1e3c97c2cSBryan Venteicher /*- 2e3c97c2cSBryan Venteicher * Copyright (c) 2013 Tsubai Masanari 3e3c97c2cSBryan Venteicher * Copyright (c) 2013 Bryan Venteicher <bryanv@FreeBSD.org> 4e3c97c2cSBryan Venteicher * 5e3c97c2cSBryan Venteicher * Permission to use, copy, modify, and distribute this software for any 6e3c97c2cSBryan Venteicher * purpose with or without fee is hereby granted, provided that the above 7e3c97c2cSBryan Venteicher * copyright notice and this permission notice appear in all copies. 8e3c97c2cSBryan Venteicher * 9e3c97c2cSBryan Venteicher * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10e3c97c2cSBryan Venteicher * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11e3c97c2cSBryan Venteicher * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12e3c97c2cSBryan Venteicher * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13e3c97c2cSBryan Venteicher * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14e3c97c2cSBryan Venteicher * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15e3c97c2cSBryan Venteicher * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16e3c97c2cSBryan Venteicher * 17e3c97c2cSBryan Venteicher * $OpenBSD: src/sys/dev/pci/if_vmx.c,v 1.11 2013/06/22 00:28:10 uebayasi Exp $ 18e3c97c2cSBryan Venteicher */ 19e3c97c2cSBryan Venteicher 20e3c97c2cSBryan Venteicher /* Driver for VMware vmxnet3 virtual ethernet devices. */ 21e3c97c2cSBryan Venteicher 22e3c97c2cSBryan Venteicher #include <sys/cdefs.h> 23e3c97c2cSBryan Venteicher __FBSDID("$FreeBSD$"); 24e3c97c2cSBryan Venteicher 25e3c97c2cSBryan Venteicher #include <sys/param.h> 26e3c97c2cSBryan Venteicher #include <sys/systm.h> 27c3322cb9SGleb Smirnoff #include <sys/eventhandler.h> 28e3c97c2cSBryan Venteicher #include <sys/kernel.h> 29e3c97c2cSBryan Venteicher #include <sys/endian.h> 30e3c97c2cSBryan Venteicher #include <sys/sockio.h> 31e3c97c2cSBryan Venteicher #include <sys/mbuf.h> 32e3c97c2cSBryan Venteicher #include <sys/malloc.h> 33e3c97c2cSBryan Venteicher #include <sys/module.h> 34e3c97c2cSBryan Venteicher #include <sys/socket.h> 35e3c97c2cSBryan Venteicher #include <sys/sysctl.h> 36*e557c1ddSBryan Venteicher #include <sys/smp.h> 37*e557c1ddSBryan Venteicher #include <sys/taskqueue.h> 38e3c97c2cSBryan Venteicher #include <vm/vm.h> 39e3c97c2cSBryan Venteicher #include <vm/pmap.h> 40e3c97c2cSBryan Venteicher 41e3c97c2cSBryan Venteicher #include <net/ethernet.h> 42e3c97c2cSBryan Venteicher #include <net/if.h> 4376039bc8SGleb Smirnoff #include <net/if_var.h> 44e3c97c2cSBryan Venteicher #include <net/if_arp.h> 45e3c97c2cSBryan Venteicher #include <net/if_dl.h> 46e3c97c2cSBryan Venteicher #include <net/if_types.h> 47e3c97c2cSBryan Venteicher #include <net/if_media.h> 48e3c97c2cSBryan Venteicher #include <net/if_vlan_var.h> 49e3c97c2cSBryan Venteicher 50e3c97c2cSBryan Venteicher #include <net/bpf.h> 51e3c97c2cSBryan Venteicher 52e3c97c2cSBryan Venteicher #include <netinet/in_systm.h> 53e3c97c2cSBryan Venteicher #include <netinet/in.h> 54e3c97c2cSBryan Venteicher #include <netinet/ip.h> 55e3c97c2cSBryan Venteicher #include <netinet/ip6.h> 56e3c97c2cSBryan Venteicher #include <netinet6/ip6_var.h> 57e3c97c2cSBryan Venteicher #include <netinet/udp.h> 58e3c97c2cSBryan Venteicher #include <netinet/tcp.h> 59e3c97c2cSBryan Venteicher 60e3c97c2cSBryan Venteicher #include <machine/bus.h> 61e3c97c2cSBryan Venteicher #include <machine/resource.h> 62e3c97c2cSBryan Venteicher #include <sys/bus.h> 63e3c97c2cSBryan Venteicher #include <sys/rman.h> 64e3c97c2cSBryan Venteicher 65e3c97c2cSBryan Venteicher #include <dev/pci/pcireg.h> 66e3c97c2cSBryan Venteicher #include <dev/pci/pcivar.h> 67e3c97c2cSBryan Venteicher 68e3c97c2cSBryan Venteicher #include "if_vmxreg.h" 69e3c97c2cSBryan Venteicher #include "if_vmxvar.h" 70e3c97c2cSBryan Venteicher 71e3c97c2cSBryan Venteicher #include "opt_inet.h" 72e3c97c2cSBryan Venteicher #include "opt_inet6.h" 73e3c97c2cSBryan Venteicher 74e3c97c2cSBryan Venteicher #ifdef VMXNET3_FAILPOINTS 75e3c97c2cSBryan Venteicher #include <sys/fail.h> 76e3c97c2cSBryan Venteicher static SYSCTL_NODE(DEBUG_FP, OID_AUTO, vmxnet3, CTLFLAG_RW, 0, 77e3c97c2cSBryan Venteicher "vmxnet3 fail points"); 78e3c97c2cSBryan Venteicher #define VMXNET3_FP _debug_fail_point_vmxnet3 79e3c97c2cSBryan Venteicher #endif 80e3c97c2cSBryan Venteicher 81e3c97c2cSBryan Venteicher static int vmxnet3_probe(device_t); 82e3c97c2cSBryan Venteicher static int vmxnet3_attach(device_t); 83e3c97c2cSBryan Venteicher static int vmxnet3_detach(device_t); 84e3c97c2cSBryan Venteicher static int vmxnet3_shutdown(device_t); 85e3c97c2cSBryan Venteicher 86e3c97c2cSBryan Venteicher static int vmxnet3_alloc_resources(struct vmxnet3_softc *); 87e3c97c2cSBryan Venteicher static void vmxnet3_free_resources(struct vmxnet3_softc *); 88e3c97c2cSBryan Venteicher static int vmxnet3_check_version(struct vmxnet3_softc *); 89e3c97c2cSBryan Venteicher static void vmxnet3_initial_config(struct vmxnet3_softc *); 90*e557c1ddSBryan Venteicher static void vmxnet3_check_multiqueue(struct vmxnet3_softc *); 91e3c97c2cSBryan Venteicher 92e3c97c2cSBryan Venteicher static int vmxnet3_alloc_msix_interrupts(struct vmxnet3_softc *); 93e3c97c2cSBryan Venteicher static int vmxnet3_alloc_msi_interrupts(struct vmxnet3_softc *); 94e3c97c2cSBryan Venteicher static int vmxnet3_alloc_legacy_interrupts(struct vmxnet3_softc *); 95e3c97c2cSBryan Venteicher static int vmxnet3_alloc_interrupt(struct vmxnet3_softc *, int, int, 96e3c97c2cSBryan Venteicher struct vmxnet3_interrupt *); 97e3c97c2cSBryan Venteicher static int vmxnet3_alloc_intr_resources(struct vmxnet3_softc *); 98e3c97c2cSBryan Venteicher static int vmxnet3_setup_msix_interrupts(struct vmxnet3_softc *); 99e3c97c2cSBryan Venteicher static int vmxnet3_setup_legacy_interrupt(struct vmxnet3_softc *); 100e3c97c2cSBryan Venteicher static int vmxnet3_setup_interrupts(struct vmxnet3_softc *); 101e3c97c2cSBryan Venteicher static int vmxnet3_alloc_interrupts(struct vmxnet3_softc *); 102e3c97c2cSBryan Venteicher 103e3c97c2cSBryan Venteicher static void vmxnet3_free_interrupt(struct vmxnet3_softc *, 104e3c97c2cSBryan Venteicher struct vmxnet3_interrupt *); 105e3c97c2cSBryan Venteicher static void vmxnet3_free_interrupts(struct vmxnet3_softc *); 106e3c97c2cSBryan Venteicher 107*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX 108*e557c1ddSBryan Venteicher static int vmxnet3_alloc_taskqueue(struct vmxnet3_softc *); 109*e557c1ddSBryan Venteicher static void vmxnet3_start_taskqueue(struct vmxnet3_softc *); 110*e557c1ddSBryan Venteicher static void vmxnet3_drain_taskqueue(struct vmxnet3_softc *); 111*e557c1ddSBryan Venteicher static void vmxnet3_free_taskqueue(struct vmxnet3_softc *); 112*e557c1ddSBryan Venteicher #endif 113*e557c1ddSBryan Venteicher 114e3c97c2cSBryan Venteicher static int vmxnet3_init_rxq(struct vmxnet3_softc *, int); 115e3c97c2cSBryan Venteicher static int vmxnet3_init_txq(struct vmxnet3_softc *, int); 116e3c97c2cSBryan Venteicher static int vmxnet3_alloc_rxtx_queues(struct vmxnet3_softc *); 117e3c97c2cSBryan Venteicher static void vmxnet3_destroy_rxq(struct vmxnet3_rxqueue *); 118e3c97c2cSBryan Venteicher static void vmxnet3_destroy_txq(struct vmxnet3_txqueue *); 119e3c97c2cSBryan Venteicher static void vmxnet3_free_rxtx_queues(struct vmxnet3_softc *); 120e3c97c2cSBryan Venteicher 121e3c97c2cSBryan Venteicher static int vmxnet3_alloc_shared_data(struct vmxnet3_softc *); 122e3c97c2cSBryan Venteicher static void vmxnet3_free_shared_data(struct vmxnet3_softc *); 123e3c97c2cSBryan Venteicher static int vmxnet3_alloc_txq_data(struct vmxnet3_softc *); 124e3c97c2cSBryan Venteicher static void vmxnet3_free_txq_data(struct vmxnet3_softc *); 125e3c97c2cSBryan Venteicher static int vmxnet3_alloc_rxq_data(struct vmxnet3_softc *); 126e3c97c2cSBryan Venteicher static void vmxnet3_free_rxq_data(struct vmxnet3_softc *); 127e3c97c2cSBryan Venteicher static int vmxnet3_alloc_queue_data(struct vmxnet3_softc *); 128e3c97c2cSBryan Venteicher static void vmxnet3_free_queue_data(struct vmxnet3_softc *); 129e3c97c2cSBryan Venteicher static int vmxnet3_alloc_mcast_table(struct vmxnet3_softc *); 130e3c97c2cSBryan Venteicher static void vmxnet3_init_shared_data(struct vmxnet3_softc *); 131e3c97c2cSBryan Venteicher static void vmxnet3_reinit_interface(struct vmxnet3_softc *); 132*e557c1ddSBryan Venteicher static void vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *); 133e3c97c2cSBryan Venteicher static void vmxnet3_reinit_shared_data(struct vmxnet3_softc *); 134e3c97c2cSBryan Venteicher static int vmxnet3_alloc_data(struct vmxnet3_softc *); 135e3c97c2cSBryan Venteicher static void vmxnet3_free_data(struct vmxnet3_softc *); 136e3c97c2cSBryan Venteicher static int vmxnet3_setup_interface(struct vmxnet3_softc *); 137e3c97c2cSBryan Venteicher 138e3c97c2cSBryan Venteicher static void vmxnet3_evintr(struct vmxnet3_softc *); 139e3c97c2cSBryan Venteicher static void vmxnet3_txq_eof(struct vmxnet3_txqueue *); 140e3c97c2cSBryan Venteicher static void vmxnet3_rx_csum(struct vmxnet3_rxcompdesc *, struct mbuf *); 141e3c97c2cSBryan Venteicher static int vmxnet3_newbuf(struct vmxnet3_softc *, struct vmxnet3_rxring *); 142e3c97c2cSBryan Venteicher static void vmxnet3_rxq_eof_discard(struct vmxnet3_rxqueue *, 143e3c97c2cSBryan Venteicher struct vmxnet3_rxring *, int); 144e3c97c2cSBryan Venteicher static void vmxnet3_rxq_eof(struct vmxnet3_rxqueue *); 145e3c97c2cSBryan Venteicher static void vmxnet3_legacy_intr(void *); 146e3c97c2cSBryan Venteicher static void vmxnet3_txq_intr(void *); 147e3c97c2cSBryan Venteicher static void vmxnet3_rxq_intr(void *); 148e3c97c2cSBryan Venteicher static void vmxnet3_event_intr(void *); 149e3c97c2cSBryan Venteicher 150e3c97c2cSBryan Venteicher static void vmxnet3_txstop(struct vmxnet3_softc *, struct vmxnet3_txqueue *); 151e3c97c2cSBryan Venteicher static void vmxnet3_rxstop(struct vmxnet3_softc *, struct vmxnet3_rxqueue *); 152e3c97c2cSBryan Venteicher static void vmxnet3_stop(struct vmxnet3_softc *); 153e3c97c2cSBryan Venteicher 154e3c97c2cSBryan Venteicher static void vmxnet3_txinit(struct vmxnet3_softc *, struct vmxnet3_txqueue *); 155e3c97c2cSBryan Venteicher static int vmxnet3_rxinit(struct vmxnet3_softc *, struct vmxnet3_rxqueue *); 156e3c97c2cSBryan Venteicher static int vmxnet3_reinit_queues(struct vmxnet3_softc *); 157e3c97c2cSBryan Venteicher static int vmxnet3_enable_device(struct vmxnet3_softc *); 158e3c97c2cSBryan Venteicher static void vmxnet3_reinit_rxfilters(struct vmxnet3_softc *); 159e3c97c2cSBryan Venteicher static int vmxnet3_reinit(struct vmxnet3_softc *); 160e3c97c2cSBryan Venteicher static void vmxnet3_init_locked(struct vmxnet3_softc *); 161e3c97c2cSBryan Venteicher static void vmxnet3_init(void *); 162e3c97c2cSBryan Venteicher 163*e557c1ddSBryan Venteicher static int vmxnet3_txq_offload_ctx(struct vmxnet3_txqueue *,struct mbuf *, 164*e557c1ddSBryan Venteicher int *, int *, int *); 165e3c97c2cSBryan Venteicher static int vmxnet3_txq_load_mbuf(struct vmxnet3_txqueue *, struct mbuf **, 166e3c97c2cSBryan Venteicher bus_dmamap_t, bus_dma_segment_t [], int *); 167e3c97c2cSBryan Venteicher static void vmxnet3_txq_unload_mbuf(struct vmxnet3_txqueue *, bus_dmamap_t); 168e3c97c2cSBryan Venteicher static int vmxnet3_txq_encap(struct vmxnet3_txqueue *, struct mbuf **); 169*e557c1ddSBryan Venteicher static void vmxnet3_txq_update_pending(struct vmxnet3_txqueue *); 170*e557c1ddSBryan Venteicher #ifdef VMXNET3_LEGACY_TX 171e3c97c2cSBryan Venteicher static void vmxnet3_start_locked(struct ifnet *); 172e3c97c2cSBryan Venteicher static void vmxnet3_start(struct ifnet *); 173*e557c1ddSBryan Venteicher #else 174*e557c1ddSBryan Venteicher static int vmxnet3_txq_mq_start_locked(struct vmxnet3_txqueue *, 175*e557c1ddSBryan Venteicher struct mbuf *); 176*e557c1ddSBryan Venteicher static int vmxnet3_txq_mq_start(struct ifnet *, struct mbuf *); 177*e557c1ddSBryan Venteicher static void vmxnet3_txq_tq_deferred(void *, int); 178*e557c1ddSBryan Venteicher #endif 179*e557c1ddSBryan Venteicher static void vmxnet3_txq_start(struct vmxnet3_txqueue *); 180*e557c1ddSBryan Venteicher static void vmxnet3_tx_start_all(struct vmxnet3_softc *); 181e3c97c2cSBryan Venteicher 182e3c97c2cSBryan Venteicher static void vmxnet3_update_vlan_filter(struct vmxnet3_softc *, int, 183e3c97c2cSBryan Venteicher uint16_t); 184e3c97c2cSBryan Venteicher static void vmxnet3_register_vlan(void *, struct ifnet *, uint16_t); 185e3c97c2cSBryan Venteicher static void vmxnet3_unregister_vlan(void *, struct ifnet *, uint16_t); 186e3c97c2cSBryan Venteicher static void vmxnet3_set_rxfilter(struct vmxnet3_softc *); 187e3c97c2cSBryan Venteicher static int vmxnet3_change_mtu(struct vmxnet3_softc *, int); 188e3c97c2cSBryan Venteicher static int vmxnet3_ioctl(struct ifnet *, u_long, caddr_t); 189e3c97c2cSBryan Venteicher 190*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX 191*e557c1ddSBryan Venteicher static void vmxnet3_qflush(struct ifnet *); 192*e557c1ddSBryan Venteicher #endif 193*e557c1ddSBryan Venteicher 194e3c97c2cSBryan Venteicher static int vmxnet3_watchdog(struct vmxnet3_txqueue *); 195*e557c1ddSBryan Venteicher static void vmxnet3_refresh_host_stats(struct vmxnet3_softc *); 196*e557c1ddSBryan Venteicher static void vmxnet3_txq_accum_stats(struct vmxnet3_txqueue *, 197*e557c1ddSBryan Venteicher struct vmxnet3_txq_stats *); 198*e557c1ddSBryan Venteicher static void vmxnet3_rxq_accum_stats(struct vmxnet3_rxqueue *, 199*e557c1ddSBryan Venteicher struct vmxnet3_rxq_stats *); 200e3c97c2cSBryan Venteicher static void vmxnet3_tick(void *); 201e3c97c2cSBryan Venteicher static void vmxnet3_link_status(struct vmxnet3_softc *); 202e3c97c2cSBryan Venteicher static void vmxnet3_media_status(struct ifnet *, struct ifmediareq *); 203e3c97c2cSBryan Venteicher static int vmxnet3_media_change(struct ifnet *); 204e3c97c2cSBryan Venteicher static void vmxnet3_set_lladdr(struct vmxnet3_softc *); 205e3c97c2cSBryan Venteicher static void vmxnet3_get_lladdr(struct vmxnet3_softc *); 206e3c97c2cSBryan Venteicher 207e3c97c2cSBryan Venteicher static void vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *, 208e3c97c2cSBryan Venteicher struct sysctl_ctx_list *, struct sysctl_oid_list *); 209e3c97c2cSBryan Venteicher static void vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *, 210e3c97c2cSBryan Venteicher struct sysctl_ctx_list *, struct sysctl_oid_list *); 211e3c97c2cSBryan Venteicher static void vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *, 212e3c97c2cSBryan Venteicher struct sysctl_ctx_list *, struct sysctl_oid_list *); 213e3c97c2cSBryan Venteicher static void vmxnet3_setup_sysctl(struct vmxnet3_softc *); 214e3c97c2cSBryan Venteicher 215e3c97c2cSBryan Venteicher static void vmxnet3_write_bar0(struct vmxnet3_softc *, bus_size_t, 216e3c97c2cSBryan Venteicher uint32_t); 217e3c97c2cSBryan Venteicher static uint32_t vmxnet3_read_bar1(struct vmxnet3_softc *, bus_size_t); 218e3c97c2cSBryan Venteicher static void vmxnet3_write_bar1(struct vmxnet3_softc *, bus_size_t, 219e3c97c2cSBryan Venteicher uint32_t); 220e3c97c2cSBryan Venteicher static void vmxnet3_write_cmd(struct vmxnet3_softc *, uint32_t); 221e3c97c2cSBryan Venteicher static uint32_t vmxnet3_read_cmd(struct vmxnet3_softc *, uint32_t); 222e3c97c2cSBryan Venteicher 223e3c97c2cSBryan Venteicher static void vmxnet3_enable_intr(struct vmxnet3_softc *, int); 224e3c97c2cSBryan Venteicher static void vmxnet3_disable_intr(struct vmxnet3_softc *, int); 225e3c97c2cSBryan Venteicher static void vmxnet3_enable_all_intrs(struct vmxnet3_softc *); 226e3c97c2cSBryan Venteicher static void vmxnet3_disable_all_intrs(struct vmxnet3_softc *); 227e3c97c2cSBryan Venteicher 228e3c97c2cSBryan Venteicher static int vmxnet3_dma_malloc(struct vmxnet3_softc *, bus_size_t, 229e3c97c2cSBryan Venteicher bus_size_t, struct vmxnet3_dma_alloc *); 230e3c97c2cSBryan Venteicher static void vmxnet3_dma_free(struct vmxnet3_softc *, 231e3c97c2cSBryan Venteicher struct vmxnet3_dma_alloc *); 2323c5dfe89SBryan Venteicher static int vmxnet3_tunable_int(struct vmxnet3_softc *, 2333c5dfe89SBryan Venteicher const char *, int); 234e3c97c2cSBryan Venteicher 235e3c97c2cSBryan Venteicher typedef enum { 236e3c97c2cSBryan Venteicher VMXNET3_BARRIER_RD, 237e3c97c2cSBryan Venteicher VMXNET3_BARRIER_WR, 238e3c97c2cSBryan Venteicher VMXNET3_BARRIER_RDWR, 239e3c97c2cSBryan Venteicher } vmxnet3_barrier_t; 240e3c97c2cSBryan Venteicher 241e3c97c2cSBryan Venteicher static void vmxnet3_barrier(struct vmxnet3_softc *, vmxnet3_barrier_t); 242e3c97c2cSBryan Venteicher 2433c5dfe89SBryan Venteicher /* Tunables. */ 244*e557c1ddSBryan Venteicher static int vmxnet3_mq_disable = 0; 245*e557c1ddSBryan Venteicher TUNABLE_INT("hw.vmx.mq_disable", &vmxnet3_mq_disable); 246*e557c1ddSBryan Venteicher static int vmxnet3_default_txnqueue = VMXNET3_DEF_TX_QUEUES; 247*e557c1ddSBryan Venteicher TUNABLE_INT("hw.vmx.txnqueue", &vmxnet3_default_txnqueue); 248*e557c1ddSBryan Venteicher static int vmxnet3_default_rxnqueue = VMXNET3_DEF_RX_QUEUES; 249*e557c1ddSBryan Venteicher TUNABLE_INT("hw.vmx.rxnqueue", &vmxnet3_default_rxnqueue); 2503c5dfe89SBryan Venteicher static int vmxnet3_default_txndesc = VMXNET3_DEF_TX_NDESC; 2513c5dfe89SBryan Venteicher TUNABLE_INT("hw.vmx.txndesc", &vmxnet3_default_txndesc); 2523c5dfe89SBryan Venteicher static int vmxnet3_default_rxndesc = VMXNET3_DEF_RX_NDESC; 2533c5dfe89SBryan Venteicher TUNABLE_INT("hw.vmx.rxndesc", &vmxnet3_default_rxndesc); 2543c5dfe89SBryan Venteicher 255e3c97c2cSBryan Venteicher static device_method_t vmxnet3_methods[] = { 256e3c97c2cSBryan Venteicher /* Device interface. */ 257e3c97c2cSBryan Venteicher DEVMETHOD(device_probe, vmxnet3_probe), 258e3c97c2cSBryan Venteicher DEVMETHOD(device_attach, vmxnet3_attach), 259e3c97c2cSBryan Venteicher DEVMETHOD(device_detach, vmxnet3_detach), 260e3c97c2cSBryan Venteicher DEVMETHOD(device_shutdown, vmxnet3_shutdown), 261e3c97c2cSBryan Venteicher 262e3c97c2cSBryan Venteicher DEVMETHOD_END 263e3c97c2cSBryan Venteicher }; 264e3c97c2cSBryan Venteicher 265e3c97c2cSBryan Venteicher static driver_t vmxnet3_driver = { 266e3c97c2cSBryan Venteicher "vmx", vmxnet3_methods, sizeof(struct vmxnet3_softc) 267e3c97c2cSBryan Venteicher }; 268e3c97c2cSBryan Venteicher 269e3c97c2cSBryan Venteicher static devclass_t vmxnet3_devclass; 270e3c97c2cSBryan Venteicher DRIVER_MODULE(vmx, pci, vmxnet3_driver, vmxnet3_devclass, 0, 0); 271e3c97c2cSBryan Venteicher 272e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, pci, 1, 1, 1); 273e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, ether, 1, 1, 1); 274e3c97c2cSBryan Venteicher 275e3c97c2cSBryan Venteicher #define VMXNET3_VMWARE_VENDOR_ID 0x15AD 276e3c97c2cSBryan Venteicher #define VMXNET3_VMWARE_DEVICE_ID 0x07B0 277e3c97c2cSBryan Venteicher 278e3c97c2cSBryan Venteicher static int 279e3c97c2cSBryan Venteicher vmxnet3_probe(device_t dev) 280e3c97c2cSBryan Venteicher { 281e3c97c2cSBryan Venteicher 282e3c97c2cSBryan Venteicher if (pci_get_vendor(dev) == VMXNET3_VMWARE_VENDOR_ID && 283e3c97c2cSBryan Venteicher pci_get_device(dev) == VMXNET3_VMWARE_DEVICE_ID) { 284e3c97c2cSBryan Venteicher device_set_desc(dev, "VMware VMXNET3 Ethernet Adapter"); 285e3c97c2cSBryan Venteicher return (BUS_PROBE_DEFAULT); 286e3c97c2cSBryan Venteicher } 287e3c97c2cSBryan Venteicher 288e3c97c2cSBryan Venteicher return (ENXIO); 289e3c97c2cSBryan Venteicher } 290e3c97c2cSBryan Venteicher 291e3c97c2cSBryan Venteicher static int 292e3c97c2cSBryan Venteicher vmxnet3_attach(device_t dev) 293e3c97c2cSBryan Venteicher { 294e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 295e3c97c2cSBryan Venteicher int error; 296e3c97c2cSBryan Venteicher 297e3c97c2cSBryan Venteicher sc = device_get_softc(dev); 298e3c97c2cSBryan Venteicher sc->vmx_dev = dev; 299e3c97c2cSBryan Venteicher 300e3c97c2cSBryan Venteicher pci_enable_busmaster(dev); 301e3c97c2cSBryan Venteicher 302e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK_INIT(sc, device_get_nameunit(dev)); 303e3c97c2cSBryan Venteicher callout_init_mtx(&sc->vmx_tick, &sc->vmx_mtx, 0); 304e3c97c2cSBryan Venteicher 305e3c97c2cSBryan Venteicher vmxnet3_initial_config(sc); 306e3c97c2cSBryan Venteicher 307e3c97c2cSBryan Venteicher error = vmxnet3_alloc_resources(sc); 308e3c97c2cSBryan Venteicher if (error) 309e3c97c2cSBryan Venteicher goto fail; 310e3c97c2cSBryan Venteicher 311e3c97c2cSBryan Venteicher error = vmxnet3_check_version(sc); 312e3c97c2cSBryan Venteicher if (error) 313e3c97c2cSBryan Venteicher goto fail; 314e3c97c2cSBryan Venteicher 315e3c97c2cSBryan Venteicher error = vmxnet3_alloc_rxtx_queues(sc); 316e3c97c2cSBryan Venteicher if (error) 317e3c97c2cSBryan Venteicher goto fail; 318e3c97c2cSBryan Venteicher 319*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX 320*e557c1ddSBryan Venteicher error = vmxnet3_alloc_taskqueue(sc); 321*e557c1ddSBryan Venteicher if (error) 322*e557c1ddSBryan Venteicher goto fail; 323*e557c1ddSBryan Venteicher #endif 324*e557c1ddSBryan Venteicher 325e3c97c2cSBryan Venteicher error = vmxnet3_alloc_interrupts(sc); 326e3c97c2cSBryan Venteicher if (error) 327e3c97c2cSBryan Venteicher goto fail; 328e3c97c2cSBryan Venteicher 329*e557c1ddSBryan Venteicher vmxnet3_check_multiqueue(sc); 330*e557c1ddSBryan Venteicher 331e3c97c2cSBryan Venteicher error = vmxnet3_alloc_data(sc); 332e3c97c2cSBryan Venteicher if (error) 333e3c97c2cSBryan Venteicher goto fail; 334e3c97c2cSBryan Venteicher 335e3c97c2cSBryan Venteicher error = vmxnet3_setup_interface(sc); 336e3c97c2cSBryan Venteicher if (error) 337e3c97c2cSBryan Venteicher goto fail; 338e3c97c2cSBryan Venteicher 339e3c97c2cSBryan Venteicher error = vmxnet3_setup_interrupts(sc); 340e3c97c2cSBryan Venteicher if (error) { 341e3c97c2cSBryan Venteicher ether_ifdetach(sc->vmx_ifp); 342e3c97c2cSBryan Venteicher device_printf(dev, "could not set up interrupt\n"); 343e3c97c2cSBryan Venteicher goto fail; 344e3c97c2cSBryan Venteicher } 345e3c97c2cSBryan Venteicher 346e3c97c2cSBryan Venteicher vmxnet3_setup_sysctl(sc); 347*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX 348*e557c1ddSBryan Venteicher vmxnet3_start_taskqueue(sc); 349*e557c1ddSBryan Venteicher #endif 350e3c97c2cSBryan Venteicher 351e3c97c2cSBryan Venteicher fail: 352e3c97c2cSBryan Venteicher if (error) 353e3c97c2cSBryan Venteicher vmxnet3_detach(dev); 354e3c97c2cSBryan Venteicher 355e3c97c2cSBryan Venteicher return (error); 356e3c97c2cSBryan Venteicher } 357e3c97c2cSBryan Venteicher 358e3c97c2cSBryan Venteicher static int 359e3c97c2cSBryan Venteicher vmxnet3_detach(device_t dev) 360e3c97c2cSBryan Venteicher { 361e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 362e3c97c2cSBryan Venteicher struct ifnet *ifp; 363e3c97c2cSBryan Venteicher 364e3c97c2cSBryan Venteicher sc = device_get_softc(dev); 365e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 366e3c97c2cSBryan Venteicher 367e3c97c2cSBryan Venteicher if (device_is_attached(dev)) { 368e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK(sc); 369e3c97c2cSBryan Venteicher vmxnet3_stop(sc); 370e3c97c2cSBryan Venteicher VMXNET3_CORE_UNLOCK(sc); 371*e557c1ddSBryan Venteicher 372e3c97c2cSBryan Venteicher callout_drain(&sc->vmx_tick); 373*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX 374*e557c1ddSBryan Venteicher vmxnet3_drain_taskqueue(sc); 375*e557c1ddSBryan Venteicher #endif 376*e557c1ddSBryan Venteicher 377*e557c1ddSBryan Venteicher ether_ifdetach(ifp); 378e3c97c2cSBryan Venteicher } 379e3c97c2cSBryan Venteicher 380e3c97c2cSBryan Venteicher if (sc->vmx_vlan_attach != NULL) { 381e3c97c2cSBryan Venteicher EVENTHANDLER_DEREGISTER(vlan_config, sc->vmx_vlan_attach); 382e3c97c2cSBryan Venteicher sc->vmx_vlan_attach = NULL; 383e3c97c2cSBryan Venteicher } 384e3c97c2cSBryan Venteicher if (sc->vmx_vlan_detach != NULL) { 385e3c97c2cSBryan Venteicher EVENTHANDLER_DEREGISTER(vlan_config, sc->vmx_vlan_detach); 386e3c97c2cSBryan Venteicher sc->vmx_vlan_detach = NULL; 387e3c97c2cSBryan Venteicher } 388e3c97c2cSBryan Venteicher 389*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX 390*e557c1ddSBryan Venteicher vmxnet3_free_taskqueue(sc); 391*e557c1ddSBryan Venteicher #endif 392e3c97c2cSBryan Venteicher vmxnet3_free_interrupts(sc); 393e3c97c2cSBryan Venteicher 394e3c97c2cSBryan Venteicher if (ifp != NULL) { 395e3c97c2cSBryan Venteicher if_free(ifp); 396e3c97c2cSBryan Venteicher sc->vmx_ifp = NULL; 397e3c97c2cSBryan Venteicher } 398e3c97c2cSBryan Venteicher 399e3c97c2cSBryan Venteicher ifmedia_removeall(&sc->vmx_media); 400e3c97c2cSBryan Venteicher 401e3c97c2cSBryan Venteicher vmxnet3_free_data(sc); 402e3c97c2cSBryan Venteicher vmxnet3_free_resources(sc); 403e3c97c2cSBryan Venteicher vmxnet3_free_rxtx_queues(sc); 404e3c97c2cSBryan Venteicher 405e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK_DESTROY(sc); 406e3c97c2cSBryan Venteicher 407e3c97c2cSBryan Venteicher return (0); 408e3c97c2cSBryan Venteicher } 409e3c97c2cSBryan Venteicher 410e3c97c2cSBryan Venteicher static int 411e3c97c2cSBryan Venteicher vmxnet3_shutdown(device_t dev) 412e3c97c2cSBryan Venteicher { 413e3c97c2cSBryan Venteicher 414e3c97c2cSBryan Venteicher return (0); 415e3c97c2cSBryan Venteicher } 416e3c97c2cSBryan Venteicher 417e3c97c2cSBryan Venteicher static int 418e3c97c2cSBryan Venteicher vmxnet3_alloc_resources(struct vmxnet3_softc *sc) 419e3c97c2cSBryan Venteicher { 420e3c97c2cSBryan Venteicher device_t dev; 421e3c97c2cSBryan Venteicher int rid; 422e3c97c2cSBryan Venteicher 423e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 424e3c97c2cSBryan Venteicher 425e3c97c2cSBryan Venteicher rid = PCIR_BAR(0); 426e3c97c2cSBryan Venteicher sc->vmx_res0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 427e3c97c2cSBryan Venteicher RF_ACTIVE); 428e3c97c2cSBryan Venteicher if (sc->vmx_res0 == NULL) { 429e3c97c2cSBryan Venteicher device_printf(dev, 430e3c97c2cSBryan Venteicher "could not map BAR0 memory\n"); 431e3c97c2cSBryan Venteicher return (ENXIO); 432e3c97c2cSBryan Venteicher } 433e3c97c2cSBryan Venteicher 434e3c97c2cSBryan Venteicher sc->vmx_iot0 = rman_get_bustag(sc->vmx_res0); 435e3c97c2cSBryan Venteicher sc->vmx_ioh0 = rman_get_bushandle(sc->vmx_res0); 436e3c97c2cSBryan Venteicher 437e3c97c2cSBryan Venteicher rid = PCIR_BAR(1); 438e3c97c2cSBryan Venteicher sc->vmx_res1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 439e3c97c2cSBryan Venteicher RF_ACTIVE); 440e3c97c2cSBryan Venteicher if (sc->vmx_res1 == NULL) { 441e3c97c2cSBryan Venteicher device_printf(dev, 442e3c97c2cSBryan Venteicher "could not map BAR1 memory\n"); 443e3c97c2cSBryan Venteicher return (ENXIO); 444e3c97c2cSBryan Venteicher } 445e3c97c2cSBryan Venteicher 446e3c97c2cSBryan Venteicher sc->vmx_iot1 = rman_get_bustag(sc->vmx_res1); 447e3c97c2cSBryan Venteicher sc->vmx_ioh1 = rman_get_bushandle(sc->vmx_res1); 448e3c97c2cSBryan Venteicher 449e3c97c2cSBryan Venteicher if (pci_find_cap(dev, PCIY_MSIX, NULL) == 0) { 450e3c97c2cSBryan Venteicher rid = PCIR_BAR(2); 451e3c97c2cSBryan Venteicher sc->vmx_msix_res = bus_alloc_resource_any(dev, 452e3c97c2cSBryan Venteicher SYS_RES_MEMORY, &rid, RF_ACTIVE); 453e3c97c2cSBryan Venteicher } 454e3c97c2cSBryan Venteicher 455e3c97c2cSBryan Venteicher if (sc->vmx_msix_res == NULL) 456e3c97c2cSBryan Venteicher sc->vmx_flags |= VMXNET3_FLAG_NO_MSIX; 457e3c97c2cSBryan Venteicher 458e3c97c2cSBryan Venteicher return (0); 459e3c97c2cSBryan Venteicher } 460e3c97c2cSBryan Venteicher 461e3c97c2cSBryan Venteicher static void 462e3c97c2cSBryan Venteicher vmxnet3_free_resources(struct vmxnet3_softc *sc) 463e3c97c2cSBryan Venteicher { 464e3c97c2cSBryan Venteicher device_t dev; 465e3c97c2cSBryan Venteicher int rid; 466e3c97c2cSBryan Venteicher 467e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 468e3c97c2cSBryan Venteicher 469e3c97c2cSBryan Venteicher if (sc->vmx_res0 != NULL) { 470e3c97c2cSBryan Venteicher rid = PCIR_BAR(0); 471e3c97c2cSBryan Venteicher bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->vmx_res0); 472e3c97c2cSBryan Venteicher sc->vmx_res0 = NULL; 473e3c97c2cSBryan Venteicher } 474e3c97c2cSBryan Venteicher 475e3c97c2cSBryan Venteicher if (sc->vmx_res1 != NULL) { 476e3c97c2cSBryan Venteicher rid = PCIR_BAR(1); 477e3c97c2cSBryan Venteicher bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->vmx_res1); 478e3c97c2cSBryan Venteicher sc->vmx_res1 = NULL; 479e3c97c2cSBryan Venteicher } 480e3c97c2cSBryan Venteicher 481e3c97c2cSBryan Venteicher if (sc->vmx_msix_res != NULL) { 482e3c97c2cSBryan Venteicher rid = PCIR_BAR(2); 483e3c97c2cSBryan Venteicher bus_release_resource(dev, SYS_RES_MEMORY, rid, 484e3c97c2cSBryan Venteicher sc->vmx_msix_res); 485e3c97c2cSBryan Venteicher sc->vmx_msix_res = NULL; 486e3c97c2cSBryan Venteicher } 487e3c97c2cSBryan Venteicher } 488e3c97c2cSBryan Venteicher 489e3c97c2cSBryan Venteicher static int 490e3c97c2cSBryan Venteicher vmxnet3_check_version(struct vmxnet3_softc *sc) 491e3c97c2cSBryan Venteicher { 492e3c97c2cSBryan Venteicher device_t dev; 493e3c97c2cSBryan Venteicher uint32_t version; 494e3c97c2cSBryan Venteicher 495e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 496e3c97c2cSBryan Venteicher 497e3c97c2cSBryan Venteicher version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_VRRS); 498e3c97c2cSBryan Venteicher if ((version & 0x01) == 0) { 499e3c97c2cSBryan Venteicher device_printf(dev, "unsupported hardware version %#x\n", 500e3c97c2cSBryan Venteicher version); 501e3c97c2cSBryan Venteicher return (ENOTSUP); 5023c965775SBryan Venteicher } 503e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_VRRS, 1); 504e3c97c2cSBryan Venteicher 505e3c97c2cSBryan Venteicher version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_UVRS); 506e3c97c2cSBryan Venteicher if ((version & 0x01) == 0) { 507e3c97c2cSBryan Venteicher device_printf(dev, "unsupported UPT version %#x\n", version); 508e3c97c2cSBryan Venteicher return (ENOTSUP); 5093c965775SBryan Venteicher } 510e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_UVRS, 1); 511e3c97c2cSBryan Venteicher 512e3c97c2cSBryan Venteicher return (0); 513e3c97c2cSBryan Venteicher } 514e3c97c2cSBryan Venteicher 515e3c97c2cSBryan Venteicher static void 516e3c97c2cSBryan Venteicher vmxnet3_initial_config(struct vmxnet3_softc *sc) 517e3c97c2cSBryan Venteicher { 518*e557c1ddSBryan Venteicher int nqueue, ndesc; 519e3c97c2cSBryan Venteicher 520*e557c1ddSBryan Venteicher nqueue = vmxnet3_tunable_int(sc, "txnqueue", vmxnet3_default_txnqueue); 521*e557c1ddSBryan Venteicher if (nqueue > VMXNET3_MAX_TX_QUEUES || nqueue < 1) 522*e557c1ddSBryan Venteicher nqueue = VMXNET3_DEF_TX_QUEUES; 523*e557c1ddSBryan Venteicher if (nqueue > mp_ncpus) 524*e557c1ddSBryan Venteicher nqueue = mp_ncpus; 525*e557c1ddSBryan Venteicher sc->vmx_max_ntxqueues = nqueue; 526*e557c1ddSBryan Venteicher 527*e557c1ddSBryan Venteicher nqueue = vmxnet3_tunable_int(sc, "rxnqueue", vmxnet3_default_rxnqueue); 528*e557c1ddSBryan Venteicher if (nqueue > VMXNET3_MAX_RX_QUEUES || nqueue < 1) 529*e557c1ddSBryan Venteicher nqueue = VMXNET3_DEF_RX_QUEUES; 530*e557c1ddSBryan Venteicher if (nqueue > mp_ncpus) 531*e557c1ddSBryan Venteicher nqueue = mp_ncpus; 532*e557c1ddSBryan Venteicher sc->vmx_max_nrxqueues = nqueue; 533*e557c1ddSBryan Venteicher 534*e557c1ddSBryan Venteicher if (vmxnet3_tunable_int(sc, "mq_disable", vmxnet3_mq_disable)) { 535*e557c1ddSBryan Venteicher sc->vmx_max_nrxqueues = 1; 536*e557c1ddSBryan Venteicher sc->vmx_max_ntxqueues = 1; 537*e557c1ddSBryan Venteicher } 5383c5dfe89SBryan Venteicher 5393c5dfe89SBryan Venteicher ndesc = vmxnet3_tunable_int(sc, "txd", vmxnet3_default_txndesc); 5403c5dfe89SBryan Venteicher if (ndesc > VMXNET3_MAX_TX_NDESC || ndesc < VMXNET3_MIN_TX_NDESC) 5413c5dfe89SBryan Venteicher ndesc = VMXNET3_DEF_TX_NDESC; 5423c5dfe89SBryan Venteicher if (ndesc & VMXNET3_MASK_TX_NDESC) 5433c5dfe89SBryan Venteicher ndesc &= ~VMXNET3_MASK_TX_NDESC; 5443c5dfe89SBryan Venteicher sc->vmx_ntxdescs = ndesc; 5453c5dfe89SBryan Venteicher 5463c5dfe89SBryan Venteicher ndesc = vmxnet3_tunable_int(sc, "rxd", vmxnet3_default_rxndesc); 5473c5dfe89SBryan Venteicher if (ndesc > VMXNET3_MAX_RX_NDESC || ndesc < VMXNET3_MIN_RX_NDESC) 5483c5dfe89SBryan Venteicher ndesc = VMXNET3_DEF_RX_NDESC; 5493c5dfe89SBryan Venteicher if (ndesc & VMXNET3_MASK_RX_NDESC) 5503c5dfe89SBryan Venteicher ndesc &= ~VMXNET3_MASK_RX_NDESC; 5513c5dfe89SBryan Venteicher sc->vmx_nrxdescs = ndesc; 552e3c97c2cSBryan Venteicher sc->vmx_max_rxsegs = VMXNET3_MAX_RX_SEGS; 553e3c97c2cSBryan Venteicher } 554e3c97c2cSBryan Venteicher 555*e557c1ddSBryan Venteicher static void 556*e557c1ddSBryan Venteicher vmxnet3_check_multiqueue(struct vmxnet3_softc *sc) 557*e557c1ddSBryan Venteicher { 558*e557c1ddSBryan Venteicher 559*e557c1ddSBryan Venteicher if (sc->vmx_intr_type != VMXNET3_IT_MSIX) 560*e557c1ddSBryan Venteicher goto out; 561*e557c1ddSBryan Venteicher 562*e557c1ddSBryan Venteicher /* BMV: Just use the maximum configured for now. */ 563*e557c1ddSBryan Venteicher sc->vmx_nrxqueues = sc->vmx_max_nrxqueues; 564*e557c1ddSBryan Venteicher sc->vmx_ntxqueues = sc->vmx_max_ntxqueues; 565*e557c1ddSBryan Venteicher 566*e557c1ddSBryan Venteicher if (sc->vmx_nrxqueues > 1) 567*e557c1ddSBryan Venteicher sc->vmx_flags |= VMXNET3_FLAG_RSS; 568*e557c1ddSBryan Venteicher 569*e557c1ddSBryan Venteicher return; 570*e557c1ddSBryan Venteicher 571*e557c1ddSBryan Venteicher out: 572*e557c1ddSBryan Venteicher sc->vmx_ntxqueues = 1; 573*e557c1ddSBryan Venteicher sc->vmx_nrxqueues = 1; 574*e557c1ddSBryan Venteicher } 575*e557c1ddSBryan Venteicher 576e3c97c2cSBryan Venteicher static int 577e3c97c2cSBryan Venteicher vmxnet3_alloc_msix_interrupts(struct vmxnet3_softc *sc) 578e3c97c2cSBryan Venteicher { 579e3c97c2cSBryan Venteicher device_t dev; 580e3c97c2cSBryan Venteicher int nmsix, cnt, required; 581e3c97c2cSBryan Venteicher 582e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 583e3c97c2cSBryan Venteicher 584e3c97c2cSBryan Venteicher if (sc->vmx_flags & VMXNET3_FLAG_NO_MSIX) 585e3c97c2cSBryan Venteicher return (1); 586e3c97c2cSBryan Venteicher 587e3c97c2cSBryan Venteicher /* Allocate an additional vector for the events interrupt. */ 588*e557c1ddSBryan Venteicher required = sc->vmx_max_nrxqueues + sc->vmx_max_ntxqueues + 1; 589e3c97c2cSBryan Venteicher 590e3c97c2cSBryan Venteicher nmsix = pci_msix_count(dev); 591e3c97c2cSBryan Venteicher if (nmsix < required) 592e3c97c2cSBryan Venteicher return (1); 593e3c97c2cSBryan Venteicher 594e3c97c2cSBryan Venteicher cnt = required; 595e3c97c2cSBryan Venteicher if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) { 596e3c97c2cSBryan Venteicher sc->vmx_nintrs = required; 597e3c97c2cSBryan Venteicher return (0); 598e3c97c2cSBryan Venteicher } else 599e3c97c2cSBryan Venteicher pci_release_msi(dev); 600e3c97c2cSBryan Venteicher 601*e557c1ddSBryan Venteicher /* BMV TODO Fallback to sharing MSIX vectors if possible. */ 602*e557c1ddSBryan Venteicher 603e3c97c2cSBryan Venteicher return (1); 604e3c97c2cSBryan Venteicher } 605e3c97c2cSBryan Venteicher 606e3c97c2cSBryan Venteicher static int 607e3c97c2cSBryan Venteicher vmxnet3_alloc_msi_interrupts(struct vmxnet3_softc *sc) 608e3c97c2cSBryan Venteicher { 609e3c97c2cSBryan Venteicher device_t dev; 610e3c97c2cSBryan Venteicher int nmsi, cnt, required; 611e3c97c2cSBryan Venteicher 612e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 613e3c97c2cSBryan Venteicher required = 1; 614e3c97c2cSBryan Venteicher 615e3c97c2cSBryan Venteicher nmsi = pci_msi_count(dev); 616e3c97c2cSBryan Venteicher if (nmsi < required) 617e3c97c2cSBryan Venteicher return (1); 618e3c97c2cSBryan Venteicher 619e3c97c2cSBryan Venteicher cnt = required; 620e3c97c2cSBryan Venteicher if (pci_alloc_msi(dev, &cnt) == 0 && cnt >= required) { 621e3c97c2cSBryan Venteicher sc->vmx_nintrs = 1; 622e3c97c2cSBryan Venteicher return (0); 623e3c97c2cSBryan Venteicher } else 624e3c97c2cSBryan Venteicher pci_release_msi(dev); 625e3c97c2cSBryan Venteicher 626e3c97c2cSBryan Venteicher return (1); 627e3c97c2cSBryan Venteicher } 628e3c97c2cSBryan Venteicher 629e3c97c2cSBryan Venteicher static int 630e3c97c2cSBryan Venteicher vmxnet3_alloc_legacy_interrupts(struct vmxnet3_softc *sc) 631e3c97c2cSBryan Venteicher { 632e3c97c2cSBryan Venteicher 633e3c97c2cSBryan Venteicher sc->vmx_nintrs = 1; 634e3c97c2cSBryan Venteicher return (0); 635e3c97c2cSBryan Venteicher } 636e3c97c2cSBryan Venteicher 637e3c97c2cSBryan Venteicher static int 638e3c97c2cSBryan Venteicher vmxnet3_alloc_interrupt(struct vmxnet3_softc *sc, int rid, int flags, 639e3c97c2cSBryan Venteicher struct vmxnet3_interrupt *intr) 640e3c97c2cSBryan Venteicher { 641e3c97c2cSBryan Venteicher struct resource *irq; 642e3c97c2cSBryan Venteicher 643e3c97c2cSBryan Venteicher irq = bus_alloc_resource_any(sc->vmx_dev, SYS_RES_IRQ, &rid, flags); 644e3c97c2cSBryan Venteicher if (irq == NULL) 645e3c97c2cSBryan Venteicher return (ENXIO); 646e3c97c2cSBryan Venteicher 647e3c97c2cSBryan Venteicher intr->vmxi_irq = irq; 648e3c97c2cSBryan Venteicher intr->vmxi_rid = rid; 649e3c97c2cSBryan Venteicher 650e3c97c2cSBryan Venteicher return (0); 651e3c97c2cSBryan Venteicher } 652e3c97c2cSBryan Venteicher 653e3c97c2cSBryan Venteicher static int 654e3c97c2cSBryan Venteicher vmxnet3_alloc_intr_resources(struct vmxnet3_softc *sc) 655e3c97c2cSBryan Venteicher { 656e3c97c2cSBryan Venteicher int i, rid, flags, error; 657e3c97c2cSBryan Venteicher 658e3c97c2cSBryan Venteicher rid = 0; 659e3c97c2cSBryan Venteicher flags = RF_ACTIVE; 660e3c97c2cSBryan Venteicher 661e3c97c2cSBryan Venteicher if (sc->vmx_intr_type == VMXNET3_IT_LEGACY) 662e3c97c2cSBryan Venteicher flags |= RF_SHAREABLE; 663e3c97c2cSBryan Venteicher else 664e3c97c2cSBryan Venteicher rid = 1; 665e3c97c2cSBryan Venteicher 666e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nintrs; i++, rid++) { 667e3c97c2cSBryan Venteicher error = vmxnet3_alloc_interrupt(sc, rid, flags, 668e3c97c2cSBryan Venteicher &sc->vmx_intrs[i]); 669e3c97c2cSBryan Venteicher if (error) 670e3c97c2cSBryan Venteicher return (error); 671e3c97c2cSBryan Venteicher } 672e3c97c2cSBryan Venteicher 673e3c97c2cSBryan Venteicher return (0); 674e3c97c2cSBryan Venteicher } 675e3c97c2cSBryan Venteicher 676e3c97c2cSBryan Venteicher static int 677e3c97c2cSBryan Venteicher vmxnet3_setup_msix_interrupts(struct vmxnet3_softc *sc) 678e3c97c2cSBryan Venteicher { 679e3c97c2cSBryan Venteicher device_t dev; 680e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq; 681e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq; 682e3c97c2cSBryan Venteicher struct vmxnet3_interrupt *intr; 683e3c97c2cSBryan Venteicher enum intr_type type; 684e3c97c2cSBryan Venteicher int i, error; 685e3c97c2cSBryan Venteicher 686e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 687e3c97c2cSBryan Venteicher intr = &sc->vmx_intrs[0]; 688e3c97c2cSBryan Venteicher type = INTR_TYPE_NET | INTR_MPSAFE; 689e3c97c2cSBryan Venteicher 690e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++, intr++) { 691e3c97c2cSBryan Venteicher txq = &sc->vmx_txq[i]; 692e3c97c2cSBryan Venteicher error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL, 693e3c97c2cSBryan Venteicher vmxnet3_txq_intr, txq, &intr->vmxi_handler); 694e3c97c2cSBryan Venteicher if (error) 695e3c97c2cSBryan Venteicher return (error); 696e3c97c2cSBryan Venteicher txq->vxtxq_intr_idx = intr->vmxi_rid - 1; 697e3c97c2cSBryan Venteicher } 698e3c97c2cSBryan Venteicher 699e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nrxqueues; i++, intr++) { 700e3c97c2cSBryan Venteicher rxq = &sc->vmx_rxq[i]; 701e3c97c2cSBryan Venteicher error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL, 702e3c97c2cSBryan Venteicher vmxnet3_rxq_intr, rxq, &intr->vmxi_handler); 703e3c97c2cSBryan Venteicher if (error) 704e3c97c2cSBryan Venteicher return (error); 705e3c97c2cSBryan Venteicher rxq->vxrxq_intr_idx = intr->vmxi_rid - 1; 706e3c97c2cSBryan Venteicher } 707e3c97c2cSBryan Venteicher 708e3c97c2cSBryan Venteicher error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL, 709e3c97c2cSBryan Venteicher vmxnet3_event_intr, sc, &intr->vmxi_handler); 710e3c97c2cSBryan Venteicher if (error) 711e3c97c2cSBryan Venteicher return (error); 712e3c97c2cSBryan Venteicher sc->vmx_event_intr_idx = intr->vmxi_rid - 1; 713e3c97c2cSBryan Venteicher 714e3c97c2cSBryan Venteicher return (0); 715e3c97c2cSBryan Venteicher } 716e3c97c2cSBryan Venteicher 717e3c97c2cSBryan Venteicher static int 718e3c97c2cSBryan Venteicher vmxnet3_setup_legacy_interrupt(struct vmxnet3_softc *sc) 719e3c97c2cSBryan Venteicher { 720e3c97c2cSBryan Venteicher struct vmxnet3_interrupt *intr; 721e3c97c2cSBryan Venteicher int i, error; 722e3c97c2cSBryan Venteicher 723e3c97c2cSBryan Venteicher intr = &sc->vmx_intrs[0]; 724e3c97c2cSBryan Venteicher error = bus_setup_intr(sc->vmx_dev, intr->vmxi_irq, 725e3c97c2cSBryan Venteicher INTR_TYPE_NET | INTR_MPSAFE, NULL, vmxnet3_legacy_intr, sc, 726e3c97c2cSBryan Venteicher &intr->vmxi_handler); 727e3c97c2cSBryan Venteicher 728e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++) 729e3c97c2cSBryan Venteicher sc->vmx_txq[i].vxtxq_intr_idx = 0; 730e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nrxqueues; i++) 731e3c97c2cSBryan Venteicher sc->vmx_rxq[i].vxrxq_intr_idx = 0; 732e3c97c2cSBryan Venteicher sc->vmx_event_intr_idx = 0; 733e3c97c2cSBryan Venteicher 734e3c97c2cSBryan Venteicher return (error); 735e3c97c2cSBryan Venteicher } 736e3c97c2cSBryan Venteicher 737e3c97c2cSBryan Venteicher static void 738e3c97c2cSBryan Venteicher vmxnet3_set_interrupt_idx(struct vmxnet3_softc *sc) 739e3c97c2cSBryan Venteicher { 740e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq; 741e3c97c2cSBryan Venteicher struct vmxnet3_txq_shared *txs; 742e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq; 743e3c97c2cSBryan Venteicher struct vmxnet3_rxq_shared *rxs; 744e3c97c2cSBryan Venteicher int i; 745e3c97c2cSBryan Venteicher 746e3c97c2cSBryan Venteicher sc->vmx_ds->evintr = sc->vmx_event_intr_idx; 747e3c97c2cSBryan Venteicher 748e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++) { 749e3c97c2cSBryan Venteicher txq = &sc->vmx_txq[i]; 750e3c97c2cSBryan Venteicher txs = txq->vxtxq_ts; 751e3c97c2cSBryan Venteicher txs->intr_idx = txq->vxtxq_intr_idx; 752e3c97c2cSBryan Venteicher } 753e3c97c2cSBryan Venteicher 754e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nrxqueues; i++) { 755e3c97c2cSBryan Venteicher rxq = &sc->vmx_rxq[i]; 756e3c97c2cSBryan Venteicher rxs = rxq->vxrxq_rs; 757e3c97c2cSBryan Venteicher rxs->intr_idx = rxq->vxrxq_intr_idx; 758e3c97c2cSBryan Venteicher } 759e3c97c2cSBryan Venteicher } 760e3c97c2cSBryan Venteicher 761e3c97c2cSBryan Venteicher static int 762e3c97c2cSBryan Venteicher vmxnet3_setup_interrupts(struct vmxnet3_softc *sc) 763e3c97c2cSBryan Venteicher { 764e3c97c2cSBryan Venteicher int error; 765e3c97c2cSBryan Venteicher 766e3c97c2cSBryan Venteicher error = vmxnet3_alloc_intr_resources(sc); 767e3c97c2cSBryan Venteicher if (error) 768e3c97c2cSBryan Venteicher return (error); 769e3c97c2cSBryan Venteicher 770e3c97c2cSBryan Venteicher switch (sc->vmx_intr_type) { 771e3c97c2cSBryan Venteicher case VMXNET3_IT_MSIX: 772e3c97c2cSBryan Venteicher error = vmxnet3_setup_msix_interrupts(sc); 773e3c97c2cSBryan Venteicher break; 774e3c97c2cSBryan Venteicher case VMXNET3_IT_MSI: 775e3c97c2cSBryan Venteicher case VMXNET3_IT_LEGACY: 776e3c97c2cSBryan Venteicher error = vmxnet3_setup_legacy_interrupt(sc); 777e3c97c2cSBryan Venteicher break; 778e3c97c2cSBryan Venteicher default: 779e3c97c2cSBryan Venteicher panic("%s: invalid interrupt type %d", __func__, 780e3c97c2cSBryan Venteicher sc->vmx_intr_type); 781e3c97c2cSBryan Venteicher } 782e3c97c2cSBryan Venteicher 783e3c97c2cSBryan Venteicher if (error == 0) 784e3c97c2cSBryan Venteicher vmxnet3_set_interrupt_idx(sc); 785e3c97c2cSBryan Venteicher 786e3c97c2cSBryan Venteicher return (error); 787e3c97c2cSBryan Venteicher } 788e3c97c2cSBryan Venteicher 789e3c97c2cSBryan Venteicher static int 790e3c97c2cSBryan Venteicher vmxnet3_alloc_interrupts(struct vmxnet3_softc *sc) 791e3c97c2cSBryan Venteicher { 792e3c97c2cSBryan Venteicher device_t dev; 793e3c97c2cSBryan Venteicher uint32_t config; 794e3c97c2cSBryan Venteicher int error; 795e3c97c2cSBryan Venteicher 796e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 797e3c97c2cSBryan Venteicher config = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_INTRCFG); 798e3c97c2cSBryan Venteicher 799e3c97c2cSBryan Venteicher sc->vmx_intr_type = config & 0x03; 800e3c97c2cSBryan Venteicher sc->vmx_intr_mask_mode = (config >> 2) & 0x03; 801e3c97c2cSBryan Venteicher 802e3c97c2cSBryan Venteicher switch (sc->vmx_intr_type) { 803e3c97c2cSBryan Venteicher case VMXNET3_IT_AUTO: 804e3c97c2cSBryan Venteicher sc->vmx_intr_type = VMXNET3_IT_MSIX; 805e3c97c2cSBryan Venteicher /* FALLTHROUGH */ 806e3c97c2cSBryan Venteicher case VMXNET3_IT_MSIX: 807e3c97c2cSBryan Venteicher error = vmxnet3_alloc_msix_interrupts(sc); 808e3c97c2cSBryan Venteicher if (error == 0) 809e3c97c2cSBryan Venteicher break; 810e3c97c2cSBryan Venteicher sc->vmx_intr_type = VMXNET3_IT_MSI; 811e3c97c2cSBryan Venteicher /* FALLTHROUGH */ 812e3c97c2cSBryan Venteicher case VMXNET3_IT_MSI: 813e3c97c2cSBryan Venteicher error = vmxnet3_alloc_msi_interrupts(sc); 814e3c97c2cSBryan Venteicher if (error == 0) 815e3c97c2cSBryan Venteicher break; 816e3c97c2cSBryan Venteicher sc->vmx_intr_type = VMXNET3_IT_LEGACY; 817e3c97c2cSBryan Venteicher /* FALLTHROUGH */ 818e3c97c2cSBryan Venteicher case VMXNET3_IT_LEGACY: 819e3c97c2cSBryan Venteicher error = vmxnet3_alloc_legacy_interrupts(sc); 820e3c97c2cSBryan Venteicher if (error == 0) 821e3c97c2cSBryan Venteicher break; 822e3c97c2cSBryan Venteicher /* FALLTHROUGH */ 823e3c97c2cSBryan Venteicher default: 824e3c97c2cSBryan Venteicher sc->vmx_intr_type = -1; 825e3c97c2cSBryan Venteicher device_printf(dev, "cannot allocate any interrupt resources\n"); 826e3c97c2cSBryan Venteicher return (ENXIO); 827e3c97c2cSBryan Venteicher } 828e3c97c2cSBryan Venteicher 829e3c97c2cSBryan Venteicher return (error); 830e3c97c2cSBryan Venteicher } 831e3c97c2cSBryan Venteicher 832e3c97c2cSBryan Venteicher static void 833e3c97c2cSBryan Venteicher vmxnet3_free_interrupt(struct vmxnet3_softc *sc, 834e3c97c2cSBryan Venteicher struct vmxnet3_interrupt *intr) 835e3c97c2cSBryan Venteicher { 836e3c97c2cSBryan Venteicher device_t dev; 837e3c97c2cSBryan Venteicher 838e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 839e3c97c2cSBryan Venteicher 840e3c97c2cSBryan Venteicher if (intr->vmxi_handler != NULL) { 841e3c97c2cSBryan Venteicher bus_teardown_intr(dev, intr->vmxi_irq, intr->vmxi_handler); 842e3c97c2cSBryan Venteicher intr->vmxi_handler = NULL; 843e3c97c2cSBryan Venteicher } 844e3c97c2cSBryan Venteicher 845e3c97c2cSBryan Venteicher if (intr->vmxi_irq != NULL) { 846e3c97c2cSBryan Venteicher bus_release_resource(dev, SYS_RES_IRQ, intr->vmxi_rid, 847e3c97c2cSBryan Venteicher intr->vmxi_irq); 848e3c97c2cSBryan Venteicher intr->vmxi_irq = NULL; 849e3c97c2cSBryan Venteicher intr->vmxi_rid = -1; 850e3c97c2cSBryan Venteicher } 851e3c97c2cSBryan Venteicher } 852e3c97c2cSBryan Venteicher 853e3c97c2cSBryan Venteicher static void 854e3c97c2cSBryan Venteicher vmxnet3_free_interrupts(struct vmxnet3_softc *sc) 855e3c97c2cSBryan Venteicher { 856e3c97c2cSBryan Venteicher int i; 857e3c97c2cSBryan Venteicher 858e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nintrs; i++) 859e3c97c2cSBryan Venteicher vmxnet3_free_interrupt(sc, &sc->vmx_intrs[i]); 860e3c97c2cSBryan Venteicher 861e3c97c2cSBryan Venteicher if (sc->vmx_intr_type == VMXNET3_IT_MSI || 862e3c97c2cSBryan Venteicher sc->vmx_intr_type == VMXNET3_IT_MSIX) 863e3c97c2cSBryan Venteicher pci_release_msi(sc->vmx_dev); 864e3c97c2cSBryan Venteicher } 865e3c97c2cSBryan Venteicher 866*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX 867*e557c1ddSBryan Venteicher static int 868*e557c1ddSBryan Venteicher vmxnet3_alloc_taskqueue(struct vmxnet3_softc *sc) 869*e557c1ddSBryan Venteicher { 870*e557c1ddSBryan Venteicher device_t dev; 871*e557c1ddSBryan Venteicher 872*e557c1ddSBryan Venteicher dev = sc->vmx_dev; 873*e557c1ddSBryan Venteicher 874*e557c1ddSBryan Venteicher sc->vmx_tq = taskqueue_create(device_get_nameunit(dev), M_NOWAIT, 875*e557c1ddSBryan Venteicher taskqueue_thread_enqueue, &sc->vmx_tq); 876*e557c1ddSBryan Venteicher if (sc->vmx_tq == NULL) 877*e557c1ddSBryan Venteicher return (ENOMEM); 878*e557c1ddSBryan Venteicher 879*e557c1ddSBryan Venteicher return (0); 880*e557c1ddSBryan Venteicher } 881*e557c1ddSBryan Venteicher 882*e557c1ddSBryan Venteicher static void 883*e557c1ddSBryan Venteicher vmxnet3_start_taskqueue(struct vmxnet3_softc *sc) 884*e557c1ddSBryan Venteicher { 885*e557c1ddSBryan Venteicher device_t dev; 886*e557c1ddSBryan Venteicher int nthreads, error; 887*e557c1ddSBryan Venteicher 888*e557c1ddSBryan Venteicher dev = sc->vmx_dev; 889*e557c1ddSBryan Venteicher 890*e557c1ddSBryan Venteicher /* 891*e557c1ddSBryan Venteicher * The taskqueue is typically not frequently used, so a dedicated 892*e557c1ddSBryan Venteicher * thread for each queue is unnecessary. 893*e557c1ddSBryan Venteicher */ 894*e557c1ddSBryan Venteicher nthreads = MAX(1, sc->vmx_ntxqueues / 2); 895*e557c1ddSBryan Venteicher 896*e557c1ddSBryan Venteicher /* 897*e557c1ddSBryan Venteicher * Most drivers just ignore the return value - it only fails 898*e557c1ddSBryan Venteicher * with ENOMEM so an error is not likely. It is hard for us 899*e557c1ddSBryan Venteicher * to recover from an error here. 900*e557c1ddSBryan Venteicher */ 901*e557c1ddSBryan Venteicher error = taskqueue_start_threads(&sc->vmx_tq, nthreads, PI_NET, 902*e557c1ddSBryan Venteicher "%s taskq", device_get_nameunit(dev)); 903*e557c1ddSBryan Venteicher if (error) 904*e557c1ddSBryan Venteicher device_printf(dev, "failed to start taskqueue: %d", error); 905*e557c1ddSBryan Venteicher } 906*e557c1ddSBryan Venteicher 907*e557c1ddSBryan Venteicher static void 908*e557c1ddSBryan Venteicher vmxnet3_drain_taskqueue(struct vmxnet3_softc *sc) 909*e557c1ddSBryan Venteicher { 910*e557c1ddSBryan Venteicher struct vmxnet3_txqueue *txq; 911*e557c1ddSBryan Venteicher int i; 912*e557c1ddSBryan Venteicher 913*e557c1ddSBryan Venteicher if (sc->vmx_tq != NULL) { 914*e557c1ddSBryan Venteicher for (i = 0; i < sc->vmx_max_ntxqueues; i++) { 915*e557c1ddSBryan Venteicher txq = &sc->vmx_txq[i]; 916*e557c1ddSBryan Venteicher taskqueue_drain(sc->vmx_tq, &txq->vxtxq_defrtask); 917*e557c1ddSBryan Venteicher } 918*e557c1ddSBryan Venteicher } 919*e557c1ddSBryan Venteicher } 920*e557c1ddSBryan Venteicher 921*e557c1ddSBryan Venteicher static void 922*e557c1ddSBryan Venteicher vmxnet3_free_taskqueue(struct vmxnet3_softc *sc) 923*e557c1ddSBryan Venteicher { 924*e557c1ddSBryan Venteicher if (sc->vmx_tq != NULL) { 925*e557c1ddSBryan Venteicher taskqueue_free(sc->vmx_tq); 926*e557c1ddSBryan Venteicher sc->vmx_tq = NULL; 927*e557c1ddSBryan Venteicher } 928*e557c1ddSBryan Venteicher } 929*e557c1ddSBryan Venteicher #endif 930*e557c1ddSBryan Venteicher 931e3c97c2cSBryan Venteicher static int 932e3c97c2cSBryan Venteicher vmxnet3_init_rxq(struct vmxnet3_softc *sc, int q) 933e3c97c2cSBryan Venteicher { 934e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq; 935e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr; 936e3c97c2cSBryan Venteicher int i; 937e3c97c2cSBryan Venteicher 938e3c97c2cSBryan Venteicher rxq = &sc->vmx_rxq[q]; 939e3c97c2cSBryan Venteicher 940e3c97c2cSBryan Venteicher snprintf(rxq->vxrxq_name, sizeof(rxq->vxrxq_name), "%s-rx%d", 941e3c97c2cSBryan Venteicher device_get_nameunit(sc->vmx_dev), q); 942e3c97c2cSBryan Venteicher mtx_init(&rxq->vxrxq_mtx, rxq->vxrxq_name, NULL, MTX_DEF); 943e3c97c2cSBryan Venteicher 944e3c97c2cSBryan Venteicher rxq->vxrxq_sc = sc; 945e3c97c2cSBryan Venteicher rxq->vxrxq_id = q; 946e3c97c2cSBryan Venteicher 947e3c97c2cSBryan Venteicher for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) { 948e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i]; 949e3c97c2cSBryan Venteicher rxr->vxrxr_rid = i; 950e3c97c2cSBryan Venteicher rxr->vxrxr_ndesc = sc->vmx_nrxdescs; 951e3c97c2cSBryan Venteicher rxr->vxrxr_rxbuf = malloc(rxr->vxrxr_ndesc * 952e3c97c2cSBryan Venteicher sizeof(struct vmxnet3_rxbuf), M_DEVBUF, M_NOWAIT | M_ZERO); 953e3c97c2cSBryan Venteicher if (rxr->vxrxr_rxbuf == NULL) 954e3c97c2cSBryan Venteicher return (ENOMEM); 955e3c97c2cSBryan Venteicher 9563c965775SBryan Venteicher rxq->vxrxq_comp_ring.vxcr_ndesc += sc->vmx_nrxdescs; 9573c965775SBryan Venteicher } 958e3c97c2cSBryan Venteicher 959e3c97c2cSBryan Venteicher return (0); 960e3c97c2cSBryan Venteicher } 961e3c97c2cSBryan Venteicher 962e3c97c2cSBryan Venteicher static int 963e3c97c2cSBryan Venteicher vmxnet3_init_txq(struct vmxnet3_softc *sc, int q) 964e3c97c2cSBryan Venteicher { 965e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq; 966e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr; 967e3c97c2cSBryan Venteicher 968e3c97c2cSBryan Venteicher txq = &sc->vmx_txq[q]; 969e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 970e3c97c2cSBryan Venteicher 971e3c97c2cSBryan Venteicher snprintf(txq->vxtxq_name, sizeof(txq->vxtxq_name), "%s-tx%d", 972e3c97c2cSBryan Venteicher device_get_nameunit(sc->vmx_dev), q); 973e3c97c2cSBryan Venteicher mtx_init(&txq->vxtxq_mtx, txq->vxtxq_name, NULL, MTX_DEF); 974e3c97c2cSBryan Venteicher 975e3c97c2cSBryan Venteicher txq->vxtxq_sc = sc; 976e3c97c2cSBryan Venteicher txq->vxtxq_id = q; 977e3c97c2cSBryan Venteicher 978e3c97c2cSBryan Venteicher txr->vxtxr_ndesc = sc->vmx_ntxdescs; 979e3c97c2cSBryan Venteicher txr->vxtxr_txbuf = malloc(txr->vxtxr_ndesc * 980e3c97c2cSBryan Venteicher sizeof(struct vmxnet3_txbuf), M_DEVBUF, M_NOWAIT | M_ZERO); 981e3c97c2cSBryan Venteicher if (txr->vxtxr_txbuf == NULL) 982e3c97c2cSBryan Venteicher return (ENOMEM); 983e3c97c2cSBryan Venteicher 984e3c97c2cSBryan Venteicher txq->vxtxq_comp_ring.vxcr_ndesc = sc->vmx_ntxdescs; 985e3c97c2cSBryan Venteicher 986*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX 987*e557c1ddSBryan Venteicher TASK_INIT(&txq->vxtxq_defrtask, 0, vmxnet3_txq_tq_deferred, txq); 988*e557c1ddSBryan Venteicher 989*e557c1ddSBryan Venteicher txq->vxtxq_br = buf_ring_alloc(VMXNET3_DEF_BUFRING_SIZE, M_DEVBUF, 990*e557c1ddSBryan Venteicher M_NOWAIT, &txq->vxtxq_mtx); 991*e557c1ddSBryan Venteicher if (txq->vxtxq_br == NULL) 992*e557c1ddSBryan Venteicher return (ENOMEM); 993*e557c1ddSBryan Venteicher #endif 994*e557c1ddSBryan Venteicher 995e3c97c2cSBryan Venteicher return (0); 996e3c97c2cSBryan Venteicher } 997e3c97c2cSBryan Venteicher 998e3c97c2cSBryan Venteicher static int 999e3c97c2cSBryan Venteicher vmxnet3_alloc_rxtx_queues(struct vmxnet3_softc *sc) 1000e3c97c2cSBryan Venteicher { 1001e3c97c2cSBryan Venteicher int i, error; 1002e3c97c2cSBryan Venteicher 1003*e557c1ddSBryan Venteicher /* 1004*e557c1ddSBryan Venteicher * Only attempt to create multiple queues if MSIX is available. MSIX is 1005*e557c1ddSBryan Venteicher * disabled by default because its apparently broken for devices passed 1006*e557c1ddSBryan Venteicher * through by at least ESXi 5.1. The hw.pci.honor_msi_blacklist tunable 1007*e557c1ddSBryan Venteicher * must be set to zero for MSIX. This check prevents us from allocating 1008*e557c1ddSBryan Venteicher * queue structures that we will not use. 1009*e557c1ddSBryan Venteicher */ 1010*e557c1ddSBryan Venteicher if (sc->vmx_flags & VMXNET3_FLAG_NO_MSIX) { 1011*e557c1ddSBryan Venteicher sc->vmx_max_nrxqueues = 1; 1012*e557c1ddSBryan Venteicher sc->vmx_max_ntxqueues = 1; 1013*e557c1ddSBryan Venteicher } 1014*e557c1ddSBryan Venteicher 1015e3c97c2cSBryan Venteicher sc->vmx_rxq = malloc(sizeof(struct vmxnet3_rxqueue) * 1016*e557c1ddSBryan Venteicher sc->vmx_max_nrxqueues, M_DEVBUF, M_NOWAIT | M_ZERO); 1017e3c97c2cSBryan Venteicher sc->vmx_txq = malloc(sizeof(struct vmxnet3_txqueue) * 1018*e557c1ddSBryan Venteicher sc->vmx_max_ntxqueues, M_DEVBUF, M_NOWAIT | M_ZERO); 1019e3c97c2cSBryan Venteicher if (sc->vmx_rxq == NULL || sc->vmx_txq == NULL) 1020e3c97c2cSBryan Venteicher return (ENOMEM); 1021e3c97c2cSBryan Venteicher 1022*e557c1ddSBryan Venteicher for (i = 0; i < sc->vmx_max_nrxqueues; i++) { 1023e3c97c2cSBryan Venteicher error = vmxnet3_init_rxq(sc, i); 1024e3c97c2cSBryan Venteicher if (error) 1025e3c97c2cSBryan Venteicher return (error); 1026e3c97c2cSBryan Venteicher } 1027e3c97c2cSBryan Venteicher 1028*e557c1ddSBryan Venteicher for (i = 0; i < sc->vmx_max_ntxqueues; i++) { 1029e3c97c2cSBryan Venteicher error = vmxnet3_init_txq(sc, i); 1030e3c97c2cSBryan Venteicher if (error) 1031e3c97c2cSBryan Venteicher return (error); 1032e3c97c2cSBryan Venteicher } 1033e3c97c2cSBryan Venteicher 1034e3c97c2cSBryan Venteicher return (0); 1035e3c97c2cSBryan Venteicher } 1036e3c97c2cSBryan Venteicher 1037e3c97c2cSBryan Venteicher static void 1038e3c97c2cSBryan Venteicher vmxnet3_destroy_rxq(struct vmxnet3_rxqueue *rxq) 1039e3c97c2cSBryan Venteicher { 1040e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr; 1041e3c97c2cSBryan Venteicher int i; 1042e3c97c2cSBryan Venteicher 1043e3c97c2cSBryan Venteicher rxq->vxrxq_sc = NULL; 1044e3c97c2cSBryan Venteicher rxq->vxrxq_id = -1; 1045e3c97c2cSBryan Venteicher 1046e3c97c2cSBryan Venteicher for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) { 1047e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i]; 1048e3c97c2cSBryan Venteicher 1049e3c97c2cSBryan Venteicher if (rxr->vxrxr_rxbuf != NULL) { 1050e3c97c2cSBryan Venteicher free(rxr->vxrxr_rxbuf, M_DEVBUF); 1051e3c97c2cSBryan Venteicher rxr->vxrxr_rxbuf = NULL; 1052e3c97c2cSBryan Venteicher } 1053e3c97c2cSBryan Venteicher } 1054e3c97c2cSBryan Venteicher 1055e3c97c2cSBryan Venteicher if (mtx_initialized(&rxq->vxrxq_mtx) != 0) 1056e3c97c2cSBryan Venteicher mtx_destroy(&rxq->vxrxq_mtx); 1057e3c97c2cSBryan Venteicher } 1058e3c97c2cSBryan Venteicher 1059e3c97c2cSBryan Venteicher static void 1060e3c97c2cSBryan Venteicher vmxnet3_destroy_txq(struct vmxnet3_txqueue *txq) 1061e3c97c2cSBryan Venteicher { 1062e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr; 1063e3c97c2cSBryan Venteicher 1064e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 1065e3c97c2cSBryan Venteicher 1066e3c97c2cSBryan Venteicher txq->vxtxq_sc = NULL; 1067e3c97c2cSBryan Venteicher txq->vxtxq_id = -1; 1068e3c97c2cSBryan Venteicher 1069*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX 1070*e557c1ddSBryan Venteicher if (txq->vxtxq_br != NULL) { 1071*e557c1ddSBryan Venteicher buf_ring_free(txq->vxtxq_br, M_DEVBUF); 1072*e557c1ddSBryan Venteicher txq->vxtxq_br = NULL; 1073*e557c1ddSBryan Venteicher } 1074*e557c1ddSBryan Venteicher #endif 1075*e557c1ddSBryan Venteicher 1076e3c97c2cSBryan Venteicher if (txr->vxtxr_txbuf != NULL) { 1077e3c97c2cSBryan Venteicher free(txr->vxtxr_txbuf, M_DEVBUF); 1078e3c97c2cSBryan Venteicher txr->vxtxr_txbuf = NULL; 1079e3c97c2cSBryan Venteicher } 1080e3c97c2cSBryan Venteicher 1081e3c97c2cSBryan Venteicher if (mtx_initialized(&txq->vxtxq_mtx) != 0) 1082e3c97c2cSBryan Venteicher mtx_destroy(&txq->vxtxq_mtx); 1083e3c97c2cSBryan Venteicher } 1084e3c97c2cSBryan Venteicher 1085e3c97c2cSBryan Venteicher static void 1086e3c97c2cSBryan Venteicher vmxnet3_free_rxtx_queues(struct vmxnet3_softc *sc) 1087e3c97c2cSBryan Venteicher { 1088e3c97c2cSBryan Venteicher int i; 1089e3c97c2cSBryan Venteicher 1090e3c97c2cSBryan Venteicher if (sc->vmx_rxq != NULL) { 1091*e557c1ddSBryan Venteicher for (i = 0; i < sc->vmx_max_nrxqueues; i++) 1092e3c97c2cSBryan Venteicher vmxnet3_destroy_rxq(&sc->vmx_rxq[i]); 1093e3c97c2cSBryan Venteicher free(sc->vmx_rxq, M_DEVBUF); 1094e3c97c2cSBryan Venteicher sc->vmx_rxq = NULL; 1095e3c97c2cSBryan Venteicher } 1096e3c97c2cSBryan Venteicher 1097e3c97c2cSBryan Venteicher if (sc->vmx_txq != NULL) { 1098*e557c1ddSBryan Venteicher for (i = 0; i < sc->vmx_max_ntxqueues; i++) 1099e3c97c2cSBryan Venteicher vmxnet3_destroy_txq(&sc->vmx_txq[i]); 1100e3c97c2cSBryan Venteicher free(sc->vmx_txq, M_DEVBUF); 1101e3c97c2cSBryan Venteicher sc->vmx_txq = NULL; 1102e3c97c2cSBryan Venteicher } 1103e3c97c2cSBryan Venteicher } 1104e3c97c2cSBryan Venteicher 1105e3c97c2cSBryan Venteicher static int 1106e3c97c2cSBryan Venteicher vmxnet3_alloc_shared_data(struct vmxnet3_softc *sc) 1107e3c97c2cSBryan Venteicher { 1108e3c97c2cSBryan Venteicher device_t dev; 1109e3c97c2cSBryan Venteicher uint8_t *kva; 1110e3c97c2cSBryan Venteicher size_t size; 1111e3c97c2cSBryan Venteicher int i, error; 1112e3c97c2cSBryan Venteicher 1113e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 1114e3c97c2cSBryan Venteicher 1115e3c97c2cSBryan Venteicher size = sizeof(struct vmxnet3_driver_shared); 1116e3c97c2cSBryan Venteicher error = vmxnet3_dma_malloc(sc, size, 1, &sc->vmx_ds_dma); 1117e3c97c2cSBryan Venteicher if (error) { 1118e3c97c2cSBryan Venteicher device_printf(dev, "cannot alloc shared memory\n"); 1119e3c97c2cSBryan Venteicher return (error); 1120e3c97c2cSBryan Venteicher } 1121e3c97c2cSBryan Venteicher sc->vmx_ds = (struct vmxnet3_driver_shared *) sc->vmx_ds_dma.dma_vaddr; 1122e3c97c2cSBryan Venteicher 1123e3c97c2cSBryan Venteicher size = sc->vmx_ntxqueues * sizeof(struct vmxnet3_txq_shared) + 1124e3c97c2cSBryan Venteicher sc->vmx_nrxqueues * sizeof(struct vmxnet3_rxq_shared); 1125e3c97c2cSBryan Venteicher error = vmxnet3_dma_malloc(sc, size, 128, &sc->vmx_qs_dma); 1126e3c97c2cSBryan Venteicher if (error) { 1127e3c97c2cSBryan Venteicher device_printf(dev, "cannot alloc queue shared memory\n"); 1128e3c97c2cSBryan Venteicher return (error); 1129e3c97c2cSBryan Venteicher } 1130e3c97c2cSBryan Venteicher sc->vmx_qs = (void *) sc->vmx_qs_dma.dma_vaddr; 1131e3c97c2cSBryan Venteicher kva = sc->vmx_qs; 1132e3c97c2cSBryan Venteicher 1133e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++) { 1134e3c97c2cSBryan Venteicher sc->vmx_txq[i].vxtxq_ts = (struct vmxnet3_txq_shared *) kva; 1135e3c97c2cSBryan Venteicher kva += sizeof(struct vmxnet3_txq_shared); 1136e3c97c2cSBryan Venteicher } 1137e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nrxqueues; i++) { 1138e3c97c2cSBryan Venteicher sc->vmx_rxq[i].vxrxq_rs = (struct vmxnet3_rxq_shared *) kva; 1139e3c97c2cSBryan Venteicher kva += sizeof(struct vmxnet3_rxq_shared); 1140e3c97c2cSBryan Venteicher } 1141e3c97c2cSBryan Venteicher 1142*e557c1ddSBryan Venteicher if (sc->vmx_flags & VMXNET3_FLAG_RSS) { 1143*e557c1ddSBryan Venteicher size = sizeof(struct vmxnet3_rss_shared); 1144*e557c1ddSBryan Venteicher error = vmxnet3_dma_malloc(sc, size, 128, &sc->vmx_rss_dma); 1145*e557c1ddSBryan Venteicher if (error) { 1146*e557c1ddSBryan Venteicher device_printf(dev, "cannot alloc rss shared memory\n"); 1147*e557c1ddSBryan Venteicher return (error); 1148*e557c1ddSBryan Venteicher } 1149*e557c1ddSBryan Venteicher sc->vmx_rss = 1150*e557c1ddSBryan Venteicher (struct vmxnet3_rss_shared *) sc->vmx_rss_dma.dma_vaddr; 1151*e557c1ddSBryan Venteicher } 1152*e557c1ddSBryan Venteicher 1153e3c97c2cSBryan Venteicher return (0); 1154e3c97c2cSBryan Venteicher } 1155e3c97c2cSBryan Venteicher 1156e3c97c2cSBryan Venteicher static void 1157e3c97c2cSBryan Venteicher vmxnet3_free_shared_data(struct vmxnet3_softc *sc) 1158e3c97c2cSBryan Venteicher { 1159e3c97c2cSBryan Venteicher 1160*e557c1ddSBryan Venteicher if (sc->vmx_rss != NULL) { 1161*e557c1ddSBryan Venteicher vmxnet3_dma_free(sc, &sc->vmx_rss_dma); 1162*e557c1ddSBryan Venteicher sc->vmx_rss = NULL; 1163*e557c1ddSBryan Venteicher } 1164*e557c1ddSBryan Venteicher 1165e3c97c2cSBryan Venteicher if (sc->vmx_qs != NULL) { 1166e3c97c2cSBryan Venteicher vmxnet3_dma_free(sc, &sc->vmx_qs_dma); 1167e3c97c2cSBryan Venteicher sc->vmx_qs = NULL; 1168e3c97c2cSBryan Venteicher } 1169e3c97c2cSBryan Venteicher 1170e3c97c2cSBryan Venteicher if (sc->vmx_ds != NULL) { 1171e3c97c2cSBryan Venteicher vmxnet3_dma_free(sc, &sc->vmx_ds_dma); 1172e3c97c2cSBryan Venteicher sc->vmx_ds = NULL; 1173e3c97c2cSBryan Venteicher } 1174e3c97c2cSBryan Venteicher } 1175e3c97c2cSBryan Venteicher 1176e3c97c2cSBryan Venteicher static int 1177e3c97c2cSBryan Venteicher vmxnet3_alloc_txq_data(struct vmxnet3_softc *sc) 1178e3c97c2cSBryan Venteicher { 1179e3c97c2cSBryan Venteicher device_t dev; 1180e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq; 1181e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr; 1182e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *txc; 1183e3c97c2cSBryan Venteicher size_t descsz, compsz; 1184e3c97c2cSBryan Venteicher int i, q, error; 1185e3c97c2cSBryan Venteicher 1186e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 1187e3c97c2cSBryan Venteicher 1188e3c97c2cSBryan Venteicher for (q = 0; q < sc->vmx_ntxqueues; q++) { 1189e3c97c2cSBryan Venteicher txq = &sc->vmx_txq[q]; 1190e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 1191e3c97c2cSBryan Venteicher txc = &txq->vxtxq_comp_ring; 1192e3c97c2cSBryan Venteicher 1193e3c97c2cSBryan Venteicher descsz = txr->vxtxr_ndesc * sizeof(struct vmxnet3_txdesc); 1194e3c97c2cSBryan Venteicher compsz = txr->vxtxr_ndesc * sizeof(struct vmxnet3_txcompdesc); 1195e3c97c2cSBryan Venteicher 1196e3c97c2cSBryan Venteicher error = bus_dma_tag_create(bus_get_dma_tag(dev), 1197e3c97c2cSBryan Venteicher 1, 0, /* alignment, boundary */ 1198e3c97c2cSBryan Venteicher BUS_SPACE_MAXADDR, /* lowaddr */ 1199e3c97c2cSBryan Venteicher BUS_SPACE_MAXADDR, /* highaddr */ 1200e3c97c2cSBryan Venteicher NULL, NULL, /* filter, filterarg */ 1201*e557c1ddSBryan Venteicher VMXNET3_TX_MAXSIZE, /* maxsize */ 1202e3c97c2cSBryan Venteicher VMXNET3_TX_MAXSEGS, /* nsegments */ 1203e3c97c2cSBryan Venteicher VMXNET3_TX_MAXSEGSIZE, /* maxsegsize */ 1204e3c97c2cSBryan Venteicher 0, /* flags */ 1205e3c97c2cSBryan Venteicher NULL, NULL, /* lockfunc, lockarg */ 1206e3c97c2cSBryan Venteicher &txr->vxtxr_txtag); 1207e3c97c2cSBryan Venteicher if (error) { 1208e3c97c2cSBryan Venteicher device_printf(dev, 1209e3c97c2cSBryan Venteicher "unable to create Tx buffer tag for queue %d\n", q); 1210e3c97c2cSBryan Venteicher return (error); 1211e3c97c2cSBryan Venteicher } 1212e3c97c2cSBryan Venteicher 1213e3c97c2cSBryan Venteicher error = vmxnet3_dma_malloc(sc, descsz, 512, &txr->vxtxr_dma); 1214e3c97c2cSBryan Venteicher if (error) { 1215e3c97c2cSBryan Venteicher device_printf(dev, "cannot alloc Tx descriptors for " 1216e3c97c2cSBryan Venteicher "queue %d error %d\n", q, error); 1217e3c97c2cSBryan Venteicher return (error); 1218e3c97c2cSBryan Venteicher } 1219e3c97c2cSBryan Venteicher txr->vxtxr_txd = 1220e3c97c2cSBryan Venteicher (struct vmxnet3_txdesc *) txr->vxtxr_dma.dma_vaddr; 1221e3c97c2cSBryan Venteicher 1222e3c97c2cSBryan Venteicher error = vmxnet3_dma_malloc(sc, compsz, 512, &txc->vxcr_dma); 1223e3c97c2cSBryan Venteicher if (error) { 1224e3c97c2cSBryan Venteicher device_printf(dev, "cannot alloc Tx comp descriptors " 1225e3c97c2cSBryan Venteicher "for queue %d error %d\n", q, error); 1226e3c97c2cSBryan Venteicher return (error); 1227e3c97c2cSBryan Venteicher } 1228e3c97c2cSBryan Venteicher txc->vxcr_u.txcd = 1229e3c97c2cSBryan Venteicher (struct vmxnet3_txcompdesc *) txc->vxcr_dma.dma_vaddr; 1230e3c97c2cSBryan Venteicher 1231e3c97c2cSBryan Venteicher for (i = 0; i < txr->vxtxr_ndesc; i++) { 1232e3c97c2cSBryan Venteicher error = bus_dmamap_create(txr->vxtxr_txtag, 0, 1233e3c97c2cSBryan Venteicher &txr->vxtxr_txbuf[i].vtxb_dmamap); 1234e3c97c2cSBryan Venteicher if (error) { 1235e3c97c2cSBryan Venteicher device_printf(dev, "unable to create Tx buf " 1236e3c97c2cSBryan Venteicher "dmamap for queue %d idx %d\n", q, i); 1237e3c97c2cSBryan Venteicher return (error); 1238e3c97c2cSBryan Venteicher } 1239e3c97c2cSBryan Venteicher } 1240e3c97c2cSBryan Venteicher } 1241e3c97c2cSBryan Venteicher 1242e3c97c2cSBryan Venteicher return (0); 1243e3c97c2cSBryan Venteicher } 1244e3c97c2cSBryan Venteicher 1245e3c97c2cSBryan Venteicher static void 1246e3c97c2cSBryan Venteicher vmxnet3_free_txq_data(struct vmxnet3_softc *sc) 1247e3c97c2cSBryan Venteicher { 1248e3c97c2cSBryan Venteicher device_t dev; 1249e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq; 1250e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr; 1251e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *txc; 1252e3c97c2cSBryan Venteicher struct vmxnet3_txbuf *txb; 1253e3c97c2cSBryan Venteicher int i, q; 1254e3c97c2cSBryan Venteicher 1255e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 1256e3c97c2cSBryan Venteicher 1257e3c97c2cSBryan Venteicher for (q = 0; q < sc->vmx_ntxqueues; q++) { 1258e3c97c2cSBryan Venteicher txq = &sc->vmx_txq[q]; 1259e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 1260e3c97c2cSBryan Venteicher txc = &txq->vxtxq_comp_ring; 1261e3c97c2cSBryan Venteicher 1262e3c97c2cSBryan Venteicher for (i = 0; i < txr->vxtxr_ndesc; i++) { 1263e3c97c2cSBryan Venteicher txb = &txr->vxtxr_txbuf[i]; 1264e3c97c2cSBryan Venteicher if (txb->vtxb_dmamap != NULL) { 1265e3c97c2cSBryan Venteicher bus_dmamap_destroy(txr->vxtxr_txtag, 1266e3c97c2cSBryan Venteicher txb->vtxb_dmamap); 1267e3c97c2cSBryan Venteicher txb->vtxb_dmamap = NULL; 1268e3c97c2cSBryan Venteicher } 1269e3c97c2cSBryan Venteicher } 1270e3c97c2cSBryan Venteicher 1271e3c97c2cSBryan Venteicher if (txc->vxcr_u.txcd != NULL) { 1272e3c97c2cSBryan Venteicher vmxnet3_dma_free(sc, &txc->vxcr_dma); 1273e3c97c2cSBryan Venteicher txc->vxcr_u.txcd = NULL; 1274e3c97c2cSBryan Venteicher } 1275e3c97c2cSBryan Venteicher 1276e3c97c2cSBryan Venteicher if (txr->vxtxr_txd != NULL) { 1277e3c97c2cSBryan Venteicher vmxnet3_dma_free(sc, &txr->vxtxr_dma); 1278e3c97c2cSBryan Venteicher txr->vxtxr_txd = NULL; 1279e3c97c2cSBryan Venteicher } 1280e3c97c2cSBryan Venteicher 1281e3c97c2cSBryan Venteicher if (txr->vxtxr_txtag != NULL) { 1282e3c97c2cSBryan Venteicher bus_dma_tag_destroy(txr->vxtxr_txtag); 1283e3c97c2cSBryan Venteicher txr->vxtxr_txtag = NULL; 1284e3c97c2cSBryan Venteicher } 1285e3c97c2cSBryan Venteicher } 1286e3c97c2cSBryan Venteicher } 1287e3c97c2cSBryan Venteicher 1288e3c97c2cSBryan Venteicher static int 1289e3c97c2cSBryan Venteicher vmxnet3_alloc_rxq_data(struct vmxnet3_softc *sc) 1290e3c97c2cSBryan Venteicher { 1291e3c97c2cSBryan Venteicher device_t dev; 1292e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq; 1293e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr; 1294e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *rxc; 1295e3c97c2cSBryan Venteicher int descsz, compsz; 1296e3c97c2cSBryan Venteicher int i, j, q, error; 1297e3c97c2cSBryan Venteicher 1298e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 1299e3c97c2cSBryan Venteicher 1300e3c97c2cSBryan Venteicher for (q = 0; q < sc->vmx_nrxqueues; q++) { 1301e3c97c2cSBryan Venteicher rxq = &sc->vmx_rxq[q]; 1302e3c97c2cSBryan Venteicher rxc = &rxq->vxrxq_comp_ring; 1303e3c97c2cSBryan Venteicher compsz = 0; 1304e3c97c2cSBryan Venteicher 1305e3c97c2cSBryan Venteicher for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) { 1306e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i]; 1307e3c97c2cSBryan Venteicher 1308e3c97c2cSBryan Venteicher descsz = rxr->vxrxr_ndesc * 1309e3c97c2cSBryan Venteicher sizeof(struct vmxnet3_rxdesc); 1310e3c97c2cSBryan Venteicher compsz += rxr->vxrxr_ndesc * 1311e3c97c2cSBryan Venteicher sizeof(struct vmxnet3_rxcompdesc); 1312e3c97c2cSBryan Venteicher 1313e3c97c2cSBryan Venteicher error = bus_dma_tag_create(bus_get_dma_tag(dev), 1314e3c97c2cSBryan Venteicher 1, 0, /* alignment, boundary */ 1315e3c97c2cSBryan Venteicher BUS_SPACE_MAXADDR, /* lowaddr */ 1316e3c97c2cSBryan Venteicher BUS_SPACE_MAXADDR, /* highaddr */ 1317e3c97c2cSBryan Venteicher NULL, NULL, /* filter, filterarg */ 1318e3c97c2cSBryan Venteicher MJUMPAGESIZE, /* maxsize */ 1319e3c97c2cSBryan Venteicher 1, /* nsegments */ 1320e3c97c2cSBryan Venteicher MJUMPAGESIZE, /* maxsegsize */ 1321e3c97c2cSBryan Venteicher 0, /* flags */ 1322e3c97c2cSBryan Venteicher NULL, NULL, /* lockfunc, lockarg */ 1323e3c97c2cSBryan Venteicher &rxr->vxrxr_rxtag); 1324e3c97c2cSBryan Venteicher if (error) { 1325e3c97c2cSBryan Venteicher device_printf(dev, 1326e3c97c2cSBryan Venteicher "unable to create Rx buffer tag for " 1327e3c97c2cSBryan Venteicher "queue %d\n", q); 1328e3c97c2cSBryan Venteicher return (error); 1329e3c97c2cSBryan Venteicher } 1330e3c97c2cSBryan Venteicher 1331e3c97c2cSBryan Venteicher error = vmxnet3_dma_malloc(sc, descsz, 512, 1332e3c97c2cSBryan Venteicher &rxr->vxrxr_dma); 1333e3c97c2cSBryan Venteicher if (error) { 1334e3c97c2cSBryan Venteicher device_printf(dev, "cannot allocate Rx " 1335e3c97c2cSBryan Venteicher "descriptors for queue %d/%d error %d\n", 1336e3c97c2cSBryan Venteicher i, q, error); 1337e3c97c2cSBryan Venteicher return (error); 1338e3c97c2cSBryan Venteicher } 1339e3c97c2cSBryan Venteicher rxr->vxrxr_rxd = 1340e3c97c2cSBryan Venteicher (struct vmxnet3_rxdesc *) rxr->vxrxr_dma.dma_vaddr; 1341e3c97c2cSBryan Venteicher } 1342e3c97c2cSBryan Venteicher 1343e3c97c2cSBryan Venteicher error = vmxnet3_dma_malloc(sc, compsz, 512, &rxc->vxcr_dma); 1344e3c97c2cSBryan Venteicher if (error) { 1345e3c97c2cSBryan Venteicher device_printf(dev, "cannot alloc Rx comp descriptors " 1346e3c97c2cSBryan Venteicher "for queue %d error %d\n", q, error); 1347e3c97c2cSBryan Venteicher return (error); 1348e3c97c2cSBryan Venteicher } 1349e3c97c2cSBryan Venteicher rxc->vxcr_u.rxcd = 1350e3c97c2cSBryan Venteicher (struct vmxnet3_rxcompdesc *) rxc->vxcr_dma.dma_vaddr; 1351e3c97c2cSBryan Venteicher 1352e3c97c2cSBryan Venteicher for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) { 1353e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i]; 1354e3c97c2cSBryan Venteicher 1355e3c97c2cSBryan Venteicher error = bus_dmamap_create(rxr->vxrxr_rxtag, 0, 1356e3c97c2cSBryan Venteicher &rxr->vxrxr_spare_dmap); 1357e3c97c2cSBryan Venteicher if (error) { 1358e3c97c2cSBryan Venteicher device_printf(dev, "unable to create spare " 1359e3c97c2cSBryan Venteicher "dmamap for queue %d/%d error %d\n", 1360e3c97c2cSBryan Venteicher q, i, error); 1361e3c97c2cSBryan Venteicher return (error); 1362e3c97c2cSBryan Venteicher } 1363e3c97c2cSBryan Venteicher 1364e3c97c2cSBryan Venteicher for (j = 0; j < rxr->vxrxr_ndesc; j++) { 1365e3c97c2cSBryan Venteicher error = bus_dmamap_create(rxr->vxrxr_rxtag, 0, 1366e3c97c2cSBryan Venteicher &rxr->vxrxr_rxbuf[j].vrxb_dmamap); 1367e3c97c2cSBryan Venteicher if (error) { 1368e3c97c2cSBryan Venteicher device_printf(dev, "unable to create " 1369e3c97c2cSBryan Venteicher "dmamap for queue %d/%d slot %d " 1370e3c97c2cSBryan Venteicher "error %d\n", 1371e3c97c2cSBryan Venteicher q, i, j, error); 1372e3c97c2cSBryan Venteicher return (error); 1373e3c97c2cSBryan Venteicher } 1374e3c97c2cSBryan Venteicher } 1375e3c97c2cSBryan Venteicher } 1376e3c97c2cSBryan Venteicher } 1377e3c97c2cSBryan Venteicher 1378e3c97c2cSBryan Venteicher return (0); 1379e3c97c2cSBryan Venteicher } 1380e3c97c2cSBryan Venteicher 1381e3c97c2cSBryan Venteicher static void 1382e3c97c2cSBryan Venteicher vmxnet3_free_rxq_data(struct vmxnet3_softc *sc) 1383e3c97c2cSBryan Venteicher { 1384e3c97c2cSBryan Venteicher device_t dev; 1385e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq; 1386e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr; 1387e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *rxc; 1388e3c97c2cSBryan Venteicher struct vmxnet3_rxbuf *rxb; 1389e3c97c2cSBryan Venteicher int i, j, q; 1390e3c97c2cSBryan Venteicher 1391e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 1392e3c97c2cSBryan Venteicher 1393e3c97c2cSBryan Venteicher for (q = 0; q < sc->vmx_nrxqueues; q++) { 1394e3c97c2cSBryan Venteicher rxq = &sc->vmx_rxq[q]; 1395e3c97c2cSBryan Venteicher rxc = &rxq->vxrxq_comp_ring; 1396e3c97c2cSBryan Venteicher 1397e3c97c2cSBryan Venteicher for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) { 1398e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i]; 1399e3c97c2cSBryan Venteicher 1400e3c97c2cSBryan Venteicher if (rxr->vxrxr_spare_dmap != NULL) { 1401e3c97c2cSBryan Venteicher bus_dmamap_destroy(rxr->vxrxr_rxtag, 1402e3c97c2cSBryan Venteicher rxr->vxrxr_spare_dmap); 1403e3c97c2cSBryan Venteicher rxr->vxrxr_spare_dmap = NULL; 1404e3c97c2cSBryan Venteicher } 1405e3c97c2cSBryan Venteicher 1406e3c97c2cSBryan Venteicher for (j = 0; j < rxr->vxrxr_ndesc; j++) { 1407e3c97c2cSBryan Venteicher rxb = &rxr->vxrxr_rxbuf[j]; 1408e3c97c2cSBryan Venteicher if (rxb->vrxb_dmamap != NULL) { 1409e3c97c2cSBryan Venteicher bus_dmamap_destroy(rxr->vxrxr_rxtag, 1410e3c97c2cSBryan Venteicher rxb->vrxb_dmamap); 1411e3c97c2cSBryan Venteicher rxb->vrxb_dmamap = NULL; 1412e3c97c2cSBryan Venteicher } 1413e3c97c2cSBryan Venteicher } 1414e3c97c2cSBryan Venteicher } 1415e3c97c2cSBryan Venteicher 1416e3c97c2cSBryan Venteicher if (rxc->vxcr_u.rxcd != NULL) { 1417e3c97c2cSBryan Venteicher vmxnet3_dma_free(sc, &rxc->vxcr_dma); 1418e3c97c2cSBryan Venteicher rxc->vxcr_u.rxcd = NULL; 1419e3c97c2cSBryan Venteicher } 1420e3c97c2cSBryan Venteicher 1421e3c97c2cSBryan Venteicher for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) { 1422e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i]; 1423e3c97c2cSBryan Venteicher 1424e3c97c2cSBryan Venteicher if (rxr->vxrxr_rxd != NULL) { 1425e3c97c2cSBryan Venteicher vmxnet3_dma_free(sc, &rxr->vxrxr_dma); 1426e3c97c2cSBryan Venteicher rxr->vxrxr_rxd = NULL; 1427e3c97c2cSBryan Venteicher } 1428e3c97c2cSBryan Venteicher 1429e3c97c2cSBryan Venteicher if (rxr->vxrxr_rxtag != NULL) { 1430e3c97c2cSBryan Venteicher bus_dma_tag_destroy(rxr->vxrxr_rxtag); 1431e3c97c2cSBryan Venteicher rxr->vxrxr_rxtag = NULL; 1432e3c97c2cSBryan Venteicher } 1433e3c97c2cSBryan Venteicher } 1434e3c97c2cSBryan Venteicher } 1435e3c97c2cSBryan Venteicher } 1436e3c97c2cSBryan Venteicher 1437e3c97c2cSBryan Venteicher static int 1438e3c97c2cSBryan Venteicher vmxnet3_alloc_queue_data(struct vmxnet3_softc *sc) 1439e3c97c2cSBryan Venteicher { 1440e3c97c2cSBryan Venteicher int error; 1441e3c97c2cSBryan Venteicher 1442e3c97c2cSBryan Venteicher error = vmxnet3_alloc_txq_data(sc); 1443e3c97c2cSBryan Venteicher if (error) 1444e3c97c2cSBryan Venteicher return (error); 1445e3c97c2cSBryan Venteicher 1446e3c97c2cSBryan Venteicher error = vmxnet3_alloc_rxq_data(sc); 1447e3c97c2cSBryan Venteicher if (error) 1448e3c97c2cSBryan Venteicher return (error); 1449e3c97c2cSBryan Venteicher 1450e3c97c2cSBryan Venteicher return (0); 1451e3c97c2cSBryan Venteicher } 1452e3c97c2cSBryan Venteicher 1453e3c97c2cSBryan Venteicher static void 1454e3c97c2cSBryan Venteicher vmxnet3_free_queue_data(struct vmxnet3_softc *sc) 1455e3c97c2cSBryan Venteicher { 1456e3c97c2cSBryan Venteicher 14573c965775SBryan Venteicher if (sc->vmx_rxq != NULL) 1458e3c97c2cSBryan Venteicher vmxnet3_free_rxq_data(sc); 14593c965775SBryan Venteicher 14603c965775SBryan Venteicher if (sc->vmx_txq != NULL) 1461e3c97c2cSBryan Venteicher vmxnet3_free_txq_data(sc); 1462e3c97c2cSBryan Venteicher } 1463e3c97c2cSBryan Venteicher 1464e3c97c2cSBryan Venteicher static int 1465e3c97c2cSBryan Venteicher vmxnet3_alloc_mcast_table(struct vmxnet3_softc *sc) 1466e3c97c2cSBryan Venteicher { 1467e3c97c2cSBryan Venteicher int error; 1468e3c97c2cSBryan Venteicher 1469e3c97c2cSBryan Venteicher error = vmxnet3_dma_malloc(sc, VMXNET3_MULTICAST_MAX * ETHER_ADDR_LEN, 1470e3c97c2cSBryan Venteicher 32, &sc->vmx_mcast_dma); 1471e3c97c2cSBryan Venteicher if (error) 1472e3c97c2cSBryan Venteicher device_printf(sc->vmx_dev, "unable to alloc multicast table\n"); 1473e3c97c2cSBryan Venteicher else 1474e3c97c2cSBryan Venteicher sc->vmx_mcast = sc->vmx_mcast_dma.dma_vaddr; 1475e3c97c2cSBryan Venteicher 1476e3c97c2cSBryan Venteicher return (error); 1477e3c97c2cSBryan Venteicher } 1478e3c97c2cSBryan Venteicher 1479e3c97c2cSBryan Venteicher static void 1480e3c97c2cSBryan Venteicher vmxnet3_free_mcast_table(struct vmxnet3_softc *sc) 1481e3c97c2cSBryan Venteicher { 1482e3c97c2cSBryan Venteicher 1483e3c97c2cSBryan Venteicher if (sc->vmx_mcast != NULL) { 1484e3c97c2cSBryan Venteicher vmxnet3_dma_free(sc, &sc->vmx_mcast_dma); 1485e3c97c2cSBryan Venteicher sc->vmx_mcast = NULL; 1486e3c97c2cSBryan Venteicher } 1487e3c97c2cSBryan Venteicher } 1488e3c97c2cSBryan Venteicher 1489e3c97c2cSBryan Venteicher static void 1490e3c97c2cSBryan Venteicher vmxnet3_init_shared_data(struct vmxnet3_softc *sc) 1491e3c97c2cSBryan Venteicher { 1492e3c97c2cSBryan Venteicher struct vmxnet3_driver_shared *ds; 1493e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq; 1494e3c97c2cSBryan Venteicher struct vmxnet3_txq_shared *txs; 1495e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq; 1496e3c97c2cSBryan Venteicher struct vmxnet3_rxq_shared *rxs; 1497e3c97c2cSBryan Venteicher int i; 1498e3c97c2cSBryan Venteicher 1499e3c97c2cSBryan Venteicher ds = sc->vmx_ds; 1500e3c97c2cSBryan Venteicher 1501e3c97c2cSBryan Venteicher /* 1502e3c97c2cSBryan Venteicher * Initialize fields of the shared data that remains the same across 1503e3c97c2cSBryan Venteicher * reinits. Note the shared data is zero'd when allocated. 1504e3c97c2cSBryan Venteicher */ 1505e3c97c2cSBryan Venteicher 1506e3c97c2cSBryan Venteicher ds->magic = VMXNET3_REV1_MAGIC; 1507e3c97c2cSBryan Venteicher 1508e3c97c2cSBryan Venteicher /* DriverInfo */ 1509e3c97c2cSBryan Venteicher ds->version = VMXNET3_DRIVER_VERSION; 1510ce3be286SBryan Venteicher ds->guest = VMXNET3_GOS_FREEBSD | 1511e3c97c2cSBryan Venteicher #ifdef __LP64__ 1512e3c97c2cSBryan Venteicher VMXNET3_GOS_64BIT; 1513e3c97c2cSBryan Venteicher #else 1514e3c97c2cSBryan Venteicher VMXNET3_GOS_32BIT; 1515e3c97c2cSBryan Venteicher #endif 1516e3c97c2cSBryan Venteicher ds->vmxnet3_revision = 1; 1517e3c97c2cSBryan Venteicher ds->upt_version = 1; 1518e3c97c2cSBryan Venteicher 1519e3c97c2cSBryan Venteicher /* Misc. conf */ 1520e3c97c2cSBryan Venteicher ds->driver_data = vtophys(sc); 1521e3c97c2cSBryan Venteicher ds->driver_data_len = sizeof(struct vmxnet3_softc); 1522e3c97c2cSBryan Venteicher ds->queue_shared = sc->vmx_qs_dma.dma_paddr; 1523e3c97c2cSBryan Venteicher ds->queue_shared_len = sc->vmx_qs_dma.dma_size; 1524e3c97c2cSBryan Venteicher ds->nrxsg_max = sc->vmx_max_rxsegs; 1525e3c97c2cSBryan Venteicher 1526*e557c1ddSBryan Venteicher /* RSS conf */ 1527*e557c1ddSBryan Venteicher if (sc->vmx_flags & VMXNET3_FLAG_RSS) { 1528*e557c1ddSBryan Venteicher ds->rss.version = 1; 1529*e557c1ddSBryan Venteicher ds->rss.paddr = sc->vmx_rss_dma.dma_paddr; 1530*e557c1ddSBryan Venteicher ds->rss.len = sc->vmx_rss_dma.dma_size; 1531*e557c1ddSBryan Venteicher } 1532*e557c1ddSBryan Venteicher 1533e3c97c2cSBryan Venteicher /* Interrupt control. */ 1534e3c97c2cSBryan Venteicher ds->automask = sc->vmx_intr_mask_mode == VMXNET3_IMM_AUTO; 1535e3c97c2cSBryan Venteicher ds->nintr = sc->vmx_nintrs; 1536e3c97c2cSBryan Venteicher ds->evintr = sc->vmx_event_intr_idx; 1537e3c97c2cSBryan Venteicher ds->ictrl = VMXNET3_ICTRL_DISABLE_ALL; 1538e3c97c2cSBryan Venteicher 1539e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nintrs; i++) 1540e3c97c2cSBryan Venteicher ds->modlevel[i] = UPT1_IMOD_ADAPTIVE; 1541e3c97c2cSBryan Venteicher 1542e3c97c2cSBryan Venteicher /* Receive filter. */ 1543e3c97c2cSBryan Venteicher ds->mcast_table = sc->vmx_mcast_dma.dma_paddr; 1544e3c97c2cSBryan Venteicher ds->mcast_tablelen = sc->vmx_mcast_dma.dma_size; 1545e3c97c2cSBryan Venteicher 1546e3c97c2cSBryan Venteicher /* Tx queues */ 1547e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++) { 1548e3c97c2cSBryan Venteicher txq = &sc->vmx_txq[i]; 1549e3c97c2cSBryan Venteicher txs = txq->vxtxq_ts; 1550e3c97c2cSBryan Venteicher 1551e3c97c2cSBryan Venteicher txs->cmd_ring = txq->vxtxq_cmd_ring.vxtxr_dma.dma_paddr; 15523c965775SBryan Venteicher txs->cmd_ring_len = txq->vxtxq_cmd_ring.vxtxr_ndesc; 1553e3c97c2cSBryan Venteicher txs->comp_ring = txq->vxtxq_comp_ring.vxcr_dma.dma_paddr; 15543c965775SBryan Venteicher txs->comp_ring_len = txq->vxtxq_comp_ring.vxcr_ndesc; 1555e3c97c2cSBryan Venteicher txs->driver_data = vtophys(txq); 1556e3c97c2cSBryan Venteicher txs->driver_data_len = sizeof(struct vmxnet3_txqueue); 1557e3c97c2cSBryan Venteicher } 1558e3c97c2cSBryan Venteicher 1559e3c97c2cSBryan Venteicher /* Rx queues */ 1560e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nrxqueues; i++) { 1561e3c97c2cSBryan Venteicher rxq = &sc->vmx_rxq[i]; 1562e3c97c2cSBryan Venteicher rxs = rxq->vxrxq_rs; 1563e3c97c2cSBryan Venteicher 1564e3c97c2cSBryan Venteicher rxs->cmd_ring[0] = rxq->vxrxq_cmd_ring[0].vxrxr_dma.dma_paddr; 1565e3c97c2cSBryan Venteicher rxs->cmd_ring_len[0] = rxq->vxrxq_cmd_ring[0].vxrxr_ndesc; 1566e3c97c2cSBryan Venteicher rxs->cmd_ring[1] = rxq->vxrxq_cmd_ring[1].vxrxr_dma.dma_paddr; 1567e3c97c2cSBryan Venteicher rxs->cmd_ring_len[1] = rxq->vxrxq_cmd_ring[1].vxrxr_ndesc; 1568e3c97c2cSBryan Venteicher rxs->comp_ring = rxq->vxrxq_comp_ring.vxcr_dma.dma_paddr; 15693c965775SBryan Venteicher rxs->comp_ring_len = rxq->vxrxq_comp_ring.vxcr_ndesc; 1570e3c97c2cSBryan Venteicher rxs->driver_data = vtophys(rxq); 1571e3c97c2cSBryan Venteicher rxs->driver_data_len = sizeof(struct vmxnet3_rxqueue); 1572e3c97c2cSBryan Venteicher } 1573e3c97c2cSBryan Venteicher } 1574e3c97c2cSBryan Venteicher 1575e3c97c2cSBryan Venteicher static void 1576e3c97c2cSBryan Venteicher vmxnet3_reinit_interface(struct vmxnet3_softc *sc) 1577e3c97c2cSBryan Venteicher { 1578e3c97c2cSBryan Venteicher struct ifnet *ifp; 1579e3c97c2cSBryan Venteicher 1580e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 1581e3c97c2cSBryan Venteicher 1582e3c97c2cSBryan Venteicher /* Use the current MAC address. */ 1583e3c97c2cSBryan Venteicher bcopy(IF_LLADDR(sc->vmx_ifp), sc->vmx_lladdr, ETHER_ADDR_LEN); 1584e3c97c2cSBryan Venteicher vmxnet3_set_lladdr(sc); 1585e3c97c2cSBryan Venteicher 1586e3c97c2cSBryan Venteicher ifp->if_hwassist = 0; 1587e3c97c2cSBryan Venteicher if (ifp->if_capenable & IFCAP_TXCSUM) 1588e3c97c2cSBryan Venteicher ifp->if_hwassist |= VMXNET3_CSUM_OFFLOAD; 1589e3c97c2cSBryan Venteicher if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 1590e3c97c2cSBryan Venteicher ifp->if_hwassist |= VMXNET3_CSUM_OFFLOAD_IPV6; 1591e3c97c2cSBryan Venteicher if (ifp->if_capenable & IFCAP_TSO4) 1592*e557c1ddSBryan Venteicher ifp->if_hwassist |= CSUM_IP_TSO; 1593e3c97c2cSBryan Venteicher if (ifp->if_capenable & IFCAP_TSO6) 1594*e557c1ddSBryan Venteicher ifp->if_hwassist |= CSUM_IP6_TSO; 1595*e557c1ddSBryan Venteicher } 1596*e557c1ddSBryan Venteicher 1597*e557c1ddSBryan Venteicher static void 1598*e557c1ddSBryan Venteicher vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *sc) 1599*e557c1ddSBryan Venteicher { 1600*e557c1ddSBryan Venteicher /* 1601*e557c1ddSBryan Venteicher * Use the same key as the Linux driver until FreeBSD can do 1602*e557c1ddSBryan Venteicher * RSS (presumably Toeplitz) in software. 1603*e557c1ddSBryan Venteicher */ 1604*e557c1ddSBryan Venteicher static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = { 1605*e557c1ddSBryan Venteicher 0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac, 1606*e557c1ddSBryan Venteicher 0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28, 1607*e557c1ddSBryan Venteicher 0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70, 1608*e557c1ddSBryan Venteicher 0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3, 1609*e557c1ddSBryan Venteicher 0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9, 1610*e557c1ddSBryan Venteicher }; 1611*e557c1ddSBryan Venteicher 1612*e557c1ddSBryan Venteicher struct vmxnet3_driver_shared *ds; 1613*e557c1ddSBryan Venteicher struct vmxnet3_rss_shared *rss; 1614*e557c1ddSBryan Venteicher int i; 1615*e557c1ddSBryan Venteicher 1616*e557c1ddSBryan Venteicher ds = sc->vmx_ds; 1617*e557c1ddSBryan Venteicher rss = sc->vmx_rss; 1618*e557c1ddSBryan Venteicher 1619*e557c1ddSBryan Venteicher rss->hash_type = 1620*e557c1ddSBryan Venteicher UPT1_RSS_HASH_TYPE_IPV4 | UPT1_RSS_HASH_TYPE_TCP_IPV4 | 1621*e557c1ddSBryan Venteicher UPT1_RSS_HASH_TYPE_IPV6 | UPT1_RSS_HASH_TYPE_TCP_IPV6; 1622*e557c1ddSBryan Venteicher rss->hash_func = UPT1_RSS_HASH_FUNC_TOEPLITZ; 1623*e557c1ddSBryan Venteicher rss->hash_key_size = UPT1_RSS_MAX_KEY_SIZE; 1624*e557c1ddSBryan Venteicher rss->ind_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE; 1625*e557c1ddSBryan Venteicher memcpy(rss->hash_key, rss_key, UPT1_RSS_MAX_KEY_SIZE); 1626*e557c1ddSBryan Venteicher 1627*e557c1ddSBryan Venteicher for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++) 1628*e557c1ddSBryan Venteicher rss->ind_table[i] = i % sc->vmx_nrxqueues; 1629e3c97c2cSBryan Venteicher } 1630e3c97c2cSBryan Venteicher 1631e3c97c2cSBryan Venteicher static void 1632e3c97c2cSBryan Venteicher vmxnet3_reinit_shared_data(struct vmxnet3_softc *sc) 1633e3c97c2cSBryan Venteicher { 1634e3c97c2cSBryan Venteicher struct ifnet *ifp; 1635e3c97c2cSBryan Venteicher struct vmxnet3_driver_shared *ds; 1636e3c97c2cSBryan Venteicher 1637e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 1638e3c97c2cSBryan Venteicher ds = sc->vmx_ds; 1639e3c97c2cSBryan Venteicher 1640*e557c1ddSBryan Venteicher ds->mtu = ifp->if_mtu; 1641*e557c1ddSBryan Venteicher ds->ntxqueue = sc->vmx_ntxqueues; 1642*e557c1ddSBryan Venteicher ds->nrxqueue = sc->vmx_nrxqueues; 1643*e557c1ddSBryan Venteicher 1644e3c97c2cSBryan Venteicher ds->upt_features = 0; 1645e3c97c2cSBryan Venteicher if (ifp->if_capenable & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) 1646e3c97c2cSBryan Venteicher ds->upt_features |= UPT1_F_CSUM; 16473c5dfe89SBryan Venteicher if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 16483c5dfe89SBryan Venteicher ds->upt_features |= UPT1_F_VLAN; 1649e3c97c2cSBryan Venteicher if (ifp->if_capenable & IFCAP_LRO) 1650e3c97c2cSBryan Venteicher ds->upt_features |= UPT1_F_LRO; 1651e3c97c2cSBryan Venteicher 1652*e557c1ddSBryan Venteicher if (sc->vmx_flags & VMXNET3_FLAG_RSS) { 1653*e557c1ddSBryan Venteicher ds->upt_features |= UPT1_F_RSS; 1654*e557c1ddSBryan Venteicher vmxnet3_reinit_rss_shared_data(sc); 1655*e557c1ddSBryan Venteicher } 1656e3c97c2cSBryan Venteicher 1657e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSL, sc->vmx_ds_dma.dma_paddr); 1658e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSH, 1659e3c97c2cSBryan Venteicher (uint64_t) sc->vmx_ds_dma.dma_paddr >> 32); 1660e3c97c2cSBryan Venteicher } 1661e3c97c2cSBryan Venteicher 1662e3c97c2cSBryan Venteicher static int 1663e3c97c2cSBryan Venteicher vmxnet3_alloc_data(struct vmxnet3_softc *sc) 1664e3c97c2cSBryan Venteicher { 1665e3c97c2cSBryan Venteicher int error; 1666e3c97c2cSBryan Venteicher 1667e3c97c2cSBryan Venteicher error = vmxnet3_alloc_shared_data(sc); 1668e3c97c2cSBryan Venteicher if (error) 1669e3c97c2cSBryan Venteicher return (error); 1670e3c97c2cSBryan Venteicher 1671e3c97c2cSBryan Venteicher error = vmxnet3_alloc_queue_data(sc); 1672e3c97c2cSBryan Venteicher if (error) 1673e3c97c2cSBryan Venteicher return (error); 1674e3c97c2cSBryan Venteicher 1675e3c97c2cSBryan Venteicher error = vmxnet3_alloc_mcast_table(sc); 1676e3c97c2cSBryan Venteicher if (error) 1677e3c97c2cSBryan Venteicher return (error); 1678e3c97c2cSBryan Venteicher 1679e3c97c2cSBryan Venteicher vmxnet3_init_shared_data(sc); 1680e3c97c2cSBryan Venteicher 1681e3c97c2cSBryan Venteicher return (0); 1682e3c97c2cSBryan Venteicher } 1683e3c97c2cSBryan Venteicher 1684e3c97c2cSBryan Venteicher static void 1685e3c97c2cSBryan Venteicher vmxnet3_free_data(struct vmxnet3_softc *sc) 1686e3c97c2cSBryan Venteicher { 1687e3c97c2cSBryan Venteicher 1688e3c97c2cSBryan Venteicher vmxnet3_free_mcast_table(sc); 1689e3c97c2cSBryan Venteicher vmxnet3_free_queue_data(sc); 1690e3c97c2cSBryan Venteicher vmxnet3_free_shared_data(sc); 1691e3c97c2cSBryan Venteicher } 1692e3c97c2cSBryan Venteicher 1693e3c97c2cSBryan Venteicher static int 1694e3c97c2cSBryan Venteicher vmxnet3_setup_interface(struct vmxnet3_softc *sc) 1695e3c97c2cSBryan Venteicher { 1696e3c97c2cSBryan Venteicher device_t dev; 1697e3c97c2cSBryan Venteicher struct ifnet *ifp; 1698e3c97c2cSBryan Venteicher 1699e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 1700e3c97c2cSBryan Venteicher 1701e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp = if_alloc(IFT_ETHER); 1702e3c97c2cSBryan Venteicher if (ifp == NULL) { 1703e3c97c2cSBryan Venteicher device_printf(dev, "cannot allocate ifnet structure\n"); 1704e3c97c2cSBryan Venteicher return (ENOSPC); 1705e3c97c2cSBryan Venteicher } 1706e3c97c2cSBryan Venteicher 1707e3c97c2cSBryan Venteicher if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1708*e557c1ddSBryan Venteicher #if __FreeBSD_version < 1000025 1709*e557c1ddSBryan Venteicher ifp->if_baudrate = 1000000000; 1710*e557c1ddSBryan Venteicher #elif __FreeBSD_version < 1100011 1711*e557c1ddSBryan Venteicher if_initbaudrate(ifp, IF_Gbps(10)); 1712*e557c1ddSBryan Venteicher #else 1713b245f96cSGleb Smirnoff ifp->if_baudrate = IF_Gbps(10); 1714*e557c1ddSBryan Venteicher #endif 1715e3c97c2cSBryan Venteicher ifp->if_softc = sc; 1716e3c97c2cSBryan Venteicher ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1717e3c97c2cSBryan Venteicher ifp->if_init = vmxnet3_init; 1718e3c97c2cSBryan Venteicher ifp->if_ioctl = vmxnet3_ioctl; 1719*e557c1ddSBryan Venteicher ifp->if_hw_tsomax = VMXNET3_TSO_MAXSIZE; 1720*e557c1ddSBryan Venteicher 1721*e557c1ddSBryan Venteicher #ifdef VMXNET3_LEGACY_TX 1722e3c97c2cSBryan Venteicher ifp->if_start = vmxnet3_start; 1723e3c97c2cSBryan Venteicher ifp->if_snd.ifq_drv_maxlen = sc->vmx_ntxdescs - 1; 1724e3c97c2cSBryan Venteicher IFQ_SET_MAXLEN(&ifp->if_snd, sc->vmx_ntxdescs - 1); 1725e3c97c2cSBryan Venteicher IFQ_SET_READY(&ifp->if_snd); 1726*e557c1ddSBryan Venteicher #else 1727*e557c1ddSBryan Venteicher ifp->if_transmit = vmxnet3_txq_mq_start; 1728*e557c1ddSBryan Venteicher ifp->if_qflush = vmxnet3_qflush; 1729*e557c1ddSBryan Venteicher #endif 1730e3c97c2cSBryan Venteicher 1731e3c97c2cSBryan Venteicher vmxnet3_get_lladdr(sc); 1732e3c97c2cSBryan Venteicher ether_ifattach(ifp, sc->vmx_lladdr); 1733e3c97c2cSBryan Venteicher 1734e3c97c2cSBryan Venteicher ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_TXCSUM; 1735e3c97c2cSBryan Venteicher ifp->if_capabilities |= IFCAP_RXCSUM_IPV6 | IFCAP_TXCSUM_IPV6; 1736e3c97c2cSBryan Venteicher ifp->if_capabilities |= IFCAP_TSO4 | IFCAP_TSO6; 17373c5dfe89SBryan Venteicher ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | 17383c5dfe89SBryan Venteicher IFCAP_VLAN_HWCSUM; 1739e3c97c2cSBryan Venteicher ifp->if_capenable = ifp->if_capabilities; 1740e3c97c2cSBryan Venteicher 17413c5dfe89SBryan Venteicher /* These capabilities are not enabled by default. */ 17423c5dfe89SBryan Venteicher ifp->if_capabilities |= IFCAP_LRO | IFCAP_VLAN_HWFILTER; 1743e3c97c2cSBryan Venteicher 1744e3c97c2cSBryan Venteicher sc->vmx_vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 1745e3c97c2cSBryan Venteicher vmxnet3_register_vlan, sc, EVENTHANDLER_PRI_FIRST); 1746e3c97c2cSBryan Venteicher sc->vmx_vlan_detach = EVENTHANDLER_REGISTER(vlan_config, 1747e3c97c2cSBryan Venteicher vmxnet3_unregister_vlan, sc, EVENTHANDLER_PRI_FIRST); 1748e3c97c2cSBryan Venteicher 1749e3c97c2cSBryan Venteicher ifmedia_init(&sc->vmx_media, 0, vmxnet3_media_change, 1750e3c97c2cSBryan Venteicher vmxnet3_media_status); 1751e3c97c2cSBryan Venteicher ifmedia_add(&sc->vmx_media, IFM_ETHER | IFM_AUTO, 0, NULL); 1752e3c97c2cSBryan Venteicher ifmedia_set(&sc->vmx_media, IFM_ETHER | IFM_AUTO); 1753e3c97c2cSBryan Venteicher 1754e3c97c2cSBryan Venteicher return (0); 1755e3c97c2cSBryan Venteicher } 1756e3c97c2cSBryan Venteicher 1757e3c97c2cSBryan Venteicher static void 1758e3c97c2cSBryan Venteicher vmxnet3_evintr(struct vmxnet3_softc *sc) 1759e3c97c2cSBryan Venteicher { 1760e3c97c2cSBryan Venteicher device_t dev; 1761e3c97c2cSBryan Venteicher struct ifnet *ifp; 1762e3c97c2cSBryan Venteicher struct vmxnet3_txq_shared *ts; 1763e3c97c2cSBryan Venteicher struct vmxnet3_rxq_shared *rs; 1764e3c97c2cSBryan Venteicher uint32_t event; 1765e3c97c2cSBryan Venteicher int reset; 1766e3c97c2cSBryan Venteicher 1767e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 1768e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 1769e3c97c2cSBryan Venteicher reset = 0; 1770e3c97c2cSBryan Venteicher 1771e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK(sc); 1772e3c97c2cSBryan Venteicher 1773e3c97c2cSBryan Venteicher /* Clear events. */ 1774e3c97c2cSBryan Venteicher event = sc->vmx_ds->event; 1775e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_EVENT, event); 1776e3c97c2cSBryan Venteicher 1777*e557c1ddSBryan Venteicher if (event & VMXNET3_EVENT_LINK) { 1778e3c97c2cSBryan Venteicher vmxnet3_link_status(sc); 1779*e557c1ddSBryan Venteicher if (sc->vmx_link_active != 0) 1780*e557c1ddSBryan Venteicher vmxnet3_tx_start_all(sc); 1781*e557c1ddSBryan Venteicher } 1782e3c97c2cSBryan Venteicher 1783e3c97c2cSBryan Venteicher if (event & (VMXNET3_EVENT_TQERROR | VMXNET3_EVENT_RQERROR)) { 1784e3c97c2cSBryan Venteicher reset = 1; 1785e3c97c2cSBryan Venteicher vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_STATUS); 1786e3c97c2cSBryan Venteicher ts = sc->vmx_txq[0].vxtxq_ts; 1787e3c97c2cSBryan Venteicher if (ts->stopped != 0) 1788e3c97c2cSBryan Venteicher device_printf(dev, "Tx queue error %#x\n", ts->error); 1789e3c97c2cSBryan Venteicher rs = sc->vmx_rxq[0].vxrxq_rs; 1790e3c97c2cSBryan Venteicher if (rs->stopped != 0) 1791e3c97c2cSBryan Venteicher device_printf(dev, "Rx queue error %#x\n", rs->error); 1792e3c97c2cSBryan Venteicher device_printf(dev, "Rx/Tx queue error event ... resetting\n"); 1793e3c97c2cSBryan Venteicher } 1794e3c97c2cSBryan Venteicher 1795e3c97c2cSBryan Venteicher if (event & VMXNET3_EVENT_DIC) 1796e3c97c2cSBryan Venteicher device_printf(dev, "device implementation change event\n"); 1797e3c97c2cSBryan Venteicher if (event & VMXNET3_EVENT_DEBUG) 1798e3c97c2cSBryan Venteicher device_printf(dev, "debug event\n"); 1799e3c97c2cSBryan Venteicher 1800e3c97c2cSBryan Venteicher if (reset != 0) { 1801e3c97c2cSBryan Venteicher ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1802e3c97c2cSBryan Venteicher vmxnet3_init_locked(sc); 1803e3c97c2cSBryan Venteicher } 1804e3c97c2cSBryan Venteicher 1805e3c97c2cSBryan Venteicher VMXNET3_CORE_UNLOCK(sc); 1806e3c97c2cSBryan Venteicher } 1807e3c97c2cSBryan Venteicher 1808e3c97c2cSBryan Venteicher static void 1809e3c97c2cSBryan Venteicher vmxnet3_txq_eof(struct vmxnet3_txqueue *txq) 1810e3c97c2cSBryan Venteicher { 1811e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 1812e3c97c2cSBryan Venteicher struct ifnet *ifp; 1813e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr; 1814e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *txc; 1815e3c97c2cSBryan Venteicher struct vmxnet3_txcompdesc *txcd; 1816e3c97c2cSBryan Venteicher struct vmxnet3_txbuf *txb; 1817*e557c1ddSBryan Venteicher struct mbuf *m; 1818e3c97c2cSBryan Venteicher u_int sop; 1819e3c97c2cSBryan Venteicher 1820e3c97c2cSBryan Venteicher sc = txq->vxtxq_sc; 1821e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 1822e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 1823e3c97c2cSBryan Venteicher txc = &txq->vxtxq_comp_ring; 1824e3c97c2cSBryan Venteicher 1825e3c97c2cSBryan Venteicher VMXNET3_TXQ_LOCK_ASSERT(txq); 1826e3c97c2cSBryan Venteicher 1827e3c97c2cSBryan Venteicher for (;;) { 1828e3c97c2cSBryan Venteicher txcd = &txc->vxcr_u.txcd[txc->vxcr_next]; 1829e3c97c2cSBryan Venteicher if (txcd->gen != txc->vxcr_gen) 1830e3c97c2cSBryan Venteicher break; 18313c965775SBryan Venteicher vmxnet3_barrier(sc, VMXNET3_BARRIER_RD); 1832e3c97c2cSBryan Venteicher 1833e3c97c2cSBryan Venteicher if (++txc->vxcr_next == txc->vxcr_ndesc) { 1834e3c97c2cSBryan Venteicher txc->vxcr_next = 0; 1835e3c97c2cSBryan Venteicher txc->vxcr_gen ^= 1; 1836e3c97c2cSBryan Venteicher } 1837e3c97c2cSBryan Venteicher 1838e3c97c2cSBryan Venteicher sop = txr->vxtxr_next; 1839e3c97c2cSBryan Venteicher txb = &txr->vxtxr_txbuf[sop]; 1840e3c97c2cSBryan Venteicher 1841*e557c1ddSBryan Venteicher if ((m = txb->vtxb_m) != NULL) { 1842e3c97c2cSBryan Venteicher bus_dmamap_sync(txr->vxtxr_txtag, txb->vtxb_dmamap, 1843e3c97c2cSBryan Venteicher BUS_DMASYNC_POSTWRITE); 1844e3c97c2cSBryan Venteicher bus_dmamap_unload(txr->vxtxr_txtag, txb->vtxb_dmamap); 1845e3c97c2cSBryan Venteicher 1846*e557c1ddSBryan Venteicher txq->vxtxq_stats.vmtxs_opackets++; 1847*e557c1ddSBryan Venteicher txq->vxtxq_stats.vmtxs_obytes += m->m_pkthdr.len; 1848*e557c1ddSBryan Venteicher if (m->m_flags & M_MCAST) 1849*e557c1ddSBryan Venteicher txq->vxtxq_stats.vmtxs_omcasts++; 1850e3c97c2cSBryan Venteicher 1851*e557c1ddSBryan Venteicher m_freem(m); 1852*e557c1ddSBryan Venteicher txb->vtxb_m = NULL; 1853e3c97c2cSBryan Venteicher } 1854e3c97c2cSBryan Venteicher 1855e3c97c2cSBryan Venteicher txr->vxtxr_next = (txcd->eop_idx + 1) % txr->vxtxr_ndesc; 1856e3c97c2cSBryan Venteicher } 1857e3c97c2cSBryan Venteicher 1858e3c97c2cSBryan Venteicher if (txr->vxtxr_head == txr->vxtxr_next) 1859e3c97c2cSBryan Venteicher txq->vxtxq_watchdog = 0; 1860e3c97c2cSBryan Venteicher } 1861e3c97c2cSBryan Venteicher 1862e3c97c2cSBryan Venteicher static int 1863e3c97c2cSBryan Venteicher vmxnet3_newbuf(struct vmxnet3_softc *sc, struct vmxnet3_rxring *rxr) 1864e3c97c2cSBryan Venteicher { 1865e3c97c2cSBryan Venteicher struct ifnet *ifp; 1866e3c97c2cSBryan Venteicher struct mbuf *m; 1867e3c97c2cSBryan Venteicher struct vmxnet3_rxdesc *rxd; 1868e3c97c2cSBryan Venteicher struct vmxnet3_rxbuf *rxb; 1869e3c97c2cSBryan Venteicher bus_dma_tag_t tag; 1870e3c97c2cSBryan Venteicher bus_dmamap_t dmap; 1871e3c97c2cSBryan Venteicher bus_dma_segment_t segs[1]; 1872e3c97c2cSBryan Venteicher int idx, clsize, btype, flags, nsegs, error; 1873e3c97c2cSBryan Venteicher 1874e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 1875e3c97c2cSBryan Venteicher tag = rxr->vxrxr_rxtag; 1876e3c97c2cSBryan Venteicher dmap = rxr->vxrxr_spare_dmap; 1877e3c97c2cSBryan Venteicher idx = rxr->vxrxr_fill; 1878e3c97c2cSBryan Venteicher rxd = &rxr->vxrxr_rxd[idx]; 1879e3c97c2cSBryan Venteicher rxb = &rxr->vxrxr_rxbuf[idx]; 1880e3c97c2cSBryan Venteicher 1881e3c97c2cSBryan Venteicher #ifdef VMXNET3_FAILPOINTS 1882e3c97c2cSBryan Venteicher KFAIL_POINT_CODE(VMXNET3_FP, newbuf, return ENOBUFS); 1883e3c97c2cSBryan Venteicher if (rxr->vxrxr_rid != 0) 1884e3c97c2cSBryan Venteicher KFAIL_POINT_CODE(VMXNET3_FP, newbuf_body_only, return ENOBUFS); 1885e3c97c2cSBryan Venteicher #endif 1886e3c97c2cSBryan Venteicher 1887e3c97c2cSBryan Venteicher if (rxr->vxrxr_rid == 0 && (idx % sc->vmx_rx_max_chain) == 0) { 1888e3c97c2cSBryan Venteicher flags = M_PKTHDR; 1889e3c97c2cSBryan Venteicher clsize = MCLBYTES; 1890e3c97c2cSBryan Venteicher btype = VMXNET3_BTYPE_HEAD; 1891e3c97c2cSBryan Venteicher } else { 1892e3c97c2cSBryan Venteicher #if __FreeBSD_version < 902001 1893e3c97c2cSBryan Venteicher /* 1894e3c97c2cSBryan Venteicher * These mbufs will never be used for the start of a frame. 1895e3c97c2cSBryan Venteicher * Roughly prior to branching releng/9.2, the load_mbuf_sg() 1896e3c97c2cSBryan Venteicher * required the mbuf to always be a packet header. Avoid 1897e3c97c2cSBryan Venteicher * unnecessary mbuf initialization in newer versions where 1898e3c97c2cSBryan Venteicher * that is not the case. 1899e3c97c2cSBryan Venteicher */ 1900e3c97c2cSBryan Venteicher flags = M_PKTHDR; 1901e3c97c2cSBryan Venteicher #else 1902e3c97c2cSBryan Venteicher flags = 0; 1903e3c97c2cSBryan Venteicher #endif 1904e3c97c2cSBryan Venteicher clsize = MJUMPAGESIZE; 1905e3c97c2cSBryan Venteicher btype = VMXNET3_BTYPE_BODY; 1906e3c97c2cSBryan Venteicher } 1907e3c97c2cSBryan Venteicher 1908e3c97c2cSBryan Venteicher m = m_getjcl(M_NOWAIT, MT_DATA, flags, clsize); 1909e3c97c2cSBryan Venteicher if (m == NULL) { 1910e3c97c2cSBryan Venteicher sc->vmx_stats.vmst_mgetcl_failed++; 1911e3c97c2cSBryan Venteicher return (ENOBUFS); 1912e3c97c2cSBryan Venteicher } 1913e3c97c2cSBryan Venteicher 1914e3c97c2cSBryan Venteicher if (btype == VMXNET3_BTYPE_HEAD) { 1915e3c97c2cSBryan Venteicher m->m_len = m->m_pkthdr.len = clsize; 1916e3c97c2cSBryan Venteicher m_adj(m, ETHER_ALIGN); 1917e3c97c2cSBryan Venteicher } else 1918e3c97c2cSBryan Venteicher m->m_len = clsize; 1919e3c97c2cSBryan Venteicher 1920e3c97c2cSBryan Venteicher error = bus_dmamap_load_mbuf_sg(tag, dmap, m, &segs[0], &nsegs, 1921e3c97c2cSBryan Venteicher BUS_DMA_NOWAIT); 1922e3c97c2cSBryan Venteicher if (error) { 1923e3c97c2cSBryan Venteicher m_freem(m); 19243c965775SBryan Venteicher sc->vmx_stats.vmst_mbuf_load_failed++; 1925e3c97c2cSBryan Venteicher return (error); 1926e3c97c2cSBryan Venteicher } 1927e3c97c2cSBryan Venteicher KASSERT(nsegs == 1, 1928e3c97c2cSBryan Venteicher ("%s: mbuf %p with too many segments %d", __func__, m, nsegs)); 1929e3c97c2cSBryan Venteicher #if __FreeBSD_version < 902001 1930e3c97c2cSBryan Venteicher if (btype == VMXNET3_BTYPE_BODY) 1931e3c97c2cSBryan Venteicher m->m_flags &= ~M_PKTHDR; 1932e3c97c2cSBryan Venteicher #endif 1933e3c97c2cSBryan Venteicher 1934e3c97c2cSBryan Venteicher if (rxb->vrxb_m != NULL) { 1935e3c97c2cSBryan Venteicher bus_dmamap_sync(tag, rxb->vrxb_dmamap, BUS_DMASYNC_POSTREAD); 1936e3c97c2cSBryan Venteicher bus_dmamap_unload(tag, rxb->vrxb_dmamap); 1937e3c97c2cSBryan Venteicher } 1938e3c97c2cSBryan Venteicher 1939e3c97c2cSBryan Venteicher rxr->vxrxr_spare_dmap = rxb->vrxb_dmamap; 1940e3c97c2cSBryan Venteicher rxb->vrxb_dmamap = dmap; 1941e3c97c2cSBryan Venteicher rxb->vrxb_m = m; 1942e3c97c2cSBryan Venteicher 1943e3c97c2cSBryan Venteicher rxd->addr = segs[0].ds_addr; 1944e3c97c2cSBryan Venteicher rxd->len = segs[0].ds_len; 1945e3c97c2cSBryan Venteicher rxd->btype = btype; 1946e3c97c2cSBryan Venteicher rxd->gen = rxr->vxrxr_gen; 1947e3c97c2cSBryan Venteicher 1948e3c97c2cSBryan Venteicher vmxnet3_rxr_increment_fill(rxr); 1949e3c97c2cSBryan Venteicher return (0); 1950e3c97c2cSBryan Venteicher } 1951e3c97c2cSBryan Venteicher 1952e3c97c2cSBryan Venteicher static void 1953e3c97c2cSBryan Venteicher vmxnet3_rxq_eof_discard(struct vmxnet3_rxqueue *rxq, 1954e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr, int idx) 1955e3c97c2cSBryan Venteicher { 1956e3c97c2cSBryan Venteicher struct vmxnet3_rxdesc *rxd; 1957e3c97c2cSBryan Venteicher 1958e3c97c2cSBryan Venteicher rxd = &rxr->vxrxr_rxd[idx]; 1959e3c97c2cSBryan Venteicher rxd->gen = rxr->vxrxr_gen; 1960e3c97c2cSBryan Venteicher vmxnet3_rxr_increment_fill(rxr); 1961e3c97c2cSBryan Venteicher } 1962e3c97c2cSBryan Venteicher 1963e3c97c2cSBryan Venteicher static void 1964e3c97c2cSBryan Venteicher vmxnet3_rxq_discard_chain(struct vmxnet3_rxqueue *rxq) 1965e3c97c2cSBryan Venteicher { 1966e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 1967e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr; 1968e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *rxc; 1969e3c97c2cSBryan Venteicher struct vmxnet3_rxcompdesc *rxcd; 1970e3c97c2cSBryan Venteicher int idx, eof; 1971e3c97c2cSBryan Venteicher 1972e3c97c2cSBryan Venteicher sc = rxq->vxrxq_sc; 1973e3c97c2cSBryan Venteicher rxc = &rxq->vxrxq_comp_ring; 1974e3c97c2cSBryan Venteicher 1975e3c97c2cSBryan Venteicher do { 1976e3c97c2cSBryan Venteicher rxcd = &rxc->vxcr_u.rxcd[rxc->vxcr_next]; 1977e3c97c2cSBryan Venteicher if (rxcd->gen != rxc->vxcr_gen) 1978e3c97c2cSBryan Venteicher break; /* Not expected. */ 1979e3c97c2cSBryan Venteicher vmxnet3_barrier(sc, VMXNET3_BARRIER_RD); 1980e3c97c2cSBryan Venteicher 1981e3c97c2cSBryan Venteicher if (++rxc->vxcr_next == rxc->vxcr_ndesc) { 1982e3c97c2cSBryan Venteicher rxc->vxcr_next = 0; 1983e3c97c2cSBryan Venteicher rxc->vxcr_gen ^= 1; 1984e3c97c2cSBryan Venteicher } 1985e3c97c2cSBryan Venteicher 1986e3c97c2cSBryan Venteicher idx = rxcd->rxd_idx; 1987e3c97c2cSBryan Venteicher eof = rxcd->eop; 1988e3c97c2cSBryan Venteicher if (rxcd->qid < sc->vmx_nrxqueues) 1989e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[0]; 1990e3c97c2cSBryan Venteicher else 1991e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[1]; 1992e3c97c2cSBryan Venteicher vmxnet3_rxq_eof_discard(rxq, rxr, idx); 1993e3c97c2cSBryan Venteicher } while (!eof); 1994e3c97c2cSBryan Venteicher } 1995e3c97c2cSBryan Venteicher 1996e3c97c2cSBryan Venteicher static void 1997e3c97c2cSBryan Venteicher vmxnet3_rx_csum(struct vmxnet3_rxcompdesc *rxcd, struct mbuf *m) 1998e3c97c2cSBryan Venteicher { 1999e3c97c2cSBryan Venteicher 2000e3c97c2cSBryan Venteicher if (rxcd->ipv4) { 2001e3c97c2cSBryan Venteicher m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2002e3c97c2cSBryan Venteicher if (rxcd->ipcsum_ok) 2003e3c97c2cSBryan Venteicher m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2004e3c97c2cSBryan Venteicher } 2005e3c97c2cSBryan Venteicher 2006e3c97c2cSBryan Venteicher if (!rxcd->fragment) { 2007e3c97c2cSBryan Venteicher if (rxcd->csum_ok && (rxcd->tcp || rxcd->udp)) { 2008e3c97c2cSBryan Venteicher m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | 2009e3c97c2cSBryan Venteicher CSUM_PSEUDO_HDR; 2010e3c97c2cSBryan Venteicher m->m_pkthdr.csum_data = 0xFFFF; 2011e3c97c2cSBryan Venteicher } 2012e3c97c2cSBryan Venteicher } 2013e3c97c2cSBryan Venteicher } 2014e3c97c2cSBryan Venteicher 2015e3c97c2cSBryan Venteicher static void 2016e3c97c2cSBryan Venteicher vmxnet3_rxq_input(struct vmxnet3_rxqueue *rxq, 2017e3c97c2cSBryan Venteicher struct vmxnet3_rxcompdesc *rxcd, struct mbuf *m) 2018e3c97c2cSBryan Venteicher { 2019e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 2020e3c97c2cSBryan Venteicher struct ifnet *ifp; 2021e3c97c2cSBryan Venteicher 2022e3c97c2cSBryan Venteicher sc = rxq->vxrxq_sc; 2023e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 2024e3c97c2cSBryan Venteicher 2025e3c97c2cSBryan Venteicher if (rxcd->error) { 2026*e557c1ddSBryan Venteicher rxq->vxrxq_stats.vmrxs_ierrors++; 2027e3c97c2cSBryan Venteicher m_freem(m); 2028e3c97c2cSBryan Venteicher return; 2029e3c97c2cSBryan Venteicher } 2030e3c97c2cSBryan Venteicher 2031*e557c1ddSBryan Venteicher #ifdef notyet 2032*e557c1ddSBryan Venteicher switch (rxcd->rss_type) { 2033*e557c1ddSBryan Venteicher case VMXNET3_RCD_RSS_TYPE_IPV4: 2034*e557c1ddSBryan Venteicher m->m_pkthdr.flowid = rxcd->rss_hash; 2035*e557c1ddSBryan Venteicher M_HASHTYPE_SET(m, M_HASHTYPE_RSS_IPV4); 2036*e557c1ddSBryan Venteicher break; 2037*e557c1ddSBryan Venteicher case VMXNET3_RCD_RSS_TYPE_TCPIPV4: 2038*e557c1ddSBryan Venteicher m->m_pkthdr.flowid = rxcd->rss_hash; 2039*e557c1ddSBryan Venteicher M_HASHTYPE_SET(m, M_HASHTYPE_RSS_TCP_IPV4); 2040*e557c1ddSBryan Venteicher break; 2041*e557c1ddSBryan Venteicher case VMXNET3_RCD_RSS_TYPE_IPV6: 2042*e557c1ddSBryan Venteicher m->m_pkthdr.flowid = rxcd->rss_hash; 2043*e557c1ddSBryan Venteicher M_HASHTYPE_SET(m, M_HASHTYPE_RSS_IPV6); 2044*e557c1ddSBryan Venteicher break; 2045*e557c1ddSBryan Venteicher case VMXNET3_RCD_RSS_TYPE_TCPIPV6: 2046*e557c1ddSBryan Venteicher m->m_pkthdr.flowid = rxcd->rss_hash; 2047*e557c1ddSBryan Venteicher M_HASHTYPE_SET(m, M_HASHTYPE_RSS_TCP_IPV6); 2048*e557c1ddSBryan Venteicher break; 2049*e557c1ddSBryan Venteicher default: /* VMXNET3_RCD_RSS_TYPE_NONE */ 2050*e557c1ddSBryan Venteicher m->m_pkthdr.flowid = rxq->vxrxq_id; 2051*e557c1ddSBryan Venteicher M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); 2052*e557c1ddSBryan Venteicher break; 2053*e557c1ddSBryan Venteicher } 2054*e557c1ddSBryan Venteicher #else 2055*e557c1ddSBryan Venteicher m->m_pkthdr.flowid = rxq->vxrxq_id; 2056*e557c1ddSBryan Venteicher m->m_flags |= M_FLOWID; 2057*e557c1ddSBryan Venteicher #endif 2058*e557c1ddSBryan Venteicher 2059e3c97c2cSBryan Venteicher if (!rxcd->no_csum) 2060e3c97c2cSBryan Venteicher vmxnet3_rx_csum(rxcd, m); 2061e3c97c2cSBryan Venteicher if (rxcd->vlan) { 2062e3c97c2cSBryan Venteicher m->m_flags |= M_VLANTAG; 2063e3c97c2cSBryan Venteicher m->m_pkthdr.ether_vtag = rxcd->vtag; 2064e3c97c2cSBryan Venteicher } 2065e3c97c2cSBryan Venteicher 2066*e557c1ddSBryan Venteicher rxq->vxrxq_stats.vmrxs_ipackets++; 2067*e557c1ddSBryan Venteicher rxq->vxrxq_stats.vmrxs_ibytes += m->m_pkthdr.len; 2068*e557c1ddSBryan Venteicher 2069e3c97c2cSBryan Venteicher VMXNET3_RXQ_UNLOCK(rxq); 2070e3c97c2cSBryan Venteicher (*ifp->if_input)(ifp, m); 2071e3c97c2cSBryan Venteicher VMXNET3_RXQ_LOCK(rxq); 2072e3c97c2cSBryan Venteicher } 2073e3c97c2cSBryan Venteicher 2074e3c97c2cSBryan Venteicher static void 2075e3c97c2cSBryan Venteicher vmxnet3_rxq_eof(struct vmxnet3_rxqueue *rxq) 2076e3c97c2cSBryan Venteicher { 2077e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 2078e3c97c2cSBryan Venteicher struct ifnet *ifp; 2079e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr; 2080e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *rxc; 2081e3c97c2cSBryan Venteicher struct vmxnet3_rxdesc *rxd; 2082e3c97c2cSBryan Venteicher struct vmxnet3_rxcompdesc *rxcd; 2083e3c97c2cSBryan Venteicher struct mbuf *m, *m_head, *m_tail; 2084e3c97c2cSBryan Venteicher int idx, length; 2085e3c97c2cSBryan Venteicher 2086e3c97c2cSBryan Venteicher sc = rxq->vxrxq_sc; 2087e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 2088e3c97c2cSBryan Venteicher rxc = &rxq->vxrxq_comp_ring; 2089e3c97c2cSBryan Venteicher m_head = m_tail = NULL; 2090e3c97c2cSBryan Venteicher 2091e3c97c2cSBryan Venteicher VMXNET3_RXQ_LOCK_ASSERT(rxq); 2092e3c97c2cSBryan Venteicher 2093e3c97c2cSBryan Venteicher if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 2094e3c97c2cSBryan Venteicher return; 2095e3c97c2cSBryan Venteicher 2096e3c97c2cSBryan Venteicher for (;;) { 2097e3c97c2cSBryan Venteicher rxcd = &rxc->vxcr_u.rxcd[rxc->vxcr_next]; 2098e3c97c2cSBryan Venteicher if (rxcd->gen != rxc->vxcr_gen) 2099e3c97c2cSBryan Venteicher break; 2100e3c97c2cSBryan Venteicher vmxnet3_barrier(sc, VMXNET3_BARRIER_RD); 2101e3c97c2cSBryan Venteicher 2102e3c97c2cSBryan Venteicher if (++rxc->vxcr_next == rxc->vxcr_ndesc) { 2103e3c97c2cSBryan Venteicher rxc->vxcr_next = 0; 2104e3c97c2cSBryan Venteicher rxc->vxcr_gen ^= 1; 2105e3c97c2cSBryan Venteicher } 2106e3c97c2cSBryan Venteicher 2107e3c97c2cSBryan Venteicher idx = rxcd->rxd_idx; 2108e3c97c2cSBryan Venteicher length = rxcd->len; 2109e3c97c2cSBryan Venteicher if (rxcd->qid < sc->vmx_nrxqueues) 2110e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[0]; 2111e3c97c2cSBryan Venteicher else 2112e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[1]; 2113e3c97c2cSBryan Venteicher rxd = &rxr->vxrxr_rxd[idx]; 2114e3c97c2cSBryan Venteicher 2115e3c97c2cSBryan Venteicher m = rxr->vxrxr_rxbuf[idx].vrxb_m; 2116e3c97c2cSBryan Venteicher KASSERT(m != NULL, ("%s: queue %d idx %d without mbuf", 2117e3c97c2cSBryan Venteicher __func__, rxcd->qid, idx)); 2118e3c97c2cSBryan Venteicher 2119e3c97c2cSBryan Venteicher /* 2120e3c97c2cSBryan Venteicher * The host may skip descriptors. We detect this when this 2121e3c97c2cSBryan Venteicher * descriptor does not match the previous fill index. Catch 2122e3c97c2cSBryan Venteicher * up with the host now. 2123e3c97c2cSBryan Venteicher */ 2124e3c97c2cSBryan Venteicher if (__predict_false(rxr->vxrxr_fill != idx)) { 2125e3c97c2cSBryan Venteicher while (rxr->vxrxr_fill != idx) { 2126e3c97c2cSBryan Venteicher rxr->vxrxr_rxd[rxr->vxrxr_fill].gen = 2127e3c97c2cSBryan Venteicher rxr->vxrxr_gen; 2128e3c97c2cSBryan Venteicher vmxnet3_rxr_increment_fill(rxr); 2129e3c97c2cSBryan Venteicher } 2130e3c97c2cSBryan Venteicher } 2131e3c97c2cSBryan Venteicher 2132e3c97c2cSBryan Venteicher if (rxcd->sop) { 2133e3c97c2cSBryan Venteicher KASSERT(rxd->btype == VMXNET3_BTYPE_HEAD, 2134e3c97c2cSBryan Venteicher ("%s: start of frame w/o head buffer", __func__)); 2135e3c97c2cSBryan Venteicher KASSERT(rxr == &rxq->vxrxq_cmd_ring[0], 2136e3c97c2cSBryan Venteicher ("%s: start of frame not in ring 0", __func__)); 2137e3c97c2cSBryan Venteicher KASSERT((idx % sc->vmx_rx_max_chain) == 0, 2138e3c97c2cSBryan Venteicher ("%s: start of frame at unexcepted index %d (%d)", 2139e3c97c2cSBryan Venteicher __func__, idx, sc->vmx_rx_max_chain)); 2140e3c97c2cSBryan Venteicher KASSERT(m_head == NULL, 2141e3c97c2cSBryan Venteicher ("%s: duplicate start of frame?", __func__)); 2142e3c97c2cSBryan Venteicher 2143e3c97c2cSBryan Venteicher if (length == 0) { 2144e3c97c2cSBryan Venteicher /* Just ignore this descriptor. */ 2145e3c97c2cSBryan Venteicher vmxnet3_rxq_eof_discard(rxq, rxr, idx); 2146e3c97c2cSBryan Venteicher goto nextp; 2147e3c97c2cSBryan Venteicher } 2148e3c97c2cSBryan Venteicher 2149e3c97c2cSBryan Venteicher if (vmxnet3_newbuf(sc, rxr) != 0) { 2150*e557c1ddSBryan Venteicher rxq->vxrxq_stats.vmrxs_iqdrops++; 2151e3c97c2cSBryan Venteicher vmxnet3_rxq_eof_discard(rxq, rxr, idx); 2152e3c97c2cSBryan Venteicher if (!rxcd->eop) 2153e3c97c2cSBryan Venteicher vmxnet3_rxq_discard_chain(rxq); 2154e3c97c2cSBryan Venteicher goto nextp; 2155e3c97c2cSBryan Venteicher } 2156e3c97c2cSBryan Venteicher 2157e3c97c2cSBryan Venteicher m->m_pkthdr.rcvif = ifp; 2158e3c97c2cSBryan Venteicher m->m_pkthdr.len = m->m_len = length; 2159e3c97c2cSBryan Venteicher m->m_pkthdr.csum_flags = 0; 2160e3c97c2cSBryan Venteicher m_head = m_tail = m; 2161e3c97c2cSBryan Venteicher 2162e3c97c2cSBryan Venteicher } else { 2163e3c97c2cSBryan Venteicher KASSERT(rxd->btype == VMXNET3_BTYPE_BODY, 2164e3c97c2cSBryan Venteicher ("%s: non start of frame w/o body buffer", __func__)); 2165e3c97c2cSBryan Venteicher KASSERT(m_head != NULL, 2166e3c97c2cSBryan Venteicher ("%s: frame not started?", __func__)); 2167e3c97c2cSBryan Venteicher 2168e3c97c2cSBryan Venteicher if (vmxnet3_newbuf(sc, rxr) != 0) { 2169*e557c1ddSBryan Venteicher rxq->vxrxq_stats.vmrxs_iqdrops++; 2170e3c97c2cSBryan Venteicher vmxnet3_rxq_eof_discard(rxq, rxr, idx); 2171e3c97c2cSBryan Venteicher if (!rxcd->eop) 2172e3c97c2cSBryan Venteicher vmxnet3_rxq_discard_chain(rxq); 2173e3c97c2cSBryan Venteicher m_freem(m_head); 2174e3c97c2cSBryan Venteicher m_head = m_tail = NULL; 2175e3c97c2cSBryan Venteicher goto nextp; 2176e3c97c2cSBryan Venteicher } 2177e3c97c2cSBryan Venteicher 2178e3c97c2cSBryan Venteicher m->m_len = length; 2179e3c97c2cSBryan Venteicher m_head->m_pkthdr.len += length; 2180e3c97c2cSBryan Venteicher m_tail->m_next = m; 2181e3c97c2cSBryan Venteicher m_tail = m; 2182e3c97c2cSBryan Venteicher } 2183e3c97c2cSBryan Venteicher 2184e3c97c2cSBryan Venteicher if (rxcd->eop) { 2185e3c97c2cSBryan Venteicher vmxnet3_rxq_input(rxq, rxcd, m_head); 2186e3c97c2cSBryan Venteicher m_head = m_tail = NULL; 2187e3c97c2cSBryan Venteicher 2188e3c97c2cSBryan Venteicher /* Must recheck after dropping the Rx lock. */ 2189e3c97c2cSBryan Venteicher if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 2190e3c97c2cSBryan Venteicher break; 2191e3c97c2cSBryan Venteicher } 2192e3c97c2cSBryan Venteicher 2193e3c97c2cSBryan Venteicher nextp: 2194e3c97c2cSBryan Venteicher if (__predict_false(rxq->vxrxq_rs->update_rxhead)) { 2195e3c97c2cSBryan Venteicher int qid = rxcd->qid; 2196e3c97c2cSBryan Venteicher bus_size_t r; 2197e3c97c2cSBryan Venteicher 2198e3c97c2cSBryan Venteicher idx = (idx + 1) % rxr->vxrxr_ndesc; 2199e3c97c2cSBryan Venteicher if (qid >= sc->vmx_nrxqueues) { 2200e3c97c2cSBryan Venteicher qid -= sc->vmx_nrxqueues; 2201e3c97c2cSBryan Venteicher r = VMXNET3_BAR0_RXH2(qid); 2202e3c97c2cSBryan Venteicher } else 2203e3c97c2cSBryan Venteicher r = VMXNET3_BAR0_RXH1(qid); 2204e3c97c2cSBryan Venteicher vmxnet3_write_bar0(sc, r, idx); 2205e3c97c2cSBryan Venteicher } 2206e3c97c2cSBryan Venteicher } 2207e3c97c2cSBryan Venteicher } 2208e3c97c2cSBryan Venteicher 2209e3c97c2cSBryan Venteicher static void 2210e3c97c2cSBryan Venteicher vmxnet3_legacy_intr(void *xsc) 2211e3c97c2cSBryan Venteicher { 2212e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 2213e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq; 2214e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq; 2215e3c97c2cSBryan Venteicher struct ifnet *ifp; 2216e3c97c2cSBryan Venteicher 2217e3c97c2cSBryan Venteicher sc = xsc; 2218e3c97c2cSBryan Venteicher rxq = &sc->vmx_rxq[0]; 2219e3c97c2cSBryan Venteicher txq = &sc->vmx_txq[0]; 2220e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 2221e3c97c2cSBryan Venteicher 2222e3c97c2cSBryan Venteicher if (sc->vmx_intr_type == VMXNET3_IT_LEGACY) { 2223e3c97c2cSBryan Venteicher if (vmxnet3_read_bar1(sc, VMXNET3_BAR1_INTR) == 0) 2224e3c97c2cSBryan Venteicher return; 2225e3c97c2cSBryan Venteicher } 2226e3c97c2cSBryan Venteicher if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE) 2227e3c97c2cSBryan Venteicher vmxnet3_disable_all_intrs(sc); 2228e3c97c2cSBryan Venteicher 2229e3c97c2cSBryan Venteicher if (sc->vmx_ds->event != 0) 2230e3c97c2cSBryan Venteicher vmxnet3_evintr(sc); 2231e3c97c2cSBryan Venteicher 2232e3c97c2cSBryan Venteicher VMXNET3_RXQ_LOCK(rxq); 2233e3c97c2cSBryan Venteicher vmxnet3_rxq_eof(rxq); 2234e3c97c2cSBryan Venteicher VMXNET3_RXQ_UNLOCK(rxq); 2235e3c97c2cSBryan Venteicher 2236e3c97c2cSBryan Venteicher VMXNET3_TXQ_LOCK(txq); 2237e3c97c2cSBryan Venteicher vmxnet3_txq_eof(txq); 2238*e557c1ddSBryan Venteicher vmxnet3_txq_start(txq); 2239e3c97c2cSBryan Venteicher VMXNET3_TXQ_UNLOCK(txq); 2240e3c97c2cSBryan Venteicher 2241e3c97c2cSBryan Venteicher vmxnet3_enable_all_intrs(sc); 2242e3c97c2cSBryan Venteicher } 2243e3c97c2cSBryan Venteicher 2244e3c97c2cSBryan Venteicher static void 2245e3c97c2cSBryan Venteicher vmxnet3_txq_intr(void *xtxq) 2246e3c97c2cSBryan Venteicher { 2247e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 2248e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq; 2249e3c97c2cSBryan Venteicher struct ifnet *ifp; 2250e3c97c2cSBryan Venteicher 2251e3c97c2cSBryan Venteicher txq = xtxq; 2252e3c97c2cSBryan Venteicher sc = txq->vxtxq_sc; 2253e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 2254e3c97c2cSBryan Venteicher 2255e3c97c2cSBryan Venteicher if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE) 2256e3c97c2cSBryan Venteicher vmxnet3_disable_intr(sc, txq->vxtxq_intr_idx); 2257e3c97c2cSBryan Venteicher 2258e3c97c2cSBryan Venteicher VMXNET3_TXQ_LOCK(txq); 2259e3c97c2cSBryan Venteicher vmxnet3_txq_eof(txq); 2260*e557c1ddSBryan Venteicher vmxnet3_txq_start(txq); 2261e3c97c2cSBryan Venteicher VMXNET3_TXQ_UNLOCK(txq); 2262e3c97c2cSBryan Venteicher 2263e3c97c2cSBryan Venteicher vmxnet3_enable_intr(sc, txq->vxtxq_intr_idx); 2264e3c97c2cSBryan Venteicher } 2265e3c97c2cSBryan Venteicher 2266e3c97c2cSBryan Venteicher static void 2267e3c97c2cSBryan Venteicher vmxnet3_rxq_intr(void *xrxq) 2268e3c97c2cSBryan Venteicher { 2269e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 2270e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq; 2271e3c97c2cSBryan Venteicher 2272e3c97c2cSBryan Venteicher rxq = xrxq; 2273e3c97c2cSBryan Venteicher sc = rxq->vxrxq_sc; 2274e3c97c2cSBryan Venteicher 2275e3c97c2cSBryan Venteicher if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE) 2276e3c97c2cSBryan Venteicher vmxnet3_disable_intr(sc, rxq->vxrxq_intr_idx); 2277e3c97c2cSBryan Venteicher 2278e3c97c2cSBryan Venteicher VMXNET3_RXQ_LOCK(rxq); 2279e3c97c2cSBryan Venteicher vmxnet3_rxq_eof(rxq); 2280e3c97c2cSBryan Venteicher VMXNET3_RXQ_UNLOCK(rxq); 2281e3c97c2cSBryan Venteicher 2282e3c97c2cSBryan Venteicher vmxnet3_enable_intr(sc, rxq->vxrxq_intr_idx); 2283e3c97c2cSBryan Venteicher } 2284e3c97c2cSBryan Venteicher 2285e3c97c2cSBryan Venteicher static void 2286e3c97c2cSBryan Venteicher vmxnet3_event_intr(void *xsc) 2287e3c97c2cSBryan Venteicher { 2288e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 2289e3c97c2cSBryan Venteicher 2290e3c97c2cSBryan Venteicher sc = xsc; 2291e3c97c2cSBryan Venteicher 2292e3c97c2cSBryan Venteicher if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE) 2293e3c97c2cSBryan Venteicher vmxnet3_disable_intr(sc, sc->vmx_event_intr_idx); 2294e3c97c2cSBryan Venteicher 2295e3c97c2cSBryan Venteicher if (sc->vmx_ds->event != 0) 2296e3c97c2cSBryan Venteicher vmxnet3_evintr(sc); 2297e3c97c2cSBryan Venteicher 2298e3c97c2cSBryan Venteicher vmxnet3_enable_intr(sc, sc->vmx_event_intr_idx); 2299e3c97c2cSBryan Venteicher } 2300e3c97c2cSBryan Venteicher 2301e3c97c2cSBryan Venteicher static void 2302e3c97c2cSBryan Venteicher vmxnet3_txstop(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq) 2303e3c97c2cSBryan Venteicher { 2304e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr; 2305e3c97c2cSBryan Venteicher struct vmxnet3_txbuf *txb; 2306e3c97c2cSBryan Venteicher int i; 2307e3c97c2cSBryan Venteicher 2308e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 2309e3c97c2cSBryan Venteicher 2310e3c97c2cSBryan Venteicher for (i = 0; i < txr->vxtxr_ndesc; i++) { 2311e3c97c2cSBryan Venteicher txb = &txr->vxtxr_txbuf[i]; 2312e3c97c2cSBryan Venteicher 2313e3c97c2cSBryan Venteicher if (txb->vtxb_m == NULL) 2314e3c97c2cSBryan Venteicher continue; 2315e3c97c2cSBryan Venteicher 2316e3c97c2cSBryan Venteicher bus_dmamap_sync(txr->vxtxr_txtag, txb->vtxb_dmamap, 2317e3c97c2cSBryan Venteicher BUS_DMASYNC_POSTWRITE); 2318e3c97c2cSBryan Venteicher bus_dmamap_unload(txr->vxtxr_txtag, txb->vtxb_dmamap); 2319e3c97c2cSBryan Venteicher m_freem(txb->vtxb_m); 2320e3c97c2cSBryan Venteicher txb->vtxb_m = NULL; 2321e3c97c2cSBryan Venteicher } 2322e3c97c2cSBryan Venteicher } 2323e3c97c2cSBryan Venteicher 2324e3c97c2cSBryan Venteicher static void 2325e3c97c2cSBryan Venteicher vmxnet3_rxstop(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq) 2326e3c97c2cSBryan Venteicher { 2327e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr; 2328e3c97c2cSBryan Venteicher struct vmxnet3_rxbuf *rxb; 2329e3c97c2cSBryan Venteicher int i, j; 2330e3c97c2cSBryan Venteicher 2331e3c97c2cSBryan Venteicher for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) { 2332e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i]; 2333e3c97c2cSBryan Venteicher 2334e3c97c2cSBryan Venteicher for (j = 0; j < rxr->vxrxr_ndesc; j++) { 2335e3c97c2cSBryan Venteicher rxb = &rxr->vxrxr_rxbuf[j]; 2336e3c97c2cSBryan Venteicher 2337e3c97c2cSBryan Venteicher if (rxb->vrxb_m == NULL) 2338e3c97c2cSBryan Venteicher continue; 2339*e557c1ddSBryan Venteicher 2340e3c97c2cSBryan Venteicher bus_dmamap_sync(rxr->vxrxr_rxtag, rxb->vrxb_dmamap, 2341e3c97c2cSBryan Venteicher BUS_DMASYNC_POSTREAD); 2342e3c97c2cSBryan Venteicher bus_dmamap_unload(rxr->vxrxr_rxtag, rxb->vrxb_dmamap); 2343e3c97c2cSBryan Venteicher m_freem(rxb->vrxb_m); 2344e3c97c2cSBryan Venteicher rxb->vrxb_m = NULL; 2345e3c97c2cSBryan Venteicher } 2346e3c97c2cSBryan Venteicher } 2347e3c97c2cSBryan Venteicher } 2348e3c97c2cSBryan Venteicher 2349e3c97c2cSBryan Venteicher static void 2350e3c97c2cSBryan Venteicher vmxnet3_stop_rendezvous(struct vmxnet3_softc *sc) 2351e3c97c2cSBryan Venteicher { 2352e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq; 2353e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq; 2354e3c97c2cSBryan Venteicher int i; 2355e3c97c2cSBryan Venteicher 2356e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nrxqueues; i++) { 2357e3c97c2cSBryan Venteicher rxq = &sc->vmx_rxq[i]; 2358e3c97c2cSBryan Venteicher VMXNET3_RXQ_LOCK(rxq); 2359e3c97c2cSBryan Venteicher VMXNET3_RXQ_UNLOCK(rxq); 2360e3c97c2cSBryan Venteicher } 2361e3c97c2cSBryan Venteicher 2362e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++) { 2363e3c97c2cSBryan Venteicher txq = &sc->vmx_txq[i]; 2364e3c97c2cSBryan Venteicher VMXNET3_TXQ_LOCK(txq); 2365e3c97c2cSBryan Venteicher VMXNET3_TXQ_UNLOCK(txq); 2366e3c97c2cSBryan Venteicher } 2367e3c97c2cSBryan Venteicher } 2368e3c97c2cSBryan Venteicher 2369e3c97c2cSBryan Venteicher static void 2370e3c97c2cSBryan Venteicher vmxnet3_stop(struct vmxnet3_softc *sc) 2371e3c97c2cSBryan Venteicher { 2372e3c97c2cSBryan Venteicher struct ifnet *ifp; 2373e3c97c2cSBryan Venteicher int q; 2374e3c97c2cSBryan Venteicher 2375e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 2376e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK_ASSERT(sc); 2377e3c97c2cSBryan Venteicher 2378e3c97c2cSBryan Venteicher ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2379e3c97c2cSBryan Venteicher sc->vmx_link_active = 0; 2380e3c97c2cSBryan Venteicher callout_stop(&sc->vmx_tick); 2381e3c97c2cSBryan Venteicher 2382e3c97c2cSBryan Venteicher /* Disable interrupts. */ 2383e3c97c2cSBryan Venteicher vmxnet3_disable_all_intrs(sc); 2384e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_DISABLE); 2385e3c97c2cSBryan Venteicher 2386e3c97c2cSBryan Venteicher vmxnet3_stop_rendezvous(sc); 2387e3c97c2cSBryan Venteicher 2388e3c97c2cSBryan Venteicher for (q = 0; q < sc->vmx_ntxqueues; q++) 2389e3c97c2cSBryan Venteicher vmxnet3_txstop(sc, &sc->vmx_txq[q]); 2390e3c97c2cSBryan Venteicher for (q = 0; q < sc->vmx_nrxqueues; q++) 2391e3c97c2cSBryan Venteicher vmxnet3_rxstop(sc, &sc->vmx_rxq[q]); 2392e3c97c2cSBryan Venteicher 2393e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_RESET); 2394e3c97c2cSBryan Venteicher } 2395e3c97c2cSBryan Venteicher 2396e3c97c2cSBryan Venteicher static void 2397e3c97c2cSBryan Venteicher vmxnet3_txinit(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq) 2398e3c97c2cSBryan Venteicher { 2399e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr; 2400e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *txc; 2401e3c97c2cSBryan Venteicher 2402e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 2403e3c97c2cSBryan Venteicher txr->vxtxr_head = 0; 2404e3c97c2cSBryan Venteicher txr->vxtxr_next = 0; 2405e3c97c2cSBryan Venteicher txr->vxtxr_gen = VMXNET3_INIT_GEN; 2406e3c97c2cSBryan Venteicher bzero(txr->vxtxr_txd, 2407e3c97c2cSBryan Venteicher txr->vxtxr_ndesc * sizeof(struct vmxnet3_txdesc)); 2408e3c97c2cSBryan Venteicher 2409e3c97c2cSBryan Venteicher txc = &txq->vxtxq_comp_ring; 2410e3c97c2cSBryan Venteicher txc->vxcr_next = 0; 2411e3c97c2cSBryan Venteicher txc->vxcr_gen = VMXNET3_INIT_GEN; 2412e3c97c2cSBryan Venteicher bzero(txc->vxcr_u.txcd, 2413e3c97c2cSBryan Venteicher txc->vxcr_ndesc * sizeof(struct vmxnet3_txcompdesc)); 2414e3c97c2cSBryan Venteicher } 2415e3c97c2cSBryan Venteicher 2416e3c97c2cSBryan Venteicher static int 2417e3c97c2cSBryan Venteicher vmxnet3_rxinit(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq) 2418e3c97c2cSBryan Venteicher { 2419e3c97c2cSBryan Venteicher struct ifnet *ifp; 2420e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr; 2421e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *rxc; 2422e3c97c2cSBryan Venteicher int i, populate, idx, frame_size, error; 2423e3c97c2cSBryan Venteicher 2424e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 24253c965775SBryan Venteicher frame_size = ETHER_ALIGN + sizeof(struct ether_vlan_header) + 24263c965775SBryan Venteicher ifp->if_mtu; 2427e3c97c2cSBryan Venteicher 2428e3c97c2cSBryan Venteicher /* 24293c965775SBryan Venteicher * If the MTU causes us to exceed what a regular sized cluster can 24303c965775SBryan Venteicher * handle, we allocate a second MJUMPAGESIZE cluster after it in 24313c965775SBryan Venteicher * ring 0. If in use, ring 1 always contains MJUMPAGESIZE clusters. 2432e3c97c2cSBryan Venteicher * 24333c965775SBryan Venteicher * Keep rx_max_chain a divisor of the maximum Rx ring size to make 24343c965775SBryan Venteicher * our life easier. We do not support changing the ring size after 24353c965775SBryan Venteicher * the attach. 2436e3c97c2cSBryan Venteicher */ 24373c965775SBryan Venteicher if (frame_size <= MCLBYTES) 2438e3c97c2cSBryan Venteicher sc->vmx_rx_max_chain = 1; 2439e3c97c2cSBryan Venteicher else 2440e3c97c2cSBryan Venteicher sc->vmx_rx_max_chain = 2; 2441e3c97c2cSBryan Venteicher 2442e3c97c2cSBryan Venteicher /* 2443e3c97c2cSBryan Venteicher * Only populate ring 1 if the configuration will take advantage 2444e3c97c2cSBryan Venteicher * of it. That is either when LRO is enabled or the frame size 2445e3c97c2cSBryan Venteicher * exceeds what ring 0 can contain. 2446e3c97c2cSBryan Venteicher */ 2447e3c97c2cSBryan Venteicher if ((ifp->if_capenable & IFCAP_LRO) == 0 && 2448e3c97c2cSBryan Venteicher frame_size <= MCLBYTES + MJUMPAGESIZE) 2449e3c97c2cSBryan Venteicher populate = 1; 2450e3c97c2cSBryan Venteicher else 2451e3c97c2cSBryan Venteicher populate = VMXNET3_RXRINGS_PERQ; 2452e3c97c2cSBryan Venteicher 2453e3c97c2cSBryan Venteicher for (i = 0; i < populate; i++) { 2454e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i]; 2455e3c97c2cSBryan Venteicher rxr->vxrxr_fill = 0; 2456e3c97c2cSBryan Venteicher rxr->vxrxr_gen = VMXNET3_INIT_GEN; 2457e3c97c2cSBryan Venteicher bzero(rxr->vxrxr_rxd, 2458e3c97c2cSBryan Venteicher rxr->vxrxr_ndesc * sizeof(struct vmxnet3_rxdesc)); 2459e3c97c2cSBryan Venteicher 2460e3c97c2cSBryan Venteicher for (idx = 0; idx < rxr->vxrxr_ndesc; idx++) { 2461e3c97c2cSBryan Venteicher error = vmxnet3_newbuf(sc, rxr); 2462e3c97c2cSBryan Venteicher if (error) 2463e3c97c2cSBryan Venteicher return (error); 2464e3c97c2cSBryan Venteicher } 2465e3c97c2cSBryan Venteicher } 2466e3c97c2cSBryan Venteicher 2467e3c97c2cSBryan Venteicher for (/**/; i < VMXNET3_RXRINGS_PERQ; i++) { 2468e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i]; 2469e3c97c2cSBryan Venteicher rxr->vxrxr_fill = 0; 2470e3c97c2cSBryan Venteicher rxr->vxrxr_gen = 0; 2471e3c97c2cSBryan Venteicher bzero(rxr->vxrxr_rxd, 2472e3c97c2cSBryan Venteicher rxr->vxrxr_ndesc * sizeof(struct vmxnet3_rxdesc)); 2473e3c97c2cSBryan Venteicher } 2474e3c97c2cSBryan Venteicher 2475e3c97c2cSBryan Venteicher rxc = &rxq->vxrxq_comp_ring; 2476e3c97c2cSBryan Venteicher rxc->vxcr_next = 0; 2477e3c97c2cSBryan Venteicher rxc->vxcr_gen = VMXNET3_INIT_GEN; 2478e3c97c2cSBryan Venteicher bzero(rxc->vxcr_u.rxcd, 2479e3c97c2cSBryan Venteicher rxc->vxcr_ndesc * sizeof(struct vmxnet3_rxcompdesc)); 2480e3c97c2cSBryan Venteicher 2481e3c97c2cSBryan Venteicher return (0); 2482e3c97c2cSBryan Venteicher } 2483e3c97c2cSBryan Venteicher 2484e3c97c2cSBryan Venteicher static int 2485e3c97c2cSBryan Venteicher vmxnet3_reinit_queues(struct vmxnet3_softc *sc) 2486e3c97c2cSBryan Venteicher { 2487e3c97c2cSBryan Venteicher device_t dev; 2488e3c97c2cSBryan Venteicher int q, error; 2489e3c97c2cSBryan Venteicher 2490e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 2491e3c97c2cSBryan Venteicher 2492e3c97c2cSBryan Venteicher for (q = 0; q < sc->vmx_ntxqueues; q++) 2493e3c97c2cSBryan Venteicher vmxnet3_txinit(sc, &sc->vmx_txq[q]); 2494e3c97c2cSBryan Venteicher 2495e3c97c2cSBryan Venteicher for (q = 0; q < sc->vmx_nrxqueues; q++) { 2496e3c97c2cSBryan Venteicher error = vmxnet3_rxinit(sc, &sc->vmx_rxq[q]); 2497e3c97c2cSBryan Venteicher if (error) { 2498e3c97c2cSBryan Venteicher device_printf(dev, "cannot populate Rx queue %d\n", q); 2499e3c97c2cSBryan Venteicher return (error); 2500e3c97c2cSBryan Venteicher } 2501e3c97c2cSBryan Venteicher } 2502e3c97c2cSBryan Venteicher 2503e3c97c2cSBryan Venteicher return (0); 2504e3c97c2cSBryan Venteicher } 2505e3c97c2cSBryan Venteicher 2506e3c97c2cSBryan Venteicher static int 2507e3c97c2cSBryan Venteicher vmxnet3_enable_device(struct vmxnet3_softc *sc) 2508e3c97c2cSBryan Venteicher { 2509e3c97c2cSBryan Venteicher int q; 2510e3c97c2cSBryan Venteicher 2511e3c97c2cSBryan Venteicher if (vmxnet3_read_cmd(sc, VMXNET3_CMD_ENABLE) != 0) { 2512e3c97c2cSBryan Venteicher device_printf(sc->vmx_dev, "device enable command failed!\n"); 2513e3c97c2cSBryan Venteicher return (1); 2514e3c97c2cSBryan Venteicher } 2515e3c97c2cSBryan Venteicher 2516e3c97c2cSBryan Venteicher /* Reset the Rx queue heads. */ 2517e3c97c2cSBryan Venteicher for (q = 0; q < sc->vmx_nrxqueues; q++) { 2518e3c97c2cSBryan Venteicher vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH1(q), 0); 2519e3c97c2cSBryan Venteicher vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH2(q), 0); 2520e3c97c2cSBryan Venteicher } 2521e3c97c2cSBryan Venteicher 2522e3c97c2cSBryan Venteicher return (0); 2523e3c97c2cSBryan Venteicher } 2524e3c97c2cSBryan Venteicher 2525e3c97c2cSBryan Venteicher static void 2526e3c97c2cSBryan Venteicher vmxnet3_reinit_rxfilters(struct vmxnet3_softc *sc) 2527e3c97c2cSBryan Venteicher { 2528e3c97c2cSBryan Venteicher struct ifnet *ifp; 2529e3c97c2cSBryan Venteicher 2530e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 2531e3c97c2cSBryan Venteicher 2532e3c97c2cSBryan Venteicher vmxnet3_set_rxfilter(sc); 2533e3c97c2cSBryan Venteicher 2534e3c97c2cSBryan Venteicher if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) 2535e3c97c2cSBryan Venteicher bcopy(sc->vmx_vlan_filter, sc->vmx_ds->vlan_filter, 2536e3c97c2cSBryan Venteicher sizeof(sc->vmx_ds->vlan_filter)); 2537e3c97c2cSBryan Venteicher else 2538e3c97c2cSBryan Venteicher bzero(sc->vmx_ds->vlan_filter, 2539e3c97c2cSBryan Venteicher sizeof(sc->vmx_ds->vlan_filter)); 2540e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_VLAN_FILTER); 2541e3c97c2cSBryan Venteicher } 2542e3c97c2cSBryan Venteicher 2543e3c97c2cSBryan Venteicher static int 2544e3c97c2cSBryan Venteicher vmxnet3_reinit(struct vmxnet3_softc *sc) 2545e3c97c2cSBryan Venteicher { 2546e3c97c2cSBryan Venteicher 2547e3c97c2cSBryan Venteicher vmxnet3_reinit_interface(sc); 2548e3c97c2cSBryan Venteicher vmxnet3_reinit_shared_data(sc); 2549e3c97c2cSBryan Venteicher 2550e3c97c2cSBryan Venteicher if (vmxnet3_reinit_queues(sc) != 0) 2551e3c97c2cSBryan Venteicher return (ENXIO); 2552e3c97c2cSBryan Venteicher 2553e3c97c2cSBryan Venteicher if (vmxnet3_enable_device(sc) != 0) 2554e3c97c2cSBryan Venteicher return (ENXIO); 2555e3c97c2cSBryan Venteicher 2556e3c97c2cSBryan Venteicher vmxnet3_reinit_rxfilters(sc); 2557e3c97c2cSBryan Venteicher 2558e3c97c2cSBryan Venteicher return (0); 2559e3c97c2cSBryan Venteicher } 2560e3c97c2cSBryan Venteicher 2561e3c97c2cSBryan Venteicher static void 2562e3c97c2cSBryan Venteicher vmxnet3_init_locked(struct vmxnet3_softc *sc) 2563e3c97c2cSBryan Venteicher { 2564e3c97c2cSBryan Venteicher struct ifnet *ifp; 2565e3c97c2cSBryan Venteicher 2566e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 2567e3c97c2cSBryan Venteicher 2568e3c97c2cSBryan Venteicher if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2569e3c97c2cSBryan Venteicher return; 2570e3c97c2cSBryan Venteicher 2571e3c97c2cSBryan Venteicher vmxnet3_stop(sc); 2572e3c97c2cSBryan Venteicher 2573e3c97c2cSBryan Venteicher if (vmxnet3_reinit(sc) != 0) { 2574e3c97c2cSBryan Venteicher vmxnet3_stop(sc); 2575e3c97c2cSBryan Venteicher return; 2576e3c97c2cSBryan Venteicher } 2577e3c97c2cSBryan Venteicher 2578e3c97c2cSBryan Venteicher ifp->if_drv_flags |= IFF_DRV_RUNNING; 2579e3c97c2cSBryan Venteicher vmxnet3_link_status(sc); 2580e3c97c2cSBryan Venteicher 2581e3c97c2cSBryan Venteicher vmxnet3_enable_all_intrs(sc); 2582e3c97c2cSBryan Venteicher callout_reset(&sc->vmx_tick, hz, vmxnet3_tick, sc); 2583e3c97c2cSBryan Venteicher } 2584e3c97c2cSBryan Venteicher 2585e3c97c2cSBryan Venteicher static void 2586e3c97c2cSBryan Venteicher vmxnet3_init(void *xsc) 2587e3c97c2cSBryan Venteicher { 2588e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 2589e3c97c2cSBryan Venteicher 2590e3c97c2cSBryan Venteicher sc = xsc; 2591e3c97c2cSBryan Venteicher 2592e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK(sc); 2593e3c97c2cSBryan Venteicher vmxnet3_init_locked(sc); 2594e3c97c2cSBryan Venteicher VMXNET3_CORE_UNLOCK(sc); 2595e3c97c2cSBryan Venteicher } 2596e3c97c2cSBryan Venteicher 2597e3c97c2cSBryan Venteicher /* 2598e3c97c2cSBryan Venteicher * BMV: Much of this can go away once we finally have offsets in 2599e3c97c2cSBryan Venteicher * the mbuf packet header. Bug andre@. 2600e3c97c2cSBryan Venteicher */ 2601e3c97c2cSBryan Venteicher static int 2602*e557c1ddSBryan Venteicher vmxnet3_txq_offload_ctx(struct vmxnet3_txqueue *txq, struct mbuf *m, 2603*e557c1ddSBryan Venteicher int *etype, int *proto, int *start) 2604e3c97c2cSBryan Venteicher { 2605e3c97c2cSBryan Venteicher struct ether_vlan_header *evh; 2606e3c97c2cSBryan Venteicher int offset; 2607e3c97c2cSBryan Venteicher 2608e3c97c2cSBryan Venteicher evh = mtod(m, struct ether_vlan_header *); 2609e3c97c2cSBryan Venteicher if (evh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 2610e3c97c2cSBryan Venteicher /* BMV: We should handle nested VLAN tags too. */ 2611e3c97c2cSBryan Venteicher *etype = ntohs(evh->evl_proto); 2612e3c97c2cSBryan Venteicher offset = sizeof(struct ether_vlan_header); 2613e3c97c2cSBryan Venteicher } else { 2614e3c97c2cSBryan Venteicher *etype = ntohs(evh->evl_encap_proto); 2615e3c97c2cSBryan Venteicher offset = sizeof(struct ether_header); 2616e3c97c2cSBryan Venteicher } 2617e3c97c2cSBryan Venteicher 2618e3c97c2cSBryan Venteicher switch (*etype) { 2619e3c97c2cSBryan Venteicher #if defined(INET) 2620e3c97c2cSBryan Venteicher case ETHERTYPE_IP: { 2621e3c97c2cSBryan Venteicher struct ip *ip, iphdr; 2622e3c97c2cSBryan Venteicher if (__predict_false(m->m_len < offset + sizeof(struct ip))) { 2623e3c97c2cSBryan Venteicher m_copydata(m, offset, sizeof(struct ip), 2624e3c97c2cSBryan Venteicher (caddr_t) &iphdr); 2625e3c97c2cSBryan Venteicher ip = &iphdr; 2626e3c97c2cSBryan Venteicher } else 2627*e557c1ddSBryan Venteicher ip = mtodo(m, offset); 2628e3c97c2cSBryan Venteicher *proto = ip->ip_p; 2629e3c97c2cSBryan Venteicher *start = offset + (ip->ip_hl << 2); 2630e3c97c2cSBryan Venteicher break; 2631e3c97c2cSBryan Venteicher } 2632e3c97c2cSBryan Venteicher #endif 2633e3c97c2cSBryan Venteicher #if defined(INET6) 2634e3c97c2cSBryan Venteicher case ETHERTYPE_IPV6: 2635e3c97c2cSBryan Venteicher *proto = -1; 2636e3c97c2cSBryan Venteicher *start = ip6_lasthdr(m, offset, IPPROTO_IPV6, proto); 2637e3c97c2cSBryan Venteicher /* Assert the network stack sent us a valid packet. */ 2638e3c97c2cSBryan Venteicher KASSERT(*start > offset, 2639e3c97c2cSBryan Venteicher ("%s: mbuf %p start %d offset %d proto %d", __func__, m, 2640e3c97c2cSBryan Venteicher *start, offset, *proto)); 2641e3c97c2cSBryan Venteicher break; 2642e3c97c2cSBryan Venteicher #endif 2643e3c97c2cSBryan Venteicher default: 2644e3c97c2cSBryan Venteicher return (EINVAL); 2645e3c97c2cSBryan Venteicher } 2646e3c97c2cSBryan Venteicher 2647e3c97c2cSBryan Venteicher if (m->m_pkthdr.csum_flags & CSUM_TSO) { 2648e3c97c2cSBryan Venteicher struct tcphdr *tcp, tcphdr; 2649e3c97c2cSBryan Venteicher 2650e3c97c2cSBryan Venteicher if (__predict_false(*proto != IPPROTO_TCP)) { 2651e3c97c2cSBryan Venteicher /* Likely failed to correctly parse the mbuf. */ 2652e3c97c2cSBryan Venteicher return (EINVAL); 2653e3c97c2cSBryan Venteicher } 2654e3c97c2cSBryan Venteicher 2655*e557c1ddSBryan Venteicher txq->vxtxq_stats.vmtxs_tso++; 2656e3c97c2cSBryan Venteicher 2657e3c97c2cSBryan Venteicher /* 2658e3c97c2cSBryan Venteicher * For TSO, the size of the protocol header is also 2659e3c97c2cSBryan Venteicher * included in the descriptor header size. 2660e3c97c2cSBryan Venteicher */ 2661*e557c1ddSBryan Venteicher if (m->m_len < *start + sizeof(struct tcphdr)) { 2662*e557c1ddSBryan Venteicher m_copydata(m, offset, sizeof(struct tcphdr), 2663*e557c1ddSBryan Venteicher (caddr_t) &tcphdr); 2664*e557c1ddSBryan Venteicher tcp = &tcphdr; 2665*e557c1ddSBryan Venteicher } else 2666*e557c1ddSBryan Venteicher tcp = mtodo(m, *start); 2667e3c97c2cSBryan Venteicher *start += (tcp->th_off << 2); 2668*e557c1ddSBryan Venteicher } else 2669*e557c1ddSBryan Venteicher txq->vxtxq_stats.vmtxs_csum++; 2670e3c97c2cSBryan Venteicher 2671e3c97c2cSBryan Venteicher return (0); 2672e3c97c2cSBryan Venteicher } 2673e3c97c2cSBryan Venteicher 2674e3c97c2cSBryan Venteicher static int 2675e3c97c2cSBryan Venteicher vmxnet3_txq_load_mbuf(struct vmxnet3_txqueue *txq, struct mbuf **m0, 2676e3c97c2cSBryan Venteicher bus_dmamap_t dmap, bus_dma_segment_t segs[], int *nsegs) 2677e3c97c2cSBryan Venteicher { 2678e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr; 2679e3c97c2cSBryan Venteicher struct mbuf *m; 2680e3c97c2cSBryan Venteicher bus_dma_tag_t tag; 2681*e557c1ddSBryan Venteicher int error; 2682e3c97c2cSBryan Venteicher 2683e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 2684e3c97c2cSBryan Venteicher m = *m0; 2685e3c97c2cSBryan Venteicher tag = txr->vxtxr_txtag; 2686e3c97c2cSBryan Venteicher 2687e3c97c2cSBryan Venteicher error = bus_dmamap_load_mbuf_sg(tag, dmap, m, segs, nsegs, 0); 2688e3c97c2cSBryan Venteicher if (error == 0 || error != EFBIG) 2689e3c97c2cSBryan Venteicher return (error); 2690e3c97c2cSBryan Venteicher 2691*e557c1ddSBryan Venteicher m = m_defrag(m, M_NOWAIT); 2692e3c97c2cSBryan Venteicher if (m != NULL) { 2693e3c97c2cSBryan Venteicher *m0 = m; 2694e3c97c2cSBryan Venteicher error = bus_dmamap_load_mbuf_sg(tag, dmap, m, segs, nsegs, 0); 2695e3c97c2cSBryan Venteicher } else 2696e3c97c2cSBryan Venteicher error = ENOBUFS; 2697e3c97c2cSBryan Venteicher 2698e3c97c2cSBryan Venteicher if (error) { 2699e3c97c2cSBryan Venteicher m_freem(*m0); 2700e3c97c2cSBryan Venteicher *m0 = NULL; 2701*e557c1ddSBryan Venteicher txq->vxtxq_sc->vmx_stats.vmst_defrag_failed++; 2702e3c97c2cSBryan Venteicher } else 2703*e557c1ddSBryan Venteicher txq->vxtxq_sc->vmx_stats.vmst_defragged++; 2704e3c97c2cSBryan Venteicher 2705e3c97c2cSBryan Venteicher return (error); 2706e3c97c2cSBryan Venteicher } 2707e3c97c2cSBryan Venteicher 2708e3c97c2cSBryan Venteicher static void 2709e3c97c2cSBryan Venteicher vmxnet3_txq_unload_mbuf(struct vmxnet3_txqueue *txq, bus_dmamap_t dmap) 2710e3c97c2cSBryan Venteicher { 2711e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr; 2712e3c97c2cSBryan Venteicher 2713e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 2714e3c97c2cSBryan Venteicher bus_dmamap_unload(txr->vxtxr_txtag, dmap); 2715e3c97c2cSBryan Venteicher } 2716e3c97c2cSBryan Venteicher 2717e3c97c2cSBryan Venteicher static int 2718e3c97c2cSBryan Venteicher vmxnet3_txq_encap(struct vmxnet3_txqueue *txq, struct mbuf **m0) 2719e3c97c2cSBryan Venteicher { 2720e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 2721e3c97c2cSBryan Venteicher struct ifnet *ifp; 2722e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr; 2723e3c97c2cSBryan Venteicher struct vmxnet3_txdesc *txd, *sop; 2724e3c97c2cSBryan Venteicher struct mbuf *m; 2725e3c97c2cSBryan Venteicher bus_dmamap_t dmap; 2726e3c97c2cSBryan Venteicher bus_dma_segment_t segs[VMXNET3_TX_MAXSEGS]; 2727e3c97c2cSBryan Venteicher int i, gen, nsegs, etype, proto, start, error; 2728e3c97c2cSBryan Venteicher 2729e3c97c2cSBryan Venteicher sc = txq->vxtxq_sc; 2730e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 2731e3c97c2cSBryan Venteicher start = 0; 2732e3c97c2cSBryan Venteicher txd = NULL; 2733e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 2734e3c97c2cSBryan Venteicher dmap = txr->vxtxr_txbuf[txr->vxtxr_head].vtxb_dmamap; 2735e3c97c2cSBryan Venteicher 2736e3c97c2cSBryan Venteicher error = vmxnet3_txq_load_mbuf(txq, m0, dmap, segs, &nsegs); 2737e3c97c2cSBryan Venteicher if (error) 2738e3c97c2cSBryan Venteicher return (error); 2739e3c97c2cSBryan Venteicher 2740e3c97c2cSBryan Venteicher m = *m0; 2741e3c97c2cSBryan Venteicher M_ASSERTPKTHDR(m); 2742e3c97c2cSBryan Venteicher KASSERT(nsegs <= VMXNET3_TX_MAXSEGS, 2743e3c97c2cSBryan Venteicher ("%s: mbuf %p with too many segments %d", __func__, m, nsegs)); 2744e3c97c2cSBryan Venteicher 2745e3c97c2cSBryan Venteicher if (VMXNET3_TXRING_AVAIL(txr) < nsegs) { 2746*e557c1ddSBryan Venteicher txq->vxtxq_stats.vmtxs_full++; 2747e3c97c2cSBryan Venteicher vmxnet3_txq_unload_mbuf(txq, dmap); 2748e3c97c2cSBryan Venteicher return (ENOSPC); 2749e3c97c2cSBryan Venteicher } else if (m->m_pkthdr.csum_flags & VMXNET3_CSUM_ALL_OFFLOAD) { 2750*e557c1ddSBryan Venteicher error = vmxnet3_txq_offload_ctx(txq, m, &etype, &proto, &start); 2751e3c97c2cSBryan Venteicher if (error) { 2752*e557c1ddSBryan Venteicher txq->vxtxq_stats.vmtxs_offload_failed++; 2753e3c97c2cSBryan Venteicher vmxnet3_txq_unload_mbuf(txq, dmap); 2754e3c97c2cSBryan Venteicher m_freem(m); 2755e3c97c2cSBryan Venteicher *m0 = NULL; 2756e3c97c2cSBryan Venteicher return (error); 2757e3c97c2cSBryan Venteicher } 2758e3c97c2cSBryan Venteicher } 2759e3c97c2cSBryan Venteicher 2760e3c97c2cSBryan Venteicher txr->vxtxr_txbuf[txr->vxtxr_head].vtxb_m = m = *m0; 2761e3c97c2cSBryan Venteicher sop = &txr->vxtxr_txd[txr->vxtxr_head]; 2762e3c97c2cSBryan Venteicher gen = txr->vxtxr_gen ^ 1; /* Owned by cpu (yet) */ 2763e3c97c2cSBryan Venteicher 2764e3c97c2cSBryan Venteicher for (i = 0; i < nsegs; i++) { 2765e3c97c2cSBryan Venteicher txd = &txr->vxtxr_txd[txr->vxtxr_head]; 2766e3c97c2cSBryan Venteicher 2767e3c97c2cSBryan Venteicher txd->addr = segs[i].ds_addr; 2768e3c97c2cSBryan Venteicher txd->len = segs[i].ds_len; 2769e3c97c2cSBryan Venteicher txd->gen = gen; 2770e3c97c2cSBryan Venteicher txd->dtype = 0; 2771e3c97c2cSBryan Venteicher txd->offload_mode = VMXNET3_OM_NONE; 2772e3c97c2cSBryan Venteicher txd->offload_pos = 0; 2773e3c97c2cSBryan Venteicher txd->hlen = 0; 2774e3c97c2cSBryan Venteicher txd->eop = 0; 2775e3c97c2cSBryan Venteicher txd->compreq = 0; 2776e3c97c2cSBryan Venteicher txd->vtag_mode = 0; 2777e3c97c2cSBryan Venteicher txd->vtag = 0; 2778e3c97c2cSBryan Venteicher 2779e3c97c2cSBryan Venteicher if (++txr->vxtxr_head == txr->vxtxr_ndesc) { 2780e3c97c2cSBryan Venteicher txr->vxtxr_head = 0; 2781e3c97c2cSBryan Venteicher txr->vxtxr_gen ^= 1; 2782e3c97c2cSBryan Venteicher } 2783e3c97c2cSBryan Venteicher gen = txr->vxtxr_gen; 2784e3c97c2cSBryan Venteicher } 2785e3c97c2cSBryan Venteicher txd->eop = 1; 2786e3c97c2cSBryan Venteicher txd->compreq = 1; 2787e3c97c2cSBryan Venteicher 2788e3c97c2cSBryan Venteicher if (m->m_flags & M_VLANTAG) { 2789e3c97c2cSBryan Venteicher sop->vtag_mode = 1; 2790e3c97c2cSBryan Venteicher sop->vtag = m->m_pkthdr.ether_vtag; 2791e3c97c2cSBryan Venteicher } 2792e3c97c2cSBryan Venteicher 2793e3c97c2cSBryan Venteicher if (m->m_pkthdr.csum_flags & CSUM_TSO) { 2794e3c97c2cSBryan Venteicher sop->offload_mode = VMXNET3_OM_TSO; 2795e3c97c2cSBryan Venteicher sop->hlen = start; 2796e3c97c2cSBryan Venteicher sop->offload_pos = m->m_pkthdr.tso_segsz; 2797e3c97c2cSBryan Venteicher } else if (m->m_pkthdr.csum_flags & (VMXNET3_CSUM_OFFLOAD | 2798e3c97c2cSBryan Venteicher VMXNET3_CSUM_OFFLOAD_IPV6)) { 2799e3c97c2cSBryan Venteicher sop->offload_mode = VMXNET3_OM_CSUM; 2800e3c97c2cSBryan Venteicher sop->hlen = start; 2801e3c97c2cSBryan Venteicher sop->offload_pos = start + m->m_pkthdr.csum_data; 2802e3c97c2cSBryan Venteicher } 2803e3c97c2cSBryan Venteicher 2804e3c97c2cSBryan Venteicher /* Finally, change the ownership. */ 2805e3c97c2cSBryan Venteicher vmxnet3_barrier(sc, VMXNET3_BARRIER_WR); 2806e3c97c2cSBryan Venteicher sop->gen ^= 1; 2807e3c97c2cSBryan Venteicher 2808e3c97c2cSBryan Venteicher if (++txq->vxtxq_ts->npending >= txq->vxtxq_ts->intr_threshold) { 2809e3c97c2cSBryan Venteicher txq->vxtxq_ts->npending = 0; 2810e3c97c2cSBryan Venteicher vmxnet3_write_bar0(sc, VMXNET3_BAR0_TXH(txq->vxtxq_id), 2811e3c97c2cSBryan Venteicher txr->vxtxr_head); 2812e3c97c2cSBryan Venteicher } 2813e3c97c2cSBryan Venteicher 2814e3c97c2cSBryan Venteicher return (0); 2815e3c97c2cSBryan Venteicher } 2816e3c97c2cSBryan Venteicher 2817e3c97c2cSBryan Venteicher static void 2818*e557c1ddSBryan Venteicher vmxnet3_txq_update_pending(struct vmxnet3_txqueue *txq) 2819*e557c1ddSBryan Venteicher { 2820*e557c1ddSBryan Venteicher struct vmxnet3_txring *txr; 2821*e557c1ddSBryan Venteicher 2822*e557c1ddSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 2823*e557c1ddSBryan Venteicher 2824*e557c1ddSBryan Venteicher if (txq->vxtxq_ts->npending > 0) { 2825*e557c1ddSBryan Venteicher txq->vxtxq_ts->npending = 0; 2826*e557c1ddSBryan Venteicher vmxnet3_write_bar0(txq->vxtxq_sc, 2827*e557c1ddSBryan Venteicher VMXNET3_BAR0_TXH(txq->vxtxq_id), txr->vxtxr_head); 2828*e557c1ddSBryan Venteicher } 2829*e557c1ddSBryan Venteicher } 2830*e557c1ddSBryan Venteicher 2831*e557c1ddSBryan Venteicher #ifdef VMXNET3_LEGACY_TX 2832*e557c1ddSBryan Venteicher 2833*e557c1ddSBryan Venteicher static void 2834e3c97c2cSBryan Venteicher vmxnet3_start_locked(struct ifnet *ifp) 2835e3c97c2cSBryan Venteicher { 2836e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 2837e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq; 2838e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr; 2839e3c97c2cSBryan Venteicher struct mbuf *m_head; 28403c5dfe89SBryan Venteicher int tx, avail; 2841e3c97c2cSBryan Venteicher 2842e3c97c2cSBryan Venteicher sc = ifp->if_softc; 2843e3c97c2cSBryan Venteicher txq = &sc->vmx_txq[0]; 2844e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 2845e3c97c2cSBryan Venteicher tx = 0; 2846e3c97c2cSBryan Venteicher 2847e3c97c2cSBryan Venteicher VMXNET3_TXQ_LOCK_ASSERT(txq); 2848e3c97c2cSBryan Venteicher 2849e3c97c2cSBryan Venteicher if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 2850e3c97c2cSBryan Venteicher sc->vmx_link_active == 0) 2851e3c97c2cSBryan Venteicher return; 2852e3c97c2cSBryan Venteicher 28533c5dfe89SBryan Venteicher while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 28543c5dfe89SBryan Venteicher if ((avail = VMXNET3_TXRING_AVAIL(txr)) < 2) 28553c5dfe89SBryan Venteicher break; 28563c5dfe89SBryan Venteicher 2857e3c97c2cSBryan Venteicher IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 2858e3c97c2cSBryan Venteicher if (m_head == NULL) 2859e3c97c2cSBryan Venteicher break; 2860e3c97c2cSBryan Venteicher 28613c5dfe89SBryan Venteicher /* Assume worse case if this mbuf is the head of a chain. */ 28623c5dfe89SBryan Venteicher if (m_head->m_next != NULL && avail < VMXNET3_TX_MAXSEGS) { 28633c5dfe89SBryan Venteicher IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 28643c5dfe89SBryan Venteicher break; 28653c5dfe89SBryan Venteicher } 28663c5dfe89SBryan Venteicher 2867e3c97c2cSBryan Venteicher if (vmxnet3_txq_encap(txq, &m_head) != 0) { 2868e3c97c2cSBryan Venteicher if (m_head != NULL) 2869e3c97c2cSBryan Venteicher IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 2870e3c97c2cSBryan Venteicher break; 2871e3c97c2cSBryan Venteicher } 2872e3c97c2cSBryan Venteicher 2873e3c97c2cSBryan Venteicher tx++; 2874e3c97c2cSBryan Venteicher ETHER_BPF_MTAP(ifp, m_head); 2875e3c97c2cSBryan Venteicher } 2876e3c97c2cSBryan Venteicher 2877e3c97c2cSBryan Venteicher if (tx > 0) { 2878*e557c1ddSBryan Venteicher vmxnet3_txq_update_pending(txq); 2879e3c97c2cSBryan Venteicher txq->vxtxq_watchdog = VMXNET3_WATCHDOG_TIMEOUT; 2880e3c97c2cSBryan Venteicher } 2881e3c97c2cSBryan Venteicher } 2882e3c97c2cSBryan Venteicher 2883e3c97c2cSBryan Venteicher static void 2884e3c97c2cSBryan Venteicher vmxnet3_start(struct ifnet *ifp) 2885e3c97c2cSBryan Venteicher { 2886e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 2887e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq; 2888e3c97c2cSBryan Venteicher 2889e3c97c2cSBryan Venteicher sc = ifp->if_softc; 2890e3c97c2cSBryan Venteicher txq = &sc->vmx_txq[0]; 2891e3c97c2cSBryan Venteicher 2892e3c97c2cSBryan Venteicher VMXNET3_TXQ_LOCK(txq); 2893e3c97c2cSBryan Venteicher vmxnet3_start_locked(ifp); 2894e3c97c2cSBryan Venteicher VMXNET3_TXQ_UNLOCK(txq); 2895e3c97c2cSBryan Venteicher } 2896e3c97c2cSBryan Venteicher 2897*e557c1ddSBryan Venteicher #else /* !VMXNET3_LEGACY_TX */ 2898*e557c1ddSBryan Venteicher 2899*e557c1ddSBryan Venteicher static int 2900*e557c1ddSBryan Venteicher vmxnet3_txq_mq_start_locked(struct vmxnet3_txqueue *txq, struct mbuf *m) 2901*e557c1ddSBryan Venteicher { 2902*e557c1ddSBryan Venteicher struct vmxnet3_softc *sc; 2903*e557c1ddSBryan Venteicher struct vmxnet3_txring *txr; 2904*e557c1ddSBryan Venteicher struct buf_ring *br; 2905*e557c1ddSBryan Venteicher struct ifnet *ifp; 2906*e557c1ddSBryan Venteicher int tx, avail, error; 2907*e557c1ddSBryan Venteicher 2908*e557c1ddSBryan Venteicher sc = txq->vxtxq_sc; 2909*e557c1ddSBryan Venteicher br = txq->vxtxq_br; 2910*e557c1ddSBryan Venteicher ifp = sc->vmx_ifp; 2911*e557c1ddSBryan Venteicher txr = &txq->vxtxq_cmd_ring; 2912*e557c1ddSBryan Venteicher tx = 0; 2913*e557c1ddSBryan Venteicher error = 0; 2914*e557c1ddSBryan Venteicher 2915*e557c1ddSBryan Venteicher VMXNET3_TXQ_LOCK_ASSERT(txq); 2916*e557c1ddSBryan Venteicher 2917*e557c1ddSBryan Venteicher if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 2918*e557c1ddSBryan Venteicher sc->vmx_link_active == 0) { 2919*e557c1ddSBryan Venteicher if (m != NULL) 2920*e557c1ddSBryan Venteicher error = drbr_enqueue(ifp, br, m); 2921*e557c1ddSBryan Venteicher return (error); 2922*e557c1ddSBryan Venteicher } 2923*e557c1ddSBryan Venteicher 2924*e557c1ddSBryan Venteicher if (m != NULL) { 2925*e557c1ddSBryan Venteicher error = drbr_enqueue(ifp, br, m); 2926*e557c1ddSBryan Venteicher if (error) 2927*e557c1ddSBryan Venteicher return (error); 2928*e557c1ddSBryan Venteicher } 2929*e557c1ddSBryan Venteicher 2930*e557c1ddSBryan Venteicher while ((avail = VMXNET3_TXRING_AVAIL(txr)) >= 2) { 2931*e557c1ddSBryan Venteicher m = drbr_peek(ifp, br); 2932*e557c1ddSBryan Venteicher if (m == NULL) 2933*e557c1ddSBryan Venteicher break; 2934*e557c1ddSBryan Venteicher 2935*e557c1ddSBryan Venteicher /* Assume worse case if this mbuf is the head of a chain. */ 2936*e557c1ddSBryan Venteicher if (m->m_next != NULL && avail < VMXNET3_TX_MAXSEGS) { 2937*e557c1ddSBryan Venteicher drbr_putback(ifp, br, m); 2938*e557c1ddSBryan Venteicher error = ENOBUFS; 2939*e557c1ddSBryan Venteicher break; 2940*e557c1ddSBryan Venteicher } 2941*e557c1ddSBryan Venteicher 2942*e557c1ddSBryan Venteicher error = vmxnet3_txq_encap(txq, &m); 2943*e557c1ddSBryan Venteicher if (error) { 2944*e557c1ddSBryan Venteicher if (m != NULL) 2945*e557c1ddSBryan Venteicher drbr_putback(ifp, br, m); 2946*e557c1ddSBryan Venteicher else 2947*e557c1ddSBryan Venteicher drbr_advance(ifp, br); 2948*e557c1ddSBryan Venteicher break; 2949*e557c1ddSBryan Venteicher } 2950*e557c1ddSBryan Venteicher drbr_advance(ifp, br); 2951*e557c1ddSBryan Venteicher 2952*e557c1ddSBryan Venteicher tx++; 2953*e557c1ddSBryan Venteicher ETHER_BPF_MTAP(ifp, m); 2954*e557c1ddSBryan Venteicher } 2955*e557c1ddSBryan Venteicher 2956*e557c1ddSBryan Venteicher if (tx > 0) { 2957*e557c1ddSBryan Venteicher vmxnet3_txq_update_pending(txq); 2958*e557c1ddSBryan Venteicher txq->vxtxq_watchdog = VMXNET3_WATCHDOG_TIMEOUT; 2959*e557c1ddSBryan Venteicher } 2960*e557c1ddSBryan Venteicher 2961*e557c1ddSBryan Venteicher return (error); 2962*e557c1ddSBryan Venteicher } 2963*e557c1ddSBryan Venteicher 2964*e557c1ddSBryan Venteicher static int 2965*e557c1ddSBryan Venteicher vmxnet3_txq_mq_start(struct ifnet *ifp, struct mbuf *m) 2966*e557c1ddSBryan Venteicher { 2967*e557c1ddSBryan Venteicher struct vmxnet3_softc *sc; 2968*e557c1ddSBryan Venteicher struct vmxnet3_txqueue *txq; 2969*e557c1ddSBryan Venteicher int i, ntxq, error; 2970*e557c1ddSBryan Venteicher 2971*e557c1ddSBryan Venteicher sc = ifp->if_softc; 2972*e557c1ddSBryan Venteicher ntxq = sc->vmx_ntxqueues; 2973*e557c1ddSBryan Venteicher 2974*e557c1ddSBryan Venteicher if (m->m_flags & M_FLOWID) 2975*e557c1ddSBryan Venteicher i = m->m_pkthdr.flowid % ntxq; 2976*e557c1ddSBryan Venteicher else 2977*e557c1ddSBryan Venteicher i = curcpu % ntxq; 2978*e557c1ddSBryan Venteicher 2979*e557c1ddSBryan Venteicher txq = &sc->vmx_txq[i]; 2980*e557c1ddSBryan Venteicher 2981*e557c1ddSBryan Venteicher if (VMXNET3_TXQ_TRYLOCK(txq) != 0) { 2982*e557c1ddSBryan Venteicher error = vmxnet3_txq_mq_start_locked(txq, m); 2983*e557c1ddSBryan Venteicher VMXNET3_TXQ_UNLOCK(txq); 2984*e557c1ddSBryan Venteicher } else { 2985*e557c1ddSBryan Venteicher error = drbr_enqueue(ifp, txq->vxtxq_br, m); 2986*e557c1ddSBryan Venteicher taskqueue_enqueue(sc->vmx_tq, &txq->vxtxq_defrtask); 2987*e557c1ddSBryan Venteicher } 2988*e557c1ddSBryan Venteicher 2989*e557c1ddSBryan Venteicher return (error); 2990*e557c1ddSBryan Venteicher } 2991*e557c1ddSBryan Venteicher 2992*e557c1ddSBryan Venteicher static void 2993*e557c1ddSBryan Venteicher vmxnet3_txq_tq_deferred(void *xtxq, int pending) 2994*e557c1ddSBryan Venteicher { 2995*e557c1ddSBryan Venteicher struct vmxnet3_softc *sc; 2996*e557c1ddSBryan Venteicher struct vmxnet3_txqueue *txq; 2997*e557c1ddSBryan Venteicher 2998*e557c1ddSBryan Venteicher txq = xtxq; 2999*e557c1ddSBryan Venteicher sc = txq->vxtxq_sc; 3000*e557c1ddSBryan Venteicher 3001*e557c1ddSBryan Venteicher VMXNET3_TXQ_LOCK(txq); 3002*e557c1ddSBryan Venteicher if (!drbr_empty(sc->vmx_ifp, txq->vxtxq_br)) 3003*e557c1ddSBryan Venteicher vmxnet3_txq_mq_start_locked(txq, NULL); 3004*e557c1ddSBryan Venteicher VMXNET3_TXQ_UNLOCK(txq); 3005*e557c1ddSBryan Venteicher } 3006*e557c1ddSBryan Venteicher 3007*e557c1ddSBryan Venteicher #endif /* VMXNET3_LEGACY_TX */ 3008*e557c1ddSBryan Venteicher 3009*e557c1ddSBryan Venteicher static void 3010*e557c1ddSBryan Venteicher vmxnet3_txq_start(struct vmxnet3_txqueue *txq) 3011*e557c1ddSBryan Venteicher { 3012*e557c1ddSBryan Venteicher struct vmxnet3_softc *sc; 3013*e557c1ddSBryan Venteicher struct ifnet *ifp; 3014*e557c1ddSBryan Venteicher 3015*e557c1ddSBryan Venteicher sc = txq->vxtxq_sc; 3016*e557c1ddSBryan Venteicher ifp = sc->vmx_ifp; 3017*e557c1ddSBryan Venteicher 3018*e557c1ddSBryan Venteicher #ifdef VMXNET3_LEGACY_TX 3019*e557c1ddSBryan Venteicher if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 3020*e557c1ddSBryan Venteicher vmxnet3_start_locked(ifp); 3021*e557c1ddSBryan Venteicher #else 3022*e557c1ddSBryan Venteicher if (!drbr_empty(ifp, txq->vxtxq_br)) 3023*e557c1ddSBryan Venteicher vmxnet3_txq_mq_start_locked(txq, NULL); 3024*e557c1ddSBryan Venteicher #endif 3025*e557c1ddSBryan Venteicher } 3026*e557c1ddSBryan Venteicher 3027*e557c1ddSBryan Venteicher static void 3028*e557c1ddSBryan Venteicher vmxnet3_tx_start_all(struct vmxnet3_softc *sc) 3029*e557c1ddSBryan Venteicher { 3030*e557c1ddSBryan Venteicher struct vmxnet3_txqueue *txq; 3031*e557c1ddSBryan Venteicher int i; 3032*e557c1ddSBryan Venteicher 3033*e557c1ddSBryan Venteicher VMXNET3_CORE_LOCK_ASSERT(sc); 3034*e557c1ddSBryan Venteicher 3035*e557c1ddSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++) { 3036*e557c1ddSBryan Venteicher txq = &sc->vmx_txq[i]; 3037*e557c1ddSBryan Venteicher 3038*e557c1ddSBryan Venteicher VMXNET3_TXQ_LOCK(txq); 3039*e557c1ddSBryan Venteicher vmxnet3_txq_start(txq); 3040*e557c1ddSBryan Venteicher VMXNET3_TXQ_UNLOCK(txq); 3041*e557c1ddSBryan Venteicher } 3042*e557c1ddSBryan Venteicher } 3043*e557c1ddSBryan Venteicher 3044e3c97c2cSBryan Venteicher static void 3045e3c97c2cSBryan Venteicher vmxnet3_update_vlan_filter(struct vmxnet3_softc *sc, int add, uint16_t tag) 3046e3c97c2cSBryan Venteicher { 3047e3c97c2cSBryan Venteicher struct ifnet *ifp; 3048e3c97c2cSBryan Venteicher int idx, bit; 3049e3c97c2cSBryan Venteicher 3050e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 3051e3c97c2cSBryan Venteicher idx = (tag >> 5) & 0x7F; 3052e3c97c2cSBryan Venteicher bit = tag & 0x1F; 3053e3c97c2cSBryan Venteicher 3054e3c97c2cSBryan Venteicher if (tag == 0 || tag > 4095) 3055e3c97c2cSBryan Venteicher return; 3056e3c97c2cSBryan Venteicher 3057e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK(sc); 3058e3c97c2cSBryan Venteicher 3059e3c97c2cSBryan Venteicher /* Update our private VLAN bitvector. */ 3060e3c97c2cSBryan Venteicher if (add) 3061e3c97c2cSBryan Venteicher sc->vmx_vlan_filter[idx] |= (1 << bit); 3062e3c97c2cSBryan Venteicher else 3063e3c97c2cSBryan Venteicher sc->vmx_vlan_filter[idx] &= ~(1 << bit); 3064e3c97c2cSBryan Venteicher 3065e3c97c2cSBryan Venteicher if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) { 3066e3c97c2cSBryan Venteicher if (add) 3067e3c97c2cSBryan Venteicher sc->vmx_ds->vlan_filter[idx] |= (1 << bit); 3068e3c97c2cSBryan Venteicher else 3069e3c97c2cSBryan Venteicher sc->vmx_ds->vlan_filter[idx] &= ~(1 << bit); 3070e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_VLAN_FILTER); 3071e3c97c2cSBryan Venteicher } 3072e3c97c2cSBryan Venteicher 3073e3c97c2cSBryan Venteicher VMXNET3_CORE_UNLOCK(sc); 3074e3c97c2cSBryan Venteicher } 3075e3c97c2cSBryan Venteicher 3076e3c97c2cSBryan Venteicher static void 3077e3c97c2cSBryan Venteicher vmxnet3_register_vlan(void *arg, struct ifnet *ifp, uint16_t tag) 3078e3c97c2cSBryan Venteicher { 3079e3c97c2cSBryan Venteicher 3080e3c97c2cSBryan Venteicher if (ifp->if_softc == arg) 3081e3c97c2cSBryan Venteicher vmxnet3_update_vlan_filter(arg, 1, tag); 3082e3c97c2cSBryan Venteicher } 3083e3c97c2cSBryan Venteicher 3084e3c97c2cSBryan Venteicher static void 3085e3c97c2cSBryan Venteicher vmxnet3_unregister_vlan(void *arg, struct ifnet *ifp, uint16_t tag) 3086e3c97c2cSBryan Venteicher { 3087e3c97c2cSBryan Venteicher 3088e3c97c2cSBryan Venteicher if (ifp->if_softc == arg) 3089e3c97c2cSBryan Venteicher vmxnet3_update_vlan_filter(arg, 0, tag); 3090e3c97c2cSBryan Venteicher } 3091e3c97c2cSBryan Venteicher 3092e3c97c2cSBryan Venteicher static void 3093e3c97c2cSBryan Venteicher vmxnet3_set_rxfilter(struct vmxnet3_softc *sc) 3094e3c97c2cSBryan Venteicher { 3095e3c97c2cSBryan Venteicher struct ifnet *ifp; 3096e3c97c2cSBryan Venteicher struct vmxnet3_driver_shared *ds; 3097e3c97c2cSBryan Venteicher struct ifmultiaddr *ifma; 3098e3c97c2cSBryan Venteicher u_int mode; 3099e3c97c2cSBryan Venteicher 3100e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 3101e3c97c2cSBryan Venteicher ds = sc->vmx_ds; 3102e3c97c2cSBryan Venteicher 3103*e557c1ddSBryan Venteicher mode = VMXNET3_RXMODE_UCAST | VMXNET3_RXMODE_BCAST; 3104e3c97c2cSBryan Venteicher if (ifp->if_flags & IFF_PROMISC) 3105e3c97c2cSBryan Venteicher mode |= VMXNET3_RXMODE_PROMISC; 3106e3c97c2cSBryan Venteicher if (ifp->if_flags & IFF_ALLMULTI) 3107e3c97c2cSBryan Venteicher mode |= VMXNET3_RXMODE_ALLMULTI; 3108e3c97c2cSBryan Venteicher else { 3109e3c97c2cSBryan Venteicher int cnt = 0, overflow = 0; 3110e3c97c2cSBryan Venteicher 3111e3c97c2cSBryan Venteicher if_maddr_rlock(ifp); 3112e3c97c2cSBryan Venteicher TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 3113e3c97c2cSBryan Venteicher if (ifma->ifma_addr->sa_family != AF_LINK) 3114e3c97c2cSBryan Venteicher continue; 3115e3c97c2cSBryan Venteicher else if (cnt == VMXNET3_MULTICAST_MAX) { 3116e3c97c2cSBryan Venteicher overflow = 1; 3117e3c97c2cSBryan Venteicher break; 3118e3c97c2cSBryan Venteicher } 3119e3c97c2cSBryan Venteicher 3120e3c97c2cSBryan Venteicher bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 3121e3c97c2cSBryan Venteicher &sc->vmx_mcast[cnt*ETHER_ADDR_LEN], ETHER_ADDR_LEN); 3122e3c97c2cSBryan Venteicher cnt++; 3123e3c97c2cSBryan Venteicher } 3124e3c97c2cSBryan Venteicher if_maddr_runlock(ifp); 3125e3c97c2cSBryan Venteicher 3126e3c97c2cSBryan Venteicher if (overflow != 0) { 3127e3c97c2cSBryan Venteicher cnt = 0; 3128e3c97c2cSBryan Venteicher mode |= VMXNET3_RXMODE_ALLMULTI; 3129e3c97c2cSBryan Venteicher } else if (cnt > 0) 3130e3c97c2cSBryan Venteicher mode |= VMXNET3_RXMODE_MCAST; 3131e3c97c2cSBryan Venteicher ds->mcast_tablelen = cnt * ETHER_ADDR_LEN; 3132e3c97c2cSBryan Venteicher } 3133e3c97c2cSBryan Venteicher 3134e3c97c2cSBryan Venteicher ds->rxmode = mode; 3135e3c97c2cSBryan Venteicher 3136e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_FILTER); 3137e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_RXMODE); 3138e3c97c2cSBryan Venteicher } 3139e3c97c2cSBryan Venteicher 3140e3c97c2cSBryan Venteicher static int 3141e3c97c2cSBryan Venteicher vmxnet3_change_mtu(struct vmxnet3_softc *sc, int mtu) 3142e3c97c2cSBryan Venteicher { 3143e3c97c2cSBryan Venteicher struct ifnet *ifp; 3144e3c97c2cSBryan Venteicher 3145e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 3146e3c97c2cSBryan Venteicher 3147e3c97c2cSBryan Venteicher if (mtu < VMXNET3_MIN_MTU || mtu > VMXNET3_MAX_MTU) 3148e3c97c2cSBryan Venteicher return (EINVAL); 3149e3c97c2cSBryan Venteicher 3150e3c97c2cSBryan Venteicher ifp->if_mtu = mtu; 3151e3c97c2cSBryan Venteicher 3152e3c97c2cSBryan Venteicher if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3153e3c97c2cSBryan Venteicher ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3154e3c97c2cSBryan Venteicher vmxnet3_init_locked(sc); 3155e3c97c2cSBryan Venteicher } 3156e3c97c2cSBryan Venteicher 3157e3c97c2cSBryan Venteicher return (0); 3158e3c97c2cSBryan Venteicher } 3159e3c97c2cSBryan Venteicher 3160e3c97c2cSBryan Venteicher static int 3161e3c97c2cSBryan Venteicher vmxnet3_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 3162e3c97c2cSBryan Venteicher { 3163e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 3164e3c97c2cSBryan Venteicher struct ifreq *ifr; 3165e3c97c2cSBryan Venteicher int reinit, mask, error; 3166e3c97c2cSBryan Venteicher 3167e3c97c2cSBryan Venteicher sc = ifp->if_softc; 3168e3c97c2cSBryan Venteicher ifr = (struct ifreq *) data; 3169e3c97c2cSBryan Venteicher error = 0; 3170e3c97c2cSBryan Venteicher 3171e3c97c2cSBryan Venteicher switch (cmd) { 3172e3c97c2cSBryan Venteicher case SIOCSIFMTU: 3173e3c97c2cSBryan Venteicher if (ifp->if_mtu != ifr->ifr_mtu) { 3174e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK(sc); 3175e3c97c2cSBryan Venteicher error = vmxnet3_change_mtu(sc, ifr->ifr_mtu); 3176e3c97c2cSBryan Venteicher VMXNET3_CORE_UNLOCK(sc); 3177e3c97c2cSBryan Venteicher } 3178e3c97c2cSBryan Venteicher break; 3179e3c97c2cSBryan Venteicher 3180e3c97c2cSBryan Venteicher case SIOCSIFFLAGS: 3181e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK(sc); 3182e3c97c2cSBryan Venteicher if (ifp->if_flags & IFF_UP) { 3183e3c97c2cSBryan Venteicher if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 3184e3c97c2cSBryan Venteicher if ((ifp->if_flags ^ sc->vmx_if_flags) & 3185e3c97c2cSBryan Venteicher (IFF_PROMISC | IFF_ALLMULTI)) { 3186e3c97c2cSBryan Venteicher vmxnet3_set_rxfilter(sc); 3187e3c97c2cSBryan Venteicher } 3188e3c97c2cSBryan Venteicher } else 3189e3c97c2cSBryan Venteicher vmxnet3_init_locked(sc); 3190e3c97c2cSBryan Venteicher } else { 3191e3c97c2cSBryan Venteicher if (ifp->if_drv_flags & IFF_DRV_RUNNING) 3192e3c97c2cSBryan Venteicher vmxnet3_stop(sc); 3193e3c97c2cSBryan Venteicher } 3194e3c97c2cSBryan Venteicher sc->vmx_if_flags = ifp->if_flags; 3195e3c97c2cSBryan Venteicher VMXNET3_CORE_UNLOCK(sc); 3196e3c97c2cSBryan Venteicher break; 3197e3c97c2cSBryan Venteicher 3198e3c97c2cSBryan Venteicher case SIOCADDMULTI: 3199e3c97c2cSBryan Venteicher case SIOCDELMULTI: 3200e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK(sc); 3201e3c97c2cSBryan Venteicher if (ifp->if_drv_flags & IFF_DRV_RUNNING) 3202e3c97c2cSBryan Venteicher vmxnet3_set_rxfilter(sc); 3203e3c97c2cSBryan Venteicher VMXNET3_CORE_UNLOCK(sc); 3204e3c97c2cSBryan Venteicher break; 3205e3c97c2cSBryan Venteicher 3206e3c97c2cSBryan Venteicher case SIOCSIFMEDIA: 3207e3c97c2cSBryan Venteicher case SIOCGIFMEDIA: 3208e3c97c2cSBryan Venteicher error = ifmedia_ioctl(ifp, ifr, &sc->vmx_media, cmd); 3209e3c97c2cSBryan Venteicher break; 3210e3c97c2cSBryan Venteicher 3211e3c97c2cSBryan Venteicher case SIOCSIFCAP: 3212e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK(sc); 3213e3c97c2cSBryan Venteicher mask = ifr->ifr_reqcap ^ ifp->if_capenable; 3214e3c97c2cSBryan Venteicher 3215e3c97c2cSBryan Venteicher if (mask & IFCAP_TXCSUM) 3216e3c97c2cSBryan Venteicher ifp->if_capenable ^= IFCAP_TXCSUM; 3217e3c97c2cSBryan Venteicher if (mask & IFCAP_TXCSUM_IPV6) 3218e3c97c2cSBryan Venteicher ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 3219e3c97c2cSBryan Venteicher if (mask & IFCAP_TSO4) 3220e3c97c2cSBryan Venteicher ifp->if_capenable ^= IFCAP_TSO4; 3221e3c97c2cSBryan Venteicher if (mask & IFCAP_TSO6) 3222e3c97c2cSBryan Venteicher ifp->if_capenable ^= IFCAP_TSO6; 3223e3c97c2cSBryan Venteicher 3224e3c97c2cSBryan Venteicher if (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 | IFCAP_LRO | 32253c5dfe89SBryan Venteicher IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWFILTER)) { 32263c5dfe89SBryan Venteicher /* Changing these features requires us to reinit. */ 3227e3c97c2cSBryan Venteicher reinit = 1; 3228e3c97c2cSBryan Venteicher 3229e3c97c2cSBryan Venteicher if (mask & IFCAP_RXCSUM) 3230e3c97c2cSBryan Venteicher ifp->if_capenable ^= IFCAP_RXCSUM; 3231e3c97c2cSBryan Venteicher if (mask & IFCAP_RXCSUM_IPV6) 3232e3c97c2cSBryan Venteicher ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 3233e3c97c2cSBryan Venteicher if (mask & IFCAP_LRO) 3234e3c97c2cSBryan Venteicher ifp->if_capenable ^= IFCAP_LRO; 32353c5dfe89SBryan Venteicher if (mask & IFCAP_VLAN_HWTAGGING) 32363c5dfe89SBryan Venteicher ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 3237e3c97c2cSBryan Venteicher if (mask & IFCAP_VLAN_HWFILTER) 3238e3c97c2cSBryan Venteicher ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 3239e3c97c2cSBryan Venteicher } else 3240e3c97c2cSBryan Venteicher reinit = 0; 3241e3c97c2cSBryan Venteicher 3242e3c97c2cSBryan Venteicher if (mask & IFCAP_VLAN_HWTSO) 3243e3c97c2cSBryan Venteicher ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 3244e3c97c2cSBryan Venteicher 3245e3c97c2cSBryan Venteicher if (reinit && (ifp->if_drv_flags & IFF_DRV_RUNNING)) { 3246e3c97c2cSBryan Venteicher ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3247e3c97c2cSBryan Venteicher vmxnet3_init_locked(sc); 3248e3c97c2cSBryan Venteicher } 3249e3c97c2cSBryan Venteicher 3250e3c97c2cSBryan Venteicher VMXNET3_CORE_UNLOCK(sc); 3251e3c97c2cSBryan Venteicher VLAN_CAPABILITIES(ifp); 3252e3c97c2cSBryan Venteicher break; 3253e3c97c2cSBryan Venteicher 3254e3c97c2cSBryan Venteicher default: 3255e3c97c2cSBryan Venteicher error = ether_ioctl(ifp, cmd, data); 3256e3c97c2cSBryan Venteicher break; 3257e3c97c2cSBryan Venteicher } 3258e3c97c2cSBryan Venteicher 3259e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK_ASSERT_NOTOWNED(sc); 3260e3c97c2cSBryan Venteicher 3261e3c97c2cSBryan Venteicher return (error); 3262e3c97c2cSBryan Venteicher } 3263e3c97c2cSBryan Venteicher 3264*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX 3265*e557c1ddSBryan Venteicher static void 3266*e557c1ddSBryan Venteicher vmxnet3_qflush(struct ifnet *ifp) 3267*e557c1ddSBryan Venteicher { 3268*e557c1ddSBryan Venteicher struct vmxnet3_softc *sc; 3269*e557c1ddSBryan Venteicher struct vmxnet3_txqueue *txq; 3270*e557c1ddSBryan Venteicher struct mbuf *m; 3271*e557c1ddSBryan Venteicher int i; 3272*e557c1ddSBryan Venteicher 3273*e557c1ddSBryan Venteicher sc = ifp->if_softc; 3274*e557c1ddSBryan Venteicher 3275*e557c1ddSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++) { 3276*e557c1ddSBryan Venteicher txq = &sc->vmx_txq[i]; 3277*e557c1ddSBryan Venteicher 3278*e557c1ddSBryan Venteicher VMXNET3_TXQ_LOCK(txq); 3279*e557c1ddSBryan Venteicher while ((m = buf_ring_dequeue_sc(txq->vxtxq_br)) != NULL) 3280*e557c1ddSBryan Venteicher m_freem(m); 3281*e557c1ddSBryan Venteicher VMXNET3_TXQ_UNLOCK(txq); 3282*e557c1ddSBryan Venteicher } 3283*e557c1ddSBryan Venteicher 3284*e557c1ddSBryan Venteicher if_qflush(ifp); 3285*e557c1ddSBryan Venteicher } 3286*e557c1ddSBryan Venteicher #endif 3287*e557c1ddSBryan Venteicher 3288e3c97c2cSBryan Venteicher static int 3289e3c97c2cSBryan Venteicher vmxnet3_watchdog(struct vmxnet3_txqueue *txq) 3290e3c97c2cSBryan Venteicher { 3291e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 3292e3c97c2cSBryan Venteicher 3293e3c97c2cSBryan Venteicher sc = txq->vxtxq_sc; 3294e3c97c2cSBryan Venteicher 3295e3c97c2cSBryan Venteicher VMXNET3_TXQ_LOCK(txq); 3296e3c97c2cSBryan Venteicher if (txq->vxtxq_watchdog == 0 || --txq->vxtxq_watchdog) { 3297e3c97c2cSBryan Venteicher VMXNET3_TXQ_UNLOCK(txq); 3298e3c97c2cSBryan Venteicher return (0); 3299e3c97c2cSBryan Venteicher } 3300e3c97c2cSBryan Venteicher VMXNET3_TXQ_UNLOCK(txq); 3301e3c97c2cSBryan Venteicher 3302e3c97c2cSBryan Venteicher if_printf(sc->vmx_ifp, "watchdog timeout on queue %d\n", 3303e3c97c2cSBryan Venteicher txq->vxtxq_id); 3304e3c97c2cSBryan Venteicher return (1); 3305e3c97c2cSBryan Venteicher } 3306e3c97c2cSBryan Venteicher 3307e3c97c2cSBryan Venteicher static void 3308*e557c1ddSBryan Venteicher vmxnet3_refresh_host_stats(struct vmxnet3_softc *sc) 3309e3c97c2cSBryan Venteicher { 3310e3c97c2cSBryan Venteicher 3311e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_GET_STATS); 3312e3c97c2cSBryan Venteicher } 3313e3c97c2cSBryan Venteicher 3314e3c97c2cSBryan Venteicher static void 3315*e557c1ddSBryan Venteicher vmxnet3_txq_accum_stats(struct vmxnet3_txqueue *txq, 3316*e557c1ddSBryan Venteicher struct vmxnet3_txq_stats *accum) 3317*e557c1ddSBryan Venteicher { 3318*e557c1ddSBryan Venteicher struct vmxnet3_txq_stats *st; 3319*e557c1ddSBryan Venteicher 3320*e557c1ddSBryan Venteicher st = &txq->vxtxq_stats; 3321*e557c1ddSBryan Venteicher 3322*e557c1ddSBryan Venteicher accum->vmtxs_opackets += st->vmtxs_opackets; 3323*e557c1ddSBryan Venteicher accum->vmtxs_obytes += st->vmtxs_obytes; 3324*e557c1ddSBryan Venteicher accum->vmtxs_omcasts += st->vmtxs_omcasts; 3325*e557c1ddSBryan Venteicher accum->vmtxs_csum += st->vmtxs_csum; 3326*e557c1ddSBryan Venteicher accum->vmtxs_tso += st->vmtxs_tso; 3327*e557c1ddSBryan Venteicher accum->vmtxs_full += st->vmtxs_full; 3328*e557c1ddSBryan Venteicher accum->vmtxs_offload_failed += st->vmtxs_offload_failed; 3329*e557c1ddSBryan Venteicher } 3330*e557c1ddSBryan Venteicher 3331*e557c1ddSBryan Venteicher static void 3332*e557c1ddSBryan Venteicher vmxnet3_rxq_accum_stats(struct vmxnet3_rxqueue *rxq, 3333*e557c1ddSBryan Venteicher struct vmxnet3_rxq_stats *accum) 3334*e557c1ddSBryan Venteicher { 3335*e557c1ddSBryan Venteicher struct vmxnet3_rxq_stats *st; 3336*e557c1ddSBryan Venteicher 3337*e557c1ddSBryan Venteicher st = &rxq->vxrxq_stats; 3338*e557c1ddSBryan Venteicher 3339*e557c1ddSBryan Venteicher accum->vmrxs_ipackets += st->vmrxs_ipackets; 3340*e557c1ddSBryan Venteicher accum->vmrxs_ibytes += st->vmrxs_ibytes; 3341*e557c1ddSBryan Venteicher accum->vmrxs_iqdrops += st->vmrxs_iqdrops; 3342*e557c1ddSBryan Venteicher accum->vmrxs_ierrors += st->vmrxs_ierrors; 3343*e557c1ddSBryan Venteicher } 3344*e557c1ddSBryan Venteicher 3345*e557c1ddSBryan Venteicher static void 3346*e557c1ddSBryan Venteicher vmxnet3_accumulate_stats(struct vmxnet3_softc *sc) 3347*e557c1ddSBryan Venteicher { 3348*e557c1ddSBryan Venteicher struct ifnet *ifp; 3349*e557c1ddSBryan Venteicher struct vmxnet3_statistics *st; 3350*e557c1ddSBryan Venteicher struct vmxnet3_txq_stats txaccum; 3351*e557c1ddSBryan Venteicher struct vmxnet3_rxq_stats rxaccum; 3352*e557c1ddSBryan Venteicher int i; 3353*e557c1ddSBryan Venteicher 3354*e557c1ddSBryan Venteicher ifp = sc->vmx_ifp; 3355*e557c1ddSBryan Venteicher st = &sc->vmx_stats; 3356*e557c1ddSBryan Venteicher 3357*e557c1ddSBryan Venteicher bzero(&txaccum, sizeof(struct vmxnet3_txq_stats)); 3358*e557c1ddSBryan Venteicher bzero(&rxaccum, sizeof(struct vmxnet3_rxq_stats)); 3359*e557c1ddSBryan Venteicher 3360*e557c1ddSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++) 3361*e557c1ddSBryan Venteicher vmxnet3_txq_accum_stats(&sc->vmx_txq[i], &txaccum); 3362*e557c1ddSBryan Venteicher for (i = 0; i < sc->vmx_nrxqueues; i++) 3363*e557c1ddSBryan Venteicher vmxnet3_rxq_accum_stats(&sc->vmx_rxq[i], &rxaccum); 3364*e557c1ddSBryan Venteicher 3365*e557c1ddSBryan Venteicher /* 3366*e557c1ddSBryan Venteicher * With the exception of if_ierrors, these ifnet statistics are 3367*e557c1ddSBryan Venteicher * only updated in the driver, so just set them to our accumulated 3368*e557c1ddSBryan Venteicher * values. if_ierrors is updated in ether_input() for malformed 3369*e557c1ddSBryan Venteicher * frames that we should have already discarded. 3370*e557c1ddSBryan Venteicher */ 3371*e557c1ddSBryan Venteicher ifp->if_ipackets = rxaccum.vmrxs_ipackets; 3372*e557c1ddSBryan Venteicher ifp->if_iqdrops = rxaccum.vmrxs_iqdrops; 3373*e557c1ddSBryan Venteicher ifp->if_ierrors = rxaccum.vmrxs_ierrors; 3374*e557c1ddSBryan Venteicher ifp->if_opackets = txaccum.vmtxs_opackets; 3375*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX 3376*e557c1ddSBryan Venteicher ifp->if_obytes = txaccum.vmtxs_obytes; 3377*e557c1ddSBryan Venteicher ifp->if_omcasts = txaccum.vmtxs_omcasts; 3378*e557c1ddSBryan Venteicher #endif 3379*e557c1ddSBryan Venteicher } 3380*e557c1ddSBryan Venteicher 3381*e557c1ddSBryan Venteicher static void 3382e3c97c2cSBryan Venteicher vmxnet3_tick(void *xsc) 3383e3c97c2cSBryan Venteicher { 3384e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 3385e3c97c2cSBryan Venteicher struct ifnet *ifp; 3386e3c97c2cSBryan Venteicher int i, timedout; 3387e3c97c2cSBryan Venteicher 3388e3c97c2cSBryan Venteicher sc = xsc; 3389e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 3390e3c97c2cSBryan Venteicher timedout = 0; 3391e3c97c2cSBryan Venteicher 3392e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK_ASSERT(sc); 3393*e557c1ddSBryan Venteicher 3394*e557c1ddSBryan Venteicher vmxnet3_accumulate_stats(sc); 3395*e557c1ddSBryan Venteicher vmxnet3_refresh_host_stats(sc); 3396e3c97c2cSBryan Venteicher 3397e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++) 3398e3c97c2cSBryan Venteicher timedout |= vmxnet3_watchdog(&sc->vmx_txq[i]); 3399e3c97c2cSBryan Venteicher 3400e3c97c2cSBryan Venteicher if (timedout != 0) { 3401e3c97c2cSBryan Venteicher ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3402e3c97c2cSBryan Venteicher vmxnet3_init_locked(sc); 3403e3c97c2cSBryan Venteicher } else 3404e3c97c2cSBryan Venteicher callout_reset(&sc->vmx_tick, hz, vmxnet3_tick, sc); 3405e3c97c2cSBryan Venteicher } 3406e3c97c2cSBryan Venteicher 3407e3c97c2cSBryan Venteicher static int 3408e3c97c2cSBryan Venteicher vmxnet3_link_is_up(struct vmxnet3_softc *sc) 3409e3c97c2cSBryan Venteicher { 3410e3c97c2cSBryan Venteicher uint32_t status; 3411e3c97c2cSBryan Venteicher 3412e3c97c2cSBryan Venteicher /* Also update the link speed while here. */ 3413e3c97c2cSBryan Venteicher status = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_LINK); 3414e3c97c2cSBryan Venteicher sc->vmx_link_speed = status >> 16; 3415e3c97c2cSBryan Venteicher return !!(status & 0x1); 3416e3c97c2cSBryan Venteicher } 3417e3c97c2cSBryan Venteicher 3418e3c97c2cSBryan Venteicher static void 3419e3c97c2cSBryan Venteicher vmxnet3_link_status(struct vmxnet3_softc *sc) 3420e3c97c2cSBryan Venteicher { 3421e3c97c2cSBryan Venteicher struct ifnet *ifp; 3422e3c97c2cSBryan Venteicher int link; 3423e3c97c2cSBryan Venteicher 3424e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp; 3425e3c97c2cSBryan Venteicher link = vmxnet3_link_is_up(sc); 3426e3c97c2cSBryan Venteicher 3427e3c97c2cSBryan Venteicher if (link != 0 && sc->vmx_link_active == 0) { 3428e3c97c2cSBryan Venteicher sc->vmx_link_active = 1; 3429e3c97c2cSBryan Venteicher if_link_state_change(ifp, LINK_STATE_UP); 3430e3c97c2cSBryan Venteicher } else if (link == 0 && sc->vmx_link_active != 0) { 3431e3c97c2cSBryan Venteicher sc->vmx_link_active = 0; 3432e3c97c2cSBryan Venteicher if_link_state_change(ifp, LINK_STATE_DOWN); 3433e3c97c2cSBryan Venteicher } 3434e3c97c2cSBryan Venteicher } 3435e3c97c2cSBryan Venteicher 3436e3c97c2cSBryan Venteicher static void 3437e3c97c2cSBryan Venteicher vmxnet3_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 3438e3c97c2cSBryan Venteicher { 3439e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc; 3440e3c97c2cSBryan Venteicher 3441e3c97c2cSBryan Venteicher sc = ifp->if_softc; 3442e3c97c2cSBryan Venteicher 3443e3c97c2cSBryan Venteicher ifmr->ifm_active = IFM_ETHER | IFM_AUTO; 3444e3c97c2cSBryan Venteicher ifmr->ifm_status = IFM_AVALID; 3445e3c97c2cSBryan Venteicher 3446e3c97c2cSBryan Venteicher VMXNET3_CORE_LOCK(sc); 3447e3c97c2cSBryan Venteicher if (vmxnet3_link_is_up(sc) != 0) 3448e3c97c2cSBryan Venteicher ifmr->ifm_status |= IFM_ACTIVE; 3449e3c97c2cSBryan Venteicher else 3450e3c97c2cSBryan Venteicher ifmr->ifm_status |= IFM_NONE; 3451e3c97c2cSBryan Venteicher VMXNET3_CORE_UNLOCK(sc); 3452e3c97c2cSBryan Venteicher } 3453e3c97c2cSBryan Venteicher 3454e3c97c2cSBryan Venteicher static int 3455e3c97c2cSBryan Venteicher vmxnet3_media_change(struct ifnet *ifp) 3456e3c97c2cSBryan Venteicher { 3457e3c97c2cSBryan Venteicher 3458e3c97c2cSBryan Venteicher /* Ignore. */ 3459e3c97c2cSBryan Venteicher return (0); 3460e3c97c2cSBryan Venteicher } 3461e3c97c2cSBryan Venteicher 3462e3c97c2cSBryan Venteicher static void 3463e3c97c2cSBryan Venteicher vmxnet3_set_lladdr(struct vmxnet3_softc *sc) 3464e3c97c2cSBryan Venteicher { 3465e3c97c2cSBryan Venteicher uint32_t ml, mh; 3466e3c97c2cSBryan Venteicher 3467e3c97c2cSBryan Venteicher ml = sc->vmx_lladdr[0]; 3468e3c97c2cSBryan Venteicher ml |= sc->vmx_lladdr[1] << 8; 3469e3c97c2cSBryan Venteicher ml |= sc->vmx_lladdr[2] << 16; 3470e3c97c2cSBryan Venteicher ml |= sc->vmx_lladdr[3] << 24; 3471e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACL, ml); 3472e3c97c2cSBryan Venteicher 3473e3c97c2cSBryan Venteicher mh = sc->vmx_lladdr[4]; 3474e3c97c2cSBryan Venteicher mh |= sc->vmx_lladdr[5] << 8; 3475e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACH, mh); 3476e3c97c2cSBryan Venteicher } 3477e3c97c2cSBryan Venteicher 3478e3c97c2cSBryan Venteicher static void 3479e3c97c2cSBryan Venteicher vmxnet3_get_lladdr(struct vmxnet3_softc *sc) 3480e3c97c2cSBryan Venteicher { 3481e3c97c2cSBryan Venteicher uint32_t ml, mh; 3482e3c97c2cSBryan Venteicher 3483e3c97c2cSBryan Venteicher ml = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACL); 3484e3c97c2cSBryan Venteicher mh = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACH); 3485e3c97c2cSBryan Venteicher 3486e3c97c2cSBryan Venteicher sc->vmx_lladdr[0] = ml; 3487e3c97c2cSBryan Venteicher sc->vmx_lladdr[1] = ml >> 8; 3488e3c97c2cSBryan Venteicher sc->vmx_lladdr[2] = ml >> 16; 3489e3c97c2cSBryan Venteicher sc->vmx_lladdr[3] = ml >> 24; 3490e3c97c2cSBryan Venteicher sc->vmx_lladdr[4] = mh; 3491e3c97c2cSBryan Venteicher sc->vmx_lladdr[5] = mh >> 8; 3492e3c97c2cSBryan Venteicher } 3493e3c97c2cSBryan Venteicher 3494e3c97c2cSBryan Venteicher static void 3495e3c97c2cSBryan Venteicher vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *txq, 3496e3c97c2cSBryan Venteicher struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child) 3497e3c97c2cSBryan Venteicher { 3498e3c97c2cSBryan Venteicher struct sysctl_oid *node, *txsnode; 3499e3c97c2cSBryan Venteicher struct sysctl_oid_list *list, *txslist; 3500e3c97c2cSBryan Venteicher struct vmxnet3_txq_stats *stats; 3501e3c97c2cSBryan Venteicher struct UPT1_TxStats *txstats; 3502e3c97c2cSBryan Venteicher char namebuf[16]; 3503e3c97c2cSBryan Venteicher 3504e3c97c2cSBryan Venteicher stats = &txq->vxtxq_stats; 3505e3c97c2cSBryan Venteicher txstats = &txq->vxtxq_ts->stats; 3506e3c97c2cSBryan Venteicher 3507e3c97c2cSBryan Venteicher snprintf(namebuf, sizeof(namebuf), "txq%d", txq->vxtxq_id); 3508e3c97c2cSBryan Venteicher node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, CTLFLAG_RD, 3509e3c97c2cSBryan Venteicher NULL, "Transmit Queue"); 3510e3c97c2cSBryan Venteicher txq->vxtxq_sysctl = list = SYSCTL_CHILDREN(node); 3511e3c97c2cSBryan Venteicher 3512*e557c1ddSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "opackets", CTLFLAG_RD, 3513*e557c1ddSBryan Venteicher &stats->vmtxs_opackets, "Transmit packets"); 3514*e557c1ddSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "obytes", CTLFLAG_RD, 3515*e557c1ddSBryan Venteicher &stats->vmtxs_obytes, "Transmit bytes"); 3516*e557c1ddSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "omcasts", CTLFLAG_RD, 3517*e557c1ddSBryan Venteicher &stats->vmtxs_omcasts, "Transmit multicasts"); 3518*e557c1ddSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "csum", CTLFLAG_RD, 3519*e557c1ddSBryan Venteicher &stats->vmtxs_csum, "Transmit checksum offloaded"); 3520*e557c1ddSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "tso", CTLFLAG_RD, 3521*e557c1ddSBryan Venteicher &stats->vmtxs_tso, "Transmit TCP segmentation offloaded"); 3522e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "ringfull", CTLFLAG_RD, 3523*e557c1ddSBryan Venteicher &stats->vmtxs_full, "Transmit ring full"); 3524e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "offload_failed", CTLFLAG_RD, 3525*e557c1ddSBryan Venteicher &stats->vmtxs_offload_failed, "Transmit checksum offload failed"); 3526e3c97c2cSBryan Venteicher 3527e3c97c2cSBryan Venteicher /* 3528e3c97c2cSBryan Venteicher * Add statistics reported by the host. These are updated once 3529e3c97c2cSBryan Venteicher * per second. 3530e3c97c2cSBryan Venteicher */ 3531e3c97c2cSBryan Venteicher txsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats", CTLFLAG_RD, 3532e3c97c2cSBryan Venteicher NULL, "Host Statistics"); 3533e3c97c2cSBryan Venteicher txslist = SYSCTL_CHILDREN(txsnode); 3534e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_packets", CTLFLAG_RD, 3535e3c97c2cSBryan Venteicher &txstats->TSO_packets, "TSO packets"); 3536e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_bytes", CTLFLAG_RD, 3537e3c97c2cSBryan Venteicher &txstats->TSO_bytes, "TSO bytes"); 3538e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "ucast_packets", CTLFLAG_RD, 3539e3c97c2cSBryan Venteicher &txstats->ucast_packets, "Unicast packets"); 3540e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD, 3541e3c97c2cSBryan Venteicher &txstats->ucast_bytes, "Unicast bytes"); 3542e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_packets", CTLFLAG_RD, 3543e3c97c2cSBryan Venteicher &txstats->mcast_packets, "Multicast packets"); 3544e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD, 3545e3c97c2cSBryan Venteicher &txstats->mcast_bytes, "Multicast bytes"); 3546e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "error", CTLFLAG_RD, 3547e3c97c2cSBryan Venteicher &txstats->error, "Errors"); 3548e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "discard", CTLFLAG_RD, 3549e3c97c2cSBryan Venteicher &txstats->discard, "Discards"); 3550e3c97c2cSBryan Venteicher } 3551e3c97c2cSBryan Venteicher 3552e3c97c2cSBryan Venteicher static void 3553e3c97c2cSBryan Venteicher vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *rxq, 3554e3c97c2cSBryan Venteicher struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child) 3555e3c97c2cSBryan Venteicher { 3556e3c97c2cSBryan Venteicher struct sysctl_oid *node, *rxsnode; 3557e3c97c2cSBryan Venteicher struct sysctl_oid_list *list, *rxslist; 3558e3c97c2cSBryan Venteicher struct vmxnet3_rxq_stats *stats; 3559e3c97c2cSBryan Venteicher struct UPT1_RxStats *rxstats; 3560e3c97c2cSBryan Venteicher char namebuf[16]; 3561e3c97c2cSBryan Venteicher 3562e3c97c2cSBryan Venteicher stats = &rxq->vxrxq_stats; 3563e3c97c2cSBryan Venteicher rxstats = &rxq->vxrxq_rs->stats; 3564e3c97c2cSBryan Venteicher 3565e3c97c2cSBryan Venteicher snprintf(namebuf, sizeof(namebuf), "rxq%d", rxq->vxrxq_id); 3566e3c97c2cSBryan Venteicher node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, CTLFLAG_RD, 3567e3c97c2cSBryan Venteicher NULL, "Receive Queue"); 3568e3c97c2cSBryan Venteicher rxq->vxrxq_sysctl = list = SYSCTL_CHILDREN(node); 3569e3c97c2cSBryan Venteicher 3570*e557c1ddSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "ipackets", CTLFLAG_RD, 3571*e557c1ddSBryan Venteicher &stats->vmrxs_ipackets, "Receive packets"); 3572*e557c1ddSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "ibytes", CTLFLAG_RD, 3573*e557c1ddSBryan Venteicher &stats->vmrxs_ibytes, "Receive bytes"); 3574*e557c1ddSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "iqdrops", CTLFLAG_RD, 3575*e557c1ddSBryan Venteicher &stats->vmrxs_iqdrops, "Receive drops"); 3576*e557c1ddSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "ierrors", CTLFLAG_RD, 3577*e557c1ddSBryan Venteicher &stats->vmrxs_ierrors, "Receive errors"); 3578*e557c1ddSBryan Venteicher 3579e3c97c2cSBryan Venteicher /* 3580e3c97c2cSBryan Venteicher * Add statistics reported by the host. These are updated once 3581e3c97c2cSBryan Venteicher * per second. 3582e3c97c2cSBryan Venteicher */ 3583e3c97c2cSBryan Venteicher rxsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats", CTLFLAG_RD, 3584e3c97c2cSBryan Venteicher NULL, "Host Statistics"); 3585e3c97c2cSBryan Venteicher rxslist = SYSCTL_CHILDREN(rxsnode); 3586e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_packets", CTLFLAG_RD, 3587e3c97c2cSBryan Venteicher &rxstats->LRO_packets, "LRO packets"); 3588e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_bytes", CTLFLAG_RD, 3589e3c97c2cSBryan Venteicher &rxstats->LRO_bytes, "LRO bytes"); 3590e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "ucast_packets", CTLFLAG_RD, 3591e3c97c2cSBryan Venteicher &rxstats->ucast_packets, "Unicast packets"); 3592e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD, 3593e3c97c2cSBryan Venteicher &rxstats->ucast_bytes, "Unicast bytes"); 3594e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_packets", CTLFLAG_RD, 3595e3c97c2cSBryan Venteicher &rxstats->mcast_packets, "Multicast packets"); 3596e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD, 3597e3c97c2cSBryan Venteicher &rxstats->mcast_bytes, "Multicast bytes"); 3598e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_packets", CTLFLAG_RD, 3599e3c97c2cSBryan Venteicher &rxstats->bcast_packets, "Broadcast packets"); 3600e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_bytes", CTLFLAG_RD, 3601e3c97c2cSBryan Venteicher &rxstats->bcast_bytes, "Broadcast bytes"); 3602e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "nobuffer", CTLFLAG_RD, 3603e3c97c2cSBryan Venteicher &rxstats->nobuffer, "No buffer"); 3604e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "error", CTLFLAG_RD, 3605e3c97c2cSBryan Venteicher &rxstats->error, "Errors"); 3606e3c97c2cSBryan Venteicher } 3607e3c97c2cSBryan Venteicher 3608e3c97c2cSBryan Venteicher static void 3609e3c97c2cSBryan Venteicher vmxnet3_setup_debug_sysctl(struct vmxnet3_softc *sc, 3610e3c97c2cSBryan Venteicher struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child) 3611e3c97c2cSBryan Venteicher { 3612e3c97c2cSBryan Venteicher struct sysctl_oid *node; 3613e3c97c2cSBryan Venteicher struct sysctl_oid_list *list; 3614e3c97c2cSBryan Venteicher int i; 3615e3c97c2cSBryan Venteicher 3616e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++) { 3617e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq = &sc->vmx_txq[i]; 3618e3c97c2cSBryan Venteicher 3619e3c97c2cSBryan Venteicher node = SYSCTL_ADD_NODE(ctx, txq->vxtxq_sysctl, OID_AUTO, 3620e3c97c2cSBryan Venteicher "debug", CTLFLAG_RD, NULL, ""); 3621e3c97c2cSBryan Venteicher list = SYSCTL_CHILDREN(node); 3622e3c97c2cSBryan Venteicher 3623e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_head", CTLFLAG_RD, 3624e3c97c2cSBryan Venteicher &txq->vxtxq_cmd_ring.vxtxr_head, 0, ""); 3625e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_next", CTLFLAG_RD, 3626e3c97c2cSBryan Venteicher &txq->vxtxq_cmd_ring.vxtxr_next, 0, ""); 3627e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_ndesc", CTLFLAG_RD, 3628e3c97c2cSBryan Venteicher &txq->vxtxq_cmd_ring.vxtxr_ndesc, 0, ""); 3629e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd_gen", CTLFLAG_RD, 3630e3c97c2cSBryan Venteicher &txq->vxtxq_cmd_ring.vxtxr_gen, 0, ""); 3631e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD, 3632e3c97c2cSBryan Venteicher &txq->vxtxq_comp_ring.vxcr_next, 0, ""); 3633e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD, 3634e3c97c2cSBryan Venteicher &txq->vxtxq_comp_ring.vxcr_ndesc, 0,""); 3635e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD, 3636e3c97c2cSBryan Venteicher &txq->vxtxq_comp_ring.vxcr_gen, 0, ""); 3637e3c97c2cSBryan Venteicher } 3638e3c97c2cSBryan Venteicher 3639e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nrxqueues; i++) { 3640e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq = &sc->vmx_rxq[i]; 3641e3c97c2cSBryan Venteicher 3642e3c97c2cSBryan Venteicher node = SYSCTL_ADD_NODE(ctx, rxq->vxrxq_sysctl, OID_AUTO, 3643e3c97c2cSBryan Venteicher "debug", CTLFLAG_RD, NULL, ""); 3644e3c97c2cSBryan Venteicher list = SYSCTL_CHILDREN(node); 3645e3c97c2cSBryan Venteicher 3646e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_fill", CTLFLAG_RD, 3647e3c97c2cSBryan Venteicher &rxq->vxrxq_cmd_ring[0].vxrxr_fill, 0, ""); 3648e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_ndesc", CTLFLAG_RD, 3649e3c97c2cSBryan Venteicher &rxq->vxrxq_cmd_ring[0].vxrxr_ndesc, 0, ""); 3650e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd0_gen", CTLFLAG_RD, 3651e3c97c2cSBryan Venteicher &rxq->vxrxq_cmd_ring[0].vxrxr_gen, 0, ""); 3652e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_fill", CTLFLAG_RD, 3653e3c97c2cSBryan Venteicher &rxq->vxrxq_cmd_ring[1].vxrxr_fill, 0, ""); 3654e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_ndesc", CTLFLAG_RD, 3655e3c97c2cSBryan Venteicher &rxq->vxrxq_cmd_ring[1].vxrxr_ndesc, 0, ""); 3656e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd1_gen", CTLFLAG_RD, 3657e3c97c2cSBryan Venteicher &rxq->vxrxq_cmd_ring[1].vxrxr_gen, 0, ""); 3658e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD, 3659e3c97c2cSBryan Venteicher &rxq->vxrxq_comp_ring.vxcr_next, 0, ""); 3660e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD, 3661e3c97c2cSBryan Venteicher &rxq->vxrxq_comp_ring.vxcr_ndesc, 0,""); 3662e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD, 3663e3c97c2cSBryan Venteicher &rxq->vxrxq_comp_ring.vxcr_gen, 0, ""); 3664e3c97c2cSBryan Venteicher } 3665e3c97c2cSBryan Venteicher } 3666e3c97c2cSBryan Venteicher 3667e3c97c2cSBryan Venteicher static void 3668e3c97c2cSBryan Venteicher vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *sc, 3669e3c97c2cSBryan Venteicher struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child) 3670e3c97c2cSBryan Venteicher { 3671e3c97c2cSBryan Venteicher int i; 3672e3c97c2cSBryan Venteicher 3673e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_ntxqueues; i++) 3674e3c97c2cSBryan Venteicher vmxnet3_setup_txq_sysctl(&sc->vmx_txq[i], ctx, child); 3675e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nrxqueues; i++) 3676e3c97c2cSBryan Venteicher vmxnet3_setup_rxq_sysctl(&sc->vmx_rxq[i], ctx, child); 3677e3c97c2cSBryan Venteicher 3678e3c97c2cSBryan Venteicher vmxnet3_setup_debug_sysctl(sc, ctx, child); 3679e3c97c2cSBryan Venteicher } 3680e3c97c2cSBryan Venteicher 3681e3c97c2cSBryan Venteicher static void 3682e3c97c2cSBryan Venteicher vmxnet3_setup_sysctl(struct vmxnet3_softc *sc) 3683e3c97c2cSBryan Venteicher { 3684e3c97c2cSBryan Venteicher device_t dev; 3685e3c97c2cSBryan Venteicher struct vmxnet3_statistics *stats; 3686e3c97c2cSBryan Venteicher struct sysctl_ctx_list *ctx; 3687e3c97c2cSBryan Venteicher struct sysctl_oid *tree; 3688e3c97c2cSBryan Venteicher struct sysctl_oid_list *child; 3689e3c97c2cSBryan Venteicher 3690e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 3691e3c97c2cSBryan Venteicher ctx = device_get_sysctl_ctx(dev); 3692e3c97c2cSBryan Venteicher tree = device_get_sysctl_tree(dev); 3693e3c97c2cSBryan Venteicher child = SYSCTL_CHILDREN(tree); 3694e3c97c2cSBryan Venteicher 3695*e557c1ddSBryan Venteicher SYSCTL_ADD_INT(ctx, child, OID_AUTO, "max_ntxqueues", CTLFLAG_RD, 3696*e557c1ddSBryan Venteicher &sc->vmx_max_ntxqueues, 0, "Maximum number of Tx queues"); 3697*e557c1ddSBryan Venteicher SYSCTL_ADD_INT(ctx, child, OID_AUTO, "max_nrxqueues", CTLFLAG_RD, 3698*e557c1ddSBryan Venteicher &sc->vmx_max_nrxqueues, 0, "Maximum number of Rx queues"); 3699e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, child, OID_AUTO, "ntxqueues", CTLFLAG_RD, 3700e3c97c2cSBryan Venteicher &sc->vmx_ntxqueues, 0, "Number of Tx queues"); 3701e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, child, OID_AUTO, "nrxqueues", CTLFLAG_RD, 3702e3c97c2cSBryan Venteicher &sc->vmx_nrxqueues, 0, "Number of Rx queues"); 3703e3c97c2cSBryan Venteicher 3704e3c97c2cSBryan Venteicher stats = &sc->vmx_stats; 3705*e557c1ddSBryan Venteicher SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "defragged", CTLFLAG_RD, 3706*e557c1ddSBryan Venteicher &stats->vmst_defragged, 0, "Tx mbuf chains defragged"); 3707*e557c1ddSBryan Venteicher SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "defrag_failed", CTLFLAG_RD, 3708*e557c1ddSBryan Venteicher &stats->vmst_defrag_failed, 0, 3709*e557c1ddSBryan Venteicher "Tx mbuf dropped because defrag failed"); 3710e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "mgetcl_failed", CTLFLAG_RD, 3711e3c97c2cSBryan Venteicher &stats->vmst_mgetcl_failed, 0, "mbuf cluster allocation failed"); 3712e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "mbuf_load_failed", CTLFLAG_RD, 3713e3c97c2cSBryan Venteicher &stats->vmst_mbuf_load_failed, 0, "mbuf load segments failed"); 3714e3c97c2cSBryan Venteicher 3715e3c97c2cSBryan Venteicher vmxnet3_setup_queue_sysctl(sc, ctx, child); 3716e3c97c2cSBryan Venteicher } 3717e3c97c2cSBryan Venteicher 3718e3c97c2cSBryan Venteicher static void 3719e3c97c2cSBryan Venteicher vmxnet3_write_bar0(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v) 3720e3c97c2cSBryan Venteicher { 3721e3c97c2cSBryan Venteicher 3722e3c97c2cSBryan Venteicher bus_space_write_4(sc->vmx_iot0, sc->vmx_ioh0, r, v); 3723e3c97c2cSBryan Venteicher } 3724e3c97c2cSBryan Venteicher 3725e3c97c2cSBryan Venteicher static uint32_t 3726e3c97c2cSBryan Venteicher vmxnet3_read_bar1(struct vmxnet3_softc *sc, bus_size_t r) 3727e3c97c2cSBryan Venteicher { 3728e3c97c2cSBryan Venteicher 3729e3c97c2cSBryan Venteicher return (bus_space_read_4(sc->vmx_iot1, sc->vmx_ioh1, r)); 3730e3c97c2cSBryan Venteicher } 3731e3c97c2cSBryan Venteicher 3732e3c97c2cSBryan Venteicher static void 3733e3c97c2cSBryan Venteicher vmxnet3_write_bar1(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v) 3734e3c97c2cSBryan Venteicher { 3735e3c97c2cSBryan Venteicher 3736e3c97c2cSBryan Venteicher bus_space_write_4(sc->vmx_iot1, sc->vmx_ioh1, r, v); 3737e3c97c2cSBryan Venteicher } 3738e3c97c2cSBryan Venteicher 3739e3c97c2cSBryan Venteicher static void 3740e3c97c2cSBryan Venteicher vmxnet3_write_cmd(struct vmxnet3_softc *sc, uint32_t cmd) 3741e3c97c2cSBryan Venteicher { 3742e3c97c2cSBryan Venteicher 3743e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_CMD, cmd); 3744e3c97c2cSBryan Venteicher } 3745e3c97c2cSBryan Venteicher 3746e3c97c2cSBryan Venteicher static uint32_t 3747e3c97c2cSBryan Venteicher vmxnet3_read_cmd(struct vmxnet3_softc *sc, uint32_t cmd) 3748e3c97c2cSBryan Venteicher { 3749e3c97c2cSBryan Venteicher 3750e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, cmd); 3751e3c97c2cSBryan Venteicher bus_space_barrier(sc->vmx_iot1, sc->vmx_ioh1, 0, 0, 3752e3c97c2cSBryan Venteicher BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 3753e3c97c2cSBryan Venteicher return (vmxnet3_read_bar1(sc, VMXNET3_BAR1_CMD)); 3754e3c97c2cSBryan Venteicher } 3755e3c97c2cSBryan Venteicher 3756e3c97c2cSBryan Venteicher static void 3757e3c97c2cSBryan Venteicher vmxnet3_enable_intr(struct vmxnet3_softc *sc, int irq) 3758e3c97c2cSBryan Venteicher { 3759e3c97c2cSBryan Venteicher 3760e3c97c2cSBryan Venteicher vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 0); 3761e3c97c2cSBryan Venteicher } 3762e3c97c2cSBryan Venteicher 3763e3c97c2cSBryan Venteicher static void 3764e3c97c2cSBryan Venteicher vmxnet3_disable_intr(struct vmxnet3_softc *sc, int irq) 3765e3c97c2cSBryan Venteicher { 3766e3c97c2cSBryan Venteicher 3767e3c97c2cSBryan Venteicher vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 1); 3768e3c97c2cSBryan Venteicher } 3769e3c97c2cSBryan Venteicher 3770e3c97c2cSBryan Venteicher static void 3771e3c97c2cSBryan Venteicher vmxnet3_enable_all_intrs(struct vmxnet3_softc *sc) 3772e3c97c2cSBryan Venteicher { 3773e3c97c2cSBryan Venteicher int i; 3774e3c97c2cSBryan Venteicher 3775e3c97c2cSBryan Venteicher sc->vmx_ds->ictrl &= ~VMXNET3_ICTRL_DISABLE_ALL; 3776e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nintrs; i++) 3777e3c97c2cSBryan Venteicher vmxnet3_enable_intr(sc, i); 3778e3c97c2cSBryan Venteicher } 3779e3c97c2cSBryan Venteicher 3780e3c97c2cSBryan Venteicher static void 3781e3c97c2cSBryan Venteicher vmxnet3_disable_all_intrs(struct vmxnet3_softc *sc) 3782e3c97c2cSBryan Venteicher { 3783e3c97c2cSBryan Venteicher int i; 3784e3c97c2cSBryan Venteicher 3785e3c97c2cSBryan Venteicher sc->vmx_ds->ictrl |= VMXNET3_ICTRL_DISABLE_ALL; 3786e3c97c2cSBryan Venteicher for (i = 0; i < sc->vmx_nintrs; i++) 3787e3c97c2cSBryan Venteicher vmxnet3_disable_intr(sc, i); 3788e3c97c2cSBryan Venteicher } 3789e3c97c2cSBryan Venteicher 3790e3c97c2cSBryan Venteicher static void 3791e3c97c2cSBryan Venteicher vmxnet3_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 3792e3c97c2cSBryan Venteicher { 3793e3c97c2cSBryan Venteicher bus_addr_t *baddr = arg; 3794e3c97c2cSBryan Venteicher 3795e3c97c2cSBryan Venteicher if (error == 0) 3796e3c97c2cSBryan Venteicher *baddr = segs->ds_addr; 3797e3c97c2cSBryan Venteicher } 3798e3c97c2cSBryan Venteicher 3799e3c97c2cSBryan Venteicher static int 3800e3c97c2cSBryan Venteicher vmxnet3_dma_malloc(struct vmxnet3_softc *sc, bus_size_t size, bus_size_t align, 3801e3c97c2cSBryan Venteicher struct vmxnet3_dma_alloc *dma) 3802e3c97c2cSBryan Venteicher { 3803e3c97c2cSBryan Venteicher device_t dev; 3804e3c97c2cSBryan Venteicher int error; 3805e3c97c2cSBryan Venteicher 3806e3c97c2cSBryan Venteicher dev = sc->vmx_dev; 3807e3c97c2cSBryan Venteicher bzero(dma, sizeof(struct vmxnet3_dma_alloc)); 3808e3c97c2cSBryan Venteicher 3809e3c97c2cSBryan Venteicher error = bus_dma_tag_create(bus_get_dma_tag(dev), 3810e3c97c2cSBryan Venteicher align, 0, /* alignment, bounds */ 3811e3c97c2cSBryan Venteicher BUS_SPACE_MAXADDR, /* lowaddr */ 3812e3c97c2cSBryan Venteicher BUS_SPACE_MAXADDR, /* highaddr */ 3813e3c97c2cSBryan Venteicher NULL, NULL, /* filter, filterarg */ 3814e3c97c2cSBryan Venteicher size, /* maxsize */ 3815e3c97c2cSBryan Venteicher 1, /* nsegments */ 3816e3c97c2cSBryan Venteicher size, /* maxsegsize */ 3817e3c97c2cSBryan Venteicher BUS_DMA_ALLOCNOW, /* flags */ 3818e3c97c2cSBryan Venteicher NULL, /* lockfunc */ 3819e3c97c2cSBryan Venteicher NULL, /* lockfuncarg */ 3820e3c97c2cSBryan Venteicher &dma->dma_tag); 3821e3c97c2cSBryan Venteicher if (error) { 3822e3c97c2cSBryan Venteicher device_printf(dev, "bus_dma_tag_create failed: %d\n", error); 3823e3c97c2cSBryan Venteicher goto fail; 3824e3c97c2cSBryan Venteicher } 3825e3c97c2cSBryan Venteicher 3826e3c97c2cSBryan Venteicher error = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr, 3827e3c97c2cSBryan Venteicher BUS_DMA_ZERO | BUS_DMA_NOWAIT, &dma->dma_map); 3828e3c97c2cSBryan Venteicher if (error) { 3829e3c97c2cSBryan Venteicher device_printf(dev, "bus_dmamem_alloc failed: %d\n", error); 3830e3c97c2cSBryan Venteicher goto fail; 3831e3c97c2cSBryan Venteicher } 3832e3c97c2cSBryan Venteicher 3833e3c97c2cSBryan Venteicher error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, 3834e3c97c2cSBryan Venteicher size, vmxnet3_dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT); 3835e3c97c2cSBryan Venteicher if (error) { 3836e3c97c2cSBryan Venteicher device_printf(dev, "bus_dmamap_load failed: %d\n", error); 3837e3c97c2cSBryan Venteicher goto fail; 3838e3c97c2cSBryan Venteicher } 3839e3c97c2cSBryan Venteicher 3840e3c97c2cSBryan Venteicher dma->dma_size = size; 3841e3c97c2cSBryan Venteicher 3842e3c97c2cSBryan Venteicher fail: 3843e3c97c2cSBryan Venteicher if (error) 3844e3c97c2cSBryan Venteicher vmxnet3_dma_free(sc, dma); 3845e3c97c2cSBryan Venteicher 3846e3c97c2cSBryan Venteicher return (error); 3847e3c97c2cSBryan Venteicher } 3848e3c97c2cSBryan Venteicher 3849e3c97c2cSBryan Venteicher static void 3850e3c97c2cSBryan Venteicher vmxnet3_dma_free(struct vmxnet3_softc *sc, struct vmxnet3_dma_alloc *dma) 3851e3c97c2cSBryan Venteicher { 3852e3c97c2cSBryan Venteicher 3853e3c97c2cSBryan Venteicher if (dma->dma_tag != NULL) { 3854e3c97c2cSBryan Venteicher if (dma->dma_map != NULL) { 3855e3c97c2cSBryan Venteicher bus_dmamap_sync(dma->dma_tag, dma->dma_map, 3856e3c97c2cSBryan Venteicher BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 3857e3c97c2cSBryan Venteicher bus_dmamap_unload(dma->dma_tag, dma->dma_map); 3858e3c97c2cSBryan Venteicher } 3859e3c97c2cSBryan Venteicher 3860e3c97c2cSBryan Venteicher if (dma->dma_vaddr != NULL) { 3861e3c97c2cSBryan Venteicher bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, 3862e3c97c2cSBryan Venteicher dma->dma_map); 3863e3c97c2cSBryan Venteicher } 3864e3c97c2cSBryan Venteicher 3865e3c97c2cSBryan Venteicher bus_dma_tag_destroy(dma->dma_tag); 3866e3c97c2cSBryan Venteicher } 3867e3c97c2cSBryan Venteicher bzero(dma, sizeof(struct vmxnet3_dma_alloc)); 3868e3c97c2cSBryan Venteicher } 3869e3c97c2cSBryan Venteicher 38703c5dfe89SBryan Venteicher static int 38713c5dfe89SBryan Venteicher vmxnet3_tunable_int(struct vmxnet3_softc *sc, const char *knob, int def) 38723c5dfe89SBryan Venteicher { 38733c5dfe89SBryan Venteicher char path[64]; 38743c5dfe89SBryan Venteicher 38753c5dfe89SBryan Venteicher snprintf(path, sizeof(path), 38763c5dfe89SBryan Venteicher "hw.vmx.%d.%s", device_get_unit(sc->vmx_dev), knob); 38773c5dfe89SBryan Venteicher TUNABLE_INT_FETCH(path, &def); 38783c5dfe89SBryan Venteicher 38793c5dfe89SBryan Venteicher return (def); 38803c5dfe89SBryan Venteicher } 38813c5dfe89SBryan Venteicher 3882e3c97c2cSBryan Venteicher /* 3883e3c97c2cSBryan Venteicher * Since this is a purely paravirtualized device, we do not have 3884e3c97c2cSBryan Venteicher * to worry about DMA coherency. But at times, we must make sure 3885e3c97c2cSBryan Venteicher * both the compiler and CPU do not reorder memory operations. 3886e3c97c2cSBryan Venteicher */ 3887e3c97c2cSBryan Venteicher static inline void 3888e3c97c2cSBryan Venteicher vmxnet3_barrier(struct vmxnet3_softc *sc, vmxnet3_barrier_t type) 3889e3c97c2cSBryan Venteicher { 3890e3c97c2cSBryan Venteicher 3891e3c97c2cSBryan Venteicher switch (type) { 3892e3c97c2cSBryan Venteicher case VMXNET3_BARRIER_RD: 3893e3c97c2cSBryan Venteicher rmb(); 3894e3c97c2cSBryan Venteicher break; 3895e3c97c2cSBryan Venteicher case VMXNET3_BARRIER_WR: 3896e3c97c2cSBryan Venteicher wmb(); 3897e3c97c2cSBryan Venteicher break; 3898e3c97c2cSBryan Venteicher case VMXNET3_BARRIER_RDWR: 3899e3c97c2cSBryan Venteicher mb(); 3900e3c97c2cSBryan Venteicher break; 3901e3c97c2cSBryan Venteicher default: 3902e3c97c2cSBryan Venteicher panic("%s: bad barrier type %d", __func__, type); 3903e3c97c2cSBryan Venteicher } 3904e3c97c2cSBryan Venteicher } 3905