1*15516c77SSepherosa Ziehau /*- 2*15516c77SSepherosa Ziehau * Copyright (c) 2010-2012 Citrix Inc. 3*15516c77SSepherosa Ziehau * Copyright (c) 2009-2012,2016 Microsoft Corp. 4*15516c77SSepherosa Ziehau * Copyright (c) 2012 NetApp Inc. 5*15516c77SSepherosa Ziehau * All rights reserved. 6*15516c77SSepherosa Ziehau * 7*15516c77SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 8*15516c77SSepherosa Ziehau * modification, are permitted provided that the following conditions 9*15516c77SSepherosa Ziehau * are met: 10*15516c77SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 11*15516c77SSepherosa Ziehau * notice unmodified, this list of conditions, and the following 12*15516c77SSepherosa Ziehau * disclaimer. 13*15516c77SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 14*15516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 15*15516c77SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 16*15516c77SSepherosa Ziehau * 17*15516c77SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18*15516c77SSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19*15516c77SSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20*15516c77SSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21*15516c77SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22*15516c77SSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23*15516c77SSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24*15516c77SSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25*15516c77SSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26*15516c77SSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27*15516c77SSepherosa Ziehau */ 28*15516c77SSepherosa Ziehau 29*15516c77SSepherosa Ziehau /*- 30*15516c77SSepherosa Ziehau * Copyright (c) 2004-2006 Kip Macy 31*15516c77SSepherosa Ziehau * All rights reserved. 32*15516c77SSepherosa Ziehau * 33*15516c77SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 34*15516c77SSepherosa Ziehau * modification, are permitted provided that the following conditions 35*15516c77SSepherosa Ziehau * are met: 36*15516c77SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 37*15516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 38*15516c77SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 39*15516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 40*15516c77SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 41*15516c77SSepherosa Ziehau * 42*15516c77SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 43*15516c77SSepherosa Ziehau * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 44*15516c77SSepherosa Ziehau * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 45*15516c77SSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 46*15516c77SSepherosa Ziehau * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47*15516c77SSepherosa Ziehau * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 48*15516c77SSepherosa Ziehau * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49*15516c77SSepherosa Ziehau * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50*15516c77SSepherosa Ziehau * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51*15516c77SSepherosa Ziehau * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52*15516c77SSepherosa Ziehau * SUCH DAMAGE. 53*15516c77SSepherosa Ziehau */ 54*15516c77SSepherosa Ziehau 55*15516c77SSepherosa Ziehau #include <sys/cdefs.h> 56*15516c77SSepherosa Ziehau __FBSDID("$FreeBSD$"); 57*15516c77SSepherosa Ziehau 58*15516c77SSepherosa Ziehau #include "opt_inet6.h" 59*15516c77SSepherosa Ziehau #include "opt_inet.h" 60*15516c77SSepherosa Ziehau 61*15516c77SSepherosa Ziehau #include <sys/param.h> 62*15516c77SSepherosa Ziehau #include <sys/bus.h> 63*15516c77SSepherosa Ziehau #include <sys/kernel.h> 64*15516c77SSepherosa Ziehau #include <sys/limits.h> 65*15516c77SSepherosa Ziehau #include <sys/malloc.h> 66*15516c77SSepherosa Ziehau #include <sys/mbuf.h> 67*15516c77SSepherosa Ziehau #include <sys/module.h> 68*15516c77SSepherosa Ziehau #include <sys/queue.h> 69*15516c77SSepherosa Ziehau #include <sys/lock.h> 70*15516c77SSepherosa Ziehau #include <sys/smp.h> 71*15516c77SSepherosa Ziehau #include <sys/socket.h> 72*15516c77SSepherosa Ziehau #include <sys/sockio.h> 73*15516c77SSepherosa Ziehau #include <sys/sx.h> 74*15516c77SSepherosa Ziehau #include <sys/sysctl.h> 75*15516c77SSepherosa Ziehau #include <sys/systm.h> 76*15516c77SSepherosa Ziehau #include <sys/taskqueue.h> 77*15516c77SSepherosa Ziehau #include <sys/buf_ring.h> 78*15516c77SSepherosa Ziehau 79*15516c77SSepherosa Ziehau #include <machine/atomic.h> 80*15516c77SSepherosa Ziehau #include <machine/in_cksum.h> 81*15516c77SSepherosa Ziehau 82*15516c77SSepherosa Ziehau #include <net/bpf.h> 83*15516c77SSepherosa Ziehau #include <net/ethernet.h> 84*15516c77SSepherosa Ziehau #include <net/if.h> 85*15516c77SSepherosa Ziehau #include <net/if_media.h> 86*15516c77SSepherosa Ziehau #include <net/if_types.h> 87*15516c77SSepherosa Ziehau #include <net/if_var.h> 88*15516c77SSepherosa Ziehau #include <net/rndis.h> 89*15516c77SSepherosa Ziehau 90*15516c77SSepherosa Ziehau #include <netinet/in_systm.h> 91*15516c77SSepherosa Ziehau #include <netinet/in.h> 92*15516c77SSepherosa Ziehau #include <netinet/ip.h> 93*15516c77SSepherosa Ziehau #include <netinet/ip6.h> 94*15516c77SSepherosa Ziehau #include <netinet/tcp.h> 95*15516c77SSepherosa Ziehau #include <netinet/tcp_lro.h> 96*15516c77SSepherosa Ziehau #include <netinet/udp.h> 97*15516c77SSepherosa Ziehau 98*15516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h> 99*15516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h> 100*15516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h> 101*15516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h> 102*15516c77SSepherosa Ziehau 103*15516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h> 104*15516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h> 105*15516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h> 106*15516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h> 107*15516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h> 108*15516c77SSepherosa Ziehau 109*15516c77SSepherosa Ziehau #include "vmbus_if.h" 110*15516c77SSepherosa Ziehau 111*15516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX 8 112*15516c77SSepherosa Ziehau 113*15516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */ 114*15516c77SSepherosa Ziehau #define HN_TX_DESC_CNT 512 115*15516c77SSepherosa Ziehau 116*15516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN \ 117*15516c77SSepherosa Ziehau (sizeof(struct rndis_packet_msg) + \ 118*15516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) + \ 119*15516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) + \ 120*15516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) + \ 121*15516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE)) 122*15516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY PAGE_SIZE 123*15516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN CACHE_LINE_SIZE 124*15516c77SSepherosa Ziehau 125*15516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY PAGE_SIZE 126*15516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE IP_MAXPACKET 127*15516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE PAGE_SIZE 128*15516c77SSepherosa Ziehau /* -1 for RNDIS packet message */ 129*15516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX (HN_GPACNT_MAX - 1) 130*15516c77SSepherosa Ziehau 131*15516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF 128 132*15516c77SSepherosa Ziehau 133*15516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH 8 134*15516c77SSepherosa Ziehau 135*15516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF (16 * 1024) 136*15516c77SSepherosa Ziehau 137*15516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF 128 138*15516c77SSepherosa Ziehau 139*15516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF (12 * ETHERMTU) 140*15516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF (25 * ETHERMTU) 141*15516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */ 142*15516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp) (2 * (ifp)->if_mtu) 143*15516c77SSepherosa Ziehau 144*15516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF 1 145*15516c77SSepherosa Ziehau 146*15516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc) \ 147*15516c77SSepherosa Ziehau sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev)) 148*15516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc) sx_destroy(&(sc)->hn_lock) 149*15516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc) sx_assert(&(sc)->hn_lock, SA_XLOCKED) 150*15516c77SSepherosa Ziehau #define HN_LOCK(sc) sx_xlock(&(sc)->hn_lock) 151*15516c77SSepherosa Ziehau #define HN_UNLOCK(sc) sx_xunlock(&(sc)->hn_lock) 152*15516c77SSepherosa Ziehau 153*15516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK (CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP) 154*15516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK (CSUM_IP6_TCP | CSUM_IP6_UDP) 155*15516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc) \ 156*15516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK) 157*15516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc) \ 158*15516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK) 159*15516c77SSepherosa Ziehau 160*15516c77SSepherosa Ziehau struct hn_txdesc { 161*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 162*15516c77SSepherosa Ziehau SLIST_ENTRY(hn_txdesc) link; 163*15516c77SSepherosa Ziehau #endif 164*15516c77SSepherosa Ziehau struct mbuf *m; 165*15516c77SSepherosa Ziehau struct hn_tx_ring *txr; 166*15516c77SSepherosa Ziehau int refs; 167*15516c77SSepherosa Ziehau uint32_t flags; /* HN_TXD_FLAG_ */ 168*15516c77SSepherosa Ziehau struct hn_nvs_sendctx send_ctx; 169*15516c77SSepherosa Ziehau uint32_t chim_index; 170*15516c77SSepherosa Ziehau int chim_size; 171*15516c77SSepherosa Ziehau 172*15516c77SSepherosa Ziehau bus_dmamap_t data_dmap; 173*15516c77SSepherosa Ziehau 174*15516c77SSepherosa Ziehau bus_addr_t rndis_pkt_paddr; 175*15516c77SSepherosa Ziehau struct rndis_packet_msg *rndis_pkt; 176*15516c77SSepherosa Ziehau bus_dmamap_t rndis_pkt_dmap; 177*15516c77SSepherosa Ziehau }; 178*15516c77SSepherosa Ziehau 179*15516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST 0x0001 180*15516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP 0x0002 181*15516c77SSepherosa Ziehau 182*15516c77SSepherosa Ziehau struct hn_rxinfo { 183*15516c77SSepherosa Ziehau uint32_t vlan_info; 184*15516c77SSepherosa Ziehau uint32_t csum_info; 185*15516c77SSepherosa Ziehau uint32_t hash_info; 186*15516c77SSepherosa Ziehau uint32_t hash_value; 187*15516c77SSepherosa Ziehau }; 188*15516c77SSepherosa Ziehau 189*15516c77SSepherosa Ziehau #define HN_RXINFO_VLAN 0x0001 190*15516c77SSepherosa Ziehau #define HN_RXINFO_CSUM 0x0002 191*15516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF 0x0004 192*15516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL 0x0008 193*15516c77SSepherosa Ziehau #define HN_RXINFO_ALL \ 194*15516c77SSepherosa Ziehau (HN_RXINFO_VLAN | \ 195*15516c77SSepherosa Ziehau HN_RXINFO_CSUM | \ 196*15516c77SSepherosa Ziehau HN_RXINFO_HASHINF | \ 197*15516c77SSepherosa Ziehau HN_RXINFO_HASHVAL) 198*15516c77SSepherosa Ziehau 199*15516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID 0xffffffff 200*15516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID 0 201*15516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID 0 202*15516c77SSepherosa Ziehau 203*15516c77SSepherosa Ziehau static int hn_probe(device_t); 204*15516c77SSepherosa Ziehau static int hn_attach(device_t); 205*15516c77SSepherosa Ziehau static int hn_detach(device_t); 206*15516c77SSepherosa Ziehau static int hn_shutdown(device_t); 207*15516c77SSepherosa Ziehau static void hn_chan_callback(struct vmbus_channel *, 208*15516c77SSepherosa Ziehau void *); 209*15516c77SSepherosa Ziehau 210*15516c77SSepherosa Ziehau static void hn_init(void *); 211*15516c77SSepherosa Ziehau static int hn_ioctl(struct ifnet *, u_long, caddr_t); 212*15516c77SSepherosa Ziehau static void hn_start(struct ifnet *); 213*15516c77SSepherosa Ziehau static int hn_transmit(struct ifnet *, struct mbuf *); 214*15516c77SSepherosa Ziehau static void hn_xmit_qflush(struct ifnet *); 215*15516c77SSepherosa Ziehau static int hn_ifmedia_upd(struct ifnet *); 216*15516c77SSepherosa Ziehau static void hn_ifmedia_sts(struct ifnet *, 217*15516c77SSepherosa Ziehau struct ifmediareq *); 218*15516c77SSepherosa Ziehau 219*15516c77SSepherosa Ziehau static int hn_rndis_rxinfo(const void *, int, 220*15516c77SSepherosa Ziehau struct hn_rxinfo *); 221*15516c77SSepherosa Ziehau static void hn_rndis_rx_data(struct hn_rx_ring *, 222*15516c77SSepherosa Ziehau const void *, int); 223*15516c77SSepherosa Ziehau static void hn_rndis_rx_status(struct hn_softc *, 224*15516c77SSepherosa Ziehau const void *, int); 225*15516c77SSepherosa Ziehau 226*15516c77SSepherosa Ziehau static void hn_nvs_handle_notify(struct hn_softc *, 227*15516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 228*15516c77SSepherosa Ziehau static void hn_nvs_handle_comp(struct hn_softc *, 229*15516c77SSepherosa Ziehau struct vmbus_channel *, 230*15516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 231*15516c77SSepherosa Ziehau static void hn_nvs_handle_rxbuf(struct hn_rx_ring *, 232*15516c77SSepherosa Ziehau struct vmbus_channel *, 233*15516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 234*15516c77SSepherosa Ziehau static void hn_nvs_ack_rxbuf(struct hn_rx_ring *, 235*15516c77SSepherosa Ziehau struct vmbus_channel *, uint64_t); 236*15516c77SSepherosa Ziehau 237*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 238*15516c77SSepherosa Ziehau static int hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS); 239*15516c77SSepherosa Ziehau static int hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS); 240*15516c77SSepherosa Ziehau #endif 241*15516c77SSepherosa Ziehau static int hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS); 242*15516c77SSepherosa Ziehau static int hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS); 243*15516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 244*15516c77SSepherosa Ziehau static int hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS); 245*15516c77SSepherosa Ziehau #else 246*15516c77SSepherosa Ziehau static int hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS); 247*15516c77SSepherosa Ziehau #endif 248*15516c77SSepherosa Ziehau static int hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 249*15516c77SSepherosa Ziehau static int hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 250*15516c77SSepherosa Ziehau static int hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS); 251*15516c77SSepherosa Ziehau static int hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS); 252*15516c77SSepherosa Ziehau static int hn_caps_sysctl(SYSCTL_HANDLER_ARGS); 253*15516c77SSepherosa Ziehau static int hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS); 254*15516c77SSepherosa Ziehau static int hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS); 255*15516c77SSepherosa Ziehau static int hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS); 256*15516c77SSepherosa Ziehau static int hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS); 257*15516c77SSepherosa Ziehau static int hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS); 258*15516c77SSepherosa Ziehau 259*15516c77SSepherosa Ziehau static void hn_stop(struct hn_softc *); 260*15516c77SSepherosa Ziehau static void hn_init_locked(struct hn_softc *); 261*15516c77SSepherosa Ziehau static int hn_chan_attach(struct hn_softc *, 262*15516c77SSepherosa Ziehau struct vmbus_channel *); 263*15516c77SSepherosa Ziehau static void hn_chan_detach(struct hn_softc *, 264*15516c77SSepherosa Ziehau struct vmbus_channel *); 265*15516c77SSepherosa Ziehau static int hn_attach_subchans(struct hn_softc *); 266*15516c77SSepherosa Ziehau static void hn_detach_allchans(struct hn_softc *); 267*15516c77SSepherosa Ziehau static void hn_chan_rollup(struct hn_rx_ring *, 268*15516c77SSepherosa Ziehau struct hn_tx_ring *); 269*15516c77SSepherosa Ziehau static void hn_set_ring_inuse(struct hn_softc *, int); 270*15516c77SSepherosa Ziehau static int hn_synth_attach(struct hn_softc *, int); 271*15516c77SSepherosa Ziehau static void hn_synth_detach(struct hn_softc *); 272*15516c77SSepherosa Ziehau static int hn_synth_alloc_subchans(struct hn_softc *, 273*15516c77SSepherosa Ziehau int *); 274*15516c77SSepherosa Ziehau static void hn_suspend(struct hn_softc *); 275*15516c77SSepherosa Ziehau static void hn_suspend_data(struct hn_softc *); 276*15516c77SSepherosa Ziehau static void hn_suspend_mgmt(struct hn_softc *); 277*15516c77SSepherosa Ziehau static void hn_resume(struct hn_softc *); 278*15516c77SSepherosa Ziehau static void hn_resume_data(struct hn_softc *); 279*15516c77SSepherosa Ziehau static void hn_resume_mgmt(struct hn_softc *); 280*15516c77SSepherosa Ziehau static void hn_suspend_mgmt_taskfunc(void *, int); 281*15516c77SSepherosa Ziehau static void hn_chan_drain(struct vmbus_channel *); 282*15516c77SSepherosa Ziehau 283*15516c77SSepherosa Ziehau static void hn_update_link_status(struct hn_softc *); 284*15516c77SSepherosa Ziehau static void hn_change_network(struct hn_softc *); 285*15516c77SSepherosa Ziehau static void hn_link_taskfunc(void *, int); 286*15516c77SSepherosa Ziehau static void hn_netchg_init_taskfunc(void *, int); 287*15516c77SSepherosa Ziehau static void hn_netchg_status_taskfunc(void *, int); 288*15516c77SSepherosa Ziehau static void hn_link_status(struct hn_softc *); 289*15516c77SSepherosa Ziehau 290*15516c77SSepherosa Ziehau static int hn_create_rx_data(struct hn_softc *, int); 291*15516c77SSepherosa Ziehau static void hn_destroy_rx_data(struct hn_softc *); 292*15516c77SSepherosa Ziehau static int hn_check_iplen(const struct mbuf *, int); 293*15516c77SSepherosa Ziehau static int hn_set_rxfilter(struct hn_softc *); 294*15516c77SSepherosa Ziehau static int hn_rss_reconfig(struct hn_softc *); 295*15516c77SSepherosa Ziehau static void hn_rss_ind_fixup(struct hn_softc *, int); 296*15516c77SSepherosa Ziehau static int hn_rxpkt(struct hn_rx_ring *, const void *, 297*15516c77SSepherosa Ziehau int, const struct hn_rxinfo *); 298*15516c77SSepherosa Ziehau 299*15516c77SSepherosa Ziehau static int hn_tx_ring_create(struct hn_softc *, int); 300*15516c77SSepherosa Ziehau static void hn_tx_ring_destroy(struct hn_tx_ring *); 301*15516c77SSepherosa Ziehau static int hn_create_tx_data(struct hn_softc *, int); 302*15516c77SSepherosa Ziehau static void hn_fixup_tx_data(struct hn_softc *); 303*15516c77SSepherosa Ziehau static void hn_destroy_tx_data(struct hn_softc *); 304*15516c77SSepherosa Ziehau static void hn_txdesc_dmamap_destroy(struct hn_txdesc *); 305*15516c77SSepherosa Ziehau static int hn_encap(struct hn_tx_ring *, 306*15516c77SSepherosa Ziehau struct hn_txdesc *, struct mbuf **); 307*15516c77SSepherosa Ziehau static int hn_txpkt(struct ifnet *, struct hn_tx_ring *, 308*15516c77SSepherosa Ziehau struct hn_txdesc *); 309*15516c77SSepherosa Ziehau static void hn_set_chim_size(struct hn_softc *, int); 310*15516c77SSepherosa Ziehau static void hn_set_tso_maxsize(struct hn_softc *, int, int); 311*15516c77SSepherosa Ziehau static bool hn_tx_ring_pending(struct hn_tx_ring *); 312*15516c77SSepherosa Ziehau static void hn_tx_ring_qflush(struct hn_tx_ring *); 313*15516c77SSepherosa Ziehau static void hn_resume_tx(struct hn_softc *, int); 314*15516c77SSepherosa Ziehau static int hn_get_txswq_depth(const struct hn_tx_ring *); 315*15516c77SSepherosa Ziehau static void hn_txpkt_done(struct hn_nvs_sendctx *, 316*15516c77SSepherosa Ziehau struct hn_softc *, struct vmbus_channel *, 317*15516c77SSepherosa Ziehau const void *, int); 318*15516c77SSepherosa Ziehau static int hn_txpkt_sglist(struct hn_tx_ring *, 319*15516c77SSepherosa Ziehau struct hn_txdesc *); 320*15516c77SSepherosa Ziehau static int hn_txpkt_chim(struct hn_tx_ring *, 321*15516c77SSepherosa Ziehau struct hn_txdesc *); 322*15516c77SSepherosa Ziehau static int hn_xmit(struct hn_tx_ring *, int); 323*15516c77SSepherosa Ziehau static void hn_xmit_taskfunc(void *, int); 324*15516c77SSepherosa Ziehau static void hn_xmit_txeof(struct hn_tx_ring *); 325*15516c77SSepherosa Ziehau static void hn_xmit_txeof_taskfunc(void *, int); 326*15516c77SSepherosa Ziehau static int hn_start_locked(struct hn_tx_ring *, int); 327*15516c77SSepherosa Ziehau static void hn_start_taskfunc(void *, int); 328*15516c77SSepherosa Ziehau static void hn_start_txeof(struct hn_tx_ring *); 329*15516c77SSepherosa Ziehau static void hn_start_txeof_taskfunc(void *, int); 330*15516c77SSepherosa Ziehau 331*15516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 332*15516c77SSepherosa Ziehau "Hyper-V network interface"); 333*15516c77SSepherosa Ziehau 334*15516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */ 335*15516c77SSepherosa Ziehau static int hn_trust_hosttcp = 1; 336*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN, 337*15516c77SSepherosa Ziehau &hn_trust_hosttcp, 0, 338*15516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 339*15516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 340*15516c77SSepherosa Ziehau 341*15516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */ 342*15516c77SSepherosa Ziehau static int hn_trust_hostudp = 1; 343*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN, 344*15516c77SSepherosa Ziehau &hn_trust_hostudp, 0, 345*15516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 346*15516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 347*15516c77SSepherosa Ziehau 348*15516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */ 349*15516c77SSepherosa Ziehau static int hn_trust_hostip = 1; 350*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN, 351*15516c77SSepherosa Ziehau &hn_trust_hostip, 0, 352*15516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 353*15516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 354*15516c77SSepherosa Ziehau 355*15516c77SSepherosa Ziehau /* Limit TSO burst size */ 356*15516c77SSepherosa Ziehau static int hn_tso_maxlen = IP_MAXPACKET; 357*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN, 358*15516c77SSepherosa Ziehau &hn_tso_maxlen, 0, "TSO burst limit"); 359*15516c77SSepherosa Ziehau 360*15516c77SSepherosa Ziehau /* Limit chimney send size */ 361*15516c77SSepherosa Ziehau static int hn_tx_chimney_size = 0; 362*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN, 363*15516c77SSepherosa Ziehau &hn_tx_chimney_size, 0, "Chimney send packet size limit"); 364*15516c77SSepherosa Ziehau 365*15516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */ 366*15516c77SSepherosa Ziehau static int hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF; 367*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN, 368*15516c77SSepherosa Ziehau &hn_direct_tx_size, 0, "Size of the packet for direct transmission"); 369*15516c77SSepherosa Ziehau 370*15516c77SSepherosa Ziehau /* # of LRO entries per RX ring */ 371*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 372*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 373*15516c77SSepherosa Ziehau static int hn_lro_entry_count = HN_LROENT_CNT_DEF; 374*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN, 375*15516c77SSepherosa Ziehau &hn_lro_entry_count, 0, "LRO entry count"); 376*15516c77SSepherosa Ziehau #endif 377*15516c77SSepherosa Ziehau #endif 378*15516c77SSepherosa Ziehau 379*15516c77SSepherosa Ziehau /* Use shared TX taskqueue */ 380*15516c77SSepherosa Ziehau static int hn_share_tx_taskq = 0; 381*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, share_tx_taskq, CTLFLAG_RDTUN, 382*15516c77SSepherosa Ziehau &hn_share_tx_taskq, 0, "Enable shared TX taskqueue"); 383*15516c77SSepherosa Ziehau 384*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 385*15516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 0; 386*15516c77SSepherosa Ziehau #else 387*15516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 1; 388*15516c77SSepherosa Ziehau #endif 389*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD, 390*15516c77SSepherosa Ziehau &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors"); 391*15516c77SSepherosa Ziehau 392*15516c77SSepherosa Ziehau /* Bind TX taskqueue to the target CPU */ 393*15516c77SSepherosa Ziehau static int hn_bind_tx_taskq = -1; 394*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, bind_tx_taskq, CTLFLAG_RDTUN, 395*15516c77SSepherosa Ziehau &hn_bind_tx_taskq, 0, "Bind TX taskqueue to the specified cpu"); 396*15516c77SSepherosa Ziehau 397*15516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */ 398*15516c77SSepherosa Ziehau static int hn_use_if_start = 0; 399*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN, 400*15516c77SSepherosa Ziehau &hn_use_if_start, 0, "Use if_start TX method"); 401*15516c77SSepherosa Ziehau 402*15516c77SSepherosa Ziehau /* # of channels to use */ 403*15516c77SSepherosa Ziehau static int hn_chan_cnt = 0; 404*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN, 405*15516c77SSepherosa Ziehau &hn_chan_cnt, 0, 406*15516c77SSepherosa Ziehau "# of channels to use; each channel has one RX ring and one TX ring"); 407*15516c77SSepherosa Ziehau 408*15516c77SSepherosa Ziehau /* # of transmit rings to use */ 409*15516c77SSepherosa Ziehau static int hn_tx_ring_cnt = 0; 410*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN, 411*15516c77SSepherosa Ziehau &hn_tx_ring_cnt, 0, "# of TX rings to use"); 412*15516c77SSepherosa Ziehau 413*15516c77SSepherosa Ziehau /* Software TX ring deptch */ 414*15516c77SSepherosa Ziehau static int hn_tx_swq_depth = 0; 415*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN, 416*15516c77SSepherosa Ziehau &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING"); 417*15516c77SSepherosa Ziehau 418*15516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */ 419*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 420*15516c77SSepherosa Ziehau static u_int hn_lro_mbufq_depth = 0; 421*15516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN, 422*15516c77SSepherosa Ziehau &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue"); 423*15516c77SSepherosa Ziehau #endif 424*15516c77SSepherosa Ziehau 425*15516c77SSepherosa Ziehau static u_int hn_cpu_index; /* next CPU for channel */ 426*15516c77SSepherosa Ziehau static struct taskqueue *hn_tx_taskq; /* shared TX taskqueue */ 427*15516c77SSepherosa Ziehau 428*15516c77SSepherosa Ziehau static const uint8_t 429*15516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = { 430*15516c77SSepherosa Ziehau 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 431*15516c77SSepherosa Ziehau 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 432*15516c77SSepherosa Ziehau 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 433*15516c77SSepherosa Ziehau 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 434*15516c77SSepherosa Ziehau 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa 435*15516c77SSepherosa Ziehau }; 436*15516c77SSepherosa Ziehau 437*15516c77SSepherosa Ziehau static device_method_t hn_methods[] = { 438*15516c77SSepherosa Ziehau /* Device interface */ 439*15516c77SSepherosa Ziehau DEVMETHOD(device_probe, hn_probe), 440*15516c77SSepherosa Ziehau DEVMETHOD(device_attach, hn_attach), 441*15516c77SSepherosa Ziehau DEVMETHOD(device_detach, hn_detach), 442*15516c77SSepherosa Ziehau DEVMETHOD(device_shutdown, hn_shutdown), 443*15516c77SSepherosa Ziehau DEVMETHOD_END 444*15516c77SSepherosa Ziehau }; 445*15516c77SSepherosa Ziehau 446*15516c77SSepherosa Ziehau static driver_t hn_driver = { 447*15516c77SSepherosa Ziehau "hn", 448*15516c77SSepherosa Ziehau hn_methods, 449*15516c77SSepherosa Ziehau sizeof(struct hn_softc) 450*15516c77SSepherosa Ziehau }; 451*15516c77SSepherosa Ziehau 452*15516c77SSepherosa Ziehau static devclass_t hn_devclass; 453*15516c77SSepherosa Ziehau 454*15516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0); 455*15516c77SSepherosa Ziehau MODULE_VERSION(hn, 1); 456*15516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1); 457*15516c77SSepherosa Ziehau 458*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 459*15516c77SSepherosa Ziehau static void 460*15516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim) 461*15516c77SSepherosa Ziehau { 462*15516c77SSepherosa Ziehau int i; 463*15516c77SSepherosa Ziehau 464*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) 465*15516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim; 466*15516c77SSepherosa Ziehau } 467*15516c77SSepherosa Ziehau #endif 468*15516c77SSepherosa Ziehau 469*15516c77SSepherosa Ziehau static int 470*15516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd) 471*15516c77SSepherosa Ziehau { 472*15516c77SSepherosa Ziehau 473*15516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 474*15516c77SSepherosa Ziehau txd->chim_size == 0, ("invalid rndis sglist txd")); 475*15516c77SSepherosa Ziehau return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA, 476*15516c77SSepherosa Ziehau &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt)); 477*15516c77SSepherosa Ziehau } 478*15516c77SSepherosa Ziehau 479*15516c77SSepherosa Ziehau static int 480*15516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd) 481*15516c77SSepherosa Ziehau { 482*15516c77SSepherosa Ziehau struct hn_nvs_rndis rndis; 483*15516c77SSepherosa Ziehau 484*15516c77SSepherosa Ziehau KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID && 485*15516c77SSepherosa Ziehau txd->chim_size > 0, ("invalid rndis chim txd")); 486*15516c77SSepherosa Ziehau 487*15516c77SSepherosa Ziehau rndis.nvs_type = HN_NVS_TYPE_RNDIS; 488*15516c77SSepherosa Ziehau rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA; 489*15516c77SSepherosa Ziehau rndis.nvs_chim_idx = txd->chim_index; 490*15516c77SSepherosa Ziehau rndis.nvs_chim_sz = txd->chim_size; 491*15516c77SSepherosa Ziehau 492*15516c77SSepherosa Ziehau return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC, 493*15516c77SSepherosa Ziehau &rndis, sizeof(rndis), &txd->send_ctx)); 494*15516c77SSepherosa Ziehau } 495*15516c77SSepherosa Ziehau 496*15516c77SSepherosa Ziehau static __inline uint32_t 497*15516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc) 498*15516c77SSepherosa Ziehau { 499*15516c77SSepherosa Ziehau int i, bmap_cnt = sc->hn_chim_bmap_cnt; 500*15516c77SSepherosa Ziehau u_long *bmap = sc->hn_chim_bmap; 501*15516c77SSepherosa Ziehau uint32_t ret = HN_NVS_CHIM_IDX_INVALID; 502*15516c77SSepherosa Ziehau 503*15516c77SSepherosa Ziehau for (i = 0; i < bmap_cnt; ++i) { 504*15516c77SSepherosa Ziehau int idx; 505*15516c77SSepherosa Ziehau 506*15516c77SSepherosa Ziehau idx = ffsl(~bmap[i]); 507*15516c77SSepherosa Ziehau if (idx == 0) 508*15516c77SSepherosa Ziehau continue; 509*15516c77SSepherosa Ziehau 510*15516c77SSepherosa Ziehau --idx; /* ffsl is 1-based */ 511*15516c77SSepherosa Ziehau KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt, 512*15516c77SSepherosa Ziehau ("invalid i %d and idx %d", i, idx)); 513*15516c77SSepherosa Ziehau 514*15516c77SSepherosa Ziehau if (atomic_testandset_long(&bmap[i], idx)) 515*15516c77SSepherosa Ziehau continue; 516*15516c77SSepherosa Ziehau 517*15516c77SSepherosa Ziehau ret = i * LONG_BIT + idx; 518*15516c77SSepherosa Ziehau break; 519*15516c77SSepherosa Ziehau } 520*15516c77SSepherosa Ziehau return (ret); 521*15516c77SSepherosa Ziehau } 522*15516c77SSepherosa Ziehau 523*15516c77SSepherosa Ziehau static __inline void 524*15516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx) 525*15516c77SSepherosa Ziehau { 526*15516c77SSepherosa Ziehau u_long mask; 527*15516c77SSepherosa Ziehau uint32_t idx; 528*15516c77SSepherosa Ziehau 529*15516c77SSepherosa Ziehau idx = chim_idx / LONG_BIT; 530*15516c77SSepherosa Ziehau KASSERT(idx < sc->hn_chim_bmap_cnt, 531*15516c77SSepherosa Ziehau ("invalid chimney index 0x%x", chim_idx)); 532*15516c77SSepherosa Ziehau 533*15516c77SSepherosa Ziehau mask = 1UL << (chim_idx % LONG_BIT); 534*15516c77SSepherosa Ziehau KASSERT(sc->hn_chim_bmap[idx] & mask, 535*15516c77SSepherosa Ziehau ("index bitmap 0x%lx, chimney index %u, " 536*15516c77SSepherosa Ziehau "bitmap idx %d, bitmask 0x%lx", 537*15516c77SSepherosa Ziehau sc->hn_chim_bmap[idx], chim_idx, idx, mask)); 538*15516c77SSepherosa Ziehau 539*15516c77SSepherosa Ziehau atomic_clear_long(&sc->hn_chim_bmap[idx], mask); 540*15516c77SSepherosa Ziehau } 541*15516c77SSepherosa Ziehau 542*15516c77SSepherosa Ziehau static int 543*15516c77SSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc) 544*15516c77SSepherosa Ziehau { 545*15516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 546*15516c77SSepherosa Ziehau uint32_t filter; 547*15516c77SSepherosa Ziehau int error = 0; 548*15516c77SSepherosa Ziehau 549*15516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 550*15516c77SSepherosa Ziehau 551*15516c77SSepherosa Ziehau if (ifp->if_flags & IFF_PROMISC) { 552*15516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_PROMISCUOUS; 553*15516c77SSepherosa Ziehau } else { 554*15516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_DIRECTED; 555*15516c77SSepherosa Ziehau if (ifp->if_flags & IFF_BROADCAST) 556*15516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_BROADCAST; 557*15516c77SSepherosa Ziehau #ifdef notyet 558*15516c77SSepherosa Ziehau /* 559*15516c77SSepherosa Ziehau * See the comment in SIOCADDMULTI/SIOCDELMULTI. 560*15516c77SSepherosa Ziehau */ 561*15516c77SSepherosa Ziehau /* TODO: support multicast list */ 562*15516c77SSepherosa Ziehau if ((ifp->if_flags & IFF_ALLMULTI) || 563*15516c77SSepherosa Ziehau !TAILQ_EMPTY(&ifp->if_multiaddrs)) 564*15516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 565*15516c77SSepherosa Ziehau #else 566*15516c77SSepherosa Ziehau /* Always enable ALLMULTI */ 567*15516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 568*15516c77SSepherosa Ziehau #endif 569*15516c77SSepherosa Ziehau } 570*15516c77SSepherosa Ziehau 571*15516c77SSepherosa Ziehau if (sc->hn_rx_filter != filter) { 572*15516c77SSepherosa Ziehau error = hn_rndis_set_rxfilter(sc, filter); 573*15516c77SSepherosa Ziehau if (!error) 574*15516c77SSepherosa Ziehau sc->hn_rx_filter = filter; 575*15516c77SSepherosa Ziehau } 576*15516c77SSepherosa Ziehau return (error); 577*15516c77SSepherosa Ziehau } 578*15516c77SSepherosa Ziehau 579*15516c77SSepherosa Ziehau static int 580*15516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr) 581*15516c77SSepherosa Ziehau { 582*15516c77SSepherosa Ziehau 583*15516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet")); 584*15516c77SSepherosa Ziehau if (hn_tx_swq_depth < txr->hn_txdesc_cnt) 585*15516c77SSepherosa Ziehau return txr->hn_txdesc_cnt; 586*15516c77SSepherosa Ziehau return hn_tx_swq_depth; 587*15516c77SSepherosa Ziehau } 588*15516c77SSepherosa Ziehau 589*15516c77SSepherosa Ziehau static int 590*15516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc) 591*15516c77SSepherosa Ziehau { 592*15516c77SSepherosa Ziehau int error; 593*15516c77SSepherosa Ziehau 594*15516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 595*15516c77SSepherosa Ziehau 596*15516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 597*15516c77SSepherosa Ziehau return (ENXIO); 598*15516c77SSepherosa Ziehau 599*15516c77SSepherosa Ziehau /* 600*15516c77SSepherosa Ziehau * Disable RSS first. 601*15516c77SSepherosa Ziehau * 602*15516c77SSepherosa Ziehau * NOTE: 603*15516c77SSepherosa Ziehau * Direct reconfiguration by setting the UNCHG flags does 604*15516c77SSepherosa Ziehau * _not_ work properly. 605*15516c77SSepherosa Ziehau */ 606*15516c77SSepherosa Ziehau if (bootverbose) 607*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "disable RSS\n"); 608*15516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE); 609*15516c77SSepherosa Ziehau if (error) { 610*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS disable failed\n"); 611*15516c77SSepherosa Ziehau return (error); 612*15516c77SSepherosa Ziehau } 613*15516c77SSepherosa Ziehau 614*15516c77SSepherosa Ziehau /* 615*15516c77SSepherosa Ziehau * Reenable the RSS w/ the updated RSS key or indirect 616*15516c77SSepherosa Ziehau * table. 617*15516c77SSepherosa Ziehau */ 618*15516c77SSepherosa Ziehau if (bootverbose) 619*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "reconfig RSS\n"); 620*15516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 621*15516c77SSepherosa Ziehau if (error) { 622*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS reconfig failed\n"); 623*15516c77SSepherosa Ziehau return (error); 624*15516c77SSepherosa Ziehau } 625*15516c77SSepherosa Ziehau return (0); 626*15516c77SSepherosa Ziehau } 627*15516c77SSepherosa Ziehau 628*15516c77SSepherosa Ziehau static void 629*15516c77SSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc, int nchan) 630*15516c77SSepherosa Ziehau { 631*15516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 632*15516c77SSepherosa Ziehau int i; 633*15516c77SSepherosa Ziehau 634*15516c77SSepherosa Ziehau KASSERT(nchan > 1, ("invalid # of channels %d", nchan)); 635*15516c77SSepherosa Ziehau 636*15516c77SSepherosa Ziehau /* 637*15516c77SSepherosa Ziehau * Check indirect table to make sure that all channels in it 638*15516c77SSepherosa Ziehau * can be used. 639*15516c77SSepherosa Ziehau */ 640*15516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 641*15516c77SSepherosa Ziehau if (rss->rss_ind[i] >= nchan) { 642*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, 643*15516c77SSepherosa Ziehau "RSS indirect table %d fixup: %u -> %d\n", 644*15516c77SSepherosa Ziehau i, rss->rss_ind[i], nchan - 1); 645*15516c77SSepherosa Ziehau rss->rss_ind[i] = nchan - 1; 646*15516c77SSepherosa Ziehau } 647*15516c77SSepherosa Ziehau } 648*15516c77SSepherosa Ziehau } 649*15516c77SSepherosa Ziehau 650*15516c77SSepherosa Ziehau static int 651*15516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused) 652*15516c77SSepherosa Ziehau { 653*15516c77SSepherosa Ziehau 654*15516c77SSepherosa Ziehau return EOPNOTSUPP; 655*15516c77SSepherosa Ziehau } 656*15516c77SSepherosa Ziehau 657*15516c77SSepherosa Ziehau static void 658*15516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 659*15516c77SSepherosa Ziehau { 660*15516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 661*15516c77SSepherosa Ziehau 662*15516c77SSepherosa Ziehau ifmr->ifm_status = IFM_AVALID; 663*15516c77SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 664*15516c77SSepherosa Ziehau 665*15516c77SSepherosa Ziehau if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) { 666*15516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_NONE; 667*15516c77SSepherosa Ziehau return; 668*15516c77SSepherosa Ziehau } 669*15516c77SSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 670*15516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 671*15516c77SSepherosa Ziehau } 672*15516c77SSepherosa Ziehau 673*15516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ 674*15516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = { 675*15516c77SSepherosa Ziehau .hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 676*15516c77SSepherosa Ziehau 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E} 677*15516c77SSepherosa Ziehau }; 678*15516c77SSepherosa Ziehau 679*15516c77SSepherosa Ziehau static int 680*15516c77SSepherosa Ziehau hn_probe(device_t dev) 681*15516c77SSepherosa Ziehau { 682*15516c77SSepherosa Ziehau 683*15516c77SSepherosa Ziehau if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, 684*15516c77SSepherosa Ziehau &g_net_vsc_device_type) == 0) { 685*15516c77SSepherosa Ziehau device_set_desc(dev, "Hyper-V Network Interface"); 686*15516c77SSepherosa Ziehau return BUS_PROBE_DEFAULT; 687*15516c77SSepherosa Ziehau } 688*15516c77SSepherosa Ziehau return ENXIO; 689*15516c77SSepherosa Ziehau } 690*15516c77SSepherosa Ziehau 691*15516c77SSepherosa Ziehau static int 692*15516c77SSepherosa Ziehau hn_attach(device_t dev) 693*15516c77SSepherosa Ziehau { 694*15516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 695*15516c77SSepherosa Ziehau struct sysctl_oid_list *child; 696*15516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 697*15516c77SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 698*15516c77SSepherosa Ziehau struct ifnet *ifp = NULL; 699*15516c77SSepherosa Ziehau int error, ring_cnt, tx_ring_cnt; 700*15516c77SSepherosa Ziehau 701*15516c77SSepherosa Ziehau sc->hn_dev = dev; 702*15516c77SSepherosa Ziehau sc->hn_prichan = vmbus_get_channel(dev); 703*15516c77SSepherosa Ziehau HN_LOCK_INIT(sc); 704*15516c77SSepherosa Ziehau 705*15516c77SSepherosa Ziehau /* 706*15516c77SSepherosa Ziehau * Setup taskqueue for transmission. 707*15516c77SSepherosa Ziehau */ 708*15516c77SSepherosa Ziehau if (hn_tx_taskq == NULL) { 709*15516c77SSepherosa Ziehau sc->hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK, 710*15516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_tx_taskq); 711*15516c77SSepherosa Ziehau if (hn_bind_tx_taskq >= 0) { 712*15516c77SSepherosa Ziehau int cpu = hn_bind_tx_taskq; 713*15516c77SSepherosa Ziehau cpuset_t cpu_set; 714*15516c77SSepherosa Ziehau 715*15516c77SSepherosa Ziehau if (cpu > mp_ncpus - 1) 716*15516c77SSepherosa Ziehau cpu = mp_ncpus - 1; 717*15516c77SSepherosa Ziehau CPU_SETOF(cpu, &cpu_set); 718*15516c77SSepherosa Ziehau taskqueue_start_threads_cpuset(&sc->hn_tx_taskq, 1, 719*15516c77SSepherosa Ziehau PI_NET, &cpu_set, "%s tx", 720*15516c77SSepherosa Ziehau device_get_nameunit(dev)); 721*15516c77SSepherosa Ziehau } else { 722*15516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_tx_taskq, 1, PI_NET, 723*15516c77SSepherosa Ziehau "%s tx", device_get_nameunit(dev)); 724*15516c77SSepherosa Ziehau } 725*15516c77SSepherosa Ziehau } else { 726*15516c77SSepherosa Ziehau sc->hn_tx_taskq = hn_tx_taskq; 727*15516c77SSepherosa Ziehau } 728*15516c77SSepherosa Ziehau 729*15516c77SSepherosa Ziehau /* 730*15516c77SSepherosa Ziehau * Setup taskqueue for mangement tasks, e.g. link status. 731*15516c77SSepherosa Ziehau */ 732*15516c77SSepherosa Ziehau sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK, 733*15516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0); 734*15516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt", 735*15516c77SSepherosa Ziehau device_get_nameunit(dev)); 736*15516c77SSepherosa Ziehau TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc); 737*15516c77SSepherosa Ziehau TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc); 738*15516c77SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0, 739*15516c77SSepherosa Ziehau hn_netchg_status_taskfunc, sc); 740*15516c77SSepherosa Ziehau 741*15516c77SSepherosa Ziehau /* 742*15516c77SSepherosa Ziehau * Allocate ifnet and setup its name earlier, so that if_printf 743*15516c77SSepherosa Ziehau * can be used by functions, which will be called after 744*15516c77SSepherosa Ziehau * ether_ifattach(). 745*15516c77SSepherosa Ziehau */ 746*15516c77SSepherosa Ziehau ifp = sc->hn_ifp = if_alloc(IFT_ETHER); 747*15516c77SSepherosa Ziehau ifp->if_softc = sc; 748*15516c77SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 749*15516c77SSepherosa Ziehau 750*15516c77SSepherosa Ziehau /* 751*15516c77SSepherosa Ziehau * Initialize ifmedia earlier so that it can be unconditionally 752*15516c77SSepherosa Ziehau * destroyed, if error happened later on. 753*15516c77SSepherosa Ziehau */ 754*15516c77SSepherosa Ziehau ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts); 755*15516c77SSepherosa Ziehau 756*15516c77SSepherosa Ziehau /* 757*15516c77SSepherosa Ziehau * Figure out the # of RX rings (ring_cnt) and the # of TX rings 758*15516c77SSepherosa Ziehau * to use (tx_ring_cnt). 759*15516c77SSepherosa Ziehau * 760*15516c77SSepherosa Ziehau * NOTE: 761*15516c77SSepherosa Ziehau * The # of RX rings to use is same as the # of channels to use. 762*15516c77SSepherosa Ziehau */ 763*15516c77SSepherosa Ziehau ring_cnt = hn_chan_cnt; 764*15516c77SSepherosa Ziehau if (ring_cnt <= 0) { 765*15516c77SSepherosa Ziehau /* Default */ 766*15516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 767*15516c77SSepherosa Ziehau if (ring_cnt > HN_RING_CNT_DEF_MAX) 768*15516c77SSepherosa Ziehau ring_cnt = HN_RING_CNT_DEF_MAX; 769*15516c77SSepherosa Ziehau } else if (ring_cnt > mp_ncpus) { 770*15516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 771*15516c77SSepherosa Ziehau } 772*15516c77SSepherosa Ziehau 773*15516c77SSepherosa Ziehau tx_ring_cnt = hn_tx_ring_cnt; 774*15516c77SSepherosa Ziehau if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt) 775*15516c77SSepherosa Ziehau tx_ring_cnt = ring_cnt; 776*15516c77SSepherosa Ziehau if (hn_use_if_start) { 777*15516c77SSepherosa Ziehau /* ifnet.if_start only needs one TX ring. */ 778*15516c77SSepherosa Ziehau tx_ring_cnt = 1; 779*15516c77SSepherosa Ziehau } 780*15516c77SSepherosa Ziehau 781*15516c77SSepherosa Ziehau /* 782*15516c77SSepherosa Ziehau * Set the leader CPU for channels. 783*15516c77SSepherosa Ziehau */ 784*15516c77SSepherosa Ziehau sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus; 785*15516c77SSepherosa Ziehau 786*15516c77SSepherosa Ziehau /* 787*15516c77SSepherosa Ziehau * Create enough TX/RX rings, even if only limited number of 788*15516c77SSepherosa Ziehau * channels can be allocated. 789*15516c77SSepherosa Ziehau */ 790*15516c77SSepherosa Ziehau error = hn_create_tx_data(sc, tx_ring_cnt); 791*15516c77SSepherosa Ziehau if (error) 792*15516c77SSepherosa Ziehau goto failed; 793*15516c77SSepherosa Ziehau error = hn_create_rx_data(sc, ring_cnt); 794*15516c77SSepherosa Ziehau if (error) 795*15516c77SSepherosa Ziehau goto failed; 796*15516c77SSepherosa Ziehau 797*15516c77SSepherosa Ziehau /* 798*15516c77SSepherosa Ziehau * Create transaction context for NVS and RNDIS transactions. 799*15516c77SSepherosa Ziehau */ 800*15516c77SSepherosa Ziehau sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev), 801*15516c77SSepherosa Ziehau HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0); 802*15516c77SSepherosa Ziehau if (sc->hn_xact == NULL) 803*15516c77SSepherosa Ziehau goto failed; 804*15516c77SSepherosa Ziehau 805*15516c77SSepherosa Ziehau /* 806*15516c77SSepherosa Ziehau * Attach the synthetic parts, i.e. NVS and RNDIS. 807*15516c77SSepherosa Ziehau */ 808*15516c77SSepherosa Ziehau error = hn_synth_attach(sc, ETHERMTU); 809*15516c77SSepherosa Ziehau if (error) 810*15516c77SSepherosa Ziehau goto failed; 811*15516c77SSepherosa Ziehau 812*15516c77SSepherosa Ziehau error = hn_rndis_get_eaddr(sc, eaddr); 813*15516c77SSepherosa Ziehau if (error) 814*15516c77SSepherosa Ziehau goto failed; 815*15516c77SSepherosa Ziehau 816*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 817*15516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 818*15516c77SSepherosa Ziehau /* 819*15516c77SSepherosa Ziehau * Reduce TCP segment aggregation limit for multiple 820*15516c77SSepherosa Ziehau * RX rings to increase ACK timeliness. 821*15516c77SSepherosa Ziehau */ 822*15516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF); 823*15516c77SSepherosa Ziehau } 824*15516c77SSepherosa Ziehau #endif 825*15516c77SSepherosa Ziehau 826*15516c77SSepherosa Ziehau /* 827*15516c77SSepherosa Ziehau * Fixup TX stuffs after synthetic parts are attached. 828*15516c77SSepherosa Ziehau */ 829*15516c77SSepherosa Ziehau hn_fixup_tx_data(sc); 830*15516c77SSepherosa Ziehau 831*15516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 832*15516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 833*15516c77SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD, 834*15516c77SSepherosa Ziehau &sc->hn_nvs_ver, 0, "NVS version"); 835*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version", 836*15516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 837*15516c77SSepherosa Ziehau hn_ndis_version_sysctl, "A", "NDIS version"); 838*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps", 839*15516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 840*15516c77SSepherosa Ziehau hn_caps_sysctl, "A", "capabilities"); 841*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist", 842*15516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 843*15516c77SSepherosa Ziehau hn_hwassist_sysctl, "A", "hwassist"); 844*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter", 845*15516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 846*15516c77SSepherosa Ziehau hn_rxfilter_sysctl, "A", "rxfilter"); 847*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash", 848*15516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 849*15516c77SSepherosa Ziehau hn_rss_hash_sysctl, "A", "RSS hash"); 850*15516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size", 851*15516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count"); 852*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key", 853*15516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 854*15516c77SSepherosa Ziehau hn_rss_key_sysctl, "IU", "RSS key"); 855*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind", 856*15516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 857*15516c77SSepherosa Ziehau hn_rss_ind_sysctl, "IU", "RSS indirect table"); 858*15516c77SSepherosa Ziehau 859*15516c77SSepherosa Ziehau /* 860*15516c77SSepherosa Ziehau * Setup the ifmedia, which has been initialized earlier. 861*15516c77SSepherosa Ziehau */ 862*15516c77SSepherosa Ziehau ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL); 863*15516c77SSepherosa Ziehau ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO); 864*15516c77SSepherosa Ziehau /* XXX ifmedia_set really should do this for us */ 865*15516c77SSepherosa Ziehau sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media; 866*15516c77SSepherosa Ziehau 867*15516c77SSepherosa Ziehau /* 868*15516c77SSepherosa Ziehau * Setup the ifnet for this interface. 869*15516c77SSepherosa Ziehau */ 870*15516c77SSepherosa Ziehau 871*15516c77SSepherosa Ziehau ifp->if_baudrate = IF_Gbps(10); 872*15516c77SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 873*15516c77SSepherosa Ziehau ifp->if_ioctl = hn_ioctl; 874*15516c77SSepherosa Ziehau ifp->if_init = hn_init; 875*15516c77SSepherosa Ziehau if (hn_use_if_start) { 876*15516c77SSepherosa Ziehau int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]); 877*15516c77SSepherosa Ziehau 878*15516c77SSepherosa Ziehau ifp->if_start = hn_start; 879*15516c77SSepherosa Ziehau IFQ_SET_MAXLEN(&ifp->if_snd, qdepth); 880*15516c77SSepherosa Ziehau ifp->if_snd.ifq_drv_maxlen = qdepth - 1; 881*15516c77SSepherosa Ziehau IFQ_SET_READY(&ifp->if_snd); 882*15516c77SSepherosa Ziehau } else { 883*15516c77SSepherosa Ziehau ifp->if_transmit = hn_transmit; 884*15516c77SSepherosa Ziehau ifp->if_qflush = hn_xmit_qflush; 885*15516c77SSepherosa Ziehau } 886*15516c77SSepherosa Ziehau 887*15516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO; 888*15516c77SSepherosa Ziehau #ifdef foo 889*15516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 890*15516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM_IPV6; 891*15516c77SSepherosa Ziehau #endif 892*15516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_VLAN) { 893*15516c77SSepherosa Ziehau /* XXX not sure about VLAN_MTU. */ 894*15516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 895*15516c77SSepherosa Ziehau } 896*15516c77SSepherosa Ziehau 897*15516c77SSepherosa Ziehau ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist; 898*15516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP_MASK) 899*15516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM; 900*15516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP6_MASK) 901*15516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM_IPV6; 902*15516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO4) { 903*15516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO4; 904*15516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 905*15516c77SSepherosa Ziehau } 906*15516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO6) { 907*15516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO6; 908*15516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 909*15516c77SSepherosa Ziehau } 910*15516c77SSepherosa Ziehau 911*15516c77SSepherosa Ziehau /* Enable all available capabilities by default. */ 912*15516c77SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 913*15516c77SSepherosa Ziehau 914*15516c77SSepherosa Ziehau if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) { 915*15516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU); 916*15516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; 917*15516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 918*15516c77SSepherosa Ziehau } 919*15516c77SSepherosa Ziehau 920*15516c77SSepherosa Ziehau ether_ifattach(ifp, eaddr); 921*15516c77SSepherosa Ziehau 922*15516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) { 923*15516c77SSepherosa Ziehau if_printf(ifp, "TSO segcnt %u segsz %u\n", 924*15516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize); 925*15516c77SSepherosa Ziehau } 926*15516c77SSepherosa Ziehau 927*15516c77SSepherosa Ziehau /* Inform the upper layer about the long frame support. */ 928*15516c77SSepherosa Ziehau ifp->if_hdrlen = sizeof(struct ether_vlan_header); 929*15516c77SSepherosa Ziehau 930*15516c77SSepherosa Ziehau /* 931*15516c77SSepherosa Ziehau * Kick off link status check. 932*15516c77SSepherosa Ziehau */ 933*15516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 934*15516c77SSepherosa Ziehau hn_update_link_status(sc); 935*15516c77SSepherosa Ziehau 936*15516c77SSepherosa Ziehau return (0); 937*15516c77SSepherosa Ziehau failed: 938*15516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) 939*15516c77SSepherosa Ziehau hn_synth_detach(sc); 940*15516c77SSepherosa Ziehau hn_detach(dev); 941*15516c77SSepherosa Ziehau return (error); 942*15516c77SSepherosa Ziehau } 943*15516c77SSepherosa Ziehau 944*15516c77SSepherosa Ziehau static int 945*15516c77SSepherosa Ziehau hn_detach(device_t dev) 946*15516c77SSepherosa Ziehau { 947*15516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 948*15516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 949*15516c77SSepherosa Ziehau 950*15516c77SSepherosa Ziehau if (device_is_attached(dev)) { 951*15516c77SSepherosa Ziehau HN_LOCK(sc); 952*15516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 953*15516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 954*15516c77SSepherosa Ziehau hn_stop(sc); 955*15516c77SSepherosa Ziehau /* 956*15516c77SSepherosa Ziehau * NOTE: 957*15516c77SSepherosa Ziehau * hn_stop() only suspends data, so managment 958*15516c77SSepherosa Ziehau * stuffs have to be suspended manually here. 959*15516c77SSepherosa Ziehau */ 960*15516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 961*15516c77SSepherosa Ziehau hn_synth_detach(sc); 962*15516c77SSepherosa Ziehau } 963*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 964*15516c77SSepherosa Ziehau ether_ifdetach(ifp); 965*15516c77SSepherosa Ziehau } 966*15516c77SSepherosa Ziehau 967*15516c77SSepherosa Ziehau ifmedia_removeall(&sc->hn_media); 968*15516c77SSepherosa Ziehau hn_destroy_rx_data(sc); 969*15516c77SSepherosa Ziehau hn_destroy_tx_data(sc); 970*15516c77SSepherosa Ziehau 971*15516c77SSepherosa Ziehau if (sc->hn_tx_taskq != hn_tx_taskq) 972*15516c77SSepherosa Ziehau taskqueue_free(sc->hn_tx_taskq); 973*15516c77SSepherosa Ziehau taskqueue_free(sc->hn_mgmt_taskq0); 974*15516c77SSepherosa Ziehau 975*15516c77SSepherosa Ziehau if (sc->hn_xact != NULL) 976*15516c77SSepherosa Ziehau vmbus_xact_ctx_destroy(sc->hn_xact); 977*15516c77SSepherosa Ziehau 978*15516c77SSepherosa Ziehau if_free(ifp); 979*15516c77SSepherosa Ziehau 980*15516c77SSepherosa Ziehau HN_LOCK_DESTROY(sc); 981*15516c77SSepherosa Ziehau return (0); 982*15516c77SSepherosa Ziehau } 983*15516c77SSepherosa Ziehau 984*15516c77SSepherosa Ziehau static int 985*15516c77SSepherosa Ziehau hn_shutdown(device_t dev) 986*15516c77SSepherosa Ziehau { 987*15516c77SSepherosa Ziehau 988*15516c77SSepherosa Ziehau return (0); 989*15516c77SSepherosa Ziehau } 990*15516c77SSepherosa Ziehau 991*15516c77SSepherosa Ziehau static void 992*15516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc) 993*15516c77SSepherosa Ziehau { 994*15516c77SSepherosa Ziehau uint32_t link_status; 995*15516c77SSepherosa Ziehau int error; 996*15516c77SSepherosa Ziehau 997*15516c77SSepherosa Ziehau error = hn_rndis_get_linkstatus(sc, &link_status); 998*15516c77SSepherosa Ziehau if (error) { 999*15516c77SSepherosa Ziehau /* XXX what to do? */ 1000*15516c77SSepherosa Ziehau return; 1001*15516c77SSepherosa Ziehau } 1002*15516c77SSepherosa Ziehau 1003*15516c77SSepherosa Ziehau if (link_status == NDIS_MEDIA_STATE_CONNECTED) 1004*15516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_LINKUP; 1005*15516c77SSepherosa Ziehau else 1006*15516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 1007*15516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, 1008*15516c77SSepherosa Ziehau (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ? 1009*15516c77SSepherosa Ziehau LINK_STATE_UP : LINK_STATE_DOWN); 1010*15516c77SSepherosa Ziehau } 1011*15516c77SSepherosa Ziehau 1012*15516c77SSepherosa Ziehau static void 1013*15516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused) 1014*15516c77SSepherosa Ziehau { 1015*15516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 1016*15516c77SSepherosa Ziehau 1017*15516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 1018*15516c77SSepherosa Ziehau return; 1019*15516c77SSepherosa Ziehau hn_link_status(sc); 1020*15516c77SSepherosa Ziehau } 1021*15516c77SSepherosa Ziehau 1022*15516c77SSepherosa Ziehau static void 1023*15516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused) 1024*15516c77SSepherosa Ziehau { 1025*15516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 1026*15516c77SSepherosa Ziehau 1027*15516c77SSepherosa Ziehau /* Prevent any link status checks from running. */ 1028*15516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_NETCHG; 1029*15516c77SSepherosa Ziehau 1030*15516c77SSepherosa Ziehau /* 1031*15516c77SSepherosa Ziehau * Fake up a [link down --> link up] state change; 5 seconds 1032*15516c77SSepherosa Ziehau * delay is used, which closely simulates miibus reaction 1033*15516c77SSepherosa Ziehau * upon link down event. 1034*15516c77SSepherosa Ziehau */ 1035*15516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 1036*15516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); 1037*15516c77SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0, 1038*15516c77SSepherosa Ziehau &sc->hn_netchg_status, 5 * hz); 1039*15516c77SSepherosa Ziehau } 1040*15516c77SSepherosa Ziehau 1041*15516c77SSepherosa Ziehau static void 1042*15516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused) 1043*15516c77SSepherosa Ziehau { 1044*15516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 1045*15516c77SSepherosa Ziehau 1046*15516c77SSepherosa Ziehau /* Re-allow link status checks. */ 1047*15516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG; 1048*15516c77SSepherosa Ziehau hn_link_status(sc); 1049*15516c77SSepherosa Ziehau } 1050*15516c77SSepherosa Ziehau 1051*15516c77SSepherosa Ziehau static void 1052*15516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc) 1053*15516c77SSepherosa Ziehau { 1054*15516c77SSepherosa Ziehau 1055*15516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 1056*15516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task); 1057*15516c77SSepherosa Ziehau } 1058*15516c77SSepherosa Ziehau 1059*15516c77SSepherosa Ziehau static void 1060*15516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc) 1061*15516c77SSepherosa Ziehau { 1062*15516c77SSepherosa Ziehau 1063*15516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 1064*15516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init); 1065*15516c77SSepherosa Ziehau } 1066*15516c77SSepherosa Ziehau 1067*15516c77SSepherosa Ziehau static __inline int 1068*15516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd, 1069*15516c77SSepherosa Ziehau struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) 1070*15516c77SSepherosa Ziehau { 1071*15516c77SSepherosa Ziehau struct mbuf *m = *m_head; 1072*15516c77SSepherosa Ziehau int error; 1073*15516c77SSepherosa Ziehau 1074*15516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim")); 1075*15516c77SSepherosa Ziehau 1076*15516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap, 1077*15516c77SSepherosa Ziehau m, segs, nsegs, BUS_DMA_NOWAIT); 1078*15516c77SSepherosa Ziehau if (error == EFBIG) { 1079*15516c77SSepherosa Ziehau struct mbuf *m_new; 1080*15516c77SSepherosa Ziehau 1081*15516c77SSepherosa Ziehau m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX); 1082*15516c77SSepherosa Ziehau if (m_new == NULL) 1083*15516c77SSepherosa Ziehau return ENOBUFS; 1084*15516c77SSepherosa Ziehau else 1085*15516c77SSepherosa Ziehau *m_head = m = m_new; 1086*15516c77SSepherosa Ziehau txr->hn_tx_collapsed++; 1087*15516c77SSepherosa Ziehau 1088*15516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, 1089*15516c77SSepherosa Ziehau txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT); 1090*15516c77SSepherosa Ziehau } 1091*15516c77SSepherosa Ziehau if (!error) { 1092*15516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap, 1093*15516c77SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 1094*15516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_DMAMAP; 1095*15516c77SSepherosa Ziehau } 1096*15516c77SSepherosa Ziehau return error; 1097*15516c77SSepherosa Ziehau } 1098*15516c77SSepherosa Ziehau 1099*15516c77SSepherosa Ziehau static __inline int 1100*15516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd) 1101*15516c77SSepherosa Ziehau { 1102*15516c77SSepherosa Ziehau 1103*15516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0, 1104*15516c77SSepherosa Ziehau ("put an onlist txd %#x", txd->flags)); 1105*15516c77SSepherosa Ziehau 1106*15516c77SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 1107*15516c77SSepherosa Ziehau if (atomic_fetchadd_int(&txd->refs, -1) != 1) 1108*15516c77SSepherosa Ziehau return 0; 1109*15516c77SSepherosa Ziehau 1110*15516c77SSepherosa Ziehau if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) { 1111*15516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 1112*15516c77SSepherosa Ziehau ("chim txd uses dmamap")); 1113*15516c77SSepherosa Ziehau hn_chim_free(txr->hn_sc, txd->chim_index); 1114*15516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 1115*15516c77SSepherosa Ziehau } else if (txd->flags & HN_TXD_FLAG_DMAMAP) { 1116*15516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, 1117*15516c77SSepherosa Ziehau txd->data_dmap, BUS_DMASYNC_POSTWRITE); 1118*15516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_data_dtag, 1119*15516c77SSepherosa Ziehau txd->data_dmap); 1120*15516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_DMAMAP; 1121*15516c77SSepherosa Ziehau } 1122*15516c77SSepherosa Ziehau 1123*15516c77SSepherosa Ziehau if (txd->m != NULL) { 1124*15516c77SSepherosa Ziehau m_freem(txd->m); 1125*15516c77SSepherosa Ziehau txd->m = NULL; 1126*15516c77SSepherosa Ziehau } 1127*15516c77SSepherosa Ziehau 1128*15516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 1129*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 1130*15516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 1131*15516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail >= 0 && 1132*15516c77SSepherosa Ziehau txr->hn_txdesc_avail < txr->hn_txdesc_cnt, 1133*15516c77SSepherosa Ziehau ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail)); 1134*15516c77SSepherosa Ziehau txr->hn_txdesc_avail++; 1135*15516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 1136*15516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 1137*15516c77SSepherosa Ziehau #else 1138*15516c77SSepherosa Ziehau atomic_add_int(&txr->hn_txdesc_avail, 1); 1139*15516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 1140*15516c77SSepherosa Ziehau #endif 1141*15516c77SSepherosa Ziehau 1142*15516c77SSepherosa Ziehau return 1; 1143*15516c77SSepherosa Ziehau } 1144*15516c77SSepherosa Ziehau 1145*15516c77SSepherosa Ziehau static __inline struct hn_txdesc * 1146*15516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr) 1147*15516c77SSepherosa Ziehau { 1148*15516c77SSepherosa Ziehau struct hn_txdesc *txd; 1149*15516c77SSepherosa Ziehau 1150*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 1151*15516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 1152*15516c77SSepherosa Ziehau txd = SLIST_FIRST(&txr->hn_txlist); 1153*15516c77SSepherosa Ziehau if (txd != NULL) { 1154*15516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail > 0, 1155*15516c77SSepherosa Ziehau ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail)); 1156*15516c77SSepherosa Ziehau txr->hn_txdesc_avail--; 1157*15516c77SSepherosa Ziehau SLIST_REMOVE_HEAD(&txr->hn_txlist, link); 1158*15516c77SSepherosa Ziehau } 1159*15516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 1160*15516c77SSepherosa Ziehau #else 1161*15516c77SSepherosa Ziehau txd = buf_ring_dequeue_sc(txr->hn_txdesc_br); 1162*15516c77SSepherosa Ziehau #endif 1163*15516c77SSepherosa Ziehau 1164*15516c77SSepherosa Ziehau if (txd != NULL) { 1165*15516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 1166*15516c77SSepherosa Ziehau atomic_subtract_int(&txr->hn_txdesc_avail, 1); 1167*15516c77SSepherosa Ziehau #endif 1168*15516c77SSepherosa Ziehau KASSERT(txd->m == NULL && txd->refs == 0 && 1169*15516c77SSepherosa Ziehau txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 1170*15516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONLIST) && 1171*15516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd")); 1172*15516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_ONLIST; 1173*15516c77SSepherosa Ziehau txd->refs = 1; 1174*15516c77SSepherosa Ziehau } 1175*15516c77SSepherosa Ziehau return txd; 1176*15516c77SSepherosa Ziehau } 1177*15516c77SSepherosa Ziehau 1178*15516c77SSepherosa Ziehau static __inline void 1179*15516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd) 1180*15516c77SSepherosa Ziehau { 1181*15516c77SSepherosa Ziehau 1182*15516c77SSepherosa Ziehau /* 0->1 transition will never work */ 1183*15516c77SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid refs %d", txd->refs)); 1184*15516c77SSepherosa Ziehau atomic_add_int(&txd->refs, 1); 1185*15516c77SSepherosa Ziehau } 1186*15516c77SSepherosa Ziehau 1187*15516c77SSepherosa Ziehau static bool 1188*15516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr) 1189*15516c77SSepherosa Ziehau { 1190*15516c77SSepherosa Ziehau bool pending = false; 1191*15516c77SSepherosa Ziehau 1192*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 1193*15516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 1194*15516c77SSepherosa Ziehau if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt) 1195*15516c77SSepherosa Ziehau pending = true; 1196*15516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 1197*15516c77SSepherosa Ziehau #else 1198*15516c77SSepherosa Ziehau if (!buf_ring_full(txr->hn_txdesc_br)) 1199*15516c77SSepherosa Ziehau pending = true; 1200*15516c77SSepherosa Ziehau #endif 1201*15516c77SSepherosa Ziehau return (pending); 1202*15516c77SSepherosa Ziehau } 1203*15516c77SSepherosa Ziehau 1204*15516c77SSepherosa Ziehau static __inline void 1205*15516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr) 1206*15516c77SSepherosa Ziehau { 1207*15516c77SSepherosa Ziehau txr->hn_has_txeof = 0; 1208*15516c77SSepherosa Ziehau txr->hn_txeof(txr); 1209*15516c77SSepherosa Ziehau } 1210*15516c77SSepherosa Ziehau 1211*15516c77SSepherosa Ziehau static void 1212*15516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc, 1213*15516c77SSepherosa Ziehau struct vmbus_channel *chan, const void *data __unused, int dlen __unused) 1214*15516c77SSepherosa Ziehau { 1215*15516c77SSepherosa Ziehau struct hn_txdesc *txd = sndc->hn_cbarg; 1216*15516c77SSepherosa Ziehau struct hn_tx_ring *txr; 1217*15516c77SSepherosa Ziehau 1218*15516c77SSepherosa Ziehau txr = txd->txr; 1219*15516c77SSepherosa Ziehau KASSERT(txr->hn_chan == chan, 1220*15516c77SSepherosa Ziehau ("channel mismatch, on chan%u, should be chan%u", 1221*15516c77SSepherosa Ziehau vmbus_chan_subidx(chan), vmbus_chan_subidx(txr->hn_chan))); 1222*15516c77SSepherosa Ziehau 1223*15516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 1224*15516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 1225*15516c77SSepherosa Ziehau 1226*15516c77SSepherosa Ziehau ++txr->hn_txdone_cnt; 1227*15516c77SSepherosa Ziehau if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) { 1228*15516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 1229*15516c77SSepherosa Ziehau if (txr->hn_oactive) 1230*15516c77SSepherosa Ziehau hn_txeof(txr); 1231*15516c77SSepherosa Ziehau } 1232*15516c77SSepherosa Ziehau } 1233*15516c77SSepherosa Ziehau 1234*15516c77SSepherosa Ziehau static void 1235*15516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr) 1236*15516c77SSepherosa Ziehau { 1237*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 1238*15516c77SSepherosa Ziehau tcp_lro_flush_all(&rxr->hn_lro); 1239*15516c77SSepherosa Ziehau #endif 1240*15516c77SSepherosa Ziehau 1241*15516c77SSepherosa Ziehau /* 1242*15516c77SSepherosa Ziehau * NOTE: 1243*15516c77SSepherosa Ziehau * 'txr' could be NULL, if multiple channels and 1244*15516c77SSepherosa Ziehau * ifnet.if_start method are enabled. 1245*15516c77SSepherosa Ziehau */ 1246*15516c77SSepherosa Ziehau if (txr == NULL || !txr->hn_has_txeof) 1247*15516c77SSepherosa Ziehau return; 1248*15516c77SSepherosa Ziehau 1249*15516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 1250*15516c77SSepherosa Ziehau hn_txeof(txr); 1251*15516c77SSepherosa Ziehau } 1252*15516c77SSepherosa Ziehau 1253*15516c77SSepherosa Ziehau static __inline uint32_t 1254*15516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs) 1255*15516c77SSepherosa Ziehau { 1256*15516c77SSepherosa Ziehau 1257*15516c77SSepherosa Ziehau KASSERT(ofs >= sizeof(struct rndis_packet_msg), 1258*15516c77SSepherosa Ziehau ("invalid RNDIS packet msg offset %u", ofs)); 1259*15516c77SSepherosa Ziehau return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset)); 1260*15516c77SSepherosa Ziehau } 1261*15516c77SSepherosa Ziehau 1262*15516c77SSepherosa Ziehau static __inline void * 1263*15516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize, 1264*15516c77SSepherosa Ziehau size_t pi_dlen, uint32_t pi_type) 1265*15516c77SSepherosa Ziehau { 1266*15516c77SSepherosa Ziehau const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen); 1267*15516c77SSepherosa Ziehau struct rndis_pktinfo *pi; 1268*15516c77SSepherosa Ziehau 1269*15516c77SSepherosa Ziehau KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0, 1270*15516c77SSepherosa Ziehau ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen)); 1271*15516c77SSepherosa Ziehau 1272*15516c77SSepherosa Ziehau /* 1273*15516c77SSepherosa Ziehau * Per-packet-info does not move; it only grows. 1274*15516c77SSepherosa Ziehau * 1275*15516c77SSepherosa Ziehau * NOTE: 1276*15516c77SSepherosa Ziehau * rm_pktinfooffset in this phase counts from the beginning 1277*15516c77SSepherosa Ziehau * of rndis_packet_msg. 1278*15516c77SSepherosa Ziehau */ 1279*15516c77SSepherosa Ziehau KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize, 1280*15516c77SSepherosa Ziehau ("%u pktinfo overflows RNDIS packet msg", pi_type)); 1281*15516c77SSepherosa Ziehau pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset + 1282*15516c77SSepherosa Ziehau pkt->rm_pktinfolen); 1283*15516c77SSepherosa Ziehau pkt->rm_pktinfolen += pi_size; 1284*15516c77SSepherosa Ziehau 1285*15516c77SSepherosa Ziehau pi->rm_size = pi_size; 1286*15516c77SSepherosa Ziehau pi->rm_type = pi_type; 1287*15516c77SSepherosa Ziehau pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET; 1288*15516c77SSepherosa Ziehau 1289*15516c77SSepherosa Ziehau /* Data immediately follow per-packet-info. */ 1290*15516c77SSepherosa Ziehau pkt->rm_dataoffset += pi_size; 1291*15516c77SSepherosa Ziehau 1292*15516c77SSepherosa Ziehau /* Update RNDIS packet msg length */ 1293*15516c77SSepherosa Ziehau pkt->rm_len += pi_size; 1294*15516c77SSepherosa Ziehau 1295*15516c77SSepherosa Ziehau return (pi->rm_data); 1296*15516c77SSepherosa Ziehau } 1297*15516c77SSepherosa Ziehau 1298*15516c77SSepherosa Ziehau /* 1299*15516c77SSepherosa Ziehau * NOTE: 1300*15516c77SSepherosa Ziehau * If this function fails, then both txd and m_head0 will be freed. 1301*15516c77SSepherosa Ziehau */ 1302*15516c77SSepherosa Ziehau static int 1303*15516c77SSepherosa Ziehau hn_encap(struct hn_tx_ring *txr, struct hn_txdesc *txd, struct mbuf **m_head0) 1304*15516c77SSepherosa Ziehau { 1305*15516c77SSepherosa Ziehau bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX]; 1306*15516c77SSepherosa Ziehau int error, nsegs, i; 1307*15516c77SSepherosa Ziehau struct mbuf *m_head = *m_head0; 1308*15516c77SSepherosa Ziehau struct rndis_packet_msg *pkt; 1309*15516c77SSepherosa Ziehau uint32_t *pi_data; 1310*15516c77SSepherosa Ziehau int pktlen; 1311*15516c77SSepherosa Ziehau 1312*15516c77SSepherosa Ziehau /* 1313*15516c77SSepherosa Ziehau * extension points to the area reserved for the 1314*15516c77SSepherosa Ziehau * rndis_filter_packet, which is placed just after 1315*15516c77SSepherosa Ziehau * the netvsc_packet (and rppi struct, if present; 1316*15516c77SSepherosa Ziehau * length is updated later). 1317*15516c77SSepherosa Ziehau */ 1318*15516c77SSepherosa Ziehau pkt = txd->rndis_pkt; 1319*15516c77SSepherosa Ziehau pkt->rm_type = REMOTE_NDIS_PACKET_MSG; 1320*15516c77SSepherosa Ziehau pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len; 1321*15516c77SSepherosa Ziehau pkt->rm_dataoffset = sizeof(*pkt); 1322*15516c77SSepherosa Ziehau pkt->rm_datalen = m_head->m_pkthdr.len; 1323*15516c77SSepherosa Ziehau pkt->rm_pktinfooffset = sizeof(*pkt); 1324*15516c77SSepherosa Ziehau pkt->rm_pktinfolen = 0; 1325*15516c77SSepherosa Ziehau 1326*15516c77SSepherosa Ziehau if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) { 1327*15516c77SSepherosa Ziehau /* 1328*15516c77SSepherosa Ziehau * Set the hash value for this packet, so that the host could 1329*15516c77SSepherosa Ziehau * dispatch the TX done event for this packet back to this TX 1330*15516c77SSepherosa Ziehau * ring's channel. 1331*15516c77SSepherosa Ziehau */ 1332*15516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 1333*15516c77SSepherosa Ziehau HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL); 1334*15516c77SSepherosa Ziehau *pi_data = txr->hn_tx_idx; 1335*15516c77SSepherosa Ziehau } 1336*15516c77SSepherosa Ziehau 1337*15516c77SSepherosa Ziehau if (m_head->m_flags & M_VLANTAG) { 1338*15516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 1339*15516c77SSepherosa Ziehau NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN); 1340*15516c77SSepherosa Ziehau *pi_data = NDIS_VLAN_INFO_MAKE( 1341*15516c77SSepherosa Ziehau EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag), 1342*15516c77SSepherosa Ziehau EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag), 1343*15516c77SSepherosa Ziehau EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag)); 1344*15516c77SSepherosa Ziehau } 1345*15516c77SSepherosa Ziehau 1346*15516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 1347*15516c77SSepherosa Ziehau #if defined(INET6) || defined(INET) 1348*15516c77SSepherosa Ziehau struct ether_vlan_header *eh; 1349*15516c77SSepherosa Ziehau int ether_len; 1350*15516c77SSepherosa Ziehau 1351*15516c77SSepherosa Ziehau /* 1352*15516c77SSepherosa Ziehau * XXX need m_pullup and use mtodo 1353*15516c77SSepherosa Ziehau */ 1354*15516c77SSepherosa Ziehau eh = mtod(m_head, struct ether_vlan_header*); 1355*15516c77SSepherosa Ziehau if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) 1356*15516c77SSepherosa Ziehau ether_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 1357*15516c77SSepherosa Ziehau else 1358*15516c77SSepherosa Ziehau ether_len = ETHER_HDR_LEN; 1359*15516c77SSepherosa Ziehau 1360*15516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 1361*15516c77SSepherosa Ziehau NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); 1362*15516c77SSepherosa Ziehau #ifdef INET 1363*15516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 1364*15516c77SSepherosa Ziehau struct ip *ip = 1365*15516c77SSepherosa Ziehau (struct ip *)(m_head->m_data + ether_len); 1366*15516c77SSepherosa Ziehau unsigned long iph_len = ip->ip_hl << 2; 1367*15516c77SSepherosa Ziehau struct tcphdr *th = 1368*15516c77SSepherosa Ziehau (struct tcphdr *)((caddr_t)ip + iph_len); 1369*15516c77SSepherosa Ziehau 1370*15516c77SSepherosa Ziehau ip->ip_len = 0; 1371*15516c77SSepherosa Ziehau ip->ip_sum = 0; 1372*15516c77SSepherosa Ziehau th->th_sum = in_pseudo(ip->ip_src.s_addr, 1373*15516c77SSepherosa Ziehau ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 1374*15516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV4(0, 1375*15516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 1376*15516c77SSepherosa Ziehau } 1377*15516c77SSepherosa Ziehau #endif 1378*15516c77SSepherosa Ziehau #if defined(INET6) && defined(INET) 1379*15516c77SSepherosa Ziehau else 1380*15516c77SSepherosa Ziehau #endif 1381*15516c77SSepherosa Ziehau #ifdef INET6 1382*15516c77SSepherosa Ziehau { 1383*15516c77SSepherosa Ziehau struct ip6_hdr *ip6 = (struct ip6_hdr *) 1384*15516c77SSepherosa Ziehau (m_head->m_data + ether_len); 1385*15516c77SSepherosa Ziehau struct tcphdr *th = (struct tcphdr *)(ip6 + 1); 1386*15516c77SSepherosa Ziehau 1387*15516c77SSepherosa Ziehau ip6->ip6_plen = 0; 1388*15516c77SSepherosa Ziehau th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 1389*15516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV6(0, 1390*15516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 1391*15516c77SSepherosa Ziehau } 1392*15516c77SSepherosa Ziehau #endif 1393*15516c77SSepherosa Ziehau #endif /* INET6 || INET */ 1394*15516c77SSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) { 1395*15516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 1396*15516c77SSepherosa Ziehau NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); 1397*15516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & 1398*15516c77SSepherosa Ziehau (CSUM_IP6_TCP | CSUM_IP6_UDP)) { 1399*15516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV6; 1400*15516c77SSepherosa Ziehau } else { 1401*15516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV4; 1402*15516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 1403*15516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_IPCS; 1404*15516c77SSepherosa Ziehau } 1405*15516c77SSepherosa Ziehau 1406*15516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) 1407*15516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_TCPCS; 1408*15516c77SSepherosa Ziehau else if (m_head->m_pkthdr.csum_flags & 1409*15516c77SSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP6_UDP)) 1410*15516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_UDPCS; 1411*15516c77SSepherosa Ziehau } 1412*15516c77SSepherosa Ziehau 1413*15516c77SSepherosa Ziehau pktlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; 1414*15516c77SSepherosa Ziehau /* Convert RNDIS packet message offsets */ 1415*15516c77SSepherosa Ziehau pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt->rm_dataoffset); 1416*15516c77SSepherosa Ziehau pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset); 1417*15516c77SSepherosa Ziehau 1418*15516c77SSepherosa Ziehau /* 1419*15516c77SSepherosa Ziehau * Chimney send, if the packet could fit into one chimney buffer. 1420*15516c77SSepherosa Ziehau */ 1421*15516c77SSepherosa Ziehau if (pkt->rm_len < txr->hn_chim_size) { 1422*15516c77SSepherosa Ziehau txr->hn_tx_chimney_tried++; 1423*15516c77SSepherosa Ziehau txd->chim_index = hn_chim_alloc(txr->hn_sc); 1424*15516c77SSepherosa Ziehau if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) { 1425*15516c77SSepherosa Ziehau uint8_t *dest = txr->hn_sc->hn_chim + 1426*15516c77SSepherosa Ziehau (txd->chim_index * txr->hn_sc->hn_chim_szmax); 1427*15516c77SSepherosa Ziehau 1428*15516c77SSepherosa Ziehau memcpy(dest, pkt, pktlen); 1429*15516c77SSepherosa Ziehau dest += pktlen; 1430*15516c77SSepherosa Ziehau m_copydata(m_head, 0, m_head->m_pkthdr.len, dest); 1431*15516c77SSepherosa Ziehau 1432*15516c77SSepherosa Ziehau txd->chim_size = pkt->rm_len; 1433*15516c77SSepherosa Ziehau txr->hn_gpa_cnt = 0; 1434*15516c77SSepherosa Ziehau txr->hn_tx_chimney++; 1435*15516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_chim; 1436*15516c77SSepherosa Ziehau goto done; 1437*15516c77SSepherosa Ziehau } 1438*15516c77SSepherosa Ziehau } 1439*15516c77SSepherosa Ziehau 1440*15516c77SSepherosa Ziehau error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs); 1441*15516c77SSepherosa Ziehau if (error) { 1442*15516c77SSepherosa Ziehau int freed; 1443*15516c77SSepherosa Ziehau 1444*15516c77SSepherosa Ziehau /* 1445*15516c77SSepherosa Ziehau * This mbuf is not linked w/ the txd yet, so free it now. 1446*15516c77SSepherosa Ziehau */ 1447*15516c77SSepherosa Ziehau m_freem(m_head); 1448*15516c77SSepherosa Ziehau *m_head0 = NULL; 1449*15516c77SSepherosa Ziehau 1450*15516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 1451*15516c77SSepherosa Ziehau KASSERT(freed != 0, 1452*15516c77SSepherosa Ziehau ("fail to free txd upon txdma error")); 1453*15516c77SSepherosa Ziehau 1454*15516c77SSepherosa Ziehau txr->hn_txdma_failed++; 1455*15516c77SSepherosa Ziehau if_inc_counter(txr->hn_sc->hn_ifp, IFCOUNTER_OERRORS, 1); 1456*15516c77SSepherosa Ziehau return error; 1457*15516c77SSepherosa Ziehau } 1458*15516c77SSepherosa Ziehau *m_head0 = m_head; 1459*15516c77SSepherosa Ziehau 1460*15516c77SSepherosa Ziehau /* +1 RNDIS packet message */ 1461*15516c77SSepherosa Ziehau txr->hn_gpa_cnt = nsegs + 1; 1462*15516c77SSepherosa Ziehau 1463*15516c77SSepherosa Ziehau /* send packet with page buffer */ 1464*15516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr); 1465*15516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK; 1466*15516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_len = pktlen; 1467*15516c77SSepherosa Ziehau 1468*15516c77SSepherosa Ziehau /* 1469*15516c77SSepherosa Ziehau * Fill the page buffers with mbuf info after the page 1470*15516c77SSepherosa Ziehau * buffer for RNDIS packet message. 1471*15516c77SSepherosa Ziehau */ 1472*15516c77SSepherosa Ziehau for (i = 0; i < nsegs; ++i) { 1473*15516c77SSepherosa Ziehau struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1]; 1474*15516c77SSepherosa Ziehau 1475*15516c77SSepherosa Ziehau gpa->gpa_page = atop(segs[i].ds_addr); 1476*15516c77SSepherosa Ziehau gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK; 1477*15516c77SSepherosa Ziehau gpa->gpa_len = segs[i].ds_len; 1478*15516c77SSepherosa Ziehau } 1479*15516c77SSepherosa Ziehau 1480*15516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 1481*15516c77SSepherosa Ziehau txd->chim_size = 0; 1482*15516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_sglist; 1483*15516c77SSepherosa Ziehau done: 1484*15516c77SSepherosa Ziehau txd->m = m_head; 1485*15516c77SSepherosa Ziehau 1486*15516c77SSepherosa Ziehau /* Set the completion routine */ 1487*15516c77SSepherosa Ziehau hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd); 1488*15516c77SSepherosa Ziehau 1489*15516c77SSepherosa Ziehau return 0; 1490*15516c77SSepherosa Ziehau } 1491*15516c77SSepherosa Ziehau 1492*15516c77SSepherosa Ziehau /* 1493*15516c77SSepherosa Ziehau * NOTE: 1494*15516c77SSepherosa Ziehau * If this function fails, then txd will be freed, but the mbuf 1495*15516c77SSepherosa Ziehau * associated w/ the txd will _not_ be freed. 1496*15516c77SSepherosa Ziehau */ 1497*15516c77SSepherosa Ziehau static int 1498*15516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd) 1499*15516c77SSepherosa Ziehau { 1500*15516c77SSepherosa Ziehau int error, send_failed = 0; 1501*15516c77SSepherosa Ziehau 1502*15516c77SSepherosa Ziehau again: 1503*15516c77SSepherosa Ziehau /* 1504*15516c77SSepherosa Ziehau * Make sure that txd is not freed before ETHER_BPF_MTAP. 1505*15516c77SSepherosa Ziehau */ 1506*15516c77SSepherosa Ziehau hn_txdesc_hold(txd); 1507*15516c77SSepherosa Ziehau error = txr->hn_sendpkt(txr, txd); 1508*15516c77SSepherosa Ziehau if (!error) { 1509*15516c77SSepherosa Ziehau ETHER_BPF_MTAP(ifp, txd->m); 1510*15516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 1511*15516c77SSepherosa Ziehau if (!hn_use_if_start) { 1512*15516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, 1513*15516c77SSepherosa Ziehau txd->m->m_pkthdr.len); 1514*15516c77SSepherosa Ziehau if (txd->m->m_flags & M_MCAST) 1515*15516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 1516*15516c77SSepherosa Ziehau } 1517*15516c77SSepherosa Ziehau txr->hn_pkts++; 1518*15516c77SSepherosa Ziehau } 1519*15516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 1520*15516c77SSepherosa Ziehau 1521*15516c77SSepherosa Ziehau if (__predict_false(error)) { 1522*15516c77SSepherosa Ziehau int freed; 1523*15516c77SSepherosa Ziehau 1524*15516c77SSepherosa Ziehau /* 1525*15516c77SSepherosa Ziehau * This should "really rarely" happen. 1526*15516c77SSepherosa Ziehau * 1527*15516c77SSepherosa Ziehau * XXX Too many RX to be acked or too many sideband 1528*15516c77SSepherosa Ziehau * commands to run? Ask netvsc_channel_rollup() 1529*15516c77SSepherosa Ziehau * to kick start later. 1530*15516c77SSepherosa Ziehau */ 1531*15516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 1532*15516c77SSepherosa Ziehau if (!send_failed) { 1533*15516c77SSepherosa Ziehau txr->hn_send_failed++; 1534*15516c77SSepherosa Ziehau send_failed = 1; 1535*15516c77SSepherosa Ziehau /* 1536*15516c77SSepherosa Ziehau * Try sending again after set hn_has_txeof; 1537*15516c77SSepherosa Ziehau * in case that we missed the last 1538*15516c77SSepherosa Ziehau * netvsc_channel_rollup(). 1539*15516c77SSepherosa Ziehau */ 1540*15516c77SSepherosa Ziehau goto again; 1541*15516c77SSepherosa Ziehau } 1542*15516c77SSepherosa Ziehau if_printf(ifp, "send failed\n"); 1543*15516c77SSepherosa Ziehau 1544*15516c77SSepherosa Ziehau /* 1545*15516c77SSepherosa Ziehau * Caller will perform further processing on the 1546*15516c77SSepherosa Ziehau * associated mbuf, so don't free it in hn_txdesc_put(); 1547*15516c77SSepherosa Ziehau * only unload it from the DMA map in hn_txdesc_put(), 1548*15516c77SSepherosa Ziehau * if it was loaded. 1549*15516c77SSepherosa Ziehau */ 1550*15516c77SSepherosa Ziehau txd->m = NULL; 1551*15516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 1552*15516c77SSepherosa Ziehau KASSERT(freed != 0, 1553*15516c77SSepherosa Ziehau ("fail to free txd upon send error")); 1554*15516c77SSepherosa Ziehau 1555*15516c77SSepherosa Ziehau txr->hn_send_failed++; 1556*15516c77SSepherosa Ziehau } 1557*15516c77SSepherosa Ziehau return error; 1558*15516c77SSepherosa Ziehau } 1559*15516c77SSepherosa Ziehau 1560*15516c77SSepherosa Ziehau /* 1561*15516c77SSepherosa Ziehau * Start a transmit of one or more packets 1562*15516c77SSepherosa Ziehau */ 1563*15516c77SSepherosa Ziehau static int 1564*15516c77SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len) 1565*15516c77SSepherosa Ziehau { 1566*15516c77SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 1567*15516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 1568*15516c77SSepherosa Ziehau 1569*15516c77SSepherosa Ziehau KASSERT(hn_use_if_start, 1570*15516c77SSepherosa Ziehau ("hn_start_locked is called, when if_start is disabled")); 1571*15516c77SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 1572*15516c77SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 1573*15516c77SSepherosa Ziehau 1574*15516c77SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 1575*15516c77SSepherosa Ziehau return 0; 1576*15516c77SSepherosa Ziehau 1577*15516c77SSepherosa Ziehau if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1578*15516c77SSepherosa Ziehau IFF_DRV_RUNNING) 1579*15516c77SSepherosa Ziehau return 0; 1580*15516c77SSepherosa Ziehau 1581*15516c77SSepherosa Ziehau while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 1582*15516c77SSepherosa Ziehau struct hn_txdesc *txd; 1583*15516c77SSepherosa Ziehau struct mbuf *m_head; 1584*15516c77SSepherosa Ziehau int error; 1585*15516c77SSepherosa Ziehau 1586*15516c77SSepherosa Ziehau IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 1587*15516c77SSepherosa Ziehau if (m_head == NULL) 1588*15516c77SSepherosa Ziehau break; 1589*15516c77SSepherosa Ziehau 1590*15516c77SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 1591*15516c77SSepherosa Ziehau /* 1592*15516c77SSepherosa Ziehau * This sending could be time consuming; let callers 1593*15516c77SSepherosa Ziehau * dispatch this packet sending (and sending of any 1594*15516c77SSepherosa Ziehau * following up packets) to tx taskqueue. 1595*15516c77SSepherosa Ziehau */ 1596*15516c77SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1597*15516c77SSepherosa Ziehau return 1; 1598*15516c77SSepherosa Ziehau } 1599*15516c77SSepherosa Ziehau 1600*15516c77SSepherosa Ziehau txd = hn_txdesc_get(txr); 1601*15516c77SSepherosa Ziehau if (txd == NULL) { 1602*15516c77SSepherosa Ziehau txr->hn_no_txdescs++; 1603*15516c77SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1604*15516c77SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 1605*15516c77SSepherosa Ziehau break; 1606*15516c77SSepherosa Ziehau } 1607*15516c77SSepherosa Ziehau 1608*15516c77SSepherosa Ziehau error = hn_encap(txr, txd, &m_head); 1609*15516c77SSepherosa Ziehau if (error) { 1610*15516c77SSepherosa Ziehau /* Both txd and m_head are freed */ 1611*15516c77SSepherosa Ziehau continue; 1612*15516c77SSepherosa Ziehau } 1613*15516c77SSepherosa Ziehau 1614*15516c77SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 1615*15516c77SSepherosa Ziehau if (__predict_false(error)) { 1616*15516c77SSepherosa Ziehau /* txd is freed, but m_head is not */ 1617*15516c77SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1618*15516c77SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 1619*15516c77SSepherosa Ziehau break; 1620*15516c77SSepherosa Ziehau } 1621*15516c77SSepherosa Ziehau } 1622*15516c77SSepherosa Ziehau return 0; 1623*15516c77SSepherosa Ziehau } 1624*15516c77SSepherosa Ziehau 1625*15516c77SSepherosa Ziehau /* 1626*15516c77SSepherosa Ziehau * Append the specified data to the indicated mbuf chain, 1627*15516c77SSepherosa Ziehau * Extend the mbuf chain if the new data does not fit in 1628*15516c77SSepherosa Ziehau * existing space. 1629*15516c77SSepherosa Ziehau * 1630*15516c77SSepherosa Ziehau * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c. 1631*15516c77SSepherosa Ziehau * There should be an equivalent in the kernel mbuf code, 1632*15516c77SSepherosa Ziehau * but there does not appear to be one yet. 1633*15516c77SSepherosa Ziehau * 1634*15516c77SSepherosa Ziehau * Differs from m_append() in that additional mbufs are 1635*15516c77SSepherosa Ziehau * allocated with cluster size MJUMPAGESIZE, and filled 1636*15516c77SSepherosa Ziehau * accordingly. 1637*15516c77SSepherosa Ziehau * 1638*15516c77SSepherosa Ziehau * Return 1 if able to complete the job; otherwise 0. 1639*15516c77SSepherosa Ziehau */ 1640*15516c77SSepherosa Ziehau static int 1641*15516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp) 1642*15516c77SSepherosa Ziehau { 1643*15516c77SSepherosa Ziehau struct mbuf *m, *n; 1644*15516c77SSepherosa Ziehau int remainder, space; 1645*15516c77SSepherosa Ziehau 1646*15516c77SSepherosa Ziehau for (m = m0; m->m_next != NULL; m = m->m_next) 1647*15516c77SSepherosa Ziehau ; 1648*15516c77SSepherosa Ziehau remainder = len; 1649*15516c77SSepherosa Ziehau space = M_TRAILINGSPACE(m); 1650*15516c77SSepherosa Ziehau if (space > 0) { 1651*15516c77SSepherosa Ziehau /* 1652*15516c77SSepherosa Ziehau * Copy into available space. 1653*15516c77SSepherosa Ziehau */ 1654*15516c77SSepherosa Ziehau if (space > remainder) 1655*15516c77SSepherosa Ziehau space = remainder; 1656*15516c77SSepherosa Ziehau bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 1657*15516c77SSepherosa Ziehau m->m_len += space; 1658*15516c77SSepherosa Ziehau cp += space; 1659*15516c77SSepherosa Ziehau remainder -= space; 1660*15516c77SSepherosa Ziehau } 1661*15516c77SSepherosa Ziehau while (remainder > 0) { 1662*15516c77SSepherosa Ziehau /* 1663*15516c77SSepherosa Ziehau * Allocate a new mbuf; could check space 1664*15516c77SSepherosa Ziehau * and allocate a cluster instead. 1665*15516c77SSepherosa Ziehau */ 1666*15516c77SSepherosa Ziehau n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE); 1667*15516c77SSepherosa Ziehau if (n == NULL) 1668*15516c77SSepherosa Ziehau break; 1669*15516c77SSepherosa Ziehau n->m_len = min(MJUMPAGESIZE, remainder); 1670*15516c77SSepherosa Ziehau bcopy(cp, mtod(n, caddr_t), n->m_len); 1671*15516c77SSepherosa Ziehau cp += n->m_len; 1672*15516c77SSepherosa Ziehau remainder -= n->m_len; 1673*15516c77SSepherosa Ziehau m->m_next = n; 1674*15516c77SSepherosa Ziehau m = n; 1675*15516c77SSepherosa Ziehau } 1676*15516c77SSepherosa Ziehau if (m0->m_flags & M_PKTHDR) 1677*15516c77SSepherosa Ziehau m0->m_pkthdr.len += len - remainder; 1678*15516c77SSepherosa Ziehau 1679*15516c77SSepherosa Ziehau return (remainder == 0); 1680*15516c77SSepherosa Ziehau } 1681*15516c77SSepherosa Ziehau 1682*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 1683*15516c77SSepherosa Ziehau static __inline int 1684*15516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m) 1685*15516c77SSepherosa Ziehau { 1686*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 1687*15516c77SSepherosa Ziehau if (hn_lro_mbufq_depth) { 1688*15516c77SSepherosa Ziehau tcp_lro_queue_mbuf(lc, m); 1689*15516c77SSepherosa Ziehau return 0; 1690*15516c77SSepherosa Ziehau } 1691*15516c77SSepherosa Ziehau #endif 1692*15516c77SSepherosa Ziehau return tcp_lro_rx(lc, m, 0); 1693*15516c77SSepherosa Ziehau } 1694*15516c77SSepherosa Ziehau #endif 1695*15516c77SSepherosa Ziehau 1696*15516c77SSepherosa Ziehau static int 1697*15516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, 1698*15516c77SSepherosa Ziehau const struct hn_rxinfo *info) 1699*15516c77SSepherosa Ziehau { 1700*15516c77SSepherosa Ziehau struct ifnet *ifp = rxr->hn_ifp; 1701*15516c77SSepherosa Ziehau struct mbuf *m_new; 1702*15516c77SSepherosa Ziehau int size, do_lro = 0, do_csum = 1; 1703*15516c77SSepherosa Ziehau int hash_type; 1704*15516c77SSepherosa Ziehau 1705*15516c77SSepherosa Ziehau if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1706*15516c77SSepherosa Ziehau return (0); 1707*15516c77SSepherosa Ziehau 1708*15516c77SSepherosa Ziehau /* 1709*15516c77SSepherosa Ziehau * Bail out if packet contains more data than configured MTU. 1710*15516c77SSepherosa Ziehau */ 1711*15516c77SSepherosa Ziehau if (dlen > (ifp->if_mtu + ETHER_HDR_LEN)) { 1712*15516c77SSepherosa Ziehau return (0); 1713*15516c77SSepherosa Ziehau } else if (dlen <= MHLEN) { 1714*15516c77SSepherosa Ziehau m_new = m_gethdr(M_NOWAIT, MT_DATA); 1715*15516c77SSepherosa Ziehau if (m_new == NULL) { 1716*15516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 1717*15516c77SSepherosa Ziehau return (0); 1718*15516c77SSepherosa Ziehau } 1719*15516c77SSepherosa Ziehau memcpy(mtod(m_new, void *), data, dlen); 1720*15516c77SSepherosa Ziehau m_new->m_pkthdr.len = m_new->m_len = dlen; 1721*15516c77SSepherosa Ziehau rxr->hn_small_pkts++; 1722*15516c77SSepherosa Ziehau } else { 1723*15516c77SSepherosa Ziehau /* 1724*15516c77SSepherosa Ziehau * Get an mbuf with a cluster. For packets 2K or less, 1725*15516c77SSepherosa Ziehau * get a standard 2K cluster. For anything larger, get a 1726*15516c77SSepherosa Ziehau * 4K cluster. Any buffers larger than 4K can cause problems 1727*15516c77SSepherosa Ziehau * if looped around to the Hyper-V TX channel, so avoid them. 1728*15516c77SSepherosa Ziehau */ 1729*15516c77SSepherosa Ziehau size = MCLBYTES; 1730*15516c77SSepherosa Ziehau if (dlen > MCLBYTES) { 1731*15516c77SSepherosa Ziehau /* 4096 */ 1732*15516c77SSepherosa Ziehau size = MJUMPAGESIZE; 1733*15516c77SSepherosa Ziehau } 1734*15516c77SSepherosa Ziehau 1735*15516c77SSepherosa Ziehau m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size); 1736*15516c77SSepherosa Ziehau if (m_new == NULL) { 1737*15516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 1738*15516c77SSepherosa Ziehau return (0); 1739*15516c77SSepherosa Ziehau } 1740*15516c77SSepherosa Ziehau 1741*15516c77SSepherosa Ziehau hv_m_append(m_new, dlen, data); 1742*15516c77SSepherosa Ziehau } 1743*15516c77SSepherosa Ziehau m_new->m_pkthdr.rcvif = ifp; 1744*15516c77SSepherosa Ziehau 1745*15516c77SSepherosa Ziehau if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0)) 1746*15516c77SSepherosa Ziehau do_csum = 0; 1747*15516c77SSepherosa Ziehau 1748*15516c77SSepherosa Ziehau /* receive side checksum offload */ 1749*15516c77SSepherosa Ziehau if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) { 1750*15516c77SSepherosa Ziehau /* IP csum offload */ 1751*15516c77SSepherosa Ziehau if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) { 1752*15516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 1753*15516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 1754*15516c77SSepherosa Ziehau rxr->hn_csum_ip++; 1755*15516c77SSepherosa Ziehau } 1756*15516c77SSepherosa Ziehau 1757*15516c77SSepherosa Ziehau /* TCP/UDP csum offload */ 1758*15516c77SSepherosa Ziehau if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK | 1759*15516c77SSepherosa Ziehau NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) { 1760*15516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 1761*15516c77SSepherosa Ziehau (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1762*15516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 1763*15516c77SSepherosa Ziehau if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK) 1764*15516c77SSepherosa Ziehau rxr->hn_csum_tcp++; 1765*15516c77SSepherosa Ziehau else 1766*15516c77SSepherosa Ziehau rxr->hn_csum_udp++; 1767*15516c77SSepherosa Ziehau } 1768*15516c77SSepherosa Ziehau 1769*15516c77SSepherosa Ziehau /* 1770*15516c77SSepherosa Ziehau * XXX 1771*15516c77SSepherosa Ziehau * As of this write (Oct 28th, 2016), host side will turn 1772*15516c77SSepherosa Ziehau * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so 1773*15516c77SSepherosa Ziehau * the do_lro setting here is actually _not_ accurate. We 1774*15516c77SSepherosa Ziehau * depend on the RSS hash type check to reset do_lro. 1775*15516c77SSepherosa Ziehau */ 1776*15516c77SSepherosa Ziehau if ((info->csum_info & 1777*15516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) == 1778*15516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) 1779*15516c77SSepherosa Ziehau do_lro = 1; 1780*15516c77SSepherosa Ziehau } else { 1781*15516c77SSepherosa Ziehau const struct ether_header *eh; 1782*15516c77SSepherosa Ziehau uint16_t etype; 1783*15516c77SSepherosa Ziehau int hoff; 1784*15516c77SSepherosa Ziehau 1785*15516c77SSepherosa Ziehau hoff = sizeof(*eh); 1786*15516c77SSepherosa Ziehau if (m_new->m_len < hoff) 1787*15516c77SSepherosa Ziehau goto skip; 1788*15516c77SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 1789*15516c77SSepherosa Ziehau etype = ntohs(eh->ether_type); 1790*15516c77SSepherosa Ziehau if (etype == ETHERTYPE_VLAN) { 1791*15516c77SSepherosa Ziehau const struct ether_vlan_header *evl; 1792*15516c77SSepherosa Ziehau 1793*15516c77SSepherosa Ziehau hoff = sizeof(*evl); 1794*15516c77SSepherosa Ziehau if (m_new->m_len < hoff) 1795*15516c77SSepherosa Ziehau goto skip; 1796*15516c77SSepherosa Ziehau evl = mtod(m_new, struct ether_vlan_header *); 1797*15516c77SSepherosa Ziehau etype = ntohs(evl->evl_proto); 1798*15516c77SSepherosa Ziehau } 1799*15516c77SSepherosa Ziehau 1800*15516c77SSepherosa Ziehau if (etype == ETHERTYPE_IP) { 1801*15516c77SSepherosa Ziehau int pr; 1802*15516c77SSepherosa Ziehau 1803*15516c77SSepherosa Ziehau pr = hn_check_iplen(m_new, hoff); 1804*15516c77SSepherosa Ziehau if (pr == IPPROTO_TCP) { 1805*15516c77SSepherosa Ziehau if (do_csum && 1806*15516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 1807*15516c77SSepherosa Ziehau HN_TRUST_HCSUM_TCP)) { 1808*15516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 1809*15516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 1810*15516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 1811*15516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1812*15516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 1813*15516c77SSepherosa Ziehau } 1814*15516c77SSepherosa Ziehau do_lro = 1; 1815*15516c77SSepherosa Ziehau } else if (pr == IPPROTO_UDP) { 1816*15516c77SSepherosa Ziehau if (do_csum && 1817*15516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 1818*15516c77SSepherosa Ziehau HN_TRUST_HCSUM_UDP)) { 1819*15516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 1820*15516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 1821*15516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 1822*15516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1823*15516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 1824*15516c77SSepherosa Ziehau } 1825*15516c77SSepherosa Ziehau } else if (pr != IPPROTO_DONE && do_csum && 1826*15516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) { 1827*15516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 1828*15516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 1829*15516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 1830*15516c77SSepherosa Ziehau } 1831*15516c77SSepherosa Ziehau } 1832*15516c77SSepherosa Ziehau } 1833*15516c77SSepherosa Ziehau skip: 1834*15516c77SSepherosa Ziehau if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) { 1835*15516c77SSepherosa Ziehau m_new->m_pkthdr.ether_vtag = EVL_MAKETAG( 1836*15516c77SSepherosa Ziehau NDIS_VLAN_INFO_ID(info->vlan_info), 1837*15516c77SSepherosa Ziehau NDIS_VLAN_INFO_PRI(info->vlan_info), 1838*15516c77SSepherosa Ziehau NDIS_VLAN_INFO_CFI(info->vlan_info)); 1839*15516c77SSepherosa Ziehau m_new->m_flags |= M_VLANTAG; 1840*15516c77SSepherosa Ziehau } 1841*15516c77SSepherosa Ziehau 1842*15516c77SSepherosa Ziehau if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) { 1843*15516c77SSepherosa Ziehau rxr->hn_rss_pkts++; 1844*15516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = info->hash_value; 1845*15516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE_HASH; 1846*15516c77SSepherosa Ziehau if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) == 1847*15516c77SSepherosa Ziehau NDIS_HASH_FUNCTION_TOEPLITZ) { 1848*15516c77SSepherosa Ziehau uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK); 1849*15516c77SSepherosa Ziehau 1850*15516c77SSepherosa Ziehau /* 1851*15516c77SSepherosa Ziehau * NOTE: 1852*15516c77SSepherosa Ziehau * do_lro is resetted, if the hash types are not TCP 1853*15516c77SSepherosa Ziehau * related. See the comment in the above csum_flags 1854*15516c77SSepherosa Ziehau * setup section. 1855*15516c77SSepherosa Ziehau */ 1856*15516c77SSepherosa Ziehau switch (type) { 1857*15516c77SSepherosa Ziehau case NDIS_HASH_IPV4: 1858*15516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV4; 1859*15516c77SSepherosa Ziehau do_lro = 0; 1860*15516c77SSepherosa Ziehau break; 1861*15516c77SSepherosa Ziehau 1862*15516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV4: 1863*15516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV4; 1864*15516c77SSepherosa Ziehau break; 1865*15516c77SSepherosa Ziehau 1866*15516c77SSepherosa Ziehau case NDIS_HASH_IPV6: 1867*15516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6; 1868*15516c77SSepherosa Ziehau do_lro = 0; 1869*15516c77SSepherosa Ziehau break; 1870*15516c77SSepherosa Ziehau 1871*15516c77SSepherosa Ziehau case NDIS_HASH_IPV6_EX: 1872*15516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6_EX; 1873*15516c77SSepherosa Ziehau do_lro = 0; 1874*15516c77SSepherosa Ziehau break; 1875*15516c77SSepherosa Ziehau 1876*15516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6: 1877*15516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6; 1878*15516c77SSepherosa Ziehau break; 1879*15516c77SSepherosa Ziehau 1880*15516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6_EX: 1881*15516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX; 1882*15516c77SSepherosa Ziehau break; 1883*15516c77SSepherosa Ziehau } 1884*15516c77SSepherosa Ziehau } 1885*15516c77SSepherosa Ziehau } else { 1886*15516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = rxr->hn_rx_idx; 1887*15516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE; 1888*15516c77SSepherosa Ziehau } 1889*15516c77SSepherosa Ziehau M_HASHTYPE_SET(m_new, hash_type); 1890*15516c77SSepherosa Ziehau 1891*15516c77SSepherosa Ziehau /* 1892*15516c77SSepherosa Ziehau * Note: Moved RX completion back to hv_nv_on_receive() so all 1893*15516c77SSepherosa Ziehau * messages (not just data messages) will trigger a response. 1894*15516c77SSepherosa Ziehau */ 1895*15516c77SSepherosa Ziehau 1896*15516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 1897*15516c77SSepherosa Ziehau rxr->hn_pkts++; 1898*15516c77SSepherosa Ziehau 1899*15516c77SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_LRO) && do_lro) { 1900*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 1901*15516c77SSepherosa Ziehau struct lro_ctrl *lro = &rxr->hn_lro; 1902*15516c77SSepherosa Ziehau 1903*15516c77SSepherosa Ziehau if (lro->lro_cnt) { 1904*15516c77SSepherosa Ziehau rxr->hn_lro_tried++; 1905*15516c77SSepherosa Ziehau if (hn_lro_rx(lro, m_new) == 0) { 1906*15516c77SSepherosa Ziehau /* DONE! */ 1907*15516c77SSepherosa Ziehau return 0; 1908*15516c77SSepherosa Ziehau } 1909*15516c77SSepherosa Ziehau } 1910*15516c77SSepherosa Ziehau #endif 1911*15516c77SSepherosa Ziehau } 1912*15516c77SSepherosa Ziehau 1913*15516c77SSepherosa Ziehau /* We're not holding the lock here, so don't release it */ 1914*15516c77SSepherosa Ziehau (*ifp->if_input)(ifp, m_new); 1915*15516c77SSepherosa Ziehau 1916*15516c77SSepherosa Ziehau return (0); 1917*15516c77SSepherosa Ziehau } 1918*15516c77SSepherosa Ziehau 1919*15516c77SSepherosa Ziehau static int 1920*15516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1921*15516c77SSepherosa Ziehau { 1922*15516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 1923*15516c77SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data; 1924*15516c77SSepherosa Ziehau int mask, error = 0; 1925*15516c77SSepherosa Ziehau 1926*15516c77SSepherosa Ziehau switch (cmd) { 1927*15516c77SSepherosa Ziehau case SIOCSIFMTU: 1928*15516c77SSepherosa Ziehau if (ifr->ifr_mtu > HN_MTU_MAX) { 1929*15516c77SSepherosa Ziehau error = EINVAL; 1930*15516c77SSepherosa Ziehau break; 1931*15516c77SSepherosa Ziehau } 1932*15516c77SSepherosa Ziehau 1933*15516c77SSepherosa Ziehau HN_LOCK(sc); 1934*15516c77SSepherosa Ziehau 1935*15516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 1936*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 1937*15516c77SSepherosa Ziehau break; 1938*15516c77SSepherosa Ziehau } 1939*15516c77SSepherosa Ziehau 1940*15516c77SSepherosa Ziehau if ((sc->hn_caps & HN_CAP_MTU) == 0) { 1941*15516c77SSepherosa Ziehau /* Can't change MTU */ 1942*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 1943*15516c77SSepherosa Ziehau error = EOPNOTSUPP; 1944*15516c77SSepherosa Ziehau break; 1945*15516c77SSepherosa Ziehau } 1946*15516c77SSepherosa Ziehau 1947*15516c77SSepherosa Ziehau if (ifp->if_mtu == ifr->ifr_mtu) { 1948*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 1949*15516c77SSepherosa Ziehau break; 1950*15516c77SSepherosa Ziehau } 1951*15516c77SSepherosa Ziehau 1952*15516c77SSepherosa Ziehau /* 1953*15516c77SSepherosa Ziehau * Suspend this interface before the synthetic parts 1954*15516c77SSepherosa Ziehau * are ripped. 1955*15516c77SSepherosa Ziehau */ 1956*15516c77SSepherosa Ziehau hn_suspend(sc); 1957*15516c77SSepherosa Ziehau 1958*15516c77SSepherosa Ziehau /* 1959*15516c77SSepherosa Ziehau * Detach the synthetics parts, i.e. NVS and RNDIS. 1960*15516c77SSepherosa Ziehau */ 1961*15516c77SSepherosa Ziehau hn_synth_detach(sc); 1962*15516c77SSepherosa Ziehau 1963*15516c77SSepherosa Ziehau /* 1964*15516c77SSepherosa Ziehau * Reattach the synthetic parts, i.e. NVS and RNDIS, 1965*15516c77SSepherosa Ziehau * with the new MTU setting. 1966*15516c77SSepherosa Ziehau */ 1967*15516c77SSepherosa Ziehau error = hn_synth_attach(sc, ifr->ifr_mtu); 1968*15516c77SSepherosa Ziehau if (error) { 1969*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 1970*15516c77SSepherosa Ziehau break; 1971*15516c77SSepherosa Ziehau } 1972*15516c77SSepherosa Ziehau 1973*15516c77SSepherosa Ziehau /* 1974*15516c77SSepherosa Ziehau * Commit the requested MTU, after the synthetic parts 1975*15516c77SSepherosa Ziehau * have been successfully attached. 1976*15516c77SSepherosa Ziehau */ 1977*15516c77SSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 1978*15516c77SSepherosa Ziehau 1979*15516c77SSepherosa Ziehau /* 1980*15516c77SSepherosa Ziehau * Make sure that various parameters based on MTU are 1981*15516c77SSepherosa Ziehau * still valid, after the MTU change. 1982*15516c77SSepherosa Ziehau */ 1983*15516c77SSepherosa Ziehau if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax) 1984*15516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 1985*15516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu); 1986*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 1987*15516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < 1988*15516c77SSepherosa Ziehau HN_LRO_LENLIM_MIN(ifp)) 1989*15516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp)); 1990*15516c77SSepherosa Ziehau #endif 1991*15516c77SSepherosa Ziehau 1992*15516c77SSepherosa Ziehau /* 1993*15516c77SSepherosa Ziehau * All done! Resume the interface now. 1994*15516c77SSepherosa Ziehau */ 1995*15516c77SSepherosa Ziehau hn_resume(sc); 1996*15516c77SSepherosa Ziehau 1997*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 1998*15516c77SSepherosa Ziehau break; 1999*15516c77SSepherosa Ziehau 2000*15516c77SSepherosa Ziehau case SIOCSIFFLAGS: 2001*15516c77SSepherosa Ziehau HN_LOCK(sc); 2002*15516c77SSepherosa Ziehau 2003*15516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 2004*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2005*15516c77SSepherosa Ziehau break; 2006*15516c77SSepherosa Ziehau } 2007*15516c77SSepherosa Ziehau 2008*15516c77SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 2009*15516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2010*15516c77SSepherosa Ziehau hn_set_rxfilter(sc); 2011*15516c77SSepherosa Ziehau else 2012*15516c77SSepherosa Ziehau hn_init_locked(sc); 2013*15516c77SSepherosa Ziehau } else { 2014*15516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2015*15516c77SSepherosa Ziehau hn_stop(sc); 2016*15516c77SSepherosa Ziehau } 2017*15516c77SSepherosa Ziehau sc->hn_if_flags = ifp->if_flags; 2018*15516c77SSepherosa Ziehau 2019*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2020*15516c77SSepherosa Ziehau break; 2021*15516c77SSepherosa Ziehau 2022*15516c77SSepherosa Ziehau case SIOCSIFCAP: 2023*15516c77SSepherosa Ziehau HN_LOCK(sc); 2024*15516c77SSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable; 2025*15516c77SSepherosa Ziehau 2026*15516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM) { 2027*15516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 2028*15516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 2029*15516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc); 2030*15516c77SSepherosa Ziehau else 2031*15516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc); 2032*15516c77SSepherosa Ziehau } 2033*15516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM_IPV6) { 2034*15516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 2035*15516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 2036*15516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc); 2037*15516c77SSepherosa Ziehau else 2038*15516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc); 2039*15516c77SSepherosa Ziehau } 2040*15516c77SSepherosa Ziehau 2041*15516c77SSepherosa Ziehau /* TODO: flip RNDIS offload parameters for RXCSUM. */ 2042*15516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 2043*15516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 2044*15516c77SSepherosa Ziehau #ifdef foo 2045*15516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 2046*15516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM_IPV6) 2047*15516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 2048*15516c77SSepherosa Ziehau #endif 2049*15516c77SSepherosa Ziehau 2050*15516c77SSepherosa Ziehau if (mask & IFCAP_LRO) 2051*15516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_LRO; 2052*15516c77SSepherosa Ziehau 2053*15516c77SSepherosa Ziehau if (mask & IFCAP_TSO4) { 2054*15516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO4; 2055*15516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 2056*15516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 2057*15516c77SSepherosa Ziehau else 2058*15516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP_TSO; 2059*15516c77SSepherosa Ziehau } 2060*15516c77SSepherosa Ziehau if (mask & IFCAP_TSO6) { 2061*15516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO6; 2062*15516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 2063*15516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 2064*15516c77SSepherosa Ziehau else 2065*15516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP6_TSO; 2066*15516c77SSepherosa Ziehau } 2067*15516c77SSepherosa Ziehau 2068*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2069*15516c77SSepherosa Ziehau break; 2070*15516c77SSepherosa Ziehau 2071*15516c77SSepherosa Ziehau case SIOCADDMULTI: 2072*15516c77SSepherosa Ziehau case SIOCDELMULTI: 2073*15516c77SSepherosa Ziehau #ifdef notyet 2074*15516c77SSepherosa Ziehau /* 2075*15516c77SSepherosa Ziehau * XXX 2076*15516c77SSepherosa Ziehau * Multicast uses mutex, while RNDIS RX filter setting 2077*15516c77SSepherosa Ziehau * sleeps. We workaround this by always enabling 2078*15516c77SSepherosa Ziehau * ALLMULTI. ALLMULTI would actually always be on, even 2079*15516c77SSepherosa Ziehau * if we supported the SIOCADDMULTI/SIOCDELMULTI, since 2080*15516c77SSepherosa Ziehau * we don't support multicast address list configuration 2081*15516c77SSepherosa Ziehau * for this driver. 2082*15516c77SSepherosa Ziehau */ 2083*15516c77SSepherosa Ziehau HN_LOCK(sc); 2084*15516c77SSepherosa Ziehau 2085*15516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 2086*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2087*15516c77SSepherosa Ziehau break; 2088*15516c77SSepherosa Ziehau } 2089*15516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2090*15516c77SSepherosa Ziehau hn_set_rxfilter(sc); 2091*15516c77SSepherosa Ziehau 2092*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2093*15516c77SSepherosa Ziehau #endif 2094*15516c77SSepherosa Ziehau break; 2095*15516c77SSepherosa Ziehau 2096*15516c77SSepherosa Ziehau case SIOCSIFMEDIA: 2097*15516c77SSepherosa Ziehau case SIOCGIFMEDIA: 2098*15516c77SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd); 2099*15516c77SSepherosa Ziehau break; 2100*15516c77SSepherosa Ziehau 2101*15516c77SSepherosa Ziehau default: 2102*15516c77SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 2103*15516c77SSepherosa Ziehau break; 2104*15516c77SSepherosa Ziehau } 2105*15516c77SSepherosa Ziehau return (error); 2106*15516c77SSepherosa Ziehau } 2107*15516c77SSepherosa Ziehau 2108*15516c77SSepherosa Ziehau static void 2109*15516c77SSepherosa Ziehau hn_stop(struct hn_softc *sc) 2110*15516c77SSepherosa Ziehau { 2111*15516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 2112*15516c77SSepherosa Ziehau int i; 2113*15516c77SSepherosa Ziehau 2114*15516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 2115*15516c77SSepherosa Ziehau 2116*15516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 2117*15516c77SSepherosa Ziehau ("synthetic parts were not attached")); 2118*15516c77SSepherosa Ziehau 2119*15516c77SSepherosa Ziehau /* Clear RUNNING bit _before_ hn_suspend_data() */ 2120*15516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 2121*15516c77SSepherosa Ziehau hn_suspend_data(sc); 2122*15516c77SSepherosa Ziehau 2123*15516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 2124*15516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 2125*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 2126*15516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 2127*15516c77SSepherosa Ziehau } 2128*15516c77SSepherosa Ziehau 2129*15516c77SSepherosa Ziehau static void 2130*15516c77SSepherosa Ziehau hn_start(struct ifnet *ifp) 2131*15516c77SSepherosa Ziehau { 2132*15516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 2133*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[0]; 2134*15516c77SSepherosa Ziehau 2135*15516c77SSepherosa Ziehau if (txr->hn_sched_tx) 2136*15516c77SSepherosa Ziehau goto do_sched; 2137*15516c77SSepherosa Ziehau 2138*15516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 2139*15516c77SSepherosa Ziehau int sched; 2140*15516c77SSepherosa Ziehau 2141*15516c77SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 2142*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 2143*15516c77SSepherosa Ziehau if (!sched) 2144*15516c77SSepherosa Ziehau return; 2145*15516c77SSepherosa Ziehau } 2146*15516c77SSepherosa Ziehau do_sched: 2147*15516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 2148*15516c77SSepherosa Ziehau } 2149*15516c77SSepherosa Ziehau 2150*15516c77SSepherosa Ziehau static void 2151*15516c77SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr) 2152*15516c77SSepherosa Ziehau { 2153*15516c77SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 2154*15516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 2155*15516c77SSepherosa Ziehau 2156*15516c77SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 2157*15516c77SSepherosa Ziehau 2158*15516c77SSepherosa Ziehau if (txr->hn_sched_tx) 2159*15516c77SSepherosa Ziehau goto do_sched; 2160*15516c77SSepherosa Ziehau 2161*15516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 2162*15516c77SSepherosa Ziehau int sched; 2163*15516c77SSepherosa Ziehau 2164*15516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 2165*15516c77SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 2166*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 2167*15516c77SSepherosa Ziehau if (sched) { 2168*15516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 2169*15516c77SSepherosa Ziehau &txr->hn_tx_task); 2170*15516c77SSepherosa Ziehau } 2171*15516c77SSepherosa Ziehau } else { 2172*15516c77SSepherosa Ziehau do_sched: 2173*15516c77SSepherosa Ziehau /* 2174*15516c77SSepherosa Ziehau * Release the OACTIVE earlier, with the hope, that 2175*15516c77SSepherosa Ziehau * others could catch up. The task will clear the 2176*15516c77SSepherosa Ziehau * flag again with the hn_tx_lock to avoid possible 2177*15516c77SSepherosa Ziehau * races. 2178*15516c77SSepherosa Ziehau */ 2179*15516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 2180*15516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 2181*15516c77SSepherosa Ziehau } 2182*15516c77SSepherosa Ziehau } 2183*15516c77SSepherosa Ziehau 2184*15516c77SSepherosa Ziehau static void 2185*15516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc) 2186*15516c77SSepherosa Ziehau { 2187*15516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 2188*15516c77SSepherosa Ziehau int i; 2189*15516c77SSepherosa Ziehau 2190*15516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 2191*15516c77SSepherosa Ziehau 2192*15516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 2193*15516c77SSepherosa Ziehau return; 2194*15516c77SSepherosa Ziehau 2195*15516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2196*15516c77SSepherosa Ziehau return; 2197*15516c77SSepherosa Ziehau 2198*15516c77SSepherosa Ziehau /* Configure RX filter */ 2199*15516c77SSepherosa Ziehau hn_set_rxfilter(sc); 2200*15516c77SSepherosa Ziehau 2201*15516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 2202*15516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 2203*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 2204*15516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 2205*15516c77SSepherosa Ziehau 2206*15516c77SSepherosa Ziehau /* Clear TX 'suspended' bit. */ 2207*15516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_inuse); 2208*15516c77SSepherosa Ziehau 2209*15516c77SSepherosa Ziehau /* Everything is ready; unleash! */ 2210*15516c77SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 2211*15516c77SSepherosa Ziehau } 2212*15516c77SSepherosa Ziehau 2213*15516c77SSepherosa Ziehau static void 2214*15516c77SSepherosa Ziehau hn_init(void *xsc) 2215*15516c77SSepherosa Ziehau { 2216*15516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 2217*15516c77SSepherosa Ziehau 2218*15516c77SSepherosa Ziehau HN_LOCK(sc); 2219*15516c77SSepherosa Ziehau hn_init_locked(sc); 2220*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2221*15516c77SSepherosa Ziehau } 2222*15516c77SSepherosa Ziehau 2223*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 2224*15516c77SSepherosa Ziehau 2225*15516c77SSepherosa Ziehau static int 2226*15516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS) 2227*15516c77SSepherosa Ziehau { 2228*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2229*15516c77SSepherosa Ziehau unsigned int lenlim; 2230*15516c77SSepherosa Ziehau int error; 2231*15516c77SSepherosa Ziehau 2232*15516c77SSepherosa Ziehau lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim; 2233*15516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &lenlim, 0, req); 2234*15516c77SSepherosa Ziehau if (error || req->newptr == NULL) 2235*15516c77SSepherosa Ziehau return error; 2236*15516c77SSepherosa Ziehau 2237*15516c77SSepherosa Ziehau HN_LOCK(sc); 2238*15516c77SSepherosa Ziehau if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) || 2239*15516c77SSepherosa Ziehau lenlim > TCP_LRO_LENGTH_MAX) { 2240*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2241*15516c77SSepherosa Ziehau return EINVAL; 2242*15516c77SSepherosa Ziehau } 2243*15516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, lenlim); 2244*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2245*15516c77SSepherosa Ziehau 2246*15516c77SSepherosa Ziehau return 0; 2247*15516c77SSepherosa Ziehau } 2248*15516c77SSepherosa Ziehau 2249*15516c77SSepherosa Ziehau static int 2250*15516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS) 2251*15516c77SSepherosa Ziehau { 2252*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2253*15516c77SSepherosa Ziehau int ackcnt, error, i; 2254*15516c77SSepherosa Ziehau 2255*15516c77SSepherosa Ziehau /* 2256*15516c77SSepherosa Ziehau * lro_ackcnt_lim is append count limit, 2257*15516c77SSepherosa Ziehau * +1 to turn it into aggregation limit. 2258*15516c77SSepherosa Ziehau */ 2259*15516c77SSepherosa Ziehau ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1; 2260*15516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &ackcnt, 0, req); 2261*15516c77SSepherosa Ziehau if (error || req->newptr == NULL) 2262*15516c77SSepherosa Ziehau return error; 2263*15516c77SSepherosa Ziehau 2264*15516c77SSepherosa Ziehau if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1)) 2265*15516c77SSepherosa Ziehau return EINVAL; 2266*15516c77SSepherosa Ziehau 2267*15516c77SSepherosa Ziehau /* 2268*15516c77SSepherosa Ziehau * Convert aggregation limit back to append 2269*15516c77SSepherosa Ziehau * count limit. 2270*15516c77SSepherosa Ziehau */ 2271*15516c77SSepherosa Ziehau --ackcnt; 2272*15516c77SSepherosa Ziehau HN_LOCK(sc); 2273*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) 2274*15516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt; 2275*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2276*15516c77SSepherosa Ziehau return 0; 2277*15516c77SSepherosa Ziehau } 2278*15516c77SSepherosa Ziehau 2279*15516c77SSepherosa Ziehau #endif 2280*15516c77SSepherosa Ziehau 2281*15516c77SSepherosa Ziehau static int 2282*15516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS) 2283*15516c77SSepherosa Ziehau { 2284*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2285*15516c77SSepherosa Ziehau int hcsum = arg2; 2286*15516c77SSepherosa Ziehau int on, error, i; 2287*15516c77SSepherosa Ziehau 2288*15516c77SSepherosa Ziehau on = 0; 2289*15516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum) 2290*15516c77SSepherosa Ziehau on = 1; 2291*15516c77SSepherosa Ziehau 2292*15516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &on, 0, req); 2293*15516c77SSepherosa Ziehau if (error || req->newptr == NULL) 2294*15516c77SSepherosa Ziehau return error; 2295*15516c77SSepherosa Ziehau 2296*15516c77SSepherosa Ziehau HN_LOCK(sc); 2297*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) { 2298*15516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 2299*15516c77SSepherosa Ziehau 2300*15516c77SSepherosa Ziehau if (on) 2301*15516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= hcsum; 2302*15516c77SSepherosa Ziehau else 2303*15516c77SSepherosa Ziehau rxr->hn_trust_hcsum &= ~hcsum; 2304*15516c77SSepherosa Ziehau } 2305*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2306*15516c77SSepherosa Ziehau return 0; 2307*15516c77SSepherosa Ziehau } 2308*15516c77SSepherosa Ziehau 2309*15516c77SSepherosa Ziehau static int 2310*15516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS) 2311*15516c77SSepherosa Ziehau { 2312*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2313*15516c77SSepherosa Ziehau int chim_size, error; 2314*15516c77SSepherosa Ziehau 2315*15516c77SSepherosa Ziehau chim_size = sc->hn_tx_ring[0].hn_chim_size; 2316*15516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &chim_size, 0, req); 2317*15516c77SSepherosa Ziehau if (error || req->newptr == NULL) 2318*15516c77SSepherosa Ziehau return error; 2319*15516c77SSepherosa Ziehau 2320*15516c77SSepherosa Ziehau if (chim_size > sc->hn_chim_szmax || chim_size <= 0) 2321*15516c77SSepherosa Ziehau return EINVAL; 2322*15516c77SSepherosa Ziehau 2323*15516c77SSepherosa Ziehau HN_LOCK(sc); 2324*15516c77SSepherosa Ziehau hn_set_chim_size(sc, chim_size); 2325*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2326*15516c77SSepherosa Ziehau return 0; 2327*15516c77SSepherosa Ziehau } 2328*15516c77SSepherosa Ziehau 2329*15516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 2330*15516c77SSepherosa Ziehau static int 2331*15516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS) 2332*15516c77SSepherosa Ziehau { 2333*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2334*15516c77SSepherosa Ziehau int ofs = arg2, i, error; 2335*15516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 2336*15516c77SSepherosa Ziehau uint64_t stat; 2337*15516c77SSepherosa Ziehau 2338*15516c77SSepherosa Ziehau stat = 0; 2339*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 2340*15516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 2341*15516c77SSepherosa Ziehau stat += *((int *)((uint8_t *)rxr + ofs)); 2342*15516c77SSepherosa Ziehau } 2343*15516c77SSepherosa Ziehau 2344*15516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 2345*15516c77SSepherosa Ziehau if (error || req->newptr == NULL) 2346*15516c77SSepherosa Ziehau return error; 2347*15516c77SSepherosa Ziehau 2348*15516c77SSepherosa Ziehau /* Zero out this stat. */ 2349*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 2350*15516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 2351*15516c77SSepherosa Ziehau *((int *)((uint8_t *)rxr + ofs)) = 0; 2352*15516c77SSepherosa Ziehau } 2353*15516c77SSepherosa Ziehau return 0; 2354*15516c77SSepherosa Ziehau } 2355*15516c77SSepherosa Ziehau #else 2356*15516c77SSepherosa Ziehau static int 2357*15516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS) 2358*15516c77SSepherosa Ziehau { 2359*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2360*15516c77SSepherosa Ziehau int ofs = arg2, i, error; 2361*15516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 2362*15516c77SSepherosa Ziehau uint64_t stat; 2363*15516c77SSepherosa Ziehau 2364*15516c77SSepherosa Ziehau stat = 0; 2365*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) { 2366*15516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 2367*15516c77SSepherosa Ziehau stat += *((uint64_t *)((uint8_t *)rxr + ofs)); 2368*15516c77SSepherosa Ziehau } 2369*15516c77SSepherosa Ziehau 2370*15516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 2371*15516c77SSepherosa Ziehau if (error || req->newptr == NULL) 2372*15516c77SSepherosa Ziehau return error; 2373*15516c77SSepherosa Ziehau 2374*15516c77SSepherosa Ziehau /* Zero out this stat. */ 2375*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) { 2376*15516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 2377*15516c77SSepherosa Ziehau *((uint64_t *)((uint8_t *)rxr + ofs)) = 0; 2378*15516c77SSepherosa Ziehau } 2379*15516c77SSepherosa Ziehau return 0; 2380*15516c77SSepherosa Ziehau } 2381*15516c77SSepherosa Ziehau 2382*15516c77SSepherosa Ziehau #endif 2383*15516c77SSepherosa Ziehau 2384*15516c77SSepherosa Ziehau static int 2385*15516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 2386*15516c77SSepherosa Ziehau { 2387*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2388*15516c77SSepherosa Ziehau int ofs = arg2, i, error; 2389*15516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 2390*15516c77SSepherosa Ziehau u_long stat; 2391*15516c77SSepherosa Ziehau 2392*15516c77SSepherosa Ziehau stat = 0; 2393*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) { 2394*15516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 2395*15516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)rxr + ofs)); 2396*15516c77SSepherosa Ziehau } 2397*15516c77SSepherosa Ziehau 2398*15516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 2399*15516c77SSepherosa Ziehau if (error || req->newptr == NULL) 2400*15516c77SSepherosa Ziehau return error; 2401*15516c77SSepherosa Ziehau 2402*15516c77SSepherosa Ziehau /* Zero out this stat. */ 2403*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) { 2404*15516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 2405*15516c77SSepherosa Ziehau *((u_long *)((uint8_t *)rxr + ofs)) = 0; 2406*15516c77SSepherosa Ziehau } 2407*15516c77SSepherosa Ziehau return 0; 2408*15516c77SSepherosa Ziehau } 2409*15516c77SSepherosa Ziehau 2410*15516c77SSepherosa Ziehau static int 2411*15516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 2412*15516c77SSepherosa Ziehau { 2413*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2414*15516c77SSepherosa Ziehau int ofs = arg2, i, error; 2415*15516c77SSepherosa Ziehau struct hn_tx_ring *txr; 2416*15516c77SSepherosa Ziehau u_long stat; 2417*15516c77SSepherosa Ziehau 2418*15516c77SSepherosa Ziehau stat = 0; 2419*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 2420*15516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 2421*15516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)txr + ofs)); 2422*15516c77SSepherosa Ziehau } 2423*15516c77SSepherosa Ziehau 2424*15516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 2425*15516c77SSepherosa Ziehau if (error || req->newptr == NULL) 2426*15516c77SSepherosa Ziehau return error; 2427*15516c77SSepherosa Ziehau 2428*15516c77SSepherosa Ziehau /* Zero out this stat. */ 2429*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 2430*15516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 2431*15516c77SSepherosa Ziehau *((u_long *)((uint8_t *)txr + ofs)) = 0; 2432*15516c77SSepherosa Ziehau } 2433*15516c77SSepherosa Ziehau return 0; 2434*15516c77SSepherosa Ziehau } 2435*15516c77SSepherosa Ziehau 2436*15516c77SSepherosa Ziehau static int 2437*15516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS) 2438*15516c77SSepherosa Ziehau { 2439*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2440*15516c77SSepherosa Ziehau int ofs = arg2, i, error, conf; 2441*15516c77SSepherosa Ziehau struct hn_tx_ring *txr; 2442*15516c77SSepherosa Ziehau 2443*15516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[0]; 2444*15516c77SSepherosa Ziehau conf = *((int *)((uint8_t *)txr + ofs)); 2445*15516c77SSepherosa Ziehau 2446*15516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &conf, 0, req); 2447*15516c77SSepherosa Ziehau if (error || req->newptr == NULL) 2448*15516c77SSepherosa Ziehau return error; 2449*15516c77SSepherosa Ziehau 2450*15516c77SSepherosa Ziehau HN_LOCK(sc); 2451*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 2452*15516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 2453*15516c77SSepherosa Ziehau *((int *)((uint8_t *)txr + ofs)) = conf; 2454*15516c77SSepherosa Ziehau } 2455*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2456*15516c77SSepherosa Ziehau 2457*15516c77SSepherosa Ziehau return 0; 2458*15516c77SSepherosa Ziehau } 2459*15516c77SSepherosa Ziehau 2460*15516c77SSepherosa Ziehau static int 2461*15516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS) 2462*15516c77SSepherosa Ziehau { 2463*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2464*15516c77SSepherosa Ziehau char verstr[16]; 2465*15516c77SSepherosa Ziehau 2466*15516c77SSepherosa Ziehau snprintf(verstr, sizeof(verstr), "%u.%u", 2467*15516c77SSepherosa Ziehau HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 2468*15516c77SSepherosa Ziehau HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 2469*15516c77SSepherosa Ziehau return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 2470*15516c77SSepherosa Ziehau } 2471*15516c77SSepherosa Ziehau 2472*15516c77SSepherosa Ziehau static int 2473*15516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS) 2474*15516c77SSepherosa Ziehau { 2475*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2476*15516c77SSepherosa Ziehau char caps_str[128]; 2477*15516c77SSepherosa Ziehau uint32_t caps; 2478*15516c77SSepherosa Ziehau 2479*15516c77SSepherosa Ziehau HN_LOCK(sc); 2480*15516c77SSepherosa Ziehau caps = sc->hn_caps; 2481*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2482*15516c77SSepherosa Ziehau snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS); 2483*15516c77SSepherosa Ziehau return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req); 2484*15516c77SSepherosa Ziehau } 2485*15516c77SSepherosa Ziehau 2486*15516c77SSepherosa Ziehau static int 2487*15516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS) 2488*15516c77SSepherosa Ziehau { 2489*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2490*15516c77SSepherosa Ziehau char assist_str[128]; 2491*15516c77SSepherosa Ziehau uint32_t hwassist; 2492*15516c77SSepherosa Ziehau 2493*15516c77SSepherosa Ziehau HN_LOCK(sc); 2494*15516c77SSepherosa Ziehau hwassist = sc->hn_ifp->if_hwassist; 2495*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2496*15516c77SSepherosa Ziehau snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS); 2497*15516c77SSepherosa Ziehau return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req); 2498*15516c77SSepherosa Ziehau } 2499*15516c77SSepherosa Ziehau 2500*15516c77SSepherosa Ziehau static int 2501*15516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS) 2502*15516c77SSepherosa Ziehau { 2503*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2504*15516c77SSepherosa Ziehau char filter_str[128]; 2505*15516c77SSepherosa Ziehau uint32_t filter; 2506*15516c77SSepherosa Ziehau 2507*15516c77SSepherosa Ziehau HN_LOCK(sc); 2508*15516c77SSepherosa Ziehau filter = sc->hn_rx_filter; 2509*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2510*15516c77SSepherosa Ziehau snprintf(filter_str, sizeof(filter_str), "%b", filter, 2511*15516c77SSepherosa Ziehau NDIS_PACKET_TYPES); 2512*15516c77SSepherosa Ziehau return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req); 2513*15516c77SSepherosa Ziehau } 2514*15516c77SSepherosa Ziehau 2515*15516c77SSepherosa Ziehau static int 2516*15516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS) 2517*15516c77SSepherosa Ziehau { 2518*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2519*15516c77SSepherosa Ziehau int error; 2520*15516c77SSepherosa Ziehau 2521*15516c77SSepherosa Ziehau HN_LOCK(sc); 2522*15516c77SSepherosa Ziehau 2523*15516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 2524*15516c77SSepherosa Ziehau if (error || req->newptr == NULL) 2525*15516c77SSepherosa Ziehau goto back; 2526*15516c77SSepherosa Ziehau 2527*15516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 2528*15516c77SSepherosa Ziehau if (error) 2529*15516c77SSepherosa Ziehau goto back; 2530*15516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 2531*15516c77SSepherosa Ziehau 2532*15516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 2533*15516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 2534*15516c77SSepherosa Ziehau } else { 2535*15516c77SSepherosa Ziehau /* Not RSS capable, at least for now; just save the RSS key. */ 2536*15516c77SSepherosa Ziehau error = 0; 2537*15516c77SSepherosa Ziehau } 2538*15516c77SSepherosa Ziehau back: 2539*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2540*15516c77SSepherosa Ziehau return (error); 2541*15516c77SSepherosa Ziehau } 2542*15516c77SSepherosa Ziehau 2543*15516c77SSepherosa Ziehau static int 2544*15516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS) 2545*15516c77SSepherosa Ziehau { 2546*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2547*15516c77SSepherosa Ziehau int error; 2548*15516c77SSepherosa Ziehau 2549*15516c77SSepherosa Ziehau HN_LOCK(sc); 2550*15516c77SSepherosa Ziehau 2551*15516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 2552*15516c77SSepherosa Ziehau if (error || req->newptr == NULL) 2553*15516c77SSepherosa Ziehau goto back; 2554*15516c77SSepherosa Ziehau 2555*15516c77SSepherosa Ziehau /* 2556*15516c77SSepherosa Ziehau * Don't allow RSS indirect table change, if this interface is not 2557*15516c77SSepherosa Ziehau * RSS capable currently. 2558*15516c77SSepherosa Ziehau */ 2559*15516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 2560*15516c77SSepherosa Ziehau error = EOPNOTSUPP; 2561*15516c77SSepherosa Ziehau goto back; 2562*15516c77SSepherosa Ziehau } 2563*15516c77SSepherosa Ziehau 2564*15516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 2565*15516c77SSepherosa Ziehau if (error) 2566*15516c77SSepherosa Ziehau goto back; 2567*15516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 2568*15516c77SSepherosa Ziehau 2569*15516c77SSepherosa Ziehau hn_rss_ind_fixup(sc, sc->hn_rx_ring_inuse); 2570*15516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 2571*15516c77SSepherosa Ziehau back: 2572*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2573*15516c77SSepherosa Ziehau return (error); 2574*15516c77SSepherosa Ziehau } 2575*15516c77SSepherosa Ziehau 2576*15516c77SSepherosa Ziehau static int 2577*15516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS) 2578*15516c77SSepherosa Ziehau { 2579*15516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 2580*15516c77SSepherosa Ziehau char hash_str[128]; 2581*15516c77SSepherosa Ziehau uint32_t hash; 2582*15516c77SSepherosa Ziehau 2583*15516c77SSepherosa Ziehau HN_LOCK(sc); 2584*15516c77SSepherosa Ziehau hash = sc->hn_rss_hash; 2585*15516c77SSepherosa Ziehau HN_UNLOCK(sc); 2586*15516c77SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 2587*15516c77SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 2588*15516c77SSepherosa Ziehau } 2589*15516c77SSepherosa Ziehau 2590*15516c77SSepherosa Ziehau static int 2591*15516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff) 2592*15516c77SSepherosa Ziehau { 2593*15516c77SSepherosa Ziehau const struct ip *ip; 2594*15516c77SSepherosa Ziehau int len, iphlen, iplen; 2595*15516c77SSepherosa Ziehau const struct tcphdr *th; 2596*15516c77SSepherosa Ziehau int thoff; /* TCP data offset */ 2597*15516c77SSepherosa Ziehau 2598*15516c77SSepherosa Ziehau len = hoff + sizeof(struct ip); 2599*15516c77SSepherosa Ziehau 2600*15516c77SSepherosa Ziehau /* The packet must be at least the size of an IP header. */ 2601*15516c77SSepherosa Ziehau if (m->m_pkthdr.len < len) 2602*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2603*15516c77SSepherosa Ziehau 2604*15516c77SSepherosa Ziehau /* The fixed IP header must reside completely in the first mbuf. */ 2605*15516c77SSepherosa Ziehau if (m->m_len < len) 2606*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2607*15516c77SSepherosa Ziehau 2608*15516c77SSepherosa Ziehau ip = mtodo(m, hoff); 2609*15516c77SSepherosa Ziehau 2610*15516c77SSepherosa Ziehau /* Bound check the packet's stated IP header length. */ 2611*15516c77SSepherosa Ziehau iphlen = ip->ip_hl << 2; 2612*15516c77SSepherosa Ziehau if (iphlen < sizeof(struct ip)) /* minimum header length */ 2613*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2614*15516c77SSepherosa Ziehau 2615*15516c77SSepherosa Ziehau /* The full IP header must reside completely in the one mbuf. */ 2616*15516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen) 2617*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2618*15516c77SSepherosa Ziehau 2619*15516c77SSepherosa Ziehau iplen = ntohs(ip->ip_len); 2620*15516c77SSepherosa Ziehau 2621*15516c77SSepherosa Ziehau /* 2622*15516c77SSepherosa Ziehau * Check that the amount of data in the buffers is as 2623*15516c77SSepherosa Ziehau * at least much as the IP header would have us expect. 2624*15516c77SSepherosa Ziehau */ 2625*15516c77SSepherosa Ziehau if (m->m_pkthdr.len < hoff + iplen) 2626*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2627*15516c77SSepherosa Ziehau 2628*15516c77SSepherosa Ziehau /* 2629*15516c77SSepherosa Ziehau * Ignore IP fragments. 2630*15516c77SSepherosa Ziehau */ 2631*15516c77SSepherosa Ziehau if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF)) 2632*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2633*15516c77SSepherosa Ziehau 2634*15516c77SSepherosa Ziehau /* 2635*15516c77SSepherosa Ziehau * The TCP/IP or UDP/IP header must be entirely contained within 2636*15516c77SSepherosa Ziehau * the first fragment of a packet. 2637*15516c77SSepherosa Ziehau */ 2638*15516c77SSepherosa Ziehau switch (ip->ip_p) { 2639*15516c77SSepherosa Ziehau case IPPROTO_TCP: 2640*15516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct tcphdr)) 2641*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2642*15516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct tcphdr)) 2643*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2644*15516c77SSepherosa Ziehau th = (const struct tcphdr *)((const uint8_t *)ip + iphlen); 2645*15516c77SSepherosa Ziehau thoff = th->th_off << 2; 2646*15516c77SSepherosa Ziehau if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen) 2647*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2648*15516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + thoff) 2649*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2650*15516c77SSepherosa Ziehau break; 2651*15516c77SSepherosa Ziehau case IPPROTO_UDP: 2652*15516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct udphdr)) 2653*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2654*15516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct udphdr)) 2655*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2656*15516c77SSepherosa Ziehau break; 2657*15516c77SSepherosa Ziehau default: 2658*15516c77SSepherosa Ziehau if (iplen < iphlen) 2659*15516c77SSepherosa Ziehau return IPPROTO_DONE; 2660*15516c77SSepherosa Ziehau break; 2661*15516c77SSepherosa Ziehau } 2662*15516c77SSepherosa Ziehau return ip->ip_p; 2663*15516c77SSepherosa Ziehau } 2664*15516c77SSepherosa Ziehau 2665*15516c77SSepherosa Ziehau static int 2666*15516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt) 2667*15516c77SSepherosa Ziehau { 2668*15516c77SSepherosa Ziehau struct sysctl_oid_list *child; 2669*15516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 2670*15516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 2671*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 2672*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 2673*15516c77SSepherosa Ziehau int lroent_cnt; 2674*15516c77SSepherosa Ziehau #endif 2675*15516c77SSepherosa Ziehau #endif 2676*15516c77SSepherosa Ziehau int i; 2677*15516c77SSepherosa Ziehau 2678*15516c77SSepherosa Ziehau /* 2679*15516c77SSepherosa Ziehau * Create RXBUF for reception. 2680*15516c77SSepherosa Ziehau * 2681*15516c77SSepherosa Ziehau * NOTE: 2682*15516c77SSepherosa Ziehau * - It is shared by all channels. 2683*15516c77SSepherosa Ziehau * - A large enough buffer is allocated, certain version of NVSes 2684*15516c77SSepherosa Ziehau * may further limit the usable space. 2685*15516c77SSepherosa Ziehau */ 2686*15516c77SSepherosa Ziehau sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 2687*15516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma, 2688*15516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 2689*15516c77SSepherosa Ziehau if (sc->hn_rxbuf == NULL) { 2690*15516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate rxbuf failed\n"); 2691*15516c77SSepherosa Ziehau return (ENOMEM); 2692*15516c77SSepherosa Ziehau } 2693*15516c77SSepherosa Ziehau 2694*15516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = ring_cnt; 2695*15516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt; 2696*15516c77SSepherosa Ziehau 2697*15516c77SSepherosa Ziehau sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt, 2698*15516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 2699*15516c77SSepherosa Ziehau 2700*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 2701*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 2702*15516c77SSepherosa Ziehau lroent_cnt = hn_lro_entry_count; 2703*15516c77SSepherosa Ziehau if (lroent_cnt < TCP_LRO_ENTRIES) 2704*15516c77SSepherosa Ziehau lroent_cnt = TCP_LRO_ENTRIES; 2705*15516c77SSepherosa Ziehau if (bootverbose) 2706*15516c77SSepherosa Ziehau device_printf(dev, "LRO: entry count %d\n", lroent_cnt); 2707*15516c77SSepherosa Ziehau #endif 2708*15516c77SSepherosa Ziehau #endif /* INET || INET6 */ 2709*15516c77SSepherosa Ziehau 2710*15516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 2711*15516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 2712*15516c77SSepherosa Ziehau 2713*15516c77SSepherosa Ziehau /* Create dev.hn.UNIT.rx sysctl tree */ 2714*15516c77SSepherosa Ziehau sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx", 2715*15516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 2716*15516c77SSepherosa Ziehau 2717*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 2718*15516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 2719*15516c77SSepherosa Ziehau 2720*15516c77SSepherosa Ziehau rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 2721*15516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE, 2722*15516c77SSepherosa Ziehau &rxr->hn_br_dma, BUS_DMA_WAITOK); 2723*15516c77SSepherosa Ziehau if (rxr->hn_br == NULL) { 2724*15516c77SSepherosa Ziehau device_printf(dev, "allocate bufring failed\n"); 2725*15516c77SSepherosa Ziehau return (ENOMEM); 2726*15516c77SSepherosa Ziehau } 2727*15516c77SSepherosa Ziehau 2728*15516c77SSepherosa Ziehau if (hn_trust_hosttcp) 2729*15516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP; 2730*15516c77SSepherosa Ziehau if (hn_trust_hostudp) 2731*15516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP; 2732*15516c77SSepherosa Ziehau if (hn_trust_hostip) 2733*15516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP; 2734*15516c77SSepherosa Ziehau rxr->hn_ifp = sc->hn_ifp; 2735*15516c77SSepherosa Ziehau if (i < sc->hn_tx_ring_cnt) 2736*15516c77SSepherosa Ziehau rxr->hn_txr = &sc->hn_tx_ring[i]; 2737*15516c77SSepherosa Ziehau rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF; 2738*15516c77SSepherosa Ziehau rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK); 2739*15516c77SSepherosa Ziehau rxr->hn_rx_idx = i; 2740*15516c77SSepherosa Ziehau rxr->hn_rxbuf = sc->hn_rxbuf; 2741*15516c77SSepherosa Ziehau 2742*15516c77SSepherosa Ziehau /* 2743*15516c77SSepherosa Ziehau * Initialize LRO. 2744*15516c77SSepherosa Ziehau */ 2745*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 2746*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 2747*15516c77SSepherosa Ziehau tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt, 2748*15516c77SSepherosa Ziehau hn_lro_mbufq_depth); 2749*15516c77SSepherosa Ziehau #else 2750*15516c77SSepherosa Ziehau tcp_lro_init(&rxr->hn_lro); 2751*15516c77SSepherosa Ziehau rxr->hn_lro.ifp = sc->hn_ifp; 2752*15516c77SSepherosa Ziehau #endif 2753*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 2754*15516c77SSepherosa Ziehau rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF; 2755*15516c77SSepherosa Ziehau rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF; 2756*15516c77SSepherosa Ziehau #endif 2757*15516c77SSepherosa Ziehau #endif /* INET || INET6 */ 2758*15516c77SSepherosa Ziehau 2759*15516c77SSepherosa Ziehau if (sc->hn_rx_sysctl_tree != NULL) { 2760*15516c77SSepherosa Ziehau char name[16]; 2761*15516c77SSepherosa Ziehau 2762*15516c77SSepherosa Ziehau /* 2763*15516c77SSepherosa Ziehau * Create per RX ring sysctl tree: 2764*15516c77SSepherosa Ziehau * dev.hn.UNIT.rx.RINGID 2765*15516c77SSepherosa Ziehau */ 2766*15516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", i); 2767*15516c77SSepherosa Ziehau rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, 2768*15516c77SSepherosa Ziehau SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree), 2769*15516c77SSepherosa Ziehau OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 2770*15516c77SSepherosa Ziehau 2771*15516c77SSepherosa Ziehau if (rxr->hn_rx_sysctl_tree != NULL) { 2772*15516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 2773*15516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 2774*15516c77SSepherosa Ziehau OID_AUTO, "packets", CTLFLAG_RW, 2775*15516c77SSepherosa Ziehau &rxr->hn_pkts, "# of packets received"); 2776*15516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 2777*15516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 2778*15516c77SSepherosa Ziehau OID_AUTO, "rss_pkts", CTLFLAG_RW, 2779*15516c77SSepherosa Ziehau &rxr->hn_rss_pkts, 2780*15516c77SSepherosa Ziehau "# of packets w/ RSS info received"); 2781*15516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, 2782*15516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 2783*15516c77SSepherosa Ziehau OID_AUTO, "pktbuf_len", CTLFLAG_RD, 2784*15516c77SSepherosa Ziehau &rxr->hn_pktbuf_len, 0, 2785*15516c77SSepherosa Ziehau "Temporary channel packet buffer length"); 2786*15516c77SSepherosa Ziehau } 2787*15516c77SSepherosa Ziehau } 2788*15516c77SSepherosa Ziehau } 2789*15516c77SSepherosa Ziehau 2790*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued", 2791*15516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 2792*15516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_queued), 2793*15516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 2794*15516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 2795*15516c77SSepherosa Ziehau #else 2796*15516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 2797*15516c77SSepherosa Ziehau #endif 2798*15516c77SSepherosa Ziehau "LU", "LRO queued"); 2799*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed", 2800*15516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 2801*15516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_flushed), 2802*15516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 2803*15516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 2804*15516c77SSepherosa Ziehau #else 2805*15516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 2806*15516c77SSepherosa Ziehau #endif 2807*15516c77SSepherosa Ziehau "LU", "LRO flushed"); 2808*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried", 2809*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 2810*15516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro_tried), 2811*15516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries"); 2812*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 2813*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim", 2814*15516c77SSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 2815*15516c77SSepherosa Ziehau hn_lro_lenlim_sysctl, "IU", 2816*15516c77SSepherosa Ziehau "Max # of data bytes to be aggregated by LRO"); 2817*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim", 2818*15516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 2819*15516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl, "I", 2820*15516c77SSepherosa Ziehau "Max # of ACKs to be aggregated by LRO"); 2821*15516c77SSepherosa Ziehau #endif 2822*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp", 2823*15516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP, 2824*15516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 2825*15516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 2826*15516c77SSepherosa Ziehau "when csum info is missing"); 2827*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp", 2828*15516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP, 2829*15516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 2830*15516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 2831*15516c77SSepherosa Ziehau "when csum info is missing"); 2832*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip", 2833*15516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP, 2834*15516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 2835*15516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 2836*15516c77SSepherosa Ziehau "when csum info is missing"); 2837*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip", 2838*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 2839*15516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_ip), 2840*15516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP"); 2841*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp", 2842*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 2843*15516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_tcp), 2844*15516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP"); 2845*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp", 2846*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 2847*15516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_udp), 2848*15516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP"); 2849*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted", 2850*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 2851*15516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_trusted), 2852*15516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", 2853*15516c77SSepherosa Ziehau "# of packets that we trust host's csum verification"); 2854*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts", 2855*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 2856*15516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_small_pkts), 2857*15516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of small packets received"); 2858*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed", 2859*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 2860*15516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_ack_failed), 2861*15516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures"); 2862*15516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt", 2863*15516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings"); 2864*15516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse", 2865*15516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings"); 2866*15516c77SSepherosa Ziehau 2867*15516c77SSepherosa Ziehau return (0); 2868*15516c77SSepherosa Ziehau } 2869*15516c77SSepherosa Ziehau 2870*15516c77SSepherosa Ziehau static void 2871*15516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc) 2872*15516c77SSepherosa Ziehau { 2873*15516c77SSepherosa Ziehau int i; 2874*15516c77SSepherosa Ziehau 2875*15516c77SSepherosa Ziehau if (sc->hn_rxbuf != NULL) { 2876*15516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf); 2877*15516c77SSepherosa Ziehau sc->hn_rxbuf = NULL; 2878*15516c77SSepherosa Ziehau } 2879*15516c77SSepherosa Ziehau 2880*15516c77SSepherosa Ziehau if (sc->hn_rx_ring_cnt == 0) 2881*15516c77SSepherosa Ziehau return; 2882*15516c77SSepherosa Ziehau 2883*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 2884*15516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 2885*15516c77SSepherosa Ziehau 2886*15516c77SSepherosa Ziehau if (rxr->hn_br == NULL) 2887*15516c77SSepherosa Ziehau continue; 2888*15516c77SSepherosa Ziehau hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br); 2889*15516c77SSepherosa Ziehau rxr->hn_br = NULL; 2890*15516c77SSepherosa Ziehau 2891*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 2892*15516c77SSepherosa Ziehau tcp_lro_free(&rxr->hn_lro); 2893*15516c77SSepherosa Ziehau #endif 2894*15516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 2895*15516c77SSepherosa Ziehau } 2896*15516c77SSepherosa Ziehau free(sc->hn_rx_ring, M_DEVBUF); 2897*15516c77SSepherosa Ziehau sc->hn_rx_ring = NULL; 2898*15516c77SSepherosa Ziehau 2899*15516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = 0; 2900*15516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = 0; 2901*15516c77SSepherosa Ziehau } 2902*15516c77SSepherosa Ziehau 2903*15516c77SSepherosa Ziehau static int 2904*15516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id) 2905*15516c77SSepherosa Ziehau { 2906*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[id]; 2907*15516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 2908*15516c77SSepherosa Ziehau bus_dma_tag_t parent_dtag; 2909*15516c77SSepherosa Ziehau int error, i; 2910*15516c77SSepherosa Ziehau 2911*15516c77SSepherosa Ziehau txr->hn_sc = sc; 2912*15516c77SSepherosa Ziehau txr->hn_tx_idx = id; 2913*15516c77SSepherosa Ziehau 2914*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 2915*15516c77SSepherosa Ziehau mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); 2916*15516c77SSepherosa Ziehau #endif 2917*15516c77SSepherosa Ziehau mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF); 2918*15516c77SSepherosa Ziehau 2919*15516c77SSepherosa Ziehau txr->hn_txdesc_cnt = HN_TX_DESC_CNT; 2920*15516c77SSepherosa Ziehau txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt, 2921*15516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 2922*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 2923*15516c77SSepherosa Ziehau SLIST_INIT(&txr->hn_txlist); 2924*15516c77SSepherosa Ziehau #else 2925*15516c77SSepherosa Ziehau txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF, 2926*15516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 2927*15516c77SSepherosa Ziehau #endif 2928*15516c77SSepherosa Ziehau 2929*15516c77SSepherosa Ziehau txr->hn_tx_taskq = sc->hn_tx_taskq; 2930*15516c77SSepherosa Ziehau 2931*15516c77SSepherosa Ziehau if (hn_use_if_start) { 2932*15516c77SSepherosa Ziehau txr->hn_txeof = hn_start_txeof; 2933*15516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr); 2934*15516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr); 2935*15516c77SSepherosa Ziehau } else { 2936*15516c77SSepherosa Ziehau int br_depth; 2937*15516c77SSepherosa Ziehau 2938*15516c77SSepherosa Ziehau txr->hn_txeof = hn_xmit_txeof; 2939*15516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr); 2940*15516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr); 2941*15516c77SSepherosa Ziehau 2942*15516c77SSepherosa Ziehau br_depth = hn_get_txswq_depth(txr); 2943*15516c77SSepherosa Ziehau txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF, 2944*15516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 2945*15516c77SSepherosa Ziehau } 2946*15516c77SSepherosa Ziehau 2947*15516c77SSepherosa Ziehau txr->hn_direct_tx_size = hn_direct_tx_size; 2948*15516c77SSepherosa Ziehau 2949*15516c77SSepherosa Ziehau /* 2950*15516c77SSepherosa Ziehau * Always schedule transmission instead of trying to do direct 2951*15516c77SSepherosa Ziehau * transmission. This one gives the best performance so far. 2952*15516c77SSepherosa Ziehau */ 2953*15516c77SSepherosa Ziehau txr->hn_sched_tx = 1; 2954*15516c77SSepherosa Ziehau 2955*15516c77SSepherosa Ziehau parent_dtag = bus_get_dma_tag(dev); 2956*15516c77SSepherosa Ziehau 2957*15516c77SSepherosa Ziehau /* DMA tag for RNDIS packet messages. */ 2958*15516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 2959*15516c77SSepherosa Ziehau HN_RNDIS_PKT_ALIGN, /* alignment */ 2960*15516c77SSepherosa Ziehau HN_RNDIS_PKT_BOUNDARY, /* boundary */ 2961*15516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 2962*15516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 2963*15516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 2964*15516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsize */ 2965*15516c77SSepherosa Ziehau 1, /* nsegments */ 2966*15516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsegsize */ 2967*15516c77SSepherosa Ziehau 0, /* flags */ 2968*15516c77SSepherosa Ziehau NULL, /* lockfunc */ 2969*15516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 2970*15516c77SSepherosa Ziehau &txr->hn_tx_rndis_dtag); 2971*15516c77SSepherosa Ziehau if (error) { 2972*15516c77SSepherosa Ziehau device_printf(dev, "failed to create rndis dmatag\n"); 2973*15516c77SSepherosa Ziehau return error; 2974*15516c77SSepherosa Ziehau } 2975*15516c77SSepherosa Ziehau 2976*15516c77SSepherosa Ziehau /* DMA tag for data. */ 2977*15516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 2978*15516c77SSepherosa Ziehau 1, /* alignment */ 2979*15516c77SSepherosa Ziehau HN_TX_DATA_BOUNDARY, /* boundary */ 2980*15516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 2981*15516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 2982*15516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 2983*15516c77SSepherosa Ziehau HN_TX_DATA_MAXSIZE, /* maxsize */ 2984*15516c77SSepherosa Ziehau HN_TX_DATA_SEGCNT_MAX, /* nsegments */ 2985*15516c77SSepherosa Ziehau HN_TX_DATA_SEGSIZE, /* maxsegsize */ 2986*15516c77SSepherosa Ziehau 0, /* flags */ 2987*15516c77SSepherosa Ziehau NULL, /* lockfunc */ 2988*15516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 2989*15516c77SSepherosa Ziehau &txr->hn_tx_data_dtag); 2990*15516c77SSepherosa Ziehau if (error) { 2991*15516c77SSepherosa Ziehau device_printf(dev, "failed to create data dmatag\n"); 2992*15516c77SSepherosa Ziehau return error; 2993*15516c77SSepherosa Ziehau } 2994*15516c77SSepherosa Ziehau 2995*15516c77SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) { 2996*15516c77SSepherosa Ziehau struct hn_txdesc *txd = &txr->hn_txdesc[i]; 2997*15516c77SSepherosa Ziehau 2998*15516c77SSepherosa Ziehau txd->txr = txr; 2999*15516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 3000*15516c77SSepherosa Ziehau 3001*15516c77SSepherosa Ziehau /* 3002*15516c77SSepherosa Ziehau * Allocate and load RNDIS packet message. 3003*15516c77SSepherosa Ziehau */ 3004*15516c77SSepherosa Ziehau error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag, 3005*15516c77SSepherosa Ziehau (void **)&txd->rndis_pkt, 3006*15516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 3007*15516c77SSepherosa Ziehau &txd->rndis_pkt_dmap); 3008*15516c77SSepherosa Ziehau if (error) { 3009*15516c77SSepherosa Ziehau device_printf(dev, 3010*15516c77SSepherosa Ziehau "failed to allocate rndis_packet_msg, %d\n", i); 3011*15516c77SSepherosa Ziehau return error; 3012*15516c77SSepherosa Ziehau } 3013*15516c77SSepherosa Ziehau 3014*15516c77SSepherosa Ziehau error = bus_dmamap_load(txr->hn_tx_rndis_dtag, 3015*15516c77SSepherosa Ziehau txd->rndis_pkt_dmap, 3016*15516c77SSepherosa Ziehau txd->rndis_pkt, HN_RNDIS_PKT_LEN, 3017*15516c77SSepherosa Ziehau hyperv_dma_map_paddr, &txd->rndis_pkt_paddr, 3018*15516c77SSepherosa Ziehau BUS_DMA_NOWAIT); 3019*15516c77SSepherosa Ziehau if (error) { 3020*15516c77SSepherosa Ziehau device_printf(dev, 3021*15516c77SSepherosa Ziehau "failed to load rndis_packet_msg, %d\n", i); 3022*15516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 3023*15516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 3024*15516c77SSepherosa Ziehau return error; 3025*15516c77SSepherosa Ziehau } 3026*15516c77SSepherosa Ziehau 3027*15516c77SSepherosa Ziehau /* DMA map for TX data. */ 3028*15516c77SSepherosa Ziehau error = bus_dmamap_create(txr->hn_tx_data_dtag, 0, 3029*15516c77SSepherosa Ziehau &txd->data_dmap); 3030*15516c77SSepherosa Ziehau if (error) { 3031*15516c77SSepherosa Ziehau device_printf(dev, 3032*15516c77SSepherosa Ziehau "failed to allocate tx data dmamap\n"); 3033*15516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, 3034*15516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 3035*15516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 3036*15516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 3037*15516c77SSepherosa Ziehau return error; 3038*15516c77SSepherosa Ziehau } 3039*15516c77SSepherosa Ziehau 3040*15516c77SSepherosa Ziehau /* All set, put it to list */ 3041*15516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 3042*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 3043*15516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 3044*15516c77SSepherosa Ziehau #else 3045*15516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 3046*15516c77SSepherosa Ziehau #endif 3047*15516c77SSepherosa Ziehau } 3048*15516c77SSepherosa Ziehau txr->hn_txdesc_avail = txr->hn_txdesc_cnt; 3049*15516c77SSepherosa Ziehau 3050*15516c77SSepherosa Ziehau if (sc->hn_tx_sysctl_tree != NULL) { 3051*15516c77SSepherosa Ziehau struct sysctl_oid_list *child; 3052*15516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 3053*15516c77SSepherosa Ziehau char name[16]; 3054*15516c77SSepherosa Ziehau 3055*15516c77SSepherosa Ziehau /* 3056*15516c77SSepherosa Ziehau * Create per TX ring sysctl tree: 3057*15516c77SSepherosa Ziehau * dev.hn.UNIT.tx.RINGID 3058*15516c77SSepherosa Ziehau */ 3059*15516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 3060*15516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree); 3061*15516c77SSepherosa Ziehau 3062*15516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", id); 3063*15516c77SSepherosa Ziehau txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, 3064*15516c77SSepherosa Ziehau name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 3065*15516c77SSepherosa Ziehau 3066*15516c77SSepherosa Ziehau if (txr->hn_tx_sysctl_tree != NULL) { 3067*15516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree); 3068*15516c77SSepherosa Ziehau 3069*15516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail", 3070*15516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_txdesc_avail, 0, 3071*15516c77SSepherosa Ziehau "# of available TX descs"); 3072*15516c77SSepherosa Ziehau if (!hn_use_if_start) { 3073*15516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive", 3074*15516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_oactive, 0, 3075*15516c77SSepherosa Ziehau "over active"); 3076*15516c77SSepherosa Ziehau } 3077*15516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets", 3078*15516c77SSepherosa Ziehau CTLFLAG_RW, &txr->hn_pkts, 3079*15516c77SSepherosa Ziehau "# of packets transmitted"); 3080*15516c77SSepherosa Ziehau } 3081*15516c77SSepherosa Ziehau } 3082*15516c77SSepherosa Ziehau 3083*15516c77SSepherosa Ziehau return 0; 3084*15516c77SSepherosa Ziehau } 3085*15516c77SSepherosa Ziehau 3086*15516c77SSepherosa Ziehau static void 3087*15516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd) 3088*15516c77SSepherosa Ziehau { 3089*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = txd->txr; 3090*15516c77SSepherosa Ziehau 3091*15516c77SSepherosa Ziehau KASSERT(txd->m == NULL, ("still has mbuf installed")); 3092*15516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped")); 3093*15516c77SSepherosa Ziehau 3094*15516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap); 3095*15516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt, 3096*15516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 3097*15516c77SSepherosa Ziehau bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap); 3098*15516c77SSepherosa Ziehau } 3099*15516c77SSepherosa Ziehau 3100*15516c77SSepherosa Ziehau static void 3101*15516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr) 3102*15516c77SSepherosa Ziehau { 3103*15516c77SSepherosa Ziehau struct hn_txdesc *txd; 3104*15516c77SSepherosa Ziehau 3105*15516c77SSepherosa Ziehau if (txr->hn_txdesc == NULL) 3106*15516c77SSepherosa Ziehau return; 3107*15516c77SSepherosa Ziehau 3108*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 3109*15516c77SSepherosa Ziehau while ((txd = SLIST_FIRST(&txr->hn_txlist)) != NULL) { 3110*15516c77SSepherosa Ziehau SLIST_REMOVE_HEAD(&txr->hn_txlist, link); 3111*15516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(txd); 3112*15516c77SSepherosa Ziehau } 3113*15516c77SSepherosa Ziehau #else 3114*15516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 3115*15516c77SSepherosa Ziehau while ((txd = buf_ring_dequeue_sc(txr->hn_txdesc_br)) != NULL) 3116*15516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(txd); 3117*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 3118*15516c77SSepherosa Ziehau #endif 3119*15516c77SSepherosa Ziehau 3120*15516c77SSepherosa Ziehau if (txr->hn_tx_data_dtag != NULL) 3121*15516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_data_dtag); 3122*15516c77SSepherosa Ziehau if (txr->hn_tx_rndis_dtag != NULL) 3123*15516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_rndis_dtag); 3124*15516c77SSepherosa Ziehau 3125*15516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 3126*15516c77SSepherosa Ziehau buf_ring_free(txr->hn_txdesc_br, M_DEVBUF); 3127*15516c77SSepherosa Ziehau #endif 3128*15516c77SSepherosa Ziehau 3129*15516c77SSepherosa Ziehau free(txr->hn_txdesc, M_DEVBUF); 3130*15516c77SSepherosa Ziehau txr->hn_txdesc = NULL; 3131*15516c77SSepherosa Ziehau 3132*15516c77SSepherosa Ziehau if (txr->hn_mbuf_br != NULL) 3133*15516c77SSepherosa Ziehau buf_ring_free(txr->hn_mbuf_br, M_DEVBUF); 3134*15516c77SSepherosa Ziehau 3135*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 3136*15516c77SSepherosa Ziehau mtx_destroy(&txr->hn_txlist_spin); 3137*15516c77SSepherosa Ziehau #endif 3138*15516c77SSepherosa Ziehau mtx_destroy(&txr->hn_tx_lock); 3139*15516c77SSepherosa Ziehau } 3140*15516c77SSepherosa Ziehau 3141*15516c77SSepherosa Ziehau static int 3142*15516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt) 3143*15516c77SSepherosa Ziehau { 3144*15516c77SSepherosa Ziehau struct sysctl_oid_list *child; 3145*15516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 3146*15516c77SSepherosa Ziehau int i; 3147*15516c77SSepherosa Ziehau 3148*15516c77SSepherosa Ziehau /* 3149*15516c77SSepherosa Ziehau * Create TXBUF for chimney sending. 3150*15516c77SSepherosa Ziehau * 3151*15516c77SSepherosa Ziehau * NOTE: It is shared by all channels. 3152*15516c77SSepherosa Ziehau */ 3153*15516c77SSepherosa Ziehau sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), 3154*15516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma, 3155*15516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 3156*15516c77SSepherosa Ziehau if (sc->hn_chim == NULL) { 3157*15516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate txbuf failed\n"); 3158*15516c77SSepherosa Ziehau return (ENOMEM); 3159*15516c77SSepherosa Ziehau } 3160*15516c77SSepherosa Ziehau 3161*15516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = ring_cnt; 3162*15516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 3163*15516c77SSepherosa Ziehau 3164*15516c77SSepherosa Ziehau sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt, 3165*15516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 3166*15516c77SSepherosa Ziehau 3167*15516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(sc->hn_dev); 3168*15516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev)); 3169*15516c77SSepherosa Ziehau 3170*15516c77SSepherosa Ziehau /* Create dev.hn.UNIT.tx sysctl tree */ 3171*15516c77SSepherosa Ziehau sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx", 3172*15516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 3173*15516c77SSepherosa Ziehau 3174*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 3175*15516c77SSepherosa Ziehau int error; 3176*15516c77SSepherosa Ziehau 3177*15516c77SSepherosa Ziehau error = hn_tx_ring_create(sc, i); 3178*15516c77SSepherosa Ziehau if (error) 3179*15516c77SSepherosa Ziehau return error; 3180*15516c77SSepherosa Ziehau } 3181*15516c77SSepherosa Ziehau 3182*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs", 3183*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 3184*15516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_no_txdescs), 3185*15516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs"); 3186*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed", 3187*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 3188*15516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_send_failed), 3189*15516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure"); 3190*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed", 3191*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 3192*15516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_txdma_failed), 3193*15516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure"); 3194*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed", 3195*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 3196*15516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_collapsed), 3197*15516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed"); 3198*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney", 3199*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 3200*15516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney), 3201*15516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send"); 3202*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried", 3203*15516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 3204*15516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney_tried), 3205*15516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries"); 3206*15516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt", 3207*15516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0, 3208*15516c77SSepherosa Ziehau "# of total TX descs"); 3209*15516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max", 3210*15516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_chim_szmax, 0, 3211*15516c77SSepherosa Ziehau "Chimney send packet size upper boundary"); 3212*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size", 3213*15516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 3214*15516c77SSepherosa Ziehau hn_chim_size_sysctl, "I", "Chimney send packet size limit"); 3215*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size", 3216*15516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 3217*15516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_direct_tx_size), 3218*15516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 3219*15516c77SSepherosa Ziehau "Size of the packet for direct transmission"); 3220*15516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx", 3221*15516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 3222*15516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_sched_tx), 3223*15516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 3224*15516c77SSepherosa Ziehau "Always schedule transmission " 3225*15516c77SSepherosa Ziehau "instead of doing direct transmission"); 3226*15516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt", 3227*15516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings"); 3228*15516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse", 3229*15516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings"); 3230*15516c77SSepherosa Ziehau 3231*15516c77SSepherosa Ziehau return 0; 3232*15516c77SSepherosa Ziehau } 3233*15516c77SSepherosa Ziehau 3234*15516c77SSepherosa Ziehau static void 3235*15516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size) 3236*15516c77SSepherosa Ziehau { 3237*15516c77SSepherosa Ziehau int i; 3238*15516c77SSepherosa Ziehau 3239*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 3240*15516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_chim_size = chim_size; 3241*15516c77SSepherosa Ziehau } 3242*15516c77SSepherosa Ziehau 3243*15516c77SSepherosa Ziehau static void 3244*15516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu) 3245*15516c77SSepherosa Ziehau { 3246*15516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 3247*15516c77SSepherosa Ziehau int tso_minlen; 3248*15516c77SSepherosa Ziehau 3249*15516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0) 3250*15516c77SSepherosa Ziehau return; 3251*15516c77SSepherosa Ziehau 3252*15516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_sgmin >= 2, 3253*15516c77SSepherosa Ziehau ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin)); 3254*15516c77SSepherosa Ziehau tso_minlen = sc->hn_ndis_tso_sgmin * mtu; 3255*15516c77SSepherosa Ziehau 3256*15516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen && 3257*15516c77SSepherosa Ziehau sc->hn_ndis_tso_szmax <= IP_MAXPACKET, 3258*15516c77SSepherosa Ziehau ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax)); 3259*15516c77SSepherosa Ziehau 3260*15516c77SSepherosa Ziehau if (tso_maxlen < tso_minlen) 3261*15516c77SSepherosa Ziehau tso_maxlen = tso_minlen; 3262*15516c77SSepherosa Ziehau else if (tso_maxlen > IP_MAXPACKET) 3263*15516c77SSepherosa Ziehau tso_maxlen = IP_MAXPACKET; 3264*15516c77SSepherosa Ziehau if (tso_maxlen > sc->hn_ndis_tso_szmax) 3265*15516c77SSepherosa Ziehau tso_maxlen = sc->hn_ndis_tso_szmax; 3266*15516c77SSepherosa Ziehau ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 3267*15516c77SSepherosa Ziehau if (bootverbose) 3268*15516c77SSepherosa Ziehau if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax); 3269*15516c77SSepherosa Ziehau } 3270*15516c77SSepherosa Ziehau 3271*15516c77SSepherosa Ziehau static void 3272*15516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc) 3273*15516c77SSepherosa Ziehau { 3274*15516c77SSepherosa Ziehau uint64_t csum_assist; 3275*15516c77SSepherosa Ziehau int i; 3276*15516c77SSepherosa Ziehau 3277*15516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 3278*15516c77SSepherosa Ziehau if (hn_tx_chimney_size > 0 && 3279*15516c77SSepherosa Ziehau hn_tx_chimney_size < sc->hn_chim_szmax) 3280*15516c77SSepherosa Ziehau hn_set_chim_size(sc, hn_tx_chimney_size); 3281*15516c77SSepherosa Ziehau 3282*15516c77SSepherosa Ziehau csum_assist = 0; 3283*15516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_IPCS) 3284*15516c77SSepherosa Ziehau csum_assist |= CSUM_IP; 3285*15516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP4CS) 3286*15516c77SSepherosa Ziehau csum_assist |= CSUM_IP_TCP; 3287*15516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP4CS) 3288*15516c77SSepherosa Ziehau csum_assist |= CSUM_IP_UDP; 3289*15516c77SSepherosa Ziehau #ifdef notyet 3290*15516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP6CS) 3291*15516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_TCP; 3292*15516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP6CS) 3293*15516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_UDP; 3294*15516c77SSepherosa Ziehau #endif 3295*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 3296*15516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_csum_assist = csum_assist; 3297*15516c77SSepherosa Ziehau 3298*15516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_HASHVAL) { 3299*15516c77SSepherosa Ziehau /* 3300*15516c77SSepherosa Ziehau * Support HASHVAL pktinfo on TX path. 3301*15516c77SSepherosa Ziehau */ 3302*15516c77SSepherosa Ziehau if (bootverbose) 3303*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n"); 3304*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 3305*15516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL; 3306*15516c77SSepherosa Ziehau } 3307*15516c77SSepherosa Ziehau } 3308*15516c77SSepherosa Ziehau 3309*15516c77SSepherosa Ziehau static void 3310*15516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc) 3311*15516c77SSepherosa Ziehau { 3312*15516c77SSepherosa Ziehau int i; 3313*15516c77SSepherosa Ziehau 3314*15516c77SSepherosa Ziehau if (sc->hn_chim != NULL) { 3315*15516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim); 3316*15516c77SSepherosa Ziehau sc->hn_chim = NULL; 3317*15516c77SSepherosa Ziehau } 3318*15516c77SSepherosa Ziehau 3319*15516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt == 0) 3320*15516c77SSepherosa Ziehau return; 3321*15516c77SSepherosa Ziehau 3322*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 3323*15516c77SSepherosa Ziehau hn_tx_ring_destroy(&sc->hn_tx_ring[i]); 3324*15516c77SSepherosa Ziehau 3325*15516c77SSepherosa Ziehau free(sc->hn_tx_ring, M_DEVBUF); 3326*15516c77SSepherosa Ziehau sc->hn_tx_ring = NULL; 3327*15516c77SSepherosa Ziehau 3328*15516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = 0; 3329*15516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = 0; 3330*15516c77SSepherosa Ziehau } 3331*15516c77SSepherosa Ziehau 3332*15516c77SSepherosa Ziehau static void 3333*15516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused) 3334*15516c77SSepherosa Ziehau { 3335*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 3336*15516c77SSepherosa Ziehau 3337*15516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 3338*15516c77SSepherosa Ziehau hn_start_locked(txr, 0); 3339*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 3340*15516c77SSepherosa Ziehau } 3341*15516c77SSepherosa Ziehau 3342*15516c77SSepherosa Ziehau static void 3343*15516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused) 3344*15516c77SSepherosa Ziehau { 3345*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 3346*15516c77SSepherosa Ziehau 3347*15516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 3348*15516c77SSepherosa Ziehau atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE); 3349*15516c77SSepherosa Ziehau hn_start_locked(txr, 0); 3350*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 3351*15516c77SSepherosa Ziehau } 3352*15516c77SSepherosa Ziehau 3353*15516c77SSepherosa Ziehau static int 3354*15516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len) 3355*15516c77SSepherosa Ziehau { 3356*15516c77SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 3357*15516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 3358*15516c77SSepherosa Ziehau struct mbuf *m_head; 3359*15516c77SSepherosa Ziehau 3360*15516c77SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 3361*15516c77SSepherosa Ziehau KASSERT(hn_use_if_start == 0, 3362*15516c77SSepherosa Ziehau ("hn_xmit is called, when if_start is enabled")); 3363*15516c77SSepherosa Ziehau 3364*15516c77SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 3365*15516c77SSepherosa Ziehau return 0; 3366*15516c77SSepherosa Ziehau 3367*15516c77SSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive) 3368*15516c77SSepherosa Ziehau return 0; 3369*15516c77SSepherosa Ziehau 3370*15516c77SSepherosa Ziehau while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) { 3371*15516c77SSepherosa Ziehau struct hn_txdesc *txd; 3372*15516c77SSepherosa Ziehau int error; 3373*15516c77SSepherosa Ziehau 3374*15516c77SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 3375*15516c77SSepherosa Ziehau /* 3376*15516c77SSepherosa Ziehau * This sending could be time consuming; let callers 3377*15516c77SSepherosa Ziehau * dispatch this packet sending (and sending of any 3378*15516c77SSepherosa Ziehau * following up packets) to tx taskqueue. 3379*15516c77SSepherosa Ziehau */ 3380*15516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 3381*15516c77SSepherosa Ziehau return 1; 3382*15516c77SSepherosa Ziehau } 3383*15516c77SSepherosa Ziehau 3384*15516c77SSepherosa Ziehau txd = hn_txdesc_get(txr); 3385*15516c77SSepherosa Ziehau if (txd == NULL) { 3386*15516c77SSepherosa Ziehau txr->hn_no_txdescs++; 3387*15516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 3388*15516c77SSepherosa Ziehau txr->hn_oactive = 1; 3389*15516c77SSepherosa Ziehau break; 3390*15516c77SSepherosa Ziehau } 3391*15516c77SSepherosa Ziehau 3392*15516c77SSepherosa Ziehau error = hn_encap(txr, txd, &m_head); 3393*15516c77SSepherosa Ziehau if (error) { 3394*15516c77SSepherosa Ziehau /* Both txd and m_head are freed; discard */ 3395*15516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 3396*15516c77SSepherosa Ziehau continue; 3397*15516c77SSepherosa Ziehau } 3398*15516c77SSepherosa Ziehau 3399*15516c77SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 3400*15516c77SSepherosa Ziehau if (__predict_false(error)) { 3401*15516c77SSepherosa Ziehau /* txd is freed, but m_head is not */ 3402*15516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 3403*15516c77SSepherosa Ziehau txr->hn_oactive = 1; 3404*15516c77SSepherosa Ziehau break; 3405*15516c77SSepherosa Ziehau } 3406*15516c77SSepherosa Ziehau 3407*15516c77SSepherosa Ziehau /* Sent */ 3408*15516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 3409*15516c77SSepherosa Ziehau } 3410*15516c77SSepherosa Ziehau return 0; 3411*15516c77SSepherosa Ziehau } 3412*15516c77SSepherosa Ziehau 3413*15516c77SSepherosa Ziehau static int 3414*15516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m) 3415*15516c77SSepherosa Ziehau { 3416*15516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 3417*15516c77SSepherosa Ziehau struct hn_tx_ring *txr; 3418*15516c77SSepherosa Ziehau int error, idx = 0; 3419*15516c77SSepherosa Ziehau 3420*15516c77SSepherosa Ziehau /* 3421*15516c77SSepherosa Ziehau * Select the TX ring based on flowid 3422*15516c77SSepherosa Ziehau */ 3423*15516c77SSepherosa Ziehau if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 3424*15516c77SSepherosa Ziehau idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse; 3425*15516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 3426*15516c77SSepherosa Ziehau 3427*15516c77SSepherosa Ziehau error = drbr_enqueue(ifp, txr->hn_mbuf_br, m); 3428*15516c77SSepherosa Ziehau if (error) { 3429*15516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 3430*15516c77SSepherosa Ziehau return error; 3431*15516c77SSepherosa Ziehau } 3432*15516c77SSepherosa Ziehau 3433*15516c77SSepherosa Ziehau if (txr->hn_oactive) 3434*15516c77SSepherosa Ziehau return 0; 3435*15516c77SSepherosa Ziehau 3436*15516c77SSepherosa Ziehau if (txr->hn_sched_tx) 3437*15516c77SSepherosa Ziehau goto do_sched; 3438*15516c77SSepherosa Ziehau 3439*15516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 3440*15516c77SSepherosa Ziehau int sched; 3441*15516c77SSepherosa Ziehau 3442*15516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 3443*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 3444*15516c77SSepherosa Ziehau if (!sched) 3445*15516c77SSepherosa Ziehau return 0; 3446*15516c77SSepherosa Ziehau } 3447*15516c77SSepherosa Ziehau do_sched: 3448*15516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 3449*15516c77SSepherosa Ziehau return 0; 3450*15516c77SSepherosa Ziehau } 3451*15516c77SSepherosa Ziehau 3452*15516c77SSepherosa Ziehau static void 3453*15516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr) 3454*15516c77SSepherosa Ziehau { 3455*15516c77SSepherosa Ziehau struct mbuf *m; 3456*15516c77SSepherosa Ziehau 3457*15516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 3458*15516c77SSepherosa Ziehau while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL) 3459*15516c77SSepherosa Ziehau m_freem(m); 3460*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 3461*15516c77SSepherosa Ziehau } 3462*15516c77SSepherosa Ziehau 3463*15516c77SSepherosa Ziehau static void 3464*15516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp) 3465*15516c77SSepherosa Ziehau { 3466*15516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 3467*15516c77SSepherosa Ziehau int i; 3468*15516c77SSepherosa Ziehau 3469*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 3470*15516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 3471*15516c77SSepherosa Ziehau if_qflush(ifp); 3472*15516c77SSepherosa Ziehau } 3473*15516c77SSepherosa Ziehau 3474*15516c77SSepherosa Ziehau static void 3475*15516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr) 3476*15516c77SSepherosa Ziehau { 3477*15516c77SSepherosa Ziehau 3478*15516c77SSepherosa Ziehau if (txr->hn_sched_tx) 3479*15516c77SSepherosa Ziehau goto do_sched; 3480*15516c77SSepherosa Ziehau 3481*15516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 3482*15516c77SSepherosa Ziehau int sched; 3483*15516c77SSepherosa Ziehau 3484*15516c77SSepherosa Ziehau txr->hn_oactive = 0; 3485*15516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 3486*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 3487*15516c77SSepherosa Ziehau if (sched) { 3488*15516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 3489*15516c77SSepherosa Ziehau &txr->hn_tx_task); 3490*15516c77SSepherosa Ziehau } 3491*15516c77SSepherosa Ziehau } else { 3492*15516c77SSepherosa Ziehau do_sched: 3493*15516c77SSepherosa Ziehau /* 3494*15516c77SSepherosa Ziehau * Release the oactive earlier, with the hope, that 3495*15516c77SSepherosa Ziehau * others could catch up. The task will clear the 3496*15516c77SSepherosa Ziehau * oactive again with the hn_tx_lock to avoid possible 3497*15516c77SSepherosa Ziehau * races. 3498*15516c77SSepherosa Ziehau */ 3499*15516c77SSepherosa Ziehau txr->hn_oactive = 0; 3500*15516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 3501*15516c77SSepherosa Ziehau } 3502*15516c77SSepherosa Ziehau } 3503*15516c77SSepherosa Ziehau 3504*15516c77SSepherosa Ziehau static void 3505*15516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused) 3506*15516c77SSepherosa Ziehau { 3507*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 3508*15516c77SSepherosa Ziehau 3509*15516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 3510*15516c77SSepherosa Ziehau hn_xmit(txr, 0); 3511*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 3512*15516c77SSepherosa Ziehau } 3513*15516c77SSepherosa Ziehau 3514*15516c77SSepherosa Ziehau static void 3515*15516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused) 3516*15516c77SSepherosa Ziehau { 3517*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 3518*15516c77SSepherosa Ziehau 3519*15516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 3520*15516c77SSepherosa Ziehau txr->hn_oactive = 0; 3521*15516c77SSepherosa Ziehau hn_xmit(txr, 0); 3522*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 3523*15516c77SSepherosa Ziehau } 3524*15516c77SSepherosa Ziehau 3525*15516c77SSepherosa Ziehau static int 3526*15516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan) 3527*15516c77SSepherosa Ziehau { 3528*15516c77SSepherosa Ziehau struct vmbus_chan_br cbr; 3529*15516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 3530*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = NULL; 3531*15516c77SSepherosa Ziehau int idx, error; 3532*15516c77SSepherosa Ziehau 3533*15516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 3534*15516c77SSepherosa Ziehau 3535*15516c77SSepherosa Ziehau /* 3536*15516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 3537*15516c77SSepherosa Ziehau */ 3538*15516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 3539*15516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 3540*15516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 3541*15516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 3542*15516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0, 3543*15516c77SSepherosa Ziehau ("RX ring %d already attached", idx)); 3544*15516c77SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED; 3545*15516c77SSepherosa Ziehau 3546*15516c77SSepherosa Ziehau if (bootverbose) { 3547*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n", 3548*15516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 3549*15516c77SSepherosa Ziehau } 3550*15516c77SSepherosa Ziehau 3551*15516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 3552*15516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 3553*15516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0, 3554*15516c77SSepherosa Ziehau ("TX ring %d already attached", idx)); 3555*15516c77SSepherosa Ziehau txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED; 3556*15516c77SSepherosa Ziehau 3557*15516c77SSepherosa Ziehau txr->hn_chan = chan; 3558*15516c77SSepherosa Ziehau if (bootverbose) { 3559*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n", 3560*15516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 3561*15516c77SSepherosa Ziehau } 3562*15516c77SSepherosa Ziehau } 3563*15516c77SSepherosa Ziehau 3564*15516c77SSepherosa Ziehau /* Bind this channel to a proper CPU. */ 3565*15516c77SSepherosa Ziehau vmbus_chan_cpu_set(chan, (sc->hn_cpu + idx) % mp_ncpus); 3566*15516c77SSepherosa Ziehau 3567*15516c77SSepherosa Ziehau /* 3568*15516c77SSepherosa Ziehau * Open this channel 3569*15516c77SSepherosa Ziehau */ 3570*15516c77SSepherosa Ziehau cbr.cbr = rxr->hn_br; 3571*15516c77SSepherosa Ziehau cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr; 3572*15516c77SSepherosa Ziehau cbr.cbr_txsz = HN_TXBR_SIZE; 3573*15516c77SSepherosa Ziehau cbr.cbr_rxsz = HN_RXBR_SIZE; 3574*15516c77SSepherosa Ziehau error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr); 3575*15516c77SSepherosa Ziehau if (error) { 3576*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "open chan%u failed: %d\n", 3577*15516c77SSepherosa Ziehau vmbus_chan_id(chan), error); 3578*15516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 3579*15516c77SSepherosa Ziehau if (txr != NULL) 3580*15516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 3581*15516c77SSepherosa Ziehau } 3582*15516c77SSepherosa Ziehau return (error); 3583*15516c77SSepherosa Ziehau } 3584*15516c77SSepherosa Ziehau 3585*15516c77SSepherosa Ziehau static void 3586*15516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan) 3587*15516c77SSepherosa Ziehau { 3588*15516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 3589*15516c77SSepherosa Ziehau int idx; 3590*15516c77SSepherosa Ziehau 3591*15516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 3592*15516c77SSepherosa Ziehau 3593*15516c77SSepherosa Ziehau /* 3594*15516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 3595*15516c77SSepherosa Ziehau */ 3596*15516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 3597*15516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 3598*15516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 3599*15516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 3600*15516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED), 3601*15516c77SSepherosa Ziehau ("RX ring %d is not attached", idx)); 3602*15516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 3603*15516c77SSepherosa Ziehau 3604*15516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 3605*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[idx]; 3606*15516c77SSepherosa Ziehau 3607*15516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED), 3608*15516c77SSepherosa Ziehau ("TX ring %d is not attached attached", idx)); 3609*15516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 3610*15516c77SSepherosa Ziehau } 3611*15516c77SSepherosa Ziehau 3612*15516c77SSepherosa Ziehau /* 3613*15516c77SSepherosa Ziehau * Close this channel. 3614*15516c77SSepherosa Ziehau * 3615*15516c77SSepherosa Ziehau * NOTE: 3616*15516c77SSepherosa Ziehau * Channel closing does _not_ destroy the target channel. 3617*15516c77SSepherosa Ziehau */ 3618*15516c77SSepherosa Ziehau vmbus_chan_close(chan); 3619*15516c77SSepherosa Ziehau } 3620*15516c77SSepherosa Ziehau 3621*15516c77SSepherosa Ziehau static int 3622*15516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc) 3623*15516c77SSepherosa Ziehau { 3624*15516c77SSepherosa Ziehau struct vmbus_channel **subchans; 3625*15516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 3626*15516c77SSepherosa Ziehau int i, error = 0; 3627*15516c77SSepherosa Ziehau 3628*15516c77SSepherosa Ziehau if (subchan_cnt == 0) 3629*15516c77SSepherosa Ziehau return (0); 3630*15516c77SSepherosa Ziehau 3631*15516c77SSepherosa Ziehau /* Attach the sub-channels. */ 3632*15516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 3633*15516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) { 3634*15516c77SSepherosa Ziehau error = hn_chan_attach(sc, subchans[i]); 3635*15516c77SSepherosa Ziehau if (error) 3636*15516c77SSepherosa Ziehau break; 3637*15516c77SSepherosa Ziehau } 3638*15516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 3639*15516c77SSepherosa Ziehau 3640*15516c77SSepherosa Ziehau if (error) { 3641*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error); 3642*15516c77SSepherosa Ziehau } else { 3643*15516c77SSepherosa Ziehau if (bootverbose) { 3644*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d sub-channels attached\n", 3645*15516c77SSepherosa Ziehau subchan_cnt); 3646*15516c77SSepherosa Ziehau } 3647*15516c77SSepherosa Ziehau } 3648*15516c77SSepherosa Ziehau return (error); 3649*15516c77SSepherosa Ziehau } 3650*15516c77SSepherosa Ziehau 3651*15516c77SSepherosa Ziehau static void 3652*15516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc) 3653*15516c77SSepherosa Ziehau { 3654*15516c77SSepherosa Ziehau struct vmbus_channel **subchans; 3655*15516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 3656*15516c77SSepherosa Ziehau int i; 3657*15516c77SSepherosa Ziehau 3658*15516c77SSepherosa Ziehau if (subchan_cnt == 0) 3659*15516c77SSepherosa Ziehau goto back; 3660*15516c77SSepherosa Ziehau 3661*15516c77SSepherosa Ziehau /* Detach the sub-channels. */ 3662*15516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 3663*15516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) 3664*15516c77SSepherosa Ziehau hn_chan_detach(sc, subchans[i]); 3665*15516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 3666*15516c77SSepherosa Ziehau 3667*15516c77SSepherosa Ziehau back: 3668*15516c77SSepherosa Ziehau /* 3669*15516c77SSepherosa Ziehau * Detach the primary channel, _after_ all sub-channels 3670*15516c77SSepherosa Ziehau * are detached. 3671*15516c77SSepherosa Ziehau */ 3672*15516c77SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 3673*15516c77SSepherosa Ziehau 3674*15516c77SSepherosa Ziehau /* Wait for sub-channels to be destroyed, if any. */ 3675*15516c77SSepherosa Ziehau vmbus_subchan_drain(sc->hn_prichan); 3676*15516c77SSepherosa Ziehau 3677*15516c77SSepherosa Ziehau #ifdef INVARIANTS 3678*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 3679*15516c77SSepherosa Ziehau KASSERT((sc->hn_rx_ring[i].hn_rx_flags & 3680*15516c77SSepherosa Ziehau HN_RX_FLAG_ATTACHED) == 0, 3681*15516c77SSepherosa Ziehau ("%dth RX ring is still attached", i)); 3682*15516c77SSepherosa Ziehau } 3683*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 3684*15516c77SSepherosa Ziehau KASSERT((sc->hn_tx_ring[i].hn_tx_flags & 3685*15516c77SSepherosa Ziehau HN_TX_FLAG_ATTACHED) == 0, 3686*15516c77SSepherosa Ziehau ("%dth TX ring is still attached", i)); 3687*15516c77SSepherosa Ziehau } 3688*15516c77SSepherosa Ziehau #endif 3689*15516c77SSepherosa Ziehau } 3690*15516c77SSepherosa Ziehau 3691*15516c77SSepherosa Ziehau static int 3692*15516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch) 3693*15516c77SSepherosa Ziehau { 3694*15516c77SSepherosa Ziehau struct vmbus_channel **subchans; 3695*15516c77SSepherosa Ziehau int nchan, rxr_cnt, error; 3696*15516c77SSepherosa Ziehau 3697*15516c77SSepherosa Ziehau nchan = *nsubch + 1; 3698*15516c77SSepherosa Ziehau if (nchan == 1) { 3699*15516c77SSepherosa Ziehau /* 3700*15516c77SSepherosa Ziehau * Multiple RX/TX rings are not requested. 3701*15516c77SSepherosa Ziehau */ 3702*15516c77SSepherosa Ziehau *nsubch = 0; 3703*15516c77SSepherosa Ziehau return (0); 3704*15516c77SSepherosa Ziehau } 3705*15516c77SSepherosa Ziehau 3706*15516c77SSepherosa Ziehau /* 3707*15516c77SSepherosa Ziehau * Query RSS capabilities, e.g. # of RX rings, and # of indirect 3708*15516c77SSepherosa Ziehau * table entries. 3709*15516c77SSepherosa Ziehau */ 3710*15516c77SSepherosa Ziehau error = hn_rndis_query_rsscaps(sc, &rxr_cnt); 3711*15516c77SSepherosa Ziehau if (error) { 3712*15516c77SSepherosa Ziehau /* No RSS; this is benign. */ 3713*15516c77SSepherosa Ziehau *nsubch = 0; 3714*15516c77SSepherosa Ziehau return (0); 3715*15516c77SSepherosa Ziehau } 3716*15516c77SSepherosa Ziehau if (bootverbose) { 3717*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n", 3718*15516c77SSepherosa Ziehau rxr_cnt, nchan); 3719*15516c77SSepherosa Ziehau } 3720*15516c77SSepherosa Ziehau 3721*15516c77SSepherosa Ziehau if (nchan > rxr_cnt) 3722*15516c77SSepherosa Ziehau nchan = rxr_cnt; 3723*15516c77SSepherosa Ziehau if (nchan == 1) { 3724*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n"); 3725*15516c77SSepherosa Ziehau *nsubch = 0; 3726*15516c77SSepherosa Ziehau return (0); 3727*15516c77SSepherosa Ziehau } 3728*15516c77SSepherosa Ziehau 3729*15516c77SSepherosa Ziehau /* 3730*15516c77SSepherosa Ziehau * Allocate sub-channels from NVS. 3731*15516c77SSepherosa Ziehau */ 3732*15516c77SSepherosa Ziehau *nsubch = nchan - 1; 3733*15516c77SSepherosa Ziehau error = hn_nvs_alloc_subchans(sc, nsubch); 3734*15516c77SSepherosa Ziehau if (error || *nsubch == 0) { 3735*15516c77SSepherosa Ziehau /* Failed to allocate sub-channels. */ 3736*15516c77SSepherosa Ziehau *nsubch = 0; 3737*15516c77SSepherosa Ziehau return (0); 3738*15516c77SSepherosa Ziehau } 3739*15516c77SSepherosa Ziehau 3740*15516c77SSepherosa Ziehau /* 3741*15516c77SSepherosa Ziehau * Wait for all sub-channels to become ready before moving on. 3742*15516c77SSepherosa Ziehau */ 3743*15516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch); 3744*15516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, *nsubch); 3745*15516c77SSepherosa Ziehau return (0); 3746*15516c77SSepherosa Ziehau } 3747*15516c77SSepherosa Ziehau 3748*15516c77SSepherosa Ziehau static int 3749*15516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu) 3750*15516c77SSepherosa Ziehau { 3751*15516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 3752*15516c77SSepherosa Ziehau int error, nsubch, nchan, i; 3753*15516c77SSepherosa Ziehau uint32_t old_caps; 3754*15516c77SSepherosa Ziehau 3755*15516c77SSepherosa Ziehau KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0, 3756*15516c77SSepherosa Ziehau ("synthetic parts were attached")); 3757*15516c77SSepherosa Ziehau 3758*15516c77SSepherosa Ziehau /* Save capabilities for later verification. */ 3759*15516c77SSepherosa Ziehau old_caps = sc->hn_caps; 3760*15516c77SSepherosa Ziehau sc->hn_caps = 0; 3761*15516c77SSepherosa Ziehau 3762*15516c77SSepherosa Ziehau /* Clear RSS stuffs. */ 3763*15516c77SSepherosa Ziehau sc->hn_rss_ind_size = 0; 3764*15516c77SSepherosa Ziehau sc->hn_rss_hash = 0; 3765*15516c77SSepherosa Ziehau 3766*15516c77SSepherosa Ziehau /* 3767*15516c77SSepherosa Ziehau * Attach the primary channel _before_ attaching NVS and RNDIS. 3768*15516c77SSepherosa Ziehau */ 3769*15516c77SSepherosa Ziehau error = hn_chan_attach(sc, sc->hn_prichan); 3770*15516c77SSepherosa Ziehau if (error) 3771*15516c77SSepherosa Ziehau return (error); 3772*15516c77SSepherosa Ziehau 3773*15516c77SSepherosa Ziehau /* 3774*15516c77SSepherosa Ziehau * Attach NVS. 3775*15516c77SSepherosa Ziehau */ 3776*15516c77SSepherosa Ziehau error = hn_nvs_attach(sc, mtu); 3777*15516c77SSepherosa Ziehau if (error) 3778*15516c77SSepherosa Ziehau return (error); 3779*15516c77SSepherosa Ziehau 3780*15516c77SSepherosa Ziehau /* 3781*15516c77SSepherosa Ziehau * Attach RNDIS _after_ NVS is attached. 3782*15516c77SSepherosa Ziehau */ 3783*15516c77SSepherosa Ziehau error = hn_rndis_attach(sc, mtu); 3784*15516c77SSepherosa Ziehau if (error) 3785*15516c77SSepherosa Ziehau return (error); 3786*15516c77SSepherosa Ziehau 3787*15516c77SSepherosa Ziehau /* 3788*15516c77SSepherosa Ziehau * Make sure capabilities are not changed. 3789*15516c77SSepherosa Ziehau */ 3790*15516c77SSepherosa Ziehau if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) { 3791*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n", 3792*15516c77SSepherosa Ziehau old_caps, sc->hn_caps); 3793*15516c77SSepherosa Ziehau /* Restore old capabilities and abort. */ 3794*15516c77SSepherosa Ziehau sc->hn_caps = old_caps; 3795*15516c77SSepherosa Ziehau return ENXIO; 3796*15516c77SSepherosa Ziehau } 3797*15516c77SSepherosa Ziehau 3798*15516c77SSepherosa Ziehau /* 3799*15516c77SSepherosa Ziehau * Allocate sub-channels for multi-TX/RX rings. 3800*15516c77SSepherosa Ziehau * 3801*15516c77SSepherosa Ziehau * NOTE: 3802*15516c77SSepherosa Ziehau * The # of RX rings that can be used is equivalent to the # of 3803*15516c77SSepherosa Ziehau * channels to be requested. 3804*15516c77SSepherosa Ziehau */ 3805*15516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_cnt - 1; 3806*15516c77SSepherosa Ziehau error = hn_synth_alloc_subchans(sc, &nsubch); 3807*15516c77SSepherosa Ziehau if (error) 3808*15516c77SSepherosa Ziehau return (error); 3809*15516c77SSepherosa Ziehau 3810*15516c77SSepherosa Ziehau nchan = nsubch + 1; 3811*15516c77SSepherosa Ziehau if (nchan == 1) { 3812*15516c77SSepherosa Ziehau /* Only the primary channel can be used; done */ 3813*15516c77SSepherosa Ziehau goto back; 3814*15516c77SSepherosa Ziehau } 3815*15516c77SSepherosa Ziehau 3816*15516c77SSepherosa Ziehau /* 3817*15516c77SSepherosa Ziehau * Configure RSS key and indirect table _after_ all sub-channels 3818*15516c77SSepherosa Ziehau * are allocated. 3819*15516c77SSepherosa Ziehau */ 3820*15516c77SSepherosa Ziehau 3821*15516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) { 3822*15516c77SSepherosa Ziehau /* 3823*15516c77SSepherosa Ziehau * RSS key is not set yet; set it to the default RSS key. 3824*15516c77SSepherosa Ziehau */ 3825*15516c77SSepherosa Ziehau if (bootverbose) 3826*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS key\n"); 3827*15516c77SSepherosa Ziehau memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key)); 3828*15516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 3829*15516c77SSepherosa Ziehau } 3830*15516c77SSepherosa Ziehau 3831*15516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) { 3832*15516c77SSepherosa Ziehau /* 3833*15516c77SSepherosa Ziehau * RSS indirect table is not set yet; set it up in round- 3834*15516c77SSepherosa Ziehau * robin fashion. 3835*15516c77SSepherosa Ziehau */ 3836*15516c77SSepherosa Ziehau if (bootverbose) { 3837*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS indirect " 3838*15516c77SSepherosa Ziehau "table\n"); 3839*15516c77SSepherosa Ziehau } 3840*15516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) 3841*15516c77SSepherosa Ziehau rss->rss_ind[i] = i % nchan; 3842*15516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 3843*15516c77SSepherosa Ziehau } else { 3844*15516c77SSepherosa Ziehau /* 3845*15516c77SSepherosa Ziehau * # of usable channels may be changed, so we have to 3846*15516c77SSepherosa Ziehau * make sure that all entries in RSS indirect table 3847*15516c77SSepherosa Ziehau * are valid. 3848*15516c77SSepherosa Ziehau */ 3849*15516c77SSepherosa Ziehau hn_rss_ind_fixup(sc, nchan); 3850*15516c77SSepherosa Ziehau } 3851*15516c77SSepherosa Ziehau 3852*15516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 3853*15516c77SSepherosa Ziehau if (error) { 3854*15516c77SSepherosa Ziehau /* 3855*15516c77SSepherosa Ziehau * Failed to configure RSS key or indirect table; only 3856*15516c77SSepherosa Ziehau * the primary channel can be used. 3857*15516c77SSepherosa Ziehau */ 3858*15516c77SSepherosa Ziehau nchan = 1; 3859*15516c77SSepherosa Ziehau } 3860*15516c77SSepherosa Ziehau back: 3861*15516c77SSepherosa Ziehau /* 3862*15516c77SSepherosa Ziehau * Set the # of TX/RX rings that could be used according to 3863*15516c77SSepherosa Ziehau * the # of channels that NVS offered. 3864*15516c77SSepherosa Ziehau */ 3865*15516c77SSepherosa Ziehau hn_set_ring_inuse(sc, nchan); 3866*15516c77SSepherosa Ziehau 3867*15516c77SSepherosa Ziehau /* 3868*15516c77SSepherosa Ziehau * Attach the sub-channels, if any. 3869*15516c77SSepherosa Ziehau */ 3870*15516c77SSepherosa Ziehau error = hn_attach_subchans(sc); 3871*15516c77SSepherosa Ziehau if (error) 3872*15516c77SSepherosa Ziehau return (error); 3873*15516c77SSepherosa Ziehau 3874*15516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED; 3875*15516c77SSepherosa Ziehau return (0); 3876*15516c77SSepherosa Ziehau } 3877*15516c77SSepherosa Ziehau 3878*15516c77SSepherosa Ziehau /* 3879*15516c77SSepherosa Ziehau * NOTE: 3880*15516c77SSepherosa Ziehau * The interface must have been suspended though hn_suspend(), before 3881*15516c77SSepherosa Ziehau * this function get called. 3882*15516c77SSepherosa Ziehau */ 3883*15516c77SSepherosa Ziehau static void 3884*15516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc) 3885*15516c77SSepherosa Ziehau { 3886*15516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 3887*15516c77SSepherosa Ziehau 3888*15516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 3889*15516c77SSepherosa Ziehau ("synthetic parts were not attached")); 3890*15516c77SSepherosa Ziehau 3891*15516c77SSepherosa Ziehau /* Detach the RNDIS first. */ 3892*15516c77SSepherosa Ziehau hn_rndis_detach(sc); 3893*15516c77SSepherosa Ziehau 3894*15516c77SSepherosa Ziehau /* Detach NVS. */ 3895*15516c77SSepherosa Ziehau hn_nvs_detach(sc); 3896*15516c77SSepherosa Ziehau 3897*15516c77SSepherosa Ziehau /* Detach all of the channels. */ 3898*15516c77SSepherosa Ziehau hn_detach_allchans(sc); 3899*15516c77SSepherosa Ziehau 3900*15516c77SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED; 3901*15516c77SSepherosa Ziehau } 3902*15516c77SSepherosa Ziehau 3903*15516c77SSepherosa Ziehau static void 3904*15516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt) 3905*15516c77SSepherosa Ziehau { 3906*15516c77SSepherosa Ziehau KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt, 3907*15516c77SSepherosa Ziehau ("invalid ring count %d", ring_cnt)); 3908*15516c77SSepherosa Ziehau 3909*15516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt > ring_cnt) 3910*15516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = ring_cnt; 3911*15516c77SSepherosa Ziehau else 3912*15516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 3913*15516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = ring_cnt; 3914*15516c77SSepherosa Ziehau 3915*15516c77SSepherosa Ziehau if (bootverbose) { 3916*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n", 3917*15516c77SSepherosa Ziehau sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse); 3918*15516c77SSepherosa Ziehau } 3919*15516c77SSepherosa Ziehau } 3920*15516c77SSepherosa Ziehau 3921*15516c77SSepherosa Ziehau static void 3922*15516c77SSepherosa Ziehau hn_chan_drain(struct vmbus_channel *chan) 3923*15516c77SSepherosa Ziehau { 3924*15516c77SSepherosa Ziehau 3925*15516c77SSepherosa Ziehau while (!vmbus_chan_rx_empty(chan) || !vmbus_chan_tx_empty(chan)) 3926*15516c77SSepherosa Ziehau pause("waitch", 1); 3927*15516c77SSepherosa Ziehau vmbus_chan_intr_drain(chan); 3928*15516c77SSepherosa Ziehau } 3929*15516c77SSepherosa Ziehau 3930*15516c77SSepherosa Ziehau static void 3931*15516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc) 3932*15516c77SSepherosa Ziehau { 3933*15516c77SSepherosa Ziehau struct vmbus_channel **subch = NULL; 3934*15516c77SSepherosa Ziehau int i, nsubch; 3935*15516c77SSepherosa Ziehau 3936*15516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 3937*15516c77SSepherosa Ziehau 3938*15516c77SSepherosa Ziehau /* 3939*15516c77SSepherosa Ziehau * Suspend TX. 3940*15516c77SSepherosa Ziehau */ 3941*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 3942*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 3943*15516c77SSepherosa Ziehau 3944*15516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 3945*15516c77SSepherosa Ziehau txr->hn_suspended = 1; 3946*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 3947*15516c77SSepherosa Ziehau /* No one is able send more packets now. */ 3948*15516c77SSepherosa Ziehau 3949*15516c77SSepherosa Ziehau /* Wait for all pending sends to finish. */ 3950*15516c77SSepherosa Ziehau while (hn_tx_ring_pending(txr)) 3951*15516c77SSepherosa Ziehau pause("hnwtx", 1 /* 1 tick */); 3952*15516c77SSepherosa Ziehau 3953*15516c77SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task); 3954*15516c77SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task); 3955*15516c77SSepherosa Ziehau } 3956*15516c77SSepherosa Ziehau 3957*15516c77SSepherosa Ziehau /* 3958*15516c77SSepherosa Ziehau * Disable RX by clearing RX filter. 3959*15516c77SSepherosa Ziehau */ 3960*15516c77SSepherosa Ziehau sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE; 3961*15516c77SSepherosa Ziehau hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); 3962*15516c77SSepherosa Ziehau 3963*15516c77SSepherosa Ziehau /* 3964*15516c77SSepherosa Ziehau * Give RNDIS enough time to flush all pending data packets. 3965*15516c77SSepherosa Ziehau */ 3966*15516c77SSepherosa Ziehau pause("waitrx", (200 * hz) / 1000); 3967*15516c77SSepherosa Ziehau 3968*15516c77SSepherosa Ziehau /* 3969*15516c77SSepherosa Ziehau * Drain RX/TX bufrings and interrupts. 3970*15516c77SSepherosa Ziehau */ 3971*15516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_inuse - 1; 3972*15516c77SSepherosa Ziehau if (nsubch > 0) 3973*15516c77SSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 3974*15516c77SSepherosa Ziehau 3975*15516c77SSepherosa Ziehau if (subch != NULL) { 3976*15516c77SSepherosa Ziehau for (i = 0; i < nsubch; ++i) 3977*15516c77SSepherosa Ziehau hn_chan_drain(subch[i]); 3978*15516c77SSepherosa Ziehau } 3979*15516c77SSepherosa Ziehau hn_chan_drain(sc->hn_prichan); 3980*15516c77SSepherosa Ziehau 3981*15516c77SSepherosa Ziehau if (subch != NULL) 3982*15516c77SSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 3983*15516c77SSepherosa Ziehau } 3984*15516c77SSepherosa Ziehau 3985*15516c77SSepherosa Ziehau static void 3986*15516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused) 3987*15516c77SSepherosa Ziehau { 3988*15516c77SSepherosa Ziehau 3989*15516c77SSepherosa Ziehau ((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL; 3990*15516c77SSepherosa Ziehau } 3991*15516c77SSepherosa Ziehau 3992*15516c77SSepherosa Ziehau static void 3993*15516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc) 3994*15516c77SSepherosa Ziehau { 3995*15516c77SSepherosa Ziehau struct task task; 3996*15516c77SSepherosa Ziehau 3997*15516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 3998*15516c77SSepherosa Ziehau 3999*15516c77SSepherosa Ziehau /* 4000*15516c77SSepherosa Ziehau * Make sure that hn_mgmt_taskq0 can nolonger be accessed 4001*15516c77SSepherosa Ziehau * through hn_mgmt_taskq. 4002*15516c77SSepherosa Ziehau */ 4003*15516c77SSepherosa Ziehau TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc); 4004*15516c77SSepherosa Ziehau vmbus_chan_run_task(sc->hn_prichan, &task); 4005*15516c77SSepherosa Ziehau 4006*15516c77SSepherosa Ziehau /* 4007*15516c77SSepherosa Ziehau * Make sure that all pending management tasks are completed. 4008*15516c77SSepherosa Ziehau */ 4009*15516c77SSepherosa Ziehau taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init); 4010*15516c77SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status); 4011*15516c77SSepherosa Ziehau taskqueue_drain_all(sc->hn_mgmt_taskq0); 4012*15516c77SSepherosa Ziehau } 4013*15516c77SSepherosa Ziehau 4014*15516c77SSepherosa Ziehau static void 4015*15516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc) 4016*15516c77SSepherosa Ziehau { 4017*15516c77SSepherosa Ziehau 4018*15516c77SSepherosa Ziehau if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 4019*15516c77SSepherosa Ziehau hn_suspend_data(sc); 4020*15516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 4021*15516c77SSepherosa Ziehau } 4022*15516c77SSepherosa Ziehau 4023*15516c77SSepherosa Ziehau static void 4024*15516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt) 4025*15516c77SSepherosa Ziehau { 4026*15516c77SSepherosa Ziehau int i; 4027*15516c77SSepherosa Ziehau 4028*15516c77SSepherosa Ziehau KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt, 4029*15516c77SSepherosa Ziehau ("invalid TX ring count %d", tx_ring_cnt)); 4030*15516c77SSepherosa Ziehau 4031*15516c77SSepherosa Ziehau for (i = 0; i < tx_ring_cnt; ++i) { 4032*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 4033*15516c77SSepherosa Ziehau 4034*15516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 4035*15516c77SSepherosa Ziehau txr->hn_suspended = 0; 4036*15516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 4037*15516c77SSepherosa Ziehau } 4038*15516c77SSepherosa Ziehau } 4039*15516c77SSepherosa Ziehau 4040*15516c77SSepherosa Ziehau static void 4041*15516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc) 4042*15516c77SSepherosa Ziehau { 4043*15516c77SSepherosa Ziehau int i; 4044*15516c77SSepherosa Ziehau 4045*15516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 4046*15516c77SSepherosa Ziehau 4047*15516c77SSepherosa Ziehau /* 4048*15516c77SSepherosa Ziehau * Re-enable RX. 4049*15516c77SSepherosa Ziehau */ 4050*15516c77SSepherosa Ziehau hn_set_rxfilter(sc); 4051*15516c77SSepherosa Ziehau 4052*15516c77SSepherosa Ziehau /* 4053*15516c77SSepherosa Ziehau * Make sure to clear suspend status on "all" TX rings, 4054*15516c77SSepherosa Ziehau * since hn_tx_ring_inuse can be changed after 4055*15516c77SSepherosa Ziehau * hn_suspend_data(). 4056*15516c77SSepherosa Ziehau */ 4057*15516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_cnt); 4058*15516c77SSepherosa Ziehau 4059*15516c77SSepherosa Ziehau if (!hn_use_if_start) { 4060*15516c77SSepherosa Ziehau /* 4061*15516c77SSepherosa Ziehau * Flush unused drbrs, since hn_tx_ring_inuse may be 4062*15516c77SSepherosa Ziehau * reduced. 4063*15516c77SSepherosa Ziehau */ 4064*15516c77SSepherosa Ziehau for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i) 4065*15516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 4066*15516c77SSepherosa Ziehau } 4067*15516c77SSepherosa Ziehau 4068*15516c77SSepherosa Ziehau /* 4069*15516c77SSepherosa Ziehau * Kick start TX. 4070*15516c77SSepherosa Ziehau */ 4071*15516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 4072*15516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 4073*15516c77SSepherosa Ziehau 4074*15516c77SSepherosa Ziehau /* 4075*15516c77SSepherosa Ziehau * Use txeof task, so that any pending oactive can be 4076*15516c77SSepherosa Ziehau * cleared properly. 4077*15516c77SSepherosa Ziehau */ 4078*15516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 4079*15516c77SSepherosa Ziehau } 4080*15516c77SSepherosa Ziehau } 4081*15516c77SSepherosa Ziehau 4082*15516c77SSepherosa Ziehau static void 4083*15516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc) 4084*15516c77SSepherosa Ziehau { 4085*15516c77SSepherosa Ziehau 4086*15516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 4087*15516c77SSepherosa Ziehau 4088*15516c77SSepherosa Ziehau /* 4089*15516c77SSepherosa Ziehau * Kick off network change detection, if it was pending. 4090*15516c77SSepherosa Ziehau * If no network change was pending, start link status 4091*15516c77SSepherosa Ziehau * checks, which is more lightweight than network change 4092*15516c77SSepherosa Ziehau * detection. 4093*15516c77SSepherosa Ziehau */ 4094*15516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 4095*15516c77SSepherosa Ziehau hn_change_network(sc); 4096*15516c77SSepherosa Ziehau else 4097*15516c77SSepherosa Ziehau hn_update_link_status(sc); 4098*15516c77SSepherosa Ziehau } 4099*15516c77SSepherosa Ziehau 4100*15516c77SSepherosa Ziehau static void 4101*15516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc) 4102*15516c77SSepherosa Ziehau { 4103*15516c77SSepherosa Ziehau 4104*15516c77SSepherosa Ziehau if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 4105*15516c77SSepherosa Ziehau hn_resume_data(sc); 4106*15516c77SSepherosa Ziehau hn_resume_mgmt(sc); 4107*15516c77SSepherosa Ziehau } 4108*15516c77SSepherosa Ziehau 4109*15516c77SSepherosa Ziehau static void 4110*15516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen) 4111*15516c77SSepherosa Ziehau { 4112*15516c77SSepherosa Ziehau const struct rndis_status_msg *msg; 4113*15516c77SSepherosa Ziehau int ofs; 4114*15516c77SSepherosa Ziehau 4115*15516c77SSepherosa Ziehau if (dlen < sizeof(*msg)) { 4116*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid RNDIS status\n"); 4117*15516c77SSepherosa Ziehau return; 4118*15516c77SSepherosa Ziehau } 4119*15516c77SSepherosa Ziehau msg = data; 4120*15516c77SSepherosa Ziehau 4121*15516c77SSepherosa Ziehau switch (msg->rm_status) { 4122*15516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_CONNECT: 4123*15516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_DISCONNECT: 4124*15516c77SSepherosa Ziehau hn_update_link_status(sc); 4125*15516c77SSepherosa Ziehau break; 4126*15516c77SSepherosa Ziehau 4127*15516c77SSepherosa Ziehau case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: 4128*15516c77SSepherosa Ziehau /* Not really useful; ignore. */ 4129*15516c77SSepherosa Ziehau break; 4130*15516c77SSepherosa Ziehau 4131*15516c77SSepherosa Ziehau case RNDIS_STATUS_NETWORK_CHANGE: 4132*15516c77SSepherosa Ziehau ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset); 4133*15516c77SSepherosa Ziehau if (dlen < ofs + msg->rm_stbuflen || 4134*15516c77SSepherosa Ziehau msg->rm_stbuflen < sizeof(uint32_t)) { 4135*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed\n"); 4136*15516c77SSepherosa Ziehau } else { 4137*15516c77SSepherosa Ziehau uint32_t change; 4138*15516c77SSepherosa Ziehau 4139*15516c77SSepherosa Ziehau memcpy(&change, ((const uint8_t *)msg) + ofs, 4140*15516c77SSepherosa Ziehau sizeof(change)); 4141*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed, change %u\n", 4142*15516c77SSepherosa Ziehau change); 4143*15516c77SSepherosa Ziehau } 4144*15516c77SSepherosa Ziehau hn_change_network(sc); 4145*15516c77SSepherosa Ziehau break; 4146*15516c77SSepherosa Ziehau 4147*15516c77SSepherosa Ziehau default: 4148*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n", 4149*15516c77SSepherosa Ziehau msg->rm_status); 4150*15516c77SSepherosa Ziehau break; 4151*15516c77SSepherosa Ziehau } 4152*15516c77SSepherosa Ziehau } 4153*15516c77SSepherosa Ziehau 4154*15516c77SSepherosa Ziehau static int 4155*15516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info) 4156*15516c77SSepherosa Ziehau { 4157*15516c77SSepherosa Ziehau const struct rndis_pktinfo *pi = info_data; 4158*15516c77SSepherosa Ziehau uint32_t mask = 0; 4159*15516c77SSepherosa Ziehau 4160*15516c77SSepherosa Ziehau while (info_dlen != 0) { 4161*15516c77SSepherosa Ziehau const void *data; 4162*15516c77SSepherosa Ziehau uint32_t dlen; 4163*15516c77SSepherosa Ziehau 4164*15516c77SSepherosa Ziehau if (__predict_false(info_dlen < sizeof(*pi))) 4165*15516c77SSepherosa Ziehau return (EINVAL); 4166*15516c77SSepherosa Ziehau if (__predict_false(info_dlen < pi->rm_size)) 4167*15516c77SSepherosa Ziehau return (EINVAL); 4168*15516c77SSepherosa Ziehau info_dlen -= pi->rm_size; 4169*15516c77SSepherosa Ziehau 4170*15516c77SSepherosa Ziehau if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK)) 4171*15516c77SSepherosa Ziehau return (EINVAL); 4172*15516c77SSepherosa Ziehau if (__predict_false(pi->rm_size < pi->rm_pktinfooffset)) 4173*15516c77SSepherosa Ziehau return (EINVAL); 4174*15516c77SSepherosa Ziehau dlen = pi->rm_size - pi->rm_pktinfooffset; 4175*15516c77SSepherosa Ziehau data = pi->rm_data; 4176*15516c77SSepherosa Ziehau 4177*15516c77SSepherosa Ziehau switch (pi->rm_type) { 4178*15516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_VLAN: 4179*15516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE)) 4180*15516c77SSepherosa Ziehau return (EINVAL); 4181*15516c77SSepherosa Ziehau info->vlan_info = *((const uint32_t *)data); 4182*15516c77SSepherosa Ziehau mask |= HN_RXINFO_VLAN; 4183*15516c77SSepherosa Ziehau break; 4184*15516c77SSepherosa Ziehau 4185*15516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_CSUM: 4186*15516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE)) 4187*15516c77SSepherosa Ziehau return (EINVAL); 4188*15516c77SSepherosa Ziehau info->csum_info = *((const uint32_t *)data); 4189*15516c77SSepherosa Ziehau mask |= HN_RXINFO_CSUM; 4190*15516c77SSepherosa Ziehau break; 4191*15516c77SSepherosa Ziehau 4192*15516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHVAL: 4193*15516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE)) 4194*15516c77SSepherosa Ziehau return (EINVAL); 4195*15516c77SSepherosa Ziehau info->hash_value = *((const uint32_t *)data); 4196*15516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHVAL; 4197*15516c77SSepherosa Ziehau break; 4198*15516c77SSepherosa Ziehau 4199*15516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHINF: 4200*15516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE)) 4201*15516c77SSepherosa Ziehau return (EINVAL); 4202*15516c77SSepherosa Ziehau info->hash_info = *((const uint32_t *)data); 4203*15516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHINF; 4204*15516c77SSepherosa Ziehau break; 4205*15516c77SSepherosa Ziehau 4206*15516c77SSepherosa Ziehau default: 4207*15516c77SSepherosa Ziehau goto next; 4208*15516c77SSepherosa Ziehau } 4209*15516c77SSepherosa Ziehau 4210*15516c77SSepherosa Ziehau if (mask == HN_RXINFO_ALL) { 4211*15516c77SSepherosa Ziehau /* All found; done */ 4212*15516c77SSepherosa Ziehau break; 4213*15516c77SSepherosa Ziehau } 4214*15516c77SSepherosa Ziehau next: 4215*15516c77SSepherosa Ziehau pi = (const struct rndis_pktinfo *) 4216*15516c77SSepherosa Ziehau ((const uint8_t *)pi + pi->rm_size); 4217*15516c77SSepherosa Ziehau } 4218*15516c77SSepherosa Ziehau 4219*15516c77SSepherosa Ziehau /* 4220*15516c77SSepherosa Ziehau * Final fixup. 4221*15516c77SSepherosa Ziehau * - If there is no hash value, invalidate the hash info. 4222*15516c77SSepherosa Ziehau */ 4223*15516c77SSepherosa Ziehau if ((mask & HN_RXINFO_HASHVAL) == 0) 4224*15516c77SSepherosa Ziehau info->hash_info = HN_NDIS_HASH_INFO_INVALID; 4225*15516c77SSepherosa Ziehau return (0); 4226*15516c77SSepherosa Ziehau } 4227*15516c77SSepherosa Ziehau 4228*15516c77SSepherosa Ziehau static __inline bool 4229*15516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len) 4230*15516c77SSepherosa Ziehau { 4231*15516c77SSepherosa Ziehau 4232*15516c77SSepherosa Ziehau if (off < check_off) { 4233*15516c77SSepherosa Ziehau if (__predict_true(off + len <= check_off)) 4234*15516c77SSepherosa Ziehau return (false); 4235*15516c77SSepherosa Ziehau } else if (off > check_off) { 4236*15516c77SSepherosa Ziehau if (__predict_true(check_off + check_len <= off)) 4237*15516c77SSepherosa Ziehau return (false); 4238*15516c77SSepherosa Ziehau } 4239*15516c77SSepherosa Ziehau return (true); 4240*15516c77SSepherosa Ziehau } 4241*15516c77SSepherosa Ziehau 4242*15516c77SSepherosa Ziehau static void 4243*15516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen) 4244*15516c77SSepherosa Ziehau { 4245*15516c77SSepherosa Ziehau const struct rndis_packet_msg *pkt; 4246*15516c77SSepherosa Ziehau struct hn_rxinfo info; 4247*15516c77SSepherosa Ziehau int data_off, pktinfo_off, data_len, pktinfo_len; 4248*15516c77SSepherosa Ziehau 4249*15516c77SSepherosa Ziehau /* 4250*15516c77SSepherosa Ziehau * Check length. 4251*15516c77SSepherosa Ziehau */ 4252*15516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*pkt))) { 4253*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n"); 4254*15516c77SSepherosa Ziehau return; 4255*15516c77SSepherosa Ziehau } 4256*15516c77SSepherosa Ziehau pkt = data; 4257*15516c77SSepherosa Ziehau 4258*15516c77SSepherosa Ziehau if (__predict_false(dlen < pkt->rm_len)) { 4259*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, " 4260*15516c77SSepherosa Ziehau "dlen %d, msglen %u\n", dlen, pkt->rm_len); 4261*15516c77SSepherosa Ziehau return; 4262*15516c77SSepherosa Ziehau } 4263*15516c77SSepherosa Ziehau if (__predict_false(pkt->rm_len < 4264*15516c77SSepherosa Ziehau pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) { 4265*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, " 4266*15516c77SSepherosa Ziehau "msglen %u, data %u, oob %u, pktinfo %u\n", 4267*15516c77SSepherosa Ziehau pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen, 4268*15516c77SSepherosa Ziehau pkt->rm_pktinfolen); 4269*15516c77SSepherosa Ziehau return; 4270*15516c77SSepherosa Ziehau } 4271*15516c77SSepherosa Ziehau if (__predict_false(pkt->rm_datalen == 0)) { 4272*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n"); 4273*15516c77SSepherosa Ziehau return; 4274*15516c77SSepherosa Ziehau } 4275*15516c77SSepherosa Ziehau 4276*15516c77SSepherosa Ziehau /* 4277*15516c77SSepherosa Ziehau * Check offests. 4278*15516c77SSepherosa Ziehau */ 4279*15516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs) \ 4280*15516c77SSepherosa Ziehau ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \ 4281*15516c77SSepherosa Ziehau ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK)) 4282*15516c77SSepherosa Ziehau 4283*15516c77SSepherosa Ziehau /* XXX Hyper-V does not meet data offset alignment requirement */ 4284*15516c77SSepherosa Ziehau if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) { 4285*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 4286*15516c77SSepherosa Ziehau "data offset %u\n", pkt->rm_dataoffset); 4287*15516c77SSepherosa Ziehau return; 4288*15516c77SSepherosa Ziehau } 4289*15516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdataoffset > 0 && 4290*15516c77SSepherosa Ziehau IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) { 4291*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 4292*15516c77SSepherosa Ziehau "oob offset %u\n", pkt->rm_oobdataoffset); 4293*15516c77SSepherosa Ziehau return; 4294*15516c77SSepherosa Ziehau } 4295*15516c77SSepherosa Ziehau if (__predict_true(pkt->rm_pktinfooffset > 0) && 4296*15516c77SSepherosa Ziehau __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) { 4297*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 4298*15516c77SSepherosa Ziehau "pktinfo offset %u\n", pkt->rm_pktinfooffset); 4299*15516c77SSepherosa Ziehau return; 4300*15516c77SSepherosa Ziehau } 4301*15516c77SSepherosa Ziehau 4302*15516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID 4303*15516c77SSepherosa Ziehau 4304*15516c77SSepherosa Ziehau data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset); 4305*15516c77SSepherosa Ziehau data_len = pkt->rm_datalen; 4306*15516c77SSepherosa Ziehau pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset); 4307*15516c77SSepherosa Ziehau pktinfo_len = pkt->rm_pktinfolen; 4308*15516c77SSepherosa Ziehau 4309*15516c77SSepherosa Ziehau /* 4310*15516c77SSepherosa Ziehau * Check OOB coverage. 4311*15516c77SSepherosa Ziehau */ 4312*15516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdatalen != 0)) { 4313*15516c77SSepherosa Ziehau int oob_off, oob_len; 4314*15516c77SSepherosa Ziehau 4315*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "got oobdata\n"); 4316*15516c77SSepherosa Ziehau oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset); 4317*15516c77SSepherosa Ziehau oob_len = pkt->rm_oobdatalen; 4318*15516c77SSepherosa Ziehau 4319*15516c77SSepherosa Ziehau if (__predict_false(oob_off + oob_len > pkt->rm_len)) { 4320*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 4321*15516c77SSepherosa Ziehau "oob overflow, msglen %u, oob abs %d len %d\n", 4322*15516c77SSepherosa Ziehau pkt->rm_len, oob_off, oob_len); 4323*15516c77SSepherosa Ziehau return; 4324*15516c77SSepherosa Ziehau } 4325*15516c77SSepherosa Ziehau 4326*15516c77SSepherosa Ziehau /* 4327*15516c77SSepherosa Ziehau * Check against data. 4328*15516c77SSepherosa Ziehau */ 4329*15516c77SSepherosa Ziehau if (hn_rndis_check_overlap(oob_off, oob_len, 4330*15516c77SSepherosa Ziehau data_off, data_len)) { 4331*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 4332*15516c77SSepherosa Ziehau "oob overlaps data, oob abs %d len %d, " 4333*15516c77SSepherosa Ziehau "data abs %d len %d\n", 4334*15516c77SSepherosa Ziehau oob_off, oob_len, data_off, data_len); 4335*15516c77SSepherosa Ziehau return; 4336*15516c77SSepherosa Ziehau } 4337*15516c77SSepherosa Ziehau 4338*15516c77SSepherosa Ziehau /* 4339*15516c77SSepherosa Ziehau * Check against pktinfo. 4340*15516c77SSepherosa Ziehau */ 4341*15516c77SSepherosa Ziehau if (pktinfo_len != 0 && 4342*15516c77SSepherosa Ziehau hn_rndis_check_overlap(oob_off, oob_len, 4343*15516c77SSepherosa Ziehau pktinfo_off, pktinfo_len)) { 4344*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 4345*15516c77SSepherosa Ziehau "oob overlaps pktinfo, oob abs %d len %d, " 4346*15516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 4347*15516c77SSepherosa Ziehau oob_off, oob_len, pktinfo_off, pktinfo_len); 4348*15516c77SSepherosa Ziehau return; 4349*15516c77SSepherosa Ziehau } 4350*15516c77SSepherosa Ziehau } 4351*15516c77SSepherosa Ziehau 4352*15516c77SSepherosa Ziehau /* 4353*15516c77SSepherosa Ziehau * Check per-packet-info coverage and find useful per-packet-info. 4354*15516c77SSepherosa Ziehau */ 4355*15516c77SSepherosa Ziehau info.vlan_info = HN_NDIS_VLAN_INFO_INVALID; 4356*15516c77SSepherosa Ziehau info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID; 4357*15516c77SSepherosa Ziehau info.hash_info = HN_NDIS_HASH_INFO_INVALID; 4358*15516c77SSepherosa Ziehau if (__predict_true(pktinfo_len != 0)) { 4359*15516c77SSepherosa Ziehau bool overlap; 4360*15516c77SSepherosa Ziehau int error; 4361*15516c77SSepherosa Ziehau 4362*15516c77SSepherosa Ziehau if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) { 4363*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 4364*15516c77SSepherosa Ziehau "pktinfo overflow, msglen %u, " 4365*15516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 4366*15516c77SSepherosa Ziehau pkt->rm_len, pktinfo_off, pktinfo_len); 4367*15516c77SSepherosa Ziehau return; 4368*15516c77SSepherosa Ziehau } 4369*15516c77SSepherosa Ziehau 4370*15516c77SSepherosa Ziehau /* 4371*15516c77SSepherosa Ziehau * Check packet info coverage. 4372*15516c77SSepherosa Ziehau */ 4373*15516c77SSepherosa Ziehau overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len, 4374*15516c77SSepherosa Ziehau data_off, data_len); 4375*15516c77SSepherosa Ziehau if (__predict_false(overlap)) { 4376*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 4377*15516c77SSepherosa Ziehau "pktinfo overlap data, pktinfo abs %d len %d, " 4378*15516c77SSepherosa Ziehau "data abs %d len %d\n", 4379*15516c77SSepherosa Ziehau pktinfo_off, pktinfo_len, data_off, data_len); 4380*15516c77SSepherosa Ziehau return; 4381*15516c77SSepherosa Ziehau } 4382*15516c77SSepherosa Ziehau 4383*15516c77SSepherosa Ziehau /* 4384*15516c77SSepherosa Ziehau * Find useful per-packet-info. 4385*15516c77SSepherosa Ziehau */ 4386*15516c77SSepherosa Ziehau error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off, 4387*15516c77SSepherosa Ziehau pktinfo_len, &info); 4388*15516c77SSepherosa Ziehau if (__predict_false(error)) { 4389*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg " 4390*15516c77SSepherosa Ziehau "pktinfo\n"); 4391*15516c77SSepherosa Ziehau return; 4392*15516c77SSepherosa Ziehau } 4393*15516c77SSepherosa Ziehau } 4394*15516c77SSepherosa Ziehau 4395*15516c77SSepherosa Ziehau if (__predict_false(data_off + data_len > pkt->rm_len)) { 4396*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 4397*15516c77SSepherosa Ziehau "data overflow, msglen %u, data abs %d len %d\n", 4398*15516c77SSepherosa Ziehau pkt->rm_len, data_off, data_len); 4399*15516c77SSepherosa Ziehau return; 4400*15516c77SSepherosa Ziehau } 4401*15516c77SSepherosa Ziehau hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info); 4402*15516c77SSepherosa Ziehau } 4403*15516c77SSepherosa Ziehau 4404*15516c77SSepherosa Ziehau static __inline void 4405*15516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen) 4406*15516c77SSepherosa Ziehau { 4407*15516c77SSepherosa Ziehau const struct rndis_msghdr *hdr; 4408*15516c77SSepherosa Ziehau 4409*15516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*hdr))) { 4410*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS msg\n"); 4411*15516c77SSepherosa Ziehau return; 4412*15516c77SSepherosa Ziehau } 4413*15516c77SSepherosa Ziehau hdr = data; 4414*15516c77SSepherosa Ziehau 4415*15516c77SSepherosa Ziehau if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) { 4416*15516c77SSepherosa Ziehau /* Hot data path. */ 4417*15516c77SSepherosa Ziehau hn_rndis_rx_data(rxr, data, dlen); 4418*15516c77SSepherosa Ziehau /* Done! */ 4419*15516c77SSepherosa Ziehau return; 4420*15516c77SSepherosa Ziehau } 4421*15516c77SSepherosa Ziehau 4422*15516c77SSepherosa Ziehau if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG) 4423*15516c77SSepherosa Ziehau hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen); 4424*15516c77SSepherosa Ziehau else 4425*15516c77SSepherosa Ziehau hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen); 4426*15516c77SSepherosa Ziehau } 4427*15516c77SSepherosa Ziehau 4428*15516c77SSepherosa Ziehau static void 4429*15516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) 4430*15516c77SSepherosa Ziehau { 4431*15516c77SSepherosa Ziehau const struct hn_nvs_hdr *hdr; 4432*15516c77SSepherosa Ziehau 4433*15516c77SSepherosa Ziehau if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) { 4434*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid nvs notify\n"); 4435*15516c77SSepherosa Ziehau return; 4436*15516c77SSepherosa Ziehau } 4437*15516c77SSepherosa Ziehau hdr = VMBUS_CHANPKT_CONST_DATA(pkt); 4438*15516c77SSepherosa Ziehau 4439*15516c77SSepherosa Ziehau if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) { 4440*15516c77SSepherosa Ziehau /* Useless; ignore */ 4441*15516c77SSepherosa Ziehau return; 4442*15516c77SSepherosa Ziehau } 4443*15516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type); 4444*15516c77SSepherosa Ziehau } 4445*15516c77SSepherosa Ziehau 4446*15516c77SSepherosa Ziehau static void 4447*15516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan, 4448*15516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkt) 4449*15516c77SSepherosa Ziehau { 4450*15516c77SSepherosa Ziehau struct hn_nvs_sendctx *sndc; 4451*15516c77SSepherosa Ziehau 4452*15516c77SSepherosa Ziehau sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid; 4453*15516c77SSepherosa Ziehau sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt), 4454*15516c77SSepherosa Ziehau VMBUS_CHANPKT_DATALEN(pkt)); 4455*15516c77SSepherosa Ziehau /* 4456*15516c77SSepherosa Ziehau * NOTE: 4457*15516c77SSepherosa Ziehau * 'sndc' CAN NOT be accessed anymore, since it can be freed by 4458*15516c77SSepherosa Ziehau * its callback. 4459*15516c77SSepherosa Ziehau */ 4460*15516c77SSepherosa Ziehau } 4461*15516c77SSepherosa Ziehau 4462*15516c77SSepherosa Ziehau static void 4463*15516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 4464*15516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkthdr) 4465*15516c77SSepherosa Ziehau { 4466*15516c77SSepherosa Ziehau const struct vmbus_chanpkt_rxbuf *pkt; 4467*15516c77SSepherosa Ziehau const struct hn_nvs_hdr *nvs_hdr; 4468*15516c77SSepherosa Ziehau int count, i, hlen; 4469*15516c77SSepherosa Ziehau 4470*15516c77SSepherosa Ziehau if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) { 4471*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n"); 4472*15516c77SSepherosa Ziehau return; 4473*15516c77SSepherosa Ziehau } 4474*15516c77SSepherosa Ziehau nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr); 4475*15516c77SSepherosa Ziehau 4476*15516c77SSepherosa Ziehau /* Make sure that this is a RNDIS message. */ 4477*15516c77SSepherosa Ziehau if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) { 4478*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n", 4479*15516c77SSepherosa Ziehau nvs_hdr->nvs_type); 4480*15516c77SSepherosa Ziehau return; 4481*15516c77SSepherosa Ziehau } 4482*15516c77SSepherosa Ziehau 4483*15516c77SSepherosa Ziehau hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen); 4484*15516c77SSepherosa Ziehau if (__predict_false(hlen < sizeof(*pkt))) { 4485*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n"); 4486*15516c77SSepherosa Ziehau return; 4487*15516c77SSepherosa Ziehau } 4488*15516c77SSepherosa Ziehau pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr; 4489*15516c77SSepherosa Ziehau 4490*15516c77SSepherosa Ziehau if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) { 4491*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n", 4492*15516c77SSepherosa Ziehau pkt->cp_rxbuf_id); 4493*15516c77SSepherosa Ziehau return; 4494*15516c77SSepherosa Ziehau } 4495*15516c77SSepherosa Ziehau 4496*15516c77SSepherosa Ziehau count = pkt->cp_rxbuf_cnt; 4497*15516c77SSepherosa Ziehau if (__predict_false(hlen < 4498*15516c77SSepherosa Ziehau __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) { 4499*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count); 4500*15516c77SSepherosa Ziehau return; 4501*15516c77SSepherosa Ziehau } 4502*15516c77SSepherosa Ziehau 4503*15516c77SSepherosa Ziehau /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 4504*15516c77SSepherosa Ziehau for (i = 0; i < count; ++i) { 4505*15516c77SSepherosa Ziehau int ofs, len; 4506*15516c77SSepherosa Ziehau 4507*15516c77SSepherosa Ziehau ofs = pkt->cp_rxbuf[i].rb_ofs; 4508*15516c77SSepherosa Ziehau len = pkt->cp_rxbuf[i].rb_len; 4509*15516c77SSepherosa Ziehau if (__predict_false(ofs + len > HN_RXBUF_SIZE)) { 4510*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, " 4511*15516c77SSepherosa Ziehau "ofs %d, len %d\n", i, ofs, len); 4512*15516c77SSepherosa Ziehau continue; 4513*15516c77SSepherosa Ziehau } 4514*15516c77SSepherosa Ziehau hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len); 4515*15516c77SSepherosa Ziehau } 4516*15516c77SSepherosa Ziehau 4517*15516c77SSepherosa Ziehau /* 4518*15516c77SSepherosa Ziehau * Ack the consumed RXBUF associated w/ this channel packet, 4519*15516c77SSepherosa Ziehau * so that this RXBUF can be recycled by the hypervisor. 4520*15516c77SSepherosa Ziehau */ 4521*15516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid); 4522*15516c77SSepherosa Ziehau } 4523*15516c77SSepherosa Ziehau 4524*15516c77SSepherosa Ziehau static void 4525*15516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 4526*15516c77SSepherosa Ziehau uint64_t tid) 4527*15516c77SSepherosa Ziehau { 4528*15516c77SSepherosa Ziehau struct hn_nvs_rndis_ack ack; 4529*15516c77SSepherosa Ziehau int retries, error; 4530*15516c77SSepherosa Ziehau 4531*15516c77SSepherosa Ziehau ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK; 4532*15516c77SSepherosa Ziehau ack.nvs_status = HN_NVS_STATUS_OK; 4533*15516c77SSepherosa Ziehau 4534*15516c77SSepherosa Ziehau retries = 0; 4535*15516c77SSepherosa Ziehau again: 4536*15516c77SSepherosa Ziehau error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 4537*15516c77SSepherosa Ziehau VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid); 4538*15516c77SSepherosa Ziehau if (__predict_false(error == EAGAIN)) { 4539*15516c77SSepherosa Ziehau /* 4540*15516c77SSepherosa Ziehau * NOTE: 4541*15516c77SSepherosa Ziehau * This should _not_ happen in real world, since the 4542*15516c77SSepherosa Ziehau * consumption of the TX bufring from the TX path is 4543*15516c77SSepherosa Ziehau * controlled. 4544*15516c77SSepherosa Ziehau */ 4545*15516c77SSepherosa Ziehau if (rxr->hn_ack_failed == 0) 4546*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack retry\n"); 4547*15516c77SSepherosa Ziehau rxr->hn_ack_failed++; 4548*15516c77SSepherosa Ziehau retries++; 4549*15516c77SSepherosa Ziehau if (retries < 10) { 4550*15516c77SSepherosa Ziehau DELAY(100); 4551*15516c77SSepherosa Ziehau goto again; 4552*15516c77SSepherosa Ziehau } 4553*15516c77SSepherosa Ziehau /* RXBUF leaks! */ 4554*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack failed\n"); 4555*15516c77SSepherosa Ziehau } 4556*15516c77SSepherosa Ziehau } 4557*15516c77SSepherosa Ziehau 4558*15516c77SSepherosa Ziehau static void 4559*15516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr) 4560*15516c77SSepherosa Ziehau { 4561*15516c77SSepherosa Ziehau struct hn_rx_ring *rxr = xrxr; 4562*15516c77SSepherosa Ziehau struct hn_softc *sc = rxr->hn_ifp->if_softc; 4563*15516c77SSepherosa Ziehau 4564*15516c77SSepherosa Ziehau for (;;) { 4565*15516c77SSepherosa Ziehau struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf; 4566*15516c77SSepherosa Ziehau int error, pktlen; 4567*15516c77SSepherosa Ziehau 4568*15516c77SSepherosa Ziehau pktlen = rxr->hn_pktbuf_len; 4569*15516c77SSepherosa Ziehau error = vmbus_chan_recv_pkt(chan, pkt, &pktlen); 4570*15516c77SSepherosa Ziehau if (__predict_false(error == ENOBUFS)) { 4571*15516c77SSepherosa Ziehau void *nbuf; 4572*15516c77SSepherosa Ziehau int nlen; 4573*15516c77SSepherosa Ziehau 4574*15516c77SSepherosa Ziehau /* 4575*15516c77SSepherosa Ziehau * Expand channel packet buffer. 4576*15516c77SSepherosa Ziehau * 4577*15516c77SSepherosa Ziehau * XXX 4578*15516c77SSepherosa Ziehau * Use M_WAITOK here, since allocation failure 4579*15516c77SSepherosa Ziehau * is fatal. 4580*15516c77SSepherosa Ziehau */ 4581*15516c77SSepherosa Ziehau nlen = rxr->hn_pktbuf_len * 2; 4582*15516c77SSepherosa Ziehau while (nlen < pktlen) 4583*15516c77SSepherosa Ziehau nlen *= 2; 4584*15516c77SSepherosa Ziehau nbuf = malloc(nlen, M_DEVBUF, M_WAITOK); 4585*15516c77SSepherosa Ziehau 4586*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n", 4587*15516c77SSepherosa Ziehau rxr->hn_pktbuf_len, nlen); 4588*15516c77SSepherosa Ziehau 4589*15516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 4590*15516c77SSepherosa Ziehau rxr->hn_pktbuf = nbuf; 4591*15516c77SSepherosa Ziehau rxr->hn_pktbuf_len = nlen; 4592*15516c77SSepherosa Ziehau /* Retry! */ 4593*15516c77SSepherosa Ziehau continue; 4594*15516c77SSepherosa Ziehau } else if (__predict_false(error == EAGAIN)) { 4595*15516c77SSepherosa Ziehau /* No more channel packets; done! */ 4596*15516c77SSepherosa Ziehau break; 4597*15516c77SSepherosa Ziehau } 4598*15516c77SSepherosa Ziehau KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error)); 4599*15516c77SSepherosa Ziehau 4600*15516c77SSepherosa Ziehau switch (pkt->cph_type) { 4601*15516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_COMP: 4602*15516c77SSepherosa Ziehau hn_nvs_handle_comp(sc, chan, pkt); 4603*15516c77SSepherosa Ziehau break; 4604*15516c77SSepherosa Ziehau 4605*15516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_RXBUF: 4606*15516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(rxr, chan, pkt); 4607*15516c77SSepherosa Ziehau break; 4608*15516c77SSepherosa Ziehau 4609*15516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_INBAND: 4610*15516c77SSepherosa Ziehau hn_nvs_handle_notify(sc, pkt); 4611*15516c77SSepherosa Ziehau break; 4612*15516c77SSepherosa Ziehau 4613*15516c77SSepherosa Ziehau default: 4614*15516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "unknown chan pkt %u\n", 4615*15516c77SSepherosa Ziehau pkt->cph_type); 4616*15516c77SSepherosa Ziehau break; 4617*15516c77SSepherosa Ziehau } 4618*15516c77SSepherosa Ziehau } 4619*15516c77SSepherosa Ziehau hn_chan_rollup(rxr, rxr->hn_txr); 4620*15516c77SSepherosa Ziehau } 4621*15516c77SSepherosa Ziehau 4622*15516c77SSepherosa Ziehau static void 4623*15516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused) 4624*15516c77SSepherosa Ziehau { 4625*15516c77SSepherosa Ziehau 4626*15516c77SSepherosa Ziehau if (vm_guest != VM_GUEST_HV) 4627*15516c77SSepherosa Ziehau return; 4628*15516c77SSepherosa Ziehau 4629*15516c77SSepherosa Ziehau if (!hn_share_tx_taskq) 4630*15516c77SSepherosa Ziehau return; 4631*15516c77SSepherosa Ziehau 4632*15516c77SSepherosa Ziehau hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK, 4633*15516c77SSepherosa Ziehau taskqueue_thread_enqueue, &hn_tx_taskq); 4634*15516c77SSepherosa Ziehau if (hn_bind_tx_taskq >= 0) { 4635*15516c77SSepherosa Ziehau int cpu = hn_bind_tx_taskq; 4636*15516c77SSepherosa Ziehau cpuset_t cpu_set; 4637*15516c77SSepherosa Ziehau 4638*15516c77SSepherosa Ziehau if (cpu > mp_ncpus - 1) 4639*15516c77SSepherosa Ziehau cpu = mp_ncpus - 1; 4640*15516c77SSepherosa Ziehau CPU_SETOF(cpu, &cpu_set); 4641*15516c77SSepherosa Ziehau taskqueue_start_threads_cpuset(&hn_tx_taskq, 1, PI_NET, 4642*15516c77SSepherosa Ziehau &cpu_set, "hn tx"); 4643*15516c77SSepherosa Ziehau } else { 4644*15516c77SSepherosa Ziehau taskqueue_start_threads(&hn_tx_taskq, 1, PI_NET, "hn tx"); 4645*15516c77SSepherosa Ziehau } 4646*15516c77SSepherosa Ziehau } 4647*15516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND, 4648*15516c77SSepherosa Ziehau hn_tx_taskq_create, NULL); 4649*15516c77SSepherosa Ziehau 4650*15516c77SSepherosa Ziehau static void 4651*15516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused) 4652*15516c77SSepherosa Ziehau { 4653*15516c77SSepherosa Ziehau 4654*15516c77SSepherosa Ziehau if (hn_tx_taskq != NULL) 4655*15516c77SSepherosa Ziehau taskqueue_free(hn_tx_taskq); 4656*15516c77SSepherosa Ziehau } 4657*15516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND, 4658*15516c77SSepherosa Ziehau hn_tx_taskq_destroy, NULL); 4659