xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision 9c6cae24315a3d73cbdb275729b31d90626c2989)
115516c77SSepherosa Ziehau /*-
215516c77SSepherosa Ziehau  * Copyright (c) 2010-2012 Citrix Inc.
315516c77SSepherosa Ziehau  * Copyright (c) 2009-2012,2016 Microsoft Corp.
415516c77SSepherosa Ziehau  * Copyright (c) 2012 NetApp Inc.
515516c77SSepherosa Ziehau  * All rights reserved.
615516c77SSepherosa Ziehau  *
715516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
815516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
915516c77SSepherosa Ziehau  * are met:
1015516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
1115516c77SSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
1215516c77SSepherosa Ziehau  *    disclaimer.
1315516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
1415516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
1515516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
1615516c77SSepherosa Ziehau  *
1715516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1815516c77SSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1915516c77SSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2015516c77SSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2115516c77SSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2215516c77SSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2315516c77SSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2415516c77SSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2515516c77SSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2615516c77SSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2715516c77SSepherosa Ziehau  */
2815516c77SSepherosa Ziehau 
2915516c77SSepherosa Ziehau /*-
3015516c77SSepherosa Ziehau  * Copyright (c) 2004-2006 Kip Macy
3115516c77SSepherosa Ziehau  * All rights reserved.
3215516c77SSepherosa Ziehau  *
3315516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
3415516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
3515516c77SSepherosa Ziehau  * are met:
3615516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
3715516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
3815516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
3915516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
4015516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
4115516c77SSepherosa Ziehau  *
4215516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4315516c77SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4415516c77SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4515516c77SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4615516c77SSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4715516c77SSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4815516c77SSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4915516c77SSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5015516c77SSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5115516c77SSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5215516c77SSepherosa Ziehau  * SUCH DAMAGE.
5315516c77SSepherosa Ziehau  */
5415516c77SSepherosa Ziehau 
5515516c77SSepherosa Ziehau #include <sys/cdefs.h>
5615516c77SSepherosa Ziehau __FBSDID("$FreeBSD$");
5715516c77SSepherosa Ziehau 
5834d68912SSepherosa Ziehau #include "opt_hn.h"
5915516c77SSepherosa Ziehau #include "opt_inet6.h"
6015516c77SSepherosa Ziehau #include "opt_inet.h"
6134d68912SSepherosa Ziehau #include "opt_rss.h"
6215516c77SSepherosa Ziehau 
6315516c77SSepherosa Ziehau #include <sys/param.h>
6415516c77SSepherosa Ziehau #include <sys/bus.h>
6515516c77SSepherosa Ziehau #include <sys/kernel.h>
6615516c77SSepherosa Ziehau #include <sys/limits.h>
6715516c77SSepherosa Ziehau #include <sys/malloc.h>
6815516c77SSepherosa Ziehau #include <sys/mbuf.h>
6915516c77SSepherosa Ziehau #include <sys/module.h>
7015516c77SSepherosa Ziehau #include <sys/queue.h>
7115516c77SSepherosa Ziehau #include <sys/lock.h>
72499c3e17SSepherosa Ziehau #include <sys/rmlock.h>
73499c3e17SSepherosa Ziehau #include <sys/sbuf.h>
7415516c77SSepherosa Ziehau #include <sys/smp.h>
7515516c77SSepherosa Ziehau #include <sys/socket.h>
7615516c77SSepherosa Ziehau #include <sys/sockio.h>
7715516c77SSepherosa Ziehau #include <sys/sx.h>
7815516c77SSepherosa Ziehau #include <sys/sysctl.h>
7915516c77SSepherosa Ziehau #include <sys/systm.h>
8015516c77SSepherosa Ziehau #include <sys/taskqueue.h>
8115516c77SSepherosa Ziehau #include <sys/buf_ring.h>
825bdfd3fdSDexuan Cui #include <sys/eventhandler.h>
8315516c77SSepherosa Ziehau 
8415516c77SSepherosa Ziehau #include <machine/atomic.h>
8515516c77SSepherosa Ziehau #include <machine/in_cksum.h>
8615516c77SSepherosa Ziehau 
8715516c77SSepherosa Ziehau #include <net/bpf.h>
8815516c77SSepherosa Ziehau #include <net/ethernet.h>
8915516c77SSepherosa Ziehau #include <net/if.h>
905bdfd3fdSDexuan Cui #include <net/if_dl.h>
9115516c77SSepherosa Ziehau #include <net/if_media.h>
9215516c77SSepherosa Ziehau #include <net/if_types.h>
9315516c77SSepherosa Ziehau #include <net/if_var.h>
9415516c77SSepherosa Ziehau #include <net/rndis.h>
9534d68912SSepherosa Ziehau #ifdef RSS
9634d68912SSepherosa Ziehau #include <net/rss_config.h>
9734d68912SSepherosa Ziehau #endif
9815516c77SSepherosa Ziehau 
9915516c77SSepherosa Ziehau #include <netinet/in_systm.h>
10015516c77SSepherosa Ziehau #include <netinet/in.h>
10115516c77SSepherosa Ziehau #include <netinet/ip.h>
10215516c77SSepherosa Ziehau #include <netinet/ip6.h>
10315516c77SSepherosa Ziehau #include <netinet/tcp.h>
10415516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
10515516c77SSepherosa Ziehau #include <netinet/udp.h>
10615516c77SSepherosa Ziehau 
10715516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
10815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
10915516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
11015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
11115516c77SSepherosa Ziehau 
11215516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
11315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
11415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
11515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
11615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
11715516c77SSepherosa Ziehau 
11815516c77SSepherosa Ziehau #include "vmbus_if.h"
11915516c77SSepherosa Ziehau 
12023bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
12123bf9e15SSepherosa Ziehau 
12215516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
12315516c77SSepherosa Ziehau 
124499c3e17SSepherosa Ziehau #define HN_VFMAP_SIZE_DEF		8
125499c3e17SSepherosa Ziehau 
126*9c6cae24SSepherosa Ziehau #define HN_XPNT_VF_ATTWAIT_MIN		2	/* seconds */
127*9c6cae24SSepherosa Ziehau 
12815516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
12915516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
13015516c77SSepherosa Ziehau 
13115516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
13215516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
13315516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
13415516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
13515516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
13615516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
13715516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
13815516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
13915516c77SSepherosa Ziehau 
14015516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
14115516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
14215516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
14315516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
14415516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
14515516c77SSepherosa Ziehau 
14615516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
14715516c77SSepherosa Ziehau 
14815516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
14915516c77SSepherosa Ziehau 
15015516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
15115516c77SSepherosa Ziehau 
15215516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
15315516c77SSepherosa Ziehau 
15415516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
15515516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
15615516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
15715516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
15815516c77SSepherosa Ziehau 
15915516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
16015516c77SSepherosa Ziehau 
16115516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
16215516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
16315516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
16415516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
165fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
166fdc4f478SSepherosa Ziehau do {							\
167fdc4f478SSepherosa Ziehau 	while (sx_try_xlock(&(sc)->hn_lock) == 0)	\
168fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
169fdc4f478SSepherosa Ziehau } while (0)
17015516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
17115516c77SSepherosa Ziehau 
17215516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
17315516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
17415516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
17515516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
17615516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
17715516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
17815516c77SSepherosa Ziehau 
179dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
180dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
181dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
182dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
183dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
184dc13fee6SSepherosa Ziehau 
18534d68912SSepherosa Ziehau #ifdef RSS
18634d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	rss_getcpu((idx) % rss_getnumbuckets())
18734d68912SSepherosa Ziehau #else
1880e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	(((sc)->hn_cpu + (idx)) % mp_ncpus)
18934d68912SSepherosa Ziehau #endif
1900e11868dSSepherosa Ziehau 
19115516c77SSepherosa Ziehau struct hn_txdesc {
19215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
19315516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
19415516c77SSepherosa Ziehau #endif
195dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
196dc13fee6SSepherosa Ziehau 
197dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
198dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
199dc13fee6SSepherosa Ziehau 
200dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
20115516c77SSepherosa Ziehau 	struct mbuf			*m;
20215516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
20315516c77SSepherosa Ziehau 	int				refs;
20415516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
20515516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
20615516c77SSepherosa Ziehau 	uint32_t			chim_index;
20715516c77SSepherosa Ziehau 	int				chim_size;
20815516c77SSepherosa Ziehau 
20915516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
21015516c77SSepherosa Ziehau 
21115516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
21215516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
21315516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
21415516c77SSepherosa Ziehau };
21515516c77SSepherosa Ziehau 
21615516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
21715516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
218dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
21915516c77SSepherosa Ziehau 
22015516c77SSepherosa Ziehau struct hn_rxinfo {
22115516c77SSepherosa Ziehau 	uint32_t			vlan_info;
22215516c77SSepherosa Ziehau 	uint32_t			csum_info;
22315516c77SSepherosa Ziehau 	uint32_t			hash_info;
22415516c77SSepherosa Ziehau 	uint32_t			hash_value;
22515516c77SSepherosa Ziehau };
22615516c77SSepherosa Ziehau 
227962f0357SSepherosa Ziehau struct hn_rxvf_setarg {
2285bdfd3fdSDexuan Cui 	struct hn_rx_ring	*rxr;
229962f0357SSepherosa Ziehau 	struct ifnet		*vf_ifp;
2305bdfd3fdSDexuan Cui };
2315bdfd3fdSDexuan Cui 
23215516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
23315516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
23415516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
23515516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
23615516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
23715516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
23815516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
23915516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
24015516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
24115516c77SSepherosa Ziehau 
24215516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
24315516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
24415516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
24515516c77SSepherosa Ziehau 
24615516c77SSepherosa Ziehau static int			hn_probe(device_t);
24715516c77SSepherosa Ziehau static int			hn_attach(device_t);
24815516c77SSepherosa Ziehau static int			hn_detach(device_t);
24915516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
25015516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
25115516c77SSepherosa Ziehau 				    void *);
25215516c77SSepherosa Ziehau 
25315516c77SSepherosa Ziehau static void			hn_init(void *);
25415516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
25523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
25615516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
25723bf9e15SSepherosa Ziehau #endif
25815516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
25915516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
26015516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
26115516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
26215516c77SSepherosa Ziehau 				    struct ifmediareq *);
26315516c77SSepherosa Ziehau 
264499c3e17SSepherosa Ziehau static void			hn_ifnet_event(void *, struct ifnet *, int);
265499c3e17SSepherosa Ziehau static void			hn_ifaddr_event(void *, struct ifnet *);
266499c3e17SSepherosa Ziehau static void			hn_ifnet_attevent(void *, struct ifnet *);
267499c3e17SSepherosa Ziehau static void			hn_ifnet_detevent(void *, struct ifnet *);
268*9c6cae24SSepherosa Ziehau static void			hn_ifnet_lnkevent(void *, struct ifnet *, int);
269499c3e17SSepherosa Ziehau 
270962f0357SSepherosa Ziehau static bool			hn_ismyvf(const struct hn_softc *,
271962f0357SSepherosa Ziehau 				    const struct ifnet *);
272962f0357SSepherosa Ziehau static void			hn_rxvf_change(struct hn_softc *,
273962f0357SSepherosa Ziehau 				    struct ifnet *, bool);
274962f0357SSepherosa Ziehau static void			hn_rxvf_set(struct hn_softc *, struct ifnet *);
275962f0357SSepherosa Ziehau static void			hn_rxvf_set_task(void *, int);
276*9c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_input(struct ifnet *, struct mbuf *);
277*9c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetflags(struct hn_softc *);
278*9c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetcaps(struct hn_softc *,
279*9c6cae24SSepherosa Ziehau 				    struct ifreq *);
280*9c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_saveifflags(struct hn_softc *);
281*9c6cae24SSepherosa Ziehau static bool			hn_xpnt_vf_isready(struct hn_softc *);
282*9c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_setready(struct hn_softc *);
283*9c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init_taskfunc(void *, int);
284*9c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init(struct hn_softc *);
285962f0357SSepherosa Ziehau 
28615516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
28715516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
28815516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
28915516c77SSepherosa Ziehau 				    const void *, int);
29015516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
29115516c77SSepherosa Ziehau 				    const void *, int);
292b3b75d9cSSepherosa Ziehau static void			hn_rndis_init_fixat(struct hn_softc *, int);
29315516c77SSepherosa Ziehau 
29415516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
29515516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
29615516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
29715516c77SSepherosa Ziehau 				    struct vmbus_channel *,
29815516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
29915516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
30015516c77SSepherosa Ziehau 				    struct vmbus_channel *,
30115516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
30215516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
30315516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
30415516c77SSepherosa Ziehau 
30515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
30615516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
30715516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
30815516c77SSepherosa Ziehau #endif
30915516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
31015516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
31115516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
31215516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
31315516c77SSepherosa Ziehau #else
31415516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
31515516c77SSepherosa Ziehau #endif
31615516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
31715516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
31815516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
31915516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
32015516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
32115516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
32215516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
32334d68912SSepherosa Ziehau #ifndef RSS
32415516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
32515516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
32634d68912SSepherosa Ziehau #endif
32715516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
328dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
329dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
330dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
331dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
3326c1204dfSSepherosa Ziehau static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
33340d60d6eSDexuan Cui static int			hn_vf_sysctl(SYSCTL_HANDLER_ARGS);
334499c3e17SSepherosa Ziehau static int			hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS);
335499c3e17SSepherosa Ziehau static int			hn_vflist_sysctl(SYSCTL_HANDLER_ARGS);
336499c3e17SSepherosa Ziehau static int			hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS);
337*9c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS);
338*9c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS);
33915516c77SSepherosa Ziehau 
3405bdfd3fdSDexuan Cui static void			hn_stop(struct hn_softc *, bool);
34115516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
34215516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
34315516c77SSepherosa Ziehau 				    struct vmbus_channel *);
34415516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
34515516c77SSepherosa Ziehau 				    struct vmbus_channel *);
34615516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
34715516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
34815516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
34915516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
35015516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
35115516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
35215516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
35315516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
35415516c77SSepherosa Ziehau 				    int *);
3552494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
35615516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
35715516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
35815516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
35915516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
36015516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
36115516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
36215516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
36325641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
36425641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
365b3b75d9cSSepherosa Ziehau static void			hn_disable_rx(struct hn_softc *);
366b3b75d9cSSepherosa Ziehau static void			hn_drain_rxtx(struct hn_softc *, int);
3676c1204dfSSepherosa Ziehau static void			hn_polling(struct hn_softc *, u_int);
3686c1204dfSSepherosa Ziehau static void			hn_chan_polling(struct vmbus_channel *, u_int);
369*9c6cae24SSepherosa Ziehau static void			hn_mtu_change_fixup(struct hn_softc *);
37015516c77SSepherosa Ziehau 
37115516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
37215516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
37315516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
37415516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
37515516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
37615516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
37715516c77SSepherosa Ziehau 
37815516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
37915516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
38015516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
381f1b0a43fSSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *, uint32_t);
382c08f7b2cSSepherosa Ziehau static int			hn_rxfilter_config(struct hn_softc *);
38334d68912SSepherosa Ziehau #ifndef RSS
38415516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
38534d68912SSepherosa Ziehau #endif
386afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
38715516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
38815516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
38915516c77SSepherosa Ziehau 
39015516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
39115516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
39215516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
39315516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
39415516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
39515516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
39625641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
39725641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
398dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
39915516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
40015516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
40115516c77SSepherosa Ziehau 				    struct hn_txdesc *);
40215516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
40315516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
40415516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
40515516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
40615516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
407dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
408dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
409dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
410dc13fee6SSepherosa Ziehau 				    int);
41115516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
41215516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
41315516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
41415516c77SSepherosa Ziehau 				    const void *, int);
41515516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
41615516c77SSepherosa Ziehau 				    struct hn_txdesc *);
41715516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
41815516c77SSepherosa Ziehau 				    struct hn_txdesc *);
41915516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
42015516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
42115516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
42215516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
42323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
42415516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
42515516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
42615516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
42715516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
42823bf9e15SSepherosa Ziehau #endif
42915516c77SSepherosa Ziehau 
43015516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
43115516c77SSepherosa Ziehau     "Hyper-V network interface");
43215516c77SSepherosa Ziehau 
43315516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
43415516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
43515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
43615516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
43715516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
43815516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
43915516c77SSepherosa Ziehau 
44015516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
44115516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
44215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
44315516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
44415516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
44515516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
44615516c77SSepherosa Ziehau 
44715516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
44815516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
44915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
45015516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
45115516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
45215516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
45315516c77SSepherosa Ziehau 
45415516c77SSepherosa Ziehau /* Limit TSO burst size */
45515516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
45615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
45715516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
45815516c77SSepherosa Ziehau 
45915516c77SSepherosa Ziehau /* Limit chimney send size */
46015516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
46115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
46215516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
46315516c77SSepherosa Ziehau 
46415516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
46515516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
46615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
46715516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
46815516c77SSepherosa Ziehau 
46915516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
47015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
47115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
47215516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
47315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
47415516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
47515516c77SSepherosa Ziehau #endif
47615516c77SSepherosa Ziehau #endif
47715516c77SSepherosa Ziehau 
478fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
479fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
480fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
481fdd0222aSSepherosa Ziehau 
4820e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
4830e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
4840e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
4850e11868dSSepherosa Ziehau 
4860e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
4870e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
4880e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
4890e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
4900e11868dSSepherosa Ziehau 
49115516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
49215516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
49315516c77SSepherosa Ziehau #else
49415516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
49515516c77SSepherosa Ziehau #endif
49615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
49715516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
49815516c77SSepherosa Ziehau 
49923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
50015516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
50115516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
50215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
50315516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
50423bf9e15SSepherosa Ziehau #endif
50515516c77SSepherosa Ziehau 
50615516c77SSepherosa Ziehau /* # of channels to use */
50715516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
50815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
50915516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
51015516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
51115516c77SSepherosa Ziehau 
51215516c77SSepherosa Ziehau /* # of transmit rings to use */
51315516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
51415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
51515516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
51615516c77SSepherosa Ziehau 
51715516c77SSepherosa Ziehau /* Software TX ring deptch */
51815516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
51915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
52015516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
52115516c77SSepherosa Ziehau 
52215516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
52315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
52415516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
52515516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
52615516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
52715516c77SSepherosa Ziehau #endif
52815516c77SSepherosa Ziehau 
529dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
530dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
531dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
532dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
533dc13fee6SSepherosa Ziehau 
534dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
535fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
536dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
537dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
538dc13fee6SSepherosa Ziehau 
539499c3e17SSepherosa Ziehau /* VF list */
540499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vflist, CTLFLAG_RD | CTLTYPE_STRING,
541499c3e17SSepherosa Ziehau     0, 0, hn_vflist_sysctl, "A", "VF list");
542499c3e17SSepherosa Ziehau 
543499c3e17SSepherosa Ziehau /* VF mapping */
544499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap, CTLFLAG_RD | CTLTYPE_STRING,
545499c3e17SSepherosa Ziehau     0, 0, hn_vfmap_sysctl, "A", "VF mapping");
546499c3e17SSepherosa Ziehau 
547*9c6cae24SSepherosa Ziehau /* Transparent VF */
548*9c6cae24SSepherosa Ziehau static int			hn_xpnt_vf = 0;
549*9c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_transparent, CTLFLAG_RDTUN,
550*9c6cae24SSepherosa Ziehau     &hn_xpnt_vf, 0, "Transparent VF mod");
551*9c6cae24SSepherosa Ziehau 
552*9c6cae24SSepherosa Ziehau /* Accurate BPF support for Transparent VF */
553*9c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf = 0;
554*9c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_accbpf, CTLFLAG_RDTUN,
555*9c6cae24SSepherosa Ziehau     &hn_xpnt_vf_accbpf, 0, "Accurate BPF for transparent VF");
556*9c6cae24SSepherosa Ziehau 
557*9c6cae24SSepherosa Ziehau /* Extra wait for transparent VF attach routing; unit seconds. */
558*9c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
559*9c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_attwait, CTLFLAG_RWTUN,
560*9c6cae24SSepherosa Ziehau     &hn_xpnt_vf_attwait, 0,
561*9c6cae24SSepherosa Ziehau     "Extra wait for transparent VF attach routing; unit: seconds");
562*9c6cae24SSepherosa Ziehau 
56315516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
564fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
56515516c77SSepherosa Ziehau 
566499c3e17SSepherosa Ziehau static struct rmlock		hn_vfmap_lock;
567499c3e17SSepherosa Ziehau static int			hn_vfmap_size;
568499c3e17SSepherosa Ziehau static struct ifnet		**hn_vfmap;
569499c3e17SSepherosa Ziehau 
57034d68912SSepherosa Ziehau #ifndef RSS
57115516c77SSepherosa Ziehau static const uint8_t
57215516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
57315516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
57415516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
57515516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
57615516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
57715516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
57815516c77SSepherosa Ziehau };
57934d68912SSepherosa Ziehau #endif	/* !RSS */
58015516c77SSepherosa Ziehau 
58115516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
58215516c77SSepherosa Ziehau 	/* Device interface */
58315516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
58415516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
58515516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
58615516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
58715516c77SSepherosa Ziehau 	DEVMETHOD_END
58815516c77SSepherosa Ziehau };
58915516c77SSepherosa Ziehau 
59015516c77SSepherosa Ziehau static driver_t hn_driver = {
59115516c77SSepherosa Ziehau 	"hn",
59215516c77SSepherosa Ziehau 	hn_methods,
59315516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
59415516c77SSepherosa Ziehau };
59515516c77SSepherosa Ziehau 
59615516c77SSepherosa Ziehau static devclass_t hn_devclass;
59715516c77SSepherosa Ziehau 
59815516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
59915516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
60015516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
60115516c77SSepherosa Ziehau 
60215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
60315516c77SSepherosa Ziehau static void
60415516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
60515516c77SSepherosa Ziehau {
60615516c77SSepherosa Ziehau 	int i;
60715516c77SSepherosa Ziehau 
608a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
60915516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
61015516c77SSepherosa Ziehau }
61115516c77SSepherosa Ziehau #endif
61215516c77SSepherosa Ziehau 
61315516c77SSepherosa Ziehau static int
61415516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
61515516c77SSepherosa Ziehau {
61615516c77SSepherosa Ziehau 
61715516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
61815516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
61915516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
62015516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
62115516c77SSepherosa Ziehau }
62215516c77SSepherosa Ziehau 
62315516c77SSepherosa Ziehau static int
62415516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
62515516c77SSepherosa Ziehau {
62615516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
62715516c77SSepherosa Ziehau 
62815516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
62915516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
63015516c77SSepherosa Ziehau 
63115516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
63215516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
63315516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
63415516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
63515516c77SSepherosa Ziehau 
63615516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
63715516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
63815516c77SSepherosa Ziehau }
63915516c77SSepherosa Ziehau 
64015516c77SSepherosa Ziehau static __inline uint32_t
64115516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
64215516c77SSepherosa Ziehau {
64315516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
64415516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
64515516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
64615516c77SSepherosa Ziehau 
64715516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
64815516c77SSepherosa Ziehau 		int idx;
64915516c77SSepherosa Ziehau 
65015516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
65115516c77SSepherosa Ziehau 		if (idx == 0)
65215516c77SSepherosa Ziehau 			continue;
65315516c77SSepherosa Ziehau 
65415516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
65515516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
65615516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
65715516c77SSepherosa Ziehau 
65815516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
65915516c77SSepherosa Ziehau 			continue;
66015516c77SSepherosa Ziehau 
66115516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
66215516c77SSepherosa Ziehau 		break;
66315516c77SSepherosa Ziehau 	}
66415516c77SSepherosa Ziehau 	return (ret);
66515516c77SSepherosa Ziehau }
66615516c77SSepherosa Ziehau 
66715516c77SSepherosa Ziehau static __inline void
66815516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
66915516c77SSepherosa Ziehau {
67015516c77SSepherosa Ziehau 	u_long mask;
67115516c77SSepherosa Ziehau 	uint32_t idx;
67215516c77SSepherosa Ziehau 
67315516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
67415516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
67515516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
67615516c77SSepherosa Ziehau 
67715516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
67815516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
67915516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
68015516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
68115516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
68215516c77SSepherosa Ziehau 
68315516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
68415516c77SSepherosa Ziehau }
68515516c77SSepherosa Ziehau 
686edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
687cc0c6ebcSSepherosa Ziehau 
688cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len)				\
689cc0c6ebcSSepherosa Ziehau do {							\
690cc0c6ebcSSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
691cc0c6ebcSSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
692cc0c6ebcSSepherosa Ziehau 		if ((m) == NULL)			\
693cc0c6ebcSSepherosa Ziehau 			return (NULL);			\
694cc0c6ebcSSepherosa Ziehau 	}						\
695cc0c6ebcSSepherosa Ziehau } while (0)
696cc0c6ebcSSepherosa Ziehau 
697edd3f315SSepherosa Ziehau /*
698edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
699edd3f315SSepherosa Ziehau  */
700edd3f315SSepherosa Ziehau static __inline struct mbuf *
701edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
702edd3f315SSepherosa Ziehau {
703edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
704edd3f315SSepherosa Ziehau 	struct tcphdr *th;
705edd3f315SSepherosa Ziehau 	int ehlen;
706edd3f315SSepherosa Ziehau 
707edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
708edd3f315SSepherosa Ziehau 
709edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
710edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
711edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
712edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
713edd3f315SSepherosa Ziehau 	else
714edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
715edd3f315SSepherosa Ziehau 
716edd3f315SSepherosa Ziehau #ifdef INET
717edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
718edd3f315SSepherosa Ziehau 		struct ip *ip;
719edd3f315SSepherosa Ziehau 		int iphlen;
720edd3f315SSepherosa Ziehau 
721edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
722edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
723edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
724edd3f315SSepherosa Ziehau 
725edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
726edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
727edd3f315SSepherosa Ziehau 
728edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
729edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
730edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
731edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
732edd3f315SSepherosa Ziehau 	}
733edd3f315SSepherosa Ziehau #endif
734edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
735edd3f315SSepherosa Ziehau 	else
736edd3f315SSepherosa Ziehau #endif
737edd3f315SSepherosa Ziehau #ifdef INET6
738edd3f315SSepherosa Ziehau 	{
739edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
740edd3f315SSepherosa Ziehau 
741edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
742edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
743edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
744edd3f315SSepherosa Ziehau 			m_freem(m_head);
745edd3f315SSepherosa Ziehau 			return (NULL);
746edd3f315SSepherosa Ziehau 		}
747edd3f315SSepherosa Ziehau 
748edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
749edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
750edd3f315SSepherosa Ziehau 
751edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
752edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
753edd3f315SSepherosa Ziehau 	}
754edd3f315SSepherosa Ziehau #endif
755edd3f315SSepherosa Ziehau 	return (m_head);
756edd3f315SSepherosa Ziehau 
757edd3f315SSepherosa Ziehau }
758cc0c6ebcSSepherosa Ziehau 
759cc0c6ebcSSepherosa Ziehau /*
760cc0c6ebcSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
761cc0c6ebcSSepherosa Ziehau  */
762cc0c6ebcSSepherosa Ziehau static __inline struct mbuf *
763cc0c6ebcSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
764cc0c6ebcSSepherosa Ziehau {
765cc0c6ebcSSepherosa Ziehau 	const struct ether_vlan_header *evl;
766cc0c6ebcSSepherosa Ziehau 	const struct tcphdr *th;
767cc0c6ebcSSepherosa Ziehau 	int ehlen;
768cc0c6ebcSSepherosa Ziehau 
769cc0c6ebcSSepherosa Ziehau 	*tcpsyn = 0;
770cc0c6ebcSSepherosa Ziehau 
771cc0c6ebcSSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
772cc0c6ebcSSepherosa Ziehau 	evl = mtod(m_head, const struct ether_vlan_header *);
773cc0c6ebcSSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
774cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
775cc0c6ebcSSepherosa Ziehau 	else
776cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
777cc0c6ebcSSepherosa Ziehau 
778cc0c6ebcSSepherosa Ziehau #ifdef INET
779cc0c6ebcSSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TCP) {
780cc0c6ebcSSepherosa Ziehau 		const struct ip *ip;
781cc0c6ebcSSepherosa Ziehau 		int iphlen;
782cc0c6ebcSSepherosa Ziehau 
783cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
784cc0c6ebcSSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
785cc0c6ebcSSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
786cc0c6ebcSSepherosa Ziehau 
787cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
788cc0c6ebcSSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
789cc0c6ebcSSepherosa Ziehau 		if (th->th_flags & TH_SYN)
790cc0c6ebcSSepherosa Ziehau 			*tcpsyn = 1;
791cc0c6ebcSSepherosa Ziehau 	}
792cc0c6ebcSSepherosa Ziehau #endif
793cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET)
794cc0c6ebcSSepherosa Ziehau 	else
795cc0c6ebcSSepherosa Ziehau #endif
796cc0c6ebcSSepherosa Ziehau #ifdef INET6
797cc0c6ebcSSepherosa Ziehau 	{
798cc0c6ebcSSepherosa Ziehau 		const struct ip6_hdr *ip6;
799cc0c6ebcSSepherosa Ziehau 
800cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
801cc0c6ebcSSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
802cc0c6ebcSSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP)
803cc0c6ebcSSepherosa Ziehau 			return (m_head);
804cc0c6ebcSSepherosa Ziehau 
805cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
806cc0c6ebcSSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
807cc0c6ebcSSepherosa Ziehau 		if (th->th_flags & TH_SYN)
808cc0c6ebcSSepherosa Ziehau 			*tcpsyn = 1;
809cc0c6ebcSSepherosa Ziehau 	}
810cc0c6ebcSSepherosa Ziehau #endif
811cc0c6ebcSSepherosa Ziehau 	return (m_head);
812cc0c6ebcSSepherosa Ziehau }
813cc0c6ebcSSepherosa Ziehau 
814cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR
815cc0c6ebcSSepherosa Ziehau 
816edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
817edd3f315SSepherosa Ziehau 
81815516c77SSepherosa Ziehau static int
819f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter)
820f1b0a43fSSepherosa Ziehau {
821f1b0a43fSSepherosa Ziehau 	int error = 0;
822f1b0a43fSSepherosa Ziehau 
823f1b0a43fSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
824f1b0a43fSSepherosa Ziehau 
825f1b0a43fSSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
826f1b0a43fSSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
827f1b0a43fSSepherosa Ziehau 		if (!error)
828f1b0a43fSSepherosa Ziehau 			sc->hn_rx_filter = filter;
829f1b0a43fSSepherosa Ziehau 	}
830f1b0a43fSSepherosa Ziehau 	return (error);
831f1b0a43fSSepherosa Ziehau }
832f1b0a43fSSepherosa Ziehau 
833f1b0a43fSSepherosa Ziehau static int
834c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc)
83515516c77SSepherosa Ziehau {
83615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
83715516c77SSepherosa Ziehau 	uint32_t filter;
83815516c77SSepherosa Ziehau 
83915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
84015516c77SSepherosa Ziehau 
841*9c6cae24SSepherosa Ziehau 	/*
842*9c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, we don't know how
843*9c6cae24SSepherosa Ziehau 	 * its RX filter is configured, so stick the synthetic device in
844*9c6cae24SSepherosa Ziehau 	 * the promiscous mode.
845*9c6cae24SSepherosa Ziehau 	 */
846*9c6cae24SSepherosa Ziehau 	if ((ifp->if_flags & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) {
84715516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
84815516c77SSepherosa Ziehau 	} else {
84915516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
85015516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
85115516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
85215516c77SSepherosa Ziehau 		/* TODO: support multicast list */
85315516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
85415516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
85515516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
85615516c77SSepherosa Ziehau 	}
857f1b0a43fSSepherosa Ziehau 	return (hn_set_rxfilter(sc, filter));
85815516c77SSepherosa Ziehau }
85915516c77SSepherosa Ziehau 
860dc13fee6SSepherosa Ziehau static void
861dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
862dc13fee6SSepherosa Ziehau {
863dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
864dc13fee6SSepherosa Ziehau 	int i;
865dc13fee6SSepherosa Ziehau 
866dc13fee6SSepherosa Ziehau 	/*
867dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
868dc13fee6SSepherosa Ziehau 	 */
869dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
870dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
871dc13fee6SSepherosa Ziehau 	else
872dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
873dc13fee6SSepherosa Ziehau 
874dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
875dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
876dc13fee6SSepherosa Ziehau 
877a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
878a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
879a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
880a4364cfeSSepherosa Ziehau 
881dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
882dc13fee6SSepherosa Ziehau 		/* Disable */
883dc13fee6SSepherosa Ziehau 		size = 0;
884dc13fee6SSepherosa Ziehau 		pkts = 0;
885dc13fee6SSepherosa Ziehau 		goto done;
886dc13fee6SSepherosa Ziehau 	}
887dc13fee6SSepherosa Ziehau 
888dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
889dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
890dc13fee6SSepherosa Ziehau 		size = INT_MAX;
891dc13fee6SSepherosa Ziehau 
892dc13fee6SSepherosa Ziehau 	/*
893dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
894dc13fee6SSepherosa Ziehau 	 */
895dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
896dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
897dc13fee6SSepherosa Ziehau 	else
898dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
899dc13fee6SSepherosa Ziehau 
900dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
901dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
902dc13fee6SSepherosa Ziehau 
903dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
904dc13fee6SSepherosa Ziehau 		/* Disable */
905dc13fee6SSepherosa Ziehau 		size = 0;
906dc13fee6SSepherosa Ziehau 		pkts = 0;
907dc13fee6SSepherosa Ziehau 		goto done;
908dc13fee6SSepherosa Ziehau 	}
909dc13fee6SSepherosa Ziehau 
910dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
911dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
912dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
913dc13fee6SSepherosa Ziehau 
914dc13fee6SSepherosa Ziehau done:
915dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
916dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
917dc13fee6SSepherosa Ziehau 		/* Disable */
918dc13fee6SSepherosa Ziehau 		size = 0;
919dc13fee6SSepherosa Ziehau 		pkts = 0;
920dc13fee6SSepherosa Ziehau 	}
921dc13fee6SSepherosa Ziehau 
922dc13fee6SSepherosa Ziehau 	if (bootverbose) {
923dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
924dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
925dc13fee6SSepherosa Ziehau 	}
926dc13fee6SSepherosa Ziehau 
927dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
928dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
929dc13fee6SSepherosa Ziehau 
930dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
931dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
932dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
933dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
934dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
935dc13fee6SSepherosa Ziehau 	}
936dc13fee6SSepherosa Ziehau }
937dc13fee6SSepherosa Ziehau 
93815516c77SSepherosa Ziehau static int
93915516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
94015516c77SSepherosa Ziehau {
94115516c77SSepherosa Ziehau 
94215516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
94315516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
94415516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
94515516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
94615516c77SSepherosa Ziehau }
94715516c77SSepherosa Ziehau 
94834d68912SSepherosa Ziehau #ifndef RSS
94915516c77SSepherosa Ziehau static int
95015516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
95115516c77SSepherosa Ziehau {
95215516c77SSepherosa Ziehau 	int error;
95315516c77SSepherosa Ziehau 
95415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
95515516c77SSepherosa Ziehau 
95615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
95715516c77SSepherosa Ziehau 		return (ENXIO);
95815516c77SSepherosa Ziehau 
95915516c77SSepherosa Ziehau 	/*
96015516c77SSepherosa Ziehau 	 * Disable RSS first.
96115516c77SSepherosa Ziehau 	 *
96215516c77SSepherosa Ziehau 	 * NOTE:
96315516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
96415516c77SSepherosa Ziehau 	 * _not_ work properly.
96515516c77SSepherosa Ziehau 	 */
96615516c77SSepherosa Ziehau 	if (bootverbose)
96715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
96815516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
96915516c77SSepherosa Ziehau 	if (error) {
97015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
97115516c77SSepherosa Ziehau 		return (error);
97215516c77SSepherosa Ziehau 	}
97315516c77SSepherosa Ziehau 
97415516c77SSepherosa Ziehau 	/*
97515516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
97615516c77SSepherosa Ziehau 	 * table.
97715516c77SSepherosa Ziehau 	 */
97815516c77SSepherosa Ziehau 	if (bootverbose)
97915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
98015516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
98115516c77SSepherosa Ziehau 	if (error) {
98215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
98315516c77SSepherosa Ziehau 		return (error);
98415516c77SSepherosa Ziehau 	}
98515516c77SSepherosa Ziehau 	return (0);
98615516c77SSepherosa Ziehau }
98734d68912SSepherosa Ziehau #endif	/* !RSS */
98815516c77SSepherosa Ziehau 
98915516c77SSepherosa Ziehau static void
990afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
99115516c77SSepherosa Ziehau {
99215516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
993afd4971bSSepherosa Ziehau 	int i, nchan;
99415516c77SSepherosa Ziehau 
995afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
99615516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
99715516c77SSepherosa Ziehau 
99815516c77SSepherosa Ziehau 	/*
99915516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
100015516c77SSepherosa Ziehau 	 * can be used.
100115516c77SSepherosa Ziehau 	 */
100215516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
100315516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
100415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
100515516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
100615516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
100715516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
100815516c77SSepherosa Ziehau 		}
100915516c77SSepherosa Ziehau 	}
101015516c77SSepherosa Ziehau }
101115516c77SSepherosa Ziehau 
101215516c77SSepherosa Ziehau static int
101315516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
101415516c77SSepherosa Ziehau {
101515516c77SSepherosa Ziehau 
101615516c77SSepherosa Ziehau 	return EOPNOTSUPP;
101715516c77SSepherosa Ziehau }
101815516c77SSepherosa Ziehau 
101915516c77SSepherosa Ziehau static void
102015516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
102115516c77SSepherosa Ziehau {
102215516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
102315516c77SSepherosa Ziehau 
102415516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
102515516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
102615516c77SSepherosa Ziehau 
102715516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
102815516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
102915516c77SSepherosa Ziehau 		return;
103015516c77SSepherosa Ziehau 	}
103115516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
103215516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
103315516c77SSepherosa Ziehau }
103415516c77SSepherosa Ziehau 
10355bdfd3fdSDexuan Cui static void
1036962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused)
10375bdfd3fdSDexuan Cui {
1038962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg *arg = xarg;
10395bdfd3fdSDexuan Cui 
1040962f0357SSepherosa Ziehau 	arg->rxr->hn_rxvf_ifp = arg->vf_ifp;
10415bdfd3fdSDexuan Cui }
10425bdfd3fdSDexuan Cui 
10435bdfd3fdSDexuan Cui static void
1044962f0357SSepherosa Ziehau hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp)
10455bdfd3fdSDexuan Cui {
10465bdfd3fdSDexuan Cui 	struct hn_rx_ring *rxr;
1047962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg arg;
10485bdfd3fdSDexuan Cui 	struct task task;
10495bdfd3fdSDexuan Cui 	int i;
10505bdfd3fdSDexuan Cui 
10515bdfd3fdSDexuan Cui 	HN_LOCK_ASSERT(sc);
10525bdfd3fdSDexuan Cui 
1053962f0357SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_rxvf_set_task, &arg);
10545bdfd3fdSDexuan Cui 
10555bdfd3fdSDexuan Cui 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
10565bdfd3fdSDexuan Cui 		rxr = &sc->hn_rx_ring[i];
10575bdfd3fdSDexuan Cui 
10585bdfd3fdSDexuan Cui 		if (i < sc->hn_rx_ring_inuse) {
1059962f0357SSepherosa Ziehau 			arg.rxr = rxr;
1060962f0357SSepherosa Ziehau 			arg.vf_ifp = vf_ifp;
10615bdfd3fdSDexuan Cui 			vmbus_chan_run_task(rxr->hn_chan, &task);
10625bdfd3fdSDexuan Cui 		} else {
1063962f0357SSepherosa Ziehau 			rxr->hn_rxvf_ifp = vf_ifp;
10645bdfd3fdSDexuan Cui 		}
10655bdfd3fdSDexuan Cui 	}
10665bdfd3fdSDexuan Cui }
10675bdfd3fdSDexuan Cui 
1068962f0357SSepherosa Ziehau static bool
1069499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp)
1070499c3e17SSepherosa Ziehau {
1071499c3e17SSepherosa Ziehau 	const struct ifnet *hn_ifp;
1072499c3e17SSepherosa Ziehau 
1073499c3e17SSepherosa Ziehau 	hn_ifp = sc->hn_ifp;
1074499c3e17SSepherosa Ziehau 
1075499c3e17SSepherosa Ziehau 	if (ifp == hn_ifp)
1076499c3e17SSepherosa Ziehau 		return (false);
1077499c3e17SSepherosa Ziehau 
1078499c3e17SSepherosa Ziehau 	if (ifp->if_alloctype != IFT_ETHER)
1079499c3e17SSepherosa Ziehau 		return (false);
1080499c3e17SSepherosa Ziehau 
1081499c3e17SSepherosa Ziehau 	/* Ignore lagg/vlan interfaces */
1082499c3e17SSepherosa Ziehau 	if (strcmp(ifp->if_dname, "lagg") == 0 ||
1083499c3e17SSepherosa Ziehau 	    strcmp(ifp->if_dname, "vlan") == 0)
1084499c3e17SSepherosa Ziehau 		return (false);
1085499c3e17SSepherosa Ziehau 
1086499c3e17SSepherosa Ziehau 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
1087499c3e17SSepherosa Ziehau 		return (false);
1088499c3e17SSepherosa Ziehau 
1089499c3e17SSepherosa Ziehau 	return (true);
1090499c3e17SSepherosa Ziehau }
1091499c3e17SSepherosa Ziehau 
10925bdfd3fdSDexuan Cui static void
1093962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf)
10945bdfd3fdSDexuan Cui {
10955bdfd3fdSDexuan Cui 	struct ifnet *hn_ifp;
10965bdfd3fdSDexuan Cui 
10975bdfd3fdSDexuan Cui 	HN_LOCK(sc);
10985bdfd3fdSDexuan Cui 
10995bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
11005bdfd3fdSDexuan Cui 		goto out;
11015bdfd3fdSDexuan Cui 
1102499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1103499c3e17SSepherosa Ziehau 		goto out;
11045bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
11055bdfd3fdSDexuan Cui 
1106962f0357SSepherosa Ziehau 	if (rxvf) {
1107962f0357SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_RXVF)
11085bdfd3fdSDexuan Cui 			goto out;
11095bdfd3fdSDexuan Cui 
1110962f0357SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_RXVF;
11115bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
11125bdfd3fdSDexuan Cui 	} else {
1113962f0357SSepherosa Ziehau 		if (!(sc->hn_flags & HN_FLAG_RXVF))
11145bdfd3fdSDexuan Cui 			goto out;
11155bdfd3fdSDexuan Cui 
1116962f0357SSepherosa Ziehau 		sc->hn_flags &= ~HN_FLAG_RXVF;
1117499c3e17SSepherosa Ziehau 		if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
11185bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
11195bdfd3fdSDexuan Cui 		else
11205bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
11215bdfd3fdSDexuan Cui 	}
11225bdfd3fdSDexuan Cui 
11235bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
1124*9c6cae24SSepherosa Ziehau 	    rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH);
11255bdfd3fdSDexuan Cui 
1126962f0357SSepherosa Ziehau 	hn_rxvf_set(sc, rxvf ? ifp : NULL);
11275bdfd3fdSDexuan Cui 
1128962f0357SSepherosa Ziehau 	if (rxvf) {
11295bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
11305bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
11315bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
1132499c3e17SSepherosa Ziehau 		if_link_state_change(hn_ifp, LINK_STATE_DOWN);
11335bdfd3fdSDexuan Cui 	} else {
11345bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
11355bdfd3fdSDexuan Cui 	}
11365bdfd3fdSDexuan Cui 
1137962f0357SSepherosa Ziehau 	devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname,
1138962f0357SSepherosa Ziehau 	    rxvf ? "VF_UP" : "VF_DOWN", NULL);
113933408a34SDexuan Cui 
1140962f0357SSepherosa Ziehau 	if (bootverbose) {
1141962f0357SSepherosa Ziehau 		if_printf(hn_ifp, "datapath is switched %s %s\n",
1142962f0357SSepherosa Ziehau 		    rxvf ? "to" : "from", ifp->if_xname);
1143962f0357SSepherosa Ziehau 	}
11445bdfd3fdSDexuan Cui out:
11455bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
11465bdfd3fdSDexuan Cui }
11475bdfd3fdSDexuan Cui 
11485bdfd3fdSDexuan Cui static void
11495bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event)
11505bdfd3fdSDexuan Cui {
1151962f0357SSepherosa Ziehau 
11525bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
11535bdfd3fdSDexuan Cui 		return;
1154962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP);
11555bdfd3fdSDexuan Cui }
11565bdfd3fdSDexuan Cui 
11575bdfd3fdSDexuan Cui static void
11585bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp)
11595bdfd3fdSDexuan Cui {
1160962f0357SSepherosa Ziehau 
1161962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP);
11625bdfd3fdSDexuan Cui }
11635bdfd3fdSDexuan Cui 
1164*9c6cae24SSepherosa Ziehau static int
1165*9c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr)
1166*9c6cae24SSepherosa Ziehau {
1167*9c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
1168*9c6cae24SSepherosa Ziehau 	uint64_t tmp;
1169*9c6cae24SSepherosa Ziehau 	int error;
1170*9c6cae24SSepherosa Ziehau 
1171*9c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1172*9c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
1173*9c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
1174*9c6cae24SSepherosa Ziehau 
1175*9c6cae24SSepherosa Ziehau 	/*
1176*9c6cae24SSepherosa Ziehau 	 * Fix up requested capabilities w/ supported capabilities,
1177*9c6cae24SSepherosa Ziehau 	 * since the supported capabilities could have been changed.
1178*9c6cae24SSepherosa Ziehau 	 */
1179*9c6cae24SSepherosa Ziehau 	ifr->ifr_reqcap &= ifp->if_capabilities;
1180*9c6cae24SSepherosa Ziehau 	/* Pass SIOCSIFCAP to VF. */
1181*9c6cae24SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr);
1182*9c6cae24SSepherosa Ziehau 
1183*9c6cae24SSepherosa Ziehau 	/*
1184*9c6cae24SSepherosa Ziehau 	 * NOTE:
1185*9c6cae24SSepherosa Ziehau 	 * The error will be propagated to the callers, however, it
1186*9c6cae24SSepherosa Ziehau 	 * is _not_ useful here.
1187*9c6cae24SSepherosa Ziehau 	 */
1188*9c6cae24SSepherosa Ziehau 
1189*9c6cae24SSepherosa Ziehau 	/*
1190*9c6cae24SSepherosa Ziehau 	 * Merge VF's enabled capabilities.
1191*9c6cae24SSepherosa Ziehau 	 */
1192*9c6cae24SSepherosa Ziehau 	ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities;
1193*9c6cae24SSepherosa Ziehau 
1194*9c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc);
1195*9c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM)
1196*9c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
1197*9c6cae24SSepherosa Ziehau 	else
1198*9c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
1199*9c6cae24SSepherosa Ziehau 
1200*9c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc);
1201*9c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
1202*9c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
1203*9c6cae24SSepherosa Ziehau 	else
1204*9c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
1205*9c6cae24SSepherosa Ziehau 
1206*9c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP_TSO;
1207*9c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO4)
1208*9c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
1209*9c6cae24SSepherosa Ziehau 	else
1210*9c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
1211*9c6cae24SSepherosa Ziehau 
1212*9c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO;
1213*9c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO6)
1214*9c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
1215*9c6cae24SSepherosa Ziehau 	else
1216*9c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
1217*9c6cae24SSepherosa Ziehau 
1218*9c6cae24SSepherosa Ziehau 	return (error);
1219*9c6cae24SSepherosa Ziehau }
1220*9c6cae24SSepherosa Ziehau 
1221*9c6cae24SSepherosa Ziehau static int
1222*9c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc)
1223*9c6cae24SSepherosa Ziehau {
1224*9c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
1225*9c6cae24SSepherosa Ziehau 	struct ifreq ifr;
1226*9c6cae24SSepherosa Ziehau 
1227*9c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1228*9c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
1229*9c6cae24SSepherosa Ziehau 
1230*9c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
1231*9c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
1232*9c6cae24SSepherosa Ziehau 	ifr.ifr_flags = vf_ifp->if_flags & 0xffff;
1233*9c6cae24SSepherosa Ziehau 	ifr.ifr_flagshigh = vf_ifp->if_flags >> 16;
1234*9c6cae24SSepherosa Ziehau 	return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
1235*9c6cae24SSepherosa Ziehau }
1236*9c6cae24SSepherosa Ziehau 
1237*9c6cae24SSepherosa Ziehau static void
1238*9c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc)
1239*9c6cae24SSepherosa Ziehau {
1240*9c6cae24SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
1241*9c6cae24SSepherosa Ziehau 	int allmulti = 0;
1242*9c6cae24SSepherosa Ziehau 
1243*9c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1244*9c6cae24SSepherosa Ziehau 
1245*9c6cae24SSepherosa Ziehau 	/* XXX vlan(4) style mcast addr maintenance */
1246*9c6cae24SSepherosa Ziehau 	if (!TAILQ_EMPTY(&ifp->if_multiaddrs))
1247*9c6cae24SSepherosa Ziehau 		allmulti = IFF_ALLMULTI;
1248*9c6cae24SSepherosa Ziehau 
1249*9c6cae24SSepherosa Ziehau 	/* Always set the VF's if_flags */
1250*9c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti;
1251*9c6cae24SSepherosa Ziehau }
1252*9c6cae24SSepherosa Ziehau 
1253*9c6cae24SSepherosa Ziehau static void
1254*9c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m)
1255*9c6cae24SSepherosa Ziehau {
1256*9c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
1257*9c6cae24SSepherosa Ziehau 	struct ifnet *hn_ifp = NULL;
1258*9c6cae24SSepherosa Ziehau 	struct mbuf *mn;
1259*9c6cae24SSepherosa Ziehau 
1260*9c6cae24SSepherosa Ziehau 	/*
1261*9c6cae24SSepherosa Ziehau 	 * XXX racy, if hn(4) ever detached.
1262*9c6cae24SSepherosa Ziehau 	 */
1263*9c6cae24SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
1264*9c6cae24SSepherosa Ziehau 	if (vf_ifp->if_index < hn_vfmap_size)
1265*9c6cae24SSepherosa Ziehau 		hn_ifp = hn_vfmap[vf_ifp->if_index];
1266*9c6cae24SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
1267*9c6cae24SSepherosa Ziehau 
1268*9c6cae24SSepherosa Ziehau 	if (hn_ifp != NULL) {
1269*9c6cae24SSepherosa Ziehau 		/*
1270*9c6cae24SSepherosa Ziehau 		 * Fix up rcvif and go through hn(4)'s if_input and
1271*9c6cae24SSepherosa Ziehau 		 * increase ipackets.
1272*9c6cae24SSepherosa Ziehau 		 */
1273*9c6cae24SSepherosa Ziehau 		for (mn = m; mn != NULL; mn = mn->m_nextpkt) {
1274*9c6cae24SSepherosa Ziehau 			/* Allow tapping on the VF. */
1275*9c6cae24SSepherosa Ziehau 			ETHER_BPF_MTAP(vf_ifp, mn);
1276*9c6cae24SSepherosa Ziehau 			mn->m_pkthdr.rcvif = hn_ifp;
1277*9c6cae24SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
1278*9c6cae24SSepherosa Ziehau 		}
1279*9c6cae24SSepherosa Ziehau 		hn_ifp->if_input(hn_ifp, m);
1280*9c6cae24SSepherosa Ziehau 	} else {
1281*9c6cae24SSepherosa Ziehau 		/*
1282*9c6cae24SSepherosa Ziehau 		 * In the middle of the transition; free this
1283*9c6cae24SSepherosa Ziehau 		 * mbuf chain.
1284*9c6cae24SSepherosa Ziehau 		 */
1285*9c6cae24SSepherosa Ziehau 		while (m != NULL) {
1286*9c6cae24SSepherosa Ziehau 			mn = m->m_nextpkt;
1287*9c6cae24SSepherosa Ziehau 			m->m_nextpkt = NULL;
1288*9c6cae24SSepherosa Ziehau 			m_freem(m);
1289*9c6cae24SSepherosa Ziehau 			m = mn;
1290*9c6cae24SSepherosa Ziehau 		}
1291*9c6cae24SSepherosa Ziehau 	}
1292*9c6cae24SSepherosa Ziehau }
1293*9c6cae24SSepherosa Ziehau 
1294*9c6cae24SSepherosa Ziehau static void
1295*9c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc)
1296*9c6cae24SSepherosa Ziehau {
1297*9c6cae24SSepherosa Ziehau 	struct ifnet *ifp;
1298*9c6cae24SSepherosa Ziehau 
1299*9c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1300*9c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
1301*9c6cae24SSepherosa Ziehau 
1302*9c6cae24SSepherosa Ziehau 	hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
1303*9c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099
1304*9c6cae24SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp))
1305*9c6cae24SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
1306*9c6cae24SSepherosa Ziehau #endif
1307*9c6cae24SSepherosa Ziehau }
1308*9c6cae24SSepherosa Ziehau 
1309*9c6cae24SSepherosa Ziehau static void
1310*9c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc)
1311*9c6cae24SSepherosa Ziehau {
1312*9c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
1313*9c6cae24SSepherosa Ziehau 	struct ifreq ifr;
1314*9c6cae24SSepherosa Ziehau 
1315*9c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1316*9c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
1317*9c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
1318*9c6cae24SSepherosa Ziehau 
1319*9c6cae24SSepherosa Ziehau 	/*
1320*9c6cae24SSepherosa Ziehau 	 * Mark the VF ready.
1321*9c6cae24SSepherosa Ziehau 	 */
1322*9c6cae24SSepherosa Ziehau 	sc->hn_vf_rdytick = 0;
1323*9c6cae24SSepherosa Ziehau 
1324*9c6cae24SSepherosa Ziehau 	/*
1325*9c6cae24SSepherosa Ziehau 	 * Save information for restoration.
1326*9c6cae24SSepherosa Ziehau 	 */
1327*9c6cae24SSepherosa Ziehau 	sc->hn_saved_caps = ifp->if_capabilities;
1328*9c6cae24SSepherosa Ziehau 	sc->hn_saved_tsomax = ifp->if_hw_tsomax;
1329*9c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount;
1330*9c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize;
1331*9c6cae24SSepherosa Ziehau 
1332*9c6cae24SSepherosa Ziehau 	/*
1333*9c6cae24SSepherosa Ziehau 	 * Intersect supported/enabled capabilities.
1334*9c6cae24SSepherosa Ziehau 	 *
1335*9c6cae24SSepherosa Ziehau 	 * NOTE:
1336*9c6cae24SSepherosa Ziehau 	 * if_hwassist is not changed here.
1337*9c6cae24SSepherosa Ziehau 	 */
1338*9c6cae24SSepherosa Ziehau 	ifp->if_capabilities &= vf_ifp->if_capabilities;
1339*9c6cae24SSepherosa Ziehau 	ifp->if_capenable &= ifp->if_capabilities;
1340*9c6cae24SSepherosa Ziehau 
1341*9c6cae24SSepherosa Ziehau 	/*
1342*9c6cae24SSepherosa Ziehau 	 * Fix TSO settings.
1343*9c6cae24SSepherosa Ziehau 	 */
1344*9c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax)
1345*9c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax;
1346*9c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount)
1347*9c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount;
1348*9c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize)
1349*9c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize;
1350*9c6cae24SSepherosa Ziehau 
1351*9c6cae24SSepherosa Ziehau 	/*
1352*9c6cae24SSepherosa Ziehau 	 * Change VF's enabled capabilities.
1353*9c6cae24SSepherosa Ziehau 	 */
1354*9c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
1355*9c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
1356*9c6cae24SSepherosa Ziehau 	ifr.ifr_reqcap = ifp->if_capenable;
1357*9c6cae24SSepherosa Ziehau 	hn_xpnt_vf_iocsetcaps(sc, &ifr);
1358*9c6cae24SSepherosa Ziehau 
1359*9c6cae24SSepherosa Ziehau 	if (ifp->if_mtu != ETHERMTU) {
1360*9c6cae24SSepherosa Ziehau 		int error;
1361*9c6cae24SSepherosa Ziehau 
1362*9c6cae24SSepherosa Ziehau 		/*
1363*9c6cae24SSepherosa Ziehau 		 * Change VF's MTU.
1364*9c6cae24SSepherosa Ziehau 		 */
1365*9c6cae24SSepherosa Ziehau 		memset(&ifr, 0, sizeof(ifr));
1366*9c6cae24SSepherosa Ziehau 		strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
1367*9c6cae24SSepherosa Ziehau 		ifr.ifr_mtu = ifp->if_mtu;
1368*9c6cae24SSepherosa Ziehau 		error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr);
1369*9c6cae24SSepherosa Ziehau 		if (error) {
1370*9c6cae24SSepherosa Ziehau 			if_printf(ifp, "%s SIOCSIFMTU %u failed\n",
1371*9c6cae24SSepherosa Ziehau 			    vf_ifp->if_xname, ifp->if_mtu);
1372*9c6cae24SSepherosa Ziehau 			if (ifp->if_mtu > ETHERMTU) {
1373*9c6cae24SSepherosa Ziehau 				if_printf(ifp, "change MTU to %d\n", ETHERMTU);
1374*9c6cae24SSepherosa Ziehau 
1375*9c6cae24SSepherosa Ziehau 				/*
1376*9c6cae24SSepherosa Ziehau 				 * XXX
1377*9c6cae24SSepherosa Ziehau 				 * No need to adjust the synthetic parts' MTU;
1378*9c6cae24SSepherosa Ziehau 				 * failure of the adjustment will cause us
1379*9c6cae24SSepherosa Ziehau 				 * infinite headache.
1380*9c6cae24SSepherosa Ziehau 				 */
1381*9c6cae24SSepherosa Ziehau 				ifp->if_mtu = ETHERMTU;
1382*9c6cae24SSepherosa Ziehau 				hn_mtu_change_fixup(sc);
1383*9c6cae24SSepherosa Ziehau 			}
1384*9c6cae24SSepherosa Ziehau 		}
1385*9c6cae24SSepherosa Ziehau 	}
1386*9c6cae24SSepherosa Ziehau }
1387*9c6cae24SSepherosa Ziehau 
1388*9c6cae24SSepherosa Ziehau static bool
1389*9c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc)
1390*9c6cae24SSepherosa Ziehau {
1391*9c6cae24SSepherosa Ziehau 
1392*9c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1393*9c6cae24SSepherosa Ziehau 
1394*9c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL)
1395*9c6cae24SSepherosa Ziehau 		return (false);
1396*9c6cae24SSepherosa Ziehau 
1397*9c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick == 0)
1398*9c6cae24SSepherosa Ziehau 		return (true);
1399*9c6cae24SSepherosa Ziehau 
1400*9c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick > ticks)
1401*9c6cae24SSepherosa Ziehau 		return (false);
1402*9c6cae24SSepherosa Ziehau 
1403*9c6cae24SSepherosa Ziehau 	/* Mark VF as ready. */
1404*9c6cae24SSepherosa Ziehau 	hn_xpnt_vf_setready(sc);
1405*9c6cae24SSepherosa Ziehau 	return (true);
1406*9c6cae24SSepherosa Ziehau }
1407*9c6cae24SSepherosa Ziehau 
1408*9c6cae24SSepherosa Ziehau static void
1409*9c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc)
1410*9c6cae24SSepherosa Ziehau {
1411*9c6cae24SSepherosa Ziehau 	int error;
1412*9c6cae24SSepherosa Ziehau 
1413*9c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1414*9c6cae24SSepherosa Ziehau 
1415*9c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
1416*9c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
1417*9c6cae24SSepherosa Ziehau 
1418*9c6cae24SSepherosa Ziehau 	if (bootverbose) {
1419*9c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "try bringing up %s\n",
1420*9c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
1421*9c6cae24SSepherosa Ziehau 	}
1422*9c6cae24SSepherosa Ziehau 
1423*9c6cae24SSepherosa Ziehau 	/*
1424*9c6cae24SSepherosa Ziehau 	 * Bring the VF up.
1425*9c6cae24SSepherosa Ziehau 	 */
1426*9c6cae24SSepherosa Ziehau 	hn_xpnt_vf_saveifflags(sc);
1427*9c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags |= IFF_UP;
1428*9c6cae24SSepherosa Ziehau 	error = hn_xpnt_vf_iocsetflags(sc);
1429*9c6cae24SSepherosa Ziehau 	if (error) {
1430*9c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "bringing up %s failed: %d\n",
1431*9c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname, error);
1432*9c6cae24SSepherosa Ziehau 		return;
1433*9c6cae24SSepherosa Ziehau 	}
1434*9c6cae24SSepherosa Ziehau 
1435*9c6cae24SSepherosa Ziehau 	/*
1436*9c6cae24SSepherosa Ziehau 	 * NOTE:
1437*9c6cae24SSepherosa Ziehau 	 * Datapath setting must happen _after_ bringing the VF up.
1438*9c6cae24SSepherosa Ziehau 	 */
1439*9c6cae24SSepherosa Ziehau 	hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
1440*9c6cae24SSepherosa Ziehau 
1441*9c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1442*9c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1443*9c6cae24SSepherosa Ziehau 	sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED;
1444*9c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1445*9c6cae24SSepherosa Ziehau }
1446*9c6cae24SSepherosa Ziehau 
1447*9c6cae24SSepherosa Ziehau static void
1448*9c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused)
1449*9c6cae24SSepherosa Ziehau {
1450*9c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1451*9c6cae24SSepherosa Ziehau 
1452*9c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
1453*9c6cae24SSepherosa Ziehau 
1454*9c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
1455*9c6cae24SSepherosa Ziehau 		goto done;
1456*9c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
1457*9c6cae24SSepherosa Ziehau 		goto done;
1458*9c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
1459*9c6cae24SSepherosa Ziehau 		goto done;
1460*9c6cae24SSepherosa Ziehau 
1461*9c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick != 0) {
1462*9c6cae24SSepherosa Ziehau 		/* Mark VF as ready. */
1463*9c6cae24SSepherosa Ziehau 		hn_xpnt_vf_setready(sc);
1464*9c6cae24SSepherosa Ziehau 	}
1465*9c6cae24SSepherosa Ziehau 
1466*9c6cae24SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) {
1467*9c6cae24SSepherosa Ziehau 		/*
1468*9c6cae24SSepherosa Ziehau 		 * Delayed VF initialization.
1469*9c6cae24SSepherosa Ziehau 		 */
1470*9c6cae24SSepherosa Ziehau 		if (bootverbose) {
1471*9c6cae24SSepherosa Ziehau 			if_printf(sc->hn_ifp, "delayed initialize %s\n",
1472*9c6cae24SSepherosa Ziehau 			    sc->hn_vf_ifp->if_xname);
1473*9c6cae24SSepherosa Ziehau 		}
1474*9c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
1475*9c6cae24SSepherosa Ziehau 	}
1476*9c6cae24SSepherosa Ziehau done:
1477*9c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
1478*9c6cae24SSepherosa Ziehau }
1479*9c6cae24SSepherosa Ziehau 
1480499c3e17SSepherosa Ziehau static void
1481499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp)
1482499c3e17SSepherosa Ziehau {
1483499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1484499c3e17SSepherosa Ziehau 
1485499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1486499c3e17SSepherosa Ziehau 
1487499c3e17SSepherosa Ziehau 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
1488499c3e17SSepherosa Ziehau 		goto done;
1489499c3e17SSepherosa Ziehau 
1490499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1491499c3e17SSepherosa Ziehau 		goto done;
1492499c3e17SSepherosa Ziehau 
1493499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp != NULL) {
1494499c3e17SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s was attached as VF\n",
1495499c3e17SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
1496499c3e17SSepherosa Ziehau 		goto done;
1497499c3e17SSepherosa Ziehau 	}
1498499c3e17SSepherosa Ziehau 
1499*9c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && ifp->if_start != NULL) {
1500*9c6cae24SSepherosa Ziehau 		/*
1501*9c6cae24SSepherosa Ziehau 		 * ifnet.if_start is _not_ supported by transparent
1502*9c6cae24SSepherosa Ziehau 		 * mode VF; mainly due to the IFF_DRV_OACTIVE flag.
1503*9c6cae24SSepherosa Ziehau 		 */
1504*9c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported "
1505*9c6cae24SSepherosa Ziehau 		    "in transparent VF mode.\n", ifp->if_xname);
1506*9c6cae24SSepherosa Ziehau 		goto done;
1507*9c6cae24SSepherosa Ziehau 	}
1508*9c6cae24SSepherosa Ziehau 
1509499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1510499c3e17SSepherosa Ziehau 
1511499c3e17SSepherosa Ziehau 	if (ifp->if_index >= hn_vfmap_size) {
1512499c3e17SSepherosa Ziehau 		struct ifnet **newmap;
1513499c3e17SSepherosa Ziehau 		int newsize;
1514499c3e17SSepherosa Ziehau 
1515499c3e17SSepherosa Ziehau 		newsize = ifp->if_index + HN_VFMAP_SIZE_DEF;
1516499c3e17SSepherosa Ziehau 		newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF,
1517499c3e17SSepherosa Ziehau 		    M_WAITOK | M_ZERO);
1518499c3e17SSepherosa Ziehau 
1519499c3e17SSepherosa Ziehau 		memcpy(newmap, hn_vfmap,
1520499c3e17SSepherosa Ziehau 		    sizeof(struct ifnet *) * hn_vfmap_size);
1521499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
1522499c3e17SSepherosa Ziehau 		hn_vfmap = newmap;
1523499c3e17SSepherosa Ziehau 		hn_vfmap_size = newsize;
1524499c3e17SSepherosa Ziehau 	}
1525499c3e17SSepherosa Ziehau 	KASSERT(hn_vfmap[ifp->if_index] == NULL,
1526499c3e17SSepherosa Ziehau 	    ("%s: ifindex %d was mapped to %s",
1527499c3e17SSepherosa Ziehau 	     ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname));
1528499c3e17SSepherosa Ziehau 	hn_vfmap[ifp->if_index] = sc->hn_ifp;
1529499c3e17SSepherosa Ziehau 
1530499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1531499c3e17SSepherosa Ziehau 
1532*9c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1533*9c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1534*9c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
1535*9c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
1536499c3e17SSepherosa Ziehau 	sc->hn_vf_ifp = ifp;
1537*9c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1538*9c6cae24SSepherosa Ziehau 
1539*9c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
1540*9c6cae24SSepherosa Ziehau 		int wait_ticks;
1541*9c6cae24SSepherosa Ziehau 
1542*9c6cae24SSepherosa Ziehau 		/*
1543*9c6cae24SSepherosa Ziehau 		 * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp.
1544*9c6cae24SSepherosa Ziehau 		 * Save vf_ifp's current if_input for later restoration.
1545*9c6cae24SSepherosa Ziehau 		 */
1546*9c6cae24SSepherosa Ziehau 		sc->hn_vf_input = ifp->if_input;
1547*9c6cae24SSepherosa Ziehau 		ifp->if_input = hn_xpnt_vf_input;
1548*9c6cae24SSepherosa Ziehau 
1549*9c6cae24SSepherosa Ziehau 		/*
1550*9c6cae24SSepherosa Ziehau 		 * Stop link status management; use the VF's.
1551*9c6cae24SSepherosa Ziehau 		 */
1552*9c6cae24SSepherosa Ziehau 		hn_suspend_mgmt(sc);
1553*9c6cae24SSepherosa Ziehau 
1554*9c6cae24SSepherosa Ziehau 		/*
1555*9c6cae24SSepherosa Ziehau 		 * Give VF sometime to complete its attach routing.
1556*9c6cae24SSepherosa Ziehau 		 */
1557*9c6cae24SSepherosa Ziehau 		wait_ticks = hn_xpnt_vf_attwait * hz;
1558*9c6cae24SSepherosa Ziehau 		sc->hn_vf_rdytick = ticks + wait_ticks;
1559*9c6cae24SSepherosa Ziehau 
1560*9c6cae24SSepherosa Ziehau 		taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init,
1561*9c6cae24SSepherosa Ziehau 		    wait_ticks);
1562*9c6cae24SSepherosa Ziehau 	}
1563499c3e17SSepherosa Ziehau done:
1564499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1565499c3e17SSepherosa Ziehau }
1566499c3e17SSepherosa Ziehau 
1567499c3e17SSepherosa Ziehau static void
1568499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp)
1569499c3e17SSepherosa Ziehau {
1570499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1571499c3e17SSepherosa Ziehau 
1572499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1573499c3e17SSepherosa Ziehau 
1574499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
1575499c3e17SSepherosa Ziehau 		goto done;
1576499c3e17SSepherosa Ziehau 
1577499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1578499c3e17SSepherosa Ziehau 		goto done;
1579499c3e17SSepherosa Ziehau 
1580*9c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
1581*9c6cae24SSepherosa Ziehau 		/*
1582*9c6cae24SSepherosa Ziehau 		 * Make sure that the delayed initialization is not running.
1583*9c6cae24SSepherosa Ziehau 		 *
1584*9c6cae24SSepherosa Ziehau 		 * NOTE:
1585*9c6cae24SSepherosa Ziehau 		 * - This lock _must_ be released, since the hn_vf_init task
1586*9c6cae24SSepherosa Ziehau 		 *   will try holding this lock.
1587*9c6cae24SSepherosa Ziehau 		 * - It is safe to release this lock here, since the
1588*9c6cae24SSepherosa Ziehau 		 *   hn_ifnet_attevent() is interlocked by the hn_vf_ifp.
1589*9c6cae24SSepherosa Ziehau 		 *
1590*9c6cae24SSepherosa Ziehau 		 * XXX racy, if hn(4) ever detached.
1591*9c6cae24SSepherosa Ziehau 		 */
1592*9c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
1593*9c6cae24SSepherosa Ziehau 		taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init);
1594*9c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
1595*9c6cae24SSepherosa Ziehau 
1596*9c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved",
1597*9c6cae24SSepherosa Ziehau 		    sc->hn_ifp->if_xname));
1598*9c6cae24SSepherosa Ziehau 		ifp->if_input = sc->hn_vf_input;
1599*9c6cae24SSepherosa Ziehau 		sc->hn_vf_input = NULL;
1600*9c6cae24SSepherosa Ziehau 
1601*9c6cae24SSepherosa Ziehau 		if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
1602*9c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
1603*9c6cae24SSepherosa Ziehau 
1604*9c6cae24SSepherosa Ziehau 		if (sc->hn_vf_rdytick == 0) {
1605*9c6cae24SSepherosa Ziehau 			/*
1606*9c6cae24SSepherosa Ziehau 			 * The VF was ready; restore some settings.
1607*9c6cae24SSepherosa Ziehau 			 */
1608*9c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_capabilities = sc->hn_saved_caps;
1609*9c6cae24SSepherosa Ziehau 			/*
1610*9c6cae24SSepherosa Ziehau 			 * NOTE:
1611*9c6cae24SSepherosa Ziehau 			 * There is _no_ need to fixup if_capenable and
1612*9c6cae24SSepherosa Ziehau 			 * if_hwassist, since the if_capabilities before
1613*9c6cae24SSepherosa Ziehau 			 * restoration was an intersection of the VF's
1614*9c6cae24SSepherosa Ziehau 			 * if_capabilites and the synthetic device's
1615*9c6cae24SSepherosa Ziehau 			 * if_capabilites.
1616*9c6cae24SSepherosa Ziehau 			 */
1617*9c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax;
1618*9c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegcount =
1619*9c6cae24SSepherosa Ziehau 			    sc->hn_saved_tsosegcnt;
1620*9c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz;
1621*9c6cae24SSepherosa Ziehau 		}
1622*9c6cae24SSepherosa Ziehau 
1623*9c6cae24SSepherosa Ziehau 		/*
1624*9c6cae24SSepherosa Ziehau 		 * Resume link status management, which was suspended
1625*9c6cae24SSepherosa Ziehau 		 * by hn_ifnet_attevent().
1626*9c6cae24SSepherosa Ziehau 		 */
1627*9c6cae24SSepherosa Ziehau 		hn_resume_mgmt(sc);
1628*9c6cae24SSepherosa Ziehau 	}
1629*9c6cae24SSepherosa Ziehau 
1630*9c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1631*9c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1632*9c6cae24SSepherosa Ziehau 	sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED;
1633499c3e17SSepherosa Ziehau 	sc->hn_vf_ifp = NULL;
1634*9c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1635499c3e17SSepherosa Ziehau 
1636499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1637499c3e17SSepherosa Ziehau 
1638499c3e17SSepherosa Ziehau 	KASSERT(ifp->if_index < hn_vfmap_size,
1639499c3e17SSepherosa Ziehau 	    ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size));
1640499c3e17SSepherosa Ziehau 	if (hn_vfmap[ifp->if_index] != NULL) {
1641499c3e17SSepherosa Ziehau 		KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp,
1642499c3e17SSepherosa Ziehau 		    ("%s: ifindex %d was mapped to %s",
1643499c3e17SSepherosa Ziehau 		     ifp->if_xname, ifp->if_index,
1644499c3e17SSepherosa Ziehau 		     hn_vfmap[ifp->if_index]->if_xname));
1645499c3e17SSepherosa Ziehau 		hn_vfmap[ifp->if_index] = NULL;
1646499c3e17SSepherosa Ziehau 	}
1647499c3e17SSepherosa Ziehau 
1648499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1649499c3e17SSepherosa Ziehau done:
1650499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1651499c3e17SSepherosa Ziehau }
1652499c3e17SSepherosa Ziehau 
1653*9c6cae24SSepherosa Ziehau static void
1654*9c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state)
1655*9c6cae24SSepherosa Ziehau {
1656*9c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1657*9c6cae24SSepherosa Ziehau 
1658*9c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == ifp)
1659*9c6cae24SSepherosa Ziehau 		if_link_state_change(sc->hn_ifp, link_state);
1660*9c6cae24SSepherosa Ziehau }
1661*9c6cae24SSepherosa Ziehau 
166215516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
166315516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = {
166415516c77SSepherosa Ziehau 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
166515516c77SSepherosa Ziehau 		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
166615516c77SSepherosa Ziehau };
166715516c77SSepherosa Ziehau 
166815516c77SSepherosa Ziehau static int
166915516c77SSepherosa Ziehau hn_probe(device_t dev)
167015516c77SSepherosa Ziehau {
167115516c77SSepherosa Ziehau 
167215516c77SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
167315516c77SSepherosa Ziehau 	    &g_net_vsc_device_type) == 0) {
167415516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
167515516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
167615516c77SSepherosa Ziehau 	}
167715516c77SSepherosa Ziehau 	return ENXIO;
167815516c77SSepherosa Ziehau }
167915516c77SSepherosa Ziehau 
168015516c77SSepherosa Ziehau static int
168115516c77SSepherosa Ziehau hn_attach(device_t dev)
168215516c77SSepherosa Ziehau {
168315516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
168415516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
168515516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
168615516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
168715516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
168815516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
168915516c77SSepherosa Ziehau 
169015516c77SSepherosa Ziehau 	sc->hn_dev = dev;
169115516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
169215516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
1693*9c6cae24SSepherosa Ziehau 	rm_init(&sc->hn_vf_lock, "hnvf");
1694*9c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_xpnt_vf_accbpf)
1695*9c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
169615516c77SSepherosa Ziehau 
169715516c77SSepherosa Ziehau 	/*
1698dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
1699dc13fee6SSepherosa Ziehau 	 */
1700dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
1701dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
1702dc13fee6SSepherosa Ziehau 
1703dc13fee6SSepherosa Ziehau 	/*
170415516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
170515516c77SSepherosa Ziehau 	 */
17060e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
1707fdd0222aSSepherosa Ziehau 		int i;
1708fdd0222aSSepherosa Ziehau 
1709fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
1710fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
1711fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
1712fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
1713fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
1714fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
1715fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
1716fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
1717fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
1718fdd0222aSSepherosa Ziehau 		}
17190e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
1720fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
172115516c77SSepherosa Ziehau 	}
172215516c77SSepherosa Ziehau 
172315516c77SSepherosa Ziehau 	/*
172415516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
172515516c77SSepherosa Ziehau 	 */
172615516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
172715516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
172815516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
172915516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
173015516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
173115516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
173215516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
173315516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
173415516c77SSepherosa Ziehau 
1735*9c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
1736*9c6cae24SSepherosa Ziehau 		/*
1737*9c6cae24SSepherosa Ziehau 		 * Setup taskqueue for VF tasks, e.g. delayed VF bringing up.
1738*9c6cae24SSepherosa Ziehau 		 */
1739*9c6cae24SSepherosa Ziehau 		sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK,
1740*9c6cae24SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_vf_taskq);
1741*9c6cae24SSepherosa Ziehau 		taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf",
1742*9c6cae24SSepherosa Ziehau 		    device_get_nameunit(dev));
1743*9c6cae24SSepherosa Ziehau 		TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0,
1744*9c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_init_taskfunc, sc);
1745*9c6cae24SSepherosa Ziehau 	}
1746*9c6cae24SSepherosa Ziehau 
174715516c77SSepherosa Ziehau 	/*
174815516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
174915516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
175015516c77SSepherosa Ziehau 	 * ether_ifattach().
175115516c77SSepherosa Ziehau 	 */
175215516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
175315516c77SSepherosa Ziehau 	ifp->if_softc = sc;
175415516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
175515516c77SSepherosa Ziehau 
175615516c77SSepherosa Ziehau 	/*
175715516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
175815516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
175915516c77SSepherosa Ziehau 	 */
176015516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
176115516c77SSepherosa Ziehau 
176215516c77SSepherosa Ziehau 	/*
176315516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
176415516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
176515516c77SSepherosa Ziehau 	 *
176615516c77SSepherosa Ziehau 	 * NOTE:
176715516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
176815516c77SSepherosa Ziehau 	 */
176915516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
177015516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
177115516c77SSepherosa Ziehau 		/* Default */
177215516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
177315516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
177415516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
177515516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
177615516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
177715516c77SSepherosa Ziehau 	}
177834d68912SSepherosa Ziehau #ifdef RSS
177934d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
178034d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
178134d68912SSepherosa Ziehau #endif
178215516c77SSepherosa Ziehau 
178315516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
178415516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
178515516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
178623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
178715516c77SSepherosa Ziehau 	if (hn_use_if_start) {
178815516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
178915516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
179015516c77SSepherosa Ziehau 	}
179123bf9e15SSepherosa Ziehau #endif
179215516c77SSepherosa Ziehau 
179315516c77SSepherosa Ziehau 	/*
179415516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
179515516c77SSepherosa Ziehau 	 */
179615516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
179715516c77SSepherosa Ziehau 
179815516c77SSepherosa Ziehau 	/*
179915516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
180015516c77SSepherosa Ziehau 	 * channels can be allocated.
180115516c77SSepherosa Ziehau 	 */
180215516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
180315516c77SSepherosa Ziehau 	if (error)
180415516c77SSepherosa Ziehau 		goto failed;
180515516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
180615516c77SSepherosa Ziehau 	if (error)
180715516c77SSepherosa Ziehau 		goto failed;
180815516c77SSepherosa Ziehau 
180915516c77SSepherosa Ziehau 	/*
181015516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
181115516c77SSepherosa Ziehau 	 */
181215516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
181315516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
181425641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
181525641fc7SSepherosa Ziehau 		error = ENXIO;
181615516c77SSepherosa Ziehau 		goto failed;
181725641fc7SSepherosa Ziehau 	}
181825641fc7SSepherosa Ziehau 
181925641fc7SSepherosa Ziehau 	/*
182025641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
182125641fc7SSepherosa Ziehau 	 * primary channel.
182225641fc7SSepherosa Ziehau 	 *
182325641fc7SSepherosa Ziehau 	 * NOTE:
182425641fc7SSepherosa Ziehau 	 * The processing order is critical here:
182525641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
182625641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
182725641fc7SSepherosa Ziehau 	 */
182825641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
182925641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
183025641fc7SSepherosa Ziehau 		error = ENXIO;
183125641fc7SSepherosa Ziehau 		goto failed;
183225641fc7SSepherosa Ziehau 	}
183315516c77SSepherosa Ziehau 
183415516c77SSepherosa Ziehau 	/*
183515516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
183615516c77SSepherosa Ziehau 	 */
183715516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
183815516c77SSepherosa Ziehau 	if (error)
183915516c77SSepherosa Ziehau 		goto failed;
184015516c77SSepherosa Ziehau 
184115516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
184215516c77SSepherosa Ziehau 	if (error)
184315516c77SSepherosa Ziehau 		goto failed;
184415516c77SSepherosa Ziehau 
184515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
184615516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
184715516c77SSepherosa Ziehau 		/*
184815516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
184915516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
185015516c77SSepherosa Ziehau 		 */
185115516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
185215516c77SSepherosa Ziehau 	}
185315516c77SSepherosa Ziehau #endif
185415516c77SSepherosa Ziehau 
185515516c77SSepherosa Ziehau 	/*
185615516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
185715516c77SSepherosa Ziehau 	 */
185815516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
185915516c77SSepherosa Ziehau 
186015516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
186115516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
186215516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
186315516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
186415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
186515516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
186615516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
186715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
186815516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
186915516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
187015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
187115516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
187215516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
1873*9c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max",
1874*9c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size");
1875*9c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt",
1876*9c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0,
1877*9c6cae24SSepherosa Ziehau 	    "max # of TSO segments");
1878*9c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz",
1879*9c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0,
1880*9c6cae24SSepherosa Ziehau 	    "max size of TSO segment");
188115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
188215516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
188315516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
188415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
188515516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
188615516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
188715516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
188815516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
188934d68912SSepherosa Ziehau #ifndef RSS
189034d68912SSepherosa Ziehau 	/*
189134d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
189234d68912SSepherosa Ziehau 	 */
189315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
189415516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
189515516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
189615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
189715516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
189815516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
189934d68912SSepherosa Ziehau #endif
1900dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
1901dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
1902dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
1903dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
1904dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
1905dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
1906dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
1907dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
1908dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
1909dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
1910dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1911dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
1912dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
1913dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
1914dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1915dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
1916dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
1917dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
19186c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
19196c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
19206c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
19216c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
192240d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
192340d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
192440d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
1925*9c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
1926499c3e17SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf",
1927499c3e17SSepherosa Ziehau 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
1928499c3e17SSepherosa Ziehau 		    hn_rxvf_sysctl, "A", "activated Virtual Function's name");
1929*9c6cae24SSepherosa Ziehau 	} else {
1930*9c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled",
1931*9c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
1932*9c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_enabled_sysctl, "I",
1933*9c6cae24SSepherosa Ziehau 		    "Transparent VF enabled");
1934*9c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf",
1935*9c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1936*9c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_accbpf_sysctl, "I",
1937*9c6cae24SSepherosa Ziehau 		    "Accurate BPF for transparent VF");
1938*9c6cae24SSepherosa Ziehau 	}
193915516c77SSepherosa Ziehau 
194015516c77SSepherosa Ziehau 	/*
194115516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
194215516c77SSepherosa Ziehau 	 */
194315516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
194415516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
194515516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
194615516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
194715516c77SSepherosa Ziehau 
194815516c77SSepherosa Ziehau 	/*
194915516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
195015516c77SSepherosa Ziehau 	 */
195115516c77SSepherosa Ziehau 
195215516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
195315516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
195415516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
195515516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
195623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
195715516c77SSepherosa Ziehau 	if (hn_use_if_start) {
195815516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
195915516c77SSepherosa Ziehau 
196015516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
196115516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
196215516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
196315516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
196423bf9e15SSepherosa Ziehau 	} else
196523bf9e15SSepherosa Ziehau #endif
196623bf9e15SSepherosa Ziehau 	{
196715516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
196815516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
196915516c77SSepherosa Ziehau 	}
197015516c77SSepherosa Ziehau 
1971*9c6cae24SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE;
197215516c77SSepherosa Ziehau #ifdef foo
197315516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
197415516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
197515516c77SSepherosa Ziehau #endif
197615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
197715516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
197815516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
197915516c77SSepherosa Ziehau 	}
198015516c77SSepherosa Ziehau 
198115516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
198215516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
198315516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
198415516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
198515516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
198615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
198715516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
198815516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
198915516c77SSepherosa Ziehau 	}
199015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
199115516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
199215516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
199315516c77SSepherosa Ziehau 	}
199415516c77SSepherosa Ziehau 
199515516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
199615516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
199715516c77SSepherosa Ziehau 
19987960e6baSSepherosa Ziehau 	/*
19997960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
20007960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
20017960e6baSSepherosa Ziehau 	 */
20027960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
20037960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
20047960e6baSSepherosa Ziehau 
200515516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
2006*9c6cae24SSepherosa Ziehau 		/*
2007*9c6cae24SSepherosa Ziehau 		 * Lock hn_set_tso_maxsize() to simplify its
2008*9c6cae24SSepherosa Ziehau 		 * internal logic.
2009*9c6cae24SSepherosa Ziehau 		 */
2010*9c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
201115516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
2012*9c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
201315516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
201415516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
201515516c77SSepherosa Ziehau 	}
201615516c77SSepherosa Ziehau 
201715516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
201815516c77SSepherosa Ziehau 
201915516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
202015516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
202115516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
202215516c77SSepherosa Ziehau 	}
202315516c77SSepherosa Ziehau 
202415516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
202515516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
202615516c77SSepherosa Ziehau 
202715516c77SSepherosa Ziehau 	/*
202815516c77SSepherosa Ziehau 	 * Kick off link status check.
202915516c77SSepherosa Ziehau 	 */
203015516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
203115516c77SSepherosa Ziehau 	hn_update_link_status(sc);
203215516c77SSepherosa Ziehau 
2033*9c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
20345bdfd3fdSDexuan Cui 		sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
20355bdfd3fdSDexuan Cui 		    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
20365bdfd3fdSDexuan Cui 		sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
20375bdfd3fdSDexuan Cui 		    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
2038*9c6cae24SSepherosa Ziehau 	} else {
2039*9c6cae24SSepherosa Ziehau 		sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event,
2040*9c6cae24SSepherosa Ziehau 		    hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY);
2041*9c6cae24SSepherosa Ziehau 	}
20425bdfd3fdSDexuan Cui 
2043f41e0df4SSepherosa Ziehau 	/*
2044f41e0df4SSepherosa Ziehau 	 * NOTE:
2045f41e0df4SSepherosa Ziehau 	 * Subscribe ether_ifattach event, instead of ifnet_arrival event,
2046f41e0df4SSepherosa Ziehau 	 * since interface's LLADDR is needed; interface LLADDR is not
2047f41e0df4SSepherosa Ziehau 	 * available when ifnet_arrival event is triggered.
2048f41e0df4SSepherosa Ziehau 	 */
2049499c3e17SSepherosa Ziehau 	sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event,
2050499c3e17SSepherosa Ziehau 	    hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY);
2051499c3e17SSepherosa Ziehau 	sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event,
2052499c3e17SSepherosa Ziehau 	    hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY);
2053499c3e17SSepherosa Ziehau 
205415516c77SSepherosa Ziehau 	return (0);
205515516c77SSepherosa Ziehau failed:
205615516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
205715516c77SSepherosa Ziehau 		hn_synth_detach(sc);
205815516c77SSepherosa Ziehau 	hn_detach(dev);
205915516c77SSepherosa Ziehau 	return (error);
206015516c77SSepherosa Ziehau }
206115516c77SSepherosa Ziehau 
206215516c77SSepherosa Ziehau static int
206315516c77SSepherosa Ziehau hn_detach(device_t dev)
206415516c77SSepherosa Ziehau {
206515516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
2066499c3e17SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp, *vf_ifp;
206715516c77SSepherosa Ziehau 
2068*9c6cae24SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
2069*9c6cae24SSepherosa Ziehau 		/*
2070*9c6cae24SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
2071*9c6cae24SSepherosa Ziehau 		 * installation.
2072*9c6cae24SSepherosa Ziehau 		 */
2073*9c6cae24SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
2074*9c6cae24SSepherosa Ziehau 	}
2075*9c6cae24SSepherosa Ziehau 
20765bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
20775bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
20785bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
20795bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
2080499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_atthand != NULL) {
2081499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ether_ifattach_event,
2082499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_atthand);
2083499c3e17SSepherosa Ziehau 	}
2084499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_dethand != NULL) {
2085499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
2086499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_dethand);
2087499c3e17SSepherosa Ziehau 	}
2088*9c6cae24SSepherosa Ziehau 	if (sc->hn_ifnet_lnkhand != NULL)
2089*9c6cae24SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand);
2090499c3e17SSepherosa Ziehau 
2091499c3e17SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
2092499c3e17SSepherosa Ziehau 	__compiler_membar();
2093499c3e17SSepherosa Ziehau 	if (vf_ifp != NULL)
2094499c3e17SSepherosa Ziehau 		hn_ifnet_detevent(sc, vf_ifp);
20955bdfd3fdSDexuan Cui 
209615516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
209715516c77SSepherosa Ziehau 		HN_LOCK(sc);
209815516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
209915516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
21005bdfd3fdSDexuan Cui 				hn_stop(sc, true);
210115516c77SSepherosa Ziehau 			/*
210215516c77SSepherosa Ziehau 			 * NOTE:
210315516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
210415516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
210515516c77SSepherosa Ziehau 			 */
210615516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
210715516c77SSepherosa Ziehau 			hn_synth_detach(sc);
210815516c77SSepherosa Ziehau 		}
210915516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
211015516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
211115516c77SSepherosa Ziehau 	}
211215516c77SSepherosa Ziehau 
211315516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
211415516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
211515516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
211615516c77SSepherosa Ziehau 
21170e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
2118fdd0222aSSepherosa Ziehau 		int i;
2119fdd0222aSSepherosa Ziehau 
2120fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
2121fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
2122fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
2123fdd0222aSSepherosa Ziehau 	}
212415516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
2125*9c6cae24SSepherosa Ziehau 	if (sc->hn_vf_taskq != NULL)
2126*9c6cae24SSepherosa Ziehau 		taskqueue_free(sc->hn_vf_taskq);
212715516c77SSepherosa Ziehau 
212825641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
212925641fc7SSepherosa Ziehau 		/*
213025641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
213125641fc7SSepherosa Ziehau 		 * destructed.
213225641fc7SSepherosa Ziehau 		 */
213325641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
213415516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
213525641fc7SSepherosa Ziehau 	}
213615516c77SSepherosa Ziehau 
213715516c77SSepherosa Ziehau 	if_free(ifp);
213815516c77SSepherosa Ziehau 
213915516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
2140*9c6cae24SSepherosa Ziehau 	rm_destroy(&sc->hn_vf_lock);
214115516c77SSepherosa Ziehau 	return (0);
214215516c77SSepherosa Ziehau }
214315516c77SSepherosa Ziehau 
214415516c77SSepherosa Ziehau static int
214515516c77SSepherosa Ziehau hn_shutdown(device_t dev)
214615516c77SSepherosa Ziehau {
214715516c77SSepherosa Ziehau 
214815516c77SSepherosa Ziehau 	return (0);
214915516c77SSepherosa Ziehau }
215015516c77SSepherosa Ziehau 
215115516c77SSepherosa Ziehau static void
215215516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
215315516c77SSepherosa Ziehau {
215415516c77SSepherosa Ziehau 	uint32_t link_status;
215515516c77SSepherosa Ziehau 	int error;
215615516c77SSepherosa Ziehau 
215715516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
215815516c77SSepherosa Ziehau 	if (error) {
215915516c77SSepherosa Ziehau 		/* XXX what to do? */
216015516c77SSepherosa Ziehau 		return;
216115516c77SSepherosa Ziehau 	}
216215516c77SSepherosa Ziehau 
216315516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
216415516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
216515516c77SSepherosa Ziehau 	else
216615516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
216715516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
216815516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
216915516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
217015516c77SSepherosa Ziehau }
217115516c77SSepherosa Ziehau 
217215516c77SSepherosa Ziehau static void
217315516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
217415516c77SSepherosa Ziehau {
217515516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
217615516c77SSepherosa Ziehau 
217715516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
217815516c77SSepherosa Ziehau 		return;
217915516c77SSepherosa Ziehau 	hn_link_status(sc);
218015516c77SSepherosa Ziehau }
218115516c77SSepherosa Ziehau 
218215516c77SSepherosa Ziehau static void
218315516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
218415516c77SSepherosa Ziehau {
218515516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
218615516c77SSepherosa Ziehau 
218715516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
218815516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
218915516c77SSepherosa Ziehau 
219015516c77SSepherosa Ziehau 	/*
219115516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
219215516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
219315516c77SSepherosa Ziehau 	 * upon link down event.
219415516c77SSepherosa Ziehau 	 */
219515516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
219615516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
219715516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
219815516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
219915516c77SSepherosa Ziehau }
220015516c77SSepherosa Ziehau 
220115516c77SSepherosa Ziehau static void
220215516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
220315516c77SSepherosa Ziehau {
220415516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
220515516c77SSepherosa Ziehau 
220615516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
220715516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
220815516c77SSepherosa Ziehau 	hn_link_status(sc);
220915516c77SSepherosa Ziehau }
221015516c77SSepherosa Ziehau 
221115516c77SSepherosa Ziehau static void
221215516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
221315516c77SSepherosa Ziehau {
221415516c77SSepherosa Ziehau 
221515516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
221615516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
221715516c77SSepherosa Ziehau }
221815516c77SSepherosa Ziehau 
221915516c77SSepherosa Ziehau static void
222015516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
222115516c77SSepherosa Ziehau {
222215516c77SSepherosa Ziehau 
222315516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
222415516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
222515516c77SSepherosa Ziehau }
222615516c77SSepherosa Ziehau 
222715516c77SSepherosa Ziehau static __inline int
222815516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
222915516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
223015516c77SSepherosa Ziehau {
223115516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
223215516c77SSepherosa Ziehau 	int error;
223315516c77SSepherosa Ziehau 
223415516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
223515516c77SSepherosa Ziehau 
223615516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
223715516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
223815516c77SSepherosa Ziehau 	if (error == EFBIG) {
223915516c77SSepherosa Ziehau 		struct mbuf *m_new;
224015516c77SSepherosa Ziehau 
224115516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
224215516c77SSepherosa Ziehau 		if (m_new == NULL)
224315516c77SSepherosa Ziehau 			return ENOBUFS;
224415516c77SSepherosa Ziehau 		else
224515516c77SSepherosa Ziehau 			*m_head = m = m_new;
224615516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
224715516c77SSepherosa Ziehau 
224815516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
224915516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
225015516c77SSepherosa Ziehau 	}
225115516c77SSepherosa Ziehau 	if (!error) {
225215516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
225315516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
225415516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
225515516c77SSepherosa Ziehau 	}
225615516c77SSepherosa Ziehau 	return error;
225715516c77SSepherosa Ziehau }
225815516c77SSepherosa Ziehau 
225915516c77SSepherosa Ziehau static __inline int
226015516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
226115516c77SSepherosa Ziehau {
226215516c77SSepherosa Ziehau 
226315516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
226415516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
2265dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2266dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
226715516c77SSepherosa Ziehau 
226815516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
226915516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
227015516c77SSepherosa Ziehau 		return 0;
227115516c77SSepherosa Ziehau 
2272dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
2273dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
2274dc13fee6SSepherosa Ziehau 
2275dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
2276dc13fee6SSepherosa Ziehau 			int freed;
2277dc13fee6SSepherosa Ziehau 
2278dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
2279dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
2280dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
2281dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
2282dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
2283dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
2284dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
2285dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
2286dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
2287dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
2288dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
2289dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
2290dc13fee6SSepherosa Ziehau 
2291dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
2292dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
2293dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
2294dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
2295dc13fee6SSepherosa Ziehau 		}
2296dc13fee6SSepherosa Ziehau 	}
2297dc13fee6SSepherosa Ziehau 
229815516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
229915516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
230015516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
230115516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
230215516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
2303dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
230415516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
230515516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
230615516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
230715516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
230815516c77SSepherosa Ziehau 		    txd->data_dmap);
230915516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
231015516c77SSepherosa Ziehau 	}
231115516c77SSepherosa Ziehau 
231215516c77SSepherosa Ziehau 	if (txd->m != NULL) {
231315516c77SSepherosa Ziehau 		m_freem(txd->m);
231415516c77SSepherosa Ziehau 		txd->m = NULL;
231515516c77SSepherosa Ziehau 	}
231615516c77SSepherosa Ziehau 
231715516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
231815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
231915516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
232015516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
232115516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
232215516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
232315516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
232415516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
232515516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
232685e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
232785e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
232815516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
232915516c77SSepherosa Ziehau #endif
233085e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
233185e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
233215516c77SSepherosa Ziehau 
233315516c77SSepherosa Ziehau 	return 1;
233415516c77SSepherosa Ziehau }
233515516c77SSepherosa Ziehau 
233615516c77SSepherosa Ziehau static __inline struct hn_txdesc *
233715516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
233815516c77SSepherosa Ziehau {
233915516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
234015516c77SSepherosa Ziehau 
234115516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
234215516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
234315516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
234415516c77SSepherosa Ziehau 	if (txd != NULL) {
234515516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
234615516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
234715516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
234815516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
234915516c77SSepherosa Ziehau 	}
235015516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
235115516c77SSepherosa Ziehau #else
235215516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
235315516c77SSepherosa Ziehau #endif
235415516c77SSepherosa Ziehau 
235515516c77SSepherosa Ziehau 	if (txd != NULL) {
235615516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
235785e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
235815516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
235915516c77SSepherosa Ziehau #endif
236085e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
236115516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
2362dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
236315516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
2364dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
236515516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
2366dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
236715516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
236815516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
236915516c77SSepherosa Ziehau 		txd->refs = 1;
237015516c77SSepherosa Ziehau 	}
237115516c77SSepherosa Ziehau 	return txd;
237215516c77SSepherosa Ziehau }
237315516c77SSepherosa Ziehau 
237415516c77SSepherosa Ziehau static __inline void
237515516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
237615516c77SSepherosa Ziehau {
237715516c77SSepherosa Ziehau 
237815516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
237925641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
238015516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
238115516c77SSepherosa Ziehau }
238215516c77SSepherosa Ziehau 
2383dc13fee6SSepherosa Ziehau static __inline void
2384dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
2385dc13fee6SSepherosa Ziehau {
2386dc13fee6SSepherosa Ziehau 
2387dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2388dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
2389dc13fee6SSepherosa Ziehau 
2390dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2391dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
2392dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
2393dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
2394dc13fee6SSepherosa Ziehau 
2395dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
2396dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
2397dc13fee6SSepherosa Ziehau }
2398dc13fee6SSepherosa Ziehau 
239915516c77SSepherosa Ziehau static bool
240015516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
240115516c77SSepherosa Ziehau {
240215516c77SSepherosa Ziehau 	bool pending = false;
240315516c77SSepherosa Ziehau 
240415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
240515516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
240615516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
240715516c77SSepherosa Ziehau 		pending = true;
240815516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
240915516c77SSepherosa Ziehau #else
241015516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
241115516c77SSepherosa Ziehau 		pending = true;
241215516c77SSepherosa Ziehau #endif
241315516c77SSepherosa Ziehau 	return (pending);
241415516c77SSepherosa Ziehau }
241515516c77SSepherosa Ziehau 
241615516c77SSepherosa Ziehau static __inline void
241715516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
241815516c77SSepherosa Ziehau {
241915516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
242015516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
242115516c77SSepherosa Ziehau }
242215516c77SSepherosa Ziehau 
242315516c77SSepherosa Ziehau static void
242415516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
242515516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
242615516c77SSepherosa Ziehau {
242715516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
242815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
242915516c77SSepherosa Ziehau 
243015516c77SSepherosa Ziehau 	txr = txd->txr;
243115516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
243215516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
2433aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
243415516c77SSepherosa Ziehau 
243515516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
243615516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
243715516c77SSepherosa Ziehau 
243815516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
243915516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
244015516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
244115516c77SSepherosa Ziehau 		if (txr->hn_oactive)
244215516c77SSepherosa Ziehau 			hn_txeof(txr);
244315516c77SSepherosa Ziehau 	}
244415516c77SSepherosa Ziehau }
244515516c77SSepherosa Ziehau 
244615516c77SSepherosa Ziehau static void
244715516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
244815516c77SSepherosa Ziehau {
244915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
245015516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
245115516c77SSepherosa Ziehau #endif
245215516c77SSepherosa Ziehau 
245315516c77SSepherosa Ziehau 	/*
245415516c77SSepherosa Ziehau 	 * NOTE:
245515516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
245615516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
245715516c77SSepherosa Ziehau 	 */
245815516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
245915516c77SSepherosa Ziehau 		return;
246015516c77SSepherosa Ziehau 
246115516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
246215516c77SSepherosa Ziehau 	hn_txeof(txr);
246315516c77SSepherosa Ziehau }
246415516c77SSepherosa Ziehau 
246515516c77SSepherosa Ziehau static __inline uint32_t
246615516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
246715516c77SSepherosa Ziehau {
246815516c77SSepherosa Ziehau 
246915516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
247015516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
247115516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
247215516c77SSepherosa Ziehau }
247315516c77SSepherosa Ziehau 
247415516c77SSepherosa Ziehau static __inline void *
247515516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
247615516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
247715516c77SSepherosa Ziehau {
247815516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
247915516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
248015516c77SSepherosa Ziehau 
248115516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
248215516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
248315516c77SSepherosa Ziehau 
248415516c77SSepherosa Ziehau 	/*
248515516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
248615516c77SSepherosa Ziehau 	 *
248715516c77SSepherosa Ziehau 	 * NOTE:
248815516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
248915516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
249015516c77SSepherosa Ziehau 	 */
249115516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
249215516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
249315516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
249415516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
249515516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
249615516c77SSepherosa Ziehau 
249715516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
249815516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
249915516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
250015516c77SSepherosa Ziehau 
250115516c77SSepherosa Ziehau 	return (pi->rm_data);
250215516c77SSepherosa Ziehau }
250315516c77SSepherosa Ziehau 
2504dc13fee6SSepherosa Ziehau static __inline int
2505dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
2506dc13fee6SSepherosa Ziehau {
2507dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
2508dc13fee6SSepherosa Ziehau 	struct mbuf *m;
2509dc13fee6SSepherosa Ziehau 	int error, pkts;
2510dc13fee6SSepherosa Ziehau 
2511dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
2512dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
2513dc13fee6SSepherosa Ziehau 
2514dc13fee6SSepherosa Ziehau 	/*
2515dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
2516dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
2517dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
2518dc13fee6SSepherosa Ziehau 	 */
2519dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
2520dc13fee6SSepherosa Ziehau 
2521dc13fee6SSepherosa Ziehau 	/*
2522dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
2523dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
2524dc13fee6SSepherosa Ziehau 	 * fails.
2525dc13fee6SSepherosa Ziehau 	 */
2526dc13fee6SSepherosa Ziehau 	m = txd->m;
2527dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
2528dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
2529dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
2530dc13fee6SSepherosa Ziehau 		m_freem(m);
2531dc13fee6SSepherosa Ziehau 
2532dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
2533dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
2534dc13fee6SSepherosa Ziehau 	}
2535dc13fee6SSepherosa Ziehau 
2536dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
2537dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
2538dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
2539dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
2540dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
2541dc13fee6SSepherosa Ziehau 
2542dc13fee6SSepherosa Ziehau 	return (error);
2543dc13fee6SSepherosa Ziehau }
2544dc13fee6SSepherosa Ziehau 
2545dc13fee6SSepherosa Ziehau static void *
2546dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2547dc13fee6SSepherosa Ziehau     int pktsize)
2548dc13fee6SSepherosa Ziehau {
2549dc13fee6SSepherosa Ziehau 	void *chim;
2550dc13fee6SSepherosa Ziehau 
2551dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
2552dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
2553dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
2554dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
2555dc13fee6SSepherosa Ziehau 			int olen;
2556dc13fee6SSepherosa Ziehau 
2557dc13fee6SSepherosa Ziehau 			/*
2558dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
2559dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
2560dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
2561dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
2562dc13fee6SSepherosa Ziehau 			 * accordingly.
2563dc13fee6SSepherosa Ziehau 			 *
2564dc13fee6SSepherosa Ziehau 			 * XXX
2565dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
2566dc13fee6SSepherosa Ziehau 			 */
2567dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
2568dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
2569dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
2570dc13fee6SSepherosa Ziehau 
2571dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
2572dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
2573dc13fee6SSepherosa Ziehau 
2574dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
2575dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
2576dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
2577dc13fee6SSepherosa Ziehau 
2578dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
2579dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
2580dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
2581dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
2582dc13fee6SSepherosa Ziehau 				/*
2583dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
2584dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
2585dc13fee6SSepherosa Ziehau 				 */
2586dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
2587dc13fee6SSepherosa Ziehau 			}
2588dc13fee6SSepherosa Ziehau 			/* Done! */
2589dc13fee6SSepherosa Ziehau 			return (chim);
2590dc13fee6SSepherosa Ziehau 		}
2591dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
2592dc13fee6SSepherosa Ziehau 	}
2593dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
2594dc13fee6SSepherosa Ziehau 
2595dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
2596dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
2597dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
2598dc13fee6SSepherosa Ziehau 		return (NULL);
2599dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
2600dc13fee6SSepherosa Ziehau 
2601dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
2602dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
2603dc13fee6SSepherosa Ziehau 
2604dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
2605dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
2606dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
2607dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
2608dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
2609dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
2610dc13fee6SSepherosa Ziehau 	}
2611dc13fee6SSepherosa Ziehau 	return (chim);
2612dc13fee6SSepherosa Ziehau }
2613dc13fee6SSepherosa Ziehau 
261415516c77SSepherosa Ziehau /*
261515516c77SSepherosa Ziehau  * NOTE:
261615516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
261715516c77SSepherosa Ziehau  */
261815516c77SSepherosa Ziehau static int
2619dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2620dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
262115516c77SSepherosa Ziehau {
262215516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
262315516c77SSepherosa Ziehau 	int error, nsegs, i;
262415516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
262515516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
262615516c77SSepherosa Ziehau 	uint32_t *pi_data;
26278966e5d5SSepherosa Ziehau 	void *chim = NULL;
2628dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
262915516c77SSepherosa Ziehau 
263015516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
2631dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
2632dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
2633dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
2634dc13fee6SSepherosa Ziehau 		if (chim != NULL)
26358966e5d5SSepherosa Ziehau 			pkt = chim;
2636dc13fee6SSepherosa Ziehau 	} else {
2637dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
2638dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
26398966e5d5SSepherosa Ziehau 	}
26408966e5d5SSepherosa Ziehau 
264115516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
26428fe90f73SSepherosa Ziehau 	pkt->rm_len = m_head->m_pkthdr.len;
26439130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = 0;
264415516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
2645dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
2646dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
2647dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
264815516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
264915516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
2650dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
2651dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
265215516c77SSepherosa Ziehau 
265315516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
265415516c77SSepherosa Ziehau 		/*
265515516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
265615516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
265715516c77SSepherosa Ziehau 		 * ring's channel.
265815516c77SSepherosa Ziehau 		 */
265915516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
266015516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
266115516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
266215516c77SSepherosa Ziehau 	}
266315516c77SSepherosa Ziehau 
266415516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
266515516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
266615516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
266715516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
266815516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
266915516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
267015516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
267115516c77SSepherosa Ziehau 	}
267215516c77SSepherosa Ziehau 
267315516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
267415516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
267515516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
267615516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
267715516c77SSepherosa Ziehau #ifdef INET
267815516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
267915516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
268015516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
268115516c77SSepherosa Ziehau 		}
268215516c77SSepherosa Ziehau #endif
268315516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
268415516c77SSepherosa Ziehau 		else
268515516c77SSepherosa Ziehau #endif
268615516c77SSepherosa Ziehau #ifdef INET6
268715516c77SSepherosa Ziehau 		{
268815516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
268915516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
269015516c77SSepherosa Ziehau 		}
269115516c77SSepherosa Ziehau #endif
269215516c77SSepherosa Ziehau #endif	/* INET6 || INET */
269315516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
269415516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
269515516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
269615516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
269715516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
269815516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
269915516c77SSepherosa Ziehau 		} else {
270015516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
270115516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
270215516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
270315516c77SSepherosa Ziehau 		}
270415516c77SSepherosa Ziehau 
270515516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
270615516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
270715516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
270815516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
270915516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
271015516c77SSepherosa Ziehau 	}
271115516c77SSepherosa Ziehau 
2712dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
27138fe90f73SSepherosa Ziehau 	/* Fixup RNDIS packet message total length */
27148fe90f73SSepherosa Ziehau 	pkt->rm_len += pkt_hlen;
271515516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
27169130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);
271715516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
271815516c77SSepherosa Ziehau 
271915516c77SSepherosa Ziehau 	/*
27208966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
272115516c77SSepherosa Ziehau 	 */
27228966e5d5SSepherosa Ziehau 	if (chim != NULL) {
2723dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
2724dc13fee6SSepherosa Ziehau 
2725dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
2726dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
2727dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
2728dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
2729dc13fee6SSepherosa Ziehau #endif
2730dc13fee6SSepherosa Ziehau 		}
2731dc13fee6SSepherosa Ziehau 
2732dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
2733dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
2734dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
2735dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
2736dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
273715516c77SSepherosa Ziehau 
27388966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
2739dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
274015516c77SSepherosa Ziehau 
274115516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
274215516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
274315516c77SSepherosa Ziehau 		goto done;
274415516c77SSepherosa Ziehau 	}
2745dc13fee6SSepherosa Ziehau 
2746dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
27478966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
27488966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
27498966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
275015516c77SSepherosa Ziehau 
275115516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
2752dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
275315516c77SSepherosa Ziehau 		int freed;
275415516c77SSepherosa Ziehau 
275515516c77SSepherosa Ziehau 		/*
275615516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
275715516c77SSepherosa Ziehau 		 */
275815516c77SSepherosa Ziehau 		m_freem(m_head);
275915516c77SSepherosa Ziehau 		*m_head0 = NULL;
276015516c77SSepherosa Ziehau 
276115516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
276215516c77SSepherosa Ziehau 		KASSERT(freed != 0,
276315516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
276415516c77SSepherosa Ziehau 
276515516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
2766dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
276715516c77SSepherosa Ziehau 		return error;
276815516c77SSepherosa Ziehau 	}
276915516c77SSepherosa Ziehau 	*m_head0 = m_head;
277015516c77SSepherosa Ziehau 
277115516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
277215516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
277315516c77SSepherosa Ziehau 
277415516c77SSepherosa Ziehau 	/* send packet with page buffer */
277515516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
277615516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
2777dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
277815516c77SSepherosa Ziehau 
277915516c77SSepherosa Ziehau 	/*
278015516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
278115516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
278215516c77SSepherosa Ziehau 	 */
278315516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
278415516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
278515516c77SSepherosa Ziehau 
278615516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
278715516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
278815516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
278915516c77SSepherosa Ziehau 	}
279015516c77SSepherosa Ziehau 
279115516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
279215516c77SSepherosa Ziehau 	txd->chim_size = 0;
279315516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
279415516c77SSepherosa Ziehau done:
279515516c77SSepherosa Ziehau 	txd->m = m_head;
279615516c77SSepherosa Ziehau 
279715516c77SSepherosa Ziehau 	/* Set the completion routine */
279815516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
279915516c77SSepherosa Ziehau 
2800dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
2801dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
2802dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
2803dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
2804dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
2805dc13fee6SSepherosa Ziehau 
280615516c77SSepherosa Ziehau 	return 0;
280715516c77SSepherosa Ziehau }
280815516c77SSepherosa Ziehau 
280915516c77SSepherosa Ziehau /*
281015516c77SSepherosa Ziehau  * NOTE:
281115516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
281215516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
281315516c77SSepherosa Ziehau  */
281415516c77SSepherosa Ziehau static int
281515516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
281615516c77SSepherosa Ziehau {
28178e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
281815516c77SSepherosa Ziehau 
281915516c77SSepherosa Ziehau again:
28208e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
28218e7d3136SSepherosa Ziehau 	if (has_bpf) {
282215516c77SSepherosa Ziehau 		/*
28238e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
28248e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
282515516c77SSepherosa Ziehau 		 */
282615516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
28278e7d3136SSepherosa Ziehau 	}
282815516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
282915516c77SSepherosa Ziehau 	if (!error) {
28308e7d3136SSepherosa Ziehau 		if (has_bpf) {
2831dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
2832dc13fee6SSepherosa Ziehau 
283315516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
2834dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
2835dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
2836dc13fee6SSepherosa Ziehau 		}
2837dc13fee6SSepherosa Ziehau 
2838dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
283923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
284023bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
284123bf9e15SSepherosa Ziehau #endif
284223bf9e15SSepherosa Ziehau 		{
284315516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
2844dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
2845dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
2846dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
2847dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
284815516c77SSepherosa Ziehau 			}
2849dc13fee6SSepherosa Ziehau 		}
2850dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
2851dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
285215516c77SSepherosa Ziehau 	}
28538e7d3136SSepherosa Ziehau 	if (has_bpf)
285415516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
285515516c77SSepherosa Ziehau 
285615516c77SSepherosa Ziehau 	if (__predict_false(error)) {
285715516c77SSepherosa Ziehau 		int freed;
285815516c77SSepherosa Ziehau 
285915516c77SSepherosa Ziehau 		/*
286015516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
286115516c77SSepherosa Ziehau 		 *
286215516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
286315516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
286415516c77SSepherosa Ziehau 		 * to kick start later.
286515516c77SSepherosa Ziehau 		 */
286615516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
286715516c77SSepherosa Ziehau 		if (!send_failed) {
286815516c77SSepherosa Ziehau 			txr->hn_send_failed++;
286915516c77SSepherosa Ziehau 			send_failed = 1;
287015516c77SSepherosa Ziehau 			/*
287115516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
287215516c77SSepherosa Ziehau 			 * in case that we missed the last
287315516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
287415516c77SSepherosa Ziehau 			 */
287515516c77SSepherosa Ziehau 			goto again;
287615516c77SSepherosa Ziehau 		}
287715516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
287815516c77SSepherosa Ziehau 
287915516c77SSepherosa Ziehau 		/*
288015516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
288115516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
288215516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
288315516c77SSepherosa Ziehau 		 * if it was loaded.
288415516c77SSepherosa Ziehau 		 */
288515516c77SSepherosa Ziehau 		txd->m = NULL;
288615516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
288715516c77SSepherosa Ziehau 		KASSERT(freed != 0,
288815516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
288915516c77SSepherosa Ziehau 
289015516c77SSepherosa Ziehau 		txr->hn_send_failed++;
289115516c77SSepherosa Ziehau 	}
2892dc13fee6SSepherosa Ziehau 
2893dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
2894dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
2895dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
2896dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
2897dc13fee6SSepherosa Ziehau 
2898dc13fee6SSepherosa Ziehau 	return (error);
289915516c77SSepherosa Ziehau }
290015516c77SSepherosa Ziehau 
290115516c77SSepherosa Ziehau /*
290215516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
290315516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
290415516c77SSepherosa Ziehau  * existing space.
290515516c77SSepherosa Ziehau  *
290615516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
290715516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
290815516c77SSepherosa Ziehau  * but there does not appear to be one yet.
290915516c77SSepherosa Ziehau  *
291015516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
291115516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
291215516c77SSepherosa Ziehau  * accordingly.
291315516c77SSepherosa Ziehau  *
291415516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
291515516c77SSepherosa Ziehau  */
291615516c77SSepherosa Ziehau static int
291715516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
291815516c77SSepherosa Ziehau {
291915516c77SSepherosa Ziehau 	struct mbuf *m, *n;
292015516c77SSepherosa Ziehau 	int remainder, space;
292115516c77SSepherosa Ziehau 
292215516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
292315516c77SSepherosa Ziehau 		;
292415516c77SSepherosa Ziehau 	remainder = len;
292515516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
292615516c77SSepherosa Ziehau 	if (space > 0) {
292715516c77SSepherosa Ziehau 		/*
292815516c77SSepherosa Ziehau 		 * Copy into available space.
292915516c77SSepherosa Ziehau 		 */
293015516c77SSepherosa Ziehau 		if (space > remainder)
293115516c77SSepherosa Ziehau 			space = remainder;
293215516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
293315516c77SSepherosa Ziehau 		m->m_len += space;
293415516c77SSepherosa Ziehau 		cp += space;
293515516c77SSepherosa Ziehau 		remainder -= space;
293615516c77SSepherosa Ziehau 	}
293715516c77SSepherosa Ziehau 	while (remainder > 0) {
293815516c77SSepherosa Ziehau 		/*
293915516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
294015516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
294115516c77SSepherosa Ziehau 		 */
294215516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
294315516c77SSepherosa Ziehau 		if (n == NULL)
294415516c77SSepherosa Ziehau 			break;
294515516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
294615516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
294715516c77SSepherosa Ziehau 		cp += n->m_len;
294815516c77SSepherosa Ziehau 		remainder -= n->m_len;
294915516c77SSepherosa Ziehau 		m->m_next = n;
295015516c77SSepherosa Ziehau 		m = n;
295115516c77SSepherosa Ziehau 	}
295215516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
295315516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
295415516c77SSepherosa Ziehau 
295515516c77SSepherosa Ziehau 	return (remainder == 0);
295615516c77SSepherosa Ziehau }
295715516c77SSepherosa Ziehau 
295815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
295915516c77SSepherosa Ziehau static __inline int
296015516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
296115516c77SSepherosa Ziehau {
296215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
296315516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
296415516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
296515516c77SSepherosa Ziehau 		return 0;
296615516c77SSepherosa Ziehau 	}
296715516c77SSepherosa Ziehau #endif
296815516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
296915516c77SSepherosa Ziehau }
297015516c77SSepherosa Ziehau #endif
297115516c77SSepherosa Ziehau 
297215516c77SSepherosa Ziehau static int
297315516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
297415516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
297515516c77SSepherosa Ziehau {
29765bdfd3fdSDexuan Cui 	struct ifnet *ifp;
297715516c77SSepherosa Ziehau 	struct mbuf *m_new;
297815516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
297915516c77SSepherosa Ziehau 	int hash_type;
298015516c77SSepherosa Ziehau 
29815bdfd3fdSDexuan Cui 	/* If the VF is active, inject the packet through the VF */
2982499c3e17SSepherosa Ziehau 	ifp = rxr->hn_rxvf_ifp ? rxr->hn_rxvf_ifp : rxr->hn_ifp;
29835bdfd3fdSDexuan Cui 
2984b3b75d9cSSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
2985b3b75d9cSSepherosa Ziehau 		/*
2986b3b75d9cSSepherosa Ziehau 		 * NOTE:
2987b3b75d9cSSepherosa Ziehau 		 * See the NOTE of hn_rndis_init_fixat().  This
2988b3b75d9cSSepherosa Ziehau 		 * function can be reached, immediately after the
2989b3b75d9cSSepherosa Ziehau 		 * RNDIS is initialized but before the ifnet is
2990b3b75d9cSSepherosa Ziehau 		 * setup on the hn_attach() path; drop the unexpected
2991b3b75d9cSSepherosa Ziehau 		 * packets.
2992b3b75d9cSSepherosa Ziehau 		 */
2993b3b75d9cSSepherosa Ziehau 		return (0);
2994b3b75d9cSSepherosa Ziehau 	}
2995b3b75d9cSSepherosa Ziehau 
2996c927d681SDexuan Cui 	if (dlen <= MHLEN) {
299715516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
299815516c77SSepherosa Ziehau 		if (m_new == NULL) {
299915516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
300015516c77SSepherosa Ziehau 			return (0);
300115516c77SSepherosa Ziehau 		}
300215516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
300315516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
300415516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
300515516c77SSepherosa Ziehau 	} else {
300615516c77SSepherosa Ziehau 		/*
300715516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
300815516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
300915516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
301015516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
301115516c77SSepherosa Ziehau 		 */
301215516c77SSepherosa Ziehau 		size = MCLBYTES;
301315516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
301415516c77SSepherosa Ziehau 			/* 4096 */
301515516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
301615516c77SSepherosa Ziehau 		}
301715516c77SSepherosa Ziehau 
301815516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
301915516c77SSepherosa Ziehau 		if (m_new == NULL) {
302015516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
302115516c77SSepherosa Ziehau 			return (0);
302215516c77SSepherosa Ziehau 		}
302315516c77SSepherosa Ziehau 
302415516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
302515516c77SSepherosa Ziehau 	}
302615516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
302715516c77SSepherosa Ziehau 
302815516c77SSepherosa Ziehau 	if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0))
302915516c77SSepherosa Ziehau 		do_csum = 0;
303015516c77SSepherosa Ziehau 
303115516c77SSepherosa Ziehau 	/* receive side checksum offload */
303215516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
303315516c77SSepherosa Ziehau 		/* IP csum offload */
303415516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
303515516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
303615516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
303715516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
303815516c77SSepherosa Ziehau 		}
303915516c77SSepherosa Ziehau 
304015516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
304115516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
304215516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
304315516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
304415516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
304515516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
304615516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
304715516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
304815516c77SSepherosa Ziehau 			else
304915516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
305015516c77SSepherosa Ziehau 		}
305115516c77SSepherosa Ziehau 
305215516c77SSepherosa Ziehau 		/*
305315516c77SSepherosa Ziehau 		 * XXX
305415516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
305515516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
305615516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
305715516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
305815516c77SSepherosa Ziehau 		 */
305915516c77SSepherosa Ziehau 		if ((info->csum_info &
306015516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
306115516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
306215516c77SSepherosa Ziehau 			do_lro = 1;
306315516c77SSepherosa Ziehau 	} else {
306415516c77SSepherosa Ziehau 		const struct ether_header *eh;
306515516c77SSepherosa Ziehau 		uint16_t etype;
306615516c77SSepherosa Ziehau 		int hoff;
306715516c77SSepherosa Ziehau 
306815516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
306915516c77SSepherosa Ziehau 		if (m_new->m_len < hoff)
307015516c77SSepherosa Ziehau 			goto skip;
307115516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
307215516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
307315516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
307415516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
307515516c77SSepherosa Ziehau 
307615516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
307715516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
307815516c77SSepherosa Ziehau 				goto skip;
307915516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
308015516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
308115516c77SSepherosa Ziehau 		}
308215516c77SSepherosa Ziehau 
308315516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
308415516c77SSepherosa Ziehau 			int pr;
308515516c77SSepherosa Ziehau 
308615516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
308715516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
308815516c77SSepherosa Ziehau 				if (do_csum &&
308915516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
309015516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
309115516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
309215516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
309315516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
309415516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
309515516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
309615516c77SSepherosa Ziehau 				}
309715516c77SSepherosa Ziehau 				do_lro = 1;
309815516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
309915516c77SSepherosa Ziehau 				if (do_csum &&
310015516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
310115516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
310215516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
310315516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
310415516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
310515516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
310615516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
310715516c77SSepherosa Ziehau 				}
310815516c77SSepherosa Ziehau 			} else if (pr != IPPROTO_DONE && do_csum &&
310915516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
311015516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
311115516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
311215516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
311315516c77SSepherosa Ziehau 			}
311415516c77SSepherosa Ziehau 		}
311515516c77SSepherosa Ziehau 	}
311615516c77SSepherosa Ziehau skip:
311715516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
311815516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
311915516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
312015516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
312115516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
312215516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
312315516c77SSepherosa Ziehau 	}
312415516c77SSepherosa Ziehau 
312515516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
312615516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
312715516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
312815516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
312915516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
313015516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
313115516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
313215516c77SSepherosa Ziehau 
313315516c77SSepherosa Ziehau 			/*
313415516c77SSepherosa Ziehau 			 * NOTE:
313515516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
313615516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
313715516c77SSepherosa Ziehau 			 * setup section.
313815516c77SSepherosa Ziehau 			 */
313915516c77SSepherosa Ziehau 			switch (type) {
314015516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
314115516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
314215516c77SSepherosa Ziehau 				do_lro = 0;
314315516c77SSepherosa Ziehau 				break;
314415516c77SSepherosa Ziehau 
314515516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
314615516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
314715516c77SSepherosa Ziehau 				break;
314815516c77SSepherosa Ziehau 
314915516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
315015516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
315115516c77SSepherosa Ziehau 				do_lro = 0;
315215516c77SSepherosa Ziehau 				break;
315315516c77SSepherosa Ziehau 
315415516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
315515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
315615516c77SSepherosa Ziehau 				do_lro = 0;
315715516c77SSepherosa Ziehau 				break;
315815516c77SSepherosa Ziehau 
315915516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
316015516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
316115516c77SSepherosa Ziehau 				break;
316215516c77SSepherosa Ziehau 
316315516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
316415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
316515516c77SSepherosa Ziehau 				break;
316615516c77SSepherosa Ziehau 			}
316715516c77SSepherosa Ziehau 		}
316815516c77SSepherosa Ziehau 	} else {
316915516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
317015516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
317115516c77SSepherosa Ziehau 	}
317215516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
317315516c77SSepherosa Ziehau 
317415516c77SSepherosa Ziehau 	/*
317515516c77SSepherosa Ziehau 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
317615516c77SSepherosa Ziehau 	 * messages (not just data messages) will trigger a response.
317715516c77SSepherosa Ziehau 	 */
317815516c77SSepherosa Ziehau 
317915516c77SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
318015516c77SSepherosa Ziehau 	rxr->hn_pkts++;
318115516c77SSepherosa Ziehau 
318215516c77SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_LRO) && do_lro) {
318315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
318415516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
318515516c77SSepherosa Ziehau 
318615516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
318715516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
318815516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
318915516c77SSepherosa Ziehau 				/* DONE! */
319015516c77SSepherosa Ziehau 				return 0;
319115516c77SSepherosa Ziehau 			}
319215516c77SSepherosa Ziehau 		}
319315516c77SSepherosa Ziehau #endif
319415516c77SSepherosa Ziehau 	}
319515516c77SSepherosa Ziehau 
319615516c77SSepherosa Ziehau 	/* We're not holding the lock here, so don't release it */
319715516c77SSepherosa Ziehau 	(*ifp->if_input)(ifp, m_new);
319815516c77SSepherosa Ziehau 
319915516c77SSepherosa Ziehau 	return (0);
320015516c77SSepherosa Ziehau }
320115516c77SSepherosa Ziehau 
320215516c77SSepherosa Ziehau static int
320315516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
320415516c77SSepherosa Ziehau {
320515516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
3206*9c6cae24SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data, ifr_vf;
3207*9c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
320815516c77SSepherosa Ziehau 	int mask, error = 0;
320915516c77SSepherosa Ziehau 
321015516c77SSepherosa Ziehau 	switch (cmd) {
321115516c77SSepherosa Ziehau 	case SIOCSIFMTU:
321215516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
321315516c77SSepherosa Ziehau 			error = EINVAL;
321415516c77SSepherosa Ziehau 			break;
321515516c77SSepherosa Ziehau 		}
321615516c77SSepherosa Ziehau 
321715516c77SSepherosa Ziehau 		HN_LOCK(sc);
321815516c77SSepherosa Ziehau 
321915516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
322015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
322115516c77SSepherosa Ziehau 			break;
322215516c77SSepherosa Ziehau 		}
322315516c77SSepherosa Ziehau 
322415516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
322515516c77SSepherosa Ziehau 			/* Can't change MTU */
322615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
322715516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
322815516c77SSepherosa Ziehau 			break;
322915516c77SSepherosa Ziehau 		}
323015516c77SSepherosa Ziehau 
323115516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
323215516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
323315516c77SSepherosa Ziehau 			break;
323415516c77SSepherosa Ziehau 		}
323515516c77SSepherosa Ziehau 
3236*9c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
3237*9c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
3238*9c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
3239*9c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname,
3240*9c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
3241*9c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU,
3242*9c6cae24SSepherosa Ziehau 			    (caddr_t)&ifr_vf);
3243*9c6cae24SSepherosa Ziehau 			if (error) {
3244*9c6cae24SSepherosa Ziehau 				HN_UNLOCK(sc);
3245*9c6cae24SSepherosa Ziehau 				if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n",
3246*9c6cae24SSepherosa Ziehau 				    vf_ifp->if_xname, ifr->ifr_mtu, error);
3247*9c6cae24SSepherosa Ziehau 				break;
3248*9c6cae24SSepherosa Ziehau 			}
3249*9c6cae24SSepherosa Ziehau 		}
3250*9c6cae24SSepherosa Ziehau 
325115516c77SSepherosa Ziehau 		/*
325215516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
325315516c77SSepherosa Ziehau 		 * are ripped.
325415516c77SSepherosa Ziehau 		 */
325515516c77SSepherosa Ziehau 		hn_suspend(sc);
325615516c77SSepherosa Ziehau 
325715516c77SSepherosa Ziehau 		/*
325815516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
325915516c77SSepherosa Ziehau 		 */
326015516c77SSepherosa Ziehau 		hn_synth_detach(sc);
326115516c77SSepherosa Ziehau 
326215516c77SSepherosa Ziehau 		/*
326315516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
326415516c77SSepherosa Ziehau 		 * with the new MTU setting.
326515516c77SSepherosa Ziehau 		 */
326615516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
326715516c77SSepherosa Ziehau 		if (error) {
326815516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
326915516c77SSepherosa Ziehau 			break;
327015516c77SSepherosa Ziehau 		}
327115516c77SSepherosa Ziehau 
327215516c77SSepherosa Ziehau 		/*
327315516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
327415516c77SSepherosa Ziehau 		 * have been successfully attached.
327515516c77SSepherosa Ziehau 		 */
327615516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
327715516c77SSepherosa Ziehau 
327815516c77SSepherosa Ziehau 		/*
3279*9c6cae24SSepherosa Ziehau 		 * Synthetic parts' reattach may change the chimney
3280*9c6cae24SSepherosa Ziehau 		 * sending size; update it.
328115516c77SSepherosa Ziehau 		 */
328215516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
328315516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
3284*9c6cae24SSepherosa Ziehau 
3285*9c6cae24SSepherosa Ziehau 		/*
3286*9c6cae24SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
3287*9c6cae24SSepherosa Ziehau 		 * still valid, after the MTU change.
3288*9c6cae24SSepherosa Ziehau 		 */
3289*9c6cae24SSepherosa Ziehau 		hn_mtu_change_fixup(sc);
329015516c77SSepherosa Ziehau 
329115516c77SSepherosa Ziehau 		/*
329215516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
329315516c77SSepherosa Ziehau 		 */
329415516c77SSepherosa Ziehau 		hn_resume(sc);
329515516c77SSepherosa Ziehau 
3296*9c6cae24SSepherosa Ziehau 		if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
3297*9c6cae24SSepherosa Ziehau 			/*
3298*9c6cae24SSepherosa Ziehau 			 * Since we have reattached the NVS part,
3299*9c6cae24SSepherosa Ziehau 			 * change the datapath to VF again; in case
3300*9c6cae24SSepherosa Ziehau 			 * that it is lost, after the NVS was detached.
3301*9c6cae24SSepherosa Ziehau 			 */
3302*9c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
3303*9c6cae24SSepherosa Ziehau 		}
3304*9c6cae24SSepherosa Ziehau 
330515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
330615516c77SSepherosa Ziehau 		break;
330715516c77SSepherosa Ziehau 
330815516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
330915516c77SSepherosa Ziehau 		HN_LOCK(sc);
331015516c77SSepherosa Ziehau 
331115516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
331215516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
331315516c77SSepherosa Ziehau 			break;
331415516c77SSepherosa Ziehau 		}
331515516c77SSepherosa Ziehau 
3316*9c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc))
3317*9c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
3318*9c6cae24SSepherosa Ziehau 
331915516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
3320fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3321fdc4f478SSepherosa Ziehau 				/*
3322fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
3323fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
3324fdc4f478SSepherosa Ziehau 				 * reply.
3325fdc4f478SSepherosa Ziehau 				 */
3326fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
3327c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
3328fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
3329*9c6cae24SSepherosa Ziehau 
3330*9c6cae24SSepherosa Ziehau 				if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
3331*9c6cae24SSepherosa Ziehau 					error = hn_xpnt_vf_iocsetflags(sc);
3332fdc4f478SSepherosa Ziehau 			} else {
333315516c77SSepherosa Ziehau 				hn_init_locked(sc);
3334fdc4f478SSepherosa Ziehau 			}
333515516c77SSepherosa Ziehau 		} else {
333615516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
33375bdfd3fdSDexuan Cui 				hn_stop(sc, false);
333815516c77SSepherosa Ziehau 		}
333915516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
334015516c77SSepherosa Ziehau 
334115516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
334215516c77SSepherosa Ziehau 		break;
334315516c77SSepherosa Ziehau 
334415516c77SSepherosa Ziehau 	case SIOCSIFCAP:
334515516c77SSepherosa Ziehau 		HN_LOCK(sc);
3346*9c6cae24SSepherosa Ziehau 
3347*9c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
3348*9c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
3349*9c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname,
3350*9c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
3351*9c6cae24SSepherosa Ziehau 			error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf);
3352*9c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
3353*9c6cae24SSepherosa Ziehau 			break;
3354*9c6cae24SSepherosa Ziehau 		}
3355*9c6cae24SSepherosa Ziehau 
3356*9c6cae24SSepherosa Ziehau 		/*
3357*9c6cae24SSepherosa Ziehau 		 * Fix up requested capabilities w/ supported capabilities,
3358*9c6cae24SSepherosa Ziehau 		 * since the supported capabilities could have been changed.
3359*9c6cae24SSepherosa Ziehau 		 */
3360*9c6cae24SSepherosa Ziehau 		mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^
3361*9c6cae24SSepherosa Ziehau 		    ifp->if_capenable;
336215516c77SSepherosa Ziehau 
336315516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
336415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
336515516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
336615516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
336715516c77SSepherosa Ziehau 			else
336815516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
336915516c77SSepherosa Ziehau 		}
337015516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
337115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
337215516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
337315516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
337415516c77SSepherosa Ziehau 			else
337515516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
337615516c77SSepherosa Ziehau 		}
337715516c77SSepherosa Ziehau 
337815516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
337915516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
338015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
338115516c77SSepherosa Ziehau #ifdef foo
338215516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
338315516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
338415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
338515516c77SSepherosa Ziehau #endif
338615516c77SSepherosa Ziehau 
338715516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
338815516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
338915516c77SSepherosa Ziehau 
339015516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
339115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
339215516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
339315516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
339415516c77SSepherosa Ziehau 			else
339515516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
339615516c77SSepherosa Ziehau 		}
339715516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
339815516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
339915516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
340015516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
340115516c77SSepherosa Ziehau 			else
340215516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
340315516c77SSepherosa Ziehau 		}
340415516c77SSepherosa Ziehau 
340515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
340615516c77SSepherosa Ziehau 		break;
340715516c77SSepherosa Ziehau 
340815516c77SSepherosa Ziehau 	case SIOCADDMULTI:
340915516c77SSepherosa Ziehau 	case SIOCDELMULTI:
341015516c77SSepherosa Ziehau 		HN_LOCK(sc);
341115516c77SSepherosa Ziehau 
341215516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
341315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
341415516c77SSepherosa Ziehau 			break;
341515516c77SSepherosa Ziehau 		}
3416fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3417fdc4f478SSepherosa Ziehau 			/*
3418fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
3419fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
3420fdc4f478SSepherosa Ziehau 			 */
3421fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
3422c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
3423fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
3424fdc4f478SSepherosa Ziehau 		}
342515516c77SSepherosa Ziehau 
3426*9c6cae24SSepherosa Ziehau 		/* XXX vlan(4) style mcast addr maintenance */
3427*9c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
3428*9c6cae24SSepherosa Ziehau 			int old_if_flags;
3429*9c6cae24SSepherosa Ziehau 
3430*9c6cae24SSepherosa Ziehau 			old_if_flags = sc->hn_vf_ifp->if_flags;
3431*9c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
3432*9c6cae24SSepherosa Ziehau 
3433*9c6cae24SSepherosa Ziehau 			if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) &&
3434*9c6cae24SSepherosa Ziehau 			    ((old_if_flags ^ sc->hn_vf_ifp->if_flags) &
3435*9c6cae24SSepherosa Ziehau 			     IFF_ALLMULTI))
3436*9c6cae24SSepherosa Ziehau 				error = hn_xpnt_vf_iocsetflags(sc);
3437*9c6cae24SSepherosa Ziehau 		}
3438*9c6cae24SSepherosa Ziehau 
343915516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
344015516c77SSepherosa Ziehau 		break;
344115516c77SSepherosa Ziehau 
344215516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
344315516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
3444*9c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
3445*9c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
3446*9c6cae24SSepherosa Ziehau 			/*
3447*9c6cae24SSepherosa Ziehau 			 * SIOCGIFMEDIA expects ifmediareq, so don't
3448*9c6cae24SSepherosa Ziehau 			 * create and pass ifr_vf to the VF here; just
3449*9c6cae24SSepherosa Ziehau 			 * replace the ifr_name.
3450*9c6cae24SSepherosa Ziehau 			 */
3451*9c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
3452*9c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, vf_ifp->if_xname,
3453*9c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
3454*9c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, cmd, data);
3455*9c6cae24SSepherosa Ziehau 			/* Restore the ifr_name. */
3456*9c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, ifp->if_xname,
3457*9c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
3458*9c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
3459*9c6cae24SSepherosa Ziehau 			break;
3460*9c6cae24SSepherosa Ziehau 		}
3461*9c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
346215516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
346315516c77SSepherosa Ziehau 		break;
346415516c77SSepherosa Ziehau 
346515516c77SSepherosa Ziehau 	default:
346615516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
346715516c77SSepherosa Ziehau 		break;
346815516c77SSepherosa Ziehau 	}
346915516c77SSepherosa Ziehau 	return (error);
347015516c77SSepherosa Ziehau }
347115516c77SSepherosa Ziehau 
347215516c77SSepherosa Ziehau static void
34735bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
347415516c77SSepherosa Ziehau {
347515516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
347615516c77SSepherosa Ziehau 	int i;
347715516c77SSepherosa Ziehau 
347815516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
347915516c77SSepherosa Ziehau 
348015516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
348115516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
348215516c77SSepherosa Ziehau 
3483*9c6cae24SSepherosa Ziehau 	/* Clear RUNNING bit ASAP. */
3484*9c6cae24SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
3485*9c6cae24SSepherosa Ziehau 
34866c1204dfSSepherosa Ziehau 	/* Disable polling. */
34876c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
34886c1204dfSSepherosa Ziehau 
3489*9c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
3490*9c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_ifp != NULL,
3491*9c6cae24SSepherosa Ziehau 		    ("%s: VF is not attached", ifp->if_xname));
3492*9c6cae24SSepherosa Ziehau 
3493*9c6cae24SSepherosa Ziehau 		/* NOTE: hn_vf_lock for hn_transmit() */
3494*9c6cae24SSepherosa Ziehau 		rm_wlock(&sc->hn_vf_lock);
3495*9c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED;
3496*9c6cae24SSepherosa Ziehau 		rm_wunlock(&sc->hn_vf_lock);
3497*9c6cae24SSepherosa Ziehau 
3498*9c6cae24SSepherosa Ziehau 		/*
3499*9c6cae24SSepherosa Ziehau 		 * NOTE:
3500*9c6cae24SSepherosa Ziehau 		 * Datapath setting must happen _before_ bringing
3501*9c6cae24SSepherosa Ziehau 		 * the VF down.
3502*9c6cae24SSepherosa Ziehau 		 */
3503*9c6cae24SSepherosa Ziehau 		hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
3504*9c6cae24SSepherosa Ziehau 
3505*9c6cae24SSepherosa Ziehau 		/*
3506*9c6cae24SSepherosa Ziehau 		 * Bring the VF down.
3507*9c6cae24SSepherosa Ziehau 		 */
3508*9c6cae24SSepherosa Ziehau 		hn_xpnt_vf_saveifflags(sc);
3509*9c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_flags &= ~IFF_UP;
3510*9c6cae24SSepherosa Ziehau 		hn_xpnt_vf_iocsetflags(sc);
3511*9c6cae24SSepherosa Ziehau 	}
3512*9c6cae24SSepherosa Ziehau 
3513*9c6cae24SSepherosa Ziehau 	/* Suspend data transfers. */
351415516c77SSepherosa Ziehau 	hn_suspend_data(sc);
351515516c77SSepherosa Ziehau 
351615516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
351715516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
351815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
351915516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
35205bdfd3fdSDexuan Cui 
35215bdfd3fdSDexuan Cui 	/*
3522*9c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is active, make sure
3523*9c6cae24SSepherosa Ziehau 	 * that the RX filter still allows packet reception.
35245bdfd3fdSDexuan Cui 	 */
3525962f0357SSepherosa Ziehau 	if (!detaching && (sc->hn_flags & HN_FLAG_RXVF))
35265bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
352715516c77SSepherosa Ziehau }
352815516c77SSepherosa Ziehau 
352915516c77SSepherosa Ziehau static void
353015516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
353115516c77SSepherosa Ziehau {
353215516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
353315516c77SSepherosa Ziehau 	int i;
353415516c77SSepherosa Ziehau 
353515516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
353615516c77SSepherosa Ziehau 
353715516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
353815516c77SSepherosa Ziehau 		return;
353915516c77SSepherosa Ziehau 
354015516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
354115516c77SSepherosa Ziehau 		return;
354215516c77SSepherosa Ziehau 
354315516c77SSepherosa Ziehau 	/* Configure RX filter */
3544c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
354515516c77SSepherosa Ziehau 
354615516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
354715516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
354815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
354915516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
355015516c77SSepherosa Ziehau 
355115516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
355215516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
355315516c77SSepherosa Ziehau 
3554*9c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
3555*9c6cae24SSepherosa Ziehau 		/* Initialize transparent VF. */
3556*9c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
3557*9c6cae24SSepherosa Ziehau 	}
3558*9c6cae24SSepherosa Ziehau 
355915516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
356015516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
35616c1204dfSSepherosa Ziehau 
35626c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
35636c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
35646c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
356515516c77SSepherosa Ziehau }
356615516c77SSepherosa Ziehau 
356715516c77SSepherosa Ziehau static void
356815516c77SSepherosa Ziehau hn_init(void *xsc)
356915516c77SSepherosa Ziehau {
357015516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
357115516c77SSepherosa Ziehau 
357215516c77SSepherosa Ziehau 	HN_LOCK(sc);
357315516c77SSepherosa Ziehau 	hn_init_locked(sc);
357415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
357515516c77SSepherosa Ziehau }
357615516c77SSepherosa Ziehau 
357715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
357815516c77SSepherosa Ziehau 
357915516c77SSepherosa Ziehau static int
358015516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
358115516c77SSepherosa Ziehau {
358215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
358315516c77SSepherosa Ziehau 	unsigned int lenlim;
358415516c77SSepherosa Ziehau 	int error;
358515516c77SSepherosa Ziehau 
358615516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
358715516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
358815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
358915516c77SSepherosa Ziehau 		return error;
359015516c77SSepherosa Ziehau 
359115516c77SSepherosa Ziehau 	HN_LOCK(sc);
359215516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
359315516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
359415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
359515516c77SSepherosa Ziehau 		return EINVAL;
359615516c77SSepherosa Ziehau 	}
359715516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
359815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
359915516c77SSepherosa Ziehau 
360015516c77SSepherosa Ziehau 	return 0;
360115516c77SSepherosa Ziehau }
360215516c77SSepherosa Ziehau 
360315516c77SSepherosa Ziehau static int
360415516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
360515516c77SSepherosa Ziehau {
360615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
360715516c77SSepherosa Ziehau 	int ackcnt, error, i;
360815516c77SSepherosa Ziehau 
360915516c77SSepherosa Ziehau 	/*
361015516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
361115516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
361215516c77SSepherosa Ziehau 	 */
361315516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
361415516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
361515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
361615516c77SSepherosa Ziehau 		return error;
361715516c77SSepherosa Ziehau 
361815516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
361915516c77SSepherosa Ziehau 		return EINVAL;
362015516c77SSepherosa Ziehau 
362115516c77SSepherosa Ziehau 	/*
362215516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
362315516c77SSepherosa Ziehau 	 * count limit.
362415516c77SSepherosa Ziehau 	 */
362515516c77SSepherosa Ziehau 	--ackcnt;
362615516c77SSepherosa Ziehau 	HN_LOCK(sc);
3627a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
362815516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
362915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
363015516c77SSepherosa Ziehau 	return 0;
363115516c77SSepherosa Ziehau }
363215516c77SSepherosa Ziehau 
363315516c77SSepherosa Ziehau #endif
363415516c77SSepherosa Ziehau 
363515516c77SSepherosa Ziehau static int
363615516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
363715516c77SSepherosa Ziehau {
363815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
363915516c77SSepherosa Ziehau 	int hcsum = arg2;
364015516c77SSepherosa Ziehau 	int on, error, i;
364115516c77SSepherosa Ziehau 
364215516c77SSepherosa Ziehau 	on = 0;
364315516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
364415516c77SSepherosa Ziehau 		on = 1;
364515516c77SSepherosa Ziehau 
364615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
364715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
364815516c77SSepherosa Ziehau 		return error;
364915516c77SSepherosa Ziehau 
365015516c77SSepherosa Ziehau 	HN_LOCK(sc);
3651a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
365215516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
365315516c77SSepherosa Ziehau 
365415516c77SSepherosa Ziehau 		if (on)
365515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
365615516c77SSepherosa Ziehau 		else
365715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
365815516c77SSepherosa Ziehau 	}
365915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
366015516c77SSepherosa Ziehau 	return 0;
366115516c77SSepherosa Ziehau }
366215516c77SSepherosa Ziehau 
366315516c77SSepherosa Ziehau static int
366415516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
366515516c77SSepherosa Ziehau {
366615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
366715516c77SSepherosa Ziehau 	int chim_size, error;
366815516c77SSepherosa Ziehau 
366915516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
367015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
367115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
367215516c77SSepherosa Ziehau 		return error;
367315516c77SSepherosa Ziehau 
367415516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
367515516c77SSepherosa Ziehau 		return EINVAL;
367615516c77SSepherosa Ziehau 
367715516c77SSepherosa Ziehau 	HN_LOCK(sc);
367815516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
367915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
368015516c77SSepherosa Ziehau 	return 0;
368115516c77SSepherosa Ziehau }
368215516c77SSepherosa Ziehau 
368315516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
368415516c77SSepherosa Ziehau static int
368515516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
368615516c77SSepherosa Ziehau {
368715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
368815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
368915516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
369015516c77SSepherosa Ziehau 	uint64_t stat;
369115516c77SSepherosa Ziehau 
369215516c77SSepherosa Ziehau 	stat = 0;
369315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
369415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
369515516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
369615516c77SSepherosa Ziehau 	}
369715516c77SSepherosa Ziehau 
369815516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
369915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
370015516c77SSepherosa Ziehau 		return error;
370115516c77SSepherosa Ziehau 
370215516c77SSepherosa Ziehau 	/* Zero out this stat. */
370315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
370415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
370515516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
370615516c77SSepherosa Ziehau 	}
370715516c77SSepherosa Ziehau 	return 0;
370815516c77SSepherosa Ziehau }
370915516c77SSepherosa Ziehau #else
371015516c77SSepherosa Ziehau static int
371115516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
371215516c77SSepherosa Ziehau {
371315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
371415516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
371515516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
371615516c77SSepherosa Ziehau 	uint64_t stat;
371715516c77SSepherosa Ziehau 
371815516c77SSepherosa Ziehau 	stat = 0;
3719a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
372015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
372115516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
372215516c77SSepherosa Ziehau 	}
372315516c77SSepherosa Ziehau 
372415516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
372515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
372615516c77SSepherosa Ziehau 		return error;
372715516c77SSepherosa Ziehau 
372815516c77SSepherosa Ziehau 	/* Zero out this stat. */
3729a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
373015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
373115516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
373215516c77SSepherosa Ziehau 	}
373315516c77SSepherosa Ziehau 	return 0;
373415516c77SSepherosa Ziehau }
373515516c77SSepherosa Ziehau 
373615516c77SSepherosa Ziehau #endif
373715516c77SSepherosa Ziehau 
373815516c77SSepherosa Ziehau static int
373915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
374015516c77SSepherosa Ziehau {
374115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
374215516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
374315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
374415516c77SSepherosa Ziehau 	u_long stat;
374515516c77SSepherosa Ziehau 
374615516c77SSepherosa Ziehau 	stat = 0;
3747a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
374815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
374915516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
375015516c77SSepherosa Ziehau 	}
375115516c77SSepherosa Ziehau 
375215516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
375315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
375415516c77SSepherosa Ziehau 		return error;
375515516c77SSepherosa Ziehau 
375615516c77SSepherosa Ziehau 	/* Zero out this stat. */
3757a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
375815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
375915516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
376015516c77SSepherosa Ziehau 	}
376115516c77SSepherosa Ziehau 	return 0;
376215516c77SSepherosa Ziehau }
376315516c77SSepherosa Ziehau 
376415516c77SSepherosa Ziehau static int
376515516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
376615516c77SSepherosa Ziehau {
376715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
376815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
376915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
377015516c77SSepherosa Ziehau 	u_long stat;
377115516c77SSepherosa Ziehau 
377215516c77SSepherosa Ziehau 	stat = 0;
3773a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
377415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
377515516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
377615516c77SSepherosa Ziehau 	}
377715516c77SSepherosa Ziehau 
377815516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
377915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
378015516c77SSepherosa Ziehau 		return error;
378115516c77SSepherosa Ziehau 
378215516c77SSepherosa Ziehau 	/* Zero out this stat. */
3783a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
378415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
378515516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
378615516c77SSepherosa Ziehau 	}
378715516c77SSepherosa Ziehau 	return 0;
378815516c77SSepherosa Ziehau }
378915516c77SSepherosa Ziehau 
379015516c77SSepherosa Ziehau static int
379115516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
379215516c77SSepherosa Ziehau {
379315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
379415516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
379515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
379615516c77SSepherosa Ziehau 
379715516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
379815516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
379915516c77SSepherosa Ziehau 
380015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
380115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
380215516c77SSepherosa Ziehau 		return error;
380315516c77SSepherosa Ziehau 
380415516c77SSepherosa Ziehau 	HN_LOCK(sc);
3805a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
380615516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
380715516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
380815516c77SSepherosa Ziehau 	}
380915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
381015516c77SSepherosa Ziehau 
381115516c77SSepherosa Ziehau 	return 0;
381215516c77SSepherosa Ziehau }
381315516c77SSepherosa Ziehau 
381415516c77SSepherosa Ziehau static int
3815dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
3816dc13fee6SSepherosa Ziehau {
3817dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3818dc13fee6SSepherosa Ziehau 	int error, size;
3819dc13fee6SSepherosa Ziehau 
3820dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
3821dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
3822dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
3823dc13fee6SSepherosa Ziehau 		return (error);
3824dc13fee6SSepherosa Ziehau 
3825dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
3826dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
3827dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
3828dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
3829dc13fee6SSepherosa Ziehau 
3830dc13fee6SSepherosa Ziehau 	return (0);
3831dc13fee6SSepherosa Ziehau }
3832dc13fee6SSepherosa Ziehau 
3833dc13fee6SSepherosa Ziehau static int
3834dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
3835dc13fee6SSepherosa Ziehau {
3836dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3837dc13fee6SSepherosa Ziehau 	int error, pkts;
3838dc13fee6SSepherosa Ziehau 
3839dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
3840dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
3841dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
3842dc13fee6SSepherosa Ziehau 		return (error);
3843dc13fee6SSepherosa Ziehau 
3844dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
3845dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
3846dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
3847dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
3848dc13fee6SSepherosa Ziehau 
3849dc13fee6SSepherosa Ziehau 	return (0);
3850dc13fee6SSepherosa Ziehau }
3851dc13fee6SSepherosa Ziehau 
3852dc13fee6SSepherosa Ziehau static int
3853dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
3854dc13fee6SSepherosa Ziehau {
3855dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3856dc13fee6SSepherosa Ziehau 	int pkts;
3857dc13fee6SSepherosa Ziehau 
3858dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
3859dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
3860dc13fee6SSepherosa Ziehau }
3861dc13fee6SSepherosa Ziehau 
3862dc13fee6SSepherosa Ziehau static int
3863dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
3864dc13fee6SSepherosa Ziehau {
3865dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3866dc13fee6SSepherosa Ziehau 	int align;
3867dc13fee6SSepherosa Ziehau 
3868dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
3869dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
3870dc13fee6SSepherosa Ziehau }
3871dc13fee6SSepherosa Ziehau 
38726c1204dfSSepherosa Ziehau static void
38736c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
38746c1204dfSSepherosa Ziehau {
38756c1204dfSSepherosa Ziehau 	if (pollhz == 0)
38766c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
38776c1204dfSSepherosa Ziehau 	else
38786c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
38796c1204dfSSepherosa Ziehau }
38806c1204dfSSepherosa Ziehau 
38816c1204dfSSepherosa Ziehau static void
38826c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
38836c1204dfSSepherosa Ziehau {
38846c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
38856c1204dfSSepherosa Ziehau 
38866c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
38876c1204dfSSepherosa Ziehau 
38886c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
38896c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
38906c1204dfSSepherosa Ziehau 		int i;
38916c1204dfSSepherosa Ziehau 
38926c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
38936c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
38946c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
38956c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
38966c1204dfSSepherosa Ziehau 	}
38976c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
38986c1204dfSSepherosa Ziehau }
38996c1204dfSSepherosa Ziehau 
39006c1204dfSSepherosa Ziehau static int
39016c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
39026c1204dfSSepherosa Ziehau {
39036c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
39046c1204dfSSepherosa Ziehau 	int pollhz, error;
39056c1204dfSSepherosa Ziehau 
39066c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
39076c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
39086c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
39096c1204dfSSepherosa Ziehau 		return (error);
39106c1204dfSSepherosa Ziehau 
39116c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
39126c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
39136c1204dfSSepherosa Ziehau 		return (EINVAL);
39146c1204dfSSepherosa Ziehau 
39156c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
39166c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
39176c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
39186c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
39196c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
39206c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
39216c1204dfSSepherosa Ziehau 	}
39226c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
39236c1204dfSSepherosa Ziehau 
39246c1204dfSSepherosa Ziehau 	return (0);
39256c1204dfSSepherosa Ziehau }
39266c1204dfSSepherosa Ziehau 
3927dc13fee6SSepherosa Ziehau static int
392815516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
392915516c77SSepherosa Ziehau {
393015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
393115516c77SSepherosa Ziehau 	char verstr[16];
393215516c77SSepherosa Ziehau 
393315516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
393415516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
393515516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
393615516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
393715516c77SSepherosa Ziehau }
393815516c77SSepherosa Ziehau 
393915516c77SSepherosa Ziehau static int
394015516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
394115516c77SSepherosa Ziehau {
394215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
394315516c77SSepherosa Ziehau 	char caps_str[128];
394415516c77SSepherosa Ziehau 	uint32_t caps;
394515516c77SSepherosa Ziehau 
394615516c77SSepherosa Ziehau 	HN_LOCK(sc);
394715516c77SSepherosa Ziehau 	caps = sc->hn_caps;
394815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
394915516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
395015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
395115516c77SSepherosa Ziehau }
395215516c77SSepherosa Ziehau 
395315516c77SSepherosa Ziehau static int
395415516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
395515516c77SSepherosa Ziehau {
395615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
395715516c77SSepherosa Ziehau 	char assist_str[128];
395815516c77SSepherosa Ziehau 	uint32_t hwassist;
395915516c77SSepherosa Ziehau 
396015516c77SSepherosa Ziehau 	HN_LOCK(sc);
396115516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
396215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
396315516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
396415516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
396515516c77SSepherosa Ziehau }
396615516c77SSepherosa Ziehau 
396715516c77SSepherosa Ziehau static int
396815516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
396915516c77SSepherosa Ziehau {
397015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
397115516c77SSepherosa Ziehau 	char filter_str[128];
397215516c77SSepherosa Ziehau 	uint32_t filter;
397315516c77SSepherosa Ziehau 
397415516c77SSepherosa Ziehau 	HN_LOCK(sc);
397515516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
397615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
397715516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
397815516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
397915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
398015516c77SSepherosa Ziehau }
398115516c77SSepherosa Ziehau 
398234d68912SSepherosa Ziehau #ifndef RSS
398334d68912SSepherosa Ziehau 
398415516c77SSepherosa Ziehau static int
398515516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
398615516c77SSepherosa Ziehau {
398715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
398815516c77SSepherosa Ziehau 	int error;
398915516c77SSepherosa Ziehau 
399015516c77SSepherosa Ziehau 	HN_LOCK(sc);
399115516c77SSepherosa Ziehau 
399215516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
399315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
399415516c77SSepherosa Ziehau 		goto back;
399515516c77SSepherosa Ziehau 
399615516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
399715516c77SSepherosa Ziehau 	if (error)
399815516c77SSepherosa Ziehau 		goto back;
399915516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
400015516c77SSepherosa Ziehau 
400115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
400215516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
400315516c77SSepherosa Ziehau 	} else {
400415516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
400515516c77SSepherosa Ziehau 		error = 0;
400615516c77SSepherosa Ziehau 	}
400715516c77SSepherosa Ziehau back:
400815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
400915516c77SSepherosa Ziehau 	return (error);
401015516c77SSepherosa Ziehau }
401115516c77SSepherosa Ziehau 
401215516c77SSepherosa Ziehau static int
401315516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
401415516c77SSepherosa Ziehau {
401515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
401615516c77SSepherosa Ziehau 	int error;
401715516c77SSepherosa Ziehau 
401815516c77SSepherosa Ziehau 	HN_LOCK(sc);
401915516c77SSepherosa Ziehau 
402015516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
402115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
402215516c77SSepherosa Ziehau 		goto back;
402315516c77SSepherosa Ziehau 
402415516c77SSepherosa Ziehau 	/*
402515516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
402615516c77SSepherosa Ziehau 	 * RSS capable currently.
402715516c77SSepherosa Ziehau 	 */
402815516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
402915516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
403015516c77SSepherosa Ziehau 		goto back;
403115516c77SSepherosa Ziehau 	}
403215516c77SSepherosa Ziehau 
403315516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
403415516c77SSepherosa Ziehau 	if (error)
403515516c77SSepherosa Ziehau 		goto back;
403615516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
403715516c77SSepherosa Ziehau 
4038afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
403915516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
404015516c77SSepherosa Ziehau back:
404115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
404215516c77SSepherosa Ziehau 	return (error);
404315516c77SSepherosa Ziehau }
404415516c77SSepherosa Ziehau 
404534d68912SSepherosa Ziehau #endif	/* !RSS */
404634d68912SSepherosa Ziehau 
404715516c77SSepherosa Ziehau static int
404815516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
404915516c77SSepherosa Ziehau {
405015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
405115516c77SSepherosa Ziehau 	char hash_str[128];
405215516c77SSepherosa Ziehau 	uint32_t hash;
405315516c77SSepherosa Ziehau 
405415516c77SSepherosa Ziehau 	HN_LOCK(sc);
405515516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
405615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
405715516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
405815516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
405915516c77SSepherosa Ziehau }
406015516c77SSepherosa Ziehau 
406115516c77SSepherosa Ziehau static int
406240d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
406340d60d6eSDexuan Cui {
406440d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
4065499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4066962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
406740d60d6eSDexuan Cui 
406840d60d6eSDexuan Cui 	HN_LOCK(sc);
406940d60d6eSDexuan Cui 	vf_name[0] = '\0';
4070962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
4071962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4072962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
407340d60d6eSDexuan Cui 	HN_UNLOCK(sc);
407440d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
407540d60d6eSDexuan Cui }
407640d60d6eSDexuan Cui 
407740d60d6eSDexuan Cui static int
4078499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS)
4079499c3e17SSepherosa Ziehau {
4080499c3e17SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4081499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4082962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
4083499c3e17SSepherosa Ziehau 
4084499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
4085499c3e17SSepherosa Ziehau 	vf_name[0] = '\0';
4086962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp;
4087962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4088962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
4089499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
4090499c3e17SSepherosa Ziehau 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
4091499c3e17SSepherosa Ziehau }
4092499c3e17SSepherosa Ziehau 
4093499c3e17SSepherosa Ziehau static int
4094499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS)
4095499c3e17SSepherosa Ziehau {
4096499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4097499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4098499c3e17SSepherosa Ziehau 	int error, i;
4099499c3e17SSepherosa Ziehau 	bool first;
4100499c3e17SSepherosa Ziehau 
4101499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4102499c3e17SSepherosa Ziehau 	if (error != 0)
4103499c3e17SSepherosa Ziehau 		return (error);
4104499c3e17SSepherosa Ziehau 
4105499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4106499c3e17SSepherosa Ziehau 	if (sb == NULL)
4107499c3e17SSepherosa Ziehau 		return (ENOMEM);
4108499c3e17SSepherosa Ziehau 
4109499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4110499c3e17SSepherosa Ziehau 
4111499c3e17SSepherosa Ziehau 	first = true;
4112499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4113499c3e17SSepherosa Ziehau 		struct ifnet *ifp;
4114499c3e17SSepherosa Ziehau 
4115499c3e17SSepherosa Ziehau 		if (hn_vfmap[i] == NULL)
4116499c3e17SSepherosa Ziehau 			continue;
4117499c3e17SSepherosa Ziehau 
4118499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4119499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4120499c3e17SSepherosa Ziehau 			if (first)
4121499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s", ifp->if_xname);
4122499c3e17SSepherosa Ziehau 			else
4123499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s", ifp->if_xname);
4124499c3e17SSepherosa Ziehau 			first = false;
4125499c3e17SSepherosa Ziehau 		}
4126499c3e17SSepherosa Ziehau 	}
4127499c3e17SSepherosa Ziehau 
4128499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4129499c3e17SSepherosa Ziehau 
4130499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4131499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4132499c3e17SSepherosa Ziehau 	return (error);
4133499c3e17SSepherosa Ziehau }
4134499c3e17SSepherosa Ziehau 
4135499c3e17SSepherosa Ziehau static int
4136499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS)
4137499c3e17SSepherosa Ziehau {
4138499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4139499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4140499c3e17SSepherosa Ziehau 	int error, i;
4141499c3e17SSepherosa Ziehau 	bool first;
4142499c3e17SSepherosa Ziehau 
4143499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4144499c3e17SSepherosa Ziehau 	if (error != 0)
4145499c3e17SSepherosa Ziehau 		return (error);
4146499c3e17SSepherosa Ziehau 
4147499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4148499c3e17SSepherosa Ziehau 	if (sb == NULL)
4149499c3e17SSepherosa Ziehau 		return (ENOMEM);
4150499c3e17SSepherosa Ziehau 
4151499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4152499c3e17SSepherosa Ziehau 
4153499c3e17SSepherosa Ziehau 	first = true;
4154499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4155499c3e17SSepherosa Ziehau 		struct ifnet *ifp, *hn_ifp;
4156499c3e17SSepherosa Ziehau 
4157499c3e17SSepherosa Ziehau 		hn_ifp = hn_vfmap[i];
4158499c3e17SSepherosa Ziehau 		if (hn_ifp == NULL)
4159499c3e17SSepherosa Ziehau 			continue;
4160499c3e17SSepherosa Ziehau 
4161499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4162499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4163499c3e17SSepherosa Ziehau 			if (first) {
4164499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s:%s", ifp->if_xname,
4165499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4166499c3e17SSepherosa Ziehau 			} else {
4167499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s:%s", ifp->if_xname,
4168499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4169499c3e17SSepherosa Ziehau 			}
4170499c3e17SSepherosa Ziehau 			first = false;
4171499c3e17SSepherosa Ziehau 		}
4172499c3e17SSepherosa Ziehau 	}
4173499c3e17SSepherosa Ziehau 
4174499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4175499c3e17SSepherosa Ziehau 
4176499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4177499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4178499c3e17SSepherosa Ziehau 	return (error);
4179499c3e17SSepherosa Ziehau }
4180499c3e17SSepherosa Ziehau 
4181499c3e17SSepherosa Ziehau static int
4182*9c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS)
4183*9c6cae24SSepherosa Ziehau {
4184*9c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4185*9c6cae24SSepherosa Ziehau 	int error, onoff = 0;
4186*9c6cae24SSepherosa Ziehau 
4187*9c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF)
4188*9c6cae24SSepherosa Ziehau 		onoff = 1;
4189*9c6cae24SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &onoff, 0, req);
4190*9c6cae24SSepherosa Ziehau 	if (error || req->newptr == NULL)
4191*9c6cae24SSepherosa Ziehau 		return (error);
4192*9c6cae24SSepherosa Ziehau 
4193*9c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
4194*9c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit() */
4195*9c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
4196*9c6cae24SSepherosa Ziehau 	if (onoff)
4197*9c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
4198*9c6cae24SSepherosa Ziehau 	else
4199*9c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF;
4200*9c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
4201*9c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
4202*9c6cae24SSepherosa Ziehau 
4203*9c6cae24SSepherosa Ziehau 	return (0);
4204*9c6cae24SSepherosa Ziehau }
4205*9c6cae24SSepherosa Ziehau 
4206*9c6cae24SSepherosa Ziehau static int
4207*9c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS)
4208*9c6cae24SSepherosa Ziehau {
4209*9c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4210*9c6cae24SSepherosa Ziehau 	int enabled = 0;
4211*9c6cae24SSepherosa Ziehau 
4212*9c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
4213*9c6cae24SSepherosa Ziehau 		enabled = 1;
4214*9c6cae24SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &enabled, 0, req));
4215*9c6cae24SSepherosa Ziehau }
4216*9c6cae24SSepherosa Ziehau 
4217*9c6cae24SSepherosa Ziehau static int
421815516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
421915516c77SSepherosa Ziehau {
422015516c77SSepherosa Ziehau 	const struct ip *ip;
422115516c77SSepherosa Ziehau 	int len, iphlen, iplen;
422215516c77SSepherosa Ziehau 	const struct tcphdr *th;
422315516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
422415516c77SSepherosa Ziehau 
422515516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
422615516c77SSepherosa Ziehau 
422715516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
422815516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
422915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
423015516c77SSepherosa Ziehau 
423115516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
423215516c77SSepherosa Ziehau 	if (m->m_len < len)
423315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
423415516c77SSepherosa Ziehau 
423515516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
423615516c77SSepherosa Ziehau 
423715516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
423815516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
423915516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
424015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
424115516c77SSepherosa Ziehau 
424215516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
424315516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
424415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
424515516c77SSepherosa Ziehau 
424615516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
424715516c77SSepherosa Ziehau 
424815516c77SSepherosa Ziehau 	/*
424915516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
425015516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
425115516c77SSepherosa Ziehau 	 */
425215516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
425315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
425415516c77SSepherosa Ziehau 
425515516c77SSepherosa Ziehau 	/*
425615516c77SSepherosa Ziehau 	 * Ignore IP fragments.
425715516c77SSepherosa Ziehau 	 */
425815516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
425915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
426015516c77SSepherosa Ziehau 
426115516c77SSepherosa Ziehau 	/*
426215516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
426315516c77SSepherosa Ziehau 	 * the first fragment of a packet.
426415516c77SSepherosa Ziehau 	 */
426515516c77SSepherosa Ziehau 	switch (ip->ip_p) {
426615516c77SSepherosa Ziehau 	case IPPROTO_TCP:
426715516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
426815516c77SSepherosa Ziehau 			return IPPROTO_DONE;
426915516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
427015516c77SSepherosa Ziehau 			return IPPROTO_DONE;
427115516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
427215516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
427315516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
427415516c77SSepherosa Ziehau 			return IPPROTO_DONE;
427515516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
427615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
427715516c77SSepherosa Ziehau 		break;
427815516c77SSepherosa Ziehau 	case IPPROTO_UDP:
427915516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
428015516c77SSepherosa Ziehau 			return IPPROTO_DONE;
428115516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
428215516c77SSepherosa Ziehau 			return IPPROTO_DONE;
428315516c77SSepherosa Ziehau 		break;
428415516c77SSepherosa Ziehau 	default:
428515516c77SSepherosa Ziehau 		if (iplen < iphlen)
428615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
428715516c77SSepherosa Ziehau 		break;
428815516c77SSepherosa Ziehau 	}
428915516c77SSepherosa Ziehau 	return ip->ip_p;
429015516c77SSepherosa Ziehau }
429115516c77SSepherosa Ziehau 
429215516c77SSepherosa Ziehau static int
429315516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
429415516c77SSepherosa Ziehau {
429515516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
429615516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
429715516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
429815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
429915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
430015516c77SSepherosa Ziehau 	int lroent_cnt;
430115516c77SSepherosa Ziehau #endif
430215516c77SSepherosa Ziehau #endif
430315516c77SSepherosa Ziehau 	int i;
430415516c77SSepherosa Ziehau 
430515516c77SSepherosa Ziehau 	/*
430615516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
430715516c77SSepherosa Ziehau 	 *
430815516c77SSepherosa Ziehau 	 * NOTE:
430915516c77SSepherosa Ziehau 	 * - It is shared by all channels.
431015516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
431115516c77SSepherosa Ziehau 	 *   may further limit the usable space.
431215516c77SSepherosa Ziehau 	 */
431315516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
431415516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
431515516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
431615516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
431715516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
431815516c77SSepherosa Ziehau 		return (ENOMEM);
431915516c77SSepherosa Ziehau 	}
432015516c77SSepherosa Ziehau 
432115516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
432215516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
432315516c77SSepherosa Ziehau 
432415516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
432515516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
432615516c77SSepherosa Ziehau 
432715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
432815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
432915516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
433015516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
433115516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
433215516c77SSepherosa Ziehau 	if (bootverbose)
433315516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
433415516c77SSepherosa Ziehau #endif
433515516c77SSepherosa Ziehau #endif	/* INET || INET6 */
433615516c77SSepherosa Ziehau 
433715516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
433815516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
433915516c77SSepherosa Ziehau 
434015516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
434115516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
434215516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
434315516c77SSepherosa Ziehau 
434415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
434515516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
434615516c77SSepherosa Ziehau 
434715516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
434815516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
434915516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
435015516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
435115516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
435215516c77SSepherosa Ziehau 			return (ENOMEM);
435315516c77SSepherosa Ziehau 		}
435415516c77SSepherosa Ziehau 
435515516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
435615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
435715516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
435815516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
435915516c77SSepherosa Ziehau 		if (hn_trust_hostip)
436015516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
436115516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
436215516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
436315516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
436415516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
436515516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
436615516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
436715516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
436815516c77SSepherosa Ziehau 
436915516c77SSepherosa Ziehau 		/*
437015516c77SSepherosa Ziehau 		 * Initialize LRO.
437115516c77SSepherosa Ziehau 		 */
437215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
437315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
437415516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
437515516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
437615516c77SSepherosa Ziehau #else
437715516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
437815516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
437915516c77SSepherosa Ziehau #endif
438015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
438115516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
438215516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
438315516c77SSepherosa Ziehau #endif
438415516c77SSepherosa Ziehau #endif	/* INET || INET6 */
438515516c77SSepherosa Ziehau 
438615516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
438715516c77SSepherosa Ziehau 			char name[16];
438815516c77SSepherosa Ziehau 
438915516c77SSepherosa Ziehau 			/*
439015516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
439115516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
439215516c77SSepherosa Ziehau 			 */
439315516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
439415516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
439515516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
439615516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
439715516c77SSepherosa Ziehau 
439815516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
439915516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
440015516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
440115516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
440215516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
440315516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
440415516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
440515516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
440615516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
440715516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
440815516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
440915516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
441015516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
441115516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
441215516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
441315516c77SSepherosa Ziehau 			}
441415516c77SSepherosa Ziehau 		}
441515516c77SSepherosa Ziehau 	}
441615516c77SSepherosa Ziehau 
441715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
441815516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
441915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
442015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
442115516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
442215516c77SSepherosa Ziehau #else
442315516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
442415516c77SSepherosa Ziehau #endif
442515516c77SSepherosa Ziehau 	    "LU", "LRO queued");
442615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
442715516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
442815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
442915516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
443015516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
443115516c77SSepherosa Ziehau #else
443215516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
443315516c77SSepherosa Ziehau #endif
443415516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
443515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
443615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
443715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
443815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
443915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
444015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
444115516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
444215516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
444315516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
444415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
444515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
444615516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
444715516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
444815516c77SSepherosa Ziehau #endif
444915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
445015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
445115516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
445215516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
445315516c77SSepherosa Ziehau 	    "when csum info is missing");
445415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
445515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
445615516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
445715516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
445815516c77SSepherosa Ziehau 	    "when csum info is missing");
445915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
446015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
446115516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
446215516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
446315516c77SSepherosa Ziehau 	    "when csum info is missing");
446415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
446515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
446615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
446715516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
446815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
446915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
447015516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
447115516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
447215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
447315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
447415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
447515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
447615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
447715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
447815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
447915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
448015516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
448115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
448215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
448315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
448415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
448515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
448615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
448715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
448815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
448915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
449015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
449115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
449215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
449315516c77SSepherosa Ziehau 
449415516c77SSepherosa Ziehau 	return (0);
449515516c77SSepherosa Ziehau }
449615516c77SSepherosa Ziehau 
449715516c77SSepherosa Ziehau static void
449815516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
449915516c77SSepherosa Ziehau {
450015516c77SSepherosa Ziehau 	int i;
450115516c77SSepherosa Ziehau 
450215516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
45032494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
450415516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
45052494d735SSepherosa Ziehau 		else
45062494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
450715516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
450815516c77SSepherosa Ziehau 	}
450915516c77SSepherosa Ziehau 
451015516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
451115516c77SSepherosa Ziehau 		return;
451215516c77SSepherosa Ziehau 
451315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
451415516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
451515516c77SSepherosa Ziehau 
451615516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
451715516c77SSepherosa Ziehau 			continue;
45182494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
451915516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
45202494d735SSepherosa Ziehau 		} else {
45212494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
45222494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
45232494d735SSepherosa Ziehau 		}
452415516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
452515516c77SSepherosa Ziehau 
452615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
452715516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
452815516c77SSepherosa Ziehau #endif
452915516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
453015516c77SSepherosa Ziehau 	}
453115516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
453215516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
453315516c77SSepherosa Ziehau 
453415516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
453515516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
453615516c77SSepherosa Ziehau }
453715516c77SSepherosa Ziehau 
453815516c77SSepherosa Ziehau static int
453915516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
454015516c77SSepherosa Ziehau {
454115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
454215516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
454315516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
454415516c77SSepherosa Ziehau 	int error, i;
454515516c77SSepherosa Ziehau 
454615516c77SSepherosa Ziehau 	txr->hn_sc = sc;
454715516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
454815516c77SSepherosa Ziehau 
454915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
455015516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
455115516c77SSepherosa Ziehau #endif
455215516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
455315516c77SSepherosa Ziehau 
455415516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
455515516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
455615516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
455715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
455815516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
455915516c77SSepherosa Ziehau #else
456015516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
456115516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
456215516c77SSepherosa Ziehau #endif
456315516c77SSepherosa Ziehau 
45640e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
45650e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
45660e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
45670e11868dSSepherosa Ziehau 	} else {
4568fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
45690e11868dSSepherosa Ziehau 	}
457015516c77SSepherosa Ziehau 
457123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
457215516c77SSepherosa Ziehau 	if (hn_use_if_start) {
457315516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
457415516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
457515516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
457623bf9e15SSepherosa Ziehau 	} else
457723bf9e15SSepherosa Ziehau #endif
457823bf9e15SSepherosa Ziehau 	{
457915516c77SSepherosa Ziehau 		int br_depth;
458015516c77SSepherosa Ziehau 
458115516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
458215516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
458315516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
458415516c77SSepherosa Ziehau 
458515516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
458615516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
458715516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
458815516c77SSepherosa Ziehau 	}
458915516c77SSepherosa Ziehau 
459015516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
459115516c77SSepherosa Ziehau 
459215516c77SSepherosa Ziehau 	/*
459315516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
459415516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
459515516c77SSepherosa Ziehau 	 */
459615516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
459715516c77SSepherosa Ziehau 
459815516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
459915516c77SSepherosa Ziehau 
460015516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
460115516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
460215516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
460315516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
460415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
460515516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
460615516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
460715516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
460815516c77SSepherosa Ziehau 	    1,				/* nsegments */
460915516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
461015516c77SSepherosa Ziehau 	    0,				/* flags */
461115516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
461215516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
461315516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
461415516c77SSepherosa Ziehau 	if (error) {
461515516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
461615516c77SSepherosa Ziehau 		return error;
461715516c77SSepherosa Ziehau 	}
461815516c77SSepherosa Ziehau 
461915516c77SSepherosa Ziehau 	/* DMA tag for data. */
462015516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
462115516c77SSepherosa Ziehau 	    1,				/* alignment */
462215516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
462315516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
462415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
462515516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
462615516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
462715516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
462815516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
462915516c77SSepherosa Ziehau 	    0,				/* flags */
463015516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
463115516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
463215516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
463315516c77SSepherosa Ziehau 	if (error) {
463415516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
463515516c77SSepherosa Ziehau 		return error;
463615516c77SSepherosa Ziehau 	}
463715516c77SSepherosa Ziehau 
463815516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
463915516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
464015516c77SSepherosa Ziehau 
464115516c77SSepherosa Ziehau 		txd->txr = txr;
464215516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
4643dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
464415516c77SSepherosa Ziehau 
464515516c77SSepherosa Ziehau 		/*
464615516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
464715516c77SSepherosa Ziehau 		 */
464815516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
464915516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
465015516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
465115516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
465215516c77SSepherosa Ziehau 		if (error) {
465315516c77SSepherosa Ziehau 			device_printf(dev,
465415516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
465515516c77SSepherosa Ziehau 			return error;
465615516c77SSepherosa Ziehau 		}
465715516c77SSepherosa Ziehau 
465815516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
465915516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
466015516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
466115516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
466215516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
466315516c77SSepherosa Ziehau 		if (error) {
466415516c77SSepherosa Ziehau 			device_printf(dev,
466515516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
466615516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
466715516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
466815516c77SSepherosa Ziehau 			return error;
466915516c77SSepherosa Ziehau 		}
467015516c77SSepherosa Ziehau 
467115516c77SSepherosa Ziehau 		/* DMA map for TX data. */
467215516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
467315516c77SSepherosa Ziehau 		    &txd->data_dmap);
467415516c77SSepherosa Ziehau 		if (error) {
467515516c77SSepherosa Ziehau 			device_printf(dev,
467615516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
467715516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
467815516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
467915516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
468015516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
468115516c77SSepherosa Ziehau 			return error;
468215516c77SSepherosa Ziehau 		}
468315516c77SSepherosa Ziehau 
468415516c77SSepherosa Ziehau 		/* All set, put it to list */
468515516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
468615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
468715516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
468815516c77SSepherosa Ziehau #else
468915516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
469015516c77SSepherosa Ziehau #endif
469115516c77SSepherosa Ziehau 	}
469215516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
469315516c77SSepherosa Ziehau 
469415516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
469515516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
469615516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
469715516c77SSepherosa Ziehau 		char name[16];
469815516c77SSepherosa Ziehau 
469915516c77SSepherosa Ziehau 		/*
470015516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
470115516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
470215516c77SSepherosa Ziehau 		 */
470315516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
470415516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
470515516c77SSepherosa Ziehau 
470615516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
470715516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
470815516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
470915516c77SSepherosa Ziehau 
471015516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
471115516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
471215516c77SSepherosa Ziehau 
471385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
471415516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
471515516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
471615516c77SSepherosa Ziehau 			    "# of available TX descs");
471785e4ae1eSSepherosa Ziehau #endif
471823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
471923bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
472023bf9e15SSepherosa Ziehau #endif
472123bf9e15SSepherosa Ziehau 			{
472215516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
472315516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
472415516c77SSepherosa Ziehau 				    "over active");
472515516c77SSepherosa Ziehau 			}
472615516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
472715516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
472815516c77SSepherosa Ziehau 			    "# of packets transmitted");
4729dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
4730dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
473115516c77SSepherosa Ziehau 		}
473215516c77SSepherosa Ziehau 	}
473315516c77SSepherosa Ziehau 
473415516c77SSepherosa Ziehau 	return 0;
473515516c77SSepherosa Ziehau }
473615516c77SSepherosa Ziehau 
473715516c77SSepherosa Ziehau static void
473815516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
473915516c77SSepherosa Ziehau {
474015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
474115516c77SSepherosa Ziehau 
474215516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
474315516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
474415516c77SSepherosa Ziehau 
474515516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
474615516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
474715516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
474815516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
474915516c77SSepherosa Ziehau }
475015516c77SSepherosa Ziehau 
475115516c77SSepherosa Ziehau static void
475225641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
475325641fc7SSepherosa Ziehau {
475425641fc7SSepherosa Ziehau 
475525641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
475625641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
475725641fc7SSepherosa Ziehau 
475825641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
475925641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
476025641fc7SSepherosa Ziehau 		int freed;
476125641fc7SSepherosa Ziehau 
476225641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
476325641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
476425641fc7SSepherosa Ziehau 	}
476525641fc7SSepherosa Ziehau }
476625641fc7SSepherosa Ziehau 
476725641fc7SSepherosa Ziehau static void
476815516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
476915516c77SSepherosa Ziehau {
477025641fc7SSepherosa Ziehau 	int i;
477115516c77SSepherosa Ziehau 
477215516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
477315516c77SSepherosa Ziehau 		return;
477415516c77SSepherosa Ziehau 
477525641fc7SSepherosa Ziehau 	/*
477625641fc7SSepherosa Ziehau 	 * NOTE:
477725641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
477825641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
477925641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
478025641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
478125641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
478225641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
478325641fc7SSepherosa Ziehau 	 *   were freed.
478425641fc7SSepherosa Ziehau 	 */
478525641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
478625641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
478725641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
478825641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
478915516c77SSepherosa Ziehau 
479015516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
479115516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
479215516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
479315516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
479415516c77SSepherosa Ziehau 
479515516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
479615516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
479715516c77SSepherosa Ziehau #endif
479815516c77SSepherosa Ziehau 
479915516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
480015516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
480115516c77SSepherosa Ziehau 
480215516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
480315516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
480415516c77SSepherosa Ziehau 
480515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
480615516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
480715516c77SSepherosa Ziehau #endif
480815516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
480915516c77SSepherosa Ziehau }
481015516c77SSepherosa Ziehau 
481115516c77SSepherosa Ziehau static int
481215516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
481315516c77SSepherosa Ziehau {
481415516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
481515516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
481615516c77SSepherosa Ziehau 	int i;
481715516c77SSepherosa Ziehau 
481815516c77SSepherosa Ziehau 	/*
481915516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
482015516c77SSepherosa Ziehau 	 *
482115516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
482215516c77SSepherosa Ziehau 	 */
482315516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
482415516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
482515516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
482615516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
482715516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
482815516c77SSepherosa Ziehau 		return (ENOMEM);
482915516c77SSepherosa Ziehau 	}
483015516c77SSepherosa Ziehau 
483115516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
483215516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
483315516c77SSepherosa Ziehau 
483415516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
483515516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
483615516c77SSepherosa Ziehau 
483715516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
483815516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
483915516c77SSepherosa Ziehau 
484015516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
484115516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
484215516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
484315516c77SSepherosa Ziehau 
484415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
484515516c77SSepherosa Ziehau 		int error;
484615516c77SSepherosa Ziehau 
484715516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
484815516c77SSepherosa Ziehau 		if (error)
484915516c77SSepherosa Ziehau 			return error;
485015516c77SSepherosa Ziehau 	}
485115516c77SSepherosa Ziehau 
485215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
485315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
485415516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
485515516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
485615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
485715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
485815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
485915516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
486015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
486115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
486215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
486315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
4864dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
4865dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
4866dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
4867dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
4868dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
486915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
487015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
487115516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
487215516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
487315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
487415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
487515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
487615516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
487715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
487815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
487915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
488015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
488115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
488215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
488315516c77SSepherosa Ziehau 	    "# of total TX descs");
488415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
488515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
488615516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
488715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
488815516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
488915516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
489015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
489115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
489215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
489315516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
489415516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
489515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
489615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
489715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
489815516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
489915516c77SSepherosa Ziehau 	    "Always schedule transmission "
490015516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
490115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
490215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
490315516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
490415516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
4905dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
4906dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
4907dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
4908dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
4909dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
4910dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
4911dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
4912dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
4913dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
4914dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
4915dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
491615516c77SSepherosa Ziehau 
491715516c77SSepherosa Ziehau 	return 0;
491815516c77SSepherosa Ziehau }
491915516c77SSepherosa Ziehau 
492015516c77SSepherosa Ziehau static void
492115516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
492215516c77SSepherosa Ziehau {
492315516c77SSepherosa Ziehau 	int i;
492415516c77SSepherosa Ziehau 
4925a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
492615516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
492715516c77SSepherosa Ziehau }
492815516c77SSepherosa Ziehau 
492915516c77SSepherosa Ziehau static void
493015516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
493115516c77SSepherosa Ziehau {
493215516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
4933*9c6cae24SSepherosa Ziehau 	u_int hw_tsomax;
493415516c77SSepherosa Ziehau 	int tso_minlen;
493515516c77SSepherosa Ziehau 
4936*9c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
4937*9c6cae24SSepherosa Ziehau 
493815516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
493915516c77SSepherosa Ziehau 		return;
494015516c77SSepherosa Ziehau 
494115516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
494215516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
494315516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
494415516c77SSepherosa Ziehau 
494515516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
494615516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
494715516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
494815516c77SSepherosa Ziehau 
494915516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
495015516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
495115516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
495215516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
495315516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
495415516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
4955*9c6cae24SSepherosa Ziehau 	hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
4956*9c6cae24SSepherosa Ziehau 
4957*9c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
4958*9c6cae24SSepherosa Ziehau 		if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax)
4959*9c6cae24SSepherosa Ziehau 			hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax;
4960*9c6cae24SSepherosa Ziehau 	}
4961*9c6cae24SSepherosa Ziehau 	ifp->if_hw_tsomax = hw_tsomax;
496215516c77SSepherosa Ziehau 	if (bootverbose)
496315516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
496415516c77SSepherosa Ziehau }
496515516c77SSepherosa Ziehau 
496615516c77SSepherosa Ziehau static void
496715516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
496815516c77SSepherosa Ziehau {
496915516c77SSepherosa Ziehau 	uint64_t csum_assist;
497015516c77SSepherosa Ziehau 	int i;
497115516c77SSepherosa Ziehau 
497215516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
497315516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
497415516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
497515516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
497615516c77SSepherosa Ziehau 
497715516c77SSepherosa Ziehau 	csum_assist = 0;
497815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
497915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
498015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
498115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
498215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
498315516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
498415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
498515516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
498615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
498715516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
498815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
498915516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
499015516c77SSepherosa Ziehau 
499115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
499215516c77SSepherosa Ziehau 		/*
499315516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
499415516c77SSepherosa Ziehau 		 */
499515516c77SSepherosa Ziehau 		if (bootverbose)
499615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
499715516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
499815516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
499915516c77SSepherosa Ziehau 	}
500015516c77SSepherosa Ziehau }
500115516c77SSepherosa Ziehau 
500215516c77SSepherosa Ziehau static void
500315516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
500415516c77SSepherosa Ziehau {
500515516c77SSepherosa Ziehau 	int i;
500615516c77SSepherosa Ziehau 
500715516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
50082494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
500915516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
50102494d735SSepherosa Ziehau 		} else {
50112494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
50122494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
50132494d735SSepherosa Ziehau 		}
501415516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
501515516c77SSepherosa Ziehau 	}
501615516c77SSepherosa Ziehau 
501715516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
501815516c77SSepherosa Ziehau 		return;
501915516c77SSepherosa Ziehau 
502015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
502115516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
502215516c77SSepherosa Ziehau 
502315516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
502415516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
502515516c77SSepherosa Ziehau 
502615516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
502715516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
502815516c77SSepherosa Ziehau }
502915516c77SSepherosa Ziehau 
503023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
503123bf9e15SSepherosa Ziehau 
503215516c77SSepherosa Ziehau static void
503315516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
503415516c77SSepherosa Ziehau {
503515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
503615516c77SSepherosa Ziehau 
503715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
503815516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
503915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
504015516c77SSepherosa Ziehau }
504115516c77SSepherosa Ziehau 
504223bf9e15SSepherosa Ziehau static int
504323bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
504423bf9e15SSepherosa Ziehau {
504523bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
504623bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
5047dc13fee6SSepherosa Ziehau 	int sched = 0;
504823bf9e15SSepherosa Ziehau 
504923bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
505023bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
505123bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
505223bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
5053dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
505423bf9e15SSepherosa Ziehau 
505523bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5056dc13fee6SSepherosa Ziehau 		return (0);
505723bf9e15SSepherosa Ziehau 
505823bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
505923bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
5060dc13fee6SSepherosa Ziehau 		return (0);
506123bf9e15SSepherosa Ziehau 
506223bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
506323bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
506423bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
506523bf9e15SSepherosa Ziehau 		int error;
506623bf9e15SSepherosa Ziehau 
506723bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
506823bf9e15SSepherosa Ziehau 		if (m_head == NULL)
506923bf9e15SSepherosa Ziehau 			break;
507023bf9e15SSepherosa Ziehau 
507123bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
507223bf9e15SSepherosa Ziehau 			/*
507323bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
507423bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
507523bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
507623bf9e15SSepherosa Ziehau 			 */
507723bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5078dc13fee6SSepherosa Ziehau 			sched = 1;
5079dc13fee6SSepherosa Ziehau 			break;
508023bf9e15SSepherosa Ziehau 		}
508123bf9e15SSepherosa Ziehau 
5082edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5083edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
5084edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
5085edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5086edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5087edd3f315SSepherosa Ziehau 				continue;
5088edd3f315SSepherosa Ziehau 			}
5089edd3f315SSepherosa Ziehau 		}
5090edd3f315SSepherosa Ziehau #endif
5091edd3f315SSepherosa Ziehau 
509223bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
509323bf9e15SSepherosa Ziehau 		if (txd == NULL) {
509423bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
509523bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
509623bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
509723bf9e15SSepherosa Ziehau 			break;
509823bf9e15SSepherosa Ziehau 		}
509923bf9e15SSepherosa Ziehau 
5100dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
510123bf9e15SSepherosa Ziehau 		if (error) {
510223bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
5103dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5104dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
510523bf9e15SSepherosa Ziehau 			continue;
510623bf9e15SSepherosa Ziehau 		}
510723bf9e15SSepherosa Ziehau 
5108dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5109dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5110dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5111dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5112dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
5113dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5114dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5115dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
5116dc13fee6SSepherosa Ziehau 					break;
5117dc13fee6SSepherosa Ziehau 				}
5118dc13fee6SSepherosa Ziehau 			} else {
5119dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
512023bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
512123bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
512223bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
512323bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5124dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5125dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
512623bf9e15SSepherosa Ziehau 					break;
512723bf9e15SSepherosa Ziehau 				}
512823bf9e15SSepherosa Ziehau 			}
5129dc13fee6SSepherosa Ziehau 		}
5130dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5131dc13fee6SSepherosa Ziehau 		else {
5132dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5133dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5134dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5135dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5136dc13fee6SSepherosa Ziehau 		}
5137dc13fee6SSepherosa Ziehau #endif
5138dc13fee6SSepherosa Ziehau 	}
5139dc13fee6SSepherosa Ziehau 
5140dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5141dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5142dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5143dc13fee6SSepherosa Ziehau 	return (sched);
514423bf9e15SSepherosa Ziehau }
514523bf9e15SSepherosa Ziehau 
514623bf9e15SSepherosa Ziehau static void
514723bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
514823bf9e15SSepherosa Ziehau {
514923bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
515023bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
515123bf9e15SSepherosa Ziehau 
515223bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
515323bf9e15SSepherosa Ziehau 		goto do_sched;
515423bf9e15SSepherosa Ziehau 
515523bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
515623bf9e15SSepherosa Ziehau 		int sched;
515723bf9e15SSepherosa Ziehau 
515823bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
515923bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
516023bf9e15SSepherosa Ziehau 		if (!sched)
516123bf9e15SSepherosa Ziehau 			return;
516223bf9e15SSepherosa Ziehau 	}
516323bf9e15SSepherosa Ziehau do_sched:
516423bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
516523bf9e15SSepherosa Ziehau }
516623bf9e15SSepherosa Ziehau 
516715516c77SSepherosa Ziehau static void
516815516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
516915516c77SSepherosa Ziehau {
517015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
517115516c77SSepherosa Ziehau 
517215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
517315516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
517415516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
517515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
517615516c77SSepherosa Ziehau }
517715516c77SSepherosa Ziehau 
517823bf9e15SSepherosa Ziehau static void
517923bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
518023bf9e15SSepherosa Ziehau {
518123bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
518223bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
518323bf9e15SSepherosa Ziehau 
518423bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
518523bf9e15SSepherosa Ziehau 
518623bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
518723bf9e15SSepherosa Ziehau 		goto do_sched;
518823bf9e15SSepherosa Ziehau 
518923bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
519023bf9e15SSepherosa Ziehau 		int sched;
519123bf9e15SSepherosa Ziehau 
519223bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
519323bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
519423bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
519523bf9e15SSepherosa Ziehau 		if (sched) {
519623bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
519723bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
519823bf9e15SSepherosa Ziehau 		}
519923bf9e15SSepherosa Ziehau 	} else {
520023bf9e15SSepherosa Ziehau do_sched:
520123bf9e15SSepherosa Ziehau 		/*
520223bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
520323bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
520423bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
520523bf9e15SSepherosa Ziehau 		 * races.
520623bf9e15SSepherosa Ziehau 		 */
520723bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
520823bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
520923bf9e15SSepherosa Ziehau 	}
521023bf9e15SSepherosa Ziehau }
521123bf9e15SSepherosa Ziehau 
521223bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
521323bf9e15SSepherosa Ziehau 
521415516c77SSepherosa Ziehau static int
521515516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
521615516c77SSepherosa Ziehau {
521715516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
521815516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
521915516c77SSepherosa Ziehau 	struct mbuf *m_head;
5220dc13fee6SSepherosa Ziehau 	int sched = 0;
522115516c77SSepherosa Ziehau 
522215516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
522323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
522415516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
522515516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
522623bf9e15SSepherosa Ziehau #endif
5227dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
522815516c77SSepherosa Ziehau 
522915516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5230dc13fee6SSepherosa Ziehau 		return (0);
523115516c77SSepherosa Ziehau 
523215516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
5233dc13fee6SSepherosa Ziehau 		return (0);
523415516c77SSepherosa Ziehau 
523515516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
523615516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
523715516c77SSepherosa Ziehau 		int error;
523815516c77SSepherosa Ziehau 
523915516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
524015516c77SSepherosa Ziehau 			/*
524115516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
524215516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
524315516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
524415516c77SSepherosa Ziehau 			 */
524515516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
5246dc13fee6SSepherosa Ziehau 			sched = 1;
5247dc13fee6SSepherosa Ziehau 			break;
524815516c77SSepherosa Ziehau 		}
524915516c77SSepherosa Ziehau 
525015516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
525115516c77SSepherosa Ziehau 		if (txd == NULL) {
525215516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
525315516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
525415516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
525515516c77SSepherosa Ziehau 			break;
525615516c77SSepherosa Ziehau 		}
525715516c77SSepherosa Ziehau 
5258dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
525915516c77SSepherosa Ziehau 		if (error) {
526015516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
5261dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5262dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
526315516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
526415516c77SSepherosa Ziehau 			continue;
526515516c77SSepherosa Ziehau 		}
526615516c77SSepherosa Ziehau 
5267dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5268dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5269dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5270dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5271dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
527215516c77SSepherosa Ziehau 				if (__predict_false(error)) {
527315516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
527415516c77SSepherosa Ziehau 					break;
527515516c77SSepherosa Ziehau 				}
5276dc13fee6SSepherosa Ziehau 			} else {
5277dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
5278dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
5279dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5280dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
5281dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
5282dc13fee6SSepherosa Ziehau 					    m_head);
5283dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
5284dc13fee6SSepherosa Ziehau 					break;
5285dc13fee6SSepherosa Ziehau 				}
5286dc13fee6SSepherosa Ziehau 			}
5287dc13fee6SSepherosa Ziehau 		}
5288dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5289dc13fee6SSepherosa Ziehau 		else {
5290dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5291dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5292dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5293dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5294dc13fee6SSepherosa Ziehau 		}
5295dc13fee6SSepherosa Ziehau #endif
529615516c77SSepherosa Ziehau 
529715516c77SSepherosa Ziehau 		/* Sent */
529815516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
529915516c77SSepherosa Ziehau 	}
5300dc13fee6SSepherosa Ziehau 
5301dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5302dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5303dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5304dc13fee6SSepherosa Ziehau 	return (sched);
530515516c77SSepherosa Ziehau }
530615516c77SSepherosa Ziehau 
530715516c77SSepherosa Ziehau static int
530815516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
530915516c77SSepherosa Ziehau {
531015516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
531115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
531215516c77SSepherosa Ziehau 	int error, idx = 0;
531315516c77SSepherosa Ziehau 
5314*9c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
5315*9c6cae24SSepherosa Ziehau 		struct rm_priotracker pt;
5316*9c6cae24SSepherosa Ziehau 
5317*9c6cae24SSepherosa Ziehau 		rm_rlock(&sc->hn_vf_lock, &pt);
5318*9c6cae24SSepherosa Ziehau 		if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
5319*9c6cae24SSepherosa Ziehau 			struct mbuf *m_bpf = NULL;
5320*9c6cae24SSepherosa Ziehau 			int obytes, omcast;
5321*9c6cae24SSepherosa Ziehau 
5322*9c6cae24SSepherosa Ziehau 			obytes = m->m_pkthdr.len;
5323*9c6cae24SSepherosa Ziehau 			if (m->m_flags & M_MCAST)
5324*9c6cae24SSepherosa Ziehau 				omcast = 1;
5325*9c6cae24SSepherosa Ziehau 
5326*9c6cae24SSepherosa Ziehau 			if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) {
5327*9c6cae24SSepherosa Ziehau 				if (bpf_peers_present(ifp->if_bpf)) {
5328*9c6cae24SSepherosa Ziehau 					m_bpf = m_copypacket(m, M_NOWAIT);
5329*9c6cae24SSepherosa Ziehau 					if (m_bpf == NULL) {
5330*9c6cae24SSepherosa Ziehau 						/*
5331*9c6cae24SSepherosa Ziehau 						 * Failed to grab a shallow
5332*9c6cae24SSepherosa Ziehau 						 * copy; tap now.
5333*9c6cae24SSepherosa Ziehau 						 */
5334*9c6cae24SSepherosa Ziehau 						ETHER_BPF_MTAP(ifp, m);
5335*9c6cae24SSepherosa Ziehau 					}
5336*9c6cae24SSepherosa Ziehau 				}
5337*9c6cae24SSepherosa Ziehau 			} else {
5338*9c6cae24SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, m);
5339*9c6cae24SSepherosa Ziehau 			}
5340*9c6cae24SSepherosa Ziehau 
5341*9c6cae24SSepherosa Ziehau 			error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m);
5342*9c6cae24SSepherosa Ziehau 			rm_runlock(&sc->hn_vf_lock, &pt);
5343*9c6cae24SSepherosa Ziehau 
5344*9c6cae24SSepherosa Ziehau 			if (m_bpf != NULL) {
5345*9c6cae24SSepherosa Ziehau 				if (!error)
5346*9c6cae24SSepherosa Ziehau 					ETHER_BPF_MTAP(ifp, m_bpf);
5347*9c6cae24SSepherosa Ziehau 				m_freem(m_bpf);
5348*9c6cae24SSepherosa Ziehau 			}
5349*9c6cae24SSepherosa Ziehau 
5350*9c6cae24SSepherosa Ziehau 			if (error == ENOBUFS) {
5351*9c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
5352*9c6cae24SSepherosa Ziehau 			} else if (error) {
5353*9c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5354*9c6cae24SSepherosa Ziehau 			} else {
5355*9c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
5356*9c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes);
5357*9c6cae24SSepherosa Ziehau 				if (omcast) {
5358*9c6cae24SSepherosa Ziehau 					if_inc_counter(ifp, IFCOUNTER_OMCASTS,
5359*9c6cae24SSepherosa Ziehau 					    omcast);
5360*9c6cae24SSepherosa Ziehau 				}
5361*9c6cae24SSepherosa Ziehau 			}
5362*9c6cae24SSepherosa Ziehau 			return (error);
5363*9c6cae24SSepherosa Ziehau 		}
5364*9c6cae24SSepherosa Ziehau 		rm_runlock(&sc->hn_vf_lock, &pt);
5365*9c6cae24SSepherosa Ziehau 	}
5366*9c6cae24SSepherosa Ziehau 
5367edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5368edd3f315SSepherosa Ziehau 	/*
5369edd3f315SSepherosa Ziehau 	 * Perform TSO packet header fixup now, since the TSO
5370edd3f315SSepherosa Ziehau 	 * packet header should be cache-hot.
5371edd3f315SSepherosa Ziehau 	 */
5372edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
5373edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
5374edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
5375edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5376edd3f315SSepherosa Ziehau 			return EIO;
5377edd3f315SSepherosa Ziehau 		}
5378edd3f315SSepherosa Ziehau 	}
5379edd3f315SSepherosa Ziehau #endif
5380edd3f315SSepherosa Ziehau 
538115516c77SSepherosa Ziehau 	/*
538215516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
538315516c77SSepherosa Ziehau 	 */
538434d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
538534d68912SSepherosa Ziehau #ifdef RSS
538634d68912SSepherosa Ziehau 		uint32_t bid;
538734d68912SSepherosa Ziehau 
538834d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
538934d68912SSepherosa Ziehau 		    &bid) == 0)
539034d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
539134d68912SSepherosa Ziehau 		else
539234d68912SSepherosa Ziehau #endif
5393cc0c6ebcSSepherosa Ziehau 		{
5394cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET)
5395cc0c6ebcSSepherosa Ziehau 			int tcpsyn = 0;
5396cc0c6ebcSSepherosa Ziehau 
5397cc0c6ebcSSepherosa Ziehau 			if (m->m_pkthdr.len < 128 &&
5398cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags &
5399cc0c6ebcSSepherosa Ziehau 			     (CSUM_IP_TCP | CSUM_IP6_TCP)) &&
5400cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
5401cc0c6ebcSSepherosa Ziehau 				m = hn_check_tcpsyn(m, &tcpsyn);
5402cc0c6ebcSSepherosa Ziehau 				if (__predict_false(m == NULL)) {
5403cc0c6ebcSSepherosa Ziehau 					if_inc_counter(ifp,
5404cc0c6ebcSSepherosa Ziehau 					    IFCOUNTER_OERRORS, 1);
5405cc0c6ebcSSepherosa Ziehau 					return (EIO);
5406cc0c6ebcSSepherosa Ziehau 				}
5407cc0c6ebcSSepherosa Ziehau 			}
5408cc0c6ebcSSepherosa Ziehau #else
5409cc0c6ebcSSepherosa Ziehau 			const int tcpsyn = 0;
5410cc0c6ebcSSepherosa Ziehau #endif
5411cc0c6ebcSSepherosa Ziehau 			if (tcpsyn)
5412cc0c6ebcSSepherosa Ziehau 				idx = 0;
5413cc0c6ebcSSepherosa Ziehau 			else
541415516c77SSepherosa Ziehau 				idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
541534d68912SSepherosa Ziehau 		}
5416cc0c6ebcSSepherosa Ziehau 	}
541715516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
541815516c77SSepherosa Ziehau 
541915516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
542015516c77SSepherosa Ziehau 	if (error) {
542115516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
542215516c77SSepherosa Ziehau 		return error;
542315516c77SSepherosa Ziehau 	}
542415516c77SSepherosa Ziehau 
542515516c77SSepherosa Ziehau 	if (txr->hn_oactive)
542615516c77SSepherosa Ziehau 		return 0;
542715516c77SSepherosa Ziehau 
542815516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
542915516c77SSepherosa Ziehau 		goto do_sched;
543015516c77SSepherosa Ziehau 
543115516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
543215516c77SSepherosa Ziehau 		int sched;
543315516c77SSepherosa Ziehau 
543415516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
543515516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
543615516c77SSepherosa Ziehau 		if (!sched)
543715516c77SSepherosa Ziehau 			return 0;
543815516c77SSepherosa Ziehau 	}
543915516c77SSepherosa Ziehau do_sched:
544015516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
544115516c77SSepherosa Ziehau 	return 0;
544215516c77SSepherosa Ziehau }
544315516c77SSepherosa Ziehau 
544415516c77SSepherosa Ziehau static void
544515516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
544615516c77SSepherosa Ziehau {
544715516c77SSepherosa Ziehau 	struct mbuf *m;
544815516c77SSepherosa Ziehau 
544915516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
545015516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
545115516c77SSepherosa Ziehau 		m_freem(m);
545215516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
545315516c77SSepherosa Ziehau }
545415516c77SSepherosa Ziehau 
545515516c77SSepherosa Ziehau static void
545615516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
545715516c77SSepherosa Ziehau {
545815516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
5459*9c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
546015516c77SSepherosa Ziehau 	int i;
546115516c77SSepherosa Ziehau 
546215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
546315516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
546415516c77SSepherosa Ziehau 	if_qflush(ifp);
5465*9c6cae24SSepherosa Ziehau 
5466*9c6cae24SSepherosa Ziehau 	rm_rlock(&sc->hn_vf_lock, &pt);
5467*9c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
5468*9c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp);
5469*9c6cae24SSepherosa Ziehau 	rm_runlock(&sc->hn_vf_lock, &pt);
547015516c77SSepherosa Ziehau }
547115516c77SSepherosa Ziehau 
547215516c77SSepherosa Ziehau static void
547315516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
547415516c77SSepherosa Ziehau {
547515516c77SSepherosa Ziehau 
547615516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
547715516c77SSepherosa Ziehau 		goto do_sched;
547815516c77SSepherosa Ziehau 
547915516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
548015516c77SSepherosa Ziehau 		int sched;
548115516c77SSepherosa Ziehau 
548215516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
548315516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
548415516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
548515516c77SSepherosa Ziehau 		if (sched) {
548615516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
548715516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
548815516c77SSepherosa Ziehau 		}
548915516c77SSepherosa Ziehau 	} else {
549015516c77SSepherosa Ziehau do_sched:
549115516c77SSepherosa Ziehau 		/*
549215516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
549315516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
549415516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
549515516c77SSepherosa Ziehau 		 * races.
549615516c77SSepherosa Ziehau 		 */
549715516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
549815516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
549915516c77SSepherosa Ziehau 	}
550015516c77SSepherosa Ziehau }
550115516c77SSepherosa Ziehau 
550215516c77SSepherosa Ziehau static void
550315516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
550415516c77SSepherosa Ziehau {
550515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
550615516c77SSepherosa Ziehau 
550715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
550815516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
550915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
551015516c77SSepherosa Ziehau }
551115516c77SSepherosa Ziehau 
551215516c77SSepherosa Ziehau static void
551315516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
551415516c77SSepherosa Ziehau {
551515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
551615516c77SSepherosa Ziehau 
551715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
551815516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
551915516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
552015516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
552115516c77SSepherosa Ziehau }
552215516c77SSepherosa Ziehau 
552315516c77SSepherosa Ziehau static int
552415516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
552515516c77SSepherosa Ziehau {
552615516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
552715516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
552815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
552915516c77SSepherosa Ziehau 	int idx, error;
553015516c77SSepherosa Ziehau 
553115516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
553215516c77SSepherosa Ziehau 
553315516c77SSepherosa Ziehau 	/*
553415516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
553515516c77SSepherosa Ziehau 	 */
553615516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
553715516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
553815516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
553915516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
554015516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
554115516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
554215516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
55433ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
554415516c77SSepherosa Ziehau 
554515516c77SSepherosa Ziehau 	if (bootverbose) {
554615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
554715516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
554815516c77SSepherosa Ziehau 	}
554915516c77SSepherosa Ziehau 
555015516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
555115516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
555215516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
555315516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
555415516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
555515516c77SSepherosa Ziehau 
555615516c77SSepherosa Ziehau 		txr->hn_chan = chan;
555715516c77SSepherosa Ziehau 		if (bootverbose) {
555815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
555915516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
556015516c77SSepherosa Ziehau 		}
556115516c77SSepherosa Ziehau 	}
556215516c77SSepherosa Ziehau 
556315516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
55640e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
556515516c77SSepherosa Ziehau 
556615516c77SSepherosa Ziehau 	/*
556715516c77SSepherosa Ziehau 	 * Open this channel
556815516c77SSepherosa Ziehau 	 */
556915516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
557015516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
557115516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
557215516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
557315516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
557415516c77SSepherosa Ziehau 	if (error) {
557571e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
557671e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
557771e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
557871e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
557971e8ac56SSepherosa Ziehau 		} else {
558015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
558115516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
558271e8ac56SSepherosa Ziehau 		}
558315516c77SSepherosa Ziehau 	}
558415516c77SSepherosa Ziehau 	return (error);
558515516c77SSepherosa Ziehau }
558615516c77SSepherosa Ziehau 
558715516c77SSepherosa Ziehau static void
558815516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
558915516c77SSepherosa Ziehau {
559015516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
55912494d735SSepherosa Ziehau 	int idx, error;
559215516c77SSepherosa Ziehau 
559315516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
559415516c77SSepherosa Ziehau 
559515516c77SSepherosa Ziehau 	/*
559615516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
559715516c77SSepherosa Ziehau 	 */
559815516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
559915516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
560015516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
560115516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
560215516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
560315516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
560415516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
560515516c77SSepherosa Ziehau 
560615516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
560715516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
560815516c77SSepherosa Ziehau 
560915516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
561015516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
561115516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
561215516c77SSepherosa Ziehau 	}
561315516c77SSepherosa Ziehau 
561415516c77SSepherosa Ziehau 	/*
561515516c77SSepherosa Ziehau 	 * Close this channel.
561615516c77SSepherosa Ziehau 	 *
561715516c77SSepherosa Ziehau 	 * NOTE:
561815516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
561915516c77SSepherosa Ziehau 	 */
56202494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
56212494d735SSepherosa Ziehau 	if (error == EISCONN) {
5622aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
5623aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
56242494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
56252494d735SSepherosa Ziehau 	} else if (error) {
5626aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
5627aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
56282494d735SSepherosa Ziehau 	}
562915516c77SSepherosa Ziehau }
563015516c77SSepherosa Ziehau 
563115516c77SSepherosa Ziehau static int
563215516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
563315516c77SSepherosa Ziehau {
563415516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
563515516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
563615516c77SSepherosa Ziehau 	int i, error = 0;
563715516c77SSepherosa Ziehau 
563871e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
563915516c77SSepherosa Ziehau 
564015516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
564115516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
564215516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
564371e8ac56SSepherosa Ziehau 		int error1;
564471e8ac56SSepherosa Ziehau 
564571e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
564671e8ac56SSepherosa Ziehau 		if (error1) {
564771e8ac56SSepherosa Ziehau 			error = error1;
564871e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
564971e8ac56SSepherosa Ziehau 		}
565015516c77SSepherosa Ziehau 	}
565115516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
565215516c77SSepherosa Ziehau 
565315516c77SSepherosa Ziehau 	if (error) {
565415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
565515516c77SSepherosa Ziehau 	} else {
565615516c77SSepherosa Ziehau 		if (bootverbose) {
565715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
565815516c77SSepherosa Ziehau 			    subchan_cnt);
565915516c77SSepherosa Ziehau 		}
566015516c77SSepherosa Ziehau 	}
566115516c77SSepherosa Ziehau 	return (error);
566215516c77SSepherosa Ziehau }
566315516c77SSepherosa Ziehau 
566415516c77SSepherosa Ziehau static void
566515516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
566615516c77SSepherosa Ziehau {
566715516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
566815516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
566915516c77SSepherosa Ziehau 	int i;
567015516c77SSepherosa Ziehau 
567115516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
567215516c77SSepherosa Ziehau 		goto back;
567315516c77SSepherosa Ziehau 
567415516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
567515516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
567615516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
567715516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
567815516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
567915516c77SSepherosa Ziehau 
568015516c77SSepherosa Ziehau back:
568115516c77SSepherosa Ziehau 	/*
568215516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
568315516c77SSepherosa Ziehau 	 * are detached.
568415516c77SSepherosa Ziehau 	 */
568515516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
568615516c77SSepherosa Ziehau 
568715516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
568815516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
568915516c77SSepherosa Ziehau 
569015516c77SSepherosa Ziehau #ifdef INVARIANTS
569115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
569215516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
569315516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
569415516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
569515516c77SSepherosa Ziehau 	}
569615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
569715516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
569815516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
569915516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
570015516c77SSepherosa Ziehau 	}
570115516c77SSepherosa Ziehau #endif
570215516c77SSepherosa Ziehau }
570315516c77SSepherosa Ziehau 
570415516c77SSepherosa Ziehau static int
570515516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
570615516c77SSepherosa Ziehau {
570715516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
570815516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
570915516c77SSepherosa Ziehau 
571015516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
571115516c77SSepherosa Ziehau 	if (nchan == 1) {
571215516c77SSepherosa Ziehau 		/*
571315516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
571415516c77SSepherosa Ziehau 		 */
571515516c77SSepherosa Ziehau 		*nsubch = 0;
571615516c77SSepherosa Ziehau 		return (0);
571715516c77SSepherosa Ziehau 	}
571815516c77SSepherosa Ziehau 
571915516c77SSepherosa Ziehau 	/*
572015516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
572115516c77SSepherosa Ziehau 	 * table entries.
572215516c77SSepherosa Ziehau 	 */
572315516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
572415516c77SSepherosa Ziehau 	if (error) {
572515516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
572615516c77SSepherosa Ziehau 		*nsubch = 0;
572715516c77SSepherosa Ziehau 		return (0);
572815516c77SSepherosa Ziehau 	}
572915516c77SSepherosa Ziehau 	if (bootverbose) {
573015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
573115516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
573215516c77SSepherosa Ziehau 	}
573315516c77SSepherosa Ziehau 
573415516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
573515516c77SSepherosa Ziehau 		nchan = rxr_cnt;
573615516c77SSepherosa Ziehau 	if (nchan == 1) {
573715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
573815516c77SSepherosa Ziehau 		*nsubch = 0;
573915516c77SSepherosa Ziehau 		return (0);
574015516c77SSepherosa Ziehau 	}
574115516c77SSepherosa Ziehau 
574215516c77SSepherosa Ziehau 	/*
574315516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
574415516c77SSepherosa Ziehau 	 */
574515516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
574615516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
574715516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
574815516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
574915516c77SSepherosa Ziehau 		*nsubch = 0;
575015516c77SSepherosa Ziehau 		return (0);
575115516c77SSepherosa Ziehau 	}
575215516c77SSepherosa Ziehau 
575315516c77SSepherosa Ziehau 	/*
575415516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
575515516c77SSepherosa Ziehau 	 */
575615516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
575715516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
575815516c77SSepherosa Ziehau 	return (0);
575915516c77SSepherosa Ziehau }
576015516c77SSepherosa Ziehau 
57612494d735SSepherosa Ziehau static bool
57622494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
57632494d735SSepherosa Ziehau {
57642494d735SSepherosa Ziehau 	int i;
57652494d735SSepherosa Ziehau 
57662494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
57672494d735SSepherosa Ziehau 		return (false);
57682494d735SSepherosa Ziehau 
57692494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
57702494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
57712494d735SSepherosa Ziehau 
57722494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
57732494d735SSepherosa Ziehau 			return (false);
57742494d735SSepherosa Ziehau 	}
57752494d735SSepherosa Ziehau 	return (true);
57762494d735SSepherosa Ziehau }
57772494d735SSepherosa Ziehau 
5778b3b75d9cSSepherosa Ziehau /*
5779b3b75d9cSSepherosa Ziehau  * Make sure that the RX filter is zero after the successful
5780b3b75d9cSSepherosa Ziehau  * RNDIS initialization.
5781b3b75d9cSSepherosa Ziehau  *
5782b3b75d9cSSepherosa Ziehau  * NOTE:
5783b3b75d9cSSepherosa Ziehau  * Under certain conditions on certain versions of Hyper-V,
5784b3b75d9cSSepherosa Ziehau  * the RNDIS rxfilter is _not_ zero on the hypervisor side
5785b3b75d9cSSepherosa Ziehau  * after the successful RNDIS initialization, which breaks
5786b3b75d9cSSepherosa Ziehau  * the assumption of any following code (well, it breaks the
5787b3b75d9cSSepherosa Ziehau  * RNDIS API contract actually).  Clear the RNDIS rxfilter
5788b3b75d9cSSepherosa Ziehau  * explicitly, drain packets sneaking through, and drain the
5789b3b75d9cSSepherosa Ziehau  * interrupt taskqueues scheduled due to the stealth packets.
5790b3b75d9cSSepherosa Ziehau  */
5791b3b75d9cSSepherosa Ziehau static void
5792b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan)
5793b3b75d9cSSepherosa Ziehau {
5794b3b75d9cSSepherosa Ziehau 
5795b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
5796b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, nchan);
5797b3b75d9cSSepherosa Ziehau }
5798b3b75d9cSSepherosa Ziehau 
579915516c77SSepherosa Ziehau static int
580015516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
580115516c77SSepherosa Ziehau {
580271e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
580371e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
580471e8ac56SSepherosa Ziehau 
580515516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
5806b3b75d9cSSepherosa Ziehau 	int error, nsubch, nchan = 1, i, rndis_inited;
580771e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
580815516c77SSepherosa Ziehau 
580915516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
581015516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
581115516c77SSepherosa Ziehau 
58122494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
58132494d735SSepherosa Ziehau 		return (ENXIO);
58142494d735SSepherosa Ziehau 
581515516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
581615516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
581715516c77SSepherosa Ziehau 	sc->hn_caps = 0;
581815516c77SSepherosa Ziehau 
581915516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
582015516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
582115516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
582215516c77SSepherosa Ziehau 
582315516c77SSepherosa Ziehau 	/*
582415516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
582515516c77SSepherosa Ziehau 	 */
582615516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
582715516c77SSepherosa Ziehau 	if (error)
582871e8ac56SSepherosa Ziehau 		goto failed;
582915516c77SSepherosa Ziehau 
583015516c77SSepherosa Ziehau 	/*
583115516c77SSepherosa Ziehau 	 * Attach NVS.
583215516c77SSepherosa Ziehau 	 */
583315516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
583415516c77SSepherosa Ziehau 	if (error)
583571e8ac56SSepherosa Ziehau 		goto failed;
583671e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
583715516c77SSepherosa Ziehau 
583815516c77SSepherosa Ziehau 	/*
583915516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
584015516c77SSepherosa Ziehau 	 */
5841b3b75d9cSSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu, &rndis_inited);
5842b3b75d9cSSepherosa Ziehau 	if (rndis_inited)
5843b3b75d9cSSepherosa Ziehau 		attached |= ATTACHED_RNDIS;
584415516c77SSepherosa Ziehau 	if (error)
584571e8ac56SSepherosa Ziehau 		goto failed;
584615516c77SSepherosa Ziehau 
584715516c77SSepherosa Ziehau 	/*
584815516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
584915516c77SSepherosa Ziehau 	 */
585015516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
585115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
585215516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
585371e8ac56SSepherosa Ziehau 		error = ENXIO;
585471e8ac56SSepherosa Ziehau 		goto failed;
585515516c77SSepherosa Ziehau 	}
585615516c77SSepherosa Ziehau 
585715516c77SSepherosa Ziehau 	/*
585815516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
585915516c77SSepherosa Ziehau 	 *
586015516c77SSepherosa Ziehau 	 * NOTE:
586115516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
586215516c77SSepherosa Ziehau 	 * channels to be requested.
586315516c77SSepherosa Ziehau 	 */
586415516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
586515516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
586615516c77SSepherosa Ziehau 	if (error)
586771e8ac56SSepherosa Ziehau 		goto failed;
586871e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
586971e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
587015516c77SSepherosa Ziehau 
587171e8ac56SSepherosa Ziehau 	/*
587271e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
587371e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
587471e8ac56SSepherosa Ziehau 	 */
587515516c77SSepherosa Ziehau 	nchan = nsubch + 1;
587671e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
587715516c77SSepherosa Ziehau 	if (nchan == 1) {
587815516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
587915516c77SSepherosa Ziehau 		goto back;
588015516c77SSepherosa Ziehau 	}
588115516c77SSepherosa Ziehau 
588215516c77SSepherosa Ziehau 	/*
588371e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
5884afd4971bSSepherosa Ziehau 	 *
5885afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
588615516c77SSepherosa Ziehau 	 */
588771e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
588871e8ac56SSepherosa Ziehau 	if (error)
588971e8ac56SSepherosa Ziehau 		goto failed;
589015516c77SSepherosa Ziehau 
589171e8ac56SSepherosa Ziehau 	/*
589271e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
589371e8ac56SSepherosa Ziehau 	 * are attached.
589471e8ac56SSepherosa Ziehau 	 */
589515516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
589615516c77SSepherosa Ziehau 		/*
589715516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
589815516c77SSepherosa Ziehau 		 */
589915516c77SSepherosa Ziehau 		if (bootverbose)
590015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
590134d68912SSepherosa Ziehau #ifdef RSS
590234d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
590334d68912SSepherosa Ziehau #else
590415516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
590534d68912SSepherosa Ziehau #endif
590615516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
590715516c77SSepherosa Ziehau 	}
590815516c77SSepherosa Ziehau 
590915516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
591015516c77SSepherosa Ziehau 		/*
591115516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
591215516c77SSepherosa Ziehau 		 * robin fashion.
591315516c77SSepherosa Ziehau 		 */
591415516c77SSepherosa Ziehau 		if (bootverbose) {
591515516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
591615516c77SSepherosa Ziehau 			    "table\n");
591715516c77SSepherosa Ziehau 		}
591834d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
591934d68912SSepherosa Ziehau 			uint32_t subidx;
592034d68912SSepherosa Ziehau 
592134d68912SSepherosa Ziehau #ifdef RSS
592234d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
592334d68912SSepherosa Ziehau #else
592434d68912SSepherosa Ziehau 			subidx = i;
592534d68912SSepherosa Ziehau #endif
592634d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
592734d68912SSepherosa Ziehau 		}
592815516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
592915516c77SSepherosa Ziehau 	} else {
593015516c77SSepherosa Ziehau 		/*
593115516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
593215516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
593315516c77SSepherosa Ziehau 		 * are valid.
5934afd4971bSSepherosa Ziehau 		 *
5935afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
593615516c77SSepherosa Ziehau 		 */
5937afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
593815516c77SSepherosa Ziehau 	}
593915516c77SSepherosa Ziehau 
594015516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
594115516c77SSepherosa Ziehau 	if (error)
594271e8ac56SSepherosa Ziehau 		goto failed;
594371e8ac56SSepherosa Ziehau back:
5944dc13fee6SSepherosa Ziehau 	/*
5945dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
5946dc13fee6SSepherosa Ziehau 	 */
5947dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
5948b3b75d9cSSepherosa Ziehau 	hn_rndis_init_fixat(sc, nchan);
594915516c77SSepherosa Ziehau 	return (0);
595071e8ac56SSepherosa Ziehau 
595171e8ac56SSepherosa Ziehau failed:
595271e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
5953b3b75d9cSSepherosa Ziehau 		hn_rndis_init_fixat(sc, nchan);
595471e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
595571e8ac56SSepherosa Ziehau 	} else {
5956b3b75d9cSSepherosa Ziehau 		if (attached & ATTACHED_RNDIS) {
5957b3b75d9cSSepherosa Ziehau 			hn_rndis_init_fixat(sc, nchan);
595871e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
5959b3b75d9cSSepherosa Ziehau 		}
596071e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
596171e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
596271e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
596371e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
596471e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
596571e8ac56SSepherosa Ziehau 	}
596671e8ac56SSepherosa Ziehau 	return (error);
596771e8ac56SSepherosa Ziehau 
596871e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
596971e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
597015516c77SSepherosa Ziehau }
597115516c77SSepherosa Ziehau 
597215516c77SSepherosa Ziehau /*
597315516c77SSepherosa Ziehau  * NOTE:
597415516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
597515516c77SSepherosa Ziehau  * this function get called.
597615516c77SSepherosa Ziehau  */
597715516c77SSepherosa Ziehau static void
597815516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
597915516c77SSepherosa Ziehau {
598015516c77SSepherosa Ziehau 
598115516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
598215516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
598315516c77SSepherosa Ziehau 
598415516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
598515516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
598615516c77SSepherosa Ziehau 
598715516c77SSepherosa Ziehau 	/* Detach NVS. */
598815516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
598915516c77SSepherosa Ziehau 
599015516c77SSepherosa Ziehau 	/* Detach all of the channels. */
599115516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
599215516c77SSepherosa Ziehau 
599315516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
599415516c77SSepherosa Ziehau }
599515516c77SSepherosa Ziehau 
599615516c77SSepherosa Ziehau static void
599715516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
599815516c77SSepherosa Ziehau {
599915516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
600015516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
600115516c77SSepherosa Ziehau 
600215516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
600315516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
600415516c77SSepherosa Ziehau 	else
600515516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
600615516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
600715516c77SSepherosa Ziehau 
600834d68912SSepherosa Ziehau #ifdef RSS
600934d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
601034d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
601134d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
601234d68912SSepherosa Ziehau 		    rss_getnumbuckets());
601334d68912SSepherosa Ziehau 	}
601434d68912SSepherosa Ziehau #endif
601534d68912SSepherosa Ziehau 
601615516c77SSepherosa Ziehau 	if (bootverbose) {
601715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
601815516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
601915516c77SSepherosa Ziehau 	}
602015516c77SSepherosa Ziehau }
602115516c77SSepherosa Ziehau 
602215516c77SSepherosa Ziehau static void
602325641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
602415516c77SSepherosa Ziehau {
602515516c77SSepherosa Ziehau 
602625641fc7SSepherosa Ziehau 	/*
602725641fc7SSepherosa Ziehau 	 * NOTE:
602825641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
602925641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
603025641fc7SSepherosa Ziehau 	 */
603125641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
603225641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
603325641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
603415516c77SSepherosa Ziehau 		pause("waitch", 1);
603515516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
603615516c77SSepherosa Ziehau }
603715516c77SSepherosa Ziehau 
603815516c77SSepherosa Ziehau static void
6039b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc)
6040b3b75d9cSSepherosa Ziehau {
6041b3b75d9cSSepherosa Ziehau 
6042b3b75d9cSSepherosa Ziehau 	/*
6043b3b75d9cSSepherosa Ziehau 	 * Disable RX by clearing RX filter forcefully.
6044b3b75d9cSSepherosa Ziehau 	 */
6045b3b75d9cSSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
6046b3b75d9cSSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */
6047b3b75d9cSSepherosa Ziehau 
6048b3b75d9cSSepherosa Ziehau 	/*
6049b3b75d9cSSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
6050b3b75d9cSSepherosa Ziehau 	 */
6051b3b75d9cSSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
6052b3b75d9cSSepherosa Ziehau }
6053b3b75d9cSSepherosa Ziehau 
6054b3b75d9cSSepherosa Ziehau /*
6055b3b75d9cSSepherosa Ziehau  * NOTE:
6056b3b75d9cSSepherosa Ziehau  * RX/TX _must_ have been suspended/disabled, before this function
6057b3b75d9cSSepherosa Ziehau  * is called.
6058b3b75d9cSSepherosa Ziehau  */
6059b3b75d9cSSepherosa Ziehau static void
6060b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan)
606115516c77SSepherosa Ziehau {
606215516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
6063b3b75d9cSSepherosa Ziehau 	int nsubch;
6064b3b75d9cSSepherosa Ziehau 
6065b3b75d9cSSepherosa Ziehau 	/*
6066b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
6067b3b75d9cSSepherosa Ziehau 	 */
6068b3b75d9cSSepherosa Ziehau 	nsubch = nchan - 1;
6069b3b75d9cSSepherosa Ziehau 	if (nsubch > 0)
6070b3b75d9cSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
6071b3b75d9cSSepherosa Ziehau 
6072b3b75d9cSSepherosa Ziehau 	if (subch != NULL) {
6073b3b75d9cSSepherosa Ziehau 		int i;
6074b3b75d9cSSepherosa Ziehau 
6075b3b75d9cSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
6076b3b75d9cSSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
6077b3b75d9cSSepherosa Ziehau 	}
6078b3b75d9cSSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
6079b3b75d9cSSepherosa Ziehau 
6080b3b75d9cSSepherosa Ziehau 	if (subch != NULL)
6081b3b75d9cSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
6082b3b75d9cSSepherosa Ziehau }
6083b3b75d9cSSepherosa Ziehau 
6084b3b75d9cSSepherosa Ziehau static void
6085b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
6086b3b75d9cSSepherosa Ziehau {
608725641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
6088b3b75d9cSSepherosa Ziehau 	int i;
608915516c77SSepherosa Ziehau 
609015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
609115516c77SSepherosa Ziehau 
609215516c77SSepherosa Ziehau 	/*
609315516c77SSepherosa Ziehau 	 * Suspend TX.
609415516c77SSepherosa Ziehau 	 */
609515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
609625641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
609715516c77SSepherosa Ziehau 
609815516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
609915516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
610015516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
610115516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
610215516c77SSepherosa Ziehau 
610325641fc7SSepherosa Ziehau 		/*
610425641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
610525641fc7SSepherosa Ziehau 		 *
610625641fc7SSepherosa Ziehau 		 * NOTE:
610725641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
610825641fc7SSepherosa Ziehau 		 * primary channel is revoked.
610925641fc7SSepherosa Ziehau 		 */
611025641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
611125641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
611215516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
611315516c77SSepherosa Ziehau 	}
611415516c77SSepherosa Ziehau 
611515516c77SSepherosa Ziehau 	/*
6116b3b75d9cSSepherosa Ziehau 	 * Disable RX.
611715516c77SSepherosa Ziehau 	 */
6118b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
611915516c77SSepherosa Ziehau 
612015516c77SSepherosa Ziehau 	/*
6121b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX.
612215516c77SSepherosa Ziehau 	 */
6123b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, sc->hn_rx_ring_inuse);
612425641fc7SSepherosa Ziehau 
612525641fc7SSepherosa Ziehau 	/*
612625641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
612725641fc7SSepherosa Ziehau 	 *
612825641fc7SSepherosa Ziehau 	 * NOTE:
6129b3b75d9cSSepherosa Ziehau 	 * The above hn_drain_rxtx() can dispatch TX tasks, so the TX
6130b3b75d9cSSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_drain_rxtx().
613125641fc7SSepherosa Ziehau 	 */
613225641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
613325641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
613425641fc7SSepherosa Ziehau 
613525641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
613625641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
613725641fc7SSepherosa Ziehau 	}
613815516c77SSepherosa Ziehau }
613915516c77SSepherosa Ziehau 
614015516c77SSepherosa Ziehau static void
614115516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
614215516c77SSepherosa Ziehau {
614315516c77SSepherosa Ziehau 
614415516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
614515516c77SSepherosa Ziehau }
614615516c77SSepherosa Ziehau 
614715516c77SSepherosa Ziehau static void
614815516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
614915516c77SSepherosa Ziehau {
615015516c77SSepherosa Ziehau 	struct task task;
615115516c77SSepherosa Ziehau 
615215516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
615315516c77SSepherosa Ziehau 
615415516c77SSepherosa Ziehau 	/*
615515516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
615615516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
615715516c77SSepherosa Ziehau 	 */
615815516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
615915516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
616015516c77SSepherosa Ziehau 
616115516c77SSepherosa Ziehau 	/*
616215516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
616315516c77SSepherosa Ziehau 	 */
616415516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
616515516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
616615516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
616715516c77SSepherosa Ziehau }
616815516c77SSepherosa Ziehau 
616915516c77SSepherosa Ziehau static void
617015516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
617115516c77SSepherosa Ziehau {
617215516c77SSepherosa Ziehau 
617387f8129dSSepherosa Ziehau 	/* Disable polling. */
617487f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
617587f8129dSSepherosa Ziehau 
6176*9c6cae24SSepherosa Ziehau 	/*
6177*9c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
6178*9c6cae24SSepherosa Ziehau 	 * device is receiving packets, so the data path of the
6179*9c6cae24SSepherosa Ziehau 	 * synthetic device must be suspended.
6180*9c6cae24SSepherosa Ziehau 	 */
61815bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6182962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
618315516c77SSepherosa Ziehau 		hn_suspend_data(sc);
618415516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
618515516c77SSepherosa Ziehau }
618615516c77SSepherosa Ziehau 
618715516c77SSepherosa Ziehau static void
618815516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
618915516c77SSepherosa Ziehau {
619015516c77SSepherosa Ziehau 	int i;
619115516c77SSepherosa Ziehau 
619215516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
619315516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
619415516c77SSepherosa Ziehau 
619515516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
619615516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
619715516c77SSepherosa Ziehau 
619815516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
619915516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
620015516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
620115516c77SSepherosa Ziehau 	}
620215516c77SSepherosa Ziehau }
620315516c77SSepherosa Ziehau 
620415516c77SSepherosa Ziehau static void
620515516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
620615516c77SSepherosa Ziehau {
620715516c77SSepherosa Ziehau 	int i;
620815516c77SSepherosa Ziehau 
620915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
621015516c77SSepherosa Ziehau 
621115516c77SSepherosa Ziehau 	/*
621215516c77SSepherosa Ziehau 	 * Re-enable RX.
621315516c77SSepherosa Ziehau 	 */
6214c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
621515516c77SSepherosa Ziehau 
621615516c77SSepherosa Ziehau 	/*
621715516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
621815516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
621915516c77SSepherosa Ziehau 	 * hn_suspend_data().
622015516c77SSepherosa Ziehau 	 */
622115516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
622215516c77SSepherosa Ziehau 
622323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
622423bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
622523bf9e15SSepherosa Ziehau #endif
622623bf9e15SSepherosa Ziehau 	{
622715516c77SSepherosa Ziehau 		/*
622815516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
622915516c77SSepherosa Ziehau 		 * reduced.
623015516c77SSepherosa Ziehau 		 */
623115516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
623215516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
623315516c77SSepherosa Ziehau 	}
623415516c77SSepherosa Ziehau 
623515516c77SSepherosa Ziehau 	/*
623615516c77SSepherosa Ziehau 	 * Kick start TX.
623715516c77SSepherosa Ziehau 	 */
623815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
623915516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
624015516c77SSepherosa Ziehau 
624115516c77SSepherosa Ziehau 		/*
624215516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
624315516c77SSepherosa Ziehau 		 * cleared properly.
624415516c77SSepherosa Ziehau 		 */
624515516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
624615516c77SSepherosa Ziehau 	}
624715516c77SSepherosa Ziehau }
624815516c77SSepherosa Ziehau 
624915516c77SSepherosa Ziehau static void
625015516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
625115516c77SSepherosa Ziehau {
625215516c77SSepherosa Ziehau 
625315516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
625415516c77SSepherosa Ziehau 
625515516c77SSepherosa Ziehau 	/*
625615516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
625715516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
625815516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
625915516c77SSepherosa Ziehau 	 * detection.
626015516c77SSepherosa Ziehau 	 */
626115516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
626215516c77SSepherosa Ziehau 		hn_change_network(sc);
626315516c77SSepherosa Ziehau 	else
626415516c77SSepherosa Ziehau 		hn_update_link_status(sc);
626515516c77SSepherosa Ziehau }
626615516c77SSepherosa Ziehau 
626715516c77SSepherosa Ziehau static void
626815516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
626915516c77SSepherosa Ziehau {
627015516c77SSepherosa Ziehau 
6271*9c6cae24SSepherosa Ziehau 	/*
6272*9c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
6273*9c6cae24SSepherosa Ziehau 	 * device have to receive packets, so the data path of the
6274*9c6cae24SSepherosa Ziehau 	 * synthetic device must be resumed.
6275*9c6cae24SSepherosa Ziehau 	 */
62765bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6277962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
627815516c77SSepherosa Ziehau 		hn_resume_data(sc);
62795bdfd3fdSDexuan Cui 
62805bdfd3fdSDexuan Cui 	/*
6281*9c6cae24SSepherosa Ziehau 	 * Don't resume link status change if VF is attached/activated.
6282*9c6cae24SSepherosa Ziehau 	 * - In the non-transparent VF mode, the synthetic device marks
6283*9c6cae24SSepherosa Ziehau 	 *   link down until the VF is deactivated; i.e. VF is down.
6284*9c6cae24SSepherosa Ziehau 	 * - In transparent VF mode, VF's media status is used until
6285*9c6cae24SSepherosa Ziehau 	 *   the VF is detached.
62865bdfd3fdSDexuan Cui 	 */
6287*9c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) == 0 &&
6288*9c6cae24SSepherosa Ziehau 	    !(hn_xpnt_vf && sc->hn_vf_ifp != NULL))
628915516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
629087f8129dSSepherosa Ziehau 
629187f8129dSSepherosa Ziehau 	/*
629287f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
629387f8129dSSepherosa Ziehau 	 * the polling is requested.
629487f8129dSSepherosa Ziehau 	 */
629587f8129dSSepherosa Ziehau 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
629687f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
629715516c77SSepherosa Ziehau }
629815516c77SSepherosa Ziehau 
629915516c77SSepherosa Ziehau static void
630015516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
630115516c77SSepherosa Ziehau {
630215516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
630315516c77SSepherosa Ziehau 	int ofs;
630415516c77SSepherosa Ziehau 
630515516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
630615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
630715516c77SSepherosa Ziehau 		return;
630815516c77SSepherosa Ziehau 	}
630915516c77SSepherosa Ziehau 	msg = data;
631015516c77SSepherosa Ziehau 
631115516c77SSepherosa Ziehau 	switch (msg->rm_status) {
631215516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
631315516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
631415516c77SSepherosa Ziehau 		hn_update_link_status(sc);
631515516c77SSepherosa Ziehau 		break;
631615516c77SSepherosa Ziehau 
631715516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
631840905afaSSepherosa Ziehau 	case RNDIS_STATUS_LINK_SPEED_CHANGE:
631915516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
632015516c77SSepherosa Ziehau 		break;
632115516c77SSepherosa Ziehau 
632215516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
632315516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
632415516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
632515516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
632615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
632715516c77SSepherosa Ziehau 		} else {
632815516c77SSepherosa Ziehau 			uint32_t change;
632915516c77SSepherosa Ziehau 
633015516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
633115516c77SSepherosa Ziehau 			    sizeof(change));
633215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
633315516c77SSepherosa Ziehau 			    change);
633415516c77SSepherosa Ziehau 		}
633515516c77SSepherosa Ziehau 		hn_change_network(sc);
633615516c77SSepherosa Ziehau 		break;
633715516c77SSepherosa Ziehau 
633815516c77SSepherosa Ziehau 	default:
633915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
634015516c77SSepherosa Ziehau 		    msg->rm_status);
634115516c77SSepherosa Ziehau 		break;
634215516c77SSepherosa Ziehau 	}
634315516c77SSepherosa Ziehau }
634415516c77SSepherosa Ziehau 
634515516c77SSepherosa Ziehau static int
634615516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
634715516c77SSepherosa Ziehau {
634815516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
634915516c77SSepherosa Ziehau 	uint32_t mask = 0;
635015516c77SSepherosa Ziehau 
635115516c77SSepherosa Ziehau 	while (info_dlen != 0) {
635215516c77SSepherosa Ziehau 		const void *data;
635315516c77SSepherosa Ziehau 		uint32_t dlen;
635415516c77SSepherosa Ziehau 
635515516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
635615516c77SSepherosa Ziehau 			return (EINVAL);
635715516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
635815516c77SSepherosa Ziehau 			return (EINVAL);
635915516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
636015516c77SSepherosa Ziehau 
636115516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
636215516c77SSepherosa Ziehau 			return (EINVAL);
636315516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
636415516c77SSepherosa Ziehau 			return (EINVAL);
636515516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
636615516c77SSepherosa Ziehau 		data = pi->rm_data;
636715516c77SSepherosa Ziehau 
636815516c77SSepherosa Ziehau 		switch (pi->rm_type) {
636915516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
637015516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
637115516c77SSepherosa Ziehau 				return (EINVAL);
637215516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
637315516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
637415516c77SSepherosa Ziehau 			break;
637515516c77SSepherosa Ziehau 
637615516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
637715516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
637815516c77SSepherosa Ziehau 				return (EINVAL);
637915516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
638015516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
638115516c77SSepherosa Ziehau 			break;
638215516c77SSepherosa Ziehau 
638315516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
638415516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
638515516c77SSepherosa Ziehau 				return (EINVAL);
638615516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
638715516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
638815516c77SSepherosa Ziehau 			break;
638915516c77SSepherosa Ziehau 
639015516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
639115516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
639215516c77SSepherosa Ziehau 				return (EINVAL);
639315516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
639415516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
639515516c77SSepherosa Ziehau 			break;
639615516c77SSepherosa Ziehau 
639715516c77SSepherosa Ziehau 		default:
639815516c77SSepherosa Ziehau 			goto next;
639915516c77SSepherosa Ziehau 		}
640015516c77SSepherosa Ziehau 
640115516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
640215516c77SSepherosa Ziehau 			/* All found; done */
640315516c77SSepherosa Ziehau 			break;
640415516c77SSepherosa Ziehau 		}
640515516c77SSepherosa Ziehau next:
640615516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
640715516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
640815516c77SSepherosa Ziehau 	}
640915516c77SSepherosa Ziehau 
641015516c77SSepherosa Ziehau 	/*
641115516c77SSepherosa Ziehau 	 * Final fixup.
641215516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
641315516c77SSepherosa Ziehau 	 */
641415516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
641515516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
641615516c77SSepherosa Ziehau 	return (0);
641715516c77SSepherosa Ziehau }
641815516c77SSepherosa Ziehau 
641915516c77SSepherosa Ziehau static __inline bool
642015516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
642115516c77SSepherosa Ziehau {
642215516c77SSepherosa Ziehau 
642315516c77SSepherosa Ziehau 	if (off < check_off) {
642415516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
642515516c77SSepherosa Ziehau 			return (false);
642615516c77SSepherosa Ziehau 	} else if (off > check_off) {
642715516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
642815516c77SSepherosa Ziehau 			return (false);
642915516c77SSepherosa Ziehau 	}
643015516c77SSepherosa Ziehau 	return (true);
643115516c77SSepherosa Ziehau }
643215516c77SSepherosa Ziehau 
643315516c77SSepherosa Ziehau static void
643415516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
643515516c77SSepherosa Ziehau {
643615516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
643715516c77SSepherosa Ziehau 	struct hn_rxinfo info;
643815516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
643915516c77SSepherosa Ziehau 
644015516c77SSepherosa Ziehau 	/*
644115516c77SSepherosa Ziehau 	 * Check length.
644215516c77SSepherosa Ziehau 	 */
644315516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
644415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
644515516c77SSepherosa Ziehau 		return;
644615516c77SSepherosa Ziehau 	}
644715516c77SSepherosa Ziehau 	pkt = data;
644815516c77SSepherosa Ziehau 
644915516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
645015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
645115516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
645215516c77SSepherosa Ziehau 		return;
645315516c77SSepherosa Ziehau 	}
645415516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
645515516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
645615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
645715516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
645815516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
645915516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
646015516c77SSepherosa Ziehau 		return;
646115516c77SSepherosa Ziehau 	}
646215516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
646315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
646415516c77SSepherosa Ziehau 		return;
646515516c77SSepherosa Ziehau 	}
646615516c77SSepherosa Ziehau 
646715516c77SSepherosa Ziehau 	/*
646815516c77SSepherosa Ziehau 	 * Check offests.
646915516c77SSepherosa Ziehau 	 */
647015516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
647115516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
647215516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
647315516c77SSepherosa Ziehau 
647415516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
647515516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
647615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
647715516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
647815516c77SSepherosa Ziehau 		return;
647915516c77SSepherosa Ziehau 	}
648015516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
648115516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
648215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
648315516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
648415516c77SSepherosa Ziehau 		return;
648515516c77SSepherosa Ziehau 	}
648615516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
648715516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
648815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
648915516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
649015516c77SSepherosa Ziehau 		return;
649115516c77SSepherosa Ziehau 	}
649215516c77SSepherosa Ziehau 
649315516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
649415516c77SSepherosa Ziehau 
649515516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
649615516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
649715516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
649815516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
649915516c77SSepherosa Ziehau 
650015516c77SSepherosa Ziehau 	/*
650115516c77SSepherosa Ziehau 	 * Check OOB coverage.
650215516c77SSepherosa Ziehau 	 */
650315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
650415516c77SSepherosa Ziehau 		int oob_off, oob_len;
650515516c77SSepherosa Ziehau 
650615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
650715516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
650815516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
650915516c77SSepherosa Ziehau 
651015516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
651115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
651215516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
651315516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
651415516c77SSepherosa Ziehau 			return;
651515516c77SSepherosa Ziehau 		}
651615516c77SSepherosa Ziehau 
651715516c77SSepherosa Ziehau 		/*
651815516c77SSepherosa Ziehau 		 * Check against data.
651915516c77SSepherosa Ziehau 		 */
652015516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
652115516c77SSepherosa Ziehau 		    data_off, data_len)) {
652215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
652315516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
652415516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
652515516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
652615516c77SSepherosa Ziehau 			return;
652715516c77SSepherosa Ziehau 		}
652815516c77SSepherosa Ziehau 
652915516c77SSepherosa Ziehau 		/*
653015516c77SSepherosa Ziehau 		 * Check against pktinfo.
653115516c77SSepherosa Ziehau 		 */
653215516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
653315516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
653415516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
653515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
653615516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
653715516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
653815516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
653915516c77SSepherosa Ziehau 			return;
654015516c77SSepherosa Ziehau 		}
654115516c77SSepherosa Ziehau 	}
654215516c77SSepherosa Ziehau 
654315516c77SSepherosa Ziehau 	/*
654415516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
654515516c77SSepherosa Ziehau 	 */
654615516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
654715516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
654815516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
654915516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
655015516c77SSepherosa Ziehau 		bool overlap;
655115516c77SSepherosa Ziehau 		int error;
655215516c77SSepherosa Ziehau 
655315516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
655415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
655515516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
655615516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
655715516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
655815516c77SSepherosa Ziehau 			return;
655915516c77SSepherosa Ziehau 		}
656015516c77SSepherosa Ziehau 
656115516c77SSepherosa Ziehau 		/*
656215516c77SSepherosa Ziehau 		 * Check packet info coverage.
656315516c77SSepherosa Ziehau 		 */
656415516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
656515516c77SSepherosa Ziehau 		    data_off, data_len);
656615516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
656715516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
656815516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
656915516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
657015516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
657115516c77SSepherosa Ziehau 			return;
657215516c77SSepherosa Ziehau 		}
657315516c77SSepherosa Ziehau 
657415516c77SSepherosa Ziehau 		/*
657515516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
657615516c77SSepherosa Ziehau 		 */
657715516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
657815516c77SSepherosa Ziehau 		    pktinfo_len, &info);
657915516c77SSepherosa Ziehau 		if (__predict_false(error)) {
658015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
658115516c77SSepherosa Ziehau 			    "pktinfo\n");
658215516c77SSepherosa Ziehau 			return;
658315516c77SSepherosa Ziehau 		}
658415516c77SSepherosa Ziehau 	}
658515516c77SSepherosa Ziehau 
658615516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
658715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
658815516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
658915516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
659015516c77SSepherosa Ziehau 		return;
659115516c77SSepherosa Ziehau 	}
659215516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
659315516c77SSepherosa Ziehau }
659415516c77SSepherosa Ziehau 
659515516c77SSepherosa Ziehau static __inline void
659615516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
659715516c77SSepherosa Ziehau {
659815516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
659915516c77SSepherosa Ziehau 
660015516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
660115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
660215516c77SSepherosa Ziehau 		return;
660315516c77SSepherosa Ziehau 	}
660415516c77SSepherosa Ziehau 	hdr = data;
660515516c77SSepherosa Ziehau 
660615516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
660715516c77SSepherosa Ziehau 		/* Hot data path. */
660815516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
660915516c77SSepherosa Ziehau 		/* Done! */
661015516c77SSepherosa Ziehau 		return;
661115516c77SSepherosa Ziehau 	}
661215516c77SSepherosa Ziehau 
661315516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
661415516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
661515516c77SSepherosa Ziehau 	else
661615516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
661715516c77SSepherosa Ziehau }
661815516c77SSepherosa Ziehau 
661915516c77SSepherosa Ziehau static void
662015516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
662115516c77SSepherosa Ziehau {
662215516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
662315516c77SSepherosa Ziehau 
662415516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
662515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
662615516c77SSepherosa Ziehau 		return;
662715516c77SSepherosa Ziehau 	}
662815516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
662915516c77SSepherosa Ziehau 
663015516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
663115516c77SSepherosa Ziehau 		/* Useless; ignore */
663215516c77SSepherosa Ziehau 		return;
663315516c77SSepherosa Ziehau 	}
663415516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
663515516c77SSepherosa Ziehau }
663615516c77SSepherosa Ziehau 
663715516c77SSepherosa Ziehau static void
663815516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
663915516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
664015516c77SSepherosa Ziehau {
664115516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
664215516c77SSepherosa Ziehau 
664315516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
664415516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
664515516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
664615516c77SSepherosa Ziehau 	/*
664715516c77SSepherosa Ziehau 	 * NOTE:
664815516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
664915516c77SSepherosa Ziehau 	 * its callback.
665015516c77SSepherosa Ziehau 	 */
665115516c77SSepherosa Ziehau }
665215516c77SSepherosa Ziehau 
665315516c77SSepherosa Ziehau static void
665415516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
665515516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
665615516c77SSepherosa Ziehau {
665715516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
665815516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
665915516c77SSepherosa Ziehau 	int count, i, hlen;
666015516c77SSepherosa Ziehau 
666115516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
666215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
666315516c77SSepherosa Ziehau 		return;
666415516c77SSepherosa Ziehau 	}
666515516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
666615516c77SSepherosa Ziehau 
666715516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
666815516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
666915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
667015516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
667115516c77SSepherosa Ziehau 		return;
667215516c77SSepherosa Ziehau 	}
667315516c77SSepherosa Ziehau 
667415516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
667515516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
667615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
667715516c77SSepherosa Ziehau 		return;
667815516c77SSepherosa Ziehau 	}
667915516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
668015516c77SSepherosa Ziehau 
668115516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
668215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
668315516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
668415516c77SSepherosa Ziehau 		return;
668515516c77SSepherosa Ziehau 	}
668615516c77SSepherosa Ziehau 
668715516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
668815516c77SSepherosa Ziehau 	if (__predict_false(hlen <
668915516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
669015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
669115516c77SSepherosa Ziehau 		return;
669215516c77SSepherosa Ziehau 	}
669315516c77SSepherosa Ziehau 
669415516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
669515516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
669615516c77SSepherosa Ziehau 		int ofs, len;
669715516c77SSepherosa Ziehau 
669815516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
669915516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
670015516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
670115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
670215516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
670315516c77SSepherosa Ziehau 			continue;
670415516c77SSepherosa Ziehau 		}
670515516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
670615516c77SSepherosa Ziehau 	}
670715516c77SSepherosa Ziehau 
670815516c77SSepherosa Ziehau 	/*
670915516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
671015516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
671115516c77SSepherosa Ziehau 	 */
671215516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
671315516c77SSepherosa Ziehau }
671415516c77SSepherosa Ziehau 
671515516c77SSepherosa Ziehau static void
671615516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
671715516c77SSepherosa Ziehau     uint64_t tid)
671815516c77SSepherosa Ziehau {
671915516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
672015516c77SSepherosa Ziehau 	int retries, error;
672115516c77SSepherosa Ziehau 
672215516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
672315516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
672415516c77SSepherosa Ziehau 
672515516c77SSepherosa Ziehau 	retries = 0;
672615516c77SSepherosa Ziehau again:
672715516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
672815516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
672915516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
673015516c77SSepherosa Ziehau 		/*
673115516c77SSepherosa Ziehau 		 * NOTE:
673215516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
673315516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
673415516c77SSepherosa Ziehau 		 * controlled.
673515516c77SSepherosa Ziehau 		 */
673615516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
673715516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
673815516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
673915516c77SSepherosa Ziehau 		retries++;
674015516c77SSepherosa Ziehau 		if (retries < 10) {
674115516c77SSepherosa Ziehau 			DELAY(100);
674215516c77SSepherosa Ziehau 			goto again;
674315516c77SSepherosa Ziehau 		}
674415516c77SSepherosa Ziehau 		/* RXBUF leaks! */
674515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
674615516c77SSepherosa Ziehau 	}
674715516c77SSepherosa Ziehau }
674815516c77SSepherosa Ziehau 
674915516c77SSepherosa Ziehau static void
675015516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
675115516c77SSepherosa Ziehau {
675215516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
675315516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
675415516c77SSepherosa Ziehau 
675515516c77SSepherosa Ziehau 	for (;;) {
675615516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
675715516c77SSepherosa Ziehau 		int error, pktlen;
675815516c77SSepherosa Ziehau 
675915516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
676015516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
676115516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
676215516c77SSepherosa Ziehau 			void *nbuf;
676315516c77SSepherosa Ziehau 			int nlen;
676415516c77SSepherosa Ziehau 
676515516c77SSepherosa Ziehau 			/*
676615516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
676715516c77SSepherosa Ziehau 			 *
676815516c77SSepherosa Ziehau 			 * XXX
676915516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
677015516c77SSepherosa Ziehau 			 * is fatal.
677115516c77SSepherosa Ziehau 			 */
677215516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
677315516c77SSepherosa Ziehau 			while (nlen < pktlen)
677415516c77SSepherosa Ziehau 				nlen *= 2;
677515516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
677615516c77SSepherosa Ziehau 
677715516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
677815516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
677915516c77SSepherosa Ziehau 
678015516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
678115516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
678215516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
678315516c77SSepherosa Ziehau 			/* Retry! */
678415516c77SSepherosa Ziehau 			continue;
678515516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
678615516c77SSepherosa Ziehau 			/* No more channel packets; done! */
678715516c77SSepherosa Ziehau 			break;
678815516c77SSepherosa Ziehau 		}
678915516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
679015516c77SSepherosa Ziehau 
679115516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
679215516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
679315516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
679415516c77SSepherosa Ziehau 			break;
679515516c77SSepherosa Ziehau 
679615516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
679715516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
679815516c77SSepherosa Ziehau 			break;
679915516c77SSepherosa Ziehau 
680015516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
680115516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
680215516c77SSepherosa Ziehau 			break;
680315516c77SSepherosa Ziehau 
680415516c77SSepherosa Ziehau 		default:
680515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
680615516c77SSepherosa Ziehau 			    pkt->cph_type);
680715516c77SSepherosa Ziehau 			break;
680815516c77SSepherosa Ziehau 		}
680915516c77SSepherosa Ziehau 	}
681015516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
681115516c77SSepherosa Ziehau }
681215516c77SSepherosa Ziehau 
681315516c77SSepherosa Ziehau static void
6814499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused)
681515516c77SSepherosa Ziehau {
6816fdd0222aSSepherosa Ziehau 	int i;
6817fdd0222aSSepherosa Ziehau 
6818*9c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
6819*9c6cae24SSepherosa Ziehau 	/*
6820*9c6cae24SSepherosa Ziehau 	 * Don't use ifnet.if_start if transparent VF mode is requested;
6821*9c6cae24SSepherosa Ziehau 	 * mainly due to the IFF_DRV_OACTIVE flag.
6822*9c6cae24SSepherosa Ziehau 	 */
6823*9c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_use_if_start) {
6824*9c6cae24SSepherosa Ziehau 		hn_use_if_start = 0;
6825*9c6cae24SSepherosa Ziehau 		printf("hn: tranparent VF mode, if_transmit will be used, "
6826*9c6cae24SSepherosa Ziehau 		    "instead of if_start\n");
6827*9c6cae24SSepherosa Ziehau 	}
6828*9c6cae24SSepherosa Ziehau #endif
6829*9c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) {
6830*9c6cae24SSepherosa Ziehau 		printf("hn: invalid transparent VF attach routing "
6831*9c6cae24SSepherosa Ziehau 		    "wait timeout %d, reset to %d\n",
6832*9c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN);
6833*9c6cae24SSepherosa Ziehau 		hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
6834*9c6cae24SSepherosa Ziehau 	}
6835*9c6cae24SSepherosa Ziehau 
6836fdd0222aSSepherosa Ziehau 	/*
6837499c3e17SSepherosa Ziehau 	 * Initialize VF map.
6838499c3e17SSepherosa Ziehau 	 */
6839499c3e17SSepherosa Ziehau 	rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE);
6840499c3e17SSepherosa Ziehau 	hn_vfmap_size = HN_VFMAP_SIZE_DEF;
6841499c3e17SSepherosa Ziehau 	hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF,
6842499c3e17SSepherosa Ziehau 	    M_WAITOK | M_ZERO);
6843499c3e17SSepherosa Ziehau 
6844499c3e17SSepherosa Ziehau 	/*
6845fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
6846fdd0222aSSepherosa Ziehau 	 */
6847fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
6848fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
6849fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
6850fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
685115516c77SSepherosa Ziehau 
68520e11868dSSepherosa Ziehau 	/*
68530e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
68540e11868dSSepherosa Ziehau 	 */
68550e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
68560e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
68570e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
68580e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
68590e11868dSSepherosa Ziehau 		break;
68600e11868dSSepherosa Ziehau 	default:
68610e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
68620e11868dSSepherosa Ziehau 		break;
68630e11868dSSepherosa Ziehau 	}
68640e11868dSSepherosa Ziehau 
686515516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
686615516c77SSepherosa Ziehau 		return;
686715516c77SSepherosa Ziehau 
68680e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
686915516c77SSepherosa Ziehau 		return;
687015516c77SSepherosa Ziehau 
6871fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
6872fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
6873fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
6874fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
6875fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
6876fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
6877fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
6878fdd0222aSSepherosa Ziehau 	}
687915516c77SSepherosa Ziehau }
6880499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL);
688115516c77SSepherosa Ziehau 
688215516c77SSepherosa Ziehau static void
6883499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused)
688415516c77SSepherosa Ziehau {
688515516c77SSepherosa Ziehau 
6886fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
6887fdd0222aSSepherosa Ziehau 		int i;
6888fdd0222aSSepherosa Ziehau 
6889fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
6890fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
6891fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
6892fdd0222aSSepherosa Ziehau 	}
6893499c3e17SSepherosa Ziehau 
6894499c3e17SSepherosa Ziehau 	if (hn_vfmap != NULL)
6895499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
6896499c3e17SSepherosa Ziehau 	rm_destroy(&hn_vfmap_lock);
689715516c77SSepherosa Ziehau }
6898499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL);
6899