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 5815516c77SSepherosa Ziehau #include "opt_inet6.h" 5915516c77SSepherosa Ziehau #include "opt_inet.h" 6015516c77SSepherosa Ziehau 6115516c77SSepherosa Ziehau #include <sys/param.h> 6215516c77SSepherosa Ziehau #include <sys/bus.h> 6315516c77SSepherosa Ziehau #include <sys/kernel.h> 6415516c77SSepherosa Ziehau #include <sys/limits.h> 6515516c77SSepherosa Ziehau #include <sys/malloc.h> 6615516c77SSepherosa Ziehau #include <sys/mbuf.h> 6715516c77SSepherosa Ziehau #include <sys/module.h> 6815516c77SSepherosa Ziehau #include <sys/queue.h> 6915516c77SSepherosa Ziehau #include <sys/lock.h> 7015516c77SSepherosa Ziehau #include <sys/smp.h> 7115516c77SSepherosa Ziehau #include <sys/socket.h> 7215516c77SSepherosa Ziehau #include <sys/sockio.h> 7315516c77SSepherosa Ziehau #include <sys/sx.h> 7415516c77SSepherosa Ziehau #include <sys/sysctl.h> 7515516c77SSepherosa Ziehau #include <sys/systm.h> 7615516c77SSepherosa Ziehau #include <sys/taskqueue.h> 7715516c77SSepherosa Ziehau #include <sys/buf_ring.h> 7815516c77SSepherosa Ziehau 7915516c77SSepherosa Ziehau #include <machine/atomic.h> 8015516c77SSepherosa Ziehau #include <machine/in_cksum.h> 8115516c77SSepherosa Ziehau 8215516c77SSepherosa Ziehau #include <net/bpf.h> 8315516c77SSepherosa Ziehau #include <net/ethernet.h> 8415516c77SSepherosa Ziehau #include <net/if.h> 8515516c77SSepherosa Ziehau #include <net/if_media.h> 8615516c77SSepherosa Ziehau #include <net/if_types.h> 8715516c77SSepherosa Ziehau #include <net/if_var.h> 8815516c77SSepherosa Ziehau #include <net/rndis.h> 8915516c77SSepherosa Ziehau 9015516c77SSepherosa Ziehau #include <netinet/in_systm.h> 9115516c77SSepherosa Ziehau #include <netinet/in.h> 9215516c77SSepherosa Ziehau #include <netinet/ip.h> 9315516c77SSepherosa Ziehau #include <netinet/ip6.h> 9415516c77SSepherosa Ziehau #include <netinet/tcp.h> 9515516c77SSepherosa Ziehau #include <netinet/tcp_lro.h> 9615516c77SSepherosa Ziehau #include <netinet/udp.h> 9715516c77SSepherosa Ziehau 9815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h> 9915516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h> 10015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h> 10115516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h> 10215516c77SSepherosa Ziehau 10315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h> 10415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h> 10515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h> 10615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h> 10715516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h> 10815516c77SSepherosa Ziehau 10915516c77SSepherosa Ziehau #include "vmbus_if.h" 11015516c77SSepherosa Ziehau 11123bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT 11223bf9e15SSepherosa Ziehau 11315516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX 8 11415516c77SSepherosa Ziehau 11515516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */ 11615516c77SSepherosa Ziehau #define HN_TX_DESC_CNT 512 11715516c77SSepherosa Ziehau 11815516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN \ 11915516c77SSepherosa Ziehau (sizeof(struct rndis_packet_msg) + \ 12015516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) + \ 12115516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) + \ 12215516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) + \ 12315516c77SSepherosa Ziehau HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE)) 12415516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY PAGE_SIZE 12515516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN CACHE_LINE_SIZE 12615516c77SSepherosa Ziehau 12715516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY PAGE_SIZE 12815516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE IP_MAXPACKET 12915516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE PAGE_SIZE 13015516c77SSepherosa Ziehau /* -1 for RNDIS packet message */ 13115516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX (HN_GPACNT_MAX - 1) 13215516c77SSepherosa Ziehau 13315516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF 128 13415516c77SSepherosa Ziehau 13515516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH 8 13615516c77SSepherosa Ziehau 13715516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF (16 * 1024) 13815516c77SSepherosa Ziehau 13915516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF 128 14015516c77SSepherosa Ziehau 14115516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF (12 * ETHERMTU) 14215516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF (25 * ETHERMTU) 14315516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */ 14415516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp) (2 * (ifp)->if_mtu) 14515516c77SSepherosa Ziehau 14615516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF 1 14715516c77SSepherosa Ziehau 14815516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc) \ 14915516c77SSepherosa Ziehau sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev)) 15015516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc) sx_destroy(&(sc)->hn_lock) 15115516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc) sx_assert(&(sc)->hn_lock, SA_XLOCKED) 152fdc4f478SSepherosa Ziehau #define HN_LOCK(sc) \ 153fdc4f478SSepherosa Ziehau do { \ 154fdc4f478SSepherosa Ziehau while (sx_try_xlock(&(sc)->hn_lock) == 0) \ 155fdc4f478SSepherosa Ziehau DELAY(1000); \ 156fdc4f478SSepherosa Ziehau } while (0) 15715516c77SSepherosa Ziehau #define HN_UNLOCK(sc) sx_xunlock(&(sc)->hn_lock) 15815516c77SSepherosa Ziehau 15915516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK (CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP) 16015516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK (CSUM_IP6_TCP | CSUM_IP6_UDP) 16115516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc) \ 16215516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK) 16315516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc) \ 16415516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK) 16515516c77SSepherosa Ziehau 166dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align) \ 167dc13fee6SSepherosa Ziehau roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \ 168dc13fee6SSepherosa Ziehau HN_RNDIS_PKT_LEN, (align)) 169dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align) \ 170dc13fee6SSepherosa Ziehau roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align)) 171dc13fee6SSepherosa Ziehau 17215516c77SSepherosa Ziehau struct hn_txdesc { 17315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 17415516c77SSepherosa Ziehau SLIST_ENTRY(hn_txdesc) link; 17515516c77SSepherosa Ziehau #endif 176dc13fee6SSepherosa Ziehau STAILQ_ENTRY(hn_txdesc) agg_link; 177dc13fee6SSepherosa Ziehau 178dc13fee6SSepherosa Ziehau /* Aggregated txdescs, in sending order. */ 179dc13fee6SSepherosa Ziehau STAILQ_HEAD(, hn_txdesc) agg_list; 180dc13fee6SSepherosa Ziehau 181dc13fee6SSepherosa Ziehau /* The oldest packet, if transmission aggregation happens. */ 18215516c77SSepherosa Ziehau struct mbuf *m; 18315516c77SSepherosa Ziehau struct hn_tx_ring *txr; 18415516c77SSepherosa Ziehau int refs; 18515516c77SSepherosa Ziehau uint32_t flags; /* HN_TXD_FLAG_ */ 18615516c77SSepherosa Ziehau struct hn_nvs_sendctx send_ctx; 18715516c77SSepherosa Ziehau uint32_t chim_index; 18815516c77SSepherosa Ziehau int chim_size; 18915516c77SSepherosa Ziehau 19015516c77SSepherosa Ziehau bus_dmamap_t data_dmap; 19115516c77SSepherosa Ziehau 19215516c77SSepherosa Ziehau bus_addr_t rndis_pkt_paddr; 19315516c77SSepherosa Ziehau struct rndis_packet_msg *rndis_pkt; 19415516c77SSepherosa Ziehau bus_dmamap_t rndis_pkt_dmap; 19515516c77SSepherosa Ziehau }; 19615516c77SSepherosa Ziehau 19715516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST 0x0001 19815516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP 0x0002 199dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG 0x0004 20015516c77SSepherosa Ziehau 20115516c77SSepherosa Ziehau struct hn_rxinfo { 20215516c77SSepherosa Ziehau uint32_t vlan_info; 20315516c77SSepherosa Ziehau uint32_t csum_info; 20415516c77SSepherosa Ziehau uint32_t hash_info; 20515516c77SSepherosa Ziehau uint32_t hash_value; 20615516c77SSepherosa Ziehau }; 20715516c77SSepherosa Ziehau 20815516c77SSepherosa Ziehau #define HN_RXINFO_VLAN 0x0001 20915516c77SSepherosa Ziehau #define HN_RXINFO_CSUM 0x0002 21015516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF 0x0004 21115516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL 0x0008 21215516c77SSepherosa Ziehau #define HN_RXINFO_ALL \ 21315516c77SSepherosa Ziehau (HN_RXINFO_VLAN | \ 21415516c77SSepherosa Ziehau HN_RXINFO_CSUM | \ 21515516c77SSepherosa Ziehau HN_RXINFO_HASHINF | \ 21615516c77SSepherosa Ziehau HN_RXINFO_HASHVAL) 21715516c77SSepherosa Ziehau 21815516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID 0xffffffff 21915516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID 0 22015516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID 0 22115516c77SSepherosa Ziehau 22215516c77SSepherosa Ziehau static int hn_probe(device_t); 22315516c77SSepherosa Ziehau static int hn_attach(device_t); 22415516c77SSepherosa Ziehau static int hn_detach(device_t); 22515516c77SSepherosa Ziehau static int hn_shutdown(device_t); 22615516c77SSepherosa Ziehau static void hn_chan_callback(struct vmbus_channel *, 22715516c77SSepherosa Ziehau void *); 22815516c77SSepherosa Ziehau 22915516c77SSepherosa Ziehau static void hn_init(void *); 23015516c77SSepherosa Ziehau static int hn_ioctl(struct ifnet *, u_long, caddr_t); 23123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 23215516c77SSepherosa Ziehau static void hn_start(struct ifnet *); 23323bf9e15SSepherosa Ziehau #endif 23415516c77SSepherosa Ziehau static int hn_transmit(struct ifnet *, struct mbuf *); 23515516c77SSepherosa Ziehau static void hn_xmit_qflush(struct ifnet *); 23615516c77SSepherosa Ziehau static int hn_ifmedia_upd(struct ifnet *); 23715516c77SSepherosa Ziehau static void hn_ifmedia_sts(struct ifnet *, 23815516c77SSepherosa Ziehau struct ifmediareq *); 23915516c77SSepherosa Ziehau 24015516c77SSepherosa Ziehau static int hn_rndis_rxinfo(const void *, int, 24115516c77SSepherosa Ziehau struct hn_rxinfo *); 24215516c77SSepherosa Ziehau static void hn_rndis_rx_data(struct hn_rx_ring *, 24315516c77SSepherosa Ziehau const void *, int); 24415516c77SSepherosa Ziehau static void hn_rndis_rx_status(struct hn_softc *, 24515516c77SSepherosa Ziehau const void *, int); 24615516c77SSepherosa Ziehau 24715516c77SSepherosa Ziehau static void hn_nvs_handle_notify(struct hn_softc *, 24815516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 24915516c77SSepherosa Ziehau static void hn_nvs_handle_comp(struct hn_softc *, 25015516c77SSepherosa Ziehau struct vmbus_channel *, 25115516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 25215516c77SSepherosa Ziehau static void hn_nvs_handle_rxbuf(struct hn_rx_ring *, 25315516c77SSepherosa Ziehau struct vmbus_channel *, 25415516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 25515516c77SSepherosa Ziehau static void hn_nvs_ack_rxbuf(struct hn_rx_ring *, 25615516c77SSepherosa Ziehau struct vmbus_channel *, uint64_t); 25715516c77SSepherosa Ziehau 25815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 25915516c77SSepherosa Ziehau static int hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS); 26015516c77SSepherosa Ziehau static int hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS); 26115516c77SSepherosa Ziehau #endif 26215516c77SSepherosa Ziehau static int hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS); 26315516c77SSepherosa Ziehau static int hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS); 26415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 26515516c77SSepherosa Ziehau static int hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS); 26615516c77SSepherosa Ziehau #else 26715516c77SSepherosa Ziehau static int hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS); 26815516c77SSepherosa Ziehau #endif 26915516c77SSepherosa Ziehau static int hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 27015516c77SSepherosa Ziehau static int hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 27115516c77SSepherosa Ziehau static int hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS); 27215516c77SSepherosa Ziehau static int hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS); 27315516c77SSepherosa Ziehau static int hn_caps_sysctl(SYSCTL_HANDLER_ARGS); 27415516c77SSepherosa Ziehau static int hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS); 27515516c77SSepherosa Ziehau static int hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS); 27615516c77SSepherosa Ziehau static int hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS); 27715516c77SSepherosa Ziehau static int hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS); 27815516c77SSepherosa Ziehau static int hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS); 279dc13fee6SSepherosa Ziehau static int hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS); 280dc13fee6SSepherosa Ziehau static int hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS); 281dc13fee6SSepherosa Ziehau static int hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS); 282dc13fee6SSepherosa Ziehau static int hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS); 28315516c77SSepherosa Ziehau 28415516c77SSepherosa Ziehau static void hn_stop(struct hn_softc *); 28515516c77SSepherosa Ziehau static void hn_init_locked(struct hn_softc *); 28615516c77SSepherosa Ziehau static int hn_chan_attach(struct hn_softc *, 28715516c77SSepherosa Ziehau struct vmbus_channel *); 28815516c77SSepherosa Ziehau static void hn_chan_detach(struct hn_softc *, 28915516c77SSepherosa Ziehau struct vmbus_channel *); 29015516c77SSepherosa Ziehau static int hn_attach_subchans(struct hn_softc *); 29115516c77SSepherosa Ziehau static void hn_detach_allchans(struct hn_softc *); 29215516c77SSepherosa Ziehau static void hn_chan_rollup(struct hn_rx_ring *, 29315516c77SSepherosa Ziehau struct hn_tx_ring *); 29415516c77SSepherosa Ziehau static void hn_set_ring_inuse(struct hn_softc *, int); 29515516c77SSepherosa Ziehau static int hn_synth_attach(struct hn_softc *, int); 29615516c77SSepherosa Ziehau static void hn_synth_detach(struct hn_softc *); 29715516c77SSepherosa Ziehau static int hn_synth_alloc_subchans(struct hn_softc *, 29815516c77SSepherosa Ziehau int *); 2992494d735SSepherosa Ziehau static bool hn_synth_attachable(const struct hn_softc *); 30015516c77SSepherosa Ziehau static void hn_suspend(struct hn_softc *); 30115516c77SSepherosa Ziehau static void hn_suspend_data(struct hn_softc *); 30215516c77SSepherosa Ziehau static void hn_suspend_mgmt(struct hn_softc *); 30315516c77SSepherosa Ziehau static void hn_resume(struct hn_softc *); 30415516c77SSepherosa Ziehau static void hn_resume_data(struct hn_softc *); 30515516c77SSepherosa Ziehau static void hn_resume_mgmt(struct hn_softc *); 30615516c77SSepherosa Ziehau static void hn_suspend_mgmt_taskfunc(void *, int); 30725641fc7SSepherosa Ziehau static void hn_chan_drain(struct hn_softc *, 30825641fc7SSepherosa Ziehau struct vmbus_channel *); 30915516c77SSepherosa Ziehau 31015516c77SSepherosa Ziehau static void hn_update_link_status(struct hn_softc *); 31115516c77SSepherosa Ziehau static void hn_change_network(struct hn_softc *); 31215516c77SSepherosa Ziehau static void hn_link_taskfunc(void *, int); 31315516c77SSepherosa Ziehau static void hn_netchg_init_taskfunc(void *, int); 31415516c77SSepherosa Ziehau static void hn_netchg_status_taskfunc(void *, int); 31515516c77SSepherosa Ziehau static void hn_link_status(struct hn_softc *); 31615516c77SSepherosa Ziehau 31715516c77SSepherosa Ziehau static int hn_create_rx_data(struct hn_softc *, int); 31815516c77SSepherosa Ziehau static void hn_destroy_rx_data(struct hn_softc *); 31915516c77SSepherosa Ziehau static int hn_check_iplen(const struct mbuf *, int); 32015516c77SSepherosa Ziehau static int hn_set_rxfilter(struct hn_softc *); 32115516c77SSepherosa Ziehau static int hn_rss_reconfig(struct hn_softc *); 32215516c77SSepherosa Ziehau static void hn_rss_ind_fixup(struct hn_softc *, int); 32315516c77SSepherosa Ziehau static int hn_rxpkt(struct hn_rx_ring *, const void *, 32415516c77SSepherosa Ziehau int, const struct hn_rxinfo *); 32515516c77SSepherosa Ziehau 32615516c77SSepherosa Ziehau static int hn_tx_ring_create(struct hn_softc *, int); 32715516c77SSepherosa Ziehau static void hn_tx_ring_destroy(struct hn_tx_ring *); 32815516c77SSepherosa Ziehau static int hn_create_tx_data(struct hn_softc *, int); 32915516c77SSepherosa Ziehau static void hn_fixup_tx_data(struct hn_softc *); 33015516c77SSepherosa Ziehau static void hn_destroy_tx_data(struct hn_softc *); 33115516c77SSepherosa Ziehau static void hn_txdesc_dmamap_destroy(struct hn_txdesc *); 33225641fc7SSepherosa Ziehau static void hn_txdesc_gc(struct hn_tx_ring *, 33325641fc7SSepherosa Ziehau struct hn_txdesc *); 334dc13fee6SSepherosa Ziehau static int hn_encap(struct ifnet *, struct hn_tx_ring *, 33515516c77SSepherosa Ziehau struct hn_txdesc *, struct mbuf **); 33615516c77SSepherosa Ziehau static int hn_txpkt(struct ifnet *, struct hn_tx_ring *, 33715516c77SSepherosa Ziehau struct hn_txdesc *); 33815516c77SSepherosa Ziehau static void hn_set_chim_size(struct hn_softc *, int); 33915516c77SSepherosa Ziehau static void hn_set_tso_maxsize(struct hn_softc *, int, int); 34015516c77SSepherosa Ziehau static bool hn_tx_ring_pending(struct hn_tx_ring *); 34115516c77SSepherosa Ziehau static void hn_tx_ring_qflush(struct hn_tx_ring *); 34215516c77SSepherosa Ziehau static void hn_resume_tx(struct hn_softc *, int); 343dc13fee6SSepherosa Ziehau static void hn_set_txagg(struct hn_softc *); 344dc13fee6SSepherosa Ziehau static void *hn_try_txagg(struct ifnet *, 345dc13fee6SSepherosa Ziehau struct hn_tx_ring *, struct hn_txdesc *, 346dc13fee6SSepherosa Ziehau int); 34715516c77SSepherosa Ziehau static int hn_get_txswq_depth(const struct hn_tx_ring *); 34815516c77SSepherosa Ziehau static void hn_txpkt_done(struct hn_nvs_sendctx *, 34915516c77SSepherosa Ziehau struct hn_softc *, struct vmbus_channel *, 35015516c77SSepherosa Ziehau const void *, int); 35115516c77SSepherosa Ziehau static int hn_txpkt_sglist(struct hn_tx_ring *, 35215516c77SSepherosa Ziehau struct hn_txdesc *); 35315516c77SSepherosa Ziehau static int hn_txpkt_chim(struct hn_tx_ring *, 35415516c77SSepherosa Ziehau struct hn_txdesc *); 35515516c77SSepherosa Ziehau static int hn_xmit(struct hn_tx_ring *, int); 35615516c77SSepherosa Ziehau static void hn_xmit_taskfunc(void *, int); 35715516c77SSepherosa Ziehau static void hn_xmit_txeof(struct hn_tx_ring *); 35815516c77SSepherosa Ziehau static void hn_xmit_txeof_taskfunc(void *, int); 35923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 36015516c77SSepherosa Ziehau static int hn_start_locked(struct hn_tx_ring *, int); 36115516c77SSepherosa Ziehau static void hn_start_taskfunc(void *, int); 36215516c77SSepherosa Ziehau static void hn_start_txeof(struct hn_tx_ring *); 36315516c77SSepherosa Ziehau static void hn_start_txeof_taskfunc(void *, int); 36423bf9e15SSepherosa Ziehau #endif 36515516c77SSepherosa Ziehau 36615516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 36715516c77SSepherosa Ziehau "Hyper-V network interface"); 36815516c77SSepherosa Ziehau 36915516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */ 37015516c77SSepherosa Ziehau static int hn_trust_hosttcp = 1; 37115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN, 37215516c77SSepherosa Ziehau &hn_trust_hosttcp, 0, 37315516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 37415516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 37515516c77SSepherosa Ziehau 37615516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */ 37715516c77SSepherosa Ziehau static int hn_trust_hostudp = 1; 37815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN, 37915516c77SSepherosa Ziehau &hn_trust_hostudp, 0, 38015516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 38115516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 38215516c77SSepherosa Ziehau 38315516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */ 38415516c77SSepherosa Ziehau static int hn_trust_hostip = 1; 38515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN, 38615516c77SSepherosa Ziehau &hn_trust_hostip, 0, 38715516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 38815516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 38915516c77SSepherosa Ziehau 39015516c77SSepherosa Ziehau /* Limit TSO burst size */ 39115516c77SSepherosa Ziehau static int hn_tso_maxlen = IP_MAXPACKET; 39215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN, 39315516c77SSepherosa Ziehau &hn_tso_maxlen, 0, "TSO burst limit"); 39415516c77SSepherosa Ziehau 39515516c77SSepherosa Ziehau /* Limit chimney send size */ 39615516c77SSepherosa Ziehau static int hn_tx_chimney_size = 0; 39715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN, 39815516c77SSepherosa Ziehau &hn_tx_chimney_size, 0, "Chimney send packet size limit"); 39915516c77SSepherosa Ziehau 40015516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */ 40115516c77SSepherosa Ziehau static int hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF; 40215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN, 40315516c77SSepherosa Ziehau &hn_direct_tx_size, 0, "Size of the packet for direct transmission"); 40415516c77SSepherosa Ziehau 40515516c77SSepherosa Ziehau /* # of LRO entries per RX ring */ 40615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 40715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 40815516c77SSepherosa Ziehau static int hn_lro_entry_count = HN_LROENT_CNT_DEF; 40915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN, 41015516c77SSepherosa Ziehau &hn_lro_entry_count, 0, "LRO entry count"); 41115516c77SSepherosa Ziehau #endif 41215516c77SSepherosa Ziehau #endif 41315516c77SSepherosa Ziehau 41415516c77SSepherosa Ziehau /* Use shared TX taskqueue */ 41515516c77SSepherosa Ziehau static int hn_share_tx_taskq = 0; 41615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, share_tx_taskq, CTLFLAG_RDTUN, 41715516c77SSepherosa Ziehau &hn_share_tx_taskq, 0, "Enable shared TX taskqueue"); 41815516c77SSepherosa Ziehau 41915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 42015516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 0; 42115516c77SSepherosa Ziehau #else 42215516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 1; 42315516c77SSepherosa Ziehau #endif 42415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD, 42515516c77SSepherosa Ziehau &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors"); 42615516c77SSepherosa Ziehau 42715516c77SSepherosa Ziehau /* Bind TX taskqueue to the target CPU */ 42815516c77SSepherosa Ziehau static int hn_bind_tx_taskq = -1; 42915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, bind_tx_taskq, CTLFLAG_RDTUN, 43015516c77SSepherosa Ziehau &hn_bind_tx_taskq, 0, "Bind TX taskqueue to the specified cpu"); 43115516c77SSepherosa Ziehau 43223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 43315516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */ 43415516c77SSepherosa Ziehau static int hn_use_if_start = 0; 43515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN, 43615516c77SSepherosa Ziehau &hn_use_if_start, 0, "Use if_start TX method"); 43723bf9e15SSepherosa Ziehau #endif 43815516c77SSepherosa Ziehau 43915516c77SSepherosa Ziehau /* # of channels to use */ 44015516c77SSepherosa Ziehau static int hn_chan_cnt = 0; 44115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN, 44215516c77SSepherosa Ziehau &hn_chan_cnt, 0, 44315516c77SSepherosa Ziehau "# of channels to use; each channel has one RX ring and one TX ring"); 44415516c77SSepherosa Ziehau 44515516c77SSepherosa Ziehau /* # of transmit rings to use */ 44615516c77SSepherosa Ziehau static int hn_tx_ring_cnt = 0; 44715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN, 44815516c77SSepherosa Ziehau &hn_tx_ring_cnt, 0, "# of TX rings to use"); 44915516c77SSepherosa Ziehau 45015516c77SSepherosa Ziehau /* Software TX ring deptch */ 45115516c77SSepherosa Ziehau static int hn_tx_swq_depth = 0; 45215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN, 45315516c77SSepherosa Ziehau &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING"); 45415516c77SSepherosa Ziehau 45515516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */ 45615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 45715516c77SSepherosa Ziehau static u_int hn_lro_mbufq_depth = 0; 45815516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN, 45915516c77SSepherosa Ziehau &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue"); 46015516c77SSepherosa Ziehau #endif 46115516c77SSepherosa Ziehau 462dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */ 463dc13fee6SSepherosa Ziehau static int hn_tx_agg_size = -1; 464dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN, 465dc13fee6SSepherosa Ziehau &hn_tx_agg_size, 0, "Packet transmission aggregation size limit"); 466dc13fee6SSepherosa Ziehau 467dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */ 468dc13fee6SSepherosa Ziehau static int hn_tx_agg_pkts = 0; 469dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN, 470dc13fee6SSepherosa Ziehau &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit"); 471dc13fee6SSepherosa Ziehau 47215516c77SSepherosa Ziehau static u_int hn_cpu_index; /* next CPU for channel */ 47315516c77SSepherosa Ziehau static struct taskqueue *hn_tx_taskq; /* shared TX taskqueue */ 47415516c77SSepherosa Ziehau 47515516c77SSepherosa Ziehau static const uint8_t 47615516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = { 47715516c77SSepherosa Ziehau 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 47815516c77SSepherosa Ziehau 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 47915516c77SSepherosa Ziehau 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 48015516c77SSepherosa Ziehau 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 48115516c77SSepherosa Ziehau 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa 48215516c77SSepherosa Ziehau }; 48315516c77SSepherosa Ziehau 48415516c77SSepherosa Ziehau static device_method_t hn_methods[] = { 48515516c77SSepherosa Ziehau /* Device interface */ 48615516c77SSepherosa Ziehau DEVMETHOD(device_probe, hn_probe), 48715516c77SSepherosa Ziehau DEVMETHOD(device_attach, hn_attach), 48815516c77SSepherosa Ziehau DEVMETHOD(device_detach, hn_detach), 48915516c77SSepherosa Ziehau DEVMETHOD(device_shutdown, hn_shutdown), 49015516c77SSepherosa Ziehau DEVMETHOD_END 49115516c77SSepherosa Ziehau }; 49215516c77SSepherosa Ziehau 49315516c77SSepherosa Ziehau static driver_t hn_driver = { 49415516c77SSepherosa Ziehau "hn", 49515516c77SSepherosa Ziehau hn_methods, 49615516c77SSepherosa Ziehau sizeof(struct hn_softc) 49715516c77SSepherosa Ziehau }; 49815516c77SSepherosa Ziehau 49915516c77SSepherosa Ziehau static devclass_t hn_devclass; 50015516c77SSepherosa Ziehau 50115516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0); 50215516c77SSepherosa Ziehau MODULE_VERSION(hn, 1); 50315516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1); 50415516c77SSepherosa Ziehau 50515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 50615516c77SSepherosa Ziehau static void 50715516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim) 50815516c77SSepherosa Ziehau { 50915516c77SSepherosa Ziehau int i; 51015516c77SSepherosa Ziehau 511a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 51215516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim; 51315516c77SSepherosa Ziehau } 51415516c77SSepherosa Ziehau #endif 51515516c77SSepherosa Ziehau 51615516c77SSepherosa Ziehau static int 51715516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd) 51815516c77SSepherosa Ziehau { 51915516c77SSepherosa Ziehau 52015516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 52115516c77SSepherosa Ziehau txd->chim_size == 0, ("invalid rndis sglist txd")); 52215516c77SSepherosa Ziehau return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA, 52315516c77SSepherosa Ziehau &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt)); 52415516c77SSepherosa Ziehau } 52515516c77SSepherosa Ziehau 52615516c77SSepherosa Ziehau static int 52715516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd) 52815516c77SSepherosa Ziehau { 52915516c77SSepherosa Ziehau struct hn_nvs_rndis rndis; 53015516c77SSepherosa Ziehau 53115516c77SSepherosa Ziehau KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID && 53215516c77SSepherosa Ziehau txd->chim_size > 0, ("invalid rndis chim txd")); 53315516c77SSepherosa Ziehau 53415516c77SSepherosa Ziehau rndis.nvs_type = HN_NVS_TYPE_RNDIS; 53515516c77SSepherosa Ziehau rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA; 53615516c77SSepherosa Ziehau rndis.nvs_chim_idx = txd->chim_index; 53715516c77SSepherosa Ziehau rndis.nvs_chim_sz = txd->chim_size; 53815516c77SSepherosa Ziehau 53915516c77SSepherosa Ziehau return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC, 54015516c77SSepherosa Ziehau &rndis, sizeof(rndis), &txd->send_ctx)); 54115516c77SSepherosa Ziehau } 54215516c77SSepherosa Ziehau 54315516c77SSepherosa Ziehau static __inline uint32_t 54415516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc) 54515516c77SSepherosa Ziehau { 54615516c77SSepherosa Ziehau int i, bmap_cnt = sc->hn_chim_bmap_cnt; 54715516c77SSepherosa Ziehau u_long *bmap = sc->hn_chim_bmap; 54815516c77SSepherosa Ziehau uint32_t ret = HN_NVS_CHIM_IDX_INVALID; 54915516c77SSepherosa Ziehau 55015516c77SSepherosa Ziehau for (i = 0; i < bmap_cnt; ++i) { 55115516c77SSepherosa Ziehau int idx; 55215516c77SSepherosa Ziehau 55315516c77SSepherosa Ziehau idx = ffsl(~bmap[i]); 55415516c77SSepherosa Ziehau if (idx == 0) 55515516c77SSepherosa Ziehau continue; 55615516c77SSepherosa Ziehau 55715516c77SSepherosa Ziehau --idx; /* ffsl is 1-based */ 55815516c77SSepherosa Ziehau KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt, 55915516c77SSepherosa Ziehau ("invalid i %d and idx %d", i, idx)); 56015516c77SSepherosa Ziehau 56115516c77SSepherosa Ziehau if (atomic_testandset_long(&bmap[i], idx)) 56215516c77SSepherosa Ziehau continue; 56315516c77SSepherosa Ziehau 56415516c77SSepherosa Ziehau ret = i * LONG_BIT + idx; 56515516c77SSepherosa Ziehau break; 56615516c77SSepherosa Ziehau } 56715516c77SSepherosa Ziehau return (ret); 56815516c77SSepherosa Ziehau } 56915516c77SSepherosa Ziehau 57015516c77SSepherosa Ziehau static __inline void 57115516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx) 57215516c77SSepherosa Ziehau { 57315516c77SSepherosa Ziehau u_long mask; 57415516c77SSepherosa Ziehau uint32_t idx; 57515516c77SSepherosa Ziehau 57615516c77SSepherosa Ziehau idx = chim_idx / LONG_BIT; 57715516c77SSepherosa Ziehau KASSERT(idx < sc->hn_chim_bmap_cnt, 57815516c77SSepherosa Ziehau ("invalid chimney index 0x%x", chim_idx)); 57915516c77SSepherosa Ziehau 58015516c77SSepherosa Ziehau mask = 1UL << (chim_idx % LONG_BIT); 58115516c77SSepherosa Ziehau KASSERT(sc->hn_chim_bmap[idx] & mask, 58215516c77SSepherosa Ziehau ("index bitmap 0x%lx, chimney index %u, " 58315516c77SSepherosa Ziehau "bitmap idx %d, bitmask 0x%lx", 58415516c77SSepherosa Ziehau sc->hn_chim_bmap[idx], chim_idx, idx, mask)); 58515516c77SSepherosa Ziehau 58615516c77SSepherosa Ziehau atomic_clear_long(&sc->hn_chim_bmap[idx], mask); 58715516c77SSepherosa Ziehau } 58815516c77SSepherosa Ziehau 589edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 590edd3f315SSepherosa Ziehau /* 591edd3f315SSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 592edd3f315SSepherosa Ziehau */ 593edd3f315SSepherosa Ziehau static __inline struct mbuf * 594edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head) 595edd3f315SSepherosa Ziehau { 596edd3f315SSepherosa Ziehau struct ether_vlan_header *evl; 597edd3f315SSepherosa Ziehau struct tcphdr *th; 598edd3f315SSepherosa Ziehau int ehlen; 599edd3f315SSepherosa Ziehau 600edd3f315SSepherosa Ziehau KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable")); 601edd3f315SSepherosa Ziehau 602edd3f315SSepherosa Ziehau #define PULLUP_HDR(m, len) \ 603edd3f315SSepherosa Ziehau do { \ 604edd3f315SSepherosa Ziehau if (__predict_false((m)->m_len < (len))) { \ 605edd3f315SSepherosa Ziehau (m) = m_pullup((m), (len)); \ 606edd3f315SSepherosa Ziehau if ((m) == NULL) \ 607edd3f315SSepherosa Ziehau return (NULL); \ 608edd3f315SSepherosa Ziehau } \ 609edd3f315SSepherosa Ziehau } while (0) 610edd3f315SSepherosa Ziehau 611edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, sizeof(*evl)); 612edd3f315SSepherosa Ziehau evl = mtod(m_head, struct ether_vlan_header *); 613edd3f315SSepherosa Ziehau if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) 614edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 615edd3f315SSepherosa Ziehau else 616edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN; 617edd3f315SSepherosa Ziehau 618edd3f315SSepherosa Ziehau #ifdef INET 619edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 620edd3f315SSepherosa Ziehau struct ip *ip; 621edd3f315SSepherosa Ziehau int iphlen; 622edd3f315SSepherosa Ziehau 623edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip)); 624edd3f315SSepherosa Ziehau ip = mtodo(m_head, ehlen); 625edd3f315SSepherosa Ziehau iphlen = ip->ip_hl << 2; 626edd3f315SSepherosa Ziehau 627edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 628edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 629edd3f315SSepherosa Ziehau 630edd3f315SSepherosa Ziehau ip->ip_len = 0; 631edd3f315SSepherosa Ziehau ip->ip_sum = 0; 632edd3f315SSepherosa Ziehau th->th_sum = in_pseudo(ip->ip_src.s_addr, 633edd3f315SSepherosa Ziehau ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 634edd3f315SSepherosa Ziehau } 635edd3f315SSepherosa Ziehau #endif 636edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET) 637edd3f315SSepherosa Ziehau else 638edd3f315SSepherosa Ziehau #endif 639edd3f315SSepherosa Ziehau #ifdef INET6 640edd3f315SSepherosa Ziehau { 641edd3f315SSepherosa Ziehau struct ip6_hdr *ip6; 642edd3f315SSepherosa Ziehau 643edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); 644edd3f315SSepherosa Ziehau ip6 = mtodo(m_head, ehlen); 645edd3f315SSepherosa Ziehau if (ip6->ip6_nxt != IPPROTO_TCP) { 646edd3f315SSepherosa Ziehau m_freem(m_head); 647edd3f315SSepherosa Ziehau return (NULL); 648edd3f315SSepherosa Ziehau } 649edd3f315SSepherosa Ziehau 650edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); 651edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + sizeof(*ip6)); 652edd3f315SSepherosa Ziehau 653edd3f315SSepherosa Ziehau ip6->ip6_plen = 0; 654edd3f315SSepherosa Ziehau th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 655edd3f315SSepherosa Ziehau } 656edd3f315SSepherosa Ziehau #endif 657edd3f315SSepherosa Ziehau return (m_head); 658edd3f315SSepherosa Ziehau 659edd3f315SSepherosa Ziehau #undef PULLUP_HDR 660edd3f315SSepherosa Ziehau } 661edd3f315SSepherosa Ziehau #endif /* INET6 || INET */ 662edd3f315SSepherosa Ziehau 66315516c77SSepherosa Ziehau static int 66415516c77SSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc) 66515516c77SSepherosa Ziehau { 66615516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 66715516c77SSepherosa Ziehau uint32_t filter; 66815516c77SSepherosa Ziehau int error = 0; 66915516c77SSepherosa Ziehau 67015516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 67115516c77SSepherosa Ziehau 67215516c77SSepherosa Ziehau if (ifp->if_flags & IFF_PROMISC) { 67315516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_PROMISCUOUS; 67415516c77SSepherosa Ziehau } else { 67515516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_DIRECTED; 67615516c77SSepherosa Ziehau if (ifp->if_flags & IFF_BROADCAST) 67715516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_BROADCAST; 67815516c77SSepherosa Ziehau /* TODO: support multicast list */ 67915516c77SSepherosa Ziehau if ((ifp->if_flags & IFF_ALLMULTI) || 68015516c77SSepherosa Ziehau !TAILQ_EMPTY(&ifp->if_multiaddrs)) 68115516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 68215516c77SSepherosa Ziehau } 68315516c77SSepherosa Ziehau 68415516c77SSepherosa Ziehau if (sc->hn_rx_filter != filter) { 68515516c77SSepherosa Ziehau error = hn_rndis_set_rxfilter(sc, filter); 68615516c77SSepherosa Ziehau if (!error) 68715516c77SSepherosa Ziehau sc->hn_rx_filter = filter; 68815516c77SSepherosa Ziehau } 68915516c77SSepherosa Ziehau return (error); 69015516c77SSepherosa Ziehau } 69115516c77SSepherosa Ziehau 692dc13fee6SSepherosa Ziehau static void 693dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc) 694dc13fee6SSepherosa Ziehau { 695dc13fee6SSepherosa Ziehau uint32_t size, pkts; 696dc13fee6SSepherosa Ziehau int i; 697dc13fee6SSepherosa Ziehau 698dc13fee6SSepherosa Ziehau /* 699dc13fee6SSepherosa Ziehau * Setup aggregation size. 700dc13fee6SSepherosa Ziehau */ 701dc13fee6SSepherosa Ziehau if (sc->hn_agg_size < 0) 702dc13fee6SSepherosa Ziehau size = UINT32_MAX; 703dc13fee6SSepherosa Ziehau else 704dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 705dc13fee6SSepherosa Ziehau 706dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_size < size) 707dc13fee6SSepherosa Ziehau size = sc->hn_rndis_agg_size; 708dc13fee6SSepherosa Ziehau 709*a4364cfeSSepherosa Ziehau /* NOTE: We only aggregate packets using chimney sending buffers. */ 710*a4364cfeSSepherosa Ziehau if (size > (uint32_t)sc->hn_chim_szmax) 711*a4364cfeSSepherosa Ziehau size = sc->hn_chim_szmax; 712*a4364cfeSSepherosa Ziehau 713dc13fee6SSepherosa Ziehau if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) { 714dc13fee6SSepherosa Ziehau /* Disable */ 715dc13fee6SSepherosa Ziehau size = 0; 716dc13fee6SSepherosa Ziehau pkts = 0; 717dc13fee6SSepherosa Ziehau goto done; 718dc13fee6SSepherosa Ziehau } 719dc13fee6SSepherosa Ziehau 720dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'int'. */ 721dc13fee6SSepherosa Ziehau if (size > INT_MAX) 722dc13fee6SSepherosa Ziehau size = INT_MAX; 723dc13fee6SSepherosa Ziehau 724dc13fee6SSepherosa Ziehau /* 725dc13fee6SSepherosa Ziehau * Setup aggregation packet count. 726dc13fee6SSepherosa Ziehau */ 727dc13fee6SSepherosa Ziehau if (sc->hn_agg_pkts < 0) 728dc13fee6SSepherosa Ziehau pkts = UINT32_MAX; 729dc13fee6SSepherosa Ziehau else 730dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 731dc13fee6SSepherosa Ziehau 732dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_pkts < pkts) 733dc13fee6SSepherosa Ziehau pkts = sc->hn_rndis_agg_pkts; 734dc13fee6SSepherosa Ziehau 735dc13fee6SSepherosa Ziehau if (pkts <= 1) { 736dc13fee6SSepherosa Ziehau /* Disable */ 737dc13fee6SSepherosa Ziehau size = 0; 738dc13fee6SSepherosa Ziehau pkts = 0; 739dc13fee6SSepherosa Ziehau goto done; 740dc13fee6SSepherosa Ziehau } 741dc13fee6SSepherosa Ziehau 742dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 743dc13fee6SSepherosa Ziehau if (pkts > SHRT_MAX) 744dc13fee6SSepherosa Ziehau pkts = SHRT_MAX; 745dc13fee6SSepherosa Ziehau 746dc13fee6SSepherosa Ziehau done: 747dc13fee6SSepherosa Ziehau /* NOTE: Type of the per TX ring setting is 'short'. */ 748dc13fee6SSepherosa Ziehau if (sc->hn_rndis_agg_align > SHRT_MAX) { 749dc13fee6SSepherosa Ziehau /* Disable */ 750dc13fee6SSepherosa Ziehau size = 0; 751dc13fee6SSepherosa Ziehau pkts = 0; 752dc13fee6SSepherosa Ziehau } 753dc13fee6SSepherosa Ziehau 754dc13fee6SSepherosa Ziehau if (bootverbose) { 755dc13fee6SSepherosa Ziehau if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n", 756dc13fee6SSepherosa Ziehau size, pkts, sc->hn_rndis_agg_align); 757dc13fee6SSepherosa Ziehau } 758dc13fee6SSepherosa Ziehau 759dc13fee6SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 760dc13fee6SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 761dc13fee6SSepherosa Ziehau 762dc13fee6SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 763dc13fee6SSepherosa Ziehau txr->hn_agg_szmax = size; 764dc13fee6SSepherosa Ziehau txr->hn_agg_pktmax = pkts; 765dc13fee6SSepherosa Ziehau txr->hn_agg_align = sc->hn_rndis_agg_align; 766dc13fee6SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 767dc13fee6SSepherosa Ziehau } 768dc13fee6SSepherosa Ziehau } 769dc13fee6SSepherosa Ziehau 77015516c77SSepherosa Ziehau static int 77115516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr) 77215516c77SSepherosa Ziehau { 77315516c77SSepherosa Ziehau 77415516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet")); 77515516c77SSepherosa Ziehau if (hn_tx_swq_depth < txr->hn_txdesc_cnt) 77615516c77SSepherosa Ziehau return txr->hn_txdesc_cnt; 77715516c77SSepherosa Ziehau return hn_tx_swq_depth; 77815516c77SSepherosa Ziehau } 77915516c77SSepherosa Ziehau 78015516c77SSepherosa Ziehau static int 78115516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc) 78215516c77SSepherosa Ziehau { 78315516c77SSepherosa Ziehau int error; 78415516c77SSepherosa Ziehau 78515516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 78615516c77SSepherosa Ziehau 78715516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 78815516c77SSepherosa Ziehau return (ENXIO); 78915516c77SSepherosa Ziehau 79015516c77SSepherosa Ziehau /* 79115516c77SSepherosa Ziehau * Disable RSS first. 79215516c77SSepherosa Ziehau * 79315516c77SSepherosa Ziehau * NOTE: 79415516c77SSepherosa Ziehau * Direct reconfiguration by setting the UNCHG flags does 79515516c77SSepherosa Ziehau * _not_ work properly. 79615516c77SSepherosa Ziehau */ 79715516c77SSepherosa Ziehau if (bootverbose) 79815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "disable RSS\n"); 79915516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE); 80015516c77SSepherosa Ziehau if (error) { 80115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS disable failed\n"); 80215516c77SSepherosa Ziehau return (error); 80315516c77SSepherosa Ziehau } 80415516c77SSepherosa Ziehau 80515516c77SSepherosa Ziehau /* 80615516c77SSepherosa Ziehau * Reenable the RSS w/ the updated RSS key or indirect 80715516c77SSepherosa Ziehau * table. 80815516c77SSepherosa Ziehau */ 80915516c77SSepherosa Ziehau if (bootverbose) 81015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "reconfig RSS\n"); 81115516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 81215516c77SSepherosa Ziehau if (error) { 81315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS reconfig failed\n"); 81415516c77SSepherosa Ziehau return (error); 81515516c77SSepherosa Ziehau } 81615516c77SSepherosa Ziehau return (0); 81715516c77SSepherosa Ziehau } 81815516c77SSepherosa Ziehau 81915516c77SSepherosa Ziehau static void 82015516c77SSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc, int nchan) 82115516c77SSepherosa Ziehau { 82215516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 82315516c77SSepherosa Ziehau int i; 82415516c77SSepherosa Ziehau 82515516c77SSepherosa Ziehau KASSERT(nchan > 1, ("invalid # of channels %d", nchan)); 82615516c77SSepherosa Ziehau 82715516c77SSepherosa Ziehau /* 82815516c77SSepherosa Ziehau * Check indirect table to make sure that all channels in it 82915516c77SSepherosa Ziehau * can be used. 83015516c77SSepherosa Ziehau */ 83115516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 83215516c77SSepherosa Ziehau if (rss->rss_ind[i] >= nchan) { 83315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, 83415516c77SSepherosa Ziehau "RSS indirect table %d fixup: %u -> %d\n", 83515516c77SSepherosa Ziehau i, rss->rss_ind[i], nchan - 1); 83615516c77SSepherosa Ziehau rss->rss_ind[i] = nchan - 1; 83715516c77SSepherosa Ziehau } 83815516c77SSepherosa Ziehau } 83915516c77SSepherosa Ziehau } 84015516c77SSepherosa Ziehau 84115516c77SSepherosa Ziehau static int 84215516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused) 84315516c77SSepherosa Ziehau { 84415516c77SSepherosa Ziehau 84515516c77SSepherosa Ziehau return EOPNOTSUPP; 84615516c77SSepherosa Ziehau } 84715516c77SSepherosa Ziehau 84815516c77SSepherosa Ziehau static void 84915516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 85015516c77SSepherosa Ziehau { 85115516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 85215516c77SSepherosa Ziehau 85315516c77SSepherosa Ziehau ifmr->ifm_status = IFM_AVALID; 85415516c77SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 85515516c77SSepherosa Ziehau 85615516c77SSepherosa Ziehau if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) { 85715516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_NONE; 85815516c77SSepherosa Ziehau return; 85915516c77SSepherosa Ziehau } 86015516c77SSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 86115516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 86215516c77SSepherosa Ziehau } 86315516c77SSepherosa Ziehau 86415516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ 86515516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = { 86615516c77SSepherosa Ziehau .hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 86715516c77SSepherosa Ziehau 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E} 86815516c77SSepherosa Ziehau }; 86915516c77SSepherosa Ziehau 87015516c77SSepherosa Ziehau static int 87115516c77SSepherosa Ziehau hn_probe(device_t dev) 87215516c77SSepherosa Ziehau { 87315516c77SSepherosa Ziehau 87415516c77SSepherosa Ziehau if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, 87515516c77SSepherosa Ziehau &g_net_vsc_device_type) == 0) { 87615516c77SSepherosa Ziehau device_set_desc(dev, "Hyper-V Network Interface"); 87715516c77SSepherosa Ziehau return BUS_PROBE_DEFAULT; 87815516c77SSepherosa Ziehau } 87915516c77SSepherosa Ziehau return ENXIO; 88015516c77SSepherosa Ziehau } 88115516c77SSepherosa Ziehau 88215516c77SSepherosa Ziehau static int 88315516c77SSepherosa Ziehau hn_attach(device_t dev) 88415516c77SSepherosa Ziehau { 88515516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 88615516c77SSepherosa Ziehau struct sysctl_oid_list *child; 88715516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 88815516c77SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 88915516c77SSepherosa Ziehau struct ifnet *ifp = NULL; 89015516c77SSepherosa Ziehau int error, ring_cnt, tx_ring_cnt; 89115516c77SSepherosa Ziehau 89215516c77SSepherosa Ziehau sc->hn_dev = dev; 89315516c77SSepherosa Ziehau sc->hn_prichan = vmbus_get_channel(dev); 89415516c77SSepherosa Ziehau HN_LOCK_INIT(sc); 89515516c77SSepherosa Ziehau 89615516c77SSepherosa Ziehau /* 897dc13fee6SSepherosa Ziehau * Initialize these tunables once. 898dc13fee6SSepherosa Ziehau */ 899dc13fee6SSepherosa Ziehau sc->hn_agg_size = hn_tx_agg_size; 900dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = hn_tx_agg_pkts; 901dc13fee6SSepherosa Ziehau 902dc13fee6SSepherosa Ziehau /* 90315516c77SSepherosa Ziehau * Setup taskqueue for transmission. 90415516c77SSepherosa Ziehau */ 90515516c77SSepherosa Ziehau if (hn_tx_taskq == NULL) { 90615516c77SSepherosa Ziehau sc->hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK, 90715516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_tx_taskq); 90815516c77SSepherosa Ziehau if (hn_bind_tx_taskq >= 0) { 90915516c77SSepherosa Ziehau int cpu = hn_bind_tx_taskq; 91015516c77SSepherosa Ziehau cpuset_t cpu_set; 91115516c77SSepherosa Ziehau 91215516c77SSepherosa Ziehau if (cpu > mp_ncpus - 1) 91315516c77SSepherosa Ziehau cpu = mp_ncpus - 1; 91415516c77SSepherosa Ziehau CPU_SETOF(cpu, &cpu_set); 91515516c77SSepherosa Ziehau taskqueue_start_threads_cpuset(&sc->hn_tx_taskq, 1, 91615516c77SSepherosa Ziehau PI_NET, &cpu_set, "%s tx", 91715516c77SSepherosa Ziehau device_get_nameunit(dev)); 91815516c77SSepherosa Ziehau } else { 91915516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_tx_taskq, 1, PI_NET, 92015516c77SSepherosa Ziehau "%s tx", device_get_nameunit(dev)); 92115516c77SSepherosa Ziehau } 92215516c77SSepherosa Ziehau } else { 92315516c77SSepherosa Ziehau sc->hn_tx_taskq = hn_tx_taskq; 92415516c77SSepherosa Ziehau } 92515516c77SSepherosa Ziehau 92615516c77SSepherosa Ziehau /* 92715516c77SSepherosa Ziehau * Setup taskqueue for mangement tasks, e.g. link status. 92815516c77SSepherosa Ziehau */ 92915516c77SSepherosa Ziehau sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK, 93015516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0); 93115516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt", 93215516c77SSepherosa Ziehau device_get_nameunit(dev)); 93315516c77SSepherosa Ziehau TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc); 93415516c77SSepherosa Ziehau TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc); 93515516c77SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0, 93615516c77SSepherosa Ziehau hn_netchg_status_taskfunc, sc); 93715516c77SSepherosa Ziehau 93815516c77SSepherosa Ziehau /* 93915516c77SSepherosa Ziehau * Allocate ifnet and setup its name earlier, so that if_printf 94015516c77SSepherosa Ziehau * can be used by functions, which will be called after 94115516c77SSepherosa Ziehau * ether_ifattach(). 94215516c77SSepherosa Ziehau */ 94315516c77SSepherosa Ziehau ifp = sc->hn_ifp = if_alloc(IFT_ETHER); 94415516c77SSepherosa Ziehau ifp->if_softc = sc; 94515516c77SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 94615516c77SSepherosa Ziehau 94715516c77SSepherosa Ziehau /* 94815516c77SSepherosa Ziehau * Initialize ifmedia earlier so that it can be unconditionally 94915516c77SSepherosa Ziehau * destroyed, if error happened later on. 95015516c77SSepherosa Ziehau */ 95115516c77SSepherosa Ziehau ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts); 95215516c77SSepherosa Ziehau 95315516c77SSepherosa Ziehau /* 95415516c77SSepherosa Ziehau * Figure out the # of RX rings (ring_cnt) and the # of TX rings 95515516c77SSepherosa Ziehau * to use (tx_ring_cnt). 95615516c77SSepherosa Ziehau * 95715516c77SSepherosa Ziehau * NOTE: 95815516c77SSepherosa Ziehau * The # of RX rings to use is same as the # of channels to use. 95915516c77SSepherosa Ziehau */ 96015516c77SSepherosa Ziehau ring_cnt = hn_chan_cnt; 96115516c77SSepherosa Ziehau if (ring_cnt <= 0) { 96215516c77SSepherosa Ziehau /* Default */ 96315516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 96415516c77SSepherosa Ziehau if (ring_cnt > HN_RING_CNT_DEF_MAX) 96515516c77SSepherosa Ziehau ring_cnt = HN_RING_CNT_DEF_MAX; 96615516c77SSepherosa Ziehau } else if (ring_cnt > mp_ncpus) { 96715516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 96815516c77SSepherosa Ziehau } 96915516c77SSepherosa Ziehau 97015516c77SSepherosa Ziehau tx_ring_cnt = hn_tx_ring_cnt; 97115516c77SSepherosa Ziehau if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt) 97215516c77SSepherosa Ziehau tx_ring_cnt = ring_cnt; 97323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 97415516c77SSepherosa Ziehau if (hn_use_if_start) { 97515516c77SSepherosa Ziehau /* ifnet.if_start only needs one TX ring. */ 97615516c77SSepherosa Ziehau tx_ring_cnt = 1; 97715516c77SSepherosa Ziehau } 97823bf9e15SSepherosa Ziehau #endif 97915516c77SSepherosa Ziehau 98015516c77SSepherosa Ziehau /* 98115516c77SSepherosa Ziehau * Set the leader CPU for channels. 98215516c77SSepherosa Ziehau */ 98315516c77SSepherosa Ziehau sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus; 98415516c77SSepherosa Ziehau 98515516c77SSepherosa Ziehau /* 98615516c77SSepherosa Ziehau * Create enough TX/RX rings, even if only limited number of 98715516c77SSepherosa Ziehau * channels can be allocated. 98815516c77SSepherosa Ziehau */ 98915516c77SSepherosa Ziehau error = hn_create_tx_data(sc, tx_ring_cnt); 99015516c77SSepherosa Ziehau if (error) 99115516c77SSepherosa Ziehau goto failed; 99215516c77SSepherosa Ziehau error = hn_create_rx_data(sc, ring_cnt); 99315516c77SSepherosa Ziehau if (error) 99415516c77SSepherosa Ziehau goto failed; 99515516c77SSepherosa Ziehau 99615516c77SSepherosa Ziehau /* 99715516c77SSepherosa Ziehau * Create transaction context for NVS and RNDIS transactions. 99815516c77SSepherosa Ziehau */ 99915516c77SSepherosa Ziehau sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev), 100015516c77SSepherosa Ziehau HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0); 100125641fc7SSepherosa Ziehau if (sc->hn_xact == NULL) { 100225641fc7SSepherosa Ziehau error = ENXIO; 100315516c77SSepherosa Ziehau goto failed; 100425641fc7SSepherosa Ziehau } 100525641fc7SSepherosa Ziehau 100625641fc7SSepherosa Ziehau /* 100725641fc7SSepherosa Ziehau * Install orphan handler for the revocation of this device's 100825641fc7SSepherosa Ziehau * primary channel. 100925641fc7SSepherosa Ziehau * 101025641fc7SSepherosa Ziehau * NOTE: 101125641fc7SSepherosa Ziehau * The processing order is critical here: 101225641fc7SSepherosa Ziehau * Install the orphan handler, _before_ testing whether this 101325641fc7SSepherosa Ziehau * device's primary channel has been revoked or not. 101425641fc7SSepherosa Ziehau */ 101525641fc7SSepherosa Ziehau vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact); 101625641fc7SSepherosa Ziehau if (vmbus_chan_is_revoked(sc->hn_prichan)) { 101725641fc7SSepherosa Ziehau error = ENXIO; 101825641fc7SSepherosa Ziehau goto failed; 101925641fc7SSepherosa Ziehau } 102015516c77SSepherosa Ziehau 102115516c77SSepherosa Ziehau /* 102215516c77SSepherosa Ziehau * Attach the synthetic parts, i.e. NVS and RNDIS. 102315516c77SSepherosa Ziehau */ 102415516c77SSepherosa Ziehau error = hn_synth_attach(sc, ETHERMTU); 102515516c77SSepherosa Ziehau if (error) 102615516c77SSepherosa Ziehau goto failed; 102715516c77SSepherosa Ziehau 102815516c77SSepherosa Ziehau error = hn_rndis_get_eaddr(sc, eaddr); 102915516c77SSepherosa Ziehau if (error) 103015516c77SSepherosa Ziehau goto failed; 103115516c77SSepherosa Ziehau 103215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 103315516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 103415516c77SSepherosa Ziehau /* 103515516c77SSepherosa Ziehau * Reduce TCP segment aggregation limit for multiple 103615516c77SSepherosa Ziehau * RX rings to increase ACK timeliness. 103715516c77SSepherosa Ziehau */ 103815516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF); 103915516c77SSepherosa Ziehau } 104015516c77SSepherosa Ziehau #endif 104115516c77SSepherosa Ziehau 104215516c77SSepherosa Ziehau /* 104315516c77SSepherosa Ziehau * Fixup TX stuffs after synthetic parts are attached. 104415516c77SSepherosa Ziehau */ 104515516c77SSepherosa Ziehau hn_fixup_tx_data(sc); 104615516c77SSepherosa Ziehau 104715516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 104815516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 104915516c77SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD, 105015516c77SSepherosa Ziehau &sc->hn_nvs_ver, 0, "NVS version"); 105115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version", 105215516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 105315516c77SSepherosa Ziehau hn_ndis_version_sysctl, "A", "NDIS version"); 105415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps", 105515516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 105615516c77SSepherosa Ziehau hn_caps_sysctl, "A", "capabilities"); 105715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist", 105815516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 105915516c77SSepherosa Ziehau hn_hwassist_sysctl, "A", "hwassist"); 106015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter", 106115516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 106215516c77SSepherosa Ziehau hn_rxfilter_sysctl, "A", "rxfilter"); 106315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash", 106415516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 106515516c77SSepherosa Ziehau hn_rss_hash_sysctl, "A", "RSS hash"); 106615516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size", 106715516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count"); 106815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key", 106915516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 107015516c77SSepherosa Ziehau hn_rss_key_sysctl, "IU", "RSS key"); 107115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind", 107215516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 107315516c77SSepherosa Ziehau hn_rss_ind_sysctl, "IU", "RSS indirect table"); 1074dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size", 1075dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_size, 0, 1076dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation size limit"); 1077dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts", 1078dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0, 1079dc13fee6SSepherosa Ziehau "RNDIS offered packet transmission aggregation count limit"); 1080dc13fee6SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align", 1081dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rndis_agg_align, 0, 1082dc13fee6SSepherosa Ziehau "RNDIS packet transmission aggregation alignment"); 1083dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size", 1084dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 1085dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl, "I", 1086dc13fee6SSepherosa Ziehau "Packet transmission aggregation size, 0 -- disable, -1 -- auto"); 1087dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts", 1088dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 1089dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl, "I", 1090dc13fee6SSepherosa Ziehau "Packet transmission aggregation packets, " 1091dc13fee6SSepherosa Ziehau "0 -- disable, -1 -- auto"); 109215516c77SSepherosa Ziehau 109315516c77SSepherosa Ziehau /* 109415516c77SSepherosa Ziehau * Setup the ifmedia, which has been initialized earlier. 109515516c77SSepherosa Ziehau */ 109615516c77SSepherosa Ziehau ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL); 109715516c77SSepherosa Ziehau ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO); 109815516c77SSepherosa Ziehau /* XXX ifmedia_set really should do this for us */ 109915516c77SSepherosa Ziehau sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media; 110015516c77SSepherosa Ziehau 110115516c77SSepherosa Ziehau /* 110215516c77SSepherosa Ziehau * Setup the ifnet for this interface. 110315516c77SSepherosa Ziehau */ 110415516c77SSepherosa Ziehau 110515516c77SSepherosa Ziehau ifp->if_baudrate = IF_Gbps(10); 110615516c77SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 110715516c77SSepherosa Ziehau ifp->if_ioctl = hn_ioctl; 110815516c77SSepherosa Ziehau ifp->if_init = hn_init; 110923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 111015516c77SSepherosa Ziehau if (hn_use_if_start) { 111115516c77SSepherosa Ziehau int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]); 111215516c77SSepherosa Ziehau 111315516c77SSepherosa Ziehau ifp->if_start = hn_start; 111415516c77SSepherosa Ziehau IFQ_SET_MAXLEN(&ifp->if_snd, qdepth); 111515516c77SSepherosa Ziehau ifp->if_snd.ifq_drv_maxlen = qdepth - 1; 111615516c77SSepherosa Ziehau IFQ_SET_READY(&ifp->if_snd); 111723bf9e15SSepherosa Ziehau } else 111823bf9e15SSepherosa Ziehau #endif 111923bf9e15SSepherosa Ziehau { 112015516c77SSepherosa Ziehau ifp->if_transmit = hn_transmit; 112115516c77SSepherosa Ziehau ifp->if_qflush = hn_xmit_qflush; 112215516c77SSepherosa Ziehau } 112315516c77SSepherosa Ziehau 112415516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO; 112515516c77SSepherosa Ziehau #ifdef foo 112615516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 112715516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM_IPV6; 112815516c77SSepherosa Ziehau #endif 112915516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_VLAN) { 113015516c77SSepherosa Ziehau /* XXX not sure about VLAN_MTU. */ 113115516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 113215516c77SSepherosa Ziehau } 113315516c77SSepherosa Ziehau 113415516c77SSepherosa Ziehau ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist; 113515516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP_MASK) 113615516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM; 113715516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP6_MASK) 113815516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM_IPV6; 113915516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO4) { 114015516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO4; 114115516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 114215516c77SSepherosa Ziehau } 114315516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO6) { 114415516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO6; 114515516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 114615516c77SSepherosa Ziehau } 114715516c77SSepherosa Ziehau 114815516c77SSepherosa Ziehau /* Enable all available capabilities by default. */ 114915516c77SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 115015516c77SSepherosa Ziehau 11517960e6baSSepherosa Ziehau /* 11527960e6baSSepherosa Ziehau * Disable IPv6 TSO and TXCSUM by default, they still can 11537960e6baSSepherosa Ziehau * be enabled through SIOCSIFCAP. 11547960e6baSSepherosa Ziehau */ 11557960e6baSSepherosa Ziehau ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 11567960e6baSSepherosa Ziehau ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO); 11577960e6baSSepherosa Ziehau 115815516c77SSepherosa Ziehau if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) { 115915516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU); 116015516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; 116115516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 116215516c77SSepherosa Ziehau } 116315516c77SSepherosa Ziehau 116415516c77SSepherosa Ziehau ether_ifattach(ifp, eaddr); 116515516c77SSepherosa Ziehau 116615516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) { 116715516c77SSepherosa Ziehau if_printf(ifp, "TSO segcnt %u segsz %u\n", 116815516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize); 116915516c77SSepherosa Ziehau } 117015516c77SSepherosa Ziehau 117115516c77SSepherosa Ziehau /* Inform the upper layer about the long frame support. */ 117215516c77SSepherosa Ziehau ifp->if_hdrlen = sizeof(struct ether_vlan_header); 117315516c77SSepherosa Ziehau 117415516c77SSepherosa Ziehau /* 117515516c77SSepherosa Ziehau * Kick off link status check. 117615516c77SSepherosa Ziehau */ 117715516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 117815516c77SSepherosa Ziehau hn_update_link_status(sc); 117915516c77SSepherosa Ziehau 118015516c77SSepherosa Ziehau return (0); 118115516c77SSepherosa Ziehau failed: 118215516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) 118315516c77SSepherosa Ziehau hn_synth_detach(sc); 118415516c77SSepherosa Ziehau hn_detach(dev); 118515516c77SSepherosa Ziehau return (error); 118615516c77SSepherosa Ziehau } 118715516c77SSepherosa Ziehau 118815516c77SSepherosa Ziehau static int 118915516c77SSepherosa Ziehau hn_detach(device_t dev) 119015516c77SSepherosa Ziehau { 119115516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 119215516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 119315516c77SSepherosa Ziehau 119425641fc7SSepherosa Ziehau if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) { 119525641fc7SSepherosa Ziehau /* 119625641fc7SSepherosa Ziehau * In case that the vmbus missed the orphan handler 119725641fc7SSepherosa Ziehau * installation. 119825641fc7SSepherosa Ziehau */ 119925641fc7SSepherosa Ziehau vmbus_xact_ctx_orphan(sc->hn_xact); 120025641fc7SSepherosa Ziehau } 120125641fc7SSepherosa Ziehau 120215516c77SSepherosa Ziehau if (device_is_attached(dev)) { 120315516c77SSepherosa Ziehau HN_LOCK(sc); 120415516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 120515516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 120615516c77SSepherosa Ziehau hn_stop(sc); 120715516c77SSepherosa Ziehau /* 120815516c77SSepherosa Ziehau * NOTE: 120915516c77SSepherosa Ziehau * hn_stop() only suspends data, so managment 121015516c77SSepherosa Ziehau * stuffs have to be suspended manually here. 121115516c77SSepherosa Ziehau */ 121215516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 121315516c77SSepherosa Ziehau hn_synth_detach(sc); 121415516c77SSepherosa Ziehau } 121515516c77SSepherosa Ziehau HN_UNLOCK(sc); 121615516c77SSepherosa Ziehau ether_ifdetach(ifp); 121715516c77SSepherosa Ziehau } 121815516c77SSepherosa Ziehau 121915516c77SSepherosa Ziehau ifmedia_removeall(&sc->hn_media); 122015516c77SSepherosa Ziehau hn_destroy_rx_data(sc); 122115516c77SSepherosa Ziehau hn_destroy_tx_data(sc); 122215516c77SSepherosa Ziehau 122315516c77SSepherosa Ziehau if (sc->hn_tx_taskq != hn_tx_taskq) 122415516c77SSepherosa Ziehau taskqueue_free(sc->hn_tx_taskq); 122515516c77SSepherosa Ziehau taskqueue_free(sc->hn_mgmt_taskq0); 122615516c77SSepherosa Ziehau 122725641fc7SSepherosa Ziehau if (sc->hn_xact != NULL) { 122825641fc7SSepherosa Ziehau /* 122925641fc7SSepherosa Ziehau * Uninstall the orphan handler _before_ the xact is 123025641fc7SSepherosa Ziehau * destructed. 123125641fc7SSepherosa Ziehau */ 123225641fc7SSepherosa Ziehau vmbus_chan_unset_orphan(sc->hn_prichan); 123315516c77SSepherosa Ziehau vmbus_xact_ctx_destroy(sc->hn_xact); 123425641fc7SSepherosa Ziehau } 123515516c77SSepherosa Ziehau 123615516c77SSepherosa Ziehau if_free(ifp); 123715516c77SSepherosa Ziehau 123815516c77SSepherosa Ziehau HN_LOCK_DESTROY(sc); 123915516c77SSepherosa Ziehau return (0); 124015516c77SSepherosa Ziehau } 124115516c77SSepherosa Ziehau 124215516c77SSepherosa Ziehau static int 124315516c77SSepherosa Ziehau hn_shutdown(device_t dev) 124415516c77SSepherosa Ziehau { 124515516c77SSepherosa Ziehau 124615516c77SSepherosa Ziehau return (0); 124715516c77SSepherosa Ziehau } 124815516c77SSepherosa Ziehau 124915516c77SSepherosa Ziehau static void 125015516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc) 125115516c77SSepherosa Ziehau { 125215516c77SSepherosa Ziehau uint32_t link_status; 125315516c77SSepherosa Ziehau int error; 125415516c77SSepherosa Ziehau 125515516c77SSepherosa Ziehau error = hn_rndis_get_linkstatus(sc, &link_status); 125615516c77SSepherosa Ziehau if (error) { 125715516c77SSepherosa Ziehau /* XXX what to do? */ 125815516c77SSepherosa Ziehau return; 125915516c77SSepherosa Ziehau } 126015516c77SSepherosa Ziehau 126115516c77SSepherosa Ziehau if (link_status == NDIS_MEDIA_STATE_CONNECTED) 126215516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_LINKUP; 126315516c77SSepherosa Ziehau else 126415516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 126515516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, 126615516c77SSepherosa Ziehau (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ? 126715516c77SSepherosa Ziehau LINK_STATE_UP : LINK_STATE_DOWN); 126815516c77SSepherosa Ziehau } 126915516c77SSepherosa Ziehau 127015516c77SSepherosa Ziehau static void 127115516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused) 127215516c77SSepherosa Ziehau { 127315516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 127415516c77SSepherosa Ziehau 127515516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 127615516c77SSepherosa Ziehau return; 127715516c77SSepherosa Ziehau hn_link_status(sc); 127815516c77SSepherosa Ziehau } 127915516c77SSepherosa Ziehau 128015516c77SSepherosa Ziehau static void 128115516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused) 128215516c77SSepherosa Ziehau { 128315516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 128415516c77SSepherosa Ziehau 128515516c77SSepherosa Ziehau /* Prevent any link status checks from running. */ 128615516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_NETCHG; 128715516c77SSepherosa Ziehau 128815516c77SSepherosa Ziehau /* 128915516c77SSepherosa Ziehau * Fake up a [link down --> link up] state change; 5 seconds 129015516c77SSepherosa Ziehau * delay is used, which closely simulates miibus reaction 129115516c77SSepherosa Ziehau * upon link down event. 129215516c77SSepherosa Ziehau */ 129315516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 129415516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); 129515516c77SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0, 129615516c77SSepherosa Ziehau &sc->hn_netchg_status, 5 * hz); 129715516c77SSepherosa Ziehau } 129815516c77SSepherosa Ziehau 129915516c77SSepherosa Ziehau static void 130015516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused) 130115516c77SSepherosa Ziehau { 130215516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 130315516c77SSepherosa Ziehau 130415516c77SSepherosa Ziehau /* Re-allow link status checks. */ 130515516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG; 130615516c77SSepherosa Ziehau hn_link_status(sc); 130715516c77SSepherosa Ziehau } 130815516c77SSepherosa Ziehau 130915516c77SSepherosa Ziehau static void 131015516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc) 131115516c77SSepherosa Ziehau { 131215516c77SSepherosa Ziehau 131315516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 131415516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task); 131515516c77SSepherosa Ziehau } 131615516c77SSepherosa Ziehau 131715516c77SSepherosa Ziehau static void 131815516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc) 131915516c77SSepherosa Ziehau { 132015516c77SSepherosa Ziehau 132115516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 132215516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init); 132315516c77SSepherosa Ziehau } 132415516c77SSepherosa Ziehau 132515516c77SSepherosa Ziehau static __inline int 132615516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd, 132715516c77SSepherosa Ziehau struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) 132815516c77SSepherosa Ziehau { 132915516c77SSepherosa Ziehau struct mbuf *m = *m_head; 133015516c77SSepherosa Ziehau int error; 133115516c77SSepherosa Ziehau 133215516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim")); 133315516c77SSepherosa Ziehau 133415516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap, 133515516c77SSepherosa Ziehau m, segs, nsegs, BUS_DMA_NOWAIT); 133615516c77SSepherosa Ziehau if (error == EFBIG) { 133715516c77SSepherosa Ziehau struct mbuf *m_new; 133815516c77SSepherosa Ziehau 133915516c77SSepherosa Ziehau m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX); 134015516c77SSepherosa Ziehau if (m_new == NULL) 134115516c77SSepherosa Ziehau return ENOBUFS; 134215516c77SSepherosa Ziehau else 134315516c77SSepherosa Ziehau *m_head = m = m_new; 134415516c77SSepherosa Ziehau txr->hn_tx_collapsed++; 134515516c77SSepherosa Ziehau 134615516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, 134715516c77SSepherosa Ziehau txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT); 134815516c77SSepherosa Ziehau } 134915516c77SSepherosa Ziehau if (!error) { 135015516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap, 135115516c77SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 135215516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_DMAMAP; 135315516c77SSepherosa Ziehau } 135415516c77SSepherosa Ziehau return error; 135515516c77SSepherosa Ziehau } 135615516c77SSepherosa Ziehau 135715516c77SSepherosa Ziehau static __inline int 135815516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd) 135915516c77SSepherosa Ziehau { 136015516c77SSepherosa Ziehau 136115516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0, 136215516c77SSepherosa Ziehau ("put an onlist txd %#x", txd->flags)); 1363dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 1364dc13fee6SSepherosa Ziehau ("put an onagg txd %#x", txd->flags)); 136515516c77SSepherosa Ziehau 136615516c77SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 136715516c77SSepherosa Ziehau if (atomic_fetchadd_int(&txd->refs, -1) != 1) 136815516c77SSepherosa Ziehau return 0; 136915516c77SSepherosa Ziehau 1370dc13fee6SSepherosa Ziehau if (!STAILQ_EMPTY(&txd->agg_list)) { 1371dc13fee6SSepherosa Ziehau struct hn_txdesc *tmp_txd; 1372dc13fee6SSepherosa Ziehau 1373dc13fee6SSepherosa Ziehau while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) { 1374dc13fee6SSepherosa Ziehau int freed; 1375dc13fee6SSepherosa Ziehau 1376dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list), 1377dc13fee6SSepherosa Ziehau ("resursive aggregation on aggregated txdesc")); 1378dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG), 1379dc13fee6SSepherosa Ziehau ("not aggregated txdesc")); 1380dc13fee6SSepherosa Ziehau KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 1381dc13fee6SSepherosa Ziehau ("aggregated txdesc uses dmamap")); 1382dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 1383dc13fee6SSepherosa Ziehau ("aggregated txdesc consumes " 1384dc13fee6SSepherosa Ziehau "chimney sending buffer")); 1385dc13fee6SSepherosa Ziehau KASSERT(tmp_txd->chim_size == 0, 1386dc13fee6SSepherosa Ziehau ("aggregated txdesc has non-zero " 1387dc13fee6SSepherosa Ziehau "chimney sending size")); 1388dc13fee6SSepherosa Ziehau 1389dc13fee6SSepherosa Ziehau STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link); 1390dc13fee6SSepherosa Ziehau tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG; 1391dc13fee6SSepherosa Ziehau freed = hn_txdesc_put(txr, tmp_txd); 1392dc13fee6SSepherosa Ziehau KASSERT(freed, ("failed to free aggregated txdesc")); 1393dc13fee6SSepherosa Ziehau } 1394dc13fee6SSepherosa Ziehau } 1395dc13fee6SSepherosa Ziehau 139615516c77SSepherosa Ziehau if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) { 139715516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 139815516c77SSepherosa Ziehau ("chim txd uses dmamap")); 139915516c77SSepherosa Ziehau hn_chim_free(txr->hn_sc, txd->chim_index); 140015516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 1401dc13fee6SSepherosa Ziehau txd->chim_size = 0; 140215516c77SSepherosa Ziehau } else if (txd->flags & HN_TXD_FLAG_DMAMAP) { 140315516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, 140415516c77SSepherosa Ziehau txd->data_dmap, BUS_DMASYNC_POSTWRITE); 140515516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_data_dtag, 140615516c77SSepherosa Ziehau txd->data_dmap); 140715516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_DMAMAP; 140815516c77SSepherosa Ziehau } 140915516c77SSepherosa Ziehau 141015516c77SSepherosa Ziehau if (txd->m != NULL) { 141115516c77SSepherosa Ziehau m_freem(txd->m); 141215516c77SSepherosa Ziehau txd->m = NULL; 141315516c77SSepherosa Ziehau } 141415516c77SSepherosa Ziehau 141515516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 141615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 141715516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 141815516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail >= 0 && 141915516c77SSepherosa Ziehau txr->hn_txdesc_avail < txr->hn_txdesc_cnt, 142015516c77SSepherosa Ziehau ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail)); 142115516c77SSepherosa Ziehau txr->hn_txdesc_avail++; 142215516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 142315516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 142415516c77SSepherosa Ziehau #else 142515516c77SSepherosa Ziehau atomic_add_int(&txr->hn_txdesc_avail, 1); 142615516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 142715516c77SSepherosa Ziehau #endif 142815516c77SSepherosa Ziehau 142915516c77SSepherosa Ziehau return 1; 143015516c77SSepherosa Ziehau } 143115516c77SSepherosa Ziehau 143215516c77SSepherosa Ziehau static __inline struct hn_txdesc * 143315516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr) 143415516c77SSepherosa Ziehau { 143515516c77SSepherosa Ziehau struct hn_txdesc *txd; 143615516c77SSepherosa Ziehau 143715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 143815516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 143915516c77SSepherosa Ziehau txd = SLIST_FIRST(&txr->hn_txlist); 144015516c77SSepherosa Ziehau if (txd != NULL) { 144115516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail > 0, 144215516c77SSepherosa Ziehau ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail)); 144315516c77SSepherosa Ziehau txr->hn_txdesc_avail--; 144415516c77SSepherosa Ziehau SLIST_REMOVE_HEAD(&txr->hn_txlist, link); 144515516c77SSepherosa Ziehau } 144615516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 144715516c77SSepherosa Ziehau #else 144815516c77SSepherosa Ziehau txd = buf_ring_dequeue_sc(txr->hn_txdesc_br); 144915516c77SSepherosa Ziehau #endif 145015516c77SSepherosa Ziehau 145115516c77SSepherosa Ziehau if (txd != NULL) { 145215516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 145315516c77SSepherosa Ziehau atomic_subtract_int(&txr->hn_txdesc_avail, 1); 145415516c77SSepherosa Ziehau #endif 145515516c77SSepherosa Ziehau KASSERT(txd->m == NULL && txd->refs == 0 && 1456dc13fee6SSepherosa Ziehau STAILQ_EMPTY(&txd->agg_list) && 145715516c77SSepherosa Ziehau txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 1458dc13fee6SSepherosa Ziehau txd->chim_size == 0 && 145915516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONLIST) && 1460dc13fee6SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONAGG) == 0 && 146115516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd")); 146215516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_ONLIST; 146315516c77SSepherosa Ziehau txd->refs = 1; 146415516c77SSepherosa Ziehau } 146515516c77SSepherosa Ziehau return txd; 146615516c77SSepherosa Ziehau } 146715516c77SSepherosa Ziehau 146815516c77SSepherosa Ziehau static __inline void 146915516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd) 147015516c77SSepherosa Ziehau { 147115516c77SSepherosa Ziehau 147215516c77SSepherosa Ziehau /* 0->1 transition will never work */ 147325641fc7SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 147415516c77SSepherosa Ziehau atomic_add_int(&txd->refs, 1); 147515516c77SSepherosa Ziehau } 147615516c77SSepherosa Ziehau 1477dc13fee6SSepherosa Ziehau static __inline void 1478dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd) 1479dc13fee6SSepherosa Ziehau { 1480dc13fee6SSepherosa Ziehau 1481dc13fee6SSepherosa Ziehau KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0, 1482dc13fee6SSepherosa Ziehau ("recursive aggregation on aggregating txdesc")); 1483dc13fee6SSepherosa Ziehau 1484dc13fee6SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0, 1485dc13fee6SSepherosa Ziehau ("already aggregated")); 1486dc13fee6SSepherosa Ziehau KASSERT(STAILQ_EMPTY(&txd->agg_list), 1487dc13fee6SSepherosa Ziehau ("recursive aggregation on to-be-aggregated txdesc")); 1488dc13fee6SSepherosa Ziehau 1489dc13fee6SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONAGG; 1490dc13fee6SSepherosa Ziehau STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link); 1491dc13fee6SSepherosa Ziehau } 1492dc13fee6SSepherosa Ziehau 149315516c77SSepherosa Ziehau static bool 149415516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr) 149515516c77SSepherosa Ziehau { 149615516c77SSepherosa Ziehau bool pending = false; 149715516c77SSepherosa Ziehau 149815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 149915516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 150015516c77SSepherosa Ziehau if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt) 150115516c77SSepherosa Ziehau pending = true; 150215516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 150315516c77SSepherosa Ziehau #else 150415516c77SSepherosa Ziehau if (!buf_ring_full(txr->hn_txdesc_br)) 150515516c77SSepherosa Ziehau pending = true; 150615516c77SSepherosa Ziehau #endif 150715516c77SSepherosa Ziehau return (pending); 150815516c77SSepherosa Ziehau } 150915516c77SSepherosa Ziehau 151015516c77SSepherosa Ziehau static __inline void 151115516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr) 151215516c77SSepherosa Ziehau { 151315516c77SSepherosa Ziehau txr->hn_has_txeof = 0; 151415516c77SSepherosa Ziehau txr->hn_txeof(txr); 151515516c77SSepherosa Ziehau } 151615516c77SSepherosa Ziehau 151715516c77SSepherosa Ziehau static void 151815516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc, 151915516c77SSepherosa Ziehau struct vmbus_channel *chan, const void *data __unused, int dlen __unused) 152015516c77SSepherosa Ziehau { 152115516c77SSepherosa Ziehau struct hn_txdesc *txd = sndc->hn_cbarg; 152215516c77SSepherosa Ziehau struct hn_tx_ring *txr; 152315516c77SSepherosa Ziehau 152415516c77SSepherosa Ziehau txr = txd->txr; 152515516c77SSepherosa Ziehau KASSERT(txr->hn_chan == chan, 152615516c77SSepherosa Ziehau ("channel mismatch, on chan%u, should be chan%u", 152715516c77SSepherosa Ziehau vmbus_chan_subidx(chan), vmbus_chan_subidx(txr->hn_chan))); 152815516c77SSepherosa Ziehau 152915516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 153015516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 153115516c77SSepherosa Ziehau 153215516c77SSepherosa Ziehau ++txr->hn_txdone_cnt; 153315516c77SSepherosa Ziehau if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) { 153415516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 153515516c77SSepherosa Ziehau if (txr->hn_oactive) 153615516c77SSepherosa Ziehau hn_txeof(txr); 153715516c77SSepherosa Ziehau } 153815516c77SSepherosa Ziehau } 153915516c77SSepherosa Ziehau 154015516c77SSepherosa Ziehau static void 154115516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr) 154215516c77SSepherosa Ziehau { 154315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 154415516c77SSepherosa Ziehau tcp_lro_flush_all(&rxr->hn_lro); 154515516c77SSepherosa Ziehau #endif 154615516c77SSepherosa Ziehau 154715516c77SSepherosa Ziehau /* 154815516c77SSepherosa Ziehau * NOTE: 154915516c77SSepherosa Ziehau * 'txr' could be NULL, if multiple channels and 155015516c77SSepherosa Ziehau * ifnet.if_start method are enabled. 155115516c77SSepherosa Ziehau */ 155215516c77SSepherosa Ziehau if (txr == NULL || !txr->hn_has_txeof) 155315516c77SSepherosa Ziehau return; 155415516c77SSepherosa Ziehau 155515516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 155615516c77SSepherosa Ziehau hn_txeof(txr); 155715516c77SSepherosa Ziehau } 155815516c77SSepherosa Ziehau 155915516c77SSepherosa Ziehau static __inline uint32_t 156015516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs) 156115516c77SSepherosa Ziehau { 156215516c77SSepherosa Ziehau 156315516c77SSepherosa Ziehau KASSERT(ofs >= sizeof(struct rndis_packet_msg), 156415516c77SSepherosa Ziehau ("invalid RNDIS packet msg offset %u", ofs)); 156515516c77SSepherosa Ziehau return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset)); 156615516c77SSepherosa Ziehau } 156715516c77SSepherosa Ziehau 156815516c77SSepherosa Ziehau static __inline void * 156915516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize, 157015516c77SSepherosa Ziehau size_t pi_dlen, uint32_t pi_type) 157115516c77SSepherosa Ziehau { 157215516c77SSepherosa Ziehau const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen); 157315516c77SSepherosa Ziehau struct rndis_pktinfo *pi; 157415516c77SSepherosa Ziehau 157515516c77SSepherosa Ziehau KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0, 157615516c77SSepherosa Ziehau ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen)); 157715516c77SSepherosa Ziehau 157815516c77SSepherosa Ziehau /* 157915516c77SSepherosa Ziehau * Per-packet-info does not move; it only grows. 158015516c77SSepherosa Ziehau * 158115516c77SSepherosa Ziehau * NOTE: 158215516c77SSepherosa Ziehau * rm_pktinfooffset in this phase counts from the beginning 158315516c77SSepherosa Ziehau * of rndis_packet_msg. 158415516c77SSepherosa Ziehau */ 158515516c77SSepherosa Ziehau KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize, 158615516c77SSepherosa Ziehau ("%u pktinfo overflows RNDIS packet msg", pi_type)); 158715516c77SSepherosa Ziehau pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset + 158815516c77SSepherosa Ziehau pkt->rm_pktinfolen); 158915516c77SSepherosa Ziehau pkt->rm_pktinfolen += pi_size; 159015516c77SSepherosa Ziehau 159115516c77SSepherosa Ziehau pi->rm_size = pi_size; 159215516c77SSepherosa Ziehau pi->rm_type = pi_type; 159315516c77SSepherosa Ziehau pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET; 159415516c77SSepherosa Ziehau 159515516c77SSepherosa Ziehau /* Data immediately follow per-packet-info. */ 159615516c77SSepherosa Ziehau pkt->rm_dataoffset += pi_size; 159715516c77SSepherosa Ziehau 159815516c77SSepherosa Ziehau /* Update RNDIS packet msg length */ 159915516c77SSepherosa Ziehau pkt->rm_len += pi_size; 160015516c77SSepherosa Ziehau 160115516c77SSepherosa Ziehau return (pi->rm_data); 160215516c77SSepherosa Ziehau } 160315516c77SSepherosa Ziehau 1604dc13fee6SSepherosa Ziehau static __inline int 1605dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr) 1606dc13fee6SSepherosa Ziehau { 1607dc13fee6SSepherosa Ziehau struct hn_txdesc *txd; 1608dc13fee6SSepherosa Ziehau struct mbuf *m; 1609dc13fee6SSepherosa Ziehau int error, pkts; 1610dc13fee6SSepherosa Ziehau 1611dc13fee6SSepherosa Ziehau txd = txr->hn_agg_txd; 1612dc13fee6SSepherosa Ziehau KASSERT(txd != NULL, ("no aggregate txdesc")); 1613dc13fee6SSepherosa Ziehau 1614dc13fee6SSepherosa Ziehau /* 1615dc13fee6SSepherosa Ziehau * Since hn_txpkt() will reset this temporary stat, save 1616dc13fee6SSepherosa Ziehau * it now, so that oerrors can be updated properly, if 1617dc13fee6SSepherosa Ziehau * hn_txpkt() ever fails. 1618dc13fee6SSepherosa Ziehau */ 1619dc13fee6SSepherosa Ziehau pkts = txr->hn_stat_pkts; 1620dc13fee6SSepherosa Ziehau 1621dc13fee6SSepherosa Ziehau /* 1622dc13fee6SSepherosa Ziehau * Since txd's mbuf will _not_ be freed upon hn_txpkt() 1623dc13fee6SSepherosa Ziehau * failure, save it for later freeing, if hn_txpkt() ever 1624dc13fee6SSepherosa Ziehau * fails. 1625dc13fee6SSepherosa Ziehau */ 1626dc13fee6SSepherosa Ziehau m = txd->m; 1627dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 1628dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 1629dc13fee6SSepherosa Ziehau /* txd is freed, but m is not. */ 1630dc13fee6SSepherosa Ziehau m_freem(m); 1631dc13fee6SSepherosa Ziehau 1632dc13fee6SSepherosa Ziehau txr->hn_flush_failed++; 1633dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts); 1634dc13fee6SSepherosa Ziehau } 1635dc13fee6SSepherosa Ziehau 1636dc13fee6SSepherosa Ziehau /* Reset all aggregation states. */ 1637dc13fee6SSepherosa Ziehau txr->hn_agg_txd = NULL; 1638dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = 0; 1639dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 1640dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = NULL; 1641dc13fee6SSepherosa Ziehau 1642dc13fee6SSepherosa Ziehau return (error); 1643dc13fee6SSepherosa Ziehau } 1644dc13fee6SSepherosa Ziehau 1645dc13fee6SSepherosa Ziehau static void * 1646dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 1647dc13fee6SSepherosa Ziehau int pktsize) 1648dc13fee6SSepherosa Ziehau { 1649dc13fee6SSepherosa Ziehau void *chim; 1650dc13fee6SSepherosa Ziehau 1651dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 1652dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) { 1653dc13fee6SSepherosa Ziehau struct hn_txdesc *agg_txd = txr->hn_agg_txd; 1654dc13fee6SSepherosa Ziehau struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt; 1655dc13fee6SSepherosa Ziehau int olen; 1656dc13fee6SSepherosa Ziehau 1657dc13fee6SSepherosa Ziehau /* 1658dc13fee6SSepherosa Ziehau * Update the previous RNDIS packet's total length, 1659dc13fee6SSepherosa Ziehau * it can be increased due to the mandatory alignment 1660dc13fee6SSepherosa Ziehau * padding for this RNDIS packet. And update the 1661dc13fee6SSepherosa Ziehau * aggregating txdesc's chimney sending buffer size 1662dc13fee6SSepherosa Ziehau * accordingly. 1663dc13fee6SSepherosa Ziehau * 1664dc13fee6SSepherosa Ziehau * XXX 1665dc13fee6SSepherosa Ziehau * Zero-out the padding, as required by the RNDIS spec. 1666dc13fee6SSepherosa Ziehau */ 1667dc13fee6SSepherosa Ziehau olen = pkt->rm_len; 1668dc13fee6SSepherosa Ziehau pkt->rm_len = roundup2(olen, txr->hn_agg_align); 1669dc13fee6SSepherosa Ziehau agg_txd->chim_size += pkt->rm_len - olen; 1670dc13fee6SSepherosa Ziehau 1671dc13fee6SSepherosa Ziehau /* Link this txdesc to the parent. */ 1672dc13fee6SSepherosa Ziehau hn_txdesc_agg(agg_txd, txd); 1673dc13fee6SSepherosa Ziehau 1674dc13fee6SSepherosa Ziehau chim = (uint8_t *)pkt + pkt->rm_len; 1675dc13fee6SSepherosa Ziehau /* Save the current packet for later fixup. */ 1676dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 1677dc13fee6SSepherosa Ziehau 1678dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft--; 1679dc13fee6SSepherosa Ziehau txr->hn_agg_szleft -= pktsize; 1680dc13fee6SSepherosa Ziehau if (txr->hn_agg_szleft <= 1681dc13fee6SSepherosa Ziehau HN_PKTSIZE_MIN(txr->hn_agg_align)) { 1682dc13fee6SSepherosa Ziehau /* 1683dc13fee6SSepherosa Ziehau * Probably can't aggregate more packets, 1684dc13fee6SSepherosa Ziehau * flush this aggregating txdesc proactively. 1685dc13fee6SSepherosa Ziehau */ 1686dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = 0; 1687dc13fee6SSepherosa Ziehau } 1688dc13fee6SSepherosa Ziehau /* Done! */ 1689dc13fee6SSepherosa Ziehau return (chim); 1690dc13fee6SSepherosa Ziehau } 1691dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 1692dc13fee6SSepherosa Ziehau } 1693dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 1694dc13fee6SSepherosa Ziehau 1695dc13fee6SSepherosa Ziehau txr->hn_tx_chimney_tried++; 1696dc13fee6SSepherosa Ziehau txd->chim_index = hn_chim_alloc(txr->hn_sc); 1697dc13fee6SSepherosa Ziehau if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID) 1698dc13fee6SSepherosa Ziehau return (NULL); 1699dc13fee6SSepherosa Ziehau txr->hn_tx_chimney++; 1700dc13fee6SSepherosa Ziehau 1701dc13fee6SSepherosa Ziehau chim = txr->hn_sc->hn_chim + 1702dc13fee6SSepherosa Ziehau (txd->chim_index * txr->hn_sc->hn_chim_szmax); 1703dc13fee6SSepherosa Ziehau 1704dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktmax > 1 && 1705dc13fee6SSepherosa Ziehau txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) { 1706dc13fee6SSepherosa Ziehau txr->hn_agg_txd = txd; 1707dc13fee6SSepherosa Ziehau txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1; 1708dc13fee6SSepherosa Ziehau txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize; 1709dc13fee6SSepherosa Ziehau txr->hn_agg_prevpkt = chim; 1710dc13fee6SSepherosa Ziehau } 1711dc13fee6SSepherosa Ziehau return (chim); 1712dc13fee6SSepherosa Ziehau } 1713dc13fee6SSepherosa Ziehau 171415516c77SSepherosa Ziehau /* 171515516c77SSepherosa Ziehau * NOTE: 171615516c77SSepherosa Ziehau * If this function fails, then both txd and m_head0 will be freed. 171715516c77SSepherosa Ziehau */ 171815516c77SSepherosa Ziehau static int 1719dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, 1720dc13fee6SSepherosa Ziehau struct mbuf **m_head0) 172115516c77SSepherosa Ziehau { 172215516c77SSepherosa Ziehau bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX]; 172315516c77SSepherosa Ziehau int error, nsegs, i; 172415516c77SSepherosa Ziehau struct mbuf *m_head = *m_head0; 172515516c77SSepherosa Ziehau struct rndis_packet_msg *pkt; 172615516c77SSepherosa Ziehau uint32_t *pi_data; 17278966e5d5SSepherosa Ziehau void *chim = NULL; 1728dc13fee6SSepherosa Ziehau int pkt_hlen, pkt_size; 172915516c77SSepherosa Ziehau 173015516c77SSepherosa Ziehau pkt = txd->rndis_pkt; 1731dc13fee6SSepherosa Ziehau pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align); 1732dc13fee6SSepherosa Ziehau if (pkt_size < txr->hn_chim_size) { 1733dc13fee6SSepherosa Ziehau chim = hn_try_txagg(ifp, txr, txd, pkt_size); 1734dc13fee6SSepherosa Ziehau if (chim != NULL) 17358966e5d5SSepherosa Ziehau pkt = chim; 1736dc13fee6SSepherosa Ziehau } else { 1737dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 1738dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 17398966e5d5SSepherosa Ziehau } 17408966e5d5SSepherosa Ziehau 174115516c77SSepherosa Ziehau pkt->rm_type = REMOTE_NDIS_PACKET_MSG; 174215516c77SSepherosa Ziehau pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len; 174315516c77SSepherosa Ziehau pkt->rm_dataoffset = sizeof(*pkt); 174415516c77SSepherosa Ziehau pkt->rm_datalen = m_head->m_pkthdr.len; 1745dc13fee6SSepherosa Ziehau pkt->rm_oobdataoffset = 0; 1746dc13fee6SSepherosa Ziehau pkt->rm_oobdatalen = 0; 1747dc13fee6SSepherosa Ziehau pkt->rm_oobdataelements = 0; 174815516c77SSepherosa Ziehau pkt->rm_pktinfooffset = sizeof(*pkt); 174915516c77SSepherosa Ziehau pkt->rm_pktinfolen = 0; 1750dc13fee6SSepherosa Ziehau pkt->rm_vchandle = 0; 1751dc13fee6SSepherosa Ziehau pkt->rm_reserved = 0; 175215516c77SSepherosa Ziehau 175315516c77SSepherosa Ziehau if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) { 175415516c77SSepherosa Ziehau /* 175515516c77SSepherosa Ziehau * Set the hash value for this packet, so that the host could 175615516c77SSepherosa Ziehau * dispatch the TX done event for this packet back to this TX 175715516c77SSepherosa Ziehau * ring's channel. 175815516c77SSepherosa Ziehau */ 175915516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 176015516c77SSepherosa Ziehau HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL); 176115516c77SSepherosa Ziehau *pi_data = txr->hn_tx_idx; 176215516c77SSepherosa Ziehau } 176315516c77SSepherosa Ziehau 176415516c77SSepherosa Ziehau if (m_head->m_flags & M_VLANTAG) { 176515516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 176615516c77SSepherosa Ziehau NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN); 176715516c77SSepherosa Ziehau *pi_data = NDIS_VLAN_INFO_MAKE( 176815516c77SSepherosa Ziehau EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag), 176915516c77SSepherosa Ziehau EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag), 177015516c77SSepherosa Ziehau EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag)); 177115516c77SSepherosa Ziehau } 177215516c77SSepherosa Ziehau 177315516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 177415516c77SSepherosa Ziehau #if defined(INET6) || defined(INET) 177515516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 177615516c77SSepherosa Ziehau NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); 177715516c77SSepherosa Ziehau #ifdef INET 177815516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 177915516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV4(0, 178015516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 178115516c77SSepherosa Ziehau } 178215516c77SSepherosa Ziehau #endif 178315516c77SSepherosa Ziehau #if defined(INET6) && defined(INET) 178415516c77SSepherosa Ziehau else 178515516c77SSepherosa Ziehau #endif 178615516c77SSepherosa Ziehau #ifdef INET6 178715516c77SSepherosa Ziehau { 178815516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV6(0, 178915516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 179015516c77SSepherosa Ziehau } 179115516c77SSepherosa Ziehau #endif 179215516c77SSepherosa Ziehau #endif /* INET6 || INET */ 179315516c77SSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) { 179415516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 179515516c77SSepherosa Ziehau NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); 179615516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & 179715516c77SSepherosa Ziehau (CSUM_IP6_TCP | CSUM_IP6_UDP)) { 179815516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV6; 179915516c77SSepherosa Ziehau } else { 180015516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV4; 180115516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 180215516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_IPCS; 180315516c77SSepherosa Ziehau } 180415516c77SSepherosa Ziehau 180515516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) 180615516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_TCPCS; 180715516c77SSepherosa Ziehau else if (m_head->m_pkthdr.csum_flags & 180815516c77SSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP6_UDP)) 180915516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_UDPCS; 181015516c77SSepherosa Ziehau } 181115516c77SSepherosa Ziehau 1812dc13fee6SSepherosa Ziehau pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; 181315516c77SSepherosa Ziehau /* Convert RNDIS packet message offsets */ 181415516c77SSepherosa Ziehau pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt->rm_dataoffset); 181515516c77SSepherosa Ziehau pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset); 181615516c77SSepherosa Ziehau 181715516c77SSepherosa Ziehau /* 18188966e5d5SSepherosa Ziehau * Fast path: Chimney sending. 181915516c77SSepherosa Ziehau */ 18208966e5d5SSepherosa Ziehau if (chim != NULL) { 1821dc13fee6SSepherosa Ziehau struct hn_txdesc *tgt_txd = txd; 1822dc13fee6SSepherosa Ziehau 1823dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 1824dc13fee6SSepherosa Ziehau tgt_txd = txr->hn_agg_txd; 1825dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 1826dc13fee6SSepherosa Ziehau *m_head0 = NULL; 1827dc13fee6SSepherosa Ziehau #endif 1828dc13fee6SSepherosa Ziehau } 1829dc13fee6SSepherosa Ziehau 1830dc13fee6SSepherosa Ziehau KASSERT(pkt == chim, 1831dc13fee6SSepherosa Ziehau ("RNDIS pkt not in chimney sending buffer")); 1832dc13fee6SSepherosa Ziehau KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID, 1833dc13fee6SSepherosa Ziehau ("chimney sending buffer is not used")); 1834dc13fee6SSepherosa Ziehau tgt_txd->chim_size += pkt->rm_len; 183515516c77SSepherosa Ziehau 18368966e5d5SSepherosa Ziehau m_copydata(m_head, 0, m_head->m_pkthdr.len, 1837dc13fee6SSepherosa Ziehau ((uint8_t *)chim) + pkt_hlen); 183815516c77SSepherosa Ziehau 183915516c77SSepherosa Ziehau txr->hn_gpa_cnt = 0; 184015516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_chim; 184115516c77SSepherosa Ziehau goto done; 184215516c77SSepherosa Ziehau } 1843dc13fee6SSepherosa Ziehau 1844dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc")); 18458966e5d5SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 18468966e5d5SSepherosa Ziehau ("chimney buffer is used")); 18478966e5d5SSepherosa Ziehau KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc")); 184815516c77SSepherosa Ziehau 184915516c77SSepherosa Ziehau error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs); 1850dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 185115516c77SSepherosa Ziehau int freed; 185215516c77SSepherosa Ziehau 185315516c77SSepherosa Ziehau /* 185415516c77SSepherosa Ziehau * This mbuf is not linked w/ the txd yet, so free it now. 185515516c77SSepherosa Ziehau */ 185615516c77SSepherosa Ziehau m_freem(m_head); 185715516c77SSepherosa Ziehau *m_head0 = NULL; 185815516c77SSepherosa Ziehau 185915516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 186015516c77SSepherosa Ziehau KASSERT(freed != 0, 186115516c77SSepherosa Ziehau ("fail to free txd upon txdma error")); 186215516c77SSepherosa Ziehau 186315516c77SSepherosa Ziehau txr->hn_txdma_failed++; 1864dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 186515516c77SSepherosa Ziehau return error; 186615516c77SSepherosa Ziehau } 186715516c77SSepherosa Ziehau *m_head0 = m_head; 186815516c77SSepherosa Ziehau 186915516c77SSepherosa Ziehau /* +1 RNDIS packet message */ 187015516c77SSepherosa Ziehau txr->hn_gpa_cnt = nsegs + 1; 187115516c77SSepherosa Ziehau 187215516c77SSepherosa Ziehau /* send packet with page buffer */ 187315516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr); 187415516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK; 1875dc13fee6SSepherosa Ziehau txr->hn_gpa[0].gpa_len = pkt_hlen; 187615516c77SSepherosa Ziehau 187715516c77SSepherosa Ziehau /* 187815516c77SSepherosa Ziehau * Fill the page buffers with mbuf info after the page 187915516c77SSepherosa Ziehau * buffer for RNDIS packet message. 188015516c77SSepherosa Ziehau */ 188115516c77SSepherosa Ziehau for (i = 0; i < nsegs; ++i) { 188215516c77SSepherosa Ziehau struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1]; 188315516c77SSepherosa Ziehau 188415516c77SSepherosa Ziehau gpa->gpa_page = atop(segs[i].ds_addr); 188515516c77SSepherosa Ziehau gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK; 188615516c77SSepherosa Ziehau gpa->gpa_len = segs[i].ds_len; 188715516c77SSepherosa Ziehau } 188815516c77SSepherosa Ziehau 188915516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 189015516c77SSepherosa Ziehau txd->chim_size = 0; 189115516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_sglist; 189215516c77SSepherosa Ziehau done: 189315516c77SSepherosa Ziehau txd->m = m_head; 189415516c77SSepherosa Ziehau 189515516c77SSepherosa Ziehau /* Set the completion routine */ 189615516c77SSepherosa Ziehau hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd); 189715516c77SSepherosa Ziehau 1898dc13fee6SSepherosa Ziehau /* Update temporary stats for later use. */ 1899dc13fee6SSepherosa Ziehau txr->hn_stat_pkts++; 1900dc13fee6SSepherosa Ziehau txr->hn_stat_size += m_head->m_pkthdr.len; 1901dc13fee6SSepherosa Ziehau if (m_head->m_flags & M_MCAST) 1902dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts++; 1903dc13fee6SSepherosa Ziehau 190415516c77SSepherosa Ziehau return 0; 190515516c77SSepherosa Ziehau } 190615516c77SSepherosa Ziehau 190715516c77SSepherosa Ziehau /* 190815516c77SSepherosa Ziehau * NOTE: 190915516c77SSepherosa Ziehau * If this function fails, then txd will be freed, but the mbuf 191015516c77SSepherosa Ziehau * associated w/ the txd will _not_ be freed. 191115516c77SSepherosa Ziehau */ 191215516c77SSepherosa Ziehau static int 191315516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd) 191415516c77SSepherosa Ziehau { 191515516c77SSepherosa Ziehau int error, send_failed = 0; 191615516c77SSepherosa Ziehau 191715516c77SSepherosa Ziehau again: 191815516c77SSepherosa Ziehau /* 1919dc13fee6SSepherosa Ziehau * Make sure that this txd and any aggregated txds are not freed 1920dc13fee6SSepherosa Ziehau * before ETHER_BPF_MTAP. 192115516c77SSepherosa Ziehau */ 192215516c77SSepherosa Ziehau hn_txdesc_hold(txd); 192315516c77SSepherosa Ziehau error = txr->hn_sendpkt(txr, txd); 192415516c77SSepherosa Ziehau if (!error) { 1925dc13fee6SSepherosa Ziehau if (bpf_peers_present(ifp->if_bpf)) { 1926dc13fee6SSepherosa Ziehau const struct hn_txdesc *tmp_txd; 1927dc13fee6SSepherosa Ziehau 192815516c77SSepherosa Ziehau ETHER_BPF_MTAP(ifp, txd->m); 1929dc13fee6SSepherosa Ziehau STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link) 1930dc13fee6SSepherosa Ziehau ETHER_BPF_MTAP(ifp, tmp_txd->m); 1931dc13fee6SSepherosa Ziehau } 1932dc13fee6SSepherosa Ziehau 1933dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts); 193423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 193523bf9e15SSepherosa Ziehau if (!hn_use_if_start) 193623bf9e15SSepherosa Ziehau #endif 193723bf9e15SSepherosa Ziehau { 193815516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, 1939dc13fee6SSepherosa Ziehau txr->hn_stat_size); 1940dc13fee6SSepherosa Ziehau if (txr->hn_stat_mcasts != 0) { 1941dc13fee6SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1942dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts); 194315516c77SSepherosa Ziehau } 1944dc13fee6SSepherosa Ziehau } 1945dc13fee6SSepherosa Ziehau txr->hn_pkts += txr->hn_stat_pkts; 1946dc13fee6SSepherosa Ziehau txr->hn_sends++; 194715516c77SSepherosa Ziehau } 194815516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 194915516c77SSepherosa Ziehau 195015516c77SSepherosa Ziehau if (__predict_false(error)) { 195115516c77SSepherosa Ziehau int freed; 195215516c77SSepherosa Ziehau 195315516c77SSepherosa Ziehau /* 195415516c77SSepherosa Ziehau * This should "really rarely" happen. 195515516c77SSepherosa Ziehau * 195615516c77SSepherosa Ziehau * XXX Too many RX to be acked or too many sideband 195715516c77SSepherosa Ziehau * commands to run? Ask netvsc_channel_rollup() 195815516c77SSepherosa Ziehau * to kick start later. 195915516c77SSepherosa Ziehau */ 196015516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 196115516c77SSepherosa Ziehau if (!send_failed) { 196215516c77SSepherosa Ziehau txr->hn_send_failed++; 196315516c77SSepherosa Ziehau send_failed = 1; 196415516c77SSepherosa Ziehau /* 196515516c77SSepherosa Ziehau * Try sending again after set hn_has_txeof; 196615516c77SSepherosa Ziehau * in case that we missed the last 196715516c77SSepherosa Ziehau * netvsc_channel_rollup(). 196815516c77SSepherosa Ziehau */ 196915516c77SSepherosa Ziehau goto again; 197015516c77SSepherosa Ziehau } 197115516c77SSepherosa Ziehau if_printf(ifp, "send failed\n"); 197215516c77SSepherosa Ziehau 197315516c77SSepherosa Ziehau /* 197415516c77SSepherosa Ziehau * Caller will perform further processing on the 197515516c77SSepherosa Ziehau * associated mbuf, so don't free it in hn_txdesc_put(); 197615516c77SSepherosa Ziehau * only unload it from the DMA map in hn_txdesc_put(), 197715516c77SSepherosa Ziehau * if it was loaded. 197815516c77SSepherosa Ziehau */ 197915516c77SSepherosa Ziehau txd->m = NULL; 198015516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 198115516c77SSepherosa Ziehau KASSERT(freed != 0, 198215516c77SSepherosa Ziehau ("fail to free txd upon send error")); 198315516c77SSepherosa Ziehau 198415516c77SSepherosa Ziehau txr->hn_send_failed++; 198515516c77SSepherosa Ziehau } 1986dc13fee6SSepherosa Ziehau 1987dc13fee6SSepherosa Ziehau /* Reset temporary stats, after this sending is done. */ 1988dc13fee6SSepherosa Ziehau txr->hn_stat_size = 0; 1989dc13fee6SSepherosa Ziehau txr->hn_stat_pkts = 0; 1990dc13fee6SSepherosa Ziehau txr->hn_stat_mcasts = 0; 1991dc13fee6SSepherosa Ziehau 1992dc13fee6SSepherosa Ziehau return (error); 199315516c77SSepherosa Ziehau } 199415516c77SSepherosa Ziehau 199515516c77SSepherosa Ziehau /* 199615516c77SSepherosa Ziehau * Append the specified data to the indicated mbuf chain, 199715516c77SSepherosa Ziehau * Extend the mbuf chain if the new data does not fit in 199815516c77SSepherosa Ziehau * existing space. 199915516c77SSepherosa Ziehau * 200015516c77SSepherosa Ziehau * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c. 200115516c77SSepherosa Ziehau * There should be an equivalent in the kernel mbuf code, 200215516c77SSepherosa Ziehau * but there does not appear to be one yet. 200315516c77SSepherosa Ziehau * 200415516c77SSepherosa Ziehau * Differs from m_append() in that additional mbufs are 200515516c77SSepherosa Ziehau * allocated with cluster size MJUMPAGESIZE, and filled 200615516c77SSepherosa Ziehau * accordingly. 200715516c77SSepherosa Ziehau * 200815516c77SSepherosa Ziehau * Return 1 if able to complete the job; otherwise 0. 200915516c77SSepherosa Ziehau */ 201015516c77SSepherosa Ziehau static int 201115516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp) 201215516c77SSepherosa Ziehau { 201315516c77SSepherosa Ziehau struct mbuf *m, *n; 201415516c77SSepherosa Ziehau int remainder, space; 201515516c77SSepherosa Ziehau 201615516c77SSepherosa Ziehau for (m = m0; m->m_next != NULL; m = m->m_next) 201715516c77SSepherosa Ziehau ; 201815516c77SSepherosa Ziehau remainder = len; 201915516c77SSepherosa Ziehau space = M_TRAILINGSPACE(m); 202015516c77SSepherosa Ziehau if (space > 0) { 202115516c77SSepherosa Ziehau /* 202215516c77SSepherosa Ziehau * Copy into available space. 202315516c77SSepherosa Ziehau */ 202415516c77SSepherosa Ziehau if (space > remainder) 202515516c77SSepherosa Ziehau space = remainder; 202615516c77SSepherosa Ziehau bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 202715516c77SSepherosa Ziehau m->m_len += space; 202815516c77SSepherosa Ziehau cp += space; 202915516c77SSepherosa Ziehau remainder -= space; 203015516c77SSepherosa Ziehau } 203115516c77SSepherosa Ziehau while (remainder > 0) { 203215516c77SSepherosa Ziehau /* 203315516c77SSepherosa Ziehau * Allocate a new mbuf; could check space 203415516c77SSepherosa Ziehau * and allocate a cluster instead. 203515516c77SSepherosa Ziehau */ 203615516c77SSepherosa Ziehau n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE); 203715516c77SSepherosa Ziehau if (n == NULL) 203815516c77SSepherosa Ziehau break; 203915516c77SSepherosa Ziehau n->m_len = min(MJUMPAGESIZE, remainder); 204015516c77SSepherosa Ziehau bcopy(cp, mtod(n, caddr_t), n->m_len); 204115516c77SSepherosa Ziehau cp += n->m_len; 204215516c77SSepherosa Ziehau remainder -= n->m_len; 204315516c77SSepherosa Ziehau m->m_next = n; 204415516c77SSepherosa Ziehau m = n; 204515516c77SSepherosa Ziehau } 204615516c77SSepherosa Ziehau if (m0->m_flags & M_PKTHDR) 204715516c77SSepherosa Ziehau m0->m_pkthdr.len += len - remainder; 204815516c77SSepherosa Ziehau 204915516c77SSepherosa Ziehau return (remainder == 0); 205015516c77SSepherosa Ziehau } 205115516c77SSepherosa Ziehau 205215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 205315516c77SSepherosa Ziehau static __inline int 205415516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m) 205515516c77SSepherosa Ziehau { 205615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 205715516c77SSepherosa Ziehau if (hn_lro_mbufq_depth) { 205815516c77SSepherosa Ziehau tcp_lro_queue_mbuf(lc, m); 205915516c77SSepherosa Ziehau return 0; 206015516c77SSepherosa Ziehau } 206115516c77SSepherosa Ziehau #endif 206215516c77SSepherosa Ziehau return tcp_lro_rx(lc, m, 0); 206315516c77SSepherosa Ziehau } 206415516c77SSepherosa Ziehau #endif 206515516c77SSepherosa Ziehau 206615516c77SSepherosa Ziehau static int 206715516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, 206815516c77SSepherosa Ziehau const struct hn_rxinfo *info) 206915516c77SSepherosa Ziehau { 207015516c77SSepherosa Ziehau struct ifnet *ifp = rxr->hn_ifp; 207115516c77SSepherosa Ziehau struct mbuf *m_new; 207215516c77SSepherosa Ziehau int size, do_lro = 0, do_csum = 1; 207315516c77SSepherosa Ziehau int hash_type; 207415516c77SSepherosa Ziehau 207515516c77SSepherosa Ziehau if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 207615516c77SSepherosa Ziehau return (0); 207715516c77SSepherosa Ziehau 207815516c77SSepherosa Ziehau /* 207915516c77SSepherosa Ziehau * Bail out if packet contains more data than configured MTU. 208015516c77SSepherosa Ziehau */ 208115516c77SSepherosa Ziehau if (dlen > (ifp->if_mtu + ETHER_HDR_LEN)) { 208215516c77SSepherosa Ziehau return (0); 208315516c77SSepherosa Ziehau } else if (dlen <= MHLEN) { 208415516c77SSepherosa Ziehau m_new = m_gethdr(M_NOWAIT, MT_DATA); 208515516c77SSepherosa Ziehau if (m_new == NULL) { 208615516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 208715516c77SSepherosa Ziehau return (0); 208815516c77SSepherosa Ziehau } 208915516c77SSepherosa Ziehau memcpy(mtod(m_new, void *), data, dlen); 209015516c77SSepherosa Ziehau m_new->m_pkthdr.len = m_new->m_len = dlen; 209115516c77SSepherosa Ziehau rxr->hn_small_pkts++; 209215516c77SSepherosa Ziehau } else { 209315516c77SSepherosa Ziehau /* 209415516c77SSepherosa Ziehau * Get an mbuf with a cluster. For packets 2K or less, 209515516c77SSepherosa Ziehau * get a standard 2K cluster. For anything larger, get a 209615516c77SSepherosa Ziehau * 4K cluster. Any buffers larger than 4K can cause problems 209715516c77SSepherosa Ziehau * if looped around to the Hyper-V TX channel, so avoid them. 209815516c77SSepherosa Ziehau */ 209915516c77SSepherosa Ziehau size = MCLBYTES; 210015516c77SSepherosa Ziehau if (dlen > MCLBYTES) { 210115516c77SSepherosa Ziehau /* 4096 */ 210215516c77SSepherosa Ziehau size = MJUMPAGESIZE; 210315516c77SSepherosa Ziehau } 210415516c77SSepherosa Ziehau 210515516c77SSepherosa Ziehau m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size); 210615516c77SSepherosa Ziehau if (m_new == NULL) { 210715516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 210815516c77SSepherosa Ziehau return (0); 210915516c77SSepherosa Ziehau } 211015516c77SSepherosa Ziehau 211115516c77SSepherosa Ziehau hv_m_append(m_new, dlen, data); 211215516c77SSepherosa Ziehau } 211315516c77SSepherosa Ziehau m_new->m_pkthdr.rcvif = ifp; 211415516c77SSepherosa Ziehau 211515516c77SSepherosa Ziehau if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0)) 211615516c77SSepherosa Ziehau do_csum = 0; 211715516c77SSepherosa Ziehau 211815516c77SSepherosa Ziehau /* receive side checksum offload */ 211915516c77SSepherosa Ziehau if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) { 212015516c77SSepherosa Ziehau /* IP csum offload */ 212115516c77SSepherosa Ziehau if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) { 212215516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 212315516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 212415516c77SSepherosa Ziehau rxr->hn_csum_ip++; 212515516c77SSepherosa Ziehau } 212615516c77SSepherosa Ziehau 212715516c77SSepherosa Ziehau /* TCP/UDP csum offload */ 212815516c77SSepherosa Ziehau if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK | 212915516c77SSepherosa Ziehau NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) { 213015516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 213115516c77SSepherosa Ziehau (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 213215516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 213315516c77SSepherosa Ziehau if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK) 213415516c77SSepherosa Ziehau rxr->hn_csum_tcp++; 213515516c77SSepherosa Ziehau else 213615516c77SSepherosa Ziehau rxr->hn_csum_udp++; 213715516c77SSepherosa Ziehau } 213815516c77SSepherosa Ziehau 213915516c77SSepherosa Ziehau /* 214015516c77SSepherosa Ziehau * XXX 214115516c77SSepherosa Ziehau * As of this write (Oct 28th, 2016), host side will turn 214215516c77SSepherosa Ziehau * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so 214315516c77SSepherosa Ziehau * the do_lro setting here is actually _not_ accurate. We 214415516c77SSepherosa Ziehau * depend on the RSS hash type check to reset do_lro. 214515516c77SSepherosa Ziehau */ 214615516c77SSepherosa Ziehau if ((info->csum_info & 214715516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) == 214815516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) 214915516c77SSepherosa Ziehau do_lro = 1; 215015516c77SSepherosa Ziehau } else { 215115516c77SSepherosa Ziehau const struct ether_header *eh; 215215516c77SSepherosa Ziehau uint16_t etype; 215315516c77SSepherosa Ziehau int hoff; 215415516c77SSepherosa Ziehau 215515516c77SSepherosa Ziehau hoff = sizeof(*eh); 215615516c77SSepherosa Ziehau if (m_new->m_len < hoff) 215715516c77SSepherosa Ziehau goto skip; 215815516c77SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 215915516c77SSepherosa Ziehau etype = ntohs(eh->ether_type); 216015516c77SSepherosa Ziehau if (etype == ETHERTYPE_VLAN) { 216115516c77SSepherosa Ziehau const struct ether_vlan_header *evl; 216215516c77SSepherosa Ziehau 216315516c77SSepherosa Ziehau hoff = sizeof(*evl); 216415516c77SSepherosa Ziehau if (m_new->m_len < hoff) 216515516c77SSepherosa Ziehau goto skip; 216615516c77SSepherosa Ziehau evl = mtod(m_new, struct ether_vlan_header *); 216715516c77SSepherosa Ziehau etype = ntohs(evl->evl_proto); 216815516c77SSepherosa Ziehau } 216915516c77SSepherosa Ziehau 217015516c77SSepherosa Ziehau if (etype == ETHERTYPE_IP) { 217115516c77SSepherosa Ziehau int pr; 217215516c77SSepherosa Ziehau 217315516c77SSepherosa Ziehau pr = hn_check_iplen(m_new, hoff); 217415516c77SSepherosa Ziehau if (pr == IPPROTO_TCP) { 217515516c77SSepherosa Ziehau if (do_csum && 217615516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 217715516c77SSepherosa Ziehau HN_TRUST_HCSUM_TCP)) { 217815516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 217915516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 218015516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 218115516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 218215516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 218315516c77SSepherosa Ziehau } 218415516c77SSepherosa Ziehau do_lro = 1; 218515516c77SSepherosa Ziehau } else if (pr == IPPROTO_UDP) { 218615516c77SSepherosa Ziehau if (do_csum && 218715516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 218815516c77SSepherosa Ziehau HN_TRUST_HCSUM_UDP)) { 218915516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 219015516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 219115516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 219215516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 219315516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 219415516c77SSepherosa Ziehau } 219515516c77SSepherosa Ziehau } else if (pr != IPPROTO_DONE && do_csum && 219615516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) { 219715516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 219815516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 219915516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 220015516c77SSepherosa Ziehau } 220115516c77SSepherosa Ziehau } 220215516c77SSepherosa Ziehau } 220315516c77SSepherosa Ziehau skip: 220415516c77SSepherosa Ziehau if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) { 220515516c77SSepherosa Ziehau m_new->m_pkthdr.ether_vtag = EVL_MAKETAG( 220615516c77SSepherosa Ziehau NDIS_VLAN_INFO_ID(info->vlan_info), 220715516c77SSepherosa Ziehau NDIS_VLAN_INFO_PRI(info->vlan_info), 220815516c77SSepherosa Ziehau NDIS_VLAN_INFO_CFI(info->vlan_info)); 220915516c77SSepherosa Ziehau m_new->m_flags |= M_VLANTAG; 221015516c77SSepherosa Ziehau } 221115516c77SSepherosa Ziehau 221215516c77SSepherosa Ziehau if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) { 221315516c77SSepherosa Ziehau rxr->hn_rss_pkts++; 221415516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = info->hash_value; 221515516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE_HASH; 221615516c77SSepherosa Ziehau if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) == 221715516c77SSepherosa Ziehau NDIS_HASH_FUNCTION_TOEPLITZ) { 221815516c77SSepherosa Ziehau uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK); 221915516c77SSepherosa Ziehau 222015516c77SSepherosa Ziehau /* 222115516c77SSepherosa Ziehau * NOTE: 222215516c77SSepherosa Ziehau * do_lro is resetted, if the hash types are not TCP 222315516c77SSepherosa Ziehau * related. See the comment in the above csum_flags 222415516c77SSepherosa Ziehau * setup section. 222515516c77SSepherosa Ziehau */ 222615516c77SSepherosa Ziehau switch (type) { 222715516c77SSepherosa Ziehau case NDIS_HASH_IPV4: 222815516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV4; 222915516c77SSepherosa Ziehau do_lro = 0; 223015516c77SSepherosa Ziehau break; 223115516c77SSepherosa Ziehau 223215516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV4: 223315516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV4; 223415516c77SSepherosa Ziehau break; 223515516c77SSepherosa Ziehau 223615516c77SSepherosa Ziehau case NDIS_HASH_IPV6: 223715516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6; 223815516c77SSepherosa Ziehau do_lro = 0; 223915516c77SSepherosa Ziehau break; 224015516c77SSepherosa Ziehau 224115516c77SSepherosa Ziehau case NDIS_HASH_IPV6_EX: 224215516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6_EX; 224315516c77SSepherosa Ziehau do_lro = 0; 224415516c77SSepherosa Ziehau break; 224515516c77SSepherosa Ziehau 224615516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6: 224715516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6; 224815516c77SSepherosa Ziehau break; 224915516c77SSepherosa Ziehau 225015516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6_EX: 225115516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX; 225215516c77SSepherosa Ziehau break; 225315516c77SSepherosa Ziehau } 225415516c77SSepherosa Ziehau } 225515516c77SSepherosa Ziehau } else { 225615516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = rxr->hn_rx_idx; 225715516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE; 225815516c77SSepherosa Ziehau } 225915516c77SSepherosa Ziehau M_HASHTYPE_SET(m_new, hash_type); 226015516c77SSepherosa Ziehau 226115516c77SSepherosa Ziehau /* 226215516c77SSepherosa Ziehau * Note: Moved RX completion back to hv_nv_on_receive() so all 226315516c77SSepherosa Ziehau * messages (not just data messages) will trigger a response. 226415516c77SSepherosa Ziehau */ 226515516c77SSepherosa Ziehau 226615516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 226715516c77SSepherosa Ziehau rxr->hn_pkts++; 226815516c77SSepherosa Ziehau 226915516c77SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_LRO) && do_lro) { 227015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 227115516c77SSepherosa Ziehau struct lro_ctrl *lro = &rxr->hn_lro; 227215516c77SSepherosa Ziehau 227315516c77SSepherosa Ziehau if (lro->lro_cnt) { 227415516c77SSepherosa Ziehau rxr->hn_lro_tried++; 227515516c77SSepherosa Ziehau if (hn_lro_rx(lro, m_new) == 0) { 227615516c77SSepherosa Ziehau /* DONE! */ 227715516c77SSepherosa Ziehau return 0; 227815516c77SSepherosa Ziehau } 227915516c77SSepherosa Ziehau } 228015516c77SSepherosa Ziehau #endif 228115516c77SSepherosa Ziehau } 228215516c77SSepherosa Ziehau 228315516c77SSepherosa Ziehau /* We're not holding the lock here, so don't release it */ 228415516c77SSepherosa Ziehau (*ifp->if_input)(ifp, m_new); 228515516c77SSepherosa Ziehau 228615516c77SSepherosa Ziehau return (0); 228715516c77SSepherosa Ziehau } 228815516c77SSepherosa Ziehau 228915516c77SSepherosa Ziehau static int 229015516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 229115516c77SSepherosa Ziehau { 229215516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 229315516c77SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data; 229415516c77SSepherosa Ziehau int mask, error = 0; 229515516c77SSepherosa Ziehau 229615516c77SSepherosa Ziehau switch (cmd) { 229715516c77SSepherosa Ziehau case SIOCSIFMTU: 229815516c77SSepherosa Ziehau if (ifr->ifr_mtu > HN_MTU_MAX) { 229915516c77SSepherosa Ziehau error = EINVAL; 230015516c77SSepherosa Ziehau break; 230115516c77SSepherosa Ziehau } 230215516c77SSepherosa Ziehau 230315516c77SSepherosa Ziehau HN_LOCK(sc); 230415516c77SSepherosa Ziehau 230515516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 230615516c77SSepherosa Ziehau HN_UNLOCK(sc); 230715516c77SSepherosa Ziehau break; 230815516c77SSepherosa Ziehau } 230915516c77SSepherosa Ziehau 231015516c77SSepherosa Ziehau if ((sc->hn_caps & HN_CAP_MTU) == 0) { 231115516c77SSepherosa Ziehau /* Can't change MTU */ 231215516c77SSepherosa Ziehau HN_UNLOCK(sc); 231315516c77SSepherosa Ziehau error = EOPNOTSUPP; 231415516c77SSepherosa Ziehau break; 231515516c77SSepherosa Ziehau } 231615516c77SSepherosa Ziehau 231715516c77SSepherosa Ziehau if (ifp->if_mtu == ifr->ifr_mtu) { 231815516c77SSepherosa Ziehau HN_UNLOCK(sc); 231915516c77SSepherosa Ziehau break; 232015516c77SSepherosa Ziehau } 232115516c77SSepherosa Ziehau 232215516c77SSepherosa Ziehau /* 232315516c77SSepherosa Ziehau * Suspend this interface before the synthetic parts 232415516c77SSepherosa Ziehau * are ripped. 232515516c77SSepherosa Ziehau */ 232615516c77SSepherosa Ziehau hn_suspend(sc); 232715516c77SSepherosa Ziehau 232815516c77SSepherosa Ziehau /* 232915516c77SSepherosa Ziehau * Detach the synthetics parts, i.e. NVS and RNDIS. 233015516c77SSepherosa Ziehau */ 233115516c77SSepherosa Ziehau hn_synth_detach(sc); 233215516c77SSepherosa Ziehau 233315516c77SSepherosa Ziehau /* 233415516c77SSepherosa Ziehau * Reattach the synthetic parts, i.e. NVS and RNDIS, 233515516c77SSepherosa Ziehau * with the new MTU setting. 233615516c77SSepherosa Ziehau */ 233715516c77SSepherosa Ziehau error = hn_synth_attach(sc, ifr->ifr_mtu); 233815516c77SSepherosa Ziehau if (error) { 233915516c77SSepherosa Ziehau HN_UNLOCK(sc); 234015516c77SSepherosa Ziehau break; 234115516c77SSepherosa Ziehau } 234215516c77SSepherosa Ziehau 234315516c77SSepherosa Ziehau /* 234415516c77SSepherosa Ziehau * Commit the requested MTU, after the synthetic parts 234515516c77SSepherosa Ziehau * have been successfully attached. 234615516c77SSepherosa Ziehau */ 234715516c77SSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 234815516c77SSepherosa Ziehau 234915516c77SSepherosa Ziehau /* 235015516c77SSepherosa Ziehau * Make sure that various parameters based on MTU are 235115516c77SSepherosa Ziehau * still valid, after the MTU change. 235215516c77SSepherosa Ziehau */ 235315516c77SSepherosa Ziehau if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax) 235415516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 235515516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu); 235615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 235715516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < 235815516c77SSepherosa Ziehau HN_LRO_LENLIM_MIN(ifp)) 235915516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp)); 236015516c77SSepherosa Ziehau #endif 236115516c77SSepherosa Ziehau 236215516c77SSepherosa Ziehau /* 236315516c77SSepherosa Ziehau * All done! Resume the interface now. 236415516c77SSepherosa Ziehau */ 236515516c77SSepherosa Ziehau hn_resume(sc); 236615516c77SSepherosa Ziehau 236715516c77SSepherosa Ziehau HN_UNLOCK(sc); 236815516c77SSepherosa Ziehau break; 236915516c77SSepherosa Ziehau 237015516c77SSepherosa Ziehau case SIOCSIFFLAGS: 237115516c77SSepherosa Ziehau HN_LOCK(sc); 237215516c77SSepherosa Ziehau 237315516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 237415516c77SSepherosa Ziehau HN_UNLOCK(sc); 237515516c77SSepherosa Ziehau break; 237615516c77SSepherosa Ziehau } 237715516c77SSepherosa Ziehau 237815516c77SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 2379fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2380fdc4f478SSepherosa Ziehau /* 2381fdc4f478SSepherosa Ziehau * Caller meight hold mutex, e.g. 2382fdc4f478SSepherosa Ziehau * bpf; use busy-wait for the RNDIS 2383fdc4f478SSepherosa Ziehau * reply. 2384fdc4f478SSepherosa Ziehau */ 2385fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 238615516c77SSepherosa Ziehau hn_set_rxfilter(sc); 2387fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 2388fdc4f478SSepherosa Ziehau } else { 238915516c77SSepherosa Ziehau hn_init_locked(sc); 2390fdc4f478SSepherosa Ziehau } 239115516c77SSepherosa Ziehau } else { 239215516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 239315516c77SSepherosa Ziehau hn_stop(sc); 239415516c77SSepherosa Ziehau } 239515516c77SSepherosa Ziehau sc->hn_if_flags = ifp->if_flags; 239615516c77SSepherosa Ziehau 239715516c77SSepherosa Ziehau HN_UNLOCK(sc); 239815516c77SSepherosa Ziehau break; 239915516c77SSepherosa Ziehau 240015516c77SSepherosa Ziehau case SIOCSIFCAP: 240115516c77SSepherosa Ziehau HN_LOCK(sc); 240215516c77SSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable; 240315516c77SSepherosa Ziehau 240415516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM) { 240515516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 240615516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 240715516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc); 240815516c77SSepherosa Ziehau else 240915516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc); 241015516c77SSepherosa Ziehau } 241115516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM_IPV6) { 241215516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 241315516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 241415516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc); 241515516c77SSepherosa Ziehau else 241615516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc); 241715516c77SSepherosa Ziehau } 241815516c77SSepherosa Ziehau 241915516c77SSepherosa Ziehau /* TODO: flip RNDIS offload parameters for RXCSUM. */ 242015516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 242115516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 242215516c77SSepherosa Ziehau #ifdef foo 242315516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 242415516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM_IPV6) 242515516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 242615516c77SSepherosa Ziehau #endif 242715516c77SSepherosa Ziehau 242815516c77SSepherosa Ziehau if (mask & IFCAP_LRO) 242915516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_LRO; 243015516c77SSepherosa Ziehau 243115516c77SSepherosa Ziehau if (mask & IFCAP_TSO4) { 243215516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO4; 243315516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 243415516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 243515516c77SSepherosa Ziehau else 243615516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP_TSO; 243715516c77SSepherosa Ziehau } 243815516c77SSepherosa Ziehau if (mask & IFCAP_TSO6) { 243915516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO6; 244015516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 244115516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 244215516c77SSepherosa Ziehau else 244315516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP6_TSO; 244415516c77SSepherosa Ziehau } 244515516c77SSepherosa Ziehau 244615516c77SSepherosa Ziehau HN_UNLOCK(sc); 244715516c77SSepherosa Ziehau break; 244815516c77SSepherosa Ziehau 244915516c77SSepherosa Ziehau case SIOCADDMULTI: 245015516c77SSepherosa Ziehau case SIOCDELMULTI: 245115516c77SSepherosa Ziehau HN_LOCK(sc); 245215516c77SSepherosa Ziehau 245315516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 245415516c77SSepherosa Ziehau HN_UNLOCK(sc); 245515516c77SSepherosa Ziehau break; 245615516c77SSepherosa Ziehau } 2457fdc4f478SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2458fdc4f478SSepherosa Ziehau /* 2459fdc4f478SSepherosa Ziehau * Multicast uses mutex; use busy-wait for 2460fdc4f478SSepherosa Ziehau * the RNDIS reply. 2461fdc4f478SSepherosa Ziehau */ 2462fdc4f478SSepherosa Ziehau HN_NO_SLEEPING(sc); 246315516c77SSepherosa Ziehau hn_set_rxfilter(sc); 2464fdc4f478SSepherosa Ziehau HN_SLEEPING_OK(sc); 2465fdc4f478SSepherosa Ziehau } 246615516c77SSepherosa Ziehau 246715516c77SSepherosa Ziehau HN_UNLOCK(sc); 246815516c77SSepherosa Ziehau break; 246915516c77SSepherosa Ziehau 247015516c77SSepherosa Ziehau case SIOCSIFMEDIA: 247115516c77SSepherosa Ziehau case SIOCGIFMEDIA: 247215516c77SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd); 247315516c77SSepherosa Ziehau break; 247415516c77SSepherosa Ziehau 247515516c77SSepherosa Ziehau default: 247615516c77SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 247715516c77SSepherosa Ziehau break; 247815516c77SSepherosa Ziehau } 247915516c77SSepherosa Ziehau return (error); 248015516c77SSepherosa Ziehau } 248115516c77SSepherosa Ziehau 248215516c77SSepherosa Ziehau static void 248315516c77SSepherosa Ziehau hn_stop(struct hn_softc *sc) 248415516c77SSepherosa Ziehau { 248515516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 248615516c77SSepherosa Ziehau int i; 248715516c77SSepherosa Ziehau 248815516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 248915516c77SSepherosa Ziehau 249015516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 249115516c77SSepherosa Ziehau ("synthetic parts were not attached")); 249215516c77SSepherosa Ziehau 249315516c77SSepherosa Ziehau /* Clear RUNNING bit _before_ hn_suspend_data() */ 249415516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 249515516c77SSepherosa Ziehau hn_suspend_data(sc); 249615516c77SSepherosa Ziehau 249715516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 249815516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 249915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 250015516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 250115516c77SSepherosa Ziehau } 250215516c77SSepherosa Ziehau 250315516c77SSepherosa Ziehau static void 250415516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc) 250515516c77SSepherosa Ziehau { 250615516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 250715516c77SSepherosa Ziehau int i; 250815516c77SSepherosa Ziehau 250915516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 251015516c77SSepherosa Ziehau 251115516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 251215516c77SSepherosa Ziehau return; 251315516c77SSepherosa Ziehau 251415516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 251515516c77SSepherosa Ziehau return; 251615516c77SSepherosa Ziehau 251715516c77SSepherosa Ziehau /* Configure RX filter */ 251815516c77SSepherosa Ziehau hn_set_rxfilter(sc); 251915516c77SSepherosa Ziehau 252015516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 252115516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 252215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 252315516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 252415516c77SSepherosa Ziehau 252515516c77SSepherosa Ziehau /* Clear TX 'suspended' bit. */ 252615516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_inuse); 252715516c77SSepherosa Ziehau 252815516c77SSepherosa Ziehau /* Everything is ready; unleash! */ 252915516c77SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 253015516c77SSepherosa Ziehau } 253115516c77SSepherosa Ziehau 253215516c77SSepherosa Ziehau static void 253315516c77SSepherosa Ziehau hn_init(void *xsc) 253415516c77SSepherosa Ziehau { 253515516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 253615516c77SSepherosa Ziehau 253715516c77SSepherosa Ziehau HN_LOCK(sc); 253815516c77SSepherosa Ziehau hn_init_locked(sc); 253915516c77SSepherosa Ziehau HN_UNLOCK(sc); 254015516c77SSepherosa Ziehau } 254115516c77SSepherosa Ziehau 254215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 254315516c77SSepherosa Ziehau 254415516c77SSepherosa Ziehau static int 254515516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS) 254615516c77SSepherosa Ziehau { 254715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 254815516c77SSepherosa Ziehau unsigned int lenlim; 254915516c77SSepherosa Ziehau int error; 255015516c77SSepherosa Ziehau 255115516c77SSepherosa Ziehau lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim; 255215516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &lenlim, 0, req); 255315516c77SSepherosa Ziehau if (error || req->newptr == NULL) 255415516c77SSepherosa Ziehau return error; 255515516c77SSepherosa Ziehau 255615516c77SSepherosa Ziehau HN_LOCK(sc); 255715516c77SSepherosa Ziehau if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) || 255815516c77SSepherosa Ziehau lenlim > TCP_LRO_LENGTH_MAX) { 255915516c77SSepherosa Ziehau HN_UNLOCK(sc); 256015516c77SSepherosa Ziehau return EINVAL; 256115516c77SSepherosa Ziehau } 256215516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, lenlim); 256315516c77SSepherosa Ziehau HN_UNLOCK(sc); 256415516c77SSepherosa Ziehau 256515516c77SSepherosa Ziehau return 0; 256615516c77SSepherosa Ziehau } 256715516c77SSepherosa Ziehau 256815516c77SSepherosa Ziehau static int 256915516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS) 257015516c77SSepherosa Ziehau { 257115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 257215516c77SSepherosa Ziehau int ackcnt, error, i; 257315516c77SSepherosa Ziehau 257415516c77SSepherosa Ziehau /* 257515516c77SSepherosa Ziehau * lro_ackcnt_lim is append count limit, 257615516c77SSepherosa Ziehau * +1 to turn it into aggregation limit. 257715516c77SSepherosa Ziehau */ 257815516c77SSepherosa Ziehau ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1; 257915516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &ackcnt, 0, req); 258015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 258115516c77SSepherosa Ziehau return error; 258215516c77SSepherosa Ziehau 258315516c77SSepherosa Ziehau if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1)) 258415516c77SSepherosa Ziehau return EINVAL; 258515516c77SSepherosa Ziehau 258615516c77SSepherosa Ziehau /* 258715516c77SSepherosa Ziehau * Convert aggregation limit back to append 258815516c77SSepherosa Ziehau * count limit. 258915516c77SSepherosa Ziehau */ 259015516c77SSepherosa Ziehau --ackcnt; 259115516c77SSepherosa Ziehau HN_LOCK(sc); 2592a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) 259315516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt; 259415516c77SSepherosa Ziehau HN_UNLOCK(sc); 259515516c77SSepherosa Ziehau return 0; 259615516c77SSepherosa Ziehau } 259715516c77SSepherosa Ziehau 259815516c77SSepherosa Ziehau #endif 259915516c77SSepherosa Ziehau 260015516c77SSepherosa Ziehau static int 260115516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS) 260215516c77SSepherosa Ziehau { 260315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 260415516c77SSepherosa Ziehau int hcsum = arg2; 260515516c77SSepherosa Ziehau int on, error, i; 260615516c77SSepherosa Ziehau 260715516c77SSepherosa Ziehau on = 0; 260815516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum) 260915516c77SSepherosa Ziehau on = 1; 261015516c77SSepherosa Ziehau 261115516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &on, 0, req); 261215516c77SSepherosa Ziehau if (error || req->newptr == NULL) 261315516c77SSepherosa Ziehau return error; 261415516c77SSepherosa Ziehau 261515516c77SSepherosa Ziehau HN_LOCK(sc); 2616a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 261715516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 261815516c77SSepherosa Ziehau 261915516c77SSepherosa Ziehau if (on) 262015516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= hcsum; 262115516c77SSepherosa Ziehau else 262215516c77SSepherosa Ziehau rxr->hn_trust_hcsum &= ~hcsum; 262315516c77SSepherosa Ziehau } 262415516c77SSepherosa Ziehau HN_UNLOCK(sc); 262515516c77SSepherosa Ziehau return 0; 262615516c77SSepherosa Ziehau } 262715516c77SSepherosa Ziehau 262815516c77SSepherosa Ziehau static int 262915516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS) 263015516c77SSepherosa Ziehau { 263115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 263215516c77SSepherosa Ziehau int chim_size, error; 263315516c77SSepherosa Ziehau 263415516c77SSepherosa Ziehau chim_size = sc->hn_tx_ring[0].hn_chim_size; 263515516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &chim_size, 0, req); 263615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 263715516c77SSepherosa Ziehau return error; 263815516c77SSepherosa Ziehau 263915516c77SSepherosa Ziehau if (chim_size > sc->hn_chim_szmax || chim_size <= 0) 264015516c77SSepherosa Ziehau return EINVAL; 264115516c77SSepherosa Ziehau 264215516c77SSepherosa Ziehau HN_LOCK(sc); 264315516c77SSepherosa Ziehau hn_set_chim_size(sc, chim_size); 264415516c77SSepherosa Ziehau HN_UNLOCK(sc); 264515516c77SSepherosa Ziehau return 0; 264615516c77SSepherosa Ziehau } 264715516c77SSepherosa Ziehau 264815516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 264915516c77SSepherosa Ziehau static int 265015516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS) 265115516c77SSepherosa Ziehau { 265215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 265315516c77SSepherosa Ziehau int ofs = arg2, i, error; 265415516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 265515516c77SSepherosa Ziehau uint64_t stat; 265615516c77SSepherosa Ziehau 265715516c77SSepherosa Ziehau stat = 0; 265815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 265915516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 266015516c77SSepherosa Ziehau stat += *((int *)((uint8_t *)rxr + ofs)); 266115516c77SSepherosa Ziehau } 266215516c77SSepherosa Ziehau 266315516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 266415516c77SSepherosa Ziehau if (error || req->newptr == NULL) 266515516c77SSepherosa Ziehau return error; 266615516c77SSepherosa Ziehau 266715516c77SSepherosa Ziehau /* Zero out this stat. */ 266815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 266915516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 267015516c77SSepherosa Ziehau *((int *)((uint8_t *)rxr + ofs)) = 0; 267115516c77SSepherosa Ziehau } 267215516c77SSepherosa Ziehau return 0; 267315516c77SSepherosa Ziehau } 267415516c77SSepherosa Ziehau #else 267515516c77SSepherosa Ziehau static int 267615516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS) 267715516c77SSepherosa Ziehau { 267815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 267915516c77SSepherosa Ziehau int ofs = arg2, i, error; 268015516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 268115516c77SSepherosa Ziehau uint64_t stat; 268215516c77SSepherosa Ziehau 268315516c77SSepherosa Ziehau stat = 0; 2684a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 268515516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 268615516c77SSepherosa Ziehau stat += *((uint64_t *)((uint8_t *)rxr + ofs)); 268715516c77SSepherosa Ziehau } 268815516c77SSepherosa Ziehau 268915516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 269015516c77SSepherosa Ziehau if (error || req->newptr == NULL) 269115516c77SSepherosa Ziehau return error; 269215516c77SSepherosa Ziehau 269315516c77SSepherosa Ziehau /* Zero out this stat. */ 2694a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 269515516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 269615516c77SSepherosa Ziehau *((uint64_t *)((uint8_t *)rxr + ofs)) = 0; 269715516c77SSepherosa Ziehau } 269815516c77SSepherosa Ziehau return 0; 269915516c77SSepherosa Ziehau } 270015516c77SSepherosa Ziehau 270115516c77SSepherosa Ziehau #endif 270215516c77SSepherosa Ziehau 270315516c77SSepherosa Ziehau static int 270415516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 270515516c77SSepherosa Ziehau { 270615516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 270715516c77SSepherosa Ziehau int ofs = arg2, i, error; 270815516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 270915516c77SSepherosa Ziehau u_long stat; 271015516c77SSepherosa Ziehau 271115516c77SSepherosa Ziehau stat = 0; 2712a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 271315516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 271415516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)rxr + ofs)); 271515516c77SSepherosa Ziehau } 271615516c77SSepherosa Ziehau 271715516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 271815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 271915516c77SSepherosa Ziehau return error; 272015516c77SSepherosa Ziehau 272115516c77SSepherosa Ziehau /* Zero out this stat. */ 2722a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 272315516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 272415516c77SSepherosa Ziehau *((u_long *)((uint8_t *)rxr + ofs)) = 0; 272515516c77SSepherosa Ziehau } 272615516c77SSepherosa Ziehau return 0; 272715516c77SSepherosa Ziehau } 272815516c77SSepherosa Ziehau 272915516c77SSepherosa Ziehau static int 273015516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 273115516c77SSepherosa Ziehau { 273215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 273315516c77SSepherosa Ziehau int ofs = arg2, i, error; 273415516c77SSepherosa Ziehau struct hn_tx_ring *txr; 273515516c77SSepherosa Ziehau u_long stat; 273615516c77SSepherosa Ziehau 273715516c77SSepherosa Ziehau stat = 0; 2738a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 273915516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 274015516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)txr + ofs)); 274115516c77SSepherosa Ziehau } 274215516c77SSepherosa Ziehau 274315516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 274415516c77SSepherosa Ziehau if (error || req->newptr == NULL) 274515516c77SSepherosa Ziehau return error; 274615516c77SSepherosa Ziehau 274715516c77SSepherosa Ziehau /* Zero out this stat. */ 2748a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 274915516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 275015516c77SSepherosa Ziehau *((u_long *)((uint8_t *)txr + ofs)) = 0; 275115516c77SSepherosa Ziehau } 275215516c77SSepherosa Ziehau return 0; 275315516c77SSepherosa Ziehau } 275415516c77SSepherosa Ziehau 275515516c77SSepherosa Ziehau static int 275615516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS) 275715516c77SSepherosa Ziehau { 275815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 275915516c77SSepherosa Ziehau int ofs = arg2, i, error, conf; 276015516c77SSepherosa Ziehau struct hn_tx_ring *txr; 276115516c77SSepherosa Ziehau 276215516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[0]; 276315516c77SSepherosa Ziehau conf = *((int *)((uint8_t *)txr + ofs)); 276415516c77SSepherosa Ziehau 276515516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &conf, 0, req); 276615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 276715516c77SSepherosa Ziehau return error; 276815516c77SSepherosa Ziehau 276915516c77SSepherosa Ziehau HN_LOCK(sc); 2770a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 277115516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 277215516c77SSepherosa Ziehau *((int *)((uint8_t *)txr + ofs)) = conf; 277315516c77SSepherosa Ziehau } 277415516c77SSepherosa Ziehau HN_UNLOCK(sc); 277515516c77SSepherosa Ziehau 277615516c77SSepherosa Ziehau return 0; 277715516c77SSepherosa Ziehau } 277815516c77SSepherosa Ziehau 277915516c77SSepherosa Ziehau static int 2780dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS) 2781dc13fee6SSepherosa Ziehau { 2782dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 2783dc13fee6SSepherosa Ziehau int error, size; 2784dc13fee6SSepherosa Ziehau 2785dc13fee6SSepherosa Ziehau size = sc->hn_agg_size; 2786dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &size, 0, req); 2787dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 2788dc13fee6SSepherosa Ziehau return (error); 2789dc13fee6SSepherosa Ziehau 2790dc13fee6SSepherosa Ziehau HN_LOCK(sc); 2791dc13fee6SSepherosa Ziehau sc->hn_agg_size = size; 2792dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 2793dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 2794dc13fee6SSepherosa Ziehau 2795dc13fee6SSepherosa Ziehau return (0); 2796dc13fee6SSepherosa Ziehau } 2797dc13fee6SSepherosa Ziehau 2798dc13fee6SSepherosa Ziehau static int 2799dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS) 2800dc13fee6SSepherosa Ziehau { 2801dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 2802dc13fee6SSepherosa Ziehau int error, pkts; 2803dc13fee6SSepherosa Ziehau 2804dc13fee6SSepherosa Ziehau pkts = sc->hn_agg_pkts; 2805dc13fee6SSepherosa Ziehau error = sysctl_handle_int(oidp, &pkts, 0, req); 2806dc13fee6SSepherosa Ziehau if (error || req->newptr == NULL) 2807dc13fee6SSepherosa Ziehau return (error); 2808dc13fee6SSepherosa Ziehau 2809dc13fee6SSepherosa Ziehau HN_LOCK(sc); 2810dc13fee6SSepherosa Ziehau sc->hn_agg_pkts = pkts; 2811dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 2812dc13fee6SSepherosa Ziehau HN_UNLOCK(sc); 2813dc13fee6SSepherosa Ziehau 2814dc13fee6SSepherosa Ziehau return (0); 2815dc13fee6SSepherosa Ziehau } 2816dc13fee6SSepherosa Ziehau 2817dc13fee6SSepherosa Ziehau static int 2818dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS) 2819dc13fee6SSepherosa Ziehau { 2820dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 2821dc13fee6SSepherosa Ziehau int pkts; 2822dc13fee6SSepherosa Ziehau 2823dc13fee6SSepherosa Ziehau pkts = sc->hn_tx_ring[0].hn_agg_pktmax; 2824dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &pkts, 0, req)); 2825dc13fee6SSepherosa Ziehau } 2826dc13fee6SSepherosa Ziehau 2827dc13fee6SSepherosa Ziehau static int 2828dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS) 2829dc13fee6SSepherosa Ziehau { 2830dc13fee6SSepherosa Ziehau struct hn_softc *sc = arg1; 2831dc13fee6SSepherosa Ziehau int align; 2832dc13fee6SSepherosa Ziehau 2833dc13fee6SSepherosa Ziehau align = sc->hn_tx_ring[0].hn_agg_align; 2834dc13fee6SSepherosa Ziehau return (sysctl_handle_int(oidp, &align, 0, req)); 2835dc13fee6SSepherosa Ziehau } 2836dc13fee6SSepherosa Ziehau 2837dc13fee6SSepherosa Ziehau static int 283815516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS) 283915516c77SSepherosa Ziehau { 284015516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 284115516c77SSepherosa Ziehau char verstr[16]; 284215516c77SSepherosa Ziehau 284315516c77SSepherosa Ziehau snprintf(verstr, sizeof(verstr), "%u.%u", 284415516c77SSepherosa Ziehau HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 284515516c77SSepherosa Ziehau HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 284615516c77SSepherosa Ziehau return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 284715516c77SSepherosa Ziehau } 284815516c77SSepherosa Ziehau 284915516c77SSepherosa Ziehau static int 285015516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS) 285115516c77SSepherosa Ziehau { 285215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 285315516c77SSepherosa Ziehau char caps_str[128]; 285415516c77SSepherosa Ziehau uint32_t caps; 285515516c77SSepherosa Ziehau 285615516c77SSepherosa Ziehau HN_LOCK(sc); 285715516c77SSepherosa Ziehau caps = sc->hn_caps; 285815516c77SSepherosa Ziehau HN_UNLOCK(sc); 285915516c77SSepherosa Ziehau snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS); 286015516c77SSepherosa Ziehau return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req); 286115516c77SSepherosa Ziehau } 286215516c77SSepherosa Ziehau 286315516c77SSepherosa Ziehau static int 286415516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS) 286515516c77SSepherosa Ziehau { 286615516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 286715516c77SSepherosa Ziehau char assist_str[128]; 286815516c77SSepherosa Ziehau uint32_t hwassist; 286915516c77SSepherosa Ziehau 287015516c77SSepherosa Ziehau HN_LOCK(sc); 287115516c77SSepherosa Ziehau hwassist = sc->hn_ifp->if_hwassist; 287215516c77SSepherosa Ziehau HN_UNLOCK(sc); 287315516c77SSepherosa Ziehau snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS); 287415516c77SSepherosa Ziehau return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req); 287515516c77SSepherosa Ziehau } 287615516c77SSepherosa Ziehau 287715516c77SSepherosa Ziehau static int 287815516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS) 287915516c77SSepherosa Ziehau { 288015516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 288115516c77SSepherosa Ziehau char filter_str[128]; 288215516c77SSepherosa Ziehau uint32_t filter; 288315516c77SSepherosa Ziehau 288415516c77SSepherosa Ziehau HN_LOCK(sc); 288515516c77SSepherosa Ziehau filter = sc->hn_rx_filter; 288615516c77SSepherosa Ziehau HN_UNLOCK(sc); 288715516c77SSepherosa Ziehau snprintf(filter_str, sizeof(filter_str), "%b", filter, 288815516c77SSepherosa Ziehau NDIS_PACKET_TYPES); 288915516c77SSepherosa Ziehau return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req); 289015516c77SSepherosa Ziehau } 289115516c77SSepherosa Ziehau 289215516c77SSepherosa Ziehau static int 289315516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS) 289415516c77SSepherosa Ziehau { 289515516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 289615516c77SSepherosa Ziehau int error; 289715516c77SSepherosa Ziehau 289815516c77SSepherosa Ziehau HN_LOCK(sc); 289915516c77SSepherosa Ziehau 290015516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 290115516c77SSepherosa Ziehau if (error || req->newptr == NULL) 290215516c77SSepherosa Ziehau goto back; 290315516c77SSepherosa Ziehau 290415516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 290515516c77SSepherosa Ziehau if (error) 290615516c77SSepherosa Ziehau goto back; 290715516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 290815516c77SSepherosa Ziehau 290915516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 291015516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 291115516c77SSepherosa Ziehau } else { 291215516c77SSepherosa Ziehau /* Not RSS capable, at least for now; just save the RSS key. */ 291315516c77SSepherosa Ziehau error = 0; 291415516c77SSepherosa Ziehau } 291515516c77SSepherosa Ziehau back: 291615516c77SSepherosa Ziehau HN_UNLOCK(sc); 291715516c77SSepherosa Ziehau return (error); 291815516c77SSepherosa Ziehau } 291915516c77SSepherosa Ziehau 292015516c77SSepherosa Ziehau static int 292115516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS) 292215516c77SSepherosa Ziehau { 292315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 292415516c77SSepherosa Ziehau int error; 292515516c77SSepherosa Ziehau 292615516c77SSepherosa Ziehau HN_LOCK(sc); 292715516c77SSepherosa Ziehau 292815516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 292915516c77SSepherosa Ziehau if (error || req->newptr == NULL) 293015516c77SSepherosa Ziehau goto back; 293115516c77SSepherosa Ziehau 293215516c77SSepherosa Ziehau /* 293315516c77SSepherosa Ziehau * Don't allow RSS indirect table change, if this interface is not 293415516c77SSepherosa Ziehau * RSS capable currently. 293515516c77SSepherosa Ziehau */ 293615516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 293715516c77SSepherosa Ziehau error = EOPNOTSUPP; 293815516c77SSepherosa Ziehau goto back; 293915516c77SSepherosa Ziehau } 294015516c77SSepherosa Ziehau 294115516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 294215516c77SSepherosa Ziehau if (error) 294315516c77SSepherosa Ziehau goto back; 294415516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 294515516c77SSepherosa Ziehau 294615516c77SSepherosa Ziehau hn_rss_ind_fixup(sc, sc->hn_rx_ring_inuse); 294715516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 294815516c77SSepherosa Ziehau back: 294915516c77SSepherosa Ziehau HN_UNLOCK(sc); 295015516c77SSepherosa Ziehau return (error); 295115516c77SSepherosa Ziehau } 295215516c77SSepherosa Ziehau 295315516c77SSepherosa Ziehau static int 295415516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS) 295515516c77SSepherosa Ziehau { 295615516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 295715516c77SSepherosa Ziehau char hash_str[128]; 295815516c77SSepherosa Ziehau uint32_t hash; 295915516c77SSepherosa Ziehau 296015516c77SSepherosa Ziehau HN_LOCK(sc); 296115516c77SSepherosa Ziehau hash = sc->hn_rss_hash; 296215516c77SSepherosa Ziehau HN_UNLOCK(sc); 296315516c77SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 296415516c77SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 296515516c77SSepherosa Ziehau } 296615516c77SSepherosa Ziehau 296715516c77SSepherosa Ziehau static int 296815516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff) 296915516c77SSepherosa Ziehau { 297015516c77SSepherosa Ziehau const struct ip *ip; 297115516c77SSepherosa Ziehau int len, iphlen, iplen; 297215516c77SSepherosa Ziehau const struct tcphdr *th; 297315516c77SSepherosa Ziehau int thoff; /* TCP data offset */ 297415516c77SSepherosa Ziehau 297515516c77SSepherosa Ziehau len = hoff + sizeof(struct ip); 297615516c77SSepherosa Ziehau 297715516c77SSepherosa Ziehau /* The packet must be at least the size of an IP header. */ 297815516c77SSepherosa Ziehau if (m->m_pkthdr.len < len) 297915516c77SSepherosa Ziehau return IPPROTO_DONE; 298015516c77SSepherosa Ziehau 298115516c77SSepherosa Ziehau /* The fixed IP header must reside completely in the first mbuf. */ 298215516c77SSepherosa Ziehau if (m->m_len < len) 298315516c77SSepherosa Ziehau return IPPROTO_DONE; 298415516c77SSepherosa Ziehau 298515516c77SSepherosa Ziehau ip = mtodo(m, hoff); 298615516c77SSepherosa Ziehau 298715516c77SSepherosa Ziehau /* Bound check the packet's stated IP header length. */ 298815516c77SSepherosa Ziehau iphlen = ip->ip_hl << 2; 298915516c77SSepherosa Ziehau if (iphlen < sizeof(struct ip)) /* minimum header length */ 299015516c77SSepherosa Ziehau return IPPROTO_DONE; 299115516c77SSepherosa Ziehau 299215516c77SSepherosa Ziehau /* The full IP header must reside completely in the one mbuf. */ 299315516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen) 299415516c77SSepherosa Ziehau return IPPROTO_DONE; 299515516c77SSepherosa Ziehau 299615516c77SSepherosa Ziehau iplen = ntohs(ip->ip_len); 299715516c77SSepherosa Ziehau 299815516c77SSepherosa Ziehau /* 299915516c77SSepherosa Ziehau * Check that the amount of data in the buffers is as 300015516c77SSepherosa Ziehau * at least much as the IP header would have us expect. 300115516c77SSepherosa Ziehau */ 300215516c77SSepherosa Ziehau if (m->m_pkthdr.len < hoff + iplen) 300315516c77SSepherosa Ziehau return IPPROTO_DONE; 300415516c77SSepherosa Ziehau 300515516c77SSepherosa Ziehau /* 300615516c77SSepherosa Ziehau * Ignore IP fragments. 300715516c77SSepherosa Ziehau */ 300815516c77SSepherosa Ziehau if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF)) 300915516c77SSepherosa Ziehau return IPPROTO_DONE; 301015516c77SSepherosa Ziehau 301115516c77SSepherosa Ziehau /* 301215516c77SSepherosa Ziehau * The TCP/IP or UDP/IP header must be entirely contained within 301315516c77SSepherosa Ziehau * the first fragment of a packet. 301415516c77SSepherosa Ziehau */ 301515516c77SSepherosa Ziehau switch (ip->ip_p) { 301615516c77SSepherosa Ziehau case IPPROTO_TCP: 301715516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct tcphdr)) 301815516c77SSepherosa Ziehau return IPPROTO_DONE; 301915516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct tcphdr)) 302015516c77SSepherosa Ziehau return IPPROTO_DONE; 302115516c77SSepherosa Ziehau th = (const struct tcphdr *)((const uint8_t *)ip + iphlen); 302215516c77SSepherosa Ziehau thoff = th->th_off << 2; 302315516c77SSepherosa Ziehau if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen) 302415516c77SSepherosa Ziehau return IPPROTO_DONE; 302515516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + thoff) 302615516c77SSepherosa Ziehau return IPPROTO_DONE; 302715516c77SSepherosa Ziehau break; 302815516c77SSepherosa Ziehau case IPPROTO_UDP: 302915516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct udphdr)) 303015516c77SSepherosa Ziehau return IPPROTO_DONE; 303115516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct udphdr)) 303215516c77SSepherosa Ziehau return IPPROTO_DONE; 303315516c77SSepherosa Ziehau break; 303415516c77SSepherosa Ziehau default: 303515516c77SSepherosa Ziehau if (iplen < iphlen) 303615516c77SSepherosa Ziehau return IPPROTO_DONE; 303715516c77SSepherosa Ziehau break; 303815516c77SSepherosa Ziehau } 303915516c77SSepherosa Ziehau return ip->ip_p; 304015516c77SSepherosa Ziehau } 304115516c77SSepherosa Ziehau 304215516c77SSepherosa Ziehau static int 304315516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt) 304415516c77SSepherosa Ziehau { 304515516c77SSepherosa Ziehau struct sysctl_oid_list *child; 304615516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 304715516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 304815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 304915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 305015516c77SSepherosa Ziehau int lroent_cnt; 305115516c77SSepherosa Ziehau #endif 305215516c77SSepherosa Ziehau #endif 305315516c77SSepherosa Ziehau int i; 305415516c77SSepherosa Ziehau 305515516c77SSepherosa Ziehau /* 305615516c77SSepherosa Ziehau * Create RXBUF for reception. 305715516c77SSepherosa Ziehau * 305815516c77SSepherosa Ziehau * NOTE: 305915516c77SSepherosa Ziehau * - It is shared by all channels. 306015516c77SSepherosa Ziehau * - A large enough buffer is allocated, certain version of NVSes 306115516c77SSepherosa Ziehau * may further limit the usable space. 306215516c77SSepherosa Ziehau */ 306315516c77SSepherosa Ziehau sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 306415516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma, 306515516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 306615516c77SSepherosa Ziehau if (sc->hn_rxbuf == NULL) { 306715516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate rxbuf failed\n"); 306815516c77SSepherosa Ziehau return (ENOMEM); 306915516c77SSepherosa Ziehau } 307015516c77SSepherosa Ziehau 307115516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = ring_cnt; 307215516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt; 307315516c77SSepherosa Ziehau 307415516c77SSepherosa Ziehau sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt, 307515516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 307615516c77SSepherosa Ziehau 307715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 307815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 307915516c77SSepherosa Ziehau lroent_cnt = hn_lro_entry_count; 308015516c77SSepherosa Ziehau if (lroent_cnt < TCP_LRO_ENTRIES) 308115516c77SSepherosa Ziehau lroent_cnt = TCP_LRO_ENTRIES; 308215516c77SSepherosa Ziehau if (bootverbose) 308315516c77SSepherosa Ziehau device_printf(dev, "LRO: entry count %d\n", lroent_cnt); 308415516c77SSepherosa Ziehau #endif 308515516c77SSepherosa Ziehau #endif /* INET || INET6 */ 308615516c77SSepherosa Ziehau 308715516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 308815516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 308915516c77SSepherosa Ziehau 309015516c77SSepherosa Ziehau /* Create dev.hn.UNIT.rx sysctl tree */ 309115516c77SSepherosa Ziehau sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx", 309215516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 309315516c77SSepherosa Ziehau 309415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 309515516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 309615516c77SSepherosa Ziehau 309715516c77SSepherosa Ziehau rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 309815516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE, 309915516c77SSepherosa Ziehau &rxr->hn_br_dma, BUS_DMA_WAITOK); 310015516c77SSepherosa Ziehau if (rxr->hn_br == NULL) { 310115516c77SSepherosa Ziehau device_printf(dev, "allocate bufring failed\n"); 310215516c77SSepherosa Ziehau return (ENOMEM); 310315516c77SSepherosa Ziehau } 310415516c77SSepherosa Ziehau 310515516c77SSepherosa Ziehau if (hn_trust_hosttcp) 310615516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP; 310715516c77SSepherosa Ziehau if (hn_trust_hostudp) 310815516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP; 310915516c77SSepherosa Ziehau if (hn_trust_hostip) 311015516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP; 311115516c77SSepherosa Ziehau rxr->hn_ifp = sc->hn_ifp; 311215516c77SSepherosa Ziehau if (i < sc->hn_tx_ring_cnt) 311315516c77SSepherosa Ziehau rxr->hn_txr = &sc->hn_tx_ring[i]; 311415516c77SSepherosa Ziehau rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF; 311515516c77SSepherosa Ziehau rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK); 311615516c77SSepherosa Ziehau rxr->hn_rx_idx = i; 311715516c77SSepherosa Ziehau rxr->hn_rxbuf = sc->hn_rxbuf; 311815516c77SSepherosa Ziehau 311915516c77SSepherosa Ziehau /* 312015516c77SSepherosa Ziehau * Initialize LRO. 312115516c77SSepherosa Ziehau */ 312215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 312315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 312415516c77SSepherosa Ziehau tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt, 312515516c77SSepherosa Ziehau hn_lro_mbufq_depth); 312615516c77SSepherosa Ziehau #else 312715516c77SSepherosa Ziehau tcp_lro_init(&rxr->hn_lro); 312815516c77SSepherosa Ziehau rxr->hn_lro.ifp = sc->hn_ifp; 312915516c77SSepherosa Ziehau #endif 313015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 313115516c77SSepherosa Ziehau rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF; 313215516c77SSepherosa Ziehau rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF; 313315516c77SSepherosa Ziehau #endif 313415516c77SSepherosa Ziehau #endif /* INET || INET6 */ 313515516c77SSepherosa Ziehau 313615516c77SSepherosa Ziehau if (sc->hn_rx_sysctl_tree != NULL) { 313715516c77SSepherosa Ziehau char name[16]; 313815516c77SSepherosa Ziehau 313915516c77SSepherosa Ziehau /* 314015516c77SSepherosa Ziehau * Create per RX ring sysctl tree: 314115516c77SSepherosa Ziehau * dev.hn.UNIT.rx.RINGID 314215516c77SSepherosa Ziehau */ 314315516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", i); 314415516c77SSepherosa Ziehau rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, 314515516c77SSepherosa Ziehau SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree), 314615516c77SSepherosa Ziehau OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 314715516c77SSepherosa Ziehau 314815516c77SSepherosa Ziehau if (rxr->hn_rx_sysctl_tree != NULL) { 314915516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 315015516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 315115516c77SSepherosa Ziehau OID_AUTO, "packets", CTLFLAG_RW, 315215516c77SSepherosa Ziehau &rxr->hn_pkts, "# of packets received"); 315315516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 315415516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 315515516c77SSepherosa Ziehau OID_AUTO, "rss_pkts", CTLFLAG_RW, 315615516c77SSepherosa Ziehau &rxr->hn_rss_pkts, 315715516c77SSepherosa Ziehau "# of packets w/ RSS info received"); 315815516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, 315915516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 316015516c77SSepherosa Ziehau OID_AUTO, "pktbuf_len", CTLFLAG_RD, 316115516c77SSepherosa Ziehau &rxr->hn_pktbuf_len, 0, 316215516c77SSepherosa Ziehau "Temporary channel packet buffer length"); 316315516c77SSepherosa Ziehau } 316415516c77SSepherosa Ziehau } 316515516c77SSepherosa Ziehau } 316615516c77SSepherosa Ziehau 316715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued", 316815516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 316915516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_queued), 317015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 317115516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 317215516c77SSepherosa Ziehau #else 317315516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 317415516c77SSepherosa Ziehau #endif 317515516c77SSepherosa Ziehau "LU", "LRO queued"); 317615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed", 317715516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 317815516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_flushed), 317915516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 318015516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 318115516c77SSepherosa Ziehau #else 318215516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 318315516c77SSepherosa Ziehau #endif 318415516c77SSepherosa Ziehau "LU", "LRO flushed"); 318515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried", 318615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 318715516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro_tried), 318815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries"); 318915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 319015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim", 319115516c77SSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 319215516c77SSepherosa Ziehau hn_lro_lenlim_sysctl, "IU", 319315516c77SSepherosa Ziehau "Max # of data bytes to be aggregated by LRO"); 319415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim", 319515516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 319615516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl, "I", 319715516c77SSepherosa Ziehau "Max # of ACKs to be aggregated by LRO"); 319815516c77SSepherosa Ziehau #endif 319915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp", 320015516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP, 320115516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 320215516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 320315516c77SSepherosa Ziehau "when csum info is missing"); 320415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp", 320515516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP, 320615516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 320715516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 320815516c77SSepherosa Ziehau "when csum info is missing"); 320915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip", 321015516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP, 321115516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 321215516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 321315516c77SSepherosa Ziehau "when csum info is missing"); 321415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip", 321515516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 321615516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_ip), 321715516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP"); 321815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp", 321915516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 322015516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_tcp), 322115516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP"); 322215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp", 322315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 322415516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_udp), 322515516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP"); 322615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted", 322715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 322815516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_trusted), 322915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", 323015516c77SSepherosa Ziehau "# of packets that we trust host's csum verification"); 323115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts", 323215516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 323315516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_small_pkts), 323415516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of small packets received"); 323515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed", 323615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 323715516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_ack_failed), 323815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures"); 323915516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt", 324015516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings"); 324115516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse", 324215516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings"); 324315516c77SSepherosa Ziehau 324415516c77SSepherosa Ziehau return (0); 324515516c77SSepherosa Ziehau } 324615516c77SSepherosa Ziehau 324715516c77SSepherosa Ziehau static void 324815516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc) 324915516c77SSepherosa Ziehau { 325015516c77SSepherosa Ziehau int i; 325115516c77SSepherosa Ziehau 325215516c77SSepherosa Ziehau if (sc->hn_rxbuf != NULL) { 32532494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0) 325415516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf); 32552494d735SSepherosa Ziehau else 32562494d735SSepherosa Ziehau device_printf(sc->hn_dev, "RXBUF is referenced\n"); 325715516c77SSepherosa Ziehau sc->hn_rxbuf = NULL; 325815516c77SSepherosa Ziehau } 325915516c77SSepherosa Ziehau 326015516c77SSepherosa Ziehau if (sc->hn_rx_ring_cnt == 0) 326115516c77SSepherosa Ziehau return; 326215516c77SSepherosa Ziehau 326315516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 326415516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 326515516c77SSepherosa Ziehau 326615516c77SSepherosa Ziehau if (rxr->hn_br == NULL) 326715516c77SSepherosa Ziehau continue; 32682494d735SSepherosa Ziehau if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) { 326915516c77SSepherosa Ziehau hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br); 32702494d735SSepherosa Ziehau } else { 32712494d735SSepherosa Ziehau device_printf(sc->hn_dev, 32722494d735SSepherosa Ziehau "%dth channel bufring is referenced", i); 32732494d735SSepherosa Ziehau } 327415516c77SSepherosa Ziehau rxr->hn_br = NULL; 327515516c77SSepherosa Ziehau 327615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 327715516c77SSepherosa Ziehau tcp_lro_free(&rxr->hn_lro); 327815516c77SSepherosa Ziehau #endif 327915516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 328015516c77SSepherosa Ziehau } 328115516c77SSepherosa Ziehau free(sc->hn_rx_ring, M_DEVBUF); 328215516c77SSepherosa Ziehau sc->hn_rx_ring = NULL; 328315516c77SSepherosa Ziehau 328415516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = 0; 328515516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = 0; 328615516c77SSepherosa Ziehau } 328715516c77SSepherosa Ziehau 328815516c77SSepherosa Ziehau static int 328915516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id) 329015516c77SSepherosa Ziehau { 329115516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[id]; 329215516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 329315516c77SSepherosa Ziehau bus_dma_tag_t parent_dtag; 329415516c77SSepherosa Ziehau int error, i; 329515516c77SSepherosa Ziehau 329615516c77SSepherosa Ziehau txr->hn_sc = sc; 329715516c77SSepherosa Ziehau txr->hn_tx_idx = id; 329815516c77SSepherosa Ziehau 329915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 330015516c77SSepherosa Ziehau mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); 330115516c77SSepherosa Ziehau #endif 330215516c77SSepherosa Ziehau mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF); 330315516c77SSepherosa Ziehau 330415516c77SSepherosa Ziehau txr->hn_txdesc_cnt = HN_TX_DESC_CNT; 330515516c77SSepherosa Ziehau txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt, 330615516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 330715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 330815516c77SSepherosa Ziehau SLIST_INIT(&txr->hn_txlist); 330915516c77SSepherosa Ziehau #else 331015516c77SSepherosa Ziehau txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF, 331115516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 331215516c77SSepherosa Ziehau #endif 331315516c77SSepherosa Ziehau 331415516c77SSepherosa Ziehau txr->hn_tx_taskq = sc->hn_tx_taskq; 331515516c77SSepherosa Ziehau 331623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 331715516c77SSepherosa Ziehau if (hn_use_if_start) { 331815516c77SSepherosa Ziehau txr->hn_txeof = hn_start_txeof; 331915516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr); 332015516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr); 332123bf9e15SSepherosa Ziehau } else 332223bf9e15SSepherosa Ziehau #endif 332323bf9e15SSepherosa Ziehau { 332415516c77SSepherosa Ziehau int br_depth; 332515516c77SSepherosa Ziehau 332615516c77SSepherosa Ziehau txr->hn_txeof = hn_xmit_txeof; 332715516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr); 332815516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr); 332915516c77SSepherosa Ziehau 333015516c77SSepherosa Ziehau br_depth = hn_get_txswq_depth(txr); 333115516c77SSepherosa Ziehau txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF, 333215516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 333315516c77SSepherosa Ziehau } 333415516c77SSepherosa Ziehau 333515516c77SSepherosa Ziehau txr->hn_direct_tx_size = hn_direct_tx_size; 333615516c77SSepherosa Ziehau 333715516c77SSepherosa Ziehau /* 333815516c77SSepherosa Ziehau * Always schedule transmission instead of trying to do direct 333915516c77SSepherosa Ziehau * transmission. This one gives the best performance so far. 334015516c77SSepherosa Ziehau */ 334115516c77SSepherosa Ziehau txr->hn_sched_tx = 1; 334215516c77SSepherosa Ziehau 334315516c77SSepherosa Ziehau parent_dtag = bus_get_dma_tag(dev); 334415516c77SSepherosa Ziehau 334515516c77SSepherosa Ziehau /* DMA tag for RNDIS packet messages. */ 334615516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 334715516c77SSepherosa Ziehau HN_RNDIS_PKT_ALIGN, /* alignment */ 334815516c77SSepherosa Ziehau HN_RNDIS_PKT_BOUNDARY, /* boundary */ 334915516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 335015516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 335115516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 335215516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsize */ 335315516c77SSepherosa Ziehau 1, /* nsegments */ 335415516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsegsize */ 335515516c77SSepherosa Ziehau 0, /* flags */ 335615516c77SSepherosa Ziehau NULL, /* lockfunc */ 335715516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 335815516c77SSepherosa Ziehau &txr->hn_tx_rndis_dtag); 335915516c77SSepherosa Ziehau if (error) { 336015516c77SSepherosa Ziehau device_printf(dev, "failed to create rndis dmatag\n"); 336115516c77SSepherosa Ziehau return error; 336215516c77SSepherosa Ziehau } 336315516c77SSepherosa Ziehau 336415516c77SSepherosa Ziehau /* DMA tag for data. */ 336515516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 336615516c77SSepherosa Ziehau 1, /* alignment */ 336715516c77SSepherosa Ziehau HN_TX_DATA_BOUNDARY, /* boundary */ 336815516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 336915516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 337015516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 337115516c77SSepherosa Ziehau HN_TX_DATA_MAXSIZE, /* maxsize */ 337215516c77SSepherosa Ziehau HN_TX_DATA_SEGCNT_MAX, /* nsegments */ 337315516c77SSepherosa Ziehau HN_TX_DATA_SEGSIZE, /* maxsegsize */ 337415516c77SSepherosa Ziehau 0, /* flags */ 337515516c77SSepherosa Ziehau NULL, /* lockfunc */ 337615516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 337715516c77SSepherosa Ziehau &txr->hn_tx_data_dtag); 337815516c77SSepherosa Ziehau if (error) { 337915516c77SSepherosa Ziehau device_printf(dev, "failed to create data dmatag\n"); 338015516c77SSepherosa Ziehau return error; 338115516c77SSepherosa Ziehau } 338215516c77SSepherosa Ziehau 338315516c77SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) { 338415516c77SSepherosa Ziehau struct hn_txdesc *txd = &txr->hn_txdesc[i]; 338515516c77SSepherosa Ziehau 338615516c77SSepherosa Ziehau txd->txr = txr; 338715516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 3388dc13fee6SSepherosa Ziehau STAILQ_INIT(&txd->agg_list); 338915516c77SSepherosa Ziehau 339015516c77SSepherosa Ziehau /* 339115516c77SSepherosa Ziehau * Allocate and load RNDIS packet message. 339215516c77SSepherosa Ziehau */ 339315516c77SSepherosa Ziehau error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag, 339415516c77SSepherosa Ziehau (void **)&txd->rndis_pkt, 339515516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 339615516c77SSepherosa Ziehau &txd->rndis_pkt_dmap); 339715516c77SSepherosa Ziehau if (error) { 339815516c77SSepherosa Ziehau device_printf(dev, 339915516c77SSepherosa Ziehau "failed to allocate rndis_packet_msg, %d\n", i); 340015516c77SSepherosa Ziehau return error; 340115516c77SSepherosa Ziehau } 340215516c77SSepherosa Ziehau 340315516c77SSepherosa Ziehau error = bus_dmamap_load(txr->hn_tx_rndis_dtag, 340415516c77SSepherosa Ziehau txd->rndis_pkt_dmap, 340515516c77SSepherosa Ziehau txd->rndis_pkt, HN_RNDIS_PKT_LEN, 340615516c77SSepherosa Ziehau hyperv_dma_map_paddr, &txd->rndis_pkt_paddr, 340715516c77SSepherosa Ziehau BUS_DMA_NOWAIT); 340815516c77SSepherosa Ziehau if (error) { 340915516c77SSepherosa Ziehau device_printf(dev, 341015516c77SSepherosa Ziehau "failed to load rndis_packet_msg, %d\n", i); 341115516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 341215516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 341315516c77SSepherosa Ziehau return error; 341415516c77SSepherosa Ziehau } 341515516c77SSepherosa Ziehau 341615516c77SSepherosa Ziehau /* DMA map for TX data. */ 341715516c77SSepherosa Ziehau error = bus_dmamap_create(txr->hn_tx_data_dtag, 0, 341815516c77SSepherosa Ziehau &txd->data_dmap); 341915516c77SSepherosa Ziehau if (error) { 342015516c77SSepherosa Ziehau device_printf(dev, 342115516c77SSepherosa Ziehau "failed to allocate tx data dmamap\n"); 342215516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, 342315516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 342415516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 342515516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 342615516c77SSepherosa Ziehau return error; 342715516c77SSepherosa Ziehau } 342815516c77SSepherosa Ziehau 342915516c77SSepherosa Ziehau /* All set, put it to list */ 343015516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 343115516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 343215516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 343315516c77SSepherosa Ziehau #else 343415516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 343515516c77SSepherosa Ziehau #endif 343615516c77SSepherosa Ziehau } 343715516c77SSepherosa Ziehau txr->hn_txdesc_avail = txr->hn_txdesc_cnt; 343815516c77SSepherosa Ziehau 343915516c77SSepherosa Ziehau if (sc->hn_tx_sysctl_tree != NULL) { 344015516c77SSepherosa Ziehau struct sysctl_oid_list *child; 344115516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 344215516c77SSepherosa Ziehau char name[16]; 344315516c77SSepherosa Ziehau 344415516c77SSepherosa Ziehau /* 344515516c77SSepherosa Ziehau * Create per TX ring sysctl tree: 344615516c77SSepherosa Ziehau * dev.hn.UNIT.tx.RINGID 344715516c77SSepherosa Ziehau */ 344815516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 344915516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree); 345015516c77SSepherosa Ziehau 345115516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", id); 345215516c77SSepherosa Ziehau txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, 345315516c77SSepherosa Ziehau name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 345415516c77SSepherosa Ziehau 345515516c77SSepherosa Ziehau if (txr->hn_tx_sysctl_tree != NULL) { 345615516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree); 345715516c77SSepherosa Ziehau 345815516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail", 345915516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_txdesc_avail, 0, 346015516c77SSepherosa Ziehau "# of available TX descs"); 346123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 346223bf9e15SSepherosa Ziehau if (!hn_use_if_start) 346323bf9e15SSepherosa Ziehau #endif 346423bf9e15SSepherosa Ziehau { 346515516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive", 346615516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_oactive, 0, 346715516c77SSepherosa Ziehau "over active"); 346815516c77SSepherosa Ziehau } 346915516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets", 347015516c77SSepherosa Ziehau CTLFLAG_RW, &txr->hn_pkts, 347115516c77SSepherosa Ziehau "# of packets transmitted"); 3472dc13fee6SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends", 3473dc13fee6SSepherosa Ziehau CTLFLAG_RW, &txr->hn_sends, "# of sends"); 347415516c77SSepherosa Ziehau } 347515516c77SSepherosa Ziehau } 347615516c77SSepherosa Ziehau 347715516c77SSepherosa Ziehau return 0; 347815516c77SSepherosa Ziehau } 347915516c77SSepherosa Ziehau 348015516c77SSepherosa Ziehau static void 348115516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd) 348215516c77SSepherosa Ziehau { 348315516c77SSepherosa Ziehau struct hn_tx_ring *txr = txd->txr; 348415516c77SSepherosa Ziehau 348515516c77SSepherosa Ziehau KASSERT(txd->m == NULL, ("still has mbuf installed")); 348615516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped")); 348715516c77SSepherosa Ziehau 348815516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap); 348915516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt, 349015516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 349115516c77SSepherosa Ziehau bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap); 349215516c77SSepherosa Ziehau } 349315516c77SSepherosa Ziehau 349415516c77SSepherosa Ziehau static void 349525641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd) 349625641fc7SSepherosa Ziehau { 349725641fc7SSepherosa Ziehau 349825641fc7SSepherosa Ziehau KASSERT(txd->refs == 0 || txd->refs == 1, 349925641fc7SSepherosa Ziehau ("invalid txd refs %d", txd->refs)); 350025641fc7SSepherosa Ziehau 350125641fc7SSepherosa Ziehau /* Aggregated txds will be freed by their aggregating txd. */ 350225641fc7SSepherosa Ziehau if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) { 350325641fc7SSepherosa Ziehau int freed; 350425641fc7SSepherosa Ziehau 350525641fc7SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 350625641fc7SSepherosa Ziehau KASSERT(freed, ("can't free txdesc")); 350725641fc7SSepherosa Ziehau } 350825641fc7SSepherosa Ziehau } 350925641fc7SSepherosa Ziehau 351025641fc7SSepherosa Ziehau static void 351115516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr) 351215516c77SSepherosa Ziehau { 351325641fc7SSepherosa Ziehau int i; 351415516c77SSepherosa Ziehau 351515516c77SSepherosa Ziehau if (txr->hn_txdesc == NULL) 351615516c77SSepherosa Ziehau return; 351715516c77SSepherosa Ziehau 351825641fc7SSepherosa Ziehau /* 351925641fc7SSepherosa Ziehau * NOTE: 352025641fc7SSepherosa Ziehau * Because the freeing of aggregated txds will be deferred 352125641fc7SSepherosa Ziehau * to the aggregating txd, two passes are used here: 352225641fc7SSepherosa Ziehau * - The first pass GCes any pending txds. This GC is necessary, 352325641fc7SSepherosa Ziehau * since if the channels are revoked, hypervisor will not 352425641fc7SSepherosa Ziehau * deliver send-done for all pending txds. 352525641fc7SSepherosa Ziehau * - The second pass frees the busdma stuffs, i.e. after all txds 352625641fc7SSepherosa Ziehau * were freed. 352725641fc7SSepherosa Ziehau */ 352825641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 352925641fc7SSepherosa Ziehau hn_txdesc_gc(txr, &txr->hn_txdesc[i]); 353025641fc7SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) 353125641fc7SSepherosa Ziehau hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]); 353215516c77SSepherosa Ziehau 353315516c77SSepherosa Ziehau if (txr->hn_tx_data_dtag != NULL) 353415516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_data_dtag); 353515516c77SSepherosa Ziehau if (txr->hn_tx_rndis_dtag != NULL) 353615516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_rndis_dtag); 353715516c77SSepherosa Ziehau 353815516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 353915516c77SSepherosa Ziehau buf_ring_free(txr->hn_txdesc_br, M_DEVBUF); 354015516c77SSepherosa Ziehau #endif 354115516c77SSepherosa Ziehau 354215516c77SSepherosa Ziehau free(txr->hn_txdesc, M_DEVBUF); 354315516c77SSepherosa Ziehau txr->hn_txdesc = NULL; 354415516c77SSepherosa Ziehau 354515516c77SSepherosa Ziehau if (txr->hn_mbuf_br != NULL) 354615516c77SSepherosa Ziehau buf_ring_free(txr->hn_mbuf_br, M_DEVBUF); 354715516c77SSepherosa Ziehau 354815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 354915516c77SSepherosa Ziehau mtx_destroy(&txr->hn_txlist_spin); 355015516c77SSepherosa Ziehau #endif 355115516c77SSepherosa Ziehau mtx_destroy(&txr->hn_tx_lock); 355215516c77SSepherosa Ziehau } 355315516c77SSepherosa Ziehau 355415516c77SSepherosa Ziehau static int 355515516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt) 355615516c77SSepherosa Ziehau { 355715516c77SSepherosa Ziehau struct sysctl_oid_list *child; 355815516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 355915516c77SSepherosa Ziehau int i; 356015516c77SSepherosa Ziehau 356115516c77SSepherosa Ziehau /* 356215516c77SSepherosa Ziehau * Create TXBUF for chimney sending. 356315516c77SSepherosa Ziehau * 356415516c77SSepherosa Ziehau * NOTE: It is shared by all channels. 356515516c77SSepherosa Ziehau */ 356615516c77SSepherosa Ziehau sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), 356715516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma, 356815516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 356915516c77SSepherosa Ziehau if (sc->hn_chim == NULL) { 357015516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate txbuf failed\n"); 357115516c77SSepherosa Ziehau return (ENOMEM); 357215516c77SSepherosa Ziehau } 357315516c77SSepherosa Ziehau 357415516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = ring_cnt; 357515516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 357615516c77SSepherosa Ziehau 357715516c77SSepherosa Ziehau sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt, 357815516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 357915516c77SSepherosa Ziehau 358015516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(sc->hn_dev); 358115516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev)); 358215516c77SSepherosa Ziehau 358315516c77SSepherosa Ziehau /* Create dev.hn.UNIT.tx sysctl tree */ 358415516c77SSepherosa Ziehau sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx", 358515516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 358615516c77SSepherosa Ziehau 358715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 358815516c77SSepherosa Ziehau int error; 358915516c77SSepherosa Ziehau 359015516c77SSepherosa Ziehau error = hn_tx_ring_create(sc, i); 359115516c77SSepherosa Ziehau if (error) 359215516c77SSepherosa Ziehau return error; 359315516c77SSepherosa Ziehau } 359415516c77SSepherosa Ziehau 359515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs", 359615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 359715516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_no_txdescs), 359815516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs"); 359915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed", 360015516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 360115516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_send_failed), 360215516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure"); 360315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed", 360415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 360515516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_txdma_failed), 360615516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure"); 3607dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed", 3608dc13fee6SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 3609dc13fee6SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_flush_failed), 3610dc13fee6SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", 3611dc13fee6SSepherosa Ziehau "# of packet transmission aggregation flush failure"); 361215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed", 361315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 361415516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_collapsed), 361515516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed"); 361615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney", 361715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 361815516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney), 361915516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send"); 362015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried", 362115516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 362215516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney_tried), 362315516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries"); 362415516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt", 362515516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0, 362615516c77SSepherosa Ziehau "# of total TX descs"); 362715516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max", 362815516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_chim_szmax, 0, 362915516c77SSepherosa Ziehau "Chimney send packet size upper boundary"); 363015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size", 363115516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 363215516c77SSepherosa Ziehau hn_chim_size_sysctl, "I", "Chimney send packet size limit"); 363315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size", 363415516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 363515516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_direct_tx_size), 363615516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 363715516c77SSepherosa Ziehau "Size of the packet for direct transmission"); 363815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx", 363915516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 364015516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_sched_tx), 364115516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 364215516c77SSepherosa Ziehau "Always schedule transmission " 364315516c77SSepherosa Ziehau "instead of doing direct transmission"); 364415516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt", 364515516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings"); 364615516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse", 364715516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings"); 3648dc13fee6SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax", 3649dc13fee6SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0, 3650dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation size"); 3651dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax", 3652dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 3653dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl, "I", 3654dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation packets"); 3655dc13fee6SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align", 3656dc13fee6SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 3657dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl, "I", 3658dc13fee6SSepherosa Ziehau "Applied packet transmission aggregation alignment"); 365915516c77SSepherosa Ziehau 366015516c77SSepherosa Ziehau return 0; 366115516c77SSepherosa Ziehau } 366215516c77SSepherosa Ziehau 366315516c77SSepherosa Ziehau static void 366415516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size) 366515516c77SSepherosa Ziehau { 366615516c77SSepherosa Ziehau int i; 366715516c77SSepherosa Ziehau 3668a7ba7648SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 366915516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_chim_size = chim_size; 367015516c77SSepherosa Ziehau } 367115516c77SSepherosa Ziehau 367215516c77SSepherosa Ziehau static void 367315516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu) 367415516c77SSepherosa Ziehau { 367515516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 367615516c77SSepherosa Ziehau int tso_minlen; 367715516c77SSepherosa Ziehau 367815516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0) 367915516c77SSepherosa Ziehau return; 368015516c77SSepherosa Ziehau 368115516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_sgmin >= 2, 368215516c77SSepherosa Ziehau ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin)); 368315516c77SSepherosa Ziehau tso_minlen = sc->hn_ndis_tso_sgmin * mtu; 368415516c77SSepherosa Ziehau 368515516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen && 368615516c77SSepherosa Ziehau sc->hn_ndis_tso_szmax <= IP_MAXPACKET, 368715516c77SSepherosa Ziehau ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax)); 368815516c77SSepherosa Ziehau 368915516c77SSepherosa Ziehau if (tso_maxlen < tso_minlen) 369015516c77SSepherosa Ziehau tso_maxlen = tso_minlen; 369115516c77SSepherosa Ziehau else if (tso_maxlen > IP_MAXPACKET) 369215516c77SSepherosa Ziehau tso_maxlen = IP_MAXPACKET; 369315516c77SSepherosa Ziehau if (tso_maxlen > sc->hn_ndis_tso_szmax) 369415516c77SSepherosa Ziehau tso_maxlen = sc->hn_ndis_tso_szmax; 369515516c77SSepherosa Ziehau ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 369615516c77SSepherosa Ziehau if (bootverbose) 369715516c77SSepherosa Ziehau if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax); 369815516c77SSepherosa Ziehau } 369915516c77SSepherosa Ziehau 370015516c77SSepherosa Ziehau static void 370115516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc) 370215516c77SSepherosa Ziehau { 370315516c77SSepherosa Ziehau uint64_t csum_assist; 370415516c77SSepherosa Ziehau int i; 370515516c77SSepherosa Ziehau 370615516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 370715516c77SSepherosa Ziehau if (hn_tx_chimney_size > 0 && 370815516c77SSepherosa Ziehau hn_tx_chimney_size < sc->hn_chim_szmax) 370915516c77SSepherosa Ziehau hn_set_chim_size(sc, hn_tx_chimney_size); 371015516c77SSepherosa Ziehau 371115516c77SSepherosa Ziehau csum_assist = 0; 371215516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_IPCS) 371315516c77SSepherosa Ziehau csum_assist |= CSUM_IP; 371415516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP4CS) 371515516c77SSepherosa Ziehau csum_assist |= CSUM_IP_TCP; 371615516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP4CS) 371715516c77SSepherosa Ziehau csum_assist |= CSUM_IP_UDP; 371815516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP6CS) 371915516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_TCP; 372015516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP6CS) 372115516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_UDP; 372215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 372315516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_csum_assist = csum_assist; 372415516c77SSepherosa Ziehau 372515516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_HASHVAL) { 372615516c77SSepherosa Ziehau /* 372715516c77SSepherosa Ziehau * Support HASHVAL pktinfo on TX path. 372815516c77SSepherosa Ziehau */ 372915516c77SSepherosa Ziehau if (bootverbose) 373015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n"); 373115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 373215516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL; 373315516c77SSepherosa Ziehau } 373415516c77SSepherosa Ziehau } 373515516c77SSepherosa Ziehau 373615516c77SSepherosa Ziehau static void 373715516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc) 373815516c77SSepherosa Ziehau { 373915516c77SSepherosa Ziehau int i; 374015516c77SSepherosa Ziehau 374115516c77SSepherosa Ziehau if (sc->hn_chim != NULL) { 37422494d735SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) { 374315516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim); 37442494d735SSepherosa Ziehau } else { 37452494d735SSepherosa Ziehau device_printf(sc->hn_dev, 37462494d735SSepherosa Ziehau "chimney sending buffer is referenced"); 37472494d735SSepherosa Ziehau } 374815516c77SSepherosa Ziehau sc->hn_chim = NULL; 374915516c77SSepherosa Ziehau } 375015516c77SSepherosa Ziehau 375115516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt == 0) 375215516c77SSepherosa Ziehau return; 375315516c77SSepherosa Ziehau 375415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 375515516c77SSepherosa Ziehau hn_tx_ring_destroy(&sc->hn_tx_ring[i]); 375615516c77SSepherosa Ziehau 375715516c77SSepherosa Ziehau free(sc->hn_tx_ring, M_DEVBUF); 375815516c77SSepherosa Ziehau sc->hn_tx_ring = NULL; 375915516c77SSepherosa Ziehau 376015516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = 0; 376115516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = 0; 376215516c77SSepherosa Ziehau } 376315516c77SSepherosa Ziehau 376423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 376523bf9e15SSepherosa Ziehau 376615516c77SSepherosa Ziehau static void 376715516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused) 376815516c77SSepherosa Ziehau { 376915516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 377015516c77SSepherosa Ziehau 377115516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 377215516c77SSepherosa Ziehau hn_start_locked(txr, 0); 377315516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 377415516c77SSepherosa Ziehau } 377515516c77SSepherosa Ziehau 377623bf9e15SSepherosa Ziehau static int 377723bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len) 377823bf9e15SSepherosa Ziehau { 377923bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 378023bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 3781dc13fee6SSepherosa Ziehau int sched = 0; 378223bf9e15SSepherosa Ziehau 378323bf9e15SSepherosa Ziehau KASSERT(hn_use_if_start, 378423bf9e15SSepherosa Ziehau ("hn_start_locked is called, when if_start is disabled")); 378523bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 378623bf9e15SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 3787dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 378823bf9e15SSepherosa Ziehau 378923bf9e15SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 3790dc13fee6SSepherosa Ziehau return (0); 379123bf9e15SSepherosa Ziehau 379223bf9e15SSepherosa Ziehau if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 379323bf9e15SSepherosa Ziehau IFF_DRV_RUNNING) 3794dc13fee6SSepherosa Ziehau return (0); 379523bf9e15SSepherosa Ziehau 379623bf9e15SSepherosa Ziehau while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 379723bf9e15SSepherosa Ziehau struct hn_txdesc *txd; 379823bf9e15SSepherosa Ziehau struct mbuf *m_head; 379923bf9e15SSepherosa Ziehau int error; 380023bf9e15SSepherosa Ziehau 380123bf9e15SSepherosa Ziehau IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 380223bf9e15SSepherosa Ziehau if (m_head == NULL) 380323bf9e15SSepherosa Ziehau break; 380423bf9e15SSepherosa Ziehau 380523bf9e15SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 380623bf9e15SSepherosa Ziehau /* 380723bf9e15SSepherosa Ziehau * This sending could be time consuming; let callers 380823bf9e15SSepherosa Ziehau * dispatch this packet sending (and sending of any 380923bf9e15SSepherosa Ziehau * following up packets) to tx taskqueue. 381023bf9e15SSepherosa Ziehau */ 381123bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 3812dc13fee6SSepherosa Ziehau sched = 1; 3813dc13fee6SSepherosa Ziehau break; 381423bf9e15SSepherosa Ziehau } 381523bf9e15SSepherosa Ziehau 3816edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 3817edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 3818edd3f315SSepherosa Ziehau m_head = hn_tso_fixup(m_head); 3819edd3f315SSepherosa Ziehau if (__predict_false(m_head == NULL)) { 3820edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 3821edd3f315SSepherosa Ziehau continue; 3822edd3f315SSepherosa Ziehau } 3823edd3f315SSepherosa Ziehau } 3824edd3f315SSepherosa Ziehau #endif 3825edd3f315SSepherosa Ziehau 382623bf9e15SSepherosa Ziehau txd = hn_txdesc_get(txr); 382723bf9e15SSepherosa Ziehau if (txd == NULL) { 382823bf9e15SSepherosa Ziehau txr->hn_no_txdescs++; 382923bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 383023bf9e15SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 383123bf9e15SSepherosa Ziehau break; 383223bf9e15SSepherosa Ziehau } 383323bf9e15SSepherosa Ziehau 3834dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 383523bf9e15SSepherosa Ziehau if (error) { 383623bf9e15SSepherosa Ziehau /* Both txd and m_head are freed */ 3837dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 3838dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 383923bf9e15SSepherosa Ziehau continue; 384023bf9e15SSepherosa Ziehau } 384123bf9e15SSepherosa Ziehau 3842dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 3843dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 3844dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 3845dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 3846dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 3847dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 3848dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 3849dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 3850dc13fee6SSepherosa Ziehau break; 3851dc13fee6SSepherosa Ziehau } 3852dc13fee6SSepherosa Ziehau } else { 3853dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 385423bf9e15SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 385523bf9e15SSepherosa Ziehau if (__predict_false(error)) { 385623bf9e15SSepherosa Ziehau /* txd is freed, but m_head is not */ 385723bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 3858dc13fee6SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, 3859dc13fee6SSepherosa Ziehau IFF_DRV_OACTIVE); 386023bf9e15SSepherosa Ziehau break; 386123bf9e15SSepherosa Ziehau } 386223bf9e15SSepherosa Ziehau } 3863dc13fee6SSepherosa Ziehau } 3864dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 3865dc13fee6SSepherosa Ziehau else { 3866dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 3867dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 3868dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 3869dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 3870dc13fee6SSepherosa Ziehau } 3871dc13fee6SSepherosa Ziehau #endif 3872dc13fee6SSepherosa Ziehau } 3873dc13fee6SSepherosa Ziehau 3874dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 3875dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 3876dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 3877dc13fee6SSepherosa Ziehau return (sched); 387823bf9e15SSepherosa Ziehau } 387923bf9e15SSepherosa Ziehau 388023bf9e15SSepherosa Ziehau static void 388123bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp) 388223bf9e15SSepherosa Ziehau { 388323bf9e15SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 388423bf9e15SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[0]; 388523bf9e15SSepherosa Ziehau 388623bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 388723bf9e15SSepherosa Ziehau goto do_sched; 388823bf9e15SSepherosa Ziehau 388923bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 389023bf9e15SSepherosa Ziehau int sched; 389123bf9e15SSepherosa Ziehau 389223bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 389323bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 389423bf9e15SSepherosa Ziehau if (!sched) 389523bf9e15SSepherosa Ziehau return; 389623bf9e15SSepherosa Ziehau } 389723bf9e15SSepherosa Ziehau do_sched: 389823bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 389923bf9e15SSepherosa Ziehau } 390023bf9e15SSepherosa Ziehau 390115516c77SSepherosa Ziehau static void 390215516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused) 390315516c77SSepherosa Ziehau { 390415516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 390515516c77SSepherosa Ziehau 390615516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 390715516c77SSepherosa Ziehau atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE); 390815516c77SSepherosa Ziehau hn_start_locked(txr, 0); 390915516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 391015516c77SSepherosa Ziehau } 391115516c77SSepherosa Ziehau 391223bf9e15SSepherosa Ziehau static void 391323bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr) 391423bf9e15SSepherosa Ziehau { 391523bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 391623bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 391723bf9e15SSepherosa Ziehau 391823bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 391923bf9e15SSepherosa Ziehau 392023bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 392123bf9e15SSepherosa Ziehau goto do_sched; 392223bf9e15SSepherosa Ziehau 392323bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 392423bf9e15SSepherosa Ziehau int sched; 392523bf9e15SSepherosa Ziehau 392623bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 392723bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 392823bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 392923bf9e15SSepherosa Ziehau if (sched) { 393023bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 393123bf9e15SSepherosa Ziehau &txr->hn_tx_task); 393223bf9e15SSepherosa Ziehau } 393323bf9e15SSepherosa Ziehau } else { 393423bf9e15SSepherosa Ziehau do_sched: 393523bf9e15SSepherosa Ziehau /* 393623bf9e15SSepherosa Ziehau * Release the OACTIVE earlier, with the hope, that 393723bf9e15SSepherosa Ziehau * others could catch up. The task will clear the 393823bf9e15SSepherosa Ziehau * flag again with the hn_tx_lock to avoid possible 393923bf9e15SSepherosa Ziehau * races. 394023bf9e15SSepherosa Ziehau */ 394123bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 394223bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 394323bf9e15SSepherosa Ziehau } 394423bf9e15SSepherosa Ziehau } 394523bf9e15SSepherosa Ziehau 394623bf9e15SSepherosa Ziehau #endif /* HN_IFSTART_SUPPORT */ 394723bf9e15SSepherosa Ziehau 394815516c77SSepherosa Ziehau static int 394915516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len) 395015516c77SSepherosa Ziehau { 395115516c77SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 395215516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 395315516c77SSepherosa Ziehau struct mbuf *m_head; 3954dc13fee6SSepherosa Ziehau int sched = 0; 395515516c77SSepherosa Ziehau 395615516c77SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 395723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 395815516c77SSepherosa Ziehau KASSERT(hn_use_if_start == 0, 395915516c77SSepherosa Ziehau ("hn_xmit is called, when if_start is enabled")); 396023bf9e15SSepherosa Ziehau #endif 3961dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc")); 396215516c77SSepherosa Ziehau 396315516c77SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 3964dc13fee6SSepherosa Ziehau return (0); 396515516c77SSepherosa Ziehau 396615516c77SSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive) 3967dc13fee6SSepherosa Ziehau return (0); 396815516c77SSepherosa Ziehau 396915516c77SSepherosa Ziehau while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) { 397015516c77SSepherosa Ziehau struct hn_txdesc *txd; 397115516c77SSepherosa Ziehau int error; 397215516c77SSepherosa Ziehau 397315516c77SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 397415516c77SSepherosa Ziehau /* 397515516c77SSepherosa Ziehau * This sending could be time consuming; let callers 397615516c77SSepherosa Ziehau * dispatch this packet sending (and sending of any 397715516c77SSepherosa Ziehau * following up packets) to tx taskqueue. 397815516c77SSepherosa Ziehau */ 397915516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 3980dc13fee6SSepherosa Ziehau sched = 1; 3981dc13fee6SSepherosa Ziehau break; 398215516c77SSepherosa Ziehau } 398315516c77SSepherosa Ziehau 398415516c77SSepherosa Ziehau txd = hn_txdesc_get(txr); 398515516c77SSepherosa Ziehau if (txd == NULL) { 398615516c77SSepherosa Ziehau txr->hn_no_txdescs++; 398715516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 398815516c77SSepherosa Ziehau txr->hn_oactive = 1; 398915516c77SSepherosa Ziehau break; 399015516c77SSepherosa Ziehau } 399115516c77SSepherosa Ziehau 3992dc13fee6SSepherosa Ziehau error = hn_encap(ifp, txr, txd, &m_head); 399315516c77SSepherosa Ziehau if (error) { 399415516c77SSepherosa Ziehau /* Both txd and m_head are freed; discard */ 3995dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd == NULL, 3996dc13fee6SSepherosa Ziehau ("encap failed w/ pending aggregating txdesc")); 399715516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 399815516c77SSepherosa Ziehau continue; 399915516c77SSepherosa Ziehau } 400015516c77SSepherosa Ziehau 4001dc13fee6SSepherosa Ziehau if (txr->hn_agg_pktleft == 0) { 4002dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) { 4003dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 4004dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 4005dc13fee6SSepherosa Ziehau error = hn_flush_txagg(ifp, txr); 400615516c77SSepherosa Ziehau if (__predict_false(error)) { 400715516c77SSepherosa Ziehau txr->hn_oactive = 1; 400815516c77SSepherosa Ziehau break; 400915516c77SSepherosa Ziehau } 4010dc13fee6SSepherosa Ziehau } else { 4011dc13fee6SSepherosa Ziehau KASSERT(m_head != NULL, ("mbuf was freed")); 4012dc13fee6SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 4013dc13fee6SSepherosa Ziehau if (__predict_false(error)) { 4014dc13fee6SSepherosa Ziehau /* txd is freed, but m_head is not */ 4015dc13fee6SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, 4016dc13fee6SSepherosa Ziehau m_head); 4017dc13fee6SSepherosa Ziehau txr->hn_oactive = 1; 4018dc13fee6SSepherosa Ziehau break; 4019dc13fee6SSepherosa Ziehau } 4020dc13fee6SSepherosa Ziehau } 4021dc13fee6SSepherosa Ziehau } 4022dc13fee6SSepherosa Ziehau #ifdef INVARIANTS 4023dc13fee6SSepherosa Ziehau else { 4024dc13fee6SSepherosa Ziehau KASSERT(txr->hn_agg_txd != NULL, 4025dc13fee6SSepherosa Ziehau ("no aggregating txdesc")); 4026dc13fee6SSepherosa Ziehau KASSERT(m_head == NULL, 4027dc13fee6SSepherosa Ziehau ("pending mbuf for aggregating txdesc")); 4028dc13fee6SSepherosa Ziehau } 4029dc13fee6SSepherosa Ziehau #endif 403015516c77SSepherosa Ziehau 403115516c77SSepherosa Ziehau /* Sent */ 403215516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 403315516c77SSepherosa Ziehau } 4034dc13fee6SSepherosa Ziehau 4035dc13fee6SSepherosa Ziehau /* Flush pending aggerated transmission. */ 4036dc13fee6SSepherosa Ziehau if (txr->hn_agg_txd != NULL) 4037dc13fee6SSepherosa Ziehau hn_flush_txagg(ifp, txr); 4038dc13fee6SSepherosa Ziehau return (sched); 403915516c77SSepherosa Ziehau } 404015516c77SSepherosa Ziehau 404115516c77SSepherosa Ziehau static int 404215516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m) 404315516c77SSepherosa Ziehau { 404415516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 404515516c77SSepherosa Ziehau struct hn_tx_ring *txr; 404615516c77SSepherosa Ziehau int error, idx = 0; 404715516c77SSepherosa Ziehau 4048edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 4049edd3f315SSepherosa Ziehau /* 4050edd3f315SSepherosa Ziehau * Perform TSO packet header fixup now, since the TSO 4051edd3f315SSepherosa Ziehau * packet header should be cache-hot. 4052edd3f315SSepherosa Ziehau */ 4053edd3f315SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 4054edd3f315SSepherosa Ziehau m = hn_tso_fixup(m); 4055edd3f315SSepherosa Ziehau if (__predict_false(m == NULL)) { 4056edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 4057edd3f315SSepherosa Ziehau return EIO; 4058edd3f315SSepherosa Ziehau } 4059edd3f315SSepherosa Ziehau } 4060edd3f315SSepherosa Ziehau #endif 4061edd3f315SSepherosa Ziehau 406215516c77SSepherosa Ziehau /* 406315516c77SSepherosa Ziehau * Select the TX ring based on flowid 406415516c77SSepherosa Ziehau */ 406515516c77SSepherosa Ziehau if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 406615516c77SSepherosa Ziehau idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse; 406715516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 406815516c77SSepherosa Ziehau 406915516c77SSepherosa Ziehau error = drbr_enqueue(ifp, txr->hn_mbuf_br, m); 407015516c77SSepherosa Ziehau if (error) { 407115516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 407215516c77SSepherosa Ziehau return error; 407315516c77SSepherosa Ziehau } 407415516c77SSepherosa Ziehau 407515516c77SSepherosa Ziehau if (txr->hn_oactive) 407615516c77SSepherosa Ziehau return 0; 407715516c77SSepherosa Ziehau 407815516c77SSepherosa Ziehau if (txr->hn_sched_tx) 407915516c77SSepherosa Ziehau goto do_sched; 408015516c77SSepherosa Ziehau 408115516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 408215516c77SSepherosa Ziehau int sched; 408315516c77SSepherosa Ziehau 408415516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 408515516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 408615516c77SSepherosa Ziehau if (!sched) 408715516c77SSepherosa Ziehau return 0; 408815516c77SSepherosa Ziehau } 408915516c77SSepherosa Ziehau do_sched: 409015516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 409115516c77SSepherosa Ziehau return 0; 409215516c77SSepherosa Ziehau } 409315516c77SSepherosa Ziehau 409415516c77SSepherosa Ziehau static void 409515516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr) 409615516c77SSepherosa Ziehau { 409715516c77SSepherosa Ziehau struct mbuf *m; 409815516c77SSepherosa Ziehau 409915516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 410015516c77SSepherosa Ziehau while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL) 410115516c77SSepherosa Ziehau m_freem(m); 410215516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 410315516c77SSepherosa Ziehau } 410415516c77SSepherosa Ziehau 410515516c77SSepherosa Ziehau static void 410615516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp) 410715516c77SSepherosa Ziehau { 410815516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 410915516c77SSepherosa Ziehau int i; 411015516c77SSepherosa Ziehau 411115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 411215516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 411315516c77SSepherosa Ziehau if_qflush(ifp); 411415516c77SSepherosa Ziehau } 411515516c77SSepherosa Ziehau 411615516c77SSepherosa Ziehau static void 411715516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr) 411815516c77SSepherosa Ziehau { 411915516c77SSepherosa Ziehau 412015516c77SSepherosa Ziehau if (txr->hn_sched_tx) 412115516c77SSepherosa Ziehau goto do_sched; 412215516c77SSepherosa Ziehau 412315516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 412415516c77SSepherosa Ziehau int sched; 412515516c77SSepherosa Ziehau 412615516c77SSepherosa Ziehau txr->hn_oactive = 0; 412715516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 412815516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 412915516c77SSepherosa Ziehau if (sched) { 413015516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 413115516c77SSepherosa Ziehau &txr->hn_tx_task); 413215516c77SSepherosa Ziehau } 413315516c77SSepherosa Ziehau } else { 413415516c77SSepherosa Ziehau do_sched: 413515516c77SSepherosa Ziehau /* 413615516c77SSepherosa Ziehau * Release the oactive earlier, with the hope, that 413715516c77SSepherosa Ziehau * others could catch up. The task will clear the 413815516c77SSepherosa Ziehau * oactive again with the hn_tx_lock to avoid possible 413915516c77SSepherosa Ziehau * races. 414015516c77SSepherosa Ziehau */ 414115516c77SSepherosa Ziehau txr->hn_oactive = 0; 414215516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 414315516c77SSepherosa Ziehau } 414415516c77SSepherosa Ziehau } 414515516c77SSepherosa Ziehau 414615516c77SSepherosa Ziehau static void 414715516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused) 414815516c77SSepherosa Ziehau { 414915516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 415015516c77SSepherosa Ziehau 415115516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 415215516c77SSepherosa Ziehau hn_xmit(txr, 0); 415315516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 415415516c77SSepherosa Ziehau } 415515516c77SSepherosa Ziehau 415615516c77SSepherosa Ziehau static void 415715516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused) 415815516c77SSepherosa Ziehau { 415915516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 416015516c77SSepherosa Ziehau 416115516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 416215516c77SSepherosa Ziehau txr->hn_oactive = 0; 416315516c77SSepherosa Ziehau hn_xmit(txr, 0); 416415516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 416515516c77SSepherosa Ziehau } 416615516c77SSepherosa Ziehau 416715516c77SSepherosa Ziehau static int 416815516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan) 416915516c77SSepherosa Ziehau { 417015516c77SSepherosa Ziehau struct vmbus_chan_br cbr; 417115516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 417215516c77SSepherosa Ziehau struct hn_tx_ring *txr = NULL; 417315516c77SSepherosa Ziehau int idx, error; 417415516c77SSepherosa Ziehau 417515516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 417615516c77SSepherosa Ziehau 417715516c77SSepherosa Ziehau /* 417815516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 417915516c77SSepherosa Ziehau */ 418015516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 418115516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 418215516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 418315516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 418415516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0, 418515516c77SSepherosa Ziehau ("RX ring %d already attached", idx)); 418615516c77SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED; 418715516c77SSepherosa Ziehau 418815516c77SSepherosa Ziehau if (bootverbose) { 418915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n", 419015516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 419115516c77SSepherosa Ziehau } 419215516c77SSepherosa Ziehau 419315516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 419415516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 419515516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0, 419615516c77SSepherosa Ziehau ("TX ring %d already attached", idx)); 419715516c77SSepherosa Ziehau txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED; 419815516c77SSepherosa Ziehau 419915516c77SSepherosa Ziehau txr->hn_chan = chan; 420015516c77SSepherosa Ziehau if (bootverbose) { 420115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n", 420215516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 420315516c77SSepherosa Ziehau } 420415516c77SSepherosa Ziehau } 420515516c77SSepherosa Ziehau 420615516c77SSepherosa Ziehau /* Bind this channel to a proper CPU. */ 420715516c77SSepherosa Ziehau vmbus_chan_cpu_set(chan, (sc->hn_cpu + idx) % mp_ncpus); 420815516c77SSepherosa Ziehau 420915516c77SSepherosa Ziehau /* 421015516c77SSepherosa Ziehau * Open this channel 421115516c77SSepherosa Ziehau */ 421215516c77SSepherosa Ziehau cbr.cbr = rxr->hn_br; 421315516c77SSepherosa Ziehau cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr; 421415516c77SSepherosa Ziehau cbr.cbr_txsz = HN_TXBR_SIZE; 421515516c77SSepherosa Ziehau cbr.cbr_rxsz = HN_RXBR_SIZE; 421615516c77SSepherosa Ziehau error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr); 421715516c77SSepherosa Ziehau if (error) { 421815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "open chan%u failed: %d\n", 421915516c77SSepherosa Ziehau vmbus_chan_id(chan), error); 422015516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 422115516c77SSepherosa Ziehau if (txr != NULL) 422215516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 422315516c77SSepherosa Ziehau } 422415516c77SSepherosa Ziehau return (error); 422515516c77SSepherosa Ziehau } 422615516c77SSepherosa Ziehau 422715516c77SSepherosa Ziehau static void 422815516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan) 422915516c77SSepherosa Ziehau { 423015516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 42312494d735SSepherosa Ziehau int idx, error; 423215516c77SSepherosa Ziehau 423315516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 423415516c77SSepherosa Ziehau 423515516c77SSepherosa Ziehau /* 423615516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 423715516c77SSepherosa Ziehau */ 423815516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 423915516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 424015516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 424115516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 424215516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED), 424315516c77SSepherosa Ziehau ("RX ring %d is not attached", idx)); 424415516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 424515516c77SSepherosa Ziehau 424615516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 424715516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[idx]; 424815516c77SSepherosa Ziehau 424915516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED), 425015516c77SSepherosa Ziehau ("TX ring %d is not attached attached", idx)); 425115516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 425215516c77SSepherosa Ziehau } 425315516c77SSepherosa Ziehau 425415516c77SSepherosa Ziehau /* 425515516c77SSepherosa Ziehau * Close this channel. 425615516c77SSepherosa Ziehau * 425715516c77SSepherosa Ziehau * NOTE: 425815516c77SSepherosa Ziehau * Channel closing does _not_ destroy the target channel. 425915516c77SSepherosa Ziehau */ 42602494d735SSepherosa Ziehau error = vmbus_chan_close_direct(chan); 42612494d735SSepherosa Ziehau if (error == EISCONN) { 42622494d735SSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u subidx%u " 42632494d735SSepherosa Ziehau "bufring is connected after being closed\n", 42642494d735SSepherosa Ziehau vmbus_chan_id(chan), vmbus_chan_subidx(chan)); 42652494d735SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF; 42662494d735SSepherosa Ziehau } else if (error) { 42672494d735SSepherosa Ziehau if_printf(sc->hn_ifp, "chan%u subidx%u close failed: %d\n", 42682494d735SSepherosa Ziehau vmbus_chan_id(chan), vmbus_chan_subidx(chan), error); 42692494d735SSepherosa Ziehau } 427015516c77SSepherosa Ziehau } 427115516c77SSepherosa Ziehau 427215516c77SSepherosa Ziehau static int 427315516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc) 427415516c77SSepherosa Ziehau { 427515516c77SSepherosa Ziehau struct vmbus_channel **subchans; 427615516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 427715516c77SSepherosa Ziehau int i, error = 0; 427815516c77SSepherosa Ziehau 427915516c77SSepherosa Ziehau if (subchan_cnt == 0) 428015516c77SSepherosa Ziehau return (0); 428115516c77SSepherosa Ziehau 428215516c77SSepherosa Ziehau /* Attach the sub-channels. */ 428315516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 428415516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) { 428515516c77SSepherosa Ziehau error = hn_chan_attach(sc, subchans[i]); 428615516c77SSepherosa Ziehau if (error) 428715516c77SSepherosa Ziehau break; 428815516c77SSepherosa Ziehau } 428915516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 429015516c77SSepherosa Ziehau 429115516c77SSepherosa Ziehau if (error) { 429215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error); 429315516c77SSepherosa Ziehau } else { 429415516c77SSepherosa Ziehau if (bootverbose) { 429515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d sub-channels attached\n", 429615516c77SSepherosa Ziehau subchan_cnt); 429715516c77SSepherosa Ziehau } 429815516c77SSepherosa Ziehau } 429915516c77SSepherosa Ziehau return (error); 430015516c77SSepherosa Ziehau } 430115516c77SSepherosa Ziehau 430215516c77SSepherosa Ziehau static void 430315516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc) 430415516c77SSepherosa Ziehau { 430515516c77SSepherosa Ziehau struct vmbus_channel **subchans; 430615516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 430715516c77SSepherosa Ziehau int i; 430815516c77SSepherosa Ziehau 430915516c77SSepherosa Ziehau if (subchan_cnt == 0) 431015516c77SSepherosa Ziehau goto back; 431115516c77SSepherosa Ziehau 431215516c77SSepherosa Ziehau /* Detach the sub-channels. */ 431315516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 431415516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) 431515516c77SSepherosa Ziehau hn_chan_detach(sc, subchans[i]); 431615516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 431715516c77SSepherosa Ziehau 431815516c77SSepherosa Ziehau back: 431915516c77SSepherosa Ziehau /* 432015516c77SSepherosa Ziehau * Detach the primary channel, _after_ all sub-channels 432115516c77SSepherosa Ziehau * are detached. 432215516c77SSepherosa Ziehau */ 432315516c77SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 432415516c77SSepherosa Ziehau 432515516c77SSepherosa Ziehau /* Wait for sub-channels to be destroyed, if any. */ 432615516c77SSepherosa Ziehau vmbus_subchan_drain(sc->hn_prichan); 432715516c77SSepherosa Ziehau 432815516c77SSepherosa Ziehau #ifdef INVARIANTS 432915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 433015516c77SSepherosa Ziehau KASSERT((sc->hn_rx_ring[i].hn_rx_flags & 433115516c77SSepherosa Ziehau HN_RX_FLAG_ATTACHED) == 0, 433215516c77SSepherosa Ziehau ("%dth RX ring is still attached", i)); 433315516c77SSepherosa Ziehau } 433415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 433515516c77SSepherosa Ziehau KASSERT((sc->hn_tx_ring[i].hn_tx_flags & 433615516c77SSepherosa Ziehau HN_TX_FLAG_ATTACHED) == 0, 433715516c77SSepherosa Ziehau ("%dth TX ring is still attached", i)); 433815516c77SSepherosa Ziehau } 433915516c77SSepherosa Ziehau #endif 434015516c77SSepherosa Ziehau } 434115516c77SSepherosa Ziehau 434215516c77SSepherosa Ziehau static int 434315516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch) 434415516c77SSepherosa Ziehau { 434515516c77SSepherosa Ziehau struct vmbus_channel **subchans; 434615516c77SSepherosa Ziehau int nchan, rxr_cnt, error; 434715516c77SSepherosa Ziehau 434815516c77SSepherosa Ziehau nchan = *nsubch + 1; 434915516c77SSepherosa Ziehau if (nchan == 1) { 435015516c77SSepherosa Ziehau /* 435115516c77SSepherosa Ziehau * Multiple RX/TX rings are not requested. 435215516c77SSepherosa Ziehau */ 435315516c77SSepherosa Ziehau *nsubch = 0; 435415516c77SSepherosa Ziehau return (0); 435515516c77SSepherosa Ziehau } 435615516c77SSepherosa Ziehau 435715516c77SSepherosa Ziehau /* 435815516c77SSepherosa Ziehau * Query RSS capabilities, e.g. # of RX rings, and # of indirect 435915516c77SSepherosa Ziehau * table entries. 436015516c77SSepherosa Ziehau */ 436115516c77SSepherosa Ziehau error = hn_rndis_query_rsscaps(sc, &rxr_cnt); 436215516c77SSepherosa Ziehau if (error) { 436315516c77SSepherosa Ziehau /* No RSS; this is benign. */ 436415516c77SSepherosa Ziehau *nsubch = 0; 436515516c77SSepherosa Ziehau return (0); 436615516c77SSepherosa Ziehau } 436715516c77SSepherosa Ziehau if (bootverbose) { 436815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n", 436915516c77SSepherosa Ziehau rxr_cnt, nchan); 437015516c77SSepherosa Ziehau } 437115516c77SSepherosa Ziehau 437215516c77SSepherosa Ziehau if (nchan > rxr_cnt) 437315516c77SSepherosa Ziehau nchan = rxr_cnt; 437415516c77SSepherosa Ziehau if (nchan == 1) { 437515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n"); 437615516c77SSepherosa Ziehau *nsubch = 0; 437715516c77SSepherosa Ziehau return (0); 437815516c77SSepherosa Ziehau } 437915516c77SSepherosa Ziehau 438015516c77SSepherosa Ziehau /* 438115516c77SSepherosa Ziehau * Allocate sub-channels from NVS. 438215516c77SSepherosa Ziehau */ 438315516c77SSepherosa Ziehau *nsubch = nchan - 1; 438415516c77SSepherosa Ziehau error = hn_nvs_alloc_subchans(sc, nsubch); 438515516c77SSepherosa Ziehau if (error || *nsubch == 0) { 438615516c77SSepherosa Ziehau /* Failed to allocate sub-channels. */ 438715516c77SSepherosa Ziehau *nsubch = 0; 438815516c77SSepherosa Ziehau return (0); 438915516c77SSepherosa Ziehau } 439015516c77SSepherosa Ziehau 439115516c77SSepherosa Ziehau /* 439215516c77SSepherosa Ziehau * Wait for all sub-channels to become ready before moving on. 439315516c77SSepherosa Ziehau */ 439415516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch); 439515516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, *nsubch); 439615516c77SSepherosa Ziehau return (0); 439715516c77SSepherosa Ziehau } 439815516c77SSepherosa Ziehau 43992494d735SSepherosa Ziehau static bool 44002494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc) 44012494d735SSepherosa Ziehau { 44022494d735SSepherosa Ziehau int i; 44032494d735SSepherosa Ziehau 44042494d735SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_ERRORS) 44052494d735SSepherosa Ziehau return (false); 44062494d735SSepherosa Ziehau 44072494d735SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 44082494d735SSepherosa Ziehau const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 44092494d735SSepherosa Ziehau 44102494d735SSepherosa Ziehau if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) 44112494d735SSepherosa Ziehau return (false); 44122494d735SSepherosa Ziehau } 44132494d735SSepherosa Ziehau return (true); 44142494d735SSepherosa Ziehau } 44152494d735SSepherosa Ziehau 441615516c77SSepherosa Ziehau static int 441715516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu) 441815516c77SSepherosa Ziehau { 441915516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 442015516c77SSepherosa Ziehau int error, nsubch, nchan, i; 442115516c77SSepherosa Ziehau uint32_t old_caps; 442215516c77SSepherosa Ziehau 442315516c77SSepherosa Ziehau KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0, 442415516c77SSepherosa Ziehau ("synthetic parts were attached")); 442515516c77SSepherosa Ziehau 44262494d735SSepherosa Ziehau if (!hn_synth_attachable(sc)) 44272494d735SSepherosa Ziehau return (ENXIO); 44282494d735SSepherosa Ziehau 442915516c77SSepherosa Ziehau /* Save capabilities for later verification. */ 443015516c77SSepherosa Ziehau old_caps = sc->hn_caps; 443115516c77SSepherosa Ziehau sc->hn_caps = 0; 443215516c77SSepherosa Ziehau 443315516c77SSepherosa Ziehau /* Clear RSS stuffs. */ 443415516c77SSepherosa Ziehau sc->hn_rss_ind_size = 0; 443515516c77SSepherosa Ziehau sc->hn_rss_hash = 0; 443615516c77SSepherosa Ziehau 443715516c77SSepherosa Ziehau /* 443815516c77SSepherosa Ziehau * Attach the primary channel _before_ attaching NVS and RNDIS. 443915516c77SSepherosa Ziehau */ 444015516c77SSepherosa Ziehau error = hn_chan_attach(sc, sc->hn_prichan); 444115516c77SSepherosa Ziehau if (error) 444215516c77SSepherosa Ziehau return (error); 444315516c77SSepherosa Ziehau 444415516c77SSepherosa Ziehau /* 444515516c77SSepherosa Ziehau * Attach NVS. 444615516c77SSepherosa Ziehau */ 444715516c77SSepherosa Ziehau error = hn_nvs_attach(sc, mtu); 444815516c77SSepherosa Ziehau if (error) 444915516c77SSepherosa Ziehau return (error); 445015516c77SSepherosa Ziehau 445115516c77SSepherosa Ziehau /* 445215516c77SSepherosa Ziehau * Attach RNDIS _after_ NVS is attached. 445315516c77SSepherosa Ziehau */ 445415516c77SSepherosa Ziehau error = hn_rndis_attach(sc, mtu); 445515516c77SSepherosa Ziehau if (error) 445615516c77SSepherosa Ziehau return (error); 445715516c77SSepherosa Ziehau 445815516c77SSepherosa Ziehau /* 445915516c77SSepherosa Ziehau * Make sure capabilities are not changed. 446015516c77SSepherosa Ziehau */ 446115516c77SSepherosa Ziehau if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) { 446215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n", 446315516c77SSepherosa Ziehau old_caps, sc->hn_caps); 446415516c77SSepherosa Ziehau /* Restore old capabilities and abort. */ 446515516c77SSepherosa Ziehau sc->hn_caps = old_caps; 446615516c77SSepherosa Ziehau return ENXIO; 446715516c77SSepherosa Ziehau } 446815516c77SSepherosa Ziehau 446915516c77SSepherosa Ziehau /* 447015516c77SSepherosa Ziehau * Allocate sub-channels for multi-TX/RX rings. 447115516c77SSepherosa Ziehau * 447215516c77SSepherosa Ziehau * NOTE: 447315516c77SSepherosa Ziehau * The # of RX rings that can be used is equivalent to the # of 447415516c77SSepherosa Ziehau * channels to be requested. 447515516c77SSepherosa Ziehau */ 447615516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_cnt - 1; 447715516c77SSepherosa Ziehau error = hn_synth_alloc_subchans(sc, &nsubch); 447815516c77SSepherosa Ziehau if (error) 447915516c77SSepherosa Ziehau return (error); 448015516c77SSepherosa Ziehau 448115516c77SSepherosa Ziehau nchan = nsubch + 1; 448215516c77SSepherosa Ziehau if (nchan == 1) { 448315516c77SSepherosa Ziehau /* Only the primary channel can be used; done */ 448415516c77SSepherosa Ziehau goto back; 448515516c77SSepherosa Ziehau } 448615516c77SSepherosa Ziehau 448715516c77SSepherosa Ziehau /* 448815516c77SSepherosa Ziehau * Configure RSS key and indirect table _after_ all sub-channels 448915516c77SSepherosa Ziehau * are allocated. 449015516c77SSepherosa Ziehau */ 449115516c77SSepherosa Ziehau 449215516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) { 449315516c77SSepherosa Ziehau /* 449415516c77SSepherosa Ziehau * RSS key is not set yet; set it to the default RSS key. 449515516c77SSepherosa Ziehau */ 449615516c77SSepherosa Ziehau if (bootverbose) 449715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS key\n"); 449815516c77SSepherosa Ziehau memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key)); 449915516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 450015516c77SSepherosa Ziehau } 450115516c77SSepherosa Ziehau 450215516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) { 450315516c77SSepherosa Ziehau /* 450415516c77SSepherosa Ziehau * RSS indirect table is not set yet; set it up in round- 450515516c77SSepherosa Ziehau * robin fashion. 450615516c77SSepherosa Ziehau */ 450715516c77SSepherosa Ziehau if (bootverbose) { 450815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS indirect " 450915516c77SSepherosa Ziehau "table\n"); 451015516c77SSepherosa Ziehau } 451115516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) 451215516c77SSepherosa Ziehau rss->rss_ind[i] = i % nchan; 451315516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 451415516c77SSepherosa Ziehau } else { 451515516c77SSepherosa Ziehau /* 451615516c77SSepherosa Ziehau * # of usable channels may be changed, so we have to 451715516c77SSepherosa Ziehau * make sure that all entries in RSS indirect table 451815516c77SSepherosa Ziehau * are valid. 451915516c77SSepherosa Ziehau */ 452015516c77SSepherosa Ziehau hn_rss_ind_fixup(sc, nchan); 452115516c77SSepherosa Ziehau } 452215516c77SSepherosa Ziehau 452315516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 452415516c77SSepherosa Ziehau if (error) { 452515516c77SSepherosa Ziehau /* 452615516c77SSepherosa Ziehau * Failed to configure RSS key or indirect table; only 452715516c77SSepherosa Ziehau * the primary channel can be used. 452815516c77SSepherosa Ziehau */ 452915516c77SSepherosa Ziehau nchan = 1; 453015516c77SSepherosa Ziehau } 453115516c77SSepherosa Ziehau back: 453215516c77SSepherosa Ziehau /* 453315516c77SSepherosa Ziehau * Set the # of TX/RX rings that could be used according to 453415516c77SSepherosa Ziehau * the # of channels that NVS offered. 453515516c77SSepherosa Ziehau */ 453615516c77SSepherosa Ziehau hn_set_ring_inuse(sc, nchan); 453715516c77SSepherosa Ziehau 453815516c77SSepherosa Ziehau /* 453915516c77SSepherosa Ziehau * Attach the sub-channels, if any. 454015516c77SSepherosa Ziehau */ 454115516c77SSepherosa Ziehau error = hn_attach_subchans(sc); 454215516c77SSepherosa Ziehau if (error) 454315516c77SSepherosa Ziehau return (error); 454415516c77SSepherosa Ziehau 4545dc13fee6SSepherosa Ziehau /* 4546dc13fee6SSepherosa Ziehau * Fixup transmission aggregation setup. 4547dc13fee6SSepherosa Ziehau */ 4548dc13fee6SSepherosa Ziehau hn_set_txagg(sc); 4549dc13fee6SSepherosa Ziehau 455015516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED; 455115516c77SSepherosa Ziehau return (0); 455215516c77SSepherosa Ziehau } 455315516c77SSepherosa Ziehau 455415516c77SSepherosa Ziehau /* 455515516c77SSepherosa Ziehau * NOTE: 455615516c77SSepherosa Ziehau * The interface must have been suspended though hn_suspend(), before 455715516c77SSepherosa Ziehau * this function get called. 455815516c77SSepherosa Ziehau */ 455915516c77SSepherosa Ziehau static void 456015516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc) 456115516c77SSepherosa Ziehau { 456215516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 456315516c77SSepherosa Ziehau 456415516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 456515516c77SSepherosa Ziehau ("synthetic parts were not attached")); 456615516c77SSepherosa Ziehau 456715516c77SSepherosa Ziehau /* Detach the RNDIS first. */ 456815516c77SSepherosa Ziehau hn_rndis_detach(sc); 456915516c77SSepherosa Ziehau 457015516c77SSepherosa Ziehau /* Detach NVS. */ 457115516c77SSepherosa Ziehau hn_nvs_detach(sc); 457215516c77SSepherosa Ziehau 457315516c77SSepherosa Ziehau /* Detach all of the channels. */ 457415516c77SSepherosa Ziehau hn_detach_allchans(sc); 457515516c77SSepherosa Ziehau 457615516c77SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED; 457715516c77SSepherosa Ziehau } 457815516c77SSepherosa Ziehau 457915516c77SSepherosa Ziehau static void 458015516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt) 458115516c77SSepherosa Ziehau { 458215516c77SSepherosa Ziehau KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt, 458315516c77SSepherosa Ziehau ("invalid ring count %d", ring_cnt)); 458415516c77SSepherosa Ziehau 458515516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt > ring_cnt) 458615516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = ring_cnt; 458715516c77SSepherosa Ziehau else 458815516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 458915516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = ring_cnt; 459015516c77SSepherosa Ziehau 459115516c77SSepherosa Ziehau if (bootverbose) { 459215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n", 459315516c77SSepherosa Ziehau sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse); 459415516c77SSepherosa Ziehau } 459515516c77SSepherosa Ziehau } 459615516c77SSepherosa Ziehau 459715516c77SSepherosa Ziehau static void 459825641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan) 459915516c77SSepherosa Ziehau { 460015516c77SSepherosa Ziehau 460125641fc7SSepherosa Ziehau /* 460225641fc7SSepherosa Ziehau * NOTE: 460325641fc7SSepherosa Ziehau * The TX bufring will not be drained by the hypervisor, 460425641fc7SSepherosa Ziehau * if the primary channel is revoked. 460525641fc7SSepherosa Ziehau */ 460625641fc7SSepherosa Ziehau while (!vmbus_chan_rx_empty(chan) || 460725641fc7SSepherosa Ziehau (!vmbus_chan_is_revoked(sc->hn_prichan) && 460825641fc7SSepherosa Ziehau !vmbus_chan_tx_empty(chan))) 460915516c77SSepherosa Ziehau pause("waitch", 1); 461015516c77SSepherosa Ziehau vmbus_chan_intr_drain(chan); 461115516c77SSepherosa Ziehau } 461215516c77SSepherosa Ziehau 461315516c77SSepherosa Ziehau static void 461415516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc) 461515516c77SSepherosa Ziehau { 461615516c77SSepherosa Ziehau struct vmbus_channel **subch = NULL; 461725641fc7SSepherosa Ziehau struct hn_tx_ring *txr; 461815516c77SSepherosa Ziehau int i, nsubch; 461915516c77SSepherosa Ziehau 462015516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 462115516c77SSepherosa Ziehau 462215516c77SSepherosa Ziehau /* 462315516c77SSepherosa Ziehau * Suspend TX. 462415516c77SSepherosa Ziehau */ 462515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 462625641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 462715516c77SSepherosa Ziehau 462815516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 462915516c77SSepherosa Ziehau txr->hn_suspended = 1; 463015516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 463115516c77SSepherosa Ziehau /* No one is able send more packets now. */ 463215516c77SSepherosa Ziehau 463325641fc7SSepherosa Ziehau /* 463425641fc7SSepherosa Ziehau * Wait for all pending sends to finish. 463525641fc7SSepherosa Ziehau * 463625641fc7SSepherosa Ziehau * NOTE: 463725641fc7SSepherosa Ziehau * We will _not_ receive all pending send-done, if the 463825641fc7SSepherosa Ziehau * primary channel is revoked. 463925641fc7SSepherosa Ziehau */ 464025641fc7SSepherosa Ziehau while (hn_tx_ring_pending(txr) && 464125641fc7SSepherosa Ziehau !vmbus_chan_is_revoked(sc->hn_prichan)) 464215516c77SSepherosa Ziehau pause("hnwtx", 1 /* 1 tick */); 464315516c77SSepherosa Ziehau } 464415516c77SSepherosa Ziehau 464515516c77SSepherosa Ziehau /* 464615516c77SSepherosa Ziehau * Disable RX by clearing RX filter. 464715516c77SSepherosa Ziehau */ 464815516c77SSepherosa Ziehau sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE; 464915516c77SSepherosa Ziehau hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); 465015516c77SSepherosa Ziehau 465115516c77SSepherosa Ziehau /* 465215516c77SSepherosa Ziehau * Give RNDIS enough time to flush all pending data packets. 465315516c77SSepherosa Ziehau */ 465415516c77SSepherosa Ziehau pause("waitrx", (200 * hz) / 1000); 465515516c77SSepherosa Ziehau 465615516c77SSepherosa Ziehau /* 465715516c77SSepherosa Ziehau * Drain RX/TX bufrings and interrupts. 465815516c77SSepherosa Ziehau */ 465915516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_inuse - 1; 466015516c77SSepherosa Ziehau if (nsubch > 0) 466115516c77SSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 466215516c77SSepherosa Ziehau 466315516c77SSepherosa Ziehau if (subch != NULL) { 466415516c77SSepherosa Ziehau for (i = 0; i < nsubch; ++i) 466525641fc7SSepherosa Ziehau hn_chan_drain(sc, subch[i]); 466615516c77SSepherosa Ziehau } 466725641fc7SSepherosa Ziehau hn_chan_drain(sc, sc->hn_prichan); 466815516c77SSepherosa Ziehau 466915516c77SSepherosa Ziehau if (subch != NULL) 467015516c77SSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 467125641fc7SSepherosa Ziehau 467225641fc7SSepherosa Ziehau /* 467325641fc7SSepherosa Ziehau * Drain any pending TX tasks. 467425641fc7SSepherosa Ziehau * 467525641fc7SSepherosa Ziehau * NOTE: 467625641fc7SSepherosa Ziehau * The above hn_chan_drain() can dispatch TX tasks, so the TX 467725641fc7SSepherosa Ziehau * tasks will have to be drained _after_ the above hn_chan_drain() 467825641fc7SSepherosa Ziehau * calls. 467925641fc7SSepherosa Ziehau */ 468025641fc7SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 468125641fc7SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 468225641fc7SSepherosa Ziehau 468325641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task); 468425641fc7SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task); 468525641fc7SSepherosa Ziehau } 468615516c77SSepherosa Ziehau } 468715516c77SSepherosa Ziehau 468815516c77SSepherosa Ziehau static void 468915516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused) 469015516c77SSepherosa Ziehau { 469115516c77SSepherosa Ziehau 469215516c77SSepherosa Ziehau ((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL; 469315516c77SSepherosa Ziehau } 469415516c77SSepherosa Ziehau 469515516c77SSepherosa Ziehau static void 469615516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc) 469715516c77SSepherosa Ziehau { 469815516c77SSepherosa Ziehau struct task task; 469915516c77SSepherosa Ziehau 470015516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 470115516c77SSepherosa Ziehau 470215516c77SSepherosa Ziehau /* 470315516c77SSepherosa Ziehau * Make sure that hn_mgmt_taskq0 can nolonger be accessed 470415516c77SSepherosa Ziehau * through hn_mgmt_taskq. 470515516c77SSepherosa Ziehau */ 470615516c77SSepherosa Ziehau TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc); 470715516c77SSepherosa Ziehau vmbus_chan_run_task(sc->hn_prichan, &task); 470815516c77SSepherosa Ziehau 470915516c77SSepherosa Ziehau /* 471015516c77SSepherosa Ziehau * Make sure that all pending management tasks are completed. 471115516c77SSepherosa Ziehau */ 471215516c77SSepherosa Ziehau taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init); 471315516c77SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status); 471415516c77SSepherosa Ziehau taskqueue_drain_all(sc->hn_mgmt_taskq0); 471515516c77SSepherosa Ziehau } 471615516c77SSepherosa Ziehau 471715516c77SSepherosa Ziehau static void 471815516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc) 471915516c77SSepherosa Ziehau { 472015516c77SSepherosa Ziehau 472115516c77SSepherosa Ziehau if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 472215516c77SSepherosa Ziehau hn_suspend_data(sc); 472315516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 472415516c77SSepherosa Ziehau } 472515516c77SSepherosa Ziehau 472615516c77SSepherosa Ziehau static void 472715516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt) 472815516c77SSepherosa Ziehau { 472915516c77SSepherosa Ziehau int i; 473015516c77SSepherosa Ziehau 473115516c77SSepherosa Ziehau KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt, 473215516c77SSepherosa Ziehau ("invalid TX ring count %d", tx_ring_cnt)); 473315516c77SSepherosa Ziehau 473415516c77SSepherosa Ziehau for (i = 0; i < tx_ring_cnt; ++i) { 473515516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 473615516c77SSepherosa Ziehau 473715516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 473815516c77SSepherosa Ziehau txr->hn_suspended = 0; 473915516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 474015516c77SSepherosa Ziehau } 474115516c77SSepherosa Ziehau } 474215516c77SSepherosa Ziehau 474315516c77SSepherosa Ziehau static void 474415516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc) 474515516c77SSepherosa Ziehau { 474615516c77SSepherosa Ziehau int i; 474715516c77SSepherosa Ziehau 474815516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 474915516c77SSepherosa Ziehau 475015516c77SSepherosa Ziehau /* 475115516c77SSepherosa Ziehau * Re-enable RX. 475215516c77SSepherosa Ziehau */ 475315516c77SSepherosa Ziehau hn_set_rxfilter(sc); 475415516c77SSepherosa Ziehau 475515516c77SSepherosa Ziehau /* 475615516c77SSepherosa Ziehau * Make sure to clear suspend status on "all" TX rings, 475715516c77SSepherosa Ziehau * since hn_tx_ring_inuse can be changed after 475815516c77SSepherosa Ziehau * hn_suspend_data(). 475915516c77SSepherosa Ziehau */ 476015516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_cnt); 476115516c77SSepherosa Ziehau 476223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 476323bf9e15SSepherosa Ziehau if (!hn_use_if_start) 476423bf9e15SSepherosa Ziehau #endif 476523bf9e15SSepherosa Ziehau { 476615516c77SSepherosa Ziehau /* 476715516c77SSepherosa Ziehau * Flush unused drbrs, since hn_tx_ring_inuse may be 476815516c77SSepherosa Ziehau * reduced. 476915516c77SSepherosa Ziehau */ 477015516c77SSepherosa Ziehau for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i) 477115516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 477215516c77SSepherosa Ziehau } 477315516c77SSepherosa Ziehau 477415516c77SSepherosa Ziehau /* 477515516c77SSepherosa Ziehau * Kick start TX. 477615516c77SSepherosa Ziehau */ 477715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 477815516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 477915516c77SSepherosa Ziehau 478015516c77SSepherosa Ziehau /* 478115516c77SSepherosa Ziehau * Use txeof task, so that any pending oactive can be 478215516c77SSepherosa Ziehau * cleared properly. 478315516c77SSepherosa Ziehau */ 478415516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 478515516c77SSepherosa Ziehau } 478615516c77SSepherosa Ziehau } 478715516c77SSepherosa Ziehau 478815516c77SSepherosa Ziehau static void 478915516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc) 479015516c77SSepherosa Ziehau { 479115516c77SSepherosa Ziehau 479215516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 479315516c77SSepherosa Ziehau 479415516c77SSepherosa Ziehau /* 479515516c77SSepherosa Ziehau * Kick off network change detection, if it was pending. 479615516c77SSepherosa Ziehau * If no network change was pending, start link status 479715516c77SSepherosa Ziehau * checks, which is more lightweight than network change 479815516c77SSepherosa Ziehau * detection. 479915516c77SSepherosa Ziehau */ 480015516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 480115516c77SSepherosa Ziehau hn_change_network(sc); 480215516c77SSepherosa Ziehau else 480315516c77SSepherosa Ziehau hn_update_link_status(sc); 480415516c77SSepherosa Ziehau } 480515516c77SSepherosa Ziehau 480615516c77SSepherosa Ziehau static void 480715516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc) 480815516c77SSepherosa Ziehau { 480915516c77SSepherosa Ziehau 481015516c77SSepherosa Ziehau if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 481115516c77SSepherosa Ziehau hn_resume_data(sc); 481215516c77SSepherosa Ziehau hn_resume_mgmt(sc); 481315516c77SSepherosa Ziehau } 481415516c77SSepherosa Ziehau 481515516c77SSepherosa Ziehau static void 481615516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen) 481715516c77SSepherosa Ziehau { 481815516c77SSepherosa Ziehau const struct rndis_status_msg *msg; 481915516c77SSepherosa Ziehau int ofs; 482015516c77SSepherosa Ziehau 482115516c77SSepherosa Ziehau if (dlen < sizeof(*msg)) { 482215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid RNDIS status\n"); 482315516c77SSepherosa Ziehau return; 482415516c77SSepherosa Ziehau } 482515516c77SSepherosa Ziehau msg = data; 482615516c77SSepherosa Ziehau 482715516c77SSepherosa Ziehau switch (msg->rm_status) { 482815516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_CONNECT: 482915516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_DISCONNECT: 483015516c77SSepherosa Ziehau hn_update_link_status(sc); 483115516c77SSepherosa Ziehau break; 483215516c77SSepherosa Ziehau 483315516c77SSepherosa Ziehau case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: 483415516c77SSepherosa Ziehau /* Not really useful; ignore. */ 483515516c77SSepherosa Ziehau break; 483615516c77SSepherosa Ziehau 483715516c77SSepherosa Ziehau case RNDIS_STATUS_NETWORK_CHANGE: 483815516c77SSepherosa Ziehau ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset); 483915516c77SSepherosa Ziehau if (dlen < ofs + msg->rm_stbuflen || 484015516c77SSepherosa Ziehau msg->rm_stbuflen < sizeof(uint32_t)) { 484115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed\n"); 484215516c77SSepherosa Ziehau } else { 484315516c77SSepherosa Ziehau uint32_t change; 484415516c77SSepherosa Ziehau 484515516c77SSepherosa Ziehau memcpy(&change, ((const uint8_t *)msg) + ofs, 484615516c77SSepherosa Ziehau sizeof(change)); 484715516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed, change %u\n", 484815516c77SSepherosa Ziehau change); 484915516c77SSepherosa Ziehau } 485015516c77SSepherosa Ziehau hn_change_network(sc); 485115516c77SSepherosa Ziehau break; 485215516c77SSepherosa Ziehau 485315516c77SSepherosa Ziehau default: 485415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n", 485515516c77SSepherosa Ziehau msg->rm_status); 485615516c77SSepherosa Ziehau break; 485715516c77SSepherosa Ziehau } 485815516c77SSepherosa Ziehau } 485915516c77SSepherosa Ziehau 486015516c77SSepherosa Ziehau static int 486115516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info) 486215516c77SSepherosa Ziehau { 486315516c77SSepherosa Ziehau const struct rndis_pktinfo *pi = info_data; 486415516c77SSepherosa Ziehau uint32_t mask = 0; 486515516c77SSepherosa Ziehau 486615516c77SSepherosa Ziehau while (info_dlen != 0) { 486715516c77SSepherosa Ziehau const void *data; 486815516c77SSepherosa Ziehau uint32_t dlen; 486915516c77SSepherosa Ziehau 487015516c77SSepherosa Ziehau if (__predict_false(info_dlen < sizeof(*pi))) 487115516c77SSepherosa Ziehau return (EINVAL); 487215516c77SSepherosa Ziehau if (__predict_false(info_dlen < pi->rm_size)) 487315516c77SSepherosa Ziehau return (EINVAL); 487415516c77SSepherosa Ziehau info_dlen -= pi->rm_size; 487515516c77SSepherosa Ziehau 487615516c77SSepherosa Ziehau if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK)) 487715516c77SSepherosa Ziehau return (EINVAL); 487815516c77SSepherosa Ziehau if (__predict_false(pi->rm_size < pi->rm_pktinfooffset)) 487915516c77SSepherosa Ziehau return (EINVAL); 488015516c77SSepherosa Ziehau dlen = pi->rm_size - pi->rm_pktinfooffset; 488115516c77SSepherosa Ziehau data = pi->rm_data; 488215516c77SSepherosa Ziehau 488315516c77SSepherosa Ziehau switch (pi->rm_type) { 488415516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_VLAN: 488515516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE)) 488615516c77SSepherosa Ziehau return (EINVAL); 488715516c77SSepherosa Ziehau info->vlan_info = *((const uint32_t *)data); 488815516c77SSepherosa Ziehau mask |= HN_RXINFO_VLAN; 488915516c77SSepherosa Ziehau break; 489015516c77SSepherosa Ziehau 489115516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_CSUM: 489215516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE)) 489315516c77SSepherosa Ziehau return (EINVAL); 489415516c77SSepherosa Ziehau info->csum_info = *((const uint32_t *)data); 489515516c77SSepherosa Ziehau mask |= HN_RXINFO_CSUM; 489615516c77SSepherosa Ziehau break; 489715516c77SSepherosa Ziehau 489815516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHVAL: 489915516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE)) 490015516c77SSepherosa Ziehau return (EINVAL); 490115516c77SSepherosa Ziehau info->hash_value = *((const uint32_t *)data); 490215516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHVAL; 490315516c77SSepherosa Ziehau break; 490415516c77SSepherosa Ziehau 490515516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHINF: 490615516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE)) 490715516c77SSepherosa Ziehau return (EINVAL); 490815516c77SSepherosa Ziehau info->hash_info = *((const uint32_t *)data); 490915516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHINF; 491015516c77SSepherosa Ziehau break; 491115516c77SSepherosa Ziehau 491215516c77SSepherosa Ziehau default: 491315516c77SSepherosa Ziehau goto next; 491415516c77SSepherosa Ziehau } 491515516c77SSepherosa Ziehau 491615516c77SSepherosa Ziehau if (mask == HN_RXINFO_ALL) { 491715516c77SSepherosa Ziehau /* All found; done */ 491815516c77SSepherosa Ziehau break; 491915516c77SSepherosa Ziehau } 492015516c77SSepherosa Ziehau next: 492115516c77SSepherosa Ziehau pi = (const struct rndis_pktinfo *) 492215516c77SSepherosa Ziehau ((const uint8_t *)pi + pi->rm_size); 492315516c77SSepherosa Ziehau } 492415516c77SSepherosa Ziehau 492515516c77SSepherosa Ziehau /* 492615516c77SSepherosa Ziehau * Final fixup. 492715516c77SSepherosa Ziehau * - If there is no hash value, invalidate the hash info. 492815516c77SSepherosa Ziehau */ 492915516c77SSepherosa Ziehau if ((mask & HN_RXINFO_HASHVAL) == 0) 493015516c77SSepherosa Ziehau info->hash_info = HN_NDIS_HASH_INFO_INVALID; 493115516c77SSepherosa Ziehau return (0); 493215516c77SSepherosa Ziehau } 493315516c77SSepherosa Ziehau 493415516c77SSepherosa Ziehau static __inline bool 493515516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len) 493615516c77SSepherosa Ziehau { 493715516c77SSepherosa Ziehau 493815516c77SSepherosa Ziehau if (off < check_off) { 493915516c77SSepherosa Ziehau if (__predict_true(off + len <= check_off)) 494015516c77SSepherosa Ziehau return (false); 494115516c77SSepherosa Ziehau } else if (off > check_off) { 494215516c77SSepherosa Ziehau if (__predict_true(check_off + check_len <= off)) 494315516c77SSepherosa Ziehau return (false); 494415516c77SSepherosa Ziehau } 494515516c77SSepherosa Ziehau return (true); 494615516c77SSepherosa Ziehau } 494715516c77SSepherosa Ziehau 494815516c77SSepherosa Ziehau static void 494915516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen) 495015516c77SSepherosa Ziehau { 495115516c77SSepherosa Ziehau const struct rndis_packet_msg *pkt; 495215516c77SSepherosa Ziehau struct hn_rxinfo info; 495315516c77SSepherosa Ziehau int data_off, pktinfo_off, data_len, pktinfo_len; 495415516c77SSepherosa Ziehau 495515516c77SSepherosa Ziehau /* 495615516c77SSepherosa Ziehau * Check length. 495715516c77SSepherosa Ziehau */ 495815516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*pkt))) { 495915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n"); 496015516c77SSepherosa Ziehau return; 496115516c77SSepherosa Ziehau } 496215516c77SSepherosa Ziehau pkt = data; 496315516c77SSepherosa Ziehau 496415516c77SSepherosa Ziehau if (__predict_false(dlen < pkt->rm_len)) { 496515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, " 496615516c77SSepherosa Ziehau "dlen %d, msglen %u\n", dlen, pkt->rm_len); 496715516c77SSepherosa Ziehau return; 496815516c77SSepherosa Ziehau } 496915516c77SSepherosa Ziehau if (__predict_false(pkt->rm_len < 497015516c77SSepherosa Ziehau pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) { 497115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, " 497215516c77SSepherosa Ziehau "msglen %u, data %u, oob %u, pktinfo %u\n", 497315516c77SSepherosa Ziehau pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen, 497415516c77SSepherosa Ziehau pkt->rm_pktinfolen); 497515516c77SSepherosa Ziehau return; 497615516c77SSepherosa Ziehau } 497715516c77SSepherosa Ziehau if (__predict_false(pkt->rm_datalen == 0)) { 497815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n"); 497915516c77SSepherosa Ziehau return; 498015516c77SSepherosa Ziehau } 498115516c77SSepherosa Ziehau 498215516c77SSepherosa Ziehau /* 498315516c77SSepherosa Ziehau * Check offests. 498415516c77SSepherosa Ziehau */ 498515516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs) \ 498615516c77SSepherosa Ziehau ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \ 498715516c77SSepherosa Ziehau ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK)) 498815516c77SSepherosa Ziehau 498915516c77SSepherosa Ziehau /* XXX Hyper-V does not meet data offset alignment requirement */ 499015516c77SSepherosa Ziehau if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) { 499115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 499215516c77SSepherosa Ziehau "data offset %u\n", pkt->rm_dataoffset); 499315516c77SSepherosa Ziehau return; 499415516c77SSepherosa Ziehau } 499515516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdataoffset > 0 && 499615516c77SSepherosa Ziehau IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) { 499715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 499815516c77SSepherosa Ziehau "oob offset %u\n", pkt->rm_oobdataoffset); 499915516c77SSepherosa Ziehau return; 500015516c77SSepherosa Ziehau } 500115516c77SSepherosa Ziehau if (__predict_true(pkt->rm_pktinfooffset > 0) && 500215516c77SSepherosa Ziehau __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) { 500315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 500415516c77SSepherosa Ziehau "pktinfo offset %u\n", pkt->rm_pktinfooffset); 500515516c77SSepherosa Ziehau return; 500615516c77SSepherosa Ziehau } 500715516c77SSepherosa Ziehau 500815516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID 500915516c77SSepherosa Ziehau 501015516c77SSepherosa Ziehau data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset); 501115516c77SSepherosa Ziehau data_len = pkt->rm_datalen; 501215516c77SSepherosa Ziehau pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset); 501315516c77SSepherosa Ziehau pktinfo_len = pkt->rm_pktinfolen; 501415516c77SSepherosa Ziehau 501515516c77SSepherosa Ziehau /* 501615516c77SSepherosa Ziehau * Check OOB coverage. 501715516c77SSepherosa Ziehau */ 501815516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdatalen != 0)) { 501915516c77SSepherosa Ziehau int oob_off, oob_len; 502015516c77SSepherosa Ziehau 502115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "got oobdata\n"); 502215516c77SSepherosa Ziehau oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset); 502315516c77SSepherosa Ziehau oob_len = pkt->rm_oobdatalen; 502415516c77SSepherosa Ziehau 502515516c77SSepherosa Ziehau if (__predict_false(oob_off + oob_len > pkt->rm_len)) { 502615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 502715516c77SSepherosa Ziehau "oob overflow, msglen %u, oob abs %d len %d\n", 502815516c77SSepherosa Ziehau pkt->rm_len, oob_off, oob_len); 502915516c77SSepherosa Ziehau return; 503015516c77SSepherosa Ziehau } 503115516c77SSepherosa Ziehau 503215516c77SSepherosa Ziehau /* 503315516c77SSepherosa Ziehau * Check against data. 503415516c77SSepherosa Ziehau */ 503515516c77SSepherosa Ziehau if (hn_rndis_check_overlap(oob_off, oob_len, 503615516c77SSepherosa Ziehau data_off, data_len)) { 503715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 503815516c77SSepherosa Ziehau "oob overlaps data, oob abs %d len %d, " 503915516c77SSepherosa Ziehau "data abs %d len %d\n", 504015516c77SSepherosa Ziehau oob_off, oob_len, data_off, data_len); 504115516c77SSepherosa Ziehau return; 504215516c77SSepherosa Ziehau } 504315516c77SSepherosa Ziehau 504415516c77SSepherosa Ziehau /* 504515516c77SSepherosa Ziehau * Check against pktinfo. 504615516c77SSepherosa Ziehau */ 504715516c77SSepherosa Ziehau if (pktinfo_len != 0 && 504815516c77SSepherosa Ziehau hn_rndis_check_overlap(oob_off, oob_len, 504915516c77SSepherosa Ziehau pktinfo_off, pktinfo_len)) { 505015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 505115516c77SSepherosa Ziehau "oob overlaps pktinfo, oob abs %d len %d, " 505215516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 505315516c77SSepherosa Ziehau oob_off, oob_len, pktinfo_off, pktinfo_len); 505415516c77SSepherosa Ziehau return; 505515516c77SSepherosa Ziehau } 505615516c77SSepherosa Ziehau } 505715516c77SSepherosa Ziehau 505815516c77SSepherosa Ziehau /* 505915516c77SSepherosa Ziehau * Check per-packet-info coverage and find useful per-packet-info. 506015516c77SSepherosa Ziehau */ 506115516c77SSepherosa Ziehau info.vlan_info = HN_NDIS_VLAN_INFO_INVALID; 506215516c77SSepherosa Ziehau info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID; 506315516c77SSepherosa Ziehau info.hash_info = HN_NDIS_HASH_INFO_INVALID; 506415516c77SSepherosa Ziehau if (__predict_true(pktinfo_len != 0)) { 506515516c77SSepherosa Ziehau bool overlap; 506615516c77SSepherosa Ziehau int error; 506715516c77SSepherosa Ziehau 506815516c77SSepherosa Ziehau if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) { 506915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 507015516c77SSepherosa Ziehau "pktinfo overflow, msglen %u, " 507115516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 507215516c77SSepherosa Ziehau pkt->rm_len, pktinfo_off, pktinfo_len); 507315516c77SSepherosa Ziehau return; 507415516c77SSepherosa Ziehau } 507515516c77SSepherosa Ziehau 507615516c77SSepherosa Ziehau /* 507715516c77SSepherosa Ziehau * Check packet info coverage. 507815516c77SSepherosa Ziehau */ 507915516c77SSepherosa Ziehau overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len, 508015516c77SSepherosa Ziehau data_off, data_len); 508115516c77SSepherosa Ziehau if (__predict_false(overlap)) { 508215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 508315516c77SSepherosa Ziehau "pktinfo overlap data, pktinfo abs %d len %d, " 508415516c77SSepherosa Ziehau "data abs %d len %d\n", 508515516c77SSepherosa Ziehau pktinfo_off, pktinfo_len, data_off, data_len); 508615516c77SSepherosa Ziehau return; 508715516c77SSepherosa Ziehau } 508815516c77SSepherosa Ziehau 508915516c77SSepherosa Ziehau /* 509015516c77SSepherosa Ziehau * Find useful per-packet-info. 509115516c77SSepherosa Ziehau */ 509215516c77SSepherosa Ziehau error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off, 509315516c77SSepherosa Ziehau pktinfo_len, &info); 509415516c77SSepherosa Ziehau if (__predict_false(error)) { 509515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg " 509615516c77SSepherosa Ziehau "pktinfo\n"); 509715516c77SSepherosa Ziehau return; 509815516c77SSepherosa Ziehau } 509915516c77SSepherosa Ziehau } 510015516c77SSepherosa Ziehau 510115516c77SSepherosa Ziehau if (__predict_false(data_off + data_len > pkt->rm_len)) { 510215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 510315516c77SSepherosa Ziehau "data overflow, msglen %u, data abs %d len %d\n", 510415516c77SSepherosa Ziehau pkt->rm_len, data_off, data_len); 510515516c77SSepherosa Ziehau return; 510615516c77SSepherosa Ziehau } 510715516c77SSepherosa Ziehau hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info); 510815516c77SSepherosa Ziehau } 510915516c77SSepherosa Ziehau 511015516c77SSepherosa Ziehau static __inline void 511115516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen) 511215516c77SSepherosa Ziehau { 511315516c77SSepherosa Ziehau const struct rndis_msghdr *hdr; 511415516c77SSepherosa Ziehau 511515516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*hdr))) { 511615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS msg\n"); 511715516c77SSepherosa Ziehau return; 511815516c77SSepherosa Ziehau } 511915516c77SSepherosa Ziehau hdr = data; 512015516c77SSepherosa Ziehau 512115516c77SSepherosa Ziehau if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) { 512215516c77SSepherosa Ziehau /* Hot data path. */ 512315516c77SSepherosa Ziehau hn_rndis_rx_data(rxr, data, dlen); 512415516c77SSepherosa Ziehau /* Done! */ 512515516c77SSepherosa Ziehau return; 512615516c77SSepherosa Ziehau } 512715516c77SSepherosa Ziehau 512815516c77SSepherosa Ziehau if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG) 512915516c77SSepherosa Ziehau hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen); 513015516c77SSepherosa Ziehau else 513115516c77SSepherosa Ziehau hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen); 513215516c77SSepherosa Ziehau } 513315516c77SSepherosa Ziehau 513415516c77SSepherosa Ziehau static void 513515516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) 513615516c77SSepherosa Ziehau { 513715516c77SSepherosa Ziehau const struct hn_nvs_hdr *hdr; 513815516c77SSepherosa Ziehau 513915516c77SSepherosa Ziehau if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) { 514015516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid nvs notify\n"); 514115516c77SSepherosa Ziehau return; 514215516c77SSepherosa Ziehau } 514315516c77SSepherosa Ziehau hdr = VMBUS_CHANPKT_CONST_DATA(pkt); 514415516c77SSepherosa Ziehau 514515516c77SSepherosa Ziehau if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) { 514615516c77SSepherosa Ziehau /* Useless; ignore */ 514715516c77SSepherosa Ziehau return; 514815516c77SSepherosa Ziehau } 514915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type); 515015516c77SSepherosa Ziehau } 515115516c77SSepherosa Ziehau 515215516c77SSepherosa Ziehau static void 515315516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan, 515415516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkt) 515515516c77SSepherosa Ziehau { 515615516c77SSepherosa Ziehau struct hn_nvs_sendctx *sndc; 515715516c77SSepherosa Ziehau 515815516c77SSepherosa Ziehau sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid; 515915516c77SSepherosa Ziehau sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt), 516015516c77SSepherosa Ziehau VMBUS_CHANPKT_DATALEN(pkt)); 516115516c77SSepherosa Ziehau /* 516215516c77SSepherosa Ziehau * NOTE: 516315516c77SSepherosa Ziehau * 'sndc' CAN NOT be accessed anymore, since it can be freed by 516415516c77SSepherosa Ziehau * its callback. 516515516c77SSepherosa Ziehau */ 516615516c77SSepherosa Ziehau } 516715516c77SSepherosa Ziehau 516815516c77SSepherosa Ziehau static void 516915516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 517015516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkthdr) 517115516c77SSepherosa Ziehau { 517215516c77SSepherosa Ziehau const struct vmbus_chanpkt_rxbuf *pkt; 517315516c77SSepherosa Ziehau const struct hn_nvs_hdr *nvs_hdr; 517415516c77SSepherosa Ziehau int count, i, hlen; 517515516c77SSepherosa Ziehau 517615516c77SSepherosa Ziehau if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) { 517715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n"); 517815516c77SSepherosa Ziehau return; 517915516c77SSepherosa Ziehau } 518015516c77SSepherosa Ziehau nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr); 518115516c77SSepherosa Ziehau 518215516c77SSepherosa Ziehau /* Make sure that this is a RNDIS message. */ 518315516c77SSepherosa Ziehau if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) { 518415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n", 518515516c77SSepherosa Ziehau nvs_hdr->nvs_type); 518615516c77SSepherosa Ziehau return; 518715516c77SSepherosa Ziehau } 518815516c77SSepherosa Ziehau 518915516c77SSepherosa Ziehau hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen); 519015516c77SSepherosa Ziehau if (__predict_false(hlen < sizeof(*pkt))) { 519115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n"); 519215516c77SSepherosa Ziehau return; 519315516c77SSepherosa Ziehau } 519415516c77SSepherosa Ziehau pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr; 519515516c77SSepherosa Ziehau 519615516c77SSepherosa Ziehau if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) { 519715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n", 519815516c77SSepherosa Ziehau pkt->cp_rxbuf_id); 519915516c77SSepherosa Ziehau return; 520015516c77SSepherosa Ziehau } 520115516c77SSepherosa Ziehau 520215516c77SSepherosa Ziehau count = pkt->cp_rxbuf_cnt; 520315516c77SSepherosa Ziehau if (__predict_false(hlen < 520415516c77SSepherosa Ziehau __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) { 520515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count); 520615516c77SSepherosa Ziehau return; 520715516c77SSepherosa Ziehau } 520815516c77SSepherosa Ziehau 520915516c77SSepherosa Ziehau /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 521015516c77SSepherosa Ziehau for (i = 0; i < count; ++i) { 521115516c77SSepherosa Ziehau int ofs, len; 521215516c77SSepherosa Ziehau 521315516c77SSepherosa Ziehau ofs = pkt->cp_rxbuf[i].rb_ofs; 521415516c77SSepherosa Ziehau len = pkt->cp_rxbuf[i].rb_len; 521515516c77SSepherosa Ziehau if (__predict_false(ofs + len > HN_RXBUF_SIZE)) { 521615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, " 521715516c77SSepherosa Ziehau "ofs %d, len %d\n", i, ofs, len); 521815516c77SSepherosa Ziehau continue; 521915516c77SSepherosa Ziehau } 522015516c77SSepherosa Ziehau hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len); 522115516c77SSepherosa Ziehau } 522215516c77SSepherosa Ziehau 522315516c77SSepherosa Ziehau /* 522415516c77SSepherosa Ziehau * Ack the consumed RXBUF associated w/ this channel packet, 522515516c77SSepherosa Ziehau * so that this RXBUF can be recycled by the hypervisor. 522615516c77SSepherosa Ziehau */ 522715516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid); 522815516c77SSepherosa Ziehau } 522915516c77SSepherosa Ziehau 523015516c77SSepherosa Ziehau static void 523115516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 523215516c77SSepherosa Ziehau uint64_t tid) 523315516c77SSepherosa Ziehau { 523415516c77SSepherosa Ziehau struct hn_nvs_rndis_ack ack; 523515516c77SSepherosa Ziehau int retries, error; 523615516c77SSepherosa Ziehau 523715516c77SSepherosa Ziehau ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK; 523815516c77SSepherosa Ziehau ack.nvs_status = HN_NVS_STATUS_OK; 523915516c77SSepherosa Ziehau 524015516c77SSepherosa Ziehau retries = 0; 524115516c77SSepherosa Ziehau again: 524215516c77SSepherosa Ziehau error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 524315516c77SSepherosa Ziehau VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid); 524415516c77SSepherosa Ziehau if (__predict_false(error == EAGAIN)) { 524515516c77SSepherosa Ziehau /* 524615516c77SSepherosa Ziehau * NOTE: 524715516c77SSepherosa Ziehau * This should _not_ happen in real world, since the 524815516c77SSepherosa Ziehau * consumption of the TX bufring from the TX path is 524915516c77SSepherosa Ziehau * controlled. 525015516c77SSepherosa Ziehau */ 525115516c77SSepherosa Ziehau if (rxr->hn_ack_failed == 0) 525215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack retry\n"); 525315516c77SSepherosa Ziehau rxr->hn_ack_failed++; 525415516c77SSepherosa Ziehau retries++; 525515516c77SSepherosa Ziehau if (retries < 10) { 525615516c77SSepherosa Ziehau DELAY(100); 525715516c77SSepherosa Ziehau goto again; 525815516c77SSepherosa Ziehau } 525915516c77SSepherosa Ziehau /* RXBUF leaks! */ 526015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack failed\n"); 526115516c77SSepherosa Ziehau } 526215516c77SSepherosa Ziehau } 526315516c77SSepherosa Ziehau 526415516c77SSepherosa Ziehau static void 526515516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr) 526615516c77SSepherosa Ziehau { 526715516c77SSepherosa Ziehau struct hn_rx_ring *rxr = xrxr; 526815516c77SSepherosa Ziehau struct hn_softc *sc = rxr->hn_ifp->if_softc; 526915516c77SSepherosa Ziehau 527015516c77SSepherosa Ziehau for (;;) { 527115516c77SSepherosa Ziehau struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf; 527215516c77SSepherosa Ziehau int error, pktlen; 527315516c77SSepherosa Ziehau 527415516c77SSepherosa Ziehau pktlen = rxr->hn_pktbuf_len; 527515516c77SSepherosa Ziehau error = vmbus_chan_recv_pkt(chan, pkt, &pktlen); 527615516c77SSepherosa Ziehau if (__predict_false(error == ENOBUFS)) { 527715516c77SSepherosa Ziehau void *nbuf; 527815516c77SSepherosa Ziehau int nlen; 527915516c77SSepherosa Ziehau 528015516c77SSepherosa Ziehau /* 528115516c77SSepherosa Ziehau * Expand channel packet buffer. 528215516c77SSepherosa Ziehau * 528315516c77SSepherosa Ziehau * XXX 528415516c77SSepherosa Ziehau * Use M_WAITOK here, since allocation failure 528515516c77SSepherosa Ziehau * is fatal. 528615516c77SSepherosa Ziehau */ 528715516c77SSepherosa Ziehau nlen = rxr->hn_pktbuf_len * 2; 528815516c77SSepherosa Ziehau while (nlen < pktlen) 528915516c77SSepherosa Ziehau nlen *= 2; 529015516c77SSepherosa Ziehau nbuf = malloc(nlen, M_DEVBUF, M_WAITOK); 529115516c77SSepherosa Ziehau 529215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n", 529315516c77SSepherosa Ziehau rxr->hn_pktbuf_len, nlen); 529415516c77SSepherosa Ziehau 529515516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 529615516c77SSepherosa Ziehau rxr->hn_pktbuf = nbuf; 529715516c77SSepherosa Ziehau rxr->hn_pktbuf_len = nlen; 529815516c77SSepherosa Ziehau /* Retry! */ 529915516c77SSepherosa Ziehau continue; 530015516c77SSepherosa Ziehau } else if (__predict_false(error == EAGAIN)) { 530115516c77SSepherosa Ziehau /* No more channel packets; done! */ 530215516c77SSepherosa Ziehau break; 530315516c77SSepherosa Ziehau } 530415516c77SSepherosa Ziehau KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error)); 530515516c77SSepherosa Ziehau 530615516c77SSepherosa Ziehau switch (pkt->cph_type) { 530715516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_COMP: 530815516c77SSepherosa Ziehau hn_nvs_handle_comp(sc, chan, pkt); 530915516c77SSepherosa Ziehau break; 531015516c77SSepherosa Ziehau 531115516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_RXBUF: 531215516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(rxr, chan, pkt); 531315516c77SSepherosa Ziehau break; 531415516c77SSepherosa Ziehau 531515516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_INBAND: 531615516c77SSepherosa Ziehau hn_nvs_handle_notify(sc, pkt); 531715516c77SSepherosa Ziehau break; 531815516c77SSepherosa Ziehau 531915516c77SSepherosa Ziehau default: 532015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "unknown chan pkt %u\n", 532115516c77SSepherosa Ziehau pkt->cph_type); 532215516c77SSepherosa Ziehau break; 532315516c77SSepherosa Ziehau } 532415516c77SSepherosa Ziehau } 532515516c77SSepherosa Ziehau hn_chan_rollup(rxr, rxr->hn_txr); 532615516c77SSepherosa Ziehau } 532715516c77SSepherosa Ziehau 532815516c77SSepherosa Ziehau static void 532915516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused) 533015516c77SSepherosa Ziehau { 533115516c77SSepherosa Ziehau 533215516c77SSepherosa Ziehau if (vm_guest != VM_GUEST_HV) 533315516c77SSepherosa Ziehau return; 533415516c77SSepherosa Ziehau 533515516c77SSepherosa Ziehau if (!hn_share_tx_taskq) 533615516c77SSepherosa Ziehau return; 533715516c77SSepherosa Ziehau 533815516c77SSepherosa Ziehau hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK, 533915516c77SSepherosa Ziehau taskqueue_thread_enqueue, &hn_tx_taskq); 534015516c77SSepherosa Ziehau if (hn_bind_tx_taskq >= 0) { 534115516c77SSepherosa Ziehau int cpu = hn_bind_tx_taskq; 534215516c77SSepherosa Ziehau cpuset_t cpu_set; 534315516c77SSepherosa Ziehau 534415516c77SSepherosa Ziehau if (cpu > mp_ncpus - 1) 534515516c77SSepherosa Ziehau cpu = mp_ncpus - 1; 534615516c77SSepherosa Ziehau CPU_SETOF(cpu, &cpu_set); 534715516c77SSepherosa Ziehau taskqueue_start_threads_cpuset(&hn_tx_taskq, 1, PI_NET, 534815516c77SSepherosa Ziehau &cpu_set, "hn tx"); 534915516c77SSepherosa Ziehau } else { 535015516c77SSepherosa Ziehau taskqueue_start_threads(&hn_tx_taskq, 1, PI_NET, "hn tx"); 535115516c77SSepherosa Ziehau } 535215516c77SSepherosa Ziehau } 535315516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND, 535415516c77SSepherosa Ziehau hn_tx_taskq_create, NULL); 535515516c77SSepherosa Ziehau 535615516c77SSepherosa Ziehau static void 535715516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused) 535815516c77SSepherosa Ziehau { 535915516c77SSepherosa Ziehau 536015516c77SSepherosa Ziehau if (hn_tx_taskq != NULL) 536115516c77SSepherosa Ziehau taskqueue_free(hn_tx_taskq); 536215516c77SSepherosa Ziehau } 536315516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND, 536415516c77SSepherosa Ziehau hn_tx_taskq_destroy, NULL); 5365