xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision da1deb784d9ad3a4015a3f91fa1a5ce394fd3fdb)
115516c77SSepherosa Ziehau /*-
215516c77SSepherosa Ziehau  * Copyright (c) 2010-2012 Citrix Inc.
393b4e111SSepherosa Ziehau  * Copyright (c) 2009-2012,2016-2017 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>
5634d68912SSepherosa Ziehau #include "opt_hn.h"
5715516c77SSepherosa Ziehau #include "opt_inet6.h"
5815516c77SSepherosa Ziehau #include "opt_inet.h"
5934d68912SSepherosa Ziehau #include "opt_rss.h"
6015516c77SSepherosa Ziehau 
6115516c77SSepherosa Ziehau #include <sys/param.h>
6235203574SSepherosa Ziehau #include <sys/systm.h>
6315516c77SSepherosa Ziehau #include <sys/bus.h>
642be266caSSepherosa Ziehau #include <sys/counter.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>
72b3460f44SWei Hu #include <sys/proc.h>
73499c3e17SSepherosa Ziehau #include <sys/rmlock.h>
74499c3e17SSepherosa Ziehau #include <sys/sbuf.h>
75b3460f44SWei Hu #include <sys/sched.h>
7615516c77SSepherosa Ziehau #include <sys/smp.h>
7715516c77SSepherosa Ziehau #include <sys/socket.h>
7815516c77SSepherosa Ziehau #include <sys/sockio.h>
7915516c77SSepherosa Ziehau #include <sys/sx.h>
8015516c77SSepherosa Ziehau #include <sys/sysctl.h>
8115516c77SSepherosa Ziehau #include <sys/taskqueue.h>
8215516c77SSepherosa Ziehau #include <sys/buf_ring.h>
835bdfd3fdSDexuan Cui #include <sys/eventhandler.h>
8426d79d40SMichael Tuexen #include <sys/epoch.h>
8515516c77SSepherosa Ziehau 
8662f9bcf2SAndrew Turner #include <vm/vm.h>
8762f9bcf2SAndrew Turner #include <vm/vm_extern.h>
8862f9bcf2SAndrew Turner #include <vm/pmap.h>
8962f9bcf2SAndrew Turner 
9015516c77SSepherosa Ziehau #include <machine/atomic.h>
9115516c77SSepherosa Ziehau #include <machine/in_cksum.h>
9215516c77SSepherosa Ziehau 
9315516c77SSepherosa Ziehau #include <net/bpf.h>
9415516c77SSepherosa Ziehau #include <net/ethernet.h>
9515516c77SSepherosa Ziehau #include <net/if.h>
965bdfd3fdSDexuan Cui #include <net/if_dl.h>
9715516c77SSepherosa Ziehau #include <net/if_media.h>
9815516c77SSepherosa Ziehau #include <net/if_types.h>
9915516c77SSepherosa Ziehau #include <net/if_var.h>
10015516c77SSepherosa Ziehau #include <net/rndis.h>
10134d68912SSepherosa Ziehau #ifdef RSS
10234d68912SSepherosa Ziehau #include <net/rss_config.h>
10334d68912SSepherosa Ziehau #endif
10415516c77SSepherosa Ziehau 
10515516c77SSepherosa Ziehau #include <netinet/in_systm.h>
10615516c77SSepherosa Ziehau #include <netinet/in.h>
10715516c77SSepherosa Ziehau #include <netinet/ip.h>
10815516c77SSepherosa Ziehau #include <netinet/ip6.h>
10915516c77SSepherosa Ziehau #include <netinet/tcp.h>
11015516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
11115516c77SSepherosa Ziehau #include <netinet/udp.h>
11215516c77SSepherosa Ziehau 
11315516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
11415516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
11515516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
11615516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
11715516c77SSepherosa Ziehau 
11815516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
11915516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
12015516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
12115516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
12215516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
12315516c77SSepherosa Ziehau 
12415516c77SSepherosa Ziehau #include "vmbus_if.h"
12515516c77SSepherosa Ziehau 
12623bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
12723bf9e15SSepherosa Ziehau 
12815516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
12915516c77SSepherosa Ziehau 
130499c3e17SSepherosa Ziehau #define HN_VFMAP_SIZE_DEF		8
131499c3e17SSepherosa Ziehau 
1329c6cae24SSepherosa Ziehau #define HN_XPNT_VF_ATTWAIT_MIN		2	/* seconds */
1339c6cae24SSepherosa Ziehau 
13415516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
13515516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
13615516c77SSepherosa Ziehau 
13715516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
13815516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
13915516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
14015516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
14115516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
14215516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
14315516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
14415516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
14515516c77SSepherosa Ziehau 
14615516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
14715516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
14815516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
14915516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
15015516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
15115516c77SSepherosa Ziehau 
15215516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
15315516c77SSepherosa Ziehau 
15415516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
15515516c77SSepherosa Ziehau 
15615516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
15715516c77SSepherosa Ziehau 
15815516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
15915516c77SSepherosa Ziehau 
16015516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
16115516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
16215516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
1634db5958aSJustin Hibbits #define HN_LRO_LENLIM_MIN(ifp)		(2 * if_getmtu(ifp))
16415516c77SSepherosa Ziehau 
16515516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
16615516c77SSepherosa Ziehau 
16715516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
16815516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
16915516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
17015516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
171fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
172fdc4f478SSepherosa Ziehau do {							\
173b3460f44SWei Hu 	while (sx_try_xlock(&(sc)->hn_lock) == 0) {	\
174b3460f44SWei Hu 		/* Relinquish cpu to avoid deadlock */	\
175b3460f44SWei Hu 		sched_relinquish(curthread);		\
176fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
177b3460f44SWei Hu 	}						\
178fdc4f478SSepherosa Ziehau } while (0)
17915516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
18015516c77SSepherosa Ziehau 
18115516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
18215516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
18315516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
18415516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
18515516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
18615516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
18715516c77SSepherosa Ziehau 
188dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
189dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
190dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
191dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
192dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
193dc13fee6SSepherosa Ziehau 
19434d68912SSepherosa Ziehau #ifdef RSS
19534d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	rss_getcpu((idx) % rss_getnumbuckets())
19634d68912SSepherosa Ziehau #else
1970e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	(((sc)->hn_cpu + (idx)) % mp_ncpus)
19834d68912SSepherosa Ziehau #endif
1990e11868dSSepherosa Ziehau 
20015516c77SSepherosa Ziehau struct hn_txdesc {
20115516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
20215516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
20315516c77SSepherosa Ziehau #endif
204dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
205dc13fee6SSepherosa Ziehau 
206dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
207dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
208dc13fee6SSepherosa Ziehau 
209dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
21015516c77SSepherosa Ziehau 	struct mbuf			*m;
21115516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
21215516c77SSepherosa Ziehau 	int				refs;
21315516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
21415516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
21515516c77SSepherosa Ziehau 	uint32_t			chim_index;
21615516c77SSepherosa Ziehau 	int				chim_size;
21715516c77SSepherosa Ziehau 
21815516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
21915516c77SSepherosa Ziehau 
22015516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
22115516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
22215516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
22315516c77SSepherosa Ziehau };
22415516c77SSepherosa Ziehau 
22515516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
22615516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
227dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
22815516c77SSepherosa Ziehau 
229a491581fSWei Hu #define	HN_NDIS_PKTINFO_SUBALLOC	0x01
230a491581fSWei Hu #define	HN_NDIS_PKTINFO_1ST_FRAG	0x02
231a491581fSWei Hu #define	HN_NDIS_PKTINFO_LAST_FRAG	0x04
232a491581fSWei Hu 
233a491581fSWei Hu struct packet_info_id {
234a491581fSWei Hu 	uint8_t				ver;
235a491581fSWei Hu 	uint8_t				flag;
236a491581fSWei Hu 	uint16_t			pkt_id;
237a491581fSWei Hu };
238a491581fSWei Hu 
239a491581fSWei Hu #define NDIS_PKTINFOID_SZ		sizeof(struct packet_info_id)
240a491581fSWei Hu 
241a491581fSWei Hu 
24215516c77SSepherosa Ziehau struct hn_rxinfo {
243a491581fSWei Hu 	const uint32_t			*vlan_info;
244a491581fSWei Hu 	const uint32_t			*csum_info;
245a491581fSWei Hu 	const uint32_t			*hash_info;
246a491581fSWei Hu 	const uint32_t			*hash_value;
247a491581fSWei Hu 	const struct packet_info_id	*pktinfo_id;
24815516c77SSepherosa Ziehau };
24915516c77SSepherosa Ziehau 
250962f0357SSepherosa Ziehau struct hn_rxvf_setarg {
2515bdfd3fdSDexuan Cui 	struct hn_rx_ring	*rxr;
2524db5958aSJustin Hibbits 	if_t			vf_ifp;
2535bdfd3fdSDexuan Cui };
2545bdfd3fdSDexuan Cui 
25515516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
25615516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
25715516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
25815516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
259a491581fSWei Hu #define HN_RXINFO_PKTINFO_ID		0x0010
26015516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
26115516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
26215516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
26315516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
264a491581fSWei Hu 	 HN_RXINFO_HASHVAL |		\
265a491581fSWei Hu 	 HN_RXINFO_PKTINFO_ID)
26615516c77SSepherosa Ziehau 
26715516c77SSepherosa Ziehau static int			hn_probe(device_t);
26815516c77SSepherosa Ziehau static int			hn_attach(device_t);
26915516c77SSepherosa Ziehau static int			hn_detach(device_t);
27015516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
27115516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
27215516c77SSepherosa Ziehau 				    void *);
27315516c77SSepherosa Ziehau 
27415516c77SSepherosa Ziehau static void			hn_init(void *);
2754db5958aSJustin Hibbits static int			hn_ioctl(if_t, u_long, caddr_t);
27623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
2774db5958aSJustin Hibbits static void			hn_start(if_t);
27823bf9e15SSepherosa Ziehau #endif
2794db5958aSJustin Hibbits static int			hn_transmit(if_t, struct mbuf *);
2804db5958aSJustin Hibbits static void			hn_xmit_qflush(if_t);
2814db5958aSJustin Hibbits static int			hn_ifmedia_upd(if_t);
2824db5958aSJustin Hibbits static void			hn_ifmedia_sts(if_t,
28315516c77SSepherosa Ziehau 				    struct ifmediareq *);
28415516c77SSepherosa Ziehau 
2854db5958aSJustin Hibbits static void			hn_ifnet_event(void *, if_t, int);
2864db5958aSJustin Hibbits static void			hn_ifaddr_event(void *, if_t);
2874db5958aSJustin Hibbits static void			hn_ifnet_attevent(void *, if_t);
2884db5958aSJustin Hibbits static void			hn_ifnet_detevent(void *, if_t);
2894db5958aSJustin Hibbits static void			hn_ifnet_lnkevent(void *, if_t, int);
290499c3e17SSepherosa Ziehau 
291962f0357SSepherosa Ziehau static bool			hn_ismyvf(const struct hn_softc *,
2924db5958aSJustin Hibbits 				    const if_t);
293962f0357SSepherosa Ziehau static void			hn_rxvf_change(struct hn_softc *,
2944db5958aSJustin Hibbits 				    if_t, bool);
2954db5958aSJustin Hibbits static void			hn_rxvf_set(struct hn_softc *, if_t);
296962f0357SSepherosa Ziehau static void			hn_rxvf_set_task(void *, int);
2974db5958aSJustin Hibbits static void			hn_xpnt_vf_input(if_t, struct mbuf *);
2989c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetflags(struct hn_softc *);
2999c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetcaps(struct hn_softc *,
3009c6cae24SSepherosa Ziehau 				    struct ifreq *);
3019c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_saveifflags(struct hn_softc *);
3029c6cae24SSepherosa Ziehau static bool			hn_xpnt_vf_isready(struct hn_softc *);
3039c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_setready(struct hn_softc *);
3049c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init_taskfunc(void *, int);
3059c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init(struct hn_softc *);
306a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setenable(struct hn_softc *);
307a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setdisable(struct hn_softc *, bool);
308642ec226SSepherosa Ziehau static void			hn_vf_rss_fixup(struct hn_softc *, bool);
309642ec226SSepherosa Ziehau static void			hn_vf_rss_restore(struct hn_softc *);
310962f0357SSepherosa Ziehau 
31115516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
31215516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
31315516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
31415516c77SSepherosa Ziehau 				    const void *, int);
31515516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
31615516c77SSepherosa Ziehau 				    const void *, int);
317b3b75d9cSSepherosa Ziehau static void			hn_rndis_init_fixat(struct hn_softc *, int);
31815516c77SSepherosa Ziehau 
31915516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
32015516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
32115516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
32215516c77SSepherosa Ziehau 				    struct vmbus_channel *,
32315516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
32415516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
32515516c77SSepherosa Ziehau 				    struct vmbus_channel *,
32615516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
32715516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
32815516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
32915516c77SSepherosa Ziehau 
33015516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
33115516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
33215516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
33315516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
33415516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
33515516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
33615516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
33715516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
33815516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
33915516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
34015516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
34115516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
34234d68912SSepherosa Ziehau #ifndef RSS
34315516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
34415516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
34534d68912SSepherosa Ziehau #endif
34615516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
347642ec226SSepherosa Ziehau static int			hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS);
348642ec226SSepherosa Ziehau static int			hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS);
349dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
350dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
351dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
352dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
3536c1204dfSSepherosa Ziehau static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
35440d60d6eSDexuan Cui static int			hn_vf_sysctl(SYSCTL_HANDLER_ARGS);
355499c3e17SSepherosa Ziehau static int			hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS);
356499c3e17SSepherosa Ziehau static int			hn_vflist_sysctl(SYSCTL_HANDLER_ARGS);
357499c3e17SSepherosa Ziehau static int			hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS);
3589c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS);
3599c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS);
36015516c77SSepherosa Ziehau 
3615bdfd3fdSDexuan Cui static void			hn_stop(struct hn_softc *, bool);
36215516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
36315516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
36415516c77SSepherosa Ziehau 				    struct vmbus_channel *);
36515516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
36615516c77SSepherosa Ziehau 				    struct vmbus_channel *);
36715516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
36815516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
36915516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
37015516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
37115516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
37215516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
37315516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
37415516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
37515516c77SSepherosa Ziehau 				    int *);
3762494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
37715516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
37815516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
37915516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
38015516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
38115516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
38215516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
38315516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
38425641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
38525641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
386b3b75d9cSSepherosa Ziehau static void			hn_disable_rx(struct hn_softc *);
387b3b75d9cSSepherosa Ziehau static void			hn_drain_rxtx(struct hn_softc *, int);
3886c1204dfSSepherosa Ziehau static void			hn_polling(struct hn_softc *, u_int);
3896c1204dfSSepherosa Ziehau static void			hn_chan_polling(struct vmbus_channel *, u_int);
3909c6cae24SSepherosa Ziehau static void			hn_mtu_change_fixup(struct hn_softc *);
39115516c77SSepherosa Ziehau 
39215516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
39315516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
39415516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
39515516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
39615516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
39715516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
39815516c77SSepherosa Ziehau 
39915516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
40015516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
40115516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
402db76829bSSepherosa Ziehau static void			hn_rxpkt_proto(const struct mbuf *, int *, int *);
403f1b0a43fSSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *, uint32_t);
404c08f7b2cSSepherosa Ziehau static int			hn_rxfilter_config(struct hn_softc *);
40515516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
406afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
407642ec226SSepherosa Ziehau static void			hn_rss_mbuf_hash(struct hn_softc *, uint32_t);
408a491581fSWei Hu static int			hn_rxpkt(struct hn_rx_ring *);
409642ec226SSepherosa Ziehau static uint32_t			hn_rss_type_fromndis(uint32_t);
410642ec226SSepherosa Ziehau static uint32_t			hn_rss_type_tondis(uint32_t);
41115516c77SSepherosa Ziehau 
41215516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
41315516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
41415516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
41515516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
416db76829bSSepherosa Ziehau static void			hn_fixup_rx_data(struct hn_softc *);
41715516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
41815516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
41925641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
42025641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
4214db5958aSJustin Hibbits static int			hn_encap(if_t, struct hn_tx_ring *,
42215516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
4234db5958aSJustin Hibbits static int			hn_txpkt(if_t, struct hn_tx_ring *,
42415516c77SSepherosa Ziehau 				    struct hn_txdesc *);
42515516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
42615516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
42715516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
42815516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
42915516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
430dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
4314db5958aSJustin Hibbits static void			*hn_try_txagg(if_t,
432dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
433dc13fee6SSepherosa Ziehau 				    int);
43415516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
43515516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
43615516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
43715516c77SSepherosa Ziehau 				    const void *, int);
43815516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
43915516c77SSepherosa Ziehau 				    struct hn_txdesc *);
44015516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
44115516c77SSepherosa Ziehau 				    struct hn_txdesc *);
44215516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
44315516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
44415516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
44515516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
44623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
44715516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
44815516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
44915516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
45015516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
45123bf9e15SSepherosa Ziehau #endif
45215516c77SSepherosa Ziehau 
45380c3eb7bSWei Hu static int			hn_rsc_sysctl(SYSCTL_HANDLER_ARGS);
45480c3eb7bSWei Hu 
45515516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
45615516c77SSepherosa Ziehau     "Hyper-V network interface");
45715516c77SSepherosa Ziehau 
458b15a632cSGordon Bergling /* Trust tcp segment verification on host side. */
45915516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
46015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
46115516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
462b15a632cSGordon Bergling     "Trust tcp segment verification on host side, "
46315516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
46415516c77SSepherosa Ziehau 
46515516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
46615516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
46715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
46815516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
46915516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
47015516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
47115516c77SSepherosa Ziehau 
47215516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
47315516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
47415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
47515516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
47615516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
47715516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
47815516c77SSepherosa Ziehau 
4792be266caSSepherosa Ziehau /*
4802be266caSSepherosa Ziehau  * Offload UDP/IPv4 checksum.
4812be266caSSepherosa Ziehau  */
4822be266caSSepherosa Ziehau static int			hn_enable_udp4cs = 1;
4832be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp4cs, CTLFLAG_RDTUN,
4842be266caSSepherosa Ziehau     &hn_enable_udp4cs, 0, "Offload UDP/IPv4 checksum");
4852be266caSSepherosa Ziehau 
4862be266caSSepherosa Ziehau /*
4872be266caSSepherosa Ziehau  * Offload UDP/IPv6 checksum.
4882be266caSSepherosa Ziehau  */
4892be266caSSepherosa Ziehau static int			hn_enable_udp6cs = 1;
4902be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp6cs, CTLFLAG_RDTUN,
4912be266caSSepherosa Ziehau     &hn_enable_udp6cs, 0, "Offload UDP/IPv6 checksum");
4922be266caSSepherosa Ziehau 
4932be266caSSepherosa Ziehau /* Stats. */
4942be266caSSepherosa Ziehau static counter_u64_t		hn_udpcs_fixup;
4952be266caSSepherosa Ziehau SYSCTL_COUNTER_U64(_hw_hn, OID_AUTO, udpcs_fixup, CTLFLAG_RW,
4962be266caSSepherosa Ziehau     &hn_udpcs_fixup, "# of UDP checksum fixup");
4972be266caSSepherosa Ziehau 
4982be266caSSepherosa Ziehau /*
4992be266caSSepherosa Ziehau  * See hn_set_hlen().
5002be266caSSepherosa Ziehau  *
5012be266caSSepherosa Ziehau  * This value is for Azure.  For Hyper-V, set this above
5022be266caSSepherosa Ziehau  * 65536 to disable UDP datagram checksum fixup.
5032be266caSSepherosa Ziehau  */
5042be266caSSepherosa Ziehau static int			hn_udpcs_fixup_mtu = 1420;
5052be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, udpcs_fixup_mtu, CTLFLAG_RWTUN,
5062be266caSSepherosa Ziehau     &hn_udpcs_fixup_mtu, 0, "UDP checksum fixup MTU threshold");
5072be266caSSepherosa Ziehau 
50815516c77SSepherosa Ziehau /* Limit TSO burst size */
50915516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
51015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
51115516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
51215516c77SSepherosa Ziehau 
51315516c77SSepherosa Ziehau /* Limit chimney send size */
51415516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
51515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
51615516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
51715516c77SSepherosa Ziehau 
51815516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
51915516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
52015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
52115516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
52215516c77SSepherosa Ziehau 
52315516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
52415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
52515516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
52615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
52715516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
52815516c77SSepherosa Ziehau #endif
52915516c77SSepherosa Ziehau 
530fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
531fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
532fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
533fdd0222aSSepherosa Ziehau 
5340e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
5350e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
5360e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
5370e11868dSSepherosa Ziehau 
5380e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
5390e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
5400e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
5410e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
5420e11868dSSepherosa Ziehau 
54315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
54415516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
54515516c77SSepherosa Ziehau #else
54615516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
54715516c77SSepherosa Ziehau #endif
54815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
54915516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
55015516c77SSepherosa Ziehau 
55123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
55215516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
55315516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
55415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
55515516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
55623bf9e15SSepherosa Ziehau #endif
55715516c77SSepherosa Ziehau 
55815516c77SSepherosa Ziehau /* # of channels to use */
55915516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
56015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
56115516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
56215516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
56315516c77SSepherosa Ziehau 
56415516c77SSepherosa Ziehau /* # of transmit rings to use */
56515516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
56615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
56715516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
56815516c77SSepherosa Ziehau 
56915516c77SSepherosa Ziehau /* Software TX ring deptch */
57015516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
57115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
57215516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
57315516c77SSepherosa Ziehau 
57415516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
57515516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
57615516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
57715516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
57815516c77SSepherosa Ziehau 
579dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
580dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
581dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
582dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
583dc13fee6SSepherosa Ziehau 
584dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
585fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
586dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
587dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
588dc13fee6SSepherosa Ziehau 
589499c3e17SSepherosa Ziehau /* VF list */
5907029da5cSPawel Biernacki SYSCTL_PROC(_hw_hn, OID_AUTO, vflist,
5917029da5cSPawel Biernacki     CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_NEEDGIANT, 0, 0,
5927029da5cSPawel Biernacki     hn_vflist_sysctl, "A",
5937029da5cSPawel Biernacki     "VF list");
594499c3e17SSepherosa Ziehau 
595499c3e17SSepherosa Ziehau /* VF mapping */
5967029da5cSPawel Biernacki SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap,
5977029da5cSPawel Biernacki     CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_NEEDGIANT, 0, 0,
5987029da5cSPawel Biernacki     hn_vfmap_sysctl, "A",
5997029da5cSPawel Biernacki     "VF mapping");
600499c3e17SSepherosa Ziehau 
6019c6cae24SSepherosa Ziehau /* Transparent VF */
60278e46963SSepherosa Ziehau static int			hn_xpnt_vf = 1;
6039c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_transparent, CTLFLAG_RDTUN,
6049c6cae24SSepherosa Ziehau     &hn_xpnt_vf, 0, "Transparent VF mod");
6059c6cae24SSepherosa Ziehau 
6069c6cae24SSepherosa Ziehau /* Accurate BPF support for Transparent VF */
6079c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf = 0;
6089c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_accbpf, CTLFLAG_RDTUN,
6099c6cae24SSepherosa Ziehau     &hn_xpnt_vf_accbpf, 0, "Accurate BPF for transparent VF");
6109c6cae24SSepherosa Ziehau 
6119c6cae24SSepherosa Ziehau /* Extra wait for transparent VF attach routing; unit seconds. */
6129c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
6139c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_attwait, CTLFLAG_RWTUN,
6149c6cae24SSepherosa Ziehau     &hn_xpnt_vf_attwait, 0,
6159c6cae24SSepherosa Ziehau     "Extra wait for transparent VF attach routing; unit: seconds");
6169c6cae24SSepherosa Ziehau 
61715516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
618fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
61915516c77SSepherosa Ziehau 
620499c3e17SSepherosa Ziehau static struct rmlock		hn_vfmap_lock;
621499c3e17SSepherosa Ziehau static int			hn_vfmap_size;
6224db5958aSJustin Hibbits static if_t			*hn_vfmap;
623499c3e17SSepherosa Ziehau 
62434d68912SSepherosa Ziehau #ifndef RSS
62515516c77SSepherosa Ziehau static const uint8_t
62615516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
62715516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
62815516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
62915516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
63015516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
63115516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
63215516c77SSepherosa Ziehau };
63334d68912SSepherosa Ziehau #endif	/* !RSS */
63415516c77SSepherosa Ziehau 
635c2d50b26SSepherosa Ziehau static const struct hyperv_guid	hn_guid = {
636c2d50b26SSepherosa Ziehau 	.hv_guid = {
637c2d50b26SSepherosa Ziehau 	    0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46,
638c2d50b26SSepherosa Ziehau 	    0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e }
639c2d50b26SSepherosa Ziehau };
640c2d50b26SSepherosa Ziehau 
64115516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
64215516c77SSepherosa Ziehau 	/* Device interface */
64315516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
64415516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
64515516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
64615516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
64715516c77SSepherosa Ziehau 	DEVMETHOD_END
64815516c77SSepherosa Ziehau };
64915516c77SSepherosa Ziehau 
65015516c77SSepherosa Ziehau static driver_t hn_driver = {
65115516c77SSepherosa Ziehau 	"hn",
65215516c77SSepherosa Ziehau 	hn_methods,
65315516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
65415516c77SSepherosa Ziehau };
65515516c77SSepherosa Ziehau 
656c1cef544SJohn Baldwin DRIVER_MODULE(hn, vmbus, hn_driver, 0, 0);
65715516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
65815516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
65915516c77SSepherosa Ziehau 
66015516c77SSepherosa Ziehau static void
hn_set_lro_lenlim(struct hn_softc * sc,int lenlim)66115516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
66215516c77SSepherosa Ziehau {
66315516c77SSepherosa Ziehau 	int i;
66415516c77SSepherosa Ziehau 
665a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
66615516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
66715516c77SSepherosa Ziehau }
66815516c77SSepherosa Ziehau 
66915516c77SSepherosa Ziehau static int
hn_txpkt_sglist(struct hn_tx_ring * txr,struct hn_txdesc * txd)67015516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
67115516c77SSepherosa Ziehau {
67215516c77SSepherosa Ziehau 
67315516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
67415516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
67515516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
67615516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
67715516c77SSepherosa Ziehau }
67815516c77SSepherosa Ziehau 
67915516c77SSepherosa Ziehau static int
hn_txpkt_chim(struct hn_tx_ring * txr,struct hn_txdesc * txd)68015516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
68115516c77SSepherosa Ziehau {
68215516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
68315516c77SSepherosa Ziehau 
68415516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
68515516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
68615516c77SSepherosa Ziehau 
68715516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
68815516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
68915516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
69015516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
69115516c77SSepherosa Ziehau 
69215516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
69315516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
69415516c77SSepherosa Ziehau }
69515516c77SSepherosa Ziehau 
69615516c77SSepherosa Ziehau static __inline uint32_t
hn_chim_alloc(struct hn_softc * sc)69715516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
69815516c77SSepherosa Ziehau {
69915516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
70015516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
70115516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
70215516c77SSepherosa Ziehau 
70315516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
70415516c77SSepherosa Ziehau 		int idx;
70515516c77SSepherosa Ziehau 
70615516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
70715516c77SSepherosa Ziehau 		if (idx == 0)
70815516c77SSepherosa Ziehau 			continue;
70915516c77SSepherosa Ziehau 
71015516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
71115516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
71215516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
71315516c77SSepherosa Ziehau 
71415516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
71515516c77SSepherosa Ziehau 			continue;
71615516c77SSepherosa Ziehau 
71715516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
71815516c77SSepherosa Ziehau 		break;
71915516c77SSepherosa Ziehau 	}
72015516c77SSepherosa Ziehau 	return (ret);
72115516c77SSepherosa Ziehau }
72215516c77SSepherosa Ziehau 
72315516c77SSepherosa Ziehau static __inline void
hn_chim_free(struct hn_softc * sc,uint32_t chim_idx)72415516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
72515516c77SSepherosa Ziehau {
72615516c77SSepherosa Ziehau 	u_long mask;
72715516c77SSepherosa Ziehau 	uint32_t idx;
72815516c77SSepherosa Ziehau 
72915516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
73015516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
73115516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
73215516c77SSepherosa Ziehau 
73315516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
73415516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
73515516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
73615516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
73715516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
73815516c77SSepherosa Ziehau 
73915516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
74015516c77SSepherosa Ziehau }
74115516c77SSepherosa Ziehau 
742edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
743cc0c6ebcSSepherosa Ziehau 
744cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len)				\
745cc0c6ebcSSepherosa Ziehau do {							\
746cc0c6ebcSSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
747cc0c6ebcSSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
748cc0c6ebcSSepherosa Ziehau 		if ((m) == NULL)			\
749cc0c6ebcSSepherosa Ziehau 			return (NULL);			\
750cc0c6ebcSSepherosa Ziehau 	}						\
751cc0c6ebcSSepherosa Ziehau } while (0)
752cc0c6ebcSSepherosa Ziehau 
753edd3f315SSepherosa Ziehau /*
754edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
755edd3f315SSepherosa Ziehau  */
756edd3f315SSepherosa Ziehau static __inline struct mbuf *
hn_tso_fixup(struct mbuf * m_head)757edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
758edd3f315SSepherosa Ziehau {
759edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
760edd3f315SSepherosa Ziehau 	struct tcphdr *th;
761edd3f315SSepherosa Ziehau 	int ehlen;
762edd3f315SSepherosa Ziehau 
763edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
764edd3f315SSepherosa Ziehau 
765edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
766edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
767edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
768edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
769edd3f315SSepherosa Ziehau 	else
770edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
771c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
772edd3f315SSepherosa Ziehau 
773edd3f315SSepherosa Ziehau #ifdef INET
774edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
775edd3f315SSepherosa Ziehau 		struct ip *ip;
776edd3f315SSepherosa Ziehau 		int iphlen;
777edd3f315SSepherosa Ziehau 
778edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
779edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
780edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
781c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
782edd3f315SSepherosa Ziehau 
783edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
784edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
785edd3f315SSepherosa Ziehau 
786edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
787edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
788edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
789edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
790edd3f315SSepherosa Ziehau 	}
791edd3f315SSepherosa Ziehau #endif
792edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
793edd3f315SSepherosa Ziehau 	else
794edd3f315SSepherosa Ziehau #endif
795edd3f315SSepherosa Ziehau #ifdef INET6
796edd3f315SSepherosa Ziehau 	{
797edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
798edd3f315SSepherosa Ziehau 
799edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
800edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
801edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
802edd3f315SSepherosa Ziehau 			m_freem(m_head);
803edd3f315SSepherosa Ziehau 			return (NULL);
804edd3f315SSepherosa Ziehau 		}
805c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
806edd3f315SSepherosa Ziehau 
807edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
808edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
809edd3f315SSepherosa Ziehau 
810edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
811edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
812edd3f315SSepherosa Ziehau 	}
813edd3f315SSepherosa Ziehau #endif
814edd3f315SSepherosa Ziehau 	return (m_head);
815edd3f315SSepherosa Ziehau }
816cc0c6ebcSSepherosa Ziehau 
817cc0c6ebcSSepherosa Ziehau /*
818cc0c6ebcSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
819cc0c6ebcSSepherosa Ziehau  */
820cc0c6ebcSSepherosa Ziehau static __inline struct mbuf *
hn_set_hlen(struct mbuf * m_head)821c49d47daSSepherosa Ziehau hn_set_hlen(struct mbuf *m_head)
822cc0c6ebcSSepherosa Ziehau {
823cc0c6ebcSSepherosa Ziehau 	const struct ether_vlan_header *evl;
824cc0c6ebcSSepherosa Ziehau 	int ehlen;
825cc0c6ebcSSepherosa Ziehau 
826cc0c6ebcSSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
827cc0c6ebcSSepherosa Ziehau 	evl = mtod(m_head, const struct ether_vlan_header *);
828cc0c6ebcSSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
829cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
830cc0c6ebcSSepherosa Ziehau 	else
831cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
832c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
833cc0c6ebcSSepherosa Ziehau 
834cc0c6ebcSSepherosa Ziehau #ifdef INET
835c49d47daSSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) {
836cc0c6ebcSSepherosa Ziehau 		const struct ip *ip;
837cc0c6ebcSSepherosa Ziehau 		int iphlen;
838cc0c6ebcSSepherosa Ziehau 
839cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
840cc0c6ebcSSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
841cc0c6ebcSSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
842c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
8432be266caSSepherosa Ziehau 
8442be266caSSepherosa Ziehau 		/*
8452be266caSSepherosa Ziehau 		 * UDP checksum offload does not work in Azure, if the
8462be266caSSepherosa Ziehau 		 * following conditions meet:
8472be266caSSepherosa Ziehau 		 * - sizeof(IP hdr + UDP hdr + payload) > 1420.
8482be266caSSepherosa Ziehau 		 * - IP_DF is not set in the IP hdr.
8492be266caSSepherosa Ziehau 		 *
8502be266caSSepherosa Ziehau 		 * Fallback to software checksum for these UDP datagrams.
8512be266caSSepherosa Ziehau 		 */
8522be266caSSepherosa Ziehau 		if ((m_head->m_pkthdr.csum_flags & CSUM_IP_UDP) &&
8532be266caSSepherosa Ziehau 		    m_head->m_pkthdr.len > hn_udpcs_fixup_mtu + ehlen &&
8542be266caSSepherosa Ziehau 		    (ntohs(ip->ip_off) & IP_DF) == 0) {
8552be266caSSepherosa Ziehau 			uint16_t off = ehlen + iphlen;
8562be266caSSepherosa Ziehau 
8572be266caSSepherosa Ziehau 			counter_u64_add(hn_udpcs_fixup, 1);
8582be266caSSepherosa Ziehau 			PULLUP_HDR(m_head, off + sizeof(struct udphdr));
8592be266caSSepherosa Ziehau 			*(uint16_t *)(m_head->m_data + off +
8602be266caSSepherosa Ziehau                             m_head->m_pkthdr.csum_data) = in_cksum_skip(
8612be266caSSepherosa Ziehau 			    m_head, m_head->m_pkthdr.len, off);
8622be266caSSepherosa Ziehau 			m_head->m_pkthdr.csum_flags &= ~CSUM_IP_UDP;
8632be266caSSepherosa Ziehau 		}
864cc0c6ebcSSepherosa Ziehau 	}
865cc0c6ebcSSepherosa Ziehau #endif
866cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET)
867cc0c6ebcSSepherosa Ziehau 	else
868cc0c6ebcSSepherosa Ziehau #endif
869cc0c6ebcSSepherosa Ziehau #ifdef INET6
870cc0c6ebcSSepherosa Ziehau 	{
871cc0c6ebcSSepherosa Ziehau 		const struct ip6_hdr *ip6;
872cc0c6ebcSSepherosa Ziehau 
873cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
874cc0c6ebcSSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
875f0319886SWei Hu 		if (ip6->ip6_nxt != IPPROTO_TCP &&
876f0319886SWei Hu 		    ip6->ip6_nxt != IPPROTO_UDP) {
877c49d47daSSepherosa Ziehau 			m_freem(m_head);
878c49d47daSSepherosa Ziehau 			return (NULL);
879c49d47daSSepherosa Ziehau 		}
880c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
881cc0c6ebcSSepherosa Ziehau 	}
882cc0c6ebcSSepherosa Ziehau #endif
883cc0c6ebcSSepherosa Ziehau 	return (m_head);
884cc0c6ebcSSepherosa Ziehau }
885cc0c6ebcSSepherosa Ziehau 
886c49d47daSSepherosa Ziehau /*
887c49d47daSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
888c49d47daSSepherosa Ziehau  */
889c49d47daSSepherosa Ziehau static __inline struct mbuf *
hn_check_tcpsyn(struct mbuf * m_head,int * tcpsyn)890c49d47daSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
891c49d47daSSepherosa Ziehau {
892c49d47daSSepherosa Ziehau 	const struct tcphdr *th;
893c49d47daSSepherosa Ziehau 	int ehlen, iphlen;
894c49d47daSSepherosa Ziehau 
895c49d47daSSepherosa Ziehau 	*tcpsyn = 0;
896c49d47daSSepherosa Ziehau 	ehlen = m_head->m_pkthdr.l2hlen;
897c49d47daSSepherosa Ziehau 	iphlen = m_head->m_pkthdr.l3hlen;
898c49d47daSSepherosa Ziehau 
899c49d47daSSepherosa Ziehau 	PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
900c49d47daSSepherosa Ziehau 	th = mtodo(m_head, ehlen + iphlen);
9010fc7bdc9SRichard Scheffenegger 	if (tcp_get_flags(th) & TH_SYN)
902c49d47daSSepherosa Ziehau 		*tcpsyn = 1;
903c49d47daSSepherosa Ziehau 	return (m_head);
904c49d47daSSepherosa Ziehau }
905c49d47daSSepherosa Ziehau 
906cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR
907cc0c6ebcSSepherosa Ziehau 
908edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
909edd3f315SSepherosa Ziehau 
91015516c77SSepherosa Ziehau static int
hn_set_rxfilter(struct hn_softc * sc,uint32_t filter)911f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter)
912f1b0a43fSSepherosa Ziehau {
913f1b0a43fSSepherosa Ziehau 	int error = 0;
914f1b0a43fSSepherosa Ziehau 
915f1b0a43fSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
916f1b0a43fSSepherosa Ziehau 
917f1b0a43fSSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
918f1b0a43fSSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
919f1b0a43fSSepherosa Ziehau 		if (!error)
920f1b0a43fSSepherosa Ziehau 			sc->hn_rx_filter = filter;
921f1b0a43fSSepherosa Ziehau 	}
922f1b0a43fSSepherosa Ziehau 	return (error);
923f1b0a43fSSepherosa Ziehau }
924f1b0a43fSSepherosa Ziehau 
925f1b0a43fSSepherosa Ziehau static int
hn_rxfilter_config(struct hn_softc * sc)926c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc)
92715516c77SSepherosa Ziehau {
9284db5958aSJustin Hibbits 	if_t ifp = sc->hn_ifp;
92915516c77SSepherosa Ziehau 	uint32_t filter;
93015516c77SSepherosa Ziehau 
93115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
93215516c77SSepherosa Ziehau 
9339c6cae24SSepherosa Ziehau 	/*
9349c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, we don't know how
9359c6cae24SSepherosa Ziehau 	 * its RX filter is configured, so stick the synthetic device in
9369c6cae24SSepherosa Ziehau 	 * the promiscous mode.
9379c6cae24SSepherosa Ziehau 	 */
9384db5958aSJustin Hibbits 	if ((if_getflags(ifp) & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) {
93915516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
94015516c77SSepherosa Ziehau 	} else {
94115516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
9424db5958aSJustin Hibbits 		if (if_getflags(ifp) & IFF_BROADCAST)
94315516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
94415516c77SSepherosa Ziehau 		/* TODO: support multicast list */
9454db5958aSJustin Hibbits 		if ((if_getflags(ifp) & IFF_ALLMULTI) ||
9464db5958aSJustin Hibbits 		    !if_maddr_empty(ifp))
94715516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
94815516c77SSepherosa Ziehau 	}
949f1b0a43fSSepherosa Ziehau 	return (hn_set_rxfilter(sc, filter));
95015516c77SSepherosa Ziehau }
95115516c77SSepherosa Ziehau 
952dc13fee6SSepherosa Ziehau static void
hn_set_txagg(struct hn_softc * sc)953dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
954dc13fee6SSepherosa Ziehau {
955dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
956dc13fee6SSepherosa Ziehau 	int i;
957dc13fee6SSepherosa Ziehau 
958dc13fee6SSepherosa Ziehau 	/*
959dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
960dc13fee6SSepherosa Ziehau 	 */
961dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
962dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
963dc13fee6SSepherosa Ziehau 	else
964dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
965dc13fee6SSepherosa Ziehau 
966dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
967dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
968dc13fee6SSepherosa Ziehau 
969a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
970a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
971a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
972a4364cfeSSepherosa Ziehau 
973dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
974dc13fee6SSepherosa Ziehau 		/* Disable */
975dc13fee6SSepherosa Ziehau 		size = 0;
976dc13fee6SSepherosa Ziehau 		pkts = 0;
977dc13fee6SSepherosa Ziehau 		goto done;
978dc13fee6SSepherosa Ziehau 	}
979dc13fee6SSepherosa Ziehau 
980dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
981dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
982dc13fee6SSepherosa Ziehau 		size = INT_MAX;
983dc13fee6SSepherosa Ziehau 
984dc13fee6SSepherosa Ziehau 	/*
985dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
986dc13fee6SSepherosa Ziehau 	 */
987dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
988dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
989dc13fee6SSepherosa Ziehau 	else
990dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
991dc13fee6SSepherosa Ziehau 
992dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
993dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
994dc13fee6SSepherosa Ziehau 
995dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
996dc13fee6SSepherosa Ziehau 		/* Disable */
997dc13fee6SSepherosa Ziehau 		size = 0;
998dc13fee6SSepherosa Ziehau 		pkts = 0;
999dc13fee6SSepherosa Ziehau 		goto done;
1000dc13fee6SSepherosa Ziehau 	}
1001dc13fee6SSepherosa Ziehau 
1002dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
1003dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
1004dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
1005dc13fee6SSepherosa Ziehau 
1006dc13fee6SSepherosa Ziehau done:
1007dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
1008dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
1009dc13fee6SSepherosa Ziehau 		/* Disable */
1010dc13fee6SSepherosa Ziehau 		size = 0;
1011dc13fee6SSepherosa Ziehau 		pkts = 0;
1012dc13fee6SSepherosa Ziehau 	}
1013dc13fee6SSepherosa Ziehau 
1014dc13fee6SSepherosa Ziehau 	if (bootverbose) {
1015dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
1016dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
1017dc13fee6SSepherosa Ziehau 	}
1018dc13fee6SSepherosa Ziehau 
1019dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
1020dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
1021dc13fee6SSepherosa Ziehau 
1022dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
1023dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
1024dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
1025dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
1026dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
1027dc13fee6SSepherosa Ziehau 	}
1028dc13fee6SSepherosa Ziehau }
1029dc13fee6SSepherosa Ziehau 
103015516c77SSepherosa Ziehau static int
hn_get_txswq_depth(const struct hn_tx_ring * txr)103115516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
103215516c77SSepherosa Ziehau {
103315516c77SSepherosa Ziehau 
103415516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
103515516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
103615516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
103715516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
103815516c77SSepherosa Ziehau }
103915516c77SSepherosa Ziehau 
104015516c77SSepherosa Ziehau static int
hn_rss_reconfig(struct hn_softc * sc)104115516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
104215516c77SSepherosa Ziehau {
104315516c77SSepherosa Ziehau 	int error;
104415516c77SSepherosa Ziehau 
104515516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
104615516c77SSepherosa Ziehau 
104715516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
104815516c77SSepherosa Ziehau 		return (ENXIO);
104915516c77SSepherosa Ziehau 
105015516c77SSepherosa Ziehau 	/*
105115516c77SSepherosa Ziehau 	 * Disable RSS first.
105215516c77SSepherosa Ziehau 	 *
105315516c77SSepherosa Ziehau 	 * NOTE:
105415516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
105515516c77SSepherosa Ziehau 	 * _not_ work properly.
105615516c77SSepherosa Ziehau 	 */
105715516c77SSepherosa Ziehau 	if (bootverbose)
105815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
105915516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
106015516c77SSepherosa Ziehau 	if (error) {
106115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
106215516c77SSepherosa Ziehau 		return (error);
106315516c77SSepherosa Ziehau 	}
106415516c77SSepherosa Ziehau 
106515516c77SSepherosa Ziehau 	/*
106615516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
106715516c77SSepherosa Ziehau 	 * table.
106815516c77SSepherosa Ziehau 	 */
106915516c77SSepherosa Ziehau 	if (bootverbose)
107015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
107115516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
107215516c77SSepherosa Ziehau 	if (error) {
107315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
107415516c77SSepherosa Ziehau 		return (error);
107515516c77SSepherosa Ziehau 	}
107615516c77SSepherosa Ziehau 	return (0);
107715516c77SSepherosa Ziehau }
107815516c77SSepherosa Ziehau 
107915516c77SSepherosa Ziehau static void
hn_rss_ind_fixup(struct hn_softc * sc)1080afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
108115516c77SSepherosa Ziehau {
108215516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
1083afd4971bSSepherosa Ziehau 	int i, nchan;
108415516c77SSepherosa Ziehau 
1085afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
108615516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
108715516c77SSepherosa Ziehau 
108815516c77SSepherosa Ziehau 	/*
108915516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
109015516c77SSepherosa Ziehau 	 * can be used.
109115516c77SSepherosa Ziehau 	 */
109215516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
109315516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
109415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
109515516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
109615516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
109715516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
109815516c77SSepherosa Ziehau 		}
109915516c77SSepherosa Ziehau 	}
110015516c77SSepherosa Ziehau }
110115516c77SSepherosa Ziehau 
110215516c77SSepherosa Ziehau static int
hn_ifmedia_upd(if_t ifp __unused)11034db5958aSJustin Hibbits hn_ifmedia_upd(if_t ifp __unused)
110415516c77SSepherosa Ziehau {
110515516c77SSepherosa Ziehau 
110663a7c4beSMark Peek 	/* Ignore since autoselect is the only defined and valid media */
110763a7c4beSMark Peek 	return (0);
110815516c77SSepherosa Ziehau }
110915516c77SSepherosa Ziehau 
111015516c77SSepherosa Ziehau static void
hn_ifmedia_sts(if_t ifp,struct ifmediareq * ifmr)11114db5958aSJustin Hibbits hn_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
111215516c77SSepherosa Ziehau {
11134db5958aSJustin Hibbits 	struct hn_softc *sc = if_getsoftc(ifp);
111415516c77SSepherosa Ziehau 
111515516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
111615516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
111715516c77SSepherosa Ziehau 
111815516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
111915516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
112015516c77SSepherosa Ziehau 		return;
112115516c77SSepherosa Ziehau 	}
112215516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
112315516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
112415516c77SSepherosa Ziehau }
112515516c77SSepherosa Ziehau 
11265bdfd3fdSDexuan Cui static void
hn_rxvf_set_task(void * xarg,int pending __unused)1127962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused)
11285bdfd3fdSDexuan Cui {
1129962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg *arg = xarg;
11305bdfd3fdSDexuan Cui 
1131962f0357SSepherosa Ziehau 	arg->rxr->hn_rxvf_ifp = arg->vf_ifp;
11325bdfd3fdSDexuan Cui }
11335bdfd3fdSDexuan Cui 
11345bdfd3fdSDexuan Cui static void
hn_rxvf_set(struct hn_softc * sc,if_t vf_ifp)11354db5958aSJustin Hibbits hn_rxvf_set(struct hn_softc *sc, if_t vf_ifp)
11365bdfd3fdSDexuan Cui {
11375bdfd3fdSDexuan Cui 	struct hn_rx_ring *rxr;
1138962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg arg;
11395bdfd3fdSDexuan Cui 	struct task task;
11405bdfd3fdSDexuan Cui 	int i;
11415bdfd3fdSDexuan Cui 
11425bdfd3fdSDexuan Cui 	HN_LOCK_ASSERT(sc);
11435bdfd3fdSDexuan Cui 
1144962f0357SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_rxvf_set_task, &arg);
11455bdfd3fdSDexuan Cui 
11465bdfd3fdSDexuan Cui 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
11475bdfd3fdSDexuan Cui 		rxr = &sc->hn_rx_ring[i];
11485bdfd3fdSDexuan Cui 
11495bdfd3fdSDexuan Cui 		if (i < sc->hn_rx_ring_inuse) {
1150962f0357SSepherosa Ziehau 			arg.rxr = rxr;
1151962f0357SSepherosa Ziehau 			arg.vf_ifp = vf_ifp;
11525bdfd3fdSDexuan Cui 			vmbus_chan_run_task(rxr->hn_chan, &task);
11535bdfd3fdSDexuan Cui 		} else {
1154962f0357SSepherosa Ziehau 			rxr->hn_rxvf_ifp = vf_ifp;
11555bdfd3fdSDexuan Cui 		}
11565bdfd3fdSDexuan Cui 	}
11575bdfd3fdSDexuan Cui }
11585bdfd3fdSDexuan Cui 
1159962f0357SSepherosa Ziehau static bool
hn_ismyvf(const struct hn_softc * sc,const if_t ifp)11604db5958aSJustin Hibbits hn_ismyvf(const struct hn_softc *sc, const if_t ifp)
1161499c3e17SSepherosa Ziehau {
11624db5958aSJustin Hibbits 	if_t hn_ifp;
1163499c3e17SSepherosa Ziehau 
1164499c3e17SSepherosa Ziehau 	hn_ifp = sc->hn_ifp;
1165499c3e17SSepherosa Ziehau 
1166499c3e17SSepherosa Ziehau 	if (ifp == hn_ifp)
1167499c3e17SSepherosa Ziehau 		return (false);
1168499c3e17SSepherosa Ziehau 
11694db5958aSJustin Hibbits 	if (if_getalloctype(ifp) != IFT_ETHER)
1170499c3e17SSepherosa Ziehau 		return (false);
1171499c3e17SSepherosa Ziehau 
1172499c3e17SSepherosa Ziehau 	/* Ignore lagg/vlan interfaces */
11734db5958aSJustin Hibbits 	if (strcmp(if_getdname(ifp), "lagg") == 0 ||
11744db5958aSJustin Hibbits 	    strcmp(if_getdname(ifp), "vlan") == 0)
1175499c3e17SSepherosa Ziehau 		return (false);
1176499c3e17SSepherosa Ziehau 
1177d76fb49fSDexuan Cui 	/*
11784db5958aSJustin Hibbits 	 * During detach events if_getifaddr(ifp) might be NULL.
1179d76fb49fSDexuan Cui 	 * Make sure the bcmp() below doesn't panic on that:
1180d76fb49fSDexuan Cui 	 */
11814db5958aSJustin Hibbits 	if (if_getifaddr(ifp) == NULL || if_getifaddr(hn_ifp) == NULL)
1182d76fb49fSDexuan Cui 		return (false);
1183d76fb49fSDexuan Cui 
11844db5958aSJustin Hibbits 	if (bcmp(if_getlladdr(ifp), if_getlladdr(hn_ifp), ETHER_ADDR_LEN) != 0)
1185499c3e17SSepherosa Ziehau 		return (false);
1186499c3e17SSepherosa Ziehau 
1187499c3e17SSepherosa Ziehau 	return (true);
1188499c3e17SSepherosa Ziehau }
1189499c3e17SSepherosa Ziehau 
11905bdfd3fdSDexuan Cui static void
hn_rxvf_change(struct hn_softc * sc,if_t ifp,bool rxvf)11914db5958aSJustin Hibbits hn_rxvf_change(struct hn_softc *sc, if_t ifp, bool rxvf)
11925bdfd3fdSDexuan Cui {
11934db5958aSJustin Hibbits 	if_t hn_ifp;
11945bdfd3fdSDexuan Cui 
11955bdfd3fdSDexuan Cui 	HN_LOCK(sc);
11965bdfd3fdSDexuan Cui 
11975bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
11985bdfd3fdSDexuan Cui 		goto out;
11995bdfd3fdSDexuan Cui 
1200499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1201499c3e17SSepherosa Ziehau 		goto out;
12025bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
12035bdfd3fdSDexuan Cui 
1204962f0357SSepherosa Ziehau 	if (rxvf) {
1205962f0357SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_RXVF)
12065bdfd3fdSDexuan Cui 			goto out;
12075bdfd3fdSDexuan Cui 
1208962f0357SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_RXVF;
12095bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
12105bdfd3fdSDexuan Cui 	} else {
1211962f0357SSepherosa Ziehau 		if (!(sc->hn_flags & HN_FLAG_RXVF))
12125bdfd3fdSDexuan Cui 			goto out;
12135bdfd3fdSDexuan Cui 
1214962f0357SSepherosa Ziehau 		sc->hn_flags &= ~HN_FLAG_RXVF;
12154db5958aSJustin Hibbits 		if (if_getdrvflags(hn_ifp) & IFF_DRV_RUNNING)
12165bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
12175bdfd3fdSDexuan Cui 		else
12185bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
12195bdfd3fdSDexuan Cui 	}
12205bdfd3fdSDexuan Cui 
12215bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
12229c6cae24SSepherosa Ziehau 	    rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH);
12235bdfd3fdSDexuan Cui 
1224962f0357SSepherosa Ziehau 	hn_rxvf_set(sc, rxvf ? ifp : NULL);
12255bdfd3fdSDexuan Cui 
1226962f0357SSepherosa Ziehau 	if (rxvf) {
1227642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, true);
12285bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
12295bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
12305bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
1231499c3e17SSepherosa Ziehau 		if_link_state_change(hn_ifp, LINK_STATE_DOWN);
12325bdfd3fdSDexuan Cui 	} else {
1233642ec226SSepherosa Ziehau 		hn_vf_rss_restore(sc);
12345bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
12355bdfd3fdSDexuan Cui 	}
12365bdfd3fdSDexuan Cui 
12374db5958aSJustin Hibbits 	devctl_notify("HYPERV_NIC_VF", if_name(hn_ifp),
1238962f0357SSepherosa Ziehau 	    rxvf ? "VF_UP" : "VF_DOWN", NULL);
123933408a34SDexuan Cui 
1240962f0357SSepherosa Ziehau 	if (bootverbose) {
1241962f0357SSepherosa Ziehau 		if_printf(hn_ifp, "datapath is switched %s %s\n",
12424db5958aSJustin Hibbits 		    rxvf ? "to" : "from", if_name(ifp));
1243962f0357SSepherosa Ziehau 	}
12445bdfd3fdSDexuan Cui out:
12455bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
12465bdfd3fdSDexuan Cui }
12475bdfd3fdSDexuan Cui 
12485bdfd3fdSDexuan Cui static void
hn_ifnet_event(void * arg,if_t ifp,int event)12494db5958aSJustin Hibbits hn_ifnet_event(void *arg, if_t ifp, int event)
12505bdfd3fdSDexuan Cui {
1251962f0357SSepherosa Ziehau 
12525bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
12535bdfd3fdSDexuan Cui 		return;
1254962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP);
12555bdfd3fdSDexuan Cui }
12565bdfd3fdSDexuan Cui 
12575bdfd3fdSDexuan Cui static void
hn_ifaddr_event(void * arg,if_t ifp)12584db5958aSJustin Hibbits hn_ifaddr_event(void *arg, if_t ifp)
12595bdfd3fdSDexuan Cui {
1260962f0357SSepherosa Ziehau 
12614db5958aSJustin Hibbits 	hn_rxvf_change(arg, ifp, if_getflags(ifp) & IFF_UP);
12625bdfd3fdSDexuan Cui }
12635bdfd3fdSDexuan Cui 
12649c6cae24SSepherosa Ziehau static int
hn_xpnt_vf_iocsetcaps(struct hn_softc * sc,struct ifreq * ifr __unused)1265289ba6b8SWei Hu hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr __unused)
12669c6cae24SSepherosa Ziehau {
12674db5958aSJustin Hibbits 	if_t ifp, vf_ifp;
12689c6cae24SSepherosa Ziehau 
12699c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12709c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
12719c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
12729c6cae24SSepherosa Ziehau 
12739c6cae24SSepherosa Ziehau 	/*
1274289ba6b8SWei Hu 	 * Just sync up with VF's enabled capabilities.
12759c6cae24SSepherosa Ziehau 	 */
1276289ba6b8SWei Hu 	if_setcapenable(ifp, if_getcapenable(vf_ifp));
1277289ba6b8SWei Hu 	if_sethwassist(ifp, if_gethwassist(vf_ifp));
12789c6cae24SSepherosa Ziehau 
1279289ba6b8SWei Hu 	return (0);
12809c6cae24SSepherosa Ziehau }
12819c6cae24SSepherosa Ziehau 
12829c6cae24SSepherosa Ziehau static int
hn_xpnt_vf_iocsetflags(struct hn_softc * sc)12839c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc)
12849c6cae24SSepherosa Ziehau {
12854db5958aSJustin Hibbits 	if_t vf_ifp;
12869c6cae24SSepherosa Ziehau 	struct ifreq ifr;
12879c6cae24SSepherosa Ziehau 
12889c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12899c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
12909c6cae24SSepherosa Ziehau 
12919c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
12924db5958aSJustin Hibbits 	strlcpy(ifr.ifr_name, if_name(vf_ifp), sizeof(ifr.ifr_name));
12934db5958aSJustin Hibbits 	ifr.ifr_flags = if_getflags(vf_ifp) & 0xffff;
12944db5958aSJustin Hibbits 	ifr.ifr_flagshigh = if_getflags(vf_ifp) >> 16;
12954db5958aSJustin Hibbits 	return (ifhwioctl(SIOCSIFFLAGS, vf_ifp, (caddr_t)&ifr, curthread));
12969c6cae24SSepherosa Ziehau }
12979c6cae24SSepherosa Ziehau 
12989c6cae24SSepherosa Ziehau static void
hn_xpnt_vf_saveifflags(struct hn_softc * sc)12999c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc)
13009c6cae24SSepherosa Ziehau {
13014db5958aSJustin Hibbits 	if_t ifp = sc->hn_ifp;
13029c6cae24SSepherosa Ziehau 	int allmulti = 0;
13039c6cae24SSepherosa Ziehau 
13049c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13059c6cae24SSepherosa Ziehau 
13069c6cae24SSepherosa Ziehau 	/* XXX vlan(4) style mcast addr maintenance */
13074db5958aSJustin Hibbits 	if (!if_maddr_empty(ifp))
13089c6cae24SSepherosa Ziehau 		allmulti = IFF_ALLMULTI;
13099c6cae24SSepherosa Ziehau 
13109c6cae24SSepherosa Ziehau 	/* Always set the VF's if_flags */
13114db5958aSJustin Hibbits 	if_setflags(sc->hn_vf_ifp, if_getflags(ifp) | allmulti);
13129c6cae24SSepherosa Ziehau }
13139c6cae24SSepherosa Ziehau 
13149c6cae24SSepherosa Ziehau static void
hn_xpnt_vf_input(if_t vf_ifp,struct mbuf * m)13154db5958aSJustin Hibbits hn_xpnt_vf_input(if_t vf_ifp, struct mbuf *m)
13169c6cae24SSepherosa Ziehau {
13179c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
13184db5958aSJustin Hibbits 	if_t hn_ifp = NULL;
13199c6cae24SSepherosa Ziehau 	struct mbuf *mn;
13209c6cae24SSepherosa Ziehau 
13219c6cae24SSepherosa Ziehau 	/*
13229c6cae24SSepherosa Ziehau 	 * XXX racy, if hn(4) ever detached.
13239c6cae24SSepherosa Ziehau 	 */
13249c6cae24SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
13254db5958aSJustin Hibbits 	if (if_getindex(vf_ifp) < hn_vfmap_size)
13264db5958aSJustin Hibbits 		hn_ifp = hn_vfmap[if_getindex(vf_ifp)];
13279c6cae24SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
13289c6cae24SSepherosa Ziehau 
13299c6cae24SSepherosa Ziehau 	if (hn_ifp != NULL) {
13309c6cae24SSepherosa Ziehau 		for (mn = m; mn != NULL; mn = mn->m_nextpkt) {
13313bed4e54SSepherosa Ziehau 			/*
13323bed4e54SSepherosa Ziehau 			 * Allow tapping on the VF.
13333bed4e54SSepherosa Ziehau 			 */
13349c6cae24SSepherosa Ziehau 			ETHER_BPF_MTAP(vf_ifp, mn);
13353bed4e54SSepherosa Ziehau 
13363bed4e54SSepherosa Ziehau 			/*
13373bed4e54SSepherosa Ziehau 			 * Update VF stats.
13383bed4e54SSepherosa Ziehau 			 */
13394db5958aSJustin Hibbits 			if ((if_getcapenable(vf_ifp) & IFCAP_HWSTATS) == 0) {
13403bed4e54SSepherosa Ziehau 				if_inc_counter(vf_ifp, IFCOUNTER_IBYTES,
13413bed4e54SSepherosa Ziehau 				    mn->m_pkthdr.len);
13423bed4e54SSepherosa Ziehau 			}
13433bed4e54SSepherosa Ziehau 			/*
13443bed4e54SSepherosa Ziehau 			 * XXX IFCOUNTER_IMCAST
13453bed4e54SSepherosa Ziehau 			 * This stat updating is kinda invasive, since it
13463bed4e54SSepherosa Ziehau 			 * requires two checks on the mbuf: the length check
13473bed4e54SSepherosa Ziehau 			 * and the ethernet header check.  As of this write,
13483bed4e54SSepherosa Ziehau 			 * all multicast packets go directly to hn(4), which
13493bed4e54SSepherosa Ziehau 			 * makes imcast stat updating in the VF a try in vian.
13503bed4e54SSepherosa Ziehau 			 */
13513bed4e54SSepherosa Ziehau 
13523bed4e54SSepherosa Ziehau 			/*
13533bed4e54SSepherosa Ziehau 			 * Fix up rcvif and increase hn(4)'s ipackets.
13543bed4e54SSepherosa Ziehau 			 */
13559c6cae24SSepherosa Ziehau 			mn->m_pkthdr.rcvif = hn_ifp;
13569c6cae24SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
13579c6cae24SSepherosa Ziehau 		}
13583bed4e54SSepherosa Ziehau 		/*
13593bed4e54SSepherosa Ziehau 		 * Go through hn(4)'s if_input.
13603bed4e54SSepherosa Ziehau 		 */
13614db5958aSJustin Hibbits 		if_input(hn_ifp, m);
13629c6cae24SSepherosa Ziehau 	} else {
13639c6cae24SSepherosa Ziehau 		/*
13649c6cae24SSepherosa Ziehau 		 * In the middle of the transition; free this
13659c6cae24SSepherosa Ziehau 		 * mbuf chain.
13669c6cae24SSepherosa Ziehau 		 */
13679c6cae24SSepherosa Ziehau 		while (m != NULL) {
13689c6cae24SSepherosa Ziehau 			mn = m->m_nextpkt;
13699c6cae24SSepherosa Ziehau 			m->m_nextpkt = NULL;
13709c6cae24SSepherosa Ziehau 			m_freem(m);
13719c6cae24SSepherosa Ziehau 			m = mn;
13729c6cae24SSepherosa Ziehau 		}
13739c6cae24SSepherosa Ziehau 	}
13749c6cae24SSepherosa Ziehau }
13759c6cae24SSepherosa Ziehau 
13769c6cae24SSepherosa Ziehau static void
hn_mtu_change_fixup(struct hn_softc * sc)13779c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc)
13789c6cae24SSepherosa Ziehau {
13794db5958aSJustin Hibbits 	if_t ifp;
13809c6cae24SSepherosa Ziehau 
13819c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13829c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
13839c6cae24SSepherosa Ziehau 
13844db5958aSJustin Hibbits 	hn_set_tso_maxsize(sc, hn_tso_maxlen, if_getmtu(ifp));
13859c6cae24SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp))
13869c6cae24SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
13879c6cae24SSepherosa Ziehau }
13889c6cae24SSepherosa Ziehau 
1389642ec226SSepherosa Ziehau static uint32_t
hn_rss_type_fromndis(uint32_t rss_hash)1390642ec226SSepherosa Ziehau hn_rss_type_fromndis(uint32_t rss_hash)
1391642ec226SSepherosa Ziehau {
1392642ec226SSepherosa Ziehau 	uint32_t types = 0;
1393642ec226SSepherosa Ziehau 
1394642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV4)
1395642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV4;
1396642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV4)
1397642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV4;
1398642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6)
1399642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6;
1400642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6_EX)
1401642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6_EX;
1402642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6)
1403642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6;
1404642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6_EX)
1405642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6_EX;
14066f12c42eSSepherosa Ziehau 	if (rss_hash & NDIS_HASH_UDP_IPV4_X)
14076f12c42eSSepherosa Ziehau 		types |= RSS_TYPE_UDP_IPV4;
1408642ec226SSepherosa Ziehau 	return (types);
1409642ec226SSepherosa Ziehau }
1410642ec226SSepherosa Ziehau 
1411642ec226SSepherosa Ziehau static uint32_t
hn_rss_type_tondis(uint32_t types)1412642ec226SSepherosa Ziehau hn_rss_type_tondis(uint32_t types)
1413642ec226SSepherosa Ziehau {
1414642ec226SSepherosa Ziehau 	uint32_t rss_hash = 0;
1415642ec226SSepherosa Ziehau 
14166f12c42eSSepherosa Ziehau 	KASSERT((types & (RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0,
14176f12c42eSSepherosa Ziehau 	    ("UDP6 and UDP6EX are not supported"));
1418642ec226SSepherosa Ziehau 
1419642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV4)
1420642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV4;
1421642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV4)
1422642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV4;
1423642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6)
1424642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6;
1425642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6_EX)
1426642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6_EX;
1427642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6)
1428642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6;
1429642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6_EX)
1430642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6_EX;
14316f12c42eSSepherosa Ziehau 	if (types & RSS_TYPE_UDP_IPV4)
14326f12c42eSSepherosa Ziehau 		rss_hash |= NDIS_HASH_UDP_IPV4_X;
1433642ec226SSepherosa Ziehau 	return (rss_hash);
1434642ec226SSepherosa Ziehau }
1435642ec226SSepherosa Ziehau 
1436642ec226SSepherosa Ziehau static void
hn_rss_mbuf_hash(struct hn_softc * sc,uint32_t mbuf_hash)1437642ec226SSepherosa Ziehau hn_rss_mbuf_hash(struct hn_softc *sc, uint32_t mbuf_hash)
1438642ec226SSepherosa Ziehau {
1439642ec226SSepherosa Ziehau 	int i;
1440642ec226SSepherosa Ziehau 
1441642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1442642ec226SSepherosa Ziehau 
1443642ec226SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1444642ec226SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_mbuf_hash = mbuf_hash;
1445642ec226SSepherosa Ziehau }
1446642ec226SSepherosa Ziehau 
1447642ec226SSepherosa Ziehau static void
hn_vf_rss_fixup(struct hn_softc * sc,bool reconf)1448642ec226SSepherosa Ziehau hn_vf_rss_fixup(struct hn_softc *sc, bool reconf)
1449642ec226SSepherosa Ziehau {
14504db5958aSJustin Hibbits 	if_t ifp, vf_ifp;
1451642ec226SSepherosa Ziehau 	struct ifrsshash ifrh;
1452642ec226SSepherosa Ziehau 	struct ifrsskey ifrk;
1453642ec226SSepherosa Ziehau 	int error;
1454642ec226SSepherosa Ziehau 	uint32_t my_types, diff_types, mbuf_types = 0;
1455642ec226SSepherosa Ziehau 
1456642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1457642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
14584db5958aSJustin Hibbits 	    ("%s: synthetic parts are not attached", if_name(sc->hn_ifp)));
1459642ec226SSepherosa Ziehau 
1460642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
1461642ec226SSepherosa Ziehau 		/* No RSS on synthetic parts; done. */
1462642ec226SSepherosa Ziehau 		return;
1463642ec226SSepherosa Ziehau 	}
1464642ec226SSepherosa Ziehau 	if ((sc->hn_rss_hcap & NDIS_HASH_FUNCTION_TOEPLITZ) == 0) {
1465642ec226SSepherosa Ziehau 		/* Synthetic parts do not support Toeplitz; done. */
1466642ec226SSepherosa Ziehau 		return;
1467642ec226SSepherosa Ziehau 	}
1468642ec226SSepherosa Ziehau 
1469642ec226SSepherosa Ziehau 	ifp = sc->hn_ifp;
1470642ec226SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
1471642ec226SSepherosa Ziehau 
1472642ec226SSepherosa Ziehau 	/*
1473642ec226SSepherosa Ziehau 	 * Extract VF's RSS key.  Only 40 bytes key for Toeplitz is
1474642ec226SSepherosa Ziehau 	 * supported.
1475642ec226SSepherosa Ziehau 	 */
1476642ec226SSepherosa Ziehau 	memset(&ifrk, 0, sizeof(ifrk));
14774db5958aSJustin Hibbits 	strlcpy(ifrk.ifrk_name, if_name(vf_ifp), sizeof(ifrk.ifrk_name));
14784db5958aSJustin Hibbits 	error = ifhwioctl(SIOCGIFRSSKEY, vf_ifp, (caddr_t)&ifrk, curthread);
1479642ec226SSepherosa Ziehau 	if (error) {
1480a3b413afSHans Petter Selasky 		if_printf(ifp, "%s SIOCGIFRSSKEY failed: %d\n",
14814db5958aSJustin Hibbits 		    if_name(vf_ifp), error);
1482642ec226SSepherosa Ziehau 		goto done;
1483642ec226SSepherosa Ziehau 	}
1484642ec226SSepherosa Ziehau 	if (ifrk.ifrk_func != RSS_FUNC_TOEPLITZ) {
1485642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
14864db5958aSJustin Hibbits 		    if_name(vf_ifp), ifrk.ifrk_func);
1487642ec226SSepherosa Ziehau 		goto done;
1488642ec226SSepherosa Ziehau 	}
1489642ec226SSepherosa Ziehau 	if (ifrk.ifrk_keylen != NDIS_HASH_KEYSIZE_TOEPLITZ) {
1490642ec226SSepherosa Ziehau 		if_printf(ifp, "%s invalid RSS Toeplitz key length %d\n",
14914db5958aSJustin Hibbits 		    if_name(vf_ifp), ifrk.ifrk_keylen);
1492642ec226SSepherosa Ziehau 		goto done;
1493642ec226SSepherosa Ziehau 	}
1494642ec226SSepherosa Ziehau 
1495642ec226SSepherosa Ziehau 	/*
1496642ec226SSepherosa Ziehau 	 * Extract VF's RSS hash.  Only Toeplitz is supported.
1497642ec226SSepherosa Ziehau 	 */
1498642ec226SSepherosa Ziehau 	memset(&ifrh, 0, sizeof(ifrh));
14994db5958aSJustin Hibbits 	strlcpy(ifrh.ifrh_name, if_name(vf_ifp), sizeof(ifrh.ifrh_name));
15004db5958aSJustin Hibbits 	error = ifhwioctl(SIOCGIFRSSHASH, vf_ifp, (caddr_t)&ifrh, curthread);
1501642ec226SSepherosa Ziehau 	if (error) {
1502642ec226SSepherosa Ziehau 		if_printf(ifp, "%s SIOCGRSSHASH failed: %d\n",
15034db5958aSJustin Hibbits 		    if_name(vf_ifp), error);
1504642ec226SSepherosa Ziehau 		goto done;
1505642ec226SSepherosa Ziehau 	}
1506642ec226SSepherosa Ziehau 	if (ifrh.ifrh_func != RSS_FUNC_TOEPLITZ) {
1507642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
15084db5958aSJustin Hibbits 		    if_name(vf_ifp), ifrh.ifrh_func);
1509642ec226SSepherosa Ziehau 		goto done;
1510642ec226SSepherosa Ziehau 	}
1511642ec226SSepherosa Ziehau 
1512642ec226SSepherosa Ziehau 	my_types = hn_rss_type_fromndis(sc->hn_rss_hcap);
1513642ec226SSepherosa Ziehau 	if ((ifrh.ifrh_types & my_types) == 0) {
1514642ec226SSepherosa Ziehau 		/* This disables RSS; ignore it then */
1515642ec226SSepherosa Ziehau 		if_printf(ifp, "%s intersection of RSS types failed.  "
15164db5958aSJustin Hibbits 		    "VF %#x, mine %#x\n", if_name(vf_ifp),
1517642ec226SSepherosa Ziehau 		    ifrh.ifrh_types, my_types);
1518642ec226SSepherosa Ziehau 		goto done;
1519642ec226SSepherosa Ziehau 	}
1520642ec226SSepherosa Ziehau 
1521642ec226SSepherosa Ziehau 	diff_types = my_types ^ ifrh.ifrh_types;
1522642ec226SSepherosa Ziehau 	my_types &= ifrh.ifrh_types;
1523642ec226SSepherosa Ziehau 	mbuf_types = my_types;
1524642ec226SSepherosa Ziehau 
1525642ec226SSepherosa Ziehau 	/*
1526642ec226SSepherosa Ziehau 	 * Detect RSS hash value/type confliction.
1527642ec226SSepherosa Ziehau 	 *
1528642ec226SSepherosa Ziehau 	 * NOTE:
1529642ec226SSepherosa Ziehau 	 * We don't disable the hash type, but stop delivery the hash
1530642ec226SSepherosa Ziehau 	 * value/type through mbufs on RX path.
15316f12c42eSSepherosa Ziehau 	 *
15326f12c42eSSepherosa Ziehau 	 * XXX If HN_CAP_UDPHASH is set in hn_caps, then UDP 4-tuple
15336f12c42eSSepherosa Ziehau 	 * hash is delivered with type of TCP_IPV4.  This means if
15346f12c42eSSepherosa Ziehau 	 * UDP_IPV4 is enabled, then TCP_IPV4 should be forced, at
15356f12c42eSSepherosa Ziehau 	 * least to hn_mbuf_hash.  However, given that _all_ of the
15366f12c42eSSepherosa Ziehau 	 * NICs implement TCP_IPV4, this will _not_ impose any issues
15376f12c42eSSepherosa Ziehau 	 * here.
1538642ec226SSepherosa Ziehau 	 */
1539642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV4) &&
1540642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1541642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV4 | RSS_TYPE_UDP_IPV4))) {
1542642ec226SSepherosa Ziehau 		/* Conflict; disable IPV4 hash type/value delivery. */
1543642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV4 mbuf hash delivery\n");
1544642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV4;
1545642ec226SSepherosa Ziehau 	}
1546642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6) &&
1547642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1548642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1549642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1550642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6_EX))) {
1551642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6 hash type/value delivery. */
1552642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6 mbuf hash delivery\n");
1553642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6;
1554642ec226SSepherosa Ziehau 	}
1555642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6_EX) &&
1556642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1557642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1558642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1559642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6))) {
1560642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6_EX hash type/value delivery. */
1561642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6_EX mbuf hash delivery\n");
1562642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6_EX;
1563642ec226SSepherosa Ziehau 	}
1564642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6) &&
1565642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6_EX)) {
1566642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6 hash type/value delivery. */
1567642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6 mbuf hash delivery\n");
1568642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6;
1569642ec226SSepherosa Ziehau 	}
1570642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6_EX) &&
1571642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6)) {
1572642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6_EX hash type/value delivery. */
1573642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6_EX mbuf hash delivery\n");
1574642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6_EX;
1575642ec226SSepherosa Ziehau 	}
1576642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6) &&
1577642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6_EX)) {
1578642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6 hash type/value delivery. */
1579642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6 mbuf hash delivery\n");
1580642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6;
1581642ec226SSepherosa Ziehau 	}
1582642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6_EX) &&
1583642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6)) {
1584642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6_EX hash type/value delivery. */
1585642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6_EX mbuf hash delivery\n");
1586642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6_EX;
1587642ec226SSepherosa Ziehau 	}
1588642ec226SSepherosa Ziehau 
1589642ec226SSepherosa Ziehau 	/*
1590642ec226SSepherosa Ziehau 	 * Indirect table does not matter.
1591642ec226SSepherosa Ziehau 	 */
1592642ec226SSepherosa Ziehau 
1593642ec226SSepherosa Ziehau 	sc->hn_rss_hash = (sc->hn_rss_hcap & NDIS_HASH_FUNCTION_MASK) |
1594642ec226SSepherosa Ziehau 	    hn_rss_type_tondis(my_types);
1595642ec226SSepherosa Ziehau 	memcpy(sc->hn_rss.rss_key, ifrk.ifrk_key, sizeof(sc->hn_rss.rss_key));
1596642ec226SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
1597642ec226SSepherosa Ziehau 
1598642ec226SSepherosa Ziehau 	if (reconf) {
1599642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1600642ec226SSepherosa Ziehau 		if (error) {
1601642ec226SSepherosa Ziehau 			/* XXX roll-back? */
1602642ec226SSepherosa Ziehau 			if_printf(ifp, "hn_rss_reconfig failed: %d\n", error);
1603642ec226SSepherosa Ziehau 			/* XXX keep going. */
1604642ec226SSepherosa Ziehau 		}
1605642ec226SSepherosa Ziehau 	}
1606642ec226SSepherosa Ziehau done:
1607642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1608642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, hn_rss_type_tondis(mbuf_types));
1609642ec226SSepherosa Ziehau }
1610642ec226SSepherosa Ziehau 
1611642ec226SSepherosa Ziehau static void
hn_vf_rss_restore(struct hn_softc * sc)1612642ec226SSepherosa Ziehau hn_vf_rss_restore(struct hn_softc *sc)
1613642ec226SSepherosa Ziehau {
1614642ec226SSepherosa Ziehau 
1615642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1616642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
16174db5958aSJustin Hibbits 	    ("%s: synthetic parts are not attached", if_name(sc->hn_ifp)));
1618642ec226SSepherosa Ziehau 
1619642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1)
1620642ec226SSepherosa Ziehau 		goto done;
1621642ec226SSepherosa Ziehau 
1622642ec226SSepherosa Ziehau 	/*
1623642ec226SSepherosa Ziehau 	 * Restore hash types.  Key does _not_ matter.
1624642ec226SSepherosa Ziehau 	 */
1625642ec226SSepherosa Ziehau 	if (sc->hn_rss_hash != sc->hn_rss_hcap) {
1626642ec226SSepherosa Ziehau 		int error;
1627642ec226SSepherosa Ziehau 
1628642ec226SSepherosa Ziehau 		sc->hn_rss_hash = sc->hn_rss_hcap;
1629642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1630642ec226SSepherosa Ziehau 		if (error) {
1631642ec226SSepherosa Ziehau 			if_printf(sc->hn_ifp, "hn_rss_reconfig failed: %d\n",
1632642ec226SSepherosa Ziehau 			    error);
1633642ec226SSepherosa Ziehau 			/* XXX keep going. */
1634642ec226SSepherosa Ziehau 		}
1635642ec226SSepherosa Ziehau 	}
1636642ec226SSepherosa Ziehau done:
1637642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1638642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, NDIS_HASH_ALL);
1639642ec226SSepherosa Ziehau }
1640642ec226SSepherosa Ziehau 
16419c6cae24SSepherosa Ziehau static void
hn_xpnt_vf_setready(struct hn_softc * sc)16429c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc)
16439c6cae24SSepherosa Ziehau {
16444db5958aSJustin Hibbits 	if_t ifp, vf_ifp;
16459c6cae24SSepherosa Ziehau 	struct ifreq ifr;
16469c6cae24SSepherosa Ziehau 
16479c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
16489c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
16499c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
16509c6cae24SSepherosa Ziehau 
16519c6cae24SSepherosa Ziehau 	/*
16529c6cae24SSepherosa Ziehau 	 * Mark the VF ready.
16539c6cae24SSepherosa Ziehau 	 */
16549c6cae24SSepherosa Ziehau 	sc->hn_vf_rdytick = 0;
16559c6cae24SSepherosa Ziehau 
16569c6cae24SSepherosa Ziehau 	/*
16579c6cae24SSepherosa Ziehau 	 * Save information for restoration.
16589c6cae24SSepherosa Ziehau 	 */
16594db5958aSJustin Hibbits 	sc->hn_saved_caps = if_getcapabilities(ifp);
16604db5958aSJustin Hibbits 	sc->hn_saved_tsomax = if_gethwtsomax(ifp);
16614db5958aSJustin Hibbits 	sc->hn_saved_tsosegcnt = if_gethwtsomaxsegcount(ifp);
16624db5958aSJustin Hibbits 	sc->hn_saved_tsosegsz = if_gethwtsomaxsegsize(ifp);
1663289ba6b8SWei Hu 	sc->hn_saved_capenable = if_getcapenable(ifp);
1664289ba6b8SWei Hu 	sc->hn_saved_hwassist = if_gethwassist(ifp);
16659c6cae24SSepherosa Ziehau 
16669c6cae24SSepherosa Ziehau 	/*
16679c6cae24SSepherosa Ziehau 	 * Intersect supported/enabled capabilities.
16689c6cae24SSepherosa Ziehau 	 *
16699c6cae24SSepherosa Ziehau 	 * NOTE:
16709c6cae24SSepherosa Ziehau 	 * if_hwassist is not changed here.
16719c6cae24SSepherosa Ziehau 	 */
16724db5958aSJustin Hibbits 	if_setcapabilitiesbit(ifp, 0, if_getcapabilities(vf_ifp));
16734db5958aSJustin Hibbits 	if_setcapenablebit(ifp, 0, if_getcapabilities(ifp));
16749c6cae24SSepherosa Ziehau 
16759c6cae24SSepherosa Ziehau 	/*
16769c6cae24SSepherosa Ziehau 	 * Fix TSO settings.
16779c6cae24SSepherosa Ziehau 	 */
16784db5958aSJustin Hibbits 	if (if_gethwtsomax(ifp) > if_gethwtsomax(vf_ifp))
16794db5958aSJustin Hibbits 		if_sethwtsomax(ifp, if_gethwtsomax(vf_ifp));
16804db5958aSJustin Hibbits 	if (if_gethwtsomaxsegcount(ifp) > if_gethwtsomaxsegcount(vf_ifp))
16814db5958aSJustin Hibbits 		if_sethwtsomaxsegcount(ifp, if_gethwtsomaxsegcount(vf_ifp));
16824db5958aSJustin Hibbits 	if (if_gethwtsomaxsegsize(ifp) > if_gethwtsomaxsegsize(vf_ifp))
16834db5958aSJustin Hibbits 		if_sethwtsomaxsegsize(ifp, if_gethwtsomaxsegsize(vf_ifp));
16849c6cae24SSepherosa Ziehau 
16859c6cae24SSepherosa Ziehau 	/*
16869c6cae24SSepherosa Ziehau 	 * Change VF's enabled capabilities.
16879c6cae24SSepherosa Ziehau 	 */
16889c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
16894db5958aSJustin Hibbits 	strlcpy(ifr.ifr_name, if_name(vf_ifp), sizeof(ifr.ifr_name));
16904db5958aSJustin Hibbits 	ifr.ifr_reqcap = if_getcapenable(ifp);
16919c6cae24SSepherosa Ziehau 	hn_xpnt_vf_iocsetcaps(sc, &ifr);
16929c6cae24SSepherosa Ziehau 
16934db5958aSJustin Hibbits 	if (if_getmtu(ifp) != ETHERMTU) {
16949c6cae24SSepherosa Ziehau 		int error;
16959c6cae24SSepherosa Ziehau 
16969c6cae24SSepherosa Ziehau 		/*
16979c6cae24SSepherosa Ziehau 		 * Change VF's MTU.
16989c6cae24SSepherosa Ziehau 		 */
16999c6cae24SSepherosa Ziehau 		memset(&ifr, 0, sizeof(ifr));
17004db5958aSJustin Hibbits 		strlcpy(ifr.ifr_name, if_name(vf_ifp), sizeof(ifr.ifr_name));
17014db5958aSJustin Hibbits 		ifr.ifr_mtu = if_getmtu(ifp);
17024db5958aSJustin Hibbits 		error = ifhwioctl(SIOCSIFMTU, vf_ifp, (caddr_t)&ifr, curthread);
17039c6cae24SSepherosa Ziehau 		if (error) {
17049c6cae24SSepherosa Ziehau 			if_printf(ifp, "%s SIOCSIFMTU %u failed\n",
17054db5958aSJustin Hibbits 			    if_name(vf_ifp), if_getmtu(ifp));
17064db5958aSJustin Hibbits 			if (if_getmtu(ifp) > ETHERMTU) {
17079c6cae24SSepherosa Ziehau 				if_printf(ifp, "change MTU to %d\n", ETHERMTU);
17089c6cae24SSepherosa Ziehau 
17099c6cae24SSepherosa Ziehau 				/*
17109c6cae24SSepherosa Ziehau 				 * XXX
17119c6cae24SSepherosa Ziehau 				 * No need to adjust the synthetic parts' MTU;
17129c6cae24SSepherosa Ziehau 				 * failure of the adjustment will cause us
17139c6cae24SSepherosa Ziehau 				 * infinite headache.
17149c6cae24SSepherosa Ziehau 				 */
17154db5958aSJustin Hibbits 				if_setmtu(ifp, ETHERMTU);
17169c6cae24SSepherosa Ziehau 				hn_mtu_change_fixup(sc);
17179c6cae24SSepherosa Ziehau 			}
17189c6cae24SSepherosa Ziehau 		}
17199c6cae24SSepherosa Ziehau 	}
17209c6cae24SSepherosa Ziehau }
17219c6cae24SSepherosa Ziehau 
17229c6cae24SSepherosa Ziehau static bool
hn_xpnt_vf_isready(struct hn_softc * sc)17239c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc)
17249c6cae24SSepherosa Ziehau {
17259c6cae24SSepherosa Ziehau 
17269c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
17279c6cae24SSepherosa Ziehau 
17289c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL)
17299c6cae24SSepherosa Ziehau 		return (false);
17309c6cae24SSepherosa Ziehau 
17319c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick == 0)
17329c6cae24SSepherosa Ziehau 		return (true);
17339c6cae24SSepherosa Ziehau 
17349c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick > ticks)
17359c6cae24SSepherosa Ziehau 		return (false);
17369c6cae24SSepherosa Ziehau 
17379c6cae24SSepherosa Ziehau 	/* Mark VF as ready. */
17389c6cae24SSepherosa Ziehau 	hn_xpnt_vf_setready(sc);
17399c6cae24SSepherosa Ziehau 	return (true);
17409c6cae24SSepherosa Ziehau }
17419c6cae24SSepherosa Ziehau 
17429c6cae24SSepherosa Ziehau static void
hn_xpnt_vf_setenable(struct hn_softc * sc)1743a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc)
1744a97fff19SSepherosa Ziehau {
1745a97fff19SSepherosa Ziehau 	int i;
1746a97fff19SSepherosa Ziehau 
1747a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1748a97fff19SSepherosa Ziehau 
1749a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1750a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1751a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED;
1752a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1753a97fff19SSepherosa Ziehau 
1754a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1755a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF;
1756a97fff19SSepherosa Ziehau }
1757a97fff19SSepherosa Ziehau 
1758a97fff19SSepherosa Ziehau static void
hn_xpnt_vf_setdisable(struct hn_softc * sc,bool clear_vf)1759a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf)
1760a97fff19SSepherosa Ziehau {
1761a97fff19SSepherosa Ziehau 	int i;
1762a97fff19SSepherosa Ziehau 
1763a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1764a97fff19SSepherosa Ziehau 
1765a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1766a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1767a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED;
1768a97fff19SSepherosa Ziehau 	if (clear_vf)
1769a97fff19SSepherosa Ziehau 		sc->hn_vf_ifp = NULL;
1770a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1771a97fff19SSepherosa Ziehau 
1772a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1773a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF;
1774a97fff19SSepherosa Ziehau }
1775a97fff19SSepherosa Ziehau 
1776a97fff19SSepherosa Ziehau static void
hn_xpnt_vf_init(struct hn_softc * sc)17779c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc)
17789c6cae24SSepherosa Ziehau {
17799c6cae24SSepherosa Ziehau 	int error;
17809c6cae24SSepherosa Ziehau 
17819c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
17829c6cae24SSepherosa Ziehau 
17839c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
17844db5958aSJustin Hibbits 	    ("%s: transparent VF was enabled", if_name(sc->hn_ifp)));
17859c6cae24SSepherosa Ziehau 
17869c6cae24SSepherosa Ziehau 	if (bootverbose) {
17879c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "try bringing up %s\n",
17884db5958aSJustin Hibbits 		    if_name(sc->hn_vf_ifp));
17899c6cae24SSepherosa Ziehau 	}
17909c6cae24SSepherosa Ziehau 
17919c6cae24SSepherosa Ziehau 	/*
17929c6cae24SSepherosa Ziehau 	 * Bring the VF up.
17939c6cae24SSepherosa Ziehau 	 */
17949c6cae24SSepherosa Ziehau 	hn_xpnt_vf_saveifflags(sc);
17954db5958aSJustin Hibbits 	if_setflagbits(sc->hn_ifp, IFF_UP, 0);
17969c6cae24SSepherosa Ziehau 	error = hn_xpnt_vf_iocsetflags(sc);
17979c6cae24SSepherosa Ziehau 	if (error) {
17989c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "bringing up %s failed: %d\n",
17994db5958aSJustin Hibbits 		    if_name(sc->hn_vf_ifp), error);
18009c6cae24SSepherosa Ziehau 		return;
18019c6cae24SSepherosa Ziehau 	}
18029c6cae24SSepherosa Ziehau 
18039c6cae24SSepherosa Ziehau 	/*
18049c6cae24SSepherosa Ziehau 	 * NOTE:
18059c6cae24SSepherosa Ziehau 	 * Datapath setting must happen _after_ bringing the VF up.
18069c6cae24SSepherosa Ziehau 	 */
18079c6cae24SSepherosa Ziehau 	hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
18089c6cae24SSepherosa Ziehau 
1809642ec226SSepherosa Ziehau 	/*
1810642ec226SSepherosa Ziehau 	 * NOTE:
1811642ec226SSepherosa Ziehau 	 * Fixup RSS related bits _after_ the VF is brought up, since
1812642ec226SSepherosa Ziehau 	 * many VFs generate RSS key during it's initialization.
1813642ec226SSepherosa Ziehau 	 */
1814642ec226SSepherosa Ziehau 	hn_vf_rss_fixup(sc, true);
1815642ec226SSepherosa Ziehau 
1816a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as enabled. */
1817a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setenable(sc);
18189c6cae24SSepherosa Ziehau }
18199c6cae24SSepherosa Ziehau 
18209c6cae24SSepherosa Ziehau static void
hn_xpnt_vf_init_taskfunc(void * xsc,int pending __unused)18219c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused)
18229c6cae24SSepherosa Ziehau {
18239c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
18249c6cae24SSepherosa Ziehau 
18259c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
18269c6cae24SSepherosa Ziehau 
18279c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
18289c6cae24SSepherosa Ziehau 		goto done;
18299c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
18309c6cae24SSepherosa Ziehau 		goto done;
18319c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
18329c6cae24SSepherosa Ziehau 		goto done;
18339c6cae24SSepherosa Ziehau 
18349c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick != 0) {
18359c6cae24SSepherosa Ziehau 		/* Mark VF as ready. */
18369c6cae24SSepherosa Ziehau 		hn_xpnt_vf_setready(sc);
18379c6cae24SSepherosa Ziehau 	}
18389c6cae24SSepherosa Ziehau 
18394db5958aSJustin Hibbits 	if (if_getdrvflags(sc->hn_ifp) & IFF_DRV_RUNNING) {
18409c6cae24SSepherosa Ziehau 		/*
18419c6cae24SSepherosa Ziehau 		 * Delayed VF initialization.
18429c6cae24SSepherosa Ziehau 		 */
18439c6cae24SSepherosa Ziehau 		if (bootverbose) {
18449c6cae24SSepherosa Ziehau 			if_printf(sc->hn_ifp, "delayed initialize %s\n",
18454db5958aSJustin Hibbits 			    if_name(sc->hn_vf_ifp));
18469c6cae24SSepherosa Ziehau 		}
18479c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
18489c6cae24SSepherosa Ziehau 	}
18499c6cae24SSepherosa Ziehau done:
18509c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
18519c6cae24SSepherosa Ziehau }
18529c6cae24SSepherosa Ziehau 
1853499c3e17SSepherosa Ziehau static void
hn_ifnet_attevent(void * xsc,if_t ifp)18544db5958aSJustin Hibbits hn_ifnet_attevent(void *xsc, if_t ifp)
1855499c3e17SSepherosa Ziehau {
1856499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1857499c3e17SSepherosa Ziehau 
1858499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1859499c3e17SSepherosa Ziehau 
1860499c3e17SSepherosa Ziehau 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
1861499c3e17SSepherosa Ziehau 		goto done;
1862499c3e17SSepherosa Ziehau 
1863499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1864499c3e17SSepherosa Ziehau 		goto done;
1865499c3e17SSepherosa Ziehau 
1866499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp != NULL) {
1867499c3e17SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s was attached as VF\n",
18684db5958aSJustin Hibbits 		    if_name(sc->hn_vf_ifp));
1869499c3e17SSepherosa Ziehau 		goto done;
1870499c3e17SSepherosa Ziehau 	}
1871499c3e17SSepherosa Ziehau 
18724db5958aSJustin Hibbits 	if (hn_xpnt_vf && if_getstartfn(ifp) != NULL) {
18739c6cae24SSepherosa Ziehau 		/*
18749c6cae24SSepherosa Ziehau 		 * ifnet.if_start is _not_ supported by transparent
18759c6cae24SSepherosa Ziehau 		 * mode VF; mainly due to the IFF_DRV_OACTIVE flag.
18769c6cae24SSepherosa Ziehau 		 */
18779c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported "
18784db5958aSJustin Hibbits 		    "in transparent VF mode.\n", if_name(sc->hn_vf_ifp));
18794db5958aSJustin Hibbits 
18809c6cae24SSepherosa Ziehau 		goto done;
18819c6cae24SSepherosa Ziehau 	}
18829c6cae24SSepherosa Ziehau 
1883499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1884499c3e17SSepherosa Ziehau 
18854db5958aSJustin Hibbits 	if (if_getindex(ifp) >= hn_vfmap_size) {
18864db5958aSJustin Hibbits 		if_t *newmap;
1887499c3e17SSepherosa Ziehau 		int newsize;
1888499c3e17SSepherosa Ziehau 
18894db5958aSJustin Hibbits 		newsize = if_getindex(ifp) + HN_VFMAP_SIZE_DEF;
18904db5958aSJustin Hibbits 		newmap = malloc(sizeof(if_t) * newsize, M_DEVBUF,
1891499c3e17SSepherosa Ziehau 		    M_WAITOK | M_ZERO);
1892499c3e17SSepherosa Ziehau 
1893499c3e17SSepherosa Ziehau 		memcpy(newmap, hn_vfmap,
18944db5958aSJustin Hibbits 		    sizeof(if_t) * hn_vfmap_size);
1895499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
1896499c3e17SSepherosa Ziehau 		hn_vfmap = newmap;
1897499c3e17SSepherosa Ziehau 		hn_vfmap_size = newsize;
1898499c3e17SSepherosa Ziehau 	}
18994db5958aSJustin Hibbits 	KASSERT(hn_vfmap[if_getindex(ifp)] == NULL,
1900499c3e17SSepherosa Ziehau 	    ("%s: ifindex %d was mapped to %s",
19014db5958aSJustin Hibbits 	     if_name(ifp), if_getindex(ifp), if_name(hn_vfmap[if_getindex(ifp)])));
19024db5958aSJustin Hibbits 	hn_vfmap[if_getindex(ifp)] = sc->hn_ifp;
1903499c3e17SSepherosa Ziehau 
1904499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1905499c3e17SSepherosa Ziehau 
19069c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
19079c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
19089c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
19094db5958aSJustin Hibbits 	    ("%s: transparent VF was enabled", if_name(sc->hn_ifp)));
1910499c3e17SSepherosa Ziehau 	sc->hn_vf_ifp = ifp;
19119c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
19129c6cae24SSepherosa Ziehau 
19139c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
19149c6cae24SSepherosa Ziehau 		int wait_ticks;
19159c6cae24SSepherosa Ziehau 
19169c6cae24SSepherosa Ziehau 		/*
19179c6cae24SSepherosa Ziehau 		 * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp.
19189c6cae24SSepherosa Ziehau 		 * Save vf_ifp's current if_input for later restoration.
19199c6cae24SSepherosa Ziehau 		 */
19204db5958aSJustin Hibbits 		sc->hn_vf_input = if_getinputfn(ifp);
19214db5958aSJustin Hibbits 		if_setinputfn(ifp, hn_xpnt_vf_input);
19229c6cae24SSepherosa Ziehau 
19239c6cae24SSepherosa Ziehau 		/*
19249c6cae24SSepherosa Ziehau 		 * Stop link status management; use the VF's.
19259c6cae24SSepherosa Ziehau 		 */
19269c6cae24SSepherosa Ziehau 		hn_suspend_mgmt(sc);
19279c6cae24SSepherosa Ziehau 
19289c6cae24SSepherosa Ziehau 		/*
19299c6cae24SSepherosa Ziehau 		 * Give VF sometime to complete its attach routing.
19309c6cae24SSepherosa Ziehau 		 */
19319c6cae24SSepherosa Ziehau 		wait_ticks = hn_xpnt_vf_attwait * hz;
19329c6cae24SSepherosa Ziehau 		sc->hn_vf_rdytick = ticks + wait_ticks;
19339c6cae24SSepherosa Ziehau 
19349c6cae24SSepherosa Ziehau 		taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init,
19359c6cae24SSepherosa Ziehau 		    wait_ticks);
19369c6cae24SSepherosa Ziehau 	}
1937499c3e17SSepherosa Ziehau done:
1938499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1939499c3e17SSepherosa Ziehau }
1940499c3e17SSepherosa Ziehau 
1941499c3e17SSepherosa Ziehau static void
hn_ifnet_detevent(void * xsc,if_t ifp)19424db5958aSJustin Hibbits hn_ifnet_detevent(void *xsc, if_t ifp)
1943499c3e17SSepherosa Ziehau {
1944499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1945499c3e17SSepherosa Ziehau 
1946499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1947499c3e17SSepherosa Ziehau 
1948499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
1949499c3e17SSepherosa Ziehau 		goto done;
1950499c3e17SSepherosa Ziehau 
1951499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1952499c3e17SSepherosa Ziehau 		goto done;
1953499c3e17SSepherosa Ziehau 
19549c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
19559c6cae24SSepherosa Ziehau 		/*
19569c6cae24SSepherosa Ziehau 		 * Make sure that the delayed initialization is not running.
19579c6cae24SSepherosa Ziehau 		 *
19589c6cae24SSepherosa Ziehau 		 * NOTE:
19599c6cae24SSepherosa Ziehau 		 * - This lock _must_ be released, since the hn_vf_init task
19609c6cae24SSepherosa Ziehau 		 *   will try holding this lock.
19619c6cae24SSepherosa Ziehau 		 * - It is safe to release this lock here, since the
19629c6cae24SSepherosa Ziehau 		 *   hn_ifnet_attevent() is interlocked by the hn_vf_ifp.
19639c6cae24SSepherosa Ziehau 		 *
19649c6cae24SSepherosa Ziehau 		 * XXX racy, if hn(4) ever detached.
19659c6cae24SSepherosa Ziehau 		 */
19669c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
19679c6cae24SSepherosa Ziehau 		taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init);
19689c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
19699c6cae24SSepherosa Ziehau 
19709c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved",
19714db5958aSJustin Hibbits 		    if_name(sc->hn_ifp)));
19724db5958aSJustin Hibbits 		if_setinputfn(ifp, sc->hn_vf_input);
19739c6cae24SSepherosa Ziehau 		sc->hn_vf_input = NULL;
19749c6cae24SSepherosa Ziehau 
1975642ec226SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) &&
1976642ec226SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED))
19779c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
19789c6cae24SSepherosa Ziehau 
19799c6cae24SSepherosa Ziehau 		if (sc->hn_vf_rdytick == 0) {
19809c6cae24SSepherosa Ziehau 			/*
19819c6cae24SSepherosa Ziehau 			 * The VF was ready; restore some settings.
19829c6cae24SSepherosa Ziehau 			 */
19834db5958aSJustin Hibbits 			if_setcapabilities(ifp, sc->hn_saved_caps);
1984289ba6b8SWei Hu 
19854db5958aSJustin Hibbits 			if_sethwtsomax(ifp, sc->hn_saved_tsomax);
19864db5958aSJustin Hibbits 			if_sethwtsomaxsegcount(sc->hn_ifp,
19874db5958aSJustin Hibbits 			    sc->hn_saved_tsosegcnt);
19884db5958aSJustin Hibbits 			if_sethwtsomaxsegsize(ifp, sc->hn_saved_tsosegsz);
1989289ba6b8SWei Hu 
1990289ba6b8SWei Hu 			if_setcapenable(ifp, sc->hn_saved_capenable);
1991289ba6b8SWei Hu 			if_sethwassist(ifp, sc->hn_saved_hwassist);
19929c6cae24SSepherosa Ziehau 		}
19939c6cae24SSepherosa Ziehau 
1994642ec226SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
1995642ec226SSepherosa Ziehau 			/*
1996642ec226SSepherosa Ziehau 			 * Restore RSS settings.
1997642ec226SSepherosa Ziehau 			 */
1998642ec226SSepherosa Ziehau 			hn_vf_rss_restore(sc);
1999642ec226SSepherosa Ziehau 
20009c6cae24SSepherosa Ziehau 			/*
20019c6cae24SSepherosa Ziehau 			 * Resume link status management, which was suspended
20029c6cae24SSepherosa Ziehau 			 * by hn_ifnet_attevent().
20039c6cae24SSepherosa Ziehau 			 */
20049c6cae24SSepherosa Ziehau 			hn_resume_mgmt(sc);
20059c6cae24SSepherosa Ziehau 		}
2006642ec226SSepherosa Ziehau 	}
20079c6cae24SSepherosa Ziehau 
2008a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as disabled. */
2009a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */);
2010499c3e17SSepherosa Ziehau 
2011499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
2012499c3e17SSepherosa Ziehau 
20134db5958aSJustin Hibbits 	KASSERT(if_getindex(ifp) < hn_vfmap_size,
20144db5958aSJustin Hibbits 	    ("ifindex %d, vfmapsize %d", if_getindex(ifp), hn_vfmap_size));
20154db5958aSJustin Hibbits 	if (hn_vfmap[if_getindex(ifp)] != NULL) {
20164db5958aSJustin Hibbits 		KASSERT(hn_vfmap[if_getindex(ifp)] == sc->hn_ifp,
2017499c3e17SSepherosa Ziehau 		    ("%s: ifindex %d was mapped to %s",
20184db5958aSJustin Hibbits 		     if_name(ifp), if_getindex(ifp),
20194db5958aSJustin Hibbits 		     if_name(hn_vfmap[if_getindex(ifp)])));
20204db5958aSJustin Hibbits 		hn_vfmap[if_getindex(ifp)] = NULL;
2021499c3e17SSepherosa Ziehau 	}
2022499c3e17SSepherosa Ziehau 
2023499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
2024499c3e17SSepherosa Ziehau done:
2025499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
2026499c3e17SSepherosa Ziehau }
2027499c3e17SSepherosa Ziehau 
20289c6cae24SSepherosa Ziehau static void
hn_ifnet_lnkevent(void * xsc,if_t ifp,int link_state)20294db5958aSJustin Hibbits hn_ifnet_lnkevent(void *xsc, if_t ifp, int link_state)
20309c6cae24SSepherosa Ziehau {
20319c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
20329c6cae24SSepherosa Ziehau 
20339c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == ifp)
20349c6cae24SSepherosa Ziehau 		if_link_state_change(sc->hn_ifp, link_state);
20359c6cae24SSepherosa Ziehau }
20369c6cae24SSepherosa Ziehau 
203715516c77SSepherosa Ziehau static int
hn_tsomax_sysctl(SYSCTL_HANDLER_ARGS)20384db5958aSJustin Hibbits hn_tsomax_sysctl(SYSCTL_HANDLER_ARGS)
20394db5958aSJustin Hibbits {
20404db5958aSJustin Hibbits 	struct hn_softc *sc = arg1;
20414db5958aSJustin Hibbits 	unsigned int tsomax;
20424db5958aSJustin Hibbits 	int error;
20434db5958aSJustin Hibbits 
20444db5958aSJustin Hibbits 	tsomax = if_gethwtsomax(sc->hn_ifp);
20454db5958aSJustin Hibbits 	error = sysctl_handle_int(oidp, &tsomax, 0, req);
20464db5958aSJustin Hibbits 	return error;
20474db5958aSJustin Hibbits }
20484db5958aSJustin Hibbits 
20494db5958aSJustin Hibbits static int
hn_tsomaxsegcnt_sysctl(SYSCTL_HANDLER_ARGS)20504db5958aSJustin Hibbits hn_tsomaxsegcnt_sysctl(SYSCTL_HANDLER_ARGS)
20514db5958aSJustin Hibbits {
20524db5958aSJustin Hibbits 	struct hn_softc *sc = arg1;
20534db5958aSJustin Hibbits 	unsigned int tsomaxsegcnt;
20544db5958aSJustin Hibbits 	int error;
20554db5958aSJustin Hibbits 
20564db5958aSJustin Hibbits 	tsomaxsegcnt = if_gethwtsomaxsegcount(sc->hn_ifp);
20574db5958aSJustin Hibbits 	error = sysctl_handle_int(oidp, &tsomaxsegcnt, 0, req);
20584db5958aSJustin Hibbits 	return error;
20594db5958aSJustin Hibbits }
20604db5958aSJustin Hibbits 
20614db5958aSJustin Hibbits static int
hn_tsomaxsegsz_sysctl(SYSCTL_HANDLER_ARGS)20624db5958aSJustin Hibbits hn_tsomaxsegsz_sysctl(SYSCTL_HANDLER_ARGS)
20634db5958aSJustin Hibbits {
20644db5958aSJustin Hibbits 	struct hn_softc *sc = arg1;
20654db5958aSJustin Hibbits 	unsigned int tsomaxsegsz;
20664db5958aSJustin Hibbits 	int error;
20674db5958aSJustin Hibbits 
20684db5958aSJustin Hibbits 	tsomaxsegsz = if_gethwtsomaxsegsize(sc->hn_ifp);
20694db5958aSJustin Hibbits 	error = sysctl_handle_int(oidp, &tsomaxsegsz, 0, req);
20704db5958aSJustin Hibbits 	return error;
20714db5958aSJustin Hibbits }
20724db5958aSJustin Hibbits 
20734db5958aSJustin Hibbits static int
hn_probe(device_t dev)207415516c77SSepherosa Ziehau hn_probe(device_t dev)
207515516c77SSepherosa Ziehau {
207615516c77SSepherosa Ziehau 
2077c2d50b26SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) {
207815516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
207915516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
208015516c77SSepherosa Ziehau 	}
208115516c77SSepherosa Ziehau 	return ENXIO;
208215516c77SSepherosa Ziehau }
208315516c77SSepherosa Ziehau 
208415516c77SSepherosa Ziehau static int
hn_attach(device_t dev)208515516c77SSepherosa Ziehau hn_attach(device_t dev)
208615516c77SSepherosa Ziehau {
208715516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
208815516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
208915516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
209015516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
20914db5958aSJustin Hibbits 	if_t ifp = NULL;
209215516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
2093eb2fe044SSepherosa Ziehau 	uint32_t mtu;
209415516c77SSepherosa Ziehau 
209515516c77SSepherosa Ziehau 	sc->hn_dev = dev;
209615516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
209715516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
20989c6cae24SSepherosa Ziehau 	rm_init(&sc->hn_vf_lock, "hnvf");
20999c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_xpnt_vf_accbpf)
21009c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
210115516c77SSepherosa Ziehau 
210215516c77SSepherosa Ziehau 	/*
2103dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
2104dc13fee6SSepherosa Ziehau 	 */
2105dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
2106dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
2107dc13fee6SSepherosa Ziehau 
2108dc13fee6SSepherosa Ziehau 	/*
210915516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
211015516c77SSepherosa Ziehau 	 */
21110e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
2112fdd0222aSSepherosa Ziehau 		int i;
2113fdd0222aSSepherosa Ziehau 
2114fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
2115fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
2116fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
2117fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
2118fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
2119fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
2120fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
2121fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
2122fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
2123fdd0222aSSepherosa Ziehau 		}
21240e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
2125fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
212615516c77SSepherosa Ziehau 	}
212715516c77SSepherosa Ziehau 
212815516c77SSepherosa Ziehau 	/*
212915516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
213015516c77SSepherosa Ziehau 	 */
213115516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
213215516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
213315516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
213415516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
213515516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
213615516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
213715516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
213815516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
213915516c77SSepherosa Ziehau 
21409c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
21419c6cae24SSepherosa Ziehau 		/*
21429c6cae24SSepherosa Ziehau 		 * Setup taskqueue for VF tasks, e.g. delayed VF bringing up.
21439c6cae24SSepherosa Ziehau 		 */
21449c6cae24SSepherosa Ziehau 		sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK,
21459c6cae24SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_vf_taskq);
21469c6cae24SSepherosa Ziehau 		taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf",
21479c6cae24SSepherosa Ziehau 		    device_get_nameunit(dev));
21489c6cae24SSepherosa Ziehau 		TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0,
21499c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_init_taskfunc, sc);
21509c6cae24SSepherosa Ziehau 	}
21519c6cae24SSepherosa Ziehau 
215215516c77SSepherosa Ziehau 	/*
215315516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
215415516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
215515516c77SSepherosa Ziehau 	 * ether_ifattach().
215615516c77SSepherosa Ziehau 	 */
215715516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
21584db5958aSJustin Hibbits 	if_setsoftc(ifp, sc);
215915516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
216015516c77SSepherosa Ziehau 
216115516c77SSepherosa Ziehau 	/*
216215516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
216315516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
216415516c77SSepherosa Ziehau 	 */
216515516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
216615516c77SSepherosa Ziehau 
216715516c77SSepherosa Ziehau 	/*
216815516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
216915516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
217015516c77SSepherosa Ziehau 	 *
217115516c77SSepherosa Ziehau 	 * NOTE:
217215516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
217315516c77SSepherosa Ziehau 	 */
217415516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
217515516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
217615516c77SSepherosa Ziehau 		/* Default */
217715516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
217815516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
217915516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
218015516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
218115516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
218215516c77SSepherosa Ziehau 	}
218334d68912SSepherosa Ziehau #ifdef RSS
218434d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
218534d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
218634d68912SSepherosa Ziehau #endif
218715516c77SSepherosa Ziehau 
218815516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
218915516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
219015516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
219123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
219215516c77SSepherosa Ziehau 	if (hn_use_if_start) {
219315516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
219415516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
219515516c77SSepherosa Ziehau 	}
219623bf9e15SSepherosa Ziehau #endif
219715516c77SSepherosa Ziehau 
219815516c77SSepherosa Ziehau 	/*
219915516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
220015516c77SSepherosa Ziehau 	 */
220115516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
220215516c77SSepherosa Ziehau 
220315516c77SSepherosa Ziehau 	/*
220415516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
220515516c77SSepherosa Ziehau 	 * channels can be allocated.
220615516c77SSepherosa Ziehau 	 */
220715516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
220815516c77SSepherosa Ziehau 	if (error)
220915516c77SSepherosa Ziehau 		goto failed;
221015516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
221115516c77SSepherosa Ziehau 	if (error)
221215516c77SSepherosa Ziehau 		goto failed;
221315516c77SSepherosa Ziehau 
221415516c77SSepherosa Ziehau 	/*
221515516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
221615516c77SSepherosa Ziehau 	 */
221715516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
221815516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
221925641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
222025641fc7SSepherosa Ziehau 		error = ENXIO;
222115516c77SSepherosa Ziehau 		goto failed;
222225641fc7SSepherosa Ziehau 	}
222325641fc7SSepherosa Ziehau 
222425641fc7SSepherosa Ziehau 	/*
222525641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
222625641fc7SSepherosa Ziehau 	 * primary channel.
222725641fc7SSepherosa Ziehau 	 *
222825641fc7SSepherosa Ziehau 	 * NOTE:
222925641fc7SSepherosa Ziehau 	 * The processing order is critical here:
223025641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
223125641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
223225641fc7SSepherosa Ziehau 	 */
223325641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
223425641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
223525641fc7SSepherosa Ziehau 		error = ENXIO;
223625641fc7SSepherosa Ziehau 		goto failed;
223725641fc7SSepherosa Ziehau 	}
223815516c77SSepherosa Ziehau 
223915516c77SSepherosa Ziehau 	/*
224015516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
224115516c77SSepherosa Ziehau 	 */
224215516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
224315516c77SSepherosa Ziehau 	if (error)
224415516c77SSepherosa Ziehau 		goto failed;
224515516c77SSepherosa Ziehau 
224615516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
224715516c77SSepherosa Ziehau 	if (error)
224815516c77SSepherosa Ziehau 		goto failed;
224915516c77SSepherosa Ziehau 
2250eb2fe044SSepherosa Ziehau 	error = hn_rndis_get_mtu(sc, &mtu);
2251eb2fe044SSepherosa Ziehau 	if (error)
2252eb2fe044SSepherosa Ziehau 		mtu = ETHERMTU;
2253eb2fe044SSepherosa Ziehau 	else if (bootverbose)
2254eb2fe044SSepherosa Ziehau 		device_printf(dev, "RNDIS mtu %u\n", mtu);
2255eb2fe044SSepherosa Ziehau 
225615516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
225715516c77SSepherosa Ziehau 		/*
225815516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
225915516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
226015516c77SSepherosa Ziehau 		 */
226115516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
226215516c77SSepherosa Ziehau 	}
226315516c77SSepherosa Ziehau 
226415516c77SSepherosa Ziehau 	/*
2265db76829bSSepherosa Ziehau 	 * Fixup TX/RX stuffs after synthetic parts are attached.
226615516c77SSepherosa Ziehau 	 */
226715516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
2268db76829bSSepherosa Ziehau 	hn_fixup_rx_data(sc);
226915516c77SSepherosa Ziehau 
227015516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
227115516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
227215516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
227315516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
227415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
227515516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
227615516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
227715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
227815516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
227915516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
228015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
228115516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
228215516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
22834db5958aSJustin Hibbits 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tso_max",
22844db5958aSJustin Hibbits 	    CTLTYPE_UINT | CTLFLAG_RD, sc, 0, hn_tsomax_sysctl,
22854db5958aSJustin Hibbits 	    "IU", "max TSO size");
22864db5958aSJustin Hibbits 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tso_maxsegcnt",
22874db5958aSJustin Hibbits 	    CTLTYPE_UINT | CTLFLAG_RD, sc, 0, hn_tsomaxsegcnt_sysctl,
22884db5958aSJustin Hibbits 	    "IU", "max # of TSO segments");
22894db5958aSJustin Hibbits 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tso_maxsegsz",
22904db5958aSJustin Hibbits 	    CTLTYPE_UINT | CTLFLAG_RD, sc, 0, hn_tsomaxsegsz_sysctl,
22914db5958aSJustin Hibbits 	    "IU", "max size of TSO segment");
229215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
229315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
229415516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
229515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
229615516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
229715516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
2298642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hashcap",
2299642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2300642ec226SSepherosa Ziehau 	    hn_rss_hcap_sysctl, "A", "RSS hash capabilities");
2301642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "mbuf_hash",
2302642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2303642ec226SSepherosa Ziehau 	    hn_rss_mbuf_sysctl, "A", "RSS hash for mbufs");
230415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
230515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
230634d68912SSepherosa Ziehau #ifndef RSS
230734d68912SSepherosa Ziehau 	/*
230834d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
230934d68912SSepherosa Ziehau 	 */
231015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
231115516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
231215516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
231315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
231415516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
231515516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
231634d68912SSepherosa Ziehau #endif
2317dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
2318dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
2319dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
2320dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
2321dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
2322dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
2323dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
2324dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
2325dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
2326dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
2327dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2328dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
2329dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
2330dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
2331dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2332dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
2333dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
2334dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
23356c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
23366c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23376c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
23386c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
233940d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
234040d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
234140d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
23429c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
2343499c3e17SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf",
2344499c3e17SSepherosa Ziehau 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2345499c3e17SSepherosa Ziehau 		    hn_rxvf_sysctl, "A", "activated Virtual Function's name");
23469c6cae24SSepherosa Ziehau 	} else {
23479c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled",
23489c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
23499c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_enabled_sysctl, "I",
23509c6cae24SSepherosa Ziehau 		    "Transparent VF enabled");
23519c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf",
23529c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23539c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_accbpf_sysctl, "I",
23549c6cae24SSepherosa Ziehau 		    "Accurate BPF for transparent VF");
23559c6cae24SSepherosa Ziehau 	}
235615516c77SSepherosa Ziehau 
235780c3eb7bSWei Hu 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rsc_switch",
2358*da1deb78SWei Hu 	    CTLTYPE_UINT | CTLFLAG_RW, sc, 0, hn_rsc_sysctl, "I",
235980c3eb7bSWei Hu 	    "switch to rsc");
236080c3eb7bSWei Hu 
236115516c77SSepherosa Ziehau 	/*
236215516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
236315516c77SSepherosa Ziehau 	 */
236415516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
236515516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
236615516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
236715516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
236815516c77SSepherosa Ziehau 
236915516c77SSepherosa Ziehau 	/*
237015516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
237115516c77SSepherosa Ziehau 	 */
237215516c77SSepherosa Ziehau 
23734db5958aSJustin Hibbits 	if_setbaudrate(ifp, IF_Gbps(10));
23744db5958aSJustin Hibbits 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
23754db5958aSJustin Hibbits 	if_setioctlfn(ifp, hn_ioctl);
23764db5958aSJustin Hibbits 	if_setinitfn(ifp, hn_init);
237723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
237815516c77SSepherosa Ziehau 	if (hn_use_if_start) {
237915516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
238015516c77SSepherosa Ziehau 
23814db5958aSJustin Hibbits 		if_setstartfn(ifp, hn_start);
23824db5958aSJustin Hibbits 		if_setsendqlen(ifp, qdepth);
23834db5958aSJustin Hibbits 		if_setsendqready(ifp);
238423bf9e15SSepherosa Ziehau 	} else
238523bf9e15SSepherosa Ziehau #endif
238623bf9e15SSepherosa Ziehau 	{
23874db5958aSJustin Hibbits 		if_settransmitfn(ifp, hn_transmit);
23884db5958aSJustin Hibbits 		if_setqflushfn(ifp, hn_xmit_qflush);
238915516c77SSepherosa Ziehau 	}
239015516c77SSepherosa Ziehau 
23914db5958aSJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE, 0);
239215516c77SSepherosa Ziehau #ifdef foo
239315516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
23944db5958aSJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_RXCSUM_IPV6, 0);
239515516c77SSepherosa Ziehau #endif
239615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
239715516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
23984db5958aSJustin Hibbits 		if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU, 0);
239915516c77SSepherosa Ziehau 	}
240015516c77SSepherosa Ziehau 
24014db5958aSJustin Hibbits 	if_sethwassist(ifp, sc->hn_tx_ring[0].hn_csum_assist);
24024db5958aSJustin Hibbits 	if (if_gethwassist(ifp) & HN_CSUM_IP_MASK)
24034db5958aSJustin Hibbits 		if_setcapabilitiesbit(ifp, IFCAP_TXCSUM, 0);
24044db5958aSJustin Hibbits 	if (if_gethwassist(ifp) & HN_CSUM_IP6_MASK)
24054db5958aSJustin Hibbits 		if_setcapabilitiesbit(ifp, IFCAP_TXCSUM_IPV6, 0);
240615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
24074db5958aSJustin Hibbits 		if_setcapabilitiesbit(ifp, IFCAP_TSO4, 0);
24084db5958aSJustin Hibbits 		if_sethwassistbits(ifp, CSUM_IP_TSO, 0);
240915516c77SSepherosa Ziehau 	}
241015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
24114db5958aSJustin Hibbits 		if_setcapabilitiesbit(ifp, IFCAP_TSO6, 0);
24124db5958aSJustin Hibbits 		if_sethwassistbits(ifp, CSUM_IP6_TSO, 0);
241315516c77SSepherosa Ziehau 	}
241415516c77SSepherosa Ziehau 
241515516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
24164db5958aSJustin Hibbits 	if_setcapenable(ifp, if_getcapabilities(ifp));
241715516c77SSepherosa Ziehau 
24187960e6baSSepherosa Ziehau 	/*
24197960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
24207960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
24217960e6baSSepherosa Ziehau 	 */
24224db5958aSJustin Hibbits 	if_setcapenablebit(ifp, 0, (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6));
24234db5958aSJustin Hibbits 	if_sethwassistbits(ifp, 0, (HN_CSUM_IP6_MASK | CSUM_IP6_TSO));
24247960e6baSSepherosa Ziehau 
24254db5958aSJustin Hibbits 	if (if_getcapabilities(ifp) & (IFCAP_TSO6 | IFCAP_TSO4)) {
24269c6cae24SSepherosa Ziehau 		/*
24279c6cae24SSepherosa Ziehau 		 * Lock hn_set_tso_maxsize() to simplify its
24289c6cae24SSepherosa Ziehau 		 * internal logic.
24299c6cae24SSepherosa Ziehau 		 */
24309c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
243115516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
24329c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
24334db5958aSJustin Hibbits 		if_sethwtsomaxsegcount(ifp, HN_TX_DATA_SEGCNT_MAX);
24344db5958aSJustin Hibbits 		if_sethwtsomaxsegsize(ifp, PAGE_SIZE);
243515516c77SSepherosa Ziehau 	}
243615516c77SSepherosa Ziehau 
243715516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
243815516c77SSepherosa Ziehau 
24394db5958aSJustin Hibbits 	if ((if_getcapabilities(ifp) & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
244015516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
24414db5958aSJustin Hibbits 		    if_gethwtsomaxsegcount(ifp), if_gethwtsomaxsegsize(ifp));
244215516c77SSepherosa Ziehau 	}
2443eb2fe044SSepherosa Ziehau 	if (mtu < ETHERMTU) {
24444db5958aSJustin Hibbits 
24454db5958aSJustin Hibbits 		if_setmtu(ifp, mtu);
2446eb2fe044SSepherosa Ziehau 	}
244715516c77SSepherosa Ziehau 
244815516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
24494db5958aSJustin Hibbits 	if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
245015516c77SSepherosa Ziehau 
245115516c77SSepherosa Ziehau 	/*
245215516c77SSepherosa Ziehau 	 * Kick off link status check.
245315516c77SSepherosa Ziehau 	 */
245415516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
245515516c77SSepherosa Ziehau 	hn_update_link_status(sc);
245615516c77SSepherosa Ziehau 
24579c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
24585bdfd3fdSDexuan Cui 		sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
24595bdfd3fdSDexuan Cui 		    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
24605bdfd3fdSDexuan Cui 		sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
24615bdfd3fdSDexuan Cui 		    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
24629c6cae24SSepherosa Ziehau 	} else {
24639c6cae24SSepherosa Ziehau 		sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event,
24649c6cae24SSepherosa Ziehau 		    hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY);
24659c6cae24SSepherosa Ziehau 	}
24665bdfd3fdSDexuan Cui 
2467f41e0df4SSepherosa Ziehau 	/*
2468f41e0df4SSepherosa Ziehau 	 * NOTE:
2469f41e0df4SSepherosa Ziehau 	 * Subscribe ether_ifattach event, instead of ifnet_arrival event,
2470f41e0df4SSepherosa Ziehau 	 * since interface's LLADDR is needed; interface LLADDR is not
2471f41e0df4SSepherosa Ziehau 	 * available when ifnet_arrival event is triggered.
2472f41e0df4SSepherosa Ziehau 	 */
2473499c3e17SSepherosa Ziehau 	sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event,
2474499c3e17SSepherosa Ziehau 	    hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY);
2475499c3e17SSepherosa Ziehau 	sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event,
2476499c3e17SSepherosa Ziehau 	    hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY);
2477499c3e17SSepherosa Ziehau 
247815516c77SSepherosa Ziehau 	return (0);
247915516c77SSepherosa Ziehau failed:
248015516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
248115516c77SSepherosa Ziehau 		hn_synth_detach(sc);
248215516c77SSepherosa Ziehau 	hn_detach(dev);
248315516c77SSepherosa Ziehau 	return (error);
248415516c77SSepherosa Ziehau }
248515516c77SSepherosa Ziehau 
248615516c77SSepherosa Ziehau static int
hn_detach(device_t dev)248715516c77SSepherosa Ziehau hn_detach(device_t dev)
248815516c77SSepherosa Ziehau {
248915516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
24904db5958aSJustin Hibbits 	if_t ifp = sc->hn_ifp, vf_ifp;
249115516c77SSepherosa Ziehau 
24929c6cae24SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
24939c6cae24SSepherosa Ziehau 		/*
24949c6cae24SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
24959c6cae24SSepherosa Ziehau 		 * installation.
24969c6cae24SSepherosa Ziehau 		 */
24979c6cae24SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
24989c6cae24SSepherosa Ziehau 	}
24999c6cae24SSepherosa Ziehau 
25005bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
25015bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
25025bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
25035bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
2504499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_atthand != NULL) {
2505499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ether_ifattach_event,
2506499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_atthand);
2507499c3e17SSepherosa Ziehau 	}
2508499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_dethand != NULL) {
2509499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
2510499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_dethand);
2511499c3e17SSepherosa Ziehau 	}
25129c6cae24SSepherosa Ziehau 	if (sc->hn_ifnet_lnkhand != NULL)
25139c6cae24SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand);
2514499c3e17SSepherosa Ziehau 
2515499c3e17SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
2516499c3e17SSepherosa Ziehau 	__compiler_membar();
2517499c3e17SSepherosa Ziehau 	if (vf_ifp != NULL)
2518499c3e17SSepherosa Ziehau 		hn_ifnet_detevent(sc, vf_ifp);
25195bdfd3fdSDexuan Cui 
252015516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
252115516c77SSepherosa Ziehau 		HN_LOCK(sc);
252215516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
25234db5958aSJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
25245bdfd3fdSDexuan Cui 				hn_stop(sc, true);
252515516c77SSepherosa Ziehau 			/*
252615516c77SSepherosa Ziehau 			 * NOTE:
252761b88a23SGordon Bergling 			 * hn_stop() only suspends data, so management
252815516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
252915516c77SSepherosa Ziehau 			 */
253015516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
253115516c77SSepherosa Ziehau 			hn_synth_detach(sc);
253215516c77SSepherosa Ziehau 		}
253315516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
253415516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
253515516c77SSepherosa Ziehau 	}
253615516c77SSepherosa Ziehau 
253715516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
253815516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
253915516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
254015516c77SSepherosa Ziehau 
25410e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
2542fdd0222aSSepherosa Ziehau 		int i;
2543fdd0222aSSepherosa Ziehau 
2544fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
2545fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
2546fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
2547fdd0222aSSepherosa Ziehau 	}
254815516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
25499c6cae24SSepherosa Ziehau 	if (sc->hn_vf_taskq != NULL)
25509c6cae24SSepherosa Ziehau 		taskqueue_free(sc->hn_vf_taskq);
255115516c77SSepherosa Ziehau 
255225641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
255325641fc7SSepherosa Ziehau 		/*
255425641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
255525641fc7SSepherosa Ziehau 		 * destructed.
255625641fc7SSepherosa Ziehau 		 */
255725641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
255815516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
255925641fc7SSepherosa Ziehau 	}
256015516c77SSepherosa Ziehau 
256115516c77SSepherosa Ziehau 	if_free(ifp);
256215516c77SSepherosa Ziehau 
256315516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
25649c6cae24SSepherosa Ziehau 	rm_destroy(&sc->hn_vf_lock);
256515516c77SSepherosa Ziehau 	return (0);
256615516c77SSepherosa Ziehau }
256715516c77SSepherosa Ziehau 
256815516c77SSepherosa Ziehau static int
hn_shutdown(device_t dev)256915516c77SSepherosa Ziehau hn_shutdown(device_t dev)
257015516c77SSepherosa Ziehau {
257115516c77SSepherosa Ziehau 
257215516c77SSepherosa Ziehau 	return (0);
257315516c77SSepherosa Ziehau }
257415516c77SSepherosa Ziehau 
257515516c77SSepherosa Ziehau static void
hn_link_status(struct hn_softc * sc)257615516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
257715516c77SSepherosa Ziehau {
257815516c77SSepherosa Ziehau 	uint32_t link_status;
257915516c77SSepherosa Ziehau 	int error;
258015516c77SSepherosa Ziehau 
258115516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
258215516c77SSepherosa Ziehau 	if (error) {
258315516c77SSepherosa Ziehau 		/* XXX what to do? */
258415516c77SSepherosa Ziehau 		return;
258515516c77SSepherosa Ziehau 	}
258615516c77SSepherosa Ziehau 
258715516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
258815516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
258915516c77SSepherosa Ziehau 	else
259015516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
259115516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
259215516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
259315516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
259415516c77SSepherosa Ziehau }
259515516c77SSepherosa Ziehau 
259615516c77SSepherosa Ziehau static void
hn_link_taskfunc(void * xsc,int pending __unused)259715516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
259815516c77SSepherosa Ziehau {
259915516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
260015516c77SSepherosa Ziehau 
260115516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
260215516c77SSepherosa Ziehau 		return;
260315516c77SSepherosa Ziehau 	hn_link_status(sc);
260415516c77SSepherosa Ziehau }
260515516c77SSepherosa Ziehau 
260615516c77SSepherosa Ziehau static void
hn_netchg_init_taskfunc(void * xsc,int pending __unused)260715516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
260815516c77SSepherosa Ziehau {
260915516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
261015516c77SSepherosa Ziehau 
261115516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
261215516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
261315516c77SSepherosa Ziehau 
261415516c77SSepherosa Ziehau 	/*
261515516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
261615516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
261715516c77SSepherosa Ziehau 	 * upon link down event.
261815516c77SSepherosa Ziehau 	 */
261915516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
262015516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
262115516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
262215516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
262315516c77SSepherosa Ziehau }
262415516c77SSepherosa Ziehau 
262515516c77SSepherosa Ziehau static void
hn_netchg_status_taskfunc(void * xsc,int pending __unused)262615516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
262715516c77SSepherosa Ziehau {
262815516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
262915516c77SSepherosa Ziehau 
263015516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
263115516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
263215516c77SSepherosa Ziehau 	hn_link_status(sc);
263315516c77SSepherosa Ziehau }
263415516c77SSepherosa Ziehau 
263515516c77SSepherosa Ziehau static void
hn_update_link_status(struct hn_softc * sc)263615516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
263715516c77SSepherosa Ziehau {
263815516c77SSepherosa Ziehau 
263915516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
264015516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
264115516c77SSepherosa Ziehau }
264215516c77SSepherosa Ziehau 
264315516c77SSepherosa Ziehau static void
hn_change_network(struct hn_softc * sc)264415516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
264515516c77SSepherosa Ziehau {
264615516c77SSepherosa Ziehau 
264715516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
264815516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
264915516c77SSepherosa Ziehau }
265015516c77SSepherosa Ziehau 
265115516c77SSepherosa Ziehau static __inline int
hn_txdesc_dmamap_load(struct hn_tx_ring * txr,struct hn_txdesc * txd,struct mbuf ** m_head,bus_dma_segment_t * segs,int * nsegs)265215516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
265315516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
265415516c77SSepherosa Ziehau {
265515516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
265615516c77SSepherosa Ziehau 	int error;
265715516c77SSepherosa Ziehau 
265815516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
265915516c77SSepherosa Ziehau 
266015516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
266115516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
266215516c77SSepherosa Ziehau 	if (error == EFBIG) {
266315516c77SSepherosa Ziehau 		struct mbuf *m_new;
266415516c77SSepherosa Ziehau 
266515516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
266615516c77SSepherosa Ziehau 		if (m_new == NULL)
266715516c77SSepherosa Ziehau 			return ENOBUFS;
266815516c77SSepherosa Ziehau 		else
266915516c77SSepherosa Ziehau 			*m_head = m = m_new;
267015516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
267115516c77SSepherosa Ziehau 
267215516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
267315516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
267415516c77SSepherosa Ziehau 	}
267515516c77SSepherosa Ziehau 	if (!error) {
267615516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
267715516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
267815516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
267915516c77SSepherosa Ziehau 	}
268015516c77SSepherosa Ziehau 	return error;
268115516c77SSepherosa Ziehau }
268215516c77SSepherosa Ziehau 
268315516c77SSepherosa Ziehau static __inline int
hn_txdesc_put(struct hn_tx_ring * txr,struct hn_txdesc * txd)268415516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
268515516c77SSepherosa Ziehau {
268615516c77SSepherosa Ziehau 
268715516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
268815516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
2689dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2690dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
269115516c77SSepherosa Ziehau 
269215516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
269315516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
269415516c77SSepherosa Ziehau 		return 0;
269515516c77SSepherosa Ziehau 
2696dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
2697dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
2698dc13fee6SSepherosa Ziehau 
2699dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
2700a0f49d67SMateusz Guzik 			int freed __diagused;
2701dc13fee6SSepherosa Ziehau 
2702dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
2703dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
2704dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
2705dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
2706dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
2707dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
2708dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
2709dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
2710dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
2711dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
2712dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
2713dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
2714dc13fee6SSepherosa Ziehau 
2715dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
2716dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
2717dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
2718dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
2719dc13fee6SSepherosa Ziehau 		}
2720dc13fee6SSepherosa Ziehau 	}
2721dc13fee6SSepherosa Ziehau 
272215516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
272315516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
272415516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
272515516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
272615516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
2727dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
272815516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
272915516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
273015516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
273115516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
273215516c77SSepherosa Ziehau 		    txd->data_dmap);
273315516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
273415516c77SSepherosa Ziehau 	}
273515516c77SSepherosa Ziehau 
273615516c77SSepherosa Ziehau 	if (txd->m != NULL) {
273715516c77SSepherosa Ziehau 		m_freem(txd->m);
273815516c77SSepherosa Ziehau 		txd->m = NULL;
273915516c77SSepherosa Ziehau 	}
274015516c77SSepherosa Ziehau 
274115516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
274215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
274315516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
274415516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
274515516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
274615516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
274715516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
274815516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
274915516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
275085e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
275185e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
275215516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
275315516c77SSepherosa Ziehau #endif
275485e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
275585e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
275615516c77SSepherosa Ziehau 
275715516c77SSepherosa Ziehau 	return 1;
275815516c77SSepherosa Ziehau }
275915516c77SSepherosa Ziehau 
276015516c77SSepherosa Ziehau static __inline struct hn_txdesc *
hn_txdesc_get(struct hn_tx_ring * txr)276115516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
276215516c77SSepherosa Ziehau {
276315516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
276415516c77SSepherosa Ziehau 
276515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
276615516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
276715516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
276815516c77SSepherosa Ziehau 	if (txd != NULL) {
276915516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
277015516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
277115516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
277215516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
277315516c77SSepherosa Ziehau 	}
277415516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
277515516c77SSepherosa Ziehau #else
277615516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
277715516c77SSepherosa Ziehau #endif
277815516c77SSepherosa Ziehau 
277915516c77SSepherosa Ziehau 	if (txd != NULL) {
278015516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
278185e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
278215516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
278315516c77SSepherosa Ziehau #endif
278485e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
278515516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
2786dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
278715516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
2788dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
278915516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
2790dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
279115516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
279215516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
279315516c77SSepherosa Ziehau 		txd->refs = 1;
279415516c77SSepherosa Ziehau 	}
279515516c77SSepherosa Ziehau 	return txd;
279615516c77SSepherosa Ziehau }
279715516c77SSepherosa Ziehau 
279815516c77SSepherosa Ziehau static __inline void
hn_txdesc_hold(struct hn_txdesc * txd)279915516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
280015516c77SSepherosa Ziehau {
280115516c77SSepherosa Ziehau 
280215516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
280325641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
280415516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
280515516c77SSepherosa Ziehau }
280615516c77SSepherosa Ziehau 
2807dc13fee6SSepherosa Ziehau static __inline void
hn_txdesc_agg(struct hn_txdesc * agg_txd,struct hn_txdesc * txd)2808dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
2809dc13fee6SSepherosa Ziehau {
2810dc13fee6SSepherosa Ziehau 
2811dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2812dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
2813dc13fee6SSepherosa Ziehau 
2814dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2815dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
2816dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
2817dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
2818dc13fee6SSepherosa Ziehau 
2819dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
2820dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
2821dc13fee6SSepherosa Ziehau }
2822dc13fee6SSepherosa Ziehau 
282315516c77SSepherosa Ziehau static bool
hn_tx_ring_pending(struct hn_tx_ring * txr)282415516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
282515516c77SSepherosa Ziehau {
282615516c77SSepherosa Ziehau 	bool pending = false;
282715516c77SSepherosa Ziehau 
282815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
282915516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
283015516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
283115516c77SSepherosa Ziehau 		pending = true;
283215516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
283315516c77SSepherosa Ziehau #else
283415516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
283515516c77SSepherosa Ziehau 		pending = true;
283615516c77SSepherosa Ziehau #endif
283715516c77SSepherosa Ziehau 	return (pending);
283815516c77SSepherosa Ziehau }
283915516c77SSepherosa Ziehau 
284015516c77SSepherosa Ziehau static __inline void
hn_txeof(struct hn_tx_ring * txr)284115516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
284215516c77SSepherosa Ziehau {
284315516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
284415516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
284515516c77SSepherosa Ziehau }
284615516c77SSepherosa Ziehau 
284715516c77SSepherosa Ziehau static void
hn_txpkt_done(struct hn_nvs_sendctx * sndc,struct hn_softc * sc,struct vmbus_channel * chan,const void * data __unused,int dlen __unused)284815516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
284915516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
285015516c77SSepherosa Ziehau {
285115516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
285215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
285315516c77SSepherosa Ziehau 
285415516c77SSepherosa Ziehau 	txr = txd->txr;
285515516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
285615516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
2857aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
285815516c77SSepherosa Ziehau 
285915516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
286015516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
286115516c77SSepherosa Ziehau 
286215516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
286315516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
286415516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
286515516c77SSepherosa Ziehau 		if (txr->hn_oactive)
286615516c77SSepherosa Ziehau 			hn_txeof(txr);
286715516c77SSepherosa Ziehau 	}
286815516c77SSepherosa Ziehau }
286915516c77SSepherosa Ziehau 
287015516c77SSepherosa Ziehau static void
hn_chan_rollup(struct hn_rx_ring * rxr,struct hn_tx_ring * txr)287115516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
287215516c77SSepherosa Ziehau {
287315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
287426d79d40SMichael Tuexen 	struct epoch_tracker et;
287526d79d40SMichael Tuexen 
287626d79d40SMichael Tuexen 	NET_EPOCH_ENTER(et);
287715516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
287826d79d40SMichael Tuexen 	NET_EPOCH_EXIT(et);
287915516c77SSepherosa Ziehau #endif
288015516c77SSepherosa Ziehau 
288115516c77SSepherosa Ziehau 	/*
288215516c77SSepherosa Ziehau 	 * NOTE:
288315516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
288415516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
288515516c77SSepherosa Ziehau 	 */
288615516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
288715516c77SSepherosa Ziehau 		return;
288815516c77SSepherosa Ziehau 
288915516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
289015516c77SSepherosa Ziehau 	hn_txeof(txr);
289115516c77SSepherosa Ziehau }
289215516c77SSepherosa Ziehau 
289315516c77SSepherosa Ziehau static __inline uint32_t
hn_rndis_pktmsg_offset(uint32_t ofs)289415516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
289515516c77SSepherosa Ziehau {
289615516c77SSepherosa Ziehau 
289715516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
289815516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
289915516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
290015516c77SSepherosa Ziehau }
290115516c77SSepherosa Ziehau 
290215516c77SSepherosa Ziehau static __inline void *
hn_rndis_pktinfo_append(struct rndis_packet_msg * pkt,size_t pktsize,size_t pi_dlen,uint32_t pi_type)290315516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
290415516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
290515516c77SSepherosa Ziehau {
290615516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
290715516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
290815516c77SSepherosa Ziehau 
290915516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
291015516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
291115516c77SSepherosa Ziehau 
291215516c77SSepherosa Ziehau 	/*
291315516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
291415516c77SSepherosa Ziehau 	 *
291515516c77SSepherosa Ziehau 	 * NOTE:
291615516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
291715516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
291815516c77SSepherosa Ziehau 	 */
291915516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
292015516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
292115516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
292215516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
292315516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
292415516c77SSepherosa Ziehau 
292515516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
292615516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
2927805dbff6SWei Hu 	pi->rm_internal = 0;
292815516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
292915516c77SSepherosa Ziehau 
293015516c77SSepherosa Ziehau 	return (pi->rm_data);
293115516c77SSepherosa Ziehau }
293215516c77SSepherosa Ziehau 
2933dc13fee6SSepherosa Ziehau static __inline int
hn_flush_txagg(if_t ifp,struct hn_tx_ring * txr)29344db5958aSJustin Hibbits hn_flush_txagg(if_t ifp, struct hn_tx_ring *txr)
2935dc13fee6SSepherosa Ziehau {
2936dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
2937dc13fee6SSepherosa Ziehau 	struct mbuf *m;
2938dc13fee6SSepherosa Ziehau 	int error, pkts;
2939dc13fee6SSepherosa Ziehau 
2940dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
2941dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
2942dc13fee6SSepherosa Ziehau 
2943dc13fee6SSepherosa Ziehau 	/*
2944dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
2945dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
2946dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
2947dc13fee6SSepherosa Ziehau 	 */
2948dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
2949dc13fee6SSepherosa Ziehau 
2950dc13fee6SSepherosa Ziehau 	/*
2951dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
2952dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
2953dc13fee6SSepherosa Ziehau 	 * fails.
2954dc13fee6SSepherosa Ziehau 	 */
2955dc13fee6SSepherosa Ziehau 	m = txd->m;
2956dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
2957dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
2958dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
2959dc13fee6SSepherosa Ziehau 		m_freem(m);
2960dc13fee6SSepherosa Ziehau 
2961dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
2962dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
2963dc13fee6SSepherosa Ziehau 	}
2964dc13fee6SSepherosa Ziehau 
2965dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
2966dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
2967dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
2968dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
2969dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
2970dc13fee6SSepherosa Ziehau 
2971dc13fee6SSepherosa Ziehau 	return (error);
2972dc13fee6SSepherosa Ziehau }
2973dc13fee6SSepherosa Ziehau 
2974dc13fee6SSepherosa Ziehau static void *
hn_try_txagg(if_t ifp,struct hn_tx_ring * txr,struct hn_txdesc * txd,int pktsize)29754db5958aSJustin Hibbits hn_try_txagg(if_t ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2976dc13fee6SSepherosa Ziehau     int pktsize)
2977dc13fee6SSepherosa Ziehau {
2978dc13fee6SSepherosa Ziehau 	void *chim;
2979dc13fee6SSepherosa Ziehau 
2980dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
2981dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
2982dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
2983dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
2984dc13fee6SSepherosa Ziehau 			int olen;
2985dc13fee6SSepherosa Ziehau 
2986dc13fee6SSepherosa Ziehau 			/*
2987dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
2988dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
2989dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
2990dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
2991dc13fee6SSepherosa Ziehau 			 * accordingly.
2992dc13fee6SSepherosa Ziehau 			 *
2993dc13fee6SSepherosa Ziehau 			 * XXX
2994dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
2995dc13fee6SSepherosa Ziehau 			 */
2996dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
2997dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
2998dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
2999dc13fee6SSepherosa Ziehau 
3000dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
3001dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
3002dc13fee6SSepherosa Ziehau 
3003dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
3004dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
3005dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
3006dc13fee6SSepherosa Ziehau 
3007dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
3008dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
3009dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
3010dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
3011dc13fee6SSepherosa Ziehau 				/*
3012dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
3013dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
3014dc13fee6SSepherosa Ziehau 				 */
3015dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
3016dc13fee6SSepherosa Ziehau 			}
3017dc13fee6SSepherosa Ziehau 			/* Done! */
3018dc13fee6SSepherosa Ziehau 			return (chim);
3019dc13fee6SSepherosa Ziehau 		}
3020dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
3021dc13fee6SSepherosa Ziehau 	}
3022dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
3023dc13fee6SSepherosa Ziehau 
3024dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
3025dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
3026dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
3027dc13fee6SSepherosa Ziehau 		return (NULL);
3028dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
3029dc13fee6SSepherosa Ziehau 
3030dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
3031dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
3032dc13fee6SSepherosa Ziehau 
3033dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
3034dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
3035dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
3036dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
3037dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
3038dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
3039dc13fee6SSepherosa Ziehau 	}
3040dc13fee6SSepherosa Ziehau 	return (chim);
3041dc13fee6SSepherosa Ziehau }
3042dc13fee6SSepherosa Ziehau 
304315516c77SSepherosa Ziehau /*
304415516c77SSepherosa Ziehau  * NOTE:
304515516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
304615516c77SSepherosa Ziehau  */
304715516c77SSepherosa Ziehau static int
hn_encap(if_t ifp,struct hn_tx_ring * txr,struct hn_txdesc * txd,struct mbuf ** m_head0)30484db5958aSJustin Hibbits hn_encap(if_t ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
3049dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
305015516c77SSepherosa Ziehau {
305115516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
305215516c77SSepherosa Ziehau 	int error, nsegs, i;
305315516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
305415516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
305515516c77SSepherosa Ziehau 	uint32_t *pi_data;
30568966e5d5SSepherosa Ziehau 	void *chim = NULL;
3057dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
305815516c77SSepherosa Ziehau 
305915516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
3060dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
3061dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
3062dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
3063dc13fee6SSepherosa Ziehau 		if (chim != NULL)
30648966e5d5SSepherosa Ziehau 			pkt = chim;
3065dc13fee6SSepherosa Ziehau 	} else {
3066dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
3067dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
30688966e5d5SSepherosa Ziehau 	}
30698966e5d5SSepherosa Ziehau 
307015516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
30718fe90f73SSepherosa Ziehau 	pkt->rm_len = m_head->m_pkthdr.len;
30729130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = 0;
307315516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
3074dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
3075dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
3076dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
307715516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
307815516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
3079dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
3080dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
308115516c77SSepherosa Ziehau 
308215516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
308315516c77SSepherosa Ziehau 		/*
308480f39bd9SWei Hu 		 * Set the hash value for this packet.
308515516c77SSepherosa Ziehau 		 */
308615516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
308715516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
308880f39bd9SWei Hu 
308980f39bd9SWei Hu 		if (M_HASHTYPE_ISHASH(m_head))
309080f39bd9SWei Hu 			/*
309180f39bd9SWei Hu 			 * The flowid field contains the hash value host
309280f39bd9SWei Hu 			 * set in the rx queue if it is a ip forwarding pkt.
309380f39bd9SWei Hu 			 * Set the same hash value so host can send on the
309480f39bd9SWei Hu 			 * cpu it was received.
309580f39bd9SWei Hu 			 */
309680f39bd9SWei Hu 			*pi_data = m_head->m_pkthdr.flowid;
309780f39bd9SWei Hu 		else
309880f39bd9SWei Hu 			/*
309980f39bd9SWei Hu 			 * Otherwise just put the tx queue index.
310080f39bd9SWei Hu 			 */
310115516c77SSepherosa Ziehau 			*pi_data = txr->hn_tx_idx;
310215516c77SSepherosa Ziehau 	}
310315516c77SSepherosa Ziehau 
310415516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
310515516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
310615516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
310715516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
310815516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
310915516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
311015516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
311115516c77SSepherosa Ziehau 	}
311215516c77SSepherosa Ziehau 
311315516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
311415516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
311515516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
311615516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
311715516c77SSepherosa Ziehau #ifdef INET
311815516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
3119c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(
3120c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
312115516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
312215516c77SSepherosa Ziehau 		}
312315516c77SSepherosa Ziehau #endif
312415516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
312515516c77SSepherosa Ziehau 		else
312615516c77SSepherosa Ziehau #endif
312715516c77SSepherosa Ziehau #ifdef INET6
312815516c77SSepherosa Ziehau 		{
3129c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(
3130c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
313115516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
313215516c77SSepherosa Ziehau 		}
313315516c77SSepherosa Ziehau #endif
313415516c77SSepherosa Ziehau #endif	/* INET6 || INET */
313515516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
313615516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
313715516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
313815516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
313915516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
314015516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
314115516c77SSepherosa Ziehau 		} else {
314215516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
314315516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
314415516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
314515516c77SSepherosa Ziehau 		}
314615516c77SSepherosa Ziehau 
3147c49d47daSSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
3148c49d47daSSepherosa Ziehau 		    (CSUM_IP_TCP | CSUM_IP6_TCP)) {
3149c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKTCPCS(
3150c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3151c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
3152c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP)) {
3153c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKUDPCS(
3154c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3155c49d47daSSepherosa Ziehau 		}
315615516c77SSepherosa Ziehau 	}
315715516c77SSepherosa Ziehau 
3158dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
31598fe90f73SSepherosa Ziehau 	/* Fixup RNDIS packet message total length */
31608fe90f73SSepherosa Ziehau 	pkt->rm_len += pkt_hlen;
316115516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
31629130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);
316315516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
316415516c77SSepherosa Ziehau 
316515516c77SSepherosa Ziehau 	/*
31668966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
316715516c77SSepherosa Ziehau 	 */
31688966e5d5SSepherosa Ziehau 	if (chim != NULL) {
3169dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
3170dc13fee6SSepherosa Ziehau 
3171dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
3172dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
3173dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3174dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
3175dc13fee6SSepherosa Ziehau #endif
3176dc13fee6SSepherosa Ziehau 		}
3177dc13fee6SSepherosa Ziehau 
3178dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
3179dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
3180dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
3181dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
3182dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
318315516c77SSepherosa Ziehau 
31848966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
3185dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
318615516c77SSepherosa Ziehau 
318715516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
318815516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
318915516c77SSepherosa Ziehau 		goto done;
319015516c77SSepherosa Ziehau 	}
3191dc13fee6SSepherosa Ziehau 
3192dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
31938966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
31948966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
31958966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
319615516c77SSepherosa Ziehau 
319715516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
3198dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
3199a0f49d67SMateusz Guzik 		int freed __diagused;
320015516c77SSepherosa Ziehau 
320115516c77SSepherosa Ziehau 		/*
320215516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
320315516c77SSepherosa Ziehau 		 */
320415516c77SSepherosa Ziehau 		m_freem(m_head);
320515516c77SSepherosa Ziehau 		*m_head0 = NULL;
320615516c77SSepherosa Ziehau 
320715516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
320815516c77SSepherosa Ziehau 		KASSERT(freed != 0,
320915516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
321015516c77SSepherosa Ziehau 
321115516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
3212dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
321315516c77SSepherosa Ziehau 		return error;
321415516c77SSepherosa Ziehau 	}
321515516c77SSepherosa Ziehau 	*m_head0 = m_head;
321615516c77SSepherosa Ziehau 
321715516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
321815516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
321915516c77SSepherosa Ziehau 
322015516c77SSepherosa Ziehau 	/* send packet with page buffer */
322115516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
322215516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
3223dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
322415516c77SSepherosa Ziehau 
322515516c77SSepherosa Ziehau 	/*
322615516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
322715516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
322815516c77SSepherosa Ziehau 	 */
322915516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
323015516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
323115516c77SSepherosa Ziehau 
323215516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
323315516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
323415516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
323515516c77SSepherosa Ziehau 	}
323615516c77SSepherosa Ziehau 
323715516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
323815516c77SSepherosa Ziehau 	txd->chim_size = 0;
323915516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
324015516c77SSepherosa Ziehau done:
324115516c77SSepherosa Ziehau 	txd->m = m_head;
324215516c77SSepherosa Ziehau 
324315516c77SSepherosa Ziehau 	/* Set the completion routine */
324415516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
324515516c77SSepherosa Ziehau 
3246dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
3247dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
3248dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
3249dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
3250dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
3251dc13fee6SSepherosa Ziehau 
325215516c77SSepherosa Ziehau 	return 0;
325315516c77SSepherosa Ziehau }
325415516c77SSepherosa Ziehau 
325515516c77SSepherosa Ziehau /*
325615516c77SSepherosa Ziehau  * NOTE:
325715516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
325815516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
325915516c77SSepherosa Ziehau  */
326015516c77SSepherosa Ziehau static int
hn_txpkt(if_t ifp,struct hn_tx_ring * txr,struct hn_txdesc * txd)32614db5958aSJustin Hibbits hn_txpkt(if_t ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
326215516c77SSepherosa Ziehau {
32638e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
326415516c77SSepherosa Ziehau 
326515516c77SSepherosa Ziehau again:
32668f31b879SJustin Hibbits 	has_bpf = bpf_peers_present_if(ifp);
32678e7d3136SSepherosa Ziehau 	if (has_bpf) {
326815516c77SSepherosa Ziehau 		/*
32698e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
32708e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
327115516c77SSepherosa Ziehau 		 */
327215516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
32738e7d3136SSepherosa Ziehau 	}
327415516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
327515516c77SSepherosa Ziehau 	if (!error) {
32768e7d3136SSepherosa Ziehau 		if (has_bpf) {
3277dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
3278dc13fee6SSepherosa Ziehau 
327915516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
3280dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
3281dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
3282dc13fee6SSepherosa Ziehau 		}
3283dc13fee6SSepherosa Ziehau 
3284dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
328523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
328623bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
328723bf9e15SSepherosa Ziehau #endif
328823bf9e15SSepherosa Ziehau 		{
328915516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
3290dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
3291dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
3292dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
3293dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
329415516c77SSepherosa Ziehau 			}
3295dc13fee6SSepherosa Ziehau 		}
3296dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
3297dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
329815516c77SSepherosa Ziehau 	}
32998e7d3136SSepherosa Ziehau 	if (has_bpf)
330015516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
330115516c77SSepherosa Ziehau 
330215516c77SSepherosa Ziehau 	if (__predict_false(error)) {
3303a0f49d67SMateusz Guzik 		int freed __diagused;
330415516c77SSepherosa Ziehau 
330515516c77SSepherosa Ziehau 		/*
330615516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
330715516c77SSepherosa Ziehau 		 *
330815516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
330915516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
331015516c77SSepherosa Ziehau 		 * to kick start later.
331115516c77SSepherosa Ziehau 		 */
331215516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
331315516c77SSepherosa Ziehau 		if (!send_failed) {
331415516c77SSepherosa Ziehau 			txr->hn_send_failed++;
331515516c77SSepherosa Ziehau 			send_failed = 1;
331615516c77SSepherosa Ziehau 			/*
331715516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
331815516c77SSepherosa Ziehau 			 * in case that we missed the last
331915516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
332015516c77SSepherosa Ziehau 			 */
332115516c77SSepherosa Ziehau 			goto again;
332215516c77SSepherosa Ziehau 		}
332315516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
332415516c77SSepherosa Ziehau 
332515516c77SSepherosa Ziehau 		/*
332615516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
332715516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
332815516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
332915516c77SSepherosa Ziehau 		 * if it was loaded.
333015516c77SSepherosa Ziehau 		 */
333115516c77SSepherosa Ziehau 		txd->m = NULL;
333215516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
333315516c77SSepherosa Ziehau 		KASSERT(freed != 0,
333415516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
333515516c77SSepherosa Ziehau 
333615516c77SSepherosa Ziehau 		txr->hn_send_failed++;
333715516c77SSepherosa Ziehau 	}
3338dc13fee6SSepherosa Ziehau 
3339dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
3340dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
3341dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
3342dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
3343dc13fee6SSepherosa Ziehau 
3344dc13fee6SSepherosa Ziehau 	return (error);
334515516c77SSepherosa Ziehau }
334615516c77SSepherosa Ziehau 
334715516c77SSepherosa Ziehau /*
334815516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
334915516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
335015516c77SSepherosa Ziehau  * existing space.
335115516c77SSepherosa Ziehau  *
335215516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
335315516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
335415516c77SSepherosa Ziehau  * but there does not appear to be one yet.
335515516c77SSepherosa Ziehau  *
335615516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
335715516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
335815516c77SSepherosa Ziehau  * accordingly.
335915516c77SSepherosa Ziehau  *
3360a491581fSWei Hu  * Return the last mbuf in the chain or NULL if failed to
3361a491581fSWei Hu  * allocate new mbuf.
336215516c77SSepherosa Ziehau  */
3363a491581fSWei Hu static struct mbuf *
hv_m_append(struct mbuf * m0,int len,c_caddr_t cp)336415516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
336515516c77SSepherosa Ziehau {
336615516c77SSepherosa Ziehau 	struct mbuf *m, *n;
336715516c77SSepherosa Ziehau 	int remainder, space;
336815516c77SSepherosa Ziehau 
336915516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
337015516c77SSepherosa Ziehau 		;
337115516c77SSepherosa Ziehau 	remainder = len;
337215516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
337315516c77SSepherosa Ziehau 	if (space > 0) {
337415516c77SSepherosa Ziehau 		/*
337515516c77SSepherosa Ziehau 		 * Copy into available space.
337615516c77SSepherosa Ziehau 		 */
337715516c77SSepherosa Ziehau 		if (space > remainder)
337815516c77SSepherosa Ziehau 			space = remainder;
337915516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
338015516c77SSepherosa Ziehau 		m->m_len += space;
338115516c77SSepherosa Ziehau 		cp += space;
338215516c77SSepherosa Ziehau 		remainder -= space;
338315516c77SSepherosa Ziehau 	}
338415516c77SSepherosa Ziehau 	while (remainder > 0) {
338515516c77SSepherosa Ziehau 		/*
338615516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
338715516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
338815516c77SSepherosa Ziehau 		 */
338915516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
339015516c77SSepherosa Ziehau 		if (n == NULL)
3391a491581fSWei Hu 			return NULL;
339215516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
339315516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
339415516c77SSepherosa Ziehau 		cp += n->m_len;
339515516c77SSepherosa Ziehau 		remainder -= n->m_len;
339615516c77SSepherosa Ziehau 		m->m_next = n;
339715516c77SSepherosa Ziehau 		m = n;
339815516c77SSepherosa Ziehau 	}
339915516c77SSepherosa Ziehau 
3400a491581fSWei Hu 	return m;
340115516c77SSepherosa Ziehau }
340215516c77SSepherosa Ziehau 
340315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
340415516c77SSepherosa Ziehau static __inline int
hn_lro_rx(struct lro_ctrl * lc,struct mbuf * m)340515516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
340615516c77SSepherosa Ziehau {
340715516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
340815516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
340915516c77SSepherosa Ziehau 		return 0;
341015516c77SSepherosa Ziehau 	}
341115516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
341215516c77SSepherosa Ziehau }
341315516c77SSepherosa Ziehau #endif
341415516c77SSepherosa Ziehau 
341515516c77SSepherosa Ziehau static int
hn_rxpkt(struct hn_rx_ring * rxr)3416a491581fSWei Hu hn_rxpkt(struct hn_rx_ring *rxr)
341715516c77SSepherosa Ziehau {
34184db5958aSJustin Hibbits 	if_t ifp, hn_ifp = rxr->hn_ifp;
3419a491581fSWei Hu 	struct mbuf *m_new, *n;
3420642ec226SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1, is_vf = 0;
3421642ec226SSepherosa Ziehau 	int hash_type = M_HASHTYPE_NONE;
3422db76829bSSepherosa Ziehau 	int l3proto = ETHERTYPE_MAX, l4proto = IPPROTO_DONE;
3423a491581fSWei Hu 	int i;
342415516c77SSepherosa Ziehau 
3425642ec226SSepherosa Ziehau 	ifp = hn_ifp;
3426642ec226SSepherosa Ziehau 	if (rxr->hn_rxvf_ifp != NULL) {
3427a97fff19SSepherosa Ziehau 		/*
3428642ec226SSepherosa Ziehau 		 * Non-transparent mode VF; pretend this packet is from
3429642ec226SSepherosa Ziehau 		 * the VF.
3430a97fff19SSepherosa Ziehau 		 */
3431642ec226SSepherosa Ziehau 		ifp = rxr->hn_rxvf_ifp;
3432642ec226SSepherosa Ziehau 		is_vf = 1;
3433642ec226SSepherosa Ziehau 	} else if (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF) {
3434642ec226SSepherosa Ziehau 		/* Transparent mode VF. */
3435642ec226SSepherosa Ziehau 		is_vf = 1;
3436642ec226SSepherosa Ziehau 	}
34375bdfd3fdSDexuan Cui 
34384db5958aSJustin Hibbits 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) {
3439b3b75d9cSSepherosa Ziehau 		/*
3440b3b75d9cSSepherosa Ziehau 		 * NOTE:
3441b3b75d9cSSepherosa Ziehau 		 * See the NOTE of hn_rndis_init_fixat().  This
3442b3b75d9cSSepherosa Ziehau 		 * function can be reached, immediately after the
3443b3b75d9cSSepherosa Ziehau 		 * RNDIS is initialized but before the ifnet is
3444b3b75d9cSSepherosa Ziehau 		 * setup on the hn_attach() path; drop the unexpected
3445b3b75d9cSSepherosa Ziehau 		 * packets.
3446b3b75d9cSSepherosa Ziehau 		 */
3447b3b75d9cSSepherosa Ziehau 		return (0);
3448b3b75d9cSSepherosa Ziehau 	}
3449b3b75d9cSSepherosa Ziehau 
3450a491581fSWei Hu 	if (__predict_false(rxr->rsc.pktlen < ETHER_HDR_LEN)) {
3451a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1);
3452a97fff19SSepherosa Ziehau 		return (0);
3453a97fff19SSepherosa Ziehau 	}
3454a97fff19SSepherosa Ziehau 
3455a491581fSWei Hu 	if (rxr->rsc.cnt == 1 && rxr->rsc.pktlen <= MHLEN) {
345615516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
345715516c77SSepherosa Ziehau 		if (m_new == NULL) {
3458a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
345915516c77SSepherosa Ziehau 			return (0);
346015516c77SSepherosa Ziehau 		}
3461a491581fSWei Hu 		memcpy(mtod(m_new, void *), rxr->rsc.frag_data[0],
3462a491581fSWei Hu 		    rxr->rsc.frag_len[0]);
3463a491581fSWei Hu 		m_new->m_pkthdr.len = m_new->m_len = rxr->rsc.frag_len[0];
346415516c77SSepherosa Ziehau 	} else {
346515516c77SSepherosa Ziehau 		/*
346615516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
346715516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
346815516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
346915516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
347015516c77SSepherosa Ziehau 		 */
347115516c77SSepherosa Ziehau 		size = MCLBYTES;
3472a491581fSWei Hu 		if (rxr->rsc.pktlen > MCLBYTES) {
347315516c77SSepherosa Ziehau 			/* 4096 */
347415516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
347515516c77SSepherosa Ziehau 		}
347615516c77SSepherosa Ziehau 
347715516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
347815516c77SSepherosa Ziehau 		if (m_new == NULL) {
3479a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
348015516c77SSepherosa Ziehau 			return (0);
348115516c77SSepherosa Ziehau 		}
348215516c77SSepherosa Ziehau 
3483a491581fSWei Hu 		n = m_new;
3484a491581fSWei Hu 		for (i = 0; i < rxr->rsc.cnt; i++) {
3485a491581fSWei Hu 			n = hv_m_append(n, rxr->rsc.frag_len[i],
3486a491581fSWei Hu 			    rxr->rsc.frag_data[i]);
3487a491581fSWei Hu 			if (n == NULL) {
3488a491581fSWei Hu 				if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
3489a491581fSWei Hu 				return (0);
3490a491581fSWei Hu 			} else {
3491a491581fSWei Hu 				m_new->m_pkthdr.len += rxr->rsc.frag_len[i];
349215516c77SSepherosa Ziehau 			}
3493a491581fSWei Hu 		}
3494a491581fSWei Hu 	}
3495a491581fSWei Hu 	if (rxr->rsc.pktlen <= MHLEN)
3496a491581fSWei Hu 		rxr->hn_small_pkts++;
3497a491581fSWei Hu 
349815516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
349915516c77SSepherosa Ziehau 
35004db5958aSJustin Hibbits 	if (__predict_false((if_getcapenable(hn_ifp) & IFCAP_RXCSUM) == 0))
350115516c77SSepherosa Ziehau 		do_csum = 0;
350215516c77SSepherosa Ziehau 
350315516c77SSepherosa Ziehau 	/* receive side checksum offload */
3504a491581fSWei Hu 	if (rxr->rsc.csum_info != NULL) {
350515516c77SSepherosa Ziehau 		/* IP csum offload */
3506a491581fSWei Hu 		if ((*(rxr->rsc.csum_info) & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
350715516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
350815516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
350915516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
351015516c77SSepherosa Ziehau 		}
351115516c77SSepherosa Ziehau 
351215516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
3513a491581fSWei Hu 		if ((*(rxr->rsc.csum_info) & (NDIS_RXCSUM_INFO_UDPCS_OK |
351415516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
351515516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
351615516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
351715516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
3518a491581fSWei Hu 			if (*(rxr->rsc.csum_info) & NDIS_RXCSUM_INFO_TCPCS_OK)
351915516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
352015516c77SSepherosa Ziehau 			else
352115516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
352215516c77SSepherosa Ziehau 		}
352315516c77SSepherosa Ziehau 
352415516c77SSepherosa Ziehau 		/*
352515516c77SSepherosa Ziehau 		 * XXX
352615516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
352715516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
352815516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
352915516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
353015516c77SSepherosa Ziehau 		 */
3531a491581fSWei Hu 		if ((*(rxr->rsc.csum_info) &
353215516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
353315516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
353415516c77SSepherosa Ziehau 			do_lro = 1;
353515516c77SSepherosa Ziehau 	} else {
3536db76829bSSepherosa Ziehau 		hn_rxpkt_proto(m_new, &l3proto, &l4proto);
3537db76829bSSepherosa Ziehau 		if (l3proto == ETHERTYPE_IP) {
3538db76829bSSepherosa Ziehau 			if (l4proto == IPPROTO_TCP) {
353915516c77SSepherosa Ziehau 				if (do_csum &&
354015516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
354115516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
354215516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
354315516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
354415516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
354515516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
354615516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
354715516c77SSepherosa Ziehau 				}
354815516c77SSepherosa Ziehau 				do_lro = 1;
3549db76829bSSepherosa Ziehau 			} else if (l4proto == IPPROTO_UDP) {
355015516c77SSepherosa Ziehau 				if (do_csum &&
355115516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
355215516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
355315516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
355415516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
355515516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
355615516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
355715516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
355815516c77SSepherosa Ziehau 				}
3559db76829bSSepherosa Ziehau 			} else if (l4proto != IPPROTO_DONE && do_csum &&
356015516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
356115516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
356215516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
356315516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
356415516c77SSepherosa Ziehau 			}
356515516c77SSepherosa Ziehau 		}
356615516c77SSepherosa Ziehau 	}
3567db76829bSSepherosa Ziehau 
3568a491581fSWei Hu 	if (rxr->rsc.vlan_info != NULL) {
356915516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
3570a491581fSWei Hu 		    NDIS_VLAN_INFO_ID(*(rxr->rsc.vlan_info)),
3571a491581fSWei Hu 		    NDIS_VLAN_INFO_PRI(*(rxr->rsc.vlan_info)),
3572a491581fSWei Hu 		    NDIS_VLAN_INFO_CFI(*(rxr->rsc.vlan_info)));
357315516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
357415516c77SSepherosa Ziehau 	}
357515516c77SSepherosa Ziehau 
3576a97fff19SSepherosa Ziehau 	/*
3577a97fff19SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3578a97fff19SSepherosa Ziehau 	 * matter here).
3579a97fff19SSepherosa Ziehau 	 *
3580a97fff19SSepherosa Ziehau 	 * - Disable LRO
3581a97fff19SSepherosa Ziehau 	 *
3582a97fff19SSepherosa Ziehau 	 *   hn(4) will only receive broadcast packets, multicast packets,
3583a97fff19SSepherosa Ziehau 	 *   TCP SYN and SYN|ACK (in Azure), LRO is useless for these
3584a97fff19SSepherosa Ziehau 	 *   packet types.
3585a97fff19SSepherosa Ziehau 	 *
3586a97fff19SSepherosa Ziehau 	 *   For non-transparent, we definitely _cannot_ enable LRO at
3587a97fff19SSepherosa Ziehau 	 *   all, since the LRO flush will use hn(4) as the receiving
3588a97fff19SSepherosa Ziehau 	 *   interface; i.e. hn_ifp->if_input(hn_ifp, m).
3589a97fff19SSepherosa Ziehau 	 */
3590642ec226SSepherosa Ziehau 	if (is_vf)
3591642ec226SSepherosa Ziehau 		do_lro = 0;
3592a97fff19SSepherosa Ziehau 
3593642ec226SSepherosa Ziehau 	/*
3594642ec226SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3595642ec226SSepherosa Ziehau 	 * matter here), do _not_ mess with unsupported hash types or
3596642ec226SSepherosa Ziehau 	 * functions.
3597642ec226SSepherosa Ziehau 	 */
3598a491581fSWei Hu 	if (rxr->rsc.hash_info != NULL) {
359915516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
3600a491581fSWei Hu 		m_new->m_pkthdr.flowid = *(rxr->rsc.hash_value);
3601642ec226SSepherosa Ziehau 		if (!is_vf)
360215516c77SSepherosa Ziehau 			hash_type = M_HASHTYPE_OPAQUE_HASH;
3603a491581fSWei Hu 		if ((*(rxr->rsc.hash_info) & NDIS_HASH_FUNCTION_MASK) ==
360415516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
3605a491581fSWei Hu 			uint32_t type = (*(rxr->rsc.hash_info) & NDIS_HASH_TYPE_MASK &
3606642ec226SSepherosa Ziehau 			    rxr->hn_mbuf_hash);
360715516c77SSepherosa Ziehau 
360815516c77SSepherosa Ziehau 			/*
360915516c77SSepherosa Ziehau 			 * NOTE:
361015516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
361115516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
361215516c77SSepherosa Ziehau 			 * setup section.
361315516c77SSepherosa Ziehau 			 */
361415516c77SSepherosa Ziehau 			switch (type) {
361515516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
361615516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
361715516c77SSepherosa Ziehau 				do_lro = 0;
361815516c77SSepherosa Ziehau 				break;
361915516c77SSepherosa Ziehau 
362015516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
362115516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
3622db76829bSSepherosa Ziehau 				if (rxr->hn_rx_flags & HN_RX_FLAG_UDP_HASH) {
3623db76829bSSepherosa Ziehau 					int def_htype = M_HASHTYPE_OPAQUE_HASH;
3624db76829bSSepherosa Ziehau 
3625db76829bSSepherosa Ziehau 					if (is_vf)
3626db76829bSSepherosa Ziehau 						def_htype = M_HASHTYPE_NONE;
3627db76829bSSepherosa Ziehau 
3628db76829bSSepherosa Ziehau 					/*
3629db76829bSSepherosa Ziehau 					 * UDP 4-tuple hash is delivered as
3630db76829bSSepherosa Ziehau 					 * TCP 4-tuple hash.
3631db76829bSSepherosa Ziehau 					 */
3632db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_MAX) {
3633db76829bSSepherosa Ziehau 						hn_rxpkt_proto(m_new,
3634db76829bSSepherosa Ziehau 						    &l3proto, &l4proto);
3635db76829bSSepherosa Ziehau 					}
3636db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_IP) {
36376f12c42eSSepherosa Ziehau 						if (l4proto == IPPROTO_UDP &&
36386f12c42eSSepherosa Ziehau 						    (rxr->hn_mbuf_hash &
36396f12c42eSSepherosa Ziehau 						     NDIS_HASH_UDP_IPV4_X)) {
3640db76829bSSepherosa Ziehau 							hash_type =
3641db76829bSSepherosa Ziehau 							M_HASHTYPE_RSS_UDP_IPV4;
3642db76829bSSepherosa Ziehau 							do_lro = 0;
3643db76829bSSepherosa Ziehau 						} else if (l4proto !=
3644db76829bSSepherosa Ziehau 						    IPPROTO_TCP) {
3645db76829bSSepherosa Ziehau 							hash_type = def_htype;
3646db76829bSSepherosa Ziehau 							do_lro = 0;
3647db76829bSSepherosa Ziehau 						}
3648db76829bSSepherosa Ziehau 					} else {
3649db76829bSSepherosa Ziehau 						hash_type = def_htype;
3650db76829bSSepherosa Ziehau 						do_lro = 0;
3651db76829bSSepherosa Ziehau 					}
3652db76829bSSepherosa Ziehau 				}
365315516c77SSepherosa Ziehau 				break;
365415516c77SSepherosa Ziehau 
365515516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
365615516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
365715516c77SSepherosa Ziehau 				do_lro = 0;
365815516c77SSepherosa Ziehau 				break;
365915516c77SSepherosa Ziehau 
366015516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
366115516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
366215516c77SSepherosa Ziehau 				do_lro = 0;
366315516c77SSepherosa Ziehau 				break;
366415516c77SSepherosa Ziehau 
366515516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
366615516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
366715516c77SSepherosa Ziehau 				break;
366815516c77SSepherosa Ziehau 
366915516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
367015516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
367115516c77SSepherosa Ziehau 				break;
367215516c77SSepherosa Ziehau 			}
367315516c77SSepherosa Ziehau 		}
3674642ec226SSepherosa Ziehau 	} else if (!is_vf) {
367515516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
367615516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
367715516c77SSepherosa Ziehau 	}
367815516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
367915516c77SSepherosa Ziehau 
3680a97fff19SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
3681a97fff19SSepherosa Ziehau 	if (hn_ifp != ifp) {
3682a97fff19SSepherosa Ziehau 		const struct ether_header *eh;
3683a97fff19SSepherosa Ziehau 
368415516c77SSepherosa Ziehau 		/*
3685a97fff19SSepherosa Ziehau 		 * Non-transparent mode VF is activated.
368615516c77SSepherosa Ziehau 		 */
368715516c77SSepherosa Ziehau 
3688a97fff19SSepherosa Ziehau 		/*
3689a97fff19SSepherosa Ziehau 		 * Allow tapping on hn(4).
3690a97fff19SSepherosa Ziehau 		 */
3691a97fff19SSepherosa Ziehau 		ETHER_BPF_MTAP(hn_ifp, m_new);
3692a97fff19SSepherosa Ziehau 
3693a97fff19SSepherosa Ziehau 		/*
3694a97fff19SSepherosa Ziehau 		 * Update hn(4)'s stats.
3695a97fff19SSepherosa Ziehau 		 */
3696a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
3697a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len);
3698a97fff19SSepherosa Ziehau 		/* Checked at the beginning of this function. */
3699a97fff19SSepherosa Ziehau 		KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame"));
3700a97fff19SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
3701a97fff19SSepherosa Ziehau 		if (ETHER_IS_MULTICAST(eh->ether_dhost))
3702a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1);
3703a97fff19SSepherosa Ziehau 	}
370415516c77SSepherosa Ziehau 	rxr->hn_pkts++;
370515516c77SSepherosa Ziehau 
37064db5958aSJustin Hibbits 	if ((if_getcapenable(hn_ifp) & IFCAP_LRO) && do_lro) {
370715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
370815516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
370915516c77SSepherosa Ziehau 
371015516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
371115516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
371215516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
371315516c77SSepherosa Ziehau 				/* DONE! */
371415516c77SSepherosa Ziehau 				return 0;
371515516c77SSepherosa Ziehau 			}
371615516c77SSepherosa Ziehau 		}
371715516c77SSepherosa Ziehau #endif
371815516c77SSepherosa Ziehau 	}
37194db5958aSJustin Hibbits 	if_input(ifp, m_new);
372015516c77SSepherosa Ziehau 
372115516c77SSepherosa Ziehau 	return (0);
372215516c77SSepherosa Ziehau }
372315516c77SSepherosa Ziehau 
372415516c77SSepherosa Ziehau static int
hn_ioctl(if_t ifp,u_long cmd,caddr_t data)37254db5958aSJustin Hibbits hn_ioctl(if_t ifp, u_long cmd, caddr_t data)
372615516c77SSepherosa Ziehau {
37274db5958aSJustin Hibbits 	struct hn_softc *sc = if_getsoftc(ifp);
37289c6cae24SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data, ifr_vf;
37294db5958aSJustin Hibbits 	if_t vf_ifp;
373015516c77SSepherosa Ziehau 	int mask, error = 0;
37318c068aa5SSepherosa Ziehau 	struct ifrsskey *ifrk;
37328c068aa5SSepherosa Ziehau 	struct ifrsshash *ifrh;
3733eb2fe044SSepherosa Ziehau 	uint32_t mtu;
373415516c77SSepherosa Ziehau 
373515516c77SSepherosa Ziehau 	switch (cmd) {
373615516c77SSepherosa Ziehau 	case SIOCSIFMTU:
373715516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
373815516c77SSepherosa Ziehau 			error = EINVAL;
373915516c77SSepherosa Ziehau 			break;
374015516c77SSepherosa Ziehau 		}
374115516c77SSepherosa Ziehau 
374215516c77SSepherosa Ziehau 		HN_LOCK(sc);
374315516c77SSepherosa Ziehau 
374415516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
374515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
374615516c77SSepherosa Ziehau 			break;
374715516c77SSepherosa Ziehau 		}
374815516c77SSepherosa Ziehau 
374915516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
375015516c77SSepherosa Ziehau 			/* Can't change MTU */
375115516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
375215516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
375315516c77SSepherosa Ziehau 			break;
375415516c77SSepherosa Ziehau 		}
375515516c77SSepherosa Ziehau 
37564db5958aSJustin Hibbits 		if (if_getmtu(ifp) == ifr->ifr_mtu) {
375715516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
375815516c77SSepherosa Ziehau 			break;
375915516c77SSepherosa Ziehau 		}
376015516c77SSepherosa Ziehau 
37619c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
37629c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
37639c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
37644db5958aSJustin Hibbits 			strlcpy(ifr_vf.ifr_name, if_name(vf_ifp),
37659c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
37664db5958aSJustin Hibbits 			error = ifhwioctl(SIOCSIFMTU,vf_ifp,
37674db5958aSJustin Hibbits 			    (caddr_t)&ifr_vf, curthread);
37689c6cae24SSepherosa Ziehau 			if (error) {
37699c6cae24SSepherosa Ziehau 				HN_UNLOCK(sc);
37709c6cae24SSepherosa Ziehau 				if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n",
37714db5958aSJustin Hibbits 				    if_name(vf_ifp), ifr->ifr_mtu, error);
37729c6cae24SSepherosa Ziehau 				break;
37739c6cae24SSepherosa Ziehau 			}
37749c6cae24SSepherosa Ziehau 		}
37759c6cae24SSepherosa Ziehau 
377615516c77SSepherosa Ziehau 		/*
377715516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
377815516c77SSepherosa Ziehau 		 * are ripped.
377915516c77SSepherosa Ziehau 		 */
378015516c77SSepherosa Ziehau 		hn_suspend(sc);
378115516c77SSepherosa Ziehau 
378215516c77SSepherosa Ziehau 		/*
378315516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
378415516c77SSepherosa Ziehau 		 */
378515516c77SSepherosa Ziehau 		hn_synth_detach(sc);
378615516c77SSepherosa Ziehau 
378715516c77SSepherosa Ziehau 		/*
378815516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
378915516c77SSepherosa Ziehau 		 * with the new MTU setting.
379015516c77SSepherosa Ziehau 		 */
379115516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
379215516c77SSepherosa Ziehau 		if (error) {
379315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
379415516c77SSepherosa Ziehau 			break;
379515516c77SSepherosa Ziehau 		}
379615516c77SSepherosa Ziehau 
3797eb2fe044SSepherosa Ziehau 		error = hn_rndis_get_mtu(sc, &mtu);
3798eb2fe044SSepherosa Ziehau 		if (error)
3799eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3800eb2fe044SSepherosa Ziehau 		else if (bootverbose)
3801eb2fe044SSepherosa Ziehau 			if_printf(ifp, "RNDIS mtu %u\n", mtu);
3802eb2fe044SSepherosa Ziehau 
380315516c77SSepherosa Ziehau 		/*
380415516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
380515516c77SSepherosa Ziehau 		 * have been successfully attached.
380615516c77SSepherosa Ziehau 		 */
3807eb2fe044SSepherosa Ziehau 		if (mtu >= ifr->ifr_mtu) {
3808eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3809eb2fe044SSepherosa Ziehau 		} else {
3810eb2fe044SSepherosa Ziehau 			if_printf(ifp, "fixup mtu %d -> %u\n",
3811eb2fe044SSepherosa Ziehau 			    ifr->ifr_mtu, mtu);
3812eb2fe044SSepherosa Ziehau 		}
38134db5958aSJustin Hibbits 		if_setmtu(ifp, mtu);
381415516c77SSepherosa Ziehau 
381515516c77SSepherosa Ziehau 		/*
38169c6cae24SSepherosa Ziehau 		 * Synthetic parts' reattach may change the chimney
38179c6cae24SSepherosa Ziehau 		 * sending size; update it.
381815516c77SSepherosa Ziehau 		 */
381915516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
382015516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
38219c6cae24SSepherosa Ziehau 
38229c6cae24SSepherosa Ziehau 		/*
38239c6cae24SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
38249c6cae24SSepherosa Ziehau 		 * still valid, after the MTU change.
38259c6cae24SSepherosa Ziehau 		 */
38269c6cae24SSepherosa Ziehau 		hn_mtu_change_fixup(sc);
382715516c77SSepherosa Ziehau 
382815516c77SSepherosa Ziehau 		/*
382915516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
383015516c77SSepherosa Ziehau 		 */
383115516c77SSepherosa Ziehau 		hn_resume(sc);
383215516c77SSepherosa Ziehau 
3833d0cd8231SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXVF) ||
3834d0cd8231SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
38359c6cae24SSepherosa Ziehau 			/*
38369c6cae24SSepherosa Ziehau 			 * Since we have reattached the NVS part,
38379c6cae24SSepherosa Ziehau 			 * change the datapath to VF again; in case
38389c6cae24SSepherosa Ziehau 			 * that it is lost, after the NVS was detached.
38399c6cae24SSepherosa Ziehau 			 */
38409c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
38419c6cae24SSepherosa Ziehau 		}
38429c6cae24SSepherosa Ziehau 
384315516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
384415516c77SSepherosa Ziehau 		break;
384515516c77SSepherosa Ziehau 
384615516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
384715516c77SSepherosa Ziehau 		HN_LOCK(sc);
384815516c77SSepherosa Ziehau 
384915516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
385015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
385115516c77SSepherosa Ziehau 			break;
385215516c77SSepherosa Ziehau 		}
385315516c77SSepherosa Ziehau 
38549c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc))
38559c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
38569c6cae24SSepherosa Ziehau 
38574db5958aSJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
38584db5958aSJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
3859fdc4f478SSepherosa Ziehau 				/*
3860fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
3861fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
3862fdc4f478SSepherosa Ziehau 				 * reply.
3863fdc4f478SSepherosa Ziehau 				 */
3864fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
3865c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
3866fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
38679c6cae24SSepherosa Ziehau 
38689c6cae24SSepherosa Ziehau 				if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
38699c6cae24SSepherosa Ziehau 					error = hn_xpnt_vf_iocsetflags(sc);
3870fdc4f478SSepherosa Ziehau 			} else {
387115516c77SSepherosa Ziehau 				hn_init_locked(sc);
3872fdc4f478SSepherosa Ziehau 			}
387315516c77SSepherosa Ziehau 		} else {
38744db5958aSJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
38755bdfd3fdSDexuan Cui 				hn_stop(sc, false);
387615516c77SSepherosa Ziehau 		}
38774db5958aSJustin Hibbits 		sc->hn_if_flags = if_getflags(ifp);
387815516c77SSepherosa Ziehau 
387915516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
388015516c77SSepherosa Ziehau 		break;
388115516c77SSepherosa Ziehau 
388215516c77SSepherosa Ziehau 	case SIOCSIFCAP:
388315516c77SSepherosa Ziehau 		HN_LOCK(sc);
38849c6cae24SSepherosa Ziehau 
38859c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
38869c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
38874db5958aSJustin Hibbits 			strlcpy(ifr_vf.ifr_name, if_name(sc->hn_vf_ifp),
38889c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
38899c6cae24SSepherosa Ziehau 			error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf);
38909c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
38919c6cae24SSepherosa Ziehau 			break;
38929c6cae24SSepherosa Ziehau 		}
38939c6cae24SSepherosa Ziehau 
38949c6cae24SSepherosa Ziehau 		/*
38959c6cae24SSepherosa Ziehau 		 * Fix up requested capabilities w/ supported capabilities,
38969c6cae24SSepherosa Ziehau 		 * since the supported capabilities could have been changed.
38979c6cae24SSepherosa Ziehau 		 */
38984db5958aSJustin Hibbits 		mask = (ifr->ifr_reqcap & if_getcapabilities(ifp)) ^
38994db5958aSJustin Hibbits 		    if_getcapenable(ifp);
390015516c77SSepherosa Ziehau 
390115516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
39024db5958aSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TXCSUM);
39034db5958aSJustin Hibbits 			if (if_getcapenable(ifp) & IFCAP_TXCSUM)
39044db5958aSJustin Hibbits 				if_sethwassistbits(ifp, HN_CSUM_IP_HWASSIST(sc), 0);
390515516c77SSepherosa Ziehau 			else
39064db5958aSJustin Hibbits 				if_sethwassistbits(ifp, 0, HN_CSUM_IP_HWASSIST(sc));
390715516c77SSepherosa Ziehau 		}
390815516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
39094db5958aSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TXCSUM_IPV6);
39104db5958aSJustin Hibbits 			if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6)
39114db5958aSJustin Hibbits 				if_sethwassistbits(ifp, HN_CSUM_IP6_HWASSIST(sc), 0);
391215516c77SSepherosa Ziehau 			else
39134db5958aSJustin Hibbits 				if_sethwassistbits(ifp, 0, HN_CSUM_IP6_HWASSIST(sc));
391415516c77SSepherosa Ziehau 		}
391515516c77SSepherosa Ziehau 
391615516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
391715516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
39184db5958aSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_RXCSUM);
391915516c77SSepherosa Ziehau #ifdef foo
392015516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
392115516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
39224db5958aSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_RXCSUM_IPV6);
392315516c77SSepherosa Ziehau #endif
392415516c77SSepherosa Ziehau 
392515516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
39264db5958aSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_LRO);
392715516c77SSepherosa Ziehau 
392815516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
39294db5958aSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TSO4);
39304db5958aSJustin Hibbits 			if (if_getcapenable(ifp) & IFCAP_TSO4)
39314db5958aSJustin Hibbits 				if_sethwassistbits(ifp, CSUM_IP_TSO, 0);
393215516c77SSepherosa Ziehau 			else
39334db5958aSJustin Hibbits 				if_sethwassistbits(ifp, 0, CSUM_IP_TSO);
393415516c77SSepherosa Ziehau 		}
393515516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
39364db5958aSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TSO6);
39374db5958aSJustin Hibbits 			if (if_getcapenable(ifp) & IFCAP_TSO6)
39384db5958aSJustin Hibbits 				if_sethwassistbits(ifp, CSUM_IP6_TSO, 0);
393915516c77SSepherosa Ziehau 			else
39404db5958aSJustin Hibbits 				if_sethwassistbits(ifp, 0, CSUM_IP6_TSO);
394115516c77SSepherosa Ziehau 		}
394215516c77SSepherosa Ziehau 
394315516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
394415516c77SSepherosa Ziehau 		break;
394515516c77SSepherosa Ziehau 
394615516c77SSepherosa Ziehau 	case SIOCADDMULTI:
394715516c77SSepherosa Ziehau 	case SIOCDELMULTI:
394815516c77SSepherosa Ziehau 		HN_LOCK(sc);
394915516c77SSepherosa Ziehau 
395015516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
395115516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
395215516c77SSepherosa Ziehau 			break;
395315516c77SSepherosa Ziehau 		}
39544db5958aSJustin Hibbits 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
3955fdc4f478SSepherosa Ziehau 			/*
3956fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
3957fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
3958fdc4f478SSepherosa Ziehau 			 */
3959fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
3960c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
3961fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
3962fdc4f478SSepherosa Ziehau 		}
396315516c77SSepherosa Ziehau 
39649c6cae24SSepherosa Ziehau 		/* XXX vlan(4) style mcast addr maintenance */
39659c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39669c6cae24SSepherosa Ziehau 			int old_if_flags;
39679c6cae24SSepherosa Ziehau 
39684db5958aSJustin Hibbits 			old_if_flags = if_getflags(sc->hn_vf_ifp);
39699c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
39709c6cae24SSepherosa Ziehau 
39719c6cae24SSepherosa Ziehau 			if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) &&
39724db5958aSJustin Hibbits 			    ((old_if_flags ^ if_getflags(sc->hn_vf_ifp)) &
39739c6cae24SSepherosa Ziehau 			     IFF_ALLMULTI))
39749c6cae24SSepherosa Ziehau 				error = hn_xpnt_vf_iocsetflags(sc);
39759c6cae24SSepherosa Ziehau 		}
39769c6cae24SSepherosa Ziehau 
397715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
397815516c77SSepherosa Ziehau 		break;
397915516c77SSepherosa Ziehau 
398015516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
398115516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
39829c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
39839c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39849c6cae24SSepherosa Ziehau 			/*
39859c6cae24SSepherosa Ziehau 			 * SIOCGIFMEDIA expects ifmediareq, so don't
39869c6cae24SSepherosa Ziehau 			 * create and pass ifr_vf to the VF here; just
39879c6cae24SSepherosa Ziehau 			 * replace the ifr_name.
39889c6cae24SSepherosa Ziehau 			 */
39899c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
39904db5958aSJustin Hibbits 			strlcpy(ifr->ifr_name, if_name(vf_ifp),
39919c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
39924db5958aSJustin Hibbits 			error = ifhwioctl(cmd, vf_ifp, data, curthread);
39939c6cae24SSepherosa Ziehau 			/* Restore the ifr_name. */
39944db5958aSJustin Hibbits 			strlcpy(ifr->ifr_name, if_name(ifp),
39959c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
39969c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
39979c6cae24SSepherosa Ziehau 			break;
39989c6cae24SSepherosa Ziehau 		}
39999c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
400015516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
400115516c77SSepherosa Ziehau 		break;
400215516c77SSepherosa Ziehau 
40038c068aa5SSepherosa Ziehau 	case SIOCGIFRSSHASH:
40048c068aa5SSepherosa Ziehau 		ifrh = (struct ifrsshash *)data;
40058c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
40068c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
40078c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
40088c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_NONE;
40098c068aa5SSepherosa Ziehau 			ifrh->ifrh_types = 0;
40108c068aa5SSepherosa Ziehau 			break;
40118c068aa5SSepherosa Ziehau 		}
40128c068aa5SSepherosa Ziehau 
40138c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
40148c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_TOEPLITZ;
40158c068aa5SSepherosa Ziehau 		else
40168c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_PRIVATE;
4017642ec226SSepherosa Ziehau 		ifrh->ifrh_types = hn_rss_type_fromndis(sc->hn_rss_hash);
40188c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
40198c068aa5SSepherosa Ziehau 		break;
40208c068aa5SSepherosa Ziehau 
40218c068aa5SSepherosa Ziehau 	case SIOCGIFRSSKEY:
40228c068aa5SSepherosa Ziehau 		ifrk = (struct ifrsskey *)data;
40238c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
40248c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
40258c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
40268c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_NONE;
40278c068aa5SSepherosa Ziehau 			ifrk->ifrk_keylen = 0;
40288c068aa5SSepherosa Ziehau 			break;
40298c068aa5SSepherosa Ziehau 		}
40308c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
40318c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_TOEPLITZ;
40328c068aa5SSepherosa Ziehau 		else
40338c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_PRIVATE;
40348c068aa5SSepherosa Ziehau 		ifrk->ifrk_keylen = NDIS_HASH_KEYSIZE_TOEPLITZ;
40358c068aa5SSepherosa Ziehau 		memcpy(ifrk->ifrk_key, sc->hn_rss.rss_key,
40368c068aa5SSepherosa Ziehau 		    NDIS_HASH_KEYSIZE_TOEPLITZ);
40378c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
40388c068aa5SSepherosa Ziehau 		break;
40398c068aa5SSepherosa Ziehau 
404015516c77SSepherosa Ziehau 	default:
404115516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
404215516c77SSepherosa Ziehau 		break;
404315516c77SSepherosa Ziehau 	}
404415516c77SSepherosa Ziehau 	return (error);
404515516c77SSepherosa Ziehau }
404615516c77SSepherosa Ziehau 
404715516c77SSepherosa Ziehau static void
hn_stop(struct hn_softc * sc,bool detaching)40485bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
404915516c77SSepherosa Ziehau {
40504db5958aSJustin Hibbits 	if_t ifp = sc->hn_ifp;
405115516c77SSepherosa Ziehau 	int i;
405215516c77SSepherosa Ziehau 
405315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
405415516c77SSepherosa Ziehau 
405515516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
405615516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
405715516c77SSepherosa Ziehau 
40589c6cae24SSepherosa Ziehau 	/* Clear RUNNING bit ASAP. */
40594db5958aSJustin Hibbits 	if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING);
40609c6cae24SSepherosa Ziehau 
40616c1204dfSSepherosa Ziehau 	/* Disable polling. */
40626c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
40636c1204dfSSepherosa Ziehau 
40649c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
40659c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_ifp != NULL,
40664db5958aSJustin Hibbits 		    ("%s: VF is not attached", if_name(ifp)));
40679c6cae24SSepherosa Ziehau 
4068a97fff19SSepherosa Ziehau 		/* Mark transparent mode VF as disabled. */
4069a97fff19SSepherosa Ziehau 		hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */);
40709c6cae24SSepherosa Ziehau 
40719c6cae24SSepherosa Ziehau 		/*
40729c6cae24SSepherosa Ziehau 		 * NOTE:
40739c6cae24SSepherosa Ziehau 		 * Datapath setting must happen _before_ bringing
40749c6cae24SSepherosa Ziehau 		 * the VF down.
40759c6cae24SSepherosa Ziehau 		 */
40769c6cae24SSepherosa Ziehau 		hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
40779c6cae24SSepherosa Ziehau 
40789c6cae24SSepherosa Ziehau 		/*
40799c6cae24SSepherosa Ziehau 		 * Bring the VF down.
40809c6cae24SSepherosa Ziehau 		 */
40819c6cae24SSepherosa Ziehau 		hn_xpnt_vf_saveifflags(sc);
40824db5958aSJustin Hibbits 		if_setflagbits(ifp, 0, IFF_UP);
40839c6cae24SSepherosa Ziehau 		hn_xpnt_vf_iocsetflags(sc);
40849c6cae24SSepherosa Ziehau 	}
40859c6cae24SSepherosa Ziehau 
40869c6cae24SSepherosa Ziehau 	/* Suspend data transfers. */
408715516c77SSepherosa Ziehau 	hn_suspend_data(sc);
408815516c77SSepherosa Ziehau 
408915516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
40904db5958aSJustin Hibbits 	if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
409115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
409215516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
40935bdfd3fdSDexuan Cui 
40945bdfd3fdSDexuan Cui 	/*
40959c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is active, make sure
40969c6cae24SSepherosa Ziehau 	 * that the RX filter still allows packet reception.
40975bdfd3fdSDexuan Cui 	 */
4098962f0357SSepherosa Ziehau 	if (!detaching && (sc->hn_flags & HN_FLAG_RXVF))
40995bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
410015516c77SSepherosa Ziehau }
410115516c77SSepherosa Ziehau 
410215516c77SSepherosa Ziehau static void
hn_init_locked(struct hn_softc * sc)410315516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
410415516c77SSepherosa Ziehau {
41054db5958aSJustin Hibbits 	if_t ifp = sc->hn_ifp;
410615516c77SSepherosa Ziehau 	int i;
410715516c77SSepherosa Ziehau 
410815516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
410915516c77SSepherosa Ziehau 
411015516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
411115516c77SSepherosa Ziehau 		return;
411215516c77SSepherosa Ziehau 
41134db5958aSJustin Hibbits 	if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
411415516c77SSepherosa Ziehau 		return;
411515516c77SSepherosa Ziehau 
411615516c77SSepherosa Ziehau 	/* Configure RX filter */
4117c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
411815516c77SSepherosa Ziehau 
411915516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
41204db5958aSJustin Hibbits 	if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
412115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
412215516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
412315516c77SSepherosa Ziehau 
412415516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
412515516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
412615516c77SSepherosa Ziehau 
41279c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
41289c6cae24SSepherosa Ziehau 		/* Initialize transparent VF. */
41299c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
41309c6cae24SSepherosa Ziehau 	}
41319c6cae24SSepherosa Ziehau 
413215516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
41334db5958aSJustin Hibbits 	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
41346c1204dfSSepherosa Ziehau 
41356c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
41366c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
41376c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
413815516c77SSepherosa Ziehau }
413915516c77SSepherosa Ziehau 
414015516c77SSepherosa Ziehau static void
hn_init(void * xsc)414115516c77SSepherosa Ziehau hn_init(void *xsc)
414215516c77SSepherosa Ziehau {
414315516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
414415516c77SSepherosa Ziehau 
414515516c77SSepherosa Ziehau 	HN_LOCK(sc);
414615516c77SSepherosa Ziehau 	hn_init_locked(sc);
414715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
414815516c77SSepherosa Ziehau }
414915516c77SSepherosa Ziehau 
415015516c77SSepherosa Ziehau static int
hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)415115516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
415215516c77SSepherosa Ziehau {
415315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
415415516c77SSepherosa Ziehau 	unsigned int lenlim;
415515516c77SSepherosa Ziehau 	int error;
415615516c77SSepherosa Ziehau 
415715516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
415815516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
415915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
416015516c77SSepherosa Ziehau 		return error;
416115516c77SSepherosa Ziehau 
416215516c77SSepherosa Ziehau 	HN_LOCK(sc);
416315516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
416415516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
416515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
416615516c77SSepherosa Ziehau 		return EINVAL;
416715516c77SSepherosa Ziehau 	}
416815516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
416915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
417015516c77SSepherosa Ziehau 
417115516c77SSepherosa Ziehau 	return 0;
417215516c77SSepherosa Ziehau }
417315516c77SSepherosa Ziehau 
417415516c77SSepherosa Ziehau static int
hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)417515516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
417615516c77SSepherosa Ziehau {
417715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
417815516c77SSepherosa Ziehau 	int ackcnt, error, i;
417915516c77SSepherosa Ziehau 
418015516c77SSepherosa Ziehau 	/*
418115516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
418215516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
418315516c77SSepherosa Ziehau 	 */
418415516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
418515516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
418615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
418715516c77SSepherosa Ziehau 		return error;
418815516c77SSepherosa Ziehau 
418915516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
419015516c77SSepherosa Ziehau 		return EINVAL;
419115516c77SSepherosa Ziehau 
419215516c77SSepherosa Ziehau 	/*
419315516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
419415516c77SSepherosa Ziehau 	 * count limit.
419515516c77SSepherosa Ziehau 	 */
419615516c77SSepherosa Ziehau 	--ackcnt;
419715516c77SSepherosa Ziehau 	HN_LOCK(sc);
4198a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
419915516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
420015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
420115516c77SSepherosa Ziehau 	return 0;
420215516c77SSepherosa Ziehau }
420315516c77SSepherosa Ziehau 
420415516c77SSepherosa Ziehau static int
hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)420515516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
420615516c77SSepherosa Ziehau {
420715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
420815516c77SSepherosa Ziehau 	int hcsum = arg2;
420915516c77SSepherosa Ziehau 	int on, error, i;
421015516c77SSepherosa Ziehau 
421115516c77SSepherosa Ziehau 	on = 0;
421215516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
421315516c77SSepherosa Ziehau 		on = 1;
421415516c77SSepherosa Ziehau 
421515516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
421615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
421715516c77SSepherosa Ziehau 		return error;
421815516c77SSepherosa Ziehau 
421915516c77SSepherosa Ziehau 	HN_LOCK(sc);
4220a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
422115516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
422215516c77SSepherosa Ziehau 
422315516c77SSepherosa Ziehau 		if (on)
422415516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
422515516c77SSepherosa Ziehau 		else
422615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
422715516c77SSepherosa Ziehau 	}
422815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
422915516c77SSepherosa Ziehau 	return 0;
423015516c77SSepherosa Ziehau }
423115516c77SSepherosa Ziehau 
423215516c77SSepherosa Ziehau static int
hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)423315516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
423415516c77SSepherosa Ziehau {
423515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
423615516c77SSepherosa Ziehau 	int chim_size, error;
423715516c77SSepherosa Ziehau 
423815516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
423915516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
424015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
424115516c77SSepherosa Ziehau 		return error;
424215516c77SSepherosa Ziehau 
424315516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
424415516c77SSepherosa Ziehau 		return EINVAL;
424515516c77SSepherosa Ziehau 
424615516c77SSepherosa Ziehau 	HN_LOCK(sc);
424715516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
424815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
424915516c77SSepherosa Ziehau 	return 0;
425015516c77SSepherosa Ziehau }
425115516c77SSepherosa Ziehau 
425215516c77SSepherosa Ziehau static int
hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)425315516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
425415516c77SSepherosa Ziehau {
425515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
425615516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
425715516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
425815516c77SSepherosa Ziehau 	uint64_t stat;
425915516c77SSepherosa Ziehau 
426015516c77SSepherosa Ziehau 	stat = 0;
4261a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
426215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
426315516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
426415516c77SSepherosa Ziehau 	}
426515516c77SSepherosa Ziehau 
426615516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
426715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
426815516c77SSepherosa Ziehau 		return error;
426915516c77SSepherosa Ziehau 
427015516c77SSepherosa Ziehau 	/* Zero out this stat. */
4271a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
427215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
427315516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
427415516c77SSepherosa Ziehau 	}
427515516c77SSepherosa Ziehau 	return 0;
427615516c77SSepherosa Ziehau }
427715516c77SSepherosa Ziehau 
427815516c77SSepherosa Ziehau static int
hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)427915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
428015516c77SSepherosa Ziehau {
428115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
428215516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
428315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
428415516c77SSepherosa Ziehau 	u_long stat;
428515516c77SSepherosa Ziehau 
428615516c77SSepherosa Ziehau 	stat = 0;
4287a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
428815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
428915516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
429015516c77SSepherosa Ziehau 	}
429115516c77SSepherosa Ziehau 
429215516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
429315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
429415516c77SSepherosa Ziehau 		return error;
429515516c77SSepherosa Ziehau 
429615516c77SSepherosa Ziehau 	/* Zero out this stat. */
4297a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
429815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
429915516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
430015516c77SSepherosa Ziehau 	}
430115516c77SSepherosa Ziehau 	return 0;
430215516c77SSepherosa Ziehau }
430315516c77SSepherosa Ziehau 
430415516c77SSepherosa Ziehau static int
hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)430515516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
430615516c77SSepherosa Ziehau {
430715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
430815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
430915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
431015516c77SSepherosa Ziehau 	u_long stat;
431115516c77SSepherosa Ziehau 
431215516c77SSepherosa Ziehau 	stat = 0;
4313a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
431415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
431515516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
431615516c77SSepherosa Ziehau 	}
431715516c77SSepherosa Ziehau 
431815516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
431915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
432015516c77SSepherosa Ziehau 		return error;
432115516c77SSepherosa Ziehau 
432215516c77SSepherosa Ziehau 	/* Zero out this stat. */
4323a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
432415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
432515516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
432615516c77SSepherosa Ziehau 	}
432715516c77SSepherosa Ziehau 	return 0;
432815516c77SSepherosa Ziehau }
432915516c77SSepherosa Ziehau 
433015516c77SSepherosa Ziehau static int
hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)433115516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
433215516c77SSepherosa Ziehau {
433315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
433415516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
433515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
433615516c77SSepherosa Ziehau 
433715516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
433815516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
433915516c77SSepherosa Ziehau 
434015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
434115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
434215516c77SSepherosa Ziehau 		return error;
434315516c77SSepherosa Ziehau 
434415516c77SSepherosa Ziehau 	HN_LOCK(sc);
4345a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
434615516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
434715516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
434815516c77SSepherosa Ziehau 	}
434915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
435015516c77SSepherosa Ziehau 
435115516c77SSepherosa Ziehau 	return 0;
435215516c77SSepherosa Ziehau }
435315516c77SSepherosa Ziehau 
435415516c77SSepherosa Ziehau static int
hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)4355dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
4356dc13fee6SSepherosa Ziehau {
4357dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4358dc13fee6SSepherosa Ziehau 	int error, size;
4359dc13fee6SSepherosa Ziehau 
4360dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
4361dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
4362dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4363dc13fee6SSepherosa Ziehau 		return (error);
4364dc13fee6SSepherosa Ziehau 
4365dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4366dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
4367dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4368dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4369dc13fee6SSepherosa Ziehau 
4370dc13fee6SSepherosa Ziehau 	return (0);
4371dc13fee6SSepherosa Ziehau }
4372dc13fee6SSepherosa Ziehau 
4373dc13fee6SSepherosa Ziehau static int
hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)4374dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
4375dc13fee6SSepherosa Ziehau {
4376dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4377dc13fee6SSepherosa Ziehau 	int error, pkts;
4378dc13fee6SSepherosa Ziehau 
4379dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
4380dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
4381dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4382dc13fee6SSepherosa Ziehau 		return (error);
4383dc13fee6SSepherosa Ziehau 
4384dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4385dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
4386dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4387dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4388dc13fee6SSepherosa Ziehau 
4389dc13fee6SSepherosa Ziehau 	return (0);
4390dc13fee6SSepherosa Ziehau }
4391dc13fee6SSepherosa Ziehau 
4392dc13fee6SSepherosa Ziehau static int
hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)4393dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
4394dc13fee6SSepherosa Ziehau {
4395dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4396dc13fee6SSepherosa Ziehau 	int pkts;
4397dc13fee6SSepherosa Ziehau 
4398dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
4399dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
4400dc13fee6SSepherosa Ziehau }
4401dc13fee6SSepherosa Ziehau 
4402dc13fee6SSepherosa Ziehau static int
hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)4403dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
4404dc13fee6SSepherosa Ziehau {
4405dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4406dc13fee6SSepherosa Ziehau 	int align;
4407dc13fee6SSepherosa Ziehau 
4408dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
4409dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
4410dc13fee6SSepherosa Ziehau }
4411dc13fee6SSepherosa Ziehau 
44126c1204dfSSepherosa Ziehau static void
hn_chan_polling(struct vmbus_channel * chan,u_int pollhz)44136c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
44146c1204dfSSepherosa Ziehau {
44156c1204dfSSepherosa Ziehau 	if (pollhz == 0)
44166c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
44176c1204dfSSepherosa Ziehau 	else
44186c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
44196c1204dfSSepherosa Ziehau }
44206c1204dfSSepherosa Ziehau 
44216c1204dfSSepherosa Ziehau static void
hn_polling(struct hn_softc * sc,u_int pollhz)44226c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
44236c1204dfSSepherosa Ziehau {
44246c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
44256c1204dfSSepherosa Ziehau 
44266c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
44276c1204dfSSepherosa Ziehau 
44286c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
44296c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
44306c1204dfSSepherosa Ziehau 		int i;
44316c1204dfSSepherosa Ziehau 
44326c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
44336c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
44346c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
44356c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
44366c1204dfSSepherosa Ziehau 	}
44376c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
44386c1204dfSSepherosa Ziehau }
44396c1204dfSSepherosa Ziehau 
44406c1204dfSSepherosa Ziehau static int
hn_polling_sysctl(SYSCTL_HANDLER_ARGS)44416c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
44426c1204dfSSepherosa Ziehau {
44436c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
44446c1204dfSSepherosa Ziehau 	int pollhz, error;
44456c1204dfSSepherosa Ziehau 
44466c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
44476c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
44486c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
44496c1204dfSSepherosa Ziehau 		return (error);
44506c1204dfSSepherosa Ziehau 
44516c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
44526c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
44536c1204dfSSepherosa Ziehau 		return (EINVAL);
44546c1204dfSSepherosa Ziehau 
44556c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
44566c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
44576c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
44584db5958aSJustin Hibbits 		if ((if_getdrvflags(sc->hn_ifp) & IFF_DRV_RUNNING) &&
44596c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
44606c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
44616c1204dfSSepherosa Ziehau 	}
44626c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
44636c1204dfSSepherosa Ziehau 
44646c1204dfSSepherosa Ziehau 	return (0);
44656c1204dfSSepherosa Ziehau }
44666c1204dfSSepherosa Ziehau 
4467dc13fee6SSepherosa Ziehau static int
hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)446815516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
446915516c77SSepherosa Ziehau {
447015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
447115516c77SSepherosa Ziehau 	char verstr[16];
447215516c77SSepherosa Ziehau 
447315516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
447415516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
447515516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
447615516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
447715516c77SSepherosa Ziehau }
447815516c77SSepherosa Ziehau 
447915516c77SSepherosa Ziehau static int
hn_caps_sysctl(SYSCTL_HANDLER_ARGS)448015516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
448115516c77SSepherosa Ziehau {
448215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
448315516c77SSepherosa Ziehau 	char caps_str[128];
448415516c77SSepherosa Ziehau 	uint32_t caps;
448515516c77SSepherosa Ziehau 
448615516c77SSepherosa Ziehau 	HN_LOCK(sc);
448715516c77SSepherosa Ziehau 	caps = sc->hn_caps;
448815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
448915516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
449015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
449115516c77SSepherosa Ziehau }
449215516c77SSepherosa Ziehau 
449315516c77SSepherosa Ziehau static int
hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)449415516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
449515516c77SSepherosa Ziehau {
449615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
449715516c77SSepherosa Ziehau 	char assist_str[128];
449815516c77SSepherosa Ziehau 	uint32_t hwassist;
449915516c77SSepherosa Ziehau 
450015516c77SSepherosa Ziehau 	HN_LOCK(sc);
45014db5958aSJustin Hibbits 	hwassist = if_gethwassist(sc->hn_ifp);
450215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
450315516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
450415516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
450515516c77SSepherosa Ziehau }
450615516c77SSepherosa Ziehau 
450715516c77SSepherosa Ziehau static int
hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)450815516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
450915516c77SSepherosa Ziehau {
451015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
451115516c77SSepherosa Ziehau 	char filter_str[128];
451215516c77SSepherosa Ziehau 	uint32_t filter;
451315516c77SSepherosa Ziehau 
451415516c77SSepherosa Ziehau 	HN_LOCK(sc);
451515516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
451615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
451715516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
451815516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
451915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
452015516c77SSepherosa Ziehau }
452115516c77SSepherosa Ziehau 
452280c3eb7bSWei Hu static int
hn_rsc_sysctl(SYSCTL_HANDLER_ARGS)452380c3eb7bSWei Hu hn_rsc_sysctl(SYSCTL_HANDLER_ARGS)
452480c3eb7bSWei Hu {
452580c3eb7bSWei Hu 	struct hn_softc *sc = arg1;
4526*da1deb78SWei Hu 	int rsc_ctrl, mtu;
452780c3eb7bSWei Hu 	int error;
452880c3eb7bSWei Hu 
4529*da1deb78SWei Hu 	rsc_ctrl = sc->hn_rsc_ctrl;
4530*da1deb78SWei Hu 	error = sysctl_handle_int(oidp, &rsc_ctrl, 0, req);
4531*da1deb78SWei Hu 	if (error || req->newptr == NULL)
4532*da1deb78SWei Hu 		return (error);
4533*da1deb78SWei Hu 
4534*da1deb78SWei Hu 	if (sc->hn_rsc_ctrl != rsc_ctrl) {
4535*da1deb78SWei Hu 		HN_LOCK(sc);
4536*da1deb78SWei Hu 		sc->hn_rsc_ctrl = rsc_ctrl;
4537*da1deb78SWei Hu 		mtu = if_getmtu(sc->hn_ifp);
453880c3eb7bSWei Hu 		error = hn_rndis_reconf_offload(sc, mtu);
453980c3eb7bSWei Hu 		HN_UNLOCK(sc);
4540*da1deb78SWei Hu 	}
4541*da1deb78SWei Hu 
454280c3eb7bSWei Hu 	return (error);
454380c3eb7bSWei Hu }
454434d68912SSepherosa Ziehau #ifndef RSS
454534d68912SSepherosa Ziehau 
454615516c77SSepherosa Ziehau static int
hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)454715516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
454815516c77SSepherosa Ziehau {
454915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
455015516c77SSepherosa Ziehau 	int error;
455115516c77SSepherosa Ziehau 
455215516c77SSepherosa Ziehau 	HN_LOCK(sc);
455315516c77SSepherosa Ziehau 
455415516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
455515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
455615516c77SSepherosa Ziehau 		goto back;
455715516c77SSepherosa Ziehau 
4558642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
4559642ec226SSepherosa Ziehau 	    (hn_xpnt_vf && sc->hn_vf_ifp != NULL)) {
4560642ec226SSepherosa Ziehau 		/*
4561642ec226SSepherosa Ziehau 		 * RSS key is synchronized w/ VF's, don't allow users
4562642ec226SSepherosa Ziehau 		 * to change it.
4563642ec226SSepherosa Ziehau 		 */
4564642ec226SSepherosa Ziehau 		error = EBUSY;
4565642ec226SSepherosa Ziehau 		goto back;
4566642ec226SSepherosa Ziehau 	}
4567642ec226SSepherosa Ziehau 
456815516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
456915516c77SSepherosa Ziehau 	if (error)
457015516c77SSepherosa Ziehau 		goto back;
457115516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
457215516c77SSepherosa Ziehau 
457315516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
457415516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
457515516c77SSepherosa Ziehau 	} else {
457615516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
457715516c77SSepherosa Ziehau 		error = 0;
457815516c77SSepherosa Ziehau 	}
457915516c77SSepherosa Ziehau back:
458015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
458115516c77SSepherosa Ziehau 	return (error);
458215516c77SSepherosa Ziehau }
458315516c77SSepherosa Ziehau 
458415516c77SSepherosa Ziehau static int
hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)458515516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
458615516c77SSepherosa Ziehau {
458715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
458815516c77SSepherosa Ziehau 	int error;
458915516c77SSepherosa Ziehau 
459015516c77SSepherosa Ziehau 	HN_LOCK(sc);
459115516c77SSepherosa Ziehau 
459215516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
459315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
459415516c77SSepherosa Ziehau 		goto back;
459515516c77SSepherosa Ziehau 
459615516c77SSepherosa Ziehau 	/*
459715516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
459815516c77SSepherosa Ziehau 	 * RSS capable currently.
459915516c77SSepherosa Ziehau 	 */
460015516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
460115516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
460215516c77SSepherosa Ziehau 		goto back;
460315516c77SSepherosa Ziehau 	}
460415516c77SSepherosa Ziehau 
460515516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
460615516c77SSepherosa Ziehau 	if (error)
460715516c77SSepherosa Ziehau 		goto back;
460815516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
460915516c77SSepherosa Ziehau 
4610afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
461115516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
461215516c77SSepherosa Ziehau back:
461315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
461415516c77SSepherosa Ziehau 	return (error);
461515516c77SSepherosa Ziehau }
461615516c77SSepherosa Ziehau 
461734d68912SSepherosa Ziehau #endif	/* !RSS */
461834d68912SSepherosa Ziehau 
461915516c77SSepherosa Ziehau static int
hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)462015516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
462115516c77SSepherosa Ziehau {
462215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
462315516c77SSepherosa Ziehau 	char hash_str[128];
462415516c77SSepherosa Ziehau 	uint32_t hash;
462515516c77SSepherosa Ziehau 
462615516c77SSepherosa Ziehau 	HN_LOCK(sc);
462715516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
462815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
462915516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
463015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
463115516c77SSepherosa Ziehau }
463215516c77SSepherosa Ziehau 
463315516c77SSepherosa Ziehau static int
hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS)4634642ec226SSepherosa Ziehau hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS)
4635642ec226SSepherosa Ziehau {
4636642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4637642ec226SSepherosa Ziehau 	char hash_str[128];
4638642ec226SSepherosa Ziehau 	uint32_t hash;
4639642ec226SSepherosa Ziehau 
4640642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4641642ec226SSepherosa Ziehau 	hash = sc->hn_rss_hcap;
4642642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4643642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4644642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4645642ec226SSepherosa Ziehau }
4646642ec226SSepherosa Ziehau 
4647642ec226SSepherosa Ziehau static int
hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS)4648642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS)
4649642ec226SSepherosa Ziehau {
4650642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4651642ec226SSepherosa Ziehau 	char hash_str[128];
4652642ec226SSepherosa Ziehau 	uint32_t hash;
4653642ec226SSepherosa Ziehau 
4654642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4655642ec226SSepherosa Ziehau 	hash = sc->hn_rx_ring[0].hn_mbuf_hash;
4656642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4657642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4658642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4659642ec226SSepherosa Ziehau }
4660642ec226SSepherosa Ziehau 
4661642ec226SSepherosa Ziehau static int
hn_vf_sysctl(SYSCTL_HANDLER_ARGS)466240d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
466340d60d6eSDexuan Cui {
466440d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
4665499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
46664db5958aSJustin Hibbits 	if_t vf_ifp;
466740d60d6eSDexuan Cui 
466840d60d6eSDexuan Cui 	HN_LOCK(sc);
466940d60d6eSDexuan Cui 	vf_name[0] = '\0';
4670962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
4671962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
46724db5958aSJustin Hibbits 		snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf_ifp));
467340d60d6eSDexuan Cui 	HN_UNLOCK(sc);
467440d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
467540d60d6eSDexuan Cui }
467640d60d6eSDexuan Cui 
467740d60d6eSDexuan Cui static int
hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS)4678499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS)
4679499c3e17SSepherosa Ziehau {
4680499c3e17SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4681499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
46824db5958aSJustin Hibbits 	if_t vf_ifp;
4683499c3e17SSepherosa Ziehau 
4684499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
4685499c3e17SSepherosa Ziehau 	vf_name[0] = '\0';
4686962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp;
4687962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
46884db5958aSJustin Hibbits 		snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf_ifp));
4689499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
4690499c3e17SSepherosa Ziehau 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
4691499c3e17SSepherosa Ziehau }
4692499c3e17SSepherosa Ziehau 
4693499c3e17SSepherosa Ziehau static int
hn_vflist_sysctl(SYSCTL_HANDLER_ARGS)4694499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS)
4695499c3e17SSepherosa Ziehau {
4696499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4697499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4698499c3e17SSepherosa Ziehau 	int error, i;
4699499c3e17SSepherosa Ziehau 	bool first;
4700499c3e17SSepherosa Ziehau 
4701499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4702499c3e17SSepherosa Ziehau 	if (error != 0)
4703499c3e17SSepherosa Ziehau 		return (error);
4704499c3e17SSepherosa Ziehau 
4705499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4706499c3e17SSepherosa Ziehau 	if (sb == NULL)
4707499c3e17SSepherosa Ziehau 		return (ENOMEM);
4708499c3e17SSepherosa Ziehau 
4709499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4710499c3e17SSepherosa Ziehau 
4711499c3e17SSepherosa Ziehau 	first = true;
4712499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4713d74b7baeSGleb Smirnoff 		struct epoch_tracker et;
47144db5958aSJustin Hibbits 		if_t ifp;
4715499c3e17SSepherosa Ziehau 
4716499c3e17SSepherosa Ziehau 		if (hn_vfmap[i] == NULL)
4717499c3e17SSepherosa Ziehau 			continue;
4718499c3e17SSepherosa Ziehau 
4719d74b7baeSGleb Smirnoff 		NET_EPOCH_ENTER(et);
4720499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4721499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4722499c3e17SSepherosa Ziehau 			if (first)
47234db5958aSJustin Hibbits 				sbuf_printf(sb, "%s", if_name(ifp));
4724499c3e17SSepherosa Ziehau 			else
47254db5958aSJustin Hibbits 				sbuf_printf(sb, " %s", if_name(ifp));
4726499c3e17SSepherosa Ziehau 			first = false;
4727499c3e17SSepherosa Ziehau 		}
4728d74b7baeSGleb Smirnoff 		NET_EPOCH_EXIT(et);
4729499c3e17SSepherosa Ziehau 	}
4730499c3e17SSepherosa Ziehau 
4731499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4732499c3e17SSepherosa Ziehau 
4733499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4734499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4735499c3e17SSepherosa Ziehau 	return (error);
4736499c3e17SSepherosa Ziehau }
4737499c3e17SSepherosa Ziehau 
4738499c3e17SSepherosa Ziehau static int
hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS)4739499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS)
4740499c3e17SSepherosa Ziehau {
4741499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4742499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4743499c3e17SSepherosa Ziehau 	int error, i;
4744499c3e17SSepherosa Ziehau 	bool first;
4745499c3e17SSepherosa Ziehau 
4746499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4747499c3e17SSepherosa Ziehau 	if (error != 0)
4748499c3e17SSepherosa Ziehau 		return (error);
4749499c3e17SSepherosa Ziehau 
4750499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4751499c3e17SSepherosa Ziehau 	if (sb == NULL)
4752499c3e17SSepherosa Ziehau 		return (ENOMEM);
4753499c3e17SSepherosa Ziehau 
4754499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4755499c3e17SSepherosa Ziehau 
4756499c3e17SSepherosa Ziehau 	first = true;
4757499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4758d74b7baeSGleb Smirnoff 		struct epoch_tracker et;
47594db5958aSJustin Hibbits 		if_t ifp, hn_ifp;
4760499c3e17SSepherosa Ziehau 
4761499c3e17SSepherosa Ziehau 		hn_ifp = hn_vfmap[i];
4762499c3e17SSepherosa Ziehau 		if (hn_ifp == NULL)
4763499c3e17SSepherosa Ziehau 			continue;
4764499c3e17SSepherosa Ziehau 
4765d74b7baeSGleb Smirnoff 		NET_EPOCH_ENTER(et);
4766499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4767499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4768499c3e17SSepherosa Ziehau 			if (first) {
47694db5958aSJustin Hibbits 				sbuf_printf(sb, "%s:%s", if_name(ifp),
47704db5958aSJustin Hibbits 				    if_name(hn_ifp));
4771499c3e17SSepherosa Ziehau 			} else {
47724db5958aSJustin Hibbits 				sbuf_printf(sb, " %s:%s", if_name(ifp),
47734db5958aSJustin Hibbits 				    if_name(hn_ifp));
4774499c3e17SSepherosa Ziehau 			}
4775499c3e17SSepherosa Ziehau 			first = false;
4776499c3e17SSepherosa Ziehau 		}
4777d74b7baeSGleb Smirnoff 		NET_EPOCH_EXIT(et);
4778499c3e17SSepherosa Ziehau 	}
4779499c3e17SSepherosa Ziehau 
4780499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4781499c3e17SSepherosa Ziehau 
4782499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4783499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4784499c3e17SSepherosa Ziehau 	return (error);
4785499c3e17SSepherosa Ziehau }
4786499c3e17SSepherosa Ziehau 
4787499c3e17SSepherosa Ziehau static int
hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS)47889c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS)
47899c6cae24SSepherosa Ziehau {
47909c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
47919c6cae24SSepherosa Ziehau 	int error, onoff = 0;
47929c6cae24SSepherosa Ziehau 
47939c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF)
47949c6cae24SSepherosa Ziehau 		onoff = 1;
47959c6cae24SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &onoff, 0, req);
47969c6cae24SSepherosa Ziehau 	if (error || req->newptr == NULL)
47979c6cae24SSepherosa Ziehau 		return (error);
47989c6cae24SSepherosa Ziehau 
47999c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
48009c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit() */
48019c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
48029c6cae24SSepherosa Ziehau 	if (onoff)
48039c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
48049c6cae24SSepherosa Ziehau 	else
48059c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF;
48069c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
48079c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
48089c6cae24SSepherosa Ziehau 
48099c6cae24SSepherosa Ziehau 	return (0);
48109c6cae24SSepherosa Ziehau }
48119c6cae24SSepherosa Ziehau 
48129c6cae24SSepherosa Ziehau static int
hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS)48139c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS)
48149c6cae24SSepherosa Ziehau {
48159c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
48169c6cae24SSepherosa Ziehau 	int enabled = 0;
48179c6cae24SSepherosa Ziehau 
48189c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
48199c6cae24SSepherosa Ziehau 		enabled = 1;
48209c6cae24SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &enabled, 0, req));
48219c6cae24SSepherosa Ziehau }
48229c6cae24SSepherosa Ziehau 
48239c6cae24SSepherosa Ziehau static int
hn_check_iplen(const struct mbuf * m,int hoff)482415516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
482515516c77SSepherosa Ziehau {
482615516c77SSepherosa Ziehau 	const struct ip *ip;
482715516c77SSepherosa Ziehau 	int len, iphlen, iplen;
482815516c77SSepherosa Ziehau 	const struct tcphdr *th;
482915516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
483015516c77SSepherosa Ziehau 
483115516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
483215516c77SSepherosa Ziehau 
483315516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
483415516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
483515516c77SSepherosa Ziehau 		return IPPROTO_DONE;
483615516c77SSepherosa Ziehau 
483715516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
483815516c77SSepherosa Ziehau 	if (m->m_len < len)
483915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
484015516c77SSepherosa Ziehau 
484115516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
484215516c77SSepherosa Ziehau 
484315516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
484415516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
484515516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
484615516c77SSepherosa Ziehau 		return IPPROTO_DONE;
484715516c77SSepherosa Ziehau 
484815516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
484915516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
485015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
485115516c77SSepherosa Ziehau 
485215516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
485315516c77SSepherosa Ziehau 
485415516c77SSepherosa Ziehau 	/*
485515516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
485615516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
485715516c77SSepherosa Ziehau 	 */
485815516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
485915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
486015516c77SSepherosa Ziehau 
486115516c77SSepherosa Ziehau 	/*
486215516c77SSepherosa Ziehau 	 * Ignore IP fragments.
486315516c77SSepherosa Ziehau 	 */
486415516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
486515516c77SSepherosa Ziehau 		return IPPROTO_DONE;
486615516c77SSepherosa Ziehau 
486715516c77SSepherosa Ziehau 	/*
486815516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
486915516c77SSepherosa Ziehau 	 * the first fragment of a packet.
487015516c77SSepherosa Ziehau 	 */
487115516c77SSepherosa Ziehau 	switch (ip->ip_p) {
487215516c77SSepherosa Ziehau 	case IPPROTO_TCP:
487315516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
487415516c77SSepherosa Ziehau 			return IPPROTO_DONE;
487515516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
487615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
487715516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
487815516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
487915516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
488015516c77SSepherosa Ziehau 			return IPPROTO_DONE;
488115516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
488215516c77SSepherosa Ziehau 			return IPPROTO_DONE;
488315516c77SSepherosa Ziehau 		break;
488415516c77SSepherosa Ziehau 	case IPPROTO_UDP:
488515516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
488615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
488715516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
488815516c77SSepherosa Ziehau 			return IPPROTO_DONE;
488915516c77SSepherosa Ziehau 		break;
489015516c77SSepherosa Ziehau 	default:
489115516c77SSepherosa Ziehau 		if (iplen < iphlen)
489215516c77SSepherosa Ziehau 			return IPPROTO_DONE;
489315516c77SSepherosa Ziehau 		break;
489415516c77SSepherosa Ziehau 	}
489515516c77SSepherosa Ziehau 	return ip->ip_p;
489615516c77SSepherosa Ziehau }
489715516c77SSepherosa Ziehau 
4898db76829bSSepherosa Ziehau static void
hn_rxpkt_proto(const struct mbuf * m_new,int * l3proto,int * l4proto)4899db76829bSSepherosa Ziehau hn_rxpkt_proto(const struct mbuf *m_new, int *l3proto, int *l4proto)
4900db76829bSSepherosa Ziehau {
4901db76829bSSepherosa Ziehau 	const struct ether_header *eh;
4902db76829bSSepherosa Ziehau 	uint16_t etype;
4903db76829bSSepherosa Ziehau 	int hoff;
4904db76829bSSepherosa Ziehau 
4905db76829bSSepherosa Ziehau 	hoff = sizeof(*eh);
4906db76829bSSepherosa Ziehau 	/* Checked at the beginning of this function. */
4907db76829bSSepherosa Ziehau 	KASSERT(m_new->m_len >= hoff, ("not ethernet frame"));
4908db76829bSSepherosa Ziehau 
4909db76829bSSepherosa Ziehau 	eh = mtod(m_new, const struct ether_header *);
4910db76829bSSepherosa Ziehau 	etype = ntohs(eh->ether_type);
4911db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_VLAN) {
4912db76829bSSepherosa Ziehau 		const struct ether_vlan_header *evl;
4913db76829bSSepherosa Ziehau 
4914db76829bSSepherosa Ziehau 		hoff = sizeof(*evl);
4915db76829bSSepherosa Ziehau 		if (m_new->m_len < hoff)
4916db76829bSSepherosa Ziehau 			return;
4917db76829bSSepherosa Ziehau 		evl = mtod(m_new, const struct ether_vlan_header *);
4918db76829bSSepherosa Ziehau 		etype = ntohs(evl->evl_proto);
4919db76829bSSepherosa Ziehau 	}
4920db76829bSSepherosa Ziehau 	*l3proto = etype;
4921db76829bSSepherosa Ziehau 
4922db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_IP)
4923db76829bSSepherosa Ziehau 		*l4proto = hn_check_iplen(m_new, hoff);
4924db76829bSSepherosa Ziehau 	else
4925db76829bSSepherosa Ziehau 		*l4proto = IPPROTO_DONE;
4926db76829bSSepherosa Ziehau }
4927db76829bSSepherosa Ziehau 
492815516c77SSepherosa Ziehau static int
hn_create_rx_data(struct hn_softc * sc,int ring_cnt)492915516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
493015516c77SSepherosa Ziehau {
493115516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
493215516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
493315516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
493415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
493515516c77SSepherosa Ziehau 	int lroent_cnt;
493615516c77SSepherosa Ziehau #endif
493715516c77SSepherosa Ziehau 	int i;
493815516c77SSepherosa Ziehau 
493915516c77SSepherosa Ziehau 	/*
494015516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
494115516c77SSepherosa Ziehau 	 *
494215516c77SSepherosa Ziehau 	 * NOTE:
494315516c77SSepherosa Ziehau 	 * - It is shared by all channels.
494415516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
494515516c77SSepherosa Ziehau 	 *   may further limit the usable space.
494615516c77SSepherosa Ziehau 	 */
494762f9bcf2SAndrew Turner 	sc->hn_rxbuf = contigmalloc(HN_RXBUF_SIZE, M_DEVBUF, M_WAITOK | M_ZERO,
494862f9bcf2SAndrew Turner 	    0ul, ~0ul, PAGE_SIZE, 0);
494915516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
495015516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
495115516c77SSepherosa Ziehau 		return (ENOMEM);
495215516c77SSepherosa Ziehau 	}
495315516c77SSepherosa Ziehau 
495415516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
495515516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
495615516c77SSepherosa Ziehau 
495715516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
495815516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
495915516c77SSepherosa Ziehau 
496015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
496115516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
496215516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
496315516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
496415516c77SSepherosa Ziehau 	if (bootverbose)
496515516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
496615516c77SSepherosa Ziehau #endif	/* INET || INET6 */
496715516c77SSepherosa Ziehau 
496815516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
496915516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
497015516c77SSepherosa Ziehau 
497115516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
497215516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
497315516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
497415516c77SSepherosa Ziehau 
497515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
497615516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
497715516c77SSepherosa Ziehau 
497862f9bcf2SAndrew Turner 		rxr->hn_br = contigmalloc(HN_TXBR_SIZE + HN_RXBR_SIZE, M_DEVBUF,
497962f9bcf2SAndrew Turner 		    M_WAITOK | M_ZERO, 0ul, ~0ul, PAGE_SIZE, 0);
498015516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
498115516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
498215516c77SSepherosa Ziehau 			return (ENOMEM);
498315516c77SSepherosa Ziehau 		}
498415516c77SSepherosa Ziehau 
498515516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
498615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
498715516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
498815516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
498915516c77SSepherosa Ziehau 		if (hn_trust_hostip)
499015516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
4991642ec226SSepherosa Ziehau 		rxr->hn_mbuf_hash = NDIS_HASH_ALL;
499215516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
499315516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
499415516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
499515516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
499615516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
499715516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
499815516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
499915516c77SSepherosa Ziehau 
500015516c77SSepherosa Ziehau 		/*
500115516c77SSepherosa Ziehau 		 * Initialize LRO.
500215516c77SSepherosa Ziehau 		 */
500315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
500415516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
500515516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
500615516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
500715516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
500815516c77SSepherosa Ziehau #endif	/* INET || INET6 */
500915516c77SSepherosa Ziehau 
501015516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
501115516c77SSepherosa Ziehau 			char name[16];
501215516c77SSepherosa Ziehau 
501315516c77SSepherosa Ziehau 			/*
501415516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
501515516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
501615516c77SSepherosa Ziehau 			 */
501715516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
501815516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
501915516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
502015516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
502115516c77SSepherosa Ziehau 
502215516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
502315516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
502415516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
5025db0ac6deSCy Schubert 				    OID_AUTO, "packets",
5026db0ac6deSCy Schubert 				    CTLFLAG_RW | CTLFLAG_STATS, &rxr->hn_pkts,
5027db0ac6deSCy Schubert 				    "# of packets received");
502815516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
502915516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
5030db0ac6deSCy Schubert 				    OID_AUTO, "rss_pkts",
5031db0ac6deSCy Schubert 				    CTLFLAG_RW | CTLFLAG_STATS,
503215516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
503315516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
5034a491581fSWei Hu 				SYSCTL_ADD_ULONG(ctx,
5035a491581fSWei Hu 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
5036db0ac6deSCy Schubert 				    OID_AUTO, "rsc_pkts",
5037db0ac6deSCy Schubert 				    CTLFLAG_RW | CTLFLAG_STATS,
5038a491581fSWei Hu 				    &rxr->hn_rsc_pkts,
5039a491581fSWei Hu 				    "# of RSC packets received");
5040a491581fSWei Hu 				SYSCTL_ADD_ULONG(ctx,
5041a491581fSWei Hu 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
5042db0ac6deSCy Schubert 				    OID_AUTO, "rsc_drop",
5043db0ac6deSCy Schubert 				    CTLFLAG_RW | CTLFLAG_STATS,
5044a491581fSWei Hu 				    &rxr->hn_rsc_drop,
5045a491581fSWei Hu 				    "# of RSC fragments dropped");
504615516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
504715516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
504815516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
504915516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
505015516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
505115516c77SSepherosa Ziehau 			}
505215516c77SSepherosa Ziehau 		}
505315516c77SSepherosa Ziehau 	}
505415516c77SSepherosa Ziehau 
505515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
5056db0ac6deSCy Schubert 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
505715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
505815516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
505915516c77SSepherosa Ziehau 	    "LU", "LRO queued");
506015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
5061db0ac6deSCy Schubert 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
506215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
506315516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
506415516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
506515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
5066db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
506715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
506815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
506915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
507015516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
507115516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
507215516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
507315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
507415516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
507515516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
507615516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
507715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
507815516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
507915516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
5080b15a632cSGordon Bergling 	    "Trust tcp segment verification on host side, "
508115516c77SSepherosa Ziehau 	    "when csum info is missing");
508215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
508315516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
508415516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
508515516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
508615516c77SSepherosa Ziehau 	    "when csum info is missing");
508715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
508815516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
508915516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
509015516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
509115516c77SSepherosa Ziehau 	    "when csum info is missing");
509215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
5093db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
509415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
509515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
509615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
5097db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
509815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
509915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
510015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
5101db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
510215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
510315516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
510415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
510515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
510615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
510715516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
510815516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
510915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
5110db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
511115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
511215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
511315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
5114db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
511515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
511615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
511715516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
511815516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
511915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
512015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
512115516c77SSepherosa Ziehau 
512215516c77SSepherosa Ziehau 	return (0);
512315516c77SSepherosa Ziehau }
512415516c77SSepherosa Ziehau 
512515516c77SSepherosa Ziehau static void
hn_destroy_rx_data(struct hn_softc * sc)512615516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
512715516c77SSepherosa Ziehau {
512815516c77SSepherosa Ziehau 	int i;
512915516c77SSepherosa Ziehau 
513015516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
51312494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
5132d1bdc282SBjoern A. Zeeb 			free(sc->hn_rxbuf, M_DEVBUF);
51332494d735SSepherosa Ziehau 		else
51342494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
513515516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
513615516c77SSepherosa Ziehau 	}
513715516c77SSepherosa Ziehau 
513815516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
513915516c77SSepherosa Ziehau 		return;
514015516c77SSepherosa Ziehau 
514115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
514215516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
514315516c77SSepherosa Ziehau 
514415516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
514515516c77SSepherosa Ziehau 			continue;
51462494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
5147d1bdc282SBjoern A. Zeeb 			free(rxr->hn_br, M_DEVBUF);
51482494d735SSepherosa Ziehau 		} else {
51492494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
51502494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
51512494d735SSepherosa Ziehau 		}
515215516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
515315516c77SSepherosa Ziehau 
515415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
515515516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
515615516c77SSepherosa Ziehau #endif
515715516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
515815516c77SSepherosa Ziehau 	}
515915516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
516015516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
516115516c77SSepherosa Ziehau 
516215516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
516315516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
516415516c77SSepherosa Ziehau }
516515516c77SSepherosa Ziehau 
516615516c77SSepherosa Ziehau static int
hn_tx_ring_create(struct hn_softc * sc,int id)516715516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
516815516c77SSepherosa Ziehau {
516915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
517015516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
517115516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
517215516c77SSepherosa Ziehau 	int error, i;
517315516c77SSepherosa Ziehau 
517415516c77SSepherosa Ziehau 	txr->hn_sc = sc;
517515516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
517615516c77SSepherosa Ziehau 
517715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
517815516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
517915516c77SSepherosa Ziehau #endif
518015516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
518115516c77SSepherosa Ziehau 
518215516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
518315516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
518415516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
518515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
518615516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
518715516c77SSepherosa Ziehau #else
518815516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
518915516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
519015516c77SSepherosa Ziehau #endif
519115516c77SSepherosa Ziehau 
51920e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
51930e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
51940e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
51950e11868dSSepherosa Ziehau 	} else {
5196fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
51970e11868dSSepherosa Ziehau 	}
519815516c77SSepherosa Ziehau 
519923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
520015516c77SSepherosa Ziehau 	if (hn_use_if_start) {
520115516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
520215516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
520315516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
520423bf9e15SSepherosa Ziehau 	} else
520523bf9e15SSepherosa Ziehau #endif
520623bf9e15SSepherosa Ziehau 	{
520715516c77SSepherosa Ziehau 		int br_depth;
520815516c77SSepherosa Ziehau 
520915516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
521015516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
521115516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
521215516c77SSepherosa Ziehau 
521315516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
521415516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
521515516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
521615516c77SSepherosa Ziehau 	}
521715516c77SSepherosa Ziehau 
521815516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
521915516c77SSepherosa Ziehau 
522015516c77SSepherosa Ziehau 	/*
522115516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
522215516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
522315516c77SSepherosa Ziehau 	 */
522415516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
522515516c77SSepherosa Ziehau 
522615516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
522715516c77SSepherosa Ziehau 
522815516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
522915516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
523015516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
523115516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
523215516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
523315516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
523415516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
523515516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
523615516c77SSepherosa Ziehau 	    1,				/* nsegments */
523715516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
523815516c77SSepherosa Ziehau 	    0,				/* flags */
523915516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
524015516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
524115516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
524215516c77SSepherosa Ziehau 	if (error) {
524315516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
524415516c77SSepherosa Ziehau 		return error;
524515516c77SSepherosa Ziehau 	}
524615516c77SSepherosa Ziehau 
524715516c77SSepherosa Ziehau 	/* DMA tag for data. */
524815516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
524915516c77SSepherosa Ziehau 	    1,				/* alignment */
525015516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
525115516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
525215516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
525315516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
525415516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
525515516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
525615516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
525715516c77SSepherosa Ziehau 	    0,				/* flags */
525815516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
525915516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
526015516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
526115516c77SSepherosa Ziehau 	if (error) {
526215516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
526315516c77SSepherosa Ziehau 		return error;
526415516c77SSepherosa Ziehau 	}
526515516c77SSepherosa Ziehau 
526615516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
526715516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
526815516c77SSepherosa Ziehau 
526915516c77SSepherosa Ziehau 		txd->txr = txr;
527015516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
5271dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
527215516c77SSepherosa Ziehau 
527315516c77SSepherosa Ziehau 		/*
527415516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
527515516c77SSepherosa Ziehau 		 */
527615516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
527715516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
527815516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
527915516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
528015516c77SSepherosa Ziehau 		if (error) {
528115516c77SSepherosa Ziehau 			device_printf(dev,
528215516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
528315516c77SSepherosa Ziehau 			return error;
528415516c77SSepherosa Ziehau 		}
528515516c77SSepherosa Ziehau 
528615516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
528715516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
528815516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
528915516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
529015516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
529115516c77SSepherosa Ziehau 		if (error) {
529215516c77SSepherosa Ziehau 			device_printf(dev,
529315516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
529415516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
529515516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
529615516c77SSepherosa Ziehau 			return error;
529715516c77SSepherosa Ziehau 		}
529815516c77SSepherosa Ziehau 
529915516c77SSepherosa Ziehau 		/* DMA map for TX data. */
530015516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
530115516c77SSepherosa Ziehau 		    &txd->data_dmap);
530215516c77SSepherosa Ziehau 		if (error) {
530315516c77SSepherosa Ziehau 			device_printf(dev,
530415516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
530515516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
530615516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
530715516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
530815516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
530915516c77SSepherosa Ziehau 			return error;
531015516c77SSepherosa Ziehau 		}
531115516c77SSepherosa Ziehau 
531215516c77SSepherosa Ziehau 		/* All set, put it to list */
531315516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
531415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
531515516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
531615516c77SSepherosa Ziehau #else
531715516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
531815516c77SSepherosa Ziehau #endif
531915516c77SSepherosa Ziehau 	}
532015516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
532115516c77SSepherosa Ziehau 
532215516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
532315516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
532415516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
532515516c77SSepherosa Ziehau 		char name[16];
532615516c77SSepherosa Ziehau 
532715516c77SSepherosa Ziehau 		/*
532815516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
532915516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
533015516c77SSepherosa Ziehau 		 */
533115516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
533215516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
533315516c77SSepherosa Ziehau 
533415516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
533515516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
533615516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
533715516c77SSepherosa Ziehau 
533815516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
533915516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
534015516c77SSepherosa Ziehau 
534185e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
534215516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
534315516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
534415516c77SSepherosa Ziehau 			    "# of available TX descs");
534585e4ae1eSSepherosa Ziehau #endif
534623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
534723bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
534823bf9e15SSepherosa Ziehau #endif
534923bf9e15SSepherosa Ziehau 			{
535015516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
535115516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
535215516c77SSepherosa Ziehau 				    "over active");
535315516c77SSepherosa Ziehau 			}
535415516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
5355db0ac6deSCy Schubert 			    CTLFLAG_RW | CTLFLAG_STATS, &txr->hn_pkts,
535615516c77SSepherosa Ziehau 			    "# of packets transmitted");
5357dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
5358db0ac6deSCy Schubert 			    CTLFLAG_RW | CTLFLAG_STATS, &txr->hn_sends,
5359db0ac6deSCy Schubert 			    "# of sends");
536015516c77SSepherosa Ziehau 		}
536115516c77SSepherosa Ziehau 	}
536215516c77SSepherosa Ziehau 
536315516c77SSepherosa Ziehau 	return 0;
536415516c77SSepherosa Ziehau }
536515516c77SSepherosa Ziehau 
536615516c77SSepherosa Ziehau static void
hn_txdesc_dmamap_destroy(struct hn_txdesc * txd)536715516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
536815516c77SSepherosa Ziehau {
536915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
537015516c77SSepherosa Ziehau 
537115516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
537215516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
537315516c77SSepherosa Ziehau 
537415516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
537515516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
537615516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
537715516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
537815516c77SSepherosa Ziehau }
537915516c77SSepherosa Ziehau 
538015516c77SSepherosa Ziehau static void
hn_txdesc_gc(struct hn_tx_ring * txr,struct hn_txdesc * txd)538125641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
538225641fc7SSepherosa Ziehau {
538325641fc7SSepherosa Ziehau 
538425641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
538525641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
538625641fc7SSepherosa Ziehau 
538725641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
538825641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
5389a0f49d67SMateusz Guzik 		int freed __diagused;
539025641fc7SSepherosa Ziehau 
539125641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
539225641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
539325641fc7SSepherosa Ziehau 	}
539425641fc7SSepherosa Ziehau }
539525641fc7SSepherosa Ziehau 
539625641fc7SSepherosa Ziehau static void
hn_tx_ring_destroy(struct hn_tx_ring * txr)539715516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
539815516c77SSepherosa Ziehau {
539925641fc7SSepherosa Ziehau 	int i;
540015516c77SSepherosa Ziehau 
540115516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
540215516c77SSepherosa Ziehau 		return;
540315516c77SSepherosa Ziehau 
540425641fc7SSepherosa Ziehau 	/*
540525641fc7SSepherosa Ziehau 	 * NOTE:
540625641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
540725641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
540825641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
540925641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
541025641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
541125641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
541225641fc7SSepherosa Ziehau 	 *   were freed.
541325641fc7SSepherosa Ziehau 	 */
541425641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
541525641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
541625641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
541725641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
541815516c77SSepherosa Ziehau 
541915516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
542015516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
542115516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
542215516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
542315516c77SSepherosa Ziehau 
542415516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
542515516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
542615516c77SSepherosa Ziehau #endif
542715516c77SSepherosa Ziehau 
542815516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
542915516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
543015516c77SSepherosa Ziehau 
543115516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
543215516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
543315516c77SSepherosa Ziehau 
543415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
543515516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
543615516c77SSepherosa Ziehau #endif
543715516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
543815516c77SSepherosa Ziehau }
543915516c77SSepherosa Ziehau 
544015516c77SSepherosa Ziehau static int
hn_create_tx_data(struct hn_softc * sc,int ring_cnt)544115516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
544215516c77SSepherosa Ziehau {
544315516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
544415516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
544515516c77SSepherosa Ziehau 	int i;
544615516c77SSepherosa Ziehau 
544715516c77SSepherosa Ziehau 	/*
544815516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
544915516c77SSepherosa Ziehau 	 *
545015516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
545115516c77SSepherosa Ziehau 	 */
545262f9bcf2SAndrew Turner 	sc->hn_chim = contigmalloc(HN_CHIM_SIZE, M_DEVBUF, M_WAITOK | M_ZERO,
545362f9bcf2SAndrew Turner 	    0ul, ~0ul, PAGE_SIZE, 0);
545415516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
545515516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
545615516c77SSepherosa Ziehau 		return (ENOMEM);
545715516c77SSepherosa Ziehau 	}
545815516c77SSepherosa Ziehau 
545915516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
546015516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
546115516c77SSepherosa Ziehau 
546215516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
546315516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
546415516c77SSepherosa Ziehau 
546515516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
546615516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
546715516c77SSepherosa Ziehau 
546815516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
546915516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
547015516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
547115516c77SSepherosa Ziehau 
547215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
547315516c77SSepherosa Ziehau 		int error;
547415516c77SSepherosa Ziehau 
547515516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
547615516c77SSepherosa Ziehau 		if (error)
547715516c77SSepherosa Ziehau 			return error;
547815516c77SSepherosa Ziehau 	}
547915516c77SSepherosa Ziehau 
548015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
5481db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
548215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
548315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
548415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
5485db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
548615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
548715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
548815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
5489db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
549015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
549115516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
5492dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
5493db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
5494dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
5495dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
5496dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
549715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
5498db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
549915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
550015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
550115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
5502db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
550315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
550415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
550515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
5506db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
550715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
550815516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
550915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
551015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
551115516c77SSepherosa Ziehau 	    "# of total TX descs");
551215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
551315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
551415516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
551515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
551615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
551715516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
551815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
551915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
552015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
552115516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
552215516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
552315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
552415516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
552515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
552615516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
552715516c77SSepherosa Ziehau 	    "Always schedule transmission "
552815516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
552915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
553015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
553115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
553215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
5533dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
5534dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
5535dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
5536dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
5537dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5538dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
5539dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
5540dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
5541dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5542dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
5543dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
554415516c77SSepherosa Ziehau 
554515516c77SSepherosa Ziehau 	return 0;
554615516c77SSepherosa Ziehau }
554715516c77SSepherosa Ziehau 
554815516c77SSepherosa Ziehau static void
hn_set_chim_size(struct hn_softc * sc,int chim_size)554915516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
555015516c77SSepherosa Ziehau {
555115516c77SSepherosa Ziehau 	int i;
555215516c77SSepherosa Ziehau 
5553a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
555415516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
555515516c77SSepherosa Ziehau }
555615516c77SSepherosa Ziehau 
555715516c77SSepherosa Ziehau static void
hn_set_tso_maxsize(struct hn_softc * sc,int tso_maxlen,int mtu)555815516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
555915516c77SSepherosa Ziehau {
55604db5958aSJustin Hibbits 	if_t ifp = sc->hn_ifp;
55619c6cae24SSepherosa Ziehau 	u_int hw_tsomax;
556215516c77SSepherosa Ziehau 	int tso_minlen;
556315516c77SSepherosa Ziehau 
55649c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
55659c6cae24SSepherosa Ziehau 
55664db5958aSJustin Hibbits 	if ((if_getcapabilities(ifp) & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
556715516c77SSepherosa Ziehau 		return;
556815516c77SSepherosa Ziehau 
556915516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
557015516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
557115516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
557215516c77SSepherosa Ziehau 
557315516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
557415516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
557515516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
557615516c77SSepherosa Ziehau 
557715516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
557815516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
557915516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
558015516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
558115516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
558215516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
55839c6cae24SSepherosa Ziehau 	hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
55849c6cae24SSepherosa Ziehau 
55859c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
55864db5958aSJustin Hibbits 		if (hw_tsomax > if_gethwtsomax(sc->hn_vf_ifp))
55874db5958aSJustin Hibbits 			hw_tsomax = if_gethwtsomax(sc->hn_vf_ifp);
55889c6cae24SSepherosa Ziehau 	}
55894db5958aSJustin Hibbits 	if_sethwtsomax(ifp, hw_tsomax);
559015516c77SSepherosa Ziehau 	if (bootverbose)
55914db5958aSJustin Hibbits 		if_printf(ifp, "TSO size max %u\n", if_gethwtsomax(ifp));
559215516c77SSepherosa Ziehau }
559315516c77SSepherosa Ziehau 
559415516c77SSepherosa Ziehau static void
hn_fixup_tx_data(struct hn_softc * sc)559515516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
559615516c77SSepherosa Ziehau {
559715516c77SSepherosa Ziehau 	uint64_t csum_assist;
559815516c77SSepherosa Ziehau 	int i;
559915516c77SSepherosa Ziehau 
560015516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
560115516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
560215516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
560315516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
560415516c77SSepherosa Ziehau 
560515516c77SSepherosa Ziehau 	csum_assist = 0;
560615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
560715516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
560815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
560915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
56102be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP4CS) && hn_enable_udp4cs)
561115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
561215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
561315516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
56142be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP6CS) && hn_enable_udp6cs)
561515516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
561615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
561715516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
561815516c77SSepherosa Ziehau 
561915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
562015516c77SSepherosa Ziehau 		/*
562115516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
562215516c77SSepherosa Ziehau 		 */
562315516c77SSepherosa Ziehau 		if (bootverbose)
562415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
562515516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
562615516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
562715516c77SSepherosa Ziehau 	}
562815516c77SSepherosa Ziehau }
562915516c77SSepherosa Ziehau 
563015516c77SSepherosa Ziehau static void
hn_fixup_rx_data(struct hn_softc * sc)5631db76829bSSepherosa Ziehau hn_fixup_rx_data(struct hn_softc *sc)
5632db76829bSSepherosa Ziehau {
5633db76829bSSepherosa Ziehau 
5634db76829bSSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDPHASH) {
5635db76829bSSepherosa Ziehau 		int i;
5636db76829bSSepherosa Ziehau 
5637db76829bSSepherosa Ziehau 		for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
5638db76829bSSepherosa Ziehau 			sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_UDP_HASH;
5639db76829bSSepherosa Ziehau 	}
5640db76829bSSepherosa Ziehau }
5641db76829bSSepherosa Ziehau 
5642db76829bSSepherosa Ziehau static void
hn_destroy_tx_data(struct hn_softc * sc)564315516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
564415516c77SSepherosa Ziehau {
564515516c77SSepherosa Ziehau 	int i;
564615516c77SSepherosa Ziehau 
564715516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
56482494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
5649d1bdc282SBjoern A. Zeeb 			free(sc->hn_chim, M_DEVBUF);
56502494d735SSepherosa Ziehau 		} else {
56512494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
56522494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
56532494d735SSepherosa Ziehau 		}
565415516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
565515516c77SSepherosa Ziehau 	}
565615516c77SSepherosa Ziehau 
565715516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
565815516c77SSepherosa Ziehau 		return;
565915516c77SSepherosa Ziehau 
566015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
566115516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
566215516c77SSepherosa Ziehau 
566315516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
566415516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
566515516c77SSepherosa Ziehau 
566615516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
566715516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
566815516c77SSepherosa Ziehau }
566915516c77SSepherosa Ziehau 
567023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
567123bf9e15SSepherosa Ziehau 
567215516c77SSepherosa Ziehau static void
hn_start_taskfunc(void * xtxr,int pending __unused)567315516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
567415516c77SSepherosa Ziehau {
567515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
567615516c77SSepherosa Ziehau 
567715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
567815516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
567915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
568015516c77SSepherosa Ziehau }
568115516c77SSepherosa Ziehau 
568223bf9e15SSepherosa Ziehau static int
hn_start_locked(struct hn_tx_ring * txr,int len)568323bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
568423bf9e15SSepherosa Ziehau {
568523bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
56864db5958aSJustin Hibbits 	if_t ifp = sc->hn_ifp;
5687dc13fee6SSepherosa Ziehau 	int sched = 0;
568823bf9e15SSepherosa Ziehau 
568923bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
569023bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
569123bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
569223bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
5693dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
569423bf9e15SSepherosa Ziehau 
569523bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5696dc13fee6SSepherosa Ziehau 		return (0);
569723bf9e15SSepherosa Ziehau 
56984db5958aSJustin Hibbits 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
569923bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
5700dc13fee6SSepherosa Ziehau 		return (0);
570123bf9e15SSepherosa Ziehau 
57024db5958aSJustin Hibbits 	while (!if_sendq_empty(ifp)) {
570323bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
570423bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
570523bf9e15SSepherosa Ziehau 		int error;
570623bf9e15SSepherosa Ziehau 
57074db5958aSJustin Hibbits 		m_head = if_dequeue(ifp);
570823bf9e15SSepherosa Ziehau 		if (m_head == NULL)
570923bf9e15SSepherosa Ziehau 			break;
571023bf9e15SSepherosa Ziehau 
571123bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
571223bf9e15SSepherosa Ziehau 			/*
571323bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
571423bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
571523bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
571623bf9e15SSepherosa Ziehau 			 */
57174db5958aSJustin Hibbits 			if_sendq_prepend(ifp, m_head);
5718dc13fee6SSepherosa Ziehau 			sched = 1;
5719dc13fee6SSepherosa Ziehau 			break;
572023bf9e15SSepherosa Ziehau 		}
572123bf9e15SSepherosa Ziehau 
5722edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5723edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
5724edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
5725edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5726edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5727edd3f315SSepherosa Ziehau 				continue;
5728edd3f315SSepherosa Ziehau 			}
5729c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
5730c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
5731c49d47daSSepherosa Ziehau 			m_head = hn_set_hlen(m_head);
5732c49d47daSSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5733c49d47daSSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5734c49d47daSSepherosa Ziehau 				continue;
5735c49d47daSSepherosa Ziehau 			}
5736edd3f315SSepherosa Ziehau 		}
5737edd3f315SSepherosa Ziehau #endif
5738edd3f315SSepherosa Ziehau 
573923bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
574023bf9e15SSepherosa Ziehau 		if (txd == NULL) {
574123bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
57424db5958aSJustin Hibbits 			if_sendq_prepend(ifp, m_head);
57434db5958aSJustin Hibbits 			if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
574423bf9e15SSepherosa Ziehau 			break;
574523bf9e15SSepherosa Ziehau 		}
574623bf9e15SSepherosa Ziehau 
5747dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
574823bf9e15SSepherosa Ziehau 		if (error) {
574923bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
5750dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5751dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
575223bf9e15SSepherosa Ziehau 			continue;
575323bf9e15SSepherosa Ziehau 		}
575423bf9e15SSepherosa Ziehau 
5755dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5756dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5757dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5758dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5759dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
5760dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
57614db5958aSJustin Hibbits 					if_setdrvflagbits(ifp,
57624db5958aSJustin Hibbits 					    IFF_DRV_OACTIVE, 0);
5763dc13fee6SSepherosa Ziehau 					break;
5764dc13fee6SSepherosa Ziehau 				}
5765dc13fee6SSepherosa Ziehau 			} else {
5766dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
576723bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
576823bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
576923bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
57704db5958aSJustin Hibbits 					if_sendq_prepend(ifp, m_head);
57714db5958aSJustin Hibbits 					if_setdrvflagbits(ifp,
57724db5958aSJustin Hibbits 					    IFF_DRV_OACTIVE, 0);
577323bf9e15SSepherosa Ziehau 					break;
577423bf9e15SSepherosa Ziehau 				}
577523bf9e15SSepherosa Ziehau 			}
5776dc13fee6SSepherosa Ziehau 		}
5777dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5778dc13fee6SSepherosa Ziehau 		else {
5779dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5780dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5781dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5782dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5783dc13fee6SSepherosa Ziehau 		}
5784dc13fee6SSepherosa Ziehau #endif
5785dc13fee6SSepherosa Ziehau 	}
5786dc13fee6SSepherosa Ziehau 
5787dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5788dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5789dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5790dc13fee6SSepherosa Ziehau 	return (sched);
579123bf9e15SSepherosa Ziehau }
579223bf9e15SSepherosa Ziehau 
579323bf9e15SSepherosa Ziehau static void
hn_start(if_t ifp)57944db5958aSJustin Hibbits hn_start(if_t ifp)
579523bf9e15SSepherosa Ziehau {
57964db5958aSJustin Hibbits 	struct hn_softc *sc = if_getsoftc(ifp);
579723bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
579823bf9e15SSepherosa Ziehau 
579923bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
580023bf9e15SSepherosa Ziehau 		goto do_sched;
580123bf9e15SSepherosa Ziehau 
580223bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
580323bf9e15SSepherosa Ziehau 		int sched;
580423bf9e15SSepherosa Ziehau 
580523bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
580623bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
580723bf9e15SSepherosa Ziehau 		if (!sched)
580823bf9e15SSepherosa Ziehau 			return;
580923bf9e15SSepherosa Ziehau 	}
581023bf9e15SSepherosa Ziehau do_sched:
581123bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
581223bf9e15SSepherosa Ziehau }
581323bf9e15SSepherosa Ziehau 
581415516c77SSepherosa Ziehau static void
hn_start_txeof_taskfunc(void * xtxr,int pending __unused)581515516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
581615516c77SSepherosa Ziehau {
581715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
581815516c77SSepherosa Ziehau 
581915516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
58204db5958aSJustin Hibbits 	if_setdrvflagbits(txr->hn_sc->hn_ifp, 0, IFF_DRV_OACTIVE);
582115516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
582215516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
582315516c77SSepherosa Ziehau }
582415516c77SSepherosa Ziehau 
582523bf9e15SSepherosa Ziehau static void
hn_start_txeof(struct hn_tx_ring * txr)582623bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
582723bf9e15SSepherosa Ziehau {
582823bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
58294db5958aSJustin Hibbits 	if_t ifp = sc->hn_ifp;
583023bf9e15SSepherosa Ziehau 
583123bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
583223bf9e15SSepherosa Ziehau 
583323bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
583423bf9e15SSepherosa Ziehau 		goto do_sched;
583523bf9e15SSepherosa Ziehau 
583623bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
583723bf9e15SSepherosa Ziehau 		int sched;
583823bf9e15SSepherosa Ziehau 
58394db5958aSJustin Hibbits 		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
584023bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
584123bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
584223bf9e15SSepherosa Ziehau 		if (sched) {
584323bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
584423bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
584523bf9e15SSepherosa Ziehau 		}
584623bf9e15SSepherosa Ziehau 	} else {
584723bf9e15SSepherosa Ziehau do_sched:
584823bf9e15SSepherosa Ziehau 		/*
584923bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
585023bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
585123bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
585223bf9e15SSepherosa Ziehau 		 * races.
585323bf9e15SSepherosa Ziehau 		 */
58544db5958aSJustin Hibbits 		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
585523bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
585623bf9e15SSepherosa Ziehau 	}
585723bf9e15SSepherosa Ziehau }
585823bf9e15SSepherosa Ziehau 
585923bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
586023bf9e15SSepherosa Ziehau 
586115516c77SSepherosa Ziehau static int
hn_xmit(struct hn_tx_ring * txr,int len)586215516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
586315516c77SSepherosa Ziehau {
586415516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
58654db5958aSJustin Hibbits 	if_t ifp = sc->hn_ifp;
586615516c77SSepherosa Ziehau 	struct mbuf *m_head;
5867dc13fee6SSepherosa Ziehau 	int sched = 0;
586815516c77SSepherosa Ziehau 
586915516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
587023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
587115516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
587215516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
587323bf9e15SSepherosa Ziehau #endif
5874dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
587515516c77SSepherosa Ziehau 
587615516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5877dc13fee6SSepherosa Ziehau 		return (0);
587815516c77SSepherosa Ziehau 
58794db5958aSJustin Hibbits 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
5880dc13fee6SSepherosa Ziehau 		return (0);
588115516c77SSepherosa Ziehau 
588215516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
588315516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
588415516c77SSepherosa Ziehau 		int error;
588515516c77SSepherosa Ziehau 
588615516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
588715516c77SSepherosa Ziehau 			/*
588815516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
588915516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
589015516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
589115516c77SSepherosa Ziehau 			 */
589215516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
5893dc13fee6SSepherosa Ziehau 			sched = 1;
5894dc13fee6SSepherosa Ziehau 			break;
589515516c77SSepherosa Ziehau 		}
589615516c77SSepherosa Ziehau 
589715516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
589815516c77SSepherosa Ziehau 		if (txd == NULL) {
589915516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
590015516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
590115516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
590215516c77SSepherosa Ziehau 			break;
590315516c77SSepherosa Ziehau 		}
590415516c77SSepherosa Ziehau 
5905dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
590615516c77SSepherosa Ziehau 		if (error) {
590715516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
5908dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5909dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
591015516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
591115516c77SSepherosa Ziehau 			continue;
591215516c77SSepherosa Ziehau 		}
591315516c77SSepherosa Ziehau 
5914dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5915dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5916dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5917dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5918dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
591915516c77SSepherosa Ziehau 				if (__predict_false(error)) {
592015516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
592115516c77SSepherosa Ziehau 					break;
592215516c77SSepherosa Ziehau 				}
5923dc13fee6SSepherosa Ziehau 			} else {
5924dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
5925dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
5926dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5927dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
5928dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
5929dc13fee6SSepherosa Ziehau 					    m_head);
5930dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
5931dc13fee6SSepherosa Ziehau 					break;
5932dc13fee6SSepherosa Ziehau 				}
5933dc13fee6SSepherosa Ziehau 			}
5934dc13fee6SSepherosa Ziehau 		}
5935dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5936dc13fee6SSepherosa Ziehau 		else {
5937dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5938dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5939dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5940dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5941dc13fee6SSepherosa Ziehau 		}
5942dc13fee6SSepherosa Ziehau #endif
594315516c77SSepherosa Ziehau 
594415516c77SSepherosa Ziehau 		/* Sent */
594515516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
594615516c77SSepherosa Ziehau 	}
5947dc13fee6SSepherosa Ziehau 
5948dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5949dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5950dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5951dc13fee6SSepherosa Ziehau 	return (sched);
595215516c77SSepherosa Ziehau }
595315516c77SSepherosa Ziehau 
595415516c77SSepherosa Ziehau static int
hn_transmit(if_t ifp,struct mbuf * m)59554db5958aSJustin Hibbits hn_transmit(if_t ifp, struct mbuf *m)
595615516c77SSepherosa Ziehau {
59574db5958aSJustin Hibbits 	struct hn_softc *sc = if_getsoftc(ifp);
595815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
595915516c77SSepherosa Ziehau 	int error, idx = 0;
596015516c77SSepherosa Ziehau 
59619c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
59629c6cae24SSepherosa Ziehau 		struct rm_priotracker pt;
59639c6cae24SSepherosa Ziehau 
59649c6cae24SSepherosa Ziehau 		rm_rlock(&sc->hn_vf_lock, &pt);
59659c6cae24SSepherosa Ziehau 		if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
59669c6cae24SSepherosa Ziehau 			struct mbuf *m_bpf = NULL;
59679c6cae24SSepherosa Ziehau 			int obytes, omcast;
59689c6cae24SSepherosa Ziehau 
59699c6cae24SSepherosa Ziehau 			obytes = m->m_pkthdr.len;
59707898a1f4SEric van Gyzen 			omcast = (m->m_flags & M_MCAST) != 0;
59719c6cae24SSepherosa Ziehau 
59729c6cae24SSepherosa Ziehau 			if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) {
59738f31b879SJustin Hibbits 				if (bpf_peers_present_if(ifp)) {
59749c6cae24SSepherosa Ziehau 					m_bpf = m_copypacket(m, M_NOWAIT);
59759c6cae24SSepherosa Ziehau 					if (m_bpf == NULL) {
59769c6cae24SSepherosa Ziehau 						/*
59779c6cae24SSepherosa Ziehau 						 * Failed to grab a shallow
59789c6cae24SSepherosa Ziehau 						 * copy; tap now.
59799c6cae24SSepherosa Ziehau 						 */
59809c6cae24SSepherosa Ziehau 						ETHER_BPF_MTAP(ifp, m);
59819c6cae24SSepherosa Ziehau 					}
59829c6cae24SSepherosa Ziehau 				}
59839c6cae24SSepherosa Ziehau 			} else {
59849c6cae24SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, m);
59859c6cae24SSepherosa Ziehau 			}
59869c6cae24SSepherosa Ziehau 
59874db5958aSJustin Hibbits 			error = if_transmit(sc->hn_vf_ifp, m);
59889c6cae24SSepherosa Ziehau 			rm_runlock(&sc->hn_vf_lock, &pt);
59899c6cae24SSepherosa Ziehau 
59909c6cae24SSepherosa Ziehau 			if (m_bpf != NULL) {
59919c6cae24SSepherosa Ziehau 				if (!error)
59929c6cae24SSepherosa Ziehau 					ETHER_BPF_MTAP(ifp, m_bpf);
59939c6cae24SSepherosa Ziehau 				m_freem(m_bpf);
59949c6cae24SSepherosa Ziehau 			}
59959c6cae24SSepherosa Ziehau 
59969c6cae24SSepherosa Ziehau 			if (error == ENOBUFS) {
59979c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
59989c6cae24SSepherosa Ziehau 			} else if (error) {
59999c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
60009c6cae24SSepherosa Ziehau 			} else {
60019c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
60029c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes);
60039c6cae24SSepherosa Ziehau 				if (omcast) {
60049c6cae24SSepherosa Ziehau 					if_inc_counter(ifp, IFCOUNTER_OMCASTS,
60059c6cae24SSepherosa Ziehau 					    omcast);
60069c6cae24SSepherosa Ziehau 				}
60079c6cae24SSepherosa Ziehau 			}
60089c6cae24SSepherosa Ziehau 			return (error);
60099c6cae24SSepherosa Ziehau 		}
60109c6cae24SSepherosa Ziehau 		rm_runlock(&sc->hn_vf_lock, &pt);
60119c6cae24SSepherosa Ziehau 	}
60129c6cae24SSepherosa Ziehau 
6013edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
6014edd3f315SSepherosa Ziehau 	/*
6015c49d47daSSepherosa Ziehau 	 * Perform TSO packet header fixup or get l2/l3 header length now,
6016c49d47daSSepherosa Ziehau 	 * since packet headers should be cache-hot.
6017edd3f315SSepherosa Ziehau 	 */
6018edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
6019edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
6020edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
6021edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
6022edd3f315SSepherosa Ziehau 			return EIO;
6023edd3f315SSepherosa Ziehau 		}
6024c49d47daSSepherosa Ziehau 	} else if (m->m_pkthdr.csum_flags &
6025c49d47daSSepherosa Ziehau 	    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
6026c49d47daSSepherosa Ziehau 		m = hn_set_hlen(m);
6027c49d47daSSepherosa Ziehau 		if (__predict_false(m == NULL)) {
6028c49d47daSSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
6029c49d47daSSepherosa Ziehau 			return EIO;
6030c49d47daSSepherosa Ziehau 		}
6031edd3f315SSepherosa Ziehau 	}
6032edd3f315SSepherosa Ziehau #endif
6033edd3f315SSepherosa Ziehau 
603415516c77SSepherosa Ziehau 	/*
603515516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
603615516c77SSepherosa Ziehau 	 */
603734d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
603834d68912SSepherosa Ziehau #ifdef RSS
603934d68912SSepherosa Ziehau 		uint32_t bid;
604034d68912SSepherosa Ziehau 
604134d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
604234d68912SSepherosa Ziehau 		    &bid) == 0)
604334d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
604434d68912SSepherosa Ziehau 		else
604534d68912SSepherosa Ziehau #endif
6046cc0c6ebcSSepherosa Ziehau 		{
6047cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET)
6048cc0c6ebcSSepherosa Ziehau 			int tcpsyn = 0;
6049cc0c6ebcSSepherosa Ziehau 
6050cc0c6ebcSSepherosa Ziehau 			if (m->m_pkthdr.len < 128 &&
6051cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags &
6052cc0c6ebcSSepherosa Ziehau 			     (CSUM_IP_TCP | CSUM_IP6_TCP)) &&
6053cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
6054cc0c6ebcSSepherosa Ziehau 				m = hn_check_tcpsyn(m, &tcpsyn);
6055cc0c6ebcSSepherosa Ziehau 				if (__predict_false(m == NULL)) {
6056cc0c6ebcSSepherosa Ziehau 					if_inc_counter(ifp,
6057cc0c6ebcSSepherosa Ziehau 					    IFCOUNTER_OERRORS, 1);
6058cc0c6ebcSSepherosa Ziehau 					return (EIO);
6059cc0c6ebcSSepherosa Ziehau 				}
6060cc0c6ebcSSepherosa Ziehau 			}
6061cc0c6ebcSSepherosa Ziehau #else
6062cc0c6ebcSSepherosa Ziehau 			const int tcpsyn = 0;
6063cc0c6ebcSSepherosa Ziehau #endif
6064cc0c6ebcSSepherosa Ziehau 			if (tcpsyn)
6065cc0c6ebcSSepherosa Ziehau 				idx = 0;
6066cc0c6ebcSSepherosa Ziehau 			else
606715516c77SSepherosa Ziehau 				idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
606834d68912SSepherosa Ziehau 		}
6069cc0c6ebcSSepherosa Ziehau 	}
607015516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
607115516c77SSepherosa Ziehau 
607215516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
607315516c77SSepherosa Ziehau 	if (error) {
607415516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
607515516c77SSepherosa Ziehau 		return error;
607615516c77SSepherosa Ziehau 	}
607715516c77SSepherosa Ziehau 
607815516c77SSepherosa Ziehau 	if (txr->hn_oactive)
607915516c77SSepherosa Ziehau 		return 0;
608015516c77SSepherosa Ziehau 
608115516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
608215516c77SSepherosa Ziehau 		goto do_sched;
608315516c77SSepherosa Ziehau 
608415516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
608515516c77SSepherosa Ziehau 		int sched;
608615516c77SSepherosa Ziehau 
608715516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
608815516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
608915516c77SSepherosa Ziehau 		if (!sched)
609015516c77SSepherosa Ziehau 			return 0;
609115516c77SSepherosa Ziehau 	}
609215516c77SSepherosa Ziehau do_sched:
609315516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
609415516c77SSepherosa Ziehau 	return 0;
609515516c77SSepherosa Ziehau }
609615516c77SSepherosa Ziehau 
609715516c77SSepherosa Ziehau static void
hn_tx_ring_qflush(struct hn_tx_ring * txr)609815516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
609915516c77SSepherosa Ziehau {
610015516c77SSepherosa Ziehau 	struct mbuf *m;
610115516c77SSepherosa Ziehau 
610215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
610315516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
610415516c77SSepherosa Ziehau 		m_freem(m);
610515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
610615516c77SSepherosa Ziehau }
610715516c77SSepherosa Ziehau 
610815516c77SSepherosa Ziehau static void
hn_xmit_qflush(if_t ifp)61094db5958aSJustin Hibbits hn_xmit_qflush(if_t ifp)
611015516c77SSepherosa Ziehau {
61114db5958aSJustin Hibbits 	struct hn_softc *sc = if_getsoftc(ifp);
61129c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
611315516c77SSepherosa Ziehau 	int i;
611415516c77SSepherosa Ziehau 
611515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
611615516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
611715516c77SSepherosa Ziehau 	if_qflush(ifp);
61189c6cae24SSepherosa Ziehau 
61199c6cae24SSepherosa Ziehau 	rm_rlock(&sc->hn_vf_lock, &pt);
61209c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
61214db5958aSJustin Hibbits 		if_qflush(sc->hn_vf_ifp);
61229c6cae24SSepherosa Ziehau 	rm_runlock(&sc->hn_vf_lock, &pt);
612315516c77SSepherosa Ziehau }
612415516c77SSepherosa Ziehau 
612515516c77SSepherosa Ziehau static void
hn_xmit_txeof(struct hn_tx_ring * txr)612615516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
612715516c77SSepherosa Ziehau {
612815516c77SSepherosa Ziehau 
612915516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
613015516c77SSepherosa Ziehau 		goto do_sched;
613115516c77SSepherosa Ziehau 
613215516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
613315516c77SSepherosa Ziehau 		int sched;
613415516c77SSepherosa Ziehau 
613515516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
613615516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
613715516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
613815516c77SSepherosa Ziehau 		if (sched) {
613915516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
614015516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
614115516c77SSepherosa Ziehau 		}
614215516c77SSepherosa Ziehau 	} else {
614315516c77SSepherosa Ziehau do_sched:
614415516c77SSepherosa Ziehau 		/*
614515516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
614615516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
614715516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
614815516c77SSepherosa Ziehau 		 * races.
614915516c77SSepherosa Ziehau 		 */
615015516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
615115516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
615215516c77SSepherosa Ziehau 	}
615315516c77SSepherosa Ziehau }
615415516c77SSepherosa Ziehau 
615515516c77SSepherosa Ziehau static void
hn_xmit_taskfunc(void * xtxr,int pending __unused)615615516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
615715516c77SSepherosa Ziehau {
615815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
615915516c77SSepherosa Ziehau 
616015516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
616115516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
616215516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
616315516c77SSepherosa Ziehau }
616415516c77SSepherosa Ziehau 
616515516c77SSepherosa Ziehau static void
hn_xmit_txeof_taskfunc(void * xtxr,int pending __unused)616615516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
616715516c77SSepherosa Ziehau {
616815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
616915516c77SSepherosa Ziehau 
617015516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
617115516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
617215516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
617315516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
617415516c77SSepherosa Ziehau }
617515516c77SSepherosa Ziehau 
617615516c77SSepherosa Ziehau static int
hn_chan_attach(struct hn_softc * sc,struct vmbus_channel * chan)617715516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
617815516c77SSepherosa Ziehau {
617915516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
618015516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
618115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
618215516c77SSepherosa Ziehau 	int idx, error;
618315516c77SSepherosa Ziehau 
618415516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
618515516c77SSepherosa Ziehau 
618615516c77SSepherosa Ziehau 	/*
618715516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
618815516c77SSepherosa Ziehau 	 */
618915516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
619015516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
619115516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
619215516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
619315516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
619415516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
619515516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
61963ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
619715516c77SSepherosa Ziehau 
619815516c77SSepherosa Ziehau 	if (bootverbose) {
619915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
620015516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
620115516c77SSepherosa Ziehau 	}
620215516c77SSepherosa Ziehau 
620315516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
620415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
620515516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
620615516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
620715516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
620815516c77SSepherosa Ziehau 
620915516c77SSepherosa Ziehau 		txr->hn_chan = chan;
621015516c77SSepherosa Ziehau 		if (bootverbose) {
621115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
621215516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
621315516c77SSepherosa Ziehau 		}
621415516c77SSepherosa Ziehau 	}
621515516c77SSepherosa Ziehau 
621615516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
62170e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
621815516c77SSepherosa Ziehau 
621915516c77SSepherosa Ziehau 	/*
622015516c77SSepherosa Ziehau 	 * Open this channel
622115516c77SSepherosa Ziehau 	 */
622215516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
622362f9bcf2SAndrew Turner 	cbr.cbr_paddr = pmap_kextract((vm_offset_t)rxr->hn_br);
622415516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
622515516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
622615516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
622715516c77SSepherosa Ziehau 	if (error) {
622871e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
622971e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
623071e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
623171e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
623271e8ac56SSepherosa Ziehau 		} else {
623315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
623415516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
623571e8ac56SSepherosa Ziehau 		}
623615516c77SSepherosa Ziehau 	}
623715516c77SSepherosa Ziehau 	return (error);
623815516c77SSepherosa Ziehau }
623915516c77SSepherosa Ziehau 
624015516c77SSepherosa Ziehau static void
hn_chan_detach(struct hn_softc * sc,struct vmbus_channel * chan)624115516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
624215516c77SSepherosa Ziehau {
624315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
62442494d735SSepherosa Ziehau 	int idx, error;
624515516c77SSepherosa Ziehau 
624615516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
624715516c77SSepherosa Ziehau 
624815516c77SSepherosa Ziehau 	/*
624915516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
625015516c77SSepherosa Ziehau 	 */
625115516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
625215516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
625315516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
625415516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
625515516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
625615516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
625715516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
625815516c77SSepherosa Ziehau 
625915516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
626015516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
626115516c77SSepherosa Ziehau 
626215516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
626315516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
626415516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
626515516c77SSepherosa Ziehau 	}
626615516c77SSepherosa Ziehau 
626715516c77SSepherosa Ziehau 	/*
626815516c77SSepherosa Ziehau 	 * Close this channel.
626915516c77SSepherosa Ziehau 	 *
627015516c77SSepherosa Ziehau 	 * NOTE:
627115516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
627215516c77SSepherosa Ziehau 	 */
62732494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
62742494d735SSepherosa Ziehau 	if (error == EISCONN) {
6275aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
6276aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
62772494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
62782494d735SSepherosa Ziehau 	} else if (error) {
6279aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
6280aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
62812494d735SSepherosa Ziehau 	}
628215516c77SSepherosa Ziehau }
628315516c77SSepherosa Ziehau 
628415516c77SSepherosa Ziehau static int
hn_attach_subchans(struct hn_softc * sc)628515516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
628615516c77SSepherosa Ziehau {
628715516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
628815516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
628915516c77SSepherosa Ziehau 	int i, error = 0;
629015516c77SSepherosa Ziehau 
629171e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
629215516c77SSepherosa Ziehau 
629315516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
629415516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
629515516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
629671e8ac56SSepherosa Ziehau 		int error1;
629771e8ac56SSepherosa Ziehau 
629871e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
629971e8ac56SSepherosa Ziehau 		if (error1) {
630071e8ac56SSepherosa Ziehau 			error = error1;
630171e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
630271e8ac56SSepherosa Ziehau 		}
630315516c77SSepherosa Ziehau 	}
630415516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
630515516c77SSepherosa Ziehau 
630615516c77SSepherosa Ziehau 	if (error) {
630715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
630815516c77SSepherosa Ziehau 	} else {
630915516c77SSepherosa Ziehau 		if (bootverbose) {
631015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
631115516c77SSepherosa Ziehau 			    subchan_cnt);
631215516c77SSepherosa Ziehau 		}
631315516c77SSepherosa Ziehau 	}
631415516c77SSepherosa Ziehau 	return (error);
631515516c77SSepherosa Ziehau }
631615516c77SSepherosa Ziehau 
631715516c77SSepherosa Ziehau static void
hn_detach_allchans(struct hn_softc * sc)631815516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
631915516c77SSepherosa Ziehau {
632015516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
632115516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
632215516c77SSepherosa Ziehau 	int i;
632315516c77SSepherosa Ziehau 
632415516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
632515516c77SSepherosa Ziehau 		goto back;
632615516c77SSepherosa Ziehau 
632715516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
632815516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
632915516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
633015516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
633115516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
633215516c77SSepherosa Ziehau 
633315516c77SSepherosa Ziehau back:
633415516c77SSepherosa Ziehau 	/*
633515516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
633615516c77SSepherosa Ziehau 	 * are detached.
633715516c77SSepherosa Ziehau 	 */
633815516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
633915516c77SSepherosa Ziehau 
634015516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
634115516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
634215516c77SSepherosa Ziehau 
634315516c77SSepherosa Ziehau #ifdef INVARIANTS
634415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
634515516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
634615516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
634715516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
634815516c77SSepherosa Ziehau 	}
634915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
635015516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
635115516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
635215516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
635315516c77SSepherosa Ziehau 	}
635415516c77SSepherosa Ziehau #endif
635515516c77SSepherosa Ziehau }
635615516c77SSepherosa Ziehau 
635715516c77SSepherosa Ziehau static int
hn_synth_alloc_subchans(struct hn_softc * sc,int * nsubch)635815516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
635915516c77SSepherosa Ziehau {
636015516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
636115516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
636215516c77SSepherosa Ziehau 
636315516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
636415516c77SSepherosa Ziehau 	if (nchan == 1) {
636515516c77SSepherosa Ziehau 		/*
636615516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
636715516c77SSepherosa Ziehau 		 */
636815516c77SSepherosa Ziehau 		*nsubch = 0;
636915516c77SSepherosa Ziehau 		return (0);
637015516c77SSepherosa Ziehau 	}
637115516c77SSepherosa Ziehau 
637215516c77SSepherosa Ziehau 	/*
637315516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
637415516c77SSepherosa Ziehau 	 * table entries.
637515516c77SSepherosa Ziehau 	 */
637615516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
637715516c77SSepherosa Ziehau 	if (error) {
637815516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
637915516c77SSepherosa Ziehau 		*nsubch = 0;
638015516c77SSepherosa Ziehau 		return (0);
638115516c77SSepherosa Ziehau 	}
638215516c77SSepherosa Ziehau 	if (bootverbose) {
638315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
638415516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
638515516c77SSepherosa Ziehau 	}
638615516c77SSepherosa Ziehau 
638715516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
638815516c77SSepherosa Ziehau 		nchan = rxr_cnt;
638915516c77SSepherosa Ziehau 	if (nchan == 1) {
639015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
639115516c77SSepherosa Ziehau 		*nsubch = 0;
639215516c77SSepherosa Ziehau 		return (0);
639315516c77SSepherosa Ziehau 	}
639415516c77SSepherosa Ziehau 
639515516c77SSepherosa Ziehau 	/*
639615516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
639715516c77SSepherosa Ziehau 	 */
639815516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
639915516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
640015516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
640115516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
640215516c77SSepherosa Ziehau 		*nsubch = 0;
640315516c77SSepherosa Ziehau 		return (0);
640415516c77SSepherosa Ziehau 	}
640515516c77SSepherosa Ziehau 
640615516c77SSepherosa Ziehau 	/*
640715516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
640815516c77SSepherosa Ziehau 	 */
640915516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
641015516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
641115516c77SSepherosa Ziehau 	return (0);
641215516c77SSepherosa Ziehau }
641315516c77SSepherosa Ziehau 
64142494d735SSepherosa Ziehau static bool
hn_synth_attachable(const struct hn_softc * sc)64152494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
64162494d735SSepherosa Ziehau {
64172494d735SSepherosa Ziehau 	int i;
64182494d735SSepherosa Ziehau 
64192494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
64202494d735SSepherosa Ziehau 		return (false);
64212494d735SSepherosa Ziehau 
64222494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
64232494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
64242494d735SSepherosa Ziehau 
64252494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
64262494d735SSepherosa Ziehau 			return (false);
64272494d735SSepherosa Ziehau 	}
64282494d735SSepherosa Ziehau 	return (true);
64292494d735SSepherosa Ziehau }
64302494d735SSepherosa Ziehau 
6431b3b75d9cSSepherosa Ziehau /*
6432b3b75d9cSSepherosa Ziehau  * Make sure that the RX filter is zero after the successful
6433b3b75d9cSSepherosa Ziehau  * RNDIS initialization.
6434b3b75d9cSSepherosa Ziehau  *
6435b3b75d9cSSepherosa Ziehau  * NOTE:
6436b3b75d9cSSepherosa Ziehau  * Under certain conditions on certain versions of Hyper-V,
6437b3b75d9cSSepherosa Ziehau  * the RNDIS rxfilter is _not_ zero on the hypervisor side
6438b3b75d9cSSepherosa Ziehau  * after the successful RNDIS initialization, which breaks
6439b3b75d9cSSepherosa Ziehau  * the assumption of any following code (well, it breaks the
6440b3b75d9cSSepherosa Ziehau  * RNDIS API contract actually).  Clear the RNDIS rxfilter
6441b3b75d9cSSepherosa Ziehau  * explicitly, drain packets sneaking through, and drain the
6442b3b75d9cSSepherosa Ziehau  * interrupt taskqueues scheduled due to the stealth packets.
6443b3b75d9cSSepherosa Ziehau  */
6444b3b75d9cSSepherosa Ziehau static void
hn_rndis_init_fixat(struct hn_softc * sc,int nchan)6445b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan)
6446b3b75d9cSSepherosa Ziehau {
6447b3b75d9cSSepherosa Ziehau 
6448b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
6449b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, nchan);
6450b3b75d9cSSepherosa Ziehau }
6451b3b75d9cSSepherosa Ziehau 
645215516c77SSepherosa Ziehau static int
hn_synth_attach(struct hn_softc * sc,int mtu)645315516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
645415516c77SSepherosa Ziehau {
645571e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
645671e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
645771e8ac56SSepherosa Ziehau 
645815516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
6459b3b75d9cSSepherosa Ziehau 	int error, nsubch, nchan = 1, i, rndis_inited;
646071e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
646115516c77SSepherosa Ziehau 
646215516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
646315516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
646415516c77SSepherosa Ziehau 
64652494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
64662494d735SSepherosa Ziehau 		return (ENXIO);
64672494d735SSepherosa Ziehau 
646815516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
646915516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
647015516c77SSepherosa Ziehau 	sc->hn_caps = 0;
647115516c77SSepherosa Ziehau 
647215516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
647315516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
647415516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
6475642ec226SSepherosa Ziehau 	sc->hn_rss_hcap = 0;
647615516c77SSepherosa Ziehau 
647715516c77SSepherosa Ziehau 	/*
647815516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
647915516c77SSepherosa Ziehau 	 */
648015516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
648115516c77SSepherosa Ziehau 	if (error)
648271e8ac56SSepherosa Ziehau 		goto failed;
648315516c77SSepherosa Ziehau 
648415516c77SSepherosa Ziehau 	/*
648515516c77SSepherosa Ziehau 	 * Attach NVS.
648615516c77SSepherosa Ziehau 	 */
648715516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
648815516c77SSepherosa Ziehau 	if (error)
648971e8ac56SSepherosa Ziehau 		goto failed;
649071e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
649115516c77SSepherosa Ziehau 
649215516c77SSepherosa Ziehau 	/*
649315516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
649415516c77SSepherosa Ziehau 	 */
6495b3b75d9cSSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu, &rndis_inited);
6496b3b75d9cSSepherosa Ziehau 	if (rndis_inited)
6497b3b75d9cSSepherosa Ziehau 		attached |= ATTACHED_RNDIS;
649815516c77SSepherosa Ziehau 	if (error)
649971e8ac56SSepherosa Ziehau 		goto failed;
650015516c77SSepherosa Ziehau 
650115516c77SSepherosa Ziehau 	/*
650215516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
650315516c77SSepherosa Ziehau 	 */
650415516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
650515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
650615516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
650771e8ac56SSepherosa Ziehau 		error = ENXIO;
650871e8ac56SSepherosa Ziehau 		goto failed;
650915516c77SSepherosa Ziehau 	}
651015516c77SSepherosa Ziehau 
651115516c77SSepherosa Ziehau 	/*
651215516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
651315516c77SSepherosa Ziehau 	 *
651415516c77SSepherosa Ziehau 	 * NOTE:
651515516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
651615516c77SSepherosa Ziehau 	 * channels to be requested.
651715516c77SSepherosa Ziehau 	 */
651815516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
651915516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
652015516c77SSepherosa Ziehau 	if (error)
652171e8ac56SSepherosa Ziehau 		goto failed;
652271e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
652371e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
652415516c77SSepherosa Ziehau 
652571e8ac56SSepherosa Ziehau 	/*
652671e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
652771e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
652871e8ac56SSepherosa Ziehau 	 */
652915516c77SSepherosa Ziehau 	nchan = nsubch + 1;
653071e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
653115516c77SSepherosa Ziehau 	if (nchan == 1) {
653215516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
653315516c77SSepherosa Ziehau 		goto back;
653415516c77SSepherosa Ziehau 	}
653515516c77SSepherosa Ziehau 
653615516c77SSepherosa Ziehau 	/*
653771e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
6538afd4971bSSepherosa Ziehau 	 *
6539afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
654015516c77SSepherosa Ziehau 	 */
654171e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
654271e8ac56SSepherosa Ziehau 	if (error)
654371e8ac56SSepherosa Ziehau 		goto failed;
654415516c77SSepherosa Ziehau 
654571e8ac56SSepherosa Ziehau 	/*
654671e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
654771e8ac56SSepherosa Ziehau 	 * are attached.
654871e8ac56SSepherosa Ziehau 	 */
654915516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
655015516c77SSepherosa Ziehau 		/*
655115516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
655215516c77SSepherosa Ziehau 		 */
655315516c77SSepherosa Ziehau 		if (bootverbose)
655415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
655534d68912SSepherosa Ziehau #ifdef RSS
655634d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
655734d68912SSepherosa Ziehau #else
655815516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
655934d68912SSepherosa Ziehau #endif
656015516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
656115516c77SSepherosa Ziehau 	}
656215516c77SSepherosa Ziehau 
656315516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
656415516c77SSepherosa Ziehau 		/*
656515516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
656615516c77SSepherosa Ziehau 		 * robin fashion.
656715516c77SSepherosa Ziehau 		 */
656815516c77SSepherosa Ziehau 		if (bootverbose) {
656915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
657015516c77SSepherosa Ziehau 			    "table\n");
657115516c77SSepherosa Ziehau 		}
657234d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
657334d68912SSepherosa Ziehau 			uint32_t subidx;
657434d68912SSepherosa Ziehau 
657534d68912SSepherosa Ziehau #ifdef RSS
657634d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
657734d68912SSepherosa Ziehau #else
657834d68912SSepherosa Ziehau 			subidx = i;
657934d68912SSepherosa Ziehau #endif
658034d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
658134d68912SSepherosa Ziehau 		}
658215516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
658315516c77SSepherosa Ziehau 	} else {
658415516c77SSepherosa Ziehau 		/*
658515516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
658615516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
658715516c77SSepherosa Ziehau 		 * are valid.
6588afd4971bSSepherosa Ziehau 		 *
6589afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
659015516c77SSepherosa Ziehau 		 */
6591afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
659215516c77SSepherosa Ziehau 	}
659315516c77SSepherosa Ziehau 
6594642ec226SSepherosa Ziehau 	sc->hn_rss_hash = sc->hn_rss_hcap;
6595642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
6596642ec226SSepherosa Ziehau 	    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
6597642ec226SSepherosa Ziehau 		/* NOTE: Don't reconfigure RSS; will do immediately. */
6598642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, false);
6599642ec226SSepherosa Ziehau 	}
660015516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
660115516c77SSepherosa Ziehau 	if (error)
660271e8ac56SSepherosa Ziehau 		goto failed;
660371e8ac56SSepherosa Ziehau back:
6604dc13fee6SSepherosa Ziehau 	/*
6605dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
6606dc13fee6SSepherosa Ziehau 	 */
6607dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
6608b3b75d9cSSepherosa Ziehau 	hn_rndis_init_fixat(sc, nchan);
660915516c77SSepherosa Ziehau 	return (0);
661071e8ac56SSepherosa Ziehau 
661171e8ac56SSepherosa Ziehau failed:
661271e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
6613b3b75d9cSSepherosa Ziehau 		hn_rndis_init_fixat(sc, nchan);
661471e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
661571e8ac56SSepherosa Ziehau 	} else {
6616b3b75d9cSSepherosa Ziehau 		if (attached & ATTACHED_RNDIS) {
6617b3b75d9cSSepherosa Ziehau 			hn_rndis_init_fixat(sc, nchan);
661871e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
6619b3b75d9cSSepherosa Ziehau 		}
662071e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
662171e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
662271e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
662371e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
662471e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
662571e8ac56SSepherosa Ziehau 	}
662671e8ac56SSepherosa Ziehau 	return (error);
662771e8ac56SSepherosa Ziehau 
662871e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
662971e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
663015516c77SSepherosa Ziehau }
663115516c77SSepherosa Ziehau 
663215516c77SSepherosa Ziehau /*
663315516c77SSepherosa Ziehau  * NOTE:
663415516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
663515516c77SSepherosa Ziehau  * this function get called.
663615516c77SSepherosa Ziehau  */
663715516c77SSepherosa Ziehau static void
hn_synth_detach(struct hn_softc * sc)663815516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
663915516c77SSepherosa Ziehau {
664015516c77SSepherosa Ziehau 
664115516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
664215516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
664315516c77SSepherosa Ziehau 
664415516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
664515516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
664615516c77SSepherosa Ziehau 
664715516c77SSepherosa Ziehau 	/* Detach NVS. */
664815516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
664915516c77SSepherosa Ziehau 
665015516c77SSepherosa Ziehau 	/* Detach all of the channels. */
665115516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
665215516c77SSepherosa Ziehau 
6653ace5ce7eSWei Hu 	if (vmbus_current_version >= VMBUS_VERSION_WIN10 && sc->hn_rxbuf_gpadl != 0) {
6654ace5ce7eSWei Hu 		/*
6655ace5ce7eSWei Hu 		 * Host is post-Win2016, disconnect RXBUF from primary channel here.
6656ace5ce7eSWei Hu 		 */
6657ace5ce7eSWei Hu 		int error;
6658ace5ce7eSWei Hu 
6659ace5ce7eSWei Hu 		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
6660ace5ce7eSWei Hu 		    sc->hn_rxbuf_gpadl);
6661ace5ce7eSWei Hu 		if (error) {
6662ace5ce7eSWei Hu 			if_printf(sc->hn_ifp,
6663ace5ce7eSWei Hu 			    "rxbuf gpadl disconn failed: %d\n", error);
6664ace5ce7eSWei Hu 			sc->hn_flags |= HN_FLAG_RXBUF_REF;
6665ace5ce7eSWei Hu 		}
6666ace5ce7eSWei Hu 		sc->hn_rxbuf_gpadl = 0;
6667ace5ce7eSWei Hu 	}
6668ace5ce7eSWei Hu 
6669ace5ce7eSWei Hu 	if (vmbus_current_version >= VMBUS_VERSION_WIN10 && sc->hn_chim_gpadl != 0) {
6670ace5ce7eSWei Hu 		/*
6671ace5ce7eSWei Hu 		 * Host is post-Win2016, disconnect chimney sending buffer from
6672ace5ce7eSWei Hu 		 * primary channel here.
6673ace5ce7eSWei Hu 		 */
6674ace5ce7eSWei Hu 		int error;
6675ace5ce7eSWei Hu 
6676ace5ce7eSWei Hu 		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
6677ace5ce7eSWei Hu 		    sc->hn_chim_gpadl);
6678ace5ce7eSWei Hu 		if (error) {
6679ace5ce7eSWei Hu 			if_printf(sc->hn_ifp,
6680ace5ce7eSWei Hu 			    "chim gpadl disconn failed: %d\n", error);
6681ace5ce7eSWei Hu 			sc->hn_flags |= HN_FLAG_CHIM_REF;
6682ace5ce7eSWei Hu 		}
6683ace5ce7eSWei Hu 		sc->hn_chim_gpadl = 0;
6684ace5ce7eSWei Hu 	}
668515516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
668615516c77SSepherosa Ziehau }
668715516c77SSepherosa Ziehau 
668815516c77SSepherosa Ziehau static void
hn_set_ring_inuse(struct hn_softc * sc,int ring_cnt)668915516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
669015516c77SSepherosa Ziehau {
669115516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
669215516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
669315516c77SSepherosa Ziehau 
669415516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
669515516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
669615516c77SSepherosa Ziehau 	else
669715516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
669815516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
669915516c77SSepherosa Ziehau 
670034d68912SSepherosa Ziehau #ifdef RSS
670134d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
670234d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
670334d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
670434d68912SSepherosa Ziehau 		    rss_getnumbuckets());
670534d68912SSepherosa Ziehau 	}
670634d68912SSepherosa Ziehau #endif
670734d68912SSepherosa Ziehau 
670815516c77SSepherosa Ziehau 	if (bootverbose) {
670915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
671015516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
671115516c77SSepherosa Ziehau 	}
671215516c77SSepherosa Ziehau }
671315516c77SSepherosa Ziehau 
671415516c77SSepherosa Ziehau static void
hn_chan_drain(struct hn_softc * sc,struct vmbus_channel * chan)671525641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
671615516c77SSepherosa Ziehau {
671715516c77SSepherosa Ziehau 
671825641fc7SSepherosa Ziehau 	/*
671925641fc7SSepherosa Ziehau 	 * NOTE:
672025641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
672125641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
672225641fc7SSepherosa Ziehau 	 */
672325641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
672425641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
672525641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
672615516c77SSepherosa Ziehau 		pause("waitch", 1);
672715516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
672815516c77SSepherosa Ziehau }
672915516c77SSepherosa Ziehau 
673015516c77SSepherosa Ziehau static void
hn_disable_rx(struct hn_softc * sc)6731b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc)
6732b3b75d9cSSepherosa Ziehau {
6733b3b75d9cSSepherosa Ziehau 
6734b3b75d9cSSepherosa Ziehau 	/*
6735b3b75d9cSSepherosa Ziehau 	 * Disable RX by clearing RX filter forcefully.
6736b3b75d9cSSepherosa Ziehau 	 */
6737b3b75d9cSSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
6738b3b75d9cSSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */
6739b3b75d9cSSepherosa Ziehau 
6740b3b75d9cSSepherosa Ziehau 	/*
6741b3b75d9cSSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
6742b3b75d9cSSepherosa Ziehau 	 */
6743b3b75d9cSSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
6744b3b75d9cSSepherosa Ziehau }
6745b3b75d9cSSepherosa Ziehau 
6746b3b75d9cSSepherosa Ziehau /*
6747b3b75d9cSSepherosa Ziehau  * NOTE:
6748b3b75d9cSSepherosa Ziehau  * RX/TX _must_ have been suspended/disabled, before this function
6749b3b75d9cSSepherosa Ziehau  * is called.
6750b3b75d9cSSepherosa Ziehau  */
6751b3b75d9cSSepherosa Ziehau static void
hn_drain_rxtx(struct hn_softc * sc,int nchan)6752b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan)
675315516c77SSepherosa Ziehau {
675415516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
6755b3b75d9cSSepherosa Ziehau 	int nsubch;
6756b3b75d9cSSepherosa Ziehau 
6757b3b75d9cSSepherosa Ziehau 	/*
6758b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
6759b3b75d9cSSepherosa Ziehau 	 */
6760b3b75d9cSSepherosa Ziehau 	nsubch = nchan - 1;
6761b3b75d9cSSepherosa Ziehau 	if (nsubch > 0)
6762b3b75d9cSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
6763b3b75d9cSSepherosa Ziehau 
6764b3b75d9cSSepherosa Ziehau 	if (subch != NULL) {
6765b3b75d9cSSepherosa Ziehau 		int i;
6766b3b75d9cSSepherosa Ziehau 
6767b3b75d9cSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
6768b3b75d9cSSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
6769b3b75d9cSSepherosa Ziehau 	}
6770b3b75d9cSSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
6771b3b75d9cSSepherosa Ziehau 
6772b3b75d9cSSepherosa Ziehau 	if (subch != NULL)
6773b3b75d9cSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
6774b3b75d9cSSepherosa Ziehau }
6775b3b75d9cSSepherosa Ziehau 
6776b3b75d9cSSepherosa Ziehau static void
hn_suspend_data(struct hn_softc * sc)6777b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
6778b3b75d9cSSepherosa Ziehau {
677925641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
6780b3b75d9cSSepherosa Ziehau 	int i;
678115516c77SSepherosa Ziehau 
678215516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
678315516c77SSepherosa Ziehau 
678415516c77SSepherosa Ziehau 	/*
678515516c77SSepherosa Ziehau 	 * Suspend TX.
678615516c77SSepherosa Ziehau 	 */
678715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
678825641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
678915516c77SSepherosa Ziehau 
679015516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
679115516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
679215516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
679315516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
679415516c77SSepherosa Ziehau 
679525641fc7SSepherosa Ziehau 		/*
679625641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
679725641fc7SSepherosa Ziehau 		 *
679825641fc7SSepherosa Ziehau 		 * NOTE:
679925641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
680025641fc7SSepherosa Ziehau 		 * primary channel is revoked.
680125641fc7SSepherosa Ziehau 		 */
680225641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
680325641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
680415516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
680515516c77SSepherosa Ziehau 	}
680615516c77SSepherosa Ziehau 
680715516c77SSepherosa Ziehau 	/*
6808b3b75d9cSSepherosa Ziehau 	 * Disable RX.
680915516c77SSepherosa Ziehau 	 */
6810b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
681115516c77SSepherosa Ziehau 
681215516c77SSepherosa Ziehau 	/*
6813b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX.
681415516c77SSepherosa Ziehau 	 */
6815b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, sc->hn_rx_ring_inuse);
681625641fc7SSepherosa Ziehau 
681725641fc7SSepherosa Ziehau 	/*
681825641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
681925641fc7SSepherosa Ziehau 	 *
682025641fc7SSepherosa Ziehau 	 * NOTE:
6821b3b75d9cSSepherosa Ziehau 	 * The above hn_drain_rxtx() can dispatch TX tasks, so the TX
6822b3b75d9cSSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_drain_rxtx().
682325641fc7SSepherosa Ziehau 	 */
682425641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
682525641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
682625641fc7SSepherosa Ziehau 
682725641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
682825641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
682925641fc7SSepherosa Ziehau 	}
683015516c77SSepherosa Ziehau }
683115516c77SSepherosa Ziehau 
683215516c77SSepherosa Ziehau static void
hn_suspend_mgmt_taskfunc(void * xsc,int pending __unused)683315516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
683415516c77SSepherosa Ziehau {
683515516c77SSepherosa Ziehau 
683615516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
683715516c77SSepherosa Ziehau }
683815516c77SSepherosa Ziehau 
683915516c77SSepherosa Ziehau static void
hn_suspend_mgmt(struct hn_softc * sc)684015516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
684115516c77SSepherosa Ziehau {
684215516c77SSepherosa Ziehau 	struct task task;
684315516c77SSepherosa Ziehau 
684415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
684515516c77SSepherosa Ziehau 
684615516c77SSepherosa Ziehau 	/*
684715516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
684815516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
684915516c77SSepherosa Ziehau 	 */
685015516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
685115516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
685215516c77SSepherosa Ziehau 
685315516c77SSepherosa Ziehau 	/*
685415516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
685515516c77SSepherosa Ziehau 	 */
685615516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
685715516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
685815516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
685915516c77SSepherosa Ziehau }
686015516c77SSepherosa Ziehau 
686115516c77SSepherosa Ziehau static void
hn_suspend(struct hn_softc * sc)686215516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
686315516c77SSepherosa Ziehau {
686415516c77SSepherosa Ziehau 
686587f8129dSSepherosa Ziehau 	/* Disable polling. */
686687f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
686787f8129dSSepherosa Ziehau 
68689c6cae24SSepherosa Ziehau 	/*
68699c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
68709c6cae24SSepherosa Ziehau 	 * device is receiving packets, so the data path of the
68719c6cae24SSepherosa Ziehau 	 * synthetic device must be suspended.
68729c6cae24SSepherosa Ziehau 	 */
68734db5958aSJustin Hibbits 	if ((if_getdrvflags(sc->hn_ifp) & IFF_DRV_RUNNING) ||
6874962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
687515516c77SSepherosa Ziehau 		hn_suspend_data(sc);
687615516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
687715516c77SSepherosa Ziehau }
687815516c77SSepherosa Ziehau 
687915516c77SSepherosa Ziehau static void
hn_resume_tx(struct hn_softc * sc,int tx_ring_cnt)688015516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
688115516c77SSepherosa Ziehau {
688215516c77SSepherosa Ziehau 	int i;
688315516c77SSepherosa Ziehau 
688415516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
688515516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
688615516c77SSepherosa Ziehau 
688715516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
688815516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
688915516c77SSepherosa Ziehau 
689015516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
689115516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
689215516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
689315516c77SSepherosa Ziehau 	}
689415516c77SSepherosa Ziehau }
689515516c77SSepherosa Ziehau 
689615516c77SSepherosa Ziehau static void
hn_resume_data(struct hn_softc * sc)689715516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
689815516c77SSepherosa Ziehau {
689915516c77SSepherosa Ziehau 	int i;
690015516c77SSepherosa Ziehau 
690115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
690215516c77SSepherosa Ziehau 
690315516c77SSepherosa Ziehau 	/*
690415516c77SSepherosa Ziehau 	 * Re-enable RX.
690515516c77SSepherosa Ziehau 	 */
6906c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
690715516c77SSepherosa Ziehau 
690815516c77SSepherosa Ziehau 	/*
690915516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
691015516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
691115516c77SSepherosa Ziehau 	 * hn_suspend_data().
691215516c77SSepherosa Ziehau 	 */
691315516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
691415516c77SSepherosa Ziehau 
691523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
691623bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
691723bf9e15SSepherosa Ziehau #endif
691823bf9e15SSepherosa Ziehau 	{
691915516c77SSepherosa Ziehau 		/*
692015516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
692115516c77SSepherosa Ziehau 		 * reduced.
692215516c77SSepherosa Ziehau 		 */
692315516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
692415516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
692515516c77SSepherosa Ziehau 	}
692615516c77SSepherosa Ziehau 
692715516c77SSepherosa Ziehau 	/*
692815516c77SSepherosa Ziehau 	 * Kick start TX.
692915516c77SSepherosa Ziehau 	 */
693015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
693115516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
693215516c77SSepherosa Ziehau 
693315516c77SSepherosa Ziehau 		/*
693415516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
693515516c77SSepherosa Ziehau 		 * cleared properly.
693615516c77SSepherosa Ziehau 		 */
693715516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
693815516c77SSepherosa Ziehau 	}
693915516c77SSepherosa Ziehau }
694015516c77SSepherosa Ziehau 
694115516c77SSepherosa Ziehau static void
hn_resume_mgmt(struct hn_softc * sc)694215516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
694315516c77SSepherosa Ziehau {
694415516c77SSepherosa Ziehau 
694515516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
694615516c77SSepherosa Ziehau 
694715516c77SSepherosa Ziehau 	/*
694815516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
694915516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
695015516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
695115516c77SSepherosa Ziehau 	 * detection.
695215516c77SSepherosa Ziehau 	 */
695315516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
695415516c77SSepherosa Ziehau 		hn_change_network(sc);
695515516c77SSepherosa Ziehau 	else
695615516c77SSepherosa Ziehau 		hn_update_link_status(sc);
695715516c77SSepherosa Ziehau }
695815516c77SSepherosa Ziehau 
695915516c77SSepherosa Ziehau static void
hn_resume(struct hn_softc * sc)696015516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
696115516c77SSepherosa Ziehau {
696215516c77SSepherosa Ziehau 
69639c6cae24SSepherosa Ziehau 	/*
69649c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
69659c6cae24SSepherosa Ziehau 	 * device have to receive packets, so the data path of the
69669c6cae24SSepherosa Ziehau 	 * synthetic device must be resumed.
69679c6cae24SSepherosa Ziehau 	 */
69684db5958aSJustin Hibbits 	if ((if_getdrvflags(sc->hn_ifp) & IFF_DRV_RUNNING) ||
6969962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
697015516c77SSepherosa Ziehau 		hn_resume_data(sc);
69715bdfd3fdSDexuan Cui 
69725bdfd3fdSDexuan Cui 	/*
69739c6cae24SSepherosa Ziehau 	 * Don't resume link status change if VF is attached/activated.
69749c6cae24SSepherosa Ziehau 	 * - In the non-transparent VF mode, the synthetic device marks
69759c6cae24SSepherosa Ziehau 	 *   link down until the VF is deactivated; i.e. VF is down.
69769c6cae24SSepherosa Ziehau 	 * - In transparent VF mode, VF's media status is used until
69779c6cae24SSepherosa Ziehau 	 *   the VF is detached.
69785bdfd3fdSDexuan Cui 	 */
69799c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) == 0 &&
69809c6cae24SSepherosa Ziehau 	    !(hn_xpnt_vf && sc->hn_vf_ifp != NULL))
698115516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
698287f8129dSSepherosa Ziehau 
698387f8129dSSepherosa Ziehau 	/*
698487f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
698587f8129dSSepherosa Ziehau 	 * the polling is requested.
698687f8129dSSepherosa Ziehau 	 */
69874db5958aSJustin Hibbits 	if ((if_getdrvflags(sc->hn_ifp) & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
698887f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
698915516c77SSepherosa Ziehau }
699015516c77SSepherosa Ziehau 
699115516c77SSepherosa Ziehau static void
hn_rndis_rx_status(struct hn_softc * sc,const void * data,int dlen)699215516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
699315516c77SSepherosa Ziehau {
699415516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
699515516c77SSepherosa Ziehau 	int ofs;
699615516c77SSepherosa Ziehau 
699715516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
699815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
699915516c77SSepherosa Ziehau 		return;
700015516c77SSepherosa Ziehau 	}
700115516c77SSepherosa Ziehau 	msg = data;
700215516c77SSepherosa Ziehau 
700315516c77SSepherosa Ziehau 	switch (msg->rm_status) {
700415516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
700515516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
700615516c77SSepherosa Ziehau 		hn_update_link_status(sc);
700715516c77SSepherosa Ziehau 		break;
700815516c77SSepherosa Ziehau 
700915516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
701040905afaSSepherosa Ziehau 	case RNDIS_STATUS_LINK_SPEED_CHANGE:
701115516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
701215516c77SSepherosa Ziehau 		break;
701315516c77SSepherosa Ziehau 
701415516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
701515516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
701615516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
701715516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
701815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
701915516c77SSepherosa Ziehau 		} else {
702015516c77SSepherosa Ziehau 			uint32_t change;
702115516c77SSepherosa Ziehau 
702215516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
702315516c77SSepherosa Ziehau 			    sizeof(change));
702415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
702515516c77SSepherosa Ziehau 			    change);
702615516c77SSepherosa Ziehau 		}
702715516c77SSepherosa Ziehau 		hn_change_network(sc);
702815516c77SSepherosa Ziehau 		break;
702915516c77SSepherosa Ziehau 
703015516c77SSepherosa Ziehau 	default:
703115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
703215516c77SSepherosa Ziehau 		    msg->rm_status);
703315516c77SSepherosa Ziehau 		break;
703415516c77SSepherosa Ziehau 	}
703515516c77SSepherosa Ziehau }
703615516c77SSepherosa Ziehau 
703715516c77SSepherosa Ziehau static int
hn_rndis_rxinfo(const void * info_data,int info_dlen,struct hn_rxinfo * info)703815516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
703915516c77SSepherosa Ziehau {
704015516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
704115516c77SSepherosa Ziehau 	uint32_t mask = 0;
704215516c77SSepherosa Ziehau 
704315516c77SSepherosa Ziehau 	while (info_dlen != 0) {
704415516c77SSepherosa Ziehau 		const void *data;
704515516c77SSepherosa Ziehau 		uint32_t dlen;
704615516c77SSepherosa Ziehau 
704715516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
704815516c77SSepherosa Ziehau 			return (EINVAL);
704915516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
705015516c77SSepherosa Ziehau 			return (EINVAL);
705115516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
705215516c77SSepherosa Ziehau 
705315516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
705415516c77SSepherosa Ziehau 			return (EINVAL);
705515516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
705615516c77SSepherosa Ziehau 			return (EINVAL);
705715516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
705815516c77SSepherosa Ziehau 		data = pi->rm_data;
705915516c77SSepherosa Ziehau 
7060a491581fSWei Hu 		if (pi->rm_internal == 1) {
7061a491581fSWei Hu 			switch (pi->rm_type) {
7062a491581fSWei Hu 			case NDIS_PKTINFO_IT_PKTINFO_ID:
7063a491581fSWei Hu 				if (__predict_false(dlen < NDIS_PKTINFOID_SZ))
7064a491581fSWei Hu 					return (EINVAL);
7065a491581fSWei Hu 				info->pktinfo_id =
7066a491581fSWei Hu 				    (const struct packet_info_id *)data;
7067a491581fSWei Hu 				mask |= HN_RXINFO_PKTINFO_ID;
7068a491581fSWei Hu 				break;
7069a491581fSWei Hu 
7070a491581fSWei Hu 			default:
7071a491581fSWei Hu 				goto next;
7072a491581fSWei Hu 			}
7073a491581fSWei Hu 		} else {
707415516c77SSepherosa Ziehau 			switch (pi->rm_type) {
707515516c77SSepherosa Ziehau 			case NDIS_PKTINFO_TYPE_VLAN:
7076a491581fSWei Hu 				if (__predict_false(dlen
7077a491581fSWei Hu 				    < NDIS_VLAN_INFO_SIZE))
707815516c77SSepherosa Ziehau 					return (EINVAL);
7079a491581fSWei Hu 				info->vlan_info = (const uint32_t *)data;
708015516c77SSepherosa Ziehau 				mask |= HN_RXINFO_VLAN;
708115516c77SSepherosa Ziehau 				break;
708215516c77SSepherosa Ziehau 
708315516c77SSepherosa Ziehau 			case NDIS_PKTINFO_TYPE_CSUM:
7084a491581fSWei Hu 				if (__predict_false(dlen
7085a491581fSWei Hu 				    < NDIS_RXCSUM_INFO_SIZE))
708615516c77SSepherosa Ziehau 					return (EINVAL);
7087a491581fSWei Hu 				info->csum_info = (const uint32_t *)data;
708815516c77SSepherosa Ziehau 				mask |= HN_RXINFO_CSUM;
708915516c77SSepherosa Ziehau 				break;
709015516c77SSepherosa Ziehau 
709115516c77SSepherosa Ziehau 			case HN_NDIS_PKTINFO_TYPE_HASHVAL:
7092a491581fSWei Hu 				if (__predict_false(dlen
7093a491581fSWei Hu 				    < HN_NDIS_HASH_VALUE_SIZE))
709415516c77SSepherosa Ziehau 					return (EINVAL);
7095a491581fSWei Hu 				info->hash_value = (const uint32_t *)data;
709615516c77SSepherosa Ziehau 				mask |= HN_RXINFO_HASHVAL;
709715516c77SSepherosa Ziehau 				break;
709815516c77SSepherosa Ziehau 
709915516c77SSepherosa Ziehau 			case HN_NDIS_PKTINFO_TYPE_HASHINF:
7100a491581fSWei Hu 				if (__predict_false(dlen
7101a491581fSWei Hu 				    < HN_NDIS_HASH_INFO_SIZE))
710215516c77SSepherosa Ziehau 					return (EINVAL);
7103a491581fSWei Hu 				info->hash_info = (const uint32_t *)data;
710415516c77SSepherosa Ziehau 				mask |= HN_RXINFO_HASHINF;
710515516c77SSepherosa Ziehau 				break;
710615516c77SSepherosa Ziehau 
710715516c77SSepherosa Ziehau 			default:
710815516c77SSepherosa Ziehau 				goto next;
710915516c77SSepherosa Ziehau 			}
7110a491581fSWei Hu 		}
711115516c77SSepherosa Ziehau 
711215516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
711315516c77SSepherosa Ziehau 			/* All found; done */
711415516c77SSepherosa Ziehau 			break;
711515516c77SSepherosa Ziehau 		}
711615516c77SSepherosa Ziehau next:
711715516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
711815516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
711915516c77SSepherosa Ziehau 	}
712015516c77SSepherosa Ziehau 
712115516c77SSepherosa Ziehau 	/*
712215516c77SSepherosa Ziehau 	 * Final fixup.
712315516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
712415516c77SSepherosa Ziehau 	 */
712515516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
7126a491581fSWei Hu 		info->hash_info = NULL;
712715516c77SSepherosa Ziehau 	return (0);
712815516c77SSepherosa Ziehau }
712915516c77SSepherosa Ziehau 
713015516c77SSepherosa Ziehau static __inline bool
hn_rndis_check_overlap(int off,int len,int check_off,int check_len)713115516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
713215516c77SSepherosa Ziehau {
713315516c77SSepherosa Ziehau 
713415516c77SSepherosa Ziehau 	if (off < check_off) {
713515516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
713615516c77SSepherosa Ziehau 			return (false);
713715516c77SSepherosa Ziehau 	} else if (off > check_off) {
713815516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
713915516c77SSepherosa Ziehau 			return (false);
714015516c77SSepherosa Ziehau 	}
714115516c77SSepherosa Ziehau 	return (true);
714215516c77SSepherosa Ziehau }
714315516c77SSepherosa Ziehau 
7144a491581fSWei Hu static __inline void
hn_rsc_add_data(struct hn_rx_ring * rxr,const void * data,uint32_t len,struct hn_rxinfo * info)7145a491581fSWei Hu hn_rsc_add_data(struct hn_rx_ring *rxr, const void *data,
7146a491581fSWei Hu 		uint32_t len, struct hn_rxinfo *info)
7147a491581fSWei Hu {
7148a491581fSWei Hu 	uint32_t cnt = rxr->rsc.cnt;
7149a491581fSWei Hu 
7150a491581fSWei Hu 	if (cnt) {
7151a491581fSWei Hu 		rxr->rsc.pktlen += len;
7152a491581fSWei Hu 	} else {
7153a491581fSWei Hu 		rxr->rsc.vlan_info = info->vlan_info;
7154a491581fSWei Hu 		rxr->rsc.csum_info = info->csum_info;
7155a491581fSWei Hu 		rxr->rsc.hash_info = info->hash_info;
7156a491581fSWei Hu 		rxr->rsc.hash_value = info->hash_value;
7157a491581fSWei Hu 		rxr->rsc.pktlen = len;
7158a491581fSWei Hu 	}
7159a491581fSWei Hu 
7160a491581fSWei Hu 	rxr->rsc.frag_data[cnt] = data;
7161a491581fSWei Hu 	rxr->rsc.frag_len[cnt] = len;
7162a491581fSWei Hu 	rxr->rsc.cnt++;
7163a491581fSWei Hu }
7164a491581fSWei Hu 
716515516c77SSepherosa Ziehau static void
hn_rndis_rx_data(struct hn_rx_ring * rxr,const void * data,int dlen)716615516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
716715516c77SSepherosa Ziehau {
716815516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
716915516c77SSepherosa Ziehau 	struct hn_rxinfo info;
717015516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
7171a491581fSWei Hu 	bool rsc_more= false;
717215516c77SSepherosa Ziehau 
717315516c77SSepherosa Ziehau 	/*
717415516c77SSepherosa Ziehau 	 * Check length.
717515516c77SSepherosa Ziehau 	 */
717615516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
717715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
717815516c77SSepherosa Ziehau 		return;
717915516c77SSepherosa Ziehau 	}
718015516c77SSepherosa Ziehau 	pkt = data;
718115516c77SSepherosa Ziehau 
718215516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
718315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
718415516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
718515516c77SSepherosa Ziehau 		return;
718615516c77SSepherosa Ziehau 	}
718715516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
718815516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
718915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
719015516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
719115516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
719215516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
719315516c77SSepherosa Ziehau 		return;
719415516c77SSepherosa Ziehau 	}
719515516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
719615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
719715516c77SSepherosa Ziehau 		return;
719815516c77SSepherosa Ziehau 	}
719915516c77SSepherosa Ziehau 
720015516c77SSepherosa Ziehau 	/*
720115516c77SSepherosa Ziehau 	 * Check offests.
720215516c77SSepherosa Ziehau 	 */
720315516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
720415516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
720515516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
720615516c77SSepherosa Ziehau 
720715516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
720815516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
720915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
721015516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
721115516c77SSepherosa Ziehau 		return;
721215516c77SSepherosa Ziehau 	}
721315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
721415516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
721515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
721615516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
721715516c77SSepherosa Ziehau 		return;
721815516c77SSepherosa Ziehau 	}
721915516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
722015516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
722115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
722215516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
722315516c77SSepherosa Ziehau 		return;
722415516c77SSepherosa Ziehau 	}
722515516c77SSepherosa Ziehau 
722615516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
722715516c77SSepherosa Ziehau 
722815516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
722915516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
723015516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
723115516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
723215516c77SSepherosa Ziehau 
723315516c77SSepherosa Ziehau 	/*
723415516c77SSepherosa Ziehau 	 * Check OOB coverage.
723515516c77SSepherosa Ziehau 	 */
723615516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
723715516c77SSepherosa Ziehau 		int oob_off, oob_len;
723815516c77SSepherosa Ziehau 
723915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
724015516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
724115516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
724215516c77SSepherosa Ziehau 
724315516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
724415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
724515516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
724615516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
724715516c77SSepherosa Ziehau 			return;
724815516c77SSepherosa Ziehau 		}
724915516c77SSepherosa Ziehau 
725015516c77SSepherosa Ziehau 		/*
725115516c77SSepherosa Ziehau 		 * Check against data.
725215516c77SSepherosa Ziehau 		 */
725315516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
725415516c77SSepherosa Ziehau 		    data_off, data_len)) {
725515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
725615516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
725715516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
725815516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
725915516c77SSepherosa Ziehau 			return;
726015516c77SSepherosa Ziehau 		}
726115516c77SSepherosa Ziehau 
726215516c77SSepherosa Ziehau 		/*
726315516c77SSepherosa Ziehau 		 * Check against pktinfo.
726415516c77SSepherosa Ziehau 		 */
726515516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
726615516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
726715516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
726815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
726915516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
727015516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
727115516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
727215516c77SSepherosa Ziehau 			return;
727315516c77SSepherosa Ziehau 		}
727415516c77SSepherosa Ziehau 	}
727515516c77SSepherosa Ziehau 
727615516c77SSepherosa Ziehau 	/*
727715516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
727815516c77SSepherosa Ziehau 	 */
7279a491581fSWei Hu 	info.vlan_info = NULL;
7280a491581fSWei Hu 	info.csum_info = NULL;
7281a491581fSWei Hu 	info.hash_info = NULL;
7282a491581fSWei Hu 	info.pktinfo_id = NULL;
7283a491581fSWei Hu 
728415516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
728515516c77SSepherosa Ziehau 		bool overlap;
728615516c77SSepherosa Ziehau 		int error;
728715516c77SSepherosa Ziehau 
728815516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
728915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
729015516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
729115516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
729215516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
729315516c77SSepherosa Ziehau 			return;
729415516c77SSepherosa Ziehau 		}
729515516c77SSepherosa Ziehau 
729615516c77SSepherosa Ziehau 		/*
729715516c77SSepherosa Ziehau 		 * Check packet info coverage.
729815516c77SSepherosa Ziehau 		 */
729915516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
730015516c77SSepherosa Ziehau 		    data_off, data_len);
730115516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
730215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
730315516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
730415516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
730515516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
730615516c77SSepherosa Ziehau 			return;
730715516c77SSepherosa Ziehau 		}
730815516c77SSepherosa Ziehau 
730915516c77SSepherosa Ziehau 		/*
731015516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
731115516c77SSepherosa Ziehau 		 */
731215516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
731315516c77SSepherosa Ziehau 		    pktinfo_len, &info);
731415516c77SSepherosa Ziehau 		if (__predict_false(error)) {
731515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
731615516c77SSepherosa Ziehau 			    "pktinfo\n");
731715516c77SSepherosa Ziehau 			return;
731815516c77SSepherosa Ziehau 		}
731915516c77SSepherosa Ziehau 	}
732015516c77SSepherosa Ziehau 
732115516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
732215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
732315516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
732415516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
732515516c77SSepherosa Ziehau 		return;
732615516c77SSepherosa Ziehau 	}
7327a491581fSWei Hu 
7328a491581fSWei Hu 	/* Identify RSC fragments, drop invalid packets */
7329a491581fSWei Hu 	if ((info.pktinfo_id != NULL) &&
7330a491581fSWei Hu 	    (info.pktinfo_id->flag & HN_NDIS_PKTINFO_SUBALLOC)) {
7331a491581fSWei Hu 		if (info.pktinfo_id->flag & HN_NDIS_PKTINFO_1ST_FRAG) {
7332a491581fSWei Hu 			rxr->rsc.cnt = 0;
7333a491581fSWei Hu 			rxr->hn_rsc_pkts++;
7334a491581fSWei Hu 		} else if (rxr->rsc.cnt == 0)
7335a491581fSWei Hu 			goto drop;
7336a491581fSWei Hu 
7337a491581fSWei Hu 		rsc_more = true;
7338a491581fSWei Hu 
7339a491581fSWei Hu 		if (info.pktinfo_id->flag & HN_NDIS_PKTINFO_LAST_FRAG)
7340a491581fSWei Hu 			rsc_more = false;
7341a491581fSWei Hu 
7342a491581fSWei Hu 		if (rsc_more && rxr->rsc.is_last)
7343a491581fSWei Hu 			goto drop;
7344a491581fSWei Hu 	} else {
7345a491581fSWei Hu 		rxr->rsc.cnt = 0;
7346a491581fSWei Hu 	}
7347a491581fSWei Hu 
7348a491581fSWei Hu 	if (__predict_false(rxr->rsc.cnt >= HN_NVS_RSC_MAX))
7349a491581fSWei Hu 		goto drop;
7350a491581fSWei Hu 
7351a491581fSWei Hu 	/* Store data in per rx ring structure */
7352a491581fSWei Hu 	hn_rsc_add_data(rxr,((const uint8_t *)pkt) + data_off,
7353a491581fSWei Hu 	    data_len, &info);
7354a491581fSWei Hu 
7355a491581fSWei Hu 	if (rsc_more)
7356a491581fSWei Hu 		return;
7357a491581fSWei Hu 
7358a491581fSWei Hu 	hn_rxpkt(rxr);
7359a491581fSWei Hu 	rxr->rsc.cnt = 0;
7360a491581fSWei Hu 	return;
7361a491581fSWei Hu drop:
7362a491581fSWei Hu 	rxr->hn_rsc_drop++;
7363a491581fSWei Hu 	return;
736415516c77SSepherosa Ziehau }
736515516c77SSepherosa Ziehau 
736615516c77SSepherosa Ziehau static __inline void
hn_rndis_rxpkt(struct hn_rx_ring * rxr,const void * data,int dlen)736715516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
736815516c77SSepherosa Ziehau {
736915516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
737015516c77SSepherosa Ziehau 
737115516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
737215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
737315516c77SSepherosa Ziehau 		return;
737415516c77SSepherosa Ziehau 	}
737515516c77SSepherosa Ziehau 	hdr = data;
737615516c77SSepherosa Ziehau 
737715516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
737815516c77SSepherosa Ziehau 		/* Hot data path. */
737915516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
738015516c77SSepherosa Ziehau 		/* Done! */
738115516c77SSepherosa Ziehau 		return;
738215516c77SSepherosa Ziehau 	}
738315516c77SSepherosa Ziehau 
738415516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
73854db5958aSJustin Hibbits 		hn_rndis_rx_status(if_getsoftc(rxr->hn_ifp), data, dlen);
738615516c77SSepherosa Ziehau 	else
73874db5958aSJustin Hibbits 		hn_rndis_rx_ctrl(if_getsoftc(rxr->hn_ifp), data, dlen);
738815516c77SSepherosa Ziehau }
738915516c77SSepherosa Ziehau 
739015516c77SSepherosa Ziehau static void
hn_nvs_handle_notify(struct hn_softc * sc,const struct vmbus_chanpkt_hdr * pkt)739115516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
739215516c77SSepherosa Ziehau {
739315516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
739415516c77SSepherosa Ziehau 
739515516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
739615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
739715516c77SSepherosa Ziehau 		return;
739815516c77SSepherosa Ziehau 	}
739915516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
740015516c77SSepherosa Ziehau 
740115516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
740215516c77SSepherosa Ziehau 		/* Useless; ignore */
740315516c77SSepherosa Ziehau 		return;
740415516c77SSepherosa Ziehau 	}
740515516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
740615516c77SSepherosa Ziehau }
740715516c77SSepherosa Ziehau 
740815516c77SSepherosa Ziehau static void
hn_nvs_handle_comp(struct hn_softc * sc,struct vmbus_channel * chan,const struct vmbus_chanpkt_hdr * pkt)740915516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
741015516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
741115516c77SSepherosa Ziehau {
741215516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
741315516c77SSepherosa Ziehau 
741415516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
741515516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
741615516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
741715516c77SSepherosa Ziehau 	/*
741815516c77SSepherosa Ziehau 	 * NOTE:
741915516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
742015516c77SSepherosa Ziehau 	 * its callback.
742115516c77SSepherosa Ziehau 	 */
742215516c77SSepherosa Ziehau }
742315516c77SSepherosa Ziehau 
742415516c77SSepherosa Ziehau static void
hn_nvs_handle_rxbuf(struct hn_rx_ring * rxr,struct vmbus_channel * chan,const struct vmbus_chanpkt_hdr * pkthdr)742515516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
742615516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
742715516c77SSepherosa Ziehau {
742826d79d40SMichael Tuexen 	struct epoch_tracker et;
742915516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
743015516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
743115516c77SSepherosa Ziehau 	int count, i, hlen;
743215516c77SSepherosa Ziehau 
743315516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
743415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
743515516c77SSepherosa Ziehau 		return;
743615516c77SSepherosa Ziehau 	}
743715516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
743815516c77SSepherosa Ziehau 
743915516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
744015516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
744115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
744215516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
744315516c77SSepherosa Ziehau 		return;
744415516c77SSepherosa Ziehau 	}
744515516c77SSepherosa Ziehau 
744615516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
744715516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
744815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
744915516c77SSepherosa Ziehau 		return;
745015516c77SSepherosa Ziehau 	}
745115516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
745215516c77SSepherosa Ziehau 
745315516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
745415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
745515516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
745615516c77SSepherosa Ziehau 		return;
745715516c77SSepherosa Ziehau 	}
745815516c77SSepherosa Ziehau 
745915516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
746015516c77SSepherosa Ziehau 	if (__predict_false(hlen <
746115516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
746215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
746315516c77SSepherosa Ziehau 		return;
746415516c77SSepherosa Ziehau 	}
746515516c77SSepherosa Ziehau 
746626d79d40SMichael Tuexen 	NET_EPOCH_ENTER(et);
746715516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
746815516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
746915516c77SSepherosa Ziehau 		int ofs, len;
747015516c77SSepherosa Ziehau 
747115516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
747215516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
747315516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
747415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
747515516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
747615516c77SSepherosa Ziehau 			continue;
747715516c77SSepherosa Ziehau 		}
7478a491581fSWei Hu 
7479a491581fSWei Hu 		rxr->rsc.is_last = (i == (count - 1));
748015516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
748115516c77SSepherosa Ziehau 	}
748226d79d40SMichael Tuexen 	NET_EPOCH_EXIT(et);
748315516c77SSepherosa Ziehau 
748415516c77SSepherosa Ziehau 	/*
748515516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
748615516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
748715516c77SSepherosa Ziehau 	 */
748815516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
748915516c77SSepherosa Ziehau }
749015516c77SSepherosa Ziehau 
749115516c77SSepherosa Ziehau static void
hn_nvs_ack_rxbuf(struct hn_rx_ring * rxr,struct vmbus_channel * chan,uint64_t tid)749215516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
749315516c77SSepherosa Ziehau     uint64_t tid)
749415516c77SSepherosa Ziehau {
749515516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
749615516c77SSepherosa Ziehau 	int retries, error;
749715516c77SSepherosa Ziehau 
749815516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
749915516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
750015516c77SSepherosa Ziehau 
750115516c77SSepherosa Ziehau 	retries = 0;
750215516c77SSepherosa Ziehau again:
750315516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
750415516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
750515516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
750615516c77SSepherosa Ziehau 		/*
750715516c77SSepherosa Ziehau 		 * NOTE:
750815516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
750915516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
751015516c77SSepherosa Ziehau 		 * controlled.
751115516c77SSepherosa Ziehau 		 */
751215516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
751315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
751415516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
751515516c77SSepherosa Ziehau 		retries++;
751615516c77SSepherosa Ziehau 		if (retries < 10) {
751715516c77SSepherosa Ziehau 			DELAY(100);
751815516c77SSepherosa Ziehau 			goto again;
751915516c77SSepherosa Ziehau 		}
752015516c77SSepherosa Ziehau 		/* RXBUF leaks! */
752115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
752215516c77SSepherosa Ziehau 	}
752315516c77SSepherosa Ziehau }
752415516c77SSepherosa Ziehau 
752515516c77SSepherosa Ziehau static void
hn_chan_callback(struct vmbus_channel * chan,void * xrxr)752615516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
752715516c77SSepherosa Ziehau {
752815516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
75294db5958aSJustin Hibbits 	struct hn_softc *sc = if_getsoftc(rxr->hn_ifp);
753015516c77SSepherosa Ziehau 
753115516c77SSepherosa Ziehau 	for (;;) {
753215516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
753315516c77SSepherosa Ziehau 		int error, pktlen;
753415516c77SSepherosa Ziehau 
753515516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
753615516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
753715516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
753815516c77SSepherosa Ziehau 			void *nbuf;
753915516c77SSepherosa Ziehau 			int nlen;
754015516c77SSepherosa Ziehau 
754115516c77SSepherosa Ziehau 			/*
754215516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
754315516c77SSepherosa Ziehau 			 *
754415516c77SSepherosa Ziehau 			 * XXX
754515516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
754615516c77SSepherosa Ziehau 			 * is fatal.
754715516c77SSepherosa Ziehau 			 */
754815516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
754915516c77SSepherosa Ziehau 			while (nlen < pktlen)
755015516c77SSepherosa Ziehau 				nlen *= 2;
755115516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
755215516c77SSepherosa Ziehau 
755315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
755415516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
755515516c77SSepherosa Ziehau 
755615516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
755715516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
755815516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
755915516c77SSepherosa Ziehau 			/* Retry! */
756015516c77SSepherosa Ziehau 			continue;
756115516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
756215516c77SSepherosa Ziehau 			/* No more channel packets; done! */
756315516c77SSepherosa Ziehau 			break;
756415516c77SSepherosa Ziehau 		}
756515516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
756615516c77SSepherosa Ziehau 
756715516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
756815516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
756915516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
757015516c77SSepherosa Ziehau 			break;
757115516c77SSepherosa Ziehau 
757215516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
757315516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
757415516c77SSepherosa Ziehau 			break;
757515516c77SSepherosa Ziehau 
757615516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
757715516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
757815516c77SSepherosa Ziehau 			break;
757915516c77SSepherosa Ziehau 
758015516c77SSepherosa Ziehau 		default:
758115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
758215516c77SSepherosa Ziehau 			    pkt->cph_type);
758315516c77SSepherosa Ziehau 			break;
758415516c77SSepherosa Ziehau 		}
758515516c77SSepherosa Ziehau 	}
758615516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
758715516c77SSepherosa Ziehau }
758815516c77SSepherosa Ziehau 
758915516c77SSepherosa Ziehau static void
hn_sysinit(void * arg __unused)7590499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused)
759115516c77SSepherosa Ziehau {
7592fdd0222aSSepherosa Ziehau 	int i;
7593fdd0222aSSepherosa Ziehau 
75942be266caSSepherosa Ziehau 	hn_udpcs_fixup = counter_u64_alloc(M_WAITOK);
75952be266caSSepherosa Ziehau 
75969c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
75979c6cae24SSepherosa Ziehau 	/*
75989c6cae24SSepherosa Ziehau 	 * Don't use ifnet.if_start if transparent VF mode is requested;
75999c6cae24SSepherosa Ziehau 	 * mainly due to the IFF_DRV_OACTIVE flag.
76009c6cae24SSepherosa Ziehau 	 */
76019c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_use_if_start) {
76029c6cae24SSepherosa Ziehau 		hn_use_if_start = 0;
76039c6cae24SSepherosa Ziehau 		printf("hn: tranparent VF mode, if_transmit will be used, "
76049c6cae24SSepherosa Ziehau 		    "instead of if_start\n");
76059c6cae24SSepherosa Ziehau 	}
76069c6cae24SSepherosa Ziehau #endif
76079c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) {
76089c6cae24SSepherosa Ziehau 		printf("hn: invalid transparent VF attach routing "
76099c6cae24SSepherosa Ziehau 		    "wait timeout %d, reset to %d\n",
76109c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN);
76119c6cae24SSepherosa Ziehau 		hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
76129c6cae24SSepherosa Ziehau 	}
76139c6cae24SSepherosa Ziehau 
7614fdd0222aSSepherosa Ziehau 	/*
7615499c3e17SSepherosa Ziehau 	 * Initialize VF map.
7616499c3e17SSepherosa Ziehau 	 */
7617499c3e17SSepherosa Ziehau 	rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE);
7618499c3e17SSepherosa Ziehau 	hn_vfmap_size = HN_VFMAP_SIZE_DEF;
76194db5958aSJustin Hibbits 	hn_vfmap = malloc(sizeof(if_t) * hn_vfmap_size, M_DEVBUF,
7620499c3e17SSepherosa Ziehau 	    M_WAITOK | M_ZERO);
7621499c3e17SSepherosa Ziehau 
7622499c3e17SSepherosa Ziehau 	/*
7623fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
7624fdd0222aSSepherosa Ziehau 	 */
7625fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
7626fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
7627fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
7628fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
762915516c77SSepherosa Ziehau 
76300e11868dSSepherosa Ziehau 	/*
76310e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
76320e11868dSSepherosa Ziehau 	 */
76330e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
76340e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
76350e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
76360e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
76370e11868dSSepherosa Ziehau 		break;
76380e11868dSSepherosa Ziehau 	default:
76390e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
76400e11868dSSepherosa Ziehau 		break;
76410e11868dSSepherosa Ziehau 	}
76420e11868dSSepherosa Ziehau 
764315516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
764415516c77SSepherosa Ziehau 		return;
764515516c77SSepherosa Ziehau 
76460e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
764715516c77SSepherosa Ziehau 		return;
764815516c77SSepherosa Ziehau 
7649fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
7650fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
7651fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
7652fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
7653fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
7654fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
7655fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
7656fdd0222aSSepherosa Ziehau 	}
765715516c77SSepherosa Ziehau }
7658499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL);
765915516c77SSepherosa Ziehau 
766015516c77SSepherosa Ziehau static void
hn_sysuninit(void * arg __unused)7661499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused)
766215516c77SSepherosa Ziehau {
766315516c77SSepherosa Ziehau 
7664fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
7665fdd0222aSSepherosa Ziehau 		int i;
7666fdd0222aSSepherosa Ziehau 
7667fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
7668fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
7669fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
7670fdd0222aSSepherosa Ziehau 	}
7671499c3e17SSepherosa Ziehau 
7672499c3e17SSepherosa Ziehau 	if (hn_vfmap != NULL)
7673499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
7674499c3e17SSepherosa Ziehau 	rm_destroy(&hn_vfmap_lock);
76752be266caSSepherosa Ziehau 
76762be266caSSepherosa Ziehau 	counter_u64_free(hn_udpcs_fixup);
767715516c77SSepherosa Ziehau }
7678499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL);
7679