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) 15215516c77SSepherosa Ziehau #define HN_LOCK(sc) sx_xlock(&(sc)->hn_lock) 15315516c77SSepherosa Ziehau #define HN_UNLOCK(sc) sx_xunlock(&(sc)->hn_lock) 15415516c77SSepherosa Ziehau 15515516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK (CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP) 15615516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK (CSUM_IP6_TCP | CSUM_IP6_UDP) 15715516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc) \ 15815516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK) 15915516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc) \ 16015516c77SSepherosa Ziehau ((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK) 16115516c77SSepherosa Ziehau 16215516c77SSepherosa Ziehau struct hn_txdesc { 16315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 16415516c77SSepherosa Ziehau SLIST_ENTRY(hn_txdesc) link; 16515516c77SSepherosa Ziehau #endif 16615516c77SSepherosa Ziehau struct mbuf *m; 16715516c77SSepherosa Ziehau struct hn_tx_ring *txr; 16815516c77SSepherosa Ziehau int refs; 16915516c77SSepherosa Ziehau uint32_t flags; /* HN_TXD_FLAG_ */ 17015516c77SSepherosa Ziehau struct hn_nvs_sendctx send_ctx; 17115516c77SSepherosa Ziehau uint32_t chim_index; 17215516c77SSepherosa Ziehau int chim_size; 17315516c77SSepherosa Ziehau 17415516c77SSepherosa Ziehau bus_dmamap_t data_dmap; 17515516c77SSepherosa Ziehau 17615516c77SSepherosa Ziehau bus_addr_t rndis_pkt_paddr; 17715516c77SSepherosa Ziehau struct rndis_packet_msg *rndis_pkt; 17815516c77SSepherosa Ziehau bus_dmamap_t rndis_pkt_dmap; 17915516c77SSepherosa Ziehau }; 18015516c77SSepherosa Ziehau 18115516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST 0x0001 18215516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP 0x0002 18315516c77SSepherosa Ziehau 18415516c77SSepherosa Ziehau struct hn_rxinfo { 18515516c77SSepherosa Ziehau uint32_t vlan_info; 18615516c77SSepherosa Ziehau uint32_t csum_info; 18715516c77SSepherosa Ziehau uint32_t hash_info; 18815516c77SSepherosa Ziehau uint32_t hash_value; 18915516c77SSepherosa Ziehau }; 19015516c77SSepherosa Ziehau 19115516c77SSepherosa Ziehau #define HN_RXINFO_VLAN 0x0001 19215516c77SSepherosa Ziehau #define HN_RXINFO_CSUM 0x0002 19315516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF 0x0004 19415516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL 0x0008 19515516c77SSepherosa Ziehau #define HN_RXINFO_ALL \ 19615516c77SSepherosa Ziehau (HN_RXINFO_VLAN | \ 19715516c77SSepherosa Ziehau HN_RXINFO_CSUM | \ 19815516c77SSepherosa Ziehau HN_RXINFO_HASHINF | \ 19915516c77SSepherosa Ziehau HN_RXINFO_HASHVAL) 20015516c77SSepherosa Ziehau 20115516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID 0xffffffff 20215516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID 0 20315516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID 0 20415516c77SSepherosa Ziehau 20515516c77SSepherosa Ziehau static int hn_probe(device_t); 20615516c77SSepherosa Ziehau static int hn_attach(device_t); 20715516c77SSepherosa Ziehau static int hn_detach(device_t); 20815516c77SSepherosa Ziehau static int hn_shutdown(device_t); 20915516c77SSepherosa Ziehau static void hn_chan_callback(struct vmbus_channel *, 21015516c77SSepherosa Ziehau void *); 21115516c77SSepherosa Ziehau 21215516c77SSepherosa Ziehau static void hn_init(void *); 21315516c77SSepherosa Ziehau static int hn_ioctl(struct ifnet *, u_long, caddr_t); 21423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 21515516c77SSepherosa Ziehau static void hn_start(struct ifnet *); 21623bf9e15SSepherosa Ziehau #endif 21715516c77SSepherosa Ziehau static int hn_transmit(struct ifnet *, struct mbuf *); 21815516c77SSepherosa Ziehau static void hn_xmit_qflush(struct ifnet *); 21915516c77SSepherosa Ziehau static int hn_ifmedia_upd(struct ifnet *); 22015516c77SSepherosa Ziehau static void hn_ifmedia_sts(struct ifnet *, 22115516c77SSepherosa Ziehau struct ifmediareq *); 22215516c77SSepherosa Ziehau 22315516c77SSepherosa Ziehau static int hn_rndis_rxinfo(const void *, int, 22415516c77SSepherosa Ziehau struct hn_rxinfo *); 22515516c77SSepherosa Ziehau static void hn_rndis_rx_data(struct hn_rx_ring *, 22615516c77SSepherosa Ziehau const void *, int); 22715516c77SSepherosa Ziehau static void hn_rndis_rx_status(struct hn_softc *, 22815516c77SSepherosa Ziehau const void *, int); 22915516c77SSepherosa Ziehau 23015516c77SSepherosa Ziehau static void hn_nvs_handle_notify(struct hn_softc *, 23115516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 23215516c77SSepherosa Ziehau static void hn_nvs_handle_comp(struct hn_softc *, 23315516c77SSepherosa Ziehau struct vmbus_channel *, 23415516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 23515516c77SSepherosa Ziehau static void hn_nvs_handle_rxbuf(struct hn_rx_ring *, 23615516c77SSepherosa Ziehau struct vmbus_channel *, 23715516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *); 23815516c77SSepherosa Ziehau static void hn_nvs_ack_rxbuf(struct hn_rx_ring *, 23915516c77SSepherosa Ziehau struct vmbus_channel *, uint64_t); 24015516c77SSepherosa Ziehau 24115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 24215516c77SSepherosa Ziehau static int hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS); 24315516c77SSepherosa Ziehau static int hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS); 24415516c77SSepherosa Ziehau #endif 24515516c77SSepherosa Ziehau static int hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS); 24615516c77SSepherosa Ziehau static int hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS); 24715516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 24815516c77SSepherosa Ziehau static int hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS); 24915516c77SSepherosa Ziehau #else 25015516c77SSepherosa Ziehau static int hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS); 25115516c77SSepherosa Ziehau #endif 25215516c77SSepherosa Ziehau static int hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 25315516c77SSepherosa Ziehau static int hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); 25415516c77SSepherosa Ziehau static int hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS); 25515516c77SSepherosa Ziehau static int hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS); 25615516c77SSepherosa Ziehau static int hn_caps_sysctl(SYSCTL_HANDLER_ARGS); 25715516c77SSepherosa Ziehau static int hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS); 25815516c77SSepherosa Ziehau static int hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS); 25915516c77SSepherosa Ziehau static int hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS); 26015516c77SSepherosa Ziehau static int hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS); 26115516c77SSepherosa Ziehau static int hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS); 26215516c77SSepherosa Ziehau 26315516c77SSepherosa Ziehau static void hn_stop(struct hn_softc *); 26415516c77SSepherosa Ziehau static void hn_init_locked(struct hn_softc *); 26515516c77SSepherosa Ziehau static int hn_chan_attach(struct hn_softc *, 26615516c77SSepherosa Ziehau struct vmbus_channel *); 26715516c77SSepherosa Ziehau static void hn_chan_detach(struct hn_softc *, 26815516c77SSepherosa Ziehau struct vmbus_channel *); 26915516c77SSepherosa Ziehau static int hn_attach_subchans(struct hn_softc *); 27015516c77SSepherosa Ziehau static void hn_detach_allchans(struct hn_softc *); 27115516c77SSepherosa Ziehau static void hn_chan_rollup(struct hn_rx_ring *, 27215516c77SSepherosa Ziehau struct hn_tx_ring *); 27315516c77SSepherosa Ziehau static void hn_set_ring_inuse(struct hn_softc *, int); 27415516c77SSepherosa Ziehau static int hn_synth_attach(struct hn_softc *, int); 27515516c77SSepherosa Ziehau static void hn_synth_detach(struct hn_softc *); 27615516c77SSepherosa Ziehau static int hn_synth_alloc_subchans(struct hn_softc *, 27715516c77SSepherosa Ziehau int *); 27815516c77SSepherosa Ziehau static void hn_suspend(struct hn_softc *); 27915516c77SSepherosa Ziehau static void hn_suspend_data(struct hn_softc *); 28015516c77SSepherosa Ziehau static void hn_suspend_mgmt(struct hn_softc *); 28115516c77SSepherosa Ziehau static void hn_resume(struct hn_softc *); 28215516c77SSepherosa Ziehau static void hn_resume_data(struct hn_softc *); 28315516c77SSepherosa Ziehau static void hn_resume_mgmt(struct hn_softc *); 28415516c77SSepherosa Ziehau static void hn_suspend_mgmt_taskfunc(void *, int); 28515516c77SSepherosa Ziehau static void hn_chan_drain(struct vmbus_channel *); 28615516c77SSepherosa Ziehau 28715516c77SSepherosa Ziehau static void hn_update_link_status(struct hn_softc *); 28815516c77SSepherosa Ziehau static void hn_change_network(struct hn_softc *); 28915516c77SSepherosa Ziehau static void hn_link_taskfunc(void *, int); 29015516c77SSepherosa Ziehau static void hn_netchg_init_taskfunc(void *, int); 29115516c77SSepherosa Ziehau static void hn_netchg_status_taskfunc(void *, int); 29215516c77SSepherosa Ziehau static void hn_link_status(struct hn_softc *); 29315516c77SSepherosa Ziehau 29415516c77SSepherosa Ziehau static int hn_create_rx_data(struct hn_softc *, int); 29515516c77SSepherosa Ziehau static void hn_destroy_rx_data(struct hn_softc *); 29615516c77SSepherosa Ziehau static int hn_check_iplen(const struct mbuf *, int); 29715516c77SSepherosa Ziehau static int hn_set_rxfilter(struct hn_softc *); 29815516c77SSepherosa Ziehau static int hn_rss_reconfig(struct hn_softc *); 29915516c77SSepherosa Ziehau static void hn_rss_ind_fixup(struct hn_softc *, int); 30015516c77SSepherosa Ziehau static int hn_rxpkt(struct hn_rx_ring *, const void *, 30115516c77SSepherosa Ziehau int, const struct hn_rxinfo *); 30215516c77SSepherosa Ziehau 30315516c77SSepherosa Ziehau static int hn_tx_ring_create(struct hn_softc *, int); 30415516c77SSepherosa Ziehau static void hn_tx_ring_destroy(struct hn_tx_ring *); 30515516c77SSepherosa Ziehau static int hn_create_tx_data(struct hn_softc *, int); 30615516c77SSepherosa Ziehau static void hn_fixup_tx_data(struct hn_softc *); 30715516c77SSepherosa Ziehau static void hn_destroy_tx_data(struct hn_softc *); 30815516c77SSepherosa Ziehau static void hn_txdesc_dmamap_destroy(struct hn_txdesc *); 30915516c77SSepherosa Ziehau static int hn_encap(struct hn_tx_ring *, 31015516c77SSepherosa Ziehau struct hn_txdesc *, struct mbuf **); 31115516c77SSepherosa Ziehau static int hn_txpkt(struct ifnet *, struct hn_tx_ring *, 31215516c77SSepherosa Ziehau struct hn_txdesc *); 31315516c77SSepherosa Ziehau static void hn_set_chim_size(struct hn_softc *, int); 31415516c77SSepherosa Ziehau static void hn_set_tso_maxsize(struct hn_softc *, int, int); 31515516c77SSepherosa Ziehau static bool hn_tx_ring_pending(struct hn_tx_ring *); 31615516c77SSepherosa Ziehau static void hn_tx_ring_qflush(struct hn_tx_ring *); 31715516c77SSepherosa Ziehau static void hn_resume_tx(struct hn_softc *, int); 31815516c77SSepherosa Ziehau static int hn_get_txswq_depth(const struct hn_tx_ring *); 31915516c77SSepherosa Ziehau static void hn_txpkt_done(struct hn_nvs_sendctx *, 32015516c77SSepherosa Ziehau struct hn_softc *, struct vmbus_channel *, 32115516c77SSepherosa Ziehau const void *, int); 32215516c77SSepherosa Ziehau static int hn_txpkt_sglist(struct hn_tx_ring *, 32315516c77SSepherosa Ziehau struct hn_txdesc *); 32415516c77SSepherosa Ziehau static int hn_txpkt_chim(struct hn_tx_ring *, 32515516c77SSepherosa Ziehau struct hn_txdesc *); 32615516c77SSepherosa Ziehau static int hn_xmit(struct hn_tx_ring *, int); 32715516c77SSepherosa Ziehau static void hn_xmit_taskfunc(void *, int); 32815516c77SSepherosa Ziehau static void hn_xmit_txeof(struct hn_tx_ring *); 32915516c77SSepherosa Ziehau static void hn_xmit_txeof_taskfunc(void *, int); 33023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 33115516c77SSepherosa Ziehau static int hn_start_locked(struct hn_tx_ring *, int); 33215516c77SSepherosa Ziehau static void hn_start_taskfunc(void *, int); 33315516c77SSepherosa Ziehau static void hn_start_txeof(struct hn_tx_ring *); 33415516c77SSepherosa Ziehau static void hn_start_txeof_taskfunc(void *, int); 33523bf9e15SSepherosa Ziehau #endif 33615516c77SSepherosa Ziehau 33715516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 33815516c77SSepherosa Ziehau "Hyper-V network interface"); 33915516c77SSepherosa Ziehau 34015516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */ 34115516c77SSepherosa Ziehau static int hn_trust_hosttcp = 1; 34215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN, 34315516c77SSepherosa Ziehau &hn_trust_hosttcp, 0, 34415516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 34515516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 34615516c77SSepherosa Ziehau 34715516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */ 34815516c77SSepherosa Ziehau static int hn_trust_hostudp = 1; 34915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN, 35015516c77SSepherosa Ziehau &hn_trust_hostudp, 0, 35115516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 35215516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 35315516c77SSepherosa Ziehau 35415516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */ 35515516c77SSepherosa Ziehau static int hn_trust_hostip = 1; 35615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN, 35715516c77SSepherosa Ziehau &hn_trust_hostip, 0, 35815516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 35915516c77SSepherosa Ziehau "when csum info is missing (global setting)"); 36015516c77SSepherosa Ziehau 36115516c77SSepherosa Ziehau /* Limit TSO burst size */ 36215516c77SSepherosa Ziehau static int hn_tso_maxlen = IP_MAXPACKET; 36315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN, 36415516c77SSepherosa Ziehau &hn_tso_maxlen, 0, "TSO burst limit"); 36515516c77SSepherosa Ziehau 36615516c77SSepherosa Ziehau /* Limit chimney send size */ 36715516c77SSepherosa Ziehau static int hn_tx_chimney_size = 0; 36815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN, 36915516c77SSepherosa Ziehau &hn_tx_chimney_size, 0, "Chimney send packet size limit"); 37015516c77SSepherosa Ziehau 37115516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */ 37215516c77SSepherosa Ziehau static int hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF; 37315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN, 37415516c77SSepherosa Ziehau &hn_direct_tx_size, 0, "Size of the packet for direct transmission"); 37515516c77SSepherosa Ziehau 37615516c77SSepherosa Ziehau /* # of LRO entries per RX ring */ 37715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 37815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 37915516c77SSepherosa Ziehau static int hn_lro_entry_count = HN_LROENT_CNT_DEF; 38015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN, 38115516c77SSepherosa Ziehau &hn_lro_entry_count, 0, "LRO entry count"); 38215516c77SSepherosa Ziehau #endif 38315516c77SSepherosa Ziehau #endif 38415516c77SSepherosa Ziehau 38515516c77SSepherosa Ziehau /* Use shared TX taskqueue */ 38615516c77SSepherosa Ziehau static int hn_share_tx_taskq = 0; 38715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, share_tx_taskq, CTLFLAG_RDTUN, 38815516c77SSepherosa Ziehau &hn_share_tx_taskq, 0, "Enable shared TX taskqueue"); 38915516c77SSepherosa Ziehau 39015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 39115516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 0; 39215516c77SSepherosa Ziehau #else 39315516c77SSepherosa Ziehau static int hn_use_txdesc_bufring = 1; 39415516c77SSepherosa Ziehau #endif 39515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD, 39615516c77SSepherosa Ziehau &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors"); 39715516c77SSepherosa Ziehau 39815516c77SSepherosa Ziehau /* Bind TX taskqueue to the target CPU */ 39915516c77SSepherosa Ziehau static int hn_bind_tx_taskq = -1; 40015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, bind_tx_taskq, CTLFLAG_RDTUN, 40115516c77SSepherosa Ziehau &hn_bind_tx_taskq, 0, "Bind TX taskqueue to the specified cpu"); 40215516c77SSepherosa Ziehau 40323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 40415516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */ 40515516c77SSepherosa Ziehau static int hn_use_if_start = 0; 40615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN, 40715516c77SSepherosa Ziehau &hn_use_if_start, 0, "Use if_start TX method"); 40823bf9e15SSepherosa Ziehau #endif 40915516c77SSepherosa Ziehau 41015516c77SSepherosa Ziehau /* # of channels to use */ 41115516c77SSepherosa Ziehau static int hn_chan_cnt = 0; 41215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN, 41315516c77SSepherosa Ziehau &hn_chan_cnt, 0, 41415516c77SSepherosa Ziehau "# of channels to use; each channel has one RX ring and one TX ring"); 41515516c77SSepherosa Ziehau 41615516c77SSepherosa Ziehau /* # of transmit rings to use */ 41715516c77SSepherosa Ziehau static int hn_tx_ring_cnt = 0; 41815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN, 41915516c77SSepherosa Ziehau &hn_tx_ring_cnt, 0, "# of TX rings to use"); 42015516c77SSepherosa Ziehau 42115516c77SSepherosa Ziehau /* Software TX ring deptch */ 42215516c77SSepherosa Ziehau static int hn_tx_swq_depth = 0; 42315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN, 42415516c77SSepherosa Ziehau &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING"); 42515516c77SSepherosa Ziehau 42615516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */ 42715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 42815516c77SSepherosa Ziehau static u_int hn_lro_mbufq_depth = 0; 42915516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN, 43015516c77SSepherosa Ziehau &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue"); 43115516c77SSepherosa Ziehau #endif 43215516c77SSepherosa Ziehau 43315516c77SSepherosa Ziehau static u_int hn_cpu_index; /* next CPU for channel */ 43415516c77SSepherosa Ziehau static struct taskqueue *hn_tx_taskq; /* shared TX taskqueue */ 43515516c77SSepherosa Ziehau 43615516c77SSepherosa Ziehau static const uint8_t 43715516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = { 43815516c77SSepherosa Ziehau 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 43915516c77SSepherosa Ziehau 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 44015516c77SSepherosa Ziehau 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 44115516c77SSepherosa Ziehau 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 44215516c77SSepherosa Ziehau 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa 44315516c77SSepherosa Ziehau }; 44415516c77SSepherosa Ziehau 44515516c77SSepherosa Ziehau static device_method_t hn_methods[] = { 44615516c77SSepherosa Ziehau /* Device interface */ 44715516c77SSepherosa Ziehau DEVMETHOD(device_probe, hn_probe), 44815516c77SSepherosa Ziehau DEVMETHOD(device_attach, hn_attach), 44915516c77SSepherosa Ziehau DEVMETHOD(device_detach, hn_detach), 45015516c77SSepherosa Ziehau DEVMETHOD(device_shutdown, hn_shutdown), 45115516c77SSepherosa Ziehau DEVMETHOD_END 45215516c77SSepherosa Ziehau }; 45315516c77SSepherosa Ziehau 45415516c77SSepherosa Ziehau static driver_t hn_driver = { 45515516c77SSepherosa Ziehau "hn", 45615516c77SSepherosa Ziehau hn_methods, 45715516c77SSepherosa Ziehau sizeof(struct hn_softc) 45815516c77SSepherosa Ziehau }; 45915516c77SSepherosa Ziehau 46015516c77SSepherosa Ziehau static devclass_t hn_devclass; 46115516c77SSepherosa Ziehau 46215516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0); 46315516c77SSepherosa Ziehau MODULE_VERSION(hn, 1); 46415516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1); 46515516c77SSepherosa Ziehau 46615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 46715516c77SSepherosa Ziehau static void 46815516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim) 46915516c77SSepherosa Ziehau { 47015516c77SSepherosa Ziehau int i; 47115516c77SSepherosa Ziehau 47215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) 47315516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim; 47415516c77SSepherosa Ziehau } 47515516c77SSepherosa Ziehau #endif 47615516c77SSepherosa Ziehau 47715516c77SSepherosa Ziehau static int 47815516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd) 47915516c77SSepherosa Ziehau { 48015516c77SSepherosa Ziehau 48115516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 48215516c77SSepherosa Ziehau txd->chim_size == 0, ("invalid rndis sglist txd")); 48315516c77SSepherosa Ziehau return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA, 48415516c77SSepherosa Ziehau &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt)); 48515516c77SSepherosa Ziehau } 48615516c77SSepherosa Ziehau 48715516c77SSepherosa Ziehau static int 48815516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd) 48915516c77SSepherosa Ziehau { 49015516c77SSepherosa Ziehau struct hn_nvs_rndis rndis; 49115516c77SSepherosa Ziehau 49215516c77SSepherosa Ziehau KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID && 49315516c77SSepherosa Ziehau txd->chim_size > 0, ("invalid rndis chim txd")); 49415516c77SSepherosa Ziehau 49515516c77SSepherosa Ziehau rndis.nvs_type = HN_NVS_TYPE_RNDIS; 49615516c77SSepherosa Ziehau rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA; 49715516c77SSepherosa Ziehau rndis.nvs_chim_idx = txd->chim_index; 49815516c77SSepherosa Ziehau rndis.nvs_chim_sz = txd->chim_size; 49915516c77SSepherosa Ziehau 50015516c77SSepherosa Ziehau return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC, 50115516c77SSepherosa Ziehau &rndis, sizeof(rndis), &txd->send_ctx)); 50215516c77SSepherosa Ziehau } 50315516c77SSepherosa Ziehau 50415516c77SSepherosa Ziehau static __inline uint32_t 50515516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc) 50615516c77SSepherosa Ziehau { 50715516c77SSepherosa Ziehau int i, bmap_cnt = sc->hn_chim_bmap_cnt; 50815516c77SSepherosa Ziehau u_long *bmap = sc->hn_chim_bmap; 50915516c77SSepherosa Ziehau uint32_t ret = HN_NVS_CHIM_IDX_INVALID; 51015516c77SSepherosa Ziehau 51115516c77SSepherosa Ziehau for (i = 0; i < bmap_cnt; ++i) { 51215516c77SSepherosa Ziehau int idx; 51315516c77SSepherosa Ziehau 51415516c77SSepherosa Ziehau idx = ffsl(~bmap[i]); 51515516c77SSepherosa Ziehau if (idx == 0) 51615516c77SSepherosa Ziehau continue; 51715516c77SSepherosa Ziehau 51815516c77SSepherosa Ziehau --idx; /* ffsl is 1-based */ 51915516c77SSepherosa Ziehau KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt, 52015516c77SSepherosa Ziehau ("invalid i %d and idx %d", i, idx)); 52115516c77SSepherosa Ziehau 52215516c77SSepherosa Ziehau if (atomic_testandset_long(&bmap[i], idx)) 52315516c77SSepherosa Ziehau continue; 52415516c77SSepherosa Ziehau 52515516c77SSepherosa Ziehau ret = i * LONG_BIT + idx; 52615516c77SSepherosa Ziehau break; 52715516c77SSepherosa Ziehau } 52815516c77SSepherosa Ziehau return (ret); 52915516c77SSepherosa Ziehau } 53015516c77SSepherosa Ziehau 53115516c77SSepherosa Ziehau static __inline void 53215516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx) 53315516c77SSepherosa Ziehau { 53415516c77SSepherosa Ziehau u_long mask; 53515516c77SSepherosa Ziehau uint32_t idx; 53615516c77SSepherosa Ziehau 53715516c77SSepherosa Ziehau idx = chim_idx / LONG_BIT; 53815516c77SSepherosa Ziehau KASSERT(idx < sc->hn_chim_bmap_cnt, 53915516c77SSepherosa Ziehau ("invalid chimney index 0x%x", chim_idx)); 54015516c77SSepherosa Ziehau 54115516c77SSepherosa Ziehau mask = 1UL << (chim_idx % LONG_BIT); 54215516c77SSepherosa Ziehau KASSERT(sc->hn_chim_bmap[idx] & mask, 54315516c77SSepherosa Ziehau ("index bitmap 0x%lx, chimney index %u, " 54415516c77SSepherosa Ziehau "bitmap idx %d, bitmask 0x%lx", 54515516c77SSepherosa Ziehau sc->hn_chim_bmap[idx], chim_idx, idx, mask)); 54615516c77SSepherosa Ziehau 54715516c77SSepherosa Ziehau atomic_clear_long(&sc->hn_chim_bmap[idx], mask); 54815516c77SSepherosa Ziehau } 54915516c77SSepherosa Ziehau 550edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 551edd3f315SSepherosa Ziehau /* 552edd3f315SSepherosa Ziehau * NOTE: If this function failed, the m_head would be freed. 553edd3f315SSepherosa Ziehau */ 554edd3f315SSepherosa Ziehau static __inline struct mbuf * 555edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head) 556edd3f315SSepherosa Ziehau { 557edd3f315SSepherosa Ziehau struct ether_vlan_header *evl; 558edd3f315SSepherosa Ziehau struct tcphdr *th; 559edd3f315SSepherosa Ziehau int ehlen; 560edd3f315SSepherosa Ziehau 561edd3f315SSepherosa Ziehau KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable")); 562edd3f315SSepherosa Ziehau 563edd3f315SSepherosa Ziehau #define PULLUP_HDR(m, len) \ 564edd3f315SSepherosa Ziehau do { \ 565edd3f315SSepherosa Ziehau if (__predict_false((m)->m_len < (len))) { \ 566edd3f315SSepherosa Ziehau (m) = m_pullup((m), (len)); \ 567edd3f315SSepherosa Ziehau if ((m) == NULL) \ 568edd3f315SSepherosa Ziehau return (NULL); \ 569edd3f315SSepherosa Ziehau } \ 570edd3f315SSepherosa Ziehau } while (0) 571edd3f315SSepherosa Ziehau 572edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, sizeof(*evl)); 573edd3f315SSepherosa Ziehau evl = mtod(m_head, struct ether_vlan_header *); 574edd3f315SSepherosa Ziehau if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) 575edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 576edd3f315SSepherosa Ziehau else 577edd3f315SSepherosa Ziehau ehlen = ETHER_HDR_LEN; 578edd3f315SSepherosa Ziehau 579edd3f315SSepherosa Ziehau #ifdef INET 580edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 581edd3f315SSepherosa Ziehau struct ip *ip; 582edd3f315SSepherosa Ziehau int iphlen; 583edd3f315SSepherosa Ziehau 584edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip)); 585edd3f315SSepherosa Ziehau ip = mtodo(m_head, ehlen); 586edd3f315SSepherosa Ziehau iphlen = ip->ip_hl << 2; 587edd3f315SSepherosa Ziehau 588edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); 589edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + iphlen); 590edd3f315SSepherosa Ziehau 591edd3f315SSepherosa Ziehau ip->ip_len = 0; 592edd3f315SSepherosa Ziehau ip->ip_sum = 0; 593edd3f315SSepherosa Ziehau th->th_sum = in_pseudo(ip->ip_src.s_addr, 594edd3f315SSepherosa Ziehau ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 595edd3f315SSepherosa Ziehau } 596edd3f315SSepherosa Ziehau #endif 597edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET) 598edd3f315SSepherosa Ziehau else 599edd3f315SSepherosa Ziehau #endif 600edd3f315SSepherosa Ziehau #ifdef INET6 601edd3f315SSepherosa Ziehau { 602edd3f315SSepherosa Ziehau struct ip6_hdr *ip6; 603edd3f315SSepherosa Ziehau 604edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); 605edd3f315SSepherosa Ziehau ip6 = mtodo(m_head, ehlen); 606edd3f315SSepherosa Ziehau if (ip6->ip6_nxt != IPPROTO_TCP) { 607edd3f315SSepherosa Ziehau m_freem(m_head); 608edd3f315SSepherosa Ziehau return (NULL); 609edd3f315SSepherosa Ziehau } 610edd3f315SSepherosa Ziehau 611edd3f315SSepherosa Ziehau PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); 612edd3f315SSepherosa Ziehau th = mtodo(m_head, ehlen + sizeof(*ip6)); 613edd3f315SSepherosa Ziehau 614edd3f315SSepherosa Ziehau ip6->ip6_plen = 0; 615edd3f315SSepherosa Ziehau th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 616edd3f315SSepherosa Ziehau } 617edd3f315SSepherosa Ziehau #endif 618edd3f315SSepherosa Ziehau return (m_head); 619edd3f315SSepherosa Ziehau 620edd3f315SSepherosa Ziehau #undef PULLUP_HDR 621edd3f315SSepherosa Ziehau } 622edd3f315SSepherosa Ziehau #endif /* INET6 || INET */ 623edd3f315SSepherosa Ziehau 62415516c77SSepherosa Ziehau static int 62515516c77SSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc) 62615516c77SSepherosa Ziehau { 62715516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 62815516c77SSepherosa Ziehau uint32_t filter; 62915516c77SSepherosa Ziehau int error = 0; 63015516c77SSepherosa Ziehau 63115516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 63215516c77SSepherosa Ziehau 63315516c77SSepherosa Ziehau if (ifp->if_flags & IFF_PROMISC) { 63415516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_PROMISCUOUS; 63515516c77SSepherosa Ziehau } else { 63615516c77SSepherosa Ziehau filter = NDIS_PACKET_TYPE_DIRECTED; 63715516c77SSepherosa Ziehau if (ifp->if_flags & IFF_BROADCAST) 63815516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_BROADCAST; 63915516c77SSepherosa Ziehau #ifdef notyet 64015516c77SSepherosa Ziehau /* 64115516c77SSepherosa Ziehau * See the comment in SIOCADDMULTI/SIOCDELMULTI. 64215516c77SSepherosa Ziehau */ 64315516c77SSepherosa Ziehau /* TODO: support multicast list */ 64415516c77SSepherosa Ziehau if ((ifp->if_flags & IFF_ALLMULTI) || 64515516c77SSepherosa Ziehau !TAILQ_EMPTY(&ifp->if_multiaddrs)) 64615516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 64715516c77SSepherosa Ziehau #else 64815516c77SSepherosa Ziehau /* Always enable ALLMULTI */ 64915516c77SSepherosa Ziehau filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 65015516c77SSepherosa Ziehau #endif 65115516c77SSepherosa Ziehau } 65215516c77SSepherosa Ziehau 65315516c77SSepherosa Ziehau if (sc->hn_rx_filter != filter) { 65415516c77SSepherosa Ziehau error = hn_rndis_set_rxfilter(sc, filter); 65515516c77SSepherosa Ziehau if (!error) 65615516c77SSepherosa Ziehau sc->hn_rx_filter = filter; 65715516c77SSepherosa Ziehau } 65815516c77SSepherosa Ziehau return (error); 65915516c77SSepherosa Ziehau } 66015516c77SSepherosa Ziehau 66115516c77SSepherosa Ziehau static int 66215516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr) 66315516c77SSepherosa Ziehau { 66415516c77SSepherosa Ziehau 66515516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet")); 66615516c77SSepherosa Ziehau if (hn_tx_swq_depth < txr->hn_txdesc_cnt) 66715516c77SSepherosa Ziehau return txr->hn_txdesc_cnt; 66815516c77SSepherosa Ziehau return hn_tx_swq_depth; 66915516c77SSepherosa Ziehau } 67015516c77SSepherosa Ziehau 67115516c77SSepherosa Ziehau static int 67215516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc) 67315516c77SSepherosa Ziehau { 67415516c77SSepherosa Ziehau int error; 67515516c77SSepherosa Ziehau 67615516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 67715516c77SSepherosa Ziehau 67815516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 67915516c77SSepherosa Ziehau return (ENXIO); 68015516c77SSepherosa Ziehau 68115516c77SSepherosa Ziehau /* 68215516c77SSepherosa Ziehau * Disable RSS first. 68315516c77SSepherosa Ziehau * 68415516c77SSepherosa Ziehau * NOTE: 68515516c77SSepherosa Ziehau * Direct reconfiguration by setting the UNCHG flags does 68615516c77SSepherosa Ziehau * _not_ work properly. 68715516c77SSepherosa Ziehau */ 68815516c77SSepherosa Ziehau if (bootverbose) 68915516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "disable RSS\n"); 69015516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE); 69115516c77SSepherosa Ziehau if (error) { 69215516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS disable failed\n"); 69315516c77SSepherosa Ziehau return (error); 69415516c77SSepherosa Ziehau } 69515516c77SSepherosa Ziehau 69615516c77SSepherosa Ziehau /* 69715516c77SSepherosa Ziehau * Reenable the RSS w/ the updated RSS key or indirect 69815516c77SSepherosa Ziehau * table. 69915516c77SSepherosa Ziehau */ 70015516c77SSepherosa Ziehau if (bootverbose) 70115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "reconfig RSS\n"); 70215516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 70315516c77SSepherosa Ziehau if (error) { 70415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RSS reconfig failed\n"); 70515516c77SSepherosa Ziehau return (error); 70615516c77SSepherosa Ziehau } 70715516c77SSepherosa Ziehau return (0); 70815516c77SSepherosa Ziehau } 70915516c77SSepherosa Ziehau 71015516c77SSepherosa Ziehau static void 71115516c77SSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc, int nchan) 71215516c77SSepherosa Ziehau { 71315516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 71415516c77SSepherosa Ziehau int i; 71515516c77SSepherosa Ziehau 71615516c77SSepherosa Ziehau KASSERT(nchan > 1, ("invalid # of channels %d", nchan)); 71715516c77SSepherosa Ziehau 71815516c77SSepherosa Ziehau /* 71915516c77SSepherosa Ziehau * Check indirect table to make sure that all channels in it 72015516c77SSepherosa Ziehau * can be used. 72115516c77SSepherosa Ziehau */ 72215516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) { 72315516c77SSepherosa Ziehau if (rss->rss_ind[i] >= nchan) { 72415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, 72515516c77SSepherosa Ziehau "RSS indirect table %d fixup: %u -> %d\n", 72615516c77SSepherosa Ziehau i, rss->rss_ind[i], nchan - 1); 72715516c77SSepherosa Ziehau rss->rss_ind[i] = nchan - 1; 72815516c77SSepherosa Ziehau } 72915516c77SSepherosa Ziehau } 73015516c77SSepherosa Ziehau } 73115516c77SSepherosa Ziehau 73215516c77SSepherosa Ziehau static int 73315516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused) 73415516c77SSepherosa Ziehau { 73515516c77SSepherosa Ziehau 73615516c77SSepherosa Ziehau return EOPNOTSUPP; 73715516c77SSepherosa Ziehau } 73815516c77SSepherosa Ziehau 73915516c77SSepherosa Ziehau static void 74015516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 74115516c77SSepherosa Ziehau { 74215516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 74315516c77SSepherosa Ziehau 74415516c77SSepherosa Ziehau ifmr->ifm_status = IFM_AVALID; 74515516c77SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 74615516c77SSepherosa Ziehau 74715516c77SSepherosa Ziehau if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) { 74815516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_NONE; 74915516c77SSepherosa Ziehau return; 75015516c77SSepherosa Ziehau } 75115516c77SSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 75215516c77SSepherosa Ziehau ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 75315516c77SSepherosa Ziehau } 75415516c77SSepherosa Ziehau 75515516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ 75615516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = { 75715516c77SSepherosa Ziehau .hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 75815516c77SSepherosa Ziehau 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E} 75915516c77SSepherosa Ziehau }; 76015516c77SSepherosa Ziehau 76115516c77SSepherosa Ziehau static int 76215516c77SSepherosa Ziehau hn_probe(device_t dev) 76315516c77SSepherosa Ziehau { 76415516c77SSepherosa Ziehau 76515516c77SSepherosa Ziehau if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, 76615516c77SSepherosa Ziehau &g_net_vsc_device_type) == 0) { 76715516c77SSepherosa Ziehau device_set_desc(dev, "Hyper-V Network Interface"); 76815516c77SSepherosa Ziehau return BUS_PROBE_DEFAULT; 76915516c77SSepherosa Ziehau } 77015516c77SSepherosa Ziehau return ENXIO; 77115516c77SSepherosa Ziehau } 77215516c77SSepherosa Ziehau 77315516c77SSepherosa Ziehau static int 77415516c77SSepherosa Ziehau hn_attach(device_t dev) 77515516c77SSepherosa Ziehau { 77615516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 77715516c77SSepherosa Ziehau struct sysctl_oid_list *child; 77815516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 77915516c77SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 78015516c77SSepherosa Ziehau struct ifnet *ifp = NULL; 78115516c77SSepherosa Ziehau int error, ring_cnt, tx_ring_cnt; 78215516c77SSepherosa Ziehau 78315516c77SSepherosa Ziehau sc->hn_dev = dev; 78415516c77SSepherosa Ziehau sc->hn_prichan = vmbus_get_channel(dev); 78515516c77SSepherosa Ziehau HN_LOCK_INIT(sc); 78615516c77SSepherosa Ziehau 78715516c77SSepherosa Ziehau /* 78815516c77SSepherosa Ziehau * Setup taskqueue for transmission. 78915516c77SSepherosa Ziehau */ 79015516c77SSepherosa Ziehau if (hn_tx_taskq == NULL) { 79115516c77SSepherosa Ziehau sc->hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK, 79215516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_tx_taskq); 79315516c77SSepherosa Ziehau if (hn_bind_tx_taskq >= 0) { 79415516c77SSepherosa Ziehau int cpu = hn_bind_tx_taskq; 79515516c77SSepherosa Ziehau cpuset_t cpu_set; 79615516c77SSepherosa Ziehau 79715516c77SSepherosa Ziehau if (cpu > mp_ncpus - 1) 79815516c77SSepherosa Ziehau cpu = mp_ncpus - 1; 79915516c77SSepherosa Ziehau CPU_SETOF(cpu, &cpu_set); 80015516c77SSepherosa Ziehau taskqueue_start_threads_cpuset(&sc->hn_tx_taskq, 1, 80115516c77SSepherosa Ziehau PI_NET, &cpu_set, "%s tx", 80215516c77SSepherosa Ziehau device_get_nameunit(dev)); 80315516c77SSepherosa Ziehau } else { 80415516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_tx_taskq, 1, PI_NET, 80515516c77SSepherosa Ziehau "%s tx", device_get_nameunit(dev)); 80615516c77SSepherosa Ziehau } 80715516c77SSepherosa Ziehau } else { 80815516c77SSepherosa Ziehau sc->hn_tx_taskq = hn_tx_taskq; 80915516c77SSepherosa Ziehau } 81015516c77SSepherosa Ziehau 81115516c77SSepherosa Ziehau /* 81215516c77SSepherosa Ziehau * Setup taskqueue for mangement tasks, e.g. link status. 81315516c77SSepherosa Ziehau */ 81415516c77SSepherosa Ziehau sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK, 81515516c77SSepherosa Ziehau taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0); 81615516c77SSepherosa Ziehau taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt", 81715516c77SSepherosa Ziehau device_get_nameunit(dev)); 81815516c77SSepherosa Ziehau TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc); 81915516c77SSepherosa Ziehau TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc); 82015516c77SSepherosa Ziehau TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0, 82115516c77SSepherosa Ziehau hn_netchg_status_taskfunc, sc); 82215516c77SSepherosa Ziehau 82315516c77SSepherosa Ziehau /* 82415516c77SSepherosa Ziehau * Allocate ifnet and setup its name earlier, so that if_printf 82515516c77SSepherosa Ziehau * can be used by functions, which will be called after 82615516c77SSepherosa Ziehau * ether_ifattach(). 82715516c77SSepherosa Ziehau */ 82815516c77SSepherosa Ziehau ifp = sc->hn_ifp = if_alloc(IFT_ETHER); 82915516c77SSepherosa Ziehau ifp->if_softc = sc; 83015516c77SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 83115516c77SSepherosa Ziehau 83215516c77SSepherosa Ziehau /* 83315516c77SSepherosa Ziehau * Initialize ifmedia earlier so that it can be unconditionally 83415516c77SSepherosa Ziehau * destroyed, if error happened later on. 83515516c77SSepherosa Ziehau */ 83615516c77SSepherosa Ziehau ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts); 83715516c77SSepherosa Ziehau 83815516c77SSepherosa Ziehau /* 83915516c77SSepherosa Ziehau * Figure out the # of RX rings (ring_cnt) and the # of TX rings 84015516c77SSepherosa Ziehau * to use (tx_ring_cnt). 84115516c77SSepherosa Ziehau * 84215516c77SSepherosa Ziehau * NOTE: 84315516c77SSepherosa Ziehau * The # of RX rings to use is same as the # of channels to use. 84415516c77SSepherosa Ziehau */ 84515516c77SSepherosa Ziehau ring_cnt = hn_chan_cnt; 84615516c77SSepherosa Ziehau if (ring_cnt <= 0) { 84715516c77SSepherosa Ziehau /* Default */ 84815516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 84915516c77SSepherosa Ziehau if (ring_cnt > HN_RING_CNT_DEF_MAX) 85015516c77SSepherosa Ziehau ring_cnt = HN_RING_CNT_DEF_MAX; 85115516c77SSepherosa Ziehau } else if (ring_cnt > mp_ncpus) { 85215516c77SSepherosa Ziehau ring_cnt = mp_ncpus; 85315516c77SSepherosa Ziehau } 85415516c77SSepherosa Ziehau 85515516c77SSepherosa Ziehau tx_ring_cnt = hn_tx_ring_cnt; 85615516c77SSepherosa Ziehau if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt) 85715516c77SSepherosa Ziehau tx_ring_cnt = ring_cnt; 85823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 85915516c77SSepherosa Ziehau if (hn_use_if_start) { 86015516c77SSepherosa Ziehau /* ifnet.if_start only needs one TX ring. */ 86115516c77SSepherosa Ziehau tx_ring_cnt = 1; 86215516c77SSepherosa Ziehau } 86323bf9e15SSepherosa Ziehau #endif 86415516c77SSepherosa Ziehau 86515516c77SSepherosa Ziehau /* 86615516c77SSepherosa Ziehau * Set the leader CPU for channels. 86715516c77SSepherosa Ziehau */ 86815516c77SSepherosa Ziehau sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus; 86915516c77SSepherosa Ziehau 87015516c77SSepherosa Ziehau /* 87115516c77SSepherosa Ziehau * Create enough TX/RX rings, even if only limited number of 87215516c77SSepherosa Ziehau * channels can be allocated. 87315516c77SSepherosa Ziehau */ 87415516c77SSepherosa Ziehau error = hn_create_tx_data(sc, tx_ring_cnt); 87515516c77SSepherosa Ziehau if (error) 87615516c77SSepherosa Ziehau goto failed; 87715516c77SSepherosa Ziehau error = hn_create_rx_data(sc, ring_cnt); 87815516c77SSepherosa Ziehau if (error) 87915516c77SSepherosa Ziehau goto failed; 88015516c77SSepherosa Ziehau 88115516c77SSepherosa Ziehau /* 88215516c77SSepherosa Ziehau * Create transaction context for NVS and RNDIS transactions. 88315516c77SSepherosa Ziehau */ 88415516c77SSepherosa Ziehau sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev), 88515516c77SSepherosa Ziehau HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0); 88615516c77SSepherosa Ziehau if (sc->hn_xact == NULL) 88715516c77SSepherosa Ziehau goto failed; 88815516c77SSepherosa Ziehau 88915516c77SSepherosa Ziehau /* 89015516c77SSepherosa Ziehau * Attach the synthetic parts, i.e. NVS and RNDIS. 89115516c77SSepherosa Ziehau */ 89215516c77SSepherosa Ziehau error = hn_synth_attach(sc, ETHERMTU); 89315516c77SSepherosa Ziehau if (error) 89415516c77SSepherosa Ziehau goto failed; 89515516c77SSepherosa Ziehau 89615516c77SSepherosa Ziehau error = hn_rndis_get_eaddr(sc, eaddr); 89715516c77SSepherosa Ziehau if (error) 89815516c77SSepherosa Ziehau goto failed; 89915516c77SSepherosa Ziehau 90015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 90115516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 90215516c77SSepherosa Ziehau /* 90315516c77SSepherosa Ziehau * Reduce TCP segment aggregation limit for multiple 90415516c77SSepherosa Ziehau * RX rings to increase ACK timeliness. 90515516c77SSepherosa Ziehau */ 90615516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF); 90715516c77SSepherosa Ziehau } 90815516c77SSepherosa Ziehau #endif 90915516c77SSepherosa Ziehau 91015516c77SSepherosa Ziehau /* 91115516c77SSepherosa Ziehau * Fixup TX stuffs after synthetic parts are attached. 91215516c77SSepherosa Ziehau */ 91315516c77SSepherosa Ziehau hn_fixup_tx_data(sc); 91415516c77SSepherosa Ziehau 91515516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 91615516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 91715516c77SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD, 91815516c77SSepherosa Ziehau &sc->hn_nvs_ver, 0, "NVS version"); 91915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version", 92015516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 92115516c77SSepherosa Ziehau hn_ndis_version_sysctl, "A", "NDIS version"); 92215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps", 92315516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 92415516c77SSepherosa Ziehau hn_caps_sysctl, "A", "capabilities"); 92515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist", 92615516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 92715516c77SSepherosa Ziehau hn_hwassist_sysctl, "A", "hwassist"); 92815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter", 92915516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 93015516c77SSepherosa Ziehau hn_rxfilter_sysctl, "A", "rxfilter"); 93115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash", 93215516c77SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 93315516c77SSepherosa Ziehau hn_rss_hash_sysctl, "A", "RSS hash"); 93415516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size", 93515516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count"); 93615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key", 93715516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 93815516c77SSepherosa Ziehau hn_rss_key_sysctl, "IU", "RSS key"); 93915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind", 94015516c77SSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 94115516c77SSepherosa Ziehau hn_rss_ind_sysctl, "IU", "RSS indirect table"); 94215516c77SSepherosa Ziehau 94315516c77SSepherosa Ziehau /* 94415516c77SSepherosa Ziehau * Setup the ifmedia, which has been initialized earlier. 94515516c77SSepherosa Ziehau */ 94615516c77SSepherosa Ziehau ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL); 94715516c77SSepherosa Ziehau ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO); 94815516c77SSepherosa Ziehau /* XXX ifmedia_set really should do this for us */ 94915516c77SSepherosa Ziehau sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media; 95015516c77SSepherosa Ziehau 95115516c77SSepherosa Ziehau /* 95215516c77SSepherosa Ziehau * Setup the ifnet for this interface. 95315516c77SSepherosa Ziehau */ 95415516c77SSepherosa Ziehau 95515516c77SSepherosa Ziehau ifp->if_baudrate = IF_Gbps(10); 95615516c77SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 95715516c77SSepherosa Ziehau ifp->if_ioctl = hn_ioctl; 95815516c77SSepherosa Ziehau ifp->if_init = hn_init; 95923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 96015516c77SSepherosa Ziehau if (hn_use_if_start) { 96115516c77SSepherosa Ziehau int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]); 96215516c77SSepherosa Ziehau 96315516c77SSepherosa Ziehau ifp->if_start = hn_start; 96415516c77SSepherosa Ziehau IFQ_SET_MAXLEN(&ifp->if_snd, qdepth); 96515516c77SSepherosa Ziehau ifp->if_snd.ifq_drv_maxlen = qdepth - 1; 96615516c77SSepherosa Ziehau IFQ_SET_READY(&ifp->if_snd); 96723bf9e15SSepherosa Ziehau } else 96823bf9e15SSepherosa Ziehau #endif 96923bf9e15SSepherosa Ziehau { 97015516c77SSepherosa Ziehau ifp->if_transmit = hn_transmit; 97115516c77SSepherosa Ziehau ifp->if_qflush = hn_xmit_qflush; 97215516c77SSepherosa Ziehau } 97315516c77SSepherosa Ziehau 97415516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO; 97515516c77SSepherosa Ziehau #ifdef foo 97615516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 97715516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_RXCSUM_IPV6; 97815516c77SSepherosa Ziehau #endif 97915516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_VLAN) { 98015516c77SSepherosa Ziehau /* XXX not sure about VLAN_MTU. */ 98115516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 98215516c77SSepherosa Ziehau } 98315516c77SSepherosa Ziehau 98415516c77SSepherosa Ziehau ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist; 98515516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP_MASK) 98615516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM; 98715516c77SSepherosa Ziehau if (ifp->if_hwassist & HN_CSUM_IP6_MASK) 98815516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM_IPV6; 98915516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO4) { 99015516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO4; 99115516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 99215516c77SSepherosa Ziehau } 99315516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TSO6) { 99415516c77SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TSO6; 99515516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 99615516c77SSepherosa Ziehau } 99715516c77SSepherosa Ziehau 99815516c77SSepherosa Ziehau /* Enable all available capabilities by default. */ 99915516c77SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 100015516c77SSepherosa Ziehau 100115516c77SSepherosa Ziehau if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) { 100215516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU); 100315516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; 100415516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 100515516c77SSepherosa Ziehau } 100615516c77SSepherosa Ziehau 100715516c77SSepherosa Ziehau ether_ifattach(ifp, eaddr); 100815516c77SSepherosa Ziehau 100915516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) { 101015516c77SSepherosa Ziehau if_printf(ifp, "TSO segcnt %u segsz %u\n", 101115516c77SSepherosa Ziehau ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize); 101215516c77SSepherosa Ziehau } 101315516c77SSepherosa Ziehau 101415516c77SSepherosa Ziehau /* Inform the upper layer about the long frame support. */ 101515516c77SSepherosa Ziehau ifp->if_hdrlen = sizeof(struct ether_vlan_header); 101615516c77SSepherosa Ziehau 101715516c77SSepherosa Ziehau /* 101815516c77SSepherosa Ziehau * Kick off link status check. 101915516c77SSepherosa Ziehau */ 102015516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 102115516c77SSepherosa Ziehau hn_update_link_status(sc); 102215516c77SSepherosa Ziehau 102315516c77SSepherosa Ziehau return (0); 102415516c77SSepherosa Ziehau failed: 102515516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) 102615516c77SSepherosa Ziehau hn_synth_detach(sc); 102715516c77SSepherosa Ziehau hn_detach(dev); 102815516c77SSepherosa Ziehau return (error); 102915516c77SSepherosa Ziehau } 103015516c77SSepherosa Ziehau 103115516c77SSepherosa Ziehau static int 103215516c77SSepherosa Ziehau hn_detach(device_t dev) 103315516c77SSepherosa Ziehau { 103415516c77SSepherosa Ziehau struct hn_softc *sc = device_get_softc(dev); 103515516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 103615516c77SSepherosa Ziehau 103715516c77SSepherosa Ziehau if (device_is_attached(dev)) { 103815516c77SSepherosa Ziehau HN_LOCK(sc); 103915516c77SSepherosa Ziehau if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) { 104015516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 104115516c77SSepherosa Ziehau hn_stop(sc); 104215516c77SSepherosa Ziehau /* 104315516c77SSepherosa Ziehau * NOTE: 104415516c77SSepherosa Ziehau * hn_stop() only suspends data, so managment 104515516c77SSepherosa Ziehau * stuffs have to be suspended manually here. 104615516c77SSepherosa Ziehau */ 104715516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 104815516c77SSepherosa Ziehau hn_synth_detach(sc); 104915516c77SSepherosa Ziehau } 105015516c77SSepherosa Ziehau HN_UNLOCK(sc); 105115516c77SSepherosa Ziehau ether_ifdetach(ifp); 105215516c77SSepherosa Ziehau } 105315516c77SSepherosa Ziehau 105415516c77SSepherosa Ziehau ifmedia_removeall(&sc->hn_media); 105515516c77SSepherosa Ziehau hn_destroy_rx_data(sc); 105615516c77SSepherosa Ziehau hn_destroy_tx_data(sc); 105715516c77SSepherosa Ziehau 105815516c77SSepherosa Ziehau if (sc->hn_tx_taskq != hn_tx_taskq) 105915516c77SSepherosa Ziehau taskqueue_free(sc->hn_tx_taskq); 106015516c77SSepherosa Ziehau taskqueue_free(sc->hn_mgmt_taskq0); 106115516c77SSepherosa Ziehau 106215516c77SSepherosa Ziehau if (sc->hn_xact != NULL) 106315516c77SSepherosa Ziehau vmbus_xact_ctx_destroy(sc->hn_xact); 106415516c77SSepherosa Ziehau 106515516c77SSepherosa Ziehau if_free(ifp); 106615516c77SSepherosa Ziehau 106715516c77SSepherosa Ziehau HN_LOCK_DESTROY(sc); 106815516c77SSepherosa Ziehau return (0); 106915516c77SSepherosa Ziehau } 107015516c77SSepherosa Ziehau 107115516c77SSepherosa Ziehau static int 107215516c77SSepherosa Ziehau hn_shutdown(device_t dev) 107315516c77SSepherosa Ziehau { 107415516c77SSepherosa Ziehau 107515516c77SSepherosa Ziehau return (0); 107615516c77SSepherosa Ziehau } 107715516c77SSepherosa Ziehau 107815516c77SSepherosa Ziehau static void 107915516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc) 108015516c77SSepherosa Ziehau { 108115516c77SSepherosa Ziehau uint32_t link_status; 108215516c77SSepherosa Ziehau int error; 108315516c77SSepherosa Ziehau 108415516c77SSepherosa Ziehau error = hn_rndis_get_linkstatus(sc, &link_status); 108515516c77SSepherosa Ziehau if (error) { 108615516c77SSepherosa Ziehau /* XXX what to do? */ 108715516c77SSepherosa Ziehau return; 108815516c77SSepherosa Ziehau } 108915516c77SSepherosa Ziehau 109015516c77SSepherosa Ziehau if (link_status == NDIS_MEDIA_STATE_CONNECTED) 109115516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_LINKUP; 109215516c77SSepherosa Ziehau else 109315516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 109415516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, 109515516c77SSepherosa Ziehau (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ? 109615516c77SSepherosa Ziehau LINK_STATE_UP : LINK_STATE_DOWN); 109715516c77SSepherosa Ziehau } 109815516c77SSepherosa Ziehau 109915516c77SSepherosa Ziehau static void 110015516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused) 110115516c77SSepherosa Ziehau { 110215516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 110315516c77SSepherosa Ziehau 110415516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 110515516c77SSepherosa Ziehau return; 110615516c77SSepherosa Ziehau hn_link_status(sc); 110715516c77SSepherosa Ziehau } 110815516c77SSepherosa Ziehau 110915516c77SSepherosa Ziehau static void 111015516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused) 111115516c77SSepherosa Ziehau { 111215516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 111315516c77SSepherosa Ziehau 111415516c77SSepherosa Ziehau /* Prevent any link status checks from running. */ 111515516c77SSepherosa Ziehau sc->hn_link_flags |= HN_LINK_FLAG_NETCHG; 111615516c77SSepherosa Ziehau 111715516c77SSepherosa Ziehau /* 111815516c77SSepherosa Ziehau * Fake up a [link down --> link up] state change; 5 seconds 111915516c77SSepherosa Ziehau * delay is used, which closely simulates miibus reaction 112015516c77SSepherosa Ziehau * upon link down event. 112115516c77SSepherosa Ziehau */ 112215516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; 112315516c77SSepherosa Ziehau if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); 112415516c77SSepherosa Ziehau taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0, 112515516c77SSepherosa Ziehau &sc->hn_netchg_status, 5 * hz); 112615516c77SSepherosa Ziehau } 112715516c77SSepherosa Ziehau 112815516c77SSepherosa Ziehau static void 112915516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused) 113015516c77SSepherosa Ziehau { 113115516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 113215516c77SSepherosa Ziehau 113315516c77SSepherosa Ziehau /* Re-allow link status checks. */ 113415516c77SSepherosa Ziehau sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG; 113515516c77SSepherosa Ziehau hn_link_status(sc); 113615516c77SSepherosa Ziehau } 113715516c77SSepherosa Ziehau 113815516c77SSepherosa Ziehau static void 113915516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc) 114015516c77SSepherosa Ziehau { 114115516c77SSepherosa Ziehau 114215516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 114315516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task); 114415516c77SSepherosa Ziehau } 114515516c77SSepherosa Ziehau 114615516c77SSepherosa Ziehau static void 114715516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc) 114815516c77SSepherosa Ziehau { 114915516c77SSepherosa Ziehau 115015516c77SSepherosa Ziehau if (sc->hn_mgmt_taskq != NULL) 115115516c77SSepherosa Ziehau taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init); 115215516c77SSepherosa Ziehau } 115315516c77SSepherosa Ziehau 115415516c77SSepherosa Ziehau static __inline int 115515516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd, 115615516c77SSepherosa Ziehau struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) 115715516c77SSepherosa Ziehau { 115815516c77SSepherosa Ziehau struct mbuf *m = *m_head; 115915516c77SSepherosa Ziehau int error; 116015516c77SSepherosa Ziehau 116115516c77SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim")); 116215516c77SSepherosa Ziehau 116315516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap, 116415516c77SSepherosa Ziehau m, segs, nsegs, BUS_DMA_NOWAIT); 116515516c77SSepherosa Ziehau if (error == EFBIG) { 116615516c77SSepherosa Ziehau struct mbuf *m_new; 116715516c77SSepherosa Ziehau 116815516c77SSepherosa Ziehau m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX); 116915516c77SSepherosa Ziehau if (m_new == NULL) 117015516c77SSepherosa Ziehau return ENOBUFS; 117115516c77SSepherosa Ziehau else 117215516c77SSepherosa Ziehau *m_head = m = m_new; 117315516c77SSepherosa Ziehau txr->hn_tx_collapsed++; 117415516c77SSepherosa Ziehau 117515516c77SSepherosa Ziehau error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, 117615516c77SSepherosa Ziehau txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT); 117715516c77SSepherosa Ziehau } 117815516c77SSepherosa Ziehau if (!error) { 117915516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap, 118015516c77SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 118115516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_DMAMAP; 118215516c77SSepherosa Ziehau } 118315516c77SSepherosa Ziehau return error; 118415516c77SSepherosa Ziehau } 118515516c77SSepherosa Ziehau 118615516c77SSepherosa Ziehau static __inline int 118715516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd) 118815516c77SSepherosa Ziehau { 118915516c77SSepherosa Ziehau 119015516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0, 119115516c77SSepherosa Ziehau ("put an onlist txd %#x", txd->flags)); 119215516c77SSepherosa Ziehau 119315516c77SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); 119415516c77SSepherosa Ziehau if (atomic_fetchadd_int(&txd->refs, -1) != 1) 119515516c77SSepherosa Ziehau return 0; 119615516c77SSepherosa Ziehau 119715516c77SSepherosa Ziehau if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) { 119815516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, 119915516c77SSepherosa Ziehau ("chim txd uses dmamap")); 120015516c77SSepherosa Ziehau hn_chim_free(txr->hn_sc, txd->chim_index); 120115516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 120215516c77SSepherosa Ziehau } else if (txd->flags & HN_TXD_FLAG_DMAMAP) { 120315516c77SSepherosa Ziehau bus_dmamap_sync(txr->hn_tx_data_dtag, 120415516c77SSepherosa Ziehau txd->data_dmap, BUS_DMASYNC_POSTWRITE); 120515516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_data_dtag, 120615516c77SSepherosa Ziehau txd->data_dmap); 120715516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_DMAMAP; 120815516c77SSepherosa Ziehau } 120915516c77SSepherosa Ziehau 121015516c77SSepherosa Ziehau if (txd->m != NULL) { 121115516c77SSepherosa Ziehau m_freem(txd->m); 121215516c77SSepherosa Ziehau txd->m = NULL; 121315516c77SSepherosa Ziehau } 121415516c77SSepherosa Ziehau 121515516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 121615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 121715516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 121815516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail >= 0 && 121915516c77SSepherosa Ziehau txr->hn_txdesc_avail < txr->hn_txdesc_cnt, 122015516c77SSepherosa Ziehau ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail)); 122115516c77SSepherosa Ziehau txr->hn_txdesc_avail++; 122215516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 122315516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 122415516c77SSepherosa Ziehau #else 122515516c77SSepherosa Ziehau atomic_add_int(&txr->hn_txdesc_avail, 1); 122615516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 122715516c77SSepherosa Ziehau #endif 122815516c77SSepherosa Ziehau 122915516c77SSepherosa Ziehau return 1; 123015516c77SSepherosa Ziehau } 123115516c77SSepherosa Ziehau 123215516c77SSepherosa Ziehau static __inline struct hn_txdesc * 123315516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr) 123415516c77SSepherosa Ziehau { 123515516c77SSepherosa Ziehau struct hn_txdesc *txd; 123615516c77SSepherosa Ziehau 123715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 123815516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 123915516c77SSepherosa Ziehau txd = SLIST_FIRST(&txr->hn_txlist); 124015516c77SSepherosa Ziehau if (txd != NULL) { 124115516c77SSepherosa Ziehau KASSERT(txr->hn_txdesc_avail > 0, 124215516c77SSepherosa Ziehau ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail)); 124315516c77SSepherosa Ziehau txr->hn_txdesc_avail--; 124415516c77SSepherosa Ziehau SLIST_REMOVE_HEAD(&txr->hn_txlist, link); 124515516c77SSepherosa Ziehau } 124615516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 124715516c77SSepherosa Ziehau #else 124815516c77SSepherosa Ziehau txd = buf_ring_dequeue_sc(txr->hn_txdesc_br); 124915516c77SSepherosa Ziehau #endif 125015516c77SSepherosa Ziehau 125115516c77SSepherosa Ziehau if (txd != NULL) { 125215516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 125315516c77SSepherosa Ziehau atomic_subtract_int(&txr->hn_txdesc_avail, 1); 125415516c77SSepherosa Ziehau #endif 125515516c77SSepherosa Ziehau KASSERT(txd->m == NULL && txd->refs == 0 && 125615516c77SSepherosa Ziehau txd->chim_index == HN_NVS_CHIM_IDX_INVALID && 125715516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_ONLIST) && 125815516c77SSepherosa Ziehau (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd")); 125915516c77SSepherosa Ziehau txd->flags &= ~HN_TXD_FLAG_ONLIST; 126015516c77SSepherosa Ziehau txd->refs = 1; 126115516c77SSepherosa Ziehau } 126215516c77SSepherosa Ziehau return txd; 126315516c77SSepherosa Ziehau } 126415516c77SSepherosa Ziehau 126515516c77SSepherosa Ziehau static __inline void 126615516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd) 126715516c77SSepherosa Ziehau { 126815516c77SSepherosa Ziehau 126915516c77SSepherosa Ziehau /* 0->1 transition will never work */ 127015516c77SSepherosa Ziehau KASSERT(txd->refs > 0, ("invalid refs %d", txd->refs)); 127115516c77SSepherosa Ziehau atomic_add_int(&txd->refs, 1); 127215516c77SSepherosa Ziehau } 127315516c77SSepherosa Ziehau 127415516c77SSepherosa Ziehau static bool 127515516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr) 127615516c77SSepherosa Ziehau { 127715516c77SSepherosa Ziehau bool pending = false; 127815516c77SSepherosa Ziehau 127915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 128015516c77SSepherosa Ziehau mtx_lock_spin(&txr->hn_txlist_spin); 128115516c77SSepherosa Ziehau if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt) 128215516c77SSepherosa Ziehau pending = true; 128315516c77SSepherosa Ziehau mtx_unlock_spin(&txr->hn_txlist_spin); 128415516c77SSepherosa Ziehau #else 128515516c77SSepherosa Ziehau if (!buf_ring_full(txr->hn_txdesc_br)) 128615516c77SSepherosa Ziehau pending = true; 128715516c77SSepherosa Ziehau #endif 128815516c77SSepherosa Ziehau return (pending); 128915516c77SSepherosa Ziehau } 129015516c77SSepherosa Ziehau 129115516c77SSepherosa Ziehau static __inline void 129215516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr) 129315516c77SSepherosa Ziehau { 129415516c77SSepherosa Ziehau txr->hn_has_txeof = 0; 129515516c77SSepherosa Ziehau txr->hn_txeof(txr); 129615516c77SSepherosa Ziehau } 129715516c77SSepherosa Ziehau 129815516c77SSepherosa Ziehau static void 129915516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc, 130015516c77SSepherosa Ziehau struct vmbus_channel *chan, const void *data __unused, int dlen __unused) 130115516c77SSepherosa Ziehau { 130215516c77SSepherosa Ziehau struct hn_txdesc *txd = sndc->hn_cbarg; 130315516c77SSepherosa Ziehau struct hn_tx_ring *txr; 130415516c77SSepherosa Ziehau 130515516c77SSepherosa Ziehau txr = txd->txr; 130615516c77SSepherosa Ziehau KASSERT(txr->hn_chan == chan, 130715516c77SSepherosa Ziehau ("channel mismatch, on chan%u, should be chan%u", 130815516c77SSepherosa Ziehau vmbus_chan_subidx(chan), vmbus_chan_subidx(txr->hn_chan))); 130915516c77SSepherosa Ziehau 131015516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 131115516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 131215516c77SSepherosa Ziehau 131315516c77SSepherosa Ziehau ++txr->hn_txdone_cnt; 131415516c77SSepherosa Ziehau if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) { 131515516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 131615516c77SSepherosa Ziehau if (txr->hn_oactive) 131715516c77SSepherosa Ziehau hn_txeof(txr); 131815516c77SSepherosa Ziehau } 131915516c77SSepherosa Ziehau } 132015516c77SSepherosa Ziehau 132115516c77SSepherosa Ziehau static void 132215516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr) 132315516c77SSepherosa Ziehau { 132415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 132515516c77SSepherosa Ziehau tcp_lro_flush_all(&rxr->hn_lro); 132615516c77SSepherosa Ziehau #endif 132715516c77SSepherosa Ziehau 132815516c77SSepherosa Ziehau /* 132915516c77SSepherosa Ziehau * NOTE: 133015516c77SSepherosa Ziehau * 'txr' could be NULL, if multiple channels and 133115516c77SSepherosa Ziehau * ifnet.if_start method are enabled. 133215516c77SSepherosa Ziehau */ 133315516c77SSepherosa Ziehau if (txr == NULL || !txr->hn_has_txeof) 133415516c77SSepherosa Ziehau return; 133515516c77SSepherosa Ziehau 133615516c77SSepherosa Ziehau txr->hn_txdone_cnt = 0; 133715516c77SSepherosa Ziehau hn_txeof(txr); 133815516c77SSepherosa Ziehau } 133915516c77SSepherosa Ziehau 134015516c77SSepherosa Ziehau static __inline uint32_t 134115516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs) 134215516c77SSepherosa Ziehau { 134315516c77SSepherosa Ziehau 134415516c77SSepherosa Ziehau KASSERT(ofs >= sizeof(struct rndis_packet_msg), 134515516c77SSepherosa Ziehau ("invalid RNDIS packet msg offset %u", ofs)); 134615516c77SSepherosa Ziehau return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset)); 134715516c77SSepherosa Ziehau } 134815516c77SSepherosa Ziehau 134915516c77SSepherosa Ziehau static __inline void * 135015516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize, 135115516c77SSepherosa Ziehau size_t pi_dlen, uint32_t pi_type) 135215516c77SSepherosa Ziehau { 135315516c77SSepherosa Ziehau const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen); 135415516c77SSepherosa Ziehau struct rndis_pktinfo *pi; 135515516c77SSepherosa Ziehau 135615516c77SSepherosa Ziehau KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0, 135715516c77SSepherosa Ziehau ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen)); 135815516c77SSepherosa Ziehau 135915516c77SSepherosa Ziehau /* 136015516c77SSepherosa Ziehau * Per-packet-info does not move; it only grows. 136115516c77SSepherosa Ziehau * 136215516c77SSepherosa Ziehau * NOTE: 136315516c77SSepherosa Ziehau * rm_pktinfooffset in this phase counts from the beginning 136415516c77SSepherosa Ziehau * of rndis_packet_msg. 136515516c77SSepherosa Ziehau */ 136615516c77SSepherosa Ziehau KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize, 136715516c77SSepherosa Ziehau ("%u pktinfo overflows RNDIS packet msg", pi_type)); 136815516c77SSepherosa Ziehau pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset + 136915516c77SSepherosa Ziehau pkt->rm_pktinfolen); 137015516c77SSepherosa Ziehau pkt->rm_pktinfolen += pi_size; 137115516c77SSepherosa Ziehau 137215516c77SSepherosa Ziehau pi->rm_size = pi_size; 137315516c77SSepherosa Ziehau pi->rm_type = pi_type; 137415516c77SSepherosa Ziehau pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET; 137515516c77SSepherosa Ziehau 137615516c77SSepherosa Ziehau /* Data immediately follow per-packet-info. */ 137715516c77SSepherosa Ziehau pkt->rm_dataoffset += pi_size; 137815516c77SSepherosa Ziehau 137915516c77SSepherosa Ziehau /* Update RNDIS packet msg length */ 138015516c77SSepherosa Ziehau pkt->rm_len += pi_size; 138115516c77SSepherosa Ziehau 138215516c77SSepherosa Ziehau return (pi->rm_data); 138315516c77SSepherosa Ziehau } 138415516c77SSepherosa Ziehau 138515516c77SSepherosa Ziehau /* 138615516c77SSepherosa Ziehau * NOTE: 138715516c77SSepherosa Ziehau * If this function fails, then both txd and m_head0 will be freed. 138815516c77SSepherosa Ziehau */ 138915516c77SSepherosa Ziehau static int 139015516c77SSepherosa Ziehau hn_encap(struct hn_tx_ring *txr, struct hn_txdesc *txd, struct mbuf **m_head0) 139115516c77SSepherosa Ziehau { 139215516c77SSepherosa Ziehau bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX]; 139315516c77SSepherosa Ziehau int error, nsegs, i; 139415516c77SSepherosa Ziehau struct mbuf *m_head = *m_head0; 139515516c77SSepherosa Ziehau struct rndis_packet_msg *pkt; 139615516c77SSepherosa Ziehau uint32_t *pi_data; 1397*8966e5d5SSepherosa Ziehau void *chim = NULL; 139815516c77SSepherosa Ziehau int pktlen; 139915516c77SSepherosa Ziehau 140015516c77SSepherosa Ziehau pkt = txd->rndis_pkt; 1401*8966e5d5SSepherosa Ziehau if (m_head->m_pkthdr.len + HN_RNDIS_PKT_LEN < txr->hn_chim_size) { 1402*8966e5d5SSepherosa Ziehau /* 1403*8966e5d5SSepherosa Ziehau * This packet is small enough to fit into a chimney sending 1404*8966e5d5SSepherosa Ziehau * buffer. Try allocating one chimney sending buffer now. 1405*8966e5d5SSepherosa Ziehau */ 1406*8966e5d5SSepherosa Ziehau txr->hn_tx_chimney_tried++; 1407*8966e5d5SSepherosa Ziehau txd->chim_index = hn_chim_alloc(txr->hn_sc); 1408*8966e5d5SSepherosa Ziehau if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) { 1409*8966e5d5SSepherosa Ziehau chim = txr->hn_sc->hn_chim + 1410*8966e5d5SSepherosa Ziehau (txd->chim_index * txr->hn_sc->hn_chim_szmax); 1411*8966e5d5SSepherosa Ziehau /* 1412*8966e5d5SSepherosa Ziehau * Directly fill the chimney sending buffer w/ the 1413*8966e5d5SSepherosa Ziehau * RNDIS packet message. 1414*8966e5d5SSepherosa Ziehau */ 1415*8966e5d5SSepherosa Ziehau pkt = chim; 1416*8966e5d5SSepherosa Ziehau } 1417*8966e5d5SSepherosa Ziehau } 1418*8966e5d5SSepherosa Ziehau 141915516c77SSepherosa Ziehau pkt->rm_type = REMOTE_NDIS_PACKET_MSG; 142015516c77SSepherosa Ziehau pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len; 142115516c77SSepherosa Ziehau pkt->rm_dataoffset = sizeof(*pkt); 142215516c77SSepherosa Ziehau pkt->rm_datalen = m_head->m_pkthdr.len; 142315516c77SSepherosa Ziehau pkt->rm_pktinfooffset = sizeof(*pkt); 142415516c77SSepherosa Ziehau pkt->rm_pktinfolen = 0; 142515516c77SSepherosa Ziehau 142615516c77SSepherosa Ziehau if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) { 142715516c77SSepherosa Ziehau /* 142815516c77SSepherosa Ziehau * Set the hash value for this packet, so that the host could 142915516c77SSepherosa Ziehau * dispatch the TX done event for this packet back to this TX 143015516c77SSepherosa Ziehau * ring's channel. 143115516c77SSepherosa Ziehau */ 143215516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 143315516c77SSepherosa Ziehau HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL); 143415516c77SSepherosa Ziehau *pi_data = txr->hn_tx_idx; 143515516c77SSepherosa Ziehau } 143615516c77SSepherosa Ziehau 143715516c77SSepherosa Ziehau if (m_head->m_flags & M_VLANTAG) { 143815516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 143915516c77SSepherosa Ziehau NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN); 144015516c77SSepherosa Ziehau *pi_data = NDIS_VLAN_INFO_MAKE( 144115516c77SSepherosa Ziehau EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag), 144215516c77SSepherosa Ziehau EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag), 144315516c77SSepherosa Ziehau EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag)); 144415516c77SSepherosa Ziehau } 144515516c77SSepherosa Ziehau 144615516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 144715516c77SSepherosa Ziehau #if defined(INET6) || defined(INET) 144815516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 144915516c77SSepherosa Ziehau NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); 145015516c77SSepherosa Ziehau #ifdef INET 145115516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { 145215516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV4(0, 145315516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 145415516c77SSepherosa Ziehau } 145515516c77SSepherosa Ziehau #endif 145615516c77SSepherosa Ziehau #if defined(INET6) && defined(INET) 145715516c77SSepherosa Ziehau else 145815516c77SSepherosa Ziehau #endif 145915516c77SSepherosa Ziehau #ifdef INET6 146015516c77SSepherosa Ziehau { 146115516c77SSepherosa Ziehau *pi_data = NDIS_LSO2_INFO_MAKEIPV6(0, 146215516c77SSepherosa Ziehau m_head->m_pkthdr.tso_segsz); 146315516c77SSepherosa Ziehau } 146415516c77SSepherosa Ziehau #endif 146515516c77SSepherosa Ziehau #endif /* INET6 || INET */ 146615516c77SSepherosa Ziehau } else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) { 146715516c77SSepherosa Ziehau pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, 146815516c77SSepherosa Ziehau NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); 146915516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & 147015516c77SSepherosa Ziehau (CSUM_IP6_TCP | CSUM_IP6_UDP)) { 147115516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV6; 147215516c77SSepherosa Ziehau } else { 147315516c77SSepherosa Ziehau *pi_data = NDIS_TXCSUM_INFO_IPV4; 147415516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 147515516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_IPCS; 147615516c77SSepherosa Ziehau } 147715516c77SSepherosa Ziehau 147815516c77SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) 147915516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_TCPCS; 148015516c77SSepherosa Ziehau else if (m_head->m_pkthdr.csum_flags & 148115516c77SSepherosa Ziehau (CSUM_IP_UDP | CSUM_IP6_UDP)) 148215516c77SSepherosa Ziehau *pi_data |= NDIS_TXCSUM_INFO_UDPCS; 148315516c77SSepherosa Ziehau } 148415516c77SSepherosa Ziehau 148515516c77SSepherosa Ziehau pktlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; 148615516c77SSepherosa Ziehau /* Convert RNDIS packet message offsets */ 148715516c77SSepherosa Ziehau pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt->rm_dataoffset); 148815516c77SSepherosa Ziehau pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset); 148915516c77SSepherosa Ziehau 149015516c77SSepherosa Ziehau /* 1491*8966e5d5SSepherosa Ziehau * Fast path: Chimney sending. 149215516c77SSepherosa Ziehau */ 1493*8966e5d5SSepherosa Ziehau if (chim != NULL) { 1494*8966e5d5SSepherosa Ziehau KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID, 1495*8966e5d5SSepherosa Ziehau ("chimney buffer is not used")); 1496*8966e5d5SSepherosa Ziehau KASSERT(pkt == chim, ("RNDIS pkt not in chimney buffer")); 149715516c77SSepherosa Ziehau 1498*8966e5d5SSepherosa Ziehau m_copydata(m_head, 0, m_head->m_pkthdr.len, 1499*8966e5d5SSepherosa Ziehau ((uint8_t *)chim) + pktlen); 150015516c77SSepherosa Ziehau 150115516c77SSepherosa Ziehau txd->chim_size = pkt->rm_len; 150215516c77SSepherosa Ziehau txr->hn_gpa_cnt = 0; 150315516c77SSepherosa Ziehau txr->hn_tx_chimney++; 150415516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_chim; 150515516c77SSepherosa Ziehau goto done; 150615516c77SSepherosa Ziehau } 1507*8966e5d5SSepherosa Ziehau KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, 1508*8966e5d5SSepherosa Ziehau ("chimney buffer is used")); 1509*8966e5d5SSepherosa Ziehau KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc")); 151015516c77SSepherosa Ziehau 151115516c77SSepherosa Ziehau error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs); 151215516c77SSepherosa Ziehau if (error) { 151315516c77SSepherosa Ziehau int freed; 151415516c77SSepherosa Ziehau 151515516c77SSepherosa Ziehau /* 151615516c77SSepherosa Ziehau * This mbuf is not linked w/ the txd yet, so free it now. 151715516c77SSepherosa Ziehau */ 151815516c77SSepherosa Ziehau m_freem(m_head); 151915516c77SSepherosa Ziehau *m_head0 = NULL; 152015516c77SSepherosa Ziehau 152115516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 152215516c77SSepherosa Ziehau KASSERT(freed != 0, 152315516c77SSepherosa Ziehau ("fail to free txd upon txdma error")); 152415516c77SSepherosa Ziehau 152515516c77SSepherosa Ziehau txr->hn_txdma_failed++; 152615516c77SSepherosa Ziehau if_inc_counter(txr->hn_sc->hn_ifp, IFCOUNTER_OERRORS, 1); 152715516c77SSepherosa Ziehau return error; 152815516c77SSepherosa Ziehau } 152915516c77SSepherosa Ziehau *m_head0 = m_head; 153015516c77SSepherosa Ziehau 153115516c77SSepherosa Ziehau /* +1 RNDIS packet message */ 153215516c77SSepherosa Ziehau txr->hn_gpa_cnt = nsegs + 1; 153315516c77SSepherosa Ziehau 153415516c77SSepherosa Ziehau /* send packet with page buffer */ 153515516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr); 153615516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK; 153715516c77SSepherosa Ziehau txr->hn_gpa[0].gpa_len = pktlen; 153815516c77SSepherosa Ziehau 153915516c77SSepherosa Ziehau /* 154015516c77SSepherosa Ziehau * Fill the page buffers with mbuf info after the page 154115516c77SSepherosa Ziehau * buffer for RNDIS packet message. 154215516c77SSepherosa Ziehau */ 154315516c77SSepherosa Ziehau for (i = 0; i < nsegs; ++i) { 154415516c77SSepherosa Ziehau struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1]; 154515516c77SSepherosa Ziehau 154615516c77SSepherosa Ziehau gpa->gpa_page = atop(segs[i].ds_addr); 154715516c77SSepherosa Ziehau gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK; 154815516c77SSepherosa Ziehau gpa->gpa_len = segs[i].ds_len; 154915516c77SSepherosa Ziehau } 155015516c77SSepherosa Ziehau 155115516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 155215516c77SSepherosa Ziehau txd->chim_size = 0; 155315516c77SSepherosa Ziehau txr->hn_sendpkt = hn_txpkt_sglist; 155415516c77SSepherosa Ziehau done: 155515516c77SSepherosa Ziehau txd->m = m_head; 155615516c77SSepherosa Ziehau 155715516c77SSepherosa Ziehau /* Set the completion routine */ 155815516c77SSepherosa Ziehau hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd); 155915516c77SSepherosa Ziehau 156015516c77SSepherosa Ziehau return 0; 156115516c77SSepherosa Ziehau } 156215516c77SSepherosa Ziehau 156315516c77SSepherosa Ziehau /* 156415516c77SSepherosa Ziehau * NOTE: 156515516c77SSepherosa Ziehau * If this function fails, then txd will be freed, but the mbuf 156615516c77SSepherosa Ziehau * associated w/ the txd will _not_ be freed. 156715516c77SSepherosa Ziehau */ 156815516c77SSepherosa Ziehau static int 156915516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd) 157015516c77SSepherosa Ziehau { 157115516c77SSepherosa Ziehau int error, send_failed = 0; 157215516c77SSepherosa Ziehau 157315516c77SSepherosa Ziehau again: 157415516c77SSepherosa Ziehau /* 157515516c77SSepherosa Ziehau * Make sure that txd is not freed before ETHER_BPF_MTAP. 157615516c77SSepherosa Ziehau */ 157715516c77SSepherosa Ziehau hn_txdesc_hold(txd); 157815516c77SSepherosa Ziehau error = txr->hn_sendpkt(txr, txd); 157915516c77SSepherosa Ziehau if (!error) { 158015516c77SSepherosa Ziehau ETHER_BPF_MTAP(ifp, txd->m); 158115516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 158223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 158323bf9e15SSepherosa Ziehau if (!hn_use_if_start) 158423bf9e15SSepherosa Ziehau #endif 158523bf9e15SSepherosa Ziehau { 158615516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OBYTES, 158715516c77SSepherosa Ziehau txd->m->m_pkthdr.len); 158815516c77SSepherosa Ziehau if (txd->m->m_flags & M_MCAST) 158915516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 159015516c77SSepherosa Ziehau } 159115516c77SSepherosa Ziehau txr->hn_pkts++; 159215516c77SSepherosa Ziehau } 159315516c77SSepherosa Ziehau hn_txdesc_put(txr, txd); 159415516c77SSepherosa Ziehau 159515516c77SSepherosa Ziehau if (__predict_false(error)) { 159615516c77SSepherosa Ziehau int freed; 159715516c77SSepherosa Ziehau 159815516c77SSepherosa Ziehau /* 159915516c77SSepherosa Ziehau * This should "really rarely" happen. 160015516c77SSepherosa Ziehau * 160115516c77SSepherosa Ziehau * XXX Too many RX to be acked or too many sideband 160215516c77SSepherosa Ziehau * commands to run? Ask netvsc_channel_rollup() 160315516c77SSepherosa Ziehau * to kick start later. 160415516c77SSepherosa Ziehau */ 160515516c77SSepherosa Ziehau txr->hn_has_txeof = 1; 160615516c77SSepherosa Ziehau if (!send_failed) { 160715516c77SSepherosa Ziehau txr->hn_send_failed++; 160815516c77SSepherosa Ziehau send_failed = 1; 160915516c77SSepherosa Ziehau /* 161015516c77SSepherosa Ziehau * Try sending again after set hn_has_txeof; 161115516c77SSepherosa Ziehau * in case that we missed the last 161215516c77SSepherosa Ziehau * netvsc_channel_rollup(). 161315516c77SSepherosa Ziehau */ 161415516c77SSepherosa Ziehau goto again; 161515516c77SSepherosa Ziehau } 161615516c77SSepherosa Ziehau if_printf(ifp, "send failed\n"); 161715516c77SSepherosa Ziehau 161815516c77SSepherosa Ziehau /* 161915516c77SSepherosa Ziehau * Caller will perform further processing on the 162015516c77SSepherosa Ziehau * associated mbuf, so don't free it in hn_txdesc_put(); 162115516c77SSepherosa Ziehau * only unload it from the DMA map in hn_txdesc_put(), 162215516c77SSepherosa Ziehau * if it was loaded. 162315516c77SSepherosa Ziehau */ 162415516c77SSepherosa Ziehau txd->m = NULL; 162515516c77SSepherosa Ziehau freed = hn_txdesc_put(txr, txd); 162615516c77SSepherosa Ziehau KASSERT(freed != 0, 162715516c77SSepherosa Ziehau ("fail to free txd upon send error")); 162815516c77SSepherosa Ziehau 162915516c77SSepherosa Ziehau txr->hn_send_failed++; 163015516c77SSepherosa Ziehau } 163115516c77SSepherosa Ziehau return error; 163215516c77SSepherosa Ziehau } 163315516c77SSepherosa Ziehau 163415516c77SSepherosa Ziehau /* 163515516c77SSepherosa Ziehau * Append the specified data to the indicated mbuf chain, 163615516c77SSepherosa Ziehau * Extend the mbuf chain if the new data does not fit in 163715516c77SSepherosa Ziehau * existing space. 163815516c77SSepherosa Ziehau * 163915516c77SSepherosa Ziehau * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c. 164015516c77SSepherosa Ziehau * There should be an equivalent in the kernel mbuf code, 164115516c77SSepherosa Ziehau * but there does not appear to be one yet. 164215516c77SSepherosa Ziehau * 164315516c77SSepherosa Ziehau * Differs from m_append() in that additional mbufs are 164415516c77SSepherosa Ziehau * allocated with cluster size MJUMPAGESIZE, and filled 164515516c77SSepherosa Ziehau * accordingly. 164615516c77SSepherosa Ziehau * 164715516c77SSepherosa Ziehau * Return 1 if able to complete the job; otherwise 0. 164815516c77SSepherosa Ziehau */ 164915516c77SSepherosa Ziehau static int 165015516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp) 165115516c77SSepherosa Ziehau { 165215516c77SSepherosa Ziehau struct mbuf *m, *n; 165315516c77SSepherosa Ziehau int remainder, space; 165415516c77SSepherosa Ziehau 165515516c77SSepherosa Ziehau for (m = m0; m->m_next != NULL; m = m->m_next) 165615516c77SSepherosa Ziehau ; 165715516c77SSepherosa Ziehau remainder = len; 165815516c77SSepherosa Ziehau space = M_TRAILINGSPACE(m); 165915516c77SSepherosa Ziehau if (space > 0) { 166015516c77SSepherosa Ziehau /* 166115516c77SSepherosa Ziehau * Copy into available space. 166215516c77SSepherosa Ziehau */ 166315516c77SSepherosa Ziehau if (space > remainder) 166415516c77SSepherosa Ziehau space = remainder; 166515516c77SSepherosa Ziehau bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 166615516c77SSepherosa Ziehau m->m_len += space; 166715516c77SSepherosa Ziehau cp += space; 166815516c77SSepherosa Ziehau remainder -= space; 166915516c77SSepherosa Ziehau } 167015516c77SSepherosa Ziehau while (remainder > 0) { 167115516c77SSepherosa Ziehau /* 167215516c77SSepherosa Ziehau * Allocate a new mbuf; could check space 167315516c77SSepherosa Ziehau * and allocate a cluster instead. 167415516c77SSepherosa Ziehau */ 167515516c77SSepherosa Ziehau n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE); 167615516c77SSepherosa Ziehau if (n == NULL) 167715516c77SSepherosa Ziehau break; 167815516c77SSepherosa Ziehau n->m_len = min(MJUMPAGESIZE, remainder); 167915516c77SSepherosa Ziehau bcopy(cp, mtod(n, caddr_t), n->m_len); 168015516c77SSepherosa Ziehau cp += n->m_len; 168115516c77SSepherosa Ziehau remainder -= n->m_len; 168215516c77SSepherosa Ziehau m->m_next = n; 168315516c77SSepherosa Ziehau m = n; 168415516c77SSepherosa Ziehau } 168515516c77SSepherosa Ziehau if (m0->m_flags & M_PKTHDR) 168615516c77SSepherosa Ziehau m0->m_pkthdr.len += len - remainder; 168715516c77SSepherosa Ziehau 168815516c77SSepherosa Ziehau return (remainder == 0); 168915516c77SSepherosa Ziehau } 169015516c77SSepherosa Ziehau 169115516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 169215516c77SSepherosa Ziehau static __inline int 169315516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m) 169415516c77SSepherosa Ziehau { 169515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 169615516c77SSepherosa Ziehau if (hn_lro_mbufq_depth) { 169715516c77SSepherosa Ziehau tcp_lro_queue_mbuf(lc, m); 169815516c77SSepherosa Ziehau return 0; 169915516c77SSepherosa Ziehau } 170015516c77SSepherosa Ziehau #endif 170115516c77SSepherosa Ziehau return tcp_lro_rx(lc, m, 0); 170215516c77SSepherosa Ziehau } 170315516c77SSepherosa Ziehau #endif 170415516c77SSepherosa Ziehau 170515516c77SSepherosa Ziehau static int 170615516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, 170715516c77SSepherosa Ziehau const struct hn_rxinfo *info) 170815516c77SSepherosa Ziehau { 170915516c77SSepherosa Ziehau struct ifnet *ifp = rxr->hn_ifp; 171015516c77SSepherosa Ziehau struct mbuf *m_new; 171115516c77SSepherosa Ziehau int size, do_lro = 0, do_csum = 1; 171215516c77SSepherosa Ziehau int hash_type; 171315516c77SSepherosa Ziehau 171415516c77SSepherosa Ziehau if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 171515516c77SSepherosa Ziehau return (0); 171615516c77SSepherosa Ziehau 171715516c77SSepherosa Ziehau /* 171815516c77SSepherosa Ziehau * Bail out if packet contains more data than configured MTU. 171915516c77SSepherosa Ziehau */ 172015516c77SSepherosa Ziehau if (dlen > (ifp->if_mtu + ETHER_HDR_LEN)) { 172115516c77SSepherosa Ziehau return (0); 172215516c77SSepherosa Ziehau } else if (dlen <= MHLEN) { 172315516c77SSepherosa Ziehau m_new = m_gethdr(M_NOWAIT, MT_DATA); 172415516c77SSepherosa Ziehau if (m_new == NULL) { 172515516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 172615516c77SSepherosa Ziehau return (0); 172715516c77SSepherosa Ziehau } 172815516c77SSepherosa Ziehau memcpy(mtod(m_new, void *), data, dlen); 172915516c77SSepherosa Ziehau m_new->m_pkthdr.len = m_new->m_len = dlen; 173015516c77SSepherosa Ziehau rxr->hn_small_pkts++; 173115516c77SSepherosa Ziehau } else { 173215516c77SSepherosa Ziehau /* 173315516c77SSepherosa Ziehau * Get an mbuf with a cluster. For packets 2K or less, 173415516c77SSepherosa Ziehau * get a standard 2K cluster. For anything larger, get a 173515516c77SSepherosa Ziehau * 4K cluster. Any buffers larger than 4K can cause problems 173615516c77SSepherosa Ziehau * if looped around to the Hyper-V TX channel, so avoid them. 173715516c77SSepherosa Ziehau */ 173815516c77SSepherosa Ziehau size = MCLBYTES; 173915516c77SSepherosa Ziehau if (dlen > MCLBYTES) { 174015516c77SSepherosa Ziehau /* 4096 */ 174115516c77SSepherosa Ziehau size = MJUMPAGESIZE; 174215516c77SSepherosa Ziehau } 174315516c77SSepherosa Ziehau 174415516c77SSepherosa Ziehau m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size); 174515516c77SSepherosa Ziehau if (m_new == NULL) { 174615516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 174715516c77SSepherosa Ziehau return (0); 174815516c77SSepherosa Ziehau } 174915516c77SSepherosa Ziehau 175015516c77SSepherosa Ziehau hv_m_append(m_new, dlen, data); 175115516c77SSepherosa Ziehau } 175215516c77SSepherosa Ziehau m_new->m_pkthdr.rcvif = ifp; 175315516c77SSepherosa Ziehau 175415516c77SSepherosa Ziehau if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0)) 175515516c77SSepherosa Ziehau do_csum = 0; 175615516c77SSepherosa Ziehau 175715516c77SSepherosa Ziehau /* receive side checksum offload */ 175815516c77SSepherosa Ziehau if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) { 175915516c77SSepherosa Ziehau /* IP csum offload */ 176015516c77SSepherosa Ziehau if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) { 176115516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 176215516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 176315516c77SSepherosa Ziehau rxr->hn_csum_ip++; 176415516c77SSepherosa Ziehau } 176515516c77SSepherosa Ziehau 176615516c77SSepherosa Ziehau /* TCP/UDP csum offload */ 176715516c77SSepherosa Ziehau if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK | 176815516c77SSepherosa Ziehau NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) { 176915516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 177015516c77SSepherosa Ziehau (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 177115516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 177215516c77SSepherosa Ziehau if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK) 177315516c77SSepherosa Ziehau rxr->hn_csum_tcp++; 177415516c77SSepherosa Ziehau else 177515516c77SSepherosa Ziehau rxr->hn_csum_udp++; 177615516c77SSepherosa Ziehau } 177715516c77SSepherosa Ziehau 177815516c77SSepherosa Ziehau /* 177915516c77SSepherosa Ziehau * XXX 178015516c77SSepherosa Ziehau * As of this write (Oct 28th, 2016), host side will turn 178115516c77SSepherosa Ziehau * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so 178215516c77SSepherosa Ziehau * the do_lro setting here is actually _not_ accurate. We 178315516c77SSepherosa Ziehau * depend on the RSS hash type check to reset do_lro. 178415516c77SSepherosa Ziehau */ 178515516c77SSepherosa Ziehau if ((info->csum_info & 178615516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) == 178715516c77SSepherosa Ziehau (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) 178815516c77SSepherosa Ziehau do_lro = 1; 178915516c77SSepherosa Ziehau } else { 179015516c77SSepherosa Ziehau const struct ether_header *eh; 179115516c77SSepherosa Ziehau uint16_t etype; 179215516c77SSepherosa Ziehau int hoff; 179315516c77SSepherosa Ziehau 179415516c77SSepherosa Ziehau hoff = sizeof(*eh); 179515516c77SSepherosa Ziehau if (m_new->m_len < hoff) 179615516c77SSepherosa Ziehau goto skip; 179715516c77SSepherosa Ziehau eh = mtod(m_new, struct ether_header *); 179815516c77SSepherosa Ziehau etype = ntohs(eh->ether_type); 179915516c77SSepherosa Ziehau if (etype == ETHERTYPE_VLAN) { 180015516c77SSepherosa Ziehau const struct ether_vlan_header *evl; 180115516c77SSepherosa Ziehau 180215516c77SSepherosa Ziehau hoff = sizeof(*evl); 180315516c77SSepherosa Ziehau if (m_new->m_len < hoff) 180415516c77SSepherosa Ziehau goto skip; 180515516c77SSepherosa Ziehau evl = mtod(m_new, struct ether_vlan_header *); 180615516c77SSepherosa Ziehau etype = ntohs(evl->evl_proto); 180715516c77SSepherosa Ziehau } 180815516c77SSepherosa Ziehau 180915516c77SSepherosa Ziehau if (etype == ETHERTYPE_IP) { 181015516c77SSepherosa Ziehau int pr; 181115516c77SSepherosa Ziehau 181215516c77SSepherosa Ziehau pr = hn_check_iplen(m_new, hoff); 181315516c77SSepherosa Ziehau if (pr == IPPROTO_TCP) { 181415516c77SSepherosa Ziehau if (do_csum && 181515516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 181615516c77SSepherosa Ziehau HN_TRUST_HCSUM_TCP)) { 181715516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 181815516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 181915516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 182015516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 182115516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 182215516c77SSepherosa Ziehau } 182315516c77SSepherosa Ziehau do_lro = 1; 182415516c77SSepherosa Ziehau } else if (pr == IPPROTO_UDP) { 182515516c77SSepherosa Ziehau if (do_csum && 182615516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & 182715516c77SSepherosa Ziehau HN_TRUST_HCSUM_UDP)) { 182815516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 182915516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 183015516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID | 183115516c77SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 183215516c77SSepherosa Ziehau m_new->m_pkthdr.csum_data = 0xffff; 183315516c77SSepherosa Ziehau } 183415516c77SSepherosa Ziehau } else if (pr != IPPROTO_DONE && do_csum && 183515516c77SSepherosa Ziehau (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) { 183615516c77SSepherosa Ziehau rxr->hn_csum_trusted++; 183715516c77SSepherosa Ziehau m_new->m_pkthdr.csum_flags |= 183815516c77SSepherosa Ziehau (CSUM_IP_CHECKED | CSUM_IP_VALID); 183915516c77SSepherosa Ziehau } 184015516c77SSepherosa Ziehau } 184115516c77SSepherosa Ziehau } 184215516c77SSepherosa Ziehau skip: 184315516c77SSepherosa Ziehau if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) { 184415516c77SSepherosa Ziehau m_new->m_pkthdr.ether_vtag = EVL_MAKETAG( 184515516c77SSepherosa Ziehau NDIS_VLAN_INFO_ID(info->vlan_info), 184615516c77SSepherosa Ziehau NDIS_VLAN_INFO_PRI(info->vlan_info), 184715516c77SSepherosa Ziehau NDIS_VLAN_INFO_CFI(info->vlan_info)); 184815516c77SSepherosa Ziehau m_new->m_flags |= M_VLANTAG; 184915516c77SSepherosa Ziehau } 185015516c77SSepherosa Ziehau 185115516c77SSepherosa Ziehau if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) { 185215516c77SSepherosa Ziehau rxr->hn_rss_pkts++; 185315516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = info->hash_value; 185415516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE_HASH; 185515516c77SSepherosa Ziehau if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) == 185615516c77SSepherosa Ziehau NDIS_HASH_FUNCTION_TOEPLITZ) { 185715516c77SSepherosa Ziehau uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK); 185815516c77SSepherosa Ziehau 185915516c77SSepherosa Ziehau /* 186015516c77SSepherosa Ziehau * NOTE: 186115516c77SSepherosa Ziehau * do_lro is resetted, if the hash types are not TCP 186215516c77SSepherosa Ziehau * related. See the comment in the above csum_flags 186315516c77SSepherosa Ziehau * setup section. 186415516c77SSepherosa Ziehau */ 186515516c77SSepherosa Ziehau switch (type) { 186615516c77SSepherosa Ziehau case NDIS_HASH_IPV4: 186715516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV4; 186815516c77SSepherosa Ziehau do_lro = 0; 186915516c77SSepherosa Ziehau break; 187015516c77SSepherosa Ziehau 187115516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV4: 187215516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV4; 187315516c77SSepherosa Ziehau break; 187415516c77SSepherosa Ziehau 187515516c77SSepherosa Ziehau case NDIS_HASH_IPV6: 187615516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6; 187715516c77SSepherosa Ziehau do_lro = 0; 187815516c77SSepherosa Ziehau break; 187915516c77SSepherosa Ziehau 188015516c77SSepherosa Ziehau case NDIS_HASH_IPV6_EX: 188115516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_IPV6_EX; 188215516c77SSepherosa Ziehau do_lro = 0; 188315516c77SSepherosa Ziehau break; 188415516c77SSepherosa Ziehau 188515516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6: 188615516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6; 188715516c77SSepherosa Ziehau break; 188815516c77SSepherosa Ziehau 188915516c77SSepherosa Ziehau case NDIS_HASH_TCP_IPV6_EX: 189015516c77SSepherosa Ziehau hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX; 189115516c77SSepherosa Ziehau break; 189215516c77SSepherosa Ziehau } 189315516c77SSepherosa Ziehau } 189415516c77SSepherosa Ziehau } else { 189515516c77SSepherosa Ziehau m_new->m_pkthdr.flowid = rxr->hn_rx_idx; 189615516c77SSepherosa Ziehau hash_type = M_HASHTYPE_OPAQUE; 189715516c77SSepherosa Ziehau } 189815516c77SSepherosa Ziehau M_HASHTYPE_SET(m_new, hash_type); 189915516c77SSepherosa Ziehau 190015516c77SSepherosa Ziehau /* 190115516c77SSepherosa Ziehau * Note: Moved RX completion back to hv_nv_on_receive() so all 190215516c77SSepherosa Ziehau * messages (not just data messages) will trigger a response. 190315516c77SSepherosa Ziehau */ 190415516c77SSepherosa Ziehau 190515516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 190615516c77SSepherosa Ziehau rxr->hn_pkts++; 190715516c77SSepherosa Ziehau 190815516c77SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_LRO) && do_lro) { 190915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 191015516c77SSepherosa Ziehau struct lro_ctrl *lro = &rxr->hn_lro; 191115516c77SSepherosa Ziehau 191215516c77SSepherosa Ziehau if (lro->lro_cnt) { 191315516c77SSepherosa Ziehau rxr->hn_lro_tried++; 191415516c77SSepherosa Ziehau if (hn_lro_rx(lro, m_new) == 0) { 191515516c77SSepherosa Ziehau /* DONE! */ 191615516c77SSepherosa Ziehau return 0; 191715516c77SSepherosa Ziehau } 191815516c77SSepherosa Ziehau } 191915516c77SSepherosa Ziehau #endif 192015516c77SSepherosa Ziehau } 192115516c77SSepherosa Ziehau 192215516c77SSepherosa Ziehau /* We're not holding the lock here, so don't release it */ 192315516c77SSepherosa Ziehau (*ifp->if_input)(ifp, m_new); 192415516c77SSepherosa Ziehau 192515516c77SSepherosa Ziehau return (0); 192615516c77SSepherosa Ziehau } 192715516c77SSepherosa Ziehau 192815516c77SSepherosa Ziehau static int 192915516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 193015516c77SSepherosa Ziehau { 193115516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 193215516c77SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data; 193315516c77SSepherosa Ziehau int mask, error = 0; 193415516c77SSepherosa Ziehau 193515516c77SSepherosa Ziehau switch (cmd) { 193615516c77SSepherosa Ziehau case SIOCSIFMTU: 193715516c77SSepherosa Ziehau if (ifr->ifr_mtu > HN_MTU_MAX) { 193815516c77SSepherosa Ziehau error = EINVAL; 193915516c77SSepherosa Ziehau break; 194015516c77SSepherosa Ziehau } 194115516c77SSepherosa Ziehau 194215516c77SSepherosa Ziehau HN_LOCK(sc); 194315516c77SSepherosa Ziehau 194415516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 194515516c77SSepherosa Ziehau HN_UNLOCK(sc); 194615516c77SSepherosa Ziehau break; 194715516c77SSepherosa Ziehau } 194815516c77SSepherosa Ziehau 194915516c77SSepherosa Ziehau if ((sc->hn_caps & HN_CAP_MTU) == 0) { 195015516c77SSepherosa Ziehau /* Can't change MTU */ 195115516c77SSepherosa Ziehau HN_UNLOCK(sc); 195215516c77SSepherosa Ziehau error = EOPNOTSUPP; 195315516c77SSepherosa Ziehau break; 195415516c77SSepherosa Ziehau } 195515516c77SSepherosa Ziehau 195615516c77SSepherosa Ziehau if (ifp->if_mtu == ifr->ifr_mtu) { 195715516c77SSepherosa Ziehau HN_UNLOCK(sc); 195815516c77SSepherosa Ziehau break; 195915516c77SSepherosa Ziehau } 196015516c77SSepherosa Ziehau 196115516c77SSepherosa Ziehau /* 196215516c77SSepherosa Ziehau * Suspend this interface before the synthetic parts 196315516c77SSepherosa Ziehau * are ripped. 196415516c77SSepherosa Ziehau */ 196515516c77SSepherosa Ziehau hn_suspend(sc); 196615516c77SSepherosa Ziehau 196715516c77SSepherosa Ziehau /* 196815516c77SSepherosa Ziehau * Detach the synthetics parts, i.e. NVS and RNDIS. 196915516c77SSepherosa Ziehau */ 197015516c77SSepherosa Ziehau hn_synth_detach(sc); 197115516c77SSepherosa Ziehau 197215516c77SSepherosa Ziehau /* 197315516c77SSepherosa Ziehau * Reattach the synthetic parts, i.e. NVS and RNDIS, 197415516c77SSepherosa Ziehau * with the new MTU setting. 197515516c77SSepherosa Ziehau */ 197615516c77SSepherosa Ziehau error = hn_synth_attach(sc, ifr->ifr_mtu); 197715516c77SSepherosa Ziehau if (error) { 197815516c77SSepherosa Ziehau HN_UNLOCK(sc); 197915516c77SSepherosa Ziehau break; 198015516c77SSepherosa Ziehau } 198115516c77SSepherosa Ziehau 198215516c77SSepherosa Ziehau /* 198315516c77SSepherosa Ziehau * Commit the requested MTU, after the synthetic parts 198415516c77SSepherosa Ziehau * have been successfully attached. 198515516c77SSepherosa Ziehau */ 198615516c77SSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 198715516c77SSepherosa Ziehau 198815516c77SSepherosa Ziehau /* 198915516c77SSepherosa Ziehau * Make sure that various parameters based on MTU are 199015516c77SSepherosa Ziehau * still valid, after the MTU change. 199115516c77SSepherosa Ziehau */ 199215516c77SSepherosa Ziehau if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax) 199315516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 199415516c77SSepherosa Ziehau hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu); 199515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 199615516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < 199715516c77SSepherosa Ziehau HN_LRO_LENLIM_MIN(ifp)) 199815516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp)); 199915516c77SSepherosa Ziehau #endif 200015516c77SSepherosa Ziehau 200115516c77SSepherosa Ziehau /* 200215516c77SSepherosa Ziehau * All done! Resume the interface now. 200315516c77SSepherosa Ziehau */ 200415516c77SSepherosa Ziehau hn_resume(sc); 200515516c77SSepherosa Ziehau 200615516c77SSepherosa Ziehau HN_UNLOCK(sc); 200715516c77SSepherosa Ziehau break; 200815516c77SSepherosa Ziehau 200915516c77SSepherosa Ziehau case SIOCSIFFLAGS: 201015516c77SSepherosa Ziehau HN_LOCK(sc); 201115516c77SSepherosa Ziehau 201215516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 201315516c77SSepherosa Ziehau HN_UNLOCK(sc); 201415516c77SSepherosa Ziehau break; 201515516c77SSepherosa Ziehau } 201615516c77SSepherosa Ziehau 201715516c77SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 201815516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 201915516c77SSepherosa Ziehau hn_set_rxfilter(sc); 202015516c77SSepherosa Ziehau else 202115516c77SSepherosa Ziehau hn_init_locked(sc); 202215516c77SSepherosa Ziehau } else { 202315516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 202415516c77SSepherosa Ziehau hn_stop(sc); 202515516c77SSepherosa Ziehau } 202615516c77SSepherosa Ziehau sc->hn_if_flags = ifp->if_flags; 202715516c77SSepherosa Ziehau 202815516c77SSepherosa Ziehau HN_UNLOCK(sc); 202915516c77SSepherosa Ziehau break; 203015516c77SSepherosa Ziehau 203115516c77SSepherosa Ziehau case SIOCSIFCAP: 203215516c77SSepherosa Ziehau HN_LOCK(sc); 203315516c77SSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable; 203415516c77SSepherosa Ziehau 203515516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM) { 203615516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 203715516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 203815516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc); 203915516c77SSepherosa Ziehau else 204015516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc); 204115516c77SSepherosa Ziehau } 204215516c77SSepherosa Ziehau if (mask & IFCAP_TXCSUM_IPV6) { 204315516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 204415516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 204515516c77SSepherosa Ziehau ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc); 204615516c77SSepherosa Ziehau else 204715516c77SSepherosa Ziehau ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc); 204815516c77SSepherosa Ziehau } 204915516c77SSepherosa Ziehau 205015516c77SSepherosa Ziehau /* TODO: flip RNDIS offload parameters for RXCSUM. */ 205115516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 205215516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 205315516c77SSepherosa Ziehau #ifdef foo 205415516c77SSepherosa Ziehau /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 205515516c77SSepherosa Ziehau if (mask & IFCAP_RXCSUM_IPV6) 205615516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 205715516c77SSepherosa Ziehau #endif 205815516c77SSepherosa Ziehau 205915516c77SSepherosa Ziehau if (mask & IFCAP_LRO) 206015516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_LRO; 206115516c77SSepherosa Ziehau 206215516c77SSepherosa Ziehau if (mask & IFCAP_TSO4) { 206315516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO4; 206415516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO4) 206515516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP_TSO; 206615516c77SSepherosa Ziehau else 206715516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP_TSO; 206815516c77SSepherosa Ziehau } 206915516c77SSepherosa Ziehau if (mask & IFCAP_TSO6) { 207015516c77SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO6; 207115516c77SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO6) 207215516c77SSepherosa Ziehau ifp->if_hwassist |= CSUM_IP6_TSO; 207315516c77SSepherosa Ziehau else 207415516c77SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_IP6_TSO; 207515516c77SSepherosa Ziehau } 207615516c77SSepherosa Ziehau 207715516c77SSepherosa Ziehau HN_UNLOCK(sc); 207815516c77SSepherosa Ziehau break; 207915516c77SSepherosa Ziehau 208015516c77SSepherosa Ziehau case SIOCADDMULTI: 208115516c77SSepherosa Ziehau case SIOCDELMULTI: 208215516c77SSepherosa Ziehau #ifdef notyet 208315516c77SSepherosa Ziehau /* 208415516c77SSepherosa Ziehau * XXX 208515516c77SSepherosa Ziehau * Multicast uses mutex, while RNDIS RX filter setting 208615516c77SSepherosa Ziehau * sleeps. We workaround this by always enabling 208715516c77SSepherosa Ziehau * ALLMULTI. ALLMULTI would actually always be on, even 208815516c77SSepherosa Ziehau * if we supported the SIOCADDMULTI/SIOCDELMULTI, since 208915516c77SSepherosa Ziehau * we don't support multicast address list configuration 209015516c77SSepherosa Ziehau * for this driver. 209115516c77SSepherosa Ziehau */ 209215516c77SSepherosa Ziehau HN_LOCK(sc); 209315516c77SSepherosa Ziehau 209415516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { 209515516c77SSepherosa Ziehau HN_UNLOCK(sc); 209615516c77SSepherosa Ziehau break; 209715516c77SSepherosa Ziehau } 209815516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 209915516c77SSepherosa Ziehau hn_set_rxfilter(sc); 210015516c77SSepherosa Ziehau 210115516c77SSepherosa Ziehau HN_UNLOCK(sc); 210215516c77SSepherosa Ziehau #endif 210315516c77SSepherosa Ziehau break; 210415516c77SSepherosa Ziehau 210515516c77SSepherosa Ziehau case SIOCSIFMEDIA: 210615516c77SSepherosa Ziehau case SIOCGIFMEDIA: 210715516c77SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd); 210815516c77SSepherosa Ziehau break; 210915516c77SSepherosa Ziehau 211015516c77SSepherosa Ziehau default: 211115516c77SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 211215516c77SSepherosa Ziehau break; 211315516c77SSepherosa Ziehau } 211415516c77SSepherosa Ziehau return (error); 211515516c77SSepherosa Ziehau } 211615516c77SSepherosa Ziehau 211715516c77SSepherosa Ziehau static void 211815516c77SSepherosa Ziehau hn_stop(struct hn_softc *sc) 211915516c77SSepherosa Ziehau { 212015516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 212115516c77SSepherosa Ziehau int i; 212215516c77SSepherosa Ziehau 212315516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 212415516c77SSepherosa Ziehau 212515516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 212615516c77SSepherosa Ziehau ("synthetic parts were not attached")); 212715516c77SSepherosa Ziehau 212815516c77SSepherosa Ziehau /* Clear RUNNING bit _before_ hn_suspend_data() */ 212915516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 213015516c77SSepherosa Ziehau hn_suspend_data(sc); 213115516c77SSepherosa Ziehau 213215516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 213315516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 213415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 213515516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 213615516c77SSepherosa Ziehau } 213715516c77SSepherosa Ziehau 213815516c77SSepherosa Ziehau static void 213915516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc) 214015516c77SSepherosa Ziehau { 214115516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 214215516c77SSepherosa Ziehau int i; 214315516c77SSepherosa Ziehau 214415516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 214515516c77SSepherosa Ziehau 214615516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) 214715516c77SSepherosa Ziehau return; 214815516c77SSepherosa Ziehau 214915516c77SSepherosa Ziehau if (ifp->if_drv_flags & IFF_DRV_RUNNING) 215015516c77SSepherosa Ziehau return; 215115516c77SSepherosa Ziehau 215215516c77SSepherosa Ziehau /* Configure RX filter */ 215315516c77SSepherosa Ziehau hn_set_rxfilter(sc); 215415516c77SSepherosa Ziehau 215515516c77SSepherosa Ziehau /* Clear OACTIVE bit. */ 215615516c77SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 215715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 215815516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_oactive = 0; 215915516c77SSepherosa Ziehau 216015516c77SSepherosa Ziehau /* Clear TX 'suspended' bit. */ 216115516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_inuse); 216215516c77SSepherosa Ziehau 216315516c77SSepherosa Ziehau /* Everything is ready; unleash! */ 216415516c77SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 216515516c77SSepherosa Ziehau } 216615516c77SSepherosa Ziehau 216715516c77SSepherosa Ziehau static void 216815516c77SSepherosa Ziehau hn_init(void *xsc) 216915516c77SSepherosa Ziehau { 217015516c77SSepherosa Ziehau struct hn_softc *sc = xsc; 217115516c77SSepherosa Ziehau 217215516c77SSepherosa Ziehau HN_LOCK(sc); 217315516c77SSepherosa Ziehau hn_init_locked(sc); 217415516c77SSepherosa Ziehau HN_UNLOCK(sc); 217515516c77SSepherosa Ziehau } 217615516c77SSepherosa Ziehau 217715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 217815516c77SSepherosa Ziehau 217915516c77SSepherosa Ziehau static int 218015516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS) 218115516c77SSepherosa Ziehau { 218215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 218315516c77SSepherosa Ziehau unsigned int lenlim; 218415516c77SSepherosa Ziehau int error; 218515516c77SSepherosa Ziehau 218615516c77SSepherosa Ziehau lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim; 218715516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &lenlim, 0, req); 218815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 218915516c77SSepherosa Ziehau return error; 219015516c77SSepherosa Ziehau 219115516c77SSepherosa Ziehau HN_LOCK(sc); 219215516c77SSepherosa Ziehau if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) || 219315516c77SSepherosa Ziehau lenlim > TCP_LRO_LENGTH_MAX) { 219415516c77SSepherosa Ziehau HN_UNLOCK(sc); 219515516c77SSepherosa Ziehau return EINVAL; 219615516c77SSepherosa Ziehau } 219715516c77SSepherosa Ziehau hn_set_lro_lenlim(sc, lenlim); 219815516c77SSepherosa Ziehau HN_UNLOCK(sc); 219915516c77SSepherosa Ziehau 220015516c77SSepherosa Ziehau return 0; 220115516c77SSepherosa Ziehau } 220215516c77SSepherosa Ziehau 220315516c77SSepherosa Ziehau static int 220415516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS) 220515516c77SSepherosa Ziehau { 220615516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 220715516c77SSepherosa Ziehau int ackcnt, error, i; 220815516c77SSepherosa Ziehau 220915516c77SSepherosa Ziehau /* 221015516c77SSepherosa Ziehau * lro_ackcnt_lim is append count limit, 221115516c77SSepherosa Ziehau * +1 to turn it into aggregation limit. 221215516c77SSepherosa Ziehau */ 221315516c77SSepherosa Ziehau ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1; 221415516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &ackcnt, 0, req); 221515516c77SSepherosa Ziehau if (error || req->newptr == NULL) 221615516c77SSepherosa Ziehau return error; 221715516c77SSepherosa Ziehau 221815516c77SSepherosa Ziehau if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1)) 221915516c77SSepherosa Ziehau return EINVAL; 222015516c77SSepherosa Ziehau 222115516c77SSepherosa Ziehau /* 222215516c77SSepherosa Ziehau * Convert aggregation limit back to append 222315516c77SSepherosa Ziehau * count limit. 222415516c77SSepherosa Ziehau */ 222515516c77SSepherosa Ziehau --ackcnt; 222615516c77SSepherosa Ziehau HN_LOCK(sc); 222715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) 222815516c77SSepherosa Ziehau sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt; 222915516c77SSepherosa Ziehau HN_UNLOCK(sc); 223015516c77SSepherosa Ziehau return 0; 223115516c77SSepherosa Ziehau } 223215516c77SSepherosa Ziehau 223315516c77SSepherosa Ziehau #endif 223415516c77SSepherosa Ziehau 223515516c77SSepherosa Ziehau static int 223615516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS) 223715516c77SSepherosa Ziehau { 223815516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 223915516c77SSepherosa Ziehau int hcsum = arg2; 224015516c77SSepherosa Ziehau int on, error, i; 224115516c77SSepherosa Ziehau 224215516c77SSepherosa Ziehau on = 0; 224315516c77SSepherosa Ziehau if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum) 224415516c77SSepherosa Ziehau on = 1; 224515516c77SSepherosa Ziehau 224615516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &on, 0, req); 224715516c77SSepherosa Ziehau if (error || req->newptr == NULL) 224815516c77SSepherosa Ziehau return error; 224915516c77SSepherosa Ziehau 225015516c77SSepherosa Ziehau HN_LOCK(sc); 225115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) { 225215516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 225315516c77SSepherosa Ziehau 225415516c77SSepherosa Ziehau if (on) 225515516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= hcsum; 225615516c77SSepherosa Ziehau else 225715516c77SSepherosa Ziehau rxr->hn_trust_hcsum &= ~hcsum; 225815516c77SSepherosa Ziehau } 225915516c77SSepherosa Ziehau HN_UNLOCK(sc); 226015516c77SSepherosa Ziehau return 0; 226115516c77SSepherosa Ziehau } 226215516c77SSepherosa Ziehau 226315516c77SSepherosa Ziehau static int 226415516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS) 226515516c77SSepherosa Ziehau { 226615516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 226715516c77SSepherosa Ziehau int chim_size, error; 226815516c77SSepherosa Ziehau 226915516c77SSepherosa Ziehau chim_size = sc->hn_tx_ring[0].hn_chim_size; 227015516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &chim_size, 0, req); 227115516c77SSepherosa Ziehau if (error || req->newptr == NULL) 227215516c77SSepherosa Ziehau return error; 227315516c77SSepherosa Ziehau 227415516c77SSepherosa Ziehau if (chim_size > sc->hn_chim_szmax || chim_size <= 0) 227515516c77SSepherosa Ziehau return EINVAL; 227615516c77SSepherosa Ziehau 227715516c77SSepherosa Ziehau HN_LOCK(sc); 227815516c77SSepherosa Ziehau hn_set_chim_size(sc, chim_size); 227915516c77SSepherosa Ziehau HN_UNLOCK(sc); 228015516c77SSepherosa Ziehau return 0; 228115516c77SSepherosa Ziehau } 228215516c77SSepherosa Ziehau 228315516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 228415516c77SSepherosa Ziehau static int 228515516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS) 228615516c77SSepherosa Ziehau { 228715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 228815516c77SSepherosa Ziehau int ofs = arg2, i, error; 228915516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 229015516c77SSepherosa Ziehau uint64_t stat; 229115516c77SSepherosa Ziehau 229215516c77SSepherosa Ziehau stat = 0; 229315516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 229415516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 229515516c77SSepherosa Ziehau stat += *((int *)((uint8_t *)rxr + ofs)); 229615516c77SSepherosa Ziehau } 229715516c77SSepherosa Ziehau 229815516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 229915516c77SSepherosa Ziehau if (error || req->newptr == NULL) 230015516c77SSepherosa Ziehau return error; 230115516c77SSepherosa Ziehau 230215516c77SSepherosa Ziehau /* Zero out this stat. */ 230315516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 230415516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 230515516c77SSepherosa Ziehau *((int *)((uint8_t *)rxr + ofs)) = 0; 230615516c77SSepherosa Ziehau } 230715516c77SSepherosa Ziehau return 0; 230815516c77SSepherosa Ziehau } 230915516c77SSepherosa Ziehau #else 231015516c77SSepherosa Ziehau static int 231115516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS) 231215516c77SSepherosa Ziehau { 231315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 231415516c77SSepherosa Ziehau int ofs = arg2, i, error; 231515516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 231615516c77SSepherosa Ziehau uint64_t stat; 231715516c77SSepherosa Ziehau 231815516c77SSepherosa Ziehau stat = 0; 231915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) { 232015516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 232115516c77SSepherosa Ziehau stat += *((uint64_t *)((uint8_t *)rxr + ofs)); 232215516c77SSepherosa Ziehau } 232315516c77SSepherosa Ziehau 232415516c77SSepherosa Ziehau error = sysctl_handle_64(oidp, &stat, 0, req); 232515516c77SSepherosa Ziehau if (error || req->newptr == NULL) 232615516c77SSepherosa Ziehau return error; 232715516c77SSepherosa Ziehau 232815516c77SSepherosa Ziehau /* Zero out this stat. */ 232915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) { 233015516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 233115516c77SSepherosa Ziehau *((uint64_t *)((uint8_t *)rxr + ofs)) = 0; 233215516c77SSepherosa Ziehau } 233315516c77SSepherosa Ziehau return 0; 233415516c77SSepherosa Ziehau } 233515516c77SSepherosa Ziehau 233615516c77SSepherosa Ziehau #endif 233715516c77SSepherosa Ziehau 233815516c77SSepherosa Ziehau static int 233915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 234015516c77SSepherosa Ziehau { 234115516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 234215516c77SSepherosa Ziehau int ofs = arg2, i, error; 234315516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 234415516c77SSepherosa Ziehau u_long stat; 234515516c77SSepherosa Ziehau 234615516c77SSepherosa Ziehau stat = 0; 234715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) { 234815516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 234915516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)rxr + ofs)); 235015516c77SSepherosa Ziehau } 235115516c77SSepherosa Ziehau 235215516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 235315516c77SSepherosa Ziehau if (error || req->newptr == NULL) 235415516c77SSepherosa Ziehau return error; 235515516c77SSepherosa Ziehau 235615516c77SSepherosa Ziehau /* Zero out this stat. */ 235715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_inuse; ++i) { 235815516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[i]; 235915516c77SSepherosa Ziehau *((u_long *)((uint8_t *)rxr + ofs)) = 0; 236015516c77SSepherosa Ziehau } 236115516c77SSepherosa Ziehau return 0; 236215516c77SSepherosa Ziehau } 236315516c77SSepherosa Ziehau 236415516c77SSepherosa Ziehau static int 236515516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS) 236615516c77SSepherosa Ziehau { 236715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 236815516c77SSepherosa Ziehau int ofs = arg2, i, error; 236915516c77SSepherosa Ziehau struct hn_tx_ring *txr; 237015516c77SSepherosa Ziehau u_long stat; 237115516c77SSepherosa Ziehau 237215516c77SSepherosa Ziehau stat = 0; 237315516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 237415516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 237515516c77SSepherosa Ziehau stat += *((u_long *)((uint8_t *)txr + ofs)); 237615516c77SSepherosa Ziehau } 237715516c77SSepherosa Ziehau 237815516c77SSepherosa Ziehau error = sysctl_handle_long(oidp, &stat, 0, req); 237915516c77SSepherosa Ziehau if (error || req->newptr == NULL) 238015516c77SSepherosa Ziehau return error; 238115516c77SSepherosa Ziehau 238215516c77SSepherosa Ziehau /* Zero out this stat. */ 238315516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 238415516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 238515516c77SSepherosa Ziehau *((u_long *)((uint8_t *)txr + ofs)) = 0; 238615516c77SSepherosa Ziehau } 238715516c77SSepherosa Ziehau return 0; 238815516c77SSepherosa Ziehau } 238915516c77SSepherosa Ziehau 239015516c77SSepherosa Ziehau static int 239115516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS) 239215516c77SSepherosa Ziehau { 239315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 239415516c77SSepherosa Ziehau int ofs = arg2, i, error, conf; 239515516c77SSepherosa Ziehau struct hn_tx_ring *txr; 239615516c77SSepherosa Ziehau 239715516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[0]; 239815516c77SSepherosa Ziehau conf = *((int *)((uint8_t *)txr + ofs)); 239915516c77SSepherosa Ziehau 240015516c77SSepherosa Ziehau error = sysctl_handle_int(oidp, &conf, 0, req); 240115516c77SSepherosa Ziehau if (error || req->newptr == NULL) 240215516c77SSepherosa Ziehau return error; 240315516c77SSepherosa Ziehau 240415516c77SSepherosa Ziehau HN_LOCK(sc); 240515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 240615516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[i]; 240715516c77SSepherosa Ziehau *((int *)((uint8_t *)txr + ofs)) = conf; 240815516c77SSepherosa Ziehau } 240915516c77SSepherosa Ziehau HN_UNLOCK(sc); 241015516c77SSepherosa Ziehau 241115516c77SSepherosa Ziehau return 0; 241215516c77SSepherosa Ziehau } 241315516c77SSepherosa Ziehau 241415516c77SSepherosa Ziehau static int 241515516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS) 241615516c77SSepherosa Ziehau { 241715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 241815516c77SSepherosa Ziehau char verstr[16]; 241915516c77SSepherosa Ziehau 242015516c77SSepherosa Ziehau snprintf(verstr, sizeof(verstr), "%u.%u", 242115516c77SSepherosa Ziehau HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 242215516c77SSepherosa Ziehau HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 242315516c77SSepherosa Ziehau return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 242415516c77SSepherosa Ziehau } 242515516c77SSepherosa Ziehau 242615516c77SSepherosa Ziehau static int 242715516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS) 242815516c77SSepherosa Ziehau { 242915516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 243015516c77SSepherosa Ziehau char caps_str[128]; 243115516c77SSepherosa Ziehau uint32_t caps; 243215516c77SSepherosa Ziehau 243315516c77SSepherosa Ziehau HN_LOCK(sc); 243415516c77SSepherosa Ziehau caps = sc->hn_caps; 243515516c77SSepherosa Ziehau HN_UNLOCK(sc); 243615516c77SSepherosa Ziehau snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS); 243715516c77SSepherosa Ziehau return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req); 243815516c77SSepherosa Ziehau } 243915516c77SSepherosa Ziehau 244015516c77SSepherosa Ziehau static int 244115516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS) 244215516c77SSepherosa Ziehau { 244315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 244415516c77SSepherosa Ziehau char assist_str[128]; 244515516c77SSepherosa Ziehau uint32_t hwassist; 244615516c77SSepherosa Ziehau 244715516c77SSepherosa Ziehau HN_LOCK(sc); 244815516c77SSepherosa Ziehau hwassist = sc->hn_ifp->if_hwassist; 244915516c77SSepherosa Ziehau HN_UNLOCK(sc); 245015516c77SSepherosa Ziehau snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS); 245115516c77SSepherosa Ziehau return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req); 245215516c77SSepherosa Ziehau } 245315516c77SSepherosa Ziehau 245415516c77SSepherosa Ziehau static int 245515516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS) 245615516c77SSepherosa Ziehau { 245715516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 245815516c77SSepherosa Ziehau char filter_str[128]; 245915516c77SSepherosa Ziehau uint32_t filter; 246015516c77SSepherosa Ziehau 246115516c77SSepherosa Ziehau HN_LOCK(sc); 246215516c77SSepherosa Ziehau filter = sc->hn_rx_filter; 246315516c77SSepherosa Ziehau HN_UNLOCK(sc); 246415516c77SSepherosa Ziehau snprintf(filter_str, sizeof(filter_str), "%b", filter, 246515516c77SSepherosa Ziehau NDIS_PACKET_TYPES); 246615516c77SSepherosa Ziehau return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req); 246715516c77SSepherosa Ziehau } 246815516c77SSepherosa Ziehau 246915516c77SSepherosa Ziehau static int 247015516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS) 247115516c77SSepherosa Ziehau { 247215516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 247315516c77SSepherosa Ziehau int error; 247415516c77SSepherosa Ziehau 247515516c77SSepherosa Ziehau HN_LOCK(sc); 247615516c77SSepherosa Ziehau 247715516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 247815516c77SSepherosa Ziehau if (error || req->newptr == NULL) 247915516c77SSepherosa Ziehau goto back; 248015516c77SSepherosa Ziehau 248115516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); 248215516c77SSepherosa Ziehau if (error) 248315516c77SSepherosa Ziehau goto back; 248415516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 248515516c77SSepherosa Ziehau 248615516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse > 1) { 248715516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 248815516c77SSepherosa Ziehau } else { 248915516c77SSepherosa Ziehau /* Not RSS capable, at least for now; just save the RSS key. */ 249015516c77SSepherosa Ziehau error = 0; 249115516c77SSepherosa Ziehau } 249215516c77SSepherosa Ziehau back: 249315516c77SSepherosa Ziehau HN_UNLOCK(sc); 249415516c77SSepherosa Ziehau return (error); 249515516c77SSepherosa Ziehau } 249615516c77SSepherosa Ziehau 249715516c77SSepherosa Ziehau static int 249815516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS) 249915516c77SSepherosa Ziehau { 250015516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 250115516c77SSepherosa Ziehau int error; 250215516c77SSepherosa Ziehau 250315516c77SSepherosa Ziehau HN_LOCK(sc); 250415516c77SSepherosa Ziehau 250515516c77SSepherosa Ziehau error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 250615516c77SSepherosa Ziehau if (error || req->newptr == NULL) 250715516c77SSepherosa Ziehau goto back; 250815516c77SSepherosa Ziehau 250915516c77SSepherosa Ziehau /* 251015516c77SSepherosa Ziehau * Don't allow RSS indirect table change, if this interface is not 251115516c77SSepherosa Ziehau * RSS capable currently. 251215516c77SSepherosa Ziehau */ 251315516c77SSepherosa Ziehau if (sc->hn_rx_ring_inuse == 1) { 251415516c77SSepherosa Ziehau error = EOPNOTSUPP; 251515516c77SSepherosa Ziehau goto back; 251615516c77SSepherosa Ziehau } 251715516c77SSepherosa Ziehau 251815516c77SSepherosa Ziehau error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); 251915516c77SSepherosa Ziehau if (error) 252015516c77SSepherosa Ziehau goto back; 252115516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 252215516c77SSepherosa Ziehau 252315516c77SSepherosa Ziehau hn_rss_ind_fixup(sc, sc->hn_rx_ring_inuse); 252415516c77SSepherosa Ziehau error = hn_rss_reconfig(sc); 252515516c77SSepherosa Ziehau back: 252615516c77SSepherosa Ziehau HN_UNLOCK(sc); 252715516c77SSepherosa Ziehau return (error); 252815516c77SSepherosa Ziehau } 252915516c77SSepherosa Ziehau 253015516c77SSepherosa Ziehau static int 253115516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS) 253215516c77SSepherosa Ziehau { 253315516c77SSepherosa Ziehau struct hn_softc *sc = arg1; 253415516c77SSepherosa Ziehau char hash_str[128]; 253515516c77SSepherosa Ziehau uint32_t hash; 253615516c77SSepherosa Ziehau 253715516c77SSepherosa Ziehau HN_LOCK(sc); 253815516c77SSepherosa Ziehau hash = sc->hn_rss_hash; 253915516c77SSepherosa Ziehau HN_UNLOCK(sc); 254015516c77SSepherosa Ziehau snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); 254115516c77SSepherosa Ziehau return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); 254215516c77SSepherosa Ziehau } 254315516c77SSepherosa Ziehau 254415516c77SSepherosa Ziehau static int 254515516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff) 254615516c77SSepherosa Ziehau { 254715516c77SSepherosa Ziehau const struct ip *ip; 254815516c77SSepherosa Ziehau int len, iphlen, iplen; 254915516c77SSepherosa Ziehau const struct tcphdr *th; 255015516c77SSepherosa Ziehau int thoff; /* TCP data offset */ 255115516c77SSepherosa Ziehau 255215516c77SSepherosa Ziehau len = hoff + sizeof(struct ip); 255315516c77SSepherosa Ziehau 255415516c77SSepherosa Ziehau /* The packet must be at least the size of an IP header. */ 255515516c77SSepherosa Ziehau if (m->m_pkthdr.len < len) 255615516c77SSepherosa Ziehau return IPPROTO_DONE; 255715516c77SSepherosa Ziehau 255815516c77SSepherosa Ziehau /* The fixed IP header must reside completely in the first mbuf. */ 255915516c77SSepherosa Ziehau if (m->m_len < len) 256015516c77SSepherosa Ziehau return IPPROTO_DONE; 256115516c77SSepherosa Ziehau 256215516c77SSepherosa Ziehau ip = mtodo(m, hoff); 256315516c77SSepherosa Ziehau 256415516c77SSepherosa Ziehau /* Bound check the packet's stated IP header length. */ 256515516c77SSepherosa Ziehau iphlen = ip->ip_hl << 2; 256615516c77SSepherosa Ziehau if (iphlen < sizeof(struct ip)) /* minimum header length */ 256715516c77SSepherosa Ziehau return IPPROTO_DONE; 256815516c77SSepherosa Ziehau 256915516c77SSepherosa Ziehau /* The full IP header must reside completely in the one mbuf. */ 257015516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen) 257115516c77SSepherosa Ziehau return IPPROTO_DONE; 257215516c77SSepherosa Ziehau 257315516c77SSepherosa Ziehau iplen = ntohs(ip->ip_len); 257415516c77SSepherosa Ziehau 257515516c77SSepherosa Ziehau /* 257615516c77SSepherosa Ziehau * Check that the amount of data in the buffers is as 257715516c77SSepherosa Ziehau * at least much as the IP header would have us expect. 257815516c77SSepherosa Ziehau */ 257915516c77SSepherosa Ziehau if (m->m_pkthdr.len < hoff + iplen) 258015516c77SSepherosa Ziehau return IPPROTO_DONE; 258115516c77SSepherosa Ziehau 258215516c77SSepherosa Ziehau /* 258315516c77SSepherosa Ziehau * Ignore IP fragments. 258415516c77SSepherosa Ziehau */ 258515516c77SSepherosa Ziehau if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF)) 258615516c77SSepherosa Ziehau return IPPROTO_DONE; 258715516c77SSepherosa Ziehau 258815516c77SSepherosa Ziehau /* 258915516c77SSepherosa Ziehau * The TCP/IP or UDP/IP header must be entirely contained within 259015516c77SSepherosa Ziehau * the first fragment of a packet. 259115516c77SSepherosa Ziehau */ 259215516c77SSepherosa Ziehau switch (ip->ip_p) { 259315516c77SSepherosa Ziehau case IPPROTO_TCP: 259415516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct tcphdr)) 259515516c77SSepherosa Ziehau return IPPROTO_DONE; 259615516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct tcphdr)) 259715516c77SSepherosa Ziehau return IPPROTO_DONE; 259815516c77SSepherosa Ziehau th = (const struct tcphdr *)((const uint8_t *)ip + iphlen); 259915516c77SSepherosa Ziehau thoff = th->th_off << 2; 260015516c77SSepherosa Ziehau if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen) 260115516c77SSepherosa Ziehau return IPPROTO_DONE; 260215516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + thoff) 260315516c77SSepherosa Ziehau return IPPROTO_DONE; 260415516c77SSepherosa Ziehau break; 260515516c77SSepherosa Ziehau case IPPROTO_UDP: 260615516c77SSepherosa Ziehau if (iplen < iphlen + sizeof(struct udphdr)) 260715516c77SSepherosa Ziehau return IPPROTO_DONE; 260815516c77SSepherosa Ziehau if (m->m_len < hoff + iphlen + sizeof(struct udphdr)) 260915516c77SSepherosa Ziehau return IPPROTO_DONE; 261015516c77SSepherosa Ziehau break; 261115516c77SSepherosa Ziehau default: 261215516c77SSepherosa Ziehau if (iplen < iphlen) 261315516c77SSepherosa Ziehau return IPPROTO_DONE; 261415516c77SSepherosa Ziehau break; 261515516c77SSepherosa Ziehau } 261615516c77SSepherosa Ziehau return ip->ip_p; 261715516c77SSepherosa Ziehau } 261815516c77SSepherosa Ziehau 261915516c77SSepherosa Ziehau static int 262015516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt) 262115516c77SSepherosa Ziehau { 262215516c77SSepherosa Ziehau struct sysctl_oid_list *child; 262315516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 262415516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 262515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 262615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 262715516c77SSepherosa Ziehau int lroent_cnt; 262815516c77SSepherosa Ziehau #endif 262915516c77SSepherosa Ziehau #endif 263015516c77SSepherosa Ziehau int i; 263115516c77SSepherosa Ziehau 263215516c77SSepherosa Ziehau /* 263315516c77SSepherosa Ziehau * Create RXBUF for reception. 263415516c77SSepherosa Ziehau * 263515516c77SSepherosa Ziehau * NOTE: 263615516c77SSepherosa Ziehau * - It is shared by all channels. 263715516c77SSepherosa Ziehau * - A large enough buffer is allocated, certain version of NVSes 263815516c77SSepherosa Ziehau * may further limit the usable space. 263915516c77SSepherosa Ziehau */ 264015516c77SSepherosa Ziehau sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 264115516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma, 264215516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 264315516c77SSepherosa Ziehau if (sc->hn_rxbuf == NULL) { 264415516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate rxbuf failed\n"); 264515516c77SSepherosa Ziehau return (ENOMEM); 264615516c77SSepherosa Ziehau } 264715516c77SSepherosa Ziehau 264815516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = ring_cnt; 264915516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt; 265015516c77SSepherosa Ziehau 265115516c77SSepherosa Ziehau sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt, 265215516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 265315516c77SSepherosa Ziehau 265415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 265515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 265615516c77SSepherosa Ziehau lroent_cnt = hn_lro_entry_count; 265715516c77SSepherosa Ziehau if (lroent_cnt < TCP_LRO_ENTRIES) 265815516c77SSepherosa Ziehau lroent_cnt = TCP_LRO_ENTRIES; 265915516c77SSepherosa Ziehau if (bootverbose) 266015516c77SSepherosa Ziehau device_printf(dev, "LRO: entry count %d\n", lroent_cnt); 266115516c77SSepherosa Ziehau #endif 266215516c77SSepherosa Ziehau #endif /* INET || INET6 */ 266315516c77SSepherosa Ziehau 266415516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 266515516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 266615516c77SSepherosa Ziehau 266715516c77SSepherosa Ziehau /* Create dev.hn.UNIT.rx sysctl tree */ 266815516c77SSepherosa Ziehau sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx", 266915516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 267015516c77SSepherosa Ziehau 267115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 267215516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 267315516c77SSepherosa Ziehau 267415516c77SSepherosa Ziehau rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev), 267515516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE, 267615516c77SSepherosa Ziehau &rxr->hn_br_dma, BUS_DMA_WAITOK); 267715516c77SSepherosa Ziehau if (rxr->hn_br == NULL) { 267815516c77SSepherosa Ziehau device_printf(dev, "allocate bufring failed\n"); 267915516c77SSepherosa Ziehau return (ENOMEM); 268015516c77SSepherosa Ziehau } 268115516c77SSepherosa Ziehau 268215516c77SSepherosa Ziehau if (hn_trust_hosttcp) 268315516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP; 268415516c77SSepherosa Ziehau if (hn_trust_hostudp) 268515516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP; 268615516c77SSepherosa Ziehau if (hn_trust_hostip) 268715516c77SSepherosa Ziehau rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP; 268815516c77SSepherosa Ziehau rxr->hn_ifp = sc->hn_ifp; 268915516c77SSepherosa Ziehau if (i < sc->hn_tx_ring_cnt) 269015516c77SSepherosa Ziehau rxr->hn_txr = &sc->hn_tx_ring[i]; 269115516c77SSepherosa Ziehau rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF; 269215516c77SSepherosa Ziehau rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK); 269315516c77SSepherosa Ziehau rxr->hn_rx_idx = i; 269415516c77SSepherosa Ziehau rxr->hn_rxbuf = sc->hn_rxbuf; 269515516c77SSepherosa Ziehau 269615516c77SSepherosa Ziehau /* 269715516c77SSepherosa Ziehau * Initialize LRO. 269815516c77SSepherosa Ziehau */ 269915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 270015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095 270115516c77SSepherosa Ziehau tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt, 270215516c77SSepherosa Ziehau hn_lro_mbufq_depth); 270315516c77SSepherosa Ziehau #else 270415516c77SSepherosa Ziehau tcp_lro_init(&rxr->hn_lro); 270515516c77SSepherosa Ziehau rxr->hn_lro.ifp = sc->hn_ifp; 270615516c77SSepherosa Ziehau #endif 270715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 270815516c77SSepherosa Ziehau rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF; 270915516c77SSepherosa Ziehau rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF; 271015516c77SSepherosa Ziehau #endif 271115516c77SSepherosa Ziehau #endif /* INET || INET6 */ 271215516c77SSepherosa Ziehau 271315516c77SSepherosa Ziehau if (sc->hn_rx_sysctl_tree != NULL) { 271415516c77SSepherosa Ziehau char name[16]; 271515516c77SSepherosa Ziehau 271615516c77SSepherosa Ziehau /* 271715516c77SSepherosa Ziehau * Create per RX ring sysctl tree: 271815516c77SSepherosa Ziehau * dev.hn.UNIT.rx.RINGID 271915516c77SSepherosa Ziehau */ 272015516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", i); 272115516c77SSepherosa Ziehau rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, 272215516c77SSepherosa Ziehau SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree), 272315516c77SSepherosa Ziehau OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 272415516c77SSepherosa Ziehau 272515516c77SSepherosa Ziehau if (rxr->hn_rx_sysctl_tree != NULL) { 272615516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 272715516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 272815516c77SSepherosa Ziehau OID_AUTO, "packets", CTLFLAG_RW, 272915516c77SSepherosa Ziehau &rxr->hn_pkts, "# of packets received"); 273015516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, 273115516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 273215516c77SSepherosa Ziehau OID_AUTO, "rss_pkts", CTLFLAG_RW, 273315516c77SSepherosa Ziehau &rxr->hn_rss_pkts, 273415516c77SSepherosa Ziehau "# of packets w/ RSS info received"); 273515516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, 273615516c77SSepherosa Ziehau SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree), 273715516c77SSepherosa Ziehau OID_AUTO, "pktbuf_len", CTLFLAG_RD, 273815516c77SSepherosa Ziehau &rxr->hn_pktbuf_len, 0, 273915516c77SSepherosa Ziehau "Temporary channel packet buffer length"); 274015516c77SSepherosa Ziehau } 274115516c77SSepherosa Ziehau } 274215516c77SSepherosa Ziehau } 274315516c77SSepherosa Ziehau 274415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued", 274515516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 274615516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_queued), 274715516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 274815516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 274915516c77SSepherosa Ziehau #else 275015516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 275115516c77SSepherosa Ziehau #endif 275215516c77SSepherosa Ziehau "LU", "LRO queued"); 275315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed", 275415516c77SSepherosa Ziehau CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 275515516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro.lro_flushed), 275615516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095 275715516c77SSepherosa Ziehau hn_rx_stat_int_sysctl, 275815516c77SSepherosa Ziehau #else 275915516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl, 276015516c77SSepherosa Ziehau #endif 276115516c77SSepherosa Ziehau "LU", "LRO flushed"); 276215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried", 276315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 276415516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_lro_tried), 276515516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries"); 276615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099 276715516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim", 276815516c77SSepherosa Ziehau CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 276915516c77SSepherosa Ziehau hn_lro_lenlim_sysctl, "IU", 277015516c77SSepherosa Ziehau "Max # of data bytes to be aggregated by LRO"); 277115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim", 277215516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 277315516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl, "I", 277415516c77SSepherosa Ziehau "Max # of ACKs to be aggregated by LRO"); 277515516c77SSepherosa Ziehau #endif 277615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp", 277715516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP, 277815516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 277915516c77SSepherosa Ziehau "Trust tcp segement verification on host side, " 278015516c77SSepherosa Ziehau "when csum info is missing"); 278115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp", 278215516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP, 278315516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 278415516c77SSepherosa Ziehau "Trust udp datagram verification on host side, " 278515516c77SSepherosa Ziehau "when csum info is missing"); 278615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip", 278715516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP, 278815516c77SSepherosa Ziehau hn_trust_hcsum_sysctl, "I", 278915516c77SSepherosa Ziehau "Trust ip packet verification on host side, " 279015516c77SSepherosa Ziehau "when csum info is missing"); 279115516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip", 279215516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 279315516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_ip), 279415516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP"); 279515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp", 279615516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 279715516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_tcp), 279815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP"); 279915516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp", 280015516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 280115516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_udp), 280215516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP"); 280315516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted", 280415516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 280515516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_csum_trusted), 280615516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", 280715516c77SSepherosa Ziehau "# of packets that we trust host's csum verification"); 280815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts", 280915516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 281015516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_small_pkts), 281115516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of small packets received"); 281215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed", 281315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 281415516c77SSepherosa Ziehau __offsetof(struct hn_rx_ring, hn_ack_failed), 281515516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures"); 281615516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt", 281715516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings"); 281815516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse", 281915516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings"); 282015516c77SSepherosa Ziehau 282115516c77SSepherosa Ziehau return (0); 282215516c77SSepherosa Ziehau } 282315516c77SSepherosa Ziehau 282415516c77SSepherosa Ziehau static void 282515516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc) 282615516c77SSepherosa Ziehau { 282715516c77SSepherosa Ziehau int i; 282815516c77SSepherosa Ziehau 282915516c77SSepherosa Ziehau if (sc->hn_rxbuf != NULL) { 283015516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf); 283115516c77SSepherosa Ziehau sc->hn_rxbuf = NULL; 283215516c77SSepherosa Ziehau } 283315516c77SSepherosa Ziehau 283415516c77SSepherosa Ziehau if (sc->hn_rx_ring_cnt == 0) 283515516c77SSepherosa Ziehau return; 283615516c77SSepherosa Ziehau 283715516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 283815516c77SSepherosa Ziehau struct hn_rx_ring *rxr = &sc->hn_rx_ring[i]; 283915516c77SSepherosa Ziehau 284015516c77SSepherosa Ziehau if (rxr->hn_br == NULL) 284115516c77SSepherosa Ziehau continue; 284215516c77SSepherosa Ziehau hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br); 284315516c77SSepherosa Ziehau rxr->hn_br = NULL; 284415516c77SSepherosa Ziehau 284515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6) 284615516c77SSepherosa Ziehau tcp_lro_free(&rxr->hn_lro); 284715516c77SSepherosa Ziehau #endif 284815516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 284915516c77SSepherosa Ziehau } 285015516c77SSepherosa Ziehau free(sc->hn_rx_ring, M_DEVBUF); 285115516c77SSepherosa Ziehau sc->hn_rx_ring = NULL; 285215516c77SSepherosa Ziehau 285315516c77SSepherosa Ziehau sc->hn_rx_ring_cnt = 0; 285415516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = 0; 285515516c77SSepherosa Ziehau } 285615516c77SSepherosa Ziehau 285715516c77SSepherosa Ziehau static int 285815516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id) 285915516c77SSepherosa Ziehau { 286015516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[id]; 286115516c77SSepherosa Ziehau device_t dev = sc->hn_dev; 286215516c77SSepherosa Ziehau bus_dma_tag_t parent_dtag; 286315516c77SSepherosa Ziehau int error, i; 286415516c77SSepherosa Ziehau 286515516c77SSepherosa Ziehau txr->hn_sc = sc; 286615516c77SSepherosa Ziehau txr->hn_tx_idx = id; 286715516c77SSepherosa Ziehau 286815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 286915516c77SSepherosa Ziehau mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); 287015516c77SSepherosa Ziehau #endif 287115516c77SSepherosa Ziehau mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF); 287215516c77SSepherosa Ziehau 287315516c77SSepherosa Ziehau txr->hn_txdesc_cnt = HN_TX_DESC_CNT; 287415516c77SSepherosa Ziehau txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt, 287515516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 287615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 287715516c77SSepherosa Ziehau SLIST_INIT(&txr->hn_txlist); 287815516c77SSepherosa Ziehau #else 287915516c77SSepherosa Ziehau txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF, 288015516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 288115516c77SSepherosa Ziehau #endif 288215516c77SSepherosa Ziehau 288315516c77SSepherosa Ziehau txr->hn_tx_taskq = sc->hn_tx_taskq; 288415516c77SSepherosa Ziehau 288523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 288615516c77SSepherosa Ziehau if (hn_use_if_start) { 288715516c77SSepherosa Ziehau txr->hn_txeof = hn_start_txeof; 288815516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr); 288915516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr); 289023bf9e15SSepherosa Ziehau } else 289123bf9e15SSepherosa Ziehau #endif 289223bf9e15SSepherosa Ziehau { 289315516c77SSepherosa Ziehau int br_depth; 289415516c77SSepherosa Ziehau 289515516c77SSepherosa Ziehau txr->hn_txeof = hn_xmit_txeof; 289615516c77SSepherosa Ziehau TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr); 289715516c77SSepherosa Ziehau TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr); 289815516c77SSepherosa Ziehau 289915516c77SSepherosa Ziehau br_depth = hn_get_txswq_depth(txr); 290015516c77SSepherosa Ziehau txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF, 290115516c77SSepherosa Ziehau M_WAITOK, &txr->hn_tx_lock); 290215516c77SSepherosa Ziehau } 290315516c77SSepherosa Ziehau 290415516c77SSepherosa Ziehau txr->hn_direct_tx_size = hn_direct_tx_size; 290515516c77SSepherosa Ziehau 290615516c77SSepherosa Ziehau /* 290715516c77SSepherosa Ziehau * Always schedule transmission instead of trying to do direct 290815516c77SSepherosa Ziehau * transmission. This one gives the best performance so far. 290915516c77SSepherosa Ziehau */ 291015516c77SSepherosa Ziehau txr->hn_sched_tx = 1; 291115516c77SSepherosa Ziehau 291215516c77SSepherosa Ziehau parent_dtag = bus_get_dma_tag(dev); 291315516c77SSepherosa Ziehau 291415516c77SSepherosa Ziehau /* DMA tag for RNDIS packet messages. */ 291515516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 291615516c77SSepherosa Ziehau HN_RNDIS_PKT_ALIGN, /* alignment */ 291715516c77SSepherosa Ziehau HN_RNDIS_PKT_BOUNDARY, /* boundary */ 291815516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 291915516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 292015516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 292115516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsize */ 292215516c77SSepherosa Ziehau 1, /* nsegments */ 292315516c77SSepherosa Ziehau HN_RNDIS_PKT_LEN, /* maxsegsize */ 292415516c77SSepherosa Ziehau 0, /* flags */ 292515516c77SSepherosa Ziehau NULL, /* lockfunc */ 292615516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 292715516c77SSepherosa Ziehau &txr->hn_tx_rndis_dtag); 292815516c77SSepherosa Ziehau if (error) { 292915516c77SSepherosa Ziehau device_printf(dev, "failed to create rndis dmatag\n"); 293015516c77SSepherosa Ziehau return error; 293115516c77SSepherosa Ziehau } 293215516c77SSepherosa Ziehau 293315516c77SSepherosa Ziehau /* DMA tag for data. */ 293415516c77SSepherosa Ziehau error = bus_dma_tag_create(parent_dtag, /* parent */ 293515516c77SSepherosa Ziehau 1, /* alignment */ 293615516c77SSepherosa Ziehau HN_TX_DATA_BOUNDARY, /* boundary */ 293715516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 293815516c77SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 293915516c77SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 294015516c77SSepherosa Ziehau HN_TX_DATA_MAXSIZE, /* maxsize */ 294115516c77SSepherosa Ziehau HN_TX_DATA_SEGCNT_MAX, /* nsegments */ 294215516c77SSepherosa Ziehau HN_TX_DATA_SEGSIZE, /* maxsegsize */ 294315516c77SSepherosa Ziehau 0, /* flags */ 294415516c77SSepherosa Ziehau NULL, /* lockfunc */ 294515516c77SSepherosa Ziehau NULL, /* lockfuncarg */ 294615516c77SSepherosa Ziehau &txr->hn_tx_data_dtag); 294715516c77SSepherosa Ziehau if (error) { 294815516c77SSepherosa Ziehau device_printf(dev, "failed to create data dmatag\n"); 294915516c77SSepherosa Ziehau return error; 295015516c77SSepherosa Ziehau } 295115516c77SSepherosa Ziehau 295215516c77SSepherosa Ziehau for (i = 0; i < txr->hn_txdesc_cnt; ++i) { 295315516c77SSepherosa Ziehau struct hn_txdesc *txd = &txr->hn_txdesc[i]; 295415516c77SSepherosa Ziehau 295515516c77SSepherosa Ziehau txd->txr = txr; 295615516c77SSepherosa Ziehau txd->chim_index = HN_NVS_CHIM_IDX_INVALID; 295715516c77SSepherosa Ziehau 295815516c77SSepherosa Ziehau /* 295915516c77SSepherosa Ziehau * Allocate and load RNDIS packet message. 296015516c77SSepherosa Ziehau */ 296115516c77SSepherosa Ziehau error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag, 296215516c77SSepherosa Ziehau (void **)&txd->rndis_pkt, 296315516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 296415516c77SSepherosa Ziehau &txd->rndis_pkt_dmap); 296515516c77SSepherosa Ziehau if (error) { 296615516c77SSepherosa Ziehau device_printf(dev, 296715516c77SSepherosa Ziehau "failed to allocate rndis_packet_msg, %d\n", i); 296815516c77SSepherosa Ziehau return error; 296915516c77SSepherosa Ziehau } 297015516c77SSepherosa Ziehau 297115516c77SSepherosa Ziehau error = bus_dmamap_load(txr->hn_tx_rndis_dtag, 297215516c77SSepherosa Ziehau txd->rndis_pkt_dmap, 297315516c77SSepherosa Ziehau txd->rndis_pkt, HN_RNDIS_PKT_LEN, 297415516c77SSepherosa Ziehau hyperv_dma_map_paddr, &txd->rndis_pkt_paddr, 297515516c77SSepherosa Ziehau BUS_DMA_NOWAIT); 297615516c77SSepherosa Ziehau if (error) { 297715516c77SSepherosa Ziehau device_printf(dev, 297815516c77SSepherosa Ziehau "failed to load rndis_packet_msg, %d\n", i); 297915516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 298015516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 298115516c77SSepherosa Ziehau return error; 298215516c77SSepherosa Ziehau } 298315516c77SSepherosa Ziehau 298415516c77SSepherosa Ziehau /* DMA map for TX data. */ 298515516c77SSepherosa Ziehau error = bus_dmamap_create(txr->hn_tx_data_dtag, 0, 298615516c77SSepherosa Ziehau &txd->data_dmap); 298715516c77SSepherosa Ziehau if (error) { 298815516c77SSepherosa Ziehau device_printf(dev, 298915516c77SSepherosa Ziehau "failed to allocate tx data dmamap\n"); 299015516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, 299115516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 299215516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, 299315516c77SSepherosa Ziehau txd->rndis_pkt, txd->rndis_pkt_dmap); 299415516c77SSepherosa Ziehau return error; 299515516c77SSepherosa Ziehau } 299615516c77SSepherosa Ziehau 299715516c77SSepherosa Ziehau /* All set, put it to list */ 299815516c77SSepherosa Ziehau txd->flags |= HN_TXD_FLAG_ONLIST; 299915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 300015516c77SSepherosa Ziehau SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); 300115516c77SSepherosa Ziehau #else 300215516c77SSepherosa Ziehau buf_ring_enqueue(txr->hn_txdesc_br, txd); 300315516c77SSepherosa Ziehau #endif 300415516c77SSepherosa Ziehau } 300515516c77SSepherosa Ziehau txr->hn_txdesc_avail = txr->hn_txdesc_cnt; 300615516c77SSepherosa Ziehau 300715516c77SSepherosa Ziehau if (sc->hn_tx_sysctl_tree != NULL) { 300815516c77SSepherosa Ziehau struct sysctl_oid_list *child; 300915516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 301015516c77SSepherosa Ziehau char name[16]; 301115516c77SSepherosa Ziehau 301215516c77SSepherosa Ziehau /* 301315516c77SSepherosa Ziehau * Create per TX ring sysctl tree: 301415516c77SSepherosa Ziehau * dev.hn.UNIT.tx.RINGID 301515516c77SSepherosa Ziehau */ 301615516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev); 301715516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree); 301815516c77SSepherosa Ziehau 301915516c77SSepherosa Ziehau snprintf(name, sizeof(name), "%d", id); 302015516c77SSepherosa Ziehau txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, 302115516c77SSepherosa Ziehau name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 302215516c77SSepherosa Ziehau 302315516c77SSepherosa Ziehau if (txr->hn_tx_sysctl_tree != NULL) { 302415516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree); 302515516c77SSepherosa Ziehau 302615516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail", 302715516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_txdesc_avail, 0, 302815516c77SSepherosa Ziehau "# of available TX descs"); 302923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 303023bf9e15SSepherosa Ziehau if (!hn_use_if_start) 303123bf9e15SSepherosa Ziehau #endif 303223bf9e15SSepherosa Ziehau { 303315516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive", 303415516c77SSepherosa Ziehau CTLFLAG_RD, &txr->hn_oactive, 0, 303515516c77SSepherosa Ziehau "over active"); 303615516c77SSepherosa Ziehau } 303715516c77SSepherosa Ziehau SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets", 303815516c77SSepherosa Ziehau CTLFLAG_RW, &txr->hn_pkts, 303915516c77SSepherosa Ziehau "# of packets transmitted"); 304015516c77SSepherosa Ziehau } 304115516c77SSepherosa Ziehau } 304215516c77SSepherosa Ziehau 304315516c77SSepherosa Ziehau return 0; 304415516c77SSepherosa Ziehau } 304515516c77SSepherosa Ziehau 304615516c77SSepherosa Ziehau static void 304715516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd) 304815516c77SSepherosa Ziehau { 304915516c77SSepherosa Ziehau struct hn_tx_ring *txr = txd->txr; 305015516c77SSepherosa Ziehau 305115516c77SSepherosa Ziehau KASSERT(txd->m == NULL, ("still has mbuf installed")); 305215516c77SSepherosa Ziehau KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped")); 305315516c77SSepherosa Ziehau 305415516c77SSepherosa Ziehau bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap); 305515516c77SSepherosa Ziehau bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt, 305615516c77SSepherosa Ziehau txd->rndis_pkt_dmap); 305715516c77SSepherosa Ziehau bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap); 305815516c77SSepherosa Ziehau } 305915516c77SSepherosa Ziehau 306015516c77SSepherosa Ziehau static void 306115516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr) 306215516c77SSepherosa Ziehau { 306315516c77SSepherosa Ziehau struct hn_txdesc *txd; 306415516c77SSepherosa Ziehau 306515516c77SSepherosa Ziehau if (txr->hn_txdesc == NULL) 306615516c77SSepherosa Ziehau return; 306715516c77SSepherosa Ziehau 306815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 306915516c77SSepherosa Ziehau while ((txd = SLIST_FIRST(&txr->hn_txlist)) != NULL) { 307015516c77SSepherosa Ziehau SLIST_REMOVE_HEAD(&txr->hn_txlist, link); 307115516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(txd); 307215516c77SSepherosa Ziehau } 307315516c77SSepherosa Ziehau #else 307415516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 307515516c77SSepherosa Ziehau while ((txd = buf_ring_dequeue_sc(txr->hn_txdesc_br)) != NULL) 307615516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(txd); 307715516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 307815516c77SSepherosa Ziehau #endif 307915516c77SSepherosa Ziehau 308015516c77SSepherosa Ziehau if (txr->hn_tx_data_dtag != NULL) 308115516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_data_dtag); 308215516c77SSepherosa Ziehau if (txr->hn_tx_rndis_dtag != NULL) 308315516c77SSepherosa Ziehau bus_dma_tag_destroy(txr->hn_tx_rndis_dtag); 308415516c77SSepherosa Ziehau 308515516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING 308615516c77SSepherosa Ziehau buf_ring_free(txr->hn_txdesc_br, M_DEVBUF); 308715516c77SSepherosa Ziehau #endif 308815516c77SSepherosa Ziehau 308915516c77SSepherosa Ziehau free(txr->hn_txdesc, M_DEVBUF); 309015516c77SSepherosa Ziehau txr->hn_txdesc = NULL; 309115516c77SSepherosa Ziehau 309215516c77SSepherosa Ziehau if (txr->hn_mbuf_br != NULL) 309315516c77SSepherosa Ziehau buf_ring_free(txr->hn_mbuf_br, M_DEVBUF); 309415516c77SSepherosa Ziehau 309515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING 309615516c77SSepherosa Ziehau mtx_destroy(&txr->hn_txlist_spin); 309715516c77SSepherosa Ziehau #endif 309815516c77SSepherosa Ziehau mtx_destroy(&txr->hn_tx_lock); 309915516c77SSepherosa Ziehau } 310015516c77SSepherosa Ziehau 310115516c77SSepherosa Ziehau static int 310215516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt) 310315516c77SSepherosa Ziehau { 310415516c77SSepherosa Ziehau struct sysctl_oid_list *child; 310515516c77SSepherosa Ziehau struct sysctl_ctx_list *ctx; 310615516c77SSepherosa Ziehau int i; 310715516c77SSepherosa Ziehau 310815516c77SSepherosa Ziehau /* 310915516c77SSepherosa Ziehau * Create TXBUF for chimney sending. 311015516c77SSepherosa Ziehau * 311115516c77SSepherosa Ziehau * NOTE: It is shared by all channels. 311215516c77SSepherosa Ziehau */ 311315516c77SSepherosa Ziehau sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), 311415516c77SSepherosa Ziehau PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma, 311515516c77SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 311615516c77SSepherosa Ziehau if (sc->hn_chim == NULL) { 311715516c77SSepherosa Ziehau device_printf(sc->hn_dev, "allocate txbuf failed\n"); 311815516c77SSepherosa Ziehau return (ENOMEM); 311915516c77SSepherosa Ziehau } 312015516c77SSepherosa Ziehau 312115516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = ring_cnt; 312215516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 312315516c77SSepherosa Ziehau 312415516c77SSepherosa Ziehau sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt, 312515516c77SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 312615516c77SSepherosa Ziehau 312715516c77SSepherosa Ziehau ctx = device_get_sysctl_ctx(sc->hn_dev); 312815516c77SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev)); 312915516c77SSepherosa Ziehau 313015516c77SSepherosa Ziehau /* Create dev.hn.UNIT.tx sysctl tree */ 313115516c77SSepherosa Ziehau sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx", 313215516c77SSepherosa Ziehau CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 313315516c77SSepherosa Ziehau 313415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 313515516c77SSepherosa Ziehau int error; 313615516c77SSepherosa Ziehau 313715516c77SSepherosa Ziehau error = hn_tx_ring_create(sc, i); 313815516c77SSepherosa Ziehau if (error) 313915516c77SSepherosa Ziehau return error; 314015516c77SSepherosa Ziehau } 314115516c77SSepherosa Ziehau 314215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs", 314315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 314415516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_no_txdescs), 314515516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs"); 314615516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed", 314715516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 314815516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_send_failed), 314915516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure"); 315015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed", 315115516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 315215516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_txdma_failed), 315315516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure"); 315415516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed", 315515516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 315615516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_collapsed), 315715516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed"); 315815516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney", 315915516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 316015516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney), 316115516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send"); 316215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried", 316315516c77SSepherosa Ziehau CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 316415516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_tx_chimney_tried), 316515516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries"); 316615516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt", 316715516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0, 316815516c77SSepherosa Ziehau "# of total TX descs"); 316915516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max", 317015516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_chim_szmax, 0, 317115516c77SSepherosa Ziehau "Chimney send packet size upper boundary"); 317215516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size", 317315516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, 317415516c77SSepherosa Ziehau hn_chim_size_sysctl, "I", "Chimney send packet size limit"); 317515516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size", 317615516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 317715516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_direct_tx_size), 317815516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 317915516c77SSepherosa Ziehau "Size of the packet for direct transmission"); 318015516c77SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx", 318115516c77SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 318215516c77SSepherosa Ziehau __offsetof(struct hn_tx_ring, hn_sched_tx), 318315516c77SSepherosa Ziehau hn_tx_conf_int_sysctl, "I", 318415516c77SSepherosa Ziehau "Always schedule transmission " 318515516c77SSepherosa Ziehau "instead of doing direct transmission"); 318615516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt", 318715516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings"); 318815516c77SSepherosa Ziehau SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse", 318915516c77SSepherosa Ziehau CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings"); 319015516c77SSepherosa Ziehau 319115516c77SSepherosa Ziehau return 0; 319215516c77SSepherosa Ziehau } 319315516c77SSepherosa Ziehau 319415516c77SSepherosa Ziehau static void 319515516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size) 319615516c77SSepherosa Ziehau { 319715516c77SSepherosa Ziehau int i; 319815516c77SSepherosa Ziehau 319915516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 320015516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_chim_size = chim_size; 320115516c77SSepherosa Ziehau } 320215516c77SSepherosa Ziehau 320315516c77SSepherosa Ziehau static void 320415516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu) 320515516c77SSepherosa Ziehau { 320615516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 320715516c77SSepherosa Ziehau int tso_minlen; 320815516c77SSepherosa Ziehau 320915516c77SSepherosa Ziehau if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0) 321015516c77SSepherosa Ziehau return; 321115516c77SSepherosa Ziehau 321215516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_sgmin >= 2, 321315516c77SSepherosa Ziehau ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin)); 321415516c77SSepherosa Ziehau tso_minlen = sc->hn_ndis_tso_sgmin * mtu; 321515516c77SSepherosa Ziehau 321615516c77SSepherosa Ziehau KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen && 321715516c77SSepherosa Ziehau sc->hn_ndis_tso_szmax <= IP_MAXPACKET, 321815516c77SSepherosa Ziehau ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax)); 321915516c77SSepherosa Ziehau 322015516c77SSepherosa Ziehau if (tso_maxlen < tso_minlen) 322115516c77SSepherosa Ziehau tso_maxlen = tso_minlen; 322215516c77SSepherosa Ziehau else if (tso_maxlen > IP_MAXPACKET) 322315516c77SSepherosa Ziehau tso_maxlen = IP_MAXPACKET; 322415516c77SSepherosa Ziehau if (tso_maxlen > sc->hn_ndis_tso_szmax) 322515516c77SSepherosa Ziehau tso_maxlen = sc->hn_ndis_tso_szmax; 322615516c77SSepherosa Ziehau ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 322715516c77SSepherosa Ziehau if (bootverbose) 322815516c77SSepherosa Ziehau if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax); 322915516c77SSepherosa Ziehau } 323015516c77SSepherosa Ziehau 323115516c77SSepherosa Ziehau static void 323215516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc) 323315516c77SSepherosa Ziehau { 323415516c77SSepherosa Ziehau uint64_t csum_assist; 323515516c77SSepherosa Ziehau int i; 323615516c77SSepherosa Ziehau 323715516c77SSepherosa Ziehau hn_set_chim_size(sc, sc->hn_chim_szmax); 323815516c77SSepherosa Ziehau if (hn_tx_chimney_size > 0 && 323915516c77SSepherosa Ziehau hn_tx_chimney_size < sc->hn_chim_szmax) 324015516c77SSepherosa Ziehau hn_set_chim_size(sc, hn_tx_chimney_size); 324115516c77SSepherosa Ziehau 324215516c77SSepherosa Ziehau csum_assist = 0; 324315516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_IPCS) 324415516c77SSepherosa Ziehau csum_assist |= CSUM_IP; 324515516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP4CS) 324615516c77SSepherosa Ziehau csum_assist |= CSUM_IP_TCP; 324715516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP4CS) 324815516c77SSepherosa Ziehau csum_assist |= CSUM_IP_UDP; 324915516c77SSepherosa Ziehau #ifdef notyet 325015516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_TCP6CS) 325115516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_TCP; 325215516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_UDP6CS) 325315516c77SSepherosa Ziehau csum_assist |= CSUM_IP6_UDP; 325415516c77SSepherosa Ziehau #endif 325515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 325615516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_csum_assist = csum_assist; 325715516c77SSepherosa Ziehau 325815516c77SSepherosa Ziehau if (sc->hn_caps & HN_CAP_HASHVAL) { 325915516c77SSepherosa Ziehau /* 326015516c77SSepherosa Ziehau * Support HASHVAL pktinfo on TX path. 326115516c77SSepherosa Ziehau */ 326215516c77SSepherosa Ziehau if (bootverbose) 326315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n"); 326415516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 326515516c77SSepherosa Ziehau sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL; 326615516c77SSepherosa Ziehau } 326715516c77SSepherosa Ziehau } 326815516c77SSepherosa Ziehau 326915516c77SSepherosa Ziehau static void 327015516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc) 327115516c77SSepherosa Ziehau { 327215516c77SSepherosa Ziehau int i; 327315516c77SSepherosa Ziehau 327415516c77SSepherosa Ziehau if (sc->hn_chim != NULL) { 327515516c77SSepherosa Ziehau hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim); 327615516c77SSepherosa Ziehau sc->hn_chim = NULL; 327715516c77SSepherosa Ziehau } 327815516c77SSepherosa Ziehau 327915516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt == 0) 328015516c77SSepherosa Ziehau return; 328115516c77SSepherosa Ziehau 328215516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) 328315516c77SSepherosa Ziehau hn_tx_ring_destroy(&sc->hn_tx_ring[i]); 328415516c77SSepherosa Ziehau 328515516c77SSepherosa Ziehau free(sc->hn_tx_ring, M_DEVBUF); 328615516c77SSepherosa Ziehau sc->hn_tx_ring = NULL; 328715516c77SSepherosa Ziehau 328815516c77SSepherosa Ziehau sc->hn_tx_ring_cnt = 0; 328915516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = 0; 329015516c77SSepherosa Ziehau } 329115516c77SSepherosa Ziehau 329223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 329323bf9e15SSepherosa Ziehau 329415516c77SSepherosa Ziehau static void 329515516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused) 329615516c77SSepherosa Ziehau { 329715516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 329815516c77SSepherosa Ziehau 329915516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 330015516c77SSepherosa Ziehau hn_start_locked(txr, 0); 330115516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 330215516c77SSepherosa Ziehau } 330315516c77SSepherosa Ziehau 330423bf9e15SSepherosa Ziehau static int 330523bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len) 330623bf9e15SSepherosa Ziehau { 330723bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 330823bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 330923bf9e15SSepherosa Ziehau 331023bf9e15SSepherosa Ziehau KASSERT(hn_use_if_start, 331123bf9e15SSepherosa Ziehau ("hn_start_locked is called, when if_start is disabled")); 331223bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 331323bf9e15SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 331423bf9e15SSepherosa Ziehau 331523bf9e15SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 331623bf9e15SSepherosa Ziehau return 0; 331723bf9e15SSepherosa Ziehau 331823bf9e15SSepherosa Ziehau if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 331923bf9e15SSepherosa Ziehau IFF_DRV_RUNNING) 332023bf9e15SSepherosa Ziehau return 0; 332123bf9e15SSepherosa Ziehau 332223bf9e15SSepherosa Ziehau while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 332323bf9e15SSepherosa Ziehau struct hn_txdesc *txd; 332423bf9e15SSepherosa Ziehau struct mbuf *m_head; 332523bf9e15SSepherosa Ziehau int error; 332623bf9e15SSepherosa Ziehau 332723bf9e15SSepherosa Ziehau IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 332823bf9e15SSepherosa Ziehau if (m_head == NULL) 332923bf9e15SSepherosa Ziehau break; 333023bf9e15SSepherosa Ziehau 333123bf9e15SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 333223bf9e15SSepherosa Ziehau /* 333323bf9e15SSepherosa Ziehau * This sending could be time consuming; let callers 333423bf9e15SSepherosa Ziehau * dispatch this packet sending (and sending of any 333523bf9e15SSepherosa Ziehau * following up packets) to tx taskqueue. 333623bf9e15SSepherosa Ziehau */ 333723bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 333823bf9e15SSepherosa Ziehau return 1; 333923bf9e15SSepherosa Ziehau } 334023bf9e15SSepherosa Ziehau 3341edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 3342edd3f315SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 3343edd3f315SSepherosa Ziehau m_head = hn_tso_fixup(m_head); 3344edd3f315SSepherosa Ziehau if (__predict_false(m_head == NULL)) { 3345edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 3346edd3f315SSepherosa Ziehau continue; 3347edd3f315SSepherosa Ziehau } 3348edd3f315SSepherosa Ziehau } 3349edd3f315SSepherosa Ziehau #endif 3350edd3f315SSepherosa Ziehau 335123bf9e15SSepherosa Ziehau txd = hn_txdesc_get(txr); 335223bf9e15SSepherosa Ziehau if (txd == NULL) { 335323bf9e15SSepherosa Ziehau txr->hn_no_txdescs++; 335423bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 335523bf9e15SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 335623bf9e15SSepherosa Ziehau break; 335723bf9e15SSepherosa Ziehau } 335823bf9e15SSepherosa Ziehau 335923bf9e15SSepherosa Ziehau error = hn_encap(txr, txd, &m_head); 336023bf9e15SSepherosa Ziehau if (error) { 336123bf9e15SSepherosa Ziehau /* Both txd and m_head are freed */ 336223bf9e15SSepherosa Ziehau continue; 336323bf9e15SSepherosa Ziehau } 336423bf9e15SSepherosa Ziehau 336523bf9e15SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 336623bf9e15SSepherosa Ziehau if (__predict_false(error)) { 336723bf9e15SSepherosa Ziehau /* txd is freed, but m_head is not */ 336823bf9e15SSepherosa Ziehau IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 336923bf9e15SSepherosa Ziehau atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 337023bf9e15SSepherosa Ziehau break; 337123bf9e15SSepherosa Ziehau } 337223bf9e15SSepherosa Ziehau } 337323bf9e15SSepherosa Ziehau return 0; 337423bf9e15SSepherosa Ziehau } 337523bf9e15SSepherosa Ziehau 337623bf9e15SSepherosa Ziehau static void 337723bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp) 337823bf9e15SSepherosa Ziehau { 337923bf9e15SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 338023bf9e15SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[0]; 338123bf9e15SSepherosa Ziehau 338223bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 338323bf9e15SSepherosa Ziehau goto do_sched; 338423bf9e15SSepherosa Ziehau 338523bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 338623bf9e15SSepherosa Ziehau int sched; 338723bf9e15SSepherosa Ziehau 338823bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 338923bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 339023bf9e15SSepherosa Ziehau if (!sched) 339123bf9e15SSepherosa Ziehau return; 339223bf9e15SSepherosa Ziehau } 339323bf9e15SSepherosa Ziehau do_sched: 339423bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 339523bf9e15SSepherosa Ziehau } 339623bf9e15SSepherosa Ziehau 339715516c77SSepherosa Ziehau static void 339815516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused) 339915516c77SSepherosa Ziehau { 340015516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 340115516c77SSepherosa Ziehau 340215516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 340315516c77SSepherosa Ziehau atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE); 340415516c77SSepherosa Ziehau hn_start_locked(txr, 0); 340515516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 340615516c77SSepherosa Ziehau } 340715516c77SSepherosa Ziehau 340823bf9e15SSepherosa Ziehau static void 340923bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr) 341023bf9e15SSepherosa Ziehau { 341123bf9e15SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 341223bf9e15SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 341323bf9e15SSepherosa Ziehau 341423bf9e15SSepherosa Ziehau KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); 341523bf9e15SSepherosa Ziehau 341623bf9e15SSepherosa Ziehau if (txr->hn_sched_tx) 341723bf9e15SSepherosa Ziehau goto do_sched; 341823bf9e15SSepherosa Ziehau 341923bf9e15SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 342023bf9e15SSepherosa Ziehau int sched; 342123bf9e15SSepherosa Ziehau 342223bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 342323bf9e15SSepherosa Ziehau sched = hn_start_locked(txr, txr->hn_direct_tx_size); 342423bf9e15SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 342523bf9e15SSepherosa Ziehau if (sched) { 342623bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 342723bf9e15SSepherosa Ziehau &txr->hn_tx_task); 342823bf9e15SSepherosa Ziehau } 342923bf9e15SSepherosa Ziehau } else { 343023bf9e15SSepherosa Ziehau do_sched: 343123bf9e15SSepherosa Ziehau /* 343223bf9e15SSepherosa Ziehau * Release the OACTIVE earlier, with the hope, that 343323bf9e15SSepherosa Ziehau * others could catch up. The task will clear the 343423bf9e15SSepherosa Ziehau * flag again with the hn_tx_lock to avoid possible 343523bf9e15SSepherosa Ziehau * races. 343623bf9e15SSepherosa Ziehau */ 343723bf9e15SSepherosa Ziehau atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 343823bf9e15SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 343923bf9e15SSepherosa Ziehau } 344023bf9e15SSepherosa Ziehau } 344123bf9e15SSepherosa Ziehau 344223bf9e15SSepherosa Ziehau #endif /* HN_IFSTART_SUPPORT */ 344323bf9e15SSepherosa Ziehau 344415516c77SSepherosa Ziehau static int 344515516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len) 344615516c77SSepherosa Ziehau { 344715516c77SSepherosa Ziehau struct hn_softc *sc = txr->hn_sc; 344815516c77SSepherosa Ziehau struct ifnet *ifp = sc->hn_ifp; 344915516c77SSepherosa Ziehau struct mbuf *m_head; 345015516c77SSepherosa Ziehau 345115516c77SSepherosa Ziehau mtx_assert(&txr->hn_tx_lock, MA_OWNED); 345223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 345315516c77SSepherosa Ziehau KASSERT(hn_use_if_start == 0, 345415516c77SSepherosa Ziehau ("hn_xmit is called, when if_start is enabled")); 345523bf9e15SSepherosa Ziehau #endif 345615516c77SSepherosa Ziehau 345715516c77SSepherosa Ziehau if (__predict_false(txr->hn_suspended)) 345815516c77SSepherosa Ziehau return 0; 345915516c77SSepherosa Ziehau 346015516c77SSepherosa Ziehau if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive) 346115516c77SSepherosa Ziehau return 0; 346215516c77SSepherosa Ziehau 346315516c77SSepherosa Ziehau while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) { 346415516c77SSepherosa Ziehau struct hn_txdesc *txd; 346515516c77SSepherosa Ziehau int error; 346615516c77SSepherosa Ziehau 346715516c77SSepherosa Ziehau if (len > 0 && m_head->m_pkthdr.len > len) { 346815516c77SSepherosa Ziehau /* 346915516c77SSepherosa Ziehau * This sending could be time consuming; let callers 347015516c77SSepherosa Ziehau * dispatch this packet sending (and sending of any 347115516c77SSepherosa Ziehau * following up packets) to tx taskqueue. 347215516c77SSepherosa Ziehau */ 347315516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 347415516c77SSepherosa Ziehau return 1; 347515516c77SSepherosa Ziehau } 347615516c77SSepherosa Ziehau 347715516c77SSepherosa Ziehau txd = hn_txdesc_get(txr); 347815516c77SSepherosa Ziehau if (txd == NULL) { 347915516c77SSepherosa Ziehau txr->hn_no_txdescs++; 348015516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 348115516c77SSepherosa Ziehau txr->hn_oactive = 1; 348215516c77SSepherosa Ziehau break; 348315516c77SSepherosa Ziehau } 348415516c77SSepherosa Ziehau 348515516c77SSepherosa Ziehau error = hn_encap(txr, txd, &m_head); 348615516c77SSepherosa Ziehau if (error) { 348715516c77SSepherosa Ziehau /* Both txd and m_head are freed; discard */ 348815516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 348915516c77SSepherosa Ziehau continue; 349015516c77SSepherosa Ziehau } 349115516c77SSepherosa Ziehau 349215516c77SSepherosa Ziehau error = hn_txpkt(ifp, txr, txd); 349315516c77SSepherosa Ziehau if (__predict_false(error)) { 349415516c77SSepherosa Ziehau /* txd is freed, but m_head is not */ 349515516c77SSepherosa Ziehau drbr_putback(ifp, txr->hn_mbuf_br, m_head); 349615516c77SSepherosa Ziehau txr->hn_oactive = 1; 349715516c77SSepherosa Ziehau break; 349815516c77SSepherosa Ziehau } 349915516c77SSepherosa Ziehau 350015516c77SSepherosa Ziehau /* Sent */ 350115516c77SSepherosa Ziehau drbr_advance(ifp, txr->hn_mbuf_br); 350215516c77SSepherosa Ziehau } 350315516c77SSepherosa Ziehau return 0; 350415516c77SSepherosa Ziehau } 350515516c77SSepherosa Ziehau 350615516c77SSepherosa Ziehau static int 350715516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m) 350815516c77SSepherosa Ziehau { 350915516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 351015516c77SSepherosa Ziehau struct hn_tx_ring *txr; 351115516c77SSepherosa Ziehau int error, idx = 0; 351215516c77SSepherosa Ziehau 3513edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET) 3514edd3f315SSepherosa Ziehau /* 3515edd3f315SSepherosa Ziehau * Perform TSO packet header fixup now, since the TSO 3516edd3f315SSepherosa Ziehau * packet header should be cache-hot. 3517edd3f315SSepherosa Ziehau */ 3518edd3f315SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 3519edd3f315SSepherosa Ziehau m = hn_tso_fixup(m); 3520edd3f315SSepherosa Ziehau if (__predict_false(m == NULL)) { 3521edd3f315SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 3522edd3f315SSepherosa Ziehau return EIO; 3523edd3f315SSepherosa Ziehau } 3524edd3f315SSepherosa Ziehau } 3525edd3f315SSepherosa Ziehau #endif 3526edd3f315SSepherosa Ziehau 352715516c77SSepherosa Ziehau /* 352815516c77SSepherosa Ziehau * Select the TX ring based on flowid 352915516c77SSepherosa Ziehau */ 353015516c77SSepherosa Ziehau if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 353115516c77SSepherosa Ziehau idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse; 353215516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 353315516c77SSepherosa Ziehau 353415516c77SSepherosa Ziehau error = drbr_enqueue(ifp, txr->hn_mbuf_br, m); 353515516c77SSepherosa Ziehau if (error) { 353615516c77SSepherosa Ziehau if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 353715516c77SSepherosa Ziehau return error; 353815516c77SSepherosa Ziehau } 353915516c77SSepherosa Ziehau 354015516c77SSepherosa Ziehau if (txr->hn_oactive) 354115516c77SSepherosa Ziehau return 0; 354215516c77SSepherosa Ziehau 354315516c77SSepherosa Ziehau if (txr->hn_sched_tx) 354415516c77SSepherosa Ziehau goto do_sched; 354515516c77SSepherosa Ziehau 354615516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 354715516c77SSepherosa Ziehau int sched; 354815516c77SSepherosa Ziehau 354915516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 355015516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 355115516c77SSepherosa Ziehau if (!sched) 355215516c77SSepherosa Ziehau return 0; 355315516c77SSepherosa Ziehau } 355415516c77SSepherosa Ziehau do_sched: 355515516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task); 355615516c77SSepherosa Ziehau return 0; 355715516c77SSepherosa Ziehau } 355815516c77SSepherosa Ziehau 355915516c77SSepherosa Ziehau static void 356015516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr) 356115516c77SSepherosa Ziehau { 356215516c77SSepherosa Ziehau struct mbuf *m; 356315516c77SSepherosa Ziehau 356415516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 356515516c77SSepherosa Ziehau while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL) 356615516c77SSepherosa Ziehau m_freem(m); 356715516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 356815516c77SSepherosa Ziehau } 356915516c77SSepherosa Ziehau 357015516c77SSepherosa Ziehau static void 357115516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp) 357215516c77SSepherosa Ziehau { 357315516c77SSepherosa Ziehau struct hn_softc *sc = ifp->if_softc; 357415516c77SSepherosa Ziehau int i; 357515516c77SSepherosa Ziehau 357615516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) 357715516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 357815516c77SSepherosa Ziehau if_qflush(ifp); 357915516c77SSepherosa Ziehau } 358015516c77SSepherosa Ziehau 358115516c77SSepherosa Ziehau static void 358215516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr) 358315516c77SSepherosa Ziehau { 358415516c77SSepherosa Ziehau 358515516c77SSepherosa Ziehau if (txr->hn_sched_tx) 358615516c77SSepherosa Ziehau goto do_sched; 358715516c77SSepherosa Ziehau 358815516c77SSepherosa Ziehau if (mtx_trylock(&txr->hn_tx_lock)) { 358915516c77SSepherosa Ziehau int sched; 359015516c77SSepherosa Ziehau 359115516c77SSepherosa Ziehau txr->hn_oactive = 0; 359215516c77SSepherosa Ziehau sched = hn_xmit(txr, txr->hn_direct_tx_size); 359315516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 359415516c77SSepherosa Ziehau if (sched) { 359515516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, 359615516c77SSepherosa Ziehau &txr->hn_tx_task); 359715516c77SSepherosa Ziehau } 359815516c77SSepherosa Ziehau } else { 359915516c77SSepherosa Ziehau do_sched: 360015516c77SSepherosa Ziehau /* 360115516c77SSepherosa Ziehau * Release the oactive earlier, with the hope, that 360215516c77SSepherosa Ziehau * others could catch up. The task will clear the 360315516c77SSepherosa Ziehau * oactive again with the hn_tx_lock to avoid possible 360415516c77SSepherosa Ziehau * races. 360515516c77SSepherosa Ziehau */ 360615516c77SSepherosa Ziehau txr->hn_oactive = 0; 360715516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 360815516c77SSepherosa Ziehau } 360915516c77SSepherosa Ziehau } 361015516c77SSepherosa Ziehau 361115516c77SSepherosa Ziehau static void 361215516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused) 361315516c77SSepherosa Ziehau { 361415516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 361515516c77SSepherosa Ziehau 361615516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 361715516c77SSepherosa Ziehau hn_xmit(txr, 0); 361815516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 361915516c77SSepherosa Ziehau } 362015516c77SSepherosa Ziehau 362115516c77SSepherosa Ziehau static void 362215516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused) 362315516c77SSepherosa Ziehau { 362415516c77SSepherosa Ziehau struct hn_tx_ring *txr = xtxr; 362515516c77SSepherosa Ziehau 362615516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 362715516c77SSepherosa Ziehau txr->hn_oactive = 0; 362815516c77SSepherosa Ziehau hn_xmit(txr, 0); 362915516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 363015516c77SSepherosa Ziehau } 363115516c77SSepherosa Ziehau 363215516c77SSepherosa Ziehau static int 363315516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan) 363415516c77SSepherosa Ziehau { 363515516c77SSepherosa Ziehau struct vmbus_chan_br cbr; 363615516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 363715516c77SSepherosa Ziehau struct hn_tx_ring *txr = NULL; 363815516c77SSepherosa Ziehau int idx, error; 363915516c77SSepherosa Ziehau 364015516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 364115516c77SSepherosa Ziehau 364215516c77SSepherosa Ziehau /* 364315516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 364415516c77SSepherosa Ziehau */ 364515516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 364615516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 364715516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 364815516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 364915516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0, 365015516c77SSepherosa Ziehau ("RX ring %d already attached", idx)); 365115516c77SSepherosa Ziehau rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED; 365215516c77SSepherosa Ziehau 365315516c77SSepherosa Ziehau if (bootverbose) { 365415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n", 365515516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 365615516c77SSepherosa Ziehau } 365715516c77SSepherosa Ziehau 365815516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 365915516c77SSepherosa Ziehau txr = &sc->hn_tx_ring[idx]; 366015516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0, 366115516c77SSepherosa Ziehau ("TX ring %d already attached", idx)); 366215516c77SSepherosa Ziehau txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED; 366315516c77SSepherosa Ziehau 366415516c77SSepherosa Ziehau txr->hn_chan = chan; 366515516c77SSepherosa Ziehau if (bootverbose) { 366615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n", 366715516c77SSepherosa Ziehau idx, vmbus_chan_id(chan)); 366815516c77SSepherosa Ziehau } 366915516c77SSepherosa Ziehau } 367015516c77SSepherosa Ziehau 367115516c77SSepherosa Ziehau /* Bind this channel to a proper CPU. */ 367215516c77SSepherosa Ziehau vmbus_chan_cpu_set(chan, (sc->hn_cpu + idx) % mp_ncpus); 367315516c77SSepherosa Ziehau 367415516c77SSepherosa Ziehau /* 367515516c77SSepherosa Ziehau * Open this channel 367615516c77SSepherosa Ziehau */ 367715516c77SSepherosa Ziehau cbr.cbr = rxr->hn_br; 367815516c77SSepherosa Ziehau cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr; 367915516c77SSepherosa Ziehau cbr.cbr_txsz = HN_TXBR_SIZE; 368015516c77SSepherosa Ziehau cbr.cbr_rxsz = HN_RXBR_SIZE; 368115516c77SSepherosa Ziehau error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr); 368215516c77SSepherosa Ziehau if (error) { 368315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "open chan%u failed: %d\n", 368415516c77SSepherosa Ziehau vmbus_chan_id(chan), error); 368515516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 368615516c77SSepherosa Ziehau if (txr != NULL) 368715516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 368815516c77SSepherosa Ziehau } 368915516c77SSepherosa Ziehau return (error); 369015516c77SSepherosa Ziehau } 369115516c77SSepherosa Ziehau 369215516c77SSepherosa Ziehau static void 369315516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan) 369415516c77SSepherosa Ziehau { 369515516c77SSepherosa Ziehau struct hn_rx_ring *rxr; 369615516c77SSepherosa Ziehau int idx; 369715516c77SSepherosa Ziehau 369815516c77SSepherosa Ziehau idx = vmbus_chan_subidx(chan); 369915516c77SSepherosa Ziehau 370015516c77SSepherosa Ziehau /* 370115516c77SSepherosa Ziehau * Link this channel to RX/TX ring. 370215516c77SSepherosa Ziehau */ 370315516c77SSepherosa Ziehau KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse, 370415516c77SSepherosa Ziehau ("invalid channel index %d, should > 0 && < %d", 370515516c77SSepherosa Ziehau idx, sc->hn_rx_ring_inuse)); 370615516c77SSepherosa Ziehau rxr = &sc->hn_rx_ring[idx]; 370715516c77SSepherosa Ziehau KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED), 370815516c77SSepherosa Ziehau ("RX ring %d is not attached", idx)); 370915516c77SSepherosa Ziehau rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED; 371015516c77SSepherosa Ziehau 371115516c77SSepherosa Ziehau if (idx < sc->hn_tx_ring_inuse) { 371215516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[idx]; 371315516c77SSepherosa Ziehau 371415516c77SSepherosa Ziehau KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED), 371515516c77SSepherosa Ziehau ("TX ring %d is not attached attached", idx)); 371615516c77SSepherosa Ziehau txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED; 371715516c77SSepherosa Ziehau } 371815516c77SSepherosa Ziehau 371915516c77SSepherosa Ziehau /* 372015516c77SSepherosa Ziehau * Close this channel. 372115516c77SSepherosa Ziehau * 372215516c77SSepherosa Ziehau * NOTE: 372315516c77SSepherosa Ziehau * Channel closing does _not_ destroy the target channel. 372415516c77SSepherosa Ziehau */ 372515516c77SSepherosa Ziehau vmbus_chan_close(chan); 372615516c77SSepherosa Ziehau } 372715516c77SSepherosa Ziehau 372815516c77SSepherosa Ziehau static int 372915516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc) 373015516c77SSepherosa Ziehau { 373115516c77SSepherosa Ziehau struct vmbus_channel **subchans; 373215516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 373315516c77SSepherosa Ziehau int i, error = 0; 373415516c77SSepherosa Ziehau 373515516c77SSepherosa Ziehau if (subchan_cnt == 0) 373615516c77SSepherosa Ziehau return (0); 373715516c77SSepherosa Ziehau 373815516c77SSepherosa Ziehau /* Attach the sub-channels. */ 373915516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 374015516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) { 374115516c77SSepherosa Ziehau error = hn_chan_attach(sc, subchans[i]); 374215516c77SSepherosa Ziehau if (error) 374315516c77SSepherosa Ziehau break; 374415516c77SSepherosa Ziehau } 374515516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 374615516c77SSepherosa Ziehau 374715516c77SSepherosa Ziehau if (error) { 374815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error); 374915516c77SSepherosa Ziehau } else { 375015516c77SSepherosa Ziehau if (bootverbose) { 375115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d sub-channels attached\n", 375215516c77SSepherosa Ziehau subchan_cnt); 375315516c77SSepherosa Ziehau } 375415516c77SSepherosa Ziehau } 375515516c77SSepherosa Ziehau return (error); 375615516c77SSepherosa Ziehau } 375715516c77SSepherosa Ziehau 375815516c77SSepherosa Ziehau static void 375915516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc) 376015516c77SSepherosa Ziehau { 376115516c77SSepherosa Ziehau struct vmbus_channel **subchans; 376215516c77SSepherosa Ziehau int subchan_cnt = sc->hn_rx_ring_inuse - 1; 376315516c77SSepherosa Ziehau int i; 376415516c77SSepherosa Ziehau 376515516c77SSepherosa Ziehau if (subchan_cnt == 0) 376615516c77SSepherosa Ziehau goto back; 376715516c77SSepherosa Ziehau 376815516c77SSepherosa Ziehau /* Detach the sub-channels. */ 376915516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt); 377015516c77SSepherosa Ziehau for (i = 0; i < subchan_cnt; ++i) 377115516c77SSepherosa Ziehau hn_chan_detach(sc, subchans[i]); 377215516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, subchan_cnt); 377315516c77SSepherosa Ziehau 377415516c77SSepherosa Ziehau back: 377515516c77SSepherosa Ziehau /* 377615516c77SSepherosa Ziehau * Detach the primary channel, _after_ all sub-channels 377715516c77SSepherosa Ziehau * are detached. 377815516c77SSepherosa Ziehau */ 377915516c77SSepherosa Ziehau hn_chan_detach(sc, sc->hn_prichan); 378015516c77SSepherosa Ziehau 378115516c77SSepherosa Ziehau /* Wait for sub-channels to be destroyed, if any. */ 378215516c77SSepherosa Ziehau vmbus_subchan_drain(sc->hn_prichan); 378315516c77SSepherosa Ziehau 378415516c77SSepherosa Ziehau #ifdef INVARIANTS 378515516c77SSepherosa Ziehau for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { 378615516c77SSepherosa Ziehau KASSERT((sc->hn_rx_ring[i].hn_rx_flags & 378715516c77SSepherosa Ziehau HN_RX_FLAG_ATTACHED) == 0, 378815516c77SSepherosa Ziehau ("%dth RX ring is still attached", i)); 378915516c77SSepherosa Ziehau } 379015516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { 379115516c77SSepherosa Ziehau KASSERT((sc->hn_tx_ring[i].hn_tx_flags & 379215516c77SSepherosa Ziehau HN_TX_FLAG_ATTACHED) == 0, 379315516c77SSepherosa Ziehau ("%dth TX ring is still attached", i)); 379415516c77SSepherosa Ziehau } 379515516c77SSepherosa Ziehau #endif 379615516c77SSepherosa Ziehau } 379715516c77SSepherosa Ziehau 379815516c77SSepherosa Ziehau static int 379915516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch) 380015516c77SSepherosa Ziehau { 380115516c77SSepherosa Ziehau struct vmbus_channel **subchans; 380215516c77SSepherosa Ziehau int nchan, rxr_cnt, error; 380315516c77SSepherosa Ziehau 380415516c77SSepherosa Ziehau nchan = *nsubch + 1; 380515516c77SSepherosa Ziehau if (nchan == 1) { 380615516c77SSepherosa Ziehau /* 380715516c77SSepherosa Ziehau * Multiple RX/TX rings are not requested. 380815516c77SSepherosa Ziehau */ 380915516c77SSepherosa Ziehau *nsubch = 0; 381015516c77SSepherosa Ziehau return (0); 381115516c77SSepherosa Ziehau } 381215516c77SSepherosa Ziehau 381315516c77SSepherosa Ziehau /* 381415516c77SSepherosa Ziehau * Query RSS capabilities, e.g. # of RX rings, and # of indirect 381515516c77SSepherosa Ziehau * table entries. 381615516c77SSepherosa Ziehau */ 381715516c77SSepherosa Ziehau error = hn_rndis_query_rsscaps(sc, &rxr_cnt); 381815516c77SSepherosa Ziehau if (error) { 381915516c77SSepherosa Ziehau /* No RSS; this is benign. */ 382015516c77SSepherosa Ziehau *nsubch = 0; 382115516c77SSepherosa Ziehau return (0); 382215516c77SSepherosa Ziehau } 382315516c77SSepherosa Ziehau if (bootverbose) { 382415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n", 382515516c77SSepherosa Ziehau rxr_cnt, nchan); 382615516c77SSepherosa Ziehau } 382715516c77SSepherosa Ziehau 382815516c77SSepherosa Ziehau if (nchan > rxr_cnt) 382915516c77SSepherosa Ziehau nchan = rxr_cnt; 383015516c77SSepherosa Ziehau if (nchan == 1) { 383115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n"); 383215516c77SSepherosa Ziehau *nsubch = 0; 383315516c77SSepherosa Ziehau return (0); 383415516c77SSepherosa Ziehau } 383515516c77SSepherosa Ziehau 383615516c77SSepherosa Ziehau /* 383715516c77SSepherosa Ziehau * Allocate sub-channels from NVS. 383815516c77SSepherosa Ziehau */ 383915516c77SSepherosa Ziehau *nsubch = nchan - 1; 384015516c77SSepherosa Ziehau error = hn_nvs_alloc_subchans(sc, nsubch); 384115516c77SSepherosa Ziehau if (error || *nsubch == 0) { 384215516c77SSepherosa Ziehau /* Failed to allocate sub-channels. */ 384315516c77SSepherosa Ziehau *nsubch = 0; 384415516c77SSepherosa Ziehau return (0); 384515516c77SSepherosa Ziehau } 384615516c77SSepherosa Ziehau 384715516c77SSepherosa Ziehau /* 384815516c77SSepherosa Ziehau * Wait for all sub-channels to become ready before moving on. 384915516c77SSepherosa Ziehau */ 385015516c77SSepherosa Ziehau subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch); 385115516c77SSepherosa Ziehau vmbus_subchan_rel(subchans, *nsubch); 385215516c77SSepherosa Ziehau return (0); 385315516c77SSepherosa Ziehau } 385415516c77SSepherosa Ziehau 385515516c77SSepherosa Ziehau static int 385615516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu) 385715516c77SSepherosa Ziehau { 385815516c77SSepherosa Ziehau struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; 385915516c77SSepherosa Ziehau int error, nsubch, nchan, i; 386015516c77SSepherosa Ziehau uint32_t old_caps; 386115516c77SSepherosa Ziehau 386215516c77SSepherosa Ziehau KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0, 386315516c77SSepherosa Ziehau ("synthetic parts were attached")); 386415516c77SSepherosa Ziehau 386515516c77SSepherosa Ziehau /* Save capabilities for later verification. */ 386615516c77SSepherosa Ziehau old_caps = sc->hn_caps; 386715516c77SSepherosa Ziehau sc->hn_caps = 0; 386815516c77SSepherosa Ziehau 386915516c77SSepherosa Ziehau /* Clear RSS stuffs. */ 387015516c77SSepherosa Ziehau sc->hn_rss_ind_size = 0; 387115516c77SSepherosa Ziehau sc->hn_rss_hash = 0; 387215516c77SSepherosa Ziehau 387315516c77SSepherosa Ziehau /* 387415516c77SSepherosa Ziehau * Attach the primary channel _before_ attaching NVS and RNDIS. 387515516c77SSepherosa Ziehau */ 387615516c77SSepherosa Ziehau error = hn_chan_attach(sc, sc->hn_prichan); 387715516c77SSepherosa Ziehau if (error) 387815516c77SSepherosa Ziehau return (error); 387915516c77SSepherosa Ziehau 388015516c77SSepherosa Ziehau /* 388115516c77SSepherosa Ziehau * Attach NVS. 388215516c77SSepherosa Ziehau */ 388315516c77SSepherosa Ziehau error = hn_nvs_attach(sc, mtu); 388415516c77SSepherosa Ziehau if (error) 388515516c77SSepherosa Ziehau return (error); 388615516c77SSepherosa Ziehau 388715516c77SSepherosa Ziehau /* 388815516c77SSepherosa Ziehau * Attach RNDIS _after_ NVS is attached. 388915516c77SSepherosa Ziehau */ 389015516c77SSepherosa Ziehau error = hn_rndis_attach(sc, mtu); 389115516c77SSepherosa Ziehau if (error) 389215516c77SSepherosa Ziehau return (error); 389315516c77SSepherosa Ziehau 389415516c77SSepherosa Ziehau /* 389515516c77SSepherosa Ziehau * Make sure capabilities are not changed. 389615516c77SSepherosa Ziehau */ 389715516c77SSepherosa Ziehau if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) { 389815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n", 389915516c77SSepherosa Ziehau old_caps, sc->hn_caps); 390015516c77SSepherosa Ziehau /* Restore old capabilities and abort. */ 390115516c77SSepherosa Ziehau sc->hn_caps = old_caps; 390215516c77SSepherosa Ziehau return ENXIO; 390315516c77SSepherosa Ziehau } 390415516c77SSepherosa Ziehau 390515516c77SSepherosa Ziehau /* 390615516c77SSepherosa Ziehau * Allocate sub-channels for multi-TX/RX rings. 390715516c77SSepherosa Ziehau * 390815516c77SSepherosa Ziehau * NOTE: 390915516c77SSepherosa Ziehau * The # of RX rings that can be used is equivalent to the # of 391015516c77SSepherosa Ziehau * channels to be requested. 391115516c77SSepherosa Ziehau */ 391215516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_cnt - 1; 391315516c77SSepherosa Ziehau error = hn_synth_alloc_subchans(sc, &nsubch); 391415516c77SSepherosa Ziehau if (error) 391515516c77SSepherosa Ziehau return (error); 391615516c77SSepherosa Ziehau 391715516c77SSepherosa Ziehau nchan = nsubch + 1; 391815516c77SSepherosa Ziehau if (nchan == 1) { 391915516c77SSepherosa Ziehau /* Only the primary channel can be used; done */ 392015516c77SSepherosa Ziehau goto back; 392115516c77SSepherosa Ziehau } 392215516c77SSepherosa Ziehau 392315516c77SSepherosa Ziehau /* 392415516c77SSepherosa Ziehau * Configure RSS key and indirect table _after_ all sub-channels 392515516c77SSepherosa Ziehau * are allocated. 392615516c77SSepherosa Ziehau */ 392715516c77SSepherosa Ziehau 392815516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) { 392915516c77SSepherosa Ziehau /* 393015516c77SSepherosa Ziehau * RSS key is not set yet; set it to the default RSS key. 393115516c77SSepherosa Ziehau */ 393215516c77SSepherosa Ziehau if (bootverbose) 393315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS key\n"); 393415516c77SSepherosa Ziehau memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key)); 393515516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSKEY; 393615516c77SSepherosa Ziehau } 393715516c77SSepherosa Ziehau 393815516c77SSepherosa Ziehau if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) { 393915516c77SSepherosa Ziehau /* 394015516c77SSepherosa Ziehau * RSS indirect table is not set yet; set it up in round- 394115516c77SSepherosa Ziehau * robin fashion. 394215516c77SSepherosa Ziehau */ 394315516c77SSepherosa Ziehau if (bootverbose) { 394415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "setup default RSS indirect " 394515516c77SSepherosa Ziehau "table\n"); 394615516c77SSepherosa Ziehau } 394715516c77SSepherosa Ziehau for (i = 0; i < NDIS_HASH_INDCNT; ++i) 394815516c77SSepherosa Ziehau rss->rss_ind[i] = i % nchan; 394915516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_HAS_RSSIND; 395015516c77SSepherosa Ziehau } else { 395115516c77SSepherosa Ziehau /* 395215516c77SSepherosa Ziehau * # of usable channels may be changed, so we have to 395315516c77SSepherosa Ziehau * make sure that all entries in RSS indirect table 395415516c77SSepherosa Ziehau * are valid. 395515516c77SSepherosa Ziehau */ 395615516c77SSepherosa Ziehau hn_rss_ind_fixup(sc, nchan); 395715516c77SSepherosa Ziehau } 395815516c77SSepherosa Ziehau 395915516c77SSepherosa Ziehau error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); 396015516c77SSepherosa Ziehau if (error) { 396115516c77SSepherosa Ziehau /* 396215516c77SSepherosa Ziehau * Failed to configure RSS key or indirect table; only 396315516c77SSepherosa Ziehau * the primary channel can be used. 396415516c77SSepherosa Ziehau */ 396515516c77SSepherosa Ziehau nchan = 1; 396615516c77SSepherosa Ziehau } 396715516c77SSepherosa Ziehau back: 396815516c77SSepherosa Ziehau /* 396915516c77SSepherosa Ziehau * Set the # of TX/RX rings that could be used according to 397015516c77SSepherosa Ziehau * the # of channels that NVS offered. 397115516c77SSepherosa Ziehau */ 397215516c77SSepherosa Ziehau hn_set_ring_inuse(sc, nchan); 397315516c77SSepherosa Ziehau 397415516c77SSepherosa Ziehau /* 397515516c77SSepherosa Ziehau * Attach the sub-channels, if any. 397615516c77SSepherosa Ziehau */ 397715516c77SSepherosa Ziehau error = hn_attach_subchans(sc); 397815516c77SSepherosa Ziehau if (error) 397915516c77SSepherosa Ziehau return (error); 398015516c77SSepherosa Ziehau 398115516c77SSepherosa Ziehau sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED; 398215516c77SSepherosa Ziehau return (0); 398315516c77SSepherosa Ziehau } 398415516c77SSepherosa Ziehau 398515516c77SSepherosa Ziehau /* 398615516c77SSepherosa Ziehau * NOTE: 398715516c77SSepherosa Ziehau * The interface must have been suspended though hn_suspend(), before 398815516c77SSepherosa Ziehau * this function get called. 398915516c77SSepherosa Ziehau */ 399015516c77SSepherosa Ziehau static void 399115516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc) 399215516c77SSepherosa Ziehau { 399315516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 399415516c77SSepherosa Ziehau 399515516c77SSepherosa Ziehau KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, 399615516c77SSepherosa Ziehau ("synthetic parts were not attached")); 399715516c77SSepherosa Ziehau 399815516c77SSepherosa Ziehau /* Detach the RNDIS first. */ 399915516c77SSepherosa Ziehau hn_rndis_detach(sc); 400015516c77SSepherosa Ziehau 400115516c77SSepherosa Ziehau /* Detach NVS. */ 400215516c77SSepherosa Ziehau hn_nvs_detach(sc); 400315516c77SSepherosa Ziehau 400415516c77SSepherosa Ziehau /* Detach all of the channels. */ 400515516c77SSepherosa Ziehau hn_detach_allchans(sc); 400615516c77SSepherosa Ziehau 400715516c77SSepherosa Ziehau sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED; 400815516c77SSepherosa Ziehau } 400915516c77SSepherosa Ziehau 401015516c77SSepherosa Ziehau static void 401115516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt) 401215516c77SSepherosa Ziehau { 401315516c77SSepherosa Ziehau KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt, 401415516c77SSepherosa Ziehau ("invalid ring count %d", ring_cnt)); 401515516c77SSepherosa Ziehau 401615516c77SSepherosa Ziehau if (sc->hn_tx_ring_cnt > ring_cnt) 401715516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = ring_cnt; 401815516c77SSepherosa Ziehau else 401915516c77SSepherosa Ziehau sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt; 402015516c77SSepherosa Ziehau sc->hn_rx_ring_inuse = ring_cnt; 402115516c77SSepherosa Ziehau 402215516c77SSepherosa Ziehau if (bootverbose) { 402315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n", 402415516c77SSepherosa Ziehau sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse); 402515516c77SSepherosa Ziehau } 402615516c77SSepherosa Ziehau } 402715516c77SSepherosa Ziehau 402815516c77SSepherosa Ziehau static void 402915516c77SSepherosa Ziehau hn_chan_drain(struct vmbus_channel *chan) 403015516c77SSepherosa Ziehau { 403115516c77SSepherosa Ziehau 403215516c77SSepherosa Ziehau while (!vmbus_chan_rx_empty(chan) || !vmbus_chan_tx_empty(chan)) 403315516c77SSepherosa Ziehau pause("waitch", 1); 403415516c77SSepherosa Ziehau vmbus_chan_intr_drain(chan); 403515516c77SSepherosa Ziehau } 403615516c77SSepherosa Ziehau 403715516c77SSepherosa Ziehau static void 403815516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc) 403915516c77SSepherosa Ziehau { 404015516c77SSepherosa Ziehau struct vmbus_channel **subch = NULL; 404115516c77SSepherosa Ziehau int i, nsubch; 404215516c77SSepherosa Ziehau 404315516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 404415516c77SSepherosa Ziehau 404515516c77SSepherosa Ziehau /* 404615516c77SSepherosa Ziehau * Suspend TX. 404715516c77SSepherosa Ziehau */ 404815516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 404915516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 405015516c77SSepherosa Ziehau 405115516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 405215516c77SSepherosa Ziehau txr->hn_suspended = 1; 405315516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 405415516c77SSepherosa Ziehau /* No one is able send more packets now. */ 405515516c77SSepherosa Ziehau 405615516c77SSepherosa Ziehau /* Wait for all pending sends to finish. */ 405715516c77SSepherosa Ziehau while (hn_tx_ring_pending(txr)) 405815516c77SSepherosa Ziehau pause("hnwtx", 1 /* 1 tick */); 405915516c77SSepherosa Ziehau 406015516c77SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task); 406115516c77SSepherosa Ziehau taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task); 406215516c77SSepherosa Ziehau } 406315516c77SSepherosa Ziehau 406415516c77SSepherosa Ziehau /* 406515516c77SSepherosa Ziehau * Disable RX by clearing RX filter. 406615516c77SSepherosa Ziehau */ 406715516c77SSepherosa Ziehau sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE; 406815516c77SSepherosa Ziehau hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); 406915516c77SSepherosa Ziehau 407015516c77SSepherosa Ziehau /* 407115516c77SSepherosa Ziehau * Give RNDIS enough time to flush all pending data packets. 407215516c77SSepherosa Ziehau */ 407315516c77SSepherosa Ziehau pause("waitrx", (200 * hz) / 1000); 407415516c77SSepherosa Ziehau 407515516c77SSepherosa Ziehau /* 407615516c77SSepherosa Ziehau * Drain RX/TX bufrings and interrupts. 407715516c77SSepherosa Ziehau */ 407815516c77SSepherosa Ziehau nsubch = sc->hn_rx_ring_inuse - 1; 407915516c77SSepherosa Ziehau if (nsubch > 0) 408015516c77SSepherosa Ziehau subch = vmbus_subchan_get(sc->hn_prichan, nsubch); 408115516c77SSepherosa Ziehau 408215516c77SSepherosa Ziehau if (subch != NULL) { 408315516c77SSepherosa Ziehau for (i = 0; i < nsubch; ++i) 408415516c77SSepherosa Ziehau hn_chan_drain(subch[i]); 408515516c77SSepherosa Ziehau } 408615516c77SSepherosa Ziehau hn_chan_drain(sc->hn_prichan); 408715516c77SSepherosa Ziehau 408815516c77SSepherosa Ziehau if (subch != NULL) 408915516c77SSepherosa Ziehau vmbus_subchan_rel(subch, nsubch); 409015516c77SSepherosa Ziehau } 409115516c77SSepherosa Ziehau 409215516c77SSepherosa Ziehau static void 409315516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused) 409415516c77SSepherosa Ziehau { 409515516c77SSepherosa Ziehau 409615516c77SSepherosa Ziehau ((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL; 409715516c77SSepherosa Ziehau } 409815516c77SSepherosa Ziehau 409915516c77SSepherosa Ziehau static void 410015516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc) 410115516c77SSepherosa Ziehau { 410215516c77SSepherosa Ziehau struct task task; 410315516c77SSepherosa Ziehau 410415516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 410515516c77SSepherosa Ziehau 410615516c77SSepherosa Ziehau /* 410715516c77SSepherosa Ziehau * Make sure that hn_mgmt_taskq0 can nolonger be accessed 410815516c77SSepherosa Ziehau * through hn_mgmt_taskq. 410915516c77SSepherosa Ziehau */ 411015516c77SSepherosa Ziehau TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc); 411115516c77SSepherosa Ziehau vmbus_chan_run_task(sc->hn_prichan, &task); 411215516c77SSepherosa Ziehau 411315516c77SSepherosa Ziehau /* 411415516c77SSepherosa Ziehau * Make sure that all pending management tasks are completed. 411515516c77SSepherosa Ziehau */ 411615516c77SSepherosa Ziehau taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init); 411715516c77SSepherosa Ziehau taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status); 411815516c77SSepherosa Ziehau taskqueue_drain_all(sc->hn_mgmt_taskq0); 411915516c77SSepherosa Ziehau } 412015516c77SSepherosa Ziehau 412115516c77SSepherosa Ziehau static void 412215516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc) 412315516c77SSepherosa Ziehau { 412415516c77SSepherosa Ziehau 412515516c77SSepherosa Ziehau if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 412615516c77SSepherosa Ziehau hn_suspend_data(sc); 412715516c77SSepherosa Ziehau hn_suspend_mgmt(sc); 412815516c77SSepherosa Ziehau } 412915516c77SSepherosa Ziehau 413015516c77SSepherosa Ziehau static void 413115516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt) 413215516c77SSepherosa Ziehau { 413315516c77SSepherosa Ziehau int i; 413415516c77SSepherosa Ziehau 413515516c77SSepherosa Ziehau KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt, 413615516c77SSepherosa Ziehau ("invalid TX ring count %d", tx_ring_cnt)); 413715516c77SSepherosa Ziehau 413815516c77SSepherosa Ziehau for (i = 0; i < tx_ring_cnt; ++i) { 413915516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 414015516c77SSepherosa Ziehau 414115516c77SSepherosa Ziehau mtx_lock(&txr->hn_tx_lock); 414215516c77SSepherosa Ziehau txr->hn_suspended = 0; 414315516c77SSepherosa Ziehau mtx_unlock(&txr->hn_tx_lock); 414415516c77SSepherosa Ziehau } 414515516c77SSepherosa Ziehau } 414615516c77SSepherosa Ziehau 414715516c77SSepherosa Ziehau static void 414815516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc) 414915516c77SSepherosa Ziehau { 415015516c77SSepherosa Ziehau int i; 415115516c77SSepherosa Ziehau 415215516c77SSepherosa Ziehau HN_LOCK_ASSERT(sc); 415315516c77SSepherosa Ziehau 415415516c77SSepherosa Ziehau /* 415515516c77SSepherosa Ziehau * Re-enable RX. 415615516c77SSepherosa Ziehau */ 415715516c77SSepherosa Ziehau hn_set_rxfilter(sc); 415815516c77SSepherosa Ziehau 415915516c77SSepherosa Ziehau /* 416015516c77SSepherosa Ziehau * Make sure to clear suspend status on "all" TX rings, 416115516c77SSepherosa Ziehau * since hn_tx_ring_inuse can be changed after 416215516c77SSepherosa Ziehau * hn_suspend_data(). 416315516c77SSepherosa Ziehau */ 416415516c77SSepherosa Ziehau hn_resume_tx(sc, sc->hn_tx_ring_cnt); 416515516c77SSepherosa Ziehau 416623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT 416723bf9e15SSepherosa Ziehau if (!hn_use_if_start) 416823bf9e15SSepherosa Ziehau #endif 416923bf9e15SSepherosa Ziehau { 417015516c77SSepherosa Ziehau /* 417115516c77SSepherosa Ziehau * Flush unused drbrs, since hn_tx_ring_inuse may be 417215516c77SSepherosa Ziehau * reduced. 417315516c77SSepherosa Ziehau */ 417415516c77SSepherosa Ziehau for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i) 417515516c77SSepherosa Ziehau hn_tx_ring_qflush(&sc->hn_tx_ring[i]); 417615516c77SSepherosa Ziehau } 417715516c77SSepherosa Ziehau 417815516c77SSepherosa Ziehau /* 417915516c77SSepherosa Ziehau * Kick start TX. 418015516c77SSepherosa Ziehau */ 418115516c77SSepherosa Ziehau for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { 418215516c77SSepherosa Ziehau struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; 418315516c77SSepherosa Ziehau 418415516c77SSepherosa Ziehau /* 418515516c77SSepherosa Ziehau * Use txeof task, so that any pending oactive can be 418615516c77SSepherosa Ziehau * cleared properly. 418715516c77SSepherosa Ziehau */ 418815516c77SSepherosa Ziehau taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); 418915516c77SSepherosa Ziehau } 419015516c77SSepherosa Ziehau } 419115516c77SSepherosa Ziehau 419215516c77SSepherosa Ziehau static void 419315516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc) 419415516c77SSepherosa Ziehau { 419515516c77SSepherosa Ziehau 419615516c77SSepherosa Ziehau sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; 419715516c77SSepherosa Ziehau 419815516c77SSepherosa Ziehau /* 419915516c77SSepherosa Ziehau * Kick off network change detection, if it was pending. 420015516c77SSepherosa Ziehau * If no network change was pending, start link status 420115516c77SSepherosa Ziehau * checks, which is more lightweight than network change 420215516c77SSepherosa Ziehau * detection. 420315516c77SSepherosa Ziehau */ 420415516c77SSepherosa Ziehau if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) 420515516c77SSepherosa Ziehau hn_change_network(sc); 420615516c77SSepherosa Ziehau else 420715516c77SSepherosa Ziehau hn_update_link_status(sc); 420815516c77SSepherosa Ziehau } 420915516c77SSepherosa Ziehau 421015516c77SSepherosa Ziehau static void 421115516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc) 421215516c77SSepherosa Ziehau { 421315516c77SSepherosa Ziehau 421415516c77SSepherosa Ziehau if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) 421515516c77SSepherosa Ziehau hn_resume_data(sc); 421615516c77SSepherosa Ziehau hn_resume_mgmt(sc); 421715516c77SSepherosa Ziehau } 421815516c77SSepherosa Ziehau 421915516c77SSepherosa Ziehau static void 422015516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen) 422115516c77SSepherosa Ziehau { 422215516c77SSepherosa Ziehau const struct rndis_status_msg *msg; 422315516c77SSepherosa Ziehau int ofs; 422415516c77SSepherosa Ziehau 422515516c77SSepherosa Ziehau if (dlen < sizeof(*msg)) { 422615516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid RNDIS status\n"); 422715516c77SSepherosa Ziehau return; 422815516c77SSepherosa Ziehau } 422915516c77SSepherosa Ziehau msg = data; 423015516c77SSepherosa Ziehau 423115516c77SSepherosa Ziehau switch (msg->rm_status) { 423215516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_CONNECT: 423315516c77SSepherosa Ziehau case RNDIS_STATUS_MEDIA_DISCONNECT: 423415516c77SSepherosa Ziehau hn_update_link_status(sc); 423515516c77SSepherosa Ziehau break; 423615516c77SSepherosa Ziehau 423715516c77SSepherosa Ziehau case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: 423815516c77SSepherosa Ziehau /* Not really useful; ignore. */ 423915516c77SSepherosa Ziehau break; 424015516c77SSepherosa Ziehau 424115516c77SSepherosa Ziehau case RNDIS_STATUS_NETWORK_CHANGE: 424215516c77SSepherosa Ziehau ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset); 424315516c77SSepherosa Ziehau if (dlen < ofs + msg->rm_stbuflen || 424415516c77SSepherosa Ziehau msg->rm_stbuflen < sizeof(uint32_t)) { 424515516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed\n"); 424615516c77SSepherosa Ziehau } else { 424715516c77SSepherosa Ziehau uint32_t change; 424815516c77SSepherosa Ziehau 424915516c77SSepherosa Ziehau memcpy(&change, ((const uint8_t *)msg) + ofs, 425015516c77SSepherosa Ziehau sizeof(change)); 425115516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "network changed, change %u\n", 425215516c77SSepherosa Ziehau change); 425315516c77SSepherosa Ziehau } 425415516c77SSepherosa Ziehau hn_change_network(sc); 425515516c77SSepherosa Ziehau break; 425615516c77SSepherosa Ziehau 425715516c77SSepherosa Ziehau default: 425815516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n", 425915516c77SSepherosa Ziehau msg->rm_status); 426015516c77SSepherosa Ziehau break; 426115516c77SSepherosa Ziehau } 426215516c77SSepherosa Ziehau } 426315516c77SSepherosa Ziehau 426415516c77SSepherosa Ziehau static int 426515516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info) 426615516c77SSepherosa Ziehau { 426715516c77SSepherosa Ziehau const struct rndis_pktinfo *pi = info_data; 426815516c77SSepherosa Ziehau uint32_t mask = 0; 426915516c77SSepherosa Ziehau 427015516c77SSepherosa Ziehau while (info_dlen != 0) { 427115516c77SSepherosa Ziehau const void *data; 427215516c77SSepherosa Ziehau uint32_t dlen; 427315516c77SSepherosa Ziehau 427415516c77SSepherosa Ziehau if (__predict_false(info_dlen < sizeof(*pi))) 427515516c77SSepherosa Ziehau return (EINVAL); 427615516c77SSepherosa Ziehau if (__predict_false(info_dlen < pi->rm_size)) 427715516c77SSepherosa Ziehau return (EINVAL); 427815516c77SSepherosa Ziehau info_dlen -= pi->rm_size; 427915516c77SSepherosa Ziehau 428015516c77SSepherosa Ziehau if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK)) 428115516c77SSepherosa Ziehau return (EINVAL); 428215516c77SSepherosa Ziehau if (__predict_false(pi->rm_size < pi->rm_pktinfooffset)) 428315516c77SSepherosa Ziehau return (EINVAL); 428415516c77SSepherosa Ziehau dlen = pi->rm_size - pi->rm_pktinfooffset; 428515516c77SSepherosa Ziehau data = pi->rm_data; 428615516c77SSepherosa Ziehau 428715516c77SSepherosa Ziehau switch (pi->rm_type) { 428815516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_VLAN: 428915516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE)) 429015516c77SSepherosa Ziehau return (EINVAL); 429115516c77SSepherosa Ziehau info->vlan_info = *((const uint32_t *)data); 429215516c77SSepherosa Ziehau mask |= HN_RXINFO_VLAN; 429315516c77SSepherosa Ziehau break; 429415516c77SSepherosa Ziehau 429515516c77SSepherosa Ziehau case NDIS_PKTINFO_TYPE_CSUM: 429615516c77SSepherosa Ziehau if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE)) 429715516c77SSepherosa Ziehau return (EINVAL); 429815516c77SSepherosa Ziehau info->csum_info = *((const uint32_t *)data); 429915516c77SSepherosa Ziehau mask |= HN_RXINFO_CSUM; 430015516c77SSepherosa Ziehau break; 430115516c77SSepherosa Ziehau 430215516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHVAL: 430315516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE)) 430415516c77SSepherosa Ziehau return (EINVAL); 430515516c77SSepherosa Ziehau info->hash_value = *((const uint32_t *)data); 430615516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHVAL; 430715516c77SSepherosa Ziehau break; 430815516c77SSepherosa Ziehau 430915516c77SSepherosa Ziehau case HN_NDIS_PKTINFO_TYPE_HASHINF: 431015516c77SSepherosa Ziehau if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE)) 431115516c77SSepherosa Ziehau return (EINVAL); 431215516c77SSepherosa Ziehau info->hash_info = *((const uint32_t *)data); 431315516c77SSepherosa Ziehau mask |= HN_RXINFO_HASHINF; 431415516c77SSepherosa Ziehau break; 431515516c77SSepherosa Ziehau 431615516c77SSepherosa Ziehau default: 431715516c77SSepherosa Ziehau goto next; 431815516c77SSepherosa Ziehau } 431915516c77SSepherosa Ziehau 432015516c77SSepherosa Ziehau if (mask == HN_RXINFO_ALL) { 432115516c77SSepherosa Ziehau /* All found; done */ 432215516c77SSepherosa Ziehau break; 432315516c77SSepherosa Ziehau } 432415516c77SSepherosa Ziehau next: 432515516c77SSepherosa Ziehau pi = (const struct rndis_pktinfo *) 432615516c77SSepherosa Ziehau ((const uint8_t *)pi + pi->rm_size); 432715516c77SSepherosa Ziehau } 432815516c77SSepherosa Ziehau 432915516c77SSepherosa Ziehau /* 433015516c77SSepherosa Ziehau * Final fixup. 433115516c77SSepherosa Ziehau * - If there is no hash value, invalidate the hash info. 433215516c77SSepherosa Ziehau */ 433315516c77SSepherosa Ziehau if ((mask & HN_RXINFO_HASHVAL) == 0) 433415516c77SSepherosa Ziehau info->hash_info = HN_NDIS_HASH_INFO_INVALID; 433515516c77SSepherosa Ziehau return (0); 433615516c77SSepherosa Ziehau } 433715516c77SSepherosa Ziehau 433815516c77SSepherosa Ziehau static __inline bool 433915516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len) 434015516c77SSepherosa Ziehau { 434115516c77SSepherosa Ziehau 434215516c77SSepherosa Ziehau if (off < check_off) { 434315516c77SSepherosa Ziehau if (__predict_true(off + len <= check_off)) 434415516c77SSepherosa Ziehau return (false); 434515516c77SSepherosa Ziehau } else if (off > check_off) { 434615516c77SSepherosa Ziehau if (__predict_true(check_off + check_len <= off)) 434715516c77SSepherosa Ziehau return (false); 434815516c77SSepherosa Ziehau } 434915516c77SSepherosa Ziehau return (true); 435015516c77SSepherosa Ziehau } 435115516c77SSepherosa Ziehau 435215516c77SSepherosa Ziehau static void 435315516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen) 435415516c77SSepherosa Ziehau { 435515516c77SSepherosa Ziehau const struct rndis_packet_msg *pkt; 435615516c77SSepherosa Ziehau struct hn_rxinfo info; 435715516c77SSepherosa Ziehau int data_off, pktinfo_off, data_len, pktinfo_len; 435815516c77SSepherosa Ziehau 435915516c77SSepherosa Ziehau /* 436015516c77SSepherosa Ziehau * Check length. 436115516c77SSepherosa Ziehau */ 436215516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*pkt))) { 436315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n"); 436415516c77SSepherosa Ziehau return; 436515516c77SSepherosa Ziehau } 436615516c77SSepherosa Ziehau pkt = data; 436715516c77SSepherosa Ziehau 436815516c77SSepherosa Ziehau if (__predict_false(dlen < pkt->rm_len)) { 436915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, " 437015516c77SSepherosa Ziehau "dlen %d, msglen %u\n", dlen, pkt->rm_len); 437115516c77SSepherosa Ziehau return; 437215516c77SSepherosa Ziehau } 437315516c77SSepherosa Ziehau if (__predict_false(pkt->rm_len < 437415516c77SSepherosa Ziehau pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) { 437515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, " 437615516c77SSepherosa Ziehau "msglen %u, data %u, oob %u, pktinfo %u\n", 437715516c77SSepherosa Ziehau pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen, 437815516c77SSepherosa Ziehau pkt->rm_pktinfolen); 437915516c77SSepherosa Ziehau return; 438015516c77SSepherosa Ziehau } 438115516c77SSepherosa Ziehau if (__predict_false(pkt->rm_datalen == 0)) { 438215516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n"); 438315516c77SSepherosa Ziehau return; 438415516c77SSepherosa Ziehau } 438515516c77SSepherosa Ziehau 438615516c77SSepherosa Ziehau /* 438715516c77SSepherosa Ziehau * Check offests. 438815516c77SSepherosa Ziehau */ 438915516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs) \ 439015516c77SSepherosa Ziehau ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \ 439115516c77SSepherosa Ziehau ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK)) 439215516c77SSepherosa Ziehau 439315516c77SSepherosa Ziehau /* XXX Hyper-V does not meet data offset alignment requirement */ 439415516c77SSepherosa Ziehau if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) { 439515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 439615516c77SSepherosa Ziehau "data offset %u\n", pkt->rm_dataoffset); 439715516c77SSepherosa Ziehau return; 439815516c77SSepherosa Ziehau } 439915516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdataoffset > 0 && 440015516c77SSepherosa Ziehau IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) { 440115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 440215516c77SSepherosa Ziehau "oob offset %u\n", pkt->rm_oobdataoffset); 440315516c77SSepherosa Ziehau return; 440415516c77SSepherosa Ziehau } 440515516c77SSepherosa Ziehau if (__predict_true(pkt->rm_pktinfooffset > 0) && 440615516c77SSepherosa Ziehau __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) { 440715516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 440815516c77SSepherosa Ziehau "pktinfo offset %u\n", pkt->rm_pktinfooffset); 440915516c77SSepherosa Ziehau return; 441015516c77SSepherosa Ziehau } 441115516c77SSepherosa Ziehau 441215516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID 441315516c77SSepherosa Ziehau 441415516c77SSepherosa Ziehau data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset); 441515516c77SSepherosa Ziehau data_len = pkt->rm_datalen; 441615516c77SSepherosa Ziehau pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset); 441715516c77SSepherosa Ziehau pktinfo_len = pkt->rm_pktinfolen; 441815516c77SSepherosa Ziehau 441915516c77SSepherosa Ziehau /* 442015516c77SSepherosa Ziehau * Check OOB coverage. 442115516c77SSepherosa Ziehau */ 442215516c77SSepherosa Ziehau if (__predict_false(pkt->rm_oobdatalen != 0)) { 442315516c77SSepherosa Ziehau int oob_off, oob_len; 442415516c77SSepherosa Ziehau 442515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "got oobdata\n"); 442615516c77SSepherosa Ziehau oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset); 442715516c77SSepherosa Ziehau oob_len = pkt->rm_oobdatalen; 442815516c77SSepherosa Ziehau 442915516c77SSepherosa Ziehau if (__predict_false(oob_off + oob_len > pkt->rm_len)) { 443015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 443115516c77SSepherosa Ziehau "oob overflow, msglen %u, oob abs %d len %d\n", 443215516c77SSepherosa Ziehau pkt->rm_len, oob_off, oob_len); 443315516c77SSepherosa Ziehau return; 443415516c77SSepherosa Ziehau } 443515516c77SSepherosa Ziehau 443615516c77SSepherosa Ziehau /* 443715516c77SSepherosa Ziehau * Check against data. 443815516c77SSepherosa Ziehau */ 443915516c77SSepherosa Ziehau if (hn_rndis_check_overlap(oob_off, oob_len, 444015516c77SSepherosa Ziehau data_off, data_len)) { 444115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 444215516c77SSepherosa Ziehau "oob overlaps data, oob abs %d len %d, " 444315516c77SSepherosa Ziehau "data abs %d len %d\n", 444415516c77SSepherosa Ziehau oob_off, oob_len, data_off, data_len); 444515516c77SSepherosa Ziehau return; 444615516c77SSepherosa Ziehau } 444715516c77SSepherosa Ziehau 444815516c77SSepherosa Ziehau /* 444915516c77SSepherosa Ziehau * Check against pktinfo. 445015516c77SSepherosa Ziehau */ 445115516c77SSepherosa Ziehau if (pktinfo_len != 0 && 445215516c77SSepherosa Ziehau hn_rndis_check_overlap(oob_off, oob_len, 445315516c77SSepherosa Ziehau pktinfo_off, pktinfo_len)) { 445415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 445515516c77SSepherosa Ziehau "oob overlaps pktinfo, oob abs %d len %d, " 445615516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 445715516c77SSepherosa Ziehau oob_off, oob_len, pktinfo_off, pktinfo_len); 445815516c77SSepherosa Ziehau return; 445915516c77SSepherosa Ziehau } 446015516c77SSepherosa Ziehau } 446115516c77SSepherosa Ziehau 446215516c77SSepherosa Ziehau /* 446315516c77SSepherosa Ziehau * Check per-packet-info coverage and find useful per-packet-info. 446415516c77SSepherosa Ziehau */ 446515516c77SSepherosa Ziehau info.vlan_info = HN_NDIS_VLAN_INFO_INVALID; 446615516c77SSepherosa Ziehau info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID; 446715516c77SSepherosa Ziehau info.hash_info = HN_NDIS_HASH_INFO_INVALID; 446815516c77SSepherosa Ziehau if (__predict_true(pktinfo_len != 0)) { 446915516c77SSepherosa Ziehau bool overlap; 447015516c77SSepherosa Ziehau int error; 447115516c77SSepherosa Ziehau 447215516c77SSepherosa Ziehau if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) { 447315516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 447415516c77SSepherosa Ziehau "pktinfo overflow, msglen %u, " 447515516c77SSepherosa Ziehau "pktinfo abs %d len %d\n", 447615516c77SSepherosa Ziehau pkt->rm_len, pktinfo_off, pktinfo_len); 447715516c77SSepherosa Ziehau return; 447815516c77SSepherosa Ziehau } 447915516c77SSepherosa Ziehau 448015516c77SSepherosa Ziehau /* 448115516c77SSepherosa Ziehau * Check packet info coverage. 448215516c77SSepherosa Ziehau */ 448315516c77SSepherosa Ziehau overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len, 448415516c77SSepherosa Ziehau data_off, data_len); 448515516c77SSepherosa Ziehau if (__predict_false(overlap)) { 448615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 448715516c77SSepherosa Ziehau "pktinfo overlap data, pktinfo abs %d len %d, " 448815516c77SSepherosa Ziehau "data abs %d len %d\n", 448915516c77SSepherosa Ziehau pktinfo_off, pktinfo_len, data_off, data_len); 449015516c77SSepherosa Ziehau return; 449115516c77SSepherosa Ziehau } 449215516c77SSepherosa Ziehau 449315516c77SSepherosa Ziehau /* 449415516c77SSepherosa Ziehau * Find useful per-packet-info. 449515516c77SSepherosa Ziehau */ 449615516c77SSepherosa Ziehau error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off, 449715516c77SSepherosa Ziehau pktinfo_len, &info); 449815516c77SSepherosa Ziehau if (__predict_false(error)) { 449915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg " 450015516c77SSepherosa Ziehau "pktinfo\n"); 450115516c77SSepherosa Ziehau return; 450215516c77SSepherosa Ziehau } 450315516c77SSepherosa Ziehau } 450415516c77SSepherosa Ziehau 450515516c77SSepherosa Ziehau if (__predict_false(data_off + data_len > pkt->rm_len)) { 450615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, " 450715516c77SSepherosa Ziehau "data overflow, msglen %u, data abs %d len %d\n", 450815516c77SSepherosa Ziehau pkt->rm_len, data_off, data_len); 450915516c77SSepherosa Ziehau return; 451015516c77SSepherosa Ziehau } 451115516c77SSepherosa Ziehau hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info); 451215516c77SSepherosa Ziehau } 451315516c77SSepherosa Ziehau 451415516c77SSepherosa Ziehau static __inline void 451515516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen) 451615516c77SSepherosa Ziehau { 451715516c77SSepherosa Ziehau const struct rndis_msghdr *hdr; 451815516c77SSepherosa Ziehau 451915516c77SSepherosa Ziehau if (__predict_false(dlen < sizeof(*hdr))) { 452015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid RNDIS msg\n"); 452115516c77SSepherosa Ziehau return; 452215516c77SSepherosa Ziehau } 452315516c77SSepherosa Ziehau hdr = data; 452415516c77SSepherosa Ziehau 452515516c77SSepherosa Ziehau if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) { 452615516c77SSepherosa Ziehau /* Hot data path. */ 452715516c77SSepherosa Ziehau hn_rndis_rx_data(rxr, data, dlen); 452815516c77SSepherosa Ziehau /* Done! */ 452915516c77SSepherosa Ziehau return; 453015516c77SSepherosa Ziehau } 453115516c77SSepherosa Ziehau 453215516c77SSepherosa Ziehau if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG) 453315516c77SSepherosa Ziehau hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen); 453415516c77SSepherosa Ziehau else 453515516c77SSepherosa Ziehau hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen); 453615516c77SSepherosa Ziehau } 453715516c77SSepherosa Ziehau 453815516c77SSepherosa Ziehau static void 453915516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) 454015516c77SSepherosa Ziehau { 454115516c77SSepherosa Ziehau const struct hn_nvs_hdr *hdr; 454215516c77SSepherosa Ziehau 454315516c77SSepherosa Ziehau if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) { 454415516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "invalid nvs notify\n"); 454515516c77SSepherosa Ziehau return; 454615516c77SSepherosa Ziehau } 454715516c77SSepherosa Ziehau hdr = VMBUS_CHANPKT_CONST_DATA(pkt); 454815516c77SSepherosa Ziehau 454915516c77SSepherosa Ziehau if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) { 455015516c77SSepherosa Ziehau /* Useless; ignore */ 455115516c77SSepherosa Ziehau return; 455215516c77SSepherosa Ziehau } 455315516c77SSepherosa Ziehau if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type); 455415516c77SSepherosa Ziehau } 455515516c77SSepherosa Ziehau 455615516c77SSepherosa Ziehau static void 455715516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan, 455815516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkt) 455915516c77SSepherosa Ziehau { 456015516c77SSepherosa Ziehau struct hn_nvs_sendctx *sndc; 456115516c77SSepherosa Ziehau 456215516c77SSepherosa Ziehau sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid; 456315516c77SSepherosa Ziehau sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt), 456415516c77SSepherosa Ziehau VMBUS_CHANPKT_DATALEN(pkt)); 456515516c77SSepherosa Ziehau /* 456615516c77SSepherosa Ziehau * NOTE: 456715516c77SSepherosa Ziehau * 'sndc' CAN NOT be accessed anymore, since it can be freed by 456815516c77SSepherosa Ziehau * its callback. 456915516c77SSepherosa Ziehau */ 457015516c77SSepherosa Ziehau } 457115516c77SSepherosa Ziehau 457215516c77SSepherosa Ziehau static void 457315516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 457415516c77SSepherosa Ziehau const struct vmbus_chanpkt_hdr *pkthdr) 457515516c77SSepherosa Ziehau { 457615516c77SSepherosa Ziehau const struct vmbus_chanpkt_rxbuf *pkt; 457715516c77SSepherosa Ziehau const struct hn_nvs_hdr *nvs_hdr; 457815516c77SSepherosa Ziehau int count, i, hlen; 457915516c77SSepherosa Ziehau 458015516c77SSepherosa Ziehau if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) { 458115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n"); 458215516c77SSepherosa Ziehau return; 458315516c77SSepherosa Ziehau } 458415516c77SSepherosa Ziehau nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr); 458515516c77SSepherosa Ziehau 458615516c77SSepherosa Ziehau /* Make sure that this is a RNDIS message. */ 458715516c77SSepherosa Ziehau if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) { 458815516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n", 458915516c77SSepherosa Ziehau nvs_hdr->nvs_type); 459015516c77SSepherosa Ziehau return; 459115516c77SSepherosa Ziehau } 459215516c77SSepherosa Ziehau 459315516c77SSepherosa Ziehau hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen); 459415516c77SSepherosa Ziehau if (__predict_false(hlen < sizeof(*pkt))) { 459515516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n"); 459615516c77SSepherosa Ziehau return; 459715516c77SSepherosa Ziehau } 459815516c77SSepherosa Ziehau pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr; 459915516c77SSepherosa Ziehau 460015516c77SSepherosa Ziehau if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) { 460115516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n", 460215516c77SSepherosa Ziehau pkt->cp_rxbuf_id); 460315516c77SSepherosa Ziehau return; 460415516c77SSepherosa Ziehau } 460515516c77SSepherosa Ziehau 460615516c77SSepherosa Ziehau count = pkt->cp_rxbuf_cnt; 460715516c77SSepherosa Ziehau if (__predict_false(hlen < 460815516c77SSepherosa Ziehau __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) { 460915516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count); 461015516c77SSepherosa Ziehau return; 461115516c77SSepherosa Ziehau } 461215516c77SSepherosa Ziehau 461315516c77SSepherosa Ziehau /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 461415516c77SSepherosa Ziehau for (i = 0; i < count; ++i) { 461515516c77SSepherosa Ziehau int ofs, len; 461615516c77SSepherosa Ziehau 461715516c77SSepherosa Ziehau ofs = pkt->cp_rxbuf[i].rb_ofs; 461815516c77SSepherosa Ziehau len = pkt->cp_rxbuf[i].rb_len; 461915516c77SSepherosa Ziehau if (__predict_false(ofs + len > HN_RXBUF_SIZE)) { 462015516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, " 462115516c77SSepherosa Ziehau "ofs %d, len %d\n", i, ofs, len); 462215516c77SSepherosa Ziehau continue; 462315516c77SSepherosa Ziehau } 462415516c77SSepherosa Ziehau hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len); 462515516c77SSepherosa Ziehau } 462615516c77SSepherosa Ziehau 462715516c77SSepherosa Ziehau /* 462815516c77SSepherosa Ziehau * Ack the consumed RXBUF associated w/ this channel packet, 462915516c77SSepherosa Ziehau * so that this RXBUF can be recycled by the hypervisor. 463015516c77SSepherosa Ziehau */ 463115516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid); 463215516c77SSepherosa Ziehau } 463315516c77SSepherosa Ziehau 463415516c77SSepherosa Ziehau static void 463515516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan, 463615516c77SSepherosa Ziehau uint64_t tid) 463715516c77SSepherosa Ziehau { 463815516c77SSepherosa Ziehau struct hn_nvs_rndis_ack ack; 463915516c77SSepherosa Ziehau int retries, error; 464015516c77SSepherosa Ziehau 464115516c77SSepherosa Ziehau ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK; 464215516c77SSepherosa Ziehau ack.nvs_status = HN_NVS_STATUS_OK; 464315516c77SSepherosa Ziehau 464415516c77SSepherosa Ziehau retries = 0; 464515516c77SSepherosa Ziehau again: 464615516c77SSepherosa Ziehau error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 464715516c77SSepherosa Ziehau VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid); 464815516c77SSepherosa Ziehau if (__predict_false(error == EAGAIN)) { 464915516c77SSepherosa Ziehau /* 465015516c77SSepherosa Ziehau * NOTE: 465115516c77SSepherosa Ziehau * This should _not_ happen in real world, since the 465215516c77SSepherosa Ziehau * consumption of the TX bufring from the TX path is 465315516c77SSepherosa Ziehau * controlled. 465415516c77SSepherosa Ziehau */ 465515516c77SSepherosa Ziehau if (rxr->hn_ack_failed == 0) 465615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack retry\n"); 465715516c77SSepherosa Ziehau rxr->hn_ack_failed++; 465815516c77SSepherosa Ziehau retries++; 465915516c77SSepherosa Ziehau if (retries < 10) { 466015516c77SSepherosa Ziehau DELAY(100); 466115516c77SSepherosa Ziehau goto again; 466215516c77SSepherosa Ziehau } 466315516c77SSepherosa Ziehau /* RXBUF leaks! */ 466415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "RXBUF ack failed\n"); 466515516c77SSepherosa Ziehau } 466615516c77SSepherosa Ziehau } 466715516c77SSepherosa Ziehau 466815516c77SSepherosa Ziehau static void 466915516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr) 467015516c77SSepherosa Ziehau { 467115516c77SSepherosa Ziehau struct hn_rx_ring *rxr = xrxr; 467215516c77SSepherosa Ziehau struct hn_softc *sc = rxr->hn_ifp->if_softc; 467315516c77SSepherosa Ziehau 467415516c77SSepherosa Ziehau for (;;) { 467515516c77SSepherosa Ziehau struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf; 467615516c77SSepherosa Ziehau int error, pktlen; 467715516c77SSepherosa Ziehau 467815516c77SSepherosa Ziehau pktlen = rxr->hn_pktbuf_len; 467915516c77SSepherosa Ziehau error = vmbus_chan_recv_pkt(chan, pkt, &pktlen); 468015516c77SSepherosa Ziehau if (__predict_false(error == ENOBUFS)) { 468115516c77SSepherosa Ziehau void *nbuf; 468215516c77SSepherosa Ziehau int nlen; 468315516c77SSepherosa Ziehau 468415516c77SSepherosa Ziehau /* 468515516c77SSepherosa Ziehau * Expand channel packet buffer. 468615516c77SSepherosa Ziehau * 468715516c77SSepherosa Ziehau * XXX 468815516c77SSepherosa Ziehau * Use M_WAITOK here, since allocation failure 468915516c77SSepherosa Ziehau * is fatal. 469015516c77SSepherosa Ziehau */ 469115516c77SSepherosa Ziehau nlen = rxr->hn_pktbuf_len * 2; 469215516c77SSepherosa Ziehau while (nlen < pktlen) 469315516c77SSepherosa Ziehau nlen *= 2; 469415516c77SSepherosa Ziehau nbuf = malloc(nlen, M_DEVBUF, M_WAITOK); 469515516c77SSepherosa Ziehau 469615516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n", 469715516c77SSepherosa Ziehau rxr->hn_pktbuf_len, nlen); 469815516c77SSepherosa Ziehau 469915516c77SSepherosa Ziehau free(rxr->hn_pktbuf, M_DEVBUF); 470015516c77SSepherosa Ziehau rxr->hn_pktbuf = nbuf; 470115516c77SSepherosa Ziehau rxr->hn_pktbuf_len = nlen; 470215516c77SSepherosa Ziehau /* Retry! */ 470315516c77SSepherosa Ziehau continue; 470415516c77SSepherosa Ziehau } else if (__predict_false(error == EAGAIN)) { 470515516c77SSepherosa Ziehau /* No more channel packets; done! */ 470615516c77SSepherosa Ziehau break; 470715516c77SSepherosa Ziehau } 470815516c77SSepherosa Ziehau KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error)); 470915516c77SSepherosa Ziehau 471015516c77SSepherosa Ziehau switch (pkt->cph_type) { 471115516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_COMP: 471215516c77SSepherosa Ziehau hn_nvs_handle_comp(sc, chan, pkt); 471315516c77SSepherosa Ziehau break; 471415516c77SSepherosa Ziehau 471515516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_RXBUF: 471615516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(rxr, chan, pkt); 471715516c77SSepherosa Ziehau break; 471815516c77SSepherosa Ziehau 471915516c77SSepherosa Ziehau case VMBUS_CHANPKT_TYPE_INBAND: 472015516c77SSepherosa Ziehau hn_nvs_handle_notify(sc, pkt); 472115516c77SSepherosa Ziehau break; 472215516c77SSepherosa Ziehau 472315516c77SSepherosa Ziehau default: 472415516c77SSepherosa Ziehau if_printf(rxr->hn_ifp, "unknown chan pkt %u\n", 472515516c77SSepherosa Ziehau pkt->cph_type); 472615516c77SSepherosa Ziehau break; 472715516c77SSepherosa Ziehau } 472815516c77SSepherosa Ziehau } 472915516c77SSepherosa Ziehau hn_chan_rollup(rxr, rxr->hn_txr); 473015516c77SSepherosa Ziehau } 473115516c77SSepherosa Ziehau 473215516c77SSepherosa Ziehau static void 473315516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused) 473415516c77SSepherosa Ziehau { 473515516c77SSepherosa Ziehau 473615516c77SSepherosa Ziehau if (vm_guest != VM_GUEST_HV) 473715516c77SSepherosa Ziehau return; 473815516c77SSepherosa Ziehau 473915516c77SSepherosa Ziehau if (!hn_share_tx_taskq) 474015516c77SSepherosa Ziehau return; 474115516c77SSepherosa Ziehau 474215516c77SSepherosa Ziehau hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK, 474315516c77SSepherosa Ziehau taskqueue_thread_enqueue, &hn_tx_taskq); 474415516c77SSepherosa Ziehau if (hn_bind_tx_taskq >= 0) { 474515516c77SSepherosa Ziehau int cpu = hn_bind_tx_taskq; 474615516c77SSepherosa Ziehau cpuset_t cpu_set; 474715516c77SSepherosa Ziehau 474815516c77SSepherosa Ziehau if (cpu > mp_ncpus - 1) 474915516c77SSepherosa Ziehau cpu = mp_ncpus - 1; 475015516c77SSepherosa Ziehau CPU_SETOF(cpu, &cpu_set); 475115516c77SSepherosa Ziehau taskqueue_start_threads_cpuset(&hn_tx_taskq, 1, PI_NET, 475215516c77SSepherosa Ziehau &cpu_set, "hn tx"); 475315516c77SSepherosa Ziehau } else { 475415516c77SSepherosa Ziehau taskqueue_start_threads(&hn_tx_taskq, 1, PI_NET, "hn tx"); 475515516c77SSepherosa Ziehau } 475615516c77SSepherosa Ziehau } 475715516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND, 475815516c77SSepherosa Ziehau hn_tx_taskq_create, NULL); 475915516c77SSepherosa Ziehau 476015516c77SSepherosa Ziehau static void 476115516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused) 476215516c77SSepherosa Ziehau { 476315516c77SSepherosa Ziehau 476415516c77SSepherosa Ziehau if (hn_tx_taskq != NULL) 476515516c77SSepherosa Ziehau taskqueue_free(hn_tx_taskq); 476615516c77SSepherosa Ziehau } 476715516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND, 476815516c77SSepherosa Ziehau hn_tx_taskq_destroy, NULL); 4769