115516c77SSepherosa Ziehau /*- 215516c77SSepherosa Ziehau * Copyright (c) 2010-2012 Citrix Inc. 315516c77SSepherosa Ziehau * Copyright (c) 2009-2012,2016 Microsoft Corp. 415516c77SSepherosa Ziehau * Copyright (c) 2012 NetApp Inc. 515516c77SSepherosa Ziehau * All rights reserved. 615516c77SSepherosa Ziehau * 715516c77SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 815516c77SSepherosa Ziehau * modification, are permitted provided that the following conditions 915516c77SSepherosa Ziehau * are met: 1015516c77SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 1115516c77SSepherosa Ziehau * notice unmodified, this list of conditions, and the following 1215516c77SSepherosa Ziehau * disclaimer. 1315516c77SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 1415516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 1515516c77SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 1615516c77SSepherosa Ziehau * 1715516c77SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1815516c77SSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1915516c77SSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2015516c77SSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2115516c77SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2215516c77SSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2315516c77SSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2415516c77SSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2515516c77SSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2615516c77SSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2715516c77SSepherosa Ziehau */ 2815516c77SSepherosa Ziehau 2915516c77SSepherosa Ziehau /*- 3015516c77SSepherosa Ziehau * Copyright (c) 2004-2006 Kip Macy 3115516c77SSepherosa Ziehau * All rights reserved. 3215516c77SSepherosa Ziehau * 3315516c77SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 3415516c77SSepherosa Ziehau * modification, are permitted provided that the following conditions 3515516c77SSepherosa Ziehau * are met: 3615516c77SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 3715516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 3815516c77SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 3915516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 4015516c77SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 4115516c77SSepherosa Ziehau * 4215516c77SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 4315516c77SSepherosa Ziehau * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4415516c77SSepherosa Ziehau * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4515516c77SSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4615516c77SSepherosa Ziehau * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4715516c77SSepherosa Ziehau * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4815516c77SSepherosa Ziehau * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4915516c77SSepherosa Ziehau * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5015516c77SSepherosa Ziehau * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5115516c77SSepherosa Ziehau * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5215516c77SSepherosa Ziehau * SUCH DAMAGE. 5315516c77SSepherosa Ziehau */ 5415516c77SSepherosa Ziehau 5515516c77SSepherosa Ziehau #include <sys/cdefs.h> 5615516c77SSepherosa Ziehau __FBSDID("$FreeBSD$"); 5715516c77SSepherosa Ziehau 5834d68912SSepherosa Ziehau #include "opt_hn.h" 5915516c77SSepherosa Ziehau #include "opt_inet6.h" 6015516c77SSepherosa Ziehau #include "opt_inet.h" 6134d68912SSepherosa Ziehau #include "opt_rss.h" 6215516c77SSepherosa Ziehau 6315516c77SSepherosa Ziehau #include <sys/param.h> 6415516c77SSepherosa Ziehau #include <sys/bus.h> 6515516c77SSepherosa Ziehau #include <sys/kernel.h> 6615516c77SSepherosa Ziehau #include <sys/limits.h> 6715516c77SSepherosa Ziehau #include <sys/malloc.h> 6815516c77SSepherosa Ziehau #include <sys/mbuf.h> 6915516c77SSepherosa Ziehau #include <sys/module.h> 7015516c77SSepherosa Ziehau #include <sys/queue.h> 7115516c77SSepherosa Ziehau #include <sys/lock.h> 72499c3e17SSepherosa Ziehau #include <sys/rmlock.h> 73499c3e17SSepherosa Ziehau #include <sys/sbuf.h> 7415516c77SSepherosa Ziehau #include <sys/smp.h> 7515516c77SSepherosa Ziehau #include <sys/socket.h> 7615516c77SSepherosa Ziehau #include <sys/sockio.h> 7715516c77SSepherosa Ziehau #include <sys/sx.h> 7815516c77SSepherosa Ziehau #include <sys/sysctl.h> 7915516c77SSepherosa Ziehau #include <sys/systm.h> 8015516c77SSepherosa Ziehau #include <sys/taskqueue.h> 8115516c77SSepherosa Ziehau #include <sys/buf_ring.h> 825bdfd3fdSDexuan Cui #include <sys/eventhandler.h> 8315516c77SSepherosa Ziehau 8415516c77SSepherosa Ziehau #include <machine/atomic.h> 8515516c77SSepherosa Ziehau #include <machine/in_cksum.h> 8615516c77SSepherosa Ziehau 8715516c77SSepherosa Ziehau #include <net/bpf.h> 8815516c77SSepherosa Ziehau #include <net/ethernet.h> 8915516c77SSepherosa Ziehau #include <net/if.h> 905bdfd3fdSDexuan Cui #include <net/if_dl.h> 9115516c77SSepherosa Ziehau #include <net/if_media.h> 9215516c77SSepherosa Ziehau #include <net/if_types.h> 9315516c77SSepherosa Ziehau #include <net/if_var.h> 9415516c77SSepherosa Ziehau #include <net/rndis.h> 9534d68912SSepherosa Ziehau #ifdef RSS 9634d68912SSepherosa Ziehau #include <net/rss_config.h> 9734d68912SSepherosa Ziehau #endif 9815516c77SSepherosa Ziehau 9915516c77SSepherosa Ziehau #include <netinet/in_systm.h> 10015516c77SSepherosa Ziehau #include <netinet/in.h> 10115516c77SSepherosa Ziehau #include <netinet/ip.h> 10215516c77SSepherosa Ziehau #include <netinet/ip6.h> 10315516c77SSepherosa Ziehau #include <netinet/tcp.h> 10415516c77SSepherosa Ziehau #include <netinet/tcp_lro.h> 10515516c77SSepherosa Ziehau #include <netinet/udp.h> 10615516c77SSepherosa Ziehau 10715516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h> 10815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h> 10915516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h> 11015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h> 11115516c77SSepherosa Ziehau 11215516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h> 11315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h> 11415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h> 11515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h> 11615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h> 11715516c77SSepherosa Ziehau 11815516c77SSepherosa Ziehau #include "vmbus_if.h" 11915516c77SSepherosa Ziehau 12023bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT 12123bf9e15SSepherosa Ziehau 12215516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX 8 12315516c77SSepherosa Ziehau 124499c3e17SSepherosa Ziehau #define HN_VFMAP_SIZE_DEF 8 125499c3e17SSepherosa Ziehau 12615516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */ 12715516c77SSepherosa Ziehau #define HN_TX_DESC_CNT 512 12815516c77SSepherosa Ziehau 12915516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN \ 13015516c77SSepherosa Ziehau (sizeof(struct rndis_packet_msg) + \ 13115516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) + \ 13215516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) + \ 13315516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) + \ 13415516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE)) 13515516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY PAGE_SIZE 13615516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN CACHE_LINE_SIZE 13715516c77SSepherosa Ziehau 13815516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY PAGE_SIZE 13915516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE IP_MAXPACKET 14015516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE PAGE_SIZE 14115516c77SSepherosa Ziehau /* -1 for RNDIS packet message */ 14215516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX (HN_GPACNT_MAX - 1) 14315516c77SSepherosa Ziehau 14415516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF 128 14515516c77SSepherosa Ziehau 14615516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH 8 14715516c77SSepherosa Ziehau 14815516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF (16 * 1024) 14915516c77SSepherosa Ziehau 15015516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF 128 15115516c77SSepherosa Ziehau 15215516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF (12 * ETHERMTU) 15315516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF (25 * ETHERMTU) 15415516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */ 15515516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp) (2 * (ifp)->if_mtu) 15615516c77SSepherosa Ziehau 15715516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF 1 15815516c77SSepherosa Ziehau 15915516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc) \ 16015516c77SSepherosa Ziehau sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev)) 16115516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc) sx_destroy(&(sc)->hn_lock) 16215516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc) sx_assert(&(sc)->hn_lock, SA_XLOCKED) 163fdc4f478SSepherosa Ziehau #define HN_LOCK(sc) \ 164fdc4f478SSepherosa Ziehau do { \ 165fdc4f478SSepherosa Ziehau while (sx_try_xlock(&(sc)->hn_lock) == 0) \ 166fdc4f478SSepherosa Ziehau DELAY(1000); \ 167fdc4f478SSepherosa Ziehau } while (0) 16815516c77SSepherosa Ziehau #define HN_UNLOCK(sc) sx_xunlock(&(sc)->hn_lock) 16915516c77SSepherosa Ziehau 17015516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK (CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP) 17115516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK (CSUM_IP6_TCP | CSUM_IP6_UDP) 17215516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc) \ 17315516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK) 17415516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc) \ 17515516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK) 17615516c77SSepherosa Ziehau 177dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align) \ 178dc13fee6SSepherosa Ziehau roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \ 179dc13fee6SSepherosa Ziehau HN_RNDIS_PKT_LEN, (align)) 180dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align) \ 181dc13fee6SSepherosa Ziehau roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align)) 182dc13fee6SSepherosa Ziehau 18334d68912SSepherosa Ziehau #ifdef RSS 18434d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx) rss_getcpu((idx) % rss_getnumbuckets()) 18534d68912SSepherosa Ziehau #else 1860e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx) (((sc)->hn_cpu + (idx)) % mp_ncpus) 18734d68912SSepherosa Ziehau #endif 1880e11868dSSepherosa Ziehau 18915516c77SSepherosa Ziehau struct hn_txdesc { 19015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 19115516c77SSepherosa Ziehau SLIST_ENTRY(hn_txdesc) link; 19215516c77SSepherosa Ziehau #endif 193dc13fee6SSepherosa Ziehau STAILQ_ENTRY(hn_txdesc) agg_link; 194dc13fee6SSepherosa Ziehau 195dc13fee6SSepherosa Ziehau /* Aggregated txdescs, in sending order. */ 196dc13fee6SSepherosa Ziehau STAILQ_HEAD(, hn_txdesc) agg_list; 197dc13fee6SSepherosa Ziehau 198dc13fee6SSepherosa Ziehau /* The oldest packet, if transmission aggregation happens. */ 19915516c77SSepherosa Ziehau struct mbuf *m; 20015516c77SSepherosa Ziehau struct hn_tx_ring *txr; 20115516c77SSepherosa Ziehau int refs; 20215516c77SSepherosa Ziehau uint32_t flags; /* HN_TXD_FLAG_ */ 20315516c77SSepherosa Ziehau struct hn_nvs_sendctx send_ctx; 20415516c77SSepherosa Ziehau uint32_t chim_index; 20515516c77SSepherosa Ziehau int chim_size; 20615516c77SSepherosa Ziehau 20715516c77SSepherosa Ziehau bus_dmamap_t data_dmap; 20815516c77SSepherosa Ziehau 20915516c77SSepherosa Ziehau bus_addr_t rndis_pkt_paddr; 21015516c77SSepherosa Ziehau struct rndis_packet_msg *rndis_pkt; 21115516c77SSepherosa Ziehau bus_dmamap_t rndis_pkt_dmap; 21215516c77SSepherosa Ziehau }; 21315516c77SSepherosa Ziehau 21415516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST 0x0001 21515516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP 0x0002 216dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG 0x0004 21715516c77SSepherosa Ziehau 21815516c77SSepherosa Ziehau struct hn_rxinfo { 21915516c77SSepherosa Ziehau uint32_t vlan_info; 22015516c77SSepherosa Ziehau uint32_t csum_info; 22115516c77SSepherosa Ziehau uint32_t hash_info; 22215516c77SSepherosa Ziehau uint32_t hash_value; 22315516c77SSepherosa Ziehau }; 22415516c77SSepherosa Ziehau 2255bdfd3fdSDexuan Cui struct hn_update_vf { 2265bdfd3fdSDexuan Cui struct hn_rx_ring *rxr; 2275bdfd3fdSDexuan Cui struct ifnet *vf; 2285bdfd3fdSDexuan Cui }; 2295bdfd3fdSDexuan Cui 23015516c77SSepherosa Ziehau #define HN_RXINFO_VLAN 0x0001 23115516c77SSepherosa Ziehau #define HN_RXINFO_CSUM 0x0002 23215516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF 0x0004 23315516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL 0x0008 23415516c77SSepherosa Ziehau #define HN_RXINFO_ALL \ 23515516c77SSepherosa Ziehau (HN_RXINFO_VLAN | \ 23615516c77SSepherosa Ziehau HN_RXINFO_CSUM | \ 23715516c77SSepherosa Ziehau HN_RXINFO_HASHINF | \ 23815516c77SSepherosa Ziehau HN_RXINFO_HASHVAL) 23915516c77SSepherosa Ziehau 24015516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID 0xffffffff 24115516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID 0 24215516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID 0 24315516c77SSepherosa Ziehau 24415516c77SSepherosa Ziehau static int hn_probe(device_t); 24515516c77SSepherosa Ziehau static int hn_attach(device_t); 24615516c77SSepherosa Ziehau static int hn_detach(device_t); 24715516c77SSepherosa Ziehau static int hn_shutdown(device_t); 24815516c77SSepherosa Ziehau static void hn_chan_callback(struct vmbus_channel *, 24915516c77SSepherosa Ziehau void *); 25015516c77SSepherosa Ziehau 25115516c77SSepherosa Ziehau static void hn_init(void *); 25215516c77SSepherosa Ziehau static int hn_ioctl(struct ifnet *, u_long, caddr_t); 25323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 25415516c77SSepherosa Ziehau static void hn_start(struct ifnet *); 25523bf9e15SSepherosa Ziehau #endif 25615516c77SSepherosa Ziehau static int hn_transmit(struct ifnet *, struct mbuf *); 25715516c77SSepherosa Ziehau static void hn_xmit_qflush(struct ifnet *); 25815516c77SSepherosa Ziehau static int hn_ifmedia_upd(struct ifnet *); 25915516c77SSepherosa Ziehau static void hn_ifmedia_sts(struct ifnet *, 26015516c77SSepherosa Ziehau struct ifmediareq *); 26115516c77SSepherosa Ziehau 262499c3e17SSepherosa Ziehau static void hn_ifnet_event(void *, struct ifnet *, int); 263499c3e17SSepherosa Ziehau static void hn_ifaddr_event(void *, struct ifnet *); 264499c3e17SSepherosa Ziehau static void hn_ifnet_attevent(void *, struct ifnet *); 265499c3e17SSepherosa Ziehau static void hn_ifnet_detevent(void *, struct ifnet *); 266499c3e17SSepherosa Ziehau 26715516c77SSepherosa Ziehau static int hn_rndis_rxinfo(const void *, int, 26815516c77SSepherosa Ziehau struct hn_rxinfo *); 26915516c77SSepherosa Ziehau static void hn_rndis_rx_data(struct hn_rx_ring *, 27015516c77SSepherosa Ziehau const void *, int); 27115516c77SSepherosa Ziehau static void hn_rndis_rx_status(struct hn_softc *, 27215516c77SSepherosa Ziehau const void *, int); 273b3b75d9cSSepherosa Ziehau static void hn_rndis_init_fixat(struct hn_softc *, int); 27415516c77SSepherosa Ziehau 27515516c77SSepherosa Ziehau static void hn_nvs_handle_notify(struct hn_softc *, 27615516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 27715516c77SSepherosa Ziehau static void hn_nvs_handle_comp(struct hn_softc *, 27815516c77SSepherosa Ziehau struct vmbus_channel *, 27915516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 28015516c77SSepherosa Ziehau static void hn_nvs_handle_rxbuf(struct hn_rx_ring *, 28115516c77SSepherosa Ziehau struct vmbus_channel *, 28215516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 28315516c77SSepherosa Ziehau static void hn_nvs_ack_rxbuf(struct hn_rx_ring *, 28415516c77SSepherosa Ziehau struct vmbus_channel *, uint64_t); 28515516c77SSepherosa Ziehau 28615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 28715516c77SSepherosa Ziehau static int hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS); 28815516c77SSepherosa Ziehau static int hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS); 28915516c77SSepherosa Ziehau #endif 29015516c77SSepherosa Ziehau static int hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS); 29115516c77SSepherosa Ziehau static int hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS); 29215516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 29315516c77SSepherosa Ziehau static int hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS); 29415516c77SSepherosa Ziehau #else 29515516c77SSepherosa Ziehau static int hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS); 29615516c77SSepherosa Ziehau #endif 29715516c77SSepherosa Ziehau static int hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 29815516c77SSepherosa Ziehau static int hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 29915516c77SSepherosa Ziehau static int hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS); 30015516c77SSepherosa Ziehau static int hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS); 30115516c77SSepherosa Ziehau static int hn_caps_sysctl(SYSCTL_HANDLER_ARGS); 30215516c77SSepherosa Ziehau static int hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS); 30315516c77SSepherosa Ziehau static int hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS); 30434d68912SSepherosa Ziehau #ifndef RSS 30515516c77SSepherosa Ziehau static int hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS); 30615516c77SSepherosa Ziehau static int hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS); 30734d68912SSepherosa Ziehau #endif 30815516c77SSepherosa Ziehau static int hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS); 309dc13fee6SSepherosa Ziehau static int hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS); 310dc13fee6SSepherosa Ziehau static int hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS); 311dc13fee6SSepherosa Ziehau static int hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS); 312dc13fee6SSepherosa Ziehau static int hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS); 3136c1204dfSSepherosa Ziehau static int hn_polling_sysctl(SYSCTL_HANDLER_ARGS); 31440d60d6eSDexuan Cui static int hn_vf_sysctl(SYSCTL_HANDLER_ARGS); 315499c3e17SSepherosa Ziehau static int hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS); 316499c3e17SSepherosa Ziehau static int hn_vflist_sysctl(SYSCTL_HANDLER_ARGS); 317499c3e17SSepherosa Ziehau static int hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS); 31815516c77SSepherosa Ziehau 3195bdfd3fdSDexuan Cui static void hn_stop(struct hn_softc *, bool); 32015516c77SSepherosa Ziehau static void hn_init_locked(struct hn_softc *); 32115516c77SSepherosa Ziehau static int hn_chan_attach(struct hn_softc *, 32215516c77SSepherosa Ziehau struct vmbus_channel *); 32315516c77SSepherosa Ziehau static void hn_chan_detach(struct hn_softc *, 32415516c77SSepherosa Ziehau struct vmbus_channel *); 32515516c77SSepherosa Ziehau static int hn_attach_subchans(struct hn_softc *); 32615516c77SSepherosa Ziehau static void hn_detach_allchans(struct hn_softc *); 32715516c77SSepherosa Ziehau static void hn_chan_rollup(struct hn_rx_ring *, 32815516c77SSepherosa Ziehau struct hn_tx_ring *); 32915516c77SSepherosa Ziehau static void hn_set_ring_inuse(struct hn_softc *, int); 33015516c77SSepherosa Ziehau static int hn_synth_attach(struct hn_softc *, int); 33115516c77SSepherosa Ziehau static void hn_synth_detach(struct hn_softc *); 33215516c77SSepherosa Ziehau static int hn_synth_alloc_subchans(struct hn_softc *, 33315516c77SSepherosa Ziehau int *); 3342494d735SSepherosa Ziehau static bool hn_synth_attachable(const struct hn_softc *); 33515516c77SSepherosa Ziehau static void hn_suspend(struct hn_softc *); 33615516c77SSepherosa Ziehau static void hn_suspend_data(struct hn_softc *); 33715516c77SSepherosa Ziehau static void hn_suspend_mgmt(struct hn_softc *); 33815516c77SSepherosa Ziehau static void hn_resume(struct hn_softc *); 33915516c77SSepherosa Ziehau static void hn_resume_data(struct hn_softc *); 34015516c77SSepherosa Ziehau static void hn_resume_mgmt(struct hn_softc *); 34115516c77SSepherosa Ziehau static void hn_suspend_mgmt_taskfunc(void *, int); 34225641fc7SSepherosa Ziehau static void hn_chan_drain(struct hn_softc *, 34325641fc7SSepherosa Ziehau struct vmbus_channel *); 344b3b75d9cSSepherosa Ziehau static void hn_disable_rx(struct hn_softc *); 345b3b75d9cSSepherosa Ziehau static void hn_drain_rxtx(struct hn_softc *, int); 3466c1204dfSSepherosa Ziehau static void hn_polling(struct hn_softc *, u_int); 3476c1204dfSSepherosa Ziehau static void hn_chan_polling(struct vmbus_channel *, u_int); 34815516c77SSepherosa Ziehau 34915516c77SSepherosa Ziehau static void hn_update_link_status(struct hn_softc *); 35015516c77SSepherosa Ziehau static void hn_change_network(struct hn_softc *); 35115516c77SSepherosa Ziehau static void hn_link_taskfunc(void *, int); 35215516c77SSepherosa Ziehau static void hn_netchg_init_taskfunc(void *, int); 35315516c77SSepherosa Ziehau static void hn_netchg_status_taskfunc(void *, int); 35415516c77SSepherosa Ziehau static void hn_link_status(struct hn_softc *); 35515516c77SSepherosa Ziehau 35615516c77SSepherosa Ziehau static int hn_create_rx_data(struct hn_softc *, int); 35715516c77SSepherosa Ziehau static void hn_destroy_rx_data(struct hn_softc *); 35815516c77SSepherosa Ziehau static int hn_check_iplen(const struct mbuf *, int); 359f1b0a43fSSepherosa Ziehau static int hn_set_rxfilter(struct hn_softc *, uint32_t); 360c08f7b2cSSepherosa Ziehau static int hn_rxfilter_config(struct hn_softc *); 36134d68912SSepherosa Ziehau #ifndef RSS 36215516c77SSepherosa Ziehau static int hn_rss_reconfig(struct hn_softc *); 36334d68912SSepherosa Ziehau #endif 364afd4971bSSepherosa Ziehau static void hn_rss_ind_fixup(struct hn_softc *); 36515516c77SSepherosa Ziehau static int hn_rxpkt(struct hn_rx_ring *, const void *, 36615516c77SSepherosa Ziehau int, const struct hn_rxinfo *); 36715516c77SSepherosa Ziehau 36815516c77SSepherosa Ziehau static int hn_tx_ring_create(struct hn_softc *, int); 36915516c77SSepherosa Ziehau static void hn_tx_ring_destroy(struct hn_tx_ring *); 37015516c77SSepherosa Ziehau static int hn_create_tx_data(struct hn_softc *, int); 37115516c77SSepherosa Ziehau static void hn_fixup_tx_data(struct hn_softc *); 37215516c77SSepherosa Ziehau static void hn_destroy_tx_data(struct hn_softc *); 37315516c77SSepherosa Ziehau static void hn_txdesc_dmamap_destroy(struct hn_txdesc *); 37425641fc7SSepherosa Ziehau static void hn_txdesc_gc(struct hn_tx_ring *, 37525641fc7SSepherosa Ziehau struct hn_txdesc *); 376dc13fee6SSepherosa Ziehau static int hn_encap(struct ifnet *, struct hn_tx_ring *, 37715516c77SSepherosa Ziehau struct hn_txdesc *, struct mbuf **); 37815516c77SSepherosa Ziehau static int hn_txpkt(struct ifnet *, struct hn_tx_ring *, 37915516c77SSepherosa Ziehau struct hn_txdesc *); 38015516c77SSepherosa Ziehau static void hn_set_chim_size(struct hn_softc *, int); 38115516c77SSepherosa Ziehau static void hn_set_tso_maxsize(struct hn_softc *, int, int); 38215516c77SSepherosa Ziehau static bool hn_tx_ring_pending(struct hn_tx_ring *); 38315516c77SSepherosa Ziehau static void hn_tx_ring_qflush(struct hn_tx_ring *); 38415516c77SSepherosa Ziehau static void hn_resume_tx(struct hn_softc *, int); 385dc13fee6SSepherosa Ziehau static void hn_set_txagg(struct hn_softc *); 386dc13fee6SSepherosa Ziehau static void *hn_try_txagg(struct ifnet *, 387dc13fee6SSepherosa Ziehau struct hn_tx_ring *, struct hn_txdesc *, 388dc13fee6SSepherosa Ziehau int); 38915516c77SSepherosa Ziehau static int hn_get_txswq_depth(const struct hn_tx_ring *); 39015516c77SSepherosa Ziehau static void hn_txpkt_done(struct hn_nvs_sendctx *, 39115516c77SSepherosa Ziehau struct hn_softc *, struct vmbus_channel *, 39215516c77SSepherosa Ziehau const void *, int); 39315516c77SSepherosa Ziehau static int hn_txpkt_sglist(struct hn_tx_ring *, 39415516c77SSepherosa Ziehau struct hn_txdesc *); 39515516c77SSepherosa Ziehau static int hn_txpkt_chim(struct hn_tx_ring *, 39615516c77SSepherosa Ziehau struct hn_txdesc *); 39715516c77SSepherosa Ziehau static int hn_xmit(struct hn_tx_ring *, int); 39815516c77SSepherosa Ziehau static void hn_xmit_taskfunc(void *, int); 39915516c77SSepherosa Ziehau static void hn_xmit_txeof(struct hn_tx_ring *); 40015516c77SSepherosa Ziehau static void hn_xmit_txeof_taskfunc(void *, int); 40123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 40215516c77SSepherosa Ziehau static int hn_start_locked(struct hn_tx_ring *, int); 40315516c77SSepherosa Ziehau static void hn_start_taskfunc(void *, int); 40415516c77SSepherosa Ziehau static void hn_start_txeof(struct hn_tx_ring *); 40515516c77SSepherosa Ziehau static void hn_start_txeof_taskfunc(void *, int); 40623bf9e15SSepherosa Ziehau #endif 40715516c77SSepherosa Ziehau 40815516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 40915516c77SSepherosa Ziehau "Hyper-V network interface"); 41015516c77SSepherosa Ziehau 41115516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */ 41215516c77SSepherosa Ziehau static int hn_trust_hosttcp = 1; 41315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN, 41415516c77SSepherosa Ziehau &hn_trust_hosttcp, 0, 41515516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 41615516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 41715516c77SSepherosa Ziehau 41815516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */ 41915516c77SSepherosa Ziehau static int hn_trust_hostudp = 1; 42015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN, 42115516c77SSepherosa Ziehau &hn_trust_hostudp, 0, 42215516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 42315516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 42415516c77SSepherosa Ziehau 42515516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */ 42615516c77SSepherosa Ziehau static int hn_trust_hostip = 1; 42715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN, 42815516c77SSepherosa Ziehau &hn_trust_hostip, 0, 42915516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 43015516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 43115516c77SSepherosa Ziehau 43215516c77SSepherosa Ziehau /* Limit TSO burst size */ 43315516c77SSepherosa Ziehau static int hn_tso_maxlen = IP_MAXPACKET; 43415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN, 43515516c77SSepherosa Ziehau &hn_tso_maxlen, 0, "TSO burst limit"); 43615516c77SSepherosa Ziehau 43715516c77SSepherosa Ziehau /* Limit chimney send size */ 43815516c77SSepherosa Ziehau static int hn_tx_chimney_size = 0; 43915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN, 44015516c77SSepherosa Ziehau &hn_tx_chimney_size, 0, "Chimney send packet size limit"); 44115516c77SSepherosa Ziehau 44215516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */ 44315516c77SSepherosa Ziehau static int hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF; 44415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN, 44515516c77SSepherosa Ziehau &hn_direct_tx_size, 0, "Size of the packet for direct transmission"); 44615516c77SSepherosa Ziehau 44715516c77SSepherosa Ziehau /* # of LRO entries per RX ring */ 44815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 44915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 45015516c77SSepherosa Ziehau static int hn_lro_entry_count = HN_LROENT_CNT_DEF; 45115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN, 45215516c77SSepherosa Ziehau &hn_lro_entry_count, 0, "LRO entry count"); 45315516c77SSepherosa Ziehau #endif 45415516c77SSepherosa Ziehau #endif 45515516c77SSepherosa Ziehau 456fdd0222aSSepherosa Ziehau static int hn_tx_taskq_cnt = 1; 457fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN, 458fdd0222aSSepherosa Ziehau &hn_tx_taskq_cnt, 0, "# of TX taskqueues"); 459fdd0222aSSepherosa Ziehau 4600e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP 0 4610e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL 1 4620e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ 2 4630e11868dSSepherosa Ziehau 4640e11868dSSepherosa Ziehau static int hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP; 4650e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN, 4660e11868dSSepherosa Ziehau &hn_tx_taskq_mode, 0, "TX taskqueue modes: " 4670e11868dSSepherosa Ziehau "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs"); 4680e11868dSSepherosa Ziehau 46915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 47015516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 0; 47115516c77SSepherosa Ziehau #else 47215516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 1; 47315516c77SSepherosa Ziehau #endif 47415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD, 47515516c77SSepherosa Ziehau &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors"); 47615516c77SSepherosa Ziehau 47723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 47815516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */ 47915516c77SSepherosa Ziehau static int hn_use_if_start = 0; 48015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN, 48115516c77SSepherosa Ziehau &hn_use_if_start, 0, "Use if_start TX method"); 48223bf9e15SSepherosa Ziehau #endif 48315516c77SSepherosa Ziehau 48415516c77SSepherosa Ziehau /* # of channels to use */ 48515516c77SSepherosa Ziehau static int hn_chan_cnt = 0; 48615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN, 48715516c77SSepherosa Ziehau &hn_chan_cnt, 0, 48815516c77SSepherosa Ziehau "# of channels to use; each channel has one RX ring and one TX ring"); 48915516c77SSepherosa Ziehau 49015516c77SSepherosa Ziehau /* # of transmit rings to use */ 49115516c77SSepherosa Ziehau static int hn_tx_ring_cnt = 0; 49215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN, 49315516c77SSepherosa Ziehau &hn_tx_ring_cnt, 0, "# of TX rings to use"); 49415516c77SSepherosa Ziehau 49515516c77SSepherosa Ziehau /* Software TX ring deptch */ 49615516c77SSepherosa Ziehau static int hn_tx_swq_depth = 0; 49715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN, 49815516c77SSepherosa Ziehau &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING"); 49915516c77SSepherosa Ziehau 50015516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */ 50115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 50215516c77SSepherosa Ziehau static u_int hn_lro_mbufq_depth = 0; 50315516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN, 50415516c77SSepherosa Ziehau &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue"); 50515516c77SSepherosa Ziehau #endif 50615516c77SSepherosa Ziehau 507dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */ 508dc13fee6SSepherosa Ziehau static int hn_tx_agg_size = -1; 509dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN, 510dc13fee6SSepherosa Ziehau &hn_tx_agg_size, 0, "Packet transmission aggregation size limit"); 511dc13fee6SSepherosa Ziehau 512dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */ 513fa915c4dSSepherosa Ziehau static int hn_tx_agg_pkts = -1; 514dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN, 515dc13fee6SSepherosa Ziehau &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit"); 516dc13fee6SSepherosa Ziehau 517499c3e17SSepherosa Ziehau /* VF list */ 518499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vflist, CTLFLAG_RD | CTLTYPE_STRING, 519499c3e17SSepherosa Ziehau 0, 0, hn_vflist_sysctl, "A", "VF list"); 520499c3e17SSepherosa Ziehau 521499c3e17SSepherosa Ziehau /* VF mapping */ 522499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap, CTLFLAG_RD | CTLTYPE_STRING, 523499c3e17SSepherosa Ziehau 0, 0, hn_vfmap_sysctl, "A", "VF mapping"); 524499c3e17SSepherosa Ziehau 52515516c77SSepherosa Ziehau static u_int hn_cpu_index; /* next CPU for channel */ 526fdd0222aSSepherosa Ziehau static struct taskqueue **hn_tx_taskque;/* shared TX taskqueues */ 52715516c77SSepherosa Ziehau 528499c3e17SSepherosa Ziehau static struct rmlock hn_vfmap_lock; 529499c3e17SSepherosa Ziehau static int hn_vfmap_size; 530499c3e17SSepherosa Ziehau static struct ifnet **hn_vfmap; 531499c3e17SSepherosa Ziehau 53234d68912SSepherosa Ziehau #ifndef RSS 53315516c77SSepherosa Ziehau static const uint8_t 53415516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = { 53515516c77SSepherosa Ziehau 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 53615516c77SSepherosa Ziehau 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 53715516c77SSepherosa Ziehau 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 53815516c77SSepherosa Ziehau 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 53915516c77SSepherosa Ziehau 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa 54015516c77SSepherosa Ziehau }; 54134d68912SSepherosa Ziehau #endif /* !RSS */ 54215516c77SSepherosa Ziehau 54315516c77SSepherosa Ziehau static device_method_t hn_methods[] = { 54415516c77SSepherosa Ziehau /* Device interface */ 54515516c77SSepherosa Ziehau DEVMETHOD(device_probe, hn_probe), 54615516c77SSepherosa Ziehau DEVMETHOD(device_attach, hn_attach), 54715516c77SSepherosa Ziehau DEVMETHOD(device_detach, hn_detach), 54815516c77SSepherosa Ziehau DEVMETHOD(device_shutdown, hn_shutdown), 54915516c77SSepherosa Ziehau DEVMETHOD_END 55015516c77SSepherosa Ziehau }; 55115516c77SSepherosa Ziehau 55215516c77SSepherosa Ziehau static driver_t hn_driver = { 55315516c77SSepherosa Ziehau "hn", 55415516c77SSepherosa Ziehau hn_methods, 55515516c77SSepherosa Ziehau sizeof(struct hn_softc) 55615516c77SSepherosa Ziehau }; 55715516c77SSepherosa Ziehau 55815516c77SSepherosa Ziehau static devclass_t hn_devclass; 55915516c77SSepherosa Ziehau 56015516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0); 56115516c77SSepherosa Ziehau MODULE_VERSION(hn, 1); 56215516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1); 56315516c77SSepherosa Ziehau 56415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 56515516c77SSepherosa Ziehau static void 56615516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim) 56715516c77SSepherosa Ziehau { 56815516c77SSepherosa Ziehau int i; 56915516c77SSepherosa Ziehau 570a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 57115516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim; 57215516c77SSepherosa Ziehau } 57315516c77SSepherosa Ziehau #endif 57415516c77SSepherosa Ziehau 57515516c77SSepherosa Ziehau static int 57615516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd) 57715516c77SSepherosa Ziehau { 57815516c77SSepherosa Ziehau 57915516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 58015516c77SSepherosa Ziehau txd->chim_size == 0, ("invalid rndis sglist txd")); 58115516c77SSepherosa Ziehau return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA, 58215516c77SSepherosa Ziehau &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt)); 58315516c77SSepherosa Ziehau } 58415516c77SSepherosa Ziehau 58515516c77SSepherosa Ziehau static int 58615516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd) 58715516c77SSepherosa Ziehau { 58815516c77SSepherosa Ziehau struct hn_nvs_rndis rndis; 58915516c77SSepherosa Ziehau 59015516c77SSepherosa Ziehau KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID && 59115516c77SSepherosa Ziehau txd->chim_size > 0, ("invalid rndis chim txd")); 59215516c77SSepherosa Ziehau 59315516c77SSepherosa Ziehau rndis.nvs_type = HN_NVS_TYPE_RNDIS; 59415516c77SSepherosa Ziehau rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA; 59515516c77SSepherosa Ziehau rndis.nvs_chim_idx = txd->chim_index; 59615516c77SSepherosa Ziehau rndis.nvs_chim_sz = txd->chim_size; 59715516c77SSepherosa Ziehau 59815516c77SSepherosa Ziehau return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC, 59915516c77SSepherosa Ziehau &rndis, sizeof(rndis), &txd->send_ctx)); 60015516c77SSepherosa Ziehau } 60115516c77SSepherosa Ziehau 60215516c77SSepherosa Ziehau static __inline uint32_t 60315516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc) 60415516c77SSepherosa Ziehau { 60515516c77SSepherosa Ziehau int i, bmap_cnt = sc->hn_chim_bmap_cnt; 60615516c77SSepherosa Ziehau u_long *bmap = sc->hn_chim_bmap; 60715516c77SSepherosa Ziehau uint32_t ret = HN_NVS_CHIM_IDX_INVALID; 60815516c77SSepherosa Ziehau 60915516c77SSepherosa Ziehau for (i = 0; i < bmap_cnt; ++i) { 61015516c77SSepherosa Ziehau int idx; 61115516c77SSepherosa Ziehau 61215516c77SSepherosa Ziehau idx = ffsl(~bmap[i]); 61315516c77SSepherosa Ziehau if (idx == 0) 61415516c77SSepherosa Ziehau continue; 61515516c77SSepherosa Ziehau 61615516c77SSepherosa Ziehau --idx; /* ffsl is 1-based */ 61715516c77SSepherosa Ziehau KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt, 61815516c77SSepherosa Ziehau ("invalid i %d and idx %d", i, idx)); 61915516c77SSepherosa Ziehau 62015516c77SSepherosa Ziehau if (atomic_testandset_long(&bmap[i], idx)) 62115516c77SSepherosa Ziehau continue; 62215516c77SSepherosa Ziehau 62315516c77SSepherosa Ziehau ret = i * LONG_BIT + idx; 62415516c77SSepherosa Ziehau break; 62515516c77SSepherosa Ziehau } 62615516c77SSepherosa Ziehau return (ret); 62715516c77SSepherosa Ziehau } 62815516c77SSepherosa Ziehau 62915516c77SSepherosa Ziehau static __inline void 63015516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx) 63115516c77SSepherosa Ziehau { 63215516c77SSepherosa Ziehau u_long mask; 63315516c77SSepherosa Ziehau uint32_t idx; 63415516c77SSepherosa Ziehau 63515516c77SSepherosa Ziehau idx = chim_idx / LONG_BIT; 63615516c77SSepherosa Ziehau KASSERT(idx < sc->hn_chim_bmap_cnt, 63715516c77SSepherosa Ziehau ("invalid chimney index 0x%x", chim_idx)); 63815516c77SSepherosa Ziehau 63915516c77SSepherosa Ziehau mask = 1UL << (chim_idx % LONG_BIT); 64015516c77SSepherosa Ziehau KASSERT(sc->hn_chim_bmap[idx] & mask, 64115516c77SSepherosa Ziehau ("index bitmap 0x%lx, chimney index %u, " 64215516c77SSepherosa Ziehau "bitmap idx %d, bitmask 0x%lx", 64315516c77SSepherosa Ziehau sc->hn_chim_bmap[idx], chim_idx, idx, mask)); 64415516c77SSepherosa Ziehau 64515516c77SSepherosa Ziehau atomic_clear_long(&sc->hn_chim_bmap[idx], mask); 64615516c77SSepherosa Ziehau } 64715516c77SSepherosa Ziehau 648edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 649cc0c6ebcSSepherosa Ziehau 650cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len) \ 651cc0c6ebcSSepherosa Ziehau do { \ 652cc0c6ebcSSepherosa Ziehau if (__predict_false((m)->m_len < (len))) { \ 653cc0c6ebcSSepherosa Ziehau (m) = m_pullup((m), (len)); \ 654cc0c6ebcSSepherosa Ziehau if ((m) == NULL) \ 655cc0c6ebcSSepherosa Ziehau return (NULL); \ 656cc0c6ebcSSepherosa Ziehau } \ 657cc0c6ebcSSepherosa Ziehau } while (0) 658cc0c6ebcSSepherosa Ziehau 659edd3f315SSepherosa Ziehau /* 660edd3f315SSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 661edd3f315SSepherosa Ziehau */ 662edd3f315SSepherosa Ziehau static __inline struct mbuf * 663edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head) 664edd3f315SSepherosa Ziehau { 665edd3f315SSepherosa Ziehau struct ether_vlan_header *evl; 666edd3f315SSepherosa Ziehau struct tcphdr *th; 667edd3f315SSepherosa Ziehau int ehlen; 668edd3f315SSepherosa Ziehau 669edd3f315SSepherosa Ziehau KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable")); 670edd3f315SSepherosa Ziehau 671edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, sizeof(*evl)); 672edd3f315SSepherosa Ziehau evl = mtod(m_head, struct ether_vlan_header *); 673edd3f315SSepherosa Ziehau if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) 674edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 675edd3f315SSepherosa Ziehau else 676edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN; 677edd3f315SSepherosa Ziehau 678edd3f315SSepherosa Ziehau #ifdef INET 679edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 680edd3f315SSepherosa Ziehau struct ip *ip; 681edd3f315SSepherosa Ziehau int iphlen; 682edd3f315SSepherosa Ziehau 683edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip)); 684edd3f315SSepherosa Ziehau ip = mtodo(m_head, ehlen); 685edd3f315SSepherosa Ziehau iphlen = ip->ip_hl << 2; 686edd3f315SSepherosa Ziehau 687edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 688edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 689edd3f315SSepherosa Ziehau 690edd3f315SSepherosa Ziehau ip->ip_len = 0; 691edd3f315SSepherosa Ziehau ip->ip_sum = 0; 692edd3f315SSepherosa Ziehau th->th_sum = in_pseudo(ip->ip_src.s_addr, 693edd3f315SSepherosa Ziehau ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 694edd3f315SSepherosa Ziehau } 695edd3f315SSepherosa Ziehau #endif 696edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET) 697edd3f315SSepherosa Ziehau else 698edd3f315SSepherosa Ziehau #endif 699edd3f315SSepherosa Ziehau #ifdef INET6 700edd3f315SSepherosa Ziehau { 701edd3f315SSepherosa Ziehau struct ip6_hdr *ip6; 702edd3f315SSepherosa Ziehau 703edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); 704edd3f315SSepherosa Ziehau ip6 = mtodo(m_head, ehlen); 705edd3f315SSepherosa Ziehau if (ip6->ip6_nxt != IPPROTO_TCP) { 706edd3f315SSepherosa Ziehau m_freem(m_head); 707edd3f315SSepherosa Ziehau return (NULL); 708edd3f315SSepherosa Ziehau } 709edd3f315SSepherosa Ziehau 710edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); 711edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + sizeof(*ip6)); 712edd3f315SSepherosa Ziehau 713edd3f315SSepherosa Ziehau ip6->ip6_plen = 0; 714edd3f315SSepherosa Ziehau th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 715edd3f315SSepherosa Ziehau } 716edd3f315SSepherosa Ziehau #endif 717edd3f315SSepherosa Ziehau return (m_head); 718edd3f315SSepherosa Ziehau 719edd3f315SSepherosa Ziehau } 720cc0c6ebcSSepherosa Ziehau 721cc0c6ebcSSepherosa Ziehau /* 722cc0c6ebcSSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 723cc0c6ebcSSepherosa Ziehau */ 724cc0c6ebcSSepherosa Ziehau static __inline struct mbuf * 725cc0c6ebcSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn) 726cc0c6ebcSSepherosa Ziehau { 727cc0c6ebcSSepherosa Ziehau const struct ether_vlan_header *evl; 728cc0c6ebcSSepherosa Ziehau const struct tcphdr *th; 729cc0c6ebcSSepherosa Ziehau int ehlen; 730cc0c6ebcSSepherosa Ziehau 731cc0c6ebcSSepherosa Ziehau *tcpsyn = 0; 732cc0c6ebcSSepherosa Ziehau 733cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, sizeof(*evl)); 734cc0c6ebcSSepherosa Ziehau evl = mtod(m_head, const struct ether_vlan_header *); 735cc0c6ebcSSepherosa Ziehau if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) 736cc0c6ebcSSepherosa Ziehau ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 737cc0c6ebcSSepherosa Ziehau else 738cc0c6ebcSSepherosa Ziehau ehlen = ETHER_HDR_LEN; 739cc0c6ebcSSepherosa Ziehau 740cc0c6ebcSSepherosa Ziehau #ifdef INET 741cc0c6ebcSSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TCP) { 742cc0c6ebcSSepherosa Ziehau const struct ip *ip; 743cc0c6ebcSSepherosa Ziehau int iphlen; 744cc0c6ebcSSepherosa Ziehau 745cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip)); 746cc0c6ebcSSepherosa Ziehau ip = mtodo(m_head, ehlen); 747cc0c6ebcSSepherosa Ziehau iphlen = ip->ip_hl << 2; 748cc0c6ebcSSepherosa Ziehau 749cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 750cc0c6ebcSSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 751cc0c6ebcSSepherosa Ziehau if (th->th_flags & TH_SYN) 752cc0c6ebcSSepherosa Ziehau *tcpsyn = 1; 753cc0c6ebcSSepherosa Ziehau } 754cc0c6ebcSSepherosa Ziehau #endif 755cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET) 756cc0c6ebcSSepherosa Ziehau else 757cc0c6ebcSSepherosa Ziehau #endif 758cc0c6ebcSSepherosa Ziehau #ifdef INET6 759cc0c6ebcSSepherosa Ziehau { 760cc0c6ebcSSepherosa Ziehau const struct ip6_hdr *ip6; 761cc0c6ebcSSepherosa Ziehau 762cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); 763cc0c6ebcSSepherosa Ziehau ip6 = mtodo(m_head, ehlen); 764cc0c6ebcSSepherosa Ziehau if (ip6->ip6_nxt != IPPROTO_TCP) 765cc0c6ebcSSepherosa Ziehau return (m_head); 766cc0c6ebcSSepherosa Ziehau 767cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); 768cc0c6ebcSSepherosa Ziehau th = mtodo(m_head, ehlen + sizeof(*ip6)); 769cc0c6ebcSSepherosa Ziehau if (th->th_flags & TH_SYN) 770cc0c6ebcSSepherosa Ziehau *tcpsyn = 1; 771cc0c6ebcSSepherosa Ziehau } 772cc0c6ebcSSepherosa Ziehau #endif 773cc0c6ebcSSepherosa Ziehau return (m_head); 774cc0c6ebcSSepherosa Ziehau } 775cc0c6ebcSSepherosa Ziehau 776cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR 777cc0c6ebcSSepherosa Ziehau 778edd3f315SSepherosa Ziehau #endif /* INET6 || INET */ 779edd3f315SSepherosa Ziehau 78015516c77SSepherosa Ziehau static int 781f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter) 782f1b0a43fSSepherosa Ziehau { 783f1b0a43fSSepherosa Ziehau int error = 0; 784f1b0a43fSSepherosa Ziehau 785f1b0a43fSSepherosa Ziehau HN_LOCK_ASSERT(sc); 786f1b0a43fSSepherosa Ziehau 787f1b0a43fSSepherosa Ziehau if (sc->hn_rx_filter != filter) { 788f1b0a43fSSepherosa Ziehau error = hn_rndis_set_rxfilter(sc, filter); 789f1b0a43fSSepherosa Ziehau if (!error) 790f1b0a43fSSepherosa Ziehau sc->hn_rx_filter = filter; 791f1b0a43fSSepherosa Ziehau } 792f1b0a43fSSepherosa Ziehau return (error); 793f1b0a43fSSepherosa Ziehau } 794f1b0a43fSSepherosa Ziehau 795f1b0a43fSSepherosa Ziehau static int 796c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc) 79715516c77SSepherosa Ziehau { 79815516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 79915516c77SSepherosa Ziehau uint32_t filter; 80015516c77SSepherosa Ziehau 80115516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 80215516c77SSepherosa Ziehau 8035bdfd3fdSDexuan Cui if ((ifp->if_flags & IFF_PROMISC) || 8045bdfd3fdSDexuan Cui (sc->hn_flags & HN_FLAG_VF)) { 80515516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_PROMISCUOUS; 80615516c77SSepherosa Ziehau } else { 80715516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_DIRECTED; 80815516c77SSepherosa Ziehau if (ifp->if_flags & IFF_BROADCAST) 80915516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_BROADCAST; 81015516c77SSepherosa Ziehau /* TODO: support multicast list */ 81115516c77SSepherosa Ziehau if ((ifp->if_flags & IFF_ALLMULTI) || 81215516c77SSepherosa Ziehau !TAILQ_EMPTY(&ifp->if_multiaddrs)) 81315516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 81415516c77SSepherosa Ziehau } 815f1b0a43fSSepherosa Ziehau return (hn_set_rxfilter(sc, filter)); 81615516c77SSepherosa Ziehau } 81715516c77SSepherosa Ziehau 818dc13fee6SSepherosa Ziehau static void 819dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc) 820dc13fee6SSepherosa Ziehau { 821dc13fee6SSepherosa Ziehau uint32_t size, pkts; 822dc13fee6SSepherosa Ziehau int i; 823dc13fee6SSepherosa Ziehau 824dc13fee6SSepherosa Ziehau /* 825dc13fee6SSepherosa Ziehau * Setup aggregation size. 826dc13fee6SSepherosa Ziehau */ 827dc13fee6SSepherosa Ziehau if (sc->hn_agg_size < 0) 828dc13fee6SSepherosa Ziehau size = UINT32_MAX; 829dc13fee6SSepherosa Ziehau else 830dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 831dc13fee6SSepherosa Ziehau 832dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_size < size) 833dc13fee6SSepherosa Ziehau size = sc->hn_rndis_agg_size; 834dc13fee6SSepherosa Ziehau 835a4364cfeSSepherosa Ziehau /* NOTE: We only aggregate packets using chimney sending buffers. */ 836a4364cfeSSepherosa Ziehau if (size > (uint32_t)sc->hn_chim_szmax) 837a4364cfeSSepherosa Ziehau size = sc->hn_chim_szmax; 838a4364cfeSSepherosa Ziehau 839dc13fee6SSepherosa Ziehau if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) { 840dc13fee6SSepherosa Ziehau /* Disable */ 841dc13fee6SSepherosa Ziehau size = 0; 842dc13fee6SSepherosa Ziehau pkts = 0; 843dc13fee6SSepherosa Ziehau goto done; 844dc13fee6SSepherosa Ziehau } 845dc13fee6SSepherosa Ziehau 846dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'int'. */ 847dc13fee6SSepherosa Ziehau if (size > INT_MAX) 848dc13fee6SSepherosa Ziehau size = INT_MAX; 849dc13fee6SSepherosa Ziehau 850dc13fee6SSepherosa Ziehau /* 851dc13fee6SSepherosa Ziehau * Setup aggregation packet count. 852dc13fee6SSepherosa Ziehau */ 853dc13fee6SSepherosa Ziehau if (sc->hn_agg_pkts < 0) 854dc13fee6SSepherosa Ziehau pkts = UINT32_MAX; 855dc13fee6SSepherosa Ziehau else 856dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 857dc13fee6SSepherosa Ziehau 858dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_pkts < pkts) 859dc13fee6SSepherosa Ziehau pkts = sc->hn_rndis_agg_pkts; 860dc13fee6SSepherosa Ziehau 861dc13fee6SSepherosa Ziehau if (pkts <= 1) { 862dc13fee6SSepherosa Ziehau /* Disable */ 863dc13fee6SSepherosa Ziehau size = 0; 864dc13fee6SSepherosa Ziehau pkts = 0; 865dc13fee6SSepherosa Ziehau goto done; 866dc13fee6SSepherosa Ziehau } 867dc13fee6SSepherosa Ziehau 868dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 869dc13fee6SSepherosa Ziehau if (pkts > SHRT_MAX) 870dc13fee6SSepherosa Ziehau pkts = SHRT_MAX; 871dc13fee6SSepherosa Ziehau 872dc13fee6SSepherosa Ziehau done: 873dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 874dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_align > SHRT_MAX) { 875dc13fee6SSepherosa Ziehau /* Disable */ 876dc13fee6SSepherosa Ziehau size = 0; 877dc13fee6SSepherosa Ziehau pkts = 0; 878dc13fee6SSepherosa Ziehau } 879dc13fee6SSepherosa Ziehau 880dc13fee6SSepherosa Ziehau if (bootverbose) { 881dc13fee6SSepherosa Ziehau if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n", 882dc13fee6SSepherosa Ziehau size, pkts, sc->hn_rndis_agg_align); 883dc13fee6SSepherosa Ziehau } 884dc13fee6SSepherosa Ziehau 885dc13fee6SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 886dc13fee6SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 887dc13fee6SSepherosa Ziehau 888dc13fee6SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 889dc13fee6SSepherosa Ziehau txr->hn_agg_szmax = size; 890dc13fee6SSepherosa Ziehau txr->hn_agg_pktmax = pkts; 891dc13fee6SSepherosa Ziehau txr->hn_agg_align = sc->hn_rndis_agg_align; 892dc13fee6SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 893dc13fee6SSepherosa Ziehau } 894dc13fee6SSepherosa Ziehau } 895dc13fee6SSepherosa Ziehau 89615516c77SSepherosa Ziehau static int 89715516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr) 89815516c77SSepherosa Ziehau { 89915516c77SSepherosa Ziehau 90015516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet")); 90115516c77SSepherosa Ziehau if (hn_tx_swq_depth < txr->hn_txdesc_cnt) 90215516c77SSepherosa Ziehau return txr->hn_txdesc_cnt; 90315516c77SSepherosa Ziehau return hn_tx_swq_depth; 90415516c77SSepherosa Ziehau } 90515516c77SSepherosa Ziehau 90634d68912SSepherosa Ziehau #ifndef RSS 90715516c77SSepherosa Ziehau static int 90815516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc) 90915516c77SSepherosa Ziehau { 91015516c77SSepherosa Ziehau int error; 91115516c77SSepherosa Ziehau 91215516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 91315516c77SSepherosa Ziehau 91415516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 91515516c77SSepherosa Ziehau return (ENXIO); 91615516c77SSepherosa Ziehau 91715516c77SSepherosa Ziehau /* 91815516c77SSepherosa Ziehau * Disable RSS first. 91915516c77SSepherosa Ziehau * 92015516c77SSepherosa Ziehau * NOTE: 92115516c77SSepherosa Ziehau * Direct reconfiguration by setting the UNCHG flags does 92215516c77SSepherosa Ziehau * _not_ work properly. 92315516c77SSepherosa Ziehau */ 92415516c77SSepherosa Ziehau if (bootverbose) 92515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "disable RSS\n"); 92615516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE); 92715516c77SSepherosa Ziehau if (error) { 92815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS disable failed\n"); 92915516c77SSepherosa Ziehau return (error); 93015516c77SSepherosa Ziehau } 93115516c77SSepherosa Ziehau 93215516c77SSepherosa Ziehau /* 93315516c77SSepherosa Ziehau * Reenable the RSS w/ the updated RSS key or indirect 93415516c77SSepherosa Ziehau * table. 93515516c77SSepherosa Ziehau */ 93615516c77SSepherosa Ziehau if (bootverbose) 93715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "reconfig RSS\n"); 93815516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 93915516c77SSepherosa Ziehau if (error) { 94015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS reconfig failed\n"); 94115516c77SSepherosa Ziehau return (error); 94215516c77SSepherosa Ziehau } 94315516c77SSepherosa Ziehau return (0); 94415516c77SSepherosa Ziehau } 94534d68912SSepherosa Ziehau #endif /* !RSS */ 94615516c77SSepherosa Ziehau 94715516c77SSepherosa Ziehau static void 948afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc) 94915516c77SSepherosa Ziehau { 95015516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 951afd4971bSSepherosa Ziehau int i, nchan; 95215516c77SSepherosa Ziehau 953afd4971bSSepherosa Ziehau nchan = sc->hn_rx_ring_inuse; 95415516c77SSepherosa Ziehau KASSERT(nchan > 1, ("invalid # of channels %d", nchan)); 95515516c77SSepherosa Ziehau 95615516c77SSepherosa Ziehau /* 95715516c77SSepherosa Ziehau * Check indirect table to make sure that all channels in it 95815516c77SSepherosa Ziehau * can be used. 95915516c77SSepherosa Ziehau */ 96015516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 96115516c77SSepherosa Ziehau if (rss->rss_ind[i] >= nchan) { 96215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, 96315516c77SSepherosa Ziehau "RSS indirect table %d fixup: %u -> %d\n", 96415516c77SSepherosa Ziehau i, rss->rss_ind[i], nchan - 1); 96515516c77SSepherosa Ziehau rss->rss_ind[i] = nchan - 1; 96615516c77SSepherosa Ziehau } 96715516c77SSepherosa Ziehau } 96815516c77SSepherosa Ziehau } 96915516c77SSepherosa Ziehau 97015516c77SSepherosa Ziehau static int 97115516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused) 97215516c77SSepherosa Ziehau { 97315516c77SSepherosa Ziehau 97415516c77SSepherosa Ziehau return EOPNOTSUPP; 97515516c77SSepherosa Ziehau } 97615516c77SSepherosa Ziehau 97715516c77SSepherosa Ziehau static void 97815516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 97915516c77SSepherosa Ziehau { 98015516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 98115516c77SSepherosa Ziehau 98215516c77SSepherosa Ziehau ifmr->ifm_status = IFM_AVALID; 98315516c77SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 98415516c77SSepherosa Ziehau 98515516c77SSepherosa Ziehau if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) { 98615516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_NONE; 98715516c77SSepherosa Ziehau return; 98815516c77SSepherosa Ziehau } 98915516c77SSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 99015516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 99115516c77SSepherosa Ziehau } 99215516c77SSepherosa Ziehau 9935bdfd3fdSDexuan Cui static void 9945bdfd3fdSDexuan Cui hn_update_vf_task(void *arg, int pending __unused) 9955bdfd3fdSDexuan Cui { 9965bdfd3fdSDexuan Cui struct hn_update_vf *uv = arg; 9975bdfd3fdSDexuan Cui 998499c3e17SSepherosa Ziehau uv->rxr->hn_rxvf_ifp = uv->vf; 9995bdfd3fdSDexuan Cui } 10005bdfd3fdSDexuan Cui 10015bdfd3fdSDexuan Cui static void 10025bdfd3fdSDexuan Cui hn_update_vf(struct hn_softc *sc, struct ifnet *vf) 10035bdfd3fdSDexuan Cui { 10045bdfd3fdSDexuan Cui struct hn_rx_ring *rxr; 10055bdfd3fdSDexuan Cui struct hn_update_vf uv; 10065bdfd3fdSDexuan Cui struct task task; 10075bdfd3fdSDexuan Cui int i; 10085bdfd3fdSDexuan Cui 10095bdfd3fdSDexuan Cui HN_LOCK_ASSERT(sc); 10105bdfd3fdSDexuan Cui 10115bdfd3fdSDexuan Cui TASK_INIT(&task, 0, hn_update_vf_task, &uv); 10125bdfd3fdSDexuan Cui 10135bdfd3fdSDexuan Cui for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 10145bdfd3fdSDexuan Cui rxr = &sc->hn_rx_ring[i]; 10155bdfd3fdSDexuan Cui 10165bdfd3fdSDexuan Cui if (i < sc->hn_rx_ring_inuse) { 10175bdfd3fdSDexuan Cui uv.rxr = rxr; 10185bdfd3fdSDexuan Cui uv.vf = vf; 10195bdfd3fdSDexuan Cui vmbus_chan_run_task(rxr->hn_chan, &task); 10205bdfd3fdSDexuan Cui } else { 1021499c3e17SSepherosa Ziehau rxr->hn_rxvf_ifp = vf; 10225bdfd3fdSDexuan Cui } 10235bdfd3fdSDexuan Cui } 10245bdfd3fdSDexuan Cui } 10255bdfd3fdSDexuan Cui 1026499c3e17SSepherosa Ziehau static __inline bool 1027499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp) 1028499c3e17SSepherosa Ziehau { 1029499c3e17SSepherosa Ziehau const struct ifnet *hn_ifp; 1030499c3e17SSepherosa Ziehau 1031499c3e17SSepherosa Ziehau hn_ifp = sc->hn_ifp; 1032499c3e17SSepherosa Ziehau 1033499c3e17SSepherosa Ziehau if (ifp == hn_ifp) 1034499c3e17SSepherosa Ziehau return (false); 1035499c3e17SSepherosa Ziehau 1036499c3e17SSepherosa Ziehau if (ifp->if_alloctype != IFT_ETHER) 1037499c3e17SSepherosa Ziehau return (false); 1038499c3e17SSepherosa Ziehau 1039499c3e17SSepherosa Ziehau /* Ignore lagg/vlan interfaces */ 1040499c3e17SSepherosa Ziehau if (strcmp(ifp->if_dname, "lagg") == 0 || 1041499c3e17SSepherosa Ziehau strcmp(ifp->if_dname, "vlan") == 0) 1042499c3e17SSepherosa Ziehau return (false); 1043499c3e17SSepherosa Ziehau 1044499c3e17SSepherosa Ziehau if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0) 1045499c3e17SSepherosa Ziehau return (false); 1046499c3e17SSepherosa Ziehau 1047499c3e17SSepherosa Ziehau return (true); 1048499c3e17SSepherosa Ziehau } 1049499c3e17SSepherosa Ziehau 10505bdfd3fdSDexuan Cui static void 10515bdfd3fdSDexuan Cui hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf) 10525bdfd3fdSDexuan Cui { 10535bdfd3fdSDexuan Cui struct ifnet *hn_ifp; 10545bdfd3fdSDexuan Cui 10555bdfd3fdSDexuan Cui HN_LOCK(sc); 10565bdfd3fdSDexuan Cui 10575bdfd3fdSDexuan Cui if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 10585bdfd3fdSDexuan Cui goto out; 10595bdfd3fdSDexuan Cui 1060499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1061499c3e17SSepherosa Ziehau goto out; 1062499c3e17SSepherosa Ziehau 10635bdfd3fdSDexuan Cui hn_ifp = sc->hn_ifp; 10645bdfd3fdSDexuan Cui 10655bdfd3fdSDexuan Cui /* Now we're sure 'ifp' is a real VF device. */ 10665bdfd3fdSDexuan Cui if (vf) { 10675bdfd3fdSDexuan Cui if (sc->hn_flags & HN_FLAG_VF) 10685bdfd3fdSDexuan Cui goto out; 10695bdfd3fdSDexuan Cui 10705bdfd3fdSDexuan Cui sc->hn_flags |= HN_FLAG_VF; 10715bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 10725bdfd3fdSDexuan Cui } else { 10735bdfd3fdSDexuan Cui if (!(sc->hn_flags & HN_FLAG_VF)) 10745bdfd3fdSDexuan Cui goto out; 10755bdfd3fdSDexuan Cui 10765bdfd3fdSDexuan Cui sc->hn_flags &= ~HN_FLAG_VF; 1077499c3e17SSepherosa Ziehau if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 10785bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 10795bdfd3fdSDexuan Cui else 10805bdfd3fdSDexuan Cui hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE); 10815bdfd3fdSDexuan Cui } 10825bdfd3fdSDexuan Cui 10835bdfd3fdSDexuan Cui hn_nvs_set_datapath(sc, 10845bdfd3fdSDexuan Cui vf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTHETIC); 10855bdfd3fdSDexuan Cui 10865bdfd3fdSDexuan Cui hn_update_vf(sc, vf ? ifp : NULL); 10875bdfd3fdSDexuan Cui 10885bdfd3fdSDexuan Cui if (vf) { 10895bdfd3fdSDexuan Cui hn_suspend_mgmt(sc); 10905bdfd3fdSDexuan Cui sc->hn_link_flags &= 10915bdfd3fdSDexuan Cui ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG); 1092499c3e17SSepherosa Ziehau if_link_state_change(hn_ifp, LINK_STATE_DOWN); 10935bdfd3fdSDexuan Cui } else { 10945bdfd3fdSDexuan Cui hn_resume_mgmt(sc); 10955bdfd3fdSDexuan Cui } 10965bdfd3fdSDexuan Cui 109733408a34SDexuan Cui devctl_notify("HYPERV_NIC_VF", if_name(hn_ifp), 109833408a34SDexuan Cui vf ? "VF_UP" : "VF_DOWN", NULL); 109933408a34SDexuan Cui 11005bdfd3fdSDexuan Cui if (bootverbose) 11015bdfd3fdSDexuan Cui if_printf(hn_ifp, "Data path is switched %s %s\n", 11025bdfd3fdSDexuan Cui vf ? "to" : "from", if_name(ifp)); 11035bdfd3fdSDexuan Cui out: 11045bdfd3fdSDexuan Cui HN_UNLOCK(sc); 11055bdfd3fdSDexuan Cui } 11065bdfd3fdSDexuan Cui 11075bdfd3fdSDexuan Cui static void 11085bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event) 11095bdfd3fdSDexuan Cui { 11105bdfd3fdSDexuan Cui if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN) 11115bdfd3fdSDexuan Cui return; 11125bdfd3fdSDexuan Cui 11135bdfd3fdSDexuan Cui hn_set_vf(arg, ifp, event == IFNET_EVENT_UP); 11145bdfd3fdSDexuan Cui } 11155bdfd3fdSDexuan Cui 11165bdfd3fdSDexuan Cui static void 11175bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp) 11185bdfd3fdSDexuan Cui { 11195bdfd3fdSDexuan Cui hn_set_vf(arg, ifp, ifp->if_flags & IFF_UP); 11205bdfd3fdSDexuan Cui } 11215bdfd3fdSDexuan Cui 1122499c3e17SSepherosa Ziehau static void 1123499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp) 1124499c3e17SSepherosa Ziehau { 1125499c3e17SSepherosa Ziehau struct hn_softc *sc = xsc; 1126499c3e17SSepherosa Ziehau 1127499c3e17SSepherosa Ziehau HN_LOCK(sc); 1128499c3e17SSepherosa Ziehau 1129499c3e17SSepherosa Ziehau if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 1130499c3e17SSepherosa Ziehau goto done; 1131499c3e17SSepherosa Ziehau 1132499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1133499c3e17SSepherosa Ziehau goto done; 1134499c3e17SSepherosa Ziehau 1135499c3e17SSepherosa Ziehau if (sc->hn_vf_ifp != NULL) { 1136499c3e17SSepherosa Ziehau if_printf(sc->hn_ifp, "%s was attached as VF\n", 1137499c3e17SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 1138499c3e17SSepherosa Ziehau goto done; 1139499c3e17SSepherosa Ziehau } 1140499c3e17SSepherosa Ziehau 1141499c3e17SSepherosa Ziehau rm_wlock(&hn_vfmap_lock); 1142499c3e17SSepherosa Ziehau 1143499c3e17SSepherosa Ziehau if (ifp->if_index >= hn_vfmap_size) { 1144499c3e17SSepherosa Ziehau struct ifnet **newmap; 1145499c3e17SSepherosa Ziehau int newsize; 1146499c3e17SSepherosa Ziehau 1147499c3e17SSepherosa Ziehau newsize = ifp->if_index + HN_VFMAP_SIZE_DEF; 1148499c3e17SSepherosa Ziehau newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF, 1149499c3e17SSepherosa Ziehau M_WAITOK | M_ZERO); 1150499c3e17SSepherosa Ziehau 1151499c3e17SSepherosa Ziehau memcpy(newmap, hn_vfmap, 1152499c3e17SSepherosa Ziehau sizeof(struct ifnet *) * hn_vfmap_size); 1153499c3e17SSepherosa Ziehau free(hn_vfmap, M_DEVBUF); 1154499c3e17SSepherosa Ziehau hn_vfmap = newmap; 1155499c3e17SSepherosa Ziehau hn_vfmap_size = newsize; 1156499c3e17SSepherosa Ziehau } 1157499c3e17SSepherosa Ziehau KASSERT(hn_vfmap[ifp->if_index] == NULL, 1158499c3e17SSepherosa Ziehau ("%s: ifindex %d was mapped to %s", 1159499c3e17SSepherosa Ziehau ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname)); 1160499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index] = sc->hn_ifp; 1161499c3e17SSepherosa Ziehau 1162499c3e17SSepherosa Ziehau rm_wunlock(&hn_vfmap_lock); 1163499c3e17SSepherosa Ziehau 1164499c3e17SSepherosa Ziehau sc->hn_vf_ifp = ifp; 1165499c3e17SSepherosa Ziehau done: 1166499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 1167499c3e17SSepherosa Ziehau } 1168499c3e17SSepherosa Ziehau 1169499c3e17SSepherosa Ziehau static void 1170499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp) 1171499c3e17SSepherosa Ziehau { 1172499c3e17SSepherosa Ziehau struct hn_softc *sc = xsc; 1173499c3e17SSepherosa Ziehau 1174499c3e17SSepherosa Ziehau HN_LOCK(sc); 1175499c3e17SSepherosa Ziehau 1176499c3e17SSepherosa Ziehau if (sc->hn_vf_ifp == NULL) 1177499c3e17SSepherosa Ziehau goto done; 1178499c3e17SSepherosa Ziehau 1179499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1180499c3e17SSepherosa Ziehau goto done; 1181499c3e17SSepherosa Ziehau 1182499c3e17SSepherosa Ziehau sc->hn_vf_ifp = NULL; 1183499c3e17SSepherosa Ziehau 1184499c3e17SSepherosa Ziehau rm_wlock(&hn_vfmap_lock); 1185499c3e17SSepherosa Ziehau 1186499c3e17SSepherosa Ziehau KASSERT(ifp->if_index < hn_vfmap_size, 1187499c3e17SSepherosa Ziehau ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size)); 1188499c3e17SSepherosa Ziehau if (hn_vfmap[ifp->if_index] != NULL) { 1189499c3e17SSepherosa Ziehau KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp, 1190499c3e17SSepherosa Ziehau ("%s: ifindex %d was mapped to %s", 1191499c3e17SSepherosa Ziehau ifp->if_xname, ifp->if_index, 1192499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index]->if_xname)); 1193499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index] = NULL; 1194499c3e17SSepherosa Ziehau } 1195499c3e17SSepherosa Ziehau 1196499c3e17SSepherosa Ziehau rm_wunlock(&hn_vfmap_lock); 1197499c3e17SSepherosa Ziehau done: 1198499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 1199499c3e17SSepherosa Ziehau } 1200499c3e17SSepherosa Ziehau 120115516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ 120215516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = { 120315516c77SSepherosa Ziehau .hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 120415516c77SSepherosa Ziehau 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E} 120515516c77SSepherosa Ziehau }; 120615516c77SSepherosa Ziehau 120715516c77SSepherosa Ziehau static int 120815516c77SSepherosa Ziehau hn_probe(device_t dev) 120915516c77SSepherosa Ziehau { 121015516c77SSepherosa Ziehau 121115516c77SSepherosa Ziehau if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, 121215516c77SSepherosa Ziehau &g_net_vsc_device_type) == 0) { 121315516c77SSepherosa Ziehau device_set_desc(dev, "Hyper-V Network Interface"); 121415516c77SSepherosa Ziehau return BUS_PROBE_DEFAULT; 121515516c77SSepherosa Ziehau } 121615516c77SSepherosa Ziehau return ENXIO; 121715516c77SSepherosa Ziehau } 121815516c77SSepherosa Ziehau 121915516c77SSepherosa Ziehau static int 122015516c77SSepherosa Ziehau hn_attach(device_t dev) 122115516c77SSepherosa Ziehau { 122215516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 122315516c77SSepherosa Ziehau struct sysctl_oid_list *child; 122415516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 122515516c77SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 122615516c77SSepherosa Ziehau struct ifnet *ifp = NULL; 122715516c77SSepherosa Ziehau int error, ring_cnt, tx_ring_cnt; 122815516c77SSepherosa Ziehau 122915516c77SSepherosa Ziehau sc->hn_dev = dev; 123015516c77SSepherosa Ziehau sc->hn_prichan = vmbus_get_channel(dev); 123115516c77SSepherosa Ziehau HN_LOCK_INIT(sc); 123215516c77SSepherosa Ziehau 123315516c77SSepherosa Ziehau /* 1234dc13fee6SSepherosa Ziehau * Initialize these tunables once. 1235dc13fee6SSepherosa Ziehau */ 1236dc13fee6SSepherosa Ziehau sc->hn_agg_size = hn_tx_agg_size; 1237dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = hn_tx_agg_pkts; 1238dc13fee6SSepherosa Ziehau 1239dc13fee6SSepherosa Ziehau /* 124015516c77SSepherosa Ziehau * Setup taskqueue for transmission. 124115516c77SSepherosa Ziehau */ 12420e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) { 1243fdd0222aSSepherosa Ziehau int i; 1244fdd0222aSSepherosa Ziehau 1245fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = 1246fdd0222aSSepherosa Ziehau malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 1247fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 1248fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 1249fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx", 1250fdd0222aSSepherosa Ziehau M_WAITOK, taskqueue_thread_enqueue, 1251fdd0222aSSepherosa Ziehau &sc->hn_tx_taskqs[i]); 1252fdd0222aSSepherosa Ziehau taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET, 1253fdd0222aSSepherosa Ziehau "%s tx%d", device_get_nameunit(dev), i); 1254fdd0222aSSepherosa Ziehau } 12550e11868dSSepherosa Ziehau } else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) { 1256fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = hn_tx_taskque; 125715516c77SSepherosa Ziehau } 125815516c77SSepherosa Ziehau 125915516c77SSepherosa Ziehau /* 126015516c77SSepherosa Ziehau * Setup taskqueue for mangement tasks, e.g. link status. 126115516c77SSepherosa Ziehau */ 126215516c77SSepherosa Ziehau sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK, 126315516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0); 126415516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt", 126515516c77SSepherosa Ziehau device_get_nameunit(dev)); 126615516c77SSepherosa Ziehau TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc); 126715516c77SSepherosa Ziehau TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc); 126815516c77SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0, 126915516c77SSepherosa Ziehau hn_netchg_status_taskfunc, sc); 127015516c77SSepherosa Ziehau 127115516c77SSepherosa Ziehau /* 127215516c77SSepherosa Ziehau * Allocate ifnet and setup its name earlier, so that if_printf 127315516c77SSepherosa Ziehau * can be used by functions, which will be called after 127415516c77SSepherosa Ziehau * ether_ifattach(). 127515516c77SSepherosa Ziehau */ 127615516c77SSepherosa Ziehau ifp = sc->hn_ifp = if_alloc(IFT_ETHER); 127715516c77SSepherosa Ziehau ifp->if_softc = sc; 127815516c77SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 127915516c77SSepherosa Ziehau 128015516c77SSepherosa Ziehau /* 128115516c77SSepherosa Ziehau * Initialize ifmedia earlier so that it can be unconditionally 128215516c77SSepherosa Ziehau * destroyed, if error happened later on. 128315516c77SSepherosa Ziehau */ 128415516c77SSepherosa Ziehau ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts); 128515516c77SSepherosa Ziehau 128615516c77SSepherosa Ziehau /* 128715516c77SSepherosa Ziehau * Figure out the # of RX rings (ring_cnt) and the # of TX rings 128815516c77SSepherosa Ziehau * to use (tx_ring_cnt). 128915516c77SSepherosa Ziehau * 129015516c77SSepherosa Ziehau * NOTE: 129115516c77SSepherosa Ziehau * The # of RX rings to use is same as the # of channels to use. 129215516c77SSepherosa Ziehau */ 129315516c77SSepherosa Ziehau ring_cnt = hn_chan_cnt; 129415516c77SSepherosa Ziehau if (ring_cnt <= 0) { 129515516c77SSepherosa Ziehau /* Default */ 129615516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 129715516c77SSepherosa Ziehau if (ring_cnt > HN_RING_CNT_DEF_MAX) 129815516c77SSepherosa Ziehau ring_cnt = HN_RING_CNT_DEF_MAX; 129915516c77SSepherosa Ziehau } else if (ring_cnt > mp_ncpus) { 130015516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 130115516c77SSepherosa Ziehau } 130234d68912SSepherosa Ziehau #ifdef RSS 130334d68912SSepherosa Ziehau if (ring_cnt > rss_getnumbuckets()) 130434d68912SSepherosa Ziehau ring_cnt = rss_getnumbuckets(); 130534d68912SSepherosa Ziehau #endif 130615516c77SSepherosa Ziehau 130715516c77SSepherosa Ziehau tx_ring_cnt = hn_tx_ring_cnt; 130815516c77SSepherosa Ziehau if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt) 130915516c77SSepherosa Ziehau tx_ring_cnt = ring_cnt; 131023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 131115516c77SSepherosa Ziehau if (hn_use_if_start) { 131215516c77SSepherosa Ziehau /* ifnet.if_start only needs one TX ring. */ 131315516c77SSepherosa Ziehau tx_ring_cnt = 1; 131415516c77SSepherosa Ziehau } 131523bf9e15SSepherosa Ziehau #endif 131615516c77SSepherosa Ziehau 131715516c77SSepherosa Ziehau /* 131815516c77SSepherosa Ziehau * Set the leader CPU for channels. 131915516c77SSepherosa Ziehau */ 132015516c77SSepherosa Ziehau sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus; 132115516c77SSepherosa Ziehau 132215516c77SSepherosa Ziehau /* 132315516c77SSepherosa Ziehau * Create enough TX/RX rings, even if only limited number of 132415516c77SSepherosa Ziehau * channels can be allocated. 132515516c77SSepherosa Ziehau */ 132615516c77SSepherosa Ziehau error = hn_create_tx_data(sc, tx_ring_cnt); 132715516c77SSepherosa Ziehau if (error) 132815516c77SSepherosa Ziehau goto failed; 132915516c77SSepherosa Ziehau error = hn_create_rx_data(sc, ring_cnt); 133015516c77SSepherosa Ziehau if (error) 133115516c77SSepherosa Ziehau goto failed; 133215516c77SSepherosa Ziehau 133315516c77SSepherosa Ziehau /* 133415516c77SSepherosa Ziehau * Create transaction context for NVS and RNDIS transactions. 133515516c77SSepherosa Ziehau */ 133615516c77SSepherosa Ziehau sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev), 133715516c77SSepherosa Ziehau HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0); 133825641fc7SSepherosa Ziehau if (sc->hn_xact == NULL) { 133925641fc7SSepherosa Ziehau error = ENXIO; 134015516c77SSepherosa Ziehau goto failed; 134125641fc7SSepherosa Ziehau } 134225641fc7SSepherosa Ziehau 134325641fc7SSepherosa Ziehau /* 134425641fc7SSepherosa Ziehau * Install orphan handler for the revocation of this device's 134525641fc7SSepherosa Ziehau * primary channel. 134625641fc7SSepherosa Ziehau * 134725641fc7SSepherosa Ziehau * NOTE: 134825641fc7SSepherosa Ziehau * The processing order is critical here: 134925641fc7SSepherosa Ziehau * Install the orphan handler, _before_ testing whether this 135025641fc7SSepherosa Ziehau * device's primary channel has been revoked or not. 135125641fc7SSepherosa Ziehau */ 135225641fc7SSepherosa Ziehau vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact); 135325641fc7SSepherosa Ziehau if (vmbus_chan_is_revoked(sc->hn_prichan)) { 135425641fc7SSepherosa Ziehau error = ENXIO; 135525641fc7SSepherosa Ziehau goto failed; 135625641fc7SSepherosa Ziehau } 135715516c77SSepherosa Ziehau 135815516c77SSepherosa Ziehau /* 135915516c77SSepherosa Ziehau * Attach the synthetic parts, i.e. NVS and RNDIS. 136015516c77SSepherosa Ziehau */ 136115516c77SSepherosa Ziehau error = hn_synth_attach(sc, ETHERMTU); 136215516c77SSepherosa Ziehau if (error) 136315516c77SSepherosa Ziehau goto failed; 136415516c77SSepherosa Ziehau 136515516c77SSepherosa Ziehau error = hn_rndis_get_eaddr(sc, eaddr); 136615516c77SSepherosa Ziehau if (error) 136715516c77SSepherosa Ziehau goto failed; 136815516c77SSepherosa Ziehau 136915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 137015516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 137115516c77SSepherosa Ziehau /* 137215516c77SSepherosa Ziehau * Reduce TCP segment aggregation limit for multiple 137315516c77SSepherosa Ziehau * RX rings to increase ACK timeliness. 137415516c77SSepherosa Ziehau */ 137515516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF); 137615516c77SSepherosa Ziehau } 137715516c77SSepherosa Ziehau #endif 137815516c77SSepherosa Ziehau 137915516c77SSepherosa Ziehau /* 138015516c77SSepherosa Ziehau * Fixup TX stuffs after synthetic parts are attached. 138115516c77SSepherosa Ziehau */ 138215516c77SSepherosa Ziehau hn_fixup_tx_data(sc); 138315516c77SSepherosa Ziehau 138415516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 138515516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 138615516c77SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD, 138715516c77SSepherosa Ziehau &sc->hn_nvs_ver, 0, "NVS version"); 138815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version", 138915516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 139015516c77SSepherosa Ziehau hn_ndis_version_sysctl, "A", "NDIS version"); 139115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps", 139215516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 139315516c77SSepherosa Ziehau hn_caps_sysctl, "A", "capabilities"); 139415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist", 139515516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 139615516c77SSepherosa Ziehau hn_hwassist_sysctl, "A", "hwassist"); 139715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter", 139815516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 139915516c77SSepherosa Ziehau hn_rxfilter_sysctl, "A", "rxfilter"); 140015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash", 140115516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 140215516c77SSepherosa Ziehau hn_rss_hash_sysctl, "A", "RSS hash"); 140315516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size", 140415516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count"); 140534d68912SSepherosa Ziehau #ifndef RSS 140634d68912SSepherosa Ziehau /* 140734d68912SSepherosa Ziehau * Don't allow RSS key/indirect table changes, if RSS is defined. 140834d68912SSepherosa Ziehau */ 140915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key", 141015516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 141115516c77SSepherosa Ziehau hn_rss_key_sysctl, "IU", "RSS key"); 141215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind", 141315516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 141415516c77SSepherosa Ziehau hn_rss_ind_sysctl, "IU", "RSS indirect table"); 141534d68912SSepherosa Ziehau #endif 1416dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size", 1417dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_size, 0, 1418dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation size limit"); 1419dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts", 1420dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0, 1421dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation count limit"); 1422dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align", 1423dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_align, 0, 1424dc13fee6SSepherosa Ziehau "RNDIS packet transmission aggregation alignment"); 1425dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size", 1426dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 1427dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl, "I", 1428dc13fee6SSepherosa Ziehau "Packet transmission aggregation size, 0 -- disable, -1 -- auto"); 1429dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts", 1430dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 1431dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl, "I", 1432dc13fee6SSepherosa Ziehau "Packet transmission aggregation packets, " 1433dc13fee6SSepherosa Ziehau "0 -- disable, -1 -- auto"); 14346c1204dfSSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling", 14356c1204dfSSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 14366c1204dfSSepherosa Ziehau hn_polling_sysctl, "I", 14376c1204dfSSepherosa Ziehau "Polling frequency: [100,1000000], 0 disable polling"); 143840d60d6eSDexuan Cui SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf", 143940d60d6eSDexuan Cui CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 144040d60d6eSDexuan Cui hn_vf_sysctl, "A", "Virtual Function's name"); 1441499c3e17SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf", 1442499c3e17SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 1443499c3e17SSepherosa Ziehau hn_rxvf_sysctl, "A", "activated Virtual Function's name"); 144415516c77SSepherosa Ziehau 144515516c77SSepherosa Ziehau /* 144615516c77SSepherosa Ziehau * Setup the ifmedia, which has been initialized earlier. 144715516c77SSepherosa Ziehau */ 144815516c77SSepherosa Ziehau ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL); 144915516c77SSepherosa Ziehau ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO); 145015516c77SSepherosa Ziehau /* XXX ifmedia_set really should do this for us */ 145115516c77SSepherosa Ziehau sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media; 145215516c77SSepherosa Ziehau 145315516c77SSepherosa Ziehau /* 145415516c77SSepherosa Ziehau * Setup the ifnet for this interface. 145515516c77SSepherosa Ziehau */ 145615516c77SSepherosa Ziehau 145715516c77SSepherosa Ziehau ifp->if_baudrate = IF_Gbps(10); 145815516c77SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 145915516c77SSepherosa Ziehau ifp->if_ioctl = hn_ioctl; 146015516c77SSepherosa Ziehau ifp->if_init = hn_init; 146123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 146215516c77SSepherosa Ziehau if (hn_use_if_start) { 146315516c77SSepherosa Ziehau int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]); 146415516c77SSepherosa Ziehau 146515516c77SSepherosa Ziehau ifp->if_start = hn_start; 146615516c77SSepherosa Ziehau IFQ_SET_MAXLEN(&ifp->if_snd, qdepth); 146715516c77SSepherosa Ziehau ifp->if_snd.ifq_drv_maxlen = qdepth - 1; 146815516c77SSepherosa Ziehau IFQ_SET_READY(&ifp->if_snd); 146923bf9e15SSepherosa Ziehau } else 147023bf9e15SSepherosa Ziehau #endif 147123bf9e15SSepherosa Ziehau { 147215516c77SSepherosa Ziehau ifp->if_transmit = hn_transmit; 147315516c77SSepherosa Ziehau ifp->if_qflush = hn_xmit_qflush; 147415516c77SSepherosa Ziehau } 147515516c77SSepherosa Ziehau 147615516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO; 147715516c77SSepherosa Ziehau #ifdef foo 147815516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 147915516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM_IPV6; 148015516c77SSepherosa Ziehau #endif 148115516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_VLAN) { 148215516c77SSepherosa Ziehau /* XXX not sure about VLAN_MTU. */ 148315516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 148415516c77SSepherosa Ziehau } 148515516c77SSepherosa Ziehau 148615516c77SSepherosa Ziehau ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist; 148715516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP_MASK) 148815516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM; 148915516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP6_MASK) 149015516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM_IPV6; 149115516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO4) { 149215516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO4; 149315516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 149415516c77SSepherosa Ziehau } 149515516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO6) { 149615516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO6; 149715516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 149815516c77SSepherosa Ziehau } 149915516c77SSepherosa Ziehau 150015516c77SSepherosa Ziehau /* Enable all available capabilities by default. */ 150115516c77SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 150215516c77SSepherosa Ziehau 15037960e6baSSepherosa Ziehau /* 15047960e6baSSepherosa Ziehau * Disable IPv6 TSO and TXCSUM by default, they still can 15057960e6baSSepherosa Ziehau * be enabled through SIOCSIFCAP. 15067960e6baSSepherosa Ziehau */ 15077960e6baSSepherosa Ziehau ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 15087960e6baSSepherosa Ziehau ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO); 15097960e6baSSepherosa Ziehau 151015516c77SSepherosa Ziehau if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) { 151115516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU); 151215516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; 151315516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 151415516c77SSepherosa Ziehau } 151515516c77SSepherosa Ziehau 151615516c77SSepherosa Ziehau ether_ifattach(ifp, eaddr); 151715516c77SSepherosa Ziehau 151815516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) { 151915516c77SSepherosa Ziehau if_printf(ifp, "TSO segcnt %u segsz %u\n", 152015516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize); 152115516c77SSepherosa Ziehau } 152215516c77SSepherosa Ziehau 152315516c77SSepherosa Ziehau /* Inform the upper layer about the long frame support. */ 152415516c77SSepherosa Ziehau ifp->if_hdrlen = sizeof(struct ether_vlan_header); 152515516c77SSepherosa Ziehau 152615516c77SSepherosa Ziehau /* 152715516c77SSepherosa Ziehau * Kick off link status check. 152815516c77SSepherosa Ziehau */ 152915516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 153015516c77SSepherosa Ziehau hn_update_link_status(sc); 153115516c77SSepherosa Ziehau 15325bdfd3fdSDexuan Cui sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event, 15335bdfd3fdSDexuan Cui hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY); 15345bdfd3fdSDexuan Cui sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event, 15355bdfd3fdSDexuan Cui hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY); 15365bdfd3fdSDexuan Cui 1537499c3e17SSepherosa Ziehau sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event, 1538499c3e17SSepherosa Ziehau hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY); 1539499c3e17SSepherosa Ziehau sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event, 1540499c3e17SSepherosa Ziehau hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY); 1541499c3e17SSepherosa Ziehau 154215516c77SSepherosa Ziehau return (0); 154315516c77SSepherosa Ziehau failed: 154415516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) 154515516c77SSepherosa Ziehau hn_synth_detach(sc); 154615516c77SSepherosa Ziehau hn_detach(dev); 154715516c77SSepherosa Ziehau return (error); 154815516c77SSepherosa Ziehau } 154915516c77SSepherosa Ziehau 155015516c77SSepherosa Ziehau static int 155115516c77SSepherosa Ziehau hn_detach(device_t dev) 155215516c77SSepherosa Ziehau { 155315516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 1554499c3e17SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp, *vf_ifp; 155515516c77SSepherosa Ziehau 15565bdfd3fdSDexuan Cui if (sc->hn_ifaddr_evthand != NULL) 15575bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand); 15585bdfd3fdSDexuan Cui if (sc->hn_ifnet_evthand != NULL) 15595bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand); 1560499c3e17SSepherosa Ziehau if (sc->hn_ifnet_atthand != NULL) { 1561499c3e17SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ether_ifattach_event, 1562499c3e17SSepherosa Ziehau sc->hn_ifnet_atthand); 1563499c3e17SSepherosa Ziehau } 1564499c3e17SSepherosa Ziehau if (sc->hn_ifnet_dethand != NULL) { 1565499c3e17SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ifnet_departure_event, 1566499c3e17SSepherosa Ziehau sc->hn_ifnet_dethand); 1567499c3e17SSepherosa Ziehau } 1568499c3e17SSepherosa Ziehau 1569499c3e17SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 1570499c3e17SSepherosa Ziehau __compiler_membar(); 1571499c3e17SSepherosa Ziehau if (vf_ifp != NULL) 1572499c3e17SSepherosa Ziehau hn_ifnet_detevent(sc, vf_ifp); 15735bdfd3fdSDexuan Cui 157425641fc7SSepherosa Ziehau if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) { 157525641fc7SSepherosa Ziehau /* 157625641fc7SSepherosa Ziehau * In case that the vmbus missed the orphan handler 157725641fc7SSepherosa Ziehau * installation. 157825641fc7SSepherosa Ziehau */ 157925641fc7SSepherosa Ziehau vmbus_xact_ctx_orphan(sc->hn_xact); 158025641fc7SSepherosa Ziehau } 158125641fc7SSepherosa Ziehau 158215516c77SSepherosa Ziehau if (device_is_attached(dev)) { 158315516c77SSepherosa Ziehau HN_LOCK(sc); 158415516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 158515516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 15865bdfd3fdSDexuan Cui hn_stop(sc, true); 158715516c77SSepherosa Ziehau /* 158815516c77SSepherosa Ziehau * NOTE: 158915516c77SSepherosa Ziehau * hn_stop() only suspends data, so managment 159015516c77SSepherosa Ziehau * stuffs have to be suspended manually here. 159115516c77SSepherosa Ziehau */ 159215516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 159315516c77SSepherosa Ziehau hn_synth_detach(sc); 159415516c77SSepherosa Ziehau } 159515516c77SSepherosa Ziehau HN_UNLOCK(sc); 159615516c77SSepherosa Ziehau ether_ifdetach(ifp); 159715516c77SSepherosa Ziehau } 159815516c77SSepherosa Ziehau 159915516c77SSepherosa Ziehau ifmedia_removeall(&sc->hn_media); 160015516c77SSepherosa Ziehau hn_destroy_rx_data(sc); 160115516c77SSepherosa Ziehau hn_destroy_tx_data(sc); 160215516c77SSepherosa Ziehau 16030e11868dSSepherosa Ziehau if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) { 1604fdd0222aSSepherosa Ziehau int i; 1605fdd0222aSSepherosa Ziehau 1606fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 1607fdd0222aSSepherosa Ziehau taskqueue_free(sc->hn_tx_taskqs[i]); 1608fdd0222aSSepherosa Ziehau free(sc->hn_tx_taskqs, M_DEVBUF); 1609fdd0222aSSepherosa Ziehau } 161015516c77SSepherosa Ziehau taskqueue_free(sc->hn_mgmt_taskq0); 161115516c77SSepherosa Ziehau 161225641fc7SSepherosa Ziehau if (sc->hn_xact != NULL) { 161325641fc7SSepherosa Ziehau /* 161425641fc7SSepherosa Ziehau * Uninstall the orphan handler _before_ the xact is 161525641fc7SSepherosa Ziehau * destructed. 161625641fc7SSepherosa Ziehau */ 161725641fc7SSepherosa Ziehau vmbus_chan_unset_orphan(sc->hn_prichan); 161815516c77SSepherosa Ziehau vmbus_xact_ctx_destroy(sc->hn_xact); 161925641fc7SSepherosa Ziehau } 162015516c77SSepherosa Ziehau 162115516c77SSepherosa Ziehau if_free(ifp); 162215516c77SSepherosa Ziehau 162315516c77SSepherosa Ziehau HN_LOCK_DESTROY(sc); 162415516c77SSepherosa Ziehau return (0); 162515516c77SSepherosa Ziehau } 162615516c77SSepherosa Ziehau 162715516c77SSepherosa Ziehau static int 162815516c77SSepherosa Ziehau hn_shutdown(device_t dev) 162915516c77SSepherosa Ziehau { 163015516c77SSepherosa Ziehau 163115516c77SSepherosa Ziehau return (0); 163215516c77SSepherosa Ziehau } 163315516c77SSepherosa Ziehau 163415516c77SSepherosa Ziehau static void 163515516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc) 163615516c77SSepherosa Ziehau { 163715516c77SSepherosa Ziehau uint32_t link_status; 163815516c77SSepherosa Ziehau int error; 163915516c77SSepherosa Ziehau 164015516c77SSepherosa Ziehau error = hn_rndis_get_linkstatus(sc, &link_status); 164115516c77SSepherosa Ziehau if (error) { 164215516c77SSepherosa Ziehau /* XXX what to do? */ 164315516c77SSepherosa Ziehau return; 164415516c77SSepherosa Ziehau } 164515516c77SSepherosa Ziehau 164615516c77SSepherosa Ziehau if (link_status == NDIS_MEDIA_STATE_CONNECTED) 164715516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_LINKUP; 164815516c77SSepherosa Ziehau else 164915516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 165015516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, 165115516c77SSepherosa Ziehau (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ? 165215516c77SSepherosa Ziehau LINK_STATE_UP : LINK_STATE_DOWN); 165315516c77SSepherosa Ziehau } 165415516c77SSepherosa Ziehau 165515516c77SSepherosa Ziehau static void 165615516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused) 165715516c77SSepherosa Ziehau { 165815516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 165915516c77SSepherosa Ziehau 166015516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 166115516c77SSepherosa Ziehau return; 166215516c77SSepherosa Ziehau hn_link_status(sc); 166315516c77SSepherosa Ziehau } 166415516c77SSepherosa Ziehau 166515516c77SSepherosa Ziehau static void 166615516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused) 166715516c77SSepherosa Ziehau { 166815516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 166915516c77SSepherosa Ziehau 167015516c77SSepherosa Ziehau /* Prevent any link status checks from running. */ 167115516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_NETCHG; 167215516c77SSepherosa Ziehau 167315516c77SSepherosa Ziehau /* 167415516c77SSepherosa Ziehau * Fake up a [link down --> link up] state change; 5 seconds 167515516c77SSepherosa Ziehau * delay is used, which closely simulates miibus reaction 167615516c77SSepherosa Ziehau * upon link down event. 167715516c77SSepherosa Ziehau */ 167815516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 167915516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); 168015516c77SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0, 168115516c77SSepherosa Ziehau &sc->hn_netchg_status, 5 * hz); 168215516c77SSepherosa Ziehau } 168315516c77SSepherosa Ziehau 168415516c77SSepherosa Ziehau static void 168515516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused) 168615516c77SSepherosa Ziehau { 168715516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 168815516c77SSepherosa Ziehau 168915516c77SSepherosa Ziehau /* Re-allow link status checks. */ 169015516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG; 169115516c77SSepherosa Ziehau hn_link_status(sc); 169215516c77SSepherosa Ziehau } 169315516c77SSepherosa Ziehau 169415516c77SSepherosa Ziehau static void 169515516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc) 169615516c77SSepherosa Ziehau { 169715516c77SSepherosa Ziehau 169815516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 169915516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task); 170015516c77SSepherosa Ziehau } 170115516c77SSepherosa Ziehau 170215516c77SSepherosa Ziehau static void 170315516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc) 170415516c77SSepherosa Ziehau { 170515516c77SSepherosa Ziehau 170615516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 170715516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init); 170815516c77SSepherosa Ziehau } 170915516c77SSepherosa Ziehau 171015516c77SSepherosa Ziehau static __inline int 171115516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd, 171215516c77SSepherosa Ziehau struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) 171315516c77SSepherosa Ziehau { 171415516c77SSepherosa Ziehau struct mbuf *m = *m_head; 171515516c77SSepherosa Ziehau int error; 171615516c77SSepherosa Ziehau 171715516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim")); 171815516c77SSepherosa Ziehau 171915516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap, 172015516c77SSepherosa Ziehau m, segs, nsegs, BUS_DMA_NOWAIT); 172115516c77SSepherosa Ziehau if (error == EFBIG) { 172215516c77SSepherosa Ziehau struct mbuf *m_new; 172315516c77SSepherosa Ziehau 172415516c77SSepherosa Ziehau m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX); 172515516c77SSepherosa Ziehau if (m_new == NULL) 172615516c77SSepherosa Ziehau return ENOBUFS; 172715516c77SSepherosa Ziehau else 172815516c77SSepherosa Ziehau *m_head = m = m_new; 172915516c77SSepherosa Ziehau txr->hn_tx_collapsed++; 173015516c77SSepherosa Ziehau 173115516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, 173215516c77SSepherosa Ziehau txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT); 173315516c77SSepherosa Ziehau } 173415516c77SSepherosa Ziehau if (!error) { 173515516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap, 173615516c77SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 173715516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_DMAMAP; 173815516c77SSepherosa Ziehau } 173915516c77SSepherosa Ziehau return error; 174015516c77SSepherosa Ziehau } 174115516c77SSepherosa Ziehau 174215516c77SSepherosa Ziehau static __inline int 174315516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd) 174415516c77SSepherosa Ziehau { 174515516c77SSepherosa Ziehau 174615516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0, 174715516c77SSepherosa Ziehau ("put an onlist txd %#x", txd->flags)); 1748dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 1749dc13fee6SSepherosa Ziehau ("put an onagg txd %#x", txd->flags)); 175015516c77SSepherosa Ziehau 175115516c77SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 175215516c77SSepherosa Ziehau if (atomic_fetchadd_int(&txd->refs, -1) != 1) 175315516c77SSepherosa Ziehau return 0; 175415516c77SSepherosa Ziehau 1755dc13fee6SSepherosa Ziehau if (!STAILQ_EMPTY(&txd->agg_list)) { 1756dc13fee6SSepherosa Ziehau struct hn_txdesc *tmp_txd; 1757dc13fee6SSepherosa Ziehau 1758dc13fee6SSepherosa Ziehau while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) { 1759dc13fee6SSepherosa Ziehau int freed; 1760dc13fee6SSepherosa Ziehau 1761dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list), 1762dc13fee6SSepherosa Ziehau ("resursive aggregation on aggregated txdesc")); 1763dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG), 1764dc13fee6SSepherosa Ziehau ("not aggregated txdesc")); 1765dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 1766dc13fee6SSepherosa Ziehau ("aggregated txdesc uses dmamap")); 1767dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 1768dc13fee6SSepherosa Ziehau ("aggregated txdesc consumes " 1769dc13fee6SSepherosa Ziehau "chimney sending buffer")); 1770dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_size == 0, 1771dc13fee6SSepherosa Ziehau ("aggregated txdesc has non-zero " 1772dc13fee6SSepherosa Ziehau "chimney sending size")); 1773dc13fee6SSepherosa Ziehau 1774dc13fee6SSepherosa Ziehau STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link); 1775dc13fee6SSepherosa Ziehau tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG; 1776dc13fee6SSepherosa Ziehau freed = hn_txdesc_put(txr, tmp_txd); 1777dc13fee6SSepherosa Ziehau KASSERT(freed, ("failed to free aggregated txdesc")); 1778dc13fee6SSepherosa Ziehau } 1779dc13fee6SSepherosa Ziehau } 1780dc13fee6SSepherosa Ziehau 178115516c77SSepherosa Ziehau if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) { 178215516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 178315516c77SSepherosa Ziehau ("chim txd uses dmamap")); 178415516c77SSepherosa Ziehau hn_chim_free(txr->hn_sc, txd->chim_index); 178515516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 1786dc13fee6SSepherosa Ziehau txd->chim_size = 0; 178715516c77SSepherosa Ziehau } else if (txd->flags & HN_TXD_FLAG_DMAMAP) { 178815516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, 178915516c77SSepherosa Ziehau txd->data_dmap, BUS_DMASYNC_POSTWRITE); 179015516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_data_dtag, 179115516c77SSepherosa Ziehau txd->data_dmap); 179215516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_DMAMAP; 179315516c77SSepherosa Ziehau } 179415516c77SSepherosa Ziehau 179515516c77SSepherosa Ziehau if (txd->m != NULL) { 179615516c77SSepherosa Ziehau m_freem(txd->m); 179715516c77SSepherosa Ziehau txd->m = NULL; 179815516c77SSepherosa Ziehau } 179915516c77SSepherosa Ziehau 180015516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 180115516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 180215516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 180315516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail >= 0 && 180415516c77SSepherosa Ziehau txr->hn_txdesc_avail < txr->hn_txdesc_cnt, 180515516c77SSepherosa Ziehau ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail)); 180615516c77SSepherosa Ziehau txr->hn_txdesc_avail++; 180715516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 180815516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 180985e4ae1eSSepherosa Ziehau #else /* HN_USE_TXDESC_BUFRING */ 181085e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 181115516c77SSepherosa Ziehau atomic_add_int(&txr->hn_txdesc_avail, 1); 181215516c77SSepherosa Ziehau #endif 181385e4ae1eSSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 181485e4ae1eSSepherosa Ziehau #endif /* !HN_USE_TXDESC_BUFRING */ 181515516c77SSepherosa Ziehau 181615516c77SSepherosa Ziehau return 1; 181715516c77SSepherosa Ziehau } 181815516c77SSepherosa Ziehau 181915516c77SSepherosa Ziehau static __inline struct hn_txdesc * 182015516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr) 182115516c77SSepherosa Ziehau { 182215516c77SSepherosa Ziehau struct hn_txdesc *txd; 182315516c77SSepherosa Ziehau 182415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 182515516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 182615516c77SSepherosa Ziehau txd = SLIST_FIRST(&txr->hn_txlist); 182715516c77SSepherosa Ziehau if (txd != NULL) { 182815516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail > 0, 182915516c77SSepherosa Ziehau ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail)); 183015516c77SSepherosa Ziehau txr->hn_txdesc_avail--; 183115516c77SSepherosa Ziehau SLIST_REMOVE_HEAD(&txr->hn_txlist, link); 183215516c77SSepherosa Ziehau } 183315516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 183415516c77SSepherosa Ziehau #else 183515516c77SSepherosa Ziehau txd = buf_ring_dequeue_sc(txr->hn_txdesc_br); 183615516c77SSepherosa Ziehau #endif 183715516c77SSepherosa Ziehau 183815516c77SSepherosa Ziehau if (txd != NULL) { 183915516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 184085e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 184115516c77SSepherosa Ziehau atomic_subtract_int(&txr->hn_txdesc_avail, 1); 184215516c77SSepherosa Ziehau #endif 184385e4ae1eSSepherosa Ziehau #endif /* HN_USE_TXDESC_BUFRING */ 184415516c77SSepherosa Ziehau KASSERT(txd->m == NULL && txd->refs == 0 && 1845dc13fee6SSepherosa Ziehau STAILQ_EMPTY(&txd->agg_list) && 184615516c77SSepherosa Ziehau txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 1847dc13fee6SSepherosa Ziehau txd->chim_size == 0 && 184815516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONLIST) && 1849dc13fee6SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONAGG) == 0 && 185015516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd")); 185115516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_ONLIST; 185215516c77SSepherosa Ziehau txd->refs = 1; 185315516c77SSepherosa Ziehau } 185415516c77SSepherosa Ziehau return txd; 185515516c77SSepherosa Ziehau } 185615516c77SSepherosa Ziehau 185715516c77SSepherosa Ziehau static __inline void 185815516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd) 185915516c77SSepherosa Ziehau { 186015516c77SSepherosa Ziehau 186115516c77SSepherosa Ziehau /* 0->1 transition will never work */ 186225641fc7SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 186315516c77SSepherosa Ziehau atomic_add_int(&txd->refs, 1); 186415516c77SSepherosa Ziehau } 186515516c77SSepherosa Ziehau 1866dc13fee6SSepherosa Ziehau static __inline void 1867dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd) 1868dc13fee6SSepherosa Ziehau { 1869dc13fee6SSepherosa Ziehau 1870dc13fee6SSepherosa Ziehau KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0, 1871dc13fee6SSepherosa Ziehau ("recursive aggregation on aggregating txdesc")); 1872dc13fee6SSepherosa Ziehau 1873dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 1874dc13fee6SSepherosa Ziehau ("already aggregated")); 1875dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&txd->agg_list), 1876dc13fee6SSepherosa Ziehau ("recursive aggregation on to-be-aggregated txdesc")); 1877dc13fee6SSepherosa Ziehau 1878dc13fee6SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONAGG; 1879dc13fee6SSepherosa Ziehau STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link); 1880dc13fee6SSepherosa Ziehau } 1881dc13fee6SSepherosa Ziehau 188215516c77SSepherosa Ziehau static bool 188315516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr) 188415516c77SSepherosa Ziehau { 188515516c77SSepherosa Ziehau bool pending = false; 188615516c77SSepherosa Ziehau 188715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 188815516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 188915516c77SSepherosa Ziehau if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt) 189015516c77SSepherosa Ziehau pending = true; 189115516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 189215516c77SSepherosa Ziehau #else 189315516c77SSepherosa Ziehau if (!buf_ring_full(txr->hn_txdesc_br)) 189415516c77SSepherosa Ziehau pending = true; 189515516c77SSepherosa Ziehau #endif 189615516c77SSepherosa Ziehau return (pending); 189715516c77SSepherosa Ziehau } 189815516c77SSepherosa Ziehau 189915516c77SSepherosa Ziehau static __inline void 190015516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr) 190115516c77SSepherosa Ziehau { 190215516c77SSepherosa Ziehau txr->hn_has_txeof = 0; 190315516c77SSepherosa Ziehau txr->hn_txeof(txr); 190415516c77SSepherosa Ziehau } 190515516c77SSepherosa Ziehau 190615516c77SSepherosa Ziehau static void 190715516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc, 190815516c77SSepherosa Ziehau struct vmbus_channel *chan, const void *data __unused, int dlen __unused) 190915516c77SSepherosa Ziehau { 191015516c77SSepherosa Ziehau struct hn_txdesc *txd = sndc->hn_cbarg; 191115516c77SSepherosa Ziehau struct hn_tx_ring *txr; 191215516c77SSepherosa Ziehau 191315516c77SSepherosa Ziehau txr = txd->txr; 191415516c77SSepherosa Ziehau KASSERT(txr->hn_chan == chan, 191515516c77SSepherosa Ziehau ("channel mismatch, on chan%u, should be chan%u", 1916aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan))); 191715516c77SSepherosa Ziehau 191815516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 191915516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 192015516c77SSepherosa Ziehau 192115516c77SSepherosa Ziehau ++txr->hn_txdone_cnt; 192215516c77SSepherosa Ziehau if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) { 192315516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 192415516c77SSepherosa Ziehau if (txr->hn_oactive) 192515516c77SSepherosa Ziehau hn_txeof(txr); 192615516c77SSepherosa Ziehau } 192715516c77SSepherosa Ziehau } 192815516c77SSepherosa Ziehau 192915516c77SSepherosa Ziehau static void 193015516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr) 193115516c77SSepherosa Ziehau { 193215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 193315516c77SSepherosa Ziehau tcp_lro_flush_all(&rxr->hn_lro); 193415516c77SSepherosa Ziehau #endif 193515516c77SSepherosa Ziehau 193615516c77SSepherosa Ziehau /* 193715516c77SSepherosa Ziehau * NOTE: 193815516c77SSepherosa Ziehau * 'txr' could be NULL, if multiple channels and 193915516c77SSepherosa Ziehau * ifnet.if_start method are enabled. 194015516c77SSepherosa Ziehau */ 194115516c77SSepherosa Ziehau if (txr == NULL || !txr->hn_has_txeof) 194215516c77SSepherosa Ziehau return; 194315516c77SSepherosa Ziehau 194415516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 194515516c77SSepherosa Ziehau hn_txeof(txr); 194615516c77SSepherosa Ziehau } 194715516c77SSepherosa Ziehau 194815516c77SSepherosa Ziehau static __inline uint32_t 194915516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs) 195015516c77SSepherosa Ziehau { 195115516c77SSepherosa Ziehau 195215516c77SSepherosa Ziehau KASSERT(ofs >= sizeof(struct rndis_packet_msg), 195315516c77SSepherosa Ziehau ("invalid RNDIS packet msg offset %u", ofs)); 195415516c77SSepherosa Ziehau return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset)); 195515516c77SSepherosa Ziehau } 195615516c77SSepherosa Ziehau 195715516c77SSepherosa Ziehau static __inline void * 195815516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize, 195915516c77SSepherosa Ziehau size_t pi_dlen, uint32_t pi_type) 196015516c77SSepherosa Ziehau { 196115516c77SSepherosa Ziehau const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen); 196215516c77SSepherosa Ziehau struct rndis_pktinfo *pi; 196315516c77SSepherosa Ziehau 196415516c77SSepherosa Ziehau KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0, 196515516c77SSepherosa Ziehau ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen)); 196615516c77SSepherosa Ziehau 196715516c77SSepherosa Ziehau /* 196815516c77SSepherosa Ziehau * Per-packet-info does not move; it only grows. 196915516c77SSepherosa Ziehau * 197015516c77SSepherosa Ziehau * NOTE: 197115516c77SSepherosa Ziehau * rm_pktinfooffset in this phase counts from the beginning 197215516c77SSepherosa Ziehau * of rndis_packet_msg. 197315516c77SSepherosa Ziehau */ 197415516c77SSepherosa Ziehau KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize, 197515516c77SSepherosa Ziehau ("%u pktinfo overflows RNDIS packet msg", pi_type)); 197615516c77SSepherosa Ziehau pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset + 197715516c77SSepherosa Ziehau pkt->rm_pktinfolen); 197815516c77SSepherosa Ziehau pkt->rm_pktinfolen += pi_size; 197915516c77SSepherosa Ziehau 198015516c77SSepherosa Ziehau pi->rm_size = pi_size; 198115516c77SSepherosa Ziehau pi->rm_type = pi_type; 198215516c77SSepherosa Ziehau pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET; 198315516c77SSepherosa Ziehau 198415516c77SSepherosa Ziehau return (pi->rm_data); 198515516c77SSepherosa Ziehau } 198615516c77SSepherosa Ziehau 1987dc13fee6SSepherosa Ziehau static __inline int 1988dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr) 1989dc13fee6SSepherosa Ziehau { 1990dc13fee6SSepherosa Ziehau struct hn_txdesc *txd; 1991dc13fee6SSepherosa Ziehau struct mbuf *m; 1992dc13fee6SSepherosa Ziehau int error, pkts; 1993dc13fee6SSepherosa Ziehau 1994dc13fee6SSepherosa Ziehau txd = txr->hn_agg_txd; 1995dc13fee6SSepherosa Ziehau KASSERT(txd != NULL, ("no aggregate txdesc")); 1996dc13fee6SSepherosa Ziehau 1997dc13fee6SSepherosa Ziehau /* 1998dc13fee6SSepherosa Ziehau * Since hn_txpkt() will reset this temporary stat, save 1999dc13fee6SSepherosa Ziehau * it now, so that oerrors can be updated properly, if 2000dc13fee6SSepherosa Ziehau * hn_txpkt() ever fails. 2001dc13fee6SSepherosa Ziehau */ 2002dc13fee6SSepherosa Ziehau pkts = txr->hn_stat_pkts; 2003dc13fee6SSepherosa Ziehau 2004dc13fee6SSepherosa Ziehau /* 2005dc13fee6SSepherosa Ziehau * Since txd's mbuf will _not_ be freed upon hn_txpkt() 2006dc13fee6SSepherosa Ziehau * failure, save it for later freeing, if hn_txpkt() ever 2007dc13fee6SSepherosa Ziehau * fails. 2008dc13fee6SSepherosa Ziehau */ 2009dc13fee6SSepherosa Ziehau m = txd->m; 2010dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 2011dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 2012dc13fee6SSepherosa Ziehau /* txd is freed, but m is not. */ 2013dc13fee6SSepherosa Ziehau m_freem(m); 2014dc13fee6SSepherosa Ziehau 2015dc13fee6SSepherosa Ziehau txr->hn_flush_failed++; 2016dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts); 2017dc13fee6SSepherosa Ziehau } 2018dc13fee6SSepherosa Ziehau 2019dc13fee6SSepherosa Ziehau /* Reset all aggregation states. */ 2020dc13fee6SSepherosa Ziehau txr->hn_agg_txd = NULL; 2021dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = 0; 2022dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 2023dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = NULL; 2024dc13fee6SSepherosa Ziehau 2025dc13fee6SSepherosa Ziehau return (error); 2026dc13fee6SSepherosa Ziehau } 2027dc13fee6SSepherosa Ziehau 2028dc13fee6SSepherosa Ziehau static void * 2029dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 2030dc13fee6SSepherosa Ziehau int pktsize) 2031dc13fee6SSepherosa Ziehau { 2032dc13fee6SSepherosa Ziehau void *chim; 2033dc13fee6SSepherosa Ziehau 2034dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 2035dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) { 2036dc13fee6SSepherosa Ziehau struct hn_txdesc *agg_txd = txr->hn_agg_txd; 2037dc13fee6SSepherosa Ziehau struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt; 2038dc13fee6SSepherosa Ziehau int olen; 2039dc13fee6SSepherosa Ziehau 2040dc13fee6SSepherosa Ziehau /* 2041dc13fee6SSepherosa Ziehau * Update the previous RNDIS packet's total length, 2042dc13fee6SSepherosa Ziehau * it can be increased due to the mandatory alignment 2043dc13fee6SSepherosa Ziehau * padding for this RNDIS packet. And update the 2044dc13fee6SSepherosa Ziehau * aggregating txdesc's chimney sending buffer size 2045dc13fee6SSepherosa Ziehau * accordingly. 2046dc13fee6SSepherosa Ziehau * 2047dc13fee6SSepherosa Ziehau * XXX 2048dc13fee6SSepherosa Ziehau * Zero-out the padding, as required by the RNDIS spec. 2049dc13fee6SSepherosa Ziehau */ 2050dc13fee6SSepherosa Ziehau olen = pkt->rm_len; 2051dc13fee6SSepherosa Ziehau pkt->rm_len = roundup2(olen, txr->hn_agg_align); 2052dc13fee6SSepherosa Ziehau agg_txd->chim_size += pkt->rm_len - olen; 2053dc13fee6SSepherosa Ziehau 2054dc13fee6SSepherosa Ziehau /* Link this txdesc to the parent. */ 2055dc13fee6SSepherosa Ziehau hn_txdesc_agg(agg_txd, txd); 2056dc13fee6SSepherosa Ziehau 2057dc13fee6SSepherosa Ziehau chim = (uint8_t *)pkt + pkt->rm_len; 2058dc13fee6SSepherosa Ziehau /* Save the current packet for later fixup. */ 2059dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 2060dc13fee6SSepherosa Ziehau 2061dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft--; 2062dc13fee6SSepherosa Ziehau txr->hn_agg_szleft -= pktsize; 2063dc13fee6SSepherosa Ziehau if (txr->hn_agg_szleft <= 2064dc13fee6SSepherosa Ziehau HN_PKTSIZE_MIN(txr->hn_agg_align)) { 2065dc13fee6SSepherosa Ziehau /* 2066dc13fee6SSepherosa Ziehau * Probably can't aggregate more packets, 2067dc13fee6SSepherosa Ziehau * flush this aggregating txdesc proactively. 2068dc13fee6SSepherosa Ziehau */ 2069dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 2070dc13fee6SSepherosa Ziehau } 2071dc13fee6SSepherosa Ziehau /* Done! */ 2072dc13fee6SSepherosa Ziehau return (chim); 2073dc13fee6SSepherosa Ziehau } 2074dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 2075dc13fee6SSepherosa Ziehau } 2076dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 2077dc13fee6SSepherosa Ziehau 2078dc13fee6SSepherosa Ziehau txr->hn_tx_chimney_tried++; 2079dc13fee6SSepherosa Ziehau txd->chim_index = hn_chim_alloc(txr->hn_sc); 2080dc13fee6SSepherosa Ziehau if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID) 2081dc13fee6SSepherosa Ziehau return (NULL); 2082dc13fee6SSepherosa Ziehau txr->hn_tx_chimney++; 2083dc13fee6SSepherosa Ziehau 2084dc13fee6SSepherosa Ziehau chim = txr->hn_sc->hn_chim + 2085dc13fee6SSepherosa Ziehau (txd->chim_index * txr->hn_sc->hn_chim_szmax); 2086dc13fee6SSepherosa Ziehau 2087dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktmax > 1 && 2088dc13fee6SSepherosa Ziehau txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) { 2089dc13fee6SSepherosa Ziehau txr->hn_agg_txd = txd; 2090dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1; 2091dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize; 2092dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 2093dc13fee6SSepherosa Ziehau } 2094dc13fee6SSepherosa Ziehau return (chim); 2095dc13fee6SSepherosa Ziehau } 2096dc13fee6SSepherosa Ziehau 209715516c77SSepherosa Ziehau /* 209815516c77SSepherosa Ziehau * NOTE: 209915516c77SSepherosa Ziehau * If this function fails, then both txd and m_head0 will be freed. 210015516c77SSepherosa Ziehau */ 210115516c77SSepherosa Ziehau static int 2102dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 2103dc13fee6SSepherosa Ziehau struct mbuf **m_head0) 210415516c77SSepherosa Ziehau { 210515516c77SSepherosa Ziehau bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX]; 210615516c77SSepherosa Ziehau int error, nsegs, i; 210715516c77SSepherosa Ziehau struct mbuf *m_head = *m_head0; 210815516c77SSepherosa Ziehau struct rndis_packet_msg *pkt; 210915516c77SSepherosa Ziehau uint32_t *pi_data; 21108966e5d5SSepherosa Ziehau void *chim = NULL; 2111dc13fee6SSepherosa Ziehau int pkt_hlen, pkt_size; 211215516c77SSepherosa Ziehau 211315516c77SSepherosa Ziehau pkt = txd->rndis_pkt; 2114dc13fee6SSepherosa Ziehau pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align); 2115dc13fee6SSepherosa Ziehau if (pkt_size < txr->hn_chim_size) { 2116dc13fee6SSepherosa Ziehau chim = hn_try_txagg(ifp, txr, txd, pkt_size); 2117dc13fee6SSepherosa Ziehau if (chim != NULL) 21188966e5d5SSepherosa Ziehau pkt = chim; 2119dc13fee6SSepherosa Ziehau } else { 2120dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 2121dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 21228966e5d5SSepherosa Ziehau } 21238966e5d5SSepherosa Ziehau 212415516c77SSepherosa Ziehau pkt->rm_type = REMOTE_NDIS_PACKET_MSG; 21258fe90f73SSepherosa Ziehau pkt->rm_len = m_head->m_pkthdr.len; 21269130c4f7SSepherosa Ziehau pkt->rm_dataoffset = 0; 212715516c77SSepherosa Ziehau pkt->rm_datalen = m_head->m_pkthdr.len; 2128dc13fee6SSepherosa Ziehau pkt->rm_oobdataoffset = 0; 2129dc13fee6SSepherosa Ziehau pkt->rm_oobdatalen = 0; 2130dc13fee6SSepherosa Ziehau pkt->rm_oobdataelements = 0; 213115516c77SSepherosa Ziehau pkt->rm_pktinfooffset = sizeof(*pkt); 213215516c77SSepherosa Ziehau pkt->rm_pktinfolen = 0; 2133dc13fee6SSepherosa Ziehau pkt->rm_vchandle = 0; 2134dc13fee6SSepherosa Ziehau pkt->rm_reserved = 0; 213515516c77SSepherosa Ziehau 213615516c77SSepherosa Ziehau if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) { 213715516c77SSepherosa Ziehau /* 213815516c77SSepherosa Ziehau * Set the hash value for this packet, so that the host could 213915516c77SSepherosa Ziehau * dispatch the TX done event for this packet back to this TX 214015516c77SSepherosa Ziehau * ring's channel. 214115516c77SSepherosa Ziehau */ 214215516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 214315516c77SSepherosa Ziehau HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL); 214415516c77SSepherosa Ziehau *pi_data = txr->hn_tx_idx; 214515516c77SSepherosa Ziehau } 214615516c77SSepherosa Ziehau 214715516c77SSepherosa Ziehau if (m_head->m_flags & M_VLANTAG) { 214815516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 214915516c77SSepherosa Ziehau NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN); 215015516c77SSepherosa Ziehau *pi_data = NDIS_VLAN_INFO_MAKE( 215115516c77SSepherosa Ziehau EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag), 215215516c77SSepherosa Ziehau EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag), 215315516c77SSepherosa Ziehau EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag)); 215415516c77SSepherosa Ziehau } 215515516c77SSepherosa Ziehau 215615516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 215715516c77SSepherosa Ziehau #if defined(INET6) || defined(INET) 215815516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 215915516c77SSepherosa Ziehau NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); 216015516c77SSepherosa Ziehau #ifdef INET 216115516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 216215516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV4(0, 216315516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 216415516c77SSepherosa Ziehau } 216515516c77SSepherosa Ziehau #endif 216615516c77SSepherosa Ziehau #if defined(INET6) && defined(INET) 216715516c77SSepherosa Ziehau else 216815516c77SSepherosa Ziehau #endif 216915516c77SSepherosa Ziehau #ifdef INET6 217015516c77SSepherosa Ziehau { 217115516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV6(0, 217215516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 217315516c77SSepherosa Ziehau } 217415516c77SSepherosa Ziehau #endif 217515516c77SSepherosa Ziehau #endif /* INET6 || INET */ 217615516c77SSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) { 217715516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 217815516c77SSepherosa Ziehau NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); 217915516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & 218015516c77SSepherosa Ziehau (CSUM_IP6_TCP | CSUM_IP6_UDP)) { 218115516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV6; 218215516c77SSepherosa Ziehau } else { 218315516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV4; 218415516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 218515516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_IPCS; 218615516c77SSepherosa Ziehau } 218715516c77SSepherosa Ziehau 218815516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) 218915516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_TCPCS; 219015516c77SSepherosa Ziehau else if (m_head->m_pkthdr.csum_flags & 219115516c77SSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP6_UDP)) 219215516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_UDPCS; 219315516c77SSepherosa Ziehau } 219415516c77SSepherosa Ziehau 2195dc13fee6SSepherosa Ziehau pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; 21968fe90f73SSepherosa Ziehau /* Fixup RNDIS packet message total length */ 21978fe90f73SSepherosa Ziehau pkt->rm_len += pkt_hlen; 219815516c77SSepherosa Ziehau /* Convert RNDIS packet message offsets */ 21999130c4f7SSepherosa Ziehau pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen); 220015516c77SSepherosa Ziehau pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset); 220115516c77SSepherosa Ziehau 220215516c77SSepherosa Ziehau /* 22038966e5d5SSepherosa Ziehau * Fast path: Chimney sending. 220415516c77SSepherosa Ziehau */ 22058966e5d5SSepherosa Ziehau if (chim != NULL) { 2206dc13fee6SSepherosa Ziehau struct hn_txdesc *tgt_txd = txd; 2207dc13fee6SSepherosa Ziehau 2208dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 2209dc13fee6SSepherosa Ziehau tgt_txd = txr->hn_agg_txd; 2210dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 2211dc13fee6SSepherosa Ziehau *m_head0 = NULL; 2212dc13fee6SSepherosa Ziehau #endif 2213dc13fee6SSepherosa Ziehau } 2214dc13fee6SSepherosa Ziehau 2215dc13fee6SSepherosa Ziehau KASSERT(pkt == chim, 2216dc13fee6SSepherosa Ziehau ("RNDIS pkt not in chimney sending buffer")); 2217dc13fee6SSepherosa Ziehau KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID, 2218dc13fee6SSepherosa Ziehau ("chimney sending buffer is not used")); 2219dc13fee6SSepherosa Ziehau tgt_txd->chim_size += pkt->rm_len; 222015516c77SSepherosa Ziehau 22218966e5d5SSepherosa Ziehau m_copydata(m_head, 0, m_head->m_pkthdr.len, 2222dc13fee6SSepherosa Ziehau ((uint8_t *)chim) + pkt_hlen); 222315516c77SSepherosa Ziehau 222415516c77SSepherosa Ziehau txr->hn_gpa_cnt = 0; 222515516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_chim; 222615516c77SSepherosa Ziehau goto done; 222715516c77SSepherosa Ziehau } 2228dc13fee6SSepherosa Ziehau 2229dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc")); 22308966e5d5SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 22318966e5d5SSepherosa Ziehau ("chimney buffer is used")); 22328966e5d5SSepherosa Ziehau KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc")); 223315516c77SSepherosa Ziehau 223415516c77SSepherosa Ziehau error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs); 2235dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 223615516c77SSepherosa Ziehau int freed; 223715516c77SSepherosa Ziehau 223815516c77SSepherosa Ziehau /* 223915516c77SSepherosa Ziehau * This mbuf is not linked w/ the txd yet, so free it now. 224015516c77SSepherosa Ziehau */ 224115516c77SSepherosa Ziehau m_freem(m_head); 224215516c77SSepherosa Ziehau *m_head0 = NULL; 224315516c77SSepherosa Ziehau 224415516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 224515516c77SSepherosa Ziehau KASSERT(freed != 0, 224615516c77SSepherosa Ziehau ("fail to free txd upon txdma error")); 224715516c77SSepherosa Ziehau 224815516c77SSepherosa Ziehau txr->hn_txdma_failed++; 2249dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 225015516c77SSepherosa Ziehau return error; 225115516c77SSepherosa Ziehau } 225215516c77SSepherosa Ziehau *m_head0 = m_head; 225315516c77SSepherosa Ziehau 225415516c77SSepherosa Ziehau /* +1 RNDIS packet message */ 225515516c77SSepherosa Ziehau txr->hn_gpa_cnt = nsegs + 1; 225615516c77SSepherosa Ziehau 225715516c77SSepherosa Ziehau /* send packet with page buffer */ 225815516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr); 225915516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK; 2260dc13fee6SSepherosa Ziehau txr->hn_gpa[0].gpa_len = pkt_hlen; 226115516c77SSepherosa Ziehau 226215516c77SSepherosa Ziehau /* 226315516c77SSepherosa Ziehau * Fill the page buffers with mbuf info after the page 226415516c77SSepherosa Ziehau * buffer for RNDIS packet message. 226515516c77SSepherosa Ziehau */ 226615516c77SSepherosa Ziehau for (i = 0; i < nsegs; ++i) { 226715516c77SSepherosa Ziehau struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1]; 226815516c77SSepherosa Ziehau 226915516c77SSepherosa Ziehau gpa->gpa_page = atop(segs[i].ds_addr); 227015516c77SSepherosa Ziehau gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK; 227115516c77SSepherosa Ziehau gpa->gpa_len = segs[i].ds_len; 227215516c77SSepherosa Ziehau } 227315516c77SSepherosa Ziehau 227415516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 227515516c77SSepherosa Ziehau txd->chim_size = 0; 227615516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_sglist; 227715516c77SSepherosa Ziehau done: 227815516c77SSepherosa Ziehau txd->m = m_head; 227915516c77SSepherosa Ziehau 228015516c77SSepherosa Ziehau /* Set the completion routine */ 228115516c77SSepherosa Ziehau hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd); 228215516c77SSepherosa Ziehau 2283dc13fee6SSepherosa Ziehau /* Update temporary stats for later use. */ 2284dc13fee6SSepherosa Ziehau txr->hn_stat_pkts++; 2285dc13fee6SSepherosa Ziehau txr->hn_stat_size += m_head->m_pkthdr.len; 2286dc13fee6SSepherosa Ziehau if (m_head->m_flags & M_MCAST) 2287dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts++; 2288dc13fee6SSepherosa Ziehau 228915516c77SSepherosa Ziehau return 0; 229015516c77SSepherosa Ziehau } 229115516c77SSepherosa Ziehau 229215516c77SSepherosa Ziehau /* 229315516c77SSepherosa Ziehau * NOTE: 229415516c77SSepherosa Ziehau * If this function fails, then txd will be freed, but the mbuf 229515516c77SSepherosa Ziehau * associated w/ the txd will _not_ be freed. 229615516c77SSepherosa Ziehau */ 229715516c77SSepherosa Ziehau static int 229815516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd) 229915516c77SSepherosa Ziehau { 23008e7d3136SSepherosa Ziehau int error, send_failed = 0, has_bpf; 230115516c77SSepherosa Ziehau 230215516c77SSepherosa Ziehau again: 23038e7d3136SSepherosa Ziehau has_bpf = bpf_peers_present(ifp->if_bpf); 23048e7d3136SSepherosa Ziehau if (has_bpf) { 230515516c77SSepherosa Ziehau /* 23068e7d3136SSepherosa Ziehau * Make sure that this txd and any aggregated txds are not 23078e7d3136SSepherosa Ziehau * freed before ETHER_BPF_MTAP. 230815516c77SSepherosa Ziehau */ 230915516c77SSepherosa Ziehau hn_txdesc_hold(txd); 23108e7d3136SSepherosa Ziehau } 231115516c77SSepherosa Ziehau error = txr->hn_sendpkt(txr, txd); 231215516c77SSepherosa Ziehau if (!error) { 23138e7d3136SSepherosa Ziehau if (has_bpf) { 2314dc13fee6SSepherosa Ziehau const struct hn_txdesc *tmp_txd; 2315dc13fee6SSepherosa Ziehau 231615516c77SSepherosa Ziehau ETHER_BPF_MTAP(ifp, txd->m); 2317dc13fee6SSepherosa Ziehau STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link) 2318dc13fee6SSepherosa Ziehau ETHER_BPF_MTAP(ifp, tmp_txd->m); 2319dc13fee6SSepherosa Ziehau } 2320dc13fee6SSepherosa Ziehau 2321dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts); 232223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 232323bf9e15SSepherosa Ziehau if (!hn_use_if_start) 232423bf9e15SSepherosa Ziehau #endif 232523bf9e15SSepherosa Ziehau { 232615516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, 2327dc13fee6SSepherosa Ziehau txr->hn_stat_size); 2328dc13fee6SSepherosa Ziehau if (txr->hn_stat_mcasts != 0) { 2329dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 2330dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts); 233115516c77SSepherosa Ziehau } 2332dc13fee6SSepherosa Ziehau } 2333dc13fee6SSepherosa Ziehau txr->hn_pkts += txr->hn_stat_pkts; 2334dc13fee6SSepherosa Ziehau txr->hn_sends++; 233515516c77SSepherosa Ziehau } 23368e7d3136SSepherosa Ziehau if (has_bpf) 233715516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 233815516c77SSepherosa Ziehau 233915516c77SSepherosa Ziehau if (__predict_false(error)) { 234015516c77SSepherosa Ziehau int freed; 234115516c77SSepherosa Ziehau 234215516c77SSepherosa Ziehau /* 234315516c77SSepherosa Ziehau * This should "really rarely" happen. 234415516c77SSepherosa Ziehau * 234515516c77SSepherosa Ziehau * XXX Too many RX to be acked or too many sideband 234615516c77SSepherosa Ziehau * commands to run? Ask netvsc_channel_rollup() 234715516c77SSepherosa Ziehau * to kick start later. 234815516c77SSepherosa Ziehau */ 234915516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 235015516c77SSepherosa Ziehau if (!send_failed) { 235115516c77SSepherosa Ziehau txr->hn_send_failed++; 235215516c77SSepherosa Ziehau send_failed = 1; 235315516c77SSepherosa Ziehau /* 235415516c77SSepherosa Ziehau * Try sending again after set hn_has_txeof; 235515516c77SSepherosa Ziehau * in case that we missed the last 235615516c77SSepherosa Ziehau * netvsc_channel_rollup(). 235715516c77SSepherosa Ziehau */ 235815516c77SSepherosa Ziehau goto again; 235915516c77SSepherosa Ziehau } 236015516c77SSepherosa Ziehau if_printf(ifp, "send failed\n"); 236115516c77SSepherosa Ziehau 236215516c77SSepherosa Ziehau /* 236315516c77SSepherosa Ziehau * Caller will perform further processing on the 236415516c77SSepherosa Ziehau * associated mbuf, so don't free it in hn_txdesc_put(); 236515516c77SSepherosa Ziehau * only unload it from the DMA map in hn_txdesc_put(), 236615516c77SSepherosa Ziehau * if it was loaded. 236715516c77SSepherosa Ziehau */ 236815516c77SSepherosa Ziehau txd->m = NULL; 236915516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 237015516c77SSepherosa Ziehau KASSERT(freed != 0, 237115516c77SSepherosa Ziehau ("fail to free txd upon send error")); 237215516c77SSepherosa Ziehau 237315516c77SSepherosa Ziehau txr->hn_send_failed++; 237415516c77SSepherosa Ziehau } 2375dc13fee6SSepherosa Ziehau 2376dc13fee6SSepherosa Ziehau /* Reset temporary stats, after this sending is done. */ 2377dc13fee6SSepherosa Ziehau txr->hn_stat_size = 0; 2378dc13fee6SSepherosa Ziehau txr->hn_stat_pkts = 0; 2379dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts = 0; 2380dc13fee6SSepherosa Ziehau 2381dc13fee6SSepherosa Ziehau return (error); 238215516c77SSepherosa Ziehau } 238315516c77SSepherosa Ziehau 238415516c77SSepherosa Ziehau /* 238515516c77SSepherosa Ziehau * Append the specified data to the indicated mbuf chain, 238615516c77SSepherosa Ziehau * Extend the mbuf chain if the new data does not fit in 238715516c77SSepherosa Ziehau * existing space. 238815516c77SSepherosa Ziehau * 238915516c77SSepherosa Ziehau * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c. 239015516c77SSepherosa Ziehau * There should be an equivalent in the kernel mbuf code, 239115516c77SSepherosa Ziehau * but there does not appear to be one yet. 239215516c77SSepherosa Ziehau * 239315516c77SSepherosa Ziehau * Differs from m_append() in that additional mbufs are 239415516c77SSepherosa Ziehau * allocated with cluster size MJUMPAGESIZE, and filled 239515516c77SSepherosa Ziehau * accordingly. 239615516c77SSepherosa Ziehau * 239715516c77SSepherosa Ziehau * Return 1 if able to complete the job; otherwise 0. 239815516c77SSepherosa Ziehau */ 239915516c77SSepherosa Ziehau static int 240015516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp) 240115516c77SSepherosa Ziehau { 240215516c77SSepherosa Ziehau struct mbuf *m, *n; 240315516c77SSepherosa Ziehau int remainder, space; 240415516c77SSepherosa Ziehau 240515516c77SSepherosa Ziehau for (m = m0; m->m_next != NULL; m = m->m_next) 240615516c77SSepherosa Ziehau ; 240715516c77SSepherosa Ziehau remainder = len; 240815516c77SSepherosa Ziehau space = M_TRAILINGSPACE(m); 240915516c77SSepherosa Ziehau if (space > 0) { 241015516c77SSepherosa Ziehau /* 241115516c77SSepherosa Ziehau * Copy into available space. 241215516c77SSepherosa Ziehau */ 241315516c77SSepherosa Ziehau if (space > remainder) 241415516c77SSepherosa Ziehau space = remainder; 241515516c77SSepherosa Ziehau bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 241615516c77SSepherosa Ziehau m->m_len += space; 241715516c77SSepherosa Ziehau cp += space; 241815516c77SSepherosa Ziehau remainder -= space; 241915516c77SSepherosa Ziehau } 242015516c77SSepherosa Ziehau while (remainder > 0) { 242115516c77SSepherosa Ziehau /* 242215516c77SSepherosa Ziehau * Allocate a new mbuf; could check space 242315516c77SSepherosa Ziehau * and allocate a cluster instead. 242415516c77SSepherosa Ziehau */ 242515516c77SSepherosa Ziehau n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE); 242615516c77SSepherosa Ziehau if (n == NULL) 242715516c77SSepherosa Ziehau break; 242815516c77SSepherosa Ziehau n->m_len = min(MJUMPAGESIZE, remainder); 242915516c77SSepherosa Ziehau bcopy(cp, mtod(n, caddr_t), n->m_len); 243015516c77SSepherosa Ziehau cp += n->m_len; 243115516c77SSepherosa Ziehau remainder -= n->m_len; 243215516c77SSepherosa Ziehau m->m_next = n; 243315516c77SSepherosa Ziehau m = n; 243415516c77SSepherosa Ziehau } 243515516c77SSepherosa Ziehau if (m0->m_flags & M_PKTHDR) 243615516c77SSepherosa Ziehau m0->m_pkthdr.len += len - remainder; 243715516c77SSepherosa Ziehau 243815516c77SSepherosa Ziehau return (remainder == 0); 243915516c77SSepherosa Ziehau } 244015516c77SSepherosa Ziehau 244115516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 244215516c77SSepherosa Ziehau static __inline int 244315516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m) 244415516c77SSepherosa Ziehau { 244515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 244615516c77SSepherosa Ziehau if (hn_lro_mbufq_depth) { 244715516c77SSepherosa Ziehau tcp_lro_queue_mbuf(lc, m); 244815516c77SSepherosa Ziehau return 0; 244915516c77SSepherosa Ziehau } 245015516c77SSepherosa Ziehau #endif 245115516c77SSepherosa Ziehau return tcp_lro_rx(lc, m, 0); 245215516c77SSepherosa Ziehau } 245315516c77SSepherosa Ziehau #endif 245415516c77SSepherosa Ziehau 245515516c77SSepherosa Ziehau static int 245615516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, 245715516c77SSepherosa Ziehau const struct hn_rxinfo *info) 245815516c77SSepherosa Ziehau { 24595bdfd3fdSDexuan Cui struct ifnet *ifp; 246015516c77SSepherosa Ziehau struct mbuf *m_new; 246115516c77SSepherosa Ziehau int size, do_lro = 0, do_csum = 1; 246215516c77SSepherosa Ziehau int hash_type; 246315516c77SSepherosa Ziehau 24645bdfd3fdSDexuan Cui /* If the VF is active, inject the packet through the VF */ 2465499c3e17SSepherosa Ziehau ifp = rxr->hn_rxvf_ifp ? rxr->hn_rxvf_ifp : rxr->hn_ifp; 24665bdfd3fdSDexuan Cui 2467b3b75d9cSSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 2468b3b75d9cSSepherosa Ziehau /* 2469b3b75d9cSSepherosa Ziehau * NOTE: 2470b3b75d9cSSepherosa Ziehau * See the NOTE of hn_rndis_init_fixat(). This 2471b3b75d9cSSepherosa Ziehau * function can be reached, immediately after the 2472b3b75d9cSSepherosa Ziehau * RNDIS is initialized but before the ifnet is 2473b3b75d9cSSepherosa Ziehau * setup on the hn_attach() path; drop the unexpected 2474b3b75d9cSSepherosa Ziehau * packets. 2475b3b75d9cSSepherosa Ziehau */ 2476b3b75d9cSSepherosa Ziehau return (0); 2477b3b75d9cSSepherosa Ziehau } 2478b3b75d9cSSepherosa Ziehau 2479c927d681SDexuan Cui if (dlen <= MHLEN) { 248015516c77SSepherosa Ziehau m_new = m_gethdr(M_NOWAIT, MT_DATA); 248115516c77SSepherosa Ziehau if (m_new == NULL) { 248215516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 248315516c77SSepherosa Ziehau return (0); 248415516c77SSepherosa Ziehau } 248515516c77SSepherosa Ziehau memcpy(mtod(m_new, void *), data, dlen); 248615516c77SSepherosa Ziehau m_new->m_pkthdr.len = m_new->m_len = dlen; 248715516c77SSepherosa Ziehau rxr->hn_small_pkts++; 248815516c77SSepherosa Ziehau } else { 248915516c77SSepherosa Ziehau /* 249015516c77SSepherosa Ziehau * Get an mbuf with a cluster. For packets 2K or less, 249115516c77SSepherosa Ziehau * get a standard 2K cluster. For anything larger, get a 249215516c77SSepherosa Ziehau * 4K cluster. Any buffers larger than 4K can cause problems 249315516c77SSepherosa Ziehau * if looped around to the Hyper-V TX channel, so avoid them. 249415516c77SSepherosa Ziehau */ 249515516c77SSepherosa Ziehau size = MCLBYTES; 249615516c77SSepherosa Ziehau if (dlen > MCLBYTES) { 249715516c77SSepherosa Ziehau /* 4096 */ 249815516c77SSepherosa Ziehau size = MJUMPAGESIZE; 249915516c77SSepherosa Ziehau } 250015516c77SSepherosa Ziehau 250115516c77SSepherosa Ziehau m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size); 250215516c77SSepherosa Ziehau if (m_new == NULL) { 250315516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 250415516c77SSepherosa Ziehau return (0); 250515516c77SSepherosa Ziehau } 250615516c77SSepherosa Ziehau 250715516c77SSepherosa Ziehau hv_m_append(m_new, dlen, data); 250815516c77SSepherosa Ziehau } 250915516c77SSepherosa Ziehau m_new->m_pkthdr.rcvif = ifp; 251015516c77SSepherosa Ziehau 251115516c77SSepherosa Ziehau if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0)) 251215516c77SSepherosa Ziehau do_csum = 0; 251315516c77SSepherosa Ziehau 251415516c77SSepherosa Ziehau /* receive side checksum offload */ 251515516c77SSepherosa Ziehau if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) { 251615516c77SSepherosa Ziehau /* IP csum offload */ 251715516c77SSepherosa Ziehau if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) { 251815516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 251915516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 252015516c77SSepherosa Ziehau rxr->hn_csum_ip++; 252115516c77SSepherosa Ziehau } 252215516c77SSepherosa Ziehau 252315516c77SSepherosa Ziehau /* TCP/UDP csum offload */ 252415516c77SSepherosa Ziehau if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK | 252515516c77SSepherosa Ziehau NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) { 252615516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 252715516c77SSepherosa Ziehau (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 252815516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 252915516c77SSepherosa Ziehau if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK) 253015516c77SSepherosa Ziehau rxr->hn_csum_tcp++; 253115516c77SSepherosa Ziehau else 253215516c77SSepherosa Ziehau rxr->hn_csum_udp++; 253315516c77SSepherosa Ziehau } 253415516c77SSepherosa Ziehau 253515516c77SSepherosa Ziehau /* 253615516c77SSepherosa Ziehau * XXX 253715516c77SSepherosa Ziehau * As of this write (Oct 28th, 2016), host side will turn 253815516c77SSepherosa Ziehau * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so 253915516c77SSepherosa Ziehau * the do_lro setting here is actually _not_ accurate. We 254015516c77SSepherosa Ziehau * depend on the RSS hash type check to reset do_lro. 254115516c77SSepherosa Ziehau */ 254215516c77SSepherosa Ziehau if ((info->csum_info & 254315516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) == 254415516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) 254515516c77SSepherosa Ziehau do_lro = 1; 254615516c77SSepherosa Ziehau } else { 254715516c77SSepherosa Ziehau const struct ether_header *eh; 254815516c77SSepherosa Ziehau uint16_t etype; 254915516c77SSepherosa Ziehau int hoff; 255015516c77SSepherosa Ziehau 255115516c77SSepherosa Ziehau hoff = sizeof(*eh); 255215516c77SSepherosa Ziehau if (m_new->m_len < hoff) 255315516c77SSepherosa Ziehau goto skip; 255415516c77SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 255515516c77SSepherosa Ziehau etype = ntohs(eh->ether_type); 255615516c77SSepherosa Ziehau if (etype == ETHERTYPE_VLAN) { 255715516c77SSepherosa Ziehau const struct ether_vlan_header *evl; 255815516c77SSepherosa Ziehau 255915516c77SSepherosa Ziehau hoff = sizeof(*evl); 256015516c77SSepherosa Ziehau if (m_new->m_len < hoff) 256115516c77SSepherosa Ziehau goto skip; 256215516c77SSepherosa Ziehau evl = mtod(m_new, struct ether_vlan_header *); 256315516c77SSepherosa Ziehau etype = ntohs(evl->evl_proto); 256415516c77SSepherosa Ziehau } 256515516c77SSepherosa Ziehau 256615516c77SSepherosa Ziehau if (etype == ETHERTYPE_IP) { 256715516c77SSepherosa Ziehau int pr; 256815516c77SSepherosa Ziehau 256915516c77SSepherosa Ziehau pr = hn_check_iplen(m_new, hoff); 257015516c77SSepherosa Ziehau if (pr == IPPROTO_TCP) { 257115516c77SSepherosa Ziehau if (do_csum && 257215516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 257315516c77SSepherosa Ziehau HN_TRUST_HCSUM_TCP)) { 257415516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 257515516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 257615516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 257715516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 257815516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 257915516c77SSepherosa Ziehau } 258015516c77SSepherosa Ziehau do_lro = 1; 258115516c77SSepherosa Ziehau } else if (pr == IPPROTO_UDP) { 258215516c77SSepherosa Ziehau if (do_csum && 258315516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 258415516c77SSepherosa Ziehau HN_TRUST_HCSUM_UDP)) { 258515516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 258615516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 258715516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 258815516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 258915516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 259015516c77SSepherosa Ziehau } 259115516c77SSepherosa Ziehau } else if (pr != IPPROTO_DONE && do_csum && 259215516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) { 259315516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 259415516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 259515516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 259615516c77SSepherosa Ziehau } 259715516c77SSepherosa Ziehau } 259815516c77SSepherosa Ziehau } 259915516c77SSepherosa Ziehau skip: 260015516c77SSepherosa Ziehau if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) { 260115516c77SSepherosa Ziehau m_new->m_pkthdr.ether_vtag = EVL_MAKETAG( 260215516c77SSepherosa Ziehau NDIS_VLAN_INFO_ID(info->vlan_info), 260315516c77SSepherosa Ziehau NDIS_VLAN_INFO_PRI(info->vlan_info), 260415516c77SSepherosa Ziehau NDIS_VLAN_INFO_CFI(info->vlan_info)); 260515516c77SSepherosa Ziehau m_new->m_flags |= M_VLANTAG; 260615516c77SSepherosa Ziehau } 260715516c77SSepherosa Ziehau 260815516c77SSepherosa Ziehau if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) { 260915516c77SSepherosa Ziehau rxr->hn_rss_pkts++; 261015516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = info->hash_value; 261115516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE_HASH; 261215516c77SSepherosa Ziehau if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) == 261315516c77SSepherosa Ziehau NDIS_HASH_FUNCTION_TOEPLITZ) { 261415516c77SSepherosa Ziehau uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK); 261515516c77SSepherosa Ziehau 261615516c77SSepherosa Ziehau /* 261715516c77SSepherosa Ziehau * NOTE: 261815516c77SSepherosa Ziehau * do_lro is resetted, if the hash types are not TCP 261915516c77SSepherosa Ziehau * related. See the comment in the above csum_flags 262015516c77SSepherosa Ziehau * setup section. 262115516c77SSepherosa Ziehau */ 262215516c77SSepherosa Ziehau switch (type) { 262315516c77SSepherosa Ziehau case NDIS_HASH_IPV4: 262415516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV4; 262515516c77SSepherosa Ziehau do_lro = 0; 262615516c77SSepherosa Ziehau break; 262715516c77SSepherosa Ziehau 262815516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV4: 262915516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV4; 263015516c77SSepherosa Ziehau break; 263115516c77SSepherosa Ziehau 263215516c77SSepherosa Ziehau case NDIS_HASH_IPV6: 263315516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6; 263415516c77SSepherosa Ziehau do_lro = 0; 263515516c77SSepherosa Ziehau break; 263615516c77SSepherosa Ziehau 263715516c77SSepherosa Ziehau case NDIS_HASH_IPV6_EX: 263815516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6_EX; 263915516c77SSepherosa Ziehau do_lro = 0; 264015516c77SSepherosa Ziehau break; 264115516c77SSepherosa Ziehau 264215516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6: 264315516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6; 264415516c77SSepherosa Ziehau break; 264515516c77SSepherosa Ziehau 264615516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6_EX: 264715516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX; 264815516c77SSepherosa Ziehau break; 264915516c77SSepherosa Ziehau } 265015516c77SSepherosa Ziehau } 265115516c77SSepherosa Ziehau } else { 265215516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = rxr->hn_rx_idx; 265315516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE; 265415516c77SSepherosa Ziehau } 265515516c77SSepherosa Ziehau M_HASHTYPE_SET(m_new, hash_type); 265615516c77SSepherosa Ziehau 265715516c77SSepherosa Ziehau /* 265815516c77SSepherosa Ziehau * Note: Moved RX completion back to hv_nv_on_receive() so all 265915516c77SSepherosa Ziehau * messages (not just data messages) will trigger a response. 266015516c77SSepherosa Ziehau */ 266115516c77SSepherosa Ziehau 266215516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 266315516c77SSepherosa Ziehau rxr->hn_pkts++; 266415516c77SSepherosa Ziehau 266515516c77SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_LRO) && do_lro) { 266615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 266715516c77SSepherosa Ziehau struct lro_ctrl *lro = &rxr->hn_lro; 266815516c77SSepherosa Ziehau 266915516c77SSepherosa Ziehau if (lro->lro_cnt) { 267015516c77SSepherosa Ziehau rxr->hn_lro_tried++; 267115516c77SSepherosa Ziehau if (hn_lro_rx(lro, m_new) == 0) { 267215516c77SSepherosa Ziehau /* DONE! */ 267315516c77SSepherosa Ziehau return 0; 267415516c77SSepherosa Ziehau } 267515516c77SSepherosa Ziehau } 267615516c77SSepherosa Ziehau #endif 267715516c77SSepherosa Ziehau } 267815516c77SSepherosa Ziehau 267915516c77SSepherosa Ziehau /* We're not holding the lock here, so don't release it */ 268015516c77SSepherosa Ziehau (*ifp->if_input)(ifp, m_new); 268115516c77SSepherosa Ziehau 268215516c77SSepherosa Ziehau return (0); 268315516c77SSepherosa Ziehau } 268415516c77SSepherosa Ziehau 268515516c77SSepherosa Ziehau static int 268615516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 268715516c77SSepherosa Ziehau { 268815516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 268915516c77SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data; 269015516c77SSepherosa Ziehau int mask, error = 0; 269115516c77SSepherosa Ziehau 269215516c77SSepherosa Ziehau switch (cmd) { 269315516c77SSepherosa Ziehau case SIOCSIFMTU: 269415516c77SSepherosa Ziehau if (ifr->ifr_mtu > HN_MTU_MAX) { 269515516c77SSepherosa Ziehau error = EINVAL; 269615516c77SSepherosa Ziehau break; 269715516c77SSepherosa Ziehau } 269815516c77SSepherosa Ziehau 269915516c77SSepherosa Ziehau HN_LOCK(sc); 270015516c77SSepherosa Ziehau 270115516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 270215516c77SSepherosa Ziehau HN_UNLOCK(sc); 270315516c77SSepherosa Ziehau break; 270415516c77SSepherosa Ziehau } 270515516c77SSepherosa Ziehau 270615516c77SSepherosa Ziehau if ((sc->hn_caps & HN_CAP_MTU) == 0) { 270715516c77SSepherosa Ziehau /* Can't change MTU */ 270815516c77SSepherosa Ziehau HN_UNLOCK(sc); 270915516c77SSepherosa Ziehau error = EOPNOTSUPP; 271015516c77SSepherosa Ziehau break; 271115516c77SSepherosa Ziehau } 271215516c77SSepherosa Ziehau 271315516c77SSepherosa Ziehau if (ifp->if_mtu == ifr->ifr_mtu) { 271415516c77SSepherosa Ziehau HN_UNLOCK(sc); 271515516c77SSepherosa Ziehau break; 271615516c77SSepherosa Ziehau } 271715516c77SSepherosa Ziehau 271815516c77SSepherosa Ziehau /* 271915516c77SSepherosa Ziehau * Suspend this interface before the synthetic parts 272015516c77SSepherosa Ziehau * are ripped. 272115516c77SSepherosa Ziehau */ 272215516c77SSepherosa Ziehau hn_suspend(sc); 272315516c77SSepherosa Ziehau 272415516c77SSepherosa Ziehau /* 272515516c77SSepherosa Ziehau * Detach the synthetics parts, i.e. NVS and RNDIS. 272615516c77SSepherosa Ziehau */ 272715516c77SSepherosa Ziehau hn_synth_detach(sc); 272815516c77SSepherosa Ziehau 272915516c77SSepherosa Ziehau /* 273015516c77SSepherosa Ziehau * Reattach the synthetic parts, i.e. NVS and RNDIS, 273115516c77SSepherosa Ziehau * with the new MTU setting. 273215516c77SSepherosa Ziehau */ 273315516c77SSepherosa Ziehau error = hn_synth_attach(sc, ifr->ifr_mtu); 273415516c77SSepherosa Ziehau if (error) { 273515516c77SSepherosa Ziehau HN_UNLOCK(sc); 273615516c77SSepherosa Ziehau break; 273715516c77SSepherosa Ziehau } 273815516c77SSepherosa Ziehau 273915516c77SSepherosa Ziehau /* 274015516c77SSepherosa Ziehau * Commit the requested MTU, after the synthetic parts 274115516c77SSepherosa Ziehau * have been successfully attached. 274215516c77SSepherosa Ziehau */ 274315516c77SSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 274415516c77SSepherosa Ziehau 274515516c77SSepherosa Ziehau /* 274615516c77SSepherosa Ziehau * Make sure that various parameters based on MTU are 274715516c77SSepherosa Ziehau * still valid, after the MTU change. 274815516c77SSepherosa Ziehau */ 274915516c77SSepherosa Ziehau if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax) 275015516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 275115516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu); 275215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 275315516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < 275415516c77SSepherosa Ziehau HN_LRO_LENLIM_MIN(ifp)) 275515516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp)); 275615516c77SSepherosa Ziehau #endif 275715516c77SSepherosa Ziehau 275815516c77SSepherosa Ziehau /* 275915516c77SSepherosa Ziehau * All done! Resume the interface now. 276015516c77SSepherosa Ziehau */ 276115516c77SSepherosa Ziehau hn_resume(sc); 276215516c77SSepherosa Ziehau 276315516c77SSepherosa Ziehau HN_UNLOCK(sc); 276415516c77SSepherosa Ziehau break; 276515516c77SSepherosa Ziehau 276615516c77SSepherosa Ziehau case SIOCSIFFLAGS: 276715516c77SSepherosa Ziehau HN_LOCK(sc); 276815516c77SSepherosa Ziehau 276915516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 277015516c77SSepherosa Ziehau HN_UNLOCK(sc); 277115516c77SSepherosa Ziehau break; 277215516c77SSepherosa Ziehau } 277315516c77SSepherosa Ziehau 277415516c77SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 2775fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2776fdc4f478SSepherosa Ziehau /* 2777fdc4f478SSepherosa Ziehau * Caller meight hold mutex, e.g. 2778fdc4f478SSepherosa Ziehau * bpf; use busy-wait for the RNDIS 2779fdc4f478SSepherosa Ziehau * reply. 2780fdc4f478SSepherosa Ziehau */ 2781fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 2782c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 2783fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 2784fdc4f478SSepherosa Ziehau } else { 278515516c77SSepherosa Ziehau hn_init_locked(sc); 2786fdc4f478SSepherosa Ziehau } 278715516c77SSepherosa Ziehau } else { 278815516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 27895bdfd3fdSDexuan Cui hn_stop(sc, false); 279015516c77SSepherosa Ziehau } 279115516c77SSepherosa Ziehau sc->hn_if_flags = ifp->if_flags; 279215516c77SSepherosa Ziehau 279315516c77SSepherosa Ziehau HN_UNLOCK(sc); 279415516c77SSepherosa Ziehau break; 279515516c77SSepherosa Ziehau 279615516c77SSepherosa Ziehau case SIOCSIFCAP: 279715516c77SSepherosa Ziehau HN_LOCK(sc); 279815516c77SSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable; 279915516c77SSepherosa Ziehau 280015516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM) { 280115516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 280215516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 280315516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc); 280415516c77SSepherosa Ziehau else 280515516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc); 280615516c77SSepherosa Ziehau } 280715516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM_IPV6) { 280815516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 280915516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 281015516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc); 281115516c77SSepherosa Ziehau else 281215516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc); 281315516c77SSepherosa Ziehau } 281415516c77SSepherosa Ziehau 281515516c77SSepherosa Ziehau /* TODO: flip RNDIS offload parameters for RXCSUM. */ 281615516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 281715516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 281815516c77SSepherosa Ziehau #ifdef foo 281915516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 282015516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM_IPV6) 282115516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 282215516c77SSepherosa Ziehau #endif 282315516c77SSepherosa Ziehau 282415516c77SSepherosa Ziehau if (mask & IFCAP_LRO) 282515516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_LRO; 282615516c77SSepherosa Ziehau 282715516c77SSepherosa Ziehau if (mask & IFCAP_TSO4) { 282815516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO4; 282915516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 283015516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 283115516c77SSepherosa Ziehau else 283215516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP_TSO; 283315516c77SSepherosa Ziehau } 283415516c77SSepherosa Ziehau if (mask & IFCAP_TSO6) { 283515516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO6; 283615516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 283715516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 283815516c77SSepherosa Ziehau else 283915516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP6_TSO; 284015516c77SSepherosa Ziehau } 284115516c77SSepherosa Ziehau 284215516c77SSepherosa Ziehau HN_UNLOCK(sc); 284315516c77SSepherosa Ziehau break; 284415516c77SSepherosa Ziehau 284515516c77SSepherosa Ziehau case SIOCADDMULTI: 284615516c77SSepherosa Ziehau case SIOCDELMULTI: 284715516c77SSepherosa Ziehau HN_LOCK(sc); 284815516c77SSepherosa Ziehau 284915516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 285015516c77SSepherosa Ziehau HN_UNLOCK(sc); 285115516c77SSepherosa Ziehau break; 285215516c77SSepherosa Ziehau } 2853fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2854fdc4f478SSepherosa Ziehau /* 2855fdc4f478SSepherosa Ziehau * Multicast uses mutex; use busy-wait for 2856fdc4f478SSepherosa Ziehau * the RNDIS reply. 2857fdc4f478SSepherosa Ziehau */ 2858fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 2859c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 2860fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 2861fdc4f478SSepherosa Ziehau } 286215516c77SSepherosa Ziehau 286315516c77SSepherosa Ziehau HN_UNLOCK(sc); 286415516c77SSepherosa Ziehau break; 286515516c77SSepherosa Ziehau 286615516c77SSepherosa Ziehau case SIOCSIFMEDIA: 286715516c77SSepherosa Ziehau case SIOCGIFMEDIA: 286815516c77SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd); 286915516c77SSepherosa Ziehau break; 287015516c77SSepherosa Ziehau 287115516c77SSepherosa Ziehau default: 287215516c77SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 287315516c77SSepherosa Ziehau break; 287415516c77SSepherosa Ziehau } 287515516c77SSepherosa Ziehau return (error); 287615516c77SSepherosa Ziehau } 287715516c77SSepherosa Ziehau 287815516c77SSepherosa Ziehau static void 28795bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching) 288015516c77SSepherosa Ziehau { 288115516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 288215516c77SSepherosa Ziehau int i; 288315516c77SSepherosa Ziehau 288415516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 288515516c77SSepherosa Ziehau 288615516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 288715516c77SSepherosa Ziehau ("synthetic parts were not attached")); 288815516c77SSepherosa Ziehau 28896c1204dfSSepherosa Ziehau /* Disable polling. */ 28906c1204dfSSepherosa Ziehau hn_polling(sc, 0); 28916c1204dfSSepherosa Ziehau 289215516c77SSepherosa Ziehau /* Clear RUNNING bit _before_ hn_suspend_data() */ 289315516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 289415516c77SSepherosa Ziehau hn_suspend_data(sc); 289515516c77SSepherosa Ziehau 289615516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 289715516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 289815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 289915516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 29005bdfd3fdSDexuan Cui 29015bdfd3fdSDexuan Cui /* 29025bdfd3fdSDexuan Cui * If the VF is active, make sure the filter is not 0, even if 29035bdfd3fdSDexuan Cui * the synthetic NIC is down. 29045bdfd3fdSDexuan Cui */ 29055bdfd3fdSDexuan Cui if (!detaching && (sc->hn_flags & HN_FLAG_VF)) 29065bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 290715516c77SSepherosa Ziehau } 290815516c77SSepherosa Ziehau 290915516c77SSepherosa Ziehau static void 291015516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc) 291115516c77SSepherosa Ziehau { 291215516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 291315516c77SSepherosa Ziehau int i; 291415516c77SSepherosa Ziehau 291515516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 291615516c77SSepherosa Ziehau 291715516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 291815516c77SSepherosa Ziehau return; 291915516c77SSepherosa Ziehau 292015516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 292115516c77SSepherosa Ziehau return; 292215516c77SSepherosa Ziehau 292315516c77SSepherosa Ziehau /* Configure RX filter */ 2924c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 292515516c77SSepherosa Ziehau 292615516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 292715516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 292815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 292915516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 293015516c77SSepherosa Ziehau 293115516c77SSepherosa Ziehau /* Clear TX 'suspended' bit. */ 293215516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_inuse); 293315516c77SSepherosa Ziehau 293415516c77SSepherosa Ziehau /* Everything is ready; unleash! */ 293515516c77SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 29366c1204dfSSepherosa Ziehau 29376c1204dfSSepherosa Ziehau /* Re-enable polling if requested. */ 29386c1204dfSSepherosa Ziehau if (sc->hn_pollhz > 0) 29396c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 294015516c77SSepherosa Ziehau } 294115516c77SSepherosa Ziehau 294215516c77SSepherosa Ziehau static void 294315516c77SSepherosa Ziehau hn_init(void *xsc) 294415516c77SSepherosa Ziehau { 294515516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 294615516c77SSepherosa Ziehau 294715516c77SSepherosa Ziehau HN_LOCK(sc); 294815516c77SSepherosa Ziehau hn_init_locked(sc); 294915516c77SSepherosa Ziehau HN_UNLOCK(sc); 295015516c77SSepherosa Ziehau } 295115516c77SSepherosa Ziehau 295215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 295315516c77SSepherosa Ziehau 295415516c77SSepherosa Ziehau static int 295515516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS) 295615516c77SSepherosa Ziehau { 295715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 295815516c77SSepherosa Ziehau unsigned int lenlim; 295915516c77SSepherosa Ziehau int error; 296015516c77SSepherosa Ziehau 296115516c77SSepherosa Ziehau lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim; 296215516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &lenlim, 0, req); 296315516c77SSepherosa Ziehau if (error || req->newptr == NULL) 296415516c77SSepherosa Ziehau return error; 296515516c77SSepherosa Ziehau 296615516c77SSepherosa Ziehau HN_LOCK(sc); 296715516c77SSepherosa Ziehau if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) || 296815516c77SSepherosa Ziehau lenlim > TCP_LRO_LENGTH_MAX) { 296915516c77SSepherosa Ziehau HN_UNLOCK(sc); 297015516c77SSepherosa Ziehau return EINVAL; 297115516c77SSepherosa Ziehau } 297215516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, lenlim); 297315516c77SSepherosa Ziehau HN_UNLOCK(sc); 297415516c77SSepherosa Ziehau 297515516c77SSepherosa Ziehau return 0; 297615516c77SSepherosa Ziehau } 297715516c77SSepherosa Ziehau 297815516c77SSepherosa Ziehau static int 297915516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS) 298015516c77SSepherosa Ziehau { 298115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 298215516c77SSepherosa Ziehau int ackcnt, error, i; 298315516c77SSepherosa Ziehau 298415516c77SSepherosa Ziehau /* 298515516c77SSepherosa Ziehau * lro_ackcnt_lim is append count limit, 298615516c77SSepherosa Ziehau * +1 to turn it into aggregation limit. 298715516c77SSepherosa Ziehau */ 298815516c77SSepherosa Ziehau ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1; 298915516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &ackcnt, 0, req); 299015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 299115516c77SSepherosa Ziehau return error; 299215516c77SSepherosa Ziehau 299315516c77SSepherosa Ziehau if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1)) 299415516c77SSepherosa Ziehau return EINVAL; 299515516c77SSepherosa Ziehau 299615516c77SSepherosa Ziehau /* 299715516c77SSepherosa Ziehau * Convert aggregation limit back to append 299815516c77SSepherosa Ziehau * count limit. 299915516c77SSepherosa Ziehau */ 300015516c77SSepherosa Ziehau --ackcnt; 300115516c77SSepherosa Ziehau HN_LOCK(sc); 3002a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 300315516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt; 300415516c77SSepherosa Ziehau HN_UNLOCK(sc); 300515516c77SSepherosa Ziehau return 0; 300615516c77SSepherosa Ziehau } 300715516c77SSepherosa Ziehau 300815516c77SSepherosa Ziehau #endif 300915516c77SSepherosa Ziehau 301015516c77SSepherosa Ziehau static int 301115516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS) 301215516c77SSepherosa Ziehau { 301315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 301415516c77SSepherosa Ziehau int hcsum = arg2; 301515516c77SSepherosa Ziehau int on, error, i; 301615516c77SSepherosa Ziehau 301715516c77SSepherosa Ziehau on = 0; 301815516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum) 301915516c77SSepherosa Ziehau on = 1; 302015516c77SSepherosa Ziehau 302115516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &on, 0, req); 302215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 302315516c77SSepherosa Ziehau return error; 302415516c77SSepherosa Ziehau 302515516c77SSepherosa Ziehau HN_LOCK(sc); 3026a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 302715516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 302815516c77SSepherosa Ziehau 302915516c77SSepherosa Ziehau if (on) 303015516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= hcsum; 303115516c77SSepherosa Ziehau else 303215516c77SSepherosa Ziehau rxr->hn_trust_hcsum &= ~hcsum; 303315516c77SSepherosa Ziehau } 303415516c77SSepherosa Ziehau HN_UNLOCK(sc); 303515516c77SSepherosa Ziehau return 0; 303615516c77SSepherosa Ziehau } 303715516c77SSepherosa Ziehau 303815516c77SSepherosa Ziehau static int 303915516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS) 304015516c77SSepherosa Ziehau { 304115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 304215516c77SSepherosa Ziehau int chim_size, error; 304315516c77SSepherosa Ziehau 304415516c77SSepherosa Ziehau chim_size = sc->hn_tx_ring[0].hn_chim_size; 304515516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &chim_size, 0, req); 304615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 304715516c77SSepherosa Ziehau return error; 304815516c77SSepherosa Ziehau 304915516c77SSepherosa Ziehau if (chim_size > sc->hn_chim_szmax || chim_size <= 0) 305015516c77SSepherosa Ziehau return EINVAL; 305115516c77SSepherosa Ziehau 305215516c77SSepherosa Ziehau HN_LOCK(sc); 305315516c77SSepherosa Ziehau hn_set_chim_size(sc, chim_size); 305415516c77SSepherosa Ziehau HN_UNLOCK(sc); 305515516c77SSepherosa Ziehau return 0; 305615516c77SSepherosa Ziehau } 305715516c77SSepherosa Ziehau 305815516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 305915516c77SSepherosa Ziehau static int 306015516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS) 306115516c77SSepherosa Ziehau { 306215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 306315516c77SSepherosa Ziehau int ofs = arg2, i, error; 306415516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 306515516c77SSepherosa Ziehau uint64_t stat; 306615516c77SSepherosa Ziehau 306715516c77SSepherosa Ziehau stat = 0; 306815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 306915516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 307015516c77SSepherosa Ziehau stat += *((int *)((uint8_t *)rxr + ofs)); 307115516c77SSepherosa Ziehau } 307215516c77SSepherosa Ziehau 307315516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 307415516c77SSepherosa Ziehau if (error || req->newptr == NULL) 307515516c77SSepherosa Ziehau return error; 307615516c77SSepherosa Ziehau 307715516c77SSepherosa Ziehau /* Zero out this stat. */ 307815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 307915516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 308015516c77SSepherosa Ziehau *((int *)((uint8_t *)rxr + ofs)) = 0; 308115516c77SSepherosa Ziehau } 308215516c77SSepherosa Ziehau return 0; 308315516c77SSepherosa Ziehau } 308415516c77SSepherosa Ziehau #else 308515516c77SSepherosa Ziehau static int 308615516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS) 308715516c77SSepherosa Ziehau { 308815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 308915516c77SSepherosa Ziehau int ofs = arg2, i, error; 309015516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 309115516c77SSepherosa Ziehau uint64_t stat; 309215516c77SSepherosa Ziehau 309315516c77SSepherosa Ziehau stat = 0; 3094a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 309515516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 309615516c77SSepherosa Ziehau stat += *((uint64_t *)((uint8_t *)rxr + ofs)); 309715516c77SSepherosa Ziehau } 309815516c77SSepherosa Ziehau 309915516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 310015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 310115516c77SSepherosa Ziehau return error; 310215516c77SSepherosa Ziehau 310315516c77SSepherosa Ziehau /* Zero out this stat. */ 3104a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 310515516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 310615516c77SSepherosa Ziehau *((uint64_t *)((uint8_t *)rxr + ofs)) = 0; 310715516c77SSepherosa Ziehau } 310815516c77SSepherosa Ziehau return 0; 310915516c77SSepherosa Ziehau } 311015516c77SSepherosa Ziehau 311115516c77SSepherosa Ziehau #endif 311215516c77SSepherosa Ziehau 311315516c77SSepherosa Ziehau static int 311415516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 311515516c77SSepherosa Ziehau { 311615516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 311715516c77SSepherosa Ziehau int ofs = arg2, i, error; 311815516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 311915516c77SSepherosa Ziehau u_long stat; 312015516c77SSepherosa Ziehau 312115516c77SSepherosa Ziehau stat = 0; 3122a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 312315516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 312415516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)rxr + ofs)); 312515516c77SSepherosa Ziehau } 312615516c77SSepherosa Ziehau 312715516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 312815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 312915516c77SSepherosa Ziehau return error; 313015516c77SSepherosa Ziehau 313115516c77SSepherosa Ziehau /* Zero out this stat. */ 3132a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 313315516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 313415516c77SSepherosa Ziehau *((u_long *)((uint8_t *)rxr + ofs)) = 0; 313515516c77SSepherosa Ziehau } 313615516c77SSepherosa Ziehau return 0; 313715516c77SSepherosa Ziehau } 313815516c77SSepherosa Ziehau 313915516c77SSepherosa Ziehau static int 314015516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 314115516c77SSepherosa Ziehau { 314215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 314315516c77SSepherosa Ziehau int ofs = arg2, i, error; 314415516c77SSepherosa Ziehau struct hn_tx_ring *txr; 314515516c77SSepherosa Ziehau u_long stat; 314615516c77SSepherosa Ziehau 314715516c77SSepherosa Ziehau stat = 0; 3148a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 314915516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 315015516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)txr + ofs)); 315115516c77SSepherosa Ziehau } 315215516c77SSepherosa Ziehau 315315516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 315415516c77SSepherosa Ziehau if (error || req->newptr == NULL) 315515516c77SSepherosa Ziehau return error; 315615516c77SSepherosa Ziehau 315715516c77SSepherosa Ziehau /* Zero out this stat. */ 3158a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 315915516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 316015516c77SSepherosa Ziehau *((u_long *)((uint8_t *)txr + ofs)) = 0; 316115516c77SSepherosa Ziehau } 316215516c77SSepherosa Ziehau return 0; 316315516c77SSepherosa Ziehau } 316415516c77SSepherosa Ziehau 316515516c77SSepherosa Ziehau static int 316615516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS) 316715516c77SSepherosa Ziehau { 316815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 316915516c77SSepherosa Ziehau int ofs = arg2, i, error, conf; 317015516c77SSepherosa Ziehau struct hn_tx_ring *txr; 317115516c77SSepherosa Ziehau 317215516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[0]; 317315516c77SSepherosa Ziehau conf = *((int *)((uint8_t *)txr + ofs)); 317415516c77SSepherosa Ziehau 317515516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &conf, 0, req); 317615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 317715516c77SSepherosa Ziehau return error; 317815516c77SSepherosa Ziehau 317915516c77SSepherosa Ziehau HN_LOCK(sc); 3180a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 318115516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 318215516c77SSepherosa Ziehau *((int *)((uint8_t *)txr + ofs)) = conf; 318315516c77SSepherosa Ziehau } 318415516c77SSepherosa Ziehau HN_UNLOCK(sc); 318515516c77SSepherosa Ziehau 318615516c77SSepherosa Ziehau return 0; 318715516c77SSepherosa Ziehau } 318815516c77SSepherosa Ziehau 318915516c77SSepherosa Ziehau static int 3190dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS) 3191dc13fee6SSepherosa Ziehau { 3192dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 3193dc13fee6SSepherosa Ziehau int error, size; 3194dc13fee6SSepherosa Ziehau 3195dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 3196dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &size, 0, req); 3197dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 3198dc13fee6SSepherosa Ziehau return (error); 3199dc13fee6SSepherosa Ziehau 3200dc13fee6SSepherosa Ziehau HN_LOCK(sc); 3201dc13fee6SSepherosa Ziehau sc->hn_agg_size = size; 3202dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 3203dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 3204dc13fee6SSepherosa Ziehau 3205dc13fee6SSepherosa Ziehau return (0); 3206dc13fee6SSepherosa Ziehau } 3207dc13fee6SSepherosa Ziehau 3208dc13fee6SSepherosa Ziehau static int 3209dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS) 3210dc13fee6SSepherosa Ziehau { 3211dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 3212dc13fee6SSepherosa Ziehau int error, pkts; 3213dc13fee6SSepherosa Ziehau 3214dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 3215dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &pkts, 0, req); 3216dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 3217dc13fee6SSepherosa Ziehau return (error); 3218dc13fee6SSepherosa Ziehau 3219dc13fee6SSepherosa Ziehau HN_LOCK(sc); 3220dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = pkts; 3221dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 3222dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 3223dc13fee6SSepherosa Ziehau 3224dc13fee6SSepherosa Ziehau return (0); 3225dc13fee6SSepherosa Ziehau } 3226dc13fee6SSepherosa Ziehau 3227dc13fee6SSepherosa Ziehau static int 3228dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS) 3229dc13fee6SSepherosa Ziehau { 3230dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 3231dc13fee6SSepherosa Ziehau int pkts; 3232dc13fee6SSepherosa Ziehau 3233dc13fee6SSepherosa Ziehau pkts = sc->hn_tx_ring[0].hn_agg_pktmax; 3234dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &pkts, 0, req)); 3235dc13fee6SSepherosa Ziehau } 3236dc13fee6SSepherosa Ziehau 3237dc13fee6SSepherosa Ziehau static int 3238dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS) 3239dc13fee6SSepherosa Ziehau { 3240dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 3241dc13fee6SSepherosa Ziehau int align; 3242dc13fee6SSepherosa Ziehau 3243dc13fee6SSepherosa Ziehau align = sc->hn_tx_ring[0].hn_agg_align; 3244dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &align, 0, req)); 3245dc13fee6SSepherosa Ziehau } 3246dc13fee6SSepherosa Ziehau 32476c1204dfSSepherosa Ziehau static void 32486c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz) 32496c1204dfSSepherosa Ziehau { 32506c1204dfSSepherosa Ziehau if (pollhz == 0) 32516c1204dfSSepherosa Ziehau vmbus_chan_poll_disable(chan); 32526c1204dfSSepherosa Ziehau else 32536c1204dfSSepherosa Ziehau vmbus_chan_poll_enable(chan, pollhz); 32546c1204dfSSepherosa Ziehau } 32556c1204dfSSepherosa Ziehau 32566c1204dfSSepherosa Ziehau static void 32576c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz) 32586c1204dfSSepherosa Ziehau { 32596c1204dfSSepherosa Ziehau int nsubch = sc->hn_rx_ring_inuse - 1; 32606c1204dfSSepherosa Ziehau 32616c1204dfSSepherosa Ziehau HN_LOCK_ASSERT(sc); 32626c1204dfSSepherosa Ziehau 32636c1204dfSSepherosa Ziehau if (nsubch > 0) { 32646c1204dfSSepherosa Ziehau struct vmbus_channel **subch; 32656c1204dfSSepherosa Ziehau int i; 32666c1204dfSSepherosa Ziehau 32676c1204dfSSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 32686c1204dfSSepherosa Ziehau for (i = 0; i < nsubch; ++i) 32696c1204dfSSepherosa Ziehau hn_chan_polling(subch[i], pollhz); 32706c1204dfSSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 32716c1204dfSSepherosa Ziehau } 32726c1204dfSSepherosa Ziehau hn_chan_polling(sc->hn_prichan, pollhz); 32736c1204dfSSepherosa Ziehau } 32746c1204dfSSepherosa Ziehau 32756c1204dfSSepherosa Ziehau static int 32766c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS) 32776c1204dfSSepherosa Ziehau { 32786c1204dfSSepherosa Ziehau struct hn_softc *sc = arg1; 32796c1204dfSSepherosa Ziehau int pollhz, error; 32806c1204dfSSepherosa Ziehau 32816c1204dfSSepherosa Ziehau pollhz = sc->hn_pollhz; 32826c1204dfSSepherosa Ziehau error = sysctl_handle_int(oidp, &pollhz, 0, req); 32836c1204dfSSepherosa Ziehau if (error || req->newptr == NULL) 32846c1204dfSSepherosa Ziehau return (error); 32856c1204dfSSepherosa Ziehau 32866c1204dfSSepherosa Ziehau if (pollhz != 0 && 32876c1204dfSSepherosa Ziehau (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX)) 32886c1204dfSSepherosa Ziehau return (EINVAL); 32896c1204dfSSepherosa Ziehau 32906c1204dfSSepherosa Ziehau HN_LOCK(sc); 32916c1204dfSSepherosa Ziehau if (sc->hn_pollhz != pollhz) { 32926c1204dfSSepherosa Ziehau sc->hn_pollhz = pollhz; 32936c1204dfSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && 32946c1204dfSSepherosa Ziehau (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 32956c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 32966c1204dfSSepherosa Ziehau } 32976c1204dfSSepherosa Ziehau HN_UNLOCK(sc); 32986c1204dfSSepherosa Ziehau 32996c1204dfSSepherosa Ziehau return (0); 33006c1204dfSSepherosa Ziehau } 33016c1204dfSSepherosa Ziehau 3302dc13fee6SSepherosa Ziehau static int 330315516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS) 330415516c77SSepherosa Ziehau { 330515516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 330615516c77SSepherosa Ziehau char verstr[16]; 330715516c77SSepherosa Ziehau 330815516c77SSepherosa Ziehau snprintf(verstr, sizeof(verstr), "%u.%u", 330915516c77SSepherosa Ziehau HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 331015516c77SSepherosa Ziehau HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 331115516c77SSepherosa Ziehau return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 331215516c77SSepherosa Ziehau } 331315516c77SSepherosa Ziehau 331415516c77SSepherosa Ziehau static int 331515516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS) 331615516c77SSepherosa Ziehau { 331715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 331815516c77SSepherosa Ziehau char caps_str[128]; 331915516c77SSepherosa Ziehau uint32_t caps; 332015516c77SSepherosa Ziehau 332115516c77SSepherosa Ziehau HN_LOCK(sc); 332215516c77SSepherosa Ziehau caps = sc->hn_caps; 332315516c77SSepherosa Ziehau HN_UNLOCK(sc); 332415516c77SSepherosa Ziehau snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS); 332515516c77SSepherosa Ziehau return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req); 332615516c77SSepherosa Ziehau } 332715516c77SSepherosa Ziehau 332815516c77SSepherosa Ziehau static int 332915516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS) 333015516c77SSepherosa Ziehau { 333115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 333215516c77SSepherosa Ziehau char assist_str[128]; 333315516c77SSepherosa Ziehau uint32_t hwassist; 333415516c77SSepherosa Ziehau 333515516c77SSepherosa Ziehau HN_LOCK(sc); 333615516c77SSepherosa Ziehau hwassist = sc->hn_ifp->if_hwassist; 333715516c77SSepherosa Ziehau HN_UNLOCK(sc); 333815516c77SSepherosa Ziehau snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS); 333915516c77SSepherosa Ziehau return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req); 334015516c77SSepherosa Ziehau } 334115516c77SSepherosa Ziehau 334215516c77SSepherosa Ziehau static int 334315516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS) 334415516c77SSepherosa Ziehau { 334515516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 334615516c77SSepherosa Ziehau char filter_str[128]; 334715516c77SSepherosa Ziehau uint32_t filter; 334815516c77SSepherosa Ziehau 334915516c77SSepherosa Ziehau HN_LOCK(sc); 335015516c77SSepherosa Ziehau filter = sc->hn_rx_filter; 335115516c77SSepherosa Ziehau HN_UNLOCK(sc); 335215516c77SSepherosa Ziehau snprintf(filter_str, sizeof(filter_str), "%b", filter, 335315516c77SSepherosa Ziehau NDIS_PACKET_TYPES); 335415516c77SSepherosa Ziehau return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req); 335515516c77SSepherosa Ziehau } 335615516c77SSepherosa Ziehau 335734d68912SSepherosa Ziehau #ifndef RSS 335834d68912SSepherosa Ziehau 335915516c77SSepherosa Ziehau static int 336015516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS) 336115516c77SSepherosa Ziehau { 336215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 336315516c77SSepherosa Ziehau int error; 336415516c77SSepherosa Ziehau 336515516c77SSepherosa Ziehau HN_LOCK(sc); 336615516c77SSepherosa Ziehau 336715516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 336815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 336915516c77SSepherosa Ziehau goto back; 337015516c77SSepherosa Ziehau 337115516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 337215516c77SSepherosa Ziehau if (error) 337315516c77SSepherosa Ziehau goto back; 337415516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 337515516c77SSepherosa Ziehau 337615516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 337715516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 337815516c77SSepherosa Ziehau } else { 337915516c77SSepherosa Ziehau /* Not RSS capable, at least for now; just save the RSS key. */ 338015516c77SSepherosa Ziehau error = 0; 338115516c77SSepherosa Ziehau } 338215516c77SSepherosa Ziehau back: 338315516c77SSepherosa Ziehau HN_UNLOCK(sc); 338415516c77SSepherosa Ziehau return (error); 338515516c77SSepherosa Ziehau } 338615516c77SSepherosa Ziehau 338715516c77SSepherosa Ziehau static int 338815516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS) 338915516c77SSepherosa Ziehau { 339015516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 339115516c77SSepherosa Ziehau int error; 339215516c77SSepherosa Ziehau 339315516c77SSepherosa Ziehau HN_LOCK(sc); 339415516c77SSepherosa Ziehau 339515516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 339615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 339715516c77SSepherosa Ziehau goto back; 339815516c77SSepherosa Ziehau 339915516c77SSepherosa Ziehau /* 340015516c77SSepherosa Ziehau * Don't allow RSS indirect table change, if this interface is not 340115516c77SSepherosa Ziehau * RSS capable currently. 340215516c77SSepherosa Ziehau */ 340315516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 340415516c77SSepherosa Ziehau error = EOPNOTSUPP; 340515516c77SSepherosa Ziehau goto back; 340615516c77SSepherosa Ziehau } 340715516c77SSepherosa Ziehau 340815516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 340915516c77SSepherosa Ziehau if (error) 341015516c77SSepherosa Ziehau goto back; 341115516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 341215516c77SSepherosa Ziehau 3413afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 341415516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 341515516c77SSepherosa Ziehau back: 341615516c77SSepherosa Ziehau HN_UNLOCK(sc); 341715516c77SSepherosa Ziehau return (error); 341815516c77SSepherosa Ziehau } 341915516c77SSepherosa Ziehau 342034d68912SSepherosa Ziehau #endif /* !RSS */ 342134d68912SSepherosa Ziehau 342215516c77SSepherosa Ziehau static int 342315516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS) 342415516c77SSepherosa Ziehau { 342515516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 342615516c77SSepherosa Ziehau char hash_str[128]; 342715516c77SSepherosa Ziehau uint32_t hash; 342815516c77SSepherosa Ziehau 342915516c77SSepherosa Ziehau HN_LOCK(sc); 343015516c77SSepherosa Ziehau hash = sc->hn_rss_hash; 343115516c77SSepherosa Ziehau HN_UNLOCK(sc); 343215516c77SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 343315516c77SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 343415516c77SSepherosa Ziehau } 343515516c77SSepherosa Ziehau 343615516c77SSepherosa Ziehau static int 343740d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS) 343840d60d6eSDexuan Cui { 343940d60d6eSDexuan Cui struct hn_softc *sc = arg1; 3440499c3e17SSepherosa Ziehau char vf_name[IFNAMSIZ + 1]; 344140d60d6eSDexuan Cui struct ifnet *vf; 344240d60d6eSDexuan Cui 344340d60d6eSDexuan Cui HN_LOCK(sc); 344440d60d6eSDexuan Cui vf_name[0] = '\0'; 3445499c3e17SSepherosa Ziehau vf = sc->hn_vf_ifp; 344640d60d6eSDexuan Cui if (vf != NULL) 344740d60d6eSDexuan Cui snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf)); 344840d60d6eSDexuan Cui HN_UNLOCK(sc); 344940d60d6eSDexuan Cui return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); 345040d60d6eSDexuan Cui } 345140d60d6eSDexuan Cui 345240d60d6eSDexuan Cui static int 3453499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS) 3454499c3e17SSepherosa Ziehau { 3455499c3e17SSepherosa Ziehau struct hn_softc *sc = arg1; 3456499c3e17SSepherosa Ziehau char vf_name[IFNAMSIZ + 1]; 3457499c3e17SSepherosa Ziehau struct ifnet *vf; 3458499c3e17SSepherosa Ziehau 3459499c3e17SSepherosa Ziehau HN_LOCK(sc); 3460499c3e17SSepherosa Ziehau vf_name[0] = '\0'; 3461499c3e17SSepherosa Ziehau vf = sc->hn_rx_ring[0].hn_rxvf_ifp; 3462499c3e17SSepherosa Ziehau if (vf != NULL) 3463499c3e17SSepherosa Ziehau snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf)); 3464499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 3465499c3e17SSepherosa Ziehau return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); 3466499c3e17SSepherosa Ziehau } 3467499c3e17SSepherosa Ziehau 3468499c3e17SSepherosa Ziehau static int 3469499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS) 3470499c3e17SSepherosa Ziehau { 3471499c3e17SSepherosa Ziehau struct rm_priotracker pt; 3472499c3e17SSepherosa Ziehau struct sbuf *sb; 3473499c3e17SSepherosa Ziehau int error, i; 3474499c3e17SSepherosa Ziehau bool first; 3475499c3e17SSepherosa Ziehau 3476499c3e17SSepherosa Ziehau error = sysctl_wire_old_buffer(req, 0); 3477499c3e17SSepherosa Ziehau if (error != 0) 3478499c3e17SSepherosa Ziehau return (error); 3479499c3e17SSepherosa Ziehau 3480499c3e17SSepherosa Ziehau sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 3481499c3e17SSepherosa Ziehau if (sb == NULL) 3482499c3e17SSepherosa Ziehau return (ENOMEM); 3483499c3e17SSepherosa Ziehau 3484499c3e17SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 3485499c3e17SSepherosa Ziehau 3486499c3e17SSepherosa Ziehau first = true; 3487499c3e17SSepherosa Ziehau for (i = 0; i < hn_vfmap_size; ++i) { 3488499c3e17SSepherosa Ziehau struct ifnet *ifp; 3489499c3e17SSepherosa Ziehau 3490499c3e17SSepherosa Ziehau if (hn_vfmap[i] == NULL) 3491499c3e17SSepherosa Ziehau continue; 3492499c3e17SSepherosa Ziehau 3493499c3e17SSepherosa Ziehau ifp = ifnet_byindex(i); 3494499c3e17SSepherosa Ziehau if (ifp != NULL) { 3495499c3e17SSepherosa Ziehau if (first) 3496499c3e17SSepherosa Ziehau sbuf_printf(sb, "%s", ifp->if_xname); 3497499c3e17SSepherosa Ziehau else 3498499c3e17SSepherosa Ziehau sbuf_printf(sb, " %s", ifp->if_xname); 3499499c3e17SSepherosa Ziehau first = false; 3500499c3e17SSepherosa Ziehau } 3501499c3e17SSepherosa Ziehau } 3502499c3e17SSepherosa Ziehau 3503499c3e17SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 3504499c3e17SSepherosa Ziehau 3505499c3e17SSepherosa Ziehau error = sbuf_finish(sb); 3506499c3e17SSepherosa Ziehau sbuf_delete(sb); 3507499c3e17SSepherosa Ziehau return (error); 3508499c3e17SSepherosa Ziehau } 3509499c3e17SSepherosa Ziehau 3510499c3e17SSepherosa Ziehau static int 3511499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS) 3512499c3e17SSepherosa Ziehau { 3513499c3e17SSepherosa Ziehau struct rm_priotracker pt; 3514499c3e17SSepherosa Ziehau struct sbuf *sb; 3515499c3e17SSepherosa Ziehau int error, i; 3516499c3e17SSepherosa Ziehau bool first; 3517499c3e17SSepherosa Ziehau 3518499c3e17SSepherosa Ziehau error = sysctl_wire_old_buffer(req, 0); 3519499c3e17SSepherosa Ziehau if (error != 0) 3520499c3e17SSepherosa Ziehau return (error); 3521499c3e17SSepherosa Ziehau 3522499c3e17SSepherosa Ziehau sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 3523499c3e17SSepherosa Ziehau if (sb == NULL) 3524499c3e17SSepherosa Ziehau return (ENOMEM); 3525499c3e17SSepherosa Ziehau 3526499c3e17SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 3527499c3e17SSepherosa Ziehau 3528499c3e17SSepherosa Ziehau first = true; 3529499c3e17SSepherosa Ziehau for (i = 0; i < hn_vfmap_size; ++i) { 3530499c3e17SSepherosa Ziehau struct ifnet *ifp, *hn_ifp; 3531499c3e17SSepherosa Ziehau 3532499c3e17SSepherosa Ziehau hn_ifp = hn_vfmap[i]; 3533499c3e17SSepherosa Ziehau if (hn_ifp == NULL) 3534499c3e17SSepherosa Ziehau continue; 3535499c3e17SSepherosa Ziehau 3536499c3e17SSepherosa Ziehau ifp = ifnet_byindex(i); 3537499c3e17SSepherosa Ziehau if (ifp != NULL) { 3538499c3e17SSepherosa Ziehau if (first) { 3539499c3e17SSepherosa Ziehau sbuf_printf(sb, "%s:%s", ifp->if_xname, 3540499c3e17SSepherosa Ziehau hn_ifp->if_xname); 3541499c3e17SSepherosa Ziehau } else { 3542499c3e17SSepherosa Ziehau sbuf_printf(sb, " %s:%s", ifp->if_xname, 3543499c3e17SSepherosa Ziehau hn_ifp->if_xname); 3544499c3e17SSepherosa Ziehau } 3545499c3e17SSepherosa Ziehau first = false; 3546499c3e17SSepherosa Ziehau } 3547499c3e17SSepherosa Ziehau } 3548499c3e17SSepherosa Ziehau 3549499c3e17SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 3550499c3e17SSepherosa Ziehau 3551499c3e17SSepherosa Ziehau error = sbuf_finish(sb); 3552499c3e17SSepherosa Ziehau sbuf_delete(sb); 3553499c3e17SSepherosa Ziehau return (error); 3554499c3e17SSepherosa Ziehau } 3555499c3e17SSepherosa Ziehau 3556499c3e17SSepherosa Ziehau static int 355715516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff) 355815516c77SSepherosa Ziehau { 355915516c77SSepherosa Ziehau const struct ip *ip; 356015516c77SSepherosa Ziehau int len, iphlen, iplen; 356115516c77SSepherosa Ziehau const struct tcphdr *th; 356215516c77SSepherosa Ziehau int thoff; /* TCP data offset */ 356315516c77SSepherosa Ziehau 356415516c77SSepherosa Ziehau len = hoff + sizeof(struct ip); 356515516c77SSepherosa Ziehau 356615516c77SSepherosa Ziehau /* The packet must be at least the size of an IP header. */ 356715516c77SSepherosa Ziehau if (m->m_pkthdr.len < len) 356815516c77SSepherosa Ziehau return IPPROTO_DONE; 356915516c77SSepherosa Ziehau 357015516c77SSepherosa Ziehau /* The fixed IP header must reside completely in the first mbuf. */ 357115516c77SSepherosa Ziehau if (m->m_len < len) 357215516c77SSepherosa Ziehau return IPPROTO_DONE; 357315516c77SSepherosa Ziehau 357415516c77SSepherosa Ziehau ip = mtodo(m, hoff); 357515516c77SSepherosa Ziehau 357615516c77SSepherosa Ziehau /* Bound check the packet's stated IP header length. */ 357715516c77SSepherosa Ziehau iphlen = ip->ip_hl << 2; 357815516c77SSepherosa Ziehau if (iphlen < sizeof(struct ip)) /* minimum header length */ 357915516c77SSepherosa Ziehau return IPPROTO_DONE; 358015516c77SSepherosa Ziehau 358115516c77SSepherosa Ziehau /* The full IP header must reside completely in the one mbuf. */ 358215516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen) 358315516c77SSepherosa Ziehau return IPPROTO_DONE; 358415516c77SSepherosa Ziehau 358515516c77SSepherosa Ziehau iplen = ntohs(ip->ip_len); 358615516c77SSepherosa Ziehau 358715516c77SSepherosa Ziehau /* 358815516c77SSepherosa Ziehau * Check that the amount of data in the buffers is as 358915516c77SSepherosa Ziehau * at least much as the IP header would have us expect. 359015516c77SSepherosa Ziehau */ 359115516c77SSepherosa Ziehau if (m->m_pkthdr.len < hoff + iplen) 359215516c77SSepherosa Ziehau return IPPROTO_DONE; 359315516c77SSepherosa Ziehau 359415516c77SSepherosa Ziehau /* 359515516c77SSepherosa Ziehau * Ignore IP fragments. 359615516c77SSepherosa Ziehau */ 359715516c77SSepherosa Ziehau if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF)) 359815516c77SSepherosa Ziehau return IPPROTO_DONE; 359915516c77SSepherosa Ziehau 360015516c77SSepherosa Ziehau /* 360115516c77SSepherosa Ziehau * The TCP/IP or UDP/IP header must be entirely contained within 360215516c77SSepherosa Ziehau * the first fragment of a packet. 360315516c77SSepherosa Ziehau */ 360415516c77SSepherosa Ziehau switch (ip->ip_p) { 360515516c77SSepherosa Ziehau case IPPROTO_TCP: 360615516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct tcphdr)) 360715516c77SSepherosa Ziehau return IPPROTO_DONE; 360815516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct tcphdr)) 360915516c77SSepherosa Ziehau return IPPROTO_DONE; 361015516c77SSepherosa Ziehau th = (const struct tcphdr *)((const uint8_t *)ip + iphlen); 361115516c77SSepherosa Ziehau thoff = th->th_off << 2; 361215516c77SSepherosa Ziehau if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen) 361315516c77SSepherosa Ziehau return IPPROTO_DONE; 361415516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + thoff) 361515516c77SSepherosa Ziehau return IPPROTO_DONE; 361615516c77SSepherosa Ziehau break; 361715516c77SSepherosa Ziehau case IPPROTO_UDP: 361815516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct udphdr)) 361915516c77SSepherosa Ziehau return IPPROTO_DONE; 362015516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct udphdr)) 362115516c77SSepherosa Ziehau return IPPROTO_DONE; 362215516c77SSepherosa Ziehau break; 362315516c77SSepherosa Ziehau default: 362415516c77SSepherosa Ziehau if (iplen < iphlen) 362515516c77SSepherosa Ziehau return IPPROTO_DONE; 362615516c77SSepherosa Ziehau break; 362715516c77SSepherosa Ziehau } 362815516c77SSepherosa Ziehau return ip->ip_p; 362915516c77SSepherosa Ziehau } 363015516c77SSepherosa Ziehau 363115516c77SSepherosa Ziehau static int 363215516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt) 363315516c77SSepherosa Ziehau { 363415516c77SSepherosa Ziehau struct sysctl_oid_list *child; 363515516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 363615516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 363715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 363815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 363915516c77SSepherosa Ziehau int lroent_cnt; 364015516c77SSepherosa Ziehau #endif 364115516c77SSepherosa Ziehau #endif 364215516c77SSepherosa Ziehau int i; 364315516c77SSepherosa Ziehau 364415516c77SSepherosa Ziehau /* 364515516c77SSepherosa Ziehau * Create RXBUF for reception. 364615516c77SSepherosa Ziehau * 364715516c77SSepherosa Ziehau * NOTE: 364815516c77SSepherosa Ziehau * - It is shared by all channels. 364915516c77SSepherosa Ziehau * - A large enough buffer is allocated, certain version of NVSes 365015516c77SSepherosa Ziehau * may further limit the usable space. 365115516c77SSepherosa Ziehau */ 365215516c77SSepherosa Ziehau sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 365315516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma, 365415516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 365515516c77SSepherosa Ziehau if (sc->hn_rxbuf == NULL) { 365615516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate rxbuf failed\n"); 365715516c77SSepherosa Ziehau return (ENOMEM); 365815516c77SSepherosa Ziehau } 365915516c77SSepherosa Ziehau 366015516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = ring_cnt; 366115516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt; 366215516c77SSepherosa Ziehau 366315516c77SSepherosa Ziehau sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt, 366415516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 366515516c77SSepherosa Ziehau 366615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 366715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 366815516c77SSepherosa Ziehau lroent_cnt = hn_lro_entry_count; 366915516c77SSepherosa Ziehau if (lroent_cnt < TCP_LRO_ENTRIES) 367015516c77SSepherosa Ziehau lroent_cnt = TCP_LRO_ENTRIES; 367115516c77SSepherosa Ziehau if (bootverbose) 367215516c77SSepherosa Ziehau device_printf(dev, "LRO: entry count %d\n", lroent_cnt); 367315516c77SSepherosa Ziehau #endif 367415516c77SSepherosa Ziehau #endif /* INET || INET6 */ 367515516c77SSepherosa Ziehau 367615516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 367715516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 367815516c77SSepherosa Ziehau 367915516c77SSepherosa Ziehau /* Create dev.hn.UNIT.rx sysctl tree */ 368015516c77SSepherosa Ziehau sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx", 368115516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 368215516c77SSepherosa Ziehau 368315516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 368415516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 368515516c77SSepherosa Ziehau 368615516c77SSepherosa Ziehau rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 368715516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE, 368815516c77SSepherosa Ziehau &rxr->hn_br_dma, BUS_DMA_WAITOK); 368915516c77SSepherosa Ziehau if (rxr->hn_br == NULL) { 369015516c77SSepherosa Ziehau device_printf(dev, "allocate bufring failed\n"); 369115516c77SSepherosa Ziehau return (ENOMEM); 369215516c77SSepherosa Ziehau } 369315516c77SSepherosa Ziehau 369415516c77SSepherosa Ziehau if (hn_trust_hosttcp) 369515516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP; 369615516c77SSepherosa Ziehau if (hn_trust_hostudp) 369715516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP; 369815516c77SSepherosa Ziehau if (hn_trust_hostip) 369915516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP; 370015516c77SSepherosa Ziehau rxr->hn_ifp = sc->hn_ifp; 370115516c77SSepherosa Ziehau if (i < sc->hn_tx_ring_cnt) 370215516c77SSepherosa Ziehau rxr->hn_txr = &sc->hn_tx_ring[i]; 370315516c77SSepherosa Ziehau rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF; 370415516c77SSepherosa Ziehau rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK); 370515516c77SSepherosa Ziehau rxr->hn_rx_idx = i; 370615516c77SSepherosa Ziehau rxr->hn_rxbuf = sc->hn_rxbuf; 370715516c77SSepherosa Ziehau 370815516c77SSepherosa Ziehau /* 370915516c77SSepherosa Ziehau * Initialize LRO. 371015516c77SSepherosa Ziehau */ 371115516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 371215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 371315516c77SSepherosa Ziehau tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt, 371415516c77SSepherosa Ziehau hn_lro_mbufq_depth); 371515516c77SSepherosa Ziehau #else 371615516c77SSepherosa Ziehau tcp_lro_init(&rxr->hn_lro); 371715516c77SSepherosa Ziehau rxr->hn_lro.ifp = sc->hn_ifp; 371815516c77SSepherosa Ziehau #endif 371915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 372015516c77SSepherosa Ziehau rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF; 372115516c77SSepherosa Ziehau rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF; 372215516c77SSepherosa Ziehau #endif 372315516c77SSepherosa Ziehau #endif /* INET || INET6 */ 372415516c77SSepherosa Ziehau 372515516c77SSepherosa Ziehau if (sc->hn_rx_sysctl_tree != NULL) { 372615516c77SSepherosa Ziehau char name[16]; 372715516c77SSepherosa Ziehau 372815516c77SSepherosa Ziehau /* 372915516c77SSepherosa Ziehau * Create per RX ring sysctl tree: 373015516c77SSepherosa Ziehau * dev.hn.UNIT.rx.RINGID 373115516c77SSepherosa Ziehau */ 373215516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", i); 373315516c77SSepherosa Ziehau rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, 373415516c77SSepherosa Ziehau SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree), 373515516c77SSepherosa Ziehau OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 373615516c77SSepherosa Ziehau 373715516c77SSepherosa Ziehau if (rxr->hn_rx_sysctl_tree != NULL) { 373815516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 373915516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 374015516c77SSepherosa Ziehau OID_AUTO, "packets", CTLFLAG_RW, 374115516c77SSepherosa Ziehau &rxr->hn_pkts, "# of packets received"); 374215516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 374315516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 374415516c77SSepherosa Ziehau OID_AUTO, "rss_pkts", CTLFLAG_RW, 374515516c77SSepherosa Ziehau &rxr->hn_rss_pkts, 374615516c77SSepherosa Ziehau "# of packets w/ RSS info received"); 374715516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, 374815516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 374915516c77SSepherosa Ziehau OID_AUTO, "pktbuf_len", CTLFLAG_RD, 375015516c77SSepherosa Ziehau &rxr->hn_pktbuf_len, 0, 375115516c77SSepherosa Ziehau "Temporary channel packet buffer length"); 375215516c77SSepherosa Ziehau } 375315516c77SSepherosa Ziehau } 375415516c77SSepherosa Ziehau } 375515516c77SSepherosa Ziehau 375615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued", 375715516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 375815516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_queued), 375915516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 376015516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 376115516c77SSepherosa Ziehau #else 376215516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 376315516c77SSepherosa Ziehau #endif 376415516c77SSepherosa Ziehau "LU", "LRO queued"); 376515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed", 376615516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 376715516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_flushed), 376815516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 376915516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 377015516c77SSepherosa Ziehau #else 377115516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 377215516c77SSepherosa Ziehau #endif 377315516c77SSepherosa Ziehau "LU", "LRO flushed"); 377415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried", 377515516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 377615516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro_tried), 377715516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries"); 377815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 377915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim", 378015516c77SSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 378115516c77SSepherosa Ziehau hn_lro_lenlim_sysctl, "IU", 378215516c77SSepherosa Ziehau "Max # of data bytes to be aggregated by LRO"); 378315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim", 378415516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 378515516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl, "I", 378615516c77SSepherosa Ziehau "Max # of ACKs to be aggregated by LRO"); 378715516c77SSepherosa Ziehau #endif 378815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp", 378915516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP, 379015516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 379115516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 379215516c77SSepherosa Ziehau "when csum info is missing"); 379315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp", 379415516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP, 379515516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 379615516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 379715516c77SSepherosa Ziehau "when csum info is missing"); 379815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip", 379915516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP, 380015516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 380115516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 380215516c77SSepherosa Ziehau "when csum info is missing"); 380315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip", 380415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 380515516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_ip), 380615516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP"); 380715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp", 380815516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 380915516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_tcp), 381015516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP"); 381115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp", 381215516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 381315516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_udp), 381415516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP"); 381515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted", 381615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 381715516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_trusted), 381815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", 381915516c77SSepherosa Ziehau "# of packets that we trust host's csum verification"); 382015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts", 382115516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 382215516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_small_pkts), 382315516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of small packets received"); 382415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed", 382515516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 382615516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_ack_failed), 382715516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures"); 382815516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt", 382915516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings"); 383015516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse", 383115516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings"); 383215516c77SSepherosa Ziehau 383315516c77SSepherosa Ziehau return (0); 383415516c77SSepherosa Ziehau } 383515516c77SSepherosa Ziehau 383615516c77SSepherosa Ziehau static void 383715516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc) 383815516c77SSepherosa Ziehau { 383915516c77SSepherosa Ziehau int i; 384015516c77SSepherosa Ziehau 384115516c77SSepherosa Ziehau if (sc->hn_rxbuf != NULL) { 38422494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0) 384315516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf); 38442494d735SSepherosa Ziehau else 38452494d735SSepherosa Ziehau device_printf(sc->hn_dev, "RXBUF is referenced\n"); 384615516c77SSepherosa Ziehau sc->hn_rxbuf = NULL; 384715516c77SSepherosa Ziehau } 384815516c77SSepherosa Ziehau 384915516c77SSepherosa Ziehau if (sc->hn_rx_ring_cnt == 0) 385015516c77SSepherosa Ziehau return; 385115516c77SSepherosa Ziehau 385215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 385315516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 385415516c77SSepherosa Ziehau 385515516c77SSepherosa Ziehau if (rxr->hn_br == NULL) 385615516c77SSepherosa Ziehau continue; 38572494d735SSepherosa Ziehau if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) { 385815516c77SSepherosa Ziehau hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br); 38592494d735SSepherosa Ziehau } else { 38602494d735SSepherosa Ziehau device_printf(sc->hn_dev, 38612494d735SSepherosa Ziehau "%dth channel bufring is referenced", i); 38622494d735SSepherosa Ziehau } 386315516c77SSepherosa Ziehau rxr->hn_br = NULL; 386415516c77SSepherosa Ziehau 386515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 386615516c77SSepherosa Ziehau tcp_lro_free(&rxr->hn_lro); 386715516c77SSepherosa Ziehau #endif 386815516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 386915516c77SSepherosa Ziehau } 387015516c77SSepherosa Ziehau free(sc->hn_rx_ring, M_DEVBUF); 387115516c77SSepherosa Ziehau sc->hn_rx_ring = NULL; 387215516c77SSepherosa Ziehau 387315516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = 0; 387415516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = 0; 387515516c77SSepherosa Ziehau } 387615516c77SSepherosa Ziehau 387715516c77SSepherosa Ziehau static int 387815516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id) 387915516c77SSepherosa Ziehau { 388015516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[id]; 388115516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 388215516c77SSepherosa Ziehau bus_dma_tag_t parent_dtag; 388315516c77SSepherosa Ziehau int error, i; 388415516c77SSepherosa Ziehau 388515516c77SSepherosa Ziehau txr->hn_sc = sc; 388615516c77SSepherosa Ziehau txr->hn_tx_idx = id; 388715516c77SSepherosa Ziehau 388815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 388915516c77SSepherosa Ziehau mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); 389015516c77SSepherosa Ziehau #endif 389115516c77SSepherosa Ziehau mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF); 389215516c77SSepherosa Ziehau 389315516c77SSepherosa Ziehau txr->hn_txdesc_cnt = HN_TX_DESC_CNT; 389415516c77SSepherosa Ziehau txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt, 389515516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 389615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 389715516c77SSepherosa Ziehau SLIST_INIT(&txr->hn_txlist); 389815516c77SSepherosa Ziehau #else 389915516c77SSepherosa Ziehau txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF, 390015516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 390115516c77SSepherosa Ziehau #endif 390215516c77SSepherosa Ziehau 39030e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) { 39040e11868dSSepherosa Ziehau txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ( 39050e11868dSSepherosa Ziehau device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id)); 39060e11868dSSepherosa Ziehau } else { 3907fdd0222aSSepherosa Ziehau txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt]; 39080e11868dSSepherosa Ziehau } 390915516c77SSepherosa Ziehau 391023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 391115516c77SSepherosa Ziehau if (hn_use_if_start) { 391215516c77SSepherosa Ziehau txr->hn_txeof = hn_start_txeof; 391315516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr); 391415516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr); 391523bf9e15SSepherosa Ziehau } else 391623bf9e15SSepherosa Ziehau #endif 391723bf9e15SSepherosa Ziehau { 391815516c77SSepherosa Ziehau int br_depth; 391915516c77SSepherosa Ziehau 392015516c77SSepherosa Ziehau txr->hn_txeof = hn_xmit_txeof; 392115516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr); 392215516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr); 392315516c77SSepherosa Ziehau 392415516c77SSepherosa Ziehau br_depth = hn_get_txswq_depth(txr); 392515516c77SSepherosa Ziehau txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF, 392615516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 392715516c77SSepherosa Ziehau } 392815516c77SSepherosa Ziehau 392915516c77SSepherosa Ziehau txr->hn_direct_tx_size = hn_direct_tx_size; 393015516c77SSepherosa Ziehau 393115516c77SSepherosa Ziehau /* 393215516c77SSepherosa Ziehau * Always schedule transmission instead of trying to do direct 393315516c77SSepherosa Ziehau * transmission. This one gives the best performance so far. 393415516c77SSepherosa Ziehau */ 393515516c77SSepherosa Ziehau txr->hn_sched_tx = 1; 393615516c77SSepherosa Ziehau 393715516c77SSepherosa Ziehau parent_dtag = bus_get_dma_tag(dev); 393815516c77SSepherosa Ziehau 393915516c77SSepherosa Ziehau /* DMA tag for RNDIS packet messages. */ 394015516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 394115516c77SSepherosa Ziehau HN_RNDIS_PKT_ALIGN, /* alignment */ 394215516c77SSepherosa Ziehau HN_RNDIS_PKT_BOUNDARY, /* boundary */ 394315516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 394415516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 394515516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 394615516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsize */ 394715516c77SSepherosa Ziehau 1, /* nsegments */ 394815516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsegsize */ 394915516c77SSepherosa Ziehau 0, /* flags */ 395015516c77SSepherosa Ziehau NULL, /* lockfunc */ 395115516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 395215516c77SSepherosa Ziehau &txr->hn_tx_rndis_dtag); 395315516c77SSepherosa Ziehau if (error) { 395415516c77SSepherosa Ziehau device_printf(dev, "failed to create rndis dmatag\n"); 395515516c77SSepherosa Ziehau return error; 395615516c77SSepherosa Ziehau } 395715516c77SSepherosa Ziehau 395815516c77SSepherosa Ziehau /* DMA tag for data. */ 395915516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 396015516c77SSepherosa Ziehau 1, /* alignment */ 396115516c77SSepherosa Ziehau HN_TX_DATA_BOUNDARY, /* boundary */ 396215516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 396315516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 396415516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 396515516c77SSepherosa Ziehau HN_TX_DATA_MAXSIZE, /* maxsize */ 396615516c77SSepherosa Ziehau HN_TX_DATA_SEGCNT_MAX, /* nsegments */ 396715516c77SSepherosa Ziehau HN_TX_DATA_SEGSIZE, /* maxsegsize */ 396815516c77SSepherosa Ziehau 0, /* flags */ 396915516c77SSepherosa Ziehau NULL, /* lockfunc */ 397015516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 397115516c77SSepherosa Ziehau &txr->hn_tx_data_dtag); 397215516c77SSepherosa Ziehau if (error) { 397315516c77SSepherosa Ziehau device_printf(dev, "failed to create data dmatag\n"); 397415516c77SSepherosa Ziehau return error; 397515516c77SSepherosa Ziehau } 397615516c77SSepherosa Ziehau 397715516c77SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) { 397815516c77SSepherosa Ziehau struct hn_txdesc *txd = &txr->hn_txdesc[i]; 397915516c77SSepherosa Ziehau 398015516c77SSepherosa Ziehau txd->txr = txr; 398115516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 3982dc13fee6SSepherosa Ziehau STAILQ_INIT(&txd->agg_list); 398315516c77SSepherosa Ziehau 398415516c77SSepherosa Ziehau /* 398515516c77SSepherosa Ziehau * Allocate and load RNDIS packet message. 398615516c77SSepherosa Ziehau */ 398715516c77SSepherosa Ziehau error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag, 398815516c77SSepherosa Ziehau (void **)&txd->rndis_pkt, 398915516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 399015516c77SSepherosa Ziehau &txd->rndis_pkt_dmap); 399115516c77SSepherosa Ziehau if (error) { 399215516c77SSepherosa Ziehau device_printf(dev, 399315516c77SSepherosa Ziehau "failed to allocate rndis_packet_msg, %d\n", i); 399415516c77SSepherosa Ziehau return error; 399515516c77SSepherosa Ziehau } 399615516c77SSepherosa Ziehau 399715516c77SSepherosa Ziehau error = bus_dmamap_load(txr->hn_tx_rndis_dtag, 399815516c77SSepherosa Ziehau txd->rndis_pkt_dmap, 399915516c77SSepherosa Ziehau txd->rndis_pkt, HN_RNDIS_PKT_LEN, 400015516c77SSepherosa Ziehau hyperv_dma_map_paddr, &txd->rndis_pkt_paddr, 400115516c77SSepherosa Ziehau BUS_DMA_NOWAIT); 400215516c77SSepherosa Ziehau if (error) { 400315516c77SSepherosa Ziehau device_printf(dev, 400415516c77SSepherosa Ziehau "failed to load rndis_packet_msg, %d\n", i); 400515516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 400615516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 400715516c77SSepherosa Ziehau return error; 400815516c77SSepherosa Ziehau } 400915516c77SSepherosa Ziehau 401015516c77SSepherosa Ziehau /* DMA map for TX data. */ 401115516c77SSepherosa Ziehau error = bus_dmamap_create(txr->hn_tx_data_dtag, 0, 401215516c77SSepherosa Ziehau &txd->data_dmap); 401315516c77SSepherosa Ziehau if (error) { 401415516c77SSepherosa Ziehau device_printf(dev, 401515516c77SSepherosa Ziehau "failed to allocate tx data dmamap\n"); 401615516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, 401715516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 401815516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 401915516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 402015516c77SSepherosa Ziehau return error; 402115516c77SSepherosa Ziehau } 402215516c77SSepherosa Ziehau 402315516c77SSepherosa Ziehau /* All set, put it to list */ 402415516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 402515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 402615516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 402715516c77SSepherosa Ziehau #else 402815516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 402915516c77SSepherosa Ziehau #endif 403015516c77SSepherosa Ziehau } 403115516c77SSepherosa Ziehau txr->hn_txdesc_avail = txr->hn_txdesc_cnt; 403215516c77SSepherosa Ziehau 403315516c77SSepherosa Ziehau if (sc->hn_tx_sysctl_tree != NULL) { 403415516c77SSepherosa Ziehau struct sysctl_oid_list *child; 403515516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 403615516c77SSepherosa Ziehau char name[16]; 403715516c77SSepherosa Ziehau 403815516c77SSepherosa Ziehau /* 403915516c77SSepherosa Ziehau * Create per TX ring sysctl tree: 404015516c77SSepherosa Ziehau * dev.hn.UNIT.tx.RINGID 404115516c77SSepherosa Ziehau */ 404215516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 404315516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree); 404415516c77SSepherosa Ziehau 404515516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", id); 404615516c77SSepherosa Ziehau txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, 404715516c77SSepherosa Ziehau name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 404815516c77SSepherosa Ziehau 404915516c77SSepherosa Ziehau if (txr->hn_tx_sysctl_tree != NULL) { 405015516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree); 405115516c77SSepherosa Ziehau 405285e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 405315516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail", 405415516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_txdesc_avail, 0, 405515516c77SSepherosa Ziehau "# of available TX descs"); 405685e4ae1eSSepherosa Ziehau #endif 405723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 405823bf9e15SSepherosa Ziehau if (!hn_use_if_start) 405923bf9e15SSepherosa Ziehau #endif 406023bf9e15SSepherosa Ziehau { 406115516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive", 406215516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_oactive, 0, 406315516c77SSepherosa Ziehau "over active"); 406415516c77SSepherosa Ziehau } 406515516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets", 406615516c77SSepherosa Ziehau CTLFLAG_RW, &txr->hn_pkts, 406715516c77SSepherosa Ziehau "# of packets transmitted"); 4068dc13fee6SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends", 4069dc13fee6SSepherosa Ziehau CTLFLAG_RW, &txr->hn_sends, "# of sends"); 407015516c77SSepherosa Ziehau } 407115516c77SSepherosa Ziehau } 407215516c77SSepherosa Ziehau 407315516c77SSepherosa Ziehau return 0; 407415516c77SSepherosa Ziehau } 407515516c77SSepherosa Ziehau 407615516c77SSepherosa Ziehau static void 407715516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd) 407815516c77SSepherosa Ziehau { 407915516c77SSepherosa Ziehau struct hn_tx_ring *txr = txd->txr; 408015516c77SSepherosa Ziehau 408115516c77SSepherosa Ziehau KASSERT(txd->m == NULL, ("still has mbuf installed")); 408215516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped")); 408315516c77SSepherosa Ziehau 408415516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap); 408515516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt, 408615516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 408715516c77SSepherosa Ziehau bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap); 408815516c77SSepherosa Ziehau } 408915516c77SSepherosa Ziehau 409015516c77SSepherosa Ziehau static void 409125641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd) 409225641fc7SSepherosa Ziehau { 409325641fc7SSepherosa Ziehau 409425641fc7SSepherosa Ziehau KASSERT(txd->refs == 0 || txd->refs == 1, 409525641fc7SSepherosa Ziehau ("invalid txd refs %d", txd->refs)); 409625641fc7SSepherosa Ziehau 409725641fc7SSepherosa Ziehau /* Aggregated txds will be freed by their aggregating txd. */ 409825641fc7SSepherosa Ziehau if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) { 409925641fc7SSepherosa Ziehau int freed; 410025641fc7SSepherosa Ziehau 410125641fc7SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 410225641fc7SSepherosa Ziehau KASSERT(freed, ("can't free txdesc")); 410325641fc7SSepherosa Ziehau } 410425641fc7SSepherosa Ziehau } 410525641fc7SSepherosa Ziehau 410625641fc7SSepherosa Ziehau static void 410715516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr) 410815516c77SSepherosa Ziehau { 410925641fc7SSepherosa Ziehau int i; 411015516c77SSepherosa Ziehau 411115516c77SSepherosa Ziehau if (txr->hn_txdesc == NULL) 411215516c77SSepherosa Ziehau return; 411315516c77SSepherosa Ziehau 411425641fc7SSepherosa Ziehau /* 411525641fc7SSepherosa Ziehau * NOTE: 411625641fc7SSepherosa Ziehau * Because the freeing of aggregated txds will be deferred 411725641fc7SSepherosa Ziehau * to the aggregating txd, two passes are used here: 411825641fc7SSepherosa Ziehau * - The first pass GCes any pending txds. This GC is necessary, 411925641fc7SSepherosa Ziehau * since if the channels are revoked, hypervisor will not 412025641fc7SSepherosa Ziehau * deliver send-done for all pending txds. 412125641fc7SSepherosa Ziehau * - The second pass frees the busdma stuffs, i.e. after all txds 412225641fc7SSepherosa Ziehau * were freed. 412325641fc7SSepherosa Ziehau */ 412425641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 412525641fc7SSepherosa Ziehau hn_txdesc_gc(txr, &txr->hn_txdesc[i]); 412625641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 412725641fc7SSepherosa Ziehau hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]); 412815516c77SSepherosa Ziehau 412915516c77SSepherosa Ziehau if (txr->hn_tx_data_dtag != NULL) 413015516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_data_dtag); 413115516c77SSepherosa Ziehau if (txr->hn_tx_rndis_dtag != NULL) 413215516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_rndis_dtag); 413315516c77SSepherosa Ziehau 413415516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 413515516c77SSepherosa Ziehau buf_ring_free(txr->hn_txdesc_br, M_DEVBUF); 413615516c77SSepherosa Ziehau #endif 413715516c77SSepherosa Ziehau 413815516c77SSepherosa Ziehau free(txr->hn_txdesc, M_DEVBUF); 413915516c77SSepherosa Ziehau txr->hn_txdesc = NULL; 414015516c77SSepherosa Ziehau 414115516c77SSepherosa Ziehau if (txr->hn_mbuf_br != NULL) 414215516c77SSepherosa Ziehau buf_ring_free(txr->hn_mbuf_br, M_DEVBUF); 414315516c77SSepherosa Ziehau 414415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 414515516c77SSepherosa Ziehau mtx_destroy(&txr->hn_txlist_spin); 414615516c77SSepherosa Ziehau #endif 414715516c77SSepherosa Ziehau mtx_destroy(&txr->hn_tx_lock); 414815516c77SSepherosa Ziehau } 414915516c77SSepherosa Ziehau 415015516c77SSepherosa Ziehau static int 415115516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt) 415215516c77SSepherosa Ziehau { 415315516c77SSepherosa Ziehau struct sysctl_oid_list *child; 415415516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 415515516c77SSepherosa Ziehau int i; 415615516c77SSepherosa Ziehau 415715516c77SSepherosa Ziehau /* 415815516c77SSepherosa Ziehau * Create TXBUF for chimney sending. 415915516c77SSepherosa Ziehau * 416015516c77SSepherosa Ziehau * NOTE: It is shared by all channels. 416115516c77SSepherosa Ziehau */ 416215516c77SSepherosa Ziehau sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), 416315516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma, 416415516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 416515516c77SSepherosa Ziehau if (sc->hn_chim == NULL) { 416615516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate txbuf failed\n"); 416715516c77SSepherosa Ziehau return (ENOMEM); 416815516c77SSepherosa Ziehau } 416915516c77SSepherosa Ziehau 417015516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = ring_cnt; 417115516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 417215516c77SSepherosa Ziehau 417315516c77SSepherosa Ziehau sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt, 417415516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 417515516c77SSepherosa Ziehau 417615516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(sc->hn_dev); 417715516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev)); 417815516c77SSepherosa Ziehau 417915516c77SSepherosa Ziehau /* Create dev.hn.UNIT.tx sysctl tree */ 418015516c77SSepherosa Ziehau sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx", 418115516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 418215516c77SSepherosa Ziehau 418315516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 418415516c77SSepherosa Ziehau int error; 418515516c77SSepherosa Ziehau 418615516c77SSepherosa Ziehau error = hn_tx_ring_create(sc, i); 418715516c77SSepherosa Ziehau if (error) 418815516c77SSepherosa Ziehau return error; 418915516c77SSepherosa Ziehau } 419015516c77SSepherosa Ziehau 419115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs", 419215516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 419315516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_no_txdescs), 419415516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs"); 419515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed", 419615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 419715516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_send_failed), 419815516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure"); 419915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed", 420015516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 420115516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_txdma_failed), 420215516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure"); 4203dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed", 4204dc13fee6SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 4205dc13fee6SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_flush_failed), 4206dc13fee6SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", 4207dc13fee6SSepherosa Ziehau "# of packet transmission aggregation flush failure"); 420815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed", 420915516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 421015516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_collapsed), 421115516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed"); 421215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney", 421315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 421415516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney), 421515516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send"); 421615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried", 421715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 421815516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney_tried), 421915516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries"); 422015516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt", 422115516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0, 422215516c77SSepherosa Ziehau "# of total TX descs"); 422315516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max", 422415516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_chim_szmax, 0, 422515516c77SSepherosa Ziehau "Chimney send packet size upper boundary"); 422615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size", 422715516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 422815516c77SSepherosa Ziehau hn_chim_size_sysctl, "I", "Chimney send packet size limit"); 422915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size", 423015516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 423115516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_direct_tx_size), 423215516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 423315516c77SSepherosa Ziehau "Size of the packet for direct transmission"); 423415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx", 423515516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 423615516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_sched_tx), 423715516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 423815516c77SSepherosa Ziehau "Always schedule transmission " 423915516c77SSepherosa Ziehau "instead of doing direct transmission"); 424015516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt", 424115516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings"); 424215516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse", 424315516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings"); 4244dc13fee6SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax", 4245dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0, 4246dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation size"); 4247dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax", 4248dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 4249dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl, "I", 4250dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation packets"); 4251dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align", 4252dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 4253dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl, "I", 4254dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation alignment"); 425515516c77SSepherosa Ziehau 425615516c77SSepherosa Ziehau return 0; 425715516c77SSepherosa Ziehau } 425815516c77SSepherosa Ziehau 425915516c77SSepherosa Ziehau static void 426015516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size) 426115516c77SSepherosa Ziehau { 426215516c77SSepherosa Ziehau int i; 426315516c77SSepherosa Ziehau 4264a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 426515516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_chim_size = chim_size; 426615516c77SSepherosa Ziehau } 426715516c77SSepherosa Ziehau 426815516c77SSepherosa Ziehau static void 426915516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu) 427015516c77SSepherosa Ziehau { 427115516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 427215516c77SSepherosa Ziehau int tso_minlen; 427315516c77SSepherosa Ziehau 427415516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0) 427515516c77SSepherosa Ziehau return; 427615516c77SSepherosa Ziehau 427715516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_sgmin >= 2, 427815516c77SSepherosa Ziehau ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin)); 427915516c77SSepherosa Ziehau tso_minlen = sc->hn_ndis_tso_sgmin * mtu; 428015516c77SSepherosa Ziehau 428115516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen && 428215516c77SSepherosa Ziehau sc->hn_ndis_tso_szmax <= IP_MAXPACKET, 428315516c77SSepherosa Ziehau ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax)); 428415516c77SSepherosa Ziehau 428515516c77SSepherosa Ziehau if (tso_maxlen < tso_minlen) 428615516c77SSepherosa Ziehau tso_maxlen = tso_minlen; 428715516c77SSepherosa Ziehau else if (tso_maxlen > IP_MAXPACKET) 428815516c77SSepherosa Ziehau tso_maxlen = IP_MAXPACKET; 428915516c77SSepherosa Ziehau if (tso_maxlen > sc->hn_ndis_tso_szmax) 429015516c77SSepherosa Ziehau tso_maxlen = sc->hn_ndis_tso_szmax; 429115516c77SSepherosa Ziehau ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 429215516c77SSepherosa Ziehau if (bootverbose) 429315516c77SSepherosa Ziehau if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax); 429415516c77SSepherosa Ziehau } 429515516c77SSepherosa Ziehau 429615516c77SSepherosa Ziehau static void 429715516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc) 429815516c77SSepherosa Ziehau { 429915516c77SSepherosa Ziehau uint64_t csum_assist; 430015516c77SSepherosa Ziehau int i; 430115516c77SSepherosa Ziehau 430215516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 430315516c77SSepherosa Ziehau if (hn_tx_chimney_size > 0 && 430415516c77SSepherosa Ziehau hn_tx_chimney_size < sc->hn_chim_szmax) 430515516c77SSepherosa Ziehau hn_set_chim_size(sc, hn_tx_chimney_size); 430615516c77SSepherosa Ziehau 430715516c77SSepherosa Ziehau csum_assist = 0; 430815516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_IPCS) 430915516c77SSepherosa Ziehau csum_assist |= CSUM_IP; 431015516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP4CS) 431115516c77SSepherosa Ziehau csum_assist |= CSUM_IP_TCP; 431215516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP4CS) 431315516c77SSepherosa Ziehau csum_assist |= CSUM_IP_UDP; 431415516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP6CS) 431515516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_TCP; 431615516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP6CS) 431715516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_UDP; 431815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 431915516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_csum_assist = csum_assist; 432015516c77SSepherosa Ziehau 432115516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_HASHVAL) { 432215516c77SSepherosa Ziehau /* 432315516c77SSepherosa Ziehau * Support HASHVAL pktinfo on TX path. 432415516c77SSepherosa Ziehau */ 432515516c77SSepherosa Ziehau if (bootverbose) 432615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n"); 432715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 432815516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL; 432915516c77SSepherosa Ziehau } 433015516c77SSepherosa Ziehau } 433115516c77SSepherosa Ziehau 433215516c77SSepherosa Ziehau static void 433315516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc) 433415516c77SSepherosa Ziehau { 433515516c77SSepherosa Ziehau int i; 433615516c77SSepherosa Ziehau 433715516c77SSepherosa Ziehau if (sc->hn_chim != NULL) { 43382494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) { 433915516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim); 43402494d735SSepherosa Ziehau } else { 43412494d735SSepherosa Ziehau device_printf(sc->hn_dev, 43422494d735SSepherosa Ziehau "chimney sending buffer is referenced"); 43432494d735SSepherosa Ziehau } 434415516c77SSepherosa Ziehau sc->hn_chim = NULL; 434515516c77SSepherosa Ziehau } 434615516c77SSepherosa Ziehau 434715516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt == 0) 434815516c77SSepherosa Ziehau return; 434915516c77SSepherosa Ziehau 435015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 435115516c77SSepherosa Ziehau hn_tx_ring_destroy(&sc->hn_tx_ring[i]); 435215516c77SSepherosa Ziehau 435315516c77SSepherosa Ziehau free(sc->hn_tx_ring, M_DEVBUF); 435415516c77SSepherosa Ziehau sc->hn_tx_ring = NULL; 435515516c77SSepherosa Ziehau 435615516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = 0; 435715516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = 0; 435815516c77SSepherosa Ziehau } 435915516c77SSepherosa Ziehau 436023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 436123bf9e15SSepherosa Ziehau 436215516c77SSepherosa Ziehau static void 436315516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused) 436415516c77SSepherosa Ziehau { 436515516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 436615516c77SSepherosa Ziehau 436715516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 436815516c77SSepherosa Ziehau hn_start_locked(txr, 0); 436915516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 437015516c77SSepherosa Ziehau } 437115516c77SSepherosa Ziehau 437223bf9e15SSepherosa Ziehau static int 437323bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len) 437423bf9e15SSepherosa Ziehau { 437523bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 437623bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 4377dc13fee6SSepherosa Ziehau int sched = 0; 437823bf9e15SSepherosa Ziehau 437923bf9e15SSepherosa Ziehau KASSERT(hn_use_if_start, 438023bf9e15SSepherosa Ziehau ("hn_start_locked is called, when if_start is disabled")); 438123bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 438223bf9e15SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 4383dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 438423bf9e15SSepherosa Ziehau 438523bf9e15SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 4386dc13fee6SSepherosa Ziehau return (0); 438723bf9e15SSepherosa Ziehau 438823bf9e15SSepherosa Ziehau if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 438923bf9e15SSepherosa Ziehau IFF_DRV_RUNNING) 4390dc13fee6SSepherosa Ziehau return (0); 439123bf9e15SSepherosa Ziehau 439223bf9e15SSepherosa Ziehau while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 439323bf9e15SSepherosa Ziehau struct hn_txdesc *txd; 439423bf9e15SSepherosa Ziehau struct mbuf *m_head; 439523bf9e15SSepherosa Ziehau int error; 439623bf9e15SSepherosa Ziehau 439723bf9e15SSepherosa Ziehau IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 439823bf9e15SSepherosa Ziehau if (m_head == NULL) 439923bf9e15SSepherosa Ziehau break; 440023bf9e15SSepherosa Ziehau 440123bf9e15SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 440223bf9e15SSepherosa Ziehau /* 440323bf9e15SSepherosa Ziehau * This sending could be time consuming; let callers 440423bf9e15SSepherosa Ziehau * dispatch this packet sending (and sending of any 440523bf9e15SSepherosa Ziehau * following up packets) to tx taskqueue. 440623bf9e15SSepherosa Ziehau */ 440723bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 4408dc13fee6SSepherosa Ziehau sched = 1; 4409dc13fee6SSepherosa Ziehau break; 441023bf9e15SSepherosa Ziehau } 441123bf9e15SSepherosa Ziehau 4412edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 4413edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 4414edd3f315SSepherosa Ziehau m_head = hn_tso_fixup(m_head); 4415edd3f315SSepherosa Ziehau if (__predict_false(m_head == NULL)) { 4416edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 4417edd3f315SSepherosa Ziehau continue; 4418edd3f315SSepherosa Ziehau } 4419edd3f315SSepherosa Ziehau } 4420edd3f315SSepherosa Ziehau #endif 4421edd3f315SSepherosa Ziehau 442223bf9e15SSepherosa Ziehau txd = hn_txdesc_get(txr); 442323bf9e15SSepherosa Ziehau if (txd == NULL) { 442423bf9e15SSepherosa Ziehau txr->hn_no_txdescs++; 442523bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 442623bf9e15SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 442723bf9e15SSepherosa Ziehau break; 442823bf9e15SSepherosa Ziehau } 442923bf9e15SSepherosa Ziehau 4430dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 443123bf9e15SSepherosa Ziehau if (error) { 443223bf9e15SSepherosa Ziehau /* Both txd and m_head are freed */ 4433dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 4434dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 443523bf9e15SSepherosa Ziehau continue; 443623bf9e15SSepherosa Ziehau } 443723bf9e15SSepherosa Ziehau 4438dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 4439dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 4440dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 4441dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 4442dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 4443dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 4444dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 4445dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 4446dc13fee6SSepherosa Ziehau break; 4447dc13fee6SSepherosa Ziehau } 4448dc13fee6SSepherosa Ziehau } else { 4449dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 445023bf9e15SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 445123bf9e15SSepherosa Ziehau if (__predict_false(error)) { 445223bf9e15SSepherosa Ziehau /* txd is freed, but m_head is not */ 445323bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 4454dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 4455dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 445623bf9e15SSepherosa Ziehau break; 445723bf9e15SSepherosa Ziehau } 445823bf9e15SSepherosa Ziehau } 4459dc13fee6SSepherosa Ziehau } 4460dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 4461dc13fee6SSepherosa Ziehau else { 4462dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 4463dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 4464dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 4465dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 4466dc13fee6SSepherosa Ziehau } 4467dc13fee6SSepherosa Ziehau #endif 4468dc13fee6SSepherosa Ziehau } 4469dc13fee6SSepherosa Ziehau 4470dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 4471dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 4472dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 4473dc13fee6SSepherosa Ziehau return (sched); 447423bf9e15SSepherosa Ziehau } 447523bf9e15SSepherosa Ziehau 447623bf9e15SSepherosa Ziehau static void 447723bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp) 447823bf9e15SSepherosa Ziehau { 447923bf9e15SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 448023bf9e15SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[0]; 448123bf9e15SSepherosa Ziehau 448223bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 448323bf9e15SSepherosa Ziehau goto do_sched; 448423bf9e15SSepherosa Ziehau 448523bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 448623bf9e15SSepherosa Ziehau int sched; 448723bf9e15SSepherosa Ziehau 448823bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 448923bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 449023bf9e15SSepherosa Ziehau if (!sched) 449123bf9e15SSepherosa Ziehau return; 449223bf9e15SSepherosa Ziehau } 449323bf9e15SSepherosa Ziehau do_sched: 449423bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 449523bf9e15SSepherosa Ziehau } 449623bf9e15SSepherosa Ziehau 449715516c77SSepherosa Ziehau static void 449815516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused) 449915516c77SSepherosa Ziehau { 450015516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 450115516c77SSepherosa Ziehau 450215516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 450315516c77SSepherosa Ziehau atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE); 450415516c77SSepherosa Ziehau hn_start_locked(txr, 0); 450515516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 450615516c77SSepherosa Ziehau } 450715516c77SSepherosa Ziehau 450823bf9e15SSepherosa Ziehau static void 450923bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr) 451023bf9e15SSepherosa Ziehau { 451123bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 451223bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 451323bf9e15SSepherosa Ziehau 451423bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 451523bf9e15SSepherosa Ziehau 451623bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 451723bf9e15SSepherosa Ziehau goto do_sched; 451823bf9e15SSepherosa Ziehau 451923bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 452023bf9e15SSepherosa Ziehau int sched; 452123bf9e15SSepherosa Ziehau 452223bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 452323bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 452423bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 452523bf9e15SSepherosa Ziehau if (sched) { 452623bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 452723bf9e15SSepherosa Ziehau &txr->hn_tx_task); 452823bf9e15SSepherosa Ziehau } 452923bf9e15SSepherosa Ziehau } else { 453023bf9e15SSepherosa Ziehau do_sched: 453123bf9e15SSepherosa Ziehau /* 453223bf9e15SSepherosa Ziehau * Release the OACTIVE earlier, with the hope, that 453323bf9e15SSepherosa Ziehau * others could catch up. The task will clear the 453423bf9e15SSepherosa Ziehau * flag again with the hn_tx_lock to avoid possible 453523bf9e15SSepherosa Ziehau * races. 453623bf9e15SSepherosa Ziehau */ 453723bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 453823bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 453923bf9e15SSepherosa Ziehau } 454023bf9e15SSepherosa Ziehau } 454123bf9e15SSepherosa Ziehau 454223bf9e15SSepherosa Ziehau #endif /* HN_IFSTART_SUPPORT */ 454323bf9e15SSepherosa Ziehau 454415516c77SSepherosa Ziehau static int 454515516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len) 454615516c77SSepherosa Ziehau { 454715516c77SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 454815516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 454915516c77SSepherosa Ziehau struct mbuf *m_head; 4550dc13fee6SSepherosa Ziehau int sched = 0; 455115516c77SSepherosa Ziehau 455215516c77SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 455323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 455415516c77SSepherosa Ziehau KASSERT(hn_use_if_start == 0, 455515516c77SSepherosa Ziehau ("hn_xmit is called, when if_start is enabled")); 455623bf9e15SSepherosa Ziehau #endif 4557dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 455815516c77SSepherosa Ziehau 455915516c77SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 4560dc13fee6SSepherosa Ziehau return (0); 456115516c77SSepherosa Ziehau 456215516c77SSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive) 4563dc13fee6SSepherosa Ziehau return (0); 456415516c77SSepherosa Ziehau 456515516c77SSepherosa Ziehau while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) { 456615516c77SSepherosa Ziehau struct hn_txdesc *txd; 456715516c77SSepherosa Ziehau int error; 456815516c77SSepherosa Ziehau 456915516c77SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 457015516c77SSepherosa Ziehau /* 457115516c77SSepherosa Ziehau * This sending could be time consuming; let callers 457215516c77SSepherosa Ziehau * dispatch this packet sending (and sending of any 457315516c77SSepherosa Ziehau * following up packets) to tx taskqueue. 457415516c77SSepherosa Ziehau */ 457515516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 4576dc13fee6SSepherosa Ziehau sched = 1; 4577dc13fee6SSepherosa Ziehau break; 457815516c77SSepherosa Ziehau } 457915516c77SSepherosa Ziehau 458015516c77SSepherosa Ziehau txd = hn_txdesc_get(txr); 458115516c77SSepherosa Ziehau if (txd == NULL) { 458215516c77SSepherosa Ziehau txr->hn_no_txdescs++; 458315516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 458415516c77SSepherosa Ziehau txr->hn_oactive = 1; 458515516c77SSepherosa Ziehau break; 458615516c77SSepherosa Ziehau } 458715516c77SSepherosa Ziehau 4588dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 458915516c77SSepherosa Ziehau if (error) { 459015516c77SSepherosa Ziehau /* Both txd and m_head are freed; discard */ 4591dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 4592dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 459315516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 459415516c77SSepherosa Ziehau continue; 459515516c77SSepherosa Ziehau } 459615516c77SSepherosa Ziehau 4597dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 4598dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 4599dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 4600dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 4601dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 460215516c77SSepherosa Ziehau if (__predict_false(error)) { 460315516c77SSepherosa Ziehau txr->hn_oactive = 1; 460415516c77SSepherosa Ziehau break; 460515516c77SSepherosa Ziehau } 4606dc13fee6SSepherosa Ziehau } else { 4607dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 4608dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 4609dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 4610dc13fee6SSepherosa Ziehau /* txd is freed, but m_head is not */ 4611dc13fee6SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, 4612dc13fee6SSepherosa Ziehau m_head); 4613dc13fee6SSepherosa Ziehau txr->hn_oactive = 1; 4614dc13fee6SSepherosa Ziehau break; 4615dc13fee6SSepherosa Ziehau } 4616dc13fee6SSepherosa Ziehau } 4617dc13fee6SSepherosa Ziehau } 4618dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 4619dc13fee6SSepherosa Ziehau else { 4620dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 4621dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 4622dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 4623dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 4624dc13fee6SSepherosa Ziehau } 4625dc13fee6SSepherosa Ziehau #endif 462615516c77SSepherosa Ziehau 462715516c77SSepherosa Ziehau /* Sent */ 462815516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 462915516c77SSepherosa Ziehau } 4630dc13fee6SSepherosa Ziehau 4631dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 4632dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 4633dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 4634dc13fee6SSepherosa Ziehau return (sched); 463515516c77SSepherosa Ziehau } 463615516c77SSepherosa Ziehau 463715516c77SSepherosa Ziehau static int 463815516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m) 463915516c77SSepherosa Ziehau { 464015516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 464115516c77SSepherosa Ziehau struct hn_tx_ring *txr; 464215516c77SSepherosa Ziehau int error, idx = 0; 464315516c77SSepherosa Ziehau 4644edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 4645edd3f315SSepherosa Ziehau /* 4646edd3f315SSepherosa Ziehau * Perform TSO packet header fixup now, since the TSO 4647edd3f315SSepherosa Ziehau * packet header should be cache-hot. 4648edd3f315SSepherosa Ziehau */ 4649edd3f315SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 4650edd3f315SSepherosa Ziehau m = hn_tso_fixup(m); 4651edd3f315SSepherosa Ziehau if (__predict_false(m == NULL)) { 4652edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 4653edd3f315SSepherosa Ziehau return EIO; 4654edd3f315SSepherosa Ziehau } 4655edd3f315SSepherosa Ziehau } 4656edd3f315SSepherosa Ziehau #endif 4657edd3f315SSepherosa Ziehau 465815516c77SSepherosa Ziehau /* 465915516c77SSepherosa Ziehau * Select the TX ring based on flowid 466015516c77SSepherosa Ziehau */ 466134d68912SSepherosa Ziehau if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 466234d68912SSepherosa Ziehau #ifdef RSS 466334d68912SSepherosa Ziehau uint32_t bid; 466434d68912SSepherosa Ziehau 466534d68912SSepherosa Ziehau if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m), 466634d68912SSepherosa Ziehau &bid) == 0) 466734d68912SSepherosa Ziehau idx = bid % sc->hn_tx_ring_inuse; 466834d68912SSepherosa Ziehau else 466934d68912SSepherosa Ziehau #endif 4670cc0c6ebcSSepherosa Ziehau { 4671cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET) 4672cc0c6ebcSSepherosa Ziehau int tcpsyn = 0; 4673cc0c6ebcSSepherosa Ziehau 4674cc0c6ebcSSepherosa Ziehau if (m->m_pkthdr.len < 128 && 4675cc0c6ebcSSepherosa Ziehau (m->m_pkthdr.csum_flags & 4676cc0c6ebcSSepherosa Ziehau (CSUM_IP_TCP | CSUM_IP6_TCP)) && 4677cc0c6ebcSSepherosa Ziehau (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) { 4678cc0c6ebcSSepherosa Ziehau m = hn_check_tcpsyn(m, &tcpsyn); 4679cc0c6ebcSSepherosa Ziehau if (__predict_false(m == NULL)) { 4680cc0c6ebcSSepherosa Ziehau if_inc_counter(ifp, 4681cc0c6ebcSSepherosa Ziehau IFCOUNTER_OERRORS, 1); 4682cc0c6ebcSSepherosa Ziehau return (EIO); 4683cc0c6ebcSSepherosa Ziehau } 4684cc0c6ebcSSepherosa Ziehau } 4685cc0c6ebcSSepherosa Ziehau #else 4686cc0c6ebcSSepherosa Ziehau const int tcpsyn = 0; 4687cc0c6ebcSSepherosa Ziehau #endif 4688cc0c6ebcSSepherosa Ziehau if (tcpsyn) 4689cc0c6ebcSSepherosa Ziehau idx = 0; 4690cc0c6ebcSSepherosa Ziehau else 469115516c77SSepherosa Ziehau idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse; 469234d68912SSepherosa Ziehau } 4693cc0c6ebcSSepherosa Ziehau } 469415516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 469515516c77SSepherosa Ziehau 469615516c77SSepherosa Ziehau error = drbr_enqueue(ifp, txr->hn_mbuf_br, m); 469715516c77SSepherosa Ziehau if (error) { 469815516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 469915516c77SSepherosa Ziehau return error; 470015516c77SSepherosa Ziehau } 470115516c77SSepherosa Ziehau 470215516c77SSepherosa Ziehau if (txr->hn_oactive) 470315516c77SSepherosa Ziehau return 0; 470415516c77SSepherosa Ziehau 470515516c77SSepherosa Ziehau if (txr->hn_sched_tx) 470615516c77SSepherosa Ziehau goto do_sched; 470715516c77SSepherosa Ziehau 470815516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 470915516c77SSepherosa Ziehau int sched; 471015516c77SSepherosa Ziehau 471115516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 471215516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 471315516c77SSepherosa Ziehau if (!sched) 471415516c77SSepherosa Ziehau return 0; 471515516c77SSepherosa Ziehau } 471615516c77SSepherosa Ziehau do_sched: 471715516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 471815516c77SSepherosa Ziehau return 0; 471915516c77SSepherosa Ziehau } 472015516c77SSepherosa Ziehau 472115516c77SSepherosa Ziehau static void 472215516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr) 472315516c77SSepherosa Ziehau { 472415516c77SSepherosa Ziehau struct mbuf *m; 472515516c77SSepherosa Ziehau 472615516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 472715516c77SSepherosa Ziehau while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL) 472815516c77SSepherosa Ziehau m_freem(m); 472915516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 473015516c77SSepherosa Ziehau } 473115516c77SSepherosa Ziehau 473215516c77SSepherosa Ziehau static void 473315516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp) 473415516c77SSepherosa Ziehau { 473515516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 473615516c77SSepherosa Ziehau int i; 473715516c77SSepherosa Ziehau 473815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 473915516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 474015516c77SSepherosa Ziehau if_qflush(ifp); 474115516c77SSepherosa Ziehau } 474215516c77SSepherosa Ziehau 474315516c77SSepherosa Ziehau static void 474415516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr) 474515516c77SSepherosa Ziehau { 474615516c77SSepherosa Ziehau 474715516c77SSepherosa Ziehau if (txr->hn_sched_tx) 474815516c77SSepherosa Ziehau goto do_sched; 474915516c77SSepherosa Ziehau 475015516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 475115516c77SSepherosa Ziehau int sched; 475215516c77SSepherosa Ziehau 475315516c77SSepherosa Ziehau txr->hn_oactive = 0; 475415516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 475515516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 475615516c77SSepherosa Ziehau if (sched) { 475715516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 475815516c77SSepherosa Ziehau &txr->hn_tx_task); 475915516c77SSepherosa Ziehau } 476015516c77SSepherosa Ziehau } else { 476115516c77SSepherosa Ziehau do_sched: 476215516c77SSepherosa Ziehau /* 476315516c77SSepherosa Ziehau * Release the oactive earlier, with the hope, that 476415516c77SSepherosa Ziehau * others could catch up. The task will clear the 476515516c77SSepherosa Ziehau * oactive again with the hn_tx_lock to avoid possible 476615516c77SSepherosa Ziehau * races. 476715516c77SSepherosa Ziehau */ 476815516c77SSepherosa Ziehau txr->hn_oactive = 0; 476915516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 477015516c77SSepherosa Ziehau } 477115516c77SSepherosa Ziehau } 477215516c77SSepherosa Ziehau 477315516c77SSepherosa Ziehau static void 477415516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused) 477515516c77SSepherosa Ziehau { 477615516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 477715516c77SSepherosa Ziehau 477815516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 477915516c77SSepherosa Ziehau hn_xmit(txr, 0); 478015516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 478115516c77SSepherosa Ziehau } 478215516c77SSepherosa Ziehau 478315516c77SSepherosa Ziehau static void 478415516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused) 478515516c77SSepherosa Ziehau { 478615516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 478715516c77SSepherosa Ziehau 478815516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 478915516c77SSepherosa Ziehau txr->hn_oactive = 0; 479015516c77SSepherosa Ziehau hn_xmit(txr, 0); 479115516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 479215516c77SSepherosa Ziehau } 479315516c77SSepherosa Ziehau 479415516c77SSepherosa Ziehau static int 479515516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan) 479615516c77SSepherosa Ziehau { 479715516c77SSepherosa Ziehau struct vmbus_chan_br cbr; 479815516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 479915516c77SSepherosa Ziehau struct hn_tx_ring *txr = NULL; 480015516c77SSepherosa Ziehau int idx, error; 480115516c77SSepherosa Ziehau 480215516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 480315516c77SSepherosa Ziehau 480415516c77SSepherosa Ziehau /* 480515516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 480615516c77SSepherosa Ziehau */ 480715516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 480815516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 480915516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 481015516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 481115516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0, 481215516c77SSepherosa Ziehau ("RX ring %d already attached", idx)); 481315516c77SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED; 48143ab0fea1SDexuan Cui rxr->hn_chan = chan; 481515516c77SSepherosa Ziehau 481615516c77SSepherosa Ziehau if (bootverbose) { 481715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n", 481815516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 481915516c77SSepherosa Ziehau } 482015516c77SSepherosa Ziehau 482115516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 482215516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 482315516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0, 482415516c77SSepherosa Ziehau ("TX ring %d already attached", idx)); 482515516c77SSepherosa Ziehau txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED; 482615516c77SSepherosa Ziehau 482715516c77SSepherosa Ziehau txr->hn_chan = chan; 482815516c77SSepherosa Ziehau if (bootverbose) { 482915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n", 483015516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 483115516c77SSepherosa Ziehau } 483215516c77SSepherosa Ziehau } 483315516c77SSepherosa Ziehau 483415516c77SSepherosa Ziehau /* Bind this channel to a proper CPU. */ 48350e11868dSSepherosa Ziehau vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx)); 483615516c77SSepherosa Ziehau 483715516c77SSepherosa Ziehau /* 483815516c77SSepherosa Ziehau * Open this channel 483915516c77SSepherosa Ziehau */ 484015516c77SSepherosa Ziehau cbr.cbr = rxr->hn_br; 484115516c77SSepherosa Ziehau cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr; 484215516c77SSepherosa Ziehau cbr.cbr_txsz = HN_TXBR_SIZE; 484315516c77SSepherosa Ziehau cbr.cbr_rxsz = HN_RXBR_SIZE; 484415516c77SSepherosa Ziehau error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr); 484515516c77SSepherosa Ziehau if (error) { 484671e8ac56SSepherosa Ziehau if (error == EISCONN) { 484771e8ac56SSepherosa Ziehau if_printf(sc->hn_ifp, "bufring is connected after " 484871e8ac56SSepherosa Ziehau "chan%u open failure\n", vmbus_chan_id(chan)); 484971e8ac56SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 485071e8ac56SSepherosa Ziehau } else { 485115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "open chan%u failed: %d\n", 485215516c77SSepherosa Ziehau vmbus_chan_id(chan), error); 485371e8ac56SSepherosa Ziehau } 485415516c77SSepherosa Ziehau } 485515516c77SSepherosa Ziehau return (error); 485615516c77SSepherosa Ziehau } 485715516c77SSepherosa Ziehau 485815516c77SSepherosa Ziehau static void 485915516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan) 486015516c77SSepherosa Ziehau { 486115516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 48622494d735SSepherosa Ziehau int idx, error; 486315516c77SSepherosa Ziehau 486415516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 486515516c77SSepherosa Ziehau 486615516c77SSepherosa Ziehau /* 486715516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 486815516c77SSepherosa Ziehau */ 486915516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 487015516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 487115516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 487215516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 487315516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED), 487415516c77SSepherosa Ziehau ("RX ring %d is not attached", idx)); 487515516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 487615516c77SSepherosa Ziehau 487715516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 487815516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[idx]; 487915516c77SSepherosa Ziehau 488015516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED), 488115516c77SSepherosa Ziehau ("TX ring %d is not attached attached", idx)); 488215516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 488315516c77SSepherosa Ziehau } 488415516c77SSepherosa Ziehau 488515516c77SSepherosa Ziehau /* 488615516c77SSepherosa Ziehau * Close this channel. 488715516c77SSepherosa Ziehau * 488815516c77SSepherosa Ziehau * NOTE: 488915516c77SSepherosa Ziehau * Channel closing does _not_ destroy the target channel. 489015516c77SSepherosa Ziehau */ 48912494d735SSepherosa Ziehau error = vmbus_chan_close_direct(chan); 48922494d735SSepherosa Ziehau if (error == EISCONN) { 4893aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u bufring is connected " 4894aa1a2adcSSepherosa Ziehau "after being closed\n", vmbus_chan_id(chan)); 48952494d735SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 48962494d735SSepherosa Ziehau } else if (error) { 4897aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u close failed: %d\n", 4898aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), error); 48992494d735SSepherosa Ziehau } 490015516c77SSepherosa Ziehau } 490115516c77SSepherosa Ziehau 490215516c77SSepherosa Ziehau static int 490315516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc) 490415516c77SSepherosa Ziehau { 490515516c77SSepherosa Ziehau struct vmbus_channel **subchans; 490615516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 490715516c77SSepherosa Ziehau int i, error = 0; 490815516c77SSepherosa Ziehau 490971e8ac56SSepherosa Ziehau KASSERT(subchan_cnt > 0, ("no sub-channels")); 491015516c77SSepherosa Ziehau 491115516c77SSepherosa Ziehau /* Attach the sub-channels. */ 491215516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 491315516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) { 491471e8ac56SSepherosa Ziehau int error1; 491571e8ac56SSepherosa Ziehau 491671e8ac56SSepherosa Ziehau error1 = hn_chan_attach(sc, subchans[i]); 491771e8ac56SSepherosa Ziehau if (error1) { 491871e8ac56SSepherosa Ziehau error = error1; 491971e8ac56SSepherosa Ziehau /* Move on; all channels will be detached later. */ 492071e8ac56SSepherosa Ziehau } 492115516c77SSepherosa Ziehau } 492215516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 492315516c77SSepherosa Ziehau 492415516c77SSepherosa Ziehau if (error) { 492515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error); 492615516c77SSepherosa Ziehau } else { 492715516c77SSepherosa Ziehau if (bootverbose) { 492815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d sub-channels attached\n", 492915516c77SSepherosa Ziehau subchan_cnt); 493015516c77SSepherosa Ziehau } 493115516c77SSepherosa Ziehau } 493215516c77SSepherosa Ziehau return (error); 493315516c77SSepherosa Ziehau } 493415516c77SSepherosa Ziehau 493515516c77SSepherosa Ziehau static void 493615516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc) 493715516c77SSepherosa Ziehau { 493815516c77SSepherosa Ziehau struct vmbus_channel **subchans; 493915516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 494015516c77SSepherosa Ziehau int i; 494115516c77SSepherosa Ziehau 494215516c77SSepherosa Ziehau if (subchan_cnt == 0) 494315516c77SSepherosa Ziehau goto back; 494415516c77SSepherosa Ziehau 494515516c77SSepherosa Ziehau /* Detach the sub-channels. */ 494615516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 494715516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) 494815516c77SSepherosa Ziehau hn_chan_detach(sc, subchans[i]); 494915516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 495015516c77SSepherosa Ziehau 495115516c77SSepherosa Ziehau back: 495215516c77SSepherosa Ziehau /* 495315516c77SSepherosa Ziehau * Detach the primary channel, _after_ all sub-channels 495415516c77SSepherosa Ziehau * are detached. 495515516c77SSepherosa Ziehau */ 495615516c77SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 495715516c77SSepherosa Ziehau 495815516c77SSepherosa Ziehau /* Wait for sub-channels to be destroyed, if any. */ 495915516c77SSepherosa Ziehau vmbus_subchan_drain(sc->hn_prichan); 496015516c77SSepherosa Ziehau 496115516c77SSepherosa Ziehau #ifdef INVARIANTS 496215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 496315516c77SSepherosa Ziehau KASSERT((sc->hn_rx_ring[i].hn_rx_flags & 496415516c77SSepherosa Ziehau HN_RX_FLAG_ATTACHED) == 0, 496515516c77SSepherosa Ziehau ("%dth RX ring is still attached", i)); 496615516c77SSepherosa Ziehau } 496715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 496815516c77SSepherosa Ziehau KASSERT((sc->hn_tx_ring[i].hn_tx_flags & 496915516c77SSepherosa Ziehau HN_TX_FLAG_ATTACHED) == 0, 497015516c77SSepherosa Ziehau ("%dth TX ring is still attached", i)); 497115516c77SSepherosa Ziehau } 497215516c77SSepherosa Ziehau #endif 497315516c77SSepherosa Ziehau } 497415516c77SSepherosa Ziehau 497515516c77SSepherosa Ziehau static int 497615516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch) 497715516c77SSepherosa Ziehau { 497815516c77SSepherosa Ziehau struct vmbus_channel **subchans; 497915516c77SSepherosa Ziehau int nchan, rxr_cnt, error; 498015516c77SSepherosa Ziehau 498115516c77SSepherosa Ziehau nchan = *nsubch + 1; 498215516c77SSepherosa Ziehau if (nchan == 1) { 498315516c77SSepherosa Ziehau /* 498415516c77SSepherosa Ziehau * Multiple RX/TX rings are not requested. 498515516c77SSepherosa Ziehau */ 498615516c77SSepherosa Ziehau *nsubch = 0; 498715516c77SSepherosa Ziehau return (0); 498815516c77SSepherosa Ziehau } 498915516c77SSepherosa Ziehau 499015516c77SSepherosa Ziehau /* 499115516c77SSepherosa Ziehau * Query RSS capabilities, e.g. # of RX rings, and # of indirect 499215516c77SSepherosa Ziehau * table entries. 499315516c77SSepherosa Ziehau */ 499415516c77SSepherosa Ziehau error = hn_rndis_query_rsscaps(sc, &rxr_cnt); 499515516c77SSepherosa Ziehau if (error) { 499615516c77SSepherosa Ziehau /* No RSS; this is benign. */ 499715516c77SSepherosa Ziehau *nsubch = 0; 499815516c77SSepherosa Ziehau return (0); 499915516c77SSepherosa Ziehau } 500015516c77SSepherosa Ziehau if (bootverbose) { 500115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n", 500215516c77SSepherosa Ziehau rxr_cnt, nchan); 500315516c77SSepherosa Ziehau } 500415516c77SSepherosa Ziehau 500515516c77SSepherosa Ziehau if (nchan > rxr_cnt) 500615516c77SSepherosa Ziehau nchan = rxr_cnt; 500715516c77SSepherosa Ziehau if (nchan == 1) { 500815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n"); 500915516c77SSepherosa Ziehau *nsubch = 0; 501015516c77SSepherosa Ziehau return (0); 501115516c77SSepherosa Ziehau } 501215516c77SSepherosa Ziehau 501315516c77SSepherosa Ziehau /* 501415516c77SSepherosa Ziehau * Allocate sub-channels from NVS. 501515516c77SSepherosa Ziehau */ 501615516c77SSepherosa Ziehau *nsubch = nchan - 1; 501715516c77SSepherosa Ziehau error = hn_nvs_alloc_subchans(sc, nsubch); 501815516c77SSepherosa Ziehau if (error || *nsubch == 0) { 501915516c77SSepherosa Ziehau /* Failed to allocate sub-channels. */ 502015516c77SSepherosa Ziehau *nsubch = 0; 502115516c77SSepherosa Ziehau return (0); 502215516c77SSepherosa Ziehau } 502315516c77SSepherosa Ziehau 502415516c77SSepherosa Ziehau /* 502515516c77SSepherosa Ziehau * Wait for all sub-channels to become ready before moving on. 502615516c77SSepherosa Ziehau */ 502715516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch); 502815516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, *nsubch); 502915516c77SSepherosa Ziehau return (0); 503015516c77SSepherosa Ziehau } 503115516c77SSepherosa Ziehau 50322494d735SSepherosa Ziehau static bool 50332494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc) 50342494d735SSepherosa Ziehau { 50352494d735SSepherosa Ziehau int i; 50362494d735SSepherosa Ziehau 50372494d735SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_ERRORS) 50382494d735SSepherosa Ziehau return (false); 50392494d735SSepherosa Ziehau 50402494d735SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 50412494d735SSepherosa Ziehau const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 50422494d735SSepherosa Ziehau 50432494d735SSepherosa Ziehau if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) 50442494d735SSepherosa Ziehau return (false); 50452494d735SSepherosa Ziehau } 50462494d735SSepherosa Ziehau return (true); 50472494d735SSepherosa Ziehau } 50482494d735SSepherosa Ziehau 5049b3b75d9cSSepherosa Ziehau /* 5050b3b75d9cSSepherosa Ziehau * Make sure that the RX filter is zero after the successful 5051b3b75d9cSSepherosa Ziehau * RNDIS initialization. 5052b3b75d9cSSepherosa Ziehau * 5053b3b75d9cSSepherosa Ziehau * NOTE: 5054b3b75d9cSSepherosa Ziehau * Under certain conditions on certain versions of Hyper-V, 5055b3b75d9cSSepherosa Ziehau * the RNDIS rxfilter is _not_ zero on the hypervisor side 5056b3b75d9cSSepherosa Ziehau * after the successful RNDIS initialization, which breaks 5057b3b75d9cSSepherosa Ziehau * the assumption of any following code (well, it breaks the 5058b3b75d9cSSepherosa Ziehau * RNDIS API contract actually). Clear the RNDIS rxfilter 5059b3b75d9cSSepherosa Ziehau * explicitly, drain packets sneaking through, and drain the 5060b3b75d9cSSepherosa Ziehau * interrupt taskqueues scheduled due to the stealth packets. 5061b3b75d9cSSepherosa Ziehau */ 5062b3b75d9cSSepherosa Ziehau static void 5063b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan) 5064b3b75d9cSSepherosa Ziehau { 5065b3b75d9cSSepherosa Ziehau 5066b3b75d9cSSepherosa Ziehau hn_disable_rx(sc); 5067b3b75d9cSSepherosa Ziehau hn_drain_rxtx(sc, nchan); 5068b3b75d9cSSepherosa Ziehau } 5069b3b75d9cSSepherosa Ziehau 507015516c77SSepherosa Ziehau static int 507115516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu) 507215516c77SSepherosa Ziehau { 507371e8ac56SSepherosa Ziehau #define ATTACHED_NVS 0x0002 507471e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS 0x0004 507571e8ac56SSepherosa Ziehau 507615516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 5077b3b75d9cSSepherosa Ziehau int error, nsubch, nchan = 1, i, rndis_inited; 507871e8ac56SSepherosa Ziehau uint32_t old_caps, attached = 0; 507915516c77SSepherosa Ziehau 508015516c77SSepherosa Ziehau KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0, 508115516c77SSepherosa Ziehau ("synthetic parts were attached")); 508215516c77SSepherosa Ziehau 50832494d735SSepherosa Ziehau if (!hn_synth_attachable(sc)) 50842494d735SSepherosa Ziehau return (ENXIO); 50852494d735SSepherosa Ziehau 508615516c77SSepherosa Ziehau /* Save capabilities for later verification. */ 508715516c77SSepherosa Ziehau old_caps = sc->hn_caps; 508815516c77SSepherosa Ziehau sc->hn_caps = 0; 508915516c77SSepherosa Ziehau 509015516c77SSepherosa Ziehau /* Clear RSS stuffs. */ 509115516c77SSepherosa Ziehau sc->hn_rss_ind_size = 0; 509215516c77SSepherosa Ziehau sc->hn_rss_hash = 0; 509315516c77SSepherosa Ziehau 509415516c77SSepherosa Ziehau /* 509515516c77SSepherosa Ziehau * Attach the primary channel _before_ attaching NVS and RNDIS. 509615516c77SSepherosa Ziehau */ 509715516c77SSepherosa Ziehau error = hn_chan_attach(sc, sc->hn_prichan); 509815516c77SSepherosa Ziehau if (error) 509971e8ac56SSepherosa Ziehau goto failed; 510015516c77SSepherosa Ziehau 510115516c77SSepherosa Ziehau /* 510215516c77SSepherosa Ziehau * Attach NVS. 510315516c77SSepherosa Ziehau */ 510415516c77SSepherosa Ziehau error = hn_nvs_attach(sc, mtu); 510515516c77SSepherosa Ziehau if (error) 510671e8ac56SSepherosa Ziehau goto failed; 510771e8ac56SSepherosa Ziehau attached |= ATTACHED_NVS; 510815516c77SSepherosa Ziehau 510915516c77SSepherosa Ziehau /* 511015516c77SSepherosa Ziehau * Attach RNDIS _after_ NVS is attached. 511115516c77SSepherosa Ziehau */ 5112b3b75d9cSSepherosa Ziehau error = hn_rndis_attach(sc, mtu, &rndis_inited); 5113b3b75d9cSSepherosa Ziehau if (rndis_inited) 5114b3b75d9cSSepherosa Ziehau attached |= ATTACHED_RNDIS; 511515516c77SSepherosa Ziehau if (error) 511671e8ac56SSepherosa Ziehau goto failed; 511715516c77SSepherosa Ziehau 511815516c77SSepherosa Ziehau /* 511915516c77SSepherosa Ziehau * Make sure capabilities are not changed. 512015516c77SSepherosa Ziehau */ 512115516c77SSepherosa Ziehau if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) { 512215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n", 512315516c77SSepherosa Ziehau old_caps, sc->hn_caps); 512471e8ac56SSepherosa Ziehau error = ENXIO; 512571e8ac56SSepherosa Ziehau goto failed; 512615516c77SSepherosa Ziehau } 512715516c77SSepherosa Ziehau 512815516c77SSepherosa Ziehau /* 512915516c77SSepherosa Ziehau * Allocate sub-channels for multi-TX/RX rings. 513015516c77SSepherosa Ziehau * 513115516c77SSepherosa Ziehau * NOTE: 513215516c77SSepherosa Ziehau * The # of RX rings that can be used is equivalent to the # of 513315516c77SSepherosa Ziehau * channels to be requested. 513415516c77SSepherosa Ziehau */ 513515516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_cnt - 1; 513615516c77SSepherosa Ziehau error = hn_synth_alloc_subchans(sc, &nsubch); 513715516c77SSepherosa Ziehau if (error) 513871e8ac56SSepherosa Ziehau goto failed; 513971e8ac56SSepherosa Ziehau /* NOTE: _Full_ synthetic parts detach is required now. */ 514071e8ac56SSepherosa Ziehau sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED; 514115516c77SSepherosa Ziehau 514271e8ac56SSepherosa Ziehau /* 514371e8ac56SSepherosa Ziehau * Set the # of TX/RX rings that could be used according to 514471e8ac56SSepherosa Ziehau * the # of channels that NVS offered. 514571e8ac56SSepherosa Ziehau */ 514615516c77SSepherosa Ziehau nchan = nsubch + 1; 514771e8ac56SSepherosa Ziehau hn_set_ring_inuse(sc, nchan); 514815516c77SSepherosa Ziehau if (nchan == 1) { 514915516c77SSepherosa Ziehau /* Only the primary channel can be used; done */ 515015516c77SSepherosa Ziehau goto back; 515115516c77SSepherosa Ziehau } 515215516c77SSepherosa Ziehau 515315516c77SSepherosa Ziehau /* 515471e8ac56SSepherosa Ziehau * Attach the sub-channels. 5155afd4971bSSepherosa Ziehau * 5156afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 515715516c77SSepherosa Ziehau */ 515871e8ac56SSepherosa Ziehau error = hn_attach_subchans(sc); 515971e8ac56SSepherosa Ziehau if (error) 516071e8ac56SSepherosa Ziehau goto failed; 516115516c77SSepherosa Ziehau 516271e8ac56SSepherosa Ziehau /* 516371e8ac56SSepherosa Ziehau * Configure RSS key and indirect table _after_ all sub-channels 516471e8ac56SSepherosa Ziehau * are attached. 516571e8ac56SSepherosa Ziehau */ 516615516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) { 516715516c77SSepherosa Ziehau /* 516815516c77SSepherosa Ziehau * RSS key is not set yet; set it to the default RSS key. 516915516c77SSepherosa Ziehau */ 517015516c77SSepherosa Ziehau if (bootverbose) 517115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS key\n"); 517234d68912SSepherosa Ziehau #ifdef RSS 517334d68912SSepherosa Ziehau rss_getkey(rss->rss_key); 517434d68912SSepherosa Ziehau #else 517515516c77SSepherosa Ziehau memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key)); 517634d68912SSepherosa Ziehau #endif 517715516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 517815516c77SSepherosa Ziehau } 517915516c77SSepherosa Ziehau 518015516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) { 518115516c77SSepherosa Ziehau /* 518215516c77SSepherosa Ziehau * RSS indirect table is not set yet; set it up in round- 518315516c77SSepherosa Ziehau * robin fashion. 518415516c77SSepherosa Ziehau */ 518515516c77SSepherosa Ziehau if (bootverbose) { 518615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS indirect " 518715516c77SSepherosa Ziehau "table\n"); 518815516c77SSepherosa Ziehau } 518934d68912SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 519034d68912SSepherosa Ziehau uint32_t subidx; 519134d68912SSepherosa Ziehau 519234d68912SSepherosa Ziehau #ifdef RSS 519334d68912SSepherosa Ziehau subidx = rss_get_indirection_to_bucket(i); 519434d68912SSepherosa Ziehau #else 519534d68912SSepherosa Ziehau subidx = i; 519634d68912SSepherosa Ziehau #endif 519734d68912SSepherosa Ziehau rss->rss_ind[i] = subidx % nchan; 519834d68912SSepherosa Ziehau } 519915516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 520015516c77SSepherosa Ziehau } else { 520115516c77SSepherosa Ziehau /* 520215516c77SSepherosa Ziehau * # of usable channels may be changed, so we have to 520315516c77SSepherosa Ziehau * make sure that all entries in RSS indirect table 520415516c77SSepherosa Ziehau * are valid. 5205afd4971bSSepherosa Ziehau * 5206afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 520715516c77SSepherosa Ziehau */ 5208afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 520915516c77SSepherosa Ziehau } 521015516c77SSepherosa Ziehau 521115516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 521215516c77SSepherosa Ziehau if (error) 521371e8ac56SSepherosa Ziehau goto failed; 521471e8ac56SSepherosa Ziehau back: 5215dc13fee6SSepherosa Ziehau /* 5216dc13fee6SSepherosa Ziehau * Fixup transmission aggregation setup. 5217dc13fee6SSepherosa Ziehau */ 5218dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 5219b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 522015516c77SSepherosa Ziehau return (0); 522171e8ac56SSepherosa Ziehau 522271e8ac56SSepherosa Ziehau failed: 522371e8ac56SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 5224b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 522571e8ac56SSepherosa Ziehau hn_synth_detach(sc); 522671e8ac56SSepherosa Ziehau } else { 5227b3b75d9cSSepherosa Ziehau if (attached & ATTACHED_RNDIS) { 5228b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 522971e8ac56SSepherosa Ziehau hn_rndis_detach(sc); 5230b3b75d9cSSepherosa Ziehau } 523171e8ac56SSepherosa Ziehau if (attached & ATTACHED_NVS) 523271e8ac56SSepherosa Ziehau hn_nvs_detach(sc); 523371e8ac56SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 523471e8ac56SSepherosa Ziehau /* Restore old capabilities. */ 523571e8ac56SSepherosa Ziehau sc->hn_caps = old_caps; 523671e8ac56SSepherosa Ziehau } 523771e8ac56SSepherosa Ziehau return (error); 523871e8ac56SSepherosa Ziehau 523971e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS 524071e8ac56SSepherosa Ziehau #undef ATTACHED_NVS 524115516c77SSepherosa Ziehau } 524215516c77SSepherosa Ziehau 524315516c77SSepherosa Ziehau /* 524415516c77SSepherosa Ziehau * NOTE: 524515516c77SSepherosa Ziehau * The interface must have been suspended though hn_suspend(), before 524615516c77SSepherosa Ziehau * this function get called. 524715516c77SSepherosa Ziehau */ 524815516c77SSepherosa Ziehau static void 524915516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc) 525015516c77SSepherosa Ziehau { 525115516c77SSepherosa Ziehau 525215516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 525315516c77SSepherosa Ziehau ("synthetic parts were not attached")); 525415516c77SSepherosa Ziehau 525515516c77SSepherosa Ziehau /* Detach the RNDIS first. */ 525615516c77SSepherosa Ziehau hn_rndis_detach(sc); 525715516c77SSepherosa Ziehau 525815516c77SSepherosa Ziehau /* Detach NVS. */ 525915516c77SSepherosa Ziehau hn_nvs_detach(sc); 526015516c77SSepherosa Ziehau 526115516c77SSepherosa Ziehau /* Detach all of the channels. */ 526215516c77SSepherosa Ziehau hn_detach_allchans(sc); 526315516c77SSepherosa Ziehau 526415516c77SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED; 526515516c77SSepherosa Ziehau } 526615516c77SSepherosa Ziehau 526715516c77SSepherosa Ziehau static void 526815516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt) 526915516c77SSepherosa Ziehau { 527015516c77SSepherosa Ziehau KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt, 527115516c77SSepherosa Ziehau ("invalid ring count %d", ring_cnt)); 527215516c77SSepherosa Ziehau 527315516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt > ring_cnt) 527415516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = ring_cnt; 527515516c77SSepherosa Ziehau else 527615516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 527715516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = ring_cnt; 527815516c77SSepherosa Ziehau 527934d68912SSepherosa Ziehau #ifdef RSS 528034d68912SSepherosa Ziehau if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) { 528134d68912SSepherosa Ziehau if_printf(sc->hn_ifp, "# of RX rings (%d) does not match " 528234d68912SSepherosa Ziehau "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse, 528334d68912SSepherosa Ziehau rss_getnumbuckets()); 528434d68912SSepherosa Ziehau } 528534d68912SSepherosa Ziehau #endif 528634d68912SSepherosa Ziehau 528715516c77SSepherosa Ziehau if (bootverbose) { 528815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n", 528915516c77SSepherosa Ziehau sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse); 529015516c77SSepherosa Ziehau } 529115516c77SSepherosa Ziehau } 529215516c77SSepherosa Ziehau 529315516c77SSepherosa Ziehau static void 529425641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan) 529515516c77SSepherosa Ziehau { 529615516c77SSepherosa Ziehau 529725641fc7SSepherosa Ziehau /* 529825641fc7SSepherosa Ziehau * NOTE: 529925641fc7SSepherosa Ziehau * The TX bufring will not be drained by the hypervisor, 530025641fc7SSepherosa Ziehau * if the primary channel is revoked. 530125641fc7SSepherosa Ziehau */ 530225641fc7SSepherosa Ziehau while (!vmbus_chan_rx_empty(chan) || 530325641fc7SSepherosa Ziehau (!vmbus_chan_is_revoked(sc->hn_prichan) && 530425641fc7SSepherosa Ziehau !vmbus_chan_tx_empty(chan))) 530515516c77SSepherosa Ziehau pause("waitch", 1); 530615516c77SSepherosa Ziehau vmbus_chan_intr_drain(chan); 530715516c77SSepherosa Ziehau } 530815516c77SSepherosa Ziehau 530915516c77SSepherosa Ziehau static void 5310b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc) 5311b3b75d9cSSepherosa Ziehau { 5312b3b75d9cSSepherosa Ziehau 5313b3b75d9cSSepherosa Ziehau /* 5314b3b75d9cSSepherosa Ziehau * Disable RX by clearing RX filter forcefully. 5315b3b75d9cSSepherosa Ziehau */ 5316b3b75d9cSSepherosa Ziehau sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE; 5317b3b75d9cSSepherosa Ziehau hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */ 5318b3b75d9cSSepherosa Ziehau 5319b3b75d9cSSepherosa Ziehau /* 5320b3b75d9cSSepherosa Ziehau * Give RNDIS enough time to flush all pending data packets. 5321b3b75d9cSSepherosa Ziehau */ 5322b3b75d9cSSepherosa Ziehau pause("waitrx", (200 * hz) / 1000); 5323b3b75d9cSSepherosa Ziehau } 5324b3b75d9cSSepherosa Ziehau 5325b3b75d9cSSepherosa Ziehau /* 5326b3b75d9cSSepherosa Ziehau * NOTE: 5327b3b75d9cSSepherosa Ziehau * RX/TX _must_ have been suspended/disabled, before this function 5328b3b75d9cSSepherosa Ziehau * is called. 5329b3b75d9cSSepherosa Ziehau */ 5330b3b75d9cSSepherosa Ziehau static void 5331b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan) 533215516c77SSepherosa Ziehau { 533315516c77SSepherosa Ziehau struct vmbus_channel **subch = NULL; 5334b3b75d9cSSepherosa Ziehau int nsubch; 5335b3b75d9cSSepherosa Ziehau 5336b3b75d9cSSepherosa Ziehau /* 5337b3b75d9cSSepherosa Ziehau * Drain RX/TX bufrings and interrupts. 5338b3b75d9cSSepherosa Ziehau */ 5339b3b75d9cSSepherosa Ziehau nsubch = nchan - 1; 5340b3b75d9cSSepherosa Ziehau if (nsubch > 0) 5341b3b75d9cSSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 5342b3b75d9cSSepherosa Ziehau 5343b3b75d9cSSepherosa Ziehau if (subch != NULL) { 5344b3b75d9cSSepherosa Ziehau int i; 5345b3b75d9cSSepherosa Ziehau 5346b3b75d9cSSepherosa Ziehau for (i = 0; i < nsubch; ++i) 5347b3b75d9cSSepherosa Ziehau hn_chan_drain(sc, subch[i]); 5348b3b75d9cSSepherosa Ziehau } 5349b3b75d9cSSepherosa Ziehau hn_chan_drain(sc, sc->hn_prichan); 5350b3b75d9cSSepherosa Ziehau 5351b3b75d9cSSepherosa Ziehau if (subch != NULL) 5352b3b75d9cSSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 5353b3b75d9cSSepherosa Ziehau } 5354b3b75d9cSSepherosa Ziehau 5355b3b75d9cSSepherosa Ziehau static void 5356b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc) 5357b3b75d9cSSepherosa Ziehau { 535825641fc7SSepherosa Ziehau struct hn_tx_ring *txr; 5359b3b75d9cSSepherosa Ziehau int i; 536015516c77SSepherosa Ziehau 536115516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 536215516c77SSepherosa Ziehau 536315516c77SSepherosa Ziehau /* 536415516c77SSepherosa Ziehau * Suspend TX. 536515516c77SSepherosa Ziehau */ 536615516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 536725641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 536815516c77SSepherosa Ziehau 536915516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 537015516c77SSepherosa Ziehau txr->hn_suspended = 1; 537115516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 537215516c77SSepherosa Ziehau /* No one is able send more packets now. */ 537315516c77SSepherosa Ziehau 537425641fc7SSepherosa Ziehau /* 537525641fc7SSepherosa Ziehau * Wait for all pending sends to finish. 537625641fc7SSepherosa Ziehau * 537725641fc7SSepherosa Ziehau * NOTE: 537825641fc7SSepherosa Ziehau * We will _not_ receive all pending send-done, if the 537925641fc7SSepherosa Ziehau * primary channel is revoked. 538025641fc7SSepherosa Ziehau */ 538125641fc7SSepherosa Ziehau while (hn_tx_ring_pending(txr) && 538225641fc7SSepherosa Ziehau !vmbus_chan_is_revoked(sc->hn_prichan)) 538315516c77SSepherosa Ziehau pause("hnwtx", 1 /* 1 tick */); 538415516c77SSepherosa Ziehau } 538515516c77SSepherosa Ziehau 538615516c77SSepherosa Ziehau /* 5387b3b75d9cSSepherosa Ziehau * Disable RX. 538815516c77SSepherosa Ziehau */ 5389b3b75d9cSSepherosa Ziehau hn_disable_rx(sc); 539015516c77SSepherosa Ziehau 539115516c77SSepherosa Ziehau /* 5392b3b75d9cSSepherosa Ziehau * Drain RX/TX. 539315516c77SSepherosa Ziehau */ 5394b3b75d9cSSepherosa Ziehau hn_drain_rxtx(sc, sc->hn_rx_ring_inuse); 539525641fc7SSepherosa Ziehau 539625641fc7SSepherosa Ziehau /* 539725641fc7SSepherosa Ziehau * Drain any pending TX tasks. 539825641fc7SSepherosa Ziehau * 539925641fc7SSepherosa Ziehau * NOTE: 5400b3b75d9cSSepherosa Ziehau * The above hn_drain_rxtx() can dispatch TX tasks, so the TX 5401b3b75d9cSSepherosa Ziehau * tasks will have to be drained _after_ the above hn_drain_rxtx(). 540225641fc7SSepherosa Ziehau */ 540325641fc7SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 540425641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 540525641fc7SSepherosa Ziehau 540625641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task); 540725641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task); 540825641fc7SSepherosa Ziehau } 540915516c77SSepherosa Ziehau } 541015516c77SSepherosa Ziehau 541115516c77SSepherosa Ziehau static void 541215516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused) 541315516c77SSepherosa Ziehau { 541415516c77SSepherosa Ziehau 541515516c77SSepherosa Ziehau ((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL; 541615516c77SSepherosa Ziehau } 541715516c77SSepherosa Ziehau 541815516c77SSepherosa Ziehau static void 541915516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc) 542015516c77SSepherosa Ziehau { 542115516c77SSepherosa Ziehau struct task task; 542215516c77SSepherosa Ziehau 542315516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 542415516c77SSepherosa Ziehau 542515516c77SSepherosa Ziehau /* 542615516c77SSepherosa Ziehau * Make sure that hn_mgmt_taskq0 can nolonger be accessed 542715516c77SSepherosa Ziehau * through hn_mgmt_taskq. 542815516c77SSepherosa Ziehau */ 542915516c77SSepherosa Ziehau TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc); 543015516c77SSepherosa Ziehau vmbus_chan_run_task(sc->hn_prichan, &task); 543115516c77SSepherosa Ziehau 543215516c77SSepherosa Ziehau /* 543315516c77SSepherosa Ziehau * Make sure that all pending management tasks are completed. 543415516c77SSepherosa Ziehau */ 543515516c77SSepherosa Ziehau taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init); 543615516c77SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status); 543715516c77SSepherosa Ziehau taskqueue_drain_all(sc->hn_mgmt_taskq0); 543815516c77SSepherosa Ziehau } 543915516c77SSepherosa Ziehau 544015516c77SSepherosa Ziehau static void 544115516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc) 544215516c77SSepherosa Ziehau { 544315516c77SSepherosa Ziehau 544487f8129dSSepherosa Ziehau /* Disable polling. */ 544587f8129dSSepherosa Ziehau hn_polling(sc, 0); 544687f8129dSSepherosa Ziehau 54475bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 54485bdfd3fdSDexuan Cui (sc->hn_flags & HN_FLAG_VF)) 544915516c77SSepherosa Ziehau hn_suspend_data(sc); 545015516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 545115516c77SSepherosa Ziehau } 545215516c77SSepherosa Ziehau 545315516c77SSepherosa Ziehau static void 545415516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt) 545515516c77SSepherosa Ziehau { 545615516c77SSepherosa Ziehau int i; 545715516c77SSepherosa Ziehau 545815516c77SSepherosa Ziehau KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt, 545915516c77SSepherosa Ziehau ("invalid TX ring count %d", tx_ring_cnt)); 546015516c77SSepherosa Ziehau 546115516c77SSepherosa Ziehau for (i = 0; i < tx_ring_cnt; ++i) { 546215516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 546315516c77SSepherosa Ziehau 546415516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 546515516c77SSepherosa Ziehau txr->hn_suspended = 0; 546615516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 546715516c77SSepherosa Ziehau } 546815516c77SSepherosa Ziehau } 546915516c77SSepherosa Ziehau 547015516c77SSepherosa Ziehau static void 547115516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc) 547215516c77SSepherosa Ziehau { 547315516c77SSepherosa Ziehau int i; 547415516c77SSepherosa Ziehau 547515516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 547615516c77SSepherosa Ziehau 547715516c77SSepherosa Ziehau /* 547815516c77SSepherosa Ziehau * Re-enable RX. 547915516c77SSepherosa Ziehau */ 5480c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 548115516c77SSepherosa Ziehau 548215516c77SSepherosa Ziehau /* 548315516c77SSepherosa Ziehau * Make sure to clear suspend status on "all" TX rings, 548415516c77SSepherosa Ziehau * since hn_tx_ring_inuse can be changed after 548515516c77SSepherosa Ziehau * hn_suspend_data(). 548615516c77SSepherosa Ziehau */ 548715516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_cnt); 548815516c77SSepherosa Ziehau 548923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 549023bf9e15SSepherosa Ziehau if (!hn_use_if_start) 549123bf9e15SSepherosa Ziehau #endif 549223bf9e15SSepherosa Ziehau { 549315516c77SSepherosa Ziehau /* 549415516c77SSepherosa Ziehau * Flush unused drbrs, since hn_tx_ring_inuse may be 549515516c77SSepherosa Ziehau * reduced. 549615516c77SSepherosa Ziehau */ 549715516c77SSepherosa Ziehau for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i) 549815516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 549915516c77SSepherosa Ziehau } 550015516c77SSepherosa Ziehau 550115516c77SSepherosa Ziehau /* 550215516c77SSepherosa Ziehau * Kick start TX. 550315516c77SSepherosa Ziehau */ 550415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 550515516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 550615516c77SSepherosa Ziehau 550715516c77SSepherosa Ziehau /* 550815516c77SSepherosa Ziehau * Use txeof task, so that any pending oactive can be 550915516c77SSepherosa Ziehau * cleared properly. 551015516c77SSepherosa Ziehau */ 551115516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 551215516c77SSepherosa Ziehau } 551315516c77SSepherosa Ziehau } 551415516c77SSepherosa Ziehau 551515516c77SSepherosa Ziehau static void 551615516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc) 551715516c77SSepherosa Ziehau { 551815516c77SSepherosa Ziehau 551915516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 552015516c77SSepherosa Ziehau 552115516c77SSepherosa Ziehau /* 552215516c77SSepherosa Ziehau * Kick off network change detection, if it was pending. 552315516c77SSepherosa Ziehau * If no network change was pending, start link status 552415516c77SSepherosa Ziehau * checks, which is more lightweight than network change 552515516c77SSepherosa Ziehau * detection. 552615516c77SSepherosa Ziehau */ 552715516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 552815516c77SSepherosa Ziehau hn_change_network(sc); 552915516c77SSepherosa Ziehau else 553015516c77SSepherosa Ziehau hn_update_link_status(sc); 553115516c77SSepherosa Ziehau } 553215516c77SSepherosa Ziehau 553315516c77SSepherosa Ziehau static void 553415516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc) 553515516c77SSepherosa Ziehau { 553615516c77SSepherosa Ziehau 55375bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 55385bdfd3fdSDexuan Cui (sc->hn_flags & HN_FLAG_VF)) 553915516c77SSepherosa Ziehau hn_resume_data(sc); 55405bdfd3fdSDexuan Cui 55415bdfd3fdSDexuan Cui /* 55425bdfd3fdSDexuan Cui * When the VF is activated, the synthetic interface is changed 55435bdfd3fdSDexuan Cui * to DOWN in hn_set_vf(). Here, if the VF is still active, we 55445bdfd3fdSDexuan Cui * don't call hn_resume_mgmt() until the VF is deactivated in 55455bdfd3fdSDexuan Cui * hn_set_vf(). 55465bdfd3fdSDexuan Cui */ 55475bdfd3fdSDexuan Cui if (!(sc->hn_flags & HN_FLAG_VF)) 554815516c77SSepherosa Ziehau hn_resume_mgmt(sc); 554987f8129dSSepherosa Ziehau 555087f8129dSSepherosa Ziehau /* 555187f8129dSSepherosa Ziehau * Re-enable polling if this interface is running and 555287f8129dSSepherosa Ziehau * the polling is requested. 555387f8129dSSepherosa Ziehau */ 555487f8129dSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0) 555587f8129dSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 555615516c77SSepherosa Ziehau } 555715516c77SSepherosa Ziehau 555815516c77SSepherosa Ziehau static void 555915516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen) 556015516c77SSepherosa Ziehau { 556115516c77SSepherosa Ziehau const struct rndis_status_msg *msg; 556215516c77SSepherosa Ziehau int ofs; 556315516c77SSepherosa Ziehau 556415516c77SSepherosa Ziehau if (dlen < sizeof(*msg)) { 556515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid RNDIS status\n"); 556615516c77SSepherosa Ziehau return; 556715516c77SSepherosa Ziehau } 556815516c77SSepherosa Ziehau msg = data; 556915516c77SSepherosa Ziehau 557015516c77SSepherosa Ziehau switch (msg->rm_status) { 557115516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_CONNECT: 557215516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_DISCONNECT: 557315516c77SSepherosa Ziehau hn_update_link_status(sc); 557415516c77SSepherosa Ziehau break; 557515516c77SSepherosa Ziehau 557615516c77SSepherosa Ziehau case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: 5577*40905afaSSepherosa Ziehau case RNDIS_STATUS_LINK_SPEED_CHANGE: 557815516c77SSepherosa Ziehau /* Not really useful; ignore. */ 557915516c77SSepherosa Ziehau break; 558015516c77SSepherosa Ziehau 558115516c77SSepherosa Ziehau case RNDIS_STATUS_NETWORK_CHANGE: 558215516c77SSepherosa Ziehau ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset); 558315516c77SSepherosa Ziehau if (dlen < ofs + msg->rm_stbuflen || 558415516c77SSepherosa Ziehau msg->rm_stbuflen < sizeof(uint32_t)) { 558515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed\n"); 558615516c77SSepherosa Ziehau } else { 558715516c77SSepherosa Ziehau uint32_t change; 558815516c77SSepherosa Ziehau 558915516c77SSepherosa Ziehau memcpy(&change, ((const uint8_t *)msg) + ofs, 559015516c77SSepherosa Ziehau sizeof(change)); 559115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed, change %u\n", 559215516c77SSepherosa Ziehau change); 559315516c77SSepherosa Ziehau } 559415516c77SSepherosa Ziehau hn_change_network(sc); 559515516c77SSepherosa Ziehau break; 559615516c77SSepherosa Ziehau 559715516c77SSepherosa Ziehau default: 559815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n", 559915516c77SSepherosa Ziehau msg->rm_status); 560015516c77SSepherosa Ziehau break; 560115516c77SSepherosa Ziehau } 560215516c77SSepherosa Ziehau } 560315516c77SSepherosa Ziehau 560415516c77SSepherosa Ziehau static int 560515516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info) 560615516c77SSepherosa Ziehau { 560715516c77SSepherosa Ziehau const struct rndis_pktinfo *pi = info_data; 560815516c77SSepherosa Ziehau uint32_t mask = 0; 560915516c77SSepherosa Ziehau 561015516c77SSepherosa Ziehau while (info_dlen != 0) { 561115516c77SSepherosa Ziehau const void *data; 561215516c77SSepherosa Ziehau uint32_t dlen; 561315516c77SSepherosa Ziehau 561415516c77SSepherosa Ziehau if (__predict_false(info_dlen < sizeof(*pi))) 561515516c77SSepherosa Ziehau return (EINVAL); 561615516c77SSepherosa Ziehau if (__predict_false(info_dlen < pi->rm_size)) 561715516c77SSepherosa Ziehau return (EINVAL); 561815516c77SSepherosa Ziehau info_dlen -= pi->rm_size; 561915516c77SSepherosa Ziehau 562015516c77SSepherosa Ziehau if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK)) 562115516c77SSepherosa Ziehau return (EINVAL); 562215516c77SSepherosa Ziehau if (__predict_false(pi->rm_size < pi->rm_pktinfooffset)) 562315516c77SSepherosa Ziehau return (EINVAL); 562415516c77SSepherosa Ziehau dlen = pi->rm_size - pi->rm_pktinfooffset; 562515516c77SSepherosa Ziehau data = pi->rm_data; 562615516c77SSepherosa Ziehau 562715516c77SSepherosa Ziehau switch (pi->rm_type) { 562815516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_VLAN: 562915516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE)) 563015516c77SSepherosa Ziehau return (EINVAL); 563115516c77SSepherosa Ziehau info->vlan_info = *((const uint32_t *)data); 563215516c77SSepherosa Ziehau mask |= HN_RXINFO_VLAN; 563315516c77SSepherosa Ziehau break; 563415516c77SSepherosa Ziehau 563515516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_CSUM: 563615516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE)) 563715516c77SSepherosa Ziehau return (EINVAL); 563815516c77SSepherosa Ziehau info->csum_info = *((const uint32_t *)data); 563915516c77SSepherosa Ziehau mask |= HN_RXINFO_CSUM; 564015516c77SSepherosa Ziehau break; 564115516c77SSepherosa Ziehau 564215516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHVAL: 564315516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE)) 564415516c77SSepherosa Ziehau return (EINVAL); 564515516c77SSepherosa Ziehau info->hash_value = *((const uint32_t *)data); 564615516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHVAL; 564715516c77SSepherosa Ziehau break; 564815516c77SSepherosa Ziehau 564915516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHINF: 565015516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE)) 565115516c77SSepherosa Ziehau return (EINVAL); 565215516c77SSepherosa Ziehau info->hash_info = *((const uint32_t *)data); 565315516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHINF; 565415516c77SSepherosa Ziehau break; 565515516c77SSepherosa Ziehau 565615516c77SSepherosa Ziehau default: 565715516c77SSepherosa Ziehau goto next; 565815516c77SSepherosa Ziehau } 565915516c77SSepherosa Ziehau 566015516c77SSepherosa Ziehau if (mask == HN_RXINFO_ALL) { 566115516c77SSepherosa Ziehau /* All found; done */ 566215516c77SSepherosa Ziehau break; 566315516c77SSepherosa Ziehau } 566415516c77SSepherosa Ziehau next: 566515516c77SSepherosa Ziehau pi = (const struct rndis_pktinfo *) 566615516c77SSepherosa Ziehau ((const uint8_t *)pi + pi->rm_size); 566715516c77SSepherosa Ziehau } 566815516c77SSepherosa Ziehau 566915516c77SSepherosa Ziehau /* 567015516c77SSepherosa Ziehau * Final fixup. 567115516c77SSepherosa Ziehau * - If there is no hash value, invalidate the hash info. 567215516c77SSepherosa Ziehau */ 567315516c77SSepherosa Ziehau if ((mask & HN_RXINFO_HASHVAL) == 0) 567415516c77SSepherosa Ziehau info->hash_info = HN_NDIS_HASH_INFO_INVALID; 567515516c77SSepherosa Ziehau return (0); 567615516c77SSepherosa Ziehau } 567715516c77SSepherosa Ziehau 567815516c77SSepherosa Ziehau static __inline bool 567915516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len) 568015516c77SSepherosa Ziehau { 568115516c77SSepherosa Ziehau 568215516c77SSepherosa Ziehau if (off < check_off) { 568315516c77SSepherosa Ziehau if (__predict_true(off + len <= check_off)) 568415516c77SSepherosa Ziehau return (false); 568515516c77SSepherosa Ziehau } else if (off > check_off) { 568615516c77SSepherosa Ziehau if (__predict_true(check_off + check_len <= off)) 568715516c77SSepherosa Ziehau return (false); 568815516c77SSepherosa Ziehau } 568915516c77SSepherosa Ziehau return (true); 569015516c77SSepherosa Ziehau } 569115516c77SSepherosa Ziehau 569215516c77SSepherosa Ziehau static void 569315516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen) 569415516c77SSepherosa Ziehau { 569515516c77SSepherosa Ziehau const struct rndis_packet_msg *pkt; 569615516c77SSepherosa Ziehau struct hn_rxinfo info; 569715516c77SSepherosa Ziehau int data_off, pktinfo_off, data_len, pktinfo_len; 569815516c77SSepherosa Ziehau 569915516c77SSepherosa Ziehau /* 570015516c77SSepherosa Ziehau * Check length. 570115516c77SSepherosa Ziehau */ 570215516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*pkt))) { 570315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n"); 570415516c77SSepherosa Ziehau return; 570515516c77SSepherosa Ziehau } 570615516c77SSepherosa Ziehau pkt = data; 570715516c77SSepherosa Ziehau 570815516c77SSepherosa Ziehau if (__predict_false(dlen < pkt->rm_len)) { 570915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, " 571015516c77SSepherosa Ziehau "dlen %d, msglen %u\n", dlen, pkt->rm_len); 571115516c77SSepherosa Ziehau return; 571215516c77SSepherosa Ziehau } 571315516c77SSepherosa Ziehau if (__predict_false(pkt->rm_len < 571415516c77SSepherosa Ziehau pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) { 571515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, " 571615516c77SSepherosa Ziehau "msglen %u, data %u, oob %u, pktinfo %u\n", 571715516c77SSepherosa Ziehau pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen, 571815516c77SSepherosa Ziehau pkt->rm_pktinfolen); 571915516c77SSepherosa Ziehau return; 572015516c77SSepherosa Ziehau } 572115516c77SSepherosa Ziehau if (__predict_false(pkt->rm_datalen == 0)) { 572215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n"); 572315516c77SSepherosa Ziehau return; 572415516c77SSepherosa Ziehau } 572515516c77SSepherosa Ziehau 572615516c77SSepherosa Ziehau /* 572715516c77SSepherosa Ziehau * Check offests. 572815516c77SSepherosa Ziehau */ 572915516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs) \ 573015516c77SSepherosa Ziehau ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \ 573115516c77SSepherosa Ziehau ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK)) 573215516c77SSepherosa Ziehau 573315516c77SSepherosa Ziehau /* XXX Hyper-V does not meet data offset alignment requirement */ 573415516c77SSepherosa Ziehau if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) { 573515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 573615516c77SSepherosa Ziehau "data offset %u\n", pkt->rm_dataoffset); 573715516c77SSepherosa Ziehau return; 573815516c77SSepherosa Ziehau } 573915516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdataoffset > 0 && 574015516c77SSepherosa Ziehau IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) { 574115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 574215516c77SSepherosa Ziehau "oob offset %u\n", pkt->rm_oobdataoffset); 574315516c77SSepherosa Ziehau return; 574415516c77SSepherosa Ziehau } 574515516c77SSepherosa Ziehau if (__predict_true(pkt->rm_pktinfooffset > 0) && 574615516c77SSepherosa Ziehau __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) { 574715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 574815516c77SSepherosa Ziehau "pktinfo offset %u\n", pkt->rm_pktinfooffset); 574915516c77SSepherosa Ziehau return; 575015516c77SSepherosa Ziehau } 575115516c77SSepherosa Ziehau 575215516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID 575315516c77SSepherosa Ziehau 575415516c77SSepherosa Ziehau data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset); 575515516c77SSepherosa Ziehau data_len = pkt->rm_datalen; 575615516c77SSepherosa Ziehau pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset); 575715516c77SSepherosa Ziehau pktinfo_len = pkt->rm_pktinfolen; 575815516c77SSepherosa Ziehau 575915516c77SSepherosa Ziehau /* 576015516c77SSepherosa Ziehau * Check OOB coverage. 576115516c77SSepherosa Ziehau */ 576215516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdatalen != 0)) { 576315516c77SSepherosa Ziehau int oob_off, oob_len; 576415516c77SSepherosa Ziehau 576515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "got oobdata\n"); 576615516c77SSepherosa Ziehau oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset); 576715516c77SSepherosa Ziehau oob_len = pkt->rm_oobdatalen; 576815516c77SSepherosa Ziehau 576915516c77SSepherosa Ziehau if (__predict_false(oob_off + oob_len > pkt->rm_len)) { 577015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 577115516c77SSepherosa Ziehau "oob overflow, msglen %u, oob abs %d len %d\n", 577215516c77SSepherosa Ziehau pkt->rm_len, oob_off, oob_len); 577315516c77SSepherosa Ziehau return; 577415516c77SSepherosa Ziehau } 577515516c77SSepherosa Ziehau 577615516c77SSepherosa Ziehau /* 577715516c77SSepherosa Ziehau * Check against data. 577815516c77SSepherosa Ziehau */ 577915516c77SSepherosa Ziehau if (hn_rndis_check_overlap(oob_off, oob_len, 578015516c77SSepherosa Ziehau data_off, data_len)) { 578115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 578215516c77SSepherosa Ziehau "oob overlaps data, oob abs %d len %d, " 578315516c77SSepherosa Ziehau "data abs %d len %d\n", 578415516c77SSepherosa Ziehau oob_off, oob_len, data_off, data_len); 578515516c77SSepherosa Ziehau return; 578615516c77SSepherosa Ziehau } 578715516c77SSepherosa Ziehau 578815516c77SSepherosa Ziehau /* 578915516c77SSepherosa Ziehau * Check against pktinfo. 579015516c77SSepherosa Ziehau */ 579115516c77SSepherosa Ziehau if (pktinfo_len != 0 && 579215516c77SSepherosa Ziehau hn_rndis_check_overlap(oob_off, oob_len, 579315516c77SSepherosa Ziehau pktinfo_off, pktinfo_len)) { 579415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 579515516c77SSepherosa Ziehau "oob overlaps pktinfo, oob abs %d len %d, " 579615516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 579715516c77SSepherosa Ziehau oob_off, oob_len, pktinfo_off, pktinfo_len); 579815516c77SSepherosa Ziehau return; 579915516c77SSepherosa Ziehau } 580015516c77SSepherosa Ziehau } 580115516c77SSepherosa Ziehau 580215516c77SSepherosa Ziehau /* 580315516c77SSepherosa Ziehau * Check per-packet-info coverage and find useful per-packet-info. 580415516c77SSepherosa Ziehau */ 580515516c77SSepherosa Ziehau info.vlan_info = HN_NDIS_VLAN_INFO_INVALID; 580615516c77SSepherosa Ziehau info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID; 580715516c77SSepherosa Ziehau info.hash_info = HN_NDIS_HASH_INFO_INVALID; 580815516c77SSepherosa Ziehau if (__predict_true(pktinfo_len != 0)) { 580915516c77SSepherosa Ziehau bool overlap; 581015516c77SSepherosa Ziehau int error; 581115516c77SSepherosa Ziehau 581215516c77SSepherosa Ziehau if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) { 581315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 581415516c77SSepherosa Ziehau "pktinfo overflow, msglen %u, " 581515516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 581615516c77SSepherosa Ziehau pkt->rm_len, pktinfo_off, pktinfo_len); 581715516c77SSepherosa Ziehau return; 581815516c77SSepherosa Ziehau } 581915516c77SSepherosa Ziehau 582015516c77SSepherosa Ziehau /* 582115516c77SSepherosa Ziehau * Check packet info coverage. 582215516c77SSepherosa Ziehau */ 582315516c77SSepherosa Ziehau overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len, 582415516c77SSepherosa Ziehau data_off, data_len); 582515516c77SSepherosa Ziehau if (__predict_false(overlap)) { 582615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 582715516c77SSepherosa Ziehau "pktinfo overlap data, pktinfo abs %d len %d, " 582815516c77SSepherosa Ziehau "data abs %d len %d\n", 582915516c77SSepherosa Ziehau pktinfo_off, pktinfo_len, data_off, data_len); 583015516c77SSepherosa Ziehau return; 583115516c77SSepherosa Ziehau } 583215516c77SSepherosa Ziehau 583315516c77SSepherosa Ziehau /* 583415516c77SSepherosa Ziehau * Find useful per-packet-info. 583515516c77SSepherosa Ziehau */ 583615516c77SSepherosa Ziehau error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off, 583715516c77SSepherosa Ziehau pktinfo_len, &info); 583815516c77SSepherosa Ziehau if (__predict_false(error)) { 583915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg " 584015516c77SSepherosa Ziehau "pktinfo\n"); 584115516c77SSepherosa Ziehau return; 584215516c77SSepherosa Ziehau } 584315516c77SSepherosa Ziehau } 584415516c77SSepherosa Ziehau 584515516c77SSepherosa Ziehau if (__predict_false(data_off + data_len > pkt->rm_len)) { 584615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 584715516c77SSepherosa Ziehau "data overflow, msglen %u, data abs %d len %d\n", 584815516c77SSepherosa Ziehau pkt->rm_len, data_off, data_len); 584915516c77SSepherosa Ziehau return; 585015516c77SSepherosa Ziehau } 585115516c77SSepherosa Ziehau hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info); 585215516c77SSepherosa Ziehau } 585315516c77SSepherosa Ziehau 585415516c77SSepherosa Ziehau static __inline void 585515516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen) 585615516c77SSepherosa Ziehau { 585715516c77SSepherosa Ziehau const struct rndis_msghdr *hdr; 585815516c77SSepherosa Ziehau 585915516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*hdr))) { 586015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS msg\n"); 586115516c77SSepherosa Ziehau return; 586215516c77SSepherosa Ziehau } 586315516c77SSepherosa Ziehau hdr = data; 586415516c77SSepherosa Ziehau 586515516c77SSepherosa Ziehau if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) { 586615516c77SSepherosa Ziehau /* Hot data path. */ 586715516c77SSepherosa Ziehau hn_rndis_rx_data(rxr, data, dlen); 586815516c77SSepherosa Ziehau /* Done! */ 586915516c77SSepherosa Ziehau return; 587015516c77SSepherosa Ziehau } 587115516c77SSepherosa Ziehau 587215516c77SSepherosa Ziehau if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG) 587315516c77SSepherosa Ziehau hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen); 587415516c77SSepherosa Ziehau else 587515516c77SSepherosa Ziehau hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen); 587615516c77SSepherosa Ziehau } 587715516c77SSepherosa Ziehau 587815516c77SSepherosa Ziehau static void 587915516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) 588015516c77SSepherosa Ziehau { 588115516c77SSepherosa Ziehau const struct hn_nvs_hdr *hdr; 588215516c77SSepherosa Ziehau 588315516c77SSepherosa Ziehau if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) { 588415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid nvs notify\n"); 588515516c77SSepherosa Ziehau return; 588615516c77SSepherosa Ziehau } 588715516c77SSepherosa Ziehau hdr = VMBUS_CHANPKT_CONST_DATA(pkt); 588815516c77SSepherosa Ziehau 588915516c77SSepherosa Ziehau if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) { 589015516c77SSepherosa Ziehau /* Useless; ignore */ 589115516c77SSepherosa Ziehau return; 589215516c77SSepherosa Ziehau } 589315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type); 589415516c77SSepherosa Ziehau } 589515516c77SSepherosa Ziehau 589615516c77SSepherosa Ziehau static void 589715516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan, 589815516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkt) 589915516c77SSepherosa Ziehau { 590015516c77SSepherosa Ziehau struct hn_nvs_sendctx *sndc; 590115516c77SSepherosa Ziehau 590215516c77SSepherosa Ziehau sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid; 590315516c77SSepherosa Ziehau sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt), 590415516c77SSepherosa Ziehau VMBUS_CHANPKT_DATALEN(pkt)); 590515516c77SSepherosa Ziehau /* 590615516c77SSepherosa Ziehau * NOTE: 590715516c77SSepherosa Ziehau * 'sndc' CAN NOT be accessed anymore, since it can be freed by 590815516c77SSepherosa Ziehau * its callback. 590915516c77SSepherosa Ziehau */ 591015516c77SSepherosa Ziehau } 591115516c77SSepherosa Ziehau 591215516c77SSepherosa Ziehau static void 591315516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 591415516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkthdr) 591515516c77SSepherosa Ziehau { 591615516c77SSepherosa Ziehau const struct vmbus_chanpkt_rxbuf *pkt; 591715516c77SSepherosa Ziehau const struct hn_nvs_hdr *nvs_hdr; 591815516c77SSepherosa Ziehau int count, i, hlen; 591915516c77SSepherosa Ziehau 592015516c77SSepherosa Ziehau if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) { 592115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n"); 592215516c77SSepherosa Ziehau return; 592315516c77SSepherosa Ziehau } 592415516c77SSepherosa Ziehau nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr); 592515516c77SSepherosa Ziehau 592615516c77SSepherosa Ziehau /* Make sure that this is a RNDIS message. */ 592715516c77SSepherosa Ziehau if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) { 592815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n", 592915516c77SSepherosa Ziehau nvs_hdr->nvs_type); 593015516c77SSepherosa Ziehau return; 593115516c77SSepherosa Ziehau } 593215516c77SSepherosa Ziehau 593315516c77SSepherosa Ziehau hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen); 593415516c77SSepherosa Ziehau if (__predict_false(hlen < sizeof(*pkt))) { 593515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n"); 593615516c77SSepherosa Ziehau return; 593715516c77SSepherosa Ziehau } 593815516c77SSepherosa Ziehau pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr; 593915516c77SSepherosa Ziehau 594015516c77SSepherosa Ziehau if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) { 594115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n", 594215516c77SSepherosa Ziehau pkt->cp_rxbuf_id); 594315516c77SSepherosa Ziehau return; 594415516c77SSepherosa Ziehau } 594515516c77SSepherosa Ziehau 594615516c77SSepherosa Ziehau count = pkt->cp_rxbuf_cnt; 594715516c77SSepherosa Ziehau if (__predict_false(hlen < 594815516c77SSepherosa Ziehau __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) { 594915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count); 595015516c77SSepherosa Ziehau return; 595115516c77SSepherosa Ziehau } 595215516c77SSepherosa Ziehau 595315516c77SSepherosa Ziehau /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 595415516c77SSepherosa Ziehau for (i = 0; i < count; ++i) { 595515516c77SSepherosa Ziehau int ofs, len; 595615516c77SSepherosa Ziehau 595715516c77SSepherosa Ziehau ofs = pkt->cp_rxbuf[i].rb_ofs; 595815516c77SSepherosa Ziehau len = pkt->cp_rxbuf[i].rb_len; 595915516c77SSepherosa Ziehau if (__predict_false(ofs + len > HN_RXBUF_SIZE)) { 596015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, " 596115516c77SSepherosa Ziehau "ofs %d, len %d\n", i, ofs, len); 596215516c77SSepherosa Ziehau continue; 596315516c77SSepherosa Ziehau } 596415516c77SSepherosa Ziehau hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len); 596515516c77SSepherosa Ziehau } 596615516c77SSepherosa Ziehau 596715516c77SSepherosa Ziehau /* 596815516c77SSepherosa Ziehau * Ack the consumed RXBUF associated w/ this channel packet, 596915516c77SSepherosa Ziehau * so that this RXBUF can be recycled by the hypervisor. 597015516c77SSepherosa Ziehau */ 597115516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid); 597215516c77SSepherosa Ziehau } 597315516c77SSepherosa Ziehau 597415516c77SSepherosa Ziehau static void 597515516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 597615516c77SSepherosa Ziehau uint64_t tid) 597715516c77SSepherosa Ziehau { 597815516c77SSepherosa Ziehau struct hn_nvs_rndis_ack ack; 597915516c77SSepherosa Ziehau int retries, error; 598015516c77SSepherosa Ziehau 598115516c77SSepherosa Ziehau ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK; 598215516c77SSepherosa Ziehau ack.nvs_status = HN_NVS_STATUS_OK; 598315516c77SSepherosa Ziehau 598415516c77SSepherosa Ziehau retries = 0; 598515516c77SSepherosa Ziehau again: 598615516c77SSepherosa Ziehau error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 598715516c77SSepherosa Ziehau VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid); 598815516c77SSepherosa Ziehau if (__predict_false(error == EAGAIN)) { 598915516c77SSepherosa Ziehau /* 599015516c77SSepherosa Ziehau * NOTE: 599115516c77SSepherosa Ziehau * This should _not_ happen in real world, since the 599215516c77SSepherosa Ziehau * consumption of the TX bufring from the TX path is 599315516c77SSepherosa Ziehau * controlled. 599415516c77SSepherosa Ziehau */ 599515516c77SSepherosa Ziehau if (rxr->hn_ack_failed == 0) 599615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack retry\n"); 599715516c77SSepherosa Ziehau rxr->hn_ack_failed++; 599815516c77SSepherosa Ziehau retries++; 599915516c77SSepherosa Ziehau if (retries < 10) { 600015516c77SSepherosa Ziehau DELAY(100); 600115516c77SSepherosa Ziehau goto again; 600215516c77SSepherosa Ziehau } 600315516c77SSepherosa Ziehau /* RXBUF leaks! */ 600415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack failed\n"); 600515516c77SSepherosa Ziehau } 600615516c77SSepherosa Ziehau } 600715516c77SSepherosa Ziehau 600815516c77SSepherosa Ziehau static void 600915516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr) 601015516c77SSepherosa Ziehau { 601115516c77SSepherosa Ziehau struct hn_rx_ring *rxr = xrxr; 601215516c77SSepherosa Ziehau struct hn_softc *sc = rxr->hn_ifp->if_softc; 601315516c77SSepherosa Ziehau 601415516c77SSepherosa Ziehau for (;;) { 601515516c77SSepherosa Ziehau struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf; 601615516c77SSepherosa Ziehau int error, pktlen; 601715516c77SSepherosa Ziehau 601815516c77SSepherosa Ziehau pktlen = rxr->hn_pktbuf_len; 601915516c77SSepherosa Ziehau error = vmbus_chan_recv_pkt(chan, pkt, &pktlen); 602015516c77SSepherosa Ziehau if (__predict_false(error == ENOBUFS)) { 602115516c77SSepherosa Ziehau void *nbuf; 602215516c77SSepherosa Ziehau int nlen; 602315516c77SSepherosa Ziehau 602415516c77SSepherosa Ziehau /* 602515516c77SSepherosa Ziehau * Expand channel packet buffer. 602615516c77SSepherosa Ziehau * 602715516c77SSepherosa Ziehau * XXX 602815516c77SSepherosa Ziehau * Use M_WAITOK here, since allocation failure 602915516c77SSepherosa Ziehau * is fatal. 603015516c77SSepherosa Ziehau */ 603115516c77SSepherosa Ziehau nlen = rxr->hn_pktbuf_len * 2; 603215516c77SSepherosa Ziehau while (nlen < pktlen) 603315516c77SSepherosa Ziehau nlen *= 2; 603415516c77SSepherosa Ziehau nbuf = malloc(nlen, M_DEVBUF, M_WAITOK); 603515516c77SSepherosa Ziehau 603615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n", 603715516c77SSepherosa Ziehau rxr->hn_pktbuf_len, nlen); 603815516c77SSepherosa Ziehau 603915516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 604015516c77SSepherosa Ziehau rxr->hn_pktbuf = nbuf; 604115516c77SSepherosa Ziehau rxr->hn_pktbuf_len = nlen; 604215516c77SSepherosa Ziehau /* Retry! */ 604315516c77SSepherosa Ziehau continue; 604415516c77SSepherosa Ziehau } else if (__predict_false(error == EAGAIN)) { 604515516c77SSepherosa Ziehau /* No more channel packets; done! */ 604615516c77SSepherosa Ziehau break; 604715516c77SSepherosa Ziehau } 604815516c77SSepherosa Ziehau KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error)); 604915516c77SSepherosa Ziehau 605015516c77SSepherosa Ziehau switch (pkt->cph_type) { 605115516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_COMP: 605215516c77SSepherosa Ziehau hn_nvs_handle_comp(sc, chan, pkt); 605315516c77SSepherosa Ziehau break; 605415516c77SSepherosa Ziehau 605515516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_RXBUF: 605615516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(rxr, chan, pkt); 605715516c77SSepherosa Ziehau break; 605815516c77SSepherosa Ziehau 605915516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_INBAND: 606015516c77SSepherosa Ziehau hn_nvs_handle_notify(sc, pkt); 606115516c77SSepherosa Ziehau break; 606215516c77SSepherosa Ziehau 606315516c77SSepherosa Ziehau default: 606415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "unknown chan pkt %u\n", 606515516c77SSepherosa Ziehau pkt->cph_type); 606615516c77SSepherosa Ziehau break; 606715516c77SSepherosa Ziehau } 606815516c77SSepherosa Ziehau } 606915516c77SSepherosa Ziehau hn_chan_rollup(rxr, rxr->hn_txr); 607015516c77SSepherosa Ziehau } 607115516c77SSepherosa Ziehau 607215516c77SSepherosa Ziehau static void 6073499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused) 607415516c77SSepherosa Ziehau { 6075fdd0222aSSepherosa Ziehau int i; 6076fdd0222aSSepherosa Ziehau 6077fdd0222aSSepherosa Ziehau /* 6078499c3e17SSepherosa Ziehau * Initialize VF map. 6079499c3e17SSepherosa Ziehau */ 6080499c3e17SSepherosa Ziehau rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE); 6081499c3e17SSepherosa Ziehau hn_vfmap_size = HN_VFMAP_SIZE_DEF; 6082499c3e17SSepherosa Ziehau hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF, 6083499c3e17SSepherosa Ziehau M_WAITOK | M_ZERO); 6084499c3e17SSepherosa Ziehau 6085499c3e17SSepherosa Ziehau /* 6086fdd0222aSSepherosa Ziehau * Fix the # of TX taskqueues. 6087fdd0222aSSepherosa Ziehau */ 6088fdd0222aSSepherosa Ziehau if (hn_tx_taskq_cnt <= 0) 6089fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = 1; 6090fdd0222aSSepherosa Ziehau else if (hn_tx_taskq_cnt > mp_ncpus) 6091fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = mp_ncpus; 609215516c77SSepherosa Ziehau 60930e11868dSSepherosa Ziehau /* 60940e11868dSSepherosa Ziehau * Fix the TX taskqueue mode. 60950e11868dSSepherosa Ziehau */ 60960e11868dSSepherosa Ziehau switch (hn_tx_taskq_mode) { 60970e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_INDEP: 60980e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_GLOBAL: 60990e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_EVTTQ: 61000e11868dSSepherosa Ziehau break; 61010e11868dSSepherosa Ziehau default: 61020e11868dSSepherosa Ziehau hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP; 61030e11868dSSepherosa Ziehau break; 61040e11868dSSepherosa Ziehau } 61050e11868dSSepherosa Ziehau 610615516c77SSepherosa Ziehau if (vm_guest != VM_GUEST_HV) 610715516c77SSepherosa Ziehau return; 610815516c77SSepherosa Ziehau 61090e11868dSSepherosa Ziehau if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL) 611015516c77SSepherosa Ziehau return; 611115516c77SSepherosa Ziehau 6112fdd0222aSSepherosa Ziehau hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 6113fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 6114fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 6115fdd0222aSSepherosa Ziehau hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK, 6116fdd0222aSSepherosa Ziehau taskqueue_thread_enqueue, &hn_tx_taskque[i]); 6117fdd0222aSSepherosa Ziehau taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET, 6118fdd0222aSSepherosa Ziehau "hn tx%d", i); 6119fdd0222aSSepherosa Ziehau } 612015516c77SSepherosa Ziehau } 6121499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL); 612215516c77SSepherosa Ziehau 612315516c77SSepherosa Ziehau static void 6124499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused) 612515516c77SSepherosa Ziehau { 612615516c77SSepherosa Ziehau 6127fdd0222aSSepherosa Ziehau if (hn_tx_taskque != NULL) { 6128fdd0222aSSepherosa Ziehau int i; 6129fdd0222aSSepherosa Ziehau 6130fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 6131fdd0222aSSepherosa Ziehau taskqueue_free(hn_tx_taskque[i]); 6132fdd0222aSSepherosa Ziehau free(hn_tx_taskque, M_DEVBUF); 6133fdd0222aSSepherosa Ziehau } 6134499c3e17SSepherosa Ziehau 6135499c3e17SSepherosa Ziehau if (hn_vfmap != NULL) 6136499c3e17SSepherosa Ziehau free(hn_vfmap, M_DEVBUF); 6137499c3e17SSepherosa Ziehau rm_destroy(&hn_vfmap_lock); 613815516c77SSepherosa Ziehau } 6139499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL); 6140