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> 6415516c77SSepherosa Ziehau #include <sys/bus.h> 6515516c77SSepherosa Ziehau #include <sys/kernel.h> 6615516c77SSepherosa Ziehau #include <sys/limits.h> 6715516c77SSepherosa Ziehau #include <sys/malloc.h> 6815516c77SSepherosa Ziehau #include <sys/mbuf.h> 6915516c77SSepherosa Ziehau #include <sys/module.h> 7015516c77SSepherosa Ziehau #include <sys/queue.h> 7115516c77SSepherosa Ziehau #include <sys/lock.h> 72499c3e17SSepherosa Ziehau #include <sys/rmlock.h> 73499c3e17SSepherosa Ziehau #include <sys/sbuf.h> 7415516c77SSepherosa Ziehau #include <sys/smp.h> 7515516c77SSepherosa Ziehau #include <sys/socket.h> 7615516c77SSepherosa Ziehau #include <sys/sockio.h> 7715516c77SSepherosa Ziehau #include <sys/sx.h> 7815516c77SSepherosa Ziehau #include <sys/sysctl.h> 7915516c77SSepherosa Ziehau #include <sys/systm.h> 8015516c77SSepherosa Ziehau #include <sys/taskqueue.h> 8115516c77SSepherosa Ziehau #include <sys/buf_ring.h> 825bdfd3fdSDexuan Cui #include <sys/eventhandler.h> 8315516c77SSepherosa Ziehau 8415516c77SSepherosa Ziehau #include <machine/atomic.h> 8515516c77SSepherosa Ziehau #include <machine/in_cksum.h> 8615516c77SSepherosa Ziehau 8715516c77SSepherosa Ziehau #include <net/bpf.h> 8815516c77SSepherosa Ziehau #include <net/ethernet.h> 8915516c77SSepherosa Ziehau #include <net/if.h> 905bdfd3fdSDexuan Cui #include <net/if_dl.h> 9115516c77SSepherosa Ziehau #include <net/if_media.h> 9215516c77SSepherosa Ziehau #include <net/if_types.h> 9315516c77SSepherosa Ziehau #include <net/if_var.h> 9415516c77SSepherosa Ziehau #include <net/rndis.h> 9534d68912SSepherosa Ziehau #ifdef RSS 9634d68912SSepherosa Ziehau #include <net/rss_config.h> 9734d68912SSepherosa Ziehau #endif 9815516c77SSepherosa Ziehau 9915516c77SSepherosa Ziehau #include <netinet/in_systm.h> 10015516c77SSepherosa Ziehau #include <netinet/in.h> 10115516c77SSepherosa Ziehau #include <netinet/ip.h> 10215516c77SSepherosa Ziehau #include <netinet/ip6.h> 10315516c77SSepherosa Ziehau #include <netinet/tcp.h> 10415516c77SSepherosa Ziehau #include <netinet/tcp_lro.h> 10515516c77SSepherosa Ziehau #include <netinet/udp.h> 10615516c77SSepherosa Ziehau 10715516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h> 10815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h> 10915516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h> 11015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h> 11115516c77SSepherosa Ziehau 11215516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h> 11315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h> 11415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h> 11515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h> 11615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h> 11715516c77SSepherosa Ziehau 11815516c77SSepherosa Ziehau #include "vmbus_if.h" 11915516c77SSepherosa Ziehau 12023bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT 12123bf9e15SSepherosa Ziehau 12215516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX 8 12315516c77SSepherosa Ziehau 124499c3e17SSepherosa Ziehau #define HN_VFMAP_SIZE_DEF 8 125499c3e17SSepherosa Ziehau 1269c6cae24SSepherosa Ziehau #define HN_XPNT_VF_ATTWAIT_MIN 2 /* seconds */ 1279c6cae24SSepherosa Ziehau 12815516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */ 12915516c77SSepherosa Ziehau #define HN_TX_DESC_CNT 512 13015516c77SSepherosa Ziehau 13115516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN \ 13215516c77SSepherosa Ziehau (sizeof(struct rndis_packet_msg) + \ 13315516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) + \ 13415516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) + \ 13515516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) + \ 13615516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE)) 13715516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY PAGE_SIZE 13815516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN CACHE_LINE_SIZE 13915516c77SSepherosa Ziehau 14015516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY PAGE_SIZE 14115516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE IP_MAXPACKET 14215516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE PAGE_SIZE 14315516c77SSepherosa Ziehau /* -1 for RNDIS packet message */ 14415516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX (HN_GPACNT_MAX - 1) 14515516c77SSepherosa Ziehau 14615516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF 128 14715516c77SSepherosa Ziehau 14815516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH 8 14915516c77SSepherosa Ziehau 15015516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF (16 * 1024) 15115516c77SSepherosa Ziehau 15215516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF 128 15315516c77SSepherosa Ziehau 15415516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF (12 * ETHERMTU) 15515516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF (25 * ETHERMTU) 15615516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */ 15715516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp) (2 * (ifp)->if_mtu) 15815516c77SSepherosa Ziehau 15915516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF 1 16015516c77SSepherosa Ziehau 16115516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc) \ 16215516c77SSepherosa Ziehau sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev)) 16315516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc) sx_destroy(&(sc)->hn_lock) 16415516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc) sx_assert(&(sc)->hn_lock, SA_XLOCKED) 165fdc4f478SSepherosa Ziehau #define HN_LOCK(sc) \ 166fdc4f478SSepherosa Ziehau do { \ 167fdc4f478SSepherosa Ziehau while (sx_try_xlock(&(sc)->hn_lock) == 0) \ 168fdc4f478SSepherosa Ziehau DELAY(1000); \ 169fdc4f478SSepherosa Ziehau } while (0) 17015516c77SSepherosa Ziehau #define HN_UNLOCK(sc) sx_xunlock(&(sc)->hn_lock) 17115516c77SSepherosa Ziehau 17215516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK (CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP) 17315516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK (CSUM_IP6_TCP | CSUM_IP6_UDP) 17415516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc) \ 17515516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK) 17615516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc) \ 17715516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK) 17815516c77SSepherosa Ziehau 179dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align) \ 180dc13fee6SSepherosa Ziehau roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \ 181dc13fee6SSepherosa Ziehau HN_RNDIS_PKT_LEN, (align)) 182dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align) \ 183dc13fee6SSepherosa Ziehau roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align)) 184dc13fee6SSepherosa Ziehau 18534d68912SSepherosa Ziehau #ifdef RSS 18634d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx) rss_getcpu((idx) % rss_getnumbuckets()) 18734d68912SSepherosa Ziehau #else 1880e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx) (((sc)->hn_cpu + (idx)) % mp_ncpus) 18934d68912SSepherosa Ziehau #endif 1900e11868dSSepherosa Ziehau 19115516c77SSepherosa Ziehau struct hn_txdesc { 19215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 19315516c77SSepherosa Ziehau SLIST_ENTRY(hn_txdesc) link; 19415516c77SSepherosa Ziehau #endif 195dc13fee6SSepherosa Ziehau STAILQ_ENTRY(hn_txdesc) agg_link; 196dc13fee6SSepherosa Ziehau 197dc13fee6SSepherosa Ziehau /* Aggregated txdescs, in sending order. */ 198dc13fee6SSepherosa Ziehau STAILQ_HEAD(, hn_txdesc) agg_list; 199dc13fee6SSepherosa Ziehau 200dc13fee6SSepherosa Ziehau /* The oldest packet, if transmission aggregation happens. */ 20115516c77SSepherosa Ziehau struct mbuf *m; 20215516c77SSepherosa Ziehau struct hn_tx_ring *txr; 20315516c77SSepherosa Ziehau int refs; 20415516c77SSepherosa Ziehau uint32_t flags; /* HN_TXD_FLAG_ */ 20515516c77SSepherosa Ziehau struct hn_nvs_sendctx send_ctx; 20615516c77SSepherosa Ziehau uint32_t chim_index; 20715516c77SSepherosa Ziehau int chim_size; 20815516c77SSepherosa Ziehau 20915516c77SSepherosa Ziehau bus_dmamap_t data_dmap; 21015516c77SSepherosa Ziehau 21115516c77SSepherosa Ziehau bus_addr_t rndis_pkt_paddr; 21215516c77SSepherosa Ziehau struct rndis_packet_msg *rndis_pkt; 21315516c77SSepherosa Ziehau bus_dmamap_t rndis_pkt_dmap; 21415516c77SSepherosa Ziehau }; 21515516c77SSepherosa Ziehau 21615516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST 0x0001 21715516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP 0x0002 218dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG 0x0004 21915516c77SSepherosa Ziehau 22015516c77SSepherosa Ziehau struct hn_rxinfo { 22115516c77SSepherosa Ziehau uint32_t vlan_info; 22215516c77SSepherosa Ziehau uint32_t csum_info; 22315516c77SSepherosa Ziehau uint32_t hash_info; 22415516c77SSepherosa Ziehau uint32_t hash_value; 22515516c77SSepherosa Ziehau }; 22615516c77SSepherosa Ziehau 227962f0357SSepherosa Ziehau struct hn_rxvf_setarg { 2285bdfd3fdSDexuan Cui struct hn_rx_ring *rxr; 229962f0357SSepherosa Ziehau struct ifnet *vf_ifp; 2305bdfd3fdSDexuan Cui }; 2315bdfd3fdSDexuan Cui 23215516c77SSepherosa Ziehau #define HN_RXINFO_VLAN 0x0001 23315516c77SSepherosa Ziehau #define HN_RXINFO_CSUM 0x0002 23415516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF 0x0004 23515516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL 0x0008 23615516c77SSepherosa Ziehau #define HN_RXINFO_ALL \ 23715516c77SSepherosa Ziehau (HN_RXINFO_VLAN | \ 23815516c77SSepherosa Ziehau HN_RXINFO_CSUM | \ 23915516c77SSepherosa Ziehau HN_RXINFO_HASHINF | \ 24015516c77SSepherosa Ziehau HN_RXINFO_HASHVAL) 24115516c77SSepherosa Ziehau 24215516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID 0xffffffff 24315516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID 0 24415516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID 0 24515516c77SSepherosa Ziehau 24615516c77SSepherosa Ziehau static int hn_probe(device_t); 24715516c77SSepherosa Ziehau static int hn_attach(device_t); 24815516c77SSepherosa Ziehau static int hn_detach(device_t); 24915516c77SSepherosa Ziehau static int hn_shutdown(device_t); 25015516c77SSepherosa Ziehau static void hn_chan_callback(struct vmbus_channel *, 25115516c77SSepherosa Ziehau void *); 25215516c77SSepherosa Ziehau 25315516c77SSepherosa Ziehau static void hn_init(void *); 25415516c77SSepherosa Ziehau static int hn_ioctl(struct ifnet *, u_long, caddr_t); 25523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 25615516c77SSepherosa Ziehau static void hn_start(struct ifnet *); 25723bf9e15SSepherosa Ziehau #endif 25815516c77SSepherosa Ziehau static int hn_transmit(struct ifnet *, struct mbuf *); 25915516c77SSepherosa Ziehau static void hn_xmit_qflush(struct ifnet *); 26015516c77SSepherosa Ziehau static int hn_ifmedia_upd(struct ifnet *); 26115516c77SSepherosa Ziehau static void hn_ifmedia_sts(struct ifnet *, 26215516c77SSepherosa Ziehau struct ifmediareq *); 26315516c77SSepherosa Ziehau 264499c3e17SSepherosa Ziehau static void hn_ifnet_event(void *, struct ifnet *, int); 265499c3e17SSepherosa Ziehau static void hn_ifaddr_event(void *, struct ifnet *); 266499c3e17SSepherosa Ziehau static void hn_ifnet_attevent(void *, struct ifnet *); 267499c3e17SSepherosa Ziehau static void hn_ifnet_detevent(void *, struct ifnet *); 2689c6cae24SSepherosa Ziehau static void hn_ifnet_lnkevent(void *, struct ifnet *, int); 269499c3e17SSepherosa Ziehau 270962f0357SSepherosa Ziehau static bool hn_ismyvf(const struct hn_softc *, 271962f0357SSepherosa Ziehau const struct ifnet *); 272962f0357SSepherosa Ziehau static void hn_rxvf_change(struct hn_softc *, 273962f0357SSepherosa Ziehau struct ifnet *, bool); 274962f0357SSepherosa Ziehau static void hn_rxvf_set(struct hn_softc *, struct ifnet *); 275962f0357SSepherosa Ziehau static void hn_rxvf_set_task(void *, int); 2769c6cae24SSepherosa Ziehau static void hn_xpnt_vf_input(struct ifnet *, struct mbuf *); 2779c6cae24SSepherosa Ziehau static int hn_xpnt_vf_iocsetflags(struct hn_softc *); 2789c6cae24SSepherosa Ziehau static int hn_xpnt_vf_iocsetcaps(struct hn_softc *, 2799c6cae24SSepherosa Ziehau struct ifreq *); 2809c6cae24SSepherosa Ziehau static void hn_xpnt_vf_saveifflags(struct hn_softc *); 2819c6cae24SSepherosa Ziehau static bool hn_xpnt_vf_isready(struct hn_softc *); 2829c6cae24SSepherosa Ziehau static void hn_xpnt_vf_setready(struct hn_softc *); 2839c6cae24SSepherosa Ziehau static void hn_xpnt_vf_init_taskfunc(void *, int); 2849c6cae24SSepherosa Ziehau static void hn_xpnt_vf_init(struct hn_softc *); 285a97fff19SSepherosa Ziehau static void hn_xpnt_vf_setenable(struct hn_softc *); 286a97fff19SSepherosa Ziehau static void hn_xpnt_vf_setdisable(struct hn_softc *, bool); 287962f0357SSepherosa Ziehau 28815516c77SSepherosa Ziehau static int hn_rndis_rxinfo(const void *, int, 28915516c77SSepherosa Ziehau struct hn_rxinfo *); 29015516c77SSepherosa Ziehau static void hn_rndis_rx_data(struct hn_rx_ring *, 29115516c77SSepherosa Ziehau const void *, int); 29215516c77SSepherosa Ziehau static void hn_rndis_rx_status(struct hn_softc *, 29315516c77SSepherosa Ziehau const void *, int); 294b3b75d9cSSepherosa Ziehau static void hn_rndis_init_fixat(struct hn_softc *, int); 29515516c77SSepherosa Ziehau 29615516c77SSepherosa Ziehau static void hn_nvs_handle_notify(struct hn_softc *, 29715516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 29815516c77SSepherosa Ziehau static void hn_nvs_handle_comp(struct hn_softc *, 29915516c77SSepherosa Ziehau struct vmbus_channel *, 30015516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 30115516c77SSepherosa Ziehau static void hn_nvs_handle_rxbuf(struct hn_rx_ring *, 30215516c77SSepherosa Ziehau struct vmbus_channel *, 30315516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 30415516c77SSepherosa Ziehau static void hn_nvs_ack_rxbuf(struct hn_rx_ring *, 30515516c77SSepherosa Ziehau struct vmbus_channel *, uint64_t); 30615516c77SSepherosa Ziehau 30715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 30815516c77SSepherosa Ziehau static int hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS); 30915516c77SSepherosa Ziehau static int hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS); 31015516c77SSepherosa Ziehau #endif 31115516c77SSepherosa Ziehau static int hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS); 31215516c77SSepherosa Ziehau static int hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS); 31315516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 31415516c77SSepherosa Ziehau static int hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS); 31515516c77SSepherosa Ziehau #else 31615516c77SSepherosa Ziehau static int hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS); 31715516c77SSepherosa Ziehau #endif 31815516c77SSepherosa Ziehau static int hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 31915516c77SSepherosa Ziehau static int hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 32015516c77SSepherosa Ziehau static int hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS); 32115516c77SSepherosa Ziehau static int hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS); 32215516c77SSepherosa Ziehau static int hn_caps_sysctl(SYSCTL_HANDLER_ARGS); 32315516c77SSepherosa Ziehau static int hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS); 32415516c77SSepherosa Ziehau static int hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS); 32534d68912SSepherosa Ziehau #ifndef RSS 32615516c77SSepherosa Ziehau static int hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS); 32715516c77SSepherosa Ziehau static int hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS); 32834d68912SSepherosa Ziehau #endif 32915516c77SSepherosa Ziehau static int hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS); 330dc13fee6SSepherosa Ziehau static int hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS); 331dc13fee6SSepherosa Ziehau static int hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS); 332dc13fee6SSepherosa Ziehau static int hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS); 333dc13fee6SSepherosa Ziehau static int hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS); 3346c1204dfSSepherosa Ziehau static int hn_polling_sysctl(SYSCTL_HANDLER_ARGS); 33540d60d6eSDexuan Cui static int hn_vf_sysctl(SYSCTL_HANDLER_ARGS); 336499c3e17SSepherosa Ziehau static int hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS); 337499c3e17SSepherosa Ziehau static int hn_vflist_sysctl(SYSCTL_HANDLER_ARGS); 338499c3e17SSepherosa Ziehau static int hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS); 3399c6cae24SSepherosa Ziehau static int hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS); 3409c6cae24SSepherosa Ziehau static int hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS); 34115516c77SSepherosa Ziehau 3425bdfd3fdSDexuan Cui static void hn_stop(struct hn_softc *, bool); 34315516c77SSepherosa Ziehau static void hn_init_locked(struct hn_softc *); 34415516c77SSepherosa Ziehau static int hn_chan_attach(struct hn_softc *, 34515516c77SSepherosa Ziehau struct vmbus_channel *); 34615516c77SSepherosa Ziehau static void hn_chan_detach(struct hn_softc *, 34715516c77SSepherosa Ziehau struct vmbus_channel *); 34815516c77SSepherosa Ziehau static int hn_attach_subchans(struct hn_softc *); 34915516c77SSepherosa Ziehau static void hn_detach_allchans(struct hn_softc *); 35015516c77SSepherosa Ziehau static void hn_chan_rollup(struct hn_rx_ring *, 35115516c77SSepherosa Ziehau struct hn_tx_ring *); 35215516c77SSepherosa Ziehau static void hn_set_ring_inuse(struct hn_softc *, int); 35315516c77SSepherosa Ziehau static int hn_synth_attach(struct hn_softc *, int); 35415516c77SSepherosa Ziehau static void hn_synth_detach(struct hn_softc *); 35515516c77SSepherosa Ziehau static int hn_synth_alloc_subchans(struct hn_softc *, 35615516c77SSepherosa Ziehau int *); 3572494d735SSepherosa Ziehau static bool hn_synth_attachable(const struct hn_softc *); 35815516c77SSepherosa Ziehau static void hn_suspend(struct hn_softc *); 35915516c77SSepherosa Ziehau static void hn_suspend_data(struct hn_softc *); 36015516c77SSepherosa Ziehau static void hn_suspend_mgmt(struct hn_softc *); 36115516c77SSepherosa Ziehau static void hn_resume(struct hn_softc *); 36215516c77SSepherosa Ziehau static void hn_resume_data(struct hn_softc *); 36315516c77SSepherosa Ziehau static void hn_resume_mgmt(struct hn_softc *); 36415516c77SSepherosa Ziehau static void hn_suspend_mgmt_taskfunc(void *, int); 36525641fc7SSepherosa Ziehau static void hn_chan_drain(struct hn_softc *, 36625641fc7SSepherosa Ziehau struct vmbus_channel *); 367b3b75d9cSSepherosa Ziehau static void hn_disable_rx(struct hn_softc *); 368b3b75d9cSSepherosa Ziehau static void hn_drain_rxtx(struct hn_softc *, int); 3696c1204dfSSepherosa Ziehau static void hn_polling(struct hn_softc *, u_int); 3706c1204dfSSepherosa Ziehau static void hn_chan_polling(struct vmbus_channel *, u_int); 3719c6cae24SSepherosa Ziehau static void hn_mtu_change_fixup(struct hn_softc *); 37215516c77SSepherosa Ziehau 37315516c77SSepherosa Ziehau static void hn_update_link_status(struct hn_softc *); 37415516c77SSepherosa Ziehau static void hn_change_network(struct hn_softc *); 37515516c77SSepherosa Ziehau static void hn_link_taskfunc(void *, int); 37615516c77SSepherosa Ziehau static void hn_netchg_init_taskfunc(void *, int); 37715516c77SSepherosa Ziehau static void hn_netchg_status_taskfunc(void *, int); 37815516c77SSepherosa Ziehau static void hn_link_status(struct hn_softc *); 37915516c77SSepherosa Ziehau 38015516c77SSepherosa Ziehau static int hn_create_rx_data(struct hn_softc *, int); 38115516c77SSepherosa Ziehau static void hn_destroy_rx_data(struct hn_softc *); 38215516c77SSepherosa Ziehau static int hn_check_iplen(const struct mbuf *, int); 383f1b0a43fSSepherosa Ziehau static int hn_set_rxfilter(struct hn_softc *, uint32_t); 384c08f7b2cSSepherosa Ziehau static int hn_rxfilter_config(struct hn_softc *); 38534d68912SSepherosa Ziehau #ifndef RSS 38615516c77SSepherosa Ziehau static int hn_rss_reconfig(struct hn_softc *); 38734d68912SSepherosa Ziehau #endif 388afd4971bSSepherosa Ziehau static void hn_rss_ind_fixup(struct hn_softc *); 38915516c77SSepherosa Ziehau static int hn_rxpkt(struct hn_rx_ring *, const void *, 39015516c77SSepherosa Ziehau int, const struct hn_rxinfo *); 39115516c77SSepherosa Ziehau 39215516c77SSepherosa Ziehau static int hn_tx_ring_create(struct hn_softc *, int); 39315516c77SSepherosa Ziehau static void hn_tx_ring_destroy(struct hn_tx_ring *); 39415516c77SSepherosa Ziehau static int hn_create_tx_data(struct hn_softc *, int); 39515516c77SSepherosa Ziehau static void hn_fixup_tx_data(struct hn_softc *); 39615516c77SSepherosa Ziehau static void hn_destroy_tx_data(struct hn_softc *); 39715516c77SSepherosa Ziehau static void hn_txdesc_dmamap_destroy(struct hn_txdesc *); 39825641fc7SSepherosa Ziehau static void hn_txdesc_gc(struct hn_tx_ring *, 39925641fc7SSepherosa Ziehau struct hn_txdesc *); 400dc13fee6SSepherosa Ziehau static int hn_encap(struct ifnet *, struct hn_tx_ring *, 40115516c77SSepherosa Ziehau struct hn_txdesc *, struct mbuf **); 40215516c77SSepherosa Ziehau static int hn_txpkt(struct ifnet *, struct hn_tx_ring *, 40315516c77SSepherosa Ziehau struct hn_txdesc *); 40415516c77SSepherosa Ziehau static void hn_set_chim_size(struct hn_softc *, int); 40515516c77SSepherosa Ziehau static void hn_set_tso_maxsize(struct hn_softc *, int, int); 40615516c77SSepherosa Ziehau static bool hn_tx_ring_pending(struct hn_tx_ring *); 40715516c77SSepherosa Ziehau static void hn_tx_ring_qflush(struct hn_tx_ring *); 40815516c77SSepherosa Ziehau static void hn_resume_tx(struct hn_softc *, int); 409dc13fee6SSepherosa Ziehau static void hn_set_txagg(struct hn_softc *); 410dc13fee6SSepherosa Ziehau static void *hn_try_txagg(struct ifnet *, 411dc13fee6SSepherosa Ziehau struct hn_tx_ring *, struct hn_txdesc *, 412dc13fee6SSepherosa Ziehau int); 41315516c77SSepherosa Ziehau static int hn_get_txswq_depth(const struct hn_tx_ring *); 41415516c77SSepherosa Ziehau static void hn_txpkt_done(struct hn_nvs_sendctx *, 41515516c77SSepherosa Ziehau struct hn_softc *, struct vmbus_channel *, 41615516c77SSepherosa Ziehau const void *, int); 41715516c77SSepherosa Ziehau static int hn_txpkt_sglist(struct hn_tx_ring *, 41815516c77SSepherosa Ziehau struct hn_txdesc *); 41915516c77SSepherosa Ziehau static int hn_txpkt_chim(struct hn_tx_ring *, 42015516c77SSepherosa Ziehau struct hn_txdesc *); 42115516c77SSepherosa Ziehau static int hn_xmit(struct hn_tx_ring *, int); 42215516c77SSepherosa Ziehau static void hn_xmit_taskfunc(void *, int); 42315516c77SSepherosa Ziehau static void hn_xmit_txeof(struct hn_tx_ring *); 42415516c77SSepherosa Ziehau static void hn_xmit_txeof_taskfunc(void *, int); 42523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 42615516c77SSepherosa Ziehau static int hn_start_locked(struct hn_tx_ring *, int); 42715516c77SSepherosa Ziehau static void hn_start_taskfunc(void *, int); 42815516c77SSepherosa Ziehau static void hn_start_txeof(struct hn_tx_ring *); 42915516c77SSepherosa Ziehau static void hn_start_txeof_taskfunc(void *, int); 43023bf9e15SSepherosa Ziehau #endif 43115516c77SSepherosa Ziehau 43215516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 43315516c77SSepherosa Ziehau "Hyper-V network interface"); 43415516c77SSepherosa Ziehau 43515516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */ 43615516c77SSepherosa Ziehau static int hn_trust_hosttcp = 1; 43715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN, 43815516c77SSepherosa Ziehau &hn_trust_hosttcp, 0, 43915516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 44015516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 44115516c77SSepherosa Ziehau 44215516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */ 44315516c77SSepherosa Ziehau static int hn_trust_hostudp = 1; 44415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN, 44515516c77SSepherosa Ziehau &hn_trust_hostudp, 0, 44615516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 44715516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 44815516c77SSepherosa Ziehau 44915516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */ 45015516c77SSepherosa Ziehau static int hn_trust_hostip = 1; 45115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN, 45215516c77SSepherosa Ziehau &hn_trust_hostip, 0, 45315516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 45415516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 45515516c77SSepherosa Ziehau 45615516c77SSepherosa Ziehau /* Limit TSO burst size */ 45715516c77SSepherosa Ziehau static int hn_tso_maxlen = IP_MAXPACKET; 45815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN, 45915516c77SSepherosa Ziehau &hn_tso_maxlen, 0, "TSO burst limit"); 46015516c77SSepherosa Ziehau 46115516c77SSepherosa Ziehau /* Limit chimney send size */ 46215516c77SSepherosa Ziehau static int hn_tx_chimney_size = 0; 46315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN, 46415516c77SSepherosa Ziehau &hn_tx_chimney_size, 0, "Chimney send packet size limit"); 46515516c77SSepherosa Ziehau 46615516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */ 46715516c77SSepherosa Ziehau static int hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF; 46815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN, 46915516c77SSepherosa Ziehau &hn_direct_tx_size, 0, "Size of the packet for direct transmission"); 47015516c77SSepherosa Ziehau 47115516c77SSepherosa Ziehau /* # of LRO entries per RX ring */ 47215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 47315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 47415516c77SSepherosa Ziehau static int hn_lro_entry_count = HN_LROENT_CNT_DEF; 47515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN, 47615516c77SSepherosa Ziehau &hn_lro_entry_count, 0, "LRO entry count"); 47715516c77SSepherosa Ziehau #endif 47815516c77SSepherosa Ziehau #endif 47915516c77SSepherosa Ziehau 480fdd0222aSSepherosa Ziehau static int hn_tx_taskq_cnt = 1; 481fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN, 482fdd0222aSSepherosa Ziehau &hn_tx_taskq_cnt, 0, "# of TX taskqueues"); 483fdd0222aSSepherosa Ziehau 4840e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP 0 4850e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL 1 4860e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ 2 4870e11868dSSepherosa Ziehau 4880e11868dSSepherosa Ziehau static int hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP; 4890e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN, 4900e11868dSSepherosa Ziehau &hn_tx_taskq_mode, 0, "TX taskqueue modes: " 4910e11868dSSepherosa Ziehau "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs"); 4920e11868dSSepherosa Ziehau 49315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 49415516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 0; 49515516c77SSepherosa Ziehau #else 49615516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 1; 49715516c77SSepherosa Ziehau #endif 49815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD, 49915516c77SSepherosa Ziehau &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors"); 50015516c77SSepherosa Ziehau 50123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 50215516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */ 50315516c77SSepherosa Ziehau static int hn_use_if_start = 0; 50415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN, 50515516c77SSepherosa Ziehau &hn_use_if_start, 0, "Use if_start TX method"); 50623bf9e15SSepherosa Ziehau #endif 50715516c77SSepherosa Ziehau 50815516c77SSepherosa Ziehau /* # of channels to use */ 50915516c77SSepherosa Ziehau static int hn_chan_cnt = 0; 51015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN, 51115516c77SSepherosa Ziehau &hn_chan_cnt, 0, 51215516c77SSepherosa Ziehau "# of channels to use; each channel has one RX ring and one TX ring"); 51315516c77SSepherosa Ziehau 51415516c77SSepherosa Ziehau /* # of transmit rings to use */ 51515516c77SSepherosa Ziehau static int hn_tx_ring_cnt = 0; 51615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN, 51715516c77SSepherosa Ziehau &hn_tx_ring_cnt, 0, "# of TX rings to use"); 51815516c77SSepherosa Ziehau 51915516c77SSepherosa Ziehau /* Software TX ring deptch */ 52015516c77SSepherosa Ziehau static int hn_tx_swq_depth = 0; 52115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN, 52215516c77SSepherosa Ziehau &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING"); 52315516c77SSepherosa Ziehau 52415516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */ 52515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 52615516c77SSepherosa Ziehau static u_int hn_lro_mbufq_depth = 0; 52715516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN, 52815516c77SSepherosa Ziehau &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue"); 52915516c77SSepherosa Ziehau #endif 53015516c77SSepherosa Ziehau 531dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */ 532dc13fee6SSepherosa Ziehau static int hn_tx_agg_size = -1; 533dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN, 534dc13fee6SSepherosa Ziehau &hn_tx_agg_size, 0, "Packet transmission aggregation size limit"); 535dc13fee6SSepherosa Ziehau 536dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */ 537fa915c4dSSepherosa Ziehau static int hn_tx_agg_pkts = -1; 538dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN, 539dc13fee6SSepherosa Ziehau &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit"); 540dc13fee6SSepherosa Ziehau 541499c3e17SSepherosa Ziehau /* VF list */ 542499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vflist, CTLFLAG_RD | CTLTYPE_STRING, 543499c3e17SSepherosa Ziehau 0, 0, hn_vflist_sysctl, "A", "VF list"); 544499c3e17SSepherosa Ziehau 545499c3e17SSepherosa Ziehau /* VF mapping */ 546499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap, CTLFLAG_RD | CTLTYPE_STRING, 547499c3e17SSepherosa Ziehau 0, 0, hn_vfmap_sysctl, "A", "VF mapping"); 548499c3e17SSepherosa Ziehau 5499c6cae24SSepherosa Ziehau /* Transparent VF */ 5509c6cae24SSepherosa Ziehau static int hn_xpnt_vf = 0; 5519c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_transparent, CTLFLAG_RDTUN, 5529c6cae24SSepherosa Ziehau &hn_xpnt_vf, 0, "Transparent VF mod"); 5539c6cae24SSepherosa Ziehau 5549c6cae24SSepherosa Ziehau /* Accurate BPF support for Transparent VF */ 5559c6cae24SSepherosa Ziehau static int hn_xpnt_vf_accbpf = 0; 5569c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_accbpf, CTLFLAG_RDTUN, 5579c6cae24SSepherosa Ziehau &hn_xpnt_vf_accbpf, 0, "Accurate BPF for transparent VF"); 5589c6cae24SSepherosa Ziehau 5599c6cae24SSepherosa Ziehau /* Extra wait for transparent VF attach routing; unit seconds. */ 5609c6cae24SSepherosa Ziehau static int hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN; 5619c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_attwait, CTLFLAG_RWTUN, 5629c6cae24SSepherosa Ziehau &hn_xpnt_vf_attwait, 0, 5639c6cae24SSepherosa Ziehau "Extra wait for transparent VF attach routing; unit: seconds"); 5649c6cae24SSepherosa Ziehau 56515516c77SSepherosa Ziehau static u_int hn_cpu_index; /* next CPU for channel */ 566fdd0222aSSepherosa Ziehau static struct taskqueue **hn_tx_taskque;/* shared TX taskqueues */ 56715516c77SSepherosa Ziehau 568499c3e17SSepherosa Ziehau static struct rmlock hn_vfmap_lock; 569499c3e17SSepherosa Ziehau static int hn_vfmap_size; 570499c3e17SSepherosa Ziehau static struct ifnet **hn_vfmap; 571499c3e17SSepherosa Ziehau 57234d68912SSepherosa Ziehau #ifndef RSS 57315516c77SSepherosa Ziehau static const uint8_t 57415516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = { 57515516c77SSepherosa Ziehau 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 57615516c77SSepherosa Ziehau 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 57715516c77SSepherosa Ziehau 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 57815516c77SSepherosa Ziehau 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 57915516c77SSepherosa Ziehau 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa 58015516c77SSepherosa Ziehau }; 58134d68912SSepherosa Ziehau #endif /* !RSS */ 58215516c77SSepherosa Ziehau 583c2d50b26SSepherosa Ziehau static const struct hyperv_guid hn_guid = { 584c2d50b26SSepherosa Ziehau .hv_guid = { 585c2d50b26SSepherosa Ziehau 0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46, 586c2d50b26SSepherosa Ziehau 0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e } 587c2d50b26SSepherosa Ziehau }; 588c2d50b26SSepherosa Ziehau 58915516c77SSepherosa Ziehau static device_method_t hn_methods[] = { 59015516c77SSepherosa Ziehau /* Device interface */ 59115516c77SSepherosa Ziehau DEVMETHOD(device_probe, hn_probe), 59215516c77SSepherosa Ziehau DEVMETHOD(device_attach, hn_attach), 59315516c77SSepherosa Ziehau DEVMETHOD(device_detach, hn_detach), 59415516c77SSepherosa Ziehau DEVMETHOD(device_shutdown, hn_shutdown), 59515516c77SSepherosa Ziehau DEVMETHOD_END 59615516c77SSepherosa Ziehau }; 59715516c77SSepherosa Ziehau 59815516c77SSepherosa Ziehau static driver_t hn_driver = { 59915516c77SSepherosa Ziehau "hn", 60015516c77SSepherosa Ziehau hn_methods, 60115516c77SSepherosa Ziehau sizeof(struct hn_softc) 60215516c77SSepherosa Ziehau }; 60315516c77SSepherosa Ziehau 60415516c77SSepherosa Ziehau static devclass_t hn_devclass; 60515516c77SSepherosa Ziehau 60615516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0); 60715516c77SSepherosa Ziehau MODULE_VERSION(hn, 1); 60815516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1); 60915516c77SSepherosa Ziehau 61015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 61115516c77SSepherosa Ziehau static void 61215516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim) 61315516c77SSepherosa Ziehau { 61415516c77SSepherosa Ziehau int i; 61515516c77SSepherosa Ziehau 616a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 61715516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim; 61815516c77SSepherosa Ziehau } 61915516c77SSepherosa Ziehau #endif 62015516c77SSepherosa Ziehau 62115516c77SSepherosa Ziehau static int 62215516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd) 62315516c77SSepherosa Ziehau { 62415516c77SSepherosa Ziehau 62515516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 62615516c77SSepherosa Ziehau txd->chim_size == 0, ("invalid rndis sglist txd")); 62715516c77SSepherosa Ziehau return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA, 62815516c77SSepherosa Ziehau &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt)); 62915516c77SSepherosa Ziehau } 63015516c77SSepherosa Ziehau 63115516c77SSepherosa Ziehau static int 63215516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd) 63315516c77SSepherosa Ziehau { 63415516c77SSepherosa Ziehau struct hn_nvs_rndis rndis; 63515516c77SSepherosa Ziehau 63615516c77SSepherosa Ziehau KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID && 63715516c77SSepherosa Ziehau txd->chim_size > 0, ("invalid rndis chim txd")); 63815516c77SSepherosa Ziehau 63915516c77SSepherosa Ziehau rndis.nvs_type = HN_NVS_TYPE_RNDIS; 64015516c77SSepherosa Ziehau rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA; 64115516c77SSepherosa Ziehau rndis.nvs_chim_idx = txd->chim_index; 64215516c77SSepherosa Ziehau rndis.nvs_chim_sz = txd->chim_size; 64315516c77SSepherosa Ziehau 64415516c77SSepherosa Ziehau return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC, 64515516c77SSepherosa Ziehau &rndis, sizeof(rndis), &txd->send_ctx)); 64615516c77SSepherosa Ziehau } 64715516c77SSepherosa Ziehau 64815516c77SSepherosa Ziehau static __inline uint32_t 64915516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc) 65015516c77SSepherosa Ziehau { 65115516c77SSepherosa Ziehau int i, bmap_cnt = sc->hn_chim_bmap_cnt; 65215516c77SSepherosa Ziehau u_long *bmap = sc->hn_chim_bmap; 65315516c77SSepherosa Ziehau uint32_t ret = HN_NVS_CHIM_IDX_INVALID; 65415516c77SSepherosa Ziehau 65515516c77SSepherosa Ziehau for (i = 0; i < bmap_cnt; ++i) { 65615516c77SSepherosa Ziehau int idx; 65715516c77SSepherosa Ziehau 65815516c77SSepherosa Ziehau idx = ffsl(~bmap[i]); 65915516c77SSepherosa Ziehau if (idx == 0) 66015516c77SSepherosa Ziehau continue; 66115516c77SSepherosa Ziehau 66215516c77SSepherosa Ziehau --idx; /* ffsl is 1-based */ 66315516c77SSepherosa Ziehau KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt, 66415516c77SSepherosa Ziehau ("invalid i %d and idx %d", i, idx)); 66515516c77SSepherosa Ziehau 66615516c77SSepherosa Ziehau if (atomic_testandset_long(&bmap[i], idx)) 66715516c77SSepherosa Ziehau continue; 66815516c77SSepherosa Ziehau 66915516c77SSepherosa Ziehau ret = i * LONG_BIT + idx; 67015516c77SSepherosa Ziehau break; 67115516c77SSepherosa Ziehau } 67215516c77SSepherosa Ziehau return (ret); 67315516c77SSepherosa Ziehau } 67415516c77SSepherosa Ziehau 67515516c77SSepherosa Ziehau static __inline void 67615516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx) 67715516c77SSepherosa Ziehau { 67815516c77SSepherosa Ziehau u_long mask; 67915516c77SSepherosa Ziehau uint32_t idx; 68015516c77SSepherosa Ziehau 68115516c77SSepherosa Ziehau idx = chim_idx / LONG_BIT; 68215516c77SSepherosa Ziehau KASSERT(idx < sc->hn_chim_bmap_cnt, 68315516c77SSepherosa Ziehau ("invalid chimney index 0x%x", chim_idx)); 68415516c77SSepherosa Ziehau 68515516c77SSepherosa Ziehau mask = 1UL << (chim_idx % LONG_BIT); 68615516c77SSepherosa Ziehau KASSERT(sc->hn_chim_bmap[idx] & mask, 68715516c77SSepherosa Ziehau ("index bitmap 0x%lx, chimney index %u, " 68815516c77SSepherosa Ziehau "bitmap idx %d, bitmask 0x%lx", 68915516c77SSepherosa Ziehau sc->hn_chim_bmap[idx], chim_idx, idx, mask)); 69015516c77SSepherosa Ziehau 69115516c77SSepherosa Ziehau atomic_clear_long(&sc->hn_chim_bmap[idx], mask); 69215516c77SSepherosa Ziehau } 69315516c77SSepherosa Ziehau 694edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 695cc0c6ebcSSepherosa Ziehau 696cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len) \ 697cc0c6ebcSSepherosa Ziehau do { \ 698cc0c6ebcSSepherosa Ziehau if (__predict_false((m)->m_len < (len))) { \ 699cc0c6ebcSSepherosa Ziehau (m) = m_pullup((m), (len)); \ 700cc0c6ebcSSepherosa Ziehau if ((m) == NULL) \ 701cc0c6ebcSSepherosa Ziehau return (NULL); \ 702cc0c6ebcSSepherosa Ziehau } \ 703cc0c6ebcSSepherosa Ziehau } while (0) 704cc0c6ebcSSepherosa Ziehau 705edd3f315SSepherosa Ziehau /* 706edd3f315SSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 707edd3f315SSepherosa Ziehau */ 708edd3f315SSepherosa Ziehau static __inline struct mbuf * 709edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head) 710edd3f315SSepherosa Ziehau { 711edd3f315SSepherosa Ziehau struct ether_vlan_header *evl; 712edd3f315SSepherosa Ziehau struct tcphdr *th; 713edd3f315SSepherosa Ziehau int ehlen; 714edd3f315SSepherosa Ziehau 715edd3f315SSepherosa Ziehau KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable")); 716edd3f315SSepherosa Ziehau 717edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, sizeof(*evl)); 718edd3f315SSepherosa Ziehau evl = mtod(m_head, struct ether_vlan_header *); 719edd3f315SSepherosa Ziehau if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) 720edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 721edd3f315SSepherosa Ziehau else 722edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN; 723edd3f315SSepherosa Ziehau 724edd3f315SSepherosa Ziehau #ifdef INET 725edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 726edd3f315SSepherosa Ziehau struct ip *ip; 727edd3f315SSepherosa Ziehau int iphlen; 728edd3f315SSepherosa Ziehau 729edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip)); 730edd3f315SSepherosa Ziehau ip = mtodo(m_head, ehlen); 731edd3f315SSepherosa Ziehau iphlen = ip->ip_hl << 2; 732edd3f315SSepherosa Ziehau 733edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 734edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 735edd3f315SSepherosa Ziehau 736edd3f315SSepherosa Ziehau ip->ip_len = 0; 737edd3f315SSepherosa Ziehau ip->ip_sum = 0; 738edd3f315SSepherosa Ziehau th->th_sum = in_pseudo(ip->ip_src.s_addr, 739edd3f315SSepherosa Ziehau ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 740edd3f315SSepherosa Ziehau } 741edd3f315SSepherosa Ziehau #endif 742edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET) 743edd3f315SSepherosa Ziehau else 744edd3f315SSepherosa Ziehau #endif 745edd3f315SSepherosa Ziehau #ifdef INET6 746edd3f315SSepherosa Ziehau { 747edd3f315SSepherosa Ziehau struct ip6_hdr *ip6; 748edd3f315SSepherosa Ziehau 749edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); 750edd3f315SSepherosa Ziehau ip6 = mtodo(m_head, ehlen); 751edd3f315SSepherosa Ziehau if (ip6->ip6_nxt != IPPROTO_TCP) { 752edd3f315SSepherosa Ziehau m_freem(m_head); 753edd3f315SSepherosa Ziehau return (NULL); 754edd3f315SSepherosa Ziehau } 755edd3f315SSepherosa Ziehau 756edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); 757edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + sizeof(*ip6)); 758edd3f315SSepherosa Ziehau 759edd3f315SSepherosa Ziehau ip6->ip6_plen = 0; 760edd3f315SSepherosa Ziehau th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 761edd3f315SSepherosa Ziehau } 762edd3f315SSepherosa Ziehau #endif 763edd3f315SSepherosa Ziehau return (m_head); 764edd3f315SSepherosa Ziehau 765edd3f315SSepherosa Ziehau } 766cc0c6ebcSSepherosa Ziehau 767cc0c6ebcSSepherosa Ziehau /* 768cc0c6ebcSSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 769cc0c6ebcSSepherosa Ziehau */ 770cc0c6ebcSSepherosa Ziehau static __inline struct mbuf * 771cc0c6ebcSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn) 772cc0c6ebcSSepherosa Ziehau { 773cc0c6ebcSSepherosa Ziehau const struct ether_vlan_header *evl; 774cc0c6ebcSSepherosa Ziehau const struct tcphdr *th; 775cc0c6ebcSSepherosa Ziehau int ehlen; 776cc0c6ebcSSepherosa Ziehau 777cc0c6ebcSSepherosa Ziehau *tcpsyn = 0; 778cc0c6ebcSSepherosa Ziehau 779cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, sizeof(*evl)); 780cc0c6ebcSSepherosa Ziehau evl = mtod(m_head, const struct ether_vlan_header *); 781cc0c6ebcSSepherosa Ziehau if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) 782cc0c6ebcSSepherosa Ziehau ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 783cc0c6ebcSSepherosa Ziehau else 784cc0c6ebcSSepherosa Ziehau ehlen = ETHER_HDR_LEN; 785cc0c6ebcSSepherosa Ziehau 786cc0c6ebcSSepherosa Ziehau #ifdef INET 787cc0c6ebcSSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TCP) { 788cc0c6ebcSSepherosa Ziehau const struct ip *ip; 789cc0c6ebcSSepherosa Ziehau int iphlen; 790cc0c6ebcSSepherosa Ziehau 791cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip)); 792cc0c6ebcSSepherosa Ziehau ip = mtodo(m_head, ehlen); 793cc0c6ebcSSepherosa Ziehau iphlen = ip->ip_hl << 2; 794cc0c6ebcSSepherosa Ziehau 795cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 796cc0c6ebcSSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 797cc0c6ebcSSepherosa Ziehau if (th->th_flags & TH_SYN) 798cc0c6ebcSSepherosa Ziehau *tcpsyn = 1; 799cc0c6ebcSSepherosa Ziehau } 800cc0c6ebcSSepherosa Ziehau #endif 801cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET) 802cc0c6ebcSSepherosa Ziehau else 803cc0c6ebcSSepherosa Ziehau #endif 804cc0c6ebcSSepherosa Ziehau #ifdef INET6 805cc0c6ebcSSepherosa Ziehau { 806cc0c6ebcSSepherosa Ziehau const struct ip6_hdr *ip6; 807cc0c6ebcSSepherosa Ziehau 808cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); 809cc0c6ebcSSepherosa Ziehau ip6 = mtodo(m_head, ehlen); 810cc0c6ebcSSepherosa Ziehau if (ip6->ip6_nxt != IPPROTO_TCP) 811cc0c6ebcSSepherosa Ziehau return (m_head); 812cc0c6ebcSSepherosa Ziehau 813cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); 814cc0c6ebcSSepherosa Ziehau th = mtodo(m_head, ehlen + sizeof(*ip6)); 815cc0c6ebcSSepherosa Ziehau if (th->th_flags & TH_SYN) 816cc0c6ebcSSepherosa Ziehau *tcpsyn = 1; 817cc0c6ebcSSepherosa Ziehau } 818cc0c6ebcSSepherosa Ziehau #endif 819cc0c6ebcSSepherosa Ziehau return (m_head); 820cc0c6ebcSSepherosa Ziehau } 821cc0c6ebcSSepherosa Ziehau 822cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR 823cc0c6ebcSSepherosa Ziehau 824edd3f315SSepherosa Ziehau #endif /* INET6 || INET */ 825edd3f315SSepherosa Ziehau 82615516c77SSepherosa Ziehau static int 827f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter) 828f1b0a43fSSepherosa Ziehau { 829f1b0a43fSSepherosa Ziehau int error = 0; 830f1b0a43fSSepherosa Ziehau 831f1b0a43fSSepherosa Ziehau HN_LOCK_ASSERT(sc); 832f1b0a43fSSepherosa Ziehau 833f1b0a43fSSepherosa Ziehau if (sc->hn_rx_filter != filter) { 834f1b0a43fSSepherosa Ziehau error = hn_rndis_set_rxfilter(sc, filter); 835f1b0a43fSSepherosa Ziehau if (!error) 836f1b0a43fSSepherosa Ziehau sc->hn_rx_filter = filter; 837f1b0a43fSSepherosa Ziehau } 838f1b0a43fSSepherosa Ziehau return (error); 839f1b0a43fSSepherosa Ziehau } 840f1b0a43fSSepherosa Ziehau 841f1b0a43fSSepherosa Ziehau static int 842c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc) 84315516c77SSepherosa Ziehau { 84415516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 84515516c77SSepherosa Ziehau uint32_t filter; 84615516c77SSepherosa Ziehau 84715516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 84815516c77SSepherosa Ziehau 8499c6cae24SSepherosa Ziehau /* 8509c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, we don't know how 8519c6cae24SSepherosa Ziehau * its RX filter is configured, so stick the synthetic device in 8529c6cae24SSepherosa Ziehau * the promiscous mode. 8539c6cae24SSepherosa Ziehau */ 8549c6cae24SSepherosa Ziehau if ((ifp->if_flags & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) { 85515516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_PROMISCUOUS; 85615516c77SSepherosa Ziehau } else { 85715516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_DIRECTED; 85815516c77SSepherosa Ziehau if (ifp->if_flags & IFF_BROADCAST) 85915516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_BROADCAST; 86015516c77SSepherosa Ziehau /* TODO: support multicast list */ 86115516c77SSepherosa Ziehau if ((ifp->if_flags & IFF_ALLMULTI) || 86215516c77SSepherosa Ziehau !TAILQ_EMPTY(&ifp->if_multiaddrs)) 86315516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 86415516c77SSepherosa Ziehau } 865f1b0a43fSSepherosa Ziehau return (hn_set_rxfilter(sc, filter)); 86615516c77SSepherosa Ziehau } 86715516c77SSepherosa Ziehau 868dc13fee6SSepherosa Ziehau static void 869dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc) 870dc13fee6SSepherosa Ziehau { 871dc13fee6SSepherosa Ziehau uint32_t size, pkts; 872dc13fee6SSepherosa Ziehau int i; 873dc13fee6SSepherosa Ziehau 874dc13fee6SSepherosa Ziehau /* 875dc13fee6SSepherosa Ziehau * Setup aggregation size. 876dc13fee6SSepherosa Ziehau */ 877dc13fee6SSepherosa Ziehau if (sc->hn_agg_size < 0) 878dc13fee6SSepherosa Ziehau size = UINT32_MAX; 879dc13fee6SSepherosa Ziehau else 880dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 881dc13fee6SSepherosa Ziehau 882dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_size < size) 883dc13fee6SSepherosa Ziehau size = sc->hn_rndis_agg_size; 884dc13fee6SSepherosa Ziehau 885a4364cfeSSepherosa Ziehau /* NOTE: We only aggregate packets using chimney sending buffers. */ 886a4364cfeSSepherosa Ziehau if (size > (uint32_t)sc->hn_chim_szmax) 887a4364cfeSSepherosa Ziehau size = sc->hn_chim_szmax; 888a4364cfeSSepherosa Ziehau 889dc13fee6SSepherosa Ziehau if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) { 890dc13fee6SSepherosa Ziehau /* Disable */ 891dc13fee6SSepherosa Ziehau size = 0; 892dc13fee6SSepherosa Ziehau pkts = 0; 893dc13fee6SSepherosa Ziehau goto done; 894dc13fee6SSepherosa Ziehau } 895dc13fee6SSepherosa Ziehau 896dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'int'. */ 897dc13fee6SSepherosa Ziehau if (size > INT_MAX) 898dc13fee6SSepherosa Ziehau size = INT_MAX; 899dc13fee6SSepherosa Ziehau 900dc13fee6SSepherosa Ziehau /* 901dc13fee6SSepherosa Ziehau * Setup aggregation packet count. 902dc13fee6SSepherosa Ziehau */ 903dc13fee6SSepherosa Ziehau if (sc->hn_agg_pkts < 0) 904dc13fee6SSepherosa Ziehau pkts = UINT32_MAX; 905dc13fee6SSepherosa Ziehau else 906dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 907dc13fee6SSepherosa Ziehau 908dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_pkts < pkts) 909dc13fee6SSepherosa Ziehau pkts = sc->hn_rndis_agg_pkts; 910dc13fee6SSepherosa Ziehau 911dc13fee6SSepherosa Ziehau if (pkts <= 1) { 912dc13fee6SSepherosa Ziehau /* Disable */ 913dc13fee6SSepherosa Ziehau size = 0; 914dc13fee6SSepherosa Ziehau pkts = 0; 915dc13fee6SSepherosa Ziehau goto done; 916dc13fee6SSepherosa Ziehau } 917dc13fee6SSepherosa Ziehau 918dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 919dc13fee6SSepherosa Ziehau if (pkts > SHRT_MAX) 920dc13fee6SSepherosa Ziehau pkts = SHRT_MAX; 921dc13fee6SSepherosa Ziehau 922dc13fee6SSepherosa Ziehau done: 923dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 924dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_align > SHRT_MAX) { 925dc13fee6SSepherosa Ziehau /* Disable */ 926dc13fee6SSepherosa Ziehau size = 0; 927dc13fee6SSepherosa Ziehau pkts = 0; 928dc13fee6SSepherosa Ziehau } 929dc13fee6SSepherosa Ziehau 930dc13fee6SSepherosa Ziehau if (bootverbose) { 931dc13fee6SSepherosa Ziehau if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n", 932dc13fee6SSepherosa Ziehau size, pkts, sc->hn_rndis_agg_align); 933dc13fee6SSepherosa Ziehau } 934dc13fee6SSepherosa Ziehau 935dc13fee6SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 936dc13fee6SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 937dc13fee6SSepherosa Ziehau 938dc13fee6SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 939dc13fee6SSepherosa Ziehau txr->hn_agg_szmax = size; 940dc13fee6SSepherosa Ziehau txr->hn_agg_pktmax = pkts; 941dc13fee6SSepherosa Ziehau txr->hn_agg_align = sc->hn_rndis_agg_align; 942dc13fee6SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 943dc13fee6SSepherosa Ziehau } 944dc13fee6SSepherosa Ziehau } 945dc13fee6SSepherosa Ziehau 94615516c77SSepherosa Ziehau static int 94715516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr) 94815516c77SSepherosa Ziehau { 94915516c77SSepherosa Ziehau 95015516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet")); 95115516c77SSepherosa Ziehau if (hn_tx_swq_depth < txr->hn_txdesc_cnt) 95215516c77SSepherosa Ziehau return txr->hn_txdesc_cnt; 95315516c77SSepherosa Ziehau return hn_tx_swq_depth; 95415516c77SSepherosa Ziehau } 95515516c77SSepherosa Ziehau 95634d68912SSepherosa Ziehau #ifndef RSS 95715516c77SSepherosa Ziehau static int 95815516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc) 95915516c77SSepherosa Ziehau { 96015516c77SSepherosa Ziehau int error; 96115516c77SSepherosa Ziehau 96215516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 96315516c77SSepherosa Ziehau 96415516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 96515516c77SSepherosa Ziehau return (ENXIO); 96615516c77SSepherosa Ziehau 96715516c77SSepherosa Ziehau /* 96815516c77SSepherosa Ziehau * Disable RSS first. 96915516c77SSepherosa Ziehau * 97015516c77SSepherosa Ziehau * NOTE: 97115516c77SSepherosa Ziehau * Direct reconfiguration by setting the UNCHG flags does 97215516c77SSepherosa Ziehau * _not_ work properly. 97315516c77SSepherosa Ziehau */ 97415516c77SSepherosa Ziehau if (bootverbose) 97515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "disable RSS\n"); 97615516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE); 97715516c77SSepherosa Ziehau if (error) { 97815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS disable failed\n"); 97915516c77SSepherosa Ziehau return (error); 98015516c77SSepherosa Ziehau } 98115516c77SSepherosa Ziehau 98215516c77SSepherosa Ziehau /* 98315516c77SSepherosa Ziehau * Reenable the RSS w/ the updated RSS key or indirect 98415516c77SSepherosa Ziehau * table. 98515516c77SSepherosa Ziehau */ 98615516c77SSepherosa Ziehau if (bootverbose) 98715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "reconfig RSS\n"); 98815516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 98915516c77SSepherosa Ziehau if (error) { 99015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS reconfig failed\n"); 99115516c77SSepherosa Ziehau return (error); 99215516c77SSepherosa Ziehau } 99315516c77SSepherosa Ziehau return (0); 99415516c77SSepherosa Ziehau } 99534d68912SSepherosa Ziehau #endif /* !RSS */ 99615516c77SSepherosa Ziehau 99715516c77SSepherosa Ziehau static void 998afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc) 99915516c77SSepherosa Ziehau { 100015516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 1001afd4971bSSepherosa Ziehau int i, nchan; 100215516c77SSepherosa Ziehau 1003afd4971bSSepherosa Ziehau nchan = sc->hn_rx_ring_inuse; 100415516c77SSepherosa Ziehau KASSERT(nchan > 1, ("invalid # of channels %d", nchan)); 100515516c77SSepherosa Ziehau 100615516c77SSepherosa Ziehau /* 100715516c77SSepherosa Ziehau * Check indirect table to make sure that all channels in it 100815516c77SSepherosa Ziehau * can be used. 100915516c77SSepherosa Ziehau */ 101015516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 101115516c77SSepherosa Ziehau if (rss->rss_ind[i] >= nchan) { 101215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, 101315516c77SSepherosa Ziehau "RSS indirect table %d fixup: %u -> %d\n", 101415516c77SSepherosa Ziehau i, rss->rss_ind[i], nchan - 1); 101515516c77SSepherosa Ziehau rss->rss_ind[i] = nchan - 1; 101615516c77SSepherosa Ziehau } 101715516c77SSepherosa Ziehau } 101815516c77SSepherosa Ziehau } 101915516c77SSepherosa Ziehau 102015516c77SSepherosa Ziehau static int 102115516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused) 102215516c77SSepherosa Ziehau { 102315516c77SSepherosa Ziehau 102415516c77SSepherosa Ziehau return EOPNOTSUPP; 102515516c77SSepherosa Ziehau } 102615516c77SSepherosa Ziehau 102715516c77SSepherosa Ziehau static void 102815516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 102915516c77SSepherosa Ziehau { 103015516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 103115516c77SSepherosa Ziehau 103215516c77SSepherosa Ziehau ifmr->ifm_status = IFM_AVALID; 103315516c77SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 103415516c77SSepherosa Ziehau 103515516c77SSepherosa Ziehau if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) { 103615516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_NONE; 103715516c77SSepherosa Ziehau return; 103815516c77SSepherosa Ziehau } 103915516c77SSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 104015516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 104115516c77SSepherosa Ziehau } 104215516c77SSepherosa Ziehau 10435bdfd3fdSDexuan Cui static void 1044962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused) 10455bdfd3fdSDexuan Cui { 1046962f0357SSepherosa Ziehau struct hn_rxvf_setarg *arg = xarg; 10475bdfd3fdSDexuan Cui 1048962f0357SSepherosa Ziehau arg->rxr->hn_rxvf_ifp = arg->vf_ifp; 10495bdfd3fdSDexuan Cui } 10505bdfd3fdSDexuan Cui 10515bdfd3fdSDexuan Cui static void 1052962f0357SSepherosa Ziehau hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp) 10535bdfd3fdSDexuan Cui { 10545bdfd3fdSDexuan Cui struct hn_rx_ring *rxr; 1055962f0357SSepherosa Ziehau struct hn_rxvf_setarg arg; 10565bdfd3fdSDexuan Cui struct task task; 10575bdfd3fdSDexuan Cui int i; 10585bdfd3fdSDexuan Cui 10595bdfd3fdSDexuan Cui HN_LOCK_ASSERT(sc); 10605bdfd3fdSDexuan Cui 1061962f0357SSepherosa Ziehau TASK_INIT(&task, 0, hn_rxvf_set_task, &arg); 10625bdfd3fdSDexuan Cui 10635bdfd3fdSDexuan Cui for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 10645bdfd3fdSDexuan Cui rxr = &sc->hn_rx_ring[i]; 10655bdfd3fdSDexuan Cui 10665bdfd3fdSDexuan Cui if (i < sc->hn_rx_ring_inuse) { 1067962f0357SSepherosa Ziehau arg.rxr = rxr; 1068962f0357SSepherosa Ziehau arg.vf_ifp = vf_ifp; 10695bdfd3fdSDexuan Cui vmbus_chan_run_task(rxr->hn_chan, &task); 10705bdfd3fdSDexuan Cui } else { 1071962f0357SSepherosa Ziehau rxr->hn_rxvf_ifp = vf_ifp; 10725bdfd3fdSDexuan Cui } 10735bdfd3fdSDexuan Cui } 10745bdfd3fdSDexuan Cui } 10755bdfd3fdSDexuan Cui 1076962f0357SSepherosa Ziehau static bool 1077499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp) 1078499c3e17SSepherosa Ziehau { 1079499c3e17SSepherosa Ziehau const struct ifnet *hn_ifp; 1080499c3e17SSepherosa Ziehau 1081499c3e17SSepherosa Ziehau hn_ifp = sc->hn_ifp; 1082499c3e17SSepherosa Ziehau 1083499c3e17SSepherosa Ziehau if (ifp == hn_ifp) 1084499c3e17SSepherosa Ziehau return (false); 1085499c3e17SSepherosa Ziehau 1086499c3e17SSepherosa Ziehau if (ifp->if_alloctype != IFT_ETHER) 1087499c3e17SSepherosa Ziehau return (false); 1088499c3e17SSepherosa Ziehau 1089499c3e17SSepherosa Ziehau /* Ignore lagg/vlan interfaces */ 1090499c3e17SSepherosa Ziehau if (strcmp(ifp->if_dname, "lagg") == 0 || 1091499c3e17SSepherosa Ziehau strcmp(ifp->if_dname, "vlan") == 0) 1092499c3e17SSepherosa Ziehau return (false); 1093499c3e17SSepherosa Ziehau 1094499c3e17SSepherosa Ziehau if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0) 1095499c3e17SSepherosa Ziehau return (false); 1096499c3e17SSepherosa Ziehau 1097499c3e17SSepherosa Ziehau return (true); 1098499c3e17SSepherosa Ziehau } 1099499c3e17SSepherosa Ziehau 11005bdfd3fdSDexuan Cui static void 1101962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf) 11025bdfd3fdSDexuan Cui { 11035bdfd3fdSDexuan Cui struct ifnet *hn_ifp; 11045bdfd3fdSDexuan Cui 11055bdfd3fdSDexuan Cui HN_LOCK(sc); 11065bdfd3fdSDexuan Cui 11075bdfd3fdSDexuan Cui if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 11085bdfd3fdSDexuan Cui goto out; 11095bdfd3fdSDexuan Cui 1110499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1111499c3e17SSepherosa Ziehau goto out; 11125bdfd3fdSDexuan Cui hn_ifp = sc->hn_ifp; 11135bdfd3fdSDexuan Cui 1114962f0357SSepherosa Ziehau if (rxvf) { 1115962f0357SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_RXVF) 11165bdfd3fdSDexuan Cui goto out; 11175bdfd3fdSDexuan Cui 1118962f0357SSepherosa Ziehau sc->hn_flags |= HN_FLAG_RXVF; 11195bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 11205bdfd3fdSDexuan Cui } else { 1121962f0357SSepherosa Ziehau if (!(sc->hn_flags & HN_FLAG_RXVF)) 11225bdfd3fdSDexuan Cui goto out; 11235bdfd3fdSDexuan Cui 1124962f0357SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_RXVF; 1125499c3e17SSepherosa Ziehau if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 11265bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 11275bdfd3fdSDexuan Cui else 11285bdfd3fdSDexuan Cui hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE); 11295bdfd3fdSDexuan Cui } 11305bdfd3fdSDexuan Cui 11315bdfd3fdSDexuan Cui hn_nvs_set_datapath(sc, 11329c6cae24SSepherosa Ziehau rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH); 11335bdfd3fdSDexuan Cui 1134962f0357SSepherosa Ziehau hn_rxvf_set(sc, rxvf ? ifp : NULL); 11355bdfd3fdSDexuan Cui 1136962f0357SSepherosa Ziehau if (rxvf) { 11375bdfd3fdSDexuan Cui hn_suspend_mgmt(sc); 11385bdfd3fdSDexuan Cui sc->hn_link_flags &= 11395bdfd3fdSDexuan Cui ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG); 1140499c3e17SSepherosa Ziehau if_link_state_change(hn_ifp, LINK_STATE_DOWN); 11415bdfd3fdSDexuan Cui } else { 11425bdfd3fdSDexuan Cui hn_resume_mgmt(sc); 11435bdfd3fdSDexuan Cui } 11445bdfd3fdSDexuan Cui 1145962f0357SSepherosa Ziehau devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname, 1146962f0357SSepherosa Ziehau rxvf ? "VF_UP" : "VF_DOWN", NULL); 114733408a34SDexuan Cui 1148962f0357SSepherosa Ziehau if (bootverbose) { 1149962f0357SSepherosa Ziehau if_printf(hn_ifp, "datapath is switched %s %s\n", 1150962f0357SSepherosa Ziehau rxvf ? "to" : "from", ifp->if_xname); 1151962f0357SSepherosa Ziehau } 11525bdfd3fdSDexuan Cui out: 11535bdfd3fdSDexuan Cui HN_UNLOCK(sc); 11545bdfd3fdSDexuan Cui } 11555bdfd3fdSDexuan Cui 11565bdfd3fdSDexuan Cui static void 11575bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event) 11585bdfd3fdSDexuan Cui { 1159962f0357SSepherosa Ziehau 11605bdfd3fdSDexuan Cui if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN) 11615bdfd3fdSDexuan Cui return; 1162962f0357SSepherosa Ziehau hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP); 11635bdfd3fdSDexuan Cui } 11645bdfd3fdSDexuan Cui 11655bdfd3fdSDexuan Cui static void 11665bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp) 11675bdfd3fdSDexuan Cui { 1168962f0357SSepherosa Ziehau 1169962f0357SSepherosa Ziehau hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP); 11705bdfd3fdSDexuan Cui } 11715bdfd3fdSDexuan Cui 11729c6cae24SSepherosa Ziehau static int 11739c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr) 11749c6cae24SSepherosa Ziehau { 11759c6cae24SSepherosa Ziehau struct ifnet *ifp, *vf_ifp; 11769c6cae24SSepherosa Ziehau uint64_t tmp; 11779c6cae24SSepherosa Ziehau int error; 11789c6cae24SSepherosa Ziehau 11799c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 11809c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 11819c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 11829c6cae24SSepherosa Ziehau 11839c6cae24SSepherosa Ziehau /* 11849c6cae24SSepherosa Ziehau * Fix up requested capabilities w/ supported capabilities, 11859c6cae24SSepherosa Ziehau * since the supported capabilities could have been changed. 11869c6cae24SSepherosa Ziehau */ 11879c6cae24SSepherosa Ziehau ifr->ifr_reqcap &= ifp->if_capabilities; 11889c6cae24SSepherosa Ziehau /* Pass SIOCSIFCAP to VF. */ 11899c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr); 11909c6cae24SSepherosa Ziehau 11919c6cae24SSepherosa Ziehau /* 11929c6cae24SSepherosa Ziehau * NOTE: 11939c6cae24SSepherosa Ziehau * The error will be propagated to the callers, however, it 11949c6cae24SSepherosa Ziehau * is _not_ useful here. 11959c6cae24SSepherosa Ziehau */ 11969c6cae24SSepherosa Ziehau 11979c6cae24SSepherosa Ziehau /* 11989c6cae24SSepherosa Ziehau * Merge VF's enabled capabilities. 11999c6cae24SSepherosa Ziehau */ 12009c6cae24SSepherosa Ziehau ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities; 12019c6cae24SSepherosa Ziehau 12029c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc); 12039c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 12049c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12059c6cae24SSepherosa Ziehau else 12069c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12079c6cae24SSepherosa Ziehau 12089c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc); 12099c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 12109c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12119c6cae24SSepherosa Ziehau else 12129c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12139c6cae24SSepherosa Ziehau 12149c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & CSUM_IP_TSO; 12159c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 12169c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12179c6cae24SSepherosa Ziehau else 12189c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12199c6cae24SSepherosa Ziehau 12209c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO; 12219c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 12229c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12239c6cae24SSepherosa Ziehau else 12249c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12259c6cae24SSepherosa Ziehau 12269c6cae24SSepherosa Ziehau return (error); 12279c6cae24SSepherosa Ziehau } 12289c6cae24SSepherosa Ziehau 12299c6cae24SSepherosa Ziehau static int 12309c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc) 12319c6cae24SSepherosa Ziehau { 12329c6cae24SSepherosa Ziehau struct ifnet *vf_ifp; 12339c6cae24SSepherosa Ziehau struct ifreq ifr; 12349c6cae24SSepherosa Ziehau 12359c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 12369c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 12379c6cae24SSepherosa Ziehau 12389c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 12399c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 12409c6cae24SSepherosa Ziehau ifr.ifr_flags = vf_ifp->if_flags & 0xffff; 12419c6cae24SSepherosa Ziehau ifr.ifr_flagshigh = vf_ifp->if_flags >> 16; 12429c6cae24SSepherosa Ziehau return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr)); 12439c6cae24SSepherosa Ziehau } 12449c6cae24SSepherosa Ziehau 12459c6cae24SSepherosa Ziehau static void 12469c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc) 12479c6cae24SSepherosa Ziehau { 12489c6cae24SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 12499c6cae24SSepherosa Ziehau int allmulti = 0; 12509c6cae24SSepherosa Ziehau 12519c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 12529c6cae24SSepherosa Ziehau 12539c6cae24SSepherosa Ziehau /* XXX vlan(4) style mcast addr maintenance */ 12549c6cae24SSepherosa Ziehau if (!TAILQ_EMPTY(&ifp->if_multiaddrs)) 12559c6cae24SSepherosa Ziehau allmulti = IFF_ALLMULTI; 12569c6cae24SSepherosa Ziehau 12579c6cae24SSepherosa Ziehau /* Always set the VF's if_flags */ 12589c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti; 12599c6cae24SSepherosa Ziehau } 12609c6cae24SSepherosa Ziehau 12619c6cae24SSepherosa Ziehau static void 12629c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m) 12639c6cae24SSepherosa Ziehau { 12649c6cae24SSepherosa Ziehau struct rm_priotracker pt; 12659c6cae24SSepherosa Ziehau struct ifnet *hn_ifp = NULL; 12669c6cae24SSepherosa Ziehau struct mbuf *mn; 12679c6cae24SSepherosa Ziehau 12689c6cae24SSepherosa Ziehau /* 12699c6cae24SSepherosa Ziehau * XXX racy, if hn(4) ever detached. 12709c6cae24SSepherosa Ziehau */ 12719c6cae24SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 12729c6cae24SSepherosa Ziehau if (vf_ifp->if_index < hn_vfmap_size) 12739c6cae24SSepherosa Ziehau hn_ifp = hn_vfmap[vf_ifp->if_index]; 12749c6cae24SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 12759c6cae24SSepherosa Ziehau 12769c6cae24SSepherosa Ziehau if (hn_ifp != NULL) { 12779c6cae24SSepherosa Ziehau for (mn = m; mn != NULL; mn = mn->m_nextpkt) { 12783bed4e54SSepherosa Ziehau /* 12793bed4e54SSepherosa Ziehau * Allow tapping on the VF. 12803bed4e54SSepherosa Ziehau */ 12819c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(vf_ifp, mn); 12823bed4e54SSepherosa Ziehau 12833bed4e54SSepherosa Ziehau /* 12843bed4e54SSepherosa Ziehau * Update VF stats. 12853bed4e54SSepherosa Ziehau */ 12863bed4e54SSepherosa Ziehau if ((vf_ifp->if_capenable & IFCAP_HWSTATS) == 0) { 12873bed4e54SSepherosa Ziehau if_inc_counter(vf_ifp, IFCOUNTER_IBYTES, 12883bed4e54SSepherosa Ziehau mn->m_pkthdr.len); 12893bed4e54SSepherosa Ziehau } 12903bed4e54SSepherosa Ziehau /* 12913bed4e54SSepherosa Ziehau * XXX IFCOUNTER_IMCAST 12923bed4e54SSepherosa Ziehau * This stat updating is kinda invasive, since it 12933bed4e54SSepherosa Ziehau * requires two checks on the mbuf: the length check 12943bed4e54SSepherosa Ziehau * and the ethernet header check. As of this write, 12953bed4e54SSepherosa Ziehau * all multicast packets go directly to hn(4), which 12963bed4e54SSepherosa Ziehau * makes imcast stat updating in the VF a try in vian. 12973bed4e54SSepherosa Ziehau */ 12983bed4e54SSepherosa Ziehau 12993bed4e54SSepherosa Ziehau /* 13003bed4e54SSepherosa Ziehau * Fix up rcvif and increase hn(4)'s ipackets. 13013bed4e54SSepherosa Ziehau */ 13029c6cae24SSepherosa Ziehau mn->m_pkthdr.rcvif = hn_ifp; 13039c6cae24SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1); 13049c6cae24SSepherosa Ziehau } 13053bed4e54SSepherosa Ziehau /* 13063bed4e54SSepherosa Ziehau * Go through hn(4)'s if_input. 13073bed4e54SSepherosa Ziehau */ 13089c6cae24SSepherosa Ziehau hn_ifp->if_input(hn_ifp, m); 13099c6cae24SSepherosa Ziehau } else { 13109c6cae24SSepherosa Ziehau /* 13119c6cae24SSepherosa Ziehau * In the middle of the transition; free this 13129c6cae24SSepherosa Ziehau * mbuf chain. 13139c6cae24SSepherosa Ziehau */ 13149c6cae24SSepherosa Ziehau while (m != NULL) { 13159c6cae24SSepherosa Ziehau mn = m->m_nextpkt; 13169c6cae24SSepherosa Ziehau m->m_nextpkt = NULL; 13179c6cae24SSepherosa Ziehau m_freem(m); 13189c6cae24SSepherosa Ziehau m = mn; 13199c6cae24SSepherosa Ziehau } 13209c6cae24SSepherosa Ziehau } 13219c6cae24SSepherosa Ziehau } 13229c6cae24SSepherosa Ziehau 13239c6cae24SSepherosa Ziehau static void 13249c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc) 13259c6cae24SSepherosa Ziehau { 13269c6cae24SSepherosa Ziehau struct ifnet *ifp; 13279c6cae24SSepherosa Ziehau 13289c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 13299c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 13309c6cae24SSepherosa Ziehau 13319c6cae24SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu); 13329c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099 13339c6cae24SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp)) 13349c6cae24SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp)); 13359c6cae24SSepherosa Ziehau #endif 13369c6cae24SSepherosa Ziehau } 13379c6cae24SSepherosa Ziehau 13389c6cae24SSepherosa Ziehau static void 13399c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc) 13409c6cae24SSepherosa Ziehau { 13419c6cae24SSepherosa Ziehau struct ifnet *ifp, *vf_ifp; 13429c6cae24SSepherosa Ziehau struct ifreq ifr; 13439c6cae24SSepherosa Ziehau 13449c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 13459c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 13469c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 13479c6cae24SSepherosa Ziehau 13489c6cae24SSepherosa Ziehau /* 13499c6cae24SSepherosa Ziehau * Mark the VF ready. 13509c6cae24SSepherosa Ziehau */ 13519c6cae24SSepherosa Ziehau sc->hn_vf_rdytick = 0; 13529c6cae24SSepherosa Ziehau 13539c6cae24SSepherosa Ziehau /* 13549c6cae24SSepherosa Ziehau * Save information for restoration. 13559c6cae24SSepherosa Ziehau */ 13569c6cae24SSepherosa Ziehau sc->hn_saved_caps = ifp->if_capabilities; 13579c6cae24SSepherosa Ziehau sc->hn_saved_tsomax = ifp->if_hw_tsomax; 13589c6cae24SSepherosa Ziehau sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount; 13599c6cae24SSepherosa Ziehau sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize; 13609c6cae24SSepherosa Ziehau 13619c6cae24SSepherosa Ziehau /* 13629c6cae24SSepherosa Ziehau * Intersect supported/enabled capabilities. 13639c6cae24SSepherosa Ziehau * 13649c6cae24SSepherosa Ziehau * NOTE: 13659c6cae24SSepherosa Ziehau * if_hwassist is not changed here. 13669c6cae24SSepherosa Ziehau */ 13679c6cae24SSepherosa Ziehau ifp->if_capabilities &= vf_ifp->if_capabilities; 13689c6cae24SSepherosa Ziehau ifp->if_capenable &= ifp->if_capabilities; 13699c6cae24SSepherosa Ziehau 13709c6cae24SSepherosa Ziehau /* 13719c6cae24SSepherosa Ziehau * Fix TSO settings. 13729c6cae24SSepherosa Ziehau */ 13739c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax) 13749c6cae24SSepherosa Ziehau ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax; 13759c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount) 13769c6cae24SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount; 13779c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize) 13789c6cae24SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize; 13799c6cae24SSepherosa Ziehau 13809c6cae24SSepherosa Ziehau /* 13819c6cae24SSepherosa Ziehau * Change VF's enabled capabilities. 13829c6cae24SSepherosa Ziehau */ 13839c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 13849c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 13859c6cae24SSepherosa Ziehau ifr.ifr_reqcap = ifp->if_capenable; 13869c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(sc, &ifr); 13879c6cae24SSepherosa Ziehau 13889c6cae24SSepherosa Ziehau if (ifp->if_mtu != ETHERMTU) { 13899c6cae24SSepherosa Ziehau int error; 13909c6cae24SSepherosa Ziehau 13919c6cae24SSepherosa Ziehau /* 13929c6cae24SSepherosa Ziehau * Change VF's MTU. 13939c6cae24SSepherosa Ziehau */ 13949c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 13959c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 13969c6cae24SSepherosa Ziehau ifr.ifr_mtu = ifp->if_mtu; 13979c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr); 13989c6cae24SSepherosa Ziehau if (error) { 13999c6cae24SSepherosa Ziehau if_printf(ifp, "%s SIOCSIFMTU %u failed\n", 14009c6cae24SSepherosa Ziehau vf_ifp->if_xname, ifp->if_mtu); 14019c6cae24SSepherosa Ziehau if (ifp->if_mtu > ETHERMTU) { 14029c6cae24SSepherosa Ziehau if_printf(ifp, "change MTU to %d\n", ETHERMTU); 14039c6cae24SSepherosa Ziehau 14049c6cae24SSepherosa Ziehau /* 14059c6cae24SSepherosa Ziehau * XXX 14069c6cae24SSepherosa Ziehau * No need to adjust the synthetic parts' MTU; 14079c6cae24SSepherosa Ziehau * failure of the adjustment will cause us 14089c6cae24SSepherosa Ziehau * infinite headache. 14099c6cae24SSepherosa Ziehau */ 14109c6cae24SSepherosa Ziehau ifp->if_mtu = ETHERMTU; 14119c6cae24SSepherosa Ziehau hn_mtu_change_fixup(sc); 14129c6cae24SSepherosa Ziehau } 14139c6cae24SSepherosa Ziehau } 14149c6cae24SSepherosa Ziehau } 14159c6cae24SSepherosa Ziehau } 14169c6cae24SSepherosa Ziehau 14179c6cae24SSepherosa Ziehau static bool 14189c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc) 14199c6cae24SSepherosa Ziehau { 14209c6cae24SSepherosa Ziehau 14219c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 14229c6cae24SSepherosa Ziehau 14239c6cae24SSepherosa Ziehau if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL) 14249c6cae24SSepherosa Ziehau return (false); 14259c6cae24SSepherosa Ziehau 14269c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick == 0) 14279c6cae24SSepherosa Ziehau return (true); 14289c6cae24SSepherosa Ziehau 14299c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick > ticks) 14309c6cae24SSepherosa Ziehau return (false); 14319c6cae24SSepherosa Ziehau 14329c6cae24SSepherosa Ziehau /* Mark VF as ready. */ 14339c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(sc); 14349c6cae24SSepherosa Ziehau return (true); 14359c6cae24SSepherosa Ziehau } 14369c6cae24SSepherosa Ziehau 14379c6cae24SSepherosa Ziehau static void 1438a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc) 1439a97fff19SSepherosa Ziehau { 1440a97fff19SSepherosa Ziehau int i; 1441a97fff19SSepherosa Ziehau 1442a97fff19SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1443a97fff19SSepherosa Ziehau 1444a97fff19SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ 1445a97fff19SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 1446a97fff19SSepherosa Ziehau sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED; 1447a97fff19SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 1448a97fff19SSepherosa Ziehau 1449a97fff19SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 1450a97fff19SSepherosa Ziehau sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF; 1451a97fff19SSepherosa Ziehau } 1452a97fff19SSepherosa Ziehau 1453a97fff19SSepherosa Ziehau static void 1454a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf) 1455a97fff19SSepherosa Ziehau { 1456a97fff19SSepherosa Ziehau int i; 1457a97fff19SSepherosa Ziehau 1458a97fff19SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1459a97fff19SSepherosa Ziehau 1460a97fff19SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ 1461a97fff19SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 1462a97fff19SSepherosa Ziehau sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED; 1463a97fff19SSepherosa Ziehau if (clear_vf) 1464a97fff19SSepherosa Ziehau sc->hn_vf_ifp = NULL; 1465a97fff19SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 1466a97fff19SSepherosa Ziehau 1467a97fff19SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 1468a97fff19SSepherosa Ziehau sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF; 1469a97fff19SSepherosa Ziehau } 1470a97fff19SSepherosa Ziehau 1471a97fff19SSepherosa Ziehau static void 14729c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc) 14739c6cae24SSepherosa Ziehau { 14749c6cae24SSepherosa Ziehau int error; 14759c6cae24SSepherosa Ziehau 14769c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 14779c6cae24SSepherosa Ziehau 14789c6cae24SSepherosa Ziehau KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0, 14799c6cae24SSepherosa Ziehau ("%s: transparent VF was enabled", sc->hn_ifp->if_xname)); 14809c6cae24SSepherosa Ziehau 14819c6cae24SSepherosa Ziehau if (bootverbose) { 14829c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "try bringing up %s\n", 14839c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 14849c6cae24SSepherosa Ziehau } 14859c6cae24SSepherosa Ziehau 14869c6cae24SSepherosa Ziehau /* 14879c6cae24SSepherosa Ziehau * Bring the VF up. 14889c6cae24SSepherosa Ziehau */ 14899c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 14909c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags |= IFF_UP; 14919c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 14929c6cae24SSepherosa Ziehau if (error) { 14939c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "bringing up %s failed: %d\n", 14949c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname, error); 14959c6cae24SSepherosa Ziehau return; 14969c6cae24SSepherosa Ziehau } 14979c6cae24SSepherosa Ziehau 14989c6cae24SSepherosa Ziehau /* 14999c6cae24SSepherosa Ziehau * NOTE: 15009c6cae24SSepherosa Ziehau * Datapath setting must happen _after_ bringing the VF up. 15019c6cae24SSepherosa Ziehau */ 15029c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF); 15039c6cae24SSepherosa Ziehau 1504a97fff19SSepherosa Ziehau /* Mark transparent mode VF as enabled. */ 1505a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(sc); 15069c6cae24SSepherosa Ziehau } 15079c6cae24SSepherosa Ziehau 15089c6cae24SSepherosa Ziehau static void 15099c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused) 15109c6cae24SSepherosa Ziehau { 15119c6cae24SSepherosa Ziehau struct hn_softc *sc = xsc; 15129c6cae24SSepherosa Ziehau 15139c6cae24SSepherosa Ziehau HN_LOCK(sc); 15149c6cae24SSepherosa Ziehau 15159c6cae24SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 15169c6cae24SSepherosa Ziehau goto done; 15179c6cae24SSepherosa Ziehau if (sc->hn_vf_ifp == NULL) 15189c6cae24SSepherosa Ziehau goto done; 15199c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 15209c6cae24SSepherosa Ziehau goto done; 15219c6cae24SSepherosa Ziehau 15229c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick != 0) { 15239c6cae24SSepherosa Ziehau /* Mark VF as ready. */ 15249c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(sc); 15259c6cae24SSepherosa Ziehau } 15269c6cae24SSepherosa Ziehau 15279c6cae24SSepherosa Ziehau if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) { 15289c6cae24SSepherosa Ziehau /* 15299c6cae24SSepherosa Ziehau * Delayed VF initialization. 15309c6cae24SSepherosa Ziehau */ 15319c6cae24SSepherosa Ziehau if (bootverbose) { 15329c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "delayed initialize %s\n", 15339c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 15349c6cae24SSepherosa Ziehau } 15359c6cae24SSepherosa Ziehau hn_xpnt_vf_init(sc); 15369c6cae24SSepherosa Ziehau } 15379c6cae24SSepherosa Ziehau done: 15389c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 15399c6cae24SSepherosa Ziehau } 15409c6cae24SSepherosa Ziehau 1541499c3e17SSepherosa Ziehau static void 1542499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp) 1543499c3e17SSepherosa Ziehau { 1544499c3e17SSepherosa Ziehau struct hn_softc *sc = xsc; 1545499c3e17SSepherosa Ziehau 1546499c3e17SSepherosa Ziehau HN_LOCK(sc); 1547499c3e17SSepherosa Ziehau 1548499c3e17SSepherosa Ziehau if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 1549499c3e17SSepherosa Ziehau goto done; 1550499c3e17SSepherosa Ziehau 1551499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1552499c3e17SSepherosa Ziehau goto done; 1553499c3e17SSepherosa Ziehau 1554499c3e17SSepherosa Ziehau if (sc->hn_vf_ifp != NULL) { 1555499c3e17SSepherosa Ziehau if_printf(sc->hn_ifp, "%s was attached as VF\n", 1556499c3e17SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 1557499c3e17SSepherosa Ziehau goto done; 1558499c3e17SSepherosa Ziehau } 1559499c3e17SSepherosa Ziehau 15609c6cae24SSepherosa Ziehau if (hn_xpnt_vf && ifp->if_start != NULL) { 15619c6cae24SSepherosa Ziehau /* 15629c6cae24SSepherosa Ziehau * ifnet.if_start is _not_ supported by transparent 15639c6cae24SSepherosa Ziehau * mode VF; mainly due to the IFF_DRV_OACTIVE flag. 15649c6cae24SSepherosa Ziehau */ 15659c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported " 15669c6cae24SSepherosa Ziehau "in transparent VF mode.\n", ifp->if_xname); 15679c6cae24SSepherosa Ziehau goto done; 15689c6cae24SSepherosa Ziehau } 15699c6cae24SSepherosa Ziehau 1570499c3e17SSepherosa Ziehau rm_wlock(&hn_vfmap_lock); 1571499c3e17SSepherosa Ziehau 1572499c3e17SSepherosa Ziehau if (ifp->if_index >= hn_vfmap_size) { 1573499c3e17SSepherosa Ziehau struct ifnet **newmap; 1574499c3e17SSepherosa Ziehau int newsize; 1575499c3e17SSepherosa Ziehau 1576499c3e17SSepherosa Ziehau newsize = ifp->if_index + HN_VFMAP_SIZE_DEF; 1577499c3e17SSepherosa Ziehau newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF, 1578499c3e17SSepherosa Ziehau M_WAITOK | M_ZERO); 1579499c3e17SSepherosa Ziehau 1580499c3e17SSepherosa Ziehau memcpy(newmap, hn_vfmap, 1581499c3e17SSepherosa Ziehau sizeof(struct ifnet *) * hn_vfmap_size); 1582499c3e17SSepherosa Ziehau free(hn_vfmap, M_DEVBUF); 1583499c3e17SSepherosa Ziehau hn_vfmap = newmap; 1584499c3e17SSepherosa Ziehau hn_vfmap_size = newsize; 1585499c3e17SSepherosa Ziehau } 1586499c3e17SSepherosa Ziehau KASSERT(hn_vfmap[ifp->if_index] == NULL, 1587499c3e17SSepherosa Ziehau ("%s: ifindex %d was mapped to %s", 1588499c3e17SSepherosa Ziehau ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname)); 1589499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index] = sc->hn_ifp; 1590499c3e17SSepherosa Ziehau 1591499c3e17SSepherosa Ziehau rm_wunlock(&hn_vfmap_lock); 1592499c3e17SSepherosa Ziehau 15939c6cae24SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ 15949c6cae24SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 15959c6cae24SSepherosa Ziehau KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0, 15969c6cae24SSepherosa Ziehau ("%s: transparent VF was enabled", sc->hn_ifp->if_xname)); 1597499c3e17SSepherosa Ziehau sc->hn_vf_ifp = ifp; 15989c6cae24SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 15999c6cae24SSepherosa Ziehau 16009c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 16019c6cae24SSepherosa Ziehau int wait_ticks; 16029c6cae24SSepherosa Ziehau 16039c6cae24SSepherosa Ziehau /* 16049c6cae24SSepherosa Ziehau * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp. 16059c6cae24SSepherosa Ziehau * Save vf_ifp's current if_input for later restoration. 16069c6cae24SSepherosa Ziehau */ 16079c6cae24SSepherosa Ziehau sc->hn_vf_input = ifp->if_input; 16089c6cae24SSepherosa Ziehau ifp->if_input = hn_xpnt_vf_input; 16099c6cae24SSepherosa Ziehau 16109c6cae24SSepherosa Ziehau /* 16119c6cae24SSepherosa Ziehau * Stop link status management; use the VF's. 16129c6cae24SSepherosa Ziehau */ 16139c6cae24SSepherosa Ziehau hn_suspend_mgmt(sc); 16149c6cae24SSepherosa Ziehau 16159c6cae24SSepherosa Ziehau /* 16169c6cae24SSepherosa Ziehau * Give VF sometime to complete its attach routing. 16179c6cae24SSepherosa Ziehau */ 16189c6cae24SSepherosa Ziehau wait_ticks = hn_xpnt_vf_attwait * hz; 16199c6cae24SSepherosa Ziehau sc->hn_vf_rdytick = ticks + wait_ticks; 16209c6cae24SSepherosa Ziehau 16219c6cae24SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init, 16229c6cae24SSepherosa Ziehau wait_ticks); 16239c6cae24SSepherosa Ziehau } 1624499c3e17SSepherosa Ziehau done: 1625499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 1626499c3e17SSepherosa Ziehau } 1627499c3e17SSepherosa Ziehau 1628499c3e17SSepherosa Ziehau static void 1629499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp) 1630499c3e17SSepherosa Ziehau { 1631499c3e17SSepherosa Ziehau struct hn_softc *sc = xsc; 1632499c3e17SSepherosa Ziehau 1633499c3e17SSepherosa Ziehau HN_LOCK(sc); 1634499c3e17SSepherosa Ziehau 1635499c3e17SSepherosa Ziehau if (sc->hn_vf_ifp == NULL) 1636499c3e17SSepherosa Ziehau goto done; 1637499c3e17SSepherosa Ziehau 1638499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1639499c3e17SSepherosa Ziehau goto done; 1640499c3e17SSepherosa Ziehau 16419c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 16429c6cae24SSepherosa Ziehau /* 16439c6cae24SSepherosa Ziehau * Make sure that the delayed initialization is not running. 16449c6cae24SSepherosa Ziehau * 16459c6cae24SSepherosa Ziehau * NOTE: 16469c6cae24SSepherosa Ziehau * - This lock _must_ be released, since the hn_vf_init task 16479c6cae24SSepherosa Ziehau * will try holding this lock. 16489c6cae24SSepherosa Ziehau * - It is safe to release this lock here, since the 16499c6cae24SSepherosa Ziehau * hn_ifnet_attevent() is interlocked by the hn_vf_ifp. 16509c6cae24SSepherosa Ziehau * 16519c6cae24SSepherosa Ziehau * XXX racy, if hn(4) ever detached. 16529c6cae24SSepherosa Ziehau */ 16539c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 16549c6cae24SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init); 16559c6cae24SSepherosa Ziehau HN_LOCK(sc); 16569c6cae24SSepherosa Ziehau 16579c6cae24SSepherosa Ziehau KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved", 16589c6cae24SSepherosa Ziehau sc->hn_ifp->if_xname)); 16599c6cae24SSepherosa Ziehau ifp->if_input = sc->hn_vf_input; 16609c6cae24SSepherosa Ziehau sc->hn_vf_input = NULL; 16619c6cae24SSepherosa Ziehau 16629c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 16639c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH); 16649c6cae24SSepherosa Ziehau 16659c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick == 0) { 16669c6cae24SSepherosa Ziehau /* 16679c6cae24SSepherosa Ziehau * The VF was ready; restore some settings. 16689c6cae24SSepherosa Ziehau */ 16699c6cae24SSepherosa Ziehau sc->hn_ifp->if_capabilities = sc->hn_saved_caps; 16709c6cae24SSepherosa Ziehau /* 16719c6cae24SSepherosa Ziehau * NOTE: 16729c6cae24SSepherosa Ziehau * There is _no_ need to fixup if_capenable and 16739c6cae24SSepherosa Ziehau * if_hwassist, since the if_capabilities before 16749c6cae24SSepherosa Ziehau * restoration was an intersection of the VF's 16759c6cae24SSepherosa Ziehau * if_capabilites and the synthetic device's 16769c6cae24SSepherosa Ziehau * if_capabilites. 16779c6cae24SSepherosa Ziehau */ 16789c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax; 16799c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomaxsegcount = 16809c6cae24SSepherosa Ziehau sc->hn_saved_tsosegcnt; 16819c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz; 16829c6cae24SSepherosa Ziehau } 16839c6cae24SSepherosa Ziehau 16849c6cae24SSepherosa Ziehau /* 16859c6cae24SSepherosa Ziehau * Resume link status management, which was suspended 16869c6cae24SSepherosa Ziehau * by hn_ifnet_attevent(). 16879c6cae24SSepherosa Ziehau */ 16889c6cae24SSepherosa Ziehau hn_resume_mgmt(sc); 16899c6cae24SSepherosa Ziehau } 16909c6cae24SSepherosa Ziehau 1691a97fff19SSepherosa Ziehau /* Mark transparent mode VF as disabled. */ 1692a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */); 1693499c3e17SSepherosa Ziehau 1694499c3e17SSepherosa Ziehau rm_wlock(&hn_vfmap_lock); 1695499c3e17SSepherosa Ziehau 1696499c3e17SSepherosa Ziehau KASSERT(ifp->if_index < hn_vfmap_size, 1697499c3e17SSepherosa Ziehau ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size)); 1698499c3e17SSepherosa Ziehau if (hn_vfmap[ifp->if_index] != NULL) { 1699499c3e17SSepherosa Ziehau KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp, 1700499c3e17SSepherosa Ziehau ("%s: ifindex %d was mapped to %s", 1701499c3e17SSepherosa Ziehau ifp->if_xname, ifp->if_index, 1702499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index]->if_xname)); 1703499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index] = NULL; 1704499c3e17SSepherosa Ziehau } 1705499c3e17SSepherosa Ziehau 1706499c3e17SSepherosa Ziehau rm_wunlock(&hn_vfmap_lock); 1707499c3e17SSepherosa Ziehau done: 1708499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 1709499c3e17SSepherosa Ziehau } 1710499c3e17SSepherosa Ziehau 17119c6cae24SSepherosa Ziehau static void 17129c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state) 17139c6cae24SSepherosa Ziehau { 17149c6cae24SSepherosa Ziehau struct hn_softc *sc = xsc; 17159c6cae24SSepherosa Ziehau 17169c6cae24SSepherosa Ziehau if (sc->hn_vf_ifp == ifp) 17179c6cae24SSepherosa Ziehau if_link_state_change(sc->hn_ifp, link_state); 17189c6cae24SSepherosa Ziehau } 17199c6cae24SSepherosa Ziehau 172015516c77SSepherosa Ziehau static int 172115516c77SSepherosa Ziehau hn_probe(device_t dev) 172215516c77SSepherosa Ziehau { 172315516c77SSepherosa Ziehau 1724c2d50b26SSepherosa Ziehau if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) { 172515516c77SSepherosa Ziehau device_set_desc(dev, "Hyper-V Network Interface"); 172615516c77SSepherosa Ziehau return BUS_PROBE_DEFAULT; 172715516c77SSepherosa Ziehau } 172815516c77SSepherosa Ziehau return ENXIO; 172915516c77SSepherosa Ziehau } 173015516c77SSepherosa Ziehau 173115516c77SSepherosa Ziehau static int 173215516c77SSepherosa Ziehau hn_attach(device_t dev) 173315516c77SSepherosa Ziehau { 173415516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 173515516c77SSepherosa Ziehau struct sysctl_oid_list *child; 173615516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 173715516c77SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 173815516c77SSepherosa Ziehau struct ifnet *ifp = NULL; 173915516c77SSepherosa Ziehau int error, ring_cnt, tx_ring_cnt; 174015516c77SSepherosa Ziehau 174115516c77SSepherosa Ziehau sc->hn_dev = dev; 174215516c77SSepherosa Ziehau sc->hn_prichan = vmbus_get_channel(dev); 174315516c77SSepherosa Ziehau HN_LOCK_INIT(sc); 17449c6cae24SSepherosa Ziehau rm_init(&sc->hn_vf_lock, "hnvf"); 17459c6cae24SSepherosa Ziehau if (hn_xpnt_vf && hn_xpnt_vf_accbpf) 17469c6cae24SSepherosa Ziehau sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF; 174715516c77SSepherosa Ziehau 174815516c77SSepherosa Ziehau /* 1749dc13fee6SSepherosa Ziehau * Initialize these tunables once. 1750dc13fee6SSepherosa Ziehau */ 1751dc13fee6SSepherosa Ziehau sc->hn_agg_size = hn_tx_agg_size; 1752dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = hn_tx_agg_pkts; 1753dc13fee6SSepherosa Ziehau 1754dc13fee6SSepherosa Ziehau /* 175515516c77SSepherosa Ziehau * Setup taskqueue for transmission. 175615516c77SSepherosa Ziehau */ 17570e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) { 1758fdd0222aSSepherosa Ziehau int i; 1759fdd0222aSSepherosa Ziehau 1760fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = 1761fdd0222aSSepherosa Ziehau malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 1762fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 1763fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 1764fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx", 1765fdd0222aSSepherosa Ziehau M_WAITOK, taskqueue_thread_enqueue, 1766fdd0222aSSepherosa Ziehau &sc->hn_tx_taskqs[i]); 1767fdd0222aSSepherosa Ziehau taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET, 1768fdd0222aSSepherosa Ziehau "%s tx%d", device_get_nameunit(dev), i); 1769fdd0222aSSepherosa Ziehau } 17700e11868dSSepherosa Ziehau } else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) { 1771fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = hn_tx_taskque; 177215516c77SSepherosa Ziehau } 177315516c77SSepherosa Ziehau 177415516c77SSepherosa Ziehau /* 177515516c77SSepherosa Ziehau * Setup taskqueue for mangement tasks, e.g. link status. 177615516c77SSepherosa Ziehau */ 177715516c77SSepherosa Ziehau sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK, 177815516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0); 177915516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt", 178015516c77SSepherosa Ziehau device_get_nameunit(dev)); 178115516c77SSepherosa Ziehau TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc); 178215516c77SSepherosa Ziehau TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc); 178315516c77SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0, 178415516c77SSepherosa Ziehau hn_netchg_status_taskfunc, sc); 178515516c77SSepherosa Ziehau 17869c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 17879c6cae24SSepherosa Ziehau /* 17889c6cae24SSepherosa Ziehau * Setup taskqueue for VF tasks, e.g. delayed VF bringing up. 17899c6cae24SSepherosa Ziehau */ 17909c6cae24SSepherosa Ziehau sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK, 17919c6cae24SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_vf_taskq); 17929c6cae24SSepherosa Ziehau taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf", 17939c6cae24SSepherosa Ziehau device_get_nameunit(dev)); 17949c6cae24SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0, 17959c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc, sc); 17969c6cae24SSepherosa Ziehau } 17979c6cae24SSepherosa Ziehau 179815516c77SSepherosa Ziehau /* 179915516c77SSepherosa Ziehau * Allocate ifnet and setup its name earlier, so that if_printf 180015516c77SSepherosa Ziehau * can be used by functions, which will be called after 180115516c77SSepherosa Ziehau * ether_ifattach(). 180215516c77SSepherosa Ziehau */ 180315516c77SSepherosa Ziehau ifp = sc->hn_ifp = if_alloc(IFT_ETHER); 180415516c77SSepherosa Ziehau ifp->if_softc = sc; 180515516c77SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 180615516c77SSepherosa Ziehau 180715516c77SSepherosa Ziehau /* 180815516c77SSepherosa Ziehau * Initialize ifmedia earlier so that it can be unconditionally 180915516c77SSepherosa Ziehau * destroyed, if error happened later on. 181015516c77SSepherosa Ziehau */ 181115516c77SSepherosa Ziehau ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts); 181215516c77SSepherosa Ziehau 181315516c77SSepherosa Ziehau /* 181415516c77SSepherosa Ziehau * Figure out the # of RX rings (ring_cnt) and the # of TX rings 181515516c77SSepherosa Ziehau * to use (tx_ring_cnt). 181615516c77SSepherosa Ziehau * 181715516c77SSepherosa Ziehau * NOTE: 181815516c77SSepherosa Ziehau * The # of RX rings to use is same as the # of channels to use. 181915516c77SSepherosa Ziehau */ 182015516c77SSepherosa Ziehau ring_cnt = hn_chan_cnt; 182115516c77SSepherosa Ziehau if (ring_cnt <= 0) { 182215516c77SSepherosa Ziehau /* Default */ 182315516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 182415516c77SSepherosa Ziehau if (ring_cnt > HN_RING_CNT_DEF_MAX) 182515516c77SSepherosa Ziehau ring_cnt = HN_RING_CNT_DEF_MAX; 182615516c77SSepherosa Ziehau } else if (ring_cnt > mp_ncpus) { 182715516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 182815516c77SSepherosa Ziehau } 182934d68912SSepherosa Ziehau #ifdef RSS 183034d68912SSepherosa Ziehau if (ring_cnt > rss_getnumbuckets()) 183134d68912SSepherosa Ziehau ring_cnt = rss_getnumbuckets(); 183234d68912SSepherosa Ziehau #endif 183315516c77SSepherosa Ziehau 183415516c77SSepherosa Ziehau tx_ring_cnt = hn_tx_ring_cnt; 183515516c77SSepherosa Ziehau if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt) 183615516c77SSepherosa Ziehau tx_ring_cnt = ring_cnt; 183723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 183815516c77SSepherosa Ziehau if (hn_use_if_start) { 183915516c77SSepherosa Ziehau /* ifnet.if_start only needs one TX ring. */ 184015516c77SSepherosa Ziehau tx_ring_cnt = 1; 184115516c77SSepherosa Ziehau } 184223bf9e15SSepherosa Ziehau #endif 184315516c77SSepherosa Ziehau 184415516c77SSepherosa Ziehau /* 184515516c77SSepherosa Ziehau * Set the leader CPU for channels. 184615516c77SSepherosa Ziehau */ 184715516c77SSepherosa Ziehau sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus; 184815516c77SSepherosa Ziehau 184915516c77SSepherosa Ziehau /* 185015516c77SSepherosa Ziehau * Create enough TX/RX rings, even if only limited number of 185115516c77SSepherosa Ziehau * channels can be allocated. 185215516c77SSepherosa Ziehau */ 185315516c77SSepherosa Ziehau error = hn_create_tx_data(sc, tx_ring_cnt); 185415516c77SSepherosa Ziehau if (error) 185515516c77SSepherosa Ziehau goto failed; 185615516c77SSepherosa Ziehau error = hn_create_rx_data(sc, ring_cnt); 185715516c77SSepherosa Ziehau if (error) 185815516c77SSepherosa Ziehau goto failed; 185915516c77SSepherosa Ziehau 186015516c77SSepherosa Ziehau /* 186115516c77SSepherosa Ziehau * Create transaction context for NVS and RNDIS transactions. 186215516c77SSepherosa Ziehau */ 186315516c77SSepherosa Ziehau sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev), 186415516c77SSepherosa Ziehau HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0); 186525641fc7SSepherosa Ziehau if (sc->hn_xact == NULL) { 186625641fc7SSepherosa Ziehau error = ENXIO; 186715516c77SSepherosa Ziehau goto failed; 186825641fc7SSepherosa Ziehau } 186925641fc7SSepherosa Ziehau 187025641fc7SSepherosa Ziehau /* 187125641fc7SSepherosa Ziehau * Install orphan handler for the revocation of this device's 187225641fc7SSepherosa Ziehau * primary channel. 187325641fc7SSepherosa Ziehau * 187425641fc7SSepherosa Ziehau * NOTE: 187525641fc7SSepherosa Ziehau * The processing order is critical here: 187625641fc7SSepherosa Ziehau * Install the orphan handler, _before_ testing whether this 187725641fc7SSepherosa Ziehau * device's primary channel has been revoked or not. 187825641fc7SSepherosa Ziehau */ 187925641fc7SSepherosa Ziehau vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact); 188025641fc7SSepherosa Ziehau if (vmbus_chan_is_revoked(sc->hn_prichan)) { 188125641fc7SSepherosa Ziehau error = ENXIO; 188225641fc7SSepherosa Ziehau goto failed; 188325641fc7SSepherosa Ziehau } 188415516c77SSepherosa Ziehau 188515516c77SSepherosa Ziehau /* 188615516c77SSepherosa Ziehau * Attach the synthetic parts, i.e. NVS and RNDIS. 188715516c77SSepherosa Ziehau */ 188815516c77SSepherosa Ziehau error = hn_synth_attach(sc, ETHERMTU); 188915516c77SSepherosa Ziehau if (error) 189015516c77SSepherosa Ziehau goto failed; 189115516c77SSepherosa Ziehau 189215516c77SSepherosa Ziehau error = hn_rndis_get_eaddr(sc, eaddr); 189315516c77SSepherosa Ziehau if (error) 189415516c77SSepherosa Ziehau goto failed; 189515516c77SSepherosa Ziehau 189615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 189715516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 189815516c77SSepherosa Ziehau /* 189915516c77SSepherosa Ziehau * Reduce TCP segment aggregation limit for multiple 190015516c77SSepherosa Ziehau * RX rings to increase ACK timeliness. 190115516c77SSepherosa Ziehau */ 190215516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF); 190315516c77SSepherosa Ziehau } 190415516c77SSepherosa Ziehau #endif 190515516c77SSepherosa Ziehau 190615516c77SSepherosa Ziehau /* 190715516c77SSepherosa Ziehau * Fixup TX stuffs after synthetic parts are attached. 190815516c77SSepherosa Ziehau */ 190915516c77SSepherosa Ziehau hn_fixup_tx_data(sc); 191015516c77SSepherosa Ziehau 191115516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 191215516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 191315516c77SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD, 191415516c77SSepherosa Ziehau &sc->hn_nvs_ver, 0, "NVS version"); 191515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version", 191615516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 191715516c77SSepherosa Ziehau hn_ndis_version_sysctl, "A", "NDIS version"); 191815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps", 191915516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 192015516c77SSepherosa Ziehau hn_caps_sysctl, "A", "capabilities"); 192115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist", 192215516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 192315516c77SSepherosa Ziehau hn_hwassist_sysctl, "A", "hwassist"); 19249c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max", 19259c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size"); 19269c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt", 19279c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0, 19289c6cae24SSepherosa Ziehau "max # of TSO segments"); 19299c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz", 19309c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0, 19319c6cae24SSepherosa Ziehau "max size of TSO segment"); 193215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter", 193315516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 193415516c77SSepherosa Ziehau hn_rxfilter_sysctl, "A", "rxfilter"); 193515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash", 193615516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 193715516c77SSepherosa Ziehau hn_rss_hash_sysctl, "A", "RSS hash"); 193815516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size", 193915516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count"); 194034d68912SSepherosa Ziehau #ifndef RSS 194134d68912SSepherosa Ziehau /* 194234d68912SSepherosa Ziehau * Don't allow RSS key/indirect table changes, if RSS is defined. 194334d68912SSepherosa Ziehau */ 194415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key", 194515516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 194615516c77SSepherosa Ziehau hn_rss_key_sysctl, "IU", "RSS key"); 194715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind", 194815516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 194915516c77SSepherosa Ziehau hn_rss_ind_sysctl, "IU", "RSS indirect table"); 195034d68912SSepherosa Ziehau #endif 1951dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size", 1952dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_size, 0, 1953dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation size limit"); 1954dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts", 1955dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0, 1956dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation count limit"); 1957dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align", 1958dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_align, 0, 1959dc13fee6SSepherosa Ziehau "RNDIS packet transmission aggregation alignment"); 1960dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size", 1961dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 1962dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl, "I", 1963dc13fee6SSepherosa Ziehau "Packet transmission aggregation size, 0 -- disable, -1 -- auto"); 1964dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts", 1965dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 1966dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl, "I", 1967dc13fee6SSepherosa Ziehau "Packet transmission aggregation packets, " 1968dc13fee6SSepherosa Ziehau "0 -- disable, -1 -- auto"); 19696c1204dfSSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling", 19706c1204dfSSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 19716c1204dfSSepherosa Ziehau hn_polling_sysctl, "I", 19726c1204dfSSepherosa Ziehau "Polling frequency: [100,1000000], 0 disable polling"); 197340d60d6eSDexuan Cui SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf", 197440d60d6eSDexuan Cui CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 197540d60d6eSDexuan Cui hn_vf_sysctl, "A", "Virtual Function's name"); 19769c6cae24SSepherosa Ziehau if (!hn_xpnt_vf) { 1977499c3e17SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf", 1978499c3e17SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 1979499c3e17SSepherosa Ziehau hn_rxvf_sysctl, "A", "activated Virtual Function's name"); 19809c6cae24SSepherosa Ziehau } else { 19819c6cae24SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled", 19829c6cae24SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 19839c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl, "I", 19849c6cae24SSepherosa Ziehau "Transparent VF enabled"); 19859c6cae24SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf", 19869c6cae24SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 19879c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl, "I", 19889c6cae24SSepherosa Ziehau "Accurate BPF for transparent VF"); 19899c6cae24SSepherosa Ziehau } 199015516c77SSepherosa Ziehau 199115516c77SSepherosa Ziehau /* 199215516c77SSepherosa Ziehau * Setup the ifmedia, which has been initialized earlier. 199315516c77SSepherosa Ziehau */ 199415516c77SSepherosa Ziehau ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL); 199515516c77SSepherosa Ziehau ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO); 199615516c77SSepherosa Ziehau /* XXX ifmedia_set really should do this for us */ 199715516c77SSepherosa Ziehau sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media; 199815516c77SSepherosa Ziehau 199915516c77SSepherosa Ziehau /* 200015516c77SSepherosa Ziehau * Setup the ifnet for this interface. 200115516c77SSepherosa Ziehau */ 200215516c77SSepherosa Ziehau 200315516c77SSepherosa Ziehau ifp->if_baudrate = IF_Gbps(10); 200415516c77SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 200515516c77SSepherosa Ziehau ifp->if_ioctl = hn_ioctl; 200615516c77SSepherosa Ziehau ifp->if_init = hn_init; 200723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 200815516c77SSepherosa Ziehau if (hn_use_if_start) { 200915516c77SSepherosa Ziehau int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]); 201015516c77SSepherosa Ziehau 201115516c77SSepherosa Ziehau ifp->if_start = hn_start; 201215516c77SSepherosa Ziehau IFQ_SET_MAXLEN(&ifp->if_snd, qdepth); 201315516c77SSepherosa Ziehau ifp->if_snd.ifq_drv_maxlen = qdepth - 1; 201415516c77SSepherosa Ziehau IFQ_SET_READY(&ifp->if_snd); 201523bf9e15SSepherosa Ziehau } else 201623bf9e15SSepherosa Ziehau #endif 201723bf9e15SSepherosa Ziehau { 201815516c77SSepherosa Ziehau ifp->if_transmit = hn_transmit; 201915516c77SSepherosa Ziehau ifp->if_qflush = hn_xmit_qflush; 202015516c77SSepherosa Ziehau } 202115516c77SSepherosa Ziehau 20229c6cae24SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE; 202315516c77SSepherosa Ziehau #ifdef foo 202415516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 202515516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM_IPV6; 202615516c77SSepherosa Ziehau #endif 202715516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_VLAN) { 202815516c77SSepherosa Ziehau /* XXX not sure about VLAN_MTU. */ 202915516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 203015516c77SSepherosa Ziehau } 203115516c77SSepherosa Ziehau 203215516c77SSepherosa Ziehau ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist; 203315516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP_MASK) 203415516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM; 203515516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP6_MASK) 203615516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM_IPV6; 203715516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO4) { 203815516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO4; 203915516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 204015516c77SSepherosa Ziehau } 204115516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO6) { 204215516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO6; 204315516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 204415516c77SSepherosa Ziehau } 204515516c77SSepherosa Ziehau 204615516c77SSepherosa Ziehau /* Enable all available capabilities by default. */ 204715516c77SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 204815516c77SSepherosa Ziehau 20497960e6baSSepherosa Ziehau /* 20507960e6baSSepherosa Ziehau * Disable IPv6 TSO and TXCSUM by default, they still can 20517960e6baSSepherosa Ziehau * be enabled through SIOCSIFCAP. 20527960e6baSSepherosa Ziehau */ 20537960e6baSSepherosa Ziehau ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 20547960e6baSSepherosa Ziehau ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO); 20557960e6baSSepherosa Ziehau 205615516c77SSepherosa Ziehau if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) { 20579c6cae24SSepherosa Ziehau /* 20589c6cae24SSepherosa Ziehau * Lock hn_set_tso_maxsize() to simplify its 20599c6cae24SSepherosa Ziehau * internal logic. 20609c6cae24SSepherosa Ziehau */ 20619c6cae24SSepherosa Ziehau HN_LOCK(sc); 206215516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU); 20639c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 206415516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; 206515516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 206615516c77SSepherosa Ziehau } 206715516c77SSepherosa Ziehau 206815516c77SSepherosa Ziehau ether_ifattach(ifp, eaddr); 206915516c77SSepherosa Ziehau 207015516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) { 207115516c77SSepherosa Ziehau if_printf(ifp, "TSO segcnt %u segsz %u\n", 207215516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize); 207315516c77SSepherosa Ziehau } 207415516c77SSepherosa Ziehau 207515516c77SSepherosa Ziehau /* Inform the upper layer about the long frame support. */ 207615516c77SSepherosa Ziehau ifp->if_hdrlen = sizeof(struct ether_vlan_header); 207715516c77SSepherosa Ziehau 207815516c77SSepherosa Ziehau /* 207915516c77SSepherosa Ziehau * Kick off link status check. 208015516c77SSepherosa Ziehau */ 208115516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 208215516c77SSepherosa Ziehau hn_update_link_status(sc); 208315516c77SSepherosa Ziehau 20849c6cae24SSepherosa Ziehau if (!hn_xpnt_vf) { 20855bdfd3fdSDexuan Cui sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event, 20865bdfd3fdSDexuan Cui hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY); 20875bdfd3fdSDexuan Cui sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event, 20885bdfd3fdSDexuan Cui hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY); 20899c6cae24SSepherosa Ziehau } else { 20909c6cae24SSepherosa Ziehau sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event, 20919c6cae24SSepherosa Ziehau hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY); 20929c6cae24SSepherosa Ziehau } 20935bdfd3fdSDexuan Cui 2094f41e0df4SSepherosa Ziehau /* 2095f41e0df4SSepherosa Ziehau * NOTE: 2096f41e0df4SSepherosa Ziehau * Subscribe ether_ifattach event, instead of ifnet_arrival event, 2097f41e0df4SSepherosa Ziehau * since interface's LLADDR is needed; interface LLADDR is not 2098f41e0df4SSepherosa Ziehau * available when ifnet_arrival event is triggered. 2099f41e0df4SSepherosa Ziehau */ 2100499c3e17SSepherosa Ziehau sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event, 2101499c3e17SSepherosa Ziehau hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY); 2102499c3e17SSepherosa Ziehau sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event, 2103499c3e17SSepherosa Ziehau hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY); 2104499c3e17SSepherosa Ziehau 210515516c77SSepherosa Ziehau return (0); 210615516c77SSepherosa Ziehau failed: 210715516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) 210815516c77SSepherosa Ziehau hn_synth_detach(sc); 210915516c77SSepherosa Ziehau hn_detach(dev); 211015516c77SSepherosa Ziehau return (error); 211115516c77SSepherosa Ziehau } 211215516c77SSepherosa Ziehau 211315516c77SSepherosa Ziehau static int 211415516c77SSepherosa Ziehau hn_detach(device_t dev) 211515516c77SSepherosa Ziehau { 211615516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 2117499c3e17SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp, *vf_ifp; 211815516c77SSepherosa Ziehau 21199c6cae24SSepherosa Ziehau if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) { 21209c6cae24SSepherosa Ziehau /* 21219c6cae24SSepherosa Ziehau * In case that the vmbus missed the orphan handler 21229c6cae24SSepherosa Ziehau * installation. 21239c6cae24SSepherosa Ziehau */ 21249c6cae24SSepherosa Ziehau vmbus_xact_ctx_orphan(sc->hn_xact); 21259c6cae24SSepherosa Ziehau } 21269c6cae24SSepherosa Ziehau 21275bdfd3fdSDexuan Cui if (sc->hn_ifaddr_evthand != NULL) 21285bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand); 21295bdfd3fdSDexuan Cui if (sc->hn_ifnet_evthand != NULL) 21305bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand); 2131499c3e17SSepherosa Ziehau if (sc->hn_ifnet_atthand != NULL) { 2132499c3e17SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ether_ifattach_event, 2133499c3e17SSepherosa Ziehau sc->hn_ifnet_atthand); 2134499c3e17SSepherosa Ziehau } 2135499c3e17SSepherosa Ziehau if (sc->hn_ifnet_dethand != NULL) { 2136499c3e17SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ifnet_departure_event, 2137499c3e17SSepherosa Ziehau sc->hn_ifnet_dethand); 2138499c3e17SSepherosa Ziehau } 21399c6cae24SSepherosa Ziehau if (sc->hn_ifnet_lnkhand != NULL) 21409c6cae24SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand); 2141499c3e17SSepherosa Ziehau 2142499c3e17SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 2143499c3e17SSepherosa Ziehau __compiler_membar(); 2144499c3e17SSepherosa Ziehau if (vf_ifp != NULL) 2145499c3e17SSepherosa Ziehau hn_ifnet_detevent(sc, vf_ifp); 21465bdfd3fdSDexuan Cui 214715516c77SSepherosa Ziehau if (device_is_attached(dev)) { 214815516c77SSepherosa Ziehau HN_LOCK(sc); 214915516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 215015516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 21515bdfd3fdSDexuan Cui hn_stop(sc, true); 215215516c77SSepherosa Ziehau /* 215315516c77SSepherosa Ziehau * NOTE: 215415516c77SSepherosa Ziehau * hn_stop() only suspends data, so managment 215515516c77SSepherosa Ziehau * stuffs have to be suspended manually here. 215615516c77SSepherosa Ziehau */ 215715516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 215815516c77SSepherosa Ziehau hn_synth_detach(sc); 215915516c77SSepherosa Ziehau } 216015516c77SSepherosa Ziehau HN_UNLOCK(sc); 216115516c77SSepherosa Ziehau ether_ifdetach(ifp); 216215516c77SSepherosa Ziehau } 216315516c77SSepherosa Ziehau 216415516c77SSepherosa Ziehau ifmedia_removeall(&sc->hn_media); 216515516c77SSepherosa Ziehau hn_destroy_rx_data(sc); 216615516c77SSepherosa Ziehau hn_destroy_tx_data(sc); 216715516c77SSepherosa Ziehau 21680e11868dSSepherosa Ziehau if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) { 2169fdd0222aSSepherosa Ziehau int i; 2170fdd0222aSSepherosa Ziehau 2171fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 2172fdd0222aSSepherosa Ziehau taskqueue_free(sc->hn_tx_taskqs[i]); 2173fdd0222aSSepherosa Ziehau free(sc->hn_tx_taskqs, M_DEVBUF); 2174fdd0222aSSepherosa Ziehau } 217515516c77SSepherosa Ziehau taskqueue_free(sc->hn_mgmt_taskq0); 21769c6cae24SSepherosa Ziehau if (sc->hn_vf_taskq != NULL) 21779c6cae24SSepherosa Ziehau taskqueue_free(sc->hn_vf_taskq); 217815516c77SSepherosa Ziehau 217925641fc7SSepherosa Ziehau if (sc->hn_xact != NULL) { 218025641fc7SSepherosa Ziehau /* 218125641fc7SSepherosa Ziehau * Uninstall the orphan handler _before_ the xact is 218225641fc7SSepherosa Ziehau * destructed. 218325641fc7SSepherosa Ziehau */ 218425641fc7SSepherosa Ziehau vmbus_chan_unset_orphan(sc->hn_prichan); 218515516c77SSepherosa Ziehau vmbus_xact_ctx_destroy(sc->hn_xact); 218625641fc7SSepherosa Ziehau } 218715516c77SSepherosa Ziehau 218815516c77SSepherosa Ziehau if_free(ifp); 218915516c77SSepherosa Ziehau 219015516c77SSepherosa Ziehau HN_LOCK_DESTROY(sc); 21919c6cae24SSepherosa Ziehau rm_destroy(&sc->hn_vf_lock); 219215516c77SSepherosa Ziehau return (0); 219315516c77SSepherosa Ziehau } 219415516c77SSepherosa Ziehau 219515516c77SSepherosa Ziehau static int 219615516c77SSepherosa Ziehau hn_shutdown(device_t dev) 219715516c77SSepherosa Ziehau { 219815516c77SSepherosa Ziehau 219915516c77SSepherosa Ziehau return (0); 220015516c77SSepherosa Ziehau } 220115516c77SSepherosa Ziehau 220215516c77SSepherosa Ziehau static void 220315516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc) 220415516c77SSepherosa Ziehau { 220515516c77SSepherosa Ziehau uint32_t link_status; 220615516c77SSepherosa Ziehau int error; 220715516c77SSepherosa Ziehau 220815516c77SSepherosa Ziehau error = hn_rndis_get_linkstatus(sc, &link_status); 220915516c77SSepherosa Ziehau if (error) { 221015516c77SSepherosa Ziehau /* XXX what to do? */ 221115516c77SSepherosa Ziehau return; 221215516c77SSepherosa Ziehau } 221315516c77SSepherosa Ziehau 221415516c77SSepherosa Ziehau if (link_status == NDIS_MEDIA_STATE_CONNECTED) 221515516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_LINKUP; 221615516c77SSepherosa Ziehau else 221715516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 221815516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, 221915516c77SSepherosa Ziehau (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ? 222015516c77SSepherosa Ziehau LINK_STATE_UP : LINK_STATE_DOWN); 222115516c77SSepherosa Ziehau } 222215516c77SSepherosa Ziehau 222315516c77SSepherosa Ziehau static void 222415516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused) 222515516c77SSepherosa Ziehau { 222615516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 222715516c77SSepherosa Ziehau 222815516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 222915516c77SSepherosa Ziehau return; 223015516c77SSepherosa Ziehau hn_link_status(sc); 223115516c77SSepherosa Ziehau } 223215516c77SSepherosa Ziehau 223315516c77SSepherosa Ziehau static void 223415516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused) 223515516c77SSepherosa Ziehau { 223615516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 223715516c77SSepherosa Ziehau 223815516c77SSepherosa Ziehau /* Prevent any link status checks from running. */ 223915516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_NETCHG; 224015516c77SSepherosa Ziehau 224115516c77SSepherosa Ziehau /* 224215516c77SSepherosa Ziehau * Fake up a [link down --> link up] state change; 5 seconds 224315516c77SSepherosa Ziehau * delay is used, which closely simulates miibus reaction 224415516c77SSepherosa Ziehau * upon link down event. 224515516c77SSepherosa Ziehau */ 224615516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 224715516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); 224815516c77SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0, 224915516c77SSepherosa Ziehau &sc->hn_netchg_status, 5 * hz); 225015516c77SSepherosa Ziehau } 225115516c77SSepherosa Ziehau 225215516c77SSepherosa Ziehau static void 225315516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused) 225415516c77SSepherosa Ziehau { 225515516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 225615516c77SSepherosa Ziehau 225715516c77SSepherosa Ziehau /* Re-allow link status checks. */ 225815516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG; 225915516c77SSepherosa Ziehau hn_link_status(sc); 226015516c77SSepherosa Ziehau } 226115516c77SSepherosa Ziehau 226215516c77SSepherosa Ziehau static void 226315516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc) 226415516c77SSepherosa Ziehau { 226515516c77SSepherosa Ziehau 226615516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 226715516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task); 226815516c77SSepherosa Ziehau } 226915516c77SSepherosa Ziehau 227015516c77SSepherosa Ziehau static void 227115516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc) 227215516c77SSepherosa Ziehau { 227315516c77SSepherosa Ziehau 227415516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 227515516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init); 227615516c77SSepherosa Ziehau } 227715516c77SSepherosa Ziehau 227815516c77SSepherosa Ziehau static __inline int 227915516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd, 228015516c77SSepherosa Ziehau struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) 228115516c77SSepherosa Ziehau { 228215516c77SSepherosa Ziehau struct mbuf *m = *m_head; 228315516c77SSepherosa Ziehau int error; 228415516c77SSepherosa Ziehau 228515516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim")); 228615516c77SSepherosa Ziehau 228715516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap, 228815516c77SSepherosa Ziehau m, segs, nsegs, BUS_DMA_NOWAIT); 228915516c77SSepherosa Ziehau if (error == EFBIG) { 229015516c77SSepherosa Ziehau struct mbuf *m_new; 229115516c77SSepherosa Ziehau 229215516c77SSepherosa Ziehau m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX); 229315516c77SSepherosa Ziehau if (m_new == NULL) 229415516c77SSepherosa Ziehau return ENOBUFS; 229515516c77SSepherosa Ziehau else 229615516c77SSepherosa Ziehau *m_head = m = m_new; 229715516c77SSepherosa Ziehau txr->hn_tx_collapsed++; 229815516c77SSepherosa Ziehau 229915516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, 230015516c77SSepherosa Ziehau txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT); 230115516c77SSepherosa Ziehau } 230215516c77SSepherosa Ziehau if (!error) { 230315516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap, 230415516c77SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 230515516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_DMAMAP; 230615516c77SSepherosa Ziehau } 230715516c77SSepherosa Ziehau return error; 230815516c77SSepherosa Ziehau } 230915516c77SSepherosa Ziehau 231015516c77SSepherosa Ziehau static __inline int 231115516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd) 231215516c77SSepherosa Ziehau { 231315516c77SSepherosa Ziehau 231415516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0, 231515516c77SSepherosa Ziehau ("put an onlist txd %#x", txd->flags)); 2316dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2317dc13fee6SSepherosa Ziehau ("put an onagg txd %#x", txd->flags)); 231815516c77SSepherosa Ziehau 231915516c77SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 232015516c77SSepherosa Ziehau if (atomic_fetchadd_int(&txd->refs, -1) != 1) 232115516c77SSepherosa Ziehau return 0; 232215516c77SSepherosa Ziehau 2323dc13fee6SSepherosa Ziehau if (!STAILQ_EMPTY(&txd->agg_list)) { 2324dc13fee6SSepherosa Ziehau struct hn_txdesc *tmp_txd; 2325dc13fee6SSepherosa Ziehau 2326dc13fee6SSepherosa Ziehau while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) { 2327dc13fee6SSepherosa Ziehau int freed; 2328dc13fee6SSepherosa Ziehau 2329dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list), 2330dc13fee6SSepherosa Ziehau ("resursive aggregation on aggregated txdesc")); 2331dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG), 2332dc13fee6SSepherosa Ziehau ("not aggregated txdesc")); 2333dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 2334dc13fee6SSepherosa Ziehau ("aggregated txdesc uses dmamap")); 2335dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 2336dc13fee6SSepherosa Ziehau ("aggregated txdesc consumes " 2337dc13fee6SSepherosa Ziehau "chimney sending buffer")); 2338dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_size == 0, 2339dc13fee6SSepherosa Ziehau ("aggregated txdesc has non-zero " 2340dc13fee6SSepherosa Ziehau "chimney sending size")); 2341dc13fee6SSepherosa Ziehau 2342dc13fee6SSepherosa Ziehau STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link); 2343dc13fee6SSepherosa Ziehau tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG; 2344dc13fee6SSepherosa Ziehau freed = hn_txdesc_put(txr, tmp_txd); 2345dc13fee6SSepherosa Ziehau KASSERT(freed, ("failed to free aggregated txdesc")); 2346dc13fee6SSepherosa Ziehau } 2347dc13fee6SSepherosa Ziehau } 2348dc13fee6SSepherosa Ziehau 234915516c77SSepherosa Ziehau if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) { 235015516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 235115516c77SSepherosa Ziehau ("chim txd uses dmamap")); 235215516c77SSepherosa Ziehau hn_chim_free(txr->hn_sc, txd->chim_index); 235315516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 2354dc13fee6SSepherosa Ziehau txd->chim_size = 0; 235515516c77SSepherosa Ziehau } else if (txd->flags & HN_TXD_FLAG_DMAMAP) { 235615516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, 235715516c77SSepherosa Ziehau txd->data_dmap, BUS_DMASYNC_POSTWRITE); 235815516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_data_dtag, 235915516c77SSepherosa Ziehau txd->data_dmap); 236015516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_DMAMAP; 236115516c77SSepherosa Ziehau } 236215516c77SSepherosa Ziehau 236315516c77SSepherosa Ziehau if (txd->m != NULL) { 236415516c77SSepherosa Ziehau m_freem(txd->m); 236515516c77SSepherosa Ziehau txd->m = NULL; 236615516c77SSepherosa Ziehau } 236715516c77SSepherosa Ziehau 236815516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 236915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 237015516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 237115516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail >= 0 && 237215516c77SSepherosa Ziehau txr->hn_txdesc_avail < txr->hn_txdesc_cnt, 237315516c77SSepherosa Ziehau ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail)); 237415516c77SSepherosa Ziehau txr->hn_txdesc_avail++; 237515516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 237615516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 237785e4ae1eSSepherosa Ziehau #else /* HN_USE_TXDESC_BUFRING */ 237885e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 237915516c77SSepherosa Ziehau atomic_add_int(&txr->hn_txdesc_avail, 1); 238015516c77SSepherosa Ziehau #endif 238185e4ae1eSSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 238285e4ae1eSSepherosa Ziehau #endif /* !HN_USE_TXDESC_BUFRING */ 238315516c77SSepherosa Ziehau 238415516c77SSepherosa Ziehau return 1; 238515516c77SSepherosa Ziehau } 238615516c77SSepherosa Ziehau 238715516c77SSepherosa Ziehau static __inline struct hn_txdesc * 238815516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr) 238915516c77SSepherosa Ziehau { 239015516c77SSepherosa Ziehau struct hn_txdesc *txd; 239115516c77SSepherosa Ziehau 239215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 239315516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 239415516c77SSepherosa Ziehau txd = SLIST_FIRST(&txr->hn_txlist); 239515516c77SSepherosa Ziehau if (txd != NULL) { 239615516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail > 0, 239715516c77SSepherosa Ziehau ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail)); 239815516c77SSepherosa Ziehau txr->hn_txdesc_avail--; 239915516c77SSepherosa Ziehau SLIST_REMOVE_HEAD(&txr->hn_txlist, link); 240015516c77SSepherosa Ziehau } 240115516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 240215516c77SSepherosa Ziehau #else 240315516c77SSepherosa Ziehau txd = buf_ring_dequeue_sc(txr->hn_txdesc_br); 240415516c77SSepherosa Ziehau #endif 240515516c77SSepherosa Ziehau 240615516c77SSepherosa Ziehau if (txd != NULL) { 240715516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 240885e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 240915516c77SSepherosa Ziehau atomic_subtract_int(&txr->hn_txdesc_avail, 1); 241015516c77SSepherosa Ziehau #endif 241185e4ae1eSSepherosa Ziehau #endif /* HN_USE_TXDESC_BUFRING */ 241215516c77SSepherosa Ziehau KASSERT(txd->m == NULL && txd->refs == 0 && 2413dc13fee6SSepherosa Ziehau STAILQ_EMPTY(&txd->agg_list) && 241415516c77SSepherosa Ziehau txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 2415dc13fee6SSepherosa Ziehau txd->chim_size == 0 && 241615516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONLIST) && 2417dc13fee6SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONAGG) == 0 && 241815516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd")); 241915516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_ONLIST; 242015516c77SSepherosa Ziehau txd->refs = 1; 242115516c77SSepherosa Ziehau } 242215516c77SSepherosa Ziehau return txd; 242315516c77SSepherosa Ziehau } 242415516c77SSepherosa Ziehau 242515516c77SSepherosa Ziehau static __inline void 242615516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd) 242715516c77SSepherosa Ziehau { 242815516c77SSepherosa Ziehau 242915516c77SSepherosa Ziehau /* 0->1 transition will never work */ 243025641fc7SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 243115516c77SSepherosa Ziehau atomic_add_int(&txd->refs, 1); 243215516c77SSepherosa Ziehau } 243315516c77SSepherosa Ziehau 2434dc13fee6SSepherosa Ziehau static __inline void 2435dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd) 2436dc13fee6SSepherosa Ziehau { 2437dc13fee6SSepherosa Ziehau 2438dc13fee6SSepherosa Ziehau KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2439dc13fee6SSepherosa Ziehau ("recursive aggregation on aggregating txdesc")); 2440dc13fee6SSepherosa Ziehau 2441dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2442dc13fee6SSepherosa Ziehau ("already aggregated")); 2443dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&txd->agg_list), 2444dc13fee6SSepherosa Ziehau ("recursive aggregation on to-be-aggregated txdesc")); 2445dc13fee6SSepherosa Ziehau 2446dc13fee6SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONAGG; 2447dc13fee6SSepherosa Ziehau STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link); 2448dc13fee6SSepherosa Ziehau } 2449dc13fee6SSepherosa Ziehau 245015516c77SSepherosa Ziehau static bool 245115516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr) 245215516c77SSepherosa Ziehau { 245315516c77SSepherosa Ziehau bool pending = false; 245415516c77SSepherosa Ziehau 245515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 245615516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 245715516c77SSepherosa Ziehau if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt) 245815516c77SSepherosa Ziehau pending = true; 245915516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 246015516c77SSepherosa Ziehau #else 246115516c77SSepherosa Ziehau if (!buf_ring_full(txr->hn_txdesc_br)) 246215516c77SSepherosa Ziehau pending = true; 246315516c77SSepherosa Ziehau #endif 246415516c77SSepherosa Ziehau return (pending); 246515516c77SSepherosa Ziehau } 246615516c77SSepherosa Ziehau 246715516c77SSepherosa Ziehau static __inline void 246815516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr) 246915516c77SSepherosa Ziehau { 247015516c77SSepherosa Ziehau txr->hn_has_txeof = 0; 247115516c77SSepherosa Ziehau txr->hn_txeof(txr); 247215516c77SSepherosa Ziehau } 247315516c77SSepherosa Ziehau 247415516c77SSepherosa Ziehau static void 247515516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc, 247615516c77SSepherosa Ziehau struct vmbus_channel *chan, const void *data __unused, int dlen __unused) 247715516c77SSepherosa Ziehau { 247815516c77SSepherosa Ziehau struct hn_txdesc *txd = sndc->hn_cbarg; 247915516c77SSepherosa Ziehau struct hn_tx_ring *txr; 248015516c77SSepherosa Ziehau 248115516c77SSepherosa Ziehau txr = txd->txr; 248215516c77SSepherosa Ziehau KASSERT(txr->hn_chan == chan, 248315516c77SSepherosa Ziehau ("channel mismatch, on chan%u, should be chan%u", 2484aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan))); 248515516c77SSepherosa Ziehau 248615516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 248715516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 248815516c77SSepherosa Ziehau 248915516c77SSepherosa Ziehau ++txr->hn_txdone_cnt; 249015516c77SSepherosa Ziehau if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) { 249115516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 249215516c77SSepherosa Ziehau if (txr->hn_oactive) 249315516c77SSepherosa Ziehau hn_txeof(txr); 249415516c77SSepherosa Ziehau } 249515516c77SSepherosa Ziehau } 249615516c77SSepherosa Ziehau 249715516c77SSepherosa Ziehau static void 249815516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr) 249915516c77SSepherosa Ziehau { 250015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 250115516c77SSepherosa Ziehau tcp_lro_flush_all(&rxr->hn_lro); 250215516c77SSepherosa Ziehau #endif 250315516c77SSepherosa Ziehau 250415516c77SSepherosa Ziehau /* 250515516c77SSepherosa Ziehau * NOTE: 250615516c77SSepherosa Ziehau * 'txr' could be NULL, if multiple channels and 250715516c77SSepherosa Ziehau * ifnet.if_start method are enabled. 250815516c77SSepherosa Ziehau */ 250915516c77SSepherosa Ziehau if (txr == NULL || !txr->hn_has_txeof) 251015516c77SSepherosa Ziehau return; 251115516c77SSepherosa Ziehau 251215516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 251315516c77SSepherosa Ziehau hn_txeof(txr); 251415516c77SSepherosa Ziehau } 251515516c77SSepherosa Ziehau 251615516c77SSepherosa Ziehau static __inline uint32_t 251715516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs) 251815516c77SSepherosa Ziehau { 251915516c77SSepherosa Ziehau 252015516c77SSepherosa Ziehau KASSERT(ofs >= sizeof(struct rndis_packet_msg), 252115516c77SSepherosa Ziehau ("invalid RNDIS packet msg offset %u", ofs)); 252215516c77SSepherosa Ziehau return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset)); 252315516c77SSepherosa Ziehau } 252415516c77SSepherosa Ziehau 252515516c77SSepherosa Ziehau static __inline void * 252615516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize, 252715516c77SSepherosa Ziehau size_t pi_dlen, uint32_t pi_type) 252815516c77SSepherosa Ziehau { 252915516c77SSepherosa Ziehau const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen); 253015516c77SSepherosa Ziehau struct rndis_pktinfo *pi; 253115516c77SSepherosa Ziehau 253215516c77SSepherosa Ziehau KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0, 253315516c77SSepherosa Ziehau ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen)); 253415516c77SSepherosa Ziehau 253515516c77SSepherosa Ziehau /* 253615516c77SSepherosa Ziehau * Per-packet-info does not move; it only grows. 253715516c77SSepherosa Ziehau * 253815516c77SSepherosa Ziehau * NOTE: 253915516c77SSepherosa Ziehau * rm_pktinfooffset in this phase counts from the beginning 254015516c77SSepherosa Ziehau * of rndis_packet_msg. 254115516c77SSepherosa Ziehau */ 254215516c77SSepherosa Ziehau KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize, 254315516c77SSepherosa Ziehau ("%u pktinfo overflows RNDIS packet msg", pi_type)); 254415516c77SSepherosa Ziehau pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset + 254515516c77SSepherosa Ziehau pkt->rm_pktinfolen); 254615516c77SSepherosa Ziehau pkt->rm_pktinfolen += pi_size; 254715516c77SSepherosa Ziehau 254815516c77SSepherosa Ziehau pi->rm_size = pi_size; 254915516c77SSepherosa Ziehau pi->rm_type = pi_type; 255015516c77SSepherosa Ziehau pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET; 255115516c77SSepherosa Ziehau 255215516c77SSepherosa Ziehau return (pi->rm_data); 255315516c77SSepherosa Ziehau } 255415516c77SSepherosa Ziehau 2555dc13fee6SSepherosa Ziehau static __inline int 2556dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr) 2557dc13fee6SSepherosa Ziehau { 2558dc13fee6SSepherosa Ziehau struct hn_txdesc *txd; 2559dc13fee6SSepherosa Ziehau struct mbuf *m; 2560dc13fee6SSepherosa Ziehau int error, pkts; 2561dc13fee6SSepherosa Ziehau 2562dc13fee6SSepherosa Ziehau txd = txr->hn_agg_txd; 2563dc13fee6SSepherosa Ziehau KASSERT(txd != NULL, ("no aggregate txdesc")); 2564dc13fee6SSepherosa Ziehau 2565dc13fee6SSepherosa Ziehau /* 2566dc13fee6SSepherosa Ziehau * Since hn_txpkt() will reset this temporary stat, save 2567dc13fee6SSepherosa Ziehau * it now, so that oerrors can be updated properly, if 2568dc13fee6SSepherosa Ziehau * hn_txpkt() ever fails. 2569dc13fee6SSepherosa Ziehau */ 2570dc13fee6SSepherosa Ziehau pkts = txr->hn_stat_pkts; 2571dc13fee6SSepherosa Ziehau 2572dc13fee6SSepherosa Ziehau /* 2573dc13fee6SSepherosa Ziehau * Since txd's mbuf will _not_ be freed upon hn_txpkt() 2574dc13fee6SSepherosa Ziehau * failure, save it for later freeing, if hn_txpkt() ever 2575dc13fee6SSepherosa Ziehau * fails. 2576dc13fee6SSepherosa Ziehau */ 2577dc13fee6SSepherosa Ziehau m = txd->m; 2578dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 2579dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 2580dc13fee6SSepherosa Ziehau /* txd is freed, but m is not. */ 2581dc13fee6SSepherosa Ziehau m_freem(m); 2582dc13fee6SSepherosa Ziehau 2583dc13fee6SSepherosa Ziehau txr->hn_flush_failed++; 2584dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts); 2585dc13fee6SSepherosa Ziehau } 2586dc13fee6SSepherosa Ziehau 2587dc13fee6SSepherosa Ziehau /* Reset all aggregation states. */ 2588dc13fee6SSepherosa Ziehau txr->hn_agg_txd = NULL; 2589dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = 0; 2590dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 2591dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = NULL; 2592dc13fee6SSepherosa Ziehau 2593dc13fee6SSepherosa Ziehau return (error); 2594dc13fee6SSepherosa Ziehau } 2595dc13fee6SSepherosa Ziehau 2596dc13fee6SSepherosa Ziehau static void * 2597dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 2598dc13fee6SSepherosa Ziehau int pktsize) 2599dc13fee6SSepherosa Ziehau { 2600dc13fee6SSepherosa Ziehau void *chim; 2601dc13fee6SSepherosa Ziehau 2602dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 2603dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) { 2604dc13fee6SSepherosa Ziehau struct hn_txdesc *agg_txd = txr->hn_agg_txd; 2605dc13fee6SSepherosa Ziehau struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt; 2606dc13fee6SSepherosa Ziehau int olen; 2607dc13fee6SSepherosa Ziehau 2608dc13fee6SSepherosa Ziehau /* 2609dc13fee6SSepherosa Ziehau * Update the previous RNDIS packet's total length, 2610dc13fee6SSepherosa Ziehau * it can be increased due to the mandatory alignment 2611dc13fee6SSepherosa Ziehau * padding for this RNDIS packet. And update the 2612dc13fee6SSepherosa Ziehau * aggregating txdesc's chimney sending buffer size 2613dc13fee6SSepherosa Ziehau * accordingly. 2614dc13fee6SSepherosa Ziehau * 2615dc13fee6SSepherosa Ziehau * XXX 2616dc13fee6SSepherosa Ziehau * Zero-out the padding, as required by the RNDIS spec. 2617dc13fee6SSepherosa Ziehau */ 2618dc13fee6SSepherosa Ziehau olen = pkt->rm_len; 2619dc13fee6SSepherosa Ziehau pkt->rm_len = roundup2(olen, txr->hn_agg_align); 2620dc13fee6SSepherosa Ziehau agg_txd->chim_size += pkt->rm_len - olen; 2621dc13fee6SSepherosa Ziehau 2622dc13fee6SSepherosa Ziehau /* Link this txdesc to the parent. */ 2623dc13fee6SSepherosa Ziehau hn_txdesc_agg(agg_txd, txd); 2624dc13fee6SSepherosa Ziehau 2625dc13fee6SSepherosa Ziehau chim = (uint8_t *)pkt + pkt->rm_len; 2626dc13fee6SSepherosa Ziehau /* Save the current packet for later fixup. */ 2627dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 2628dc13fee6SSepherosa Ziehau 2629dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft--; 2630dc13fee6SSepherosa Ziehau txr->hn_agg_szleft -= pktsize; 2631dc13fee6SSepherosa Ziehau if (txr->hn_agg_szleft <= 2632dc13fee6SSepherosa Ziehau HN_PKTSIZE_MIN(txr->hn_agg_align)) { 2633dc13fee6SSepherosa Ziehau /* 2634dc13fee6SSepherosa Ziehau * Probably can't aggregate more packets, 2635dc13fee6SSepherosa Ziehau * flush this aggregating txdesc proactively. 2636dc13fee6SSepherosa Ziehau */ 2637dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 2638dc13fee6SSepherosa Ziehau } 2639dc13fee6SSepherosa Ziehau /* Done! */ 2640dc13fee6SSepherosa Ziehau return (chim); 2641dc13fee6SSepherosa Ziehau } 2642dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 2643dc13fee6SSepherosa Ziehau } 2644dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 2645dc13fee6SSepherosa Ziehau 2646dc13fee6SSepherosa Ziehau txr->hn_tx_chimney_tried++; 2647dc13fee6SSepherosa Ziehau txd->chim_index = hn_chim_alloc(txr->hn_sc); 2648dc13fee6SSepherosa Ziehau if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID) 2649dc13fee6SSepherosa Ziehau return (NULL); 2650dc13fee6SSepherosa Ziehau txr->hn_tx_chimney++; 2651dc13fee6SSepherosa Ziehau 2652dc13fee6SSepherosa Ziehau chim = txr->hn_sc->hn_chim + 2653dc13fee6SSepherosa Ziehau (txd->chim_index * txr->hn_sc->hn_chim_szmax); 2654dc13fee6SSepherosa Ziehau 2655dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktmax > 1 && 2656dc13fee6SSepherosa Ziehau txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) { 2657dc13fee6SSepherosa Ziehau txr->hn_agg_txd = txd; 2658dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1; 2659dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize; 2660dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 2661dc13fee6SSepherosa Ziehau } 2662dc13fee6SSepherosa Ziehau return (chim); 2663dc13fee6SSepherosa Ziehau } 2664dc13fee6SSepherosa Ziehau 266515516c77SSepherosa Ziehau /* 266615516c77SSepherosa Ziehau * NOTE: 266715516c77SSepherosa Ziehau * If this function fails, then both txd and m_head0 will be freed. 266815516c77SSepherosa Ziehau */ 266915516c77SSepherosa Ziehau static int 2670dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 2671dc13fee6SSepherosa Ziehau struct mbuf **m_head0) 267215516c77SSepherosa Ziehau { 267315516c77SSepherosa Ziehau bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX]; 267415516c77SSepherosa Ziehau int error, nsegs, i; 267515516c77SSepherosa Ziehau struct mbuf *m_head = *m_head0; 267615516c77SSepherosa Ziehau struct rndis_packet_msg *pkt; 267715516c77SSepherosa Ziehau uint32_t *pi_data; 26788966e5d5SSepherosa Ziehau void *chim = NULL; 2679dc13fee6SSepherosa Ziehau int pkt_hlen, pkt_size; 268015516c77SSepherosa Ziehau 268115516c77SSepherosa Ziehau pkt = txd->rndis_pkt; 2682dc13fee6SSepherosa Ziehau pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align); 2683dc13fee6SSepherosa Ziehau if (pkt_size < txr->hn_chim_size) { 2684dc13fee6SSepherosa Ziehau chim = hn_try_txagg(ifp, txr, txd, pkt_size); 2685dc13fee6SSepherosa Ziehau if (chim != NULL) 26868966e5d5SSepherosa Ziehau pkt = chim; 2687dc13fee6SSepherosa Ziehau } else { 2688dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 2689dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 26908966e5d5SSepherosa Ziehau } 26918966e5d5SSepherosa Ziehau 269215516c77SSepherosa Ziehau pkt->rm_type = REMOTE_NDIS_PACKET_MSG; 26938fe90f73SSepherosa Ziehau pkt->rm_len = m_head->m_pkthdr.len; 26949130c4f7SSepherosa Ziehau pkt->rm_dataoffset = 0; 269515516c77SSepherosa Ziehau pkt->rm_datalen = m_head->m_pkthdr.len; 2696dc13fee6SSepherosa Ziehau pkt->rm_oobdataoffset = 0; 2697dc13fee6SSepherosa Ziehau pkt->rm_oobdatalen = 0; 2698dc13fee6SSepherosa Ziehau pkt->rm_oobdataelements = 0; 269915516c77SSepherosa Ziehau pkt->rm_pktinfooffset = sizeof(*pkt); 270015516c77SSepherosa Ziehau pkt->rm_pktinfolen = 0; 2701dc13fee6SSepherosa Ziehau pkt->rm_vchandle = 0; 2702dc13fee6SSepherosa Ziehau pkt->rm_reserved = 0; 270315516c77SSepherosa Ziehau 270415516c77SSepherosa Ziehau if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) { 270515516c77SSepherosa Ziehau /* 270615516c77SSepherosa Ziehau * Set the hash value for this packet, so that the host could 270715516c77SSepherosa Ziehau * dispatch the TX done event for this packet back to this TX 270815516c77SSepherosa Ziehau * ring's channel. 270915516c77SSepherosa Ziehau */ 271015516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 271115516c77SSepherosa Ziehau HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL); 271215516c77SSepherosa Ziehau *pi_data = txr->hn_tx_idx; 271315516c77SSepherosa Ziehau } 271415516c77SSepherosa Ziehau 271515516c77SSepherosa Ziehau if (m_head->m_flags & M_VLANTAG) { 271615516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 271715516c77SSepherosa Ziehau NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN); 271815516c77SSepherosa Ziehau *pi_data = NDIS_VLAN_INFO_MAKE( 271915516c77SSepherosa Ziehau EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag), 272015516c77SSepherosa Ziehau EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag), 272115516c77SSepherosa Ziehau EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag)); 272215516c77SSepherosa Ziehau } 272315516c77SSepherosa Ziehau 272415516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 272515516c77SSepherosa Ziehau #if defined(INET6) || defined(INET) 272615516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 272715516c77SSepherosa Ziehau NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); 272815516c77SSepherosa Ziehau #ifdef INET 272915516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 273015516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV4(0, 273115516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 273215516c77SSepherosa Ziehau } 273315516c77SSepherosa Ziehau #endif 273415516c77SSepherosa Ziehau #if defined(INET6) && defined(INET) 273515516c77SSepherosa Ziehau else 273615516c77SSepherosa Ziehau #endif 273715516c77SSepherosa Ziehau #ifdef INET6 273815516c77SSepherosa Ziehau { 273915516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV6(0, 274015516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 274115516c77SSepherosa Ziehau } 274215516c77SSepherosa Ziehau #endif 274315516c77SSepherosa Ziehau #endif /* INET6 || INET */ 274415516c77SSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) { 274515516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 274615516c77SSepherosa Ziehau NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); 274715516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & 274815516c77SSepherosa Ziehau (CSUM_IP6_TCP | CSUM_IP6_UDP)) { 274915516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV6; 275015516c77SSepherosa Ziehau } else { 275115516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV4; 275215516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 275315516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_IPCS; 275415516c77SSepherosa Ziehau } 275515516c77SSepherosa Ziehau 275615516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) 275715516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_TCPCS; 275815516c77SSepherosa Ziehau else if (m_head->m_pkthdr.csum_flags & 275915516c77SSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP6_UDP)) 276015516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_UDPCS; 276115516c77SSepherosa Ziehau } 276215516c77SSepherosa Ziehau 2763dc13fee6SSepherosa Ziehau pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; 27648fe90f73SSepherosa Ziehau /* Fixup RNDIS packet message total length */ 27658fe90f73SSepherosa Ziehau pkt->rm_len += pkt_hlen; 276615516c77SSepherosa Ziehau /* Convert RNDIS packet message offsets */ 27679130c4f7SSepherosa Ziehau pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen); 276815516c77SSepherosa Ziehau pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset); 276915516c77SSepherosa Ziehau 277015516c77SSepherosa Ziehau /* 27718966e5d5SSepherosa Ziehau * Fast path: Chimney sending. 277215516c77SSepherosa Ziehau */ 27738966e5d5SSepherosa Ziehau if (chim != NULL) { 2774dc13fee6SSepherosa Ziehau struct hn_txdesc *tgt_txd = txd; 2775dc13fee6SSepherosa Ziehau 2776dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 2777dc13fee6SSepherosa Ziehau tgt_txd = txr->hn_agg_txd; 2778dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 2779dc13fee6SSepherosa Ziehau *m_head0 = NULL; 2780dc13fee6SSepherosa Ziehau #endif 2781dc13fee6SSepherosa Ziehau } 2782dc13fee6SSepherosa Ziehau 2783dc13fee6SSepherosa Ziehau KASSERT(pkt == chim, 2784dc13fee6SSepherosa Ziehau ("RNDIS pkt not in chimney sending buffer")); 2785dc13fee6SSepherosa Ziehau KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID, 2786dc13fee6SSepherosa Ziehau ("chimney sending buffer is not used")); 2787dc13fee6SSepherosa Ziehau tgt_txd->chim_size += pkt->rm_len; 278815516c77SSepherosa Ziehau 27898966e5d5SSepherosa Ziehau m_copydata(m_head, 0, m_head->m_pkthdr.len, 2790dc13fee6SSepherosa Ziehau ((uint8_t *)chim) + pkt_hlen); 279115516c77SSepherosa Ziehau 279215516c77SSepherosa Ziehau txr->hn_gpa_cnt = 0; 279315516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_chim; 279415516c77SSepherosa Ziehau goto done; 279515516c77SSepherosa Ziehau } 2796dc13fee6SSepherosa Ziehau 2797dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc")); 27988966e5d5SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 27998966e5d5SSepherosa Ziehau ("chimney buffer is used")); 28008966e5d5SSepherosa Ziehau KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc")); 280115516c77SSepherosa Ziehau 280215516c77SSepherosa Ziehau error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs); 2803dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 280415516c77SSepherosa Ziehau int freed; 280515516c77SSepherosa Ziehau 280615516c77SSepherosa Ziehau /* 280715516c77SSepherosa Ziehau * This mbuf is not linked w/ the txd yet, so free it now. 280815516c77SSepherosa Ziehau */ 280915516c77SSepherosa Ziehau m_freem(m_head); 281015516c77SSepherosa Ziehau *m_head0 = NULL; 281115516c77SSepherosa Ziehau 281215516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 281315516c77SSepherosa Ziehau KASSERT(freed != 0, 281415516c77SSepherosa Ziehau ("fail to free txd upon txdma error")); 281515516c77SSepherosa Ziehau 281615516c77SSepherosa Ziehau txr->hn_txdma_failed++; 2817dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 281815516c77SSepherosa Ziehau return error; 281915516c77SSepherosa Ziehau } 282015516c77SSepherosa Ziehau *m_head0 = m_head; 282115516c77SSepherosa Ziehau 282215516c77SSepherosa Ziehau /* +1 RNDIS packet message */ 282315516c77SSepherosa Ziehau txr->hn_gpa_cnt = nsegs + 1; 282415516c77SSepherosa Ziehau 282515516c77SSepherosa Ziehau /* send packet with page buffer */ 282615516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr); 282715516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK; 2828dc13fee6SSepherosa Ziehau txr->hn_gpa[0].gpa_len = pkt_hlen; 282915516c77SSepherosa Ziehau 283015516c77SSepherosa Ziehau /* 283115516c77SSepherosa Ziehau * Fill the page buffers with mbuf info after the page 283215516c77SSepherosa Ziehau * buffer for RNDIS packet message. 283315516c77SSepherosa Ziehau */ 283415516c77SSepherosa Ziehau for (i = 0; i < nsegs; ++i) { 283515516c77SSepherosa Ziehau struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1]; 283615516c77SSepherosa Ziehau 283715516c77SSepherosa Ziehau gpa->gpa_page = atop(segs[i].ds_addr); 283815516c77SSepherosa Ziehau gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK; 283915516c77SSepherosa Ziehau gpa->gpa_len = segs[i].ds_len; 284015516c77SSepherosa Ziehau } 284115516c77SSepherosa Ziehau 284215516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 284315516c77SSepherosa Ziehau txd->chim_size = 0; 284415516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_sglist; 284515516c77SSepherosa Ziehau done: 284615516c77SSepherosa Ziehau txd->m = m_head; 284715516c77SSepherosa Ziehau 284815516c77SSepherosa Ziehau /* Set the completion routine */ 284915516c77SSepherosa Ziehau hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd); 285015516c77SSepherosa Ziehau 2851dc13fee6SSepherosa Ziehau /* Update temporary stats for later use. */ 2852dc13fee6SSepherosa Ziehau txr->hn_stat_pkts++; 2853dc13fee6SSepherosa Ziehau txr->hn_stat_size += m_head->m_pkthdr.len; 2854dc13fee6SSepherosa Ziehau if (m_head->m_flags & M_MCAST) 2855dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts++; 2856dc13fee6SSepherosa Ziehau 285715516c77SSepherosa Ziehau return 0; 285815516c77SSepherosa Ziehau } 285915516c77SSepherosa Ziehau 286015516c77SSepherosa Ziehau /* 286115516c77SSepherosa Ziehau * NOTE: 286215516c77SSepherosa Ziehau * If this function fails, then txd will be freed, but the mbuf 286315516c77SSepherosa Ziehau * associated w/ the txd will _not_ be freed. 286415516c77SSepherosa Ziehau */ 286515516c77SSepherosa Ziehau static int 286615516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd) 286715516c77SSepherosa Ziehau { 28688e7d3136SSepherosa Ziehau int error, send_failed = 0, has_bpf; 286915516c77SSepherosa Ziehau 287015516c77SSepherosa Ziehau again: 28718e7d3136SSepherosa Ziehau has_bpf = bpf_peers_present(ifp->if_bpf); 28728e7d3136SSepherosa Ziehau if (has_bpf) { 287315516c77SSepherosa Ziehau /* 28748e7d3136SSepherosa Ziehau * Make sure that this txd and any aggregated txds are not 28758e7d3136SSepherosa Ziehau * freed before ETHER_BPF_MTAP. 287615516c77SSepherosa Ziehau */ 287715516c77SSepherosa Ziehau hn_txdesc_hold(txd); 28788e7d3136SSepherosa Ziehau } 287915516c77SSepherosa Ziehau error = txr->hn_sendpkt(txr, txd); 288015516c77SSepherosa Ziehau if (!error) { 28818e7d3136SSepherosa Ziehau if (has_bpf) { 2882dc13fee6SSepherosa Ziehau const struct hn_txdesc *tmp_txd; 2883dc13fee6SSepherosa Ziehau 288415516c77SSepherosa Ziehau ETHER_BPF_MTAP(ifp, txd->m); 2885dc13fee6SSepherosa Ziehau STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link) 2886dc13fee6SSepherosa Ziehau ETHER_BPF_MTAP(ifp, tmp_txd->m); 2887dc13fee6SSepherosa Ziehau } 2888dc13fee6SSepherosa Ziehau 2889dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts); 289023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 289123bf9e15SSepherosa Ziehau if (!hn_use_if_start) 289223bf9e15SSepherosa Ziehau #endif 289323bf9e15SSepherosa Ziehau { 289415516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, 2895dc13fee6SSepherosa Ziehau txr->hn_stat_size); 2896dc13fee6SSepherosa Ziehau if (txr->hn_stat_mcasts != 0) { 2897dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 2898dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts); 289915516c77SSepherosa Ziehau } 2900dc13fee6SSepherosa Ziehau } 2901dc13fee6SSepherosa Ziehau txr->hn_pkts += txr->hn_stat_pkts; 2902dc13fee6SSepherosa Ziehau txr->hn_sends++; 290315516c77SSepherosa Ziehau } 29048e7d3136SSepherosa Ziehau if (has_bpf) 290515516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 290615516c77SSepherosa Ziehau 290715516c77SSepherosa Ziehau if (__predict_false(error)) { 290815516c77SSepherosa Ziehau int freed; 290915516c77SSepherosa Ziehau 291015516c77SSepherosa Ziehau /* 291115516c77SSepherosa Ziehau * This should "really rarely" happen. 291215516c77SSepherosa Ziehau * 291315516c77SSepherosa Ziehau * XXX Too many RX to be acked or too many sideband 291415516c77SSepherosa Ziehau * commands to run? Ask netvsc_channel_rollup() 291515516c77SSepherosa Ziehau * to kick start later. 291615516c77SSepherosa Ziehau */ 291715516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 291815516c77SSepherosa Ziehau if (!send_failed) { 291915516c77SSepherosa Ziehau txr->hn_send_failed++; 292015516c77SSepherosa Ziehau send_failed = 1; 292115516c77SSepherosa Ziehau /* 292215516c77SSepherosa Ziehau * Try sending again after set hn_has_txeof; 292315516c77SSepherosa Ziehau * in case that we missed the last 292415516c77SSepherosa Ziehau * netvsc_channel_rollup(). 292515516c77SSepherosa Ziehau */ 292615516c77SSepherosa Ziehau goto again; 292715516c77SSepherosa Ziehau } 292815516c77SSepherosa Ziehau if_printf(ifp, "send failed\n"); 292915516c77SSepherosa Ziehau 293015516c77SSepherosa Ziehau /* 293115516c77SSepherosa Ziehau * Caller will perform further processing on the 293215516c77SSepherosa Ziehau * associated mbuf, so don't free it in hn_txdesc_put(); 293315516c77SSepherosa Ziehau * only unload it from the DMA map in hn_txdesc_put(), 293415516c77SSepherosa Ziehau * if it was loaded. 293515516c77SSepherosa Ziehau */ 293615516c77SSepherosa Ziehau txd->m = NULL; 293715516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 293815516c77SSepherosa Ziehau KASSERT(freed != 0, 293915516c77SSepherosa Ziehau ("fail to free txd upon send error")); 294015516c77SSepherosa Ziehau 294115516c77SSepherosa Ziehau txr->hn_send_failed++; 294215516c77SSepherosa Ziehau } 2943dc13fee6SSepherosa Ziehau 2944dc13fee6SSepherosa Ziehau /* Reset temporary stats, after this sending is done. */ 2945dc13fee6SSepherosa Ziehau txr->hn_stat_size = 0; 2946dc13fee6SSepherosa Ziehau txr->hn_stat_pkts = 0; 2947dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts = 0; 2948dc13fee6SSepherosa Ziehau 2949dc13fee6SSepherosa Ziehau return (error); 295015516c77SSepherosa Ziehau } 295115516c77SSepherosa Ziehau 295215516c77SSepherosa Ziehau /* 295315516c77SSepherosa Ziehau * Append the specified data to the indicated mbuf chain, 295415516c77SSepherosa Ziehau * Extend the mbuf chain if the new data does not fit in 295515516c77SSepherosa Ziehau * existing space. 295615516c77SSepherosa Ziehau * 295715516c77SSepherosa Ziehau * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c. 295815516c77SSepherosa Ziehau * There should be an equivalent in the kernel mbuf code, 295915516c77SSepherosa Ziehau * but there does not appear to be one yet. 296015516c77SSepherosa Ziehau * 296115516c77SSepherosa Ziehau * Differs from m_append() in that additional mbufs are 296215516c77SSepherosa Ziehau * allocated with cluster size MJUMPAGESIZE, and filled 296315516c77SSepherosa Ziehau * accordingly. 296415516c77SSepherosa Ziehau * 296515516c77SSepherosa Ziehau * Return 1 if able to complete the job; otherwise 0. 296615516c77SSepherosa Ziehau */ 296715516c77SSepherosa Ziehau static int 296815516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp) 296915516c77SSepherosa Ziehau { 297015516c77SSepherosa Ziehau struct mbuf *m, *n; 297115516c77SSepherosa Ziehau int remainder, space; 297215516c77SSepherosa Ziehau 297315516c77SSepherosa Ziehau for (m = m0; m->m_next != NULL; m = m->m_next) 297415516c77SSepherosa Ziehau ; 297515516c77SSepherosa Ziehau remainder = len; 297615516c77SSepherosa Ziehau space = M_TRAILINGSPACE(m); 297715516c77SSepherosa Ziehau if (space > 0) { 297815516c77SSepherosa Ziehau /* 297915516c77SSepherosa Ziehau * Copy into available space. 298015516c77SSepherosa Ziehau */ 298115516c77SSepherosa Ziehau if (space > remainder) 298215516c77SSepherosa Ziehau space = remainder; 298315516c77SSepherosa Ziehau bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 298415516c77SSepherosa Ziehau m->m_len += space; 298515516c77SSepherosa Ziehau cp += space; 298615516c77SSepherosa Ziehau remainder -= space; 298715516c77SSepherosa Ziehau } 298815516c77SSepherosa Ziehau while (remainder > 0) { 298915516c77SSepherosa Ziehau /* 299015516c77SSepherosa Ziehau * Allocate a new mbuf; could check space 299115516c77SSepherosa Ziehau * and allocate a cluster instead. 299215516c77SSepherosa Ziehau */ 299315516c77SSepherosa Ziehau n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE); 299415516c77SSepherosa Ziehau if (n == NULL) 299515516c77SSepherosa Ziehau break; 299615516c77SSepherosa Ziehau n->m_len = min(MJUMPAGESIZE, remainder); 299715516c77SSepherosa Ziehau bcopy(cp, mtod(n, caddr_t), n->m_len); 299815516c77SSepherosa Ziehau cp += n->m_len; 299915516c77SSepherosa Ziehau remainder -= n->m_len; 300015516c77SSepherosa Ziehau m->m_next = n; 300115516c77SSepherosa Ziehau m = n; 300215516c77SSepherosa Ziehau } 300315516c77SSepherosa Ziehau if (m0->m_flags & M_PKTHDR) 300415516c77SSepherosa Ziehau m0->m_pkthdr.len += len - remainder; 300515516c77SSepherosa Ziehau 300615516c77SSepherosa Ziehau return (remainder == 0); 300715516c77SSepherosa Ziehau } 300815516c77SSepherosa Ziehau 300915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 301015516c77SSepherosa Ziehau static __inline int 301115516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m) 301215516c77SSepherosa Ziehau { 301315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 301415516c77SSepherosa Ziehau if (hn_lro_mbufq_depth) { 301515516c77SSepherosa Ziehau tcp_lro_queue_mbuf(lc, m); 301615516c77SSepherosa Ziehau return 0; 301715516c77SSepherosa Ziehau } 301815516c77SSepherosa Ziehau #endif 301915516c77SSepherosa Ziehau return tcp_lro_rx(lc, m, 0); 302015516c77SSepherosa Ziehau } 302115516c77SSepherosa Ziehau #endif 302215516c77SSepherosa Ziehau 302315516c77SSepherosa Ziehau static int 302415516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, 302515516c77SSepherosa Ziehau const struct hn_rxinfo *info) 302615516c77SSepherosa Ziehau { 3027a97fff19SSepherosa Ziehau struct ifnet *ifp, *hn_ifp = rxr->hn_ifp; 302815516c77SSepherosa Ziehau struct mbuf *m_new; 302915516c77SSepherosa Ziehau int size, do_lro = 0, do_csum = 1; 303015516c77SSepherosa Ziehau int hash_type; 303115516c77SSepherosa Ziehau 3032a97fff19SSepherosa Ziehau /* 3033a97fff19SSepherosa Ziehau * If the non-transparent mode VF is active, inject this packet 3034a97fff19SSepherosa Ziehau * into the VF. 3035a97fff19SSepherosa Ziehau */ 3036a97fff19SSepherosa Ziehau ifp = rxr->hn_rxvf_ifp ? rxr->hn_rxvf_ifp : hn_ifp; 30375bdfd3fdSDexuan Cui 3038b3b75d9cSSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 3039b3b75d9cSSepherosa Ziehau /* 3040b3b75d9cSSepherosa Ziehau * NOTE: 3041b3b75d9cSSepherosa Ziehau * See the NOTE of hn_rndis_init_fixat(). This 3042b3b75d9cSSepherosa Ziehau * function can be reached, immediately after the 3043b3b75d9cSSepherosa Ziehau * RNDIS is initialized but before the ifnet is 3044b3b75d9cSSepherosa Ziehau * setup on the hn_attach() path; drop the unexpected 3045b3b75d9cSSepherosa Ziehau * packets. 3046b3b75d9cSSepherosa Ziehau */ 3047b3b75d9cSSepherosa Ziehau return (0); 3048b3b75d9cSSepherosa Ziehau } 3049b3b75d9cSSepherosa Ziehau 3050a97fff19SSepherosa Ziehau if (__predict_false(dlen < ETHER_HDR_LEN)) { 3051a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1); 3052a97fff19SSepherosa Ziehau return (0); 3053a97fff19SSepherosa Ziehau } 3054a97fff19SSepherosa Ziehau 3055c927d681SDexuan Cui if (dlen <= MHLEN) { 305615516c77SSepherosa Ziehau m_new = m_gethdr(M_NOWAIT, MT_DATA); 305715516c77SSepherosa Ziehau if (m_new == NULL) { 3058a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1); 305915516c77SSepherosa Ziehau return (0); 306015516c77SSepherosa Ziehau } 306115516c77SSepherosa Ziehau memcpy(mtod(m_new, void *), data, dlen); 306215516c77SSepherosa Ziehau m_new->m_pkthdr.len = m_new->m_len = dlen; 306315516c77SSepherosa Ziehau rxr->hn_small_pkts++; 306415516c77SSepherosa Ziehau } else { 306515516c77SSepherosa Ziehau /* 306615516c77SSepherosa Ziehau * Get an mbuf with a cluster. For packets 2K or less, 306715516c77SSepherosa Ziehau * get a standard 2K cluster. For anything larger, get a 306815516c77SSepherosa Ziehau * 4K cluster. Any buffers larger than 4K can cause problems 306915516c77SSepherosa Ziehau * if looped around to the Hyper-V TX channel, so avoid them. 307015516c77SSepherosa Ziehau */ 307115516c77SSepherosa Ziehau size = MCLBYTES; 307215516c77SSepherosa Ziehau if (dlen > MCLBYTES) { 307315516c77SSepherosa Ziehau /* 4096 */ 307415516c77SSepherosa Ziehau size = MJUMPAGESIZE; 307515516c77SSepherosa Ziehau } 307615516c77SSepherosa Ziehau 307715516c77SSepherosa Ziehau m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size); 307815516c77SSepherosa Ziehau if (m_new == NULL) { 3079a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1); 308015516c77SSepherosa Ziehau return (0); 308115516c77SSepherosa Ziehau } 308215516c77SSepherosa Ziehau 308315516c77SSepherosa Ziehau hv_m_append(m_new, dlen, data); 308415516c77SSepherosa Ziehau } 308515516c77SSepherosa Ziehau m_new->m_pkthdr.rcvif = ifp; 308615516c77SSepherosa Ziehau 3087a97fff19SSepherosa Ziehau if (__predict_false((hn_ifp->if_capenable & IFCAP_RXCSUM) == 0)) 308815516c77SSepherosa Ziehau do_csum = 0; 308915516c77SSepherosa Ziehau 309015516c77SSepherosa Ziehau /* receive side checksum offload */ 309115516c77SSepherosa Ziehau if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) { 309215516c77SSepherosa Ziehau /* IP csum offload */ 309315516c77SSepherosa Ziehau if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) { 309415516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 309515516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 309615516c77SSepherosa Ziehau rxr->hn_csum_ip++; 309715516c77SSepherosa Ziehau } 309815516c77SSepherosa Ziehau 309915516c77SSepherosa Ziehau /* TCP/UDP csum offload */ 310015516c77SSepherosa Ziehau if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK | 310115516c77SSepherosa Ziehau NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) { 310215516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 310315516c77SSepherosa Ziehau (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 310415516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 310515516c77SSepherosa Ziehau if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK) 310615516c77SSepherosa Ziehau rxr->hn_csum_tcp++; 310715516c77SSepherosa Ziehau else 310815516c77SSepherosa Ziehau rxr->hn_csum_udp++; 310915516c77SSepherosa Ziehau } 311015516c77SSepherosa Ziehau 311115516c77SSepherosa Ziehau /* 311215516c77SSepherosa Ziehau * XXX 311315516c77SSepherosa Ziehau * As of this write (Oct 28th, 2016), host side will turn 311415516c77SSepherosa Ziehau * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so 311515516c77SSepherosa Ziehau * the do_lro setting here is actually _not_ accurate. We 311615516c77SSepherosa Ziehau * depend on the RSS hash type check to reset do_lro. 311715516c77SSepherosa Ziehau */ 311815516c77SSepherosa Ziehau if ((info->csum_info & 311915516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) == 312015516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) 312115516c77SSepherosa Ziehau do_lro = 1; 312215516c77SSepherosa Ziehau } else { 312315516c77SSepherosa Ziehau const struct ether_header *eh; 312415516c77SSepherosa Ziehau uint16_t etype; 312515516c77SSepherosa Ziehau int hoff; 312615516c77SSepherosa Ziehau 312715516c77SSepherosa Ziehau hoff = sizeof(*eh); 3128a97fff19SSepherosa Ziehau /* Checked at the beginning of this function. */ 3129a97fff19SSepherosa Ziehau KASSERT(m_new->m_len >= hoff, ("not ethernet frame")); 3130a97fff19SSepherosa Ziehau 313115516c77SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 313215516c77SSepherosa Ziehau etype = ntohs(eh->ether_type); 313315516c77SSepherosa Ziehau if (etype == ETHERTYPE_VLAN) { 313415516c77SSepherosa Ziehau const struct ether_vlan_header *evl; 313515516c77SSepherosa Ziehau 313615516c77SSepherosa Ziehau hoff = sizeof(*evl); 313715516c77SSepherosa Ziehau if (m_new->m_len < hoff) 313815516c77SSepherosa Ziehau goto skip; 313915516c77SSepherosa Ziehau evl = mtod(m_new, struct ether_vlan_header *); 314015516c77SSepherosa Ziehau etype = ntohs(evl->evl_proto); 314115516c77SSepherosa Ziehau } 314215516c77SSepherosa Ziehau 314315516c77SSepherosa Ziehau if (etype == ETHERTYPE_IP) { 314415516c77SSepherosa Ziehau int pr; 314515516c77SSepherosa Ziehau 314615516c77SSepherosa Ziehau pr = hn_check_iplen(m_new, hoff); 314715516c77SSepherosa Ziehau if (pr == IPPROTO_TCP) { 314815516c77SSepherosa Ziehau if (do_csum && 314915516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 315015516c77SSepherosa Ziehau HN_TRUST_HCSUM_TCP)) { 315115516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 315215516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 315315516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 315415516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 315515516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 315615516c77SSepherosa Ziehau } 315715516c77SSepherosa Ziehau do_lro = 1; 315815516c77SSepherosa Ziehau } else if (pr == IPPROTO_UDP) { 315915516c77SSepherosa Ziehau if (do_csum && 316015516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 316115516c77SSepherosa Ziehau HN_TRUST_HCSUM_UDP)) { 316215516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 316315516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 316415516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 316515516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 316615516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 316715516c77SSepherosa Ziehau } 316815516c77SSepherosa Ziehau } else if (pr != IPPROTO_DONE && do_csum && 316915516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) { 317015516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 317115516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 317215516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 317315516c77SSepherosa Ziehau } 317415516c77SSepherosa Ziehau } 317515516c77SSepherosa Ziehau } 317615516c77SSepherosa Ziehau skip: 317715516c77SSepherosa Ziehau if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) { 317815516c77SSepherosa Ziehau m_new->m_pkthdr.ether_vtag = EVL_MAKETAG( 317915516c77SSepherosa Ziehau NDIS_VLAN_INFO_ID(info->vlan_info), 318015516c77SSepherosa Ziehau NDIS_VLAN_INFO_PRI(info->vlan_info), 318115516c77SSepherosa Ziehau NDIS_VLAN_INFO_CFI(info->vlan_info)); 318215516c77SSepherosa Ziehau m_new->m_flags |= M_VLANTAG; 318315516c77SSepherosa Ziehau } 318415516c77SSepherosa Ziehau 3185a97fff19SSepherosa Ziehau /* 3186a97fff19SSepherosa Ziehau * If VF is activated (tranparent/non-transparent mode does not 3187a97fff19SSepherosa Ziehau * matter here). 3188a97fff19SSepherosa Ziehau * 3189a97fff19SSepherosa Ziehau * - Don't setup mbuf hash, if 'options RSS' is set. 3190a97fff19SSepherosa Ziehau * 3191a97fff19SSepherosa Ziehau * In Azure, when VF is activated, TCP SYN and SYN|ACK go 3192a97fff19SSepherosa Ziehau * through hn(4) while the rest of segments and ACKs belonging 3193a97fff19SSepherosa Ziehau * to the same TCP 4-tuple go through the VF. So don't setup 3194a97fff19SSepherosa Ziehau * mbuf hash, if a VF is activated and 'options RSS' is not 3195a97fff19SSepherosa Ziehau * enabled. hn(4) and the VF may use neither the same RSS 3196a97fff19SSepherosa Ziehau * hash key nor the same RSS hash function, so the hash value 3197a97fff19SSepherosa Ziehau * for packets belonging to the same flow could be different! 3198a97fff19SSepherosa Ziehau * 3199a97fff19SSepherosa Ziehau * - Disable LRO 3200a97fff19SSepherosa Ziehau * 3201a97fff19SSepherosa Ziehau * hn(4) will only receive broadcast packets, multicast packets, 3202a97fff19SSepherosa Ziehau * TCP SYN and SYN|ACK (in Azure), LRO is useless for these 3203a97fff19SSepherosa Ziehau * packet types. 3204a97fff19SSepherosa Ziehau * 3205a97fff19SSepherosa Ziehau * For non-transparent, we definitely _cannot_ enable LRO at 3206a97fff19SSepherosa Ziehau * all, since the LRO flush will use hn(4) as the receiving 3207a97fff19SSepherosa Ziehau * interface; i.e. hn_ifp->if_input(hn_ifp, m). 3208a97fff19SSepherosa Ziehau */ 3209a97fff19SSepherosa Ziehau if (hn_ifp != ifp || (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF)) { 3210a97fff19SSepherosa Ziehau do_lro = 0; /* disable LRO. */ 3211a97fff19SSepherosa Ziehau #ifndef RSS 3212a97fff19SSepherosa Ziehau goto skip_hash; /* skip mbuf hash setup */ 3213a97fff19SSepherosa Ziehau #endif 3214a97fff19SSepherosa Ziehau } 3215a97fff19SSepherosa Ziehau 321615516c77SSepherosa Ziehau if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) { 321715516c77SSepherosa Ziehau rxr->hn_rss_pkts++; 321815516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = info->hash_value; 321915516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE_HASH; 322015516c77SSepherosa Ziehau if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) == 322115516c77SSepherosa Ziehau NDIS_HASH_FUNCTION_TOEPLITZ) { 322215516c77SSepherosa Ziehau uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK); 322315516c77SSepherosa Ziehau 322415516c77SSepherosa Ziehau /* 322515516c77SSepherosa Ziehau * NOTE: 322615516c77SSepherosa Ziehau * do_lro is resetted, if the hash types are not TCP 322715516c77SSepherosa Ziehau * related. See the comment in the above csum_flags 322815516c77SSepherosa Ziehau * setup section. 322915516c77SSepherosa Ziehau */ 323015516c77SSepherosa Ziehau switch (type) { 323115516c77SSepherosa Ziehau case NDIS_HASH_IPV4: 323215516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV4; 323315516c77SSepherosa Ziehau do_lro = 0; 323415516c77SSepherosa Ziehau break; 323515516c77SSepherosa Ziehau 323615516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV4: 323715516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV4; 323815516c77SSepherosa Ziehau break; 323915516c77SSepherosa Ziehau 324015516c77SSepherosa Ziehau case NDIS_HASH_IPV6: 324115516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6; 324215516c77SSepherosa Ziehau do_lro = 0; 324315516c77SSepherosa Ziehau break; 324415516c77SSepherosa Ziehau 324515516c77SSepherosa Ziehau case NDIS_HASH_IPV6_EX: 324615516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6_EX; 324715516c77SSepherosa Ziehau do_lro = 0; 324815516c77SSepherosa Ziehau break; 324915516c77SSepherosa Ziehau 325015516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6: 325115516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6; 325215516c77SSepherosa Ziehau break; 325315516c77SSepherosa Ziehau 325415516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6_EX: 325515516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX; 325615516c77SSepherosa Ziehau break; 325715516c77SSepherosa Ziehau } 325815516c77SSepherosa Ziehau } 325915516c77SSepherosa Ziehau } else { 326015516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = rxr->hn_rx_idx; 326115516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE; 326215516c77SSepherosa Ziehau } 326315516c77SSepherosa Ziehau M_HASHTYPE_SET(m_new, hash_type); 326415516c77SSepherosa Ziehau 3265a97fff19SSepherosa Ziehau #ifndef RSS 3266a97fff19SSepherosa Ziehau skip_hash: 3267a97fff19SSepherosa Ziehau #endif 3268a97fff19SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 3269a97fff19SSepherosa Ziehau if (hn_ifp != ifp) { 3270a97fff19SSepherosa Ziehau const struct ether_header *eh; 3271a97fff19SSepherosa Ziehau 327215516c77SSepherosa Ziehau /* 3273a97fff19SSepherosa Ziehau * Non-transparent mode VF is activated. 327415516c77SSepherosa Ziehau */ 327515516c77SSepherosa Ziehau 3276a97fff19SSepherosa Ziehau /* 3277a97fff19SSepherosa Ziehau * Allow tapping on hn(4). 3278a97fff19SSepherosa Ziehau */ 3279a97fff19SSepherosa Ziehau ETHER_BPF_MTAP(hn_ifp, m_new); 3280a97fff19SSepherosa Ziehau 3281a97fff19SSepherosa Ziehau /* 3282a97fff19SSepherosa Ziehau * Update hn(4)'s stats. 3283a97fff19SSepherosa Ziehau */ 3284a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1); 3285a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len); 3286a97fff19SSepherosa Ziehau /* Checked at the beginning of this function. */ 3287a97fff19SSepherosa Ziehau KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame")); 3288a97fff19SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 3289a97fff19SSepherosa Ziehau if (ETHER_IS_MULTICAST(eh->ether_dhost)) 3290a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1); 3291a97fff19SSepherosa Ziehau } 329215516c77SSepherosa Ziehau rxr->hn_pkts++; 329315516c77SSepherosa Ziehau 3294a97fff19SSepherosa Ziehau if ((hn_ifp->if_capenable & IFCAP_LRO) && do_lro) { 329515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 329615516c77SSepherosa Ziehau struct lro_ctrl *lro = &rxr->hn_lro; 329715516c77SSepherosa Ziehau 329815516c77SSepherosa Ziehau if (lro->lro_cnt) { 329915516c77SSepherosa Ziehau rxr->hn_lro_tried++; 330015516c77SSepherosa Ziehau if (hn_lro_rx(lro, m_new) == 0) { 330115516c77SSepherosa Ziehau /* DONE! */ 330215516c77SSepherosa Ziehau return 0; 330315516c77SSepherosa Ziehau } 330415516c77SSepherosa Ziehau } 330515516c77SSepherosa Ziehau #endif 330615516c77SSepherosa Ziehau } 3307a97fff19SSepherosa Ziehau ifp->if_input(ifp, m_new); 330815516c77SSepherosa Ziehau 330915516c77SSepherosa Ziehau return (0); 331015516c77SSepherosa Ziehau } 331115516c77SSepherosa Ziehau 331215516c77SSepherosa Ziehau static int 331315516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 331415516c77SSepherosa Ziehau { 331515516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 33169c6cae24SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data, ifr_vf; 33179c6cae24SSepherosa Ziehau struct ifnet *vf_ifp; 331815516c77SSepherosa Ziehau int mask, error = 0; 3319*8c068aa5SSepherosa Ziehau struct ifrsskey *ifrk; 3320*8c068aa5SSepherosa Ziehau struct ifrsshash *ifrh; 332115516c77SSepherosa Ziehau 332215516c77SSepherosa Ziehau switch (cmd) { 332315516c77SSepherosa Ziehau case SIOCSIFMTU: 332415516c77SSepherosa Ziehau if (ifr->ifr_mtu > HN_MTU_MAX) { 332515516c77SSepherosa Ziehau error = EINVAL; 332615516c77SSepherosa Ziehau break; 332715516c77SSepherosa Ziehau } 332815516c77SSepherosa Ziehau 332915516c77SSepherosa Ziehau HN_LOCK(sc); 333015516c77SSepherosa Ziehau 333115516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 333215516c77SSepherosa Ziehau HN_UNLOCK(sc); 333315516c77SSepherosa Ziehau break; 333415516c77SSepherosa Ziehau } 333515516c77SSepherosa Ziehau 333615516c77SSepherosa Ziehau if ((sc->hn_caps & HN_CAP_MTU) == 0) { 333715516c77SSepherosa Ziehau /* Can't change MTU */ 333815516c77SSepherosa Ziehau HN_UNLOCK(sc); 333915516c77SSepherosa Ziehau error = EOPNOTSUPP; 334015516c77SSepherosa Ziehau break; 334115516c77SSepherosa Ziehau } 334215516c77SSepherosa Ziehau 334315516c77SSepherosa Ziehau if (ifp->if_mtu == ifr->ifr_mtu) { 334415516c77SSepherosa Ziehau HN_UNLOCK(sc); 334515516c77SSepherosa Ziehau break; 334615516c77SSepherosa Ziehau } 334715516c77SSepherosa Ziehau 33489c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 33499c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 33509c6cae24SSepherosa Ziehau ifr_vf = *ifr; 33519c6cae24SSepherosa Ziehau strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname, 33529c6cae24SSepherosa Ziehau sizeof(ifr_vf.ifr_name)); 33539c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, 33549c6cae24SSepherosa Ziehau (caddr_t)&ifr_vf); 33559c6cae24SSepherosa Ziehau if (error) { 33569c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 33579c6cae24SSepherosa Ziehau if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n", 33589c6cae24SSepherosa Ziehau vf_ifp->if_xname, ifr->ifr_mtu, error); 33599c6cae24SSepherosa Ziehau break; 33609c6cae24SSepherosa Ziehau } 33619c6cae24SSepherosa Ziehau } 33629c6cae24SSepherosa Ziehau 336315516c77SSepherosa Ziehau /* 336415516c77SSepherosa Ziehau * Suspend this interface before the synthetic parts 336515516c77SSepherosa Ziehau * are ripped. 336615516c77SSepherosa Ziehau */ 336715516c77SSepherosa Ziehau hn_suspend(sc); 336815516c77SSepherosa Ziehau 336915516c77SSepherosa Ziehau /* 337015516c77SSepherosa Ziehau * Detach the synthetics parts, i.e. NVS and RNDIS. 337115516c77SSepherosa Ziehau */ 337215516c77SSepherosa Ziehau hn_synth_detach(sc); 337315516c77SSepherosa Ziehau 337415516c77SSepherosa Ziehau /* 337515516c77SSepherosa Ziehau * Reattach the synthetic parts, i.e. NVS and RNDIS, 337615516c77SSepherosa Ziehau * with the new MTU setting. 337715516c77SSepherosa Ziehau */ 337815516c77SSepherosa Ziehau error = hn_synth_attach(sc, ifr->ifr_mtu); 337915516c77SSepherosa Ziehau if (error) { 338015516c77SSepherosa Ziehau HN_UNLOCK(sc); 338115516c77SSepherosa Ziehau break; 338215516c77SSepherosa Ziehau } 338315516c77SSepherosa Ziehau 338415516c77SSepherosa Ziehau /* 338515516c77SSepherosa Ziehau * Commit the requested MTU, after the synthetic parts 338615516c77SSepherosa Ziehau * have been successfully attached. 338715516c77SSepherosa Ziehau */ 338815516c77SSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 338915516c77SSepherosa Ziehau 339015516c77SSepherosa Ziehau /* 33919c6cae24SSepherosa Ziehau * Synthetic parts' reattach may change the chimney 33929c6cae24SSepherosa Ziehau * sending size; update it. 339315516c77SSepherosa Ziehau */ 339415516c77SSepherosa Ziehau if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax) 339515516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 33969c6cae24SSepherosa Ziehau 33979c6cae24SSepherosa Ziehau /* 33989c6cae24SSepherosa Ziehau * Make sure that various parameters based on MTU are 33999c6cae24SSepherosa Ziehau * still valid, after the MTU change. 34009c6cae24SSepherosa Ziehau */ 34019c6cae24SSepherosa Ziehau hn_mtu_change_fixup(sc); 340215516c77SSepherosa Ziehau 340315516c77SSepherosa Ziehau /* 340415516c77SSepherosa Ziehau * All done! Resume the interface now. 340515516c77SSepherosa Ziehau */ 340615516c77SSepherosa Ziehau hn_resume(sc); 340715516c77SSepherosa Ziehau 3408d0cd8231SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) || 3409d0cd8231SSepherosa Ziehau (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { 34109c6cae24SSepherosa Ziehau /* 34119c6cae24SSepherosa Ziehau * Since we have reattached the NVS part, 34129c6cae24SSepherosa Ziehau * change the datapath to VF again; in case 34139c6cae24SSepherosa Ziehau * that it is lost, after the NVS was detached. 34149c6cae24SSepherosa Ziehau */ 34159c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF); 34169c6cae24SSepherosa Ziehau } 34179c6cae24SSepherosa Ziehau 341815516c77SSepherosa Ziehau HN_UNLOCK(sc); 341915516c77SSepherosa Ziehau break; 342015516c77SSepherosa Ziehau 342115516c77SSepherosa Ziehau case SIOCSIFFLAGS: 342215516c77SSepherosa Ziehau HN_LOCK(sc); 342315516c77SSepherosa Ziehau 342415516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 342515516c77SSepherosa Ziehau HN_UNLOCK(sc); 342615516c77SSepherosa Ziehau break; 342715516c77SSepherosa Ziehau } 342815516c77SSepherosa Ziehau 34299c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) 34309c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 34319c6cae24SSepherosa Ziehau 343215516c77SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 3433fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3434fdc4f478SSepherosa Ziehau /* 3435fdc4f478SSepherosa Ziehau * Caller meight hold mutex, e.g. 3436fdc4f478SSepherosa Ziehau * bpf; use busy-wait for the RNDIS 3437fdc4f478SSepherosa Ziehau * reply. 3438fdc4f478SSepherosa Ziehau */ 3439fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 3440c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 3441fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 34429c6cae24SSepherosa Ziehau 34439c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 34449c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 3445fdc4f478SSepherosa Ziehau } else { 344615516c77SSepherosa Ziehau hn_init_locked(sc); 3447fdc4f478SSepherosa Ziehau } 344815516c77SSepherosa Ziehau } else { 344915516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 34505bdfd3fdSDexuan Cui hn_stop(sc, false); 345115516c77SSepherosa Ziehau } 345215516c77SSepherosa Ziehau sc->hn_if_flags = ifp->if_flags; 345315516c77SSepherosa Ziehau 345415516c77SSepherosa Ziehau HN_UNLOCK(sc); 345515516c77SSepherosa Ziehau break; 345615516c77SSepherosa Ziehau 345715516c77SSepherosa Ziehau case SIOCSIFCAP: 345815516c77SSepherosa Ziehau HN_LOCK(sc); 34599c6cae24SSepherosa Ziehau 34609c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 34619c6cae24SSepherosa Ziehau ifr_vf = *ifr; 34629c6cae24SSepherosa Ziehau strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname, 34639c6cae24SSepherosa Ziehau sizeof(ifr_vf.ifr_name)); 34649c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf); 34659c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 34669c6cae24SSepherosa Ziehau break; 34679c6cae24SSepherosa Ziehau } 34689c6cae24SSepherosa Ziehau 34699c6cae24SSepherosa Ziehau /* 34709c6cae24SSepherosa Ziehau * Fix up requested capabilities w/ supported capabilities, 34719c6cae24SSepherosa Ziehau * since the supported capabilities could have been changed. 34729c6cae24SSepherosa Ziehau */ 34739c6cae24SSepherosa Ziehau mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^ 34749c6cae24SSepherosa Ziehau ifp->if_capenable; 347515516c77SSepherosa Ziehau 347615516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM) { 347715516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 347815516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 347915516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc); 348015516c77SSepherosa Ziehau else 348115516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc); 348215516c77SSepherosa Ziehau } 348315516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM_IPV6) { 348415516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 348515516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 348615516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc); 348715516c77SSepherosa Ziehau else 348815516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc); 348915516c77SSepherosa Ziehau } 349015516c77SSepherosa Ziehau 349115516c77SSepherosa Ziehau /* TODO: flip RNDIS offload parameters for RXCSUM. */ 349215516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 349315516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 349415516c77SSepherosa Ziehau #ifdef foo 349515516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 349615516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM_IPV6) 349715516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 349815516c77SSepherosa Ziehau #endif 349915516c77SSepherosa Ziehau 350015516c77SSepherosa Ziehau if (mask & IFCAP_LRO) 350115516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_LRO; 350215516c77SSepherosa Ziehau 350315516c77SSepherosa Ziehau if (mask & IFCAP_TSO4) { 350415516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO4; 350515516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 350615516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 350715516c77SSepherosa Ziehau else 350815516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP_TSO; 350915516c77SSepherosa Ziehau } 351015516c77SSepherosa Ziehau if (mask & IFCAP_TSO6) { 351115516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO6; 351215516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 351315516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 351415516c77SSepherosa Ziehau else 351515516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP6_TSO; 351615516c77SSepherosa Ziehau } 351715516c77SSepherosa Ziehau 351815516c77SSepherosa Ziehau HN_UNLOCK(sc); 351915516c77SSepherosa Ziehau break; 352015516c77SSepherosa Ziehau 352115516c77SSepherosa Ziehau case SIOCADDMULTI: 352215516c77SSepherosa Ziehau case SIOCDELMULTI: 352315516c77SSepherosa Ziehau HN_LOCK(sc); 352415516c77SSepherosa Ziehau 352515516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 352615516c77SSepherosa Ziehau HN_UNLOCK(sc); 352715516c77SSepherosa Ziehau break; 352815516c77SSepherosa Ziehau } 3529fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3530fdc4f478SSepherosa Ziehau /* 3531fdc4f478SSepherosa Ziehau * Multicast uses mutex; use busy-wait for 3532fdc4f478SSepherosa Ziehau * the RNDIS reply. 3533fdc4f478SSepherosa Ziehau */ 3534fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 3535c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 3536fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 3537fdc4f478SSepherosa Ziehau } 353815516c77SSepherosa Ziehau 35399c6cae24SSepherosa Ziehau /* XXX vlan(4) style mcast addr maintenance */ 35409c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 35419c6cae24SSepherosa Ziehau int old_if_flags; 35429c6cae24SSepherosa Ziehau 35439c6cae24SSepherosa Ziehau old_if_flags = sc->hn_vf_ifp->if_flags; 35449c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 35459c6cae24SSepherosa Ziehau 35469c6cae24SSepherosa Ziehau if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) && 35479c6cae24SSepherosa Ziehau ((old_if_flags ^ sc->hn_vf_ifp->if_flags) & 35489c6cae24SSepherosa Ziehau IFF_ALLMULTI)) 35499c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 35509c6cae24SSepherosa Ziehau } 35519c6cae24SSepherosa Ziehau 355215516c77SSepherosa Ziehau HN_UNLOCK(sc); 355315516c77SSepherosa Ziehau break; 355415516c77SSepherosa Ziehau 355515516c77SSepherosa Ziehau case SIOCSIFMEDIA: 355615516c77SSepherosa Ziehau case SIOCGIFMEDIA: 35579c6cae24SSepherosa Ziehau HN_LOCK(sc); 35589c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 35599c6cae24SSepherosa Ziehau /* 35609c6cae24SSepherosa Ziehau * SIOCGIFMEDIA expects ifmediareq, so don't 35619c6cae24SSepherosa Ziehau * create and pass ifr_vf to the VF here; just 35629c6cae24SSepherosa Ziehau * replace the ifr_name. 35639c6cae24SSepherosa Ziehau */ 35649c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 35659c6cae24SSepherosa Ziehau strlcpy(ifr->ifr_name, vf_ifp->if_xname, 35669c6cae24SSepherosa Ziehau sizeof(ifr->ifr_name)); 35679c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, cmd, data); 35689c6cae24SSepherosa Ziehau /* Restore the ifr_name. */ 35699c6cae24SSepherosa Ziehau strlcpy(ifr->ifr_name, ifp->if_xname, 35709c6cae24SSepherosa Ziehau sizeof(ifr->ifr_name)); 35719c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 35729c6cae24SSepherosa Ziehau break; 35739c6cae24SSepherosa Ziehau } 35749c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 357515516c77SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd); 357615516c77SSepherosa Ziehau break; 357715516c77SSepherosa Ziehau 3578*8c068aa5SSepherosa Ziehau case SIOCGIFRSSHASH: 3579*8c068aa5SSepherosa Ziehau ifrh = (struct ifrsshash *)data; 3580*8c068aa5SSepherosa Ziehau HN_LOCK(sc); 3581*8c068aa5SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 3582*8c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 3583*8c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_NONE; 3584*8c068aa5SSepherosa Ziehau ifrh->ifrh_types = 0; 3585*8c068aa5SSepherosa Ziehau break; 3586*8c068aa5SSepherosa Ziehau } 3587*8c068aa5SSepherosa Ziehau 3588*8c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ) 3589*8c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_TOEPLITZ; 3590*8c068aa5SSepherosa Ziehau else 3591*8c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_PRIVATE; 3592*8c068aa5SSepherosa Ziehau 3593*8c068aa5SSepherosa Ziehau ifrh->ifrh_types = 0; 3594*8c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_IPV4) 3595*8c068aa5SSepherosa Ziehau ifrh->ifrh_types |= RSS_TYPE_IPV4; 3596*8c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_TCP_IPV4) 3597*8c068aa5SSepherosa Ziehau ifrh->ifrh_types |= RSS_TYPE_TCP_IPV4; 3598*8c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_IPV6) 3599*8c068aa5SSepherosa Ziehau ifrh->ifrh_types |= RSS_TYPE_IPV6; 3600*8c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_IPV6_EX) 3601*8c068aa5SSepherosa Ziehau ifrh->ifrh_types |= RSS_TYPE_IPV6_EX; 3602*8c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_TCP_IPV6) 3603*8c068aa5SSepherosa Ziehau ifrh->ifrh_types |= RSS_TYPE_TCP_IPV6; 3604*8c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_TCP_IPV6_EX) 3605*8c068aa5SSepherosa Ziehau ifrh->ifrh_types |= RSS_TYPE_TCP_IPV6_EX; 3606*8c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 3607*8c068aa5SSepherosa Ziehau break; 3608*8c068aa5SSepherosa Ziehau 3609*8c068aa5SSepherosa Ziehau case SIOCGIFRSSKEY: 3610*8c068aa5SSepherosa Ziehau ifrk = (struct ifrsskey *)data; 3611*8c068aa5SSepherosa Ziehau HN_LOCK(sc); 3612*8c068aa5SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 3613*8c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 3614*8c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_NONE; 3615*8c068aa5SSepherosa Ziehau ifrk->ifrk_keylen = 0; 3616*8c068aa5SSepherosa Ziehau break; 3617*8c068aa5SSepherosa Ziehau } 3618*8c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ) 3619*8c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_TOEPLITZ; 3620*8c068aa5SSepherosa Ziehau else 3621*8c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_PRIVATE; 3622*8c068aa5SSepherosa Ziehau ifrk->ifrk_keylen = NDIS_HASH_KEYSIZE_TOEPLITZ; 3623*8c068aa5SSepherosa Ziehau memcpy(ifrk->ifrk_key, sc->hn_rss.rss_key, 3624*8c068aa5SSepherosa Ziehau NDIS_HASH_KEYSIZE_TOEPLITZ); 3625*8c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 3626*8c068aa5SSepherosa Ziehau break; 3627*8c068aa5SSepherosa Ziehau 362815516c77SSepherosa Ziehau default: 362915516c77SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 363015516c77SSepherosa Ziehau break; 363115516c77SSepherosa Ziehau } 363215516c77SSepherosa Ziehau return (error); 363315516c77SSepherosa Ziehau } 363415516c77SSepherosa Ziehau 363515516c77SSepherosa Ziehau static void 36365bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching) 363715516c77SSepherosa Ziehau { 363815516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 363915516c77SSepherosa Ziehau int i; 364015516c77SSepherosa Ziehau 364115516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 364215516c77SSepherosa Ziehau 364315516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 364415516c77SSepherosa Ziehau ("synthetic parts were not attached")); 364515516c77SSepherosa Ziehau 36469c6cae24SSepherosa Ziehau /* Clear RUNNING bit ASAP. */ 36479c6cae24SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 36489c6cae24SSepherosa Ziehau 36496c1204dfSSepherosa Ziehau /* Disable polling. */ 36506c1204dfSSepherosa Ziehau hn_polling(sc, 0); 36516c1204dfSSepherosa Ziehau 36529c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) { 36539c6cae24SSepherosa Ziehau KASSERT(sc->hn_vf_ifp != NULL, 36549c6cae24SSepherosa Ziehau ("%s: VF is not attached", ifp->if_xname)); 36559c6cae24SSepherosa Ziehau 3656a97fff19SSepherosa Ziehau /* Mark transparent mode VF as disabled. */ 3657a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */); 36589c6cae24SSepherosa Ziehau 36599c6cae24SSepherosa Ziehau /* 36609c6cae24SSepherosa Ziehau * NOTE: 36619c6cae24SSepherosa Ziehau * Datapath setting must happen _before_ bringing 36629c6cae24SSepherosa Ziehau * the VF down. 36639c6cae24SSepherosa Ziehau */ 36649c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH); 36659c6cae24SSepherosa Ziehau 36669c6cae24SSepherosa Ziehau /* 36679c6cae24SSepherosa Ziehau * Bring the VF down. 36689c6cae24SSepherosa Ziehau */ 36699c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 36709c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags &= ~IFF_UP; 36719c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(sc); 36729c6cae24SSepherosa Ziehau } 36739c6cae24SSepherosa Ziehau 36749c6cae24SSepherosa Ziehau /* Suspend data transfers. */ 367515516c77SSepherosa Ziehau hn_suspend_data(sc); 367615516c77SSepherosa Ziehau 367715516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 367815516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 367915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 368015516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 36815bdfd3fdSDexuan Cui 36825bdfd3fdSDexuan Cui /* 36839c6cae24SSepherosa Ziehau * If the non-transparent mode VF is active, make sure 36849c6cae24SSepherosa Ziehau * that the RX filter still allows packet reception. 36855bdfd3fdSDexuan Cui */ 3686962f0357SSepherosa Ziehau if (!detaching && (sc->hn_flags & HN_FLAG_RXVF)) 36875bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 368815516c77SSepherosa Ziehau } 368915516c77SSepherosa Ziehau 369015516c77SSepherosa Ziehau static void 369115516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc) 369215516c77SSepherosa Ziehau { 369315516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 369415516c77SSepherosa Ziehau int i; 369515516c77SSepherosa Ziehau 369615516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 369715516c77SSepherosa Ziehau 369815516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 369915516c77SSepherosa Ziehau return; 370015516c77SSepherosa Ziehau 370115516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 370215516c77SSepherosa Ziehau return; 370315516c77SSepherosa Ziehau 370415516c77SSepherosa Ziehau /* Configure RX filter */ 3705c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 370615516c77SSepherosa Ziehau 370715516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 370815516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 370915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 371015516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 371115516c77SSepherosa Ziehau 371215516c77SSepherosa Ziehau /* Clear TX 'suspended' bit. */ 371315516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_inuse); 371415516c77SSepherosa Ziehau 37159c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 37169c6cae24SSepherosa Ziehau /* Initialize transparent VF. */ 37179c6cae24SSepherosa Ziehau hn_xpnt_vf_init(sc); 37189c6cae24SSepherosa Ziehau } 37199c6cae24SSepherosa Ziehau 372015516c77SSepherosa Ziehau /* Everything is ready; unleash! */ 372115516c77SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 37226c1204dfSSepherosa Ziehau 37236c1204dfSSepherosa Ziehau /* Re-enable polling if requested. */ 37246c1204dfSSepherosa Ziehau if (sc->hn_pollhz > 0) 37256c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 372615516c77SSepherosa Ziehau } 372715516c77SSepherosa Ziehau 372815516c77SSepherosa Ziehau static void 372915516c77SSepherosa Ziehau hn_init(void *xsc) 373015516c77SSepherosa Ziehau { 373115516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 373215516c77SSepherosa Ziehau 373315516c77SSepherosa Ziehau HN_LOCK(sc); 373415516c77SSepherosa Ziehau hn_init_locked(sc); 373515516c77SSepherosa Ziehau HN_UNLOCK(sc); 373615516c77SSepherosa Ziehau } 373715516c77SSepherosa Ziehau 373815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 373915516c77SSepherosa Ziehau 374015516c77SSepherosa Ziehau static int 374115516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS) 374215516c77SSepherosa Ziehau { 374315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 374415516c77SSepherosa Ziehau unsigned int lenlim; 374515516c77SSepherosa Ziehau int error; 374615516c77SSepherosa Ziehau 374715516c77SSepherosa Ziehau lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim; 374815516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &lenlim, 0, req); 374915516c77SSepherosa Ziehau if (error || req->newptr == NULL) 375015516c77SSepherosa Ziehau return error; 375115516c77SSepherosa Ziehau 375215516c77SSepherosa Ziehau HN_LOCK(sc); 375315516c77SSepherosa Ziehau if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) || 375415516c77SSepherosa Ziehau lenlim > TCP_LRO_LENGTH_MAX) { 375515516c77SSepherosa Ziehau HN_UNLOCK(sc); 375615516c77SSepherosa Ziehau return EINVAL; 375715516c77SSepherosa Ziehau } 375815516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, lenlim); 375915516c77SSepherosa Ziehau HN_UNLOCK(sc); 376015516c77SSepherosa Ziehau 376115516c77SSepherosa Ziehau return 0; 376215516c77SSepherosa Ziehau } 376315516c77SSepherosa Ziehau 376415516c77SSepherosa Ziehau static int 376515516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS) 376615516c77SSepherosa Ziehau { 376715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 376815516c77SSepherosa Ziehau int ackcnt, error, i; 376915516c77SSepherosa Ziehau 377015516c77SSepherosa Ziehau /* 377115516c77SSepherosa Ziehau * lro_ackcnt_lim is append count limit, 377215516c77SSepherosa Ziehau * +1 to turn it into aggregation limit. 377315516c77SSepherosa Ziehau */ 377415516c77SSepherosa Ziehau ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1; 377515516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &ackcnt, 0, req); 377615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 377715516c77SSepherosa Ziehau return error; 377815516c77SSepherosa Ziehau 377915516c77SSepherosa Ziehau if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1)) 378015516c77SSepherosa Ziehau return EINVAL; 378115516c77SSepherosa Ziehau 378215516c77SSepherosa Ziehau /* 378315516c77SSepherosa Ziehau * Convert aggregation limit back to append 378415516c77SSepherosa Ziehau * count limit. 378515516c77SSepherosa Ziehau */ 378615516c77SSepherosa Ziehau --ackcnt; 378715516c77SSepherosa Ziehau HN_LOCK(sc); 3788a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 378915516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt; 379015516c77SSepherosa Ziehau HN_UNLOCK(sc); 379115516c77SSepherosa Ziehau return 0; 379215516c77SSepherosa Ziehau } 379315516c77SSepherosa Ziehau 379415516c77SSepherosa Ziehau #endif 379515516c77SSepherosa Ziehau 379615516c77SSepherosa Ziehau static int 379715516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS) 379815516c77SSepherosa Ziehau { 379915516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 380015516c77SSepherosa Ziehau int hcsum = arg2; 380115516c77SSepherosa Ziehau int on, error, i; 380215516c77SSepherosa Ziehau 380315516c77SSepherosa Ziehau on = 0; 380415516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum) 380515516c77SSepherosa Ziehau on = 1; 380615516c77SSepherosa Ziehau 380715516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &on, 0, req); 380815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 380915516c77SSepherosa Ziehau return error; 381015516c77SSepherosa Ziehau 381115516c77SSepherosa Ziehau HN_LOCK(sc); 3812a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 381315516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 381415516c77SSepherosa Ziehau 381515516c77SSepherosa Ziehau if (on) 381615516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= hcsum; 381715516c77SSepherosa Ziehau else 381815516c77SSepherosa Ziehau rxr->hn_trust_hcsum &= ~hcsum; 381915516c77SSepherosa Ziehau } 382015516c77SSepherosa Ziehau HN_UNLOCK(sc); 382115516c77SSepherosa Ziehau return 0; 382215516c77SSepherosa Ziehau } 382315516c77SSepherosa Ziehau 382415516c77SSepherosa Ziehau static int 382515516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS) 382615516c77SSepherosa Ziehau { 382715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 382815516c77SSepherosa Ziehau int chim_size, error; 382915516c77SSepherosa Ziehau 383015516c77SSepherosa Ziehau chim_size = sc->hn_tx_ring[0].hn_chim_size; 383115516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &chim_size, 0, req); 383215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 383315516c77SSepherosa Ziehau return error; 383415516c77SSepherosa Ziehau 383515516c77SSepherosa Ziehau if (chim_size > sc->hn_chim_szmax || chim_size <= 0) 383615516c77SSepherosa Ziehau return EINVAL; 383715516c77SSepherosa Ziehau 383815516c77SSepherosa Ziehau HN_LOCK(sc); 383915516c77SSepherosa Ziehau hn_set_chim_size(sc, chim_size); 384015516c77SSepherosa Ziehau HN_UNLOCK(sc); 384115516c77SSepherosa Ziehau return 0; 384215516c77SSepherosa Ziehau } 384315516c77SSepherosa Ziehau 384415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 384515516c77SSepherosa Ziehau static int 384615516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS) 384715516c77SSepherosa Ziehau { 384815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 384915516c77SSepherosa Ziehau int ofs = arg2, i, error; 385015516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 385115516c77SSepherosa Ziehau uint64_t stat; 385215516c77SSepherosa Ziehau 385315516c77SSepherosa Ziehau stat = 0; 385415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 385515516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 385615516c77SSepherosa Ziehau stat += *((int *)((uint8_t *)rxr + ofs)); 385715516c77SSepherosa Ziehau } 385815516c77SSepherosa Ziehau 385915516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 386015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 386115516c77SSepherosa Ziehau return error; 386215516c77SSepherosa Ziehau 386315516c77SSepherosa Ziehau /* Zero out this stat. */ 386415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 386515516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 386615516c77SSepherosa Ziehau *((int *)((uint8_t *)rxr + ofs)) = 0; 386715516c77SSepherosa Ziehau } 386815516c77SSepherosa Ziehau return 0; 386915516c77SSepherosa Ziehau } 387015516c77SSepherosa Ziehau #else 387115516c77SSepherosa Ziehau static int 387215516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS) 387315516c77SSepherosa Ziehau { 387415516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 387515516c77SSepherosa Ziehau int ofs = arg2, i, error; 387615516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 387715516c77SSepherosa Ziehau uint64_t stat; 387815516c77SSepherosa Ziehau 387915516c77SSepherosa Ziehau stat = 0; 3880a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 388115516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 388215516c77SSepherosa Ziehau stat += *((uint64_t *)((uint8_t *)rxr + ofs)); 388315516c77SSepherosa Ziehau } 388415516c77SSepherosa Ziehau 388515516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 388615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 388715516c77SSepherosa Ziehau return error; 388815516c77SSepherosa Ziehau 388915516c77SSepherosa Ziehau /* Zero out this stat. */ 3890a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 389115516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 389215516c77SSepherosa Ziehau *((uint64_t *)((uint8_t *)rxr + ofs)) = 0; 389315516c77SSepherosa Ziehau } 389415516c77SSepherosa Ziehau return 0; 389515516c77SSepherosa Ziehau } 389615516c77SSepherosa Ziehau 389715516c77SSepherosa Ziehau #endif 389815516c77SSepherosa Ziehau 389915516c77SSepherosa Ziehau static int 390015516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 390115516c77SSepherosa Ziehau { 390215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 390315516c77SSepherosa Ziehau int ofs = arg2, i, error; 390415516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 390515516c77SSepherosa Ziehau u_long stat; 390615516c77SSepherosa Ziehau 390715516c77SSepherosa Ziehau stat = 0; 3908a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 390915516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 391015516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)rxr + ofs)); 391115516c77SSepherosa Ziehau } 391215516c77SSepherosa Ziehau 391315516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 391415516c77SSepherosa Ziehau if (error || req->newptr == NULL) 391515516c77SSepherosa Ziehau return error; 391615516c77SSepherosa Ziehau 391715516c77SSepherosa Ziehau /* Zero out this stat. */ 3918a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 391915516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 392015516c77SSepherosa Ziehau *((u_long *)((uint8_t *)rxr + ofs)) = 0; 392115516c77SSepherosa Ziehau } 392215516c77SSepherosa Ziehau return 0; 392315516c77SSepherosa Ziehau } 392415516c77SSepherosa Ziehau 392515516c77SSepherosa Ziehau static int 392615516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 392715516c77SSepherosa Ziehau { 392815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 392915516c77SSepherosa Ziehau int ofs = arg2, i, error; 393015516c77SSepherosa Ziehau struct hn_tx_ring *txr; 393115516c77SSepherosa Ziehau u_long stat; 393215516c77SSepherosa Ziehau 393315516c77SSepherosa Ziehau stat = 0; 3934a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 393515516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 393615516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)txr + ofs)); 393715516c77SSepherosa Ziehau } 393815516c77SSepherosa Ziehau 393915516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 394015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 394115516c77SSepherosa Ziehau return error; 394215516c77SSepherosa Ziehau 394315516c77SSepherosa Ziehau /* Zero out this stat. */ 3944a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 394515516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 394615516c77SSepherosa Ziehau *((u_long *)((uint8_t *)txr + ofs)) = 0; 394715516c77SSepherosa Ziehau } 394815516c77SSepherosa Ziehau return 0; 394915516c77SSepherosa Ziehau } 395015516c77SSepherosa Ziehau 395115516c77SSepherosa Ziehau static int 395215516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS) 395315516c77SSepherosa Ziehau { 395415516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 395515516c77SSepherosa Ziehau int ofs = arg2, i, error, conf; 395615516c77SSepherosa Ziehau struct hn_tx_ring *txr; 395715516c77SSepherosa Ziehau 395815516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[0]; 395915516c77SSepherosa Ziehau conf = *((int *)((uint8_t *)txr + ofs)); 396015516c77SSepherosa Ziehau 396115516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &conf, 0, req); 396215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 396315516c77SSepherosa Ziehau return error; 396415516c77SSepherosa Ziehau 396515516c77SSepherosa Ziehau HN_LOCK(sc); 3966a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 396715516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 396815516c77SSepherosa Ziehau *((int *)((uint8_t *)txr + ofs)) = conf; 396915516c77SSepherosa Ziehau } 397015516c77SSepherosa Ziehau HN_UNLOCK(sc); 397115516c77SSepherosa Ziehau 397215516c77SSepherosa Ziehau return 0; 397315516c77SSepherosa Ziehau } 397415516c77SSepherosa Ziehau 397515516c77SSepherosa Ziehau static int 3976dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS) 3977dc13fee6SSepherosa Ziehau { 3978dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 3979dc13fee6SSepherosa Ziehau int error, size; 3980dc13fee6SSepherosa Ziehau 3981dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 3982dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &size, 0, req); 3983dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 3984dc13fee6SSepherosa Ziehau return (error); 3985dc13fee6SSepherosa Ziehau 3986dc13fee6SSepherosa Ziehau HN_LOCK(sc); 3987dc13fee6SSepherosa Ziehau sc->hn_agg_size = size; 3988dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 3989dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 3990dc13fee6SSepherosa Ziehau 3991dc13fee6SSepherosa Ziehau return (0); 3992dc13fee6SSepherosa Ziehau } 3993dc13fee6SSepherosa Ziehau 3994dc13fee6SSepherosa Ziehau static int 3995dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS) 3996dc13fee6SSepherosa Ziehau { 3997dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 3998dc13fee6SSepherosa Ziehau int error, pkts; 3999dc13fee6SSepherosa Ziehau 4000dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 4001dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &pkts, 0, req); 4002dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 4003dc13fee6SSepherosa Ziehau return (error); 4004dc13fee6SSepherosa Ziehau 4005dc13fee6SSepherosa Ziehau HN_LOCK(sc); 4006dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = pkts; 4007dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 4008dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 4009dc13fee6SSepherosa Ziehau 4010dc13fee6SSepherosa Ziehau return (0); 4011dc13fee6SSepherosa Ziehau } 4012dc13fee6SSepherosa Ziehau 4013dc13fee6SSepherosa Ziehau static int 4014dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS) 4015dc13fee6SSepherosa Ziehau { 4016dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4017dc13fee6SSepherosa Ziehau int pkts; 4018dc13fee6SSepherosa Ziehau 4019dc13fee6SSepherosa Ziehau pkts = sc->hn_tx_ring[0].hn_agg_pktmax; 4020dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &pkts, 0, req)); 4021dc13fee6SSepherosa Ziehau } 4022dc13fee6SSepherosa Ziehau 4023dc13fee6SSepherosa Ziehau static int 4024dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS) 4025dc13fee6SSepherosa Ziehau { 4026dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4027dc13fee6SSepherosa Ziehau int align; 4028dc13fee6SSepherosa Ziehau 4029dc13fee6SSepherosa Ziehau align = sc->hn_tx_ring[0].hn_agg_align; 4030dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &align, 0, req)); 4031dc13fee6SSepherosa Ziehau } 4032dc13fee6SSepherosa Ziehau 40336c1204dfSSepherosa Ziehau static void 40346c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz) 40356c1204dfSSepherosa Ziehau { 40366c1204dfSSepherosa Ziehau if (pollhz == 0) 40376c1204dfSSepherosa Ziehau vmbus_chan_poll_disable(chan); 40386c1204dfSSepherosa Ziehau else 40396c1204dfSSepherosa Ziehau vmbus_chan_poll_enable(chan, pollhz); 40406c1204dfSSepherosa Ziehau } 40416c1204dfSSepherosa Ziehau 40426c1204dfSSepherosa Ziehau static void 40436c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz) 40446c1204dfSSepherosa Ziehau { 40456c1204dfSSepherosa Ziehau int nsubch = sc->hn_rx_ring_inuse - 1; 40466c1204dfSSepherosa Ziehau 40476c1204dfSSepherosa Ziehau HN_LOCK_ASSERT(sc); 40486c1204dfSSepherosa Ziehau 40496c1204dfSSepherosa Ziehau if (nsubch > 0) { 40506c1204dfSSepherosa Ziehau struct vmbus_channel **subch; 40516c1204dfSSepherosa Ziehau int i; 40526c1204dfSSepherosa Ziehau 40536c1204dfSSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 40546c1204dfSSepherosa Ziehau for (i = 0; i < nsubch; ++i) 40556c1204dfSSepherosa Ziehau hn_chan_polling(subch[i], pollhz); 40566c1204dfSSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 40576c1204dfSSepherosa Ziehau } 40586c1204dfSSepherosa Ziehau hn_chan_polling(sc->hn_prichan, pollhz); 40596c1204dfSSepherosa Ziehau } 40606c1204dfSSepherosa Ziehau 40616c1204dfSSepherosa Ziehau static int 40626c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS) 40636c1204dfSSepherosa Ziehau { 40646c1204dfSSepherosa Ziehau struct hn_softc *sc = arg1; 40656c1204dfSSepherosa Ziehau int pollhz, error; 40666c1204dfSSepherosa Ziehau 40676c1204dfSSepherosa Ziehau pollhz = sc->hn_pollhz; 40686c1204dfSSepherosa Ziehau error = sysctl_handle_int(oidp, &pollhz, 0, req); 40696c1204dfSSepherosa Ziehau if (error || req->newptr == NULL) 40706c1204dfSSepherosa Ziehau return (error); 40716c1204dfSSepherosa Ziehau 40726c1204dfSSepherosa Ziehau if (pollhz != 0 && 40736c1204dfSSepherosa Ziehau (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX)) 40746c1204dfSSepherosa Ziehau return (EINVAL); 40756c1204dfSSepherosa Ziehau 40766c1204dfSSepherosa Ziehau HN_LOCK(sc); 40776c1204dfSSepherosa Ziehau if (sc->hn_pollhz != pollhz) { 40786c1204dfSSepherosa Ziehau sc->hn_pollhz = pollhz; 40796c1204dfSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && 40806c1204dfSSepherosa Ziehau (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 40816c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 40826c1204dfSSepherosa Ziehau } 40836c1204dfSSepherosa Ziehau HN_UNLOCK(sc); 40846c1204dfSSepherosa Ziehau 40856c1204dfSSepherosa Ziehau return (0); 40866c1204dfSSepherosa Ziehau } 40876c1204dfSSepherosa Ziehau 4088dc13fee6SSepherosa Ziehau static int 408915516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS) 409015516c77SSepherosa Ziehau { 409115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 409215516c77SSepherosa Ziehau char verstr[16]; 409315516c77SSepherosa Ziehau 409415516c77SSepherosa Ziehau snprintf(verstr, sizeof(verstr), "%u.%u", 409515516c77SSepherosa Ziehau HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 409615516c77SSepherosa Ziehau HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 409715516c77SSepherosa Ziehau return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 409815516c77SSepherosa Ziehau } 409915516c77SSepherosa Ziehau 410015516c77SSepherosa Ziehau static int 410115516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS) 410215516c77SSepherosa Ziehau { 410315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 410415516c77SSepherosa Ziehau char caps_str[128]; 410515516c77SSepherosa Ziehau uint32_t caps; 410615516c77SSepherosa Ziehau 410715516c77SSepherosa Ziehau HN_LOCK(sc); 410815516c77SSepherosa Ziehau caps = sc->hn_caps; 410915516c77SSepherosa Ziehau HN_UNLOCK(sc); 411015516c77SSepherosa Ziehau snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS); 411115516c77SSepherosa Ziehau return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req); 411215516c77SSepherosa Ziehau } 411315516c77SSepherosa Ziehau 411415516c77SSepherosa Ziehau static int 411515516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS) 411615516c77SSepherosa Ziehau { 411715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 411815516c77SSepherosa Ziehau char assist_str[128]; 411915516c77SSepherosa Ziehau uint32_t hwassist; 412015516c77SSepherosa Ziehau 412115516c77SSepherosa Ziehau HN_LOCK(sc); 412215516c77SSepherosa Ziehau hwassist = sc->hn_ifp->if_hwassist; 412315516c77SSepherosa Ziehau HN_UNLOCK(sc); 412415516c77SSepherosa Ziehau snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS); 412515516c77SSepherosa Ziehau return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req); 412615516c77SSepherosa Ziehau } 412715516c77SSepherosa Ziehau 412815516c77SSepherosa Ziehau static int 412915516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS) 413015516c77SSepherosa Ziehau { 413115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 413215516c77SSepherosa Ziehau char filter_str[128]; 413315516c77SSepherosa Ziehau uint32_t filter; 413415516c77SSepherosa Ziehau 413515516c77SSepherosa Ziehau HN_LOCK(sc); 413615516c77SSepherosa Ziehau filter = sc->hn_rx_filter; 413715516c77SSepherosa Ziehau HN_UNLOCK(sc); 413815516c77SSepherosa Ziehau snprintf(filter_str, sizeof(filter_str), "%b", filter, 413915516c77SSepherosa Ziehau NDIS_PACKET_TYPES); 414015516c77SSepherosa Ziehau return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req); 414115516c77SSepherosa Ziehau } 414215516c77SSepherosa Ziehau 414334d68912SSepherosa Ziehau #ifndef RSS 414434d68912SSepherosa Ziehau 414515516c77SSepherosa Ziehau static int 414615516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS) 414715516c77SSepherosa Ziehau { 414815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 414915516c77SSepherosa Ziehau int error; 415015516c77SSepherosa Ziehau 415115516c77SSepherosa Ziehau HN_LOCK(sc); 415215516c77SSepherosa Ziehau 415315516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 415415516c77SSepherosa Ziehau if (error || req->newptr == NULL) 415515516c77SSepherosa Ziehau goto back; 415615516c77SSepherosa Ziehau 415715516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 415815516c77SSepherosa Ziehau if (error) 415915516c77SSepherosa Ziehau goto back; 416015516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 416115516c77SSepherosa Ziehau 416215516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 416315516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 416415516c77SSepherosa Ziehau } else { 416515516c77SSepherosa Ziehau /* Not RSS capable, at least for now; just save the RSS key. */ 416615516c77SSepherosa Ziehau error = 0; 416715516c77SSepherosa Ziehau } 416815516c77SSepherosa Ziehau back: 416915516c77SSepherosa Ziehau HN_UNLOCK(sc); 417015516c77SSepherosa Ziehau return (error); 417115516c77SSepherosa Ziehau } 417215516c77SSepherosa Ziehau 417315516c77SSepherosa Ziehau static int 417415516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS) 417515516c77SSepherosa Ziehau { 417615516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 417715516c77SSepherosa Ziehau int error; 417815516c77SSepherosa Ziehau 417915516c77SSepherosa Ziehau HN_LOCK(sc); 418015516c77SSepherosa Ziehau 418115516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 418215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 418315516c77SSepherosa Ziehau goto back; 418415516c77SSepherosa Ziehau 418515516c77SSepherosa Ziehau /* 418615516c77SSepherosa Ziehau * Don't allow RSS indirect table change, if this interface is not 418715516c77SSepherosa Ziehau * RSS capable currently. 418815516c77SSepherosa Ziehau */ 418915516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 419015516c77SSepherosa Ziehau error = EOPNOTSUPP; 419115516c77SSepherosa Ziehau goto back; 419215516c77SSepherosa Ziehau } 419315516c77SSepherosa Ziehau 419415516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 419515516c77SSepherosa Ziehau if (error) 419615516c77SSepherosa Ziehau goto back; 419715516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 419815516c77SSepherosa Ziehau 4199afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 420015516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 420115516c77SSepherosa Ziehau back: 420215516c77SSepherosa Ziehau HN_UNLOCK(sc); 420315516c77SSepherosa Ziehau return (error); 420415516c77SSepherosa Ziehau } 420515516c77SSepherosa Ziehau 420634d68912SSepherosa Ziehau #endif /* !RSS */ 420734d68912SSepherosa Ziehau 420815516c77SSepherosa Ziehau static int 420915516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS) 421015516c77SSepherosa Ziehau { 421115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 421215516c77SSepherosa Ziehau char hash_str[128]; 421315516c77SSepherosa Ziehau uint32_t hash; 421415516c77SSepherosa Ziehau 421515516c77SSepherosa Ziehau HN_LOCK(sc); 421615516c77SSepherosa Ziehau hash = sc->hn_rss_hash; 421715516c77SSepherosa Ziehau HN_UNLOCK(sc); 421815516c77SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 421915516c77SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 422015516c77SSepherosa Ziehau } 422115516c77SSepherosa Ziehau 422215516c77SSepherosa Ziehau static int 422340d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS) 422440d60d6eSDexuan Cui { 422540d60d6eSDexuan Cui struct hn_softc *sc = arg1; 4226499c3e17SSepherosa Ziehau char vf_name[IFNAMSIZ + 1]; 4227962f0357SSepherosa Ziehau struct ifnet *vf_ifp; 422840d60d6eSDexuan Cui 422940d60d6eSDexuan Cui HN_LOCK(sc); 423040d60d6eSDexuan Cui vf_name[0] = '\0'; 4231962f0357SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 4232962f0357SSepherosa Ziehau if (vf_ifp != NULL) 4233962f0357SSepherosa Ziehau snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname); 423440d60d6eSDexuan Cui HN_UNLOCK(sc); 423540d60d6eSDexuan Cui return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); 423640d60d6eSDexuan Cui } 423740d60d6eSDexuan Cui 423840d60d6eSDexuan Cui static int 4239499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS) 4240499c3e17SSepherosa Ziehau { 4241499c3e17SSepherosa Ziehau struct hn_softc *sc = arg1; 4242499c3e17SSepherosa Ziehau char vf_name[IFNAMSIZ + 1]; 4243962f0357SSepherosa Ziehau struct ifnet *vf_ifp; 4244499c3e17SSepherosa Ziehau 4245499c3e17SSepherosa Ziehau HN_LOCK(sc); 4246499c3e17SSepherosa Ziehau vf_name[0] = '\0'; 4247962f0357SSepherosa Ziehau vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp; 4248962f0357SSepherosa Ziehau if (vf_ifp != NULL) 4249962f0357SSepherosa Ziehau snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname); 4250499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 4251499c3e17SSepherosa Ziehau return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); 4252499c3e17SSepherosa Ziehau } 4253499c3e17SSepherosa Ziehau 4254499c3e17SSepherosa Ziehau static int 4255499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS) 4256499c3e17SSepherosa Ziehau { 4257499c3e17SSepherosa Ziehau struct rm_priotracker pt; 4258499c3e17SSepherosa Ziehau struct sbuf *sb; 4259499c3e17SSepherosa Ziehau int error, i; 4260499c3e17SSepherosa Ziehau bool first; 4261499c3e17SSepherosa Ziehau 4262499c3e17SSepherosa Ziehau error = sysctl_wire_old_buffer(req, 0); 4263499c3e17SSepherosa Ziehau if (error != 0) 4264499c3e17SSepherosa Ziehau return (error); 4265499c3e17SSepherosa Ziehau 4266499c3e17SSepherosa Ziehau sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4267499c3e17SSepherosa Ziehau if (sb == NULL) 4268499c3e17SSepherosa Ziehau return (ENOMEM); 4269499c3e17SSepherosa Ziehau 4270499c3e17SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 4271499c3e17SSepherosa Ziehau 4272499c3e17SSepherosa Ziehau first = true; 4273499c3e17SSepherosa Ziehau for (i = 0; i < hn_vfmap_size; ++i) { 4274499c3e17SSepherosa Ziehau struct ifnet *ifp; 4275499c3e17SSepherosa Ziehau 4276499c3e17SSepherosa Ziehau if (hn_vfmap[i] == NULL) 4277499c3e17SSepherosa Ziehau continue; 4278499c3e17SSepherosa Ziehau 4279499c3e17SSepherosa Ziehau ifp = ifnet_byindex(i); 4280499c3e17SSepherosa Ziehau if (ifp != NULL) { 4281499c3e17SSepherosa Ziehau if (first) 4282499c3e17SSepherosa Ziehau sbuf_printf(sb, "%s", ifp->if_xname); 4283499c3e17SSepherosa Ziehau else 4284499c3e17SSepherosa Ziehau sbuf_printf(sb, " %s", ifp->if_xname); 4285499c3e17SSepherosa Ziehau first = false; 4286499c3e17SSepherosa Ziehau } 4287499c3e17SSepherosa Ziehau } 4288499c3e17SSepherosa Ziehau 4289499c3e17SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 4290499c3e17SSepherosa Ziehau 4291499c3e17SSepherosa Ziehau error = sbuf_finish(sb); 4292499c3e17SSepherosa Ziehau sbuf_delete(sb); 4293499c3e17SSepherosa Ziehau return (error); 4294499c3e17SSepherosa Ziehau } 4295499c3e17SSepherosa Ziehau 4296499c3e17SSepherosa Ziehau static int 4297499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS) 4298499c3e17SSepherosa Ziehau { 4299499c3e17SSepherosa Ziehau struct rm_priotracker pt; 4300499c3e17SSepherosa Ziehau struct sbuf *sb; 4301499c3e17SSepherosa Ziehau int error, i; 4302499c3e17SSepherosa Ziehau bool first; 4303499c3e17SSepherosa Ziehau 4304499c3e17SSepherosa Ziehau error = sysctl_wire_old_buffer(req, 0); 4305499c3e17SSepherosa Ziehau if (error != 0) 4306499c3e17SSepherosa Ziehau return (error); 4307499c3e17SSepherosa Ziehau 4308499c3e17SSepherosa Ziehau sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4309499c3e17SSepherosa Ziehau if (sb == NULL) 4310499c3e17SSepherosa Ziehau return (ENOMEM); 4311499c3e17SSepherosa Ziehau 4312499c3e17SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 4313499c3e17SSepherosa Ziehau 4314499c3e17SSepherosa Ziehau first = true; 4315499c3e17SSepherosa Ziehau for (i = 0; i < hn_vfmap_size; ++i) { 4316499c3e17SSepherosa Ziehau struct ifnet *ifp, *hn_ifp; 4317499c3e17SSepherosa Ziehau 4318499c3e17SSepherosa Ziehau hn_ifp = hn_vfmap[i]; 4319499c3e17SSepherosa Ziehau if (hn_ifp == NULL) 4320499c3e17SSepherosa Ziehau continue; 4321499c3e17SSepherosa Ziehau 4322499c3e17SSepherosa Ziehau ifp = ifnet_byindex(i); 4323499c3e17SSepherosa Ziehau if (ifp != NULL) { 4324499c3e17SSepherosa Ziehau if (first) { 4325499c3e17SSepherosa Ziehau sbuf_printf(sb, "%s:%s", ifp->if_xname, 4326499c3e17SSepherosa Ziehau hn_ifp->if_xname); 4327499c3e17SSepherosa Ziehau } else { 4328499c3e17SSepherosa Ziehau sbuf_printf(sb, " %s:%s", ifp->if_xname, 4329499c3e17SSepherosa Ziehau hn_ifp->if_xname); 4330499c3e17SSepherosa Ziehau } 4331499c3e17SSepherosa Ziehau first = false; 4332499c3e17SSepherosa Ziehau } 4333499c3e17SSepherosa Ziehau } 4334499c3e17SSepherosa Ziehau 4335499c3e17SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 4336499c3e17SSepherosa Ziehau 4337499c3e17SSepherosa Ziehau error = sbuf_finish(sb); 4338499c3e17SSepherosa Ziehau sbuf_delete(sb); 4339499c3e17SSepherosa Ziehau return (error); 4340499c3e17SSepherosa Ziehau } 4341499c3e17SSepherosa Ziehau 4342499c3e17SSepherosa Ziehau static int 43439c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS) 43449c6cae24SSepherosa Ziehau { 43459c6cae24SSepherosa Ziehau struct hn_softc *sc = arg1; 43469c6cae24SSepherosa Ziehau int error, onoff = 0; 43479c6cae24SSepherosa Ziehau 43489c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) 43499c6cae24SSepherosa Ziehau onoff = 1; 43509c6cae24SSepherosa Ziehau error = sysctl_handle_int(oidp, &onoff, 0, req); 43519c6cae24SSepherosa Ziehau if (error || req->newptr == NULL) 43529c6cae24SSepherosa Ziehau return (error); 43539c6cae24SSepherosa Ziehau 43549c6cae24SSepherosa Ziehau HN_LOCK(sc); 43559c6cae24SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit() */ 43569c6cae24SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 43579c6cae24SSepherosa Ziehau if (onoff) 43589c6cae24SSepherosa Ziehau sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF; 43599c6cae24SSepherosa Ziehau else 43609c6cae24SSepherosa Ziehau sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF; 43619c6cae24SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 43629c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 43639c6cae24SSepherosa Ziehau 43649c6cae24SSepherosa Ziehau return (0); 43659c6cae24SSepherosa Ziehau } 43669c6cae24SSepherosa Ziehau 43679c6cae24SSepherosa Ziehau static int 43689c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS) 43699c6cae24SSepherosa Ziehau { 43709c6cae24SSepherosa Ziehau struct hn_softc *sc = arg1; 43719c6cae24SSepherosa Ziehau int enabled = 0; 43729c6cae24SSepherosa Ziehau 43739c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 43749c6cae24SSepherosa Ziehau enabled = 1; 43759c6cae24SSepherosa Ziehau return (sysctl_handle_int(oidp, &enabled, 0, req)); 43769c6cae24SSepherosa Ziehau } 43779c6cae24SSepherosa Ziehau 43789c6cae24SSepherosa Ziehau static int 437915516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff) 438015516c77SSepherosa Ziehau { 438115516c77SSepherosa Ziehau const struct ip *ip; 438215516c77SSepherosa Ziehau int len, iphlen, iplen; 438315516c77SSepherosa Ziehau const struct tcphdr *th; 438415516c77SSepherosa Ziehau int thoff; /* TCP data offset */ 438515516c77SSepherosa Ziehau 438615516c77SSepherosa Ziehau len = hoff + sizeof(struct ip); 438715516c77SSepherosa Ziehau 438815516c77SSepherosa Ziehau /* The packet must be at least the size of an IP header. */ 438915516c77SSepherosa Ziehau if (m->m_pkthdr.len < len) 439015516c77SSepherosa Ziehau return IPPROTO_DONE; 439115516c77SSepherosa Ziehau 439215516c77SSepherosa Ziehau /* The fixed IP header must reside completely in the first mbuf. */ 439315516c77SSepherosa Ziehau if (m->m_len < len) 439415516c77SSepherosa Ziehau return IPPROTO_DONE; 439515516c77SSepherosa Ziehau 439615516c77SSepherosa Ziehau ip = mtodo(m, hoff); 439715516c77SSepherosa Ziehau 439815516c77SSepherosa Ziehau /* Bound check the packet's stated IP header length. */ 439915516c77SSepherosa Ziehau iphlen = ip->ip_hl << 2; 440015516c77SSepherosa Ziehau if (iphlen < sizeof(struct ip)) /* minimum header length */ 440115516c77SSepherosa Ziehau return IPPROTO_DONE; 440215516c77SSepherosa Ziehau 440315516c77SSepherosa Ziehau /* The full IP header must reside completely in the one mbuf. */ 440415516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen) 440515516c77SSepherosa Ziehau return IPPROTO_DONE; 440615516c77SSepherosa Ziehau 440715516c77SSepherosa Ziehau iplen = ntohs(ip->ip_len); 440815516c77SSepherosa Ziehau 440915516c77SSepherosa Ziehau /* 441015516c77SSepherosa Ziehau * Check that the amount of data in the buffers is as 441115516c77SSepherosa Ziehau * at least much as the IP header would have us expect. 441215516c77SSepherosa Ziehau */ 441315516c77SSepherosa Ziehau if (m->m_pkthdr.len < hoff + iplen) 441415516c77SSepherosa Ziehau return IPPROTO_DONE; 441515516c77SSepherosa Ziehau 441615516c77SSepherosa Ziehau /* 441715516c77SSepherosa Ziehau * Ignore IP fragments. 441815516c77SSepherosa Ziehau */ 441915516c77SSepherosa Ziehau if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF)) 442015516c77SSepherosa Ziehau return IPPROTO_DONE; 442115516c77SSepherosa Ziehau 442215516c77SSepherosa Ziehau /* 442315516c77SSepherosa Ziehau * The TCP/IP or UDP/IP header must be entirely contained within 442415516c77SSepherosa Ziehau * the first fragment of a packet. 442515516c77SSepherosa Ziehau */ 442615516c77SSepherosa Ziehau switch (ip->ip_p) { 442715516c77SSepherosa Ziehau case IPPROTO_TCP: 442815516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct tcphdr)) 442915516c77SSepherosa Ziehau return IPPROTO_DONE; 443015516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct tcphdr)) 443115516c77SSepherosa Ziehau return IPPROTO_DONE; 443215516c77SSepherosa Ziehau th = (const struct tcphdr *)((const uint8_t *)ip + iphlen); 443315516c77SSepherosa Ziehau thoff = th->th_off << 2; 443415516c77SSepherosa Ziehau if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen) 443515516c77SSepherosa Ziehau return IPPROTO_DONE; 443615516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + thoff) 443715516c77SSepherosa Ziehau return IPPROTO_DONE; 443815516c77SSepherosa Ziehau break; 443915516c77SSepherosa Ziehau case IPPROTO_UDP: 444015516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct udphdr)) 444115516c77SSepherosa Ziehau return IPPROTO_DONE; 444215516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct udphdr)) 444315516c77SSepherosa Ziehau return IPPROTO_DONE; 444415516c77SSepherosa Ziehau break; 444515516c77SSepherosa Ziehau default: 444615516c77SSepherosa Ziehau if (iplen < iphlen) 444715516c77SSepherosa Ziehau return IPPROTO_DONE; 444815516c77SSepherosa Ziehau break; 444915516c77SSepherosa Ziehau } 445015516c77SSepherosa Ziehau return ip->ip_p; 445115516c77SSepherosa Ziehau } 445215516c77SSepherosa Ziehau 445315516c77SSepherosa Ziehau static int 445415516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt) 445515516c77SSepherosa Ziehau { 445615516c77SSepherosa Ziehau struct sysctl_oid_list *child; 445715516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 445815516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 445915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 446015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 446115516c77SSepherosa Ziehau int lroent_cnt; 446215516c77SSepherosa Ziehau #endif 446315516c77SSepherosa Ziehau #endif 446415516c77SSepherosa Ziehau int i; 446515516c77SSepherosa Ziehau 446615516c77SSepherosa Ziehau /* 446715516c77SSepherosa Ziehau * Create RXBUF for reception. 446815516c77SSepherosa Ziehau * 446915516c77SSepherosa Ziehau * NOTE: 447015516c77SSepherosa Ziehau * - It is shared by all channels. 447115516c77SSepherosa Ziehau * - A large enough buffer is allocated, certain version of NVSes 447215516c77SSepherosa Ziehau * may further limit the usable space. 447315516c77SSepherosa Ziehau */ 447415516c77SSepherosa Ziehau sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 447515516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma, 447615516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 447715516c77SSepherosa Ziehau if (sc->hn_rxbuf == NULL) { 447815516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate rxbuf failed\n"); 447915516c77SSepherosa Ziehau return (ENOMEM); 448015516c77SSepherosa Ziehau } 448115516c77SSepherosa Ziehau 448215516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = ring_cnt; 448315516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt; 448415516c77SSepherosa Ziehau 448515516c77SSepherosa Ziehau sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt, 448615516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 448715516c77SSepherosa Ziehau 448815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 448915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 449015516c77SSepherosa Ziehau lroent_cnt = hn_lro_entry_count; 449115516c77SSepherosa Ziehau if (lroent_cnt < TCP_LRO_ENTRIES) 449215516c77SSepherosa Ziehau lroent_cnt = TCP_LRO_ENTRIES; 449315516c77SSepherosa Ziehau if (bootverbose) 449415516c77SSepherosa Ziehau device_printf(dev, "LRO: entry count %d\n", lroent_cnt); 449515516c77SSepherosa Ziehau #endif 449615516c77SSepherosa Ziehau #endif /* INET || INET6 */ 449715516c77SSepherosa Ziehau 449815516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 449915516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 450015516c77SSepherosa Ziehau 450115516c77SSepherosa Ziehau /* Create dev.hn.UNIT.rx sysctl tree */ 450215516c77SSepherosa Ziehau sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx", 450315516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 450415516c77SSepherosa Ziehau 450515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 450615516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 450715516c77SSepherosa Ziehau 450815516c77SSepherosa Ziehau rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 450915516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE, 451015516c77SSepherosa Ziehau &rxr->hn_br_dma, BUS_DMA_WAITOK); 451115516c77SSepherosa Ziehau if (rxr->hn_br == NULL) { 451215516c77SSepherosa Ziehau device_printf(dev, "allocate bufring failed\n"); 451315516c77SSepherosa Ziehau return (ENOMEM); 451415516c77SSepherosa Ziehau } 451515516c77SSepherosa Ziehau 451615516c77SSepherosa Ziehau if (hn_trust_hosttcp) 451715516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP; 451815516c77SSepherosa Ziehau if (hn_trust_hostudp) 451915516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP; 452015516c77SSepherosa Ziehau if (hn_trust_hostip) 452115516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP; 452215516c77SSepherosa Ziehau rxr->hn_ifp = sc->hn_ifp; 452315516c77SSepherosa Ziehau if (i < sc->hn_tx_ring_cnt) 452415516c77SSepherosa Ziehau rxr->hn_txr = &sc->hn_tx_ring[i]; 452515516c77SSepherosa Ziehau rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF; 452615516c77SSepherosa Ziehau rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK); 452715516c77SSepherosa Ziehau rxr->hn_rx_idx = i; 452815516c77SSepherosa Ziehau rxr->hn_rxbuf = sc->hn_rxbuf; 452915516c77SSepherosa Ziehau 453015516c77SSepherosa Ziehau /* 453115516c77SSepherosa Ziehau * Initialize LRO. 453215516c77SSepherosa Ziehau */ 453315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 453415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 453515516c77SSepherosa Ziehau tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt, 453615516c77SSepherosa Ziehau hn_lro_mbufq_depth); 453715516c77SSepherosa Ziehau #else 453815516c77SSepherosa Ziehau tcp_lro_init(&rxr->hn_lro); 453915516c77SSepherosa Ziehau rxr->hn_lro.ifp = sc->hn_ifp; 454015516c77SSepherosa Ziehau #endif 454115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 454215516c77SSepherosa Ziehau rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF; 454315516c77SSepherosa Ziehau rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF; 454415516c77SSepherosa Ziehau #endif 454515516c77SSepherosa Ziehau #endif /* INET || INET6 */ 454615516c77SSepherosa Ziehau 454715516c77SSepherosa Ziehau if (sc->hn_rx_sysctl_tree != NULL) { 454815516c77SSepherosa Ziehau char name[16]; 454915516c77SSepherosa Ziehau 455015516c77SSepherosa Ziehau /* 455115516c77SSepherosa Ziehau * Create per RX ring sysctl tree: 455215516c77SSepherosa Ziehau * dev.hn.UNIT.rx.RINGID 455315516c77SSepherosa Ziehau */ 455415516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", i); 455515516c77SSepherosa Ziehau rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, 455615516c77SSepherosa Ziehau SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree), 455715516c77SSepherosa Ziehau OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 455815516c77SSepherosa Ziehau 455915516c77SSepherosa Ziehau if (rxr->hn_rx_sysctl_tree != NULL) { 456015516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 456115516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 456215516c77SSepherosa Ziehau OID_AUTO, "packets", CTLFLAG_RW, 456315516c77SSepherosa Ziehau &rxr->hn_pkts, "# of packets received"); 456415516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 456515516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 456615516c77SSepherosa Ziehau OID_AUTO, "rss_pkts", CTLFLAG_RW, 456715516c77SSepherosa Ziehau &rxr->hn_rss_pkts, 456815516c77SSepherosa Ziehau "# of packets w/ RSS info received"); 456915516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, 457015516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 457115516c77SSepherosa Ziehau OID_AUTO, "pktbuf_len", CTLFLAG_RD, 457215516c77SSepherosa Ziehau &rxr->hn_pktbuf_len, 0, 457315516c77SSepherosa Ziehau "Temporary channel packet buffer length"); 457415516c77SSepherosa Ziehau } 457515516c77SSepherosa Ziehau } 457615516c77SSepherosa Ziehau } 457715516c77SSepherosa Ziehau 457815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued", 457915516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 458015516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_queued), 458115516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 458215516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 458315516c77SSepherosa Ziehau #else 458415516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 458515516c77SSepherosa Ziehau #endif 458615516c77SSepherosa Ziehau "LU", "LRO queued"); 458715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed", 458815516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 458915516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_flushed), 459015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 459115516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 459215516c77SSepherosa Ziehau #else 459315516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 459415516c77SSepherosa Ziehau #endif 459515516c77SSepherosa Ziehau "LU", "LRO flushed"); 459615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried", 459715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 459815516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro_tried), 459915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries"); 460015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 460115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim", 460215516c77SSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 460315516c77SSepherosa Ziehau hn_lro_lenlim_sysctl, "IU", 460415516c77SSepherosa Ziehau "Max # of data bytes to be aggregated by LRO"); 460515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim", 460615516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 460715516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl, "I", 460815516c77SSepherosa Ziehau "Max # of ACKs to be aggregated by LRO"); 460915516c77SSepherosa Ziehau #endif 461015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp", 461115516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP, 461215516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 461315516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 461415516c77SSepherosa Ziehau "when csum info is missing"); 461515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp", 461615516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP, 461715516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 461815516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 461915516c77SSepherosa Ziehau "when csum info is missing"); 462015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip", 462115516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP, 462215516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 462315516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 462415516c77SSepherosa Ziehau "when csum info is missing"); 462515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip", 462615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 462715516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_ip), 462815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP"); 462915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp", 463015516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 463115516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_tcp), 463215516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP"); 463315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp", 463415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 463515516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_udp), 463615516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP"); 463715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted", 463815516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 463915516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_trusted), 464015516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", 464115516c77SSepherosa Ziehau "# of packets that we trust host's csum verification"); 464215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts", 464315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 464415516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_small_pkts), 464515516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of small packets received"); 464615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed", 464715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 464815516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_ack_failed), 464915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures"); 465015516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt", 465115516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings"); 465215516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse", 465315516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings"); 465415516c77SSepherosa Ziehau 465515516c77SSepherosa Ziehau return (0); 465615516c77SSepherosa Ziehau } 465715516c77SSepherosa Ziehau 465815516c77SSepherosa Ziehau static void 465915516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc) 466015516c77SSepherosa Ziehau { 466115516c77SSepherosa Ziehau int i; 466215516c77SSepherosa Ziehau 466315516c77SSepherosa Ziehau if (sc->hn_rxbuf != NULL) { 46642494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0) 466515516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf); 46662494d735SSepherosa Ziehau else 46672494d735SSepherosa Ziehau device_printf(sc->hn_dev, "RXBUF is referenced\n"); 466815516c77SSepherosa Ziehau sc->hn_rxbuf = NULL; 466915516c77SSepherosa Ziehau } 467015516c77SSepherosa Ziehau 467115516c77SSepherosa Ziehau if (sc->hn_rx_ring_cnt == 0) 467215516c77SSepherosa Ziehau return; 467315516c77SSepherosa Ziehau 467415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 467515516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 467615516c77SSepherosa Ziehau 467715516c77SSepherosa Ziehau if (rxr->hn_br == NULL) 467815516c77SSepherosa Ziehau continue; 46792494d735SSepherosa Ziehau if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) { 468015516c77SSepherosa Ziehau hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br); 46812494d735SSepherosa Ziehau } else { 46822494d735SSepherosa Ziehau device_printf(sc->hn_dev, 46832494d735SSepherosa Ziehau "%dth channel bufring is referenced", i); 46842494d735SSepherosa Ziehau } 468515516c77SSepherosa Ziehau rxr->hn_br = NULL; 468615516c77SSepherosa Ziehau 468715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 468815516c77SSepherosa Ziehau tcp_lro_free(&rxr->hn_lro); 468915516c77SSepherosa Ziehau #endif 469015516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 469115516c77SSepherosa Ziehau } 469215516c77SSepherosa Ziehau free(sc->hn_rx_ring, M_DEVBUF); 469315516c77SSepherosa Ziehau sc->hn_rx_ring = NULL; 469415516c77SSepherosa Ziehau 469515516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = 0; 469615516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = 0; 469715516c77SSepherosa Ziehau } 469815516c77SSepherosa Ziehau 469915516c77SSepherosa Ziehau static int 470015516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id) 470115516c77SSepherosa Ziehau { 470215516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[id]; 470315516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 470415516c77SSepherosa Ziehau bus_dma_tag_t parent_dtag; 470515516c77SSepherosa Ziehau int error, i; 470615516c77SSepherosa Ziehau 470715516c77SSepherosa Ziehau txr->hn_sc = sc; 470815516c77SSepherosa Ziehau txr->hn_tx_idx = id; 470915516c77SSepherosa Ziehau 471015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 471115516c77SSepherosa Ziehau mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); 471215516c77SSepherosa Ziehau #endif 471315516c77SSepherosa Ziehau mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF); 471415516c77SSepherosa Ziehau 471515516c77SSepherosa Ziehau txr->hn_txdesc_cnt = HN_TX_DESC_CNT; 471615516c77SSepherosa Ziehau txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt, 471715516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 471815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 471915516c77SSepherosa Ziehau SLIST_INIT(&txr->hn_txlist); 472015516c77SSepherosa Ziehau #else 472115516c77SSepherosa Ziehau txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF, 472215516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 472315516c77SSepherosa Ziehau #endif 472415516c77SSepherosa Ziehau 47250e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) { 47260e11868dSSepherosa Ziehau txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ( 47270e11868dSSepherosa Ziehau device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id)); 47280e11868dSSepherosa Ziehau } else { 4729fdd0222aSSepherosa Ziehau txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt]; 47300e11868dSSepherosa Ziehau } 473115516c77SSepherosa Ziehau 473223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 473315516c77SSepherosa Ziehau if (hn_use_if_start) { 473415516c77SSepherosa Ziehau txr->hn_txeof = hn_start_txeof; 473515516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr); 473615516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr); 473723bf9e15SSepherosa Ziehau } else 473823bf9e15SSepherosa Ziehau #endif 473923bf9e15SSepherosa Ziehau { 474015516c77SSepherosa Ziehau int br_depth; 474115516c77SSepherosa Ziehau 474215516c77SSepherosa Ziehau txr->hn_txeof = hn_xmit_txeof; 474315516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr); 474415516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr); 474515516c77SSepherosa Ziehau 474615516c77SSepherosa Ziehau br_depth = hn_get_txswq_depth(txr); 474715516c77SSepherosa Ziehau txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF, 474815516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 474915516c77SSepherosa Ziehau } 475015516c77SSepherosa Ziehau 475115516c77SSepherosa Ziehau txr->hn_direct_tx_size = hn_direct_tx_size; 475215516c77SSepherosa Ziehau 475315516c77SSepherosa Ziehau /* 475415516c77SSepherosa Ziehau * Always schedule transmission instead of trying to do direct 475515516c77SSepherosa Ziehau * transmission. This one gives the best performance so far. 475615516c77SSepherosa Ziehau */ 475715516c77SSepherosa Ziehau txr->hn_sched_tx = 1; 475815516c77SSepherosa Ziehau 475915516c77SSepherosa Ziehau parent_dtag = bus_get_dma_tag(dev); 476015516c77SSepherosa Ziehau 476115516c77SSepherosa Ziehau /* DMA tag for RNDIS packet messages. */ 476215516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 476315516c77SSepherosa Ziehau HN_RNDIS_PKT_ALIGN, /* alignment */ 476415516c77SSepherosa Ziehau HN_RNDIS_PKT_BOUNDARY, /* boundary */ 476515516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 476615516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 476715516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 476815516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsize */ 476915516c77SSepherosa Ziehau 1, /* nsegments */ 477015516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsegsize */ 477115516c77SSepherosa Ziehau 0, /* flags */ 477215516c77SSepherosa Ziehau NULL, /* lockfunc */ 477315516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 477415516c77SSepherosa Ziehau &txr->hn_tx_rndis_dtag); 477515516c77SSepherosa Ziehau if (error) { 477615516c77SSepherosa Ziehau device_printf(dev, "failed to create rndis dmatag\n"); 477715516c77SSepherosa Ziehau return error; 477815516c77SSepherosa Ziehau } 477915516c77SSepherosa Ziehau 478015516c77SSepherosa Ziehau /* DMA tag for data. */ 478115516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 478215516c77SSepherosa Ziehau 1, /* alignment */ 478315516c77SSepherosa Ziehau HN_TX_DATA_BOUNDARY, /* boundary */ 478415516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 478515516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 478615516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 478715516c77SSepherosa Ziehau HN_TX_DATA_MAXSIZE, /* maxsize */ 478815516c77SSepherosa Ziehau HN_TX_DATA_SEGCNT_MAX, /* nsegments */ 478915516c77SSepherosa Ziehau HN_TX_DATA_SEGSIZE, /* maxsegsize */ 479015516c77SSepherosa Ziehau 0, /* flags */ 479115516c77SSepherosa Ziehau NULL, /* lockfunc */ 479215516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 479315516c77SSepherosa Ziehau &txr->hn_tx_data_dtag); 479415516c77SSepherosa Ziehau if (error) { 479515516c77SSepherosa Ziehau device_printf(dev, "failed to create data dmatag\n"); 479615516c77SSepherosa Ziehau return error; 479715516c77SSepherosa Ziehau } 479815516c77SSepherosa Ziehau 479915516c77SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) { 480015516c77SSepherosa Ziehau struct hn_txdesc *txd = &txr->hn_txdesc[i]; 480115516c77SSepherosa Ziehau 480215516c77SSepherosa Ziehau txd->txr = txr; 480315516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 4804dc13fee6SSepherosa Ziehau STAILQ_INIT(&txd->agg_list); 480515516c77SSepherosa Ziehau 480615516c77SSepherosa Ziehau /* 480715516c77SSepherosa Ziehau * Allocate and load RNDIS packet message. 480815516c77SSepherosa Ziehau */ 480915516c77SSepherosa Ziehau error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag, 481015516c77SSepherosa Ziehau (void **)&txd->rndis_pkt, 481115516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 481215516c77SSepherosa Ziehau &txd->rndis_pkt_dmap); 481315516c77SSepherosa Ziehau if (error) { 481415516c77SSepherosa Ziehau device_printf(dev, 481515516c77SSepherosa Ziehau "failed to allocate rndis_packet_msg, %d\n", i); 481615516c77SSepherosa Ziehau return error; 481715516c77SSepherosa Ziehau } 481815516c77SSepherosa Ziehau 481915516c77SSepherosa Ziehau error = bus_dmamap_load(txr->hn_tx_rndis_dtag, 482015516c77SSepherosa Ziehau txd->rndis_pkt_dmap, 482115516c77SSepherosa Ziehau txd->rndis_pkt, HN_RNDIS_PKT_LEN, 482215516c77SSepherosa Ziehau hyperv_dma_map_paddr, &txd->rndis_pkt_paddr, 482315516c77SSepherosa Ziehau BUS_DMA_NOWAIT); 482415516c77SSepherosa Ziehau if (error) { 482515516c77SSepherosa Ziehau device_printf(dev, 482615516c77SSepherosa Ziehau "failed to load rndis_packet_msg, %d\n", i); 482715516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 482815516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 482915516c77SSepherosa Ziehau return error; 483015516c77SSepherosa Ziehau } 483115516c77SSepherosa Ziehau 483215516c77SSepherosa Ziehau /* DMA map for TX data. */ 483315516c77SSepherosa Ziehau error = bus_dmamap_create(txr->hn_tx_data_dtag, 0, 483415516c77SSepherosa Ziehau &txd->data_dmap); 483515516c77SSepherosa Ziehau if (error) { 483615516c77SSepherosa Ziehau device_printf(dev, 483715516c77SSepherosa Ziehau "failed to allocate tx data dmamap\n"); 483815516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, 483915516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 484015516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 484115516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 484215516c77SSepherosa Ziehau return error; 484315516c77SSepherosa Ziehau } 484415516c77SSepherosa Ziehau 484515516c77SSepherosa Ziehau /* All set, put it to list */ 484615516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 484715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 484815516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 484915516c77SSepherosa Ziehau #else 485015516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 485115516c77SSepherosa Ziehau #endif 485215516c77SSepherosa Ziehau } 485315516c77SSepherosa Ziehau txr->hn_txdesc_avail = txr->hn_txdesc_cnt; 485415516c77SSepherosa Ziehau 485515516c77SSepherosa Ziehau if (sc->hn_tx_sysctl_tree != NULL) { 485615516c77SSepherosa Ziehau struct sysctl_oid_list *child; 485715516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 485815516c77SSepherosa Ziehau char name[16]; 485915516c77SSepherosa Ziehau 486015516c77SSepherosa Ziehau /* 486115516c77SSepherosa Ziehau * Create per TX ring sysctl tree: 486215516c77SSepherosa Ziehau * dev.hn.UNIT.tx.RINGID 486315516c77SSepherosa Ziehau */ 486415516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 486515516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree); 486615516c77SSepherosa Ziehau 486715516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", id); 486815516c77SSepherosa Ziehau txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, 486915516c77SSepherosa Ziehau name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 487015516c77SSepherosa Ziehau 487115516c77SSepherosa Ziehau if (txr->hn_tx_sysctl_tree != NULL) { 487215516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree); 487315516c77SSepherosa Ziehau 487485e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 487515516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail", 487615516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_txdesc_avail, 0, 487715516c77SSepherosa Ziehau "# of available TX descs"); 487885e4ae1eSSepherosa Ziehau #endif 487923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 488023bf9e15SSepherosa Ziehau if (!hn_use_if_start) 488123bf9e15SSepherosa Ziehau #endif 488223bf9e15SSepherosa Ziehau { 488315516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive", 488415516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_oactive, 0, 488515516c77SSepherosa Ziehau "over active"); 488615516c77SSepherosa Ziehau } 488715516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets", 488815516c77SSepherosa Ziehau CTLFLAG_RW, &txr->hn_pkts, 488915516c77SSepherosa Ziehau "# of packets transmitted"); 4890dc13fee6SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends", 4891dc13fee6SSepherosa Ziehau CTLFLAG_RW, &txr->hn_sends, "# of sends"); 489215516c77SSepherosa Ziehau } 489315516c77SSepherosa Ziehau } 489415516c77SSepherosa Ziehau 489515516c77SSepherosa Ziehau return 0; 489615516c77SSepherosa Ziehau } 489715516c77SSepherosa Ziehau 489815516c77SSepherosa Ziehau static void 489915516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd) 490015516c77SSepherosa Ziehau { 490115516c77SSepherosa Ziehau struct hn_tx_ring *txr = txd->txr; 490215516c77SSepherosa Ziehau 490315516c77SSepherosa Ziehau KASSERT(txd->m == NULL, ("still has mbuf installed")); 490415516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped")); 490515516c77SSepherosa Ziehau 490615516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap); 490715516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt, 490815516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 490915516c77SSepherosa Ziehau bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap); 491015516c77SSepherosa Ziehau } 491115516c77SSepherosa Ziehau 491215516c77SSepherosa Ziehau static void 491325641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd) 491425641fc7SSepherosa Ziehau { 491525641fc7SSepherosa Ziehau 491625641fc7SSepherosa Ziehau KASSERT(txd->refs == 0 || txd->refs == 1, 491725641fc7SSepherosa Ziehau ("invalid txd refs %d", txd->refs)); 491825641fc7SSepherosa Ziehau 491925641fc7SSepherosa Ziehau /* Aggregated txds will be freed by their aggregating txd. */ 492025641fc7SSepherosa Ziehau if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) { 492125641fc7SSepherosa Ziehau int freed; 492225641fc7SSepherosa Ziehau 492325641fc7SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 492425641fc7SSepherosa Ziehau KASSERT(freed, ("can't free txdesc")); 492525641fc7SSepherosa Ziehau } 492625641fc7SSepherosa Ziehau } 492725641fc7SSepherosa Ziehau 492825641fc7SSepherosa Ziehau static void 492915516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr) 493015516c77SSepherosa Ziehau { 493125641fc7SSepherosa Ziehau int i; 493215516c77SSepherosa Ziehau 493315516c77SSepherosa Ziehau if (txr->hn_txdesc == NULL) 493415516c77SSepherosa Ziehau return; 493515516c77SSepherosa Ziehau 493625641fc7SSepherosa Ziehau /* 493725641fc7SSepherosa Ziehau * NOTE: 493825641fc7SSepherosa Ziehau * Because the freeing of aggregated txds will be deferred 493925641fc7SSepherosa Ziehau * to the aggregating txd, two passes are used here: 494025641fc7SSepherosa Ziehau * - The first pass GCes any pending txds. This GC is necessary, 494125641fc7SSepherosa Ziehau * since if the channels are revoked, hypervisor will not 494225641fc7SSepherosa Ziehau * deliver send-done for all pending txds. 494325641fc7SSepherosa Ziehau * - The second pass frees the busdma stuffs, i.e. after all txds 494425641fc7SSepherosa Ziehau * were freed. 494525641fc7SSepherosa Ziehau */ 494625641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 494725641fc7SSepherosa Ziehau hn_txdesc_gc(txr, &txr->hn_txdesc[i]); 494825641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 494925641fc7SSepherosa Ziehau hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]); 495015516c77SSepherosa Ziehau 495115516c77SSepherosa Ziehau if (txr->hn_tx_data_dtag != NULL) 495215516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_data_dtag); 495315516c77SSepherosa Ziehau if (txr->hn_tx_rndis_dtag != NULL) 495415516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_rndis_dtag); 495515516c77SSepherosa Ziehau 495615516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 495715516c77SSepherosa Ziehau buf_ring_free(txr->hn_txdesc_br, M_DEVBUF); 495815516c77SSepherosa Ziehau #endif 495915516c77SSepherosa Ziehau 496015516c77SSepherosa Ziehau free(txr->hn_txdesc, M_DEVBUF); 496115516c77SSepherosa Ziehau txr->hn_txdesc = NULL; 496215516c77SSepherosa Ziehau 496315516c77SSepherosa Ziehau if (txr->hn_mbuf_br != NULL) 496415516c77SSepherosa Ziehau buf_ring_free(txr->hn_mbuf_br, M_DEVBUF); 496515516c77SSepherosa Ziehau 496615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 496715516c77SSepherosa Ziehau mtx_destroy(&txr->hn_txlist_spin); 496815516c77SSepherosa Ziehau #endif 496915516c77SSepherosa Ziehau mtx_destroy(&txr->hn_tx_lock); 497015516c77SSepherosa Ziehau } 497115516c77SSepherosa Ziehau 497215516c77SSepherosa Ziehau static int 497315516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt) 497415516c77SSepherosa Ziehau { 497515516c77SSepherosa Ziehau struct sysctl_oid_list *child; 497615516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 497715516c77SSepherosa Ziehau int i; 497815516c77SSepherosa Ziehau 497915516c77SSepherosa Ziehau /* 498015516c77SSepherosa Ziehau * Create TXBUF for chimney sending. 498115516c77SSepherosa Ziehau * 498215516c77SSepherosa Ziehau * NOTE: It is shared by all channels. 498315516c77SSepherosa Ziehau */ 498415516c77SSepherosa Ziehau sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), 498515516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma, 498615516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 498715516c77SSepherosa Ziehau if (sc->hn_chim == NULL) { 498815516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate txbuf failed\n"); 498915516c77SSepherosa Ziehau return (ENOMEM); 499015516c77SSepherosa Ziehau } 499115516c77SSepherosa Ziehau 499215516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = ring_cnt; 499315516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 499415516c77SSepherosa Ziehau 499515516c77SSepherosa Ziehau sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt, 499615516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 499715516c77SSepherosa Ziehau 499815516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(sc->hn_dev); 499915516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev)); 500015516c77SSepherosa Ziehau 500115516c77SSepherosa Ziehau /* Create dev.hn.UNIT.tx sysctl tree */ 500215516c77SSepherosa Ziehau sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx", 500315516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 500415516c77SSepherosa Ziehau 500515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 500615516c77SSepherosa Ziehau int error; 500715516c77SSepherosa Ziehau 500815516c77SSepherosa Ziehau error = hn_tx_ring_create(sc, i); 500915516c77SSepherosa Ziehau if (error) 501015516c77SSepherosa Ziehau return error; 501115516c77SSepherosa Ziehau } 501215516c77SSepherosa Ziehau 501315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs", 501415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 501515516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_no_txdescs), 501615516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs"); 501715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed", 501815516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 501915516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_send_failed), 502015516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure"); 502115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed", 502215516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 502315516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_txdma_failed), 502415516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure"); 5025dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed", 5026dc13fee6SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 5027dc13fee6SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_flush_failed), 5028dc13fee6SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", 5029dc13fee6SSepherosa Ziehau "# of packet transmission aggregation flush failure"); 503015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed", 503115516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 503215516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_collapsed), 503315516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed"); 503415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney", 503515516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 503615516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney), 503715516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send"); 503815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried", 503915516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 504015516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney_tried), 504115516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries"); 504215516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt", 504315516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0, 504415516c77SSepherosa Ziehau "# of total TX descs"); 504515516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max", 504615516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_chim_szmax, 0, 504715516c77SSepherosa Ziehau "Chimney send packet size upper boundary"); 504815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size", 504915516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 505015516c77SSepherosa Ziehau hn_chim_size_sysctl, "I", "Chimney send packet size limit"); 505115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size", 505215516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 505315516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_direct_tx_size), 505415516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 505515516c77SSepherosa Ziehau "Size of the packet for direct transmission"); 505615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx", 505715516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 505815516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_sched_tx), 505915516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 506015516c77SSepherosa Ziehau "Always schedule transmission " 506115516c77SSepherosa Ziehau "instead of doing direct transmission"); 506215516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt", 506315516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings"); 506415516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse", 506515516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings"); 5066dc13fee6SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax", 5067dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0, 5068dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation size"); 5069dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax", 5070dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 5071dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl, "I", 5072dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation packets"); 5073dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align", 5074dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 5075dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl, "I", 5076dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation alignment"); 507715516c77SSepherosa Ziehau 507815516c77SSepherosa Ziehau return 0; 507915516c77SSepherosa Ziehau } 508015516c77SSepherosa Ziehau 508115516c77SSepherosa Ziehau static void 508215516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size) 508315516c77SSepherosa Ziehau { 508415516c77SSepherosa Ziehau int i; 508515516c77SSepherosa Ziehau 5086a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 508715516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_chim_size = chim_size; 508815516c77SSepherosa Ziehau } 508915516c77SSepherosa Ziehau 509015516c77SSepherosa Ziehau static void 509115516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu) 509215516c77SSepherosa Ziehau { 509315516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 50949c6cae24SSepherosa Ziehau u_int hw_tsomax; 509515516c77SSepherosa Ziehau int tso_minlen; 509615516c77SSepherosa Ziehau 50979c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 50989c6cae24SSepherosa Ziehau 509915516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0) 510015516c77SSepherosa Ziehau return; 510115516c77SSepherosa Ziehau 510215516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_sgmin >= 2, 510315516c77SSepherosa Ziehau ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin)); 510415516c77SSepherosa Ziehau tso_minlen = sc->hn_ndis_tso_sgmin * mtu; 510515516c77SSepherosa Ziehau 510615516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen && 510715516c77SSepherosa Ziehau sc->hn_ndis_tso_szmax <= IP_MAXPACKET, 510815516c77SSepherosa Ziehau ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax)); 510915516c77SSepherosa Ziehau 511015516c77SSepherosa Ziehau if (tso_maxlen < tso_minlen) 511115516c77SSepherosa Ziehau tso_maxlen = tso_minlen; 511215516c77SSepherosa Ziehau else if (tso_maxlen > IP_MAXPACKET) 511315516c77SSepherosa Ziehau tso_maxlen = IP_MAXPACKET; 511415516c77SSepherosa Ziehau if (tso_maxlen > sc->hn_ndis_tso_szmax) 511515516c77SSepherosa Ziehau tso_maxlen = sc->hn_ndis_tso_szmax; 51169c6cae24SSepherosa Ziehau hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 51179c6cae24SSepherosa Ziehau 51189c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 51199c6cae24SSepherosa Ziehau if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax) 51209c6cae24SSepherosa Ziehau hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax; 51219c6cae24SSepherosa Ziehau } 51229c6cae24SSepherosa Ziehau ifp->if_hw_tsomax = hw_tsomax; 512315516c77SSepherosa Ziehau if (bootverbose) 512415516c77SSepherosa Ziehau if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax); 512515516c77SSepherosa Ziehau } 512615516c77SSepherosa Ziehau 512715516c77SSepherosa Ziehau static void 512815516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc) 512915516c77SSepherosa Ziehau { 513015516c77SSepherosa Ziehau uint64_t csum_assist; 513115516c77SSepherosa Ziehau int i; 513215516c77SSepherosa Ziehau 513315516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 513415516c77SSepherosa Ziehau if (hn_tx_chimney_size > 0 && 513515516c77SSepherosa Ziehau hn_tx_chimney_size < sc->hn_chim_szmax) 513615516c77SSepherosa Ziehau hn_set_chim_size(sc, hn_tx_chimney_size); 513715516c77SSepherosa Ziehau 513815516c77SSepherosa Ziehau csum_assist = 0; 513915516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_IPCS) 514015516c77SSepherosa Ziehau csum_assist |= CSUM_IP; 514115516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP4CS) 514215516c77SSepherosa Ziehau csum_assist |= CSUM_IP_TCP; 514315516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP4CS) 514415516c77SSepherosa Ziehau csum_assist |= CSUM_IP_UDP; 514515516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP6CS) 514615516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_TCP; 514715516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP6CS) 514815516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_UDP; 514915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 515015516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_csum_assist = csum_assist; 515115516c77SSepherosa Ziehau 515215516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_HASHVAL) { 515315516c77SSepherosa Ziehau /* 515415516c77SSepherosa Ziehau * Support HASHVAL pktinfo on TX path. 515515516c77SSepherosa Ziehau */ 515615516c77SSepherosa Ziehau if (bootverbose) 515715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n"); 515815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 515915516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL; 516015516c77SSepherosa Ziehau } 516115516c77SSepherosa Ziehau } 516215516c77SSepherosa Ziehau 516315516c77SSepherosa Ziehau static void 516415516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc) 516515516c77SSepherosa Ziehau { 516615516c77SSepherosa Ziehau int i; 516715516c77SSepherosa Ziehau 516815516c77SSepherosa Ziehau if (sc->hn_chim != NULL) { 51692494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) { 517015516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim); 51712494d735SSepherosa Ziehau } else { 51722494d735SSepherosa Ziehau device_printf(sc->hn_dev, 51732494d735SSepherosa Ziehau "chimney sending buffer is referenced"); 51742494d735SSepherosa Ziehau } 517515516c77SSepherosa Ziehau sc->hn_chim = NULL; 517615516c77SSepherosa Ziehau } 517715516c77SSepherosa Ziehau 517815516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt == 0) 517915516c77SSepherosa Ziehau return; 518015516c77SSepherosa Ziehau 518115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 518215516c77SSepherosa Ziehau hn_tx_ring_destroy(&sc->hn_tx_ring[i]); 518315516c77SSepherosa Ziehau 518415516c77SSepherosa Ziehau free(sc->hn_tx_ring, M_DEVBUF); 518515516c77SSepherosa Ziehau sc->hn_tx_ring = NULL; 518615516c77SSepherosa Ziehau 518715516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = 0; 518815516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = 0; 518915516c77SSepherosa Ziehau } 519015516c77SSepherosa Ziehau 519123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 519223bf9e15SSepherosa Ziehau 519315516c77SSepherosa Ziehau static void 519415516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused) 519515516c77SSepherosa Ziehau { 519615516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 519715516c77SSepherosa Ziehau 519815516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 519915516c77SSepherosa Ziehau hn_start_locked(txr, 0); 520015516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 520115516c77SSepherosa Ziehau } 520215516c77SSepherosa Ziehau 520323bf9e15SSepherosa Ziehau static int 520423bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len) 520523bf9e15SSepherosa Ziehau { 520623bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 520723bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 5208dc13fee6SSepherosa Ziehau int sched = 0; 520923bf9e15SSepherosa Ziehau 521023bf9e15SSepherosa Ziehau KASSERT(hn_use_if_start, 521123bf9e15SSepherosa Ziehau ("hn_start_locked is called, when if_start is disabled")); 521223bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 521323bf9e15SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 5214dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 521523bf9e15SSepherosa Ziehau 521623bf9e15SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 5217dc13fee6SSepherosa Ziehau return (0); 521823bf9e15SSepherosa Ziehau 521923bf9e15SSepherosa Ziehau if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 522023bf9e15SSepherosa Ziehau IFF_DRV_RUNNING) 5221dc13fee6SSepherosa Ziehau return (0); 522223bf9e15SSepherosa Ziehau 522323bf9e15SSepherosa Ziehau while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 522423bf9e15SSepherosa Ziehau struct hn_txdesc *txd; 522523bf9e15SSepherosa Ziehau struct mbuf *m_head; 522623bf9e15SSepherosa Ziehau int error; 522723bf9e15SSepherosa Ziehau 522823bf9e15SSepherosa Ziehau IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 522923bf9e15SSepherosa Ziehau if (m_head == NULL) 523023bf9e15SSepherosa Ziehau break; 523123bf9e15SSepherosa Ziehau 523223bf9e15SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 523323bf9e15SSepherosa Ziehau /* 523423bf9e15SSepherosa Ziehau * This sending could be time consuming; let callers 523523bf9e15SSepherosa Ziehau * dispatch this packet sending (and sending of any 523623bf9e15SSepherosa Ziehau * following up packets) to tx taskqueue. 523723bf9e15SSepherosa Ziehau */ 523823bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 5239dc13fee6SSepherosa Ziehau sched = 1; 5240dc13fee6SSepherosa Ziehau break; 524123bf9e15SSepherosa Ziehau } 524223bf9e15SSepherosa Ziehau 5243edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 5244edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 5245edd3f315SSepherosa Ziehau m_head = hn_tso_fixup(m_head); 5246edd3f315SSepherosa Ziehau if (__predict_false(m_head == NULL)) { 5247edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 5248edd3f315SSepherosa Ziehau continue; 5249edd3f315SSepherosa Ziehau } 5250edd3f315SSepherosa Ziehau } 5251edd3f315SSepherosa Ziehau #endif 5252edd3f315SSepherosa Ziehau 525323bf9e15SSepherosa Ziehau txd = hn_txdesc_get(txr); 525423bf9e15SSepherosa Ziehau if (txd == NULL) { 525523bf9e15SSepherosa Ziehau txr->hn_no_txdescs++; 525623bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 525723bf9e15SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 525823bf9e15SSepherosa Ziehau break; 525923bf9e15SSepherosa Ziehau } 526023bf9e15SSepherosa Ziehau 5261dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 526223bf9e15SSepherosa Ziehau if (error) { 526323bf9e15SSepherosa Ziehau /* Both txd and m_head are freed */ 5264dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 5265dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 526623bf9e15SSepherosa Ziehau continue; 526723bf9e15SSepherosa Ziehau } 526823bf9e15SSepherosa Ziehau 5269dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 5270dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 5271dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5272dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5273dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 5274dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 5275dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 5276dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 5277dc13fee6SSepherosa Ziehau break; 5278dc13fee6SSepherosa Ziehau } 5279dc13fee6SSepherosa Ziehau } else { 5280dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 528123bf9e15SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 528223bf9e15SSepherosa Ziehau if (__predict_false(error)) { 528323bf9e15SSepherosa Ziehau /* txd is freed, but m_head is not */ 528423bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 5285dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 5286dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 528723bf9e15SSepherosa Ziehau break; 528823bf9e15SSepherosa Ziehau } 528923bf9e15SSepherosa Ziehau } 5290dc13fee6SSepherosa Ziehau } 5291dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 5292dc13fee6SSepherosa Ziehau else { 5293dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 5294dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 5295dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5296dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5297dc13fee6SSepherosa Ziehau } 5298dc13fee6SSepherosa Ziehau #endif 5299dc13fee6SSepherosa Ziehau } 5300dc13fee6SSepherosa Ziehau 5301dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 5302dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 5303dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 5304dc13fee6SSepherosa Ziehau return (sched); 530523bf9e15SSepherosa Ziehau } 530623bf9e15SSepherosa Ziehau 530723bf9e15SSepherosa Ziehau static void 530823bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp) 530923bf9e15SSepherosa Ziehau { 531023bf9e15SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 531123bf9e15SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[0]; 531223bf9e15SSepherosa Ziehau 531323bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 531423bf9e15SSepherosa Ziehau goto do_sched; 531523bf9e15SSepherosa Ziehau 531623bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 531723bf9e15SSepherosa Ziehau int sched; 531823bf9e15SSepherosa Ziehau 531923bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 532023bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 532123bf9e15SSepherosa Ziehau if (!sched) 532223bf9e15SSepherosa Ziehau return; 532323bf9e15SSepherosa Ziehau } 532423bf9e15SSepherosa Ziehau do_sched: 532523bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 532623bf9e15SSepherosa Ziehau } 532723bf9e15SSepherosa Ziehau 532815516c77SSepherosa Ziehau static void 532915516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused) 533015516c77SSepherosa Ziehau { 533115516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 533215516c77SSepherosa Ziehau 533315516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 533415516c77SSepherosa Ziehau atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE); 533515516c77SSepherosa Ziehau hn_start_locked(txr, 0); 533615516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 533715516c77SSepherosa Ziehau } 533815516c77SSepherosa Ziehau 533923bf9e15SSepherosa Ziehau static void 534023bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr) 534123bf9e15SSepherosa Ziehau { 534223bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 534323bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 534423bf9e15SSepherosa Ziehau 534523bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 534623bf9e15SSepherosa Ziehau 534723bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 534823bf9e15SSepherosa Ziehau goto do_sched; 534923bf9e15SSepherosa Ziehau 535023bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 535123bf9e15SSepherosa Ziehau int sched; 535223bf9e15SSepherosa Ziehau 535323bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 535423bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 535523bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 535623bf9e15SSepherosa Ziehau if (sched) { 535723bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 535823bf9e15SSepherosa Ziehau &txr->hn_tx_task); 535923bf9e15SSepherosa Ziehau } 536023bf9e15SSepherosa Ziehau } else { 536123bf9e15SSepherosa Ziehau do_sched: 536223bf9e15SSepherosa Ziehau /* 536323bf9e15SSepherosa Ziehau * Release the OACTIVE earlier, with the hope, that 536423bf9e15SSepherosa Ziehau * others could catch up. The task will clear the 536523bf9e15SSepherosa Ziehau * flag again with the hn_tx_lock to avoid possible 536623bf9e15SSepherosa Ziehau * races. 536723bf9e15SSepherosa Ziehau */ 536823bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 536923bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 537023bf9e15SSepherosa Ziehau } 537123bf9e15SSepherosa Ziehau } 537223bf9e15SSepherosa Ziehau 537323bf9e15SSepherosa Ziehau #endif /* HN_IFSTART_SUPPORT */ 537423bf9e15SSepherosa Ziehau 537515516c77SSepherosa Ziehau static int 537615516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len) 537715516c77SSepherosa Ziehau { 537815516c77SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 537915516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 538015516c77SSepherosa Ziehau struct mbuf *m_head; 5381dc13fee6SSepherosa Ziehau int sched = 0; 538215516c77SSepherosa Ziehau 538315516c77SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 538423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 538515516c77SSepherosa Ziehau KASSERT(hn_use_if_start == 0, 538615516c77SSepherosa Ziehau ("hn_xmit is called, when if_start is enabled")); 538723bf9e15SSepherosa Ziehau #endif 5388dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 538915516c77SSepherosa Ziehau 539015516c77SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 5391dc13fee6SSepherosa Ziehau return (0); 539215516c77SSepherosa Ziehau 539315516c77SSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive) 5394dc13fee6SSepherosa Ziehau return (0); 539515516c77SSepherosa Ziehau 539615516c77SSepherosa Ziehau while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) { 539715516c77SSepherosa Ziehau struct hn_txdesc *txd; 539815516c77SSepherosa Ziehau int error; 539915516c77SSepherosa Ziehau 540015516c77SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 540115516c77SSepherosa Ziehau /* 540215516c77SSepherosa Ziehau * This sending could be time consuming; let callers 540315516c77SSepherosa Ziehau * dispatch this packet sending (and sending of any 540415516c77SSepherosa Ziehau * following up packets) to tx taskqueue. 540515516c77SSepherosa Ziehau */ 540615516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 5407dc13fee6SSepherosa Ziehau sched = 1; 5408dc13fee6SSepherosa Ziehau break; 540915516c77SSepherosa Ziehau } 541015516c77SSepherosa Ziehau 541115516c77SSepherosa Ziehau txd = hn_txdesc_get(txr); 541215516c77SSepherosa Ziehau if (txd == NULL) { 541315516c77SSepherosa Ziehau txr->hn_no_txdescs++; 541415516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 541515516c77SSepherosa Ziehau txr->hn_oactive = 1; 541615516c77SSepherosa Ziehau break; 541715516c77SSepherosa Ziehau } 541815516c77SSepherosa Ziehau 5419dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 542015516c77SSepherosa Ziehau if (error) { 542115516c77SSepherosa Ziehau /* Both txd and m_head are freed; discard */ 5422dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 5423dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 542415516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 542515516c77SSepherosa Ziehau continue; 542615516c77SSepherosa Ziehau } 542715516c77SSepherosa Ziehau 5428dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 5429dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 5430dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5431dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5432dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 543315516c77SSepherosa Ziehau if (__predict_false(error)) { 543415516c77SSepherosa Ziehau txr->hn_oactive = 1; 543515516c77SSepherosa Ziehau break; 543615516c77SSepherosa Ziehau } 5437dc13fee6SSepherosa Ziehau } else { 5438dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 5439dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 5440dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 5441dc13fee6SSepherosa Ziehau /* txd is freed, but m_head is not */ 5442dc13fee6SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, 5443dc13fee6SSepherosa Ziehau m_head); 5444dc13fee6SSepherosa Ziehau txr->hn_oactive = 1; 5445dc13fee6SSepherosa Ziehau break; 5446dc13fee6SSepherosa Ziehau } 5447dc13fee6SSepherosa Ziehau } 5448dc13fee6SSepherosa Ziehau } 5449dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 5450dc13fee6SSepherosa Ziehau else { 5451dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 5452dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 5453dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5454dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5455dc13fee6SSepherosa Ziehau } 5456dc13fee6SSepherosa Ziehau #endif 545715516c77SSepherosa Ziehau 545815516c77SSepherosa Ziehau /* Sent */ 545915516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 546015516c77SSepherosa Ziehau } 5461dc13fee6SSepherosa Ziehau 5462dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 5463dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 5464dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 5465dc13fee6SSepherosa Ziehau return (sched); 546615516c77SSepherosa Ziehau } 546715516c77SSepherosa Ziehau 546815516c77SSepherosa Ziehau static int 546915516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m) 547015516c77SSepherosa Ziehau { 547115516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 547215516c77SSepherosa Ziehau struct hn_tx_ring *txr; 547315516c77SSepherosa Ziehau int error, idx = 0; 547415516c77SSepherosa Ziehau 54759c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) { 54769c6cae24SSepherosa Ziehau struct rm_priotracker pt; 54779c6cae24SSepherosa Ziehau 54789c6cae24SSepherosa Ziehau rm_rlock(&sc->hn_vf_lock, &pt); 54799c6cae24SSepherosa Ziehau if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { 54809c6cae24SSepherosa Ziehau struct mbuf *m_bpf = NULL; 54819c6cae24SSepherosa Ziehau int obytes, omcast; 54829c6cae24SSepherosa Ziehau 54839c6cae24SSepherosa Ziehau obytes = m->m_pkthdr.len; 54849c6cae24SSepherosa Ziehau if (m->m_flags & M_MCAST) 54859c6cae24SSepherosa Ziehau omcast = 1; 54869c6cae24SSepherosa Ziehau 54879c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) { 54889c6cae24SSepherosa Ziehau if (bpf_peers_present(ifp->if_bpf)) { 54899c6cae24SSepherosa Ziehau m_bpf = m_copypacket(m, M_NOWAIT); 54909c6cae24SSepherosa Ziehau if (m_bpf == NULL) { 54919c6cae24SSepherosa Ziehau /* 54929c6cae24SSepherosa Ziehau * Failed to grab a shallow 54939c6cae24SSepherosa Ziehau * copy; tap now. 54949c6cae24SSepherosa Ziehau */ 54959c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m); 54969c6cae24SSepherosa Ziehau } 54979c6cae24SSepherosa Ziehau } 54989c6cae24SSepherosa Ziehau } else { 54999c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m); 55009c6cae24SSepherosa Ziehau } 55019c6cae24SSepherosa Ziehau 55029c6cae24SSepherosa Ziehau error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m); 55039c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 55049c6cae24SSepherosa Ziehau 55059c6cae24SSepherosa Ziehau if (m_bpf != NULL) { 55069c6cae24SSepherosa Ziehau if (!error) 55079c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m_bpf); 55089c6cae24SSepherosa Ziehau m_freem(m_bpf); 55099c6cae24SSepherosa Ziehau } 55109c6cae24SSepherosa Ziehau 55119c6cae24SSepherosa Ziehau if (error == ENOBUFS) { 55129c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 55139c6cae24SSepherosa Ziehau } else if (error) { 55149c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 55159c6cae24SSepherosa Ziehau } else { 55169c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 55179c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes); 55189c6cae24SSepherosa Ziehau if (omcast) { 55199c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 55209c6cae24SSepherosa Ziehau omcast); 55219c6cae24SSepherosa Ziehau } 55229c6cae24SSepherosa Ziehau } 55239c6cae24SSepherosa Ziehau return (error); 55249c6cae24SSepherosa Ziehau } 55259c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 55269c6cae24SSepherosa Ziehau } 55279c6cae24SSepherosa Ziehau 5528edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 5529edd3f315SSepherosa Ziehau /* 5530edd3f315SSepherosa Ziehau * Perform TSO packet header fixup now, since the TSO 5531edd3f315SSepherosa Ziehau * packet header should be cache-hot. 5532edd3f315SSepherosa Ziehau */ 5533edd3f315SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 5534edd3f315SSepherosa Ziehau m = hn_tso_fixup(m); 5535edd3f315SSepherosa Ziehau if (__predict_false(m == NULL)) { 5536edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 5537edd3f315SSepherosa Ziehau return EIO; 5538edd3f315SSepherosa Ziehau } 5539edd3f315SSepherosa Ziehau } 5540edd3f315SSepherosa Ziehau #endif 5541edd3f315SSepherosa Ziehau 554215516c77SSepherosa Ziehau /* 554315516c77SSepherosa Ziehau * Select the TX ring based on flowid 554415516c77SSepherosa Ziehau */ 554534d68912SSepherosa Ziehau if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 554634d68912SSepherosa Ziehau #ifdef RSS 554734d68912SSepherosa Ziehau uint32_t bid; 554834d68912SSepherosa Ziehau 554934d68912SSepherosa Ziehau if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m), 555034d68912SSepherosa Ziehau &bid) == 0) 555134d68912SSepherosa Ziehau idx = bid % sc->hn_tx_ring_inuse; 555234d68912SSepherosa Ziehau else 555334d68912SSepherosa Ziehau #endif 5554cc0c6ebcSSepherosa Ziehau { 5555cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET) 5556cc0c6ebcSSepherosa Ziehau int tcpsyn = 0; 5557cc0c6ebcSSepherosa Ziehau 5558cc0c6ebcSSepherosa Ziehau if (m->m_pkthdr.len < 128 && 5559cc0c6ebcSSepherosa Ziehau (m->m_pkthdr.csum_flags & 5560cc0c6ebcSSepherosa Ziehau (CSUM_IP_TCP | CSUM_IP6_TCP)) && 5561cc0c6ebcSSepherosa Ziehau (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) { 5562cc0c6ebcSSepherosa Ziehau m = hn_check_tcpsyn(m, &tcpsyn); 5563cc0c6ebcSSepherosa Ziehau if (__predict_false(m == NULL)) { 5564cc0c6ebcSSepherosa Ziehau if_inc_counter(ifp, 5565cc0c6ebcSSepherosa Ziehau IFCOUNTER_OERRORS, 1); 5566cc0c6ebcSSepherosa Ziehau return (EIO); 5567cc0c6ebcSSepherosa Ziehau } 5568cc0c6ebcSSepherosa Ziehau } 5569cc0c6ebcSSepherosa Ziehau #else 5570cc0c6ebcSSepherosa Ziehau const int tcpsyn = 0; 5571cc0c6ebcSSepherosa Ziehau #endif 5572cc0c6ebcSSepherosa Ziehau if (tcpsyn) 5573cc0c6ebcSSepherosa Ziehau idx = 0; 5574cc0c6ebcSSepherosa Ziehau else 557515516c77SSepherosa Ziehau idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse; 557634d68912SSepherosa Ziehau } 5577cc0c6ebcSSepherosa Ziehau } 557815516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 557915516c77SSepherosa Ziehau 558015516c77SSepherosa Ziehau error = drbr_enqueue(ifp, txr->hn_mbuf_br, m); 558115516c77SSepherosa Ziehau if (error) { 558215516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 558315516c77SSepherosa Ziehau return error; 558415516c77SSepherosa Ziehau } 558515516c77SSepherosa Ziehau 558615516c77SSepherosa Ziehau if (txr->hn_oactive) 558715516c77SSepherosa Ziehau return 0; 558815516c77SSepherosa Ziehau 558915516c77SSepherosa Ziehau if (txr->hn_sched_tx) 559015516c77SSepherosa Ziehau goto do_sched; 559115516c77SSepherosa Ziehau 559215516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 559315516c77SSepherosa Ziehau int sched; 559415516c77SSepherosa Ziehau 559515516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 559615516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 559715516c77SSepherosa Ziehau if (!sched) 559815516c77SSepherosa Ziehau return 0; 559915516c77SSepherosa Ziehau } 560015516c77SSepherosa Ziehau do_sched: 560115516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 560215516c77SSepherosa Ziehau return 0; 560315516c77SSepherosa Ziehau } 560415516c77SSepherosa Ziehau 560515516c77SSepherosa Ziehau static void 560615516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr) 560715516c77SSepherosa Ziehau { 560815516c77SSepherosa Ziehau struct mbuf *m; 560915516c77SSepherosa Ziehau 561015516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 561115516c77SSepherosa Ziehau while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL) 561215516c77SSepherosa Ziehau m_freem(m); 561315516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 561415516c77SSepherosa Ziehau } 561515516c77SSepherosa Ziehau 561615516c77SSepherosa Ziehau static void 561715516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp) 561815516c77SSepherosa Ziehau { 561915516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 56209c6cae24SSepherosa Ziehau struct rm_priotracker pt; 562115516c77SSepherosa Ziehau int i; 562215516c77SSepherosa Ziehau 562315516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 562415516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 562515516c77SSepherosa Ziehau if_qflush(ifp); 56269c6cae24SSepherosa Ziehau 56279c6cae24SSepherosa Ziehau rm_rlock(&sc->hn_vf_lock, &pt); 56289c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 56299c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp); 56309c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 563115516c77SSepherosa Ziehau } 563215516c77SSepherosa Ziehau 563315516c77SSepherosa Ziehau static void 563415516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr) 563515516c77SSepherosa Ziehau { 563615516c77SSepherosa Ziehau 563715516c77SSepherosa Ziehau if (txr->hn_sched_tx) 563815516c77SSepherosa Ziehau goto do_sched; 563915516c77SSepherosa Ziehau 564015516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 564115516c77SSepherosa Ziehau int sched; 564215516c77SSepherosa Ziehau 564315516c77SSepherosa Ziehau txr->hn_oactive = 0; 564415516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 564515516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 564615516c77SSepherosa Ziehau if (sched) { 564715516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 564815516c77SSepherosa Ziehau &txr->hn_tx_task); 564915516c77SSepherosa Ziehau } 565015516c77SSepherosa Ziehau } else { 565115516c77SSepherosa Ziehau do_sched: 565215516c77SSepherosa Ziehau /* 565315516c77SSepherosa Ziehau * Release the oactive earlier, with the hope, that 565415516c77SSepherosa Ziehau * others could catch up. The task will clear the 565515516c77SSepherosa Ziehau * oactive again with the hn_tx_lock to avoid possible 565615516c77SSepherosa Ziehau * races. 565715516c77SSepherosa Ziehau */ 565815516c77SSepherosa Ziehau txr->hn_oactive = 0; 565915516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 566015516c77SSepherosa Ziehau } 566115516c77SSepherosa Ziehau } 566215516c77SSepherosa Ziehau 566315516c77SSepherosa Ziehau static void 566415516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused) 566515516c77SSepherosa Ziehau { 566615516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 566715516c77SSepherosa Ziehau 566815516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 566915516c77SSepherosa Ziehau hn_xmit(txr, 0); 567015516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 567115516c77SSepherosa Ziehau } 567215516c77SSepherosa Ziehau 567315516c77SSepherosa Ziehau static void 567415516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused) 567515516c77SSepherosa Ziehau { 567615516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 567715516c77SSepherosa Ziehau 567815516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 567915516c77SSepherosa Ziehau txr->hn_oactive = 0; 568015516c77SSepherosa Ziehau hn_xmit(txr, 0); 568115516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 568215516c77SSepherosa Ziehau } 568315516c77SSepherosa Ziehau 568415516c77SSepherosa Ziehau static int 568515516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan) 568615516c77SSepherosa Ziehau { 568715516c77SSepherosa Ziehau struct vmbus_chan_br cbr; 568815516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 568915516c77SSepherosa Ziehau struct hn_tx_ring *txr = NULL; 569015516c77SSepherosa Ziehau int idx, error; 569115516c77SSepherosa Ziehau 569215516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 569315516c77SSepherosa Ziehau 569415516c77SSepherosa Ziehau /* 569515516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 569615516c77SSepherosa Ziehau */ 569715516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 569815516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 569915516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 570015516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 570115516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0, 570215516c77SSepherosa Ziehau ("RX ring %d already attached", idx)); 570315516c77SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED; 57043ab0fea1SDexuan Cui rxr->hn_chan = chan; 570515516c77SSepherosa Ziehau 570615516c77SSepherosa Ziehau if (bootverbose) { 570715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n", 570815516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 570915516c77SSepherosa Ziehau } 571015516c77SSepherosa Ziehau 571115516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 571215516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 571315516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0, 571415516c77SSepherosa Ziehau ("TX ring %d already attached", idx)); 571515516c77SSepherosa Ziehau txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED; 571615516c77SSepherosa Ziehau 571715516c77SSepherosa Ziehau txr->hn_chan = chan; 571815516c77SSepherosa Ziehau if (bootverbose) { 571915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n", 572015516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 572115516c77SSepherosa Ziehau } 572215516c77SSepherosa Ziehau } 572315516c77SSepherosa Ziehau 572415516c77SSepherosa Ziehau /* Bind this channel to a proper CPU. */ 57250e11868dSSepherosa Ziehau vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx)); 572615516c77SSepherosa Ziehau 572715516c77SSepherosa Ziehau /* 572815516c77SSepherosa Ziehau * Open this channel 572915516c77SSepherosa Ziehau */ 573015516c77SSepherosa Ziehau cbr.cbr = rxr->hn_br; 573115516c77SSepherosa Ziehau cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr; 573215516c77SSepherosa Ziehau cbr.cbr_txsz = HN_TXBR_SIZE; 573315516c77SSepherosa Ziehau cbr.cbr_rxsz = HN_RXBR_SIZE; 573415516c77SSepherosa Ziehau error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr); 573515516c77SSepherosa Ziehau if (error) { 573671e8ac56SSepherosa Ziehau if (error == EISCONN) { 573771e8ac56SSepherosa Ziehau if_printf(sc->hn_ifp, "bufring is connected after " 573871e8ac56SSepherosa Ziehau "chan%u open failure\n", vmbus_chan_id(chan)); 573971e8ac56SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 574071e8ac56SSepherosa Ziehau } else { 574115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "open chan%u failed: %d\n", 574215516c77SSepherosa Ziehau vmbus_chan_id(chan), error); 574371e8ac56SSepherosa Ziehau } 574415516c77SSepherosa Ziehau } 574515516c77SSepherosa Ziehau return (error); 574615516c77SSepherosa Ziehau } 574715516c77SSepherosa Ziehau 574815516c77SSepherosa Ziehau static void 574915516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan) 575015516c77SSepherosa Ziehau { 575115516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 57522494d735SSepherosa Ziehau int idx, error; 575315516c77SSepherosa Ziehau 575415516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 575515516c77SSepherosa Ziehau 575615516c77SSepherosa Ziehau /* 575715516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 575815516c77SSepherosa Ziehau */ 575915516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 576015516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 576115516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 576215516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 576315516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED), 576415516c77SSepherosa Ziehau ("RX ring %d is not attached", idx)); 576515516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 576615516c77SSepherosa Ziehau 576715516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 576815516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[idx]; 576915516c77SSepherosa Ziehau 577015516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED), 577115516c77SSepherosa Ziehau ("TX ring %d is not attached attached", idx)); 577215516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 577315516c77SSepherosa Ziehau } 577415516c77SSepherosa Ziehau 577515516c77SSepherosa Ziehau /* 577615516c77SSepherosa Ziehau * Close this channel. 577715516c77SSepherosa Ziehau * 577815516c77SSepherosa Ziehau * NOTE: 577915516c77SSepherosa Ziehau * Channel closing does _not_ destroy the target channel. 578015516c77SSepherosa Ziehau */ 57812494d735SSepherosa Ziehau error = vmbus_chan_close_direct(chan); 57822494d735SSepherosa Ziehau if (error == EISCONN) { 5783aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u bufring is connected " 5784aa1a2adcSSepherosa Ziehau "after being closed\n", vmbus_chan_id(chan)); 57852494d735SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 57862494d735SSepherosa Ziehau } else if (error) { 5787aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u close failed: %d\n", 5788aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), error); 57892494d735SSepherosa Ziehau } 579015516c77SSepherosa Ziehau } 579115516c77SSepherosa Ziehau 579215516c77SSepherosa Ziehau static int 579315516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc) 579415516c77SSepherosa Ziehau { 579515516c77SSepherosa Ziehau struct vmbus_channel **subchans; 579615516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 579715516c77SSepherosa Ziehau int i, error = 0; 579815516c77SSepherosa Ziehau 579971e8ac56SSepherosa Ziehau KASSERT(subchan_cnt > 0, ("no sub-channels")); 580015516c77SSepherosa Ziehau 580115516c77SSepherosa Ziehau /* Attach the sub-channels. */ 580215516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 580315516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) { 580471e8ac56SSepherosa Ziehau int error1; 580571e8ac56SSepherosa Ziehau 580671e8ac56SSepherosa Ziehau error1 = hn_chan_attach(sc, subchans[i]); 580771e8ac56SSepherosa Ziehau if (error1) { 580871e8ac56SSepherosa Ziehau error = error1; 580971e8ac56SSepherosa Ziehau /* Move on; all channels will be detached later. */ 581071e8ac56SSepherosa Ziehau } 581115516c77SSepherosa Ziehau } 581215516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 581315516c77SSepherosa Ziehau 581415516c77SSepherosa Ziehau if (error) { 581515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error); 581615516c77SSepherosa Ziehau } else { 581715516c77SSepherosa Ziehau if (bootverbose) { 581815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d sub-channels attached\n", 581915516c77SSepherosa Ziehau subchan_cnt); 582015516c77SSepherosa Ziehau } 582115516c77SSepherosa Ziehau } 582215516c77SSepherosa Ziehau return (error); 582315516c77SSepherosa Ziehau } 582415516c77SSepherosa Ziehau 582515516c77SSepherosa Ziehau static void 582615516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc) 582715516c77SSepherosa Ziehau { 582815516c77SSepherosa Ziehau struct vmbus_channel **subchans; 582915516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 583015516c77SSepherosa Ziehau int i; 583115516c77SSepherosa Ziehau 583215516c77SSepherosa Ziehau if (subchan_cnt == 0) 583315516c77SSepherosa Ziehau goto back; 583415516c77SSepherosa Ziehau 583515516c77SSepherosa Ziehau /* Detach the sub-channels. */ 583615516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 583715516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) 583815516c77SSepherosa Ziehau hn_chan_detach(sc, subchans[i]); 583915516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 584015516c77SSepherosa Ziehau 584115516c77SSepherosa Ziehau back: 584215516c77SSepherosa Ziehau /* 584315516c77SSepherosa Ziehau * Detach the primary channel, _after_ all sub-channels 584415516c77SSepherosa Ziehau * are detached. 584515516c77SSepherosa Ziehau */ 584615516c77SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 584715516c77SSepherosa Ziehau 584815516c77SSepherosa Ziehau /* Wait for sub-channels to be destroyed, if any. */ 584915516c77SSepherosa Ziehau vmbus_subchan_drain(sc->hn_prichan); 585015516c77SSepherosa Ziehau 585115516c77SSepherosa Ziehau #ifdef INVARIANTS 585215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 585315516c77SSepherosa Ziehau KASSERT((sc->hn_rx_ring[i].hn_rx_flags & 585415516c77SSepherosa Ziehau HN_RX_FLAG_ATTACHED) == 0, 585515516c77SSepherosa Ziehau ("%dth RX ring is still attached", i)); 585615516c77SSepherosa Ziehau } 585715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 585815516c77SSepherosa Ziehau KASSERT((sc->hn_tx_ring[i].hn_tx_flags & 585915516c77SSepherosa Ziehau HN_TX_FLAG_ATTACHED) == 0, 586015516c77SSepherosa Ziehau ("%dth TX ring is still attached", i)); 586115516c77SSepherosa Ziehau } 586215516c77SSepherosa Ziehau #endif 586315516c77SSepherosa Ziehau } 586415516c77SSepherosa Ziehau 586515516c77SSepherosa Ziehau static int 586615516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch) 586715516c77SSepherosa Ziehau { 586815516c77SSepherosa Ziehau struct vmbus_channel **subchans; 586915516c77SSepherosa Ziehau int nchan, rxr_cnt, error; 587015516c77SSepherosa Ziehau 587115516c77SSepherosa Ziehau nchan = *nsubch + 1; 587215516c77SSepherosa Ziehau if (nchan == 1) { 587315516c77SSepherosa Ziehau /* 587415516c77SSepherosa Ziehau * Multiple RX/TX rings are not requested. 587515516c77SSepherosa Ziehau */ 587615516c77SSepherosa Ziehau *nsubch = 0; 587715516c77SSepherosa Ziehau return (0); 587815516c77SSepherosa Ziehau } 587915516c77SSepherosa Ziehau 588015516c77SSepherosa Ziehau /* 588115516c77SSepherosa Ziehau * Query RSS capabilities, e.g. # of RX rings, and # of indirect 588215516c77SSepherosa Ziehau * table entries. 588315516c77SSepherosa Ziehau */ 588415516c77SSepherosa Ziehau error = hn_rndis_query_rsscaps(sc, &rxr_cnt); 588515516c77SSepherosa Ziehau if (error) { 588615516c77SSepherosa Ziehau /* No RSS; this is benign. */ 588715516c77SSepherosa Ziehau *nsubch = 0; 588815516c77SSepherosa Ziehau return (0); 588915516c77SSepherosa Ziehau } 589015516c77SSepherosa Ziehau if (bootverbose) { 589115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n", 589215516c77SSepherosa Ziehau rxr_cnt, nchan); 589315516c77SSepherosa Ziehau } 589415516c77SSepherosa Ziehau 589515516c77SSepherosa Ziehau if (nchan > rxr_cnt) 589615516c77SSepherosa Ziehau nchan = rxr_cnt; 589715516c77SSepherosa Ziehau if (nchan == 1) { 589815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n"); 589915516c77SSepherosa Ziehau *nsubch = 0; 590015516c77SSepherosa Ziehau return (0); 590115516c77SSepherosa Ziehau } 590215516c77SSepherosa Ziehau 590315516c77SSepherosa Ziehau /* 590415516c77SSepherosa Ziehau * Allocate sub-channels from NVS. 590515516c77SSepherosa Ziehau */ 590615516c77SSepherosa Ziehau *nsubch = nchan - 1; 590715516c77SSepherosa Ziehau error = hn_nvs_alloc_subchans(sc, nsubch); 590815516c77SSepherosa Ziehau if (error || *nsubch == 0) { 590915516c77SSepherosa Ziehau /* Failed to allocate sub-channels. */ 591015516c77SSepherosa Ziehau *nsubch = 0; 591115516c77SSepherosa Ziehau return (0); 591215516c77SSepherosa Ziehau } 591315516c77SSepherosa Ziehau 591415516c77SSepherosa Ziehau /* 591515516c77SSepherosa Ziehau * Wait for all sub-channels to become ready before moving on. 591615516c77SSepherosa Ziehau */ 591715516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch); 591815516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, *nsubch); 591915516c77SSepherosa Ziehau return (0); 592015516c77SSepherosa Ziehau } 592115516c77SSepherosa Ziehau 59222494d735SSepherosa Ziehau static bool 59232494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc) 59242494d735SSepherosa Ziehau { 59252494d735SSepherosa Ziehau int i; 59262494d735SSepherosa Ziehau 59272494d735SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_ERRORS) 59282494d735SSepherosa Ziehau return (false); 59292494d735SSepherosa Ziehau 59302494d735SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 59312494d735SSepherosa Ziehau const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 59322494d735SSepherosa Ziehau 59332494d735SSepherosa Ziehau if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) 59342494d735SSepherosa Ziehau return (false); 59352494d735SSepherosa Ziehau } 59362494d735SSepherosa Ziehau return (true); 59372494d735SSepherosa Ziehau } 59382494d735SSepherosa Ziehau 5939b3b75d9cSSepherosa Ziehau /* 5940b3b75d9cSSepherosa Ziehau * Make sure that the RX filter is zero after the successful 5941b3b75d9cSSepherosa Ziehau * RNDIS initialization. 5942b3b75d9cSSepherosa Ziehau * 5943b3b75d9cSSepherosa Ziehau * NOTE: 5944b3b75d9cSSepherosa Ziehau * Under certain conditions on certain versions of Hyper-V, 5945b3b75d9cSSepherosa Ziehau * the RNDIS rxfilter is _not_ zero on the hypervisor side 5946b3b75d9cSSepherosa Ziehau * after the successful RNDIS initialization, which breaks 5947b3b75d9cSSepherosa Ziehau * the assumption of any following code (well, it breaks the 5948b3b75d9cSSepherosa Ziehau * RNDIS API contract actually). Clear the RNDIS rxfilter 5949b3b75d9cSSepherosa Ziehau * explicitly, drain packets sneaking through, and drain the 5950b3b75d9cSSepherosa Ziehau * interrupt taskqueues scheduled due to the stealth packets. 5951b3b75d9cSSepherosa Ziehau */ 5952b3b75d9cSSepherosa Ziehau static void 5953b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan) 5954b3b75d9cSSepherosa Ziehau { 5955b3b75d9cSSepherosa Ziehau 5956b3b75d9cSSepherosa Ziehau hn_disable_rx(sc); 5957b3b75d9cSSepherosa Ziehau hn_drain_rxtx(sc, nchan); 5958b3b75d9cSSepherosa Ziehau } 5959b3b75d9cSSepherosa Ziehau 596015516c77SSepherosa Ziehau static int 596115516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu) 596215516c77SSepherosa Ziehau { 596371e8ac56SSepherosa Ziehau #define ATTACHED_NVS 0x0002 596471e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS 0x0004 596571e8ac56SSepherosa Ziehau 596615516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 5967b3b75d9cSSepherosa Ziehau int error, nsubch, nchan = 1, i, rndis_inited; 596871e8ac56SSepherosa Ziehau uint32_t old_caps, attached = 0; 596915516c77SSepherosa Ziehau 597015516c77SSepherosa Ziehau KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0, 597115516c77SSepherosa Ziehau ("synthetic parts were attached")); 597215516c77SSepherosa Ziehau 59732494d735SSepherosa Ziehau if (!hn_synth_attachable(sc)) 59742494d735SSepherosa Ziehau return (ENXIO); 59752494d735SSepherosa Ziehau 597615516c77SSepherosa Ziehau /* Save capabilities for later verification. */ 597715516c77SSepherosa Ziehau old_caps = sc->hn_caps; 597815516c77SSepherosa Ziehau sc->hn_caps = 0; 597915516c77SSepherosa Ziehau 598015516c77SSepherosa Ziehau /* Clear RSS stuffs. */ 598115516c77SSepherosa Ziehau sc->hn_rss_ind_size = 0; 598215516c77SSepherosa Ziehau sc->hn_rss_hash = 0; 598315516c77SSepherosa Ziehau 598415516c77SSepherosa Ziehau /* 598515516c77SSepherosa Ziehau * Attach the primary channel _before_ attaching NVS and RNDIS. 598615516c77SSepherosa Ziehau */ 598715516c77SSepherosa Ziehau error = hn_chan_attach(sc, sc->hn_prichan); 598815516c77SSepherosa Ziehau if (error) 598971e8ac56SSepherosa Ziehau goto failed; 599015516c77SSepherosa Ziehau 599115516c77SSepherosa Ziehau /* 599215516c77SSepherosa Ziehau * Attach NVS. 599315516c77SSepherosa Ziehau */ 599415516c77SSepherosa Ziehau error = hn_nvs_attach(sc, mtu); 599515516c77SSepherosa Ziehau if (error) 599671e8ac56SSepherosa Ziehau goto failed; 599771e8ac56SSepherosa Ziehau attached |= ATTACHED_NVS; 599815516c77SSepherosa Ziehau 599915516c77SSepherosa Ziehau /* 600015516c77SSepherosa Ziehau * Attach RNDIS _after_ NVS is attached. 600115516c77SSepherosa Ziehau */ 6002b3b75d9cSSepherosa Ziehau error = hn_rndis_attach(sc, mtu, &rndis_inited); 6003b3b75d9cSSepherosa Ziehau if (rndis_inited) 6004b3b75d9cSSepherosa Ziehau attached |= ATTACHED_RNDIS; 600515516c77SSepherosa Ziehau if (error) 600671e8ac56SSepherosa Ziehau goto failed; 600715516c77SSepherosa Ziehau 600815516c77SSepherosa Ziehau /* 600915516c77SSepherosa Ziehau * Make sure capabilities are not changed. 601015516c77SSepherosa Ziehau */ 601115516c77SSepherosa Ziehau if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) { 601215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n", 601315516c77SSepherosa Ziehau old_caps, sc->hn_caps); 601471e8ac56SSepherosa Ziehau error = ENXIO; 601571e8ac56SSepherosa Ziehau goto failed; 601615516c77SSepherosa Ziehau } 601715516c77SSepherosa Ziehau 601815516c77SSepherosa Ziehau /* 601915516c77SSepherosa Ziehau * Allocate sub-channels for multi-TX/RX rings. 602015516c77SSepherosa Ziehau * 602115516c77SSepherosa Ziehau * NOTE: 602215516c77SSepherosa Ziehau * The # of RX rings that can be used is equivalent to the # of 602315516c77SSepherosa Ziehau * channels to be requested. 602415516c77SSepherosa Ziehau */ 602515516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_cnt - 1; 602615516c77SSepherosa Ziehau error = hn_synth_alloc_subchans(sc, &nsubch); 602715516c77SSepherosa Ziehau if (error) 602871e8ac56SSepherosa Ziehau goto failed; 602971e8ac56SSepherosa Ziehau /* NOTE: _Full_ synthetic parts detach is required now. */ 603071e8ac56SSepherosa Ziehau sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED; 603115516c77SSepherosa Ziehau 603271e8ac56SSepherosa Ziehau /* 603371e8ac56SSepherosa Ziehau * Set the # of TX/RX rings that could be used according to 603471e8ac56SSepherosa Ziehau * the # of channels that NVS offered. 603571e8ac56SSepherosa Ziehau */ 603615516c77SSepherosa Ziehau nchan = nsubch + 1; 603771e8ac56SSepherosa Ziehau hn_set_ring_inuse(sc, nchan); 603815516c77SSepherosa Ziehau if (nchan == 1) { 603915516c77SSepherosa Ziehau /* Only the primary channel can be used; done */ 604015516c77SSepherosa Ziehau goto back; 604115516c77SSepherosa Ziehau } 604215516c77SSepherosa Ziehau 604315516c77SSepherosa Ziehau /* 604471e8ac56SSepherosa Ziehau * Attach the sub-channels. 6045afd4971bSSepherosa Ziehau * 6046afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 604715516c77SSepherosa Ziehau */ 604871e8ac56SSepherosa Ziehau error = hn_attach_subchans(sc); 604971e8ac56SSepherosa Ziehau if (error) 605071e8ac56SSepherosa Ziehau goto failed; 605115516c77SSepherosa Ziehau 605271e8ac56SSepherosa Ziehau /* 605371e8ac56SSepherosa Ziehau * Configure RSS key and indirect table _after_ all sub-channels 605471e8ac56SSepherosa Ziehau * are attached. 605571e8ac56SSepherosa Ziehau */ 605615516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) { 605715516c77SSepherosa Ziehau /* 605815516c77SSepherosa Ziehau * RSS key is not set yet; set it to the default RSS key. 605915516c77SSepherosa Ziehau */ 606015516c77SSepherosa Ziehau if (bootverbose) 606115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS key\n"); 606234d68912SSepherosa Ziehau #ifdef RSS 606334d68912SSepherosa Ziehau rss_getkey(rss->rss_key); 606434d68912SSepherosa Ziehau #else 606515516c77SSepherosa Ziehau memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key)); 606634d68912SSepherosa Ziehau #endif 606715516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 606815516c77SSepherosa Ziehau } 606915516c77SSepherosa Ziehau 607015516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) { 607115516c77SSepherosa Ziehau /* 607215516c77SSepherosa Ziehau * RSS indirect table is not set yet; set it up in round- 607315516c77SSepherosa Ziehau * robin fashion. 607415516c77SSepherosa Ziehau */ 607515516c77SSepherosa Ziehau if (bootverbose) { 607615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS indirect " 607715516c77SSepherosa Ziehau "table\n"); 607815516c77SSepherosa Ziehau } 607934d68912SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 608034d68912SSepherosa Ziehau uint32_t subidx; 608134d68912SSepherosa Ziehau 608234d68912SSepherosa Ziehau #ifdef RSS 608334d68912SSepherosa Ziehau subidx = rss_get_indirection_to_bucket(i); 608434d68912SSepherosa Ziehau #else 608534d68912SSepherosa Ziehau subidx = i; 608634d68912SSepherosa Ziehau #endif 608734d68912SSepherosa Ziehau rss->rss_ind[i] = subidx % nchan; 608834d68912SSepherosa Ziehau } 608915516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 609015516c77SSepherosa Ziehau } else { 609115516c77SSepherosa Ziehau /* 609215516c77SSepherosa Ziehau * # of usable channels may be changed, so we have to 609315516c77SSepherosa Ziehau * make sure that all entries in RSS indirect table 609415516c77SSepherosa Ziehau * are valid. 6095afd4971bSSepherosa Ziehau * 6096afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 609715516c77SSepherosa Ziehau */ 6098afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 609915516c77SSepherosa Ziehau } 610015516c77SSepherosa Ziehau 610115516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 610215516c77SSepherosa Ziehau if (error) 610371e8ac56SSepherosa Ziehau goto failed; 610471e8ac56SSepherosa Ziehau back: 6105dc13fee6SSepherosa Ziehau /* 6106dc13fee6SSepherosa Ziehau * Fixup transmission aggregation setup. 6107dc13fee6SSepherosa Ziehau */ 6108dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 6109b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 611015516c77SSepherosa Ziehau return (0); 611171e8ac56SSepherosa Ziehau 611271e8ac56SSepherosa Ziehau failed: 611371e8ac56SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 6114b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 611571e8ac56SSepherosa Ziehau hn_synth_detach(sc); 611671e8ac56SSepherosa Ziehau } else { 6117b3b75d9cSSepherosa Ziehau if (attached & ATTACHED_RNDIS) { 6118b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 611971e8ac56SSepherosa Ziehau hn_rndis_detach(sc); 6120b3b75d9cSSepherosa Ziehau } 612171e8ac56SSepherosa Ziehau if (attached & ATTACHED_NVS) 612271e8ac56SSepherosa Ziehau hn_nvs_detach(sc); 612371e8ac56SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 612471e8ac56SSepherosa Ziehau /* Restore old capabilities. */ 612571e8ac56SSepherosa Ziehau sc->hn_caps = old_caps; 612671e8ac56SSepherosa Ziehau } 612771e8ac56SSepherosa Ziehau return (error); 612871e8ac56SSepherosa Ziehau 612971e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS 613071e8ac56SSepherosa Ziehau #undef ATTACHED_NVS 613115516c77SSepherosa Ziehau } 613215516c77SSepherosa Ziehau 613315516c77SSepherosa Ziehau /* 613415516c77SSepherosa Ziehau * NOTE: 613515516c77SSepherosa Ziehau * The interface must have been suspended though hn_suspend(), before 613615516c77SSepherosa Ziehau * this function get called. 613715516c77SSepherosa Ziehau */ 613815516c77SSepherosa Ziehau static void 613915516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc) 614015516c77SSepherosa Ziehau { 614115516c77SSepherosa Ziehau 614215516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 614315516c77SSepherosa Ziehau ("synthetic parts were not attached")); 614415516c77SSepherosa Ziehau 614515516c77SSepherosa Ziehau /* Detach the RNDIS first. */ 614615516c77SSepherosa Ziehau hn_rndis_detach(sc); 614715516c77SSepherosa Ziehau 614815516c77SSepherosa Ziehau /* Detach NVS. */ 614915516c77SSepherosa Ziehau hn_nvs_detach(sc); 615015516c77SSepherosa Ziehau 615115516c77SSepherosa Ziehau /* Detach all of the channels. */ 615215516c77SSepherosa Ziehau hn_detach_allchans(sc); 615315516c77SSepherosa Ziehau 615415516c77SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED; 615515516c77SSepherosa Ziehau } 615615516c77SSepherosa Ziehau 615715516c77SSepherosa Ziehau static void 615815516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt) 615915516c77SSepherosa Ziehau { 616015516c77SSepherosa Ziehau KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt, 616115516c77SSepherosa Ziehau ("invalid ring count %d", ring_cnt)); 616215516c77SSepherosa Ziehau 616315516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt > ring_cnt) 616415516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = ring_cnt; 616515516c77SSepherosa Ziehau else 616615516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 616715516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = ring_cnt; 616815516c77SSepherosa Ziehau 616934d68912SSepherosa Ziehau #ifdef RSS 617034d68912SSepherosa Ziehau if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) { 617134d68912SSepherosa Ziehau if_printf(sc->hn_ifp, "# of RX rings (%d) does not match " 617234d68912SSepherosa Ziehau "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse, 617334d68912SSepherosa Ziehau rss_getnumbuckets()); 617434d68912SSepherosa Ziehau } 617534d68912SSepherosa Ziehau #endif 617634d68912SSepherosa Ziehau 617715516c77SSepherosa Ziehau if (bootverbose) { 617815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n", 617915516c77SSepherosa Ziehau sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse); 618015516c77SSepherosa Ziehau } 618115516c77SSepherosa Ziehau } 618215516c77SSepherosa Ziehau 618315516c77SSepherosa Ziehau static void 618425641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan) 618515516c77SSepherosa Ziehau { 618615516c77SSepherosa Ziehau 618725641fc7SSepherosa Ziehau /* 618825641fc7SSepherosa Ziehau * NOTE: 618925641fc7SSepherosa Ziehau * The TX bufring will not be drained by the hypervisor, 619025641fc7SSepherosa Ziehau * if the primary channel is revoked. 619125641fc7SSepherosa Ziehau */ 619225641fc7SSepherosa Ziehau while (!vmbus_chan_rx_empty(chan) || 619325641fc7SSepherosa Ziehau (!vmbus_chan_is_revoked(sc->hn_prichan) && 619425641fc7SSepherosa Ziehau !vmbus_chan_tx_empty(chan))) 619515516c77SSepherosa Ziehau pause("waitch", 1); 619615516c77SSepherosa Ziehau vmbus_chan_intr_drain(chan); 619715516c77SSepherosa Ziehau } 619815516c77SSepherosa Ziehau 619915516c77SSepherosa Ziehau static void 6200b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc) 6201b3b75d9cSSepherosa Ziehau { 6202b3b75d9cSSepherosa Ziehau 6203b3b75d9cSSepherosa Ziehau /* 6204b3b75d9cSSepherosa Ziehau * Disable RX by clearing RX filter forcefully. 6205b3b75d9cSSepherosa Ziehau */ 6206b3b75d9cSSepherosa Ziehau sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE; 6207b3b75d9cSSepherosa Ziehau hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */ 6208b3b75d9cSSepherosa Ziehau 6209b3b75d9cSSepherosa Ziehau /* 6210b3b75d9cSSepherosa Ziehau * Give RNDIS enough time to flush all pending data packets. 6211b3b75d9cSSepherosa Ziehau */ 6212b3b75d9cSSepherosa Ziehau pause("waitrx", (200 * hz) / 1000); 6213b3b75d9cSSepherosa Ziehau } 6214b3b75d9cSSepherosa Ziehau 6215b3b75d9cSSepherosa Ziehau /* 6216b3b75d9cSSepherosa Ziehau * NOTE: 6217b3b75d9cSSepherosa Ziehau * RX/TX _must_ have been suspended/disabled, before this function 6218b3b75d9cSSepherosa Ziehau * is called. 6219b3b75d9cSSepherosa Ziehau */ 6220b3b75d9cSSepherosa Ziehau static void 6221b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan) 622215516c77SSepherosa Ziehau { 622315516c77SSepherosa Ziehau struct vmbus_channel **subch = NULL; 6224b3b75d9cSSepherosa Ziehau int nsubch; 6225b3b75d9cSSepherosa Ziehau 6226b3b75d9cSSepherosa Ziehau /* 6227b3b75d9cSSepherosa Ziehau * Drain RX/TX bufrings and interrupts. 6228b3b75d9cSSepherosa Ziehau */ 6229b3b75d9cSSepherosa Ziehau nsubch = nchan - 1; 6230b3b75d9cSSepherosa Ziehau if (nsubch > 0) 6231b3b75d9cSSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 6232b3b75d9cSSepherosa Ziehau 6233b3b75d9cSSepherosa Ziehau if (subch != NULL) { 6234b3b75d9cSSepherosa Ziehau int i; 6235b3b75d9cSSepherosa Ziehau 6236b3b75d9cSSepherosa Ziehau for (i = 0; i < nsubch; ++i) 6237b3b75d9cSSepherosa Ziehau hn_chan_drain(sc, subch[i]); 6238b3b75d9cSSepherosa Ziehau } 6239b3b75d9cSSepherosa Ziehau hn_chan_drain(sc, sc->hn_prichan); 6240b3b75d9cSSepherosa Ziehau 6241b3b75d9cSSepherosa Ziehau if (subch != NULL) 6242b3b75d9cSSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 6243b3b75d9cSSepherosa Ziehau } 6244b3b75d9cSSepherosa Ziehau 6245b3b75d9cSSepherosa Ziehau static void 6246b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc) 6247b3b75d9cSSepherosa Ziehau { 624825641fc7SSepherosa Ziehau struct hn_tx_ring *txr; 6249b3b75d9cSSepherosa Ziehau int i; 625015516c77SSepherosa Ziehau 625115516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 625215516c77SSepherosa Ziehau 625315516c77SSepherosa Ziehau /* 625415516c77SSepherosa Ziehau * Suspend TX. 625515516c77SSepherosa Ziehau */ 625615516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 625725641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 625815516c77SSepherosa Ziehau 625915516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 626015516c77SSepherosa Ziehau txr->hn_suspended = 1; 626115516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 626215516c77SSepherosa Ziehau /* No one is able send more packets now. */ 626315516c77SSepherosa Ziehau 626425641fc7SSepherosa Ziehau /* 626525641fc7SSepherosa Ziehau * Wait for all pending sends to finish. 626625641fc7SSepherosa Ziehau * 626725641fc7SSepherosa Ziehau * NOTE: 626825641fc7SSepherosa Ziehau * We will _not_ receive all pending send-done, if the 626925641fc7SSepherosa Ziehau * primary channel is revoked. 627025641fc7SSepherosa Ziehau */ 627125641fc7SSepherosa Ziehau while (hn_tx_ring_pending(txr) && 627225641fc7SSepherosa Ziehau !vmbus_chan_is_revoked(sc->hn_prichan)) 627315516c77SSepherosa Ziehau pause("hnwtx", 1 /* 1 tick */); 627415516c77SSepherosa Ziehau } 627515516c77SSepherosa Ziehau 627615516c77SSepherosa Ziehau /* 6277b3b75d9cSSepherosa Ziehau * Disable RX. 627815516c77SSepherosa Ziehau */ 6279b3b75d9cSSepherosa Ziehau hn_disable_rx(sc); 628015516c77SSepherosa Ziehau 628115516c77SSepherosa Ziehau /* 6282b3b75d9cSSepherosa Ziehau * Drain RX/TX. 628315516c77SSepherosa Ziehau */ 6284b3b75d9cSSepherosa Ziehau hn_drain_rxtx(sc, sc->hn_rx_ring_inuse); 628525641fc7SSepherosa Ziehau 628625641fc7SSepherosa Ziehau /* 628725641fc7SSepherosa Ziehau * Drain any pending TX tasks. 628825641fc7SSepherosa Ziehau * 628925641fc7SSepherosa Ziehau * NOTE: 6290b3b75d9cSSepherosa Ziehau * The above hn_drain_rxtx() can dispatch TX tasks, so the TX 6291b3b75d9cSSepherosa Ziehau * tasks will have to be drained _after_ the above hn_drain_rxtx(). 629225641fc7SSepherosa Ziehau */ 629325641fc7SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 629425641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 629525641fc7SSepherosa Ziehau 629625641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task); 629725641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task); 629825641fc7SSepherosa Ziehau } 629915516c77SSepherosa Ziehau } 630015516c77SSepherosa Ziehau 630115516c77SSepherosa Ziehau static void 630215516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused) 630315516c77SSepherosa Ziehau { 630415516c77SSepherosa Ziehau 630515516c77SSepherosa Ziehau ((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL; 630615516c77SSepherosa Ziehau } 630715516c77SSepherosa Ziehau 630815516c77SSepherosa Ziehau static void 630915516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc) 631015516c77SSepherosa Ziehau { 631115516c77SSepherosa Ziehau struct task task; 631215516c77SSepherosa Ziehau 631315516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 631415516c77SSepherosa Ziehau 631515516c77SSepherosa Ziehau /* 631615516c77SSepherosa Ziehau * Make sure that hn_mgmt_taskq0 can nolonger be accessed 631715516c77SSepherosa Ziehau * through hn_mgmt_taskq. 631815516c77SSepherosa Ziehau */ 631915516c77SSepherosa Ziehau TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc); 632015516c77SSepherosa Ziehau vmbus_chan_run_task(sc->hn_prichan, &task); 632115516c77SSepherosa Ziehau 632215516c77SSepherosa Ziehau /* 632315516c77SSepherosa Ziehau * Make sure that all pending management tasks are completed. 632415516c77SSepherosa Ziehau */ 632515516c77SSepherosa Ziehau taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init); 632615516c77SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status); 632715516c77SSepherosa Ziehau taskqueue_drain_all(sc->hn_mgmt_taskq0); 632815516c77SSepherosa Ziehau } 632915516c77SSepherosa Ziehau 633015516c77SSepherosa Ziehau static void 633115516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc) 633215516c77SSepherosa Ziehau { 633315516c77SSepherosa Ziehau 633487f8129dSSepherosa Ziehau /* Disable polling. */ 633587f8129dSSepherosa Ziehau hn_polling(sc, 0); 633687f8129dSSepherosa Ziehau 63379c6cae24SSepherosa Ziehau /* 63389c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, the synthetic 63399c6cae24SSepherosa Ziehau * device is receiving packets, so the data path of the 63409c6cae24SSepherosa Ziehau * synthetic device must be suspended. 63419c6cae24SSepherosa Ziehau */ 63425bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 6343962f0357SSepherosa Ziehau (sc->hn_flags & HN_FLAG_RXVF)) 634415516c77SSepherosa Ziehau hn_suspend_data(sc); 634515516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 634615516c77SSepherosa Ziehau } 634715516c77SSepherosa Ziehau 634815516c77SSepherosa Ziehau static void 634915516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt) 635015516c77SSepherosa Ziehau { 635115516c77SSepherosa Ziehau int i; 635215516c77SSepherosa Ziehau 635315516c77SSepherosa Ziehau KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt, 635415516c77SSepherosa Ziehau ("invalid TX ring count %d", tx_ring_cnt)); 635515516c77SSepherosa Ziehau 635615516c77SSepherosa Ziehau for (i = 0; i < tx_ring_cnt; ++i) { 635715516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 635815516c77SSepherosa Ziehau 635915516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 636015516c77SSepherosa Ziehau txr->hn_suspended = 0; 636115516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 636215516c77SSepherosa Ziehau } 636315516c77SSepherosa Ziehau } 636415516c77SSepherosa Ziehau 636515516c77SSepherosa Ziehau static void 636615516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc) 636715516c77SSepherosa Ziehau { 636815516c77SSepherosa Ziehau int i; 636915516c77SSepherosa Ziehau 637015516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 637115516c77SSepherosa Ziehau 637215516c77SSepherosa Ziehau /* 637315516c77SSepherosa Ziehau * Re-enable RX. 637415516c77SSepherosa Ziehau */ 6375c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 637615516c77SSepherosa Ziehau 637715516c77SSepherosa Ziehau /* 637815516c77SSepherosa Ziehau * Make sure to clear suspend status on "all" TX rings, 637915516c77SSepherosa Ziehau * since hn_tx_ring_inuse can be changed after 638015516c77SSepherosa Ziehau * hn_suspend_data(). 638115516c77SSepherosa Ziehau */ 638215516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_cnt); 638315516c77SSepherosa Ziehau 638423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 638523bf9e15SSepherosa Ziehau if (!hn_use_if_start) 638623bf9e15SSepherosa Ziehau #endif 638723bf9e15SSepherosa Ziehau { 638815516c77SSepherosa Ziehau /* 638915516c77SSepherosa Ziehau * Flush unused drbrs, since hn_tx_ring_inuse may be 639015516c77SSepherosa Ziehau * reduced. 639115516c77SSepherosa Ziehau */ 639215516c77SSepherosa Ziehau for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i) 639315516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 639415516c77SSepherosa Ziehau } 639515516c77SSepherosa Ziehau 639615516c77SSepherosa Ziehau /* 639715516c77SSepherosa Ziehau * Kick start TX. 639815516c77SSepherosa Ziehau */ 639915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 640015516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 640115516c77SSepherosa Ziehau 640215516c77SSepherosa Ziehau /* 640315516c77SSepherosa Ziehau * Use txeof task, so that any pending oactive can be 640415516c77SSepherosa Ziehau * cleared properly. 640515516c77SSepherosa Ziehau */ 640615516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 640715516c77SSepherosa Ziehau } 640815516c77SSepherosa Ziehau } 640915516c77SSepherosa Ziehau 641015516c77SSepherosa Ziehau static void 641115516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc) 641215516c77SSepherosa Ziehau { 641315516c77SSepherosa Ziehau 641415516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 641515516c77SSepherosa Ziehau 641615516c77SSepherosa Ziehau /* 641715516c77SSepherosa Ziehau * Kick off network change detection, if it was pending. 641815516c77SSepherosa Ziehau * If no network change was pending, start link status 641915516c77SSepherosa Ziehau * checks, which is more lightweight than network change 642015516c77SSepherosa Ziehau * detection. 642115516c77SSepherosa Ziehau */ 642215516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 642315516c77SSepherosa Ziehau hn_change_network(sc); 642415516c77SSepherosa Ziehau else 642515516c77SSepherosa Ziehau hn_update_link_status(sc); 642615516c77SSepherosa Ziehau } 642715516c77SSepherosa Ziehau 642815516c77SSepherosa Ziehau static void 642915516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc) 643015516c77SSepherosa Ziehau { 643115516c77SSepherosa Ziehau 64329c6cae24SSepherosa Ziehau /* 64339c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, the synthetic 64349c6cae24SSepherosa Ziehau * device have to receive packets, so the data path of the 64359c6cae24SSepherosa Ziehau * synthetic device must be resumed. 64369c6cae24SSepherosa Ziehau */ 64375bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 6438962f0357SSepherosa Ziehau (sc->hn_flags & HN_FLAG_RXVF)) 643915516c77SSepherosa Ziehau hn_resume_data(sc); 64405bdfd3fdSDexuan Cui 64415bdfd3fdSDexuan Cui /* 64429c6cae24SSepherosa Ziehau * Don't resume link status change if VF is attached/activated. 64439c6cae24SSepherosa Ziehau * - In the non-transparent VF mode, the synthetic device marks 64449c6cae24SSepherosa Ziehau * link down until the VF is deactivated; i.e. VF is down. 64459c6cae24SSepherosa Ziehau * - In transparent VF mode, VF's media status is used until 64469c6cae24SSepherosa Ziehau * the VF is detached. 64475bdfd3fdSDexuan Cui */ 64489c6cae24SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) == 0 && 64499c6cae24SSepherosa Ziehau !(hn_xpnt_vf && sc->hn_vf_ifp != NULL)) 645015516c77SSepherosa Ziehau hn_resume_mgmt(sc); 645187f8129dSSepherosa Ziehau 645287f8129dSSepherosa Ziehau /* 645387f8129dSSepherosa Ziehau * Re-enable polling if this interface is running and 645487f8129dSSepherosa Ziehau * the polling is requested. 645587f8129dSSepherosa Ziehau */ 645687f8129dSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0) 645787f8129dSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 645815516c77SSepherosa Ziehau } 645915516c77SSepherosa Ziehau 646015516c77SSepherosa Ziehau static void 646115516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen) 646215516c77SSepherosa Ziehau { 646315516c77SSepherosa Ziehau const struct rndis_status_msg *msg; 646415516c77SSepherosa Ziehau int ofs; 646515516c77SSepherosa Ziehau 646615516c77SSepherosa Ziehau if (dlen < sizeof(*msg)) { 646715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid RNDIS status\n"); 646815516c77SSepherosa Ziehau return; 646915516c77SSepherosa Ziehau } 647015516c77SSepherosa Ziehau msg = data; 647115516c77SSepherosa Ziehau 647215516c77SSepherosa Ziehau switch (msg->rm_status) { 647315516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_CONNECT: 647415516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_DISCONNECT: 647515516c77SSepherosa Ziehau hn_update_link_status(sc); 647615516c77SSepherosa Ziehau break; 647715516c77SSepherosa Ziehau 647815516c77SSepherosa Ziehau case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: 647940905afaSSepherosa Ziehau case RNDIS_STATUS_LINK_SPEED_CHANGE: 648015516c77SSepherosa Ziehau /* Not really useful; ignore. */ 648115516c77SSepherosa Ziehau break; 648215516c77SSepherosa Ziehau 648315516c77SSepherosa Ziehau case RNDIS_STATUS_NETWORK_CHANGE: 648415516c77SSepherosa Ziehau ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset); 648515516c77SSepherosa Ziehau if (dlen < ofs + msg->rm_stbuflen || 648615516c77SSepherosa Ziehau msg->rm_stbuflen < sizeof(uint32_t)) { 648715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed\n"); 648815516c77SSepherosa Ziehau } else { 648915516c77SSepherosa Ziehau uint32_t change; 649015516c77SSepherosa Ziehau 649115516c77SSepherosa Ziehau memcpy(&change, ((const uint8_t *)msg) + ofs, 649215516c77SSepherosa Ziehau sizeof(change)); 649315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed, change %u\n", 649415516c77SSepherosa Ziehau change); 649515516c77SSepherosa Ziehau } 649615516c77SSepherosa Ziehau hn_change_network(sc); 649715516c77SSepherosa Ziehau break; 649815516c77SSepherosa Ziehau 649915516c77SSepherosa Ziehau default: 650015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n", 650115516c77SSepherosa Ziehau msg->rm_status); 650215516c77SSepherosa Ziehau break; 650315516c77SSepherosa Ziehau } 650415516c77SSepherosa Ziehau } 650515516c77SSepherosa Ziehau 650615516c77SSepherosa Ziehau static int 650715516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info) 650815516c77SSepherosa Ziehau { 650915516c77SSepherosa Ziehau const struct rndis_pktinfo *pi = info_data; 651015516c77SSepherosa Ziehau uint32_t mask = 0; 651115516c77SSepherosa Ziehau 651215516c77SSepherosa Ziehau while (info_dlen != 0) { 651315516c77SSepherosa Ziehau const void *data; 651415516c77SSepherosa Ziehau uint32_t dlen; 651515516c77SSepherosa Ziehau 651615516c77SSepherosa Ziehau if (__predict_false(info_dlen < sizeof(*pi))) 651715516c77SSepherosa Ziehau return (EINVAL); 651815516c77SSepherosa Ziehau if (__predict_false(info_dlen < pi->rm_size)) 651915516c77SSepherosa Ziehau return (EINVAL); 652015516c77SSepherosa Ziehau info_dlen -= pi->rm_size; 652115516c77SSepherosa Ziehau 652215516c77SSepherosa Ziehau if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK)) 652315516c77SSepherosa Ziehau return (EINVAL); 652415516c77SSepherosa Ziehau if (__predict_false(pi->rm_size < pi->rm_pktinfooffset)) 652515516c77SSepherosa Ziehau return (EINVAL); 652615516c77SSepherosa Ziehau dlen = pi->rm_size - pi->rm_pktinfooffset; 652715516c77SSepherosa Ziehau data = pi->rm_data; 652815516c77SSepherosa Ziehau 652915516c77SSepherosa Ziehau switch (pi->rm_type) { 653015516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_VLAN: 653115516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE)) 653215516c77SSepherosa Ziehau return (EINVAL); 653315516c77SSepherosa Ziehau info->vlan_info = *((const uint32_t *)data); 653415516c77SSepherosa Ziehau mask |= HN_RXINFO_VLAN; 653515516c77SSepherosa Ziehau break; 653615516c77SSepherosa Ziehau 653715516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_CSUM: 653815516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE)) 653915516c77SSepherosa Ziehau return (EINVAL); 654015516c77SSepherosa Ziehau info->csum_info = *((const uint32_t *)data); 654115516c77SSepherosa Ziehau mask |= HN_RXINFO_CSUM; 654215516c77SSepherosa Ziehau break; 654315516c77SSepherosa Ziehau 654415516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHVAL: 654515516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE)) 654615516c77SSepherosa Ziehau return (EINVAL); 654715516c77SSepherosa Ziehau info->hash_value = *((const uint32_t *)data); 654815516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHVAL; 654915516c77SSepherosa Ziehau break; 655015516c77SSepherosa Ziehau 655115516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHINF: 655215516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE)) 655315516c77SSepherosa Ziehau return (EINVAL); 655415516c77SSepherosa Ziehau info->hash_info = *((const uint32_t *)data); 655515516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHINF; 655615516c77SSepherosa Ziehau break; 655715516c77SSepherosa Ziehau 655815516c77SSepherosa Ziehau default: 655915516c77SSepherosa Ziehau goto next; 656015516c77SSepherosa Ziehau } 656115516c77SSepherosa Ziehau 656215516c77SSepherosa Ziehau if (mask == HN_RXINFO_ALL) { 656315516c77SSepherosa Ziehau /* All found; done */ 656415516c77SSepherosa Ziehau break; 656515516c77SSepherosa Ziehau } 656615516c77SSepherosa Ziehau next: 656715516c77SSepherosa Ziehau pi = (const struct rndis_pktinfo *) 656815516c77SSepherosa Ziehau ((const uint8_t *)pi + pi->rm_size); 656915516c77SSepherosa Ziehau } 657015516c77SSepherosa Ziehau 657115516c77SSepherosa Ziehau /* 657215516c77SSepherosa Ziehau * Final fixup. 657315516c77SSepherosa Ziehau * - If there is no hash value, invalidate the hash info. 657415516c77SSepherosa Ziehau */ 657515516c77SSepherosa Ziehau if ((mask & HN_RXINFO_HASHVAL) == 0) 657615516c77SSepherosa Ziehau info->hash_info = HN_NDIS_HASH_INFO_INVALID; 657715516c77SSepherosa Ziehau return (0); 657815516c77SSepherosa Ziehau } 657915516c77SSepherosa Ziehau 658015516c77SSepherosa Ziehau static __inline bool 658115516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len) 658215516c77SSepherosa Ziehau { 658315516c77SSepherosa Ziehau 658415516c77SSepherosa Ziehau if (off < check_off) { 658515516c77SSepherosa Ziehau if (__predict_true(off + len <= check_off)) 658615516c77SSepherosa Ziehau return (false); 658715516c77SSepherosa Ziehau } else if (off > check_off) { 658815516c77SSepherosa Ziehau if (__predict_true(check_off + check_len <= off)) 658915516c77SSepherosa Ziehau return (false); 659015516c77SSepherosa Ziehau } 659115516c77SSepherosa Ziehau return (true); 659215516c77SSepherosa Ziehau } 659315516c77SSepherosa Ziehau 659415516c77SSepherosa Ziehau static void 659515516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen) 659615516c77SSepherosa Ziehau { 659715516c77SSepherosa Ziehau const struct rndis_packet_msg *pkt; 659815516c77SSepherosa Ziehau struct hn_rxinfo info; 659915516c77SSepherosa Ziehau int data_off, pktinfo_off, data_len, pktinfo_len; 660015516c77SSepherosa Ziehau 660115516c77SSepherosa Ziehau /* 660215516c77SSepherosa Ziehau * Check length. 660315516c77SSepherosa Ziehau */ 660415516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*pkt))) { 660515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n"); 660615516c77SSepherosa Ziehau return; 660715516c77SSepherosa Ziehau } 660815516c77SSepherosa Ziehau pkt = data; 660915516c77SSepherosa Ziehau 661015516c77SSepherosa Ziehau if (__predict_false(dlen < pkt->rm_len)) { 661115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, " 661215516c77SSepherosa Ziehau "dlen %d, msglen %u\n", dlen, pkt->rm_len); 661315516c77SSepherosa Ziehau return; 661415516c77SSepherosa Ziehau } 661515516c77SSepherosa Ziehau if (__predict_false(pkt->rm_len < 661615516c77SSepherosa Ziehau pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) { 661715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, " 661815516c77SSepherosa Ziehau "msglen %u, data %u, oob %u, pktinfo %u\n", 661915516c77SSepherosa Ziehau pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen, 662015516c77SSepherosa Ziehau pkt->rm_pktinfolen); 662115516c77SSepherosa Ziehau return; 662215516c77SSepherosa Ziehau } 662315516c77SSepherosa Ziehau if (__predict_false(pkt->rm_datalen == 0)) { 662415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n"); 662515516c77SSepherosa Ziehau return; 662615516c77SSepherosa Ziehau } 662715516c77SSepherosa Ziehau 662815516c77SSepherosa Ziehau /* 662915516c77SSepherosa Ziehau * Check offests. 663015516c77SSepherosa Ziehau */ 663115516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs) \ 663215516c77SSepherosa Ziehau ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \ 663315516c77SSepherosa Ziehau ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK)) 663415516c77SSepherosa Ziehau 663515516c77SSepherosa Ziehau /* XXX Hyper-V does not meet data offset alignment requirement */ 663615516c77SSepherosa Ziehau if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) { 663715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 663815516c77SSepherosa Ziehau "data offset %u\n", pkt->rm_dataoffset); 663915516c77SSepherosa Ziehau return; 664015516c77SSepherosa Ziehau } 664115516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdataoffset > 0 && 664215516c77SSepherosa Ziehau IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) { 664315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 664415516c77SSepherosa Ziehau "oob offset %u\n", pkt->rm_oobdataoffset); 664515516c77SSepherosa Ziehau return; 664615516c77SSepherosa Ziehau } 664715516c77SSepherosa Ziehau if (__predict_true(pkt->rm_pktinfooffset > 0) && 664815516c77SSepherosa Ziehau __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) { 664915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 665015516c77SSepherosa Ziehau "pktinfo offset %u\n", pkt->rm_pktinfooffset); 665115516c77SSepherosa Ziehau return; 665215516c77SSepherosa Ziehau } 665315516c77SSepherosa Ziehau 665415516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID 665515516c77SSepherosa Ziehau 665615516c77SSepherosa Ziehau data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset); 665715516c77SSepherosa Ziehau data_len = pkt->rm_datalen; 665815516c77SSepherosa Ziehau pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset); 665915516c77SSepherosa Ziehau pktinfo_len = pkt->rm_pktinfolen; 666015516c77SSepherosa Ziehau 666115516c77SSepherosa Ziehau /* 666215516c77SSepherosa Ziehau * Check OOB coverage. 666315516c77SSepherosa Ziehau */ 666415516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdatalen != 0)) { 666515516c77SSepherosa Ziehau int oob_off, oob_len; 666615516c77SSepherosa Ziehau 666715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "got oobdata\n"); 666815516c77SSepherosa Ziehau oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset); 666915516c77SSepherosa Ziehau oob_len = pkt->rm_oobdatalen; 667015516c77SSepherosa Ziehau 667115516c77SSepherosa Ziehau if (__predict_false(oob_off + oob_len > pkt->rm_len)) { 667215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 667315516c77SSepherosa Ziehau "oob overflow, msglen %u, oob abs %d len %d\n", 667415516c77SSepherosa Ziehau pkt->rm_len, oob_off, oob_len); 667515516c77SSepherosa Ziehau return; 667615516c77SSepherosa Ziehau } 667715516c77SSepherosa Ziehau 667815516c77SSepherosa Ziehau /* 667915516c77SSepherosa Ziehau * Check against data. 668015516c77SSepherosa Ziehau */ 668115516c77SSepherosa Ziehau if (hn_rndis_check_overlap(oob_off, oob_len, 668215516c77SSepherosa Ziehau data_off, data_len)) { 668315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 668415516c77SSepherosa Ziehau "oob overlaps data, oob abs %d len %d, " 668515516c77SSepherosa Ziehau "data abs %d len %d\n", 668615516c77SSepherosa Ziehau oob_off, oob_len, data_off, data_len); 668715516c77SSepherosa Ziehau return; 668815516c77SSepherosa Ziehau } 668915516c77SSepherosa Ziehau 669015516c77SSepherosa Ziehau /* 669115516c77SSepherosa Ziehau * Check against pktinfo. 669215516c77SSepherosa Ziehau */ 669315516c77SSepherosa Ziehau if (pktinfo_len != 0 && 669415516c77SSepherosa Ziehau hn_rndis_check_overlap(oob_off, oob_len, 669515516c77SSepherosa Ziehau pktinfo_off, pktinfo_len)) { 669615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 669715516c77SSepherosa Ziehau "oob overlaps pktinfo, oob abs %d len %d, " 669815516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 669915516c77SSepherosa Ziehau oob_off, oob_len, pktinfo_off, pktinfo_len); 670015516c77SSepherosa Ziehau return; 670115516c77SSepherosa Ziehau } 670215516c77SSepherosa Ziehau } 670315516c77SSepherosa Ziehau 670415516c77SSepherosa Ziehau /* 670515516c77SSepherosa Ziehau * Check per-packet-info coverage and find useful per-packet-info. 670615516c77SSepherosa Ziehau */ 670715516c77SSepherosa Ziehau info.vlan_info = HN_NDIS_VLAN_INFO_INVALID; 670815516c77SSepherosa Ziehau info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID; 670915516c77SSepherosa Ziehau info.hash_info = HN_NDIS_HASH_INFO_INVALID; 671015516c77SSepherosa Ziehau if (__predict_true(pktinfo_len != 0)) { 671115516c77SSepherosa Ziehau bool overlap; 671215516c77SSepherosa Ziehau int error; 671315516c77SSepherosa Ziehau 671415516c77SSepherosa Ziehau if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) { 671515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 671615516c77SSepherosa Ziehau "pktinfo overflow, msglen %u, " 671715516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 671815516c77SSepherosa Ziehau pkt->rm_len, pktinfo_off, pktinfo_len); 671915516c77SSepherosa Ziehau return; 672015516c77SSepherosa Ziehau } 672115516c77SSepherosa Ziehau 672215516c77SSepherosa Ziehau /* 672315516c77SSepherosa Ziehau * Check packet info coverage. 672415516c77SSepherosa Ziehau */ 672515516c77SSepherosa Ziehau overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len, 672615516c77SSepherosa Ziehau data_off, data_len); 672715516c77SSepherosa Ziehau if (__predict_false(overlap)) { 672815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 672915516c77SSepherosa Ziehau "pktinfo overlap data, pktinfo abs %d len %d, " 673015516c77SSepherosa Ziehau "data abs %d len %d\n", 673115516c77SSepherosa Ziehau pktinfo_off, pktinfo_len, data_off, data_len); 673215516c77SSepherosa Ziehau return; 673315516c77SSepherosa Ziehau } 673415516c77SSepherosa Ziehau 673515516c77SSepherosa Ziehau /* 673615516c77SSepherosa Ziehau * Find useful per-packet-info. 673715516c77SSepherosa Ziehau */ 673815516c77SSepherosa Ziehau error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off, 673915516c77SSepherosa Ziehau pktinfo_len, &info); 674015516c77SSepherosa Ziehau if (__predict_false(error)) { 674115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg " 674215516c77SSepherosa Ziehau "pktinfo\n"); 674315516c77SSepherosa Ziehau return; 674415516c77SSepherosa Ziehau } 674515516c77SSepherosa Ziehau } 674615516c77SSepherosa Ziehau 674715516c77SSepherosa Ziehau if (__predict_false(data_off + data_len > pkt->rm_len)) { 674815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 674915516c77SSepherosa Ziehau "data overflow, msglen %u, data abs %d len %d\n", 675015516c77SSepherosa Ziehau pkt->rm_len, data_off, data_len); 675115516c77SSepherosa Ziehau return; 675215516c77SSepherosa Ziehau } 675315516c77SSepherosa Ziehau hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info); 675415516c77SSepherosa Ziehau } 675515516c77SSepherosa Ziehau 675615516c77SSepherosa Ziehau static __inline void 675715516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen) 675815516c77SSepherosa Ziehau { 675915516c77SSepherosa Ziehau const struct rndis_msghdr *hdr; 676015516c77SSepherosa Ziehau 676115516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*hdr))) { 676215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS msg\n"); 676315516c77SSepherosa Ziehau return; 676415516c77SSepherosa Ziehau } 676515516c77SSepherosa Ziehau hdr = data; 676615516c77SSepherosa Ziehau 676715516c77SSepherosa Ziehau if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) { 676815516c77SSepherosa Ziehau /* Hot data path. */ 676915516c77SSepherosa Ziehau hn_rndis_rx_data(rxr, data, dlen); 677015516c77SSepherosa Ziehau /* Done! */ 677115516c77SSepherosa Ziehau return; 677215516c77SSepherosa Ziehau } 677315516c77SSepherosa Ziehau 677415516c77SSepherosa Ziehau if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG) 677515516c77SSepherosa Ziehau hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen); 677615516c77SSepherosa Ziehau else 677715516c77SSepherosa Ziehau hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen); 677815516c77SSepherosa Ziehau } 677915516c77SSepherosa Ziehau 678015516c77SSepherosa Ziehau static void 678115516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) 678215516c77SSepherosa Ziehau { 678315516c77SSepherosa Ziehau const struct hn_nvs_hdr *hdr; 678415516c77SSepherosa Ziehau 678515516c77SSepherosa Ziehau if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) { 678615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid nvs notify\n"); 678715516c77SSepherosa Ziehau return; 678815516c77SSepherosa Ziehau } 678915516c77SSepherosa Ziehau hdr = VMBUS_CHANPKT_CONST_DATA(pkt); 679015516c77SSepherosa Ziehau 679115516c77SSepherosa Ziehau if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) { 679215516c77SSepherosa Ziehau /* Useless; ignore */ 679315516c77SSepherosa Ziehau return; 679415516c77SSepherosa Ziehau } 679515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type); 679615516c77SSepherosa Ziehau } 679715516c77SSepherosa Ziehau 679815516c77SSepherosa Ziehau static void 679915516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan, 680015516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkt) 680115516c77SSepherosa Ziehau { 680215516c77SSepherosa Ziehau struct hn_nvs_sendctx *sndc; 680315516c77SSepherosa Ziehau 680415516c77SSepherosa Ziehau sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid; 680515516c77SSepherosa Ziehau sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt), 680615516c77SSepherosa Ziehau VMBUS_CHANPKT_DATALEN(pkt)); 680715516c77SSepherosa Ziehau /* 680815516c77SSepherosa Ziehau * NOTE: 680915516c77SSepherosa Ziehau * 'sndc' CAN NOT be accessed anymore, since it can be freed by 681015516c77SSepherosa Ziehau * its callback. 681115516c77SSepherosa Ziehau */ 681215516c77SSepherosa Ziehau } 681315516c77SSepherosa Ziehau 681415516c77SSepherosa Ziehau static void 681515516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 681615516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkthdr) 681715516c77SSepherosa Ziehau { 681815516c77SSepherosa Ziehau const struct vmbus_chanpkt_rxbuf *pkt; 681915516c77SSepherosa Ziehau const struct hn_nvs_hdr *nvs_hdr; 682015516c77SSepherosa Ziehau int count, i, hlen; 682115516c77SSepherosa Ziehau 682215516c77SSepherosa Ziehau if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) { 682315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n"); 682415516c77SSepherosa Ziehau return; 682515516c77SSepherosa Ziehau } 682615516c77SSepherosa Ziehau nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr); 682715516c77SSepherosa Ziehau 682815516c77SSepherosa Ziehau /* Make sure that this is a RNDIS message. */ 682915516c77SSepherosa Ziehau if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) { 683015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n", 683115516c77SSepherosa Ziehau nvs_hdr->nvs_type); 683215516c77SSepherosa Ziehau return; 683315516c77SSepherosa Ziehau } 683415516c77SSepherosa Ziehau 683515516c77SSepherosa Ziehau hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen); 683615516c77SSepherosa Ziehau if (__predict_false(hlen < sizeof(*pkt))) { 683715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n"); 683815516c77SSepherosa Ziehau return; 683915516c77SSepherosa Ziehau } 684015516c77SSepherosa Ziehau pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr; 684115516c77SSepherosa Ziehau 684215516c77SSepherosa Ziehau if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) { 684315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n", 684415516c77SSepherosa Ziehau pkt->cp_rxbuf_id); 684515516c77SSepherosa Ziehau return; 684615516c77SSepherosa Ziehau } 684715516c77SSepherosa Ziehau 684815516c77SSepherosa Ziehau count = pkt->cp_rxbuf_cnt; 684915516c77SSepherosa Ziehau if (__predict_false(hlen < 685015516c77SSepherosa Ziehau __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) { 685115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count); 685215516c77SSepherosa Ziehau return; 685315516c77SSepherosa Ziehau } 685415516c77SSepherosa Ziehau 685515516c77SSepherosa Ziehau /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 685615516c77SSepherosa Ziehau for (i = 0; i < count; ++i) { 685715516c77SSepherosa Ziehau int ofs, len; 685815516c77SSepherosa Ziehau 685915516c77SSepherosa Ziehau ofs = pkt->cp_rxbuf[i].rb_ofs; 686015516c77SSepherosa Ziehau len = pkt->cp_rxbuf[i].rb_len; 686115516c77SSepherosa Ziehau if (__predict_false(ofs + len > HN_RXBUF_SIZE)) { 686215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, " 686315516c77SSepherosa Ziehau "ofs %d, len %d\n", i, ofs, len); 686415516c77SSepherosa Ziehau continue; 686515516c77SSepherosa Ziehau } 686615516c77SSepherosa Ziehau hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len); 686715516c77SSepherosa Ziehau } 686815516c77SSepherosa Ziehau 686915516c77SSepherosa Ziehau /* 687015516c77SSepherosa Ziehau * Ack the consumed RXBUF associated w/ this channel packet, 687115516c77SSepherosa Ziehau * so that this RXBUF can be recycled by the hypervisor. 687215516c77SSepherosa Ziehau */ 687315516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid); 687415516c77SSepherosa Ziehau } 687515516c77SSepherosa Ziehau 687615516c77SSepherosa Ziehau static void 687715516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 687815516c77SSepherosa Ziehau uint64_t tid) 687915516c77SSepherosa Ziehau { 688015516c77SSepherosa Ziehau struct hn_nvs_rndis_ack ack; 688115516c77SSepherosa Ziehau int retries, error; 688215516c77SSepherosa Ziehau 688315516c77SSepherosa Ziehau ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK; 688415516c77SSepherosa Ziehau ack.nvs_status = HN_NVS_STATUS_OK; 688515516c77SSepherosa Ziehau 688615516c77SSepherosa Ziehau retries = 0; 688715516c77SSepherosa Ziehau again: 688815516c77SSepherosa Ziehau error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 688915516c77SSepherosa Ziehau VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid); 689015516c77SSepherosa Ziehau if (__predict_false(error == EAGAIN)) { 689115516c77SSepherosa Ziehau /* 689215516c77SSepherosa Ziehau * NOTE: 689315516c77SSepherosa Ziehau * This should _not_ happen in real world, since the 689415516c77SSepherosa Ziehau * consumption of the TX bufring from the TX path is 689515516c77SSepherosa Ziehau * controlled. 689615516c77SSepherosa Ziehau */ 689715516c77SSepherosa Ziehau if (rxr->hn_ack_failed == 0) 689815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack retry\n"); 689915516c77SSepherosa Ziehau rxr->hn_ack_failed++; 690015516c77SSepherosa Ziehau retries++; 690115516c77SSepherosa Ziehau if (retries < 10) { 690215516c77SSepherosa Ziehau DELAY(100); 690315516c77SSepherosa Ziehau goto again; 690415516c77SSepherosa Ziehau } 690515516c77SSepherosa Ziehau /* RXBUF leaks! */ 690615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack failed\n"); 690715516c77SSepherosa Ziehau } 690815516c77SSepherosa Ziehau } 690915516c77SSepherosa Ziehau 691015516c77SSepherosa Ziehau static void 691115516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr) 691215516c77SSepherosa Ziehau { 691315516c77SSepherosa Ziehau struct hn_rx_ring *rxr = xrxr; 691415516c77SSepherosa Ziehau struct hn_softc *sc = rxr->hn_ifp->if_softc; 691515516c77SSepherosa Ziehau 691615516c77SSepherosa Ziehau for (;;) { 691715516c77SSepherosa Ziehau struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf; 691815516c77SSepherosa Ziehau int error, pktlen; 691915516c77SSepherosa Ziehau 692015516c77SSepherosa Ziehau pktlen = rxr->hn_pktbuf_len; 692115516c77SSepherosa Ziehau error = vmbus_chan_recv_pkt(chan, pkt, &pktlen); 692215516c77SSepherosa Ziehau if (__predict_false(error == ENOBUFS)) { 692315516c77SSepherosa Ziehau void *nbuf; 692415516c77SSepherosa Ziehau int nlen; 692515516c77SSepherosa Ziehau 692615516c77SSepherosa Ziehau /* 692715516c77SSepherosa Ziehau * Expand channel packet buffer. 692815516c77SSepherosa Ziehau * 692915516c77SSepherosa Ziehau * XXX 693015516c77SSepherosa Ziehau * Use M_WAITOK here, since allocation failure 693115516c77SSepherosa Ziehau * is fatal. 693215516c77SSepherosa Ziehau */ 693315516c77SSepherosa Ziehau nlen = rxr->hn_pktbuf_len * 2; 693415516c77SSepherosa Ziehau while (nlen < pktlen) 693515516c77SSepherosa Ziehau nlen *= 2; 693615516c77SSepherosa Ziehau nbuf = malloc(nlen, M_DEVBUF, M_WAITOK); 693715516c77SSepherosa Ziehau 693815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n", 693915516c77SSepherosa Ziehau rxr->hn_pktbuf_len, nlen); 694015516c77SSepherosa Ziehau 694115516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 694215516c77SSepherosa Ziehau rxr->hn_pktbuf = nbuf; 694315516c77SSepherosa Ziehau rxr->hn_pktbuf_len = nlen; 694415516c77SSepherosa Ziehau /* Retry! */ 694515516c77SSepherosa Ziehau continue; 694615516c77SSepherosa Ziehau } else if (__predict_false(error == EAGAIN)) { 694715516c77SSepherosa Ziehau /* No more channel packets; done! */ 694815516c77SSepherosa Ziehau break; 694915516c77SSepherosa Ziehau } 695015516c77SSepherosa Ziehau KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error)); 695115516c77SSepherosa Ziehau 695215516c77SSepherosa Ziehau switch (pkt->cph_type) { 695315516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_COMP: 695415516c77SSepherosa Ziehau hn_nvs_handle_comp(sc, chan, pkt); 695515516c77SSepherosa Ziehau break; 695615516c77SSepherosa Ziehau 695715516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_RXBUF: 695815516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(rxr, chan, pkt); 695915516c77SSepherosa Ziehau break; 696015516c77SSepherosa Ziehau 696115516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_INBAND: 696215516c77SSepherosa Ziehau hn_nvs_handle_notify(sc, pkt); 696315516c77SSepherosa Ziehau break; 696415516c77SSepherosa Ziehau 696515516c77SSepherosa Ziehau default: 696615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "unknown chan pkt %u\n", 696715516c77SSepherosa Ziehau pkt->cph_type); 696815516c77SSepherosa Ziehau break; 696915516c77SSepherosa Ziehau } 697015516c77SSepherosa Ziehau } 697115516c77SSepherosa Ziehau hn_chan_rollup(rxr, rxr->hn_txr); 697215516c77SSepherosa Ziehau } 697315516c77SSepherosa Ziehau 697415516c77SSepherosa Ziehau static void 6975499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused) 697615516c77SSepherosa Ziehau { 6977fdd0222aSSepherosa Ziehau int i; 6978fdd0222aSSepherosa Ziehau 69799c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 69809c6cae24SSepherosa Ziehau /* 69819c6cae24SSepherosa Ziehau * Don't use ifnet.if_start if transparent VF mode is requested; 69829c6cae24SSepherosa Ziehau * mainly due to the IFF_DRV_OACTIVE flag. 69839c6cae24SSepherosa Ziehau */ 69849c6cae24SSepherosa Ziehau if (hn_xpnt_vf && hn_use_if_start) { 69859c6cae24SSepherosa Ziehau hn_use_if_start = 0; 69869c6cae24SSepherosa Ziehau printf("hn: tranparent VF mode, if_transmit will be used, " 69879c6cae24SSepherosa Ziehau "instead of if_start\n"); 69889c6cae24SSepherosa Ziehau } 69899c6cae24SSepherosa Ziehau #endif 69909c6cae24SSepherosa Ziehau if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) { 69919c6cae24SSepherosa Ziehau printf("hn: invalid transparent VF attach routing " 69929c6cae24SSepherosa Ziehau "wait timeout %d, reset to %d\n", 69939c6cae24SSepherosa Ziehau hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN); 69949c6cae24SSepherosa Ziehau hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN; 69959c6cae24SSepherosa Ziehau } 69969c6cae24SSepherosa Ziehau 6997fdd0222aSSepherosa Ziehau /* 6998499c3e17SSepherosa Ziehau * Initialize VF map. 6999499c3e17SSepherosa Ziehau */ 7000499c3e17SSepherosa Ziehau rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE); 7001499c3e17SSepherosa Ziehau hn_vfmap_size = HN_VFMAP_SIZE_DEF; 7002499c3e17SSepherosa Ziehau hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF, 7003499c3e17SSepherosa Ziehau M_WAITOK | M_ZERO); 7004499c3e17SSepherosa Ziehau 7005499c3e17SSepherosa Ziehau /* 7006fdd0222aSSepherosa Ziehau * Fix the # of TX taskqueues. 7007fdd0222aSSepherosa Ziehau */ 7008fdd0222aSSepherosa Ziehau if (hn_tx_taskq_cnt <= 0) 7009fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = 1; 7010fdd0222aSSepherosa Ziehau else if (hn_tx_taskq_cnt > mp_ncpus) 7011fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = mp_ncpus; 701215516c77SSepherosa Ziehau 70130e11868dSSepherosa Ziehau /* 70140e11868dSSepherosa Ziehau * Fix the TX taskqueue mode. 70150e11868dSSepherosa Ziehau */ 70160e11868dSSepherosa Ziehau switch (hn_tx_taskq_mode) { 70170e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_INDEP: 70180e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_GLOBAL: 70190e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_EVTTQ: 70200e11868dSSepherosa Ziehau break; 70210e11868dSSepherosa Ziehau default: 70220e11868dSSepherosa Ziehau hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP; 70230e11868dSSepherosa Ziehau break; 70240e11868dSSepherosa Ziehau } 70250e11868dSSepherosa Ziehau 702615516c77SSepherosa Ziehau if (vm_guest != VM_GUEST_HV) 702715516c77SSepherosa Ziehau return; 702815516c77SSepherosa Ziehau 70290e11868dSSepherosa Ziehau if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL) 703015516c77SSepherosa Ziehau return; 703115516c77SSepherosa Ziehau 7032fdd0222aSSepherosa Ziehau hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 7033fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 7034fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 7035fdd0222aSSepherosa Ziehau hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK, 7036fdd0222aSSepherosa Ziehau taskqueue_thread_enqueue, &hn_tx_taskque[i]); 7037fdd0222aSSepherosa Ziehau taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET, 7038fdd0222aSSepherosa Ziehau "hn tx%d", i); 7039fdd0222aSSepherosa Ziehau } 704015516c77SSepherosa Ziehau } 7041499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL); 704215516c77SSepherosa Ziehau 704315516c77SSepherosa Ziehau static void 7044499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused) 704515516c77SSepherosa Ziehau { 704615516c77SSepherosa Ziehau 7047fdd0222aSSepherosa Ziehau if (hn_tx_taskque != NULL) { 7048fdd0222aSSepherosa Ziehau int i; 7049fdd0222aSSepherosa Ziehau 7050fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 7051fdd0222aSSepherosa Ziehau taskqueue_free(hn_tx_taskque[i]); 7052fdd0222aSSepherosa Ziehau free(hn_tx_taskque, M_DEVBUF); 7053fdd0222aSSepherosa Ziehau } 7054499c3e17SSepherosa Ziehau 7055499c3e17SSepherosa Ziehau if (hn_vfmap != NULL) 7056499c3e17SSepherosa Ziehau free(hn_vfmap, M_DEVBUF); 7057499c3e17SSepherosa Ziehau rm_destroy(&hn_vfmap_lock); 705815516c77SSepherosa Ziehau } 7059499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL); 7060