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> 6435203574SSepherosa 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); 388db76829bSSepherosa Ziehau static void hn_rxpkt_proto(const struct mbuf *, int *, int *); 389f1b0a43fSSepherosa Ziehau static int hn_set_rxfilter(struct hn_softc *, uint32_t); 390c08f7b2cSSepherosa Ziehau static int hn_rxfilter_config(struct hn_softc *); 39115516c77SSepherosa Ziehau static int hn_rss_reconfig(struct hn_softc *); 392afd4971bSSepherosa Ziehau static void hn_rss_ind_fixup(struct hn_softc *); 393642ec226SSepherosa Ziehau static void hn_rss_mbuf_hash(struct hn_softc *, uint32_t); 39415516c77SSepherosa Ziehau static int hn_rxpkt(struct hn_rx_ring *, const void *, 39515516c77SSepherosa Ziehau int, const struct hn_rxinfo *); 396642ec226SSepherosa Ziehau static uint32_t hn_rss_type_fromndis(uint32_t); 397642ec226SSepherosa Ziehau static uint32_t hn_rss_type_tondis(uint32_t); 39815516c77SSepherosa Ziehau 39915516c77SSepherosa Ziehau static int hn_tx_ring_create(struct hn_softc *, int); 40015516c77SSepherosa Ziehau static void hn_tx_ring_destroy(struct hn_tx_ring *); 40115516c77SSepherosa Ziehau static int hn_create_tx_data(struct hn_softc *, int); 40215516c77SSepherosa Ziehau static void hn_fixup_tx_data(struct hn_softc *); 403db76829bSSepherosa Ziehau static void hn_fixup_rx_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 */ 58778e46963SSepherosa Ziehau static int hn_xpnt_vf = 1; 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); 864f0319886SWei Hu if (ip6->ip6_nxt != IPPROTO_TCP && 865f0319886SWei Hu ip6->ip6_nxt != IPPROTO_UDP) { 866c49d47daSSepherosa Ziehau m_freem(m_head); 867c49d47daSSepherosa Ziehau return (NULL); 868c49d47daSSepherosa Ziehau } 869c49d47daSSepherosa Ziehau m_head->m_pkthdr.l3hlen = sizeof(*ip6); 870cc0c6ebcSSepherosa Ziehau } 871cc0c6ebcSSepherosa Ziehau #endif 872cc0c6ebcSSepherosa Ziehau return (m_head); 873cc0c6ebcSSepherosa Ziehau } 874cc0c6ebcSSepherosa Ziehau 875c49d47daSSepherosa Ziehau /* 876c49d47daSSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 877c49d47daSSepherosa Ziehau */ 878c49d47daSSepherosa Ziehau static __inline struct mbuf * 879c49d47daSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn) 880c49d47daSSepherosa Ziehau { 881c49d47daSSepherosa Ziehau const struct tcphdr *th; 882c49d47daSSepherosa Ziehau int ehlen, iphlen; 883c49d47daSSepherosa Ziehau 884c49d47daSSepherosa Ziehau *tcpsyn = 0; 885c49d47daSSepherosa Ziehau ehlen = m_head->m_pkthdr.l2hlen; 886c49d47daSSepherosa Ziehau iphlen = m_head->m_pkthdr.l3hlen; 887c49d47daSSepherosa Ziehau 888c49d47daSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 889c49d47daSSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 890c49d47daSSepherosa Ziehau if (th->th_flags & TH_SYN) 891c49d47daSSepherosa Ziehau *tcpsyn = 1; 892c49d47daSSepherosa Ziehau return (m_head); 893c49d47daSSepherosa Ziehau } 894c49d47daSSepherosa Ziehau 895cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR 896cc0c6ebcSSepherosa Ziehau 897edd3f315SSepherosa Ziehau #endif /* INET6 || INET */ 898edd3f315SSepherosa Ziehau 89915516c77SSepherosa Ziehau static int 900f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter) 901f1b0a43fSSepherosa Ziehau { 902f1b0a43fSSepherosa Ziehau int error = 0; 903f1b0a43fSSepherosa Ziehau 904f1b0a43fSSepherosa Ziehau HN_LOCK_ASSERT(sc); 905f1b0a43fSSepherosa Ziehau 906f1b0a43fSSepherosa Ziehau if (sc->hn_rx_filter != filter) { 907f1b0a43fSSepherosa Ziehau error = hn_rndis_set_rxfilter(sc, filter); 908f1b0a43fSSepherosa Ziehau if (!error) 909f1b0a43fSSepherosa Ziehau sc->hn_rx_filter = filter; 910f1b0a43fSSepherosa Ziehau } 911f1b0a43fSSepherosa Ziehau return (error); 912f1b0a43fSSepherosa Ziehau } 913f1b0a43fSSepherosa Ziehau 914f1b0a43fSSepherosa Ziehau static int 915c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc) 91615516c77SSepherosa Ziehau { 91715516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 91815516c77SSepherosa Ziehau uint32_t filter; 91915516c77SSepherosa Ziehau 92015516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 92115516c77SSepherosa Ziehau 9229c6cae24SSepherosa Ziehau /* 9239c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, we don't know how 9249c6cae24SSepherosa Ziehau * its RX filter is configured, so stick the synthetic device in 9259c6cae24SSepherosa Ziehau * the promiscous mode. 9269c6cae24SSepherosa Ziehau */ 9279c6cae24SSepherosa Ziehau if ((ifp->if_flags & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) { 92815516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_PROMISCUOUS; 92915516c77SSepherosa Ziehau } else { 93015516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_DIRECTED; 93115516c77SSepherosa Ziehau if (ifp->if_flags & IFF_BROADCAST) 93215516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_BROADCAST; 93315516c77SSepherosa Ziehau /* TODO: support multicast list */ 93415516c77SSepherosa Ziehau if ((ifp->if_flags & IFF_ALLMULTI) || 935d7c5a620SMatt Macy !CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) 93615516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 93715516c77SSepherosa Ziehau } 938f1b0a43fSSepherosa Ziehau return (hn_set_rxfilter(sc, filter)); 93915516c77SSepherosa Ziehau } 94015516c77SSepherosa Ziehau 941dc13fee6SSepherosa Ziehau static void 942dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc) 943dc13fee6SSepherosa Ziehau { 944dc13fee6SSepherosa Ziehau uint32_t size, pkts; 945dc13fee6SSepherosa Ziehau int i; 946dc13fee6SSepherosa Ziehau 947dc13fee6SSepherosa Ziehau /* 948dc13fee6SSepherosa Ziehau * Setup aggregation size. 949dc13fee6SSepherosa Ziehau */ 950dc13fee6SSepherosa Ziehau if (sc->hn_agg_size < 0) 951dc13fee6SSepherosa Ziehau size = UINT32_MAX; 952dc13fee6SSepherosa Ziehau else 953dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 954dc13fee6SSepherosa Ziehau 955dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_size < size) 956dc13fee6SSepherosa Ziehau size = sc->hn_rndis_agg_size; 957dc13fee6SSepherosa Ziehau 958a4364cfeSSepherosa Ziehau /* NOTE: We only aggregate packets using chimney sending buffers. */ 959a4364cfeSSepherosa Ziehau if (size > (uint32_t)sc->hn_chim_szmax) 960a4364cfeSSepherosa Ziehau size = sc->hn_chim_szmax; 961a4364cfeSSepherosa Ziehau 962dc13fee6SSepherosa Ziehau if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) { 963dc13fee6SSepherosa Ziehau /* Disable */ 964dc13fee6SSepherosa Ziehau size = 0; 965dc13fee6SSepherosa Ziehau pkts = 0; 966dc13fee6SSepherosa Ziehau goto done; 967dc13fee6SSepherosa Ziehau } 968dc13fee6SSepherosa Ziehau 969dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'int'. */ 970dc13fee6SSepherosa Ziehau if (size > INT_MAX) 971dc13fee6SSepherosa Ziehau size = INT_MAX; 972dc13fee6SSepherosa Ziehau 973dc13fee6SSepherosa Ziehau /* 974dc13fee6SSepherosa Ziehau * Setup aggregation packet count. 975dc13fee6SSepherosa Ziehau */ 976dc13fee6SSepherosa Ziehau if (sc->hn_agg_pkts < 0) 977dc13fee6SSepherosa Ziehau pkts = UINT32_MAX; 978dc13fee6SSepherosa Ziehau else 979dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 980dc13fee6SSepherosa Ziehau 981dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_pkts < pkts) 982dc13fee6SSepherosa Ziehau pkts = sc->hn_rndis_agg_pkts; 983dc13fee6SSepherosa Ziehau 984dc13fee6SSepherosa Ziehau if (pkts <= 1) { 985dc13fee6SSepherosa Ziehau /* Disable */ 986dc13fee6SSepherosa Ziehau size = 0; 987dc13fee6SSepherosa Ziehau pkts = 0; 988dc13fee6SSepherosa Ziehau goto done; 989dc13fee6SSepherosa Ziehau } 990dc13fee6SSepherosa Ziehau 991dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 992dc13fee6SSepherosa Ziehau if (pkts > SHRT_MAX) 993dc13fee6SSepherosa Ziehau pkts = SHRT_MAX; 994dc13fee6SSepherosa Ziehau 995dc13fee6SSepherosa Ziehau done: 996dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 997dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_align > SHRT_MAX) { 998dc13fee6SSepherosa Ziehau /* Disable */ 999dc13fee6SSepherosa Ziehau size = 0; 1000dc13fee6SSepherosa Ziehau pkts = 0; 1001dc13fee6SSepherosa Ziehau } 1002dc13fee6SSepherosa Ziehau 1003dc13fee6SSepherosa Ziehau if (bootverbose) { 1004dc13fee6SSepherosa Ziehau if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n", 1005dc13fee6SSepherosa Ziehau size, pkts, sc->hn_rndis_agg_align); 1006dc13fee6SSepherosa Ziehau } 1007dc13fee6SSepherosa Ziehau 1008dc13fee6SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 1009dc13fee6SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 1010dc13fee6SSepherosa Ziehau 1011dc13fee6SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 1012dc13fee6SSepherosa Ziehau txr->hn_agg_szmax = size; 1013dc13fee6SSepherosa Ziehau txr->hn_agg_pktmax = pkts; 1014dc13fee6SSepherosa Ziehau txr->hn_agg_align = sc->hn_rndis_agg_align; 1015dc13fee6SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 1016dc13fee6SSepherosa Ziehau } 1017dc13fee6SSepherosa Ziehau } 1018dc13fee6SSepherosa Ziehau 101915516c77SSepherosa Ziehau static int 102015516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr) 102115516c77SSepherosa Ziehau { 102215516c77SSepherosa Ziehau 102315516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet")); 102415516c77SSepherosa Ziehau if (hn_tx_swq_depth < txr->hn_txdesc_cnt) 102515516c77SSepherosa Ziehau return txr->hn_txdesc_cnt; 102615516c77SSepherosa Ziehau return hn_tx_swq_depth; 102715516c77SSepherosa Ziehau } 102815516c77SSepherosa Ziehau 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 } 106715516c77SSepherosa Ziehau 106815516c77SSepherosa Ziehau static void 1069afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc) 107015516c77SSepherosa Ziehau { 107115516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 1072afd4971bSSepherosa Ziehau int i, nchan; 107315516c77SSepherosa Ziehau 1074afd4971bSSepherosa Ziehau nchan = sc->hn_rx_ring_inuse; 107515516c77SSepherosa Ziehau KASSERT(nchan > 1, ("invalid # of channels %d", nchan)); 107615516c77SSepherosa Ziehau 107715516c77SSepherosa Ziehau /* 107815516c77SSepherosa Ziehau * Check indirect table to make sure that all channels in it 107915516c77SSepherosa Ziehau * can be used. 108015516c77SSepherosa Ziehau */ 108115516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 108215516c77SSepherosa Ziehau if (rss->rss_ind[i] >= nchan) { 108315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, 108415516c77SSepherosa Ziehau "RSS indirect table %d fixup: %u -> %d\n", 108515516c77SSepherosa Ziehau i, rss->rss_ind[i], nchan - 1); 108615516c77SSepherosa Ziehau rss->rss_ind[i] = nchan - 1; 108715516c77SSepherosa Ziehau } 108815516c77SSepherosa Ziehau } 108915516c77SSepherosa Ziehau } 109015516c77SSepherosa Ziehau 109115516c77SSepherosa Ziehau static int 109215516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused) 109315516c77SSepherosa Ziehau { 109415516c77SSepherosa Ziehau 109515516c77SSepherosa Ziehau return EOPNOTSUPP; 109615516c77SSepherosa Ziehau } 109715516c77SSepherosa Ziehau 109815516c77SSepherosa Ziehau static void 109915516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 110015516c77SSepherosa Ziehau { 110115516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 110215516c77SSepherosa Ziehau 110315516c77SSepherosa Ziehau ifmr->ifm_status = IFM_AVALID; 110415516c77SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 110515516c77SSepherosa Ziehau 110615516c77SSepherosa Ziehau if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) { 110715516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_NONE; 110815516c77SSepherosa Ziehau return; 110915516c77SSepherosa Ziehau } 111015516c77SSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 111115516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 111215516c77SSepherosa Ziehau } 111315516c77SSepherosa Ziehau 11145bdfd3fdSDexuan Cui static void 1115962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused) 11165bdfd3fdSDexuan Cui { 1117962f0357SSepherosa Ziehau struct hn_rxvf_setarg *arg = xarg; 11185bdfd3fdSDexuan Cui 1119962f0357SSepherosa Ziehau arg->rxr->hn_rxvf_ifp = arg->vf_ifp; 11205bdfd3fdSDexuan Cui } 11215bdfd3fdSDexuan Cui 11225bdfd3fdSDexuan Cui static void 1123962f0357SSepherosa Ziehau hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp) 11245bdfd3fdSDexuan Cui { 11255bdfd3fdSDexuan Cui struct hn_rx_ring *rxr; 1126962f0357SSepherosa Ziehau struct hn_rxvf_setarg arg; 11275bdfd3fdSDexuan Cui struct task task; 11285bdfd3fdSDexuan Cui int i; 11295bdfd3fdSDexuan Cui 11305bdfd3fdSDexuan Cui HN_LOCK_ASSERT(sc); 11315bdfd3fdSDexuan Cui 1132962f0357SSepherosa Ziehau TASK_INIT(&task, 0, hn_rxvf_set_task, &arg); 11335bdfd3fdSDexuan Cui 11345bdfd3fdSDexuan Cui for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 11355bdfd3fdSDexuan Cui rxr = &sc->hn_rx_ring[i]; 11365bdfd3fdSDexuan Cui 11375bdfd3fdSDexuan Cui if (i < sc->hn_rx_ring_inuse) { 1138962f0357SSepherosa Ziehau arg.rxr = rxr; 1139962f0357SSepherosa Ziehau arg.vf_ifp = vf_ifp; 11405bdfd3fdSDexuan Cui vmbus_chan_run_task(rxr->hn_chan, &task); 11415bdfd3fdSDexuan Cui } else { 1142962f0357SSepherosa Ziehau rxr->hn_rxvf_ifp = vf_ifp; 11435bdfd3fdSDexuan Cui } 11445bdfd3fdSDexuan Cui } 11455bdfd3fdSDexuan Cui } 11465bdfd3fdSDexuan Cui 1147962f0357SSepherosa Ziehau static bool 1148499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp) 1149499c3e17SSepherosa Ziehau { 1150499c3e17SSepherosa Ziehau const struct ifnet *hn_ifp; 1151499c3e17SSepherosa Ziehau 1152499c3e17SSepherosa Ziehau hn_ifp = sc->hn_ifp; 1153499c3e17SSepherosa Ziehau 1154499c3e17SSepherosa Ziehau if (ifp == hn_ifp) 1155499c3e17SSepherosa Ziehau return (false); 1156499c3e17SSepherosa Ziehau 1157499c3e17SSepherosa Ziehau if (ifp->if_alloctype != IFT_ETHER) 1158499c3e17SSepherosa Ziehau return (false); 1159499c3e17SSepherosa Ziehau 1160499c3e17SSepherosa Ziehau /* Ignore lagg/vlan interfaces */ 1161499c3e17SSepherosa Ziehau if (strcmp(ifp->if_dname, "lagg") == 0 || 1162499c3e17SSepherosa Ziehau strcmp(ifp->if_dname, "vlan") == 0) 1163499c3e17SSepherosa Ziehau return (false); 1164499c3e17SSepherosa Ziehau 1165d76fb49fSDexuan Cui /* 1166d76fb49fSDexuan Cui * During detach events ifp->if_addr might be NULL. 1167d76fb49fSDexuan Cui * Make sure the bcmp() below doesn't panic on that: 1168d76fb49fSDexuan Cui */ 1169d76fb49fSDexuan Cui if (ifp->if_addr == NULL || hn_ifp->if_addr == NULL) 1170d76fb49fSDexuan Cui return (false); 1171d76fb49fSDexuan Cui 1172499c3e17SSepherosa Ziehau if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0) 1173499c3e17SSepherosa Ziehau return (false); 1174499c3e17SSepherosa Ziehau 1175499c3e17SSepherosa Ziehau return (true); 1176499c3e17SSepherosa Ziehau } 1177499c3e17SSepherosa Ziehau 11785bdfd3fdSDexuan Cui static void 1179962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf) 11805bdfd3fdSDexuan Cui { 11815bdfd3fdSDexuan Cui struct ifnet *hn_ifp; 11825bdfd3fdSDexuan Cui 11835bdfd3fdSDexuan Cui HN_LOCK(sc); 11845bdfd3fdSDexuan Cui 11855bdfd3fdSDexuan Cui if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 11865bdfd3fdSDexuan Cui goto out; 11875bdfd3fdSDexuan Cui 1188499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1189499c3e17SSepherosa Ziehau goto out; 11905bdfd3fdSDexuan Cui hn_ifp = sc->hn_ifp; 11915bdfd3fdSDexuan Cui 1192962f0357SSepherosa Ziehau if (rxvf) { 1193962f0357SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_RXVF) 11945bdfd3fdSDexuan Cui goto out; 11955bdfd3fdSDexuan Cui 1196962f0357SSepherosa Ziehau sc->hn_flags |= HN_FLAG_RXVF; 11975bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 11985bdfd3fdSDexuan Cui } else { 1199962f0357SSepherosa Ziehau if (!(sc->hn_flags & HN_FLAG_RXVF)) 12005bdfd3fdSDexuan Cui goto out; 12015bdfd3fdSDexuan Cui 1202962f0357SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_RXVF; 1203499c3e17SSepherosa Ziehau if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 12045bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 12055bdfd3fdSDexuan Cui else 12065bdfd3fdSDexuan Cui hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE); 12075bdfd3fdSDexuan Cui } 12085bdfd3fdSDexuan Cui 12095bdfd3fdSDexuan Cui hn_nvs_set_datapath(sc, 12109c6cae24SSepherosa Ziehau rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH); 12115bdfd3fdSDexuan Cui 1212962f0357SSepherosa Ziehau hn_rxvf_set(sc, rxvf ? ifp : NULL); 12135bdfd3fdSDexuan Cui 1214962f0357SSepherosa Ziehau if (rxvf) { 1215642ec226SSepherosa Ziehau hn_vf_rss_fixup(sc, true); 12165bdfd3fdSDexuan Cui hn_suspend_mgmt(sc); 12175bdfd3fdSDexuan Cui sc->hn_link_flags &= 12185bdfd3fdSDexuan Cui ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG); 1219499c3e17SSepherosa Ziehau if_link_state_change(hn_ifp, LINK_STATE_DOWN); 12205bdfd3fdSDexuan Cui } else { 1221642ec226SSepherosa Ziehau hn_vf_rss_restore(sc); 12225bdfd3fdSDexuan Cui hn_resume_mgmt(sc); 12235bdfd3fdSDexuan Cui } 12245bdfd3fdSDexuan Cui 1225962f0357SSepherosa Ziehau devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname, 1226962f0357SSepherosa Ziehau rxvf ? "VF_UP" : "VF_DOWN", NULL); 122733408a34SDexuan Cui 1228962f0357SSepherosa Ziehau if (bootverbose) { 1229962f0357SSepherosa Ziehau if_printf(hn_ifp, "datapath is switched %s %s\n", 1230962f0357SSepherosa Ziehau rxvf ? "to" : "from", ifp->if_xname); 1231962f0357SSepherosa Ziehau } 12325bdfd3fdSDexuan Cui out: 12335bdfd3fdSDexuan Cui HN_UNLOCK(sc); 12345bdfd3fdSDexuan Cui } 12355bdfd3fdSDexuan Cui 12365bdfd3fdSDexuan Cui static void 12375bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event) 12385bdfd3fdSDexuan Cui { 1239962f0357SSepherosa Ziehau 12405bdfd3fdSDexuan Cui if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN) 12415bdfd3fdSDexuan Cui return; 1242962f0357SSepherosa Ziehau hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP); 12435bdfd3fdSDexuan Cui } 12445bdfd3fdSDexuan Cui 12455bdfd3fdSDexuan Cui static void 12465bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp) 12475bdfd3fdSDexuan Cui { 1248962f0357SSepherosa Ziehau 1249962f0357SSepherosa Ziehau hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP); 12505bdfd3fdSDexuan Cui } 12515bdfd3fdSDexuan Cui 12529c6cae24SSepherosa Ziehau static int 12539c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr) 12549c6cae24SSepherosa Ziehau { 12559c6cae24SSepherosa Ziehau struct ifnet *ifp, *vf_ifp; 12569c6cae24SSepherosa Ziehau uint64_t tmp; 12579c6cae24SSepherosa Ziehau int error; 12589c6cae24SSepherosa Ziehau 12599c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 12609c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 12619c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 12629c6cae24SSepherosa Ziehau 12639c6cae24SSepherosa Ziehau /* 12649c6cae24SSepherosa Ziehau * Fix up requested capabilities w/ supported capabilities, 12659c6cae24SSepherosa Ziehau * since the supported capabilities could have been changed. 12669c6cae24SSepherosa Ziehau */ 12679c6cae24SSepherosa Ziehau ifr->ifr_reqcap &= ifp->if_capabilities; 12689c6cae24SSepherosa Ziehau /* Pass SIOCSIFCAP to VF. */ 12699c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr); 12709c6cae24SSepherosa Ziehau 12719c6cae24SSepherosa Ziehau /* 12729c6cae24SSepherosa Ziehau * NOTE: 12739c6cae24SSepherosa Ziehau * The error will be propagated to the callers, however, it 12749c6cae24SSepherosa Ziehau * is _not_ useful here. 12759c6cae24SSepherosa Ziehau */ 12769c6cae24SSepherosa Ziehau 12779c6cae24SSepherosa Ziehau /* 12789c6cae24SSepherosa Ziehau * Merge VF's enabled capabilities. 12799c6cae24SSepherosa Ziehau */ 12809c6cae24SSepherosa Ziehau ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities; 12819c6cae24SSepherosa Ziehau 12829c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc); 12839c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 12849c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12859c6cae24SSepherosa Ziehau else 12869c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12879c6cae24SSepherosa Ziehau 12889c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc); 12899c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 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_IP_TSO; 12959c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 12969c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12979c6cae24SSepherosa Ziehau else 12989c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12999c6cae24SSepherosa Ziehau 13009c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO; 13019c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 13029c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 13039c6cae24SSepherosa Ziehau else 13049c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 13059c6cae24SSepherosa Ziehau 13069c6cae24SSepherosa Ziehau return (error); 13079c6cae24SSepherosa Ziehau } 13089c6cae24SSepherosa Ziehau 13099c6cae24SSepherosa Ziehau static int 13109c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc) 13119c6cae24SSepherosa Ziehau { 13129c6cae24SSepherosa Ziehau struct ifnet *vf_ifp; 13139c6cae24SSepherosa Ziehau struct ifreq ifr; 13149c6cae24SSepherosa Ziehau 13159c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 13169c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 13179c6cae24SSepherosa Ziehau 13189c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 13199c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 13209c6cae24SSepherosa Ziehau ifr.ifr_flags = vf_ifp->if_flags & 0xffff; 13219c6cae24SSepherosa Ziehau ifr.ifr_flagshigh = vf_ifp->if_flags >> 16; 13229c6cae24SSepherosa Ziehau return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr)); 13239c6cae24SSepherosa Ziehau } 13249c6cae24SSepherosa Ziehau 13259c6cae24SSepherosa Ziehau static void 13269c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc) 13279c6cae24SSepherosa Ziehau { 13289c6cae24SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 13299c6cae24SSepherosa Ziehau int allmulti = 0; 13309c6cae24SSepherosa Ziehau 13319c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 13329c6cae24SSepherosa Ziehau 13339c6cae24SSepherosa Ziehau /* XXX vlan(4) style mcast addr maintenance */ 1334d7c5a620SMatt Macy if (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) 13359c6cae24SSepherosa Ziehau allmulti = IFF_ALLMULTI; 13369c6cae24SSepherosa Ziehau 13379c6cae24SSepherosa Ziehau /* Always set the VF's if_flags */ 13389c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti; 13399c6cae24SSepherosa Ziehau } 13409c6cae24SSepherosa Ziehau 13419c6cae24SSepherosa Ziehau static void 13429c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m) 13439c6cae24SSepherosa Ziehau { 13449c6cae24SSepherosa Ziehau struct rm_priotracker pt; 13459c6cae24SSepherosa Ziehau struct ifnet *hn_ifp = NULL; 13469c6cae24SSepherosa Ziehau struct mbuf *mn; 13479c6cae24SSepherosa Ziehau 13489c6cae24SSepherosa Ziehau /* 13499c6cae24SSepherosa Ziehau * XXX racy, if hn(4) ever detached. 13509c6cae24SSepherosa Ziehau */ 13519c6cae24SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 13529c6cae24SSepherosa Ziehau if (vf_ifp->if_index < hn_vfmap_size) 13539c6cae24SSepherosa Ziehau hn_ifp = hn_vfmap[vf_ifp->if_index]; 13549c6cae24SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 13559c6cae24SSepherosa Ziehau 13569c6cae24SSepherosa Ziehau if (hn_ifp != NULL) { 13579c6cae24SSepherosa Ziehau for (mn = m; mn != NULL; mn = mn->m_nextpkt) { 13583bed4e54SSepherosa Ziehau /* 13593bed4e54SSepherosa Ziehau * Allow tapping on the VF. 13603bed4e54SSepherosa Ziehau */ 13619c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(vf_ifp, mn); 13623bed4e54SSepherosa Ziehau 13633bed4e54SSepherosa Ziehau /* 13643bed4e54SSepherosa Ziehau * Update VF stats. 13653bed4e54SSepherosa Ziehau */ 13663bed4e54SSepherosa Ziehau if ((vf_ifp->if_capenable & IFCAP_HWSTATS) == 0) { 13673bed4e54SSepherosa Ziehau if_inc_counter(vf_ifp, IFCOUNTER_IBYTES, 13683bed4e54SSepherosa Ziehau mn->m_pkthdr.len); 13693bed4e54SSepherosa Ziehau } 13703bed4e54SSepherosa Ziehau /* 13713bed4e54SSepherosa Ziehau * XXX IFCOUNTER_IMCAST 13723bed4e54SSepherosa Ziehau * This stat updating is kinda invasive, since it 13733bed4e54SSepherosa Ziehau * requires two checks on the mbuf: the length check 13743bed4e54SSepherosa Ziehau * and the ethernet header check. As of this write, 13753bed4e54SSepherosa Ziehau * all multicast packets go directly to hn(4), which 13763bed4e54SSepherosa Ziehau * makes imcast stat updating in the VF a try in vian. 13773bed4e54SSepherosa Ziehau */ 13783bed4e54SSepherosa Ziehau 13793bed4e54SSepherosa Ziehau /* 13803bed4e54SSepherosa Ziehau * Fix up rcvif and increase hn(4)'s ipackets. 13813bed4e54SSepherosa Ziehau */ 13829c6cae24SSepherosa Ziehau mn->m_pkthdr.rcvif = hn_ifp; 13839c6cae24SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1); 13849c6cae24SSepherosa Ziehau } 13853bed4e54SSepherosa Ziehau /* 13863bed4e54SSepherosa Ziehau * Go through hn(4)'s if_input. 13873bed4e54SSepherosa Ziehau */ 13889c6cae24SSepherosa Ziehau hn_ifp->if_input(hn_ifp, m); 13899c6cae24SSepherosa Ziehau } else { 13909c6cae24SSepherosa Ziehau /* 13919c6cae24SSepherosa Ziehau * In the middle of the transition; free this 13929c6cae24SSepherosa Ziehau * mbuf chain. 13939c6cae24SSepherosa Ziehau */ 13949c6cae24SSepherosa Ziehau while (m != NULL) { 13959c6cae24SSepherosa Ziehau mn = m->m_nextpkt; 13969c6cae24SSepherosa Ziehau m->m_nextpkt = NULL; 13979c6cae24SSepherosa Ziehau m_freem(m); 13989c6cae24SSepherosa Ziehau m = mn; 13999c6cae24SSepherosa Ziehau } 14009c6cae24SSepherosa Ziehau } 14019c6cae24SSepherosa Ziehau } 14029c6cae24SSepherosa Ziehau 14039c6cae24SSepherosa Ziehau static void 14049c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc) 14059c6cae24SSepherosa Ziehau { 14069c6cae24SSepherosa Ziehau struct ifnet *ifp; 14079c6cae24SSepherosa Ziehau 14089c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 14099c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 14109c6cae24SSepherosa Ziehau 14119c6cae24SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu); 14129c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099 14139c6cae24SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp)) 14149c6cae24SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp)); 14159c6cae24SSepherosa Ziehau #endif 14169c6cae24SSepherosa Ziehau } 14179c6cae24SSepherosa Ziehau 1418642ec226SSepherosa Ziehau static uint32_t 1419642ec226SSepherosa Ziehau hn_rss_type_fromndis(uint32_t rss_hash) 1420642ec226SSepherosa Ziehau { 1421642ec226SSepherosa Ziehau uint32_t types = 0; 1422642ec226SSepherosa Ziehau 1423642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_IPV4) 1424642ec226SSepherosa Ziehau types |= RSS_TYPE_IPV4; 1425642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_TCP_IPV4) 1426642ec226SSepherosa Ziehau types |= RSS_TYPE_TCP_IPV4; 1427642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_IPV6) 1428642ec226SSepherosa Ziehau types |= RSS_TYPE_IPV6; 1429642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_IPV6_EX) 1430642ec226SSepherosa Ziehau types |= RSS_TYPE_IPV6_EX; 1431642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_TCP_IPV6) 1432642ec226SSepherosa Ziehau types |= RSS_TYPE_TCP_IPV6; 1433642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_TCP_IPV6_EX) 1434642ec226SSepherosa Ziehau types |= RSS_TYPE_TCP_IPV6_EX; 14356f12c42eSSepherosa Ziehau if (rss_hash & NDIS_HASH_UDP_IPV4_X) 14366f12c42eSSepherosa Ziehau types |= RSS_TYPE_UDP_IPV4; 1437642ec226SSepherosa Ziehau return (types); 1438642ec226SSepherosa Ziehau } 1439642ec226SSepherosa Ziehau 1440642ec226SSepherosa Ziehau static uint32_t 1441642ec226SSepherosa Ziehau hn_rss_type_tondis(uint32_t types) 1442642ec226SSepherosa Ziehau { 1443642ec226SSepherosa Ziehau uint32_t rss_hash = 0; 1444642ec226SSepherosa Ziehau 14456f12c42eSSepherosa Ziehau KASSERT((types & (RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0, 14466f12c42eSSepherosa Ziehau ("UDP6 and UDP6EX are not supported")); 1447642ec226SSepherosa Ziehau 1448642ec226SSepherosa Ziehau if (types & RSS_TYPE_IPV4) 1449642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_IPV4; 1450642ec226SSepherosa Ziehau if (types & RSS_TYPE_TCP_IPV4) 1451642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_TCP_IPV4; 1452642ec226SSepherosa Ziehau if (types & RSS_TYPE_IPV6) 1453642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_IPV6; 1454642ec226SSepherosa Ziehau if (types & RSS_TYPE_IPV6_EX) 1455642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_IPV6_EX; 1456642ec226SSepherosa Ziehau if (types & RSS_TYPE_TCP_IPV6) 1457642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_TCP_IPV6; 1458642ec226SSepherosa Ziehau if (types & RSS_TYPE_TCP_IPV6_EX) 1459642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_TCP_IPV6_EX; 14606f12c42eSSepherosa Ziehau if (types & RSS_TYPE_UDP_IPV4) 14616f12c42eSSepherosa Ziehau rss_hash |= NDIS_HASH_UDP_IPV4_X; 1462642ec226SSepherosa Ziehau return (rss_hash); 1463642ec226SSepherosa Ziehau } 1464642ec226SSepherosa Ziehau 1465642ec226SSepherosa Ziehau static void 1466642ec226SSepherosa Ziehau hn_rss_mbuf_hash(struct hn_softc *sc, uint32_t mbuf_hash) 1467642ec226SSepherosa Ziehau { 1468642ec226SSepherosa Ziehau int i; 1469642ec226SSepherosa Ziehau 1470642ec226SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1471642ec226SSepherosa Ziehau 1472642ec226SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 1473642ec226SSepherosa Ziehau sc->hn_rx_ring[i].hn_mbuf_hash = mbuf_hash; 1474642ec226SSepherosa Ziehau } 1475642ec226SSepherosa Ziehau 1476642ec226SSepherosa Ziehau static void 1477642ec226SSepherosa Ziehau hn_vf_rss_fixup(struct hn_softc *sc, bool reconf) 1478642ec226SSepherosa Ziehau { 1479642ec226SSepherosa Ziehau struct ifnet *ifp, *vf_ifp; 1480642ec226SSepherosa Ziehau struct ifrsshash ifrh; 1481642ec226SSepherosa Ziehau struct ifrsskey ifrk; 1482642ec226SSepherosa Ziehau int error; 1483642ec226SSepherosa Ziehau uint32_t my_types, diff_types, mbuf_types = 0; 1484642ec226SSepherosa Ziehau 1485642ec226SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1486642ec226SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 1487642ec226SSepherosa Ziehau ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname)); 1488642ec226SSepherosa Ziehau 1489642ec226SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 1490642ec226SSepherosa Ziehau /* No RSS on synthetic parts; done. */ 1491642ec226SSepherosa Ziehau return; 1492642ec226SSepherosa Ziehau } 1493642ec226SSepherosa Ziehau if ((sc->hn_rss_hcap & NDIS_HASH_FUNCTION_TOEPLITZ) == 0) { 1494642ec226SSepherosa Ziehau /* Synthetic parts do not support Toeplitz; done. */ 1495642ec226SSepherosa Ziehau return; 1496642ec226SSepherosa Ziehau } 1497642ec226SSepherosa Ziehau 1498642ec226SSepherosa Ziehau ifp = sc->hn_ifp; 1499642ec226SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 1500642ec226SSepherosa Ziehau 1501642ec226SSepherosa Ziehau /* 1502642ec226SSepherosa Ziehau * Extract VF's RSS key. Only 40 bytes key for Toeplitz is 1503642ec226SSepherosa Ziehau * supported. 1504642ec226SSepherosa Ziehau */ 1505642ec226SSepherosa Ziehau memset(&ifrk, 0, sizeof(ifrk)); 1506642ec226SSepherosa Ziehau strlcpy(ifrk.ifrk_name, vf_ifp->if_xname, sizeof(ifrk.ifrk_name)); 1507642ec226SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSKEY, (caddr_t)&ifrk); 1508642ec226SSepherosa Ziehau if (error) { 1509*a3b413afSHans Petter Selasky if_printf(ifp, "%s SIOCGIFRSSKEY failed: %d\n", 1510642ec226SSepherosa Ziehau vf_ifp->if_xname, error); 1511642ec226SSepherosa Ziehau goto done; 1512642ec226SSepherosa Ziehau } 1513642ec226SSepherosa Ziehau if (ifrk.ifrk_func != RSS_FUNC_TOEPLITZ) { 1514642ec226SSepherosa Ziehau if_printf(ifp, "%s RSS function %u is not Toeplitz\n", 1515642ec226SSepherosa Ziehau vf_ifp->if_xname, ifrk.ifrk_func); 1516642ec226SSepherosa Ziehau goto done; 1517642ec226SSepherosa Ziehau } 1518642ec226SSepherosa Ziehau if (ifrk.ifrk_keylen != NDIS_HASH_KEYSIZE_TOEPLITZ) { 1519642ec226SSepherosa Ziehau if_printf(ifp, "%s invalid RSS Toeplitz key length %d\n", 1520642ec226SSepherosa Ziehau vf_ifp->if_xname, ifrk.ifrk_keylen); 1521642ec226SSepherosa Ziehau goto done; 1522642ec226SSepherosa Ziehau } 1523642ec226SSepherosa Ziehau 1524642ec226SSepherosa Ziehau /* 1525642ec226SSepherosa Ziehau * Extract VF's RSS hash. Only Toeplitz is supported. 1526642ec226SSepherosa Ziehau */ 1527642ec226SSepherosa Ziehau memset(&ifrh, 0, sizeof(ifrh)); 1528642ec226SSepherosa Ziehau strlcpy(ifrh.ifrh_name, vf_ifp->if_xname, sizeof(ifrh.ifrh_name)); 1529642ec226SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSHASH, (caddr_t)&ifrh); 1530642ec226SSepherosa Ziehau if (error) { 1531642ec226SSepherosa Ziehau if_printf(ifp, "%s SIOCGRSSHASH failed: %d\n", 1532642ec226SSepherosa Ziehau vf_ifp->if_xname, error); 1533642ec226SSepherosa Ziehau goto done; 1534642ec226SSepherosa Ziehau } 1535642ec226SSepherosa Ziehau if (ifrh.ifrh_func != RSS_FUNC_TOEPLITZ) { 1536642ec226SSepherosa Ziehau if_printf(ifp, "%s RSS function %u is not Toeplitz\n", 1537642ec226SSepherosa Ziehau vf_ifp->if_xname, ifrh.ifrh_func); 1538642ec226SSepherosa Ziehau goto done; 1539642ec226SSepherosa Ziehau } 1540642ec226SSepherosa Ziehau 1541642ec226SSepherosa Ziehau my_types = hn_rss_type_fromndis(sc->hn_rss_hcap); 1542642ec226SSepherosa Ziehau if ((ifrh.ifrh_types & my_types) == 0) { 1543642ec226SSepherosa Ziehau /* This disables RSS; ignore it then */ 1544642ec226SSepherosa Ziehau if_printf(ifp, "%s intersection of RSS types failed. " 1545642ec226SSepherosa Ziehau "VF %#x, mine %#x\n", vf_ifp->if_xname, 1546642ec226SSepherosa Ziehau ifrh.ifrh_types, my_types); 1547642ec226SSepherosa Ziehau goto done; 1548642ec226SSepherosa Ziehau } 1549642ec226SSepherosa Ziehau 1550642ec226SSepherosa Ziehau diff_types = my_types ^ ifrh.ifrh_types; 1551642ec226SSepherosa Ziehau my_types &= ifrh.ifrh_types; 1552642ec226SSepherosa Ziehau mbuf_types = my_types; 1553642ec226SSepherosa Ziehau 1554642ec226SSepherosa Ziehau /* 1555642ec226SSepherosa Ziehau * Detect RSS hash value/type confliction. 1556642ec226SSepherosa Ziehau * 1557642ec226SSepherosa Ziehau * NOTE: 1558642ec226SSepherosa Ziehau * We don't disable the hash type, but stop delivery the hash 1559642ec226SSepherosa Ziehau * value/type through mbufs on RX path. 15606f12c42eSSepherosa Ziehau * 15616f12c42eSSepherosa Ziehau * XXX If HN_CAP_UDPHASH is set in hn_caps, then UDP 4-tuple 15626f12c42eSSepherosa Ziehau * hash is delivered with type of TCP_IPV4. This means if 15636f12c42eSSepherosa Ziehau * UDP_IPV4 is enabled, then TCP_IPV4 should be forced, at 15646f12c42eSSepherosa Ziehau * least to hn_mbuf_hash. However, given that _all_ of the 15656f12c42eSSepherosa Ziehau * NICs implement TCP_IPV4, this will _not_ impose any issues 15666f12c42eSSepherosa Ziehau * here. 1567642ec226SSepherosa Ziehau */ 1568642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_IPV4) && 1569642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & 1570642ec226SSepherosa Ziehau (RSS_TYPE_TCP_IPV4 | RSS_TYPE_UDP_IPV4))) { 1571642ec226SSepherosa Ziehau /* Conflict; disable IPV4 hash type/value delivery. */ 1572642ec226SSepherosa Ziehau if_printf(ifp, "disable IPV4 mbuf hash delivery\n"); 1573642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_IPV4; 1574642ec226SSepherosa Ziehau } 1575642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_IPV6) && 1576642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & 1577642ec226SSepherosa Ziehau (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 | 1578642ec226SSepherosa Ziehau RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX | 1579642ec226SSepherosa Ziehau RSS_TYPE_IPV6_EX))) { 1580642ec226SSepherosa Ziehau /* Conflict; disable IPV6 hash type/value delivery. */ 1581642ec226SSepherosa Ziehau if_printf(ifp, "disable IPV6 mbuf hash delivery\n"); 1582642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_IPV6; 1583642ec226SSepherosa Ziehau } 1584642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_IPV6_EX) && 1585642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & 1586642ec226SSepherosa Ziehau (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 | 1587642ec226SSepherosa Ziehau RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX | 1588642ec226SSepherosa Ziehau RSS_TYPE_IPV6))) { 1589642ec226SSepherosa Ziehau /* Conflict; disable IPV6_EX hash type/value delivery. */ 1590642ec226SSepherosa Ziehau if_printf(ifp, "disable IPV6_EX mbuf hash delivery\n"); 1591642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_IPV6_EX; 1592642ec226SSepherosa Ziehau } 1593642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_TCP_IPV6) && 1594642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6_EX)) { 1595642ec226SSepherosa Ziehau /* Conflict; disable TCP_IPV6 hash type/value delivery. */ 1596642ec226SSepherosa Ziehau if_printf(ifp, "disable TCP_IPV6 mbuf hash delivery\n"); 1597642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_TCP_IPV6; 1598642ec226SSepherosa Ziehau } 1599642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_TCP_IPV6_EX) && 1600642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6)) { 1601642ec226SSepherosa Ziehau /* Conflict; disable TCP_IPV6_EX hash type/value delivery. */ 1602642ec226SSepherosa Ziehau if_printf(ifp, "disable TCP_IPV6_EX mbuf hash delivery\n"); 1603642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_TCP_IPV6_EX; 1604642ec226SSepherosa Ziehau } 1605642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_UDP_IPV6) && 1606642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6_EX)) { 1607642ec226SSepherosa Ziehau /* Conflict; disable UDP_IPV6 hash type/value delivery. */ 1608642ec226SSepherosa Ziehau if_printf(ifp, "disable UDP_IPV6 mbuf hash delivery\n"); 1609642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_UDP_IPV6; 1610642ec226SSepherosa Ziehau } 1611642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_UDP_IPV6_EX) && 1612642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6)) { 1613642ec226SSepherosa Ziehau /* Conflict; disable UDP_IPV6_EX hash type/value delivery. */ 1614642ec226SSepherosa Ziehau if_printf(ifp, "disable UDP_IPV6_EX mbuf hash delivery\n"); 1615642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_UDP_IPV6_EX; 1616642ec226SSepherosa Ziehau } 1617642ec226SSepherosa Ziehau 1618642ec226SSepherosa Ziehau /* 1619642ec226SSepherosa Ziehau * Indirect table does not matter. 1620642ec226SSepherosa Ziehau */ 1621642ec226SSepherosa Ziehau 1622642ec226SSepherosa Ziehau sc->hn_rss_hash = (sc->hn_rss_hcap & NDIS_HASH_FUNCTION_MASK) | 1623642ec226SSepherosa Ziehau hn_rss_type_tondis(my_types); 1624642ec226SSepherosa Ziehau memcpy(sc->hn_rss.rss_key, ifrk.ifrk_key, sizeof(sc->hn_rss.rss_key)); 1625642ec226SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 1626642ec226SSepherosa Ziehau 1627642ec226SSepherosa Ziehau if (reconf) { 1628642ec226SSepherosa Ziehau error = hn_rss_reconfig(sc); 1629642ec226SSepherosa Ziehau if (error) { 1630642ec226SSepherosa Ziehau /* XXX roll-back? */ 1631642ec226SSepherosa Ziehau if_printf(ifp, "hn_rss_reconfig failed: %d\n", error); 1632642ec226SSepherosa Ziehau /* XXX keep going. */ 1633642ec226SSepherosa Ziehau } 1634642ec226SSepherosa Ziehau } 1635642ec226SSepherosa Ziehau done: 1636642ec226SSepherosa Ziehau /* Hash deliverability for mbufs. */ 1637642ec226SSepherosa Ziehau hn_rss_mbuf_hash(sc, hn_rss_type_tondis(mbuf_types)); 1638642ec226SSepherosa Ziehau } 1639642ec226SSepherosa Ziehau 1640642ec226SSepherosa Ziehau static void 1641642ec226SSepherosa Ziehau hn_vf_rss_restore(struct hn_softc *sc) 1642642ec226SSepherosa Ziehau { 1643642ec226SSepherosa Ziehau 1644642ec226SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1645642ec226SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 1646642ec226SSepherosa Ziehau ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname)); 1647642ec226SSepherosa Ziehau 1648642ec226SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) 1649642ec226SSepherosa Ziehau goto done; 1650642ec226SSepherosa Ziehau 1651642ec226SSepherosa Ziehau /* 1652642ec226SSepherosa Ziehau * Restore hash types. Key does _not_ matter. 1653642ec226SSepherosa Ziehau */ 1654642ec226SSepherosa Ziehau if (sc->hn_rss_hash != sc->hn_rss_hcap) { 1655642ec226SSepherosa Ziehau int error; 1656642ec226SSepherosa Ziehau 1657642ec226SSepherosa Ziehau sc->hn_rss_hash = sc->hn_rss_hcap; 1658642ec226SSepherosa Ziehau error = hn_rss_reconfig(sc); 1659642ec226SSepherosa Ziehau if (error) { 1660642ec226SSepherosa Ziehau if_printf(sc->hn_ifp, "hn_rss_reconfig failed: %d\n", 1661642ec226SSepherosa Ziehau error); 1662642ec226SSepherosa Ziehau /* XXX keep going. */ 1663642ec226SSepherosa Ziehau } 1664642ec226SSepherosa Ziehau } 1665642ec226SSepherosa Ziehau done: 1666642ec226SSepherosa Ziehau /* Hash deliverability for mbufs. */ 1667642ec226SSepherosa Ziehau hn_rss_mbuf_hash(sc, NDIS_HASH_ALL); 1668642ec226SSepherosa Ziehau } 1669642ec226SSepherosa Ziehau 16709c6cae24SSepherosa Ziehau static void 16719c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc) 16729c6cae24SSepherosa Ziehau { 16739c6cae24SSepherosa Ziehau struct ifnet *ifp, *vf_ifp; 16749c6cae24SSepherosa Ziehau struct ifreq ifr; 16759c6cae24SSepherosa Ziehau 16769c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 16779c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 16789c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 16799c6cae24SSepherosa Ziehau 16809c6cae24SSepherosa Ziehau /* 16819c6cae24SSepherosa Ziehau * Mark the VF ready. 16829c6cae24SSepherosa Ziehau */ 16839c6cae24SSepherosa Ziehau sc->hn_vf_rdytick = 0; 16849c6cae24SSepherosa Ziehau 16859c6cae24SSepherosa Ziehau /* 16869c6cae24SSepherosa Ziehau * Save information for restoration. 16879c6cae24SSepherosa Ziehau */ 16889c6cae24SSepherosa Ziehau sc->hn_saved_caps = ifp->if_capabilities; 16899c6cae24SSepherosa Ziehau sc->hn_saved_tsomax = ifp->if_hw_tsomax; 16909c6cae24SSepherosa Ziehau sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount; 16919c6cae24SSepherosa Ziehau sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize; 16929c6cae24SSepherosa Ziehau 16939c6cae24SSepherosa Ziehau /* 16949c6cae24SSepherosa Ziehau * Intersect supported/enabled capabilities. 16959c6cae24SSepherosa Ziehau * 16969c6cae24SSepherosa Ziehau * NOTE: 16979c6cae24SSepherosa Ziehau * if_hwassist is not changed here. 16989c6cae24SSepherosa Ziehau */ 16999c6cae24SSepherosa Ziehau ifp->if_capabilities &= vf_ifp->if_capabilities; 17009c6cae24SSepherosa Ziehau ifp->if_capenable &= ifp->if_capabilities; 17019c6cae24SSepherosa Ziehau 17029c6cae24SSepherosa Ziehau /* 17039c6cae24SSepherosa Ziehau * Fix TSO settings. 17049c6cae24SSepherosa Ziehau */ 17059c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax) 17069c6cae24SSepherosa Ziehau ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax; 17079c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount) 17089c6cae24SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount; 17099c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize) 17109c6cae24SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize; 17119c6cae24SSepherosa Ziehau 17129c6cae24SSepherosa Ziehau /* 17139c6cae24SSepherosa Ziehau * Change VF's enabled capabilities. 17149c6cae24SSepherosa Ziehau */ 17159c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 17169c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 17179c6cae24SSepherosa Ziehau ifr.ifr_reqcap = ifp->if_capenable; 17189c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(sc, &ifr); 17199c6cae24SSepherosa Ziehau 17209c6cae24SSepherosa Ziehau if (ifp->if_mtu != ETHERMTU) { 17219c6cae24SSepherosa Ziehau int error; 17229c6cae24SSepherosa Ziehau 17239c6cae24SSepherosa Ziehau /* 17249c6cae24SSepherosa Ziehau * Change VF's MTU. 17259c6cae24SSepherosa Ziehau */ 17269c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 17279c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 17289c6cae24SSepherosa Ziehau ifr.ifr_mtu = ifp->if_mtu; 17299c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr); 17309c6cae24SSepherosa Ziehau if (error) { 17319c6cae24SSepherosa Ziehau if_printf(ifp, "%s SIOCSIFMTU %u failed\n", 17329c6cae24SSepherosa Ziehau vf_ifp->if_xname, ifp->if_mtu); 17339c6cae24SSepherosa Ziehau if (ifp->if_mtu > ETHERMTU) { 17349c6cae24SSepherosa Ziehau if_printf(ifp, "change MTU to %d\n", ETHERMTU); 17359c6cae24SSepherosa Ziehau 17369c6cae24SSepherosa Ziehau /* 17379c6cae24SSepherosa Ziehau * XXX 17389c6cae24SSepherosa Ziehau * No need to adjust the synthetic parts' MTU; 17399c6cae24SSepherosa Ziehau * failure of the adjustment will cause us 17409c6cae24SSepherosa Ziehau * infinite headache. 17419c6cae24SSepherosa Ziehau */ 17429c6cae24SSepherosa Ziehau ifp->if_mtu = ETHERMTU; 17439c6cae24SSepherosa Ziehau hn_mtu_change_fixup(sc); 17449c6cae24SSepherosa Ziehau } 17459c6cae24SSepherosa Ziehau } 17469c6cae24SSepherosa Ziehau } 17479c6cae24SSepherosa Ziehau } 17489c6cae24SSepherosa Ziehau 17499c6cae24SSepherosa Ziehau static bool 17509c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc) 17519c6cae24SSepherosa Ziehau { 17529c6cae24SSepherosa Ziehau 17539c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 17549c6cae24SSepherosa Ziehau 17559c6cae24SSepherosa Ziehau if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL) 17569c6cae24SSepherosa Ziehau return (false); 17579c6cae24SSepherosa Ziehau 17589c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick == 0) 17599c6cae24SSepherosa Ziehau return (true); 17609c6cae24SSepherosa Ziehau 17619c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick > ticks) 17629c6cae24SSepherosa Ziehau return (false); 17639c6cae24SSepherosa Ziehau 17649c6cae24SSepherosa Ziehau /* Mark VF as ready. */ 17659c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(sc); 17669c6cae24SSepherosa Ziehau return (true); 17679c6cae24SSepherosa Ziehau } 17689c6cae24SSepherosa Ziehau 17699c6cae24SSepherosa Ziehau static void 1770a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc) 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 rm_wunlock(&sc->hn_vf_lock); 1780a97fff19SSepherosa Ziehau 1781a97fff19SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 1782a97fff19SSepherosa Ziehau sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF; 1783a97fff19SSepherosa Ziehau } 1784a97fff19SSepherosa Ziehau 1785a97fff19SSepherosa Ziehau static void 1786a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf) 1787a97fff19SSepherosa Ziehau { 1788a97fff19SSepherosa Ziehau int i; 1789a97fff19SSepherosa Ziehau 1790a97fff19SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1791a97fff19SSepherosa Ziehau 1792a97fff19SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ 1793a97fff19SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 1794a97fff19SSepherosa Ziehau sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED; 1795a97fff19SSepherosa Ziehau if (clear_vf) 1796a97fff19SSepherosa Ziehau sc->hn_vf_ifp = NULL; 1797a97fff19SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 1798a97fff19SSepherosa Ziehau 1799a97fff19SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 1800a97fff19SSepherosa Ziehau sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF; 1801a97fff19SSepherosa Ziehau } 1802a97fff19SSepherosa Ziehau 1803a97fff19SSepherosa Ziehau static void 18049c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc) 18059c6cae24SSepherosa Ziehau { 18069c6cae24SSepherosa Ziehau int error; 18079c6cae24SSepherosa Ziehau 18089c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 18099c6cae24SSepherosa Ziehau 18109c6cae24SSepherosa Ziehau KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0, 18119c6cae24SSepherosa Ziehau ("%s: transparent VF was enabled", sc->hn_ifp->if_xname)); 18129c6cae24SSepherosa Ziehau 18139c6cae24SSepherosa Ziehau if (bootverbose) { 18149c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "try bringing up %s\n", 18159c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 18169c6cae24SSepherosa Ziehau } 18179c6cae24SSepherosa Ziehau 18189c6cae24SSepherosa Ziehau /* 18199c6cae24SSepherosa Ziehau * Bring the VF up. 18209c6cae24SSepherosa Ziehau */ 18219c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 18229c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags |= IFF_UP; 18239c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 18249c6cae24SSepherosa Ziehau if (error) { 18259c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "bringing up %s failed: %d\n", 18269c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname, error); 18279c6cae24SSepherosa Ziehau return; 18289c6cae24SSepherosa Ziehau } 18299c6cae24SSepherosa Ziehau 18309c6cae24SSepherosa Ziehau /* 18319c6cae24SSepherosa Ziehau * NOTE: 18329c6cae24SSepherosa Ziehau * Datapath setting must happen _after_ bringing the VF up. 18339c6cae24SSepherosa Ziehau */ 18349c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF); 18359c6cae24SSepherosa Ziehau 1836642ec226SSepherosa Ziehau /* 1837642ec226SSepherosa Ziehau * NOTE: 1838642ec226SSepherosa Ziehau * Fixup RSS related bits _after_ the VF is brought up, since 1839642ec226SSepherosa Ziehau * many VFs generate RSS key during it's initialization. 1840642ec226SSepherosa Ziehau */ 1841642ec226SSepherosa Ziehau hn_vf_rss_fixup(sc, true); 1842642ec226SSepherosa Ziehau 1843a97fff19SSepherosa Ziehau /* Mark transparent mode VF as enabled. */ 1844a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(sc); 18459c6cae24SSepherosa Ziehau } 18469c6cae24SSepherosa Ziehau 18479c6cae24SSepherosa Ziehau static void 18489c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused) 18499c6cae24SSepherosa Ziehau { 18509c6cae24SSepherosa Ziehau struct hn_softc *sc = xsc; 18519c6cae24SSepherosa Ziehau 18529c6cae24SSepherosa Ziehau HN_LOCK(sc); 18539c6cae24SSepherosa Ziehau 18549c6cae24SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 18559c6cae24SSepherosa Ziehau goto done; 18569c6cae24SSepherosa Ziehau if (sc->hn_vf_ifp == NULL) 18579c6cae24SSepherosa Ziehau goto done; 18589c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 18599c6cae24SSepherosa Ziehau goto done; 18609c6cae24SSepherosa Ziehau 18619c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick != 0) { 18629c6cae24SSepherosa Ziehau /* Mark VF as ready. */ 18639c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(sc); 18649c6cae24SSepherosa Ziehau } 18659c6cae24SSepherosa Ziehau 18669c6cae24SSepherosa Ziehau if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) { 18679c6cae24SSepherosa Ziehau /* 18689c6cae24SSepherosa Ziehau * Delayed VF initialization. 18699c6cae24SSepherosa Ziehau */ 18709c6cae24SSepherosa Ziehau if (bootverbose) { 18719c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "delayed initialize %s\n", 18729c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 18739c6cae24SSepherosa Ziehau } 18749c6cae24SSepherosa Ziehau hn_xpnt_vf_init(sc); 18759c6cae24SSepherosa Ziehau } 18769c6cae24SSepherosa Ziehau done: 18779c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 18789c6cae24SSepherosa Ziehau } 18799c6cae24SSepherosa Ziehau 1880499c3e17SSepherosa Ziehau static void 1881499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp) 1882499c3e17SSepherosa Ziehau { 1883499c3e17SSepherosa Ziehau struct hn_softc *sc = xsc; 1884499c3e17SSepherosa Ziehau 1885499c3e17SSepherosa Ziehau HN_LOCK(sc); 1886499c3e17SSepherosa Ziehau 1887499c3e17SSepherosa Ziehau if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 1888499c3e17SSepherosa Ziehau goto done; 1889499c3e17SSepherosa Ziehau 1890499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1891499c3e17SSepherosa Ziehau goto done; 1892499c3e17SSepherosa Ziehau 1893499c3e17SSepherosa Ziehau if (sc->hn_vf_ifp != NULL) { 1894499c3e17SSepherosa Ziehau if_printf(sc->hn_ifp, "%s was attached as VF\n", 1895499c3e17SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 1896499c3e17SSepherosa Ziehau goto done; 1897499c3e17SSepherosa Ziehau } 1898499c3e17SSepherosa Ziehau 18999c6cae24SSepherosa Ziehau if (hn_xpnt_vf && ifp->if_start != NULL) { 19009c6cae24SSepherosa Ziehau /* 19019c6cae24SSepherosa Ziehau * ifnet.if_start is _not_ supported by transparent 19029c6cae24SSepherosa Ziehau * mode VF; mainly due to the IFF_DRV_OACTIVE flag. 19039c6cae24SSepherosa Ziehau */ 19049c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported " 19059c6cae24SSepherosa Ziehau "in transparent VF mode.\n", ifp->if_xname); 19069c6cae24SSepherosa Ziehau goto done; 19079c6cae24SSepherosa Ziehau } 19089c6cae24SSepherosa Ziehau 1909499c3e17SSepherosa Ziehau rm_wlock(&hn_vfmap_lock); 1910499c3e17SSepherosa Ziehau 1911499c3e17SSepherosa Ziehau if (ifp->if_index >= hn_vfmap_size) { 1912499c3e17SSepherosa Ziehau struct ifnet **newmap; 1913499c3e17SSepherosa Ziehau int newsize; 1914499c3e17SSepherosa Ziehau 1915499c3e17SSepherosa Ziehau newsize = ifp->if_index + HN_VFMAP_SIZE_DEF; 1916499c3e17SSepherosa Ziehau newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF, 1917499c3e17SSepherosa Ziehau M_WAITOK | M_ZERO); 1918499c3e17SSepherosa Ziehau 1919499c3e17SSepherosa Ziehau memcpy(newmap, hn_vfmap, 1920499c3e17SSepherosa Ziehau sizeof(struct ifnet *) * hn_vfmap_size); 1921499c3e17SSepherosa Ziehau free(hn_vfmap, M_DEVBUF); 1922499c3e17SSepherosa Ziehau hn_vfmap = newmap; 1923499c3e17SSepherosa Ziehau hn_vfmap_size = newsize; 1924499c3e17SSepherosa Ziehau } 1925499c3e17SSepherosa Ziehau KASSERT(hn_vfmap[ifp->if_index] == NULL, 1926499c3e17SSepherosa Ziehau ("%s: ifindex %d was mapped to %s", 1927499c3e17SSepherosa Ziehau ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname)); 1928499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index] = sc->hn_ifp; 1929499c3e17SSepherosa Ziehau 1930499c3e17SSepherosa Ziehau rm_wunlock(&hn_vfmap_lock); 1931499c3e17SSepherosa Ziehau 19329c6cae24SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ 19339c6cae24SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 19349c6cae24SSepherosa Ziehau KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0, 19359c6cae24SSepherosa Ziehau ("%s: transparent VF was enabled", sc->hn_ifp->if_xname)); 1936499c3e17SSepherosa Ziehau sc->hn_vf_ifp = ifp; 19379c6cae24SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 19389c6cae24SSepherosa Ziehau 19399c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 19409c6cae24SSepherosa Ziehau int wait_ticks; 19419c6cae24SSepherosa Ziehau 19429c6cae24SSepherosa Ziehau /* 19439c6cae24SSepherosa Ziehau * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp. 19449c6cae24SSepherosa Ziehau * Save vf_ifp's current if_input for later restoration. 19459c6cae24SSepherosa Ziehau */ 19469c6cae24SSepherosa Ziehau sc->hn_vf_input = ifp->if_input; 19479c6cae24SSepherosa Ziehau ifp->if_input = hn_xpnt_vf_input; 19489c6cae24SSepherosa Ziehau 19499c6cae24SSepherosa Ziehau /* 19509c6cae24SSepherosa Ziehau * Stop link status management; use the VF's. 19519c6cae24SSepherosa Ziehau */ 19529c6cae24SSepherosa Ziehau hn_suspend_mgmt(sc); 19539c6cae24SSepherosa Ziehau 19549c6cae24SSepherosa Ziehau /* 19559c6cae24SSepherosa Ziehau * Give VF sometime to complete its attach routing. 19569c6cae24SSepherosa Ziehau */ 19579c6cae24SSepherosa Ziehau wait_ticks = hn_xpnt_vf_attwait * hz; 19589c6cae24SSepherosa Ziehau sc->hn_vf_rdytick = ticks + wait_ticks; 19599c6cae24SSepherosa Ziehau 19609c6cae24SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init, 19619c6cae24SSepherosa Ziehau wait_ticks); 19629c6cae24SSepherosa Ziehau } 1963499c3e17SSepherosa Ziehau done: 1964499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 1965499c3e17SSepherosa Ziehau } 1966499c3e17SSepherosa Ziehau 1967499c3e17SSepherosa Ziehau static void 1968499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp) 1969499c3e17SSepherosa Ziehau { 1970499c3e17SSepherosa Ziehau struct hn_softc *sc = xsc; 1971499c3e17SSepherosa Ziehau 1972499c3e17SSepherosa Ziehau HN_LOCK(sc); 1973499c3e17SSepherosa Ziehau 1974499c3e17SSepherosa Ziehau if (sc->hn_vf_ifp == NULL) 1975499c3e17SSepherosa Ziehau goto done; 1976499c3e17SSepherosa Ziehau 1977499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1978499c3e17SSepherosa Ziehau goto done; 1979499c3e17SSepherosa Ziehau 19809c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 19819c6cae24SSepherosa Ziehau /* 19829c6cae24SSepherosa Ziehau * Make sure that the delayed initialization is not running. 19839c6cae24SSepherosa Ziehau * 19849c6cae24SSepherosa Ziehau * NOTE: 19859c6cae24SSepherosa Ziehau * - This lock _must_ be released, since the hn_vf_init task 19869c6cae24SSepherosa Ziehau * will try holding this lock. 19879c6cae24SSepherosa Ziehau * - It is safe to release this lock here, since the 19889c6cae24SSepherosa Ziehau * hn_ifnet_attevent() is interlocked by the hn_vf_ifp. 19899c6cae24SSepherosa Ziehau * 19909c6cae24SSepherosa Ziehau * XXX racy, if hn(4) ever detached. 19919c6cae24SSepherosa Ziehau */ 19929c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 19939c6cae24SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init); 19949c6cae24SSepherosa Ziehau HN_LOCK(sc); 19959c6cae24SSepherosa Ziehau 19969c6cae24SSepherosa Ziehau KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved", 19979c6cae24SSepherosa Ziehau sc->hn_ifp->if_xname)); 19989c6cae24SSepherosa Ziehau ifp->if_input = sc->hn_vf_input; 19999c6cae24SSepherosa Ziehau sc->hn_vf_input = NULL; 20009c6cae24SSepherosa Ziehau 2001642ec226SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) && 2002642ec226SSepherosa Ziehau (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) 20039c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH); 20049c6cae24SSepherosa Ziehau 20059c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick == 0) { 20069c6cae24SSepherosa Ziehau /* 20079c6cae24SSepherosa Ziehau * The VF was ready; restore some settings. 20089c6cae24SSepherosa Ziehau */ 20099c6cae24SSepherosa Ziehau sc->hn_ifp->if_capabilities = sc->hn_saved_caps; 20109c6cae24SSepherosa Ziehau /* 20119c6cae24SSepherosa Ziehau * NOTE: 20129c6cae24SSepherosa Ziehau * There is _no_ need to fixup if_capenable and 20139c6cae24SSepherosa Ziehau * if_hwassist, since the if_capabilities before 20149c6cae24SSepherosa Ziehau * restoration was an intersection of the VF's 20159c6cae24SSepherosa Ziehau * if_capabilites and the synthetic device's 20169c6cae24SSepherosa Ziehau * if_capabilites. 20179c6cae24SSepherosa Ziehau */ 20189c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax; 20199c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomaxsegcount = 20209c6cae24SSepherosa Ziehau sc->hn_saved_tsosegcnt; 20219c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz; 20229c6cae24SSepherosa Ziehau } 20239c6cae24SSepherosa Ziehau 2024642ec226SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 2025642ec226SSepherosa Ziehau /* 2026642ec226SSepherosa Ziehau * Restore RSS settings. 2027642ec226SSepherosa Ziehau */ 2028642ec226SSepherosa Ziehau hn_vf_rss_restore(sc); 2029642ec226SSepherosa Ziehau 20309c6cae24SSepherosa Ziehau /* 20319c6cae24SSepherosa Ziehau * Resume link status management, which was suspended 20329c6cae24SSepherosa Ziehau * by hn_ifnet_attevent(). 20339c6cae24SSepherosa Ziehau */ 20349c6cae24SSepherosa Ziehau hn_resume_mgmt(sc); 20359c6cae24SSepherosa Ziehau } 2036642ec226SSepherosa Ziehau } 20379c6cae24SSepherosa Ziehau 2038a97fff19SSepherosa Ziehau /* Mark transparent mode VF as disabled. */ 2039a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */); 2040499c3e17SSepherosa Ziehau 2041499c3e17SSepherosa Ziehau rm_wlock(&hn_vfmap_lock); 2042499c3e17SSepherosa Ziehau 2043499c3e17SSepherosa Ziehau KASSERT(ifp->if_index < hn_vfmap_size, 2044499c3e17SSepherosa Ziehau ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size)); 2045499c3e17SSepherosa Ziehau if (hn_vfmap[ifp->if_index] != NULL) { 2046499c3e17SSepherosa Ziehau KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp, 2047499c3e17SSepherosa Ziehau ("%s: ifindex %d was mapped to %s", 2048499c3e17SSepherosa Ziehau ifp->if_xname, ifp->if_index, 2049499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index]->if_xname)); 2050499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index] = NULL; 2051499c3e17SSepherosa Ziehau } 2052499c3e17SSepherosa Ziehau 2053499c3e17SSepherosa Ziehau rm_wunlock(&hn_vfmap_lock); 2054499c3e17SSepherosa Ziehau done: 2055499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 2056499c3e17SSepherosa Ziehau } 2057499c3e17SSepherosa Ziehau 20589c6cae24SSepherosa Ziehau static void 20599c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state) 20609c6cae24SSepherosa Ziehau { 20619c6cae24SSepherosa Ziehau struct hn_softc *sc = xsc; 20629c6cae24SSepherosa Ziehau 20639c6cae24SSepherosa Ziehau if (sc->hn_vf_ifp == ifp) 20649c6cae24SSepherosa Ziehau if_link_state_change(sc->hn_ifp, link_state); 20659c6cae24SSepherosa Ziehau } 20669c6cae24SSepherosa Ziehau 206715516c77SSepherosa Ziehau static int 206815516c77SSepherosa Ziehau hn_probe(device_t dev) 206915516c77SSepherosa Ziehau { 207015516c77SSepherosa Ziehau 2071c2d50b26SSepherosa Ziehau if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) { 207215516c77SSepherosa Ziehau device_set_desc(dev, "Hyper-V Network Interface"); 207315516c77SSepherosa Ziehau return BUS_PROBE_DEFAULT; 207415516c77SSepherosa Ziehau } 207515516c77SSepherosa Ziehau return ENXIO; 207615516c77SSepherosa Ziehau } 207715516c77SSepherosa Ziehau 207815516c77SSepherosa Ziehau static int 207915516c77SSepherosa Ziehau hn_attach(device_t dev) 208015516c77SSepherosa Ziehau { 208115516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 208215516c77SSepherosa Ziehau struct sysctl_oid_list *child; 208315516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 208415516c77SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 208515516c77SSepherosa Ziehau struct ifnet *ifp = NULL; 208615516c77SSepherosa Ziehau int error, ring_cnt, tx_ring_cnt; 2087eb2fe044SSepherosa Ziehau uint32_t mtu; 208815516c77SSepherosa Ziehau 208915516c77SSepherosa Ziehau sc->hn_dev = dev; 209015516c77SSepherosa Ziehau sc->hn_prichan = vmbus_get_channel(dev); 209115516c77SSepherosa Ziehau HN_LOCK_INIT(sc); 20929c6cae24SSepherosa Ziehau rm_init(&sc->hn_vf_lock, "hnvf"); 20939c6cae24SSepherosa Ziehau if (hn_xpnt_vf && hn_xpnt_vf_accbpf) 20949c6cae24SSepherosa Ziehau sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF; 209515516c77SSepherosa Ziehau 209615516c77SSepherosa Ziehau /* 2097dc13fee6SSepherosa Ziehau * Initialize these tunables once. 2098dc13fee6SSepherosa Ziehau */ 2099dc13fee6SSepherosa Ziehau sc->hn_agg_size = hn_tx_agg_size; 2100dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = hn_tx_agg_pkts; 2101dc13fee6SSepherosa Ziehau 2102dc13fee6SSepherosa Ziehau /* 210315516c77SSepherosa Ziehau * Setup taskqueue for transmission. 210415516c77SSepherosa Ziehau */ 21050e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) { 2106fdd0222aSSepherosa Ziehau int i; 2107fdd0222aSSepherosa Ziehau 2108fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = 2109fdd0222aSSepherosa Ziehau malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 2110fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 2111fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 2112fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx", 2113fdd0222aSSepherosa Ziehau M_WAITOK, taskqueue_thread_enqueue, 2114fdd0222aSSepherosa Ziehau &sc->hn_tx_taskqs[i]); 2115fdd0222aSSepherosa Ziehau taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET, 2116fdd0222aSSepherosa Ziehau "%s tx%d", device_get_nameunit(dev), i); 2117fdd0222aSSepherosa Ziehau } 21180e11868dSSepherosa Ziehau } else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) { 2119fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = hn_tx_taskque; 212015516c77SSepherosa Ziehau } 212115516c77SSepherosa Ziehau 212215516c77SSepherosa Ziehau /* 212315516c77SSepherosa Ziehau * Setup taskqueue for mangement tasks, e.g. link status. 212415516c77SSepherosa Ziehau */ 212515516c77SSepherosa Ziehau sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK, 212615516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0); 212715516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt", 212815516c77SSepherosa Ziehau device_get_nameunit(dev)); 212915516c77SSepherosa Ziehau TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc); 213015516c77SSepherosa Ziehau TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc); 213115516c77SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0, 213215516c77SSepherosa Ziehau hn_netchg_status_taskfunc, sc); 213315516c77SSepherosa Ziehau 21349c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 21359c6cae24SSepherosa Ziehau /* 21369c6cae24SSepherosa Ziehau * Setup taskqueue for VF tasks, e.g. delayed VF bringing up. 21379c6cae24SSepherosa Ziehau */ 21389c6cae24SSepherosa Ziehau sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK, 21399c6cae24SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_vf_taskq); 21409c6cae24SSepherosa Ziehau taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf", 21419c6cae24SSepherosa Ziehau device_get_nameunit(dev)); 21429c6cae24SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0, 21439c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc, sc); 21449c6cae24SSepherosa Ziehau } 21459c6cae24SSepherosa Ziehau 214615516c77SSepherosa Ziehau /* 214715516c77SSepherosa Ziehau * Allocate ifnet and setup its name earlier, so that if_printf 214815516c77SSepherosa Ziehau * can be used by functions, which will be called after 214915516c77SSepherosa Ziehau * ether_ifattach(). 215015516c77SSepherosa Ziehau */ 215115516c77SSepherosa Ziehau ifp = sc->hn_ifp = if_alloc(IFT_ETHER); 215215516c77SSepherosa Ziehau ifp->if_softc = sc; 215315516c77SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 215415516c77SSepherosa Ziehau 215515516c77SSepherosa Ziehau /* 215615516c77SSepherosa Ziehau * Initialize ifmedia earlier so that it can be unconditionally 215715516c77SSepherosa Ziehau * destroyed, if error happened later on. 215815516c77SSepherosa Ziehau */ 215915516c77SSepherosa Ziehau ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts); 216015516c77SSepherosa Ziehau 216115516c77SSepherosa Ziehau /* 216215516c77SSepherosa Ziehau * Figure out the # of RX rings (ring_cnt) and the # of TX rings 216315516c77SSepherosa Ziehau * to use (tx_ring_cnt). 216415516c77SSepherosa Ziehau * 216515516c77SSepherosa Ziehau * NOTE: 216615516c77SSepherosa Ziehau * The # of RX rings to use is same as the # of channels to use. 216715516c77SSepherosa Ziehau */ 216815516c77SSepherosa Ziehau ring_cnt = hn_chan_cnt; 216915516c77SSepherosa Ziehau if (ring_cnt <= 0) { 217015516c77SSepherosa Ziehau /* Default */ 217115516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 217215516c77SSepherosa Ziehau if (ring_cnt > HN_RING_CNT_DEF_MAX) 217315516c77SSepherosa Ziehau ring_cnt = HN_RING_CNT_DEF_MAX; 217415516c77SSepherosa Ziehau } else if (ring_cnt > mp_ncpus) { 217515516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 217615516c77SSepherosa Ziehau } 217734d68912SSepherosa Ziehau #ifdef RSS 217834d68912SSepherosa Ziehau if (ring_cnt > rss_getnumbuckets()) 217934d68912SSepherosa Ziehau ring_cnt = rss_getnumbuckets(); 218034d68912SSepherosa Ziehau #endif 218115516c77SSepherosa Ziehau 218215516c77SSepherosa Ziehau tx_ring_cnt = hn_tx_ring_cnt; 218315516c77SSepherosa Ziehau if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt) 218415516c77SSepherosa Ziehau tx_ring_cnt = ring_cnt; 218523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 218615516c77SSepherosa Ziehau if (hn_use_if_start) { 218715516c77SSepherosa Ziehau /* ifnet.if_start only needs one TX ring. */ 218815516c77SSepherosa Ziehau tx_ring_cnt = 1; 218915516c77SSepherosa Ziehau } 219023bf9e15SSepherosa Ziehau #endif 219115516c77SSepherosa Ziehau 219215516c77SSepherosa Ziehau /* 219315516c77SSepherosa Ziehau * Set the leader CPU for channels. 219415516c77SSepherosa Ziehau */ 219515516c77SSepherosa Ziehau sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus; 219615516c77SSepherosa Ziehau 219715516c77SSepherosa Ziehau /* 219815516c77SSepherosa Ziehau * Create enough TX/RX rings, even if only limited number of 219915516c77SSepherosa Ziehau * channels can be allocated. 220015516c77SSepherosa Ziehau */ 220115516c77SSepherosa Ziehau error = hn_create_tx_data(sc, tx_ring_cnt); 220215516c77SSepherosa Ziehau if (error) 220315516c77SSepherosa Ziehau goto failed; 220415516c77SSepherosa Ziehau error = hn_create_rx_data(sc, ring_cnt); 220515516c77SSepherosa Ziehau if (error) 220615516c77SSepherosa Ziehau goto failed; 220715516c77SSepherosa Ziehau 220815516c77SSepherosa Ziehau /* 220915516c77SSepherosa Ziehau * Create transaction context for NVS and RNDIS transactions. 221015516c77SSepherosa Ziehau */ 221115516c77SSepherosa Ziehau sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev), 221215516c77SSepherosa Ziehau HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0); 221325641fc7SSepherosa Ziehau if (sc->hn_xact == NULL) { 221425641fc7SSepherosa Ziehau error = ENXIO; 221515516c77SSepherosa Ziehau goto failed; 221625641fc7SSepherosa Ziehau } 221725641fc7SSepherosa Ziehau 221825641fc7SSepherosa Ziehau /* 221925641fc7SSepherosa Ziehau * Install orphan handler for the revocation of this device's 222025641fc7SSepherosa Ziehau * primary channel. 222125641fc7SSepherosa Ziehau * 222225641fc7SSepherosa Ziehau * NOTE: 222325641fc7SSepherosa Ziehau * The processing order is critical here: 222425641fc7SSepherosa Ziehau * Install the orphan handler, _before_ testing whether this 222525641fc7SSepherosa Ziehau * device's primary channel has been revoked or not. 222625641fc7SSepherosa Ziehau */ 222725641fc7SSepherosa Ziehau vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact); 222825641fc7SSepherosa Ziehau if (vmbus_chan_is_revoked(sc->hn_prichan)) { 222925641fc7SSepherosa Ziehau error = ENXIO; 223025641fc7SSepherosa Ziehau goto failed; 223125641fc7SSepherosa Ziehau } 223215516c77SSepherosa Ziehau 223315516c77SSepherosa Ziehau /* 223415516c77SSepherosa Ziehau * Attach the synthetic parts, i.e. NVS and RNDIS. 223515516c77SSepherosa Ziehau */ 223615516c77SSepherosa Ziehau error = hn_synth_attach(sc, ETHERMTU); 223715516c77SSepherosa Ziehau if (error) 223815516c77SSepherosa Ziehau goto failed; 223915516c77SSepherosa Ziehau 224015516c77SSepherosa Ziehau error = hn_rndis_get_eaddr(sc, eaddr); 224115516c77SSepherosa Ziehau if (error) 224215516c77SSepherosa Ziehau goto failed; 224315516c77SSepherosa Ziehau 2244eb2fe044SSepherosa Ziehau error = hn_rndis_get_mtu(sc, &mtu); 2245eb2fe044SSepherosa Ziehau if (error) 2246eb2fe044SSepherosa Ziehau mtu = ETHERMTU; 2247eb2fe044SSepherosa Ziehau else if (bootverbose) 2248eb2fe044SSepherosa Ziehau device_printf(dev, "RNDIS mtu %u\n", mtu); 2249eb2fe044SSepherosa Ziehau 225015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 225115516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 225215516c77SSepherosa Ziehau /* 225315516c77SSepherosa Ziehau * Reduce TCP segment aggregation limit for multiple 225415516c77SSepherosa Ziehau * RX rings to increase ACK timeliness. 225515516c77SSepherosa Ziehau */ 225615516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF); 225715516c77SSepherosa Ziehau } 225815516c77SSepherosa Ziehau #endif 225915516c77SSepherosa Ziehau 226015516c77SSepherosa Ziehau /* 2261db76829bSSepherosa Ziehau * Fixup TX/RX stuffs after synthetic parts are attached. 226215516c77SSepherosa Ziehau */ 226315516c77SSepherosa Ziehau hn_fixup_tx_data(sc); 2264db76829bSSepherosa Ziehau hn_fixup_rx_data(sc); 226515516c77SSepherosa Ziehau 226615516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 226715516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 226815516c77SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD, 226915516c77SSepherosa Ziehau &sc->hn_nvs_ver, 0, "NVS version"); 227015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version", 227115516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 227215516c77SSepherosa Ziehau hn_ndis_version_sysctl, "A", "NDIS version"); 227315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps", 227415516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 227515516c77SSepherosa Ziehau hn_caps_sysctl, "A", "capabilities"); 227615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist", 227715516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 227815516c77SSepherosa Ziehau hn_hwassist_sysctl, "A", "hwassist"); 22799c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max", 22809c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size"); 22819c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt", 22829c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0, 22839c6cae24SSepherosa Ziehau "max # of TSO segments"); 22849c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz", 22859c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0, 22869c6cae24SSepherosa Ziehau "max size of TSO segment"); 228715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter", 228815516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 228915516c77SSepherosa Ziehau hn_rxfilter_sysctl, "A", "rxfilter"); 229015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash", 229115516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 229215516c77SSepherosa Ziehau hn_rss_hash_sysctl, "A", "RSS hash"); 2293642ec226SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hashcap", 2294642ec226SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 2295642ec226SSepherosa Ziehau hn_rss_hcap_sysctl, "A", "RSS hash capabilities"); 2296642ec226SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "mbuf_hash", 2297642ec226SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 2298642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl, "A", "RSS hash for mbufs"); 229915516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size", 230015516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count"); 230134d68912SSepherosa Ziehau #ifndef RSS 230234d68912SSepherosa Ziehau /* 230334d68912SSepherosa Ziehau * Don't allow RSS key/indirect table changes, if RSS is defined. 230434d68912SSepherosa Ziehau */ 230515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key", 230615516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 230715516c77SSepherosa Ziehau hn_rss_key_sysctl, "IU", "RSS key"); 230815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind", 230915516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 231015516c77SSepherosa Ziehau hn_rss_ind_sysctl, "IU", "RSS indirect table"); 231134d68912SSepherosa Ziehau #endif 2312dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size", 2313dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_size, 0, 2314dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation size limit"); 2315dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts", 2316dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0, 2317dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation count limit"); 2318dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align", 2319dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_align, 0, 2320dc13fee6SSepherosa Ziehau "RNDIS packet transmission aggregation alignment"); 2321dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size", 2322dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 2323dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl, "I", 2324dc13fee6SSepherosa Ziehau "Packet transmission aggregation size, 0 -- disable, -1 -- auto"); 2325dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts", 2326dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 2327dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl, "I", 2328dc13fee6SSepherosa Ziehau "Packet transmission aggregation packets, " 2329dc13fee6SSepherosa Ziehau "0 -- disable, -1 -- auto"); 23306c1204dfSSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling", 23316c1204dfSSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 23326c1204dfSSepherosa Ziehau hn_polling_sysctl, "I", 23336c1204dfSSepherosa Ziehau "Polling frequency: [100,1000000], 0 disable polling"); 233440d60d6eSDexuan Cui SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf", 233540d60d6eSDexuan Cui CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 233640d60d6eSDexuan Cui hn_vf_sysctl, "A", "Virtual Function's name"); 23379c6cae24SSepherosa Ziehau if (!hn_xpnt_vf) { 2338499c3e17SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf", 2339499c3e17SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 2340499c3e17SSepherosa Ziehau hn_rxvf_sysctl, "A", "activated Virtual Function's name"); 23419c6cae24SSepherosa Ziehau } else { 23429c6cae24SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled", 23439c6cae24SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 23449c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl, "I", 23459c6cae24SSepherosa Ziehau "Transparent VF enabled"); 23469c6cae24SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf", 23479c6cae24SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 23489c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl, "I", 23499c6cae24SSepherosa Ziehau "Accurate BPF for transparent VF"); 23509c6cae24SSepherosa Ziehau } 235115516c77SSepherosa Ziehau 235215516c77SSepherosa Ziehau /* 235315516c77SSepherosa Ziehau * Setup the ifmedia, which has been initialized earlier. 235415516c77SSepherosa Ziehau */ 235515516c77SSepherosa Ziehau ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL); 235615516c77SSepherosa Ziehau ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO); 235715516c77SSepherosa Ziehau /* XXX ifmedia_set really should do this for us */ 235815516c77SSepherosa Ziehau sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media; 235915516c77SSepherosa Ziehau 236015516c77SSepherosa Ziehau /* 236115516c77SSepherosa Ziehau * Setup the ifnet for this interface. 236215516c77SSepherosa Ziehau */ 236315516c77SSepherosa Ziehau 236415516c77SSepherosa Ziehau ifp->if_baudrate = IF_Gbps(10); 236515516c77SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 236615516c77SSepherosa Ziehau ifp->if_ioctl = hn_ioctl; 236715516c77SSepherosa Ziehau ifp->if_init = hn_init; 236823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 236915516c77SSepherosa Ziehau if (hn_use_if_start) { 237015516c77SSepherosa Ziehau int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]); 237115516c77SSepherosa Ziehau 237215516c77SSepherosa Ziehau ifp->if_start = hn_start; 237315516c77SSepherosa Ziehau IFQ_SET_MAXLEN(&ifp->if_snd, qdepth); 237415516c77SSepherosa Ziehau ifp->if_snd.ifq_drv_maxlen = qdepth - 1; 237515516c77SSepherosa Ziehau IFQ_SET_READY(&ifp->if_snd); 237623bf9e15SSepherosa Ziehau } else 237723bf9e15SSepherosa Ziehau #endif 237823bf9e15SSepherosa Ziehau { 237915516c77SSepherosa Ziehau ifp->if_transmit = hn_transmit; 238015516c77SSepherosa Ziehau ifp->if_qflush = hn_xmit_qflush; 238115516c77SSepherosa Ziehau } 238215516c77SSepherosa Ziehau 23839c6cae24SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE; 238415516c77SSepherosa Ziehau #ifdef foo 238515516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 238615516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM_IPV6; 238715516c77SSepherosa Ziehau #endif 238815516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_VLAN) { 238915516c77SSepherosa Ziehau /* XXX not sure about VLAN_MTU. */ 239015516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 239115516c77SSepherosa Ziehau } 239215516c77SSepherosa Ziehau 239315516c77SSepherosa Ziehau ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist; 239415516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP_MASK) 239515516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM; 239615516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP6_MASK) 239715516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM_IPV6; 239815516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO4) { 239915516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO4; 240015516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 240115516c77SSepherosa Ziehau } 240215516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO6) { 240315516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO6; 240415516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 240515516c77SSepherosa Ziehau } 240615516c77SSepherosa Ziehau 240715516c77SSepherosa Ziehau /* Enable all available capabilities by default. */ 240815516c77SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 240915516c77SSepherosa Ziehau 24107960e6baSSepherosa Ziehau /* 24117960e6baSSepherosa Ziehau * Disable IPv6 TSO and TXCSUM by default, they still can 24127960e6baSSepherosa Ziehau * be enabled through SIOCSIFCAP. 24137960e6baSSepherosa Ziehau */ 24147960e6baSSepherosa Ziehau ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 24157960e6baSSepherosa Ziehau ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO); 24167960e6baSSepherosa Ziehau 241715516c77SSepherosa Ziehau if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) { 24189c6cae24SSepherosa Ziehau /* 24199c6cae24SSepherosa Ziehau * Lock hn_set_tso_maxsize() to simplify its 24209c6cae24SSepherosa Ziehau * internal logic. 24219c6cae24SSepherosa Ziehau */ 24229c6cae24SSepherosa Ziehau HN_LOCK(sc); 242315516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU); 24249c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 242515516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; 242615516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 242715516c77SSepherosa Ziehau } 242815516c77SSepherosa Ziehau 242915516c77SSepherosa Ziehau ether_ifattach(ifp, eaddr); 243015516c77SSepherosa Ziehau 243115516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) { 243215516c77SSepherosa Ziehau if_printf(ifp, "TSO segcnt %u segsz %u\n", 243315516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize); 243415516c77SSepherosa Ziehau } 2435eb2fe044SSepherosa Ziehau if (mtu < ETHERMTU) { 2436eb2fe044SSepherosa Ziehau if_printf(ifp, "fixup mtu %u -> %u\n", ifp->if_mtu, mtu); 2437eb2fe044SSepherosa Ziehau ifp->if_mtu = mtu; 2438eb2fe044SSepherosa Ziehau } 243915516c77SSepherosa Ziehau 244015516c77SSepherosa Ziehau /* Inform the upper layer about the long frame support. */ 244115516c77SSepherosa Ziehau ifp->if_hdrlen = sizeof(struct ether_vlan_header); 244215516c77SSepherosa Ziehau 244315516c77SSepherosa Ziehau /* 244415516c77SSepherosa Ziehau * Kick off link status check. 244515516c77SSepherosa Ziehau */ 244615516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 244715516c77SSepherosa Ziehau hn_update_link_status(sc); 244815516c77SSepherosa Ziehau 24499c6cae24SSepherosa Ziehau if (!hn_xpnt_vf) { 24505bdfd3fdSDexuan Cui sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event, 24515bdfd3fdSDexuan Cui hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY); 24525bdfd3fdSDexuan Cui sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event, 24535bdfd3fdSDexuan Cui hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY); 24549c6cae24SSepherosa Ziehau } else { 24559c6cae24SSepherosa Ziehau sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event, 24569c6cae24SSepherosa Ziehau hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY); 24579c6cae24SSepherosa Ziehau } 24585bdfd3fdSDexuan Cui 2459f41e0df4SSepherosa Ziehau /* 2460f41e0df4SSepherosa Ziehau * NOTE: 2461f41e0df4SSepherosa Ziehau * Subscribe ether_ifattach event, instead of ifnet_arrival event, 2462f41e0df4SSepherosa Ziehau * since interface's LLADDR is needed; interface LLADDR is not 2463f41e0df4SSepherosa Ziehau * available when ifnet_arrival event is triggered. 2464f41e0df4SSepherosa Ziehau */ 2465499c3e17SSepherosa Ziehau sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event, 2466499c3e17SSepherosa Ziehau hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY); 2467499c3e17SSepherosa Ziehau sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event, 2468499c3e17SSepherosa Ziehau hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY); 2469499c3e17SSepherosa Ziehau 247015516c77SSepherosa Ziehau return (0); 247115516c77SSepherosa Ziehau failed: 247215516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) 247315516c77SSepherosa Ziehau hn_synth_detach(sc); 247415516c77SSepherosa Ziehau hn_detach(dev); 247515516c77SSepherosa Ziehau return (error); 247615516c77SSepherosa Ziehau } 247715516c77SSepherosa Ziehau 247815516c77SSepherosa Ziehau static int 247915516c77SSepherosa Ziehau hn_detach(device_t dev) 248015516c77SSepherosa Ziehau { 248115516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 2482499c3e17SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp, *vf_ifp; 248315516c77SSepherosa Ziehau 24849c6cae24SSepherosa Ziehau if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) { 24859c6cae24SSepherosa Ziehau /* 24869c6cae24SSepherosa Ziehau * In case that the vmbus missed the orphan handler 24879c6cae24SSepherosa Ziehau * installation. 24889c6cae24SSepherosa Ziehau */ 24899c6cae24SSepherosa Ziehau vmbus_xact_ctx_orphan(sc->hn_xact); 24909c6cae24SSepherosa Ziehau } 24919c6cae24SSepherosa Ziehau 24925bdfd3fdSDexuan Cui if (sc->hn_ifaddr_evthand != NULL) 24935bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand); 24945bdfd3fdSDexuan Cui if (sc->hn_ifnet_evthand != NULL) 24955bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand); 2496499c3e17SSepherosa Ziehau if (sc->hn_ifnet_atthand != NULL) { 2497499c3e17SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ether_ifattach_event, 2498499c3e17SSepherosa Ziehau sc->hn_ifnet_atthand); 2499499c3e17SSepherosa Ziehau } 2500499c3e17SSepherosa Ziehau if (sc->hn_ifnet_dethand != NULL) { 2501499c3e17SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ifnet_departure_event, 2502499c3e17SSepherosa Ziehau sc->hn_ifnet_dethand); 2503499c3e17SSepherosa Ziehau } 25049c6cae24SSepherosa Ziehau if (sc->hn_ifnet_lnkhand != NULL) 25059c6cae24SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand); 2506499c3e17SSepherosa Ziehau 2507499c3e17SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 2508499c3e17SSepherosa Ziehau __compiler_membar(); 2509499c3e17SSepherosa Ziehau if (vf_ifp != NULL) 2510499c3e17SSepherosa Ziehau hn_ifnet_detevent(sc, vf_ifp); 25115bdfd3fdSDexuan Cui 251215516c77SSepherosa Ziehau if (device_is_attached(dev)) { 251315516c77SSepherosa Ziehau HN_LOCK(sc); 251415516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 251515516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 25165bdfd3fdSDexuan Cui hn_stop(sc, true); 251715516c77SSepherosa Ziehau /* 251815516c77SSepherosa Ziehau * NOTE: 251915516c77SSepherosa Ziehau * hn_stop() only suspends data, so managment 252015516c77SSepherosa Ziehau * stuffs have to be suspended manually here. 252115516c77SSepherosa Ziehau */ 252215516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 252315516c77SSepherosa Ziehau hn_synth_detach(sc); 252415516c77SSepherosa Ziehau } 252515516c77SSepherosa Ziehau HN_UNLOCK(sc); 252615516c77SSepherosa Ziehau ether_ifdetach(ifp); 252715516c77SSepherosa Ziehau } 252815516c77SSepherosa Ziehau 252915516c77SSepherosa Ziehau ifmedia_removeall(&sc->hn_media); 253015516c77SSepherosa Ziehau hn_destroy_rx_data(sc); 253115516c77SSepherosa Ziehau hn_destroy_tx_data(sc); 253215516c77SSepherosa Ziehau 25330e11868dSSepherosa Ziehau if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) { 2534fdd0222aSSepherosa Ziehau int i; 2535fdd0222aSSepherosa Ziehau 2536fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 2537fdd0222aSSepherosa Ziehau taskqueue_free(sc->hn_tx_taskqs[i]); 2538fdd0222aSSepherosa Ziehau free(sc->hn_tx_taskqs, M_DEVBUF); 2539fdd0222aSSepherosa Ziehau } 254015516c77SSepherosa Ziehau taskqueue_free(sc->hn_mgmt_taskq0); 25419c6cae24SSepherosa Ziehau if (sc->hn_vf_taskq != NULL) 25429c6cae24SSepherosa Ziehau taskqueue_free(sc->hn_vf_taskq); 254315516c77SSepherosa Ziehau 254425641fc7SSepherosa Ziehau if (sc->hn_xact != NULL) { 254525641fc7SSepherosa Ziehau /* 254625641fc7SSepherosa Ziehau * Uninstall the orphan handler _before_ the xact is 254725641fc7SSepherosa Ziehau * destructed. 254825641fc7SSepherosa Ziehau */ 254925641fc7SSepherosa Ziehau vmbus_chan_unset_orphan(sc->hn_prichan); 255015516c77SSepherosa Ziehau vmbus_xact_ctx_destroy(sc->hn_xact); 255125641fc7SSepherosa Ziehau } 255215516c77SSepherosa Ziehau 255315516c77SSepherosa Ziehau if_free(ifp); 255415516c77SSepherosa Ziehau 255515516c77SSepherosa Ziehau HN_LOCK_DESTROY(sc); 25569c6cae24SSepherosa Ziehau rm_destroy(&sc->hn_vf_lock); 255715516c77SSepherosa Ziehau return (0); 255815516c77SSepherosa Ziehau } 255915516c77SSepherosa Ziehau 256015516c77SSepherosa Ziehau static int 256115516c77SSepherosa Ziehau hn_shutdown(device_t dev) 256215516c77SSepherosa Ziehau { 256315516c77SSepherosa Ziehau 256415516c77SSepherosa Ziehau return (0); 256515516c77SSepherosa Ziehau } 256615516c77SSepherosa Ziehau 256715516c77SSepherosa Ziehau static void 256815516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc) 256915516c77SSepherosa Ziehau { 257015516c77SSepherosa Ziehau uint32_t link_status; 257115516c77SSepherosa Ziehau int error; 257215516c77SSepherosa Ziehau 257315516c77SSepherosa Ziehau error = hn_rndis_get_linkstatus(sc, &link_status); 257415516c77SSepherosa Ziehau if (error) { 257515516c77SSepherosa Ziehau /* XXX what to do? */ 257615516c77SSepherosa Ziehau return; 257715516c77SSepherosa Ziehau } 257815516c77SSepherosa Ziehau 257915516c77SSepherosa Ziehau if (link_status == NDIS_MEDIA_STATE_CONNECTED) 258015516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_LINKUP; 258115516c77SSepherosa Ziehau else 258215516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 258315516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, 258415516c77SSepherosa Ziehau (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ? 258515516c77SSepherosa Ziehau LINK_STATE_UP : LINK_STATE_DOWN); 258615516c77SSepherosa Ziehau } 258715516c77SSepherosa Ziehau 258815516c77SSepherosa Ziehau static void 258915516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused) 259015516c77SSepherosa Ziehau { 259115516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 259215516c77SSepherosa Ziehau 259315516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 259415516c77SSepherosa Ziehau return; 259515516c77SSepherosa Ziehau hn_link_status(sc); 259615516c77SSepherosa Ziehau } 259715516c77SSepherosa Ziehau 259815516c77SSepherosa Ziehau static void 259915516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused) 260015516c77SSepherosa Ziehau { 260115516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 260215516c77SSepherosa Ziehau 260315516c77SSepherosa Ziehau /* Prevent any link status checks from running. */ 260415516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_NETCHG; 260515516c77SSepherosa Ziehau 260615516c77SSepherosa Ziehau /* 260715516c77SSepherosa Ziehau * Fake up a [link down --> link up] state change; 5 seconds 260815516c77SSepherosa Ziehau * delay is used, which closely simulates miibus reaction 260915516c77SSepherosa Ziehau * upon link down event. 261015516c77SSepherosa Ziehau */ 261115516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 261215516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); 261315516c77SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0, 261415516c77SSepherosa Ziehau &sc->hn_netchg_status, 5 * hz); 261515516c77SSepherosa Ziehau } 261615516c77SSepherosa Ziehau 261715516c77SSepherosa Ziehau static void 261815516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused) 261915516c77SSepherosa Ziehau { 262015516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 262115516c77SSepherosa Ziehau 262215516c77SSepherosa Ziehau /* Re-allow link status checks. */ 262315516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG; 262415516c77SSepherosa Ziehau hn_link_status(sc); 262515516c77SSepherosa Ziehau } 262615516c77SSepherosa Ziehau 262715516c77SSepherosa Ziehau static void 262815516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc) 262915516c77SSepherosa Ziehau { 263015516c77SSepherosa Ziehau 263115516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 263215516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task); 263315516c77SSepherosa Ziehau } 263415516c77SSepherosa Ziehau 263515516c77SSepherosa Ziehau static void 263615516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc) 263715516c77SSepherosa Ziehau { 263815516c77SSepherosa Ziehau 263915516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 264015516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init); 264115516c77SSepherosa Ziehau } 264215516c77SSepherosa Ziehau 264315516c77SSepherosa Ziehau static __inline int 264415516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd, 264515516c77SSepherosa Ziehau struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) 264615516c77SSepherosa Ziehau { 264715516c77SSepherosa Ziehau struct mbuf *m = *m_head; 264815516c77SSepherosa Ziehau int error; 264915516c77SSepherosa Ziehau 265015516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim")); 265115516c77SSepherosa Ziehau 265215516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap, 265315516c77SSepherosa Ziehau m, segs, nsegs, BUS_DMA_NOWAIT); 265415516c77SSepherosa Ziehau if (error == EFBIG) { 265515516c77SSepherosa Ziehau struct mbuf *m_new; 265615516c77SSepherosa Ziehau 265715516c77SSepherosa Ziehau m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX); 265815516c77SSepherosa Ziehau if (m_new == NULL) 265915516c77SSepherosa Ziehau return ENOBUFS; 266015516c77SSepherosa Ziehau else 266115516c77SSepherosa Ziehau *m_head = m = m_new; 266215516c77SSepherosa Ziehau txr->hn_tx_collapsed++; 266315516c77SSepherosa Ziehau 266415516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, 266515516c77SSepherosa Ziehau txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT); 266615516c77SSepherosa Ziehau } 266715516c77SSepherosa Ziehau if (!error) { 266815516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap, 266915516c77SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 267015516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_DMAMAP; 267115516c77SSepherosa Ziehau } 267215516c77SSepherosa Ziehau return error; 267315516c77SSepherosa Ziehau } 267415516c77SSepherosa Ziehau 267515516c77SSepherosa Ziehau static __inline int 267615516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd) 267715516c77SSepherosa Ziehau { 267815516c77SSepherosa Ziehau 267915516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0, 268015516c77SSepherosa Ziehau ("put an onlist txd %#x", txd->flags)); 2681dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2682dc13fee6SSepherosa Ziehau ("put an onagg txd %#x", txd->flags)); 268315516c77SSepherosa Ziehau 268415516c77SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 268515516c77SSepherosa Ziehau if (atomic_fetchadd_int(&txd->refs, -1) != 1) 268615516c77SSepherosa Ziehau return 0; 268715516c77SSepherosa Ziehau 2688dc13fee6SSepherosa Ziehau if (!STAILQ_EMPTY(&txd->agg_list)) { 2689dc13fee6SSepherosa Ziehau struct hn_txdesc *tmp_txd; 2690dc13fee6SSepherosa Ziehau 2691dc13fee6SSepherosa Ziehau while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) { 2692dc13fee6SSepherosa Ziehau int freed; 2693dc13fee6SSepherosa Ziehau 2694dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list), 2695dc13fee6SSepherosa Ziehau ("resursive aggregation on aggregated txdesc")); 2696dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG), 2697dc13fee6SSepherosa Ziehau ("not aggregated txdesc")); 2698dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 2699dc13fee6SSepherosa Ziehau ("aggregated txdesc uses dmamap")); 2700dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 2701dc13fee6SSepherosa Ziehau ("aggregated txdesc consumes " 2702dc13fee6SSepherosa Ziehau "chimney sending buffer")); 2703dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_size == 0, 2704dc13fee6SSepherosa Ziehau ("aggregated txdesc has non-zero " 2705dc13fee6SSepherosa Ziehau "chimney sending size")); 2706dc13fee6SSepherosa Ziehau 2707dc13fee6SSepherosa Ziehau STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link); 2708dc13fee6SSepherosa Ziehau tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG; 2709dc13fee6SSepherosa Ziehau freed = hn_txdesc_put(txr, tmp_txd); 2710dc13fee6SSepherosa Ziehau KASSERT(freed, ("failed to free aggregated txdesc")); 2711dc13fee6SSepherosa Ziehau } 2712dc13fee6SSepherosa Ziehau } 2713dc13fee6SSepherosa Ziehau 271415516c77SSepherosa Ziehau if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) { 271515516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 271615516c77SSepherosa Ziehau ("chim txd uses dmamap")); 271715516c77SSepherosa Ziehau hn_chim_free(txr->hn_sc, txd->chim_index); 271815516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 2719dc13fee6SSepherosa Ziehau txd->chim_size = 0; 272015516c77SSepherosa Ziehau } else if (txd->flags & HN_TXD_FLAG_DMAMAP) { 272115516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, 272215516c77SSepherosa Ziehau txd->data_dmap, BUS_DMASYNC_POSTWRITE); 272315516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_data_dtag, 272415516c77SSepherosa Ziehau txd->data_dmap); 272515516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_DMAMAP; 272615516c77SSepherosa Ziehau } 272715516c77SSepherosa Ziehau 272815516c77SSepherosa Ziehau if (txd->m != NULL) { 272915516c77SSepherosa Ziehau m_freem(txd->m); 273015516c77SSepherosa Ziehau txd->m = NULL; 273115516c77SSepherosa Ziehau } 273215516c77SSepherosa Ziehau 273315516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 273415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 273515516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 273615516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail >= 0 && 273715516c77SSepherosa Ziehau txr->hn_txdesc_avail < txr->hn_txdesc_cnt, 273815516c77SSepherosa Ziehau ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail)); 273915516c77SSepherosa Ziehau txr->hn_txdesc_avail++; 274015516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 274115516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 274285e4ae1eSSepherosa Ziehau #else /* HN_USE_TXDESC_BUFRING */ 274385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 274415516c77SSepherosa Ziehau atomic_add_int(&txr->hn_txdesc_avail, 1); 274515516c77SSepherosa Ziehau #endif 274685e4ae1eSSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 274785e4ae1eSSepherosa Ziehau #endif /* !HN_USE_TXDESC_BUFRING */ 274815516c77SSepherosa Ziehau 274915516c77SSepherosa Ziehau return 1; 275015516c77SSepherosa Ziehau } 275115516c77SSepherosa Ziehau 275215516c77SSepherosa Ziehau static __inline struct hn_txdesc * 275315516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr) 275415516c77SSepherosa Ziehau { 275515516c77SSepherosa Ziehau struct hn_txdesc *txd; 275615516c77SSepherosa Ziehau 275715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 275815516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 275915516c77SSepherosa Ziehau txd = SLIST_FIRST(&txr->hn_txlist); 276015516c77SSepherosa Ziehau if (txd != NULL) { 276115516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail > 0, 276215516c77SSepherosa Ziehau ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail)); 276315516c77SSepherosa Ziehau txr->hn_txdesc_avail--; 276415516c77SSepherosa Ziehau SLIST_REMOVE_HEAD(&txr->hn_txlist, link); 276515516c77SSepherosa Ziehau } 276615516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 276715516c77SSepherosa Ziehau #else 276815516c77SSepherosa Ziehau txd = buf_ring_dequeue_sc(txr->hn_txdesc_br); 276915516c77SSepherosa Ziehau #endif 277015516c77SSepherosa Ziehau 277115516c77SSepherosa Ziehau if (txd != NULL) { 277215516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 277385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 277415516c77SSepherosa Ziehau atomic_subtract_int(&txr->hn_txdesc_avail, 1); 277515516c77SSepherosa Ziehau #endif 277685e4ae1eSSepherosa Ziehau #endif /* HN_USE_TXDESC_BUFRING */ 277715516c77SSepherosa Ziehau KASSERT(txd->m == NULL && txd->refs == 0 && 2778dc13fee6SSepherosa Ziehau STAILQ_EMPTY(&txd->agg_list) && 277915516c77SSepherosa Ziehau txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 2780dc13fee6SSepherosa Ziehau txd->chim_size == 0 && 278115516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONLIST) && 2782dc13fee6SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONAGG) == 0 && 278315516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd")); 278415516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_ONLIST; 278515516c77SSepherosa Ziehau txd->refs = 1; 278615516c77SSepherosa Ziehau } 278715516c77SSepherosa Ziehau return txd; 278815516c77SSepherosa Ziehau } 278915516c77SSepherosa Ziehau 279015516c77SSepherosa Ziehau static __inline void 279115516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd) 279215516c77SSepherosa Ziehau { 279315516c77SSepherosa Ziehau 279415516c77SSepherosa Ziehau /* 0->1 transition will never work */ 279525641fc7SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 279615516c77SSepherosa Ziehau atomic_add_int(&txd->refs, 1); 279715516c77SSepherosa Ziehau } 279815516c77SSepherosa Ziehau 2799dc13fee6SSepherosa Ziehau static __inline void 2800dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd) 2801dc13fee6SSepherosa Ziehau { 2802dc13fee6SSepherosa Ziehau 2803dc13fee6SSepherosa Ziehau KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2804dc13fee6SSepherosa Ziehau ("recursive aggregation on aggregating txdesc")); 2805dc13fee6SSepherosa Ziehau 2806dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2807dc13fee6SSepherosa Ziehau ("already aggregated")); 2808dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&txd->agg_list), 2809dc13fee6SSepherosa Ziehau ("recursive aggregation on to-be-aggregated txdesc")); 2810dc13fee6SSepherosa Ziehau 2811dc13fee6SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONAGG; 2812dc13fee6SSepherosa Ziehau STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link); 2813dc13fee6SSepherosa Ziehau } 2814dc13fee6SSepherosa Ziehau 281515516c77SSepherosa Ziehau static bool 281615516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr) 281715516c77SSepherosa Ziehau { 281815516c77SSepherosa Ziehau bool pending = false; 281915516c77SSepherosa Ziehau 282015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 282115516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 282215516c77SSepherosa Ziehau if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt) 282315516c77SSepherosa Ziehau pending = true; 282415516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 282515516c77SSepherosa Ziehau #else 282615516c77SSepherosa Ziehau if (!buf_ring_full(txr->hn_txdesc_br)) 282715516c77SSepherosa Ziehau pending = true; 282815516c77SSepherosa Ziehau #endif 282915516c77SSepherosa Ziehau return (pending); 283015516c77SSepherosa Ziehau } 283115516c77SSepherosa Ziehau 283215516c77SSepherosa Ziehau static __inline void 283315516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr) 283415516c77SSepherosa Ziehau { 283515516c77SSepherosa Ziehau txr->hn_has_txeof = 0; 283615516c77SSepherosa Ziehau txr->hn_txeof(txr); 283715516c77SSepherosa Ziehau } 283815516c77SSepherosa Ziehau 283915516c77SSepherosa Ziehau static void 284015516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc, 284115516c77SSepherosa Ziehau struct vmbus_channel *chan, const void *data __unused, int dlen __unused) 284215516c77SSepherosa Ziehau { 284315516c77SSepherosa Ziehau struct hn_txdesc *txd = sndc->hn_cbarg; 284415516c77SSepherosa Ziehau struct hn_tx_ring *txr; 284515516c77SSepherosa Ziehau 284615516c77SSepherosa Ziehau txr = txd->txr; 284715516c77SSepherosa Ziehau KASSERT(txr->hn_chan == chan, 284815516c77SSepherosa Ziehau ("channel mismatch, on chan%u, should be chan%u", 2849aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan))); 285015516c77SSepherosa Ziehau 285115516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 285215516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 285315516c77SSepherosa Ziehau 285415516c77SSepherosa Ziehau ++txr->hn_txdone_cnt; 285515516c77SSepherosa Ziehau if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) { 285615516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 285715516c77SSepherosa Ziehau if (txr->hn_oactive) 285815516c77SSepherosa Ziehau hn_txeof(txr); 285915516c77SSepherosa Ziehau } 286015516c77SSepherosa Ziehau } 286115516c77SSepherosa Ziehau 286215516c77SSepherosa Ziehau static void 286315516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr) 286415516c77SSepherosa Ziehau { 286515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 286615516c77SSepherosa Ziehau tcp_lro_flush_all(&rxr->hn_lro); 286715516c77SSepherosa Ziehau #endif 286815516c77SSepherosa Ziehau 286915516c77SSepherosa Ziehau /* 287015516c77SSepherosa Ziehau * NOTE: 287115516c77SSepherosa Ziehau * 'txr' could be NULL, if multiple channels and 287215516c77SSepherosa Ziehau * ifnet.if_start method are enabled. 287315516c77SSepherosa Ziehau */ 287415516c77SSepherosa Ziehau if (txr == NULL || !txr->hn_has_txeof) 287515516c77SSepherosa Ziehau return; 287615516c77SSepherosa Ziehau 287715516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 287815516c77SSepherosa Ziehau hn_txeof(txr); 287915516c77SSepherosa Ziehau } 288015516c77SSepherosa Ziehau 288115516c77SSepherosa Ziehau static __inline uint32_t 288215516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs) 288315516c77SSepherosa Ziehau { 288415516c77SSepherosa Ziehau 288515516c77SSepherosa Ziehau KASSERT(ofs >= sizeof(struct rndis_packet_msg), 288615516c77SSepherosa Ziehau ("invalid RNDIS packet msg offset %u", ofs)); 288715516c77SSepherosa Ziehau return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset)); 288815516c77SSepherosa Ziehau } 288915516c77SSepherosa Ziehau 289015516c77SSepherosa Ziehau static __inline void * 289115516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize, 289215516c77SSepherosa Ziehau size_t pi_dlen, uint32_t pi_type) 289315516c77SSepherosa Ziehau { 289415516c77SSepherosa Ziehau const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen); 289515516c77SSepherosa Ziehau struct rndis_pktinfo *pi; 289615516c77SSepherosa Ziehau 289715516c77SSepherosa Ziehau KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0, 289815516c77SSepherosa Ziehau ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen)); 289915516c77SSepherosa Ziehau 290015516c77SSepherosa Ziehau /* 290115516c77SSepherosa Ziehau * Per-packet-info does not move; it only grows. 290215516c77SSepherosa Ziehau * 290315516c77SSepherosa Ziehau * NOTE: 290415516c77SSepherosa Ziehau * rm_pktinfooffset in this phase counts from the beginning 290515516c77SSepherosa Ziehau * of rndis_packet_msg. 290615516c77SSepherosa Ziehau */ 290715516c77SSepherosa Ziehau KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize, 290815516c77SSepherosa Ziehau ("%u pktinfo overflows RNDIS packet msg", pi_type)); 290915516c77SSepherosa Ziehau pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset + 291015516c77SSepherosa Ziehau pkt->rm_pktinfolen); 291115516c77SSepherosa Ziehau pkt->rm_pktinfolen += pi_size; 291215516c77SSepherosa Ziehau 291315516c77SSepherosa Ziehau pi->rm_size = pi_size; 291415516c77SSepherosa Ziehau pi->rm_type = pi_type; 291515516c77SSepherosa Ziehau pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET; 291615516c77SSepherosa Ziehau 291715516c77SSepherosa Ziehau return (pi->rm_data); 291815516c77SSepherosa Ziehau } 291915516c77SSepherosa Ziehau 2920dc13fee6SSepherosa Ziehau static __inline int 2921dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr) 2922dc13fee6SSepherosa Ziehau { 2923dc13fee6SSepherosa Ziehau struct hn_txdesc *txd; 2924dc13fee6SSepherosa Ziehau struct mbuf *m; 2925dc13fee6SSepherosa Ziehau int error, pkts; 2926dc13fee6SSepherosa Ziehau 2927dc13fee6SSepherosa Ziehau txd = txr->hn_agg_txd; 2928dc13fee6SSepherosa Ziehau KASSERT(txd != NULL, ("no aggregate txdesc")); 2929dc13fee6SSepherosa Ziehau 2930dc13fee6SSepherosa Ziehau /* 2931dc13fee6SSepherosa Ziehau * Since hn_txpkt() will reset this temporary stat, save 2932dc13fee6SSepherosa Ziehau * it now, so that oerrors can be updated properly, if 2933dc13fee6SSepherosa Ziehau * hn_txpkt() ever fails. 2934dc13fee6SSepherosa Ziehau */ 2935dc13fee6SSepherosa Ziehau pkts = txr->hn_stat_pkts; 2936dc13fee6SSepherosa Ziehau 2937dc13fee6SSepherosa Ziehau /* 2938dc13fee6SSepherosa Ziehau * Since txd's mbuf will _not_ be freed upon hn_txpkt() 2939dc13fee6SSepherosa Ziehau * failure, save it for later freeing, if hn_txpkt() ever 2940dc13fee6SSepherosa Ziehau * fails. 2941dc13fee6SSepherosa Ziehau */ 2942dc13fee6SSepherosa Ziehau m = txd->m; 2943dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 2944dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 2945dc13fee6SSepherosa Ziehau /* txd is freed, but m is not. */ 2946dc13fee6SSepherosa Ziehau m_freem(m); 2947dc13fee6SSepherosa Ziehau 2948dc13fee6SSepherosa Ziehau txr->hn_flush_failed++; 2949dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts); 2950dc13fee6SSepherosa Ziehau } 2951dc13fee6SSepherosa Ziehau 2952dc13fee6SSepherosa Ziehau /* Reset all aggregation states. */ 2953dc13fee6SSepherosa Ziehau txr->hn_agg_txd = NULL; 2954dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = 0; 2955dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 2956dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = NULL; 2957dc13fee6SSepherosa Ziehau 2958dc13fee6SSepherosa Ziehau return (error); 2959dc13fee6SSepherosa Ziehau } 2960dc13fee6SSepherosa Ziehau 2961dc13fee6SSepherosa Ziehau static void * 2962dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 2963dc13fee6SSepherosa Ziehau int pktsize) 2964dc13fee6SSepherosa Ziehau { 2965dc13fee6SSepherosa Ziehau void *chim; 2966dc13fee6SSepherosa Ziehau 2967dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 2968dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) { 2969dc13fee6SSepherosa Ziehau struct hn_txdesc *agg_txd = txr->hn_agg_txd; 2970dc13fee6SSepherosa Ziehau struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt; 2971dc13fee6SSepherosa Ziehau int olen; 2972dc13fee6SSepherosa Ziehau 2973dc13fee6SSepherosa Ziehau /* 2974dc13fee6SSepherosa Ziehau * Update the previous RNDIS packet's total length, 2975dc13fee6SSepherosa Ziehau * it can be increased due to the mandatory alignment 2976dc13fee6SSepherosa Ziehau * padding for this RNDIS packet. And update the 2977dc13fee6SSepherosa Ziehau * aggregating txdesc's chimney sending buffer size 2978dc13fee6SSepherosa Ziehau * accordingly. 2979dc13fee6SSepherosa Ziehau * 2980dc13fee6SSepherosa Ziehau * XXX 2981dc13fee6SSepherosa Ziehau * Zero-out the padding, as required by the RNDIS spec. 2982dc13fee6SSepherosa Ziehau */ 2983dc13fee6SSepherosa Ziehau olen = pkt->rm_len; 2984dc13fee6SSepherosa Ziehau pkt->rm_len = roundup2(olen, txr->hn_agg_align); 2985dc13fee6SSepherosa Ziehau agg_txd->chim_size += pkt->rm_len - olen; 2986dc13fee6SSepherosa Ziehau 2987dc13fee6SSepherosa Ziehau /* Link this txdesc to the parent. */ 2988dc13fee6SSepherosa Ziehau hn_txdesc_agg(agg_txd, txd); 2989dc13fee6SSepherosa Ziehau 2990dc13fee6SSepherosa Ziehau chim = (uint8_t *)pkt + pkt->rm_len; 2991dc13fee6SSepherosa Ziehau /* Save the current packet for later fixup. */ 2992dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 2993dc13fee6SSepherosa Ziehau 2994dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft--; 2995dc13fee6SSepherosa Ziehau txr->hn_agg_szleft -= pktsize; 2996dc13fee6SSepherosa Ziehau if (txr->hn_agg_szleft <= 2997dc13fee6SSepherosa Ziehau HN_PKTSIZE_MIN(txr->hn_agg_align)) { 2998dc13fee6SSepherosa Ziehau /* 2999dc13fee6SSepherosa Ziehau * Probably can't aggregate more packets, 3000dc13fee6SSepherosa Ziehau * flush this aggregating txdesc proactively. 3001dc13fee6SSepherosa Ziehau */ 3002dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 3003dc13fee6SSepherosa Ziehau } 3004dc13fee6SSepherosa Ziehau /* Done! */ 3005dc13fee6SSepherosa Ziehau return (chim); 3006dc13fee6SSepherosa Ziehau } 3007dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 3008dc13fee6SSepherosa Ziehau } 3009dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 3010dc13fee6SSepherosa Ziehau 3011dc13fee6SSepherosa Ziehau txr->hn_tx_chimney_tried++; 3012dc13fee6SSepherosa Ziehau txd->chim_index = hn_chim_alloc(txr->hn_sc); 3013dc13fee6SSepherosa Ziehau if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID) 3014dc13fee6SSepherosa Ziehau return (NULL); 3015dc13fee6SSepherosa Ziehau txr->hn_tx_chimney++; 3016dc13fee6SSepherosa Ziehau 3017dc13fee6SSepherosa Ziehau chim = txr->hn_sc->hn_chim + 3018dc13fee6SSepherosa Ziehau (txd->chim_index * txr->hn_sc->hn_chim_szmax); 3019dc13fee6SSepherosa Ziehau 3020dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktmax > 1 && 3021dc13fee6SSepherosa Ziehau txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) { 3022dc13fee6SSepherosa Ziehau txr->hn_agg_txd = txd; 3023dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1; 3024dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize; 3025dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 3026dc13fee6SSepherosa Ziehau } 3027dc13fee6SSepherosa Ziehau return (chim); 3028dc13fee6SSepherosa Ziehau } 3029dc13fee6SSepherosa Ziehau 303015516c77SSepherosa Ziehau /* 303115516c77SSepherosa Ziehau * NOTE: 303215516c77SSepherosa Ziehau * If this function fails, then both txd and m_head0 will be freed. 303315516c77SSepherosa Ziehau */ 303415516c77SSepherosa Ziehau static int 3035dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 3036dc13fee6SSepherosa Ziehau struct mbuf **m_head0) 303715516c77SSepherosa Ziehau { 303815516c77SSepherosa Ziehau bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX]; 303915516c77SSepherosa Ziehau int error, nsegs, i; 304015516c77SSepherosa Ziehau struct mbuf *m_head = *m_head0; 304115516c77SSepherosa Ziehau struct rndis_packet_msg *pkt; 304215516c77SSepherosa Ziehau uint32_t *pi_data; 30438966e5d5SSepherosa Ziehau void *chim = NULL; 3044dc13fee6SSepherosa Ziehau int pkt_hlen, pkt_size; 304515516c77SSepherosa Ziehau 304615516c77SSepherosa Ziehau pkt = txd->rndis_pkt; 3047dc13fee6SSepherosa Ziehau pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align); 3048dc13fee6SSepherosa Ziehau if (pkt_size < txr->hn_chim_size) { 3049dc13fee6SSepherosa Ziehau chim = hn_try_txagg(ifp, txr, txd, pkt_size); 3050dc13fee6SSepherosa Ziehau if (chim != NULL) 30518966e5d5SSepherosa Ziehau pkt = chim; 3052dc13fee6SSepherosa Ziehau } else { 3053dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 3054dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 30558966e5d5SSepherosa Ziehau } 30568966e5d5SSepherosa Ziehau 305715516c77SSepherosa Ziehau pkt->rm_type = REMOTE_NDIS_PACKET_MSG; 30588fe90f73SSepherosa Ziehau pkt->rm_len = m_head->m_pkthdr.len; 30599130c4f7SSepherosa Ziehau pkt->rm_dataoffset = 0; 306015516c77SSepherosa Ziehau pkt->rm_datalen = m_head->m_pkthdr.len; 3061dc13fee6SSepherosa Ziehau pkt->rm_oobdataoffset = 0; 3062dc13fee6SSepherosa Ziehau pkt->rm_oobdatalen = 0; 3063dc13fee6SSepherosa Ziehau pkt->rm_oobdataelements = 0; 306415516c77SSepherosa Ziehau pkt->rm_pktinfooffset = sizeof(*pkt); 306515516c77SSepherosa Ziehau pkt->rm_pktinfolen = 0; 3066dc13fee6SSepherosa Ziehau pkt->rm_vchandle = 0; 3067dc13fee6SSepherosa Ziehau pkt->rm_reserved = 0; 306815516c77SSepherosa Ziehau 306915516c77SSepherosa Ziehau if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) { 307015516c77SSepherosa Ziehau /* 307115516c77SSepherosa Ziehau * Set the hash value for this packet, so that the host could 307215516c77SSepherosa Ziehau * dispatch the TX done event for this packet back to this TX 307315516c77SSepherosa Ziehau * ring's channel. 307415516c77SSepherosa Ziehau */ 307515516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 307615516c77SSepherosa Ziehau HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL); 307715516c77SSepherosa Ziehau *pi_data = txr->hn_tx_idx; 307815516c77SSepherosa Ziehau } 307915516c77SSepherosa Ziehau 308015516c77SSepherosa Ziehau if (m_head->m_flags & M_VLANTAG) { 308115516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 308215516c77SSepherosa Ziehau NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN); 308315516c77SSepherosa Ziehau *pi_data = NDIS_VLAN_INFO_MAKE( 308415516c77SSepherosa Ziehau EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag), 308515516c77SSepherosa Ziehau EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag), 308615516c77SSepherosa Ziehau EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag)); 308715516c77SSepherosa Ziehau } 308815516c77SSepherosa Ziehau 308915516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 309015516c77SSepherosa Ziehau #if defined(INET6) || defined(INET) 309115516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 309215516c77SSepherosa Ziehau NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); 309315516c77SSepherosa Ziehau #ifdef INET 309415516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 3095c49d47daSSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV4( 3096c49d47daSSepherosa Ziehau m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen, 309715516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 309815516c77SSepherosa Ziehau } 309915516c77SSepherosa Ziehau #endif 310015516c77SSepherosa Ziehau #if defined(INET6) && defined(INET) 310115516c77SSepherosa Ziehau else 310215516c77SSepherosa Ziehau #endif 310315516c77SSepherosa Ziehau #ifdef INET6 310415516c77SSepherosa Ziehau { 3105c49d47daSSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV6( 3106c49d47daSSepherosa Ziehau m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen, 310715516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 310815516c77SSepherosa Ziehau } 310915516c77SSepherosa Ziehau #endif 311015516c77SSepherosa Ziehau #endif /* INET6 || INET */ 311115516c77SSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) { 311215516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 311315516c77SSepherosa Ziehau NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); 311415516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & 311515516c77SSepherosa Ziehau (CSUM_IP6_TCP | CSUM_IP6_UDP)) { 311615516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV6; 311715516c77SSepherosa Ziehau } else { 311815516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV4; 311915516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 312015516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_IPCS; 312115516c77SSepherosa Ziehau } 312215516c77SSepherosa Ziehau 3123c49d47daSSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & 3124c49d47daSSepherosa Ziehau (CSUM_IP_TCP | CSUM_IP6_TCP)) { 3125c49d47daSSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_MKTCPCS( 3126c49d47daSSepherosa Ziehau m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen); 3127c49d47daSSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & 3128c49d47daSSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP6_UDP)) { 3129c49d47daSSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_MKUDPCS( 3130c49d47daSSepherosa Ziehau m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen); 3131c49d47daSSepherosa Ziehau } 313215516c77SSepherosa Ziehau } 313315516c77SSepherosa Ziehau 3134dc13fee6SSepherosa Ziehau pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; 31358fe90f73SSepherosa Ziehau /* Fixup RNDIS packet message total length */ 31368fe90f73SSepherosa Ziehau pkt->rm_len += pkt_hlen; 313715516c77SSepherosa Ziehau /* Convert RNDIS packet message offsets */ 31389130c4f7SSepherosa Ziehau pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen); 313915516c77SSepherosa Ziehau pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset); 314015516c77SSepherosa Ziehau 314115516c77SSepherosa Ziehau /* 31428966e5d5SSepherosa Ziehau * Fast path: Chimney sending. 314315516c77SSepherosa Ziehau */ 31448966e5d5SSepherosa Ziehau if (chim != NULL) { 3145dc13fee6SSepherosa Ziehau struct hn_txdesc *tgt_txd = txd; 3146dc13fee6SSepherosa Ziehau 3147dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 3148dc13fee6SSepherosa Ziehau tgt_txd = txr->hn_agg_txd; 3149dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 3150dc13fee6SSepherosa Ziehau *m_head0 = NULL; 3151dc13fee6SSepherosa Ziehau #endif 3152dc13fee6SSepherosa Ziehau } 3153dc13fee6SSepherosa Ziehau 3154dc13fee6SSepherosa Ziehau KASSERT(pkt == chim, 3155dc13fee6SSepherosa Ziehau ("RNDIS pkt not in chimney sending buffer")); 3156dc13fee6SSepherosa Ziehau KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID, 3157dc13fee6SSepherosa Ziehau ("chimney sending buffer is not used")); 3158dc13fee6SSepherosa Ziehau tgt_txd->chim_size += pkt->rm_len; 315915516c77SSepherosa Ziehau 31608966e5d5SSepherosa Ziehau m_copydata(m_head, 0, m_head->m_pkthdr.len, 3161dc13fee6SSepherosa Ziehau ((uint8_t *)chim) + pkt_hlen); 316215516c77SSepherosa Ziehau 316315516c77SSepherosa Ziehau txr->hn_gpa_cnt = 0; 316415516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_chim; 316515516c77SSepherosa Ziehau goto done; 316615516c77SSepherosa Ziehau } 3167dc13fee6SSepherosa Ziehau 3168dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc")); 31698966e5d5SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 31708966e5d5SSepherosa Ziehau ("chimney buffer is used")); 31718966e5d5SSepherosa Ziehau KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc")); 317215516c77SSepherosa Ziehau 317315516c77SSepherosa Ziehau error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs); 3174dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 317515516c77SSepherosa Ziehau int freed; 317615516c77SSepherosa Ziehau 317715516c77SSepherosa Ziehau /* 317815516c77SSepherosa Ziehau * This mbuf is not linked w/ the txd yet, so free it now. 317915516c77SSepherosa Ziehau */ 318015516c77SSepherosa Ziehau m_freem(m_head); 318115516c77SSepherosa Ziehau *m_head0 = NULL; 318215516c77SSepherosa Ziehau 318315516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 318415516c77SSepherosa Ziehau KASSERT(freed != 0, 318515516c77SSepherosa Ziehau ("fail to free txd upon txdma error")); 318615516c77SSepherosa Ziehau 318715516c77SSepherosa Ziehau txr->hn_txdma_failed++; 3188dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 318915516c77SSepherosa Ziehau return error; 319015516c77SSepherosa Ziehau } 319115516c77SSepherosa Ziehau *m_head0 = m_head; 319215516c77SSepherosa Ziehau 319315516c77SSepherosa Ziehau /* +1 RNDIS packet message */ 319415516c77SSepherosa Ziehau txr->hn_gpa_cnt = nsegs + 1; 319515516c77SSepherosa Ziehau 319615516c77SSepherosa Ziehau /* send packet with page buffer */ 319715516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr); 319815516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK; 3199dc13fee6SSepherosa Ziehau txr->hn_gpa[0].gpa_len = pkt_hlen; 320015516c77SSepherosa Ziehau 320115516c77SSepherosa Ziehau /* 320215516c77SSepherosa Ziehau * Fill the page buffers with mbuf info after the page 320315516c77SSepherosa Ziehau * buffer for RNDIS packet message. 320415516c77SSepherosa Ziehau */ 320515516c77SSepherosa Ziehau for (i = 0; i < nsegs; ++i) { 320615516c77SSepherosa Ziehau struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1]; 320715516c77SSepherosa Ziehau 320815516c77SSepherosa Ziehau gpa->gpa_page = atop(segs[i].ds_addr); 320915516c77SSepherosa Ziehau gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK; 321015516c77SSepherosa Ziehau gpa->gpa_len = segs[i].ds_len; 321115516c77SSepherosa Ziehau } 321215516c77SSepherosa Ziehau 321315516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 321415516c77SSepherosa Ziehau txd->chim_size = 0; 321515516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_sglist; 321615516c77SSepherosa Ziehau done: 321715516c77SSepherosa Ziehau txd->m = m_head; 321815516c77SSepherosa Ziehau 321915516c77SSepherosa Ziehau /* Set the completion routine */ 322015516c77SSepherosa Ziehau hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd); 322115516c77SSepherosa Ziehau 3222dc13fee6SSepherosa Ziehau /* Update temporary stats for later use. */ 3223dc13fee6SSepherosa Ziehau txr->hn_stat_pkts++; 3224dc13fee6SSepherosa Ziehau txr->hn_stat_size += m_head->m_pkthdr.len; 3225dc13fee6SSepherosa Ziehau if (m_head->m_flags & M_MCAST) 3226dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts++; 3227dc13fee6SSepherosa Ziehau 322815516c77SSepherosa Ziehau return 0; 322915516c77SSepherosa Ziehau } 323015516c77SSepherosa Ziehau 323115516c77SSepherosa Ziehau /* 323215516c77SSepherosa Ziehau * NOTE: 323315516c77SSepherosa Ziehau * If this function fails, then txd will be freed, but the mbuf 323415516c77SSepherosa Ziehau * associated w/ the txd will _not_ be freed. 323515516c77SSepherosa Ziehau */ 323615516c77SSepherosa Ziehau static int 323715516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd) 323815516c77SSepherosa Ziehau { 32398e7d3136SSepherosa Ziehau int error, send_failed = 0, has_bpf; 324015516c77SSepherosa Ziehau 324115516c77SSepherosa Ziehau again: 32428e7d3136SSepherosa Ziehau has_bpf = bpf_peers_present(ifp->if_bpf); 32438e7d3136SSepherosa Ziehau if (has_bpf) { 324415516c77SSepherosa Ziehau /* 32458e7d3136SSepherosa Ziehau * Make sure that this txd and any aggregated txds are not 32468e7d3136SSepherosa Ziehau * freed before ETHER_BPF_MTAP. 324715516c77SSepherosa Ziehau */ 324815516c77SSepherosa Ziehau hn_txdesc_hold(txd); 32498e7d3136SSepherosa Ziehau } 325015516c77SSepherosa Ziehau error = txr->hn_sendpkt(txr, txd); 325115516c77SSepherosa Ziehau if (!error) { 32528e7d3136SSepherosa Ziehau if (has_bpf) { 3253dc13fee6SSepherosa Ziehau const struct hn_txdesc *tmp_txd; 3254dc13fee6SSepherosa Ziehau 325515516c77SSepherosa Ziehau ETHER_BPF_MTAP(ifp, txd->m); 3256dc13fee6SSepherosa Ziehau STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link) 3257dc13fee6SSepherosa Ziehau ETHER_BPF_MTAP(ifp, tmp_txd->m); 3258dc13fee6SSepherosa Ziehau } 3259dc13fee6SSepherosa Ziehau 3260dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts); 326123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 326223bf9e15SSepherosa Ziehau if (!hn_use_if_start) 326323bf9e15SSepherosa Ziehau #endif 326423bf9e15SSepherosa Ziehau { 326515516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, 3266dc13fee6SSepherosa Ziehau txr->hn_stat_size); 3267dc13fee6SSepherosa Ziehau if (txr->hn_stat_mcasts != 0) { 3268dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 3269dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts); 327015516c77SSepherosa Ziehau } 3271dc13fee6SSepherosa Ziehau } 3272dc13fee6SSepherosa Ziehau txr->hn_pkts += txr->hn_stat_pkts; 3273dc13fee6SSepherosa Ziehau txr->hn_sends++; 327415516c77SSepherosa Ziehau } 32758e7d3136SSepherosa Ziehau if (has_bpf) 327615516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 327715516c77SSepherosa Ziehau 327815516c77SSepherosa Ziehau if (__predict_false(error)) { 327915516c77SSepherosa Ziehau int freed; 328015516c77SSepherosa Ziehau 328115516c77SSepherosa Ziehau /* 328215516c77SSepherosa Ziehau * This should "really rarely" happen. 328315516c77SSepherosa Ziehau * 328415516c77SSepherosa Ziehau * XXX Too many RX to be acked or too many sideband 328515516c77SSepherosa Ziehau * commands to run? Ask netvsc_channel_rollup() 328615516c77SSepherosa Ziehau * to kick start later. 328715516c77SSepherosa Ziehau */ 328815516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 328915516c77SSepherosa Ziehau if (!send_failed) { 329015516c77SSepherosa Ziehau txr->hn_send_failed++; 329115516c77SSepherosa Ziehau send_failed = 1; 329215516c77SSepherosa Ziehau /* 329315516c77SSepherosa Ziehau * Try sending again after set hn_has_txeof; 329415516c77SSepherosa Ziehau * in case that we missed the last 329515516c77SSepherosa Ziehau * netvsc_channel_rollup(). 329615516c77SSepherosa Ziehau */ 329715516c77SSepherosa Ziehau goto again; 329815516c77SSepherosa Ziehau } 329915516c77SSepherosa Ziehau if_printf(ifp, "send failed\n"); 330015516c77SSepherosa Ziehau 330115516c77SSepherosa Ziehau /* 330215516c77SSepherosa Ziehau * Caller will perform further processing on the 330315516c77SSepherosa Ziehau * associated mbuf, so don't free it in hn_txdesc_put(); 330415516c77SSepherosa Ziehau * only unload it from the DMA map in hn_txdesc_put(), 330515516c77SSepherosa Ziehau * if it was loaded. 330615516c77SSepherosa Ziehau */ 330715516c77SSepherosa Ziehau txd->m = NULL; 330815516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 330915516c77SSepherosa Ziehau KASSERT(freed != 0, 331015516c77SSepherosa Ziehau ("fail to free txd upon send error")); 331115516c77SSepherosa Ziehau 331215516c77SSepherosa Ziehau txr->hn_send_failed++; 331315516c77SSepherosa Ziehau } 3314dc13fee6SSepherosa Ziehau 3315dc13fee6SSepherosa Ziehau /* Reset temporary stats, after this sending is done. */ 3316dc13fee6SSepherosa Ziehau txr->hn_stat_size = 0; 3317dc13fee6SSepherosa Ziehau txr->hn_stat_pkts = 0; 3318dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts = 0; 3319dc13fee6SSepherosa Ziehau 3320dc13fee6SSepherosa Ziehau return (error); 332115516c77SSepherosa Ziehau } 332215516c77SSepherosa Ziehau 332315516c77SSepherosa Ziehau /* 332415516c77SSepherosa Ziehau * Append the specified data to the indicated mbuf chain, 332515516c77SSepherosa Ziehau * Extend the mbuf chain if the new data does not fit in 332615516c77SSepherosa Ziehau * existing space. 332715516c77SSepherosa Ziehau * 332815516c77SSepherosa Ziehau * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c. 332915516c77SSepherosa Ziehau * There should be an equivalent in the kernel mbuf code, 333015516c77SSepherosa Ziehau * but there does not appear to be one yet. 333115516c77SSepherosa Ziehau * 333215516c77SSepherosa Ziehau * Differs from m_append() in that additional mbufs are 333315516c77SSepherosa Ziehau * allocated with cluster size MJUMPAGESIZE, and filled 333415516c77SSepherosa Ziehau * accordingly. 333515516c77SSepherosa Ziehau * 333615516c77SSepherosa Ziehau * Return 1 if able to complete the job; otherwise 0. 333715516c77SSepherosa Ziehau */ 333815516c77SSepherosa Ziehau static int 333915516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp) 334015516c77SSepherosa Ziehau { 334115516c77SSepherosa Ziehau struct mbuf *m, *n; 334215516c77SSepherosa Ziehau int remainder, space; 334315516c77SSepherosa Ziehau 334415516c77SSepherosa Ziehau for (m = m0; m->m_next != NULL; m = m->m_next) 334515516c77SSepherosa Ziehau ; 334615516c77SSepherosa Ziehau remainder = len; 334715516c77SSepherosa Ziehau space = M_TRAILINGSPACE(m); 334815516c77SSepherosa Ziehau if (space > 0) { 334915516c77SSepherosa Ziehau /* 335015516c77SSepherosa Ziehau * Copy into available space. 335115516c77SSepherosa Ziehau */ 335215516c77SSepherosa Ziehau if (space > remainder) 335315516c77SSepherosa Ziehau space = remainder; 335415516c77SSepherosa Ziehau bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 335515516c77SSepherosa Ziehau m->m_len += space; 335615516c77SSepherosa Ziehau cp += space; 335715516c77SSepherosa Ziehau remainder -= space; 335815516c77SSepherosa Ziehau } 335915516c77SSepherosa Ziehau while (remainder > 0) { 336015516c77SSepherosa Ziehau /* 336115516c77SSepherosa Ziehau * Allocate a new mbuf; could check space 336215516c77SSepherosa Ziehau * and allocate a cluster instead. 336315516c77SSepherosa Ziehau */ 336415516c77SSepherosa Ziehau n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE); 336515516c77SSepherosa Ziehau if (n == NULL) 336615516c77SSepherosa Ziehau break; 336715516c77SSepherosa Ziehau n->m_len = min(MJUMPAGESIZE, remainder); 336815516c77SSepherosa Ziehau bcopy(cp, mtod(n, caddr_t), n->m_len); 336915516c77SSepherosa Ziehau cp += n->m_len; 337015516c77SSepherosa Ziehau remainder -= n->m_len; 337115516c77SSepherosa Ziehau m->m_next = n; 337215516c77SSepherosa Ziehau m = n; 337315516c77SSepherosa Ziehau } 337415516c77SSepherosa Ziehau if (m0->m_flags & M_PKTHDR) 337515516c77SSepherosa Ziehau m0->m_pkthdr.len += len - remainder; 337615516c77SSepherosa Ziehau 337715516c77SSepherosa Ziehau return (remainder == 0); 337815516c77SSepherosa Ziehau } 337915516c77SSepherosa Ziehau 338015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 338115516c77SSepherosa Ziehau static __inline int 338215516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m) 338315516c77SSepherosa Ziehau { 338415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 338515516c77SSepherosa Ziehau if (hn_lro_mbufq_depth) { 338615516c77SSepherosa Ziehau tcp_lro_queue_mbuf(lc, m); 338715516c77SSepherosa Ziehau return 0; 338815516c77SSepherosa Ziehau } 338915516c77SSepherosa Ziehau #endif 339015516c77SSepherosa Ziehau return tcp_lro_rx(lc, m, 0); 339115516c77SSepherosa Ziehau } 339215516c77SSepherosa Ziehau #endif 339315516c77SSepherosa Ziehau 339415516c77SSepherosa Ziehau static int 339515516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, 339615516c77SSepherosa Ziehau const struct hn_rxinfo *info) 339715516c77SSepherosa Ziehau { 3398a97fff19SSepherosa Ziehau struct ifnet *ifp, *hn_ifp = rxr->hn_ifp; 339915516c77SSepherosa Ziehau struct mbuf *m_new; 3400642ec226SSepherosa Ziehau int size, do_lro = 0, do_csum = 1, is_vf = 0; 3401642ec226SSepherosa Ziehau int hash_type = M_HASHTYPE_NONE; 3402db76829bSSepherosa Ziehau int l3proto = ETHERTYPE_MAX, l4proto = IPPROTO_DONE; 340315516c77SSepherosa Ziehau 3404642ec226SSepherosa Ziehau ifp = hn_ifp; 3405642ec226SSepherosa Ziehau if (rxr->hn_rxvf_ifp != NULL) { 3406a97fff19SSepherosa Ziehau /* 3407642ec226SSepherosa Ziehau * Non-transparent mode VF; pretend this packet is from 3408642ec226SSepherosa Ziehau * the VF. 3409a97fff19SSepherosa Ziehau */ 3410642ec226SSepherosa Ziehau ifp = rxr->hn_rxvf_ifp; 3411642ec226SSepherosa Ziehau is_vf = 1; 3412642ec226SSepherosa Ziehau } else if (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF) { 3413642ec226SSepherosa Ziehau /* Transparent mode VF. */ 3414642ec226SSepherosa Ziehau is_vf = 1; 3415642ec226SSepherosa Ziehau } 34165bdfd3fdSDexuan Cui 3417b3b75d9cSSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 3418b3b75d9cSSepherosa Ziehau /* 3419b3b75d9cSSepherosa Ziehau * NOTE: 3420b3b75d9cSSepherosa Ziehau * See the NOTE of hn_rndis_init_fixat(). This 3421b3b75d9cSSepherosa Ziehau * function can be reached, immediately after the 3422b3b75d9cSSepherosa Ziehau * RNDIS is initialized but before the ifnet is 3423b3b75d9cSSepherosa Ziehau * setup on the hn_attach() path; drop the unexpected 3424b3b75d9cSSepherosa Ziehau * packets. 3425b3b75d9cSSepherosa Ziehau */ 3426b3b75d9cSSepherosa Ziehau return (0); 3427b3b75d9cSSepherosa Ziehau } 3428b3b75d9cSSepherosa Ziehau 3429a97fff19SSepherosa Ziehau if (__predict_false(dlen < ETHER_HDR_LEN)) { 3430a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1); 3431a97fff19SSepherosa Ziehau return (0); 3432a97fff19SSepherosa Ziehau } 3433a97fff19SSepherosa Ziehau 3434c927d681SDexuan Cui if (dlen <= MHLEN) { 343515516c77SSepherosa Ziehau m_new = m_gethdr(M_NOWAIT, MT_DATA); 343615516c77SSepherosa Ziehau if (m_new == NULL) { 3437a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1); 343815516c77SSepherosa Ziehau return (0); 343915516c77SSepherosa Ziehau } 344015516c77SSepherosa Ziehau memcpy(mtod(m_new, void *), data, dlen); 344115516c77SSepherosa Ziehau m_new->m_pkthdr.len = m_new->m_len = dlen; 344215516c77SSepherosa Ziehau rxr->hn_small_pkts++; 344315516c77SSepherosa Ziehau } else { 344415516c77SSepherosa Ziehau /* 344515516c77SSepherosa Ziehau * Get an mbuf with a cluster. For packets 2K or less, 344615516c77SSepherosa Ziehau * get a standard 2K cluster. For anything larger, get a 344715516c77SSepherosa Ziehau * 4K cluster. Any buffers larger than 4K can cause problems 344815516c77SSepherosa Ziehau * if looped around to the Hyper-V TX channel, so avoid them. 344915516c77SSepherosa Ziehau */ 345015516c77SSepherosa Ziehau size = MCLBYTES; 345115516c77SSepherosa Ziehau if (dlen > MCLBYTES) { 345215516c77SSepherosa Ziehau /* 4096 */ 345315516c77SSepherosa Ziehau size = MJUMPAGESIZE; 345415516c77SSepherosa Ziehau } 345515516c77SSepherosa Ziehau 345615516c77SSepherosa Ziehau m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size); 345715516c77SSepherosa Ziehau if (m_new == NULL) { 3458a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1); 345915516c77SSepherosa Ziehau return (0); 346015516c77SSepherosa Ziehau } 346115516c77SSepherosa Ziehau 346215516c77SSepherosa Ziehau hv_m_append(m_new, dlen, data); 346315516c77SSepherosa Ziehau } 346415516c77SSepherosa Ziehau m_new->m_pkthdr.rcvif = ifp; 346515516c77SSepherosa Ziehau 3466a97fff19SSepherosa Ziehau if (__predict_false((hn_ifp->if_capenable & IFCAP_RXCSUM) == 0)) 346715516c77SSepherosa Ziehau do_csum = 0; 346815516c77SSepherosa Ziehau 346915516c77SSepherosa Ziehau /* receive side checksum offload */ 347015516c77SSepherosa Ziehau if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) { 347115516c77SSepherosa Ziehau /* IP csum offload */ 347215516c77SSepherosa Ziehau if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) { 347315516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 347415516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 347515516c77SSepherosa Ziehau rxr->hn_csum_ip++; 347615516c77SSepherosa Ziehau } 347715516c77SSepherosa Ziehau 347815516c77SSepherosa Ziehau /* TCP/UDP csum offload */ 347915516c77SSepherosa Ziehau if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK | 348015516c77SSepherosa Ziehau NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) { 348115516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 348215516c77SSepherosa Ziehau (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 348315516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 348415516c77SSepherosa Ziehau if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK) 348515516c77SSepherosa Ziehau rxr->hn_csum_tcp++; 348615516c77SSepherosa Ziehau else 348715516c77SSepherosa Ziehau rxr->hn_csum_udp++; 348815516c77SSepherosa Ziehau } 348915516c77SSepherosa Ziehau 349015516c77SSepherosa Ziehau /* 349115516c77SSepherosa Ziehau * XXX 349215516c77SSepherosa Ziehau * As of this write (Oct 28th, 2016), host side will turn 349315516c77SSepherosa Ziehau * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so 349415516c77SSepherosa Ziehau * the do_lro setting here is actually _not_ accurate. We 349515516c77SSepherosa Ziehau * depend on the RSS hash type check to reset do_lro. 349615516c77SSepherosa Ziehau */ 349715516c77SSepherosa Ziehau if ((info->csum_info & 349815516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) == 349915516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) 350015516c77SSepherosa Ziehau do_lro = 1; 350115516c77SSepherosa Ziehau } else { 3502db76829bSSepherosa Ziehau hn_rxpkt_proto(m_new, &l3proto, &l4proto); 3503db76829bSSepherosa Ziehau if (l3proto == ETHERTYPE_IP) { 3504db76829bSSepherosa Ziehau if (l4proto == IPPROTO_TCP) { 350515516c77SSepherosa Ziehau if (do_csum && 350615516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 350715516c77SSepherosa Ziehau HN_TRUST_HCSUM_TCP)) { 350815516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 350915516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 351015516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 351115516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 351215516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 351315516c77SSepherosa Ziehau } 351415516c77SSepherosa Ziehau do_lro = 1; 3515db76829bSSepherosa Ziehau } else if (l4proto == IPPROTO_UDP) { 351615516c77SSepherosa Ziehau if (do_csum && 351715516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 351815516c77SSepherosa Ziehau HN_TRUST_HCSUM_UDP)) { 351915516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 352015516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 352115516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 352215516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 352315516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 352415516c77SSepherosa Ziehau } 3525db76829bSSepherosa Ziehau } else if (l4proto != IPPROTO_DONE && do_csum && 352615516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) { 352715516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 352815516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 352915516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 353015516c77SSepherosa Ziehau } 353115516c77SSepherosa Ziehau } 353215516c77SSepherosa Ziehau } 3533db76829bSSepherosa Ziehau 353415516c77SSepherosa Ziehau if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) { 353515516c77SSepherosa Ziehau m_new->m_pkthdr.ether_vtag = EVL_MAKETAG( 353615516c77SSepherosa Ziehau NDIS_VLAN_INFO_ID(info->vlan_info), 353715516c77SSepherosa Ziehau NDIS_VLAN_INFO_PRI(info->vlan_info), 353815516c77SSepherosa Ziehau NDIS_VLAN_INFO_CFI(info->vlan_info)); 353915516c77SSepherosa Ziehau m_new->m_flags |= M_VLANTAG; 354015516c77SSepherosa Ziehau } 354115516c77SSepherosa Ziehau 3542a97fff19SSepherosa Ziehau /* 3543a97fff19SSepherosa Ziehau * If VF is activated (tranparent/non-transparent mode does not 3544a97fff19SSepherosa Ziehau * matter here). 3545a97fff19SSepherosa Ziehau * 3546a97fff19SSepherosa Ziehau * - Disable LRO 3547a97fff19SSepherosa Ziehau * 3548a97fff19SSepherosa Ziehau * hn(4) will only receive broadcast packets, multicast packets, 3549a97fff19SSepherosa Ziehau * TCP SYN and SYN|ACK (in Azure), LRO is useless for these 3550a97fff19SSepherosa Ziehau * packet types. 3551a97fff19SSepherosa Ziehau * 3552a97fff19SSepherosa Ziehau * For non-transparent, we definitely _cannot_ enable LRO at 3553a97fff19SSepherosa Ziehau * all, since the LRO flush will use hn(4) as the receiving 3554a97fff19SSepherosa Ziehau * interface; i.e. hn_ifp->if_input(hn_ifp, m). 3555a97fff19SSepherosa Ziehau */ 3556642ec226SSepherosa Ziehau if (is_vf) 3557642ec226SSepherosa Ziehau do_lro = 0; 3558a97fff19SSepherosa Ziehau 3559642ec226SSepherosa Ziehau /* 3560642ec226SSepherosa Ziehau * If VF is activated (tranparent/non-transparent mode does not 3561642ec226SSepherosa Ziehau * matter here), do _not_ mess with unsupported hash types or 3562642ec226SSepherosa Ziehau * functions. 3563642ec226SSepherosa Ziehau */ 356415516c77SSepherosa Ziehau if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) { 356515516c77SSepherosa Ziehau rxr->hn_rss_pkts++; 356615516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = info->hash_value; 3567642ec226SSepherosa Ziehau if (!is_vf) 356815516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE_HASH; 356915516c77SSepherosa Ziehau if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) == 357015516c77SSepherosa Ziehau NDIS_HASH_FUNCTION_TOEPLITZ) { 3571642ec226SSepherosa Ziehau uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK & 3572642ec226SSepherosa Ziehau rxr->hn_mbuf_hash); 357315516c77SSepherosa Ziehau 357415516c77SSepherosa Ziehau /* 357515516c77SSepherosa Ziehau * NOTE: 357615516c77SSepherosa Ziehau * do_lro is resetted, if the hash types are not TCP 357715516c77SSepherosa Ziehau * related. See the comment in the above csum_flags 357815516c77SSepherosa Ziehau * setup section. 357915516c77SSepherosa Ziehau */ 358015516c77SSepherosa Ziehau switch (type) { 358115516c77SSepherosa Ziehau case NDIS_HASH_IPV4: 358215516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV4; 358315516c77SSepherosa Ziehau do_lro = 0; 358415516c77SSepherosa Ziehau break; 358515516c77SSepherosa Ziehau 358615516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV4: 358715516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV4; 3588db76829bSSepherosa Ziehau if (rxr->hn_rx_flags & HN_RX_FLAG_UDP_HASH) { 3589db76829bSSepherosa Ziehau int def_htype = M_HASHTYPE_OPAQUE_HASH; 3590db76829bSSepherosa Ziehau 3591db76829bSSepherosa Ziehau if (is_vf) 3592db76829bSSepherosa Ziehau def_htype = M_HASHTYPE_NONE; 3593db76829bSSepherosa Ziehau 3594db76829bSSepherosa Ziehau /* 3595db76829bSSepherosa Ziehau * UDP 4-tuple hash is delivered as 3596db76829bSSepherosa Ziehau * TCP 4-tuple hash. 3597db76829bSSepherosa Ziehau */ 3598db76829bSSepherosa Ziehau if (l3proto == ETHERTYPE_MAX) { 3599db76829bSSepherosa Ziehau hn_rxpkt_proto(m_new, 3600db76829bSSepherosa Ziehau &l3proto, &l4proto); 3601db76829bSSepherosa Ziehau } 3602db76829bSSepherosa Ziehau if (l3proto == ETHERTYPE_IP) { 36036f12c42eSSepherosa Ziehau if (l4proto == IPPROTO_UDP && 36046f12c42eSSepherosa Ziehau (rxr->hn_mbuf_hash & 36056f12c42eSSepherosa Ziehau NDIS_HASH_UDP_IPV4_X)) { 3606db76829bSSepherosa Ziehau hash_type = 3607db76829bSSepherosa Ziehau M_HASHTYPE_RSS_UDP_IPV4; 3608db76829bSSepherosa Ziehau do_lro = 0; 3609db76829bSSepherosa Ziehau } else if (l4proto != 3610db76829bSSepherosa Ziehau IPPROTO_TCP) { 3611db76829bSSepherosa Ziehau hash_type = def_htype; 3612db76829bSSepherosa Ziehau do_lro = 0; 3613db76829bSSepherosa Ziehau } 3614db76829bSSepherosa Ziehau } else { 3615db76829bSSepherosa Ziehau hash_type = def_htype; 3616db76829bSSepherosa Ziehau do_lro = 0; 3617db76829bSSepherosa Ziehau } 3618db76829bSSepherosa Ziehau } 361915516c77SSepherosa Ziehau break; 362015516c77SSepherosa Ziehau 362115516c77SSepherosa Ziehau case NDIS_HASH_IPV6: 362215516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6; 362315516c77SSepherosa Ziehau do_lro = 0; 362415516c77SSepherosa Ziehau break; 362515516c77SSepherosa Ziehau 362615516c77SSepherosa Ziehau case NDIS_HASH_IPV6_EX: 362715516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6_EX; 362815516c77SSepherosa Ziehau do_lro = 0; 362915516c77SSepherosa Ziehau break; 363015516c77SSepherosa Ziehau 363115516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6: 363215516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6; 363315516c77SSepherosa Ziehau break; 363415516c77SSepherosa Ziehau 363515516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6_EX: 363615516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX; 363715516c77SSepherosa Ziehau break; 363815516c77SSepherosa Ziehau } 363915516c77SSepherosa Ziehau } 3640642ec226SSepherosa Ziehau } else if (!is_vf) { 364115516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = rxr->hn_rx_idx; 364215516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE; 364315516c77SSepherosa Ziehau } 364415516c77SSepherosa Ziehau M_HASHTYPE_SET(m_new, hash_type); 364515516c77SSepherosa Ziehau 3646a97fff19SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 3647a97fff19SSepherosa Ziehau if (hn_ifp != ifp) { 3648a97fff19SSepherosa Ziehau const struct ether_header *eh; 3649a97fff19SSepherosa Ziehau 365015516c77SSepherosa Ziehau /* 3651a97fff19SSepherosa Ziehau * Non-transparent mode VF is activated. 365215516c77SSepherosa Ziehau */ 365315516c77SSepherosa Ziehau 3654a97fff19SSepherosa Ziehau /* 3655a97fff19SSepherosa Ziehau * Allow tapping on hn(4). 3656a97fff19SSepherosa Ziehau */ 3657a97fff19SSepherosa Ziehau ETHER_BPF_MTAP(hn_ifp, m_new); 3658a97fff19SSepherosa Ziehau 3659a97fff19SSepherosa Ziehau /* 3660a97fff19SSepherosa Ziehau * Update hn(4)'s stats. 3661a97fff19SSepherosa Ziehau */ 3662a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1); 3663a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len); 3664a97fff19SSepherosa Ziehau /* Checked at the beginning of this function. */ 3665a97fff19SSepherosa Ziehau KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame")); 3666a97fff19SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 3667a97fff19SSepherosa Ziehau if (ETHER_IS_MULTICAST(eh->ether_dhost)) 3668a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1); 3669a97fff19SSepherosa Ziehau } 367015516c77SSepherosa Ziehau rxr->hn_pkts++; 367115516c77SSepherosa Ziehau 3672a97fff19SSepherosa Ziehau if ((hn_ifp->if_capenable & IFCAP_LRO) && do_lro) { 367315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 367415516c77SSepherosa Ziehau struct lro_ctrl *lro = &rxr->hn_lro; 367515516c77SSepherosa Ziehau 367615516c77SSepherosa Ziehau if (lro->lro_cnt) { 367715516c77SSepherosa Ziehau rxr->hn_lro_tried++; 367815516c77SSepherosa Ziehau if (hn_lro_rx(lro, m_new) == 0) { 367915516c77SSepherosa Ziehau /* DONE! */ 368015516c77SSepherosa Ziehau return 0; 368115516c77SSepherosa Ziehau } 368215516c77SSepherosa Ziehau } 368315516c77SSepherosa Ziehau #endif 368415516c77SSepherosa Ziehau } 3685a97fff19SSepherosa Ziehau ifp->if_input(ifp, m_new); 368615516c77SSepherosa Ziehau 368715516c77SSepherosa Ziehau return (0); 368815516c77SSepherosa Ziehau } 368915516c77SSepherosa Ziehau 369015516c77SSepherosa Ziehau static int 369115516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 369215516c77SSepherosa Ziehau { 369315516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 36949c6cae24SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data, ifr_vf; 36959c6cae24SSepherosa Ziehau struct ifnet *vf_ifp; 369615516c77SSepherosa Ziehau int mask, error = 0; 36978c068aa5SSepherosa Ziehau struct ifrsskey *ifrk; 36988c068aa5SSepherosa Ziehau struct ifrsshash *ifrh; 3699eb2fe044SSepherosa Ziehau uint32_t mtu; 370015516c77SSepherosa Ziehau 370115516c77SSepherosa Ziehau switch (cmd) { 370215516c77SSepherosa Ziehau case SIOCSIFMTU: 370315516c77SSepherosa Ziehau if (ifr->ifr_mtu > HN_MTU_MAX) { 370415516c77SSepherosa Ziehau error = EINVAL; 370515516c77SSepherosa Ziehau break; 370615516c77SSepherosa Ziehau } 370715516c77SSepherosa Ziehau 370815516c77SSepherosa Ziehau HN_LOCK(sc); 370915516c77SSepherosa Ziehau 371015516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 371115516c77SSepherosa Ziehau HN_UNLOCK(sc); 371215516c77SSepherosa Ziehau break; 371315516c77SSepherosa Ziehau } 371415516c77SSepherosa Ziehau 371515516c77SSepherosa Ziehau if ((sc->hn_caps & HN_CAP_MTU) == 0) { 371615516c77SSepherosa Ziehau /* Can't change MTU */ 371715516c77SSepherosa Ziehau HN_UNLOCK(sc); 371815516c77SSepherosa Ziehau error = EOPNOTSUPP; 371915516c77SSepherosa Ziehau break; 372015516c77SSepherosa Ziehau } 372115516c77SSepherosa Ziehau 372215516c77SSepherosa Ziehau if (ifp->if_mtu == ifr->ifr_mtu) { 372315516c77SSepherosa Ziehau HN_UNLOCK(sc); 372415516c77SSepherosa Ziehau break; 372515516c77SSepherosa Ziehau } 372615516c77SSepherosa Ziehau 37279c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 37289c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 37299c6cae24SSepherosa Ziehau ifr_vf = *ifr; 37309c6cae24SSepherosa Ziehau strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname, 37319c6cae24SSepherosa Ziehau sizeof(ifr_vf.ifr_name)); 37329c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, 37339c6cae24SSepherosa Ziehau (caddr_t)&ifr_vf); 37349c6cae24SSepherosa Ziehau if (error) { 37359c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 37369c6cae24SSepherosa Ziehau if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n", 37379c6cae24SSepherosa Ziehau vf_ifp->if_xname, ifr->ifr_mtu, error); 37389c6cae24SSepherosa Ziehau break; 37399c6cae24SSepherosa Ziehau } 37409c6cae24SSepherosa Ziehau } 37419c6cae24SSepherosa Ziehau 374215516c77SSepherosa Ziehau /* 374315516c77SSepherosa Ziehau * Suspend this interface before the synthetic parts 374415516c77SSepherosa Ziehau * are ripped. 374515516c77SSepherosa Ziehau */ 374615516c77SSepherosa Ziehau hn_suspend(sc); 374715516c77SSepherosa Ziehau 374815516c77SSepherosa Ziehau /* 374915516c77SSepherosa Ziehau * Detach the synthetics parts, i.e. NVS and RNDIS. 375015516c77SSepherosa Ziehau */ 375115516c77SSepherosa Ziehau hn_synth_detach(sc); 375215516c77SSepherosa Ziehau 375315516c77SSepherosa Ziehau /* 375415516c77SSepherosa Ziehau * Reattach the synthetic parts, i.e. NVS and RNDIS, 375515516c77SSepherosa Ziehau * with the new MTU setting. 375615516c77SSepherosa Ziehau */ 375715516c77SSepherosa Ziehau error = hn_synth_attach(sc, ifr->ifr_mtu); 375815516c77SSepherosa Ziehau if (error) { 375915516c77SSepherosa Ziehau HN_UNLOCK(sc); 376015516c77SSepherosa Ziehau break; 376115516c77SSepherosa Ziehau } 376215516c77SSepherosa Ziehau 3763eb2fe044SSepherosa Ziehau error = hn_rndis_get_mtu(sc, &mtu); 3764eb2fe044SSepherosa Ziehau if (error) 3765eb2fe044SSepherosa Ziehau mtu = ifr->ifr_mtu; 3766eb2fe044SSepherosa Ziehau else if (bootverbose) 3767eb2fe044SSepherosa Ziehau if_printf(ifp, "RNDIS mtu %u\n", mtu); 3768eb2fe044SSepherosa Ziehau 376915516c77SSepherosa Ziehau /* 377015516c77SSepherosa Ziehau * Commit the requested MTU, after the synthetic parts 377115516c77SSepherosa Ziehau * have been successfully attached. 377215516c77SSepherosa Ziehau */ 3773eb2fe044SSepherosa Ziehau if (mtu >= ifr->ifr_mtu) { 3774eb2fe044SSepherosa Ziehau mtu = ifr->ifr_mtu; 3775eb2fe044SSepherosa Ziehau } else { 3776eb2fe044SSepherosa Ziehau if_printf(ifp, "fixup mtu %d -> %u\n", 3777eb2fe044SSepherosa Ziehau ifr->ifr_mtu, mtu); 3778eb2fe044SSepherosa Ziehau } 3779eb2fe044SSepherosa Ziehau ifp->if_mtu = mtu; 378015516c77SSepherosa Ziehau 378115516c77SSepherosa Ziehau /* 37829c6cae24SSepherosa Ziehau * Synthetic parts' reattach may change the chimney 37839c6cae24SSepherosa Ziehau * sending size; update it. 378415516c77SSepherosa Ziehau */ 378515516c77SSepherosa Ziehau if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax) 378615516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 37879c6cae24SSepherosa Ziehau 37889c6cae24SSepherosa Ziehau /* 37899c6cae24SSepherosa Ziehau * Make sure that various parameters based on MTU are 37909c6cae24SSepherosa Ziehau * still valid, after the MTU change. 37919c6cae24SSepherosa Ziehau */ 37929c6cae24SSepherosa Ziehau hn_mtu_change_fixup(sc); 379315516c77SSepherosa Ziehau 379415516c77SSepherosa Ziehau /* 379515516c77SSepherosa Ziehau * All done! Resume the interface now. 379615516c77SSepherosa Ziehau */ 379715516c77SSepherosa Ziehau hn_resume(sc); 379815516c77SSepherosa Ziehau 3799d0cd8231SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) || 3800d0cd8231SSepherosa Ziehau (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { 38019c6cae24SSepherosa Ziehau /* 38029c6cae24SSepherosa Ziehau * Since we have reattached the NVS part, 38039c6cae24SSepherosa Ziehau * change the datapath to VF again; in case 38049c6cae24SSepherosa Ziehau * that it is lost, after the NVS was detached. 38059c6cae24SSepherosa Ziehau */ 38069c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF); 38079c6cae24SSepherosa Ziehau } 38089c6cae24SSepherosa Ziehau 380915516c77SSepherosa Ziehau HN_UNLOCK(sc); 381015516c77SSepherosa Ziehau break; 381115516c77SSepherosa Ziehau 381215516c77SSepherosa Ziehau case SIOCSIFFLAGS: 381315516c77SSepherosa Ziehau HN_LOCK(sc); 381415516c77SSepherosa Ziehau 381515516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 381615516c77SSepherosa Ziehau HN_UNLOCK(sc); 381715516c77SSepherosa Ziehau break; 381815516c77SSepherosa Ziehau } 381915516c77SSepherosa Ziehau 38209c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) 38219c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 38229c6cae24SSepherosa Ziehau 382315516c77SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 3824fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3825fdc4f478SSepherosa Ziehau /* 3826fdc4f478SSepherosa Ziehau * Caller meight hold mutex, e.g. 3827fdc4f478SSepherosa Ziehau * bpf; use busy-wait for the RNDIS 3828fdc4f478SSepherosa Ziehau * reply. 3829fdc4f478SSepherosa Ziehau */ 3830fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 3831c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 3832fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 38339c6cae24SSepherosa Ziehau 38349c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 38359c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 3836fdc4f478SSepherosa Ziehau } else { 383715516c77SSepherosa Ziehau hn_init_locked(sc); 3838fdc4f478SSepherosa Ziehau } 383915516c77SSepherosa Ziehau } else { 384015516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 38415bdfd3fdSDexuan Cui hn_stop(sc, false); 384215516c77SSepherosa Ziehau } 384315516c77SSepherosa Ziehau sc->hn_if_flags = ifp->if_flags; 384415516c77SSepherosa Ziehau 384515516c77SSepherosa Ziehau HN_UNLOCK(sc); 384615516c77SSepherosa Ziehau break; 384715516c77SSepherosa Ziehau 384815516c77SSepherosa Ziehau case SIOCSIFCAP: 384915516c77SSepherosa Ziehau HN_LOCK(sc); 38509c6cae24SSepherosa Ziehau 38519c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 38529c6cae24SSepherosa Ziehau ifr_vf = *ifr; 38539c6cae24SSepherosa Ziehau strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname, 38549c6cae24SSepherosa Ziehau sizeof(ifr_vf.ifr_name)); 38559c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf); 38569c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 38579c6cae24SSepherosa Ziehau break; 38589c6cae24SSepherosa Ziehau } 38599c6cae24SSepherosa Ziehau 38609c6cae24SSepherosa Ziehau /* 38619c6cae24SSepherosa Ziehau * Fix up requested capabilities w/ supported capabilities, 38629c6cae24SSepherosa Ziehau * since the supported capabilities could have been changed. 38639c6cae24SSepherosa Ziehau */ 38649c6cae24SSepherosa Ziehau mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^ 38659c6cae24SSepherosa Ziehau ifp->if_capenable; 386615516c77SSepherosa Ziehau 386715516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM) { 386815516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 386915516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 387015516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc); 387115516c77SSepherosa Ziehau else 387215516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc); 387315516c77SSepherosa Ziehau } 387415516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM_IPV6) { 387515516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 387615516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 387715516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc); 387815516c77SSepherosa Ziehau else 387915516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc); 388015516c77SSepherosa Ziehau } 388115516c77SSepherosa Ziehau 388215516c77SSepherosa Ziehau /* TODO: flip RNDIS offload parameters for RXCSUM. */ 388315516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 388415516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 388515516c77SSepherosa Ziehau #ifdef foo 388615516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 388715516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM_IPV6) 388815516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 388915516c77SSepherosa Ziehau #endif 389015516c77SSepherosa Ziehau 389115516c77SSepherosa Ziehau if (mask & IFCAP_LRO) 389215516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_LRO; 389315516c77SSepherosa Ziehau 389415516c77SSepherosa Ziehau if (mask & IFCAP_TSO4) { 389515516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO4; 389615516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 389715516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 389815516c77SSepherosa Ziehau else 389915516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP_TSO; 390015516c77SSepherosa Ziehau } 390115516c77SSepherosa Ziehau if (mask & IFCAP_TSO6) { 390215516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO6; 390315516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 390415516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 390515516c77SSepherosa Ziehau else 390615516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP6_TSO; 390715516c77SSepherosa Ziehau } 390815516c77SSepherosa Ziehau 390915516c77SSepherosa Ziehau HN_UNLOCK(sc); 391015516c77SSepherosa Ziehau break; 391115516c77SSepherosa Ziehau 391215516c77SSepherosa Ziehau case SIOCADDMULTI: 391315516c77SSepherosa Ziehau case SIOCDELMULTI: 391415516c77SSepherosa Ziehau HN_LOCK(sc); 391515516c77SSepherosa Ziehau 391615516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 391715516c77SSepherosa Ziehau HN_UNLOCK(sc); 391815516c77SSepherosa Ziehau break; 391915516c77SSepherosa Ziehau } 3920fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3921fdc4f478SSepherosa Ziehau /* 3922fdc4f478SSepherosa Ziehau * Multicast uses mutex; use busy-wait for 3923fdc4f478SSepherosa Ziehau * the RNDIS reply. 3924fdc4f478SSepherosa Ziehau */ 3925fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 3926c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 3927fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 3928fdc4f478SSepherosa Ziehau } 392915516c77SSepherosa Ziehau 39309c6cae24SSepherosa Ziehau /* XXX vlan(4) style mcast addr maintenance */ 39319c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 39329c6cae24SSepherosa Ziehau int old_if_flags; 39339c6cae24SSepherosa Ziehau 39349c6cae24SSepherosa Ziehau old_if_flags = sc->hn_vf_ifp->if_flags; 39359c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 39369c6cae24SSepherosa Ziehau 39379c6cae24SSepherosa Ziehau if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) && 39389c6cae24SSepherosa Ziehau ((old_if_flags ^ sc->hn_vf_ifp->if_flags) & 39399c6cae24SSepherosa Ziehau IFF_ALLMULTI)) 39409c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 39419c6cae24SSepherosa Ziehau } 39429c6cae24SSepherosa Ziehau 394315516c77SSepherosa Ziehau HN_UNLOCK(sc); 394415516c77SSepherosa Ziehau break; 394515516c77SSepherosa Ziehau 394615516c77SSepherosa Ziehau case SIOCSIFMEDIA: 394715516c77SSepherosa Ziehau case SIOCGIFMEDIA: 39489c6cae24SSepherosa Ziehau HN_LOCK(sc); 39499c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 39509c6cae24SSepherosa Ziehau /* 39519c6cae24SSepherosa Ziehau * SIOCGIFMEDIA expects ifmediareq, so don't 39529c6cae24SSepherosa Ziehau * create and pass ifr_vf to the VF here; just 39539c6cae24SSepherosa Ziehau * replace the ifr_name. 39549c6cae24SSepherosa Ziehau */ 39559c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 39569c6cae24SSepherosa Ziehau strlcpy(ifr->ifr_name, vf_ifp->if_xname, 39579c6cae24SSepherosa Ziehau sizeof(ifr->ifr_name)); 39589c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, cmd, data); 39599c6cae24SSepherosa Ziehau /* Restore the ifr_name. */ 39609c6cae24SSepherosa Ziehau strlcpy(ifr->ifr_name, ifp->if_xname, 39619c6cae24SSepherosa Ziehau sizeof(ifr->ifr_name)); 39629c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 39639c6cae24SSepherosa Ziehau break; 39649c6cae24SSepherosa Ziehau } 39659c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 396615516c77SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd); 396715516c77SSepherosa Ziehau break; 396815516c77SSepherosa Ziehau 39698c068aa5SSepherosa Ziehau case SIOCGIFRSSHASH: 39708c068aa5SSepherosa Ziehau ifrh = (struct ifrsshash *)data; 39718c068aa5SSepherosa Ziehau HN_LOCK(sc); 39728c068aa5SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 39738c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 39748c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_NONE; 39758c068aa5SSepherosa Ziehau ifrh->ifrh_types = 0; 39768c068aa5SSepherosa Ziehau break; 39778c068aa5SSepherosa Ziehau } 39788c068aa5SSepherosa Ziehau 39798c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ) 39808c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_TOEPLITZ; 39818c068aa5SSepherosa Ziehau else 39828c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_PRIVATE; 3983642ec226SSepherosa Ziehau ifrh->ifrh_types = hn_rss_type_fromndis(sc->hn_rss_hash); 39848c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 39858c068aa5SSepherosa Ziehau break; 39868c068aa5SSepherosa Ziehau 39878c068aa5SSepherosa Ziehau case SIOCGIFRSSKEY: 39888c068aa5SSepherosa Ziehau ifrk = (struct ifrsskey *)data; 39898c068aa5SSepherosa Ziehau HN_LOCK(sc); 39908c068aa5SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 39918c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 39928c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_NONE; 39938c068aa5SSepherosa Ziehau ifrk->ifrk_keylen = 0; 39948c068aa5SSepherosa Ziehau break; 39958c068aa5SSepherosa Ziehau } 39968c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ) 39978c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_TOEPLITZ; 39988c068aa5SSepherosa Ziehau else 39998c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_PRIVATE; 40008c068aa5SSepherosa Ziehau ifrk->ifrk_keylen = NDIS_HASH_KEYSIZE_TOEPLITZ; 40018c068aa5SSepherosa Ziehau memcpy(ifrk->ifrk_key, sc->hn_rss.rss_key, 40028c068aa5SSepherosa Ziehau NDIS_HASH_KEYSIZE_TOEPLITZ); 40038c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 40048c068aa5SSepherosa Ziehau break; 40058c068aa5SSepherosa Ziehau 400615516c77SSepherosa Ziehau default: 400715516c77SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 400815516c77SSepherosa Ziehau break; 400915516c77SSepherosa Ziehau } 401015516c77SSepherosa Ziehau return (error); 401115516c77SSepherosa Ziehau } 401215516c77SSepherosa Ziehau 401315516c77SSepherosa Ziehau static void 40145bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching) 401515516c77SSepherosa Ziehau { 401615516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 401715516c77SSepherosa Ziehau int i; 401815516c77SSepherosa Ziehau 401915516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 402015516c77SSepherosa Ziehau 402115516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 402215516c77SSepherosa Ziehau ("synthetic parts were not attached")); 402315516c77SSepherosa Ziehau 40249c6cae24SSepherosa Ziehau /* Clear RUNNING bit ASAP. */ 40259c6cae24SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 40269c6cae24SSepherosa Ziehau 40276c1204dfSSepherosa Ziehau /* Disable polling. */ 40286c1204dfSSepherosa Ziehau hn_polling(sc, 0); 40296c1204dfSSepherosa Ziehau 40309c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) { 40319c6cae24SSepherosa Ziehau KASSERT(sc->hn_vf_ifp != NULL, 40329c6cae24SSepherosa Ziehau ("%s: VF is not attached", ifp->if_xname)); 40339c6cae24SSepherosa Ziehau 4034a97fff19SSepherosa Ziehau /* Mark transparent mode VF as disabled. */ 4035a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */); 40369c6cae24SSepherosa Ziehau 40379c6cae24SSepherosa Ziehau /* 40389c6cae24SSepherosa Ziehau * NOTE: 40399c6cae24SSepherosa Ziehau * Datapath setting must happen _before_ bringing 40409c6cae24SSepherosa Ziehau * the VF down. 40419c6cae24SSepherosa Ziehau */ 40429c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH); 40439c6cae24SSepherosa Ziehau 40449c6cae24SSepherosa Ziehau /* 40459c6cae24SSepherosa Ziehau * Bring the VF down. 40469c6cae24SSepherosa Ziehau */ 40479c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 40489c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags &= ~IFF_UP; 40499c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(sc); 40509c6cae24SSepherosa Ziehau } 40519c6cae24SSepherosa Ziehau 40529c6cae24SSepherosa Ziehau /* Suspend data transfers. */ 405315516c77SSepherosa Ziehau hn_suspend_data(sc); 405415516c77SSepherosa Ziehau 405515516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 405615516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 405715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 405815516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 40595bdfd3fdSDexuan Cui 40605bdfd3fdSDexuan Cui /* 40619c6cae24SSepherosa Ziehau * If the non-transparent mode VF is active, make sure 40629c6cae24SSepherosa Ziehau * that the RX filter still allows packet reception. 40635bdfd3fdSDexuan Cui */ 4064962f0357SSepherosa Ziehau if (!detaching && (sc->hn_flags & HN_FLAG_RXVF)) 40655bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 406615516c77SSepherosa Ziehau } 406715516c77SSepherosa Ziehau 406815516c77SSepherosa Ziehau static void 406915516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc) 407015516c77SSepherosa Ziehau { 407115516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 407215516c77SSepherosa Ziehau int i; 407315516c77SSepherosa Ziehau 407415516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 407515516c77SSepherosa Ziehau 407615516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 407715516c77SSepherosa Ziehau return; 407815516c77SSepherosa Ziehau 407915516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 408015516c77SSepherosa Ziehau return; 408115516c77SSepherosa Ziehau 408215516c77SSepherosa Ziehau /* Configure RX filter */ 4083c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 408415516c77SSepherosa Ziehau 408515516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 408615516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 408715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 408815516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 408915516c77SSepherosa Ziehau 409015516c77SSepherosa Ziehau /* Clear TX 'suspended' bit. */ 409115516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_inuse); 409215516c77SSepherosa Ziehau 40939c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 40949c6cae24SSepherosa Ziehau /* Initialize transparent VF. */ 40959c6cae24SSepherosa Ziehau hn_xpnt_vf_init(sc); 40969c6cae24SSepherosa Ziehau } 40979c6cae24SSepherosa Ziehau 409815516c77SSepherosa Ziehau /* Everything is ready; unleash! */ 409915516c77SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 41006c1204dfSSepherosa Ziehau 41016c1204dfSSepherosa Ziehau /* Re-enable polling if requested. */ 41026c1204dfSSepherosa Ziehau if (sc->hn_pollhz > 0) 41036c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 410415516c77SSepherosa Ziehau } 410515516c77SSepherosa Ziehau 410615516c77SSepherosa Ziehau static void 410715516c77SSepherosa Ziehau hn_init(void *xsc) 410815516c77SSepherosa Ziehau { 410915516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 411015516c77SSepherosa Ziehau 411115516c77SSepherosa Ziehau HN_LOCK(sc); 411215516c77SSepherosa Ziehau hn_init_locked(sc); 411315516c77SSepherosa Ziehau HN_UNLOCK(sc); 411415516c77SSepherosa Ziehau } 411515516c77SSepherosa Ziehau 411615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 411715516c77SSepherosa Ziehau 411815516c77SSepherosa Ziehau static int 411915516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS) 412015516c77SSepherosa Ziehau { 412115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 412215516c77SSepherosa Ziehau unsigned int lenlim; 412315516c77SSepherosa Ziehau int error; 412415516c77SSepherosa Ziehau 412515516c77SSepherosa Ziehau lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim; 412615516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &lenlim, 0, req); 412715516c77SSepherosa Ziehau if (error || req->newptr == NULL) 412815516c77SSepherosa Ziehau return error; 412915516c77SSepherosa Ziehau 413015516c77SSepherosa Ziehau HN_LOCK(sc); 413115516c77SSepherosa Ziehau if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) || 413215516c77SSepherosa Ziehau lenlim > TCP_LRO_LENGTH_MAX) { 413315516c77SSepherosa Ziehau HN_UNLOCK(sc); 413415516c77SSepherosa Ziehau return EINVAL; 413515516c77SSepherosa Ziehau } 413615516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, lenlim); 413715516c77SSepherosa Ziehau HN_UNLOCK(sc); 413815516c77SSepherosa Ziehau 413915516c77SSepherosa Ziehau return 0; 414015516c77SSepherosa Ziehau } 414115516c77SSepherosa Ziehau 414215516c77SSepherosa Ziehau static int 414315516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS) 414415516c77SSepherosa Ziehau { 414515516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 414615516c77SSepherosa Ziehau int ackcnt, error, i; 414715516c77SSepherosa Ziehau 414815516c77SSepherosa Ziehau /* 414915516c77SSepherosa Ziehau * lro_ackcnt_lim is append count limit, 415015516c77SSepherosa Ziehau * +1 to turn it into aggregation limit. 415115516c77SSepherosa Ziehau */ 415215516c77SSepherosa Ziehau ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1; 415315516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &ackcnt, 0, req); 415415516c77SSepherosa Ziehau if (error || req->newptr == NULL) 415515516c77SSepherosa Ziehau return error; 415615516c77SSepherosa Ziehau 415715516c77SSepherosa Ziehau if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1)) 415815516c77SSepherosa Ziehau return EINVAL; 415915516c77SSepherosa Ziehau 416015516c77SSepherosa Ziehau /* 416115516c77SSepherosa Ziehau * Convert aggregation limit back to append 416215516c77SSepherosa Ziehau * count limit. 416315516c77SSepherosa Ziehau */ 416415516c77SSepherosa Ziehau --ackcnt; 416515516c77SSepherosa Ziehau HN_LOCK(sc); 4166a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 416715516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt; 416815516c77SSepherosa Ziehau HN_UNLOCK(sc); 416915516c77SSepherosa Ziehau return 0; 417015516c77SSepherosa Ziehau } 417115516c77SSepherosa Ziehau 417215516c77SSepherosa Ziehau #endif 417315516c77SSepherosa Ziehau 417415516c77SSepherosa Ziehau static int 417515516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS) 417615516c77SSepherosa Ziehau { 417715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 417815516c77SSepherosa Ziehau int hcsum = arg2; 417915516c77SSepherosa Ziehau int on, error, i; 418015516c77SSepherosa Ziehau 418115516c77SSepherosa Ziehau on = 0; 418215516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum) 418315516c77SSepherosa Ziehau on = 1; 418415516c77SSepherosa Ziehau 418515516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &on, 0, req); 418615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 418715516c77SSepherosa Ziehau return error; 418815516c77SSepherosa Ziehau 418915516c77SSepherosa Ziehau HN_LOCK(sc); 4190a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 419115516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 419215516c77SSepherosa Ziehau 419315516c77SSepherosa Ziehau if (on) 419415516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= hcsum; 419515516c77SSepherosa Ziehau else 419615516c77SSepherosa Ziehau rxr->hn_trust_hcsum &= ~hcsum; 419715516c77SSepherosa Ziehau } 419815516c77SSepherosa Ziehau HN_UNLOCK(sc); 419915516c77SSepherosa Ziehau return 0; 420015516c77SSepherosa Ziehau } 420115516c77SSepherosa Ziehau 420215516c77SSepherosa Ziehau static int 420315516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS) 420415516c77SSepherosa Ziehau { 420515516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 420615516c77SSepherosa Ziehau int chim_size, error; 420715516c77SSepherosa Ziehau 420815516c77SSepherosa Ziehau chim_size = sc->hn_tx_ring[0].hn_chim_size; 420915516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &chim_size, 0, req); 421015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 421115516c77SSepherosa Ziehau return error; 421215516c77SSepherosa Ziehau 421315516c77SSepherosa Ziehau if (chim_size > sc->hn_chim_szmax || chim_size <= 0) 421415516c77SSepherosa Ziehau return EINVAL; 421515516c77SSepherosa Ziehau 421615516c77SSepherosa Ziehau HN_LOCK(sc); 421715516c77SSepherosa Ziehau hn_set_chim_size(sc, chim_size); 421815516c77SSepherosa Ziehau HN_UNLOCK(sc); 421915516c77SSepherosa Ziehau return 0; 422015516c77SSepherosa Ziehau } 422115516c77SSepherosa Ziehau 422215516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 422315516c77SSepherosa Ziehau static int 422415516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS) 422515516c77SSepherosa Ziehau { 422615516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 422715516c77SSepherosa Ziehau int ofs = arg2, i, error; 422815516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 422915516c77SSepherosa Ziehau uint64_t stat; 423015516c77SSepherosa Ziehau 423115516c77SSepherosa Ziehau stat = 0; 423215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 423315516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 423415516c77SSepherosa Ziehau stat += *((int *)((uint8_t *)rxr + ofs)); 423515516c77SSepherosa Ziehau } 423615516c77SSepherosa Ziehau 423715516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 423815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 423915516c77SSepherosa Ziehau return error; 424015516c77SSepherosa Ziehau 424115516c77SSepherosa Ziehau /* Zero out this stat. */ 424215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 424315516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 424415516c77SSepherosa Ziehau *((int *)((uint8_t *)rxr + ofs)) = 0; 424515516c77SSepherosa Ziehau } 424615516c77SSepherosa Ziehau return 0; 424715516c77SSepherosa Ziehau } 424815516c77SSepherosa Ziehau #else 424915516c77SSepherosa Ziehau static int 425015516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS) 425115516c77SSepherosa Ziehau { 425215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 425315516c77SSepherosa Ziehau int ofs = arg2, i, error; 425415516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 425515516c77SSepherosa Ziehau uint64_t stat; 425615516c77SSepherosa Ziehau 425715516c77SSepherosa Ziehau stat = 0; 4258a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 425915516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 426015516c77SSepherosa Ziehau stat += *((uint64_t *)((uint8_t *)rxr + ofs)); 426115516c77SSepherosa Ziehau } 426215516c77SSepherosa Ziehau 426315516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 426415516c77SSepherosa Ziehau if (error || req->newptr == NULL) 426515516c77SSepherosa Ziehau return error; 426615516c77SSepherosa Ziehau 426715516c77SSepherosa Ziehau /* Zero out this stat. */ 4268a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 426915516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 427015516c77SSepherosa Ziehau *((uint64_t *)((uint8_t *)rxr + ofs)) = 0; 427115516c77SSepherosa Ziehau } 427215516c77SSepherosa Ziehau return 0; 427315516c77SSepherosa Ziehau } 427415516c77SSepherosa Ziehau 427515516c77SSepherosa Ziehau #endif 427615516c77SSepherosa Ziehau 427715516c77SSepherosa Ziehau static int 427815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 427915516c77SSepherosa Ziehau { 428015516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 428115516c77SSepherosa Ziehau int ofs = arg2, i, error; 428215516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 428315516c77SSepherosa Ziehau u_long stat; 428415516c77SSepherosa Ziehau 428515516c77SSepherosa Ziehau stat = 0; 4286a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 428715516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 428815516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)rxr + ofs)); 428915516c77SSepherosa Ziehau } 429015516c77SSepherosa Ziehau 429115516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 429215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 429315516c77SSepherosa Ziehau return error; 429415516c77SSepherosa Ziehau 429515516c77SSepherosa Ziehau /* Zero out this stat. */ 4296a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 429715516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 429815516c77SSepherosa Ziehau *((u_long *)((uint8_t *)rxr + ofs)) = 0; 429915516c77SSepherosa Ziehau } 430015516c77SSepherosa Ziehau return 0; 430115516c77SSepherosa Ziehau } 430215516c77SSepherosa Ziehau 430315516c77SSepherosa Ziehau static int 430415516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 430515516c77SSepherosa Ziehau { 430615516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 430715516c77SSepherosa Ziehau int ofs = arg2, i, error; 430815516c77SSepherosa Ziehau struct hn_tx_ring *txr; 430915516c77SSepherosa Ziehau u_long stat; 431015516c77SSepherosa Ziehau 431115516c77SSepherosa Ziehau stat = 0; 4312a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 431315516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 431415516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)txr + ofs)); 431515516c77SSepherosa Ziehau } 431615516c77SSepherosa Ziehau 431715516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 431815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 431915516c77SSepherosa Ziehau return error; 432015516c77SSepherosa Ziehau 432115516c77SSepherosa Ziehau /* Zero out this stat. */ 4322a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 432315516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 432415516c77SSepherosa Ziehau *((u_long *)((uint8_t *)txr + ofs)) = 0; 432515516c77SSepherosa Ziehau } 432615516c77SSepherosa Ziehau return 0; 432715516c77SSepherosa Ziehau } 432815516c77SSepherosa Ziehau 432915516c77SSepherosa Ziehau static int 433015516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS) 433115516c77SSepherosa Ziehau { 433215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 433315516c77SSepherosa Ziehau int ofs = arg2, i, error, conf; 433415516c77SSepherosa Ziehau struct hn_tx_ring *txr; 433515516c77SSepherosa Ziehau 433615516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[0]; 433715516c77SSepherosa Ziehau conf = *((int *)((uint8_t *)txr + ofs)); 433815516c77SSepherosa Ziehau 433915516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &conf, 0, req); 434015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 434115516c77SSepherosa Ziehau return error; 434215516c77SSepherosa Ziehau 434315516c77SSepherosa Ziehau HN_LOCK(sc); 4344a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 434515516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 434615516c77SSepherosa Ziehau *((int *)((uint8_t *)txr + ofs)) = conf; 434715516c77SSepherosa Ziehau } 434815516c77SSepherosa Ziehau HN_UNLOCK(sc); 434915516c77SSepherosa Ziehau 435015516c77SSepherosa Ziehau return 0; 435115516c77SSepherosa Ziehau } 435215516c77SSepherosa Ziehau 435315516c77SSepherosa Ziehau static int 4354dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS) 4355dc13fee6SSepherosa Ziehau { 4356dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4357dc13fee6SSepherosa Ziehau int error, size; 4358dc13fee6SSepherosa Ziehau 4359dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 4360dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &size, 0, req); 4361dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 4362dc13fee6SSepherosa Ziehau return (error); 4363dc13fee6SSepherosa Ziehau 4364dc13fee6SSepherosa Ziehau HN_LOCK(sc); 4365dc13fee6SSepherosa Ziehau sc->hn_agg_size = size; 4366dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 4367dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 4368dc13fee6SSepherosa Ziehau 4369dc13fee6SSepherosa Ziehau return (0); 4370dc13fee6SSepherosa Ziehau } 4371dc13fee6SSepherosa Ziehau 4372dc13fee6SSepherosa Ziehau static int 4373dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS) 4374dc13fee6SSepherosa Ziehau { 4375dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4376dc13fee6SSepherosa Ziehau int error, pkts; 4377dc13fee6SSepherosa Ziehau 4378dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 4379dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &pkts, 0, req); 4380dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 4381dc13fee6SSepherosa Ziehau return (error); 4382dc13fee6SSepherosa Ziehau 4383dc13fee6SSepherosa Ziehau HN_LOCK(sc); 4384dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = pkts; 4385dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 4386dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 4387dc13fee6SSepherosa Ziehau 4388dc13fee6SSepherosa Ziehau return (0); 4389dc13fee6SSepherosa Ziehau } 4390dc13fee6SSepherosa Ziehau 4391dc13fee6SSepherosa Ziehau static int 4392dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS) 4393dc13fee6SSepherosa Ziehau { 4394dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4395dc13fee6SSepherosa Ziehau int pkts; 4396dc13fee6SSepherosa Ziehau 4397dc13fee6SSepherosa Ziehau pkts = sc->hn_tx_ring[0].hn_agg_pktmax; 4398dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &pkts, 0, req)); 4399dc13fee6SSepherosa Ziehau } 4400dc13fee6SSepherosa Ziehau 4401dc13fee6SSepherosa Ziehau static int 4402dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS) 4403dc13fee6SSepherosa Ziehau { 4404dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4405dc13fee6SSepherosa Ziehau int align; 4406dc13fee6SSepherosa Ziehau 4407dc13fee6SSepherosa Ziehau align = sc->hn_tx_ring[0].hn_agg_align; 4408dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &align, 0, req)); 4409dc13fee6SSepherosa Ziehau } 4410dc13fee6SSepherosa Ziehau 44116c1204dfSSepherosa Ziehau static void 44126c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz) 44136c1204dfSSepherosa Ziehau { 44146c1204dfSSepherosa Ziehau if (pollhz == 0) 44156c1204dfSSepherosa Ziehau vmbus_chan_poll_disable(chan); 44166c1204dfSSepherosa Ziehau else 44176c1204dfSSepherosa Ziehau vmbus_chan_poll_enable(chan, pollhz); 44186c1204dfSSepherosa Ziehau } 44196c1204dfSSepherosa Ziehau 44206c1204dfSSepherosa Ziehau static void 44216c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz) 44226c1204dfSSepherosa Ziehau { 44236c1204dfSSepherosa Ziehau int nsubch = sc->hn_rx_ring_inuse - 1; 44246c1204dfSSepherosa Ziehau 44256c1204dfSSepherosa Ziehau HN_LOCK_ASSERT(sc); 44266c1204dfSSepherosa Ziehau 44276c1204dfSSepherosa Ziehau if (nsubch > 0) { 44286c1204dfSSepherosa Ziehau struct vmbus_channel **subch; 44296c1204dfSSepherosa Ziehau int i; 44306c1204dfSSepherosa Ziehau 44316c1204dfSSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 44326c1204dfSSepherosa Ziehau for (i = 0; i < nsubch; ++i) 44336c1204dfSSepherosa Ziehau hn_chan_polling(subch[i], pollhz); 44346c1204dfSSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 44356c1204dfSSepherosa Ziehau } 44366c1204dfSSepherosa Ziehau hn_chan_polling(sc->hn_prichan, pollhz); 44376c1204dfSSepherosa Ziehau } 44386c1204dfSSepherosa Ziehau 44396c1204dfSSepherosa Ziehau static int 44406c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS) 44416c1204dfSSepherosa Ziehau { 44426c1204dfSSepherosa Ziehau struct hn_softc *sc = arg1; 44436c1204dfSSepherosa Ziehau int pollhz, error; 44446c1204dfSSepherosa Ziehau 44456c1204dfSSepherosa Ziehau pollhz = sc->hn_pollhz; 44466c1204dfSSepherosa Ziehau error = sysctl_handle_int(oidp, &pollhz, 0, req); 44476c1204dfSSepherosa Ziehau if (error || req->newptr == NULL) 44486c1204dfSSepherosa Ziehau return (error); 44496c1204dfSSepherosa Ziehau 44506c1204dfSSepherosa Ziehau if (pollhz != 0 && 44516c1204dfSSepherosa Ziehau (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX)) 44526c1204dfSSepherosa Ziehau return (EINVAL); 44536c1204dfSSepherosa Ziehau 44546c1204dfSSepherosa Ziehau HN_LOCK(sc); 44556c1204dfSSepherosa Ziehau if (sc->hn_pollhz != pollhz) { 44566c1204dfSSepherosa Ziehau sc->hn_pollhz = pollhz; 44576c1204dfSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && 44586c1204dfSSepherosa Ziehau (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 44596c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 44606c1204dfSSepherosa Ziehau } 44616c1204dfSSepherosa Ziehau HN_UNLOCK(sc); 44626c1204dfSSepherosa Ziehau 44636c1204dfSSepherosa Ziehau return (0); 44646c1204dfSSepherosa Ziehau } 44656c1204dfSSepherosa Ziehau 4466dc13fee6SSepherosa Ziehau static int 446715516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS) 446815516c77SSepherosa Ziehau { 446915516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 447015516c77SSepherosa Ziehau char verstr[16]; 447115516c77SSepherosa Ziehau 447215516c77SSepherosa Ziehau snprintf(verstr, sizeof(verstr), "%u.%u", 447315516c77SSepherosa Ziehau HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 447415516c77SSepherosa Ziehau HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 447515516c77SSepherosa Ziehau return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 447615516c77SSepherosa Ziehau } 447715516c77SSepherosa Ziehau 447815516c77SSepherosa Ziehau static int 447915516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS) 448015516c77SSepherosa Ziehau { 448115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 448215516c77SSepherosa Ziehau char caps_str[128]; 448315516c77SSepherosa Ziehau uint32_t caps; 448415516c77SSepherosa Ziehau 448515516c77SSepherosa Ziehau HN_LOCK(sc); 448615516c77SSepherosa Ziehau caps = sc->hn_caps; 448715516c77SSepherosa Ziehau HN_UNLOCK(sc); 448815516c77SSepherosa Ziehau snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS); 448915516c77SSepherosa Ziehau return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req); 449015516c77SSepherosa Ziehau } 449115516c77SSepherosa Ziehau 449215516c77SSepherosa Ziehau static int 449315516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS) 449415516c77SSepherosa Ziehau { 449515516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 449615516c77SSepherosa Ziehau char assist_str[128]; 449715516c77SSepherosa Ziehau uint32_t hwassist; 449815516c77SSepherosa Ziehau 449915516c77SSepherosa Ziehau HN_LOCK(sc); 450015516c77SSepherosa Ziehau hwassist = sc->hn_ifp->if_hwassist; 450115516c77SSepherosa Ziehau HN_UNLOCK(sc); 450215516c77SSepherosa Ziehau snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS); 450315516c77SSepherosa Ziehau return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req); 450415516c77SSepherosa Ziehau } 450515516c77SSepherosa Ziehau 450615516c77SSepherosa Ziehau static int 450715516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS) 450815516c77SSepherosa Ziehau { 450915516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 451015516c77SSepherosa Ziehau char filter_str[128]; 451115516c77SSepherosa Ziehau uint32_t filter; 451215516c77SSepherosa Ziehau 451315516c77SSepherosa Ziehau HN_LOCK(sc); 451415516c77SSepherosa Ziehau filter = sc->hn_rx_filter; 451515516c77SSepherosa Ziehau HN_UNLOCK(sc); 451615516c77SSepherosa Ziehau snprintf(filter_str, sizeof(filter_str), "%b", filter, 451715516c77SSepherosa Ziehau NDIS_PACKET_TYPES); 451815516c77SSepherosa Ziehau return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req); 451915516c77SSepherosa Ziehau } 452015516c77SSepherosa Ziehau 452134d68912SSepherosa Ziehau #ifndef RSS 452234d68912SSepherosa Ziehau 452315516c77SSepherosa Ziehau static int 452415516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS) 452515516c77SSepherosa Ziehau { 452615516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 452715516c77SSepherosa Ziehau int error; 452815516c77SSepherosa Ziehau 452915516c77SSepherosa Ziehau HN_LOCK(sc); 453015516c77SSepherosa Ziehau 453115516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 453215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 453315516c77SSepherosa Ziehau goto back; 453415516c77SSepherosa Ziehau 4535642ec226SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) || 4536642ec226SSepherosa Ziehau (hn_xpnt_vf && sc->hn_vf_ifp != NULL)) { 4537642ec226SSepherosa Ziehau /* 4538642ec226SSepherosa Ziehau * RSS key is synchronized w/ VF's, don't allow users 4539642ec226SSepherosa Ziehau * to change it. 4540642ec226SSepherosa Ziehau */ 4541642ec226SSepherosa Ziehau error = EBUSY; 4542642ec226SSepherosa Ziehau goto back; 4543642ec226SSepherosa Ziehau } 4544642ec226SSepherosa Ziehau 454515516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 454615516c77SSepherosa Ziehau if (error) 454715516c77SSepherosa Ziehau goto back; 454815516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 454915516c77SSepherosa Ziehau 455015516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 455115516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 455215516c77SSepherosa Ziehau } else { 455315516c77SSepherosa Ziehau /* Not RSS capable, at least for now; just save the RSS key. */ 455415516c77SSepherosa Ziehau error = 0; 455515516c77SSepherosa Ziehau } 455615516c77SSepherosa Ziehau back: 455715516c77SSepherosa Ziehau HN_UNLOCK(sc); 455815516c77SSepherosa Ziehau return (error); 455915516c77SSepherosa Ziehau } 456015516c77SSepherosa Ziehau 456115516c77SSepherosa Ziehau static int 456215516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS) 456315516c77SSepherosa Ziehau { 456415516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 456515516c77SSepherosa Ziehau int error; 456615516c77SSepherosa Ziehau 456715516c77SSepherosa Ziehau HN_LOCK(sc); 456815516c77SSepherosa Ziehau 456915516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 457015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 457115516c77SSepherosa Ziehau goto back; 457215516c77SSepherosa Ziehau 457315516c77SSepherosa Ziehau /* 457415516c77SSepherosa Ziehau * Don't allow RSS indirect table change, if this interface is not 457515516c77SSepherosa Ziehau * RSS capable currently. 457615516c77SSepherosa Ziehau */ 457715516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 457815516c77SSepherosa Ziehau error = EOPNOTSUPP; 457915516c77SSepherosa Ziehau goto back; 458015516c77SSepherosa Ziehau } 458115516c77SSepherosa Ziehau 458215516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 458315516c77SSepherosa Ziehau if (error) 458415516c77SSepherosa Ziehau goto back; 458515516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 458615516c77SSepherosa Ziehau 4587afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 458815516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 458915516c77SSepherosa Ziehau back: 459015516c77SSepherosa Ziehau HN_UNLOCK(sc); 459115516c77SSepherosa Ziehau return (error); 459215516c77SSepherosa Ziehau } 459315516c77SSepherosa Ziehau 459434d68912SSepherosa Ziehau #endif /* !RSS */ 459534d68912SSepherosa Ziehau 459615516c77SSepherosa Ziehau static int 459715516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS) 459815516c77SSepherosa Ziehau { 459915516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 460015516c77SSepherosa Ziehau char hash_str[128]; 460115516c77SSepherosa Ziehau uint32_t hash; 460215516c77SSepherosa Ziehau 460315516c77SSepherosa Ziehau HN_LOCK(sc); 460415516c77SSepherosa Ziehau hash = sc->hn_rss_hash; 460515516c77SSepherosa Ziehau HN_UNLOCK(sc); 460615516c77SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 460715516c77SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 460815516c77SSepherosa Ziehau } 460915516c77SSepherosa Ziehau 461015516c77SSepherosa Ziehau static int 4611642ec226SSepherosa Ziehau hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS) 4612642ec226SSepherosa Ziehau { 4613642ec226SSepherosa Ziehau struct hn_softc *sc = arg1; 4614642ec226SSepherosa Ziehau char hash_str[128]; 4615642ec226SSepherosa Ziehau uint32_t hash; 4616642ec226SSepherosa Ziehau 4617642ec226SSepherosa Ziehau HN_LOCK(sc); 4618642ec226SSepherosa Ziehau hash = sc->hn_rss_hcap; 4619642ec226SSepherosa Ziehau HN_UNLOCK(sc); 4620642ec226SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 4621642ec226SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 4622642ec226SSepherosa Ziehau } 4623642ec226SSepherosa Ziehau 4624642ec226SSepherosa Ziehau static int 4625642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS) 4626642ec226SSepherosa Ziehau { 4627642ec226SSepherosa Ziehau struct hn_softc *sc = arg1; 4628642ec226SSepherosa Ziehau char hash_str[128]; 4629642ec226SSepherosa Ziehau uint32_t hash; 4630642ec226SSepherosa Ziehau 4631642ec226SSepherosa Ziehau HN_LOCK(sc); 4632642ec226SSepherosa Ziehau hash = sc->hn_rx_ring[0].hn_mbuf_hash; 4633642ec226SSepherosa Ziehau HN_UNLOCK(sc); 4634642ec226SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 4635642ec226SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 4636642ec226SSepherosa Ziehau } 4637642ec226SSepherosa Ziehau 4638642ec226SSepherosa Ziehau static int 463940d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS) 464040d60d6eSDexuan Cui { 464140d60d6eSDexuan Cui struct hn_softc *sc = arg1; 4642499c3e17SSepherosa Ziehau char vf_name[IFNAMSIZ + 1]; 4643962f0357SSepherosa Ziehau struct ifnet *vf_ifp; 464440d60d6eSDexuan Cui 464540d60d6eSDexuan Cui HN_LOCK(sc); 464640d60d6eSDexuan Cui vf_name[0] = '\0'; 4647962f0357SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 4648962f0357SSepherosa Ziehau if (vf_ifp != NULL) 4649962f0357SSepherosa Ziehau snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname); 465040d60d6eSDexuan Cui HN_UNLOCK(sc); 465140d60d6eSDexuan Cui return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); 465240d60d6eSDexuan Cui } 465340d60d6eSDexuan Cui 465440d60d6eSDexuan Cui static int 4655499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS) 4656499c3e17SSepherosa Ziehau { 4657499c3e17SSepherosa Ziehau struct hn_softc *sc = arg1; 4658499c3e17SSepherosa Ziehau char vf_name[IFNAMSIZ + 1]; 4659962f0357SSepherosa Ziehau struct ifnet *vf_ifp; 4660499c3e17SSepherosa Ziehau 4661499c3e17SSepherosa Ziehau HN_LOCK(sc); 4662499c3e17SSepherosa Ziehau vf_name[0] = '\0'; 4663962f0357SSepherosa Ziehau vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp; 4664962f0357SSepherosa Ziehau if (vf_ifp != NULL) 4665962f0357SSepherosa Ziehau snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname); 4666499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 4667499c3e17SSepherosa Ziehau return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); 4668499c3e17SSepherosa Ziehau } 4669499c3e17SSepherosa Ziehau 4670499c3e17SSepherosa Ziehau static int 4671499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS) 4672499c3e17SSepherosa Ziehau { 4673499c3e17SSepherosa Ziehau struct rm_priotracker pt; 4674499c3e17SSepherosa Ziehau struct sbuf *sb; 4675499c3e17SSepherosa Ziehau int error, i; 4676499c3e17SSepherosa Ziehau bool first; 4677499c3e17SSepherosa Ziehau 4678499c3e17SSepherosa Ziehau error = sysctl_wire_old_buffer(req, 0); 4679499c3e17SSepherosa Ziehau if (error != 0) 4680499c3e17SSepherosa Ziehau return (error); 4681499c3e17SSepherosa Ziehau 4682499c3e17SSepherosa Ziehau sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4683499c3e17SSepherosa Ziehau if (sb == NULL) 4684499c3e17SSepherosa Ziehau return (ENOMEM); 4685499c3e17SSepherosa Ziehau 4686499c3e17SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 4687499c3e17SSepherosa Ziehau 4688499c3e17SSepherosa Ziehau first = true; 4689499c3e17SSepherosa Ziehau for (i = 0; i < hn_vfmap_size; ++i) { 4690499c3e17SSepherosa Ziehau struct ifnet *ifp; 4691499c3e17SSepherosa Ziehau 4692499c3e17SSepherosa Ziehau if (hn_vfmap[i] == NULL) 4693499c3e17SSepherosa Ziehau continue; 4694499c3e17SSepherosa Ziehau 4695499c3e17SSepherosa Ziehau ifp = ifnet_byindex(i); 4696499c3e17SSepherosa Ziehau if (ifp != NULL) { 4697499c3e17SSepherosa Ziehau if (first) 4698499c3e17SSepherosa Ziehau sbuf_printf(sb, "%s", ifp->if_xname); 4699499c3e17SSepherosa Ziehau else 4700499c3e17SSepherosa Ziehau sbuf_printf(sb, " %s", ifp->if_xname); 4701499c3e17SSepherosa Ziehau first = false; 4702499c3e17SSepherosa Ziehau } 4703499c3e17SSepherosa Ziehau } 4704499c3e17SSepherosa Ziehau 4705499c3e17SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 4706499c3e17SSepherosa Ziehau 4707499c3e17SSepherosa Ziehau error = sbuf_finish(sb); 4708499c3e17SSepherosa Ziehau sbuf_delete(sb); 4709499c3e17SSepherosa Ziehau return (error); 4710499c3e17SSepherosa Ziehau } 4711499c3e17SSepherosa Ziehau 4712499c3e17SSepherosa Ziehau static int 4713499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS) 4714499c3e17SSepherosa Ziehau { 4715499c3e17SSepherosa Ziehau struct rm_priotracker pt; 4716499c3e17SSepherosa Ziehau struct sbuf *sb; 4717499c3e17SSepherosa Ziehau int error, i; 4718499c3e17SSepherosa Ziehau bool first; 4719499c3e17SSepherosa Ziehau 4720499c3e17SSepherosa Ziehau error = sysctl_wire_old_buffer(req, 0); 4721499c3e17SSepherosa Ziehau if (error != 0) 4722499c3e17SSepherosa Ziehau return (error); 4723499c3e17SSepherosa Ziehau 4724499c3e17SSepherosa Ziehau sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4725499c3e17SSepherosa Ziehau if (sb == NULL) 4726499c3e17SSepherosa Ziehau return (ENOMEM); 4727499c3e17SSepherosa Ziehau 4728499c3e17SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 4729499c3e17SSepherosa Ziehau 4730499c3e17SSepherosa Ziehau first = true; 4731499c3e17SSepherosa Ziehau for (i = 0; i < hn_vfmap_size; ++i) { 4732499c3e17SSepherosa Ziehau struct ifnet *ifp, *hn_ifp; 4733499c3e17SSepherosa Ziehau 4734499c3e17SSepherosa Ziehau hn_ifp = hn_vfmap[i]; 4735499c3e17SSepherosa Ziehau if (hn_ifp == NULL) 4736499c3e17SSepherosa Ziehau continue; 4737499c3e17SSepherosa Ziehau 4738499c3e17SSepherosa Ziehau ifp = ifnet_byindex(i); 4739499c3e17SSepherosa Ziehau if (ifp != NULL) { 4740499c3e17SSepherosa Ziehau if (first) { 4741499c3e17SSepherosa Ziehau sbuf_printf(sb, "%s:%s", ifp->if_xname, 4742499c3e17SSepherosa Ziehau hn_ifp->if_xname); 4743499c3e17SSepherosa Ziehau } else { 4744499c3e17SSepherosa Ziehau sbuf_printf(sb, " %s:%s", ifp->if_xname, 4745499c3e17SSepherosa Ziehau hn_ifp->if_xname); 4746499c3e17SSepherosa Ziehau } 4747499c3e17SSepherosa Ziehau first = false; 4748499c3e17SSepherosa Ziehau } 4749499c3e17SSepherosa Ziehau } 4750499c3e17SSepherosa Ziehau 4751499c3e17SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 4752499c3e17SSepherosa Ziehau 4753499c3e17SSepherosa Ziehau error = sbuf_finish(sb); 4754499c3e17SSepherosa Ziehau sbuf_delete(sb); 4755499c3e17SSepherosa Ziehau return (error); 4756499c3e17SSepherosa Ziehau } 4757499c3e17SSepherosa Ziehau 4758499c3e17SSepherosa Ziehau static int 47599c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS) 47609c6cae24SSepherosa Ziehau { 47619c6cae24SSepherosa Ziehau struct hn_softc *sc = arg1; 47629c6cae24SSepherosa Ziehau int error, onoff = 0; 47639c6cae24SSepherosa Ziehau 47649c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) 47659c6cae24SSepherosa Ziehau onoff = 1; 47669c6cae24SSepherosa Ziehau error = sysctl_handle_int(oidp, &onoff, 0, req); 47679c6cae24SSepherosa Ziehau if (error || req->newptr == NULL) 47689c6cae24SSepherosa Ziehau return (error); 47699c6cae24SSepherosa Ziehau 47709c6cae24SSepherosa Ziehau HN_LOCK(sc); 47719c6cae24SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit() */ 47729c6cae24SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 47739c6cae24SSepherosa Ziehau if (onoff) 47749c6cae24SSepherosa Ziehau sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF; 47759c6cae24SSepherosa Ziehau else 47769c6cae24SSepherosa Ziehau sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF; 47779c6cae24SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 47789c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 47799c6cae24SSepherosa Ziehau 47809c6cae24SSepherosa Ziehau return (0); 47819c6cae24SSepherosa Ziehau } 47829c6cae24SSepherosa Ziehau 47839c6cae24SSepherosa Ziehau static int 47849c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS) 47859c6cae24SSepherosa Ziehau { 47869c6cae24SSepherosa Ziehau struct hn_softc *sc = arg1; 47879c6cae24SSepherosa Ziehau int enabled = 0; 47889c6cae24SSepherosa Ziehau 47899c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 47909c6cae24SSepherosa Ziehau enabled = 1; 47919c6cae24SSepherosa Ziehau return (sysctl_handle_int(oidp, &enabled, 0, req)); 47929c6cae24SSepherosa Ziehau } 47939c6cae24SSepherosa Ziehau 47949c6cae24SSepherosa Ziehau static int 479515516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff) 479615516c77SSepherosa Ziehau { 479715516c77SSepherosa Ziehau const struct ip *ip; 479815516c77SSepherosa Ziehau int len, iphlen, iplen; 479915516c77SSepherosa Ziehau const struct tcphdr *th; 480015516c77SSepherosa Ziehau int thoff; /* TCP data offset */ 480115516c77SSepherosa Ziehau 480215516c77SSepherosa Ziehau len = hoff + sizeof(struct ip); 480315516c77SSepherosa Ziehau 480415516c77SSepherosa Ziehau /* The packet must be at least the size of an IP header. */ 480515516c77SSepherosa Ziehau if (m->m_pkthdr.len < len) 480615516c77SSepherosa Ziehau return IPPROTO_DONE; 480715516c77SSepherosa Ziehau 480815516c77SSepherosa Ziehau /* The fixed IP header must reside completely in the first mbuf. */ 480915516c77SSepherosa Ziehau if (m->m_len < len) 481015516c77SSepherosa Ziehau return IPPROTO_DONE; 481115516c77SSepherosa Ziehau 481215516c77SSepherosa Ziehau ip = mtodo(m, hoff); 481315516c77SSepherosa Ziehau 481415516c77SSepherosa Ziehau /* Bound check the packet's stated IP header length. */ 481515516c77SSepherosa Ziehau iphlen = ip->ip_hl << 2; 481615516c77SSepherosa Ziehau if (iphlen < sizeof(struct ip)) /* minimum header length */ 481715516c77SSepherosa Ziehau return IPPROTO_DONE; 481815516c77SSepherosa Ziehau 481915516c77SSepherosa Ziehau /* The full IP header must reside completely in the one mbuf. */ 482015516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen) 482115516c77SSepherosa Ziehau return IPPROTO_DONE; 482215516c77SSepherosa Ziehau 482315516c77SSepherosa Ziehau iplen = ntohs(ip->ip_len); 482415516c77SSepherosa Ziehau 482515516c77SSepherosa Ziehau /* 482615516c77SSepherosa Ziehau * Check that the amount of data in the buffers is as 482715516c77SSepherosa Ziehau * at least much as the IP header would have us expect. 482815516c77SSepherosa Ziehau */ 482915516c77SSepherosa Ziehau if (m->m_pkthdr.len < hoff + iplen) 483015516c77SSepherosa Ziehau return IPPROTO_DONE; 483115516c77SSepherosa Ziehau 483215516c77SSepherosa Ziehau /* 483315516c77SSepherosa Ziehau * Ignore IP fragments. 483415516c77SSepherosa Ziehau */ 483515516c77SSepherosa Ziehau if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF)) 483615516c77SSepherosa Ziehau return IPPROTO_DONE; 483715516c77SSepherosa Ziehau 483815516c77SSepherosa Ziehau /* 483915516c77SSepherosa Ziehau * The TCP/IP or UDP/IP header must be entirely contained within 484015516c77SSepherosa Ziehau * the first fragment of a packet. 484115516c77SSepherosa Ziehau */ 484215516c77SSepherosa Ziehau switch (ip->ip_p) { 484315516c77SSepherosa Ziehau case IPPROTO_TCP: 484415516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct tcphdr)) 484515516c77SSepherosa Ziehau return IPPROTO_DONE; 484615516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct tcphdr)) 484715516c77SSepherosa Ziehau return IPPROTO_DONE; 484815516c77SSepherosa Ziehau th = (const struct tcphdr *)((const uint8_t *)ip + iphlen); 484915516c77SSepherosa Ziehau thoff = th->th_off << 2; 485015516c77SSepherosa Ziehau if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen) 485115516c77SSepherosa Ziehau return IPPROTO_DONE; 485215516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + thoff) 485315516c77SSepherosa Ziehau return IPPROTO_DONE; 485415516c77SSepherosa Ziehau break; 485515516c77SSepherosa Ziehau case IPPROTO_UDP: 485615516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct udphdr)) 485715516c77SSepherosa Ziehau return IPPROTO_DONE; 485815516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct udphdr)) 485915516c77SSepherosa Ziehau return IPPROTO_DONE; 486015516c77SSepherosa Ziehau break; 486115516c77SSepherosa Ziehau default: 486215516c77SSepherosa Ziehau if (iplen < iphlen) 486315516c77SSepherosa Ziehau return IPPROTO_DONE; 486415516c77SSepherosa Ziehau break; 486515516c77SSepherosa Ziehau } 486615516c77SSepherosa Ziehau return ip->ip_p; 486715516c77SSepherosa Ziehau } 486815516c77SSepherosa Ziehau 4869db76829bSSepherosa Ziehau static void 4870db76829bSSepherosa Ziehau hn_rxpkt_proto(const struct mbuf *m_new, int *l3proto, int *l4proto) 4871db76829bSSepherosa Ziehau { 4872db76829bSSepherosa Ziehau const struct ether_header *eh; 4873db76829bSSepherosa Ziehau uint16_t etype; 4874db76829bSSepherosa Ziehau int hoff; 4875db76829bSSepherosa Ziehau 4876db76829bSSepherosa Ziehau hoff = sizeof(*eh); 4877db76829bSSepherosa Ziehau /* Checked at the beginning of this function. */ 4878db76829bSSepherosa Ziehau KASSERT(m_new->m_len >= hoff, ("not ethernet frame")); 4879db76829bSSepherosa Ziehau 4880db76829bSSepherosa Ziehau eh = mtod(m_new, const struct ether_header *); 4881db76829bSSepherosa Ziehau etype = ntohs(eh->ether_type); 4882db76829bSSepherosa Ziehau if (etype == ETHERTYPE_VLAN) { 4883db76829bSSepherosa Ziehau const struct ether_vlan_header *evl; 4884db76829bSSepherosa Ziehau 4885db76829bSSepherosa Ziehau hoff = sizeof(*evl); 4886db76829bSSepherosa Ziehau if (m_new->m_len < hoff) 4887db76829bSSepherosa Ziehau return; 4888db76829bSSepherosa Ziehau evl = mtod(m_new, const struct ether_vlan_header *); 4889db76829bSSepherosa Ziehau etype = ntohs(evl->evl_proto); 4890db76829bSSepherosa Ziehau } 4891db76829bSSepherosa Ziehau *l3proto = etype; 4892db76829bSSepherosa Ziehau 4893db76829bSSepherosa Ziehau if (etype == ETHERTYPE_IP) 4894db76829bSSepherosa Ziehau *l4proto = hn_check_iplen(m_new, hoff); 4895db76829bSSepherosa Ziehau else 4896db76829bSSepherosa Ziehau *l4proto = IPPROTO_DONE; 4897db76829bSSepherosa Ziehau } 4898db76829bSSepherosa Ziehau 489915516c77SSepherosa Ziehau static int 490015516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt) 490115516c77SSepherosa Ziehau { 490215516c77SSepherosa Ziehau struct sysctl_oid_list *child; 490315516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 490415516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 490515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 490615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 490715516c77SSepherosa Ziehau int lroent_cnt; 490815516c77SSepherosa Ziehau #endif 490915516c77SSepherosa Ziehau #endif 491015516c77SSepherosa Ziehau int i; 491115516c77SSepherosa Ziehau 491215516c77SSepherosa Ziehau /* 491315516c77SSepherosa Ziehau * Create RXBUF for reception. 491415516c77SSepherosa Ziehau * 491515516c77SSepherosa Ziehau * NOTE: 491615516c77SSepherosa Ziehau * - It is shared by all channels. 491715516c77SSepherosa Ziehau * - A large enough buffer is allocated, certain version of NVSes 491815516c77SSepherosa Ziehau * may further limit the usable space. 491915516c77SSepherosa Ziehau */ 492015516c77SSepherosa Ziehau sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 492115516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma, 492215516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 492315516c77SSepherosa Ziehau if (sc->hn_rxbuf == NULL) { 492415516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate rxbuf failed\n"); 492515516c77SSepherosa Ziehau return (ENOMEM); 492615516c77SSepherosa Ziehau } 492715516c77SSepherosa Ziehau 492815516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = ring_cnt; 492915516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt; 493015516c77SSepherosa Ziehau 493115516c77SSepherosa Ziehau sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt, 493215516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 493315516c77SSepherosa Ziehau 493415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 493515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 493615516c77SSepherosa Ziehau lroent_cnt = hn_lro_entry_count; 493715516c77SSepherosa Ziehau if (lroent_cnt < TCP_LRO_ENTRIES) 493815516c77SSepherosa Ziehau lroent_cnt = TCP_LRO_ENTRIES; 493915516c77SSepherosa Ziehau if (bootverbose) 494015516c77SSepherosa Ziehau device_printf(dev, "LRO: entry count %d\n", lroent_cnt); 494115516c77SSepherosa Ziehau #endif 494215516c77SSepherosa Ziehau #endif /* INET || INET6 */ 494315516c77SSepherosa Ziehau 494415516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 494515516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 494615516c77SSepherosa Ziehau 494715516c77SSepherosa Ziehau /* Create dev.hn.UNIT.rx sysctl tree */ 494815516c77SSepherosa Ziehau sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx", 494915516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 495015516c77SSepherosa Ziehau 495115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 495215516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 495315516c77SSepherosa Ziehau 495415516c77SSepherosa Ziehau rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 495515516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE, 495615516c77SSepherosa Ziehau &rxr->hn_br_dma, BUS_DMA_WAITOK); 495715516c77SSepherosa Ziehau if (rxr->hn_br == NULL) { 495815516c77SSepherosa Ziehau device_printf(dev, "allocate bufring failed\n"); 495915516c77SSepherosa Ziehau return (ENOMEM); 496015516c77SSepherosa Ziehau } 496115516c77SSepherosa Ziehau 496215516c77SSepherosa Ziehau if (hn_trust_hosttcp) 496315516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP; 496415516c77SSepherosa Ziehau if (hn_trust_hostudp) 496515516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP; 496615516c77SSepherosa Ziehau if (hn_trust_hostip) 496715516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP; 4968642ec226SSepherosa Ziehau rxr->hn_mbuf_hash = NDIS_HASH_ALL; 496915516c77SSepherosa Ziehau rxr->hn_ifp = sc->hn_ifp; 497015516c77SSepherosa Ziehau if (i < sc->hn_tx_ring_cnt) 497115516c77SSepherosa Ziehau rxr->hn_txr = &sc->hn_tx_ring[i]; 497215516c77SSepherosa Ziehau rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF; 497315516c77SSepherosa Ziehau rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK); 497415516c77SSepherosa Ziehau rxr->hn_rx_idx = i; 497515516c77SSepherosa Ziehau rxr->hn_rxbuf = sc->hn_rxbuf; 497615516c77SSepherosa Ziehau 497715516c77SSepherosa Ziehau /* 497815516c77SSepherosa Ziehau * Initialize LRO. 497915516c77SSepherosa Ziehau */ 498015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 498115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 498215516c77SSepherosa Ziehau tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt, 498315516c77SSepherosa Ziehau hn_lro_mbufq_depth); 498415516c77SSepherosa Ziehau #else 498515516c77SSepherosa Ziehau tcp_lro_init(&rxr->hn_lro); 498615516c77SSepherosa Ziehau rxr->hn_lro.ifp = sc->hn_ifp; 498715516c77SSepherosa Ziehau #endif 498815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 498915516c77SSepherosa Ziehau rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF; 499015516c77SSepherosa Ziehau rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF; 499115516c77SSepherosa Ziehau #endif 499215516c77SSepherosa Ziehau #endif /* INET || INET6 */ 499315516c77SSepherosa Ziehau 499415516c77SSepherosa Ziehau if (sc->hn_rx_sysctl_tree != NULL) { 499515516c77SSepherosa Ziehau char name[16]; 499615516c77SSepherosa Ziehau 499715516c77SSepherosa Ziehau /* 499815516c77SSepherosa Ziehau * Create per RX ring sysctl tree: 499915516c77SSepherosa Ziehau * dev.hn.UNIT.rx.RINGID 500015516c77SSepherosa Ziehau */ 500115516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", i); 500215516c77SSepherosa Ziehau rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, 500315516c77SSepherosa Ziehau SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree), 500415516c77SSepherosa Ziehau OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 500515516c77SSepherosa Ziehau 500615516c77SSepherosa Ziehau if (rxr->hn_rx_sysctl_tree != NULL) { 500715516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 500815516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 500915516c77SSepherosa Ziehau OID_AUTO, "packets", CTLFLAG_RW, 501015516c77SSepherosa Ziehau &rxr->hn_pkts, "# of packets received"); 501115516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 501215516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 501315516c77SSepherosa Ziehau OID_AUTO, "rss_pkts", CTLFLAG_RW, 501415516c77SSepherosa Ziehau &rxr->hn_rss_pkts, 501515516c77SSepherosa Ziehau "# of packets w/ RSS info received"); 501615516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, 501715516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 501815516c77SSepherosa Ziehau OID_AUTO, "pktbuf_len", CTLFLAG_RD, 501915516c77SSepherosa Ziehau &rxr->hn_pktbuf_len, 0, 502015516c77SSepherosa Ziehau "Temporary channel packet buffer length"); 502115516c77SSepherosa Ziehau } 502215516c77SSepherosa Ziehau } 502315516c77SSepherosa Ziehau } 502415516c77SSepherosa Ziehau 502515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued", 502615516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 502715516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_queued), 502815516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 502915516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 503015516c77SSepherosa Ziehau #else 503115516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 503215516c77SSepherosa Ziehau #endif 503315516c77SSepherosa Ziehau "LU", "LRO queued"); 503415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed", 503515516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 503615516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_flushed), 503715516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 503815516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 503915516c77SSepherosa Ziehau #else 504015516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 504115516c77SSepherosa Ziehau #endif 504215516c77SSepherosa Ziehau "LU", "LRO flushed"); 504315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried", 504415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 504515516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro_tried), 504615516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries"); 504715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 504815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim", 504915516c77SSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 505015516c77SSepherosa Ziehau hn_lro_lenlim_sysctl, "IU", 505115516c77SSepherosa Ziehau "Max # of data bytes to be aggregated by LRO"); 505215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim", 505315516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 505415516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl, "I", 505515516c77SSepherosa Ziehau "Max # of ACKs to be aggregated by LRO"); 505615516c77SSepherosa Ziehau #endif 505715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp", 505815516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP, 505915516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 506015516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 506115516c77SSepherosa Ziehau "when csum info is missing"); 506215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp", 506315516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP, 506415516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 506515516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 506615516c77SSepherosa Ziehau "when csum info is missing"); 506715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip", 506815516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP, 506915516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 507015516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 507115516c77SSepherosa Ziehau "when csum info is missing"); 507215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip", 507315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 507415516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_ip), 507515516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP"); 507615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp", 507715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 507815516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_tcp), 507915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP"); 508015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp", 508115516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 508215516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_udp), 508315516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP"); 508415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted", 508515516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 508615516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_trusted), 508715516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", 508815516c77SSepherosa Ziehau "# of packets that we trust host's csum verification"); 508915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts", 509015516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 509115516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_small_pkts), 509215516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of small packets received"); 509315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed", 509415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 509515516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_ack_failed), 509615516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures"); 509715516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt", 509815516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings"); 509915516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse", 510015516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings"); 510115516c77SSepherosa Ziehau 510215516c77SSepherosa Ziehau return (0); 510315516c77SSepherosa Ziehau } 510415516c77SSepherosa Ziehau 510515516c77SSepherosa Ziehau static void 510615516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc) 510715516c77SSepherosa Ziehau { 510815516c77SSepherosa Ziehau int i; 510915516c77SSepherosa Ziehau 511015516c77SSepherosa Ziehau if (sc->hn_rxbuf != NULL) { 51112494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0) 511215516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf); 51132494d735SSepherosa Ziehau else 51142494d735SSepherosa Ziehau device_printf(sc->hn_dev, "RXBUF is referenced\n"); 511515516c77SSepherosa Ziehau sc->hn_rxbuf = NULL; 511615516c77SSepherosa Ziehau } 511715516c77SSepherosa Ziehau 511815516c77SSepherosa Ziehau if (sc->hn_rx_ring_cnt == 0) 511915516c77SSepherosa Ziehau return; 512015516c77SSepherosa Ziehau 512115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 512215516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 512315516c77SSepherosa Ziehau 512415516c77SSepherosa Ziehau if (rxr->hn_br == NULL) 512515516c77SSepherosa Ziehau continue; 51262494d735SSepherosa Ziehau if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) { 512715516c77SSepherosa Ziehau hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br); 51282494d735SSepherosa Ziehau } else { 51292494d735SSepherosa Ziehau device_printf(sc->hn_dev, 51302494d735SSepherosa Ziehau "%dth channel bufring is referenced", i); 51312494d735SSepherosa Ziehau } 513215516c77SSepherosa Ziehau rxr->hn_br = NULL; 513315516c77SSepherosa Ziehau 513415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 513515516c77SSepherosa Ziehau tcp_lro_free(&rxr->hn_lro); 513615516c77SSepherosa Ziehau #endif 513715516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 513815516c77SSepherosa Ziehau } 513915516c77SSepherosa Ziehau free(sc->hn_rx_ring, M_DEVBUF); 514015516c77SSepherosa Ziehau sc->hn_rx_ring = NULL; 514115516c77SSepherosa Ziehau 514215516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = 0; 514315516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = 0; 514415516c77SSepherosa Ziehau } 514515516c77SSepherosa Ziehau 514615516c77SSepherosa Ziehau static int 514715516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id) 514815516c77SSepherosa Ziehau { 514915516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[id]; 515015516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 515115516c77SSepherosa Ziehau bus_dma_tag_t parent_dtag; 515215516c77SSepherosa Ziehau int error, i; 515315516c77SSepherosa Ziehau 515415516c77SSepherosa Ziehau txr->hn_sc = sc; 515515516c77SSepherosa Ziehau txr->hn_tx_idx = id; 515615516c77SSepherosa Ziehau 515715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 515815516c77SSepherosa Ziehau mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); 515915516c77SSepherosa Ziehau #endif 516015516c77SSepherosa Ziehau mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF); 516115516c77SSepherosa Ziehau 516215516c77SSepherosa Ziehau txr->hn_txdesc_cnt = HN_TX_DESC_CNT; 516315516c77SSepherosa Ziehau txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt, 516415516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 516515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 516615516c77SSepherosa Ziehau SLIST_INIT(&txr->hn_txlist); 516715516c77SSepherosa Ziehau #else 516815516c77SSepherosa Ziehau txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF, 516915516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 517015516c77SSepherosa Ziehau #endif 517115516c77SSepherosa Ziehau 51720e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) { 51730e11868dSSepherosa Ziehau txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ( 51740e11868dSSepherosa Ziehau device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id)); 51750e11868dSSepherosa Ziehau } else { 5176fdd0222aSSepherosa Ziehau txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt]; 51770e11868dSSepherosa Ziehau } 517815516c77SSepherosa Ziehau 517923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 518015516c77SSepherosa Ziehau if (hn_use_if_start) { 518115516c77SSepherosa Ziehau txr->hn_txeof = hn_start_txeof; 518215516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr); 518315516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr); 518423bf9e15SSepherosa Ziehau } else 518523bf9e15SSepherosa Ziehau #endif 518623bf9e15SSepherosa Ziehau { 518715516c77SSepherosa Ziehau int br_depth; 518815516c77SSepherosa Ziehau 518915516c77SSepherosa Ziehau txr->hn_txeof = hn_xmit_txeof; 519015516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr); 519115516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr); 519215516c77SSepherosa Ziehau 519315516c77SSepherosa Ziehau br_depth = hn_get_txswq_depth(txr); 519415516c77SSepherosa Ziehau txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF, 519515516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 519615516c77SSepherosa Ziehau } 519715516c77SSepherosa Ziehau 519815516c77SSepherosa Ziehau txr->hn_direct_tx_size = hn_direct_tx_size; 519915516c77SSepherosa Ziehau 520015516c77SSepherosa Ziehau /* 520115516c77SSepherosa Ziehau * Always schedule transmission instead of trying to do direct 520215516c77SSepherosa Ziehau * transmission. This one gives the best performance so far. 520315516c77SSepherosa Ziehau */ 520415516c77SSepherosa Ziehau txr->hn_sched_tx = 1; 520515516c77SSepherosa Ziehau 520615516c77SSepherosa Ziehau parent_dtag = bus_get_dma_tag(dev); 520715516c77SSepherosa Ziehau 520815516c77SSepherosa Ziehau /* DMA tag for RNDIS packet messages. */ 520915516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 521015516c77SSepherosa Ziehau HN_RNDIS_PKT_ALIGN, /* alignment */ 521115516c77SSepherosa Ziehau HN_RNDIS_PKT_BOUNDARY, /* boundary */ 521215516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 521315516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 521415516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 521515516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsize */ 521615516c77SSepherosa Ziehau 1, /* nsegments */ 521715516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsegsize */ 521815516c77SSepherosa Ziehau 0, /* flags */ 521915516c77SSepherosa Ziehau NULL, /* lockfunc */ 522015516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 522115516c77SSepherosa Ziehau &txr->hn_tx_rndis_dtag); 522215516c77SSepherosa Ziehau if (error) { 522315516c77SSepherosa Ziehau device_printf(dev, "failed to create rndis dmatag\n"); 522415516c77SSepherosa Ziehau return error; 522515516c77SSepherosa Ziehau } 522615516c77SSepherosa Ziehau 522715516c77SSepherosa Ziehau /* DMA tag for data. */ 522815516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 522915516c77SSepherosa Ziehau 1, /* alignment */ 523015516c77SSepherosa Ziehau HN_TX_DATA_BOUNDARY, /* boundary */ 523115516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 523215516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 523315516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 523415516c77SSepherosa Ziehau HN_TX_DATA_MAXSIZE, /* maxsize */ 523515516c77SSepherosa Ziehau HN_TX_DATA_SEGCNT_MAX, /* nsegments */ 523615516c77SSepherosa Ziehau HN_TX_DATA_SEGSIZE, /* maxsegsize */ 523715516c77SSepherosa Ziehau 0, /* flags */ 523815516c77SSepherosa Ziehau NULL, /* lockfunc */ 523915516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 524015516c77SSepherosa Ziehau &txr->hn_tx_data_dtag); 524115516c77SSepherosa Ziehau if (error) { 524215516c77SSepherosa Ziehau device_printf(dev, "failed to create data dmatag\n"); 524315516c77SSepherosa Ziehau return error; 524415516c77SSepherosa Ziehau } 524515516c77SSepherosa Ziehau 524615516c77SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) { 524715516c77SSepherosa Ziehau struct hn_txdesc *txd = &txr->hn_txdesc[i]; 524815516c77SSepherosa Ziehau 524915516c77SSepherosa Ziehau txd->txr = txr; 525015516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 5251dc13fee6SSepherosa Ziehau STAILQ_INIT(&txd->agg_list); 525215516c77SSepherosa Ziehau 525315516c77SSepherosa Ziehau /* 525415516c77SSepherosa Ziehau * Allocate and load RNDIS packet message. 525515516c77SSepherosa Ziehau */ 525615516c77SSepherosa Ziehau error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag, 525715516c77SSepherosa Ziehau (void **)&txd->rndis_pkt, 525815516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 525915516c77SSepherosa Ziehau &txd->rndis_pkt_dmap); 526015516c77SSepherosa Ziehau if (error) { 526115516c77SSepherosa Ziehau device_printf(dev, 526215516c77SSepherosa Ziehau "failed to allocate rndis_packet_msg, %d\n", i); 526315516c77SSepherosa Ziehau return error; 526415516c77SSepherosa Ziehau } 526515516c77SSepherosa Ziehau 526615516c77SSepherosa Ziehau error = bus_dmamap_load(txr->hn_tx_rndis_dtag, 526715516c77SSepherosa Ziehau txd->rndis_pkt_dmap, 526815516c77SSepherosa Ziehau txd->rndis_pkt, HN_RNDIS_PKT_LEN, 526915516c77SSepherosa Ziehau hyperv_dma_map_paddr, &txd->rndis_pkt_paddr, 527015516c77SSepherosa Ziehau BUS_DMA_NOWAIT); 527115516c77SSepherosa Ziehau if (error) { 527215516c77SSepherosa Ziehau device_printf(dev, 527315516c77SSepherosa Ziehau "failed to load rndis_packet_msg, %d\n", i); 527415516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 527515516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 527615516c77SSepherosa Ziehau return error; 527715516c77SSepherosa Ziehau } 527815516c77SSepherosa Ziehau 527915516c77SSepherosa Ziehau /* DMA map for TX data. */ 528015516c77SSepherosa Ziehau error = bus_dmamap_create(txr->hn_tx_data_dtag, 0, 528115516c77SSepherosa Ziehau &txd->data_dmap); 528215516c77SSepherosa Ziehau if (error) { 528315516c77SSepherosa Ziehau device_printf(dev, 528415516c77SSepherosa Ziehau "failed to allocate tx data dmamap\n"); 528515516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, 528615516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 528715516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 528815516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 528915516c77SSepherosa Ziehau return error; 529015516c77SSepherosa Ziehau } 529115516c77SSepherosa Ziehau 529215516c77SSepherosa Ziehau /* All set, put it to list */ 529315516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 529415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 529515516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 529615516c77SSepherosa Ziehau #else 529715516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 529815516c77SSepherosa Ziehau #endif 529915516c77SSepherosa Ziehau } 530015516c77SSepherosa Ziehau txr->hn_txdesc_avail = txr->hn_txdesc_cnt; 530115516c77SSepherosa Ziehau 530215516c77SSepherosa Ziehau if (sc->hn_tx_sysctl_tree != NULL) { 530315516c77SSepherosa Ziehau struct sysctl_oid_list *child; 530415516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 530515516c77SSepherosa Ziehau char name[16]; 530615516c77SSepherosa Ziehau 530715516c77SSepherosa Ziehau /* 530815516c77SSepherosa Ziehau * Create per TX ring sysctl tree: 530915516c77SSepherosa Ziehau * dev.hn.UNIT.tx.RINGID 531015516c77SSepherosa Ziehau */ 531115516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 531215516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree); 531315516c77SSepherosa Ziehau 531415516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", id); 531515516c77SSepherosa Ziehau txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, 531615516c77SSepherosa Ziehau name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 531715516c77SSepherosa Ziehau 531815516c77SSepherosa Ziehau if (txr->hn_tx_sysctl_tree != NULL) { 531915516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree); 532015516c77SSepherosa Ziehau 532185e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 532215516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail", 532315516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_txdesc_avail, 0, 532415516c77SSepherosa Ziehau "# of available TX descs"); 532585e4ae1eSSepherosa Ziehau #endif 532623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 532723bf9e15SSepherosa Ziehau if (!hn_use_if_start) 532823bf9e15SSepherosa Ziehau #endif 532923bf9e15SSepherosa Ziehau { 533015516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive", 533115516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_oactive, 0, 533215516c77SSepherosa Ziehau "over active"); 533315516c77SSepherosa Ziehau } 533415516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets", 533515516c77SSepherosa Ziehau CTLFLAG_RW, &txr->hn_pkts, 533615516c77SSepherosa Ziehau "# of packets transmitted"); 5337dc13fee6SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends", 5338dc13fee6SSepherosa Ziehau CTLFLAG_RW, &txr->hn_sends, "# of sends"); 533915516c77SSepherosa Ziehau } 534015516c77SSepherosa Ziehau } 534115516c77SSepherosa Ziehau 534215516c77SSepherosa Ziehau return 0; 534315516c77SSepherosa Ziehau } 534415516c77SSepherosa Ziehau 534515516c77SSepherosa Ziehau static void 534615516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd) 534715516c77SSepherosa Ziehau { 534815516c77SSepherosa Ziehau struct hn_tx_ring *txr = txd->txr; 534915516c77SSepherosa Ziehau 535015516c77SSepherosa Ziehau KASSERT(txd->m == NULL, ("still has mbuf installed")); 535115516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped")); 535215516c77SSepherosa Ziehau 535315516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap); 535415516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt, 535515516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 535615516c77SSepherosa Ziehau bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap); 535715516c77SSepherosa Ziehau } 535815516c77SSepherosa Ziehau 535915516c77SSepherosa Ziehau static void 536025641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd) 536125641fc7SSepherosa Ziehau { 536225641fc7SSepherosa Ziehau 536325641fc7SSepherosa Ziehau KASSERT(txd->refs == 0 || txd->refs == 1, 536425641fc7SSepherosa Ziehau ("invalid txd refs %d", txd->refs)); 536525641fc7SSepherosa Ziehau 536625641fc7SSepherosa Ziehau /* Aggregated txds will be freed by their aggregating txd. */ 536725641fc7SSepherosa Ziehau if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) { 536825641fc7SSepherosa Ziehau int freed; 536925641fc7SSepherosa Ziehau 537025641fc7SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 537125641fc7SSepherosa Ziehau KASSERT(freed, ("can't free txdesc")); 537225641fc7SSepherosa Ziehau } 537325641fc7SSepherosa Ziehau } 537425641fc7SSepherosa Ziehau 537525641fc7SSepherosa Ziehau static void 537615516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr) 537715516c77SSepherosa Ziehau { 537825641fc7SSepherosa Ziehau int i; 537915516c77SSepherosa Ziehau 538015516c77SSepherosa Ziehau if (txr->hn_txdesc == NULL) 538115516c77SSepherosa Ziehau return; 538215516c77SSepherosa Ziehau 538325641fc7SSepherosa Ziehau /* 538425641fc7SSepherosa Ziehau * NOTE: 538525641fc7SSepherosa Ziehau * Because the freeing of aggregated txds will be deferred 538625641fc7SSepherosa Ziehau * to the aggregating txd, two passes are used here: 538725641fc7SSepherosa Ziehau * - The first pass GCes any pending txds. This GC is necessary, 538825641fc7SSepherosa Ziehau * since if the channels are revoked, hypervisor will not 538925641fc7SSepherosa Ziehau * deliver send-done for all pending txds. 539025641fc7SSepherosa Ziehau * - The second pass frees the busdma stuffs, i.e. after all txds 539125641fc7SSepherosa Ziehau * were freed. 539225641fc7SSepherosa Ziehau */ 539325641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 539425641fc7SSepherosa Ziehau hn_txdesc_gc(txr, &txr->hn_txdesc[i]); 539525641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 539625641fc7SSepherosa Ziehau hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]); 539715516c77SSepherosa Ziehau 539815516c77SSepherosa Ziehau if (txr->hn_tx_data_dtag != NULL) 539915516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_data_dtag); 540015516c77SSepherosa Ziehau if (txr->hn_tx_rndis_dtag != NULL) 540115516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_rndis_dtag); 540215516c77SSepherosa Ziehau 540315516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 540415516c77SSepherosa Ziehau buf_ring_free(txr->hn_txdesc_br, M_DEVBUF); 540515516c77SSepherosa Ziehau #endif 540615516c77SSepherosa Ziehau 540715516c77SSepherosa Ziehau free(txr->hn_txdesc, M_DEVBUF); 540815516c77SSepherosa Ziehau txr->hn_txdesc = NULL; 540915516c77SSepherosa Ziehau 541015516c77SSepherosa Ziehau if (txr->hn_mbuf_br != NULL) 541115516c77SSepherosa Ziehau buf_ring_free(txr->hn_mbuf_br, M_DEVBUF); 541215516c77SSepherosa Ziehau 541315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 541415516c77SSepherosa Ziehau mtx_destroy(&txr->hn_txlist_spin); 541515516c77SSepherosa Ziehau #endif 541615516c77SSepherosa Ziehau mtx_destroy(&txr->hn_tx_lock); 541715516c77SSepherosa Ziehau } 541815516c77SSepherosa Ziehau 541915516c77SSepherosa Ziehau static int 542015516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt) 542115516c77SSepherosa Ziehau { 542215516c77SSepherosa Ziehau struct sysctl_oid_list *child; 542315516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 542415516c77SSepherosa Ziehau int i; 542515516c77SSepherosa Ziehau 542615516c77SSepherosa Ziehau /* 542715516c77SSepherosa Ziehau * Create TXBUF for chimney sending. 542815516c77SSepherosa Ziehau * 542915516c77SSepherosa Ziehau * NOTE: It is shared by all channels. 543015516c77SSepherosa Ziehau */ 543115516c77SSepherosa Ziehau sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), 543215516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma, 543315516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 543415516c77SSepherosa Ziehau if (sc->hn_chim == NULL) { 543515516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate txbuf failed\n"); 543615516c77SSepherosa Ziehau return (ENOMEM); 543715516c77SSepherosa Ziehau } 543815516c77SSepherosa Ziehau 543915516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = ring_cnt; 544015516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 544115516c77SSepherosa Ziehau 544215516c77SSepherosa Ziehau sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt, 544315516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 544415516c77SSepherosa Ziehau 544515516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(sc->hn_dev); 544615516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev)); 544715516c77SSepherosa Ziehau 544815516c77SSepherosa Ziehau /* Create dev.hn.UNIT.tx sysctl tree */ 544915516c77SSepherosa Ziehau sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx", 545015516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 545115516c77SSepherosa Ziehau 545215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 545315516c77SSepherosa Ziehau int error; 545415516c77SSepherosa Ziehau 545515516c77SSepherosa Ziehau error = hn_tx_ring_create(sc, i); 545615516c77SSepherosa Ziehau if (error) 545715516c77SSepherosa Ziehau return error; 545815516c77SSepherosa Ziehau } 545915516c77SSepherosa Ziehau 546015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs", 546115516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 546215516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_no_txdescs), 546315516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs"); 546415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed", 546515516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 546615516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_send_failed), 546715516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure"); 546815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed", 546915516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 547015516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_txdma_failed), 547115516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure"); 5472dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed", 5473dc13fee6SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 5474dc13fee6SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_flush_failed), 5475dc13fee6SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", 5476dc13fee6SSepherosa Ziehau "# of packet transmission aggregation flush failure"); 547715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed", 547815516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 547915516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_collapsed), 548015516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed"); 548115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney", 548215516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 548315516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney), 548415516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send"); 548515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried", 548615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 548715516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney_tried), 548815516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries"); 548915516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt", 549015516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0, 549115516c77SSepherosa Ziehau "# of total TX descs"); 549215516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max", 549315516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_chim_szmax, 0, 549415516c77SSepherosa Ziehau "Chimney send packet size upper boundary"); 549515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size", 549615516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 549715516c77SSepherosa Ziehau hn_chim_size_sysctl, "I", "Chimney send packet size limit"); 549815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size", 549915516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 550015516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_direct_tx_size), 550115516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 550215516c77SSepherosa Ziehau "Size of the packet for direct transmission"); 550315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx", 550415516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 550515516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_sched_tx), 550615516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 550715516c77SSepherosa Ziehau "Always schedule transmission " 550815516c77SSepherosa Ziehau "instead of doing direct transmission"); 550915516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt", 551015516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings"); 551115516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse", 551215516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings"); 5513dc13fee6SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax", 5514dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0, 5515dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation size"); 5516dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax", 5517dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 5518dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl, "I", 5519dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation packets"); 5520dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align", 5521dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 5522dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl, "I", 5523dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation alignment"); 552415516c77SSepherosa Ziehau 552515516c77SSepherosa Ziehau return 0; 552615516c77SSepherosa Ziehau } 552715516c77SSepherosa Ziehau 552815516c77SSepherosa Ziehau static void 552915516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size) 553015516c77SSepherosa Ziehau { 553115516c77SSepherosa Ziehau int i; 553215516c77SSepherosa Ziehau 5533a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 553415516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_chim_size = chim_size; 553515516c77SSepherosa Ziehau } 553615516c77SSepherosa Ziehau 553715516c77SSepherosa Ziehau static void 553815516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu) 553915516c77SSepherosa Ziehau { 554015516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 55419c6cae24SSepherosa Ziehau u_int hw_tsomax; 554215516c77SSepherosa Ziehau int tso_minlen; 554315516c77SSepherosa Ziehau 55449c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 55459c6cae24SSepherosa Ziehau 554615516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0) 554715516c77SSepherosa Ziehau return; 554815516c77SSepherosa Ziehau 554915516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_sgmin >= 2, 555015516c77SSepherosa Ziehau ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin)); 555115516c77SSepherosa Ziehau tso_minlen = sc->hn_ndis_tso_sgmin * mtu; 555215516c77SSepherosa Ziehau 555315516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen && 555415516c77SSepherosa Ziehau sc->hn_ndis_tso_szmax <= IP_MAXPACKET, 555515516c77SSepherosa Ziehau ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax)); 555615516c77SSepherosa Ziehau 555715516c77SSepherosa Ziehau if (tso_maxlen < tso_minlen) 555815516c77SSepherosa Ziehau tso_maxlen = tso_minlen; 555915516c77SSepherosa Ziehau else if (tso_maxlen > IP_MAXPACKET) 556015516c77SSepherosa Ziehau tso_maxlen = IP_MAXPACKET; 556115516c77SSepherosa Ziehau if (tso_maxlen > sc->hn_ndis_tso_szmax) 556215516c77SSepherosa Ziehau tso_maxlen = sc->hn_ndis_tso_szmax; 55639c6cae24SSepherosa Ziehau hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 55649c6cae24SSepherosa Ziehau 55659c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 55669c6cae24SSepherosa Ziehau if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax) 55679c6cae24SSepherosa Ziehau hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax; 55689c6cae24SSepherosa Ziehau } 55699c6cae24SSepherosa Ziehau ifp->if_hw_tsomax = hw_tsomax; 557015516c77SSepherosa Ziehau if (bootverbose) 557115516c77SSepherosa Ziehau if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax); 557215516c77SSepherosa Ziehau } 557315516c77SSepherosa Ziehau 557415516c77SSepherosa Ziehau static void 557515516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc) 557615516c77SSepherosa Ziehau { 557715516c77SSepherosa Ziehau uint64_t csum_assist; 557815516c77SSepherosa Ziehau int i; 557915516c77SSepherosa Ziehau 558015516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 558115516c77SSepherosa Ziehau if (hn_tx_chimney_size > 0 && 558215516c77SSepherosa Ziehau hn_tx_chimney_size < sc->hn_chim_szmax) 558315516c77SSepherosa Ziehau hn_set_chim_size(sc, hn_tx_chimney_size); 558415516c77SSepherosa Ziehau 558515516c77SSepherosa Ziehau csum_assist = 0; 558615516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_IPCS) 558715516c77SSepherosa Ziehau csum_assist |= CSUM_IP; 558815516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP4CS) 558915516c77SSepherosa Ziehau csum_assist |= CSUM_IP_TCP; 55902be266caSSepherosa Ziehau if ((sc->hn_caps & HN_CAP_UDP4CS) && hn_enable_udp4cs) 559115516c77SSepherosa Ziehau csum_assist |= CSUM_IP_UDP; 559215516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP6CS) 559315516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_TCP; 55942be266caSSepherosa Ziehau if ((sc->hn_caps & HN_CAP_UDP6CS) && hn_enable_udp6cs) 559515516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_UDP; 559615516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 559715516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_csum_assist = csum_assist; 559815516c77SSepherosa Ziehau 559915516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_HASHVAL) { 560015516c77SSepherosa Ziehau /* 560115516c77SSepherosa Ziehau * Support HASHVAL pktinfo on TX path. 560215516c77SSepherosa Ziehau */ 560315516c77SSepherosa Ziehau if (bootverbose) 560415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n"); 560515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 560615516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL; 560715516c77SSepherosa Ziehau } 560815516c77SSepherosa Ziehau } 560915516c77SSepherosa Ziehau 561015516c77SSepherosa Ziehau static void 5611db76829bSSepherosa Ziehau hn_fixup_rx_data(struct hn_softc *sc) 5612db76829bSSepherosa Ziehau { 5613db76829bSSepherosa Ziehau 5614db76829bSSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDPHASH) { 5615db76829bSSepherosa Ziehau int i; 5616db76829bSSepherosa Ziehau 5617db76829bSSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 5618db76829bSSepherosa Ziehau sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_UDP_HASH; 5619db76829bSSepherosa Ziehau } 5620db76829bSSepherosa Ziehau } 5621db76829bSSepherosa Ziehau 5622db76829bSSepherosa Ziehau static void 562315516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc) 562415516c77SSepherosa Ziehau { 562515516c77SSepherosa Ziehau int i; 562615516c77SSepherosa Ziehau 562715516c77SSepherosa Ziehau if (sc->hn_chim != NULL) { 56282494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) { 562915516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim); 56302494d735SSepherosa Ziehau } else { 56312494d735SSepherosa Ziehau device_printf(sc->hn_dev, 56322494d735SSepherosa Ziehau "chimney sending buffer is referenced"); 56332494d735SSepherosa Ziehau } 563415516c77SSepherosa Ziehau sc->hn_chim = NULL; 563515516c77SSepherosa Ziehau } 563615516c77SSepherosa Ziehau 563715516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt == 0) 563815516c77SSepherosa Ziehau return; 563915516c77SSepherosa Ziehau 564015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 564115516c77SSepherosa Ziehau hn_tx_ring_destroy(&sc->hn_tx_ring[i]); 564215516c77SSepherosa Ziehau 564315516c77SSepherosa Ziehau free(sc->hn_tx_ring, M_DEVBUF); 564415516c77SSepherosa Ziehau sc->hn_tx_ring = NULL; 564515516c77SSepherosa Ziehau 564615516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = 0; 564715516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = 0; 564815516c77SSepherosa Ziehau } 564915516c77SSepherosa Ziehau 565023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 565123bf9e15SSepherosa Ziehau 565215516c77SSepherosa Ziehau static void 565315516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused) 565415516c77SSepherosa Ziehau { 565515516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 565615516c77SSepherosa Ziehau 565715516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 565815516c77SSepherosa Ziehau hn_start_locked(txr, 0); 565915516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 566015516c77SSepherosa Ziehau } 566115516c77SSepherosa Ziehau 566223bf9e15SSepherosa Ziehau static int 566323bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len) 566423bf9e15SSepherosa Ziehau { 566523bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 566623bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 5667dc13fee6SSepherosa Ziehau int sched = 0; 566823bf9e15SSepherosa Ziehau 566923bf9e15SSepherosa Ziehau KASSERT(hn_use_if_start, 567023bf9e15SSepherosa Ziehau ("hn_start_locked is called, when if_start is disabled")); 567123bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 567223bf9e15SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 5673dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 567423bf9e15SSepherosa Ziehau 567523bf9e15SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 5676dc13fee6SSepherosa Ziehau return (0); 567723bf9e15SSepherosa Ziehau 567823bf9e15SSepherosa Ziehau if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 567923bf9e15SSepherosa Ziehau IFF_DRV_RUNNING) 5680dc13fee6SSepherosa Ziehau return (0); 568123bf9e15SSepherosa Ziehau 568223bf9e15SSepherosa Ziehau while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 568323bf9e15SSepherosa Ziehau struct hn_txdesc *txd; 568423bf9e15SSepherosa Ziehau struct mbuf *m_head; 568523bf9e15SSepherosa Ziehau int error; 568623bf9e15SSepherosa Ziehau 568723bf9e15SSepherosa Ziehau IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 568823bf9e15SSepherosa Ziehau if (m_head == NULL) 568923bf9e15SSepherosa Ziehau break; 569023bf9e15SSepherosa Ziehau 569123bf9e15SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 569223bf9e15SSepherosa Ziehau /* 569323bf9e15SSepherosa Ziehau * This sending could be time consuming; let callers 569423bf9e15SSepherosa Ziehau * dispatch this packet sending (and sending of any 569523bf9e15SSepherosa Ziehau * following up packets) to tx taskqueue. 569623bf9e15SSepherosa Ziehau */ 569723bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 5698dc13fee6SSepherosa Ziehau sched = 1; 5699dc13fee6SSepherosa Ziehau break; 570023bf9e15SSepherosa Ziehau } 570123bf9e15SSepherosa Ziehau 5702edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 5703edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 5704edd3f315SSepherosa Ziehau m_head = hn_tso_fixup(m_head); 5705edd3f315SSepherosa Ziehau if (__predict_false(m_head == NULL)) { 5706edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 5707edd3f315SSepherosa Ziehau continue; 5708edd3f315SSepherosa Ziehau } 5709c49d47daSSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & 5710c49d47daSSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) { 5711c49d47daSSepherosa Ziehau m_head = hn_set_hlen(m_head); 5712c49d47daSSepherosa Ziehau if (__predict_false(m_head == NULL)) { 5713c49d47daSSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 5714c49d47daSSepherosa Ziehau continue; 5715c49d47daSSepherosa Ziehau } 5716edd3f315SSepherosa Ziehau } 5717edd3f315SSepherosa Ziehau #endif 5718edd3f315SSepherosa Ziehau 571923bf9e15SSepherosa Ziehau txd = hn_txdesc_get(txr); 572023bf9e15SSepherosa Ziehau if (txd == NULL) { 572123bf9e15SSepherosa Ziehau txr->hn_no_txdescs++; 572223bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 572323bf9e15SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 572423bf9e15SSepherosa Ziehau break; 572523bf9e15SSepherosa Ziehau } 572623bf9e15SSepherosa Ziehau 5727dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 572823bf9e15SSepherosa Ziehau if (error) { 572923bf9e15SSepherosa Ziehau /* Both txd and m_head are freed */ 5730dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 5731dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 573223bf9e15SSepherosa Ziehau continue; 573323bf9e15SSepherosa Ziehau } 573423bf9e15SSepherosa Ziehau 5735dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 5736dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 5737dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5738dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5739dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 5740dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 5741dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 5742dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 5743dc13fee6SSepherosa Ziehau break; 5744dc13fee6SSepherosa Ziehau } 5745dc13fee6SSepherosa Ziehau } else { 5746dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 574723bf9e15SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 574823bf9e15SSepherosa Ziehau if (__predict_false(error)) { 574923bf9e15SSepherosa Ziehau /* txd is freed, but m_head is not */ 575023bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 5751dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 5752dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 575323bf9e15SSepherosa Ziehau break; 575423bf9e15SSepherosa Ziehau } 575523bf9e15SSepherosa Ziehau } 5756dc13fee6SSepherosa Ziehau } 5757dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 5758dc13fee6SSepherosa Ziehau else { 5759dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 5760dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 5761dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5762dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5763dc13fee6SSepherosa Ziehau } 5764dc13fee6SSepherosa Ziehau #endif 5765dc13fee6SSepherosa Ziehau } 5766dc13fee6SSepherosa Ziehau 5767dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 5768dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 5769dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 5770dc13fee6SSepherosa Ziehau return (sched); 577123bf9e15SSepherosa Ziehau } 577223bf9e15SSepherosa Ziehau 577323bf9e15SSepherosa Ziehau static void 577423bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp) 577523bf9e15SSepherosa Ziehau { 577623bf9e15SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 577723bf9e15SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[0]; 577823bf9e15SSepherosa Ziehau 577923bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 578023bf9e15SSepherosa Ziehau goto do_sched; 578123bf9e15SSepherosa Ziehau 578223bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 578323bf9e15SSepherosa Ziehau int sched; 578423bf9e15SSepherosa Ziehau 578523bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 578623bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 578723bf9e15SSepherosa Ziehau if (!sched) 578823bf9e15SSepherosa Ziehau return; 578923bf9e15SSepherosa Ziehau } 579023bf9e15SSepherosa Ziehau do_sched: 579123bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 579223bf9e15SSepherosa Ziehau } 579323bf9e15SSepherosa Ziehau 579415516c77SSepherosa Ziehau static void 579515516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused) 579615516c77SSepherosa Ziehau { 579715516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 579815516c77SSepherosa Ziehau 579915516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 580015516c77SSepherosa Ziehau atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE); 580115516c77SSepherosa Ziehau hn_start_locked(txr, 0); 580215516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 580315516c77SSepherosa Ziehau } 580415516c77SSepherosa Ziehau 580523bf9e15SSepherosa Ziehau static void 580623bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr) 580723bf9e15SSepherosa Ziehau { 580823bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 580923bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 581023bf9e15SSepherosa Ziehau 581123bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 581223bf9e15SSepherosa Ziehau 581323bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 581423bf9e15SSepherosa Ziehau goto do_sched; 581523bf9e15SSepherosa Ziehau 581623bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 581723bf9e15SSepherosa Ziehau int sched; 581823bf9e15SSepherosa Ziehau 581923bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 582023bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 582123bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 582223bf9e15SSepherosa Ziehau if (sched) { 582323bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 582423bf9e15SSepherosa Ziehau &txr->hn_tx_task); 582523bf9e15SSepherosa Ziehau } 582623bf9e15SSepherosa Ziehau } else { 582723bf9e15SSepherosa Ziehau do_sched: 582823bf9e15SSepherosa Ziehau /* 582923bf9e15SSepherosa Ziehau * Release the OACTIVE earlier, with the hope, that 583023bf9e15SSepherosa Ziehau * others could catch up. The task will clear the 583123bf9e15SSepherosa Ziehau * flag again with the hn_tx_lock to avoid possible 583223bf9e15SSepherosa Ziehau * races. 583323bf9e15SSepherosa Ziehau */ 583423bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 583523bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 583623bf9e15SSepherosa Ziehau } 583723bf9e15SSepherosa Ziehau } 583823bf9e15SSepherosa Ziehau 583923bf9e15SSepherosa Ziehau #endif /* HN_IFSTART_SUPPORT */ 584023bf9e15SSepherosa Ziehau 584115516c77SSepherosa Ziehau static int 584215516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len) 584315516c77SSepherosa Ziehau { 584415516c77SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 584515516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 584615516c77SSepherosa Ziehau struct mbuf *m_head; 5847dc13fee6SSepherosa Ziehau int sched = 0; 584815516c77SSepherosa Ziehau 584915516c77SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 585023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 585115516c77SSepherosa Ziehau KASSERT(hn_use_if_start == 0, 585215516c77SSepherosa Ziehau ("hn_xmit is called, when if_start is enabled")); 585323bf9e15SSepherosa Ziehau #endif 5854dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 585515516c77SSepherosa Ziehau 585615516c77SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 5857dc13fee6SSepherosa Ziehau return (0); 585815516c77SSepherosa Ziehau 585915516c77SSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive) 5860dc13fee6SSepherosa Ziehau return (0); 586115516c77SSepherosa Ziehau 586215516c77SSepherosa Ziehau while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) { 586315516c77SSepherosa Ziehau struct hn_txdesc *txd; 586415516c77SSepherosa Ziehau int error; 586515516c77SSepherosa Ziehau 586615516c77SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 586715516c77SSepherosa Ziehau /* 586815516c77SSepherosa Ziehau * This sending could be time consuming; let callers 586915516c77SSepherosa Ziehau * dispatch this packet sending (and sending of any 587015516c77SSepherosa Ziehau * following up packets) to tx taskqueue. 587115516c77SSepherosa Ziehau */ 587215516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 5873dc13fee6SSepherosa Ziehau sched = 1; 5874dc13fee6SSepherosa Ziehau break; 587515516c77SSepherosa Ziehau } 587615516c77SSepherosa Ziehau 587715516c77SSepherosa Ziehau txd = hn_txdesc_get(txr); 587815516c77SSepherosa Ziehau if (txd == NULL) { 587915516c77SSepherosa Ziehau txr->hn_no_txdescs++; 588015516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 588115516c77SSepherosa Ziehau txr->hn_oactive = 1; 588215516c77SSepherosa Ziehau break; 588315516c77SSepherosa Ziehau } 588415516c77SSepherosa Ziehau 5885dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 588615516c77SSepherosa Ziehau if (error) { 588715516c77SSepherosa Ziehau /* Both txd and m_head are freed; discard */ 5888dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 5889dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 589015516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 589115516c77SSepherosa Ziehau continue; 589215516c77SSepherosa Ziehau } 589315516c77SSepherosa Ziehau 5894dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 5895dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 5896dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5897dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5898dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 589915516c77SSepherosa Ziehau if (__predict_false(error)) { 590015516c77SSepherosa Ziehau txr->hn_oactive = 1; 590115516c77SSepherosa Ziehau break; 590215516c77SSepherosa Ziehau } 5903dc13fee6SSepherosa Ziehau } else { 5904dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 5905dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 5906dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 5907dc13fee6SSepherosa Ziehau /* txd is freed, but m_head is not */ 5908dc13fee6SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, 5909dc13fee6SSepherosa Ziehau m_head); 5910dc13fee6SSepherosa Ziehau txr->hn_oactive = 1; 5911dc13fee6SSepherosa Ziehau break; 5912dc13fee6SSepherosa Ziehau } 5913dc13fee6SSepherosa Ziehau } 5914dc13fee6SSepherosa Ziehau } 5915dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 5916dc13fee6SSepherosa Ziehau else { 5917dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 5918dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 5919dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5920dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5921dc13fee6SSepherosa Ziehau } 5922dc13fee6SSepherosa Ziehau #endif 592315516c77SSepherosa Ziehau 592415516c77SSepherosa Ziehau /* Sent */ 592515516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 592615516c77SSepherosa Ziehau } 5927dc13fee6SSepherosa Ziehau 5928dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 5929dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 5930dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 5931dc13fee6SSepherosa Ziehau return (sched); 593215516c77SSepherosa Ziehau } 593315516c77SSepherosa Ziehau 593415516c77SSepherosa Ziehau static int 593515516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m) 593615516c77SSepherosa Ziehau { 593715516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 593815516c77SSepherosa Ziehau struct hn_tx_ring *txr; 593915516c77SSepherosa Ziehau int error, idx = 0; 594015516c77SSepherosa Ziehau 59419c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) { 59429c6cae24SSepherosa Ziehau struct rm_priotracker pt; 59439c6cae24SSepherosa Ziehau 59449c6cae24SSepherosa Ziehau rm_rlock(&sc->hn_vf_lock, &pt); 59459c6cae24SSepherosa Ziehau if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { 59469c6cae24SSepherosa Ziehau struct mbuf *m_bpf = NULL; 59479c6cae24SSepherosa Ziehau int obytes, omcast; 59489c6cae24SSepherosa Ziehau 59499c6cae24SSepherosa Ziehau obytes = m->m_pkthdr.len; 59507898a1f4SEric van Gyzen omcast = (m->m_flags & M_MCAST) != 0; 59519c6cae24SSepherosa Ziehau 59529c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) { 59539c6cae24SSepherosa Ziehau if (bpf_peers_present(ifp->if_bpf)) { 59549c6cae24SSepherosa Ziehau m_bpf = m_copypacket(m, M_NOWAIT); 59559c6cae24SSepherosa Ziehau if (m_bpf == NULL) { 59569c6cae24SSepherosa Ziehau /* 59579c6cae24SSepherosa Ziehau * Failed to grab a shallow 59589c6cae24SSepherosa Ziehau * copy; tap now. 59599c6cae24SSepherosa Ziehau */ 59609c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m); 59619c6cae24SSepherosa Ziehau } 59629c6cae24SSepherosa Ziehau } 59639c6cae24SSepherosa Ziehau } else { 59649c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m); 59659c6cae24SSepherosa Ziehau } 59669c6cae24SSepherosa Ziehau 59679c6cae24SSepherosa Ziehau error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m); 59689c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 59699c6cae24SSepherosa Ziehau 59709c6cae24SSepherosa Ziehau if (m_bpf != NULL) { 59719c6cae24SSepherosa Ziehau if (!error) 59729c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m_bpf); 59739c6cae24SSepherosa Ziehau m_freem(m_bpf); 59749c6cae24SSepherosa Ziehau } 59759c6cae24SSepherosa Ziehau 59769c6cae24SSepherosa Ziehau if (error == ENOBUFS) { 59779c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 59789c6cae24SSepherosa Ziehau } else if (error) { 59799c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 59809c6cae24SSepherosa Ziehau } else { 59819c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 59829c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes); 59839c6cae24SSepherosa Ziehau if (omcast) { 59849c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 59859c6cae24SSepherosa Ziehau omcast); 59869c6cae24SSepherosa Ziehau } 59879c6cae24SSepherosa Ziehau } 59889c6cae24SSepherosa Ziehau return (error); 59899c6cae24SSepherosa Ziehau } 59909c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 59919c6cae24SSepherosa Ziehau } 59929c6cae24SSepherosa Ziehau 5993edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 5994edd3f315SSepherosa Ziehau /* 5995c49d47daSSepherosa Ziehau * Perform TSO packet header fixup or get l2/l3 header length now, 5996c49d47daSSepherosa Ziehau * since packet headers should be cache-hot. 5997edd3f315SSepherosa Ziehau */ 5998edd3f315SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 5999edd3f315SSepherosa Ziehau m = hn_tso_fixup(m); 6000edd3f315SSepherosa Ziehau if (__predict_false(m == NULL)) { 6001edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 6002edd3f315SSepherosa Ziehau return EIO; 6003edd3f315SSepherosa Ziehau } 6004c49d47daSSepherosa Ziehau } else if (m->m_pkthdr.csum_flags & 6005c49d47daSSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) { 6006c49d47daSSepherosa Ziehau m = hn_set_hlen(m); 6007c49d47daSSepherosa Ziehau if (__predict_false(m == NULL)) { 6008c49d47daSSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 6009c49d47daSSepherosa Ziehau return EIO; 6010c49d47daSSepherosa Ziehau } 6011edd3f315SSepherosa Ziehau } 6012edd3f315SSepherosa Ziehau #endif 6013edd3f315SSepherosa Ziehau 601415516c77SSepherosa Ziehau /* 601515516c77SSepherosa Ziehau * Select the TX ring based on flowid 601615516c77SSepherosa Ziehau */ 601734d68912SSepherosa Ziehau if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 601834d68912SSepherosa Ziehau #ifdef RSS 601934d68912SSepherosa Ziehau uint32_t bid; 602034d68912SSepherosa Ziehau 602134d68912SSepherosa Ziehau if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m), 602234d68912SSepherosa Ziehau &bid) == 0) 602334d68912SSepherosa Ziehau idx = bid % sc->hn_tx_ring_inuse; 602434d68912SSepherosa Ziehau else 602534d68912SSepherosa Ziehau #endif 6026cc0c6ebcSSepherosa Ziehau { 6027cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET) 6028cc0c6ebcSSepherosa Ziehau int tcpsyn = 0; 6029cc0c6ebcSSepherosa Ziehau 6030cc0c6ebcSSepherosa Ziehau if (m->m_pkthdr.len < 128 && 6031cc0c6ebcSSepherosa Ziehau (m->m_pkthdr.csum_flags & 6032cc0c6ebcSSepherosa Ziehau (CSUM_IP_TCP | CSUM_IP6_TCP)) && 6033cc0c6ebcSSepherosa Ziehau (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) { 6034cc0c6ebcSSepherosa Ziehau m = hn_check_tcpsyn(m, &tcpsyn); 6035cc0c6ebcSSepherosa Ziehau if (__predict_false(m == NULL)) { 6036cc0c6ebcSSepherosa Ziehau if_inc_counter(ifp, 6037cc0c6ebcSSepherosa Ziehau IFCOUNTER_OERRORS, 1); 6038cc0c6ebcSSepherosa Ziehau return (EIO); 6039cc0c6ebcSSepherosa Ziehau } 6040cc0c6ebcSSepherosa Ziehau } 6041cc0c6ebcSSepherosa Ziehau #else 6042cc0c6ebcSSepherosa Ziehau const int tcpsyn = 0; 6043cc0c6ebcSSepherosa Ziehau #endif 6044cc0c6ebcSSepherosa Ziehau if (tcpsyn) 6045cc0c6ebcSSepherosa Ziehau idx = 0; 6046cc0c6ebcSSepherosa Ziehau else 604715516c77SSepherosa Ziehau idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse; 604834d68912SSepherosa Ziehau } 6049cc0c6ebcSSepherosa Ziehau } 605015516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 605115516c77SSepherosa Ziehau 605215516c77SSepherosa Ziehau error = drbr_enqueue(ifp, txr->hn_mbuf_br, m); 605315516c77SSepherosa Ziehau if (error) { 605415516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 605515516c77SSepherosa Ziehau return error; 605615516c77SSepherosa Ziehau } 605715516c77SSepherosa Ziehau 605815516c77SSepherosa Ziehau if (txr->hn_oactive) 605915516c77SSepherosa Ziehau return 0; 606015516c77SSepherosa Ziehau 606115516c77SSepherosa Ziehau if (txr->hn_sched_tx) 606215516c77SSepherosa Ziehau goto do_sched; 606315516c77SSepherosa Ziehau 606415516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 606515516c77SSepherosa Ziehau int sched; 606615516c77SSepherosa Ziehau 606715516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 606815516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 606915516c77SSepherosa Ziehau if (!sched) 607015516c77SSepherosa Ziehau return 0; 607115516c77SSepherosa Ziehau } 607215516c77SSepherosa Ziehau do_sched: 607315516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 607415516c77SSepherosa Ziehau return 0; 607515516c77SSepherosa Ziehau } 607615516c77SSepherosa Ziehau 607715516c77SSepherosa Ziehau static void 607815516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr) 607915516c77SSepherosa Ziehau { 608015516c77SSepherosa Ziehau struct mbuf *m; 608115516c77SSepherosa Ziehau 608215516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 608315516c77SSepherosa Ziehau while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL) 608415516c77SSepherosa Ziehau m_freem(m); 608515516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 608615516c77SSepherosa Ziehau } 608715516c77SSepherosa Ziehau 608815516c77SSepherosa Ziehau static void 608915516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp) 609015516c77SSepherosa Ziehau { 609115516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 60929c6cae24SSepherosa Ziehau struct rm_priotracker pt; 609315516c77SSepherosa Ziehau int i; 609415516c77SSepherosa Ziehau 609515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 609615516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 609715516c77SSepherosa Ziehau if_qflush(ifp); 60989c6cae24SSepherosa Ziehau 60999c6cae24SSepherosa Ziehau rm_rlock(&sc->hn_vf_lock, &pt); 61009c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 61019c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp); 61029c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 610315516c77SSepherosa Ziehau } 610415516c77SSepherosa Ziehau 610515516c77SSepherosa Ziehau static void 610615516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr) 610715516c77SSepherosa Ziehau { 610815516c77SSepherosa Ziehau 610915516c77SSepherosa Ziehau if (txr->hn_sched_tx) 611015516c77SSepherosa Ziehau goto do_sched; 611115516c77SSepherosa Ziehau 611215516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 611315516c77SSepherosa Ziehau int sched; 611415516c77SSepherosa Ziehau 611515516c77SSepherosa Ziehau txr->hn_oactive = 0; 611615516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 611715516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 611815516c77SSepherosa Ziehau if (sched) { 611915516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 612015516c77SSepherosa Ziehau &txr->hn_tx_task); 612115516c77SSepherosa Ziehau } 612215516c77SSepherosa Ziehau } else { 612315516c77SSepherosa Ziehau do_sched: 612415516c77SSepherosa Ziehau /* 612515516c77SSepherosa Ziehau * Release the oactive earlier, with the hope, that 612615516c77SSepherosa Ziehau * others could catch up. The task will clear the 612715516c77SSepherosa Ziehau * oactive again with the hn_tx_lock to avoid possible 612815516c77SSepherosa Ziehau * races. 612915516c77SSepherosa Ziehau */ 613015516c77SSepherosa Ziehau txr->hn_oactive = 0; 613115516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 613215516c77SSepherosa Ziehau } 613315516c77SSepherosa Ziehau } 613415516c77SSepherosa Ziehau 613515516c77SSepherosa Ziehau static void 613615516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused) 613715516c77SSepherosa Ziehau { 613815516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 613915516c77SSepherosa Ziehau 614015516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 614115516c77SSepherosa Ziehau hn_xmit(txr, 0); 614215516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 614315516c77SSepherosa Ziehau } 614415516c77SSepherosa Ziehau 614515516c77SSepherosa Ziehau static void 614615516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused) 614715516c77SSepherosa Ziehau { 614815516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 614915516c77SSepherosa Ziehau 615015516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 615115516c77SSepherosa Ziehau txr->hn_oactive = 0; 615215516c77SSepherosa Ziehau hn_xmit(txr, 0); 615315516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 615415516c77SSepherosa Ziehau } 615515516c77SSepherosa Ziehau 615615516c77SSepherosa Ziehau static int 615715516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan) 615815516c77SSepherosa Ziehau { 615915516c77SSepherosa Ziehau struct vmbus_chan_br cbr; 616015516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 616115516c77SSepherosa Ziehau struct hn_tx_ring *txr = NULL; 616215516c77SSepherosa Ziehau int idx, error; 616315516c77SSepherosa Ziehau 616415516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 616515516c77SSepherosa Ziehau 616615516c77SSepherosa Ziehau /* 616715516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 616815516c77SSepherosa Ziehau */ 616915516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 617015516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 617115516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 617215516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 617315516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0, 617415516c77SSepherosa Ziehau ("RX ring %d already attached", idx)); 617515516c77SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED; 61763ab0fea1SDexuan Cui rxr->hn_chan = chan; 617715516c77SSepherosa Ziehau 617815516c77SSepherosa Ziehau if (bootverbose) { 617915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n", 618015516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 618115516c77SSepherosa Ziehau } 618215516c77SSepherosa Ziehau 618315516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 618415516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 618515516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0, 618615516c77SSepherosa Ziehau ("TX ring %d already attached", idx)); 618715516c77SSepherosa Ziehau txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED; 618815516c77SSepherosa Ziehau 618915516c77SSepherosa Ziehau txr->hn_chan = chan; 619015516c77SSepherosa Ziehau if (bootverbose) { 619115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n", 619215516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 619315516c77SSepherosa Ziehau } 619415516c77SSepherosa Ziehau } 619515516c77SSepherosa Ziehau 619615516c77SSepherosa Ziehau /* Bind this channel to a proper CPU. */ 61970e11868dSSepherosa Ziehau vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx)); 619815516c77SSepherosa Ziehau 619915516c77SSepherosa Ziehau /* 620015516c77SSepherosa Ziehau * Open this channel 620115516c77SSepherosa Ziehau */ 620215516c77SSepherosa Ziehau cbr.cbr = rxr->hn_br; 620315516c77SSepherosa Ziehau cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr; 620415516c77SSepherosa Ziehau cbr.cbr_txsz = HN_TXBR_SIZE; 620515516c77SSepherosa Ziehau cbr.cbr_rxsz = HN_RXBR_SIZE; 620615516c77SSepherosa Ziehau error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr); 620715516c77SSepherosa Ziehau if (error) { 620871e8ac56SSepherosa Ziehau if (error == EISCONN) { 620971e8ac56SSepherosa Ziehau if_printf(sc->hn_ifp, "bufring is connected after " 621071e8ac56SSepherosa Ziehau "chan%u open failure\n", vmbus_chan_id(chan)); 621171e8ac56SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 621271e8ac56SSepherosa Ziehau } else { 621315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "open chan%u failed: %d\n", 621415516c77SSepherosa Ziehau vmbus_chan_id(chan), error); 621571e8ac56SSepherosa Ziehau } 621615516c77SSepherosa Ziehau } 621715516c77SSepherosa Ziehau return (error); 621815516c77SSepherosa Ziehau } 621915516c77SSepherosa Ziehau 622015516c77SSepherosa Ziehau static void 622115516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan) 622215516c77SSepherosa Ziehau { 622315516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 62242494d735SSepherosa Ziehau int idx, error; 622515516c77SSepherosa Ziehau 622615516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 622715516c77SSepherosa Ziehau 622815516c77SSepherosa Ziehau /* 622915516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 623015516c77SSepherosa Ziehau */ 623115516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 623215516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 623315516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 623415516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 623515516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED), 623615516c77SSepherosa Ziehau ("RX ring %d is not attached", idx)); 623715516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 623815516c77SSepherosa Ziehau 623915516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 624015516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[idx]; 624115516c77SSepherosa Ziehau 624215516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED), 624315516c77SSepherosa Ziehau ("TX ring %d is not attached attached", idx)); 624415516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 624515516c77SSepherosa Ziehau } 624615516c77SSepherosa Ziehau 624715516c77SSepherosa Ziehau /* 624815516c77SSepherosa Ziehau * Close this channel. 624915516c77SSepherosa Ziehau * 625015516c77SSepherosa Ziehau * NOTE: 625115516c77SSepherosa Ziehau * Channel closing does _not_ destroy the target channel. 625215516c77SSepherosa Ziehau */ 62532494d735SSepherosa Ziehau error = vmbus_chan_close_direct(chan); 62542494d735SSepherosa Ziehau if (error == EISCONN) { 6255aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u bufring is connected " 6256aa1a2adcSSepherosa Ziehau "after being closed\n", vmbus_chan_id(chan)); 62572494d735SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 62582494d735SSepherosa Ziehau } else if (error) { 6259aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u close failed: %d\n", 6260aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), error); 62612494d735SSepherosa Ziehau } 626215516c77SSepherosa Ziehau } 626315516c77SSepherosa Ziehau 626415516c77SSepherosa Ziehau static int 626515516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc) 626615516c77SSepherosa Ziehau { 626715516c77SSepherosa Ziehau struct vmbus_channel **subchans; 626815516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 626915516c77SSepherosa Ziehau int i, error = 0; 627015516c77SSepherosa Ziehau 627171e8ac56SSepherosa Ziehau KASSERT(subchan_cnt > 0, ("no sub-channels")); 627215516c77SSepherosa Ziehau 627315516c77SSepherosa Ziehau /* Attach the sub-channels. */ 627415516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 627515516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) { 627671e8ac56SSepherosa Ziehau int error1; 627771e8ac56SSepherosa Ziehau 627871e8ac56SSepherosa Ziehau error1 = hn_chan_attach(sc, subchans[i]); 627971e8ac56SSepherosa Ziehau if (error1) { 628071e8ac56SSepherosa Ziehau error = error1; 628171e8ac56SSepherosa Ziehau /* Move on; all channels will be detached later. */ 628271e8ac56SSepherosa Ziehau } 628315516c77SSepherosa Ziehau } 628415516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 628515516c77SSepherosa Ziehau 628615516c77SSepherosa Ziehau if (error) { 628715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error); 628815516c77SSepherosa Ziehau } else { 628915516c77SSepherosa Ziehau if (bootverbose) { 629015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d sub-channels attached\n", 629115516c77SSepherosa Ziehau subchan_cnt); 629215516c77SSepherosa Ziehau } 629315516c77SSepherosa Ziehau } 629415516c77SSepherosa Ziehau return (error); 629515516c77SSepherosa Ziehau } 629615516c77SSepherosa Ziehau 629715516c77SSepherosa Ziehau static void 629815516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc) 629915516c77SSepherosa Ziehau { 630015516c77SSepherosa Ziehau struct vmbus_channel **subchans; 630115516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 630215516c77SSepherosa Ziehau int i; 630315516c77SSepherosa Ziehau 630415516c77SSepherosa Ziehau if (subchan_cnt == 0) 630515516c77SSepherosa Ziehau goto back; 630615516c77SSepherosa Ziehau 630715516c77SSepherosa Ziehau /* Detach the sub-channels. */ 630815516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 630915516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) 631015516c77SSepherosa Ziehau hn_chan_detach(sc, subchans[i]); 631115516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 631215516c77SSepherosa Ziehau 631315516c77SSepherosa Ziehau back: 631415516c77SSepherosa Ziehau /* 631515516c77SSepherosa Ziehau * Detach the primary channel, _after_ all sub-channels 631615516c77SSepherosa Ziehau * are detached. 631715516c77SSepherosa Ziehau */ 631815516c77SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 631915516c77SSepherosa Ziehau 632015516c77SSepherosa Ziehau /* Wait for sub-channels to be destroyed, if any. */ 632115516c77SSepherosa Ziehau vmbus_subchan_drain(sc->hn_prichan); 632215516c77SSepherosa Ziehau 632315516c77SSepherosa Ziehau #ifdef INVARIANTS 632415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 632515516c77SSepherosa Ziehau KASSERT((sc->hn_rx_ring[i].hn_rx_flags & 632615516c77SSepherosa Ziehau HN_RX_FLAG_ATTACHED) == 0, 632715516c77SSepherosa Ziehau ("%dth RX ring is still attached", i)); 632815516c77SSepherosa Ziehau } 632915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 633015516c77SSepherosa Ziehau KASSERT((sc->hn_tx_ring[i].hn_tx_flags & 633115516c77SSepherosa Ziehau HN_TX_FLAG_ATTACHED) == 0, 633215516c77SSepherosa Ziehau ("%dth TX ring is still attached", i)); 633315516c77SSepherosa Ziehau } 633415516c77SSepherosa Ziehau #endif 633515516c77SSepherosa Ziehau } 633615516c77SSepherosa Ziehau 633715516c77SSepherosa Ziehau static int 633815516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch) 633915516c77SSepherosa Ziehau { 634015516c77SSepherosa Ziehau struct vmbus_channel **subchans; 634115516c77SSepherosa Ziehau int nchan, rxr_cnt, error; 634215516c77SSepherosa Ziehau 634315516c77SSepherosa Ziehau nchan = *nsubch + 1; 634415516c77SSepherosa Ziehau if (nchan == 1) { 634515516c77SSepherosa Ziehau /* 634615516c77SSepherosa Ziehau * Multiple RX/TX rings are not requested. 634715516c77SSepherosa Ziehau */ 634815516c77SSepherosa Ziehau *nsubch = 0; 634915516c77SSepherosa Ziehau return (0); 635015516c77SSepherosa Ziehau } 635115516c77SSepherosa Ziehau 635215516c77SSepherosa Ziehau /* 635315516c77SSepherosa Ziehau * Query RSS capabilities, e.g. # of RX rings, and # of indirect 635415516c77SSepherosa Ziehau * table entries. 635515516c77SSepherosa Ziehau */ 635615516c77SSepherosa Ziehau error = hn_rndis_query_rsscaps(sc, &rxr_cnt); 635715516c77SSepherosa Ziehau if (error) { 635815516c77SSepherosa Ziehau /* No RSS; this is benign. */ 635915516c77SSepherosa Ziehau *nsubch = 0; 636015516c77SSepherosa Ziehau return (0); 636115516c77SSepherosa Ziehau } 636215516c77SSepherosa Ziehau if (bootverbose) { 636315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n", 636415516c77SSepherosa Ziehau rxr_cnt, nchan); 636515516c77SSepherosa Ziehau } 636615516c77SSepherosa Ziehau 636715516c77SSepherosa Ziehau if (nchan > rxr_cnt) 636815516c77SSepherosa Ziehau nchan = rxr_cnt; 636915516c77SSepherosa Ziehau if (nchan == 1) { 637015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n"); 637115516c77SSepherosa Ziehau *nsubch = 0; 637215516c77SSepherosa Ziehau return (0); 637315516c77SSepherosa Ziehau } 637415516c77SSepherosa Ziehau 637515516c77SSepherosa Ziehau /* 637615516c77SSepherosa Ziehau * Allocate sub-channels from NVS. 637715516c77SSepherosa Ziehau */ 637815516c77SSepherosa Ziehau *nsubch = nchan - 1; 637915516c77SSepherosa Ziehau error = hn_nvs_alloc_subchans(sc, nsubch); 638015516c77SSepherosa Ziehau if (error || *nsubch == 0) { 638115516c77SSepherosa Ziehau /* Failed to allocate sub-channels. */ 638215516c77SSepherosa Ziehau *nsubch = 0; 638315516c77SSepherosa Ziehau return (0); 638415516c77SSepherosa Ziehau } 638515516c77SSepherosa Ziehau 638615516c77SSepherosa Ziehau /* 638715516c77SSepherosa Ziehau * Wait for all sub-channels to become ready before moving on. 638815516c77SSepherosa Ziehau */ 638915516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch); 639015516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, *nsubch); 639115516c77SSepherosa Ziehau return (0); 639215516c77SSepherosa Ziehau } 639315516c77SSepherosa Ziehau 63942494d735SSepherosa Ziehau static bool 63952494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc) 63962494d735SSepherosa Ziehau { 63972494d735SSepherosa Ziehau int i; 63982494d735SSepherosa Ziehau 63992494d735SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_ERRORS) 64002494d735SSepherosa Ziehau return (false); 64012494d735SSepherosa Ziehau 64022494d735SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 64032494d735SSepherosa Ziehau const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 64042494d735SSepherosa Ziehau 64052494d735SSepherosa Ziehau if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) 64062494d735SSepherosa Ziehau return (false); 64072494d735SSepherosa Ziehau } 64082494d735SSepherosa Ziehau return (true); 64092494d735SSepherosa Ziehau } 64102494d735SSepherosa Ziehau 6411b3b75d9cSSepherosa Ziehau /* 6412b3b75d9cSSepherosa Ziehau * Make sure that the RX filter is zero after the successful 6413b3b75d9cSSepherosa Ziehau * RNDIS initialization. 6414b3b75d9cSSepherosa Ziehau * 6415b3b75d9cSSepherosa Ziehau * NOTE: 6416b3b75d9cSSepherosa Ziehau * Under certain conditions on certain versions of Hyper-V, 6417b3b75d9cSSepherosa Ziehau * the RNDIS rxfilter is _not_ zero on the hypervisor side 6418b3b75d9cSSepherosa Ziehau * after the successful RNDIS initialization, which breaks 6419b3b75d9cSSepherosa Ziehau * the assumption of any following code (well, it breaks the 6420b3b75d9cSSepherosa Ziehau * RNDIS API contract actually). Clear the RNDIS rxfilter 6421b3b75d9cSSepherosa Ziehau * explicitly, drain packets sneaking through, and drain the 6422b3b75d9cSSepherosa Ziehau * interrupt taskqueues scheduled due to the stealth packets. 6423b3b75d9cSSepherosa Ziehau */ 6424b3b75d9cSSepherosa Ziehau static void 6425b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan) 6426b3b75d9cSSepherosa Ziehau { 6427b3b75d9cSSepherosa Ziehau 6428b3b75d9cSSepherosa Ziehau hn_disable_rx(sc); 6429b3b75d9cSSepherosa Ziehau hn_drain_rxtx(sc, nchan); 6430b3b75d9cSSepherosa Ziehau } 6431b3b75d9cSSepherosa Ziehau 643215516c77SSepherosa Ziehau static int 643315516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu) 643415516c77SSepherosa Ziehau { 643571e8ac56SSepherosa Ziehau #define ATTACHED_NVS 0x0002 643671e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS 0x0004 643771e8ac56SSepherosa Ziehau 643815516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 6439b3b75d9cSSepherosa Ziehau int error, nsubch, nchan = 1, i, rndis_inited; 644071e8ac56SSepherosa Ziehau uint32_t old_caps, attached = 0; 644115516c77SSepherosa Ziehau 644215516c77SSepherosa Ziehau KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0, 644315516c77SSepherosa Ziehau ("synthetic parts were attached")); 644415516c77SSepherosa Ziehau 64452494d735SSepherosa Ziehau if (!hn_synth_attachable(sc)) 64462494d735SSepherosa Ziehau return (ENXIO); 64472494d735SSepherosa Ziehau 644815516c77SSepherosa Ziehau /* Save capabilities for later verification. */ 644915516c77SSepherosa Ziehau old_caps = sc->hn_caps; 645015516c77SSepherosa Ziehau sc->hn_caps = 0; 645115516c77SSepherosa Ziehau 645215516c77SSepherosa Ziehau /* Clear RSS stuffs. */ 645315516c77SSepherosa Ziehau sc->hn_rss_ind_size = 0; 645415516c77SSepherosa Ziehau sc->hn_rss_hash = 0; 6455642ec226SSepherosa Ziehau sc->hn_rss_hcap = 0; 645615516c77SSepherosa Ziehau 645715516c77SSepherosa Ziehau /* 645815516c77SSepherosa Ziehau * Attach the primary channel _before_ attaching NVS and RNDIS. 645915516c77SSepherosa Ziehau */ 646015516c77SSepherosa Ziehau error = hn_chan_attach(sc, sc->hn_prichan); 646115516c77SSepherosa Ziehau if (error) 646271e8ac56SSepherosa Ziehau goto failed; 646315516c77SSepherosa Ziehau 646415516c77SSepherosa Ziehau /* 646515516c77SSepherosa Ziehau * Attach NVS. 646615516c77SSepherosa Ziehau */ 646715516c77SSepherosa Ziehau error = hn_nvs_attach(sc, mtu); 646815516c77SSepherosa Ziehau if (error) 646971e8ac56SSepherosa Ziehau goto failed; 647071e8ac56SSepherosa Ziehau attached |= ATTACHED_NVS; 647115516c77SSepherosa Ziehau 647215516c77SSepherosa Ziehau /* 647315516c77SSepherosa Ziehau * Attach RNDIS _after_ NVS is attached. 647415516c77SSepherosa Ziehau */ 6475b3b75d9cSSepherosa Ziehau error = hn_rndis_attach(sc, mtu, &rndis_inited); 6476b3b75d9cSSepherosa Ziehau if (rndis_inited) 6477b3b75d9cSSepherosa Ziehau attached |= ATTACHED_RNDIS; 647815516c77SSepherosa Ziehau if (error) 647971e8ac56SSepherosa Ziehau goto failed; 648015516c77SSepherosa Ziehau 648115516c77SSepherosa Ziehau /* 648215516c77SSepherosa Ziehau * Make sure capabilities are not changed. 648315516c77SSepherosa Ziehau */ 648415516c77SSepherosa Ziehau if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) { 648515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n", 648615516c77SSepherosa Ziehau old_caps, sc->hn_caps); 648771e8ac56SSepherosa Ziehau error = ENXIO; 648871e8ac56SSepherosa Ziehau goto failed; 648915516c77SSepherosa Ziehau } 649015516c77SSepherosa Ziehau 649115516c77SSepherosa Ziehau /* 649215516c77SSepherosa Ziehau * Allocate sub-channels for multi-TX/RX rings. 649315516c77SSepherosa Ziehau * 649415516c77SSepherosa Ziehau * NOTE: 649515516c77SSepherosa Ziehau * The # of RX rings that can be used is equivalent to the # of 649615516c77SSepherosa Ziehau * channels to be requested. 649715516c77SSepherosa Ziehau */ 649815516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_cnt - 1; 649915516c77SSepherosa Ziehau error = hn_synth_alloc_subchans(sc, &nsubch); 650015516c77SSepherosa Ziehau if (error) 650171e8ac56SSepherosa Ziehau goto failed; 650271e8ac56SSepherosa Ziehau /* NOTE: _Full_ synthetic parts detach is required now. */ 650371e8ac56SSepherosa Ziehau sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED; 650415516c77SSepherosa Ziehau 650571e8ac56SSepherosa Ziehau /* 650671e8ac56SSepherosa Ziehau * Set the # of TX/RX rings that could be used according to 650771e8ac56SSepherosa Ziehau * the # of channels that NVS offered. 650871e8ac56SSepherosa Ziehau */ 650915516c77SSepherosa Ziehau nchan = nsubch + 1; 651071e8ac56SSepherosa Ziehau hn_set_ring_inuse(sc, nchan); 651115516c77SSepherosa Ziehau if (nchan == 1) { 651215516c77SSepherosa Ziehau /* Only the primary channel can be used; done */ 651315516c77SSepherosa Ziehau goto back; 651415516c77SSepherosa Ziehau } 651515516c77SSepherosa Ziehau 651615516c77SSepherosa Ziehau /* 651771e8ac56SSepherosa Ziehau * Attach the sub-channels. 6518afd4971bSSepherosa Ziehau * 6519afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 652015516c77SSepherosa Ziehau */ 652171e8ac56SSepherosa Ziehau error = hn_attach_subchans(sc); 652271e8ac56SSepherosa Ziehau if (error) 652371e8ac56SSepherosa Ziehau goto failed; 652415516c77SSepherosa Ziehau 652571e8ac56SSepherosa Ziehau /* 652671e8ac56SSepherosa Ziehau * Configure RSS key and indirect table _after_ all sub-channels 652771e8ac56SSepherosa Ziehau * are attached. 652871e8ac56SSepherosa Ziehau */ 652915516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) { 653015516c77SSepherosa Ziehau /* 653115516c77SSepherosa Ziehau * RSS key is not set yet; set it to the default RSS key. 653215516c77SSepherosa Ziehau */ 653315516c77SSepherosa Ziehau if (bootverbose) 653415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS key\n"); 653534d68912SSepherosa Ziehau #ifdef RSS 653634d68912SSepherosa Ziehau rss_getkey(rss->rss_key); 653734d68912SSepherosa Ziehau #else 653815516c77SSepherosa Ziehau memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key)); 653934d68912SSepherosa Ziehau #endif 654015516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 654115516c77SSepherosa Ziehau } 654215516c77SSepherosa Ziehau 654315516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) { 654415516c77SSepherosa Ziehau /* 654515516c77SSepherosa Ziehau * RSS indirect table is not set yet; set it up in round- 654615516c77SSepherosa Ziehau * robin fashion. 654715516c77SSepherosa Ziehau */ 654815516c77SSepherosa Ziehau if (bootverbose) { 654915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS indirect " 655015516c77SSepherosa Ziehau "table\n"); 655115516c77SSepherosa Ziehau } 655234d68912SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 655334d68912SSepherosa Ziehau uint32_t subidx; 655434d68912SSepherosa Ziehau 655534d68912SSepherosa Ziehau #ifdef RSS 655634d68912SSepherosa Ziehau subidx = rss_get_indirection_to_bucket(i); 655734d68912SSepherosa Ziehau #else 655834d68912SSepherosa Ziehau subidx = i; 655934d68912SSepherosa Ziehau #endif 656034d68912SSepherosa Ziehau rss->rss_ind[i] = subidx % nchan; 656134d68912SSepherosa Ziehau } 656215516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 656315516c77SSepherosa Ziehau } else { 656415516c77SSepherosa Ziehau /* 656515516c77SSepherosa Ziehau * # of usable channels may be changed, so we have to 656615516c77SSepherosa Ziehau * make sure that all entries in RSS indirect table 656715516c77SSepherosa Ziehau * are valid. 6568afd4971bSSepherosa Ziehau * 6569afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 657015516c77SSepherosa Ziehau */ 6571afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 657215516c77SSepherosa Ziehau } 657315516c77SSepherosa Ziehau 6574642ec226SSepherosa Ziehau sc->hn_rss_hash = sc->hn_rss_hcap; 6575642ec226SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) || 6576642ec226SSepherosa Ziehau (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { 6577642ec226SSepherosa Ziehau /* NOTE: Don't reconfigure RSS; will do immediately. */ 6578642ec226SSepherosa Ziehau hn_vf_rss_fixup(sc, false); 6579642ec226SSepherosa Ziehau } 658015516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 658115516c77SSepherosa Ziehau if (error) 658271e8ac56SSepherosa Ziehau goto failed; 658371e8ac56SSepherosa Ziehau back: 6584dc13fee6SSepherosa Ziehau /* 6585dc13fee6SSepherosa Ziehau * Fixup transmission aggregation setup. 6586dc13fee6SSepherosa Ziehau */ 6587dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 6588b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 658915516c77SSepherosa Ziehau return (0); 659071e8ac56SSepherosa Ziehau 659171e8ac56SSepherosa Ziehau failed: 659271e8ac56SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 6593b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 659471e8ac56SSepherosa Ziehau hn_synth_detach(sc); 659571e8ac56SSepherosa Ziehau } else { 6596b3b75d9cSSepherosa Ziehau if (attached & ATTACHED_RNDIS) { 6597b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 659871e8ac56SSepherosa Ziehau hn_rndis_detach(sc); 6599b3b75d9cSSepherosa Ziehau } 660071e8ac56SSepherosa Ziehau if (attached & ATTACHED_NVS) 660171e8ac56SSepherosa Ziehau hn_nvs_detach(sc); 660271e8ac56SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 660371e8ac56SSepherosa Ziehau /* Restore old capabilities. */ 660471e8ac56SSepherosa Ziehau sc->hn_caps = old_caps; 660571e8ac56SSepherosa Ziehau } 660671e8ac56SSepherosa Ziehau return (error); 660771e8ac56SSepherosa Ziehau 660871e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS 660971e8ac56SSepherosa Ziehau #undef ATTACHED_NVS 661015516c77SSepherosa Ziehau } 661115516c77SSepherosa Ziehau 661215516c77SSepherosa Ziehau /* 661315516c77SSepherosa Ziehau * NOTE: 661415516c77SSepherosa Ziehau * The interface must have been suspended though hn_suspend(), before 661515516c77SSepherosa Ziehau * this function get called. 661615516c77SSepherosa Ziehau */ 661715516c77SSepherosa Ziehau static void 661815516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc) 661915516c77SSepherosa Ziehau { 662015516c77SSepherosa Ziehau 662115516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 662215516c77SSepherosa Ziehau ("synthetic parts were not attached")); 662315516c77SSepherosa Ziehau 662415516c77SSepherosa Ziehau /* Detach the RNDIS first. */ 662515516c77SSepherosa Ziehau hn_rndis_detach(sc); 662615516c77SSepherosa Ziehau 662715516c77SSepherosa Ziehau /* Detach NVS. */ 662815516c77SSepherosa Ziehau hn_nvs_detach(sc); 662915516c77SSepherosa Ziehau 663015516c77SSepherosa Ziehau /* Detach all of the channels. */ 663115516c77SSepherosa Ziehau hn_detach_allchans(sc); 663215516c77SSepherosa Ziehau 6633ace5ce7eSWei Hu if (vmbus_current_version >= VMBUS_VERSION_WIN10 && sc->hn_rxbuf_gpadl != 0) { 6634ace5ce7eSWei Hu /* 6635ace5ce7eSWei Hu * Host is post-Win2016, disconnect RXBUF from primary channel here. 6636ace5ce7eSWei Hu */ 6637ace5ce7eSWei Hu int error; 6638ace5ce7eSWei Hu 6639ace5ce7eSWei Hu error = vmbus_chan_gpadl_disconnect(sc->hn_prichan, 6640ace5ce7eSWei Hu sc->hn_rxbuf_gpadl); 6641ace5ce7eSWei Hu if (error) { 6642ace5ce7eSWei Hu if_printf(sc->hn_ifp, 6643ace5ce7eSWei Hu "rxbuf gpadl disconn failed: %d\n", error); 6644ace5ce7eSWei Hu sc->hn_flags |= HN_FLAG_RXBUF_REF; 6645ace5ce7eSWei Hu } 6646ace5ce7eSWei Hu sc->hn_rxbuf_gpadl = 0; 6647ace5ce7eSWei Hu } 6648ace5ce7eSWei Hu 6649ace5ce7eSWei Hu if (vmbus_current_version >= VMBUS_VERSION_WIN10 && sc->hn_chim_gpadl != 0) { 6650ace5ce7eSWei Hu /* 6651ace5ce7eSWei Hu * Host is post-Win2016, disconnect chimney sending buffer from 6652ace5ce7eSWei Hu * primary channel here. 6653ace5ce7eSWei Hu */ 6654ace5ce7eSWei Hu int error; 6655ace5ce7eSWei Hu 6656ace5ce7eSWei Hu error = vmbus_chan_gpadl_disconnect(sc->hn_prichan, 6657ace5ce7eSWei Hu sc->hn_chim_gpadl); 6658ace5ce7eSWei Hu if (error) { 6659ace5ce7eSWei Hu if_printf(sc->hn_ifp, 6660ace5ce7eSWei Hu "chim gpadl disconn failed: %d\n", error); 6661ace5ce7eSWei Hu sc->hn_flags |= HN_FLAG_CHIM_REF; 6662ace5ce7eSWei Hu } 6663ace5ce7eSWei Hu sc->hn_chim_gpadl = 0; 6664ace5ce7eSWei Hu } 666515516c77SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED; 666615516c77SSepherosa Ziehau } 666715516c77SSepherosa Ziehau 666815516c77SSepherosa Ziehau static void 666915516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt) 667015516c77SSepherosa Ziehau { 667115516c77SSepherosa Ziehau KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt, 667215516c77SSepherosa Ziehau ("invalid ring count %d", ring_cnt)); 667315516c77SSepherosa Ziehau 667415516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt > ring_cnt) 667515516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = ring_cnt; 667615516c77SSepherosa Ziehau else 667715516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 667815516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = ring_cnt; 667915516c77SSepherosa Ziehau 668034d68912SSepherosa Ziehau #ifdef RSS 668134d68912SSepherosa Ziehau if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) { 668234d68912SSepherosa Ziehau if_printf(sc->hn_ifp, "# of RX rings (%d) does not match " 668334d68912SSepherosa Ziehau "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse, 668434d68912SSepherosa Ziehau rss_getnumbuckets()); 668534d68912SSepherosa Ziehau } 668634d68912SSepherosa Ziehau #endif 668734d68912SSepherosa Ziehau 668815516c77SSepherosa Ziehau if (bootverbose) { 668915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n", 669015516c77SSepherosa Ziehau sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse); 669115516c77SSepherosa Ziehau } 669215516c77SSepherosa Ziehau } 669315516c77SSepherosa Ziehau 669415516c77SSepherosa Ziehau static void 669525641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan) 669615516c77SSepherosa Ziehau { 669715516c77SSepherosa Ziehau 669825641fc7SSepherosa Ziehau /* 669925641fc7SSepherosa Ziehau * NOTE: 670025641fc7SSepherosa Ziehau * The TX bufring will not be drained by the hypervisor, 670125641fc7SSepherosa Ziehau * if the primary channel is revoked. 670225641fc7SSepherosa Ziehau */ 670325641fc7SSepherosa Ziehau while (!vmbus_chan_rx_empty(chan) || 670425641fc7SSepherosa Ziehau (!vmbus_chan_is_revoked(sc->hn_prichan) && 670525641fc7SSepherosa Ziehau !vmbus_chan_tx_empty(chan))) 670615516c77SSepherosa Ziehau pause("waitch", 1); 670715516c77SSepherosa Ziehau vmbus_chan_intr_drain(chan); 670815516c77SSepherosa Ziehau } 670915516c77SSepherosa Ziehau 671015516c77SSepherosa Ziehau static void 6711b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc) 6712b3b75d9cSSepherosa Ziehau { 6713b3b75d9cSSepherosa Ziehau 6714b3b75d9cSSepherosa Ziehau /* 6715b3b75d9cSSepherosa Ziehau * Disable RX by clearing RX filter forcefully. 6716b3b75d9cSSepherosa Ziehau */ 6717b3b75d9cSSepherosa Ziehau sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE; 6718b3b75d9cSSepherosa Ziehau hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */ 6719b3b75d9cSSepherosa Ziehau 6720b3b75d9cSSepherosa Ziehau /* 6721b3b75d9cSSepherosa Ziehau * Give RNDIS enough time to flush all pending data packets. 6722b3b75d9cSSepherosa Ziehau */ 6723b3b75d9cSSepherosa Ziehau pause("waitrx", (200 * hz) / 1000); 6724b3b75d9cSSepherosa Ziehau } 6725b3b75d9cSSepherosa Ziehau 6726b3b75d9cSSepherosa Ziehau /* 6727b3b75d9cSSepherosa Ziehau * NOTE: 6728b3b75d9cSSepherosa Ziehau * RX/TX _must_ have been suspended/disabled, before this function 6729b3b75d9cSSepherosa Ziehau * is called. 6730b3b75d9cSSepherosa Ziehau */ 6731b3b75d9cSSepherosa Ziehau static void 6732b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan) 673315516c77SSepherosa Ziehau { 673415516c77SSepherosa Ziehau struct vmbus_channel **subch = NULL; 6735b3b75d9cSSepherosa Ziehau int nsubch; 6736b3b75d9cSSepherosa Ziehau 6737b3b75d9cSSepherosa Ziehau /* 6738b3b75d9cSSepherosa Ziehau * Drain RX/TX bufrings and interrupts. 6739b3b75d9cSSepherosa Ziehau */ 6740b3b75d9cSSepherosa Ziehau nsubch = nchan - 1; 6741b3b75d9cSSepherosa Ziehau if (nsubch > 0) 6742b3b75d9cSSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 6743b3b75d9cSSepherosa Ziehau 6744b3b75d9cSSepherosa Ziehau if (subch != NULL) { 6745b3b75d9cSSepherosa Ziehau int i; 6746b3b75d9cSSepherosa Ziehau 6747b3b75d9cSSepherosa Ziehau for (i = 0; i < nsubch; ++i) 6748b3b75d9cSSepherosa Ziehau hn_chan_drain(sc, subch[i]); 6749b3b75d9cSSepherosa Ziehau } 6750b3b75d9cSSepherosa Ziehau hn_chan_drain(sc, sc->hn_prichan); 6751b3b75d9cSSepherosa Ziehau 6752b3b75d9cSSepherosa Ziehau if (subch != NULL) 6753b3b75d9cSSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 6754b3b75d9cSSepherosa Ziehau } 6755b3b75d9cSSepherosa Ziehau 6756b3b75d9cSSepherosa Ziehau static void 6757b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc) 6758b3b75d9cSSepherosa Ziehau { 675925641fc7SSepherosa Ziehau struct hn_tx_ring *txr; 6760b3b75d9cSSepherosa Ziehau int i; 676115516c77SSepherosa Ziehau 676215516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 676315516c77SSepherosa Ziehau 676415516c77SSepherosa Ziehau /* 676515516c77SSepherosa Ziehau * Suspend TX. 676615516c77SSepherosa Ziehau */ 676715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 676825641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 676915516c77SSepherosa Ziehau 677015516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 677115516c77SSepherosa Ziehau txr->hn_suspended = 1; 677215516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 677315516c77SSepherosa Ziehau /* No one is able send more packets now. */ 677415516c77SSepherosa Ziehau 677525641fc7SSepherosa Ziehau /* 677625641fc7SSepherosa Ziehau * Wait for all pending sends to finish. 677725641fc7SSepherosa Ziehau * 677825641fc7SSepherosa Ziehau * NOTE: 677925641fc7SSepherosa Ziehau * We will _not_ receive all pending send-done, if the 678025641fc7SSepherosa Ziehau * primary channel is revoked. 678125641fc7SSepherosa Ziehau */ 678225641fc7SSepherosa Ziehau while (hn_tx_ring_pending(txr) && 678325641fc7SSepherosa Ziehau !vmbus_chan_is_revoked(sc->hn_prichan)) 678415516c77SSepherosa Ziehau pause("hnwtx", 1 /* 1 tick */); 678515516c77SSepherosa Ziehau } 678615516c77SSepherosa Ziehau 678715516c77SSepherosa Ziehau /* 6788b3b75d9cSSepherosa Ziehau * Disable RX. 678915516c77SSepherosa Ziehau */ 6790b3b75d9cSSepherosa Ziehau hn_disable_rx(sc); 679115516c77SSepherosa Ziehau 679215516c77SSepherosa Ziehau /* 6793b3b75d9cSSepherosa Ziehau * Drain RX/TX. 679415516c77SSepherosa Ziehau */ 6795b3b75d9cSSepherosa Ziehau hn_drain_rxtx(sc, sc->hn_rx_ring_inuse); 679625641fc7SSepherosa Ziehau 679725641fc7SSepherosa Ziehau /* 679825641fc7SSepherosa Ziehau * Drain any pending TX tasks. 679925641fc7SSepherosa Ziehau * 680025641fc7SSepherosa Ziehau * NOTE: 6801b3b75d9cSSepherosa Ziehau * The above hn_drain_rxtx() can dispatch TX tasks, so the TX 6802b3b75d9cSSepherosa Ziehau * tasks will have to be drained _after_ the above hn_drain_rxtx(). 680325641fc7SSepherosa Ziehau */ 680425641fc7SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 680525641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 680625641fc7SSepherosa Ziehau 680725641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task); 680825641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task); 680925641fc7SSepherosa Ziehau } 681015516c77SSepherosa Ziehau } 681115516c77SSepherosa Ziehau 681215516c77SSepherosa Ziehau static void 681315516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused) 681415516c77SSepherosa Ziehau { 681515516c77SSepherosa Ziehau 681615516c77SSepherosa Ziehau ((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL; 681715516c77SSepherosa Ziehau } 681815516c77SSepherosa Ziehau 681915516c77SSepherosa Ziehau static void 682015516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc) 682115516c77SSepherosa Ziehau { 682215516c77SSepherosa Ziehau struct task task; 682315516c77SSepherosa Ziehau 682415516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 682515516c77SSepherosa Ziehau 682615516c77SSepherosa Ziehau /* 682715516c77SSepherosa Ziehau * Make sure that hn_mgmt_taskq0 can nolonger be accessed 682815516c77SSepherosa Ziehau * through hn_mgmt_taskq. 682915516c77SSepherosa Ziehau */ 683015516c77SSepherosa Ziehau TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc); 683115516c77SSepherosa Ziehau vmbus_chan_run_task(sc->hn_prichan, &task); 683215516c77SSepherosa Ziehau 683315516c77SSepherosa Ziehau /* 683415516c77SSepherosa Ziehau * Make sure that all pending management tasks are completed. 683515516c77SSepherosa Ziehau */ 683615516c77SSepherosa Ziehau taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init); 683715516c77SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status); 683815516c77SSepherosa Ziehau taskqueue_drain_all(sc->hn_mgmt_taskq0); 683915516c77SSepherosa Ziehau } 684015516c77SSepherosa Ziehau 684115516c77SSepherosa Ziehau static void 684215516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc) 684315516c77SSepherosa Ziehau { 684415516c77SSepherosa Ziehau 684587f8129dSSepherosa Ziehau /* Disable polling. */ 684687f8129dSSepherosa Ziehau hn_polling(sc, 0); 684787f8129dSSepherosa Ziehau 68489c6cae24SSepherosa Ziehau /* 68499c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, the synthetic 68509c6cae24SSepherosa Ziehau * device is receiving packets, so the data path of the 68519c6cae24SSepherosa Ziehau * synthetic device must be suspended. 68529c6cae24SSepherosa Ziehau */ 68535bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 6854962f0357SSepherosa Ziehau (sc->hn_flags & HN_FLAG_RXVF)) 685515516c77SSepherosa Ziehau hn_suspend_data(sc); 685615516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 685715516c77SSepherosa Ziehau } 685815516c77SSepherosa Ziehau 685915516c77SSepherosa Ziehau static void 686015516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt) 686115516c77SSepherosa Ziehau { 686215516c77SSepherosa Ziehau int i; 686315516c77SSepherosa Ziehau 686415516c77SSepherosa Ziehau KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt, 686515516c77SSepherosa Ziehau ("invalid TX ring count %d", tx_ring_cnt)); 686615516c77SSepherosa Ziehau 686715516c77SSepherosa Ziehau for (i = 0; i < tx_ring_cnt; ++i) { 686815516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 686915516c77SSepherosa Ziehau 687015516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 687115516c77SSepherosa Ziehau txr->hn_suspended = 0; 687215516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 687315516c77SSepherosa Ziehau } 687415516c77SSepherosa Ziehau } 687515516c77SSepherosa Ziehau 687615516c77SSepherosa Ziehau static void 687715516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc) 687815516c77SSepherosa Ziehau { 687915516c77SSepherosa Ziehau int i; 688015516c77SSepherosa Ziehau 688115516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 688215516c77SSepherosa Ziehau 688315516c77SSepherosa Ziehau /* 688415516c77SSepherosa Ziehau * Re-enable RX. 688515516c77SSepherosa Ziehau */ 6886c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 688715516c77SSepherosa Ziehau 688815516c77SSepherosa Ziehau /* 688915516c77SSepherosa Ziehau * Make sure to clear suspend status on "all" TX rings, 689015516c77SSepherosa Ziehau * since hn_tx_ring_inuse can be changed after 689115516c77SSepherosa Ziehau * hn_suspend_data(). 689215516c77SSepherosa Ziehau */ 689315516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_cnt); 689415516c77SSepherosa Ziehau 689523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 689623bf9e15SSepherosa Ziehau if (!hn_use_if_start) 689723bf9e15SSepherosa Ziehau #endif 689823bf9e15SSepherosa Ziehau { 689915516c77SSepherosa Ziehau /* 690015516c77SSepherosa Ziehau * Flush unused drbrs, since hn_tx_ring_inuse may be 690115516c77SSepherosa Ziehau * reduced. 690215516c77SSepherosa Ziehau */ 690315516c77SSepherosa Ziehau for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i) 690415516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 690515516c77SSepherosa Ziehau } 690615516c77SSepherosa Ziehau 690715516c77SSepherosa Ziehau /* 690815516c77SSepherosa Ziehau * Kick start TX. 690915516c77SSepherosa Ziehau */ 691015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 691115516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 691215516c77SSepherosa Ziehau 691315516c77SSepherosa Ziehau /* 691415516c77SSepherosa Ziehau * Use txeof task, so that any pending oactive can be 691515516c77SSepherosa Ziehau * cleared properly. 691615516c77SSepherosa Ziehau */ 691715516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 691815516c77SSepherosa Ziehau } 691915516c77SSepherosa Ziehau } 692015516c77SSepherosa Ziehau 692115516c77SSepherosa Ziehau static void 692215516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc) 692315516c77SSepherosa Ziehau { 692415516c77SSepherosa Ziehau 692515516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 692615516c77SSepherosa Ziehau 692715516c77SSepherosa Ziehau /* 692815516c77SSepherosa Ziehau * Kick off network change detection, if it was pending. 692915516c77SSepherosa Ziehau * If no network change was pending, start link status 693015516c77SSepherosa Ziehau * checks, which is more lightweight than network change 693115516c77SSepherosa Ziehau * detection. 693215516c77SSepherosa Ziehau */ 693315516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 693415516c77SSepherosa Ziehau hn_change_network(sc); 693515516c77SSepherosa Ziehau else 693615516c77SSepherosa Ziehau hn_update_link_status(sc); 693715516c77SSepherosa Ziehau } 693815516c77SSepherosa Ziehau 693915516c77SSepherosa Ziehau static void 694015516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc) 694115516c77SSepherosa Ziehau { 694215516c77SSepherosa Ziehau 69439c6cae24SSepherosa Ziehau /* 69449c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, the synthetic 69459c6cae24SSepherosa Ziehau * device have to receive packets, so the data path of the 69469c6cae24SSepherosa Ziehau * synthetic device must be resumed. 69479c6cae24SSepherosa Ziehau */ 69485bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 6949962f0357SSepherosa Ziehau (sc->hn_flags & HN_FLAG_RXVF)) 695015516c77SSepherosa Ziehau hn_resume_data(sc); 69515bdfd3fdSDexuan Cui 69525bdfd3fdSDexuan Cui /* 69539c6cae24SSepherosa Ziehau * Don't resume link status change if VF is attached/activated. 69549c6cae24SSepherosa Ziehau * - In the non-transparent VF mode, the synthetic device marks 69559c6cae24SSepherosa Ziehau * link down until the VF is deactivated; i.e. VF is down. 69569c6cae24SSepherosa Ziehau * - In transparent VF mode, VF's media status is used until 69579c6cae24SSepherosa Ziehau * the VF is detached. 69585bdfd3fdSDexuan Cui */ 69599c6cae24SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) == 0 && 69609c6cae24SSepherosa Ziehau !(hn_xpnt_vf && sc->hn_vf_ifp != NULL)) 696115516c77SSepherosa Ziehau hn_resume_mgmt(sc); 696287f8129dSSepherosa Ziehau 696387f8129dSSepherosa Ziehau /* 696487f8129dSSepherosa Ziehau * Re-enable polling if this interface is running and 696587f8129dSSepherosa Ziehau * the polling is requested. 696687f8129dSSepherosa Ziehau */ 696787f8129dSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0) 696887f8129dSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 696915516c77SSepherosa Ziehau } 697015516c77SSepherosa Ziehau 697115516c77SSepherosa Ziehau static void 697215516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen) 697315516c77SSepherosa Ziehau { 697415516c77SSepherosa Ziehau const struct rndis_status_msg *msg; 697515516c77SSepherosa Ziehau int ofs; 697615516c77SSepherosa Ziehau 697715516c77SSepherosa Ziehau if (dlen < sizeof(*msg)) { 697815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid RNDIS status\n"); 697915516c77SSepherosa Ziehau return; 698015516c77SSepherosa Ziehau } 698115516c77SSepherosa Ziehau msg = data; 698215516c77SSepherosa Ziehau 698315516c77SSepherosa Ziehau switch (msg->rm_status) { 698415516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_CONNECT: 698515516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_DISCONNECT: 698615516c77SSepherosa Ziehau hn_update_link_status(sc); 698715516c77SSepherosa Ziehau break; 698815516c77SSepherosa Ziehau 698915516c77SSepherosa Ziehau case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: 699040905afaSSepherosa Ziehau case RNDIS_STATUS_LINK_SPEED_CHANGE: 699115516c77SSepherosa Ziehau /* Not really useful; ignore. */ 699215516c77SSepherosa Ziehau break; 699315516c77SSepherosa Ziehau 699415516c77SSepherosa Ziehau case RNDIS_STATUS_NETWORK_CHANGE: 699515516c77SSepherosa Ziehau ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset); 699615516c77SSepherosa Ziehau if (dlen < ofs + msg->rm_stbuflen || 699715516c77SSepherosa Ziehau msg->rm_stbuflen < sizeof(uint32_t)) { 699815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed\n"); 699915516c77SSepherosa Ziehau } else { 700015516c77SSepherosa Ziehau uint32_t change; 700115516c77SSepherosa Ziehau 700215516c77SSepherosa Ziehau memcpy(&change, ((const uint8_t *)msg) + ofs, 700315516c77SSepherosa Ziehau sizeof(change)); 700415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed, change %u\n", 700515516c77SSepherosa Ziehau change); 700615516c77SSepherosa Ziehau } 700715516c77SSepherosa Ziehau hn_change_network(sc); 700815516c77SSepherosa Ziehau break; 700915516c77SSepherosa Ziehau 701015516c77SSepherosa Ziehau default: 701115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n", 701215516c77SSepherosa Ziehau msg->rm_status); 701315516c77SSepherosa Ziehau break; 701415516c77SSepherosa Ziehau } 701515516c77SSepherosa Ziehau } 701615516c77SSepherosa Ziehau 701715516c77SSepherosa Ziehau static int 701815516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info) 701915516c77SSepherosa Ziehau { 702015516c77SSepherosa Ziehau const struct rndis_pktinfo *pi = info_data; 702115516c77SSepherosa Ziehau uint32_t mask = 0; 702215516c77SSepherosa Ziehau 702315516c77SSepherosa Ziehau while (info_dlen != 0) { 702415516c77SSepherosa Ziehau const void *data; 702515516c77SSepherosa Ziehau uint32_t dlen; 702615516c77SSepherosa Ziehau 702715516c77SSepherosa Ziehau if (__predict_false(info_dlen < sizeof(*pi))) 702815516c77SSepherosa Ziehau return (EINVAL); 702915516c77SSepherosa Ziehau if (__predict_false(info_dlen < pi->rm_size)) 703015516c77SSepherosa Ziehau return (EINVAL); 703115516c77SSepherosa Ziehau info_dlen -= pi->rm_size; 703215516c77SSepherosa Ziehau 703315516c77SSepherosa Ziehau if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK)) 703415516c77SSepherosa Ziehau return (EINVAL); 703515516c77SSepherosa Ziehau if (__predict_false(pi->rm_size < pi->rm_pktinfooffset)) 703615516c77SSepherosa Ziehau return (EINVAL); 703715516c77SSepherosa Ziehau dlen = pi->rm_size - pi->rm_pktinfooffset; 703815516c77SSepherosa Ziehau data = pi->rm_data; 703915516c77SSepherosa Ziehau 704015516c77SSepherosa Ziehau switch (pi->rm_type) { 704115516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_VLAN: 704215516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE)) 704315516c77SSepherosa Ziehau return (EINVAL); 704415516c77SSepherosa Ziehau info->vlan_info = *((const uint32_t *)data); 704515516c77SSepherosa Ziehau mask |= HN_RXINFO_VLAN; 704615516c77SSepherosa Ziehau break; 704715516c77SSepherosa Ziehau 704815516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_CSUM: 704915516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE)) 705015516c77SSepherosa Ziehau return (EINVAL); 705115516c77SSepherosa Ziehau info->csum_info = *((const uint32_t *)data); 705215516c77SSepherosa Ziehau mask |= HN_RXINFO_CSUM; 705315516c77SSepherosa Ziehau break; 705415516c77SSepherosa Ziehau 705515516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHVAL: 705615516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE)) 705715516c77SSepherosa Ziehau return (EINVAL); 705815516c77SSepherosa Ziehau info->hash_value = *((const uint32_t *)data); 705915516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHVAL; 706015516c77SSepherosa Ziehau break; 706115516c77SSepherosa Ziehau 706215516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHINF: 706315516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE)) 706415516c77SSepherosa Ziehau return (EINVAL); 706515516c77SSepherosa Ziehau info->hash_info = *((const uint32_t *)data); 706615516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHINF; 706715516c77SSepherosa Ziehau break; 706815516c77SSepherosa Ziehau 706915516c77SSepherosa Ziehau default: 707015516c77SSepherosa Ziehau goto next; 707115516c77SSepherosa Ziehau } 707215516c77SSepherosa Ziehau 707315516c77SSepherosa Ziehau if (mask == HN_RXINFO_ALL) { 707415516c77SSepherosa Ziehau /* All found; done */ 707515516c77SSepherosa Ziehau break; 707615516c77SSepherosa Ziehau } 707715516c77SSepherosa Ziehau next: 707815516c77SSepherosa Ziehau pi = (const struct rndis_pktinfo *) 707915516c77SSepherosa Ziehau ((const uint8_t *)pi + pi->rm_size); 708015516c77SSepherosa Ziehau } 708115516c77SSepherosa Ziehau 708215516c77SSepherosa Ziehau /* 708315516c77SSepherosa Ziehau * Final fixup. 708415516c77SSepherosa Ziehau * - If there is no hash value, invalidate the hash info. 708515516c77SSepherosa Ziehau */ 708615516c77SSepherosa Ziehau if ((mask & HN_RXINFO_HASHVAL) == 0) 708715516c77SSepherosa Ziehau info->hash_info = HN_NDIS_HASH_INFO_INVALID; 708815516c77SSepherosa Ziehau return (0); 708915516c77SSepherosa Ziehau } 709015516c77SSepherosa Ziehau 709115516c77SSepherosa Ziehau static __inline bool 709215516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len) 709315516c77SSepherosa Ziehau { 709415516c77SSepherosa Ziehau 709515516c77SSepherosa Ziehau if (off < check_off) { 709615516c77SSepherosa Ziehau if (__predict_true(off + len <= check_off)) 709715516c77SSepherosa Ziehau return (false); 709815516c77SSepherosa Ziehau } else if (off > check_off) { 709915516c77SSepherosa Ziehau if (__predict_true(check_off + check_len <= off)) 710015516c77SSepherosa Ziehau return (false); 710115516c77SSepherosa Ziehau } 710215516c77SSepherosa Ziehau return (true); 710315516c77SSepherosa Ziehau } 710415516c77SSepherosa Ziehau 710515516c77SSepherosa Ziehau static void 710615516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen) 710715516c77SSepherosa Ziehau { 710815516c77SSepherosa Ziehau const struct rndis_packet_msg *pkt; 710915516c77SSepherosa Ziehau struct hn_rxinfo info; 711015516c77SSepherosa Ziehau int data_off, pktinfo_off, data_len, pktinfo_len; 711115516c77SSepherosa Ziehau 711215516c77SSepherosa Ziehau /* 711315516c77SSepherosa Ziehau * Check length. 711415516c77SSepherosa Ziehau */ 711515516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*pkt))) { 711615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n"); 711715516c77SSepherosa Ziehau return; 711815516c77SSepherosa Ziehau } 711915516c77SSepherosa Ziehau pkt = data; 712015516c77SSepherosa Ziehau 712115516c77SSepherosa Ziehau if (__predict_false(dlen < pkt->rm_len)) { 712215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, " 712315516c77SSepherosa Ziehau "dlen %d, msglen %u\n", dlen, pkt->rm_len); 712415516c77SSepherosa Ziehau return; 712515516c77SSepherosa Ziehau } 712615516c77SSepherosa Ziehau if (__predict_false(pkt->rm_len < 712715516c77SSepherosa Ziehau pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) { 712815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, " 712915516c77SSepherosa Ziehau "msglen %u, data %u, oob %u, pktinfo %u\n", 713015516c77SSepherosa Ziehau pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen, 713115516c77SSepherosa Ziehau pkt->rm_pktinfolen); 713215516c77SSepherosa Ziehau return; 713315516c77SSepherosa Ziehau } 713415516c77SSepherosa Ziehau if (__predict_false(pkt->rm_datalen == 0)) { 713515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n"); 713615516c77SSepherosa Ziehau return; 713715516c77SSepherosa Ziehau } 713815516c77SSepherosa Ziehau 713915516c77SSepherosa Ziehau /* 714015516c77SSepherosa Ziehau * Check offests. 714115516c77SSepherosa Ziehau */ 714215516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs) \ 714315516c77SSepherosa Ziehau ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \ 714415516c77SSepherosa Ziehau ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK)) 714515516c77SSepherosa Ziehau 714615516c77SSepherosa Ziehau /* XXX Hyper-V does not meet data offset alignment requirement */ 714715516c77SSepherosa Ziehau if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) { 714815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 714915516c77SSepherosa Ziehau "data offset %u\n", pkt->rm_dataoffset); 715015516c77SSepherosa Ziehau return; 715115516c77SSepherosa Ziehau } 715215516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdataoffset > 0 && 715315516c77SSepherosa Ziehau IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) { 715415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 715515516c77SSepherosa Ziehau "oob offset %u\n", pkt->rm_oobdataoffset); 715615516c77SSepherosa Ziehau return; 715715516c77SSepherosa Ziehau } 715815516c77SSepherosa Ziehau if (__predict_true(pkt->rm_pktinfooffset > 0) && 715915516c77SSepherosa Ziehau __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) { 716015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 716115516c77SSepherosa Ziehau "pktinfo offset %u\n", pkt->rm_pktinfooffset); 716215516c77SSepherosa Ziehau return; 716315516c77SSepherosa Ziehau } 716415516c77SSepherosa Ziehau 716515516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID 716615516c77SSepherosa Ziehau 716715516c77SSepherosa Ziehau data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset); 716815516c77SSepherosa Ziehau data_len = pkt->rm_datalen; 716915516c77SSepherosa Ziehau pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset); 717015516c77SSepherosa Ziehau pktinfo_len = pkt->rm_pktinfolen; 717115516c77SSepherosa Ziehau 717215516c77SSepherosa Ziehau /* 717315516c77SSepherosa Ziehau * Check OOB coverage. 717415516c77SSepherosa Ziehau */ 717515516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdatalen != 0)) { 717615516c77SSepherosa Ziehau int oob_off, oob_len; 717715516c77SSepherosa Ziehau 717815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "got oobdata\n"); 717915516c77SSepherosa Ziehau oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset); 718015516c77SSepherosa Ziehau oob_len = pkt->rm_oobdatalen; 718115516c77SSepherosa Ziehau 718215516c77SSepherosa Ziehau if (__predict_false(oob_off + oob_len > pkt->rm_len)) { 718315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 718415516c77SSepherosa Ziehau "oob overflow, msglen %u, oob abs %d len %d\n", 718515516c77SSepherosa Ziehau pkt->rm_len, oob_off, oob_len); 718615516c77SSepherosa Ziehau return; 718715516c77SSepherosa Ziehau } 718815516c77SSepherosa Ziehau 718915516c77SSepherosa Ziehau /* 719015516c77SSepherosa Ziehau * Check against data. 719115516c77SSepherosa Ziehau */ 719215516c77SSepherosa Ziehau if (hn_rndis_check_overlap(oob_off, oob_len, 719315516c77SSepherosa Ziehau data_off, data_len)) { 719415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 719515516c77SSepherosa Ziehau "oob overlaps data, oob abs %d len %d, " 719615516c77SSepherosa Ziehau "data abs %d len %d\n", 719715516c77SSepherosa Ziehau oob_off, oob_len, data_off, data_len); 719815516c77SSepherosa Ziehau return; 719915516c77SSepherosa Ziehau } 720015516c77SSepherosa Ziehau 720115516c77SSepherosa Ziehau /* 720215516c77SSepherosa Ziehau * Check against pktinfo. 720315516c77SSepherosa Ziehau */ 720415516c77SSepherosa Ziehau if (pktinfo_len != 0 && 720515516c77SSepherosa Ziehau hn_rndis_check_overlap(oob_off, oob_len, 720615516c77SSepherosa Ziehau pktinfo_off, pktinfo_len)) { 720715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 720815516c77SSepherosa Ziehau "oob overlaps pktinfo, oob abs %d len %d, " 720915516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 721015516c77SSepherosa Ziehau oob_off, oob_len, pktinfo_off, pktinfo_len); 721115516c77SSepherosa Ziehau return; 721215516c77SSepherosa Ziehau } 721315516c77SSepherosa Ziehau } 721415516c77SSepherosa Ziehau 721515516c77SSepherosa Ziehau /* 721615516c77SSepherosa Ziehau * Check per-packet-info coverage and find useful per-packet-info. 721715516c77SSepherosa Ziehau */ 721815516c77SSepherosa Ziehau info.vlan_info = HN_NDIS_VLAN_INFO_INVALID; 721915516c77SSepherosa Ziehau info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID; 722015516c77SSepherosa Ziehau info.hash_info = HN_NDIS_HASH_INFO_INVALID; 722115516c77SSepherosa Ziehau if (__predict_true(pktinfo_len != 0)) { 722215516c77SSepherosa Ziehau bool overlap; 722315516c77SSepherosa Ziehau int error; 722415516c77SSepherosa Ziehau 722515516c77SSepherosa Ziehau if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) { 722615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 722715516c77SSepherosa Ziehau "pktinfo overflow, msglen %u, " 722815516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 722915516c77SSepherosa Ziehau pkt->rm_len, pktinfo_off, pktinfo_len); 723015516c77SSepherosa Ziehau return; 723115516c77SSepherosa Ziehau } 723215516c77SSepherosa Ziehau 723315516c77SSepherosa Ziehau /* 723415516c77SSepherosa Ziehau * Check packet info coverage. 723515516c77SSepherosa Ziehau */ 723615516c77SSepherosa Ziehau overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len, 723715516c77SSepherosa Ziehau data_off, data_len); 723815516c77SSepherosa Ziehau if (__predict_false(overlap)) { 723915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 724015516c77SSepherosa Ziehau "pktinfo overlap data, pktinfo abs %d len %d, " 724115516c77SSepherosa Ziehau "data abs %d len %d\n", 724215516c77SSepherosa Ziehau pktinfo_off, pktinfo_len, data_off, data_len); 724315516c77SSepherosa Ziehau return; 724415516c77SSepherosa Ziehau } 724515516c77SSepherosa Ziehau 724615516c77SSepherosa Ziehau /* 724715516c77SSepherosa Ziehau * Find useful per-packet-info. 724815516c77SSepherosa Ziehau */ 724915516c77SSepherosa Ziehau error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off, 725015516c77SSepherosa Ziehau pktinfo_len, &info); 725115516c77SSepherosa Ziehau if (__predict_false(error)) { 725215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg " 725315516c77SSepherosa Ziehau "pktinfo\n"); 725415516c77SSepherosa Ziehau return; 725515516c77SSepherosa Ziehau } 725615516c77SSepherosa Ziehau } 725715516c77SSepherosa Ziehau 725815516c77SSepherosa Ziehau if (__predict_false(data_off + data_len > pkt->rm_len)) { 725915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 726015516c77SSepherosa Ziehau "data overflow, msglen %u, data abs %d len %d\n", 726115516c77SSepherosa Ziehau pkt->rm_len, data_off, data_len); 726215516c77SSepherosa Ziehau return; 726315516c77SSepherosa Ziehau } 726415516c77SSepherosa Ziehau hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info); 726515516c77SSepherosa Ziehau } 726615516c77SSepherosa Ziehau 726715516c77SSepherosa Ziehau static __inline void 726815516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen) 726915516c77SSepherosa Ziehau { 727015516c77SSepherosa Ziehau const struct rndis_msghdr *hdr; 727115516c77SSepherosa Ziehau 727215516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*hdr))) { 727315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS msg\n"); 727415516c77SSepherosa Ziehau return; 727515516c77SSepherosa Ziehau } 727615516c77SSepherosa Ziehau hdr = data; 727715516c77SSepherosa Ziehau 727815516c77SSepherosa Ziehau if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) { 727915516c77SSepherosa Ziehau /* Hot data path. */ 728015516c77SSepherosa Ziehau hn_rndis_rx_data(rxr, data, dlen); 728115516c77SSepherosa Ziehau /* Done! */ 728215516c77SSepherosa Ziehau return; 728315516c77SSepherosa Ziehau } 728415516c77SSepherosa Ziehau 728515516c77SSepherosa Ziehau if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG) 728615516c77SSepherosa Ziehau hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen); 728715516c77SSepherosa Ziehau else 728815516c77SSepherosa Ziehau hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen); 728915516c77SSepherosa Ziehau } 729015516c77SSepherosa Ziehau 729115516c77SSepherosa Ziehau static void 729215516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) 729315516c77SSepherosa Ziehau { 729415516c77SSepherosa Ziehau const struct hn_nvs_hdr *hdr; 729515516c77SSepherosa Ziehau 729615516c77SSepherosa Ziehau if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) { 729715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid nvs notify\n"); 729815516c77SSepherosa Ziehau return; 729915516c77SSepherosa Ziehau } 730015516c77SSepherosa Ziehau hdr = VMBUS_CHANPKT_CONST_DATA(pkt); 730115516c77SSepherosa Ziehau 730215516c77SSepherosa Ziehau if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) { 730315516c77SSepherosa Ziehau /* Useless; ignore */ 730415516c77SSepherosa Ziehau return; 730515516c77SSepherosa Ziehau } 730615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type); 730715516c77SSepherosa Ziehau } 730815516c77SSepherosa Ziehau 730915516c77SSepherosa Ziehau static void 731015516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan, 731115516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkt) 731215516c77SSepherosa Ziehau { 731315516c77SSepherosa Ziehau struct hn_nvs_sendctx *sndc; 731415516c77SSepherosa Ziehau 731515516c77SSepherosa Ziehau sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid; 731615516c77SSepherosa Ziehau sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt), 731715516c77SSepherosa Ziehau VMBUS_CHANPKT_DATALEN(pkt)); 731815516c77SSepherosa Ziehau /* 731915516c77SSepherosa Ziehau * NOTE: 732015516c77SSepherosa Ziehau * 'sndc' CAN NOT be accessed anymore, since it can be freed by 732115516c77SSepherosa Ziehau * its callback. 732215516c77SSepherosa Ziehau */ 732315516c77SSepherosa Ziehau } 732415516c77SSepherosa Ziehau 732515516c77SSepherosa Ziehau static void 732615516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 732715516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkthdr) 732815516c77SSepherosa Ziehau { 732915516c77SSepherosa Ziehau const struct vmbus_chanpkt_rxbuf *pkt; 733015516c77SSepherosa Ziehau const struct hn_nvs_hdr *nvs_hdr; 733115516c77SSepherosa Ziehau int count, i, hlen; 733215516c77SSepherosa Ziehau 733315516c77SSepherosa Ziehau if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) { 733415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n"); 733515516c77SSepherosa Ziehau return; 733615516c77SSepherosa Ziehau } 733715516c77SSepherosa Ziehau nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr); 733815516c77SSepherosa Ziehau 733915516c77SSepherosa Ziehau /* Make sure that this is a RNDIS message. */ 734015516c77SSepherosa Ziehau if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) { 734115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n", 734215516c77SSepherosa Ziehau nvs_hdr->nvs_type); 734315516c77SSepherosa Ziehau return; 734415516c77SSepherosa Ziehau } 734515516c77SSepherosa Ziehau 734615516c77SSepherosa Ziehau hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen); 734715516c77SSepherosa Ziehau if (__predict_false(hlen < sizeof(*pkt))) { 734815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n"); 734915516c77SSepherosa Ziehau return; 735015516c77SSepherosa Ziehau } 735115516c77SSepherosa Ziehau pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr; 735215516c77SSepherosa Ziehau 735315516c77SSepherosa Ziehau if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) { 735415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n", 735515516c77SSepherosa Ziehau pkt->cp_rxbuf_id); 735615516c77SSepherosa Ziehau return; 735715516c77SSepherosa Ziehau } 735815516c77SSepherosa Ziehau 735915516c77SSepherosa Ziehau count = pkt->cp_rxbuf_cnt; 736015516c77SSepherosa Ziehau if (__predict_false(hlen < 736115516c77SSepherosa Ziehau __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) { 736215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count); 736315516c77SSepherosa Ziehau return; 736415516c77SSepherosa Ziehau } 736515516c77SSepherosa Ziehau 736615516c77SSepherosa Ziehau /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 736715516c77SSepherosa Ziehau for (i = 0; i < count; ++i) { 736815516c77SSepherosa Ziehau int ofs, len; 736915516c77SSepherosa Ziehau 737015516c77SSepherosa Ziehau ofs = pkt->cp_rxbuf[i].rb_ofs; 737115516c77SSepherosa Ziehau len = pkt->cp_rxbuf[i].rb_len; 737215516c77SSepherosa Ziehau if (__predict_false(ofs + len > HN_RXBUF_SIZE)) { 737315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, " 737415516c77SSepherosa Ziehau "ofs %d, len %d\n", i, ofs, len); 737515516c77SSepherosa Ziehau continue; 737615516c77SSepherosa Ziehau } 737715516c77SSepherosa Ziehau hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len); 737815516c77SSepherosa Ziehau } 737915516c77SSepherosa Ziehau 738015516c77SSepherosa Ziehau /* 738115516c77SSepherosa Ziehau * Ack the consumed RXBUF associated w/ this channel packet, 738215516c77SSepherosa Ziehau * so that this RXBUF can be recycled by the hypervisor. 738315516c77SSepherosa Ziehau */ 738415516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid); 738515516c77SSepherosa Ziehau } 738615516c77SSepherosa Ziehau 738715516c77SSepherosa Ziehau static void 738815516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 738915516c77SSepherosa Ziehau uint64_t tid) 739015516c77SSepherosa Ziehau { 739115516c77SSepherosa Ziehau struct hn_nvs_rndis_ack ack; 739215516c77SSepherosa Ziehau int retries, error; 739315516c77SSepherosa Ziehau 739415516c77SSepherosa Ziehau ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK; 739515516c77SSepherosa Ziehau ack.nvs_status = HN_NVS_STATUS_OK; 739615516c77SSepherosa Ziehau 739715516c77SSepherosa Ziehau retries = 0; 739815516c77SSepherosa Ziehau again: 739915516c77SSepherosa Ziehau error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 740015516c77SSepherosa Ziehau VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid); 740115516c77SSepherosa Ziehau if (__predict_false(error == EAGAIN)) { 740215516c77SSepherosa Ziehau /* 740315516c77SSepherosa Ziehau * NOTE: 740415516c77SSepherosa Ziehau * This should _not_ happen in real world, since the 740515516c77SSepherosa Ziehau * consumption of the TX bufring from the TX path is 740615516c77SSepherosa Ziehau * controlled. 740715516c77SSepherosa Ziehau */ 740815516c77SSepherosa Ziehau if (rxr->hn_ack_failed == 0) 740915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack retry\n"); 741015516c77SSepherosa Ziehau rxr->hn_ack_failed++; 741115516c77SSepherosa Ziehau retries++; 741215516c77SSepherosa Ziehau if (retries < 10) { 741315516c77SSepherosa Ziehau DELAY(100); 741415516c77SSepherosa Ziehau goto again; 741515516c77SSepherosa Ziehau } 741615516c77SSepherosa Ziehau /* RXBUF leaks! */ 741715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack failed\n"); 741815516c77SSepherosa Ziehau } 741915516c77SSepherosa Ziehau } 742015516c77SSepherosa Ziehau 742115516c77SSepherosa Ziehau static void 742215516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr) 742315516c77SSepherosa Ziehau { 742415516c77SSepherosa Ziehau struct hn_rx_ring *rxr = xrxr; 742515516c77SSepherosa Ziehau struct hn_softc *sc = rxr->hn_ifp->if_softc; 742615516c77SSepherosa Ziehau 742715516c77SSepherosa Ziehau for (;;) { 742815516c77SSepherosa Ziehau struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf; 742915516c77SSepherosa Ziehau int error, pktlen; 743015516c77SSepherosa Ziehau 743115516c77SSepherosa Ziehau pktlen = rxr->hn_pktbuf_len; 743215516c77SSepherosa Ziehau error = vmbus_chan_recv_pkt(chan, pkt, &pktlen); 743315516c77SSepherosa Ziehau if (__predict_false(error == ENOBUFS)) { 743415516c77SSepherosa Ziehau void *nbuf; 743515516c77SSepherosa Ziehau int nlen; 743615516c77SSepherosa Ziehau 743715516c77SSepherosa Ziehau /* 743815516c77SSepherosa Ziehau * Expand channel packet buffer. 743915516c77SSepherosa Ziehau * 744015516c77SSepherosa Ziehau * XXX 744115516c77SSepherosa Ziehau * Use M_WAITOK here, since allocation failure 744215516c77SSepherosa Ziehau * is fatal. 744315516c77SSepherosa Ziehau */ 744415516c77SSepherosa Ziehau nlen = rxr->hn_pktbuf_len * 2; 744515516c77SSepherosa Ziehau while (nlen < pktlen) 744615516c77SSepherosa Ziehau nlen *= 2; 744715516c77SSepherosa Ziehau nbuf = malloc(nlen, M_DEVBUF, M_WAITOK); 744815516c77SSepherosa Ziehau 744915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n", 745015516c77SSepherosa Ziehau rxr->hn_pktbuf_len, nlen); 745115516c77SSepherosa Ziehau 745215516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 745315516c77SSepherosa Ziehau rxr->hn_pktbuf = nbuf; 745415516c77SSepherosa Ziehau rxr->hn_pktbuf_len = nlen; 745515516c77SSepherosa Ziehau /* Retry! */ 745615516c77SSepherosa Ziehau continue; 745715516c77SSepherosa Ziehau } else if (__predict_false(error == EAGAIN)) { 745815516c77SSepherosa Ziehau /* No more channel packets; done! */ 745915516c77SSepherosa Ziehau break; 746015516c77SSepherosa Ziehau } 746115516c77SSepherosa Ziehau KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error)); 746215516c77SSepherosa Ziehau 746315516c77SSepherosa Ziehau switch (pkt->cph_type) { 746415516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_COMP: 746515516c77SSepherosa Ziehau hn_nvs_handle_comp(sc, chan, pkt); 746615516c77SSepherosa Ziehau break; 746715516c77SSepherosa Ziehau 746815516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_RXBUF: 746915516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(rxr, chan, pkt); 747015516c77SSepherosa Ziehau break; 747115516c77SSepherosa Ziehau 747215516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_INBAND: 747315516c77SSepherosa Ziehau hn_nvs_handle_notify(sc, pkt); 747415516c77SSepherosa Ziehau break; 747515516c77SSepherosa Ziehau 747615516c77SSepherosa Ziehau default: 747715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "unknown chan pkt %u\n", 747815516c77SSepherosa Ziehau pkt->cph_type); 747915516c77SSepherosa Ziehau break; 748015516c77SSepherosa Ziehau } 748115516c77SSepherosa Ziehau } 748215516c77SSepherosa Ziehau hn_chan_rollup(rxr, rxr->hn_txr); 748315516c77SSepherosa Ziehau } 748415516c77SSepherosa Ziehau 748515516c77SSepherosa Ziehau static void 7486499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused) 748715516c77SSepherosa Ziehau { 7488fdd0222aSSepherosa Ziehau int i; 7489fdd0222aSSepherosa Ziehau 74902be266caSSepherosa Ziehau hn_udpcs_fixup = counter_u64_alloc(M_WAITOK); 74912be266caSSepherosa Ziehau 74929c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 74939c6cae24SSepherosa Ziehau /* 74949c6cae24SSepherosa Ziehau * Don't use ifnet.if_start if transparent VF mode is requested; 74959c6cae24SSepherosa Ziehau * mainly due to the IFF_DRV_OACTIVE flag. 74969c6cae24SSepherosa Ziehau */ 74979c6cae24SSepherosa Ziehau if (hn_xpnt_vf && hn_use_if_start) { 74989c6cae24SSepherosa Ziehau hn_use_if_start = 0; 74999c6cae24SSepherosa Ziehau printf("hn: tranparent VF mode, if_transmit will be used, " 75009c6cae24SSepherosa Ziehau "instead of if_start\n"); 75019c6cae24SSepherosa Ziehau } 75029c6cae24SSepherosa Ziehau #endif 75039c6cae24SSepherosa Ziehau if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) { 75049c6cae24SSepherosa Ziehau printf("hn: invalid transparent VF attach routing " 75059c6cae24SSepherosa Ziehau "wait timeout %d, reset to %d\n", 75069c6cae24SSepherosa Ziehau hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN); 75079c6cae24SSepherosa Ziehau hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN; 75089c6cae24SSepherosa Ziehau } 75099c6cae24SSepherosa Ziehau 7510fdd0222aSSepherosa Ziehau /* 7511499c3e17SSepherosa Ziehau * Initialize VF map. 7512499c3e17SSepherosa Ziehau */ 7513499c3e17SSepherosa Ziehau rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE); 7514499c3e17SSepherosa Ziehau hn_vfmap_size = HN_VFMAP_SIZE_DEF; 7515499c3e17SSepherosa Ziehau hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF, 7516499c3e17SSepherosa Ziehau M_WAITOK | M_ZERO); 7517499c3e17SSepherosa Ziehau 7518499c3e17SSepherosa Ziehau /* 7519fdd0222aSSepherosa Ziehau * Fix the # of TX taskqueues. 7520fdd0222aSSepherosa Ziehau */ 7521fdd0222aSSepherosa Ziehau if (hn_tx_taskq_cnt <= 0) 7522fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = 1; 7523fdd0222aSSepherosa Ziehau else if (hn_tx_taskq_cnt > mp_ncpus) 7524fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = mp_ncpus; 752515516c77SSepherosa Ziehau 75260e11868dSSepherosa Ziehau /* 75270e11868dSSepherosa Ziehau * Fix the TX taskqueue mode. 75280e11868dSSepherosa Ziehau */ 75290e11868dSSepherosa Ziehau switch (hn_tx_taskq_mode) { 75300e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_INDEP: 75310e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_GLOBAL: 75320e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_EVTTQ: 75330e11868dSSepherosa Ziehau break; 75340e11868dSSepherosa Ziehau default: 75350e11868dSSepherosa Ziehau hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP; 75360e11868dSSepherosa Ziehau break; 75370e11868dSSepherosa Ziehau } 75380e11868dSSepherosa Ziehau 753915516c77SSepherosa Ziehau if (vm_guest != VM_GUEST_HV) 754015516c77SSepherosa Ziehau return; 754115516c77SSepherosa Ziehau 75420e11868dSSepherosa Ziehau if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL) 754315516c77SSepherosa Ziehau return; 754415516c77SSepherosa Ziehau 7545fdd0222aSSepherosa Ziehau hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 7546fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 7547fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 7548fdd0222aSSepherosa Ziehau hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK, 7549fdd0222aSSepherosa Ziehau taskqueue_thread_enqueue, &hn_tx_taskque[i]); 7550fdd0222aSSepherosa Ziehau taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET, 7551fdd0222aSSepherosa Ziehau "hn tx%d", i); 7552fdd0222aSSepherosa Ziehau } 755315516c77SSepherosa Ziehau } 7554499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL); 755515516c77SSepherosa Ziehau 755615516c77SSepherosa Ziehau static void 7557499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused) 755815516c77SSepherosa Ziehau { 755915516c77SSepherosa Ziehau 7560fdd0222aSSepherosa Ziehau if (hn_tx_taskque != NULL) { 7561fdd0222aSSepherosa Ziehau int i; 7562fdd0222aSSepherosa Ziehau 7563fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 7564fdd0222aSSepherosa Ziehau taskqueue_free(hn_tx_taskque[i]); 7565fdd0222aSSepherosa Ziehau free(hn_tx_taskque, M_DEVBUF); 7566fdd0222aSSepherosa Ziehau } 7567499c3e17SSepherosa Ziehau 7568499c3e17SSepherosa Ziehau if (hn_vfmap != NULL) 7569499c3e17SSepherosa Ziehau free(hn_vfmap, M_DEVBUF); 7570499c3e17SSepherosa Ziehau rm_destroy(&hn_vfmap_lock); 75712be266caSSepherosa Ziehau 75722be266caSSepherosa Ziehau counter_u64_free(hn_udpcs_fixup); 757315516c77SSepherosa Ziehau } 7574499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL); 7575