115516c77SSepherosa Ziehau /*- 215516c77SSepherosa Ziehau * Copyright (c) 2010-2012 Citrix Inc. 315516c77SSepherosa Ziehau * Copyright (c) 2009-2012,2016 Microsoft Corp. 415516c77SSepherosa Ziehau * Copyright (c) 2012 NetApp Inc. 515516c77SSepherosa Ziehau * All rights reserved. 615516c77SSepherosa Ziehau * 715516c77SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 815516c77SSepherosa Ziehau * modification, are permitted provided that the following conditions 915516c77SSepherosa Ziehau * are met: 1015516c77SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 1115516c77SSepherosa Ziehau * notice unmodified, this list of conditions, and the following 1215516c77SSepherosa Ziehau * disclaimer. 1315516c77SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 1415516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 1515516c77SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 1615516c77SSepherosa Ziehau * 1715516c77SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1815516c77SSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1915516c77SSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2015516c77SSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2115516c77SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2215516c77SSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2315516c77SSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2415516c77SSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2515516c77SSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2615516c77SSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2715516c77SSepherosa Ziehau */ 2815516c77SSepherosa Ziehau 2915516c77SSepherosa Ziehau /*- 3015516c77SSepherosa Ziehau * Copyright (c) 2004-2006 Kip Macy 3115516c77SSepherosa Ziehau * All rights reserved. 3215516c77SSepherosa Ziehau * 3315516c77SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 3415516c77SSepherosa Ziehau * modification, are permitted provided that the following conditions 3515516c77SSepherosa Ziehau * are met: 3615516c77SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 3715516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 3815516c77SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 3915516c77SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 4015516c77SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 4115516c77SSepherosa Ziehau * 4215516c77SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 4315516c77SSepherosa Ziehau * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4415516c77SSepherosa Ziehau * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4515516c77SSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4615516c77SSepherosa Ziehau * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4715516c77SSepherosa Ziehau * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4815516c77SSepherosa Ziehau * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4915516c77SSepherosa Ziehau * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5015516c77SSepherosa Ziehau * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5115516c77SSepherosa Ziehau * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5215516c77SSepherosa Ziehau * SUCH DAMAGE. 5315516c77SSepherosa Ziehau */ 5415516c77SSepherosa Ziehau 5515516c77SSepherosa Ziehau #include <sys/cdefs.h> 5615516c77SSepherosa Ziehau __FBSDID("$FreeBSD$"); 5715516c77SSepherosa Ziehau 5834d68912SSepherosa Ziehau #include "opt_hn.h" 5915516c77SSepherosa Ziehau #include "opt_inet6.h" 6015516c77SSepherosa Ziehau #include "opt_inet.h" 6134d68912SSepherosa Ziehau #include "opt_rss.h" 6215516c77SSepherosa Ziehau 6315516c77SSepherosa Ziehau #include <sys/param.h> 6415516c77SSepherosa Ziehau #include <sys/bus.h> 6515516c77SSepherosa Ziehau #include <sys/kernel.h> 6615516c77SSepherosa Ziehau #include <sys/limits.h> 6715516c77SSepherosa Ziehau #include <sys/malloc.h> 6815516c77SSepherosa Ziehau #include <sys/mbuf.h> 6915516c77SSepherosa Ziehau #include <sys/module.h> 7015516c77SSepherosa Ziehau #include <sys/queue.h> 7115516c77SSepherosa Ziehau #include <sys/lock.h> 7215516c77SSepherosa Ziehau #include <sys/smp.h> 7315516c77SSepherosa Ziehau #include <sys/socket.h> 7415516c77SSepherosa Ziehau #include <sys/sockio.h> 7515516c77SSepherosa Ziehau #include <sys/sx.h> 7615516c77SSepherosa Ziehau #include <sys/sysctl.h> 7715516c77SSepherosa Ziehau #include <sys/systm.h> 7815516c77SSepherosa Ziehau #include <sys/taskqueue.h> 7915516c77SSepherosa Ziehau #include <sys/buf_ring.h> 805bdfd3fdSDexuan Cui #include <sys/eventhandler.h> 8115516c77SSepherosa Ziehau 8215516c77SSepherosa Ziehau #include <machine/atomic.h> 8315516c77SSepherosa Ziehau #include <machine/in_cksum.h> 8415516c77SSepherosa Ziehau 8515516c77SSepherosa Ziehau #include <net/bpf.h> 8615516c77SSepherosa Ziehau #include <net/ethernet.h> 8715516c77SSepherosa Ziehau #include <net/if.h> 885bdfd3fdSDexuan Cui #include <net/if_dl.h> 8915516c77SSepherosa Ziehau #include <net/if_media.h> 9015516c77SSepherosa Ziehau #include <net/if_types.h> 9115516c77SSepherosa Ziehau #include <net/if_var.h> 9215516c77SSepherosa Ziehau #include <net/rndis.h> 9334d68912SSepherosa Ziehau #ifdef RSS 9434d68912SSepherosa Ziehau #include <net/rss_config.h> 9534d68912SSepherosa Ziehau #endif 9615516c77SSepherosa Ziehau 9715516c77SSepherosa Ziehau #include <netinet/in_systm.h> 9815516c77SSepherosa Ziehau #include <netinet/in.h> 9915516c77SSepherosa Ziehau #include <netinet/ip.h> 10015516c77SSepherosa Ziehau #include <netinet/ip6.h> 10115516c77SSepherosa Ziehau #include <netinet/tcp.h> 10215516c77SSepherosa Ziehau #include <netinet/tcp_lro.h> 10315516c77SSepherosa Ziehau #include <netinet/udp.h> 10415516c77SSepherosa Ziehau 10515516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h> 10615516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h> 10715516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h> 10815516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h> 10915516c77SSepherosa Ziehau 11015516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h> 11115516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h> 11215516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h> 11315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h> 11415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h> 11515516c77SSepherosa Ziehau 11615516c77SSepherosa Ziehau #include "vmbus_if.h" 11715516c77SSepherosa Ziehau 11823bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT 11923bf9e15SSepherosa Ziehau 12015516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX 8 12115516c77SSepherosa Ziehau 12215516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */ 12315516c77SSepherosa Ziehau #define HN_TX_DESC_CNT 512 12415516c77SSepherosa Ziehau 12515516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN \ 12615516c77SSepherosa Ziehau (sizeof(struct rndis_packet_msg) + \ 12715516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) + \ 12815516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) + \ 12915516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) + \ 13015516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE)) 13115516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY PAGE_SIZE 13215516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN CACHE_LINE_SIZE 13315516c77SSepherosa Ziehau 13415516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY PAGE_SIZE 13515516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE IP_MAXPACKET 13615516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE PAGE_SIZE 13715516c77SSepherosa Ziehau /* -1 for RNDIS packet message */ 13815516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX (HN_GPACNT_MAX - 1) 13915516c77SSepherosa Ziehau 14015516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF 128 14115516c77SSepherosa Ziehau 14215516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH 8 14315516c77SSepherosa Ziehau 14415516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF (16 * 1024) 14515516c77SSepherosa Ziehau 14615516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF 128 14715516c77SSepherosa Ziehau 14815516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF (12 * ETHERMTU) 14915516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF (25 * ETHERMTU) 15015516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */ 15115516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp) (2 * (ifp)->if_mtu) 15215516c77SSepherosa Ziehau 15315516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF 1 15415516c77SSepherosa Ziehau 15515516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc) \ 15615516c77SSepherosa Ziehau sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev)) 15715516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc) sx_destroy(&(sc)->hn_lock) 15815516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc) sx_assert(&(sc)->hn_lock, SA_XLOCKED) 159fdc4f478SSepherosa Ziehau #define HN_LOCK(sc) \ 160fdc4f478SSepherosa Ziehau do { \ 161fdc4f478SSepherosa Ziehau while (sx_try_xlock(&(sc)->hn_lock) == 0) \ 162fdc4f478SSepherosa Ziehau DELAY(1000); \ 163fdc4f478SSepherosa Ziehau } while (0) 16415516c77SSepherosa Ziehau #define HN_UNLOCK(sc) sx_xunlock(&(sc)->hn_lock) 16515516c77SSepherosa Ziehau 16615516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK (CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP) 16715516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK (CSUM_IP6_TCP | CSUM_IP6_UDP) 16815516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc) \ 16915516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK) 17015516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc) \ 17115516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK) 17215516c77SSepherosa Ziehau 173dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align) \ 174dc13fee6SSepherosa Ziehau roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \ 175dc13fee6SSepherosa Ziehau HN_RNDIS_PKT_LEN, (align)) 176dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align) \ 177dc13fee6SSepherosa Ziehau roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align)) 178dc13fee6SSepherosa Ziehau 17934d68912SSepherosa Ziehau #ifdef RSS 18034d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx) rss_getcpu((idx) % rss_getnumbuckets()) 18134d68912SSepherosa Ziehau #else 1820e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx) (((sc)->hn_cpu + (idx)) % mp_ncpus) 18334d68912SSepherosa Ziehau #endif 1840e11868dSSepherosa Ziehau 18515516c77SSepherosa Ziehau struct hn_txdesc { 18615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 18715516c77SSepherosa Ziehau SLIST_ENTRY(hn_txdesc) link; 18815516c77SSepherosa Ziehau #endif 189dc13fee6SSepherosa Ziehau STAILQ_ENTRY(hn_txdesc) agg_link; 190dc13fee6SSepherosa Ziehau 191dc13fee6SSepherosa Ziehau /* Aggregated txdescs, in sending order. */ 192dc13fee6SSepherosa Ziehau STAILQ_HEAD(, hn_txdesc) agg_list; 193dc13fee6SSepherosa Ziehau 194dc13fee6SSepherosa Ziehau /* The oldest packet, if transmission aggregation happens. */ 19515516c77SSepherosa Ziehau struct mbuf *m; 19615516c77SSepherosa Ziehau struct hn_tx_ring *txr; 19715516c77SSepherosa Ziehau int refs; 19815516c77SSepherosa Ziehau uint32_t flags; /* HN_TXD_FLAG_ */ 19915516c77SSepherosa Ziehau struct hn_nvs_sendctx send_ctx; 20015516c77SSepherosa Ziehau uint32_t chim_index; 20115516c77SSepherosa Ziehau int chim_size; 20215516c77SSepherosa Ziehau 20315516c77SSepherosa Ziehau bus_dmamap_t data_dmap; 20415516c77SSepherosa Ziehau 20515516c77SSepherosa Ziehau bus_addr_t rndis_pkt_paddr; 20615516c77SSepherosa Ziehau struct rndis_packet_msg *rndis_pkt; 20715516c77SSepherosa Ziehau bus_dmamap_t rndis_pkt_dmap; 20815516c77SSepherosa Ziehau }; 20915516c77SSepherosa Ziehau 21015516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST 0x0001 21115516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP 0x0002 212dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG 0x0004 21315516c77SSepherosa Ziehau 21415516c77SSepherosa Ziehau struct hn_rxinfo { 21515516c77SSepherosa Ziehau uint32_t vlan_info; 21615516c77SSepherosa Ziehau uint32_t csum_info; 21715516c77SSepherosa Ziehau uint32_t hash_info; 21815516c77SSepherosa Ziehau uint32_t hash_value; 21915516c77SSepherosa Ziehau }; 22015516c77SSepherosa Ziehau 2215bdfd3fdSDexuan Cui struct hn_update_vf { 2225bdfd3fdSDexuan Cui struct hn_rx_ring *rxr; 2235bdfd3fdSDexuan Cui struct ifnet *vf; 2245bdfd3fdSDexuan Cui }; 2255bdfd3fdSDexuan Cui 22615516c77SSepherosa Ziehau #define HN_RXINFO_VLAN 0x0001 22715516c77SSepherosa Ziehau #define HN_RXINFO_CSUM 0x0002 22815516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF 0x0004 22915516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL 0x0008 23015516c77SSepherosa Ziehau #define HN_RXINFO_ALL \ 23115516c77SSepherosa Ziehau (HN_RXINFO_VLAN | \ 23215516c77SSepherosa Ziehau HN_RXINFO_CSUM | \ 23315516c77SSepherosa Ziehau HN_RXINFO_HASHINF | \ 23415516c77SSepherosa Ziehau HN_RXINFO_HASHVAL) 23515516c77SSepherosa Ziehau 23615516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID 0xffffffff 23715516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID 0 23815516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID 0 23915516c77SSepherosa Ziehau 24015516c77SSepherosa Ziehau static int hn_probe(device_t); 24115516c77SSepherosa Ziehau static int hn_attach(device_t); 24215516c77SSepherosa Ziehau static int hn_detach(device_t); 24315516c77SSepherosa Ziehau static int hn_shutdown(device_t); 24415516c77SSepherosa Ziehau static void hn_chan_callback(struct vmbus_channel *, 24515516c77SSepherosa Ziehau void *); 24615516c77SSepherosa Ziehau 24715516c77SSepherosa Ziehau static void hn_init(void *); 24815516c77SSepherosa Ziehau static int hn_ioctl(struct ifnet *, u_long, caddr_t); 24923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 25015516c77SSepherosa Ziehau static void hn_start(struct ifnet *); 25123bf9e15SSepherosa Ziehau #endif 25215516c77SSepherosa Ziehau static int hn_transmit(struct ifnet *, struct mbuf *); 25315516c77SSepherosa Ziehau static void hn_xmit_qflush(struct ifnet *); 25415516c77SSepherosa Ziehau static int hn_ifmedia_upd(struct ifnet *); 25515516c77SSepherosa Ziehau static void hn_ifmedia_sts(struct ifnet *, 25615516c77SSepherosa Ziehau struct ifmediareq *); 25715516c77SSepherosa Ziehau 25815516c77SSepherosa Ziehau static int hn_rndis_rxinfo(const void *, int, 25915516c77SSepherosa Ziehau struct hn_rxinfo *); 26015516c77SSepherosa Ziehau static void hn_rndis_rx_data(struct hn_rx_ring *, 26115516c77SSepherosa Ziehau const void *, int); 26215516c77SSepherosa Ziehau static void hn_rndis_rx_status(struct hn_softc *, 26315516c77SSepherosa Ziehau const void *, int); 26415516c77SSepherosa Ziehau 26515516c77SSepherosa Ziehau static void hn_nvs_handle_notify(struct hn_softc *, 26615516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 26715516c77SSepherosa Ziehau static void hn_nvs_handle_comp(struct hn_softc *, 26815516c77SSepherosa Ziehau struct vmbus_channel *, 26915516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 27015516c77SSepherosa Ziehau static void hn_nvs_handle_rxbuf(struct hn_rx_ring *, 27115516c77SSepherosa Ziehau struct vmbus_channel *, 27215516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 27315516c77SSepherosa Ziehau static void hn_nvs_ack_rxbuf(struct hn_rx_ring *, 27415516c77SSepherosa Ziehau struct vmbus_channel *, uint64_t); 27515516c77SSepherosa Ziehau 27615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 27715516c77SSepherosa Ziehau static int hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS); 27815516c77SSepherosa Ziehau static int hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS); 27915516c77SSepherosa Ziehau #endif 28015516c77SSepherosa Ziehau static int hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS); 28115516c77SSepherosa Ziehau static int hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS); 28215516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 28315516c77SSepherosa Ziehau static int hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS); 28415516c77SSepherosa Ziehau #else 28515516c77SSepherosa Ziehau static int hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS); 28615516c77SSepherosa Ziehau #endif 28715516c77SSepherosa Ziehau static int hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 28815516c77SSepherosa Ziehau static int hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 28915516c77SSepherosa Ziehau static int hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS); 29015516c77SSepherosa Ziehau static int hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS); 29115516c77SSepherosa Ziehau static int hn_caps_sysctl(SYSCTL_HANDLER_ARGS); 29215516c77SSepherosa Ziehau static int hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS); 29315516c77SSepherosa Ziehau static int hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS); 29434d68912SSepherosa Ziehau #ifndef RSS 29515516c77SSepherosa Ziehau static int hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS); 29615516c77SSepherosa Ziehau static int hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS); 29734d68912SSepherosa Ziehau #endif 29815516c77SSepherosa Ziehau static int hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS); 299dc13fee6SSepherosa Ziehau static int hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS); 300dc13fee6SSepherosa Ziehau static int hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS); 301dc13fee6SSepherosa Ziehau static int hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS); 302dc13fee6SSepherosa Ziehau static int hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS); 3036c1204dfSSepherosa Ziehau static int hn_polling_sysctl(SYSCTL_HANDLER_ARGS); 30440d60d6eSDexuan Cui static int hn_vf_sysctl(SYSCTL_HANDLER_ARGS); 30515516c77SSepherosa Ziehau 3065bdfd3fdSDexuan Cui static void hn_stop(struct hn_softc *, bool); 30715516c77SSepherosa Ziehau static void hn_init_locked(struct hn_softc *); 30815516c77SSepherosa Ziehau static int hn_chan_attach(struct hn_softc *, 30915516c77SSepherosa Ziehau struct vmbus_channel *); 31015516c77SSepherosa Ziehau static void hn_chan_detach(struct hn_softc *, 31115516c77SSepherosa Ziehau struct vmbus_channel *); 31215516c77SSepherosa Ziehau static int hn_attach_subchans(struct hn_softc *); 31315516c77SSepherosa Ziehau static void hn_detach_allchans(struct hn_softc *); 31415516c77SSepherosa Ziehau static void hn_chan_rollup(struct hn_rx_ring *, 31515516c77SSepherosa Ziehau struct hn_tx_ring *); 31615516c77SSepherosa Ziehau static void hn_set_ring_inuse(struct hn_softc *, int); 31715516c77SSepherosa Ziehau static int hn_synth_attach(struct hn_softc *, int); 31815516c77SSepherosa Ziehau static void hn_synth_detach(struct hn_softc *); 31915516c77SSepherosa Ziehau static int hn_synth_alloc_subchans(struct hn_softc *, 32015516c77SSepherosa Ziehau int *); 3212494d735SSepherosa Ziehau static bool hn_synth_attachable(const struct hn_softc *); 32215516c77SSepherosa Ziehau static void hn_suspend(struct hn_softc *); 32315516c77SSepherosa Ziehau static void hn_suspend_data(struct hn_softc *); 32415516c77SSepherosa Ziehau static void hn_suspend_mgmt(struct hn_softc *); 32515516c77SSepherosa Ziehau static void hn_resume(struct hn_softc *); 32615516c77SSepherosa Ziehau static void hn_resume_data(struct hn_softc *); 32715516c77SSepherosa Ziehau static void hn_resume_mgmt(struct hn_softc *); 32815516c77SSepherosa Ziehau static void hn_suspend_mgmt_taskfunc(void *, int); 32925641fc7SSepherosa Ziehau static void hn_chan_drain(struct hn_softc *, 33025641fc7SSepherosa Ziehau struct vmbus_channel *); 3316c1204dfSSepherosa Ziehau static void hn_polling(struct hn_softc *, u_int); 3326c1204dfSSepherosa Ziehau static void hn_chan_polling(struct vmbus_channel *, u_int); 33315516c77SSepherosa Ziehau 33415516c77SSepherosa Ziehau static void hn_update_link_status(struct hn_softc *); 33515516c77SSepherosa Ziehau static void hn_change_network(struct hn_softc *); 33615516c77SSepherosa Ziehau static void hn_link_taskfunc(void *, int); 33715516c77SSepherosa Ziehau static void hn_netchg_init_taskfunc(void *, int); 33815516c77SSepherosa Ziehau static void hn_netchg_status_taskfunc(void *, int); 33915516c77SSepherosa Ziehau static void hn_link_status(struct hn_softc *); 34015516c77SSepherosa Ziehau 34115516c77SSepherosa Ziehau static int hn_create_rx_data(struct hn_softc *, int); 34215516c77SSepherosa Ziehau static void hn_destroy_rx_data(struct hn_softc *); 34315516c77SSepherosa Ziehau static int hn_check_iplen(const struct mbuf *, int); 344f1b0a43fSSepherosa Ziehau static int hn_set_rxfilter(struct hn_softc *, uint32_t); 345c08f7b2cSSepherosa Ziehau static int hn_rxfilter_config(struct hn_softc *); 34634d68912SSepherosa Ziehau #ifndef RSS 34715516c77SSepherosa Ziehau static int hn_rss_reconfig(struct hn_softc *); 34834d68912SSepherosa Ziehau #endif 349afd4971bSSepherosa Ziehau static void hn_rss_ind_fixup(struct hn_softc *); 35015516c77SSepherosa Ziehau static int hn_rxpkt(struct hn_rx_ring *, const void *, 35115516c77SSepherosa Ziehau int, const struct hn_rxinfo *); 35215516c77SSepherosa Ziehau 35315516c77SSepherosa Ziehau static int hn_tx_ring_create(struct hn_softc *, int); 35415516c77SSepherosa Ziehau static void hn_tx_ring_destroy(struct hn_tx_ring *); 35515516c77SSepherosa Ziehau static int hn_create_tx_data(struct hn_softc *, int); 35615516c77SSepherosa Ziehau static void hn_fixup_tx_data(struct hn_softc *); 35715516c77SSepherosa Ziehau static void hn_destroy_tx_data(struct hn_softc *); 35815516c77SSepherosa Ziehau static void hn_txdesc_dmamap_destroy(struct hn_txdesc *); 35925641fc7SSepherosa Ziehau static void hn_txdesc_gc(struct hn_tx_ring *, 36025641fc7SSepherosa Ziehau struct hn_txdesc *); 361dc13fee6SSepherosa Ziehau static int hn_encap(struct ifnet *, struct hn_tx_ring *, 36215516c77SSepherosa Ziehau struct hn_txdesc *, struct mbuf **); 36315516c77SSepherosa Ziehau static int hn_txpkt(struct ifnet *, struct hn_tx_ring *, 36415516c77SSepherosa Ziehau struct hn_txdesc *); 36515516c77SSepherosa Ziehau static void hn_set_chim_size(struct hn_softc *, int); 36615516c77SSepherosa Ziehau static void hn_set_tso_maxsize(struct hn_softc *, int, int); 36715516c77SSepherosa Ziehau static bool hn_tx_ring_pending(struct hn_tx_ring *); 36815516c77SSepherosa Ziehau static void hn_tx_ring_qflush(struct hn_tx_ring *); 36915516c77SSepherosa Ziehau static void hn_resume_tx(struct hn_softc *, int); 370dc13fee6SSepherosa Ziehau static void hn_set_txagg(struct hn_softc *); 371dc13fee6SSepherosa Ziehau static void *hn_try_txagg(struct ifnet *, 372dc13fee6SSepherosa Ziehau struct hn_tx_ring *, struct hn_txdesc *, 373dc13fee6SSepherosa Ziehau int); 37415516c77SSepherosa Ziehau static int hn_get_txswq_depth(const struct hn_tx_ring *); 37515516c77SSepherosa Ziehau static void hn_txpkt_done(struct hn_nvs_sendctx *, 37615516c77SSepherosa Ziehau struct hn_softc *, struct vmbus_channel *, 37715516c77SSepherosa Ziehau const void *, int); 37815516c77SSepherosa Ziehau static int hn_txpkt_sglist(struct hn_tx_ring *, 37915516c77SSepherosa Ziehau struct hn_txdesc *); 38015516c77SSepherosa Ziehau static int hn_txpkt_chim(struct hn_tx_ring *, 38115516c77SSepherosa Ziehau struct hn_txdesc *); 38215516c77SSepherosa Ziehau static int hn_xmit(struct hn_tx_ring *, int); 38315516c77SSepherosa Ziehau static void hn_xmit_taskfunc(void *, int); 38415516c77SSepherosa Ziehau static void hn_xmit_txeof(struct hn_tx_ring *); 38515516c77SSepherosa Ziehau static void hn_xmit_txeof_taskfunc(void *, int); 38623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 38715516c77SSepherosa Ziehau static int hn_start_locked(struct hn_tx_ring *, int); 38815516c77SSepherosa Ziehau static void hn_start_taskfunc(void *, int); 38915516c77SSepherosa Ziehau static void hn_start_txeof(struct hn_tx_ring *); 39015516c77SSepherosa Ziehau static void hn_start_txeof_taskfunc(void *, int); 39123bf9e15SSepherosa Ziehau #endif 39215516c77SSepherosa Ziehau 39315516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 39415516c77SSepherosa Ziehau "Hyper-V network interface"); 39515516c77SSepherosa Ziehau 39615516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */ 39715516c77SSepherosa Ziehau static int hn_trust_hosttcp = 1; 39815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN, 39915516c77SSepherosa Ziehau &hn_trust_hosttcp, 0, 40015516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 40115516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 40215516c77SSepherosa Ziehau 40315516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */ 40415516c77SSepherosa Ziehau static int hn_trust_hostudp = 1; 40515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN, 40615516c77SSepherosa Ziehau &hn_trust_hostudp, 0, 40715516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 40815516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 40915516c77SSepherosa Ziehau 41015516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */ 41115516c77SSepherosa Ziehau static int hn_trust_hostip = 1; 41215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN, 41315516c77SSepherosa Ziehau &hn_trust_hostip, 0, 41415516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 41515516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 41615516c77SSepherosa Ziehau 41715516c77SSepherosa Ziehau /* Limit TSO burst size */ 41815516c77SSepherosa Ziehau static int hn_tso_maxlen = IP_MAXPACKET; 41915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN, 42015516c77SSepherosa Ziehau &hn_tso_maxlen, 0, "TSO burst limit"); 42115516c77SSepherosa Ziehau 42215516c77SSepherosa Ziehau /* Limit chimney send size */ 42315516c77SSepherosa Ziehau static int hn_tx_chimney_size = 0; 42415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN, 42515516c77SSepherosa Ziehau &hn_tx_chimney_size, 0, "Chimney send packet size limit"); 42615516c77SSepherosa Ziehau 42715516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */ 42815516c77SSepherosa Ziehau static int hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF; 42915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN, 43015516c77SSepherosa Ziehau &hn_direct_tx_size, 0, "Size of the packet for direct transmission"); 43115516c77SSepherosa Ziehau 43215516c77SSepherosa Ziehau /* # of LRO entries per RX ring */ 43315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 43415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 43515516c77SSepherosa Ziehau static int hn_lro_entry_count = HN_LROENT_CNT_DEF; 43615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN, 43715516c77SSepherosa Ziehau &hn_lro_entry_count, 0, "LRO entry count"); 43815516c77SSepherosa Ziehau #endif 43915516c77SSepherosa Ziehau #endif 44015516c77SSepherosa Ziehau 441fdd0222aSSepherosa Ziehau static int hn_tx_taskq_cnt = 1; 442fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN, 443fdd0222aSSepherosa Ziehau &hn_tx_taskq_cnt, 0, "# of TX taskqueues"); 444fdd0222aSSepherosa Ziehau 4450e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP 0 4460e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL 1 4470e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ 2 4480e11868dSSepherosa Ziehau 4490e11868dSSepherosa Ziehau static int hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP; 4500e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN, 4510e11868dSSepherosa Ziehau &hn_tx_taskq_mode, 0, "TX taskqueue modes: " 4520e11868dSSepherosa Ziehau "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs"); 4530e11868dSSepherosa Ziehau 45415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 45515516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 0; 45615516c77SSepherosa Ziehau #else 45715516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 1; 45815516c77SSepherosa Ziehau #endif 45915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD, 46015516c77SSepherosa Ziehau &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors"); 46115516c77SSepherosa Ziehau 46223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 46315516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */ 46415516c77SSepherosa Ziehau static int hn_use_if_start = 0; 46515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN, 46615516c77SSepherosa Ziehau &hn_use_if_start, 0, "Use if_start TX method"); 46723bf9e15SSepherosa Ziehau #endif 46815516c77SSepherosa Ziehau 46915516c77SSepherosa Ziehau /* # of channels to use */ 47015516c77SSepherosa Ziehau static int hn_chan_cnt = 0; 47115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN, 47215516c77SSepherosa Ziehau &hn_chan_cnt, 0, 47315516c77SSepherosa Ziehau "# of channels to use; each channel has one RX ring and one TX ring"); 47415516c77SSepherosa Ziehau 47515516c77SSepherosa Ziehau /* # of transmit rings to use */ 47615516c77SSepherosa Ziehau static int hn_tx_ring_cnt = 0; 47715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN, 47815516c77SSepherosa Ziehau &hn_tx_ring_cnt, 0, "# of TX rings to use"); 47915516c77SSepherosa Ziehau 48015516c77SSepherosa Ziehau /* Software TX ring deptch */ 48115516c77SSepherosa Ziehau static int hn_tx_swq_depth = 0; 48215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN, 48315516c77SSepherosa Ziehau &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING"); 48415516c77SSepherosa Ziehau 48515516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */ 48615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 48715516c77SSepherosa Ziehau static u_int hn_lro_mbufq_depth = 0; 48815516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN, 48915516c77SSepherosa Ziehau &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue"); 49015516c77SSepherosa Ziehau #endif 49115516c77SSepherosa Ziehau 492dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */ 493dc13fee6SSepherosa Ziehau static int hn_tx_agg_size = -1; 494dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN, 495dc13fee6SSepherosa Ziehau &hn_tx_agg_size, 0, "Packet transmission aggregation size limit"); 496dc13fee6SSepherosa Ziehau 497dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */ 498fa915c4dSSepherosa Ziehau static int hn_tx_agg_pkts = -1; 499dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN, 500dc13fee6SSepherosa Ziehau &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit"); 501dc13fee6SSepherosa Ziehau 50215516c77SSepherosa Ziehau static u_int hn_cpu_index; /* next CPU for channel */ 503fdd0222aSSepherosa Ziehau static struct taskqueue **hn_tx_taskque;/* shared TX taskqueues */ 50415516c77SSepherosa Ziehau 50534d68912SSepherosa Ziehau #ifndef RSS 50615516c77SSepherosa Ziehau static const uint8_t 50715516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = { 50815516c77SSepherosa Ziehau 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 50915516c77SSepherosa Ziehau 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 51015516c77SSepherosa Ziehau 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 51115516c77SSepherosa Ziehau 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 51215516c77SSepherosa Ziehau 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa 51315516c77SSepherosa Ziehau }; 51434d68912SSepherosa Ziehau #endif /* !RSS */ 51515516c77SSepherosa Ziehau 51615516c77SSepherosa Ziehau static device_method_t hn_methods[] = { 51715516c77SSepherosa Ziehau /* Device interface */ 51815516c77SSepherosa Ziehau DEVMETHOD(device_probe, hn_probe), 51915516c77SSepherosa Ziehau DEVMETHOD(device_attach, hn_attach), 52015516c77SSepherosa Ziehau DEVMETHOD(device_detach, hn_detach), 52115516c77SSepherosa Ziehau DEVMETHOD(device_shutdown, hn_shutdown), 52215516c77SSepherosa Ziehau DEVMETHOD_END 52315516c77SSepherosa Ziehau }; 52415516c77SSepherosa Ziehau 52515516c77SSepherosa Ziehau static driver_t hn_driver = { 52615516c77SSepherosa Ziehau "hn", 52715516c77SSepherosa Ziehau hn_methods, 52815516c77SSepherosa Ziehau sizeof(struct hn_softc) 52915516c77SSepherosa Ziehau }; 53015516c77SSepherosa Ziehau 53115516c77SSepherosa Ziehau static devclass_t hn_devclass; 53215516c77SSepherosa Ziehau 53315516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0); 53415516c77SSepherosa Ziehau MODULE_VERSION(hn, 1); 53515516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1); 53615516c77SSepherosa Ziehau 53715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 53815516c77SSepherosa Ziehau static void 53915516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim) 54015516c77SSepherosa Ziehau { 54115516c77SSepherosa Ziehau int i; 54215516c77SSepherosa Ziehau 543a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 54415516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim; 54515516c77SSepherosa Ziehau } 54615516c77SSepherosa Ziehau #endif 54715516c77SSepherosa Ziehau 54815516c77SSepherosa Ziehau static int 54915516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd) 55015516c77SSepherosa Ziehau { 55115516c77SSepherosa Ziehau 55215516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 55315516c77SSepherosa Ziehau txd->chim_size == 0, ("invalid rndis sglist txd")); 55415516c77SSepherosa Ziehau return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA, 55515516c77SSepherosa Ziehau &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt)); 55615516c77SSepherosa Ziehau } 55715516c77SSepherosa Ziehau 55815516c77SSepherosa Ziehau static int 55915516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd) 56015516c77SSepherosa Ziehau { 56115516c77SSepherosa Ziehau struct hn_nvs_rndis rndis; 56215516c77SSepherosa Ziehau 56315516c77SSepherosa Ziehau KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID && 56415516c77SSepherosa Ziehau txd->chim_size > 0, ("invalid rndis chim txd")); 56515516c77SSepherosa Ziehau 56615516c77SSepherosa Ziehau rndis.nvs_type = HN_NVS_TYPE_RNDIS; 56715516c77SSepherosa Ziehau rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA; 56815516c77SSepherosa Ziehau rndis.nvs_chim_idx = txd->chim_index; 56915516c77SSepherosa Ziehau rndis.nvs_chim_sz = txd->chim_size; 57015516c77SSepherosa Ziehau 57115516c77SSepherosa Ziehau return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC, 57215516c77SSepherosa Ziehau &rndis, sizeof(rndis), &txd->send_ctx)); 57315516c77SSepherosa Ziehau } 57415516c77SSepherosa Ziehau 57515516c77SSepherosa Ziehau static __inline uint32_t 57615516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc) 57715516c77SSepherosa Ziehau { 57815516c77SSepherosa Ziehau int i, bmap_cnt = sc->hn_chim_bmap_cnt; 57915516c77SSepherosa Ziehau u_long *bmap = sc->hn_chim_bmap; 58015516c77SSepherosa Ziehau uint32_t ret = HN_NVS_CHIM_IDX_INVALID; 58115516c77SSepherosa Ziehau 58215516c77SSepherosa Ziehau for (i = 0; i < bmap_cnt; ++i) { 58315516c77SSepherosa Ziehau int idx; 58415516c77SSepherosa Ziehau 58515516c77SSepherosa Ziehau idx = ffsl(~bmap[i]); 58615516c77SSepherosa Ziehau if (idx == 0) 58715516c77SSepherosa Ziehau continue; 58815516c77SSepherosa Ziehau 58915516c77SSepherosa Ziehau --idx; /* ffsl is 1-based */ 59015516c77SSepherosa Ziehau KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt, 59115516c77SSepherosa Ziehau ("invalid i %d and idx %d", i, idx)); 59215516c77SSepherosa Ziehau 59315516c77SSepherosa Ziehau if (atomic_testandset_long(&bmap[i], idx)) 59415516c77SSepherosa Ziehau continue; 59515516c77SSepherosa Ziehau 59615516c77SSepherosa Ziehau ret = i * LONG_BIT + idx; 59715516c77SSepherosa Ziehau break; 59815516c77SSepherosa Ziehau } 59915516c77SSepherosa Ziehau return (ret); 60015516c77SSepherosa Ziehau } 60115516c77SSepherosa Ziehau 60215516c77SSepherosa Ziehau static __inline void 60315516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx) 60415516c77SSepherosa Ziehau { 60515516c77SSepherosa Ziehau u_long mask; 60615516c77SSepherosa Ziehau uint32_t idx; 60715516c77SSepherosa Ziehau 60815516c77SSepherosa Ziehau idx = chim_idx / LONG_BIT; 60915516c77SSepherosa Ziehau KASSERT(idx < sc->hn_chim_bmap_cnt, 61015516c77SSepherosa Ziehau ("invalid chimney index 0x%x", chim_idx)); 61115516c77SSepherosa Ziehau 61215516c77SSepherosa Ziehau mask = 1UL << (chim_idx % LONG_BIT); 61315516c77SSepherosa Ziehau KASSERT(sc->hn_chim_bmap[idx] & mask, 61415516c77SSepherosa Ziehau ("index bitmap 0x%lx, chimney index %u, " 61515516c77SSepherosa Ziehau "bitmap idx %d, bitmask 0x%lx", 61615516c77SSepherosa Ziehau sc->hn_chim_bmap[idx], chim_idx, idx, mask)); 61715516c77SSepherosa Ziehau 61815516c77SSepherosa Ziehau atomic_clear_long(&sc->hn_chim_bmap[idx], mask); 61915516c77SSepherosa Ziehau } 62015516c77SSepherosa Ziehau 621edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 622edd3f315SSepherosa Ziehau /* 623edd3f315SSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 624edd3f315SSepherosa Ziehau */ 625edd3f315SSepherosa Ziehau static __inline struct mbuf * 626edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head) 627edd3f315SSepherosa Ziehau { 628edd3f315SSepherosa Ziehau struct ether_vlan_header *evl; 629edd3f315SSepherosa Ziehau struct tcphdr *th; 630edd3f315SSepherosa Ziehau int ehlen; 631edd3f315SSepherosa Ziehau 632edd3f315SSepherosa Ziehau KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable")); 633edd3f315SSepherosa Ziehau 634edd3f315SSepherosa Ziehau #define PULLUP_HDR(m, len) \ 635edd3f315SSepherosa Ziehau do { \ 636edd3f315SSepherosa Ziehau if (__predict_false((m)->m_len < (len))) { \ 637edd3f315SSepherosa Ziehau (m) = m_pullup((m), (len)); \ 638edd3f315SSepherosa Ziehau if ((m) == NULL) \ 639edd3f315SSepherosa Ziehau return (NULL); \ 640edd3f315SSepherosa Ziehau } \ 641edd3f315SSepherosa Ziehau } while (0) 642edd3f315SSepherosa Ziehau 643edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, sizeof(*evl)); 644edd3f315SSepherosa Ziehau evl = mtod(m_head, struct ether_vlan_header *); 645edd3f315SSepherosa Ziehau if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) 646edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 647edd3f315SSepherosa Ziehau else 648edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN; 649edd3f315SSepherosa Ziehau 650edd3f315SSepherosa Ziehau #ifdef INET 651edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 652edd3f315SSepherosa Ziehau struct ip *ip; 653edd3f315SSepherosa Ziehau int iphlen; 654edd3f315SSepherosa Ziehau 655edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip)); 656edd3f315SSepherosa Ziehau ip = mtodo(m_head, ehlen); 657edd3f315SSepherosa Ziehau iphlen = ip->ip_hl << 2; 658edd3f315SSepherosa Ziehau 659edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 660edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 661edd3f315SSepherosa Ziehau 662edd3f315SSepherosa Ziehau ip->ip_len = 0; 663edd3f315SSepherosa Ziehau ip->ip_sum = 0; 664edd3f315SSepherosa Ziehau th->th_sum = in_pseudo(ip->ip_src.s_addr, 665edd3f315SSepherosa Ziehau ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 666edd3f315SSepherosa Ziehau } 667edd3f315SSepherosa Ziehau #endif 668edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET) 669edd3f315SSepherosa Ziehau else 670edd3f315SSepherosa Ziehau #endif 671edd3f315SSepherosa Ziehau #ifdef INET6 672edd3f315SSepherosa Ziehau { 673edd3f315SSepherosa Ziehau struct ip6_hdr *ip6; 674edd3f315SSepherosa Ziehau 675edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); 676edd3f315SSepherosa Ziehau ip6 = mtodo(m_head, ehlen); 677edd3f315SSepherosa Ziehau if (ip6->ip6_nxt != IPPROTO_TCP) { 678edd3f315SSepherosa Ziehau m_freem(m_head); 679edd3f315SSepherosa Ziehau return (NULL); 680edd3f315SSepherosa Ziehau } 681edd3f315SSepherosa Ziehau 682edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); 683edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + sizeof(*ip6)); 684edd3f315SSepherosa Ziehau 685edd3f315SSepherosa Ziehau ip6->ip6_plen = 0; 686edd3f315SSepherosa Ziehau th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 687edd3f315SSepherosa Ziehau } 688edd3f315SSepherosa Ziehau #endif 689edd3f315SSepherosa Ziehau return (m_head); 690edd3f315SSepherosa Ziehau 691edd3f315SSepherosa Ziehau #undef PULLUP_HDR 692edd3f315SSepherosa Ziehau } 693edd3f315SSepherosa Ziehau #endif /* INET6 || INET */ 694edd3f315SSepherosa Ziehau 69515516c77SSepherosa Ziehau static int 696f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter) 697f1b0a43fSSepherosa Ziehau { 698f1b0a43fSSepherosa Ziehau int error = 0; 699f1b0a43fSSepherosa Ziehau 700f1b0a43fSSepherosa Ziehau HN_LOCK_ASSERT(sc); 701f1b0a43fSSepherosa Ziehau 702f1b0a43fSSepherosa Ziehau if (sc->hn_rx_filter != filter) { 703f1b0a43fSSepherosa Ziehau error = hn_rndis_set_rxfilter(sc, filter); 704f1b0a43fSSepherosa Ziehau if (!error) 705f1b0a43fSSepherosa Ziehau sc->hn_rx_filter = filter; 706f1b0a43fSSepherosa Ziehau } 707f1b0a43fSSepherosa Ziehau return (error); 708f1b0a43fSSepherosa Ziehau } 709f1b0a43fSSepherosa Ziehau 710f1b0a43fSSepherosa Ziehau static int 711c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc) 71215516c77SSepherosa Ziehau { 71315516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 71415516c77SSepherosa Ziehau uint32_t filter; 71515516c77SSepherosa Ziehau 71615516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 71715516c77SSepherosa Ziehau 7185bdfd3fdSDexuan Cui if ((ifp->if_flags & IFF_PROMISC) || 7195bdfd3fdSDexuan Cui (sc->hn_flags & HN_FLAG_VF)) { 72015516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_PROMISCUOUS; 72115516c77SSepherosa Ziehau } else { 72215516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_DIRECTED; 72315516c77SSepherosa Ziehau if (ifp->if_flags & IFF_BROADCAST) 72415516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_BROADCAST; 72515516c77SSepherosa Ziehau /* TODO: support multicast list */ 72615516c77SSepherosa Ziehau if ((ifp->if_flags & IFF_ALLMULTI) || 72715516c77SSepherosa Ziehau !TAILQ_EMPTY(&ifp->if_multiaddrs)) 72815516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 72915516c77SSepherosa Ziehau } 730f1b0a43fSSepherosa Ziehau return (hn_set_rxfilter(sc, filter)); 73115516c77SSepherosa Ziehau } 73215516c77SSepherosa Ziehau 733dc13fee6SSepherosa Ziehau static void 734dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc) 735dc13fee6SSepherosa Ziehau { 736dc13fee6SSepherosa Ziehau uint32_t size, pkts; 737dc13fee6SSepherosa Ziehau int i; 738dc13fee6SSepherosa Ziehau 739dc13fee6SSepherosa Ziehau /* 740dc13fee6SSepherosa Ziehau * Setup aggregation size. 741dc13fee6SSepherosa Ziehau */ 742dc13fee6SSepherosa Ziehau if (sc->hn_agg_size < 0) 743dc13fee6SSepherosa Ziehau size = UINT32_MAX; 744dc13fee6SSepherosa Ziehau else 745dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 746dc13fee6SSepherosa Ziehau 747dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_size < size) 748dc13fee6SSepherosa Ziehau size = sc->hn_rndis_agg_size; 749dc13fee6SSepherosa Ziehau 750a4364cfeSSepherosa Ziehau /* NOTE: We only aggregate packets using chimney sending buffers. */ 751a4364cfeSSepherosa Ziehau if (size > (uint32_t)sc->hn_chim_szmax) 752a4364cfeSSepherosa Ziehau size = sc->hn_chim_szmax; 753a4364cfeSSepherosa Ziehau 754dc13fee6SSepherosa Ziehau if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) { 755dc13fee6SSepherosa Ziehau /* Disable */ 756dc13fee6SSepherosa Ziehau size = 0; 757dc13fee6SSepherosa Ziehau pkts = 0; 758dc13fee6SSepherosa Ziehau goto done; 759dc13fee6SSepherosa Ziehau } 760dc13fee6SSepherosa Ziehau 761dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'int'. */ 762dc13fee6SSepherosa Ziehau if (size > INT_MAX) 763dc13fee6SSepherosa Ziehau size = INT_MAX; 764dc13fee6SSepherosa Ziehau 765dc13fee6SSepherosa Ziehau /* 766dc13fee6SSepherosa Ziehau * Setup aggregation packet count. 767dc13fee6SSepherosa Ziehau */ 768dc13fee6SSepherosa Ziehau if (sc->hn_agg_pkts < 0) 769dc13fee6SSepherosa Ziehau pkts = UINT32_MAX; 770dc13fee6SSepherosa Ziehau else 771dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 772dc13fee6SSepherosa Ziehau 773dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_pkts < pkts) 774dc13fee6SSepherosa Ziehau pkts = sc->hn_rndis_agg_pkts; 775dc13fee6SSepherosa Ziehau 776dc13fee6SSepherosa Ziehau if (pkts <= 1) { 777dc13fee6SSepherosa Ziehau /* Disable */ 778dc13fee6SSepherosa Ziehau size = 0; 779dc13fee6SSepherosa Ziehau pkts = 0; 780dc13fee6SSepherosa Ziehau goto done; 781dc13fee6SSepherosa Ziehau } 782dc13fee6SSepherosa Ziehau 783dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 784dc13fee6SSepherosa Ziehau if (pkts > SHRT_MAX) 785dc13fee6SSepherosa Ziehau pkts = SHRT_MAX; 786dc13fee6SSepherosa Ziehau 787dc13fee6SSepherosa Ziehau done: 788dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 789dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_align > SHRT_MAX) { 790dc13fee6SSepherosa Ziehau /* Disable */ 791dc13fee6SSepherosa Ziehau size = 0; 792dc13fee6SSepherosa Ziehau pkts = 0; 793dc13fee6SSepherosa Ziehau } 794dc13fee6SSepherosa Ziehau 795dc13fee6SSepherosa Ziehau if (bootverbose) { 796dc13fee6SSepherosa Ziehau if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n", 797dc13fee6SSepherosa Ziehau size, pkts, sc->hn_rndis_agg_align); 798dc13fee6SSepherosa Ziehau } 799dc13fee6SSepherosa Ziehau 800dc13fee6SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 801dc13fee6SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 802dc13fee6SSepherosa Ziehau 803dc13fee6SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 804dc13fee6SSepherosa Ziehau txr->hn_agg_szmax = size; 805dc13fee6SSepherosa Ziehau txr->hn_agg_pktmax = pkts; 806dc13fee6SSepherosa Ziehau txr->hn_agg_align = sc->hn_rndis_agg_align; 807dc13fee6SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 808dc13fee6SSepherosa Ziehau } 809dc13fee6SSepherosa Ziehau } 810dc13fee6SSepherosa Ziehau 81115516c77SSepherosa Ziehau static int 81215516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr) 81315516c77SSepherosa Ziehau { 81415516c77SSepherosa Ziehau 81515516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet")); 81615516c77SSepherosa Ziehau if (hn_tx_swq_depth < txr->hn_txdesc_cnt) 81715516c77SSepherosa Ziehau return txr->hn_txdesc_cnt; 81815516c77SSepherosa Ziehau return hn_tx_swq_depth; 81915516c77SSepherosa Ziehau } 82015516c77SSepherosa Ziehau 82134d68912SSepherosa Ziehau #ifndef RSS 82215516c77SSepherosa Ziehau static int 82315516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc) 82415516c77SSepherosa Ziehau { 82515516c77SSepherosa Ziehau int error; 82615516c77SSepherosa Ziehau 82715516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 82815516c77SSepherosa Ziehau 82915516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 83015516c77SSepherosa Ziehau return (ENXIO); 83115516c77SSepherosa Ziehau 83215516c77SSepherosa Ziehau /* 83315516c77SSepherosa Ziehau * Disable RSS first. 83415516c77SSepherosa Ziehau * 83515516c77SSepherosa Ziehau * NOTE: 83615516c77SSepherosa Ziehau * Direct reconfiguration by setting the UNCHG flags does 83715516c77SSepherosa Ziehau * _not_ work properly. 83815516c77SSepherosa Ziehau */ 83915516c77SSepherosa Ziehau if (bootverbose) 84015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "disable RSS\n"); 84115516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE); 84215516c77SSepherosa Ziehau if (error) { 84315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS disable failed\n"); 84415516c77SSepherosa Ziehau return (error); 84515516c77SSepherosa Ziehau } 84615516c77SSepherosa Ziehau 84715516c77SSepherosa Ziehau /* 84815516c77SSepherosa Ziehau * Reenable the RSS w/ the updated RSS key or indirect 84915516c77SSepherosa Ziehau * table. 85015516c77SSepherosa Ziehau */ 85115516c77SSepherosa Ziehau if (bootverbose) 85215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "reconfig RSS\n"); 85315516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 85415516c77SSepherosa Ziehau if (error) { 85515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS reconfig failed\n"); 85615516c77SSepherosa Ziehau return (error); 85715516c77SSepherosa Ziehau } 85815516c77SSepherosa Ziehau return (0); 85915516c77SSepherosa Ziehau } 86034d68912SSepherosa Ziehau #endif /* !RSS */ 86115516c77SSepherosa Ziehau 86215516c77SSepherosa Ziehau static void 863afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc) 86415516c77SSepherosa Ziehau { 86515516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 866afd4971bSSepherosa Ziehau int i, nchan; 86715516c77SSepherosa Ziehau 868afd4971bSSepherosa Ziehau nchan = sc->hn_rx_ring_inuse; 86915516c77SSepherosa Ziehau KASSERT(nchan > 1, ("invalid # of channels %d", nchan)); 87015516c77SSepherosa Ziehau 87115516c77SSepherosa Ziehau /* 87215516c77SSepherosa Ziehau * Check indirect table to make sure that all channels in it 87315516c77SSepherosa Ziehau * can be used. 87415516c77SSepherosa Ziehau */ 87515516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 87615516c77SSepherosa Ziehau if (rss->rss_ind[i] >= nchan) { 87715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, 87815516c77SSepherosa Ziehau "RSS indirect table %d fixup: %u -> %d\n", 87915516c77SSepherosa Ziehau i, rss->rss_ind[i], nchan - 1); 88015516c77SSepherosa Ziehau rss->rss_ind[i] = nchan - 1; 88115516c77SSepherosa Ziehau } 88215516c77SSepherosa Ziehau } 88315516c77SSepherosa Ziehau } 88415516c77SSepherosa Ziehau 88515516c77SSepherosa Ziehau static int 88615516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused) 88715516c77SSepherosa Ziehau { 88815516c77SSepherosa Ziehau 88915516c77SSepherosa Ziehau return EOPNOTSUPP; 89015516c77SSepherosa Ziehau } 89115516c77SSepherosa Ziehau 89215516c77SSepherosa Ziehau static void 89315516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 89415516c77SSepherosa Ziehau { 89515516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 89615516c77SSepherosa Ziehau 89715516c77SSepherosa Ziehau ifmr->ifm_status = IFM_AVALID; 89815516c77SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 89915516c77SSepherosa Ziehau 90015516c77SSepherosa Ziehau if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) { 90115516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_NONE; 90215516c77SSepherosa Ziehau return; 90315516c77SSepherosa Ziehau } 90415516c77SSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 90515516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 90615516c77SSepherosa Ziehau } 90715516c77SSepherosa Ziehau 9085bdfd3fdSDexuan Cui static void 9095bdfd3fdSDexuan Cui hn_update_vf_task(void *arg, int pending __unused) 9105bdfd3fdSDexuan Cui { 9115bdfd3fdSDexuan Cui struct hn_update_vf *uv = arg; 9125bdfd3fdSDexuan Cui 9135bdfd3fdSDexuan Cui uv->rxr->hn_vf = uv->vf; 9145bdfd3fdSDexuan Cui } 9155bdfd3fdSDexuan Cui 9165bdfd3fdSDexuan Cui static void 9175bdfd3fdSDexuan Cui hn_update_vf(struct hn_softc *sc, struct ifnet *vf) 9185bdfd3fdSDexuan Cui { 9195bdfd3fdSDexuan Cui struct hn_rx_ring *rxr; 9205bdfd3fdSDexuan Cui struct hn_update_vf uv; 9215bdfd3fdSDexuan Cui struct task task; 9225bdfd3fdSDexuan Cui int i; 9235bdfd3fdSDexuan Cui 9245bdfd3fdSDexuan Cui HN_LOCK_ASSERT(sc); 9255bdfd3fdSDexuan Cui 9265bdfd3fdSDexuan Cui TASK_INIT(&task, 0, hn_update_vf_task, &uv); 9275bdfd3fdSDexuan Cui 9285bdfd3fdSDexuan Cui for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 9295bdfd3fdSDexuan Cui rxr = &sc->hn_rx_ring[i]; 9305bdfd3fdSDexuan Cui 9315bdfd3fdSDexuan Cui if (i < sc->hn_rx_ring_inuse) { 9325bdfd3fdSDexuan Cui uv.rxr = rxr; 9335bdfd3fdSDexuan Cui uv.vf = vf; 9345bdfd3fdSDexuan Cui vmbus_chan_run_task(rxr->hn_chan, &task); 9355bdfd3fdSDexuan Cui } else { 9365bdfd3fdSDexuan Cui rxr->hn_vf = vf; 9375bdfd3fdSDexuan Cui } 9385bdfd3fdSDexuan Cui } 9395bdfd3fdSDexuan Cui } 9405bdfd3fdSDexuan Cui 9415bdfd3fdSDexuan Cui static void 9425bdfd3fdSDexuan Cui hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf) 9435bdfd3fdSDexuan Cui { 9445bdfd3fdSDexuan Cui struct ifnet *hn_ifp; 9455bdfd3fdSDexuan Cui 9465bdfd3fdSDexuan Cui HN_LOCK(sc); 9475bdfd3fdSDexuan Cui 9485bdfd3fdSDexuan Cui if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 9495bdfd3fdSDexuan Cui goto out; 9505bdfd3fdSDexuan Cui 9515bdfd3fdSDexuan Cui hn_ifp = sc->hn_ifp; 9525bdfd3fdSDexuan Cui 9535bdfd3fdSDexuan Cui if (ifp == hn_ifp) 9545bdfd3fdSDexuan Cui goto out; 9555bdfd3fdSDexuan Cui 9565bdfd3fdSDexuan Cui if (ifp->if_alloctype != IFT_ETHER) 9575bdfd3fdSDexuan Cui goto out; 9585bdfd3fdSDexuan Cui 9595bdfd3fdSDexuan Cui /* Ignore lagg/vlan interfaces */ 9605bdfd3fdSDexuan Cui if (strcmp(ifp->if_dname, "lagg") == 0 || 9615bdfd3fdSDexuan Cui strcmp(ifp->if_dname, "vlan") == 0) 9625bdfd3fdSDexuan Cui goto out; 9635bdfd3fdSDexuan Cui 9645bdfd3fdSDexuan Cui if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0) 9655bdfd3fdSDexuan Cui goto out; 9665bdfd3fdSDexuan Cui 9675bdfd3fdSDexuan Cui /* Now we're sure 'ifp' is a real VF device. */ 9685bdfd3fdSDexuan Cui if (vf) { 9695bdfd3fdSDexuan Cui if (sc->hn_flags & HN_FLAG_VF) 9705bdfd3fdSDexuan Cui goto out; 9715bdfd3fdSDexuan Cui 9725bdfd3fdSDexuan Cui sc->hn_flags |= HN_FLAG_VF; 9735bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 9745bdfd3fdSDexuan Cui } else { 9755bdfd3fdSDexuan Cui if (!(sc->hn_flags & HN_FLAG_VF)) 9765bdfd3fdSDexuan Cui goto out; 9775bdfd3fdSDexuan Cui 9785bdfd3fdSDexuan Cui sc->hn_flags &= ~HN_FLAG_VF; 9795bdfd3fdSDexuan Cui if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 9805bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 9815bdfd3fdSDexuan Cui else 9825bdfd3fdSDexuan Cui hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE); 9835bdfd3fdSDexuan Cui } 9845bdfd3fdSDexuan Cui 9855bdfd3fdSDexuan Cui hn_nvs_set_datapath(sc, 9865bdfd3fdSDexuan Cui vf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTHETIC); 9875bdfd3fdSDexuan Cui 9885bdfd3fdSDexuan Cui hn_update_vf(sc, vf ? ifp : NULL); 9895bdfd3fdSDexuan Cui 9905bdfd3fdSDexuan Cui if (vf) { 9915bdfd3fdSDexuan Cui hn_suspend_mgmt(sc); 9925bdfd3fdSDexuan Cui sc->hn_link_flags &= 9935bdfd3fdSDexuan Cui ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG); 9945bdfd3fdSDexuan Cui if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); 9955bdfd3fdSDexuan Cui } else { 9965bdfd3fdSDexuan Cui hn_resume_mgmt(sc); 9975bdfd3fdSDexuan Cui } 9985bdfd3fdSDexuan Cui 99933408a34SDexuan Cui devctl_notify("HYPERV_NIC_VF", if_name(hn_ifp), 100033408a34SDexuan Cui vf ? "VF_UP" : "VF_DOWN", NULL); 100133408a34SDexuan Cui 10025bdfd3fdSDexuan Cui if (bootverbose) 10035bdfd3fdSDexuan Cui if_printf(hn_ifp, "Data path is switched %s %s\n", 10045bdfd3fdSDexuan Cui vf ? "to" : "from", if_name(ifp)); 10055bdfd3fdSDexuan Cui out: 10065bdfd3fdSDexuan Cui HN_UNLOCK(sc); 10075bdfd3fdSDexuan Cui } 10085bdfd3fdSDexuan Cui 10095bdfd3fdSDexuan Cui static void 10105bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event) 10115bdfd3fdSDexuan Cui { 10125bdfd3fdSDexuan Cui if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN) 10135bdfd3fdSDexuan Cui return; 10145bdfd3fdSDexuan Cui 10155bdfd3fdSDexuan Cui hn_set_vf(arg, ifp, event == IFNET_EVENT_UP); 10165bdfd3fdSDexuan Cui } 10175bdfd3fdSDexuan Cui 10185bdfd3fdSDexuan Cui static void 10195bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp) 10205bdfd3fdSDexuan Cui { 10215bdfd3fdSDexuan Cui hn_set_vf(arg, ifp, ifp->if_flags & IFF_UP); 10225bdfd3fdSDexuan Cui } 10235bdfd3fdSDexuan Cui 102415516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ 102515516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = { 102615516c77SSepherosa Ziehau .hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 102715516c77SSepherosa Ziehau 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E} 102815516c77SSepherosa Ziehau }; 102915516c77SSepherosa Ziehau 103015516c77SSepherosa Ziehau static int 103115516c77SSepherosa Ziehau hn_probe(device_t dev) 103215516c77SSepherosa Ziehau { 103315516c77SSepherosa Ziehau 103415516c77SSepherosa Ziehau if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, 103515516c77SSepherosa Ziehau &g_net_vsc_device_type) == 0) { 103615516c77SSepherosa Ziehau device_set_desc(dev, "Hyper-V Network Interface"); 103715516c77SSepherosa Ziehau return BUS_PROBE_DEFAULT; 103815516c77SSepherosa Ziehau } 103915516c77SSepherosa Ziehau return ENXIO; 104015516c77SSepherosa Ziehau } 104115516c77SSepherosa Ziehau 104215516c77SSepherosa Ziehau static int 104315516c77SSepherosa Ziehau hn_attach(device_t dev) 104415516c77SSepherosa Ziehau { 104515516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 104615516c77SSepherosa Ziehau struct sysctl_oid_list *child; 104715516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 104815516c77SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 104915516c77SSepherosa Ziehau struct ifnet *ifp = NULL; 105015516c77SSepherosa Ziehau int error, ring_cnt, tx_ring_cnt; 105115516c77SSepherosa Ziehau 105215516c77SSepherosa Ziehau sc->hn_dev = dev; 105315516c77SSepherosa Ziehau sc->hn_prichan = vmbus_get_channel(dev); 105415516c77SSepherosa Ziehau HN_LOCK_INIT(sc); 105515516c77SSepherosa Ziehau 105615516c77SSepherosa Ziehau /* 1057dc13fee6SSepherosa Ziehau * Initialize these tunables once. 1058dc13fee6SSepherosa Ziehau */ 1059dc13fee6SSepherosa Ziehau sc->hn_agg_size = hn_tx_agg_size; 1060dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = hn_tx_agg_pkts; 1061dc13fee6SSepherosa Ziehau 1062dc13fee6SSepherosa Ziehau /* 106315516c77SSepherosa Ziehau * Setup taskqueue for transmission. 106415516c77SSepherosa Ziehau */ 10650e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) { 1066fdd0222aSSepherosa Ziehau int i; 1067fdd0222aSSepherosa Ziehau 1068fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = 1069fdd0222aSSepherosa Ziehau malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 1070fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 1071fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 1072fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx", 1073fdd0222aSSepherosa Ziehau M_WAITOK, taskqueue_thread_enqueue, 1074fdd0222aSSepherosa Ziehau &sc->hn_tx_taskqs[i]); 1075fdd0222aSSepherosa Ziehau taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET, 1076fdd0222aSSepherosa Ziehau "%s tx%d", device_get_nameunit(dev), i); 1077fdd0222aSSepherosa Ziehau } 10780e11868dSSepherosa Ziehau } else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) { 1079fdd0222aSSepherosa Ziehau sc->hn_tx_taskqs = hn_tx_taskque; 108015516c77SSepherosa Ziehau } 108115516c77SSepherosa Ziehau 108215516c77SSepherosa Ziehau /* 108315516c77SSepherosa Ziehau * Setup taskqueue for mangement tasks, e.g. link status. 108415516c77SSepherosa Ziehau */ 108515516c77SSepherosa Ziehau sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK, 108615516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0); 108715516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt", 108815516c77SSepherosa Ziehau device_get_nameunit(dev)); 108915516c77SSepherosa Ziehau TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc); 109015516c77SSepherosa Ziehau TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc); 109115516c77SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0, 109215516c77SSepherosa Ziehau hn_netchg_status_taskfunc, sc); 109315516c77SSepherosa Ziehau 109415516c77SSepherosa Ziehau /* 109515516c77SSepherosa Ziehau * Allocate ifnet and setup its name earlier, so that if_printf 109615516c77SSepherosa Ziehau * can be used by functions, which will be called after 109715516c77SSepherosa Ziehau * ether_ifattach(). 109815516c77SSepherosa Ziehau */ 109915516c77SSepherosa Ziehau ifp = sc->hn_ifp = if_alloc(IFT_ETHER); 110015516c77SSepherosa Ziehau ifp->if_softc = sc; 110115516c77SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 110215516c77SSepherosa Ziehau 110315516c77SSepherosa Ziehau /* 110415516c77SSepherosa Ziehau * Initialize ifmedia earlier so that it can be unconditionally 110515516c77SSepherosa Ziehau * destroyed, if error happened later on. 110615516c77SSepherosa Ziehau */ 110715516c77SSepherosa Ziehau ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts); 110815516c77SSepherosa Ziehau 110915516c77SSepherosa Ziehau /* 111015516c77SSepherosa Ziehau * Figure out the # of RX rings (ring_cnt) and the # of TX rings 111115516c77SSepherosa Ziehau * to use (tx_ring_cnt). 111215516c77SSepherosa Ziehau * 111315516c77SSepherosa Ziehau * NOTE: 111415516c77SSepherosa Ziehau * The # of RX rings to use is same as the # of channels to use. 111515516c77SSepherosa Ziehau */ 111615516c77SSepherosa Ziehau ring_cnt = hn_chan_cnt; 111715516c77SSepherosa Ziehau if (ring_cnt <= 0) { 111815516c77SSepherosa Ziehau /* Default */ 111915516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 112015516c77SSepherosa Ziehau if (ring_cnt > HN_RING_CNT_DEF_MAX) 112115516c77SSepherosa Ziehau ring_cnt = HN_RING_CNT_DEF_MAX; 112215516c77SSepherosa Ziehau } else if (ring_cnt > mp_ncpus) { 112315516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 112415516c77SSepherosa Ziehau } 112534d68912SSepherosa Ziehau #ifdef RSS 112634d68912SSepherosa Ziehau if (ring_cnt > rss_getnumbuckets()) 112734d68912SSepherosa Ziehau ring_cnt = rss_getnumbuckets(); 112834d68912SSepherosa Ziehau #endif 112915516c77SSepherosa Ziehau 113015516c77SSepherosa Ziehau tx_ring_cnt = hn_tx_ring_cnt; 113115516c77SSepherosa Ziehau if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt) 113215516c77SSepherosa Ziehau tx_ring_cnt = ring_cnt; 113323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 113415516c77SSepherosa Ziehau if (hn_use_if_start) { 113515516c77SSepherosa Ziehau /* ifnet.if_start only needs one TX ring. */ 113615516c77SSepherosa Ziehau tx_ring_cnt = 1; 113715516c77SSepherosa Ziehau } 113823bf9e15SSepherosa Ziehau #endif 113915516c77SSepherosa Ziehau 114015516c77SSepherosa Ziehau /* 114115516c77SSepherosa Ziehau * Set the leader CPU for channels. 114215516c77SSepherosa Ziehau */ 114315516c77SSepherosa Ziehau sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus; 114415516c77SSepherosa Ziehau 114515516c77SSepherosa Ziehau /* 114615516c77SSepherosa Ziehau * Create enough TX/RX rings, even if only limited number of 114715516c77SSepherosa Ziehau * channels can be allocated. 114815516c77SSepherosa Ziehau */ 114915516c77SSepherosa Ziehau error = hn_create_tx_data(sc, tx_ring_cnt); 115015516c77SSepherosa Ziehau if (error) 115115516c77SSepherosa Ziehau goto failed; 115215516c77SSepherosa Ziehau error = hn_create_rx_data(sc, ring_cnt); 115315516c77SSepherosa Ziehau if (error) 115415516c77SSepherosa Ziehau goto failed; 115515516c77SSepherosa Ziehau 115615516c77SSepherosa Ziehau /* 115715516c77SSepherosa Ziehau * Create transaction context for NVS and RNDIS transactions. 115815516c77SSepherosa Ziehau */ 115915516c77SSepherosa Ziehau sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev), 116015516c77SSepherosa Ziehau HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0); 116125641fc7SSepherosa Ziehau if (sc->hn_xact == NULL) { 116225641fc7SSepherosa Ziehau error = ENXIO; 116315516c77SSepherosa Ziehau goto failed; 116425641fc7SSepherosa Ziehau } 116525641fc7SSepherosa Ziehau 116625641fc7SSepherosa Ziehau /* 116725641fc7SSepherosa Ziehau * Install orphan handler for the revocation of this device's 116825641fc7SSepherosa Ziehau * primary channel. 116925641fc7SSepherosa Ziehau * 117025641fc7SSepherosa Ziehau * NOTE: 117125641fc7SSepherosa Ziehau * The processing order is critical here: 117225641fc7SSepherosa Ziehau * Install the orphan handler, _before_ testing whether this 117325641fc7SSepherosa Ziehau * device's primary channel has been revoked or not. 117425641fc7SSepherosa Ziehau */ 117525641fc7SSepherosa Ziehau vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact); 117625641fc7SSepherosa Ziehau if (vmbus_chan_is_revoked(sc->hn_prichan)) { 117725641fc7SSepherosa Ziehau error = ENXIO; 117825641fc7SSepherosa Ziehau goto failed; 117925641fc7SSepherosa Ziehau } 118015516c77SSepherosa Ziehau 118115516c77SSepherosa Ziehau /* 118215516c77SSepherosa Ziehau * Attach the synthetic parts, i.e. NVS and RNDIS. 118315516c77SSepherosa Ziehau */ 118415516c77SSepherosa Ziehau error = hn_synth_attach(sc, ETHERMTU); 118515516c77SSepherosa Ziehau if (error) 118615516c77SSepherosa Ziehau goto failed; 118715516c77SSepherosa Ziehau 118815516c77SSepherosa Ziehau error = hn_rndis_get_eaddr(sc, eaddr); 118915516c77SSepherosa Ziehau if (error) 119015516c77SSepherosa Ziehau goto failed; 119115516c77SSepherosa Ziehau 119215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 119315516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 119415516c77SSepherosa Ziehau /* 119515516c77SSepherosa Ziehau * Reduce TCP segment aggregation limit for multiple 119615516c77SSepherosa Ziehau * RX rings to increase ACK timeliness. 119715516c77SSepherosa Ziehau */ 119815516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF); 119915516c77SSepherosa Ziehau } 120015516c77SSepherosa Ziehau #endif 120115516c77SSepherosa Ziehau 120215516c77SSepherosa Ziehau /* 120315516c77SSepherosa Ziehau * Fixup TX stuffs after synthetic parts are attached. 120415516c77SSepherosa Ziehau */ 120515516c77SSepherosa Ziehau hn_fixup_tx_data(sc); 120615516c77SSepherosa Ziehau 120715516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 120815516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 120915516c77SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD, 121015516c77SSepherosa Ziehau &sc->hn_nvs_ver, 0, "NVS version"); 121115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version", 121215516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 121315516c77SSepherosa Ziehau hn_ndis_version_sysctl, "A", "NDIS version"); 121415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps", 121515516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 121615516c77SSepherosa Ziehau hn_caps_sysctl, "A", "capabilities"); 121715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist", 121815516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 121915516c77SSepherosa Ziehau hn_hwassist_sysctl, "A", "hwassist"); 122015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter", 122115516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 122215516c77SSepherosa Ziehau hn_rxfilter_sysctl, "A", "rxfilter"); 122315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash", 122415516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 122515516c77SSepherosa Ziehau hn_rss_hash_sysctl, "A", "RSS hash"); 122615516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size", 122715516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count"); 122834d68912SSepherosa Ziehau #ifndef RSS 122934d68912SSepherosa Ziehau /* 123034d68912SSepherosa Ziehau * Don't allow RSS key/indirect table changes, if RSS is defined. 123134d68912SSepherosa Ziehau */ 123215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key", 123315516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 123415516c77SSepherosa Ziehau hn_rss_key_sysctl, "IU", "RSS key"); 123515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind", 123615516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 123715516c77SSepherosa Ziehau hn_rss_ind_sysctl, "IU", "RSS indirect table"); 123834d68912SSepherosa Ziehau #endif 1239dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size", 1240dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_size, 0, 1241dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation size limit"); 1242dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts", 1243dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0, 1244dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation count limit"); 1245dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align", 1246dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_align, 0, 1247dc13fee6SSepherosa Ziehau "RNDIS packet transmission aggregation alignment"); 1248dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size", 1249dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 1250dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl, "I", 1251dc13fee6SSepherosa Ziehau "Packet transmission aggregation size, 0 -- disable, -1 -- auto"); 1252dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts", 1253dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 1254dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl, "I", 1255dc13fee6SSepherosa Ziehau "Packet transmission aggregation packets, " 1256dc13fee6SSepherosa Ziehau "0 -- disable, -1 -- auto"); 12576c1204dfSSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling", 12586c1204dfSSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 12596c1204dfSSepherosa Ziehau hn_polling_sysctl, "I", 12606c1204dfSSepherosa Ziehau "Polling frequency: [100,1000000], 0 disable polling"); 126140d60d6eSDexuan Cui SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf", 126240d60d6eSDexuan Cui CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 126340d60d6eSDexuan Cui hn_vf_sysctl, "A", "Virtual Function's name"); 126415516c77SSepherosa Ziehau 126515516c77SSepherosa Ziehau /* 126615516c77SSepherosa Ziehau * Setup the ifmedia, which has been initialized earlier. 126715516c77SSepherosa Ziehau */ 126815516c77SSepherosa Ziehau ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL); 126915516c77SSepherosa Ziehau ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO); 127015516c77SSepherosa Ziehau /* XXX ifmedia_set really should do this for us */ 127115516c77SSepherosa Ziehau sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media; 127215516c77SSepherosa Ziehau 127315516c77SSepherosa Ziehau /* 127415516c77SSepherosa Ziehau * Setup the ifnet for this interface. 127515516c77SSepherosa Ziehau */ 127615516c77SSepherosa Ziehau 127715516c77SSepherosa Ziehau ifp->if_baudrate = IF_Gbps(10); 127815516c77SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 127915516c77SSepherosa Ziehau ifp->if_ioctl = hn_ioctl; 128015516c77SSepherosa Ziehau ifp->if_init = hn_init; 128123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 128215516c77SSepherosa Ziehau if (hn_use_if_start) { 128315516c77SSepherosa Ziehau int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]); 128415516c77SSepherosa Ziehau 128515516c77SSepherosa Ziehau ifp->if_start = hn_start; 128615516c77SSepherosa Ziehau IFQ_SET_MAXLEN(&ifp->if_snd, qdepth); 128715516c77SSepherosa Ziehau ifp->if_snd.ifq_drv_maxlen = qdepth - 1; 128815516c77SSepherosa Ziehau IFQ_SET_READY(&ifp->if_snd); 128923bf9e15SSepherosa Ziehau } else 129023bf9e15SSepherosa Ziehau #endif 129123bf9e15SSepherosa Ziehau { 129215516c77SSepherosa Ziehau ifp->if_transmit = hn_transmit; 129315516c77SSepherosa Ziehau ifp->if_qflush = hn_xmit_qflush; 129415516c77SSepherosa Ziehau } 129515516c77SSepherosa Ziehau 129615516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO; 129715516c77SSepherosa Ziehau #ifdef foo 129815516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 129915516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM_IPV6; 130015516c77SSepherosa Ziehau #endif 130115516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_VLAN) { 130215516c77SSepherosa Ziehau /* XXX not sure about VLAN_MTU. */ 130315516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 130415516c77SSepherosa Ziehau } 130515516c77SSepherosa Ziehau 130615516c77SSepherosa Ziehau ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist; 130715516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP_MASK) 130815516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM; 130915516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP6_MASK) 131015516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM_IPV6; 131115516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO4) { 131215516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO4; 131315516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 131415516c77SSepherosa Ziehau } 131515516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO6) { 131615516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO6; 131715516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 131815516c77SSepherosa Ziehau } 131915516c77SSepherosa Ziehau 132015516c77SSepherosa Ziehau /* Enable all available capabilities by default. */ 132115516c77SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 132215516c77SSepherosa Ziehau 13237960e6baSSepherosa Ziehau /* 13247960e6baSSepherosa Ziehau * Disable IPv6 TSO and TXCSUM by default, they still can 13257960e6baSSepherosa Ziehau * be enabled through SIOCSIFCAP. 13267960e6baSSepherosa Ziehau */ 13277960e6baSSepherosa Ziehau ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 13287960e6baSSepherosa Ziehau ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO); 13297960e6baSSepherosa Ziehau 133015516c77SSepherosa Ziehau if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) { 133115516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU); 133215516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; 133315516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 133415516c77SSepherosa Ziehau } 133515516c77SSepherosa Ziehau 133615516c77SSepherosa Ziehau ether_ifattach(ifp, eaddr); 133715516c77SSepherosa Ziehau 133815516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) { 133915516c77SSepherosa Ziehau if_printf(ifp, "TSO segcnt %u segsz %u\n", 134015516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize); 134115516c77SSepherosa Ziehau } 134215516c77SSepherosa Ziehau 134315516c77SSepherosa Ziehau /* Inform the upper layer about the long frame support. */ 134415516c77SSepherosa Ziehau ifp->if_hdrlen = sizeof(struct ether_vlan_header); 134515516c77SSepherosa Ziehau 134615516c77SSepherosa Ziehau /* 134715516c77SSepherosa Ziehau * Kick off link status check. 134815516c77SSepherosa Ziehau */ 134915516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 135015516c77SSepherosa Ziehau hn_update_link_status(sc); 135115516c77SSepherosa Ziehau 13525bdfd3fdSDexuan Cui sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event, 13535bdfd3fdSDexuan Cui hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY); 13545bdfd3fdSDexuan Cui 13555bdfd3fdSDexuan Cui sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event, 13565bdfd3fdSDexuan Cui hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY); 13575bdfd3fdSDexuan Cui 135815516c77SSepherosa Ziehau return (0); 135915516c77SSepherosa Ziehau failed: 136015516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) 136115516c77SSepherosa Ziehau hn_synth_detach(sc); 136215516c77SSepherosa Ziehau hn_detach(dev); 136315516c77SSepherosa Ziehau return (error); 136415516c77SSepherosa Ziehau } 136515516c77SSepherosa Ziehau 136615516c77SSepherosa Ziehau static int 136715516c77SSepherosa Ziehau hn_detach(device_t dev) 136815516c77SSepherosa Ziehau { 136915516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 137015516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 137115516c77SSepherosa Ziehau 13725bdfd3fdSDexuan Cui if (sc->hn_ifaddr_evthand != NULL) 13735bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand); 13745bdfd3fdSDexuan Cui if (sc->hn_ifnet_evthand != NULL) 13755bdfd3fdSDexuan Cui EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand); 13765bdfd3fdSDexuan Cui 137725641fc7SSepherosa Ziehau if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) { 137825641fc7SSepherosa Ziehau /* 137925641fc7SSepherosa Ziehau * In case that the vmbus missed the orphan handler 138025641fc7SSepherosa Ziehau * installation. 138125641fc7SSepherosa Ziehau */ 138225641fc7SSepherosa Ziehau vmbus_xact_ctx_orphan(sc->hn_xact); 138325641fc7SSepherosa Ziehau } 138425641fc7SSepherosa Ziehau 138515516c77SSepherosa Ziehau if (device_is_attached(dev)) { 138615516c77SSepherosa Ziehau HN_LOCK(sc); 138715516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 138815516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 13895bdfd3fdSDexuan Cui hn_stop(sc, true); 139015516c77SSepherosa Ziehau /* 139115516c77SSepherosa Ziehau * NOTE: 139215516c77SSepherosa Ziehau * hn_stop() only suspends data, so managment 139315516c77SSepherosa Ziehau * stuffs have to be suspended manually here. 139415516c77SSepherosa Ziehau */ 139515516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 139615516c77SSepherosa Ziehau hn_synth_detach(sc); 139715516c77SSepherosa Ziehau } 139815516c77SSepherosa Ziehau HN_UNLOCK(sc); 139915516c77SSepherosa Ziehau ether_ifdetach(ifp); 140015516c77SSepherosa Ziehau } 140115516c77SSepherosa Ziehau 140215516c77SSepherosa Ziehau ifmedia_removeall(&sc->hn_media); 140315516c77SSepherosa Ziehau hn_destroy_rx_data(sc); 140415516c77SSepherosa Ziehau hn_destroy_tx_data(sc); 140515516c77SSepherosa Ziehau 14060e11868dSSepherosa Ziehau if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) { 1407fdd0222aSSepherosa Ziehau int i; 1408fdd0222aSSepherosa Ziehau 1409fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 1410fdd0222aSSepherosa Ziehau taskqueue_free(sc->hn_tx_taskqs[i]); 1411fdd0222aSSepherosa Ziehau free(sc->hn_tx_taskqs, M_DEVBUF); 1412fdd0222aSSepherosa Ziehau } 141315516c77SSepherosa Ziehau taskqueue_free(sc->hn_mgmt_taskq0); 141415516c77SSepherosa Ziehau 141525641fc7SSepherosa Ziehau if (sc->hn_xact != NULL) { 141625641fc7SSepherosa Ziehau /* 141725641fc7SSepherosa Ziehau * Uninstall the orphan handler _before_ the xact is 141825641fc7SSepherosa Ziehau * destructed. 141925641fc7SSepherosa Ziehau */ 142025641fc7SSepherosa Ziehau vmbus_chan_unset_orphan(sc->hn_prichan); 142115516c77SSepherosa Ziehau vmbus_xact_ctx_destroy(sc->hn_xact); 142225641fc7SSepherosa Ziehau } 142315516c77SSepherosa Ziehau 142415516c77SSepherosa Ziehau if_free(ifp); 142515516c77SSepherosa Ziehau 142615516c77SSepherosa Ziehau HN_LOCK_DESTROY(sc); 142715516c77SSepherosa Ziehau return (0); 142815516c77SSepherosa Ziehau } 142915516c77SSepherosa Ziehau 143015516c77SSepherosa Ziehau static int 143115516c77SSepherosa Ziehau hn_shutdown(device_t dev) 143215516c77SSepherosa Ziehau { 143315516c77SSepherosa Ziehau 143415516c77SSepherosa Ziehau return (0); 143515516c77SSepherosa Ziehau } 143615516c77SSepherosa Ziehau 143715516c77SSepherosa Ziehau static void 143815516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc) 143915516c77SSepherosa Ziehau { 144015516c77SSepherosa Ziehau uint32_t link_status; 144115516c77SSepherosa Ziehau int error; 144215516c77SSepherosa Ziehau 144315516c77SSepherosa Ziehau error = hn_rndis_get_linkstatus(sc, &link_status); 144415516c77SSepherosa Ziehau if (error) { 144515516c77SSepherosa Ziehau /* XXX what to do? */ 144615516c77SSepherosa Ziehau return; 144715516c77SSepherosa Ziehau } 144815516c77SSepherosa Ziehau 144915516c77SSepherosa Ziehau if (link_status == NDIS_MEDIA_STATE_CONNECTED) 145015516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_LINKUP; 145115516c77SSepherosa Ziehau else 145215516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 145315516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, 145415516c77SSepherosa Ziehau (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ? 145515516c77SSepherosa Ziehau LINK_STATE_UP : LINK_STATE_DOWN); 145615516c77SSepherosa Ziehau } 145715516c77SSepherosa Ziehau 145815516c77SSepherosa Ziehau static void 145915516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused) 146015516c77SSepherosa Ziehau { 146115516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 146215516c77SSepherosa Ziehau 146315516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 146415516c77SSepherosa Ziehau return; 146515516c77SSepherosa Ziehau hn_link_status(sc); 146615516c77SSepherosa Ziehau } 146715516c77SSepherosa Ziehau 146815516c77SSepherosa Ziehau static void 146915516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused) 147015516c77SSepherosa Ziehau { 147115516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 147215516c77SSepherosa Ziehau 147315516c77SSepherosa Ziehau /* Prevent any link status checks from running. */ 147415516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_NETCHG; 147515516c77SSepherosa Ziehau 147615516c77SSepherosa Ziehau /* 147715516c77SSepherosa Ziehau * Fake up a [link down --> link up] state change; 5 seconds 147815516c77SSepherosa Ziehau * delay is used, which closely simulates miibus reaction 147915516c77SSepherosa Ziehau * upon link down event. 148015516c77SSepherosa Ziehau */ 148115516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 148215516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); 148315516c77SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0, 148415516c77SSepherosa Ziehau &sc->hn_netchg_status, 5 * hz); 148515516c77SSepherosa Ziehau } 148615516c77SSepherosa Ziehau 148715516c77SSepherosa Ziehau static void 148815516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused) 148915516c77SSepherosa Ziehau { 149015516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 149115516c77SSepherosa Ziehau 149215516c77SSepherosa Ziehau /* Re-allow link status checks. */ 149315516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG; 149415516c77SSepherosa Ziehau hn_link_status(sc); 149515516c77SSepherosa Ziehau } 149615516c77SSepherosa Ziehau 149715516c77SSepherosa Ziehau static void 149815516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc) 149915516c77SSepherosa Ziehau { 150015516c77SSepherosa Ziehau 150115516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 150215516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task); 150315516c77SSepherosa Ziehau } 150415516c77SSepherosa Ziehau 150515516c77SSepherosa Ziehau static void 150615516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc) 150715516c77SSepherosa Ziehau { 150815516c77SSepherosa Ziehau 150915516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 151015516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init); 151115516c77SSepherosa Ziehau } 151215516c77SSepherosa Ziehau 151315516c77SSepherosa Ziehau static __inline int 151415516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd, 151515516c77SSepherosa Ziehau struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) 151615516c77SSepherosa Ziehau { 151715516c77SSepherosa Ziehau struct mbuf *m = *m_head; 151815516c77SSepherosa Ziehau int error; 151915516c77SSepherosa Ziehau 152015516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim")); 152115516c77SSepherosa Ziehau 152215516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap, 152315516c77SSepherosa Ziehau m, segs, nsegs, BUS_DMA_NOWAIT); 152415516c77SSepherosa Ziehau if (error == EFBIG) { 152515516c77SSepherosa Ziehau struct mbuf *m_new; 152615516c77SSepherosa Ziehau 152715516c77SSepherosa Ziehau m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX); 152815516c77SSepherosa Ziehau if (m_new == NULL) 152915516c77SSepherosa Ziehau return ENOBUFS; 153015516c77SSepherosa Ziehau else 153115516c77SSepherosa Ziehau *m_head = m = m_new; 153215516c77SSepherosa Ziehau txr->hn_tx_collapsed++; 153315516c77SSepherosa Ziehau 153415516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, 153515516c77SSepherosa Ziehau txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT); 153615516c77SSepherosa Ziehau } 153715516c77SSepherosa Ziehau if (!error) { 153815516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap, 153915516c77SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 154015516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_DMAMAP; 154115516c77SSepherosa Ziehau } 154215516c77SSepherosa Ziehau return error; 154315516c77SSepherosa Ziehau } 154415516c77SSepherosa Ziehau 154515516c77SSepherosa Ziehau static __inline int 154615516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd) 154715516c77SSepherosa Ziehau { 154815516c77SSepherosa Ziehau 154915516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0, 155015516c77SSepherosa Ziehau ("put an onlist txd %#x", txd->flags)); 1551dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 1552dc13fee6SSepherosa Ziehau ("put an onagg txd %#x", txd->flags)); 155315516c77SSepherosa Ziehau 155415516c77SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 155515516c77SSepherosa Ziehau if (atomic_fetchadd_int(&txd->refs, -1) != 1) 155615516c77SSepherosa Ziehau return 0; 155715516c77SSepherosa Ziehau 1558dc13fee6SSepherosa Ziehau if (!STAILQ_EMPTY(&txd->agg_list)) { 1559dc13fee6SSepherosa Ziehau struct hn_txdesc *tmp_txd; 1560dc13fee6SSepherosa Ziehau 1561dc13fee6SSepherosa Ziehau while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) { 1562dc13fee6SSepherosa Ziehau int freed; 1563dc13fee6SSepherosa Ziehau 1564dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list), 1565dc13fee6SSepherosa Ziehau ("resursive aggregation on aggregated txdesc")); 1566dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG), 1567dc13fee6SSepherosa Ziehau ("not aggregated txdesc")); 1568dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 1569dc13fee6SSepherosa Ziehau ("aggregated txdesc uses dmamap")); 1570dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 1571dc13fee6SSepherosa Ziehau ("aggregated txdesc consumes " 1572dc13fee6SSepherosa Ziehau "chimney sending buffer")); 1573dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_size == 0, 1574dc13fee6SSepherosa Ziehau ("aggregated txdesc has non-zero " 1575dc13fee6SSepherosa Ziehau "chimney sending size")); 1576dc13fee6SSepherosa Ziehau 1577dc13fee6SSepherosa Ziehau STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link); 1578dc13fee6SSepherosa Ziehau tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG; 1579dc13fee6SSepherosa Ziehau freed = hn_txdesc_put(txr, tmp_txd); 1580dc13fee6SSepherosa Ziehau KASSERT(freed, ("failed to free aggregated txdesc")); 1581dc13fee6SSepherosa Ziehau } 1582dc13fee6SSepherosa Ziehau } 1583dc13fee6SSepherosa Ziehau 158415516c77SSepherosa Ziehau if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) { 158515516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 158615516c77SSepherosa Ziehau ("chim txd uses dmamap")); 158715516c77SSepherosa Ziehau hn_chim_free(txr->hn_sc, txd->chim_index); 158815516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 1589dc13fee6SSepherosa Ziehau txd->chim_size = 0; 159015516c77SSepherosa Ziehau } else if (txd->flags & HN_TXD_FLAG_DMAMAP) { 159115516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, 159215516c77SSepherosa Ziehau txd->data_dmap, BUS_DMASYNC_POSTWRITE); 159315516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_data_dtag, 159415516c77SSepherosa Ziehau txd->data_dmap); 159515516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_DMAMAP; 159615516c77SSepherosa Ziehau } 159715516c77SSepherosa Ziehau 159815516c77SSepherosa Ziehau if (txd->m != NULL) { 159915516c77SSepherosa Ziehau m_freem(txd->m); 160015516c77SSepherosa Ziehau txd->m = NULL; 160115516c77SSepherosa Ziehau } 160215516c77SSepherosa Ziehau 160315516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 160415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 160515516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 160615516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail >= 0 && 160715516c77SSepherosa Ziehau txr->hn_txdesc_avail < txr->hn_txdesc_cnt, 160815516c77SSepherosa Ziehau ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail)); 160915516c77SSepherosa Ziehau txr->hn_txdesc_avail++; 161015516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 161115516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 161285e4ae1eSSepherosa Ziehau #else /* HN_USE_TXDESC_BUFRING */ 161385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 161415516c77SSepherosa Ziehau atomic_add_int(&txr->hn_txdesc_avail, 1); 161515516c77SSepherosa Ziehau #endif 161685e4ae1eSSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 161785e4ae1eSSepherosa Ziehau #endif /* !HN_USE_TXDESC_BUFRING */ 161815516c77SSepherosa Ziehau 161915516c77SSepherosa Ziehau return 1; 162015516c77SSepherosa Ziehau } 162115516c77SSepherosa Ziehau 162215516c77SSepherosa Ziehau static __inline struct hn_txdesc * 162315516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr) 162415516c77SSepherosa Ziehau { 162515516c77SSepherosa Ziehau struct hn_txdesc *txd; 162615516c77SSepherosa Ziehau 162715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 162815516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 162915516c77SSepherosa Ziehau txd = SLIST_FIRST(&txr->hn_txlist); 163015516c77SSepherosa Ziehau if (txd != NULL) { 163115516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail > 0, 163215516c77SSepherosa Ziehau ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail)); 163315516c77SSepherosa Ziehau txr->hn_txdesc_avail--; 163415516c77SSepherosa Ziehau SLIST_REMOVE_HEAD(&txr->hn_txlist, link); 163515516c77SSepherosa Ziehau } 163615516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 163715516c77SSepherosa Ziehau #else 163815516c77SSepherosa Ziehau txd = buf_ring_dequeue_sc(txr->hn_txdesc_br); 163915516c77SSepherosa Ziehau #endif 164015516c77SSepherosa Ziehau 164115516c77SSepherosa Ziehau if (txd != NULL) { 164215516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 164385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 164415516c77SSepherosa Ziehau atomic_subtract_int(&txr->hn_txdesc_avail, 1); 164515516c77SSepherosa Ziehau #endif 164685e4ae1eSSepherosa Ziehau #endif /* HN_USE_TXDESC_BUFRING */ 164715516c77SSepherosa Ziehau KASSERT(txd->m == NULL && txd->refs == 0 && 1648dc13fee6SSepherosa Ziehau STAILQ_EMPTY(&txd->agg_list) && 164915516c77SSepherosa Ziehau txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 1650dc13fee6SSepherosa Ziehau txd->chim_size == 0 && 165115516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONLIST) && 1652dc13fee6SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONAGG) == 0 && 165315516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd")); 165415516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_ONLIST; 165515516c77SSepherosa Ziehau txd->refs = 1; 165615516c77SSepherosa Ziehau } 165715516c77SSepherosa Ziehau return txd; 165815516c77SSepherosa Ziehau } 165915516c77SSepherosa Ziehau 166015516c77SSepherosa Ziehau static __inline void 166115516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd) 166215516c77SSepherosa Ziehau { 166315516c77SSepherosa Ziehau 166415516c77SSepherosa Ziehau /* 0->1 transition will never work */ 166525641fc7SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 166615516c77SSepherosa Ziehau atomic_add_int(&txd->refs, 1); 166715516c77SSepherosa Ziehau } 166815516c77SSepherosa Ziehau 1669dc13fee6SSepherosa Ziehau static __inline void 1670dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd) 1671dc13fee6SSepherosa Ziehau { 1672dc13fee6SSepherosa Ziehau 1673dc13fee6SSepherosa Ziehau KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0, 1674dc13fee6SSepherosa Ziehau ("recursive aggregation on aggregating txdesc")); 1675dc13fee6SSepherosa Ziehau 1676dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 1677dc13fee6SSepherosa Ziehau ("already aggregated")); 1678dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&txd->agg_list), 1679dc13fee6SSepherosa Ziehau ("recursive aggregation on to-be-aggregated txdesc")); 1680dc13fee6SSepherosa Ziehau 1681dc13fee6SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONAGG; 1682dc13fee6SSepherosa Ziehau STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link); 1683dc13fee6SSepherosa Ziehau } 1684dc13fee6SSepherosa Ziehau 168515516c77SSepherosa Ziehau static bool 168615516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr) 168715516c77SSepherosa Ziehau { 168815516c77SSepherosa Ziehau bool pending = false; 168915516c77SSepherosa Ziehau 169015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 169115516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 169215516c77SSepherosa Ziehau if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt) 169315516c77SSepherosa Ziehau pending = true; 169415516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 169515516c77SSepherosa Ziehau #else 169615516c77SSepherosa Ziehau if (!buf_ring_full(txr->hn_txdesc_br)) 169715516c77SSepherosa Ziehau pending = true; 169815516c77SSepherosa Ziehau #endif 169915516c77SSepherosa Ziehau return (pending); 170015516c77SSepherosa Ziehau } 170115516c77SSepherosa Ziehau 170215516c77SSepherosa Ziehau static __inline void 170315516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr) 170415516c77SSepherosa Ziehau { 170515516c77SSepherosa Ziehau txr->hn_has_txeof = 0; 170615516c77SSepherosa Ziehau txr->hn_txeof(txr); 170715516c77SSepherosa Ziehau } 170815516c77SSepherosa Ziehau 170915516c77SSepherosa Ziehau static void 171015516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc, 171115516c77SSepherosa Ziehau struct vmbus_channel *chan, const void *data __unused, int dlen __unused) 171215516c77SSepherosa Ziehau { 171315516c77SSepherosa Ziehau struct hn_txdesc *txd = sndc->hn_cbarg; 171415516c77SSepherosa Ziehau struct hn_tx_ring *txr; 171515516c77SSepherosa Ziehau 171615516c77SSepherosa Ziehau txr = txd->txr; 171715516c77SSepherosa Ziehau KASSERT(txr->hn_chan == chan, 171815516c77SSepherosa Ziehau ("channel mismatch, on chan%u, should be chan%u", 1719aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan))); 172015516c77SSepherosa Ziehau 172115516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 172215516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 172315516c77SSepherosa Ziehau 172415516c77SSepherosa Ziehau ++txr->hn_txdone_cnt; 172515516c77SSepherosa Ziehau if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) { 172615516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 172715516c77SSepherosa Ziehau if (txr->hn_oactive) 172815516c77SSepherosa Ziehau hn_txeof(txr); 172915516c77SSepherosa Ziehau } 173015516c77SSepherosa Ziehau } 173115516c77SSepherosa Ziehau 173215516c77SSepherosa Ziehau static void 173315516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr) 173415516c77SSepherosa Ziehau { 173515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 173615516c77SSepherosa Ziehau tcp_lro_flush_all(&rxr->hn_lro); 173715516c77SSepherosa Ziehau #endif 173815516c77SSepherosa Ziehau 173915516c77SSepherosa Ziehau /* 174015516c77SSepherosa Ziehau * NOTE: 174115516c77SSepherosa Ziehau * 'txr' could be NULL, if multiple channels and 174215516c77SSepherosa Ziehau * ifnet.if_start method are enabled. 174315516c77SSepherosa Ziehau */ 174415516c77SSepherosa Ziehau if (txr == NULL || !txr->hn_has_txeof) 174515516c77SSepherosa Ziehau return; 174615516c77SSepherosa Ziehau 174715516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 174815516c77SSepherosa Ziehau hn_txeof(txr); 174915516c77SSepherosa Ziehau } 175015516c77SSepherosa Ziehau 175115516c77SSepherosa Ziehau static __inline uint32_t 175215516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs) 175315516c77SSepherosa Ziehau { 175415516c77SSepherosa Ziehau 175515516c77SSepherosa Ziehau KASSERT(ofs >= sizeof(struct rndis_packet_msg), 175615516c77SSepherosa Ziehau ("invalid RNDIS packet msg offset %u", ofs)); 175715516c77SSepherosa Ziehau return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset)); 175815516c77SSepherosa Ziehau } 175915516c77SSepherosa Ziehau 176015516c77SSepherosa Ziehau static __inline void * 176115516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize, 176215516c77SSepherosa Ziehau size_t pi_dlen, uint32_t pi_type) 176315516c77SSepherosa Ziehau { 176415516c77SSepherosa Ziehau const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen); 176515516c77SSepherosa Ziehau struct rndis_pktinfo *pi; 176615516c77SSepherosa Ziehau 176715516c77SSepherosa Ziehau KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0, 176815516c77SSepherosa Ziehau ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen)); 176915516c77SSepherosa Ziehau 177015516c77SSepherosa Ziehau /* 177115516c77SSepherosa Ziehau * Per-packet-info does not move; it only grows. 177215516c77SSepherosa Ziehau * 177315516c77SSepherosa Ziehau * NOTE: 177415516c77SSepherosa Ziehau * rm_pktinfooffset in this phase counts from the beginning 177515516c77SSepherosa Ziehau * of rndis_packet_msg. 177615516c77SSepherosa Ziehau */ 177715516c77SSepherosa Ziehau KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize, 177815516c77SSepherosa Ziehau ("%u pktinfo overflows RNDIS packet msg", pi_type)); 177915516c77SSepherosa Ziehau pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset + 178015516c77SSepherosa Ziehau pkt->rm_pktinfolen); 178115516c77SSepherosa Ziehau pkt->rm_pktinfolen += pi_size; 178215516c77SSepherosa Ziehau 178315516c77SSepherosa Ziehau pi->rm_size = pi_size; 178415516c77SSepherosa Ziehau pi->rm_type = pi_type; 178515516c77SSepherosa Ziehau pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET; 178615516c77SSepherosa Ziehau 178715516c77SSepherosa Ziehau /* Update RNDIS packet msg length */ 178815516c77SSepherosa Ziehau pkt->rm_len += pi_size; 178915516c77SSepherosa Ziehau 179015516c77SSepherosa Ziehau return (pi->rm_data); 179115516c77SSepherosa Ziehau } 179215516c77SSepherosa Ziehau 1793dc13fee6SSepherosa Ziehau static __inline int 1794dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr) 1795dc13fee6SSepherosa Ziehau { 1796dc13fee6SSepherosa Ziehau struct hn_txdesc *txd; 1797dc13fee6SSepherosa Ziehau struct mbuf *m; 1798dc13fee6SSepherosa Ziehau int error, pkts; 1799dc13fee6SSepherosa Ziehau 1800dc13fee6SSepherosa Ziehau txd = txr->hn_agg_txd; 1801dc13fee6SSepherosa Ziehau KASSERT(txd != NULL, ("no aggregate txdesc")); 1802dc13fee6SSepherosa Ziehau 1803dc13fee6SSepherosa Ziehau /* 1804dc13fee6SSepherosa Ziehau * Since hn_txpkt() will reset this temporary stat, save 1805dc13fee6SSepherosa Ziehau * it now, so that oerrors can be updated properly, if 1806dc13fee6SSepherosa Ziehau * hn_txpkt() ever fails. 1807dc13fee6SSepherosa Ziehau */ 1808dc13fee6SSepherosa Ziehau pkts = txr->hn_stat_pkts; 1809dc13fee6SSepherosa Ziehau 1810dc13fee6SSepherosa Ziehau /* 1811dc13fee6SSepherosa Ziehau * Since txd's mbuf will _not_ be freed upon hn_txpkt() 1812dc13fee6SSepherosa Ziehau * failure, save it for later freeing, if hn_txpkt() ever 1813dc13fee6SSepherosa Ziehau * fails. 1814dc13fee6SSepherosa Ziehau */ 1815dc13fee6SSepherosa Ziehau m = txd->m; 1816dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 1817dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 1818dc13fee6SSepherosa Ziehau /* txd is freed, but m is not. */ 1819dc13fee6SSepherosa Ziehau m_freem(m); 1820dc13fee6SSepherosa Ziehau 1821dc13fee6SSepherosa Ziehau txr->hn_flush_failed++; 1822dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts); 1823dc13fee6SSepherosa Ziehau } 1824dc13fee6SSepherosa Ziehau 1825dc13fee6SSepherosa Ziehau /* Reset all aggregation states. */ 1826dc13fee6SSepherosa Ziehau txr->hn_agg_txd = NULL; 1827dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = 0; 1828dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 1829dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = NULL; 1830dc13fee6SSepherosa Ziehau 1831dc13fee6SSepherosa Ziehau return (error); 1832dc13fee6SSepherosa Ziehau } 1833dc13fee6SSepherosa Ziehau 1834dc13fee6SSepherosa Ziehau static void * 1835dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 1836dc13fee6SSepherosa Ziehau int pktsize) 1837dc13fee6SSepherosa Ziehau { 1838dc13fee6SSepherosa Ziehau void *chim; 1839dc13fee6SSepherosa Ziehau 1840dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 1841dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) { 1842dc13fee6SSepherosa Ziehau struct hn_txdesc *agg_txd = txr->hn_agg_txd; 1843dc13fee6SSepherosa Ziehau struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt; 1844dc13fee6SSepherosa Ziehau int olen; 1845dc13fee6SSepherosa Ziehau 1846dc13fee6SSepherosa Ziehau /* 1847dc13fee6SSepherosa Ziehau * Update the previous RNDIS packet's total length, 1848dc13fee6SSepherosa Ziehau * it can be increased due to the mandatory alignment 1849dc13fee6SSepherosa Ziehau * padding for this RNDIS packet. And update the 1850dc13fee6SSepherosa Ziehau * aggregating txdesc's chimney sending buffer size 1851dc13fee6SSepherosa Ziehau * accordingly. 1852dc13fee6SSepherosa Ziehau * 1853dc13fee6SSepherosa Ziehau * XXX 1854dc13fee6SSepherosa Ziehau * Zero-out the padding, as required by the RNDIS spec. 1855dc13fee6SSepherosa Ziehau */ 1856dc13fee6SSepherosa Ziehau olen = pkt->rm_len; 1857dc13fee6SSepherosa Ziehau pkt->rm_len = roundup2(olen, txr->hn_agg_align); 1858dc13fee6SSepherosa Ziehau agg_txd->chim_size += pkt->rm_len - olen; 1859dc13fee6SSepherosa Ziehau 1860dc13fee6SSepherosa Ziehau /* Link this txdesc to the parent. */ 1861dc13fee6SSepherosa Ziehau hn_txdesc_agg(agg_txd, txd); 1862dc13fee6SSepherosa Ziehau 1863dc13fee6SSepherosa Ziehau chim = (uint8_t *)pkt + pkt->rm_len; 1864dc13fee6SSepherosa Ziehau /* Save the current packet for later fixup. */ 1865dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 1866dc13fee6SSepherosa Ziehau 1867dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft--; 1868dc13fee6SSepherosa Ziehau txr->hn_agg_szleft -= pktsize; 1869dc13fee6SSepherosa Ziehau if (txr->hn_agg_szleft <= 1870dc13fee6SSepherosa Ziehau HN_PKTSIZE_MIN(txr->hn_agg_align)) { 1871dc13fee6SSepherosa Ziehau /* 1872dc13fee6SSepherosa Ziehau * Probably can't aggregate more packets, 1873dc13fee6SSepherosa Ziehau * flush this aggregating txdesc proactively. 1874dc13fee6SSepherosa Ziehau */ 1875dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 1876dc13fee6SSepherosa Ziehau } 1877dc13fee6SSepherosa Ziehau /* Done! */ 1878dc13fee6SSepherosa Ziehau return (chim); 1879dc13fee6SSepherosa Ziehau } 1880dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 1881dc13fee6SSepherosa Ziehau } 1882dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 1883dc13fee6SSepherosa Ziehau 1884dc13fee6SSepherosa Ziehau txr->hn_tx_chimney_tried++; 1885dc13fee6SSepherosa Ziehau txd->chim_index = hn_chim_alloc(txr->hn_sc); 1886dc13fee6SSepherosa Ziehau if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID) 1887dc13fee6SSepherosa Ziehau return (NULL); 1888dc13fee6SSepherosa Ziehau txr->hn_tx_chimney++; 1889dc13fee6SSepherosa Ziehau 1890dc13fee6SSepherosa Ziehau chim = txr->hn_sc->hn_chim + 1891dc13fee6SSepherosa Ziehau (txd->chim_index * txr->hn_sc->hn_chim_szmax); 1892dc13fee6SSepherosa Ziehau 1893dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktmax > 1 && 1894dc13fee6SSepherosa Ziehau txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) { 1895dc13fee6SSepherosa Ziehau txr->hn_agg_txd = txd; 1896dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1; 1897dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize; 1898dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 1899dc13fee6SSepherosa Ziehau } 1900dc13fee6SSepherosa Ziehau return (chim); 1901dc13fee6SSepherosa Ziehau } 1902dc13fee6SSepherosa Ziehau 190315516c77SSepherosa Ziehau /* 190415516c77SSepherosa Ziehau * NOTE: 190515516c77SSepherosa Ziehau * If this function fails, then both txd and m_head0 will be freed. 190615516c77SSepherosa Ziehau */ 190715516c77SSepherosa Ziehau static int 1908dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 1909dc13fee6SSepherosa Ziehau struct mbuf **m_head0) 191015516c77SSepherosa Ziehau { 191115516c77SSepherosa Ziehau bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX]; 191215516c77SSepherosa Ziehau int error, nsegs, i; 191315516c77SSepherosa Ziehau struct mbuf *m_head = *m_head0; 191415516c77SSepherosa Ziehau struct rndis_packet_msg *pkt; 191515516c77SSepherosa Ziehau uint32_t *pi_data; 19168966e5d5SSepherosa Ziehau void *chim = NULL; 1917dc13fee6SSepherosa Ziehau int pkt_hlen, pkt_size; 191815516c77SSepherosa Ziehau 191915516c77SSepherosa Ziehau pkt = txd->rndis_pkt; 1920dc13fee6SSepherosa Ziehau pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align); 1921dc13fee6SSepherosa Ziehau if (pkt_size < txr->hn_chim_size) { 1922dc13fee6SSepherosa Ziehau chim = hn_try_txagg(ifp, txr, txd, pkt_size); 1923dc13fee6SSepherosa Ziehau if (chim != NULL) 19248966e5d5SSepherosa Ziehau pkt = chim; 1925dc13fee6SSepherosa Ziehau } else { 1926dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 1927dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 19288966e5d5SSepherosa Ziehau } 19298966e5d5SSepherosa Ziehau 193015516c77SSepherosa Ziehau pkt->rm_type = REMOTE_NDIS_PACKET_MSG; 193115516c77SSepherosa Ziehau pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len; 1932*9130c4f7SSepherosa Ziehau pkt->rm_dataoffset = 0; 193315516c77SSepherosa Ziehau pkt->rm_datalen = m_head->m_pkthdr.len; 1934dc13fee6SSepherosa Ziehau pkt->rm_oobdataoffset = 0; 1935dc13fee6SSepherosa Ziehau pkt->rm_oobdatalen = 0; 1936dc13fee6SSepherosa Ziehau pkt->rm_oobdataelements = 0; 193715516c77SSepherosa Ziehau pkt->rm_pktinfooffset = sizeof(*pkt); 193815516c77SSepherosa Ziehau pkt->rm_pktinfolen = 0; 1939dc13fee6SSepherosa Ziehau pkt->rm_vchandle = 0; 1940dc13fee6SSepherosa Ziehau pkt->rm_reserved = 0; 194115516c77SSepherosa Ziehau 194215516c77SSepherosa Ziehau if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) { 194315516c77SSepherosa Ziehau /* 194415516c77SSepherosa Ziehau * Set the hash value for this packet, so that the host could 194515516c77SSepherosa Ziehau * dispatch the TX done event for this packet back to this TX 194615516c77SSepherosa Ziehau * ring's channel. 194715516c77SSepherosa Ziehau */ 194815516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 194915516c77SSepherosa Ziehau HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL); 195015516c77SSepherosa Ziehau *pi_data = txr->hn_tx_idx; 195115516c77SSepherosa Ziehau } 195215516c77SSepherosa Ziehau 195315516c77SSepherosa Ziehau if (m_head->m_flags & M_VLANTAG) { 195415516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 195515516c77SSepherosa Ziehau NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN); 195615516c77SSepherosa Ziehau *pi_data = NDIS_VLAN_INFO_MAKE( 195715516c77SSepherosa Ziehau EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag), 195815516c77SSepherosa Ziehau EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag), 195915516c77SSepherosa Ziehau EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag)); 196015516c77SSepherosa Ziehau } 196115516c77SSepherosa Ziehau 196215516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 196315516c77SSepherosa Ziehau #if defined(INET6) || defined(INET) 196415516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 196515516c77SSepherosa Ziehau NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); 196615516c77SSepherosa Ziehau #ifdef INET 196715516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 196815516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV4(0, 196915516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 197015516c77SSepherosa Ziehau } 197115516c77SSepherosa Ziehau #endif 197215516c77SSepherosa Ziehau #if defined(INET6) && defined(INET) 197315516c77SSepherosa Ziehau else 197415516c77SSepherosa Ziehau #endif 197515516c77SSepherosa Ziehau #ifdef INET6 197615516c77SSepherosa Ziehau { 197715516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV6(0, 197815516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 197915516c77SSepherosa Ziehau } 198015516c77SSepherosa Ziehau #endif 198115516c77SSepherosa Ziehau #endif /* INET6 || INET */ 198215516c77SSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) { 198315516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 198415516c77SSepherosa Ziehau NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); 198515516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & 198615516c77SSepherosa Ziehau (CSUM_IP6_TCP | CSUM_IP6_UDP)) { 198715516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV6; 198815516c77SSepherosa Ziehau } else { 198915516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV4; 199015516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 199115516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_IPCS; 199215516c77SSepherosa Ziehau } 199315516c77SSepherosa Ziehau 199415516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) 199515516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_TCPCS; 199615516c77SSepherosa Ziehau else if (m_head->m_pkthdr.csum_flags & 199715516c77SSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP6_UDP)) 199815516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_UDPCS; 199915516c77SSepherosa Ziehau } 200015516c77SSepherosa Ziehau 2001dc13fee6SSepherosa Ziehau pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; 200215516c77SSepherosa Ziehau /* Convert RNDIS packet message offsets */ 2003*9130c4f7SSepherosa Ziehau pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen); 200415516c77SSepherosa Ziehau pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset); 200515516c77SSepherosa Ziehau 200615516c77SSepherosa Ziehau /* 20078966e5d5SSepherosa Ziehau * Fast path: Chimney sending. 200815516c77SSepherosa Ziehau */ 20098966e5d5SSepherosa Ziehau if (chim != NULL) { 2010dc13fee6SSepherosa Ziehau struct hn_txdesc *tgt_txd = txd; 2011dc13fee6SSepherosa Ziehau 2012dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 2013dc13fee6SSepherosa Ziehau tgt_txd = txr->hn_agg_txd; 2014dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 2015dc13fee6SSepherosa Ziehau *m_head0 = NULL; 2016dc13fee6SSepherosa Ziehau #endif 2017dc13fee6SSepherosa Ziehau } 2018dc13fee6SSepherosa Ziehau 2019dc13fee6SSepherosa Ziehau KASSERT(pkt == chim, 2020dc13fee6SSepherosa Ziehau ("RNDIS pkt not in chimney sending buffer")); 2021dc13fee6SSepherosa Ziehau KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID, 2022dc13fee6SSepherosa Ziehau ("chimney sending buffer is not used")); 2023dc13fee6SSepherosa Ziehau tgt_txd->chim_size += pkt->rm_len; 202415516c77SSepherosa Ziehau 20258966e5d5SSepherosa Ziehau m_copydata(m_head, 0, m_head->m_pkthdr.len, 2026dc13fee6SSepherosa Ziehau ((uint8_t *)chim) + pkt_hlen); 202715516c77SSepherosa Ziehau 202815516c77SSepherosa Ziehau txr->hn_gpa_cnt = 0; 202915516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_chim; 203015516c77SSepherosa Ziehau goto done; 203115516c77SSepherosa Ziehau } 2032dc13fee6SSepherosa Ziehau 2033dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc")); 20348966e5d5SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 20358966e5d5SSepherosa Ziehau ("chimney buffer is used")); 20368966e5d5SSepherosa Ziehau KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc")); 203715516c77SSepherosa Ziehau 203815516c77SSepherosa Ziehau error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs); 2039dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 204015516c77SSepherosa Ziehau int freed; 204115516c77SSepherosa Ziehau 204215516c77SSepherosa Ziehau /* 204315516c77SSepherosa Ziehau * This mbuf is not linked w/ the txd yet, so free it now. 204415516c77SSepherosa Ziehau */ 204515516c77SSepherosa Ziehau m_freem(m_head); 204615516c77SSepherosa Ziehau *m_head0 = NULL; 204715516c77SSepherosa Ziehau 204815516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 204915516c77SSepherosa Ziehau KASSERT(freed != 0, 205015516c77SSepherosa Ziehau ("fail to free txd upon txdma error")); 205115516c77SSepherosa Ziehau 205215516c77SSepherosa Ziehau txr->hn_txdma_failed++; 2053dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 205415516c77SSepherosa Ziehau return error; 205515516c77SSepherosa Ziehau } 205615516c77SSepherosa Ziehau *m_head0 = m_head; 205715516c77SSepherosa Ziehau 205815516c77SSepherosa Ziehau /* +1 RNDIS packet message */ 205915516c77SSepherosa Ziehau txr->hn_gpa_cnt = nsegs + 1; 206015516c77SSepherosa Ziehau 206115516c77SSepherosa Ziehau /* send packet with page buffer */ 206215516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr); 206315516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK; 2064dc13fee6SSepherosa Ziehau txr->hn_gpa[0].gpa_len = pkt_hlen; 206515516c77SSepherosa Ziehau 206615516c77SSepherosa Ziehau /* 206715516c77SSepherosa Ziehau * Fill the page buffers with mbuf info after the page 206815516c77SSepherosa Ziehau * buffer for RNDIS packet message. 206915516c77SSepherosa Ziehau */ 207015516c77SSepherosa Ziehau for (i = 0; i < nsegs; ++i) { 207115516c77SSepherosa Ziehau struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1]; 207215516c77SSepherosa Ziehau 207315516c77SSepherosa Ziehau gpa->gpa_page = atop(segs[i].ds_addr); 207415516c77SSepherosa Ziehau gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK; 207515516c77SSepherosa Ziehau gpa->gpa_len = segs[i].ds_len; 207615516c77SSepherosa Ziehau } 207715516c77SSepherosa Ziehau 207815516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 207915516c77SSepherosa Ziehau txd->chim_size = 0; 208015516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_sglist; 208115516c77SSepherosa Ziehau done: 208215516c77SSepherosa Ziehau txd->m = m_head; 208315516c77SSepherosa Ziehau 208415516c77SSepherosa Ziehau /* Set the completion routine */ 208515516c77SSepherosa Ziehau hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd); 208615516c77SSepherosa Ziehau 2087dc13fee6SSepherosa Ziehau /* Update temporary stats for later use. */ 2088dc13fee6SSepherosa Ziehau txr->hn_stat_pkts++; 2089dc13fee6SSepherosa Ziehau txr->hn_stat_size += m_head->m_pkthdr.len; 2090dc13fee6SSepherosa Ziehau if (m_head->m_flags & M_MCAST) 2091dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts++; 2092dc13fee6SSepherosa Ziehau 209315516c77SSepherosa Ziehau return 0; 209415516c77SSepherosa Ziehau } 209515516c77SSepherosa Ziehau 209615516c77SSepherosa Ziehau /* 209715516c77SSepherosa Ziehau * NOTE: 209815516c77SSepherosa Ziehau * If this function fails, then txd will be freed, but the mbuf 209915516c77SSepherosa Ziehau * associated w/ the txd will _not_ be freed. 210015516c77SSepherosa Ziehau */ 210115516c77SSepherosa Ziehau static int 210215516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd) 210315516c77SSepherosa Ziehau { 21048e7d3136SSepherosa Ziehau int error, send_failed = 0, has_bpf; 210515516c77SSepherosa Ziehau 210615516c77SSepherosa Ziehau again: 21078e7d3136SSepherosa Ziehau has_bpf = bpf_peers_present(ifp->if_bpf); 21088e7d3136SSepherosa Ziehau if (has_bpf) { 210915516c77SSepherosa Ziehau /* 21108e7d3136SSepherosa Ziehau * Make sure that this txd and any aggregated txds are not 21118e7d3136SSepherosa Ziehau * freed before ETHER_BPF_MTAP. 211215516c77SSepherosa Ziehau */ 211315516c77SSepherosa Ziehau hn_txdesc_hold(txd); 21148e7d3136SSepherosa Ziehau } 211515516c77SSepherosa Ziehau error = txr->hn_sendpkt(txr, txd); 211615516c77SSepherosa Ziehau if (!error) { 21178e7d3136SSepherosa Ziehau if (has_bpf) { 2118dc13fee6SSepherosa Ziehau const struct hn_txdesc *tmp_txd; 2119dc13fee6SSepherosa Ziehau 212015516c77SSepherosa Ziehau ETHER_BPF_MTAP(ifp, txd->m); 2121dc13fee6SSepherosa Ziehau STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link) 2122dc13fee6SSepherosa Ziehau ETHER_BPF_MTAP(ifp, tmp_txd->m); 2123dc13fee6SSepherosa Ziehau } 2124dc13fee6SSepherosa Ziehau 2125dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts); 212623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 212723bf9e15SSepherosa Ziehau if (!hn_use_if_start) 212823bf9e15SSepherosa Ziehau #endif 212923bf9e15SSepherosa Ziehau { 213015516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, 2131dc13fee6SSepherosa Ziehau txr->hn_stat_size); 2132dc13fee6SSepherosa Ziehau if (txr->hn_stat_mcasts != 0) { 2133dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 2134dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts); 213515516c77SSepherosa Ziehau } 2136dc13fee6SSepherosa Ziehau } 2137dc13fee6SSepherosa Ziehau txr->hn_pkts += txr->hn_stat_pkts; 2138dc13fee6SSepherosa Ziehau txr->hn_sends++; 213915516c77SSepherosa Ziehau } 21408e7d3136SSepherosa Ziehau if (has_bpf) 214115516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 214215516c77SSepherosa Ziehau 214315516c77SSepherosa Ziehau if (__predict_false(error)) { 214415516c77SSepherosa Ziehau int freed; 214515516c77SSepherosa Ziehau 214615516c77SSepherosa Ziehau /* 214715516c77SSepherosa Ziehau * This should "really rarely" happen. 214815516c77SSepherosa Ziehau * 214915516c77SSepherosa Ziehau * XXX Too many RX to be acked or too many sideband 215015516c77SSepherosa Ziehau * commands to run? Ask netvsc_channel_rollup() 215115516c77SSepherosa Ziehau * to kick start later. 215215516c77SSepherosa Ziehau */ 215315516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 215415516c77SSepherosa Ziehau if (!send_failed) { 215515516c77SSepherosa Ziehau txr->hn_send_failed++; 215615516c77SSepherosa Ziehau send_failed = 1; 215715516c77SSepherosa Ziehau /* 215815516c77SSepherosa Ziehau * Try sending again after set hn_has_txeof; 215915516c77SSepherosa Ziehau * in case that we missed the last 216015516c77SSepherosa Ziehau * netvsc_channel_rollup(). 216115516c77SSepherosa Ziehau */ 216215516c77SSepherosa Ziehau goto again; 216315516c77SSepherosa Ziehau } 216415516c77SSepherosa Ziehau if_printf(ifp, "send failed\n"); 216515516c77SSepherosa Ziehau 216615516c77SSepherosa Ziehau /* 216715516c77SSepherosa Ziehau * Caller will perform further processing on the 216815516c77SSepherosa Ziehau * associated mbuf, so don't free it in hn_txdesc_put(); 216915516c77SSepherosa Ziehau * only unload it from the DMA map in hn_txdesc_put(), 217015516c77SSepherosa Ziehau * if it was loaded. 217115516c77SSepherosa Ziehau */ 217215516c77SSepherosa Ziehau txd->m = NULL; 217315516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 217415516c77SSepherosa Ziehau KASSERT(freed != 0, 217515516c77SSepherosa Ziehau ("fail to free txd upon send error")); 217615516c77SSepherosa Ziehau 217715516c77SSepherosa Ziehau txr->hn_send_failed++; 217815516c77SSepherosa Ziehau } 2179dc13fee6SSepherosa Ziehau 2180dc13fee6SSepherosa Ziehau /* Reset temporary stats, after this sending is done. */ 2181dc13fee6SSepherosa Ziehau txr->hn_stat_size = 0; 2182dc13fee6SSepherosa Ziehau txr->hn_stat_pkts = 0; 2183dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts = 0; 2184dc13fee6SSepherosa Ziehau 2185dc13fee6SSepherosa Ziehau return (error); 218615516c77SSepherosa Ziehau } 218715516c77SSepherosa Ziehau 218815516c77SSepherosa Ziehau /* 218915516c77SSepherosa Ziehau * Append the specified data to the indicated mbuf chain, 219015516c77SSepherosa Ziehau * Extend the mbuf chain if the new data does not fit in 219115516c77SSepherosa Ziehau * existing space. 219215516c77SSepherosa Ziehau * 219315516c77SSepherosa Ziehau * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c. 219415516c77SSepherosa Ziehau * There should be an equivalent in the kernel mbuf code, 219515516c77SSepherosa Ziehau * but there does not appear to be one yet. 219615516c77SSepherosa Ziehau * 219715516c77SSepherosa Ziehau * Differs from m_append() in that additional mbufs are 219815516c77SSepherosa Ziehau * allocated with cluster size MJUMPAGESIZE, and filled 219915516c77SSepherosa Ziehau * accordingly. 220015516c77SSepherosa Ziehau * 220115516c77SSepherosa Ziehau * Return 1 if able to complete the job; otherwise 0. 220215516c77SSepherosa Ziehau */ 220315516c77SSepherosa Ziehau static int 220415516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp) 220515516c77SSepherosa Ziehau { 220615516c77SSepherosa Ziehau struct mbuf *m, *n; 220715516c77SSepherosa Ziehau int remainder, space; 220815516c77SSepherosa Ziehau 220915516c77SSepherosa Ziehau for (m = m0; m->m_next != NULL; m = m->m_next) 221015516c77SSepherosa Ziehau ; 221115516c77SSepherosa Ziehau remainder = len; 221215516c77SSepherosa Ziehau space = M_TRAILINGSPACE(m); 221315516c77SSepherosa Ziehau if (space > 0) { 221415516c77SSepherosa Ziehau /* 221515516c77SSepherosa Ziehau * Copy into available space. 221615516c77SSepherosa Ziehau */ 221715516c77SSepherosa Ziehau if (space > remainder) 221815516c77SSepherosa Ziehau space = remainder; 221915516c77SSepherosa Ziehau bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 222015516c77SSepherosa Ziehau m->m_len += space; 222115516c77SSepherosa Ziehau cp += space; 222215516c77SSepherosa Ziehau remainder -= space; 222315516c77SSepherosa Ziehau } 222415516c77SSepherosa Ziehau while (remainder > 0) { 222515516c77SSepherosa Ziehau /* 222615516c77SSepherosa Ziehau * Allocate a new mbuf; could check space 222715516c77SSepherosa Ziehau * and allocate a cluster instead. 222815516c77SSepherosa Ziehau */ 222915516c77SSepherosa Ziehau n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE); 223015516c77SSepherosa Ziehau if (n == NULL) 223115516c77SSepherosa Ziehau break; 223215516c77SSepherosa Ziehau n->m_len = min(MJUMPAGESIZE, remainder); 223315516c77SSepherosa Ziehau bcopy(cp, mtod(n, caddr_t), n->m_len); 223415516c77SSepherosa Ziehau cp += n->m_len; 223515516c77SSepherosa Ziehau remainder -= n->m_len; 223615516c77SSepherosa Ziehau m->m_next = n; 223715516c77SSepherosa Ziehau m = n; 223815516c77SSepherosa Ziehau } 223915516c77SSepherosa Ziehau if (m0->m_flags & M_PKTHDR) 224015516c77SSepherosa Ziehau m0->m_pkthdr.len += len - remainder; 224115516c77SSepherosa Ziehau 224215516c77SSepherosa Ziehau return (remainder == 0); 224315516c77SSepherosa Ziehau } 224415516c77SSepherosa Ziehau 224515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 224615516c77SSepherosa Ziehau static __inline int 224715516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m) 224815516c77SSepherosa Ziehau { 224915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 225015516c77SSepherosa Ziehau if (hn_lro_mbufq_depth) { 225115516c77SSepherosa Ziehau tcp_lro_queue_mbuf(lc, m); 225215516c77SSepherosa Ziehau return 0; 225315516c77SSepherosa Ziehau } 225415516c77SSepherosa Ziehau #endif 225515516c77SSepherosa Ziehau return tcp_lro_rx(lc, m, 0); 225615516c77SSepherosa Ziehau } 225715516c77SSepherosa Ziehau #endif 225815516c77SSepherosa Ziehau 225915516c77SSepherosa Ziehau static int 226015516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, 226115516c77SSepherosa Ziehau const struct hn_rxinfo *info) 226215516c77SSepherosa Ziehau { 22635bdfd3fdSDexuan Cui struct ifnet *ifp; 226415516c77SSepherosa Ziehau struct mbuf *m_new; 226515516c77SSepherosa Ziehau int size, do_lro = 0, do_csum = 1; 226615516c77SSepherosa Ziehau int hash_type; 226715516c77SSepherosa Ziehau 22685bdfd3fdSDexuan Cui /* If the VF is active, inject the packet through the VF */ 22695bdfd3fdSDexuan Cui ifp = rxr->hn_vf ? rxr->hn_vf : rxr->hn_ifp; 22705bdfd3fdSDexuan Cui 2271c927d681SDexuan Cui if (dlen <= MHLEN) { 227215516c77SSepherosa Ziehau m_new = m_gethdr(M_NOWAIT, MT_DATA); 227315516c77SSepherosa Ziehau if (m_new == NULL) { 227415516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 227515516c77SSepherosa Ziehau return (0); 227615516c77SSepherosa Ziehau } 227715516c77SSepherosa Ziehau memcpy(mtod(m_new, void *), data, dlen); 227815516c77SSepherosa Ziehau m_new->m_pkthdr.len = m_new->m_len = dlen; 227915516c77SSepherosa Ziehau rxr->hn_small_pkts++; 228015516c77SSepherosa Ziehau } else { 228115516c77SSepherosa Ziehau /* 228215516c77SSepherosa Ziehau * Get an mbuf with a cluster. For packets 2K or less, 228315516c77SSepherosa Ziehau * get a standard 2K cluster. For anything larger, get a 228415516c77SSepherosa Ziehau * 4K cluster. Any buffers larger than 4K can cause problems 228515516c77SSepherosa Ziehau * if looped around to the Hyper-V TX channel, so avoid them. 228615516c77SSepherosa Ziehau */ 228715516c77SSepherosa Ziehau size = MCLBYTES; 228815516c77SSepherosa Ziehau if (dlen > MCLBYTES) { 228915516c77SSepherosa Ziehau /* 4096 */ 229015516c77SSepherosa Ziehau size = MJUMPAGESIZE; 229115516c77SSepherosa Ziehau } 229215516c77SSepherosa Ziehau 229315516c77SSepherosa Ziehau m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size); 229415516c77SSepherosa Ziehau if (m_new == NULL) { 229515516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 229615516c77SSepherosa Ziehau return (0); 229715516c77SSepherosa Ziehau } 229815516c77SSepherosa Ziehau 229915516c77SSepherosa Ziehau hv_m_append(m_new, dlen, data); 230015516c77SSepherosa Ziehau } 230115516c77SSepherosa Ziehau m_new->m_pkthdr.rcvif = ifp; 230215516c77SSepherosa Ziehau 230315516c77SSepherosa Ziehau if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0)) 230415516c77SSepherosa Ziehau do_csum = 0; 230515516c77SSepherosa Ziehau 230615516c77SSepherosa Ziehau /* receive side checksum offload */ 230715516c77SSepherosa Ziehau if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) { 230815516c77SSepherosa Ziehau /* IP csum offload */ 230915516c77SSepherosa Ziehau if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) { 231015516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 231115516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 231215516c77SSepherosa Ziehau rxr->hn_csum_ip++; 231315516c77SSepherosa Ziehau } 231415516c77SSepherosa Ziehau 231515516c77SSepherosa Ziehau /* TCP/UDP csum offload */ 231615516c77SSepherosa Ziehau if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK | 231715516c77SSepherosa Ziehau NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) { 231815516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 231915516c77SSepherosa Ziehau (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 232015516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 232115516c77SSepherosa Ziehau if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK) 232215516c77SSepherosa Ziehau rxr->hn_csum_tcp++; 232315516c77SSepherosa Ziehau else 232415516c77SSepherosa Ziehau rxr->hn_csum_udp++; 232515516c77SSepherosa Ziehau } 232615516c77SSepherosa Ziehau 232715516c77SSepherosa Ziehau /* 232815516c77SSepherosa Ziehau * XXX 232915516c77SSepherosa Ziehau * As of this write (Oct 28th, 2016), host side will turn 233015516c77SSepherosa Ziehau * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so 233115516c77SSepherosa Ziehau * the do_lro setting here is actually _not_ accurate. We 233215516c77SSepherosa Ziehau * depend on the RSS hash type check to reset do_lro. 233315516c77SSepherosa Ziehau */ 233415516c77SSepherosa Ziehau if ((info->csum_info & 233515516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) == 233615516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) 233715516c77SSepherosa Ziehau do_lro = 1; 233815516c77SSepherosa Ziehau } else { 233915516c77SSepherosa Ziehau const struct ether_header *eh; 234015516c77SSepherosa Ziehau uint16_t etype; 234115516c77SSepherosa Ziehau int hoff; 234215516c77SSepherosa Ziehau 234315516c77SSepherosa Ziehau hoff = sizeof(*eh); 234415516c77SSepherosa Ziehau if (m_new->m_len < hoff) 234515516c77SSepherosa Ziehau goto skip; 234615516c77SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 234715516c77SSepherosa Ziehau etype = ntohs(eh->ether_type); 234815516c77SSepherosa Ziehau if (etype == ETHERTYPE_VLAN) { 234915516c77SSepherosa Ziehau const struct ether_vlan_header *evl; 235015516c77SSepherosa Ziehau 235115516c77SSepherosa Ziehau hoff = sizeof(*evl); 235215516c77SSepherosa Ziehau if (m_new->m_len < hoff) 235315516c77SSepherosa Ziehau goto skip; 235415516c77SSepherosa Ziehau evl = mtod(m_new, struct ether_vlan_header *); 235515516c77SSepherosa Ziehau etype = ntohs(evl->evl_proto); 235615516c77SSepherosa Ziehau } 235715516c77SSepherosa Ziehau 235815516c77SSepherosa Ziehau if (etype == ETHERTYPE_IP) { 235915516c77SSepherosa Ziehau int pr; 236015516c77SSepherosa Ziehau 236115516c77SSepherosa Ziehau pr = hn_check_iplen(m_new, hoff); 236215516c77SSepherosa Ziehau if (pr == IPPROTO_TCP) { 236315516c77SSepherosa Ziehau if (do_csum && 236415516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 236515516c77SSepherosa Ziehau HN_TRUST_HCSUM_TCP)) { 236615516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 236715516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 236815516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 236915516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 237015516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 237115516c77SSepherosa Ziehau } 237215516c77SSepherosa Ziehau do_lro = 1; 237315516c77SSepherosa Ziehau } else if (pr == IPPROTO_UDP) { 237415516c77SSepherosa Ziehau if (do_csum && 237515516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 237615516c77SSepherosa Ziehau HN_TRUST_HCSUM_UDP)) { 237715516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 237815516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 237915516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 238015516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 238115516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 238215516c77SSepherosa Ziehau } 238315516c77SSepherosa Ziehau } else if (pr != IPPROTO_DONE && do_csum && 238415516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) { 238515516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 238615516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 238715516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 238815516c77SSepherosa Ziehau } 238915516c77SSepherosa Ziehau } 239015516c77SSepherosa Ziehau } 239115516c77SSepherosa Ziehau skip: 239215516c77SSepherosa Ziehau if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) { 239315516c77SSepherosa Ziehau m_new->m_pkthdr.ether_vtag = EVL_MAKETAG( 239415516c77SSepherosa Ziehau NDIS_VLAN_INFO_ID(info->vlan_info), 239515516c77SSepherosa Ziehau NDIS_VLAN_INFO_PRI(info->vlan_info), 239615516c77SSepherosa Ziehau NDIS_VLAN_INFO_CFI(info->vlan_info)); 239715516c77SSepherosa Ziehau m_new->m_flags |= M_VLANTAG; 239815516c77SSepherosa Ziehau } 239915516c77SSepherosa Ziehau 240015516c77SSepherosa Ziehau if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) { 240115516c77SSepherosa Ziehau rxr->hn_rss_pkts++; 240215516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = info->hash_value; 240315516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE_HASH; 240415516c77SSepherosa Ziehau if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) == 240515516c77SSepherosa Ziehau NDIS_HASH_FUNCTION_TOEPLITZ) { 240615516c77SSepherosa Ziehau uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK); 240715516c77SSepherosa Ziehau 240815516c77SSepherosa Ziehau /* 240915516c77SSepherosa Ziehau * NOTE: 241015516c77SSepherosa Ziehau * do_lro is resetted, if the hash types are not TCP 241115516c77SSepherosa Ziehau * related. See the comment in the above csum_flags 241215516c77SSepherosa Ziehau * setup section. 241315516c77SSepherosa Ziehau */ 241415516c77SSepherosa Ziehau switch (type) { 241515516c77SSepherosa Ziehau case NDIS_HASH_IPV4: 241615516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV4; 241715516c77SSepherosa Ziehau do_lro = 0; 241815516c77SSepherosa Ziehau break; 241915516c77SSepherosa Ziehau 242015516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV4: 242115516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV4; 242215516c77SSepherosa Ziehau break; 242315516c77SSepherosa Ziehau 242415516c77SSepherosa Ziehau case NDIS_HASH_IPV6: 242515516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6; 242615516c77SSepherosa Ziehau do_lro = 0; 242715516c77SSepherosa Ziehau break; 242815516c77SSepherosa Ziehau 242915516c77SSepherosa Ziehau case NDIS_HASH_IPV6_EX: 243015516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6_EX; 243115516c77SSepherosa Ziehau do_lro = 0; 243215516c77SSepherosa Ziehau break; 243315516c77SSepherosa Ziehau 243415516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6: 243515516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6; 243615516c77SSepherosa Ziehau break; 243715516c77SSepherosa Ziehau 243815516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6_EX: 243915516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX; 244015516c77SSepherosa Ziehau break; 244115516c77SSepherosa Ziehau } 244215516c77SSepherosa Ziehau } 244315516c77SSepherosa Ziehau } else { 244415516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = rxr->hn_rx_idx; 244515516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE; 244615516c77SSepherosa Ziehau } 244715516c77SSepherosa Ziehau M_HASHTYPE_SET(m_new, hash_type); 244815516c77SSepherosa Ziehau 244915516c77SSepherosa Ziehau /* 245015516c77SSepherosa Ziehau * Note: Moved RX completion back to hv_nv_on_receive() so all 245115516c77SSepherosa Ziehau * messages (not just data messages) will trigger a response. 245215516c77SSepherosa Ziehau */ 245315516c77SSepherosa Ziehau 245415516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 245515516c77SSepherosa Ziehau rxr->hn_pkts++; 245615516c77SSepherosa Ziehau 245715516c77SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_LRO) && do_lro) { 245815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 245915516c77SSepherosa Ziehau struct lro_ctrl *lro = &rxr->hn_lro; 246015516c77SSepherosa Ziehau 246115516c77SSepherosa Ziehau if (lro->lro_cnt) { 246215516c77SSepherosa Ziehau rxr->hn_lro_tried++; 246315516c77SSepherosa Ziehau if (hn_lro_rx(lro, m_new) == 0) { 246415516c77SSepherosa Ziehau /* DONE! */ 246515516c77SSepherosa Ziehau return 0; 246615516c77SSepherosa Ziehau } 246715516c77SSepherosa Ziehau } 246815516c77SSepherosa Ziehau #endif 246915516c77SSepherosa Ziehau } 247015516c77SSepherosa Ziehau 247115516c77SSepherosa Ziehau /* We're not holding the lock here, so don't release it */ 247215516c77SSepherosa Ziehau (*ifp->if_input)(ifp, m_new); 247315516c77SSepherosa Ziehau 247415516c77SSepherosa Ziehau return (0); 247515516c77SSepherosa Ziehau } 247615516c77SSepherosa Ziehau 247715516c77SSepherosa Ziehau static int 247815516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 247915516c77SSepherosa Ziehau { 248015516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 248115516c77SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data; 248215516c77SSepherosa Ziehau int mask, error = 0; 248315516c77SSepherosa Ziehau 248415516c77SSepherosa Ziehau switch (cmd) { 248515516c77SSepherosa Ziehau case SIOCSIFMTU: 248615516c77SSepherosa Ziehau if (ifr->ifr_mtu > HN_MTU_MAX) { 248715516c77SSepherosa Ziehau error = EINVAL; 248815516c77SSepherosa Ziehau break; 248915516c77SSepherosa Ziehau } 249015516c77SSepherosa Ziehau 249115516c77SSepherosa Ziehau HN_LOCK(sc); 249215516c77SSepherosa Ziehau 249315516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 249415516c77SSepherosa Ziehau HN_UNLOCK(sc); 249515516c77SSepherosa Ziehau break; 249615516c77SSepherosa Ziehau } 249715516c77SSepherosa Ziehau 249815516c77SSepherosa Ziehau if ((sc->hn_caps & HN_CAP_MTU) == 0) { 249915516c77SSepherosa Ziehau /* Can't change MTU */ 250015516c77SSepherosa Ziehau HN_UNLOCK(sc); 250115516c77SSepherosa Ziehau error = EOPNOTSUPP; 250215516c77SSepherosa Ziehau break; 250315516c77SSepherosa Ziehau } 250415516c77SSepherosa Ziehau 250515516c77SSepherosa Ziehau if (ifp->if_mtu == ifr->ifr_mtu) { 250615516c77SSepherosa Ziehau HN_UNLOCK(sc); 250715516c77SSepherosa Ziehau break; 250815516c77SSepherosa Ziehau } 250915516c77SSepherosa Ziehau 251015516c77SSepherosa Ziehau /* 251115516c77SSepherosa Ziehau * Suspend this interface before the synthetic parts 251215516c77SSepherosa Ziehau * are ripped. 251315516c77SSepherosa Ziehau */ 251415516c77SSepherosa Ziehau hn_suspend(sc); 251515516c77SSepherosa Ziehau 251615516c77SSepherosa Ziehau /* 251715516c77SSepherosa Ziehau * Detach the synthetics parts, i.e. NVS and RNDIS. 251815516c77SSepherosa Ziehau */ 251915516c77SSepherosa Ziehau hn_synth_detach(sc); 252015516c77SSepherosa Ziehau 252115516c77SSepherosa Ziehau /* 252215516c77SSepherosa Ziehau * Reattach the synthetic parts, i.e. NVS and RNDIS, 252315516c77SSepherosa Ziehau * with the new MTU setting. 252415516c77SSepherosa Ziehau */ 252515516c77SSepherosa Ziehau error = hn_synth_attach(sc, ifr->ifr_mtu); 252615516c77SSepherosa Ziehau if (error) { 252715516c77SSepherosa Ziehau HN_UNLOCK(sc); 252815516c77SSepherosa Ziehau break; 252915516c77SSepherosa Ziehau } 253015516c77SSepherosa Ziehau 253115516c77SSepherosa Ziehau /* 253215516c77SSepherosa Ziehau * Commit the requested MTU, after the synthetic parts 253315516c77SSepherosa Ziehau * have been successfully attached. 253415516c77SSepherosa Ziehau */ 253515516c77SSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 253615516c77SSepherosa Ziehau 253715516c77SSepherosa Ziehau /* 253815516c77SSepherosa Ziehau * Make sure that various parameters based on MTU are 253915516c77SSepherosa Ziehau * still valid, after the MTU change. 254015516c77SSepherosa Ziehau */ 254115516c77SSepherosa Ziehau if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax) 254215516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 254315516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu); 254415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 254515516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < 254615516c77SSepherosa Ziehau HN_LRO_LENLIM_MIN(ifp)) 254715516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp)); 254815516c77SSepherosa Ziehau #endif 254915516c77SSepherosa Ziehau 255015516c77SSepherosa Ziehau /* 255115516c77SSepherosa Ziehau * All done! Resume the interface now. 255215516c77SSepherosa Ziehau */ 255315516c77SSepherosa Ziehau hn_resume(sc); 255415516c77SSepherosa Ziehau 255515516c77SSepherosa Ziehau HN_UNLOCK(sc); 255615516c77SSepherosa Ziehau break; 255715516c77SSepherosa Ziehau 255815516c77SSepherosa Ziehau case SIOCSIFFLAGS: 255915516c77SSepherosa Ziehau HN_LOCK(sc); 256015516c77SSepherosa Ziehau 256115516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 256215516c77SSepherosa Ziehau HN_UNLOCK(sc); 256315516c77SSepherosa Ziehau break; 256415516c77SSepherosa Ziehau } 256515516c77SSepherosa Ziehau 256615516c77SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 2567fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2568fdc4f478SSepherosa Ziehau /* 2569fdc4f478SSepherosa Ziehau * Caller meight hold mutex, e.g. 2570fdc4f478SSepherosa Ziehau * bpf; use busy-wait for the RNDIS 2571fdc4f478SSepherosa Ziehau * reply. 2572fdc4f478SSepherosa Ziehau */ 2573fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 2574c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 2575fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 2576fdc4f478SSepherosa Ziehau } else { 257715516c77SSepherosa Ziehau hn_init_locked(sc); 2578fdc4f478SSepherosa Ziehau } 257915516c77SSepherosa Ziehau } else { 258015516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 25815bdfd3fdSDexuan Cui hn_stop(sc, false); 258215516c77SSepherosa Ziehau } 258315516c77SSepherosa Ziehau sc->hn_if_flags = ifp->if_flags; 258415516c77SSepherosa Ziehau 258515516c77SSepherosa Ziehau HN_UNLOCK(sc); 258615516c77SSepherosa Ziehau break; 258715516c77SSepherosa Ziehau 258815516c77SSepherosa Ziehau case SIOCSIFCAP: 258915516c77SSepherosa Ziehau HN_LOCK(sc); 259015516c77SSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable; 259115516c77SSepherosa Ziehau 259215516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM) { 259315516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 259415516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 259515516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc); 259615516c77SSepherosa Ziehau else 259715516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc); 259815516c77SSepherosa Ziehau } 259915516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM_IPV6) { 260015516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 260115516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 260215516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc); 260315516c77SSepherosa Ziehau else 260415516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc); 260515516c77SSepherosa Ziehau } 260615516c77SSepherosa Ziehau 260715516c77SSepherosa Ziehau /* TODO: flip RNDIS offload parameters for RXCSUM. */ 260815516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 260915516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 261015516c77SSepherosa Ziehau #ifdef foo 261115516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 261215516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM_IPV6) 261315516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 261415516c77SSepherosa Ziehau #endif 261515516c77SSepherosa Ziehau 261615516c77SSepherosa Ziehau if (mask & IFCAP_LRO) 261715516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_LRO; 261815516c77SSepherosa Ziehau 261915516c77SSepherosa Ziehau if (mask & IFCAP_TSO4) { 262015516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO4; 262115516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 262215516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 262315516c77SSepherosa Ziehau else 262415516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP_TSO; 262515516c77SSepherosa Ziehau } 262615516c77SSepherosa Ziehau if (mask & IFCAP_TSO6) { 262715516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO6; 262815516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 262915516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 263015516c77SSepherosa Ziehau else 263115516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP6_TSO; 263215516c77SSepherosa Ziehau } 263315516c77SSepherosa Ziehau 263415516c77SSepherosa Ziehau HN_UNLOCK(sc); 263515516c77SSepherosa Ziehau break; 263615516c77SSepherosa Ziehau 263715516c77SSepherosa Ziehau case SIOCADDMULTI: 263815516c77SSepherosa Ziehau case SIOCDELMULTI: 263915516c77SSepherosa Ziehau HN_LOCK(sc); 264015516c77SSepherosa Ziehau 264115516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 264215516c77SSepherosa Ziehau HN_UNLOCK(sc); 264315516c77SSepherosa Ziehau break; 264415516c77SSepherosa Ziehau } 2645fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2646fdc4f478SSepherosa Ziehau /* 2647fdc4f478SSepherosa Ziehau * Multicast uses mutex; use busy-wait for 2648fdc4f478SSepherosa Ziehau * the RNDIS reply. 2649fdc4f478SSepherosa Ziehau */ 2650fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 2651c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 2652fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 2653fdc4f478SSepherosa Ziehau } 265415516c77SSepherosa Ziehau 265515516c77SSepherosa Ziehau HN_UNLOCK(sc); 265615516c77SSepherosa Ziehau break; 265715516c77SSepherosa Ziehau 265815516c77SSepherosa Ziehau case SIOCSIFMEDIA: 265915516c77SSepherosa Ziehau case SIOCGIFMEDIA: 266015516c77SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd); 266115516c77SSepherosa Ziehau break; 266215516c77SSepherosa Ziehau 266315516c77SSepherosa Ziehau default: 266415516c77SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 266515516c77SSepherosa Ziehau break; 266615516c77SSepherosa Ziehau } 266715516c77SSepherosa Ziehau return (error); 266815516c77SSepherosa Ziehau } 266915516c77SSepherosa Ziehau 267015516c77SSepherosa Ziehau static void 26715bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching) 267215516c77SSepherosa Ziehau { 267315516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 267415516c77SSepherosa Ziehau int i; 267515516c77SSepherosa Ziehau 267615516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 267715516c77SSepherosa Ziehau 267815516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 267915516c77SSepherosa Ziehau ("synthetic parts were not attached")); 268015516c77SSepherosa Ziehau 26816c1204dfSSepherosa Ziehau /* Disable polling. */ 26826c1204dfSSepherosa Ziehau hn_polling(sc, 0); 26836c1204dfSSepherosa Ziehau 268415516c77SSepherosa Ziehau /* Clear RUNNING bit _before_ hn_suspend_data() */ 268515516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 268615516c77SSepherosa Ziehau hn_suspend_data(sc); 268715516c77SSepherosa Ziehau 268815516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 268915516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 269015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 269115516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 26925bdfd3fdSDexuan Cui 26935bdfd3fdSDexuan Cui /* 26945bdfd3fdSDexuan Cui * If the VF is active, make sure the filter is not 0, even if 26955bdfd3fdSDexuan Cui * the synthetic NIC is down. 26965bdfd3fdSDexuan Cui */ 26975bdfd3fdSDexuan Cui if (!detaching && (sc->hn_flags & HN_FLAG_VF)) 26985bdfd3fdSDexuan Cui hn_rxfilter_config(sc); 269915516c77SSepherosa Ziehau } 270015516c77SSepherosa Ziehau 270115516c77SSepherosa Ziehau static void 270215516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc) 270315516c77SSepherosa Ziehau { 270415516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 270515516c77SSepherosa Ziehau int i; 270615516c77SSepherosa Ziehau 270715516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 270815516c77SSepherosa Ziehau 270915516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 271015516c77SSepherosa Ziehau return; 271115516c77SSepherosa Ziehau 271215516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 271315516c77SSepherosa Ziehau return; 271415516c77SSepherosa Ziehau 271515516c77SSepherosa Ziehau /* Configure RX filter */ 2716c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 271715516c77SSepherosa Ziehau 271815516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 271915516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 272015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 272115516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 272215516c77SSepherosa Ziehau 272315516c77SSepherosa Ziehau /* Clear TX 'suspended' bit. */ 272415516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_inuse); 272515516c77SSepherosa Ziehau 272615516c77SSepherosa Ziehau /* Everything is ready; unleash! */ 272715516c77SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 27286c1204dfSSepherosa Ziehau 27296c1204dfSSepherosa Ziehau /* Re-enable polling if requested. */ 27306c1204dfSSepherosa Ziehau if (sc->hn_pollhz > 0) 27316c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 273215516c77SSepherosa Ziehau } 273315516c77SSepherosa Ziehau 273415516c77SSepherosa Ziehau static void 273515516c77SSepherosa Ziehau hn_init(void *xsc) 273615516c77SSepherosa Ziehau { 273715516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 273815516c77SSepherosa Ziehau 273915516c77SSepherosa Ziehau HN_LOCK(sc); 274015516c77SSepherosa Ziehau hn_init_locked(sc); 274115516c77SSepherosa Ziehau HN_UNLOCK(sc); 274215516c77SSepherosa Ziehau } 274315516c77SSepherosa Ziehau 274415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 274515516c77SSepherosa Ziehau 274615516c77SSepherosa Ziehau static int 274715516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS) 274815516c77SSepherosa Ziehau { 274915516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 275015516c77SSepherosa Ziehau unsigned int lenlim; 275115516c77SSepherosa Ziehau int error; 275215516c77SSepherosa Ziehau 275315516c77SSepherosa Ziehau lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim; 275415516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &lenlim, 0, req); 275515516c77SSepherosa Ziehau if (error || req->newptr == NULL) 275615516c77SSepherosa Ziehau return error; 275715516c77SSepherosa Ziehau 275815516c77SSepherosa Ziehau HN_LOCK(sc); 275915516c77SSepherosa Ziehau if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) || 276015516c77SSepherosa Ziehau lenlim > TCP_LRO_LENGTH_MAX) { 276115516c77SSepherosa Ziehau HN_UNLOCK(sc); 276215516c77SSepherosa Ziehau return EINVAL; 276315516c77SSepherosa Ziehau } 276415516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, lenlim); 276515516c77SSepherosa Ziehau HN_UNLOCK(sc); 276615516c77SSepherosa Ziehau 276715516c77SSepherosa Ziehau return 0; 276815516c77SSepherosa Ziehau } 276915516c77SSepherosa Ziehau 277015516c77SSepherosa Ziehau static int 277115516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS) 277215516c77SSepherosa Ziehau { 277315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 277415516c77SSepherosa Ziehau int ackcnt, error, i; 277515516c77SSepherosa Ziehau 277615516c77SSepherosa Ziehau /* 277715516c77SSepherosa Ziehau * lro_ackcnt_lim is append count limit, 277815516c77SSepherosa Ziehau * +1 to turn it into aggregation limit. 277915516c77SSepherosa Ziehau */ 278015516c77SSepherosa Ziehau ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1; 278115516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &ackcnt, 0, req); 278215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 278315516c77SSepherosa Ziehau return error; 278415516c77SSepherosa Ziehau 278515516c77SSepherosa Ziehau if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1)) 278615516c77SSepherosa Ziehau return EINVAL; 278715516c77SSepherosa Ziehau 278815516c77SSepherosa Ziehau /* 278915516c77SSepherosa Ziehau * Convert aggregation limit back to append 279015516c77SSepherosa Ziehau * count limit. 279115516c77SSepherosa Ziehau */ 279215516c77SSepherosa Ziehau --ackcnt; 279315516c77SSepherosa Ziehau HN_LOCK(sc); 2794a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 279515516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt; 279615516c77SSepherosa Ziehau HN_UNLOCK(sc); 279715516c77SSepherosa Ziehau return 0; 279815516c77SSepherosa Ziehau } 279915516c77SSepherosa Ziehau 280015516c77SSepherosa Ziehau #endif 280115516c77SSepherosa Ziehau 280215516c77SSepherosa Ziehau static int 280315516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS) 280415516c77SSepherosa Ziehau { 280515516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 280615516c77SSepherosa Ziehau int hcsum = arg2; 280715516c77SSepherosa Ziehau int on, error, i; 280815516c77SSepherosa Ziehau 280915516c77SSepherosa Ziehau on = 0; 281015516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum) 281115516c77SSepherosa Ziehau on = 1; 281215516c77SSepherosa Ziehau 281315516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &on, 0, req); 281415516c77SSepherosa Ziehau if (error || req->newptr == NULL) 281515516c77SSepherosa Ziehau return error; 281615516c77SSepherosa Ziehau 281715516c77SSepherosa Ziehau HN_LOCK(sc); 2818a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 281915516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 282015516c77SSepherosa Ziehau 282115516c77SSepherosa Ziehau if (on) 282215516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= hcsum; 282315516c77SSepherosa Ziehau else 282415516c77SSepherosa Ziehau rxr->hn_trust_hcsum &= ~hcsum; 282515516c77SSepherosa Ziehau } 282615516c77SSepherosa Ziehau HN_UNLOCK(sc); 282715516c77SSepherosa Ziehau return 0; 282815516c77SSepherosa Ziehau } 282915516c77SSepherosa Ziehau 283015516c77SSepherosa Ziehau static int 283115516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS) 283215516c77SSepherosa Ziehau { 283315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 283415516c77SSepherosa Ziehau int chim_size, error; 283515516c77SSepherosa Ziehau 283615516c77SSepherosa Ziehau chim_size = sc->hn_tx_ring[0].hn_chim_size; 283715516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &chim_size, 0, req); 283815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 283915516c77SSepherosa Ziehau return error; 284015516c77SSepherosa Ziehau 284115516c77SSepherosa Ziehau if (chim_size > sc->hn_chim_szmax || chim_size <= 0) 284215516c77SSepherosa Ziehau return EINVAL; 284315516c77SSepherosa Ziehau 284415516c77SSepherosa Ziehau HN_LOCK(sc); 284515516c77SSepherosa Ziehau hn_set_chim_size(sc, chim_size); 284615516c77SSepherosa Ziehau HN_UNLOCK(sc); 284715516c77SSepherosa Ziehau return 0; 284815516c77SSepherosa Ziehau } 284915516c77SSepherosa Ziehau 285015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 285115516c77SSepherosa Ziehau static int 285215516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS) 285315516c77SSepherosa Ziehau { 285415516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 285515516c77SSepherosa Ziehau int ofs = arg2, i, error; 285615516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 285715516c77SSepherosa Ziehau uint64_t stat; 285815516c77SSepherosa Ziehau 285915516c77SSepherosa Ziehau stat = 0; 286015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 286115516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 286215516c77SSepherosa Ziehau stat += *((int *)((uint8_t *)rxr + ofs)); 286315516c77SSepherosa Ziehau } 286415516c77SSepherosa Ziehau 286515516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 286615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 286715516c77SSepherosa Ziehau return error; 286815516c77SSepherosa Ziehau 286915516c77SSepherosa Ziehau /* Zero out this stat. */ 287015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 287115516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 287215516c77SSepherosa Ziehau *((int *)((uint8_t *)rxr + ofs)) = 0; 287315516c77SSepherosa Ziehau } 287415516c77SSepherosa Ziehau return 0; 287515516c77SSepherosa Ziehau } 287615516c77SSepherosa Ziehau #else 287715516c77SSepherosa Ziehau static int 287815516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS) 287915516c77SSepherosa Ziehau { 288015516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 288115516c77SSepherosa Ziehau int ofs = arg2, i, error; 288215516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 288315516c77SSepherosa Ziehau uint64_t stat; 288415516c77SSepherosa Ziehau 288515516c77SSepherosa Ziehau stat = 0; 2886a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 288715516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 288815516c77SSepherosa Ziehau stat += *((uint64_t *)((uint8_t *)rxr + ofs)); 288915516c77SSepherosa Ziehau } 289015516c77SSepherosa Ziehau 289115516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 289215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 289315516c77SSepherosa Ziehau return error; 289415516c77SSepherosa Ziehau 289515516c77SSepherosa Ziehau /* Zero out this stat. */ 2896a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 289715516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 289815516c77SSepherosa Ziehau *((uint64_t *)((uint8_t *)rxr + ofs)) = 0; 289915516c77SSepherosa Ziehau } 290015516c77SSepherosa Ziehau return 0; 290115516c77SSepherosa Ziehau } 290215516c77SSepherosa Ziehau 290315516c77SSepherosa Ziehau #endif 290415516c77SSepherosa Ziehau 290515516c77SSepherosa Ziehau static int 290615516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 290715516c77SSepherosa Ziehau { 290815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 290915516c77SSepherosa Ziehau int ofs = arg2, i, error; 291015516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 291115516c77SSepherosa Ziehau u_long stat; 291215516c77SSepherosa Ziehau 291315516c77SSepherosa Ziehau stat = 0; 2914a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 291515516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 291615516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)rxr + ofs)); 291715516c77SSepherosa Ziehau } 291815516c77SSepherosa Ziehau 291915516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 292015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 292115516c77SSepherosa Ziehau return error; 292215516c77SSepherosa Ziehau 292315516c77SSepherosa Ziehau /* Zero out this stat. */ 2924a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 292515516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 292615516c77SSepherosa Ziehau *((u_long *)((uint8_t *)rxr + ofs)) = 0; 292715516c77SSepherosa Ziehau } 292815516c77SSepherosa Ziehau return 0; 292915516c77SSepherosa Ziehau } 293015516c77SSepherosa Ziehau 293115516c77SSepherosa Ziehau static int 293215516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 293315516c77SSepherosa Ziehau { 293415516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 293515516c77SSepherosa Ziehau int ofs = arg2, i, error; 293615516c77SSepherosa Ziehau struct hn_tx_ring *txr; 293715516c77SSepherosa Ziehau u_long stat; 293815516c77SSepherosa Ziehau 293915516c77SSepherosa Ziehau stat = 0; 2940a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 294115516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 294215516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)txr + ofs)); 294315516c77SSepherosa Ziehau } 294415516c77SSepherosa Ziehau 294515516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 294615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 294715516c77SSepherosa Ziehau return error; 294815516c77SSepherosa Ziehau 294915516c77SSepherosa Ziehau /* Zero out this stat. */ 2950a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 295115516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 295215516c77SSepherosa Ziehau *((u_long *)((uint8_t *)txr + ofs)) = 0; 295315516c77SSepherosa Ziehau } 295415516c77SSepherosa Ziehau return 0; 295515516c77SSepherosa Ziehau } 295615516c77SSepherosa Ziehau 295715516c77SSepherosa Ziehau static int 295815516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS) 295915516c77SSepherosa Ziehau { 296015516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 296115516c77SSepherosa Ziehau int ofs = arg2, i, error, conf; 296215516c77SSepherosa Ziehau struct hn_tx_ring *txr; 296315516c77SSepherosa Ziehau 296415516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[0]; 296515516c77SSepherosa Ziehau conf = *((int *)((uint8_t *)txr + ofs)); 296615516c77SSepherosa Ziehau 296715516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &conf, 0, req); 296815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 296915516c77SSepherosa Ziehau return error; 297015516c77SSepherosa Ziehau 297115516c77SSepherosa Ziehau HN_LOCK(sc); 2972a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 297315516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 297415516c77SSepherosa Ziehau *((int *)((uint8_t *)txr + ofs)) = conf; 297515516c77SSepherosa Ziehau } 297615516c77SSepherosa Ziehau HN_UNLOCK(sc); 297715516c77SSepherosa Ziehau 297815516c77SSepherosa Ziehau return 0; 297915516c77SSepherosa Ziehau } 298015516c77SSepherosa Ziehau 298115516c77SSepherosa Ziehau static int 2982dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS) 2983dc13fee6SSepherosa Ziehau { 2984dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 2985dc13fee6SSepherosa Ziehau int error, size; 2986dc13fee6SSepherosa Ziehau 2987dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 2988dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &size, 0, req); 2989dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 2990dc13fee6SSepherosa Ziehau return (error); 2991dc13fee6SSepherosa Ziehau 2992dc13fee6SSepherosa Ziehau HN_LOCK(sc); 2993dc13fee6SSepherosa Ziehau sc->hn_agg_size = size; 2994dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 2995dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 2996dc13fee6SSepherosa Ziehau 2997dc13fee6SSepherosa Ziehau return (0); 2998dc13fee6SSepherosa Ziehau } 2999dc13fee6SSepherosa Ziehau 3000dc13fee6SSepherosa Ziehau static int 3001dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS) 3002dc13fee6SSepherosa Ziehau { 3003dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 3004dc13fee6SSepherosa Ziehau int error, pkts; 3005dc13fee6SSepherosa Ziehau 3006dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 3007dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &pkts, 0, req); 3008dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 3009dc13fee6SSepherosa Ziehau return (error); 3010dc13fee6SSepherosa Ziehau 3011dc13fee6SSepherosa Ziehau HN_LOCK(sc); 3012dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = pkts; 3013dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 3014dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 3015dc13fee6SSepherosa Ziehau 3016dc13fee6SSepherosa Ziehau return (0); 3017dc13fee6SSepherosa Ziehau } 3018dc13fee6SSepherosa Ziehau 3019dc13fee6SSepherosa Ziehau static int 3020dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS) 3021dc13fee6SSepherosa Ziehau { 3022dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 3023dc13fee6SSepherosa Ziehau int pkts; 3024dc13fee6SSepherosa Ziehau 3025dc13fee6SSepherosa Ziehau pkts = sc->hn_tx_ring[0].hn_agg_pktmax; 3026dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &pkts, 0, req)); 3027dc13fee6SSepherosa Ziehau } 3028dc13fee6SSepherosa Ziehau 3029dc13fee6SSepherosa Ziehau static int 3030dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS) 3031dc13fee6SSepherosa Ziehau { 3032dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 3033dc13fee6SSepherosa Ziehau int align; 3034dc13fee6SSepherosa Ziehau 3035dc13fee6SSepherosa Ziehau align = sc->hn_tx_ring[0].hn_agg_align; 3036dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &align, 0, req)); 3037dc13fee6SSepherosa Ziehau } 3038dc13fee6SSepherosa Ziehau 30396c1204dfSSepherosa Ziehau static void 30406c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz) 30416c1204dfSSepherosa Ziehau { 30426c1204dfSSepherosa Ziehau if (pollhz == 0) 30436c1204dfSSepherosa Ziehau vmbus_chan_poll_disable(chan); 30446c1204dfSSepherosa Ziehau else 30456c1204dfSSepherosa Ziehau vmbus_chan_poll_enable(chan, pollhz); 30466c1204dfSSepherosa Ziehau } 30476c1204dfSSepherosa Ziehau 30486c1204dfSSepherosa Ziehau static void 30496c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz) 30506c1204dfSSepherosa Ziehau { 30516c1204dfSSepherosa Ziehau int nsubch = sc->hn_rx_ring_inuse - 1; 30526c1204dfSSepherosa Ziehau 30536c1204dfSSepherosa Ziehau HN_LOCK_ASSERT(sc); 30546c1204dfSSepherosa Ziehau 30556c1204dfSSepherosa Ziehau if (nsubch > 0) { 30566c1204dfSSepherosa Ziehau struct vmbus_channel **subch; 30576c1204dfSSepherosa Ziehau int i; 30586c1204dfSSepherosa Ziehau 30596c1204dfSSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 30606c1204dfSSepherosa Ziehau for (i = 0; i < nsubch; ++i) 30616c1204dfSSepherosa Ziehau hn_chan_polling(subch[i], pollhz); 30626c1204dfSSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 30636c1204dfSSepherosa Ziehau } 30646c1204dfSSepherosa Ziehau hn_chan_polling(sc->hn_prichan, pollhz); 30656c1204dfSSepherosa Ziehau } 30666c1204dfSSepherosa Ziehau 30676c1204dfSSepherosa Ziehau static int 30686c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS) 30696c1204dfSSepherosa Ziehau { 30706c1204dfSSepherosa Ziehau struct hn_softc *sc = arg1; 30716c1204dfSSepherosa Ziehau int pollhz, error; 30726c1204dfSSepherosa Ziehau 30736c1204dfSSepherosa Ziehau pollhz = sc->hn_pollhz; 30746c1204dfSSepherosa Ziehau error = sysctl_handle_int(oidp, &pollhz, 0, req); 30756c1204dfSSepherosa Ziehau if (error || req->newptr == NULL) 30766c1204dfSSepherosa Ziehau return (error); 30776c1204dfSSepherosa Ziehau 30786c1204dfSSepherosa Ziehau if (pollhz != 0 && 30796c1204dfSSepherosa Ziehau (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX)) 30806c1204dfSSepherosa Ziehau return (EINVAL); 30816c1204dfSSepherosa Ziehau 30826c1204dfSSepherosa Ziehau HN_LOCK(sc); 30836c1204dfSSepherosa Ziehau if (sc->hn_pollhz != pollhz) { 30846c1204dfSSepherosa Ziehau sc->hn_pollhz = pollhz; 30856c1204dfSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && 30866c1204dfSSepherosa Ziehau (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) 30876c1204dfSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 30886c1204dfSSepherosa Ziehau } 30896c1204dfSSepherosa Ziehau HN_UNLOCK(sc); 30906c1204dfSSepherosa Ziehau 30916c1204dfSSepherosa Ziehau return (0); 30926c1204dfSSepherosa Ziehau } 30936c1204dfSSepherosa Ziehau 3094dc13fee6SSepherosa Ziehau static int 309515516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS) 309615516c77SSepherosa Ziehau { 309715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 309815516c77SSepherosa Ziehau char verstr[16]; 309915516c77SSepherosa Ziehau 310015516c77SSepherosa Ziehau snprintf(verstr, sizeof(verstr), "%u.%u", 310115516c77SSepherosa Ziehau HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 310215516c77SSepherosa Ziehau HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 310315516c77SSepherosa Ziehau return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 310415516c77SSepherosa Ziehau } 310515516c77SSepherosa Ziehau 310615516c77SSepherosa Ziehau static int 310715516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS) 310815516c77SSepherosa Ziehau { 310915516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 311015516c77SSepherosa Ziehau char caps_str[128]; 311115516c77SSepherosa Ziehau uint32_t caps; 311215516c77SSepherosa Ziehau 311315516c77SSepherosa Ziehau HN_LOCK(sc); 311415516c77SSepherosa Ziehau caps = sc->hn_caps; 311515516c77SSepherosa Ziehau HN_UNLOCK(sc); 311615516c77SSepherosa Ziehau snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS); 311715516c77SSepherosa Ziehau return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req); 311815516c77SSepherosa Ziehau } 311915516c77SSepherosa Ziehau 312015516c77SSepherosa Ziehau static int 312115516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS) 312215516c77SSepherosa Ziehau { 312315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 312415516c77SSepherosa Ziehau char assist_str[128]; 312515516c77SSepherosa Ziehau uint32_t hwassist; 312615516c77SSepherosa Ziehau 312715516c77SSepherosa Ziehau HN_LOCK(sc); 312815516c77SSepherosa Ziehau hwassist = sc->hn_ifp->if_hwassist; 312915516c77SSepherosa Ziehau HN_UNLOCK(sc); 313015516c77SSepherosa Ziehau snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS); 313115516c77SSepherosa Ziehau return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req); 313215516c77SSepherosa Ziehau } 313315516c77SSepherosa Ziehau 313415516c77SSepherosa Ziehau static int 313515516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS) 313615516c77SSepherosa Ziehau { 313715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 313815516c77SSepherosa Ziehau char filter_str[128]; 313915516c77SSepherosa Ziehau uint32_t filter; 314015516c77SSepherosa Ziehau 314115516c77SSepherosa Ziehau HN_LOCK(sc); 314215516c77SSepherosa Ziehau filter = sc->hn_rx_filter; 314315516c77SSepherosa Ziehau HN_UNLOCK(sc); 314415516c77SSepherosa Ziehau snprintf(filter_str, sizeof(filter_str), "%b", filter, 314515516c77SSepherosa Ziehau NDIS_PACKET_TYPES); 314615516c77SSepherosa Ziehau return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req); 314715516c77SSepherosa Ziehau } 314815516c77SSepherosa Ziehau 314934d68912SSepherosa Ziehau #ifndef RSS 315034d68912SSepherosa Ziehau 315115516c77SSepherosa Ziehau static int 315215516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS) 315315516c77SSepherosa Ziehau { 315415516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 315515516c77SSepherosa Ziehau int error; 315615516c77SSepherosa Ziehau 315715516c77SSepherosa Ziehau HN_LOCK(sc); 315815516c77SSepherosa Ziehau 315915516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 316015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 316115516c77SSepherosa Ziehau goto back; 316215516c77SSepherosa Ziehau 316315516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 316415516c77SSepherosa Ziehau if (error) 316515516c77SSepherosa Ziehau goto back; 316615516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 316715516c77SSepherosa Ziehau 316815516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 316915516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 317015516c77SSepherosa Ziehau } else { 317115516c77SSepherosa Ziehau /* Not RSS capable, at least for now; just save the RSS key. */ 317215516c77SSepherosa Ziehau error = 0; 317315516c77SSepherosa Ziehau } 317415516c77SSepherosa Ziehau back: 317515516c77SSepherosa Ziehau HN_UNLOCK(sc); 317615516c77SSepherosa Ziehau return (error); 317715516c77SSepherosa Ziehau } 317815516c77SSepherosa Ziehau 317915516c77SSepherosa Ziehau static int 318015516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS) 318115516c77SSepherosa Ziehau { 318215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 318315516c77SSepherosa Ziehau int error; 318415516c77SSepherosa Ziehau 318515516c77SSepherosa Ziehau HN_LOCK(sc); 318615516c77SSepherosa Ziehau 318715516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 318815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 318915516c77SSepherosa Ziehau goto back; 319015516c77SSepherosa Ziehau 319115516c77SSepherosa Ziehau /* 319215516c77SSepherosa Ziehau * Don't allow RSS indirect table change, if this interface is not 319315516c77SSepherosa Ziehau * RSS capable currently. 319415516c77SSepherosa Ziehau */ 319515516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 319615516c77SSepherosa Ziehau error = EOPNOTSUPP; 319715516c77SSepherosa Ziehau goto back; 319815516c77SSepherosa Ziehau } 319915516c77SSepherosa Ziehau 320015516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 320115516c77SSepherosa Ziehau if (error) 320215516c77SSepherosa Ziehau goto back; 320315516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 320415516c77SSepherosa Ziehau 3205afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 320615516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 320715516c77SSepherosa Ziehau back: 320815516c77SSepherosa Ziehau HN_UNLOCK(sc); 320915516c77SSepherosa Ziehau return (error); 321015516c77SSepherosa Ziehau } 321115516c77SSepherosa Ziehau 321234d68912SSepherosa Ziehau #endif /* !RSS */ 321334d68912SSepherosa Ziehau 321415516c77SSepherosa Ziehau static int 321515516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS) 321615516c77SSepherosa Ziehau { 321715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 321815516c77SSepherosa Ziehau char hash_str[128]; 321915516c77SSepherosa Ziehau uint32_t hash; 322015516c77SSepherosa Ziehau 322115516c77SSepherosa Ziehau HN_LOCK(sc); 322215516c77SSepherosa Ziehau hash = sc->hn_rss_hash; 322315516c77SSepherosa Ziehau HN_UNLOCK(sc); 322415516c77SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 322515516c77SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 322615516c77SSepherosa Ziehau } 322715516c77SSepherosa Ziehau 322815516c77SSepherosa Ziehau static int 322940d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS) 323040d60d6eSDexuan Cui { 323140d60d6eSDexuan Cui struct hn_softc *sc = arg1; 323240d60d6eSDexuan Cui char vf_name[128]; 323340d60d6eSDexuan Cui struct ifnet *vf; 323440d60d6eSDexuan Cui 323540d60d6eSDexuan Cui HN_LOCK(sc); 323640d60d6eSDexuan Cui vf_name[0] = '\0'; 323740d60d6eSDexuan Cui vf = sc->hn_rx_ring[0].hn_vf; 323840d60d6eSDexuan Cui if (vf != NULL) 323940d60d6eSDexuan Cui snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf)); 324040d60d6eSDexuan Cui HN_UNLOCK(sc); 324140d60d6eSDexuan Cui return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); 324240d60d6eSDexuan Cui } 324340d60d6eSDexuan Cui 324440d60d6eSDexuan Cui static int 324515516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff) 324615516c77SSepherosa Ziehau { 324715516c77SSepherosa Ziehau const struct ip *ip; 324815516c77SSepherosa Ziehau int len, iphlen, iplen; 324915516c77SSepherosa Ziehau const struct tcphdr *th; 325015516c77SSepherosa Ziehau int thoff; /* TCP data offset */ 325115516c77SSepherosa Ziehau 325215516c77SSepherosa Ziehau len = hoff + sizeof(struct ip); 325315516c77SSepherosa Ziehau 325415516c77SSepherosa Ziehau /* The packet must be at least the size of an IP header. */ 325515516c77SSepherosa Ziehau if (m->m_pkthdr.len < len) 325615516c77SSepherosa Ziehau return IPPROTO_DONE; 325715516c77SSepherosa Ziehau 325815516c77SSepherosa Ziehau /* The fixed IP header must reside completely in the first mbuf. */ 325915516c77SSepherosa Ziehau if (m->m_len < len) 326015516c77SSepherosa Ziehau return IPPROTO_DONE; 326115516c77SSepherosa Ziehau 326215516c77SSepherosa Ziehau ip = mtodo(m, hoff); 326315516c77SSepherosa Ziehau 326415516c77SSepherosa Ziehau /* Bound check the packet's stated IP header length. */ 326515516c77SSepherosa Ziehau iphlen = ip->ip_hl << 2; 326615516c77SSepherosa Ziehau if (iphlen < sizeof(struct ip)) /* minimum header length */ 326715516c77SSepherosa Ziehau return IPPROTO_DONE; 326815516c77SSepherosa Ziehau 326915516c77SSepherosa Ziehau /* The full IP header must reside completely in the one mbuf. */ 327015516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen) 327115516c77SSepherosa Ziehau return IPPROTO_DONE; 327215516c77SSepherosa Ziehau 327315516c77SSepherosa Ziehau iplen = ntohs(ip->ip_len); 327415516c77SSepherosa Ziehau 327515516c77SSepherosa Ziehau /* 327615516c77SSepherosa Ziehau * Check that the amount of data in the buffers is as 327715516c77SSepherosa Ziehau * at least much as the IP header would have us expect. 327815516c77SSepherosa Ziehau */ 327915516c77SSepherosa Ziehau if (m->m_pkthdr.len < hoff + iplen) 328015516c77SSepherosa Ziehau return IPPROTO_DONE; 328115516c77SSepherosa Ziehau 328215516c77SSepherosa Ziehau /* 328315516c77SSepherosa Ziehau * Ignore IP fragments. 328415516c77SSepherosa Ziehau */ 328515516c77SSepherosa Ziehau if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF)) 328615516c77SSepherosa Ziehau return IPPROTO_DONE; 328715516c77SSepherosa Ziehau 328815516c77SSepherosa Ziehau /* 328915516c77SSepherosa Ziehau * The TCP/IP or UDP/IP header must be entirely contained within 329015516c77SSepherosa Ziehau * the first fragment of a packet. 329115516c77SSepherosa Ziehau */ 329215516c77SSepherosa Ziehau switch (ip->ip_p) { 329315516c77SSepherosa Ziehau case IPPROTO_TCP: 329415516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct tcphdr)) 329515516c77SSepherosa Ziehau return IPPROTO_DONE; 329615516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct tcphdr)) 329715516c77SSepherosa Ziehau return IPPROTO_DONE; 329815516c77SSepherosa Ziehau th = (const struct tcphdr *)((const uint8_t *)ip + iphlen); 329915516c77SSepherosa Ziehau thoff = th->th_off << 2; 330015516c77SSepherosa Ziehau if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen) 330115516c77SSepherosa Ziehau return IPPROTO_DONE; 330215516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + thoff) 330315516c77SSepherosa Ziehau return IPPROTO_DONE; 330415516c77SSepherosa Ziehau break; 330515516c77SSepherosa Ziehau case IPPROTO_UDP: 330615516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct udphdr)) 330715516c77SSepherosa Ziehau return IPPROTO_DONE; 330815516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct udphdr)) 330915516c77SSepherosa Ziehau return IPPROTO_DONE; 331015516c77SSepherosa Ziehau break; 331115516c77SSepherosa Ziehau default: 331215516c77SSepherosa Ziehau if (iplen < iphlen) 331315516c77SSepherosa Ziehau return IPPROTO_DONE; 331415516c77SSepherosa Ziehau break; 331515516c77SSepherosa Ziehau } 331615516c77SSepherosa Ziehau return ip->ip_p; 331715516c77SSepherosa Ziehau } 331815516c77SSepherosa Ziehau 331915516c77SSepherosa Ziehau static int 332015516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt) 332115516c77SSepherosa Ziehau { 332215516c77SSepherosa Ziehau struct sysctl_oid_list *child; 332315516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 332415516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 332515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 332615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 332715516c77SSepherosa Ziehau int lroent_cnt; 332815516c77SSepherosa Ziehau #endif 332915516c77SSepherosa Ziehau #endif 333015516c77SSepherosa Ziehau int i; 333115516c77SSepherosa Ziehau 333215516c77SSepherosa Ziehau /* 333315516c77SSepherosa Ziehau * Create RXBUF for reception. 333415516c77SSepherosa Ziehau * 333515516c77SSepherosa Ziehau * NOTE: 333615516c77SSepherosa Ziehau * - It is shared by all channels. 333715516c77SSepherosa Ziehau * - A large enough buffer is allocated, certain version of NVSes 333815516c77SSepherosa Ziehau * may further limit the usable space. 333915516c77SSepherosa Ziehau */ 334015516c77SSepherosa Ziehau sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 334115516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma, 334215516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 334315516c77SSepherosa Ziehau if (sc->hn_rxbuf == NULL) { 334415516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate rxbuf failed\n"); 334515516c77SSepherosa Ziehau return (ENOMEM); 334615516c77SSepherosa Ziehau } 334715516c77SSepherosa Ziehau 334815516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = ring_cnt; 334915516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt; 335015516c77SSepherosa Ziehau 335115516c77SSepherosa Ziehau sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt, 335215516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 335315516c77SSepherosa Ziehau 335415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 335515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 335615516c77SSepherosa Ziehau lroent_cnt = hn_lro_entry_count; 335715516c77SSepherosa Ziehau if (lroent_cnt < TCP_LRO_ENTRIES) 335815516c77SSepherosa Ziehau lroent_cnt = TCP_LRO_ENTRIES; 335915516c77SSepherosa Ziehau if (bootverbose) 336015516c77SSepherosa Ziehau device_printf(dev, "LRO: entry count %d\n", lroent_cnt); 336115516c77SSepherosa Ziehau #endif 336215516c77SSepherosa Ziehau #endif /* INET || INET6 */ 336315516c77SSepherosa Ziehau 336415516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 336515516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 336615516c77SSepherosa Ziehau 336715516c77SSepherosa Ziehau /* Create dev.hn.UNIT.rx sysctl tree */ 336815516c77SSepherosa Ziehau sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx", 336915516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 337015516c77SSepherosa Ziehau 337115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 337215516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 337315516c77SSepherosa Ziehau 337415516c77SSepherosa Ziehau rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 337515516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE, 337615516c77SSepherosa Ziehau &rxr->hn_br_dma, BUS_DMA_WAITOK); 337715516c77SSepherosa Ziehau if (rxr->hn_br == NULL) { 337815516c77SSepherosa Ziehau device_printf(dev, "allocate bufring failed\n"); 337915516c77SSepherosa Ziehau return (ENOMEM); 338015516c77SSepherosa Ziehau } 338115516c77SSepherosa Ziehau 338215516c77SSepherosa Ziehau if (hn_trust_hosttcp) 338315516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP; 338415516c77SSepherosa Ziehau if (hn_trust_hostudp) 338515516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP; 338615516c77SSepherosa Ziehau if (hn_trust_hostip) 338715516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP; 338815516c77SSepherosa Ziehau rxr->hn_ifp = sc->hn_ifp; 338915516c77SSepherosa Ziehau if (i < sc->hn_tx_ring_cnt) 339015516c77SSepherosa Ziehau rxr->hn_txr = &sc->hn_tx_ring[i]; 339115516c77SSepherosa Ziehau rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF; 339215516c77SSepherosa Ziehau rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK); 339315516c77SSepherosa Ziehau rxr->hn_rx_idx = i; 339415516c77SSepherosa Ziehau rxr->hn_rxbuf = sc->hn_rxbuf; 339515516c77SSepherosa Ziehau 339615516c77SSepherosa Ziehau /* 339715516c77SSepherosa Ziehau * Initialize LRO. 339815516c77SSepherosa Ziehau */ 339915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 340015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 340115516c77SSepherosa Ziehau tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt, 340215516c77SSepherosa Ziehau hn_lro_mbufq_depth); 340315516c77SSepherosa Ziehau #else 340415516c77SSepherosa Ziehau tcp_lro_init(&rxr->hn_lro); 340515516c77SSepherosa Ziehau rxr->hn_lro.ifp = sc->hn_ifp; 340615516c77SSepherosa Ziehau #endif 340715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 340815516c77SSepherosa Ziehau rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF; 340915516c77SSepherosa Ziehau rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF; 341015516c77SSepherosa Ziehau #endif 341115516c77SSepherosa Ziehau #endif /* INET || INET6 */ 341215516c77SSepherosa Ziehau 341315516c77SSepherosa Ziehau if (sc->hn_rx_sysctl_tree != NULL) { 341415516c77SSepherosa Ziehau char name[16]; 341515516c77SSepherosa Ziehau 341615516c77SSepherosa Ziehau /* 341715516c77SSepherosa Ziehau * Create per RX ring sysctl tree: 341815516c77SSepherosa Ziehau * dev.hn.UNIT.rx.RINGID 341915516c77SSepherosa Ziehau */ 342015516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", i); 342115516c77SSepherosa Ziehau rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, 342215516c77SSepherosa Ziehau SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree), 342315516c77SSepherosa Ziehau OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 342415516c77SSepherosa Ziehau 342515516c77SSepherosa Ziehau if (rxr->hn_rx_sysctl_tree != NULL) { 342615516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 342715516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 342815516c77SSepherosa Ziehau OID_AUTO, "packets", CTLFLAG_RW, 342915516c77SSepherosa Ziehau &rxr->hn_pkts, "# of packets received"); 343015516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 343115516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 343215516c77SSepherosa Ziehau OID_AUTO, "rss_pkts", CTLFLAG_RW, 343315516c77SSepherosa Ziehau &rxr->hn_rss_pkts, 343415516c77SSepherosa Ziehau "# of packets w/ RSS info received"); 343515516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, 343615516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 343715516c77SSepherosa Ziehau OID_AUTO, "pktbuf_len", CTLFLAG_RD, 343815516c77SSepherosa Ziehau &rxr->hn_pktbuf_len, 0, 343915516c77SSepherosa Ziehau "Temporary channel packet buffer length"); 344015516c77SSepherosa Ziehau } 344115516c77SSepherosa Ziehau } 344215516c77SSepherosa Ziehau } 344315516c77SSepherosa Ziehau 344415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued", 344515516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 344615516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_queued), 344715516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 344815516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 344915516c77SSepherosa Ziehau #else 345015516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 345115516c77SSepherosa Ziehau #endif 345215516c77SSepherosa Ziehau "LU", "LRO queued"); 345315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed", 345415516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 345515516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_flushed), 345615516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 345715516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 345815516c77SSepherosa Ziehau #else 345915516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 346015516c77SSepherosa Ziehau #endif 346115516c77SSepherosa Ziehau "LU", "LRO flushed"); 346215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried", 346315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 346415516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro_tried), 346515516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries"); 346615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 346715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim", 346815516c77SSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 346915516c77SSepherosa Ziehau hn_lro_lenlim_sysctl, "IU", 347015516c77SSepherosa Ziehau "Max # of data bytes to be aggregated by LRO"); 347115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim", 347215516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 347315516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl, "I", 347415516c77SSepherosa Ziehau "Max # of ACKs to be aggregated by LRO"); 347515516c77SSepherosa Ziehau #endif 347615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp", 347715516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP, 347815516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 347915516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 348015516c77SSepherosa Ziehau "when csum info is missing"); 348115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp", 348215516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP, 348315516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 348415516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 348515516c77SSepherosa Ziehau "when csum info is missing"); 348615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip", 348715516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP, 348815516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 348915516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 349015516c77SSepherosa Ziehau "when csum info is missing"); 349115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip", 349215516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 349315516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_ip), 349415516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP"); 349515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp", 349615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 349715516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_tcp), 349815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP"); 349915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp", 350015516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 350115516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_udp), 350215516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP"); 350315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted", 350415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 350515516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_trusted), 350615516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", 350715516c77SSepherosa Ziehau "# of packets that we trust host's csum verification"); 350815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts", 350915516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 351015516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_small_pkts), 351115516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of small packets received"); 351215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed", 351315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 351415516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_ack_failed), 351515516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures"); 351615516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt", 351715516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings"); 351815516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse", 351915516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings"); 352015516c77SSepherosa Ziehau 352115516c77SSepherosa Ziehau return (0); 352215516c77SSepherosa Ziehau } 352315516c77SSepherosa Ziehau 352415516c77SSepherosa Ziehau static void 352515516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc) 352615516c77SSepherosa Ziehau { 352715516c77SSepherosa Ziehau int i; 352815516c77SSepherosa Ziehau 352915516c77SSepherosa Ziehau if (sc->hn_rxbuf != NULL) { 35302494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0) 353115516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf); 35322494d735SSepherosa Ziehau else 35332494d735SSepherosa Ziehau device_printf(sc->hn_dev, "RXBUF is referenced\n"); 353415516c77SSepherosa Ziehau sc->hn_rxbuf = NULL; 353515516c77SSepherosa Ziehau } 353615516c77SSepherosa Ziehau 353715516c77SSepherosa Ziehau if (sc->hn_rx_ring_cnt == 0) 353815516c77SSepherosa Ziehau return; 353915516c77SSepherosa Ziehau 354015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 354115516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 354215516c77SSepherosa Ziehau 354315516c77SSepherosa Ziehau if (rxr->hn_br == NULL) 354415516c77SSepherosa Ziehau continue; 35452494d735SSepherosa Ziehau if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) { 354615516c77SSepherosa Ziehau hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br); 35472494d735SSepherosa Ziehau } else { 35482494d735SSepherosa Ziehau device_printf(sc->hn_dev, 35492494d735SSepherosa Ziehau "%dth channel bufring is referenced", i); 35502494d735SSepherosa Ziehau } 355115516c77SSepherosa Ziehau rxr->hn_br = NULL; 355215516c77SSepherosa Ziehau 355315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 355415516c77SSepherosa Ziehau tcp_lro_free(&rxr->hn_lro); 355515516c77SSepherosa Ziehau #endif 355615516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 355715516c77SSepherosa Ziehau } 355815516c77SSepherosa Ziehau free(sc->hn_rx_ring, M_DEVBUF); 355915516c77SSepherosa Ziehau sc->hn_rx_ring = NULL; 356015516c77SSepherosa Ziehau 356115516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = 0; 356215516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = 0; 356315516c77SSepherosa Ziehau } 356415516c77SSepherosa Ziehau 356515516c77SSepherosa Ziehau static int 356615516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id) 356715516c77SSepherosa Ziehau { 356815516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[id]; 356915516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 357015516c77SSepherosa Ziehau bus_dma_tag_t parent_dtag; 357115516c77SSepherosa Ziehau int error, i; 357215516c77SSepherosa Ziehau 357315516c77SSepherosa Ziehau txr->hn_sc = sc; 357415516c77SSepherosa Ziehau txr->hn_tx_idx = id; 357515516c77SSepherosa Ziehau 357615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 357715516c77SSepherosa Ziehau mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); 357815516c77SSepherosa Ziehau #endif 357915516c77SSepherosa Ziehau mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF); 358015516c77SSepherosa Ziehau 358115516c77SSepherosa Ziehau txr->hn_txdesc_cnt = HN_TX_DESC_CNT; 358215516c77SSepherosa Ziehau txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt, 358315516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 358415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 358515516c77SSepherosa Ziehau SLIST_INIT(&txr->hn_txlist); 358615516c77SSepherosa Ziehau #else 358715516c77SSepherosa Ziehau txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF, 358815516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 358915516c77SSepherosa Ziehau #endif 359015516c77SSepherosa Ziehau 35910e11868dSSepherosa Ziehau if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) { 35920e11868dSSepherosa Ziehau txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ( 35930e11868dSSepherosa Ziehau device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id)); 35940e11868dSSepherosa Ziehau } else { 3595fdd0222aSSepherosa Ziehau txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt]; 35960e11868dSSepherosa Ziehau } 359715516c77SSepherosa Ziehau 359823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 359915516c77SSepherosa Ziehau if (hn_use_if_start) { 360015516c77SSepherosa Ziehau txr->hn_txeof = hn_start_txeof; 360115516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr); 360215516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr); 360323bf9e15SSepherosa Ziehau } else 360423bf9e15SSepherosa Ziehau #endif 360523bf9e15SSepherosa Ziehau { 360615516c77SSepherosa Ziehau int br_depth; 360715516c77SSepherosa Ziehau 360815516c77SSepherosa Ziehau txr->hn_txeof = hn_xmit_txeof; 360915516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr); 361015516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr); 361115516c77SSepherosa Ziehau 361215516c77SSepherosa Ziehau br_depth = hn_get_txswq_depth(txr); 361315516c77SSepherosa Ziehau txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF, 361415516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 361515516c77SSepherosa Ziehau } 361615516c77SSepherosa Ziehau 361715516c77SSepherosa Ziehau txr->hn_direct_tx_size = hn_direct_tx_size; 361815516c77SSepherosa Ziehau 361915516c77SSepherosa Ziehau /* 362015516c77SSepherosa Ziehau * Always schedule transmission instead of trying to do direct 362115516c77SSepherosa Ziehau * transmission. This one gives the best performance so far. 362215516c77SSepherosa Ziehau */ 362315516c77SSepherosa Ziehau txr->hn_sched_tx = 1; 362415516c77SSepherosa Ziehau 362515516c77SSepherosa Ziehau parent_dtag = bus_get_dma_tag(dev); 362615516c77SSepherosa Ziehau 362715516c77SSepherosa Ziehau /* DMA tag for RNDIS packet messages. */ 362815516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 362915516c77SSepherosa Ziehau HN_RNDIS_PKT_ALIGN, /* alignment */ 363015516c77SSepherosa Ziehau HN_RNDIS_PKT_BOUNDARY, /* boundary */ 363115516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 363215516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 363315516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 363415516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsize */ 363515516c77SSepherosa Ziehau 1, /* nsegments */ 363615516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsegsize */ 363715516c77SSepherosa Ziehau 0, /* flags */ 363815516c77SSepherosa Ziehau NULL, /* lockfunc */ 363915516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 364015516c77SSepherosa Ziehau &txr->hn_tx_rndis_dtag); 364115516c77SSepherosa Ziehau if (error) { 364215516c77SSepherosa Ziehau device_printf(dev, "failed to create rndis dmatag\n"); 364315516c77SSepherosa Ziehau return error; 364415516c77SSepherosa Ziehau } 364515516c77SSepherosa Ziehau 364615516c77SSepherosa Ziehau /* DMA tag for data. */ 364715516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 364815516c77SSepherosa Ziehau 1, /* alignment */ 364915516c77SSepherosa Ziehau HN_TX_DATA_BOUNDARY, /* boundary */ 365015516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 365115516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 365215516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 365315516c77SSepherosa Ziehau HN_TX_DATA_MAXSIZE, /* maxsize */ 365415516c77SSepherosa Ziehau HN_TX_DATA_SEGCNT_MAX, /* nsegments */ 365515516c77SSepherosa Ziehau HN_TX_DATA_SEGSIZE, /* maxsegsize */ 365615516c77SSepherosa Ziehau 0, /* flags */ 365715516c77SSepherosa Ziehau NULL, /* lockfunc */ 365815516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 365915516c77SSepherosa Ziehau &txr->hn_tx_data_dtag); 366015516c77SSepherosa Ziehau if (error) { 366115516c77SSepherosa Ziehau device_printf(dev, "failed to create data dmatag\n"); 366215516c77SSepherosa Ziehau return error; 366315516c77SSepherosa Ziehau } 366415516c77SSepherosa Ziehau 366515516c77SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) { 366615516c77SSepherosa Ziehau struct hn_txdesc *txd = &txr->hn_txdesc[i]; 366715516c77SSepherosa Ziehau 366815516c77SSepherosa Ziehau txd->txr = txr; 366915516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 3670dc13fee6SSepherosa Ziehau STAILQ_INIT(&txd->agg_list); 367115516c77SSepherosa Ziehau 367215516c77SSepherosa Ziehau /* 367315516c77SSepherosa Ziehau * Allocate and load RNDIS packet message. 367415516c77SSepherosa Ziehau */ 367515516c77SSepherosa Ziehau error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag, 367615516c77SSepherosa Ziehau (void **)&txd->rndis_pkt, 367715516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 367815516c77SSepherosa Ziehau &txd->rndis_pkt_dmap); 367915516c77SSepherosa Ziehau if (error) { 368015516c77SSepherosa Ziehau device_printf(dev, 368115516c77SSepherosa Ziehau "failed to allocate rndis_packet_msg, %d\n", i); 368215516c77SSepherosa Ziehau return error; 368315516c77SSepherosa Ziehau } 368415516c77SSepherosa Ziehau 368515516c77SSepherosa Ziehau error = bus_dmamap_load(txr->hn_tx_rndis_dtag, 368615516c77SSepherosa Ziehau txd->rndis_pkt_dmap, 368715516c77SSepherosa Ziehau txd->rndis_pkt, HN_RNDIS_PKT_LEN, 368815516c77SSepherosa Ziehau hyperv_dma_map_paddr, &txd->rndis_pkt_paddr, 368915516c77SSepherosa Ziehau BUS_DMA_NOWAIT); 369015516c77SSepherosa Ziehau if (error) { 369115516c77SSepherosa Ziehau device_printf(dev, 369215516c77SSepherosa Ziehau "failed to load rndis_packet_msg, %d\n", i); 369315516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 369415516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 369515516c77SSepherosa Ziehau return error; 369615516c77SSepherosa Ziehau } 369715516c77SSepherosa Ziehau 369815516c77SSepherosa Ziehau /* DMA map for TX data. */ 369915516c77SSepherosa Ziehau error = bus_dmamap_create(txr->hn_tx_data_dtag, 0, 370015516c77SSepherosa Ziehau &txd->data_dmap); 370115516c77SSepherosa Ziehau if (error) { 370215516c77SSepherosa Ziehau device_printf(dev, 370315516c77SSepherosa Ziehau "failed to allocate tx data dmamap\n"); 370415516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, 370515516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 370615516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 370715516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 370815516c77SSepherosa Ziehau return error; 370915516c77SSepherosa Ziehau } 371015516c77SSepherosa Ziehau 371115516c77SSepherosa Ziehau /* All set, put it to list */ 371215516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 371315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 371415516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 371515516c77SSepherosa Ziehau #else 371615516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 371715516c77SSepherosa Ziehau #endif 371815516c77SSepherosa Ziehau } 371915516c77SSepherosa Ziehau txr->hn_txdesc_avail = txr->hn_txdesc_cnt; 372015516c77SSepherosa Ziehau 372115516c77SSepherosa Ziehau if (sc->hn_tx_sysctl_tree != NULL) { 372215516c77SSepherosa Ziehau struct sysctl_oid_list *child; 372315516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 372415516c77SSepherosa Ziehau char name[16]; 372515516c77SSepherosa Ziehau 372615516c77SSepherosa Ziehau /* 372715516c77SSepherosa Ziehau * Create per TX ring sysctl tree: 372815516c77SSepherosa Ziehau * dev.hn.UNIT.tx.RINGID 372915516c77SSepherosa Ziehau */ 373015516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 373115516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree); 373215516c77SSepherosa Ziehau 373315516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", id); 373415516c77SSepherosa Ziehau txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, 373515516c77SSepherosa Ziehau name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 373615516c77SSepherosa Ziehau 373715516c77SSepherosa Ziehau if (txr->hn_tx_sysctl_tree != NULL) { 373815516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree); 373915516c77SSepherosa Ziehau 374085e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG 374115516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail", 374215516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_txdesc_avail, 0, 374315516c77SSepherosa Ziehau "# of available TX descs"); 374485e4ae1eSSepherosa Ziehau #endif 374523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 374623bf9e15SSepherosa Ziehau if (!hn_use_if_start) 374723bf9e15SSepherosa Ziehau #endif 374823bf9e15SSepherosa Ziehau { 374915516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive", 375015516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_oactive, 0, 375115516c77SSepherosa Ziehau "over active"); 375215516c77SSepherosa Ziehau } 375315516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets", 375415516c77SSepherosa Ziehau CTLFLAG_RW, &txr->hn_pkts, 375515516c77SSepherosa Ziehau "# of packets transmitted"); 3756dc13fee6SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends", 3757dc13fee6SSepherosa Ziehau CTLFLAG_RW, &txr->hn_sends, "# of sends"); 375815516c77SSepherosa Ziehau } 375915516c77SSepherosa Ziehau } 376015516c77SSepherosa Ziehau 376115516c77SSepherosa Ziehau return 0; 376215516c77SSepherosa Ziehau } 376315516c77SSepherosa Ziehau 376415516c77SSepherosa Ziehau static void 376515516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd) 376615516c77SSepherosa Ziehau { 376715516c77SSepherosa Ziehau struct hn_tx_ring *txr = txd->txr; 376815516c77SSepherosa Ziehau 376915516c77SSepherosa Ziehau KASSERT(txd->m == NULL, ("still has mbuf installed")); 377015516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped")); 377115516c77SSepherosa Ziehau 377215516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap); 377315516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt, 377415516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 377515516c77SSepherosa Ziehau bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap); 377615516c77SSepherosa Ziehau } 377715516c77SSepherosa Ziehau 377815516c77SSepherosa Ziehau static void 377925641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd) 378025641fc7SSepherosa Ziehau { 378125641fc7SSepherosa Ziehau 378225641fc7SSepherosa Ziehau KASSERT(txd->refs == 0 || txd->refs == 1, 378325641fc7SSepherosa Ziehau ("invalid txd refs %d", txd->refs)); 378425641fc7SSepherosa Ziehau 378525641fc7SSepherosa Ziehau /* Aggregated txds will be freed by their aggregating txd. */ 378625641fc7SSepherosa Ziehau if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) { 378725641fc7SSepherosa Ziehau int freed; 378825641fc7SSepherosa Ziehau 378925641fc7SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 379025641fc7SSepherosa Ziehau KASSERT(freed, ("can't free txdesc")); 379125641fc7SSepherosa Ziehau } 379225641fc7SSepherosa Ziehau } 379325641fc7SSepherosa Ziehau 379425641fc7SSepherosa Ziehau static void 379515516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr) 379615516c77SSepherosa Ziehau { 379725641fc7SSepherosa Ziehau int i; 379815516c77SSepherosa Ziehau 379915516c77SSepherosa Ziehau if (txr->hn_txdesc == NULL) 380015516c77SSepherosa Ziehau return; 380115516c77SSepherosa Ziehau 380225641fc7SSepherosa Ziehau /* 380325641fc7SSepherosa Ziehau * NOTE: 380425641fc7SSepherosa Ziehau * Because the freeing of aggregated txds will be deferred 380525641fc7SSepherosa Ziehau * to the aggregating txd, two passes are used here: 380625641fc7SSepherosa Ziehau * - The first pass GCes any pending txds. This GC is necessary, 380725641fc7SSepherosa Ziehau * since if the channels are revoked, hypervisor will not 380825641fc7SSepherosa Ziehau * deliver send-done for all pending txds. 380925641fc7SSepherosa Ziehau * - The second pass frees the busdma stuffs, i.e. after all txds 381025641fc7SSepherosa Ziehau * were freed. 381125641fc7SSepherosa Ziehau */ 381225641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 381325641fc7SSepherosa Ziehau hn_txdesc_gc(txr, &txr->hn_txdesc[i]); 381425641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 381525641fc7SSepherosa Ziehau hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]); 381615516c77SSepherosa Ziehau 381715516c77SSepherosa Ziehau if (txr->hn_tx_data_dtag != NULL) 381815516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_data_dtag); 381915516c77SSepherosa Ziehau if (txr->hn_tx_rndis_dtag != NULL) 382015516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_rndis_dtag); 382115516c77SSepherosa Ziehau 382215516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 382315516c77SSepherosa Ziehau buf_ring_free(txr->hn_txdesc_br, M_DEVBUF); 382415516c77SSepherosa Ziehau #endif 382515516c77SSepherosa Ziehau 382615516c77SSepherosa Ziehau free(txr->hn_txdesc, M_DEVBUF); 382715516c77SSepherosa Ziehau txr->hn_txdesc = NULL; 382815516c77SSepherosa Ziehau 382915516c77SSepherosa Ziehau if (txr->hn_mbuf_br != NULL) 383015516c77SSepherosa Ziehau buf_ring_free(txr->hn_mbuf_br, M_DEVBUF); 383115516c77SSepherosa Ziehau 383215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 383315516c77SSepherosa Ziehau mtx_destroy(&txr->hn_txlist_spin); 383415516c77SSepherosa Ziehau #endif 383515516c77SSepherosa Ziehau mtx_destroy(&txr->hn_tx_lock); 383615516c77SSepherosa Ziehau } 383715516c77SSepherosa Ziehau 383815516c77SSepherosa Ziehau static int 383915516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt) 384015516c77SSepherosa Ziehau { 384115516c77SSepherosa Ziehau struct sysctl_oid_list *child; 384215516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 384315516c77SSepherosa Ziehau int i; 384415516c77SSepherosa Ziehau 384515516c77SSepherosa Ziehau /* 384615516c77SSepherosa Ziehau * Create TXBUF for chimney sending. 384715516c77SSepherosa Ziehau * 384815516c77SSepherosa Ziehau * NOTE: It is shared by all channels. 384915516c77SSepherosa Ziehau */ 385015516c77SSepherosa Ziehau sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), 385115516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma, 385215516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 385315516c77SSepherosa Ziehau if (sc->hn_chim == NULL) { 385415516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate txbuf failed\n"); 385515516c77SSepherosa Ziehau return (ENOMEM); 385615516c77SSepherosa Ziehau } 385715516c77SSepherosa Ziehau 385815516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = ring_cnt; 385915516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 386015516c77SSepherosa Ziehau 386115516c77SSepherosa Ziehau sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt, 386215516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 386315516c77SSepherosa Ziehau 386415516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(sc->hn_dev); 386515516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev)); 386615516c77SSepherosa Ziehau 386715516c77SSepherosa Ziehau /* Create dev.hn.UNIT.tx sysctl tree */ 386815516c77SSepherosa Ziehau sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx", 386915516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 387015516c77SSepherosa Ziehau 387115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 387215516c77SSepherosa Ziehau int error; 387315516c77SSepherosa Ziehau 387415516c77SSepherosa Ziehau error = hn_tx_ring_create(sc, i); 387515516c77SSepherosa Ziehau if (error) 387615516c77SSepherosa Ziehau return error; 387715516c77SSepherosa Ziehau } 387815516c77SSepherosa Ziehau 387915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs", 388015516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 388115516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_no_txdescs), 388215516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs"); 388315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed", 388415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 388515516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_send_failed), 388615516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure"); 388715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed", 388815516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 388915516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_txdma_failed), 389015516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure"); 3891dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed", 3892dc13fee6SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 3893dc13fee6SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_flush_failed), 3894dc13fee6SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", 3895dc13fee6SSepherosa Ziehau "# of packet transmission aggregation flush failure"); 389615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed", 389715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 389815516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_collapsed), 389915516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed"); 390015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney", 390115516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 390215516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney), 390315516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send"); 390415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried", 390515516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 390615516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney_tried), 390715516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries"); 390815516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt", 390915516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0, 391015516c77SSepherosa Ziehau "# of total TX descs"); 391115516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max", 391215516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_chim_szmax, 0, 391315516c77SSepherosa Ziehau "Chimney send packet size upper boundary"); 391415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size", 391515516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 391615516c77SSepherosa Ziehau hn_chim_size_sysctl, "I", "Chimney send packet size limit"); 391715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size", 391815516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 391915516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_direct_tx_size), 392015516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 392115516c77SSepherosa Ziehau "Size of the packet for direct transmission"); 392215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx", 392315516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 392415516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_sched_tx), 392515516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 392615516c77SSepherosa Ziehau "Always schedule transmission " 392715516c77SSepherosa Ziehau "instead of doing direct transmission"); 392815516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt", 392915516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings"); 393015516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse", 393115516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings"); 3932dc13fee6SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax", 3933dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0, 3934dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation size"); 3935dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax", 3936dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 3937dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl, "I", 3938dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation packets"); 3939dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align", 3940dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 3941dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl, "I", 3942dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation alignment"); 394315516c77SSepherosa Ziehau 394415516c77SSepherosa Ziehau return 0; 394515516c77SSepherosa Ziehau } 394615516c77SSepherosa Ziehau 394715516c77SSepherosa Ziehau static void 394815516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size) 394915516c77SSepherosa Ziehau { 395015516c77SSepherosa Ziehau int i; 395115516c77SSepherosa Ziehau 3952a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 395315516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_chim_size = chim_size; 395415516c77SSepherosa Ziehau } 395515516c77SSepherosa Ziehau 395615516c77SSepherosa Ziehau static void 395715516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu) 395815516c77SSepherosa Ziehau { 395915516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 396015516c77SSepherosa Ziehau int tso_minlen; 396115516c77SSepherosa Ziehau 396215516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0) 396315516c77SSepherosa Ziehau return; 396415516c77SSepherosa Ziehau 396515516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_sgmin >= 2, 396615516c77SSepherosa Ziehau ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin)); 396715516c77SSepherosa Ziehau tso_minlen = sc->hn_ndis_tso_sgmin * mtu; 396815516c77SSepherosa Ziehau 396915516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen && 397015516c77SSepherosa Ziehau sc->hn_ndis_tso_szmax <= IP_MAXPACKET, 397115516c77SSepherosa Ziehau ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax)); 397215516c77SSepherosa Ziehau 397315516c77SSepherosa Ziehau if (tso_maxlen < tso_minlen) 397415516c77SSepherosa Ziehau tso_maxlen = tso_minlen; 397515516c77SSepherosa Ziehau else if (tso_maxlen > IP_MAXPACKET) 397615516c77SSepherosa Ziehau tso_maxlen = IP_MAXPACKET; 397715516c77SSepherosa Ziehau if (tso_maxlen > sc->hn_ndis_tso_szmax) 397815516c77SSepherosa Ziehau tso_maxlen = sc->hn_ndis_tso_szmax; 397915516c77SSepherosa Ziehau ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 398015516c77SSepherosa Ziehau if (bootverbose) 398115516c77SSepherosa Ziehau if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax); 398215516c77SSepherosa Ziehau } 398315516c77SSepherosa Ziehau 398415516c77SSepherosa Ziehau static void 398515516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc) 398615516c77SSepherosa Ziehau { 398715516c77SSepherosa Ziehau uint64_t csum_assist; 398815516c77SSepherosa Ziehau int i; 398915516c77SSepherosa Ziehau 399015516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 399115516c77SSepherosa Ziehau if (hn_tx_chimney_size > 0 && 399215516c77SSepherosa Ziehau hn_tx_chimney_size < sc->hn_chim_szmax) 399315516c77SSepherosa Ziehau hn_set_chim_size(sc, hn_tx_chimney_size); 399415516c77SSepherosa Ziehau 399515516c77SSepherosa Ziehau csum_assist = 0; 399615516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_IPCS) 399715516c77SSepherosa Ziehau csum_assist |= CSUM_IP; 399815516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP4CS) 399915516c77SSepherosa Ziehau csum_assist |= CSUM_IP_TCP; 400015516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP4CS) 400115516c77SSepherosa Ziehau csum_assist |= CSUM_IP_UDP; 400215516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP6CS) 400315516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_TCP; 400415516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP6CS) 400515516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_UDP; 400615516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 400715516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_csum_assist = csum_assist; 400815516c77SSepherosa Ziehau 400915516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_HASHVAL) { 401015516c77SSepherosa Ziehau /* 401115516c77SSepherosa Ziehau * Support HASHVAL pktinfo on TX path. 401215516c77SSepherosa Ziehau */ 401315516c77SSepherosa Ziehau if (bootverbose) 401415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n"); 401515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 401615516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL; 401715516c77SSepherosa Ziehau } 401815516c77SSepherosa Ziehau } 401915516c77SSepherosa Ziehau 402015516c77SSepherosa Ziehau static void 402115516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc) 402215516c77SSepherosa Ziehau { 402315516c77SSepherosa Ziehau int i; 402415516c77SSepherosa Ziehau 402515516c77SSepherosa Ziehau if (sc->hn_chim != NULL) { 40262494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) { 402715516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim); 40282494d735SSepherosa Ziehau } else { 40292494d735SSepherosa Ziehau device_printf(sc->hn_dev, 40302494d735SSepherosa Ziehau "chimney sending buffer is referenced"); 40312494d735SSepherosa Ziehau } 403215516c77SSepherosa Ziehau sc->hn_chim = NULL; 403315516c77SSepherosa Ziehau } 403415516c77SSepherosa Ziehau 403515516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt == 0) 403615516c77SSepherosa Ziehau return; 403715516c77SSepherosa Ziehau 403815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 403915516c77SSepherosa Ziehau hn_tx_ring_destroy(&sc->hn_tx_ring[i]); 404015516c77SSepherosa Ziehau 404115516c77SSepherosa Ziehau free(sc->hn_tx_ring, M_DEVBUF); 404215516c77SSepherosa Ziehau sc->hn_tx_ring = NULL; 404315516c77SSepherosa Ziehau 404415516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = 0; 404515516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = 0; 404615516c77SSepherosa Ziehau } 404715516c77SSepherosa Ziehau 404823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 404923bf9e15SSepherosa Ziehau 405015516c77SSepherosa Ziehau static void 405115516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused) 405215516c77SSepherosa Ziehau { 405315516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 405415516c77SSepherosa Ziehau 405515516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 405615516c77SSepherosa Ziehau hn_start_locked(txr, 0); 405715516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 405815516c77SSepherosa Ziehau } 405915516c77SSepherosa Ziehau 406023bf9e15SSepherosa Ziehau static int 406123bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len) 406223bf9e15SSepherosa Ziehau { 406323bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 406423bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 4065dc13fee6SSepherosa Ziehau int sched = 0; 406623bf9e15SSepherosa Ziehau 406723bf9e15SSepherosa Ziehau KASSERT(hn_use_if_start, 406823bf9e15SSepherosa Ziehau ("hn_start_locked is called, when if_start is disabled")); 406923bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 407023bf9e15SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 4071dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 407223bf9e15SSepherosa Ziehau 407323bf9e15SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 4074dc13fee6SSepherosa Ziehau return (0); 407523bf9e15SSepherosa Ziehau 407623bf9e15SSepherosa Ziehau if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 407723bf9e15SSepherosa Ziehau IFF_DRV_RUNNING) 4078dc13fee6SSepherosa Ziehau return (0); 407923bf9e15SSepherosa Ziehau 408023bf9e15SSepherosa Ziehau while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 408123bf9e15SSepherosa Ziehau struct hn_txdesc *txd; 408223bf9e15SSepherosa Ziehau struct mbuf *m_head; 408323bf9e15SSepherosa Ziehau int error; 408423bf9e15SSepherosa Ziehau 408523bf9e15SSepherosa Ziehau IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 408623bf9e15SSepherosa Ziehau if (m_head == NULL) 408723bf9e15SSepherosa Ziehau break; 408823bf9e15SSepherosa Ziehau 408923bf9e15SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 409023bf9e15SSepherosa Ziehau /* 409123bf9e15SSepherosa Ziehau * This sending could be time consuming; let callers 409223bf9e15SSepherosa Ziehau * dispatch this packet sending (and sending of any 409323bf9e15SSepherosa Ziehau * following up packets) to tx taskqueue. 409423bf9e15SSepherosa Ziehau */ 409523bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 4096dc13fee6SSepherosa Ziehau sched = 1; 4097dc13fee6SSepherosa Ziehau break; 409823bf9e15SSepherosa Ziehau } 409923bf9e15SSepherosa Ziehau 4100edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 4101edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 4102edd3f315SSepherosa Ziehau m_head = hn_tso_fixup(m_head); 4103edd3f315SSepherosa Ziehau if (__predict_false(m_head == NULL)) { 4104edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 4105edd3f315SSepherosa Ziehau continue; 4106edd3f315SSepherosa Ziehau } 4107edd3f315SSepherosa Ziehau } 4108edd3f315SSepherosa Ziehau #endif 4109edd3f315SSepherosa Ziehau 411023bf9e15SSepherosa Ziehau txd = hn_txdesc_get(txr); 411123bf9e15SSepherosa Ziehau if (txd == NULL) { 411223bf9e15SSepherosa Ziehau txr->hn_no_txdescs++; 411323bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 411423bf9e15SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 411523bf9e15SSepherosa Ziehau break; 411623bf9e15SSepherosa Ziehau } 411723bf9e15SSepherosa Ziehau 4118dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 411923bf9e15SSepherosa Ziehau if (error) { 412023bf9e15SSepherosa Ziehau /* Both txd and m_head are freed */ 4121dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 4122dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 412323bf9e15SSepherosa Ziehau continue; 412423bf9e15SSepherosa Ziehau } 412523bf9e15SSepherosa Ziehau 4126dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 4127dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 4128dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 4129dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 4130dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 4131dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 4132dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 4133dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 4134dc13fee6SSepherosa Ziehau break; 4135dc13fee6SSepherosa Ziehau } 4136dc13fee6SSepherosa Ziehau } else { 4137dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 413823bf9e15SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 413923bf9e15SSepherosa Ziehau if (__predict_false(error)) { 414023bf9e15SSepherosa Ziehau /* txd is freed, but m_head is not */ 414123bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 4142dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 4143dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 414423bf9e15SSepherosa Ziehau break; 414523bf9e15SSepherosa Ziehau } 414623bf9e15SSepherosa Ziehau } 4147dc13fee6SSepherosa Ziehau } 4148dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 4149dc13fee6SSepherosa Ziehau else { 4150dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 4151dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 4152dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 4153dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 4154dc13fee6SSepherosa Ziehau } 4155dc13fee6SSepherosa Ziehau #endif 4156dc13fee6SSepherosa Ziehau } 4157dc13fee6SSepherosa Ziehau 4158dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 4159dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 4160dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 4161dc13fee6SSepherosa Ziehau return (sched); 416223bf9e15SSepherosa Ziehau } 416323bf9e15SSepherosa Ziehau 416423bf9e15SSepherosa Ziehau static void 416523bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp) 416623bf9e15SSepherosa Ziehau { 416723bf9e15SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 416823bf9e15SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[0]; 416923bf9e15SSepherosa Ziehau 417023bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 417123bf9e15SSepherosa Ziehau goto do_sched; 417223bf9e15SSepherosa Ziehau 417323bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 417423bf9e15SSepherosa Ziehau int sched; 417523bf9e15SSepherosa Ziehau 417623bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 417723bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 417823bf9e15SSepherosa Ziehau if (!sched) 417923bf9e15SSepherosa Ziehau return; 418023bf9e15SSepherosa Ziehau } 418123bf9e15SSepherosa Ziehau do_sched: 418223bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 418323bf9e15SSepherosa Ziehau } 418423bf9e15SSepherosa Ziehau 418515516c77SSepherosa Ziehau static void 418615516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused) 418715516c77SSepherosa Ziehau { 418815516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 418915516c77SSepherosa Ziehau 419015516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 419115516c77SSepherosa Ziehau atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE); 419215516c77SSepherosa Ziehau hn_start_locked(txr, 0); 419315516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 419415516c77SSepherosa Ziehau } 419515516c77SSepherosa Ziehau 419623bf9e15SSepherosa Ziehau static void 419723bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr) 419823bf9e15SSepherosa Ziehau { 419923bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 420023bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 420123bf9e15SSepherosa Ziehau 420223bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 420323bf9e15SSepherosa Ziehau 420423bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 420523bf9e15SSepherosa Ziehau goto do_sched; 420623bf9e15SSepherosa Ziehau 420723bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 420823bf9e15SSepherosa Ziehau int sched; 420923bf9e15SSepherosa Ziehau 421023bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 421123bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 421223bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 421323bf9e15SSepherosa Ziehau if (sched) { 421423bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 421523bf9e15SSepherosa Ziehau &txr->hn_tx_task); 421623bf9e15SSepherosa Ziehau } 421723bf9e15SSepherosa Ziehau } else { 421823bf9e15SSepherosa Ziehau do_sched: 421923bf9e15SSepherosa Ziehau /* 422023bf9e15SSepherosa Ziehau * Release the OACTIVE earlier, with the hope, that 422123bf9e15SSepherosa Ziehau * others could catch up. The task will clear the 422223bf9e15SSepherosa Ziehau * flag again with the hn_tx_lock to avoid possible 422323bf9e15SSepherosa Ziehau * races. 422423bf9e15SSepherosa Ziehau */ 422523bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 422623bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 422723bf9e15SSepherosa Ziehau } 422823bf9e15SSepherosa Ziehau } 422923bf9e15SSepherosa Ziehau 423023bf9e15SSepherosa Ziehau #endif /* HN_IFSTART_SUPPORT */ 423123bf9e15SSepherosa Ziehau 423215516c77SSepherosa Ziehau static int 423315516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len) 423415516c77SSepherosa Ziehau { 423515516c77SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 423615516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 423715516c77SSepherosa Ziehau struct mbuf *m_head; 4238dc13fee6SSepherosa Ziehau int sched = 0; 423915516c77SSepherosa Ziehau 424015516c77SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 424123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 424215516c77SSepherosa Ziehau KASSERT(hn_use_if_start == 0, 424315516c77SSepherosa Ziehau ("hn_xmit is called, when if_start is enabled")); 424423bf9e15SSepherosa Ziehau #endif 4245dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 424615516c77SSepherosa Ziehau 424715516c77SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 4248dc13fee6SSepherosa Ziehau return (0); 424915516c77SSepherosa Ziehau 425015516c77SSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive) 4251dc13fee6SSepherosa Ziehau return (0); 425215516c77SSepherosa Ziehau 425315516c77SSepherosa Ziehau while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) { 425415516c77SSepherosa Ziehau struct hn_txdesc *txd; 425515516c77SSepherosa Ziehau int error; 425615516c77SSepherosa Ziehau 425715516c77SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 425815516c77SSepherosa Ziehau /* 425915516c77SSepherosa Ziehau * This sending could be time consuming; let callers 426015516c77SSepherosa Ziehau * dispatch this packet sending (and sending of any 426115516c77SSepherosa Ziehau * following up packets) to tx taskqueue. 426215516c77SSepherosa Ziehau */ 426315516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 4264dc13fee6SSepherosa Ziehau sched = 1; 4265dc13fee6SSepherosa Ziehau break; 426615516c77SSepherosa Ziehau } 426715516c77SSepherosa Ziehau 426815516c77SSepherosa Ziehau txd = hn_txdesc_get(txr); 426915516c77SSepherosa Ziehau if (txd == NULL) { 427015516c77SSepherosa Ziehau txr->hn_no_txdescs++; 427115516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 427215516c77SSepherosa Ziehau txr->hn_oactive = 1; 427315516c77SSepherosa Ziehau break; 427415516c77SSepherosa Ziehau } 427515516c77SSepherosa Ziehau 4276dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 427715516c77SSepherosa Ziehau if (error) { 427815516c77SSepherosa Ziehau /* Both txd and m_head are freed; discard */ 4279dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 4280dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 428115516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 428215516c77SSepherosa Ziehau continue; 428315516c77SSepherosa Ziehau } 428415516c77SSepherosa Ziehau 4285dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 4286dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 4287dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 4288dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 4289dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 429015516c77SSepherosa Ziehau if (__predict_false(error)) { 429115516c77SSepherosa Ziehau txr->hn_oactive = 1; 429215516c77SSepherosa Ziehau break; 429315516c77SSepherosa Ziehau } 4294dc13fee6SSepherosa Ziehau } else { 4295dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 4296dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 4297dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 4298dc13fee6SSepherosa Ziehau /* txd is freed, but m_head is not */ 4299dc13fee6SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, 4300dc13fee6SSepherosa Ziehau m_head); 4301dc13fee6SSepherosa Ziehau txr->hn_oactive = 1; 4302dc13fee6SSepherosa Ziehau break; 4303dc13fee6SSepherosa Ziehau } 4304dc13fee6SSepherosa Ziehau } 4305dc13fee6SSepherosa Ziehau } 4306dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 4307dc13fee6SSepherosa Ziehau else { 4308dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 4309dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 4310dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 4311dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 4312dc13fee6SSepherosa Ziehau } 4313dc13fee6SSepherosa Ziehau #endif 431415516c77SSepherosa Ziehau 431515516c77SSepherosa Ziehau /* Sent */ 431615516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 431715516c77SSepherosa Ziehau } 4318dc13fee6SSepherosa Ziehau 4319dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 4320dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 4321dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 4322dc13fee6SSepherosa Ziehau return (sched); 432315516c77SSepherosa Ziehau } 432415516c77SSepherosa Ziehau 432515516c77SSepherosa Ziehau static int 432615516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m) 432715516c77SSepherosa Ziehau { 432815516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 432915516c77SSepherosa Ziehau struct hn_tx_ring *txr; 433015516c77SSepherosa Ziehau int error, idx = 0; 433115516c77SSepherosa Ziehau 4332edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 4333edd3f315SSepherosa Ziehau /* 4334edd3f315SSepherosa Ziehau * Perform TSO packet header fixup now, since the TSO 4335edd3f315SSepherosa Ziehau * packet header should be cache-hot. 4336edd3f315SSepherosa Ziehau */ 4337edd3f315SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 4338edd3f315SSepherosa Ziehau m = hn_tso_fixup(m); 4339edd3f315SSepherosa Ziehau if (__predict_false(m == NULL)) { 4340edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 4341edd3f315SSepherosa Ziehau return EIO; 4342edd3f315SSepherosa Ziehau } 4343edd3f315SSepherosa Ziehau } 4344edd3f315SSepherosa Ziehau #endif 4345edd3f315SSepherosa Ziehau 434615516c77SSepherosa Ziehau /* 434715516c77SSepherosa Ziehau * Select the TX ring based on flowid 434815516c77SSepherosa Ziehau */ 434934d68912SSepherosa Ziehau if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 435034d68912SSepherosa Ziehau #ifdef RSS 435134d68912SSepherosa Ziehau uint32_t bid; 435234d68912SSepherosa Ziehau 435334d68912SSepherosa Ziehau if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m), 435434d68912SSepherosa Ziehau &bid) == 0) 435534d68912SSepherosa Ziehau idx = bid % sc->hn_tx_ring_inuse; 435634d68912SSepherosa Ziehau else 435734d68912SSepherosa Ziehau #endif 435815516c77SSepherosa Ziehau idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse; 435934d68912SSepherosa Ziehau } 436015516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 436115516c77SSepherosa Ziehau 436215516c77SSepherosa Ziehau error = drbr_enqueue(ifp, txr->hn_mbuf_br, m); 436315516c77SSepherosa Ziehau if (error) { 436415516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 436515516c77SSepherosa Ziehau return error; 436615516c77SSepherosa Ziehau } 436715516c77SSepherosa Ziehau 436815516c77SSepherosa Ziehau if (txr->hn_oactive) 436915516c77SSepherosa Ziehau return 0; 437015516c77SSepherosa Ziehau 437115516c77SSepherosa Ziehau if (txr->hn_sched_tx) 437215516c77SSepherosa Ziehau goto do_sched; 437315516c77SSepherosa Ziehau 437415516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 437515516c77SSepherosa Ziehau int sched; 437615516c77SSepherosa Ziehau 437715516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 437815516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 437915516c77SSepherosa Ziehau if (!sched) 438015516c77SSepherosa Ziehau return 0; 438115516c77SSepherosa Ziehau } 438215516c77SSepherosa Ziehau do_sched: 438315516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 438415516c77SSepherosa Ziehau return 0; 438515516c77SSepherosa Ziehau } 438615516c77SSepherosa Ziehau 438715516c77SSepherosa Ziehau static void 438815516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr) 438915516c77SSepherosa Ziehau { 439015516c77SSepherosa Ziehau struct mbuf *m; 439115516c77SSepherosa Ziehau 439215516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 439315516c77SSepherosa Ziehau while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL) 439415516c77SSepherosa Ziehau m_freem(m); 439515516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 439615516c77SSepherosa Ziehau } 439715516c77SSepherosa Ziehau 439815516c77SSepherosa Ziehau static void 439915516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp) 440015516c77SSepherosa Ziehau { 440115516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 440215516c77SSepherosa Ziehau int i; 440315516c77SSepherosa Ziehau 440415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 440515516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 440615516c77SSepherosa Ziehau if_qflush(ifp); 440715516c77SSepherosa Ziehau } 440815516c77SSepherosa Ziehau 440915516c77SSepherosa Ziehau static void 441015516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr) 441115516c77SSepherosa Ziehau { 441215516c77SSepherosa Ziehau 441315516c77SSepherosa Ziehau if (txr->hn_sched_tx) 441415516c77SSepherosa Ziehau goto do_sched; 441515516c77SSepherosa Ziehau 441615516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 441715516c77SSepherosa Ziehau int sched; 441815516c77SSepherosa Ziehau 441915516c77SSepherosa Ziehau txr->hn_oactive = 0; 442015516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 442115516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 442215516c77SSepherosa Ziehau if (sched) { 442315516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 442415516c77SSepherosa Ziehau &txr->hn_tx_task); 442515516c77SSepherosa Ziehau } 442615516c77SSepherosa Ziehau } else { 442715516c77SSepherosa Ziehau do_sched: 442815516c77SSepherosa Ziehau /* 442915516c77SSepherosa Ziehau * Release the oactive earlier, with the hope, that 443015516c77SSepherosa Ziehau * others could catch up. The task will clear the 443115516c77SSepherosa Ziehau * oactive again with the hn_tx_lock to avoid possible 443215516c77SSepherosa Ziehau * races. 443315516c77SSepherosa Ziehau */ 443415516c77SSepherosa Ziehau txr->hn_oactive = 0; 443515516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 443615516c77SSepherosa Ziehau } 443715516c77SSepherosa Ziehau } 443815516c77SSepherosa Ziehau 443915516c77SSepherosa Ziehau static void 444015516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused) 444115516c77SSepherosa Ziehau { 444215516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 444315516c77SSepherosa Ziehau 444415516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 444515516c77SSepherosa Ziehau hn_xmit(txr, 0); 444615516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 444715516c77SSepherosa Ziehau } 444815516c77SSepherosa Ziehau 444915516c77SSepherosa Ziehau static void 445015516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused) 445115516c77SSepherosa Ziehau { 445215516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 445315516c77SSepherosa Ziehau 445415516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 445515516c77SSepherosa Ziehau txr->hn_oactive = 0; 445615516c77SSepherosa Ziehau hn_xmit(txr, 0); 445715516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 445815516c77SSepherosa Ziehau } 445915516c77SSepherosa Ziehau 446015516c77SSepherosa Ziehau static int 446115516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan) 446215516c77SSepherosa Ziehau { 446315516c77SSepherosa Ziehau struct vmbus_chan_br cbr; 446415516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 446515516c77SSepherosa Ziehau struct hn_tx_ring *txr = NULL; 446615516c77SSepherosa Ziehau int idx, error; 446715516c77SSepherosa Ziehau 446815516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 446915516c77SSepherosa Ziehau 447015516c77SSepherosa Ziehau /* 447115516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 447215516c77SSepherosa Ziehau */ 447315516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 447415516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 447515516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 447615516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 447715516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0, 447815516c77SSepherosa Ziehau ("RX ring %d already attached", idx)); 447915516c77SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED; 44803ab0fea1SDexuan Cui rxr->hn_chan = chan; 448115516c77SSepherosa Ziehau 448215516c77SSepherosa Ziehau if (bootverbose) { 448315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n", 448415516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 448515516c77SSepherosa Ziehau } 448615516c77SSepherosa Ziehau 448715516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 448815516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 448915516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0, 449015516c77SSepherosa Ziehau ("TX ring %d already attached", idx)); 449115516c77SSepherosa Ziehau txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED; 449215516c77SSepherosa Ziehau 449315516c77SSepherosa Ziehau txr->hn_chan = chan; 449415516c77SSepherosa Ziehau if (bootverbose) { 449515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n", 449615516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 449715516c77SSepherosa Ziehau } 449815516c77SSepherosa Ziehau } 449915516c77SSepherosa Ziehau 450015516c77SSepherosa Ziehau /* Bind this channel to a proper CPU. */ 45010e11868dSSepherosa Ziehau vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx)); 450215516c77SSepherosa Ziehau 450315516c77SSepherosa Ziehau /* 450415516c77SSepherosa Ziehau * Open this channel 450515516c77SSepherosa Ziehau */ 450615516c77SSepherosa Ziehau cbr.cbr = rxr->hn_br; 450715516c77SSepherosa Ziehau cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr; 450815516c77SSepherosa Ziehau cbr.cbr_txsz = HN_TXBR_SIZE; 450915516c77SSepherosa Ziehau cbr.cbr_rxsz = HN_RXBR_SIZE; 451015516c77SSepherosa Ziehau error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr); 451115516c77SSepherosa Ziehau if (error) { 451271e8ac56SSepherosa Ziehau if (error == EISCONN) { 451371e8ac56SSepherosa Ziehau if_printf(sc->hn_ifp, "bufring is connected after " 451471e8ac56SSepherosa Ziehau "chan%u open failure\n", vmbus_chan_id(chan)); 451571e8ac56SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 451671e8ac56SSepherosa Ziehau } else { 451715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "open chan%u failed: %d\n", 451815516c77SSepherosa Ziehau vmbus_chan_id(chan), error); 451971e8ac56SSepherosa Ziehau } 452015516c77SSepherosa Ziehau } 452115516c77SSepherosa Ziehau return (error); 452215516c77SSepherosa Ziehau } 452315516c77SSepherosa Ziehau 452415516c77SSepherosa Ziehau static void 452515516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan) 452615516c77SSepherosa Ziehau { 452715516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 45282494d735SSepherosa Ziehau int idx, error; 452915516c77SSepherosa Ziehau 453015516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 453115516c77SSepherosa Ziehau 453215516c77SSepherosa Ziehau /* 453315516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 453415516c77SSepherosa Ziehau */ 453515516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 453615516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 453715516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 453815516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 453915516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED), 454015516c77SSepherosa Ziehau ("RX ring %d is not attached", idx)); 454115516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 454215516c77SSepherosa Ziehau 454315516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 454415516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[idx]; 454515516c77SSepherosa Ziehau 454615516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED), 454715516c77SSepherosa Ziehau ("TX ring %d is not attached attached", idx)); 454815516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 454915516c77SSepherosa Ziehau } 455015516c77SSepherosa Ziehau 455115516c77SSepherosa Ziehau /* 455215516c77SSepherosa Ziehau * Close this channel. 455315516c77SSepherosa Ziehau * 455415516c77SSepherosa Ziehau * NOTE: 455515516c77SSepherosa Ziehau * Channel closing does _not_ destroy the target channel. 455615516c77SSepherosa Ziehau */ 45572494d735SSepherosa Ziehau error = vmbus_chan_close_direct(chan); 45582494d735SSepherosa Ziehau if (error == EISCONN) { 4559aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u bufring is connected " 4560aa1a2adcSSepherosa Ziehau "after being closed\n", vmbus_chan_id(chan)); 45612494d735SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 45622494d735SSepherosa Ziehau } else if (error) { 4563aa1a2adcSSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u close failed: %d\n", 4564aa1a2adcSSepherosa Ziehau vmbus_chan_id(chan), error); 45652494d735SSepherosa Ziehau } 456615516c77SSepherosa Ziehau } 456715516c77SSepherosa Ziehau 456815516c77SSepherosa Ziehau static int 456915516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc) 457015516c77SSepherosa Ziehau { 457115516c77SSepherosa Ziehau struct vmbus_channel **subchans; 457215516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 457315516c77SSepherosa Ziehau int i, error = 0; 457415516c77SSepherosa Ziehau 457571e8ac56SSepherosa Ziehau KASSERT(subchan_cnt > 0, ("no sub-channels")); 457615516c77SSepherosa Ziehau 457715516c77SSepherosa Ziehau /* Attach the sub-channels. */ 457815516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 457915516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) { 458071e8ac56SSepherosa Ziehau int error1; 458171e8ac56SSepherosa Ziehau 458271e8ac56SSepherosa Ziehau error1 = hn_chan_attach(sc, subchans[i]); 458371e8ac56SSepherosa Ziehau if (error1) { 458471e8ac56SSepherosa Ziehau error = error1; 458571e8ac56SSepherosa Ziehau /* Move on; all channels will be detached later. */ 458671e8ac56SSepherosa Ziehau } 458715516c77SSepherosa Ziehau } 458815516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 458915516c77SSepherosa Ziehau 459015516c77SSepherosa Ziehau if (error) { 459115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error); 459215516c77SSepherosa Ziehau } else { 459315516c77SSepherosa Ziehau if (bootverbose) { 459415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d sub-channels attached\n", 459515516c77SSepherosa Ziehau subchan_cnt); 459615516c77SSepherosa Ziehau } 459715516c77SSepherosa Ziehau } 459815516c77SSepherosa Ziehau return (error); 459915516c77SSepherosa Ziehau } 460015516c77SSepherosa Ziehau 460115516c77SSepherosa Ziehau static void 460215516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc) 460315516c77SSepherosa Ziehau { 460415516c77SSepherosa Ziehau struct vmbus_channel **subchans; 460515516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 460615516c77SSepherosa Ziehau int i; 460715516c77SSepherosa Ziehau 460815516c77SSepherosa Ziehau if (subchan_cnt == 0) 460915516c77SSepherosa Ziehau goto back; 461015516c77SSepherosa Ziehau 461115516c77SSepherosa Ziehau /* Detach the sub-channels. */ 461215516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 461315516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) 461415516c77SSepherosa Ziehau hn_chan_detach(sc, subchans[i]); 461515516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 461615516c77SSepherosa Ziehau 461715516c77SSepherosa Ziehau back: 461815516c77SSepherosa Ziehau /* 461915516c77SSepherosa Ziehau * Detach the primary channel, _after_ all sub-channels 462015516c77SSepherosa Ziehau * are detached. 462115516c77SSepherosa Ziehau */ 462215516c77SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 462315516c77SSepherosa Ziehau 462415516c77SSepherosa Ziehau /* Wait for sub-channels to be destroyed, if any. */ 462515516c77SSepherosa Ziehau vmbus_subchan_drain(sc->hn_prichan); 462615516c77SSepherosa Ziehau 462715516c77SSepherosa Ziehau #ifdef INVARIANTS 462815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 462915516c77SSepherosa Ziehau KASSERT((sc->hn_rx_ring[i].hn_rx_flags & 463015516c77SSepherosa Ziehau HN_RX_FLAG_ATTACHED) == 0, 463115516c77SSepherosa Ziehau ("%dth RX ring is still attached", i)); 463215516c77SSepherosa Ziehau } 463315516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 463415516c77SSepherosa Ziehau KASSERT((sc->hn_tx_ring[i].hn_tx_flags & 463515516c77SSepherosa Ziehau HN_TX_FLAG_ATTACHED) == 0, 463615516c77SSepherosa Ziehau ("%dth TX ring is still attached", i)); 463715516c77SSepherosa Ziehau } 463815516c77SSepherosa Ziehau #endif 463915516c77SSepherosa Ziehau } 464015516c77SSepherosa Ziehau 464115516c77SSepherosa Ziehau static int 464215516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch) 464315516c77SSepherosa Ziehau { 464415516c77SSepherosa Ziehau struct vmbus_channel **subchans; 464515516c77SSepherosa Ziehau int nchan, rxr_cnt, error; 464615516c77SSepherosa Ziehau 464715516c77SSepherosa Ziehau nchan = *nsubch + 1; 464815516c77SSepherosa Ziehau if (nchan == 1) { 464915516c77SSepherosa Ziehau /* 465015516c77SSepherosa Ziehau * Multiple RX/TX rings are not requested. 465115516c77SSepherosa Ziehau */ 465215516c77SSepherosa Ziehau *nsubch = 0; 465315516c77SSepherosa Ziehau return (0); 465415516c77SSepherosa Ziehau } 465515516c77SSepherosa Ziehau 465615516c77SSepherosa Ziehau /* 465715516c77SSepherosa Ziehau * Query RSS capabilities, e.g. # of RX rings, and # of indirect 465815516c77SSepherosa Ziehau * table entries. 465915516c77SSepherosa Ziehau */ 466015516c77SSepherosa Ziehau error = hn_rndis_query_rsscaps(sc, &rxr_cnt); 466115516c77SSepherosa Ziehau if (error) { 466215516c77SSepherosa Ziehau /* No RSS; this is benign. */ 466315516c77SSepherosa Ziehau *nsubch = 0; 466415516c77SSepherosa Ziehau return (0); 466515516c77SSepherosa Ziehau } 466615516c77SSepherosa Ziehau if (bootverbose) { 466715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n", 466815516c77SSepherosa Ziehau rxr_cnt, nchan); 466915516c77SSepherosa Ziehau } 467015516c77SSepherosa Ziehau 467115516c77SSepherosa Ziehau if (nchan > rxr_cnt) 467215516c77SSepherosa Ziehau nchan = rxr_cnt; 467315516c77SSepherosa Ziehau if (nchan == 1) { 467415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n"); 467515516c77SSepherosa Ziehau *nsubch = 0; 467615516c77SSepherosa Ziehau return (0); 467715516c77SSepherosa Ziehau } 467815516c77SSepherosa Ziehau 467915516c77SSepherosa Ziehau /* 468015516c77SSepherosa Ziehau * Allocate sub-channels from NVS. 468115516c77SSepherosa Ziehau */ 468215516c77SSepherosa Ziehau *nsubch = nchan - 1; 468315516c77SSepherosa Ziehau error = hn_nvs_alloc_subchans(sc, nsubch); 468415516c77SSepherosa Ziehau if (error || *nsubch == 0) { 468515516c77SSepherosa Ziehau /* Failed to allocate sub-channels. */ 468615516c77SSepherosa Ziehau *nsubch = 0; 468715516c77SSepherosa Ziehau return (0); 468815516c77SSepherosa Ziehau } 468915516c77SSepherosa Ziehau 469015516c77SSepherosa Ziehau /* 469115516c77SSepherosa Ziehau * Wait for all sub-channels to become ready before moving on. 469215516c77SSepherosa Ziehau */ 469315516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch); 469415516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, *nsubch); 469515516c77SSepherosa Ziehau return (0); 469615516c77SSepherosa Ziehau } 469715516c77SSepherosa Ziehau 46982494d735SSepherosa Ziehau static bool 46992494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc) 47002494d735SSepherosa Ziehau { 47012494d735SSepherosa Ziehau int i; 47022494d735SSepherosa Ziehau 47032494d735SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_ERRORS) 47042494d735SSepherosa Ziehau return (false); 47052494d735SSepherosa Ziehau 47062494d735SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 47072494d735SSepherosa Ziehau const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 47082494d735SSepherosa Ziehau 47092494d735SSepherosa Ziehau if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) 47102494d735SSepherosa Ziehau return (false); 47112494d735SSepherosa Ziehau } 47122494d735SSepherosa Ziehau return (true); 47132494d735SSepherosa Ziehau } 47142494d735SSepherosa Ziehau 471515516c77SSepherosa Ziehau static int 471615516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu) 471715516c77SSepherosa Ziehau { 471871e8ac56SSepherosa Ziehau #define ATTACHED_NVS 0x0002 471971e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS 0x0004 472071e8ac56SSepherosa Ziehau 472115516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 472215516c77SSepherosa Ziehau int error, nsubch, nchan, i; 472371e8ac56SSepherosa Ziehau uint32_t old_caps, attached = 0; 472415516c77SSepherosa Ziehau 472515516c77SSepherosa Ziehau KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0, 472615516c77SSepherosa Ziehau ("synthetic parts were attached")); 472715516c77SSepherosa Ziehau 47282494d735SSepherosa Ziehau if (!hn_synth_attachable(sc)) 47292494d735SSepherosa Ziehau return (ENXIO); 47302494d735SSepherosa Ziehau 473115516c77SSepherosa Ziehau /* Save capabilities for later verification. */ 473215516c77SSepherosa Ziehau old_caps = sc->hn_caps; 473315516c77SSepherosa Ziehau sc->hn_caps = 0; 473415516c77SSepherosa Ziehau 473515516c77SSepherosa Ziehau /* Clear RSS stuffs. */ 473615516c77SSepherosa Ziehau sc->hn_rss_ind_size = 0; 473715516c77SSepherosa Ziehau sc->hn_rss_hash = 0; 473815516c77SSepherosa Ziehau 473915516c77SSepherosa Ziehau /* 474015516c77SSepherosa Ziehau * Attach the primary channel _before_ attaching NVS and RNDIS. 474115516c77SSepherosa Ziehau */ 474215516c77SSepherosa Ziehau error = hn_chan_attach(sc, sc->hn_prichan); 474315516c77SSepherosa Ziehau if (error) 474471e8ac56SSepherosa Ziehau goto failed; 474515516c77SSepherosa Ziehau 474615516c77SSepherosa Ziehau /* 474715516c77SSepherosa Ziehau * Attach NVS. 474815516c77SSepherosa Ziehau */ 474915516c77SSepherosa Ziehau error = hn_nvs_attach(sc, mtu); 475015516c77SSepherosa Ziehau if (error) 475171e8ac56SSepherosa Ziehau goto failed; 475271e8ac56SSepherosa Ziehau attached |= ATTACHED_NVS; 475315516c77SSepherosa Ziehau 475415516c77SSepherosa Ziehau /* 475515516c77SSepherosa Ziehau * Attach RNDIS _after_ NVS is attached. 475615516c77SSepherosa Ziehau */ 475715516c77SSepherosa Ziehau error = hn_rndis_attach(sc, mtu); 475815516c77SSepherosa Ziehau if (error) 475971e8ac56SSepherosa Ziehau goto failed; 476071e8ac56SSepherosa Ziehau attached |= ATTACHED_RNDIS; 476115516c77SSepherosa Ziehau 476215516c77SSepherosa Ziehau /* 476315516c77SSepherosa Ziehau * Make sure capabilities are not changed. 476415516c77SSepherosa Ziehau */ 476515516c77SSepherosa Ziehau if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) { 476615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n", 476715516c77SSepherosa Ziehau old_caps, sc->hn_caps); 476871e8ac56SSepherosa Ziehau error = ENXIO; 476971e8ac56SSepherosa Ziehau goto failed; 477015516c77SSepherosa Ziehau } 477115516c77SSepherosa Ziehau 477215516c77SSepherosa Ziehau /* 477315516c77SSepherosa Ziehau * Allocate sub-channels for multi-TX/RX rings. 477415516c77SSepherosa Ziehau * 477515516c77SSepherosa Ziehau * NOTE: 477615516c77SSepherosa Ziehau * The # of RX rings that can be used is equivalent to the # of 477715516c77SSepherosa Ziehau * channels to be requested. 477815516c77SSepherosa Ziehau */ 477915516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_cnt - 1; 478015516c77SSepherosa Ziehau error = hn_synth_alloc_subchans(sc, &nsubch); 478115516c77SSepherosa Ziehau if (error) 478271e8ac56SSepherosa Ziehau goto failed; 478371e8ac56SSepherosa Ziehau /* NOTE: _Full_ synthetic parts detach is required now. */ 478471e8ac56SSepherosa Ziehau sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED; 478515516c77SSepherosa Ziehau 478671e8ac56SSepherosa Ziehau /* 478771e8ac56SSepherosa Ziehau * Set the # of TX/RX rings that could be used according to 478871e8ac56SSepherosa Ziehau * the # of channels that NVS offered. 478971e8ac56SSepherosa Ziehau */ 479015516c77SSepherosa Ziehau nchan = nsubch + 1; 479171e8ac56SSepherosa Ziehau hn_set_ring_inuse(sc, nchan); 479215516c77SSepherosa Ziehau if (nchan == 1) { 479315516c77SSepherosa Ziehau /* Only the primary channel can be used; done */ 479415516c77SSepherosa Ziehau goto back; 479515516c77SSepherosa Ziehau } 479615516c77SSepherosa Ziehau 479715516c77SSepherosa Ziehau /* 479871e8ac56SSepherosa Ziehau * Attach the sub-channels. 4799afd4971bSSepherosa Ziehau * 4800afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 480115516c77SSepherosa Ziehau */ 480271e8ac56SSepherosa Ziehau error = hn_attach_subchans(sc); 480371e8ac56SSepherosa Ziehau if (error) 480471e8ac56SSepherosa Ziehau goto failed; 480515516c77SSepherosa Ziehau 480671e8ac56SSepherosa Ziehau /* 480771e8ac56SSepherosa Ziehau * Configure RSS key and indirect table _after_ all sub-channels 480871e8ac56SSepherosa Ziehau * are attached. 480971e8ac56SSepherosa Ziehau */ 481015516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) { 481115516c77SSepherosa Ziehau /* 481215516c77SSepherosa Ziehau * RSS key is not set yet; set it to the default RSS key. 481315516c77SSepherosa Ziehau */ 481415516c77SSepherosa Ziehau if (bootverbose) 481515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS key\n"); 481634d68912SSepherosa Ziehau #ifdef RSS 481734d68912SSepherosa Ziehau rss_getkey(rss->rss_key); 481834d68912SSepherosa Ziehau #else 481915516c77SSepherosa Ziehau memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key)); 482034d68912SSepherosa Ziehau #endif 482115516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 482215516c77SSepherosa Ziehau } 482315516c77SSepherosa Ziehau 482415516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) { 482515516c77SSepherosa Ziehau /* 482615516c77SSepherosa Ziehau * RSS indirect table is not set yet; set it up in round- 482715516c77SSepherosa Ziehau * robin fashion. 482815516c77SSepherosa Ziehau */ 482915516c77SSepherosa Ziehau if (bootverbose) { 483015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS indirect " 483115516c77SSepherosa Ziehau "table\n"); 483215516c77SSepherosa Ziehau } 483334d68912SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 483434d68912SSepherosa Ziehau uint32_t subidx; 483534d68912SSepherosa Ziehau 483634d68912SSepherosa Ziehau #ifdef RSS 483734d68912SSepherosa Ziehau subidx = rss_get_indirection_to_bucket(i); 483834d68912SSepherosa Ziehau #else 483934d68912SSepherosa Ziehau subidx = i; 484034d68912SSepherosa Ziehau #endif 484134d68912SSepherosa Ziehau rss->rss_ind[i] = subidx % nchan; 484234d68912SSepherosa Ziehau } 484315516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 484415516c77SSepherosa Ziehau } else { 484515516c77SSepherosa Ziehau /* 484615516c77SSepherosa Ziehau * # of usable channels may be changed, so we have to 484715516c77SSepherosa Ziehau * make sure that all entries in RSS indirect table 484815516c77SSepherosa Ziehau * are valid. 4849afd4971bSSepherosa Ziehau * 4850afd4971bSSepherosa Ziehau * NOTE: hn_set_ring_inuse() _must_ have been called. 485115516c77SSepherosa Ziehau */ 4852afd4971bSSepherosa Ziehau hn_rss_ind_fixup(sc); 485315516c77SSepherosa Ziehau } 485415516c77SSepherosa Ziehau 485515516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 485615516c77SSepherosa Ziehau if (error) 485771e8ac56SSepherosa Ziehau goto failed; 485871e8ac56SSepherosa Ziehau back: 4859dc13fee6SSepherosa Ziehau /* 4860dc13fee6SSepherosa Ziehau * Fixup transmission aggregation setup. 4861dc13fee6SSepherosa Ziehau */ 4862dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 486315516c77SSepherosa Ziehau return (0); 486471e8ac56SSepherosa Ziehau 486571e8ac56SSepherosa Ziehau failed: 486671e8ac56SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 486771e8ac56SSepherosa Ziehau hn_synth_detach(sc); 486871e8ac56SSepherosa Ziehau } else { 486971e8ac56SSepherosa Ziehau if (attached & ATTACHED_RNDIS) 487071e8ac56SSepherosa Ziehau hn_rndis_detach(sc); 487171e8ac56SSepherosa Ziehau if (attached & ATTACHED_NVS) 487271e8ac56SSepherosa Ziehau hn_nvs_detach(sc); 487371e8ac56SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 487471e8ac56SSepherosa Ziehau /* Restore old capabilities. */ 487571e8ac56SSepherosa Ziehau sc->hn_caps = old_caps; 487671e8ac56SSepherosa Ziehau } 487771e8ac56SSepherosa Ziehau return (error); 487871e8ac56SSepherosa Ziehau 487971e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS 488071e8ac56SSepherosa Ziehau #undef ATTACHED_NVS 488115516c77SSepherosa Ziehau } 488215516c77SSepherosa Ziehau 488315516c77SSepherosa Ziehau /* 488415516c77SSepherosa Ziehau * NOTE: 488515516c77SSepherosa Ziehau * The interface must have been suspended though hn_suspend(), before 488615516c77SSepherosa Ziehau * this function get called. 488715516c77SSepherosa Ziehau */ 488815516c77SSepherosa Ziehau static void 488915516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc) 489015516c77SSepherosa Ziehau { 489115516c77SSepherosa Ziehau 489215516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 489315516c77SSepherosa Ziehau ("synthetic parts were not attached")); 489415516c77SSepherosa Ziehau 489515516c77SSepherosa Ziehau /* Detach the RNDIS first. */ 489615516c77SSepherosa Ziehau hn_rndis_detach(sc); 489715516c77SSepherosa Ziehau 489815516c77SSepherosa Ziehau /* Detach NVS. */ 489915516c77SSepherosa Ziehau hn_nvs_detach(sc); 490015516c77SSepherosa Ziehau 490115516c77SSepherosa Ziehau /* Detach all of the channels. */ 490215516c77SSepherosa Ziehau hn_detach_allchans(sc); 490315516c77SSepherosa Ziehau 490415516c77SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED; 490515516c77SSepherosa Ziehau } 490615516c77SSepherosa Ziehau 490715516c77SSepherosa Ziehau static void 490815516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt) 490915516c77SSepherosa Ziehau { 491015516c77SSepherosa Ziehau KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt, 491115516c77SSepherosa Ziehau ("invalid ring count %d", ring_cnt)); 491215516c77SSepherosa Ziehau 491315516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt > ring_cnt) 491415516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = ring_cnt; 491515516c77SSepherosa Ziehau else 491615516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 491715516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = ring_cnt; 491815516c77SSepherosa Ziehau 491934d68912SSepherosa Ziehau #ifdef RSS 492034d68912SSepherosa Ziehau if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) { 492134d68912SSepherosa Ziehau if_printf(sc->hn_ifp, "# of RX rings (%d) does not match " 492234d68912SSepherosa Ziehau "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse, 492334d68912SSepherosa Ziehau rss_getnumbuckets()); 492434d68912SSepherosa Ziehau } 492534d68912SSepherosa Ziehau #endif 492634d68912SSepherosa Ziehau 492715516c77SSepherosa Ziehau if (bootverbose) { 492815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n", 492915516c77SSepherosa Ziehau sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse); 493015516c77SSepherosa Ziehau } 493115516c77SSepherosa Ziehau } 493215516c77SSepherosa Ziehau 493315516c77SSepherosa Ziehau static void 493425641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan) 493515516c77SSepherosa Ziehau { 493615516c77SSepherosa Ziehau 493725641fc7SSepherosa Ziehau /* 493825641fc7SSepherosa Ziehau * NOTE: 493925641fc7SSepherosa Ziehau * The TX bufring will not be drained by the hypervisor, 494025641fc7SSepherosa Ziehau * if the primary channel is revoked. 494125641fc7SSepherosa Ziehau */ 494225641fc7SSepherosa Ziehau while (!vmbus_chan_rx_empty(chan) || 494325641fc7SSepherosa Ziehau (!vmbus_chan_is_revoked(sc->hn_prichan) && 494425641fc7SSepherosa Ziehau !vmbus_chan_tx_empty(chan))) 494515516c77SSepherosa Ziehau pause("waitch", 1); 494615516c77SSepherosa Ziehau vmbus_chan_intr_drain(chan); 494715516c77SSepherosa Ziehau } 494815516c77SSepherosa Ziehau 494915516c77SSepherosa Ziehau static void 495015516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc) 495115516c77SSepherosa Ziehau { 495215516c77SSepherosa Ziehau struct vmbus_channel **subch = NULL; 495325641fc7SSepherosa Ziehau struct hn_tx_ring *txr; 495415516c77SSepherosa Ziehau int i, nsubch; 495515516c77SSepherosa Ziehau 495615516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 495715516c77SSepherosa Ziehau 495815516c77SSepherosa Ziehau /* 495915516c77SSepherosa Ziehau * Suspend TX. 496015516c77SSepherosa Ziehau */ 496115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 496225641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 496315516c77SSepherosa Ziehau 496415516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 496515516c77SSepherosa Ziehau txr->hn_suspended = 1; 496615516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 496715516c77SSepherosa Ziehau /* No one is able send more packets now. */ 496815516c77SSepherosa Ziehau 496925641fc7SSepherosa Ziehau /* 497025641fc7SSepherosa Ziehau * Wait for all pending sends to finish. 497125641fc7SSepherosa Ziehau * 497225641fc7SSepherosa Ziehau * NOTE: 497325641fc7SSepherosa Ziehau * We will _not_ receive all pending send-done, if the 497425641fc7SSepherosa Ziehau * primary channel is revoked. 497525641fc7SSepherosa Ziehau */ 497625641fc7SSepherosa Ziehau while (hn_tx_ring_pending(txr) && 497725641fc7SSepherosa Ziehau !vmbus_chan_is_revoked(sc->hn_prichan)) 497815516c77SSepherosa Ziehau pause("hnwtx", 1 /* 1 tick */); 497915516c77SSepherosa Ziehau } 498015516c77SSepherosa Ziehau 498115516c77SSepherosa Ziehau /* 498215516c77SSepherosa Ziehau * Disable RX by clearing RX filter. 498315516c77SSepherosa Ziehau */ 4984f1b0a43fSSepherosa Ziehau hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE); 498515516c77SSepherosa Ziehau 498615516c77SSepherosa Ziehau /* 498715516c77SSepherosa Ziehau * Give RNDIS enough time to flush all pending data packets. 498815516c77SSepherosa Ziehau */ 498915516c77SSepherosa Ziehau pause("waitrx", (200 * hz) / 1000); 499015516c77SSepherosa Ziehau 499115516c77SSepherosa Ziehau /* 499215516c77SSepherosa Ziehau * Drain RX/TX bufrings and interrupts. 499315516c77SSepherosa Ziehau */ 499415516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_inuse - 1; 499515516c77SSepherosa Ziehau if (nsubch > 0) 499615516c77SSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 499715516c77SSepherosa Ziehau 499815516c77SSepherosa Ziehau if (subch != NULL) { 499915516c77SSepherosa Ziehau for (i = 0; i < nsubch; ++i) 500025641fc7SSepherosa Ziehau hn_chan_drain(sc, subch[i]); 500115516c77SSepherosa Ziehau } 500225641fc7SSepherosa Ziehau hn_chan_drain(sc, sc->hn_prichan); 500315516c77SSepherosa Ziehau 500415516c77SSepherosa Ziehau if (subch != NULL) 500515516c77SSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 500625641fc7SSepherosa Ziehau 500725641fc7SSepherosa Ziehau /* 500825641fc7SSepherosa Ziehau * Drain any pending TX tasks. 500925641fc7SSepherosa Ziehau * 501025641fc7SSepherosa Ziehau * NOTE: 501125641fc7SSepherosa Ziehau * The above hn_chan_drain() can dispatch TX tasks, so the TX 501225641fc7SSepherosa Ziehau * tasks will have to be drained _after_ the above hn_chan_drain() 501325641fc7SSepherosa Ziehau * calls. 501425641fc7SSepherosa Ziehau */ 501525641fc7SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 501625641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 501725641fc7SSepherosa Ziehau 501825641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task); 501925641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task); 502025641fc7SSepherosa Ziehau } 502115516c77SSepherosa Ziehau } 502215516c77SSepherosa Ziehau 502315516c77SSepherosa Ziehau static void 502415516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused) 502515516c77SSepherosa Ziehau { 502615516c77SSepherosa Ziehau 502715516c77SSepherosa Ziehau ((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL; 502815516c77SSepherosa Ziehau } 502915516c77SSepherosa Ziehau 503015516c77SSepherosa Ziehau static void 503115516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc) 503215516c77SSepherosa Ziehau { 503315516c77SSepherosa Ziehau struct task task; 503415516c77SSepherosa Ziehau 503515516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 503615516c77SSepherosa Ziehau 503715516c77SSepherosa Ziehau /* 503815516c77SSepherosa Ziehau * Make sure that hn_mgmt_taskq0 can nolonger be accessed 503915516c77SSepherosa Ziehau * through hn_mgmt_taskq. 504015516c77SSepherosa Ziehau */ 504115516c77SSepherosa Ziehau TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc); 504215516c77SSepherosa Ziehau vmbus_chan_run_task(sc->hn_prichan, &task); 504315516c77SSepherosa Ziehau 504415516c77SSepherosa Ziehau /* 504515516c77SSepherosa Ziehau * Make sure that all pending management tasks are completed. 504615516c77SSepherosa Ziehau */ 504715516c77SSepherosa Ziehau taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init); 504815516c77SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status); 504915516c77SSepherosa Ziehau taskqueue_drain_all(sc->hn_mgmt_taskq0); 505015516c77SSepherosa Ziehau } 505115516c77SSepherosa Ziehau 505215516c77SSepherosa Ziehau static void 505315516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc) 505415516c77SSepherosa Ziehau { 505515516c77SSepherosa Ziehau 505687f8129dSSepherosa Ziehau /* Disable polling. */ 505787f8129dSSepherosa Ziehau hn_polling(sc, 0); 505887f8129dSSepherosa Ziehau 50595bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 50605bdfd3fdSDexuan Cui (sc->hn_flags & HN_FLAG_VF)) 506115516c77SSepherosa Ziehau hn_suspend_data(sc); 506215516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 506315516c77SSepherosa Ziehau } 506415516c77SSepherosa Ziehau 506515516c77SSepherosa Ziehau static void 506615516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt) 506715516c77SSepherosa Ziehau { 506815516c77SSepherosa Ziehau int i; 506915516c77SSepherosa Ziehau 507015516c77SSepherosa Ziehau KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt, 507115516c77SSepherosa Ziehau ("invalid TX ring count %d", tx_ring_cnt)); 507215516c77SSepherosa Ziehau 507315516c77SSepherosa Ziehau for (i = 0; i < tx_ring_cnt; ++i) { 507415516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 507515516c77SSepherosa Ziehau 507615516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 507715516c77SSepherosa Ziehau txr->hn_suspended = 0; 507815516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 507915516c77SSepherosa Ziehau } 508015516c77SSepherosa Ziehau } 508115516c77SSepherosa Ziehau 508215516c77SSepherosa Ziehau static void 508315516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc) 508415516c77SSepherosa Ziehau { 508515516c77SSepherosa Ziehau int i; 508615516c77SSepherosa Ziehau 508715516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 508815516c77SSepherosa Ziehau 508915516c77SSepherosa Ziehau /* 509015516c77SSepherosa Ziehau * Re-enable RX. 509115516c77SSepherosa Ziehau */ 5092c08f7b2cSSepherosa Ziehau hn_rxfilter_config(sc); 509315516c77SSepherosa Ziehau 509415516c77SSepherosa Ziehau /* 509515516c77SSepherosa Ziehau * Make sure to clear suspend status on "all" TX rings, 509615516c77SSepherosa Ziehau * since hn_tx_ring_inuse can be changed after 509715516c77SSepherosa Ziehau * hn_suspend_data(). 509815516c77SSepherosa Ziehau */ 509915516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_cnt); 510015516c77SSepherosa Ziehau 510123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 510223bf9e15SSepherosa Ziehau if (!hn_use_if_start) 510323bf9e15SSepherosa Ziehau #endif 510423bf9e15SSepherosa Ziehau { 510515516c77SSepherosa Ziehau /* 510615516c77SSepherosa Ziehau * Flush unused drbrs, since hn_tx_ring_inuse may be 510715516c77SSepherosa Ziehau * reduced. 510815516c77SSepherosa Ziehau */ 510915516c77SSepherosa Ziehau for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i) 511015516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 511115516c77SSepherosa Ziehau } 511215516c77SSepherosa Ziehau 511315516c77SSepherosa Ziehau /* 511415516c77SSepherosa Ziehau * Kick start TX. 511515516c77SSepherosa Ziehau */ 511615516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 511715516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 511815516c77SSepherosa Ziehau 511915516c77SSepherosa Ziehau /* 512015516c77SSepherosa Ziehau * Use txeof task, so that any pending oactive can be 512115516c77SSepherosa Ziehau * cleared properly. 512215516c77SSepherosa Ziehau */ 512315516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 512415516c77SSepherosa Ziehau } 512515516c77SSepherosa Ziehau } 512615516c77SSepherosa Ziehau 512715516c77SSepherosa Ziehau static void 512815516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc) 512915516c77SSepherosa Ziehau { 513015516c77SSepherosa Ziehau 513115516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 513215516c77SSepherosa Ziehau 513315516c77SSepherosa Ziehau /* 513415516c77SSepherosa Ziehau * Kick off network change detection, if it was pending. 513515516c77SSepherosa Ziehau * If no network change was pending, start link status 513615516c77SSepherosa Ziehau * checks, which is more lightweight than network change 513715516c77SSepherosa Ziehau * detection. 513815516c77SSepherosa Ziehau */ 513915516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 514015516c77SSepherosa Ziehau hn_change_network(sc); 514115516c77SSepherosa Ziehau else 514215516c77SSepherosa Ziehau hn_update_link_status(sc); 514315516c77SSepherosa Ziehau } 514415516c77SSepherosa Ziehau 514515516c77SSepherosa Ziehau static void 514615516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc) 514715516c77SSepherosa Ziehau { 514815516c77SSepherosa Ziehau 51495bdfd3fdSDexuan Cui if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || 51505bdfd3fdSDexuan Cui (sc->hn_flags & HN_FLAG_VF)) 515115516c77SSepherosa Ziehau hn_resume_data(sc); 51525bdfd3fdSDexuan Cui 51535bdfd3fdSDexuan Cui /* 51545bdfd3fdSDexuan Cui * When the VF is activated, the synthetic interface is changed 51555bdfd3fdSDexuan Cui * to DOWN in hn_set_vf(). Here, if the VF is still active, we 51565bdfd3fdSDexuan Cui * don't call hn_resume_mgmt() until the VF is deactivated in 51575bdfd3fdSDexuan Cui * hn_set_vf(). 51585bdfd3fdSDexuan Cui */ 51595bdfd3fdSDexuan Cui if (!(sc->hn_flags & HN_FLAG_VF)) 516015516c77SSepherosa Ziehau hn_resume_mgmt(sc); 516187f8129dSSepherosa Ziehau 516287f8129dSSepherosa Ziehau /* 516387f8129dSSepherosa Ziehau * Re-enable polling if this interface is running and 516487f8129dSSepherosa Ziehau * the polling is requested. 516587f8129dSSepherosa Ziehau */ 516687f8129dSSepherosa Ziehau if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0) 516787f8129dSSepherosa Ziehau hn_polling(sc, sc->hn_pollhz); 516815516c77SSepherosa Ziehau } 516915516c77SSepherosa Ziehau 517015516c77SSepherosa Ziehau static void 517115516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen) 517215516c77SSepherosa Ziehau { 517315516c77SSepherosa Ziehau const struct rndis_status_msg *msg; 517415516c77SSepherosa Ziehau int ofs; 517515516c77SSepherosa Ziehau 517615516c77SSepherosa Ziehau if (dlen < sizeof(*msg)) { 517715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid RNDIS status\n"); 517815516c77SSepherosa Ziehau return; 517915516c77SSepherosa Ziehau } 518015516c77SSepherosa Ziehau msg = data; 518115516c77SSepherosa Ziehau 518215516c77SSepherosa Ziehau switch (msg->rm_status) { 518315516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_CONNECT: 518415516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_DISCONNECT: 518515516c77SSepherosa Ziehau hn_update_link_status(sc); 518615516c77SSepherosa Ziehau break; 518715516c77SSepherosa Ziehau 518815516c77SSepherosa Ziehau case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: 518915516c77SSepherosa Ziehau /* Not really useful; ignore. */ 519015516c77SSepherosa Ziehau break; 519115516c77SSepherosa Ziehau 519215516c77SSepherosa Ziehau case RNDIS_STATUS_NETWORK_CHANGE: 519315516c77SSepherosa Ziehau ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset); 519415516c77SSepherosa Ziehau if (dlen < ofs + msg->rm_stbuflen || 519515516c77SSepherosa Ziehau msg->rm_stbuflen < sizeof(uint32_t)) { 519615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed\n"); 519715516c77SSepherosa Ziehau } else { 519815516c77SSepherosa Ziehau uint32_t change; 519915516c77SSepherosa Ziehau 520015516c77SSepherosa Ziehau memcpy(&change, ((const uint8_t *)msg) + ofs, 520115516c77SSepherosa Ziehau sizeof(change)); 520215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed, change %u\n", 520315516c77SSepherosa Ziehau change); 520415516c77SSepherosa Ziehau } 520515516c77SSepherosa Ziehau hn_change_network(sc); 520615516c77SSepherosa Ziehau break; 520715516c77SSepherosa Ziehau 520815516c77SSepherosa Ziehau default: 520915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n", 521015516c77SSepherosa Ziehau msg->rm_status); 521115516c77SSepherosa Ziehau break; 521215516c77SSepherosa Ziehau } 521315516c77SSepherosa Ziehau } 521415516c77SSepherosa Ziehau 521515516c77SSepherosa Ziehau static int 521615516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info) 521715516c77SSepherosa Ziehau { 521815516c77SSepherosa Ziehau const struct rndis_pktinfo *pi = info_data; 521915516c77SSepherosa Ziehau uint32_t mask = 0; 522015516c77SSepherosa Ziehau 522115516c77SSepherosa Ziehau while (info_dlen != 0) { 522215516c77SSepherosa Ziehau const void *data; 522315516c77SSepherosa Ziehau uint32_t dlen; 522415516c77SSepherosa Ziehau 522515516c77SSepherosa Ziehau if (__predict_false(info_dlen < sizeof(*pi))) 522615516c77SSepherosa Ziehau return (EINVAL); 522715516c77SSepherosa Ziehau if (__predict_false(info_dlen < pi->rm_size)) 522815516c77SSepherosa Ziehau return (EINVAL); 522915516c77SSepherosa Ziehau info_dlen -= pi->rm_size; 523015516c77SSepherosa Ziehau 523115516c77SSepherosa Ziehau if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK)) 523215516c77SSepherosa Ziehau return (EINVAL); 523315516c77SSepherosa Ziehau if (__predict_false(pi->rm_size < pi->rm_pktinfooffset)) 523415516c77SSepherosa Ziehau return (EINVAL); 523515516c77SSepherosa Ziehau dlen = pi->rm_size - pi->rm_pktinfooffset; 523615516c77SSepherosa Ziehau data = pi->rm_data; 523715516c77SSepherosa Ziehau 523815516c77SSepherosa Ziehau switch (pi->rm_type) { 523915516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_VLAN: 524015516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE)) 524115516c77SSepherosa Ziehau return (EINVAL); 524215516c77SSepherosa Ziehau info->vlan_info = *((const uint32_t *)data); 524315516c77SSepherosa Ziehau mask |= HN_RXINFO_VLAN; 524415516c77SSepherosa Ziehau break; 524515516c77SSepherosa Ziehau 524615516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_CSUM: 524715516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE)) 524815516c77SSepherosa Ziehau return (EINVAL); 524915516c77SSepherosa Ziehau info->csum_info = *((const uint32_t *)data); 525015516c77SSepherosa Ziehau mask |= HN_RXINFO_CSUM; 525115516c77SSepherosa Ziehau break; 525215516c77SSepherosa Ziehau 525315516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHVAL: 525415516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE)) 525515516c77SSepherosa Ziehau return (EINVAL); 525615516c77SSepherosa Ziehau info->hash_value = *((const uint32_t *)data); 525715516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHVAL; 525815516c77SSepherosa Ziehau break; 525915516c77SSepherosa Ziehau 526015516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHINF: 526115516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE)) 526215516c77SSepherosa Ziehau return (EINVAL); 526315516c77SSepherosa Ziehau info->hash_info = *((const uint32_t *)data); 526415516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHINF; 526515516c77SSepherosa Ziehau break; 526615516c77SSepherosa Ziehau 526715516c77SSepherosa Ziehau default: 526815516c77SSepherosa Ziehau goto next; 526915516c77SSepherosa Ziehau } 527015516c77SSepherosa Ziehau 527115516c77SSepherosa Ziehau if (mask == HN_RXINFO_ALL) { 527215516c77SSepherosa Ziehau /* All found; done */ 527315516c77SSepherosa Ziehau break; 527415516c77SSepherosa Ziehau } 527515516c77SSepherosa Ziehau next: 527615516c77SSepherosa Ziehau pi = (const struct rndis_pktinfo *) 527715516c77SSepherosa Ziehau ((const uint8_t *)pi + pi->rm_size); 527815516c77SSepherosa Ziehau } 527915516c77SSepherosa Ziehau 528015516c77SSepherosa Ziehau /* 528115516c77SSepherosa Ziehau * Final fixup. 528215516c77SSepherosa Ziehau * - If there is no hash value, invalidate the hash info. 528315516c77SSepherosa Ziehau */ 528415516c77SSepherosa Ziehau if ((mask & HN_RXINFO_HASHVAL) == 0) 528515516c77SSepherosa Ziehau info->hash_info = HN_NDIS_HASH_INFO_INVALID; 528615516c77SSepherosa Ziehau return (0); 528715516c77SSepherosa Ziehau } 528815516c77SSepherosa Ziehau 528915516c77SSepherosa Ziehau static __inline bool 529015516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len) 529115516c77SSepherosa Ziehau { 529215516c77SSepherosa Ziehau 529315516c77SSepherosa Ziehau if (off < check_off) { 529415516c77SSepherosa Ziehau if (__predict_true(off + len <= check_off)) 529515516c77SSepherosa Ziehau return (false); 529615516c77SSepherosa Ziehau } else if (off > check_off) { 529715516c77SSepherosa Ziehau if (__predict_true(check_off + check_len <= off)) 529815516c77SSepherosa Ziehau return (false); 529915516c77SSepherosa Ziehau } 530015516c77SSepherosa Ziehau return (true); 530115516c77SSepherosa Ziehau } 530215516c77SSepherosa Ziehau 530315516c77SSepherosa Ziehau static void 530415516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen) 530515516c77SSepherosa Ziehau { 530615516c77SSepherosa Ziehau const struct rndis_packet_msg *pkt; 530715516c77SSepherosa Ziehau struct hn_rxinfo info; 530815516c77SSepherosa Ziehau int data_off, pktinfo_off, data_len, pktinfo_len; 530915516c77SSepherosa Ziehau 531015516c77SSepherosa Ziehau /* 531115516c77SSepherosa Ziehau * Check length. 531215516c77SSepherosa Ziehau */ 531315516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*pkt))) { 531415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n"); 531515516c77SSepherosa Ziehau return; 531615516c77SSepherosa Ziehau } 531715516c77SSepherosa Ziehau pkt = data; 531815516c77SSepherosa Ziehau 531915516c77SSepherosa Ziehau if (__predict_false(dlen < pkt->rm_len)) { 532015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, " 532115516c77SSepherosa Ziehau "dlen %d, msglen %u\n", dlen, pkt->rm_len); 532215516c77SSepherosa Ziehau return; 532315516c77SSepherosa Ziehau } 532415516c77SSepherosa Ziehau if (__predict_false(pkt->rm_len < 532515516c77SSepherosa Ziehau pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) { 532615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, " 532715516c77SSepherosa Ziehau "msglen %u, data %u, oob %u, pktinfo %u\n", 532815516c77SSepherosa Ziehau pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen, 532915516c77SSepherosa Ziehau pkt->rm_pktinfolen); 533015516c77SSepherosa Ziehau return; 533115516c77SSepherosa Ziehau } 533215516c77SSepherosa Ziehau if (__predict_false(pkt->rm_datalen == 0)) { 533315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n"); 533415516c77SSepherosa Ziehau return; 533515516c77SSepherosa Ziehau } 533615516c77SSepherosa Ziehau 533715516c77SSepherosa Ziehau /* 533815516c77SSepherosa Ziehau * Check offests. 533915516c77SSepherosa Ziehau */ 534015516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs) \ 534115516c77SSepherosa Ziehau ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \ 534215516c77SSepherosa Ziehau ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK)) 534315516c77SSepherosa Ziehau 534415516c77SSepherosa Ziehau /* XXX Hyper-V does not meet data offset alignment requirement */ 534515516c77SSepherosa Ziehau if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) { 534615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 534715516c77SSepherosa Ziehau "data offset %u\n", pkt->rm_dataoffset); 534815516c77SSepherosa Ziehau return; 534915516c77SSepherosa Ziehau } 535015516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdataoffset > 0 && 535115516c77SSepherosa Ziehau IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) { 535215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 535315516c77SSepherosa Ziehau "oob offset %u\n", pkt->rm_oobdataoffset); 535415516c77SSepherosa Ziehau return; 535515516c77SSepherosa Ziehau } 535615516c77SSepherosa Ziehau if (__predict_true(pkt->rm_pktinfooffset > 0) && 535715516c77SSepherosa Ziehau __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) { 535815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 535915516c77SSepherosa Ziehau "pktinfo offset %u\n", pkt->rm_pktinfooffset); 536015516c77SSepherosa Ziehau return; 536115516c77SSepherosa Ziehau } 536215516c77SSepherosa Ziehau 536315516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID 536415516c77SSepherosa Ziehau 536515516c77SSepherosa Ziehau data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset); 536615516c77SSepherosa Ziehau data_len = pkt->rm_datalen; 536715516c77SSepherosa Ziehau pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset); 536815516c77SSepherosa Ziehau pktinfo_len = pkt->rm_pktinfolen; 536915516c77SSepherosa Ziehau 537015516c77SSepherosa Ziehau /* 537115516c77SSepherosa Ziehau * Check OOB coverage. 537215516c77SSepherosa Ziehau */ 537315516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdatalen != 0)) { 537415516c77SSepherosa Ziehau int oob_off, oob_len; 537515516c77SSepherosa Ziehau 537615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "got oobdata\n"); 537715516c77SSepherosa Ziehau oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset); 537815516c77SSepherosa Ziehau oob_len = pkt->rm_oobdatalen; 537915516c77SSepherosa Ziehau 538015516c77SSepherosa Ziehau if (__predict_false(oob_off + oob_len > pkt->rm_len)) { 538115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 538215516c77SSepherosa Ziehau "oob overflow, msglen %u, oob abs %d len %d\n", 538315516c77SSepherosa Ziehau pkt->rm_len, oob_off, oob_len); 538415516c77SSepherosa Ziehau return; 538515516c77SSepherosa Ziehau } 538615516c77SSepherosa Ziehau 538715516c77SSepherosa Ziehau /* 538815516c77SSepherosa Ziehau * Check against data. 538915516c77SSepherosa Ziehau */ 539015516c77SSepherosa Ziehau if (hn_rndis_check_overlap(oob_off, oob_len, 539115516c77SSepherosa Ziehau data_off, data_len)) { 539215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 539315516c77SSepherosa Ziehau "oob overlaps data, oob abs %d len %d, " 539415516c77SSepherosa Ziehau "data abs %d len %d\n", 539515516c77SSepherosa Ziehau oob_off, oob_len, data_off, data_len); 539615516c77SSepherosa Ziehau return; 539715516c77SSepherosa Ziehau } 539815516c77SSepherosa Ziehau 539915516c77SSepherosa Ziehau /* 540015516c77SSepherosa Ziehau * Check against pktinfo. 540115516c77SSepherosa Ziehau */ 540215516c77SSepherosa Ziehau if (pktinfo_len != 0 && 540315516c77SSepherosa Ziehau hn_rndis_check_overlap(oob_off, oob_len, 540415516c77SSepherosa Ziehau pktinfo_off, pktinfo_len)) { 540515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 540615516c77SSepherosa Ziehau "oob overlaps pktinfo, oob abs %d len %d, " 540715516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 540815516c77SSepherosa Ziehau oob_off, oob_len, pktinfo_off, pktinfo_len); 540915516c77SSepherosa Ziehau return; 541015516c77SSepherosa Ziehau } 541115516c77SSepherosa Ziehau } 541215516c77SSepherosa Ziehau 541315516c77SSepherosa Ziehau /* 541415516c77SSepherosa Ziehau * Check per-packet-info coverage and find useful per-packet-info. 541515516c77SSepherosa Ziehau */ 541615516c77SSepherosa Ziehau info.vlan_info = HN_NDIS_VLAN_INFO_INVALID; 541715516c77SSepherosa Ziehau info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID; 541815516c77SSepherosa Ziehau info.hash_info = HN_NDIS_HASH_INFO_INVALID; 541915516c77SSepherosa Ziehau if (__predict_true(pktinfo_len != 0)) { 542015516c77SSepherosa Ziehau bool overlap; 542115516c77SSepherosa Ziehau int error; 542215516c77SSepherosa Ziehau 542315516c77SSepherosa Ziehau if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) { 542415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 542515516c77SSepherosa Ziehau "pktinfo overflow, msglen %u, " 542615516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 542715516c77SSepherosa Ziehau pkt->rm_len, pktinfo_off, pktinfo_len); 542815516c77SSepherosa Ziehau return; 542915516c77SSepherosa Ziehau } 543015516c77SSepherosa Ziehau 543115516c77SSepherosa Ziehau /* 543215516c77SSepherosa Ziehau * Check packet info coverage. 543315516c77SSepherosa Ziehau */ 543415516c77SSepherosa Ziehau overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len, 543515516c77SSepherosa Ziehau data_off, data_len); 543615516c77SSepherosa Ziehau if (__predict_false(overlap)) { 543715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 543815516c77SSepherosa Ziehau "pktinfo overlap data, pktinfo abs %d len %d, " 543915516c77SSepherosa Ziehau "data abs %d len %d\n", 544015516c77SSepherosa Ziehau pktinfo_off, pktinfo_len, data_off, data_len); 544115516c77SSepherosa Ziehau return; 544215516c77SSepherosa Ziehau } 544315516c77SSepherosa Ziehau 544415516c77SSepherosa Ziehau /* 544515516c77SSepherosa Ziehau * Find useful per-packet-info. 544615516c77SSepherosa Ziehau */ 544715516c77SSepherosa Ziehau error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off, 544815516c77SSepherosa Ziehau pktinfo_len, &info); 544915516c77SSepherosa Ziehau if (__predict_false(error)) { 545015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg " 545115516c77SSepherosa Ziehau "pktinfo\n"); 545215516c77SSepherosa Ziehau return; 545315516c77SSepherosa Ziehau } 545415516c77SSepherosa Ziehau } 545515516c77SSepherosa Ziehau 545615516c77SSepherosa Ziehau if (__predict_false(data_off + data_len > pkt->rm_len)) { 545715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 545815516c77SSepherosa Ziehau "data overflow, msglen %u, data abs %d len %d\n", 545915516c77SSepherosa Ziehau pkt->rm_len, data_off, data_len); 546015516c77SSepherosa Ziehau return; 546115516c77SSepherosa Ziehau } 546215516c77SSepherosa Ziehau hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info); 546315516c77SSepherosa Ziehau } 546415516c77SSepherosa Ziehau 546515516c77SSepherosa Ziehau static __inline void 546615516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen) 546715516c77SSepherosa Ziehau { 546815516c77SSepherosa Ziehau const struct rndis_msghdr *hdr; 546915516c77SSepherosa Ziehau 547015516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*hdr))) { 547115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS msg\n"); 547215516c77SSepherosa Ziehau return; 547315516c77SSepherosa Ziehau } 547415516c77SSepherosa Ziehau hdr = data; 547515516c77SSepherosa Ziehau 547615516c77SSepherosa Ziehau if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) { 547715516c77SSepherosa Ziehau /* Hot data path. */ 547815516c77SSepherosa Ziehau hn_rndis_rx_data(rxr, data, dlen); 547915516c77SSepherosa Ziehau /* Done! */ 548015516c77SSepherosa Ziehau return; 548115516c77SSepherosa Ziehau } 548215516c77SSepherosa Ziehau 548315516c77SSepherosa Ziehau if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG) 548415516c77SSepherosa Ziehau hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen); 548515516c77SSepherosa Ziehau else 548615516c77SSepherosa Ziehau hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen); 548715516c77SSepherosa Ziehau } 548815516c77SSepherosa Ziehau 548915516c77SSepherosa Ziehau static void 549015516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) 549115516c77SSepherosa Ziehau { 549215516c77SSepherosa Ziehau const struct hn_nvs_hdr *hdr; 549315516c77SSepherosa Ziehau 549415516c77SSepherosa Ziehau if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) { 549515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid nvs notify\n"); 549615516c77SSepherosa Ziehau return; 549715516c77SSepherosa Ziehau } 549815516c77SSepherosa Ziehau hdr = VMBUS_CHANPKT_CONST_DATA(pkt); 549915516c77SSepherosa Ziehau 550015516c77SSepherosa Ziehau if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) { 550115516c77SSepherosa Ziehau /* Useless; ignore */ 550215516c77SSepherosa Ziehau return; 550315516c77SSepherosa Ziehau } 550415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type); 550515516c77SSepherosa Ziehau } 550615516c77SSepherosa Ziehau 550715516c77SSepherosa Ziehau static void 550815516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan, 550915516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkt) 551015516c77SSepherosa Ziehau { 551115516c77SSepherosa Ziehau struct hn_nvs_sendctx *sndc; 551215516c77SSepherosa Ziehau 551315516c77SSepherosa Ziehau sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid; 551415516c77SSepherosa Ziehau sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt), 551515516c77SSepherosa Ziehau VMBUS_CHANPKT_DATALEN(pkt)); 551615516c77SSepherosa Ziehau /* 551715516c77SSepherosa Ziehau * NOTE: 551815516c77SSepherosa Ziehau * 'sndc' CAN NOT be accessed anymore, since it can be freed by 551915516c77SSepherosa Ziehau * its callback. 552015516c77SSepherosa Ziehau */ 552115516c77SSepherosa Ziehau } 552215516c77SSepherosa Ziehau 552315516c77SSepherosa Ziehau static void 552415516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 552515516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkthdr) 552615516c77SSepherosa Ziehau { 552715516c77SSepherosa Ziehau const struct vmbus_chanpkt_rxbuf *pkt; 552815516c77SSepherosa Ziehau const struct hn_nvs_hdr *nvs_hdr; 552915516c77SSepherosa Ziehau int count, i, hlen; 553015516c77SSepherosa Ziehau 553115516c77SSepherosa Ziehau if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) { 553215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n"); 553315516c77SSepherosa Ziehau return; 553415516c77SSepherosa Ziehau } 553515516c77SSepherosa Ziehau nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr); 553615516c77SSepherosa Ziehau 553715516c77SSepherosa Ziehau /* Make sure that this is a RNDIS message. */ 553815516c77SSepherosa Ziehau if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) { 553915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n", 554015516c77SSepherosa Ziehau nvs_hdr->nvs_type); 554115516c77SSepherosa Ziehau return; 554215516c77SSepherosa Ziehau } 554315516c77SSepherosa Ziehau 554415516c77SSepherosa Ziehau hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen); 554515516c77SSepherosa Ziehau if (__predict_false(hlen < sizeof(*pkt))) { 554615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n"); 554715516c77SSepherosa Ziehau return; 554815516c77SSepherosa Ziehau } 554915516c77SSepherosa Ziehau pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr; 555015516c77SSepherosa Ziehau 555115516c77SSepherosa Ziehau if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) { 555215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n", 555315516c77SSepherosa Ziehau pkt->cp_rxbuf_id); 555415516c77SSepherosa Ziehau return; 555515516c77SSepherosa Ziehau } 555615516c77SSepherosa Ziehau 555715516c77SSepherosa Ziehau count = pkt->cp_rxbuf_cnt; 555815516c77SSepherosa Ziehau if (__predict_false(hlen < 555915516c77SSepherosa Ziehau __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) { 556015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count); 556115516c77SSepherosa Ziehau return; 556215516c77SSepherosa Ziehau } 556315516c77SSepherosa Ziehau 556415516c77SSepherosa Ziehau /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 556515516c77SSepherosa Ziehau for (i = 0; i < count; ++i) { 556615516c77SSepherosa Ziehau int ofs, len; 556715516c77SSepherosa Ziehau 556815516c77SSepherosa Ziehau ofs = pkt->cp_rxbuf[i].rb_ofs; 556915516c77SSepherosa Ziehau len = pkt->cp_rxbuf[i].rb_len; 557015516c77SSepherosa Ziehau if (__predict_false(ofs + len > HN_RXBUF_SIZE)) { 557115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, " 557215516c77SSepherosa Ziehau "ofs %d, len %d\n", i, ofs, len); 557315516c77SSepherosa Ziehau continue; 557415516c77SSepherosa Ziehau } 557515516c77SSepherosa Ziehau hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len); 557615516c77SSepherosa Ziehau } 557715516c77SSepherosa Ziehau 557815516c77SSepherosa Ziehau /* 557915516c77SSepherosa Ziehau * Ack the consumed RXBUF associated w/ this channel packet, 558015516c77SSepherosa Ziehau * so that this RXBUF can be recycled by the hypervisor. 558115516c77SSepherosa Ziehau */ 558215516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid); 558315516c77SSepherosa Ziehau } 558415516c77SSepherosa Ziehau 558515516c77SSepherosa Ziehau static void 558615516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 558715516c77SSepherosa Ziehau uint64_t tid) 558815516c77SSepherosa Ziehau { 558915516c77SSepherosa Ziehau struct hn_nvs_rndis_ack ack; 559015516c77SSepherosa Ziehau int retries, error; 559115516c77SSepherosa Ziehau 559215516c77SSepherosa Ziehau ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK; 559315516c77SSepherosa Ziehau ack.nvs_status = HN_NVS_STATUS_OK; 559415516c77SSepherosa Ziehau 559515516c77SSepherosa Ziehau retries = 0; 559615516c77SSepherosa Ziehau again: 559715516c77SSepherosa Ziehau error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 559815516c77SSepherosa Ziehau VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid); 559915516c77SSepherosa Ziehau if (__predict_false(error == EAGAIN)) { 560015516c77SSepherosa Ziehau /* 560115516c77SSepherosa Ziehau * NOTE: 560215516c77SSepherosa Ziehau * This should _not_ happen in real world, since the 560315516c77SSepherosa Ziehau * consumption of the TX bufring from the TX path is 560415516c77SSepherosa Ziehau * controlled. 560515516c77SSepherosa Ziehau */ 560615516c77SSepherosa Ziehau if (rxr->hn_ack_failed == 0) 560715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack retry\n"); 560815516c77SSepherosa Ziehau rxr->hn_ack_failed++; 560915516c77SSepherosa Ziehau retries++; 561015516c77SSepherosa Ziehau if (retries < 10) { 561115516c77SSepherosa Ziehau DELAY(100); 561215516c77SSepherosa Ziehau goto again; 561315516c77SSepherosa Ziehau } 561415516c77SSepherosa Ziehau /* RXBUF leaks! */ 561515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack failed\n"); 561615516c77SSepherosa Ziehau } 561715516c77SSepherosa Ziehau } 561815516c77SSepherosa Ziehau 561915516c77SSepherosa Ziehau static void 562015516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr) 562115516c77SSepherosa Ziehau { 562215516c77SSepherosa Ziehau struct hn_rx_ring *rxr = xrxr; 562315516c77SSepherosa Ziehau struct hn_softc *sc = rxr->hn_ifp->if_softc; 562415516c77SSepherosa Ziehau 562515516c77SSepherosa Ziehau for (;;) { 562615516c77SSepherosa Ziehau struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf; 562715516c77SSepherosa Ziehau int error, pktlen; 562815516c77SSepherosa Ziehau 562915516c77SSepherosa Ziehau pktlen = rxr->hn_pktbuf_len; 563015516c77SSepherosa Ziehau error = vmbus_chan_recv_pkt(chan, pkt, &pktlen); 563115516c77SSepherosa Ziehau if (__predict_false(error == ENOBUFS)) { 563215516c77SSepherosa Ziehau void *nbuf; 563315516c77SSepherosa Ziehau int nlen; 563415516c77SSepherosa Ziehau 563515516c77SSepherosa Ziehau /* 563615516c77SSepherosa Ziehau * Expand channel packet buffer. 563715516c77SSepherosa Ziehau * 563815516c77SSepherosa Ziehau * XXX 563915516c77SSepherosa Ziehau * Use M_WAITOK here, since allocation failure 564015516c77SSepherosa Ziehau * is fatal. 564115516c77SSepherosa Ziehau */ 564215516c77SSepherosa Ziehau nlen = rxr->hn_pktbuf_len * 2; 564315516c77SSepherosa Ziehau while (nlen < pktlen) 564415516c77SSepherosa Ziehau nlen *= 2; 564515516c77SSepherosa Ziehau nbuf = malloc(nlen, M_DEVBUF, M_WAITOK); 564615516c77SSepherosa Ziehau 564715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n", 564815516c77SSepherosa Ziehau rxr->hn_pktbuf_len, nlen); 564915516c77SSepherosa Ziehau 565015516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 565115516c77SSepherosa Ziehau rxr->hn_pktbuf = nbuf; 565215516c77SSepherosa Ziehau rxr->hn_pktbuf_len = nlen; 565315516c77SSepherosa Ziehau /* Retry! */ 565415516c77SSepherosa Ziehau continue; 565515516c77SSepherosa Ziehau } else if (__predict_false(error == EAGAIN)) { 565615516c77SSepherosa Ziehau /* No more channel packets; done! */ 565715516c77SSepherosa Ziehau break; 565815516c77SSepherosa Ziehau } 565915516c77SSepherosa Ziehau KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error)); 566015516c77SSepherosa Ziehau 566115516c77SSepherosa Ziehau switch (pkt->cph_type) { 566215516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_COMP: 566315516c77SSepherosa Ziehau hn_nvs_handle_comp(sc, chan, pkt); 566415516c77SSepherosa Ziehau break; 566515516c77SSepherosa Ziehau 566615516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_RXBUF: 566715516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(rxr, chan, pkt); 566815516c77SSepherosa Ziehau break; 566915516c77SSepherosa Ziehau 567015516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_INBAND: 567115516c77SSepherosa Ziehau hn_nvs_handle_notify(sc, pkt); 567215516c77SSepherosa Ziehau break; 567315516c77SSepherosa Ziehau 567415516c77SSepherosa Ziehau default: 567515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "unknown chan pkt %u\n", 567615516c77SSepherosa Ziehau pkt->cph_type); 567715516c77SSepherosa Ziehau break; 567815516c77SSepherosa Ziehau } 567915516c77SSepherosa Ziehau } 568015516c77SSepherosa Ziehau hn_chan_rollup(rxr, rxr->hn_txr); 568115516c77SSepherosa Ziehau } 568215516c77SSepherosa Ziehau 568315516c77SSepherosa Ziehau static void 568415516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused) 568515516c77SSepherosa Ziehau { 5686fdd0222aSSepherosa Ziehau int i; 5687fdd0222aSSepherosa Ziehau 5688fdd0222aSSepherosa Ziehau /* 5689fdd0222aSSepherosa Ziehau * Fix the # of TX taskqueues. 5690fdd0222aSSepherosa Ziehau */ 5691fdd0222aSSepherosa Ziehau if (hn_tx_taskq_cnt <= 0) 5692fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = 1; 5693fdd0222aSSepherosa Ziehau else if (hn_tx_taskq_cnt > mp_ncpus) 5694fdd0222aSSepherosa Ziehau hn_tx_taskq_cnt = mp_ncpus; 569515516c77SSepherosa Ziehau 56960e11868dSSepherosa Ziehau /* 56970e11868dSSepherosa Ziehau * Fix the TX taskqueue mode. 56980e11868dSSepherosa Ziehau */ 56990e11868dSSepherosa Ziehau switch (hn_tx_taskq_mode) { 57000e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_INDEP: 57010e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_GLOBAL: 57020e11868dSSepherosa Ziehau case HN_TX_TASKQ_M_EVTTQ: 57030e11868dSSepherosa Ziehau break; 57040e11868dSSepherosa Ziehau default: 57050e11868dSSepherosa Ziehau hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP; 57060e11868dSSepherosa Ziehau break; 57070e11868dSSepherosa Ziehau } 57080e11868dSSepherosa Ziehau 570915516c77SSepherosa Ziehau if (vm_guest != VM_GUEST_HV) 571015516c77SSepherosa Ziehau return; 571115516c77SSepherosa Ziehau 57120e11868dSSepherosa Ziehau if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL) 571315516c77SSepherosa Ziehau return; 571415516c77SSepherosa Ziehau 5715fdd0222aSSepherosa Ziehau hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), 5716fdd0222aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 5717fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) { 5718fdd0222aSSepherosa Ziehau hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK, 5719fdd0222aSSepherosa Ziehau taskqueue_thread_enqueue, &hn_tx_taskque[i]); 5720fdd0222aSSepherosa Ziehau taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET, 5721fdd0222aSSepherosa Ziehau "hn tx%d", i); 5722fdd0222aSSepherosa Ziehau } 572315516c77SSepherosa Ziehau } 572415516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND, 572515516c77SSepherosa Ziehau hn_tx_taskq_create, NULL); 572615516c77SSepherosa Ziehau 572715516c77SSepherosa Ziehau static void 572815516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused) 572915516c77SSepherosa Ziehau { 573015516c77SSepherosa Ziehau 5731fdd0222aSSepherosa Ziehau if (hn_tx_taskque != NULL) { 5732fdd0222aSSepherosa Ziehau int i; 5733fdd0222aSSepherosa Ziehau 5734fdd0222aSSepherosa Ziehau for (i = 0; i < hn_tx_taskq_cnt; ++i) 5735fdd0222aSSepherosa Ziehau taskqueue_free(hn_tx_taskque[i]); 5736fdd0222aSSepherosa Ziehau free(hn_tx_taskque, M_DEVBUF); 5737fdd0222aSSepherosa Ziehau } 573815516c77SSepherosa Ziehau } 573915516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND, 574015516c77SSepherosa Ziehau hn_tx_taskq_destroy, NULL); 5741