115516c77SSepherosa Ziehau /*- 215516c77SSepherosa Ziehau * Copyright (c) 2010-2012 Citrix Inc. 393b4e111SSepherosa Ziehau * Copyright (c) 2009-2012,2016-2017 Microsoft Corp. 415516c77SSepherosa Ziehau * Copyright (c) 2012 NetApp Inc. 515516c77SSepherosa Ziehau * All rights reserved. 615516c77SSepherosa Ziehau * 715516c77SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 815516c77SSepherosa Ziehau * modification, are permitted provided that the following conditions 915516c77SSepherosa Ziehau * are met: 1015516c77SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 1115516c77SSepherosa Ziehau * notice unmodified, this list of conditions, and the following 1215516c77SSepherosa Ziehau * disclaimer. 1315516c77SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 1415516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 1515516c77SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 1615516c77SSepherosa Ziehau * 1715516c77SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1815516c77SSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1915516c77SSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2015516c77SSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2115516c77SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2215516c77SSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2315516c77SSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2415516c77SSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2515516c77SSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2615516c77SSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2715516c77SSepherosa Ziehau */ 2815516c77SSepherosa Ziehau 2915516c77SSepherosa Ziehau /*- 3015516c77SSepherosa Ziehau * Copyright (c) 2004-2006 Kip Macy 3115516c77SSepherosa Ziehau * All rights reserved. 3215516c77SSepherosa Ziehau * 3315516c77SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 3415516c77SSepherosa Ziehau * modification, are permitted provided that the following conditions 3515516c77SSepherosa Ziehau * are met: 3615516c77SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 3715516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 3815516c77SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 3915516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 4015516c77SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 4115516c77SSepherosa Ziehau * 4215516c77SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 4315516c77SSepherosa Ziehau * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4415516c77SSepherosa Ziehau * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4515516c77SSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4615516c77SSepherosa Ziehau * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4715516c77SSepherosa Ziehau * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4815516c77SSepherosa Ziehau * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4915516c77SSepherosa Ziehau * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5015516c77SSepherosa Ziehau * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5115516c77SSepherosa Ziehau * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5215516c77SSepherosa Ziehau * SUCH DAMAGE. 5315516c77SSepherosa Ziehau */ 5415516c77SSepherosa Ziehau 5515516c77SSepherosa Ziehau #include <sys/cdefs.h> 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> 64*35203574SSepherosa Ziehau #include <sys/systm.h> 6515516c77SSepherosa Ziehau #include <sys/bus.h> 662be266caSSepherosa Ziehau #include <sys/counter.h> 6715516c77SSepherosa Ziehau #include <sys/kernel.h> 6815516c77SSepherosa Ziehau #include <sys/limits.h> 6915516c77SSepherosa Ziehau #include <sys/malloc.h> 7015516c77SSepherosa Ziehau #include <sys/mbuf.h> 7115516c77SSepherosa Ziehau #include <sys/module.h> 7215516c77SSepherosa Ziehau #include <sys/queue.h> 7315516c77SSepherosa Ziehau #include <sys/lock.h> 74499c3e17SSepherosa Ziehau #include <sys/rmlock.h> 75499c3e17SSepherosa Ziehau #include <sys/sbuf.h> 7615516c77SSepherosa Ziehau #include <sys/smp.h> 7715516c77SSepherosa Ziehau #include <sys/socket.h> 7815516c77SSepherosa Ziehau #include <sys/sockio.h> 7915516c77SSepherosa Ziehau #include <sys/sx.h> 8015516c77SSepherosa Ziehau #include <sys/sysctl.h> 8115516c77SSepherosa Ziehau #include <sys/taskqueue.h> 8215516c77SSepherosa Ziehau #include <sys/buf_ring.h> 835bdfd3fdSDexuan Cui #include <sys/eventhandler.h> 8415516c77SSepherosa Ziehau 8515516c77SSepherosa Ziehau #include <machine/atomic.h> 8615516c77SSepherosa Ziehau #include <machine/in_cksum.h> 8715516c77SSepherosa Ziehau 8815516c77SSepherosa Ziehau #include <net/bpf.h> 8915516c77SSepherosa Ziehau #include <net/ethernet.h> 9015516c77SSepherosa Ziehau #include <net/if.h> 915bdfd3fdSDexuan Cui #include <net/if_dl.h> 9215516c77SSepherosa Ziehau #include <net/if_media.h> 9315516c77SSepherosa Ziehau #include <net/if_types.h> 9415516c77SSepherosa Ziehau #include <net/if_var.h> 9515516c77SSepherosa Ziehau #include <net/rndis.h> 9634d68912SSepherosa Ziehau #ifdef RSS 9734d68912SSepherosa Ziehau #include <net/rss_config.h> 9834d68912SSepherosa Ziehau #endif 9915516c77SSepherosa Ziehau 10015516c77SSepherosa Ziehau #include <netinet/in_systm.h> 10115516c77SSepherosa Ziehau #include <netinet/in.h> 10215516c77SSepherosa Ziehau #include <netinet/ip.h> 10315516c77SSepherosa Ziehau #include <netinet/ip6.h> 10415516c77SSepherosa Ziehau #include <netinet/tcp.h> 10515516c77SSepherosa Ziehau #include <netinet/tcp_lro.h> 10615516c77SSepherosa Ziehau #include <netinet/udp.h> 10715516c77SSepherosa Ziehau 10815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h> 10915516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h> 11015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h> 11115516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h> 11215516c77SSepherosa Ziehau 11315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h> 11415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h> 11515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h> 11615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h> 11715516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h> 11815516c77SSepherosa Ziehau 11915516c77SSepherosa Ziehau #include "vmbus_if.h" 12015516c77SSepherosa Ziehau 12123bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT 12223bf9e15SSepherosa Ziehau 12315516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX 8 12415516c77SSepherosa Ziehau 125499c3e17SSepherosa Ziehau #define HN_VFMAP_SIZE_DEF 8 126499c3e17SSepherosa Ziehau 1279c6cae24SSepherosa Ziehau #define HN_XPNT_VF_ATTWAIT_MIN 2 /* seconds */ 1289c6cae24SSepherosa Ziehau 12915516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */ 13015516c77SSepherosa Ziehau #define HN_TX_DESC_CNT 512 13115516c77SSepherosa Ziehau 13215516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN \ 13315516c77SSepherosa Ziehau (sizeof(struct rndis_packet_msg) + \ 13415516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) + \ 13515516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) + \ 13615516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) + \ 13715516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE)) 13815516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY PAGE_SIZE 13915516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN CACHE_LINE_SIZE 14015516c77SSepherosa Ziehau 14115516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY PAGE_SIZE 14215516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE IP_MAXPACKET 14315516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE PAGE_SIZE 14415516c77SSepherosa Ziehau /* -1 for RNDIS packet message */ 14515516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX (HN_GPACNT_MAX - 1) 14615516c77SSepherosa Ziehau 14715516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF 128 14815516c77SSepherosa Ziehau 14915516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH 8 15015516c77SSepherosa Ziehau 15115516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF (16 * 1024) 15215516c77SSepherosa Ziehau 15315516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF 128 15415516c77SSepherosa Ziehau 15515516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF (12 * ETHERMTU) 15615516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF (25 * ETHERMTU) 15715516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */ 15815516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp) (2 * (ifp)->if_mtu) 15915516c77SSepherosa Ziehau 16015516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF 1 16115516c77SSepherosa Ziehau 16215516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc) \ 16315516c77SSepherosa Ziehau sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev)) 16415516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc) sx_destroy(&(sc)->hn_lock) 16515516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc) sx_assert(&(sc)->hn_lock, SA_XLOCKED) 166fdc4f478SSepherosa Ziehau #define HN_LOCK(sc) \ 167fdc4f478SSepherosa Ziehau do { \ 168fdc4f478SSepherosa Ziehau while (sx_try_xlock(&(sc)->hn_lock) == 0) \ 169fdc4f478SSepherosa Ziehau DELAY(1000); \ 170fdc4f478SSepherosa Ziehau } while (0) 17115516c77SSepherosa Ziehau #define HN_UNLOCK(sc) sx_xunlock(&(sc)->hn_lock) 17215516c77SSepherosa Ziehau 17315516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK (CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP) 17415516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK (CSUM_IP6_TCP | CSUM_IP6_UDP) 17515516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc) \ 17615516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK) 17715516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc) \ 17815516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK) 17915516c77SSepherosa Ziehau 180dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align) \ 181dc13fee6SSepherosa Ziehau roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \ 182dc13fee6SSepherosa Ziehau HN_RNDIS_PKT_LEN, (align)) 183dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align) \ 184dc13fee6SSepherosa Ziehau roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align)) 185dc13fee6SSepherosa Ziehau 18634d68912SSepherosa Ziehau #ifdef RSS 18734d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx) rss_getcpu((idx) % rss_getnumbuckets()) 18834d68912SSepherosa Ziehau #else 1890e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx) (((sc)->hn_cpu + (idx)) % mp_ncpus) 19034d68912SSepherosa Ziehau #endif 1910e11868dSSepherosa Ziehau 19215516c77SSepherosa Ziehau struct hn_txdesc { 19315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 19415516c77SSepherosa Ziehau SLIST_ENTRY(hn_txdesc) link; 19515516c77SSepherosa Ziehau #endif 196dc13fee6SSepherosa Ziehau STAILQ_ENTRY(hn_txdesc) agg_link; 197dc13fee6SSepherosa Ziehau 198dc13fee6SSepherosa Ziehau /* Aggregated txdescs, in sending order. */ 199dc13fee6SSepherosa Ziehau STAILQ_HEAD(, hn_txdesc) agg_list; 200dc13fee6SSepherosa Ziehau 201dc13fee6SSepherosa Ziehau /* The oldest packet, if transmission aggregation happens. */ 20215516c77SSepherosa Ziehau struct mbuf *m; 20315516c77SSepherosa Ziehau struct hn_tx_ring *txr; 20415516c77SSepherosa Ziehau int refs; 20515516c77SSepherosa Ziehau uint32_t flags; /* HN_TXD_FLAG_ */ 20615516c77SSepherosa Ziehau struct hn_nvs_sendctx send_ctx; 20715516c77SSepherosa Ziehau uint32_t chim_index; 20815516c77SSepherosa Ziehau int chim_size; 20915516c77SSepherosa Ziehau 21015516c77SSepherosa Ziehau bus_dmamap_t data_dmap; 21115516c77SSepherosa Ziehau 21215516c77SSepherosa Ziehau bus_addr_t rndis_pkt_paddr; 21315516c77SSepherosa Ziehau struct rndis_packet_msg *rndis_pkt; 21415516c77SSepherosa Ziehau bus_dmamap_t rndis_pkt_dmap; 21515516c77SSepherosa Ziehau }; 21615516c77SSepherosa Ziehau 21715516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST 0x0001 21815516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP 0x0002 219dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG 0x0004 22015516c77SSepherosa Ziehau 22115516c77SSepherosa Ziehau struct hn_rxinfo { 22215516c77SSepherosa Ziehau uint32_t vlan_info; 22315516c77SSepherosa Ziehau uint32_t csum_info; 22415516c77SSepherosa Ziehau uint32_t hash_info; 22515516c77SSepherosa Ziehau uint32_t hash_value; 22615516c77SSepherosa Ziehau }; 22715516c77SSepherosa Ziehau 228962f0357SSepherosa Ziehau struct hn_rxvf_setarg { 2295bdfd3fdSDexuan Cui struct hn_rx_ring *rxr; 230962f0357SSepherosa Ziehau struct ifnet *vf_ifp; 2315bdfd3fdSDexuan Cui }; 2325bdfd3fdSDexuan Cui 23315516c77SSepherosa Ziehau #define HN_RXINFO_VLAN 0x0001 23415516c77SSepherosa Ziehau #define HN_RXINFO_CSUM 0x0002 23515516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF 0x0004 23615516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL 0x0008 23715516c77SSepherosa Ziehau #define HN_RXINFO_ALL \ 23815516c77SSepherosa Ziehau (HN_RXINFO_VLAN | \ 23915516c77SSepherosa Ziehau HN_RXINFO_CSUM | \ 24015516c77SSepherosa Ziehau HN_RXINFO_HASHINF | \ 24115516c77SSepherosa Ziehau HN_RXINFO_HASHVAL) 24215516c77SSepherosa Ziehau 24315516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID 0xffffffff 24415516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID 0 24515516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID 0 24615516c77SSepherosa Ziehau 24715516c77SSepherosa Ziehau static int hn_probe(device_t); 24815516c77SSepherosa Ziehau static int hn_attach(device_t); 24915516c77SSepherosa Ziehau static int hn_detach(device_t); 25015516c77SSepherosa Ziehau static int hn_shutdown(device_t); 25115516c77SSepherosa Ziehau static void hn_chan_callback(struct vmbus_channel *, 25215516c77SSepherosa Ziehau void *); 25315516c77SSepherosa Ziehau 25415516c77SSepherosa Ziehau static void hn_init(void *); 25515516c77SSepherosa Ziehau static int hn_ioctl(struct ifnet *, u_long, caddr_t); 25623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 25715516c77SSepherosa Ziehau static void hn_start(struct ifnet *); 25823bf9e15SSepherosa Ziehau #endif 25915516c77SSepherosa Ziehau static int hn_transmit(struct ifnet *, struct mbuf *); 26015516c77SSepherosa Ziehau static void hn_xmit_qflush(struct ifnet *); 26115516c77SSepherosa Ziehau static int hn_ifmedia_upd(struct ifnet *); 26215516c77SSepherosa Ziehau static void hn_ifmedia_sts(struct ifnet *, 26315516c77SSepherosa Ziehau struct ifmediareq *); 26415516c77SSepherosa Ziehau 265499c3e17SSepherosa Ziehau static void hn_ifnet_event(void *, struct ifnet *, int); 266499c3e17SSepherosa Ziehau static void hn_ifaddr_event(void *, struct ifnet *); 267499c3e17SSepherosa Ziehau static void hn_ifnet_attevent(void *, struct ifnet *); 268499c3e17SSepherosa Ziehau static void hn_ifnet_detevent(void *, struct ifnet *); 2699c6cae24SSepherosa Ziehau static void hn_ifnet_lnkevent(void *, struct ifnet *, int); 270499c3e17SSepherosa Ziehau 271962f0357SSepherosa Ziehau static bool hn_ismyvf(const struct hn_softc *, 272962f0357SSepherosa Ziehau const struct ifnet *); 273962f0357SSepherosa Ziehau static void hn_rxvf_change(struct hn_softc *, 274962f0357SSepherosa Ziehau struct ifnet *, bool); 275962f0357SSepherosa Ziehau static void hn_rxvf_set(struct hn_softc *, struct ifnet *); 276962f0357SSepherosa Ziehau static void hn_rxvf_set_task(void *, int); 2779c6cae24SSepherosa Ziehau static void hn_xpnt_vf_input(struct ifnet *, struct mbuf *); 2789c6cae24SSepherosa Ziehau static int hn_xpnt_vf_iocsetflags(struct hn_softc *); 2799c6cae24SSepherosa Ziehau static int hn_xpnt_vf_iocsetcaps(struct hn_softc *, 2809c6cae24SSepherosa Ziehau struct ifreq *); 2819c6cae24SSepherosa Ziehau static void hn_xpnt_vf_saveifflags(struct hn_softc *); 2829c6cae24SSepherosa Ziehau static bool hn_xpnt_vf_isready(struct hn_softc *); 2839c6cae24SSepherosa Ziehau static void hn_xpnt_vf_setready(struct hn_softc *); 2849c6cae24SSepherosa Ziehau static void hn_xpnt_vf_init_taskfunc(void *, int); 2859c6cae24SSepherosa Ziehau static void hn_xpnt_vf_init(struct hn_softc *); 286a97fff19SSepherosa Ziehau static void hn_xpnt_vf_setenable(struct hn_softc *); 287a97fff19SSepherosa Ziehau static void hn_xpnt_vf_setdisable(struct hn_softc *, bool); 288642ec226SSepherosa Ziehau static void hn_vf_rss_fixup(struct hn_softc *, bool); 289642ec226SSepherosa Ziehau static void hn_vf_rss_restore(struct hn_softc *); 290962f0357SSepherosa Ziehau 29115516c77SSepherosa Ziehau static int hn_rndis_rxinfo(const void *, int, 29215516c77SSepherosa Ziehau struct hn_rxinfo *); 29315516c77SSepherosa Ziehau static void hn_rndis_rx_data(struct hn_rx_ring *, 29415516c77SSepherosa Ziehau const void *, int); 29515516c77SSepherosa Ziehau static void hn_rndis_rx_status(struct hn_softc *, 29615516c77SSepherosa Ziehau const void *, int); 297b3b75d9cSSepherosa Ziehau static void hn_rndis_init_fixat(struct hn_softc *, int); 29815516c77SSepherosa Ziehau 29915516c77SSepherosa Ziehau static void hn_nvs_handle_notify(struct hn_softc *, 30015516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 30115516c77SSepherosa Ziehau static void hn_nvs_handle_comp(struct hn_softc *, 30215516c77SSepherosa Ziehau struct vmbus_channel *, 30315516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 30415516c77SSepherosa Ziehau static void hn_nvs_handle_rxbuf(struct hn_rx_ring *, 30515516c77SSepherosa Ziehau struct vmbus_channel *, 30615516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 30715516c77SSepherosa Ziehau static void hn_nvs_ack_rxbuf(struct hn_rx_ring *, 30815516c77SSepherosa Ziehau struct vmbus_channel *, uint64_t); 30915516c77SSepherosa Ziehau 31015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 31115516c77SSepherosa Ziehau static int hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS); 31215516c77SSepherosa Ziehau static int hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS); 31315516c77SSepherosa Ziehau #endif 31415516c77SSepherosa Ziehau static int hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS); 31515516c77SSepherosa Ziehau static int hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS); 31615516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 31715516c77SSepherosa Ziehau static int hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS); 31815516c77SSepherosa Ziehau #else 31915516c77SSepherosa Ziehau static int hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS); 32015516c77SSepherosa Ziehau #endif 32115516c77SSepherosa Ziehau static int hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 32215516c77SSepherosa Ziehau static int hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 32315516c77SSepherosa Ziehau static int hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS); 32415516c77SSepherosa Ziehau static int hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS); 32515516c77SSepherosa Ziehau static int hn_caps_sysctl(SYSCTL_HANDLER_ARGS); 32615516c77SSepherosa Ziehau static int hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS); 32715516c77SSepherosa Ziehau static int hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS); 32834d68912SSepherosa Ziehau #ifndef RSS 32915516c77SSepherosa Ziehau static int hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS); 33015516c77SSepherosa Ziehau static int hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS); 33134d68912SSepherosa Ziehau #endif 33215516c77SSepherosa Ziehau static int hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS); 333642ec226SSepherosa Ziehau static int hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS); 334642ec226SSepherosa Ziehau static int hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS); 335dc13fee6SSepherosa Ziehau static int hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS); 336dc13fee6SSepherosa Ziehau static int hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS); 337dc13fee6SSepherosa Ziehau static int hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS); 338dc13fee6SSepherosa Ziehau static int hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS); 3396c1204dfSSepherosa Ziehau static int hn_polling_sysctl(SYSCTL_HANDLER_ARGS); 34040d60d6eSDexuan Cui static int hn_vf_sysctl(SYSCTL_HANDLER_ARGS); 341499c3e17SSepherosa Ziehau static int hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS); 342499c3e17SSepherosa Ziehau static int hn_vflist_sysctl(SYSCTL_HANDLER_ARGS); 343499c3e17SSepherosa Ziehau static int hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS); 3449c6cae24SSepherosa Ziehau static int hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS); 3459c6cae24SSepherosa Ziehau static int hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS); 34615516c77SSepherosa Ziehau 3475bdfd3fdSDexuan Cui static void hn_stop(struct hn_softc *, bool); 34815516c77SSepherosa Ziehau static void hn_init_locked(struct hn_softc *); 34915516c77SSepherosa Ziehau static int hn_chan_attach(struct hn_softc *, 35015516c77SSepherosa Ziehau struct vmbus_channel *); 35115516c77SSepherosa Ziehau static void hn_chan_detach(struct hn_softc *, 35215516c77SSepherosa Ziehau struct vmbus_channel *); 35315516c77SSepherosa Ziehau static int hn_attach_subchans(struct hn_softc *); 35415516c77SSepherosa Ziehau static void hn_detach_allchans(struct hn_softc *); 35515516c77SSepherosa Ziehau static void hn_chan_rollup(struct hn_rx_ring *, 35615516c77SSepherosa Ziehau struct hn_tx_ring *); 35715516c77SSepherosa Ziehau static void hn_set_ring_inuse(struct hn_softc *, int); 35815516c77SSepherosa Ziehau static int hn_synth_attach(struct hn_softc *, int); 35915516c77SSepherosa Ziehau static void hn_synth_detach(struct hn_softc *); 36015516c77SSepherosa Ziehau static int hn_synth_alloc_subchans(struct hn_softc *, 36115516c77SSepherosa Ziehau int *); 3622494d735SSepherosa Ziehau static bool hn_synth_attachable(const struct hn_softc *); 36315516c77SSepherosa Ziehau static void hn_suspend(struct hn_softc *); 36415516c77SSepherosa Ziehau static void hn_suspend_data(struct hn_softc *); 36515516c77SSepherosa Ziehau static void hn_suspend_mgmt(struct hn_softc *); 36615516c77SSepherosa Ziehau static void hn_resume(struct hn_softc *); 36715516c77SSepherosa Ziehau static void hn_resume_data(struct hn_softc *); 36815516c77SSepherosa Ziehau static void hn_resume_mgmt(struct hn_softc *); 36915516c77SSepherosa Ziehau static void hn_suspend_mgmt_taskfunc(void *, int); 37025641fc7SSepherosa Ziehau static void hn_chan_drain(struct hn_softc *, 37125641fc7SSepherosa Ziehau struct vmbus_channel *); 372b3b75d9cSSepherosa Ziehau static void hn_disable_rx(struct hn_softc *); 373b3b75d9cSSepherosa Ziehau static void hn_drain_rxtx(struct hn_softc *, int); 3746c1204dfSSepherosa Ziehau static void hn_polling(struct hn_softc *, u_int); 3756c1204dfSSepherosa Ziehau static void hn_chan_polling(struct vmbus_channel *, u_int); 3769c6cae24SSepherosa Ziehau static void hn_mtu_change_fixup(struct hn_softc *); 37715516c77SSepherosa Ziehau 37815516c77SSepherosa Ziehau static void hn_update_link_status(struct hn_softc *); 37915516c77SSepherosa Ziehau static void hn_change_network(struct hn_softc *); 38015516c77SSepherosa Ziehau static void hn_link_taskfunc(void *, int); 38115516c77SSepherosa Ziehau static void hn_netchg_init_taskfunc(void *, int); 38215516c77SSepherosa Ziehau static void hn_netchg_status_taskfunc(void *, int); 38315516c77SSepherosa Ziehau static void hn_link_status(struct hn_softc *); 38415516c77SSepherosa Ziehau 38515516c77SSepherosa Ziehau static int hn_create_rx_data(struct hn_softc *, int); 38615516c77SSepherosa Ziehau static void hn_destroy_rx_data(struct hn_softc *); 38715516c77SSepherosa Ziehau static int hn_check_iplen(const struct mbuf *, int); 388f1b0a43fSSepherosa Ziehau static int hn_set_rxfilter(struct hn_softc *, uint32_t); 389c08f7b2cSSepherosa Ziehau static int hn_rxfilter_config(struct hn_softc *); 39034d68912SSepherosa Ziehau #ifndef RSS 39115516c77SSepherosa Ziehau static int hn_rss_reconfig(struct hn_softc *); 39234d68912SSepherosa Ziehau #endif 393afd4971bSSepherosa Ziehau static void hn_rss_ind_fixup(struct hn_softc *); 394642ec226SSepherosa Ziehau static void hn_rss_mbuf_hash(struct hn_softc *, uint32_t); 39515516c77SSepherosa Ziehau static int hn_rxpkt(struct hn_rx_ring *, const void *, 39615516c77SSepherosa Ziehau int, const struct hn_rxinfo *); 397642ec226SSepherosa Ziehau static uint32_t hn_rss_type_fromndis(uint32_t); 398642ec226SSepherosa Ziehau static uint32_t hn_rss_type_tondis(uint32_t); 39915516c77SSepherosa Ziehau 40015516c77SSepherosa Ziehau static int hn_tx_ring_create(struct hn_softc *, int); 40115516c77SSepherosa Ziehau static void hn_tx_ring_destroy(struct hn_tx_ring *); 40215516c77SSepherosa Ziehau static int hn_create_tx_data(struct hn_softc *, int); 40315516c77SSepherosa Ziehau static void hn_fixup_tx_data(struct hn_softc *); 40415516c77SSepherosa Ziehau static void hn_destroy_tx_data(struct hn_softc *); 40515516c77SSepherosa Ziehau static void hn_txdesc_dmamap_destroy(struct hn_txdesc *); 40625641fc7SSepherosa Ziehau static void hn_txdesc_gc(struct hn_tx_ring *, 40725641fc7SSepherosa Ziehau struct hn_txdesc *); 408dc13fee6SSepherosa Ziehau static int hn_encap(struct ifnet *, struct hn_tx_ring *, 40915516c77SSepherosa Ziehau struct hn_txdesc *, struct mbuf **); 41015516c77SSepherosa Ziehau static int hn_txpkt(struct ifnet *, struct hn_tx_ring *, 41115516c77SSepherosa Ziehau struct hn_txdesc *); 41215516c77SSepherosa Ziehau static void hn_set_chim_size(struct hn_softc *, int); 41315516c77SSepherosa Ziehau static void hn_set_tso_maxsize(struct hn_softc *, int, int); 41415516c77SSepherosa Ziehau static bool hn_tx_ring_pending(struct hn_tx_ring *); 41515516c77SSepherosa Ziehau static void hn_tx_ring_qflush(struct hn_tx_ring *); 41615516c77SSepherosa Ziehau static void hn_resume_tx(struct hn_softc *, int); 417dc13fee6SSepherosa Ziehau static void hn_set_txagg(struct hn_softc *); 418dc13fee6SSepherosa Ziehau static void *hn_try_txagg(struct ifnet *, 419dc13fee6SSepherosa Ziehau struct hn_tx_ring *, struct hn_txdesc *, 420dc13fee6SSepherosa Ziehau int); 42115516c77SSepherosa Ziehau static int hn_get_txswq_depth(const struct hn_tx_ring *); 42215516c77SSepherosa Ziehau static void hn_txpkt_done(struct hn_nvs_sendctx *, 42315516c77SSepherosa Ziehau struct hn_softc *, struct vmbus_channel *, 42415516c77SSepherosa Ziehau const void *, int); 42515516c77SSepherosa Ziehau static int hn_txpkt_sglist(struct hn_tx_ring *, 42615516c77SSepherosa Ziehau struct hn_txdesc *); 42715516c77SSepherosa Ziehau static int hn_txpkt_chim(struct hn_tx_ring *, 42815516c77SSepherosa Ziehau struct hn_txdesc *); 42915516c77SSepherosa Ziehau static int hn_xmit(struct hn_tx_ring *, int); 43015516c77SSepherosa Ziehau static void hn_xmit_taskfunc(void *, int); 43115516c77SSepherosa Ziehau static void hn_xmit_txeof(struct hn_tx_ring *); 43215516c77SSepherosa Ziehau static void hn_xmit_txeof_taskfunc(void *, int); 43323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 43415516c77SSepherosa Ziehau static int hn_start_locked(struct hn_tx_ring *, int); 43515516c77SSepherosa Ziehau static void hn_start_taskfunc(void *, int); 43615516c77SSepherosa Ziehau static void hn_start_txeof(struct hn_tx_ring *); 43715516c77SSepherosa Ziehau static void hn_start_txeof_taskfunc(void *, int); 43823bf9e15SSepherosa Ziehau #endif 43915516c77SSepherosa Ziehau 44015516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 44115516c77SSepherosa Ziehau "Hyper-V network interface"); 44215516c77SSepherosa Ziehau 44315516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */ 44415516c77SSepherosa Ziehau static int hn_trust_hosttcp = 1; 44515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN, 44615516c77SSepherosa Ziehau &hn_trust_hosttcp, 0, 44715516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 44815516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 44915516c77SSepherosa Ziehau 45015516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */ 45115516c77SSepherosa Ziehau static int hn_trust_hostudp = 1; 45215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN, 45315516c77SSepherosa Ziehau &hn_trust_hostudp, 0, 45415516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 45515516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 45615516c77SSepherosa Ziehau 45715516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */ 45815516c77SSepherosa Ziehau static int hn_trust_hostip = 1; 45915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN, 46015516c77SSepherosa Ziehau &hn_trust_hostip, 0, 46115516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 46215516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 46315516c77SSepherosa Ziehau 4642be266caSSepherosa Ziehau /* 4652be266caSSepherosa Ziehau * Offload UDP/IPv4 checksum. 4662be266caSSepherosa Ziehau */ 4672be266caSSepherosa Ziehau static int hn_enable_udp4cs = 1; 4682be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp4cs, CTLFLAG_RDTUN, 4692be266caSSepherosa Ziehau &hn_enable_udp4cs, 0, "Offload UDP/IPv4 checksum"); 4702be266caSSepherosa Ziehau 4712be266caSSepherosa Ziehau /* 4722be266caSSepherosa Ziehau * Offload UDP/IPv6 checksum. 4732be266caSSepherosa Ziehau */ 4742be266caSSepherosa Ziehau static int hn_enable_udp6cs = 1; 4752be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp6cs, CTLFLAG_RDTUN, 4762be266caSSepherosa Ziehau &hn_enable_udp6cs, 0, "Offload UDP/IPv6 checksum"); 4772be266caSSepherosa Ziehau 4782be266caSSepherosa Ziehau /* Stats. */ 4792be266caSSepherosa Ziehau static counter_u64_t hn_udpcs_fixup; 4802be266caSSepherosa Ziehau SYSCTL_COUNTER_U64(_hw_hn, OID_AUTO, udpcs_fixup, CTLFLAG_RW, 4812be266caSSepherosa Ziehau &hn_udpcs_fixup, "# of UDP checksum fixup"); 4822be266caSSepherosa Ziehau 4832be266caSSepherosa Ziehau /* 4842be266caSSepherosa Ziehau * See hn_set_hlen(). 4852be266caSSepherosa Ziehau * 4862be266caSSepherosa Ziehau * This value is for Azure. For Hyper-V, set this above 4872be266caSSepherosa Ziehau * 65536 to disable UDP datagram checksum fixup. 4882be266caSSepherosa Ziehau */ 4892be266caSSepherosa Ziehau static int hn_udpcs_fixup_mtu = 1420; 4902be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, udpcs_fixup_mtu, CTLFLAG_RWTUN, 4912be266caSSepherosa Ziehau &hn_udpcs_fixup_mtu, 0, "UDP checksum fixup MTU threshold"); 4922be266caSSepherosa Ziehau 49315516c77SSepherosa Ziehau /* Limit TSO burst size */ 49415516c77SSepherosa Ziehau static int hn_tso_maxlen = IP_MAXPACKET; 49515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN, 49615516c77SSepherosa Ziehau &hn_tso_maxlen, 0, "TSO burst limit"); 49715516c77SSepherosa Ziehau 49815516c77SSepherosa Ziehau /* Limit chimney send size */ 49915516c77SSepherosa Ziehau static int hn_tx_chimney_size = 0; 50015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN, 50115516c77SSepherosa Ziehau &hn_tx_chimney_size, 0, "Chimney send packet size limit"); 50215516c77SSepherosa Ziehau 50315516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */ 50415516c77SSepherosa Ziehau static int hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF; 50515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN, 50615516c77SSepherosa Ziehau &hn_direct_tx_size, 0, "Size of the packet for direct transmission"); 50715516c77SSepherosa Ziehau 50815516c77SSepherosa Ziehau /* # of LRO entries per RX ring */ 50915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 51015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 51115516c77SSepherosa Ziehau static int hn_lro_entry_count = HN_LROENT_CNT_DEF; 51215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN, 51315516c77SSepherosa Ziehau &hn_lro_entry_count, 0, "LRO entry count"); 51415516c77SSepherosa Ziehau #endif 51515516c77SSepherosa Ziehau #endif 51615516c77SSepherosa Ziehau 517fdd0222aSSepherosa Ziehau static int hn_tx_taskq_cnt = 1; 518fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN, 519fdd0222aSSepherosa Ziehau &hn_tx_taskq_cnt, 0, "# of TX taskqueues"); 520fdd0222aSSepherosa Ziehau 5210e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP 0 5220e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL 1 5230e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ 2 5240e11868dSSepherosa Ziehau 5250e11868dSSepherosa Ziehau static int hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP; 5260e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN, 5270e11868dSSepherosa Ziehau &hn_tx_taskq_mode, 0, "TX taskqueue modes: " 5280e11868dSSepherosa Ziehau "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs"); 5290e11868dSSepherosa Ziehau 53015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 53115516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 0; 53215516c77SSepherosa Ziehau #else 53315516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 1; 53415516c77SSepherosa Ziehau #endif 53515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD, 53615516c77SSepherosa Ziehau &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors"); 53715516c77SSepherosa Ziehau 53823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 53915516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */ 54015516c77SSepherosa Ziehau static int hn_use_if_start = 0; 54115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN, 54215516c77SSepherosa Ziehau &hn_use_if_start, 0, "Use if_start TX method"); 54323bf9e15SSepherosa Ziehau #endif 54415516c77SSepherosa Ziehau 54515516c77SSepherosa Ziehau /* # of channels to use */ 54615516c77SSepherosa Ziehau static int hn_chan_cnt = 0; 54715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN, 54815516c77SSepherosa Ziehau &hn_chan_cnt, 0, 54915516c77SSepherosa Ziehau "# of channels to use; each channel has one RX ring and one TX ring"); 55015516c77SSepherosa Ziehau 55115516c77SSepherosa Ziehau /* # of transmit rings to use */ 55215516c77SSepherosa Ziehau static int hn_tx_ring_cnt = 0; 55315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN, 55415516c77SSepherosa Ziehau &hn_tx_ring_cnt, 0, "# of TX rings to use"); 55515516c77SSepherosa Ziehau 55615516c77SSepherosa Ziehau /* Software TX ring deptch */ 55715516c77SSepherosa Ziehau static int hn_tx_swq_depth = 0; 55815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN, 55915516c77SSepherosa Ziehau &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING"); 56015516c77SSepherosa Ziehau 56115516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */ 56215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 56315516c77SSepherosa Ziehau static u_int hn_lro_mbufq_depth = 0; 56415516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN, 56515516c77SSepherosa Ziehau &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue"); 56615516c77SSepherosa Ziehau #endif 56715516c77SSepherosa Ziehau 568dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */ 569dc13fee6SSepherosa Ziehau static int hn_tx_agg_size = -1; 570dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN, 571dc13fee6SSepherosa Ziehau &hn_tx_agg_size, 0, "Packet transmission aggregation size limit"); 572dc13fee6SSepherosa Ziehau 573dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */ 574fa915c4dSSepherosa Ziehau static int hn_tx_agg_pkts = -1; 575dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN, 576dc13fee6SSepherosa Ziehau &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit"); 577dc13fee6SSepherosa Ziehau 578499c3e17SSepherosa Ziehau /* VF list */ 579499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vflist, CTLFLAG_RD | CTLTYPE_STRING, 580499c3e17SSepherosa Ziehau 0, 0, hn_vflist_sysctl, "A", "VF list"); 581499c3e17SSepherosa Ziehau 582499c3e17SSepherosa Ziehau /* VF mapping */ 583499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap, CTLFLAG_RD | CTLTYPE_STRING, 584499c3e17SSepherosa Ziehau 0, 0, hn_vfmap_sysctl, "A", "VF mapping"); 585499c3e17SSepherosa Ziehau 5869c6cae24SSepherosa Ziehau /* Transparent VF */ 5879c6cae24SSepherosa Ziehau static int hn_xpnt_vf = 0; 5889c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_transparent, CTLFLAG_RDTUN, 5899c6cae24SSepherosa Ziehau &hn_xpnt_vf, 0, "Transparent VF mod"); 5909c6cae24SSepherosa Ziehau 5919c6cae24SSepherosa Ziehau /* Accurate BPF support for Transparent VF */ 5929c6cae24SSepherosa Ziehau static int hn_xpnt_vf_accbpf = 0; 5939c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_accbpf, CTLFLAG_RDTUN, 5949c6cae24SSepherosa Ziehau &hn_xpnt_vf_accbpf, 0, "Accurate BPF for transparent VF"); 5959c6cae24SSepherosa Ziehau 5969c6cae24SSepherosa Ziehau /* Extra wait for transparent VF attach routing; unit seconds. */ 5979c6cae24SSepherosa Ziehau static int hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN; 5989c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_attwait, CTLFLAG_RWTUN, 5999c6cae24SSepherosa Ziehau &hn_xpnt_vf_attwait, 0, 6009c6cae24SSepherosa Ziehau "Extra wait for transparent VF attach routing; unit: seconds"); 6019c6cae24SSepherosa Ziehau 60215516c77SSepherosa Ziehau static u_int hn_cpu_index; /* next CPU for channel */ 603fdd0222aSSepherosa Ziehau static struct taskqueue **hn_tx_taskque;/* shared TX taskqueues */ 60415516c77SSepherosa Ziehau 605499c3e17SSepherosa Ziehau static struct rmlock hn_vfmap_lock; 606499c3e17SSepherosa Ziehau static int hn_vfmap_size; 607499c3e17SSepherosa Ziehau static struct ifnet **hn_vfmap; 608499c3e17SSepherosa Ziehau 60934d68912SSepherosa Ziehau #ifndef RSS 61015516c77SSepherosa Ziehau static const uint8_t 61115516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = { 61215516c77SSepherosa Ziehau 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 61315516c77SSepherosa Ziehau 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 61415516c77SSepherosa Ziehau 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 61515516c77SSepherosa Ziehau 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 61615516c77SSepherosa Ziehau 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa 61715516c77SSepherosa Ziehau }; 61834d68912SSepherosa Ziehau #endif /* !RSS */ 61915516c77SSepherosa Ziehau 620c2d50b26SSepherosa Ziehau static const struct hyperv_guid hn_guid = { 621c2d50b26SSepherosa Ziehau .hv_guid = { 622c2d50b26SSepherosa Ziehau 0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46, 623c2d50b26SSepherosa Ziehau 0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e } 624c2d50b26SSepherosa Ziehau }; 625c2d50b26SSepherosa Ziehau 62615516c77SSepherosa Ziehau static device_method_t hn_methods[] = { 62715516c77SSepherosa Ziehau /* Device interface */ 62815516c77SSepherosa Ziehau DEVMETHOD(device_probe, hn_probe), 62915516c77SSepherosa Ziehau DEVMETHOD(device_attach, hn_attach), 63015516c77SSepherosa Ziehau DEVMETHOD(device_detach, hn_detach), 63115516c77SSepherosa Ziehau DEVMETHOD(device_shutdown, hn_shutdown), 63215516c77SSepherosa Ziehau DEVMETHOD_END 63315516c77SSepherosa Ziehau }; 63415516c77SSepherosa Ziehau 63515516c77SSepherosa Ziehau static driver_t hn_driver = { 63615516c77SSepherosa Ziehau "hn", 63715516c77SSepherosa Ziehau hn_methods, 63815516c77SSepherosa Ziehau sizeof(struct hn_softc) 63915516c77SSepherosa Ziehau }; 64015516c77SSepherosa Ziehau 64115516c77SSepherosa Ziehau static devclass_t hn_devclass; 64215516c77SSepherosa Ziehau 64315516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0); 64415516c77SSepherosa Ziehau MODULE_VERSION(hn, 1); 64515516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1); 64615516c77SSepherosa Ziehau 64715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 64815516c77SSepherosa Ziehau static void 64915516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim) 65015516c77SSepherosa Ziehau { 65115516c77SSepherosa Ziehau int i; 65215516c77SSepherosa Ziehau 653a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 65415516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim; 65515516c77SSepherosa Ziehau } 65615516c77SSepherosa Ziehau #endif 65715516c77SSepherosa Ziehau 65815516c77SSepherosa Ziehau static int 65915516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd) 66015516c77SSepherosa Ziehau { 66115516c77SSepherosa Ziehau 66215516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 66315516c77SSepherosa Ziehau txd->chim_size == 0, ("invalid rndis sglist txd")); 66415516c77SSepherosa Ziehau return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA, 66515516c77SSepherosa Ziehau &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt)); 66615516c77SSepherosa Ziehau } 66715516c77SSepherosa Ziehau 66815516c77SSepherosa Ziehau static int 66915516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd) 67015516c77SSepherosa Ziehau { 67115516c77SSepherosa Ziehau struct hn_nvs_rndis rndis; 67215516c77SSepherosa Ziehau 67315516c77SSepherosa Ziehau KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID && 67415516c77SSepherosa Ziehau txd->chim_size > 0, ("invalid rndis chim txd")); 67515516c77SSepherosa Ziehau 67615516c77SSepherosa Ziehau rndis.nvs_type = HN_NVS_TYPE_RNDIS; 67715516c77SSepherosa Ziehau rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA; 67815516c77SSepherosa Ziehau rndis.nvs_chim_idx = txd->chim_index; 67915516c77SSepherosa Ziehau rndis.nvs_chim_sz = txd->chim_size; 68015516c77SSepherosa Ziehau 68115516c77SSepherosa Ziehau return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC, 68215516c77SSepherosa Ziehau &rndis, sizeof(rndis), &txd->send_ctx)); 68315516c77SSepherosa Ziehau } 68415516c77SSepherosa Ziehau 68515516c77SSepherosa Ziehau static __inline uint32_t 68615516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc) 68715516c77SSepherosa Ziehau { 68815516c77SSepherosa Ziehau int i, bmap_cnt = sc->hn_chim_bmap_cnt; 68915516c77SSepherosa Ziehau u_long *bmap = sc->hn_chim_bmap; 69015516c77SSepherosa Ziehau uint32_t ret = HN_NVS_CHIM_IDX_INVALID; 69115516c77SSepherosa Ziehau 69215516c77SSepherosa Ziehau for (i = 0; i < bmap_cnt; ++i) { 69315516c77SSepherosa Ziehau int idx; 69415516c77SSepherosa Ziehau 69515516c77SSepherosa Ziehau idx = ffsl(~bmap[i]); 69615516c77SSepherosa Ziehau if (idx == 0) 69715516c77SSepherosa Ziehau continue; 69815516c77SSepherosa Ziehau 69915516c77SSepherosa Ziehau --idx; /* ffsl is 1-based */ 70015516c77SSepherosa Ziehau KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt, 70115516c77SSepherosa Ziehau ("invalid i %d and idx %d", i, idx)); 70215516c77SSepherosa Ziehau 70315516c77SSepherosa Ziehau if (atomic_testandset_long(&bmap[i], idx)) 70415516c77SSepherosa Ziehau continue; 70515516c77SSepherosa Ziehau 70615516c77SSepherosa Ziehau ret = i * LONG_BIT + idx; 70715516c77SSepherosa Ziehau break; 70815516c77SSepherosa Ziehau } 70915516c77SSepherosa Ziehau return (ret); 71015516c77SSepherosa Ziehau } 71115516c77SSepherosa Ziehau 71215516c77SSepherosa Ziehau static __inline void 71315516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx) 71415516c77SSepherosa Ziehau { 71515516c77SSepherosa Ziehau u_long mask; 71615516c77SSepherosa Ziehau uint32_t idx; 71715516c77SSepherosa Ziehau 71815516c77SSepherosa Ziehau idx = chim_idx / LONG_BIT; 71915516c77SSepherosa Ziehau KASSERT(idx < sc->hn_chim_bmap_cnt, 72015516c77SSepherosa Ziehau ("invalid chimney index 0x%x", chim_idx)); 72115516c77SSepherosa Ziehau 72215516c77SSepherosa Ziehau mask = 1UL << (chim_idx % LONG_BIT); 72315516c77SSepherosa Ziehau KASSERT(sc->hn_chim_bmap[idx] & mask, 72415516c77SSepherosa Ziehau ("index bitmap 0x%lx, chimney index %u, " 72515516c77SSepherosa Ziehau "bitmap idx %d, bitmask 0x%lx", 72615516c77SSepherosa Ziehau sc->hn_chim_bmap[idx], chim_idx, idx, mask)); 72715516c77SSepherosa Ziehau 72815516c77SSepherosa Ziehau atomic_clear_long(&sc->hn_chim_bmap[idx], mask); 72915516c77SSepherosa Ziehau } 73015516c77SSepherosa Ziehau 731edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 732cc0c6ebcSSepherosa Ziehau 733cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len) \ 734cc0c6ebcSSepherosa Ziehau do { \ 735cc0c6ebcSSepherosa Ziehau if (__predict_false((m)->m_len < (len))) { \ 736cc0c6ebcSSepherosa Ziehau (m) = m_pullup((m), (len)); \ 737cc0c6ebcSSepherosa Ziehau if ((m) == NULL) \ 738cc0c6ebcSSepherosa Ziehau return (NULL); \ 739cc0c6ebcSSepherosa Ziehau } \ 740cc0c6ebcSSepherosa Ziehau } while (0) 741cc0c6ebcSSepherosa Ziehau 742edd3f315SSepherosa Ziehau /* 743edd3f315SSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 744edd3f315SSepherosa Ziehau */ 745edd3f315SSepherosa Ziehau static __inline struct mbuf * 746edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head) 747edd3f315SSepherosa Ziehau { 748edd3f315SSepherosa Ziehau struct ether_vlan_header *evl; 749edd3f315SSepherosa Ziehau struct tcphdr *th; 750edd3f315SSepherosa Ziehau int ehlen; 751edd3f315SSepherosa Ziehau 752edd3f315SSepherosa Ziehau KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable")); 753edd3f315SSepherosa Ziehau 754edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, sizeof(*evl)); 755edd3f315SSepherosa Ziehau evl = mtod(m_head, struct ether_vlan_header *); 756edd3f315SSepherosa Ziehau if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) 757edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 758edd3f315SSepherosa Ziehau else 759edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN; 760c49d47daSSepherosa Ziehau m_head->m_pkthdr.l2hlen = ehlen; 761edd3f315SSepherosa Ziehau 762edd3f315SSepherosa Ziehau #ifdef INET 763edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 764edd3f315SSepherosa Ziehau struct ip *ip; 765edd3f315SSepherosa Ziehau int iphlen; 766edd3f315SSepherosa Ziehau 767edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip)); 768edd3f315SSepherosa Ziehau ip = mtodo(m_head, ehlen); 769edd3f315SSepherosa Ziehau iphlen = ip->ip_hl << 2; 770c49d47daSSepherosa Ziehau m_head->m_pkthdr.l3hlen = iphlen; 771edd3f315SSepherosa Ziehau 772edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 773edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 774edd3f315SSepherosa Ziehau 775edd3f315SSepherosa Ziehau ip->ip_len = 0; 776edd3f315SSepherosa Ziehau ip->ip_sum = 0; 777edd3f315SSepherosa Ziehau th->th_sum = in_pseudo(ip->ip_src.s_addr, 778edd3f315SSepherosa Ziehau ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 779edd3f315SSepherosa Ziehau } 780edd3f315SSepherosa Ziehau #endif 781edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET) 782edd3f315SSepherosa Ziehau else 783edd3f315SSepherosa Ziehau #endif 784edd3f315SSepherosa Ziehau #ifdef INET6 785edd3f315SSepherosa Ziehau { 786edd3f315SSepherosa Ziehau struct ip6_hdr *ip6; 787edd3f315SSepherosa Ziehau 788edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); 789edd3f315SSepherosa Ziehau ip6 = mtodo(m_head, ehlen); 790edd3f315SSepherosa Ziehau if (ip6->ip6_nxt != IPPROTO_TCP) { 791edd3f315SSepherosa Ziehau m_freem(m_head); 792edd3f315SSepherosa Ziehau return (NULL); 793edd3f315SSepherosa Ziehau } 794c49d47daSSepherosa Ziehau m_head->m_pkthdr.l3hlen = sizeof(*ip6); 795edd3f315SSepherosa Ziehau 796edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); 797edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + sizeof(*ip6)); 798edd3f315SSepherosa Ziehau 799edd3f315SSepherosa Ziehau ip6->ip6_plen = 0; 800edd3f315SSepherosa Ziehau th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 801edd3f315SSepherosa Ziehau } 802edd3f315SSepherosa Ziehau #endif 803edd3f315SSepherosa Ziehau return (m_head); 804edd3f315SSepherosa Ziehau } 805cc0c6ebcSSepherosa Ziehau 806cc0c6ebcSSepherosa Ziehau /* 807cc0c6ebcSSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 808cc0c6ebcSSepherosa Ziehau */ 809cc0c6ebcSSepherosa Ziehau static __inline struct mbuf * 810c49d47daSSepherosa Ziehau hn_set_hlen(struct mbuf *m_head) 811cc0c6ebcSSepherosa Ziehau { 812cc0c6ebcSSepherosa Ziehau const struct ether_vlan_header *evl; 813cc0c6ebcSSepherosa Ziehau int ehlen; 814cc0c6ebcSSepherosa Ziehau 815cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, sizeof(*evl)); 816cc0c6ebcSSepherosa Ziehau evl = mtod(m_head, const struct ether_vlan_header *); 817cc0c6ebcSSepherosa Ziehau if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) 818cc0c6ebcSSepherosa Ziehau ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 819cc0c6ebcSSepherosa Ziehau else 820cc0c6ebcSSepherosa Ziehau ehlen = ETHER_HDR_LEN; 821c49d47daSSepherosa Ziehau m_head->m_pkthdr.l2hlen = ehlen; 822cc0c6ebcSSepherosa Ziehau 823cc0c6ebcSSepherosa Ziehau #ifdef INET 824c49d47daSSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) { 825cc0c6ebcSSepherosa Ziehau const struct ip *ip; 826cc0c6ebcSSepherosa Ziehau int iphlen; 827cc0c6ebcSSepherosa Ziehau 828cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip)); 829cc0c6ebcSSepherosa Ziehau ip = mtodo(m_head, ehlen); 830cc0c6ebcSSepherosa Ziehau iphlen = ip->ip_hl << 2; 831c49d47daSSepherosa Ziehau m_head->m_pkthdr.l3hlen = iphlen; 8322be266caSSepherosa Ziehau 8332be266caSSepherosa Ziehau /* 8342be266caSSepherosa Ziehau * UDP checksum offload does not work in Azure, if the 8352be266caSSepherosa Ziehau * following conditions meet: 8362be266caSSepherosa Ziehau * - sizeof(IP hdr + UDP hdr + payload) > 1420. 8372be266caSSepherosa Ziehau * - IP_DF is not set in the IP hdr. 8382be266caSSepherosa Ziehau * 8392be266caSSepherosa Ziehau * Fallback to software checksum for these UDP datagrams. 8402be266caSSepherosa Ziehau */ 8412be266caSSepherosa Ziehau if ((m_head->m_pkthdr.csum_flags & CSUM_IP_UDP) && 8422be266caSSepherosa Ziehau m_head->m_pkthdr.len > hn_udpcs_fixup_mtu + ehlen && 8432be266caSSepherosa Ziehau (ntohs(ip->ip_off) & IP_DF) == 0) { 8442be266caSSepherosa Ziehau uint16_t off = ehlen + iphlen; 8452be266caSSepherosa Ziehau 8462be266caSSepherosa Ziehau counter_u64_add(hn_udpcs_fixup, 1); 8472be266caSSepherosa Ziehau PULLUP_HDR(m_head, off + sizeof(struct udphdr)); 8482be266caSSepherosa Ziehau *(uint16_t *)(m_head->m_data + off + 8492be266caSSepherosa Ziehau m_head->m_pkthdr.csum_data) = in_cksum_skip( 8502be266caSSepherosa Ziehau m_head, m_head->m_pkthdr.len, off); 8512be266caSSepherosa Ziehau m_head->m_pkthdr.csum_flags &= ~CSUM_IP_UDP; 8522be266caSSepherosa Ziehau } 853cc0c6ebcSSepherosa Ziehau } 854cc0c6ebcSSepherosa Ziehau #endif 855cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET) 856cc0c6ebcSSepherosa Ziehau else 857cc0c6ebcSSepherosa Ziehau #endif 858cc0c6ebcSSepherosa Ziehau #ifdef INET6 859cc0c6ebcSSepherosa Ziehau { 860cc0c6ebcSSepherosa Ziehau const struct ip6_hdr *ip6; 861cc0c6ebcSSepherosa Ziehau 862cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); 863cc0c6ebcSSepherosa Ziehau ip6 = mtodo(m_head, ehlen); 864c49d47daSSepherosa Ziehau if (ip6->ip6_nxt != IPPROTO_TCP) { 865c49d47daSSepherosa Ziehau m_freem(m_head); 866c49d47daSSepherosa Ziehau return (NULL); 867c49d47daSSepherosa Ziehau } 868c49d47daSSepherosa Ziehau m_head->m_pkthdr.l3hlen = sizeof(*ip6); 869cc0c6ebcSSepherosa Ziehau } 870cc0c6ebcSSepherosa Ziehau #endif 871cc0c6ebcSSepherosa Ziehau return (m_head); 872cc0c6ebcSSepherosa Ziehau } 873cc0c6ebcSSepherosa Ziehau 874c49d47daSSepherosa Ziehau /* 875c49d47daSSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 876c49d47daSSepherosa Ziehau */ 877c49d47daSSepherosa Ziehau static __inline struct mbuf * 878c49d47daSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn) 879c49d47daSSepherosa Ziehau { 880c49d47daSSepherosa Ziehau const struct tcphdr *th; 881c49d47daSSepherosa Ziehau int ehlen, iphlen; 882c49d47daSSepherosa Ziehau 883c49d47daSSepherosa Ziehau *tcpsyn = 0; 884c49d47daSSepherosa Ziehau ehlen = m_head->m_pkthdr.l2hlen; 885c49d47daSSepherosa Ziehau iphlen = m_head->m_pkthdr.l3hlen; 886c49d47daSSepherosa Ziehau 887c49d47daSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 888c49d47daSSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 889c49d47daSSepherosa Ziehau if (th->th_flags & TH_SYN) 890c49d47daSSepherosa Ziehau *tcpsyn = 1; 891c49d47daSSepherosa Ziehau return (m_head); 892c49d47daSSepherosa Ziehau } 893c49d47daSSepherosa Ziehau 894cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR 895cc0c6ebcSSepherosa Ziehau 896edd3f315SSepherosa Ziehau #endif /* INET6 || INET */ 897edd3f315SSepherosa Ziehau 89815516c77SSepherosa Ziehau static int 899f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter) 900f1b0a43fSSepherosa Ziehau { 901f1b0a43fSSepherosa Ziehau int error = 0; 902f1b0a43fSSepherosa Ziehau 903f1b0a43fSSepherosa Ziehau HN_LOCK_ASSERT(sc); 904f1b0a43fSSepherosa Ziehau 905f1b0a43fSSepherosa Ziehau if (sc->hn_rx_filter != filter) { 906f1b0a43fSSepherosa Ziehau error = hn_rndis_set_rxfilter(sc, filter); 907f1b0a43fSSepherosa Ziehau if (!error) 908f1b0a43fSSepherosa Ziehau sc->hn_rx_filter = filter; 909f1b0a43fSSepherosa Ziehau } 910f1b0a43fSSepherosa Ziehau return (error); 911f1b0a43fSSepherosa Ziehau } 912f1b0a43fSSepherosa Ziehau 913f1b0a43fSSepherosa Ziehau static int 914c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc) 91515516c77SSepherosa Ziehau { 91615516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 91715516c77SSepherosa Ziehau uint32_t filter; 91815516c77SSepherosa Ziehau 91915516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 92015516c77SSepherosa Ziehau 9219c6cae24SSepherosa Ziehau /* 9229c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, we don't know how 9239c6cae24SSepherosa Ziehau * its RX filter is configured, so stick the synthetic device in 9249c6cae24SSepherosa Ziehau * the promiscous mode. 9259c6cae24SSepherosa Ziehau */ 9269c6cae24SSepherosa Ziehau if ((ifp->if_flags & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) { 92715516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_PROMISCUOUS; 92815516c77SSepherosa Ziehau } else { 92915516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_DIRECTED; 93015516c77SSepherosa Ziehau if (ifp->if_flags & IFF_BROADCAST) 93115516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_BROADCAST; 93215516c77SSepherosa Ziehau /* TODO: support multicast list */ 93315516c77SSepherosa Ziehau if ((ifp->if_flags & IFF_ALLMULTI) || 93415516c77SSepherosa Ziehau !TAILQ_EMPTY(&ifp->if_multiaddrs)) 93515516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 93615516c77SSepherosa Ziehau } 937f1b0a43fSSepherosa Ziehau return (hn_set_rxfilter(sc, filter)); 93815516c77SSepherosa Ziehau } 93915516c77SSepherosa Ziehau 940dc13fee6SSepherosa Ziehau static void 941dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc) 942dc13fee6SSepherosa Ziehau { 943dc13fee6SSepherosa Ziehau uint32_t size, pkts; 944dc13fee6SSepherosa Ziehau int i; 945dc13fee6SSepherosa Ziehau 946dc13fee6SSepherosa Ziehau /* 947dc13fee6SSepherosa Ziehau * Setup aggregation size. 948dc13fee6SSepherosa Ziehau */ 949dc13fee6SSepherosa Ziehau if (sc->hn_agg_size < 0) 950dc13fee6SSepherosa Ziehau size = UINT32_MAX; 951dc13fee6SSepherosa Ziehau else 952dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 953dc13fee6SSepherosa Ziehau 954dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_size < size) 955dc13fee6SSepherosa Ziehau size = sc->hn_rndis_agg_size; 956dc13fee6SSepherosa Ziehau 957a4364cfeSSepherosa Ziehau /* NOTE: We only aggregate packets using chimney sending buffers. */ 958a4364cfeSSepherosa Ziehau if (size > (uint32_t)sc->hn_chim_szmax) 959a4364cfeSSepherosa Ziehau size = sc->hn_chim_szmax; 960a4364cfeSSepherosa Ziehau 961dc13fee6SSepherosa Ziehau if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) { 962dc13fee6SSepherosa Ziehau /* Disable */ 963dc13fee6SSepherosa Ziehau size = 0; 964dc13fee6SSepherosa Ziehau pkts = 0; 965dc13fee6SSepherosa Ziehau goto done; 966dc13fee6SSepherosa Ziehau } 967dc13fee6SSepherosa Ziehau 968dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'int'. */ 969dc13fee6SSepherosa Ziehau if (size > INT_MAX) 970dc13fee6SSepherosa Ziehau size = INT_MAX; 971dc13fee6SSepherosa Ziehau 972dc13fee6SSepherosa Ziehau /* 973dc13fee6SSepherosa Ziehau * Setup aggregation packet count. 974dc13fee6SSepherosa Ziehau */ 975dc13fee6SSepherosa Ziehau if (sc->hn_agg_pkts < 0) 976dc13fee6SSepherosa Ziehau pkts = UINT32_MAX; 977dc13fee6SSepherosa Ziehau else 978dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 979dc13fee6SSepherosa Ziehau 980dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_pkts < pkts) 981dc13fee6SSepherosa Ziehau pkts = sc->hn_rndis_agg_pkts; 982dc13fee6SSepherosa Ziehau 983dc13fee6SSepherosa Ziehau if (pkts <= 1) { 984dc13fee6SSepherosa Ziehau /* Disable */ 985dc13fee6SSepherosa Ziehau size = 0; 986dc13fee6SSepherosa Ziehau pkts = 0; 987dc13fee6SSepherosa Ziehau goto done; 988dc13fee6SSepherosa Ziehau } 989dc13fee6SSepherosa Ziehau 990dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 991dc13fee6SSepherosa Ziehau if (pkts > SHRT_MAX) 992dc13fee6SSepherosa Ziehau pkts = SHRT_MAX; 993dc13fee6SSepherosa Ziehau 994dc13fee6SSepherosa Ziehau done: 995dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 996dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_align > SHRT_MAX) { 997dc13fee6SSepherosa Ziehau /* Disable */ 998dc13fee6SSepherosa Ziehau size = 0; 999dc13fee6SSepherosa Ziehau pkts = 0; 1000dc13fee6SSepherosa Ziehau } 1001dc13fee6SSepherosa Ziehau 1002dc13fee6SSepherosa Ziehau if (bootverbose) { 1003dc13fee6SSepherosa Ziehau if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n", 1004dc13fee6SSepherosa Ziehau size, pkts, sc->hn_rndis_agg_align); 1005dc13fee6SSepherosa Ziehau } 1006dc13fee6SSepherosa Ziehau 1007dc13fee6SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 1008dc13fee6SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 1009dc13fee6SSepherosa Ziehau 1010dc13fee6SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 1011dc13fee6SSepherosa Ziehau txr->hn_agg_szmax = size; 1012dc13fee6SSepherosa Ziehau txr->hn_agg_pktmax = pkts; 1013dc13fee6SSepherosa Ziehau txr->hn_agg_align = sc->hn_rndis_agg_align; 1014dc13fee6SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 1015dc13fee6SSepherosa Ziehau } 1016dc13fee6SSepherosa Ziehau } 1017dc13fee6SSepherosa Ziehau 101815516c77SSepherosa Ziehau static int 101915516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr) 102015516c77SSepherosa Ziehau { 102115516c77SSepherosa Ziehau 102215516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet")); 102315516c77SSepherosa Ziehau if (hn_tx_swq_depth < txr->hn_txdesc_cnt) 102415516c77SSepherosa Ziehau return txr->hn_txdesc_cnt; 102515516c77SSepherosa Ziehau return hn_tx_swq_depth; 102615516c77SSepherosa Ziehau } 102715516c77SSepherosa Ziehau 102834d68912SSepherosa Ziehau #ifndef RSS 102915516c77SSepherosa Ziehau static int 103015516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc) 103115516c77SSepherosa Ziehau { 103215516c77SSepherosa Ziehau int error; 103315516c77SSepherosa Ziehau 103415516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 103515516c77SSepherosa Ziehau 103615516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 103715516c77SSepherosa Ziehau return (ENXIO); 103815516c77SSepherosa Ziehau 103915516c77SSepherosa Ziehau /* 104015516c77SSepherosa Ziehau * Disable RSS first. 104115516c77SSepherosa Ziehau * 104215516c77SSepherosa Ziehau * NOTE: 104315516c77SSepherosa Ziehau * Direct reconfiguration by setting the UNCHG flags does 104415516c77SSepherosa Ziehau * _not_ work properly. 104515516c77SSepherosa Ziehau */ 104615516c77SSepherosa Ziehau if (bootverbose) 104715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "disable RSS\n"); 104815516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE); 104915516c77SSepherosa Ziehau if (error) { 105015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS disable failed\n"); 105115516c77SSepherosa Ziehau return (error); 105215516c77SSepherosa Ziehau } 105315516c77SSepherosa Ziehau 105415516c77SSepherosa Ziehau /* 105515516c77SSepherosa Ziehau * Reenable the RSS w/ the updated RSS key or indirect 105615516c77SSepherosa Ziehau * table. 105715516c77SSepherosa Ziehau */ 105815516c77SSepherosa Ziehau if (bootverbose) 105915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "reconfig RSS\n"); 106015516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 106115516c77SSepherosa Ziehau if (error) { 106215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS reconfig failed\n"); 106315516c77SSepherosa Ziehau return (error); 106415516c77SSepherosa Ziehau } 106515516c77SSepherosa Ziehau return (0); 106615516c77SSepherosa Ziehau } 106734d68912SSepherosa Ziehau #endif /* !RSS */ 106815516c77SSepherosa Ziehau 106915516c77SSepherosa Ziehau static void 1070afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc) 107115516c77SSepherosa Ziehau { 107215516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 1073afd4971bSSepherosa Ziehau int i, nchan; 107415516c77SSepherosa Ziehau 1075afd4971bSSepherosa Ziehau nchan = sc->hn_rx_ring_inuse; 107615516c77SSepherosa Ziehau KASSERT(nchan > 1, ("invalid # of channels %d", nchan)); 107715516c77SSepherosa Ziehau 107815516c77SSepherosa Ziehau /* 107915516c77SSepherosa Ziehau * Check indirect table to make sure that all channels in it 108015516c77SSepherosa Ziehau * can be used. 108115516c77SSepherosa Ziehau */ 108215516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 108315516c77SSepherosa Ziehau if (rss->rss_ind[i] >= nchan) { 108415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, 108515516c77SSepherosa Ziehau "RSS indirect table %d fixup: %u -> %d\n", 108615516c77SSepherosa Ziehau i, rss->rss_ind[i], nchan - 1); 108715516c77SSepherosa Ziehau rss->rss_ind[i] = nchan - 1; 108815516c77SSepherosa Ziehau } 108915516c77SSepherosa Ziehau } 109015516c77SSepherosa Ziehau } 109115516c77SSepherosa Ziehau 109215516c77SSepherosa Ziehau static int 109315516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused) 109415516c77SSepherosa Ziehau { 109515516c77SSepherosa Ziehau 109615516c77SSepherosa Ziehau return EOPNOTSUPP; 109715516c77SSepherosa Ziehau } 109815516c77SSepherosa Ziehau 109915516c77SSepherosa Ziehau static void 110015516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 110115516c77SSepherosa Ziehau { 110215516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 110315516c77SSepherosa Ziehau 110415516c77SSepherosa Ziehau ifmr->ifm_status = IFM_AVALID; 110515516c77SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 110615516c77SSepherosa Ziehau 110715516c77SSepherosa Ziehau if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) { 110815516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_NONE; 110915516c77SSepherosa Ziehau return; 111015516c77SSepherosa Ziehau } 111115516c77SSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 111215516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 111315516c77SSepherosa Ziehau } 111415516c77SSepherosa Ziehau 11155bdfd3fdSDexuan Cui static void 1116962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused) 11175bdfd3fdSDexuan Cui { 1118962f0357SSepherosa Ziehau struct hn_rxvf_setarg *arg = xarg; 11195bdfd3fdSDexuan Cui 1120962f0357SSepherosa Ziehau arg->rxr->hn_rxvf_ifp = arg->vf_ifp; 11215bdfd3fdSDexuan Cui } 11225bdfd3fdSDexuan Cui 11235bdfd3fdSDexuan Cui static void 1124962f0357SSepherosa Ziehau hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp) 11255bdfd3fdSDexuan Cui { 11265bdfd3fdSDexuan Cui struct hn_rx_ring *rxr; 1127962f0357SSepherosa Ziehau struct hn_rxvf_setarg arg; 11285bdfd3fdSDexuan Cui struct task task; 11295bdfd3fdSDexuan Cui int i; 11305bdfd3fdSDexuan Cui 11315bdfd3fdSDexuan Cui HN_LOCK_ASSERT(sc); 11325bdfd3fdSDexuan Cui 1133962f0357SSepherosa Ziehau TASK_INIT(&task, 0, hn_rxvf_set_task, &arg); 11345bdfd3fdSDexuan Cui 11355bdfd3fdSDexuan Cui for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 11365bdfd3fdSDexuan Cui rxr = &sc->hn_rx_ring[i]; 11375bdfd3fdSDexuan Cui 11385bdfd3fdSDexuan Cui if (i < sc->hn_rx_ring_inuse) { 1139962f0357SSepherosa Ziehau arg.rxr = rxr; 1140962f0357SSepherosa Ziehau arg.vf_ifp = vf_ifp; 11415bdfd3fdSDexuan Cui vmbus_chan_run_task(rxr->hn_chan, &task); 11425bdfd3fdSDexuan Cui } else { 1143962f0357SSepherosa Ziehau rxr->hn_rxvf_ifp = vf_ifp; 11445bdfd3fdSDexuan Cui } 11455bdfd3fdSDexuan Cui } 11465bdfd3fdSDexuan Cui } 11475bdfd3fdSDexuan Cui 1148962f0357SSepherosa Ziehau static bool 1149499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp) 1150499c3e17SSepherosa Ziehau { 1151499c3e17SSepherosa Ziehau const struct ifnet *hn_ifp; 1152499c3e17SSepherosa Ziehau 1153499c3e17SSepherosa Ziehau hn_ifp = sc->hn_ifp; 1154499c3e17SSepherosa Ziehau 1155499c3e17SSepherosa Ziehau if (ifp == hn_ifp) 1156499c3e17SSepherosa Ziehau return (false); 1157499c3e17SSepherosa Ziehau 1158499c3e17SSepherosa Ziehau if (ifp->if_alloctype != IFT_ETHER) 1159499c3e17SSepherosa Ziehau return (false); 1160499c3e17SSepherosa Ziehau 1161499c3e17SSepherosa Ziehau /* Ignore lagg/vlan interfaces */ 1162499c3e17SSepherosa Ziehau if (strcmp(ifp->if_dname, "lagg") == 0 || 1163499c3e17SSepherosa Ziehau strcmp(ifp->if_dname, "vlan") == 0) 1164499c3e17SSepherosa Ziehau return (false); 1165499c3e17SSepherosa Ziehau 1166499c3e17SSepherosa Ziehau if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0) 1167499c3e17SSepherosa Ziehau return (false); 1168499c3e17SSepherosa Ziehau 1169499c3e17SSepherosa Ziehau return (true); 1170499c3e17SSepherosa Ziehau } 1171499c3e17SSepherosa Ziehau 11725bdfd3fdSDexuan Cui static void 1173962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf) 11745bdfd3fdSDexuan Cui { 11755bdfd3fdSDexuan Cui struct ifnet *hn_ifp; 11765bdfd3fdSDexuan Cui 11775bdfd3fdSDexuan Cui HN_LOCK(sc); 11785bdfd3fdSDexuan Cui 11795bdfd3fdSDexuan Cui if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 11805bdfd3fdSDexuan Cui goto out; 11815bdfd3fdSDexuan Cui 1182499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1183499c3e17SSepherosa Ziehau goto out; 11845bdfd3fdSDexuan Cui hn_ifp = sc->hn_ifp; 11855bdfd3fdSDexuan Cui 1186962f0357SSepherosa Ziehau if (rxvf) { 1187962f0357SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_RXVF) 11885bdfd3fdSDexuan Cui goto out; 11895bdfd3fdSDexuan Cui 1190962f0357SSepherosa Ziehau sc->hn_flags |= HN_FLAG_RXVF; 11915bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 11925bdfd3fdSDexuan Cui } else { 1193962f0357SSepherosa Ziehau if (!(sc->hn_flags & HN_FLAG_RXVF)) 11945bdfd3fdSDexuan Cui goto out; 11955bdfd3fdSDexuan Cui 1196962f0357SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_RXVF; 1197499c3e17SSepherosa Ziehau if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 11985bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 11995bdfd3fdSDexuan Cui else 12005bdfd3fdSDexuan Cui hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE); 12015bdfd3fdSDexuan Cui } 12025bdfd3fdSDexuan Cui 12035bdfd3fdSDexuan Cui hn_nvs_set_datapath(sc, 12049c6cae24SSepherosa Ziehau rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH); 12055bdfd3fdSDexuan Cui 1206962f0357SSepherosa Ziehau hn_rxvf_set(sc, rxvf ? ifp : NULL); 12075bdfd3fdSDexuan Cui 1208962f0357SSepherosa Ziehau if (rxvf) { 1209642ec226SSepherosa Ziehau hn_vf_rss_fixup(sc, true); 12105bdfd3fdSDexuan Cui hn_suspend_mgmt(sc); 12115bdfd3fdSDexuan Cui sc->hn_link_flags &= 12125bdfd3fdSDexuan Cui ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG); 1213499c3e17SSepherosa Ziehau if_link_state_change(hn_ifp, LINK_STATE_DOWN); 12145bdfd3fdSDexuan Cui } else { 1215642ec226SSepherosa Ziehau hn_vf_rss_restore(sc); 12165bdfd3fdSDexuan Cui hn_resume_mgmt(sc); 12175bdfd3fdSDexuan Cui } 12185bdfd3fdSDexuan Cui 1219962f0357SSepherosa Ziehau devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname, 1220962f0357SSepherosa Ziehau rxvf ? "VF_UP" : "VF_DOWN", NULL); 122133408a34SDexuan Cui 1222962f0357SSepherosa Ziehau if (bootverbose) { 1223962f0357SSepherosa Ziehau if_printf(hn_ifp, "datapath is switched %s %s\n", 1224962f0357SSepherosa Ziehau rxvf ? "to" : "from", ifp->if_xname); 1225962f0357SSepherosa Ziehau } 12265bdfd3fdSDexuan Cui out: 12275bdfd3fdSDexuan Cui HN_UNLOCK(sc); 12285bdfd3fdSDexuan Cui } 12295bdfd3fdSDexuan Cui 12305bdfd3fdSDexuan Cui static void 12315bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event) 12325bdfd3fdSDexuan Cui { 1233962f0357SSepherosa Ziehau 12345bdfd3fdSDexuan Cui if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN) 12355bdfd3fdSDexuan Cui return; 1236962f0357SSepherosa Ziehau hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP); 12375bdfd3fdSDexuan Cui } 12385bdfd3fdSDexuan Cui 12395bdfd3fdSDexuan Cui static void 12405bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp) 12415bdfd3fdSDexuan Cui { 1242962f0357SSepherosa Ziehau 1243962f0357SSepherosa Ziehau hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP); 12445bdfd3fdSDexuan Cui } 12455bdfd3fdSDexuan Cui 12469c6cae24SSepherosa Ziehau static int 12479c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr) 12489c6cae24SSepherosa Ziehau { 12499c6cae24SSepherosa Ziehau struct ifnet *ifp, *vf_ifp; 12509c6cae24SSepherosa Ziehau uint64_t tmp; 12519c6cae24SSepherosa Ziehau int error; 12529c6cae24SSepherosa Ziehau 12539c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 12549c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 12559c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 12569c6cae24SSepherosa Ziehau 12579c6cae24SSepherosa Ziehau /* 12589c6cae24SSepherosa Ziehau * Fix up requested capabilities w/ supported capabilities, 12599c6cae24SSepherosa Ziehau * since the supported capabilities could have been changed. 12609c6cae24SSepherosa Ziehau */ 12619c6cae24SSepherosa Ziehau ifr->ifr_reqcap &= ifp->if_capabilities; 12629c6cae24SSepherosa Ziehau /* Pass SIOCSIFCAP to VF. */ 12639c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr); 12649c6cae24SSepherosa Ziehau 12659c6cae24SSepherosa Ziehau /* 12669c6cae24SSepherosa Ziehau * NOTE: 12679c6cae24SSepherosa Ziehau * The error will be propagated to the callers, however, it 12689c6cae24SSepherosa Ziehau * is _not_ useful here. 12699c6cae24SSepherosa Ziehau */ 12709c6cae24SSepherosa Ziehau 12719c6cae24SSepherosa Ziehau /* 12729c6cae24SSepherosa Ziehau * Merge VF's enabled capabilities. 12739c6cae24SSepherosa Ziehau */ 12749c6cae24SSepherosa Ziehau ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities; 12759c6cae24SSepherosa Ziehau 12769c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc); 12779c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 12789c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12799c6cae24SSepherosa Ziehau else 12809c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12819c6cae24SSepherosa Ziehau 12829c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc); 12839c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 12849c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12859c6cae24SSepherosa Ziehau else 12869c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12879c6cae24SSepherosa Ziehau 12889c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & CSUM_IP_TSO; 12899c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 12909c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12919c6cae24SSepherosa Ziehau else 12929c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12939c6cae24SSepherosa Ziehau 12949c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO; 12959c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 12969c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12979c6cae24SSepherosa Ziehau else 12989c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12999c6cae24SSepherosa Ziehau 13009c6cae24SSepherosa Ziehau return (error); 13019c6cae24SSepherosa Ziehau } 13029c6cae24SSepherosa Ziehau 13039c6cae24SSepherosa Ziehau static int 13049c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc) 13059c6cae24SSepherosa Ziehau { 13069c6cae24SSepherosa Ziehau struct ifnet *vf_ifp; 13079c6cae24SSepherosa Ziehau struct ifreq ifr; 13089c6cae24SSepherosa Ziehau 13099c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 13109c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 13119c6cae24SSepherosa Ziehau 13129c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 13139c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 13149c6cae24SSepherosa Ziehau ifr.ifr_flags = vf_ifp->if_flags & 0xffff; 13159c6cae24SSepherosa Ziehau ifr.ifr_flagshigh = vf_ifp->if_flags >> 16; 13169c6cae24SSepherosa Ziehau return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr)); 13179c6cae24SSepherosa Ziehau } 13189c6cae24SSepherosa Ziehau 13199c6cae24SSepherosa Ziehau static void 13209c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc) 13219c6cae24SSepherosa Ziehau { 13229c6cae24SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 13239c6cae24SSepherosa Ziehau int allmulti = 0; 13249c6cae24SSepherosa Ziehau 13259c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 13269c6cae24SSepherosa Ziehau 13279c6cae24SSepherosa Ziehau /* XXX vlan(4) style mcast addr maintenance */ 13289c6cae24SSepherosa Ziehau if (!TAILQ_EMPTY(&ifp->if_multiaddrs)) 13299c6cae24SSepherosa Ziehau allmulti = IFF_ALLMULTI; 13309c6cae24SSepherosa Ziehau 13319c6cae24SSepherosa Ziehau /* Always set the VF's if_flags */ 13329c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti; 13339c6cae24SSepherosa Ziehau } 13349c6cae24SSepherosa Ziehau 13359c6cae24SSepherosa Ziehau static void 13369c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m) 13379c6cae24SSepherosa Ziehau { 13389c6cae24SSepherosa Ziehau struct rm_priotracker pt; 13399c6cae24SSepherosa Ziehau struct ifnet *hn_ifp = NULL; 13409c6cae24SSepherosa Ziehau struct mbuf *mn; 13419c6cae24SSepherosa Ziehau 13429c6cae24SSepherosa Ziehau /* 13439c6cae24SSepherosa Ziehau * XXX racy, if hn(4) ever detached. 13449c6cae24SSepherosa Ziehau */ 13459c6cae24SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 13469c6cae24SSepherosa Ziehau if (vf_ifp->if_index < hn_vfmap_size) 13479c6cae24SSepherosa Ziehau hn_ifp = hn_vfmap[vf_ifp->if_index]; 13489c6cae24SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 13499c6cae24SSepherosa Ziehau 13509c6cae24SSepherosa Ziehau if (hn_ifp != NULL) { 13519c6cae24SSepherosa Ziehau for (mn = m; mn != NULL; mn = mn->m_nextpkt) { 13523bed4e54SSepherosa Ziehau /* 13533bed4e54SSepherosa Ziehau * Allow tapping on the VF. 13543bed4e54SSepherosa Ziehau */ 13559c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(vf_ifp, mn); 13563bed4e54SSepherosa Ziehau 13573bed4e54SSepherosa Ziehau /* 13583bed4e54SSepherosa Ziehau * Update VF stats. 13593bed4e54SSepherosa Ziehau */ 13603bed4e54SSepherosa Ziehau if ((vf_ifp->if_capenable & IFCAP_HWSTATS) == 0) { 13613bed4e54SSepherosa Ziehau if_inc_counter(vf_ifp, IFCOUNTER_IBYTES, 13623bed4e54SSepherosa Ziehau mn->m_pkthdr.len); 13633bed4e54SSepherosa Ziehau } 13643bed4e54SSepherosa Ziehau /* 13653bed4e54SSepherosa Ziehau * XXX IFCOUNTER_IMCAST 13663bed4e54SSepherosa Ziehau * This stat updating is kinda invasive, since it 13673bed4e54SSepherosa Ziehau * requires two checks on the mbuf: the length check 13683bed4e54SSepherosa Ziehau * and the ethernet header check. As of this write, 13693bed4e54SSepherosa Ziehau * all multicast packets go directly to hn(4), which 13703bed4e54SSepherosa Ziehau * makes imcast stat updating in the VF a try in vian. 13713bed4e54SSepherosa Ziehau */ 13723bed4e54SSepherosa Ziehau 13733bed4e54SSepherosa Ziehau /* 13743bed4e54SSepherosa Ziehau * Fix up rcvif and increase hn(4)'s ipackets. 13753bed4e54SSepherosa Ziehau */ 13769c6cae24SSepherosa Ziehau mn->m_pkthdr.rcvif = hn_ifp; 13779c6cae24SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1); 13789c6cae24SSepherosa Ziehau } 13793bed4e54SSepherosa Ziehau /* 13803bed4e54SSepherosa Ziehau * Go through hn(4)'s if_input. 13813bed4e54SSepherosa Ziehau */ 13829c6cae24SSepherosa Ziehau hn_ifp->if_input(hn_ifp, m); 13839c6cae24SSepherosa Ziehau } else { 13849c6cae24SSepherosa Ziehau /* 13859c6cae24SSepherosa Ziehau * In the middle of the transition; free this 13869c6cae24SSepherosa Ziehau * mbuf chain. 13879c6cae24SSepherosa Ziehau */ 13889c6cae24SSepherosa Ziehau while (m != NULL) { 13899c6cae24SSepherosa Ziehau mn = m->m_nextpkt; 13909c6cae24SSepherosa Ziehau m->m_nextpkt = NULL; 13919c6cae24SSepherosa Ziehau m_freem(m); 13929c6cae24SSepherosa Ziehau m = mn; 13939c6cae24SSepherosa Ziehau } 13949c6cae24SSepherosa Ziehau } 13959c6cae24SSepherosa Ziehau } 13969c6cae24SSepherosa Ziehau 13979c6cae24SSepherosa Ziehau static void 13989c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc) 13999c6cae24SSepherosa Ziehau { 14009c6cae24SSepherosa Ziehau struct ifnet *ifp; 14019c6cae24SSepherosa Ziehau 14029c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 14039c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 14049c6cae24SSepherosa Ziehau 14059c6cae24SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu); 14069c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099 14079c6cae24SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp)) 14089c6cae24SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp)); 14099c6cae24SSepherosa Ziehau #endif 14109c6cae24SSepherosa Ziehau } 14119c6cae24SSepherosa Ziehau 1412642ec226SSepherosa Ziehau static uint32_t 1413642ec226SSepherosa Ziehau hn_rss_type_fromndis(uint32_t rss_hash) 1414642ec226SSepherosa Ziehau { 1415642ec226SSepherosa Ziehau uint32_t types = 0; 1416642ec226SSepherosa Ziehau 1417642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_IPV4) 1418642ec226SSepherosa Ziehau types |= RSS_TYPE_IPV4; 1419642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_TCP_IPV4) 1420642ec226SSepherosa Ziehau types |= RSS_TYPE_TCP_IPV4; 1421642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_IPV6) 1422642ec226SSepherosa Ziehau types |= RSS_TYPE_IPV6; 1423642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_IPV6_EX) 1424642ec226SSepherosa Ziehau types |= RSS_TYPE_IPV6_EX; 1425642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_TCP_IPV6) 1426642ec226SSepherosa Ziehau types |= RSS_TYPE_TCP_IPV6; 1427642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_TCP_IPV6_EX) 1428642ec226SSepherosa Ziehau types |= RSS_TYPE_TCP_IPV6_EX; 1429642ec226SSepherosa Ziehau return (types); 1430642ec226SSepherosa Ziehau } 1431642ec226SSepherosa Ziehau 1432642ec226SSepherosa Ziehau static uint32_t 1433642ec226SSepherosa Ziehau hn_rss_type_tondis(uint32_t types) 1434642ec226SSepherosa Ziehau { 1435642ec226SSepherosa Ziehau uint32_t rss_hash = 0; 1436642ec226SSepherosa Ziehau 1437642ec226SSepherosa Ziehau KASSERT((types & 1438642ec226SSepherosa Ziehau (RSS_TYPE_UDP_IPV4 | RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0, 1439642ec226SSepherosa Ziehau ("UDP4, UDP6 and UDP6EX are not supported")); 1440642ec226SSepherosa Ziehau 1441642ec226SSepherosa Ziehau if (types & RSS_TYPE_IPV4) 1442642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_IPV4; 1443642ec226SSepherosa Ziehau if (types & RSS_TYPE_TCP_IPV4) 1444642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_TCP_IPV4; 1445642ec226SSepherosa Ziehau if (types & RSS_TYPE_IPV6) 1446642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_IPV6; 1447642ec226SSepherosa Ziehau if (types & RSS_TYPE_IPV6_EX) 1448642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_IPV6_EX; 1449642ec226SSepherosa Ziehau if (types & RSS_TYPE_TCP_IPV6) 1450642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_TCP_IPV6; 1451642ec226SSepherosa Ziehau if (types & RSS_TYPE_TCP_IPV6_EX) 1452642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_TCP_IPV6_EX; 1453642ec226SSepherosa Ziehau return (rss_hash); 1454642ec226SSepherosa Ziehau } 1455642ec226SSepherosa Ziehau 1456642ec226SSepherosa Ziehau static void 1457642ec226SSepherosa Ziehau hn_rss_mbuf_hash(struct hn_softc *sc, uint32_t mbuf_hash) 1458642ec226SSepherosa Ziehau { 1459642ec226SSepherosa Ziehau int i; 1460642ec226SSepherosa Ziehau 1461642ec226SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1462642ec226SSepherosa Ziehau 1463642ec226SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 1464642ec226SSepherosa Ziehau sc->hn_rx_ring[i].hn_mbuf_hash = mbuf_hash; 1465642ec226SSepherosa Ziehau } 1466642ec226SSepherosa Ziehau 1467642ec226SSepherosa Ziehau static void 1468642ec226SSepherosa Ziehau hn_vf_rss_fixup(struct hn_softc *sc, bool reconf) 1469642ec226SSepherosa Ziehau { 1470642ec226SSepherosa Ziehau struct ifnet *ifp, *vf_ifp; 1471642ec226SSepherosa Ziehau struct ifrsshash ifrh; 1472642ec226SSepherosa Ziehau struct ifrsskey ifrk; 1473642ec226SSepherosa Ziehau int error; 1474642ec226SSepherosa Ziehau uint32_t my_types, diff_types, mbuf_types = 0; 1475642ec226SSepherosa Ziehau 1476642ec226SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1477642ec226SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 1478642ec226SSepherosa Ziehau ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname)); 1479642ec226SSepherosa Ziehau 1480642ec226SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 1481642ec226SSepherosa Ziehau /* No RSS on synthetic parts; done. */ 1482642ec226SSepherosa Ziehau return; 1483642ec226SSepherosa Ziehau } 1484642ec226SSepherosa Ziehau if ((sc->hn_rss_hcap & NDIS_HASH_FUNCTION_TOEPLITZ) == 0) { 1485642ec226SSepherosa Ziehau /* Synthetic parts do not support Toeplitz; done. */ 1486642ec226SSepherosa Ziehau return; 1487642ec226SSepherosa Ziehau } 1488642ec226SSepherosa Ziehau 1489642ec226SSepherosa Ziehau ifp = sc->hn_ifp; 1490642ec226SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 1491642ec226SSepherosa Ziehau 1492642ec226SSepherosa Ziehau /* 1493642ec226SSepherosa Ziehau * Extract VF's RSS key. Only 40 bytes key for Toeplitz is 1494642ec226SSepherosa Ziehau * supported. 1495642ec226SSepherosa Ziehau */ 1496642ec226SSepherosa Ziehau memset(&ifrk, 0, sizeof(ifrk)); 1497642ec226SSepherosa Ziehau strlcpy(ifrk.ifrk_name, vf_ifp->if_xname, sizeof(ifrk.ifrk_name)); 1498642ec226SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSKEY, (caddr_t)&ifrk); 1499642ec226SSepherosa Ziehau if (error) { 1500642ec226SSepherosa Ziehau if_printf(ifp, "%s SIOCGRSSKEY failed: %d\n", 1501642ec226SSepherosa Ziehau vf_ifp->if_xname, error); 1502642ec226SSepherosa Ziehau goto done; 1503642ec226SSepherosa Ziehau } 1504642ec226SSepherosa Ziehau if (ifrk.ifrk_func != RSS_FUNC_TOEPLITZ) { 1505642ec226SSepherosa Ziehau if_printf(ifp, "%s RSS function %u is not Toeplitz\n", 1506642ec226SSepherosa Ziehau vf_ifp->if_xname, ifrk.ifrk_func); 1507642ec226SSepherosa Ziehau goto done; 1508642ec226SSepherosa Ziehau } 1509642ec226SSepherosa Ziehau if (ifrk.ifrk_keylen != NDIS_HASH_KEYSIZE_TOEPLITZ) { 1510642ec226SSepherosa Ziehau if_printf(ifp, "%s invalid RSS Toeplitz key length %d\n", 1511642ec226SSepherosa Ziehau vf_ifp->if_xname, ifrk.ifrk_keylen); 1512642ec226SSepherosa Ziehau goto done; 1513642ec226SSepherosa Ziehau } 1514642ec226SSepherosa Ziehau 1515642ec226SSepherosa Ziehau /* 1516642ec226SSepherosa Ziehau * Extract VF's RSS hash. Only Toeplitz is supported. 1517642ec226SSepherosa Ziehau */ 1518642ec226SSepherosa Ziehau memset(&ifrh, 0, sizeof(ifrh)); 1519642ec226SSepherosa Ziehau strlcpy(ifrh.ifrh_name, vf_ifp->if_xname, sizeof(ifrh.ifrh_name)); 1520642ec226SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSHASH, (caddr_t)&ifrh); 1521642ec226SSepherosa Ziehau if (error) { 1522642ec226SSepherosa Ziehau if_printf(ifp, "%s SIOCGRSSHASH failed: %d\n", 1523642ec226SSepherosa Ziehau vf_ifp->if_xname, error); 1524642ec226SSepherosa Ziehau goto done; 1525642ec226SSepherosa Ziehau } 1526642ec226SSepherosa Ziehau if (ifrh.ifrh_func != RSS_FUNC_TOEPLITZ) { 1527642ec226SSepherosa Ziehau if_printf(ifp, "%s RSS function %u is not Toeplitz\n", 1528642ec226SSepherosa Ziehau vf_ifp->if_xname, ifrh.ifrh_func); 1529642ec226SSepherosa Ziehau goto done; 1530642ec226SSepherosa Ziehau } 1531642ec226SSepherosa Ziehau 1532642ec226SSepherosa Ziehau my_types = hn_rss_type_fromndis(sc->hn_rss_hcap); 1533642ec226SSepherosa Ziehau if ((ifrh.ifrh_types & my_types) == 0) { 1534642ec226SSepherosa Ziehau /* This disables RSS; ignore it then */ 1535642ec226SSepherosa Ziehau if_printf(ifp, "%s intersection of RSS types failed. " 1536642ec226SSepherosa Ziehau "VF %#x, mine %#x\n", vf_ifp->if_xname, 1537642ec226SSepherosa Ziehau ifrh.ifrh_types, my_types); 1538642ec226SSepherosa Ziehau goto done; 1539642ec226SSepherosa Ziehau } 1540642ec226SSepherosa Ziehau 1541642ec226SSepherosa Ziehau diff_types = my_types ^ ifrh.ifrh_types; 1542642ec226SSepherosa Ziehau my_types &= ifrh.ifrh_types; 1543642ec226SSepherosa Ziehau mbuf_types = my_types; 1544642ec226SSepherosa Ziehau 1545642ec226SSepherosa Ziehau /* 1546642ec226SSepherosa Ziehau * Detect RSS hash value/type confliction. 1547642ec226SSepherosa Ziehau * 1548642ec226SSepherosa Ziehau * NOTE: 1549642ec226SSepherosa Ziehau * We don't disable the hash type, but stop delivery the hash 1550642ec226SSepherosa Ziehau * value/type through mbufs on RX path. 1551642ec226SSepherosa Ziehau */ 1552642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_IPV4) && 1553642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & 1554642ec226SSepherosa Ziehau (RSS_TYPE_TCP_IPV4 | RSS_TYPE_UDP_IPV4))) { 1555642ec226SSepherosa Ziehau /* Conflict; disable IPV4 hash type/value delivery. */ 1556642ec226SSepherosa Ziehau if_printf(ifp, "disable IPV4 mbuf hash delivery\n"); 1557642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_IPV4; 1558642ec226SSepherosa Ziehau } 1559642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_IPV6) && 1560642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & 1561642ec226SSepherosa Ziehau (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 | 1562642ec226SSepherosa Ziehau RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX | 1563642ec226SSepherosa Ziehau RSS_TYPE_IPV6_EX))) { 1564642ec226SSepherosa Ziehau /* Conflict; disable IPV6 hash type/value delivery. */ 1565642ec226SSepherosa Ziehau if_printf(ifp, "disable IPV6 mbuf hash delivery\n"); 1566642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_IPV6; 1567642ec226SSepherosa Ziehau } 1568642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_IPV6_EX) && 1569642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & 1570642ec226SSepherosa Ziehau (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 | 1571642ec226SSepherosa Ziehau RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX | 1572642ec226SSepherosa Ziehau RSS_TYPE_IPV6))) { 1573642ec226SSepherosa Ziehau /* Conflict; disable IPV6_EX hash type/value delivery. */ 1574642ec226SSepherosa Ziehau if_printf(ifp, "disable IPV6_EX mbuf hash delivery\n"); 1575642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_IPV6_EX; 1576642ec226SSepherosa Ziehau } 1577642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_TCP_IPV6) && 1578642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6_EX)) { 1579642ec226SSepherosa Ziehau /* Conflict; disable TCP_IPV6 hash type/value delivery. */ 1580642ec226SSepherosa Ziehau if_printf(ifp, "disable TCP_IPV6 mbuf hash delivery\n"); 1581642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_TCP_IPV6; 1582642ec226SSepherosa Ziehau } 1583642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_TCP_IPV6_EX) && 1584642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6)) { 1585642ec226SSepherosa Ziehau /* Conflict; disable TCP_IPV6_EX hash type/value delivery. */ 1586642ec226SSepherosa Ziehau if_printf(ifp, "disable TCP_IPV6_EX mbuf hash delivery\n"); 1587642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_TCP_IPV6_EX; 1588642ec226SSepherosa Ziehau } 1589642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_UDP_IPV6) && 1590642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6_EX)) { 1591642ec226SSepherosa Ziehau /* Conflict; disable UDP_IPV6 hash type/value delivery. */ 1592642ec226SSepherosa Ziehau if_printf(ifp, "disable UDP_IPV6 mbuf hash delivery\n"); 1593642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_UDP_IPV6; 1594642ec226SSepherosa Ziehau } 1595642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_UDP_IPV6_EX) && 1596642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6)) { 1597642ec226SSepherosa Ziehau /* Conflict; disable UDP_IPV6_EX hash type/value delivery. */ 1598642ec226SSepherosa Ziehau if_printf(ifp, "disable UDP_IPV6_EX mbuf hash delivery\n"); 1599642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_UDP_IPV6_EX; 1600642ec226SSepherosa Ziehau } 1601642ec226SSepherosa Ziehau 1602642ec226SSepherosa Ziehau /* 1603642ec226SSepherosa Ziehau * Indirect table does not matter. 1604642ec226SSepherosa Ziehau */ 1605642ec226SSepherosa Ziehau 1606642ec226SSepherosa Ziehau sc->hn_rss_hash = (sc->hn_rss_hcap & NDIS_HASH_FUNCTION_MASK) | 1607642ec226SSepherosa Ziehau hn_rss_type_tondis(my_types); 1608642ec226SSepherosa Ziehau memcpy(sc->hn_rss.rss_key, ifrk.ifrk_key, sizeof(sc->hn_rss.rss_key)); 1609642ec226SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 1610642ec226SSepherosa Ziehau 1611642ec226SSepherosa Ziehau if (reconf) { 1612642ec226SSepherosa Ziehau error = hn_rss_reconfig(sc); 1613642ec226SSepherosa Ziehau if (error) { 1614642ec226SSepherosa Ziehau /* XXX roll-back? */ 1615642ec226SSepherosa Ziehau if_printf(ifp, "hn_rss_reconfig failed: %d\n", error); 1616642ec226SSepherosa Ziehau /* XXX keep going. */ 1617642ec226SSepherosa Ziehau } 1618642ec226SSepherosa Ziehau } 1619642ec226SSepherosa Ziehau done: 1620642ec226SSepherosa Ziehau /* Hash deliverability for mbufs. */ 1621642ec226SSepherosa Ziehau hn_rss_mbuf_hash(sc, hn_rss_type_tondis(mbuf_types)); 1622642ec226SSepherosa Ziehau } 1623642ec226SSepherosa Ziehau 1624642ec226SSepherosa Ziehau static void 1625642ec226SSepherosa Ziehau hn_vf_rss_restore(struct hn_softc *sc) 1626642ec226SSepherosa Ziehau { 1627642ec226SSepherosa Ziehau 1628642ec226SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1629642ec226SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 1630642ec226SSepherosa Ziehau ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname)); 1631642ec226SSepherosa Ziehau 1632642ec226SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) 1633642ec226SSepherosa Ziehau goto done; 1634642ec226SSepherosa Ziehau 1635642ec226SSepherosa Ziehau /* 1636642ec226SSepherosa Ziehau * Restore hash types. Key does _not_ matter. 1637642ec226SSepherosa Ziehau */ 1638642ec226SSepherosa Ziehau if (sc->hn_rss_hash != sc->hn_rss_hcap) { 1639642ec226SSepherosa Ziehau int error; 1640642ec226SSepherosa Ziehau 1641642ec226SSepherosa Ziehau sc->hn_rss_hash = sc->hn_rss_hcap; 1642642ec226SSepherosa Ziehau error = hn_rss_reconfig(sc); 1643642ec226SSepherosa Ziehau if (error) { 1644642ec226SSepherosa Ziehau if_printf(sc->hn_ifp, "hn_rss_reconfig failed: %d\n", 1645642ec226SSepherosa Ziehau error); 1646642ec226SSepherosa Ziehau /* XXX keep going. */ 1647642ec226SSepherosa Ziehau } 1648642ec226SSepherosa Ziehau } 1649642ec226SSepherosa Ziehau done: 1650642ec226SSepherosa Ziehau /* Hash deliverability for mbufs. */ 1651642ec226SSepherosa Ziehau hn_rss_mbuf_hash(sc, NDIS_HASH_ALL); 1652642ec226SSepherosa Ziehau } 1653642ec226SSepherosa Ziehau 16549c6cae24SSepherosa Ziehau static void 16559c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc) 16569c6cae24SSepherosa Ziehau { 16579c6cae24SSepherosa Ziehau struct ifnet *ifp, *vf_ifp; 16589c6cae24SSepherosa Ziehau struct ifreq ifr; 16599c6cae24SSepherosa Ziehau 16609c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 16619c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 16629c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 16639c6cae24SSepherosa Ziehau 16649c6cae24SSepherosa Ziehau /* 16659c6cae24SSepherosa Ziehau * Mark the VF ready. 16669c6cae24SSepherosa Ziehau */ 16679c6cae24SSepherosa Ziehau sc->hn_vf_rdytick = 0; 16689c6cae24SSepherosa Ziehau 16699c6cae24SSepherosa Ziehau /* 16709c6cae24SSepherosa Ziehau * Save information for restoration. 16719c6cae24SSepherosa Ziehau */ 16729c6cae24SSepherosa Ziehau sc->hn_saved_caps = ifp->if_capabilities; 16739c6cae24SSepherosa Ziehau sc->hn_saved_tsomax = ifp->if_hw_tsomax; 16749c6cae24SSepherosa Ziehau sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount; 16759c6cae24SSepherosa Ziehau sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize; 16769c6cae24SSepherosa Ziehau 16779c6cae24SSepherosa Ziehau /* 16789c6cae24SSepherosa Ziehau * Intersect supported/enabled capabilities. 16799c6cae24SSepherosa Ziehau * 16809c6cae24SSepherosa Ziehau * NOTE: 16819c6cae24SSepherosa Ziehau * if_hwassist is not changed here. 16829c6cae24SSepherosa Ziehau */ 16839c6cae24SSepherosa Ziehau ifp->if_capabilities &= vf_ifp->if_capabilities; 16849c6cae24SSepherosa Ziehau ifp->if_capenable &= ifp->if_capabilities; 16859c6cae24SSepherosa Ziehau 16869c6cae24SSepherosa Ziehau /* 16879c6cae24SSepherosa Ziehau * Fix TSO settings. 16889c6cae24SSepherosa Ziehau */ 16899c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax) 16909c6cae24SSepherosa Ziehau ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax; 16919c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount) 16929c6cae24SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount; 16939c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize) 16949c6cae24SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize; 16959c6cae24SSepherosa Ziehau 16969c6cae24SSepherosa Ziehau /* 16979c6cae24SSepherosa Ziehau * Change VF's enabled capabilities. 16989c6cae24SSepherosa Ziehau */ 16999c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 17009c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 17019c6cae24SSepherosa Ziehau ifr.ifr_reqcap = ifp->if_capenable; 17029c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(sc, &ifr); 17039c6cae24SSepherosa Ziehau 17049c6cae24SSepherosa Ziehau if (ifp->if_mtu != ETHERMTU) { 17059c6cae24SSepherosa Ziehau int error; 17069c6cae24SSepherosa Ziehau 17079c6cae24SSepherosa Ziehau /* 17089c6cae24SSepherosa Ziehau * Change VF's MTU. 17099c6cae24SSepherosa Ziehau */ 17109c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 17119c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 17129c6cae24SSepherosa Ziehau ifr.ifr_mtu = ifp->if_mtu; 17139c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr); 17149c6cae24SSepherosa Ziehau if (error) { 17159c6cae24SSepherosa Ziehau if_printf(ifp, "%s SIOCSIFMTU %u failed\n", 17169c6cae24SSepherosa Ziehau vf_ifp->if_xname, ifp->if_mtu); 17179c6cae24SSepherosa Ziehau if (ifp->if_mtu > ETHERMTU) { 17189c6cae24SSepherosa Ziehau if_printf(ifp, "change MTU to %d\n", ETHERMTU); 17199c6cae24SSepherosa Ziehau 17209c6cae24SSepherosa Ziehau /* 17219c6cae24SSepherosa Ziehau * XXX 17229c6cae24SSepherosa Ziehau * No need to adjust the synthetic parts' MTU; 17239c6cae24SSepherosa Ziehau * failure of the adjustment will cause us 17249c6cae24SSepherosa Ziehau * infinite headache. 17259c6cae24SSepherosa Ziehau */ 17269c6cae24SSepherosa Ziehau ifp->if_mtu = ETHERMTU; 17279c6cae24SSepherosa Ziehau hn_mtu_change_fixup(sc); 17289c6cae24SSepherosa Ziehau } 17299c6cae24SSepherosa Ziehau } 17309c6cae24SSepherosa Ziehau } 17319c6cae24SSepherosa Ziehau } 17329c6cae24SSepherosa Ziehau 17339c6cae24SSepherosa Ziehau static bool 17349c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc) 17359c6cae24SSepherosa Ziehau { 17369c6cae24SSepherosa Ziehau 17379c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 17389c6cae24SSepherosa Ziehau 17399c6cae24SSepherosa Ziehau if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL) 17409c6cae24SSepherosa Ziehau return (false); 17419c6cae24SSepherosa Ziehau 17429c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick == 0) 17439c6cae24SSepherosa Ziehau return (true); 17449c6cae24SSepherosa Ziehau 17459c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick > ticks) 17469c6cae24SSepherosa Ziehau return (false); 17479c6cae24SSepherosa Ziehau 17489c6cae24SSepherosa Ziehau /* Mark VF as ready. */ 17499c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(sc); 17509c6cae24SSepherosa Ziehau return (true); 17519c6cae24SSepherosa Ziehau } 17529c6cae24SSepherosa Ziehau 17539c6cae24SSepherosa Ziehau static void 1754a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc) 1755a97fff19SSepherosa Ziehau { 1756a97fff19SSepherosa Ziehau int i; 1757a97fff19SSepherosa Ziehau 1758a97fff19SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1759a97fff19SSepherosa Ziehau 1760a97fff19SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ 1761a97fff19SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 1762a97fff19SSepherosa Ziehau sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED; 1763a97fff19SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 1764a97fff19SSepherosa Ziehau 1765a97fff19SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 1766a97fff19SSepherosa Ziehau sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF; 1767a97fff19SSepherosa Ziehau } 1768a97fff19SSepherosa Ziehau 1769a97fff19SSepherosa Ziehau static void 1770a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf) 1771a97fff19SSepherosa Ziehau { 1772a97fff19SSepherosa Ziehau int i; 1773a97fff19SSepherosa Ziehau 1774a97fff19SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1775a97fff19SSepherosa Ziehau 1776a97fff19SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ 1777a97fff19SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 1778a97fff19SSepherosa Ziehau sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED; 1779a97fff19SSepherosa Ziehau if (clear_vf) 1780a97fff19SSepherosa Ziehau sc->hn_vf_ifp = NULL; 1781a97fff19SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 1782a97fff19SSepherosa Ziehau 1783a97fff19SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 1784a97fff19SSepherosa Ziehau sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF; 1785a97fff19SSepherosa Ziehau } 1786a97fff19SSepherosa Ziehau 1787a97fff19SSepherosa Ziehau static void 17889c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc) 17899c6cae24SSepherosa Ziehau { 17909c6cae24SSepherosa Ziehau int error; 17919c6cae24SSepherosa Ziehau 17929c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 17939c6cae24SSepherosa Ziehau 17949c6cae24SSepherosa Ziehau KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0, 17959c6cae24SSepherosa Ziehau ("%s: transparent VF was enabled", sc->hn_ifp->if_xname)); 17969c6cae24SSepherosa Ziehau 17979c6cae24SSepherosa Ziehau if (bootverbose) { 17989c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "try bringing up %s\n", 17999c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 18009c6cae24SSepherosa Ziehau } 18019c6cae24SSepherosa Ziehau 18029c6cae24SSepherosa Ziehau /* 18039c6cae24SSepherosa Ziehau * Bring the VF up. 18049c6cae24SSepherosa Ziehau */ 18059c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 18069c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags |= IFF_UP; 18079c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 18089c6cae24SSepherosa Ziehau if (error) { 18099c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "bringing up %s failed: %d\n", 18109c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname, error); 18119c6cae24SSepherosa Ziehau return; 18129c6cae24SSepherosa Ziehau } 18139c6cae24SSepherosa Ziehau 18149c6cae24SSepherosa Ziehau /* 18159c6cae24SSepherosa Ziehau * NOTE: 18169c6cae24SSepherosa Ziehau * Datapath setting must happen _after_ bringing the VF up. 18179c6cae24SSepherosa Ziehau */ 18189c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF); 18199c6cae24SSepherosa Ziehau 1820642ec226SSepherosa Ziehau /* 1821642ec226SSepherosa Ziehau * NOTE: 1822642ec226SSepherosa Ziehau * Fixup RSS related bits _after_ the VF is brought up, since 1823642ec226SSepherosa Ziehau * many VFs generate RSS key during it's initialization. 1824642ec226SSepherosa Ziehau */ 1825642ec226SSepherosa Ziehau hn_vf_rss_fixup(sc, true); 1826642ec226SSepherosa Ziehau 1827a97fff19SSepherosa Ziehau /* Mark transparent mode VF as enabled. */ 1828a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(sc); 18299c6cae24SSepherosa Ziehau } 18309c6cae24SSepherosa Ziehau 18319c6cae24SSepherosa Ziehau static void 18329c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused) 18339c6cae24SSepherosa Ziehau { 18349c6cae24SSepherosa Ziehau struct hn_softc *sc = xsc; 18359c6cae24SSepherosa Ziehau 18369c6cae24SSepherosa Ziehau HN_LOCK(sc); 18379c6cae24SSepherosa Ziehau 18389c6cae24SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 18399c6cae24SSepherosa Ziehau goto done; 18409c6cae24SSepherosa Ziehau if (sc->hn_vf_ifp == NULL) 18419c6cae24SSepherosa Ziehau goto done; 18429c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 18439c6cae24SSepherosa Ziehau goto done; 18449c6cae24SSepherosa Ziehau 18459c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick != 0) { 18469c6cae24SSepherosa Ziehau /* Mark VF as ready. */ 18479c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(sc); 18489c6cae24SSepherosa Ziehau } 18499c6cae24SSepherosa Ziehau 18509c6cae24SSepherosa Ziehau if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) { 18519c6cae24SSepherosa Ziehau /* 18529c6cae24SSepherosa Ziehau * Delayed VF initialization. 18539c6cae24SSepherosa Ziehau */ 18549c6cae24SSepherosa Ziehau if (bootverbose) { 18559c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "delayed initialize %s\n", 18569c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 18579c6cae24SSepherosa Ziehau } 18589c6cae24SSepherosa Ziehau hn_xpnt_vf_init(sc); 18599c6cae24SSepherosa Ziehau } 18609c6cae24SSepherosa Ziehau done: 18619c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 18629c6cae24SSepherosa Ziehau } 18639c6cae24SSepherosa Ziehau 1864499c3e17SSepherosa Ziehau static void 1865499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp) 1866499c3e17SSepherosa Ziehau { 1867499c3e17SSepherosa Ziehau struct hn_softc *sc = xsc; 1868499c3e17SSepherosa Ziehau 1869499c3e17SSepherosa Ziehau HN_LOCK(sc); 1870499c3e17SSepherosa Ziehau 1871499c3e17SSepherosa Ziehau if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 1872499c3e17SSepherosa Ziehau goto done; 1873499c3e17SSepherosa Ziehau 1874499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1875499c3e17SSepherosa Ziehau goto done; 1876499c3e17SSepherosa Ziehau 1877499c3e17SSepherosa Ziehau if (sc->hn_vf_ifp != NULL) { 1878499c3e17SSepherosa Ziehau if_printf(sc->hn_ifp, "%s was attached as VF\n", 1879499c3e17SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 1880499c3e17SSepherosa Ziehau goto done; 1881499c3e17SSepherosa Ziehau } 1882499c3e17SSepherosa Ziehau 18839c6cae24SSepherosa Ziehau if (hn_xpnt_vf && ifp->if_start != NULL) { 18849c6cae24SSepherosa Ziehau /* 18859c6cae24SSepherosa Ziehau * ifnet.if_start is _not_ supported by transparent 18869c6cae24SSepherosa Ziehau * mode VF; mainly due to the IFF_DRV_OACTIVE flag. 18879c6cae24SSepherosa Ziehau */ 18889c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported " 18899c6cae24SSepherosa Ziehau "in transparent VF mode.\n", ifp->if_xname); 18909c6cae24SSepherosa Ziehau goto done; 18919c6cae24SSepherosa Ziehau } 18929c6cae24SSepherosa Ziehau 1893499c3e17SSepherosa Ziehau rm_wlock(&hn_vfmap_lock); 1894499c3e17SSepherosa Ziehau 1895499c3e17SSepherosa Ziehau if (ifp->if_index >= hn_vfmap_size) { 1896499c3e17SSepherosa Ziehau struct ifnet **newmap; 1897499c3e17SSepherosa Ziehau int newsize; 1898499c3e17SSepherosa Ziehau 1899499c3e17SSepherosa Ziehau newsize = ifp->if_index + HN_VFMAP_SIZE_DEF; 1900499c3e17SSepherosa Ziehau newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF, 1901499c3e17SSepherosa Ziehau M_WAITOK | M_ZERO); 1902499c3e17SSepherosa Ziehau 1903499c3e17SSepherosa Ziehau memcpy(newmap, hn_vfmap, 1904499c3e17SSepherosa Ziehau sizeof(struct ifnet *) * hn_vfmap_size); 1905499c3e17SSepherosa Ziehau free(hn_vfmap, M_DEVBUF); 1906499c3e17SSepherosa Ziehau hn_vfmap = newmap; 1907499c3e17SSepherosa Ziehau hn_vfmap_size = newsize; 1908499c3e17SSepherosa Ziehau } 1909499c3e17SSepherosa Ziehau KASSERT(hn_vfmap[ifp->if_index] == NULL, 1910499c3e17SSepherosa Ziehau ("%s: ifindex %d was mapped to %s", 1911499c3e17SSepherosa Ziehau ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname)); 1912499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index] = sc->hn_ifp; 1913499c3e17SSepherosa Ziehau 1914499c3e17SSepherosa Ziehau rm_wunlock(&hn_vfmap_lock); 1915499c3e17SSepherosa Ziehau 19169c6cae24SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ 19179c6cae24SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 19189c6cae24SSepherosa Ziehau KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0, 19199c6cae24SSepherosa Ziehau ("%s: transparent VF was enabled", sc->hn_ifp->if_xname)); 1920499c3e17SSepherosa Ziehau sc->hn_vf_ifp = ifp; 19219c6cae24SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 19229c6cae24SSepherosa Ziehau 19239c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 19249c6cae24SSepherosa Ziehau int wait_ticks; 19259c6cae24SSepherosa Ziehau 19269c6cae24SSepherosa Ziehau /* 19279c6cae24SSepherosa Ziehau * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp. 19289c6cae24SSepherosa Ziehau * Save vf_ifp's current if_input for later restoration. 19299c6cae24SSepherosa Ziehau */ 19309c6cae24SSepherosa Ziehau sc->hn_vf_input = ifp->if_input; 19319c6cae24SSepherosa Ziehau ifp->if_input = hn_xpnt_vf_input; 19329c6cae24SSepherosa Ziehau 19339c6cae24SSepherosa Ziehau /* 19349c6cae24SSepherosa Ziehau * Stop link status management; use the VF's. 19359c6cae24SSepherosa Ziehau */ 19369c6cae24SSepherosa Ziehau hn_suspend_mgmt(sc); 19379c6cae24SSepherosa Ziehau 19389c6cae24SSepherosa Ziehau /* 19399c6cae24SSepherosa Ziehau * Give VF sometime to complete its attach routing. 19409c6cae24SSepherosa Ziehau */ 19419c6cae24SSepherosa Ziehau wait_ticks = hn_xpnt_vf_attwait * hz; 19429c6cae24SSepherosa Ziehau sc->hn_vf_rdytick = ticks + wait_ticks; 19439c6cae24SSepherosa Ziehau 19449c6cae24SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init, 19459c6cae24SSepherosa Ziehau wait_ticks); 19469c6cae24SSepherosa Ziehau } 1947499c3e17SSepherosa Ziehau done: 1948499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 1949499c3e17SSepherosa Ziehau } 1950499c3e17SSepherosa Ziehau 1951499c3e17SSepherosa Ziehau static void 1952499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp) 1953499c3e17SSepherosa Ziehau { 1954499c3e17SSepherosa Ziehau struct hn_softc *sc = xsc; 1955499c3e17SSepherosa Ziehau 1956499c3e17SSepherosa Ziehau HN_LOCK(sc); 1957499c3e17SSepherosa Ziehau 1958499c3e17SSepherosa Ziehau if (sc->hn_vf_ifp == NULL) 1959499c3e17SSepherosa Ziehau goto done; 1960499c3e17SSepherosa Ziehau 1961499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1962499c3e17SSepherosa Ziehau goto done; 1963499c3e17SSepherosa Ziehau 19649c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 19659c6cae24SSepherosa Ziehau /* 19669c6cae24SSepherosa Ziehau * Make sure that the delayed initialization is not running. 19679c6cae24SSepherosa Ziehau * 19689c6cae24SSepherosa Ziehau * NOTE: 19699c6cae24SSepherosa Ziehau * - This lock _must_ be released, since the hn_vf_init task 19709c6cae24SSepherosa Ziehau * will try holding this lock. 19719c6cae24SSepherosa Ziehau * - It is safe to release this lock here, since the 19729c6cae24SSepherosa Ziehau * hn_ifnet_attevent() is interlocked by the hn_vf_ifp. 19739c6cae24SSepherosa Ziehau * 19749c6cae24SSepherosa Ziehau * XXX racy, if hn(4) ever detached. 19759c6cae24SSepherosa Ziehau */ 19769c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 19779c6cae24SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init); 19789c6cae24SSepherosa Ziehau HN_LOCK(sc); 19799c6cae24SSepherosa Ziehau 19809c6cae24SSepherosa Ziehau KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved", 19819c6cae24SSepherosa Ziehau sc->hn_ifp->if_xname)); 19829c6cae24SSepherosa Ziehau ifp->if_input = sc->hn_vf_input; 19839c6cae24SSepherosa Ziehau sc->hn_vf_input = NULL; 19849c6cae24SSepherosa Ziehau 1985642ec226SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) && 1986642ec226SSepherosa Ziehau (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) 19879c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH); 19889c6cae24SSepherosa Ziehau 19899c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick == 0) { 19909c6cae24SSepherosa Ziehau /* 19919c6cae24SSepherosa Ziehau * The VF was ready; restore some settings. 19929c6cae24SSepherosa Ziehau */ 19939c6cae24SSepherosa Ziehau sc->hn_ifp->if_capabilities = sc->hn_saved_caps; 19949c6cae24SSepherosa Ziehau /* 19959c6cae24SSepherosa Ziehau * NOTE: 19969c6cae24SSepherosa Ziehau * There is _no_ need to fixup if_capenable and 19979c6cae24SSepherosa Ziehau * if_hwassist, since the if_capabilities before 19989c6cae24SSepherosa Ziehau * restoration was an intersection of the VF's 19999c6cae24SSepherosa Ziehau * if_capabilites and the synthetic device's 20009c6cae24SSepherosa Ziehau * if_capabilites. 20019c6cae24SSepherosa Ziehau */ 20029c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax; 20039c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomaxsegcount = 20049c6cae24SSepherosa Ziehau sc->hn_saved_tsosegcnt; 20059c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz; 20069c6cae24SSepherosa Ziehau } 20079c6cae24SSepherosa Ziehau 2008642ec226SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 2009642ec226SSepherosa Ziehau /* 2010642ec226SSepherosa Ziehau * Restore RSS settings. 2011642ec226SSepherosa Ziehau */ 2012642ec226SSepherosa Ziehau hn_vf_rss_restore(sc); 2013642ec226SSepherosa Ziehau 20149c6cae24SSepherosa Ziehau /* 20159c6cae24SSepherosa Ziehau * Resume link status management, which was suspended 20169c6cae24SSepherosa Ziehau * by hn_ifnet_attevent(). 20179c6cae24SSepherosa Ziehau */ 20189c6cae24SSepherosa Ziehau hn_resume_mgmt(sc); 20199c6cae24SSepherosa Ziehau } 2020642ec226SSepherosa Ziehau } 20219c6cae24SSepherosa Ziehau 2022a97fff19SSepherosa Ziehau /* Mark transparent mode VF as disabled. */ 2023a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */); 2024499c3e17SSepherosa Ziehau 2025499c3e17SSepherosa Ziehau rm_wlock(&hn_vfmap_lock); 2026499c3e17SSepherosa Ziehau 2027499c3e17SSepherosa Ziehau KASSERT(ifp->if_index < hn_vfmap_size, 2028499c3e17SSepherosa Ziehau ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size)); 2029499c3e17SSepherosa Ziehau if (hn_vfmap[ifp->if_index] != NULL) { 2030499c3e17SSepherosa Ziehau KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp, 2031499c3e17SSepherosa Ziehau ("%s: ifindex %d was mapped to %s", 2032499c3e17SSepherosa Ziehau ifp->if_xname, ifp->if_index, 2033499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index]->if_xname)); 2034499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index] = NULL; 2035499c3e17SSepherosa Ziehau } 2036499c3e17SSepherosa Ziehau 2037499c3e17SSepherosa Ziehau rm_wunlock(&hn_vfmap_lock); 2038499c3e17SSepherosa Ziehau done: 2039499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 2040499c3e17SSepherosa Ziehau } 2041499c3e17SSepherosa Ziehau 20429c6cae24SSepherosa Ziehau static void 20439c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state) 20449c6cae24SSepherosa Ziehau { 20459c6cae24SSepherosa Ziehau struct hn_softc *sc = xsc; 20469c6cae24SSepherosa Ziehau 20479c6cae24SSepherosa Ziehau if (sc->hn_vf_ifp == ifp) 20489c6cae24SSepherosa Ziehau if_link_state_change(sc->hn_ifp, link_state); 20499c6cae24SSepherosa Ziehau } 20509c6cae24SSepherosa Ziehau 205115516c77SSepherosa Ziehau static int 205215516c77SSepherosa Ziehau hn_probe(device_t dev) 205315516c77SSepherosa Ziehau { 205415516c77SSepherosa Ziehau 2055c2d50b26SSepherosa Ziehau if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) { 205615516c77SSepherosa Ziehau device_set_desc(dev, "Hyper-V Network Interface"); 205715516c77SSepherosa Ziehau return BUS_PROBE_DEFAULT; 205815516c77SSepherosa Ziehau } 205915516c77SSepherosa Ziehau return ENXIO; 206015516c77SSepherosa Ziehau } 206115516c77SSepherosa Ziehau 206215516c77SSepherosa Ziehau static int 206315516c77SSepherosa Ziehau hn_attach(device_t dev) 206415516c77SSepherosa Ziehau { 206515516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 206615516c77SSepherosa Ziehau struct sysctl_oid_list *child; 206715516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 206815516c77SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 206915516c77SSepherosa Ziehau struct ifnet *ifp = NULL; 207015516c77SSepherosa Ziehau int error, ring_cnt, tx_ring_cnt; 2071eb2fe044SSepherosa Ziehau uint32_t mtu; 207215516c77SSepherosa Ziehau 207315516c77SSepherosa Ziehau sc->hn_dev = dev; 207415516c77SSepherosa Ziehau sc->hn_prichan = vmbus_get_channel(dev); 207515516c77SSepherosa Ziehau HN_LOCK_INIT(sc); 20769c6cae24SSepherosa Ziehau rm_init(&sc->hn_vf_lock, "hnvf"); 20779c6cae24SSepherosa Ziehau if (hn_xpnt_vf && hn_xpnt_vf_accbpf) 20789c6cae24SSepherosa Ziehau sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF; 207915516c77SSepherosa Ziehau 208015516c77SSepherosa Ziehau /* 2081dc13fee6SSepherosa Ziehau * Initialize these tunables once. 2082dc13fee6SSepherosa Ziehau */ 2083dc13fee6SSepherosa Ziehau sc->hn_agg_size = hn_tx_agg_size; 2084dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = hn_tx_agg_pkts; 2085dc13fee6SSepherosa Ziehau 2086dc13fee6SSepherosa Ziehau /* 208715516c77SSepherosa Ziehau * Setup taskqueue for transmission. 208815516c77SSepherosa Ziehau */ 20890e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) { 2090fdd0222aSSepherosa Ziehau int i; 2091fdd0222aSSepherosa Ziehau 2092fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = 2093fdd0222aSSepherosa Ziehau malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 2094fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 2095fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 2096fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx", 2097fdd0222aSSepherosa Ziehau M_WAITOK, taskqueue_thread_enqueue, 2098fdd0222aSSepherosa Ziehau &sc->hn_tx_taskqs[i]); 2099fdd0222aSSepherosa Ziehau taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET, 2100fdd0222aSSepherosa Ziehau "%s tx%d", device_get_nameunit(dev), i); 2101fdd0222aSSepherosa Ziehau } 21020e11868dSSepherosa Ziehau } else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) { 2103fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = hn_tx_taskque; 210415516c77SSepherosa Ziehau } 210515516c77SSepherosa Ziehau 210615516c77SSepherosa Ziehau /* 210715516c77SSepherosa Ziehau * Setup taskqueue for mangement tasks, e.g. link status. 210815516c77SSepherosa Ziehau */ 210915516c77SSepherosa Ziehau sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK, 211015516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0); 211115516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt", 211215516c77SSepherosa Ziehau device_get_nameunit(dev)); 211315516c77SSepherosa Ziehau TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc); 211415516c77SSepherosa Ziehau TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc); 211515516c77SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0, 211615516c77SSepherosa Ziehau hn_netchg_status_taskfunc, sc); 211715516c77SSepherosa Ziehau 21189c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 21199c6cae24SSepherosa Ziehau /* 21209c6cae24SSepherosa Ziehau * Setup taskqueue for VF tasks, e.g. delayed VF bringing up. 21219c6cae24SSepherosa Ziehau */ 21229c6cae24SSepherosa Ziehau sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK, 21239c6cae24SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_vf_taskq); 21249c6cae24SSepherosa Ziehau taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf", 21259c6cae24SSepherosa Ziehau device_get_nameunit(dev)); 21269c6cae24SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0, 21279c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc, sc); 21289c6cae24SSepherosa Ziehau } 21299c6cae24SSepherosa Ziehau 213015516c77SSepherosa Ziehau /* 213115516c77SSepherosa Ziehau * Allocate ifnet and setup its name earlier, so that if_printf 213215516c77SSepherosa Ziehau * can be used by functions, which will be called after 213315516c77SSepherosa Ziehau * ether_ifattach(). 213415516c77SSepherosa Ziehau */ 213515516c77SSepherosa Ziehau ifp = sc->hn_ifp = if_alloc(IFT_ETHER); 213615516c77SSepherosa Ziehau ifp->if_softc = sc; 213715516c77SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 213815516c77SSepherosa Ziehau 213915516c77SSepherosa Ziehau /* 214015516c77SSepherosa Ziehau * Initialize ifmedia earlier so that it can be unconditionally 214115516c77SSepherosa Ziehau * destroyed, if error happened later on. 214215516c77SSepherosa Ziehau */ 214315516c77SSepherosa Ziehau ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts); 214415516c77SSepherosa Ziehau 214515516c77SSepherosa Ziehau /* 214615516c77SSepherosa Ziehau * Figure out the # of RX rings (ring_cnt) and the # of TX rings 214715516c77SSepherosa Ziehau * to use (tx_ring_cnt). 214815516c77SSepherosa Ziehau * 214915516c77SSepherosa Ziehau * NOTE: 215015516c77SSepherosa Ziehau * The # of RX rings to use is same as the # of channels to use. 215115516c77SSepherosa Ziehau */ 215215516c77SSepherosa Ziehau ring_cnt = hn_chan_cnt; 215315516c77SSepherosa Ziehau if (ring_cnt <= 0) { 215415516c77SSepherosa Ziehau /* Default */ 215515516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 215615516c77SSepherosa Ziehau if (ring_cnt > HN_RING_CNT_DEF_MAX) 215715516c77SSepherosa Ziehau ring_cnt = HN_RING_CNT_DEF_MAX; 215815516c77SSepherosa Ziehau } else if (ring_cnt > mp_ncpus) { 215915516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 216015516c77SSepherosa Ziehau } 216134d68912SSepherosa Ziehau #ifdef RSS 216234d68912SSepherosa Ziehau if (ring_cnt > rss_getnumbuckets()) 216334d68912SSepherosa Ziehau ring_cnt = rss_getnumbuckets(); 216434d68912SSepherosa Ziehau #endif 216515516c77SSepherosa Ziehau 216615516c77SSepherosa Ziehau tx_ring_cnt = hn_tx_ring_cnt; 216715516c77SSepherosa Ziehau if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt) 216815516c77SSepherosa Ziehau tx_ring_cnt = ring_cnt; 216923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 217015516c77SSepherosa Ziehau if (hn_use_if_start) { 217115516c77SSepherosa Ziehau /* ifnet.if_start only needs one TX ring. */ 217215516c77SSepherosa Ziehau tx_ring_cnt = 1; 217315516c77SSepherosa Ziehau } 217423bf9e15SSepherosa Ziehau #endif 217515516c77SSepherosa Ziehau 217615516c77SSepherosa Ziehau /* 217715516c77SSepherosa Ziehau * Set the leader CPU for channels. 217815516c77SSepherosa Ziehau */ 217915516c77SSepherosa Ziehau sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus; 218015516c77SSepherosa Ziehau 218115516c77SSepherosa Ziehau /* 218215516c77SSepherosa Ziehau * Create enough TX/RX rings, even if only limited number of 218315516c77SSepherosa Ziehau * channels can be allocated. 218415516c77SSepherosa Ziehau */ 218515516c77SSepherosa Ziehau error = hn_create_tx_data(sc, tx_ring_cnt); 218615516c77SSepherosa Ziehau if (error) 218715516c77SSepherosa Ziehau goto failed; 218815516c77SSepherosa Ziehau error = hn_create_rx_data(sc, ring_cnt); 218915516c77SSepherosa Ziehau if (error) 219015516c77SSepherosa Ziehau goto failed; 219115516c77SSepherosa Ziehau 219215516c77SSepherosa Ziehau /* 219315516c77SSepherosa Ziehau * Create transaction context for NVS and RNDIS transactions. 219415516c77SSepherosa Ziehau */ 219515516c77SSepherosa Ziehau sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev), 219615516c77SSepherosa Ziehau HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0); 219725641fc7SSepherosa Ziehau if (sc->hn_xact == NULL) { 219825641fc7SSepherosa Ziehau error = ENXIO; 219915516c77SSepherosa Ziehau goto failed; 220025641fc7SSepherosa Ziehau } 220125641fc7SSepherosa Ziehau 220225641fc7SSepherosa Ziehau /* 220325641fc7SSepherosa Ziehau * Install orphan handler for the revocation of this device's 220425641fc7SSepherosa Ziehau * primary channel. 220525641fc7SSepherosa Ziehau * 220625641fc7SSepherosa Ziehau * NOTE: 220725641fc7SSepherosa Ziehau * The processing order is critical here: 220825641fc7SSepherosa Ziehau * Install the orphan handler, _before_ testing whether this 220925641fc7SSepherosa Ziehau * device's primary channel has been revoked or not. 221025641fc7SSepherosa Ziehau */ 221125641fc7SSepherosa Ziehau vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact); 221225641fc7SSepherosa Ziehau if (vmbus_chan_is_revoked(sc->hn_prichan)) { 221325641fc7SSepherosa Ziehau error = ENXIO; 221425641fc7SSepherosa Ziehau goto failed; 221525641fc7SSepherosa Ziehau } 221615516c77SSepherosa Ziehau 221715516c77SSepherosa Ziehau /* 221815516c77SSepherosa Ziehau * Attach the synthetic parts, i.e. NVS and RNDIS. 221915516c77SSepherosa Ziehau */ 222015516c77SSepherosa Ziehau error = hn_synth_attach(sc, ETHERMTU); 222115516c77SSepherosa Ziehau if (error) 222215516c77SSepherosa Ziehau goto failed; 222315516c77SSepherosa Ziehau 222415516c77SSepherosa Ziehau error = hn_rndis_get_eaddr(sc, eaddr); 222515516c77SSepherosa Ziehau if (error) 222615516c77SSepherosa Ziehau goto failed; 222715516c77SSepherosa Ziehau 2228eb2fe044SSepherosa Ziehau error = hn_rndis_get_mtu(sc, &mtu); 2229eb2fe044SSepherosa Ziehau if (error) 2230eb2fe044SSepherosa Ziehau mtu = ETHERMTU; 2231eb2fe044SSepherosa Ziehau else if (bootverbose) 2232eb2fe044SSepherosa Ziehau device_printf(dev, "RNDIS mtu %u\n", mtu); 2233eb2fe044SSepherosa Ziehau 223415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 223515516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 223615516c77SSepherosa Ziehau /* 223715516c77SSepherosa Ziehau * Reduce TCP segment aggregation limit for multiple 223815516c77SSepherosa Ziehau * RX rings to increase ACK timeliness. 223915516c77SSepherosa Ziehau */ 224015516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF); 224115516c77SSepherosa Ziehau } 224215516c77SSepherosa Ziehau #endif 224315516c77SSepherosa Ziehau 224415516c77SSepherosa Ziehau /* 224515516c77SSepherosa Ziehau * Fixup TX stuffs after synthetic parts are attached. 224615516c77SSepherosa Ziehau */ 224715516c77SSepherosa Ziehau hn_fixup_tx_data(sc); 224815516c77SSepherosa Ziehau 224915516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 225015516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 225115516c77SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD, 225215516c77SSepherosa Ziehau &sc->hn_nvs_ver, 0, "NVS version"); 225315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version", 225415516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 225515516c77SSepherosa Ziehau hn_ndis_version_sysctl, "A", "NDIS version"); 225615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps", 225715516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 225815516c77SSepherosa Ziehau hn_caps_sysctl, "A", "capabilities"); 225915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist", 226015516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 226115516c77SSepherosa Ziehau hn_hwassist_sysctl, "A", "hwassist"); 22629c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max", 22639c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size"); 22649c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt", 22659c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0, 22669c6cae24SSepherosa Ziehau "max # of TSO segments"); 22679c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz", 22689c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0, 22699c6cae24SSepherosa Ziehau "max size of TSO segment"); 227015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter", 227115516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 227215516c77SSepherosa Ziehau hn_rxfilter_sysctl, "A", "rxfilter"); 227315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash", 227415516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 227515516c77SSepherosa Ziehau hn_rss_hash_sysctl, "A", "RSS hash"); 2276642ec226SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hashcap", 2277642ec226SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 2278642ec226SSepherosa Ziehau hn_rss_hcap_sysctl, "A", "RSS hash capabilities"); 2279642ec226SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "mbuf_hash", 2280642ec226SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 2281642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl, "A", "RSS hash for mbufs"); 228215516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size", 228315516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count"); 228434d68912SSepherosa Ziehau #ifndef RSS 228534d68912SSepherosa Ziehau /* 228634d68912SSepherosa Ziehau * Don't allow RSS key/indirect table changes, if RSS is defined. 228734d68912SSepherosa Ziehau */ 228815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key", 228915516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 229015516c77SSepherosa Ziehau hn_rss_key_sysctl, "IU", "RSS key"); 229115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind", 229215516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 229315516c77SSepherosa Ziehau hn_rss_ind_sysctl, "IU", "RSS indirect table"); 229434d68912SSepherosa Ziehau #endif 2295dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size", 2296dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_size, 0, 2297dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation size limit"); 2298dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts", 2299dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0, 2300dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation count limit"); 2301dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align", 2302dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_align, 0, 2303dc13fee6SSepherosa Ziehau "RNDIS packet transmission aggregation alignment"); 2304dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size", 2305dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 2306dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl, "I", 2307dc13fee6SSepherosa Ziehau "Packet transmission aggregation size, 0 -- disable, -1 -- auto"); 2308dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts", 2309dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 2310dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl, "I", 2311dc13fee6SSepherosa Ziehau "Packet transmission aggregation packets, " 2312dc13fee6SSepherosa Ziehau "0 -- disable, -1 -- auto"); 23136c1204dfSSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling", 23146c1204dfSSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 23156c1204dfSSepherosa Ziehau hn_polling_sysctl, "I", 23166c1204dfSSepherosa Ziehau "Polling frequency: [100,1000000], 0 disable polling"); 231740d60d6eSDexuan Cui SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf", 231840d60d6eSDexuan Cui CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 231940d60d6eSDexuan Cui hn_vf_sysctl, "A", "Virtual Function's name"); 23209c6cae24SSepherosa Ziehau if (!hn_xpnt_vf) { 2321499c3e17SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf", 2322499c3e17SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 2323499c3e17SSepherosa Ziehau hn_rxvf_sysctl, "A", "activated Virtual Function's name"); 23249c6cae24SSepherosa Ziehau } else { 23259c6cae24SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled", 23269c6cae24SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 23279c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl, "I", 23289c6cae24SSepherosa Ziehau "Transparent VF enabled"); 23299c6cae24SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf", 23309c6cae24SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 23319c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl, "I", 23329c6cae24SSepherosa Ziehau "Accurate BPF for transparent VF"); 23339c6cae24SSepherosa Ziehau } 233415516c77SSepherosa Ziehau 233515516c77SSepherosa Ziehau /* 233615516c77SSepherosa Ziehau * Setup the ifmedia, which has been initialized earlier. 233715516c77SSepherosa Ziehau */ 233815516c77SSepherosa Ziehau ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL); 233915516c77SSepherosa Ziehau ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO); 234015516c77SSepherosa Ziehau /* XXX ifmedia_set really should do this for us */ 234115516c77SSepherosa Ziehau sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media; 234215516c77SSepherosa Ziehau 234315516c77SSepherosa Ziehau /* 234415516c77SSepherosa Ziehau * Setup the ifnet for this interface. 234515516c77SSepherosa Ziehau */ 234615516c77SSepherosa Ziehau 234715516c77SSepherosa Ziehau ifp->if_baudrate = IF_Gbps(10); 234815516c77SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 234915516c77SSepherosa Ziehau ifp->if_ioctl = hn_ioctl; 235015516c77SSepherosa Ziehau ifp->if_init = hn_init; 235123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 235215516c77SSepherosa Ziehau if (hn_use_if_start) { 235315516c77SSepherosa Ziehau int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]); 235415516c77SSepherosa Ziehau 235515516c77SSepherosa Ziehau ifp->if_start = hn_start; 235615516c77SSepherosa Ziehau IFQ_SET_MAXLEN(&ifp->if_snd, qdepth); 235715516c77SSepherosa Ziehau ifp->if_snd.ifq_drv_maxlen = qdepth - 1; 235815516c77SSepherosa Ziehau IFQ_SET_READY(&ifp->if_snd); 235923bf9e15SSepherosa Ziehau } else 236023bf9e15SSepherosa Ziehau #endif 236123bf9e15SSepherosa Ziehau { 236215516c77SSepherosa Ziehau ifp->if_transmit = hn_transmit; 236315516c77SSepherosa Ziehau ifp->if_qflush = hn_xmit_qflush; 236415516c77SSepherosa Ziehau } 236515516c77SSepherosa Ziehau 23669c6cae24SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE; 236715516c77SSepherosa Ziehau #ifdef foo 236815516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 236915516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM_IPV6; 237015516c77SSepherosa Ziehau #endif 237115516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_VLAN) { 237215516c77SSepherosa Ziehau /* XXX not sure about VLAN_MTU. */ 237315516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 237415516c77SSepherosa Ziehau } 237515516c77SSepherosa Ziehau 237615516c77SSepherosa Ziehau ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist; 237715516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP_MASK) 237815516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM; 237915516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP6_MASK) 238015516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM_IPV6; 238115516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO4) { 238215516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO4; 238315516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 238415516c77SSepherosa Ziehau } 238515516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO6) { 238615516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO6; 238715516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 238815516c77SSepherosa Ziehau } 238915516c77SSepherosa Ziehau 239015516c77SSepherosa Ziehau /* Enable all available capabilities by default. */ 239115516c77SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 239215516c77SSepherosa Ziehau 23937960e6baSSepherosa Ziehau /* 23947960e6baSSepherosa Ziehau * Disable IPv6 TSO and TXCSUM by default, they still can 23957960e6baSSepherosa Ziehau * be enabled through SIOCSIFCAP. 23967960e6baSSepherosa Ziehau */ 23977960e6baSSepherosa Ziehau ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 23987960e6baSSepherosa Ziehau ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO); 23997960e6baSSepherosa Ziehau 240015516c77SSepherosa Ziehau if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) { 24019c6cae24SSepherosa Ziehau /* 24029c6cae24SSepherosa Ziehau * Lock hn_set_tso_maxsize() to simplify its 24039c6cae24SSepherosa Ziehau * internal logic. 24049c6cae24SSepherosa Ziehau */ 24059c6cae24SSepherosa Ziehau HN_LOCK(sc); 240615516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU); 24079c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 240815516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; 240915516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 241015516c77SSepherosa Ziehau } 241115516c77SSepherosa Ziehau 241215516c77SSepherosa Ziehau ether_ifattach(ifp, eaddr); 241315516c77SSepherosa Ziehau 241415516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) { 241515516c77SSepherosa Ziehau if_printf(ifp, "TSO segcnt %u segsz %u\n", 241615516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize); 241715516c77SSepherosa Ziehau } 2418eb2fe044SSepherosa Ziehau if (mtu < ETHERMTU) { 2419eb2fe044SSepherosa Ziehau if_printf(ifp, "fixup mtu %u -> %u\n", ifp->if_mtu, mtu); 2420eb2fe044SSepherosa Ziehau ifp->if_mtu = mtu; 2421eb2fe044SSepherosa Ziehau } 242215516c77SSepherosa Ziehau 242315516c77SSepherosa Ziehau /* Inform the upper layer about the long frame support. */ 242415516c77SSepherosa Ziehau ifp->if_hdrlen = sizeof(struct ether_vlan_header); 242515516c77SSepherosa Ziehau 242615516c77SSepherosa Ziehau /* 242715516c77SSepherosa Ziehau * Kick off link status check. 242815516c77SSepherosa Ziehau */ 242915516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 243015516c77SSepherosa Ziehau hn_update_link_status(sc); 243115516c77SSepherosa Ziehau 24329c6cae24SSepherosa Ziehau if (!hn_xpnt_vf) { 24335bdfd3fdSDexuan Cui sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event, 24345bdfd3fdSDexuan Cui hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY); 24355bdfd3fdSDexuan Cui sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event, 24365bdfd3fdSDexuan Cui hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY); 24379c6cae24SSepherosa Ziehau } else { 24389c6cae24SSepherosa Ziehau sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event, 24399c6cae24SSepherosa Ziehau hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY); 24409c6cae24SSepherosa Ziehau } 24415bdfd3fdSDexuan Cui 2442f41e0df4SSepherosa Ziehau /* 2443f41e0df4SSepherosa Ziehau * NOTE: 2444f41e0df4SSepherosa Ziehau * Subscribe ether_ifattach event, instead of ifnet_arrival event, 2445f41e0df4SSepherosa Ziehau * since interface's LLADDR is needed; interface LLADDR is not 2446f41e0df4SSepherosa Ziehau * available when ifnet_arrival event is triggered. 2447f41e0df4SSepherosa Ziehau */ 2448499c3e17SSepherosa Ziehau sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event, 2449499c3e17SSepherosa Ziehau hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY); 2450499c3e17SSepherosa Ziehau sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event, 2451499c3e17SSepherosa Ziehau hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY); 2452499c3e17SSepherosa Ziehau 245315516c77SSepherosa Ziehau return (0); 245415516c77SSepherosa Ziehau failed: 245515516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) 245615516c77SSepherosa Ziehau hn_synth_detach(sc); 245715516c77SSepherosa Ziehau hn_detach(dev); 245815516c77SSepherosa Ziehau return (error); 245915516c77SSepherosa Ziehau } 246015516c77SSepherosa Ziehau 246115516c77SSepherosa Ziehau static int 246215516c77SSepherosa Ziehau hn_detach(device_t dev) 246315516c77SSepherosa Ziehau { 246415516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 2465499c3e17SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp, *vf_ifp; 246615516c77SSepherosa Ziehau 24679c6cae24SSepherosa Ziehau if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) { 24689c6cae24SSepherosa Ziehau /* 24699c6cae24SSepherosa Ziehau * In case that the vmbus missed the orphan handler 24709c6cae24SSepherosa Ziehau * installation. 24719c6cae24SSepherosa Ziehau */ 24729c6cae24SSepherosa Ziehau vmbus_xact_ctx_orphan(sc->hn_xact); 24739c6cae24SSepherosa Ziehau } 24749c6cae24SSepherosa Ziehau 24755bdfd3fdSDexuan Cui if (sc->hn_ifaddr_evthand != NULL) 24765bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand); 24775bdfd3fdSDexuan Cui if (sc->hn_ifnet_evthand != NULL) 24785bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand); 2479499c3e17SSepherosa Ziehau if (sc->hn_ifnet_atthand != NULL) { 2480499c3e17SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ether_ifattach_event, 2481499c3e17SSepherosa Ziehau sc->hn_ifnet_atthand); 2482499c3e17SSepherosa Ziehau } 2483499c3e17SSepherosa Ziehau if (sc->hn_ifnet_dethand != NULL) { 2484499c3e17SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ifnet_departure_event, 2485499c3e17SSepherosa Ziehau sc->hn_ifnet_dethand); 2486499c3e17SSepherosa Ziehau } 24879c6cae24SSepherosa Ziehau if (sc->hn_ifnet_lnkhand != NULL) 24889c6cae24SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand); 2489499c3e17SSepherosa Ziehau 2490499c3e17SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 2491499c3e17SSepherosa Ziehau __compiler_membar(); 2492499c3e17SSepherosa Ziehau if (vf_ifp != NULL) 2493499c3e17SSepherosa Ziehau hn_ifnet_detevent(sc, vf_ifp); 24945bdfd3fdSDexuan Cui 249515516c77SSepherosa Ziehau if (device_is_attached(dev)) { 249615516c77SSepherosa Ziehau HN_LOCK(sc); 249715516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 249815516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 24995bdfd3fdSDexuan Cui hn_stop(sc, true); 250015516c77SSepherosa Ziehau /* 250115516c77SSepherosa Ziehau * NOTE: 250215516c77SSepherosa Ziehau * hn_stop() only suspends data, so managment 250315516c77SSepherosa Ziehau * stuffs have to be suspended manually here. 250415516c77SSepherosa Ziehau */ 250515516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 250615516c77SSepherosa Ziehau hn_synth_detach(sc); 250715516c77SSepherosa Ziehau } 250815516c77SSepherosa Ziehau HN_UNLOCK(sc); 250915516c77SSepherosa Ziehau ether_ifdetach(ifp); 251015516c77SSepherosa Ziehau } 251115516c77SSepherosa Ziehau 251215516c77SSepherosa Ziehau ifmedia_removeall(&sc->hn_media); 251315516c77SSepherosa Ziehau hn_destroy_rx_data(sc); 251415516c77SSepherosa Ziehau hn_destroy_tx_data(sc); 251515516c77SSepherosa Ziehau 25160e11868dSSepherosa Ziehau if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) { 2517fdd0222aSSepherosa Ziehau int i; 2518fdd0222aSSepherosa Ziehau 2519fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 2520fdd0222aSSepherosa Ziehau taskqueue_free(sc->hn_tx_taskqs[i]); 2521fdd0222aSSepherosa Ziehau free(sc->hn_tx_taskqs, M_DEVBUF); 2522fdd0222aSSepherosa Ziehau } 252315516c77SSepherosa Ziehau taskqueue_free(sc->hn_mgmt_taskq0); 25249c6cae24SSepherosa Ziehau if (sc->hn_vf_taskq != NULL) 25259c6cae24SSepherosa Ziehau taskqueue_free(sc->hn_vf_taskq); 252615516c77SSepherosa Ziehau 252725641fc7SSepherosa Ziehau if (sc->hn_xact != NULL) { 252825641fc7SSepherosa Ziehau /* 252925641fc7SSepherosa Ziehau * Uninstall the orphan handler _before_ the xact is 253025641fc7SSepherosa Ziehau * destructed. 253125641fc7SSepherosa Ziehau */ 253225641fc7SSepherosa Ziehau vmbus_chan_unset_orphan(sc->hn_prichan); 253315516c77SSepherosa Ziehau vmbus_xact_ctx_destroy(sc->hn_xact); 253425641fc7SSepherosa Ziehau } 253515516c77SSepherosa Ziehau 253615516c77SSepherosa Ziehau if_free(ifp); 253715516c77SSepherosa Ziehau 253815516c77SSepherosa Ziehau HN_LOCK_DESTROY(sc); 25399c6cae24SSepherosa Ziehau rm_destroy(&sc->hn_vf_lock); 254015516c77SSepherosa Ziehau return (0); 254115516c77SSepherosa Ziehau } 254215516c77SSepherosa Ziehau 254315516c77SSepherosa Ziehau static int 254415516c77SSepherosa Ziehau hn_shutdown(device_t dev) 254515516c77SSepherosa Ziehau { 254615516c77SSepherosa Ziehau 254715516c77SSepherosa Ziehau return (0); 254815516c77SSepherosa Ziehau } 254915516c77SSepherosa Ziehau 255015516c77SSepherosa Ziehau static void 255115516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc) 255215516c77SSepherosa Ziehau { 255315516c77SSepherosa Ziehau uint32_t link_status; 255415516c77SSepherosa Ziehau int error; 255515516c77SSepherosa Ziehau 255615516c77SSepherosa Ziehau error = hn_rndis_get_linkstatus(sc, &link_status); 255715516c77SSepherosa Ziehau if (error) { 255815516c77SSepherosa Ziehau /* XXX what to do? */ 255915516c77SSepherosa Ziehau return; 256015516c77SSepherosa Ziehau } 256115516c77SSepherosa Ziehau 256215516c77SSepherosa Ziehau if (link_status == NDIS_MEDIA_STATE_CONNECTED) 256315516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_LINKUP; 256415516c77SSepherosa Ziehau else 256515516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 256615516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, 256715516c77SSepherosa Ziehau (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ? 256815516c77SSepherosa Ziehau LINK_STATE_UP : LINK_STATE_DOWN); 256915516c77SSepherosa Ziehau } 257015516c77SSepherosa Ziehau 257115516c77SSepherosa Ziehau static void 257215516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused) 257315516c77SSepherosa Ziehau { 257415516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 257515516c77SSepherosa Ziehau 257615516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 257715516c77SSepherosa Ziehau return; 257815516c77SSepherosa Ziehau hn_link_status(sc); 257915516c77SSepherosa Ziehau } 258015516c77SSepherosa Ziehau 258115516c77SSepherosa Ziehau static void 258215516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused) 258315516c77SSepherosa Ziehau { 258415516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 258515516c77SSepherosa Ziehau 258615516c77SSepherosa Ziehau /* Prevent any link status checks from running. */ 258715516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_NETCHG; 258815516c77SSepherosa Ziehau 258915516c77SSepherosa Ziehau /* 259015516c77SSepherosa Ziehau * Fake up a [link down --> link up] state change; 5 seconds 259115516c77SSepherosa Ziehau * delay is used, which closely simulates miibus reaction 259215516c77SSepherosa Ziehau * upon link down event. 259315516c77SSepherosa Ziehau */ 259415516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 259515516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); 259615516c77SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0, 259715516c77SSepherosa Ziehau &sc->hn_netchg_status, 5 * hz); 259815516c77SSepherosa Ziehau } 259915516c77SSepherosa Ziehau 260015516c77SSepherosa Ziehau static void 260115516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused) 260215516c77SSepherosa Ziehau { 260315516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 260415516c77SSepherosa Ziehau 260515516c77SSepherosa Ziehau /* Re-allow link status checks. */ 260615516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG; 260715516c77SSepherosa Ziehau hn_link_status(sc); 260815516c77SSepherosa Ziehau } 260915516c77SSepherosa Ziehau 261015516c77SSepherosa Ziehau static void 261115516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc) 261215516c77SSepherosa Ziehau { 261315516c77SSepherosa Ziehau 261415516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 261515516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task); 261615516c77SSepherosa Ziehau } 261715516c77SSepherosa Ziehau 261815516c77SSepherosa Ziehau static void 261915516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc) 262015516c77SSepherosa Ziehau { 262115516c77SSepherosa Ziehau 262215516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 262315516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init); 262415516c77SSepherosa Ziehau } 262515516c77SSepherosa Ziehau 262615516c77SSepherosa Ziehau static __inline int 262715516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd, 262815516c77SSepherosa Ziehau struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) 262915516c77SSepherosa Ziehau { 263015516c77SSepherosa Ziehau struct mbuf *m = *m_head; 263115516c77SSepherosa Ziehau int error; 263215516c77SSepherosa Ziehau 263315516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim")); 263415516c77SSepherosa Ziehau 263515516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap, 263615516c77SSepherosa Ziehau m, segs, nsegs, BUS_DMA_NOWAIT); 263715516c77SSepherosa Ziehau if (error == EFBIG) { 263815516c77SSepherosa Ziehau struct mbuf *m_new; 263915516c77SSepherosa Ziehau 264015516c77SSepherosa Ziehau m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX); 264115516c77SSepherosa Ziehau if (m_new == NULL) 264215516c77SSepherosa Ziehau return ENOBUFS; 264315516c77SSepherosa Ziehau else 264415516c77SSepherosa Ziehau *m_head = m = m_new; 264515516c77SSepherosa Ziehau txr->hn_tx_collapsed++; 264615516c77SSepherosa Ziehau 264715516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, 264815516c77SSepherosa Ziehau txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT); 264915516c77SSepherosa Ziehau } 265015516c77SSepherosa Ziehau if (!error) { 265115516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap, 265215516c77SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 265315516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_DMAMAP; 265415516c77SSepherosa Ziehau } 265515516c77SSepherosa Ziehau return error; 265615516c77SSepherosa Ziehau } 265715516c77SSepherosa Ziehau 265815516c77SSepherosa Ziehau static __inline int 265915516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd) 266015516c77SSepherosa Ziehau { 266115516c77SSepherosa Ziehau 266215516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0, 266315516c77SSepherosa Ziehau ("put an onlist txd %#x", txd->flags)); 2664dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2665dc13fee6SSepherosa Ziehau ("put an onagg txd %#x", txd->flags)); 266615516c77SSepherosa Ziehau 266715516c77SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 266815516c77SSepherosa Ziehau if (atomic_fetchadd_int(&txd->refs, -1) != 1) 266915516c77SSepherosa Ziehau return 0; 267015516c77SSepherosa Ziehau 2671dc13fee6SSepherosa Ziehau if (!STAILQ_EMPTY(&txd->agg_list)) { 2672dc13fee6SSepherosa Ziehau struct hn_txdesc *tmp_txd; 2673dc13fee6SSepherosa Ziehau 2674dc13fee6SSepherosa Ziehau while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) { 2675dc13fee6SSepherosa Ziehau int freed; 2676dc13fee6SSepherosa Ziehau 2677dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list), 2678dc13fee6SSepherosa Ziehau ("resursive aggregation on aggregated txdesc")); 2679dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG), 2680dc13fee6SSepherosa Ziehau ("not aggregated txdesc")); 2681dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 2682dc13fee6SSepherosa Ziehau ("aggregated txdesc uses dmamap")); 2683dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 2684dc13fee6SSepherosa Ziehau ("aggregated txdesc consumes " 2685dc13fee6SSepherosa Ziehau "chimney sending buffer")); 2686dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_size == 0, 2687dc13fee6SSepherosa Ziehau ("aggregated txdesc has non-zero " 2688dc13fee6SSepherosa Ziehau "chimney sending size")); 2689dc13fee6SSepherosa Ziehau 2690dc13fee6SSepherosa Ziehau STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link); 2691dc13fee6SSepherosa Ziehau tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG; 2692dc13fee6SSepherosa Ziehau freed = hn_txdesc_put(txr, tmp_txd); 2693dc13fee6SSepherosa Ziehau KASSERT(freed, ("failed to free aggregated txdesc")); 2694dc13fee6SSepherosa Ziehau } 2695dc13fee6SSepherosa Ziehau } 2696dc13fee6SSepherosa Ziehau 269715516c77SSepherosa Ziehau if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) { 269815516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 269915516c77SSepherosa Ziehau ("chim txd uses dmamap")); 270015516c77SSepherosa Ziehau hn_chim_free(txr->hn_sc, txd->chim_index); 270115516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 2702dc13fee6SSepherosa Ziehau txd->chim_size = 0; 270315516c77SSepherosa Ziehau } else if (txd->flags & HN_TXD_FLAG_DMAMAP) { 270415516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, 270515516c77SSepherosa Ziehau txd->data_dmap, BUS_DMASYNC_POSTWRITE); 270615516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_data_dtag, 270715516c77SSepherosa Ziehau txd->data_dmap); 270815516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_DMAMAP; 270915516c77SSepherosa Ziehau } 271015516c77SSepherosa Ziehau 271115516c77SSepherosa Ziehau if (txd->m != NULL) { 271215516c77SSepherosa Ziehau m_freem(txd->m); 271315516c77SSepherosa Ziehau txd->m = NULL; 271415516c77SSepherosa Ziehau } 271515516c77SSepherosa Ziehau 271615516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 271715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 271815516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 271915516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail >= 0 && 272015516c77SSepherosa Ziehau txr->hn_txdesc_avail < txr->hn_txdesc_cnt, 272115516c77SSepherosa Ziehau ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail)); 272215516c77SSepherosa Ziehau txr->hn_txdesc_avail++; 272315516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 272415516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 272585e4ae1eSSepherosa Ziehau #else /* HN_USE_TXDESC_BUFRING */ 272685e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 272715516c77SSepherosa Ziehau atomic_add_int(&txr->hn_txdesc_avail, 1); 272815516c77SSepherosa Ziehau #endif 272985e4ae1eSSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 273085e4ae1eSSepherosa Ziehau #endif /* !HN_USE_TXDESC_BUFRING */ 273115516c77SSepherosa Ziehau 273215516c77SSepherosa Ziehau return 1; 273315516c77SSepherosa Ziehau } 273415516c77SSepherosa Ziehau 273515516c77SSepherosa Ziehau static __inline struct hn_txdesc * 273615516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr) 273715516c77SSepherosa Ziehau { 273815516c77SSepherosa Ziehau struct hn_txdesc *txd; 273915516c77SSepherosa Ziehau 274015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 274115516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 274215516c77SSepherosa Ziehau txd = SLIST_FIRST(&txr->hn_txlist); 274315516c77SSepherosa Ziehau if (txd != NULL) { 274415516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail > 0, 274515516c77SSepherosa Ziehau ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail)); 274615516c77SSepherosa Ziehau txr->hn_txdesc_avail--; 274715516c77SSepherosa Ziehau SLIST_REMOVE_HEAD(&txr->hn_txlist, link); 274815516c77SSepherosa Ziehau } 274915516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 275015516c77SSepherosa Ziehau #else 275115516c77SSepherosa Ziehau txd = buf_ring_dequeue_sc(txr->hn_txdesc_br); 275215516c77SSepherosa Ziehau #endif 275315516c77SSepherosa Ziehau 275415516c77SSepherosa Ziehau if (txd != NULL) { 275515516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 275685e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 275715516c77SSepherosa Ziehau atomic_subtract_int(&txr->hn_txdesc_avail, 1); 275815516c77SSepherosa Ziehau #endif 275985e4ae1eSSepherosa Ziehau #endif /* HN_USE_TXDESC_BUFRING */ 276015516c77SSepherosa Ziehau KASSERT(txd->m == NULL && txd->refs == 0 && 2761dc13fee6SSepherosa Ziehau STAILQ_EMPTY(&txd->agg_list) && 276215516c77SSepherosa Ziehau txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 2763dc13fee6SSepherosa Ziehau txd->chim_size == 0 && 276415516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONLIST) && 2765dc13fee6SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONAGG) == 0 && 276615516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd")); 276715516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_ONLIST; 276815516c77SSepherosa Ziehau txd->refs = 1; 276915516c77SSepherosa Ziehau } 277015516c77SSepherosa Ziehau return txd; 277115516c77SSepherosa Ziehau } 277215516c77SSepherosa Ziehau 277315516c77SSepherosa Ziehau static __inline void 277415516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd) 277515516c77SSepherosa Ziehau { 277615516c77SSepherosa Ziehau 277715516c77SSepherosa Ziehau /* 0->1 transition will never work */ 277825641fc7SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 277915516c77SSepherosa Ziehau atomic_add_int(&txd->refs, 1); 278015516c77SSepherosa Ziehau } 278115516c77SSepherosa Ziehau 2782dc13fee6SSepherosa Ziehau static __inline void 2783dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd) 2784dc13fee6SSepherosa Ziehau { 2785dc13fee6SSepherosa Ziehau 2786dc13fee6SSepherosa Ziehau KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2787dc13fee6SSepherosa Ziehau ("recursive aggregation on aggregating txdesc")); 2788dc13fee6SSepherosa Ziehau 2789dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2790dc13fee6SSepherosa Ziehau ("already aggregated")); 2791dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&txd->agg_list), 2792dc13fee6SSepherosa Ziehau ("recursive aggregation on to-be-aggregated txdesc")); 2793dc13fee6SSepherosa Ziehau 2794dc13fee6SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONAGG; 2795dc13fee6SSepherosa Ziehau STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link); 2796dc13fee6SSepherosa Ziehau } 2797dc13fee6SSepherosa Ziehau 279815516c77SSepherosa Ziehau static bool 279915516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr) 280015516c77SSepherosa Ziehau { 280115516c77SSepherosa Ziehau bool pending = false; 280215516c77SSepherosa Ziehau 280315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 280415516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 280515516c77SSepherosa Ziehau if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt) 280615516c77SSepherosa Ziehau pending = true; 280715516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 280815516c77SSepherosa Ziehau #else 280915516c77SSepherosa Ziehau if (!buf_ring_full(txr->hn_txdesc_br)) 281015516c77SSepherosa Ziehau pending = true; 281115516c77SSepherosa Ziehau #endif 281215516c77SSepherosa Ziehau return (pending); 281315516c77SSepherosa Ziehau } 281415516c77SSepherosa Ziehau 281515516c77SSepherosa Ziehau static __inline void 281615516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr) 281715516c77SSepherosa Ziehau { 281815516c77SSepherosa Ziehau txr->hn_has_txeof = 0; 281915516c77SSepherosa Ziehau txr->hn_txeof(txr); 282015516c77SSepherosa Ziehau } 282115516c77SSepherosa Ziehau 282215516c77SSepherosa Ziehau static void 282315516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc, 282415516c77SSepherosa Ziehau struct vmbus_channel *chan, const void *data __unused, int dlen __unused) 282515516c77SSepherosa Ziehau { 282615516c77SSepherosa Ziehau struct hn_txdesc *txd = sndc->hn_cbarg; 282715516c77SSepherosa Ziehau struct hn_tx_ring *txr; 282815516c77SSepherosa Ziehau 282915516c77SSepherosa Ziehau txr = txd->txr; 283015516c77SSepherosa Ziehau KASSERT(txr->hn_chan == chan, 283115516c77SSepherosa Ziehau ("channel mismatch, on chan%u, should be chan%u", 2832aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan))); 283315516c77SSepherosa Ziehau 283415516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 283515516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 283615516c77SSepherosa Ziehau 283715516c77SSepherosa Ziehau ++txr->hn_txdone_cnt; 283815516c77SSepherosa Ziehau if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) { 283915516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 284015516c77SSepherosa Ziehau if (txr->hn_oactive) 284115516c77SSepherosa Ziehau hn_txeof(txr); 284215516c77SSepherosa Ziehau } 284315516c77SSepherosa Ziehau } 284415516c77SSepherosa Ziehau 284515516c77SSepherosa Ziehau static void 284615516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr) 284715516c77SSepherosa Ziehau { 284815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 284915516c77SSepherosa Ziehau tcp_lro_flush_all(&rxr->hn_lro); 285015516c77SSepherosa Ziehau #endif 285115516c77SSepherosa Ziehau 285215516c77SSepherosa Ziehau /* 285315516c77SSepherosa Ziehau * NOTE: 285415516c77SSepherosa Ziehau * 'txr' could be NULL, if multiple channels and 285515516c77SSepherosa Ziehau * ifnet.if_start method are enabled. 285615516c77SSepherosa Ziehau */ 285715516c77SSepherosa Ziehau if (txr == NULL || !txr->hn_has_txeof) 285815516c77SSepherosa Ziehau return; 285915516c77SSepherosa Ziehau 286015516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 286115516c77SSepherosa Ziehau hn_txeof(txr); 286215516c77SSepherosa Ziehau } 286315516c77SSepherosa Ziehau 286415516c77SSepherosa Ziehau static __inline uint32_t 286515516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs) 286615516c77SSepherosa Ziehau { 286715516c77SSepherosa Ziehau 286815516c77SSepherosa Ziehau KASSERT(ofs >= sizeof(struct rndis_packet_msg), 286915516c77SSepherosa Ziehau ("invalid RNDIS packet msg offset %u", ofs)); 287015516c77SSepherosa Ziehau return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset)); 287115516c77SSepherosa Ziehau } 287215516c77SSepherosa Ziehau 287315516c77SSepherosa Ziehau static __inline void * 287415516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize, 287515516c77SSepherosa Ziehau size_t pi_dlen, uint32_t pi_type) 287615516c77SSepherosa Ziehau { 287715516c77SSepherosa Ziehau const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen); 287815516c77SSepherosa Ziehau struct rndis_pktinfo *pi; 287915516c77SSepherosa Ziehau 288015516c77SSepherosa Ziehau KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0, 288115516c77SSepherosa Ziehau ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen)); 288215516c77SSepherosa Ziehau 288315516c77SSepherosa Ziehau /* 288415516c77SSepherosa Ziehau * Per-packet-info does not move; it only grows. 288515516c77SSepherosa Ziehau * 288615516c77SSepherosa Ziehau * NOTE: 288715516c77SSepherosa Ziehau * rm_pktinfooffset in this phase counts from the beginning 288815516c77SSepherosa Ziehau * of rndis_packet_msg. 288915516c77SSepherosa Ziehau */ 289015516c77SSepherosa Ziehau KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize, 289115516c77SSepherosa Ziehau ("%u pktinfo overflows RNDIS packet msg", pi_type)); 289215516c77SSepherosa Ziehau pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset + 289315516c77SSepherosa Ziehau pkt->rm_pktinfolen); 289415516c77SSepherosa Ziehau pkt->rm_pktinfolen += pi_size; 289515516c77SSepherosa Ziehau 289615516c77SSepherosa Ziehau pi->rm_size = pi_size; 289715516c77SSepherosa Ziehau pi->rm_type = pi_type; 289815516c77SSepherosa Ziehau pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET; 289915516c77SSepherosa Ziehau 290015516c77SSepherosa Ziehau return (pi->rm_data); 290115516c77SSepherosa Ziehau } 290215516c77SSepherosa Ziehau 2903dc13fee6SSepherosa Ziehau static __inline int 2904dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr) 2905dc13fee6SSepherosa Ziehau { 2906dc13fee6SSepherosa Ziehau struct hn_txdesc *txd; 2907dc13fee6SSepherosa Ziehau struct mbuf *m; 2908dc13fee6SSepherosa Ziehau int error, pkts; 2909dc13fee6SSepherosa Ziehau 2910dc13fee6SSepherosa Ziehau txd = txr->hn_agg_txd; 2911dc13fee6SSepherosa Ziehau KASSERT(txd != NULL, ("no aggregate txdesc")); 2912dc13fee6SSepherosa Ziehau 2913dc13fee6SSepherosa Ziehau /* 2914dc13fee6SSepherosa Ziehau * Since hn_txpkt() will reset this temporary stat, save 2915dc13fee6SSepherosa Ziehau * it now, so that oerrors can be updated properly, if 2916dc13fee6SSepherosa Ziehau * hn_txpkt() ever fails. 2917dc13fee6SSepherosa Ziehau */ 2918dc13fee6SSepherosa Ziehau pkts = txr->hn_stat_pkts; 2919dc13fee6SSepherosa Ziehau 2920dc13fee6SSepherosa Ziehau /* 2921dc13fee6SSepherosa Ziehau * Since txd's mbuf will _not_ be freed upon hn_txpkt() 2922dc13fee6SSepherosa Ziehau * failure, save it for later freeing, if hn_txpkt() ever 2923dc13fee6SSepherosa Ziehau * fails. 2924dc13fee6SSepherosa Ziehau */ 2925dc13fee6SSepherosa Ziehau m = txd->m; 2926dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 2927dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 2928dc13fee6SSepherosa Ziehau /* txd is freed, but m is not. */ 2929dc13fee6SSepherosa Ziehau m_freem(m); 2930dc13fee6SSepherosa Ziehau 2931dc13fee6SSepherosa Ziehau txr->hn_flush_failed++; 2932dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts); 2933dc13fee6SSepherosa Ziehau } 2934dc13fee6SSepherosa Ziehau 2935dc13fee6SSepherosa Ziehau /* Reset all aggregation states. */ 2936dc13fee6SSepherosa Ziehau txr->hn_agg_txd = NULL; 2937dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = 0; 2938dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 2939dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = NULL; 2940dc13fee6SSepherosa Ziehau 2941dc13fee6SSepherosa Ziehau return (error); 2942dc13fee6SSepherosa Ziehau } 2943dc13fee6SSepherosa Ziehau 2944dc13fee6SSepherosa Ziehau static void * 2945dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 2946dc13fee6SSepherosa Ziehau int pktsize) 2947dc13fee6SSepherosa Ziehau { 2948dc13fee6SSepherosa Ziehau void *chim; 2949dc13fee6SSepherosa Ziehau 2950dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 2951dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) { 2952dc13fee6SSepherosa Ziehau struct hn_txdesc *agg_txd = txr->hn_agg_txd; 2953dc13fee6SSepherosa Ziehau struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt; 2954dc13fee6SSepherosa Ziehau int olen; 2955dc13fee6SSepherosa Ziehau 2956dc13fee6SSepherosa Ziehau /* 2957dc13fee6SSepherosa Ziehau * Update the previous RNDIS packet's total length, 2958dc13fee6SSepherosa Ziehau * it can be increased due to the mandatory alignment 2959dc13fee6SSepherosa Ziehau * padding for this RNDIS packet. And update the 2960dc13fee6SSepherosa Ziehau * aggregating txdesc's chimney sending buffer size 2961dc13fee6SSepherosa Ziehau * accordingly. 2962dc13fee6SSepherosa Ziehau * 2963dc13fee6SSepherosa Ziehau * XXX 2964dc13fee6SSepherosa Ziehau * Zero-out the padding, as required by the RNDIS spec. 2965dc13fee6SSepherosa Ziehau */ 2966dc13fee6SSepherosa Ziehau olen = pkt->rm_len; 2967dc13fee6SSepherosa Ziehau pkt->rm_len = roundup2(olen, txr->hn_agg_align); 2968dc13fee6SSepherosa Ziehau agg_txd->chim_size += pkt->rm_len - olen; 2969dc13fee6SSepherosa Ziehau 2970dc13fee6SSepherosa Ziehau /* Link this txdesc to the parent. */ 2971dc13fee6SSepherosa Ziehau hn_txdesc_agg(agg_txd, txd); 2972dc13fee6SSepherosa Ziehau 2973dc13fee6SSepherosa Ziehau chim = (uint8_t *)pkt + pkt->rm_len; 2974dc13fee6SSepherosa Ziehau /* Save the current packet for later fixup. */ 2975dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 2976dc13fee6SSepherosa Ziehau 2977dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft--; 2978dc13fee6SSepherosa Ziehau txr->hn_agg_szleft -= pktsize; 2979dc13fee6SSepherosa Ziehau if (txr->hn_agg_szleft <= 2980dc13fee6SSepherosa Ziehau HN_PKTSIZE_MIN(txr->hn_agg_align)) { 2981dc13fee6SSepherosa Ziehau /* 2982dc13fee6SSepherosa Ziehau * Probably can't aggregate more packets, 2983dc13fee6SSepherosa Ziehau * flush this aggregating txdesc proactively. 2984dc13fee6SSepherosa Ziehau */ 2985dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 2986dc13fee6SSepherosa Ziehau } 2987dc13fee6SSepherosa Ziehau /* Done! */ 2988dc13fee6SSepherosa Ziehau return (chim); 2989dc13fee6SSepherosa Ziehau } 2990dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 2991dc13fee6SSepherosa Ziehau } 2992dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 2993dc13fee6SSepherosa Ziehau 2994dc13fee6SSepherosa Ziehau txr->hn_tx_chimney_tried++; 2995dc13fee6SSepherosa Ziehau txd->chim_index = hn_chim_alloc(txr->hn_sc); 2996dc13fee6SSepherosa Ziehau if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID) 2997dc13fee6SSepherosa Ziehau return (NULL); 2998dc13fee6SSepherosa Ziehau txr->hn_tx_chimney++; 2999dc13fee6SSepherosa Ziehau 3000dc13fee6SSepherosa Ziehau chim = txr->hn_sc->hn_chim + 3001dc13fee6SSepherosa Ziehau (txd->chim_index * txr->hn_sc->hn_chim_szmax); 3002dc13fee6SSepherosa Ziehau 3003dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktmax > 1 && 3004dc13fee6SSepherosa Ziehau txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) { 3005dc13fee6SSepherosa Ziehau txr->hn_agg_txd = txd; 3006dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1; 3007dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize; 3008dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 3009dc13fee6SSepherosa Ziehau } 3010dc13fee6SSepherosa Ziehau return (chim); 3011dc13fee6SSepherosa Ziehau } 3012dc13fee6SSepherosa Ziehau 301315516c77SSepherosa Ziehau /* 301415516c77SSepherosa Ziehau * NOTE: 301515516c77SSepherosa Ziehau * If this function fails, then both txd and m_head0 will be freed. 301615516c77SSepherosa Ziehau */ 301715516c77SSepherosa Ziehau static int 3018dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 3019dc13fee6SSepherosa Ziehau struct mbuf **m_head0) 302015516c77SSepherosa Ziehau { 302115516c77SSepherosa Ziehau bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX]; 302215516c77SSepherosa Ziehau int error, nsegs, i; 302315516c77SSepherosa Ziehau struct mbuf *m_head = *m_head0; 302415516c77SSepherosa Ziehau struct rndis_packet_msg *pkt; 302515516c77SSepherosa Ziehau uint32_t *pi_data; 30268966e5d5SSepherosa Ziehau void *chim = NULL; 3027dc13fee6SSepherosa Ziehau int pkt_hlen, pkt_size; 302815516c77SSepherosa Ziehau 302915516c77SSepherosa Ziehau pkt = txd->rndis_pkt; 3030dc13fee6SSepherosa Ziehau pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align); 3031dc13fee6SSepherosa Ziehau if (pkt_size < txr->hn_chim_size) { 3032dc13fee6SSepherosa Ziehau chim = hn_try_txagg(ifp, txr, txd, pkt_size); 3033dc13fee6SSepherosa Ziehau if (chim != NULL) 30348966e5d5SSepherosa Ziehau pkt = chim; 3035dc13fee6SSepherosa Ziehau } else { 3036dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 3037dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 30388966e5d5SSepherosa Ziehau } 30398966e5d5SSepherosa Ziehau 304015516c77SSepherosa Ziehau pkt->rm_type = REMOTE_NDIS_PACKET_MSG; 30418fe90f73SSepherosa Ziehau pkt->rm_len = m_head->m_pkthdr.len; 30429130c4f7SSepherosa Ziehau pkt->rm_dataoffset = 0; 304315516c77SSepherosa Ziehau pkt->rm_datalen = m_head->m_pkthdr.len; 3044dc13fee6SSepherosa Ziehau pkt->rm_oobdataoffset = 0; 3045dc13fee6SSepherosa Ziehau pkt->rm_oobdatalen = 0; 3046dc13fee6SSepherosa Ziehau pkt->rm_oobdataelements = 0; 304715516c77SSepherosa Ziehau pkt->rm_pktinfooffset = sizeof(*pkt); 304815516c77SSepherosa Ziehau pkt->rm_pktinfolen = 0; 3049dc13fee6SSepherosa Ziehau pkt->rm_vchandle = 0; 3050dc13fee6SSepherosa Ziehau pkt->rm_reserved = 0; 305115516c77SSepherosa Ziehau 305215516c77SSepherosa Ziehau if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) { 305315516c77SSepherosa Ziehau /* 305415516c77SSepherosa Ziehau * Set the hash value for this packet, so that the host could 305515516c77SSepherosa Ziehau * dispatch the TX done event for this packet back to this TX 305615516c77SSepherosa Ziehau * ring's channel. 305715516c77SSepherosa Ziehau */ 305815516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 305915516c77SSepherosa Ziehau HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL); 306015516c77SSepherosa Ziehau *pi_data = txr->hn_tx_idx; 306115516c77SSepherosa Ziehau } 306215516c77SSepherosa Ziehau 306315516c77SSepherosa Ziehau if (m_head->m_flags & M_VLANTAG) { 306415516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 306515516c77SSepherosa Ziehau NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN); 306615516c77SSepherosa Ziehau *pi_data = NDIS_VLAN_INFO_MAKE( 306715516c77SSepherosa Ziehau EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag), 306815516c77SSepherosa Ziehau EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag), 306915516c77SSepherosa Ziehau EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag)); 307015516c77SSepherosa Ziehau } 307115516c77SSepherosa Ziehau 307215516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 307315516c77SSepherosa Ziehau #if defined(INET6) || defined(INET) 307415516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 307515516c77SSepherosa Ziehau NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); 307615516c77SSepherosa Ziehau #ifdef INET 307715516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 3078c49d47daSSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV4( 3079c49d47daSSepherosa Ziehau m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen, 308015516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 308115516c77SSepherosa Ziehau } 308215516c77SSepherosa Ziehau #endif 308315516c77SSepherosa Ziehau #if defined(INET6) && defined(INET) 308415516c77SSepherosa Ziehau else 308515516c77SSepherosa Ziehau #endif 308615516c77SSepherosa Ziehau #ifdef INET6 308715516c77SSepherosa Ziehau { 3088c49d47daSSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV6( 3089c49d47daSSepherosa Ziehau m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen, 309015516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 309115516c77SSepherosa Ziehau } 309215516c77SSepherosa Ziehau #endif 309315516c77SSepherosa Ziehau #endif /* INET6 || INET */ 309415516c77SSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) { 309515516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 309615516c77SSepherosa Ziehau NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); 309715516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & 309815516c77SSepherosa Ziehau (CSUM_IP6_TCP | CSUM_IP6_UDP)) { 309915516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV6; 310015516c77SSepherosa Ziehau } else { 310115516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV4; 310215516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 310315516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_IPCS; 310415516c77SSepherosa Ziehau } 310515516c77SSepherosa Ziehau 3106c49d47daSSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & 3107c49d47daSSepherosa Ziehau (CSUM_IP_TCP | CSUM_IP6_TCP)) { 3108c49d47daSSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_MKTCPCS( 3109c49d47daSSepherosa Ziehau m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen); 3110c49d47daSSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & 3111c49d47daSSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP6_UDP)) { 3112c49d47daSSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_MKUDPCS( 3113c49d47daSSepherosa Ziehau m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen); 3114c49d47daSSepherosa Ziehau } 311515516c77SSepherosa Ziehau } 311615516c77SSepherosa Ziehau 3117dc13fee6SSepherosa Ziehau pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; 31188fe90f73SSepherosa Ziehau /* Fixup RNDIS packet message total length */ 31198fe90f73SSepherosa Ziehau pkt->rm_len += pkt_hlen; 312015516c77SSepherosa Ziehau /* Convert RNDIS packet message offsets */ 31219130c4f7SSepherosa Ziehau pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen); 312215516c77SSepherosa Ziehau pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset); 312315516c77SSepherosa Ziehau 312415516c77SSepherosa Ziehau /* 31258966e5d5SSepherosa Ziehau * Fast path: Chimney sending. 312615516c77SSepherosa Ziehau */ 31278966e5d5SSepherosa Ziehau if (chim != NULL) { 3128dc13fee6SSepherosa Ziehau struct hn_txdesc *tgt_txd = txd; 3129dc13fee6SSepherosa Ziehau 3130dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 3131dc13fee6SSepherosa Ziehau tgt_txd = txr->hn_agg_txd; 3132dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 3133dc13fee6SSepherosa Ziehau *m_head0 = NULL; 3134dc13fee6SSepherosa Ziehau #endif 3135dc13fee6SSepherosa Ziehau } 3136dc13fee6SSepherosa Ziehau 3137dc13fee6SSepherosa Ziehau KASSERT(pkt == chim, 3138dc13fee6SSepherosa Ziehau ("RNDIS pkt not in chimney sending buffer")); 3139dc13fee6SSepherosa Ziehau KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID, 3140dc13fee6SSepherosa Ziehau ("chimney sending buffer is not used")); 3141dc13fee6SSepherosa Ziehau tgt_txd->chim_size += pkt->rm_len; 314215516c77SSepherosa Ziehau 31438966e5d5SSepherosa Ziehau m_copydata(m_head, 0, m_head->m_pkthdr.len, 3144dc13fee6SSepherosa Ziehau ((uint8_t *)chim) + pkt_hlen); 314515516c77SSepherosa Ziehau 314615516c77SSepherosa Ziehau txr->hn_gpa_cnt = 0; 314715516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_chim; 314815516c77SSepherosa Ziehau goto done; 314915516c77SSepherosa Ziehau } 3150dc13fee6SSepherosa Ziehau 3151dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc")); 31528966e5d5SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 31538966e5d5SSepherosa Ziehau ("chimney buffer is used")); 31548966e5d5SSepherosa Ziehau KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc")); 315515516c77SSepherosa Ziehau 315615516c77SSepherosa Ziehau error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs); 3157dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 315815516c77SSepherosa Ziehau int freed; 315915516c77SSepherosa Ziehau 316015516c77SSepherosa Ziehau /* 316115516c77SSepherosa Ziehau * This mbuf is not linked w/ the txd yet, so free it now. 316215516c77SSepherosa Ziehau */ 316315516c77SSepherosa Ziehau m_freem(m_head); 316415516c77SSepherosa Ziehau *m_head0 = NULL; 316515516c77SSepherosa Ziehau 316615516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 316715516c77SSepherosa Ziehau KASSERT(freed != 0, 316815516c77SSepherosa Ziehau ("fail to free txd upon txdma error")); 316915516c77SSepherosa Ziehau 317015516c77SSepherosa Ziehau txr->hn_txdma_failed++; 3171dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 317215516c77SSepherosa Ziehau return error; 317315516c77SSepherosa Ziehau } 317415516c77SSepherosa Ziehau *m_head0 = m_head; 317515516c77SSepherosa Ziehau 317615516c77SSepherosa Ziehau /* +1 RNDIS packet message */ 317715516c77SSepherosa Ziehau txr->hn_gpa_cnt = nsegs + 1; 317815516c77SSepherosa Ziehau 317915516c77SSepherosa Ziehau /* send packet with page buffer */ 318015516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr); 318115516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK; 3182dc13fee6SSepherosa Ziehau txr->hn_gpa[0].gpa_len = pkt_hlen; 318315516c77SSepherosa Ziehau 318415516c77SSepherosa Ziehau /* 318515516c77SSepherosa Ziehau * Fill the page buffers with mbuf info after the page 318615516c77SSepherosa Ziehau * buffer for RNDIS packet message. 318715516c77SSepherosa Ziehau */ 318815516c77SSepherosa Ziehau for (i = 0; i < nsegs; ++i) { 318915516c77SSepherosa Ziehau struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1]; 319015516c77SSepherosa Ziehau 319115516c77SSepherosa Ziehau gpa->gpa_page = atop(segs[i].ds_addr); 319215516c77SSepherosa Ziehau gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK; 319315516c77SSepherosa Ziehau gpa->gpa_len = segs[i].ds_len; 319415516c77SSepherosa Ziehau } 319515516c77SSepherosa Ziehau 319615516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 319715516c77SSepherosa Ziehau txd->chim_size = 0; 319815516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_sglist; 319915516c77SSepherosa Ziehau done: 320015516c77SSepherosa Ziehau txd->m = m_head; 320115516c77SSepherosa Ziehau 320215516c77SSepherosa Ziehau /* Set the completion routine */ 320315516c77SSepherosa Ziehau hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd); 320415516c77SSepherosa Ziehau 3205dc13fee6SSepherosa Ziehau /* Update temporary stats for later use. */ 3206dc13fee6SSepherosa Ziehau txr->hn_stat_pkts++; 3207dc13fee6SSepherosa Ziehau txr->hn_stat_size += m_head->m_pkthdr.len; 3208dc13fee6SSepherosa Ziehau if (m_head->m_flags & M_MCAST) 3209dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts++; 3210dc13fee6SSepherosa Ziehau 321115516c77SSepherosa Ziehau return 0; 321215516c77SSepherosa Ziehau } 321315516c77SSepherosa Ziehau 321415516c77SSepherosa Ziehau /* 321515516c77SSepherosa Ziehau * NOTE: 321615516c77SSepherosa Ziehau * If this function fails, then txd will be freed, but the mbuf 321715516c77SSepherosa Ziehau * associated w/ the txd will _not_ be freed. 321815516c77SSepherosa Ziehau */ 321915516c77SSepherosa Ziehau static int 322015516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd) 322115516c77SSepherosa Ziehau { 32228e7d3136SSepherosa Ziehau int error, send_failed = 0, has_bpf; 322315516c77SSepherosa Ziehau 322415516c77SSepherosa Ziehau again: 32258e7d3136SSepherosa Ziehau has_bpf = bpf_peers_present(ifp->if_bpf); 32268e7d3136SSepherosa Ziehau if (has_bpf) { 322715516c77SSepherosa Ziehau /* 32288e7d3136SSepherosa Ziehau * Make sure that this txd and any aggregated txds are not 32298e7d3136SSepherosa Ziehau * freed before ETHER_BPF_MTAP. 323015516c77SSepherosa Ziehau */ 323115516c77SSepherosa Ziehau hn_txdesc_hold(txd); 32328e7d3136SSepherosa Ziehau } 323315516c77SSepherosa Ziehau error = txr->hn_sendpkt(txr, txd); 323415516c77SSepherosa Ziehau if (!error) { 32358e7d3136SSepherosa Ziehau if (has_bpf) { 3236dc13fee6SSepherosa Ziehau const struct hn_txdesc *tmp_txd; 3237dc13fee6SSepherosa Ziehau 323815516c77SSepherosa Ziehau ETHER_BPF_MTAP(ifp, txd->m); 3239dc13fee6SSepherosa Ziehau STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link) 3240dc13fee6SSepherosa Ziehau ETHER_BPF_MTAP(ifp, tmp_txd->m); 3241dc13fee6SSepherosa Ziehau } 3242dc13fee6SSepherosa Ziehau 3243dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts); 324423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 324523bf9e15SSepherosa Ziehau if (!hn_use_if_start) 324623bf9e15SSepherosa Ziehau #endif 324723bf9e15SSepherosa Ziehau { 324815516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, 3249dc13fee6SSepherosa Ziehau txr->hn_stat_size); 3250dc13fee6SSepherosa Ziehau if (txr->hn_stat_mcasts != 0) { 3251dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 3252dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts); 325315516c77SSepherosa Ziehau } 3254dc13fee6SSepherosa Ziehau } 3255dc13fee6SSepherosa Ziehau txr->hn_pkts += txr->hn_stat_pkts; 3256dc13fee6SSepherosa Ziehau txr->hn_sends++; 325715516c77SSepherosa Ziehau } 32588e7d3136SSepherosa Ziehau if (has_bpf) 325915516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 326015516c77SSepherosa Ziehau 326115516c77SSepherosa Ziehau if (__predict_false(error)) { 326215516c77SSepherosa Ziehau int freed; 326315516c77SSepherosa Ziehau 326415516c77SSepherosa Ziehau /* 326515516c77SSepherosa Ziehau * This should "really rarely" happen. 326615516c77SSepherosa Ziehau * 326715516c77SSepherosa Ziehau * XXX Too many RX to be acked or too many sideband 326815516c77SSepherosa Ziehau * commands to run? Ask netvsc_channel_rollup() 326915516c77SSepherosa Ziehau * to kick start later. 327015516c77SSepherosa Ziehau */ 327115516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 327215516c77SSepherosa Ziehau if (!send_failed) { 327315516c77SSepherosa Ziehau txr->hn_send_failed++; 327415516c77SSepherosa Ziehau send_failed = 1; 327515516c77SSepherosa Ziehau /* 327615516c77SSepherosa Ziehau * Try sending again after set hn_has_txeof; 327715516c77SSepherosa Ziehau * in case that we missed the last 327815516c77SSepherosa Ziehau * netvsc_channel_rollup(). 327915516c77SSepherosa Ziehau */ 328015516c77SSepherosa Ziehau goto again; 328115516c77SSepherosa Ziehau } 328215516c77SSepherosa Ziehau if_printf(ifp, "send failed\n"); 328315516c77SSepherosa Ziehau 328415516c77SSepherosa Ziehau /* 328515516c77SSepherosa Ziehau * Caller will perform further processing on the 328615516c77SSepherosa Ziehau * associated mbuf, so don't free it in hn_txdesc_put(); 328715516c77SSepherosa Ziehau * only unload it from the DMA map in hn_txdesc_put(), 328815516c77SSepherosa Ziehau * if it was loaded. 328915516c77SSepherosa Ziehau */ 329015516c77SSepherosa Ziehau txd->m = NULL; 329115516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 329215516c77SSepherosa Ziehau KASSERT(freed != 0, 329315516c77SSepherosa Ziehau ("fail to free txd upon send error")); 329415516c77SSepherosa Ziehau 329515516c77SSepherosa Ziehau txr->hn_send_failed++; 329615516c77SSepherosa Ziehau } 3297dc13fee6SSepherosa Ziehau 3298dc13fee6SSepherosa Ziehau /* Reset temporary stats, after this sending is done. */ 3299dc13fee6SSepherosa Ziehau txr->hn_stat_size = 0; 3300dc13fee6SSepherosa Ziehau txr->hn_stat_pkts = 0; 3301dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts = 0; 3302dc13fee6SSepherosa Ziehau 3303dc13fee6SSepherosa Ziehau return (error); 330415516c77SSepherosa Ziehau } 330515516c77SSepherosa Ziehau 330615516c77SSepherosa Ziehau /* 330715516c77SSepherosa Ziehau * Append the specified data to the indicated mbuf chain, 330815516c77SSepherosa Ziehau * Extend the mbuf chain if the new data does not fit in 330915516c77SSepherosa Ziehau * existing space. 331015516c77SSepherosa Ziehau * 331115516c77SSepherosa Ziehau * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c. 331215516c77SSepherosa Ziehau * There should be an equivalent in the kernel mbuf code, 331315516c77SSepherosa Ziehau * but there does not appear to be one yet. 331415516c77SSepherosa Ziehau * 331515516c77SSepherosa Ziehau * Differs from m_append() in that additional mbufs are 331615516c77SSepherosa Ziehau * allocated with cluster size MJUMPAGESIZE, and filled 331715516c77SSepherosa Ziehau * accordingly. 331815516c77SSepherosa Ziehau * 331915516c77SSepherosa Ziehau * Return 1 if able to complete the job; otherwise 0. 332015516c77SSepherosa Ziehau */ 332115516c77SSepherosa Ziehau static int 332215516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp) 332315516c77SSepherosa Ziehau { 332415516c77SSepherosa Ziehau struct mbuf *m, *n; 332515516c77SSepherosa Ziehau int remainder, space; 332615516c77SSepherosa Ziehau 332715516c77SSepherosa Ziehau for (m = m0; m->m_next != NULL; m = m->m_next) 332815516c77SSepherosa Ziehau ; 332915516c77SSepherosa Ziehau remainder = len; 333015516c77SSepherosa Ziehau space = M_TRAILINGSPACE(m); 333115516c77SSepherosa Ziehau if (space > 0) { 333215516c77SSepherosa Ziehau /* 333315516c77SSepherosa Ziehau * Copy into available space. 333415516c77SSepherosa Ziehau */ 333515516c77SSepherosa Ziehau if (space > remainder) 333615516c77SSepherosa Ziehau space = remainder; 333715516c77SSepherosa Ziehau bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 333815516c77SSepherosa Ziehau m->m_len += space; 333915516c77SSepherosa Ziehau cp += space; 334015516c77SSepherosa Ziehau remainder -= space; 334115516c77SSepherosa Ziehau } 334215516c77SSepherosa Ziehau while (remainder > 0) { 334315516c77SSepherosa Ziehau /* 334415516c77SSepherosa Ziehau * Allocate a new mbuf; could check space 334515516c77SSepherosa Ziehau * and allocate a cluster instead. 334615516c77SSepherosa Ziehau */ 334715516c77SSepherosa Ziehau n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE); 334815516c77SSepherosa Ziehau if (n == NULL) 334915516c77SSepherosa Ziehau break; 335015516c77SSepherosa Ziehau n->m_len = min(MJUMPAGESIZE, remainder); 335115516c77SSepherosa Ziehau bcopy(cp, mtod(n, caddr_t), n->m_len); 335215516c77SSepherosa Ziehau cp += n->m_len; 335315516c77SSepherosa Ziehau remainder -= n->m_len; 335415516c77SSepherosa Ziehau m->m_next = n; 335515516c77SSepherosa Ziehau m = n; 335615516c77SSepherosa Ziehau } 335715516c77SSepherosa Ziehau if (m0->m_flags & M_PKTHDR) 335815516c77SSepherosa Ziehau m0->m_pkthdr.len += len - remainder; 335915516c77SSepherosa Ziehau 336015516c77SSepherosa Ziehau return (remainder == 0); 336115516c77SSepherosa Ziehau } 336215516c77SSepherosa Ziehau 336315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 336415516c77SSepherosa Ziehau static __inline int 336515516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m) 336615516c77SSepherosa Ziehau { 336715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 336815516c77SSepherosa Ziehau if (hn_lro_mbufq_depth) { 336915516c77SSepherosa Ziehau tcp_lro_queue_mbuf(lc, m); 337015516c77SSepherosa Ziehau return 0; 337115516c77SSepherosa Ziehau } 337215516c77SSepherosa Ziehau #endif 337315516c77SSepherosa Ziehau return tcp_lro_rx(lc, m, 0); 337415516c77SSepherosa Ziehau } 337515516c77SSepherosa Ziehau #endif 337615516c77SSepherosa Ziehau 337715516c77SSepherosa Ziehau static int 337815516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, 337915516c77SSepherosa Ziehau const struct hn_rxinfo *info) 338015516c77SSepherosa Ziehau { 3381a97fff19SSepherosa Ziehau struct ifnet *ifp, *hn_ifp = rxr->hn_ifp; 338215516c77SSepherosa Ziehau struct mbuf *m_new; 3383642ec226SSepherosa Ziehau int size, do_lro = 0, do_csum = 1, is_vf = 0; 3384642ec226SSepherosa Ziehau int hash_type = M_HASHTYPE_NONE; 338515516c77SSepherosa Ziehau 3386642ec226SSepherosa Ziehau ifp = hn_ifp; 3387642ec226SSepherosa Ziehau if (rxr->hn_rxvf_ifp != NULL) { 3388a97fff19SSepherosa Ziehau /* 3389642ec226SSepherosa Ziehau * Non-transparent mode VF; pretend this packet is from 3390642ec226SSepherosa Ziehau * the VF. 3391a97fff19SSepherosa Ziehau */ 3392642ec226SSepherosa Ziehau ifp = rxr->hn_rxvf_ifp; 3393642ec226SSepherosa Ziehau is_vf = 1; 3394642ec226SSepherosa Ziehau } else if (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF) { 3395642ec226SSepherosa Ziehau /* Transparent mode VF. */ 3396642ec226SSepherosa Ziehau is_vf = 1; 3397642ec226SSepherosa Ziehau } 33985bdfd3fdSDexuan Cui 3399b3b75d9cSSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 3400b3b75d9cSSepherosa Ziehau /* 3401b3b75d9cSSepherosa Ziehau * NOTE: 3402b3b75d9cSSepherosa Ziehau * See the NOTE of hn_rndis_init_fixat(). This 3403b3b75d9cSSepherosa Ziehau * function can be reached, immediately after the 3404b3b75d9cSSepherosa Ziehau * RNDIS is initialized but before the ifnet is 3405b3b75d9cSSepherosa Ziehau * setup on the hn_attach() path; drop the unexpected 3406b3b75d9cSSepherosa Ziehau * packets. 3407b3b75d9cSSepherosa Ziehau */ 3408b3b75d9cSSepherosa Ziehau return (0); 3409b3b75d9cSSepherosa Ziehau } 3410b3b75d9cSSepherosa Ziehau 3411a97fff19SSepherosa Ziehau if (__predict_false(dlen < ETHER_HDR_LEN)) { 3412a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1); 3413a97fff19SSepherosa Ziehau return (0); 3414a97fff19SSepherosa Ziehau } 3415a97fff19SSepherosa Ziehau 3416c927d681SDexuan Cui if (dlen <= MHLEN) { 341715516c77SSepherosa Ziehau m_new = m_gethdr(M_NOWAIT, MT_DATA); 341815516c77SSepherosa Ziehau if (m_new == NULL) { 3419a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1); 342015516c77SSepherosa Ziehau return (0); 342115516c77SSepherosa Ziehau } 342215516c77SSepherosa Ziehau memcpy(mtod(m_new, void *), data, dlen); 342315516c77SSepherosa Ziehau m_new->m_pkthdr.len = m_new->m_len = dlen; 342415516c77SSepherosa Ziehau rxr->hn_small_pkts++; 342515516c77SSepherosa Ziehau } else { 342615516c77SSepherosa Ziehau /* 342715516c77SSepherosa Ziehau * Get an mbuf with a cluster. For packets 2K or less, 342815516c77SSepherosa Ziehau * get a standard 2K cluster. For anything larger, get a 342915516c77SSepherosa Ziehau * 4K cluster. Any buffers larger than 4K can cause problems 343015516c77SSepherosa Ziehau * if looped around to the Hyper-V TX channel, so avoid them. 343115516c77SSepherosa Ziehau */ 343215516c77SSepherosa Ziehau size = MCLBYTES; 343315516c77SSepherosa Ziehau if (dlen > MCLBYTES) { 343415516c77SSepherosa Ziehau /* 4096 */ 343515516c77SSepherosa Ziehau size = MJUMPAGESIZE; 343615516c77SSepherosa Ziehau } 343715516c77SSepherosa Ziehau 343815516c77SSepherosa Ziehau m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size); 343915516c77SSepherosa Ziehau if (m_new == NULL) { 3440a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1); 344115516c77SSepherosa Ziehau return (0); 344215516c77SSepherosa Ziehau } 344315516c77SSepherosa Ziehau 344415516c77SSepherosa Ziehau hv_m_append(m_new, dlen, data); 344515516c77SSepherosa Ziehau } 344615516c77SSepherosa Ziehau m_new->m_pkthdr.rcvif = ifp; 344715516c77SSepherosa Ziehau 3448a97fff19SSepherosa Ziehau if (__predict_false((hn_ifp->if_capenable & IFCAP_RXCSUM) == 0)) 344915516c77SSepherosa Ziehau do_csum = 0; 345015516c77SSepherosa Ziehau 345115516c77SSepherosa Ziehau /* receive side checksum offload */ 345215516c77SSepherosa Ziehau if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) { 345315516c77SSepherosa Ziehau /* IP csum offload */ 345415516c77SSepherosa Ziehau if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) { 345515516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 345615516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 345715516c77SSepherosa Ziehau rxr->hn_csum_ip++; 345815516c77SSepherosa Ziehau } 345915516c77SSepherosa Ziehau 346015516c77SSepherosa Ziehau /* TCP/UDP csum offload */ 346115516c77SSepherosa Ziehau if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK | 346215516c77SSepherosa Ziehau NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) { 346315516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 346415516c77SSepherosa Ziehau (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 346515516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 346615516c77SSepherosa Ziehau if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK) 346715516c77SSepherosa Ziehau rxr->hn_csum_tcp++; 346815516c77SSepherosa Ziehau else 346915516c77SSepherosa Ziehau rxr->hn_csum_udp++; 347015516c77SSepherosa Ziehau } 347115516c77SSepherosa Ziehau 347215516c77SSepherosa Ziehau /* 347315516c77SSepherosa Ziehau * XXX 347415516c77SSepherosa Ziehau * As of this write (Oct 28th, 2016), host side will turn 347515516c77SSepherosa Ziehau * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so 347615516c77SSepherosa Ziehau * the do_lro setting here is actually _not_ accurate. We 347715516c77SSepherosa Ziehau * depend on the RSS hash type check to reset do_lro. 347815516c77SSepherosa Ziehau */ 347915516c77SSepherosa Ziehau if ((info->csum_info & 348015516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) == 348115516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) 348215516c77SSepherosa Ziehau do_lro = 1; 348315516c77SSepherosa Ziehau } else { 348415516c77SSepherosa Ziehau const struct ether_header *eh; 348515516c77SSepherosa Ziehau uint16_t etype; 348615516c77SSepherosa Ziehau int hoff; 348715516c77SSepherosa Ziehau 348815516c77SSepherosa Ziehau hoff = sizeof(*eh); 3489a97fff19SSepherosa Ziehau /* Checked at the beginning of this function. */ 3490a97fff19SSepherosa Ziehau KASSERT(m_new->m_len >= hoff, ("not ethernet frame")); 3491a97fff19SSepherosa Ziehau 349215516c77SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 349315516c77SSepherosa Ziehau etype = ntohs(eh->ether_type); 349415516c77SSepherosa Ziehau if (etype == ETHERTYPE_VLAN) { 349515516c77SSepherosa Ziehau const struct ether_vlan_header *evl; 349615516c77SSepherosa Ziehau 349715516c77SSepherosa Ziehau hoff = sizeof(*evl); 349815516c77SSepherosa Ziehau if (m_new->m_len < hoff) 349915516c77SSepherosa Ziehau goto skip; 350015516c77SSepherosa Ziehau evl = mtod(m_new, struct ether_vlan_header *); 350115516c77SSepherosa Ziehau etype = ntohs(evl->evl_proto); 350215516c77SSepherosa Ziehau } 350315516c77SSepherosa Ziehau 350415516c77SSepherosa Ziehau if (etype == ETHERTYPE_IP) { 350515516c77SSepherosa Ziehau int pr; 350615516c77SSepherosa Ziehau 350715516c77SSepherosa Ziehau pr = hn_check_iplen(m_new, hoff); 350815516c77SSepherosa Ziehau if (pr == IPPROTO_TCP) { 350915516c77SSepherosa Ziehau if (do_csum && 351015516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 351115516c77SSepherosa Ziehau HN_TRUST_HCSUM_TCP)) { 351215516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 351315516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 351415516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 351515516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 351615516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 351715516c77SSepherosa Ziehau } 351815516c77SSepherosa Ziehau do_lro = 1; 351915516c77SSepherosa Ziehau } else if (pr == IPPROTO_UDP) { 352015516c77SSepherosa Ziehau if (do_csum && 352115516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 352215516c77SSepherosa Ziehau HN_TRUST_HCSUM_UDP)) { 352315516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 352415516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 352515516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 352615516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 352715516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 352815516c77SSepherosa Ziehau } 352915516c77SSepherosa Ziehau } else if (pr != IPPROTO_DONE && do_csum && 353015516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) { 353115516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 353215516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 353315516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 353415516c77SSepherosa Ziehau } 353515516c77SSepherosa Ziehau } 353615516c77SSepherosa Ziehau } 353715516c77SSepherosa Ziehau skip: 353815516c77SSepherosa Ziehau if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) { 353915516c77SSepherosa Ziehau m_new->m_pkthdr.ether_vtag = EVL_MAKETAG( 354015516c77SSepherosa Ziehau NDIS_VLAN_INFO_ID(info->vlan_info), 354115516c77SSepherosa Ziehau NDIS_VLAN_INFO_PRI(info->vlan_info), 354215516c77SSepherosa Ziehau NDIS_VLAN_INFO_CFI(info->vlan_info)); 354315516c77SSepherosa Ziehau m_new->m_flags |= M_VLANTAG; 354415516c77SSepherosa Ziehau } 354515516c77SSepherosa Ziehau 3546a97fff19SSepherosa Ziehau /* 3547a97fff19SSepherosa Ziehau * If VF is activated (tranparent/non-transparent mode does not 3548a97fff19SSepherosa Ziehau * matter here). 3549a97fff19SSepherosa Ziehau * 3550a97fff19SSepherosa Ziehau * - Disable LRO 3551a97fff19SSepherosa Ziehau * 3552a97fff19SSepherosa Ziehau * hn(4) will only receive broadcast packets, multicast packets, 3553a97fff19SSepherosa Ziehau * TCP SYN and SYN|ACK (in Azure), LRO is useless for these 3554a97fff19SSepherosa Ziehau * packet types. 3555a97fff19SSepherosa Ziehau * 3556a97fff19SSepherosa Ziehau * For non-transparent, we definitely _cannot_ enable LRO at 3557a97fff19SSepherosa Ziehau * all, since the LRO flush will use hn(4) as the receiving 3558a97fff19SSepherosa Ziehau * interface; i.e. hn_ifp->if_input(hn_ifp, m). 3559a97fff19SSepherosa Ziehau */ 3560642ec226SSepherosa Ziehau if (is_vf) 3561642ec226SSepherosa Ziehau do_lro = 0; 3562a97fff19SSepherosa Ziehau 3563642ec226SSepherosa Ziehau /* 3564642ec226SSepherosa Ziehau * If VF is activated (tranparent/non-transparent mode does not 3565642ec226SSepherosa Ziehau * matter here), do _not_ mess with unsupported hash types or 3566642ec226SSepherosa Ziehau * functions. 3567642ec226SSepherosa Ziehau */ 356815516c77SSepherosa Ziehau if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) { 356915516c77SSepherosa Ziehau rxr->hn_rss_pkts++; 357015516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = info->hash_value; 3571642ec226SSepherosa Ziehau if (!is_vf) 357215516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE_HASH; 357315516c77SSepherosa Ziehau if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) == 357415516c77SSepherosa Ziehau NDIS_HASH_FUNCTION_TOEPLITZ) { 3575642ec226SSepherosa Ziehau uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK & 3576642ec226SSepherosa Ziehau rxr->hn_mbuf_hash); 357715516c77SSepherosa Ziehau 357815516c77SSepherosa Ziehau /* 357915516c77SSepherosa Ziehau * NOTE: 358015516c77SSepherosa Ziehau * do_lro is resetted, if the hash types are not TCP 358115516c77SSepherosa Ziehau * related. See the comment in the above csum_flags 358215516c77SSepherosa Ziehau * setup section. 358315516c77SSepherosa Ziehau */ 358415516c77SSepherosa Ziehau switch (type) { 358515516c77SSepherosa Ziehau case NDIS_HASH_IPV4: 358615516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV4; 358715516c77SSepherosa Ziehau do_lro = 0; 358815516c77SSepherosa Ziehau break; 358915516c77SSepherosa Ziehau 359015516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV4: 359115516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV4; 359215516c77SSepherosa Ziehau break; 359315516c77SSepherosa Ziehau 359415516c77SSepherosa Ziehau case NDIS_HASH_IPV6: 359515516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6; 359615516c77SSepherosa Ziehau do_lro = 0; 359715516c77SSepherosa Ziehau break; 359815516c77SSepherosa Ziehau 359915516c77SSepherosa Ziehau case NDIS_HASH_IPV6_EX: 360015516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6_EX; 360115516c77SSepherosa Ziehau do_lro = 0; 360215516c77SSepherosa Ziehau break; 360315516c77SSepherosa Ziehau 360415516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6: 360515516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6; 360615516c77SSepherosa Ziehau break; 360715516c77SSepherosa Ziehau 360815516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6_EX: 360915516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX; 361015516c77SSepherosa Ziehau break; 361115516c77SSepherosa Ziehau } 361215516c77SSepherosa Ziehau } 3613642ec226SSepherosa Ziehau } else if (!is_vf) { 361415516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = rxr->hn_rx_idx; 361515516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE; 361615516c77SSepherosa Ziehau } 361715516c77SSepherosa Ziehau M_HASHTYPE_SET(m_new, hash_type); 361815516c77SSepherosa Ziehau 3619a97fff19SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 3620a97fff19SSepherosa Ziehau if (hn_ifp != ifp) { 3621a97fff19SSepherosa Ziehau const struct ether_header *eh; 3622a97fff19SSepherosa Ziehau 362315516c77SSepherosa Ziehau /* 3624a97fff19SSepherosa Ziehau * Non-transparent mode VF is activated. 362515516c77SSepherosa Ziehau */ 362615516c77SSepherosa Ziehau 3627a97fff19SSepherosa Ziehau /* 3628a97fff19SSepherosa Ziehau * Allow tapping on hn(4). 3629a97fff19SSepherosa Ziehau */ 3630a97fff19SSepherosa Ziehau ETHER_BPF_MTAP(hn_ifp, m_new); 3631a97fff19SSepherosa Ziehau 3632a97fff19SSepherosa Ziehau /* 3633a97fff19SSepherosa Ziehau * Update hn(4)'s stats. 3634a97fff19SSepherosa Ziehau */ 3635a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1); 3636a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len); 3637a97fff19SSepherosa Ziehau /* Checked at the beginning of this function. */ 3638a97fff19SSepherosa Ziehau KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame")); 3639a97fff19SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 3640a97fff19SSepherosa Ziehau if (ETHER_IS_MULTICAST(eh->ether_dhost)) 3641a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1); 3642a97fff19SSepherosa Ziehau } 364315516c77SSepherosa Ziehau rxr->hn_pkts++; 364415516c77SSepherosa Ziehau 3645a97fff19SSepherosa Ziehau if ((hn_ifp->if_capenable & IFCAP_LRO) && do_lro) { 364615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 364715516c77SSepherosa Ziehau struct lro_ctrl *lro = &rxr->hn_lro; 364815516c77SSepherosa Ziehau 364915516c77SSepherosa Ziehau if (lro->lro_cnt) { 365015516c77SSepherosa Ziehau rxr->hn_lro_tried++; 365115516c77SSepherosa Ziehau if (hn_lro_rx(lro, m_new) == 0) { 365215516c77SSepherosa Ziehau /* DONE! */ 365315516c77SSepherosa Ziehau return 0; 365415516c77SSepherosa Ziehau } 365515516c77SSepherosa Ziehau } 365615516c77SSepherosa Ziehau #endif 365715516c77SSepherosa Ziehau } 3658a97fff19SSepherosa Ziehau ifp->if_input(ifp, m_new); 365915516c77SSepherosa Ziehau 366015516c77SSepherosa Ziehau return (0); 366115516c77SSepherosa Ziehau } 366215516c77SSepherosa Ziehau 366315516c77SSepherosa Ziehau static int 366415516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 366515516c77SSepherosa Ziehau { 366615516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 36679c6cae24SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data, ifr_vf; 36689c6cae24SSepherosa Ziehau struct ifnet *vf_ifp; 366915516c77SSepherosa Ziehau int mask, error = 0; 36708c068aa5SSepherosa Ziehau struct ifrsskey *ifrk; 36718c068aa5SSepherosa Ziehau struct ifrsshash *ifrh; 3672eb2fe044SSepherosa Ziehau uint32_t mtu; 367315516c77SSepherosa Ziehau 367415516c77SSepherosa Ziehau switch (cmd) { 367515516c77SSepherosa Ziehau case SIOCSIFMTU: 367615516c77SSepherosa Ziehau if (ifr->ifr_mtu > HN_MTU_MAX) { 367715516c77SSepherosa Ziehau error = EINVAL; 367815516c77SSepherosa Ziehau break; 367915516c77SSepherosa Ziehau } 368015516c77SSepherosa Ziehau 368115516c77SSepherosa Ziehau HN_LOCK(sc); 368215516c77SSepherosa Ziehau 368315516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 368415516c77SSepherosa Ziehau HN_UNLOCK(sc); 368515516c77SSepherosa Ziehau break; 368615516c77SSepherosa Ziehau } 368715516c77SSepherosa Ziehau 368815516c77SSepherosa Ziehau if ((sc->hn_caps & HN_CAP_MTU) == 0) { 368915516c77SSepherosa Ziehau /* Can't change MTU */ 369015516c77SSepherosa Ziehau HN_UNLOCK(sc); 369115516c77SSepherosa Ziehau error = EOPNOTSUPP; 369215516c77SSepherosa Ziehau break; 369315516c77SSepherosa Ziehau } 369415516c77SSepherosa Ziehau 369515516c77SSepherosa Ziehau if (ifp->if_mtu == ifr->ifr_mtu) { 369615516c77SSepherosa Ziehau HN_UNLOCK(sc); 369715516c77SSepherosa Ziehau break; 369815516c77SSepherosa Ziehau } 369915516c77SSepherosa Ziehau 37009c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 37019c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 37029c6cae24SSepherosa Ziehau ifr_vf = *ifr; 37039c6cae24SSepherosa Ziehau strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname, 37049c6cae24SSepherosa Ziehau sizeof(ifr_vf.ifr_name)); 37059c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, 37069c6cae24SSepherosa Ziehau (caddr_t)&ifr_vf); 37079c6cae24SSepherosa Ziehau if (error) { 37089c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 37099c6cae24SSepherosa Ziehau if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n", 37109c6cae24SSepherosa Ziehau vf_ifp->if_xname, ifr->ifr_mtu, error); 37119c6cae24SSepherosa Ziehau break; 37129c6cae24SSepherosa Ziehau } 37139c6cae24SSepherosa Ziehau } 37149c6cae24SSepherosa Ziehau 371515516c77SSepherosa Ziehau /* 371615516c77SSepherosa Ziehau * Suspend this interface before the synthetic parts 371715516c77SSepherosa Ziehau * are ripped. 371815516c77SSepherosa Ziehau */ 371915516c77SSepherosa Ziehau hn_suspend(sc); 372015516c77SSepherosa Ziehau 372115516c77SSepherosa Ziehau /* 372215516c77SSepherosa Ziehau * Detach the synthetics parts, i.e. NVS and RNDIS. 372315516c77SSepherosa Ziehau */ 372415516c77SSepherosa Ziehau hn_synth_detach(sc); 372515516c77SSepherosa Ziehau 372615516c77SSepherosa Ziehau /* 372715516c77SSepherosa Ziehau * Reattach the synthetic parts, i.e. NVS and RNDIS, 372815516c77SSepherosa Ziehau * with the new MTU setting. 372915516c77SSepherosa Ziehau */ 373015516c77SSepherosa Ziehau error = hn_synth_attach(sc, ifr->ifr_mtu); 373115516c77SSepherosa Ziehau if (error) { 373215516c77SSepherosa Ziehau HN_UNLOCK(sc); 373315516c77SSepherosa Ziehau break; 373415516c77SSepherosa Ziehau } 373515516c77SSepherosa Ziehau 3736eb2fe044SSepherosa Ziehau error = hn_rndis_get_mtu(sc, &mtu); 3737eb2fe044SSepherosa Ziehau if (error) 3738eb2fe044SSepherosa Ziehau mtu = ifr->ifr_mtu; 3739eb2fe044SSepherosa Ziehau else if (bootverbose) 3740eb2fe044SSepherosa Ziehau if_printf(ifp, "RNDIS mtu %u\n", mtu); 3741eb2fe044SSepherosa Ziehau 374215516c77SSepherosa Ziehau /* 374315516c77SSepherosa Ziehau * Commit the requested MTU, after the synthetic parts 374415516c77SSepherosa Ziehau * have been successfully attached. 374515516c77SSepherosa Ziehau */ 3746eb2fe044SSepherosa Ziehau if (mtu >= ifr->ifr_mtu) { 3747eb2fe044SSepherosa Ziehau mtu = ifr->ifr_mtu; 3748eb2fe044SSepherosa Ziehau } else { 3749eb2fe044SSepherosa Ziehau if_printf(ifp, "fixup mtu %d -> %u\n", 3750eb2fe044SSepherosa Ziehau ifr->ifr_mtu, mtu); 3751eb2fe044SSepherosa Ziehau } 3752eb2fe044SSepherosa Ziehau ifp->if_mtu = mtu; 375315516c77SSepherosa Ziehau 375415516c77SSepherosa Ziehau /* 37559c6cae24SSepherosa Ziehau * Synthetic parts' reattach may change the chimney 37569c6cae24SSepherosa Ziehau * sending size; update it. 375715516c77SSepherosa Ziehau */ 375815516c77SSepherosa Ziehau if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax) 375915516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 37609c6cae24SSepherosa Ziehau 37619c6cae24SSepherosa Ziehau /* 37629c6cae24SSepherosa Ziehau * Make sure that various parameters based on MTU are 37639c6cae24SSepherosa Ziehau * still valid, after the MTU change. 37649c6cae24SSepherosa Ziehau */ 37659c6cae24SSepherosa Ziehau hn_mtu_change_fixup(sc); 376615516c77SSepherosa Ziehau 376715516c77SSepherosa Ziehau /* 376815516c77SSepherosa Ziehau * All done! Resume the interface now. 376915516c77SSepherosa Ziehau */ 377015516c77SSepherosa Ziehau hn_resume(sc); 377115516c77SSepherosa Ziehau 3772d0cd8231SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) || 3773d0cd8231SSepherosa Ziehau (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { 37749c6cae24SSepherosa Ziehau /* 37759c6cae24SSepherosa Ziehau * Since we have reattached the NVS part, 37769c6cae24SSepherosa Ziehau * change the datapath to VF again; in case 37779c6cae24SSepherosa Ziehau * that it is lost, after the NVS was detached. 37789c6cae24SSepherosa Ziehau */ 37799c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF); 37809c6cae24SSepherosa Ziehau } 37819c6cae24SSepherosa Ziehau 378215516c77SSepherosa Ziehau HN_UNLOCK(sc); 378315516c77SSepherosa Ziehau break; 378415516c77SSepherosa Ziehau 378515516c77SSepherosa Ziehau case SIOCSIFFLAGS: 378615516c77SSepherosa Ziehau HN_LOCK(sc); 378715516c77SSepherosa Ziehau 378815516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 378915516c77SSepherosa Ziehau HN_UNLOCK(sc); 379015516c77SSepherosa Ziehau break; 379115516c77SSepherosa Ziehau } 379215516c77SSepherosa Ziehau 37939c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) 37949c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 37959c6cae24SSepherosa Ziehau 379615516c77SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 3797fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3798fdc4f478SSepherosa Ziehau /* 3799fdc4f478SSepherosa Ziehau * Caller meight hold mutex, e.g. 3800fdc4f478SSepherosa Ziehau * bpf; use busy-wait for the RNDIS 3801fdc4f478SSepherosa Ziehau * reply. 3802fdc4f478SSepherosa Ziehau */ 3803fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 3804c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 3805fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 38069c6cae24SSepherosa Ziehau 38079c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 38089c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 3809fdc4f478SSepherosa Ziehau } else { 381015516c77SSepherosa Ziehau hn_init_locked(sc); 3811fdc4f478SSepherosa Ziehau } 381215516c77SSepherosa Ziehau } else { 381315516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 38145bdfd3fdSDexuan Cui hn_stop(sc, false); 381515516c77SSepherosa Ziehau } 381615516c77SSepherosa Ziehau sc->hn_if_flags = ifp->if_flags; 381715516c77SSepherosa Ziehau 381815516c77SSepherosa Ziehau HN_UNLOCK(sc); 381915516c77SSepherosa Ziehau break; 382015516c77SSepherosa Ziehau 382115516c77SSepherosa Ziehau case SIOCSIFCAP: 382215516c77SSepherosa Ziehau HN_LOCK(sc); 38239c6cae24SSepherosa Ziehau 38249c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 38259c6cae24SSepherosa Ziehau ifr_vf = *ifr; 38269c6cae24SSepherosa Ziehau strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname, 38279c6cae24SSepherosa Ziehau sizeof(ifr_vf.ifr_name)); 38289c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf); 38299c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 38309c6cae24SSepherosa Ziehau break; 38319c6cae24SSepherosa Ziehau } 38329c6cae24SSepherosa Ziehau 38339c6cae24SSepherosa Ziehau /* 38349c6cae24SSepherosa Ziehau * Fix up requested capabilities w/ supported capabilities, 38359c6cae24SSepherosa Ziehau * since the supported capabilities could have been changed. 38369c6cae24SSepherosa Ziehau */ 38379c6cae24SSepherosa Ziehau mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^ 38389c6cae24SSepherosa Ziehau ifp->if_capenable; 383915516c77SSepherosa Ziehau 384015516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM) { 384115516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 384215516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 384315516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc); 384415516c77SSepherosa Ziehau else 384515516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc); 384615516c77SSepherosa Ziehau } 384715516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM_IPV6) { 384815516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 384915516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 385015516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc); 385115516c77SSepherosa Ziehau else 385215516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc); 385315516c77SSepherosa Ziehau } 385415516c77SSepherosa Ziehau 385515516c77SSepherosa Ziehau /* TODO: flip RNDIS offload parameters for RXCSUM. */ 385615516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 385715516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 385815516c77SSepherosa Ziehau #ifdef foo 385915516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 386015516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM_IPV6) 386115516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 386215516c77SSepherosa Ziehau #endif 386315516c77SSepherosa Ziehau 386415516c77SSepherosa Ziehau if (mask & IFCAP_LRO) 386515516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_LRO; 386615516c77SSepherosa Ziehau 386715516c77SSepherosa Ziehau if (mask & IFCAP_TSO4) { 386815516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO4; 386915516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 387015516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 387115516c77SSepherosa Ziehau else 387215516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP_TSO; 387315516c77SSepherosa Ziehau } 387415516c77SSepherosa Ziehau if (mask & IFCAP_TSO6) { 387515516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO6; 387615516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 387715516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 387815516c77SSepherosa Ziehau else 387915516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP6_TSO; 388015516c77SSepherosa Ziehau } 388115516c77SSepherosa Ziehau 388215516c77SSepherosa Ziehau HN_UNLOCK(sc); 388315516c77SSepherosa Ziehau break; 388415516c77SSepherosa Ziehau 388515516c77SSepherosa Ziehau case SIOCADDMULTI: 388615516c77SSepherosa Ziehau case SIOCDELMULTI: 388715516c77SSepherosa Ziehau HN_LOCK(sc); 388815516c77SSepherosa Ziehau 388915516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 389015516c77SSepherosa Ziehau HN_UNLOCK(sc); 389115516c77SSepherosa Ziehau break; 389215516c77SSepherosa Ziehau } 3893fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3894fdc4f478SSepherosa Ziehau /* 3895fdc4f478SSepherosa Ziehau * Multicast uses mutex; use busy-wait for 3896fdc4f478SSepherosa Ziehau * the RNDIS reply. 3897fdc4f478SSepherosa Ziehau */ 3898fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 3899c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 3900fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 3901fdc4f478SSepherosa Ziehau } 390215516c77SSepherosa Ziehau 39039c6cae24SSepherosa Ziehau /* XXX vlan(4) style mcast addr maintenance */ 39049c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 39059c6cae24SSepherosa Ziehau int old_if_flags; 39069c6cae24SSepherosa Ziehau 39079c6cae24SSepherosa Ziehau old_if_flags = sc->hn_vf_ifp->if_flags; 39089c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 39099c6cae24SSepherosa Ziehau 39109c6cae24SSepherosa Ziehau if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) && 39119c6cae24SSepherosa Ziehau ((old_if_flags ^ sc->hn_vf_ifp->if_flags) & 39129c6cae24SSepherosa Ziehau IFF_ALLMULTI)) 39139c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 39149c6cae24SSepherosa Ziehau } 39159c6cae24SSepherosa Ziehau 391615516c77SSepherosa Ziehau HN_UNLOCK(sc); 391715516c77SSepherosa Ziehau break; 391815516c77SSepherosa Ziehau 391915516c77SSepherosa Ziehau case SIOCSIFMEDIA: 392015516c77SSepherosa Ziehau case SIOCGIFMEDIA: 39219c6cae24SSepherosa Ziehau HN_LOCK(sc); 39229c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 39239c6cae24SSepherosa Ziehau /* 39249c6cae24SSepherosa Ziehau * SIOCGIFMEDIA expects ifmediareq, so don't 39259c6cae24SSepherosa Ziehau * create and pass ifr_vf to the VF here; just 39269c6cae24SSepherosa Ziehau * replace the ifr_name. 39279c6cae24SSepherosa Ziehau */ 39289c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 39299c6cae24SSepherosa Ziehau strlcpy(ifr->ifr_name, vf_ifp->if_xname, 39309c6cae24SSepherosa Ziehau sizeof(ifr->ifr_name)); 39319c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, cmd, data); 39329c6cae24SSepherosa Ziehau /* Restore the ifr_name. */ 39339c6cae24SSepherosa Ziehau strlcpy(ifr->ifr_name, ifp->if_xname, 39349c6cae24SSepherosa Ziehau sizeof(ifr->ifr_name)); 39359c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 39369c6cae24SSepherosa Ziehau break; 39379c6cae24SSepherosa Ziehau } 39389c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 393915516c77SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd); 394015516c77SSepherosa Ziehau break; 394115516c77SSepherosa Ziehau 39428c068aa5SSepherosa Ziehau case SIOCGIFRSSHASH: 39438c068aa5SSepherosa Ziehau ifrh = (struct ifrsshash *)data; 39448c068aa5SSepherosa Ziehau HN_LOCK(sc); 39458c068aa5SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 39468c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 39478c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_NONE; 39488c068aa5SSepherosa Ziehau ifrh->ifrh_types = 0; 39498c068aa5SSepherosa Ziehau break; 39508c068aa5SSepherosa Ziehau } 39518c068aa5SSepherosa Ziehau 39528c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ) 39538c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_TOEPLITZ; 39548c068aa5SSepherosa Ziehau else 39558c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_PRIVATE; 3956642ec226SSepherosa Ziehau ifrh->ifrh_types = hn_rss_type_fromndis(sc->hn_rss_hash); 39578c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 39588c068aa5SSepherosa Ziehau break; 39598c068aa5SSepherosa Ziehau 39608c068aa5SSepherosa Ziehau case SIOCGIFRSSKEY: 39618c068aa5SSepherosa Ziehau ifrk = (struct ifrsskey *)data; 39628c068aa5SSepherosa Ziehau HN_LOCK(sc); 39638c068aa5SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 39648c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 39658c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_NONE; 39668c068aa5SSepherosa Ziehau ifrk->ifrk_keylen = 0; 39678c068aa5SSepherosa Ziehau break; 39688c068aa5SSepherosa Ziehau } 39698c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ) 39708c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_TOEPLITZ; 39718c068aa5SSepherosa Ziehau else 39728c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_PRIVATE; 39738c068aa5SSepherosa Ziehau ifrk->ifrk_keylen = NDIS_HASH_KEYSIZE_TOEPLITZ; 39748c068aa5SSepherosa Ziehau memcpy(ifrk->ifrk_key, sc->hn_rss.rss_key, 39758c068aa5SSepherosa Ziehau NDIS_HASH_KEYSIZE_TOEPLITZ); 39768c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 39778c068aa5SSepherosa Ziehau break; 39788c068aa5SSepherosa Ziehau 397915516c77SSepherosa Ziehau default: 398015516c77SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 398115516c77SSepherosa Ziehau break; 398215516c77SSepherosa Ziehau } 398315516c77SSepherosa Ziehau return (error); 398415516c77SSepherosa Ziehau } 398515516c77SSepherosa Ziehau 398615516c77SSepherosa Ziehau static void 39875bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching) 398815516c77SSepherosa Ziehau { 398915516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 399015516c77SSepherosa Ziehau int i; 399115516c77SSepherosa Ziehau 399215516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 399315516c77SSepherosa Ziehau 399415516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 399515516c77SSepherosa Ziehau ("synthetic parts were not attached")); 399615516c77SSepherosa Ziehau 39979c6cae24SSepherosa Ziehau /* Clear RUNNING bit ASAP. */ 39989c6cae24SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 39999c6cae24SSepherosa Ziehau 40006c1204dfSSepherosa Ziehau /* Disable polling. */ 40016c1204dfSSepherosa Ziehau hn_polling(sc, 0); 40026c1204dfSSepherosa Ziehau 40039c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) { 40049c6cae24SSepherosa Ziehau KASSERT(sc->hn_vf_ifp != NULL, 40059c6cae24SSepherosa Ziehau ("%s: VF is not attached", ifp->if_xname)); 40069c6cae24SSepherosa Ziehau 4007a97fff19SSepherosa Ziehau /* Mark transparent mode VF as disabled. */ 4008a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */); 40099c6cae24SSepherosa Ziehau 40109c6cae24SSepherosa Ziehau /* 40119c6cae24SSepherosa Ziehau * NOTE: 40129c6cae24SSepherosa Ziehau * Datapath setting must happen _before_ bringing 40139c6cae24SSepherosa Ziehau * the VF down. 40149c6cae24SSepherosa Ziehau */ 40159c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH); 40169c6cae24SSepherosa Ziehau 40179c6cae24SSepherosa Ziehau /* 40189c6cae24SSepherosa Ziehau * Bring the VF down. 40199c6cae24SSepherosa Ziehau */ 40209c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 40219c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags &= ~IFF_UP; 40229c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(sc); 40239c6cae24SSepherosa Ziehau } 40249c6cae24SSepherosa Ziehau 40259c6cae24SSepherosa Ziehau /* Suspend data transfers. */ 402615516c77SSepherosa Ziehau hn_suspend_data(sc); 402715516c77SSepherosa Ziehau 402815516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 402915516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 403015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 403115516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 40325bdfd3fdSDexuan Cui 40335bdfd3fdSDexuan Cui /* 40349c6cae24SSepherosa Ziehau * If the non-transparent mode VF is active, make sure 40359c6cae24SSepherosa Ziehau * that the RX filter still allows packet reception. 40365bdfd3fdSDexuan Cui */ 4037962f0357SSepherosa Ziehau if (!detaching && (sc->hn_flags & HN_FLAG_RXVF)) 40385bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 403915516c77SSepherosa Ziehau } 404015516c77SSepherosa Ziehau 404115516c77SSepherosa Ziehau static void 404215516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc) 404315516c77SSepherosa Ziehau { 404415516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 404515516c77SSepherosa Ziehau int i; 404615516c77SSepherosa Ziehau 404715516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 404815516c77SSepherosa Ziehau 404915516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 405015516c77SSepherosa Ziehau return; 405115516c77SSepherosa Ziehau 405215516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 405315516c77SSepherosa Ziehau return; 405415516c77SSepherosa Ziehau 405515516c77SSepherosa Ziehau /* Configure RX filter */ 4056c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 405715516c77SSepherosa Ziehau 405815516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 405915516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 406015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 406115516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 406215516c77SSepherosa Ziehau 406315516c77SSepherosa Ziehau /* Clear TX 'suspended' bit. */ 406415516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_inuse); 406515516c77SSepherosa Ziehau 40669c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 40679c6cae24SSepherosa Ziehau /* Initialize transparent VF. */ 40689c6cae24SSepherosa Ziehau hn_xpnt_vf_init(sc); 40699c6cae24SSepherosa Ziehau } 40709c6cae24SSepherosa Ziehau 407115516c77SSepherosa Ziehau /* Everything is ready; unleash! */ 407215516c77SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 40736c1204dfSSepherosa Ziehau 40746c1204dfSSepherosa Ziehau /* Re-enable polling if requested. */ 40756c1204dfSSepherosa Ziehau if (sc->hn_pollhz > 0) 40766c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 407715516c77SSepherosa Ziehau } 407815516c77SSepherosa Ziehau 407915516c77SSepherosa Ziehau static void 408015516c77SSepherosa Ziehau hn_init(void *xsc) 408115516c77SSepherosa Ziehau { 408215516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 408315516c77SSepherosa Ziehau 408415516c77SSepherosa Ziehau HN_LOCK(sc); 408515516c77SSepherosa Ziehau hn_init_locked(sc); 408615516c77SSepherosa Ziehau HN_UNLOCK(sc); 408715516c77SSepherosa Ziehau } 408815516c77SSepherosa Ziehau 408915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 409015516c77SSepherosa Ziehau 409115516c77SSepherosa Ziehau static int 409215516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS) 409315516c77SSepherosa Ziehau { 409415516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 409515516c77SSepherosa Ziehau unsigned int lenlim; 409615516c77SSepherosa Ziehau int error; 409715516c77SSepherosa Ziehau 409815516c77SSepherosa Ziehau lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim; 409915516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &lenlim, 0, req); 410015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 410115516c77SSepherosa Ziehau return error; 410215516c77SSepherosa Ziehau 410315516c77SSepherosa Ziehau HN_LOCK(sc); 410415516c77SSepherosa Ziehau if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) || 410515516c77SSepherosa Ziehau lenlim > TCP_LRO_LENGTH_MAX) { 410615516c77SSepherosa Ziehau HN_UNLOCK(sc); 410715516c77SSepherosa Ziehau return EINVAL; 410815516c77SSepherosa Ziehau } 410915516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, lenlim); 411015516c77SSepherosa Ziehau HN_UNLOCK(sc); 411115516c77SSepherosa Ziehau 411215516c77SSepherosa Ziehau return 0; 411315516c77SSepherosa Ziehau } 411415516c77SSepherosa Ziehau 411515516c77SSepherosa Ziehau static int 411615516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS) 411715516c77SSepherosa Ziehau { 411815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 411915516c77SSepherosa Ziehau int ackcnt, error, i; 412015516c77SSepherosa Ziehau 412115516c77SSepherosa Ziehau /* 412215516c77SSepherosa Ziehau * lro_ackcnt_lim is append count limit, 412315516c77SSepherosa Ziehau * +1 to turn it into aggregation limit. 412415516c77SSepherosa Ziehau */ 412515516c77SSepherosa Ziehau ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1; 412615516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &ackcnt, 0, req); 412715516c77SSepherosa Ziehau if (error || req->newptr == NULL) 412815516c77SSepherosa Ziehau return error; 412915516c77SSepherosa Ziehau 413015516c77SSepherosa Ziehau if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1)) 413115516c77SSepherosa Ziehau return EINVAL; 413215516c77SSepherosa Ziehau 413315516c77SSepherosa Ziehau /* 413415516c77SSepherosa Ziehau * Convert aggregation limit back to append 413515516c77SSepherosa Ziehau * count limit. 413615516c77SSepherosa Ziehau */ 413715516c77SSepherosa Ziehau --ackcnt; 413815516c77SSepherosa Ziehau HN_LOCK(sc); 4139a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 414015516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt; 414115516c77SSepherosa Ziehau HN_UNLOCK(sc); 414215516c77SSepherosa Ziehau return 0; 414315516c77SSepherosa Ziehau } 414415516c77SSepherosa Ziehau 414515516c77SSepherosa Ziehau #endif 414615516c77SSepherosa Ziehau 414715516c77SSepherosa Ziehau static int 414815516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS) 414915516c77SSepherosa Ziehau { 415015516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 415115516c77SSepherosa Ziehau int hcsum = arg2; 415215516c77SSepherosa Ziehau int on, error, i; 415315516c77SSepherosa Ziehau 415415516c77SSepherosa Ziehau on = 0; 415515516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum) 415615516c77SSepherosa Ziehau on = 1; 415715516c77SSepherosa Ziehau 415815516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &on, 0, req); 415915516c77SSepherosa Ziehau if (error || req->newptr == NULL) 416015516c77SSepherosa Ziehau return error; 416115516c77SSepherosa Ziehau 416215516c77SSepherosa Ziehau HN_LOCK(sc); 4163a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 416415516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 416515516c77SSepherosa Ziehau 416615516c77SSepherosa Ziehau if (on) 416715516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= hcsum; 416815516c77SSepherosa Ziehau else 416915516c77SSepherosa Ziehau rxr->hn_trust_hcsum &= ~hcsum; 417015516c77SSepherosa Ziehau } 417115516c77SSepherosa Ziehau HN_UNLOCK(sc); 417215516c77SSepherosa Ziehau return 0; 417315516c77SSepherosa Ziehau } 417415516c77SSepherosa Ziehau 417515516c77SSepherosa Ziehau static int 417615516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS) 417715516c77SSepherosa Ziehau { 417815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 417915516c77SSepherosa Ziehau int chim_size, error; 418015516c77SSepherosa Ziehau 418115516c77SSepherosa Ziehau chim_size = sc->hn_tx_ring[0].hn_chim_size; 418215516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &chim_size, 0, req); 418315516c77SSepherosa Ziehau if (error || req->newptr == NULL) 418415516c77SSepherosa Ziehau return error; 418515516c77SSepherosa Ziehau 418615516c77SSepherosa Ziehau if (chim_size > sc->hn_chim_szmax || chim_size <= 0) 418715516c77SSepherosa Ziehau return EINVAL; 418815516c77SSepherosa Ziehau 418915516c77SSepherosa Ziehau HN_LOCK(sc); 419015516c77SSepherosa Ziehau hn_set_chim_size(sc, chim_size); 419115516c77SSepherosa Ziehau HN_UNLOCK(sc); 419215516c77SSepherosa Ziehau return 0; 419315516c77SSepherosa Ziehau } 419415516c77SSepherosa Ziehau 419515516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 419615516c77SSepherosa Ziehau static int 419715516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS) 419815516c77SSepherosa Ziehau { 419915516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 420015516c77SSepherosa Ziehau int ofs = arg2, i, error; 420115516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 420215516c77SSepherosa Ziehau uint64_t stat; 420315516c77SSepherosa Ziehau 420415516c77SSepherosa Ziehau stat = 0; 420515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 420615516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 420715516c77SSepherosa Ziehau stat += *((int *)((uint8_t *)rxr + ofs)); 420815516c77SSepherosa Ziehau } 420915516c77SSepherosa Ziehau 421015516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 421115516c77SSepherosa Ziehau if (error || req->newptr == NULL) 421215516c77SSepherosa Ziehau return error; 421315516c77SSepherosa Ziehau 421415516c77SSepherosa Ziehau /* Zero out this stat. */ 421515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 421615516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 421715516c77SSepherosa Ziehau *((int *)((uint8_t *)rxr + ofs)) = 0; 421815516c77SSepherosa Ziehau } 421915516c77SSepherosa Ziehau return 0; 422015516c77SSepherosa Ziehau } 422115516c77SSepherosa Ziehau #else 422215516c77SSepherosa Ziehau static int 422315516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS) 422415516c77SSepherosa Ziehau { 422515516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 422615516c77SSepherosa Ziehau int ofs = arg2, i, error; 422715516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 422815516c77SSepherosa Ziehau uint64_t stat; 422915516c77SSepherosa Ziehau 423015516c77SSepherosa Ziehau stat = 0; 4231a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 423215516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 423315516c77SSepherosa Ziehau stat += *((uint64_t *)((uint8_t *)rxr + ofs)); 423415516c77SSepherosa Ziehau } 423515516c77SSepherosa Ziehau 423615516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 423715516c77SSepherosa Ziehau if (error || req->newptr == NULL) 423815516c77SSepherosa Ziehau return error; 423915516c77SSepherosa Ziehau 424015516c77SSepherosa Ziehau /* Zero out this stat. */ 4241a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 424215516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 424315516c77SSepherosa Ziehau *((uint64_t *)((uint8_t *)rxr + ofs)) = 0; 424415516c77SSepherosa Ziehau } 424515516c77SSepherosa Ziehau return 0; 424615516c77SSepherosa Ziehau } 424715516c77SSepherosa Ziehau 424815516c77SSepherosa Ziehau #endif 424915516c77SSepherosa Ziehau 425015516c77SSepherosa Ziehau static int 425115516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 425215516c77SSepherosa Ziehau { 425315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 425415516c77SSepherosa Ziehau int ofs = arg2, i, error; 425515516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 425615516c77SSepherosa Ziehau u_long stat; 425715516c77SSepherosa Ziehau 425815516c77SSepherosa Ziehau stat = 0; 4259a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 426015516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 426115516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)rxr + ofs)); 426215516c77SSepherosa Ziehau } 426315516c77SSepherosa Ziehau 426415516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 426515516c77SSepherosa Ziehau if (error || req->newptr == NULL) 426615516c77SSepherosa Ziehau return error; 426715516c77SSepherosa Ziehau 426815516c77SSepherosa Ziehau /* Zero out this stat. */ 4269a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 427015516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 427115516c77SSepherosa Ziehau *((u_long *)((uint8_t *)rxr + ofs)) = 0; 427215516c77SSepherosa Ziehau } 427315516c77SSepherosa Ziehau return 0; 427415516c77SSepherosa Ziehau } 427515516c77SSepherosa Ziehau 427615516c77SSepherosa Ziehau static int 427715516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 427815516c77SSepherosa Ziehau { 427915516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 428015516c77SSepherosa Ziehau int ofs = arg2, i, error; 428115516c77SSepherosa Ziehau struct hn_tx_ring *txr; 428215516c77SSepherosa Ziehau u_long stat; 428315516c77SSepherosa Ziehau 428415516c77SSepherosa Ziehau stat = 0; 4285a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 428615516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 428715516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)txr + ofs)); 428815516c77SSepherosa Ziehau } 428915516c77SSepherosa Ziehau 429015516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 429115516c77SSepherosa Ziehau if (error || req->newptr == NULL) 429215516c77SSepherosa Ziehau return error; 429315516c77SSepherosa Ziehau 429415516c77SSepherosa Ziehau /* Zero out this stat. */ 4295a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 429615516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 429715516c77SSepherosa Ziehau *((u_long *)((uint8_t *)txr + ofs)) = 0; 429815516c77SSepherosa Ziehau } 429915516c77SSepherosa Ziehau return 0; 430015516c77SSepherosa Ziehau } 430115516c77SSepherosa Ziehau 430215516c77SSepherosa Ziehau static int 430315516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS) 430415516c77SSepherosa Ziehau { 430515516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 430615516c77SSepherosa Ziehau int ofs = arg2, i, error, conf; 430715516c77SSepherosa Ziehau struct hn_tx_ring *txr; 430815516c77SSepherosa Ziehau 430915516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[0]; 431015516c77SSepherosa Ziehau conf = *((int *)((uint8_t *)txr + ofs)); 431115516c77SSepherosa Ziehau 431215516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &conf, 0, req); 431315516c77SSepherosa Ziehau if (error || req->newptr == NULL) 431415516c77SSepherosa Ziehau return error; 431515516c77SSepherosa Ziehau 431615516c77SSepherosa Ziehau HN_LOCK(sc); 4317a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 431815516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 431915516c77SSepherosa Ziehau *((int *)((uint8_t *)txr + ofs)) = conf; 432015516c77SSepherosa Ziehau } 432115516c77SSepherosa Ziehau HN_UNLOCK(sc); 432215516c77SSepherosa Ziehau 432315516c77SSepherosa Ziehau return 0; 432415516c77SSepherosa Ziehau } 432515516c77SSepherosa Ziehau 432615516c77SSepherosa Ziehau static int 4327dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS) 4328dc13fee6SSepherosa Ziehau { 4329dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4330dc13fee6SSepherosa Ziehau int error, size; 4331dc13fee6SSepherosa Ziehau 4332dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 4333dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &size, 0, req); 4334dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 4335dc13fee6SSepherosa Ziehau return (error); 4336dc13fee6SSepherosa Ziehau 4337dc13fee6SSepherosa Ziehau HN_LOCK(sc); 4338dc13fee6SSepherosa Ziehau sc->hn_agg_size = size; 4339dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 4340dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 4341dc13fee6SSepherosa Ziehau 4342dc13fee6SSepherosa Ziehau return (0); 4343dc13fee6SSepherosa Ziehau } 4344dc13fee6SSepherosa Ziehau 4345dc13fee6SSepherosa Ziehau static int 4346dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS) 4347dc13fee6SSepherosa Ziehau { 4348dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4349dc13fee6SSepherosa Ziehau int error, pkts; 4350dc13fee6SSepherosa Ziehau 4351dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 4352dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &pkts, 0, req); 4353dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 4354dc13fee6SSepherosa Ziehau return (error); 4355dc13fee6SSepherosa Ziehau 4356dc13fee6SSepherosa Ziehau HN_LOCK(sc); 4357dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = pkts; 4358dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 4359dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 4360dc13fee6SSepherosa Ziehau 4361dc13fee6SSepherosa Ziehau return (0); 4362dc13fee6SSepherosa Ziehau } 4363dc13fee6SSepherosa Ziehau 4364dc13fee6SSepherosa Ziehau static int 4365dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS) 4366dc13fee6SSepherosa Ziehau { 4367dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4368dc13fee6SSepherosa Ziehau int pkts; 4369dc13fee6SSepherosa Ziehau 4370dc13fee6SSepherosa Ziehau pkts = sc->hn_tx_ring[0].hn_agg_pktmax; 4371dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &pkts, 0, req)); 4372dc13fee6SSepherosa Ziehau } 4373dc13fee6SSepherosa Ziehau 4374dc13fee6SSepherosa Ziehau static int 4375dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS) 4376dc13fee6SSepherosa Ziehau { 4377dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4378dc13fee6SSepherosa Ziehau int align; 4379dc13fee6SSepherosa Ziehau 4380dc13fee6SSepherosa Ziehau align = sc->hn_tx_ring[0].hn_agg_align; 4381dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &align, 0, req)); 4382dc13fee6SSepherosa Ziehau } 4383dc13fee6SSepherosa Ziehau 43846c1204dfSSepherosa Ziehau static void 43856c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz) 43866c1204dfSSepherosa Ziehau { 43876c1204dfSSepherosa Ziehau if (pollhz == 0) 43886c1204dfSSepherosa Ziehau vmbus_chan_poll_disable(chan); 43896c1204dfSSepherosa Ziehau else 43906c1204dfSSepherosa Ziehau vmbus_chan_poll_enable(chan, pollhz); 43916c1204dfSSepherosa Ziehau } 43926c1204dfSSepherosa Ziehau 43936c1204dfSSepherosa Ziehau static void 43946c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz) 43956c1204dfSSepherosa Ziehau { 43966c1204dfSSepherosa Ziehau int nsubch = sc->hn_rx_ring_inuse - 1; 43976c1204dfSSepherosa Ziehau 43986c1204dfSSepherosa Ziehau HN_LOCK_ASSERT(sc); 43996c1204dfSSepherosa Ziehau 44006c1204dfSSepherosa Ziehau if (nsubch > 0) { 44016c1204dfSSepherosa Ziehau struct vmbus_channel **subch; 44026c1204dfSSepherosa Ziehau int i; 44036c1204dfSSepherosa Ziehau 44046c1204dfSSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 44056c1204dfSSepherosa Ziehau for (i = 0; i < nsubch; ++i) 44066c1204dfSSepherosa Ziehau hn_chan_polling(subch[i], pollhz); 44076c1204dfSSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 44086c1204dfSSepherosa Ziehau } 44096c1204dfSSepherosa Ziehau hn_chan_polling(sc->hn_prichan, pollhz); 44106c1204dfSSepherosa Ziehau } 44116c1204dfSSepherosa Ziehau 44126c1204dfSSepherosa Ziehau static int 44136c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS) 44146c1204dfSSepherosa Ziehau { 44156c1204dfSSepherosa Ziehau struct hn_softc *sc = arg1; 44166c1204dfSSepherosa Ziehau int pollhz, error; 44176c1204dfSSepherosa Ziehau 44186c1204dfSSepherosa Ziehau pollhz = sc->hn_pollhz; 44196c1204dfSSepherosa Ziehau error = sysctl_handle_int(oidp, &pollhz, 0, req); 44206c1204dfSSepherosa Ziehau if (error || req->newptr == NULL) 44216c1204dfSSepherosa Ziehau return (error); 44226c1204dfSSepherosa Ziehau 44236c1204dfSSepherosa Ziehau if (pollhz != 0 && 44246c1204dfSSepherosa Ziehau (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX)) 44256c1204dfSSepherosa Ziehau return (EINVAL); 44266c1204dfSSepherosa Ziehau 44276c1204dfSSepherosa Ziehau HN_LOCK(sc); 44286c1204dfSSepherosa Ziehau if (sc->hn_pollhz != pollhz) { 44296c1204dfSSepherosa Ziehau sc->hn_pollhz = pollhz; 44306c1204dfSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && 44316c1204dfSSepherosa Ziehau (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 44326c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 44336c1204dfSSepherosa Ziehau } 44346c1204dfSSepherosa Ziehau HN_UNLOCK(sc); 44356c1204dfSSepherosa Ziehau 44366c1204dfSSepherosa Ziehau return (0); 44376c1204dfSSepherosa Ziehau } 44386c1204dfSSepherosa Ziehau 4439dc13fee6SSepherosa Ziehau static int 444015516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS) 444115516c77SSepherosa Ziehau { 444215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 444315516c77SSepherosa Ziehau char verstr[16]; 444415516c77SSepherosa Ziehau 444515516c77SSepherosa Ziehau snprintf(verstr, sizeof(verstr), "%u.%u", 444615516c77SSepherosa Ziehau HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 444715516c77SSepherosa Ziehau HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 444815516c77SSepherosa Ziehau return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 444915516c77SSepherosa Ziehau } 445015516c77SSepherosa Ziehau 445115516c77SSepherosa Ziehau static int 445215516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS) 445315516c77SSepherosa Ziehau { 445415516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 445515516c77SSepherosa Ziehau char caps_str[128]; 445615516c77SSepherosa Ziehau uint32_t caps; 445715516c77SSepherosa Ziehau 445815516c77SSepherosa Ziehau HN_LOCK(sc); 445915516c77SSepherosa Ziehau caps = sc->hn_caps; 446015516c77SSepherosa Ziehau HN_UNLOCK(sc); 446115516c77SSepherosa Ziehau snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS); 446215516c77SSepherosa Ziehau return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req); 446315516c77SSepherosa Ziehau } 446415516c77SSepherosa Ziehau 446515516c77SSepherosa Ziehau static int 446615516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS) 446715516c77SSepherosa Ziehau { 446815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 446915516c77SSepherosa Ziehau char assist_str[128]; 447015516c77SSepherosa Ziehau uint32_t hwassist; 447115516c77SSepherosa Ziehau 447215516c77SSepherosa Ziehau HN_LOCK(sc); 447315516c77SSepherosa Ziehau hwassist = sc->hn_ifp->if_hwassist; 447415516c77SSepherosa Ziehau HN_UNLOCK(sc); 447515516c77SSepherosa Ziehau snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS); 447615516c77SSepherosa Ziehau return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req); 447715516c77SSepherosa Ziehau } 447815516c77SSepherosa Ziehau 447915516c77SSepherosa Ziehau static int 448015516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS) 448115516c77SSepherosa Ziehau { 448215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 448315516c77SSepherosa Ziehau char filter_str[128]; 448415516c77SSepherosa Ziehau uint32_t filter; 448515516c77SSepherosa Ziehau 448615516c77SSepherosa Ziehau HN_LOCK(sc); 448715516c77SSepherosa Ziehau filter = sc->hn_rx_filter; 448815516c77SSepherosa Ziehau HN_UNLOCK(sc); 448915516c77SSepherosa Ziehau snprintf(filter_str, sizeof(filter_str), "%b", filter, 449015516c77SSepherosa Ziehau NDIS_PACKET_TYPES); 449115516c77SSepherosa Ziehau return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req); 449215516c77SSepherosa Ziehau } 449315516c77SSepherosa Ziehau 449434d68912SSepherosa Ziehau #ifndef RSS 449534d68912SSepherosa Ziehau 449615516c77SSepherosa Ziehau static int 449715516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS) 449815516c77SSepherosa Ziehau { 449915516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 450015516c77SSepherosa Ziehau int error; 450115516c77SSepherosa Ziehau 450215516c77SSepherosa Ziehau HN_LOCK(sc); 450315516c77SSepherosa Ziehau 450415516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 450515516c77SSepherosa Ziehau if (error || req->newptr == NULL) 450615516c77SSepherosa Ziehau goto back; 450715516c77SSepherosa Ziehau 4508642ec226SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) || 4509642ec226SSepherosa Ziehau (hn_xpnt_vf && sc->hn_vf_ifp != NULL)) { 4510642ec226SSepherosa Ziehau /* 4511642ec226SSepherosa Ziehau * RSS key is synchronized w/ VF's, don't allow users 4512642ec226SSepherosa Ziehau * to change it. 4513642ec226SSepherosa Ziehau */ 4514642ec226SSepherosa Ziehau error = EBUSY; 4515642ec226SSepherosa Ziehau goto back; 4516642ec226SSepherosa Ziehau } 4517642ec226SSepherosa Ziehau 451815516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 451915516c77SSepherosa Ziehau if (error) 452015516c77SSepherosa Ziehau goto back; 452115516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 452215516c77SSepherosa Ziehau 452315516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 452415516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 452515516c77SSepherosa Ziehau } else { 452615516c77SSepherosa Ziehau /* Not RSS capable, at least for now; just save the RSS key. */ 452715516c77SSepherosa Ziehau error = 0; 452815516c77SSepherosa Ziehau } 452915516c77SSepherosa Ziehau back: 453015516c77SSepherosa Ziehau HN_UNLOCK(sc); 453115516c77SSepherosa Ziehau return (error); 453215516c77SSepherosa Ziehau } 453315516c77SSepherosa Ziehau 453415516c77SSepherosa Ziehau static int 453515516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS) 453615516c77SSepherosa Ziehau { 453715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 453815516c77SSepherosa Ziehau int error; 453915516c77SSepherosa Ziehau 454015516c77SSepherosa Ziehau HN_LOCK(sc); 454115516c77SSepherosa Ziehau 454215516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 454315516c77SSepherosa Ziehau if (error || req->newptr == NULL) 454415516c77SSepherosa Ziehau goto back; 454515516c77SSepherosa Ziehau 454615516c77SSepherosa Ziehau /* 454715516c77SSepherosa Ziehau * Don't allow RSS indirect table change, if this interface is not 454815516c77SSepherosa Ziehau * RSS capable currently. 454915516c77SSepherosa Ziehau */ 455015516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 455115516c77SSepherosa Ziehau error = EOPNOTSUPP; 455215516c77SSepherosa Ziehau goto back; 455315516c77SSepherosa Ziehau } 455415516c77SSepherosa Ziehau 455515516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 455615516c77SSepherosa Ziehau if (error) 455715516c77SSepherosa Ziehau goto back; 455815516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 455915516c77SSepherosa Ziehau 4560afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 456115516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 456215516c77SSepherosa Ziehau back: 456315516c77SSepherosa Ziehau HN_UNLOCK(sc); 456415516c77SSepherosa Ziehau return (error); 456515516c77SSepherosa Ziehau } 456615516c77SSepherosa Ziehau 456734d68912SSepherosa Ziehau #endif /* !RSS */ 456834d68912SSepherosa Ziehau 456915516c77SSepherosa Ziehau static int 457015516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS) 457115516c77SSepherosa Ziehau { 457215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 457315516c77SSepherosa Ziehau char hash_str[128]; 457415516c77SSepherosa Ziehau uint32_t hash; 457515516c77SSepherosa Ziehau 457615516c77SSepherosa Ziehau HN_LOCK(sc); 457715516c77SSepherosa Ziehau hash = sc->hn_rss_hash; 457815516c77SSepherosa Ziehau HN_UNLOCK(sc); 457915516c77SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 458015516c77SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 458115516c77SSepherosa Ziehau } 458215516c77SSepherosa Ziehau 458315516c77SSepherosa Ziehau static int 4584642ec226SSepherosa Ziehau hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS) 4585642ec226SSepherosa Ziehau { 4586642ec226SSepherosa Ziehau struct hn_softc *sc = arg1; 4587642ec226SSepherosa Ziehau char hash_str[128]; 4588642ec226SSepherosa Ziehau uint32_t hash; 4589642ec226SSepherosa Ziehau 4590642ec226SSepherosa Ziehau HN_LOCK(sc); 4591642ec226SSepherosa Ziehau hash = sc->hn_rss_hcap; 4592642ec226SSepherosa Ziehau HN_UNLOCK(sc); 4593642ec226SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 4594642ec226SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 4595642ec226SSepherosa Ziehau } 4596642ec226SSepherosa Ziehau 4597642ec226SSepherosa Ziehau static int 4598642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS) 4599642ec226SSepherosa Ziehau { 4600642ec226SSepherosa Ziehau struct hn_softc *sc = arg1; 4601642ec226SSepherosa Ziehau char hash_str[128]; 4602642ec226SSepherosa Ziehau uint32_t hash; 4603642ec226SSepherosa Ziehau 4604642ec226SSepherosa Ziehau HN_LOCK(sc); 4605642ec226SSepherosa Ziehau hash = sc->hn_rx_ring[0].hn_mbuf_hash; 4606642ec226SSepherosa Ziehau HN_UNLOCK(sc); 4607642ec226SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 4608642ec226SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 4609642ec226SSepherosa Ziehau } 4610642ec226SSepherosa Ziehau 4611642ec226SSepherosa Ziehau static int 461240d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS) 461340d60d6eSDexuan Cui { 461440d60d6eSDexuan Cui struct hn_softc *sc = arg1; 4615499c3e17SSepherosa Ziehau char vf_name[IFNAMSIZ + 1]; 4616962f0357SSepherosa Ziehau struct ifnet *vf_ifp; 461740d60d6eSDexuan Cui 461840d60d6eSDexuan Cui HN_LOCK(sc); 461940d60d6eSDexuan Cui vf_name[0] = '\0'; 4620962f0357SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 4621962f0357SSepherosa Ziehau if (vf_ifp != NULL) 4622962f0357SSepherosa Ziehau snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname); 462340d60d6eSDexuan Cui HN_UNLOCK(sc); 462440d60d6eSDexuan Cui return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); 462540d60d6eSDexuan Cui } 462640d60d6eSDexuan Cui 462740d60d6eSDexuan Cui static int 4628499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS) 4629499c3e17SSepherosa Ziehau { 4630499c3e17SSepherosa Ziehau struct hn_softc *sc = arg1; 4631499c3e17SSepherosa Ziehau char vf_name[IFNAMSIZ + 1]; 4632962f0357SSepherosa Ziehau struct ifnet *vf_ifp; 4633499c3e17SSepherosa Ziehau 4634499c3e17SSepherosa Ziehau HN_LOCK(sc); 4635499c3e17SSepherosa Ziehau vf_name[0] = '\0'; 4636962f0357SSepherosa Ziehau vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp; 4637962f0357SSepherosa Ziehau if (vf_ifp != NULL) 4638962f0357SSepherosa Ziehau snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname); 4639499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 4640499c3e17SSepherosa Ziehau return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); 4641499c3e17SSepherosa Ziehau } 4642499c3e17SSepherosa Ziehau 4643499c3e17SSepherosa Ziehau static int 4644499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS) 4645499c3e17SSepherosa Ziehau { 4646499c3e17SSepherosa Ziehau struct rm_priotracker pt; 4647499c3e17SSepherosa Ziehau struct sbuf *sb; 4648499c3e17SSepherosa Ziehau int error, i; 4649499c3e17SSepherosa Ziehau bool first; 4650499c3e17SSepherosa Ziehau 4651499c3e17SSepherosa Ziehau error = sysctl_wire_old_buffer(req, 0); 4652499c3e17SSepherosa Ziehau if (error != 0) 4653499c3e17SSepherosa Ziehau return (error); 4654499c3e17SSepherosa Ziehau 4655499c3e17SSepherosa Ziehau sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4656499c3e17SSepherosa Ziehau if (sb == NULL) 4657499c3e17SSepherosa Ziehau return (ENOMEM); 4658499c3e17SSepherosa Ziehau 4659499c3e17SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 4660499c3e17SSepherosa Ziehau 4661499c3e17SSepherosa Ziehau first = true; 4662499c3e17SSepherosa Ziehau for (i = 0; i < hn_vfmap_size; ++i) { 4663499c3e17SSepherosa Ziehau struct ifnet *ifp; 4664499c3e17SSepherosa Ziehau 4665499c3e17SSepherosa Ziehau if (hn_vfmap[i] == NULL) 4666499c3e17SSepherosa Ziehau continue; 4667499c3e17SSepherosa Ziehau 4668499c3e17SSepherosa Ziehau ifp = ifnet_byindex(i); 4669499c3e17SSepherosa Ziehau if (ifp != NULL) { 4670499c3e17SSepherosa Ziehau if (first) 4671499c3e17SSepherosa Ziehau sbuf_printf(sb, "%s", ifp->if_xname); 4672499c3e17SSepherosa Ziehau else 4673499c3e17SSepherosa Ziehau sbuf_printf(sb, " %s", ifp->if_xname); 4674499c3e17SSepherosa Ziehau first = false; 4675499c3e17SSepherosa Ziehau } 4676499c3e17SSepherosa Ziehau } 4677499c3e17SSepherosa Ziehau 4678499c3e17SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 4679499c3e17SSepherosa Ziehau 4680499c3e17SSepherosa Ziehau error = sbuf_finish(sb); 4681499c3e17SSepherosa Ziehau sbuf_delete(sb); 4682499c3e17SSepherosa Ziehau return (error); 4683499c3e17SSepherosa Ziehau } 4684499c3e17SSepherosa Ziehau 4685499c3e17SSepherosa Ziehau static int 4686499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS) 4687499c3e17SSepherosa Ziehau { 4688499c3e17SSepherosa Ziehau struct rm_priotracker pt; 4689499c3e17SSepherosa Ziehau struct sbuf *sb; 4690499c3e17SSepherosa Ziehau int error, i; 4691499c3e17SSepherosa Ziehau bool first; 4692499c3e17SSepherosa Ziehau 4693499c3e17SSepherosa Ziehau error = sysctl_wire_old_buffer(req, 0); 4694499c3e17SSepherosa Ziehau if (error != 0) 4695499c3e17SSepherosa Ziehau return (error); 4696499c3e17SSepherosa Ziehau 4697499c3e17SSepherosa Ziehau sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4698499c3e17SSepherosa Ziehau if (sb == NULL) 4699499c3e17SSepherosa Ziehau return (ENOMEM); 4700499c3e17SSepherosa Ziehau 4701499c3e17SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 4702499c3e17SSepherosa Ziehau 4703499c3e17SSepherosa Ziehau first = true; 4704499c3e17SSepherosa Ziehau for (i = 0; i < hn_vfmap_size; ++i) { 4705499c3e17SSepherosa Ziehau struct ifnet *ifp, *hn_ifp; 4706499c3e17SSepherosa Ziehau 4707499c3e17SSepherosa Ziehau hn_ifp = hn_vfmap[i]; 4708499c3e17SSepherosa Ziehau if (hn_ifp == NULL) 4709499c3e17SSepherosa Ziehau continue; 4710499c3e17SSepherosa Ziehau 4711499c3e17SSepherosa Ziehau ifp = ifnet_byindex(i); 4712499c3e17SSepherosa Ziehau if (ifp != NULL) { 4713499c3e17SSepherosa Ziehau if (first) { 4714499c3e17SSepherosa Ziehau sbuf_printf(sb, "%s:%s", ifp->if_xname, 4715499c3e17SSepherosa Ziehau hn_ifp->if_xname); 4716499c3e17SSepherosa Ziehau } else { 4717499c3e17SSepherosa Ziehau sbuf_printf(sb, " %s:%s", ifp->if_xname, 4718499c3e17SSepherosa Ziehau hn_ifp->if_xname); 4719499c3e17SSepherosa Ziehau } 4720499c3e17SSepherosa Ziehau first = false; 4721499c3e17SSepherosa Ziehau } 4722499c3e17SSepherosa Ziehau } 4723499c3e17SSepherosa Ziehau 4724499c3e17SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 4725499c3e17SSepherosa Ziehau 4726499c3e17SSepherosa Ziehau error = sbuf_finish(sb); 4727499c3e17SSepherosa Ziehau sbuf_delete(sb); 4728499c3e17SSepherosa Ziehau return (error); 4729499c3e17SSepherosa Ziehau } 4730499c3e17SSepherosa Ziehau 4731499c3e17SSepherosa Ziehau static int 47329c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS) 47339c6cae24SSepherosa Ziehau { 47349c6cae24SSepherosa Ziehau struct hn_softc *sc = arg1; 47359c6cae24SSepherosa Ziehau int error, onoff = 0; 47369c6cae24SSepherosa Ziehau 47379c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) 47389c6cae24SSepherosa Ziehau onoff = 1; 47399c6cae24SSepherosa Ziehau error = sysctl_handle_int(oidp, &onoff, 0, req); 47409c6cae24SSepherosa Ziehau if (error || req->newptr == NULL) 47419c6cae24SSepherosa Ziehau return (error); 47429c6cae24SSepherosa Ziehau 47439c6cae24SSepherosa Ziehau HN_LOCK(sc); 47449c6cae24SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit() */ 47459c6cae24SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 47469c6cae24SSepherosa Ziehau if (onoff) 47479c6cae24SSepherosa Ziehau sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF; 47489c6cae24SSepherosa Ziehau else 47499c6cae24SSepherosa Ziehau sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF; 47509c6cae24SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 47519c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 47529c6cae24SSepherosa Ziehau 47539c6cae24SSepherosa Ziehau return (0); 47549c6cae24SSepherosa Ziehau } 47559c6cae24SSepherosa Ziehau 47569c6cae24SSepherosa Ziehau static int 47579c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS) 47589c6cae24SSepherosa Ziehau { 47599c6cae24SSepherosa Ziehau struct hn_softc *sc = arg1; 47609c6cae24SSepherosa Ziehau int enabled = 0; 47619c6cae24SSepherosa Ziehau 47629c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 47639c6cae24SSepherosa Ziehau enabled = 1; 47649c6cae24SSepherosa Ziehau return (sysctl_handle_int(oidp, &enabled, 0, req)); 47659c6cae24SSepherosa Ziehau } 47669c6cae24SSepherosa Ziehau 47679c6cae24SSepherosa Ziehau static int 476815516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff) 476915516c77SSepherosa Ziehau { 477015516c77SSepherosa Ziehau const struct ip *ip; 477115516c77SSepherosa Ziehau int len, iphlen, iplen; 477215516c77SSepherosa Ziehau const struct tcphdr *th; 477315516c77SSepherosa Ziehau int thoff; /* TCP data offset */ 477415516c77SSepherosa Ziehau 477515516c77SSepherosa Ziehau len = hoff + sizeof(struct ip); 477615516c77SSepherosa Ziehau 477715516c77SSepherosa Ziehau /* The packet must be at least the size of an IP header. */ 477815516c77SSepherosa Ziehau if (m->m_pkthdr.len < len) 477915516c77SSepherosa Ziehau return IPPROTO_DONE; 478015516c77SSepherosa Ziehau 478115516c77SSepherosa Ziehau /* The fixed IP header must reside completely in the first mbuf. */ 478215516c77SSepherosa Ziehau if (m->m_len < len) 478315516c77SSepherosa Ziehau return IPPROTO_DONE; 478415516c77SSepherosa Ziehau 478515516c77SSepherosa Ziehau ip = mtodo(m, hoff); 478615516c77SSepherosa Ziehau 478715516c77SSepherosa Ziehau /* Bound check the packet's stated IP header length. */ 478815516c77SSepherosa Ziehau iphlen = ip->ip_hl << 2; 478915516c77SSepherosa Ziehau if (iphlen < sizeof(struct ip)) /* minimum header length */ 479015516c77SSepherosa Ziehau return IPPROTO_DONE; 479115516c77SSepherosa Ziehau 479215516c77SSepherosa Ziehau /* The full IP header must reside completely in the one mbuf. */ 479315516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen) 479415516c77SSepherosa Ziehau return IPPROTO_DONE; 479515516c77SSepherosa Ziehau 479615516c77SSepherosa Ziehau iplen = ntohs(ip->ip_len); 479715516c77SSepherosa Ziehau 479815516c77SSepherosa Ziehau /* 479915516c77SSepherosa Ziehau * Check that the amount of data in the buffers is as 480015516c77SSepherosa Ziehau * at least much as the IP header would have us expect. 480115516c77SSepherosa Ziehau */ 480215516c77SSepherosa Ziehau if (m->m_pkthdr.len < hoff + iplen) 480315516c77SSepherosa Ziehau return IPPROTO_DONE; 480415516c77SSepherosa Ziehau 480515516c77SSepherosa Ziehau /* 480615516c77SSepherosa Ziehau * Ignore IP fragments. 480715516c77SSepherosa Ziehau */ 480815516c77SSepherosa Ziehau if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF)) 480915516c77SSepherosa Ziehau return IPPROTO_DONE; 481015516c77SSepherosa Ziehau 481115516c77SSepherosa Ziehau /* 481215516c77SSepherosa Ziehau * The TCP/IP or UDP/IP header must be entirely contained within 481315516c77SSepherosa Ziehau * the first fragment of a packet. 481415516c77SSepherosa Ziehau */ 481515516c77SSepherosa Ziehau switch (ip->ip_p) { 481615516c77SSepherosa Ziehau case IPPROTO_TCP: 481715516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct tcphdr)) 481815516c77SSepherosa Ziehau return IPPROTO_DONE; 481915516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct tcphdr)) 482015516c77SSepherosa Ziehau return IPPROTO_DONE; 482115516c77SSepherosa Ziehau th = (const struct tcphdr *)((const uint8_t *)ip + iphlen); 482215516c77SSepherosa Ziehau thoff = th->th_off << 2; 482315516c77SSepherosa Ziehau if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen) 482415516c77SSepherosa Ziehau return IPPROTO_DONE; 482515516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + thoff) 482615516c77SSepherosa Ziehau return IPPROTO_DONE; 482715516c77SSepherosa Ziehau break; 482815516c77SSepherosa Ziehau case IPPROTO_UDP: 482915516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct udphdr)) 483015516c77SSepherosa Ziehau return IPPROTO_DONE; 483115516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct udphdr)) 483215516c77SSepherosa Ziehau return IPPROTO_DONE; 483315516c77SSepherosa Ziehau break; 483415516c77SSepherosa Ziehau default: 483515516c77SSepherosa Ziehau if (iplen < iphlen) 483615516c77SSepherosa Ziehau return IPPROTO_DONE; 483715516c77SSepherosa Ziehau break; 483815516c77SSepherosa Ziehau } 483915516c77SSepherosa Ziehau return ip->ip_p; 484015516c77SSepherosa Ziehau } 484115516c77SSepherosa Ziehau 484215516c77SSepherosa Ziehau static int 484315516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt) 484415516c77SSepherosa Ziehau { 484515516c77SSepherosa Ziehau struct sysctl_oid_list *child; 484615516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 484715516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 484815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 484915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 485015516c77SSepherosa Ziehau int lroent_cnt; 485115516c77SSepherosa Ziehau #endif 485215516c77SSepherosa Ziehau #endif 485315516c77SSepherosa Ziehau int i; 485415516c77SSepherosa Ziehau 485515516c77SSepherosa Ziehau /* 485615516c77SSepherosa Ziehau * Create RXBUF for reception. 485715516c77SSepherosa Ziehau * 485815516c77SSepherosa Ziehau * NOTE: 485915516c77SSepherosa Ziehau * - It is shared by all channels. 486015516c77SSepherosa Ziehau * - A large enough buffer is allocated, certain version of NVSes 486115516c77SSepherosa Ziehau * may further limit the usable space. 486215516c77SSepherosa Ziehau */ 486315516c77SSepherosa Ziehau sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 486415516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma, 486515516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 486615516c77SSepherosa Ziehau if (sc->hn_rxbuf == NULL) { 486715516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate rxbuf failed\n"); 486815516c77SSepherosa Ziehau return (ENOMEM); 486915516c77SSepherosa Ziehau } 487015516c77SSepherosa Ziehau 487115516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = ring_cnt; 487215516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt; 487315516c77SSepherosa Ziehau 487415516c77SSepherosa Ziehau sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt, 487515516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 487615516c77SSepherosa Ziehau 487715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 487815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 487915516c77SSepherosa Ziehau lroent_cnt = hn_lro_entry_count; 488015516c77SSepherosa Ziehau if (lroent_cnt < TCP_LRO_ENTRIES) 488115516c77SSepherosa Ziehau lroent_cnt = TCP_LRO_ENTRIES; 488215516c77SSepherosa Ziehau if (bootverbose) 488315516c77SSepherosa Ziehau device_printf(dev, "LRO: entry count %d\n", lroent_cnt); 488415516c77SSepherosa Ziehau #endif 488515516c77SSepherosa Ziehau #endif /* INET || INET6 */ 488615516c77SSepherosa Ziehau 488715516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 488815516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 488915516c77SSepherosa Ziehau 489015516c77SSepherosa Ziehau /* Create dev.hn.UNIT.rx sysctl tree */ 489115516c77SSepherosa Ziehau sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx", 489215516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 489315516c77SSepherosa Ziehau 489415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 489515516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 489615516c77SSepherosa Ziehau 489715516c77SSepherosa Ziehau rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 489815516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE, 489915516c77SSepherosa Ziehau &rxr->hn_br_dma, BUS_DMA_WAITOK); 490015516c77SSepherosa Ziehau if (rxr->hn_br == NULL) { 490115516c77SSepherosa Ziehau device_printf(dev, "allocate bufring failed\n"); 490215516c77SSepherosa Ziehau return (ENOMEM); 490315516c77SSepherosa Ziehau } 490415516c77SSepherosa Ziehau 490515516c77SSepherosa Ziehau if (hn_trust_hosttcp) 490615516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP; 490715516c77SSepherosa Ziehau if (hn_trust_hostudp) 490815516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP; 490915516c77SSepherosa Ziehau if (hn_trust_hostip) 491015516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP; 4911642ec226SSepherosa Ziehau rxr->hn_mbuf_hash = NDIS_HASH_ALL; 491215516c77SSepherosa Ziehau rxr->hn_ifp = sc->hn_ifp; 491315516c77SSepherosa Ziehau if (i < sc->hn_tx_ring_cnt) 491415516c77SSepherosa Ziehau rxr->hn_txr = &sc->hn_tx_ring[i]; 491515516c77SSepherosa Ziehau rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF; 491615516c77SSepherosa Ziehau rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK); 491715516c77SSepherosa Ziehau rxr->hn_rx_idx = i; 491815516c77SSepherosa Ziehau rxr->hn_rxbuf = sc->hn_rxbuf; 491915516c77SSepherosa Ziehau 492015516c77SSepherosa Ziehau /* 492115516c77SSepherosa Ziehau * Initialize LRO. 492215516c77SSepherosa Ziehau */ 492315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 492415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 492515516c77SSepherosa Ziehau tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt, 492615516c77SSepherosa Ziehau hn_lro_mbufq_depth); 492715516c77SSepherosa Ziehau #else 492815516c77SSepherosa Ziehau tcp_lro_init(&rxr->hn_lro); 492915516c77SSepherosa Ziehau rxr->hn_lro.ifp = sc->hn_ifp; 493015516c77SSepherosa Ziehau #endif 493115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 493215516c77SSepherosa Ziehau rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF; 493315516c77SSepherosa Ziehau rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF; 493415516c77SSepherosa Ziehau #endif 493515516c77SSepherosa Ziehau #endif /* INET || INET6 */ 493615516c77SSepherosa Ziehau 493715516c77SSepherosa Ziehau if (sc->hn_rx_sysctl_tree != NULL) { 493815516c77SSepherosa Ziehau char name[16]; 493915516c77SSepherosa Ziehau 494015516c77SSepherosa Ziehau /* 494115516c77SSepherosa Ziehau * Create per RX ring sysctl tree: 494215516c77SSepherosa Ziehau * dev.hn.UNIT.rx.RINGID 494315516c77SSepherosa Ziehau */ 494415516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", i); 494515516c77SSepherosa Ziehau rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, 494615516c77SSepherosa Ziehau SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree), 494715516c77SSepherosa Ziehau OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 494815516c77SSepherosa Ziehau 494915516c77SSepherosa Ziehau if (rxr->hn_rx_sysctl_tree != NULL) { 495015516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 495115516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 495215516c77SSepherosa Ziehau OID_AUTO, "packets", CTLFLAG_RW, 495315516c77SSepherosa Ziehau &rxr->hn_pkts, "# of packets received"); 495415516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 495515516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 495615516c77SSepherosa Ziehau OID_AUTO, "rss_pkts", CTLFLAG_RW, 495715516c77SSepherosa Ziehau &rxr->hn_rss_pkts, 495815516c77SSepherosa Ziehau "# of packets w/ RSS info received"); 495915516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, 496015516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 496115516c77SSepherosa Ziehau OID_AUTO, "pktbuf_len", CTLFLAG_RD, 496215516c77SSepherosa Ziehau &rxr->hn_pktbuf_len, 0, 496315516c77SSepherosa Ziehau "Temporary channel packet buffer length"); 496415516c77SSepherosa Ziehau } 496515516c77SSepherosa Ziehau } 496615516c77SSepherosa Ziehau } 496715516c77SSepherosa Ziehau 496815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued", 496915516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 497015516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_queued), 497115516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 497215516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 497315516c77SSepherosa Ziehau #else 497415516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 497515516c77SSepherosa Ziehau #endif 497615516c77SSepherosa Ziehau "LU", "LRO queued"); 497715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed", 497815516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 497915516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_flushed), 498015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 498115516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 498215516c77SSepherosa Ziehau #else 498315516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 498415516c77SSepherosa Ziehau #endif 498515516c77SSepherosa Ziehau "LU", "LRO flushed"); 498615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried", 498715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 498815516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro_tried), 498915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries"); 499015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 499115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim", 499215516c77SSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 499315516c77SSepherosa Ziehau hn_lro_lenlim_sysctl, "IU", 499415516c77SSepherosa Ziehau "Max # of data bytes to be aggregated by LRO"); 499515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim", 499615516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 499715516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl, "I", 499815516c77SSepherosa Ziehau "Max # of ACKs to be aggregated by LRO"); 499915516c77SSepherosa Ziehau #endif 500015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp", 500115516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP, 500215516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 500315516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 500415516c77SSepherosa Ziehau "when csum info is missing"); 500515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp", 500615516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP, 500715516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 500815516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 500915516c77SSepherosa Ziehau "when csum info is missing"); 501015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip", 501115516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP, 501215516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 501315516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 501415516c77SSepherosa Ziehau "when csum info is missing"); 501515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip", 501615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 501715516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_ip), 501815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP"); 501915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp", 502015516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 502115516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_tcp), 502215516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP"); 502315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp", 502415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 502515516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_udp), 502615516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP"); 502715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted", 502815516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 502915516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_trusted), 503015516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", 503115516c77SSepherosa Ziehau "# of packets that we trust host's csum verification"); 503215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts", 503315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 503415516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_small_pkts), 503515516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of small packets received"); 503615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed", 503715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 503815516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_ack_failed), 503915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures"); 504015516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt", 504115516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings"); 504215516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse", 504315516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings"); 504415516c77SSepherosa Ziehau 504515516c77SSepherosa Ziehau return (0); 504615516c77SSepherosa Ziehau } 504715516c77SSepherosa Ziehau 504815516c77SSepherosa Ziehau static void 504915516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc) 505015516c77SSepherosa Ziehau { 505115516c77SSepherosa Ziehau int i; 505215516c77SSepherosa Ziehau 505315516c77SSepherosa Ziehau if (sc->hn_rxbuf != NULL) { 50542494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0) 505515516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf); 50562494d735SSepherosa Ziehau else 50572494d735SSepherosa Ziehau device_printf(sc->hn_dev, "RXBUF is referenced\n"); 505815516c77SSepherosa Ziehau sc->hn_rxbuf = NULL; 505915516c77SSepherosa Ziehau } 506015516c77SSepherosa Ziehau 506115516c77SSepherosa Ziehau if (sc->hn_rx_ring_cnt == 0) 506215516c77SSepherosa Ziehau return; 506315516c77SSepherosa Ziehau 506415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 506515516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 506615516c77SSepherosa Ziehau 506715516c77SSepherosa Ziehau if (rxr->hn_br == NULL) 506815516c77SSepherosa Ziehau continue; 50692494d735SSepherosa Ziehau if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) { 507015516c77SSepherosa Ziehau hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br); 50712494d735SSepherosa Ziehau } else { 50722494d735SSepherosa Ziehau device_printf(sc->hn_dev, 50732494d735SSepherosa Ziehau "%dth channel bufring is referenced", i); 50742494d735SSepherosa Ziehau } 507515516c77SSepherosa Ziehau rxr->hn_br = NULL; 507615516c77SSepherosa Ziehau 507715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 507815516c77SSepherosa Ziehau tcp_lro_free(&rxr->hn_lro); 507915516c77SSepherosa Ziehau #endif 508015516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 508115516c77SSepherosa Ziehau } 508215516c77SSepherosa Ziehau free(sc->hn_rx_ring, M_DEVBUF); 508315516c77SSepherosa Ziehau sc->hn_rx_ring = NULL; 508415516c77SSepherosa Ziehau 508515516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = 0; 508615516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = 0; 508715516c77SSepherosa Ziehau } 508815516c77SSepherosa Ziehau 508915516c77SSepherosa Ziehau static int 509015516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id) 509115516c77SSepherosa Ziehau { 509215516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[id]; 509315516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 509415516c77SSepherosa Ziehau bus_dma_tag_t parent_dtag; 509515516c77SSepherosa Ziehau int error, i; 509615516c77SSepherosa Ziehau 509715516c77SSepherosa Ziehau txr->hn_sc = sc; 509815516c77SSepherosa Ziehau txr->hn_tx_idx = id; 509915516c77SSepherosa Ziehau 510015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 510115516c77SSepherosa Ziehau mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); 510215516c77SSepherosa Ziehau #endif 510315516c77SSepherosa Ziehau mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF); 510415516c77SSepherosa Ziehau 510515516c77SSepherosa Ziehau txr->hn_txdesc_cnt = HN_TX_DESC_CNT; 510615516c77SSepherosa Ziehau txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt, 510715516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 510815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 510915516c77SSepherosa Ziehau SLIST_INIT(&txr->hn_txlist); 511015516c77SSepherosa Ziehau #else 511115516c77SSepherosa Ziehau txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF, 511215516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 511315516c77SSepherosa Ziehau #endif 511415516c77SSepherosa Ziehau 51150e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) { 51160e11868dSSepherosa Ziehau txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ( 51170e11868dSSepherosa Ziehau device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id)); 51180e11868dSSepherosa Ziehau } else { 5119fdd0222aSSepherosa Ziehau txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt]; 51200e11868dSSepherosa Ziehau } 512115516c77SSepherosa Ziehau 512223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 512315516c77SSepherosa Ziehau if (hn_use_if_start) { 512415516c77SSepherosa Ziehau txr->hn_txeof = hn_start_txeof; 512515516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr); 512615516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr); 512723bf9e15SSepherosa Ziehau } else 512823bf9e15SSepherosa Ziehau #endif 512923bf9e15SSepherosa Ziehau { 513015516c77SSepherosa Ziehau int br_depth; 513115516c77SSepherosa Ziehau 513215516c77SSepherosa Ziehau txr->hn_txeof = hn_xmit_txeof; 513315516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr); 513415516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr); 513515516c77SSepherosa Ziehau 513615516c77SSepherosa Ziehau br_depth = hn_get_txswq_depth(txr); 513715516c77SSepherosa Ziehau txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF, 513815516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 513915516c77SSepherosa Ziehau } 514015516c77SSepherosa Ziehau 514115516c77SSepherosa Ziehau txr->hn_direct_tx_size = hn_direct_tx_size; 514215516c77SSepherosa Ziehau 514315516c77SSepherosa Ziehau /* 514415516c77SSepherosa Ziehau * Always schedule transmission instead of trying to do direct 514515516c77SSepherosa Ziehau * transmission. This one gives the best performance so far. 514615516c77SSepherosa Ziehau */ 514715516c77SSepherosa Ziehau txr->hn_sched_tx = 1; 514815516c77SSepherosa Ziehau 514915516c77SSepherosa Ziehau parent_dtag = bus_get_dma_tag(dev); 515015516c77SSepherosa Ziehau 515115516c77SSepherosa Ziehau /* DMA tag for RNDIS packet messages. */ 515215516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 515315516c77SSepherosa Ziehau HN_RNDIS_PKT_ALIGN, /* alignment */ 515415516c77SSepherosa Ziehau HN_RNDIS_PKT_BOUNDARY, /* boundary */ 515515516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 515615516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 515715516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 515815516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsize */ 515915516c77SSepherosa Ziehau 1, /* nsegments */ 516015516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsegsize */ 516115516c77SSepherosa Ziehau 0, /* flags */ 516215516c77SSepherosa Ziehau NULL, /* lockfunc */ 516315516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 516415516c77SSepherosa Ziehau &txr->hn_tx_rndis_dtag); 516515516c77SSepherosa Ziehau if (error) { 516615516c77SSepherosa Ziehau device_printf(dev, "failed to create rndis dmatag\n"); 516715516c77SSepherosa Ziehau return error; 516815516c77SSepherosa Ziehau } 516915516c77SSepherosa Ziehau 517015516c77SSepherosa Ziehau /* DMA tag for data. */ 517115516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 517215516c77SSepherosa Ziehau 1, /* alignment */ 517315516c77SSepherosa Ziehau HN_TX_DATA_BOUNDARY, /* boundary */ 517415516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 517515516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 517615516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 517715516c77SSepherosa Ziehau HN_TX_DATA_MAXSIZE, /* maxsize */ 517815516c77SSepherosa Ziehau HN_TX_DATA_SEGCNT_MAX, /* nsegments */ 517915516c77SSepherosa Ziehau HN_TX_DATA_SEGSIZE, /* maxsegsize */ 518015516c77SSepherosa Ziehau 0, /* flags */ 518115516c77SSepherosa Ziehau NULL, /* lockfunc */ 518215516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 518315516c77SSepherosa Ziehau &txr->hn_tx_data_dtag); 518415516c77SSepherosa Ziehau if (error) { 518515516c77SSepherosa Ziehau device_printf(dev, "failed to create data dmatag\n"); 518615516c77SSepherosa Ziehau return error; 518715516c77SSepherosa Ziehau } 518815516c77SSepherosa Ziehau 518915516c77SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) { 519015516c77SSepherosa Ziehau struct hn_txdesc *txd = &txr->hn_txdesc[i]; 519115516c77SSepherosa Ziehau 519215516c77SSepherosa Ziehau txd->txr = txr; 519315516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 5194dc13fee6SSepherosa Ziehau STAILQ_INIT(&txd->agg_list); 519515516c77SSepherosa Ziehau 519615516c77SSepherosa Ziehau /* 519715516c77SSepherosa Ziehau * Allocate and load RNDIS packet message. 519815516c77SSepherosa Ziehau */ 519915516c77SSepherosa Ziehau error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag, 520015516c77SSepherosa Ziehau (void **)&txd->rndis_pkt, 520115516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 520215516c77SSepherosa Ziehau &txd->rndis_pkt_dmap); 520315516c77SSepherosa Ziehau if (error) { 520415516c77SSepherosa Ziehau device_printf(dev, 520515516c77SSepherosa Ziehau "failed to allocate rndis_packet_msg, %d\n", i); 520615516c77SSepherosa Ziehau return error; 520715516c77SSepherosa Ziehau } 520815516c77SSepherosa Ziehau 520915516c77SSepherosa Ziehau error = bus_dmamap_load(txr->hn_tx_rndis_dtag, 521015516c77SSepherosa Ziehau txd->rndis_pkt_dmap, 521115516c77SSepherosa Ziehau txd->rndis_pkt, HN_RNDIS_PKT_LEN, 521215516c77SSepherosa Ziehau hyperv_dma_map_paddr, &txd->rndis_pkt_paddr, 521315516c77SSepherosa Ziehau BUS_DMA_NOWAIT); 521415516c77SSepherosa Ziehau if (error) { 521515516c77SSepherosa Ziehau device_printf(dev, 521615516c77SSepherosa Ziehau "failed to load rndis_packet_msg, %d\n", i); 521715516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 521815516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 521915516c77SSepherosa Ziehau return error; 522015516c77SSepherosa Ziehau } 522115516c77SSepherosa Ziehau 522215516c77SSepherosa Ziehau /* DMA map for TX data. */ 522315516c77SSepherosa Ziehau error = bus_dmamap_create(txr->hn_tx_data_dtag, 0, 522415516c77SSepherosa Ziehau &txd->data_dmap); 522515516c77SSepherosa Ziehau if (error) { 522615516c77SSepherosa Ziehau device_printf(dev, 522715516c77SSepherosa Ziehau "failed to allocate tx data dmamap\n"); 522815516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, 522915516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 523015516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 523115516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 523215516c77SSepherosa Ziehau return error; 523315516c77SSepherosa Ziehau } 523415516c77SSepherosa Ziehau 523515516c77SSepherosa Ziehau /* All set, put it to list */ 523615516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 523715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 523815516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 523915516c77SSepherosa Ziehau #else 524015516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 524115516c77SSepherosa Ziehau #endif 524215516c77SSepherosa Ziehau } 524315516c77SSepherosa Ziehau txr->hn_txdesc_avail = txr->hn_txdesc_cnt; 524415516c77SSepherosa Ziehau 524515516c77SSepherosa Ziehau if (sc->hn_tx_sysctl_tree != NULL) { 524615516c77SSepherosa Ziehau struct sysctl_oid_list *child; 524715516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 524815516c77SSepherosa Ziehau char name[16]; 524915516c77SSepherosa Ziehau 525015516c77SSepherosa Ziehau /* 525115516c77SSepherosa Ziehau * Create per TX ring sysctl tree: 525215516c77SSepherosa Ziehau * dev.hn.UNIT.tx.RINGID 525315516c77SSepherosa Ziehau */ 525415516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 525515516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree); 525615516c77SSepherosa Ziehau 525715516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", id); 525815516c77SSepherosa Ziehau txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, 525915516c77SSepherosa Ziehau name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 526015516c77SSepherosa Ziehau 526115516c77SSepherosa Ziehau if (txr->hn_tx_sysctl_tree != NULL) { 526215516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree); 526315516c77SSepherosa Ziehau 526485e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 526515516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail", 526615516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_txdesc_avail, 0, 526715516c77SSepherosa Ziehau "# of available TX descs"); 526885e4ae1eSSepherosa Ziehau #endif 526923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 527023bf9e15SSepherosa Ziehau if (!hn_use_if_start) 527123bf9e15SSepherosa Ziehau #endif 527223bf9e15SSepherosa Ziehau { 527315516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive", 527415516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_oactive, 0, 527515516c77SSepherosa Ziehau "over active"); 527615516c77SSepherosa Ziehau } 527715516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets", 527815516c77SSepherosa Ziehau CTLFLAG_RW, &txr->hn_pkts, 527915516c77SSepherosa Ziehau "# of packets transmitted"); 5280dc13fee6SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends", 5281dc13fee6SSepherosa Ziehau CTLFLAG_RW, &txr->hn_sends, "# of sends"); 528215516c77SSepherosa Ziehau } 528315516c77SSepherosa Ziehau } 528415516c77SSepherosa Ziehau 528515516c77SSepherosa Ziehau return 0; 528615516c77SSepherosa Ziehau } 528715516c77SSepherosa Ziehau 528815516c77SSepherosa Ziehau static void 528915516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd) 529015516c77SSepherosa Ziehau { 529115516c77SSepherosa Ziehau struct hn_tx_ring *txr = txd->txr; 529215516c77SSepherosa Ziehau 529315516c77SSepherosa Ziehau KASSERT(txd->m == NULL, ("still has mbuf installed")); 529415516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped")); 529515516c77SSepherosa Ziehau 529615516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap); 529715516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt, 529815516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 529915516c77SSepherosa Ziehau bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap); 530015516c77SSepherosa Ziehau } 530115516c77SSepherosa Ziehau 530215516c77SSepherosa Ziehau static void 530325641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd) 530425641fc7SSepherosa Ziehau { 530525641fc7SSepherosa Ziehau 530625641fc7SSepherosa Ziehau KASSERT(txd->refs == 0 || txd->refs == 1, 530725641fc7SSepherosa Ziehau ("invalid txd refs %d", txd->refs)); 530825641fc7SSepherosa Ziehau 530925641fc7SSepherosa Ziehau /* Aggregated txds will be freed by their aggregating txd. */ 531025641fc7SSepherosa Ziehau if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) { 531125641fc7SSepherosa Ziehau int freed; 531225641fc7SSepherosa Ziehau 531325641fc7SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 531425641fc7SSepherosa Ziehau KASSERT(freed, ("can't free txdesc")); 531525641fc7SSepherosa Ziehau } 531625641fc7SSepherosa Ziehau } 531725641fc7SSepherosa Ziehau 531825641fc7SSepherosa Ziehau static void 531915516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr) 532015516c77SSepherosa Ziehau { 532125641fc7SSepherosa Ziehau int i; 532215516c77SSepherosa Ziehau 532315516c77SSepherosa Ziehau if (txr->hn_txdesc == NULL) 532415516c77SSepherosa Ziehau return; 532515516c77SSepherosa Ziehau 532625641fc7SSepherosa Ziehau /* 532725641fc7SSepherosa Ziehau * NOTE: 532825641fc7SSepherosa Ziehau * Because the freeing of aggregated txds will be deferred 532925641fc7SSepherosa Ziehau * to the aggregating txd, two passes are used here: 533025641fc7SSepherosa Ziehau * - The first pass GCes any pending txds. This GC is necessary, 533125641fc7SSepherosa Ziehau * since if the channels are revoked, hypervisor will not 533225641fc7SSepherosa Ziehau * deliver send-done for all pending txds. 533325641fc7SSepherosa Ziehau * - The second pass frees the busdma stuffs, i.e. after all txds 533425641fc7SSepherosa Ziehau * were freed. 533525641fc7SSepherosa Ziehau */ 533625641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 533725641fc7SSepherosa Ziehau hn_txdesc_gc(txr, &txr->hn_txdesc[i]); 533825641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 533925641fc7SSepherosa Ziehau hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]); 534015516c77SSepherosa Ziehau 534115516c77SSepherosa Ziehau if (txr->hn_tx_data_dtag != NULL) 534215516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_data_dtag); 534315516c77SSepherosa Ziehau if (txr->hn_tx_rndis_dtag != NULL) 534415516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_rndis_dtag); 534515516c77SSepherosa Ziehau 534615516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 534715516c77SSepherosa Ziehau buf_ring_free(txr->hn_txdesc_br, M_DEVBUF); 534815516c77SSepherosa Ziehau #endif 534915516c77SSepherosa Ziehau 535015516c77SSepherosa Ziehau free(txr->hn_txdesc, M_DEVBUF); 535115516c77SSepherosa Ziehau txr->hn_txdesc = NULL; 535215516c77SSepherosa Ziehau 535315516c77SSepherosa Ziehau if (txr->hn_mbuf_br != NULL) 535415516c77SSepherosa Ziehau buf_ring_free(txr->hn_mbuf_br, M_DEVBUF); 535515516c77SSepherosa Ziehau 535615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 535715516c77SSepherosa Ziehau mtx_destroy(&txr->hn_txlist_spin); 535815516c77SSepherosa Ziehau #endif 535915516c77SSepherosa Ziehau mtx_destroy(&txr->hn_tx_lock); 536015516c77SSepherosa Ziehau } 536115516c77SSepherosa Ziehau 536215516c77SSepherosa Ziehau static int 536315516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt) 536415516c77SSepherosa Ziehau { 536515516c77SSepherosa Ziehau struct sysctl_oid_list *child; 536615516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 536715516c77SSepherosa Ziehau int i; 536815516c77SSepherosa Ziehau 536915516c77SSepherosa Ziehau /* 537015516c77SSepherosa Ziehau * Create TXBUF for chimney sending. 537115516c77SSepherosa Ziehau * 537215516c77SSepherosa Ziehau * NOTE: It is shared by all channels. 537315516c77SSepherosa Ziehau */ 537415516c77SSepherosa Ziehau sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), 537515516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma, 537615516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 537715516c77SSepherosa Ziehau if (sc->hn_chim == NULL) { 537815516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate txbuf failed\n"); 537915516c77SSepherosa Ziehau return (ENOMEM); 538015516c77SSepherosa Ziehau } 538115516c77SSepherosa Ziehau 538215516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = ring_cnt; 538315516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 538415516c77SSepherosa Ziehau 538515516c77SSepherosa Ziehau sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt, 538615516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 538715516c77SSepherosa Ziehau 538815516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(sc->hn_dev); 538915516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev)); 539015516c77SSepherosa Ziehau 539115516c77SSepherosa Ziehau /* Create dev.hn.UNIT.tx sysctl tree */ 539215516c77SSepherosa Ziehau sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx", 539315516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 539415516c77SSepherosa Ziehau 539515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 539615516c77SSepherosa Ziehau int error; 539715516c77SSepherosa Ziehau 539815516c77SSepherosa Ziehau error = hn_tx_ring_create(sc, i); 539915516c77SSepherosa Ziehau if (error) 540015516c77SSepherosa Ziehau return error; 540115516c77SSepherosa Ziehau } 540215516c77SSepherosa Ziehau 540315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs", 540415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 540515516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_no_txdescs), 540615516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs"); 540715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed", 540815516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 540915516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_send_failed), 541015516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure"); 541115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed", 541215516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 541315516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_txdma_failed), 541415516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure"); 5415dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed", 5416dc13fee6SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 5417dc13fee6SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_flush_failed), 5418dc13fee6SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", 5419dc13fee6SSepherosa Ziehau "# of packet transmission aggregation flush failure"); 542015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed", 542115516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 542215516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_collapsed), 542315516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed"); 542415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney", 542515516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 542615516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney), 542715516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send"); 542815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried", 542915516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 543015516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney_tried), 543115516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries"); 543215516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt", 543315516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0, 543415516c77SSepherosa Ziehau "# of total TX descs"); 543515516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max", 543615516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_chim_szmax, 0, 543715516c77SSepherosa Ziehau "Chimney send packet size upper boundary"); 543815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size", 543915516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 544015516c77SSepherosa Ziehau hn_chim_size_sysctl, "I", "Chimney send packet size limit"); 544115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size", 544215516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 544315516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_direct_tx_size), 544415516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 544515516c77SSepherosa Ziehau "Size of the packet for direct transmission"); 544615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx", 544715516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 544815516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_sched_tx), 544915516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 545015516c77SSepherosa Ziehau "Always schedule transmission " 545115516c77SSepherosa Ziehau "instead of doing direct transmission"); 545215516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt", 545315516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings"); 545415516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse", 545515516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings"); 5456dc13fee6SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax", 5457dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0, 5458dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation size"); 5459dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax", 5460dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 5461dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl, "I", 5462dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation packets"); 5463dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align", 5464dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 5465dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl, "I", 5466dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation alignment"); 546715516c77SSepherosa Ziehau 546815516c77SSepherosa Ziehau return 0; 546915516c77SSepherosa Ziehau } 547015516c77SSepherosa Ziehau 547115516c77SSepherosa Ziehau static void 547215516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size) 547315516c77SSepherosa Ziehau { 547415516c77SSepherosa Ziehau int i; 547515516c77SSepherosa Ziehau 5476a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 547715516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_chim_size = chim_size; 547815516c77SSepherosa Ziehau } 547915516c77SSepherosa Ziehau 548015516c77SSepherosa Ziehau static void 548115516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu) 548215516c77SSepherosa Ziehau { 548315516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 54849c6cae24SSepherosa Ziehau u_int hw_tsomax; 548515516c77SSepherosa Ziehau int tso_minlen; 548615516c77SSepherosa Ziehau 54879c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 54889c6cae24SSepherosa Ziehau 548915516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0) 549015516c77SSepherosa Ziehau return; 549115516c77SSepherosa Ziehau 549215516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_sgmin >= 2, 549315516c77SSepherosa Ziehau ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin)); 549415516c77SSepherosa Ziehau tso_minlen = sc->hn_ndis_tso_sgmin * mtu; 549515516c77SSepherosa Ziehau 549615516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen && 549715516c77SSepherosa Ziehau sc->hn_ndis_tso_szmax <= IP_MAXPACKET, 549815516c77SSepherosa Ziehau ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax)); 549915516c77SSepherosa Ziehau 550015516c77SSepherosa Ziehau if (tso_maxlen < tso_minlen) 550115516c77SSepherosa Ziehau tso_maxlen = tso_minlen; 550215516c77SSepherosa Ziehau else if (tso_maxlen > IP_MAXPACKET) 550315516c77SSepherosa Ziehau tso_maxlen = IP_MAXPACKET; 550415516c77SSepherosa Ziehau if (tso_maxlen > sc->hn_ndis_tso_szmax) 550515516c77SSepherosa Ziehau tso_maxlen = sc->hn_ndis_tso_szmax; 55069c6cae24SSepherosa Ziehau hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 55079c6cae24SSepherosa Ziehau 55089c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 55099c6cae24SSepherosa Ziehau if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax) 55109c6cae24SSepherosa Ziehau hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax; 55119c6cae24SSepherosa Ziehau } 55129c6cae24SSepherosa Ziehau ifp->if_hw_tsomax = hw_tsomax; 551315516c77SSepherosa Ziehau if (bootverbose) 551415516c77SSepherosa Ziehau if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax); 551515516c77SSepherosa Ziehau } 551615516c77SSepherosa Ziehau 551715516c77SSepherosa Ziehau static void 551815516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc) 551915516c77SSepherosa Ziehau { 552015516c77SSepherosa Ziehau uint64_t csum_assist; 552115516c77SSepherosa Ziehau int i; 552215516c77SSepherosa Ziehau 552315516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 552415516c77SSepherosa Ziehau if (hn_tx_chimney_size > 0 && 552515516c77SSepherosa Ziehau hn_tx_chimney_size < sc->hn_chim_szmax) 552615516c77SSepherosa Ziehau hn_set_chim_size(sc, hn_tx_chimney_size); 552715516c77SSepherosa Ziehau 552815516c77SSepherosa Ziehau csum_assist = 0; 552915516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_IPCS) 553015516c77SSepherosa Ziehau csum_assist |= CSUM_IP; 553115516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP4CS) 553215516c77SSepherosa Ziehau csum_assist |= CSUM_IP_TCP; 55332be266caSSepherosa Ziehau if ((sc->hn_caps & HN_CAP_UDP4CS) && hn_enable_udp4cs) 553415516c77SSepherosa Ziehau csum_assist |= CSUM_IP_UDP; 553515516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP6CS) 553615516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_TCP; 55372be266caSSepherosa Ziehau if ((sc->hn_caps & HN_CAP_UDP6CS) && hn_enable_udp6cs) 553815516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_UDP; 553915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 554015516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_csum_assist = csum_assist; 554115516c77SSepherosa Ziehau 554215516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_HASHVAL) { 554315516c77SSepherosa Ziehau /* 554415516c77SSepherosa Ziehau * Support HASHVAL pktinfo on TX path. 554515516c77SSepherosa Ziehau */ 554615516c77SSepherosa Ziehau if (bootverbose) 554715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n"); 554815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 554915516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL; 555015516c77SSepherosa Ziehau } 555115516c77SSepherosa Ziehau } 555215516c77SSepherosa Ziehau 555315516c77SSepherosa Ziehau static void 555415516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc) 555515516c77SSepherosa Ziehau { 555615516c77SSepherosa Ziehau int i; 555715516c77SSepherosa Ziehau 555815516c77SSepherosa Ziehau if (sc->hn_chim != NULL) { 55592494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) { 556015516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim); 55612494d735SSepherosa Ziehau } else { 55622494d735SSepherosa Ziehau device_printf(sc->hn_dev, 55632494d735SSepherosa Ziehau "chimney sending buffer is referenced"); 55642494d735SSepherosa Ziehau } 556515516c77SSepherosa Ziehau sc->hn_chim = NULL; 556615516c77SSepherosa Ziehau } 556715516c77SSepherosa Ziehau 556815516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt == 0) 556915516c77SSepherosa Ziehau return; 557015516c77SSepherosa Ziehau 557115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 557215516c77SSepherosa Ziehau hn_tx_ring_destroy(&sc->hn_tx_ring[i]); 557315516c77SSepherosa Ziehau 557415516c77SSepherosa Ziehau free(sc->hn_tx_ring, M_DEVBUF); 557515516c77SSepherosa Ziehau sc->hn_tx_ring = NULL; 557615516c77SSepherosa Ziehau 557715516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = 0; 557815516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = 0; 557915516c77SSepherosa Ziehau } 558015516c77SSepherosa Ziehau 558123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 558223bf9e15SSepherosa Ziehau 558315516c77SSepherosa Ziehau static void 558415516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused) 558515516c77SSepherosa Ziehau { 558615516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 558715516c77SSepherosa Ziehau 558815516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 558915516c77SSepherosa Ziehau hn_start_locked(txr, 0); 559015516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 559115516c77SSepherosa Ziehau } 559215516c77SSepherosa Ziehau 559323bf9e15SSepherosa Ziehau static int 559423bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len) 559523bf9e15SSepherosa Ziehau { 559623bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 559723bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 5598dc13fee6SSepherosa Ziehau int sched = 0; 559923bf9e15SSepherosa Ziehau 560023bf9e15SSepherosa Ziehau KASSERT(hn_use_if_start, 560123bf9e15SSepherosa Ziehau ("hn_start_locked is called, when if_start is disabled")); 560223bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 560323bf9e15SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 5604dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 560523bf9e15SSepherosa Ziehau 560623bf9e15SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 5607dc13fee6SSepherosa Ziehau return (0); 560823bf9e15SSepherosa Ziehau 560923bf9e15SSepherosa Ziehau if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 561023bf9e15SSepherosa Ziehau IFF_DRV_RUNNING) 5611dc13fee6SSepherosa Ziehau return (0); 561223bf9e15SSepherosa Ziehau 561323bf9e15SSepherosa Ziehau while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 561423bf9e15SSepherosa Ziehau struct hn_txdesc *txd; 561523bf9e15SSepherosa Ziehau struct mbuf *m_head; 561623bf9e15SSepherosa Ziehau int error; 561723bf9e15SSepherosa Ziehau 561823bf9e15SSepherosa Ziehau IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 561923bf9e15SSepherosa Ziehau if (m_head == NULL) 562023bf9e15SSepherosa Ziehau break; 562123bf9e15SSepherosa Ziehau 562223bf9e15SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 562323bf9e15SSepherosa Ziehau /* 562423bf9e15SSepherosa Ziehau * This sending could be time consuming; let callers 562523bf9e15SSepherosa Ziehau * dispatch this packet sending (and sending of any 562623bf9e15SSepherosa Ziehau * following up packets) to tx taskqueue. 562723bf9e15SSepherosa Ziehau */ 562823bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 5629dc13fee6SSepherosa Ziehau sched = 1; 5630dc13fee6SSepherosa Ziehau break; 563123bf9e15SSepherosa Ziehau } 563223bf9e15SSepherosa Ziehau 5633edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 5634edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 5635edd3f315SSepherosa Ziehau m_head = hn_tso_fixup(m_head); 5636edd3f315SSepherosa Ziehau if (__predict_false(m_head == NULL)) { 5637edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 5638edd3f315SSepherosa Ziehau continue; 5639edd3f315SSepherosa Ziehau } 5640c49d47daSSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & 5641c49d47daSSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) { 5642c49d47daSSepherosa Ziehau m_head = hn_set_hlen(m_head); 5643c49d47daSSepherosa Ziehau if (__predict_false(m_head == NULL)) { 5644c49d47daSSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 5645c49d47daSSepherosa Ziehau continue; 5646c49d47daSSepherosa Ziehau } 5647edd3f315SSepherosa Ziehau } 5648edd3f315SSepherosa Ziehau #endif 5649edd3f315SSepherosa Ziehau 565023bf9e15SSepherosa Ziehau txd = hn_txdesc_get(txr); 565123bf9e15SSepherosa Ziehau if (txd == NULL) { 565223bf9e15SSepherosa Ziehau txr->hn_no_txdescs++; 565323bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 565423bf9e15SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 565523bf9e15SSepherosa Ziehau break; 565623bf9e15SSepherosa Ziehau } 565723bf9e15SSepherosa Ziehau 5658dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 565923bf9e15SSepherosa Ziehau if (error) { 566023bf9e15SSepherosa Ziehau /* Both txd and m_head are freed */ 5661dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 5662dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 566323bf9e15SSepherosa Ziehau continue; 566423bf9e15SSepherosa Ziehau } 566523bf9e15SSepherosa Ziehau 5666dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 5667dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 5668dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5669dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5670dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 5671dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 5672dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 5673dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 5674dc13fee6SSepherosa Ziehau break; 5675dc13fee6SSepherosa Ziehau } 5676dc13fee6SSepherosa Ziehau } else { 5677dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 567823bf9e15SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 567923bf9e15SSepherosa Ziehau if (__predict_false(error)) { 568023bf9e15SSepherosa Ziehau /* txd is freed, but m_head is not */ 568123bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 5682dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 5683dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 568423bf9e15SSepherosa Ziehau break; 568523bf9e15SSepherosa Ziehau } 568623bf9e15SSepherosa Ziehau } 5687dc13fee6SSepherosa Ziehau } 5688dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 5689dc13fee6SSepherosa Ziehau else { 5690dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 5691dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 5692dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5693dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5694dc13fee6SSepherosa Ziehau } 5695dc13fee6SSepherosa Ziehau #endif 5696dc13fee6SSepherosa Ziehau } 5697dc13fee6SSepherosa Ziehau 5698dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 5699dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 5700dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 5701dc13fee6SSepherosa Ziehau return (sched); 570223bf9e15SSepherosa Ziehau } 570323bf9e15SSepherosa Ziehau 570423bf9e15SSepherosa Ziehau static void 570523bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp) 570623bf9e15SSepherosa Ziehau { 570723bf9e15SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 570823bf9e15SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[0]; 570923bf9e15SSepherosa Ziehau 571023bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 571123bf9e15SSepherosa Ziehau goto do_sched; 571223bf9e15SSepherosa Ziehau 571323bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 571423bf9e15SSepherosa Ziehau int sched; 571523bf9e15SSepherosa Ziehau 571623bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 571723bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 571823bf9e15SSepherosa Ziehau if (!sched) 571923bf9e15SSepherosa Ziehau return; 572023bf9e15SSepherosa Ziehau } 572123bf9e15SSepherosa Ziehau do_sched: 572223bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 572323bf9e15SSepherosa Ziehau } 572423bf9e15SSepherosa Ziehau 572515516c77SSepherosa Ziehau static void 572615516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused) 572715516c77SSepherosa Ziehau { 572815516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 572915516c77SSepherosa Ziehau 573015516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 573115516c77SSepherosa Ziehau atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE); 573215516c77SSepherosa Ziehau hn_start_locked(txr, 0); 573315516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 573415516c77SSepherosa Ziehau } 573515516c77SSepherosa Ziehau 573623bf9e15SSepherosa Ziehau static void 573723bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr) 573823bf9e15SSepherosa Ziehau { 573923bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 574023bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 574123bf9e15SSepherosa Ziehau 574223bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 574323bf9e15SSepherosa Ziehau 574423bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 574523bf9e15SSepherosa Ziehau goto do_sched; 574623bf9e15SSepherosa Ziehau 574723bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 574823bf9e15SSepherosa Ziehau int sched; 574923bf9e15SSepherosa Ziehau 575023bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 575123bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 575223bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 575323bf9e15SSepherosa Ziehau if (sched) { 575423bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 575523bf9e15SSepherosa Ziehau &txr->hn_tx_task); 575623bf9e15SSepherosa Ziehau } 575723bf9e15SSepherosa Ziehau } else { 575823bf9e15SSepherosa Ziehau do_sched: 575923bf9e15SSepherosa Ziehau /* 576023bf9e15SSepherosa Ziehau * Release the OACTIVE earlier, with the hope, that 576123bf9e15SSepherosa Ziehau * others could catch up. The task will clear the 576223bf9e15SSepherosa Ziehau * flag again with the hn_tx_lock to avoid possible 576323bf9e15SSepherosa Ziehau * races. 576423bf9e15SSepherosa Ziehau */ 576523bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 576623bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 576723bf9e15SSepherosa Ziehau } 576823bf9e15SSepherosa Ziehau } 576923bf9e15SSepherosa Ziehau 577023bf9e15SSepherosa Ziehau #endif /* HN_IFSTART_SUPPORT */ 577123bf9e15SSepherosa Ziehau 577215516c77SSepherosa Ziehau static int 577315516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len) 577415516c77SSepherosa Ziehau { 577515516c77SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 577615516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 577715516c77SSepherosa Ziehau struct mbuf *m_head; 5778dc13fee6SSepherosa Ziehau int sched = 0; 577915516c77SSepherosa Ziehau 578015516c77SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 578123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 578215516c77SSepherosa Ziehau KASSERT(hn_use_if_start == 0, 578315516c77SSepherosa Ziehau ("hn_xmit is called, when if_start is enabled")); 578423bf9e15SSepherosa Ziehau #endif 5785dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 578615516c77SSepherosa Ziehau 578715516c77SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 5788dc13fee6SSepherosa Ziehau return (0); 578915516c77SSepherosa Ziehau 579015516c77SSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive) 5791dc13fee6SSepherosa Ziehau return (0); 579215516c77SSepherosa Ziehau 579315516c77SSepherosa Ziehau while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) { 579415516c77SSepherosa Ziehau struct hn_txdesc *txd; 579515516c77SSepherosa Ziehau int error; 579615516c77SSepherosa Ziehau 579715516c77SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 579815516c77SSepherosa Ziehau /* 579915516c77SSepherosa Ziehau * This sending could be time consuming; let callers 580015516c77SSepherosa Ziehau * dispatch this packet sending (and sending of any 580115516c77SSepherosa Ziehau * following up packets) to tx taskqueue. 580215516c77SSepherosa Ziehau */ 580315516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 5804dc13fee6SSepherosa Ziehau sched = 1; 5805dc13fee6SSepherosa Ziehau break; 580615516c77SSepherosa Ziehau } 580715516c77SSepherosa Ziehau 580815516c77SSepherosa Ziehau txd = hn_txdesc_get(txr); 580915516c77SSepherosa Ziehau if (txd == NULL) { 581015516c77SSepherosa Ziehau txr->hn_no_txdescs++; 581115516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 581215516c77SSepherosa Ziehau txr->hn_oactive = 1; 581315516c77SSepherosa Ziehau break; 581415516c77SSepherosa Ziehau } 581515516c77SSepherosa Ziehau 5816dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 581715516c77SSepherosa Ziehau if (error) { 581815516c77SSepherosa Ziehau /* Both txd and m_head are freed; discard */ 5819dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 5820dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 582115516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 582215516c77SSepherosa Ziehau continue; 582315516c77SSepherosa Ziehau } 582415516c77SSepherosa Ziehau 5825dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 5826dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 5827dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5828dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5829dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 583015516c77SSepherosa Ziehau if (__predict_false(error)) { 583115516c77SSepherosa Ziehau txr->hn_oactive = 1; 583215516c77SSepherosa Ziehau break; 583315516c77SSepherosa Ziehau } 5834dc13fee6SSepherosa Ziehau } else { 5835dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 5836dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 5837dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 5838dc13fee6SSepherosa Ziehau /* txd is freed, but m_head is not */ 5839dc13fee6SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, 5840dc13fee6SSepherosa Ziehau m_head); 5841dc13fee6SSepherosa Ziehau txr->hn_oactive = 1; 5842dc13fee6SSepherosa Ziehau break; 5843dc13fee6SSepherosa Ziehau } 5844dc13fee6SSepherosa Ziehau } 5845dc13fee6SSepherosa Ziehau } 5846dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 5847dc13fee6SSepherosa Ziehau else { 5848dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 5849dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 5850dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5851dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5852dc13fee6SSepherosa Ziehau } 5853dc13fee6SSepherosa Ziehau #endif 585415516c77SSepherosa Ziehau 585515516c77SSepherosa Ziehau /* Sent */ 585615516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 585715516c77SSepherosa Ziehau } 5858dc13fee6SSepherosa Ziehau 5859dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 5860dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 5861dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 5862dc13fee6SSepherosa Ziehau return (sched); 586315516c77SSepherosa Ziehau } 586415516c77SSepherosa Ziehau 586515516c77SSepherosa Ziehau static int 586615516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m) 586715516c77SSepherosa Ziehau { 586815516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 586915516c77SSepherosa Ziehau struct hn_tx_ring *txr; 587015516c77SSepherosa Ziehau int error, idx = 0; 587115516c77SSepherosa Ziehau 58729c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) { 58739c6cae24SSepherosa Ziehau struct rm_priotracker pt; 58749c6cae24SSepherosa Ziehau 58759c6cae24SSepherosa Ziehau rm_rlock(&sc->hn_vf_lock, &pt); 58769c6cae24SSepherosa Ziehau if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { 58779c6cae24SSepherosa Ziehau struct mbuf *m_bpf = NULL; 58789c6cae24SSepherosa Ziehau int obytes, omcast; 58799c6cae24SSepherosa Ziehau 58809c6cae24SSepherosa Ziehau obytes = m->m_pkthdr.len; 58819c6cae24SSepherosa Ziehau if (m->m_flags & M_MCAST) 58829c6cae24SSepherosa Ziehau omcast = 1; 58839c6cae24SSepherosa Ziehau 58849c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) { 58859c6cae24SSepherosa Ziehau if (bpf_peers_present(ifp->if_bpf)) { 58869c6cae24SSepherosa Ziehau m_bpf = m_copypacket(m, M_NOWAIT); 58879c6cae24SSepherosa Ziehau if (m_bpf == NULL) { 58889c6cae24SSepherosa Ziehau /* 58899c6cae24SSepherosa Ziehau * Failed to grab a shallow 58909c6cae24SSepherosa Ziehau * copy; tap now. 58919c6cae24SSepherosa Ziehau */ 58929c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m); 58939c6cae24SSepherosa Ziehau } 58949c6cae24SSepherosa Ziehau } 58959c6cae24SSepherosa Ziehau } else { 58969c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m); 58979c6cae24SSepherosa Ziehau } 58989c6cae24SSepherosa Ziehau 58999c6cae24SSepherosa Ziehau error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m); 59009c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 59019c6cae24SSepherosa Ziehau 59029c6cae24SSepherosa Ziehau if (m_bpf != NULL) { 59039c6cae24SSepherosa Ziehau if (!error) 59049c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m_bpf); 59059c6cae24SSepherosa Ziehau m_freem(m_bpf); 59069c6cae24SSepherosa Ziehau } 59079c6cae24SSepherosa Ziehau 59089c6cae24SSepherosa Ziehau if (error == ENOBUFS) { 59099c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 59109c6cae24SSepherosa Ziehau } else if (error) { 59119c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 59129c6cae24SSepherosa Ziehau } else { 59139c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 59149c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes); 59159c6cae24SSepherosa Ziehau if (omcast) { 59169c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 59179c6cae24SSepherosa Ziehau omcast); 59189c6cae24SSepherosa Ziehau } 59199c6cae24SSepherosa Ziehau } 59209c6cae24SSepherosa Ziehau return (error); 59219c6cae24SSepherosa Ziehau } 59229c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 59239c6cae24SSepherosa Ziehau } 59249c6cae24SSepherosa Ziehau 5925edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 5926edd3f315SSepherosa Ziehau /* 5927c49d47daSSepherosa Ziehau * Perform TSO packet header fixup or get l2/l3 header length now, 5928c49d47daSSepherosa Ziehau * since packet headers should be cache-hot. 5929edd3f315SSepherosa Ziehau */ 5930edd3f315SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 5931edd3f315SSepherosa Ziehau m = hn_tso_fixup(m); 5932edd3f315SSepherosa Ziehau if (__predict_false(m == NULL)) { 5933edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 5934edd3f315SSepherosa Ziehau return EIO; 5935edd3f315SSepherosa Ziehau } 5936c49d47daSSepherosa Ziehau } else if (m->m_pkthdr.csum_flags & 5937c49d47daSSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) { 5938c49d47daSSepherosa Ziehau m = hn_set_hlen(m); 5939c49d47daSSepherosa Ziehau if (__predict_false(m == NULL)) { 5940c49d47daSSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 5941c49d47daSSepherosa Ziehau return EIO; 5942c49d47daSSepherosa Ziehau } 5943edd3f315SSepherosa Ziehau } 5944edd3f315SSepherosa Ziehau #endif 5945edd3f315SSepherosa Ziehau 594615516c77SSepherosa Ziehau /* 594715516c77SSepherosa Ziehau * Select the TX ring based on flowid 594815516c77SSepherosa Ziehau */ 594934d68912SSepherosa Ziehau if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 595034d68912SSepherosa Ziehau #ifdef RSS 595134d68912SSepherosa Ziehau uint32_t bid; 595234d68912SSepherosa Ziehau 595334d68912SSepherosa Ziehau if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m), 595434d68912SSepherosa Ziehau &bid) == 0) 595534d68912SSepherosa Ziehau idx = bid % sc->hn_tx_ring_inuse; 595634d68912SSepherosa Ziehau else 595734d68912SSepherosa Ziehau #endif 5958cc0c6ebcSSepherosa Ziehau { 5959cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET) 5960cc0c6ebcSSepherosa Ziehau int tcpsyn = 0; 5961cc0c6ebcSSepherosa Ziehau 5962cc0c6ebcSSepherosa Ziehau if (m->m_pkthdr.len < 128 && 5963cc0c6ebcSSepherosa Ziehau (m->m_pkthdr.csum_flags & 5964cc0c6ebcSSepherosa Ziehau (CSUM_IP_TCP | CSUM_IP6_TCP)) && 5965cc0c6ebcSSepherosa Ziehau (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) { 5966cc0c6ebcSSepherosa Ziehau m = hn_check_tcpsyn(m, &tcpsyn); 5967cc0c6ebcSSepherosa Ziehau if (__predict_false(m == NULL)) { 5968cc0c6ebcSSepherosa Ziehau if_inc_counter(ifp, 5969cc0c6ebcSSepherosa Ziehau IFCOUNTER_OERRORS, 1); 5970cc0c6ebcSSepherosa Ziehau return (EIO); 5971cc0c6ebcSSepherosa Ziehau } 5972cc0c6ebcSSepherosa Ziehau } 5973cc0c6ebcSSepherosa Ziehau #else 5974cc0c6ebcSSepherosa Ziehau const int tcpsyn = 0; 5975cc0c6ebcSSepherosa Ziehau #endif 5976cc0c6ebcSSepherosa Ziehau if (tcpsyn) 5977cc0c6ebcSSepherosa Ziehau idx = 0; 5978cc0c6ebcSSepherosa Ziehau else 597915516c77SSepherosa Ziehau idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse; 598034d68912SSepherosa Ziehau } 5981cc0c6ebcSSepherosa Ziehau } 598215516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 598315516c77SSepherosa Ziehau 598415516c77SSepherosa Ziehau error = drbr_enqueue(ifp, txr->hn_mbuf_br, m); 598515516c77SSepherosa Ziehau if (error) { 598615516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 598715516c77SSepherosa Ziehau return error; 598815516c77SSepherosa Ziehau } 598915516c77SSepherosa Ziehau 599015516c77SSepherosa Ziehau if (txr->hn_oactive) 599115516c77SSepherosa Ziehau return 0; 599215516c77SSepherosa Ziehau 599315516c77SSepherosa Ziehau if (txr->hn_sched_tx) 599415516c77SSepherosa Ziehau goto do_sched; 599515516c77SSepherosa Ziehau 599615516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 599715516c77SSepherosa Ziehau int sched; 599815516c77SSepherosa Ziehau 599915516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 600015516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 600115516c77SSepherosa Ziehau if (!sched) 600215516c77SSepherosa Ziehau return 0; 600315516c77SSepherosa Ziehau } 600415516c77SSepherosa Ziehau do_sched: 600515516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 600615516c77SSepherosa Ziehau return 0; 600715516c77SSepherosa Ziehau } 600815516c77SSepherosa Ziehau 600915516c77SSepherosa Ziehau static void 601015516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr) 601115516c77SSepherosa Ziehau { 601215516c77SSepherosa Ziehau struct mbuf *m; 601315516c77SSepherosa Ziehau 601415516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 601515516c77SSepherosa Ziehau while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL) 601615516c77SSepherosa Ziehau m_freem(m); 601715516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 601815516c77SSepherosa Ziehau } 601915516c77SSepherosa Ziehau 602015516c77SSepherosa Ziehau static void 602115516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp) 602215516c77SSepherosa Ziehau { 602315516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 60249c6cae24SSepherosa Ziehau struct rm_priotracker pt; 602515516c77SSepherosa Ziehau int i; 602615516c77SSepherosa Ziehau 602715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 602815516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 602915516c77SSepherosa Ziehau if_qflush(ifp); 60309c6cae24SSepherosa Ziehau 60319c6cae24SSepherosa Ziehau rm_rlock(&sc->hn_vf_lock, &pt); 60329c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 60339c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp); 60349c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 603515516c77SSepherosa Ziehau } 603615516c77SSepherosa Ziehau 603715516c77SSepherosa Ziehau static void 603815516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr) 603915516c77SSepherosa Ziehau { 604015516c77SSepherosa Ziehau 604115516c77SSepherosa Ziehau if (txr->hn_sched_tx) 604215516c77SSepherosa Ziehau goto do_sched; 604315516c77SSepherosa Ziehau 604415516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 604515516c77SSepherosa Ziehau int sched; 604615516c77SSepherosa Ziehau 604715516c77SSepherosa Ziehau txr->hn_oactive = 0; 604815516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 604915516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 605015516c77SSepherosa Ziehau if (sched) { 605115516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 605215516c77SSepherosa Ziehau &txr->hn_tx_task); 605315516c77SSepherosa Ziehau } 605415516c77SSepherosa Ziehau } else { 605515516c77SSepherosa Ziehau do_sched: 605615516c77SSepherosa Ziehau /* 605715516c77SSepherosa Ziehau * Release the oactive earlier, with the hope, that 605815516c77SSepherosa Ziehau * others could catch up. The task will clear the 605915516c77SSepherosa Ziehau * oactive again with the hn_tx_lock to avoid possible 606015516c77SSepherosa Ziehau * races. 606115516c77SSepherosa Ziehau */ 606215516c77SSepherosa Ziehau txr->hn_oactive = 0; 606315516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 606415516c77SSepherosa Ziehau } 606515516c77SSepherosa Ziehau } 606615516c77SSepherosa Ziehau 606715516c77SSepherosa Ziehau static void 606815516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused) 606915516c77SSepherosa Ziehau { 607015516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 607115516c77SSepherosa Ziehau 607215516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 607315516c77SSepherosa Ziehau hn_xmit(txr, 0); 607415516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 607515516c77SSepherosa Ziehau } 607615516c77SSepherosa Ziehau 607715516c77SSepherosa Ziehau static void 607815516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused) 607915516c77SSepherosa Ziehau { 608015516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 608115516c77SSepherosa Ziehau 608215516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 608315516c77SSepherosa Ziehau txr->hn_oactive = 0; 608415516c77SSepherosa Ziehau hn_xmit(txr, 0); 608515516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 608615516c77SSepherosa Ziehau } 608715516c77SSepherosa Ziehau 608815516c77SSepherosa Ziehau static int 608915516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan) 609015516c77SSepherosa Ziehau { 609115516c77SSepherosa Ziehau struct vmbus_chan_br cbr; 609215516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 609315516c77SSepherosa Ziehau struct hn_tx_ring *txr = NULL; 609415516c77SSepherosa Ziehau int idx, error; 609515516c77SSepherosa Ziehau 609615516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 609715516c77SSepherosa Ziehau 609815516c77SSepherosa Ziehau /* 609915516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 610015516c77SSepherosa Ziehau */ 610115516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 610215516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 610315516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 610415516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 610515516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0, 610615516c77SSepherosa Ziehau ("RX ring %d already attached", idx)); 610715516c77SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED; 61083ab0fea1SDexuan Cui rxr->hn_chan = chan; 610915516c77SSepherosa Ziehau 611015516c77SSepherosa Ziehau if (bootverbose) { 611115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n", 611215516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 611315516c77SSepherosa Ziehau } 611415516c77SSepherosa Ziehau 611515516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 611615516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 611715516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0, 611815516c77SSepherosa Ziehau ("TX ring %d already attached", idx)); 611915516c77SSepherosa Ziehau txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED; 612015516c77SSepherosa Ziehau 612115516c77SSepherosa Ziehau txr->hn_chan = chan; 612215516c77SSepherosa Ziehau if (bootverbose) { 612315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n", 612415516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 612515516c77SSepherosa Ziehau } 612615516c77SSepherosa Ziehau } 612715516c77SSepherosa Ziehau 612815516c77SSepherosa Ziehau /* Bind this channel to a proper CPU. */ 61290e11868dSSepherosa Ziehau vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx)); 613015516c77SSepherosa Ziehau 613115516c77SSepherosa Ziehau /* 613215516c77SSepherosa Ziehau * Open this channel 613315516c77SSepherosa Ziehau */ 613415516c77SSepherosa Ziehau cbr.cbr = rxr->hn_br; 613515516c77SSepherosa Ziehau cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr; 613615516c77SSepherosa Ziehau cbr.cbr_txsz = HN_TXBR_SIZE; 613715516c77SSepherosa Ziehau cbr.cbr_rxsz = HN_RXBR_SIZE; 613815516c77SSepherosa Ziehau error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr); 613915516c77SSepherosa Ziehau if (error) { 614071e8ac56SSepherosa Ziehau if (error == EISCONN) { 614171e8ac56SSepherosa Ziehau if_printf(sc->hn_ifp, "bufring is connected after " 614271e8ac56SSepherosa Ziehau "chan%u open failure\n", vmbus_chan_id(chan)); 614371e8ac56SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 614471e8ac56SSepherosa Ziehau } else { 614515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "open chan%u failed: %d\n", 614615516c77SSepherosa Ziehau vmbus_chan_id(chan), error); 614771e8ac56SSepherosa Ziehau } 614815516c77SSepherosa Ziehau } 614915516c77SSepherosa Ziehau return (error); 615015516c77SSepherosa Ziehau } 615115516c77SSepherosa Ziehau 615215516c77SSepherosa Ziehau static void 615315516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan) 615415516c77SSepherosa Ziehau { 615515516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 61562494d735SSepherosa Ziehau int idx, error; 615715516c77SSepherosa Ziehau 615815516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 615915516c77SSepherosa Ziehau 616015516c77SSepherosa Ziehau /* 616115516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 616215516c77SSepherosa Ziehau */ 616315516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 616415516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 616515516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 616615516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 616715516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED), 616815516c77SSepherosa Ziehau ("RX ring %d is not attached", idx)); 616915516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 617015516c77SSepherosa Ziehau 617115516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 617215516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[idx]; 617315516c77SSepherosa Ziehau 617415516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED), 617515516c77SSepherosa Ziehau ("TX ring %d is not attached attached", idx)); 617615516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 617715516c77SSepherosa Ziehau } 617815516c77SSepherosa Ziehau 617915516c77SSepherosa Ziehau /* 618015516c77SSepherosa Ziehau * Close this channel. 618115516c77SSepherosa Ziehau * 618215516c77SSepherosa Ziehau * NOTE: 618315516c77SSepherosa Ziehau * Channel closing does _not_ destroy the target channel. 618415516c77SSepherosa Ziehau */ 61852494d735SSepherosa Ziehau error = vmbus_chan_close_direct(chan); 61862494d735SSepherosa Ziehau if (error == EISCONN) { 6187aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u bufring is connected " 6188aa1a2adcSSepherosa Ziehau "after being closed\n", vmbus_chan_id(chan)); 61892494d735SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 61902494d735SSepherosa Ziehau } else if (error) { 6191aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u close failed: %d\n", 6192aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), error); 61932494d735SSepherosa Ziehau } 619415516c77SSepherosa Ziehau } 619515516c77SSepherosa Ziehau 619615516c77SSepherosa Ziehau static int 619715516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc) 619815516c77SSepherosa Ziehau { 619915516c77SSepherosa Ziehau struct vmbus_channel **subchans; 620015516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 620115516c77SSepherosa Ziehau int i, error = 0; 620215516c77SSepherosa Ziehau 620371e8ac56SSepherosa Ziehau KASSERT(subchan_cnt > 0, ("no sub-channels")); 620415516c77SSepherosa Ziehau 620515516c77SSepherosa Ziehau /* Attach the sub-channels. */ 620615516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 620715516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) { 620871e8ac56SSepherosa Ziehau int error1; 620971e8ac56SSepherosa Ziehau 621071e8ac56SSepherosa Ziehau error1 = hn_chan_attach(sc, subchans[i]); 621171e8ac56SSepherosa Ziehau if (error1) { 621271e8ac56SSepherosa Ziehau error = error1; 621371e8ac56SSepherosa Ziehau /* Move on; all channels will be detached later. */ 621471e8ac56SSepherosa Ziehau } 621515516c77SSepherosa Ziehau } 621615516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 621715516c77SSepherosa Ziehau 621815516c77SSepherosa Ziehau if (error) { 621915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error); 622015516c77SSepherosa Ziehau } else { 622115516c77SSepherosa Ziehau if (bootverbose) { 622215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d sub-channels attached\n", 622315516c77SSepherosa Ziehau subchan_cnt); 622415516c77SSepherosa Ziehau } 622515516c77SSepherosa Ziehau } 622615516c77SSepherosa Ziehau return (error); 622715516c77SSepherosa Ziehau } 622815516c77SSepherosa Ziehau 622915516c77SSepherosa Ziehau static void 623015516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc) 623115516c77SSepherosa Ziehau { 623215516c77SSepherosa Ziehau struct vmbus_channel **subchans; 623315516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 623415516c77SSepherosa Ziehau int i; 623515516c77SSepherosa Ziehau 623615516c77SSepherosa Ziehau if (subchan_cnt == 0) 623715516c77SSepherosa Ziehau goto back; 623815516c77SSepherosa Ziehau 623915516c77SSepherosa Ziehau /* Detach the sub-channels. */ 624015516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 624115516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) 624215516c77SSepherosa Ziehau hn_chan_detach(sc, subchans[i]); 624315516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 624415516c77SSepherosa Ziehau 624515516c77SSepherosa Ziehau back: 624615516c77SSepherosa Ziehau /* 624715516c77SSepherosa Ziehau * Detach the primary channel, _after_ all sub-channels 624815516c77SSepherosa Ziehau * are detached. 624915516c77SSepherosa Ziehau */ 625015516c77SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 625115516c77SSepherosa Ziehau 625215516c77SSepherosa Ziehau /* Wait for sub-channels to be destroyed, if any. */ 625315516c77SSepherosa Ziehau vmbus_subchan_drain(sc->hn_prichan); 625415516c77SSepherosa Ziehau 625515516c77SSepherosa Ziehau #ifdef INVARIANTS 625615516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 625715516c77SSepherosa Ziehau KASSERT((sc->hn_rx_ring[i].hn_rx_flags & 625815516c77SSepherosa Ziehau HN_RX_FLAG_ATTACHED) == 0, 625915516c77SSepherosa Ziehau ("%dth RX ring is still attached", i)); 626015516c77SSepherosa Ziehau } 626115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 626215516c77SSepherosa Ziehau KASSERT((sc->hn_tx_ring[i].hn_tx_flags & 626315516c77SSepherosa Ziehau HN_TX_FLAG_ATTACHED) == 0, 626415516c77SSepherosa Ziehau ("%dth TX ring is still attached", i)); 626515516c77SSepherosa Ziehau } 626615516c77SSepherosa Ziehau #endif 626715516c77SSepherosa Ziehau } 626815516c77SSepherosa Ziehau 626915516c77SSepherosa Ziehau static int 627015516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch) 627115516c77SSepherosa Ziehau { 627215516c77SSepherosa Ziehau struct vmbus_channel **subchans; 627315516c77SSepherosa Ziehau int nchan, rxr_cnt, error; 627415516c77SSepherosa Ziehau 627515516c77SSepherosa Ziehau nchan = *nsubch + 1; 627615516c77SSepherosa Ziehau if (nchan == 1) { 627715516c77SSepherosa Ziehau /* 627815516c77SSepherosa Ziehau * Multiple RX/TX rings are not requested. 627915516c77SSepherosa Ziehau */ 628015516c77SSepherosa Ziehau *nsubch = 0; 628115516c77SSepherosa Ziehau return (0); 628215516c77SSepherosa Ziehau } 628315516c77SSepherosa Ziehau 628415516c77SSepherosa Ziehau /* 628515516c77SSepherosa Ziehau * Query RSS capabilities, e.g. # of RX rings, and # of indirect 628615516c77SSepherosa Ziehau * table entries. 628715516c77SSepherosa Ziehau */ 628815516c77SSepherosa Ziehau error = hn_rndis_query_rsscaps(sc, &rxr_cnt); 628915516c77SSepherosa Ziehau if (error) { 629015516c77SSepherosa Ziehau /* No RSS; this is benign. */ 629115516c77SSepherosa Ziehau *nsubch = 0; 629215516c77SSepherosa Ziehau return (0); 629315516c77SSepherosa Ziehau } 629415516c77SSepherosa Ziehau if (bootverbose) { 629515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n", 629615516c77SSepherosa Ziehau rxr_cnt, nchan); 629715516c77SSepherosa Ziehau } 629815516c77SSepherosa Ziehau 629915516c77SSepherosa Ziehau if (nchan > rxr_cnt) 630015516c77SSepherosa Ziehau nchan = rxr_cnt; 630115516c77SSepherosa Ziehau if (nchan == 1) { 630215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n"); 630315516c77SSepherosa Ziehau *nsubch = 0; 630415516c77SSepherosa Ziehau return (0); 630515516c77SSepherosa Ziehau } 630615516c77SSepherosa Ziehau 630715516c77SSepherosa Ziehau /* 630815516c77SSepherosa Ziehau * Allocate sub-channels from NVS. 630915516c77SSepherosa Ziehau */ 631015516c77SSepherosa Ziehau *nsubch = nchan - 1; 631115516c77SSepherosa Ziehau error = hn_nvs_alloc_subchans(sc, nsubch); 631215516c77SSepherosa Ziehau if (error || *nsubch == 0) { 631315516c77SSepherosa Ziehau /* Failed to allocate sub-channels. */ 631415516c77SSepherosa Ziehau *nsubch = 0; 631515516c77SSepherosa Ziehau return (0); 631615516c77SSepherosa Ziehau } 631715516c77SSepherosa Ziehau 631815516c77SSepherosa Ziehau /* 631915516c77SSepherosa Ziehau * Wait for all sub-channels to become ready before moving on. 632015516c77SSepherosa Ziehau */ 632115516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch); 632215516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, *nsubch); 632315516c77SSepherosa Ziehau return (0); 632415516c77SSepherosa Ziehau } 632515516c77SSepherosa Ziehau 63262494d735SSepherosa Ziehau static bool 63272494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc) 63282494d735SSepherosa Ziehau { 63292494d735SSepherosa Ziehau int i; 63302494d735SSepherosa Ziehau 63312494d735SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_ERRORS) 63322494d735SSepherosa Ziehau return (false); 63332494d735SSepherosa Ziehau 63342494d735SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 63352494d735SSepherosa Ziehau const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 63362494d735SSepherosa Ziehau 63372494d735SSepherosa Ziehau if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) 63382494d735SSepherosa Ziehau return (false); 63392494d735SSepherosa Ziehau } 63402494d735SSepherosa Ziehau return (true); 63412494d735SSepherosa Ziehau } 63422494d735SSepherosa Ziehau 6343b3b75d9cSSepherosa Ziehau /* 6344b3b75d9cSSepherosa Ziehau * Make sure that the RX filter is zero after the successful 6345b3b75d9cSSepherosa Ziehau * RNDIS initialization. 6346b3b75d9cSSepherosa Ziehau * 6347b3b75d9cSSepherosa Ziehau * NOTE: 6348b3b75d9cSSepherosa Ziehau * Under certain conditions on certain versions of Hyper-V, 6349b3b75d9cSSepherosa Ziehau * the RNDIS rxfilter is _not_ zero on the hypervisor side 6350b3b75d9cSSepherosa Ziehau * after the successful RNDIS initialization, which breaks 6351b3b75d9cSSepherosa Ziehau * the assumption of any following code (well, it breaks the 6352b3b75d9cSSepherosa Ziehau * RNDIS API contract actually). Clear the RNDIS rxfilter 6353b3b75d9cSSepherosa Ziehau * explicitly, drain packets sneaking through, and drain the 6354b3b75d9cSSepherosa Ziehau * interrupt taskqueues scheduled due to the stealth packets. 6355b3b75d9cSSepherosa Ziehau */ 6356b3b75d9cSSepherosa Ziehau static void 6357b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan) 6358b3b75d9cSSepherosa Ziehau { 6359b3b75d9cSSepherosa Ziehau 6360b3b75d9cSSepherosa Ziehau hn_disable_rx(sc); 6361b3b75d9cSSepherosa Ziehau hn_drain_rxtx(sc, nchan); 6362b3b75d9cSSepherosa Ziehau } 6363b3b75d9cSSepherosa Ziehau 636415516c77SSepherosa Ziehau static int 636515516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu) 636615516c77SSepherosa Ziehau { 636771e8ac56SSepherosa Ziehau #define ATTACHED_NVS 0x0002 636871e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS 0x0004 636971e8ac56SSepherosa Ziehau 637015516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 6371b3b75d9cSSepherosa Ziehau int error, nsubch, nchan = 1, i, rndis_inited; 637271e8ac56SSepherosa Ziehau uint32_t old_caps, attached = 0; 637315516c77SSepherosa Ziehau 637415516c77SSepherosa Ziehau KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0, 637515516c77SSepherosa Ziehau ("synthetic parts were attached")); 637615516c77SSepherosa Ziehau 63772494d735SSepherosa Ziehau if (!hn_synth_attachable(sc)) 63782494d735SSepherosa Ziehau return (ENXIO); 63792494d735SSepherosa Ziehau 638015516c77SSepherosa Ziehau /* Save capabilities for later verification. */ 638115516c77SSepherosa Ziehau old_caps = sc->hn_caps; 638215516c77SSepherosa Ziehau sc->hn_caps = 0; 638315516c77SSepherosa Ziehau 638415516c77SSepherosa Ziehau /* Clear RSS stuffs. */ 638515516c77SSepherosa Ziehau sc->hn_rss_ind_size = 0; 638615516c77SSepherosa Ziehau sc->hn_rss_hash = 0; 6387642ec226SSepherosa Ziehau sc->hn_rss_hcap = 0; 638815516c77SSepherosa Ziehau 638915516c77SSepherosa Ziehau /* 639015516c77SSepherosa Ziehau * Attach the primary channel _before_ attaching NVS and RNDIS. 639115516c77SSepherosa Ziehau */ 639215516c77SSepherosa Ziehau error = hn_chan_attach(sc, sc->hn_prichan); 639315516c77SSepherosa Ziehau if (error) 639471e8ac56SSepherosa Ziehau goto failed; 639515516c77SSepherosa Ziehau 639615516c77SSepherosa Ziehau /* 639715516c77SSepherosa Ziehau * Attach NVS. 639815516c77SSepherosa Ziehau */ 639915516c77SSepherosa Ziehau error = hn_nvs_attach(sc, mtu); 640015516c77SSepherosa Ziehau if (error) 640171e8ac56SSepherosa Ziehau goto failed; 640271e8ac56SSepherosa Ziehau attached |= ATTACHED_NVS; 640315516c77SSepherosa Ziehau 640415516c77SSepherosa Ziehau /* 640515516c77SSepherosa Ziehau * Attach RNDIS _after_ NVS is attached. 640615516c77SSepherosa Ziehau */ 6407b3b75d9cSSepherosa Ziehau error = hn_rndis_attach(sc, mtu, &rndis_inited); 6408b3b75d9cSSepherosa Ziehau if (rndis_inited) 6409b3b75d9cSSepherosa Ziehau attached |= ATTACHED_RNDIS; 641015516c77SSepherosa Ziehau if (error) 641171e8ac56SSepherosa Ziehau goto failed; 641215516c77SSepherosa Ziehau 641315516c77SSepherosa Ziehau /* 641415516c77SSepherosa Ziehau * Make sure capabilities are not changed. 641515516c77SSepherosa Ziehau */ 641615516c77SSepherosa Ziehau if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) { 641715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n", 641815516c77SSepherosa Ziehau old_caps, sc->hn_caps); 641971e8ac56SSepherosa Ziehau error = ENXIO; 642071e8ac56SSepherosa Ziehau goto failed; 642115516c77SSepherosa Ziehau } 642215516c77SSepherosa Ziehau 642315516c77SSepherosa Ziehau /* 642415516c77SSepherosa Ziehau * Allocate sub-channels for multi-TX/RX rings. 642515516c77SSepherosa Ziehau * 642615516c77SSepherosa Ziehau * NOTE: 642715516c77SSepherosa Ziehau * The # of RX rings that can be used is equivalent to the # of 642815516c77SSepherosa Ziehau * channels to be requested. 642915516c77SSepherosa Ziehau */ 643015516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_cnt - 1; 643115516c77SSepherosa Ziehau error = hn_synth_alloc_subchans(sc, &nsubch); 643215516c77SSepherosa Ziehau if (error) 643371e8ac56SSepherosa Ziehau goto failed; 643471e8ac56SSepherosa Ziehau /* NOTE: _Full_ synthetic parts detach is required now. */ 643571e8ac56SSepherosa Ziehau sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED; 643615516c77SSepherosa Ziehau 643771e8ac56SSepherosa Ziehau /* 643871e8ac56SSepherosa Ziehau * Set the # of TX/RX rings that could be used according to 643971e8ac56SSepherosa Ziehau * the # of channels that NVS offered. 644071e8ac56SSepherosa Ziehau */ 644115516c77SSepherosa Ziehau nchan = nsubch + 1; 644271e8ac56SSepherosa Ziehau hn_set_ring_inuse(sc, nchan); 644315516c77SSepherosa Ziehau if (nchan == 1) { 644415516c77SSepherosa Ziehau /* Only the primary channel can be used; done */ 644515516c77SSepherosa Ziehau goto back; 644615516c77SSepherosa Ziehau } 644715516c77SSepherosa Ziehau 644815516c77SSepherosa Ziehau /* 644971e8ac56SSepherosa Ziehau * Attach the sub-channels. 6450afd4971bSSepherosa Ziehau * 6451afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 645215516c77SSepherosa Ziehau */ 645371e8ac56SSepherosa Ziehau error = hn_attach_subchans(sc); 645471e8ac56SSepherosa Ziehau if (error) 645571e8ac56SSepherosa Ziehau goto failed; 645615516c77SSepherosa Ziehau 645771e8ac56SSepherosa Ziehau /* 645871e8ac56SSepherosa Ziehau * Configure RSS key and indirect table _after_ all sub-channels 645971e8ac56SSepherosa Ziehau * are attached. 646071e8ac56SSepherosa Ziehau */ 646115516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) { 646215516c77SSepherosa Ziehau /* 646315516c77SSepherosa Ziehau * RSS key is not set yet; set it to the default RSS key. 646415516c77SSepherosa Ziehau */ 646515516c77SSepherosa Ziehau if (bootverbose) 646615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS key\n"); 646734d68912SSepherosa Ziehau #ifdef RSS 646834d68912SSepherosa Ziehau rss_getkey(rss->rss_key); 646934d68912SSepherosa Ziehau #else 647015516c77SSepherosa Ziehau memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key)); 647134d68912SSepherosa Ziehau #endif 647215516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 647315516c77SSepherosa Ziehau } 647415516c77SSepherosa Ziehau 647515516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) { 647615516c77SSepherosa Ziehau /* 647715516c77SSepherosa Ziehau * RSS indirect table is not set yet; set it up in round- 647815516c77SSepherosa Ziehau * robin fashion. 647915516c77SSepherosa Ziehau */ 648015516c77SSepherosa Ziehau if (bootverbose) { 648115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS indirect " 648215516c77SSepherosa Ziehau "table\n"); 648315516c77SSepherosa Ziehau } 648434d68912SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 648534d68912SSepherosa Ziehau uint32_t subidx; 648634d68912SSepherosa Ziehau 648734d68912SSepherosa Ziehau #ifdef RSS 648834d68912SSepherosa Ziehau subidx = rss_get_indirection_to_bucket(i); 648934d68912SSepherosa Ziehau #else 649034d68912SSepherosa Ziehau subidx = i; 649134d68912SSepherosa Ziehau #endif 649234d68912SSepherosa Ziehau rss->rss_ind[i] = subidx % nchan; 649334d68912SSepherosa Ziehau } 649415516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 649515516c77SSepherosa Ziehau } else { 649615516c77SSepherosa Ziehau /* 649715516c77SSepherosa Ziehau * # of usable channels may be changed, so we have to 649815516c77SSepherosa Ziehau * make sure that all entries in RSS indirect table 649915516c77SSepherosa Ziehau * are valid. 6500afd4971bSSepherosa Ziehau * 6501afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 650215516c77SSepherosa Ziehau */ 6503afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 650415516c77SSepherosa Ziehau } 650515516c77SSepherosa Ziehau 6506642ec226SSepherosa Ziehau sc->hn_rss_hash = sc->hn_rss_hcap; 6507642ec226SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) || 6508642ec226SSepherosa Ziehau (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { 6509642ec226SSepherosa Ziehau /* NOTE: Don't reconfigure RSS; will do immediately. */ 6510642ec226SSepherosa Ziehau hn_vf_rss_fixup(sc, false); 6511642ec226SSepherosa Ziehau } 651215516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 651315516c77SSepherosa Ziehau if (error) 651471e8ac56SSepherosa Ziehau goto failed; 651571e8ac56SSepherosa Ziehau back: 6516dc13fee6SSepherosa Ziehau /* 6517dc13fee6SSepherosa Ziehau * Fixup transmission aggregation setup. 6518dc13fee6SSepherosa Ziehau */ 6519dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 6520b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 652115516c77SSepherosa Ziehau return (0); 652271e8ac56SSepherosa Ziehau 652371e8ac56SSepherosa Ziehau failed: 652471e8ac56SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 6525b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 652671e8ac56SSepherosa Ziehau hn_synth_detach(sc); 652771e8ac56SSepherosa Ziehau } else { 6528b3b75d9cSSepherosa Ziehau if (attached & ATTACHED_RNDIS) { 6529b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 653071e8ac56SSepherosa Ziehau hn_rndis_detach(sc); 6531b3b75d9cSSepherosa Ziehau } 653271e8ac56SSepherosa Ziehau if (attached & ATTACHED_NVS) 653371e8ac56SSepherosa Ziehau hn_nvs_detach(sc); 653471e8ac56SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 653571e8ac56SSepherosa Ziehau /* Restore old capabilities. */ 653671e8ac56SSepherosa Ziehau sc->hn_caps = old_caps; 653771e8ac56SSepherosa Ziehau } 653871e8ac56SSepherosa Ziehau return (error); 653971e8ac56SSepherosa Ziehau 654071e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS 654171e8ac56SSepherosa Ziehau #undef ATTACHED_NVS 654215516c77SSepherosa Ziehau } 654315516c77SSepherosa Ziehau 654415516c77SSepherosa Ziehau /* 654515516c77SSepherosa Ziehau * NOTE: 654615516c77SSepherosa Ziehau * The interface must have been suspended though hn_suspend(), before 654715516c77SSepherosa Ziehau * this function get called. 654815516c77SSepherosa Ziehau */ 654915516c77SSepherosa Ziehau static void 655015516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc) 655115516c77SSepherosa Ziehau { 655215516c77SSepherosa Ziehau 655315516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 655415516c77SSepherosa Ziehau ("synthetic parts were not attached")); 655515516c77SSepherosa Ziehau 655615516c77SSepherosa Ziehau /* Detach the RNDIS first. */ 655715516c77SSepherosa Ziehau hn_rndis_detach(sc); 655815516c77SSepherosa Ziehau 655915516c77SSepherosa Ziehau /* Detach NVS. */ 656015516c77SSepherosa Ziehau hn_nvs_detach(sc); 656115516c77SSepherosa Ziehau 656215516c77SSepherosa Ziehau /* Detach all of the channels. */ 656315516c77SSepherosa Ziehau hn_detach_allchans(sc); 656415516c77SSepherosa Ziehau 656515516c77SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED; 656615516c77SSepherosa Ziehau } 656715516c77SSepherosa Ziehau 656815516c77SSepherosa Ziehau static void 656915516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt) 657015516c77SSepherosa Ziehau { 657115516c77SSepherosa Ziehau KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt, 657215516c77SSepherosa Ziehau ("invalid ring count %d", ring_cnt)); 657315516c77SSepherosa Ziehau 657415516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt > ring_cnt) 657515516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = ring_cnt; 657615516c77SSepherosa Ziehau else 657715516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 657815516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = ring_cnt; 657915516c77SSepherosa Ziehau 658034d68912SSepherosa Ziehau #ifdef RSS 658134d68912SSepherosa Ziehau if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) { 658234d68912SSepherosa Ziehau if_printf(sc->hn_ifp, "# of RX rings (%d) does not match " 658334d68912SSepherosa Ziehau "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse, 658434d68912SSepherosa Ziehau rss_getnumbuckets()); 658534d68912SSepherosa Ziehau } 658634d68912SSepherosa Ziehau #endif 658734d68912SSepherosa Ziehau 658815516c77SSepherosa Ziehau if (bootverbose) { 658915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n", 659015516c77SSepherosa Ziehau sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse); 659115516c77SSepherosa Ziehau } 659215516c77SSepherosa Ziehau } 659315516c77SSepherosa Ziehau 659415516c77SSepherosa Ziehau static void 659525641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan) 659615516c77SSepherosa Ziehau { 659715516c77SSepherosa Ziehau 659825641fc7SSepherosa Ziehau /* 659925641fc7SSepherosa Ziehau * NOTE: 660025641fc7SSepherosa Ziehau * The TX bufring will not be drained by the hypervisor, 660125641fc7SSepherosa Ziehau * if the primary channel is revoked. 660225641fc7SSepherosa Ziehau */ 660325641fc7SSepherosa Ziehau while (!vmbus_chan_rx_empty(chan) || 660425641fc7SSepherosa Ziehau (!vmbus_chan_is_revoked(sc->hn_prichan) && 660525641fc7SSepherosa Ziehau !vmbus_chan_tx_empty(chan))) 660615516c77SSepherosa Ziehau pause("waitch", 1); 660715516c77SSepherosa Ziehau vmbus_chan_intr_drain(chan); 660815516c77SSepherosa Ziehau } 660915516c77SSepherosa Ziehau 661015516c77SSepherosa Ziehau static void 6611b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc) 6612b3b75d9cSSepherosa Ziehau { 6613b3b75d9cSSepherosa Ziehau 6614b3b75d9cSSepherosa Ziehau /* 6615b3b75d9cSSepherosa Ziehau * Disable RX by clearing RX filter forcefully. 6616b3b75d9cSSepherosa Ziehau */ 6617b3b75d9cSSepherosa Ziehau sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE; 6618b3b75d9cSSepherosa Ziehau hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */ 6619b3b75d9cSSepherosa Ziehau 6620b3b75d9cSSepherosa Ziehau /* 6621b3b75d9cSSepherosa Ziehau * Give RNDIS enough time to flush all pending data packets. 6622b3b75d9cSSepherosa Ziehau */ 6623b3b75d9cSSepherosa Ziehau pause("waitrx", (200 * hz) / 1000); 6624b3b75d9cSSepherosa Ziehau } 6625b3b75d9cSSepherosa Ziehau 6626b3b75d9cSSepherosa Ziehau /* 6627b3b75d9cSSepherosa Ziehau * NOTE: 6628b3b75d9cSSepherosa Ziehau * RX/TX _must_ have been suspended/disabled, before this function 6629b3b75d9cSSepherosa Ziehau * is called. 6630b3b75d9cSSepherosa Ziehau */ 6631b3b75d9cSSepherosa Ziehau static void 6632b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan) 663315516c77SSepherosa Ziehau { 663415516c77SSepherosa Ziehau struct vmbus_channel **subch = NULL; 6635b3b75d9cSSepherosa Ziehau int nsubch; 6636b3b75d9cSSepherosa Ziehau 6637b3b75d9cSSepherosa Ziehau /* 6638b3b75d9cSSepherosa Ziehau * Drain RX/TX bufrings and interrupts. 6639b3b75d9cSSepherosa Ziehau */ 6640b3b75d9cSSepherosa Ziehau nsubch = nchan - 1; 6641b3b75d9cSSepherosa Ziehau if (nsubch > 0) 6642b3b75d9cSSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 6643b3b75d9cSSepherosa Ziehau 6644b3b75d9cSSepherosa Ziehau if (subch != NULL) { 6645b3b75d9cSSepherosa Ziehau int i; 6646b3b75d9cSSepherosa Ziehau 6647b3b75d9cSSepherosa Ziehau for (i = 0; i < nsubch; ++i) 6648b3b75d9cSSepherosa Ziehau hn_chan_drain(sc, subch[i]); 6649b3b75d9cSSepherosa Ziehau } 6650b3b75d9cSSepherosa Ziehau hn_chan_drain(sc, sc->hn_prichan); 6651b3b75d9cSSepherosa Ziehau 6652b3b75d9cSSepherosa Ziehau if (subch != NULL) 6653b3b75d9cSSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 6654b3b75d9cSSepherosa Ziehau } 6655b3b75d9cSSepherosa Ziehau 6656b3b75d9cSSepherosa Ziehau static void 6657b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc) 6658b3b75d9cSSepherosa Ziehau { 665925641fc7SSepherosa Ziehau struct hn_tx_ring *txr; 6660b3b75d9cSSepherosa Ziehau int i; 666115516c77SSepherosa Ziehau 666215516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 666315516c77SSepherosa Ziehau 666415516c77SSepherosa Ziehau /* 666515516c77SSepherosa Ziehau * Suspend TX. 666615516c77SSepherosa Ziehau */ 666715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 666825641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 666915516c77SSepherosa Ziehau 667015516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 667115516c77SSepherosa Ziehau txr->hn_suspended = 1; 667215516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 667315516c77SSepherosa Ziehau /* No one is able send more packets now. */ 667415516c77SSepherosa Ziehau 667525641fc7SSepherosa Ziehau /* 667625641fc7SSepherosa Ziehau * Wait for all pending sends to finish. 667725641fc7SSepherosa Ziehau * 667825641fc7SSepherosa Ziehau * NOTE: 667925641fc7SSepherosa Ziehau * We will _not_ receive all pending send-done, if the 668025641fc7SSepherosa Ziehau * primary channel is revoked. 668125641fc7SSepherosa Ziehau */ 668225641fc7SSepherosa Ziehau while (hn_tx_ring_pending(txr) && 668325641fc7SSepherosa Ziehau !vmbus_chan_is_revoked(sc->hn_prichan)) 668415516c77SSepherosa Ziehau pause("hnwtx", 1 /* 1 tick */); 668515516c77SSepherosa Ziehau } 668615516c77SSepherosa Ziehau 668715516c77SSepherosa Ziehau /* 6688b3b75d9cSSepherosa Ziehau * Disable RX. 668915516c77SSepherosa Ziehau */ 6690b3b75d9cSSepherosa Ziehau hn_disable_rx(sc); 669115516c77SSepherosa Ziehau 669215516c77SSepherosa Ziehau /* 6693b3b75d9cSSepherosa Ziehau * Drain RX/TX. 669415516c77SSepherosa Ziehau */ 6695b3b75d9cSSepherosa Ziehau hn_drain_rxtx(sc, sc->hn_rx_ring_inuse); 669625641fc7SSepherosa Ziehau 669725641fc7SSepherosa Ziehau /* 669825641fc7SSepherosa Ziehau * Drain any pending TX tasks. 669925641fc7SSepherosa Ziehau * 670025641fc7SSepherosa Ziehau * NOTE: 6701b3b75d9cSSepherosa Ziehau * The above hn_drain_rxtx() can dispatch TX tasks, so the TX 6702b3b75d9cSSepherosa Ziehau * tasks will have to be drained _after_ the above hn_drain_rxtx(). 670325641fc7SSepherosa Ziehau */ 670425641fc7SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 670525641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 670625641fc7SSepherosa Ziehau 670725641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task); 670825641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task); 670925641fc7SSepherosa Ziehau } 671015516c77SSepherosa Ziehau } 671115516c77SSepherosa Ziehau 671215516c77SSepherosa Ziehau static void 671315516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused) 671415516c77SSepherosa Ziehau { 671515516c77SSepherosa Ziehau 671615516c77SSepherosa Ziehau ((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL; 671715516c77SSepherosa Ziehau } 671815516c77SSepherosa Ziehau 671915516c77SSepherosa Ziehau static void 672015516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc) 672115516c77SSepherosa Ziehau { 672215516c77SSepherosa Ziehau struct task task; 672315516c77SSepherosa Ziehau 672415516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 672515516c77SSepherosa Ziehau 672615516c77SSepherosa Ziehau /* 672715516c77SSepherosa Ziehau * Make sure that hn_mgmt_taskq0 can nolonger be accessed 672815516c77SSepherosa Ziehau * through hn_mgmt_taskq. 672915516c77SSepherosa Ziehau */ 673015516c77SSepherosa Ziehau TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc); 673115516c77SSepherosa Ziehau vmbus_chan_run_task(sc->hn_prichan, &task); 673215516c77SSepherosa Ziehau 673315516c77SSepherosa Ziehau /* 673415516c77SSepherosa Ziehau * Make sure that all pending management tasks are completed. 673515516c77SSepherosa Ziehau */ 673615516c77SSepherosa Ziehau taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init); 673715516c77SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status); 673815516c77SSepherosa Ziehau taskqueue_drain_all(sc->hn_mgmt_taskq0); 673915516c77SSepherosa Ziehau } 674015516c77SSepherosa Ziehau 674115516c77SSepherosa Ziehau static void 674215516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc) 674315516c77SSepherosa Ziehau { 674415516c77SSepherosa Ziehau 674587f8129dSSepherosa Ziehau /* Disable polling. */ 674687f8129dSSepherosa Ziehau hn_polling(sc, 0); 674787f8129dSSepherosa Ziehau 67489c6cae24SSepherosa Ziehau /* 67499c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, the synthetic 67509c6cae24SSepherosa Ziehau * device is receiving packets, so the data path of the 67519c6cae24SSepherosa Ziehau * synthetic device must be suspended. 67529c6cae24SSepherosa Ziehau */ 67535bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 6754962f0357SSepherosa Ziehau (sc->hn_flags & HN_FLAG_RXVF)) 675515516c77SSepherosa Ziehau hn_suspend_data(sc); 675615516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 675715516c77SSepherosa Ziehau } 675815516c77SSepherosa Ziehau 675915516c77SSepherosa Ziehau static void 676015516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt) 676115516c77SSepherosa Ziehau { 676215516c77SSepherosa Ziehau int i; 676315516c77SSepherosa Ziehau 676415516c77SSepherosa Ziehau KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt, 676515516c77SSepherosa Ziehau ("invalid TX ring count %d", tx_ring_cnt)); 676615516c77SSepherosa Ziehau 676715516c77SSepherosa Ziehau for (i = 0; i < tx_ring_cnt; ++i) { 676815516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 676915516c77SSepherosa Ziehau 677015516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 677115516c77SSepherosa Ziehau txr->hn_suspended = 0; 677215516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 677315516c77SSepherosa Ziehau } 677415516c77SSepherosa Ziehau } 677515516c77SSepherosa Ziehau 677615516c77SSepherosa Ziehau static void 677715516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc) 677815516c77SSepherosa Ziehau { 677915516c77SSepherosa Ziehau int i; 678015516c77SSepherosa Ziehau 678115516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 678215516c77SSepherosa Ziehau 678315516c77SSepherosa Ziehau /* 678415516c77SSepherosa Ziehau * Re-enable RX. 678515516c77SSepherosa Ziehau */ 6786c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 678715516c77SSepherosa Ziehau 678815516c77SSepherosa Ziehau /* 678915516c77SSepherosa Ziehau * Make sure to clear suspend status on "all" TX rings, 679015516c77SSepherosa Ziehau * since hn_tx_ring_inuse can be changed after 679115516c77SSepherosa Ziehau * hn_suspend_data(). 679215516c77SSepherosa Ziehau */ 679315516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_cnt); 679415516c77SSepherosa Ziehau 679523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 679623bf9e15SSepherosa Ziehau if (!hn_use_if_start) 679723bf9e15SSepherosa Ziehau #endif 679823bf9e15SSepherosa Ziehau { 679915516c77SSepherosa Ziehau /* 680015516c77SSepherosa Ziehau * Flush unused drbrs, since hn_tx_ring_inuse may be 680115516c77SSepherosa Ziehau * reduced. 680215516c77SSepherosa Ziehau */ 680315516c77SSepherosa Ziehau for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i) 680415516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 680515516c77SSepherosa Ziehau } 680615516c77SSepherosa Ziehau 680715516c77SSepherosa Ziehau /* 680815516c77SSepherosa Ziehau * Kick start TX. 680915516c77SSepherosa Ziehau */ 681015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 681115516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 681215516c77SSepherosa Ziehau 681315516c77SSepherosa Ziehau /* 681415516c77SSepherosa Ziehau * Use txeof task, so that any pending oactive can be 681515516c77SSepherosa Ziehau * cleared properly. 681615516c77SSepherosa Ziehau */ 681715516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 681815516c77SSepherosa Ziehau } 681915516c77SSepherosa Ziehau } 682015516c77SSepherosa Ziehau 682115516c77SSepherosa Ziehau static void 682215516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc) 682315516c77SSepherosa Ziehau { 682415516c77SSepherosa Ziehau 682515516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 682615516c77SSepherosa Ziehau 682715516c77SSepherosa Ziehau /* 682815516c77SSepherosa Ziehau * Kick off network change detection, if it was pending. 682915516c77SSepherosa Ziehau * If no network change was pending, start link status 683015516c77SSepherosa Ziehau * checks, which is more lightweight than network change 683115516c77SSepherosa Ziehau * detection. 683215516c77SSepherosa Ziehau */ 683315516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 683415516c77SSepherosa Ziehau hn_change_network(sc); 683515516c77SSepherosa Ziehau else 683615516c77SSepherosa Ziehau hn_update_link_status(sc); 683715516c77SSepherosa Ziehau } 683815516c77SSepherosa Ziehau 683915516c77SSepherosa Ziehau static void 684015516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc) 684115516c77SSepherosa Ziehau { 684215516c77SSepherosa Ziehau 68439c6cae24SSepherosa Ziehau /* 68449c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, the synthetic 68459c6cae24SSepherosa Ziehau * device have to receive packets, so the data path of the 68469c6cae24SSepherosa Ziehau * synthetic device must be resumed. 68479c6cae24SSepherosa Ziehau */ 68485bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 6849962f0357SSepherosa Ziehau (sc->hn_flags & HN_FLAG_RXVF)) 685015516c77SSepherosa Ziehau hn_resume_data(sc); 68515bdfd3fdSDexuan Cui 68525bdfd3fdSDexuan Cui /* 68539c6cae24SSepherosa Ziehau * Don't resume link status change if VF is attached/activated. 68549c6cae24SSepherosa Ziehau * - In the non-transparent VF mode, the synthetic device marks 68559c6cae24SSepherosa Ziehau * link down until the VF is deactivated; i.e. VF is down. 68569c6cae24SSepherosa Ziehau * - In transparent VF mode, VF's media status is used until 68579c6cae24SSepherosa Ziehau * the VF is detached. 68585bdfd3fdSDexuan Cui */ 68599c6cae24SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) == 0 && 68609c6cae24SSepherosa Ziehau !(hn_xpnt_vf && sc->hn_vf_ifp != NULL)) 686115516c77SSepherosa Ziehau hn_resume_mgmt(sc); 686287f8129dSSepherosa Ziehau 686387f8129dSSepherosa Ziehau /* 686487f8129dSSepherosa Ziehau * Re-enable polling if this interface is running and 686587f8129dSSepherosa Ziehau * the polling is requested. 686687f8129dSSepherosa Ziehau */ 686787f8129dSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0) 686887f8129dSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 686915516c77SSepherosa Ziehau } 687015516c77SSepherosa Ziehau 687115516c77SSepherosa Ziehau static void 687215516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen) 687315516c77SSepherosa Ziehau { 687415516c77SSepherosa Ziehau const struct rndis_status_msg *msg; 687515516c77SSepherosa Ziehau int ofs; 687615516c77SSepherosa Ziehau 687715516c77SSepherosa Ziehau if (dlen < sizeof(*msg)) { 687815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid RNDIS status\n"); 687915516c77SSepherosa Ziehau return; 688015516c77SSepherosa Ziehau } 688115516c77SSepherosa Ziehau msg = data; 688215516c77SSepherosa Ziehau 688315516c77SSepherosa Ziehau switch (msg->rm_status) { 688415516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_CONNECT: 688515516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_DISCONNECT: 688615516c77SSepherosa Ziehau hn_update_link_status(sc); 688715516c77SSepherosa Ziehau break; 688815516c77SSepherosa Ziehau 688915516c77SSepherosa Ziehau case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: 689040905afaSSepherosa Ziehau case RNDIS_STATUS_LINK_SPEED_CHANGE: 689115516c77SSepherosa Ziehau /* Not really useful; ignore. */ 689215516c77SSepherosa Ziehau break; 689315516c77SSepherosa Ziehau 689415516c77SSepherosa Ziehau case RNDIS_STATUS_NETWORK_CHANGE: 689515516c77SSepherosa Ziehau ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset); 689615516c77SSepherosa Ziehau if (dlen < ofs + msg->rm_stbuflen || 689715516c77SSepherosa Ziehau msg->rm_stbuflen < sizeof(uint32_t)) { 689815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed\n"); 689915516c77SSepherosa Ziehau } else { 690015516c77SSepherosa Ziehau uint32_t change; 690115516c77SSepherosa Ziehau 690215516c77SSepherosa Ziehau memcpy(&change, ((const uint8_t *)msg) + ofs, 690315516c77SSepherosa Ziehau sizeof(change)); 690415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed, change %u\n", 690515516c77SSepherosa Ziehau change); 690615516c77SSepherosa Ziehau } 690715516c77SSepherosa Ziehau hn_change_network(sc); 690815516c77SSepherosa Ziehau break; 690915516c77SSepherosa Ziehau 691015516c77SSepherosa Ziehau default: 691115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n", 691215516c77SSepherosa Ziehau msg->rm_status); 691315516c77SSepherosa Ziehau break; 691415516c77SSepherosa Ziehau } 691515516c77SSepherosa Ziehau } 691615516c77SSepherosa Ziehau 691715516c77SSepherosa Ziehau static int 691815516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info) 691915516c77SSepherosa Ziehau { 692015516c77SSepherosa Ziehau const struct rndis_pktinfo *pi = info_data; 692115516c77SSepherosa Ziehau uint32_t mask = 0; 692215516c77SSepherosa Ziehau 692315516c77SSepherosa Ziehau while (info_dlen != 0) { 692415516c77SSepherosa Ziehau const void *data; 692515516c77SSepherosa Ziehau uint32_t dlen; 692615516c77SSepherosa Ziehau 692715516c77SSepherosa Ziehau if (__predict_false(info_dlen < sizeof(*pi))) 692815516c77SSepherosa Ziehau return (EINVAL); 692915516c77SSepherosa Ziehau if (__predict_false(info_dlen < pi->rm_size)) 693015516c77SSepherosa Ziehau return (EINVAL); 693115516c77SSepherosa Ziehau info_dlen -= pi->rm_size; 693215516c77SSepherosa Ziehau 693315516c77SSepherosa Ziehau if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK)) 693415516c77SSepherosa Ziehau return (EINVAL); 693515516c77SSepherosa Ziehau if (__predict_false(pi->rm_size < pi->rm_pktinfooffset)) 693615516c77SSepherosa Ziehau return (EINVAL); 693715516c77SSepherosa Ziehau dlen = pi->rm_size - pi->rm_pktinfooffset; 693815516c77SSepherosa Ziehau data = pi->rm_data; 693915516c77SSepherosa Ziehau 694015516c77SSepherosa Ziehau switch (pi->rm_type) { 694115516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_VLAN: 694215516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE)) 694315516c77SSepherosa Ziehau return (EINVAL); 694415516c77SSepherosa Ziehau info->vlan_info = *((const uint32_t *)data); 694515516c77SSepherosa Ziehau mask |= HN_RXINFO_VLAN; 694615516c77SSepherosa Ziehau break; 694715516c77SSepherosa Ziehau 694815516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_CSUM: 694915516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE)) 695015516c77SSepherosa Ziehau return (EINVAL); 695115516c77SSepherosa Ziehau info->csum_info = *((const uint32_t *)data); 695215516c77SSepherosa Ziehau mask |= HN_RXINFO_CSUM; 695315516c77SSepherosa Ziehau break; 695415516c77SSepherosa Ziehau 695515516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHVAL: 695615516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE)) 695715516c77SSepherosa Ziehau return (EINVAL); 695815516c77SSepherosa Ziehau info->hash_value = *((const uint32_t *)data); 695915516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHVAL; 696015516c77SSepherosa Ziehau break; 696115516c77SSepherosa Ziehau 696215516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHINF: 696315516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE)) 696415516c77SSepherosa Ziehau return (EINVAL); 696515516c77SSepherosa Ziehau info->hash_info = *((const uint32_t *)data); 696615516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHINF; 696715516c77SSepherosa Ziehau break; 696815516c77SSepherosa Ziehau 696915516c77SSepherosa Ziehau default: 697015516c77SSepherosa Ziehau goto next; 697115516c77SSepherosa Ziehau } 697215516c77SSepherosa Ziehau 697315516c77SSepherosa Ziehau if (mask == HN_RXINFO_ALL) { 697415516c77SSepherosa Ziehau /* All found; done */ 697515516c77SSepherosa Ziehau break; 697615516c77SSepherosa Ziehau } 697715516c77SSepherosa Ziehau next: 697815516c77SSepherosa Ziehau pi = (const struct rndis_pktinfo *) 697915516c77SSepherosa Ziehau ((const uint8_t *)pi + pi->rm_size); 698015516c77SSepherosa Ziehau } 698115516c77SSepherosa Ziehau 698215516c77SSepherosa Ziehau /* 698315516c77SSepherosa Ziehau * Final fixup. 698415516c77SSepherosa Ziehau * - If there is no hash value, invalidate the hash info. 698515516c77SSepherosa Ziehau */ 698615516c77SSepherosa Ziehau if ((mask & HN_RXINFO_HASHVAL) == 0) 698715516c77SSepherosa Ziehau info->hash_info = HN_NDIS_HASH_INFO_INVALID; 698815516c77SSepherosa Ziehau return (0); 698915516c77SSepherosa Ziehau } 699015516c77SSepherosa Ziehau 699115516c77SSepherosa Ziehau static __inline bool 699215516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len) 699315516c77SSepherosa Ziehau { 699415516c77SSepherosa Ziehau 699515516c77SSepherosa Ziehau if (off < check_off) { 699615516c77SSepherosa Ziehau if (__predict_true(off + len <= check_off)) 699715516c77SSepherosa Ziehau return (false); 699815516c77SSepherosa Ziehau } else if (off > check_off) { 699915516c77SSepherosa Ziehau if (__predict_true(check_off + check_len <= off)) 700015516c77SSepherosa Ziehau return (false); 700115516c77SSepherosa Ziehau } 700215516c77SSepherosa Ziehau return (true); 700315516c77SSepherosa Ziehau } 700415516c77SSepherosa Ziehau 700515516c77SSepherosa Ziehau static void 700615516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen) 700715516c77SSepherosa Ziehau { 700815516c77SSepherosa Ziehau const struct rndis_packet_msg *pkt; 700915516c77SSepherosa Ziehau struct hn_rxinfo info; 701015516c77SSepherosa Ziehau int data_off, pktinfo_off, data_len, pktinfo_len; 701115516c77SSepherosa Ziehau 701215516c77SSepherosa Ziehau /* 701315516c77SSepherosa Ziehau * Check length. 701415516c77SSepherosa Ziehau */ 701515516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*pkt))) { 701615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n"); 701715516c77SSepherosa Ziehau return; 701815516c77SSepherosa Ziehau } 701915516c77SSepherosa Ziehau pkt = data; 702015516c77SSepherosa Ziehau 702115516c77SSepherosa Ziehau if (__predict_false(dlen < pkt->rm_len)) { 702215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, " 702315516c77SSepherosa Ziehau "dlen %d, msglen %u\n", dlen, pkt->rm_len); 702415516c77SSepherosa Ziehau return; 702515516c77SSepherosa Ziehau } 702615516c77SSepherosa Ziehau if (__predict_false(pkt->rm_len < 702715516c77SSepherosa Ziehau pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) { 702815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, " 702915516c77SSepherosa Ziehau "msglen %u, data %u, oob %u, pktinfo %u\n", 703015516c77SSepherosa Ziehau pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen, 703115516c77SSepherosa Ziehau pkt->rm_pktinfolen); 703215516c77SSepherosa Ziehau return; 703315516c77SSepherosa Ziehau } 703415516c77SSepherosa Ziehau if (__predict_false(pkt->rm_datalen == 0)) { 703515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n"); 703615516c77SSepherosa Ziehau return; 703715516c77SSepherosa Ziehau } 703815516c77SSepherosa Ziehau 703915516c77SSepherosa Ziehau /* 704015516c77SSepherosa Ziehau * Check offests. 704115516c77SSepherosa Ziehau */ 704215516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs) \ 704315516c77SSepherosa Ziehau ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \ 704415516c77SSepherosa Ziehau ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK)) 704515516c77SSepherosa Ziehau 704615516c77SSepherosa Ziehau /* XXX Hyper-V does not meet data offset alignment requirement */ 704715516c77SSepherosa Ziehau if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) { 704815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 704915516c77SSepherosa Ziehau "data offset %u\n", pkt->rm_dataoffset); 705015516c77SSepherosa Ziehau return; 705115516c77SSepherosa Ziehau } 705215516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdataoffset > 0 && 705315516c77SSepherosa Ziehau IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) { 705415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 705515516c77SSepherosa Ziehau "oob offset %u\n", pkt->rm_oobdataoffset); 705615516c77SSepherosa Ziehau return; 705715516c77SSepherosa Ziehau } 705815516c77SSepherosa Ziehau if (__predict_true(pkt->rm_pktinfooffset > 0) && 705915516c77SSepherosa Ziehau __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) { 706015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 706115516c77SSepherosa Ziehau "pktinfo offset %u\n", pkt->rm_pktinfooffset); 706215516c77SSepherosa Ziehau return; 706315516c77SSepherosa Ziehau } 706415516c77SSepherosa Ziehau 706515516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID 706615516c77SSepherosa Ziehau 706715516c77SSepherosa Ziehau data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset); 706815516c77SSepherosa Ziehau data_len = pkt->rm_datalen; 706915516c77SSepherosa Ziehau pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset); 707015516c77SSepherosa Ziehau pktinfo_len = pkt->rm_pktinfolen; 707115516c77SSepherosa Ziehau 707215516c77SSepherosa Ziehau /* 707315516c77SSepherosa Ziehau * Check OOB coverage. 707415516c77SSepherosa Ziehau */ 707515516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdatalen != 0)) { 707615516c77SSepherosa Ziehau int oob_off, oob_len; 707715516c77SSepherosa Ziehau 707815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "got oobdata\n"); 707915516c77SSepherosa Ziehau oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset); 708015516c77SSepherosa Ziehau oob_len = pkt->rm_oobdatalen; 708115516c77SSepherosa Ziehau 708215516c77SSepherosa Ziehau if (__predict_false(oob_off + oob_len > pkt->rm_len)) { 708315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 708415516c77SSepherosa Ziehau "oob overflow, msglen %u, oob abs %d len %d\n", 708515516c77SSepherosa Ziehau pkt->rm_len, oob_off, oob_len); 708615516c77SSepherosa Ziehau return; 708715516c77SSepherosa Ziehau } 708815516c77SSepherosa Ziehau 708915516c77SSepherosa Ziehau /* 709015516c77SSepherosa Ziehau * Check against data. 709115516c77SSepherosa Ziehau */ 709215516c77SSepherosa Ziehau if (hn_rndis_check_overlap(oob_off, oob_len, 709315516c77SSepherosa Ziehau data_off, data_len)) { 709415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 709515516c77SSepherosa Ziehau "oob overlaps data, oob abs %d len %d, " 709615516c77SSepherosa Ziehau "data abs %d len %d\n", 709715516c77SSepherosa Ziehau oob_off, oob_len, data_off, data_len); 709815516c77SSepherosa Ziehau return; 709915516c77SSepherosa Ziehau } 710015516c77SSepherosa Ziehau 710115516c77SSepherosa Ziehau /* 710215516c77SSepherosa Ziehau * Check against pktinfo. 710315516c77SSepherosa Ziehau */ 710415516c77SSepherosa Ziehau if (pktinfo_len != 0 && 710515516c77SSepherosa Ziehau hn_rndis_check_overlap(oob_off, oob_len, 710615516c77SSepherosa Ziehau pktinfo_off, pktinfo_len)) { 710715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 710815516c77SSepherosa Ziehau "oob overlaps pktinfo, oob abs %d len %d, " 710915516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 711015516c77SSepherosa Ziehau oob_off, oob_len, pktinfo_off, pktinfo_len); 711115516c77SSepherosa Ziehau return; 711215516c77SSepherosa Ziehau } 711315516c77SSepherosa Ziehau } 711415516c77SSepherosa Ziehau 711515516c77SSepherosa Ziehau /* 711615516c77SSepherosa Ziehau * Check per-packet-info coverage and find useful per-packet-info. 711715516c77SSepherosa Ziehau */ 711815516c77SSepherosa Ziehau info.vlan_info = HN_NDIS_VLAN_INFO_INVALID; 711915516c77SSepherosa Ziehau info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID; 712015516c77SSepherosa Ziehau info.hash_info = HN_NDIS_HASH_INFO_INVALID; 712115516c77SSepherosa Ziehau if (__predict_true(pktinfo_len != 0)) { 712215516c77SSepherosa Ziehau bool overlap; 712315516c77SSepherosa Ziehau int error; 712415516c77SSepherosa Ziehau 712515516c77SSepherosa Ziehau if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) { 712615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 712715516c77SSepherosa Ziehau "pktinfo overflow, msglen %u, " 712815516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 712915516c77SSepherosa Ziehau pkt->rm_len, pktinfo_off, pktinfo_len); 713015516c77SSepherosa Ziehau return; 713115516c77SSepherosa Ziehau } 713215516c77SSepherosa Ziehau 713315516c77SSepherosa Ziehau /* 713415516c77SSepherosa Ziehau * Check packet info coverage. 713515516c77SSepherosa Ziehau */ 713615516c77SSepherosa Ziehau overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len, 713715516c77SSepherosa Ziehau data_off, data_len); 713815516c77SSepherosa Ziehau if (__predict_false(overlap)) { 713915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 714015516c77SSepherosa Ziehau "pktinfo overlap data, pktinfo abs %d len %d, " 714115516c77SSepherosa Ziehau "data abs %d len %d\n", 714215516c77SSepherosa Ziehau pktinfo_off, pktinfo_len, data_off, data_len); 714315516c77SSepherosa Ziehau return; 714415516c77SSepherosa Ziehau } 714515516c77SSepherosa Ziehau 714615516c77SSepherosa Ziehau /* 714715516c77SSepherosa Ziehau * Find useful per-packet-info. 714815516c77SSepherosa Ziehau */ 714915516c77SSepherosa Ziehau error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off, 715015516c77SSepherosa Ziehau pktinfo_len, &info); 715115516c77SSepherosa Ziehau if (__predict_false(error)) { 715215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg " 715315516c77SSepherosa Ziehau "pktinfo\n"); 715415516c77SSepherosa Ziehau return; 715515516c77SSepherosa Ziehau } 715615516c77SSepherosa Ziehau } 715715516c77SSepherosa Ziehau 715815516c77SSepherosa Ziehau if (__predict_false(data_off + data_len > pkt->rm_len)) { 715915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 716015516c77SSepherosa Ziehau "data overflow, msglen %u, data abs %d len %d\n", 716115516c77SSepherosa Ziehau pkt->rm_len, data_off, data_len); 716215516c77SSepherosa Ziehau return; 716315516c77SSepherosa Ziehau } 716415516c77SSepherosa Ziehau hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info); 716515516c77SSepherosa Ziehau } 716615516c77SSepherosa Ziehau 716715516c77SSepherosa Ziehau static __inline void 716815516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen) 716915516c77SSepherosa Ziehau { 717015516c77SSepherosa Ziehau const struct rndis_msghdr *hdr; 717115516c77SSepherosa Ziehau 717215516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*hdr))) { 717315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS msg\n"); 717415516c77SSepherosa Ziehau return; 717515516c77SSepherosa Ziehau } 717615516c77SSepherosa Ziehau hdr = data; 717715516c77SSepherosa Ziehau 717815516c77SSepherosa Ziehau if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) { 717915516c77SSepherosa Ziehau /* Hot data path. */ 718015516c77SSepherosa Ziehau hn_rndis_rx_data(rxr, data, dlen); 718115516c77SSepherosa Ziehau /* Done! */ 718215516c77SSepherosa Ziehau return; 718315516c77SSepherosa Ziehau } 718415516c77SSepherosa Ziehau 718515516c77SSepherosa Ziehau if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG) 718615516c77SSepherosa Ziehau hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen); 718715516c77SSepherosa Ziehau else 718815516c77SSepherosa Ziehau hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen); 718915516c77SSepherosa Ziehau } 719015516c77SSepherosa Ziehau 719115516c77SSepherosa Ziehau static void 719215516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) 719315516c77SSepherosa Ziehau { 719415516c77SSepherosa Ziehau const struct hn_nvs_hdr *hdr; 719515516c77SSepherosa Ziehau 719615516c77SSepherosa Ziehau if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) { 719715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid nvs notify\n"); 719815516c77SSepherosa Ziehau return; 719915516c77SSepherosa Ziehau } 720015516c77SSepherosa Ziehau hdr = VMBUS_CHANPKT_CONST_DATA(pkt); 720115516c77SSepherosa Ziehau 720215516c77SSepherosa Ziehau if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) { 720315516c77SSepherosa Ziehau /* Useless; ignore */ 720415516c77SSepherosa Ziehau return; 720515516c77SSepherosa Ziehau } 720615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type); 720715516c77SSepherosa Ziehau } 720815516c77SSepherosa Ziehau 720915516c77SSepherosa Ziehau static void 721015516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan, 721115516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkt) 721215516c77SSepherosa Ziehau { 721315516c77SSepherosa Ziehau struct hn_nvs_sendctx *sndc; 721415516c77SSepherosa Ziehau 721515516c77SSepherosa Ziehau sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid; 721615516c77SSepherosa Ziehau sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt), 721715516c77SSepherosa Ziehau VMBUS_CHANPKT_DATALEN(pkt)); 721815516c77SSepherosa Ziehau /* 721915516c77SSepherosa Ziehau * NOTE: 722015516c77SSepherosa Ziehau * 'sndc' CAN NOT be accessed anymore, since it can be freed by 722115516c77SSepherosa Ziehau * its callback. 722215516c77SSepherosa Ziehau */ 722315516c77SSepherosa Ziehau } 722415516c77SSepherosa Ziehau 722515516c77SSepherosa Ziehau static void 722615516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 722715516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkthdr) 722815516c77SSepherosa Ziehau { 722915516c77SSepherosa Ziehau const struct vmbus_chanpkt_rxbuf *pkt; 723015516c77SSepherosa Ziehau const struct hn_nvs_hdr *nvs_hdr; 723115516c77SSepherosa Ziehau int count, i, hlen; 723215516c77SSepherosa Ziehau 723315516c77SSepherosa Ziehau if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) { 723415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n"); 723515516c77SSepherosa Ziehau return; 723615516c77SSepherosa Ziehau } 723715516c77SSepherosa Ziehau nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr); 723815516c77SSepherosa Ziehau 723915516c77SSepherosa Ziehau /* Make sure that this is a RNDIS message. */ 724015516c77SSepherosa Ziehau if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) { 724115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n", 724215516c77SSepherosa Ziehau nvs_hdr->nvs_type); 724315516c77SSepherosa Ziehau return; 724415516c77SSepherosa Ziehau } 724515516c77SSepherosa Ziehau 724615516c77SSepherosa Ziehau hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen); 724715516c77SSepherosa Ziehau if (__predict_false(hlen < sizeof(*pkt))) { 724815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n"); 724915516c77SSepherosa Ziehau return; 725015516c77SSepherosa Ziehau } 725115516c77SSepherosa Ziehau pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr; 725215516c77SSepherosa Ziehau 725315516c77SSepherosa Ziehau if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) { 725415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n", 725515516c77SSepherosa Ziehau pkt->cp_rxbuf_id); 725615516c77SSepherosa Ziehau return; 725715516c77SSepherosa Ziehau } 725815516c77SSepherosa Ziehau 725915516c77SSepherosa Ziehau count = pkt->cp_rxbuf_cnt; 726015516c77SSepherosa Ziehau if (__predict_false(hlen < 726115516c77SSepherosa Ziehau __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) { 726215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count); 726315516c77SSepherosa Ziehau return; 726415516c77SSepherosa Ziehau } 726515516c77SSepherosa Ziehau 726615516c77SSepherosa Ziehau /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 726715516c77SSepherosa Ziehau for (i = 0; i < count; ++i) { 726815516c77SSepherosa Ziehau int ofs, len; 726915516c77SSepherosa Ziehau 727015516c77SSepherosa Ziehau ofs = pkt->cp_rxbuf[i].rb_ofs; 727115516c77SSepherosa Ziehau len = pkt->cp_rxbuf[i].rb_len; 727215516c77SSepherosa Ziehau if (__predict_false(ofs + len > HN_RXBUF_SIZE)) { 727315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, " 727415516c77SSepherosa Ziehau "ofs %d, len %d\n", i, ofs, len); 727515516c77SSepherosa Ziehau continue; 727615516c77SSepherosa Ziehau } 727715516c77SSepherosa Ziehau hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len); 727815516c77SSepherosa Ziehau } 727915516c77SSepherosa Ziehau 728015516c77SSepherosa Ziehau /* 728115516c77SSepherosa Ziehau * Ack the consumed RXBUF associated w/ this channel packet, 728215516c77SSepherosa Ziehau * so that this RXBUF can be recycled by the hypervisor. 728315516c77SSepherosa Ziehau */ 728415516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid); 728515516c77SSepherosa Ziehau } 728615516c77SSepherosa Ziehau 728715516c77SSepherosa Ziehau static void 728815516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 728915516c77SSepherosa Ziehau uint64_t tid) 729015516c77SSepherosa Ziehau { 729115516c77SSepherosa Ziehau struct hn_nvs_rndis_ack ack; 729215516c77SSepherosa Ziehau int retries, error; 729315516c77SSepherosa Ziehau 729415516c77SSepherosa Ziehau ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK; 729515516c77SSepherosa Ziehau ack.nvs_status = HN_NVS_STATUS_OK; 729615516c77SSepherosa Ziehau 729715516c77SSepherosa Ziehau retries = 0; 729815516c77SSepherosa Ziehau again: 729915516c77SSepherosa Ziehau error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 730015516c77SSepherosa Ziehau VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid); 730115516c77SSepherosa Ziehau if (__predict_false(error == EAGAIN)) { 730215516c77SSepherosa Ziehau /* 730315516c77SSepherosa Ziehau * NOTE: 730415516c77SSepherosa Ziehau * This should _not_ happen in real world, since the 730515516c77SSepherosa Ziehau * consumption of the TX bufring from the TX path is 730615516c77SSepherosa Ziehau * controlled. 730715516c77SSepherosa Ziehau */ 730815516c77SSepherosa Ziehau if (rxr->hn_ack_failed == 0) 730915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack retry\n"); 731015516c77SSepherosa Ziehau rxr->hn_ack_failed++; 731115516c77SSepherosa Ziehau retries++; 731215516c77SSepherosa Ziehau if (retries < 10) { 731315516c77SSepherosa Ziehau DELAY(100); 731415516c77SSepherosa Ziehau goto again; 731515516c77SSepherosa Ziehau } 731615516c77SSepherosa Ziehau /* RXBUF leaks! */ 731715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack failed\n"); 731815516c77SSepherosa Ziehau } 731915516c77SSepherosa Ziehau } 732015516c77SSepherosa Ziehau 732115516c77SSepherosa Ziehau static void 732215516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr) 732315516c77SSepherosa Ziehau { 732415516c77SSepherosa Ziehau struct hn_rx_ring *rxr = xrxr; 732515516c77SSepherosa Ziehau struct hn_softc *sc = rxr->hn_ifp->if_softc; 732615516c77SSepherosa Ziehau 732715516c77SSepherosa Ziehau for (;;) { 732815516c77SSepherosa Ziehau struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf; 732915516c77SSepherosa Ziehau int error, pktlen; 733015516c77SSepherosa Ziehau 733115516c77SSepherosa Ziehau pktlen = rxr->hn_pktbuf_len; 733215516c77SSepherosa Ziehau error = vmbus_chan_recv_pkt(chan, pkt, &pktlen); 733315516c77SSepherosa Ziehau if (__predict_false(error == ENOBUFS)) { 733415516c77SSepherosa Ziehau void *nbuf; 733515516c77SSepherosa Ziehau int nlen; 733615516c77SSepherosa Ziehau 733715516c77SSepherosa Ziehau /* 733815516c77SSepherosa Ziehau * Expand channel packet buffer. 733915516c77SSepherosa Ziehau * 734015516c77SSepherosa Ziehau * XXX 734115516c77SSepherosa Ziehau * Use M_WAITOK here, since allocation failure 734215516c77SSepherosa Ziehau * is fatal. 734315516c77SSepherosa Ziehau */ 734415516c77SSepherosa Ziehau nlen = rxr->hn_pktbuf_len * 2; 734515516c77SSepherosa Ziehau while (nlen < pktlen) 734615516c77SSepherosa Ziehau nlen *= 2; 734715516c77SSepherosa Ziehau nbuf = malloc(nlen, M_DEVBUF, M_WAITOK); 734815516c77SSepherosa Ziehau 734915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n", 735015516c77SSepherosa Ziehau rxr->hn_pktbuf_len, nlen); 735115516c77SSepherosa Ziehau 735215516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 735315516c77SSepherosa Ziehau rxr->hn_pktbuf = nbuf; 735415516c77SSepherosa Ziehau rxr->hn_pktbuf_len = nlen; 735515516c77SSepherosa Ziehau /* Retry! */ 735615516c77SSepherosa Ziehau continue; 735715516c77SSepherosa Ziehau } else if (__predict_false(error == EAGAIN)) { 735815516c77SSepherosa Ziehau /* No more channel packets; done! */ 735915516c77SSepherosa Ziehau break; 736015516c77SSepherosa Ziehau } 736115516c77SSepherosa Ziehau KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error)); 736215516c77SSepherosa Ziehau 736315516c77SSepherosa Ziehau switch (pkt->cph_type) { 736415516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_COMP: 736515516c77SSepherosa Ziehau hn_nvs_handle_comp(sc, chan, pkt); 736615516c77SSepherosa Ziehau break; 736715516c77SSepherosa Ziehau 736815516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_RXBUF: 736915516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(rxr, chan, pkt); 737015516c77SSepherosa Ziehau break; 737115516c77SSepherosa Ziehau 737215516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_INBAND: 737315516c77SSepherosa Ziehau hn_nvs_handle_notify(sc, pkt); 737415516c77SSepherosa Ziehau break; 737515516c77SSepherosa Ziehau 737615516c77SSepherosa Ziehau default: 737715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "unknown chan pkt %u\n", 737815516c77SSepherosa Ziehau pkt->cph_type); 737915516c77SSepherosa Ziehau break; 738015516c77SSepherosa Ziehau } 738115516c77SSepherosa Ziehau } 738215516c77SSepherosa Ziehau hn_chan_rollup(rxr, rxr->hn_txr); 738315516c77SSepherosa Ziehau } 738415516c77SSepherosa Ziehau 738515516c77SSepherosa Ziehau static void 7386499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused) 738715516c77SSepherosa Ziehau { 7388fdd0222aSSepherosa Ziehau int i; 7389fdd0222aSSepherosa Ziehau 73902be266caSSepherosa Ziehau hn_udpcs_fixup = counter_u64_alloc(M_WAITOK); 73912be266caSSepherosa Ziehau 73929c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 73939c6cae24SSepherosa Ziehau /* 73949c6cae24SSepherosa Ziehau * Don't use ifnet.if_start if transparent VF mode is requested; 73959c6cae24SSepherosa Ziehau * mainly due to the IFF_DRV_OACTIVE flag. 73969c6cae24SSepherosa Ziehau */ 73979c6cae24SSepherosa Ziehau if (hn_xpnt_vf && hn_use_if_start) { 73989c6cae24SSepherosa Ziehau hn_use_if_start = 0; 73999c6cae24SSepherosa Ziehau printf("hn: tranparent VF mode, if_transmit will be used, " 74009c6cae24SSepherosa Ziehau "instead of if_start\n"); 74019c6cae24SSepherosa Ziehau } 74029c6cae24SSepherosa Ziehau #endif 74039c6cae24SSepherosa Ziehau if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) { 74049c6cae24SSepherosa Ziehau printf("hn: invalid transparent VF attach routing " 74059c6cae24SSepherosa Ziehau "wait timeout %d, reset to %d\n", 74069c6cae24SSepherosa Ziehau hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN); 74079c6cae24SSepherosa Ziehau hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN; 74089c6cae24SSepherosa Ziehau } 74099c6cae24SSepherosa Ziehau 7410fdd0222aSSepherosa Ziehau /* 7411499c3e17SSepherosa Ziehau * Initialize VF map. 7412499c3e17SSepherosa Ziehau */ 7413499c3e17SSepherosa Ziehau rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE); 7414499c3e17SSepherosa Ziehau hn_vfmap_size = HN_VFMAP_SIZE_DEF; 7415499c3e17SSepherosa Ziehau hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF, 7416499c3e17SSepherosa Ziehau M_WAITOK | M_ZERO); 7417499c3e17SSepherosa Ziehau 7418499c3e17SSepherosa Ziehau /* 7419fdd0222aSSepherosa Ziehau * Fix the # of TX taskqueues. 7420fdd0222aSSepherosa Ziehau */ 7421fdd0222aSSepherosa Ziehau if (hn_tx_taskq_cnt <= 0) 7422fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = 1; 7423fdd0222aSSepherosa Ziehau else if (hn_tx_taskq_cnt > mp_ncpus) 7424fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = mp_ncpus; 742515516c77SSepherosa Ziehau 74260e11868dSSepherosa Ziehau /* 74270e11868dSSepherosa Ziehau * Fix the TX taskqueue mode. 74280e11868dSSepherosa Ziehau */ 74290e11868dSSepherosa Ziehau switch (hn_tx_taskq_mode) { 74300e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_INDEP: 74310e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_GLOBAL: 74320e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_EVTTQ: 74330e11868dSSepherosa Ziehau break; 74340e11868dSSepherosa Ziehau default: 74350e11868dSSepherosa Ziehau hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP; 74360e11868dSSepherosa Ziehau break; 74370e11868dSSepherosa Ziehau } 74380e11868dSSepherosa Ziehau 743915516c77SSepherosa Ziehau if (vm_guest != VM_GUEST_HV) 744015516c77SSepherosa Ziehau return; 744115516c77SSepherosa Ziehau 74420e11868dSSepherosa Ziehau if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL) 744315516c77SSepherosa Ziehau return; 744415516c77SSepherosa Ziehau 7445fdd0222aSSepherosa Ziehau hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 7446fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 7447fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 7448fdd0222aSSepherosa Ziehau hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK, 7449fdd0222aSSepherosa Ziehau taskqueue_thread_enqueue, &hn_tx_taskque[i]); 7450fdd0222aSSepherosa Ziehau taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET, 7451fdd0222aSSepherosa Ziehau "hn tx%d", i); 7452fdd0222aSSepherosa Ziehau } 745315516c77SSepherosa Ziehau } 7454499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL); 745515516c77SSepherosa Ziehau 745615516c77SSepherosa Ziehau static void 7457499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused) 745815516c77SSepherosa Ziehau { 745915516c77SSepherosa Ziehau 7460fdd0222aSSepherosa Ziehau if (hn_tx_taskque != NULL) { 7461fdd0222aSSepherosa Ziehau int i; 7462fdd0222aSSepherosa Ziehau 7463fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 7464fdd0222aSSepherosa Ziehau taskqueue_free(hn_tx_taskque[i]); 7465fdd0222aSSepherosa Ziehau free(hn_tx_taskque, M_DEVBUF); 7466fdd0222aSSepherosa Ziehau } 7467499c3e17SSepherosa Ziehau 7468499c3e17SSepherosa Ziehau if (hn_vfmap != NULL) 7469499c3e17SSepherosa Ziehau free(hn_vfmap, M_DEVBUF); 7470499c3e17SSepherosa Ziehau rm_destroy(&hn_vfmap_lock); 74712be266caSSepherosa Ziehau 74722be266caSSepherosa Ziehau counter_u64_free(hn_udpcs_fixup); 747315516c77SSepherosa Ziehau } 7474499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL); 7475