115516c77SSepherosa Ziehau /*- 215516c77SSepherosa Ziehau * Copyright (c) 2010-2012 Citrix Inc. 393b4e111SSepherosa Ziehau * Copyright (c) 2009-2012,2016-2017 Microsoft Corp. 415516c77SSepherosa Ziehau * Copyright (c) 2012 NetApp Inc. 515516c77SSepherosa Ziehau * All rights reserved. 615516c77SSepherosa Ziehau * 715516c77SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 815516c77SSepherosa Ziehau * modification, are permitted provided that the following conditions 915516c77SSepherosa Ziehau * are met: 1015516c77SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 1115516c77SSepherosa Ziehau * notice unmodified, this list of conditions, and the following 1215516c77SSepherosa Ziehau * disclaimer. 1315516c77SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 1415516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 1515516c77SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 1615516c77SSepherosa Ziehau * 1715516c77SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1815516c77SSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1915516c77SSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2015516c77SSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2115516c77SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2215516c77SSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2315516c77SSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2415516c77SSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2515516c77SSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2615516c77SSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2715516c77SSepherosa Ziehau */ 2815516c77SSepherosa Ziehau 2915516c77SSepherosa Ziehau /*- 3015516c77SSepherosa Ziehau * Copyright (c) 2004-2006 Kip Macy 3115516c77SSepherosa Ziehau * All rights reserved. 3215516c77SSepherosa Ziehau * 3315516c77SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 3415516c77SSepherosa Ziehau * modification, are permitted provided that the following conditions 3515516c77SSepherosa Ziehau * are met: 3615516c77SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 3715516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 3815516c77SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 3915516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 4015516c77SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 4115516c77SSepherosa Ziehau * 4215516c77SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 4315516c77SSepherosa Ziehau * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4415516c77SSepherosa Ziehau * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4515516c77SSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4615516c77SSepherosa Ziehau * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4715516c77SSepherosa Ziehau * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4815516c77SSepherosa Ziehau * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4915516c77SSepherosa Ziehau * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5015516c77SSepherosa Ziehau * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5115516c77SSepherosa Ziehau * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5215516c77SSepherosa Ziehau * SUCH DAMAGE. 5315516c77SSepherosa Ziehau */ 5415516c77SSepherosa Ziehau 5515516c77SSepherosa Ziehau #include <sys/cdefs.h> 5615516c77SSepherosa Ziehau __FBSDID("$FreeBSD$"); 5715516c77SSepherosa Ziehau 5834d68912SSepherosa Ziehau #include "opt_hn.h" 5915516c77SSepherosa Ziehau #include "opt_inet6.h" 6015516c77SSepherosa Ziehau #include "opt_inet.h" 6134d68912SSepherosa Ziehau #include "opt_rss.h" 6215516c77SSepherosa Ziehau 6315516c77SSepherosa Ziehau #include <sys/param.h> 6415516c77SSepherosa Ziehau #include <sys/bus.h> 6515516c77SSepherosa Ziehau #include <sys/kernel.h> 6615516c77SSepherosa Ziehau #include <sys/limits.h> 6715516c77SSepherosa Ziehau #include <sys/malloc.h> 6815516c77SSepherosa Ziehau #include <sys/mbuf.h> 6915516c77SSepherosa Ziehau #include <sys/module.h> 7015516c77SSepherosa Ziehau #include <sys/queue.h> 7115516c77SSepherosa Ziehau #include <sys/lock.h> 72499c3e17SSepherosa Ziehau #include <sys/rmlock.h> 73499c3e17SSepherosa Ziehau #include <sys/sbuf.h> 7415516c77SSepherosa Ziehau #include <sys/smp.h> 7515516c77SSepherosa Ziehau #include <sys/socket.h> 7615516c77SSepherosa Ziehau #include <sys/sockio.h> 7715516c77SSepherosa Ziehau #include <sys/sx.h> 7815516c77SSepherosa Ziehau #include <sys/sysctl.h> 7915516c77SSepherosa Ziehau #include <sys/systm.h> 8015516c77SSepherosa Ziehau #include <sys/taskqueue.h> 8115516c77SSepherosa Ziehau #include <sys/buf_ring.h> 825bdfd3fdSDexuan Cui #include <sys/eventhandler.h> 8315516c77SSepherosa Ziehau 8415516c77SSepherosa Ziehau #include <machine/atomic.h> 8515516c77SSepherosa Ziehau #include <machine/in_cksum.h> 8615516c77SSepherosa Ziehau 8715516c77SSepherosa Ziehau #include <net/bpf.h> 8815516c77SSepherosa Ziehau #include <net/ethernet.h> 8915516c77SSepherosa Ziehau #include <net/if.h> 905bdfd3fdSDexuan Cui #include <net/if_dl.h> 9115516c77SSepherosa Ziehau #include <net/if_media.h> 9215516c77SSepherosa Ziehau #include <net/if_types.h> 9315516c77SSepherosa Ziehau #include <net/if_var.h> 9415516c77SSepherosa Ziehau #include <net/rndis.h> 9534d68912SSepherosa Ziehau #ifdef RSS 9634d68912SSepherosa Ziehau #include <net/rss_config.h> 9734d68912SSepherosa Ziehau #endif 9815516c77SSepherosa Ziehau 9915516c77SSepherosa Ziehau #include <netinet/in_systm.h> 10015516c77SSepherosa Ziehau #include <netinet/in.h> 10115516c77SSepherosa Ziehau #include <netinet/ip.h> 10215516c77SSepherosa Ziehau #include <netinet/ip6.h> 10315516c77SSepherosa Ziehau #include <netinet/tcp.h> 10415516c77SSepherosa Ziehau #include <netinet/tcp_lro.h> 10515516c77SSepherosa Ziehau #include <netinet/udp.h> 10615516c77SSepherosa Ziehau 10715516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h> 10815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h> 10915516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h> 11015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h> 11115516c77SSepherosa Ziehau 11215516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h> 11315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h> 11415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h> 11515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h> 11615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h> 11715516c77SSepherosa Ziehau 11815516c77SSepherosa Ziehau #include "vmbus_if.h" 11915516c77SSepherosa Ziehau 12023bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT 12123bf9e15SSepherosa Ziehau 12215516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX 8 12315516c77SSepherosa Ziehau 124499c3e17SSepherosa Ziehau #define HN_VFMAP_SIZE_DEF 8 125499c3e17SSepherosa Ziehau 1269c6cae24SSepherosa Ziehau #define HN_XPNT_VF_ATTWAIT_MIN 2 /* seconds */ 1279c6cae24SSepherosa Ziehau 12815516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */ 12915516c77SSepherosa Ziehau #define HN_TX_DESC_CNT 512 13015516c77SSepherosa Ziehau 13115516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN \ 13215516c77SSepherosa Ziehau (sizeof(struct rndis_packet_msg) + \ 13315516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) + \ 13415516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) + \ 13515516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) + \ 13615516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE)) 13715516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY PAGE_SIZE 13815516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN CACHE_LINE_SIZE 13915516c77SSepherosa Ziehau 14015516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY PAGE_SIZE 14115516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE IP_MAXPACKET 14215516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE PAGE_SIZE 14315516c77SSepherosa Ziehau /* -1 for RNDIS packet message */ 14415516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX (HN_GPACNT_MAX - 1) 14515516c77SSepherosa Ziehau 14615516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF 128 14715516c77SSepherosa Ziehau 14815516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH 8 14915516c77SSepherosa Ziehau 15015516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF (16 * 1024) 15115516c77SSepherosa Ziehau 15215516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF 128 15315516c77SSepherosa Ziehau 15415516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF (12 * ETHERMTU) 15515516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF (25 * ETHERMTU) 15615516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */ 15715516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp) (2 * (ifp)->if_mtu) 15815516c77SSepherosa Ziehau 15915516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF 1 16015516c77SSepherosa Ziehau 16115516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc) \ 16215516c77SSepherosa Ziehau sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev)) 16315516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc) sx_destroy(&(sc)->hn_lock) 16415516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc) sx_assert(&(sc)->hn_lock, SA_XLOCKED) 165fdc4f478SSepherosa Ziehau #define HN_LOCK(sc) \ 166fdc4f478SSepherosa Ziehau do { \ 167fdc4f478SSepherosa Ziehau while (sx_try_xlock(&(sc)->hn_lock) == 0) \ 168fdc4f478SSepherosa Ziehau DELAY(1000); \ 169fdc4f478SSepherosa Ziehau } while (0) 17015516c77SSepherosa Ziehau #define HN_UNLOCK(sc) sx_xunlock(&(sc)->hn_lock) 17115516c77SSepherosa Ziehau 17215516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK (CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP) 17315516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK (CSUM_IP6_TCP | CSUM_IP6_UDP) 17415516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc) \ 17515516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK) 17615516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc) \ 17715516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK) 17815516c77SSepherosa Ziehau 179dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align) \ 180dc13fee6SSepherosa Ziehau roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \ 181dc13fee6SSepherosa Ziehau HN_RNDIS_PKT_LEN, (align)) 182dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align) \ 183dc13fee6SSepherosa Ziehau roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align)) 184dc13fee6SSepherosa Ziehau 18534d68912SSepherosa Ziehau #ifdef RSS 18634d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx) rss_getcpu((idx) % rss_getnumbuckets()) 18734d68912SSepherosa Ziehau #else 1880e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx) (((sc)->hn_cpu + (idx)) % mp_ncpus) 18934d68912SSepherosa Ziehau #endif 1900e11868dSSepherosa Ziehau 19115516c77SSepherosa Ziehau struct hn_txdesc { 19215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 19315516c77SSepherosa Ziehau SLIST_ENTRY(hn_txdesc) link; 19415516c77SSepherosa Ziehau #endif 195dc13fee6SSepherosa Ziehau STAILQ_ENTRY(hn_txdesc) agg_link; 196dc13fee6SSepherosa Ziehau 197dc13fee6SSepherosa Ziehau /* Aggregated txdescs, in sending order. */ 198dc13fee6SSepherosa Ziehau STAILQ_HEAD(, hn_txdesc) agg_list; 199dc13fee6SSepherosa Ziehau 200dc13fee6SSepherosa Ziehau /* The oldest packet, if transmission aggregation happens. */ 20115516c77SSepherosa Ziehau struct mbuf *m; 20215516c77SSepherosa Ziehau struct hn_tx_ring *txr; 20315516c77SSepherosa Ziehau int refs; 20415516c77SSepherosa Ziehau uint32_t flags; /* HN_TXD_FLAG_ */ 20515516c77SSepherosa Ziehau struct hn_nvs_sendctx send_ctx; 20615516c77SSepherosa Ziehau uint32_t chim_index; 20715516c77SSepherosa Ziehau int chim_size; 20815516c77SSepherosa Ziehau 20915516c77SSepherosa Ziehau bus_dmamap_t data_dmap; 21015516c77SSepherosa Ziehau 21115516c77SSepherosa Ziehau bus_addr_t rndis_pkt_paddr; 21215516c77SSepherosa Ziehau struct rndis_packet_msg *rndis_pkt; 21315516c77SSepherosa Ziehau bus_dmamap_t rndis_pkt_dmap; 21415516c77SSepherosa Ziehau }; 21515516c77SSepherosa Ziehau 21615516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST 0x0001 21715516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP 0x0002 218dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG 0x0004 21915516c77SSepherosa Ziehau 22015516c77SSepherosa Ziehau struct hn_rxinfo { 22115516c77SSepherosa Ziehau uint32_t vlan_info; 22215516c77SSepherosa Ziehau uint32_t csum_info; 22315516c77SSepherosa Ziehau uint32_t hash_info; 22415516c77SSepherosa Ziehau uint32_t hash_value; 22515516c77SSepherosa Ziehau }; 22615516c77SSepherosa Ziehau 227962f0357SSepherosa Ziehau struct hn_rxvf_setarg { 2285bdfd3fdSDexuan Cui struct hn_rx_ring *rxr; 229962f0357SSepherosa Ziehau struct ifnet *vf_ifp; 2305bdfd3fdSDexuan Cui }; 2315bdfd3fdSDexuan Cui 23215516c77SSepherosa Ziehau #define HN_RXINFO_VLAN 0x0001 23315516c77SSepherosa Ziehau #define HN_RXINFO_CSUM 0x0002 23415516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF 0x0004 23515516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL 0x0008 23615516c77SSepherosa Ziehau #define HN_RXINFO_ALL \ 23715516c77SSepherosa Ziehau (HN_RXINFO_VLAN | \ 23815516c77SSepherosa Ziehau HN_RXINFO_CSUM | \ 23915516c77SSepherosa Ziehau HN_RXINFO_HASHINF | \ 24015516c77SSepherosa Ziehau HN_RXINFO_HASHVAL) 24115516c77SSepherosa Ziehau 24215516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID 0xffffffff 24315516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID 0 24415516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID 0 24515516c77SSepherosa Ziehau 24615516c77SSepherosa Ziehau static int hn_probe(device_t); 24715516c77SSepherosa Ziehau static int hn_attach(device_t); 24815516c77SSepherosa Ziehau static int hn_detach(device_t); 24915516c77SSepherosa Ziehau static int hn_shutdown(device_t); 25015516c77SSepherosa Ziehau static void hn_chan_callback(struct vmbus_channel *, 25115516c77SSepherosa Ziehau void *); 25215516c77SSepherosa Ziehau 25315516c77SSepherosa Ziehau static void hn_init(void *); 25415516c77SSepherosa Ziehau static int hn_ioctl(struct ifnet *, u_long, caddr_t); 25523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 25615516c77SSepherosa Ziehau static void hn_start(struct ifnet *); 25723bf9e15SSepherosa Ziehau #endif 25815516c77SSepherosa Ziehau static int hn_transmit(struct ifnet *, struct mbuf *); 25915516c77SSepherosa Ziehau static void hn_xmit_qflush(struct ifnet *); 26015516c77SSepherosa Ziehau static int hn_ifmedia_upd(struct ifnet *); 26115516c77SSepherosa Ziehau static void hn_ifmedia_sts(struct ifnet *, 26215516c77SSepherosa Ziehau struct ifmediareq *); 26315516c77SSepherosa Ziehau 264499c3e17SSepherosa Ziehau static void hn_ifnet_event(void *, struct ifnet *, int); 265499c3e17SSepherosa Ziehau static void hn_ifaddr_event(void *, struct ifnet *); 266499c3e17SSepherosa Ziehau static void hn_ifnet_attevent(void *, struct ifnet *); 267499c3e17SSepherosa Ziehau static void hn_ifnet_detevent(void *, struct ifnet *); 2689c6cae24SSepherosa Ziehau static void hn_ifnet_lnkevent(void *, struct ifnet *, int); 269499c3e17SSepherosa Ziehau 270962f0357SSepherosa Ziehau static bool hn_ismyvf(const struct hn_softc *, 271962f0357SSepherosa Ziehau const struct ifnet *); 272962f0357SSepherosa Ziehau static void hn_rxvf_change(struct hn_softc *, 273962f0357SSepherosa Ziehau struct ifnet *, bool); 274962f0357SSepherosa Ziehau static void hn_rxvf_set(struct hn_softc *, struct ifnet *); 275962f0357SSepherosa Ziehau static void hn_rxvf_set_task(void *, int); 2769c6cae24SSepherosa Ziehau static void hn_xpnt_vf_input(struct ifnet *, struct mbuf *); 2779c6cae24SSepherosa Ziehau static int hn_xpnt_vf_iocsetflags(struct hn_softc *); 2789c6cae24SSepherosa Ziehau static int hn_xpnt_vf_iocsetcaps(struct hn_softc *, 2799c6cae24SSepherosa Ziehau struct ifreq *); 2809c6cae24SSepherosa Ziehau static void hn_xpnt_vf_saveifflags(struct hn_softc *); 2819c6cae24SSepherosa Ziehau static bool hn_xpnt_vf_isready(struct hn_softc *); 2829c6cae24SSepherosa Ziehau static void hn_xpnt_vf_setready(struct hn_softc *); 2839c6cae24SSepherosa Ziehau static void hn_xpnt_vf_init_taskfunc(void *, int); 2849c6cae24SSepherosa Ziehau static void hn_xpnt_vf_init(struct hn_softc *); 285a97fff19SSepherosa Ziehau static void hn_xpnt_vf_setenable(struct hn_softc *); 286a97fff19SSepherosa Ziehau static void hn_xpnt_vf_setdisable(struct hn_softc *, bool); 287642ec226SSepherosa Ziehau static void hn_vf_rss_fixup(struct hn_softc *, bool); 288642ec226SSepherosa Ziehau static void hn_vf_rss_restore(struct hn_softc *); 289962f0357SSepherosa Ziehau 29015516c77SSepherosa Ziehau static int hn_rndis_rxinfo(const void *, int, 29115516c77SSepherosa Ziehau struct hn_rxinfo *); 29215516c77SSepherosa Ziehau static void hn_rndis_rx_data(struct hn_rx_ring *, 29315516c77SSepherosa Ziehau const void *, int); 29415516c77SSepherosa Ziehau static void hn_rndis_rx_status(struct hn_softc *, 29515516c77SSepherosa Ziehau const void *, int); 296b3b75d9cSSepherosa Ziehau static void hn_rndis_init_fixat(struct hn_softc *, int); 29715516c77SSepherosa Ziehau 29815516c77SSepherosa Ziehau static void hn_nvs_handle_notify(struct hn_softc *, 29915516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 30015516c77SSepherosa Ziehau static void hn_nvs_handle_comp(struct hn_softc *, 30115516c77SSepherosa Ziehau struct vmbus_channel *, 30215516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 30315516c77SSepherosa Ziehau static void hn_nvs_handle_rxbuf(struct hn_rx_ring *, 30415516c77SSepherosa Ziehau struct vmbus_channel *, 30515516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 30615516c77SSepherosa Ziehau static void hn_nvs_ack_rxbuf(struct hn_rx_ring *, 30715516c77SSepherosa Ziehau struct vmbus_channel *, uint64_t); 30815516c77SSepherosa Ziehau 30915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 31015516c77SSepherosa Ziehau static int hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS); 31115516c77SSepherosa Ziehau static int hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS); 31215516c77SSepherosa Ziehau #endif 31315516c77SSepherosa Ziehau static int hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS); 31415516c77SSepherosa Ziehau static int hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS); 31515516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 31615516c77SSepherosa Ziehau static int hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS); 31715516c77SSepherosa Ziehau #else 31815516c77SSepherosa Ziehau static int hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS); 31915516c77SSepherosa Ziehau #endif 32015516c77SSepherosa Ziehau static int hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 32115516c77SSepherosa Ziehau static int hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 32215516c77SSepherosa Ziehau static int hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS); 32315516c77SSepherosa Ziehau static int hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS); 32415516c77SSepherosa Ziehau static int hn_caps_sysctl(SYSCTL_HANDLER_ARGS); 32515516c77SSepherosa Ziehau static int hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS); 32615516c77SSepherosa Ziehau static int hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS); 32734d68912SSepherosa Ziehau #ifndef RSS 32815516c77SSepherosa Ziehau static int hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS); 32915516c77SSepherosa Ziehau static int hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS); 33034d68912SSepherosa Ziehau #endif 33115516c77SSepherosa Ziehau static int hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS); 332642ec226SSepherosa Ziehau static int hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS); 333642ec226SSepherosa Ziehau static int hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS); 334dc13fee6SSepherosa Ziehau static int hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS); 335dc13fee6SSepherosa Ziehau static int hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS); 336dc13fee6SSepherosa Ziehau static int hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS); 337dc13fee6SSepherosa Ziehau static int hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS); 3386c1204dfSSepherosa Ziehau static int hn_polling_sysctl(SYSCTL_HANDLER_ARGS); 33940d60d6eSDexuan Cui static int hn_vf_sysctl(SYSCTL_HANDLER_ARGS); 340499c3e17SSepherosa Ziehau static int hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS); 341499c3e17SSepherosa Ziehau static int hn_vflist_sysctl(SYSCTL_HANDLER_ARGS); 342499c3e17SSepherosa Ziehau static int hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS); 3439c6cae24SSepherosa Ziehau static int hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS); 3449c6cae24SSepherosa Ziehau static int hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS); 34515516c77SSepherosa Ziehau 3465bdfd3fdSDexuan Cui static void hn_stop(struct hn_softc *, bool); 34715516c77SSepherosa Ziehau static void hn_init_locked(struct hn_softc *); 34815516c77SSepherosa Ziehau static int hn_chan_attach(struct hn_softc *, 34915516c77SSepherosa Ziehau struct vmbus_channel *); 35015516c77SSepherosa Ziehau static void hn_chan_detach(struct hn_softc *, 35115516c77SSepherosa Ziehau struct vmbus_channel *); 35215516c77SSepherosa Ziehau static int hn_attach_subchans(struct hn_softc *); 35315516c77SSepherosa Ziehau static void hn_detach_allchans(struct hn_softc *); 35415516c77SSepherosa Ziehau static void hn_chan_rollup(struct hn_rx_ring *, 35515516c77SSepherosa Ziehau struct hn_tx_ring *); 35615516c77SSepherosa Ziehau static void hn_set_ring_inuse(struct hn_softc *, int); 35715516c77SSepherosa Ziehau static int hn_synth_attach(struct hn_softc *, int); 35815516c77SSepherosa Ziehau static void hn_synth_detach(struct hn_softc *); 35915516c77SSepherosa Ziehau static int hn_synth_alloc_subchans(struct hn_softc *, 36015516c77SSepherosa Ziehau int *); 3612494d735SSepherosa Ziehau static bool hn_synth_attachable(const struct hn_softc *); 36215516c77SSepherosa Ziehau static void hn_suspend(struct hn_softc *); 36315516c77SSepherosa Ziehau static void hn_suspend_data(struct hn_softc *); 36415516c77SSepherosa Ziehau static void hn_suspend_mgmt(struct hn_softc *); 36515516c77SSepherosa Ziehau static void hn_resume(struct hn_softc *); 36615516c77SSepherosa Ziehau static void hn_resume_data(struct hn_softc *); 36715516c77SSepherosa Ziehau static void hn_resume_mgmt(struct hn_softc *); 36815516c77SSepherosa Ziehau static void hn_suspend_mgmt_taskfunc(void *, int); 36925641fc7SSepherosa Ziehau static void hn_chan_drain(struct hn_softc *, 37025641fc7SSepherosa Ziehau struct vmbus_channel *); 371b3b75d9cSSepherosa Ziehau static void hn_disable_rx(struct hn_softc *); 372b3b75d9cSSepherosa Ziehau static void hn_drain_rxtx(struct hn_softc *, int); 3736c1204dfSSepherosa Ziehau static void hn_polling(struct hn_softc *, u_int); 3746c1204dfSSepherosa Ziehau static void hn_chan_polling(struct vmbus_channel *, u_int); 3759c6cae24SSepherosa Ziehau static void hn_mtu_change_fixup(struct hn_softc *); 37615516c77SSepherosa Ziehau 37715516c77SSepherosa Ziehau static void hn_update_link_status(struct hn_softc *); 37815516c77SSepherosa Ziehau static void hn_change_network(struct hn_softc *); 37915516c77SSepherosa Ziehau static void hn_link_taskfunc(void *, int); 38015516c77SSepherosa Ziehau static void hn_netchg_init_taskfunc(void *, int); 38115516c77SSepherosa Ziehau static void hn_netchg_status_taskfunc(void *, int); 38215516c77SSepherosa Ziehau static void hn_link_status(struct hn_softc *); 38315516c77SSepherosa Ziehau 38415516c77SSepherosa Ziehau static int hn_create_rx_data(struct hn_softc *, int); 38515516c77SSepherosa Ziehau static void hn_destroy_rx_data(struct hn_softc *); 38615516c77SSepherosa Ziehau static int hn_check_iplen(const struct mbuf *, int); 387f1b0a43fSSepherosa Ziehau static int hn_set_rxfilter(struct hn_softc *, uint32_t); 388c08f7b2cSSepherosa Ziehau static int hn_rxfilter_config(struct hn_softc *); 38934d68912SSepherosa Ziehau #ifndef RSS 39015516c77SSepherosa Ziehau static int hn_rss_reconfig(struct hn_softc *); 39134d68912SSepherosa Ziehau #endif 392afd4971bSSepherosa Ziehau static void hn_rss_ind_fixup(struct hn_softc *); 393642ec226SSepherosa Ziehau static void hn_rss_mbuf_hash(struct hn_softc *, uint32_t); 39415516c77SSepherosa Ziehau static int hn_rxpkt(struct hn_rx_ring *, const void *, 39515516c77SSepherosa Ziehau int, const struct hn_rxinfo *); 396642ec226SSepherosa Ziehau static uint32_t hn_rss_type_fromndis(uint32_t); 397642ec226SSepherosa Ziehau static uint32_t hn_rss_type_tondis(uint32_t); 39815516c77SSepherosa Ziehau 39915516c77SSepherosa Ziehau static int hn_tx_ring_create(struct hn_softc *, int); 40015516c77SSepherosa Ziehau static void hn_tx_ring_destroy(struct hn_tx_ring *); 40115516c77SSepherosa Ziehau static int hn_create_tx_data(struct hn_softc *, int); 40215516c77SSepherosa Ziehau static void hn_fixup_tx_data(struct hn_softc *); 40315516c77SSepherosa Ziehau static void hn_destroy_tx_data(struct hn_softc *); 40415516c77SSepherosa Ziehau static void hn_txdesc_dmamap_destroy(struct hn_txdesc *); 40525641fc7SSepherosa Ziehau static void hn_txdesc_gc(struct hn_tx_ring *, 40625641fc7SSepherosa Ziehau struct hn_txdesc *); 407dc13fee6SSepherosa Ziehau static int hn_encap(struct ifnet *, struct hn_tx_ring *, 40815516c77SSepherosa Ziehau struct hn_txdesc *, struct mbuf **); 40915516c77SSepherosa Ziehau static int hn_txpkt(struct ifnet *, struct hn_tx_ring *, 41015516c77SSepherosa Ziehau struct hn_txdesc *); 41115516c77SSepherosa Ziehau static void hn_set_chim_size(struct hn_softc *, int); 41215516c77SSepherosa Ziehau static void hn_set_tso_maxsize(struct hn_softc *, int, int); 41315516c77SSepherosa Ziehau static bool hn_tx_ring_pending(struct hn_tx_ring *); 41415516c77SSepherosa Ziehau static void hn_tx_ring_qflush(struct hn_tx_ring *); 41515516c77SSepherosa Ziehau static void hn_resume_tx(struct hn_softc *, int); 416dc13fee6SSepherosa Ziehau static void hn_set_txagg(struct hn_softc *); 417dc13fee6SSepherosa Ziehau static void *hn_try_txagg(struct ifnet *, 418dc13fee6SSepherosa Ziehau struct hn_tx_ring *, struct hn_txdesc *, 419dc13fee6SSepherosa Ziehau int); 42015516c77SSepherosa Ziehau static int hn_get_txswq_depth(const struct hn_tx_ring *); 42115516c77SSepherosa Ziehau static void hn_txpkt_done(struct hn_nvs_sendctx *, 42215516c77SSepherosa Ziehau struct hn_softc *, struct vmbus_channel *, 42315516c77SSepherosa Ziehau const void *, int); 42415516c77SSepherosa Ziehau static int hn_txpkt_sglist(struct hn_tx_ring *, 42515516c77SSepherosa Ziehau struct hn_txdesc *); 42615516c77SSepherosa Ziehau static int hn_txpkt_chim(struct hn_tx_ring *, 42715516c77SSepherosa Ziehau struct hn_txdesc *); 42815516c77SSepherosa Ziehau static int hn_xmit(struct hn_tx_ring *, int); 42915516c77SSepherosa Ziehau static void hn_xmit_taskfunc(void *, int); 43015516c77SSepherosa Ziehau static void hn_xmit_txeof(struct hn_tx_ring *); 43115516c77SSepherosa Ziehau static void hn_xmit_txeof_taskfunc(void *, int); 43223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 43315516c77SSepherosa Ziehau static int hn_start_locked(struct hn_tx_ring *, int); 43415516c77SSepherosa Ziehau static void hn_start_taskfunc(void *, int); 43515516c77SSepherosa Ziehau static void hn_start_txeof(struct hn_tx_ring *); 43615516c77SSepherosa Ziehau static void hn_start_txeof_taskfunc(void *, int); 43723bf9e15SSepherosa Ziehau #endif 43815516c77SSepherosa Ziehau 43915516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 44015516c77SSepherosa Ziehau "Hyper-V network interface"); 44115516c77SSepherosa Ziehau 44215516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */ 44315516c77SSepherosa Ziehau static int hn_trust_hosttcp = 1; 44415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN, 44515516c77SSepherosa Ziehau &hn_trust_hosttcp, 0, 44615516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 44715516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 44815516c77SSepherosa Ziehau 44915516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */ 45015516c77SSepherosa Ziehau static int hn_trust_hostudp = 1; 45115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN, 45215516c77SSepherosa Ziehau &hn_trust_hostudp, 0, 45315516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 45415516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 45515516c77SSepherosa Ziehau 45615516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */ 45715516c77SSepherosa Ziehau static int hn_trust_hostip = 1; 45815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN, 45915516c77SSepherosa Ziehau &hn_trust_hostip, 0, 46015516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 46115516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 46215516c77SSepherosa Ziehau 46315516c77SSepherosa Ziehau /* Limit TSO burst size */ 46415516c77SSepherosa Ziehau static int hn_tso_maxlen = IP_MAXPACKET; 46515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN, 46615516c77SSepherosa Ziehau &hn_tso_maxlen, 0, "TSO burst limit"); 46715516c77SSepherosa Ziehau 46815516c77SSepherosa Ziehau /* Limit chimney send size */ 46915516c77SSepherosa Ziehau static int hn_tx_chimney_size = 0; 47015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN, 47115516c77SSepherosa Ziehau &hn_tx_chimney_size, 0, "Chimney send packet size limit"); 47215516c77SSepherosa Ziehau 47315516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */ 47415516c77SSepherosa Ziehau static int hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF; 47515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN, 47615516c77SSepherosa Ziehau &hn_direct_tx_size, 0, "Size of the packet for direct transmission"); 47715516c77SSepherosa Ziehau 47815516c77SSepherosa Ziehau /* # of LRO entries per RX ring */ 47915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 48015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 48115516c77SSepherosa Ziehau static int hn_lro_entry_count = HN_LROENT_CNT_DEF; 48215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN, 48315516c77SSepherosa Ziehau &hn_lro_entry_count, 0, "LRO entry count"); 48415516c77SSepherosa Ziehau #endif 48515516c77SSepherosa Ziehau #endif 48615516c77SSepherosa Ziehau 487fdd0222aSSepherosa Ziehau static int hn_tx_taskq_cnt = 1; 488fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN, 489fdd0222aSSepherosa Ziehau &hn_tx_taskq_cnt, 0, "# of TX taskqueues"); 490fdd0222aSSepherosa Ziehau 4910e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP 0 4920e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL 1 4930e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ 2 4940e11868dSSepherosa Ziehau 4950e11868dSSepherosa Ziehau static int hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP; 4960e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN, 4970e11868dSSepherosa Ziehau &hn_tx_taskq_mode, 0, "TX taskqueue modes: " 4980e11868dSSepherosa Ziehau "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs"); 4990e11868dSSepherosa Ziehau 50015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 50115516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 0; 50215516c77SSepherosa Ziehau #else 50315516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 1; 50415516c77SSepherosa Ziehau #endif 50515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD, 50615516c77SSepherosa Ziehau &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors"); 50715516c77SSepherosa Ziehau 50823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 50915516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */ 51015516c77SSepherosa Ziehau static int hn_use_if_start = 0; 51115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN, 51215516c77SSepherosa Ziehau &hn_use_if_start, 0, "Use if_start TX method"); 51323bf9e15SSepherosa Ziehau #endif 51415516c77SSepherosa Ziehau 51515516c77SSepherosa Ziehau /* # of channels to use */ 51615516c77SSepherosa Ziehau static int hn_chan_cnt = 0; 51715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN, 51815516c77SSepherosa Ziehau &hn_chan_cnt, 0, 51915516c77SSepherosa Ziehau "# of channels to use; each channel has one RX ring and one TX ring"); 52015516c77SSepherosa Ziehau 52115516c77SSepherosa Ziehau /* # of transmit rings to use */ 52215516c77SSepherosa Ziehau static int hn_tx_ring_cnt = 0; 52315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN, 52415516c77SSepherosa Ziehau &hn_tx_ring_cnt, 0, "# of TX rings to use"); 52515516c77SSepherosa Ziehau 52615516c77SSepherosa Ziehau /* Software TX ring deptch */ 52715516c77SSepherosa Ziehau static int hn_tx_swq_depth = 0; 52815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN, 52915516c77SSepherosa Ziehau &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING"); 53015516c77SSepherosa Ziehau 53115516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */ 53215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 53315516c77SSepherosa Ziehau static u_int hn_lro_mbufq_depth = 0; 53415516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN, 53515516c77SSepherosa Ziehau &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue"); 53615516c77SSepherosa Ziehau #endif 53715516c77SSepherosa Ziehau 538dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */ 539dc13fee6SSepherosa Ziehau static int hn_tx_agg_size = -1; 540dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN, 541dc13fee6SSepherosa Ziehau &hn_tx_agg_size, 0, "Packet transmission aggregation size limit"); 542dc13fee6SSepherosa Ziehau 543dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */ 544fa915c4dSSepherosa Ziehau static int hn_tx_agg_pkts = -1; 545dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN, 546dc13fee6SSepherosa Ziehau &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit"); 547dc13fee6SSepherosa Ziehau 548499c3e17SSepherosa Ziehau /* VF list */ 549499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vflist, CTLFLAG_RD | CTLTYPE_STRING, 550499c3e17SSepherosa Ziehau 0, 0, hn_vflist_sysctl, "A", "VF list"); 551499c3e17SSepherosa Ziehau 552499c3e17SSepherosa Ziehau /* VF mapping */ 553499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap, CTLFLAG_RD | CTLTYPE_STRING, 554499c3e17SSepherosa Ziehau 0, 0, hn_vfmap_sysctl, "A", "VF mapping"); 555499c3e17SSepherosa Ziehau 5569c6cae24SSepherosa Ziehau /* Transparent VF */ 5579c6cae24SSepherosa Ziehau static int hn_xpnt_vf = 0; 5589c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_transparent, CTLFLAG_RDTUN, 5599c6cae24SSepherosa Ziehau &hn_xpnt_vf, 0, "Transparent VF mod"); 5609c6cae24SSepherosa Ziehau 5619c6cae24SSepherosa Ziehau /* Accurate BPF support for Transparent VF */ 5629c6cae24SSepherosa Ziehau static int hn_xpnt_vf_accbpf = 0; 5639c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_accbpf, CTLFLAG_RDTUN, 5649c6cae24SSepherosa Ziehau &hn_xpnt_vf_accbpf, 0, "Accurate BPF for transparent VF"); 5659c6cae24SSepherosa Ziehau 5669c6cae24SSepherosa Ziehau /* Extra wait for transparent VF attach routing; unit seconds. */ 5679c6cae24SSepherosa Ziehau static int hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN; 5689c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_attwait, CTLFLAG_RWTUN, 5699c6cae24SSepherosa Ziehau &hn_xpnt_vf_attwait, 0, 5709c6cae24SSepherosa Ziehau "Extra wait for transparent VF attach routing; unit: seconds"); 5719c6cae24SSepherosa Ziehau 57215516c77SSepherosa Ziehau static u_int hn_cpu_index; /* next CPU for channel */ 573fdd0222aSSepherosa Ziehau static struct taskqueue **hn_tx_taskque;/* shared TX taskqueues */ 57415516c77SSepherosa Ziehau 575499c3e17SSepherosa Ziehau static struct rmlock hn_vfmap_lock; 576499c3e17SSepherosa Ziehau static int hn_vfmap_size; 577499c3e17SSepherosa Ziehau static struct ifnet **hn_vfmap; 578499c3e17SSepherosa Ziehau 57934d68912SSepherosa Ziehau #ifndef RSS 58015516c77SSepherosa Ziehau static const uint8_t 58115516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = { 58215516c77SSepherosa Ziehau 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 58315516c77SSepherosa Ziehau 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 58415516c77SSepherosa Ziehau 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 58515516c77SSepherosa Ziehau 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 58615516c77SSepherosa Ziehau 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa 58715516c77SSepherosa Ziehau }; 58834d68912SSepherosa Ziehau #endif /* !RSS */ 58915516c77SSepherosa Ziehau 590c2d50b26SSepherosa Ziehau static const struct hyperv_guid hn_guid = { 591c2d50b26SSepherosa Ziehau .hv_guid = { 592c2d50b26SSepherosa Ziehau 0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46, 593c2d50b26SSepherosa Ziehau 0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e } 594c2d50b26SSepherosa Ziehau }; 595c2d50b26SSepherosa Ziehau 59615516c77SSepherosa Ziehau static device_method_t hn_methods[] = { 59715516c77SSepherosa Ziehau /* Device interface */ 59815516c77SSepherosa Ziehau DEVMETHOD(device_probe, hn_probe), 59915516c77SSepherosa Ziehau DEVMETHOD(device_attach, hn_attach), 60015516c77SSepherosa Ziehau DEVMETHOD(device_detach, hn_detach), 60115516c77SSepherosa Ziehau DEVMETHOD(device_shutdown, hn_shutdown), 60215516c77SSepherosa Ziehau DEVMETHOD_END 60315516c77SSepherosa Ziehau }; 60415516c77SSepherosa Ziehau 60515516c77SSepherosa Ziehau static driver_t hn_driver = { 60615516c77SSepherosa Ziehau "hn", 60715516c77SSepherosa Ziehau hn_methods, 60815516c77SSepherosa Ziehau sizeof(struct hn_softc) 60915516c77SSepherosa Ziehau }; 61015516c77SSepherosa Ziehau 61115516c77SSepherosa Ziehau static devclass_t hn_devclass; 61215516c77SSepherosa Ziehau 61315516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0); 61415516c77SSepherosa Ziehau MODULE_VERSION(hn, 1); 61515516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1); 61615516c77SSepherosa Ziehau 61715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 61815516c77SSepherosa Ziehau static void 61915516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim) 62015516c77SSepherosa Ziehau { 62115516c77SSepherosa Ziehau int i; 62215516c77SSepherosa Ziehau 623a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 62415516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim; 62515516c77SSepherosa Ziehau } 62615516c77SSepherosa Ziehau #endif 62715516c77SSepherosa Ziehau 62815516c77SSepherosa Ziehau static int 62915516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd) 63015516c77SSepherosa Ziehau { 63115516c77SSepherosa Ziehau 63215516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 63315516c77SSepherosa Ziehau txd->chim_size == 0, ("invalid rndis sglist txd")); 63415516c77SSepherosa Ziehau return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA, 63515516c77SSepherosa Ziehau &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt)); 63615516c77SSepherosa Ziehau } 63715516c77SSepherosa Ziehau 63815516c77SSepherosa Ziehau static int 63915516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd) 64015516c77SSepherosa Ziehau { 64115516c77SSepherosa Ziehau struct hn_nvs_rndis rndis; 64215516c77SSepherosa Ziehau 64315516c77SSepherosa Ziehau KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID && 64415516c77SSepherosa Ziehau txd->chim_size > 0, ("invalid rndis chim txd")); 64515516c77SSepherosa Ziehau 64615516c77SSepherosa Ziehau rndis.nvs_type = HN_NVS_TYPE_RNDIS; 64715516c77SSepherosa Ziehau rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA; 64815516c77SSepherosa Ziehau rndis.nvs_chim_idx = txd->chim_index; 64915516c77SSepherosa Ziehau rndis.nvs_chim_sz = txd->chim_size; 65015516c77SSepherosa Ziehau 65115516c77SSepherosa Ziehau return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC, 65215516c77SSepherosa Ziehau &rndis, sizeof(rndis), &txd->send_ctx)); 65315516c77SSepherosa Ziehau } 65415516c77SSepherosa Ziehau 65515516c77SSepherosa Ziehau static __inline uint32_t 65615516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc) 65715516c77SSepherosa Ziehau { 65815516c77SSepherosa Ziehau int i, bmap_cnt = sc->hn_chim_bmap_cnt; 65915516c77SSepherosa Ziehau u_long *bmap = sc->hn_chim_bmap; 66015516c77SSepherosa Ziehau uint32_t ret = HN_NVS_CHIM_IDX_INVALID; 66115516c77SSepherosa Ziehau 66215516c77SSepherosa Ziehau for (i = 0; i < bmap_cnt; ++i) { 66315516c77SSepherosa Ziehau int idx; 66415516c77SSepherosa Ziehau 66515516c77SSepherosa Ziehau idx = ffsl(~bmap[i]); 66615516c77SSepherosa Ziehau if (idx == 0) 66715516c77SSepherosa Ziehau continue; 66815516c77SSepherosa Ziehau 66915516c77SSepherosa Ziehau --idx; /* ffsl is 1-based */ 67015516c77SSepherosa Ziehau KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt, 67115516c77SSepherosa Ziehau ("invalid i %d and idx %d", i, idx)); 67215516c77SSepherosa Ziehau 67315516c77SSepherosa Ziehau if (atomic_testandset_long(&bmap[i], idx)) 67415516c77SSepherosa Ziehau continue; 67515516c77SSepherosa Ziehau 67615516c77SSepherosa Ziehau ret = i * LONG_BIT + idx; 67715516c77SSepherosa Ziehau break; 67815516c77SSepherosa Ziehau } 67915516c77SSepherosa Ziehau return (ret); 68015516c77SSepherosa Ziehau } 68115516c77SSepherosa Ziehau 68215516c77SSepherosa Ziehau static __inline void 68315516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx) 68415516c77SSepherosa Ziehau { 68515516c77SSepherosa Ziehau u_long mask; 68615516c77SSepherosa Ziehau uint32_t idx; 68715516c77SSepherosa Ziehau 68815516c77SSepherosa Ziehau idx = chim_idx / LONG_BIT; 68915516c77SSepherosa Ziehau KASSERT(idx < sc->hn_chim_bmap_cnt, 69015516c77SSepherosa Ziehau ("invalid chimney index 0x%x", chim_idx)); 69115516c77SSepherosa Ziehau 69215516c77SSepherosa Ziehau mask = 1UL << (chim_idx % LONG_BIT); 69315516c77SSepherosa Ziehau KASSERT(sc->hn_chim_bmap[idx] & mask, 69415516c77SSepherosa Ziehau ("index bitmap 0x%lx, chimney index %u, " 69515516c77SSepherosa Ziehau "bitmap idx %d, bitmask 0x%lx", 69615516c77SSepherosa Ziehau sc->hn_chim_bmap[idx], chim_idx, idx, mask)); 69715516c77SSepherosa Ziehau 69815516c77SSepherosa Ziehau atomic_clear_long(&sc->hn_chim_bmap[idx], mask); 69915516c77SSepherosa Ziehau } 70015516c77SSepherosa Ziehau 701edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 702cc0c6ebcSSepherosa Ziehau 703cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len) \ 704cc0c6ebcSSepherosa Ziehau do { \ 705cc0c6ebcSSepherosa Ziehau if (__predict_false((m)->m_len < (len))) { \ 706cc0c6ebcSSepherosa Ziehau (m) = m_pullup((m), (len)); \ 707cc0c6ebcSSepherosa Ziehau if ((m) == NULL) \ 708cc0c6ebcSSepherosa Ziehau return (NULL); \ 709cc0c6ebcSSepherosa Ziehau } \ 710cc0c6ebcSSepherosa Ziehau } while (0) 711cc0c6ebcSSepherosa Ziehau 712edd3f315SSepherosa Ziehau /* 713edd3f315SSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 714edd3f315SSepherosa Ziehau */ 715edd3f315SSepherosa Ziehau static __inline struct mbuf * 716edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head) 717edd3f315SSepherosa Ziehau { 718edd3f315SSepherosa Ziehau struct ether_vlan_header *evl; 719edd3f315SSepherosa Ziehau struct tcphdr *th; 720edd3f315SSepherosa Ziehau int ehlen; 721edd3f315SSepherosa Ziehau 722edd3f315SSepherosa Ziehau KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable")); 723edd3f315SSepherosa Ziehau 724edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, sizeof(*evl)); 725edd3f315SSepherosa Ziehau evl = mtod(m_head, struct ether_vlan_header *); 726edd3f315SSepherosa Ziehau if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) 727edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 728edd3f315SSepherosa Ziehau else 729edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN; 730edd3f315SSepherosa Ziehau 731edd3f315SSepherosa Ziehau #ifdef INET 732edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 733edd3f315SSepherosa Ziehau struct ip *ip; 734edd3f315SSepherosa Ziehau int iphlen; 735edd3f315SSepherosa Ziehau 736edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip)); 737edd3f315SSepherosa Ziehau ip = mtodo(m_head, ehlen); 738edd3f315SSepherosa Ziehau iphlen = ip->ip_hl << 2; 739edd3f315SSepherosa Ziehau 740edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 741edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 742edd3f315SSepherosa Ziehau 743edd3f315SSepherosa Ziehau ip->ip_len = 0; 744edd3f315SSepherosa Ziehau ip->ip_sum = 0; 745edd3f315SSepherosa Ziehau th->th_sum = in_pseudo(ip->ip_src.s_addr, 746edd3f315SSepherosa Ziehau ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 747edd3f315SSepherosa Ziehau } 748edd3f315SSepherosa Ziehau #endif 749edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET) 750edd3f315SSepherosa Ziehau else 751edd3f315SSepherosa Ziehau #endif 752edd3f315SSepherosa Ziehau #ifdef INET6 753edd3f315SSepherosa Ziehau { 754edd3f315SSepherosa Ziehau struct ip6_hdr *ip6; 755edd3f315SSepherosa Ziehau 756edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); 757edd3f315SSepherosa Ziehau ip6 = mtodo(m_head, ehlen); 758edd3f315SSepherosa Ziehau if (ip6->ip6_nxt != IPPROTO_TCP) { 759edd3f315SSepherosa Ziehau m_freem(m_head); 760edd3f315SSepherosa Ziehau return (NULL); 761edd3f315SSepherosa Ziehau } 762edd3f315SSepherosa Ziehau 763edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); 764edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + sizeof(*ip6)); 765edd3f315SSepherosa Ziehau 766edd3f315SSepherosa Ziehau ip6->ip6_plen = 0; 767edd3f315SSepherosa Ziehau th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 768edd3f315SSepherosa Ziehau } 769edd3f315SSepherosa Ziehau #endif 770edd3f315SSepherosa Ziehau return (m_head); 771edd3f315SSepherosa Ziehau 772edd3f315SSepherosa Ziehau } 773cc0c6ebcSSepherosa Ziehau 774cc0c6ebcSSepherosa Ziehau /* 775cc0c6ebcSSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 776cc0c6ebcSSepherosa Ziehau */ 777cc0c6ebcSSepherosa Ziehau static __inline struct mbuf * 778cc0c6ebcSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn) 779cc0c6ebcSSepherosa Ziehau { 780cc0c6ebcSSepherosa Ziehau const struct ether_vlan_header *evl; 781cc0c6ebcSSepherosa Ziehau const struct tcphdr *th; 782cc0c6ebcSSepherosa Ziehau int ehlen; 783cc0c6ebcSSepherosa Ziehau 784cc0c6ebcSSepherosa Ziehau *tcpsyn = 0; 785cc0c6ebcSSepherosa Ziehau 786cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, sizeof(*evl)); 787cc0c6ebcSSepherosa Ziehau evl = mtod(m_head, const struct ether_vlan_header *); 788cc0c6ebcSSepherosa Ziehau if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) 789cc0c6ebcSSepherosa Ziehau ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 790cc0c6ebcSSepherosa Ziehau else 791cc0c6ebcSSepherosa Ziehau ehlen = ETHER_HDR_LEN; 792cc0c6ebcSSepherosa Ziehau 793cc0c6ebcSSepherosa Ziehau #ifdef INET 794cc0c6ebcSSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TCP) { 795cc0c6ebcSSepherosa Ziehau const struct ip *ip; 796cc0c6ebcSSepherosa Ziehau int iphlen; 797cc0c6ebcSSepherosa Ziehau 798cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip)); 799cc0c6ebcSSepherosa Ziehau ip = mtodo(m_head, ehlen); 800cc0c6ebcSSepherosa Ziehau iphlen = ip->ip_hl << 2; 801cc0c6ebcSSepherosa Ziehau 802cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 803cc0c6ebcSSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 804cc0c6ebcSSepherosa Ziehau if (th->th_flags & TH_SYN) 805cc0c6ebcSSepherosa Ziehau *tcpsyn = 1; 806cc0c6ebcSSepherosa Ziehau } 807cc0c6ebcSSepherosa Ziehau #endif 808cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET) 809cc0c6ebcSSepherosa Ziehau else 810cc0c6ebcSSepherosa Ziehau #endif 811cc0c6ebcSSepherosa Ziehau #ifdef INET6 812cc0c6ebcSSepherosa Ziehau { 813cc0c6ebcSSepherosa Ziehau const struct ip6_hdr *ip6; 814cc0c6ebcSSepherosa Ziehau 815cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); 816cc0c6ebcSSepherosa Ziehau ip6 = mtodo(m_head, ehlen); 817cc0c6ebcSSepherosa Ziehau if (ip6->ip6_nxt != IPPROTO_TCP) 818cc0c6ebcSSepherosa Ziehau return (m_head); 819cc0c6ebcSSepherosa Ziehau 820cc0c6ebcSSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); 821cc0c6ebcSSepherosa Ziehau th = mtodo(m_head, ehlen + sizeof(*ip6)); 822cc0c6ebcSSepherosa Ziehau if (th->th_flags & TH_SYN) 823cc0c6ebcSSepherosa Ziehau *tcpsyn = 1; 824cc0c6ebcSSepherosa Ziehau } 825cc0c6ebcSSepherosa Ziehau #endif 826cc0c6ebcSSepherosa Ziehau return (m_head); 827cc0c6ebcSSepherosa Ziehau } 828cc0c6ebcSSepherosa Ziehau 829cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR 830cc0c6ebcSSepherosa Ziehau 831edd3f315SSepherosa Ziehau #endif /* INET6 || INET */ 832edd3f315SSepherosa Ziehau 83315516c77SSepherosa Ziehau static int 834f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter) 835f1b0a43fSSepherosa Ziehau { 836f1b0a43fSSepherosa Ziehau int error = 0; 837f1b0a43fSSepherosa Ziehau 838f1b0a43fSSepherosa Ziehau HN_LOCK_ASSERT(sc); 839f1b0a43fSSepherosa Ziehau 840f1b0a43fSSepherosa Ziehau if (sc->hn_rx_filter != filter) { 841f1b0a43fSSepherosa Ziehau error = hn_rndis_set_rxfilter(sc, filter); 842f1b0a43fSSepherosa Ziehau if (!error) 843f1b0a43fSSepherosa Ziehau sc->hn_rx_filter = filter; 844f1b0a43fSSepherosa Ziehau } 845f1b0a43fSSepherosa Ziehau return (error); 846f1b0a43fSSepherosa Ziehau } 847f1b0a43fSSepherosa Ziehau 848f1b0a43fSSepherosa Ziehau static int 849c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc) 85015516c77SSepherosa Ziehau { 85115516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 85215516c77SSepherosa Ziehau uint32_t filter; 85315516c77SSepherosa Ziehau 85415516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 85515516c77SSepherosa Ziehau 8569c6cae24SSepherosa Ziehau /* 8579c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, we don't know how 8589c6cae24SSepherosa Ziehau * its RX filter is configured, so stick the synthetic device in 8599c6cae24SSepherosa Ziehau * the promiscous mode. 8609c6cae24SSepherosa Ziehau */ 8619c6cae24SSepherosa Ziehau if ((ifp->if_flags & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) { 86215516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_PROMISCUOUS; 86315516c77SSepherosa Ziehau } else { 86415516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_DIRECTED; 86515516c77SSepherosa Ziehau if (ifp->if_flags & IFF_BROADCAST) 86615516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_BROADCAST; 86715516c77SSepherosa Ziehau /* TODO: support multicast list */ 86815516c77SSepherosa Ziehau if ((ifp->if_flags & IFF_ALLMULTI) || 86915516c77SSepherosa Ziehau !TAILQ_EMPTY(&ifp->if_multiaddrs)) 87015516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 87115516c77SSepherosa Ziehau } 872f1b0a43fSSepherosa Ziehau return (hn_set_rxfilter(sc, filter)); 87315516c77SSepherosa Ziehau } 87415516c77SSepherosa Ziehau 875dc13fee6SSepherosa Ziehau static void 876dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc) 877dc13fee6SSepherosa Ziehau { 878dc13fee6SSepherosa Ziehau uint32_t size, pkts; 879dc13fee6SSepherosa Ziehau int i; 880dc13fee6SSepherosa Ziehau 881dc13fee6SSepherosa Ziehau /* 882dc13fee6SSepherosa Ziehau * Setup aggregation size. 883dc13fee6SSepherosa Ziehau */ 884dc13fee6SSepherosa Ziehau if (sc->hn_agg_size < 0) 885dc13fee6SSepherosa Ziehau size = UINT32_MAX; 886dc13fee6SSepherosa Ziehau else 887dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 888dc13fee6SSepherosa Ziehau 889dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_size < size) 890dc13fee6SSepherosa Ziehau size = sc->hn_rndis_agg_size; 891dc13fee6SSepherosa Ziehau 892a4364cfeSSepherosa Ziehau /* NOTE: We only aggregate packets using chimney sending buffers. */ 893a4364cfeSSepherosa Ziehau if (size > (uint32_t)sc->hn_chim_szmax) 894a4364cfeSSepherosa Ziehau size = sc->hn_chim_szmax; 895a4364cfeSSepherosa Ziehau 896dc13fee6SSepherosa Ziehau if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) { 897dc13fee6SSepherosa Ziehau /* Disable */ 898dc13fee6SSepherosa Ziehau size = 0; 899dc13fee6SSepherosa Ziehau pkts = 0; 900dc13fee6SSepherosa Ziehau goto done; 901dc13fee6SSepherosa Ziehau } 902dc13fee6SSepherosa Ziehau 903dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'int'. */ 904dc13fee6SSepherosa Ziehau if (size > INT_MAX) 905dc13fee6SSepherosa Ziehau size = INT_MAX; 906dc13fee6SSepherosa Ziehau 907dc13fee6SSepherosa Ziehau /* 908dc13fee6SSepherosa Ziehau * Setup aggregation packet count. 909dc13fee6SSepherosa Ziehau */ 910dc13fee6SSepherosa Ziehau if (sc->hn_agg_pkts < 0) 911dc13fee6SSepherosa Ziehau pkts = UINT32_MAX; 912dc13fee6SSepherosa Ziehau else 913dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 914dc13fee6SSepherosa Ziehau 915dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_pkts < pkts) 916dc13fee6SSepherosa Ziehau pkts = sc->hn_rndis_agg_pkts; 917dc13fee6SSepherosa Ziehau 918dc13fee6SSepherosa Ziehau if (pkts <= 1) { 919dc13fee6SSepherosa Ziehau /* Disable */ 920dc13fee6SSepherosa Ziehau size = 0; 921dc13fee6SSepherosa Ziehau pkts = 0; 922dc13fee6SSepherosa Ziehau goto done; 923dc13fee6SSepherosa Ziehau } 924dc13fee6SSepherosa Ziehau 925dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 926dc13fee6SSepherosa Ziehau if (pkts > SHRT_MAX) 927dc13fee6SSepherosa Ziehau pkts = SHRT_MAX; 928dc13fee6SSepherosa Ziehau 929dc13fee6SSepherosa Ziehau done: 930dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 931dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_align > SHRT_MAX) { 932dc13fee6SSepherosa Ziehau /* Disable */ 933dc13fee6SSepherosa Ziehau size = 0; 934dc13fee6SSepherosa Ziehau pkts = 0; 935dc13fee6SSepherosa Ziehau } 936dc13fee6SSepherosa Ziehau 937dc13fee6SSepherosa Ziehau if (bootverbose) { 938dc13fee6SSepherosa Ziehau if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n", 939dc13fee6SSepherosa Ziehau size, pkts, sc->hn_rndis_agg_align); 940dc13fee6SSepherosa Ziehau } 941dc13fee6SSepherosa Ziehau 942dc13fee6SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 943dc13fee6SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 944dc13fee6SSepherosa Ziehau 945dc13fee6SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 946dc13fee6SSepherosa Ziehau txr->hn_agg_szmax = size; 947dc13fee6SSepherosa Ziehau txr->hn_agg_pktmax = pkts; 948dc13fee6SSepherosa Ziehau txr->hn_agg_align = sc->hn_rndis_agg_align; 949dc13fee6SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 950dc13fee6SSepherosa Ziehau } 951dc13fee6SSepherosa Ziehau } 952dc13fee6SSepherosa Ziehau 95315516c77SSepherosa Ziehau static int 95415516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr) 95515516c77SSepherosa Ziehau { 95615516c77SSepherosa Ziehau 95715516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet")); 95815516c77SSepherosa Ziehau if (hn_tx_swq_depth < txr->hn_txdesc_cnt) 95915516c77SSepherosa Ziehau return txr->hn_txdesc_cnt; 96015516c77SSepherosa Ziehau return hn_tx_swq_depth; 96115516c77SSepherosa Ziehau } 96215516c77SSepherosa Ziehau 96334d68912SSepherosa Ziehau #ifndef RSS 96415516c77SSepherosa Ziehau static int 96515516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc) 96615516c77SSepherosa Ziehau { 96715516c77SSepherosa Ziehau int error; 96815516c77SSepherosa Ziehau 96915516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 97015516c77SSepherosa Ziehau 97115516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 97215516c77SSepherosa Ziehau return (ENXIO); 97315516c77SSepherosa Ziehau 97415516c77SSepherosa Ziehau /* 97515516c77SSepherosa Ziehau * Disable RSS first. 97615516c77SSepherosa Ziehau * 97715516c77SSepherosa Ziehau * NOTE: 97815516c77SSepherosa Ziehau * Direct reconfiguration by setting the UNCHG flags does 97915516c77SSepherosa Ziehau * _not_ work properly. 98015516c77SSepherosa Ziehau */ 98115516c77SSepherosa Ziehau if (bootverbose) 98215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "disable RSS\n"); 98315516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE); 98415516c77SSepherosa Ziehau if (error) { 98515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS disable failed\n"); 98615516c77SSepherosa Ziehau return (error); 98715516c77SSepherosa Ziehau } 98815516c77SSepherosa Ziehau 98915516c77SSepherosa Ziehau /* 99015516c77SSepherosa Ziehau * Reenable the RSS w/ the updated RSS key or indirect 99115516c77SSepherosa Ziehau * table. 99215516c77SSepherosa Ziehau */ 99315516c77SSepherosa Ziehau if (bootverbose) 99415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "reconfig RSS\n"); 99515516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 99615516c77SSepherosa Ziehau if (error) { 99715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS reconfig failed\n"); 99815516c77SSepherosa Ziehau return (error); 99915516c77SSepherosa Ziehau } 100015516c77SSepherosa Ziehau return (0); 100115516c77SSepherosa Ziehau } 100234d68912SSepherosa Ziehau #endif /* !RSS */ 100315516c77SSepherosa Ziehau 100415516c77SSepherosa Ziehau static void 1005afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc) 100615516c77SSepherosa Ziehau { 100715516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 1008afd4971bSSepherosa Ziehau int i, nchan; 100915516c77SSepherosa Ziehau 1010afd4971bSSepherosa Ziehau nchan = sc->hn_rx_ring_inuse; 101115516c77SSepherosa Ziehau KASSERT(nchan > 1, ("invalid # of channels %d", nchan)); 101215516c77SSepherosa Ziehau 101315516c77SSepherosa Ziehau /* 101415516c77SSepherosa Ziehau * Check indirect table to make sure that all channels in it 101515516c77SSepherosa Ziehau * can be used. 101615516c77SSepherosa Ziehau */ 101715516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 101815516c77SSepherosa Ziehau if (rss->rss_ind[i] >= nchan) { 101915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, 102015516c77SSepherosa Ziehau "RSS indirect table %d fixup: %u -> %d\n", 102115516c77SSepherosa Ziehau i, rss->rss_ind[i], nchan - 1); 102215516c77SSepherosa Ziehau rss->rss_ind[i] = nchan - 1; 102315516c77SSepherosa Ziehau } 102415516c77SSepherosa Ziehau } 102515516c77SSepherosa Ziehau } 102615516c77SSepherosa Ziehau 102715516c77SSepherosa Ziehau static int 102815516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused) 102915516c77SSepherosa Ziehau { 103015516c77SSepherosa Ziehau 103115516c77SSepherosa Ziehau return EOPNOTSUPP; 103215516c77SSepherosa Ziehau } 103315516c77SSepherosa Ziehau 103415516c77SSepherosa Ziehau static void 103515516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 103615516c77SSepherosa Ziehau { 103715516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 103815516c77SSepherosa Ziehau 103915516c77SSepherosa Ziehau ifmr->ifm_status = IFM_AVALID; 104015516c77SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 104115516c77SSepherosa Ziehau 104215516c77SSepherosa Ziehau if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) { 104315516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_NONE; 104415516c77SSepherosa Ziehau return; 104515516c77SSepherosa Ziehau } 104615516c77SSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 104715516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 104815516c77SSepherosa Ziehau } 104915516c77SSepherosa Ziehau 10505bdfd3fdSDexuan Cui static void 1051962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused) 10525bdfd3fdSDexuan Cui { 1053962f0357SSepherosa Ziehau struct hn_rxvf_setarg *arg = xarg; 10545bdfd3fdSDexuan Cui 1055962f0357SSepherosa Ziehau arg->rxr->hn_rxvf_ifp = arg->vf_ifp; 10565bdfd3fdSDexuan Cui } 10575bdfd3fdSDexuan Cui 10585bdfd3fdSDexuan Cui static void 1059962f0357SSepherosa Ziehau hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp) 10605bdfd3fdSDexuan Cui { 10615bdfd3fdSDexuan Cui struct hn_rx_ring *rxr; 1062962f0357SSepherosa Ziehau struct hn_rxvf_setarg arg; 10635bdfd3fdSDexuan Cui struct task task; 10645bdfd3fdSDexuan Cui int i; 10655bdfd3fdSDexuan Cui 10665bdfd3fdSDexuan Cui HN_LOCK_ASSERT(sc); 10675bdfd3fdSDexuan Cui 1068962f0357SSepherosa Ziehau TASK_INIT(&task, 0, hn_rxvf_set_task, &arg); 10695bdfd3fdSDexuan Cui 10705bdfd3fdSDexuan Cui for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 10715bdfd3fdSDexuan Cui rxr = &sc->hn_rx_ring[i]; 10725bdfd3fdSDexuan Cui 10735bdfd3fdSDexuan Cui if (i < sc->hn_rx_ring_inuse) { 1074962f0357SSepherosa Ziehau arg.rxr = rxr; 1075962f0357SSepherosa Ziehau arg.vf_ifp = vf_ifp; 10765bdfd3fdSDexuan Cui vmbus_chan_run_task(rxr->hn_chan, &task); 10775bdfd3fdSDexuan Cui } else { 1078962f0357SSepherosa Ziehau rxr->hn_rxvf_ifp = vf_ifp; 10795bdfd3fdSDexuan Cui } 10805bdfd3fdSDexuan Cui } 10815bdfd3fdSDexuan Cui } 10825bdfd3fdSDexuan Cui 1083962f0357SSepherosa Ziehau static bool 1084499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp) 1085499c3e17SSepherosa Ziehau { 1086499c3e17SSepherosa Ziehau const struct ifnet *hn_ifp; 1087499c3e17SSepherosa Ziehau 1088499c3e17SSepherosa Ziehau hn_ifp = sc->hn_ifp; 1089499c3e17SSepherosa Ziehau 1090499c3e17SSepherosa Ziehau if (ifp == hn_ifp) 1091499c3e17SSepherosa Ziehau return (false); 1092499c3e17SSepherosa Ziehau 1093499c3e17SSepherosa Ziehau if (ifp->if_alloctype != IFT_ETHER) 1094499c3e17SSepherosa Ziehau return (false); 1095499c3e17SSepherosa Ziehau 1096499c3e17SSepherosa Ziehau /* Ignore lagg/vlan interfaces */ 1097499c3e17SSepherosa Ziehau if (strcmp(ifp->if_dname, "lagg") == 0 || 1098499c3e17SSepherosa Ziehau strcmp(ifp->if_dname, "vlan") == 0) 1099499c3e17SSepherosa Ziehau return (false); 1100499c3e17SSepherosa Ziehau 1101499c3e17SSepherosa Ziehau if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0) 1102499c3e17SSepherosa Ziehau return (false); 1103499c3e17SSepherosa Ziehau 1104499c3e17SSepherosa Ziehau return (true); 1105499c3e17SSepherosa Ziehau } 1106499c3e17SSepherosa Ziehau 11075bdfd3fdSDexuan Cui static void 1108962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf) 11095bdfd3fdSDexuan Cui { 11105bdfd3fdSDexuan Cui struct ifnet *hn_ifp; 11115bdfd3fdSDexuan Cui 11125bdfd3fdSDexuan Cui HN_LOCK(sc); 11135bdfd3fdSDexuan Cui 11145bdfd3fdSDexuan Cui if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 11155bdfd3fdSDexuan Cui goto out; 11165bdfd3fdSDexuan Cui 1117499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1118499c3e17SSepherosa Ziehau goto out; 11195bdfd3fdSDexuan Cui hn_ifp = sc->hn_ifp; 11205bdfd3fdSDexuan Cui 1121962f0357SSepherosa Ziehau if (rxvf) { 1122962f0357SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_RXVF) 11235bdfd3fdSDexuan Cui goto out; 11245bdfd3fdSDexuan Cui 1125962f0357SSepherosa Ziehau sc->hn_flags |= HN_FLAG_RXVF; 11265bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 11275bdfd3fdSDexuan Cui } else { 1128962f0357SSepherosa Ziehau if (!(sc->hn_flags & HN_FLAG_RXVF)) 11295bdfd3fdSDexuan Cui goto out; 11305bdfd3fdSDexuan Cui 1131962f0357SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_RXVF; 1132499c3e17SSepherosa Ziehau if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 11335bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 11345bdfd3fdSDexuan Cui else 11355bdfd3fdSDexuan Cui hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE); 11365bdfd3fdSDexuan Cui } 11375bdfd3fdSDexuan Cui 11385bdfd3fdSDexuan Cui hn_nvs_set_datapath(sc, 11399c6cae24SSepherosa Ziehau rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH); 11405bdfd3fdSDexuan Cui 1141962f0357SSepherosa Ziehau hn_rxvf_set(sc, rxvf ? ifp : NULL); 11425bdfd3fdSDexuan Cui 1143962f0357SSepherosa Ziehau if (rxvf) { 1144642ec226SSepherosa Ziehau hn_vf_rss_fixup(sc, true); 11455bdfd3fdSDexuan Cui hn_suspend_mgmt(sc); 11465bdfd3fdSDexuan Cui sc->hn_link_flags &= 11475bdfd3fdSDexuan Cui ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG); 1148499c3e17SSepherosa Ziehau if_link_state_change(hn_ifp, LINK_STATE_DOWN); 11495bdfd3fdSDexuan Cui } else { 1150642ec226SSepherosa Ziehau hn_vf_rss_restore(sc); 11515bdfd3fdSDexuan Cui hn_resume_mgmt(sc); 11525bdfd3fdSDexuan Cui } 11535bdfd3fdSDexuan Cui 1154962f0357SSepherosa Ziehau devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname, 1155962f0357SSepherosa Ziehau rxvf ? "VF_UP" : "VF_DOWN", NULL); 115633408a34SDexuan Cui 1157962f0357SSepherosa Ziehau if (bootverbose) { 1158962f0357SSepherosa Ziehau if_printf(hn_ifp, "datapath is switched %s %s\n", 1159962f0357SSepherosa Ziehau rxvf ? "to" : "from", ifp->if_xname); 1160962f0357SSepherosa Ziehau } 11615bdfd3fdSDexuan Cui out: 11625bdfd3fdSDexuan Cui HN_UNLOCK(sc); 11635bdfd3fdSDexuan Cui } 11645bdfd3fdSDexuan Cui 11655bdfd3fdSDexuan Cui static void 11665bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event) 11675bdfd3fdSDexuan Cui { 1168962f0357SSepherosa Ziehau 11695bdfd3fdSDexuan Cui if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN) 11705bdfd3fdSDexuan Cui return; 1171962f0357SSepherosa Ziehau hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP); 11725bdfd3fdSDexuan Cui } 11735bdfd3fdSDexuan Cui 11745bdfd3fdSDexuan Cui static void 11755bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp) 11765bdfd3fdSDexuan Cui { 1177962f0357SSepherosa Ziehau 1178962f0357SSepherosa Ziehau hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP); 11795bdfd3fdSDexuan Cui } 11805bdfd3fdSDexuan Cui 11819c6cae24SSepherosa Ziehau static int 11829c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr) 11839c6cae24SSepherosa Ziehau { 11849c6cae24SSepherosa Ziehau struct ifnet *ifp, *vf_ifp; 11859c6cae24SSepherosa Ziehau uint64_t tmp; 11869c6cae24SSepherosa Ziehau int error; 11879c6cae24SSepherosa Ziehau 11889c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 11899c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 11909c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 11919c6cae24SSepherosa Ziehau 11929c6cae24SSepherosa Ziehau /* 11939c6cae24SSepherosa Ziehau * Fix up requested capabilities w/ supported capabilities, 11949c6cae24SSepherosa Ziehau * since the supported capabilities could have been changed. 11959c6cae24SSepherosa Ziehau */ 11969c6cae24SSepherosa Ziehau ifr->ifr_reqcap &= ifp->if_capabilities; 11979c6cae24SSepherosa Ziehau /* Pass SIOCSIFCAP to VF. */ 11989c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr); 11999c6cae24SSepherosa Ziehau 12009c6cae24SSepherosa Ziehau /* 12019c6cae24SSepherosa Ziehau * NOTE: 12029c6cae24SSepherosa Ziehau * The error will be propagated to the callers, however, it 12039c6cae24SSepherosa Ziehau * is _not_ useful here. 12049c6cae24SSepherosa Ziehau */ 12059c6cae24SSepherosa Ziehau 12069c6cae24SSepherosa Ziehau /* 12079c6cae24SSepherosa Ziehau * Merge VF's enabled capabilities. 12089c6cae24SSepherosa Ziehau */ 12099c6cae24SSepherosa Ziehau ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities; 12109c6cae24SSepherosa Ziehau 12119c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc); 12129c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 12139c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12149c6cae24SSepherosa Ziehau else 12159c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12169c6cae24SSepherosa Ziehau 12179c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc); 12189c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 12199c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12209c6cae24SSepherosa Ziehau else 12219c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12229c6cae24SSepherosa Ziehau 12239c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & CSUM_IP_TSO; 12249c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 12259c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12269c6cae24SSepherosa Ziehau else 12279c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12289c6cae24SSepherosa Ziehau 12299c6cae24SSepherosa Ziehau tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO; 12309c6cae24SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 12319c6cae24SSepherosa Ziehau ifp->if_hwassist |= tmp; 12329c6cae24SSepherosa Ziehau else 12339c6cae24SSepherosa Ziehau ifp->if_hwassist &= ~tmp; 12349c6cae24SSepherosa Ziehau 12359c6cae24SSepherosa Ziehau return (error); 12369c6cae24SSepherosa Ziehau } 12379c6cae24SSepherosa Ziehau 12389c6cae24SSepherosa Ziehau static int 12399c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc) 12409c6cae24SSepherosa Ziehau { 12419c6cae24SSepherosa Ziehau struct ifnet *vf_ifp; 12429c6cae24SSepherosa Ziehau struct ifreq ifr; 12439c6cae24SSepherosa Ziehau 12449c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 12459c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 12469c6cae24SSepherosa Ziehau 12479c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 12489c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 12499c6cae24SSepherosa Ziehau ifr.ifr_flags = vf_ifp->if_flags & 0xffff; 12509c6cae24SSepherosa Ziehau ifr.ifr_flagshigh = vf_ifp->if_flags >> 16; 12519c6cae24SSepherosa Ziehau return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr)); 12529c6cae24SSepherosa Ziehau } 12539c6cae24SSepherosa Ziehau 12549c6cae24SSepherosa Ziehau static void 12559c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc) 12569c6cae24SSepherosa Ziehau { 12579c6cae24SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 12589c6cae24SSepherosa Ziehau int allmulti = 0; 12599c6cae24SSepherosa Ziehau 12609c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 12619c6cae24SSepherosa Ziehau 12629c6cae24SSepherosa Ziehau /* XXX vlan(4) style mcast addr maintenance */ 12639c6cae24SSepherosa Ziehau if (!TAILQ_EMPTY(&ifp->if_multiaddrs)) 12649c6cae24SSepherosa Ziehau allmulti = IFF_ALLMULTI; 12659c6cae24SSepherosa Ziehau 12669c6cae24SSepherosa Ziehau /* Always set the VF's if_flags */ 12679c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti; 12689c6cae24SSepherosa Ziehau } 12699c6cae24SSepherosa Ziehau 12709c6cae24SSepherosa Ziehau static void 12719c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m) 12729c6cae24SSepherosa Ziehau { 12739c6cae24SSepherosa Ziehau struct rm_priotracker pt; 12749c6cae24SSepherosa Ziehau struct ifnet *hn_ifp = NULL; 12759c6cae24SSepherosa Ziehau struct mbuf *mn; 12769c6cae24SSepherosa Ziehau 12779c6cae24SSepherosa Ziehau /* 12789c6cae24SSepherosa Ziehau * XXX racy, if hn(4) ever detached. 12799c6cae24SSepherosa Ziehau */ 12809c6cae24SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 12819c6cae24SSepherosa Ziehau if (vf_ifp->if_index < hn_vfmap_size) 12829c6cae24SSepherosa Ziehau hn_ifp = hn_vfmap[vf_ifp->if_index]; 12839c6cae24SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 12849c6cae24SSepherosa Ziehau 12859c6cae24SSepherosa Ziehau if (hn_ifp != NULL) { 12869c6cae24SSepherosa Ziehau for (mn = m; mn != NULL; mn = mn->m_nextpkt) { 12873bed4e54SSepherosa Ziehau /* 12883bed4e54SSepherosa Ziehau * Allow tapping on the VF. 12893bed4e54SSepherosa Ziehau */ 12909c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(vf_ifp, mn); 12913bed4e54SSepherosa Ziehau 12923bed4e54SSepherosa Ziehau /* 12933bed4e54SSepherosa Ziehau * Update VF stats. 12943bed4e54SSepherosa Ziehau */ 12953bed4e54SSepherosa Ziehau if ((vf_ifp->if_capenable & IFCAP_HWSTATS) == 0) { 12963bed4e54SSepherosa Ziehau if_inc_counter(vf_ifp, IFCOUNTER_IBYTES, 12973bed4e54SSepherosa Ziehau mn->m_pkthdr.len); 12983bed4e54SSepherosa Ziehau } 12993bed4e54SSepherosa Ziehau /* 13003bed4e54SSepherosa Ziehau * XXX IFCOUNTER_IMCAST 13013bed4e54SSepherosa Ziehau * This stat updating is kinda invasive, since it 13023bed4e54SSepherosa Ziehau * requires two checks on the mbuf: the length check 13033bed4e54SSepherosa Ziehau * and the ethernet header check. As of this write, 13043bed4e54SSepherosa Ziehau * all multicast packets go directly to hn(4), which 13053bed4e54SSepherosa Ziehau * makes imcast stat updating in the VF a try in vian. 13063bed4e54SSepherosa Ziehau */ 13073bed4e54SSepherosa Ziehau 13083bed4e54SSepherosa Ziehau /* 13093bed4e54SSepherosa Ziehau * Fix up rcvif and increase hn(4)'s ipackets. 13103bed4e54SSepherosa Ziehau */ 13119c6cae24SSepherosa Ziehau mn->m_pkthdr.rcvif = hn_ifp; 13129c6cae24SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1); 13139c6cae24SSepherosa Ziehau } 13143bed4e54SSepherosa Ziehau /* 13153bed4e54SSepherosa Ziehau * Go through hn(4)'s if_input. 13163bed4e54SSepherosa Ziehau */ 13179c6cae24SSepherosa Ziehau hn_ifp->if_input(hn_ifp, m); 13189c6cae24SSepherosa Ziehau } else { 13199c6cae24SSepherosa Ziehau /* 13209c6cae24SSepherosa Ziehau * In the middle of the transition; free this 13219c6cae24SSepherosa Ziehau * mbuf chain. 13229c6cae24SSepherosa Ziehau */ 13239c6cae24SSepherosa Ziehau while (m != NULL) { 13249c6cae24SSepherosa Ziehau mn = m->m_nextpkt; 13259c6cae24SSepherosa Ziehau m->m_nextpkt = NULL; 13269c6cae24SSepherosa Ziehau m_freem(m); 13279c6cae24SSepherosa Ziehau m = mn; 13289c6cae24SSepherosa Ziehau } 13299c6cae24SSepherosa Ziehau } 13309c6cae24SSepherosa Ziehau } 13319c6cae24SSepherosa Ziehau 13329c6cae24SSepherosa Ziehau static void 13339c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc) 13349c6cae24SSepherosa Ziehau { 13359c6cae24SSepherosa Ziehau struct ifnet *ifp; 13369c6cae24SSepherosa Ziehau 13379c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 13389c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 13399c6cae24SSepherosa Ziehau 13409c6cae24SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu); 13419c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099 13429c6cae24SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp)) 13439c6cae24SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp)); 13449c6cae24SSepherosa Ziehau #endif 13459c6cae24SSepherosa Ziehau } 13469c6cae24SSepherosa Ziehau 1347642ec226SSepherosa Ziehau static uint32_t 1348642ec226SSepherosa Ziehau hn_rss_type_fromndis(uint32_t rss_hash) 1349642ec226SSepherosa Ziehau { 1350642ec226SSepherosa Ziehau uint32_t types = 0; 1351642ec226SSepherosa Ziehau 1352642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_IPV4) 1353642ec226SSepherosa Ziehau types |= RSS_TYPE_IPV4; 1354642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_TCP_IPV4) 1355642ec226SSepherosa Ziehau types |= RSS_TYPE_TCP_IPV4; 1356642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_IPV6) 1357642ec226SSepherosa Ziehau types |= RSS_TYPE_IPV6; 1358642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_IPV6_EX) 1359642ec226SSepherosa Ziehau types |= RSS_TYPE_IPV6_EX; 1360642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_TCP_IPV6) 1361642ec226SSepherosa Ziehau types |= RSS_TYPE_TCP_IPV6; 1362642ec226SSepherosa Ziehau if (rss_hash & NDIS_HASH_TCP_IPV6_EX) 1363642ec226SSepherosa Ziehau types |= RSS_TYPE_TCP_IPV6_EX; 1364642ec226SSepherosa Ziehau return (types); 1365642ec226SSepherosa Ziehau } 1366642ec226SSepherosa Ziehau 1367642ec226SSepherosa Ziehau static uint32_t 1368642ec226SSepherosa Ziehau hn_rss_type_tondis(uint32_t types) 1369642ec226SSepherosa Ziehau { 1370642ec226SSepherosa Ziehau uint32_t rss_hash = 0; 1371642ec226SSepherosa Ziehau 1372642ec226SSepherosa Ziehau KASSERT((types & 1373642ec226SSepherosa Ziehau (RSS_TYPE_UDP_IPV4 | RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0, 1374642ec226SSepherosa Ziehau ("UDP4, UDP6 and UDP6EX are not supported")); 1375642ec226SSepherosa Ziehau 1376642ec226SSepherosa Ziehau if (types & RSS_TYPE_IPV4) 1377642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_IPV4; 1378642ec226SSepherosa Ziehau if (types & RSS_TYPE_TCP_IPV4) 1379642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_TCP_IPV4; 1380642ec226SSepherosa Ziehau if (types & RSS_TYPE_IPV6) 1381642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_IPV6; 1382642ec226SSepherosa Ziehau if (types & RSS_TYPE_IPV6_EX) 1383642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_IPV6_EX; 1384642ec226SSepherosa Ziehau if (types & RSS_TYPE_TCP_IPV6) 1385642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_TCP_IPV6; 1386642ec226SSepherosa Ziehau if (types & RSS_TYPE_TCP_IPV6_EX) 1387642ec226SSepherosa Ziehau rss_hash |= NDIS_HASH_TCP_IPV6_EX; 1388642ec226SSepherosa Ziehau return (rss_hash); 1389642ec226SSepherosa Ziehau } 1390642ec226SSepherosa Ziehau 1391642ec226SSepherosa Ziehau static void 1392642ec226SSepherosa Ziehau hn_rss_mbuf_hash(struct hn_softc *sc, uint32_t mbuf_hash) 1393642ec226SSepherosa Ziehau { 1394642ec226SSepherosa Ziehau int i; 1395642ec226SSepherosa Ziehau 1396642ec226SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1397642ec226SSepherosa Ziehau 1398642ec226SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 1399642ec226SSepherosa Ziehau sc->hn_rx_ring[i].hn_mbuf_hash = mbuf_hash; 1400642ec226SSepherosa Ziehau } 1401642ec226SSepherosa Ziehau 1402642ec226SSepherosa Ziehau static void 1403642ec226SSepherosa Ziehau hn_vf_rss_fixup(struct hn_softc *sc, bool reconf) 1404642ec226SSepherosa Ziehau { 1405642ec226SSepherosa Ziehau struct ifnet *ifp, *vf_ifp; 1406642ec226SSepherosa Ziehau struct ifrsshash ifrh; 1407642ec226SSepherosa Ziehau struct ifrsskey ifrk; 1408642ec226SSepherosa Ziehau int error; 1409642ec226SSepherosa Ziehau uint32_t my_types, diff_types, mbuf_types = 0; 1410642ec226SSepherosa Ziehau 1411642ec226SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1412642ec226SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 1413642ec226SSepherosa Ziehau ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname)); 1414642ec226SSepherosa Ziehau 1415642ec226SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 1416642ec226SSepherosa Ziehau /* No RSS on synthetic parts; done. */ 1417642ec226SSepherosa Ziehau return; 1418642ec226SSepherosa Ziehau } 1419642ec226SSepherosa Ziehau if ((sc->hn_rss_hcap & NDIS_HASH_FUNCTION_TOEPLITZ) == 0) { 1420642ec226SSepherosa Ziehau /* Synthetic parts do not support Toeplitz; done. */ 1421642ec226SSepherosa Ziehau return; 1422642ec226SSepherosa Ziehau } 1423642ec226SSepherosa Ziehau 1424642ec226SSepherosa Ziehau ifp = sc->hn_ifp; 1425642ec226SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 1426642ec226SSepherosa Ziehau 1427642ec226SSepherosa Ziehau /* 1428642ec226SSepherosa Ziehau * Extract VF's RSS key. Only 40 bytes key for Toeplitz is 1429642ec226SSepherosa Ziehau * supported. 1430642ec226SSepherosa Ziehau */ 1431642ec226SSepherosa Ziehau memset(&ifrk, 0, sizeof(ifrk)); 1432642ec226SSepherosa Ziehau strlcpy(ifrk.ifrk_name, vf_ifp->if_xname, sizeof(ifrk.ifrk_name)); 1433642ec226SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSKEY, (caddr_t)&ifrk); 1434642ec226SSepherosa Ziehau if (error) { 1435642ec226SSepherosa Ziehau if_printf(ifp, "%s SIOCGRSSKEY failed: %d\n", 1436642ec226SSepherosa Ziehau vf_ifp->if_xname, error); 1437642ec226SSepherosa Ziehau goto done; 1438642ec226SSepherosa Ziehau } 1439642ec226SSepherosa Ziehau if (ifrk.ifrk_func != RSS_FUNC_TOEPLITZ) { 1440642ec226SSepherosa Ziehau if_printf(ifp, "%s RSS function %u is not Toeplitz\n", 1441642ec226SSepherosa Ziehau vf_ifp->if_xname, ifrk.ifrk_func); 1442642ec226SSepherosa Ziehau goto done; 1443642ec226SSepherosa Ziehau } 1444642ec226SSepherosa Ziehau if (ifrk.ifrk_keylen != NDIS_HASH_KEYSIZE_TOEPLITZ) { 1445642ec226SSepherosa Ziehau if_printf(ifp, "%s invalid RSS Toeplitz key length %d\n", 1446642ec226SSepherosa Ziehau vf_ifp->if_xname, ifrk.ifrk_keylen); 1447642ec226SSepherosa Ziehau goto done; 1448642ec226SSepherosa Ziehau } 1449642ec226SSepherosa Ziehau 1450642ec226SSepherosa Ziehau /* 1451642ec226SSepherosa Ziehau * Extract VF's RSS hash. Only Toeplitz is supported. 1452642ec226SSepherosa Ziehau */ 1453642ec226SSepherosa Ziehau memset(&ifrh, 0, sizeof(ifrh)); 1454642ec226SSepherosa Ziehau strlcpy(ifrh.ifrh_name, vf_ifp->if_xname, sizeof(ifrh.ifrh_name)); 1455642ec226SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSHASH, (caddr_t)&ifrh); 1456642ec226SSepherosa Ziehau if (error) { 1457642ec226SSepherosa Ziehau if_printf(ifp, "%s SIOCGRSSHASH failed: %d\n", 1458642ec226SSepherosa Ziehau vf_ifp->if_xname, error); 1459642ec226SSepherosa Ziehau goto done; 1460642ec226SSepherosa Ziehau } 1461642ec226SSepherosa Ziehau if (ifrh.ifrh_func != RSS_FUNC_TOEPLITZ) { 1462642ec226SSepherosa Ziehau if_printf(ifp, "%s RSS function %u is not Toeplitz\n", 1463642ec226SSepherosa Ziehau vf_ifp->if_xname, ifrh.ifrh_func); 1464642ec226SSepherosa Ziehau goto done; 1465642ec226SSepherosa Ziehau } 1466642ec226SSepherosa Ziehau 1467642ec226SSepherosa Ziehau my_types = hn_rss_type_fromndis(sc->hn_rss_hcap); 1468642ec226SSepherosa Ziehau if ((ifrh.ifrh_types & my_types) == 0) { 1469642ec226SSepherosa Ziehau /* This disables RSS; ignore it then */ 1470642ec226SSepherosa Ziehau if_printf(ifp, "%s intersection of RSS types failed. " 1471642ec226SSepherosa Ziehau "VF %#x, mine %#x\n", vf_ifp->if_xname, 1472642ec226SSepherosa Ziehau ifrh.ifrh_types, my_types); 1473642ec226SSepherosa Ziehau goto done; 1474642ec226SSepherosa Ziehau } 1475642ec226SSepherosa Ziehau 1476642ec226SSepherosa Ziehau diff_types = my_types ^ ifrh.ifrh_types; 1477642ec226SSepherosa Ziehau my_types &= ifrh.ifrh_types; 1478642ec226SSepherosa Ziehau mbuf_types = my_types; 1479642ec226SSepherosa Ziehau 1480642ec226SSepherosa Ziehau /* 1481642ec226SSepherosa Ziehau * Detect RSS hash value/type confliction. 1482642ec226SSepherosa Ziehau * 1483642ec226SSepherosa Ziehau * NOTE: 1484642ec226SSepherosa Ziehau * We don't disable the hash type, but stop delivery the hash 1485642ec226SSepherosa Ziehau * value/type through mbufs on RX path. 1486642ec226SSepherosa Ziehau */ 1487642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_IPV4) && 1488642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & 1489642ec226SSepherosa Ziehau (RSS_TYPE_TCP_IPV4 | RSS_TYPE_UDP_IPV4))) { 1490642ec226SSepherosa Ziehau /* Conflict; disable IPV4 hash type/value delivery. */ 1491642ec226SSepherosa Ziehau if_printf(ifp, "disable IPV4 mbuf hash delivery\n"); 1492642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_IPV4; 1493642ec226SSepherosa Ziehau } 1494642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_IPV6) && 1495642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & 1496642ec226SSepherosa Ziehau (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 | 1497642ec226SSepherosa Ziehau RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX | 1498642ec226SSepherosa Ziehau RSS_TYPE_IPV6_EX))) { 1499642ec226SSepherosa Ziehau /* Conflict; disable IPV6 hash type/value delivery. */ 1500642ec226SSepherosa Ziehau if_printf(ifp, "disable IPV6 mbuf hash delivery\n"); 1501642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_IPV6; 1502642ec226SSepherosa Ziehau } 1503642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_IPV6_EX) && 1504642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & 1505642ec226SSepherosa Ziehau (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 | 1506642ec226SSepherosa Ziehau RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX | 1507642ec226SSepherosa Ziehau RSS_TYPE_IPV6))) { 1508642ec226SSepherosa Ziehau /* Conflict; disable IPV6_EX hash type/value delivery. */ 1509642ec226SSepherosa Ziehau if_printf(ifp, "disable IPV6_EX mbuf hash delivery\n"); 1510642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_IPV6_EX; 1511642ec226SSepherosa Ziehau } 1512642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_TCP_IPV6) && 1513642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6_EX)) { 1514642ec226SSepherosa Ziehau /* Conflict; disable TCP_IPV6 hash type/value delivery. */ 1515642ec226SSepherosa Ziehau if_printf(ifp, "disable TCP_IPV6 mbuf hash delivery\n"); 1516642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_TCP_IPV6; 1517642ec226SSepherosa Ziehau } 1518642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_TCP_IPV6_EX) && 1519642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6)) { 1520642ec226SSepherosa Ziehau /* Conflict; disable TCP_IPV6_EX hash type/value delivery. */ 1521642ec226SSepherosa Ziehau if_printf(ifp, "disable TCP_IPV6_EX mbuf hash delivery\n"); 1522642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_TCP_IPV6_EX; 1523642ec226SSepherosa Ziehau } 1524642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_UDP_IPV6) && 1525642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6_EX)) { 1526642ec226SSepherosa Ziehau /* Conflict; disable UDP_IPV6 hash type/value delivery. */ 1527642ec226SSepherosa Ziehau if_printf(ifp, "disable UDP_IPV6 mbuf hash delivery\n"); 1528642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_UDP_IPV6; 1529642ec226SSepherosa Ziehau } 1530642ec226SSepherosa Ziehau if ((my_types & RSS_TYPE_UDP_IPV6_EX) && 1531642ec226SSepherosa Ziehau (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6)) { 1532642ec226SSepherosa Ziehau /* Conflict; disable UDP_IPV6_EX hash type/value delivery. */ 1533642ec226SSepherosa Ziehau if_printf(ifp, "disable UDP_IPV6_EX mbuf hash delivery\n"); 1534642ec226SSepherosa Ziehau mbuf_types &= ~RSS_TYPE_UDP_IPV6_EX; 1535642ec226SSepherosa Ziehau } 1536642ec226SSepherosa Ziehau 1537642ec226SSepherosa Ziehau /* 1538642ec226SSepherosa Ziehau * Indirect table does not matter. 1539642ec226SSepherosa Ziehau */ 1540642ec226SSepherosa Ziehau 1541642ec226SSepherosa Ziehau sc->hn_rss_hash = (sc->hn_rss_hcap & NDIS_HASH_FUNCTION_MASK) | 1542642ec226SSepherosa Ziehau hn_rss_type_tondis(my_types); 1543642ec226SSepherosa Ziehau memcpy(sc->hn_rss.rss_key, ifrk.ifrk_key, sizeof(sc->hn_rss.rss_key)); 1544642ec226SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 1545642ec226SSepherosa Ziehau 1546642ec226SSepherosa Ziehau if (reconf) { 1547642ec226SSepherosa Ziehau error = hn_rss_reconfig(sc); 1548642ec226SSepherosa Ziehau if (error) { 1549642ec226SSepherosa Ziehau /* XXX roll-back? */ 1550642ec226SSepherosa Ziehau if_printf(ifp, "hn_rss_reconfig failed: %d\n", error); 1551642ec226SSepherosa Ziehau /* XXX keep going. */ 1552642ec226SSepherosa Ziehau } 1553642ec226SSepherosa Ziehau } 1554642ec226SSepherosa Ziehau done: 1555642ec226SSepherosa Ziehau /* Hash deliverability for mbufs. */ 1556642ec226SSepherosa Ziehau hn_rss_mbuf_hash(sc, hn_rss_type_tondis(mbuf_types)); 1557642ec226SSepherosa Ziehau } 1558642ec226SSepherosa Ziehau 1559642ec226SSepherosa Ziehau static void 1560642ec226SSepherosa Ziehau hn_vf_rss_restore(struct hn_softc *sc) 1561642ec226SSepherosa Ziehau { 1562642ec226SSepherosa Ziehau 1563642ec226SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1564642ec226SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 1565642ec226SSepherosa Ziehau ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname)); 1566642ec226SSepherosa Ziehau 1567642ec226SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) 1568642ec226SSepherosa Ziehau goto done; 1569642ec226SSepherosa Ziehau 1570642ec226SSepherosa Ziehau /* 1571642ec226SSepherosa Ziehau * Restore hash types. Key does _not_ matter. 1572642ec226SSepherosa Ziehau */ 1573642ec226SSepherosa Ziehau if (sc->hn_rss_hash != sc->hn_rss_hcap) { 1574642ec226SSepherosa Ziehau int error; 1575642ec226SSepherosa Ziehau 1576642ec226SSepherosa Ziehau sc->hn_rss_hash = sc->hn_rss_hcap; 1577642ec226SSepherosa Ziehau error = hn_rss_reconfig(sc); 1578642ec226SSepherosa Ziehau if (error) { 1579642ec226SSepherosa Ziehau if_printf(sc->hn_ifp, "hn_rss_reconfig failed: %d\n", 1580642ec226SSepherosa Ziehau error); 1581642ec226SSepherosa Ziehau /* XXX keep going. */ 1582642ec226SSepherosa Ziehau } 1583642ec226SSepherosa Ziehau } 1584642ec226SSepherosa Ziehau done: 1585642ec226SSepherosa Ziehau /* Hash deliverability for mbufs. */ 1586642ec226SSepherosa Ziehau hn_rss_mbuf_hash(sc, NDIS_HASH_ALL); 1587642ec226SSepherosa Ziehau } 1588642ec226SSepherosa Ziehau 15899c6cae24SSepherosa Ziehau static void 15909c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc) 15919c6cae24SSepherosa Ziehau { 15929c6cae24SSepherosa Ziehau struct ifnet *ifp, *vf_ifp; 15939c6cae24SSepherosa Ziehau struct ifreq ifr; 15949c6cae24SSepherosa Ziehau 15959c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 15969c6cae24SSepherosa Ziehau ifp = sc->hn_ifp; 15979c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 15989c6cae24SSepherosa Ziehau 15999c6cae24SSepherosa Ziehau /* 16009c6cae24SSepherosa Ziehau * Mark the VF ready. 16019c6cae24SSepherosa Ziehau */ 16029c6cae24SSepherosa Ziehau sc->hn_vf_rdytick = 0; 16039c6cae24SSepherosa Ziehau 16049c6cae24SSepherosa Ziehau /* 16059c6cae24SSepherosa Ziehau * Save information for restoration. 16069c6cae24SSepherosa Ziehau */ 16079c6cae24SSepherosa Ziehau sc->hn_saved_caps = ifp->if_capabilities; 16089c6cae24SSepherosa Ziehau sc->hn_saved_tsomax = ifp->if_hw_tsomax; 16099c6cae24SSepherosa Ziehau sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount; 16109c6cae24SSepherosa Ziehau sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize; 16119c6cae24SSepherosa Ziehau 16129c6cae24SSepherosa Ziehau /* 16139c6cae24SSepherosa Ziehau * Intersect supported/enabled capabilities. 16149c6cae24SSepherosa Ziehau * 16159c6cae24SSepherosa Ziehau * NOTE: 16169c6cae24SSepherosa Ziehau * if_hwassist is not changed here. 16179c6cae24SSepherosa Ziehau */ 16189c6cae24SSepherosa Ziehau ifp->if_capabilities &= vf_ifp->if_capabilities; 16199c6cae24SSepherosa Ziehau ifp->if_capenable &= ifp->if_capabilities; 16209c6cae24SSepherosa Ziehau 16219c6cae24SSepherosa Ziehau /* 16229c6cae24SSepherosa Ziehau * Fix TSO settings. 16239c6cae24SSepherosa Ziehau */ 16249c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax) 16259c6cae24SSepherosa Ziehau ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax; 16269c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount) 16279c6cae24SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount; 16289c6cae24SSepherosa Ziehau if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize) 16299c6cae24SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize; 16309c6cae24SSepherosa Ziehau 16319c6cae24SSepherosa Ziehau /* 16329c6cae24SSepherosa Ziehau * Change VF's enabled capabilities. 16339c6cae24SSepherosa Ziehau */ 16349c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 16359c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 16369c6cae24SSepherosa Ziehau ifr.ifr_reqcap = ifp->if_capenable; 16379c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(sc, &ifr); 16389c6cae24SSepherosa Ziehau 16399c6cae24SSepherosa Ziehau if (ifp->if_mtu != ETHERMTU) { 16409c6cae24SSepherosa Ziehau int error; 16419c6cae24SSepherosa Ziehau 16429c6cae24SSepherosa Ziehau /* 16439c6cae24SSepherosa Ziehau * Change VF's MTU. 16449c6cae24SSepherosa Ziehau */ 16459c6cae24SSepherosa Ziehau memset(&ifr, 0, sizeof(ifr)); 16469c6cae24SSepherosa Ziehau strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name)); 16479c6cae24SSepherosa Ziehau ifr.ifr_mtu = ifp->if_mtu; 16489c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr); 16499c6cae24SSepherosa Ziehau if (error) { 16509c6cae24SSepherosa Ziehau if_printf(ifp, "%s SIOCSIFMTU %u failed\n", 16519c6cae24SSepherosa Ziehau vf_ifp->if_xname, ifp->if_mtu); 16529c6cae24SSepherosa Ziehau if (ifp->if_mtu > ETHERMTU) { 16539c6cae24SSepherosa Ziehau if_printf(ifp, "change MTU to %d\n", ETHERMTU); 16549c6cae24SSepherosa Ziehau 16559c6cae24SSepherosa Ziehau /* 16569c6cae24SSepherosa Ziehau * XXX 16579c6cae24SSepherosa Ziehau * No need to adjust the synthetic parts' MTU; 16589c6cae24SSepherosa Ziehau * failure of the adjustment will cause us 16599c6cae24SSepherosa Ziehau * infinite headache. 16609c6cae24SSepherosa Ziehau */ 16619c6cae24SSepherosa Ziehau ifp->if_mtu = ETHERMTU; 16629c6cae24SSepherosa Ziehau hn_mtu_change_fixup(sc); 16639c6cae24SSepherosa Ziehau } 16649c6cae24SSepherosa Ziehau } 16659c6cae24SSepherosa Ziehau } 16669c6cae24SSepherosa Ziehau } 16679c6cae24SSepherosa Ziehau 16689c6cae24SSepherosa Ziehau static bool 16699c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc) 16709c6cae24SSepherosa Ziehau { 16719c6cae24SSepherosa Ziehau 16729c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 16739c6cae24SSepherosa Ziehau 16749c6cae24SSepherosa Ziehau if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL) 16759c6cae24SSepherosa Ziehau return (false); 16769c6cae24SSepherosa Ziehau 16779c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick == 0) 16789c6cae24SSepherosa Ziehau return (true); 16799c6cae24SSepherosa Ziehau 16809c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick > ticks) 16819c6cae24SSepherosa Ziehau return (false); 16829c6cae24SSepherosa Ziehau 16839c6cae24SSepherosa Ziehau /* Mark VF as ready. */ 16849c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(sc); 16859c6cae24SSepherosa Ziehau return (true); 16869c6cae24SSepherosa Ziehau } 16879c6cae24SSepherosa Ziehau 16889c6cae24SSepherosa Ziehau static void 1689a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc) 1690a97fff19SSepherosa Ziehau { 1691a97fff19SSepherosa Ziehau int i; 1692a97fff19SSepherosa Ziehau 1693a97fff19SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1694a97fff19SSepherosa Ziehau 1695a97fff19SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ 1696a97fff19SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 1697a97fff19SSepherosa Ziehau sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED; 1698a97fff19SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 1699a97fff19SSepherosa Ziehau 1700a97fff19SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 1701a97fff19SSepherosa Ziehau sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF; 1702a97fff19SSepherosa Ziehau } 1703a97fff19SSepherosa Ziehau 1704a97fff19SSepherosa Ziehau static void 1705a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf) 1706a97fff19SSepherosa Ziehau { 1707a97fff19SSepherosa Ziehau int i; 1708a97fff19SSepherosa Ziehau 1709a97fff19SSepherosa Ziehau HN_LOCK_ASSERT(sc); 1710a97fff19SSepherosa Ziehau 1711a97fff19SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ 1712a97fff19SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 1713a97fff19SSepherosa Ziehau sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED; 1714a97fff19SSepherosa Ziehau if (clear_vf) 1715a97fff19SSepherosa Ziehau sc->hn_vf_ifp = NULL; 1716a97fff19SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 1717a97fff19SSepherosa Ziehau 1718a97fff19SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 1719a97fff19SSepherosa Ziehau sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF; 1720a97fff19SSepherosa Ziehau } 1721a97fff19SSepherosa Ziehau 1722a97fff19SSepherosa Ziehau static void 17239c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc) 17249c6cae24SSepherosa Ziehau { 17259c6cae24SSepherosa Ziehau int error; 17269c6cae24SSepherosa Ziehau 17279c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 17289c6cae24SSepherosa Ziehau 17299c6cae24SSepherosa Ziehau KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0, 17309c6cae24SSepherosa Ziehau ("%s: transparent VF was enabled", sc->hn_ifp->if_xname)); 17319c6cae24SSepherosa Ziehau 17329c6cae24SSepherosa Ziehau if (bootverbose) { 17339c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "try bringing up %s\n", 17349c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 17359c6cae24SSepherosa Ziehau } 17369c6cae24SSepherosa Ziehau 17379c6cae24SSepherosa Ziehau /* 17389c6cae24SSepherosa Ziehau * Bring the VF up. 17399c6cae24SSepherosa Ziehau */ 17409c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 17419c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags |= IFF_UP; 17429c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 17439c6cae24SSepherosa Ziehau if (error) { 17449c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "bringing up %s failed: %d\n", 17459c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname, error); 17469c6cae24SSepherosa Ziehau return; 17479c6cae24SSepherosa Ziehau } 17489c6cae24SSepherosa Ziehau 17499c6cae24SSepherosa Ziehau /* 17509c6cae24SSepherosa Ziehau * NOTE: 17519c6cae24SSepherosa Ziehau * Datapath setting must happen _after_ bringing the VF up. 17529c6cae24SSepherosa Ziehau */ 17539c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF); 17549c6cae24SSepherosa Ziehau 1755642ec226SSepherosa Ziehau /* 1756642ec226SSepherosa Ziehau * NOTE: 1757642ec226SSepherosa Ziehau * Fixup RSS related bits _after_ the VF is brought up, since 1758642ec226SSepherosa Ziehau * many VFs generate RSS key during it's initialization. 1759642ec226SSepherosa Ziehau */ 1760642ec226SSepherosa Ziehau hn_vf_rss_fixup(sc, true); 1761642ec226SSepherosa Ziehau 1762a97fff19SSepherosa Ziehau /* Mark transparent mode VF as enabled. */ 1763a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(sc); 17649c6cae24SSepherosa Ziehau } 17659c6cae24SSepherosa Ziehau 17669c6cae24SSepherosa Ziehau static void 17679c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused) 17689c6cae24SSepherosa Ziehau { 17699c6cae24SSepherosa Ziehau struct hn_softc *sc = xsc; 17709c6cae24SSepherosa Ziehau 17719c6cae24SSepherosa Ziehau HN_LOCK(sc); 17729c6cae24SSepherosa Ziehau 17739c6cae24SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 17749c6cae24SSepherosa Ziehau goto done; 17759c6cae24SSepherosa Ziehau if (sc->hn_vf_ifp == NULL) 17769c6cae24SSepherosa Ziehau goto done; 17779c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 17789c6cae24SSepherosa Ziehau goto done; 17799c6cae24SSepherosa Ziehau 17809c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick != 0) { 17819c6cae24SSepherosa Ziehau /* Mark VF as ready. */ 17829c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(sc); 17839c6cae24SSepherosa Ziehau } 17849c6cae24SSepherosa Ziehau 17859c6cae24SSepherosa Ziehau if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) { 17869c6cae24SSepherosa Ziehau /* 17879c6cae24SSepherosa Ziehau * Delayed VF initialization. 17889c6cae24SSepherosa Ziehau */ 17899c6cae24SSepherosa Ziehau if (bootverbose) { 17909c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "delayed initialize %s\n", 17919c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 17929c6cae24SSepherosa Ziehau } 17939c6cae24SSepherosa Ziehau hn_xpnt_vf_init(sc); 17949c6cae24SSepherosa Ziehau } 17959c6cae24SSepherosa Ziehau done: 17969c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 17979c6cae24SSepherosa Ziehau } 17989c6cae24SSepherosa Ziehau 1799499c3e17SSepherosa Ziehau static void 1800499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp) 1801499c3e17SSepherosa Ziehau { 1802499c3e17SSepherosa Ziehau struct hn_softc *sc = xsc; 1803499c3e17SSepherosa Ziehau 1804499c3e17SSepherosa Ziehau HN_LOCK(sc); 1805499c3e17SSepherosa Ziehau 1806499c3e17SSepherosa Ziehau if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 1807499c3e17SSepherosa Ziehau goto done; 1808499c3e17SSepherosa Ziehau 1809499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1810499c3e17SSepherosa Ziehau goto done; 1811499c3e17SSepherosa Ziehau 1812499c3e17SSepherosa Ziehau if (sc->hn_vf_ifp != NULL) { 1813499c3e17SSepherosa Ziehau if_printf(sc->hn_ifp, "%s was attached as VF\n", 1814499c3e17SSepherosa Ziehau sc->hn_vf_ifp->if_xname); 1815499c3e17SSepherosa Ziehau goto done; 1816499c3e17SSepherosa Ziehau } 1817499c3e17SSepherosa Ziehau 18189c6cae24SSepherosa Ziehau if (hn_xpnt_vf && ifp->if_start != NULL) { 18199c6cae24SSepherosa Ziehau /* 18209c6cae24SSepherosa Ziehau * ifnet.if_start is _not_ supported by transparent 18219c6cae24SSepherosa Ziehau * mode VF; mainly due to the IFF_DRV_OACTIVE flag. 18229c6cae24SSepherosa Ziehau */ 18239c6cae24SSepherosa Ziehau if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported " 18249c6cae24SSepherosa Ziehau "in transparent VF mode.\n", ifp->if_xname); 18259c6cae24SSepherosa Ziehau goto done; 18269c6cae24SSepherosa Ziehau } 18279c6cae24SSepherosa Ziehau 1828499c3e17SSepherosa Ziehau rm_wlock(&hn_vfmap_lock); 1829499c3e17SSepherosa Ziehau 1830499c3e17SSepherosa Ziehau if (ifp->if_index >= hn_vfmap_size) { 1831499c3e17SSepherosa Ziehau struct ifnet **newmap; 1832499c3e17SSepherosa Ziehau int newsize; 1833499c3e17SSepherosa Ziehau 1834499c3e17SSepherosa Ziehau newsize = ifp->if_index + HN_VFMAP_SIZE_DEF; 1835499c3e17SSepherosa Ziehau newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF, 1836499c3e17SSepherosa Ziehau M_WAITOK | M_ZERO); 1837499c3e17SSepherosa Ziehau 1838499c3e17SSepherosa Ziehau memcpy(newmap, hn_vfmap, 1839499c3e17SSepherosa Ziehau sizeof(struct ifnet *) * hn_vfmap_size); 1840499c3e17SSepherosa Ziehau free(hn_vfmap, M_DEVBUF); 1841499c3e17SSepherosa Ziehau hn_vfmap = newmap; 1842499c3e17SSepherosa Ziehau hn_vfmap_size = newsize; 1843499c3e17SSepherosa Ziehau } 1844499c3e17SSepherosa Ziehau KASSERT(hn_vfmap[ifp->if_index] == NULL, 1845499c3e17SSepherosa Ziehau ("%s: ifindex %d was mapped to %s", 1846499c3e17SSepherosa Ziehau ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname)); 1847499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index] = sc->hn_ifp; 1848499c3e17SSepherosa Ziehau 1849499c3e17SSepherosa Ziehau rm_wunlock(&hn_vfmap_lock); 1850499c3e17SSepherosa Ziehau 18519c6cae24SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */ 18529c6cae24SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 18539c6cae24SSepherosa Ziehau KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0, 18549c6cae24SSepherosa Ziehau ("%s: transparent VF was enabled", sc->hn_ifp->if_xname)); 1855499c3e17SSepherosa Ziehau sc->hn_vf_ifp = ifp; 18569c6cae24SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 18579c6cae24SSepherosa Ziehau 18589c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 18599c6cae24SSepherosa Ziehau int wait_ticks; 18609c6cae24SSepherosa Ziehau 18619c6cae24SSepherosa Ziehau /* 18629c6cae24SSepherosa Ziehau * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp. 18639c6cae24SSepherosa Ziehau * Save vf_ifp's current if_input for later restoration. 18649c6cae24SSepherosa Ziehau */ 18659c6cae24SSepherosa Ziehau sc->hn_vf_input = ifp->if_input; 18669c6cae24SSepherosa Ziehau ifp->if_input = hn_xpnt_vf_input; 18679c6cae24SSepherosa Ziehau 18689c6cae24SSepherosa Ziehau /* 18699c6cae24SSepherosa Ziehau * Stop link status management; use the VF's. 18709c6cae24SSepherosa Ziehau */ 18719c6cae24SSepherosa Ziehau hn_suspend_mgmt(sc); 18729c6cae24SSepherosa Ziehau 18739c6cae24SSepherosa Ziehau /* 18749c6cae24SSepherosa Ziehau * Give VF sometime to complete its attach routing. 18759c6cae24SSepherosa Ziehau */ 18769c6cae24SSepherosa Ziehau wait_ticks = hn_xpnt_vf_attwait * hz; 18779c6cae24SSepherosa Ziehau sc->hn_vf_rdytick = ticks + wait_ticks; 18789c6cae24SSepherosa Ziehau 18799c6cae24SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init, 18809c6cae24SSepherosa Ziehau wait_ticks); 18819c6cae24SSepherosa Ziehau } 1882499c3e17SSepherosa Ziehau done: 1883499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 1884499c3e17SSepherosa Ziehau } 1885499c3e17SSepherosa Ziehau 1886499c3e17SSepherosa Ziehau static void 1887499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp) 1888499c3e17SSepherosa Ziehau { 1889499c3e17SSepherosa Ziehau struct hn_softc *sc = xsc; 1890499c3e17SSepherosa Ziehau 1891499c3e17SSepherosa Ziehau HN_LOCK(sc); 1892499c3e17SSepherosa Ziehau 1893499c3e17SSepherosa Ziehau if (sc->hn_vf_ifp == NULL) 1894499c3e17SSepherosa Ziehau goto done; 1895499c3e17SSepherosa Ziehau 1896499c3e17SSepherosa Ziehau if (!hn_ismyvf(sc, ifp)) 1897499c3e17SSepherosa Ziehau goto done; 1898499c3e17SSepherosa Ziehau 18999c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 19009c6cae24SSepherosa Ziehau /* 19019c6cae24SSepherosa Ziehau * Make sure that the delayed initialization is not running. 19029c6cae24SSepherosa Ziehau * 19039c6cae24SSepherosa Ziehau * NOTE: 19049c6cae24SSepherosa Ziehau * - This lock _must_ be released, since the hn_vf_init task 19059c6cae24SSepherosa Ziehau * will try holding this lock. 19069c6cae24SSepherosa Ziehau * - It is safe to release this lock here, since the 19079c6cae24SSepherosa Ziehau * hn_ifnet_attevent() is interlocked by the hn_vf_ifp. 19089c6cae24SSepherosa Ziehau * 19099c6cae24SSepherosa Ziehau * XXX racy, if hn(4) ever detached. 19109c6cae24SSepherosa Ziehau */ 19119c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 19129c6cae24SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init); 19139c6cae24SSepherosa Ziehau HN_LOCK(sc); 19149c6cae24SSepherosa Ziehau 19159c6cae24SSepherosa Ziehau KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved", 19169c6cae24SSepherosa Ziehau sc->hn_ifp->if_xname)); 19179c6cae24SSepherosa Ziehau ifp->if_input = sc->hn_vf_input; 19189c6cae24SSepherosa Ziehau sc->hn_vf_input = NULL; 19199c6cae24SSepherosa Ziehau 1920642ec226SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) && 1921642ec226SSepherosa Ziehau (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) 19229c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH); 19239c6cae24SSepherosa Ziehau 19249c6cae24SSepherosa Ziehau if (sc->hn_vf_rdytick == 0) { 19259c6cae24SSepherosa Ziehau /* 19269c6cae24SSepherosa Ziehau * The VF was ready; restore some settings. 19279c6cae24SSepherosa Ziehau */ 19289c6cae24SSepherosa Ziehau sc->hn_ifp->if_capabilities = sc->hn_saved_caps; 19299c6cae24SSepherosa Ziehau /* 19309c6cae24SSepherosa Ziehau * NOTE: 19319c6cae24SSepherosa Ziehau * There is _no_ need to fixup if_capenable and 19329c6cae24SSepherosa Ziehau * if_hwassist, since the if_capabilities before 19339c6cae24SSepherosa Ziehau * restoration was an intersection of the VF's 19349c6cae24SSepherosa Ziehau * if_capabilites and the synthetic device's 19359c6cae24SSepherosa Ziehau * if_capabilites. 19369c6cae24SSepherosa Ziehau */ 19379c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax; 19389c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomaxsegcount = 19399c6cae24SSepherosa Ziehau sc->hn_saved_tsosegcnt; 19409c6cae24SSepherosa Ziehau sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz; 19419c6cae24SSepherosa Ziehau } 19429c6cae24SSepherosa Ziehau 1943642ec226SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 1944642ec226SSepherosa Ziehau /* 1945642ec226SSepherosa Ziehau * Restore RSS settings. 1946642ec226SSepherosa Ziehau */ 1947642ec226SSepherosa Ziehau hn_vf_rss_restore(sc); 1948642ec226SSepherosa Ziehau 19499c6cae24SSepherosa Ziehau /* 19509c6cae24SSepherosa Ziehau * Resume link status management, which was suspended 19519c6cae24SSepherosa Ziehau * by hn_ifnet_attevent(). 19529c6cae24SSepherosa Ziehau */ 19539c6cae24SSepherosa Ziehau hn_resume_mgmt(sc); 19549c6cae24SSepherosa Ziehau } 1955642ec226SSepherosa Ziehau } 19569c6cae24SSepherosa Ziehau 1957a97fff19SSepherosa Ziehau /* Mark transparent mode VF as disabled. */ 1958a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */); 1959499c3e17SSepherosa Ziehau 1960499c3e17SSepherosa Ziehau rm_wlock(&hn_vfmap_lock); 1961499c3e17SSepherosa Ziehau 1962499c3e17SSepherosa Ziehau KASSERT(ifp->if_index < hn_vfmap_size, 1963499c3e17SSepherosa Ziehau ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size)); 1964499c3e17SSepherosa Ziehau if (hn_vfmap[ifp->if_index] != NULL) { 1965499c3e17SSepherosa Ziehau KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp, 1966499c3e17SSepherosa Ziehau ("%s: ifindex %d was mapped to %s", 1967499c3e17SSepherosa Ziehau ifp->if_xname, ifp->if_index, 1968499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index]->if_xname)); 1969499c3e17SSepherosa Ziehau hn_vfmap[ifp->if_index] = NULL; 1970499c3e17SSepherosa Ziehau } 1971499c3e17SSepherosa Ziehau 1972499c3e17SSepherosa Ziehau rm_wunlock(&hn_vfmap_lock); 1973499c3e17SSepherosa Ziehau done: 1974499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 1975499c3e17SSepherosa Ziehau } 1976499c3e17SSepherosa Ziehau 19779c6cae24SSepherosa Ziehau static void 19789c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state) 19799c6cae24SSepherosa Ziehau { 19809c6cae24SSepherosa Ziehau struct hn_softc *sc = xsc; 19819c6cae24SSepherosa Ziehau 19829c6cae24SSepherosa Ziehau if (sc->hn_vf_ifp == ifp) 19839c6cae24SSepherosa Ziehau if_link_state_change(sc->hn_ifp, link_state); 19849c6cae24SSepherosa Ziehau } 19859c6cae24SSepherosa Ziehau 198615516c77SSepherosa Ziehau static int 198715516c77SSepherosa Ziehau hn_probe(device_t dev) 198815516c77SSepherosa Ziehau { 198915516c77SSepherosa Ziehau 1990c2d50b26SSepherosa Ziehau if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) { 199115516c77SSepherosa Ziehau device_set_desc(dev, "Hyper-V Network Interface"); 199215516c77SSepherosa Ziehau return BUS_PROBE_DEFAULT; 199315516c77SSepherosa Ziehau } 199415516c77SSepherosa Ziehau return ENXIO; 199515516c77SSepherosa Ziehau } 199615516c77SSepherosa Ziehau 199715516c77SSepherosa Ziehau static int 199815516c77SSepherosa Ziehau hn_attach(device_t dev) 199915516c77SSepherosa Ziehau { 200015516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 200115516c77SSepherosa Ziehau struct sysctl_oid_list *child; 200215516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 200315516c77SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 200415516c77SSepherosa Ziehau struct ifnet *ifp = NULL; 200515516c77SSepherosa Ziehau int error, ring_cnt, tx_ring_cnt; 2006*eb2fe044SSepherosa Ziehau uint32_t mtu; 200715516c77SSepherosa Ziehau 200815516c77SSepherosa Ziehau sc->hn_dev = dev; 200915516c77SSepherosa Ziehau sc->hn_prichan = vmbus_get_channel(dev); 201015516c77SSepherosa Ziehau HN_LOCK_INIT(sc); 20119c6cae24SSepherosa Ziehau rm_init(&sc->hn_vf_lock, "hnvf"); 20129c6cae24SSepherosa Ziehau if (hn_xpnt_vf && hn_xpnt_vf_accbpf) 20139c6cae24SSepherosa Ziehau sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF; 201415516c77SSepherosa Ziehau 201515516c77SSepherosa Ziehau /* 2016dc13fee6SSepherosa Ziehau * Initialize these tunables once. 2017dc13fee6SSepherosa Ziehau */ 2018dc13fee6SSepherosa Ziehau sc->hn_agg_size = hn_tx_agg_size; 2019dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = hn_tx_agg_pkts; 2020dc13fee6SSepherosa Ziehau 2021dc13fee6SSepherosa Ziehau /* 202215516c77SSepherosa Ziehau * Setup taskqueue for transmission. 202315516c77SSepherosa Ziehau */ 20240e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) { 2025fdd0222aSSepherosa Ziehau int i; 2026fdd0222aSSepherosa Ziehau 2027fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = 2028fdd0222aSSepherosa Ziehau malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 2029fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 2030fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 2031fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx", 2032fdd0222aSSepherosa Ziehau M_WAITOK, taskqueue_thread_enqueue, 2033fdd0222aSSepherosa Ziehau &sc->hn_tx_taskqs[i]); 2034fdd0222aSSepherosa Ziehau taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET, 2035fdd0222aSSepherosa Ziehau "%s tx%d", device_get_nameunit(dev), i); 2036fdd0222aSSepherosa Ziehau } 20370e11868dSSepherosa Ziehau } else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) { 2038fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = hn_tx_taskque; 203915516c77SSepherosa Ziehau } 204015516c77SSepherosa Ziehau 204115516c77SSepherosa Ziehau /* 204215516c77SSepherosa Ziehau * Setup taskqueue for mangement tasks, e.g. link status. 204315516c77SSepherosa Ziehau */ 204415516c77SSepherosa Ziehau sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK, 204515516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0); 204615516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt", 204715516c77SSepherosa Ziehau device_get_nameunit(dev)); 204815516c77SSepherosa Ziehau TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc); 204915516c77SSepherosa Ziehau TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc); 205015516c77SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0, 205115516c77SSepherosa Ziehau hn_netchg_status_taskfunc, sc); 205215516c77SSepherosa Ziehau 20539c6cae24SSepherosa Ziehau if (hn_xpnt_vf) { 20549c6cae24SSepherosa Ziehau /* 20559c6cae24SSepherosa Ziehau * Setup taskqueue for VF tasks, e.g. delayed VF bringing up. 20569c6cae24SSepherosa Ziehau */ 20579c6cae24SSepherosa Ziehau sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK, 20589c6cae24SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_vf_taskq); 20599c6cae24SSepherosa Ziehau taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf", 20609c6cae24SSepherosa Ziehau device_get_nameunit(dev)); 20619c6cae24SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0, 20629c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc, sc); 20639c6cae24SSepherosa Ziehau } 20649c6cae24SSepherosa Ziehau 206515516c77SSepherosa Ziehau /* 206615516c77SSepherosa Ziehau * Allocate ifnet and setup its name earlier, so that if_printf 206715516c77SSepherosa Ziehau * can be used by functions, which will be called after 206815516c77SSepherosa Ziehau * ether_ifattach(). 206915516c77SSepherosa Ziehau */ 207015516c77SSepherosa Ziehau ifp = sc->hn_ifp = if_alloc(IFT_ETHER); 207115516c77SSepherosa Ziehau ifp->if_softc = sc; 207215516c77SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 207315516c77SSepherosa Ziehau 207415516c77SSepherosa Ziehau /* 207515516c77SSepherosa Ziehau * Initialize ifmedia earlier so that it can be unconditionally 207615516c77SSepherosa Ziehau * destroyed, if error happened later on. 207715516c77SSepherosa Ziehau */ 207815516c77SSepherosa Ziehau ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts); 207915516c77SSepherosa Ziehau 208015516c77SSepherosa Ziehau /* 208115516c77SSepherosa Ziehau * Figure out the # of RX rings (ring_cnt) and the # of TX rings 208215516c77SSepherosa Ziehau * to use (tx_ring_cnt). 208315516c77SSepherosa Ziehau * 208415516c77SSepherosa Ziehau * NOTE: 208515516c77SSepherosa Ziehau * The # of RX rings to use is same as the # of channels to use. 208615516c77SSepherosa Ziehau */ 208715516c77SSepherosa Ziehau ring_cnt = hn_chan_cnt; 208815516c77SSepherosa Ziehau if (ring_cnt <= 0) { 208915516c77SSepherosa Ziehau /* Default */ 209015516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 209115516c77SSepherosa Ziehau if (ring_cnt > HN_RING_CNT_DEF_MAX) 209215516c77SSepherosa Ziehau ring_cnt = HN_RING_CNT_DEF_MAX; 209315516c77SSepherosa Ziehau } else if (ring_cnt > mp_ncpus) { 209415516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 209515516c77SSepherosa Ziehau } 209634d68912SSepherosa Ziehau #ifdef RSS 209734d68912SSepherosa Ziehau if (ring_cnt > rss_getnumbuckets()) 209834d68912SSepherosa Ziehau ring_cnt = rss_getnumbuckets(); 209934d68912SSepherosa Ziehau #endif 210015516c77SSepherosa Ziehau 210115516c77SSepherosa Ziehau tx_ring_cnt = hn_tx_ring_cnt; 210215516c77SSepherosa Ziehau if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt) 210315516c77SSepherosa Ziehau tx_ring_cnt = ring_cnt; 210423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 210515516c77SSepherosa Ziehau if (hn_use_if_start) { 210615516c77SSepherosa Ziehau /* ifnet.if_start only needs one TX ring. */ 210715516c77SSepherosa Ziehau tx_ring_cnt = 1; 210815516c77SSepherosa Ziehau } 210923bf9e15SSepherosa Ziehau #endif 211015516c77SSepherosa Ziehau 211115516c77SSepherosa Ziehau /* 211215516c77SSepherosa Ziehau * Set the leader CPU for channels. 211315516c77SSepherosa Ziehau */ 211415516c77SSepherosa Ziehau sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus; 211515516c77SSepherosa Ziehau 211615516c77SSepherosa Ziehau /* 211715516c77SSepherosa Ziehau * Create enough TX/RX rings, even if only limited number of 211815516c77SSepherosa Ziehau * channels can be allocated. 211915516c77SSepherosa Ziehau */ 212015516c77SSepherosa Ziehau error = hn_create_tx_data(sc, tx_ring_cnt); 212115516c77SSepherosa Ziehau if (error) 212215516c77SSepherosa Ziehau goto failed; 212315516c77SSepherosa Ziehau error = hn_create_rx_data(sc, ring_cnt); 212415516c77SSepherosa Ziehau if (error) 212515516c77SSepherosa Ziehau goto failed; 212615516c77SSepherosa Ziehau 212715516c77SSepherosa Ziehau /* 212815516c77SSepherosa Ziehau * Create transaction context for NVS and RNDIS transactions. 212915516c77SSepherosa Ziehau */ 213015516c77SSepherosa Ziehau sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev), 213115516c77SSepherosa Ziehau HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0); 213225641fc7SSepherosa Ziehau if (sc->hn_xact == NULL) { 213325641fc7SSepherosa Ziehau error = ENXIO; 213415516c77SSepherosa Ziehau goto failed; 213525641fc7SSepherosa Ziehau } 213625641fc7SSepherosa Ziehau 213725641fc7SSepherosa Ziehau /* 213825641fc7SSepherosa Ziehau * Install orphan handler for the revocation of this device's 213925641fc7SSepherosa Ziehau * primary channel. 214025641fc7SSepherosa Ziehau * 214125641fc7SSepherosa Ziehau * NOTE: 214225641fc7SSepherosa Ziehau * The processing order is critical here: 214325641fc7SSepherosa Ziehau * Install the orphan handler, _before_ testing whether this 214425641fc7SSepherosa Ziehau * device's primary channel has been revoked or not. 214525641fc7SSepherosa Ziehau */ 214625641fc7SSepherosa Ziehau vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact); 214725641fc7SSepherosa Ziehau if (vmbus_chan_is_revoked(sc->hn_prichan)) { 214825641fc7SSepherosa Ziehau error = ENXIO; 214925641fc7SSepherosa Ziehau goto failed; 215025641fc7SSepherosa Ziehau } 215115516c77SSepherosa Ziehau 215215516c77SSepherosa Ziehau /* 215315516c77SSepherosa Ziehau * Attach the synthetic parts, i.e. NVS and RNDIS. 215415516c77SSepherosa Ziehau */ 215515516c77SSepherosa Ziehau error = hn_synth_attach(sc, ETHERMTU); 215615516c77SSepherosa Ziehau if (error) 215715516c77SSepherosa Ziehau goto failed; 215815516c77SSepherosa Ziehau 215915516c77SSepherosa Ziehau error = hn_rndis_get_eaddr(sc, eaddr); 216015516c77SSepherosa Ziehau if (error) 216115516c77SSepherosa Ziehau goto failed; 216215516c77SSepherosa Ziehau 2163*eb2fe044SSepherosa Ziehau error = hn_rndis_get_mtu(sc, &mtu); 2164*eb2fe044SSepherosa Ziehau if (error) 2165*eb2fe044SSepherosa Ziehau mtu = ETHERMTU; 2166*eb2fe044SSepherosa Ziehau else if (bootverbose) 2167*eb2fe044SSepherosa Ziehau device_printf(dev, "RNDIS mtu %u\n", mtu); 2168*eb2fe044SSepherosa Ziehau 216915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 217015516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 217115516c77SSepherosa Ziehau /* 217215516c77SSepherosa Ziehau * Reduce TCP segment aggregation limit for multiple 217315516c77SSepherosa Ziehau * RX rings to increase ACK timeliness. 217415516c77SSepherosa Ziehau */ 217515516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF); 217615516c77SSepherosa Ziehau } 217715516c77SSepherosa Ziehau #endif 217815516c77SSepherosa Ziehau 217915516c77SSepherosa Ziehau /* 218015516c77SSepherosa Ziehau * Fixup TX stuffs after synthetic parts are attached. 218115516c77SSepherosa Ziehau */ 218215516c77SSepherosa Ziehau hn_fixup_tx_data(sc); 218315516c77SSepherosa Ziehau 218415516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 218515516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 218615516c77SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD, 218715516c77SSepherosa Ziehau &sc->hn_nvs_ver, 0, "NVS version"); 218815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version", 218915516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 219015516c77SSepherosa Ziehau hn_ndis_version_sysctl, "A", "NDIS version"); 219115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps", 219215516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 219315516c77SSepherosa Ziehau hn_caps_sysctl, "A", "capabilities"); 219415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist", 219515516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 219615516c77SSepherosa Ziehau hn_hwassist_sysctl, "A", "hwassist"); 21979c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max", 21989c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size"); 21999c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt", 22009c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0, 22019c6cae24SSepherosa Ziehau "max # of TSO segments"); 22029c6cae24SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz", 22039c6cae24SSepherosa Ziehau CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0, 22049c6cae24SSepherosa Ziehau "max size of TSO segment"); 220515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter", 220615516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 220715516c77SSepherosa Ziehau hn_rxfilter_sysctl, "A", "rxfilter"); 220815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash", 220915516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 221015516c77SSepherosa Ziehau hn_rss_hash_sysctl, "A", "RSS hash"); 2211642ec226SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hashcap", 2212642ec226SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 2213642ec226SSepherosa Ziehau hn_rss_hcap_sysctl, "A", "RSS hash capabilities"); 2214642ec226SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "mbuf_hash", 2215642ec226SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 2216642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl, "A", "RSS hash for mbufs"); 221715516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size", 221815516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count"); 221934d68912SSepherosa Ziehau #ifndef RSS 222034d68912SSepherosa Ziehau /* 222134d68912SSepherosa Ziehau * Don't allow RSS key/indirect table changes, if RSS is defined. 222234d68912SSepherosa Ziehau */ 222315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key", 222415516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 222515516c77SSepherosa Ziehau hn_rss_key_sysctl, "IU", "RSS key"); 222615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind", 222715516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 222815516c77SSepherosa Ziehau hn_rss_ind_sysctl, "IU", "RSS indirect table"); 222934d68912SSepherosa Ziehau #endif 2230dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size", 2231dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_size, 0, 2232dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation size limit"); 2233dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts", 2234dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0, 2235dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation count limit"); 2236dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align", 2237dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_align, 0, 2238dc13fee6SSepherosa Ziehau "RNDIS packet transmission aggregation alignment"); 2239dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size", 2240dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 2241dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl, "I", 2242dc13fee6SSepherosa Ziehau "Packet transmission aggregation size, 0 -- disable, -1 -- auto"); 2243dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts", 2244dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 2245dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl, "I", 2246dc13fee6SSepherosa Ziehau "Packet transmission aggregation packets, " 2247dc13fee6SSepherosa Ziehau "0 -- disable, -1 -- auto"); 22486c1204dfSSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling", 22496c1204dfSSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 22506c1204dfSSepherosa Ziehau hn_polling_sysctl, "I", 22516c1204dfSSepherosa Ziehau "Polling frequency: [100,1000000], 0 disable polling"); 225240d60d6eSDexuan Cui SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf", 225340d60d6eSDexuan Cui CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 225440d60d6eSDexuan Cui hn_vf_sysctl, "A", "Virtual Function's name"); 22559c6cae24SSepherosa Ziehau if (!hn_xpnt_vf) { 2256499c3e17SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf", 2257499c3e17SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 2258499c3e17SSepherosa Ziehau hn_rxvf_sysctl, "A", "activated Virtual Function's name"); 22599c6cae24SSepherosa Ziehau } else { 22609c6cae24SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled", 22619c6cae24SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 22629c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl, "I", 22639c6cae24SSepherosa Ziehau "Transparent VF enabled"); 22649c6cae24SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf", 22659c6cae24SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 22669c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl, "I", 22679c6cae24SSepherosa Ziehau "Accurate BPF for transparent VF"); 22689c6cae24SSepherosa Ziehau } 226915516c77SSepherosa Ziehau 227015516c77SSepherosa Ziehau /* 227115516c77SSepherosa Ziehau * Setup the ifmedia, which has been initialized earlier. 227215516c77SSepherosa Ziehau */ 227315516c77SSepherosa Ziehau ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL); 227415516c77SSepherosa Ziehau ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO); 227515516c77SSepherosa Ziehau /* XXX ifmedia_set really should do this for us */ 227615516c77SSepherosa Ziehau sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media; 227715516c77SSepherosa Ziehau 227815516c77SSepherosa Ziehau /* 227915516c77SSepherosa Ziehau * Setup the ifnet for this interface. 228015516c77SSepherosa Ziehau */ 228115516c77SSepherosa Ziehau 228215516c77SSepherosa Ziehau ifp->if_baudrate = IF_Gbps(10); 228315516c77SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 228415516c77SSepherosa Ziehau ifp->if_ioctl = hn_ioctl; 228515516c77SSepherosa Ziehau ifp->if_init = hn_init; 228623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 228715516c77SSepherosa Ziehau if (hn_use_if_start) { 228815516c77SSepherosa Ziehau int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]); 228915516c77SSepherosa Ziehau 229015516c77SSepherosa Ziehau ifp->if_start = hn_start; 229115516c77SSepherosa Ziehau IFQ_SET_MAXLEN(&ifp->if_snd, qdepth); 229215516c77SSepherosa Ziehau ifp->if_snd.ifq_drv_maxlen = qdepth - 1; 229315516c77SSepherosa Ziehau IFQ_SET_READY(&ifp->if_snd); 229423bf9e15SSepherosa Ziehau } else 229523bf9e15SSepherosa Ziehau #endif 229623bf9e15SSepherosa Ziehau { 229715516c77SSepherosa Ziehau ifp->if_transmit = hn_transmit; 229815516c77SSepherosa Ziehau ifp->if_qflush = hn_xmit_qflush; 229915516c77SSepherosa Ziehau } 230015516c77SSepherosa Ziehau 23019c6cae24SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE; 230215516c77SSepherosa Ziehau #ifdef foo 230315516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 230415516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM_IPV6; 230515516c77SSepherosa Ziehau #endif 230615516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_VLAN) { 230715516c77SSepherosa Ziehau /* XXX not sure about VLAN_MTU. */ 230815516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 230915516c77SSepherosa Ziehau } 231015516c77SSepherosa Ziehau 231115516c77SSepherosa Ziehau ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist; 231215516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP_MASK) 231315516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM; 231415516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP6_MASK) 231515516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM_IPV6; 231615516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO4) { 231715516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO4; 231815516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 231915516c77SSepherosa Ziehau } 232015516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO6) { 232115516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO6; 232215516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 232315516c77SSepherosa Ziehau } 232415516c77SSepherosa Ziehau 232515516c77SSepherosa Ziehau /* Enable all available capabilities by default. */ 232615516c77SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 232715516c77SSepherosa Ziehau 23287960e6baSSepherosa Ziehau /* 23297960e6baSSepherosa Ziehau * Disable IPv6 TSO and TXCSUM by default, they still can 23307960e6baSSepherosa Ziehau * be enabled through SIOCSIFCAP. 23317960e6baSSepherosa Ziehau */ 23327960e6baSSepherosa Ziehau ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 23337960e6baSSepherosa Ziehau ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO); 23347960e6baSSepherosa Ziehau 233515516c77SSepherosa Ziehau if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) { 23369c6cae24SSepherosa Ziehau /* 23379c6cae24SSepherosa Ziehau * Lock hn_set_tso_maxsize() to simplify its 23389c6cae24SSepherosa Ziehau * internal logic. 23399c6cae24SSepherosa Ziehau */ 23409c6cae24SSepherosa Ziehau HN_LOCK(sc); 234115516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU); 23429c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 234315516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; 234415516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 234515516c77SSepherosa Ziehau } 234615516c77SSepherosa Ziehau 234715516c77SSepherosa Ziehau ether_ifattach(ifp, eaddr); 234815516c77SSepherosa Ziehau 234915516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) { 235015516c77SSepherosa Ziehau if_printf(ifp, "TSO segcnt %u segsz %u\n", 235115516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize); 235215516c77SSepherosa Ziehau } 2353*eb2fe044SSepherosa Ziehau if (mtu < ETHERMTU) { 2354*eb2fe044SSepherosa Ziehau if_printf(ifp, "fixup mtu %u -> %u\n", ifp->if_mtu, mtu); 2355*eb2fe044SSepherosa Ziehau ifp->if_mtu = mtu; 2356*eb2fe044SSepherosa Ziehau } 235715516c77SSepherosa Ziehau 235815516c77SSepherosa Ziehau /* Inform the upper layer about the long frame support. */ 235915516c77SSepherosa Ziehau ifp->if_hdrlen = sizeof(struct ether_vlan_header); 236015516c77SSepherosa Ziehau 236115516c77SSepherosa Ziehau /* 236215516c77SSepherosa Ziehau * Kick off link status check. 236315516c77SSepherosa Ziehau */ 236415516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 236515516c77SSepherosa Ziehau hn_update_link_status(sc); 236615516c77SSepherosa Ziehau 23679c6cae24SSepherosa Ziehau if (!hn_xpnt_vf) { 23685bdfd3fdSDexuan Cui sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event, 23695bdfd3fdSDexuan Cui hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY); 23705bdfd3fdSDexuan Cui sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event, 23715bdfd3fdSDexuan Cui hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY); 23729c6cae24SSepherosa Ziehau } else { 23739c6cae24SSepherosa Ziehau sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event, 23749c6cae24SSepherosa Ziehau hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY); 23759c6cae24SSepherosa Ziehau } 23765bdfd3fdSDexuan Cui 2377f41e0df4SSepherosa Ziehau /* 2378f41e0df4SSepherosa Ziehau * NOTE: 2379f41e0df4SSepherosa Ziehau * Subscribe ether_ifattach event, instead of ifnet_arrival event, 2380f41e0df4SSepherosa Ziehau * since interface's LLADDR is needed; interface LLADDR is not 2381f41e0df4SSepherosa Ziehau * available when ifnet_arrival event is triggered. 2382f41e0df4SSepherosa Ziehau */ 2383499c3e17SSepherosa Ziehau sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event, 2384499c3e17SSepherosa Ziehau hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY); 2385499c3e17SSepherosa Ziehau sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event, 2386499c3e17SSepherosa Ziehau hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY); 2387499c3e17SSepherosa Ziehau 238815516c77SSepherosa Ziehau return (0); 238915516c77SSepherosa Ziehau failed: 239015516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) 239115516c77SSepherosa Ziehau hn_synth_detach(sc); 239215516c77SSepherosa Ziehau hn_detach(dev); 239315516c77SSepherosa Ziehau return (error); 239415516c77SSepherosa Ziehau } 239515516c77SSepherosa Ziehau 239615516c77SSepherosa Ziehau static int 239715516c77SSepherosa Ziehau hn_detach(device_t dev) 239815516c77SSepherosa Ziehau { 239915516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 2400499c3e17SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp, *vf_ifp; 240115516c77SSepherosa Ziehau 24029c6cae24SSepherosa Ziehau if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) { 24039c6cae24SSepherosa Ziehau /* 24049c6cae24SSepherosa Ziehau * In case that the vmbus missed the orphan handler 24059c6cae24SSepherosa Ziehau * installation. 24069c6cae24SSepherosa Ziehau */ 24079c6cae24SSepherosa Ziehau vmbus_xact_ctx_orphan(sc->hn_xact); 24089c6cae24SSepherosa Ziehau } 24099c6cae24SSepherosa Ziehau 24105bdfd3fdSDexuan Cui if (sc->hn_ifaddr_evthand != NULL) 24115bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand); 24125bdfd3fdSDexuan Cui if (sc->hn_ifnet_evthand != NULL) 24135bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand); 2414499c3e17SSepherosa Ziehau if (sc->hn_ifnet_atthand != NULL) { 2415499c3e17SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ether_ifattach_event, 2416499c3e17SSepherosa Ziehau sc->hn_ifnet_atthand); 2417499c3e17SSepherosa Ziehau } 2418499c3e17SSepherosa Ziehau if (sc->hn_ifnet_dethand != NULL) { 2419499c3e17SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ifnet_departure_event, 2420499c3e17SSepherosa Ziehau sc->hn_ifnet_dethand); 2421499c3e17SSepherosa Ziehau } 24229c6cae24SSepherosa Ziehau if (sc->hn_ifnet_lnkhand != NULL) 24239c6cae24SSepherosa Ziehau EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand); 2424499c3e17SSepherosa Ziehau 2425499c3e17SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 2426499c3e17SSepherosa Ziehau __compiler_membar(); 2427499c3e17SSepherosa Ziehau if (vf_ifp != NULL) 2428499c3e17SSepherosa Ziehau hn_ifnet_detevent(sc, vf_ifp); 24295bdfd3fdSDexuan Cui 243015516c77SSepherosa Ziehau if (device_is_attached(dev)) { 243115516c77SSepherosa Ziehau HN_LOCK(sc); 243215516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 243315516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 24345bdfd3fdSDexuan Cui hn_stop(sc, true); 243515516c77SSepherosa Ziehau /* 243615516c77SSepherosa Ziehau * NOTE: 243715516c77SSepherosa Ziehau * hn_stop() only suspends data, so managment 243815516c77SSepherosa Ziehau * stuffs have to be suspended manually here. 243915516c77SSepherosa Ziehau */ 244015516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 244115516c77SSepherosa Ziehau hn_synth_detach(sc); 244215516c77SSepherosa Ziehau } 244315516c77SSepherosa Ziehau HN_UNLOCK(sc); 244415516c77SSepherosa Ziehau ether_ifdetach(ifp); 244515516c77SSepherosa Ziehau } 244615516c77SSepherosa Ziehau 244715516c77SSepherosa Ziehau ifmedia_removeall(&sc->hn_media); 244815516c77SSepherosa Ziehau hn_destroy_rx_data(sc); 244915516c77SSepherosa Ziehau hn_destroy_tx_data(sc); 245015516c77SSepherosa Ziehau 24510e11868dSSepherosa Ziehau if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) { 2452fdd0222aSSepherosa Ziehau int i; 2453fdd0222aSSepherosa Ziehau 2454fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 2455fdd0222aSSepherosa Ziehau taskqueue_free(sc->hn_tx_taskqs[i]); 2456fdd0222aSSepherosa Ziehau free(sc->hn_tx_taskqs, M_DEVBUF); 2457fdd0222aSSepherosa Ziehau } 245815516c77SSepherosa Ziehau taskqueue_free(sc->hn_mgmt_taskq0); 24599c6cae24SSepherosa Ziehau if (sc->hn_vf_taskq != NULL) 24609c6cae24SSepherosa Ziehau taskqueue_free(sc->hn_vf_taskq); 246115516c77SSepherosa Ziehau 246225641fc7SSepherosa Ziehau if (sc->hn_xact != NULL) { 246325641fc7SSepherosa Ziehau /* 246425641fc7SSepherosa Ziehau * Uninstall the orphan handler _before_ the xact is 246525641fc7SSepherosa Ziehau * destructed. 246625641fc7SSepherosa Ziehau */ 246725641fc7SSepherosa Ziehau vmbus_chan_unset_orphan(sc->hn_prichan); 246815516c77SSepherosa Ziehau vmbus_xact_ctx_destroy(sc->hn_xact); 246925641fc7SSepherosa Ziehau } 247015516c77SSepherosa Ziehau 247115516c77SSepherosa Ziehau if_free(ifp); 247215516c77SSepherosa Ziehau 247315516c77SSepherosa Ziehau HN_LOCK_DESTROY(sc); 24749c6cae24SSepherosa Ziehau rm_destroy(&sc->hn_vf_lock); 247515516c77SSepherosa Ziehau return (0); 247615516c77SSepherosa Ziehau } 247715516c77SSepherosa Ziehau 247815516c77SSepherosa Ziehau static int 247915516c77SSepherosa Ziehau hn_shutdown(device_t dev) 248015516c77SSepherosa Ziehau { 248115516c77SSepherosa Ziehau 248215516c77SSepherosa Ziehau return (0); 248315516c77SSepherosa Ziehau } 248415516c77SSepherosa Ziehau 248515516c77SSepherosa Ziehau static void 248615516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc) 248715516c77SSepherosa Ziehau { 248815516c77SSepherosa Ziehau uint32_t link_status; 248915516c77SSepherosa Ziehau int error; 249015516c77SSepherosa Ziehau 249115516c77SSepherosa Ziehau error = hn_rndis_get_linkstatus(sc, &link_status); 249215516c77SSepherosa Ziehau if (error) { 249315516c77SSepherosa Ziehau /* XXX what to do? */ 249415516c77SSepherosa Ziehau return; 249515516c77SSepherosa Ziehau } 249615516c77SSepherosa Ziehau 249715516c77SSepherosa Ziehau if (link_status == NDIS_MEDIA_STATE_CONNECTED) 249815516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_LINKUP; 249915516c77SSepherosa Ziehau else 250015516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 250115516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, 250215516c77SSepherosa Ziehau (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ? 250315516c77SSepherosa Ziehau LINK_STATE_UP : LINK_STATE_DOWN); 250415516c77SSepherosa Ziehau } 250515516c77SSepherosa Ziehau 250615516c77SSepherosa Ziehau static void 250715516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused) 250815516c77SSepherosa Ziehau { 250915516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 251015516c77SSepherosa Ziehau 251115516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 251215516c77SSepherosa Ziehau return; 251315516c77SSepherosa Ziehau hn_link_status(sc); 251415516c77SSepherosa Ziehau } 251515516c77SSepherosa Ziehau 251615516c77SSepherosa Ziehau static void 251715516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused) 251815516c77SSepherosa Ziehau { 251915516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 252015516c77SSepherosa Ziehau 252115516c77SSepherosa Ziehau /* Prevent any link status checks from running. */ 252215516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_NETCHG; 252315516c77SSepherosa Ziehau 252415516c77SSepherosa Ziehau /* 252515516c77SSepherosa Ziehau * Fake up a [link down --> link up] state change; 5 seconds 252615516c77SSepherosa Ziehau * delay is used, which closely simulates miibus reaction 252715516c77SSepherosa Ziehau * upon link down event. 252815516c77SSepherosa Ziehau */ 252915516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 253015516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); 253115516c77SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0, 253215516c77SSepherosa Ziehau &sc->hn_netchg_status, 5 * hz); 253315516c77SSepherosa Ziehau } 253415516c77SSepherosa Ziehau 253515516c77SSepherosa Ziehau static void 253615516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused) 253715516c77SSepherosa Ziehau { 253815516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 253915516c77SSepherosa Ziehau 254015516c77SSepherosa Ziehau /* Re-allow link status checks. */ 254115516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG; 254215516c77SSepherosa Ziehau hn_link_status(sc); 254315516c77SSepherosa Ziehau } 254415516c77SSepherosa Ziehau 254515516c77SSepherosa Ziehau static void 254615516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc) 254715516c77SSepherosa Ziehau { 254815516c77SSepherosa Ziehau 254915516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 255015516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task); 255115516c77SSepherosa Ziehau } 255215516c77SSepherosa Ziehau 255315516c77SSepherosa Ziehau static void 255415516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc) 255515516c77SSepherosa Ziehau { 255615516c77SSepherosa Ziehau 255715516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 255815516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init); 255915516c77SSepherosa Ziehau } 256015516c77SSepherosa Ziehau 256115516c77SSepherosa Ziehau static __inline int 256215516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd, 256315516c77SSepherosa Ziehau struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) 256415516c77SSepherosa Ziehau { 256515516c77SSepherosa Ziehau struct mbuf *m = *m_head; 256615516c77SSepherosa Ziehau int error; 256715516c77SSepherosa Ziehau 256815516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim")); 256915516c77SSepherosa Ziehau 257015516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap, 257115516c77SSepherosa Ziehau m, segs, nsegs, BUS_DMA_NOWAIT); 257215516c77SSepherosa Ziehau if (error == EFBIG) { 257315516c77SSepherosa Ziehau struct mbuf *m_new; 257415516c77SSepherosa Ziehau 257515516c77SSepherosa Ziehau m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX); 257615516c77SSepherosa Ziehau if (m_new == NULL) 257715516c77SSepherosa Ziehau return ENOBUFS; 257815516c77SSepherosa Ziehau else 257915516c77SSepherosa Ziehau *m_head = m = m_new; 258015516c77SSepherosa Ziehau txr->hn_tx_collapsed++; 258115516c77SSepherosa Ziehau 258215516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, 258315516c77SSepherosa Ziehau txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT); 258415516c77SSepherosa Ziehau } 258515516c77SSepherosa Ziehau if (!error) { 258615516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap, 258715516c77SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 258815516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_DMAMAP; 258915516c77SSepherosa Ziehau } 259015516c77SSepherosa Ziehau return error; 259115516c77SSepherosa Ziehau } 259215516c77SSepherosa Ziehau 259315516c77SSepherosa Ziehau static __inline int 259415516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd) 259515516c77SSepherosa Ziehau { 259615516c77SSepherosa Ziehau 259715516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0, 259815516c77SSepherosa Ziehau ("put an onlist txd %#x", txd->flags)); 2599dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2600dc13fee6SSepherosa Ziehau ("put an onagg txd %#x", txd->flags)); 260115516c77SSepherosa Ziehau 260215516c77SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 260315516c77SSepherosa Ziehau if (atomic_fetchadd_int(&txd->refs, -1) != 1) 260415516c77SSepherosa Ziehau return 0; 260515516c77SSepherosa Ziehau 2606dc13fee6SSepherosa Ziehau if (!STAILQ_EMPTY(&txd->agg_list)) { 2607dc13fee6SSepherosa Ziehau struct hn_txdesc *tmp_txd; 2608dc13fee6SSepherosa Ziehau 2609dc13fee6SSepherosa Ziehau while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) { 2610dc13fee6SSepherosa Ziehau int freed; 2611dc13fee6SSepherosa Ziehau 2612dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list), 2613dc13fee6SSepherosa Ziehau ("resursive aggregation on aggregated txdesc")); 2614dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG), 2615dc13fee6SSepherosa Ziehau ("not aggregated txdesc")); 2616dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 2617dc13fee6SSepherosa Ziehau ("aggregated txdesc uses dmamap")); 2618dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 2619dc13fee6SSepherosa Ziehau ("aggregated txdesc consumes " 2620dc13fee6SSepherosa Ziehau "chimney sending buffer")); 2621dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_size == 0, 2622dc13fee6SSepherosa Ziehau ("aggregated txdesc has non-zero " 2623dc13fee6SSepherosa Ziehau "chimney sending size")); 2624dc13fee6SSepherosa Ziehau 2625dc13fee6SSepherosa Ziehau STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link); 2626dc13fee6SSepherosa Ziehau tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG; 2627dc13fee6SSepherosa Ziehau freed = hn_txdesc_put(txr, tmp_txd); 2628dc13fee6SSepherosa Ziehau KASSERT(freed, ("failed to free aggregated txdesc")); 2629dc13fee6SSepherosa Ziehau } 2630dc13fee6SSepherosa Ziehau } 2631dc13fee6SSepherosa Ziehau 263215516c77SSepherosa Ziehau if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) { 263315516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 263415516c77SSepherosa Ziehau ("chim txd uses dmamap")); 263515516c77SSepherosa Ziehau hn_chim_free(txr->hn_sc, txd->chim_index); 263615516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 2637dc13fee6SSepherosa Ziehau txd->chim_size = 0; 263815516c77SSepherosa Ziehau } else if (txd->flags & HN_TXD_FLAG_DMAMAP) { 263915516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, 264015516c77SSepherosa Ziehau txd->data_dmap, BUS_DMASYNC_POSTWRITE); 264115516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_data_dtag, 264215516c77SSepherosa Ziehau txd->data_dmap); 264315516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_DMAMAP; 264415516c77SSepherosa Ziehau } 264515516c77SSepherosa Ziehau 264615516c77SSepherosa Ziehau if (txd->m != NULL) { 264715516c77SSepherosa Ziehau m_freem(txd->m); 264815516c77SSepherosa Ziehau txd->m = NULL; 264915516c77SSepherosa Ziehau } 265015516c77SSepherosa Ziehau 265115516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 265215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 265315516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 265415516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail >= 0 && 265515516c77SSepherosa Ziehau txr->hn_txdesc_avail < txr->hn_txdesc_cnt, 265615516c77SSepherosa Ziehau ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail)); 265715516c77SSepherosa Ziehau txr->hn_txdesc_avail++; 265815516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 265915516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 266085e4ae1eSSepherosa Ziehau #else /* HN_USE_TXDESC_BUFRING */ 266185e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 266215516c77SSepherosa Ziehau atomic_add_int(&txr->hn_txdesc_avail, 1); 266315516c77SSepherosa Ziehau #endif 266485e4ae1eSSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 266585e4ae1eSSepherosa Ziehau #endif /* !HN_USE_TXDESC_BUFRING */ 266615516c77SSepherosa Ziehau 266715516c77SSepherosa Ziehau return 1; 266815516c77SSepherosa Ziehau } 266915516c77SSepherosa Ziehau 267015516c77SSepherosa Ziehau static __inline struct hn_txdesc * 267115516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr) 267215516c77SSepherosa Ziehau { 267315516c77SSepherosa Ziehau struct hn_txdesc *txd; 267415516c77SSepherosa Ziehau 267515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 267615516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 267715516c77SSepherosa Ziehau txd = SLIST_FIRST(&txr->hn_txlist); 267815516c77SSepherosa Ziehau if (txd != NULL) { 267915516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail > 0, 268015516c77SSepherosa Ziehau ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail)); 268115516c77SSepherosa Ziehau txr->hn_txdesc_avail--; 268215516c77SSepherosa Ziehau SLIST_REMOVE_HEAD(&txr->hn_txlist, link); 268315516c77SSepherosa Ziehau } 268415516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 268515516c77SSepherosa Ziehau #else 268615516c77SSepherosa Ziehau txd = buf_ring_dequeue_sc(txr->hn_txdesc_br); 268715516c77SSepherosa Ziehau #endif 268815516c77SSepherosa Ziehau 268915516c77SSepherosa Ziehau if (txd != NULL) { 269015516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 269185e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 269215516c77SSepherosa Ziehau atomic_subtract_int(&txr->hn_txdesc_avail, 1); 269315516c77SSepherosa Ziehau #endif 269485e4ae1eSSepherosa Ziehau #endif /* HN_USE_TXDESC_BUFRING */ 269515516c77SSepherosa Ziehau KASSERT(txd->m == NULL && txd->refs == 0 && 2696dc13fee6SSepherosa Ziehau STAILQ_EMPTY(&txd->agg_list) && 269715516c77SSepherosa Ziehau txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 2698dc13fee6SSepherosa Ziehau txd->chim_size == 0 && 269915516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONLIST) && 2700dc13fee6SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONAGG) == 0 && 270115516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd")); 270215516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_ONLIST; 270315516c77SSepherosa Ziehau txd->refs = 1; 270415516c77SSepherosa Ziehau } 270515516c77SSepherosa Ziehau return txd; 270615516c77SSepherosa Ziehau } 270715516c77SSepherosa Ziehau 270815516c77SSepherosa Ziehau static __inline void 270915516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd) 271015516c77SSepherosa Ziehau { 271115516c77SSepherosa Ziehau 271215516c77SSepherosa Ziehau /* 0->1 transition will never work */ 271325641fc7SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 271415516c77SSepherosa Ziehau atomic_add_int(&txd->refs, 1); 271515516c77SSepherosa Ziehau } 271615516c77SSepherosa Ziehau 2717dc13fee6SSepherosa Ziehau static __inline void 2718dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd) 2719dc13fee6SSepherosa Ziehau { 2720dc13fee6SSepherosa Ziehau 2721dc13fee6SSepherosa Ziehau KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2722dc13fee6SSepherosa Ziehau ("recursive aggregation on aggregating txdesc")); 2723dc13fee6SSepherosa Ziehau 2724dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 2725dc13fee6SSepherosa Ziehau ("already aggregated")); 2726dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&txd->agg_list), 2727dc13fee6SSepherosa Ziehau ("recursive aggregation on to-be-aggregated txdesc")); 2728dc13fee6SSepherosa Ziehau 2729dc13fee6SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONAGG; 2730dc13fee6SSepherosa Ziehau STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link); 2731dc13fee6SSepherosa Ziehau } 2732dc13fee6SSepherosa Ziehau 273315516c77SSepherosa Ziehau static bool 273415516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr) 273515516c77SSepherosa Ziehau { 273615516c77SSepherosa Ziehau bool pending = false; 273715516c77SSepherosa Ziehau 273815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 273915516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 274015516c77SSepherosa Ziehau if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt) 274115516c77SSepherosa Ziehau pending = true; 274215516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 274315516c77SSepherosa Ziehau #else 274415516c77SSepherosa Ziehau if (!buf_ring_full(txr->hn_txdesc_br)) 274515516c77SSepherosa Ziehau pending = true; 274615516c77SSepherosa Ziehau #endif 274715516c77SSepherosa Ziehau return (pending); 274815516c77SSepherosa Ziehau } 274915516c77SSepherosa Ziehau 275015516c77SSepherosa Ziehau static __inline void 275115516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr) 275215516c77SSepherosa Ziehau { 275315516c77SSepherosa Ziehau txr->hn_has_txeof = 0; 275415516c77SSepherosa Ziehau txr->hn_txeof(txr); 275515516c77SSepherosa Ziehau } 275615516c77SSepherosa Ziehau 275715516c77SSepherosa Ziehau static void 275815516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc, 275915516c77SSepherosa Ziehau struct vmbus_channel *chan, const void *data __unused, int dlen __unused) 276015516c77SSepherosa Ziehau { 276115516c77SSepherosa Ziehau struct hn_txdesc *txd = sndc->hn_cbarg; 276215516c77SSepherosa Ziehau struct hn_tx_ring *txr; 276315516c77SSepherosa Ziehau 276415516c77SSepherosa Ziehau txr = txd->txr; 276515516c77SSepherosa Ziehau KASSERT(txr->hn_chan == chan, 276615516c77SSepherosa Ziehau ("channel mismatch, on chan%u, should be chan%u", 2767aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan))); 276815516c77SSepherosa Ziehau 276915516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 277015516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 277115516c77SSepherosa Ziehau 277215516c77SSepherosa Ziehau ++txr->hn_txdone_cnt; 277315516c77SSepherosa Ziehau if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) { 277415516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 277515516c77SSepherosa Ziehau if (txr->hn_oactive) 277615516c77SSepherosa Ziehau hn_txeof(txr); 277715516c77SSepherosa Ziehau } 277815516c77SSepherosa Ziehau } 277915516c77SSepherosa Ziehau 278015516c77SSepherosa Ziehau static void 278115516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr) 278215516c77SSepherosa Ziehau { 278315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 278415516c77SSepherosa Ziehau tcp_lro_flush_all(&rxr->hn_lro); 278515516c77SSepherosa Ziehau #endif 278615516c77SSepherosa Ziehau 278715516c77SSepherosa Ziehau /* 278815516c77SSepherosa Ziehau * NOTE: 278915516c77SSepherosa Ziehau * 'txr' could be NULL, if multiple channels and 279015516c77SSepherosa Ziehau * ifnet.if_start method are enabled. 279115516c77SSepherosa Ziehau */ 279215516c77SSepherosa Ziehau if (txr == NULL || !txr->hn_has_txeof) 279315516c77SSepherosa Ziehau return; 279415516c77SSepherosa Ziehau 279515516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 279615516c77SSepherosa Ziehau hn_txeof(txr); 279715516c77SSepherosa Ziehau } 279815516c77SSepherosa Ziehau 279915516c77SSepherosa Ziehau static __inline uint32_t 280015516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs) 280115516c77SSepherosa Ziehau { 280215516c77SSepherosa Ziehau 280315516c77SSepherosa Ziehau KASSERT(ofs >= sizeof(struct rndis_packet_msg), 280415516c77SSepherosa Ziehau ("invalid RNDIS packet msg offset %u", ofs)); 280515516c77SSepherosa Ziehau return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset)); 280615516c77SSepherosa Ziehau } 280715516c77SSepherosa Ziehau 280815516c77SSepherosa Ziehau static __inline void * 280915516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize, 281015516c77SSepherosa Ziehau size_t pi_dlen, uint32_t pi_type) 281115516c77SSepherosa Ziehau { 281215516c77SSepherosa Ziehau const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen); 281315516c77SSepherosa Ziehau struct rndis_pktinfo *pi; 281415516c77SSepherosa Ziehau 281515516c77SSepherosa Ziehau KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0, 281615516c77SSepherosa Ziehau ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen)); 281715516c77SSepherosa Ziehau 281815516c77SSepherosa Ziehau /* 281915516c77SSepherosa Ziehau * Per-packet-info does not move; it only grows. 282015516c77SSepherosa Ziehau * 282115516c77SSepherosa Ziehau * NOTE: 282215516c77SSepherosa Ziehau * rm_pktinfooffset in this phase counts from the beginning 282315516c77SSepherosa Ziehau * of rndis_packet_msg. 282415516c77SSepherosa Ziehau */ 282515516c77SSepherosa Ziehau KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize, 282615516c77SSepherosa Ziehau ("%u pktinfo overflows RNDIS packet msg", pi_type)); 282715516c77SSepherosa Ziehau pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset + 282815516c77SSepherosa Ziehau pkt->rm_pktinfolen); 282915516c77SSepherosa Ziehau pkt->rm_pktinfolen += pi_size; 283015516c77SSepherosa Ziehau 283115516c77SSepherosa Ziehau pi->rm_size = pi_size; 283215516c77SSepherosa Ziehau pi->rm_type = pi_type; 283315516c77SSepherosa Ziehau pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET; 283415516c77SSepherosa Ziehau 283515516c77SSepherosa Ziehau return (pi->rm_data); 283615516c77SSepherosa Ziehau } 283715516c77SSepherosa Ziehau 2838dc13fee6SSepherosa Ziehau static __inline int 2839dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr) 2840dc13fee6SSepherosa Ziehau { 2841dc13fee6SSepherosa Ziehau struct hn_txdesc *txd; 2842dc13fee6SSepherosa Ziehau struct mbuf *m; 2843dc13fee6SSepherosa Ziehau int error, pkts; 2844dc13fee6SSepherosa Ziehau 2845dc13fee6SSepherosa Ziehau txd = txr->hn_agg_txd; 2846dc13fee6SSepherosa Ziehau KASSERT(txd != NULL, ("no aggregate txdesc")); 2847dc13fee6SSepherosa Ziehau 2848dc13fee6SSepherosa Ziehau /* 2849dc13fee6SSepherosa Ziehau * Since hn_txpkt() will reset this temporary stat, save 2850dc13fee6SSepherosa Ziehau * it now, so that oerrors can be updated properly, if 2851dc13fee6SSepherosa Ziehau * hn_txpkt() ever fails. 2852dc13fee6SSepherosa Ziehau */ 2853dc13fee6SSepherosa Ziehau pkts = txr->hn_stat_pkts; 2854dc13fee6SSepherosa Ziehau 2855dc13fee6SSepherosa Ziehau /* 2856dc13fee6SSepherosa Ziehau * Since txd's mbuf will _not_ be freed upon hn_txpkt() 2857dc13fee6SSepherosa Ziehau * failure, save it for later freeing, if hn_txpkt() ever 2858dc13fee6SSepherosa Ziehau * fails. 2859dc13fee6SSepherosa Ziehau */ 2860dc13fee6SSepherosa Ziehau m = txd->m; 2861dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 2862dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 2863dc13fee6SSepherosa Ziehau /* txd is freed, but m is not. */ 2864dc13fee6SSepherosa Ziehau m_freem(m); 2865dc13fee6SSepherosa Ziehau 2866dc13fee6SSepherosa Ziehau txr->hn_flush_failed++; 2867dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts); 2868dc13fee6SSepherosa Ziehau } 2869dc13fee6SSepherosa Ziehau 2870dc13fee6SSepherosa Ziehau /* Reset all aggregation states. */ 2871dc13fee6SSepherosa Ziehau txr->hn_agg_txd = NULL; 2872dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = 0; 2873dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 2874dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = NULL; 2875dc13fee6SSepherosa Ziehau 2876dc13fee6SSepherosa Ziehau return (error); 2877dc13fee6SSepherosa Ziehau } 2878dc13fee6SSepherosa Ziehau 2879dc13fee6SSepherosa Ziehau static void * 2880dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 2881dc13fee6SSepherosa Ziehau int pktsize) 2882dc13fee6SSepherosa Ziehau { 2883dc13fee6SSepherosa Ziehau void *chim; 2884dc13fee6SSepherosa Ziehau 2885dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 2886dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) { 2887dc13fee6SSepherosa Ziehau struct hn_txdesc *agg_txd = txr->hn_agg_txd; 2888dc13fee6SSepherosa Ziehau struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt; 2889dc13fee6SSepherosa Ziehau int olen; 2890dc13fee6SSepherosa Ziehau 2891dc13fee6SSepherosa Ziehau /* 2892dc13fee6SSepherosa Ziehau * Update the previous RNDIS packet's total length, 2893dc13fee6SSepherosa Ziehau * it can be increased due to the mandatory alignment 2894dc13fee6SSepherosa Ziehau * padding for this RNDIS packet. And update the 2895dc13fee6SSepherosa Ziehau * aggregating txdesc's chimney sending buffer size 2896dc13fee6SSepherosa Ziehau * accordingly. 2897dc13fee6SSepherosa Ziehau * 2898dc13fee6SSepherosa Ziehau * XXX 2899dc13fee6SSepherosa Ziehau * Zero-out the padding, as required by the RNDIS spec. 2900dc13fee6SSepherosa Ziehau */ 2901dc13fee6SSepherosa Ziehau olen = pkt->rm_len; 2902dc13fee6SSepherosa Ziehau pkt->rm_len = roundup2(olen, txr->hn_agg_align); 2903dc13fee6SSepherosa Ziehau agg_txd->chim_size += pkt->rm_len - olen; 2904dc13fee6SSepherosa Ziehau 2905dc13fee6SSepherosa Ziehau /* Link this txdesc to the parent. */ 2906dc13fee6SSepherosa Ziehau hn_txdesc_agg(agg_txd, txd); 2907dc13fee6SSepherosa Ziehau 2908dc13fee6SSepherosa Ziehau chim = (uint8_t *)pkt + pkt->rm_len; 2909dc13fee6SSepherosa Ziehau /* Save the current packet for later fixup. */ 2910dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 2911dc13fee6SSepherosa Ziehau 2912dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft--; 2913dc13fee6SSepherosa Ziehau txr->hn_agg_szleft -= pktsize; 2914dc13fee6SSepherosa Ziehau if (txr->hn_agg_szleft <= 2915dc13fee6SSepherosa Ziehau HN_PKTSIZE_MIN(txr->hn_agg_align)) { 2916dc13fee6SSepherosa Ziehau /* 2917dc13fee6SSepherosa Ziehau * Probably can't aggregate more packets, 2918dc13fee6SSepherosa Ziehau * flush this aggregating txdesc proactively. 2919dc13fee6SSepherosa Ziehau */ 2920dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 2921dc13fee6SSepherosa Ziehau } 2922dc13fee6SSepherosa Ziehau /* Done! */ 2923dc13fee6SSepherosa Ziehau return (chim); 2924dc13fee6SSepherosa Ziehau } 2925dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 2926dc13fee6SSepherosa Ziehau } 2927dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 2928dc13fee6SSepherosa Ziehau 2929dc13fee6SSepherosa Ziehau txr->hn_tx_chimney_tried++; 2930dc13fee6SSepherosa Ziehau txd->chim_index = hn_chim_alloc(txr->hn_sc); 2931dc13fee6SSepherosa Ziehau if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID) 2932dc13fee6SSepherosa Ziehau return (NULL); 2933dc13fee6SSepherosa Ziehau txr->hn_tx_chimney++; 2934dc13fee6SSepherosa Ziehau 2935dc13fee6SSepherosa Ziehau chim = txr->hn_sc->hn_chim + 2936dc13fee6SSepherosa Ziehau (txd->chim_index * txr->hn_sc->hn_chim_szmax); 2937dc13fee6SSepherosa Ziehau 2938dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktmax > 1 && 2939dc13fee6SSepherosa Ziehau txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) { 2940dc13fee6SSepherosa Ziehau txr->hn_agg_txd = txd; 2941dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1; 2942dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize; 2943dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 2944dc13fee6SSepherosa Ziehau } 2945dc13fee6SSepherosa Ziehau return (chim); 2946dc13fee6SSepherosa Ziehau } 2947dc13fee6SSepherosa Ziehau 294815516c77SSepherosa Ziehau /* 294915516c77SSepherosa Ziehau * NOTE: 295015516c77SSepherosa Ziehau * If this function fails, then both txd and m_head0 will be freed. 295115516c77SSepherosa Ziehau */ 295215516c77SSepherosa Ziehau static int 2953dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 2954dc13fee6SSepherosa Ziehau struct mbuf **m_head0) 295515516c77SSepherosa Ziehau { 295615516c77SSepherosa Ziehau bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX]; 295715516c77SSepherosa Ziehau int error, nsegs, i; 295815516c77SSepherosa Ziehau struct mbuf *m_head = *m_head0; 295915516c77SSepherosa Ziehau struct rndis_packet_msg *pkt; 296015516c77SSepherosa Ziehau uint32_t *pi_data; 29618966e5d5SSepherosa Ziehau void *chim = NULL; 2962dc13fee6SSepherosa Ziehau int pkt_hlen, pkt_size; 296315516c77SSepherosa Ziehau 296415516c77SSepherosa Ziehau pkt = txd->rndis_pkt; 2965dc13fee6SSepherosa Ziehau pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align); 2966dc13fee6SSepherosa Ziehau if (pkt_size < txr->hn_chim_size) { 2967dc13fee6SSepherosa Ziehau chim = hn_try_txagg(ifp, txr, txd, pkt_size); 2968dc13fee6SSepherosa Ziehau if (chim != NULL) 29698966e5d5SSepherosa Ziehau pkt = chim; 2970dc13fee6SSepherosa Ziehau } else { 2971dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 2972dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 29738966e5d5SSepherosa Ziehau } 29748966e5d5SSepherosa Ziehau 297515516c77SSepherosa Ziehau pkt->rm_type = REMOTE_NDIS_PACKET_MSG; 29768fe90f73SSepherosa Ziehau pkt->rm_len = m_head->m_pkthdr.len; 29779130c4f7SSepherosa Ziehau pkt->rm_dataoffset = 0; 297815516c77SSepherosa Ziehau pkt->rm_datalen = m_head->m_pkthdr.len; 2979dc13fee6SSepherosa Ziehau pkt->rm_oobdataoffset = 0; 2980dc13fee6SSepherosa Ziehau pkt->rm_oobdatalen = 0; 2981dc13fee6SSepherosa Ziehau pkt->rm_oobdataelements = 0; 298215516c77SSepherosa Ziehau pkt->rm_pktinfooffset = sizeof(*pkt); 298315516c77SSepherosa Ziehau pkt->rm_pktinfolen = 0; 2984dc13fee6SSepherosa Ziehau pkt->rm_vchandle = 0; 2985dc13fee6SSepherosa Ziehau pkt->rm_reserved = 0; 298615516c77SSepherosa Ziehau 298715516c77SSepherosa Ziehau if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) { 298815516c77SSepherosa Ziehau /* 298915516c77SSepherosa Ziehau * Set the hash value for this packet, so that the host could 299015516c77SSepherosa Ziehau * dispatch the TX done event for this packet back to this TX 299115516c77SSepherosa Ziehau * ring's channel. 299215516c77SSepherosa Ziehau */ 299315516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 299415516c77SSepherosa Ziehau HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL); 299515516c77SSepherosa Ziehau *pi_data = txr->hn_tx_idx; 299615516c77SSepherosa Ziehau } 299715516c77SSepherosa Ziehau 299815516c77SSepherosa Ziehau if (m_head->m_flags & M_VLANTAG) { 299915516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 300015516c77SSepherosa Ziehau NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN); 300115516c77SSepherosa Ziehau *pi_data = NDIS_VLAN_INFO_MAKE( 300215516c77SSepherosa Ziehau EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag), 300315516c77SSepherosa Ziehau EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag), 300415516c77SSepherosa Ziehau EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag)); 300515516c77SSepherosa Ziehau } 300615516c77SSepherosa Ziehau 300715516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 300815516c77SSepherosa Ziehau #if defined(INET6) || defined(INET) 300915516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 301015516c77SSepherosa Ziehau NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); 301115516c77SSepherosa Ziehau #ifdef INET 301215516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 301315516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV4(0, 301415516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 301515516c77SSepherosa Ziehau } 301615516c77SSepherosa Ziehau #endif 301715516c77SSepherosa Ziehau #if defined(INET6) && defined(INET) 301815516c77SSepherosa Ziehau else 301915516c77SSepherosa Ziehau #endif 302015516c77SSepherosa Ziehau #ifdef INET6 302115516c77SSepherosa Ziehau { 302215516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV6(0, 302315516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 302415516c77SSepherosa Ziehau } 302515516c77SSepherosa Ziehau #endif 302615516c77SSepherosa Ziehau #endif /* INET6 || INET */ 302715516c77SSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) { 302815516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 302915516c77SSepherosa Ziehau NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); 303015516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & 303115516c77SSepherosa Ziehau (CSUM_IP6_TCP | CSUM_IP6_UDP)) { 303215516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV6; 303315516c77SSepherosa Ziehau } else { 303415516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV4; 303515516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 303615516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_IPCS; 303715516c77SSepherosa Ziehau } 303815516c77SSepherosa Ziehau 303915516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) 304015516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_TCPCS; 304115516c77SSepherosa Ziehau else if (m_head->m_pkthdr.csum_flags & 304215516c77SSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP6_UDP)) 304315516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_UDPCS; 304415516c77SSepherosa Ziehau } 304515516c77SSepherosa Ziehau 3046dc13fee6SSepherosa Ziehau pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; 30478fe90f73SSepherosa Ziehau /* Fixup RNDIS packet message total length */ 30488fe90f73SSepherosa Ziehau pkt->rm_len += pkt_hlen; 304915516c77SSepherosa Ziehau /* Convert RNDIS packet message offsets */ 30509130c4f7SSepherosa Ziehau pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen); 305115516c77SSepherosa Ziehau pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset); 305215516c77SSepherosa Ziehau 305315516c77SSepherosa Ziehau /* 30548966e5d5SSepherosa Ziehau * Fast path: Chimney sending. 305515516c77SSepherosa Ziehau */ 30568966e5d5SSepherosa Ziehau if (chim != NULL) { 3057dc13fee6SSepherosa Ziehau struct hn_txdesc *tgt_txd = txd; 3058dc13fee6SSepherosa Ziehau 3059dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 3060dc13fee6SSepherosa Ziehau tgt_txd = txr->hn_agg_txd; 3061dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 3062dc13fee6SSepherosa Ziehau *m_head0 = NULL; 3063dc13fee6SSepherosa Ziehau #endif 3064dc13fee6SSepherosa Ziehau } 3065dc13fee6SSepherosa Ziehau 3066dc13fee6SSepherosa Ziehau KASSERT(pkt == chim, 3067dc13fee6SSepherosa Ziehau ("RNDIS pkt not in chimney sending buffer")); 3068dc13fee6SSepherosa Ziehau KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID, 3069dc13fee6SSepherosa Ziehau ("chimney sending buffer is not used")); 3070dc13fee6SSepherosa Ziehau tgt_txd->chim_size += pkt->rm_len; 307115516c77SSepherosa Ziehau 30728966e5d5SSepherosa Ziehau m_copydata(m_head, 0, m_head->m_pkthdr.len, 3073dc13fee6SSepherosa Ziehau ((uint8_t *)chim) + pkt_hlen); 307415516c77SSepherosa Ziehau 307515516c77SSepherosa Ziehau txr->hn_gpa_cnt = 0; 307615516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_chim; 307715516c77SSepherosa Ziehau goto done; 307815516c77SSepherosa Ziehau } 3079dc13fee6SSepherosa Ziehau 3080dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc")); 30818966e5d5SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 30828966e5d5SSepherosa Ziehau ("chimney buffer is used")); 30838966e5d5SSepherosa Ziehau KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc")); 308415516c77SSepherosa Ziehau 308515516c77SSepherosa Ziehau error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs); 3086dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 308715516c77SSepherosa Ziehau int freed; 308815516c77SSepherosa Ziehau 308915516c77SSepherosa Ziehau /* 309015516c77SSepherosa Ziehau * This mbuf is not linked w/ the txd yet, so free it now. 309115516c77SSepherosa Ziehau */ 309215516c77SSepherosa Ziehau m_freem(m_head); 309315516c77SSepherosa Ziehau *m_head0 = NULL; 309415516c77SSepherosa Ziehau 309515516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 309615516c77SSepherosa Ziehau KASSERT(freed != 0, 309715516c77SSepherosa Ziehau ("fail to free txd upon txdma error")); 309815516c77SSepherosa Ziehau 309915516c77SSepherosa Ziehau txr->hn_txdma_failed++; 3100dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 310115516c77SSepherosa Ziehau return error; 310215516c77SSepherosa Ziehau } 310315516c77SSepherosa Ziehau *m_head0 = m_head; 310415516c77SSepherosa Ziehau 310515516c77SSepherosa Ziehau /* +1 RNDIS packet message */ 310615516c77SSepherosa Ziehau txr->hn_gpa_cnt = nsegs + 1; 310715516c77SSepherosa Ziehau 310815516c77SSepherosa Ziehau /* send packet with page buffer */ 310915516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr); 311015516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK; 3111dc13fee6SSepherosa Ziehau txr->hn_gpa[0].gpa_len = pkt_hlen; 311215516c77SSepherosa Ziehau 311315516c77SSepherosa Ziehau /* 311415516c77SSepherosa Ziehau * Fill the page buffers with mbuf info after the page 311515516c77SSepherosa Ziehau * buffer for RNDIS packet message. 311615516c77SSepherosa Ziehau */ 311715516c77SSepherosa Ziehau for (i = 0; i < nsegs; ++i) { 311815516c77SSepherosa Ziehau struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1]; 311915516c77SSepherosa Ziehau 312015516c77SSepherosa Ziehau gpa->gpa_page = atop(segs[i].ds_addr); 312115516c77SSepherosa Ziehau gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK; 312215516c77SSepherosa Ziehau gpa->gpa_len = segs[i].ds_len; 312315516c77SSepherosa Ziehau } 312415516c77SSepherosa Ziehau 312515516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 312615516c77SSepherosa Ziehau txd->chim_size = 0; 312715516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_sglist; 312815516c77SSepherosa Ziehau done: 312915516c77SSepherosa Ziehau txd->m = m_head; 313015516c77SSepherosa Ziehau 313115516c77SSepherosa Ziehau /* Set the completion routine */ 313215516c77SSepherosa Ziehau hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd); 313315516c77SSepherosa Ziehau 3134dc13fee6SSepherosa Ziehau /* Update temporary stats for later use. */ 3135dc13fee6SSepherosa Ziehau txr->hn_stat_pkts++; 3136dc13fee6SSepherosa Ziehau txr->hn_stat_size += m_head->m_pkthdr.len; 3137dc13fee6SSepherosa Ziehau if (m_head->m_flags & M_MCAST) 3138dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts++; 3139dc13fee6SSepherosa Ziehau 314015516c77SSepherosa Ziehau return 0; 314115516c77SSepherosa Ziehau } 314215516c77SSepherosa Ziehau 314315516c77SSepherosa Ziehau /* 314415516c77SSepherosa Ziehau * NOTE: 314515516c77SSepherosa Ziehau * If this function fails, then txd will be freed, but the mbuf 314615516c77SSepherosa Ziehau * associated w/ the txd will _not_ be freed. 314715516c77SSepherosa Ziehau */ 314815516c77SSepherosa Ziehau static int 314915516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd) 315015516c77SSepherosa Ziehau { 31518e7d3136SSepherosa Ziehau int error, send_failed = 0, has_bpf; 315215516c77SSepherosa Ziehau 315315516c77SSepherosa Ziehau again: 31548e7d3136SSepherosa Ziehau has_bpf = bpf_peers_present(ifp->if_bpf); 31558e7d3136SSepherosa Ziehau if (has_bpf) { 315615516c77SSepherosa Ziehau /* 31578e7d3136SSepherosa Ziehau * Make sure that this txd and any aggregated txds are not 31588e7d3136SSepherosa Ziehau * freed before ETHER_BPF_MTAP. 315915516c77SSepherosa Ziehau */ 316015516c77SSepherosa Ziehau hn_txdesc_hold(txd); 31618e7d3136SSepherosa Ziehau } 316215516c77SSepherosa Ziehau error = txr->hn_sendpkt(txr, txd); 316315516c77SSepherosa Ziehau if (!error) { 31648e7d3136SSepherosa Ziehau if (has_bpf) { 3165dc13fee6SSepherosa Ziehau const struct hn_txdesc *tmp_txd; 3166dc13fee6SSepherosa Ziehau 316715516c77SSepherosa Ziehau ETHER_BPF_MTAP(ifp, txd->m); 3168dc13fee6SSepherosa Ziehau STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link) 3169dc13fee6SSepherosa Ziehau ETHER_BPF_MTAP(ifp, tmp_txd->m); 3170dc13fee6SSepherosa Ziehau } 3171dc13fee6SSepherosa Ziehau 3172dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts); 317323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 317423bf9e15SSepherosa Ziehau if (!hn_use_if_start) 317523bf9e15SSepherosa Ziehau #endif 317623bf9e15SSepherosa Ziehau { 317715516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, 3178dc13fee6SSepherosa Ziehau txr->hn_stat_size); 3179dc13fee6SSepherosa Ziehau if (txr->hn_stat_mcasts != 0) { 3180dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 3181dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts); 318215516c77SSepherosa Ziehau } 3183dc13fee6SSepherosa Ziehau } 3184dc13fee6SSepherosa Ziehau txr->hn_pkts += txr->hn_stat_pkts; 3185dc13fee6SSepherosa Ziehau txr->hn_sends++; 318615516c77SSepherosa Ziehau } 31878e7d3136SSepherosa Ziehau if (has_bpf) 318815516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 318915516c77SSepherosa Ziehau 319015516c77SSepherosa Ziehau if (__predict_false(error)) { 319115516c77SSepherosa Ziehau int freed; 319215516c77SSepherosa Ziehau 319315516c77SSepherosa Ziehau /* 319415516c77SSepherosa Ziehau * This should "really rarely" happen. 319515516c77SSepherosa Ziehau * 319615516c77SSepherosa Ziehau * XXX Too many RX to be acked or too many sideband 319715516c77SSepherosa Ziehau * commands to run? Ask netvsc_channel_rollup() 319815516c77SSepherosa Ziehau * to kick start later. 319915516c77SSepherosa Ziehau */ 320015516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 320115516c77SSepherosa Ziehau if (!send_failed) { 320215516c77SSepherosa Ziehau txr->hn_send_failed++; 320315516c77SSepherosa Ziehau send_failed = 1; 320415516c77SSepherosa Ziehau /* 320515516c77SSepherosa Ziehau * Try sending again after set hn_has_txeof; 320615516c77SSepherosa Ziehau * in case that we missed the last 320715516c77SSepherosa Ziehau * netvsc_channel_rollup(). 320815516c77SSepherosa Ziehau */ 320915516c77SSepherosa Ziehau goto again; 321015516c77SSepherosa Ziehau } 321115516c77SSepherosa Ziehau if_printf(ifp, "send failed\n"); 321215516c77SSepherosa Ziehau 321315516c77SSepherosa Ziehau /* 321415516c77SSepherosa Ziehau * Caller will perform further processing on the 321515516c77SSepherosa Ziehau * associated mbuf, so don't free it in hn_txdesc_put(); 321615516c77SSepherosa Ziehau * only unload it from the DMA map in hn_txdesc_put(), 321715516c77SSepherosa Ziehau * if it was loaded. 321815516c77SSepherosa Ziehau */ 321915516c77SSepherosa Ziehau txd->m = NULL; 322015516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 322115516c77SSepherosa Ziehau KASSERT(freed != 0, 322215516c77SSepherosa Ziehau ("fail to free txd upon send error")); 322315516c77SSepherosa Ziehau 322415516c77SSepherosa Ziehau txr->hn_send_failed++; 322515516c77SSepherosa Ziehau } 3226dc13fee6SSepherosa Ziehau 3227dc13fee6SSepherosa Ziehau /* Reset temporary stats, after this sending is done. */ 3228dc13fee6SSepherosa Ziehau txr->hn_stat_size = 0; 3229dc13fee6SSepherosa Ziehau txr->hn_stat_pkts = 0; 3230dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts = 0; 3231dc13fee6SSepherosa Ziehau 3232dc13fee6SSepherosa Ziehau return (error); 323315516c77SSepherosa Ziehau } 323415516c77SSepherosa Ziehau 323515516c77SSepherosa Ziehau /* 323615516c77SSepherosa Ziehau * Append the specified data to the indicated mbuf chain, 323715516c77SSepherosa Ziehau * Extend the mbuf chain if the new data does not fit in 323815516c77SSepherosa Ziehau * existing space. 323915516c77SSepherosa Ziehau * 324015516c77SSepherosa Ziehau * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c. 324115516c77SSepherosa Ziehau * There should be an equivalent in the kernel mbuf code, 324215516c77SSepherosa Ziehau * but there does not appear to be one yet. 324315516c77SSepherosa Ziehau * 324415516c77SSepherosa Ziehau * Differs from m_append() in that additional mbufs are 324515516c77SSepherosa Ziehau * allocated with cluster size MJUMPAGESIZE, and filled 324615516c77SSepherosa Ziehau * accordingly. 324715516c77SSepherosa Ziehau * 324815516c77SSepherosa Ziehau * Return 1 if able to complete the job; otherwise 0. 324915516c77SSepherosa Ziehau */ 325015516c77SSepherosa Ziehau static int 325115516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp) 325215516c77SSepherosa Ziehau { 325315516c77SSepherosa Ziehau struct mbuf *m, *n; 325415516c77SSepherosa Ziehau int remainder, space; 325515516c77SSepherosa Ziehau 325615516c77SSepherosa Ziehau for (m = m0; m->m_next != NULL; m = m->m_next) 325715516c77SSepherosa Ziehau ; 325815516c77SSepherosa Ziehau remainder = len; 325915516c77SSepherosa Ziehau space = M_TRAILINGSPACE(m); 326015516c77SSepherosa Ziehau if (space > 0) { 326115516c77SSepherosa Ziehau /* 326215516c77SSepherosa Ziehau * Copy into available space. 326315516c77SSepherosa Ziehau */ 326415516c77SSepherosa Ziehau if (space > remainder) 326515516c77SSepherosa Ziehau space = remainder; 326615516c77SSepherosa Ziehau bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 326715516c77SSepherosa Ziehau m->m_len += space; 326815516c77SSepherosa Ziehau cp += space; 326915516c77SSepherosa Ziehau remainder -= space; 327015516c77SSepherosa Ziehau } 327115516c77SSepherosa Ziehau while (remainder > 0) { 327215516c77SSepherosa Ziehau /* 327315516c77SSepherosa Ziehau * Allocate a new mbuf; could check space 327415516c77SSepherosa Ziehau * and allocate a cluster instead. 327515516c77SSepherosa Ziehau */ 327615516c77SSepherosa Ziehau n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE); 327715516c77SSepherosa Ziehau if (n == NULL) 327815516c77SSepherosa Ziehau break; 327915516c77SSepherosa Ziehau n->m_len = min(MJUMPAGESIZE, remainder); 328015516c77SSepherosa Ziehau bcopy(cp, mtod(n, caddr_t), n->m_len); 328115516c77SSepherosa Ziehau cp += n->m_len; 328215516c77SSepherosa Ziehau remainder -= n->m_len; 328315516c77SSepherosa Ziehau m->m_next = n; 328415516c77SSepherosa Ziehau m = n; 328515516c77SSepherosa Ziehau } 328615516c77SSepherosa Ziehau if (m0->m_flags & M_PKTHDR) 328715516c77SSepherosa Ziehau m0->m_pkthdr.len += len - remainder; 328815516c77SSepherosa Ziehau 328915516c77SSepherosa Ziehau return (remainder == 0); 329015516c77SSepherosa Ziehau } 329115516c77SSepherosa Ziehau 329215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 329315516c77SSepherosa Ziehau static __inline int 329415516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m) 329515516c77SSepherosa Ziehau { 329615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 329715516c77SSepherosa Ziehau if (hn_lro_mbufq_depth) { 329815516c77SSepherosa Ziehau tcp_lro_queue_mbuf(lc, m); 329915516c77SSepherosa Ziehau return 0; 330015516c77SSepherosa Ziehau } 330115516c77SSepherosa Ziehau #endif 330215516c77SSepherosa Ziehau return tcp_lro_rx(lc, m, 0); 330315516c77SSepherosa Ziehau } 330415516c77SSepherosa Ziehau #endif 330515516c77SSepherosa Ziehau 330615516c77SSepherosa Ziehau static int 330715516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, 330815516c77SSepherosa Ziehau const struct hn_rxinfo *info) 330915516c77SSepherosa Ziehau { 3310a97fff19SSepherosa Ziehau struct ifnet *ifp, *hn_ifp = rxr->hn_ifp; 331115516c77SSepherosa Ziehau struct mbuf *m_new; 3312642ec226SSepherosa Ziehau int size, do_lro = 0, do_csum = 1, is_vf = 0; 3313642ec226SSepherosa Ziehau int hash_type = M_HASHTYPE_NONE; 331415516c77SSepherosa Ziehau 3315642ec226SSepherosa Ziehau ifp = hn_ifp; 3316642ec226SSepherosa Ziehau if (rxr->hn_rxvf_ifp != NULL) { 3317a97fff19SSepherosa Ziehau /* 3318642ec226SSepherosa Ziehau * Non-transparent mode VF; pretend this packet is from 3319642ec226SSepherosa Ziehau * the VF. 3320a97fff19SSepherosa Ziehau */ 3321642ec226SSepherosa Ziehau ifp = rxr->hn_rxvf_ifp; 3322642ec226SSepherosa Ziehau is_vf = 1; 3323642ec226SSepherosa Ziehau } else if (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF) { 3324642ec226SSepherosa Ziehau /* Transparent mode VF. */ 3325642ec226SSepherosa Ziehau is_vf = 1; 3326642ec226SSepherosa Ziehau } 33275bdfd3fdSDexuan Cui 3328b3b75d9cSSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 3329b3b75d9cSSepherosa Ziehau /* 3330b3b75d9cSSepherosa Ziehau * NOTE: 3331b3b75d9cSSepherosa Ziehau * See the NOTE of hn_rndis_init_fixat(). This 3332b3b75d9cSSepherosa Ziehau * function can be reached, immediately after the 3333b3b75d9cSSepherosa Ziehau * RNDIS is initialized but before the ifnet is 3334b3b75d9cSSepherosa Ziehau * setup on the hn_attach() path; drop the unexpected 3335b3b75d9cSSepherosa Ziehau * packets. 3336b3b75d9cSSepherosa Ziehau */ 3337b3b75d9cSSepherosa Ziehau return (0); 3338b3b75d9cSSepherosa Ziehau } 3339b3b75d9cSSepherosa Ziehau 3340a97fff19SSepherosa Ziehau if (__predict_false(dlen < ETHER_HDR_LEN)) { 3341a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1); 3342a97fff19SSepherosa Ziehau return (0); 3343a97fff19SSepherosa Ziehau } 3344a97fff19SSepherosa Ziehau 3345c927d681SDexuan Cui if (dlen <= MHLEN) { 334615516c77SSepherosa Ziehau m_new = m_gethdr(M_NOWAIT, MT_DATA); 334715516c77SSepherosa Ziehau if (m_new == NULL) { 3348a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1); 334915516c77SSepherosa Ziehau return (0); 335015516c77SSepherosa Ziehau } 335115516c77SSepherosa Ziehau memcpy(mtod(m_new, void *), data, dlen); 335215516c77SSepherosa Ziehau m_new->m_pkthdr.len = m_new->m_len = dlen; 335315516c77SSepherosa Ziehau rxr->hn_small_pkts++; 335415516c77SSepherosa Ziehau } else { 335515516c77SSepherosa Ziehau /* 335615516c77SSepherosa Ziehau * Get an mbuf with a cluster. For packets 2K or less, 335715516c77SSepherosa Ziehau * get a standard 2K cluster. For anything larger, get a 335815516c77SSepherosa Ziehau * 4K cluster. Any buffers larger than 4K can cause problems 335915516c77SSepherosa Ziehau * if looped around to the Hyper-V TX channel, so avoid them. 336015516c77SSepherosa Ziehau */ 336115516c77SSepherosa Ziehau size = MCLBYTES; 336215516c77SSepherosa Ziehau if (dlen > MCLBYTES) { 336315516c77SSepherosa Ziehau /* 4096 */ 336415516c77SSepherosa Ziehau size = MJUMPAGESIZE; 336515516c77SSepherosa Ziehau } 336615516c77SSepherosa Ziehau 336715516c77SSepherosa Ziehau m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size); 336815516c77SSepherosa Ziehau if (m_new == NULL) { 3369a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1); 337015516c77SSepherosa Ziehau return (0); 337115516c77SSepherosa Ziehau } 337215516c77SSepherosa Ziehau 337315516c77SSepherosa Ziehau hv_m_append(m_new, dlen, data); 337415516c77SSepherosa Ziehau } 337515516c77SSepherosa Ziehau m_new->m_pkthdr.rcvif = ifp; 337615516c77SSepherosa Ziehau 3377a97fff19SSepherosa Ziehau if (__predict_false((hn_ifp->if_capenable & IFCAP_RXCSUM) == 0)) 337815516c77SSepherosa Ziehau do_csum = 0; 337915516c77SSepherosa Ziehau 338015516c77SSepherosa Ziehau /* receive side checksum offload */ 338115516c77SSepherosa Ziehau if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) { 338215516c77SSepherosa Ziehau /* IP csum offload */ 338315516c77SSepherosa Ziehau if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) { 338415516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 338515516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 338615516c77SSepherosa Ziehau rxr->hn_csum_ip++; 338715516c77SSepherosa Ziehau } 338815516c77SSepherosa Ziehau 338915516c77SSepherosa Ziehau /* TCP/UDP csum offload */ 339015516c77SSepherosa Ziehau if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK | 339115516c77SSepherosa Ziehau NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) { 339215516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 339315516c77SSepherosa Ziehau (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 339415516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 339515516c77SSepherosa Ziehau if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK) 339615516c77SSepherosa Ziehau rxr->hn_csum_tcp++; 339715516c77SSepherosa Ziehau else 339815516c77SSepherosa Ziehau rxr->hn_csum_udp++; 339915516c77SSepherosa Ziehau } 340015516c77SSepherosa Ziehau 340115516c77SSepherosa Ziehau /* 340215516c77SSepherosa Ziehau * XXX 340315516c77SSepherosa Ziehau * As of this write (Oct 28th, 2016), host side will turn 340415516c77SSepherosa Ziehau * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so 340515516c77SSepherosa Ziehau * the do_lro setting here is actually _not_ accurate. We 340615516c77SSepherosa Ziehau * depend on the RSS hash type check to reset do_lro. 340715516c77SSepherosa Ziehau */ 340815516c77SSepherosa Ziehau if ((info->csum_info & 340915516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) == 341015516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) 341115516c77SSepherosa Ziehau do_lro = 1; 341215516c77SSepherosa Ziehau } else { 341315516c77SSepherosa Ziehau const struct ether_header *eh; 341415516c77SSepherosa Ziehau uint16_t etype; 341515516c77SSepherosa Ziehau int hoff; 341615516c77SSepherosa Ziehau 341715516c77SSepherosa Ziehau hoff = sizeof(*eh); 3418a97fff19SSepherosa Ziehau /* Checked at the beginning of this function. */ 3419a97fff19SSepherosa Ziehau KASSERT(m_new->m_len >= hoff, ("not ethernet frame")); 3420a97fff19SSepherosa Ziehau 342115516c77SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 342215516c77SSepherosa Ziehau etype = ntohs(eh->ether_type); 342315516c77SSepherosa Ziehau if (etype == ETHERTYPE_VLAN) { 342415516c77SSepherosa Ziehau const struct ether_vlan_header *evl; 342515516c77SSepherosa Ziehau 342615516c77SSepherosa Ziehau hoff = sizeof(*evl); 342715516c77SSepherosa Ziehau if (m_new->m_len < hoff) 342815516c77SSepherosa Ziehau goto skip; 342915516c77SSepherosa Ziehau evl = mtod(m_new, struct ether_vlan_header *); 343015516c77SSepherosa Ziehau etype = ntohs(evl->evl_proto); 343115516c77SSepherosa Ziehau } 343215516c77SSepherosa Ziehau 343315516c77SSepherosa Ziehau if (etype == ETHERTYPE_IP) { 343415516c77SSepherosa Ziehau int pr; 343515516c77SSepherosa Ziehau 343615516c77SSepherosa Ziehau pr = hn_check_iplen(m_new, hoff); 343715516c77SSepherosa Ziehau if (pr == IPPROTO_TCP) { 343815516c77SSepherosa Ziehau if (do_csum && 343915516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 344015516c77SSepherosa Ziehau HN_TRUST_HCSUM_TCP)) { 344115516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 344215516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 344315516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 344415516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 344515516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 344615516c77SSepherosa Ziehau } 344715516c77SSepherosa Ziehau do_lro = 1; 344815516c77SSepherosa Ziehau } else if (pr == IPPROTO_UDP) { 344915516c77SSepherosa Ziehau if (do_csum && 345015516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 345115516c77SSepherosa Ziehau HN_TRUST_HCSUM_UDP)) { 345215516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 345315516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 345415516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 345515516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 345615516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 345715516c77SSepherosa Ziehau } 345815516c77SSepherosa Ziehau } else if (pr != IPPROTO_DONE && do_csum && 345915516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) { 346015516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 346115516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 346215516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 346315516c77SSepherosa Ziehau } 346415516c77SSepherosa Ziehau } 346515516c77SSepherosa Ziehau } 346615516c77SSepherosa Ziehau skip: 346715516c77SSepherosa Ziehau if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) { 346815516c77SSepherosa Ziehau m_new->m_pkthdr.ether_vtag = EVL_MAKETAG( 346915516c77SSepherosa Ziehau NDIS_VLAN_INFO_ID(info->vlan_info), 347015516c77SSepherosa Ziehau NDIS_VLAN_INFO_PRI(info->vlan_info), 347115516c77SSepherosa Ziehau NDIS_VLAN_INFO_CFI(info->vlan_info)); 347215516c77SSepherosa Ziehau m_new->m_flags |= M_VLANTAG; 347315516c77SSepherosa Ziehau } 347415516c77SSepherosa Ziehau 3475a97fff19SSepherosa Ziehau /* 3476a97fff19SSepherosa Ziehau * If VF is activated (tranparent/non-transparent mode does not 3477a97fff19SSepherosa Ziehau * matter here). 3478a97fff19SSepherosa Ziehau * 3479a97fff19SSepherosa Ziehau * - Disable LRO 3480a97fff19SSepherosa Ziehau * 3481a97fff19SSepherosa Ziehau * hn(4) will only receive broadcast packets, multicast packets, 3482a97fff19SSepherosa Ziehau * TCP SYN and SYN|ACK (in Azure), LRO is useless for these 3483a97fff19SSepherosa Ziehau * packet types. 3484a97fff19SSepherosa Ziehau * 3485a97fff19SSepherosa Ziehau * For non-transparent, we definitely _cannot_ enable LRO at 3486a97fff19SSepherosa Ziehau * all, since the LRO flush will use hn(4) as the receiving 3487a97fff19SSepherosa Ziehau * interface; i.e. hn_ifp->if_input(hn_ifp, m). 3488a97fff19SSepherosa Ziehau */ 3489642ec226SSepherosa Ziehau if (is_vf) 3490642ec226SSepherosa Ziehau do_lro = 0; 3491a97fff19SSepherosa Ziehau 3492642ec226SSepherosa Ziehau /* 3493642ec226SSepherosa Ziehau * If VF is activated (tranparent/non-transparent mode does not 3494642ec226SSepherosa Ziehau * matter here), do _not_ mess with unsupported hash types or 3495642ec226SSepherosa Ziehau * functions. 3496642ec226SSepherosa Ziehau */ 349715516c77SSepherosa Ziehau if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) { 349815516c77SSepherosa Ziehau rxr->hn_rss_pkts++; 349915516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = info->hash_value; 3500642ec226SSepherosa Ziehau if (!is_vf) 350115516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE_HASH; 350215516c77SSepherosa Ziehau if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) == 350315516c77SSepherosa Ziehau NDIS_HASH_FUNCTION_TOEPLITZ) { 3504642ec226SSepherosa Ziehau uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK & 3505642ec226SSepherosa Ziehau rxr->hn_mbuf_hash); 350615516c77SSepherosa Ziehau 350715516c77SSepherosa Ziehau /* 350815516c77SSepherosa Ziehau * NOTE: 350915516c77SSepherosa Ziehau * do_lro is resetted, if the hash types are not TCP 351015516c77SSepherosa Ziehau * related. See the comment in the above csum_flags 351115516c77SSepherosa Ziehau * setup section. 351215516c77SSepherosa Ziehau */ 351315516c77SSepherosa Ziehau switch (type) { 351415516c77SSepherosa Ziehau case NDIS_HASH_IPV4: 351515516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV4; 351615516c77SSepherosa Ziehau do_lro = 0; 351715516c77SSepherosa Ziehau break; 351815516c77SSepherosa Ziehau 351915516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV4: 352015516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV4; 352115516c77SSepherosa Ziehau break; 352215516c77SSepherosa Ziehau 352315516c77SSepherosa Ziehau case NDIS_HASH_IPV6: 352415516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6; 352515516c77SSepherosa Ziehau do_lro = 0; 352615516c77SSepherosa Ziehau break; 352715516c77SSepherosa Ziehau 352815516c77SSepherosa Ziehau case NDIS_HASH_IPV6_EX: 352915516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6_EX; 353015516c77SSepherosa Ziehau do_lro = 0; 353115516c77SSepherosa Ziehau break; 353215516c77SSepherosa Ziehau 353315516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6: 353415516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6; 353515516c77SSepherosa Ziehau break; 353615516c77SSepherosa Ziehau 353715516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6_EX: 353815516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX; 353915516c77SSepherosa Ziehau break; 354015516c77SSepherosa Ziehau } 354115516c77SSepherosa Ziehau } 3542642ec226SSepherosa Ziehau } else if (!is_vf) { 354315516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = rxr->hn_rx_idx; 354415516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE; 354515516c77SSepherosa Ziehau } 354615516c77SSepherosa Ziehau M_HASHTYPE_SET(m_new, hash_type); 354715516c77SSepherosa Ziehau 3548a97fff19SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 3549a97fff19SSepherosa Ziehau if (hn_ifp != ifp) { 3550a97fff19SSepherosa Ziehau const struct ether_header *eh; 3551a97fff19SSepherosa Ziehau 355215516c77SSepherosa Ziehau /* 3553a97fff19SSepherosa Ziehau * Non-transparent mode VF is activated. 355415516c77SSepherosa Ziehau */ 355515516c77SSepherosa Ziehau 3556a97fff19SSepherosa Ziehau /* 3557a97fff19SSepherosa Ziehau * Allow tapping on hn(4). 3558a97fff19SSepherosa Ziehau */ 3559a97fff19SSepherosa Ziehau ETHER_BPF_MTAP(hn_ifp, m_new); 3560a97fff19SSepherosa Ziehau 3561a97fff19SSepherosa Ziehau /* 3562a97fff19SSepherosa Ziehau * Update hn(4)'s stats. 3563a97fff19SSepherosa Ziehau */ 3564a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1); 3565a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len); 3566a97fff19SSepherosa Ziehau /* Checked at the beginning of this function. */ 3567a97fff19SSepherosa Ziehau KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame")); 3568a97fff19SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 3569a97fff19SSepherosa Ziehau if (ETHER_IS_MULTICAST(eh->ether_dhost)) 3570a97fff19SSepherosa Ziehau if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1); 3571a97fff19SSepherosa Ziehau } 357215516c77SSepherosa Ziehau rxr->hn_pkts++; 357315516c77SSepherosa Ziehau 3574a97fff19SSepherosa Ziehau if ((hn_ifp->if_capenable & IFCAP_LRO) && do_lro) { 357515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 357615516c77SSepherosa Ziehau struct lro_ctrl *lro = &rxr->hn_lro; 357715516c77SSepherosa Ziehau 357815516c77SSepherosa Ziehau if (lro->lro_cnt) { 357915516c77SSepherosa Ziehau rxr->hn_lro_tried++; 358015516c77SSepherosa Ziehau if (hn_lro_rx(lro, m_new) == 0) { 358115516c77SSepherosa Ziehau /* DONE! */ 358215516c77SSepherosa Ziehau return 0; 358315516c77SSepherosa Ziehau } 358415516c77SSepherosa Ziehau } 358515516c77SSepherosa Ziehau #endif 358615516c77SSepherosa Ziehau } 3587a97fff19SSepherosa Ziehau ifp->if_input(ifp, m_new); 358815516c77SSepherosa Ziehau 358915516c77SSepherosa Ziehau return (0); 359015516c77SSepherosa Ziehau } 359115516c77SSepherosa Ziehau 359215516c77SSepherosa Ziehau static int 359315516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 359415516c77SSepherosa Ziehau { 359515516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 35969c6cae24SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data, ifr_vf; 35979c6cae24SSepherosa Ziehau struct ifnet *vf_ifp; 359815516c77SSepherosa Ziehau int mask, error = 0; 35998c068aa5SSepherosa Ziehau struct ifrsskey *ifrk; 36008c068aa5SSepherosa Ziehau struct ifrsshash *ifrh; 3601*eb2fe044SSepherosa Ziehau uint32_t mtu; 360215516c77SSepherosa Ziehau 360315516c77SSepherosa Ziehau switch (cmd) { 360415516c77SSepherosa Ziehau case SIOCSIFMTU: 360515516c77SSepherosa Ziehau if (ifr->ifr_mtu > HN_MTU_MAX) { 360615516c77SSepherosa Ziehau error = EINVAL; 360715516c77SSepherosa Ziehau break; 360815516c77SSepherosa Ziehau } 360915516c77SSepherosa Ziehau 361015516c77SSepherosa Ziehau HN_LOCK(sc); 361115516c77SSepherosa Ziehau 361215516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 361315516c77SSepherosa Ziehau HN_UNLOCK(sc); 361415516c77SSepherosa Ziehau break; 361515516c77SSepherosa Ziehau } 361615516c77SSepherosa Ziehau 361715516c77SSepherosa Ziehau if ((sc->hn_caps & HN_CAP_MTU) == 0) { 361815516c77SSepherosa Ziehau /* Can't change MTU */ 361915516c77SSepherosa Ziehau HN_UNLOCK(sc); 362015516c77SSepherosa Ziehau error = EOPNOTSUPP; 362115516c77SSepherosa Ziehau break; 362215516c77SSepherosa Ziehau } 362315516c77SSepherosa Ziehau 362415516c77SSepherosa Ziehau if (ifp->if_mtu == ifr->ifr_mtu) { 362515516c77SSepherosa Ziehau HN_UNLOCK(sc); 362615516c77SSepherosa Ziehau break; 362715516c77SSepherosa Ziehau } 362815516c77SSepherosa Ziehau 36299c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 36309c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 36319c6cae24SSepherosa Ziehau ifr_vf = *ifr; 36329c6cae24SSepherosa Ziehau strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname, 36339c6cae24SSepherosa Ziehau sizeof(ifr_vf.ifr_name)); 36349c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, 36359c6cae24SSepherosa Ziehau (caddr_t)&ifr_vf); 36369c6cae24SSepherosa Ziehau if (error) { 36379c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 36389c6cae24SSepherosa Ziehau if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n", 36399c6cae24SSepherosa Ziehau vf_ifp->if_xname, ifr->ifr_mtu, error); 36409c6cae24SSepherosa Ziehau break; 36419c6cae24SSepherosa Ziehau } 36429c6cae24SSepherosa Ziehau } 36439c6cae24SSepherosa Ziehau 364415516c77SSepherosa Ziehau /* 364515516c77SSepherosa Ziehau * Suspend this interface before the synthetic parts 364615516c77SSepherosa Ziehau * are ripped. 364715516c77SSepherosa Ziehau */ 364815516c77SSepherosa Ziehau hn_suspend(sc); 364915516c77SSepherosa Ziehau 365015516c77SSepherosa Ziehau /* 365115516c77SSepherosa Ziehau * Detach the synthetics parts, i.e. NVS and RNDIS. 365215516c77SSepherosa Ziehau */ 365315516c77SSepherosa Ziehau hn_synth_detach(sc); 365415516c77SSepherosa Ziehau 365515516c77SSepherosa Ziehau /* 365615516c77SSepherosa Ziehau * Reattach the synthetic parts, i.e. NVS and RNDIS, 365715516c77SSepherosa Ziehau * with the new MTU setting. 365815516c77SSepherosa Ziehau */ 365915516c77SSepherosa Ziehau error = hn_synth_attach(sc, ifr->ifr_mtu); 366015516c77SSepherosa Ziehau if (error) { 366115516c77SSepherosa Ziehau HN_UNLOCK(sc); 366215516c77SSepherosa Ziehau break; 366315516c77SSepherosa Ziehau } 366415516c77SSepherosa Ziehau 3665*eb2fe044SSepherosa Ziehau error = hn_rndis_get_mtu(sc, &mtu); 3666*eb2fe044SSepherosa Ziehau if (error) 3667*eb2fe044SSepherosa Ziehau mtu = ifr->ifr_mtu; 3668*eb2fe044SSepherosa Ziehau else if (bootverbose) 3669*eb2fe044SSepherosa Ziehau if_printf(ifp, "RNDIS mtu %u\n", mtu); 3670*eb2fe044SSepherosa Ziehau 367115516c77SSepherosa Ziehau /* 367215516c77SSepherosa Ziehau * Commit the requested MTU, after the synthetic parts 367315516c77SSepherosa Ziehau * have been successfully attached. 367415516c77SSepherosa Ziehau */ 3675*eb2fe044SSepherosa Ziehau if (mtu >= ifr->ifr_mtu) { 3676*eb2fe044SSepherosa Ziehau mtu = ifr->ifr_mtu; 3677*eb2fe044SSepherosa Ziehau } else { 3678*eb2fe044SSepherosa Ziehau if_printf(ifp, "fixup mtu %d -> %u\n", 3679*eb2fe044SSepherosa Ziehau ifr->ifr_mtu, mtu); 3680*eb2fe044SSepherosa Ziehau } 3681*eb2fe044SSepherosa Ziehau ifp->if_mtu = mtu; 368215516c77SSepherosa Ziehau 368315516c77SSepherosa Ziehau /* 36849c6cae24SSepherosa Ziehau * Synthetic parts' reattach may change the chimney 36859c6cae24SSepherosa Ziehau * sending size; update it. 368615516c77SSepherosa Ziehau */ 368715516c77SSepherosa Ziehau if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax) 368815516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 36899c6cae24SSepherosa Ziehau 36909c6cae24SSepherosa Ziehau /* 36919c6cae24SSepherosa Ziehau * Make sure that various parameters based on MTU are 36929c6cae24SSepherosa Ziehau * still valid, after the MTU change. 36939c6cae24SSepherosa Ziehau */ 36949c6cae24SSepherosa Ziehau hn_mtu_change_fixup(sc); 369515516c77SSepherosa Ziehau 369615516c77SSepherosa Ziehau /* 369715516c77SSepherosa Ziehau * All done! Resume the interface now. 369815516c77SSepherosa Ziehau */ 369915516c77SSepherosa Ziehau hn_resume(sc); 370015516c77SSepherosa Ziehau 3701d0cd8231SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) || 3702d0cd8231SSepherosa Ziehau (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { 37039c6cae24SSepherosa Ziehau /* 37049c6cae24SSepherosa Ziehau * Since we have reattached the NVS part, 37059c6cae24SSepherosa Ziehau * change the datapath to VF again; in case 37069c6cae24SSepherosa Ziehau * that it is lost, after the NVS was detached. 37079c6cae24SSepherosa Ziehau */ 37089c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF); 37099c6cae24SSepherosa Ziehau } 37109c6cae24SSepherosa Ziehau 371115516c77SSepherosa Ziehau HN_UNLOCK(sc); 371215516c77SSepherosa Ziehau break; 371315516c77SSepherosa Ziehau 371415516c77SSepherosa Ziehau case SIOCSIFFLAGS: 371515516c77SSepherosa Ziehau HN_LOCK(sc); 371615516c77SSepherosa Ziehau 371715516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 371815516c77SSepherosa Ziehau HN_UNLOCK(sc); 371915516c77SSepherosa Ziehau break; 372015516c77SSepherosa Ziehau } 372115516c77SSepherosa Ziehau 37229c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) 37239c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 37249c6cae24SSepherosa Ziehau 372515516c77SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 3726fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3727fdc4f478SSepherosa Ziehau /* 3728fdc4f478SSepherosa Ziehau * Caller meight hold mutex, e.g. 3729fdc4f478SSepherosa Ziehau * bpf; use busy-wait for the RNDIS 3730fdc4f478SSepherosa Ziehau * reply. 3731fdc4f478SSepherosa Ziehau */ 3732fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 3733c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 3734fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 37359c6cae24SSepherosa Ziehau 37369c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 37379c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 3738fdc4f478SSepherosa Ziehau } else { 373915516c77SSepherosa Ziehau hn_init_locked(sc); 3740fdc4f478SSepherosa Ziehau } 374115516c77SSepherosa Ziehau } else { 374215516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 37435bdfd3fdSDexuan Cui hn_stop(sc, false); 374415516c77SSepherosa Ziehau } 374515516c77SSepherosa Ziehau sc->hn_if_flags = ifp->if_flags; 374615516c77SSepherosa Ziehau 374715516c77SSepherosa Ziehau HN_UNLOCK(sc); 374815516c77SSepherosa Ziehau break; 374915516c77SSepherosa Ziehau 375015516c77SSepherosa Ziehau case SIOCSIFCAP: 375115516c77SSepherosa Ziehau HN_LOCK(sc); 37529c6cae24SSepherosa Ziehau 37539c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 37549c6cae24SSepherosa Ziehau ifr_vf = *ifr; 37559c6cae24SSepherosa Ziehau strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname, 37569c6cae24SSepherosa Ziehau sizeof(ifr_vf.ifr_name)); 37579c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf); 37589c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 37599c6cae24SSepherosa Ziehau break; 37609c6cae24SSepherosa Ziehau } 37619c6cae24SSepherosa Ziehau 37629c6cae24SSepherosa Ziehau /* 37639c6cae24SSepherosa Ziehau * Fix up requested capabilities w/ supported capabilities, 37649c6cae24SSepherosa Ziehau * since the supported capabilities could have been changed. 37659c6cae24SSepherosa Ziehau */ 37669c6cae24SSepherosa Ziehau mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^ 37679c6cae24SSepherosa Ziehau ifp->if_capenable; 376815516c77SSepherosa Ziehau 376915516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM) { 377015516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 377115516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 377215516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc); 377315516c77SSepherosa Ziehau else 377415516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc); 377515516c77SSepherosa Ziehau } 377615516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM_IPV6) { 377715516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 377815516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 377915516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc); 378015516c77SSepherosa Ziehau else 378115516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc); 378215516c77SSepherosa Ziehau } 378315516c77SSepherosa Ziehau 378415516c77SSepherosa Ziehau /* TODO: flip RNDIS offload parameters for RXCSUM. */ 378515516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 378615516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 378715516c77SSepherosa Ziehau #ifdef foo 378815516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 378915516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM_IPV6) 379015516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 379115516c77SSepherosa Ziehau #endif 379215516c77SSepherosa Ziehau 379315516c77SSepherosa Ziehau if (mask & IFCAP_LRO) 379415516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_LRO; 379515516c77SSepherosa Ziehau 379615516c77SSepherosa Ziehau if (mask & IFCAP_TSO4) { 379715516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO4; 379815516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 379915516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 380015516c77SSepherosa Ziehau else 380115516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP_TSO; 380215516c77SSepherosa Ziehau } 380315516c77SSepherosa Ziehau if (mask & IFCAP_TSO6) { 380415516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO6; 380515516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 380615516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 380715516c77SSepherosa Ziehau else 380815516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP6_TSO; 380915516c77SSepherosa Ziehau } 381015516c77SSepherosa Ziehau 381115516c77SSepherosa Ziehau HN_UNLOCK(sc); 381215516c77SSepherosa Ziehau break; 381315516c77SSepherosa Ziehau 381415516c77SSepherosa Ziehau case SIOCADDMULTI: 381515516c77SSepherosa Ziehau case SIOCDELMULTI: 381615516c77SSepherosa Ziehau HN_LOCK(sc); 381715516c77SSepherosa Ziehau 381815516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 381915516c77SSepherosa Ziehau HN_UNLOCK(sc); 382015516c77SSepherosa Ziehau break; 382115516c77SSepherosa Ziehau } 3822fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3823fdc4f478SSepherosa Ziehau /* 3824fdc4f478SSepherosa Ziehau * Multicast uses mutex; use busy-wait for 3825fdc4f478SSepherosa Ziehau * the RNDIS reply. 3826fdc4f478SSepherosa Ziehau */ 3827fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 3828c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 3829fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 3830fdc4f478SSepherosa Ziehau } 383115516c77SSepherosa Ziehau 38329c6cae24SSepherosa Ziehau /* XXX vlan(4) style mcast addr maintenance */ 38339c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 38349c6cae24SSepherosa Ziehau int old_if_flags; 38359c6cae24SSepherosa Ziehau 38369c6cae24SSepherosa Ziehau old_if_flags = sc->hn_vf_ifp->if_flags; 38379c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 38389c6cae24SSepherosa Ziehau 38399c6cae24SSepherosa Ziehau if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) && 38409c6cae24SSepherosa Ziehau ((old_if_flags ^ sc->hn_vf_ifp->if_flags) & 38419c6cae24SSepherosa Ziehau IFF_ALLMULTI)) 38429c6cae24SSepherosa Ziehau error = hn_xpnt_vf_iocsetflags(sc); 38439c6cae24SSepherosa Ziehau } 38449c6cae24SSepherosa Ziehau 384515516c77SSepherosa Ziehau HN_UNLOCK(sc); 384615516c77SSepherosa Ziehau break; 384715516c77SSepherosa Ziehau 384815516c77SSepherosa Ziehau case SIOCSIFMEDIA: 384915516c77SSepherosa Ziehau case SIOCGIFMEDIA: 38509c6cae24SSepherosa Ziehau HN_LOCK(sc); 38519c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 38529c6cae24SSepherosa Ziehau /* 38539c6cae24SSepherosa Ziehau * SIOCGIFMEDIA expects ifmediareq, so don't 38549c6cae24SSepherosa Ziehau * create and pass ifr_vf to the VF here; just 38559c6cae24SSepherosa Ziehau * replace the ifr_name. 38569c6cae24SSepherosa Ziehau */ 38579c6cae24SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 38589c6cae24SSepherosa Ziehau strlcpy(ifr->ifr_name, vf_ifp->if_xname, 38599c6cae24SSepherosa Ziehau sizeof(ifr->ifr_name)); 38609c6cae24SSepherosa Ziehau error = vf_ifp->if_ioctl(vf_ifp, cmd, data); 38619c6cae24SSepherosa Ziehau /* Restore the ifr_name. */ 38629c6cae24SSepherosa Ziehau strlcpy(ifr->ifr_name, ifp->if_xname, 38639c6cae24SSepherosa Ziehau sizeof(ifr->ifr_name)); 38649c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 38659c6cae24SSepherosa Ziehau break; 38669c6cae24SSepherosa Ziehau } 38679c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 386815516c77SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd); 386915516c77SSepherosa Ziehau break; 387015516c77SSepherosa Ziehau 38718c068aa5SSepherosa Ziehau case SIOCGIFRSSHASH: 38728c068aa5SSepherosa Ziehau ifrh = (struct ifrsshash *)data; 38738c068aa5SSepherosa Ziehau HN_LOCK(sc); 38748c068aa5SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 38758c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 38768c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_NONE; 38778c068aa5SSepherosa Ziehau ifrh->ifrh_types = 0; 38788c068aa5SSepherosa Ziehau break; 38798c068aa5SSepherosa Ziehau } 38808c068aa5SSepherosa Ziehau 38818c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ) 38828c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_TOEPLITZ; 38838c068aa5SSepherosa Ziehau else 38848c068aa5SSepherosa Ziehau ifrh->ifrh_func = RSS_FUNC_PRIVATE; 3885642ec226SSepherosa Ziehau ifrh->ifrh_types = hn_rss_type_fromndis(sc->hn_rss_hash); 38868c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 38878c068aa5SSepherosa Ziehau break; 38888c068aa5SSepherosa Ziehau 38898c068aa5SSepherosa Ziehau case SIOCGIFRSSKEY: 38908c068aa5SSepherosa Ziehau ifrk = (struct ifrsskey *)data; 38918c068aa5SSepherosa Ziehau HN_LOCK(sc); 38928c068aa5SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 38938c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 38948c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_NONE; 38958c068aa5SSepherosa Ziehau ifrk->ifrk_keylen = 0; 38968c068aa5SSepherosa Ziehau break; 38978c068aa5SSepherosa Ziehau } 38988c068aa5SSepherosa Ziehau if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ) 38998c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_TOEPLITZ; 39008c068aa5SSepherosa Ziehau else 39018c068aa5SSepherosa Ziehau ifrk->ifrk_func = RSS_FUNC_PRIVATE; 39028c068aa5SSepherosa Ziehau ifrk->ifrk_keylen = NDIS_HASH_KEYSIZE_TOEPLITZ; 39038c068aa5SSepherosa Ziehau memcpy(ifrk->ifrk_key, sc->hn_rss.rss_key, 39048c068aa5SSepherosa Ziehau NDIS_HASH_KEYSIZE_TOEPLITZ); 39058c068aa5SSepherosa Ziehau HN_UNLOCK(sc); 39068c068aa5SSepherosa Ziehau break; 39078c068aa5SSepherosa Ziehau 390815516c77SSepherosa Ziehau default: 390915516c77SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 391015516c77SSepherosa Ziehau break; 391115516c77SSepherosa Ziehau } 391215516c77SSepherosa Ziehau return (error); 391315516c77SSepherosa Ziehau } 391415516c77SSepherosa Ziehau 391515516c77SSepherosa Ziehau static void 39165bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching) 391715516c77SSepherosa Ziehau { 391815516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 391915516c77SSepherosa Ziehau int i; 392015516c77SSepherosa Ziehau 392115516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 392215516c77SSepherosa Ziehau 392315516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 392415516c77SSepherosa Ziehau ("synthetic parts were not attached")); 392515516c77SSepherosa Ziehau 39269c6cae24SSepherosa Ziehau /* Clear RUNNING bit ASAP. */ 39279c6cae24SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 39289c6cae24SSepherosa Ziehau 39296c1204dfSSepherosa Ziehau /* Disable polling. */ 39306c1204dfSSepherosa Ziehau hn_polling(sc, 0); 39316c1204dfSSepherosa Ziehau 39329c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) { 39339c6cae24SSepherosa Ziehau KASSERT(sc->hn_vf_ifp != NULL, 39349c6cae24SSepherosa Ziehau ("%s: VF is not attached", ifp->if_xname)); 39359c6cae24SSepherosa Ziehau 3936a97fff19SSepherosa Ziehau /* Mark transparent mode VF as disabled. */ 3937a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */); 39389c6cae24SSepherosa Ziehau 39399c6cae24SSepherosa Ziehau /* 39409c6cae24SSepherosa Ziehau * NOTE: 39419c6cae24SSepherosa Ziehau * Datapath setting must happen _before_ bringing 39429c6cae24SSepherosa Ziehau * the VF down. 39439c6cae24SSepherosa Ziehau */ 39449c6cae24SSepherosa Ziehau hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH); 39459c6cae24SSepherosa Ziehau 39469c6cae24SSepherosa Ziehau /* 39479c6cae24SSepherosa Ziehau * Bring the VF down. 39489c6cae24SSepherosa Ziehau */ 39499c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(sc); 39509c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_flags &= ~IFF_UP; 39519c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(sc); 39529c6cae24SSepherosa Ziehau } 39539c6cae24SSepherosa Ziehau 39549c6cae24SSepherosa Ziehau /* Suspend data transfers. */ 395515516c77SSepherosa Ziehau hn_suspend_data(sc); 395615516c77SSepherosa Ziehau 395715516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 395815516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 395915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 396015516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 39615bdfd3fdSDexuan Cui 39625bdfd3fdSDexuan Cui /* 39639c6cae24SSepherosa Ziehau * If the non-transparent mode VF is active, make sure 39649c6cae24SSepherosa Ziehau * that the RX filter still allows packet reception. 39655bdfd3fdSDexuan Cui */ 3966962f0357SSepherosa Ziehau if (!detaching && (sc->hn_flags & HN_FLAG_RXVF)) 39675bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 396815516c77SSepherosa Ziehau } 396915516c77SSepherosa Ziehau 397015516c77SSepherosa Ziehau static void 397115516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc) 397215516c77SSepherosa Ziehau { 397315516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 397415516c77SSepherosa Ziehau int i; 397515516c77SSepherosa Ziehau 397615516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 397715516c77SSepherosa Ziehau 397815516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 397915516c77SSepherosa Ziehau return; 398015516c77SSepherosa Ziehau 398115516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 398215516c77SSepherosa Ziehau return; 398315516c77SSepherosa Ziehau 398415516c77SSepherosa Ziehau /* Configure RX filter */ 3985c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 398615516c77SSepherosa Ziehau 398715516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 398815516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 398915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 399015516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 399115516c77SSepherosa Ziehau 399215516c77SSepherosa Ziehau /* Clear TX 'suspended' bit. */ 399315516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_inuse); 399415516c77SSepherosa Ziehau 39959c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 39969c6cae24SSepherosa Ziehau /* Initialize transparent VF. */ 39979c6cae24SSepherosa Ziehau hn_xpnt_vf_init(sc); 39989c6cae24SSepherosa Ziehau } 39999c6cae24SSepherosa Ziehau 400015516c77SSepherosa Ziehau /* Everything is ready; unleash! */ 400115516c77SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 40026c1204dfSSepherosa Ziehau 40036c1204dfSSepherosa Ziehau /* Re-enable polling if requested. */ 40046c1204dfSSepherosa Ziehau if (sc->hn_pollhz > 0) 40056c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 400615516c77SSepherosa Ziehau } 400715516c77SSepherosa Ziehau 400815516c77SSepherosa Ziehau static void 400915516c77SSepherosa Ziehau hn_init(void *xsc) 401015516c77SSepherosa Ziehau { 401115516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 401215516c77SSepherosa Ziehau 401315516c77SSepherosa Ziehau HN_LOCK(sc); 401415516c77SSepherosa Ziehau hn_init_locked(sc); 401515516c77SSepherosa Ziehau HN_UNLOCK(sc); 401615516c77SSepherosa Ziehau } 401715516c77SSepherosa Ziehau 401815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 401915516c77SSepherosa Ziehau 402015516c77SSepherosa Ziehau static int 402115516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS) 402215516c77SSepherosa Ziehau { 402315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 402415516c77SSepherosa Ziehau unsigned int lenlim; 402515516c77SSepherosa Ziehau int error; 402615516c77SSepherosa Ziehau 402715516c77SSepherosa Ziehau lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim; 402815516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &lenlim, 0, req); 402915516c77SSepherosa Ziehau if (error || req->newptr == NULL) 403015516c77SSepherosa Ziehau return error; 403115516c77SSepherosa Ziehau 403215516c77SSepherosa Ziehau HN_LOCK(sc); 403315516c77SSepherosa Ziehau if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) || 403415516c77SSepherosa Ziehau lenlim > TCP_LRO_LENGTH_MAX) { 403515516c77SSepherosa Ziehau HN_UNLOCK(sc); 403615516c77SSepherosa Ziehau return EINVAL; 403715516c77SSepherosa Ziehau } 403815516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, lenlim); 403915516c77SSepherosa Ziehau HN_UNLOCK(sc); 404015516c77SSepherosa Ziehau 404115516c77SSepherosa Ziehau return 0; 404215516c77SSepherosa Ziehau } 404315516c77SSepherosa Ziehau 404415516c77SSepherosa Ziehau static int 404515516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS) 404615516c77SSepherosa Ziehau { 404715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 404815516c77SSepherosa Ziehau int ackcnt, error, i; 404915516c77SSepherosa Ziehau 405015516c77SSepherosa Ziehau /* 405115516c77SSepherosa Ziehau * lro_ackcnt_lim is append count limit, 405215516c77SSepherosa Ziehau * +1 to turn it into aggregation limit. 405315516c77SSepherosa Ziehau */ 405415516c77SSepherosa Ziehau ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1; 405515516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &ackcnt, 0, req); 405615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 405715516c77SSepherosa Ziehau return error; 405815516c77SSepherosa Ziehau 405915516c77SSepherosa Ziehau if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1)) 406015516c77SSepherosa Ziehau return EINVAL; 406115516c77SSepherosa Ziehau 406215516c77SSepherosa Ziehau /* 406315516c77SSepherosa Ziehau * Convert aggregation limit back to append 406415516c77SSepherosa Ziehau * count limit. 406515516c77SSepherosa Ziehau */ 406615516c77SSepherosa Ziehau --ackcnt; 406715516c77SSepherosa Ziehau HN_LOCK(sc); 4068a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 406915516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt; 407015516c77SSepherosa Ziehau HN_UNLOCK(sc); 407115516c77SSepherosa Ziehau return 0; 407215516c77SSepherosa Ziehau } 407315516c77SSepherosa Ziehau 407415516c77SSepherosa Ziehau #endif 407515516c77SSepherosa Ziehau 407615516c77SSepherosa Ziehau static int 407715516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS) 407815516c77SSepherosa Ziehau { 407915516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 408015516c77SSepherosa Ziehau int hcsum = arg2; 408115516c77SSepherosa Ziehau int on, error, i; 408215516c77SSepherosa Ziehau 408315516c77SSepherosa Ziehau on = 0; 408415516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum) 408515516c77SSepherosa Ziehau on = 1; 408615516c77SSepherosa Ziehau 408715516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &on, 0, req); 408815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 408915516c77SSepherosa Ziehau return error; 409015516c77SSepherosa Ziehau 409115516c77SSepherosa Ziehau HN_LOCK(sc); 4092a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 409315516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 409415516c77SSepherosa Ziehau 409515516c77SSepherosa Ziehau if (on) 409615516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= hcsum; 409715516c77SSepherosa Ziehau else 409815516c77SSepherosa Ziehau rxr->hn_trust_hcsum &= ~hcsum; 409915516c77SSepherosa Ziehau } 410015516c77SSepherosa Ziehau HN_UNLOCK(sc); 410115516c77SSepherosa Ziehau return 0; 410215516c77SSepherosa Ziehau } 410315516c77SSepherosa Ziehau 410415516c77SSepherosa Ziehau static int 410515516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS) 410615516c77SSepherosa Ziehau { 410715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 410815516c77SSepherosa Ziehau int chim_size, error; 410915516c77SSepherosa Ziehau 411015516c77SSepherosa Ziehau chim_size = sc->hn_tx_ring[0].hn_chim_size; 411115516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &chim_size, 0, req); 411215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 411315516c77SSepherosa Ziehau return error; 411415516c77SSepherosa Ziehau 411515516c77SSepherosa Ziehau if (chim_size > sc->hn_chim_szmax || chim_size <= 0) 411615516c77SSepherosa Ziehau return EINVAL; 411715516c77SSepherosa Ziehau 411815516c77SSepherosa Ziehau HN_LOCK(sc); 411915516c77SSepherosa Ziehau hn_set_chim_size(sc, chim_size); 412015516c77SSepherosa Ziehau HN_UNLOCK(sc); 412115516c77SSepherosa Ziehau return 0; 412215516c77SSepherosa Ziehau } 412315516c77SSepherosa Ziehau 412415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 412515516c77SSepherosa Ziehau static int 412615516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS) 412715516c77SSepherosa Ziehau { 412815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 412915516c77SSepherosa Ziehau int ofs = arg2, i, error; 413015516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 413115516c77SSepherosa Ziehau uint64_t stat; 413215516c77SSepherosa Ziehau 413315516c77SSepherosa Ziehau stat = 0; 413415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 413515516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 413615516c77SSepherosa Ziehau stat += *((int *)((uint8_t *)rxr + ofs)); 413715516c77SSepherosa Ziehau } 413815516c77SSepherosa Ziehau 413915516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 414015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 414115516c77SSepherosa Ziehau return error; 414215516c77SSepherosa Ziehau 414315516c77SSepherosa Ziehau /* Zero out this stat. */ 414415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 414515516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 414615516c77SSepherosa Ziehau *((int *)((uint8_t *)rxr + ofs)) = 0; 414715516c77SSepherosa Ziehau } 414815516c77SSepherosa Ziehau return 0; 414915516c77SSepherosa Ziehau } 415015516c77SSepherosa Ziehau #else 415115516c77SSepherosa Ziehau static int 415215516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS) 415315516c77SSepherosa Ziehau { 415415516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 415515516c77SSepherosa Ziehau int ofs = arg2, i, error; 415615516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 415715516c77SSepherosa Ziehau uint64_t stat; 415815516c77SSepherosa Ziehau 415915516c77SSepherosa Ziehau stat = 0; 4160a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 416115516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 416215516c77SSepherosa Ziehau stat += *((uint64_t *)((uint8_t *)rxr + ofs)); 416315516c77SSepherosa Ziehau } 416415516c77SSepherosa Ziehau 416515516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 416615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 416715516c77SSepherosa Ziehau return error; 416815516c77SSepherosa Ziehau 416915516c77SSepherosa Ziehau /* Zero out this stat. */ 4170a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 417115516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 417215516c77SSepherosa Ziehau *((uint64_t *)((uint8_t *)rxr + ofs)) = 0; 417315516c77SSepherosa Ziehau } 417415516c77SSepherosa Ziehau return 0; 417515516c77SSepherosa Ziehau } 417615516c77SSepherosa Ziehau 417715516c77SSepherosa Ziehau #endif 417815516c77SSepherosa Ziehau 417915516c77SSepherosa Ziehau static int 418015516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 418115516c77SSepherosa Ziehau { 418215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 418315516c77SSepherosa Ziehau int ofs = arg2, i, error; 418415516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 418515516c77SSepherosa Ziehau u_long stat; 418615516c77SSepherosa Ziehau 418715516c77SSepherosa Ziehau stat = 0; 4188a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 418915516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 419015516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)rxr + ofs)); 419115516c77SSepherosa Ziehau } 419215516c77SSepherosa Ziehau 419315516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 419415516c77SSepherosa Ziehau if (error || req->newptr == NULL) 419515516c77SSepherosa Ziehau return error; 419615516c77SSepherosa Ziehau 419715516c77SSepherosa Ziehau /* Zero out this stat. */ 4198a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 419915516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 420015516c77SSepherosa Ziehau *((u_long *)((uint8_t *)rxr + ofs)) = 0; 420115516c77SSepherosa Ziehau } 420215516c77SSepherosa Ziehau return 0; 420315516c77SSepherosa Ziehau } 420415516c77SSepherosa Ziehau 420515516c77SSepherosa Ziehau static int 420615516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 420715516c77SSepherosa Ziehau { 420815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 420915516c77SSepherosa Ziehau int ofs = arg2, i, error; 421015516c77SSepherosa Ziehau struct hn_tx_ring *txr; 421115516c77SSepherosa Ziehau u_long stat; 421215516c77SSepherosa Ziehau 421315516c77SSepherosa Ziehau stat = 0; 4214a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 421515516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 421615516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)txr + ofs)); 421715516c77SSepherosa Ziehau } 421815516c77SSepherosa Ziehau 421915516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 422015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 422115516c77SSepherosa Ziehau return error; 422215516c77SSepherosa Ziehau 422315516c77SSepherosa Ziehau /* Zero out this stat. */ 4224a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 422515516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 422615516c77SSepherosa Ziehau *((u_long *)((uint8_t *)txr + ofs)) = 0; 422715516c77SSepherosa Ziehau } 422815516c77SSepherosa Ziehau return 0; 422915516c77SSepherosa Ziehau } 423015516c77SSepherosa Ziehau 423115516c77SSepherosa Ziehau static int 423215516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS) 423315516c77SSepherosa Ziehau { 423415516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 423515516c77SSepherosa Ziehau int ofs = arg2, i, error, conf; 423615516c77SSepherosa Ziehau struct hn_tx_ring *txr; 423715516c77SSepherosa Ziehau 423815516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[0]; 423915516c77SSepherosa Ziehau conf = *((int *)((uint8_t *)txr + ofs)); 424015516c77SSepherosa Ziehau 424115516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &conf, 0, req); 424215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 424315516c77SSepherosa Ziehau return error; 424415516c77SSepherosa Ziehau 424515516c77SSepherosa Ziehau HN_LOCK(sc); 4246a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 424715516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 424815516c77SSepherosa Ziehau *((int *)((uint8_t *)txr + ofs)) = conf; 424915516c77SSepherosa Ziehau } 425015516c77SSepherosa Ziehau HN_UNLOCK(sc); 425115516c77SSepherosa Ziehau 425215516c77SSepherosa Ziehau return 0; 425315516c77SSepherosa Ziehau } 425415516c77SSepherosa Ziehau 425515516c77SSepherosa Ziehau static int 4256dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS) 4257dc13fee6SSepherosa Ziehau { 4258dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4259dc13fee6SSepherosa Ziehau int error, size; 4260dc13fee6SSepherosa Ziehau 4261dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 4262dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &size, 0, req); 4263dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 4264dc13fee6SSepherosa Ziehau return (error); 4265dc13fee6SSepherosa Ziehau 4266dc13fee6SSepherosa Ziehau HN_LOCK(sc); 4267dc13fee6SSepherosa Ziehau sc->hn_agg_size = size; 4268dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 4269dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 4270dc13fee6SSepherosa Ziehau 4271dc13fee6SSepherosa Ziehau return (0); 4272dc13fee6SSepherosa Ziehau } 4273dc13fee6SSepherosa Ziehau 4274dc13fee6SSepherosa Ziehau static int 4275dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS) 4276dc13fee6SSepherosa Ziehau { 4277dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4278dc13fee6SSepherosa Ziehau int error, pkts; 4279dc13fee6SSepherosa Ziehau 4280dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 4281dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &pkts, 0, req); 4282dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 4283dc13fee6SSepherosa Ziehau return (error); 4284dc13fee6SSepherosa Ziehau 4285dc13fee6SSepherosa Ziehau HN_LOCK(sc); 4286dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = pkts; 4287dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 4288dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 4289dc13fee6SSepherosa Ziehau 4290dc13fee6SSepherosa Ziehau return (0); 4291dc13fee6SSepherosa Ziehau } 4292dc13fee6SSepherosa Ziehau 4293dc13fee6SSepherosa Ziehau static int 4294dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS) 4295dc13fee6SSepherosa Ziehau { 4296dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4297dc13fee6SSepherosa Ziehau int pkts; 4298dc13fee6SSepherosa Ziehau 4299dc13fee6SSepherosa Ziehau pkts = sc->hn_tx_ring[0].hn_agg_pktmax; 4300dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &pkts, 0, req)); 4301dc13fee6SSepherosa Ziehau } 4302dc13fee6SSepherosa Ziehau 4303dc13fee6SSepherosa Ziehau static int 4304dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS) 4305dc13fee6SSepherosa Ziehau { 4306dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 4307dc13fee6SSepherosa Ziehau int align; 4308dc13fee6SSepherosa Ziehau 4309dc13fee6SSepherosa Ziehau align = sc->hn_tx_ring[0].hn_agg_align; 4310dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &align, 0, req)); 4311dc13fee6SSepherosa Ziehau } 4312dc13fee6SSepherosa Ziehau 43136c1204dfSSepherosa Ziehau static void 43146c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz) 43156c1204dfSSepherosa Ziehau { 43166c1204dfSSepherosa Ziehau if (pollhz == 0) 43176c1204dfSSepherosa Ziehau vmbus_chan_poll_disable(chan); 43186c1204dfSSepherosa Ziehau else 43196c1204dfSSepherosa Ziehau vmbus_chan_poll_enable(chan, pollhz); 43206c1204dfSSepherosa Ziehau } 43216c1204dfSSepherosa Ziehau 43226c1204dfSSepherosa Ziehau static void 43236c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz) 43246c1204dfSSepherosa Ziehau { 43256c1204dfSSepherosa Ziehau int nsubch = sc->hn_rx_ring_inuse - 1; 43266c1204dfSSepherosa Ziehau 43276c1204dfSSepherosa Ziehau HN_LOCK_ASSERT(sc); 43286c1204dfSSepherosa Ziehau 43296c1204dfSSepherosa Ziehau if (nsubch > 0) { 43306c1204dfSSepherosa Ziehau struct vmbus_channel **subch; 43316c1204dfSSepherosa Ziehau int i; 43326c1204dfSSepherosa Ziehau 43336c1204dfSSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 43346c1204dfSSepherosa Ziehau for (i = 0; i < nsubch; ++i) 43356c1204dfSSepherosa Ziehau hn_chan_polling(subch[i], pollhz); 43366c1204dfSSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 43376c1204dfSSepherosa Ziehau } 43386c1204dfSSepherosa Ziehau hn_chan_polling(sc->hn_prichan, pollhz); 43396c1204dfSSepherosa Ziehau } 43406c1204dfSSepherosa Ziehau 43416c1204dfSSepherosa Ziehau static int 43426c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS) 43436c1204dfSSepherosa Ziehau { 43446c1204dfSSepherosa Ziehau struct hn_softc *sc = arg1; 43456c1204dfSSepherosa Ziehau int pollhz, error; 43466c1204dfSSepherosa Ziehau 43476c1204dfSSepherosa Ziehau pollhz = sc->hn_pollhz; 43486c1204dfSSepherosa Ziehau error = sysctl_handle_int(oidp, &pollhz, 0, req); 43496c1204dfSSepherosa Ziehau if (error || req->newptr == NULL) 43506c1204dfSSepherosa Ziehau return (error); 43516c1204dfSSepherosa Ziehau 43526c1204dfSSepherosa Ziehau if (pollhz != 0 && 43536c1204dfSSepherosa Ziehau (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX)) 43546c1204dfSSepherosa Ziehau return (EINVAL); 43556c1204dfSSepherosa Ziehau 43566c1204dfSSepherosa Ziehau HN_LOCK(sc); 43576c1204dfSSepherosa Ziehau if (sc->hn_pollhz != pollhz) { 43586c1204dfSSepherosa Ziehau sc->hn_pollhz = pollhz; 43596c1204dfSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && 43606c1204dfSSepherosa Ziehau (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 43616c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 43626c1204dfSSepherosa Ziehau } 43636c1204dfSSepherosa Ziehau HN_UNLOCK(sc); 43646c1204dfSSepherosa Ziehau 43656c1204dfSSepherosa Ziehau return (0); 43666c1204dfSSepherosa Ziehau } 43676c1204dfSSepherosa Ziehau 4368dc13fee6SSepherosa Ziehau static int 436915516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS) 437015516c77SSepherosa Ziehau { 437115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 437215516c77SSepherosa Ziehau char verstr[16]; 437315516c77SSepherosa Ziehau 437415516c77SSepherosa Ziehau snprintf(verstr, sizeof(verstr), "%u.%u", 437515516c77SSepherosa Ziehau HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 437615516c77SSepherosa Ziehau HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 437715516c77SSepherosa Ziehau return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 437815516c77SSepherosa Ziehau } 437915516c77SSepherosa Ziehau 438015516c77SSepherosa Ziehau static int 438115516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS) 438215516c77SSepherosa Ziehau { 438315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 438415516c77SSepherosa Ziehau char caps_str[128]; 438515516c77SSepherosa Ziehau uint32_t caps; 438615516c77SSepherosa Ziehau 438715516c77SSepherosa Ziehau HN_LOCK(sc); 438815516c77SSepherosa Ziehau caps = sc->hn_caps; 438915516c77SSepherosa Ziehau HN_UNLOCK(sc); 439015516c77SSepherosa Ziehau snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS); 439115516c77SSepherosa Ziehau return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req); 439215516c77SSepherosa Ziehau } 439315516c77SSepherosa Ziehau 439415516c77SSepherosa Ziehau static int 439515516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS) 439615516c77SSepherosa Ziehau { 439715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 439815516c77SSepherosa Ziehau char assist_str[128]; 439915516c77SSepherosa Ziehau uint32_t hwassist; 440015516c77SSepherosa Ziehau 440115516c77SSepherosa Ziehau HN_LOCK(sc); 440215516c77SSepherosa Ziehau hwassist = sc->hn_ifp->if_hwassist; 440315516c77SSepherosa Ziehau HN_UNLOCK(sc); 440415516c77SSepherosa Ziehau snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS); 440515516c77SSepherosa Ziehau return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req); 440615516c77SSepherosa Ziehau } 440715516c77SSepherosa Ziehau 440815516c77SSepherosa Ziehau static int 440915516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS) 441015516c77SSepherosa Ziehau { 441115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 441215516c77SSepherosa Ziehau char filter_str[128]; 441315516c77SSepherosa Ziehau uint32_t filter; 441415516c77SSepherosa Ziehau 441515516c77SSepherosa Ziehau HN_LOCK(sc); 441615516c77SSepherosa Ziehau filter = sc->hn_rx_filter; 441715516c77SSepherosa Ziehau HN_UNLOCK(sc); 441815516c77SSepherosa Ziehau snprintf(filter_str, sizeof(filter_str), "%b", filter, 441915516c77SSepherosa Ziehau NDIS_PACKET_TYPES); 442015516c77SSepherosa Ziehau return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req); 442115516c77SSepherosa Ziehau } 442215516c77SSepherosa Ziehau 442334d68912SSepherosa Ziehau #ifndef RSS 442434d68912SSepherosa Ziehau 442515516c77SSepherosa Ziehau static int 442615516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS) 442715516c77SSepherosa Ziehau { 442815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 442915516c77SSepherosa Ziehau int error; 443015516c77SSepherosa Ziehau 443115516c77SSepherosa Ziehau HN_LOCK(sc); 443215516c77SSepherosa Ziehau 443315516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 443415516c77SSepherosa Ziehau if (error || req->newptr == NULL) 443515516c77SSepherosa Ziehau goto back; 443615516c77SSepherosa Ziehau 4437642ec226SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) || 4438642ec226SSepherosa Ziehau (hn_xpnt_vf && sc->hn_vf_ifp != NULL)) { 4439642ec226SSepherosa Ziehau /* 4440642ec226SSepherosa Ziehau * RSS key is synchronized w/ VF's, don't allow users 4441642ec226SSepherosa Ziehau * to change it. 4442642ec226SSepherosa Ziehau */ 4443642ec226SSepherosa Ziehau error = EBUSY; 4444642ec226SSepherosa Ziehau goto back; 4445642ec226SSepherosa Ziehau } 4446642ec226SSepherosa Ziehau 444715516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 444815516c77SSepherosa Ziehau if (error) 444915516c77SSepherosa Ziehau goto back; 445015516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 445115516c77SSepherosa Ziehau 445215516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 445315516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 445415516c77SSepherosa Ziehau } else { 445515516c77SSepherosa Ziehau /* Not RSS capable, at least for now; just save the RSS key. */ 445615516c77SSepherosa Ziehau error = 0; 445715516c77SSepherosa Ziehau } 445815516c77SSepherosa Ziehau back: 445915516c77SSepherosa Ziehau HN_UNLOCK(sc); 446015516c77SSepherosa Ziehau return (error); 446115516c77SSepherosa Ziehau } 446215516c77SSepherosa Ziehau 446315516c77SSepherosa Ziehau static int 446415516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS) 446515516c77SSepherosa Ziehau { 446615516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 446715516c77SSepherosa Ziehau int error; 446815516c77SSepherosa Ziehau 446915516c77SSepherosa Ziehau HN_LOCK(sc); 447015516c77SSepherosa Ziehau 447115516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 447215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 447315516c77SSepherosa Ziehau goto back; 447415516c77SSepherosa Ziehau 447515516c77SSepherosa Ziehau /* 447615516c77SSepherosa Ziehau * Don't allow RSS indirect table change, if this interface is not 447715516c77SSepherosa Ziehau * RSS capable currently. 447815516c77SSepherosa Ziehau */ 447915516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 448015516c77SSepherosa Ziehau error = EOPNOTSUPP; 448115516c77SSepherosa Ziehau goto back; 448215516c77SSepherosa Ziehau } 448315516c77SSepherosa Ziehau 448415516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 448515516c77SSepherosa Ziehau if (error) 448615516c77SSepherosa Ziehau goto back; 448715516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 448815516c77SSepherosa Ziehau 4489afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 449015516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 449115516c77SSepherosa Ziehau back: 449215516c77SSepherosa Ziehau HN_UNLOCK(sc); 449315516c77SSepherosa Ziehau return (error); 449415516c77SSepherosa Ziehau } 449515516c77SSepherosa Ziehau 449634d68912SSepherosa Ziehau #endif /* !RSS */ 449734d68912SSepherosa Ziehau 449815516c77SSepherosa Ziehau static int 449915516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS) 450015516c77SSepherosa Ziehau { 450115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 450215516c77SSepherosa Ziehau char hash_str[128]; 450315516c77SSepherosa Ziehau uint32_t hash; 450415516c77SSepherosa Ziehau 450515516c77SSepherosa Ziehau HN_LOCK(sc); 450615516c77SSepherosa Ziehau hash = sc->hn_rss_hash; 450715516c77SSepherosa Ziehau HN_UNLOCK(sc); 450815516c77SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 450915516c77SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 451015516c77SSepherosa Ziehau } 451115516c77SSepherosa Ziehau 451215516c77SSepherosa Ziehau static int 4513642ec226SSepherosa Ziehau hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS) 4514642ec226SSepherosa Ziehau { 4515642ec226SSepherosa Ziehau struct hn_softc *sc = arg1; 4516642ec226SSepherosa Ziehau char hash_str[128]; 4517642ec226SSepherosa Ziehau uint32_t hash; 4518642ec226SSepherosa Ziehau 4519642ec226SSepherosa Ziehau HN_LOCK(sc); 4520642ec226SSepherosa Ziehau hash = sc->hn_rss_hcap; 4521642ec226SSepherosa Ziehau HN_UNLOCK(sc); 4522642ec226SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 4523642ec226SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 4524642ec226SSepherosa Ziehau } 4525642ec226SSepherosa Ziehau 4526642ec226SSepherosa Ziehau static int 4527642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS) 4528642ec226SSepherosa Ziehau { 4529642ec226SSepherosa Ziehau struct hn_softc *sc = arg1; 4530642ec226SSepherosa Ziehau char hash_str[128]; 4531642ec226SSepherosa Ziehau uint32_t hash; 4532642ec226SSepherosa Ziehau 4533642ec226SSepherosa Ziehau HN_LOCK(sc); 4534642ec226SSepherosa Ziehau hash = sc->hn_rx_ring[0].hn_mbuf_hash; 4535642ec226SSepherosa Ziehau HN_UNLOCK(sc); 4536642ec226SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 4537642ec226SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 4538642ec226SSepherosa Ziehau } 4539642ec226SSepherosa Ziehau 4540642ec226SSepherosa Ziehau static int 454140d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS) 454240d60d6eSDexuan Cui { 454340d60d6eSDexuan Cui struct hn_softc *sc = arg1; 4544499c3e17SSepherosa Ziehau char vf_name[IFNAMSIZ + 1]; 4545962f0357SSepherosa Ziehau struct ifnet *vf_ifp; 454640d60d6eSDexuan Cui 454740d60d6eSDexuan Cui HN_LOCK(sc); 454840d60d6eSDexuan Cui vf_name[0] = '\0'; 4549962f0357SSepherosa Ziehau vf_ifp = sc->hn_vf_ifp; 4550962f0357SSepherosa Ziehau if (vf_ifp != NULL) 4551962f0357SSepherosa Ziehau snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname); 455240d60d6eSDexuan Cui HN_UNLOCK(sc); 455340d60d6eSDexuan Cui return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); 455440d60d6eSDexuan Cui } 455540d60d6eSDexuan Cui 455640d60d6eSDexuan Cui static int 4557499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS) 4558499c3e17SSepherosa Ziehau { 4559499c3e17SSepherosa Ziehau struct hn_softc *sc = arg1; 4560499c3e17SSepherosa Ziehau char vf_name[IFNAMSIZ + 1]; 4561962f0357SSepherosa Ziehau struct ifnet *vf_ifp; 4562499c3e17SSepherosa Ziehau 4563499c3e17SSepherosa Ziehau HN_LOCK(sc); 4564499c3e17SSepherosa Ziehau vf_name[0] = '\0'; 4565962f0357SSepherosa Ziehau vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp; 4566962f0357SSepherosa Ziehau if (vf_ifp != NULL) 4567962f0357SSepherosa Ziehau snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname); 4568499c3e17SSepherosa Ziehau HN_UNLOCK(sc); 4569499c3e17SSepherosa Ziehau return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); 4570499c3e17SSepherosa Ziehau } 4571499c3e17SSepherosa Ziehau 4572499c3e17SSepherosa Ziehau static int 4573499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS) 4574499c3e17SSepherosa Ziehau { 4575499c3e17SSepherosa Ziehau struct rm_priotracker pt; 4576499c3e17SSepherosa Ziehau struct sbuf *sb; 4577499c3e17SSepherosa Ziehau int error, i; 4578499c3e17SSepherosa Ziehau bool first; 4579499c3e17SSepherosa Ziehau 4580499c3e17SSepherosa Ziehau error = sysctl_wire_old_buffer(req, 0); 4581499c3e17SSepherosa Ziehau if (error != 0) 4582499c3e17SSepherosa Ziehau return (error); 4583499c3e17SSepherosa Ziehau 4584499c3e17SSepherosa Ziehau sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4585499c3e17SSepherosa Ziehau if (sb == NULL) 4586499c3e17SSepherosa Ziehau return (ENOMEM); 4587499c3e17SSepherosa Ziehau 4588499c3e17SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 4589499c3e17SSepherosa Ziehau 4590499c3e17SSepherosa Ziehau first = true; 4591499c3e17SSepherosa Ziehau for (i = 0; i < hn_vfmap_size; ++i) { 4592499c3e17SSepherosa Ziehau struct ifnet *ifp; 4593499c3e17SSepherosa Ziehau 4594499c3e17SSepherosa Ziehau if (hn_vfmap[i] == NULL) 4595499c3e17SSepherosa Ziehau continue; 4596499c3e17SSepherosa Ziehau 4597499c3e17SSepherosa Ziehau ifp = ifnet_byindex(i); 4598499c3e17SSepherosa Ziehau if (ifp != NULL) { 4599499c3e17SSepherosa Ziehau if (first) 4600499c3e17SSepherosa Ziehau sbuf_printf(sb, "%s", ifp->if_xname); 4601499c3e17SSepherosa Ziehau else 4602499c3e17SSepherosa Ziehau sbuf_printf(sb, " %s", ifp->if_xname); 4603499c3e17SSepherosa Ziehau first = false; 4604499c3e17SSepherosa Ziehau } 4605499c3e17SSepherosa Ziehau } 4606499c3e17SSepherosa Ziehau 4607499c3e17SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 4608499c3e17SSepherosa Ziehau 4609499c3e17SSepherosa Ziehau error = sbuf_finish(sb); 4610499c3e17SSepherosa Ziehau sbuf_delete(sb); 4611499c3e17SSepherosa Ziehau return (error); 4612499c3e17SSepherosa Ziehau } 4613499c3e17SSepherosa Ziehau 4614499c3e17SSepherosa Ziehau static int 4615499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS) 4616499c3e17SSepherosa Ziehau { 4617499c3e17SSepherosa Ziehau struct rm_priotracker pt; 4618499c3e17SSepherosa Ziehau struct sbuf *sb; 4619499c3e17SSepherosa Ziehau int error, i; 4620499c3e17SSepherosa Ziehau bool first; 4621499c3e17SSepherosa Ziehau 4622499c3e17SSepherosa Ziehau error = sysctl_wire_old_buffer(req, 0); 4623499c3e17SSepherosa Ziehau if (error != 0) 4624499c3e17SSepherosa Ziehau return (error); 4625499c3e17SSepherosa Ziehau 4626499c3e17SSepherosa Ziehau sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4627499c3e17SSepherosa Ziehau if (sb == NULL) 4628499c3e17SSepherosa Ziehau return (ENOMEM); 4629499c3e17SSepherosa Ziehau 4630499c3e17SSepherosa Ziehau rm_rlock(&hn_vfmap_lock, &pt); 4631499c3e17SSepherosa Ziehau 4632499c3e17SSepherosa Ziehau first = true; 4633499c3e17SSepherosa Ziehau for (i = 0; i < hn_vfmap_size; ++i) { 4634499c3e17SSepherosa Ziehau struct ifnet *ifp, *hn_ifp; 4635499c3e17SSepherosa Ziehau 4636499c3e17SSepherosa Ziehau hn_ifp = hn_vfmap[i]; 4637499c3e17SSepherosa Ziehau if (hn_ifp == NULL) 4638499c3e17SSepherosa Ziehau continue; 4639499c3e17SSepherosa Ziehau 4640499c3e17SSepherosa Ziehau ifp = ifnet_byindex(i); 4641499c3e17SSepherosa Ziehau if (ifp != NULL) { 4642499c3e17SSepherosa Ziehau if (first) { 4643499c3e17SSepherosa Ziehau sbuf_printf(sb, "%s:%s", ifp->if_xname, 4644499c3e17SSepherosa Ziehau hn_ifp->if_xname); 4645499c3e17SSepherosa Ziehau } else { 4646499c3e17SSepherosa Ziehau sbuf_printf(sb, " %s:%s", ifp->if_xname, 4647499c3e17SSepherosa Ziehau hn_ifp->if_xname); 4648499c3e17SSepherosa Ziehau } 4649499c3e17SSepherosa Ziehau first = false; 4650499c3e17SSepherosa Ziehau } 4651499c3e17SSepherosa Ziehau } 4652499c3e17SSepherosa Ziehau 4653499c3e17SSepherosa Ziehau rm_runlock(&hn_vfmap_lock, &pt); 4654499c3e17SSepherosa Ziehau 4655499c3e17SSepherosa Ziehau error = sbuf_finish(sb); 4656499c3e17SSepherosa Ziehau sbuf_delete(sb); 4657499c3e17SSepherosa Ziehau return (error); 4658499c3e17SSepherosa Ziehau } 4659499c3e17SSepherosa Ziehau 4660499c3e17SSepherosa Ziehau static int 46619c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS) 46629c6cae24SSepherosa Ziehau { 46639c6cae24SSepherosa Ziehau struct hn_softc *sc = arg1; 46649c6cae24SSepherosa Ziehau int error, onoff = 0; 46659c6cae24SSepherosa Ziehau 46669c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) 46679c6cae24SSepherosa Ziehau onoff = 1; 46689c6cae24SSepherosa Ziehau error = sysctl_handle_int(oidp, &onoff, 0, req); 46699c6cae24SSepherosa Ziehau if (error || req->newptr == NULL) 46709c6cae24SSepherosa Ziehau return (error); 46719c6cae24SSepherosa Ziehau 46729c6cae24SSepherosa Ziehau HN_LOCK(sc); 46739c6cae24SSepherosa Ziehau /* NOTE: hn_vf_lock for hn_transmit() */ 46749c6cae24SSepherosa Ziehau rm_wlock(&sc->hn_vf_lock); 46759c6cae24SSepherosa Ziehau if (onoff) 46769c6cae24SSepherosa Ziehau sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF; 46779c6cae24SSepherosa Ziehau else 46789c6cae24SSepherosa Ziehau sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF; 46799c6cae24SSepherosa Ziehau rm_wunlock(&sc->hn_vf_lock); 46809c6cae24SSepherosa Ziehau HN_UNLOCK(sc); 46819c6cae24SSepherosa Ziehau 46829c6cae24SSepherosa Ziehau return (0); 46839c6cae24SSepherosa Ziehau } 46849c6cae24SSepherosa Ziehau 46859c6cae24SSepherosa Ziehau static int 46869c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS) 46879c6cae24SSepherosa Ziehau { 46889c6cae24SSepherosa Ziehau struct hn_softc *sc = arg1; 46899c6cae24SSepherosa Ziehau int enabled = 0; 46909c6cae24SSepherosa Ziehau 46919c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 46929c6cae24SSepherosa Ziehau enabled = 1; 46939c6cae24SSepherosa Ziehau return (sysctl_handle_int(oidp, &enabled, 0, req)); 46949c6cae24SSepherosa Ziehau } 46959c6cae24SSepherosa Ziehau 46969c6cae24SSepherosa Ziehau static int 469715516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff) 469815516c77SSepherosa Ziehau { 469915516c77SSepherosa Ziehau const struct ip *ip; 470015516c77SSepherosa Ziehau int len, iphlen, iplen; 470115516c77SSepherosa Ziehau const struct tcphdr *th; 470215516c77SSepherosa Ziehau int thoff; /* TCP data offset */ 470315516c77SSepherosa Ziehau 470415516c77SSepherosa Ziehau len = hoff + sizeof(struct ip); 470515516c77SSepherosa Ziehau 470615516c77SSepherosa Ziehau /* The packet must be at least the size of an IP header. */ 470715516c77SSepherosa Ziehau if (m->m_pkthdr.len < len) 470815516c77SSepherosa Ziehau return IPPROTO_DONE; 470915516c77SSepherosa Ziehau 471015516c77SSepherosa Ziehau /* The fixed IP header must reside completely in the first mbuf. */ 471115516c77SSepherosa Ziehau if (m->m_len < len) 471215516c77SSepherosa Ziehau return IPPROTO_DONE; 471315516c77SSepherosa Ziehau 471415516c77SSepherosa Ziehau ip = mtodo(m, hoff); 471515516c77SSepherosa Ziehau 471615516c77SSepherosa Ziehau /* Bound check the packet's stated IP header length. */ 471715516c77SSepherosa Ziehau iphlen = ip->ip_hl << 2; 471815516c77SSepherosa Ziehau if (iphlen < sizeof(struct ip)) /* minimum header length */ 471915516c77SSepherosa Ziehau return IPPROTO_DONE; 472015516c77SSepherosa Ziehau 472115516c77SSepherosa Ziehau /* The full IP header must reside completely in the one mbuf. */ 472215516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen) 472315516c77SSepherosa Ziehau return IPPROTO_DONE; 472415516c77SSepherosa Ziehau 472515516c77SSepherosa Ziehau iplen = ntohs(ip->ip_len); 472615516c77SSepherosa Ziehau 472715516c77SSepherosa Ziehau /* 472815516c77SSepherosa Ziehau * Check that the amount of data in the buffers is as 472915516c77SSepherosa Ziehau * at least much as the IP header would have us expect. 473015516c77SSepherosa Ziehau */ 473115516c77SSepherosa Ziehau if (m->m_pkthdr.len < hoff + iplen) 473215516c77SSepherosa Ziehau return IPPROTO_DONE; 473315516c77SSepherosa Ziehau 473415516c77SSepherosa Ziehau /* 473515516c77SSepherosa Ziehau * Ignore IP fragments. 473615516c77SSepherosa Ziehau */ 473715516c77SSepherosa Ziehau if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF)) 473815516c77SSepherosa Ziehau return IPPROTO_DONE; 473915516c77SSepherosa Ziehau 474015516c77SSepherosa Ziehau /* 474115516c77SSepherosa Ziehau * The TCP/IP or UDP/IP header must be entirely contained within 474215516c77SSepherosa Ziehau * the first fragment of a packet. 474315516c77SSepherosa Ziehau */ 474415516c77SSepherosa Ziehau switch (ip->ip_p) { 474515516c77SSepherosa Ziehau case IPPROTO_TCP: 474615516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct tcphdr)) 474715516c77SSepherosa Ziehau return IPPROTO_DONE; 474815516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct tcphdr)) 474915516c77SSepherosa Ziehau return IPPROTO_DONE; 475015516c77SSepherosa Ziehau th = (const struct tcphdr *)((const uint8_t *)ip + iphlen); 475115516c77SSepherosa Ziehau thoff = th->th_off << 2; 475215516c77SSepherosa Ziehau if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen) 475315516c77SSepherosa Ziehau return IPPROTO_DONE; 475415516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + thoff) 475515516c77SSepherosa Ziehau return IPPROTO_DONE; 475615516c77SSepherosa Ziehau break; 475715516c77SSepherosa Ziehau case IPPROTO_UDP: 475815516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct udphdr)) 475915516c77SSepherosa Ziehau return IPPROTO_DONE; 476015516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct udphdr)) 476115516c77SSepherosa Ziehau return IPPROTO_DONE; 476215516c77SSepherosa Ziehau break; 476315516c77SSepherosa Ziehau default: 476415516c77SSepherosa Ziehau if (iplen < iphlen) 476515516c77SSepherosa Ziehau return IPPROTO_DONE; 476615516c77SSepherosa Ziehau break; 476715516c77SSepherosa Ziehau } 476815516c77SSepherosa Ziehau return ip->ip_p; 476915516c77SSepherosa Ziehau } 477015516c77SSepherosa Ziehau 477115516c77SSepherosa Ziehau static int 477215516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt) 477315516c77SSepherosa Ziehau { 477415516c77SSepherosa Ziehau struct sysctl_oid_list *child; 477515516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 477615516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 477715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 477815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 477915516c77SSepherosa Ziehau int lroent_cnt; 478015516c77SSepherosa Ziehau #endif 478115516c77SSepherosa Ziehau #endif 478215516c77SSepherosa Ziehau int i; 478315516c77SSepherosa Ziehau 478415516c77SSepherosa Ziehau /* 478515516c77SSepherosa Ziehau * Create RXBUF for reception. 478615516c77SSepherosa Ziehau * 478715516c77SSepherosa Ziehau * NOTE: 478815516c77SSepherosa Ziehau * - It is shared by all channels. 478915516c77SSepherosa Ziehau * - A large enough buffer is allocated, certain version of NVSes 479015516c77SSepherosa Ziehau * may further limit the usable space. 479115516c77SSepherosa Ziehau */ 479215516c77SSepherosa Ziehau sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 479315516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma, 479415516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 479515516c77SSepherosa Ziehau if (sc->hn_rxbuf == NULL) { 479615516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate rxbuf failed\n"); 479715516c77SSepherosa Ziehau return (ENOMEM); 479815516c77SSepherosa Ziehau } 479915516c77SSepherosa Ziehau 480015516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = ring_cnt; 480115516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt; 480215516c77SSepherosa Ziehau 480315516c77SSepherosa Ziehau sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt, 480415516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 480515516c77SSepherosa Ziehau 480615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 480715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 480815516c77SSepherosa Ziehau lroent_cnt = hn_lro_entry_count; 480915516c77SSepherosa Ziehau if (lroent_cnt < TCP_LRO_ENTRIES) 481015516c77SSepherosa Ziehau lroent_cnt = TCP_LRO_ENTRIES; 481115516c77SSepherosa Ziehau if (bootverbose) 481215516c77SSepherosa Ziehau device_printf(dev, "LRO: entry count %d\n", lroent_cnt); 481315516c77SSepherosa Ziehau #endif 481415516c77SSepherosa Ziehau #endif /* INET || INET6 */ 481515516c77SSepherosa Ziehau 481615516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 481715516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 481815516c77SSepherosa Ziehau 481915516c77SSepherosa Ziehau /* Create dev.hn.UNIT.rx sysctl tree */ 482015516c77SSepherosa Ziehau sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx", 482115516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 482215516c77SSepherosa Ziehau 482315516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 482415516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 482515516c77SSepherosa Ziehau 482615516c77SSepherosa Ziehau rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 482715516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE, 482815516c77SSepherosa Ziehau &rxr->hn_br_dma, BUS_DMA_WAITOK); 482915516c77SSepherosa Ziehau if (rxr->hn_br == NULL) { 483015516c77SSepherosa Ziehau device_printf(dev, "allocate bufring failed\n"); 483115516c77SSepherosa Ziehau return (ENOMEM); 483215516c77SSepherosa Ziehau } 483315516c77SSepherosa Ziehau 483415516c77SSepherosa Ziehau if (hn_trust_hosttcp) 483515516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP; 483615516c77SSepherosa Ziehau if (hn_trust_hostudp) 483715516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP; 483815516c77SSepherosa Ziehau if (hn_trust_hostip) 483915516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP; 4840642ec226SSepherosa Ziehau rxr->hn_mbuf_hash = NDIS_HASH_ALL; 484115516c77SSepherosa Ziehau rxr->hn_ifp = sc->hn_ifp; 484215516c77SSepherosa Ziehau if (i < sc->hn_tx_ring_cnt) 484315516c77SSepherosa Ziehau rxr->hn_txr = &sc->hn_tx_ring[i]; 484415516c77SSepherosa Ziehau rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF; 484515516c77SSepherosa Ziehau rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK); 484615516c77SSepherosa Ziehau rxr->hn_rx_idx = i; 484715516c77SSepherosa Ziehau rxr->hn_rxbuf = sc->hn_rxbuf; 484815516c77SSepherosa Ziehau 484915516c77SSepherosa Ziehau /* 485015516c77SSepherosa Ziehau * Initialize LRO. 485115516c77SSepherosa Ziehau */ 485215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 485315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 485415516c77SSepherosa Ziehau tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt, 485515516c77SSepherosa Ziehau hn_lro_mbufq_depth); 485615516c77SSepherosa Ziehau #else 485715516c77SSepherosa Ziehau tcp_lro_init(&rxr->hn_lro); 485815516c77SSepherosa Ziehau rxr->hn_lro.ifp = sc->hn_ifp; 485915516c77SSepherosa Ziehau #endif 486015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 486115516c77SSepherosa Ziehau rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF; 486215516c77SSepherosa Ziehau rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF; 486315516c77SSepherosa Ziehau #endif 486415516c77SSepherosa Ziehau #endif /* INET || INET6 */ 486515516c77SSepherosa Ziehau 486615516c77SSepherosa Ziehau if (sc->hn_rx_sysctl_tree != NULL) { 486715516c77SSepherosa Ziehau char name[16]; 486815516c77SSepherosa Ziehau 486915516c77SSepherosa Ziehau /* 487015516c77SSepherosa Ziehau * Create per RX ring sysctl tree: 487115516c77SSepherosa Ziehau * dev.hn.UNIT.rx.RINGID 487215516c77SSepherosa Ziehau */ 487315516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", i); 487415516c77SSepherosa Ziehau rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, 487515516c77SSepherosa Ziehau SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree), 487615516c77SSepherosa Ziehau OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 487715516c77SSepherosa Ziehau 487815516c77SSepherosa Ziehau if (rxr->hn_rx_sysctl_tree != NULL) { 487915516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 488015516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 488115516c77SSepherosa Ziehau OID_AUTO, "packets", CTLFLAG_RW, 488215516c77SSepherosa Ziehau &rxr->hn_pkts, "# of packets received"); 488315516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 488415516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 488515516c77SSepherosa Ziehau OID_AUTO, "rss_pkts", CTLFLAG_RW, 488615516c77SSepherosa Ziehau &rxr->hn_rss_pkts, 488715516c77SSepherosa Ziehau "# of packets w/ RSS info received"); 488815516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, 488915516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 489015516c77SSepherosa Ziehau OID_AUTO, "pktbuf_len", CTLFLAG_RD, 489115516c77SSepherosa Ziehau &rxr->hn_pktbuf_len, 0, 489215516c77SSepherosa Ziehau "Temporary channel packet buffer length"); 489315516c77SSepherosa Ziehau } 489415516c77SSepherosa Ziehau } 489515516c77SSepherosa Ziehau } 489615516c77SSepherosa Ziehau 489715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued", 489815516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 489915516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_queued), 490015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 490115516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 490215516c77SSepherosa Ziehau #else 490315516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 490415516c77SSepherosa Ziehau #endif 490515516c77SSepherosa Ziehau "LU", "LRO queued"); 490615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed", 490715516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 490815516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_flushed), 490915516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 491015516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 491115516c77SSepherosa Ziehau #else 491215516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 491315516c77SSepherosa Ziehau #endif 491415516c77SSepherosa Ziehau "LU", "LRO flushed"); 491515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried", 491615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 491715516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro_tried), 491815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries"); 491915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 492015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim", 492115516c77SSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 492215516c77SSepherosa Ziehau hn_lro_lenlim_sysctl, "IU", 492315516c77SSepherosa Ziehau "Max # of data bytes to be aggregated by LRO"); 492415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim", 492515516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 492615516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl, "I", 492715516c77SSepherosa Ziehau "Max # of ACKs to be aggregated by LRO"); 492815516c77SSepherosa Ziehau #endif 492915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp", 493015516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP, 493115516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 493215516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 493315516c77SSepherosa Ziehau "when csum info is missing"); 493415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp", 493515516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP, 493615516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 493715516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 493815516c77SSepherosa Ziehau "when csum info is missing"); 493915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip", 494015516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP, 494115516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 494215516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 494315516c77SSepherosa Ziehau "when csum info is missing"); 494415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip", 494515516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 494615516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_ip), 494715516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP"); 494815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp", 494915516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 495015516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_tcp), 495115516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP"); 495215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp", 495315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 495415516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_udp), 495515516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP"); 495615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted", 495715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 495815516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_trusted), 495915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", 496015516c77SSepherosa Ziehau "# of packets that we trust host's csum verification"); 496115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts", 496215516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 496315516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_small_pkts), 496415516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of small packets received"); 496515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed", 496615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 496715516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_ack_failed), 496815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures"); 496915516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt", 497015516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings"); 497115516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse", 497215516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings"); 497315516c77SSepherosa Ziehau 497415516c77SSepherosa Ziehau return (0); 497515516c77SSepherosa Ziehau } 497615516c77SSepherosa Ziehau 497715516c77SSepherosa Ziehau static void 497815516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc) 497915516c77SSepherosa Ziehau { 498015516c77SSepherosa Ziehau int i; 498115516c77SSepherosa Ziehau 498215516c77SSepherosa Ziehau if (sc->hn_rxbuf != NULL) { 49832494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0) 498415516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf); 49852494d735SSepherosa Ziehau else 49862494d735SSepherosa Ziehau device_printf(sc->hn_dev, "RXBUF is referenced\n"); 498715516c77SSepherosa Ziehau sc->hn_rxbuf = NULL; 498815516c77SSepherosa Ziehau } 498915516c77SSepherosa Ziehau 499015516c77SSepherosa Ziehau if (sc->hn_rx_ring_cnt == 0) 499115516c77SSepherosa Ziehau return; 499215516c77SSepherosa Ziehau 499315516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 499415516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 499515516c77SSepherosa Ziehau 499615516c77SSepherosa Ziehau if (rxr->hn_br == NULL) 499715516c77SSepherosa Ziehau continue; 49982494d735SSepherosa Ziehau if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) { 499915516c77SSepherosa Ziehau hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br); 50002494d735SSepherosa Ziehau } else { 50012494d735SSepherosa Ziehau device_printf(sc->hn_dev, 50022494d735SSepherosa Ziehau "%dth channel bufring is referenced", i); 50032494d735SSepherosa Ziehau } 500415516c77SSepherosa Ziehau rxr->hn_br = NULL; 500515516c77SSepherosa Ziehau 500615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 500715516c77SSepherosa Ziehau tcp_lro_free(&rxr->hn_lro); 500815516c77SSepherosa Ziehau #endif 500915516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 501015516c77SSepherosa Ziehau } 501115516c77SSepherosa Ziehau free(sc->hn_rx_ring, M_DEVBUF); 501215516c77SSepherosa Ziehau sc->hn_rx_ring = NULL; 501315516c77SSepherosa Ziehau 501415516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = 0; 501515516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = 0; 501615516c77SSepherosa Ziehau } 501715516c77SSepherosa Ziehau 501815516c77SSepherosa Ziehau static int 501915516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id) 502015516c77SSepherosa Ziehau { 502115516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[id]; 502215516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 502315516c77SSepherosa Ziehau bus_dma_tag_t parent_dtag; 502415516c77SSepherosa Ziehau int error, i; 502515516c77SSepherosa Ziehau 502615516c77SSepherosa Ziehau txr->hn_sc = sc; 502715516c77SSepherosa Ziehau txr->hn_tx_idx = id; 502815516c77SSepherosa Ziehau 502915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 503015516c77SSepherosa Ziehau mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); 503115516c77SSepherosa Ziehau #endif 503215516c77SSepherosa Ziehau mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF); 503315516c77SSepherosa Ziehau 503415516c77SSepherosa Ziehau txr->hn_txdesc_cnt = HN_TX_DESC_CNT; 503515516c77SSepherosa Ziehau txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt, 503615516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 503715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 503815516c77SSepherosa Ziehau SLIST_INIT(&txr->hn_txlist); 503915516c77SSepherosa Ziehau #else 504015516c77SSepherosa Ziehau txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF, 504115516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 504215516c77SSepherosa Ziehau #endif 504315516c77SSepherosa Ziehau 50440e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) { 50450e11868dSSepherosa Ziehau txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ( 50460e11868dSSepherosa Ziehau device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id)); 50470e11868dSSepherosa Ziehau } else { 5048fdd0222aSSepherosa Ziehau txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt]; 50490e11868dSSepherosa Ziehau } 505015516c77SSepherosa Ziehau 505123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 505215516c77SSepherosa Ziehau if (hn_use_if_start) { 505315516c77SSepherosa Ziehau txr->hn_txeof = hn_start_txeof; 505415516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr); 505515516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr); 505623bf9e15SSepherosa Ziehau } else 505723bf9e15SSepherosa Ziehau #endif 505823bf9e15SSepherosa Ziehau { 505915516c77SSepherosa Ziehau int br_depth; 506015516c77SSepherosa Ziehau 506115516c77SSepherosa Ziehau txr->hn_txeof = hn_xmit_txeof; 506215516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr); 506315516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr); 506415516c77SSepherosa Ziehau 506515516c77SSepherosa Ziehau br_depth = hn_get_txswq_depth(txr); 506615516c77SSepherosa Ziehau txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF, 506715516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 506815516c77SSepherosa Ziehau } 506915516c77SSepherosa Ziehau 507015516c77SSepherosa Ziehau txr->hn_direct_tx_size = hn_direct_tx_size; 507115516c77SSepherosa Ziehau 507215516c77SSepherosa Ziehau /* 507315516c77SSepherosa Ziehau * Always schedule transmission instead of trying to do direct 507415516c77SSepherosa Ziehau * transmission. This one gives the best performance so far. 507515516c77SSepherosa Ziehau */ 507615516c77SSepherosa Ziehau txr->hn_sched_tx = 1; 507715516c77SSepherosa Ziehau 507815516c77SSepherosa Ziehau parent_dtag = bus_get_dma_tag(dev); 507915516c77SSepherosa Ziehau 508015516c77SSepherosa Ziehau /* DMA tag for RNDIS packet messages. */ 508115516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 508215516c77SSepherosa Ziehau HN_RNDIS_PKT_ALIGN, /* alignment */ 508315516c77SSepherosa Ziehau HN_RNDIS_PKT_BOUNDARY, /* boundary */ 508415516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 508515516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 508615516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 508715516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsize */ 508815516c77SSepherosa Ziehau 1, /* nsegments */ 508915516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsegsize */ 509015516c77SSepherosa Ziehau 0, /* flags */ 509115516c77SSepherosa Ziehau NULL, /* lockfunc */ 509215516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 509315516c77SSepherosa Ziehau &txr->hn_tx_rndis_dtag); 509415516c77SSepherosa Ziehau if (error) { 509515516c77SSepherosa Ziehau device_printf(dev, "failed to create rndis dmatag\n"); 509615516c77SSepherosa Ziehau return error; 509715516c77SSepherosa Ziehau } 509815516c77SSepherosa Ziehau 509915516c77SSepherosa Ziehau /* DMA tag for data. */ 510015516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 510115516c77SSepherosa Ziehau 1, /* alignment */ 510215516c77SSepherosa Ziehau HN_TX_DATA_BOUNDARY, /* boundary */ 510315516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 510415516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 510515516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 510615516c77SSepherosa Ziehau HN_TX_DATA_MAXSIZE, /* maxsize */ 510715516c77SSepherosa Ziehau HN_TX_DATA_SEGCNT_MAX, /* nsegments */ 510815516c77SSepherosa Ziehau HN_TX_DATA_SEGSIZE, /* maxsegsize */ 510915516c77SSepherosa Ziehau 0, /* flags */ 511015516c77SSepherosa Ziehau NULL, /* lockfunc */ 511115516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 511215516c77SSepherosa Ziehau &txr->hn_tx_data_dtag); 511315516c77SSepherosa Ziehau if (error) { 511415516c77SSepherosa Ziehau device_printf(dev, "failed to create data dmatag\n"); 511515516c77SSepherosa Ziehau return error; 511615516c77SSepherosa Ziehau } 511715516c77SSepherosa Ziehau 511815516c77SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) { 511915516c77SSepherosa Ziehau struct hn_txdesc *txd = &txr->hn_txdesc[i]; 512015516c77SSepherosa Ziehau 512115516c77SSepherosa Ziehau txd->txr = txr; 512215516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 5123dc13fee6SSepherosa Ziehau STAILQ_INIT(&txd->agg_list); 512415516c77SSepherosa Ziehau 512515516c77SSepherosa Ziehau /* 512615516c77SSepherosa Ziehau * Allocate and load RNDIS packet message. 512715516c77SSepherosa Ziehau */ 512815516c77SSepherosa Ziehau error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag, 512915516c77SSepherosa Ziehau (void **)&txd->rndis_pkt, 513015516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 513115516c77SSepherosa Ziehau &txd->rndis_pkt_dmap); 513215516c77SSepherosa Ziehau if (error) { 513315516c77SSepherosa Ziehau device_printf(dev, 513415516c77SSepherosa Ziehau "failed to allocate rndis_packet_msg, %d\n", i); 513515516c77SSepherosa Ziehau return error; 513615516c77SSepherosa Ziehau } 513715516c77SSepherosa Ziehau 513815516c77SSepherosa Ziehau error = bus_dmamap_load(txr->hn_tx_rndis_dtag, 513915516c77SSepherosa Ziehau txd->rndis_pkt_dmap, 514015516c77SSepherosa Ziehau txd->rndis_pkt, HN_RNDIS_PKT_LEN, 514115516c77SSepherosa Ziehau hyperv_dma_map_paddr, &txd->rndis_pkt_paddr, 514215516c77SSepherosa Ziehau BUS_DMA_NOWAIT); 514315516c77SSepherosa Ziehau if (error) { 514415516c77SSepherosa Ziehau device_printf(dev, 514515516c77SSepherosa Ziehau "failed to load rndis_packet_msg, %d\n", i); 514615516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 514715516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 514815516c77SSepherosa Ziehau return error; 514915516c77SSepherosa Ziehau } 515015516c77SSepherosa Ziehau 515115516c77SSepherosa Ziehau /* DMA map for TX data. */ 515215516c77SSepherosa Ziehau error = bus_dmamap_create(txr->hn_tx_data_dtag, 0, 515315516c77SSepherosa Ziehau &txd->data_dmap); 515415516c77SSepherosa Ziehau if (error) { 515515516c77SSepherosa Ziehau device_printf(dev, 515615516c77SSepherosa Ziehau "failed to allocate tx data dmamap\n"); 515715516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, 515815516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 515915516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 516015516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 516115516c77SSepherosa Ziehau return error; 516215516c77SSepherosa Ziehau } 516315516c77SSepherosa Ziehau 516415516c77SSepherosa Ziehau /* All set, put it to list */ 516515516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 516615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 516715516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 516815516c77SSepherosa Ziehau #else 516915516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 517015516c77SSepherosa Ziehau #endif 517115516c77SSepherosa Ziehau } 517215516c77SSepherosa Ziehau txr->hn_txdesc_avail = txr->hn_txdesc_cnt; 517315516c77SSepherosa Ziehau 517415516c77SSepherosa Ziehau if (sc->hn_tx_sysctl_tree != NULL) { 517515516c77SSepherosa Ziehau struct sysctl_oid_list *child; 517615516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 517715516c77SSepherosa Ziehau char name[16]; 517815516c77SSepherosa Ziehau 517915516c77SSepherosa Ziehau /* 518015516c77SSepherosa Ziehau * Create per TX ring sysctl tree: 518115516c77SSepherosa Ziehau * dev.hn.UNIT.tx.RINGID 518215516c77SSepherosa Ziehau */ 518315516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 518415516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree); 518515516c77SSepherosa Ziehau 518615516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", id); 518715516c77SSepherosa Ziehau txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, 518815516c77SSepherosa Ziehau name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 518915516c77SSepherosa Ziehau 519015516c77SSepherosa Ziehau if (txr->hn_tx_sysctl_tree != NULL) { 519115516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree); 519215516c77SSepherosa Ziehau 519385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 519415516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail", 519515516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_txdesc_avail, 0, 519615516c77SSepherosa Ziehau "# of available TX descs"); 519785e4ae1eSSepherosa Ziehau #endif 519823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 519923bf9e15SSepherosa Ziehau if (!hn_use_if_start) 520023bf9e15SSepherosa Ziehau #endif 520123bf9e15SSepherosa Ziehau { 520215516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive", 520315516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_oactive, 0, 520415516c77SSepherosa Ziehau "over active"); 520515516c77SSepherosa Ziehau } 520615516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets", 520715516c77SSepherosa Ziehau CTLFLAG_RW, &txr->hn_pkts, 520815516c77SSepherosa Ziehau "# of packets transmitted"); 5209dc13fee6SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends", 5210dc13fee6SSepherosa Ziehau CTLFLAG_RW, &txr->hn_sends, "# of sends"); 521115516c77SSepherosa Ziehau } 521215516c77SSepherosa Ziehau } 521315516c77SSepherosa Ziehau 521415516c77SSepherosa Ziehau return 0; 521515516c77SSepherosa Ziehau } 521615516c77SSepherosa Ziehau 521715516c77SSepherosa Ziehau static void 521815516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd) 521915516c77SSepherosa Ziehau { 522015516c77SSepherosa Ziehau struct hn_tx_ring *txr = txd->txr; 522115516c77SSepherosa Ziehau 522215516c77SSepherosa Ziehau KASSERT(txd->m == NULL, ("still has mbuf installed")); 522315516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped")); 522415516c77SSepherosa Ziehau 522515516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap); 522615516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt, 522715516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 522815516c77SSepherosa Ziehau bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap); 522915516c77SSepherosa Ziehau } 523015516c77SSepherosa Ziehau 523115516c77SSepherosa Ziehau static void 523225641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd) 523325641fc7SSepherosa Ziehau { 523425641fc7SSepherosa Ziehau 523525641fc7SSepherosa Ziehau KASSERT(txd->refs == 0 || txd->refs == 1, 523625641fc7SSepherosa Ziehau ("invalid txd refs %d", txd->refs)); 523725641fc7SSepherosa Ziehau 523825641fc7SSepherosa Ziehau /* Aggregated txds will be freed by their aggregating txd. */ 523925641fc7SSepherosa Ziehau if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) { 524025641fc7SSepherosa Ziehau int freed; 524125641fc7SSepherosa Ziehau 524225641fc7SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 524325641fc7SSepherosa Ziehau KASSERT(freed, ("can't free txdesc")); 524425641fc7SSepherosa Ziehau } 524525641fc7SSepherosa Ziehau } 524625641fc7SSepherosa Ziehau 524725641fc7SSepherosa Ziehau static void 524815516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr) 524915516c77SSepherosa Ziehau { 525025641fc7SSepherosa Ziehau int i; 525115516c77SSepherosa Ziehau 525215516c77SSepherosa Ziehau if (txr->hn_txdesc == NULL) 525315516c77SSepherosa Ziehau return; 525415516c77SSepherosa Ziehau 525525641fc7SSepherosa Ziehau /* 525625641fc7SSepherosa Ziehau * NOTE: 525725641fc7SSepherosa Ziehau * Because the freeing of aggregated txds will be deferred 525825641fc7SSepherosa Ziehau * to the aggregating txd, two passes are used here: 525925641fc7SSepherosa Ziehau * - The first pass GCes any pending txds. This GC is necessary, 526025641fc7SSepherosa Ziehau * since if the channels are revoked, hypervisor will not 526125641fc7SSepherosa Ziehau * deliver send-done for all pending txds. 526225641fc7SSepherosa Ziehau * - The second pass frees the busdma stuffs, i.e. after all txds 526325641fc7SSepherosa Ziehau * were freed. 526425641fc7SSepherosa Ziehau */ 526525641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 526625641fc7SSepherosa Ziehau hn_txdesc_gc(txr, &txr->hn_txdesc[i]); 526725641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 526825641fc7SSepherosa Ziehau hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]); 526915516c77SSepherosa Ziehau 527015516c77SSepherosa Ziehau if (txr->hn_tx_data_dtag != NULL) 527115516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_data_dtag); 527215516c77SSepherosa Ziehau if (txr->hn_tx_rndis_dtag != NULL) 527315516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_rndis_dtag); 527415516c77SSepherosa Ziehau 527515516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 527615516c77SSepherosa Ziehau buf_ring_free(txr->hn_txdesc_br, M_DEVBUF); 527715516c77SSepherosa Ziehau #endif 527815516c77SSepherosa Ziehau 527915516c77SSepherosa Ziehau free(txr->hn_txdesc, M_DEVBUF); 528015516c77SSepherosa Ziehau txr->hn_txdesc = NULL; 528115516c77SSepherosa Ziehau 528215516c77SSepherosa Ziehau if (txr->hn_mbuf_br != NULL) 528315516c77SSepherosa Ziehau buf_ring_free(txr->hn_mbuf_br, M_DEVBUF); 528415516c77SSepherosa Ziehau 528515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 528615516c77SSepherosa Ziehau mtx_destroy(&txr->hn_txlist_spin); 528715516c77SSepherosa Ziehau #endif 528815516c77SSepherosa Ziehau mtx_destroy(&txr->hn_tx_lock); 528915516c77SSepherosa Ziehau } 529015516c77SSepherosa Ziehau 529115516c77SSepherosa Ziehau static int 529215516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt) 529315516c77SSepherosa Ziehau { 529415516c77SSepherosa Ziehau struct sysctl_oid_list *child; 529515516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 529615516c77SSepherosa Ziehau int i; 529715516c77SSepherosa Ziehau 529815516c77SSepherosa Ziehau /* 529915516c77SSepherosa Ziehau * Create TXBUF for chimney sending. 530015516c77SSepherosa Ziehau * 530115516c77SSepherosa Ziehau * NOTE: It is shared by all channels. 530215516c77SSepherosa Ziehau */ 530315516c77SSepherosa Ziehau sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), 530415516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma, 530515516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 530615516c77SSepherosa Ziehau if (sc->hn_chim == NULL) { 530715516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate txbuf failed\n"); 530815516c77SSepherosa Ziehau return (ENOMEM); 530915516c77SSepherosa Ziehau } 531015516c77SSepherosa Ziehau 531115516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = ring_cnt; 531215516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 531315516c77SSepherosa Ziehau 531415516c77SSepherosa Ziehau sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt, 531515516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 531615516c77SSepherosa Ziehau 531715516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(sc->hn_dev); 531815516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev)); 531915516c77SSepherosa Ziehau 532015516c77SSepherosa Ziehau /* Create dev.hn.UNIT.tx sysctl tree */ 532115516c77SSepherosa Ziehau sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx", 532215516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 532315516c77SSepherosa Ziehau 532415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 532515516c77SSepherosa Ziehau int error; 532615516c77SSepherosa Ziehau 532715516c77SSepherosa Ziehau error = hn_tx_ring_create(sc, i); 532815516c77SSepherosa Ziehau if (error) 532915516c77SSepherosa Ziehau return error; 533015516c77SSepherosa Ziehau } 533115516c77SSepherosa Ziehau 533215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs", 533315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 533415516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_no_txdescs), 533515516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs"); 533615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed", 533715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 533815516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_send_failed), 533915516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure"); 534015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed", 534115516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 534215516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_txdma_failed), 534315516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure"); 5344dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed", 5345dc13fee6SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 5346dc13fee6SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_flush_failed), 5347dc13fee6SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", 5348dc13fee6SSepherosa Ziehau "# of packet transmission aggregation flush failure"); 534915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed", 535015516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 535115516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_collapsed), 535215516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed"); 535315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney", 535415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 535515516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney), 535615516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send"); 535715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried", 535815516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 535915516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney_tried), 536015516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries"); 536115516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt", 536215516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0, 536315516c77SSepherosa Ziehau "# of total TX descs"); 536415516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max", 536515516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_chim_szmax, 0, 536615516c77SSepherosa Ziehau "Chimney send packet size upper boundary"); 536715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size", 536815516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 536915516c77SSepherosa Ziehau hn_chim_size_sysctl, "I", "Chimney send packet size limit"); 537015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size", 537115516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 537215516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_direct_tx_size), 537315516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 537415516c77SSepherosa Ziehau "Size of the packet for direct transmission"); 537515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx", 537615516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 537715516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_sched_tx), 537815516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 537915516c77SSepherosa Ziehau "Always schedule transmission " 538015516c77SSepherosa Ziehau "instead of doing direct transmission"); 538115516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt", 538215516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings"); 538315516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse", 538415516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings"); 5385dc13fee6SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax", 5386dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0, 5387dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation size"); 5388dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax", 5389dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 5390dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl, "I", 5391dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation packets"); 5392dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align", 5393dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 5394dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl, "I", 5395dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation alignment"); 539615516c77SSepherosa Ziehau 539715516c77SSepherosa Ziehau return 0; 539815516c77SSepherosa Ziehau } 539915516c77SSepherosa Ziehau 540015516c77SSepherosa Ziehau static void 540115516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size) 540215516c77SSepherosa Ziehau { 540315516c77SSepherosa Ziehau int i; 540415516c77SSepherosa Ziehau 5405a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 540615516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_chim_size = chim_size; 540715516c77SSepherosa Ziehau } 540815516c77SSepherosa Ziehau 540915516c77SSepherosa Ziehau static void 541015516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu) 541115516c77SSepherosa Ziehau { 541215516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 54139c6cae24SSepherosa Ziehau u_int hw_tsomax; 541415516c77SSepherosa Ziehau int tso_minlen; 541515516c77SSepherosa Ziehau 54169c6cae24SSepherosa Ziehau HN_LOCK_ASSERT(sc); 54179c6cae24SSepherosa Ziehau 541815516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0) 541915516c77SSepherosa Ziehau return; 542015516c77SSepherosa Ziehau 542115516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_sgmin >= 2, 542215516c77SSepherosa Ziehau ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin)); 542315516c77SSepherosa Ziehau tso_minlen = sc->hn_ndis_tso_sgmin * mtu; 542415516c77SSepherosa Ziehau 542515516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen && 542615516c77SSepherosa Ziehau sc->hn_ndis_tso_szmax <= IP_MAXPACKET, 542715516c77SSepherosa Ziehau ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax)); 542815516c77SSepherosa Ziehau 542915516c77SSepherosa Ziehau if (tso_maxlen < tso_minlen) 543015516c77SSepherosa Ziehau tso_maxlen = tso_minlen; 543115516c77SSepherosa Ziehau else if (tso_maxlen > IP_MAXPACKET) 543215516c77SSepherosa Ziehau tso_maxlen = IP_MAXPACKET; 543315516c77SSepherosa Ziehau if (tso_maxlen > sc->hn_ndis_tso_szmax) 543415516c77SSepherosa Ziehau tso_maxlen = sc->hn_ndis_tso_szmax; 54359c6cae24SSepherosa Ziehau hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 54369c6cae24SSepherosa Ziehau 54379c6cae24SSepherosa Ziehau if (hn_xpnt_vf_isready(sc)) { 54389c6cae24SSepherosa Ziehau if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax) 54399c6cae24SSepherosa Ziehau hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax; 54409c6cae24SSepherosa Ziehau } 54419c6cae24SSepherosa Ziehau ifp->if_hw_tsomax = hw_tsomax; 544215516c77SSepherosa Ziehau if (bootverbose) 544315516c77SSepherosa Ziehau if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax); 544415516c77SSepherosa Ziehau } 544515516c77SSepherosa Ziehau 544615516c77SSepherosa Ziehau static void 544715516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc) 544815516c77SSepherosa Ziehau { 544915516c77SSepherosa Ziehau uint64_t csum_assist; 545015516c77SSepherosa Ziehau int i; 545115516c77SSepherosa Ziehau 545215516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 545315516c77SSepherosa Ziehau if (hn_tx_chimney_size > 0 && 545415516c77SSepherosa Ziehau hn_tx_chimney_size < sc->hn_chim_szmax) 545515516c77SSepherosa Ziehau hn_set_chim_size(sc, hn_tx_chimney_size); 545615516c77SSepherosa Ziehau 545715516c77SSepherosa Ziehau csum_assist = 0; 545815516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_IPCS) 545915516c77SSepherosa Ziehau csum_assist |= CSUM_IP; 546015516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP4CS) 546115516c77SSepherosa Ziehau csum_assist |= CSUM_IP_TCP; 546215516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP4CS) 546315516c77SSepherosa Ziehau csum_assist |= CSUM_IP_UDP; 546415516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP6CS) 546515516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_TCP; 546615516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP6CS) 546715516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_UDP; 546815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 546915516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_csum_assist = csum_assist; 547015516c77SSepherosa Ziehau 547115516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_HASHVAL) { 547215516c77SSepherosa Ziehau /* 547315516c77SSepherosa Ziehau * Support HASHVAL pktinfo on TX path. 547415516c77SSepherosa Ziehau */ 547515516c77SSepherosa Ziehau if (bootverbose) 547615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n"); 547715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 547815516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL; 547915516c77SSepherosa Ziehau } 548015516c77SSepherosa Ziehau } 548115516c77SSepherosa Ziehau 548215516c77SSepherosa Ziehau static void 548315516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc) 548415516c77SSepherosa Ziehau { 548515516c77SSepherosa Ziehau int i; 548615516c77SSepherosa Ziehau 548715516c77SSepherosa Ziehau if (sc->hn_chim != NULL) { 54882494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) { 548915516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim); 54902494d735SSepherosa Ziehau } else { 54912494d735SSepherosa Ziehau device_printf(sc->hn_dev, 54922494d735SSepherosa Ziehau "chimney sending buffer is referenced"); 54932494d735SSepherosa Ziehau } 549415516c77SSepherosa Ziehau sc->hn_chim = NULL; 549515516c77SSepherosa Ziehau } 549615516c77SSepherosa Ziehau 549715516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt == 0) 549815516c77SSepherosa Ziehau return; 549915516c77SSepherosa Ziehau 550015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 550115516c77SSepherosa Ziehau hn_tx_ring_destroy(&sc->hn_tx_ring[i]); 550215516c77SSepherosa Ziehau 550315516c77SSepherosa Ziehau free(sc->hn_tx_ring, M_DEVBUF); 550415516c77SSepherosa Ziehau sc->hn_tx_ring = NULL; 550515516c77SSepherosa Ziehau 550615516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = 0; 550715516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = 0; 550815516c77SSepherosa Ziehau } 550915516c77SSepherosa Ziehau 551023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 551123bf9e15SSepherosa Ziehau 551215516c77SSepherosa Ziehau static void 551315516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused) 551415516c77SSepherosa Ziehau { 551515516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 551615516c77SSepherosa Ziehau 551715516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 551815516c77SSepherosa Ziehau hn_start_locked(txr, 0); 551915516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 552015516c77SSepherosa Ziehau } 552115516c77SSepherosa Ziehau 552223bf9e15SSepherosa Ziehau static int 552323bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len) 552423bf9e15SSepherosa Ziehau { 552523bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 552623bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 5527dc13fee6SSepherosa Ziehau int sched = 0; 552823bf9e15SSepherosa Ziehau 552923bf9e15SSepherosa Ziehau KASSERT(hn_use_if_start, 553023bf9e15SSepherosa Ziehau ("hn_start_locked is called, when if_start is disabled")); 553123bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 553223bf9e15SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 5533dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 553423bf9e15SSepherosa Ziehau 553523bf9e15SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 5536dc13fee6SSepherosa Ziehau return (0); 553723bf9e15SSepherosa Ziehau 553823bf9e15SSepherosa Ziehau if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 553923bf9e15SSepherosa Ziehau IFF_DRV_RUNNING) 5540dc13fee6SSepherosa Ziehau return (0); 554123bf9e15SSepherosa Ziehau 554223bf9e15SSepherosa Ziehau while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 554323bf9e15SSepherosa Ziehau struct hn_txdesc *txd; 554423bf9e15SSepherosa Ziehau struct mbuf *m_head; 554523bf9e15SSepherosa Ziehau int error; 554623bf9e15SSepherosa Ziehau 554723bf9e15SSepherosa Ziehau IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 554823bf9e15SSepherosa Ziehau if (m_head == NULL) 554923bf9e15SSepherosa Ziehau break; 555023bf9e15SSepherosa Ziehau 555123bf9e15SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 555223bf9e15SSepherosa Ziehau /* 555323bf9e15SSepherosa Ziehau * This sending could be time consuming; let callers 555423bf9e15SSepherosa Ziehau * dispatch this packet sending (and sending of any 555523bf9e15SSepherosa Ziehau * following up packets) to tx taskqueue. 555623bf9e15SSepherosa Ziehau */ 555723bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 5558dc13fee6SSepherosa Ziehau sched = 1; 5559dc13fee6SSepherosa Ziehau break; 556023bf9e15SSepherosa Ziehau } 556123bf9e15SSepherosa Ziehau 5562edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 5563edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 5564edd3f315SSepherosa Ziehau m_head = hn_tso_fixup(m_head); 5565edd3f315SSepherosa Ziehau if (__predict_false(m_head == NULL)) { 5566edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 5567edd3f315SSepherosa Ziehau continue; 5568edd3f315SSepherosa Ziehau } 5569edd3f315SSepherosa Ziehau } 5570edd3f315SSepherosa Ziehau #endif 5571edd3f315SSepherosa Ziehau 557223bf9e15SSepherosa Ziehau txd = hn_txdesc_get(txr); 557323bf9e15SSepherosa Ziehau if (txd == NULL) { 557423bf9e15SSepherosa Ziehau txr->hn_no_txdescs++; 557523bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 557623bf9e15SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 557723bf9e15SSepherosa Ziehau break; 557823bf9e15SSepherosa Ziehau } 557923bf9e15SSepherosa Ziehau 5580dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 558123bf9e15SSepherosa Ziehau if (error) { 558223bf9e15SSepherosa Ziehau /* Both txd and m_head are freed */ 5583dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 5584dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 558523bf9e15SSepherosa Ziehau continue; 558623bf9e15SSepherosa Ziehau } 558723bf9e15SSepherosa Ziehau 5588dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 5589dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 5590dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5591dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5592dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 5593dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 5594dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 5595dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 5596dc13fee6SSepherosa Ziehau break; 5597dc13fee6SSepherosa Ziehau } 5598dc13fee6SSepherosa Ziehau } else { 5599dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 560023bf9e15SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 560123bf9e15SSepherosa Ziehau if (__predict_false(error)) { 560223bf9e15SSepherosa Ziehau /* txd is freed, but m_head is not */ 560323bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 5604dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 5605dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 560623bf9e15SSepherosa Ziehau break; 560723bf9e15SSepherosa Ziehau } 560823bf9e15SSepherosa Ziehau } 5609dc13fee6SSepherosa Ziehau } 5610dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 5611dc13fee6SSepherosa Ziehau else { 5612dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 5613dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 5614dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5615dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5616dc13fee6SSepherosa Ziehau } 5617dc13fee6SSepherosa Ziehau #endif 5618dc13fee6SSepherosa Ziehau } 5619dc13fee6SSepherosa Ziehau 5620dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 5621dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 5622dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 5623dc13fee6SSepherosa Ziehau return (sched); 562423bf9e15SSepherosa Ziehau } 562523bf9e15SSepherosa Ziehau 562623bf9e15SSepherosa Ziehau static void 562723bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp) 562823bf9e15SSepherosa Ziehau { 562923bf9e15SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 563023bf9e15SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[0]; 563123bf9e15SSepherosa Ziehau 563223bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 563323bf9e15SSepherosa Ziehau goto do_sched; 563423bf9e15SSepherosa Ziehau 563523bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 563623bf9e15SSepherosa Ziehau int sched; 563723bf9e15SSepherosa Ziehau 563823bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 563923bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 564023bf9e15SSepherosa Ziehau if (!sched) 564123bf9e15SSepherosa Ziehau return; 564223bf9e15SSepherosa Ziehau } 564323bf9e15SSepherosa Ziehau do_sched: 564423bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 564523bf9e15SSepherosa Ziehau } 564623bf9e15SSepherosa Ziehau 564715516c77SSepherosa Ziehau static void 564815516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused) 564915516c77SSepherosa Ziehau { 565015516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 565115516c77SSepherosa Ziehau 565215516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 565315516c77SSepherosa Ziehau atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE); 565415516c77SSepherosa Ziehau hn_start_locked(txr, 0); 565515516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 565615516c77SSepherosa Ziehau } 565715516c77SSepherosa Ziehau 565823bf9e15SSepherosa Ziehau static void 565923bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr) 566023bf9e15SSepherosa Ziehau { 566123bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 566223bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 566323bf9e15SSepherosa Ziehau 566423bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 566523bf9e15SSepherosa Ziehau 566623bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 566723bf9e15SSepherosa Ziehau goto do_sched; 566823bf9e15SSepherosa Ziehau 566923bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 567023bf9e15SSepherosa Ziehau int sched; 567123bf9e15SSepherosa Ziehau 567223bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 567323bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 567423bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 567523bf9e15SSepherosa Ziehau if (sched) { 567623bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 567723bf9e15SSepherosa Ziehau &txr->hn_tx_task); 567823bf9e15SSepherosa Ziehau } 567923bf9e15SSepherosa Ziehau } else { 568023bf9e15SSepherosa Ziehau do_sched: 568123bf9e15SSepherosa Ziehau /* 568223bf9e15SSepherosa Ziehau * Release the OACTIVE earlier, with the hope, that 568323bf9e15SSepherosa Ziehau * others could catch up. The task will clear the 568423bf9e15SSepherosa Ziehau * flag again with the hn_tx_lock to avoid possible 568523bf9e15SSepherosa Ziehau * races. 568623bf9e15SSepherosa Ziehau */ 568723bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 568823bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 568923bf9e15SSepherosa Ziehau } 569023bf9e15SSepherosa Ziehau } 569123bf9e15SSepherosa Ziehau 569223bf9e15SSepherosa Ziehau #endif /* HN_IFSTART_SUPPORT */ 569323bf9e15SSepherosa Ziehau 569415516c77SSepherosa Ziehau static int 569515516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len) 569615516c77SSepherosa Ziehau { 569715516c77SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 569815516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 569915516c77SSepherosa Ziehau struct mbuf *m_head; 5700dc13fee6SSepherosa Ziehau int sched = 0; 570115516c77SSepherosa Ziehau 570215516c77SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 570323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 570415516c77SSepherosa Ziehau KASSERT(hn_use_if_start == 0, 570515516c77SSepherosa Ziehau ("hn_xmit is called, when if_start is enabled")); 570623bf9e15SSepherosa Ziehau #endif 5707dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 570815516c77SSepherosa Ziehau 570915516c77SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 5710dc13fee6SSepherosa Ziehau return (0); 571115516c77SSepherosa Ziehau 571215516c77SSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive) 5713dc13fee6SSepherosa Ziehau return (0); 571415516c77SSepherosa Ziehau 571515516c77SSepherosa Ziehau while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) { 571615516c77SSepherosa Ziehau struct hn_txdesc *txd; 571715516c77SSepherosa Ziehau int error; 571815516c77SSepherosa Ziehau 571915516c77SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 572015516c77SSepherosa Ziehau /* 572115516c77SSepherosa Ziehau * This sending could be time consuming; let callers 572215516c77SSepherosa Ziehau * dispatch this packet sending (and sending of any 572315516c77SSepherosa Ziehau * following up packets) to tx taskqueue. 572415516c77SSepherosa Ziehau */ 572515516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 5726dc13fee6SSepherosa Ziehau sched = 1; 5727dc13fee6SSepherosa Ziehau break; 572815516c77SSepherosa Ziehau } 572915516c77SSepherosa Ziehau 573015516c77SSepherosa Ziehau txd = hn_txdesc_get(txr); 573115516c77SSepherosa Ziehau if (txd == NULL) { 573215516c77SSepherosa Ziehau txr->hn_no_txdescs++; 573315516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 573415516c77SSepherosa Ziehau txr->hn_oactive = 1; 573515516c77SSepherosa Ziehau break; 573615516c77SSepherosa Ziehau } 573715516c77SSepherosa Ziehau 5738dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 573915516c77SSepherosa Ziehau if (error) { 574015516c77SSepherosa Ziehau /* Both txd and m_head are freed; discard */ 5741dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 5742dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 574315516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 574415516c77SSepherosa Ziehau continue; 574515516c77SSepherosa Ziehau } 574615516c77SSepherosa Ziehau 5747dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 5748dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 5749dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5750dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5751dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 575215516c77SSepherosa Ziehau if (__predict_false(error)) { 575315516c77SSepherosa Ziehau txr->hn_oactive = 1; 575415516c77SSepherosa Ziehau break; 575515516c77SSepherosa Ziehau } 5756dc13fee6SSepherosa Ziehau } else { 5757dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 5758dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 5759dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 5760dc13fee6SSepherosa Ziehau /* txd is freed, but m_head is not */ 5761dc13fee6SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, 5762dc13fee6SSepherosa Ziehau m_head); 5763dc13fee6SSepherosa Ziehau txr->hn_oactive = 1; 5764dc13fee6SSepherosa Ziehau break; 5765dc13fee6SSepherosa Ziehau } 5766dc13fee6SSepherosa Ziehau } 5767dc13fee6SSepherosa Ziehau } 5768dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 5769dc13fee6SSepherosa Ziehau else { 5770dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 5771dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 5772dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 5773dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 5774dc13fee6SSepherosa Ziehau } 5775dc13fee6SSepherosa Ziehau #endif 577615516c77SSepherosa Ziehau 577715516c77SSepherosa Ziehau /* Sent */ 577815516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 577915516c77SSepherosa Ziehau } 5780dc13fee6SSepherosa Ziehau 5781dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 5782dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 5783dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 5784dc13fee6SSepherosa Ziehau return (sched); 578515516c77SSepherosa Ziehau } 578615516c77SSepherosa Ziehau 578715516c77SSepherosa Ziehau static int 578815516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m) 578915516c77SSepherosa Ziehau { 579015516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 579115516c77SSepherosa Ziehau struct hn_tx_ring *txr; 579215516c77SSepherosa Ziehau int error, idx = 0; 579315516c77SSepherosa Ziehau 57949c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) { 57959c6cae24SSepherosa Ziehau struct rm_priotracker pt; 57969c6cae24SSepherosa Ziehau 57979c6cae24SSepherosa Ziehau rm_rlock(&sc->hn_vf_lock, &pt); 57989c6cae24SSepherosa Ziehau if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { 57999c6cae24SSepherosa Ziehau struct mbuf *m_bpf = NULL; 58009c6cae24SSepherosa Ziehau int obytes, omcast; 58019c6cae24SSepherosa Ziehau 58029c6cae24SSepherosa Ziehau obytes = m->m_pkthdr.len; 58039c6cae24SSepherosa Ziehau if (m->m_flags & M_MCAST) 58049c6cae24SSepherosa Ziehau omcast = 1; 58059c6cae24SSepherosa Ziehau 58069c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) { 58079c6cae24SSepherosa Ziehau if (bpf_peers_present(ifp->if_bpf)) { 58089c6cae24SSepherosa Ziehau m_bpf = m_copypacket(m, M_NOWAIT); 58099c6cae24SSepherosa Ziehau if (m_bpf == NULL) { 58109c6cae24SSepherosa Ziehau /* 58119c6cae24SSepherosa Ziehau * Failed to grab a shallow 58129c6cae24SSepherosa Ziehau * copy; tap now. 58139c6cae24SSepherosa Ziehau */ 58149c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m); 58159c6cae24SSepherosa Ziehau } 58169c6cae24SSepherosa Ziehau } 58179c6cae24SSepherosa Ziehau } else { 58189c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m); 58199c6cae24SSepherosa Ziehau } 58209c6cae24SSepherosa Ziehau 58219c6cae24SSepherosa Ziehau error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m); 58229c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 58239c6cae24SSepherosa Ziehau 58249c6cae24SSepherosa Ziehau if (m_bpf != NULL) { 58259c6cae24SSepherosa Ziehau if (!error) 58269c6cae24SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m_bpf); 58279c6cae24SSepherosa Ziehau m_freem(m_bpf); 58289c6cae24SSepherosa Ziehau } 58299c6cae24SSepherosa Ziehau 58309c6cae24SSepherosa Ziehau if (error == ENOBUFS) { 58319c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 58329c6cae24SSepherosa Ziehau } else if (error) { 58339c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 58349c6cae24SSepherosa Ziehau } else { 58359c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 58369c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes); 58379c6cae24SSepherosa Ziehau if (omcast) { 58389c6cae24SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 58399c6cae24SSepherosa Ziehau omcast); 58409c6cae24SSepherosa Ziehau } 58419c6cae24SSepherosa Ziehau } 58429c6cae24SSepherosa Ziehau return (error); 58439c6cae24SSepherosa Ziehau } 58449c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 58459c6cae24SSepherosa Ziehau } 58469c6cae24SSepherosa Ziehau 5847edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 5848edd3f315SSepherosa Ziehau /* 5849edd3f315SSepherosa Ziehau * Perform TSO packet header fixup now, since the TSO 5850edd3f315SSepherosa Ziehau * packet header should be cache-hot. 5851edd3f315SSepherosa Ziehau */ 5852edd3f315SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 5853edd3f315SSepherosa Ziehau m = hn_tso_fixup(m); 5854edd3f315SSepherosa Ziehau if (__predict_false(m == NULL)) { 5855edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 5856edd3f315SSepherosa Ziehau return EIO; 5857edd3f315SSepherosa Ziehau } 5858edd3f315SSepherosa Ziehau } 5859edd3f315SSepherosa Ziehau #endif 5860edd3f315SSepherosa Ziehau 586115516c77SSepherosa Ziehau /* 586215516c77SSepherosa Ziehau * Select the TX ring based on flowid 586315516c77SSepherosa Ziehau */ 586434d68912SSepherosa Ziehau if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 586534d68912SSepherosa Ziehau #ifdef RSS 586634d68912SSepherosa Ziehau uint32_t bid; 586734d68912SSepherosa Ziehau 586834d68912SSepherosa Ziehau if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m), 586934d68912SSepherosa Ziehau &bid) == 0) 587034d68912SSepherosa Ziehau idx = bid % sc->hn_tx_ring_inuse; 587134d68912SSepherosa Ziehau else 587234d68912SSepherosa Ziehau #endif 5873cc0c6ebcSSepherosa Ziehau { 5874cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET) 5875cc0c6ebcSSepherosa Ziehau int tcpsyn = 0; 5876cc0c6ebcSSepherosa Ziehau 5877cc0c6ebcSSepherosa Ziehau if (m->m_pkthdr.len < 128 && 5878cc0c6ebcSSepherosa Ziehau (m->m_pkthdr.csum_flags & 5879cc0c6ebcSSepherosa Ziehau (CSUM_IP_TCP | CSUM_IP6_TCP)) && 5880cc0c6ebcSSepherosa Ziehau (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) { 5881cc0c6ebcSSepherosa Ziehau m = hn_check_tcpsyn(m, &tcpsyn); 5882cc0c6ebcSSepherosa Ziehau if (__predict_false(m == NULL)) { 5883cc0c6ebcSSepherosa Ziehau if_inc_counter(ifp, 5884cc0c6ebcSSepherosa Ziehau IFCOUNTER_OERRORS, 1); 5885cc0c6ebcSSepherosa Ziehau return (EIO); 5886cc0c6ebcSSepherosa Ziehau } 5887cc0c6ebcSSepherosa Ziehau } 5888cc0c6ebcSSepherosa Ziehau #else 5889cc0c6ebcSSepherosa Ziehau const int tcpsyn = 0; 5890cc0c6ebcSSepherosa Ziehau #endif 5891cc0c6ebcSSepherosa Ziehau if (tcpsyn) 5892cc0c6ebcSSepherosa Ziehau idx = 0; 5893cc0c6ebcSSepherosa Ziehau else 589415516c77SSepherosa Ziehau idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse; 589534d68912SSepherosa Ziehau } 5896cc0c6ebcSSepherosa Ziehau } 589715516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 589815516c77SSepherosa Ziehau 589915516c77SSepherosa Ziehau error = drbr_enqueue(ifp, txr->hn_mbuf_br, m); 590015516c77SSepherosa Ziehau if (error) { 590115516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 590215516c77SSepherosa Ziehau return error; 590315516c77SSepherosa Ziehau } 590415516c77SSepherosa Ziehau 590515516c77SSepherosa Ziehau if (txr->hn_oactive) 590615516c77SSepherosa Ziehau return 0; 590715516c77SSepherosa Ziehau 590815516c77SSepherosa Ziehau if (txr->hn_sched_tx) 590915516c77SSepherosa Ziehau goto do_sched; 591015516c77SSepherosa Ziehau 591115516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 591215516c77SSepherosa Ziehau int sched; 591315516c77SSepherosa Ziehau 591415516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 591515516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 591615516c77SSepherosa Ziehau if (!sched) 591715516c77SSepherosa Ziehau return 0; 591815516c77SSepherosa Ziehau } 591915516c77SSepherosa Ziehau do_sched: 592015516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 592115516c77SSepherosa Ziehau return 0; 592215516c77SSepherosa Ziehau } 592315516c77SSepherosa Ziehau 592415516c77SSepherosa Ziehau static void 592515516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr) 592615516c77SSepherosa Ziehau { 592715516c77SSepherosa Ziehau struct mbuf *m; 592815516c77SSepherosa Ziehau 592915516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 593015516c77SSepherosa Ziehau while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL) 593115516c77SSepherosa Ziehau m_freem(m); 593215516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 593315516c77SSepherosa Ziehau } 593415516c77SSepherosa Ziehau 593515516c77SSepherosa Ziehau static void 593615516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp) 593715516c77SSepherosa Ziehau { 593815516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 59399c6cae24SSepherosa Ziehau struct rm_priotracker pt; 594015516c77SSepherosa Ziehau int i; 594115516c77SSepherosa Ziehau 594215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 594315516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 594415516c77SSepherosa Ziehau if_qflush(ifp); 59459c6cae24SSepherosa Ziehau 59469c6cae24SSepherosa Ziehau rm_rlock(&sc->hn_vf_lock, &pt); 59479c6cae24SSepherosa Ziehau if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) 59489c6cae24SSepherosa Ziehau sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp); 59499c6cae24SSepherosa Ziehau rm_runlock(&sc->hn_vf_lock, &pt); 595015516c77SSepherosa Ziehau } 595115516c77SSepherosa Ziehau 595215516c77SSepherosa Ziehau static void 595315516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr) 595415516c77SSepherosa Ziehau { 595515516c77SSepherosa Ziehau 595615516c77SSepherosa Ziehau if (txr->hn_sched_tx) 595715516c77SSepherosa Ziehau goto do_sched; 595815516c77SSepherosa Ziehau 595915516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 596015516c77SSepherosa Ziehau int sched; 596115516c77SSepherosa Ziehau 596215516c77SSepherosa Ziehau txr->hn_oactive = 0; 596315516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 596415516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 596515516c77SSepherosa Ziehau if (sched) { 596615516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 596715516c77SSepherosa Ziehau &txr->hn_tx_task); 596815516c77SSepherosa Ziehau } 596915516c77SSepherosa Ziehau } else { 597015516c77SSepherosa Ziehau do_sched: 597115516c77SSepherosa Ziehau /* 597215516c77SSepherosa Ziehau * Release the oactive earlier, with the hope, that 597315516c77SSepherosa Ziehau * others could catch up. The task will clear the 597415516c77SSepherosa Ziehau * oactive again with the hn_tx_lock to avoid possible 597515516c77SSepherosa Ziehau * races. 597615516c77SSepherosa Ziehau */ 597715516c77SSepherosa Ziehau txr->hn_oactive = 0; 597815516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 597915516c77SSepherosa Ziehau } 598015516c77SSepherosa Ziehau } 598115516c77SSepherosa Ziehau 598215516c77SSepherosa Ziehau static void 598315516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused) 598415516c77SSepherosa Ziehau { 598515516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 598615516c77SSepherosa Ziehau 598715516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 598815516c77SSepherosa Ziehau hn_xmit(txr, 0); 598915516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 599015516c77SSepherosa Ziehau } 599115516c77SSepherosa Ziehau 599215516c77SSepherosa Ziehau static void 599315516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused) 599415516c77SSepherosa Ziehau { 599515516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 599615516c77SSepherosa Ziehau 599715516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 599815516c77SSepherosa Ziehau txr->hn_oactive = 0; 599915516c77SSepherosa Ziehau hn_xmit(txr, 0); 600015516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 600115516c77SSepherosa Ziehau } 600215516c77SSepherosa Ziehau 600315516c77SSepherosa Ziehau static int 600415516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan) 600515516c77SSepherosa Ziehau { 600615516c77SSepherosa Ziehau struct vmbus_chan_br cbr; 600715516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 600815516c77SSepherosa Ziehau struct hn_tx_ring *txr = NULL; 600915516c77SSepherosa Ziehau int idx, error; 601015516c77SSepherosa Ziehau 601115516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 601215516c77SSepherosa Ziehau 601315516c77SSepherosa Ziehau /* 601415516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 601515516c77SSepherosa Ziehau */ 601615516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 601715516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 601815516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 601915516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 602015516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0, 602115516c77SSepherosa Ziehau ("RX ring %d already attached", idx)); 602215516c77SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED; 60233ab0fea1SDexuan Cui rxr->hn_chan = chan; 602415516c77SSepherosa Ziehau 602515516c77SSepherosa Ziehau if (bootverbose) { 602615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n", 602715516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 602815516c77SSepherosa Ziehau } 602915516c77SSepherosa Ziehau 603015516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 603115516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 603215516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0, 603315516c77SSepherosa Ziehau ("TX ring %d already attached", idx)); 603415516c77SSepherosa Ziehau txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED; 603515516c77SSepherosa Ziehau 603615516c77SSepherosa Ziehau txr->hn_chan = chan; 603715516c77SSepherosa Ziehau if (bootverbose) { 603815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n", 603915516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 604015516c77SSepherosa Ziehau } 604115516c77SSepherosa Ziehau } 604215516c77SSepherosa Ziehau 604315516c77SSepherosa Ziehau /* Bind this channel to a proper CPU. */ 60440e11868dSSepherosa Ziehau vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx)); 604515516c77SSepherosa Ziehau 604615516c77SSepherosa Ziehau /* 604715516c77SSepherosa Ziehau * Open this channel 604815516c77SSepherosa Ziehau */ 604915516c77SSepherosa Ziehau cbr.cbr = rxr->hn_br; 605015516c77SSepherosa Ziehau cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr; 605115516c77SSepherosa Ziehau cbr.cbr_txsz = HN_TXBR_SIZE; 605215516c77SSepherosa Ziehau cbr.cbr_rxsz = HN_RXBR_SIZE; 605315516c77SSepherosa Ziehau error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr); 605415516c77SSepherosa Ziehau if (error) { 605571e8ac56SSepherosa Ziehau if (error == EISCONN) { 605671e8ac56SSepherosa Ziehau if_printf(sc->hn_ifp, "bufring is connected after " 605771e8ac56SSepherosa Ziehau "chan%u open failure\n", vmbus_chan_id(chan)); 605871e8ac56SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 605971e8ac56SSepherosa Ziehau } else { 606015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "open chan%u failed: %d\n", 606115516c77SSepherosa Ziehau vmbus_chan_id(chan), error); 606271e8ac56SSepherosa Ziehau } 606315516c77SSepherosa Ziehau } 606415516c77SSepherosa Ziehau return (error); 606515516c77SSepherosa Ziehau } 606615516c77SSepherosa Ziehau 606715516c77SSepherosa Ziehau static void 606815516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan) 606915516c77SSepherosa Ziehau { 607015516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 60712494d735SSepherosa Ziehau int idx, error; 607215516c77SSepherosa Ziehau 607315516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 607415516c77SSepherosa Ziehau 607515516c77SSepherosa Ziehau /* 607615516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 607715516c77SSepherosa Ziehau */ 607815516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 607915516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 608015516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 608115516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 608215516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED), 608315516c77SSepherosa Ziehau ("RX ring %d is not attached", idx)); 608415516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 608515516c77SSepherosa Ziehau 608615516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 608715516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[idx]; 608815516c77SSepherosa Ziehau 608915516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED), 609015516c77SSepherosa Ziehau ("TX ring %d is not attached attached", idx)); 609115516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 609215516c77SSepherosa Ziehau } 609315516c77SSepherosa Ziehau 609415516c77SSepherosa Ziehau /* 609515516c77SSepherosa Ziehau * Close this channel. 609615516c77SSepherosa Ziehau * 609715516c77SSepherosa Ziehau * NOTE: 609815516c77SSepherosa Ziehau * Channel closing does _not_ destroy the target channel. 609915516c77SSepherosa Ziehau */ 61002494d735SSepherosa Ziehau error = vmbus_chan_close_direct(chan); 61012494d735SSepherosa Ziehau if (error == EISCONN) { 6102aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u bufring is connected " 6103aa1a2adcSSepherosa Ziehau "after being closed\n", vmbus_chan_id(chan)); 61042494d735SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 61052494d735SSepherosa Ziehau } else if (error) { 6106aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u close failed: %d\n", 6107aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), error); 61082494d735SSepherosa Ziehau } 610915516c77SSepherosa Ziehau } 611015516c77SSepherosa Ziehau 611115516c77SSepherosa Ziehau static int 611215516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc) 611315516c77SSepherosa Ziehau { 611415516c77SSepherosa Ziehau struct vmbus_channel **subchans; 611515516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 611615516c77SSepherosa Ziehau int i, error = 0; 611715516c77SSepherosa Ziehau 611871e8ac56SSepherosa Ziehau KASSERT(subchan_cnt > 0, ("no sub-channels")); 611915516c77SSepherosa Ziehau 612015516c77SSepherosa Ziehau /* Attach the sub-channels. */ 612115516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 612215516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) { 612371e8ac56SSepherosa Ziehau int error1; 612471e8ac56SSepherosa Ziehau 612571e8ac56SSepherosa Ziehau error1 = hn_chan_attach(sc, subchans[i]); 612671e8ac56SSepherosa Ziehau if (error1) { 612771e8ac56SSepherosa Ziehau error = error1; 612871e8ac56SSepherosa Ziehau /* Move on; all channels will be detached later. */ 612971e8ac56SSepherosa Ziehau } 613015516c77SSepherosa Ziehau } 613115516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 613215516c77SSepherosa Ziehau 613315516c77SSepherosa Ziehau if (error) { 613415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error); 613515516c77SSepherosa Ziehau } else { 613615516c77SSepherosa Ziehau if (bootverbose) { 613715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d sub-channels attached\n", 613815516c77SSepherosa Ziehau subchan_cnt); 613915516c77SSepherosa Ziehau } 614015516c77SSepherosa Ziehau } 614115516c77SSepherosa Ziehau return (error); 614215516c77SSepherosa Ziehau } 614315516c77SSepherosa Ziehau 614415516c77SSepherosa Ziehau static void 614515516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc) 614615516c77SSepherosa Ziehau { 614715516c77SSepherosa Ziehau struct vmbus_channel **subchans; 614815516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 614915516c77SSepherosa Ziehau int i; 615015516c77SSepherosa Ziehau 615115516c77SSepherosa Ziehau if (subchan_cnt == 0) 615215516c77SSepherosa Ziehau goto back; 615315516c77SSepherosa Ziehau 615415516c77SSepherosa Ziehau /* Detach the sub-channels. */ 615515516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 615615516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) 615715516c77SSepherosa Ziehau hn_chan_detach(sc, subchans[i]); 615815516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 615915516c77SSepherosa Ziehau 616015516c77SSepherosa Ziehau back: 616115516c77SSepherosa Ziehau /* 616215516c77SSepherosa Ziehau * Detach the primary channel, _after_ all sub-channels 616315516c77SSepherosa Ziehau * are detached. 616415516c77SSepherosa Ziehau */ 616515516c77SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 616615516c77SSepherosa Ziehau 616715516c77SSepherosa Ziehau /* Wait for sub-channels to be destroyed, if any. */ 616815516c77SSepherosa Ziehau vmbus_subchan_drain(sc->hn_prichan); 616915516c77SSepherosa Ziehau 617015516c77SSepherosa Ziehau #ifdef INVARIANTS 617115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 617215516c77SSepherosa Ziehau KASSERT((sc->hn_rx_ring[i].hn_rx_flags & 617315516c77SSepherosa Ziehau HN_RX_FLAG_ATTACHED) == 0, 617415516c77SSepherosa Ziehau ("%dth RX ring is still attached", i)); 617515516c77SSepherosa Ziehau } 617615516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 617715516c77SSepherosa Ziehau KASSERT((sc->hn_tx_ring[i].hn_tx_flags & 617815516c77SSepherosa Ziehau HN_TX_FLAG_ATTACHED) == 0, 617915516c77SSepherosa Ziehau ("%dth TX ring is still attached", i)); 618015516c77SSepherosa Ziehau } 618115516c77SSepherosa Ziehau #endif 618215516c77SSepherosa Ziehau } 618315516c77SSepherosa Ziehau 618415516c77SSepherosa Ziehau static int 618515516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch) 618615516c77SSepherosa Ziehau { 618715516c77SSepherosa Ziehau struct vmbus_channel **subchans; 618815516c77SSepherosa Ziehau int nchan, rxr_cnt, error; 618915516c77SSepherosa Ziehau 619015516c77SSepherosa Ziehau nchan = *nsubch + 1; 619115516c77SSepherosa Ziehau if (nchan == 1) { 619215516c77SSepherosa Ziehau /* 619315516c77SSepherosa Ziehau * Multiple RX/TX rings are not requested. 619415516c77SSepherosa Ziehau */ 619515516c77SSepherosa Ziehau *nsubch = 0; 619615516c77SSepherosa Ziehau return (0); 619715516c77SSepherosa Ziehau } 619815516c77SSepherosa Ziehau 619915516c77SSepherosa Ziehau /* 620015516c77SSepherosa Ziehau * Query RSS capabilities, e.g. # of RX rings, and # of indirect 620115516c77SSepherosa Ziehau * table entries. 620215516c77SSepherosa Ziehau */ 620315516c77SSepherosa Ziehau error = hn_rndis_query_rsscaps(sc, &rxr_cnt); 620415516c77SSepherosa Ziehau if (error) { 620515516c77SSepherosa Ziehau /* No RSS; this is benign. */ 620615516c77SSepherosa Ziehau *nsubch = 0; 620715516c77SSepherosa Ziehau return (0); 620815516c77SSepherosa Ziehau } 620915516c77SSepherosa Ziehau if (bootverbose) { 621015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n", 621115516c77SSepherosa Ziehau rxr_cnt, nchan); 621215516c77SSepherosa Ziehau } 621315516c77SSepherosa Ziehau 621415516c77SSepherosa Ziehau if (nchan > rxr_cnt) 621515516c77SSepherosa Ziehau nchan = rxr_cnt; 621615516c77SSepherosa Ziehau if (nchan == 1) { 621715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n"); 621815516c77SSepherosa Ziehau *nsubch = 0; 621915516c77SSepherosa Ziehau return (0); 622015516c77SSepherosa Ziehau } 622115516c77SSepherosa Ziehau 622215516c77SSepherosa Ziehau /* 622315516c77SSepherosa Ziehau * Allocate sub-channels from NVS. 622415516c77SSepherosa Ziehau */ 622515516c77SSepherosa Ziehau *nsubch = nchan - 1; 622615516c77SSepherosa Ziehau error = hn_nvs_alloc_subchans(sc, nsubch); 622715516c77SSepherosa Ziehau if (error || *nsubch == 0) { 622815516c77SSepherosa Ziehau /* Failed to allocate sub-channels. */ 622915516c77SSepherosa Ziehau *nsubch = 0; 623015516c77SSepherosa Ziehau return (0); 623115516c77SSepherosa Ziehau } 623215516c77SSepherosa Ziehau 623315516c77SSepherosa Ziehau /* 623415516c77SSepherosa Ziehau * Wait for all sub-channels to become ready before moving on. 623515516c77SSepherosa Ziehau */ 623615516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch); 623715516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, *nsubch); 623815516c77SSepherosa Ziehau return (0); 623915516c77SSepherosa Ziehau } 624015516c77SSepherosa Ziehau 62412494d735SSepherosa Ziehau static bool 62422494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc) 62432494d735SSepherosa Ziehau { 62442494d735SSepherosa Ziehau int i; 62452494d735SSepherosa Ziehau 62462494d735SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_ERRORS) 62472494d735SSepherosa Ziehau return (false); 62482494d735SSepherosa Ziehau 62492494d735SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 62502494d735SSepherosa Ziehau const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 62512494d735SSepherosa Ziehau 62522494d735SSepherosa Ziehau if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) 62532494d735SSepherosa Ziehau return (false); 62542494d735SSepherosa Ziehau } 62552494d735SSepherosa Ziehau return (true); 62562494d735SSepherosa Ziehau } 62572494d735SSepherosa Ziehau 6258b3b75d9cSSepherosa Ziehau /* 6259b3b75d9cSSepherosa Ziehau * Make sure that the RX filter is zero after the successful 6260b3b75d9cSSepherosa Ziehau * RNDIS initialization. 6261b3b75d9cSSepherosa Ziehau * 6262b3b75d9cSSepherosa Ziehau * NOTE: 6263b3b75d9cSSepherosa Ziehau * Under certain conditions on certain versions of Hyper-V, 6264b3b75d9cSSepherosa Ziehau * the RNDIS rxfilter is _not_ zero on the hypervisor side 6265b3b75d9cSSepherosa Ziehau * after the successful RNDIS initialization, which breaks 6266b3b75d9cSSepherosa Ziehau * the assumption of any following code (well, it breaks the 6267b3b75d9cSSepherosa Ziehau * RNDIS API contract actually). Clear the RNDIS rxfilter 6268b3b75d9cSSepherosa Ziehau * explicitly, drain packets sneaking through, and drain the 6269b3b75d9cSSepherosa Ziehau * interrupt taskqueues scheduled due to the stealth packets. 6270b3b75d9cSSepherosa Ziehau */ 6271b3b75d9cSSepherosa Ziehau static void 6272b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan) 6273b3b75d9cSSepherosa Ziehau { 6274b3b75d9cSSepherosa Ziehau 6275b3b75d9cSSepherosa Ziehau hn_disable_rx(sc); 6276b3b75d9cSSepherosa Ziehau hn_drain_rxtx(sc, nchan); 6277b3b75d9cSSepherosa Ziehau } 6278b3b75d9cSSepherosa Ziehau 627915516c77SSepherosa Ziehau static int 628015516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu) 628115516c77SSepherosa Ziehau { 628271e8ac56SSepherosa Ziehau #define ATTACHED_NVS 0x0002 628371e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS 0x0004 628471e8ac56SSepherosa Ziehau 628515516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 6286b3b75d9cSSepherosa Ziehau int error, nsubch, nchan = 1, i, rndis_inited; 628771e8ac56SSepherosa Ziehau uint32_t old_caps, attached = 0; 628815516c77SSepherosa Ziehau 628915516c77SSepherosa Ziehau KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0, 629015516c77SSepherosa Ziehau ("synthetic parts were attached")); 629115516c77SSepherosa Ziehau 62922494d735SSepherosa Ziehau if (!hn_synth_attachable(sc)) 62932494d735SSepherosa Ziehau return (ENXIO); 62942494d735SSepherosa Ziehau 629515516c77SSepherosa Ziehau /* Save capabilities for later verification. */ 629615516c77SSepherosa Ziehau old_caps = sc->hn_caps; 629715516c77SSepherosa Ziehau sc->hn_caps = 0; 629815516c77SSepherosa Ziehau 629915516c77SSepherosa Ziehau /* Clear RSS stuffs. */ 630015516c77SSepherosa Ziehau sc->hn_rss_ind_size = 0; 630115516c77SSepherosa Ziehau sc->hn_rss_hash = 0; 6302642ec226SSepherosa Ziehau sc->hn_rss_hcap = 0; 630315516c77SSepherosa Ziehau 630415516c77SSepherosa Ziehau /* 630515516c77SSepherosa Ziehau * Attach the primary channel _before_ attaching NVS and RNDIS. 630615516c77SSepherosa Ziehau */ 630715516c77SSepherosa Ziehau error = hn_chan_attach(sc, sc->hn_prichan); 630815516c77SSepherosa Ziehau if (error) 630971e8ac56SSepherosa Ziehau goto failed; 631015516c77SSepherosa Ziehau 631115516c77SSepherosa Ziehau /* 631215516c77SSepherosa Ziehau * Attach NVS. 631315516c77SSepherosa Ziehau */ 631415516c77SSepherosa Ziehau error = hn_nvs_attach(sc, mtu); 631515516c77SSepherosa Ziehau if (error) 631671e8ac56SSepherosa Ziehau goto failed; 631771e8ac56SSepherosa Ziehau attached |= ATTACHED_NVS; 631815516c77SSepherosa Ziehau 631915516c77SSepherosa Ziehau /* 632015516c77SSepherosa Ziehau * Attach RNDIS _after_ NVS is attached. 632115516c77SSepherosa Ziehau */ 6322b3b75d9cSSepherosa Ziehau error = hn_rndis_attach(sc, mtu, &rndis_inited); 6323b3b75d9cSSepherosa Ziehau if (rndis_inited) 6324b3b75d9cSSepherosa Ziehau attached |= ATTACHED_RNDIS; 632515516c77SSepherosa Ziehau if (error) 632671e8ac56SSepherosa Ziehau goto failed; 632715516c77SSepherosa Ziehau 632815516c77SSepherosa Ziehau /* 632915516c77SSepherosa Ziehau * Make sure capabilities are not changed. 633015516c77SSepherosa Ziehau */ 633115516c77SSepherosa Ziehau if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) { 633215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n", 633315516c77SSepherosa Ziehau old_caps, sc->hn_caps); 633471e8ac56SSepherosa Ziehau error = ENXIO; 633571e8ac56SSepherosa Ziehau goto failed; 633615516c77SSepherosa Ziehau } 633715516c77SSepherosa Ziehau 633815516c77SSepherosa Ziehau /* 633915516c77SSepherosa Ziehau * Allocate sub-channels for multi-TX/RX rings. 634015516c77SSepherosa Ziehau * 634115516c77SSepherosa Ziehau * NOTE: 634215516c77SSepherosa Ziehau * The # of RX rings that can be used is equivalent to the # of 634315516c77SSepherosa Ziehau * channels to be requested. 634415516c77SSepherosa Ziehau */ 634515516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_cnt - 1; 634615516c77SSepherosa Ziehau error = hn_synth_alloc_subchans(sc, &nsubch); 634715516c77SSepherosa Ziehau if (error) 634871e8ac56SSepherosa Ziehau goto failed; 634971e8ac56SSepherosa Ziehau /* NOTE: _Full_ synthetic parts detach is required now. */ 635071e8ac56SSepherosa Ziehau sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED; 635115516c77SSepherosa Ziehau 635271e8ac56SSepherosa Ziehau /* 635371e8ac56SSepherosa Ziehau * Set the # of TX/RX rings that could be used according to 635471e8ac56SSepherosa Ziehau * the # of channels that NVS offered. 635571e8ac56SSepherosa Ziehau */ 635615516c77SSepherosa Ziehau nchan = nsubch + 1; 635771e8ac56SSepherosa Ziehau hn_set_ring_inuse(sc, nchan); 635815516c77SSepherosa Ziehau if (nchan == 1) { 635915516c77SSepherosa Ziehau /* Only the primary channel can be used; done */ 636015516c77SSepherosa Ziehau goto back; 636115516c77SSepherosa Ziehau } 636215516c77SSepherosa Ziehau 636315516c77SSepherosa Ziehau /* 636471e8ac56SSepherosa Ziehau * Attach the sub-channels. 6365afd4971bSSepherosa Ziehau * 6366afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 636715516c77SSepherosa Ziehau */ 636871e8ac56SSepherosa Ziehau error = hn_attach_subchans(sc); 636971e8ac56SSepherosa Ziehau if (error) 637071e8ac56SSepherosa Ziehau goto failed; 637115516c77SSepherosa Ziehau 637271e8ac56SSepherosa Ziehau /* 637371e8ac56SSepherosa Ziehau * Configure RSS key and indirect table _after_ all sub-channels 637471e8ac56SSepherosa Ziehau * are attached. 637571e8ac56SSepherosa Ziehau */ 637615516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) { 637715516c77SSepherosa Ziehau /* 637815516c77SSepherosa Ziehau * RSS key is not set yet; set it to the default RSS key. 637915516c77SSepherosa Ziehau */ 638015516c77SSepherosa Ziehau if (bootverbose) 638115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS key\n"); 638234d68912SSepherosa Ziehau #ifdef RSS 638334d68912SSepherosa Ziehau rss_getkey(rss->rss_key); 638434d68912SSepherosa Ziehau #else 638515516c77SSepherosa Ziehau memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key)); 638634d68912SSepherosa Ziehau #endif 638715516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 638815516c77SSepherosa Ziehau } 638915516c77SSepherosa Ziehau 639015516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) { 639115516c77SSepherosa Ziehau /* 639215516c77SSepherosa Ziehau * RSS indirect table is not set yet; set it up in round- 639315516c77SSepherosa Ziehau * robin fashion. 639415516c77SSepherosa Ziehau */ 639515516c77SSepherosa Ziehau if (bootverbose) { 639615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS indirect " 639715516c77SSepherosa Ziehau "table\n"); 639815516c77SSepherosa Ziehau } 639934d68912SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 640034d68912SSepherosa Ziehau uint32_t subidx; 640134d68912SSepherosa Ziehau 640234d68912SSepherosa Ziehau #ifdef RSS 640334d68912SSepherosa Ziehau subidx = rss_get_indirection_to_bucket(i); 640434d68912SSepherosa Ziehau #else 640534d68912SSepherosa Ziehau subidx = i; 640634d68912SSepherosa Ziehau #endif 640734d68912SSepherosa Ziehau rss->rss_ind[i] = subidx % nchan; 640834d68912SSepherosa Ziehau } 640915516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 641015516c77SSepherosa Ziehau } else { 641115516c77SSepherosa Ziehau /* 641215516c77SSepherosa Ziehau * # of usable channels may be changed, so we have to 641315516c77SSepherosa Ziehau * make sure that all entries in RSS indirect table 641415516c77SSepherosa Ziehau * are valid. 6415afd4971bSSepherosa Ziehau * 6416afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 641715516c77SSepherosa Ziehau */ 6418afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 641915516c77SSepherosa Ziehau } 642015516c77SSepherosa Ziehau 6421642ec226SSepherosa Ziehau sc->hn_rss_hash = sc->hn_rss_hcap; 6422642ec226SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) || 6423642ec226SSepherosa Ziehau (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { 6424642ec226SSepherosa Ziehau /* NOTE: Don't reconfigure RSS; will do immediately. */ 6425642ec226SSepherosa Ziehau hn_vf_rss_fixup(sc, false); 6426642ec226SSepherosa Ziehau } 642715516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 642815516c77SSepherosa Ziehau if (error) 642971e8ac56SSepherosa Ziehau goto failed; 643071e8ac56SSepherosa Ziehau back: 6431dc13fee6SSepherosa Ziehau /* 6432dc13fee6SSepherosa Ziehau * Fixup transmission aggregation setup. 6433dc13fee6SSepherosa Ziehau */ 6434dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 6435b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 643615516c77SSepherosa Ziehau return (0); 643771e8ac56SSepherosa Ziehau 643871e8ac56SSepherosa Ziehau failed: 643971e8ac56SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 6440b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 644171e8ac56SSepherosa Ziehau hn_synth_detach(sc); 644271e8ac56SSepherosa Ziehau } else { 6443b3b75d9cSSepherosa Ziehau if (attached & ATTACHED_RNDIS) { 6444b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(sc, nchan); 644571e8ac56SSepherosa Ziehau hn_rndis_detach(sc); 6446b3b75d9cSSepherosa Ziehau } 644771e8ac56SSepherosa Ziehau if (attached & ATTACHED_NVS) 644871e8ac56SSepherosa Ziehau hn_nvs_detach(sc); 644971e8ac56SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 645071e8ac56SSepherosa Ziehau /* Restore old capabilities. */ 645171e8ac56SSepherosa Ziehau sc->hn_caps = old_caps; 645271e8ac56SSepherosa Ziehau } 645371e8ac56SSepherosa Ziehau return (error); 645471e8ac56SSepherosa Ziehau 645571e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS 645671e8ac56SSepherosa Ziehau #undef ATTACHED_NVS 645715516c77SSepherosa Ziehau } 645815516c77SSepherosa Ziehau 645915516c77SSepherosa Ziehau /* 646015516c77SSepherosa Ziehau * NOTE: 646115516c77SSepherosa Ziehau * The interface must have been suspended though hn_suspend(), before 646215516c77SSepherosa Ziehau * this function get called. 646315516c77SSepherosa Ziehau */ 646415516c77SSepherosa Ziehau static void 646515516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc) 646615516c77SSepherosa Ziehau { 646715516c77SSepherosa Ziehau 646815516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 646915516c77SSepherosa Ziehau ("synthetic parts were not attached")); 647015516c77SSepherosa Ziehau 647115516c77SSepherosa Ziehau /* Detach the RNDIS first. */ 647215516c77SSepherosa Ziehau hn_rndis_detach(sc); 647315516c77SSepherosa Ziehau 647415516c77SSepherosa Ziehau /* Detach NVS. */ 647515516c77SSepherosa Ziehau hn_nvs_detach(sc); 647615516c77SSepherosa Ziehau 647715516c77SSepherosa Ziehau /* Detach all of the channels. */ 647815516c77SSepherosa Ziehau hn_detach_allchans(sc); 647915516c77SSepherosa Ziehau 648015516c77SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED; 648115516c77SSepherosa Ziehau } 648215516c77SSepherosa Ziehau 648315516c77SSepherosa Ziehau static void 648415516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt) 648515516c77SSepherosa Ziehau { 648615516c77SSepherosa Ziehau KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt, 648715516c77SSepherosa Ziehau ("invalid ring count %d", ring_cnt)); 648815516c77SSepherosa Ziehau 648915516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt > ring_cnt) 649015516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = ring_cnt; 649115516c77SSepherosa Ziehau else 649215516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 649315516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = ring_cnt; 649415516c77SSepherosa Ziehau 649534d68912SSepherosa Ziehau #ifdef RSS 649634d68912SSepherosa Ziehau if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) { 649734d68912SSepherosa Ziehau if_printf(sc->hn_ifp, "# of RX rings (%d) does not match " 649834d68912SSepherosa Ziehau "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse, 649934d68912SSepherosa Ziehau rss_getnumbuckets()); 650034d68912SSepherosa Ziehau } 650134d68912SSepherosa Ziehau #endif 650234d68912SSepherosa Ziehau 650315516c77SSepherosa Ziehau if (bootverbose) { 650415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n", 650515516c77SSepherosa Ziehau sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse); 650615516c77SSepherosa Ziehau } 650715516c77SSepherosa Ziehau } 650815516c77SSepherosa Ziehau 650915516c77SSepherosa Ziehau static void 651025641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan) 651115516c77SSepherosa Ziehau { 651215516c77SSepherosa Ziehau 651325641fc7SSepherosa Ziehau /* 651425641fc7SSepherosa Ziehau * NOTE: 651525641fc7SSepherosa Ziehau * The TX bufring will not be drained by the hypervisor, 651625641fc7SSepherosa Ziehau * if the primary channel is revoked. 651725641fc7SSepherosa Ziehau */ 651825641fc7SSepherosa Ziehau while (!vmbus_chan_rx_empty(chan) || 651925641fc7SSepherosa Ziehau (!vmbus_chan_is_revoked(sc->hn_prichan) && 652025641fc7SSepherosa Ziehau !vmbus_chan_tx_empty(chan))) 652115516c77SSepherosa Ziehau pause("waitch", 1); 652215516c77SSepherosa Ziehau vmbus_chan_intr_drain(chan); 652315516c77SSepherosa Ziehau } 652415516c77SSepherosa Ziehau 652515516c77SSepherosa Ziehau static void 6526b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc) 6527b3b75d9cSSepherosa Ziehau { 6528b3b75d9cSSepherosa Ziehau 6529b3b75d9cSSepherosa Ziehau /* 6530b3b75d9cSSepherosa Ziehau * Disable RX by clearing RX filter forcefully. 6531b3b75d9cSSepherosa Ziehau */ 6532b3b75d9cSSepherosa Ziehau sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE; 6533b3b75d9cSSepherosa Ziehau hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */ 6534b3b75d9cSSepherosa Ziehau 6535b3b75d9cSSepherosa Ziehau /* 6536b3b75d9cSSepherosa Ziehau * Give RNDIS enough time to flush all pending data packets. 6537b3b75d9cSSepherosa Ziehau */ 6538b3b75d9cSSepherosa Ziehau pause("waitrx", (200 * hz) / 1000); 6539b3b75d9cSSepherosa Ziehau } 6540b3b75d9cSSepherosa Ziehau 6541b3b75d9cSSepherosa Ziehau /* 6542b3b75d9cSSepherosa Ziehau * NOTE: 6543b3b75d9cSSepherosa Ziehau * RX/TX _must_ have been suspended/disabled, before this function 6544b3b75d9cSSepherosa Ziehau * is called. 6545b3b75d9cSSepherosa Ziehau */ 6546b3b75d9cSSepherosa Ziehau static void 6547b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan) 654815516c77SSepherosa Ziehau { 654915516c77SSepherosa Ziehau struct vmbus_channel **subch = NULL; 6550b3b75d9cSSepherosa Ziehau int nsubch; 6551b3b75d9cSSepherosa Ziehau 6552b3b75d9cSSepherosa Ziehau /* 6553b3b75d9cSSepherosa Ziehau * Drain RX/TX bufrings and interrupts. 6554b3b75d9cSSepherosa Ziehau */ 6555b3b75d9cSSepherosa Ziehau nsubch = nchan - 1; 6556b3b75d9cSSepherosa Ziehau if (nsubch > 0) 6557b3b75d9cSSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 6558b3b75d9cSSepherosa Ziehau 6559b3b75d9cSSepherosa Ziehau if (subch != NULL) { 6560b3b75d9cSSepherosa Ziehau int i; 6561b3b75d9cSSepherosa Ziehau 6562b3b75d9cSSepherosa Ziehau for (i = 0; i < nsubch; ++i) 6563b3b75d9cSSepherosa Ziehau hn_chan_drain(sc, subch[i]); 6564b3b75d9cSSepherosa Ziehau } 6565b3b75d9cSSepherosa Ziehau hn_chan_drain(sc, sc->hn_prichan); 6566b3b75d9cSSepherosa Ziehau 6567b3b75d9cSSepherosa Ziehau if (subch != NULL) 6568b3b75d9cSSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 6569b3b75d9cSSepherosa Ziehau } 6570b3b75d9cSSepherosa Ziehau 6571b3b75d9cSSepherosa Ziehau static void 6572b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc) 6573b3b75d9cSSepherosa Ziehau { 657425641fc7SSepherosa Ziehau struct hn_tx_ring *txr; 6575b3b75d9cSSepherosa Ziehau int i; 657615516c77SSepherosa Ziehau 657715516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 657815516c77SSepherosa Ziehau 657915516c77SSepherosa Ziehau /* 658015516c77SSepherosa Ziehau * Suspend TX. 658115516c77SSepherosa Ziehau */ 658215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 658325641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 658415516c77SSepherosa Ziehau 658515516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 658615516c77SSepherosa Ziehau txr->hn_suspended = 1; 658715516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 658815516c77SSepherosa Ziehau /* No one is able send more packets now. */ 658915516c77SSepherosa Ziehau 659025641fc7SSepherosa Ziehau /* 659125641fc7SSepherosa Ziehau * Wait for all pending sends to finish. 659225641fc7SSepherosa Ziehau * 659325641fc7SSepherosa Ziehau * NOTE: 659425641fc7SSepherosa Ziehau * We will _not_ receive all pending send-done, if the 659525641fc7SSepherosa Ziehau * primary channel is revoked. 659625641fc7SSepherosa Ziehau */ 659725641fc7SSepherosa Ziehau while (hn_tx_ring_pending(txr) && 659825641fc7SSepherosa Ziehau !vmbus_chan_is_revoked(sc->hn_prichan)) 659915516c77SSepherosa Ziehau pause("hnwtx", 1 /* 1 tick */); 660015516c77SSepherosa Ziehau } 660115516c77SSepherosa Ziehau 660215516c77SSepherosa Ziehau /* 6603b3b75d9cSSepherosa Ziehau * Disable RX. 660415516c77SSepherosa Ziehau */ 6605b3b75d9cSSepherosa Ziehau hn_disable_rx(sc); 660615516c77SSepherosa Ziehau 660715516c77SSepherosa Ziehau /* 6608b3b75d9cSSepherosa Ziehau * Drain RX/TX. 660915516c77SSepherosa Ziehau */ 6610b3b75d9cSSepherosa Ziehau hn_drain_rxtx(sc, sc->hn_rx_ring_inuse); 661125641fc7SSepherosa Ziehau 661225641fc7SSepherosa Ziehau /* 661325641fc7SSepherosa Ziehau * Drain any pending TX tasks. 661425641fc7SSepherosa Ziehau * 661525641fc7SSepherosa Ziehau * NOTE: 6616b3b75d9cSSepherosa Ziehau * The above hn_drain_rxtx() can dispatch TX tasks, so the TX 6617b3b75d9cSSepherosa Ziehau * tasks will have to be drained _after_ the above hn_drain_rxtx(). 661825641fc7SSepherosa Ziehau */ 661925641fc7SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 662025641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 662125641fc7SSepherosa Ziehau 662225641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task); 662325641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task); 662425641fc7SSepherosa Ziehau } 662515516c77SSepherosa Ziehau } 662615516c77SSepherosa Ziehau 662715516c77SSepherosa Ziehau static void 662815516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused) 662915516c77SSepherosa Ziehau { 663015516c77SSepherosa Ziehau 663115516c77SSepherosa Ziehau ((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL; 663215516c77SSepherosa Ziehau } 663315516c77SSepherosa Ziehau 663415516c77SSepherosa Ziehau static void 663515516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc) 663615516c77SSepherosa Ziehau { 663715516c77SSepherosa Ziehau struct task task; 663815516c77SSepherosa Ziehau 663915516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 664015516c77SSepherosa Ziehau 664115516c77SSepherosa Ziehau /* 664215516c77SSepherosa Ziehau * Make sure that hn_mgmt_taskq0 can nolonger be accessed 664315516c77SSepherosa Ziehau * through hn_mgmt_taskq. 664415516c77SSepherosa Ziehau */ 664515516c77SSepherosa Ziehau TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc); 664615516c77SSepherosa Ziehau vmbus_chan_run_task(sc->hn_prichan, &task); 664715516c77SSepherosa Ziehau 664815516c77SSepherosa Ziehau /* 664915516c77SSepherosa Ziehau * Make sure that all pending management tasks are completed. 665015516c77SSepherosa Ziehau */ 665115516c77SSepherosa Ziehau taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init); 665215516c77SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status); 665315516c77SSepherosa Ziehau taskqueue_drain_all(sc->hn_mgmt_taskq0); 665415516c77SSepherosa Ziehau } 665515516c77SSepherosa Ziehau 665615516c77SSepherosa Ziehau static void 665715516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc) 665815516c77SSepherosa Ziehau { 665915516c77SSepherosa Ziehau 666087f8129dSSepherosa Ziehau /* Disable polling. */ 666187f8129dSSepherosa Ziehau hn_polling(sc, 0); 666287f8129dSSepherosa Ziehau 66639c6cae24SSepherosa Ziehau /* 66649c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, the synthetic 66659c6cae24SSepherosa Ziehau * device is receiving packets, so the data path of the 66669c6cae24SSepherosa Ziehau * synthetic device must be suspended. 66679c6cae24SSepherosa Ziehau */ 66685bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 6669962f0357SSepherosa Ziehau (sc->hn_flags & HN_FLAG_RXVF)) 667015516c77SSepherosa Ziehau hn_suspend_data(sc); 667115516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 667215516c77SSepherosa Ziehau } 667315516c77SSepherosa Ziehau 667415516c77SSepherosa Ziehau static void 667515516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt) 667615516c77SSepherosa Ziehau { 667715516c77SSepherosa Ziehau int i; 667815516c77SSepherosa Ziehau 667915516c77SSepherosa Ziehau KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt, 668015516c77SSepherosa Ziehau ("invalid TX ring count %d", tx_ring_cnt)); 668115516c77SSepherosa Ziehau 668215516c77SSepherosa Ziehau for (i = 0; i < tx_ring_cnt; ++i) { 668315516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 668415516c77SSepherosa Ziehau 668515516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 668615516c77SSepherosa Ziehau txr->hn_suspended = 0; 668715516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 668815516c77SSepherosa Ziehau } 668915516c77SSepherosa Ziehau } 669015516c77SSepherosa Ziehau 669115516c77SSepherosa Ziehau static void 669215516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc) 669315516c77SSepherosa Ziehau { 669415516c77SSepherosa Ziehau int i; 669515516c77SSepherosa Ziehau 669615516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 669715516c77SSepherosa Ziehau 669815516c77SSepherosa Ziehau /* 669915516c77SSepherosa Ziehau * Re-enable RX. 670015516c77SSepherosa Ziehau */ 6701c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 670215516c77SSepherosa Ziehau 670315516c77SSepherosa Ziehau /* 670415516c77SSepherosa Ziehau * Make sure to clear suspend status on "all" TX rings, 670515516c77SSepherosa Ziehau * since hn_tx_ring_inuse can be changed after 670615516c77SSepherosa Ziehau * hn_suspend_data(). 670715516c77SSepherosa Ziehau */ 670815516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_cnt); 670915516c77SSepherosa Ziehau 671023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 671123bf9e15SSepherosa Ziehau if (!hn_use_if_start) 671223bf9e15SSepherosa Ziehau #endif 671323bf9e15SSepherosa Ziehau { 671415516c77SSepherosa Ziehau /* 671515516c77SSepherosa Ziehau * Flush unused drbrs, since hn_tx_ring_inuse may be 671615516c77SSepherosa Ziehau * reduced. 671715516c77SSepherosa Ziehau */ 671815516c77SSepherosa Ziehau for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i) 671915516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 672015516c77SSepherosa Ziehau } 672115516c77SSepherosa Ziehau 672215516c77SSepherosa Ziehau /* 672315516c77SSepherosa Ziehau * Kick start TX. 672415516c77SSepherosa Ziehau */ 672515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 672615516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 672715516c77SSepherosa Ziehau 672815516c77SSepherosa Ziehau /* 672915516c77SSepherosa Ziehau * Use txeof task, so that any pending oactive can be 673015516c77SSepherosa Ziehau * cleared properly. 673115516c77SSepherosa Ziehau */ 673215516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 673315516c77SSepherosa Ziehau } 673415516c77SSepherosa Ziehau } 673515516c77SSepherosa Ziehau 673615516c77SSepherosa Ziehau static void 673715516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc) 673815516c77SSepherosa Ziehau { 673915516c77SSepherosa Ziehau 674015516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 674115516c77SSepherosa Ziehau 674215516c77SSepherosa Ziehau /* 674315516c77SSepherosa Ziehau * Kick off network change detection, if it was pending. 674415516c77SSepherosa Ziehau * If no network change was pending, start link status 674515516c77SSepherosa Ziehau * checks, which is more lightweight than network change 674615516c77SSepherosa Ziehau * detection. 674715516c77SSepherosa Ziehau */ 674815516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 674915516c77SSepherosa Ziehau hn_change_network(sc); 675015516c77SSepherosa Ziehau else 675115516c77SSepherosa Ziehau hn_update_link_status(sc); 675215516c77SSepherosa Ziehau } 675315516c77SSepherosa Ziehau 675415516c77SSepherosa Ziehau static void 675515516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc) 675615516c77SSepherosa Ziehau { 675715516c77SSepherosa Ziehau 67589c6cae24SSepherosa Ziehau /* 67599c6cae24SSepherosa Ziehau * If the non-transparent mode VF is activated, the synthetic 67609c6cae24SSepherosa Ziehau * device have to receive packets, so the data path of the 67619c6cae24SSepherosa Ziehau * synthetic device must be resumed. 67629c6cae24SSepherosa Ziehau */ 67635bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 6764962f0357SSepherosa Ziehau (sc->hn_flags & HN_FLAG_RXVF)) 676515516c77SSepherosa Ziehau hn_resume_data(sc); 67665bdfd3fdSDexuan Cui 67675bdfd3fdSDexuan Cui /* 67689c6cae24SSepherosa Ziehau * Don't resume link status change if VF is attached/activated. 67699c6cae24SSepherosa Ziehau * - In the non-transparent VF mode, the synthetic device marks 67709c6cae24SSepherosa Ziehau * link down until the VF is deactivated; i.e. VF is down. 67719c6cae24SSepherosa Ziehau * - In transparent VF mode, VF's media status is used until 67729c6cae24SSepherosa Ziehau * the VF is detached. 67735bdfd3fdSDexuan Cui */ 67749c6cae24SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXVF) == 0 && 67759c6cae24SSepherosa Ziehau !(hn_xpnt_vf && sc->hn_vf_ifp != NULL)) 677615516c77SSepherosa Ziehau hn_resume_mgmt(sc); 677787f8129dSSepherosa Ziehau 677887f8129dSSepherosa Ziehau /* 677987f8129dSSepherosa Ziehau * Re-enable polling if this interface is running and 678087f8129dSSepherosa Ziehau * the polling is requested. 678187f8129dSSepherosa Ziehau */ 678287f8129dSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0) 678387f8129dSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 678415516c77SSepherosa Ziehau } 678515516c77SSepherosa Ziehau 678615516c77SSepherosa Ziehau static void 678715516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen) 678815516c77SSepherosa Ziehau { 678915516c77SSepherosa Ziehau const struct rndis_status_msg *msg; 679015516c77SSepherosa Ziehau int ofs; 679115516c77SSepherosa Ziehau 679215516c77SSepherosa Ziehau if (dlen < sizeof(*msg)) { 679315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid RNDIS status\n"); 679415516c77SSepherosa Ziehau return; 679515516c77SSepherosa Ziehau } 679615516c77SSepherosa Ziehau msg = data; 679715516c77SSepherosa Ziehau 679815516c77SSepherosa Ziehau switch (msg->rm_status) { 679915516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_CONNECT: 680015516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_DISCONNECT: 680115516c77SSepherosa Ziehau hn_update_link_status(sc); 680215516c77SSepherosa Ziehau break; 680315516c77SSepherosa Ziehau 680415516c77SSepherosa Ziehau case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: 680540905afaSSepherosa Ziehau case RNDIS_STATUS_LINK_SPEED_CHANGE: 680615516c77SSepherosa Ziehau /* Not really useful; ignore. */ 680715516c77SSepherosa Ziehau break; 680815516c77SSepherosa Ziehau 680915516c77SSepherosa Ziehau case RNDIS_STATUS_NETWORK_CHANGE: 681015516c77SSepherosa Ziehau ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset); 681115516c77SSepherosa Ziehau if (dlen < ofs + msg->rm_stbuflen || 681215516c77SSepherosa Ziehau msg->rm_stbuflen < sizeof(uint32_t)) { 681315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed\n"); 681415516c77SSepherosa Ziehau } else { 681515516c77SSepherosa Ziehau uint32_t change; 681615516c77SSepherosa Ziehau 681715516c77SSepherosa Ziehau memcpy(&change, ((const uint8_t *)msg) + ofs, 681815516c77SSepherosa Ziehau sizeof(change)); 681915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed, change %u\n", 682015516c77SSepherosa Ziehau change); 682115516c77SSepherosa Ziehau } 682215516c77SSepherosa Ziehau hn_change_network(sc); 682315516c77SSepherosa Ziehau break; 682415516c77SSepherosa Ziehau 682515516c77SSepherosa Ziehau default: 682615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n", 682715516c77SSepherosa Ziehau msg->rm_status); 682815516c77SSepherosa Ziehau break; 682915516c77SSepherosa Ziehau } 683015516c77SSepherosa Ziehau } 683115516c77SSepherosa Ziehau 683215516c77SSepherosa Ziehau static int 683315516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info) 683415516c77SSepherosa Ziehau { 683515516c77SSepherosa Ziehau const struct rndis_pktinfo *pi = info_data; 683615516c77SSepherosa Ziehau uint32_t mask = 0; 683715516c77SSepherosa Ziehau 683815516c77SSepherosa Ziehau while (info_dlen != 0) { 683915516c77SSepherosa Ziehau const void *data; 684015516c77SSepherosa Ziehau uint32_t dlen; 684115516c77SSepherosa Ziehau 684215516c77SSepherosa Ziehau if (__predict_false(info_dlen < sizeof(*pi))) 684315516c77SSepherosa Ziehau return (EINVAL); 684415516c77SSepherosa Ziehau if (__predict_false(info_dlen < pi->rm_size)) 684515516c77SSepherosa Ziehau return (EINVAL); 684615516c77SSepherosa Ziehau info_dlen -= pi->rm_size; 684715516c77SSepherosa Ziehau 684815516c77SSepherosa Ziehau if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK)) 684915516c77SSepherosa Ziehau return (EINVAL); 685015516c77SSepherosa Ziehau if (__predict_false(pi->rm_size < pi->rm_pktinfooffset)) 685115516c77SSepherosa Ziehau return (EINVAL); 685215516c77SSepherosa Ziehau dlen = pi->rm_size - pi->rm_pktinfooffset; 685315516c77SSepherosa Ziehau data = pi->rm_data; 685415516c77SSepherosa Ziehau 685515516c77SSepherosa Ziehau switch (pi->rm_type) { 685615516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_VLAN: 685715516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE)) 685815516c77SSepherosa Ziehau return (EINVAL); 685915516c77SSepherosa Ziehau info->vlan_info = *((const uint32_t *)data); 686015516c77SSepherosa Ziehau mask |= HN_RXINFO_VLAN; 686115516c77SSepherosa Ziehau break; 686215516c77SSepherosa Ziehau 686315516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_CSUM: 686415516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE)) 686515516c77SSepherosa Ziehau return (EINVAL); 686615516c77SSepherosa Ziehau info->csum_info = *((const uint32_t *)data); 686715516c77SSepherosa Ziehau mask |= HN_RXINFO_CSUM; 686815516c77SSepherosa Ziehau break; 686915516c77SSepherosa Ziehau 687015516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHVAL: 687115516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE)) 687215516c77SSepherosa Ziehau return (EINVAL); 687315516c77SSepherosa Ziehau info->hash_value = *((const uint32_t *)data); 687415516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHVAL; 687515516c77SSepherosa Ziehau break; 687615516c77SSepherosa Ziehau 687715516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHINF: 687815516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE)) 687915516c77SSepherosa Ziehau return (EINVAL); 688015516c77SSepherosa Ziehau info->hash_info = *((const uint32_t *)data); 688115516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHINF; 688215516c77SSepherosa Ziehau break; 688315516c77SSepherosa Ziehau 688415516c77SSepherosa Ziehau default: 688515516c77SSepherosa Ziehau goto next; 688615516c77SSepherosa Ziehau } 688715516c77SSepherosa Ziehau 688815516c77SSepherosa Ziehau if (mask == HN_RXINFO_ALL) { 688915516c77SSepherosa Ziehau /* All found; done */ 689015516c77SSepherosa Ziehau break; 689115516c77SSepherosa Ziehau } 689215516c77SSepherosa Ziehau next: 689315516c77SSepherosa Ziehau pi = (const struct rndis_pktinfo *) 689415516c77SSepherosa Ziehau ((const uint8_t *)pi + pi->rm_size); 689515516c77SSepherosa Ziehau } 689615516c77SSepherosa Ziehau 689715516c77SSepherosa Ziehau /* 689815516c77SSepherosa Ziehau * Final fixup. 689915516c77SSepherosa Ziehau * - If there is no hash value, invalidate the hash info. 690015516c77SSepherosa Ziehau */ 690115516c77SSepherosa Ziehau if ((mask & HN_RXINFO_HASHVAL) == 0) 690215516c77SSepherosa Ziehau info->hash_info = HN_NDIS_HASH_INFO_INVALID; 690315516c77SSepherosa Ziehau return (0); 690415516c77SSepherosa Ziehau } 690515516c77SSepherosa Ziehau 690615516c77SSepherosa Ziehau static __inline bool 690715516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len) 690815516c77SSepherosa Ziehau { 690915516c77SSepherosa Ziehau 691015516c77SSepherosa Ziehau if (off < check_off) { 691115516c77SSepherosa Ziehau if (__predict_true(off + len <= check_off)) 691215516c77SSepherosa Ziehau return (false); 691315516c77SSepherosa Ziehau } else if (off > check_off) { 691415516c77SSepherosa Ziehau if (__predict_true(check_off + check_len <= off)) 691515516c77SSepherosa Ziehau return (false); 691615516c77SSepherosa Ziehau } 691715516c77SSepherosa Ziehau return (true); 691815516c77SSepherosa Ziehau } 691915516c77SSepherosa Ziehau 692015516c77SSepherosa Ziehau static void 692115516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen) 692215516c77SSepherosa Ziehau { 692315516c77SSepherosa Ziehau const struct rndis_packet_msg *pkt; 692415516c77SSepherosa Ziehau struct hn_rxinfo info; 692515516c77SSepherosa Ziehau int data_off, pktinfo_off, data_len, pktinfo_len; 692615516c77SSepherosa Ziehau 692715516c77SSepherosa Ziehau /* 692815516c77SSepherosa Ziehau * Check length. 692915516c77SSepherosa Ziehau */ 693015516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*pkt))) { 693115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n"); 693215516c77SSepherosa Ziehau return; 693315516c77SSepherosa Ziehau } 693415516c77SSepherosa Ziehau pkt = data; 693515516c77SSepherosa Ziehau 693615516c77SSepherosa Ziehau if (__predict_false(dlen < pkt->rm_len)) { 693715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, " 693815516c77SSepherosa Ziehau "dlen %d, msglen %u\n", dlen, pkt->rm_len); 693915516c77SSepherosa Ziehau return; 694015516c77SSepherosa Ziehau } 694115516c77SSepherosa Ziehau if (__predict_false(pkt->rm_len < 694215516c77SSepherosa Ziehau pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) { 694315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, " 694415516c77SSepherosa Ziehau "msglen %u, data %u, oob %u, pktinfo %u\n", 694515516c77SSepherosa Ziehau pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen, 694615516c77SSepherosa Ziehau pkt->rm_pktinfolen); 694715516c77SSepherosa Ziehau return; 694815516c77SSepherosa Ziehau } 694915516c77SSepherosa Ziehau if (__predict_false(pkt->rm_datalen == 0)) { 695015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n"); 695115516c77SSepherosa Ziehau return; 695215516c77SSepherosa Ziehau } 695315516c77SSepherosa Ziehau 695415516c77SSepherosa Ziehau /* 695515516c77SSepherosa Ziehau * Check offests. 695615516c77SSepherosa Ziehau */ 695715516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs) \ 695815516c77SSepherosa Ziehau ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \ 695915516c77SSepherosa Ziehau ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK)) 696015516c77SSepherosa Ziehau 696115516c77SSepherosa Ziehau /* XXX Hyper-V does not meet data offset alignment requirement */ 696215516c77SSepherosa Ziehau if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) { 696315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 696415516c77SSepherosa Ziehau "data offset %u\n", pkt->rm_dataoffset); 696515516c77SSepherosa Ziehau return; 696615516c77SSepherosa Ziehau } 696715516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdataoffset > 0 && 696815516c77SSepherosa Ziehau IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) { 696915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 697015516c77SSepherosa Ziehau "oob offset %u\n", pkt->rm_oobdataoffset); 697115516c77SSepherosa Ziehau return; 697215516c77SSepherosa Ziehau } 697315516c77SSepherosa Ziehau if (__predict_true(pkt->rm_pktinfooffset > 0) && 697415516c77SSepherosa Ziehau __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) { 697515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 697615516c77SSepherosa Ziehau "pktinfo offset %u\n", pkt->rm_pktinfooffset); 697715516c77SSepherosa Ziehau return; 697815516c77SSepherosa Ziehau } 697915516c77SSepherosa Ziehau 698015516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID 698115516c77SSepherosa Ziehau 698215516c77SSepherosa Ziehau data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset); 698315516c77SSepherosa Ziehau data_len = pkt->rm_datalen; 698415516c77SSepherosa Ziehau pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset); 698515516c77SSepherosa Ziehau pktinfo_len = pkt->rm_pktinfolen; 698615516c77SSepherosa Ziehau 698715516c77SSepherosa Ziehau /* 698815516c77SSepherosa Ziehau * Check OOB coverage. 698915516c77SSepherosa Ziehau */ 699015516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdatalen != 0)) { 699115516c77SSepherosa Ziehau int oob_off, oob_len; 699215516c77SSepherosa Ziehau 699315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "got oobdata\n"); 699415516c77SSepherosa Ziehau oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset); 699515516c77SSepherosa Ziehau oob_len = pkt->rm_oobdatalen; 699615516c77SSepherosa Ziehau 699715516c77SSepherosa Ziehau if (__predict_false(oob_off + oob_len > pkt->rm_len)) { 699815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 699915516c77SSepherosa Ziehau "oob overflow, msglen %u, oob abs %d len %d\n", 700015516c77SSepherosa Ziehau pkt->rm_len, oob_off, oob_len); 700115516c77SSepherosa Ziehau return; 700215516c77SSepherosa Ziehau } 700315516c77SSepherosa Ziehau 700415516c77SSepherosa Ziehau /* 700515516c77SSepherosa Ziehau * Check against data. 700615516c77SSepherosa Ziehau */ 700715516c77SSepherosa Ziehau if (hn_rndis_check_overlap(oob_off, oob_len, 700815516c77SSepherosa Ziehau data_off, data_len)) { 700915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 701015516c77SSepherosa Ziehau "oob overlaps data, oob abs %d len %d, " 701115516c77SSepherosa Ziehau "data abs %d len %d\n", 701215516c77SSepherosa Ziehau oob_off, oob_len, data_off, data_len); 701315516c77SSepherosa Ziehau return; 701415516c77SSepherosa Ziehau } 701515516c77SSepherosa Ziehau 701615516c77SSepherosa Ziehau /* 701715516c77SSepherosa Ziehau * Check against pktinfo. 701815516c77SSepherosa Ziehau */ 701915516c77SSepherosa Ziehau if (pktinfo_len != 0 && 702015516c77SSepherosa Ziehau hn_rndis_check_overlap(oob_off, oob_len, 702115516c77SSepherosa Ziehau pktinfo_off, pktinfo_len)) { 702215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 702315516c77SSepherosa Ziehau "oob overlaps pktinfo, oob abs %d len %d, " 702415516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 702515516c77SSepherosa Ziehau oob_off, oob_len, pktinfo_off, pktinfo_len); 702615516c77SSepherosa Ziehau return; 702715516c77SSepherosa Ziehau } 702815516c77SSepherosa Ziehau } 702915516c77SSepherosa Ziehau 703015516c77SSepherosa Ziehau /* 703115516c77SSepherosa Ziehau * Check per-packet-info coverage and find useful per-packet-info. 703215516c77SSepherosa Ziehau */ 703315516c77SSepherosa Ziehau info.vlan_info = HN_NDIS_VLAN_INFO_INVALID; 703415516c77SSepherosa Ziehau info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID; 703515516c77SSepherosa Ziehau info.hash_info = HN_NDIS_HASH_INFO_INVALID; 703615516c77SSepherosa Ziehau if (__predict_true(pktinfo_len != 0)) { 703715516c77SSepherosa Ziehau bool overlap; 703815516c77SSepherosa Ziehau int error; 703915516c77SSepherosa Ziehau 704015516c77SSepherosa Ziehau if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) { 704115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 704215516c77SSepherosa Ziehau "pktinfo overflow, msglen %u, " 704315516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 704415516c77SSepherosa Ziehau pkt->rm_len, pktinfo_off, pktinfo_len); 704515516c77SSepherosa Ziehau return; 704615516c77SSepherosa Ziehau } 704715516c77SSepherosa Ziehau 704815516c77SSepherosa Ziehau /* 704915516c77SSepherosa Ziehau * Check packet info coverage. 705015516c77SSepherosa Ziehau */ 705115516c77SSepherosa Ziehau overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len, 705215516c77SSepherosa Ziehau data_off, data_len); 705315516c77SSepherosa Ziehau if (__predict_false(overlap)) { 705415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 705515516c77SSepherosa Ziehau "pktinfo overlap data, pktinfo abs %d len %d, " 705615516c77SSepherosa Ziehau "data abs %d len %d\n", 705715516c77SSepherosa Ziehau pktinfo_off, pktinfo_len, data_off, data_len); 705815516c77SSepherosa Ziehau return; 705915516c77SSepherosa Ziehau } 706015516c77SSepherosa Ziehau 706115516c77SSepherosa Ziehau /* 706215516c77SSepherosa Ziehau * Find useful per-packet-info. 706315516c77SSepherosa Ziehau */ 706415516c77SSepherosa Ziehau error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off, 706515516c77SSepherosa Ziehau pktinfo_len, &info); 706615516c77SSepherosa Ziehau if (__predict_false(error)) { 706715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg " 706815516c77SSepherosa Ziehau "pktinfo\n"); 706915516c77SSepherosa Ziehau return; 707015516c77SSepherosa Ziehau } 707115516c77SSepherosa Ziehau } 707215516c77SSepherosa Ziehau 707315516c77SSepherosa Ziehau if (__predict_false(data_off + data_len > pkt->rm_len)) { 707415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 707515516c77SSepherosa Ziehau "data overflow, msglen %u, data abs %d len %d\n", 707615516c77SSepherosa Ziehau pkt->rm_len, data_off, data_len); 707715516c77SSepherosa Ziehau return; 707815516c77SSepherosa Ziehau } 707915516c77SSepherosa Ziehau hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info); 708015516c77SSepherosa Ziehau } 708115516c77SSepherosa Ziehau 708215516c77SSepherosa Ziehau static __inline void 708315516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen) 708415516c77SSepherosa Ziehau { 708515516c77SSepherosa Ziehau const struct rndis_msghdr *hdr; 708615516c77SSepherosa Ziehau 708715516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*hdr))) { 708815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS msg\n"); 708915516c77SSepherosa Ziehau return; 709015516c77SSepherosa Ziehau } 709115516c77SSepherosa Ziehau hdr = data; 709215516c77SSepherosa Ziehau 709315516c77SSepherosa Ziehau if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) { 709415516c77SSepherosa Ziehau /* Hot data path. */ 709515516c77SSepherosa Ziehau hn_rndis_rx_data(rxr, data, dlen); 709615516c77SSepherosa Ziehau /* Done! */ 709715516c77SSepherosa Ziehau return; 709815516c77SSepherosa Ziehau } 709915516c77SSepherosa Ziehau 710015516c77SSepherosa Ziehau if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG) 710115516c77SSepherosa Ziehau hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen); 710215516c77SSepherosa Ziehau else 710315516c77SSepherosa Ziehau hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen); 710415516c77SSepherosa Ziehau } 710515516c77SSepherosa Ziehau 710615516c77SSepherosa Ziehau static void 710715516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) 710815516c77SSepherosa Ziehau { 710915516c77SSepherosa Ziehau const struct hn_nvs_hdr *hdr; 711015516c77SSepherosa Ziehau 711115516c77SSepherosa Ziehau if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) { 711215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid nvs notify\n"); 711315516c77SSepherosa Ziehau return; 711415516c77SSepherosa Ziehau } 711515516c77SSepherosa Ziehau hdr = VMBUS_CHANPKT_CONST_DATA(pkt); 711615516c77SSepherosa Ziehau 711715516c77SSepherosa Ziehau if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) { 711815516c77SSepherosa Ziehau /* Useless; ignore */ 711915516c77SSepherosa Ziehau return; 712015516c77SSepherosa Ziehau } 712115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type); 712215516c77SSepherosa Ziehau } 712315516c77SSepherosa Ziehau 712415516c77SSepherosa Ziehau static void 712515516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan, 712615516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkt) 712715516c77SSepherosa Ziehau { 712815516c77SSepherosa Ziehau struct hn_nvs_sendctx *sndc; 712915516c77SSepherosa Ziehau 713015516c77SSepherosa Ziehau sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid; 713115516c77SSepherosa Ziehau sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt), 713215516c77SSepherosa Ziehau VMBUS_CHANPKT_DATALEN(pkt)); 713315516c77SSepherosa Ziehau /* 713415516c77SSepherosa Ziehau * NOTE: 713515516c77SSepherosa Ziehau * 'sndc' CAN NOT be accessed anymore, since it can be freed by 713615516c77SSepherosa Ziehau * its callback. 713715516c77SSepherosa Ziehau */ 713815516c77SSepherosa Ziehau } 713915516c77SSepherosa Ziehau 714015516c77SSepherosa Ziehau static void 714115516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 714215516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkthdr) 714315516c77SSepherosa Ziehau { 714415516c77SSepherosa Ziehau const struct vmbus_chanpkt_rxbuf *pkt; 714515516c77SSepherosa Ziehau const struct hn_nvs_hdr *nvs_hdr; 714615516c77SSepherosa Ziehau int count, i, hlen; 714715516c77SSepherosa Ziehau 714815516c77SSepherosa Ziehau if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) { 714915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n"); 715015516c77SSepherosa Ziehau return; 715115516c77SSepherosa Ziehau } 715215516c77SSepherosa Ziehau nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr); 715315516c77SSepherosa Ziehau 715415516c77SSepherosa Ziehau /* Make sure that this is a RNDIS message. */ 715515516c77SSepherosa Ziehau if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) { 715615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n", 715715516c77SSepherosa Ziehau nvs_hdr->nvs_type); 715815516c77SSepherosa Ziehau return; 715915516c77SSepherosa Ziehau } 716015516c77SSepherosa Ziehau 716115516c77SSepherosa Ziehau hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen); 716215516c77SSepherosa Ziehau if (__predict_false(hlen < sizeof(*pkt))) { 716315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n"); 716415516c77SSepherosa Ziehau return; 716515516c77SSepherosa Ziehau } 716615516c77SSepherosa Ziehau pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr; 716715516c77SSepherosa Ziehau 716815516c77SSepherosa Ziehau if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) { 716915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n", 717015516c77SSepherosa Ziehau pkt->cp_rxbuf_id); 717115516c77SSepherosa Ziehau return; 717215516c77SSepherosa Ziehau } 717315516c77SSepherosa Ziehau 717415516c77SSepherosa Ziehau count = pkt->cp_rxbuf_cnt; 717515516c77SSepherosa Ziehau if (__predict_false(hlen < 717615516c77SSepherosa Ziehau __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) { 717715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count); 717815516c77SSepherosa Ziehau return; 717915516c77SSepherosa Ziehau } 718015516c77SSepherosa Ziehau 718115516c77SSepherosa Ziehau /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 718215516c77SSepherosa Ziehau for (i = 0; i < count; ++i) { 718315516c77SSepherosa Ziehau int ofs, len; 718415516c77SSepherosa Ziehau 718515516c77SSepherosa Ziehau ofs = pkt->cp_rxbuf[i].rb_ofs; 718615516c77SSepherosa Ziehau len = pkt->cp_rxbuf[i].rb_len; 718715516c77SSepherosa Ziehau if (__predict_false(ofs + len > HN_RXBUF_SIZE)) { 718815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, " 718915516c77SSepherosa Ziehau "ofs %d, len %d\n", i, ofs, len); 719015516c77SSepherosa Ziehau continue; 719115516c77SSepherosa Ziehau } 719215516c77SSepherosa Ziehau hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len); 719315516c77SSepherosa Ziehau } 719415516c77SSepherosa Ziehau 719515516c77SSepherosa Ziehau /* 719615516c77SSepherosa Ziehau * Ack the consumed RXBUF associated w/ this channel packet, 719715516c77SSepherosa Ziehau * so that this RXBUF can be recycled by the hypervisor. 719815516c77SSepherosa Ziehau */ 719915516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid); 720015516c77SSepherosa Ziehau } 720115516c77SSepherosa Ziehau 720215516c77SSepherosa Ziehau static void 720315516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 720415516c77SSepherosa Ziehau uint64_t tid) 720515516c77SSepherosa Ziehau { 720615516c77SSepherosa Ziehau struct hn_nvs_rndis_ack ack; 720715516c77SSepherosa Ziehau int retries, error; 720815516c77SSepherosa Ziehau 720915516c77SSepherosa Ziehau ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK; 721015516c77SSepherosa Ziehau ack.nvs_status = HN_NVS_STATUS_OK; 721115516c77SSepherosa Ziehau 721215516c77SSepherosa Ziehau retries = 0; 721315516c77SSepherosa Ziehau again: 721415516c77SSepherosa Ziehau error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 721515516c77SSepherosa Ziehau VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid); 721615516c77SSepherosa Ziehau if (__predict_false(error == EAGAIN)) { 721715516c77SSepherosa Ziehau /* 721815516c77SSepherosa Ziehau * NOTE: 721915516c77SSepherosa Ziehau * This should _not_ happen in real world, since the 722015516c77SSepherosa Ziehau * consumption of the TX bufring from the TX path is 722115516c77SSepherosa Ziehau * controlled. 722215516c77SSepherosa Ziehau */ 722315516c77SSepherosa Ziehau if (rxr->hn_ack_failed == 0) 722415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack retry\n"); 722515516c77SSepherosa Ziehau rxr->hn_ack_failed++; 722615516c77SSepherosa Ziehau retries++; 722715516c77SSepherosa Ziehau if (retries < 10) { 722815516c77SSepherosa Ziehau DELAY(100); 722915516c77SSepherosa Ziehau goto again; 723015516c77SSepherosa Ziehau } 723115516c77SSepherosa Ziehau /* RXBUF leaks! */ 723215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack failed\n"); 723315516c77SSepherosa Ziehau } 723415516c77SSepherosa Ziehau } 723515516c77SSepherosa Ziehau 723615516c77SSepherosa Ziehau static void 723715516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr) 723815516c77SSepherosa Ziehau { 723915516c77SSepherosa Ziehau struct hn_rx_ring *rxr = xrxr; 724015516c77SSepherosa Ziehau struct hn_softc *sc = rxr->hn_ifp->if_softc; 724115516c77SSepherosa Ziehau 724215516c77SSepherosa Ziehau for (;;) { 724315516c77SSepherosa Ziehau struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf; 724415516c77SSepherosa Ziehau int error, pktlen; 724515516c77SSepherosa Ziehau 724615516c77SSepherosa Ziehau pktlen = rxr->hn_pktbuf_len; 724715516c77SSepherosa Ziehau error = vmbus_chan_recv_pkt(chan, pkt, &pktlen); 724815516c77SSepherosa Ziehau if (__predict_false(error == ENOBUFS)) { 724915516c77SSepherosa Ziehau void *nbuf; 725015516c77SSepherosa Ziehau int nlen; 725115516c77SSepherosa Ziehau 725215516c77SSepherosa Ziehau /* 725315516c77SSepherosa Ziehau * Expand channel packet buffer. 725415516c77SSepherosa Ziehau * 725515516c77SSepherosa Ziehau * XXX 725615516c77SSepherosa Ziehau * Use M_WAITOK here, since allocation failure 725715516c77SSepherosa Ziehau * is fatal. 725815516c77SSepherosa Ziehau */ 725915516c77SSepherosa Ziehau nlen = rxr->hn_pktbuf_len * 2; 726015516c77SSepherosa Ziehau while (nlen < pktlen) 726115516c77SSepherosa Ziehau nlen *= 2; 726215516c77SSepherosa Ziehau nbuf = malloc(nlen, M_DEVBUF, M_WAITOK); 726315516c77SSepherosa Ziehau 726415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n", 726515516c77SSepherosa Ziehau rxr->hn_pktbuf_len, nlen); 726615516c77SSepherosa Ziehau 726715516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 726815516c77SSepherosa Ziehau rxr->hn_pktbuf = nbuf; 726915516c77SSepherosa Ziehau rxr->hn_pktbuf_len = nlen; 727015516c77SSepherosa Ziehau /* Retry! */ 727115516c77SSepherosa Ziehau continue; 727215516c77SSepherosa Ziehau } else if (__predict_false(error == EAGAIN)) { 727315516c77SSepherosa Ziehau /* No more channel packets; done! */ 727415516c77SSepherosa Ziehau break; 727515516c77SSepherosa Ziehau } 727615516c77SSepherosa Ziehau KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error)); 727715516c77SSepherosa Ziehau 727815516c77SSepherosa Ziehau switch (pkt->cph_type) { 727915516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_COMP: 728015516c77SSepherosa Ziehau hn_nvs_handle_comp(sc, chan, pkt); 728115516c77SSepherosa Ziehau break; 728215516c77SSepherosa Ziehau 728315516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_RXBUF: 728415516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(rxr, chan, pkt); 728515516c77SSepherosa Ziehau break; 728615516c77SSepherosa Ziehau 728715516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_INBAND: 728815516c77SSepherosa Ziehau hn_nvs_handle_notify(sc, pkt); 728915516c77SSepherosa Ziehau break; 729015516c77SSepherosa Ziehau 729115516c77SSepherosa Ziehau default: 729215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "unknown chan pkt %u\n", 729315516c77SSepherosa Ziehau pkt->cph_type); 729415516c77SSepherosa Ziehau break; 729515516c77SSepherosa Ziehau } 729615516c77SSepherosa Ziehau } 729715516c77SSepherosa Ziehau hn_chan_rollup(rxr, rxr->hn_txr); 729815516c77SSepherosa Ziehau } 729915516c77SSepherosa Ziehau 730015516c77SSepherosa Ziehau static void 7301499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused) 730215516c77SSepherosa Ziehau { 7303fdd0222aSSepherosa Ziehau int i; 7304fdd0222aSSepherosa Ziehau 73059c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 73069c6cae24SSepherosa Ziehau /* 73079c6cae24SSepherosa Ziehau * Don't use ifnet.if_start if transparent VF mode is requested; 73089c6cae24SSepherosa Ziehau * mainly due to the IFF_DRV_OACTIVE flag. 73099c6cae24SSepherosa Ziehau */ 73109c6cae24SSepherosa Ziehau if (hn_xpnt_vf && hn_use_if_start) { 73119c6cae24SSepherosa Ziehau hn_use_if_start = 0; 73129c6cae24SSepherosa Ziehau printf("hn: tranparent VF mode, if_transmit will be used, " 73139c6cae24SSepherosa Ziehau "instead of if_start\n"); 73149c6cae24SSepherosa Ziehau } 73159c6cae24SSepherosa Ziehau #endif 73169c6cae24SSepherosa Ziehau if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) { 73179c6cae24SSepherosa Ziehau printf("hn: invalid transparent VF attach routing " 73189c6cae24SSepherosa Ziehau "wait timeout %d, reset to %d\n", 73199c6cae24SSepherosa Ziehau hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN); 73209c6cae24SSepherosa Ziehau hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN; 73219c6cae24SSepherosa Ziehau } 73229c6cae24SSepherosa Ziehau 7323fdd0222aSSepherosa Ziehau /* 7324499c3e17SSepherosa Ziehau * Initialize VF map. 7325499c3e17SSepherosa Ziehau */ 7326499c3e17SSepherosa Ziehau rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE); 7327499c3e17SSepherosa Ziehau hn_vfmap_size = HN_VFMAP_SIZE_DEF; 7328499c3e17SSepherosa Ziehau hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF, 7329499c3e17SSepherosa Ziehau M_WAITOK | M_ZERO); 7330499c3e17SSepherosa Ziehau 7331499c3e17SSepherosa Ziehau /* 7332fdd0222aSSepherosa Ziehau * Fix the # of TX taskqueues. 7333fdd0222aSSepherosa Ziehau */ 7334fdd0222aSSepherosa Ziehau if (hn_tx_taskq_cnt <= 0) 7335fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = 1; 7336fdd0222aSSepherosa Ziehau else if (hn_tx_taskq_cnt > mp_ncpus) 7337fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = mp_ncpus; 733815516c77SSepherosa Ziehau 73390e11868dSSepherosa Ziehau /* 73400e11868dSSepherosa Ziehau * Fix the TX taskqueue mode. 73410e11868dSSepherosa Ziehau */ 73420e11868dSSepherosa Ziehau switch (hn_tx_taskq_mode) { 73430e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_INDEP: 73440e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_GLOBAL: 73450e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_EVTTQ: 73460e11868dSSepherosa Ziehau break; 73470e11868dSSepherosa Ziehau default: 73480e11868dSSepherosa Ziehau hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP; 73490e11868dSSepherosa Ziehau break; 73500e11868dSSepherosa Ziehau } 73510e11868dSSepherosa Ziehau 735215516c77SSepherosa Ziehau if (vm_guest != VM_GUEST_HV) 735315516c77SSepherosa Ziehau return; 735415516c77SSepherosa Ziehau 73550e11868dSSepherosa Ziehau if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL) 735615516c77SSepherosa Ziehau return; 735715516c77SSepherosa Ziehau 7358fdd0222aSSepherosa Ziehau hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 7359fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 7360fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 7361fdd0222aSSepherosa Ziehau hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK, 7362fdd0222aSSepherosa Ziehau taskqueue_thread_enqueue, &hn_tx_taskque[i]); 7363fdd0222aSSepherosa Ziehau taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET, 7364fdd0222aSSepherosa Ziehau "hn tx%d", i); 7365fdd0222aSSepherosa Ziehau } 736615516c77SSepherosa Ziehau } 7367499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL); 736815516c77SSepherosa Ziehau 736915516c77SSepherosa Ziehau static void 7370499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused) 737115516c77SSepherosa Ziehau { 737215516c77SSepherosa Ziehau 7373fdd0222aSSepherosa Ziehau if (hn_tx_taskque != NULL) { 7374fdd0222aSSepherosa Ziehau int i; 7375fdd0222aSSepherosa Ziehau 7376fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 7377fdd0222aSSepherosa Ziehau taskqueue_free(hn_tx_taskque[i]); 7378fdd0222aSSepherosa Ziehau free(hn_tx_taskque, M_DEVBUF); 7379fdd0222aSSepherosa Ziehau } 7380499c3e17SSepherosa Ziehau 7381499c3e17SSepherosa Ziehau if (hn_vfmap != NULL) 7382499c3e17SSepherosa Ziehau free(hn_vfmap, M_DEVBUF); 7383499c3e17SSepherosa Ziehau rm_destroy(&hn_vfmap_lock); 738415516c77SSepherosa Ziehau } 7385499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL); 7386