1*a9643ea8Slogwang /*- 2*a9643ea8Slogwang * Copyright (c) 2014-2016, Matthew Macy <[email protected]> 3*a9643ea8Slogwang * All rights reserved. 4*a9643ea8Slogwang * 5*a9643ea8Slogwang * Redistribution and use in source and binary forms, with or without 6*a9643ea8Slogwang * modification, are permitted provided that the following conditions are met: 7*a9643ea8Slogwang * 8*a9643ea8Slogwang * 1. Redistributions of source code must retain the above copyright notice, 9*a9643ea8Slogwang * this list of conditions and the following disclaimer. 10*a9643ea8Slogwang * 11*a9643ea8Slogwang * 2. Neither the name of Matthew Macy nor the names of its 12*a9643ea8Slogwang * contributors may be used to endorse or promote products derived from 13*a9643ea8Slogwang * this software without specific prior written permission. 14*a9643ea8Slogwang * 15*a9643ea8Slogwang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16*a9643ea8Slogwang * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*a9643ea8Slogwang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*a9643ea8Slogwang * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19*a9643ea8Slogwang * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20*a9643ea8Slogwang * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21*a9643ea8Slogwang * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22*a9643ea8Slogwang * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23*a9643ea8Slogwang * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24*a9643ea8Slogwang * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25*a9643ea8Slogwang * POSSIBILITY OF SUCH DAMAGE. 26*a9643ea8Slogwang */ 27*a9643ea8Slogwang 28*a9643ea8Slogwang #include <sys/cdefs.h> 29*a9643ea8Slogwang __FBSDID("$FreeBSD$"); 30*a9643ea8Slogwang 31*a9643ea8Slogwang #include "opt_inet.h" 32*a9643ea8Slogwang #include "opt_inet6.h" 33*a9643ea8Slogwang #include "opt_acpi.h" 34*a9643ea8Slogwang 35*a9643ea8Slogwang #include <sys/param.h> 36*a9643ea8Slogwang #include <sys/types.h> 37*a9643ea8Slogwang #include <sys/bus.h> 38*a9643ea8Slogwang #include <sys/eventhandler.h> 39*a9643ea8Slogwang #include <sys/sockio.h> 40*a9643ea8Slogwang #include <sys/kernel.h> 41*a9643ea8Slogwang #include <sys/lock.h> 42*a9643ea8Slogwang #include <sys/mutex.h> 43*a9643ea8Slogwang #include <sys/module.h> 44*a9643ea8Slogwang #include <sys/kobj.h> 45*a9643ea8Slogwang #include <sys/rman.h> 46*a9643ea8Slogwang #include <sys/sbuf.h> 47*a9643ea8Slogwang #include <sys/smp.h> 48*a9643ea8Slogwang #include <sys/socket.h> 49*a9643ea8Slogwang #include <sys/sysctl.h> 50*a9643ea8Slogwang #include <sys/syslog.h> 51*a9643ea8Slogwang #include <sys/taskqueue.h> 52*a9643ea8Slogwang #include <sys/limits.h> 53*a9643ea8Slogwang 54*a9643ea8Slogwang 55*a9643ea8Slogwang #include <net/if.h> 56*a9643ea8Slogwang #include <net/if_var.h> 57*a9643ea8Slogwang #include <net/if_types.h> 58*a9643ea8Slogwang #include <net/if_media.h> 59*a9643ea8Slogwang #include <net/bpf.h> 60*a9643ea8Slogwang #include <net/ethernet.h> 61*a9643ea8Slogwang #include <net/mp_ring.h> 62*a9643ea8Slogwang 63*a9643ea8Slogwang #include <netinet/in.h> 64*a9643ea8Slogwang #include <netinet/in_pcb.h> 65*a9643ea8Slogwang #include <netinet/tcp_lro.h> 66*a9643ea8Slogwang #include <netinet/in_systm.h> 67*a9643ea8Slogwang #include <netinet/if_ether.h> 68*a9643ea8Slogwang #include <netinet/ip.h> 69*a9643ea8Slogwang #include <netinet/ip6.h> 70*a9643ea8Slogwang #include <netinet/tcp.h> 71*a9643ea8Slogwang 72*a9643ea8Slogwang #include <machine/bus.h> 73*a9643ea8Slogwang #include <machine/in_cksum.h> 74*a9643ea8Slogwang 75*a9643ea8Slogwang #include <vm/vm.h> 76*a9643ea8Slogwang #include <vm/pmap.h> 77*a9643ea8Slogwang 78*a9643ea8Slogwang #include <dev/led/led.h> 79*a9643ea8Slogwang #include <dev/pci/pcireg.h> 80*a9643ea8Slogwang #include <dev/pci/pcivar.h> 81*a9643ea8Slogwang #include <dev/pci/pci_private.h> 82*a9643ea8Slogwang 83*a9643ea8Slogwang #include <net/iflib.h> 84*a9643ea8Slogwang 85*a9643ea8Slogwang #include "ifdi_if.h" 86*a9643ea8Slogwang 87*a9643ea8Slogwang #if defined(__i386__) || defined(__amd64__) 88*a9643ea8Slogwang #include <sys/memdesc.h> 89*a9643ea8Slogwang #include <machine/bus.h> 90*a9643ea8Slogwang #include <machine/md_var.h> 91*a9643ea8Slogwang #include <machine/specialreg.h> 92*a9643ea8Slogwang #include <x86/include/busdma_impl.h> 93*a9643ea8Slogwang #include <x86/iommu/busdma_dmar.h> 94*a9643ea8Slogwang #endif 95*a9643ea8Slogwang 96*a9643ea8Slogwang 97*a9643ea8Slogwang /* 98*a9643ea8Slogwang * enable accounting of every mbuf as it comes in to and goes out of iflib's software descriptor references 99*a9643ea8Slogwang */ 100*a9643ea8Slogwang #define MEMORY_LOGGING 0 101*a9643ea8Slogwang /* 102*a9643ea8Slogwang * Enable mbuf vectors for compressing long mbuf chains 103*a9643ea8Slogwang */ 104*a9643ea8Slogwang 105*a9643ea8Slogwang /* 106*a9643ea8Slogwang * NB: 107*a9643ea8Slogwang * - Prefetching in tx cleaning should perhaps be a tunable. The distance ahead 108*a9643ea8Slogwang * we prefetch needs to be determined by the time spent in m_free vis a vis 109*a9643ea8Slogwang * the cost of a prefetch. This will of course vary based on the workload: 110*a9643ea8Slogwang * - NFLX's m_free path is dominated by vm-based M_EXT manipulation which 111*a9643ea8Slogwang * is quite expensive, thus suggesting very little prefetch. 112*a9643ea8Slogwang * - small packet forwarding which is just returning a single mbuf to 113*a9643ea8Slogwang * UMA will typically be very fast vis a vis the cost of a memory 114*a9643ea8Slogwang * access. 115*a9643ea8Slogwang */ 116*a9643ea8Slogwang 117*a9643ea8Slogwang 118*a9643ea8Slogwang /* 119*a9643ea8Slogwang * File organization: 120*a9643ea8Slogwang * - private structures 121*a9643ea8Slogwang * - iflib private utility functions 122*a9643ea8Slogwang * - ifnet functions 123*a9643ea8Slogwang * - vlan registry and other exported functions 124*a9643ea8Slogwang * - iflib public core functions 125*a9643ea8Slogwang * 126*a9643ea8Slogwang * 127*a9643ea8Slogwang */ 128*a9643ea8Slogwang static MALLOC_DEFINE(M_IFLIB, "iflib", "ifnet library"); 129*a9643ea8Slogwang 130*a9643ea8Slogwang struct iflib_txq; 131*a9643ea8Slogwang typedef struct iflib_txq *iflib_txq_t; 132*a9643ea8Slogwang struct iflib_rxq; 133*a9643ea8Slogwang typedef struct iflib_rxq *iflib_rxq_t; 134*a9643ea8Slogwang struct iflib_fl; 135*a9643ea8Slogwang typedef struct iflib_fl *iflib_fl_t; 136*a9643ea8Slogwang 137*a9643ea8Slogwang typedef struct iflib_filter_info { 138*a9643ea8Slogwang driver_filter_t *ifi_filter; 139*a9643ea8Slogwang void *ifi_filter_arg; 140*a9643ea8Slogwang struct grouptask *ifi_task; 141*a9643ea8Slogwang } *iflib_filter_info_t; 142*a9643ea8Slogwang 143*a9643ea8Slogwang struct iflib_ctx { 144*a9643ea8Slogwang KOBJ_FIELDS; 145*a9643ea8Slogwang /* 146*a9643ea8Slogwang * Pointer to hardware driver's softc 147*a9643ea8Slogwang */ 148*a9643ea8Slogwang void *ifc_softc; 149*a9643ea8Slogwang device_t ifc_dev; 150*a9643ea8Slogwang if_t ifc_ifp; 151*a9643ea8Slogwang 152*a9643ea8Slogwang cpuset_t ifc_cpus; 153*a9643ea8Slogwang if_shared_ctx_t ifc_sctx; 154*a9643ea8Slogwang struct if_softc_ctx ifc_softc_ctx; 155*a9643ea8Slogwang 156*a9643ea8Slogwang struct mtx ifc_mtx; 157*a9643ea8Slogwang 158*a9643ea8Slogwang uint16_t ifc_nhwtxqs; 159*a9643ea8Slogwang uint16_t ifc_nhwrxqs; 160*a9643ea8Slogwang 161*a9643ea8Slogwang iflib_txq_t ifc_txqs; 162*a9643ea8Slogwang iflib_rxq_t ifc_rxqs; 163*a9643ea8Slogwang uint32_t ifc_if_flags; 164*a9643ea8Slogwang uint32_t ifc_flags; 165*a9643ea8Slogwang uint32_t ifc_max_fl_buf_size; 166*a9643ea8Slogwang int ifc_in_detach; 167*a9643ea8Slogwang 168*a9643ea8Slogwang int ifc_link_state; 169*a9643ea8Slogwang int ifc_link_irq; 170*a9643ea8Slogwang int ifc_pause_frames; 171*a9643ea8Slogwang int ifc_watchdog_events; 172*a9643ea8Slogwang struct cdev *ifc_led_dev; 173*a9643ea8Slogwang struct resource *ifc_msix_mem; 174*a9643ea8Slogwang 175*a9643ea8Slogwang struct if_irq ifc_legacy_irq; 176*a9643ea8Slogwang struct grouptask ifc_admin_task; 177*a9643ea8Slogwang struct grouptask ifc_vflr_task; 178*a9643ea8Slogwang struct iflib_filter_info ifc_filter_info; 179*a9643ea8Slogwang struct ifmedia ifc_media; 180*a9643ea8Slogwang 181*a9643ea8Slogwang struct sysctl_oid *ifc_sysctl_node; 182*a9643ea8Slogwang uint16_t ifc_sysctl_ntxqs; 183*a9643ea8Slogwang uint16_t ifc_sysctl_nrxqs; 184*a9643ea8Slogwang uint16_t ifc_sysctl_qs_eq_override; 185*a9643ea8Slogwang 186*a9643ea8Slogwang uint16_t ifc_sysctl_ntxds[8]; 187*a9643ea8Slogwang uint16_t ifc_sysctl_nrxds[8]; 188*a9643ea8Slogwang struct if_txrx ifc_txrx; 189*a9643ea8Slogwang #define isc_txd_encap ifc_txrx.ift_txd_encap 190*a9643ea8Slogwang #define isc_txd_flush ifc_txrx.ift_txd_flush 191*a9643ea8Slogwang #define isc_txd_credits_update ifc_txrx.ift_txd_credits_update 192*a9643ea8Slogwang #define isc_rxd_available ifc_txrx.ift_rxd_available 193*a9643ea8Slogwang #define isc_rxd_pkt_get ifc_txrx.ift_rxd_pkt_get 194*a9643ea8Slogwang #define isc_rxd_refill ifc_txrx.ift_rxd_refill 195*a9643ea8Slogwang #define isc_rxd_flush ifc_txrx.ift_rxd_flush 196*a9643ea8Slogwang #define isc_rxd_refill ifc_txrx.ift_rxd_refill 197*a9643ea8Slogwang #define isc_rxd_refill ifc_txrx.ift_rxd_refill 198*a9643ea8Slogwang #define isc_legacy_intr ifc_txrx.ift_legacy_intr 199*a9643ea8Slogwang eventhandler_tag ifc_vlan_attach_event; 200*a9643ea8Slogwang eventhandler_tag ifc_vlan_detach_event; 201*a9643ea8Slogwang uint8_t ifc_mac[ETHER_ADDR_LEN]; 202*a9643ea8Slogwang char ifc_mtx_name[16]; 203*a9643ea8Slogwang }; 204*a9643ea8Slogwang 205*a9643ea8Slogwang 206*a9643ea8Slogwang void * 207*a9643ea8Slogwang iflib_get_softc(if_ctx_t ctx) 208*a9643ea8Slogwang { 209*a9643ea8Slogwang 210*a9643ea8Slogwang return (ctx->ifc_softc); 211*a9643ea8Slogwang } 212*a9643ea8Slogwang 213*a9643ea8Slogwang device_t 214*a9643ea8Slogwang iflib_get_dev(if_ctx_t ctx) 215*a9643ea8Slogwang { 216*a9643ea8Slogwang 217*a9643ea8Slogwang return (ctx->ifc_dev); 218*a9643ea8Slogwang } 219*a9643ea8Slogwang 220*a9643ea8Slogwang if_t 221*a9643ea8Slogwang iflib_get_ifp(if_ctx_t ctx) 222*a9643ea8Slogwang { 223*a9643ea8Slogwang 224*a9643ea8Slogwang return (ctx->ifc_ifp); 225*a9643ea8Slogwang } 226*a9643ea8Slogwang 227*a9643ea8Slogwang struct ifmedia * 228*a9643ea8Slogwang iflib_get_media(if_ctx_t ctx) 229*a9643ea8Slogwang { 230*a9643ea8Slogwang 231*a9643ea8Slogwang return (&ctx->ifc_media); 232*a9643ea8Slogwang } 233*a9643ea8Slogwang 234*a9643ea8Slogwang void 235*a9643ea8Slogwang iflib_set_mac(if_ctx_t ctx, uint8_t mac[ETHER_ADDR_LEN]) 236*a9643ea8Slogwang { 237*a9643ea8Slogwang 238*a9643ea8Slogwang bcopy(mac, ctx->ifc_mac, ETHER_ADDR_LEN); 239*a9643ea8Slogwang } 240*a9643ea8Slogwang 241*a9643ea8Slogwang if_softc_ctx_t 242*a9643ea8Slogwang iflib_get_softc_ctx(if_ctx_t ctx) 243*a9643ea8Slogwang { 244*a9643ea8Slogwang 245*a9643ea8Slogwang return (&ctx->ifc_softc_ctx); 246*a9643ea8Slogwang } 247*a9643ea8Slogwang 248*a9643ea8Slogwang if_shared_ctx_t 249*a9643ea8Slogwang iflib_get_sctx(if_ctx_t ctx) 250*a9643ea8Slogwang { 251*a9643ea8Slogwang 252*a9643ea8Slogwang return (ctx->ifc_sctx); 253*a9643ea8Slogwang } 254*a9643ea8Slogwang 255*a9643ea8Slogwang #define CACHE_PTR_INCREMENT (CACHE_LINE_SIZE/sizeof(void*)) 256*a9643ea8Slogwang 257*a9643ea8Slogwang #define LINK_ACTIVE(ctx) ((ctx)->ifc_link_state == LINK_STATE_UP) 258*a9643ea8Slogwang #define CTX_IS_VF(ctx) ((ctx)->ifc_sctx->isc_flags & IFLIB_IS_VF) 259*a9643ea8Slogwang 260*a9643ea8Slogwang #define RX_SW_DESC_MAP_CREATED (1 << 0) 261*a9643ea8Slogwang #define TX_SW_DESC_MAP_CREATED (1 << 1) 262*a9643ea8Slogwang #define RX_SW_DESC_INUSE (1 << 3) 263*a9643ea8Slogwang #define TX_SW_DESC_MAPPED (1 << 4) 264*a9643ea8Slogwang 265*a9643ea8Slogwang typedef struct iflib_sw_rx_desc { 266*a9643ea8Slogwang bus_dmamap_t ifsd_map; /* bus_dma map for packet */ 267*a9643ea8Slogwang struct mbuf *ifsd_m; /* rx: uninitialized mbuf */ 268*a9643ea8Slogwang caddr_t ifsd_cl; /* direct cluster pointer for rx */ 269*a9643ea8Slogwang uint16_t ifsd_flags; 270*a9643ea8Slogwang } *iflib_rxsd_t; 271*a9643ea8Slogwang 272*a9643ea8Slogwang typedef struct iflib_sw_tx_desc_val { 273*a9643ea8Slogwang bus_dmamap_t ifsd_map; /* bus_dma map for packet */ 274*a9643ea8Slogwang struct mbuf *ifsd_m; /* pkthdr mbuf */ 275*a9643ea8Slogwang uint8_t ifsd_flags; 276*a9643ea8Slogwang } *iflib_txsd_val_t; 277*a9643ea8Slogwang 278*a9643ea8Slogwang typedef struct iflib_sw_tx_desc_array { 279*a9643ea8Slogwang bus_dmamap_t *ifsd_map; /* bus_dma maps for packet */ 280*a9643ea8Slogwang struct mbuf **ifsd_m; /* pkthdr mbufs */ 281*a9643ea8Slogwang uint8_t *ifsd_flags; 282*a9643ea8Slogwang } iflib_txsd_array_t; 283*a9643ea8Slogwang 284*a9643ea8Slogwang 285*a9643ea8Slogwang /* magic number that should be high enough for any hardware */ 286*a9643ea8Slogwang #define IFLIB_MAX_TX_SEGS 128 287*a9643ea8Slogwang #define IFLIB_MAX_RX_SEGS 32 288*a9643ea8Slogwang #define IFLIB_RX_COPY_THRESH 128 289*a9643ea8Slogwang #define IFLIB_MAX_RX_REFRESH 32 290*a9643ea8Slogwang #define IFLIB_QUEUE_IDLE 0 291*a9643ea8Slogwang #define IFLIB_QUEUE_HUNG 1 292*a9643ea8Slogwang #define IFLIB_QUEUE_WORKING 2 293*a9643ea8Slogwang 294*a9643ea8Slogwang /* this should really scale with ring size - 32 is a fairly arbitrary value for this */ 295*a9643ea8Slogwang #define TX_BATCH_SIZE 16 296*a9643ea8Slogwang 297*a9643ea8Slogwang #define IFLIB_RESTART_BUDGET 8 298*a9643ea8Slogwang 299*a9643ea8Slogwang #define IFC_LEGACY 0x01 300*a9643ea8Slogwang #define IFC_QFLUSH 0x02 301*a9643ea8Slogwang #define IFC_MULTISEG 0x04 302*a9643ea8Slogwang #define IFC_DMAR 0x08 303*a9643ea8Slogwang #define IFC_SC_ALLOCATED 0x10 304*a9643ea8Slogwang 305*a9643ea8Slogwang #define CSUM_OFFLOAD (CSUM_IP_TSO|CSUM_IP6_TSO|CSUM_IP| \ 306*a9643ea8Slogwang CSUM_IP_UDP|CSUM_IP_TCP|CSUM_IP_SCTP| \ 307*a9643ea8Slogwang CSUM_IP6_UDP|CSUM_IP6_TCP|CSUM_IP6_SCTP) 308*a9643ea8Slogwang struct iflib_txq { 309*a9643ea8Slogwang uint16_t ift_in_use; 310*a9643ea8Slogwang uint16_t ift_cidx; 311*a9643ea8Slogwang uint16_t ift_cidx_processed; 312*a9643ea8Slogwang uint16_t ift_pidx; 313*a9643ea8Slogwang uint8_t ift_gen; 314*a9643ea8Slogwang uint8_t ift_db_pending; 315*a9643ea8Slogwang uint8_t ift_db_pending_queued; 316*a9643ea8Slogwang uint8_t ift_npending; 317*a9643ea8Slogwang uint8_t ift_br_offset; 318*a9643ea8Slogwang /* implicit pad */ 319*a9643ea8Slogwang uint64_t ift_processed; 320*a9643ea8Slogwang uint64_t ift_cleaned; 321*a9643ea8Slogwang #if MEMORY_LOGGING 322*a9643ea8Slogwang uint64_t ift_enqueued; 323*a9643ea8Slogwang uint64_t ift_dequeued; 324*a9643ea8Slogwang #endif 325*a9643ea8Slogwang uint64_t ift_no_tx_dma_setup; 326*a9643ea8Slogwang uint64_t ift_no_desc_avail; 327*a9643ea8Slogwang uint64_t ift_mbuf_defrag_failed; 328*a9643ea8Slogwang uint64_t ift_mbuf_defrag; 329*a9643ea8Slogwang uint64_t ift_map_failed; 330*a9643ea8Slogwang uint64_t ift_txd_encap_efbig; 331*a9643ea8Slogwang uint64_t ift_pullups; 332*a9643ea8Slogwang 333*a9643ea8Slogwang struct mtx ift_mtx; 334*a9643ea8Slogwang struct mtx ift_db_mtx; 335*a9643ea8Slogwang 336*a9643ea8Slogwang /* constant values */ 337*a9643ea8Slogwang if_ctx_t ift_ctx; 338*a9643ea8Slogwang struct ifmp_ring **ift_br; 339*a9643ea8Slogwang struct grouptask ift_task; 340*a9643ea8Slogwang uint16_t ift_size; 341*a9643ea8Slogwang uint16_t ift_id; 342*a9643ea8Slogwang struct callout ift_timer; 343*a9643ea8Slogwang struct callout ift_db_check; 344*a9643ea8Slogwang 345*a9643ea8Slogwang iflib_txsd_array_t ift_sds; 346*a9643ea8Slogwang uint8_t ift_nbr; 347*a9643ea8Slogwang uint8_t ift_qstatus; 348*a9643ea8Slogwang uint8_t ift_active; 349*a9643ea8Slogwang uint8_t ift_closed; 350*a9643ea8Slogwang int ift_watchdog_time; 351*a9643ea8Slogwang struct iflib_filter_info ift_filter_info; 352*a9643ea8Slogwang bus_dma_tag_t ift_desc_tag; 353*a9643ea8Slogwang bus_dma_tag_t ift_tso_desc_tag; 354*a9643ea8Slogwang iflib_dma_info_t ift_ifdi; 355*a9643ea8Slogwang #define MTX_NAME_LEN 16 356*a9643ea8Slogwang char ift_mtx_name[MTX_NAME_LEN]; 357*a9643ea8Slogwang char ift_db_mtx_name[MTX_NAME_LEN]; 358*a9643ea8Slogwang bus_dma_segment_t ift_segs[IFLIB_MAX_TX_SEGS] __aligned(CACHE_LINE_SIZE); 359*a9643ea8Slogwang } __aligned(CACHE_LINE_SIZE); 360*a9643ea8Slogwang 361*a9643ea8Slogwang struct iflib_fl { 362*a9643ea8Slogwang uint16_t ifl_cidx; 363*a9643ea8Slogwang uint16_t ifl_pidx; 364*a9643ea8Slogwang uint16_t ifl_credits; 365*a9643ea8Slogwang uint8_t ifl_gen; 366*a9643ea8Slogwang #if MEMORY_LOGGING 367*a9643ea8Slogwang uint64_t ifl_m_enqueued; 368*a9643ea8Slogwang uint64_t ifl_m_dequeued; 369*a9643ea8Slogwang uint64_t ifl_cl_enqueued; 370*a9643ea8Slogwang uint64_t ifl_cl_dequeued; 371*a9643ea8Slogwang #endif 372*a9643ea8Slogwang /* implicit pad */ 373*a9643ea8Slogwang 374*a9643ea8Slogwang /* constant */ 375*a9643ea8Slogwang uint16_t ifl_size; 376*a9643ea8Slogwang uint16_t ifl_buf_size; 377*a9643ea8Slogwang uint16_t ifl_cltype; 378*a9643ea8Slogwang uma_zone_t ifl_zone; 379*a9643ea8Slogwang iflib_rxsd_t ifl_sds; 380*a9643ea8Slogwang iflib_rxq_t ifl_rxq; 381*a9643ea8Slogwang uint8_t ifl_id; 382*a9643ea8Slogwang bus_dma_tag_t ifl_desc_tag; 383*a9643ea8Slogwang iflib_dma_info_t ifl_ifdi; 384*a9643ea8Slogwang uint64_t ifl_bus_addrs[IFLIB_MAX_RX_REFRESH] __aligned(CACHE_LINE_SIZE); 385*a9643ea8Slogwang caddr_t ifl_vm_addrs[IFLIB_MAX_RX_REFRESH]; 386*a9643ea8Slogwang } __aligned(CACHE_LINE_SIZE); 387*a9643ea8Slogwang 388*a9643ea8Slogwang static inline int 389*a9643ea8Slogwang get_inuse(int size, int cidx, int pidx, int gen) 390*a9643ea8Slogwang { 391*a9643ea8Slogwang int used; 392*a9643ea8Slogwang 393*a9643ea8Slogwang if (pidx > cidx) 394*a9643ea8Slogwang used = pidx - cidx; 395*a9643ea8Slogwang else if (pidx < cidx) 396*a9643ea8Slogwang used = size - cidx + pidx; 397*a9643ea8Slogwang else if (gen == 0 && pidx == cidx) 398*a9643ea8Slogwang used = 0; 399*a9643ea8Slogwang else if (gen == 1 && pidx == cidx) 400*a9643ea8Slogwang used = size; 401*a9643ea8Slogwang else 402*a9643ea8Slogwang panic("bad state"); 403*a9643ea8Slogwang 404*a9643ea8Slogwang return (used); 405*a9643ea8Slogwang } 406*a9643ea8Slogwang 407*a9643ea8Slogwang #define TXQ_AVAIL(txq) (txq->ift_size - get_inuse(txq->ift_size, txq->ift_cidx, txq->ift_pidx, txq->ift_gen)) 408*a9643ea8Slogwang 409*a9643ea8Slogwang #define IDXDIFF(head, tail, wrap) \ 410*a9643ea8Slogwang ((head) >= (tail) ? (head) - (tail) : (wrap) - (tail) + (head)) 411*a9643ea8Slogwang 412*a9643ea8Slogwang struct iflib_rxq { 413*a9643ea8Slogwang /* If there is a separate completion queue - 414*a9643ea8Slogwang * these are the cq cidx and pidx. Otherwise 415*a9643ea8Slogwang * these are unused. 416*a9643ea8Slogwang */ 417*a9643ea8Slogwang uint16_t ifr_size; 418*a9643ea8Slogwang uint16_t ifr_cq_cidx; 419*a9643ea8Slogwang uint16_t ifr_cq_pidx; 420*a9643ea8Slogwang uint8_t ifr_cq_gen; 421*a9643ea8Slogwang uint8_t ifr_fl_offset; 422*a9643ea8Slogwang 423*a9643ea8Slogwang if_ctx_t ifr_ctx; 424*a9643ea8Slogwang iflib_fl_t ifr_fl; 425*a9643ea8Slogwang uint64_t ifr_rx_irq; 426*a9643ea8Slogwang uint16_t ifr_id; 427*a9643ea8Slogwang uint8_t ifr_lro_enabled; 428*a9643ea8Slogwang uint8_t ifr_nfl; 429*a9643ea8Slogwang struct lro_ctrl ifr_lc; 430*a9643ea8Slogwang struct grouptask ifr_task; 431*a9643ea8Slogwang struct iflib_filter_info ifr_filter_info; 432*a9643ea8Slogwang iflib_dma_info_t ifr_ifdi; 433*a9643ea8Slogwang /* dynamically allocate if any drivers need a value substantially larger than this */ 434*a9643ea8Slogwang struct if_rxd_frag ifr_frags[IFLIB_MAX_RX_SEGS] __aligned(CACHE_LINE_SIZE); 435*a9643ea8Slogwang } __aligned(CACHE_LINE_SIZE); 436*a9643ea8Slogwang 437*a9643ea8Slogwang /* 438*a9643ea8Slogwang * Only allow a single packet to take up most 1/nth of the tx ring 439*a9643ea8Slogwang */ 440*a9643ea8Slogwang #define MAX_SINGLE_PACKET_FRACTION 12 441*a9643ea8Slogwang #define IF_BAD_DMA (bus_addr_t)-1 442*a9643ea8Slogwang 443*a9643ea8Slogwang static int enable_msix = 1; 444*a9643ea8Slogwang 445*a9643ea8Slogwang #define mtx_held(m) (((m)->mtx_lock & ~MTX_FLAGMASK) != (uintptr_t)0) 446*a9643ea8Slogwang 447*a9643ea8Slogwang 448*a9643ea8Slogwang 449*a9643ea8Slogwang #define CTX_ACTIVE(ctx) ((if_getdrvflags((ctx)->ifc_ifp) & IFF_DRV_RUNNING)) 450*a9643ea8Slogwang 451*a9643ea8Slogwang #define CTX_LOCK_INIT(_sc, _name) mtx_init(&(_sc)->ifc_mtx, _name, "iflib ctx lock", MTX_DEF) 452*a9643ea8Slogwang 453*a9643ea8Slogwang #define CTX_LOCK(ctx) mtx_lock(&(ctx)->ifc_mtx) 454*a9643ea8Slogwang #define CTX_UNLOCK(ctx) mtx_unlock(&(ctx)->ifc_mtx) 455*a9643ea8Slogwang #define CTX_LOCK_DESTROY(ctx) mtx_destroy(&(ctx)->ifc_mtx) 456*a9643ea8Slogwang 457*a9643ea8Slogwang 458*a9643ea8Slogwang #define TXDB_LOCK_INIT(txq) mtx_init(&(txq)->ift_db_mtx, (txq)->ift_db_mtx_name, NULL, MTX_DEF) 459*a9643ea8Slogwang #define TXDB_TRYLOCK(txq) mtx_trylock(&(txq)->ift_db_mtx) 460*a9643ea8Slogwang #define TXDB_LOCK(txq) mtx_lock(&(txq)->ift_db_mtx) 461*a9643ea8Slogwang #define TXDB_UNLOCK(txq) mtx_unlock(&(txq)->ift_db_mtx) 462*a9643ea8Slogwang #define TXDB_LOCK_DESTROY(txq) mtx_destroy(&(txq)->ift_db_mtx) 463*a9643ea8Slogwang 464*a9643ea8Slogwang #define CALLOUT_LOCK(txq) mtx_lock(&txq->ift_mtx) 465*a9643ea8Slogwang #define CALLOUT_UNLOCK(txq) mtx_unlock(&txq->ift_mtx) 466*a9643ea8Slogwang 467*a9643ea8Slogwang 468*a9643ea8Slogwang /* Our boot-time initialization hook */ 469*a9643ea8Slogwang static int iflib_module_event_handler(module_t, int, void *); 470*a9643ea8Slogwang 471*a9643ea8Slogwang static moduledata_t iflib_moduledata = { 472*a9643ea8Slogwang "iflib", 473*a9643ea8Slogwang iflib_module_event_handler, 474*a9643ea8Slogwang NULL 475*a9643ea8Slogwang }; 476*a9643ea8Slogwang 477*a9643ea8Slogwang DECLARE_MODULE(iflib, iflib_moduledata, SI_SUB_INIT_IF, SI_ORDER_ANY); 478*a9643ea8Slogwang MODULE_VERSION(iflib, 1); 479*a9643ea8Slogwang 480*a9643ea8Slogwang MODULE_DEPEND(iflib, pci, 1, 1, 1); 481*a9643ea8Slogwang MODULE_DEPEND(iflib, ether, 1, 1, 1); 482*a9643ea8Slogwang 483*a9643ea8Slogwang TASKQGROUP_DEFINE(if_io_tqg, mp_ncpus, 1); 484*a9643ea8Slogwang TASKQGROUP_DEFINE(if_config_tqg, 1, 1); 485*a9643ea8Slogwang 486*a9643ea8Slogwang #ifndef IFLIB_DEBUG_COUNTERS 487*a9643ea8Slogwang #ifdef INVARIANTS 488*a9643ea8Slogwang #define IFLIB_DEBUG_COUNTERS 1 489*a9643ea8Slogwang #else 490*a9643ea8Slogwang #define IFLIB_DEBUG_COUNTERS 0 491*a9643ea8Slogwang #endif /* !INVARIANTS */ 492*a9643ea8Slogwang #endif 493*a9643ea8Slogwang 494*a9643ea8Slogwang static SYSCTL_NODE(_net, OID_AUTO, iflib, CTLFLAG_RD, 0, 495*a9643ea8Slogwang "iflib driver parameters"); 496*a9643ea8Slogwang 497*a9643ea8Slogwang /* 498*a9643ea8Slogwang * XXX need to ensure that this can't accidentally cause the head to be moved backwards 499*a9643ea8Slogwang */ 500*a9643ea8Slogwang static int iflib_min_tx_latency = 0; 501*a9643ea8Slogwang 502*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, min_tx_latency, CTLFLAG_RW, 503*a9643ea8Slogwang &iflib_min_tx_latency, 0, "minimize transmit latency at the possibel expense of throughput"); 504*a9643ea8Slogwang 505*a9643ea8Slogwang 506*a9643ea8Slogwang #if IFLIB_DEBUG_COUNTERS 507*a9643ea8Slogwang 508*a9643ea8Slogwang static int iflib_tx_seen; 509*a9643ea8Slogwang static int iflib_tx_sent; 510*a9643ea8Slogwang static int iflib_tx_encap; 511*a9643ea8Slogwang static int iflib_rx_allocs; 512*a9643ea8Slogwang static int iflib_fl_refills; 513*a9643ea8Slogwang static int iflib_fl_refills_large; 514*a9643ea8Slogwang static int iflib_tx_frees; 515*a9643ea8Slogwang 516*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, tx_seen, CTLFLAG_RD, 517*a9643ea8Slogwang &iflib_tx_seen, 0, "# tx mbufs seen"); 518*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, tx_sent, CTLFLAG_RD, 519*a9643ea8Slogwang &iflib_tx_sent, 0, "# tx mbufs sent"); 520*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, tx_encap, CTLFLAG_RD, 521*a9643ea8Slogwang &iflib_tx_encap, 0, "# tx mbufs encapped"); 522*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, tx_frees, CTLFLAG_RD, 523*a9643ea8Slogwang &iflib_tx_frees, 0, "# tx frees"); 524*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, rx_allocs, CTLFLAG_RD, 525*a9643ea8Slogwang &iflib_rx_allocs, 0, "# rx allocations"); 526*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, fl_refills, CTLFLAG_RD, 527*a9643ea8Slogwang &iflib_fl_refills, 0, "# refills"); 528*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, fl_refills_large, CTLFLAG_RD, 529*a9643ea8Slogwang &iflib_fl_refills_large, 0, "# large refills"); 530*a9643ea8Slogwang 531*a9643ea8Slogwang 532*a9643ea8Slogwang static int iflib_txq_drain_flushing; 533*a9643ea8Slogwang static int iflib_txq_drain_oactive; 534*a9643ea8Slogwang static int iflib_txq_drain_notready; 535*a9643ea8Slogwang static int iflib_txq_drain_encapfail; 536*a9643ea8Slogwang 537*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_flushing, CTLFLAG_RD, 538*a9643ea8Slogwang &iflib_txq_drain_flushing, 0, "# drain flushes"); 539*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_oactive, CTLFLAG_RD, 540*a9643ea8Slogwang &iflib_txq_drain_oactive, 0, "# drain oactives"); 541*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_notready, CTLFLAG_RD, 542*a9643ea8Slogwang &iflib_txq_drain_notready, 0, "# drain notready"); 543*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_encapfail, CTLFLAG_RD, 544*a9643ea8Slogwang &iflib_txq_drain_encapfail, 0, "# drain encap fails"); 545*a9643ea8Slogwang 546*a9643ea8Slogwang 547*a9643ea8Slogwang static int iflib_encap_load_mbuf_fail; 548*a9643ea8Slogwang static int iflib_encap_txq_avail_fail; 549*a9643ea8Slogwang static int iflib_encap_txd_encap_fail; 550*a9643ea8Slogwang 551*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, encap_load_mbuf_fail, CTLFLAG_RD, 552*a9643ea8Slogwang &iflib_encap_load_mbuf_fail, 0, "# busdma load failures"); 553*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, encap_txq_avail_fail, CTLFLAG_RD, 554*a9643ea8Slogwang &iflib_encap_txq_avail_fail, 0, "# txq avail failures"); 555*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, encap_txd_encap_fail, CTLFLAG_RD, 556*a9643ea8Slogwang &iflib_encap_txd_encap_fail, 0, "# driver encap failures"); 557*a9643ea8Slogwang 558*a9643ea8Slogwang static int iflib_task_fn_rxs; 559*a9643ea8Slogwang static int iflib_rx_intr_enables; 560*a9643ea8Slogwang static int iflib_fast_intrs; 561*a9643ea8Slogwang static int iflib_intr_link; 562*a9643ea8Slogwang static int iflib_intr_msix; 563*a9643ea8Slogwang static int iflib_rx_unavail; 564*a9643ea8Slogwang static int iflib_rx_ctx_inactive; 565*a9643ea8Slogwang static int iflib_rx_zero_len; 566*a9643ea8Slogwang static int iflib_rx_if_input; 567*a9643ea8Slogwang static int iflib_rx_mbuf_null; 568*a9643ea8Slogwang static int iflib_rxd_flush; 569*a9643ea8Slogwang 570*a9643ea8Slogwang static int iflib_verbose_debug; 571*a9643ea8Slogwang 572*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, intr_link, CTLFLAG_RD, 573*a9643ea8Slogwang &iflib_intr_link, 0, "# intr link calls"); 574*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, intr_msix, CTLFLAG_RD, 575*a9643ea8Slogwang &iflib_intr_msix, 0, "# intr msix calls"); 576*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, task_fn_rx, CTLFLAG_RD, 577*a9643ea8Slogwang &iflib_task_fn_rxs, 0, "# task_fn_rx calls"); 578*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, rx_intr_enables, CTLFLAG_RD, 579*a9643ea8Slogwang &iflib_rx_intr_enables, 0, "# rx intr enables"); 580*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, fast_intrs, CTLFLAG_RD, 581*a9643ea8Slogwang &iflib_fast_intrs, 0, "# fast_intr calls"); 582*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, rx_unavail, CTLFLAG_RD, 583*a9643ea8Slogwang &iflib_rx_unavail, 0, "# times rxeof called with no available data"); 584*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, rx_ctx_inactive, CTLFLAG_RD, 585*a9643ea8Slogwang &iflib_rx_ctx_inactive, 0, "# times rxeof called with inactive context"); 586*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, rx_zero_len, CTLFLAG_RD, 587*a9643ea8Slogwang &iflib_rx_zero_len, 0, "# times rxeof saw zero len mbuf"); 588*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, rx_if_input, CTLFLAG_RD, 589*a9643ea8Slogwang &iflib_rx_if_input, 0, "# times rxeof called if_input"); 590*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, rx_mbuf_null, CTLFLAG_RD, 591*a9643ea8Slogwang &iflib_rx_mbuf_null, 0, "# times rxeof got null mbuf"); 592*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, rxd_flush, CTLFLAG_RD, 593*a9643ea8Slogwang &iflib_rxd_flush, 0, "# times rxd_flush called"); 594*a9643ea8Slogwang SYSCTL_INT(_net_iflib, OID_AUTO, verbose_debug, CTLFLAG_RW, 595*a9643ea8Slogwang &iflib_verbose_debug, 0, "enable verbose debugging"); 596*a9643ea8Slogwang 597*a9643ea8Slogwang #define DBG_COUNTER_INC(name) atomic_add_int(&(iflib_ ## name), 1) 598*a9643ea8Slogwang 599*a9643ea8Slogwang #else 600*a9643ea8Slogwang #define DBG_COUNTER_INC(name) 601*a9643ea8Slogwang 602*a9643ea8Slogwang #endif 603*a9643ea8Slogwang 604*a9643ea8Slogwang 605*a9643ea8Slogwang 606*a9643ea8Slogwang #define IFLIB_DEBUG 0 607*a9643ea8Slogwang 608*a9643ea8Slogwang static void iflib_tx_structures_free(if_ctx_t ctx); 609*a9643ea8Slogwang static void iflib_rx_structures_free(if_ctx_t ctx); 610*a9643ea8Slogwang static int iflib_queues_alloc(if_ctx_t ctx); 611*a9643ea8Slogwang static int iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq); 612*a9643ea8Slogwang static int iflib_rxd_avail(if_ctx_t ctx, iflib_rxq_t rxq, int cidx, int budget); 613*a9643ea8Slogwang static int iflib_qset_structures_setup(if_ctx_t ctx); 614*a9643ea8Slogwang static int iflib_msix_init(if_ctx_t ctx); 615*a9643ea8Slogwang static int iflib_legacy_setup(if_ctx_t ctx, driver_filter_t filter, void *filterarg, int *rid, char *str); 616*a9643ea8Slogwang static void iflib_txq_check_drain(iflib_txq_t txq, int budget); 617*a9643ea8Slogwang static uint32_t iflib_txq_can_drain(struct ifmp_ring *); 618*a9643ea8Slogwang static int iflib_register(if_ctx_t); 619*a9643ea8Slogwang static void iflib_init_locked(if_ctx_t ctx); 620*a9643ea8Slogwang static void iflib_add_device_sysctl_pre(if_ctx_t ctx); 621*a9643ea8Slogwang static void iflib_add_device_sysctl_post(if_ctx_t ctx); 622*a9643ea8Slogwang 623*a9643ea8Slogwang 624*a9643ea8Slogwang #ifdef DEV_NETMAP 625*a9643ea8Slogwang #include <sys/selinfo.h> 626*a9643ea8Slogwang #include <net/netmap.h> 627*a9643ea8Slogwang #include <dev/netmap/netmap_kern.h> 628*a9643ea8Slogwang 629*a9643ea8Slogwang MODULE_DEPEND(iflib, netmap, 1, 1, 1); 630*a9643ea8Slogwang 631*a9643ea8Slogwang /* 632*a9643ea8Slogwang * device-specific sysctl variables: 633*a9643ea8Slogwang * 634*a9643ea8Slogwang * iflib_crcstrip: 0: keep CRC in rx frames (default), 1: strip it. 635*a9643ea8Slogwang * During regular operations the CRC is stripped, but on some 636*a9643ea8Slogwang * hardware reception of frames not multiple of 64 is slower, 637*a9643ea8Slogwang * so using crcstrip=0 helps in benchmarks. 638*a9643ea8Slogwang * 639*a9643ea8Slogwang * iflib_rx_miss, iflib_rx_miss_bufs: 640*a9643ea8Slogwang * count packets that might be missed due to lost interrupts. 641*a9643ea8Slogwang */ 642*a9643ea8Slogwang SYSCTL_DECL(_dev_netmap); 643*a9643ea8Slogwang /* 644*a9643ea8Slogwang * The xl driver by default strips CRCs and we do not override it. 645*a9643ea8Slogwang */ 646*a9643ea8Slogwang 647*a9643ea8Slogwang int iflib_crcstrip = 1; 648*a9643ea8Slogwang SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_crcstrip, 649*a9643ea8Slogwang CTLFLAG_RW, &iflib_crcstrip, 1, "strip CRC on rx frames"); 650*a9643ea8Slogwang 651*a9643ea8Slogwang int iflib_rx_miss, iflib_rx_miss_bufs; 652*a9643ea8Slogwang SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_rx_miss, 653*a9643ea8Slogwang CTLFLAG_RW, &iflib_rx_miss, 0, "potentially missed rx intr"); 654*a9643ea8Slogwang SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_rx_miss_bufs, 655*a9643ea8Slogwang CTLFLAG_RW, &iflib_rx_miss_bufs, 0, "potentially missed rx intr bufs"); 656*a9643ea8Slogwang 657*a9643ea8Slogwang /* 658*a9643ea8Slogwang * Register/unregister. We are already under netmap lock. 659*a9643ea8Slogwang * Only called on the first register or the last unregister. 660*a9643ea8Slogwang */ 661*a9643ea8Slogwang static int 662*a9643ea8Slogwang iflib_netmap_register(struct netmap_adapter *na, int onoff) 663*a9643ea8Slogwang { 664*a9643ea8Slogwang struct ifnet *ifp = na->ifp; 665*a9643ea8Slogwang if_ctx_t ctx = ifp->if_softc; 666*a9643ea8Slogwang 667*a9643ea8Slogwang CTX_LOCK(ctx); 668*a9643ea8Slogwang IFDI_INTR_DISABLE(ctx); 669*a9643ea8Slogwang 670*a9643ea8Slogwang /* Tell the stack that the interface is no longer active */ 671*a9643ea8Slogwang ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 672*a9643ea8Slogwang 673*a9643ea8Slogwang if (!CTX_IS_VF(ctx)) 674*a9643ea8Slogwang IFDI_CRCSTRIP_SET(ctx, onoff); 675*a9643ea8Slogwang 676*a9643ea8Slogwang /* enable or disable flags and callbacks in na and ifp */ 677*a9643ea8Slogwang if (onoff) { 678*a9643ea8Slogwang nm_set_native_flags(na); 679*a9643ea8Slogwang } else { 680*a9643ea8Slogwang nm_clear_native_flags(na); 681*a9643ea8Slogwang } 682*a9643ea8Slogwang IFDI_INIT(ctx); 683*a9643ea8Slogwang IFDI_CRCSTRIP_SET(ctx, onoff); // XXX why twice ? 684*a9643ea8Slogwang CTX_UNLOCK(ctx); 685*a9643ea8Slogwang return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1); 686*a9643ea8Slogwang } 687*a9643ea8Slogwang 688*a9643ea8Slogwang /* 689*a9643ea8Slogwang * Reconcile kernel and user view of the transmit ring. 690*a9643ea8Slogwang * 691*a9643ea8Slogwang * All information is in the kring. 692*a9643ea8Slogwang * Userspace wants to send packets up to the one before kring->rhead, 693*a9643ea8Slogwang * kernel knows kring->nr_hwcur is the first unsent packet. 694*a9643ea8Slogwang * 695*a9643ea8Slogwang * Here we push packets out (as many as possible), and possibly 696*a9643ea8Slogwang * reclaim buffers from previously completed transmission. 697*a9643ea8Slogwang * 698*a9643ea8Slogwang * The caller (netmap) guarantees that there is only one instance 699*a9643ea8Slogwang * running at any time. Any interference with other driver 700*a9643ea8Slogwang * methods should be handled by the individual drivers. 701*a9643ea8Slogwang */ 702*a9643ea8Slogwang static int 703*a9643ea8Slogwang iflib_netmap_txsync(struct netmap_kring *kring, int flags) 704*a9643ea8Slogwang { 705*a9643ea8Slogwang struct netmap_adapter *na = kring->na; 706*a9643ea8Slogwang struct ifnet *ifp = na->ifp; 707*a9643ea8Slogwang struct netmap_ring *ring = kring->ring; 708*a9643ea8Slogwang u_int nm_i; /* index into the netmap ring */ 709*a9643ea8Slogwang u_int nic_i; /* index into the NIC ring */ 710*a9643ea8Slogwang u_int n; 711*a9643ea8Slogwang u_int const lim = kring->nkr_num_slots - 1; 712*a9643ea8Slogwang u_int const head = kring->rhead; 713*a9643ea8Slogwang struct if_pkt_info pi; 714*a9643ea8Slogwang 715*a9643ea8Slogwang /* 716*a9643ea8Slogwang * interrupts on every tx packet are expensive so request 717*a9643ea8Slogwang * them every half ring, or where NS_REPORT is set 718*a9643ea8Slogwang */ 719*a9643ea8Slogwang u_int report_frequency = kring->nkr_num_slots >> 1; 720*a9643ea8Slogwang /* device-specific */ 721*a9643ea8Slogwang if_ctx_t ctx = ifp->if_softc; 722*a9643ea8Slogwang iflib_txq_t txq = &ctx->ifc_txqs[kring->ring_id]; 723*a9643ea8Slogwang 724*a9643ea8Slogwang pi.ipi_segs = txq->ift_segs; 725*a9643ea8Slogwang pi.ipi_qsidx = kring->ring_id; 726*a9643ea8Slogwang pi.ipi_ndescs = 0; 727*a9643ea8Slogwang 728*a9643ea8Slogwang bus_dmamap_sync(txq->ift_desc_tag, txq->ift_ifdi->idi_map, 729*a9643ea8Slogwang BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 730*a9643ea8Slogwang 731*a9643ea8Slogwang 732*a9643ea8Slogwang /* 733*a9643ea8Slogwang * First part: process new packets to send. 734*a9643ea8Slogwang * nm_i is the current index in the netmap ring, 735*a9643ea8Slogwang * nic_i is the corresponding index in the NIC ring. 736*a9643ea8Slogwang * 737*a9643ea8Slogwang * If we have packets to send (nm_i != head) 738*a9643ea8Slogwang * iterate over the netmap ring, fetch length and update 739*a9643ea8Slogwang * the corresponding slot in the NIC ring. Some drivers also 740*a9643ea8Slogwang * need to update the buffer's physical address in the NIC slot 741*a9643ea8Slogwang * even NS_BUF_CHANGED is not set (PNMB computes the addresses). 742*a9643ea8Slogwang * 743*a9643ea8Slogwang * The netmap_reload_map() calls is especially expensive, 744*a9643ea8Slogwang * even when (as in this case) the tag is 0, so do only 745*a9643ea8Slogwang * when the buffer has actually changed. 746*a9643ea8Slogwang * 747*a9643ea8Slogwang * If possible do not set the report/intr bit on all slots, 748*a9643ea8Slogwang * but only a few times per ring or when NS_REPORT is set. 749*a9643ea8Slogwang * 750*a9643ea8Slogwang * Finally, on 10G and faster drivers, it might be useful 751*a9643ea8Slogwang * to prefetch the next slot and txr entry. 752*a9643ea8Slogwang */ 753*a9643ea8Slogwang 754*a9643ea8Slogwang nm_i = kring->nr_hwcur; 755*a9643ea8Slogwang if (nm_i != head) { /* we have new packets to send */ 756*a9643ea8Slogwang nic_i = netmap_idx_k2n(kring, nm_i); 757*a9643ea8Slogwang 758*a9643ea8Slogwang __builtin_prefetch(&ring->slot[nm_i]); 759*a9643ea8Slogwang __builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i]); 760*a9643ea8Slogwang __builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i]); 761*a9643ea8Slogwang 762*a9643ea8Slogwang for (n = 0; nm_i != head; n++) { 763*a9643ea8Slogwang struct netmap_slot *slot = &ring->slot[nm_i]; 764*a9643ea8Slogwang u_int len = slot->len; 765*a9643ea8Slogwang uint64_t paddr; 766*a9643ea8Slogwang void *addr = PNMB(na, slot, &paddr); 767*a9643ea8Slogwang int flags = (slot->flags & NS_REPORT || 768*a9643ea8Slogwang nic_i == 0 || nic_i == report_frequency) ? 769*a9643ea8Slogwang IPI_TX_INTR : 0; 770*a9643ea8Slogwang 771*a9643ea8Slogwang /* device-specific */ 772*a9643ea8Slogwang pi.ipi_pidx = nic_i; 773*a9643ea8Slogwang pi.ipi_flags = flags; 774*a9643ea8Slogwang 775*a9643ea8Slogwang /* Fill the slot in the NIC ring. */ 776*a9643ea8Slogwang ctx->isc_txd_encap(ctx->ifc_softc, &pi); 777*a9643ea8Slogwang 778*a9643ea8Slogwang /* prefetch for next round */ 779*a9643ea8Slogwang __builtin_prefetch(&ring->slot[nm_i + 1]); 780*a9643ea8Slogwang __builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i + 1]); 781*a9643ea8Slogwang __builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i + 1]); 782*a9643ea8Slogwang 783*a9643ea8Slogwang NM_CHECK_ADDR_LEN(na, addr, len); 784*a9643ea8Slogwang 785*a9643ea8Slogwang if (slot->flags & NS_BUF_CHANGED) { 786*a9643ea8Slogwang /* buffer has changed, reload map */ 787*a9643ea8Slogwang netmap_reload_map(na, txq->ift_desc_tag, txq->ift_sds.ifsd_map[nic_i], addr); 788*a9643ea8Slogwang } 789*a9643ea8Slogwang slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED); 790*a9643ea8Slogwang 791*a9643ea8Slogwang /* make sure changes to the buffer are synced */ 792*a9643ea8Slogwang bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_sds.ifsd_map[nic_i], 793*a9643ea8Slogwang BUS_DMASYNC_PREWRITE); 794*a9643ea8Slogwang 795*a9643ea8Slogwang nm_i = nm_next(nm_i, lim); 796*a9643ea8Slogwang nic_i = nm_next(nic_i, lim); 797*a9643ea8Slogwang } 798*a9643ea8Slogwang kring->nr_hwcur = head; 799*a9643ea8Slogwang 800*a9643ea8Slogwang /* synchronize the NIC ring */ 801*a9643ea8Slogwang bus_dmamap_sync(txq->ift_desc_tag, txq->ift_ifdi->idi_map, 802*a9643ea8Slogwang BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 803*a9643ea8Slogwang 804*a9643ea8Slogwang /* (re)start the tx unit up to slot nic_i (excluded) */ 805*a9643ea8Slogwang ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, nic_i); 806*a9643ea8Slogwang } 807*a9643ea8Slogwang 808*a9643ea8Slogwang /* 809*a9643ea8Slogwang * Second part: reclaim buffers for completed transmissions. 810*a9643ea8Slogwang */ 811*a9643ea8Slogwang if (iflib_tx_credits_update(ctx, txq)) { 812*a9643ea8Slogwang /* some tx completed, increment avail */ 813*a9643ea8Slogwang nic_i = txq->ift_cidx_processed; 814*a9643ea8Slogwang kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim); 815*a9643ea8Slogwang } 816*a9643ea8Slogwang return (0); 817*a9643ea8Slogwang } 818*a9643ea8Slogwang 819*a9643ea8Slogwang /* 820*a9643ea8Slogwang * Reconcile kernel and user view of the receive ring. 821*a9643ea8Slogwang * Same as for the txsync, this routine must be efficient. 822*a9643ea8Slogwang * The caller guarantees a single invocations, but races against 823*a9643ea8Slogwang * the rest of the driver should be handled here. 824*a9643ea8Slogwang * 825*a9643ea8Slogwang * On call, kring->rhead is the first packet that userspace wants 826*a9643ea8Slogwang * to keep, and kring->rcur is the wakeup point. 827*a9643ea8Slogwang * The kernel has previously reported packets up to kring->rtail. 828*a9643ea8Slogwang * 829*a9643ea8Slogwang * If (flags & NAF_FORCE_READ) also check for incoming packets irrespective 830*a9643ea8Slogwang * of whether or not we received an interrupt. 831*a9643ea8Slogwang */ 832*a9643ea8Slogwang static int 833*a9643ea8Slogwang iflib_netmap_rxsync(struct netmap_kring *kring, int flags) 834*a9643ea8Slogwang { 835*a9643ea8Slogwang struct netmap_adapter *na = kring->na; 836*a9643ea8Slogwang struct ifnet *ifp = na->ifp; 837*a9643ea8Slogwang struct netmap_ring *ring = kring->ring; 838*a9643ea8Slogwang u_int nm_i; /* index into the netmap ring */ 839*a9643ea8Slogwang u_int nic_i; /* index into the NIC ring */ 840*a9643ea8Slogwang u_int i, n; 841*a9643ea8Slogwang u_int const lim = kring->nkr_num_slots - 1; 842*a9643ea8Slogwang u_int const head = kring->rhead; 843*a9643ea8Slogwang int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; 844*a9643ea8Slogwang struct if_rxd_info ri; 845*a9643ea8Slogwang /* device-specific */ 846*a9643ea8Slogwang if_ctx_t ctx = ifp->if_softc; 847*a9643ea8Slogwang iflib_rxq_t rxq = &ctx->ifc_rxqs[kring->ring_id]; 848*a9643ea8Slogwang iflib_fl_t fl = rxq->ifr_fl; 849*a9643ea8Slogwang if (head > lim) 850*a9643ea8Slogwang return netmap_ring_reinit(kring); 851*a9643ea8Slogwang 852*a9643ea8Slogwang bzero(&ri, sizeof(ri)); 853*a9643ea8Slogwang ri.iri_qsidx = kring->ring_id; 854*a9643ea8Slogwang ri.iri_ifp = ctx->ifc_ifp; 855*a9643ea8Slogwang /* XXX check sync modes */ 856*a9643ea8Slogwang for (i = 0, fl = rxq->ifr_fl; i < rxq->ifr_nfl; i++, fl++) 857*a9643ea8Slogwang bus_dmamap_sync(rxq->ifr_fl[i].ifl_desc_tag, fl->ifl_ifdi->idi_map, 858*a9643ea8Slogwang BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 859*a9643ea8Slogwang 860*a9643ea8Slogwang /* 861*a9643ea8Slogwang * First part: import newly received packets. 862*a9643ea8Slogwang * 863*a9643ea8Slogwang * nm_i is the index of the next free slot in the netmap ring, 864*a9643ea8Slogwang * nic_i is the index of the next received packet in the NIC ring, 865*a9643ea8Slogwang * and they may differ in case if_init() has been called while 866*a9643ea8Slogwang * in netmap mode. For the receive ring we have 867*a9643ea8Slogwang * 868*a9643ea8Slogwang * nic_i = rxr->next_check; 869*a9643ea8Slogwang * nm_i = kring->nr_hwtail (previous) 870*a9643ea8Slogwang * and 871*a9643ea8Slogwang * nm_i == (nic_i + kring->nkr_hwofs) % ring_size 872*a9643ea8Slogwang * 873*a9643ea8Slogwang * rxr->next_check is set to 0 on a ring reinit 874*a9643ea8Slogwang */ 875*a9643ea8Slogwang if (netmap_no_pendintr || force_update) { 876*a9643ea8Slogwang int crclen = iflib_crcstrip ? 0 : 4; 877*a9643ea8Slogwang int error, avail; 878*a9643ea8Slogwang uint16_t slot_flags = kring->nkr_slot_flags; 879*a9643ea8Slogwang 880*a9643ea8Slogwang for (fl = rxq->ifr_fl, i = 0; i < rxq->ifr_nfl; i++, fl++) { 881*a9643ea8Slogwang nic_i = fl->ifl_cidx; 882*a9643ea8Slogwang nm_i = netmap_idx_n2k(kring, nic_i); 883*a9643ea8Slogwang avail = ctx->isc_rxd_available(ctx->ifc_softc, kring->ring_id, nic_i, INT_MAX); 884*a9643ea8Slogwang for (n = 0; avail > 0; n++, avail--) { 885*a9643ea8Slogwang error = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri); 886*a9643ea8Slogwang if (error) 887*a9643ea8Slogwang ring->slot[nm_i].len = 0; 888*a9643ea8Slogwang else 889*a9643ea8Slogwang ring->slot[nm_i].len = ri.iri_len - crclen; 890*a9643ea8Slogwang ring->slot[nm_i].flags = slot_flags; 891*a9643ea8Slogwang bus_dmamap_sync(fl->ifl_ifdi->idi_tag, 892*a9643ea8Slogwang fl->ifl_sds[nic_i].ifsd_map, BUS_DMASYNC_POSTREAD); 893*a9643ea8Slogwang nm_i = nm_next(nm_i, lim); 894*a9643ea8Slogwang nic_i = nm_next(nic_i, lim); 895*a9643ea8Slogwang } 896*a9643ea8Slogwang if (n) { /* update the state variables */ 897*a9643ea8Slogwang if (netmap_no_pendintr && !force_update) { 898*a9643ea8Slogwang /* diagnostics */ 899*a9643ea8Slogwang iflib_rx_miss ++; 900*a9643ea8Slogwang iflib_rx_miss_bufs += n; 901*a9643ea8Slogwang } 902*a9643ea8Slogwang fl->ifl_cidx = nic_i; 903*a9643ea8Slogwang kring->nr_hwtail = nm_i; 904*a9643ea8Slogwang } 905*a9643ea8Slogwang kring->nr_kflags &= ~NKR_PENDINTR; 906*a9643ea8Slogwang } 907*a9643ea8Slogwang } 908*a9643ea8Slogwang /* 909*a9643ea8Slogwang * Second part: skip past packets that userspace has released. 910*a9643ea8Slogwang * (kring->nr_hwcur to head excluded), 911*a9643ea8Slogwang * and make the buffers available for reception. 912*a9643ea8Slogwang * As usual nm_i is the index in the netmap ring, 913*a9643ea8Slogwang * nic_i is the index in the NIC ring, and 914*a9643ea8Slogwang * nm_i == (nic_i + kring->nkr_hwofs) % ring_size 915*a9643ea8Slogwang */ 916*a9643ea8Slogwang /* XXX not sure how this will work with multiple free lists */ 917*a9643ea8Slogwang nm_i = kring->nr_hwcur; 918*a9643ea8Slogwang if (nm_i != head) { 919*a9643ea8Slogwang nic_i = netmap_idx_k2n(kring, nm_i); 920*a9643ea8Slogwang for (n = 0; nm_i != head; n++) { 921*a9643ea8Slogwang struct netmap_slot *slot = &ring->slot[nm_i]; 922*a9643ea8Slogwang uint64_t paddr; 923*a9643ea8Slogwang caddr_t vaddr; 924*a9643ea8Slogwang void *addr = PNMB(na, slot, &paddr); 925*a9643ea8Slogwang 926*a9643ea8Slogwang if (addr == NETMAP_BUF_BASE(na)) /* bad buf */ 927*a9643ea8Slogwang goto ring_reset; 928*a9643ea8Slogwang 929*a9643ea8Slogwang vaddr = addr; 930*a9643ea8Slogwang if (slot->flags & NS_BUF_CHANGED) { 931*a9643ea8Slogwang /* buffer has changed, reload map */ 932*a9643ea8Slogwang netmap_reload_map(na, fl->ifl_ifdi->idi_tag, fl->ifl_sds[nic_i].ifsd_map, addr); 933*a9643ea8Slogwang slot->flags &= ~NS_BUF_CHANGED; 934*a9643ea8Slogwang } 935*a9643ea8Slogwang /* 936*a9643ea8Slogwang * XXX we should be batching this operation - TODO 937*a9643ea8Slogwang */ 938*a9643ea8Slogwang ctx->isc_rxd_refill(ctx->ifc_softc, rxq->ifr_id, fl->ifl_id, nic_i, &paddr, &vaddr, 1, fl->ifl_buf_size); 939*a9643ea8Slogwang bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_sds[nic_i].ifsd_map, 940*a9643ea8Slogwang BUS_DMASYNC_PREREAD); 941*a9643ea8Slogwang nm_i = nm_next(nm_i, lim); 942*a9643ea8Slogwang nic_i = nm_next(nic_i, lim); 943*a9643ea8Slogwang } 944*a9643ea8Slogwang kring->nr_hwcur = head; 945*a9643ea8Slogwang 946*a9643ea8Slogwang bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map, 947*a9643ea8Slogwang BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 948*a9643ea8Slogwang /* 949*a9643ea8Slogwang * IMPORTANT: we must leave one free slot in the ring, 950*a9643ea8Slogwang * so move nic_i back by one unit 951*a9643ea8Slogwang */ 952*a9643ea8Slogwang nic_i = nm_prev(nic_i, lim); 953*a9643ea8Slogwang ctx->isc_rxd_flush(ctx->ifc_softc, rxq->ifr_id, fl->ifl_id, nic_i); 954*a9643ea8Slogwang } 955*a9643ea8Slogwang 956*a9643ea8Slogwang return 0; 957*a9643ea8Slogwang 958*a9643ea8Slogwang ring_reset: 959*a9643ea8Slogwang return netmap_ring_reinit(kring); 960*a9643ea8Slogwang } 961*a9643ea8Slogwang 962*a9643ea8Slogwang static int 963*a9643ea8Slogwang iflib_netmap_attach(if_ctx_t ctx) 964*a9643ea8Slogwang { 965*a9643ea8Slogwang struct netmap_adapter na; 966*a9643ea8Slogwang if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; 967*a9643ea8Slogwang 968*a9643ea8Slogwang bzero(&na, sizeof(na)); 969*a9643ea8Slogwang 970*a9643ea8Slogwang na.ifp = ctx->ifc_ifp; 971*a9643ea8Slogwang na.na_flags = NAF_BDG_MAYSLEEP; 972*a9643ea8Slogwang MPASS(ctx->ifc_softc_ctx.isc_ntxqsets); 973*a9643ea8Slogwang MPASS(ctx->ifc_softc_ctx.isc_nrxqsets); 974*a9643ea8Slogwang 975*a9643ea8Slogwang na.num_tx_desc = scctx->isc_ntxd[0]; 976*a9643ea8Slogwang na.num_rx_desc = scctx->isc_nrxd[0]; 977*a9643ea8Slogwang na.nm_txsync = iflib_netmap_txsync; 978*a9643ea8Slogwang na.nm_rxsync = iflib_netmap_rxsync; 979*a9643ea8Slogwang na.nm_register = iflib_netmap_register; 980*a9643ea8Slogwang na.num_tx_rings = ctx->ifc_softc_ctx.isc_ntxqsets; 981*a9643ea8Slogwang na.num_rx_rings = ctx->ifc_softc_ctx.isc_nrxqsets; 982*a9643ea8Slogwang return (netmap_attach(&na)); 983*a9643ea8Slogwang } 984*a9643ea8Slogwang 985*a9643ea8Slogwang static void 986*a9643ea8Slogwang iflib_netmap_txq_init(if_ctx_t ctx, iflib_txq_t txq) 987*a9643ea8Slogwang { 988*a9643ea8Slogwang struct netmap_adapter *na = NA(ctx->ifc_ifp); 989*a9643ea8Slogwang struct netmap_slot *slot; 990*a9643ea8Slogwang 991*a9643ea8Slogwang slot = netmap_reset(na, NR_TX, txq->ift_id, 0); 992*a9643ea8Slogwang if (slot == 0) 993*a9643ea8Slogwang return; 994*a9643ea8Slogwang 995*a9643ea8Slogwang for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxd[0]; i++) { 996*a9643ea8Slogwang 997*a9643ea8Slogwang /* 998*a9643ea8Slogwang * In netmap mode, set the map for the packet buffer. 999*a9643ea8Slogwang * NOTE: Some drivers (not this one) also need to set 1000*a9643ea8Slogwang * the physical buffer address in the NIC ring. 1001*a9643ea8Slogwang * netmap_idx_n2k() maps a nic index, i, into the corresponding 1002*a9643ea8Slogwang * netmap slot index, si 1003*a9643ea8Slogwang */ 1004*a9643ea8Slogwang int si = netmap_idx_n2k(&na->tx_rings[txq->ift_id], i); 1005*a9643ea8Slogwang netmap_load_map(na, txq->ift_desc_tag, txq->ift_sds.ifsd_map[i], NMB(na, slot + si)); 1006*a9643ea8Slogwang } 1007*a9643ea8Slogwang } 1008*a9643ea8Slogwang static void 1009*a9643ea8Slogwang iflib_netmap_rxq_init(if_ctx_t ctx, iflib_rxq_t rxq) 1010*a9643ea8Slogwang { 1011*a9643ea8Slogwang struct netmap_adapter *na = NA(ctx->ifc_ifp); 1012*a9643ea8Slogwang struct netmap_slot *slot; 1013*a9643ea8Slogwang iflib_rxsd_t sd; 1014*a9643ea8Slogwang int nrxd; 1015*a9643ea8Slogwang 1016*a9643ea8Slogwang slot = netmap_reset(na, NR_RX, rxq->ifr_id, 0); 1017*a9643ea8Slogwang if (slot == 0) 1018*a9643ea8Slogwang return; 1019*a9643ea8Slogwang sd = rxq->ifr_fl[0].ifl_sds; 1020*a9643ea8Slogwang nrxd = ctx->ifc_softc_ctx.isc_nrxd[0]; 1021*a9643ea8Slogwang for (int i = 0; i < nrxd; i++, sd++) { 1022*a9643ea8Slogwang int sj = netmap_idx_n2k(&na->rx_rings[rxq->ifr_id], i); 1023*a9643ea8Slogwang uint64_t paddr; 1024*a9643ea8Slogwang void *addr; 1025*a9643ea8Slogwang caddr_t vaddr; 1026*a9643ea8Slogwang 1027*a9643ea8Slogwang vaddr = addr = PNMB(na, slot + sj, &paddr); 1028*a9643ea8Slogwang netmap_load_map(na, rxq->ifr_fl[0].ifl_ifdi->idi_tag, sd->ifsd_map, addr); 1029*a9643ea8Slogwang /* Update descriptor and the cached value */ 1030*a9643ea8Slogwang ctx->isc_rxd_refill(ctx->ifc_softc, rxq->ifr_id, 0 /* fl_id */, i, &paddr, &vaddr, 1, rxq->ifr_fl[0].ifl_buf_size); 1031*a9643ea8Slogwang } 1032*a9643ea8Slogwang /* preserve queue */ 1033*a9643ea8Slogwang if (ctx->ifc_ifp->if_capenable & IFCAP_NETMAP) { 1034*a9643ea8Slogwang struct netmap_kring *kring = &na->rx_rings[rxq->ifr_id]; 1035*a9643ea8Slogwang int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); 1036*a9643ea8Slogwang ctx->isc_rxd_flush(ctx->ifc_softc, rxq->ifr_id, 0 /* fl_id */, t); 1037*a9643ea8Slogwang } else 1038*a9643ea8Slogwang ctx->isc_rxd_flush(ctx->ifc_softc, rxq->ifr_id, 0 /* fl_id */, nrxd-1); 1039*a9643ea8Slogwang } 1040*a9643ea8Slogwang 1041*a9643ea8Slogwang #define iflib_netmap_detach(ifp) netmap_detach(ifp) 1042*a9643ea8Slogwang 1043*a9643ea8Slogwang #else 1044*a9643ea8Slogwang #define iflib_netmap_txq_init(ctx, txq) 1045*a9643ea8Slogwang #define iflib_netmap_rxq_init(ctx, rxq) 1046*a9643ea8Slogwang #define iflib_netmap_detach(ifp) 1047*a9643ea8Slogwang 1048*a9643ea8Slogwang #define iflib_netmap_attach(ctx) (0) 1049*a9643ea8Slogwang #define netmap_rx_irq(ifp, qid, budget) (0) 1050*a9643ea8Slogwang 1051*a9643ea8Slogwang #endif 1052*a9643ea8Slogwang 1053*a9643ea8Slogwang #if defined(__i386__) || defined(__amd64__) 1054*a9643ea8Slogwang static __inline void 1055*a9643ea8Slogwang prefetch(void *x) 1056*a9643ea8Slogwang { 1057*a9643ea8Slogwang __asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x)); 1058*a9643ea8Slogwang } 1059*a9643ea8Slogwang #else 1060*a9643ea8Slogwang #define prefetch(x) 1061*a9643ea8Slogwang #endif 1062*a9643ea8Slogwang 1063*a9643ea8Slogwang static void 1064*a9643ea8Slogwang _iflib_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 1065*a9643ea8Slogwang { 1066*a9643ea8Slogwang if (err) 1067*a9643ea8Slogwang return; 1068*a9643ea8Slogwang *(bus_addr_t *) arg = segs[0].ds_addr; 1069*a9643ea8Slogwang } 1070*a9643ea8Slogwang 1071*a9643ea8Slogwang int 1072*a9643ea8Slogwang iflib_dma_alloc(if_ctx_t ctx, int size, iflib_dma_info_t dma, int mapflags) 1073*a9643ea8Slogwang { 1074*a9643ea8Slogwang int err; 1075*a9643ea8Slogwang if_shared_ctx_t sctx = ctx->ifc_sctx; 1076*a9643ea8Slogwang device_t dev = ctx->ifc_dev; 1077*a9643ea8Slogwang 1078*a9643ea8Slogwang KASSERT(sctx->isc_q_align != 0, ("alignment value not initialized")); 1079*a9643ea8Slogwang 1080*a9643ea8Slogwang err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 1081*a9643ea8Slogwang sctx->isc_q_align, 0, /* alignment, bounds */ 1082*a9643ea8Slogwang BUS_SPACE_MAXADDR, /* lowaddr */ 1083*a9643ea8Slogwang BUS_SPACE_MAXADDR, /* highaddr */ 1084*a9643ea8Slogwang NULL, NULL, /* filter, filterarg */ 1085*a9643ea8Slogwang size, /* maxsize */ 1086*a9643ea8Slogwang 1, /* nsegments */ 1087*a9643ea8Slogwang size, /* maxsegsize */ 1088*a9643ea8Slogwang BUS_DMA_ALLOCNOW, /* flags */ 1089*a9643ea8Slogwang NULL, /* lockfunc */ 1090*a9643ea8Slogwang NULL, /* lockarg */ 1091*a9643ea8Slogwang &dma->idi_tag); 1092*a9643ea8Slogwang if (err) { 1093*a9643ea8Slogwang device_printf(dev, 1094*a9643ea8Slogwang "%s: bus_dma_tag_create failed: %d\n", 1095*a9643ea8Slogwang __func__, err); 1096*a9643ea8Slogwang goto fail_0; 1097*a9643ea8Slogwang } 1098*a9643ea8Slogwang 1099*a9643ea8Slogwang err = bus_dmamem_alloc(dma->idi_tag, (void**) &dma->idi_vaddr, 1100*a9643ea8Slogwang BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_ZERO, &dma->idi_map); 1101*a9643ea8Slogwang if (err) { 1102*a9643ea8Slogwang device_printf(dev, 1103*a9643ea8Slogwang "%s: bus_dmamem_alloc(%ju) failed: %d\n", 1104*a9643ea8Slogwang __func__, (uintmax_t)size, err); 1105*a9643ea8Slogwang goto fail_1; 1106*a9643ea8Slogwang } 1107*a9643ea8Slogwang 1108*a9643ea8Slogwang dma->idi_paddr = IF_BAD_DMA; 1109*a9643ea8Slogwang err = bus_dmamap_load(dma->idi_tag, dma->idi_map, dma->idi_vaddr, 1110*a9643ea8Slogwang size, _iflib_dmamap_cb, &dma->idi_paddr, mapflags | BUS_DMA_NOWAIT); 1111*a9643ea8Slogwang if (err || dma->idi_paddr == IF_BAD_DMA) { 1112*a9643ea8Slogwang device_printf(dev, 1113*a9643ea8Slogwang "%s: bus_dmamap_load failed: %d\n", 1114*a9643ea8Slogwang __func__, err); 1115*a9643ea8Slogwang goto fail_2; 1116*a9643ea8Slogwang } 1117*a9643ea8Slogwang 1118*a9643ea8Slogwang dma->idi_size = size; 1119*a9643ea8Slogwang return (0); 1120*a9643ea8Slogwang 1121*a9643ea8Slogwang fail_2: 1122*a9643ea8Slogwang bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map); 1123*a9643ea8Slogwang fail_1: 1124*a9643ea8Slogwang bus_dma_tag_destroy(dma->idi_tag); 1125*a9643ea8Slogwang fail_0: 1126*a9643ea8Slogwang dma->idi_tag = NULL; 1127*a9643ea8Slogwang 1128*a9643ea8Slogwang return (err); 1129*a9643ea8Slogwang } 1130*a9643ea8Slogwang 1131*a9643ea8Slogwang int 1132*a9643ea8Slogwang iflib_dma_alloc_multi(if_ctx_t ctx, int *sizes, iflib_dma_info_t *dmalist, int mapflags, int count) 1133*a9643ea8Slogwang { 1134*a9643ea8Slogwang int i, err; 1135*a9643ea8Slogwang iflib_dma_info_t *dmaiter; 1136*a9643ea8Slogwang 1137*a9643ea8Slogwang dmaiter = dmalist; 1138*a9643ea8Slogwang for (i = 0; i < count; i++, dmaiter++) { 1139*a9643ea8Slogwang if ((err = iflib_dma_alloc(ctx, sizes[i], *dmaiter, mapflags)) != 0) 1140*a9643ea8Slogwang break; 1141*a9643ea8Slogwang } 1142*a9643ea8Slogwang if (err) 1143*a9643ea8Slogwang iflib_dma_free_multi(dmalist, i); 1144*a9643ea8Slogwang return (err); 1145*a9643ea8Slogwang } 1146*a9643ea8Slogwang 1147*a9643ea8Slogwang void 1148*a9643ea8Slogwang iflib_dma_free(iflib_dma_info_t dma) 1149*a9643ea8Slogwang { 1150*a9643ea8Slogwang if (dma->idi_tag == NULL) 1151*a9643ea8Slogwang return; 1152*a9643ea8Slogwang if (dma->idi_paddr != IF_BAD_DMA) { 1153*a9643ea8Slogwang bus_dmamap_sync(dma->idi_tag, dma->idi_map, 1154*a9643ea8Slogwang BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1155*a9643ea8Slogwang bus_dmamap_unload(dma->idi_tag, dma->idi_map); 1156*a9643ea8Slogwang dma->idi_paddr = IF_BAD_DMA; 1157*a9643ea8Slogwang } 1158*a9643ea8Slogwang if (dma->idi_vaddr != NULL) { 1159*a9643ea8Slogwang bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map); 1160*a9643ea8Slogwang dma->idi_vaddr = NULL; 1161*a9643ea8Slogwang } 1162*a9643ea8Slogwang bus_dma_tag_destroy(dma->idi_tag); 1163*a9643ea8Slogwang dma->idi_tag = NULL; 1164*a9643ea8Slogwang } 1165*a9643ea8Slogwang 1166*a9643ea8Slogwang void 1167*a9643ea8Slogwang iflib_dma_free_multi(iflib_dma_info_t *dmalist, int count) 1168*a9643ea8Slogwang { 1169*a9643ea8Slogwang int i; 1170*a9643ea8Slogwang iflib_dma_info_t *dmaiter = dmalist; 1171*a9643ea8Slogwang 1172*a9643ea8Slogwang for (i = 0; i < count; i++, dmaiter++) 1173*a9643ea8Slogwang iflib_dma_free(*dmaiter); 1174*a9643ea8Slogwang } 1175*a9643ea8Slogwang 1176*a9643ea8Slogwang static int 1177*a9643ea8Slogwang iflib_fast_intr(void *arg) 1178*a9643ea8Slogwang { 1179*a9643ea8Slogwang iflib_filter_info_t info = arg; 1180*a9643ea8Slogwang struct grouptask *gtask = info->ifi_task; 1181*a9643ea8Slogwang 1182*a9643ea8Slogwang DBG_COUNTER_INC(fast_intrs); 1183*a9643ea8Slogwang if (info->ifi_filter != NULL && info->ifi_filter(info->ifi_filter_arg) == FILTER_HANDLED) 1184*a9643ea8Slogwang return (FILTER_HANDLED); 1185*a9643ea8Slogwang 1186*a9643ea8Slogwang GROUPTASK_ENQUEUE(gtask); 1187*a9643ea8Slogwang return (FILTER_HANDLED); 1188*a9643ea8Slogwang } 1189*a9643ea8Slogwang 1190*a9643ea8Slogwang static int 1191*a9643ea8Slogwang _iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid, 1192*a9643ea8Slogwang driver_filter_t filter, driver_intr_t handler, void *arg, 1193*a9643ea8Slogwang char *name) 1194*a9643ea8Slogwang { 1195*a9643ea8Slogwang int rc; 1196*a9643ea8Slogwang struct resource *res; 1197*a9643ea8Slogwang void *tag; 1198*a9643ea8Slogwang device_t dev = ctx->ifc_dev; 1199*a9643ea8Slogwang 1200*a9643ea8Slogwang MPASS(rid < 512); 1201*a9643ea8Slogwang irq->ii_rid = rid; 1202*a9643ea8Slogwang res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irq->ii_rid, 1203*a9643ea8Slogwang RF_SHAREABLE | RF_ACTIVE); 1204*a9643ea8Slogwang if (res == NULL) { 1205*a9643ea8Slogwang device_printf(dev, 1206*a9643ea8Slogwang "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 1207*a9643ea8Slogwang return (ENOMEM); 1208*a9643ea8Slogwang } 1209*a9643ea8Slogwang irq->ii_res = res; 1210*a9643ea8Slogwang KASSERT(filter == NULL || handler == NULL, ("filter and handler can't both be non-NULL")); 1211*a9643ea8Slogwang rc = bus_setup_intr(dev, res, INTR_MPSAFE | INTR_TYPE_NET, 1212*a9643ea8Slogwang filter, handler, arg, &tag); 1213*a9643ea8Slogwang if (rc != 0) { 1214*a9643ea8Slogwang device_printf(dev, 1215*a9643ea8Slogwang "failed to setup interrupt for rid %d, name %s: %d\n", 1216*a9643ea8Slogwang rid, name ? name : "unknown", rc); 1217*a9643ea8Slogwang return (rc); 1218*a9643ea8Slogwang } else if (name) 1219*a9643ea8Slogwang bus_describe_intr(dev, res, tag, name); 1220*a9643ea8Slogwang 1221*a9643ea8Slogwang irq->ii_tag = tag; 1222*a9643ea8Slogwang return (0); 1223*a9643ea8Slogwang } 1224*a9643ea8Slogwang 1225*a9643ea8Slogwang 1226*a9643ea8Slogwang /********************************************************************* 1227*a9643ea8Slogwang * 1228*a9643ea8Slogwang * Allocate memory for tx_buffer structures. The tx_buffer stores all 1229*a9643ea8Slogwang * the information needed to transmit a packet on the wire. This is 1230*a9643ea8Slogwang * called only once at attach, setup is done every reset. 1231*a9643ea8Slogwang * 1232*a9643ea8Slogwang **********************************************************************/ 1233*a9643ea8Slogwang 1234*a9643ea8Slogwang static int 1235*a9643ea8Slogwang iflib_txsd_alloc(iflib_txq_t txq) 1236*a9643ea8Slogwang { 1237*a9643ea8Slogwang if_ctx_t ctx = txq->ift_ctx; 1238*a9643ea8Slogwang if_shared_ctx_t sctx = ctx->ifc_sctx; 1239*a9643ea8Slogwang if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; 1240*a9643ea8Slogwang device_t dev = ctx->ifc_dev; 1241*a9643ea8Slogwang int err, nsegments, ntsosegments; 1242*a9643ea8Slogwang 1243*a9643ea8Slogwang nsegments = scctx->isc_tx_nsegments; 1244*a9643ea8Slogwang ntsosegments = scctx->isc_tx_tso_segments_max; 1245*a9643ea8Slogwang MPASS(scctx->isc_ntxd[0] > 0); 1246*a9643ea8Slogwang MPASS(scctx->isc_ntxd[txq->ift_br_offset] > 0); 1247*a9643ea8Slogwang MPASS(nsegments > 0); 1248*a9643ea8Slogwang MPASS(ntsosegments > 0); 1249*a9643ea8Slogwang /* 1250*a9643ea8Slogwang * Setup DMA descriptor areas. 1251*a9643ea8Slogwang */ 1252*a9643ea8Slogwang if ((err = bus_dma_tag_create(bus_get_dma_tag(dev), 1253*a9643ea8Slogwang 1, 0, /* alignment, bounds */ 1254*a9643ea8Slogwang BUS_SPACE_MAXADDR, /* lowaddr */ 1255*a9643ea8Slogwang BUS_SPACE_MAXADDR, /* highaddr */ 1256*a9643ea8Slogwang NULL, NULL, /* filter, filterarg */ 1257*a9643ea8Slogwang sctx->isc_tx_maxsize, /* maxsize */ 1258*a9643ea8Slogwang nsegments, /* nsegments */ 1259*a9643ea8Slogwang sctx->isc_tx_maxsegsize, /* maxsegsize */ 1260*a9643ea8Slogwang 0, /* flags */ 1261*a9643ea8Slogwang NULL, /* lockfunc */ 1262*a9643ea8Slogwang NULL, /* lockfuncarg */ 1263*a9643ea8Slogwang &txq->ift_desc_tag))) { 1264*a9643ea8Slogwang device_printf(dev,"Unable to allocate TX DMA tag: %d\n", err); 1265*a9643ea8Slogwang device_printf(dev,"maxsize: %zd nsegments: %d maxsegsize: %zd\n", 1266*a9643ea8Slogwang sctx->isc_tx_maxsize, nsegments, sctx->isc_tx_maxsegsize); 1267*a9643ea8Slogwang goto fail; 1268*a9643ea8Slogwang } 1269*a9643ea8Slogwang #ifdef IFLIB_DIAGNOSTICS 1270*a9643ea8Slogwang device_printf(dev,"maxsize: %zd nsegments: %d maxsegsize: %zd\n", 1271*a9643ea8Slogwang sctx->isc_tx_maxsize, nsegments, sctx->isc_tx_maxsegsize); 1272*a9643ea8Slogwang 1273*a9643ea8Slogwang #endif 1274*a9643ea8Slogwang if ((err = bus_dma_tag_create(bus_get_dma_tag(dev), 1275*a9643ea8Slogwang 1, 0, /* alignment, bounds */ 1276*a9643ea8Slogwang BUS_SPACE_MAXADDR, /* lowaddr */ 1277*a9643ea8Slogwang BUS_SPACE_MAXADDR, /* highaddr */ 1278*a9643ea8Slogwang NULL, NULL, /* filter, filterarg */ 1279*a9643ea8Slogwang scctx->isc_tx_tso_size_max, /* maxsize */ 1280*a9643ea8Slogwang ntsosegments, /* nsegments */ 1281*a9643ea8Slogwang scctx->isc_tx_tso_segsize_max, /* maxsegsize */ 1282*a9643ea8Slogwang 0, /* flags */ 1283*a9643ea8Slogwang NULL, /* lockfunc */ 1284*a9643ea8Slogwang NULL, /* lockfuncarg */ 1285*a9643ea8Slogwang &txq->ift_tso_desc_tag))) { 1286*a9643ea8Slogwang device_printf(dev,"Unable to allocate TX TSO DMA tag: %d\n", err); 1287*a9643ea8Slogwang 1288*a9643ea8Slogwang goto fail; 1289*a9643ea8Slogwang } 1290*a9643ea8Slogwang #ifdef IFLIB_DIAGNOSTICS 1291*a9643ea8Slogwang device_printf(dev,"TSO maxsize: %d ntsosegments: %d maxsegsize: %d\n", 1292*a9643ea8Slogwang scctx->isc_tx_tso_size_max, ntsosegments, 1293*a9643ea8Slogwang scctx->isc_tx_tso_segsize_max); 1294*a9643ea8Slogwang #endif 1295*a9643ea8Slogwang if (!(txq->ift_sds.ifsd_flags = 1296*a9643ea8Slogwang (uint8_t *) malloc(sizeof(uint8_t) * 1297*a9643ea8Slogwang scctx->isc_ntxd[txq->ift_br_offset], M_IFLIB, M_NOWAIT | M_ZERO))) { 1298*a9643ea8Slogwang device_printf(dev, "Unable to allocate tx_buffer memory\n"); 1299*a9643ea8Slogwang err = ENOMEM; 1300*a9643ea8Slogwang goto fail; 1301*a9643ea8Slogwang } 1302*a9643ea8Slogwang if (!(txq->ift_sds.ifsd_m = 1303*a9643ea8Slogwang (struct mbuf **) malloc(sizeof(struct mbuf *) * 1304*a9643ea8Slogwang scctx->isc_ntxd[txq->ift_br_offset], M_IFLIB, M_NOWAIT | M_ZERO))) { 1305*a9643ea8Slogwang device_printf(dev, "Unable to allocate tx_buffer memory\n"); 1306*a9643ea8Slogwang err = ENOMEM; 1307*a9643ea8Slogwang goto fail; 1308*a9643ea8Slogwang } 1309*a9643ea8Slogwang 1310*a9643ea8Slogwang /* Create the descriptor buffer dma maps */ 1311*a9643ea8Slogwang #if defined(ACPI_DMAR) || (!(defined(__i386__) && !defined(__amd64__))) 1312*a9643ea8Slogwang if ((ctx->ifc_flags & IFC_DMAR) == 0) 1313*a9643ea8Slogwang return (0); 1314*a9643ea8Slogwang 1315*a9643ea8Slogwang if (!(txq->ift_sds.ifsd_map = 1316*a9643ea8Slogwang (bus_dmamap_t *) malloc(sizeof(bus_dmamap_t) * scctx->isc_ntxd[txq->ift_br_offset], M_IFLIB, M_NOWAIT | M_ZERO))) { 1317*a9643ea8Slogwang device_printf(dev, "Unable to allocate tx_buffer map memory\n"); 1318*a9643ea8Slogwang err = ENOMEM; 1319*a9643ea8Slogwang goto fail; 1320*a9643ea8Slogwang } 1321*a9643ea8Slogwang 1322*a9643ea8Slogwang for (int i = 0; i < scctx->isc_ntxd[txq->ift_br_offset]; i++) { 1323*a9643ea8Slogwang err = bus_dmamap_create(txq->ift_desc_tag, 0, &txq->ift_sds.ifsd_map[i]); 1324*a9643ea8Slogwang if (err != 0) { 1325*a9643ea8Slogwang device_printf(dev, "Unable to create TX DMA map\n"); 1326*a9643ea8Slogwang goto fail; 1327*a9643ea8Slogwang } 1328*a9643ea8Slogwang } 1329*a9643ea8Slogwang #endif 1330*a9643ea8Slogwang return (0); 1331*a9643ea8Slogwang fail: 1332*a9643ea8Slogwang /* We free all, it handles case where we are in the middle */ 1333*a9643ea8Slogwang iflib_tx_structures_free(ctx); 1334*a9643ea8Slogwang return (err); 1335*a9643ea8Slogwang } 1336*a9643ea8Slogwang 1337*a9643ea8Slogwang static void 1338*a9643ea8Slogwang iflib_txsd_destroy(if_ctx_t ctx, iflib_txq_t txq, int i) 1339*a9643ea8Slogwang { 1340*a9643ea8Slogwang bus_dmamap_t map; 1341*a9643ea8Slogwang 1342*a9643ea8Slogwang map = NULL; 1343*a9643ea8Slogwang if (txq->ift_sds.ifsd_map != NULL) 1344*a9643ea8Slogwang map = txq->ift_sds.ifsd_map[i]; 1345*a9643ea8Slogwang if (map != NULL) { 1346*a9643ea8Slogwang bus_dmamap_unload(txq->ift_desc_tag, map); 1347*a9643ea8Slogwang bus_dmamap_destroy(txq->ift_desc_tag, map); 1348*a9643ea8Slogwang txq->ift_sds.ifsd_map[i] = NULL; 1349*a9643ea8Slogwang } 1350*a9643ea8Slogwang } 1351*a9643ea8Slogwang 1352*a9643ea8Slogwang static void 1353*a9643ea8Slogwang iflib_txq_destroy(iflib_txq_t txq) 1354*a9643ea8Slogwang { 1355*a9643ea8Slogwang if_ctx_t ctx = txq->ift_ctx; 1356*a9643ea8Slogwang 1357*a9643ea8Slogwang for (int i = 0; i < txq->ift_size; i++) 1358*a9643ea8Slogwang iflib_txsd_destroy(ctx, txq, i); 1359*a9643ea8Slogwang if (txq->ift_sds.ifsd_map != NULL) { 1360*a9643ea8Slogwang free(txq->ift_sds.ifsd_map, M_IFLIB); 1361*a9643ea8Slogwang txq->ift_sds.ifsd_map = NULL; 1362*a9643ea8Slogwang } 1363*a9643ea8Slogwang if (txq->ift_sds.ifsd_m != NULL) { 1364*a9643ea8Slogwang free(txq->ift_sds.ifsd_m, M_IFLIB); 1365*a9643ea8Slogwang txq->ift_sds.ifsd_m = NULL; 1366*a9643ea8Slogwang } 1367*a9643ea8Slogwang if (txq->ift_sds.ifsd_flags != NULL) { 1368*a9643ea8Slogwang free(txq->ift_sds.ifsd_flags, M_IFLIB); 1369*a9643ea8Slogwang txq->ift_sds.ifsd_flags = NULL; 1370*a9643ea8Slogwang } 1371*a9643ea8Slogwang if (txq->ift_desc_tag != NULL) { 1372*a9643ea8Slogwang bus_dma_tag_destroy(txq->ift_desc_tag); 1373*a9643ea8Slogwang txq->ift_desc_tag = NULL; 1374*a9643ea8Slogwang } 1375*a9643ea8Slogwang if (txq->ift_tso_desc_tag != NULL) { 1376*a9643ea8Slogwang bus_dma_tag_destroy(txq->ift_tso_desc_tag); 1377*a9643ea8Slogwang txq->ift_tso_desc_tag = NULL; 1378*a9643ea8Slogwang } 1379*a9643ea8Slogwang } 1380*a9643ea8Slogwang 1381*a9643ea8Slogwang static void 1382*a9643ea8Slogwang iflib_txsd_free(if_ctx_t ctx, iflib_txq_t txq, int i) 1383*a9643ea8Slogwang { 1384*a9643ea8Slogwang struct mbuf **mp; 1385*a9643ea8Slogwang 1386*a9643ea8Slogwang mp = &txq->ift_sds.ifsd_m[i]; 1387*a9643ea8Slogwang if (*mp == NULL) 1388*a9643ea8Slogwang return; 1389*a9643ea8Slogwang 1390*a9643ea8Slogwang if (txq->ift_sds.ifsd_map != NULL) { 1391*a9643ea8Slogwang bus_dmamap_sync(txq->ift_desc_tag, 1392*a9643ea8Slogwang txq->ift_sds.ifsd_map[i], 1393*a9643ea8Slogwang BUS_DMASYNC_POSTWRITE); 1394*a9643ea8Slogwang bus_dmamap_unload(txq->ift_desc_tag, 1395*a9643ea8Slogwang txq->ift_sds.ifsd_map[i]); 1396*a9643ea8Slogwang } 1397*a9643ea8Slogwang m_free(*mp); 1398*a9643ea8Slogwang DBG_COUNTER_INC(tx_frees); 1399*a9643ea8Slogwang *mp = NULL; 1400*a9643ea8Slogwang } 1401*a9643ea8Slogwang 1402*a9643ea8Slogwang static int 1403*a9643ea8Slogwang iflib_txq_setup(iflib_txq_t txq) 1404*a9643ea8Slogwang { 1405*a9643ea8Slogwang if_ctx_t ctx = txq->ift_ctx; 1406*a9643ea8Slogwang if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; 1407*a9643ea8Slogwang iflib_dma_info_t di; 1408*a9643ea8Slogwang int i; 1409*a9643ea8Slogwang 1410*a9643ea8Slogwang /* Set number of descriptors available */ 1411*a9643ea8Slogwang txq->ift_qstatus = IFLIB_QUEUE_IDLE; 1412*a9643ea8Slogwang 1413*a9643ea8Slogwang /* Reset indices */ 1414*a9643ea8Slogwang txq->ift_cidx_processed = txq->ift_pidx = txq->ift_cidx = txq->ift_npending = 0; 1415*a9643ea8Slogwang txq->ift_size = scctx->isc_ntxd[txq->ift_br_offset]; 1416*a9643ea8Slogwang 1417*a9643ea8Slogwang for (i = 0, di = txq->ift_ifdi; i < ctx->ifc_nhwtxqs; i++, di++) 1418*a9643ea8Slogwang bzero((void *)di->idi_vaddr, di->idi_size); 1419*a9643ea8Slogwang 1420*a9643ea8Slogwang IFDI_TXQ_SETUP(ctx, txq->ift_id); 1421*a9643ea8Slogwang for (i = 0, di = txq->ift_ifdi; i < ctx->ifc_nhwtxqs; i++, di++) 1422*a9643ea8Slogwang bus_dmamap_sync(di->idi_tag, di->idi_map, 1423*a9643ea8Slogwang BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1424*a9643ea8Slogwang return (0); 1425*a9643ea8Slogwang } 1426*a9643ea8Slogwang 1427*a9643ea8Slogwang /********************************************************************* 1428*a9643ea8Slogwang * 1429*a9643ea8Slogwang * Allocate memory for rx_buffer structures. Since we use one 1430*a9643ea8Slogwang * rx_buffer per received packet, the maximum number of rx_buffer's 1431*a9643ea8Slogwang * that we'll need is equal to the number of receive descriptors 1432*a9643ea8Slogwang * that we've allocated. 1433*a9643ea8Slogwang * 1434*a9643ea8Slogwang **********************************************************************/ 1435*a9643ea8Slogwang static int 1436*a9643ea8Slogwang iflib_rxsd_alloc(iflib_rxq_t rxq) 1437*a9643ea8Slogwang { 1438*a9643ea8Slogwang if_ctx_t ctx = rxq->ifr_ctx; 1439*a9643ea8Slogwang if_shared_ctx_t sctx = ctx->ifc_sctx; 1440*a9643ea8Slogwang if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; 1441*a9643ea8Slogwang device_t dev = ctx->ifc_dev; 1442*a9643ea8Slogwang iflib_fl_t fl; 1443*a9643ea8Slogwang iflib_rxsd_t rxsd; 1444*a9643ea8Slogwang int err; 1445*a9643ea8Slogwang 1446*a9643ea8Slogwang MPASS(scctx->isc_nrxd[0] > 0); 1447*a9643ea8Slogwang MPASS(scctx->isc_nrxd[rxq->ifr_fl_offset] > 0); 1448*a9643ea8Slogwang 1449*a9643ea8Slogwang fl = rxq->ifr_fl; 1450*a9643ea8Slogwang for (int i = 0; i < rxq->ifr_nfl; i++, fl++) { 1451*a9643ea8Slogwang fl->ifl_sds = malloc(sizeof(struct iflib_sw_rx_desc) * 1452*a9643ea8Slogwang scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, 1453*a9643ea8Slogwang M_WAITOK | M_ZERO); 1454*a9643ea8Slogwang if (fl->ifl_sds == NULL) { 1455*a9643ea8Slogwang device_printf(dev, "Unable to allocate rx sw desc memory\n"); 1456*a9643ea8Slogwang return (ENOMEM); 1457*a9643ea8Slogwang } 1458*a9643ea8Slogwang fl->ifl_size = scctx->isc_nrxd[rxq->ifr_fl_offset]; /* this isn't necessarily the same */ 1459*a9643ea8Slogwang err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 1460*a9643ea8Slogwang 1, 0, /* alignment, bounds */ 1461*a9643ea8Slogwang BUS_SPACE_MAXADDR, /* lowaddr */ 1462*a9643ea8Slogwang BUS_SPACE_MAXADDR, /* highaddr */ 1463*a9643ea8Slogwang NULL, NULL, /* filter, filterarg */ 1464*a9643ea8Slogwang sctx->isc_rx_maxsize, /* maxsize */ 1465*a9643ea8Slogwang sctx->isc_rx_nsegments, /* nsegments */ 1466*a9643ea8Slogwang sctx->isc_rx_maxsegsize, /* maxsegsize */ 1467*a9643ea8Slogwang 0, /* flags */ 1468*a9643ea8Slogwang NULL, /* lockfunc */ 1469*a9643ea8Slogwang NULL, /* lockarg */ 1470*a9643ea8Slogwang &fl->ifl_desc_tag); 1471*a9643ea8Slogwang if (err) { 1472*a9643ea8Slogwang device_printf(dev, "%s: bus_dma_tag_create failed %d\n", 1473*a9643ea8Slogwang __func__, err); 1474*a9643ea8Slogwang goto fail; 1475*a9643ea8Slogwang } 1476*a9643ea8Slogwang 1477*a9643ea8Slogwang rxsd = fl->ifl_sds; 1478*a9643ea8Slogwang for (int i = 0; i < scctx->isc_nrxd[rxq->ifr_fl_offset]; i++, rxsd++) { 1479*a9643ea8Slogwang err = bus_dmamap_create(fl->ifl_desc_tag, 0, &rxsd->ifsd_map); 1480*a9643ea8Slogwang if (err) { 1481*a9643ea8Slogwang device_printf(dev, "%s: bus_dmamap_create failed: %d\n", 1482*a9643ea8Slogwang __func__, err); 1483*a9643ea8Slogwang goto fail; 1484*a9643ea8Slogwang } 1485*a9643ea8Slogwang } 1486*a9643ea8Slogwang } 1487*a9643ea8Slogwang return (0); 1488*a9643ea8Slogwang 1489*a9643ea8Slogwang fail: 1490*a9643ea8Slogwang iflib_rx_structures_free(ctx); 1491*a9643ea8Slogwang return (err); 1492*a9643ea8Slogwang } 1493*a9643ea8Slogwang 1494*a9643ea8Slogwang 1495*a9643ea8Slogwang /* 1496*a9643ea8Slogwang * Internal service routines 1497*a9643ea8Slogwang */ 1498*a9643ea8Slogwang 1499*a9643ea8Slogwang struct rxq_refill_cb_arg { 1500*a9643ea8Slogwang int error; 1501*a9643ea8Slogwang bus_dma_segment_t seg; 1502*a9643ea8Slogwang int nseg; 1503*a9643ea8Slogwang }; 1504*a9643ea8Slogwang 1505*a9643ea8Slogwang static void 1506*a9643ea8Slogwang _rxq_refill_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1507*a9643ea8Slogwang { 1508*a9643ea8Slogwang struct rxq_refill_cb_arg *cb_arg = arg; 1509*a9643ea8Slogwang 1510*a9643ea8Slogwang cb_arg->error = error; 1511*a9643ea8Slogwang cb_arg->seg = segs[0]; 1512*a9643ea8Slogwang cb_arg->nseg = nseg; 1513*a9643ea8Slogwang } 1514*a9643ea8Slogwang 1515*a9643ea8Slogwang 1516*a9643ea8Slogwang #ifdef ACPI_DMAR 1517*a9643ea8Slogwang #define IS_DMAR(ctx) (ctx->ifc_flags & IFC_DMAR) 1518*a9643ea8Slogwang #else 1519*a9643ea8Slogwang #define IS_DMAR(ctx) (0) 1520*a9643ea8Slogwang #endif 1521*a9643ea8Slogwang 1522*a9643ea8Slogwang /** 1523*a9643ea8Slogwang * rxq_refill - refill an rxq free-buffer list 1524*a9643ea8Slogwang * @ctx: the iflib context 1525*a9643ea8Slogwang * @rxq: the free-list to refill 1526*a9643ea8Slogwang * @n: the number of new buffers to allocate 1527*a9643ea8Slogwang * 1528*a9643ea8Slogwang * (Re)populate an rxq free-buffer list with up to @n new packet buffers. 1529*a9643ea8Slogwang * The caller must assure that @n does not exceed the queue's capacity. 1530*a9643ea8Slogwang */ 1531*a9643ea8Slogwang static void 1532*a9643ea8Slogwang _iflib_fl_refill(if_ctx_t ctx, iflib_fl_t fl, int count) 1533*a9643ea8Slogwang { 1534*a9643ea8Slogwang struct mbuf *m; 1535*a9643ea8Slogwang int pidx = fl->ifl_pidx; 1536*a9643ea8Slogwang iflib_rxsd_t rxsd = &fl->ifl_sds[pidx]; 1537*a9643ea8Slogwang caddr_t cl; 1538*a9643ea8Slogwang int n, i = 0; 1539*a9643ea8Slogwang uint64_t bus_addr; 1540*a9643ea8Slogwang int err; 1541*a9643ea8Slogwang 1542*a9643ea8Slogwang n = count; 1543*a9643ea8Slogwang MPASS(n > 0); 1544*a9643ea8Slogwang MPASS(fl->ifl_credits + n <= fl->ifl_size); 1545*a9643ea8Slogwang 1546*a9643ea8Slogwang if (pidx < fl->ifl_cidx) 1547*a9643ea8Slogwang MPASS(pidx + n <= fl->ifl_cidx); 1548*a9643ea8Slogwang if (pidx == fl->ifl_cidx && (fl->ifl_credits < fl->ifl_size)) 1549*a9643ea8Slogwang MPASS(fl->ifl_gen == 0); 1550*a9643ea8Slogwang if (pidx > fl->ifl_cidx) 1551*a9643ea8Slogwang MPASS(n <= fl->ifl_size - pidx + fl->ifl_cidx); 1552*a9643ea8Slogwang 1553*a9643ea8Slogwang DBG_COUNTER_INC(fl_refills); 1554*a9643ea8Slogwang if (n > 8) 1555*a9643ea8Slogwang DBG_COUNTER_INC(fl_refills_large); 1556*a9643ea8Slogwang 1557*a9643ea8Slogwang while (n--) { 1558*a9643ea8Slogwang /* 1559*a9643ea8Slogwang * We allocate an uninitialized mbuf + cluster, mbuf is 1560*a9643ea8Slogwang * initialized after rx. 1561*a9643ea8Slogwang * 1562*a9643ea8Slogwang * If the cluster is still set then we know a minimum sized packet was received 1563*a9643ea8Slogwang */ 1564*a9643ea8Slogwang if ((cl = rxsd->ifsd_cl) == NULL) { 1565*a9643ea8Slogwang if ((cl = rxsd->ifsd_cl = m_cljget(NULL, M_NOWAIT, fl->ifl_buf_size)) == NULL) 1566*a9643ea8Slogwang break; 1567*a9643ea8Slogwang #if MEMORY_LOGGING 1568*a9643ea8Slogwang fl->ifl_cl_enqueued++; 1569*a9643ea8Slogwang #endif 1570*a9643ea8Slogwang } 1571*a9643ea8Slogwang if ((m = m_gethdr(M_NOWAIT, MT_NOINIT)) == NULL) { 1572*a9643ea8Slogwang break; 1573*a9643ea8Slogwang } 1574*a9643ea8Slogwang #if MEMORY_LOGGING 1575*a9643ea8Slogwang fl->ifl_m_enqueued++; 1576*a9643ea8Slogwang #endif 1577*a9643ea8Slogwang 1578*a9643ea8Slogwang DBG_COUNTER_INC(rx_allocs); 1579*a9643ea8Slogwang #ifdef notyet 1580*a9643ea8Slogwang if ((rxsd->ifsd_flags & RX_SW_DESC_MAP_CREATED) == 0) { 1581*a9643ea8Slogwang int err; 1582*a9643ea8Slogwang 1583*a9643ea8Slogwang if ((err = bus_dmamap_create(fl->ifl_ifdi->idi_tag, 0, &rxsd->ifsd_map))) { 1584*a9643ea8Slogwang log(LOG_WARNING, "bus_dmamap_create failed %d\n", err); 1585*a9643ea8Slogwang uma_zfree(fl->ifl_zone, cl); 1586*a9643ea8Slogwang n = 0; 1587*a9643ea8Slogwang goto done; 1588*a9643ea8Slogwang } 1589*a9643ea8Slogwang rxsd->ifsd_flags |= RX_SW_DESC_MAP_CREATED; 1590*a9643ea8Slogwang } 1591*a9643ea8Slogwang #endif 1592*a9643ea8Slogwang #if defined(__i386__) || defined(__amd64__) 1593*a9643ea8Slogwang if (!IS_DMAR(ctx)) { 1594*a9643ea8Slogwang bus_addr = pmap_kextract((vm_offset_t)cl); 1595*a9643ea8Slogwang } else 1596*a9643ea8Slogwang #endif 1597*a9643ea8Slogwang { 1598*a9643ea8Slogwang struct rxq_refill_cb_arg cb_arg; 1599*a9643ea8Slogwang iflib_rxq_t q; 1600*a9643ea8Slogwang 1601*a9643ea8Slogwang cb_arg.error = 0; 1602*a9643ea8Slogwang q = fl->ifl_rxq; 1603*a9643ea8Slogwang err = bus_dmamap_load(fl->ifl_desc_tag, rxsd->ifsd_map, 1604*a9643ea8Slogwang cl, fl->ifl_buf_size, _rxq_refill_cb, &cb_arg, 0); 1605*a9643ea8Slogwang 1606*a9643ea8Slogwang if (err != 0 || cb_arg.error) { 1607*a9643ea8Slogwang /* 1608*a9643ea8Slogwang * !zone_pack ? 1609*a9643ea8Slogwang */ 1610*a9643ea8Slogwang if (fl->ifl_zone == zone_pack) 1611*a9643ea8Slogwang uma_zfree(fl->ifl_zone, cl); 1612*a9643ea8Slogwang m_free(m); 1613*a9643ea8Slogwang n = 0; 1614*a9643ea8Slogwang goto done; 1615*a9643ea8Slogwang } 1616*a9643ea8Slogwang bus_addr = cb_arg.seg.ds_addr; 1617*a9643ea8Slogwang } 1618*a9643ea8Slogwang rxsd->ifsd_flags |= RX_SW_DESC_INUSE; 1619*a9643ea8Slogwang 1620*a9643ea8Slogwang MPASS(rxsd->ifsd_m == NULL); 1621*a9643ea8Slogwang rxsd->ifsd_cl = cl; 1622*a9643ea8Slogwang rxsd->ifsd_m = m; 1623*a9643ea8Slogwang fl->ifl_bus_addrs[i] = bus_addr; 1624*a9643ea8Slogwang fl->ifl_vm_addrs[i] = cl; 1625*a9643ea8Slogwang rxsd++; 1626*a9643ea8Slogwang fl->ifl_credits++; 1627*a9643ea8Slogwang i++; 1628*a9643ea8Slogwang MPASS(fl->ifl_credits <= fl->ifl_size); 1629*a9643ea8Slogwang if (++fl->ifl_pidx == fl->ifl_size) { 1630*a9643ea8Slogwang fl->ifl_pidx = 0; 1631*a9643ea8Slogwang fl->ifl_gen = 1; 1632*a9643ea8Slogwang rxsd = fl->ifl_sds; 1633*a9643ea8Slogwang } 1634*a9643ea8Slogwang if (n == 0 || i == IFLIB_MAX_RX_REFRESH) { 1635*a9643ea8Slogwang ctx->isc_rxd_refill(ctx->ifc_softc, fl->ifl_rxq->ifr_id, fl->ifl_id, pidx, 1636*a9643ea8Slogwang fl->ifl_bus_addrs, fl->ifl_vm_addrs, i, fl->ifl_buf_size); 1637*a9643ea8Slogwang i = 0; 1638*a9643ea8Slogwang pidx = fl->ifl_pidx; 1639*a9643ea8Slogwang } 1640*a9643ea8Slogwang } 1641*a9643ea8Slogwang done: 1642*a9643ea8Slogwang DBG_COUNTER_INC(rxd_flush); 1643*a9643ea8Slogwang if (fl->ifl_pidx == 0) 1644*a9643ea8Slogwang pidx = fl->ifl_size - 1; 1645*a9643ea8Slogwang else 1646*a9643ea8Slogwang pidx = fl->ifl_pidx - 1; 1647*a9643ea8Slogwang ctx->isc_rxd_flush(ctx->ifc_softc, fl->ifl_rxq->ifr_id, fl->ifl_id, pidx); 1648*a9643ea8Slogwang } 1649*a9643ea8Slogwang 1650*a9643ea8Slogwang static __inline void 1651*a9643ea8Slogwang __iflib_fl_refill_lt(if_ctx_t ctx, iflib_fl_t fl, int max) 1652*a9643ea8Slogwang { 1653*a9643ea8Slogwang /* we avoid allowing pidx to catch up with cidx as it confuses ixl */ 1654*a9643ea8Slogwang int32_t reclaimable = fl->ifl_size - fl->ifl_credits - 1; 1655*a9643ea8Slogwang #ifdef INVARIANTS 1656*a9643ea8Slogwang int32_t delta = fl->ifl_size - get_inuse(fl->ifl_size, fl->ifl_cidx, fl->ifl_pidx, fl->ifl_gen) - 1; 1657*a9643ea8Slogwang #endif 1658*a9643ea8Slogwang 1659*a9643ea8Slogwang MPASS(fl->ifl_credits <= fl->ifl_size); 1660*a9643ea8Slogwang MPASS(reclaimable == delta); 1661*a9643ea8Slogwang 1662*a9643ea8Slogwang if (reclaimable > 0) 1663*a9643ea8Slogwang _iflib_fl_refill(ctx, fl, min(max, reclaimable)); 1664*a9643ea8Slogwang } 1665*a9643ea8Slogwang 1666*a9643ea8Slogwang static void 1667*a9643ea8Slogwang iflib_fl_bufs_free(iflib_fl_t fl) 1668*a9643ea8Slogwang { 1669*a9643ea8Slogwang iflib_dma_info_t idi = fl->ifl_ifdi; 1670*a9643ea8Slogwang uint32_t i; 1671*a9643ea8Slogwang 1672*a9643ea8Slogwang for (i = 0; i < fl->ifl_size; i++) { 1673*a9643ea8Slogwang iflib_rxsd_t d = &fl->ifl_sds[i]; 1674*a9643ea8Slogwang 1675*a9643ea8Slogwang if (d->ifsd_flags & RX_SW_DESC_INUSE) { 1676*a9643ea8Slogwang bus_dmamap_unload(fl->ifl_desc_tag, d->ifsd_map); 1677*a9643ea8Slogwang bus_dmamap_destroy(fl->ifl_desc_tag, d->ifsd_map); 1678*a9643ea8Slogwang if (d->ifsd_m != NULL) { 1679*a9643ea8Slogwang m_init(d->ifsd_m, M_NOWAIT, MT_DATA, 0); 1680*a9643ea8Slogwang uma_zfree(zone_mbuf, d->ifsd_m); 1681*a9643ea8Slogwang } 1682*a9643ea8Slogwang if (d->ifsd_cl != NULL) 1683*a9643ea8Slogwang uma_zfree(fl->ifl_zone, d->ifsd_cl); 1684*a9643ea8Slogwang d->ifsd_flags = 0; 1685*a9643ea8Slogwang } else { 1686*a9643ea8Slogwang MPASS(d->ifsd_cl == NULL); 1687*a9643ea8Slogwang MPASS(d->ifsd_m == NULL); 1688*a9643ea8Slogwang } 1689*a9643ea8Slogwang #if MEMORY_LOGGING 1690*a9643ea8Slogwang fl->ifl_m_dequeued++; 1691*a9643ea8Slogwang fl->ifl_cl_dequeued++; 1692*a9643ea8Slogwang #endif 1693*a9643ea8Slogwang d->ifsd_cl = NULL; 1694*a9643ea8Slogwang d->ifsd_m = NULL; 1695*a9643ea8Slogwang } 1696*a9643ea8Slogwang /* 1697*a9643ea8Slogwang * Reset free list values 1698*a9643ea8Slogwang */ 1699*a9643ea8Slogwang fl->ifl_credits = fl->ifl_cidx = fl->ifl_pidx = fl->ifl_gen = 0;; 1700*a9643ea8Slogwang bzero(idi->idi_vaddr, idi->idi_size); 1701*a9643ea8Slogwang } 1702*a9643ea8Slogwang 1703*a9643ea8Slogwang /********************************************************************* 1704*a9643ea8Slogwang * 1705*a9643ea8Slogwang * Initialize a receive ring and its buffers. 1706*a9643ea8Slogwang * 1707*a9643ea8Slogwang **********************************************************************/ 1708*a9643ea8Slogwang static int 1709*a9643ea8Slogwang iflib_fl_setup(iflib_fl_t fl) 1710*a9643ea8Slogwang { 1711*a9643ea8Slogwang iflib_rxq_t rxq = fl->ifl_rxq; 1712*a9643ea8Slogwang if_ctx_t ctx = rxq->ifr_ctx; 1713*a9643ea8Slogwang if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; 1714*a9643ea8Slogwang 1715*a9643ea8Slogwang /* 1716*a9643ea8Slogwang ** Free current RX buffer structs and their mbufs 1717*a9643ea8Slogwang */ 1718*a9643ea8Slogwang iflib_fl_bufs_free(fl); 1719*a9643ea8Slogwang /* Now replenish the mbufs */ 1720*a9643ea8Slogwang MPASS(fl->ifl_credits == 0); 1721*a9643ea8Slogwang /* 1722*a9643ea8Slogwang * XXX don't set the max_frame_size to larger 1723*a9643ea8Slogwang * than the hardware can handle 1724*a9643ea8Slogwang */ 1725*a9643ea8Slogwang if (sctx->isc_max_frame_size <= 2048) 1726*a9643ea8Slogwang fl->ifl_buf_size = MCLBYTES; 1727*a9643ea8Slogwang else if (sctx->isc_max_frame_size <= 4096) 1728*a9643ea8Slogwang fl->ifl_buf_size = MJUMPAGESIZE; 1729*a9643ea8Slogwang else if (sctx->isc_max_frame_size <= 9216) 1730*a9643ea8Slogwang fl->ifl_buf_size = MJUM9BYTES; 1731*a9643ea8Slogwang else 1732*a9643ea8Slogwang fl->ifl_buf_size = MJUM16BYTES; 1733*a9643ea8Slogwang if (fl->ifl_buf_size > ctx->ifc_max_fl_buf_size) 1734*a9643ea8Slogwang ctx->ifc_max_fl_buf_size = fl->ifl_buf_size; 1735*a9643ea8Slogwang fl->ifl_cltype = m_gettype(fl->ifl_buf_size); 1736*a9643ea8Slogwang fl->ifl_zone = m_getzone(fl->ifl_buf_size); 1737*a9643ea8Slogwang 1738*a9643ea8Slogwang 1739*a9643ea8Slogwang /* avoid pre-allocating zillions of clusters to an idle card 1740*a9643ea8Slogwang * potentially speeding up attach 1741*a9643ea8Slogwang */ 1742*a9643ea8Slogwang _iflib_fl_refill(ctx, fl, min(128, fl->ifl_size)); 1743*a9643ea8Slogwang MPASS(min(128, fl->ifl_size) == fl->ifl_credits); 1744*a9643ea8Slogwang if (min(128, fl->ifl_size) != fl->ifl_credits) 1745*a9643ea8Slogwang return (ENOBUFS); 1746*a9643ea8Slogwang /* 1747*a9643ea8Slogwang * handle failure 1748*a9643ea8Slogwang */ 1749*a9643ea8Slogwang MPASS(rxq != NULL); 1750*a9643ea8Slogwang MPASS(fl->ifl_ifdi != NULL); 1751*a9643ea8Slogwang bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map, 1752*a9643ea8Slogwang BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1753*a9643ea8Slogwang return (0); 1754*a9643ea8Slogwang } 1755*a9643ea8Slogwang 1756*a9643ea8Slogwang /********************************************************************* 1757*a9643ea8Slogwang * 1758*a9643ea8Slogwang * Free receive ring data structures 1759*a9643ea8Slogwang * 1760*a9643ea8Slogwang **********************************************************************/ 1761*a9643ea8Slogwang static void 1762*a9643ea8Slogwang iflib_rx_sds_free(iflib_rxq_t rxq) 1763*a9643ea8Slogwang { 1764*a9643ea8Slogwang iflib_fl_t fl; 1765*a9643ea8Slogwang int i; 1766*a9643ea8Slogwang 1767*a9643ea8Slogwang if (rxq->ifr_fl != NULL) { 1768*a9643ea8Slogwang for (i = 0; i < rxq->ifr_nfl; i++) { 1769*a9643ea8Slogwang fl = &rxq->ifr_fl[i]; 1770*a9643ea8Slogwang if (fl->ifl_desc_tag != NULL) { 1771*a9643ea8Slogwang bus_dma_tag_destroy(fl->ifl_desc_tag); 1772*a9643ea8Slogwang fl->ifl_desc_tag = NULL; 1773*a9643ea8Slogwang } 1774*a9643ea8Slogwang } 1775*a9643ea8Slogwang if (rxq->ifr_fl->ifl_sds != NULL) 1776*a9643ea8Slogwang free(rxq->ifr_fl->ifl_sds, M_IFLIB); 1777*a9643ea8Slogwang 1778*a9643ea8Slogwang free(rxq->ifr_fl, M_IFLIB); 1779*a9643ea8Slogwang rxq->ifr_fl = NULL; 1780*a9643ea8Slogwang rxq->ifr_cq_gen = rxq->ifr_cq_cidx = rxq->ifr_cq_pidx = 0; 1781*a9643ea8Slogwang } 1782*a9643ea8Slogwang } 1783*a9643ea8Slogwang 1784*a9643ea8Slogwang /* 1785*a9643ea8Slogwang * MI independent logic 1786*a9643ea8Slogwang * 1787*a9643ea8Slogwang */ 1788*a9643ea8Slogwang static void 1789*a9643ea8Slogwang iflib_timer(void *arg) 1790*a9643ea8Slogwang { 1791*a9643ea8Slogwang iflib_txq_t txq = arg; 1792*a9643ea8Slogwang if_ctx_t ctx = txq->ift_ctx; 1793*a9643ea8Slogwang if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; 1794*a9643ea8Slogwang 1795*a9643ea8Slogwang if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) 1796*a9643ea8Slogwang return; 1797*a9643ea8Slogwang /* 1798*a9643ea8Slogwang ** Check on the state of the TX queue(s), this 1799*a9643ea8Slogwang ** can be done without the lock because its RO 1800*a9643ea8Slogwang ** and the HUNG state will be static if set. 1801*a9643ea8Slogwang */ 1802*a9643ea8Slogwang IFDI_TIMER(ctx, txq->ift_id); 1803*a9643ea8Slogwang if ((txq->ift_qstatus == IFLIB_QUEUE_HUNG) && 1804*a9643ea8Slogwang (ctx->ifc_pause_frames == 0)) 1805*a9643ea8Slogwang goto hung; 1806*a9643ea8Slogwang 1807*a9643ea8Slogwang if (TXQ_AVAIL(txq) <= 2*scctx->isc_tx_nsegments || 1808*a9643ea8Slogwang ifmp_ring_is_stalled(txq->ift_br[0])) 1809*a9643ea8Slogwang GROUPTASK_ENQUEUE(&txq->ift_task); 1810*a9643ea8Slogwang 1811*a9643ea8Slogwang ctx->ifc_pause_frames = 0; 1812*a9643ea8Slogwang if (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) 1813*a9643ea8Slogwang callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, txq, txq->ift_timer.c_cpu); 1814*a9643ea8Slogwang return; 1815*a9643ea8Slogwang hung: 1816*a9643ea8Slogwang CTX_LOCK(ctx); 1817*a9643ea8Slogwang if_setdrvflagbits(ctx->ifc_ifp, 0, IFF_DRV_RUNNING); 1818*a9643ea8Slogwang device_printf(ctx->ifc_dev, "TX(%d) desc avail = %d, pidx = %d\n", 1819*a9643ea8Slogwang txq->ift_id, TXQ_AVAIL(txq), txq->ift_pidx); 1820*a9643ea8Slogwang 1821*a9643ea8Slogwang IFDI_WATCHDOG_RESET(ctx); 1822*a9643ea8Slogwang ctx->ifc_watchdog_events++; 1823*a9643ea8Slogwang ctx->ifc_pause_frames = 0; 1824*a9643ea8Slogwang 1825*a9643ea8Slogwang iflib_init_locked(ctx); 1826*a9643ea8Slogwang CTX_UNLOCK(ctx); 1827*a9643ea8Slogwang } 1828*a9643ea8Slogwang 1829*a9643ea8Slogwang static void 1830*a9643ea8Slogwang iflib_init_locked(if_ctx_t ctx) 1831*a9643ea8Slogwang { 1832*a9643ea8Slogwang if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; 1833*a9643ea8Slogwang if_t ifp = ctx->ifc_ifp; 1834*a9643ea8Slogwang iflib_fl_t fl; 1835*a9643ea8Slogwang iflib_txq_t txq; 1836*a9643ea8Slogwang iflib_rxq_t rxq; 1837*a9643ea8Slogwang int i, j; 1838*a9643ea8Slogwang 1839*a9643ea8Slogwang 1840*a9643ea8Slogwang if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); 1841*a9643ea8Slogwang IFDI_INTR_DISABLE(ctx); 1842*a9643ea8Slogwang 1843*a9643ea8Slogwang /* Set hardware offload abilities */ 1844*a9643ea8Slogwang if_clearhwassist(ifp); 1845*a9643ea8Slogwang if (if_getcapenable(ifp) & IFCAP_TXCSUM) 1846*a9643ea8Slogwang if_sethwassistbits(ifp, CSUM_IP | CSUM_TCP | CSUM_UDP, 0); 1847*a9643ea8Slogwang if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6) 1848*a9643ea8Slogwang if_sethwassistbits(ifp, (CSUM_TCP_IPV6 | CSUM_UDP_IPV6), 0); 1849*a9643ea8Slogwang if (if_getcapenable(ifp) & IFCAP_TSO4) 1850*a9643ea8Slogwang if_sethwassistbits(ifp, CSUM_IP_TSO, 0); 1851*a9643ea8Slogwang if (if_getcapenable(ifp) & IFCAP_TSO6) 1852*a9643ea8Slogwang if_sethwassistbits(ifp, CSUM_IP6_TSO, 0); 1853*a9643ea8Slogwang 1854*a9643ea8Slogwang for (i = 0, txq = ctx->ifc_txqs; i < sctx->isc_ntxqsets; i++, txq++) { 1855*a9643ea8Slogwang CALLOUT_LOCK(txq); 1856*a9643ea8Slogwang callout_stop(&txq->ift_timer); 1857*a9643ea8Slogwang callout_stop(&txq->ift_db_check); 1858*a9643ea8Slogwang CALLOUT_UNLOCK(txq); 1859*a9643ea8Slogwang iflib_netmap_txq_init(ctx, txq); 1860*a9643ea8Slogwang } 1861*a9643ea8Slogwang for (i = 0, rxq = ctx->ifc_rxqs; i < sctx->isc_nrxqsets; i++, rxq++) { 1862*a9643ea8Slogwang iflib_netmap_rxq_init(ctx, rxq); 1863*a9643ea8Slogwang } 1864*a9643ea8Slogwang #ifdef INVARIANTS 1865*a9643ea8Slogwang i = if_getdrvflags(ifp); 1866*a9643ea8Slogwang #endif 1867*a9643ea8Slogwang IFDI_INIT(ctx); 1868*a9643ea8Slogwang MPASS(if_getdrvflags(ifp) == i); 1869*a9643ea8Slogwang for (i = 0, rxq = ctx->ifc_rxqs; i < sctx->isc_nrxqsets; i++, rxq++) { 1870*a9643ea8Slogwang for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) { 1871*a9643ea8Slogwang if (iflib_fl_setup(fl)) { 1872*a9643ea8Slogwang device_printf(ctx->ifc_dev, "freelist setup failed - check cluster settings\n"); 1873*a9643ea8Slogwang goto done; 1874*a9643ea8Slogwang } 1875*a9643ea8Slogwang } 1876*a9643ea8Slogwang } 1877*a9643ea8Slogwang done: 1878*a9643ea8Slogwang if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); 1879*a9643ea8Slogwang IFDI_INTR_ENABLE(ctx); 1880*a9643ea8Slogwang txq = ctx->ifc_txqs; 1881*a9643ea8Slogwang for (i = 0; i < sctx->isc_ntxqsets; i++, txq++) 1882*a9643ea8Slogwang callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, txq, 1883*a9643ea8Slogwang txq->ift_timer.c_cpu); 1884*a9643ea8Slogwang } 1885*a9643ea8Slogwang 1886*a9643ea8Slogwang static int 1887*a9643ea8Slogwang iflib_media_change(if_t ifp) 1888*a9643ea8Slogwang { 1889*a9643ea8Slogwang if_ctx_t ctx = if_getsoftc(ifp); 1890*a9643ea8Slogwang int err; 1891*a9643ea8Slogwang 1892*a9643ea8Slogwang CTX_LOCK(ctx); 1893*a9643ea8Slogwang if ((err = IFDI_MEDIA_CHANGE(ctx)) == 0) 1894*a9643ea8Slogwang iflib_init_locked(ctx); 1895*a9643ea8Slogwang CTX_UNLOCK(ctx); 1896*a9643ea8Slogwang return (err); 1897*a9643ea8Slogwang } 1898*a9643ea8Slogwang 1899*a9643ea8Slogwang static void 1900*a9643ea8Slogwang iflib_media_status(if_t ifp, struct ifmediareq *ifmr) 1901*a9643ea8Slogwang { 1902*a9643ea8Slogwang if_ctx_t ctx = if_getsoftc(ifp); 1903*a9643ea8Slogwang 1904*a9643ea8Slogwang CTX_LOCK(ctx); 1905*a9643ea8Slogwang IFDI_UPDATE_ADMIN_STATUS(ctx); 1906*a9643ea8Slogwang IFDI_MEDIA_STATUS(ctx, ifmr); 1907*a9643ea8Slogwang CTX_UNLOCK(ctx); 1908*a9643ea8Slogwang } 1909*a9643ea8Slogwang 1910*a9643ea8Slogwang static void 1911*a9643ea8Slogwang iflib_stop(if_ctx_t ctx) 1912*a9643ea8Slogwang { 1913*a9643ea8Slogwang iflib_txq_t txq = ctx->ifc_txqs; 1914*a9643ea8Slogwang iflib_rxq_t rxq = ctx->ifc_rxqs; 1915*a9643ea8Slogwang if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; 1916*a9643ea8Slogwang iflib_dma_info_t di; 1917*a9643ea8Slogwang iflib_fl_t fl; 1918*a9643ea8Slogwang int i, j; 1919*a9643ea8Slogwang 1920*a9643ea8Slogwang /* Tell the stack that the interface is no longer active */ 1921*a9643ea8Slogwang if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); 1922*a9643ea8Slogwang 1923*a9643ea8Slogwang IFDI_INTR_DISABLE(ctx); 1924*a9643ea8Slogwang msleep(ctx, &ctx->ifc_mtx, PUSER, "iflib_init", hz); 1925*a9643ea8Slogwang 1926*a9643ea8Slogwang /* Wait for current tx queue users to exit to disarm watchdog timer. */ 1927*a9643ea8Slogwang for (i = 0; i < scctx->isc_ntxqsets; i++, txq++) { 1928*a9643ea8Slogwang /* make sure all transmitters have completed before proceeding XXX */ 1929*a9643ea8Slogwang 1930*a9643ea8Slogwang /* clean any enqueued buffers */ 1931*a9643ea8Slogwang iflib_txq_check_drain(txq, 0); 1932*a9643ea8Slogwang /* Free any existing tx buffers. */ 1933*a9643ea8Slogwang for (j = 0; j < txq->ift_size; j++) { 1934*a9643ea8Slogwang iflib_txsd_free(ctx, txq, j); 1935*a9643ea8Slogwang } 1936*a9643ea8Slogwang txq->ift_processed = txq->ift_cleaned = txq->ift_cidx_processed = 0; 1937*a9643ea8Slogwang txq->ift_in_use = txq->ift_cidx = txq->ift_pidx = txq->ift_no_desc_avail = 0; 1938*a9643ea8Slogwang txq->ift_closed = txq->ift_mbuf_defrag = txq->ift_mbuf_defrag_failed = 0; 1939*a9643ea8Slogwang txq->ift_no_tx_dma_setup = txq->ift_txd_encap_efbig = txq->ift_map_failed = 0; 1940*a9643ea8Slogwang txq->ift_pullups = 0; 1941*a9643ea8Slogwang ifmp_ring_reset_stats(txq->ift_br[0]); 1942*a9643ea8Slogwang for (j = 0, di = txq->ift_ifdi; j < ctx->ifc_nhwtxqs; j++, di++) 1943*a9643ea8Slogwang bzero((void *)di->idi_vaddr, di->idi_size); 1944*a9643ea8Slogwang } 1945*a9643ea8Slogwang for (i = 0; i < scctx->isc_nrxqsets; i++, rxq++) { 1946*a9643ea8Slogwang /* make sure all transmitters have completed before proceeding XXX */ 1947*a9643ea8Slogwang 1948*a9643ea8Slogwang for (j = 0, di = txq->ift_ifdi; j < ctx->ifc_nhwrxqs; j++, di++) 1949*a9643ea8Slogwang bzero((void *)di->idi_vaddr, di->idi_size); 1950*a9643ea8Slogwang /* also resets the free lists pidx/cidx */ 1951*a9643ea8Slogwang for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) 1952*a9643ea8Slogwang iflib_fl_bufs_free(fl); 1953*a9643ea8Slogwang } 1954*a9643ea8Slogwang IFDI_STOP(ctx); 1955*a9643ea8Slogwang } 1956*a9643ea8Slogwang 1957*a9643ea8Slogwang static iflib_rxsd_t 1958*a9643ea8Slogwang rxd_frag_to_sd(iflib_rxq_t rxq, if_rxd_frag_t irf, int *cltype, int unload) 1959*a9643ea8Slogwang { 1960*a9643ea8Slogwang int flid, cidx; 1961*a9643ea8Slogwang iflib_rxsd_t sd; 1962*a9643ea8Slogwang iflib_fl_t fl; 1963*a9643ea8Slogwang iflib_dma_info_t di; 1964*a9643ea8Slogwang 1965*a9643ea8Slogwang flid = irf->irf_flid; 1966*a9643ea8Slogwang cidx = irf->irf_idx; 1967*a9643ea8Slogwang fl = &rxq->ifr_fl[flid]; 1968*a9643ea8Slogwang fl->ifl_credits--; 1969*a9643ea8Slogwang #if MEMORY_LOGGING 1970*a9643ea8Slogwang fl->ifl_m_dequeued++; 1971*a9643ea8Slogwang if (cltype) 1972*a9643ea8Slogwang fl->ifl_cl_dequeued++; 1973*a9643ea8Slogwang #endif 1974*a9643ea8Slogwang sd = &fl->ifl_sds[cidx]; 1975*a9643ea8Slogwang di = fl->ifl_ifdi; 1976*a9643ea8Slogwang bus_dmamap_sync(di->idi_tag, di->idi_map, 1977*a9643ea8Slogwang BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1978*a9643ea8Slogwang 1979*a9643ea8Slogwang /* not valid assert if bxe really does SGE from non-contiguous elements */ 1980*a9643ea8Slogwang MPASS(fl->ifl_cidx == cidx); 1981*a9643ea8Slogwang if (unload) 1982*a9643ea8Slogwang bus_dmamap_unload(fl->ifl_desc_tag, sd->ifsd_map); 1983*a9643ea8Slogwang 1984*a9643ea8Slogwang if (__predict_false(++fl->ifl_cidx == fl->ifl_size)) { 1985*a9643ea8Slogwang fl->ifl_cidx = 0; 1986*a9643ea8Slogwang fl->ifl_gen = 0; 1987*a9643ea8Slogwang } 1988*a9643ea8Slogwang /* YES ick */ 1989*a9643ea8Slogwang if (cltype) 1990*a9643ea8Slogwang *cltype = fl->ifl_cltype; 1991*a9643ea8Slogwang return (sd); 1992*a9643ea8Slogwang } 1993*a9643ea8Slogwang 1994*a9643ea8Slogwang static struct mbuf * 1995*a9643ea8Slogwang assemble_segments(iflib_rxq_t rxq, if_rxd_info_t ri) 1996*a9643ea8Slogwang { 1997*a9643ea8Slogwang int i, padlen , flags, cltype; 1998*a9643ea8Slogwang struct mbuf *m, *mh, *mt; 1999*a9643ea8Slogwang iflib_rxsd_t sd; 2000*a9643ea8Slogwang caddr_t cl; 2001*a9643ea8Slogwang 2002*a9643ea8Slogwang i = 0; 2003*a9643ea8Slogwang mh = NULL; 2004*a9643ea8Slogwang do { 2005*a9643ea8Slogwang sd = rxd_frag_to_sd(rxq, &ri->iri_frags[i], &cltype, TRUE); 2006*a9643ea8Slogwang 2007*a9643ea8Slogwang MPASS(sd->ifsd_cl != NULL); 2008*a9643ea8Slogwang MPASS(sd->ifsd_m != NULL); 2009*a9643ea8Slogwang 2010*a9643ea8Slogwang /* Don't include zero-length frags */ 2011*a9643ea8Slogwang if (ri->iri_frags[i].irf_len == 0) { 2012*a9643ea8Slogwang /* XXX we can save the cluster here, but not the mbuf */ 2013*a9643ea8Slogwang m_init(sd->ifsd_m, M_NOWAIT, MT_DATA, 0); 2014*a9643ea8Slogwang m_free(sd->ifsd_m); 2015*a9643ea8Slogwang sd->ifsd_m = NULL; 2016*a9643ea8Slogwang continue; 2017*a9643ea8Slogwang } 2018*a9643ea8Slogwang 2019*a9643ea8Slogwang m = sd->ifsd_m; 2020*a9643ea8Slogwang if (mh == NULL) { 2021*a9643ea8Slogwang flags = M_PKTHDR|M_EXT; 2022*a9643ea8Slogwang mh = mt = m; 2023*a9643ea8Slogwang padlen = ri->iri_pad; 2024*a9643ea8Slogwang } else { 2025*a9643ea8Slogwang flags = M_EXT; 2026*a9643ea8Slogwang mt->m_next = m; 2027*a9643ea8Slogwang mt = m; 2028*a9643ea8Slogwang /* assuming padding is only on the first fragment */ 2029*a9643ea8Slogwang padlen = 0; 2030*a9643ea8Slogwang } 2031*a9643ea8Slogwang sd->ifsd_m = NULL; 2032*a9643ea8Slogwang cl = sd->ifsd_cl; 2033*a9643ea8Slogwang sd->ifsd_cl = NULL; 2034*a9643ea8Slogwang 2035*a9643ea8Slogwang /* Can these two be made one ? */ 2036*a9643ea8Slogwang m_init(m, M_NOWAIT, MT_DATA, flags); 2037*a9643ea8Slogwang m_cljset(m, cl, cltype); 2038*a9643ea8Slogwang /* 2039*a9643ea8Slogwang * These must follow m_init and m_cljset 2040*a9643ea8Slogwang */ 2041*a9643ea8Slogwang m->m_data += padlen; 2042*a9643ea8Slogwang ri->iri_len -= padlen; 2043*a9643ea8Slogwang m->m_len = ri->iri_frags[i].irf_len; 2044*a9643ea8Slogwang } while (++i < ri->iri_nfrags); 2045*a9643ea8Slogwang 2046*a9643ea8Slogwang return (mh); 2047*a9643ea8Slogwang } 2048*a9643ea8Slogwang 2049*a9643ea8Slogwang /* 2050*a9643ea8Slogwang * Process one software descriptor 2051*a9643ea8Slogwang */ 2052*a9643ea8Slogwang static struct mbuf * 2053*a9643ea8Slogwang iflib_rxd_pkt_get(iflib_rxq_t rxq, if_rxd_info_t ri) 2054*a9643ea8Slogwang { 2055*a9643ea8Slogwang struct mbuf *m; 2056*a9643ea8Slogwang iflib_rxsd_t sd; 2057*a9643ea8Slogwang 2058*a9643ea8Slogwang /* should I merge this back in now that the two paths are basically duplicated? */ 2059*a9643ea8Slogwang if (ri->iri_nfrags == 1 && 2060*a9643ea8Slogwang ri->iri_frags[0].irf_len <= IFLIB_RX_COPY_THRESH) { 2061*a9643ea8Slogwang sd = rxd_frag_to_sd(rxq, &ri->iri_frags[0], NULL, FALSE); 2062*a9643ea8Slogwang m = sd->ifsd_m; 2063*a9643ea8Slogwang sd->ifsd_m = NULL; 2064*a9643ea8Slogwang m_init(m, M_NOWAIT, MT_DATA, M_PKTHDR); 2065*a9643ea8Slogwang memcpy(m->m_data, sd->ifsd_cl, ri->iri_len); 2066*a9643ea8Slogwang m->m_len = ri->iri_frags[0].irf_len; 2067*a9643ea8Slogwang } else { 2068*a9643ea8Slogwang m = assemble_segments(rxq, ri); 2069*a9643ea8Slogwang } 2070*a9643ea8Slogwang m->m_pkthdr.len = ri->iri_len; 2071*a9643ea8Slogwang m->m_pkthdr.rcvif = ri->iri_ifp; 2072*a9643ea8Slogwang m->m_flags |= ri->iri_flags; 2073*a9643ea8Slogwang m->m_pkthdr.ether_vtag = ri->iri_vtag; 2074*a9643ea8Slogwang m->m_pkthdr.flowid = ri->iri_flowid; 2075*a9643ea8Slogwang M_HASHTYPE_SET(m, ri->iri_rsstype); 2076*a9643ea8Slogwang m->m_pkthdr.csum_flags = ri->iri_csum_flags; 2077*a9643ea8Slogwang m->m_pkthdr.csum_data = ri->iri_csum_data; 2078*a9643ea8Slogwang return (m); 2079*a9643ea8Slogwang } 2080*a9643ea8Slogwang 2081*a9643ea8Slogwang static bool 2082*a9643ea8Slogwang iflib_rxeof(iflib_rxq_t rxq, int budget) 2083*a9643ea8Slogwang { 2084*a9643ea8Slogwang if_ctx_t ctx = rxq->ifr_ctx; 2085*a9643ea8Slogwang if_shared_ctx_t sctx = ctx->ifc_sctx; 2086*a9643ea8Slogwang if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; 2087*a9643ea8Slogwang int avail, i; 2088*a9643ea8Slogwang uint16_t *cidxp; 2089*a9643ea8Slogwang struct if_rxd_info ri; 2090*a9643ea8Slogwang int err, budget_left, rx_bytes, rx_pkts; 2091*a9643ea8Slogwang iflib_fl_t fl; 2092*a9643ea8Slogwang struct ifnet *ifp; 2093*a9643ea8Slogwang int lro_enabled; 2094*a9643ea8Slogwang /* 2095*a9643ea8Slogwang * XXX early demux data packets so that if_input processing only handles 2096*a9643ea8Slogwang * acks in interrupt context 2097*a9643ea8Slogwang */ 2098*a9643ea8Slogwang struct mbuf *m, *mh, *mt; 2099*a9643ea8Slogwang 2100*a9643ea8Slogwang if (netmap_rx_irq(ctx->ifc_ifp, rxq->ifr_id, &budget)) { 2101*a9643ea8Slogwang return (FALSE); 2102*a9643ea8Slogwang } 2103*a9643ea8Slogwang 2104*a9643ea8Slogwang mh = mt = NULL; 2105*a9643ea8Slogwang MPASS(budget > 0); 2106*a9643ea8Slogwang rx_pkts = rx_bytes = 0; 2107*a9643ea8Slogwang if (sctx->isc_flags & IFLIB_HAS_RXCQ) 2108*a9643ea8Slogwang cidxp = &rxq->ifr_cq_cidx; 2109*a9643ea8Slogwang else 2110*a9643ea8Slogwang cidxp = &rxq->ifr_fl[0].ifl_cidx; 2111*a9643ea8Slogwang if ((avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget)) == 0) { 2112*a9643ea8Slogwang for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++) 2113*a9643ea8Slogwang __iflib_fl_refill_lt(ctx, fl, budget + 8); 2114*a9643ea8Slogwang DBG_COUNTER_INC(rx_unavail); 2115*a9643ea8Slogwang return (false); 2116*a9643ea8Slogwang } 2117*a9643ea8Slogwang 2118*a9643ea8Slogwang for (budget_left = budget; (budget_left > 0) && (avail > 0); budget_left--, avail--) { 2119*a9643ea8Slogwang if (__predict_false(!CTX_ACTIVE(ctx))) { 2120*a9643ea8Slogwang DBG_COUNTER_INC(rx_ctx_inactive); 2121*a9643ea8Slogwang break; 2122*a9643ea8Slogwang } 2123*a9643ea8Slogwang /* 2124*a9643ea8Slogwang * Reset client set fields to their default values 2125*a9643ea8Slogwang */ 2126*a9643ea8Slogwang bzero(&ri, sizeof(ri)); 2127*a9643ea8Slogwang ri.iri_qsidx = rxq->ifr_id; 2128*a9643ea8Slogwang ri.iri_cidx = *cidxp; 2129*a9643ea8Slogwang ri.iri_ifp = ctx->ifc_ifp; 2130*a9643ea8Slogwang ri.iri_frags = rxq->ifr_frags; 2131*a9643ea8Slogwang err = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri); 2132*a9643ea8Slogwang 2133*a9643ea8Slogwang /* in lieu of handling correctly - make sure it isn't being unhandled */ 2134*a9643ea8Slogwang MPASS(err == 0); 2135*a9643ea8Slogwang if (sctx->isc_flags & IFLIB_HAS_RXCQ) { 2136*a9643ea8Slogwang *cidxp = ri.iri_cidx; 2137*a9643ea8Slogwang /* Update our consumer index */ 2138*a9643ea8Slogwang while (rxq->ifr_cq_cidx >= scctx->isc_nrxd[0]) { 2139*a9643ea8Slogwang rxq->ifr_cq_cidx -= scctx->isc_nrxd[0]; 2140*a9643ea8Slogwang rxq->ifr_cq_gen = 0; 2141*a9643ea8Slogwang } 2142*a9643ea8Slogwang /* was this only a completion queue message? */ 2143*a9643ea8Slogwang if (__predict_false(ri.iri_nfrags == 0)) 2144*a9643ea8Slogwang continue; 2145*a9643ea8Slogwang } 2146*a9643ea8Slogwang MPASS(ri.iri_nfrags != 0); 2147*a9643ea8Slogwang MPASS(ri.iri_len != 0); 2148*a9643ea8Slogwang 2149*a9643ea8Slogwang /* will advance the cidx on the corresponding free lists */ 2150*a9643ea8Slogwang m = iflib_rxd_pkt_get(rxq, &ri); 2151*a9643ea8Slogwang if (avail == 0 && budget_left) 2152*a9643ea8Slogwang avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget_left); 2153*a9643ea8Slogwang 2154*a9643ea8Slogwang if (__predict_false(m == NULL)) { 2155*a9643ea8Slogwang DBG_COUNTER_INC(rx_mbuf_null); 2156*a9643ea8Slogwang continue; 2157*a9643ea8Slogwang } 2158*a9643ea8Slogwang /* imm_pkt: -- cxgb */ 2159*a9643ea8Slogwang if (mh == NULL) 2160*a9643ea8Slogwang mh = mt = m; 2161*a9643ea8Slogwang else { 2162*a9643ea8Slogwang mt->m_nextpkt = m; 2163*a9643ea8Slogwang mt = m; 2164*a9643ea8Slogwang } 2165*a9643ea8Slogwang } 2166*a9643ea8Slogwang /* make sure that we can refill faster than drain */ 2167*a9643ea8Slogwang for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++) 2168*a9643ea8Slogwang __iflib_fl_refill_lt(ctx, fl, budget + 8); 2169*a9643ea8Slogwang 2170*a9643ea8Slogwang ifp = ctx->ifc_ifp; 2171*a9643ea8Slogwang lro_enabled = (if_getcapenable(ifp) & IFCAP_LRO); 2172*a9643ea8Slogwang while (mh != NULL) { 2173*a9643ea8Slogwang m = mh; 2174*a9643ea8Slogwang mh = mh->m_nextpkt; 2175*a9643ea8Slogwang m->m_nextpkt = NULL; 2176*a9643ea8Slogwang rx_bytes += m->m_pkthdr.len; 2177*a9643ea8Slogwang rx_pkts++; 2178*a9643ea8Slogwang #if defined(INET6) || defined(INET) 2179*a9643ea8Slogwang if (lro_enabled && tcp_lro_rx(&rxq->ifr_lc, m, 0) == 0) 2180*a9643ea8Slogwang continue; 2181*a9643ea8Slogwang #endif 2182*a9643ea8Slogwang DBG_COUNTER_INC(rx_if_input); 2183*a9643ea8Slogwang ifp->if_input(ifp, m); 2184*a9643ea8Slogwang } 2185*a9643ea8Slogwang 2186*a9643ea8Slogwang if_inc_counter(ifp, IFCOUNTER_IBYTES, rx_bytes); 2187*a9643ea8Slogwang if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_pkts); 2188*a9643ea8Slogwang 2189*a9643ea8Slogwang /* 2190*a9643ea8Slogwang * Flush any outstanding LRO work 2191*a9643ea8Slogwang */ 2192*a9643ea8Slogwang #if defined(INET6) || defined(INET) 2193*a9643ea8Slogwang tcp_lro_flush_all(&rxq->ifr_lc); 2194*a9643ea8Slogwang #endif 2195*a9643ea8Slogwang if (avail) 2196*a9643ea8Slogwang return true; 2197*a9643ea8Slogwang return (iflib_rxd_avail(ctx, rxq, *cidxp, 1)); 2198*a9643ea8Slogwang } 2199*a9643ea8Slogwang 2200*a9643ea8Slogwang #define M_CSUM_FLAGS(m) ((m)->m_pkthdr.csum_flags) 2201*a9643ea8Slogwang #define M_HAS_VLANTAG(m) (m->m_flags & M_VLANTAG) 2202*a9643ea8Slogwang #define TXQ_MAX_DB_DEFERRED(size) (size >> 5) 2203*a9643ea8Slogwang #define TXQ_MAX_DB_CONSUMED(size) (size >> 4) 2204*a9643ea8Slogwang 2205*a9643ea8Slogwang static __inline void 2206*a9643ea8Slogwang iflib_txd_db_check(if_ctx_t ctx, iflib_txq_t txq, int ring) 2207*a9643ea8Slogwang { 2208*a9643ea8Slogwang uint32_t dbval; 2209*a9643ea8Slogwang 2210*a9643ea8Slogwang if (ring || txq->ift_db_pending >= 2211*a9643ea8Slogwang TXQ_MAX_DB_DEFERRED(txq->ift_size)) { 2212*a9643ea8Slogwang 2213*a9643ea8Slogwang /* the lock will only ever be contended in the !min_latency case */ 2214*a9643ea8Slogwang if (!TXDB_TRYLOCK(txq)) 2215*a9643ea8Slogwang return; 2216*a9643ea8Slogwang dbval = txq->ift_npending ? txq->ift_npending : txq->ift_pidx; 2217*a9643ea8Slogwang ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, dbval); 2218*a9643ea8Slogwang txq->ift_db_pending = txq->ift_npending = 0; 2219*a9643ea8Slogwang TXDB_UNLOCK(txq); 2220*a9643ea8Slogwang } 2221*a9643ea8Slogwang } 2222*a9643ea8Slogwang 2223*a9643ea8Slogwang static void 2224*a9643ea8Slogwang iflib_txd_deferred_db_check(void * arg) 2225*a9643ea8Slogwang { 2226*a9643ea8Slogwang iflib_txq_t txq = arg; 2227*a9643ea8Slogwang 2228*a9643ea8Slogwang /* simple non-zero boolean so use bitwise OR */ 2229*a9643ea8Slogwang if ((txq->ift_db_pending | txq->ift_npending) && 2230*a9643ea8Slogwang txq->ift_db_pending >= txq->ift_db_pending_queued) 2231*a9643ea8Slogwang iflib_txd_db_check(txq->ift_ctx, txq, TRUE); 2232*a9643ea8Slogwang txq->ift_db_pending_queued = 0; 2233*a9643ea8Slogwang if (ifmp_ring_is_stalled(txq->ift_br[0])) 2234*a9643ea8Slogwang iflib_txq_check_drain(txq, 4); 2235*a9643ea8Slogwang } 2236*a9643ea8Slogwang 2237*a9643ea8Slogwang #ifdef PKT_DEBUG 2238*a9643ea8Slogwang static void 2239*a9643ea8Slogwang print_pkt(if_pkt_info_t pi) 2240*a9643ea8Slogwang { 2241*a9643ea8Slogwang printf("pi len: %d qsidx: %d nsegs: %d ndescs: %d flags: %x pidx: %d\n", 2242*a9643ea8Slogwang pi->ipi_len, pi->ipi_qsidx, pi->ipi_nsegs, pi->ipi_ndescs, pi->ipi_flags, pi->ipi_pidx); 2243*a9643ea8Slogwang printf("pi new_pidx: %d csum_flags: %lx tso_segsz: %d mflags: %x vtag: %d\n", 2244*a9643ea8Slogwang pi->ipi_new_pidx, pi->ipi_csum_flags, pi->ipi_tso_segsz, pi->ipi_mflags, pi->ipi_vtag); 2245*a9643ea8Slogwang printf("pi etype: %d ehdrlen: %d ip_hlen: %d ipproto: %d\n", 2246*a9643ea8Slogwang pi->ipi_etype, pi->ipi_ehdrlen, pi->ipi_ip_hlen, pi->ipi_ipproto); 2247*a9643ea8Slogwang } 2248*a9643ea8Slogwang #endif 2249*a9643ea8Slogwang 2250*a9643ea8Slogwang #define IS_TSO4(pi) ((pi)->ipi_csum_flags & CSUM_IP_TSO) 2251*a9643ea8Slogwang #define IS_TSO6(pi) ((pi)->ipi_csum_flags & CSUM_IP6_TSO) 2252*a9643ea8Slogwang 2253*a9643ea8Slogwang static int 2254*a9643ea8Slogwang iflib_parse_header(iflib_txq_t txq, if_pkt_info_t pi, struct mbuf **mp) 2255*a9643ea8Slogwang { 2256*a9643ea8Slogwang struct ether_vlan_header *eh; 2257*a9643ea8Slogwang struct mbuf *m, *n; 2258*a9643ea8Slogwang 2259*a9643ea8Slogwang n = m = *mp; 2260*a9643ea8Slogwang /* 2261*a9643ea8Slogwang * Determine where frame payload starts. 2262*a9643ea8Slogwang * Jump over vlan headers if already present, 2263*a9643ea8Slogwang * helpful for QinQ too. 2264*a9643ea8Slogwang */ 2265*a9643ea8Slogwang if (__predict_false(m->m_len < sizeof(*eh))) { 2266*a9643ea8Slogwang txq->ift_pullups++; 2267*a9643ea8Slogwang if (__predict_false((m = m_pullup(m, sizeof(*eh))) == NULL)) 2268*a9643ea8Slogwang return (ENOMEM); 2269*a9643ea8Slogwang } 2270*a9643ea8Slogwang eh = mtod(m, struct ether_vlan_header *); 2271*a9643ea8Slogwang if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 2272*a9643ea8Slogwang pi->ipi_etype = ntohs(eh->evl_proto); 2273*a9643ea8Slogwang pi->ipi_ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 2274*a9643ea8Slogwang } else { 2275*a9643ea8Slogwang pi->ipi_etype = ntohs(eh->evl_encap_proto); 2276*a9643ea8Slogwang pi->ipi_ehdrlen = ETHER_HDR_LEN; 2277*a9643ea8Slogwang } 2278*a9643ea8Slogwang 2279*a9643ea8Slogwang switch (pi->ipi_etype) { 2280*a9643ea8Slogwang #ifdef INET 2281*a9643ea8Slogwang case ETHERTYPE_IP: 2282*a9643ea8Slogwang { 2283*a9643ea8Slogwang struct ip *ip = NULL; 2284*a9643ea8Slogwang struct tcphdr *th = NULL; 2285*a9643ea8Slogwang int minthlen; 2286*a9643ea8Slogwang 2287*a9643ea8Slogwang minthlen = min(m->m_pkthdr.len, pi->ipi_ehdrlen + sizeof(*ip) + sizeof(*th)); 2288*a9643ea8Slogwang if (__predict_false(m->m_len < minthlen)) { 2289*a9643ea8Slogwang /* 2290*a9643ea8Slogwang * if this code bloat is causing too much of a hit 2291*a9643ea8Slogwang * move it to a separate function and mark it noinline 2292*a9643ea8Slogwang */ 2293*a9643ea8Slogwang if (m->m_len == pi->ipi_ehdrlen) { 2294*a9643ea8Slogwang n = m->m_next; 2295*a9643ea8Slogwang MPASS(n); 2296*a9643ea8Slogwang if (n->m_len >= sizeof(*ip)) { 2297*a9643ea8Slogwang ip = (struct ip *)n->m_data; 2298*a9643ea8Slogwang if (n->m_len >= (ip->ip_hl << 2) + sizeof(*th)) 2299*a9643ea8Slogwang th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 2300*a9643ea8Slogwang } else { 2301*a9643ea8Slogwang txq->ift_pullups++; 2302*a9643ea8Slogwang if (__predict_false((m = m_pullup(m, minthlen)) == NULL)) 2303*a9643ea8Slogwang return (ENOMEM); 2304*a9643ea8Slogwang ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen); 2305*a9643ea8Slogwang } 2306*a9643ea8Slogwang } else { 2307*a9643ea8Slogwang txq->ift_pullups++; 2308*a9643ea8Slogwang if (__predict_false((m = m_pullup(m, minthlen)) == NULL)) 2309*a9643ea8Slogwang return (ENOMEM); 2310*a9643ea8Slogwang ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen); 2311*a9643ea8Slogwang if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th)) 2312*a9643ea8Slogwang th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 2313*a9643ea8Slogwang } 2314*a9643ea8Slogwang } else { 2315*a9643ea8Slogwang ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen); 2316*a9643ea8Slogwang if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th)) 2317*a9643ea8Slogwang th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 2318*a9643ea8Slogwang } 2319*a9643ea8Slogwang pi->ipi_ip_hlen = ip->ip_hl << 2; 2320*a9643ea8Slogwang pi->ipi_ipproto = ip->ip_p; 2321*a9643ea8Slogwang pi->ipi_flags |= IPI_TX_IPV4; 2322*a9643ea8Slogwang 2323*a9643ea8Slogwang if (pi->ipi_csum_flags & CSUM_IP) 2324*a9643ea8Slogwang ip->ip_sum = 0; 2325*a9643ea8Slogwang 2326*a9643ea8Slogwang if (pi->ipi_ipproto == IPPROTO_TCP) { 2327*a9643ea8Slogwang if (__predict_false(th == NULL)) { 2328*a9643ea8Slogwang txq->ift_pullups++; 2329*a9643ea8Slogwang if (__predict_false((m = m_pullup(m, (ip->ip_hl << 2) + sizeof(*th))) == NULL)) 2330*a9643ea8Slogwang return (ENOMEM); 2331*a9643ea8Slogwang th = (struct tcphdr *)((caddr_t)ip + pi->ipi_ip_hlen); 2332*a9643ea8Slogwang } 2333*a9643ea8Slogwang pi->ipi_tcp_hflags = th->th_flags; 2334*a9643ea8Slogwang pi->ipi_tcp_hlen = th->th_off << 2; 2335*a9643ea8Slogwang pi->ipi_tcp_seq = th->th_seq; 2336*a9643ea8Slogwang } 2337*a9643ea8Slogwang if (IS_TSO4(pi)) { 2338*a9643ea8Slogwang if (__predict_false(ip->ip_p != IPPROTO_TCP)) 2339*a9643ea8Slogwang return (ENXIO); 2340*a9643ea8Slogwang th->th_sum = in_pseudo(ip->ip_src.s_addr, 2341*a9643ea8Slogwang ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 2342*a9643ea8Slogwang pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz; 2343*a9643ea8Slogwang } 2344*a9643ea8Slogwang break; 2345*a9643ea8Slogwang } 2346*a9643ea8Slogwang #endif 2347*a9643ea8Slogwang #ifdef INET6 2348*a9643ea8Slogwang case ETHERTYPE_IPV6: 2349*a9643ea8Slogwang { 2350*a9643ea8Slogwang struct ip6_hdr *ip6 = (struct ip6_hdr *)(m->m_data + pi->ipi_ehdrlen); 2351*a9643ea8Slogwang struct tcphdr *th; 2352*a9643ea8Slogwang pi->ipi_ip_hlen = sizeof(struct ip6_hdr); 2353*a9643ea8Slogwang 2354*a9643ea8Slogwang if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) { 2355*a9643ea8Slogwang if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) == NULL)) 2356*a9643ea8Slogwang return (ENOMEM); 2357*a9643ea8Slogwang } 2358*a9643ea8Slogwang th = (struct tcphdr *)((caddr_t)ip6 + pi->ipi_ip_hlen); 2359*a9643ea8Slogwang 2360*a9643ea8Slogwang /* XXX-BZ this will go badly in case of ext hdrs. */ 2361*a9643ea8Slogwang pi->ipi_ipproto = ip6->ip6_nxt; 2362*a9643ea8Slogwang pi->ipi_flags |= IPI_TX_IPV6; 2363*a9643ea8Slogwang 2364*a9643ea8Slogwang if (pi->ipi_ipproto == IPPROTO_TCP) { 2365*a9643ea8Slogwang if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) { 2366*a9643ea8Slogwang if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) == NULL)) 2367*a9643ea8Slogwang return (ENOMEM); 2368*a9643ea8Slogwang } 2369*a9643ea8Slogwang pi->ipi_tcp_hflags = th->th_flags; 2370*a9643ea8Slogwang pi->ipi_tcp_hlen = th->th_off << 2; 2371*a9643ea8Slogwang } 2372*a9643ea8Slogwang if (IS_TSO6(pi)) { 2373*a9643ea8Slogwang 2374*a9643ea8Slogwang if (__predict_false(ip6->ip6_nxt != IPPROTO_TCP)) 2375*a9643ea8Slogwang return (ENXIO); 2376*a9643ea8Slogwang /* 2377*a9643ea8Slogwang * The corresponding flag is set by the stack in the IPv4 2378*a9643ea8Slogwang * TSO case, but not in IPv6 (at least in FreeBSD 10.2). 2379*a9643ea8Slogwang * So, set it here because the rest of the flow requires it. 2380*a9643ea8Slogwang */ 2381*a9643ea8Slogwang pi->ipi_csum_flags |= CSUM_TCP_IPV6; 2382*a9643ea8Slogwang th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 2383*a9643ea8Slogwang pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz; 2384*a9643ea8Slogwang } 2385*a9643ea8Slogwang break; 2386*a9643ea8Slogwang } 2387*a9643ea8Slogwang #endif 2388*a9643ea8Slogwang default: 2389*a9643ea8Slogwang pi->ipi_csum_flags &= ~CSUM_OFFLOAD; 2390*a9643ea8Slogwang pi->ipi_ip_hlen = 0; 2391*a9643ea8Slogwang break; 2392*a9643ea8Slogwang } 2393*a9643ea8Slogwang *mp = m; 2394*a9643ea8Slogwang return (0); 2395*a9643ea8Slogwang } 2396*a9643ea8Slogwang 2397*a9643ea8Slogwang 2398*a9643ea8Slogwang static __noinline struct mbuf * 2399*a9643ea8Slogwang collapse_pkthdr(struct mbuf *m0) 2400*a9643ea8Slogwang { 2401*a9643ea8Slogwang struct mbuf *m, *m_next, *tmp; 2402*a9643ea8Slogwang 2403*a9643ea8Slogwang m = m0; 2404*a9643ea8Slogwang m_next = m->m_next; 2405*a9643ea8Slogwang while (m_next != NULL && m_next->m_len == 0) { 2406*a9643ea8Slogwang m = m_next; 2407*a9643ea8Slogwang m->m_next = NULL; 2408*a9643ea8Slogwang m_free(m); 2409*a9643ea8Slogwang m_next = m_next->m_next; 2410*a9643ea8Slogwang } 2411*a9643ea8Slogwang m = m0; 2412*a9643ea8Slogwang m->m_next = m_next; 2413*a9643ea8Slogwang if ((m_next->m_flags & M_EXT) == 0) { 2414*a9643ea8Slogwang m = m_defrag(m, M_NOWAIT); 2415*a9643ea8Slogwang } else { 2416*a9643ea8Slogwang tmp = m_next->m_next; 2417*a9643ea8Slogwang memcpy(m_next, m, MPKTHSIZE); 2418*a9643ea8Slogwang m = m_next; 2419*a9643ea8Slogwang m->m_next = tmp; 2420*a9643ea8Slogwang } 2421*a9643ea8Slogwang return (m); 2422*a9643ea8Slogwang } 2423*a9643ea8Slogwang 2424*a9643ea8Slogwang /* 2425*a9643ea8Slogwang * If dodgy hardware rejects the scatter gather chain we've handed it 2426*a9643ea8Slogwang * we'll need to remove the mbuf chain from ifsg_m[] before we can add the 2427*a9643ea8Slogwang * m_defrag'd mbufs 2428*a9643ea8Slogwang */ 2429*a9643ea8Slogwang static __noinline struct mbuf * 2430*a9643ea8Slogwang iflib_remove_mbuf(iflib_txq_t txq) 2431*a9643ea8Slogwang { 2432*a9643ea8Slogwang int ntxd, i, pidx; 2433*a9643ea8Slogwang struct mbuf *m, *mh, **ifsd_m; 2434*a9643ea8Slogwang 2435*a9643ea8Slogwang pidx = txq->ift_pidx; 2436*a9643ea8Slogwang ifsd_m = txq->ift_sds.ifsd_m; 2437*a9643ea8Slogwang ntxd = txq->ift_size; 2438*a9643ea8Slogwang mh = m = ifsd_m[pidx]; 2439*a9643ea8Slogwang ifsd_m[pidx] = NULL; 2440*a9643ea8Slogwang #if MEMORY_LOGGING 2441*a9643ea8Slogwang txq->ift_dequeued++; 2442*a9643ea8Slogwang #endif 2443*a9643ea8Slogwang i = 1; 2444*a9643ea8Slogwang 2445*a9643ea8Slogwang while (m) { 2446*a9643ea8Slogwang ifsd_m[(pidx + i) & (ntxd -1)] = NULL; 2447*a9643ea8Slogwang #if MEMORY_LOGGING 2448*a9643ea8Slogwang txq->ift_dequeued++; 2449*a9643ea8Slogwang #endif 2450*a9643ea8Slogwang m = m->m_next; 2451*a9643ea8Slogwang i++; 2452*a9643ea8Slogwang } 2453*a9643ea8Slogwang return (mh); 2454*a9643ea8Slogwang } 2455*a9643ea8Slogwang 2456*a9643ea8Slogwang static int 2457*a9643ea8Slogwang iflib_busdma_load_mbuf_sg(iflib_txq_t txq, bus_dma_tag_t tag, bus_dmamap_t map, 2458*a9643ea8Slogwang struct mbuf **m0, bus_dma_segment_t *segs, int *nsegs, 2459*a9643ea8Slogwang int max_segs, int flags) 2460*a9643ea8Slogwang { 2461*a9643ea8Slogwang if_ctx_t ctx; 2462*a9643ea8Slogwang if_shared_ctx_t sctx; 2463*a9643ea8Slogwang if_softc_ctx_t scctx; 2464*a9643ea8Slogwang int i, next, pidx, mask, err, maxsegsz, ntxd, count; 2465*a9643ea8Slogwang struct mbuf *m, *tmp, **ifsd_m, **mp; 2466*a9643ea8Slogwang 2467*a9643ea8Slogwang m = *m0; 2468*a9643ea8Slogwang 2469*a9643ea8Slogwang /* 2470*a9643ea8Slogwang * Please don't ever do this 2471*a9643ea8Slogwang */ 2472*a9643ea8Slogwang if (__predict_false(m->m_len == 0)) 2473*a9643ea8Slogwang *m0 = m = collapse_pkthdr(m); 2474*a9643ea8Slogwang 2475*a9643ea8Slogwang ctx = txq->ift_ctx; 2476*a9643ea8Slogwang sctx = ctx->ifc_sctx; 2477*a9643ea8Slogwang scctx = &ctx->ifc_softc_ctx; 2478*a9643ea8Slogwang ifsd_m = txq->ift_sds.ifsd_m; 2479*a9643ea8Slogwang ntxd = txq->ift_size; 2480*a9643ea8Slogwang pidx = txq->ift_pidx; 2481*a9643ea8Slogwang if (map != NULL) { 2482*a9643ea8Slogwang uint8_t *ifsd_flags = txq->ift_sds.ifsd_flags; 2483*a9643ea8Slogwang 2484*a9643ea8Slogwang err = bus_dmamap_load_mbuf_sg(tag, map, 2485*a9643ea8Slogwang *m0, segs, nsegs, BUS_DMA_NOWAIT); 2486*a9643ea8Slogwang if (err) 2487*a9643ea8Slogwang return (err); 2488*a9643ea8Slogwang ifsd_flags[pidx] |= TX_SW_DESC_MAPPED; 2489*a9643ea8Slogwang i = 0; 2490*a9643ea8Slogwang next = pidx; 2491*a9643ea8Slogwang mask = (txq->ift_size-1); 2492*a9643ea8Slogwang m = *m0; 2493*a9643ea8Slogwang do { 2494*a9643ea8Slogwang mp = &ifsd_m[next]; 2495*a9643ea8Slogwang *mp = m; 2496*a9643ea8Slogwang m = m->m_next; 2497*a9643ea8Slogwang if (__predict_false((*mp)->m_len == 0)) { 2498*a9643ea8Slogwang m_free(*mp); 2499*a9643ea8Slogwang *mp = NULL; 2500*a9643ea8Slogwang } else 2501*a9643ea8Slogwang next = (pidx + i) & (ntxd-1); 2502*a9643ea8Slogwang } while (m != NULL); 2503*a9643ea8Slogwang } else { 2504*a9643ea8Slogwang int buflen, sgsize, max_sgsize; 2505*a9643ea8Slogwang vm_offset_t vaddr; 2506*a9643ea8Slogwang vm_paddr_t curaddr; 2507*a9643ea8Slogwang 2508*a9643ea8Slogwang count = i = 0; 2509*a9643ea8Slogwang maxsegsz = sctx->isc_tx_maxsize; 2510*a9643ea8Slogwang m = *m0; 2511*a9643ea8Slogwang do { 2512*a9643ea8Slogwang if (__predict_false(m->m_len <= 0)) { 2513*a9643ea8Slogwang tmp = m; 2514*a9643ea8Slogwang m = m->m_next; 2515*a9643ea8Slogwang tmp->m_next = NULL; 2516*a9643ea8Slogwang m_free(tmp); 2517*a9643ea8Slogwang continue; 2518*a9643ea8Slogwang } 2519*a9643ea8Slogwang buflen = m->m_len; 2520*a9643ea8Slogwang vaddr = (vm_offset_t)m->m_data; 2521*a9643ea8Slogwang /* 2522*a9643ea8Slogwang * see if we can't be smarter about physically 2523*a9643ea8Slogwang * contiguous mappings 2524*a9643ea8Slogwang */ 2525*a9643ea8Slogwang next = (pidx + count) & (ntxd-1); 2526*a9643ea8Slogwang MPASS(ifsd_m[next] == NULL); 2527*a9643ea8Slogwang #if MEMORY_LOGGING 2528*a9643ea8Slogwang txq->ift_enqueued++; 2529*a9643ea8Slogwang #endif 2530*a9643ea8Slogwang ifsd_m[next] = m; 2531*a9643ea8Slogwang while (buflen > 0) { 2532*a9643ea8Slogwang max_sgsize = MIN(buflen, maxsegsz); 2533*a9643ea8Slogwang curaddr = pmap_kextract(vaddr); 2534*a9643ea8Slogwang sgsize = PAGE_SIZE - (curaddr & PAGE_MASK); 2535*a9643ea8Slogwang sgsize = MIN(sgsize, max_sgsize); 2536*a9643ea8Slogwang segs[i].ds_addr = curaddr; 2537*a9643ea8Slogwang segs[i].ds_len = sgsize; 2538*a9643ea8Slogwang vaddr += sgsize; 2539*a9643ea8Slogwang buflen -= sgsize; 2540*a9643ea8Slogwang i++; 2541*a9643ea8Slogwang if (i >= max_segs) 2542*a9643ea8Slogwang goto err; 2543*a9643ea8Slogwang } 2544*a9643ea8Slogwang count++; 2545*a9643ea8Slogwang tmp = m; 2546*a9643ea8Slogwang m = m->m_next; 2547*a9643ea8Slogwang } while (m != NULL); 2548*a9643ea8Slogwang *nsegs = i; 2549*a9643ea8Slogwang } 2550*a9643ea8Slogwang return (0); 2551*a9643ea8Slogwang err: 2552*a9643ea8Slogwang *m0 = iflib_remove_mbuf(txq); 2553*a9643ea8Slogwang return (EFBIG); 2554*a9643ea8Slogwang } 2555*a9643ea8Slogwang 2556*a9643ea8Slogwang static int 2557*a9643ea8Slogwang iflib_encap(iflib_txq_t txq, struct mbuf **m_headp) 2558*a9643ea8Slogwang { 2559*a9643ea8Slogwang if_ctx_t ctx; 2560*a9643ea8Slogwang if_shared_ctx_t sctx; 2561*a9643ea8Slogwang if_softc_ctx_t scctx; 2562*a9643ea8Slogwang bus_dma_segment_t *segs; 2563*a9643ea8Slogwang struct mbuf *m_head; 2564*a9643ea8Slogwang bus_dmamap_t map; 2565*a9643ea8Slogwang struct if_pkt_info pi; 2566*a9643ea8Slogwang int remap = 0; 2567*a9643ea8Slogwang int err, nsegs, ndesc, max_segs, pidx, cidx, next, ntxd; 2568*a9643ea8Slogwang bus_dma_tag_t desc_tag; 2569*a9643ea8Slogwang 2570*a9643ea8Slogwang segs = txq->ift_segs; 2571*a9643ea8Slogwang ctx = txq->ift_ctx; 2572*a9643ea8Slogwang sctx = ctx->ifc_sctx; 2573*a9643ea8Slogwang scctx = &ctx->ifc_softc_ctx; 2574*a9643ea8Slogwang segs = txq->ift_segs; 2575*a9643ea8Slogwang ntxd = txq->ift_size; 2576*a9643ea8Slogwang m_head = *m_headp; 2577*a9643ea8Slogwang map = NULL; 2578*a9643ea8Slogwang 2579*a9643ea8Slogwang /* 2580*a9643ea8Slogwang * If we're doing TSO the next descriptor to clean may be quite far ahead 2581*a9643ea8Slogwang */ 2582*a9643ea8Slogwang cidx = txq->ift_cidx; 2583*a9643ea8Slogwang pidx = txq->ift_pidx; 2584*a9643ea8Slogwang next = (cidx + CACHE_PTR_INCREMENT) & (ntxd-1); 2585*a9643ea8Slogwang 2586*a9643ea8Slogwang /* prefetch the next cache line of mbuf pointers and flags */ 2587*a9643ea8Slogwang prefetch(&txq->ift_sds.ifsd_m[next]); 2588*a9643ea8Slogwang if (txq->ift_sds.ifsd_map != NULL) { 2589*a9643ea8Slogwang prefetch(&txq->ift_sds.ifsd_map[next]); 2590*a9643ea8Slogwang map = txq->ift_sds.ifsd_map[pidx]; 2591*a9643ea8Slogwang next = (cidx + CACHE_LINE_SIZE) & (ntxd-1); 2592*a9643ea8Slogwang prefetch(&txq->ift_sds.ifsd_flags[next]); 2593*a9643ea8Slogwang } 2594*a9643ea8Slogwang 2595*a9643ea8Slogwang 2596*a9643ea8Slogwang if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 2597*a9643ea8Slogwang desc_tag = txq->ift_tso_desc_tag; 2598*a9643ea8Slogwang max_segs = scctx->isc_tx_tso_segments_max; 2599*a9643ea8Slogwang } else { 2600*a9643ea8Slogwang desc_tag = txq->ift_desc_tag; 2601*a9643ea8Slogwang max_segs = scctx->isc_tx_nsegments; 2602*a9643ea8Slogwang } 2603*a9643ea8Slogwang m_head = *m_headp; 2604*a9643ea8Slogwang bzero(&pi, sizeof(pi)); 2605*a9643ea8Slogwang pi.ipi_len = m_head->m_pkthdr.len; 2606*a9643ea8Slogwang pi.ipi_mflags = (m_head->m_flags & (M_VLANTAG|M_BCAST|M_MCAST)); 2607*a9643ea8Slogwang pi.ipi_csum_flags = m_head->m_pkthdr.csum_flags; 2608*a9643ea8Slogwang pi.ipi_vtag = (m_head->m_flags & M_VLANTAG) ? m_head->m_pkthdr.ether_vtag : 0; 2609*a9643ea8Slogwang pi.ipi_pidx = pidx; 2610*a9643ea8Slogwang pi.ipi_qsidx = txq->ift_id; 2611*a9643ea8Slogwang 2612*a9643ea8Slogwang /* deliberate bitwise OR to make one condition */ 2613*a9643ea8Slogwang if (__predict_true((pi.ipi_csum_flags | pi.ipi_vtag))) { 2614*a9643ea8Slogwang if (__predict_false((err = iflib_parse_header(txq, &pi, m_headp)) != 0)) 2615*a9643ea8Slogwang return (err); 2616*a9643ea8Slogwang m_head = *m_headp; 2617*a9643ea8Slogwang } 2618*a9643ea8Slogwang 2619*a9643ea8Slogwang retry: 2620*a9643ea8Slogwang err = iflib_busdma_load_mbuf_sg(txq, desc_tag, map, m_headp, segs, &nsegs, max_segs, BUS_DMA_NOWAIT); 2621*a9643ea8Slogwang defrag: 2622*a9643ea8Slogwang if (__predict_false(err)) { 2623*a9643ea8Slogwang switch (err) { 2624*a9643ea8Slogwang case EFBIG: 2625*a9643ea8Slogwang /* try collapse once and defrag once */ 2626*a9643ea8Slogwang if (remap == 0) 2627*a9643ea8Slogwang m_head = m_collapse(*m_headp, M_NOWAIT, max_segs); 2628*a9643ea8Slogwang if (remap == 1) 2629*a9643ea8Slogwang m_head = m_defrag(*m_headp, M_NOWAIT); 2630*a9643ea8Slogwang remap++; 2631*a9643ea8Slogwang if (__predict_false(m_head == NULL)) 2632*a9643ea8Slogwang goto defrag_failed; 2633*a9643ea8Slogwang txq->ift_mbuf_defrag++; 2634*a9643ea8Slogwang *m_headp = m_head; 2635*a9643ea8Slogwang goto retry; 2636*a9643ea8Slogwang break; 2637*a9643ea8Slogwang case ENOMEM: 2638*a9643ea8Slogwang txq->ift_no_tx_dma_setup++; 2639*a9643ea8Slogwang break; 2640*a9643ea8Slogwang default: 2641*a9643ea8Slogwang txq->ift_no_tx_dma_setup++; 2642*a9643ea8Slogwang m_freem(*m_headp); 2643*a9643ea8Slogwang DBG_COUNTER_INC(tx_frees); 2644*a9643ea8Slogwang *m_headp = NULL; 2645*a9643ea8Slogwang break; 2646*a9643ea8Slogwang } 2647*a9643ea8Slogwang txq->ift_map_failed++; 2648*a9643ea8Slogwang DBG_COUNTER_INC(encap_load_mbuf_fail); 2649*a9643ea8Slogwang return (err); 2650*a9643ea8Slogwang } 2651*a9643ea8Slogwang 2652*a9643ea8Slogwang /* 2653*a9643ea8Slogwang * XXX assumes a 1 to 1 relationship between segments and 2654*a9643ea8Slogwang * descriptors - this does not hold true on all drivers, e.g. 2655*a9643ea8Slogwang * cxgb 2656*a9643ea8Slogwang */ 2657*a9643ea8Slogwang if (__predict_false(nsegs + 2 > TXQ_AVAIL(txq))) { 2658*a9643ea8Slogwang txq->ift_no_desc_avail++; 2659*a9643ea8Slogwang if (map != NULL) 2660*a9643ea8Slogwang bus_dmamap_unload(desc_tag, map); 2661*a9643ea8Slogwang DBG_COUNTER_INC(encap_txq_avail_fail); 2662*a9643ea8Slogwang if ((txq->ift_task.gt_task.ta_flags & TASK_ENQUEUED) == 0) 2663*a9643ea8Slogwang GROUPTASK_ENQUEUE(&txq->ift_task); 2664*a9643ea8Slogwang return (ENOBUFS); 2665*a9643ea8Slogwang } 2666*a9643ea8Slogwang pi.ipi_segs = segs; 2667*a9643ea8Slogwang pi.ipi_nsegs = nsegs; 2668*a9643ea8Slogwang 2669*a9643ea8Slogwang MPASS(pidx >= 0 && pidx < txq->ift_size); 2670*a9643ea8Slogwang #ifdef PKT_DEBUG 2671*a9643ea8Slogwang print_pkt(&pi); 2672*a9643ea8Slogwang #endif 2673*a9643ea8Slogwang if ((err = ctx->isc_txd_encap(ctx->ifc_softc, &pi)) == 0) { 2674*a9643ea8Slogwang bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map, 2675*a9643ea8Slogwang BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2676*a9643ea8Slogwang 2677*a9643ea8Slogwang DBG_COUNTER_INC(tx_encap); 2678*a9643ea8Slogwang MPASS(pi.ipi_new_pidx >= 0 && 2679*a9643ea8Slogwang pi.ipi_new_pidx < txq->ift_size); 2680*a9643ea8Slogwang 2681*a9643ea8Slogwang ndesc = pi.ipi_new_pidx - pi.ipi_pidx; 2682*a9643ea8Slogwang if (pi.ipi_new_pidx < pi.ipi_pidx) { 2683*a9643ea8Slogwang ndesc += txq->ift_size; 2684*a9643ea8Slogwang txq->ift_gen = 1; 2685*a9643ea8Slogwang } 2686*a9643ea8Slogwang MPASS(pi.ipi_new_pidx != pidx); 2687*a9643ea8Slogwang MPASS(ndesc > 0); 2688*a9643ea8Slogwang txq->ift_in_use += ndesc; 2689*a9643ea8Slogwang /* 2690*a9643ea8Slogwang * We update the last software descriptor again here because there may 2691*a9643ea8Slogwang * be a sentinel and/or there may be more mbufs than segments 2692*a9643ea8Slogwang */ 2693*a9643ea8Slogwang txq->ift_pidx = pi.ipi_new_pidx; 2694*a9643ea8Slogwang txq->ift_npending += pi.ipi_ndescs; 2695*a9643ea8Slogwang } else if (__predict_false(err == EFBIG && remap < 2)) { 2696*a9643ea8Slogwang *m_headp = m_head = iflib_remove_mbuf(txq); 2697*a9643ea8Slogwang remap = 1; 2698*a9643ea8Slogwang txq->ift_txd_encap_efbig++; 2699*a9643ea8Slogwang goto defrag; 2700*a9643ea8Slogwang } else 2701*a9643ea8Slogwang DBG_COUNTER_INC(encap_txd_encap_fail); 2702*a9643ea8Slogwang return (err); 2703*a9643ea8Slogwang 2704*a9643ea8Slogwang defrag_failed: 2705*a9643ea8Slogwang txq->ift_mbuf_defrag_failed++; 2706*a9643ea8Slogwang txq->ift_map_failed++; 2707*a9643ea8Slogwang m_freem(*m_headp); 2708*a9643ea8Slogwang DBG_COUNTER_INC(tx_frees); 2709*a9643ea8Slogwang *m_headp = NULL; 2710*a9643ea8Slogwang return (ENOMEM); 2711*a9643ea8Slogwang } 2712*a9643ea8Slogwang 2713*a9643ea8Slogwang /* forward compatibility for cxgb */ 2714*a9643ea8Slogwang #define FIRST_QSET(ctx) 0 2715*a9643ea8Slogwang 2716*a9643ea8Slogwang #define NTXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_ntxqsets) 2717*a9643ea8Slogwang #define NRXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_nrxqsets) 2718*a9643ea8Slogwang #define QIDX(ctx, m) ((((m)->m_pkthdr.flowid & ctx->ifc_softc_ctx.isc_rss_table_mask) % NTXQSETS(ctx)) + FIRST_QSET(ctx)) 2719*a9643ea8Slogwang #define DESC_RECLAIMABLE(q) ((int)((q)->ift_processed - (q)->ift_cleaned - (q)->ift_ctx->ifc_softc_ctx.isc_tx_nsegments)) 2720*a9643ea8Slogwang #define RECLAIM_THRESH(ctx) ((ctx)->ifc_sctx->isc_tx_reclaim_thresh) 2721*a9643ea8Slogwang #define MAX_TX_DESC(ctx) ((ctx)->ifc_softc_ctx.isc_tx_tso_segments_max) 2722*a9643ea8Slogwang 2723*a9643ea8Slogwang 2724*a9643ea8Slogwang 2725*a9643ea8Slogwang /* if there are more than TXQ_MIN_OCCUPANCY packets pending we consider deferring 2726*a9643ea8Slogwang * doorbell writes 2727*a9643ea8Slogwang * 2728*a9643ea8Slogwang * ORing with 2 assures that min occupancy is never less than 2 without any conditional logic 2729*a9643ea8Slogwang */ 2730*a9643ea8Slogwang #define TXQ_MIN_OCCUPANCY(size) ((size >> 6)| 0x2) 2731*a9643ea8Slogwang 2732*a9643ea8Slogwang static inline int 2733*a9643ea8Slogwang iflib_txq_min_occupancy(iflib_txq_t txq) 2734*a9643ea8Slogwang { 2735*a9643ea8Slogwang if_ctx_t ctx; 2736*a9643ea8Slogwang 2737*a9643ea8Slogwang ctx = txq->ift_ctx; 2738*a9643ea8Slogwang return (get_inuse(txq->ift_size, txq->ift_cidx, txq->ift_pidx, 2739*a9643ea8Slogwang txq->ift_gen) < TXQ_MIN_OCCUPANCY(txq->ift_size) + 2740*a9643ea8Slogwang MAX_TX_DESC(ctx)); 2741*a9643ea8Slogwang } 2742*a9643ea8Slogwang 2743*a9643ea8Slogwang static void 2744*a9643ea8Slogwang iflib_tx_desc_free(iflib_txq_t txq, int n) 2745*a9643ea8Slogwang { 2746*a9643ea8Slogwang int hasmap; 2747*a9643ea8Slogwang uint32_t qsize, cidx, mask, gen; 2748*a9643ea8Slogwang struct mbuf *m, **ifsd_m; 2749*a9643ea8Slogwang uint8_t *ifsd_flags; 2750*a9643ea8Slogwang bus_dmamap_t *ifsd_map; 2751*a9643ea8Slogwang 2752*a9643ea8Slogwang cidx = txq->ift_cidx; 2753*a9643ea8Slogwang gen = txq->ift_gen; 2754*a9643ea8Slogwang qsize = txq->ift_size; 2755*a9643ea8Slogwang mask = qsize-1; 2756*a9643ea8Slogwang hasmap = txq->ift_sds.ifsd_map != NULL; 2757*a9643ea8Slogwang ifsd_flags = txq->ift_sds.ifsd_flags; 2758*a9643ea8Slogwang ifsd_m = txq->ift_sds.ifsd_m; 2759*a9643ea8Slogwang ifsd_map = txq->ift_sds.ifsd_map; 2760*a9643ea8Slogwang 2761*a9643ea8Slogwang while (n--) { 2762*a9643ea8Slogwang prefetch(ifsd_m[(cidx + 3) & mask]); 2763*a9643ea8Slogwang prefetch(ifsd_m[(cidx + 4) & mask]); 2764*a9643ea8Slogwang 2765*a9643ea8Slogwang if (ifsd_m[cidx] != NULL) { 2766*a9643ea8Slogwang prefetch(&ifsd_m[(cidx + CACHE_PTR_INCREMENT) & mask]); 2767*a9643ea8Slogwang prefetch(&ifsd_flags[(cidx + CACHE_PTR_INCREMENT) & mask]); 2768*a9643ea8Slogwang if (hasmap && (ifsd_flags[cidx] & TX_SW_DESC_MAPPED)) { 2769*a9643ea8Slogwang /* 2770*a9643ea8Slogwang * does it matter if it's not the TSO tag? If so we'll 2771*a9643ea8Slogwang * have to add the type to flags 2772*a9643ea8Slogwang */ 2773*a9643ea8Slogwang bus_dmamap_unload(txq->ift_desc_tag, ifsd_map[cidx]); 2774*a9643ea8Slogwang ifsd_flags[cidx] &= ~TX_SW_DESC_MAPPED; 2775*a9643ea8Slogwang } 2776*a9643ea8Slogwang if ((m = ifsd_m[cidx]) != NULL) { 2777*a9643ea8Slogwang /* XXX we don't support any drivers that batch packets yet */ 2778*a9643ea8Slogwang MPASS(m->m_nextpkt == NULL); 2779*a9643ea8Slogwang 2780*a9643ea8Slogwang m_free(m); 2781*a9643ea8Slogwang ifsd_m[cidx] = NULL; 2782*a9643ea8Slogwang #if MEMORY_LOGGING 2783*a9643ea8Slogwang txq->ift_dequeued++; 2784*a9643ea8Slogwang #endif 2785*a9643ea8Slogwang DBG_COUNTER_INC(tx_frees); 2786*a9643ea8Slogwang } 2787*a9643ea8Slogwang } 2788*a9643ea8Slogwang if (__predict_false(++cidx == qsize)) { 2789*a9643ea8Slogwang cidx = 0; 2790*a9643ea8Slogwang gen = 0; 2791*a9643ea8Slogwang } 2792*a9643ea8Slogwang } 2793*a9643ea8Slogwang txq->ift_cidx = cidx; 2794*a9643ea8Slogwang txq->ift_gen = gen; 2795*a9643ea8Slogwang } 2796*a9643ea8Slogwang 2797*a9643ea8Slogwang static __inline int 2798*a9643ea8Slogwang iflib_completed_tx_reclaim(iflib_txq_t txq, int thresh) 2799*a9643ea8Slogwang { 2800*a9643ea8Slogwang int reclaim; 2801*a9643ea8Slogwang if_ctx_t ctx = txq->ift_ctx; 2802*a9643ea8Slogwang 2803*a9643ea8Slogwang KASSERT(thresh >= 0, ("invalid threshold to reclaim")); 2804*a9643ea8Slogwang MPASS(thresh /*+ MAX_TX_DESC(txq->ift_ctx) */ < txq->ift_size); 2805*a9643ea8Slogwang 2806*a9643ea8Slogwang /* 2807*a9643ea8Slogwang * Need a rate-limiting check so that this isn't called every time 2808*a9643ea8Slogwang */ 2809*a9643ea8Slogwang iflib_tx_credits_update(ctx, txq); 2810*a9643ea8Slogwang reclaim = DESC_RECLAIMABLE(txq); 2811*a9643ea8Slogwang 2812*a9643ea8Slogwang if (reclaim <= thresh /* + MAX_TX_DESC(txq->ift_ctx) */) { 2813*a9643ea8Slogwang #ifdef INVARIANTS 2814*a9643ea8Slogwang if (iflib_verbose_debug) { 2815*a9643ea8Slogwang printf("%s processed=%ju cleaned=%ju tx_nsegments=%d reclaim=%d thresh=%d\n", __FUNCTION__, 2816*a9643ea8Slogwang txq->ift_processed, txq->ift_cleaned, txq->ift_ctx->ifc_softc_ctx.isc_tx_nsegments, 2817*a9643ea8Slogwang reclaim, thresh); 2818*a9643ea8Slogwang 2819*a9643ea8Slogwang } 2820*a9643ea8Slogwang #endif 2821*a9643ea8Slogwang return (0); 2822*a9643ea8Slogwang } 2823*a9643ea8Slogwang iflib_tx_desc_free(txq, reclaim); 2824*a9643ea8Slogwang txq->ift_cleaned += reclaim; 2825*a9643ea8Slogwang txq->ift_in_use -= reclaim; 2826*a9643ea8Slogwang 2827*a9643ea8Slogwang if (txq->ift_active == FALSE) 2828*a9643ea8Slogwang txq->ift_active = TRUE; 2829*a9643ea8Slogwang 2830*a9643ea8Slogwang return (reclaim); 2831*a9643ea8Slogwang } 2832*a9643ea8Slogwang 2833*a9643ea8Slogwang static struct mbuf ** 2834*a9643ea8Slogwang _ring_peek_one(struct ifmp_ring *r, int cidx, int offset) 2835*a9643ea8Slogwang { 2836*a9643ea8Slogwang 2837*a9643ea8Slogwang return (__DEVOLATILE(struct mbuf **, &r->items[(cidx + offset) & (r->size-1)])); 2838*a9643ea8Slogwang } 2839*a9643ea8Slogwang 2840*a9643ea8Slogwang static void 2841*a9643ea8Slogwang iflib_txq_check_drain(iflib_txq_t txq, int budget) 2842*a9643ea8Slogwang { 2843*a9643ea8Slogwang 2844*a9643ea8Slogwang ifmp_ring_check_drainage(txq->ift_br[0], budget); 2845*a9643ea8Slogwang } 2846*a9643ea8Slogwang 2847*a9643ea8Slogwang static uint32_t 2848*a9643ea8Slogwang iflib_txq_can_drain(struct ifmp_ring *r) 2849*a9643ea8Slogwang { 2850*a9643ea8Slogwang iflib_txq_t txq = r->cookie; 2851*a9643ea8Slogwang if_ctx_t ctx = txq->ift_ctx; 2852*a9643ea8Slogwang 2853*a9643ea8Slogwang return ((TXQ_AVAIL(txq) >= MAX_TX_DESC(ctx)) || 2854*a9643ea8Slogwang ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, txq->ift_cidx_processed, false)); 2855*a9643ea8Slogwang } 2856*a9643ea8Slogwang 2857*a9643ea8Slogwang static uint32_t 2858*a9643ea8Slogwang iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) 2859*a9643ea8Slogwang { 2860*a9643ea8Slogwang iflib_txq_t txq = r->cookie; 2861*a9643ea8Slogwang if_ctx_t ctx = txq->ift_ctx; 2862*a9643ea8Slogwang if_t ifp = ctx->ifc_ifp; 2863*a9643ea8Slogwang struct mbuf **mp, *m; 2864*a9643ea8Slogwang int i, count, consumed, pkt_sent, bytes_sent, mcast_sent, avail, err, in_use_prev, desc_used; 2865*a9643ea8Slogwang 2866*a9643ea8Slogwang if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING) || 2867*a9643ea8Slogwang !LINK_ACTIVE(ctx))) { 2868*a9643ea8Slogwang DBG_COUNTER_INC(txq_drain_notready); 2869*a9643ea8Slogwang return (0); 2870*a9643ea8Slogwang } 2871*a9643ea8Slogwang 2872*a9643ea8Slogwang avail = IDXDIFF(pidx, cidx, r->size); 2873*a9643ea8Slogwang if (__predict_false(ctx->ifc_flags & IFC_QFLUSH)) { 2874*a9643ea8Slogwang DBG_COUNTER_INC(txq_drain_flushing); 2875*a9643ea8Slogwang for (i = 0; i < avail; i++) { 2876*a9643ea8Slogwang m_free(r->items[(cidx + i) & (r->size-1)]); 2877*a9643ea8Slogwang r->items[(cidx + i) & (r->size-1)] = NULL; 2878*a9643ea8Slogwang } 2879*a9643ea8Slogwang return (avail); 2880*a9643ea8Slogwang } 2881*a9643ea8Slogwang iflib_completed_tx_reclaim(txq, RECLAIM_THRESH(ctx)); 2882*a9643ea8Slogwang if (__predict_false(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE)) { 2883*a9643ea8Slogwang txq->ift_qstatus = IFLIB_QUEUE_IDLE; 2884*a9643ea8Slogwang CALLOUT_LOCK(txq); 2885*a9643ea8Slogwang callout_stop(&txq->ift_timer); 2886*a9643ea8Slogwang callout_stop(&txq->ift_db_check); 2887*a9643ea8Slogwang CALLOUT_UNLOCK(txq); 2888*a9643ea8Slogwang DBG_COUNTER_INC(txq_drain_oactive); 2889*a9643ea8Slogwang return (0); 2890*a9643ea8Slogwang } 2891*a9643ea8Slogwang consumed = mcast_sent = bytes_sent = pkt_sent = 0; 2892*a9643ea8Slogwang count = MIN(avail, TX_BATCH_SIZE); 2893*a9643ea8Slogwang 2894*a9643ea8Slogwang for (desc_used = i = 0; i < count && TXQ_AVAIL(txq) > MAX_TX_DESC(ctx) + 2; i++) { 2895*a9643ea8Slogwang mp = _ring_peek_one(r, cidx, i); 2896*a9643ea8Slogwang in_use_prev = txq->ift_in_use; 2897*a9643ea8Slogwang err = iflib_encap(txq, mp); 2898*a9643ea8Slogwang /* 2899*a9643ea8Slogwang * What other errors should we bail out for? 2900*a9643ea8Slogwang */ 2901*a9643ea8Slogwang if (err == ENOBUFS) { 2902*a9643ea8Slogwang DBG_COUNTER_INC(txq_drain_encapfail); 2903*a9643ea8Slogwang break; 2904*a9643ea8Slogwang } 2905*a9643ea8Slogwang consumed++; 2906*a9643ea8Slogwang if (err) 2907*a9643ea8Slogwang continue; 2908*a9643ea8Slogwang 2909*a9643ea8Slogwang pkt_sent++; 2910*a9643ea8Slogwang m = *mp; 2911*a9643ea8Slogwang DBG_COUNTER_INC(tx_sent); 2912*a9643ea8Slogwang bytes_sent += m->m_pkthdr.len; 2913*a9643ea8Slogwang if (m->m_flags & M_MCAST) 2914*a9643ea8Slogwang mcast_sent++; 2915*a9643ea8Slogwang 2916*a9643ea8Slogwang txq->ift_db_pending += (txq->ift_in_use - in_use_prev); 2917*a9643ea8Slogwang desc_used += (txq->ift_in_use - in_use_prev); 2918*a9643ea8Slogwang iflib_txd_db_check(ctx, txq, FALSE); 2919*a9643ea8Slogwang ETHER_BPF_MTAP(ifp, m); 2920*a9643ea8Slogwang if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))) 2921*a9643ea8Slogwang break; 2922*a9643ea8Slogwang 2923*a9643ea8Slogwang if (desc_used > TXQ_MAX_DB_CONSUMED(txq->ift_size)) 2924*a9643ea8Slogwang break; 2925*a9643ea8Slogwang } 2926*a9643ea8Slogwang 2927*a9643ea8Slogwang if ((iflib_min_tx_latency || iflib_txq_min_occupancy(txq)) && txq->ift_db_pending) 2928*a9643ea8Slogwang iflib_txd_db_check(ctx, txq, TRUE); 2929*a9643ea8Slogwang else if ((txq->ift_db_pending || TXQ_AVAIL(txq) < MAX_TX_DESC(ctx)) && 2930*a9643ea8Slogwang (callout_pending(&txq->ift_db_check) == 0)) { 2931*a9643ea8Slogwang txq->ift_db_pending_queued = txq->ift_db_pending; 2932*a9643ea8Slogwang callout_reset_on(&txq->ift_db_check, 1, iflib_txd_deferred_db_check, 2933*a9643ea8Slogwang txq, txq->ift_db_check.c_cpu); 2934*a9643ea8Slogwang } 2935*a9643ea8Slogwang if_inc_counter(ifp, IFCOUNTER_OBYTES, bytes_sent); 2936*a9643ea8Slogwang if_inc_counter(ifp, IFCOUNTER_OPACKETS, pkt_sent); 2937*a9643ea8Slogwang if (mcast_sent) 2938*a9643ea8Slogwang if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast_sent); 2939*a9643ea8Slogwang 2940*a9643ea8Slogwang return (consumed); 2941*a9643ea8Slogwang } 2942*a9643ea8Slogwang 2943*a9643ea8Slogwang static void 2944*a9643ea8Slogwang _task_fn_tx(void *context) 2945*a9643ea8Slogwang { 2946*a9643ea8Slogwang iflib_txq_t txq = context; 2947*a9643ea8Slogwang if_ctx_t ctx = txq->ift_ctx; 2948*a9643ea8Slogwang 2949*a9643ea8Slogwang if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) 2950*a9643ea8Slogwang return; 2951*a9643ea8Slogwang ifmp_ring_check_drainage(txq->ift_br[0], TX_BATCH_SIZE); 2952*a9643ea8Slogwang } 2953*a9643ea8Slogwang 2954*a9643ea8Slogwang static void 2955*a9643ea8Slogwang _task_fn_rx(void *context) 2956*a9643ea8Slogwang { 2957*a9643ea8Slogwang iflib_rxq_t rxq = context; 2958*a9643ea8Slogwang if_ctx_t ctx = rxq->ifr_ctx; 2959*a9643ea8Slogwang bool more; 2960*a9643ea8Slogwang int rc; 2961*a9643ea8Slogwang 2962*a9643ea8Slogwang DBG_COUNTER_INC(task_fn_rxs); 2963*a9643ea8Slogwang if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))) 2964*a9643ea8Slogwang return; 2965*a9643ea8Slogwang 2966*a9643ea8Slogwang if ((more = iflib_rxeof(rxq, 16 /* XXX */)) == false) { 2967*a9643ea8Slogwang if (ctx->ifc_flags & IFC_LEGACY) 2968*a9643ea8Slogwang IFDI_INTR_ENABLE(ctx); 2969*a9643ea8Slogwang else { 2970*a9643ea8Slogwang DBG_COUNTER_INC(rx_intr_enables); 2971*a9643ea8Slogwang rc = IFDI_QUEUE_INTR_ENABLE(ctx, rxq->ifr_id); 2972*a9643ea8Slogwang KASSERT(rc != ENOTSUP, ("MSI-X support requires queue_intr_enable, but not implemented in driver")); 2973*a9643ea8Slogwang } 2974*a9643ea8Slogwang } 2975*a9643ea8Slogwang if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))) 2976*a9643ea8Slogwang return; 2977*a9643ea8Slogwang if (more) 2978*a9643ea8Slogwang GROUPTASK_ENQUEUE(&rxq->ifr_task); 2979*a9643ea8Slogwang } 2980*a9643ea8Slogwang 2981*a9643ea8Slogwang static void 2982*a9643ea8Slogwang _task_fn_admin(void *context) 2983*a9643ea8Slogwang { 2984*a9643ea8Slogwang if_ctx_t ctx = context; 2985*a9643ea8Slogwang if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; 2986*a9643ea8Slogwang iflib_txq_t txq; 2987*a9643ea8Slogwang int i; 2988*a9643ea8Slogwang 2989*a9643ea8Slogwang if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) 2990*a9643ea8Slogwang return; 2991*a9643ea8Slogwang 2992*a9643ea8Slogwang CTX_LOCK(ctx); 2993*a9643ea8Slogwang for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) { 2994*a9643ea8Slogwang CALLOUT_LOCK(txq); 2995*a9643ea8Slogwang callout_stop(&txq->ift_timer); 2996*a9643ea8Slogwang CALLOUT_UNLOCK(txq); 2997*a9643ea8Slogwang } 2998*a9643ea8Slogwang IFDI_UPDATE_ADMIN_STATUS(ctx); 2999*a9643ea8Slogwang for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) 3000*a9643ea8Slogwang callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, txq, txq->ift_timer.c_cpu); 3001*a9643ea8Slogwang IFDI_LINK_INTR_ENABLE(ctx); 3002*a9643ea8Slogwang CTX_UNLOCK(ctx); 3003*a9643ea8Slogwang 3004*a9643ea8Slogwang if (LINK_ACTIVE(ctx) == 0) 3005*a9643ea8Slogwang return; 3006*a9643ea8Slogwang for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) 3007*a9643ea8Slogwang iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET); 3008*a9643ea8Slogwang } 3009*a9643ea8Slogwang 3010*a9643ea8Slogwang 3011*a9643ea8Slogwang static void 3012*a9643ea8Slogwang _task_fn_iov(void *context) 3013*a9643ea8Slogwang { 3014*a9643ea8Slogwang if_ctx_t ctx = context; 3015*a9643ea8Slogwang 3016*a9643ea8Slogwang if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) 3017*a9643ea8Slogwang return; 3018*a9643ea8Slogwang 3019*a9643ea8Slogwang CTX_LOCK(ctx); 3020*a9643ea8Slogwang IFDI_VFLR_HANDLE(ctx); 3021*a9643ea8Slogwang CTX_UNLOCK(ctx); 3022*a9643ea8Slogwang } 3023*a9643ea8Slogwang 3024*a9643ea8Slogwang static int 3025*a9643ea8Slogwang iflib_sysctl_int_delay(SYSCTL_HANDLER_ARGS) 3026*a9643ea8Slogwang { 3027*a9643ea8Slogwang int err; 3028*a9643ea8Slogwang if_int_delay_info_t info; 3029*a9643ea8Slogwang if_ctx_t ctx; 3030*a9643ea8Slogwang 3031*a9643ea8Slogwang info = (if_int_delay_info_t)arg1; 3032*a9643ea8Slogwang ctx = info->iidi_ctx; 3033*a9643ea8Slogwang info->iidi_req = req; 3034*a9643ea8Slogwang info->iidi_oidp = oidp; 3035*a9643ea8Slogwang CTX_LOCK(ctx); 3036*a9643ea8Slogwang err = IFDI_SYSCTL_INT_DELAY(ctx, info); 3037*a9643ea8Slogwang CTX_UNLOCK(ctx); 3038*a9643ea8Slogwang return (err); 3039*a9643ea8Slogwang } 3040*a9643ea8Slogwang 3041*a9643ea8Slogwang /********************************************************************* 3042*a9643ea8Slogwang * 3043*a9643ea8Slogwang * IFNET FUNCTIONS 3044*a9643ea8Slogwang * 3045*a9643ea8Slogwang **********************************************************************/ 3046*a9643ea8Slogwang 3047*a9643ea8Slogwang static void 3048*a9643ea8Slogwang iflib_if_init_locked(if_ctx_t ctx) 3049*a9643ea8Slogwang { 3050*a9643ea8Slogwang iflib_stop(ctx); 3051*a9643ea8Slogwang iflib_init_locked(ctx); 3052*a9643ea8Slogwang } 3053*a9643ea8Slogwang 3054*a9643ea8Slogwang 3055*a9643ea8Slogwang static void 3056*a9643ea8Slogwang iflib_if_init(void *arg) 3057*a9643ea8Slogwang { 3058*a9643ea8Slogwang if_ctx_t ctx = arg; 3059*a9643ea8Slogwang 3060*a9643ea8Slogwang CTX_LOCK(ctx); 3061*a9643ea8Slogwang iflib_if_init_locked(ctx); 3062*a9643ea8Slogwang CTX_UNLOCK(ctx); 3063*a9643ea8Slogwang } 3064*a9643ea8Slogwang 3065*a9643ea8Slogwang static int 3066*a9643ea8Slogwang iflib_if_transmit(if_t ifp, struct mbuf *m) 3067*a9643ea8Slogwang { 3068*a9643ea8Slogwang if_ctx_t ctx = if_getsoftc(ifp); 3069*a9643ea8Slogwang 3070*a9643ea8Slogwang iflib_txq_t txq; 3071*a9643ea8Slogwang int err, qidx; 3072*a9643ea8Slogwang 3073*a9643ea8Slogwang if (__predict_false((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || !LINK_ACTIVE(ctx))) { 3074*a9643ea8Slogwang DBG_COUNTER_INC(tx_frees); 3075*a9643ea8Slogwang m_freem(m); 3076*a9643ea8Slogwang return (0); 3077*a9643ea8Slogwang } 3078*a9643ea8Slogwang 3079*a9643ea8Slogwang MPASS(m->m_nextpkt == NULL); 3080*a9643ea8Slogwang qidx = 0; 3081*a9643ea8Slogwang if ((NTXQSETS(ctx) > 1) && M_HASHTYPE_GET(m)) 3082*a9643ea8Slogwang qidx = QIDX(ctx, m); 3083*a9643ea8Slogwang /* 3084*a9643ea8Slogwang * XXX calculate buf_ring based on flowid (divvy up bits?) 3085*a9643ea8Slogwang */ 3086*a9643ea8Slogwang txq = &ctx->ifc_txqs[qidx]; 3087*a9643ea8Slogwang 3088*a9643ea8Slogwang #ifdef DRIVER_BACKPRESSURE 3089*a9643ea8Slogwang if (txq->ift_closed) { 3090*a9643ea8Slogwang while (m != NULL) { 3091*a9643ea8Slogwang next = m->m_nextpkt; 3092*a9643ea8Slogwang m->m_nextpkt = NULL; 3093*a9643ea8Slogwang m_freem(m); 3094*a9643ea8Slogwang m = next; 3095*a9643ea8Slogwang } 3096*a9643ea8Slogwang return (ENOBUFS); 3097*a9643ea8Slogwang } 3098*a9643ea8Slogwang #endif 3099*a9643ea8Slogwang #ifdef notyet 3100*a9643ea8Slogwang qidx = count = 0; 3101*a9643ea8Slogwang mp = marr; 3102*a9643ea8Slogwang next = m; 3103*a9643ea8Slogwang do { 3104*a9643ea8Slogwang count++; 3105*a9643ea8Slogwang next = next->m_nextpkt; 3106*a9643ea8Slogwang } while (next != NULL); 3107*a9643ea8Slogwang 3108*a9643ea8Slogwang if (count > nitems(marr)) 3109*a9643ea8Slogwang if ((mp = malloc(count*sizeof(struct mbuf *), M_IFLIB, M_NOWAIT)) == NULL) { 3110*a9643ea8Slogwang /* XXX check nextpkt */ 3111*a9643ea8Slogwang m_freem(m); 3112*a9643ea8Slogwang /* XXX simplify for now */ 3113*a9643ea8Slogwang DBG_COUNTER_INC(tx_frees); 3114*a9643ea8Slogwang return (ENOBUFS); 3115*a9643ea8Slogwang } 3116*a9643ea8Slogwang for (next = m, i = 0; next != NULL; i++) { 3117*a9643ea8Slogwang mp[i] = next; 3118*a9643ea8Slogwang next = next->m_nextpkt; 3119*a9643ea8Slogwang mp[i]->m_nextpkt = NULL; 3120*a9643ea8Slogwang } 3121*a9643ea8Slogwang #endif 3122*a9643ea8Slogwang DBG_COUNTER_INC(tx_seen); 3123*a9643ea8Slogwang err = ifmp_ring_enqueue(txq->ift_br[0], (void **)&m, 1, TX_BATCH_SIZE); 3124*a9643ea8Slogwang 3125*a9643ea8Slogwang if (err) { 3126*a9643ea8Slogwang GROUPTASK_ENQUEUE(&txq->ift_task); 3127*a9643ea8Slogwang /* support forthcoming later */ 3128*a9643ea8Slogwang #ifdef DRIVER_BACKPRESSURE 3129*a9643ea8Slogwang txq->ift_closed = TRUE; 3130*a9643ea8Slogwang #endif 3131*a9643ea8Slogwang ifmp_ring_check_drainage(txq->ift_br[0], TX_BATCH_SIZE); 3132*a9643ea8Slogwang m_freem(m); 3133*a9643ea8Slogwang } else if (TXQ_AVAIL(txq) < (txq->ift_size >> 1)) { 3134*a9643ea8Slogwang GROUPTASK_ENQUEUE(&txq->ift_task); 3135*a9643ea8Slogwang } 3136*a9643ea8Slogwang 3137*a9643ea8Slogwang return (err); 3138*a9643ea8Slogwang } 3139*a9643ea8Slogwang 3140*a9643ea8Slogwang static void 3141*a9643ea8Slogwang iflib_if_qflush(if_t ifp) 3142*a9643ea8Slogwang { 3143*a9643ea8Slogwang if_ctx_t ctx = if_getsoftc(ifp); 3144*a9643ea8Slogwang iflib_txq_t txq = ctx->ifc_txqs; 3145*a9643ea8Slogwang int i; 3146*a9643ea8Slogwang 3147*a9643ea8Slogwang CTX_LOCK(ctx); 3148*a9643ea8Slogwang ctx->ifc_flags |= IFC_QFLUSH; 3149*a9643ea8Slogwang CTX_UNLOCK(ctx); 3150*a9643ea8Slogwang for (i = 0; i < NTXQSETS(ctx); i++, txq++) 3151*a9643ea8Slogwang while (!(ifmp_ring_is_idle(txq->ift_br[0]) || ifmp_ring_is_stalled(txq->ift_br[0]))) 3152*a9643ea8Slogwang iflib_txq_check_drain(txq, 0); 3153*a9643ea8Slogwang CTX_LOCK(ctx); 3154*a9643ea8Slogwang ctx->ifc_flags &= ~IFC_QFLUSH; 3155*a9643ea8Slogwang CTX_UNLOCK(ctx); 3156*a9643ea8Slogwang 3157*a9643ea8Slogwang if_qflush(ifp); 3158*a9643ea8Slogwang } 3159*a9643ea8Slogwang 3160*a9643ea8Slogwang 3161*a9643ea8Slogwang #define IFCAP_FLAGS (IFCAP_TXCSUM_IPV6 | IFCAP_RXCSUM_IPV6 | IFCAP_HWCSUM | IFCAP_LRO | \ 3162*a9643ea8Slogwang IFCAP_TSO4 | IFCAP_TSO6 | IFCAP_VLAN_HWTAGGING | \ 3163*a9643ea8Slogwang IFCAP_VLAN_MTU | IFCAP_VLAN_HWFILTER | IFCAP_VLAN_HWTSO) 3164*a9643ea8Slogwang 3165*a9643ea8Slogwang #define IFCAP_REINIT IFCAP_FLAGS 3166*a9643ea8Slogwang 3167*a9643ea8Slogwang static int 3168*a9643ea8Slogwang iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) 3169*a9643ea8Slogwang { 3170*a9643ea8Slogwang if_ctx_t ctx = if_getsoftc(ifp); 3171*a9643ea8Slogwang struct ifreq *ifr = (struct ifreq *)data; 3172*a9643ea8Slogwang #if defined(INET) || defined(INET6) 3173*a9643ea8Slogwang struct ifaddr *ifa = (struct ifaddr *)data; 3174*a9643ea8Slogwang #endif 3175*a9643ea8Slogwang bool avoid_reset = FALSE; 3176*a9643ea8Slogwang int err = 0, reinit = 0, bits; 3177*a9643ea8Slogwang 3178*a9643ea8Slogwang switch (command) { 3179*a9643ea8Slogwang case SIOCSIFADDR: 3180*a9643ea8Slogwang #ifdef INET 3181*a9643ea8Slogwang if (ifa->ifa_addr->sa_family == AF_INET) 3182*a9643ea8Slogwang avoid_reset = TRUE; 3183*a9643ea8Slogwang #endif 3184*a9643ea8Slogwang #ifdef INET6 3185*a9643ea8Slogwang if (ifa->ifa_addr->sa_family == AF_INET6) 3186*a9643ea8Slogwang avoid_reset = TRUE; 3187*a9643ea8Slogwang #endif 3188*a9643ea8Slogwang /* 3189*a9643ea8Slogwang ** Calling init results in link renegotiation, 3190*a9643ea8Slogwang ** so we avoid doing it when possible. 3191*a9643ea8Slogwang */ 3192*a9643ea8Slogwang if (avoid_reset) { 3193*a9643ea8Slogwang if_setflagbits(ifp, IFF_UP,0); 3194*a9643ea8Slogwang if (!(if_getdrvflags(ifp)& IFF_DRV_RUNNING)) 3195*a9643ea8Slogwang reinit = 1; 3196*a9643ea8Slogwang #ifdef INET 3197*a9643ea8Slogwang if (!(if_getflags(ifp) & IFF_NOARP)) 3198*a9643ea8Slogwang arp_ifinit(ifp, ifa); 3199*a9643ea8Slogwang #endif 3200*a9643ea8Slogwang } else 3201*a9643ea8Slogwang err = ether_ioctl(ifp, command, data); 3202*a9643ea8Slogwang break; 3203*a9643ea8Slogwang case SIOCSIFMTU: 3204*a9643ea8Slogwang CTX_LOCK(ctx); 3205*a9643ea8Slogwang if (ifr->ifr_mtu == if_getmtu(ifp)) { 3206*a9643ea8Slogwang CTX_UNLOCK(ctx); 3207*a9643ea8Slogwang break; 3208*a9643ea8Slogwang } 3209*a9643ea8Slogwang bits = if_getdrvflags(ifp); 3210*a9643ea8Slogwang /* stop the driver and free any clusters before proceeding */ 3211*a9643ea8Slogwang iflib_stop(ctx); 3212*a9643ea8Slogwang 3213*a9643ea8Slogwang if ((err = IFDI_MTU_SET(ctx, ifr->ifr_mtu)) == 0) { 3214*a9643ea8Slogwang if (ifr->ifr_mtu > ctx->ifc_max_fl_buf_size) 3215*a9643ea8Slogwang ctx->ifc_flags |= IFC_MULTISEG; 3216*a9643ea8Slogwang else 3217*a9643ea8Slogwang ctx->ifc_flags &= ~IFC_MULTISEG; 3218*a9643ea8Slogwang err = if_setmtu(ifp, ifr->ifr_mtu); 3219*a9643ea8Slogwang } 3220*a9643ea8Slogwang iflib_init_locked(ctx); 3221*a9643ea8Slogwang if_setdrvflags(ifp, bits); 3222*a9643ea8Slogwang CTX_UNLOCK(ctx); 3223*a9643ea8Slogwang break; 3224*a9643ea8Slogwang case SIOCSIFFLAGS: 3225*a9643ea8Slogwang CTX_LOCK(ctx); 3226*a9643ea8Slogwang if (if_getflags(ifp) & IFF_UP) { 3227*a9643ea8Slogwang if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 3228*a9643ea8Slogwang if ((if_getflags(ifp) ^ ctx->ifc_if_flags) & 3229*a9643ea8Slogwang (IFF_PROMISC | IFF_ALLMULTI)) { 3230*a9643ea8Slogwang err = IFDI_PROMISC_SET(ctx, if_getflags(ifp)); 3231*a9643ea8Slogwang } 3232*a9643ea8Slogwang } else 3233*a9643ea8Slogwang reinit = 1; 3234*a9643ea8Slogwang } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 3235*a9643ea8Slogwang iflib_stop(ctx); 3236*a9643ea8Slogwang } 3237*a9643ea8Slogwang ctx->ifc_if_flags = if_getflags(ifp); 3238*a9643ea8Slogwang CTX_UNLOCK(ctx); 3239*a9643ea8Slogwang break; 3240*a9643ea8Slogwang 3241*a9643ea8Slogwang break; 3242*a9643ea8Slogwang case SIOCADDMULTI: 3243*a9643ea8Slogwang case SIOCDELMULTI: 3244*a9643ea8Slogwang if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 3245*a9643ea8Slogwang CTX_LOCK(ctx); 3246*a9643ea8Slogwang IFDI_INTR_DISABLE(ctx); 3247*a9643ea8Slogwang IFDI_MULTI_SET(ctx); 3248*a9643ea8Slogwang IFDI_INTR_ENABLE(ctx); 3249*a9643ea8Slogwang CTX_UNLOCK(ctx); 3250*a9643ea8Slogwang } 3251*a9643ea8Slogwang break; 3252*a9643ea8Slogwang case SIOCSIFMEDIA: 3253*a9643ea8Slogwang CTX_LOCK(ctx); 3254*a9643ea8Slogwang IFDI_MEDIA_SET(ctx); 3255*a9643ea8Slogwang CTX_UNLOCK(ctx); 3256*a9643ea8Slogwang /* falls thru */ 3257*a9643ea8Slogwang case SIOCGIFMEDIA: 3258*a9643ea8Slogwang err = ifmedia_ioctl(ifp, ifr, &ctx->ifc_media, command); 3259*a9643ea8Slogwang break; 3260*a9643ea8Slogwang case SIOCGI2C: 3261*a9643ea8Slogwang { 3262*a9643ea8Slogwang struct ifi2creq i2c; 3263*a9643ea8Slogwang 3264*a9643ea8Slogwang err = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); 3265*a9643ea8Slogwang if (err != 0) 3266*a9643ea8Slogwang break; 3267*a9643ea8Slogwang if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { 3268*a9643ea8Slogwang err = EINVAL; 3269*a9643ea8Slogwang break; 3270*a9643ea8Slogwang } 3271*a9643ea8Slogwang if (i2c.len > sizeof(i2c.data)) { 3272*a9643ea8Slogwang err = EINVAL; 3273*a9643ea8Slogwang break; 3274*a9643ea8Slogwang } 3275*a9643ea8Slogwang 3276*a9643ea8Slogwang if ((err = IFDI_I2C_REQ(ctx, &i2c)) == 0) 3277*a9643ea8Slogwang err = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); 3278*a9643ea8Slogwang break; 3279*a9643ea8Slogwang } 3280*a9643ea8Slogwang case SIOCSIFCAP: 3281*a9643ea8Slogwang { 3282*a9643ea8Slogwang int mask, setmask; 3283*a9643ea8Slogwang 3284*a9643ea8Slogwang mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 3285*a9643ea8Slogwang setmask = 0; 3286*a9643ea8Slogwang #ifdef TCP_OFFLOAD 3287*a9643ea8Slogwang setmask |= mask & (IFCAP_TOE4|IFCAP_TOE6); 3288*a9643ea8Slogwang #endif 3289*a9643ea8Slogwang setmask |= (mask & IFCAP_FLAGS); 3290*a9643ea8Slogwang 3291*a9643ea8Slogwang if ((mask & IFCAP_WOL) && 3292*a9643ea8Slogwang (if_getcapabilities(ifp) & IFCAP_WOL) != 0) 3293*a9643ea8Slogwang setmask |= (mask & (IFCAP_WOL_MCAST|IFCAP_WOL_MAGIC)); 3294*a9643ea8Slogwang if_vlancap(ifp); 3295*a9643ea8Slogwang /* 3296*a9643ea8Slogwang * want to ensure that traffic has stopped before we change any of the flags 3297*a9643ea8Slogwang */ 3298*a9643ea8Slogwang if (setmask) { 3299*a9643ea8Slogwang CTX_LOCK(ctx); 3300*a9643ea8Slogwang bits = if_getdrvflags(ifp); 3301*a9643ea8Slogwang if (setmask & IFCAP_REINIT) 3302*a9643ea8Slogwang iflib_stop(ctx); 3303*a9643ea8Slogwang if_togglecapenable(ifp, setmask); 3304*a9643ea8Slogwang if (setmask & IFCAP_REINIT) 3305*a9643ea8Slogwang iflib_init_locked(ctx); 3306*a9643ea8Slogwang if_setdrvflags(ifp, bits); 3307*a9643ea8Slogwang CTX_UNLOCK(ctx); 3308*a9643ea8Slogwang } 3309*a9643ea8Slogwang break; 3310*a9643ea8Slogwang } 3311*a9643ea8Slogwang case SIOCGPRIVATE_0: 3312*a9643ea8Slogwang case SIOCSDRVSPEC: 3313*a9643ea8Slogwang case SIOCGDRVSPEC: 3314*a9643ea8Slogwang CTX_LOCK(ctx); 3315*a9643ea8Slogwang err = IFDI_PRIV_IOCTL(ctx, command, data); 3316*a9643ea8Slogwang CTX_UNLOCK(ctx); 3317*a9643ea8Slogwang break; 3318*a9643ea8Slogwang default: 3319*a9643ea8Slogwang err = ether_ioctl(ifp, command, data); 3320*a9643ea8Slogwang break; 3321*a9643ea8Slogwang } 3322*a9643ea8Slogwang if (reinit) 3323*a9643ea8Slogwang iflib_if_init(ctx); 3324*a9643ea8Slogwang return (err); 3325*a9643ea8Slogwang } 3326*a9643ea8Slogwang 3327*a9643ea8Slogwang static uint64_t 3328*a9643ea8Slogwang iflib_if_get_counter(if_t ifp, ift_counter cnt) 3329*a9643ea8Slogwang { 3330*a9643ea8Slogwang if_ctx_t ctx = if_getsoftc(ifp); 3331*a9643ea8Slogwang 3332*a9643ea8Slogwang return (IFDI_GET_COUNTER(ctx, cnt)); 3333*a9643ea8Slogwang } 3334*a9643ea8Slogwang 3335*a9643ea8Slogwang /********************************************************************* 3336*a9643ea8Slogwang * 3337*a9643ea8Slogwang * OTHER FUNCTIONS EXPORTED TO THE STACK 3338*a9643ea8Slogwang * 3339*a9643ea8Slogwang **********************************************************************/ 3340*a9643ea8Slogwang 3341*a9643ea8Slogwang static void 3342*a9643ea8Slogwang iflib_vlan_register(void *arg, if_t ifp, uint16_t vtag) 3343*a9643ea8Slogwang { 3344*a9643ea8Slogwang if_ctx_t ctx = if_getsoftc(ifp); 3345*a9643ea8Slogwang 3346*a9643ea8Slogwang if ((void *)ctx != arg) 3347*a9643ea8Slogwang return; 3348*a9643ea8Slogwang 3349*a9643ea8Slogwang if ((vtag == 0) || (vtag > 4095)) 3350*a9643ea8Slogwang return; 3351*a9643ea8Slogwang 3352*a9643ea8Slogwang CTX_LOCK(ctx); 3353*a9643ea8Slogwang IFDI_VLAN_REGISTER(ctx, vtag); 3354*a9643ea8Slogwang /* Re-init to load the changes */ 3355*a9643ea8Slogwang if (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) 3356*a9643ea8Slogwang iflib_init_locked(ctx); 3357*a9643ea8Slogwang CTX_UNLOCK(ctx); 3358*a9643ea8Slogwang } 3359*a9643ea8Slogwang 3360*a9643ea8Slogwang static void 3361*a9643ea8Slogwang iflib_vlan_unregister(void *arg, if_t ifp, uint16_t vtag) 3362*a9643ea8Slogwang { 3363*a9643ea8Slogwang if_ctx_t ctx = if_getsoftc(ifp); 3364*a9643ea8Slogwang 3365*a9643ea8Slogwang if ((void *)ctx != arg) 3366*a9643ea8Slogwang return; 3367*a9643ea8Slogwang 3368*a9643ea8Slogwang if ((vtag == 0) || (vtag > 4095)) 3369*a9643ea8Slogwang return; 3370*a9643ea8Slogwang 3371*a9643ea8Slogwang CTX_LOCK(ctx); 3372*a9643ea8Slogwang IFDI_VLAN_UNREGISTER(ctx, vtag); 3373*a9643ea8Slogwang /* Re-init to load the changes */ 3374*a9643ea8Slogwang if (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) 3375*a9643ea8Slogwang iflib_init_locked(ctx); 3376*a9643ea8Slogwang CTX_UNLOCK(ctx); 3377*a9643ea8Slogwang } 3378*a9643ea8Slogwang 3379*a9643ea8Slogwang static void 3380*a9643ea8Slogwang iflib_led_func(void *arg, int onoff) 3381*a9643ea8Slogwang { 3382*a9643ea8Slogwang if_ctx_t ctx = arg; 3383*a9643ea8Slogwang 3384*a9643ea8Slogwang CTX_LOCK(ctx); 3385*a9643ea8Slogwang IFDI_LED_FUNC(ctx, onoff); 3386*a9643ea8Slogwang CTX_UNLOCK(ctx); 3387*a9643ea8Slogwang } 3388*a9643ea8Slogwang 3389*a9643ea8Slogwang /********************************************************************* 3390*a9643ea8Slogwang * 3391*a9643ea8Slogwang * BUS FUNCTION DEFINITIONS 3392*a9643ea8Slogwang * 3393*a9643ea8Slogwang **********************************************************************/ 3394*a9643ea8Slogwang 3395*a9643ea8Slogwang int 3396*a9643ea8Slogwang iflib_device_probe(device_t dev) 3397*a9643ea8Slogwang { 3398*a9643ea8Slogwang pci_vendor_info_t *ent; 3399*a9643ea8Slogwang 3400*a9643ea8Slogwang uint16_t pci_vendor_id, pci_device_id; 3401*a9643ea8Slogwang uint16_t pci_subvendor_id, pci_subdevice_id; 3402*a9643ea8Slogwang uint16_t pci_rev_id; 3403*a9643ea8Slogwang if_shared_ctx_t sctx; 3404*a9643ea8Slogwang 3405*a9643ea8Slogwang if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC) 3406*a9643ea8Slogwang return (ENOTSUP); 3407*a9643ea8Slogwang 3408*a9643ea8Slogwang pci_vendor_id = pci_get_vendor(dev); 3409*a9643ea8Slogwang pci_device_id = pci_get_device(dev); 3410*a9643ea8Slogwang pci_subvendor_id = pci_get_subvendor(dev); 3411*a9643ea8Slogwang pci_subdevice_id = pci_get_subdevice(dev); 3412*a9643ea8Slogwang pci_rev_id = pci_get_revid(dev); 3413*a9643ea8Slogwang if (sctx->isc_parse_devinfo != NULL) 3414*a9643ea8Slogwang sctx->isc_parse_devinfo(&pci_device_id, &pci_subvendor_id, &pci_subdevice_id, &pci_rev_id); 3415*a9643ea8Slogwang 3416*a9643ea8Slogwang ent = sctx->isc_vendor_info; 3417*a9643ea8Slogwang while (ent->pvi_vendor_id != 0) { 3418*a9643ea8Slogwang if (pci_vendor_id != ent->pvi_vendor_id) { 3419*a9643ea8Slogwang ent++; 3420*a9643ea8Slogwang continue; 3421*a9643ea8Slogwang } 3422*a9643ea8Slogwang if ((pci_device_id == ent->pvi_device_id) && 3423*a9643ea8Slogwang ((pci_subvendor_id == ent->pvi_subvendor_id) || 3424*a9643ea8Slogwang (ent->pvi_subvendor_id == 0)) && 3425*a9643ea8Slogwang ((pci_subdevice_id == ent->pvi_subdevice_id) || 3426*a9643ea8Slogwang (ent->pvi_subdevice_id == 0)) && 3427*a9643ea8Slogwang ((pci_rev_id == ent->pvi_rev_id) || 3428*a9643ea8Slogwang (ent->pvi_rev_id == 0))) { 3429*a9643ea8Slogwang 3430*a9643ea8Slogwang device_set_desc_copy(dev, ent->pvi_name); 3431*a9643ea8Slogwang /* this needs to be changed to zero if the bus probing code 3432*a9643ea8Slogwang * ever stops re-probing on best match because the sctx 3433*a9643ea8Slogwang * may have its values over written by register calls 3434*a9643ea8Slogwang * in subsequent probes 3435*a9643ea8Slogwang */ 3436*a9643ea8Slogwang return (BUS_PROBE_DEFAULT); 3437*a9643ea8Slogwang } 3438*a9643ea8Slogwang ent++; 3439*a9643ea8Slogwang } 3440*a9643ea8Slogwang return (ENXIO); 3441*a9643ea8Slogwang } 3442*a9643ea8Slogwang 3443*a9643ea8Slogwang int 3444*a9643ea8Slogwang iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ctxp) 3445*a9643ea8Slogwang { 3446*a9643ea8Slogwang int err, rid, msix, msix_bar; 3447*a9643ea8Slogwang if_ctx_t ctx; 3448*a9643ea8Slogwang if_t ifp; 3449*a9643ea8Slogwang if_softc_ctx_t scctx; 3450*a9643ea8Slogwang int i; 3451*a9643ea8Slogwang uint16_t main_txq; 3452*a9643ea8Slogwang uint16_t main_rxq; 3453*a9643ea8Slogwang 3454*a9643ea8Slogwang 3455*a9643ea8Slogwang ctx = malloc(sizeof(* ctx), M_IFLIB, M_WAITOK|M_ZERO); 3456*a9643ea8Slogwang 3457*a9643ea8Slogwang if (sc == NULL) { 3458*a9643ea8Slogwang sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK|M_ZERO); 3459*a9643ea8Slogwang device_set_softc(dev, ctx); 3460*a9643ea8Slogwang ctx->ifc_flags |= IFC_SC_ALLOCATED; 3461*a9643ea8Slogwang } 3462*a9643ea8Slogwang 3463*a9643ea8Slogwang ctx->ifc_sctx = sctx; 3464*a9643ea8Slogwang ctx->ifc_dev = dev; 3465*a9643ea8Slogwang ctx->ifc_txrx = *sctx->isc_txrx; 3466*a9643ea8Slogwang ctx->ifc_softc = sc; 3467*a9643ea8Slogwang 3468*a9643ea8Slogwang if ((err = iflib_register(ctx)) != 0) { 3469*a9643ea8Slogwang device_printf(dev, "iflib_register failed %d\n", err); 3470*a9643ea8Slogwang return (err); 3471*a9643ea8Slogwang } 3472*a9643ea8Slogwang iflib_add_device_sysctl_pre(ctx); 3473*a9643ea8Slogwang 3474*a9643ea8Slogwang scctx = &ctx->ifc_softc_ctx; 3475*a9643ea8Slogwang /* 3476*a9643ea8Slogwang * XXX sanity check that ntxd & nrxd are a power of 2 3477*a9643ea8Slogwang */ 3478*a9643ea8Slogwang if (ctx->ifc_sysctl_ntxqs != 0) 3479*a9643ea8Slogwang scctx->isc_ntxqsets = ctx->ifc_sysctl_ntxqs; 3480*a9643ea8Slogwang if (ctx->ifc_sysctl_nrxqs != 0) 3481*a9643ea8Slogwang scctx->isc_nrxqsets = ctx->ifc_sysctl_nrxqs; 3482*a9643ea8Slogwang 3483*a9643ea8Slogwang for (i = 0; i < sctx->isc_ntxqs; i++) { 3484*a9643ea8Slogwang if (ctx->ifc_sysctl_ntxds[i] != 0) 3485*a9643ea8Slogwang scctx->isc_ntxd[i] = ctx->ifc_sysctl_ntxds[i]; 3486*a9643ea8Slogwang else 3487*a9643ea8Slogwang scctx->isc_ntxd[i] = sctx->isc_ntxd_default[i]; 3488*a9643ea8Slogwang } 3489*a9643ea8Slogwang 3490*a9643ea8Slogwang for (i = 0; i < sctx->isc_nrxqs; i++) { 3491*a9643ea8Slogwang if (ctx->ifc_sysctl_nrxds[i] != 0) 3492*a9643ea8Slogwang scctx->isc_nrxd[i] = ctx->ifc_sysctl_nrxds[i]; 3493*a9643ea8Slogwang else 3494*a9643ea8Slogwang scctx->isc_nrxd[i] = sctx->isc_nrxd_default[i]; 3495*a9643ea8Slogwang } 3496*a9643ea8Slogwang 3497*a9643ea8Slogwang for (i = 0; i < sctx->isc_nrxqs; i++) { 3498*a9643ea8Slogwang if (scctx->isc_nrxd[i] < sctx->isc_nrxd_min[i]) { 3499*a9643ea8Slogwang device_printf(dev, "nrxd%d: %d less than nrxd_min %d - resetting to min\n", 3500*a9643ea8Slogwang i, scctx->isc_nrxd[i], sctx->isc_nrxd_min[i]); 3501*a9643ea8Slogwang scctx->isc_nrxd[i] = sctx->isc_nrxd_min[i]; 3502*a9643ea8Slogwang } 3503*a9643ea8Slogwang if (scctx->isc_nrxd[i] > sctx->isc_nrxd_max[i]) { 3504*a9643ea8Slogwang device_printf(dev, "nrxd%d: %d greater than nrxd_max %d - resetting to max\n", 3505*a9643ea8Slogwang i, scctx->isc_nrxd[i], sctx->isc_nrxd_max[i]); 3506*a9643ea8Slogwang scctx->isc_nrxd[i] = sctx->isc_nrxd_max[i]; 3507*a9643ea8Slogwang } 3508*a9643ea8Slogwang } 3509*a9643ea8Slogwang 3510*a9643ea8Slogwang for (i = 0; i < sctx->isc_ntxqs; i++) { 3511*a9643ea8Slogwang if (scctx->isc_ntxd[i] < sctx->isc_ntxd_min[i]) { 3512*a9643ea8Slogwang device_printf(dev, "ntxd%d: %d less than ntxd_min %d - resetting to min\n", 3513*a9643ea8Slogwang i, scctx->isc_ntxd[i], sctx->isc_ntxd_min[i]); 3514*a9643ea8Slogwang scctx->isc_ntxd[i] = sctx->isc_ntxd_min[i]; 3515*a9643ea8Slogwang } 3516*a9643ea8Slogwang if (scctx->isc_ntxd[i] > sctx->isc_ntxd_max[i]) { 3517*a9643ea8Slogwang device_printf(dev, "ntxd%d: %d greater than ntxd_max %d - resetting to max\n", 3518*a9643ea8Slogwang i, scctx->isc_ntxd[i], sctx->isc_ntxd_max[i]); 3519*a9643ea8Slogwang scctx->isc_ntxd[i] = sctx->isc_ntxd_max[i]; 3520*a9643ea8Slogwang } 3521*a9643ea8Slogwang } 3522*a9643ea8Slogwang 3523*a9643ea8Slogwang if ((err = IFDI_ATTACH_PRE(ctx)) != 0) { 3524*a9643ea8Slogwang device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err); 3525*a9643ea8Slogwang return (err); 3526*a9643ea8Slogwang } 3527*a9643ea8Slogwang if (scctx->isc_ntxqsets_max) 3528*a9643ea8Slogwang scctx->isc_ntxqsets = min(scctx->isc_ntxqsets, scctx->isc_ntxqsets_max); 3529*a9643ea8Slogwang if (scctx->isc_nrxqsets_max) 3530*a9643ea8Slogwang scctx->isc_nrxqsets = min(scctx->isc_nrxqsets, scctx->isc_nrxqsets_max); 3531*a9643ea8Slogwang 3532*a9643ea8Slogwang #ifdef ACPI_DMAR 3533*a9643ea8Slogwang if (dmar_get_dma_tag(device_get_parent(dev), dev) != NULL) 3534*a9643ea8Slogwang ctx->ifc_flags |= IFC_DMAR; 3535*a9643ea8Slogwang #endif 3536*a9643ea8Slogwang 3537*a9643ea8Slogwang msix_bar = scctx->isc_msix_bar; 3538*a9643ea8Slogwang 3539*a9643ea8Slogwang ifp = ctx->ifc_ifp; 3540*a9643ea8Slogwang 3541*a9643ea8Slogwang if(sctx->isc_flags & IFLIB_HAS_TXCQ) 3542*a9643ea8Slogwang main_txq = 1; 3543*a9643ea8Slogwang else 3544*a9643ea8Slogwang main_txq = 0; 3545*a9643ea8Slogwang 3546*a9643ea8Slogwang if(sctx->isc_flags & IFLIB_HAS_RXCQ) 3547*a9643ea8Slogwang main_rxq = 1; 3548*a9643ea8Slogwang else 3549*a9643ea8Slogwang main_rxq = 0; 3550*a9643ea8Slogwang 3551*a9643ea8Slogwang /* XXX change for per-queue sizes */ 3552*a9643ea8Slogwang device_printf(dev, "using %d tx descriptors and %d rx descriptors\n", 3553*a9643ea8Slogwang scctx->isc_ntxd[main_txq], scctx->isc_nrxd[main_rxq]); 3554*a9643ea8Slogwang for (i = 0; i < sctx->isc_nrxqs; i++) { 3555*a9643ea8Slogwang if (!powerof2(scctx->isc_nrxd[i])) { 3556*a9643ea8Slogwang /* round down instead? */ 3557*a9643ea8Slogwang device_printf(dev, "# rx descriptors must be a power of 2\n"); 3558*a9643ea8Slogwang err = EINVAL; 3559*a9643ea8Slogwang goto fail; 3560*a9643ea8Slogwang } 3561*a9643ea8Slogwang } 3562*a9643ea8Slogwang for (i = 0; i < sctx->isc_ntxqs; i++) { 3563*a9643ea8Slogwang if (!powerof2(scctx->isc_ntxd[i])) { 3564*a9643ea8Slogwang device_printf(dev, 3565*a9643ea8Slogwang "# tx descriptors must be a power of 2"); 3566*a9643ea8Slogwang err = EINVAL; 3567*a9643ea8Slogwang goto fail; 3568*a9643ea8Slogwang } 3569*a9643ea8Slogwang } 3570*a9643ea8Slogwang 3571*a9643ea8Slogwang if (scctx->isc_tx_nsegments > scctx->isc_ntxd[main_txq] / 3572*a9643ea8Slogwang MAX_SINGLE_PACKET_FRACTION) 3573*a9643ea8Slogwang scctx->isc_tx_nsegments = max(1, scctx->isc_ntxd[main_txq] / 3574*a9643ea8Slogwang MAX_SINGLE_PACKET_FRACTION); 3575*a9643ea8Slogwang if (scctx->isc_tx_tso_segments_max > scctx->isc_ntxd[main_txq] / 3576*a9643ea8Slogwang MAX_SINGLE_PACKET_FRACTION) 3577*a9643ea8Slogwang scctx->isc_tx_tso_segments_max = max(1, 3578*a9643ea8Slogwang scctx->isc_ntxd[main_txq] / MAX_SINGLE_PACKET_FRACTION); 3579*a9643ea8Slogwang 3580*a9643ea8Slogwang /* 3581*a9643ea8Slogwang * Protect the stack against modern hardware 3582*a9643ea8Slogwang */ 3583*a9643ea8Slogwang if (scctx->isc_tx_tso_size_max > FREEBSD_TSO_SIZE_MAX) 3584*a9643ea8Slogwang scctx->isc_tx_tso_size_max = FREEBSD_TSO_SIZE_MAX; 3585*a9643ea8Slogwang 3586*a9643ea8Slogwang /* TSO parameters - dig these out of the data sheet - simply correspond to tag setup */ 3587*a9643ea8Slogwang ifp->if_hw_tsomaxsegcount = scctx->isc_tx_tso_segments_max; 3588*a9643ea8Slogwang ifp->if_hw_tsomax = scctx->isc_tx_tso_size_max; 3589*a9643ea8Slogwang ifp->if_hw_tsomaxsegsize = scctx->isc_tx_tso_segsize_max; 3590*a9643ea8Slogwang if (scctx->isc_rss_table_size == 0) 3591*a9643ea8Slogwang scctx->isc_rss_table_size = 64; 3592*a9643ea8Slogwang scctx->isc_rss_table_mask = scctx->isc_rss_table_size-1; 3593*a9643ea8Slogwang /* 3594*a9643ea8Slogwang ** Now setup MSI or MSI/X, should 3595*a9643ea8Slogwang ** return us the number of supported 3596*a9643ea8Slogwang ** vectors. (Will be 1 for MSI) 3597*a9643ea8Slogwang */ 3598*a9643ea8Slogwang if (sctx->isc_flags & IFLIB_SKIP_MSIX) { 3599*a9643ea8Slogwang msix = scctx->isc_vectors; 3600*a9643ea8Slogwang } else if (scctx->isc_msix_bar != 0) 3601*a9643ea8Slogwang msix = iflib_msix_init(ctx); 3602*a9643ea8Slogwang else { 3603*a9643ea8Slogwang scctx->isc_vectors = 1; 3604*a9643ea8Slogwang scctx->isc_ntxqsets = 1; 3605*a9643ea8Slogwang scctx->isc_nrxqsets = 1; 3606*a9643ea8Slogwang scctx->isc_intr = IFLIB_INTR_LEGACY; 3607*a9643ea8Slogwang msix = 0; 3608*a9643ea8Slogwang } 3609*a9643ea8Slogwang /* Get memory for the station queues */ 3610*a9643ea8Slogwang if ((err = iflib_queues_alloc(ctx))) { 3611*a9643ea8Slogwang device_printf(dev, "Unable to allocate queue memory\n"); 3612*a9643ea8Slogwang goto fail; 3613*a9643ea8Slogwang } 3614*a9643ea8Slogwang 3615*a9643ea8Slogwang if ((err = iflib_qset_structures_setup(ctx))) { 3616*a9643ea8Slogwang device_printf(dev, "qset structure setup failed %d\n", err); 3617*a9643ea8Slogwang goto fail_queues; 3618*a9643ea8Slogwang } 3619*a9643ea8Slogwang 3620*a9643ea8Slogwang if (msix > 1 && (err = IFDI_MSIX_INTR_ASSIGN(ctx, msix)) != 0) { 3621*a9643ea8Slogwang device_printf(dev, "IFDI_MSIX_INTR_ASSIGN failed %d\n", err); 3622*a9643ea8Slogwang goto fail_intr_free; 3623*a9643ea8Slogwang } 3624*a9643ea8Slogwang if (msix <= 1) { 3625*a9643ea8Slogwang rid = 0; 3626*a9643ea8Slogwang if (scctx->isc_intr == IFLIB_INTR_MSI) { 3627*a9643ea8Slogwang MPASS(msix == 1); 3628*a9643ea8Slogwang rid = 1; 3629*a9643ea8Slogwang } 3630*a9643ea8Slogwang if ((err = iflib_legacy_setup(ctx, ctx->isc_legacy_intr, ctx->ifc_softc, &rid, "irq0")) != 0) { 3631*a9643ea8Slogwang device_printf(dev, "iflib_legacy_setup failed %d\n", err); 3632*a9643ea8Slogwang goto fail_intr_free; 3633*a9643ea8Slogwang } 3634*a9643ea8Slogwang } 3635*a9643ea8Slogwang ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac); 3636*a9643ea8Slogwang if ((err = IFDI_ATTACH_POST(ctx)) != 0) { 3637*a9643ea8Slogwang device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err); 3638*a9643ea8Slogwang goto fail_detach; 3639*a9643ea8Slogwang } 3640*a9643ea8Slogwang if ((err = iflib_netmap_attach(ctx))) { 3641*a9643ea8Slogwang device_printf(ctx->ifc_dev, "netmap attach failed: %d\n", err); 3642*a9643ea8Slogwang goto fail_detach; 3643*a9643ea8Slogwang } 3644*a9643ea8Slogwang *ctxp = ctx; 3645*a9643ea8Slogwang 3646*a9643ea8Slogwang if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter); 3647*a9643ea8Slogwang iflib_add_device_sysctl_post(ctx); 3648*a9643ea8Slogwang return (0); 3649*a9643ea8Slogwang fail_detach: 3650*a9643ea8Slogwang ether_ifdetach(ctx->ifc_ifp); 3651*a9643ea8Slogwang fail_intr_free: 3652*a9643ea8Slogwang if (scctx->isc_intr == IFLIB_INTR_MSIX || scctx->isc_intr == IFLIB_INTR_MSI) 3653*a9643ea8Slogwang pci_release_msi(ctx->ifc_dev); 3654*a9643ea8Slogwang fail_queues: 3655*a9643ea8Slogwang /* XXX free queues */ 3656*a9643ea8Slogwang fail: 3657*a9643ea8Slogwang IFDI_DETACH(ctx); 3658*a9643ea8Slogwang return (err); 3659*a9643ea8Slogwang } 3660*a9643ea8Slogwang 3661*a9643ea8Slogwang int 3662*a9643ea8Slogwang iflib_device_attach(device_t dev) 3663*a9643ea8Slogwang { 3664*a9643ea8Slogwang if_ctx_t ctx; 3665*a9643ea8Slogwang if_shared_ctx_t sctx; 3666*a9643ea8Slogwang 3667*a9643ea8Slogwang if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC) 3668*a9643ea8Slogwang return (ENOTSUP); 3669*a9643ea8Slogwang 3670*a9643ea8Slogwang pci_enable_busmaster(dev); 3671*a9643ea8Slogwang 3672*a9643ea8Slogwang return (iflib_device_register(dev, NULL, sctx, &ctx)); 3673*a9643ea8Slogwang } 3674*a9643ea8Slogwang 3675*a9643ea8Slogwang int 3676*a9643ea8Slogwang iflib_device_deregister(if_ctx_t ctx) 3677*a9643ea8Slogwang { 3678*a9643ea8Slogwang if_t ifp = ctx->ifc_ifp; 3679*a9643ea8Slogwang iflib_txq_t txq; 3680*a9643ea8Slogwang iflib_rxq_t rxq; 3681*a9643ea8Slogwang device_t dev = ctx->ifc_dev; 3682*a9643ea8Slogwang int i; 3683*a9643ea8Slogwang struct taskqgroup *tqg; 3684*a9643ea8Slogwang 3685*a9643ea8Slogwang /* Make sure VLANS are not using driver */ 3686*a9643ea8Slogwang if (if_vlantrunkinuse(ifp)) { 3687*a9643ea8Slogwang device_printf(dev,"Vlan in use, detach first\n"); 3688*a9643ea8Slogwang return (EBUSY); 3689*a9643ea8Slogwang } 3690*a9643ea8Slogwang 3691*a9643ea8Slogwang CTX_LOCK(ctx); 3692*a9643ea8Slogwang ctx->ifc_in_detach = 1; 3693*a9643ea8Slogwang iflib_stop(ctx); 3694*a9643ea8Slogwang CTX_UNLOCK(ctx); 3695*a9643ea8Slogwang 3696*a9643ea8Slogwang /* Unregister VLAN events */ 3697*a9643ea8Slogwang if (ctx->ifc_vlan_attach_event != NULL) 3698*a9643ea8Slogwang EVENTHANDLER_DEREGISTER(vlan_config, ctx->ifc_vlan_attach_event); 3699*a9643ea8Slogwang if (ctx->ifc_vlan_detach_event != NULL) 3700*a9643ea8Slogwang EVENTHANDLER_DEREGISTER(vlan_unconfig, ctx->ifc_vlan_detach_event); 3701*a9643ea8Slogwang 3702*a9643ea8Slogwang iflib_netmap_detach(ifp); 3703*a9643ea8Slogwang ether_ifdetach(ifp); 3704*a9643ea8Slogwang /* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/ 3705*a9643ea8Slogwang CTX_LOCK_DESTROY(ctx); 3706*a9643ea8Slogwang if (ctx->ifc_led_dev != NULL) 3707*a9643ea8Slogwang led_destroy(ctx->ifc_led_dev); 3708*a9643ea8Slogwang /* XXX drain any dependent tasks */ 3709*a9643ea8Slogwang tqg = qgroup_if_io_tqg; 3710*a9643ea8Slogwang for (txq = ctx->ifc_txqs, i = 0; i < NTXQSETS(ctx); i++, txq++) { 3711*a9643ea8Slogwang callout_drain(&txq->ift_timer); 3712*a9643ea8Slogwang callout_drain(&txq->ift_db_check); 3713*a9643ea8Slogwang if (txq->ift_task.gt_uniq != NULL) 3714*a9643ea8Slogwang taskqgroup_detach(tqg, &txq->ift_task); 3715*a9643ea8Slogwang } 3716*a9643ea8Slogwang for (i = 0, rxq = ctx->ifc_rxqs; i < NRXQSETS(ctx); i++, rxq++) { 3717*a9643ea8Slogwang if (rxq->ifr_task.gt_uniq != NULL) 3718*a9643ea8Slogwang taskqgroup_detach(tqg, &rxq->ifr_task); 3719*a9643ea8Slogwang } 3720*a9643ea8Slogwang tqg = qgroup_if_config_tqg; 3721*a9643ea8Slogwang if (ctx->ifc_admin_task.gt_uniq != NULL) 3722*a9643ea8Slogwang taskqgroup_detach(tqg, &ctx->ifc_admin_task); 3723*a9643ea8Slogwang if (ctx->ifc_vflr_task.gt_uniq != NULL) 3724*a9643ea8Slogwang taskqgroup_detach(tqg, &ctx->ifc_vflr_task); 3725*a9643ea8Slogwang 3726*a9643ea8Slogwang IFDI_DETACH(ctx); 3727*a9643ea8Slogwang device_set_softc(ctx->ifc_dev, NULL); 3728*a9643ea8Slogwang if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_LEGACY) { 3729*a9643ea8Slogwang pci_release_msi(dev); 3730*a9643ea8Slogwang } 3731*a9643ea8Slogwang if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_MSIX) { 3732*a9643ea8Slogwang iflib_irq_free(ctx, &ctx->ifc_legacy_irq); 3733*a9643ea8Slogwang } 3734*a9643ea8Slogwang if (ctx->ifc_msix_mem != NULL) { 3735*a9643ea8Slogwang bus_release_resource(ctx->ifc_dev, SYS_RES_MEMORY, 3736*a9643ea8Slogwang ctx->ifc_softc_ctx.isc_msix_bar, ctx->ifc_msix_mem); 3737*a9643ea8Slogwang ctx->ifc_msix_mem = NULL; 3738*a9643ea8Slogwang } 3739*a9643ea8Slogwang 3740*a9643ea8Slogwang bus_generic_detach(dev); 3741*a9643ea8Slogwang if_free(ifp); 3742*a9643ea8Slogwang 3743*a9643ea8Slogwang iflib_tx_structures_free(ctx); 3744*a9643ea8Slogwang iflib_rx_structures_free(ctx); 3745*a9643ea8Slogwang if (ctx->ifc_flags & IFC_SC_ALLOCATED) 3746*a9643ea8Slogwang free(ctx->ifc_softc, M_IFLIB); 3747*a9643ea8Slogwang free(ctx, M_IFLIB); 3748*a9643ea8Slogwang return (0); 3749*a9643ea8Slogwang } 3750*a9643ea8Slogwang 3751*a9643ea8Slogwang 3752*a9643ea8Slogwang int 3753*a9643ea8Slogwang iflib_device_detach(device_t dev) 3754*a9643ea8Slogwang { 3755*a9643ea8Slogwang if_ctx_t ctx = device_get_softc(dev); 3756*a9643ea8Slogwang 3757*a9643ea8Slogwang return (iflib_device_deregister(ctx)); 3758*a9643ea8Slogwang } 3759*a9643ea8Slogwang 3760*a9643ea8Slogwang int 3761*a9643ea8Slogwang iflib_device_suspend(device_t dev) 3762*a9643ea8Slogwang { 3763*a9643ea8Slogwang if_ctx_t ctx = device_get_softc(dev); 3764*a9643ea8Slogwang 3765*a9643ea8Slogwang CTX_LOCK(ctx); 3766*a9643ea8Slogwang IFDI_SUSPEND(ctx); 3767*a9643ea8Slogwang CTX_UNLOCK(ctx); 3768*a9643ea8Slogwang 3769*a9643ea8Slogwang return bus_generic_suspend(dev); 3770*a9643ea8Slogwang } 3771*a9643ea8Slogwang int 3772*a9643ea8Slogwang iflib_device_shutdown(device_t dev) 3773*a9643ea8Slogwang { 3774*a9643ea8Slogwang if_ctx_t ctx = device_get_softc(dev); 3775*a9643ea8Slogwang 3776*a9643ea8Slogwang CTX_LOCK(ctx); 3777*a9643ea8Slogwang IFDI_SHUTDOWN(ctx); 3778*a9643ea8Slogwang CTX_UNLOCK(ctx); 3779*a9643ea8Slogwang 3780*a9643ea8Slogwang return bus_generic_suspend(dev); 3781*a9643ea8Slogwang } 3782*a9643ea8Slogwang 3783*a9643ea8Slogwang 3784*a9643ea8Slogwang int 3785*a9643ea8Slogwang iflib_device_resume(device_t dev) 3786*a9643ea8Slogwang { 3787*a9643ea8Slogwang if_ctx_t ctx = device_get_softc(dev); 3788*a9643ea8Slogwang iflib_txq_t txq = ctx->ifc_txqs; 3789*a9643ea8Slogwang 3790*a9643ea8Slogwang CTX_LOCK(ctx); 3791*a9643ea8Slogwang IFDI_RESUME(ctx); 3792*a9643ea8Slogwang iflib_init_locked(ctx); 3793*a9643ea8Slogwang CTX_UNLOCK(ctx); 3794*a9643ea8Slogwang for (int i = 0; i < NTXQSETS(ctx); i++, txq++) 3795*a9643ea8Slogwang iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET); 3796*a9643ea8Slogwang 3797*a9643ea8Slogwang return (bus_generic_resume(dev)); 3798*a9643ea8Slogwang } 3799*a9643ea8Slogwang 3800*a9643ea8Slogwang int 3801*a9643ea8Slogwang iflib_device_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params) 3802*a9643ea8Slogwang { 3803*a9643ea8Slogwang int error; 3804*a9643ea8Slogwang if_ctx_t ctx = device_get_softc(dev); 3805*a9643ea8Slogwang 3806*a9643ea8Slogwang CTX_LOCK(ctx); 3807*a9643ea8Slogwang error = IFDI_IOV_INIT(ctx, num_vfs, params); 3808*a9643ea8Slogwang CTX_UNLOCK(ctx); 3809*a9643ea8Slogwang 3810*a9643ea8Slogwang return (error); 3811*a9643ea8Slogwang } 3812*a9643ea8Slogwang 3813*a9643ea8Slogwang void 3814*a9643ea8Slogwang iflib_device_iov_uninit(device_t dev) 3815*a9643ea8Slogwang { 3816*a9643ea8Slogwang if_ctx_t ctx = device_get_softc(dev); 3817*a9643ea8Slogwang 3818*a9643ea8Slogwang CTX_LOCK(ctx); 3819*a9643ea8Slogwang IFDI_IOV_UNINIT(ctx); 3820*a9643ea8Slogwang CTX_UNLOCK(ctx); 3821*a9643ea8Slogwang } 3822*a9643ea8Slogwang 3823*a9643ea8Slogwang int 3824*a9643ea8Slogwang iflib_device_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params) 3825*a9643ea8Slogwang { 3826*a9643ea8Slogwang int error; 3827*a9643ea8Slogwang if_ctx_t ctx = device_get_softc(dev); 3828*a9643ea8Slogwang 3829*a9643ea8Slogwang CTX_LOCK(ctx); 3830*a9643ea8Slogwang error = IFDI_IOV_VF_ADD(ctx, vfnum, params); 3831*a9643ea8Slogwang CTX_UNLOCK(ctx); 3832*a9643ea8Slogwang 3833*a9643ea8Slogwang return (error); 3834*a9643ea8Slogwang } 3835*a9643ea8Slogwang 3836*a9643ea8Slogwang /********************************************************************* 3837*a9643ea8Slogwang * 3838*a9643ea8Slogwang * MODULE FUNCTION DEFINITIONS 3839*a9643ea8Slogwang * 3840*a9643ea8Slogwang **********************************************************************/ 3841*a9643ea8Slogwang 3842*a9643ea8Slogwang /* 3843*a9643ea8Slogwang * - Start a fast taskqueue thread for each core 3844*a9643ea8Slogwang * - Start a taskqueue for control operations 3845*a9643ea8Slogwang */ 3846*a9643ea8Slogwang static int 3847*a9643ea8Slogwang iflib_module_init(void) 3848*a9643ea8Slogwang { 3849*a9643ea8Slogwang return (0); 3850*a9643ea8Slogwang } 3851*a9643ea8Slogwang 3852*a9643ea8Slogwang static int 3853*a9643ea8Slogwang iflib_module_event_handler(module_t mod, int what, void *arg) 3854*a9643ea8Slogwang { 3855*a9643ea8Slogwang int err; 3856*a9643ea8Slogwang 3857*a9643ea8Slogwang switch (what) { 3858*a9643ea8Slogwang case MOD_LOAD: 3859*a9643ea8Slogwang if ((err = iflib_module_init()) != 0) 3860*a9643ea8Slogwang return (err); 3861*a9643ea8Slogwang break; 3862*a9643ea8Slogwang case MOD_UNLOAD: 3863*a9643ea8Slogwang return (EBUSY); 3864*a9643ea8Slogwang default: 3865*a9643ea8Slogwang return (EOPNOTSUPP); 3866*a9643ea8Slogwang } 3867*a9643ea8Slogwang 3868*a9643ea8Slogwang return (0); 3869*a9643ea8Slogwang } 3870*a9643ea8Slogwang 3871*a9643ea8Slogwang /********************************************************************* 3872*a9643ea8Slogwang * 3873*a9643ea8Slogwang * PUBLIC FUNCTION DEFINITIONS 3874*a9643ea8Slogwang * ordered as in iflib.h 3875*a9643ea8Slogwang * 3876*a9643ea8Slogwang **********************************************************************/ 3877*a9643ea8Slogwang 3878*a9643ea8Slogwang 3879*a9643ea8Slogwang static void 3880*a9643ea8Slogwang _iflib_assert(if_shared_ctx_t sctx) 3881*a9643ea8Slogwang { 3882*a9643ea8Slogwang MPASS(sctx->isc_tx_maxsize); 3883*a9643ea8Slogwang MPASS(sctx->isc_tx_maxsegsize); 3884*a9643ea8Slogwang 3885*a9643ea8Slogwang MPASS(sctx->isc_rx_maxsize); 3886*a9643ea8Slogwang MPASS(sctx->isc_rx_nsegments); 3887*a9643ea8Slogwang MPASS(sctx->isc_rx_maxsegsize); 3888*a9643ea8Slogwang 3889*a9643ea8Slogwang 3890*a9643ea8Slogwang MPASS(sctx->isc_txrx->ift_txd_encap); 3891*a9643ea8Slogwang MPASS(sctx->isc_txrx->ift_txd_flush); 3892*a9643ea8Slogwang MPASS(sctx->isc_txrx->ift_txd_credits_update); 3893*a9643ea8Slogwang MPASS(sctx->isc_txrx->ift_rxd_available); 3894*a9643ea8Slogwang MPASS(sctx->isc_txrx->ift_rxd_pkt_get); 3895*a9643ea8Slogwang MPASS(sctx->isc_txrx->ift_rxd_refill); 3896*a9643ea8Slogwang MPASS(sctx->isc_txrx->ift_rxd_flush); 3897*a9643ea8Slogwang 3898*a9643ea8Slogwang MPASS(sctx->isc_nrxd_min[0]); 3899*a9643ea8Slogwang MPASS(sctx->isc_nrxd_max[0]); 3900*a9643ea8Slogwang MPASS(sctx->isc_nrxd_default[0]); 3901*a9643ea8Slogwang MPASS(sctx->isc_ntxd_min[0]); 3902*a9643ea8Slogwang MPASS(sctx->isc_ntxd_max[0]); 3903*a9643ea8Slogwang MPASS(sctx->isc_ntxd_default[0]); 3904*a9643ea8Slogwang } 3905*a9643ea8Slogwang 3906*a9643ea8Slogwang static int 3907*a9643ea8Slogwang iflib_register(if_ctx_t ctx) 3908*a9643ea8Slogwang { 3909*a9643ea8Slogwang if_shared_ctx_t sctx = ctx->ifc_sctx; 3910*a9643ea8Slogwang driver_t *driver = sctx->isc_driver; 3911*a9643ea8Slogwang device_t dev = ctx->ifc_dev; 3912*a9643ea8Slogwang if_t ifp; 3913*a9643ea8Slogwang 3914*a9643ea8Slogwang _iflib_assert(sctx); 3915*a9643ea8Slogwang 3916*a9643ea8Slogwang CTX_LOCK_INIT(ctx, device_get_nameunit(ctx->ifc_dev)); 3917*a9643ea8Slogwang 3918*a9643ea8Slogwang ifp = ctx->ifc_ifp = if_gethandle(IFT_ETHER); 3919*a9643ea8Slogwang if (ifp == NULL) { 3920*a9643ea8Slogwang device_printf(dev, "can not allocate ifnet structure\n"); 3921*a9643ea8Slogwang return (ENOMEM); 3922*a9643ea8Slogwang } 3923*a9643ea8Slogwang 3924*a9643ea8Slogwang /* 3925*a9643ea8Slogwang * Initialize our context's device specific methods 3926*a9643ea8Slogwang */ 3927*a9643ea8Slogwang kobj_init((kobj_t) ctx, (kobj_class_t) driver); 3928*a9643ea8Slogwang kobj_class_compile((kobj_class_t) driver); 3929*a9643ea8Slogwang driver->refs++; 3930*a9643ea8Slogwang 3931*a9643ea8Slogwang if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 3932*a9643ea8Slogwang if_setsoftc(ifp, ctx); 3933*a9643ea8Slogwang if_setdev(ifp, dev); 3934*a9643ea8Slogwang if_setinitfn(ifp, iflib_if_init); 3935*a9643ea8Slogwang if_setioctlfn(ifp, iflib_if_ioctl); 3936*a9643ea8Slogwang if_settransmitfn(ifp, iflib_if_transmit); 3937*a9643ea8Slogwang if_setqflushfn(ifp, iflib_if_qflush); 3938*a9643ea8Slogwang if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 3939*a9643ea8Slogwang 3940*a9643ea8Slogwang if_setcapabilities(ifp, 0); 3941*a9643ea8Slogwang if_setcapenable(ifp, 0); 3942*a9643ea8Slogwang 3943*a9643ea8Slogwang ctx->ifc_vlan_attach_event = 3944*a9643ea8Slogwang EVENTHANDLER_REGISTER(vlan_config, iflib_vlan_register, ctx, 3945*a9643ea8Slogwang EVENTHANDLER_PRI_FIRST); 3946*a9643ea8Slogwang ctx->ifc_vlan_detach_event = 3947*a9643ea8Slogwang EVENTHANDLER_REGISTER(vlan_unconfig, iflib_vlan_unregister, ctx, 3948*a9643ea8Slogwang EVENTHANDLER_PRI_FIRST); 3949*a9643ea8Slogwang 3950*a9643ea8Slogwang ifmedia_init(&ctx->ifc_media, IFM_IMASK, 3951*a9643ea8Slogwang iflib_media_change, iflib_media_status); 3952*a9643ea8Slogwang 3953*a9643ea8Slogwang return (0); 3954*a9643ea8Slogwang } 3955*a9643ea8Slogwang 3956*a9643ea8Slogwang 3957*a9643ea8Slogwang static int 3958*a9643ea8Slogwang iflib_queues_alloc(if_ctx_t ctx) 3959*a9643ea8Slogwang { 3960*a9643ea8Slogwang if_shared_ctx_t sctx = ctx->ifc_sctx; 3961*a9643ea8Slogwang if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; 3962*a9643ea8Slogwang device_t dev = ctx->ifc_dev; 3963*a9643ea8Slogwang int nrxqsets = scctx->isc_nrxqsets; 3964*a9643ea8Slogwang int ntxqsets = scctx->isc_ntxqsets; 3965*a9643ea8Slogwang iflib_txq_t txq; 3966*a9643ea8Slogwang iflib_rxq_t rxq; 3967*a9643ea8Slogwang iflib_fl_t fl = NULL; 3968*a9643ea8Slogwang int i, j, cpu, err, txconf, rxconf; 3969*a9643ea8Slogwang iflib_dma_info_t ifdip; 3970*a9643ea8Slogwang uint32_t *rxqsizes = scctx->isc_rxqsizes; 3971*a9643ea8Slogwang uint32_t *txqsizes = scctx->isc_txqsizes; 3972*a9643ea8Slogwang uint8_t nrxqs = sctx->isc_nrxqs; 3973*a9643ea8Slogwang uint8_t ntxqs = sctx->isc_ntxqs; 3974*a9643ea8Slogwang int nfree_lists = sctx->isc_nfl ? sctx->isc_nfl : 1; 3975*a9643ea8Slogwang caddr_t *vaddrs; 3976*a9643ea8Slogwang uint64_t *paddrs; 3977*a9643ea8Slogwang struct ifmp_ring **brscp; 3978*a9643ea8Slogwang int nbuf_rings = 1; /* XXX determine dynamically */ 3979*a9643ea8Slogwang 3980*a9643ea8Slogwang KASSERT(ntxqs > 0, ("number of queues per qset must be at least 1")); 3981*a9643ea8Slogwang KASSERT(nrxqs > 0, ("number of queues per qset must be at least 1")); 3982*a9643ea8Slogwang 3983*a9643ea8Slogwang brscp = NULL; 3984*a9643ea8Slogwang txq = NULL; 3985*a9643ea8Slogwang rxq = NULL; 3986*a9643ea8Slogwang 3987*a9643ea8Slogwang /* Allocate the TX ring struct memory */ 3988*a9643ea8Slogwang if (!(txq = 3989*a9643ea8Slogwang (iflib_txq_t) malloc(sizeof(struct iflib_txq) * 3990*a9643ea8Slogwang ntxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) { 3991*a9643ea8Slogwang device_printf(dev, "Unable to allocate TX ring memory\n"); 3992*a9643ea8Slogwang err = ENOMEM; 3993*a9643ea8Slogwang goto fail; 3994*a9643ea8Slogwang } 3995*a9643ea8Slogwang 3996*a9643ea8Slogwang /* Now allocate the RX */ 3997*a9643ea8Slogwang if (!(rxq = 3998*a9643ea8Slogwang (iflib_rxq_t) malloc(sizeof(struct iflib_rxq) * 3999*a9643ea8Slogwang nrxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) { 4000*a9643ea8Slogwang device_printf(dev, "Unable to allocate RX ring memory\n"); 4001*a9643ea8Slogwang err = ENOMEM; 4002*a9643ea8Slogwang goto rx_fail; 4003*a9643ea8Slogwang } 4004*a9643ea8Slogwang if (!(brscp = malloc(sizeof(void *) * nbuf_rings * nrxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) { 4005*a9643ea8Slogwang device_printf(dev, "Unable to buf_ring_sc * memory\n"); 4006*a9643ea8Slogwang err = ENOMEM; 4007*a9643ea8Slogwang goto rx_fail; 4008*a9643ea8Slogwang } 4009*a9643ea8Slogwang 4010*a9643ea8Slogwang ctx->ifc_txqs = txq; 4011*a9643ea8Slogwang ctx->ifc_rxqs = rxq; 4012*a9643ea8Slogwang 4013*a9643ea8Slogwang /* 4014*a9643ea8Slogwang * XXX handle allocation failure 4015*a9643ea8Slogwang */ 4016*a9643ea8Slogwang for (txconf = i = 0, cpu = CPU_FIRST(); i < ntxqsets; i++, txconf++, txq++, cpu = CPU_NEXT(cpu)) { 4017*a9643ea8Slogwang /* Set up some basics */ 4018*a9643ea8Slogwang 4019*a9643ea8Slogwang if ((ifdip = malloc(sizeof(struct iflib_dma_info) * ntxqs, M_IFLIB, M_WAITOK|M_ZERO)) == NULL) { 4020*a9643ea8Slogwang device_printf(dev, "failed to allocate iflib_dma_info\n"); 4021*a9643ea8Slogwang err = ENOMEM; 4022*a9643ea8Slogwang goto err_tx_desc; 4023*a9643ea8Slogwang } 4024*a9643ea8Slogwang txq->ift_ifdi = ifdip; 4025*a9643ea8Slogwang for (j = 0; j < ntxqs; j++, ifdip++) { 4026*a9643ea8Slogwang if (iflib_dma_alloc(ctx, txqsizes[j], ifdip, BUS_DMA_NOWAIT)) { 4027*a9643ea8Slogwang device_printf(dev, "Unable to allocate Descriptor memory\n"); 4028*a9643ea8Slogwang err = ENOMEM; 4029*a9643ea8Slogwang goto err_tx_desc; 4030*a9643ea8Slogwang } 4031*a9643ea8Slogwang bzero((void *)ifdip->idi_vaddr, txqsizes[j]); 4032*a9643ea8Slogwang } 4033*a9643ea8Slogwang txq->ift_ctx = ctx; 4034*a9643ea8Slogwang txq->ift_id = i; 4035*a9643ea8Slogwang if (sctx->isc_flags & IFLIB_HAS_TXCQ) { 4036*a9643ea8Slogwang txq->ift_br_offset = 1; 4037*a9643ea8Slogwang } else { 4038*a9643ea8Slogwang txq->ift_br_offset = 0; 4039*a9643ea8Slogwang } 4040*a9643ea8Slogwang /* XXX fix this */ 4041*a9643ea8Slogwang txq->ift_timer.c_cpu = cpu; 4042*a9643ea8Slogwang txq->ift_db_check.c_cpu = cpu; 4043*a9643ea8Slogwang txq->ift_nbr = nbuf_rings; 4044*a9643ea8Slogwang 4045*a9643ea8Slogwang if (iflib_txsd_alloc(txq)) { 4046*a9643ea8Slogwang device_printf(dev, "Critical Failure setting up TX buffers\n"); 4047*a9643ea8Slogwang err = ENOMEM; 4048*a9643ea8Slogwang goto err_tx_desc; 4049*a9643ea8Slogwang } 4050*a9643ea8Slogwang 4051*a9643ea8Slogwang /* Initialize the TX lock */ 4052*a9643ea8Slogwang snprintf(txq->ift_mtx_name, MTX_NAME_LEN, "%s:tx(%d):callout", 4053*a9643ea8Slogwang device_get_nameunit(dev), txq->ift_id); 4054*a9643ea8Slogwang mtx_init(&txq->ift_mtx, txq->ift_mtx_name, NULL, MTX_DEF); 4055*a9643ea8Slogwang callout_init_mtx(&txq->ift_timer, &txq->ift_mtx, 0); 4056*a9643ea8Slogwang callout_init_mtx(&txq->ift_db_check, &txq->ift_mtx, 0); 4057*a9643ea8Slogwang 4058*a9643ea8Slogwang snprintf(txq->ift_db_mtx_name, MTX_NAME_LEN, "%s:tx(%d):db", 4059*a9643ea8Slogwang device_get_nameunit(dev), txq->ift_id); 4060*a9643ea8Slogwang TXDB_LOCK_INIT(txq); 4061*a9643ea8Slogwang 4062*a9643ea8Slogwang txq->ift_br = brscp + i*nbuf_rings; 4063*a9643ea8Slogwang for (j = 0; j < nbuf_rings; j++) { 4064*a9643ea8Slogwang err = ifmp_ring_alloc(&txq->ift_br[j], 2048, txq, iflib_txq_drain, 4065*a9643ea8Slogwang iflib_txq_can_drain, M_IFLIB, M_WAITOK); 4066*a9643ea8Slogwang if (err) { 4067*a9643ea8Slogwang /* XXX free any allocated rings */ 4068*a9643ea8Slogwang device_printf(dev, "Unable to allocate buf_ring\n"); 4069*a9643ea8Slogwang goto err_tx_desc; 4070*a9643ea8Slogwang } 4071*a9643ea8Slogwang } 4072*a9643ea8Slogwang } 4073*a9643ea8Slogwang 4074*a9643ea8Slogwang for (rxconf = i = 0; i < nrxqsets; i++, rxconf++, rxq++) { 4075*a9643ea8Slogwang /* Set up some basics */ 4076*a9643ea8Slogwang 4077*a9643ea8Slogwang if ((ifdip = malloc(sizeof(struct iflib_dma_info) * nrxqs, M_IFLIB, M_WAITOK|M_ZERO)) == NULL) { 4078*a9643ea8Slogwang device_printf(dev, "failed to allocate iflib_dma_info\n"); 4079*a9643ea8Slogwang err = ENOMEM; 4080*a9643ea8Slogwang goto err_tx_desc; 4081*a9643ea8Slogwang } 4082*a9643ea8Slogwang 4083*a9643ea8Slogwang rxq->ifr_ifdi = ifdip; 4084*a9643ea8Slogwang for (j = 0; j < nrxqs; j++, ifdip++) { 4085*a9643ea8Slogwang if (iflib_dma_alloc(ctx, rxqsizes[j], ifdip, BUS_DMA_NOWAIT)) { 4086*a9643ea8Slogwang device_printf(dev, "Unable to allocate Descriptor memory\n"); 4087*a9643ea8Slogwang err = ENOMEM; 4088*a9643ea8Slogwang goto err_tx_desc; 4089*a9643ea8Slogwang } 4090*a9643ea8Slogwang bzero((void *)ifdip->idi_vaddr, rxqsizes[j]); 4091*a9643ea8Slogwang } 4092*a9643ea8Slogwang rxq->ifr_ctx = ctx; 4093*a9643ea8Slogwang rxq->ifr_id = i; 4094*a9643ea8Slogwang if (sctx->isc_flags & IFLIB_HAS_RXCQ) { 4095*a9643ea8Slogwang rxq->ifr_fl_offset = 1; 4096*a9643ea8Slogwang } else { 4097*a9643ea8Slogwang rxq->ifr_fl_offset = 0; 4098*a9643ea8Slogwang } 4099*a9643ea8Slogwang rxq->ifr_nfl = nfree_lists; 4100*a9643ea8Slogwang if (!(fl = 4101*a9643ea8Slogwang (iflib_fl_t) malloc(sizeof(struct iflib_fl) * nfree_lists, M_IFLIB, M_NOWAIT | M_ZERO))) { 4102*a9643ea8Slogwang device_printf(dev, "Unable to allocate free list memory\n"); 4103*a9643ea8Slogwang err = ENOMEM; 4104*a9643ea8Slogwang goto err_tx_desc; 4105*a9643ea8Slogwang } 4106*a9643ea8Slogwang rxq->ifr_fl = fl; 4107*a9643ea8Slogwang for (j = 0; j < nfree_lists; j++) { 4108*a9643ea8Slogwang rxq->ifr_fl[j].ifl_rxq = rxq; 4109*a9643ea8Slogwang rxq->ifr_fl[j].ifl_id = j; 4110*a9643ea8Slogwang rxq->ifr_fl[j].ifl_ifdi = 4111*a9643ea8Slogwang &rxq->ifr_ifdi[j + rxq->ifr_fl_offset]; 4112*a9643ea8Slogwang } 4113*a9643ea8Slogwang /* Allocate receive buffers for the ring*/ 4114*a9643ea8Slogwang if (iflib_rxsd_alloc(rxq)) { 4115*a9643ea8Slogwang device_printf(dev, 4116*a9643ea8Slogwang "Critical Failure setting up receive buffers\n"); 4117*a9643ea8Slogwang err = ENOMEM; 4118*a9643ea8Slogwang goto err_rx_desc; 4119*a9643ea8Slogwang } 4120*a9643ea8Slogwang } 4121*a9643ea8Slogwang 4122*a9643ea8Slogwang /* TXQs */ 4123*a9643ea8Slogwang vaddrs = malloc(sizeof(caddr_t)*ntxqsets*ntxqs, M_IFLIB, M_WAITOK); 4124*a9643ea8Slogwang paddrs = malloc(sizeof(uint64_t)*ntxqsets*ntxqs, M_IFLIB, M_WAITOK); 4125*a9643ea8Slogwang for (i = 0; i < ntxqsets; i++) { 4126*a9643ea8Slogwang iflib_dma_info_t di = ctx->ifc_txqs[i].ift_ifdi; 4127*a9643ea8Slogwang 4128*a9643ea8Slogwang for (j = 0; j < ntxqs; j++, di++) { 4129*a9643ea8Slogwang vaddrs[i*ntxqs + j] = di->idi_vaddr; 4130*a9643ea8Slogwang paddrs[i*ntxqs + j] = di->idi_paddr; 4131*a9643ea8Slogwang } 4132*a9643ea8Slogwang } 4133*a9643ea8Slogwang if ((err = IFDI_TX_QUEUES_ALLOC(ctx, vaddrs, paddrs, ntxqs, ntxqsets)) != 0) { 4134*a9643ea8Slogwang device_printf(ctx->ifc_dev, "device queue allocation failed\n"); 4135*a9643ea8Slogwang iflib_tx_structures_free(ctx); 4136*a9643ea8Slogwang free(vaddrs, M_IFLIB); 4137*a9643ea8Slogwang free(paddrs, M_IFLIB); 4138*a9643ea8Slogwang goto err_rx_desc; 4139*a9643ea8Slogwang } 4140*a9643ea8Slogwang free(vaddrs, M_IFLIB); 4141*a9643ea8Slogwang free(paddrs, M_IFLIB); 4142*a9643ea8Slogwang 4143*a9643ea8Slogwang /* RXQs */ 4144*a9643ea8Slogwang vaddrs = malloc(sizeof(caddr_t)*nrxqsets*nrxqs, M_IFLIB, M_WAITOK); 4145*a9643ea8Slogwang paddrs = malloc(sizeof(uint64_t)*nrxqsets*nrxqs, M_IFLIB, M_WAITOK); 4146*a9643ea8Slogwang for (i = 0; i < nrxqsets; i++) { 4147*a9643ea8Slogwang iflib_dma_info_t di = ctx->ifc_rxqs[i].ifr_ifdi; 4148*a9643ea8Slogwang 4149*a9643ea8Slogwang for (j = 0; j < nrxqs; j++, di++) { 4150*a9643ea8Slogwang vaddrs[i*nrxqs + j] = di->idi_vaddr; 4151*a9643ea8Slogwang paddrs[i*nrxqs + j] = di->idi_paddr; 4152*a9643ea8Slogwang } 4153*a9643ea8Slogwang } 4154*a9643ea8Slogwang if ((err = IFDI_RX_QUEUES_ALLOC(ctx, vaddrs, paddrs, nrxqs, nrxqsets)) != 0) { 4155*a9643ea8Slogwang device_printf(ctx->ifc_dev, "device queue allocation failed\n"); 4156*a9643ea8Slogwang iflib_tx_structures_free(ctx); 4157*a9643ea8Slogwang free(vaddrs, M_IFLIB); 4158*a9643ea8Slogwang free(paddrs, M_IFLIB); 4159*a9643ea8Slogwang goto err_rx_desc; 4160*a9643ea8Slogwang } 4161*a9643ea8Slogwang free(vaddrs, M_IFLIB); 4162*a9643ea8Slogwang free(paddrs, M_IFLIB); 4163*a9643ea8Slogwang 4164*a9643ea8Slogwang return (0); 4165*a9643ea8Slogwang 4166*a9643ea8Slogwang /* XXX handle allocation failure changes */ 4167*a9643ea8Slogwang err_rx_desc: 4168*a9643ea8Slogwang err_tx_desc: 4169*a9643ea8Slogwang if (ctx->ifc_rxqs != NULL) 4170*a9643ea8Slogwang free(ctx->ifc_rxqs, M_IFLIB); 4171*a9643ea8Slogwang ctx->ifc_rxqs = NULL; 4172*a9643ea8Slogwang if (ctx->ifc_txqs != NULL) 4173*a9643ea8Slogwang free(ctx->ifc_txqs, M_IFLIB); 4174*a9643ea8Slogwang ctx->ifc_txqs = NULL; 4175*a9643ea8Slogwang rx_fail: 4176*a9643ea8Slogwang if (brscp != NULL) 4177*a9643ea8Slogwang free(brscp, M_IFLIB); 4178*a9643ea8Slogwang if (rxq != NULL) 4179*a9643ea8Slogwang free(rxq, M_IFLIB); 4180*a9643ea8Slogwang if (txq != NULL) 4181*a9643ea8Slogwang free(txq, M_IFLIB); 4182*a9643ea8Slogwang fail: 4183*a9643ea8Slogwang return (err); 4184*a9643ea8Slogwang } 4185*a9643ea8Slogwang 4186*a9643ea8Slogwang static int 4187*a9643ea8Slogwang iflib_tx_structures_setup(if_ctx_t ctx) 4188*a9643ea8Slogwang { 4189*a9643ea8Slogwang iflib_txq_t txq = ctx->ifc_txqs; 4190*a9643ea8Slogwang int i; 4191*a9643ea8Slogwang 4192*a9643ea8Slogwang for (i = 0; i < NTXQSETS(ctx); i++, txq++) 4193*a9643ea8Slogwang iflib_txq_setup(txq); 4194*a9643ea8Slogwang 4195*a9643ea8Slogwang return (0); 4196*a9643ea8Slogwang } 4197*a9643ea8Slogwang 4198*a9643ea8Slogwang static void 4199*a9643ea8Slogwang iflib_tx_structures_free(if_ctx_t ctx) 4200*a9643ea8Slogwang { 4201*a9643ea8Slogwang iflib_txq_t txq = ctx->ifc_txqs; 4202*a9643ea8Slogwang int i, j; 4203*a9643ea8Slogwang 4204*a9643ea8Slogwang for (i = 0; i < NTXQSETS(ctx); i++, txq++) { 4205*a9643ea8Slogwang iflib_txq_destroy(txq); 4206*a9643ea8Slogwang for (j = 0; j < ctx->ifc_nhwtxqs; j++) 4207*a9643ea8Slogwang iflib_dma_free(&txq->ift_ifdi[j]); 4208*a9643ea8Slogwang } 4209*a9643ea8Slogwang free(ctx->ifc_txqs, M_IFLIB); 4210*a9643ea8Slogwang ctx->ifc_txqs = NULL; 4211*a9643ea8Slogwang IFDI_QUEUES_FREE(ctx); 4212*a9643ea8Slogwang } 4213*a9643ea8Slogwang 4214*a9643ea8Slogwang /********************************************************************* 4215*a9643ea8Slogwang * 4216*a9643ea8Slogwang * Initialize all receive rings. 4217*a9643ea8Slogwang * 4218*a9643ea8Slogwang **********************************************************************/ 4219*a9643ea8Slogwang static int 4220*a9643ea8Slogwang iflib_rx_structures_setup(if_ctx_t ctx) 4221*a9643ea8Slogwang { 4222*a9643ea8Slogwang iflib_rxq_t rxq = ctx->ifc_rxqs; 4223*a9643ea8Slogwang int q; 4224*a9643ea8Slogwang #if defined(INET6) || defined(INET) 4225*a9643ea8Slogwang int i, err; 4226*a9643ea8Slogwang #endif 4227*a9643ea8Slogwang 4228*a9643ea8Slogwang for (q = 0; q < ctx->ifc_softc_ctx.isc_nrxqsets; q++, rxq++) { 4229*a9643ea8Slogwang #if defined(INET6) || defined(INET) 4230*a9643ea8Slogwang tcp_lro_free(&rxq->ifr_lc); 4231*a9643ea8Slogwang if ((err = tcp_lro_init_args(&rxq->ifr_lc, ctx->ifc_ifp, 4232*a9643ea8Slogwang TCP_LRO_ENTRIES, min(1024, 4233*a9643ea8Slogwang ctx->ifc_softc_ctx.isc_nrxd[rxq->ifr_fl_offset]))) != 0) { 4234*a9643ea8Slogwang device_printf(ctx->ifc_dev, "LRO Initialization failed!\n"); 4235*a9643ea8Slogwang goto fail; 4236*a9643ea8Slogwang } 4237*a9643ea8Slogwang rxq->ifr_lro_enabled = TRUE; 4238*a9643ea8Slogwang #endif 4239*a9643ea8Slogwang IFDI_RXQ_SETUP(ctx, rxq->ifr_id); 4240*a9643ea8Slogwang } 4241*a9643ea8Slogwang return (0); 4242*a9643ea8Slogwang #if defined(INET6) || defined(INET) 4243*a9643ea8Slogwang fail: 4244*a9643ea8Slogwang /* 4245*a9643ea8Slogwang * Free RX software descriptors allocated so far, we will only handle 4246*a9643ea8Slogwang * the rings that completed, the failing case will have 4247*a9643ea8Slogwang * cleaned up for itself. 'q' failed, so its the terminus. 4248*a9643ea8Slogwang */ 4249*a9643ea8Slogwang rxq = ctx->ifc_rxqs; 4250*a9643ea8Slogwang for (i = 0; i < q; ++i, rxq++) { 4251*a9643ea8Slogwang iflib_rx_sds_free(rxq); 4252*a9643ea8Slogwang rxq->ifr_cq_gen = rxq->ifr_cq_cidx = rxq->ifr_cq_pidx = 0; 4253*a9643ea8Slogwang } 4254*a9643ea8Slogwang return (err); 4255*a9643ea8Slogwang #endif 4256*a9643ea8Slogwang } 4257*a9643ea8Slogwang 4258*a9643ea8Slogwang /********************************************************************* 4259*a9643ea8Slogwang * 4260*a9643ea8Slogwang * Free all receive rings. 4261*a9643ea8Slogwang * 4262*a9643ea8Slogwang **********************************************************************/ 4263*a9643ea8Slogwang static void 4264*a9643ea8Slogwang iflib_rx_structures_free(if_ctx_t ctx) 4265*a9643ea8Slogwang { 4266*a9643ea8Slogwang iflib_rxq_t rxq = ctx->ifc_rxqs; 4267*a9643ea8Slogwang 4268*a9643ea8Slogwang for (int i = 0; i < ctx->ifc_softc_ctx.isc_nrxqsets; i++, rxq++) { 4269*a9643ea8Slogwang iflib_rx_sds_free(rxq); 4270*a9643ea8Slogwang } 4271*a9643ea8Slogwang } 4272*a9643ea8Slogwang 4273*a9643ea8Slogwang static int 4274*a9643ea8Slogwang iflib_qset_structures_setup(if_ctx_t ctx) 4275*a9643ea8Slogwang { 4276*a9643ea8Slogwang int err; 4277*a9643ea8Slogwang 4278*a9643ea8Slogwang if ((err = iflib_tx_structures_setup(ctx)) != 0) 4279*a9643ea8Slogwang return (err); 4280*a9643ea8Slogwang 4281*a9643ea8Slogwang if ((err = iflib_rx_structures_setup(ctx)) != 0) { 4282*a9643ea8Slogwang device_printf(ctx->ifc_dev, "iflib_rx_structures_setup failed: %d\n", err); 4283*a9643ea8Slogwang iflib_tx_structures_free(ctx); 4284*a9643ea8Slogwang iflib_rx_structures_free(ctx); 4285*a9643ea8Slogwang } 4286*a9643ea8Slogwang return (err); 4287*a9643ea8Slogwang } 4288*a9643ea8Slogwang 4289*a9643ea8Slogwang int 4290*a9643ea8Slogwang iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid, 4291*a9643ea8Slogwang driver_filter_t filter, void *filter_arg, driver_intr_t handler, void *arg, char *name) 4292*a9643ea8Slogwang { 4293*a9643ea8Slogwang 4294*a9643ea8Slogwang return (_iflib_irq_alloc(ctx, irq, rid, filter, handler, arg, name)); 4295*a9643ea8Slogwang } 4296*a9643ea8Slogwang 4297*a9643ea8Slogwang static void 4298*a9643ea8Slogwang find_nth(if_ctx_t ctx, cpuset_t *cpus, int qid) 4299*a9643ea8Slogwang { 4300*a9643ea8Slogwang int i, cpuid; 4301*a9643ea8Slogwang 4302*a9643ea8Slogwang CPU_COPY(&ctx->ifc_cpus, cpus); 4303*a9643ea8Slogwang /* clear up to the qid'th bit */ 4304*a9643ea8Slogwang for (i = 0; i < qid; i++) { 4305*a9643ea8Slogwang cpuid = CPU_FFS(cpus); 4306*a9643ea8Slogwang CPU_CLR(cpuid, cpus); 4307*a9643ea8Slogwang } 4308*a9643ea8Slogwang } 4309*a9643ea8Slogwang 4310*a9643ea8Slogwang int 4311*a9643ea8Slogwang iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid, 4312*a9643ea8Slogwang iflib_intr_type_t type, driver_filter_t *filter, 4313*a9643ea8Slogwang void *filter_arg, int qid, char *name) 4314*a9643ea8Slogwang { 4315*a9643ea8Slogwang struct grouptask *gtask; 4316*a9643ea8Slogwang struct taskqgroup *tqg; 4317*a9643ea8Slogwang iflib_filter_info_t info; 4318*a9643ea8Slogwang cpuset_t cpus; 4319*a9643ea8Slogwang gtask_fn_t *fn; 4320*a9643ea8Slogwang int tqrid, err; 4321*a9643ea8Slogwang void *q; 4322*a9643ea8Slogwang 4323*a9643ea8Slogwang info = &ctx->ifc_filter_info; 4324*a9643ea8Slogwang 4325*a9643ea8Slogwang switch (type) { 4326*a9643ea8Slogwang /* XXX merge tx/rx for netmap? */ 4327*a9643ea8Slogwang case IFLIB_INTR_TX: 4328*a9643ea8Slogwang q = &ctx->ifc_txqs[qid]; 4329*a9643ea8Slogwang info = &ctx->ifc_txqs[qid].ift_filter_info; 4330*a9643ea8Slogwang gtask = &ctx->ifc_txqs[qid].ift_task; 4331*a9643ea8Slogwang tqg = qgroup_if_io_tqg; 4332*a9643ea8Slogwang tqrid = irq->ii_rid; 4333*a9643ea8Slogwang fn = _task_fn_tx; 4334*a9643ea8Slogwang break; 4335*a9643ea8Slogwang case IFLIB_INTR_RX: 4336*a9643ea8Slogwang q = &ctx->ifc_rxqs[qid]; 4337*a9643ea8Slogwang info = &ctx->ifc_rxqs[qid].ifr_filter_info; 4338*a9643ea8Slogwang gtask = &ctx->ifc_rxqs[qid].ifr_task; 4339*a9643ea8Slogwang tqg = qgroup_if_io_tqg; 4340*a9643ea8Slogwang tqrid = irq->ii_rid; 4341*a9643ea8Slogwang fn = _task_fn_rx; 4342*a9643ea8Slogwang break; 4343*a9643ea8Slogwang case IFLIB_INTR_ADMIN: 4344*a9643ea8Slogwang q = ctx; 4345*a9643ea8Slogwang info = &ctx->ifc_filter_info; 4346*a9643ea8Slogwang gtask = &ctx->ifc_admin_task; 4347*a9643ea8Slogwang tqg = qgroup_if_config_tqg; 4348*a9643ea8Slogwang tqrid = -1; 4349*a9643ea8Slogwang fn = _task_fn_admin; 4350*a9643ea8Slogwang break; 4351*a9643ea8Slogwang default: 4352*a9643ea8Slogwang panic("unknown net intr type"); 4353*a9643ea8Slogwang } 4354*a9643ea8Slogwang GROUPTASK_INIT(gtask, 0, fn, q); 4355*a9643ea8Slogwang 4356*a9643ea8Slogwang info->ifi_filter = filter; 4357*a9643ea8Slogwang info->ifi_filter_arg = filter_arg; 4358*a9643ea8Slogwang info->ifi_task = gtask; 4359*a9643ea8Slogwang 4360*a9643ea8Slogwang /* XXX query cpu that rid belongs to */ 4361*a9643ea8Slogwang 4362*a9643ea8Slogwang err = _iflib_irq_alloc(ctx, irq, rid, iflib_fast_intr, NULL, info, name); 4363*a9643ea8Slogwang if (err != 0) 4364*a9643ea8Slogwang return (err); 4365*a9643ea8Slogwang if (tqrid != -1) { 4366*a9643ea8Slogwang find_nth(ctx, &cpus, qid); 4367*a9643ea8Slogwang taskqgroup_attach_cpu(tqg, gtask, q, CPU_FFS(&cpus), irq->ii_rid, name); 4368*a9643ea8Slogwang } else 4369*a9643ea8Slogwang taskqgroup_attach(tqg, gtask, q, tqrid, name); 4370*a9643ea8Slogwang 4371*a9643ea8Slogwang 4372*a9643ea8Slogwang return (0); 4373*a9643ea8Slogwang } 4374*a9643ea8Slogwang 4375*a9643ea8Slogwang void 4376*a9643ea8Slogwang iflib_softirq_alloc_generic(if_ctx_t ctx, int rid, iflib_intr_type_t type, void *arg, int qid, char *name) 4377*a9643ea8Slogwang { 4378*a9643ea8Slogwang struct grouptask *gtask; 4379*a9643ea8Slogwang struct taskqgroup *tqg; 4380*a9643ea8Slogwang gtask_fn_t *fn; 4381*a9643ea8Slogwang void *q; 4382*a9643ea8Slogwang 4383*a9643ea8Slogwang switch (type) { 4384*a9643ea8Slogwang case IFLIB_INTR_TX: 4385*a9643ea8Slogwang q = &ctx->ifc_txqs[qid]; 4386*a9643ea8Slogwang gtask = &ctx->ifc_txqs[qid].ift_task; 4387*a9643ea8Slogwang tqg = qgroup_if_io_tqg; 4388*a9643ea8Slogwang fn = _task_fn_tx; 4389*a9643ea8Slogwang break; 4390*a9643ea8Slogwang case IFLIB_INTR_RX: 4391*a9643ea8Slogwang q = &ctx->ifc_rxqs[qid]; 4392*a9643ea8Slogwang gtask = &ctx->ifc_rxqs[qid].ifr_task; 4393*a9643ea8Slogwang tqg = qgroup_if_io_tqg; 4394*a9643ea8Slogwang fn = _task_fn_rx; 4395*a9643ea8Slogwang break; 4396*a9643ea8Slogwang case IFLIB_INTR_ADMIN: 4397*a9643ea8Slogwang q = ctx; 4398*a9643ea8Slogwang gtask = &ctx->ifc_admin_task; 4399*a9643ea8Slogwang tqg = qgroup_if_config_tqg; 4400*a9643ea8Slogwang rid = -1; 4401*a9643ea8Slogwang fn = _task_fn_admin; 4402*a9643ea8Slogwang break; 4403*a9643ea8Slogwang case IFLIB_INTR_IOV: 4404*a9643ea8Slogwang q = ctx; 4405*a9643ea8Slogwang gtask = &ctx->ifc_vflr_task; 4406*a9643ea8Slogwang tqg = qgroup_if_config_tqg; 4407*a9643ea8Slogwang rid = -1; 4408*a9643ea8Slogwang fn = _task_fn_iov; 4409*a9643ea8Slogwang break; 4410*a9643ea8Slogwang default: 4411*a9643ea8Slogwang panic("unknown net intr type"); 4412*a9643ea8Slogwang } 4413*a9643ea8Slogwang GROUPTASK_INIT(gtask, 0, fn, q); 4414*a9643ea8Slogwang taskqgroup_attach(tqg, gtask, q, rid, name); 4415*a9643ea8Slogwang } 4416*a9643ea8Slogwang 4417*a9643ea8Slogwang void 4418*a9643ea8Slogwang iflib_irq_free(if_ctx_t ctx, if_irq_t irq) 4419*a9643ea8Slogwang { 4420*a9643ea8Slogwang if (irq->ii_tag) 4421*a9643ea8Slogwang bus_teardown_intr(ctx->ifc_dev, irq->ii_res, irq->ii_tag); 4422*a9643ea8Slogwang 4423*a9643ea8Slogwang if (irq->ii_res) 4424*a9643ea8Slogwang bus_release_resource(ctx->ifc_dev, SYS_RES_IRQ, irq->ii_rid, irq->ii_res); 4425*a9643ea8Slogwang } 4426*a9643ea8Slogwang 4427*a9643ea8Slogwang static int 4428*a9643ea8Slogwang iflib_legacy_setup(if_ctx_t ctx, driver_filter_t filter, void *filter_arg, int *rid, char *name) 4429*a9643ea8Slogwang { 4430*a9643ea8Slogwang iflib_txq_t txq = ctx->ifc_txqs; 4431*a9643ea8Slogwang iflib_rxq_t rxq = ctx->ifc_rxqs; 4432*a9643ea8Slogwang if_irq_t irq = &ctx->ifc_legacy_irq; 4433*a9643ea8Slogwang iflib_filter_info_t info; 4434*a9643ea8Slogwang struct grouptask *gtask; 4435*a9643ea8Slogwang struct taskqgroup *tqg; 4436*a9643ea8Slogwang gtask_fn_t *fn; 4437*a9643ea8Slogwang int tqrid; 4438*a9643ea8Slogwang void *q; 4439*a9643ea8Slogwang int err; 4440*a9643ea8Slogwang 4441*a9643ea8Slogwang q = &ctx->ifc_rxqs[0]; 4442*a9643ea8Slogwang info = &rxq[0].ifr_filter_info; 4443*a9643ea8Slogwang gtask = &rxq[0].ifr_task; 4444*a9643ea8Slogwang tqg = qgroup_if_io_tqg; 4445*a9643ea8Slogwang tqrid = irq->ii_rid = *rid; 4446*a9643ea8Slogwang fn = _task_fn_rx; 4447*a9643ea8Slogwang 4448*a9643ea8Slogwang ctx->ifc_flags |= IFC_LEGACY; 4449*a9643ea8Slogwang info->ifi_filter = filter; 4450*a9643ea8Slogwang info->ifi_filter_arg = filter_arg; 4451*a9643ea8Slogwang info->ifi_task = gtask; 4452*a9643ea8Slogwang 4453*a9643ea8Slogwang /* We allocate a single interrupt resource */ 4454*a9643ea8Slogwang if ((err = _iflib_irq_alloc(ctx, irq, tqrid, iflib_fast_intr, NULL, info, name)) != 0) 4455*a9643ea8Slogwang return (err); 4456*a9643ea8Slogwang GROUPTASK_INIT(gtask, 0, fn, q); 4457*a9643ea8Slogwang taskqgroup_attach(tqg, gtask, q, tqrid, name); 4458*a9643ea8Slogwang 4459*a9643ea8Slogwang GROUPTASK_INIT(&txq->ift_task, 0, _task_fn_tx, txq); 4460*a9643ea8Slogwang taskqgroup_attach(qgroup_if_io_tqg, &txq->ift_task, txq, tqrid, "tx"); 4461*a9643ea8Slogwang GROUPTASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx); 4462*a9643ea8Slogwang taskqgroup_attach(qgroup_if_config_tqg, &ctx->ifc_admin_task, ctx, -1, "admin/link"); 4463*a9643ea8Slogwang 4464*a9643ea8Slogwang return (0); 4465*a9643ea8Slogwang } 4466*a9643ea8Slogwang 4467*a9643ea8Slogwang void 4468*a9643ea8Slogwang iflib_led_create(if_ctx_t ctx) 4469*a9643ea8Slogwang { 4470*a9643ea8Slogwang 4471*a9643ea8Slogwang ctx->ifc_led_dev = led_create(iflib_led_func, ctx, 4472*a9643ea8Slogwang device_get_nameunit(ctx->ifc_dev)); 4473*a9643ea8Slogwang } 4474*a9643ea8Slogwang 4475*a9643ea8Slogwang void 4476*a9643ea8Slogwang iflib_tx_intr_deferred(if_ctx_t ctx, int txqid) 4477*a9643ea8Slogwang { 4478*a9643ea8Slogwang 4479*a9643ea8Slogwang GROUPTASK_ENQUEUE(&ctx->ifc_txqs[txqid].ift_task); 4480*a9643ea8Slogwang } 4481*a9643ea8Slogwang 4482*a9643ea8Slogwang void 4483*a9643ea8Slogwang iflib_rx_intr_deferred(if_ctx_t ctx, int rxqid) 4484*a9643ea8Slogwang { 4485*a9643ea8Slogwang 4486*a9643ea8Slogwang GROUPTASK_ENQUEUE(&ctx->ifc_rxqs[rxqid].ifr_task); 4487*a9643ea8Slogwang } 4488*a9643ea8Slogwang 4489*a9643ea8Slogwang void 4490*a9643ea8Slogwang iflib_admin_intr_deferred(if_ctx_t ctx) 4491*a9643ea8Slogwang { 4492*a9643ea8Slogwang 4493*a9643ea8Slogwang GROUPTASK_ENQUEUE(&ctx->ifc_admin_task); 4494*a9643ea8Slogwang } 4495*a9643ea8Slogwang 4496*a9643ea8Slogwang void 4497*a9643ea8Slogwang iflib_iov_intr_deferred(if_ctx_t ctx) 4498*a9643ea8Slogwang { 4499*a9643ea8Slogwang 4500*a9643ea8Slogwang GROUPTASK_ENQUEUE(&ctx->ifc_vflr_task); 4501*a9643ea8Slogwang } 4502*a9643ea8Slogwang 4503*a9643ea8Slogwang void 4504*a9643ea8Slogwang iflib_io_tqg_attach(struct grouptask *gt, void *uniq, int cpu, char *name) 4505*a9643ea8Slogwang { 4506*a9643ea8Slogwang 4507*a9643ea8Slogwang taskqgroup_attach_cpu(qgroup_if_io_tqg, gt, uniq, cpu, -1, name); 4508*a9643ea8Slogwang } 4509*a9643ea8Slogwang 4510*a9643ea8Slogwang void 4511*a9643ea8Slogwang iflib_config_gtask_init(if_ctx_t ctx, struct grouptask *gtask, gtask_fn_t *fn, 4512*a9643ea8Slogwang char *name) 4513*a9643ea8Slogwang { 4514*a9643ea8Slogwang 4515*a9643ea8Slogwang GROUPTASK_INIT(gtask, 0, fn, ctx); 4516*a9643ea8Slogwang taskqgroup_attach(qgroup_if_config_tqg, gtask, gtask, -1, name); 4517*a9643ea8Slogwang } 4518*a9643ea8Slogwang 4519*a9643ea8Slogwang void 4520*a9643ea8Slogwang iflib_config_gtask_deinit(struct grouptask *gtask) 4521*a9643ea8Slogwang { 4522*a9643ea8Slogwang 4523*a9643ea8Slogwang taskqgroup_detach(qgroup_if_config_tqg, gtask); 4524*a9643ea8Slogwang } 4525*a9643ea8Slogwang 4526*a9643ea8Slogwang void 4527*a9643ea8Slogwang iflib_link_state_change(if_ctx_t ctx, int link_state, uint64_t baudrate) 4528*a9643ea8Slogwang { 4529*a9643ea8Slogwang if_t ifp = ctx->ifc_ifp; 4530*a9643ea8Slogwang iflib_txq_t txq = ctx->ifc_txqs; 4531*a9643ea8Slogwang 4532*a9643ea8Slogwang 4533*a9643ea8Slogwang if_setbaudrate(ifp, baudrate); 4534*a9643ea8Slogwang 4535*a9643ea8Slogwang /* If link down, disable watchdog */ 4536*a9643ea8Slogwang if ((ctx->ifc_link_state == LINK_STATE_UP) && (link_state == LINK_STATE_DOWN)) { 4537*a9643ea8Slogwang for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxqsets; i++, txq++) 4538*a9643ea8Slogwang txq->ift_qstatus = IFLIB_QUEUE_IDLE; 4539*a9643ea8Slogwang } 4540*a9643ea8Slogwang ctx->ifc_link_state = link_state; 4541*a9643ea8Slogwang if_link_state_change(ifp, link_state); 4542*a9643ea8Slogwang } 4543*a9643ea8Slogwang 4544*a9643ea8Slogwang static int 4545*a9643ea8Slogwang iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq) 4546*a9643ea8Slogwang { 4547*a9643ea8Slogwang int credits; 4548*a9643ea8Slogwang 4549*a9643ea8Slogwang if (ctx->isc_txd_credits_update == NULL) 4550*a9643ea8Slogwang return (0); 4551*a9643ea8Slogwang 4552*a9643ea8Slogwang if ((credits = ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, txq->ift_cidx_processed, true)) == 0) 4553*a9643ea8Slogwang return (0); 4554*a9643ea8Slogwang 4555*a9643ea8Slogwang txq->ift_processed += credits; 4556*a9643ea8Slogwang txq->ift_cidx_processed += credits; 4557*a9643ea8Slogwang 4558*a9643ea8Slogwang if (txq->ift_cidx_processed >= txq->ift_size) 4559*a9643ea8Slogwang txq->ift_cidx_processed -= txq->ift_size; 4560*a9643ea8Slogwang return (credits); 4561*a9643ea8Slogwang } 4562*a9643ea8Slogwang 4563*a9643ea8Slogwang static int 4564*a9643ea8Slogwang iflib_rxd_avail(if_ctx_t ctx, iflib_rxq_t rxq, int cidx, int budget) 4565*a9643ea8Slogwang { 4566*a9643ea8Slogwang 4567*a9643ea8Slogwang return (ctx->isc_rxd_available(ctx->ifc_softc, rxq->ifr_id, cidx, 4568*a9643ea8Slogwang budget)); 4569*a9643ea8Slogwang } 4570*a9643ea8Slogwang 4571*a9643ea8Slogwang void 4572*a9643ea8Slogwang iflib_add_int_delay_sysctl(if_ctx_t ctx, const char *name, 4573*a9643ea8Slogwang const char *description, if_int_delay_info_t info, 4574*a9643ea8Slogwang int offset, int value) 4575*a9643ea8Slogwang { 4576*a9643ea8Slogwang info->iidi_ctx = ctx; 4577*a9643ea8Slogwang info->iidi_offset = offset; 4578*a9643ea8Slogwang info->iidi_value = value; 4579*a9643ea8Slogwang SYSCTL_ADD_PROC(device_get_sysctl_ctx(ctx->ifc_dev), 4580*a9643ea8Slogwang SYSCTL_CHILDREN(device_get_sysctl_tree(ctx->ifc_dev)), 4581*a9643ea8Slogwang OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, 4582*a9643ea8Slogwang info, 0, iflib_sysctl_int_delay, "I", description); 4583*a9643ea8Slogwang } 4584*a9643ea8Slogwang 4585*a9643ea8Slogwang struct mtx * 4586*a9643ea8Slogwang iflib_ctx_lock_get(if_ctx_t ctx) 4587*a9643ea8Slogwang { 4588*a9643ea8Slogwang 4589*a9643ea8Slogwang return (&ctx->ifc_mtx); 4590*a9643ea8Slogwang } 4591*a9643ea8Slogwang 4592*a9643ea8Slogwang static int 4593*a9643ea8Slogwang iflib_msix_init(if_ctx_t ctx) 4594*a9643ea8Slogwang { 4595*a9643ea8Slogwang device_t dev = ctx->ifc_dev; 4596*a9643ea8Slogwang if_shared_ctx_t sctx = ctx->ifc_sctx; 4597*a9643ea8Slogwang if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; 4598*a9643ea8Slogwang int vectors, queues, rx_queues, tx_queues, queuemsgs, msgs; 4599*a9643ea8Slogwang int iflib_num_tx_queues, iflib_num_rx_queues; 4600*a9643ea8Slogwang int err, admincnt, bar; 4601*a9643ea8Slogwang 4602*a9643ea8Slogwang iflib_num_tx_queues = scctx->isc_ntxqsets; 4603*a9643ea8Slogwang iflib_num_rx_queues = scctx->isc_nrxqsets; 4604*a9643ea8Slogwang 4605*a9643ea8Slogwang bar = ctx->ifc_softc_ctx.isc_msix_bar; 4606*a9643ea8Slogwang admincnt = sctx->isc_admin_intrcnt; 4607*a9643ea8Slogwang /* Override by tuneable */ 4608*a9643ea8Slogwang if (enable_msix == 0) 4609*a9643ea8Slogwang goto msi; 4610*a9643ea8Slogwang 4611*a9643ea8Slogwang /* 4612*a9643ea8Slogwang ** When used in a virtualized environment 4613*a9643ea8Slogwang ** PCI BUSMASTER capability may not be set 4614*a9643ea8Slogwang ** so explicity set it here and rewrite 4615*a9643ea8Slogwang ** the ENABLE in the MSIX control register 4616*a9643ea8Slogwang ** at this point to cause the host to 4617*a9643ea8Slogwang ** successfully initialize us. 4618*a9643ea8Slogwang */ 4619*a9643ea8Slogwang { 4620*a9643ea8Slogwang uint16_t pci_cmd_word; 4621*a9643ea8Slogwang int msix_ctrl, rid; 4622*a9643ea8Slogwang 4623*a9643ea8Slogwang rid = 0; 4624*a9643ea8Slogwang pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); 4625*a9643ea8Slogwang pci_cmd_word |= PCIM_CMD_BUSMASTEREN; 4626*a9643ea8Slogwang pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); 4627*a9643ea8Slogwang pci_find_cap(dev, PCIY_MSIX, &rid); 4628*a9643ea8Slogwang rid += PCIR_MSIX_CTRL; 4629*a9643ea8Slogwang msix_ctrl = pci_read_config(dev, rid, 2); 4630*a9643ea8Slogwang msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; 4631*a9643ea8Slogwang pci_write_config(dev, rid, msix_ctrl, 2); 4632*a9643ea8Slogwang } 4633*a9643ea8Slogwang 4634*a9643ea8Slogwang /* 4635*a9643ea8Slogwang * bar == -1 => "trust me I know what I'm doing" 4636*a9643ea8Slogwang * https://www.youtube.com/watch?v=nnwWKkNau4I 4637*a9643ea8Slogwang * Some drivers are for hardware that is so shoddily 4638*a9643ea8Slogwang * documented that no one knows which bars are which 4639*a9643ea8Slogwang * so the developer has to map all bars. This hack 4640*a9643ea8Slogwang * allows shoddy garbage to use msix in this framework. 4641*a9643ea8Slogwang */ 4642*a9643ea8Slogwang if (bar != -1) { 4643*a9643ea8Slogwang ctx->ifc_msix_mem = bus_alloc_resource_any(dev, 4644*a9643ea8Slogwang SYS_RES_MEMORY, &bar, RF_ACTIVE); 4645*a9643ea8Slogwang if (ctx->ifc_msix_mem == NULL) { 4646*a9643ea8Slogwang /* May not be enabled */ 4647*a9643ea8Slogwang device_printf(dev, "Unable to map MSIX table \n"); 4648*a9643ea8Slogwang goto msi; 4649*a9643ea8Slogwang } 4650*a9643ea8Slogwang } 4651*a9643ea8Slogwang /* First try MSI/X */ 4652*a9643ea8Slogwang if ((msgs = pci_msix_count(dev)) == 0) { /* system has msix disabled */ 4653*a9643ea8Slogwang device_printf(dev, "System has MSIX disabled \n"); 4654*a9643ea8Slogwang bus_release_resource(dev, SYS_RES_MEMORY, 4655*a9643ea8Slogwang bar, ctx->ifc_msix_mem); 4656*a9643ea8Slogwang ctx->ifc_msix_mem = NULL; 4657*a9643ea8Slogwang goto msi; 4658*a9643ea8Slogwang } 4659*a9643ea8Slogwang #if IFLIB_DEBUG 4660*a9643ea8Slogwang /* use only 1 qset in debug mode */ 4661*a9643ea8Slogwang queuemsgs = min(msgs - admincnt, 1); 4662*a9643ea8Slogwang #else 4663*a9643ea8Slogwang queuemsgs = msgs - admincnt; 4664*a9643ea8Slogwang #endif 4665*a9643ea8Slogwang if (bus_get_cpus(dev, INTR_CPUS, sizeof(ctx->ifc_cpus), &ctx->ifc_cpus) == 0) { 4666*a9643ea8Slogwang #ifdef RSS 4667*a9643ea8Slogwang queues = imin(queuemsgs, rss_getnumbuckets()); 4668*a9643ea8Slogwang #else 4669*a9643ea8Slogwang queues = queuemsgs; 4670*a9643ea8Slogwang #endif 4671*a9643ea8Slogwang queues = imin(CPU_COUNT(&ctx->ifc_cpus), queues); 4672*a9643ea8Slogwang device_printf(dev, "pxm cpus: %d queue msgs: %d admincnt: %d\n", 4673*a9643ea8Slogwang CPU_COUNT(&ctx->ifc_cpus), queuemsgs, admincnt); 4674*a9643ea8Slogwang } else { 4675*a9643ea8Slogwang device_printf(dev, "Unable to fetch CPU list\n"); 4676*a9643ea8Slogwang /* Figure out a reasonable auto config value */ 4677*a9643ea8Slogwang queues = min(queuemsgs, mp_ncpus); 4678*a9643ea8Slogwang } 4679*a9643ea8Slogwang #ifdef RSS 4680*a9643ea8Slogwang /* If we're doing RSS, clamp at the number of RSS buckets */ 4681*a9643ea8Slogwang if (queues > rss_getnumbuckets()) 4682*a9643ea8Slogwang queues = rss_getnumbuckets(); 4683*a9643ea8Slogwang #endif 4684*a9643ea8Slogwang if (iflib_num_rx_queues > 0 && iflib_num_rx_queues < queuemsgs - admincnt) 4685*a9643ea8Slogwang rx_queues = iflib_num_rx_queues; 4686*a9643ea8Slogwang else 4687*a9643ea8Slogwang rx_queues = queues; 4688*a9643ea8Slogwang /* 4689*a9643ea8Slogwang * We want this to be all logical CPUs by default 4690*a9643ea8Slogwang */ 4691*a9643ea8Slogwang if (iflib_num_tx_queues > 0 && iflib_num_tx_queues < queues) 4692*a9643ea8Slogwang tx_queues = iflib_num_tx_queues; 4693*a9643ea8Slogwang else 4694*a9643ea8Slogwang tx_queues = mp_ncpus; 4695*a9643ea8Slogwang 4696*a9643ea8Slogwang if (ctx->ifc_sysctl_qs_eq_override == 0) { 4697*a9643ea8Slogwang #ifdef INVARIANTS 4698*a9643ea8Slogwang if (tx_queues != rx_queues) 4699*a9643ea8Slogwang device_printf(dev, "queue equality override not set, capping rx_queues at %d and tx_queues at %d\n", 4700*a9643ea8Slogwang min(rx_queues, tx_queues), min(rx_queues, tx_queues)); 4701*a9643ea8Slogwang #endif 4702*a9643ea8Slogwang tx_queues = min(rx_queues, tx_queues); 4703*a9643ea8Slogwang rx_queues = min(rx_queues, tx_queues); 4704*a9643ea8Slogwang } 4705*a9643ea8Slogwang 4706*a9643ea8Slogwang device_printf(dev, "using %d rx queues %d tx queues \n", rx_queues, tx_queues); 4707*a9643ea8Slogwang 4708*a9643ea8Slogwang vectors = rx_queues + admincnt; 4709*a9643ea8Slogwang if ((err = pci_alloc_msix(dev, &vectors)) == 0) { 4710*a9643ea8Slogwang device_printf(dev, 4711*a9643ea8Slogwang "Using MSIX interrupts with %d vectors\n", vectors); 4712*a9643ea8Slogwang scctx->isc_vectors = vectors; 4713*a9643ea8Slogwang scctx->isc_nrxqsets = rx_queues; 4714*a9643ea8Slogwang scctx->isc_ntxqsets = tx_queues; 4715*a9643ea8Slogwang scctx->isc_intr = IFLIB_INTR_MSIX; 4716*a9643ea8Slogwang 4717*a9643ea8Slogwang return (vectors); 4718*a9643ea8Slogwang } else { 4719*a9643ea8Slogwang device_printf(dev, "failed to allocate %d msix vectors, err: %d - using MSI\n", vectors, err); 4720*a9643ea8Slogwang } 4721*a9643ea8Slogwang msi: 4722*a9643ea8Slogwang vectors = pci_msi_count(dev); 4723*a9643ea8Slogwang scctx->isc_nrxqsets = 1; 4724*a9643ea8Slogwang scctx->isc_ntxqsets = 1; 4725*a9643ea8Slogwang scctx->isc_vectors = vectors; 4726*a9643ea8Slogwang if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) { 4727*a9643ea8Slogwang device_printf(dev,"Using an MSI interrupt\n"); 4728*a9643ea8Slogwang scctx->isc_intr = IFLIB_INTR_MSI; 4729*a9643ea8Slogwang } else { 4730*a9643ea8Slogwang device_printf(dev,"Using a Legacy interrupt\n"); 4731*a9643ea8Slogwang scctx->isc_intr = IFLIB_INTR_LEGACY; 4732*a9643ea8Slogwang } 4733*a9643ea8Slogwang 4734*a9643ea8Slogwang return (vectors); 4735*a9643ea8Slogwang } 4736*a9643ea8Slogwang 4737*a9643ea8Slogwang char * ring_states[] = { "IDLE", "BUSY", "STALLED", "ABDICATED" }; 4738*a9643ea8Slogwang 4739*a9643ea8Slogwang static int 4740*a9643ea8Slogwang mp_ring_state_handler(SYSCTL_HANDLER_ARGS) 4741*a9643ea8Slogwang { 4742*a9643ea8Slogwang int rc; 4743*a9643ea8Slogwang uint16_t *state = ((uint16_t *)oidp->oid_arg1); 4744*a9643ea8Slogwang struct sbuf *sb; 4745*a9643ea8Slogwang char *ring_state = "UNKNOWN"; 4746*a9643ea8Slogwang 4747*a9643ea8Slogwang /* XXX needed ? */ 4748*a9643ea8Slogwang rc = sysctl_wire_old_buffer(req, 0); 4749*a9643ea8Slogwang MPASS(rc == 0); 4750*a9643ea8Slogwang if (rc != 0) 4751*a9643ea8Slogwang return (rc); 4752*a9643ea8Slogwang sb = sbuf_new_for_sysctl(NULL, NULL, 80, req); 4753*a9643ea8Slogwang MPASS(sb != NULL); 4754*a9643ea8Slogwang if (sb == NULL) 4755*a9643ea8Slogwang return (ENOMEM); 4756*a9643ea8Slogwang if (state[3] <= 3) 4757*a9643ea8Slogwang ring_state = ring_states[state[3]]; 4758*a9643ea8Slogwang 4759*a9643ea8Slogwang sbuf_printf(sb, "pidx_head: %04hd pidx_tail: %04hd cidx: %04hd state: %s", 4760*a9643ea8Slogwang state[0], state[1], state[2], ring_state); 4761*a9643ea8Slogwang rc = sbuf_finish(sb); 4762*a9643ea8Slogwang sbuf_delete(sb); 4763*a9643ea8Slogwang return(rc); 4764*a9643ea8Slogwang } 4765*a9643ea8Slogwang 4766*a9643ea8Slogwang enum iflib_ndesc_handler { 4767*a9643ea8Slogwang IFLIB_NTXD_HANDLER, 4768*a9643ea8Slogwang IFLIB_NRXD_HANDLER, 4769*a9643ea8Slogwang }; 4770*a9643ea8Slogwang 4771*a9643ea8Slogwang static int 4772*a9643ea8Slogwang mp_ndesc_handler(SYSCTL_HANDLER_ARGS) 4773*a9643ea8Slogwang { 4774*a9643ea8Slogwang if_ctx_t ctx = (void *)arg1; 4775*a9643ea8Slogwang enum iflib_ndesc_handler type = arg2; 4776*a9643ea8Slogwang char buf[256] = {0}; 4777*a9643ea8Slogwang uint16_t *ndesc; 4778*a9643ea8Slogwang char *p, *next; 4779*a9643ea8Slogwang int nqs, rc, i; 4780*a9643ea8Slogwang 4781*a9643ea8Slogwang MPASS(type == IFLIB_NTXD_HANDLER || type == IFLIB_NRXD_HANDLER); 4782*a9643ea8Slogwang 4783*a9643ea8Slogwang nqs = 8; 4784*a9643ea8Slogwang switch(type) { 4785*a9643ea8Slogwang case IFLIB_NTXD_HANDLER: 4786*a9643ea8Slogwang ndesc = ctx->ifc_sysctl_ntxds; 4787*a9643ea8Slogwang if (ctx->ifc_sctx) 4788*a9643ea8Slogwang nqs = ctx->ifc_sctx->isc_ntxqs; 4789*a9643ea8Slogwang break; 4790*a9643ea8Slogwang case IFLIB_NRXD_HANDLER: 4791*a9643ea8Slogwang ndesc = ctx->ifc_sysctl_nrxds; 4792*a9643ea8Slogwang if (ctx->ifc_sctx) 4793*a9643ea8Slogwang nqs = ctx->ifc_sctx->isc_nrxqs; 4794*a9643ea8Slogwang break; 4795*a9643ea8Slogwang } 4796*a9643ea8Slogwang if (nqs == 0) 4797*a9643ea8Slogwang nqs = 8; 4798*a9643ea8Slogwang 4799*a9643ea8Slogwang for (i=0; i<8; i++) { 4800*a9643ea8Slogwang if (i >= nqs) 4801*a9643ea8Slogwang break; 4802*a9643ea8Slogwang if (i) 4803*a9643ea8Slogwang strcat(buf, ","); 4804*a9643ea8Slogwang sprintf(strchr(buf, 0), "%d", ndesc[i]); 4805*a9643ea8Slogwang } 4806*a9643ea8Slogwang 4807*a9643ea8Slogwang rc = sysctl_handle_string(oidp, buf, sizeof(buf), req); 4808*a9643ea8Slogwang if (rc || req->newptr == NULL) 4809*a9643ea8Slogwang return rc; 4810*a9643ea8Slogwang 4811*a9643ea8Slogwang for (i = 0, next = buf, p = strsep(&next, " ,"); i < 8 && p; 4812*a9643ea8Slogwang i++, p = strsep(&next, " ,")) { 4813*a9643ea8Slogwang ndesc[i] = strtoul(p, NULL, 10); 4814*a9643ea8Slogwang } 4815*a9643ea8Slogwang 4816*a9643ea8Slogwang return(rc); 4817*a9643ea8Slogwang } 4818*a9643ea8Slogwang 4819*a9643ea8Slogwang #define NAME_BUFLEN 32 4820*a9643ea8Slogwang static void 4821*a9643ea8Slogwang iflib_add_device_sysctl_pre(if_ctx_t ctx) 4822*a9643ea8Slogwang { 4823*a9643ea8Slogwang device_t dev = iflib_get_dev(ctx); 4824*a9643ea8Slogwang struct sysctl_oid_list *child, *oid_list; 4825*a9643ea8Slogwang struct sysctl_ctx_list *ctx_list; 4826*a9643ea8Slogwang struct sysctl_oid *node; 4827*a9643ea8Slogwang 4828*a9643ea8Slogwang ctx_list = device_get_sysctl_ctx(dev); 4829*a9643ea8Slogwang child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 4830*a9643ea8Slogwang ctx->ifc_sysctl_node = node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, "iflib", 4831*a9643ea8Slogwang CTLFLAG_RD, NULL, "IFLIB fields"); 4832*a9643ea8Slogwang oid_list = SYSCTL_CHILDREN(node); 4833*a9643ea8Slogwang 4834*a9643ea8Slogwang SYSCTL_ADD_STRING(ctx_list, oid_list, OID_AUTO, "driver_version", 4835*a9643ea8Slogwang CTLFLAG_RD, ctx->ifc_sctx->isc_driver_version, 0, 4836*a9643ea8Slogwang "driver version"); 4837*a9643ea8Slogwang 4838*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_ntxqs", 4839*a9643ea8Slogwang CTLFLAG_RWTUN, &ctx->ifc_sysctl_ntxqs, 0, 4840*a9643ea8Slogwang "# of txqs to use, 0 => use default #"); 4841*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_nrxqs", 4842*a9643ea8Slogwang CTLFLAG_RWTUN, &ctx->ifc_sysctl_nrxqs, 0, 4843*a9643ea8Slogwang "# of rxqs to use, 0 => use default #"); 4844*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_qs_enable", 4845*a9643ea8Slogwang CTLFLAG_RWTUN, &ctx->ifc_sysctl_qs_eq_override, 0, 4846*a9643ea8Slogwang "permit #txq != #rxq"); 4847*a9643ea8Slogwang 4848*a9643ea8Slogwang /* XXX change for per-queue sizes */ 4849*a9643ea8Slogwang SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_ntxds", 4850*a9643ea8Slogwang CTLTYPE_STRING|CTLFLAG_RWTUN, ctx, IFLIB_NTXD_HANDLER, 4851*a9643ea8Slogwang mp_ndesc_handler, "A", 4852*a9643ea8Slogwang "list of # of tx descriptors to use, 0 = use default #"); 4853*a9643ea8Slogwang SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_nrxds", 4854*a9643ea8Slogwang CTLTYPE_STRING|CTLFLAG_RWTUN, ctx, IFLIB_NRXD_HANDLER, 4855*a9643ea8Slogwang mp_ndesc_handler, "A", 4856*a9643ea8Slogwang "list of # of rx descriptors to use, 0 = use default #"); 4857*a9643ea8Slogwang } 4858*a9643ea8Slogwang 4859*a9643ea8Slogwang static void 4860*a9643ea8Slogwang iflib_add_device_sysctl_post(if_ctx_t ctx) 4861*a9643ea8Slogwang { 4862*a9643ea8Slogwang if_shared_ctx_t sctx = ctx->ifc_sctx; 4863*a9643ea8Slogwang if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; 4864*a9643ea8Slogwang device_t dev = iflib_get_dev(ctx); 4865*a9643ea8Slogwang struct sysctl_oid_list *child; 4866*a9643ea8Slogwang struct sysctl_ctx_list *ctx_list; 4867*a9643ea8Slogwang iflib_fl_t fl; 4868*a9643ea8Slogwang iflib_txq_t txq; 4869*a9643ea8Slogwang iflib_rxq_t rxq; 4870*a9643ea8Slogwang int i, j; 4871*a9643ea8Slogwang char namebuf[NAME_BUFLEN]; 4872*a9643ea8Slogwang char *qfmt; 4873*a9643ea8Slogwang struct sysctl_oid *queue_node, *fl_node, *node; 4874*a9643ea8Slogwang struct sysctl_oid_list *queue_list, *fl_list; 4875*a9643ea8Slogwang ctx_list = device_get_sysctl_ctx(dev); 4876*a9643ea8Slogwang 4877*a9643ea8Slogwang node = ctx->ifc_sysctl_node; 4878*a9643ea8Slogwang child = SYSCTL_CHILDREN(node); 4879*a9643ea8Slogwang 4880*a9643ea8Slogwang if (scctx->isc_ntxqsets > 100) 4881*a9643ea8Slogwang qfmt = "txq%03d"; 4882*a9643ea8Slogwang else if (scctx->isc_ntxqsets > 10) 4883*a9643ea8Slogwang qfmt = "txq%02d"; 4884*a9643ea8Slogwang else 4885*a9643ea8Slogwang qfmt = "txq%d"; 4886*a9643ea8Slogwang for (i = 0, txq = ctx->ifc_txqs; i < scctx->isc_ntxqsets; i++, txq++) { 4887*a9643ea8Slogwang snprintf(namebuf, NAME_BUFLEN, qfmt, i); 4888*a9643ea8Slogwang queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf, 4889*a9643ea8Slogwang CTLFLAG_RD, NULL, "Queue Name"); 4890*a9643ea8Slogwang queue_list = SYSCTL_CHILDREN(queue_node); 4891*a9643ea8Slogwang #if MEMORY_LOGGING 4892*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_dequeued", 4893*a9643ea8Slogwang CTLFLAG_RD, 4894*a9643ea8Slogwang &txq->ift_dequeued, "total mbufs freed"); 4895*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_enqueued", 4896*a9643ea8Slogwang CTLFLAG_RD, 4897*a9643ea8Slogwang &txq->ift_enqueued, "total mbufs enqueued"); 4898*a9643ea8Slogwang #endif 4899*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "mbuf_defrag", 4900*a9643ea8Slogwang CTLFLAG_RD, 4901*a9643ea8Slogwang &txq->ift_mbuf_defrag, "# of times m_defrag was called"); 4902*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "m_pullups", 4903*a9643ea8Slogwang CTLFLAG_RD, 4904*a9643ea8Slogwang &txq->ift_pullups, "# of times m_pullup was called"); 4905*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "mbuf_defrag_failed", 4906*a9643ea8Slogwang CTLFLAG_RD, 4907*a9643ea8Slogwang &txq->ift_mbuf_defrag_failed, "# of times m_defrag failed"); 4908*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "no_desc_avail", 4909*a9643ea8Slogwang CTLFLAG_RD, 4910*a9643ea8Slogwang &txq->ift_no_desc_avail, "# of times no descriptors were available"); 4911*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "tx_map_failed", 4912*a9643ea8Slogwang CTLFLAG_RD, 4913*a9643ea8Slogwang &txq->ift_map_failed, "# of times dma map failed"); 4914*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txd_encap_efbig", 4915*a9643ea8Slogwang CTLFLAG_RD, 4916*a9643ea8Slogwang &txq->ift_txd_encap_efbig, "# of times txd_encap returned EFBIG"); 4917*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "no_tx_dma_setup", 4918*a9643ea8Slogwang CTLFLAG_RD, 4919*a9643ea8Slogwang &txq->ift_no_tx_dma_setup, "# of times map failed for other than EFBIG"); 4920*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_pidx", 4921*a9643ea8Slogwang CTLFLAG_RD, 4922*a9643ea8Slogwang &txq->ift_pidx, 1, "Producer Index"); 4923*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_cidx", 4924*a9643ea8Slogwang CTLFLAG_RD, 4925*a9643ea8Slogwang &txq->ift_cidx, 1, "Consumer Index"); 4926*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_cidx_processed", 4927*a9643ea8Slogwang CTLFLAG_RD, 4928*a9643ea8Slogwang &txq->ift_cidx_processed, 1, "Consumer Index seen by credit update"); 4929*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_in_use", 4930*a9643ea8Slogwang CTLFLAG_RD, 4931*a9643ea8Slogwang &txq->ift_in_use, 1, "descriptors in use"); 4932*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_processed", 4933*a9643ea8Slogwang CTLFLAG_RD, 4934*a9643ea8Slogwang &txq->ift_processed, "descriptors procesed for clean"); 4935*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_cleaned", 4936*a9643ea8Slogwang CTLFLAG_RD, 4937*a9643ea8Slogwang &txq->ift_cleaned, "total cleaned"); 4938*a9643ea8Slogwang SYSCTL_ADD_PROC(ctx_list, queue_list, OID_AUTO, "ring_state", 4939*a9643ea8Slogwang CTLTYPE_STRING | CTLFLAG_RD, __DEVOLATILE(uint64_t *, &txq->ift_br[0]->state), 4940*a9643ea8Slogwang 0, mp_ring_state_handler, "A", "soft ring state"); 4941*a9643ea8Slogwang SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_enqueues", 4942*a9643ea8Slogwang CTLFLAG_RD, &txq->ift_br[0]->enqueues, 4943*a9643ea8Slogwang "# of enqueues to the mp_ring for this queue"); 4944*a9643ea8Slogwang SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_drops", 4945*a9643ea8Slogwang CTLFLAG_RD, &txq->ift_br[0]->drops, 4946*a9643ea8Slogwang "# of drops in the mp_ring for this queue"); 4947*a9643ea8Slogwang SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_starts", 4948*a9643ea8Slogwang CTLFLAG_RD, &txq->ift_br[0]->starts, 4949*a9643ea8Slogwang "# of normal consumer starts in the mp_ring for this queue"); 4950*a9643ea8Slogwang SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_stalls", 4951*a9643ea8Slogwang CTLFLAG_RD, &txq->ift_br[0]->stalls, 4952*a9643ea8Slogwang "# of consumer stalls in the mp_ring for this queue"); 4953*a9643ea8Slogwang SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_restarts", 4954*a9643ea8Slogwang CTLFLAG_RD, &txq->ift_br[0]->restarts, 4955*a9643ea8Slogwang "# of consumer restarts in the mp_ring for this queue"); 4956*a9643ea8Slogwang SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_abdications", 4957*a9643ea8Slogwang CTLFLAG_RD, &txq->ift_br[0]->abdications, 4958*a9643ea8Slogwang "# of consumer abdications in the mp_ring for this queue"); 4959*a9643ea8Slogwang 4960*a9643ea8Slogwang } 4961*a9643ea8Slogwang 4962*a9643ea8Slogwang if (scctx->isc_nrxqsets > 100) 4963*a9643ea8Slogwang qfmt = "rxq%03d"; 4964*a9643ea8Slogwang else if (scctx->isc_nrxqsets > 10) 4965*a9643ea8Slogwang qfmt = "rxq%02d"; 4966*a9643ea8Slogwang else 4967*a9643ea8Slogwang qfmt = "rxq%d"; 4968*a9643ea8Slogwang for (i = 0, rxq = ctx->ifc_rxqs; i < scctx->isc_nrxqsets; i++, rxq++) { 4969*a9643ea8Slogwang snprintf(namebuf, NAME_BUFLEN, qfmt, i); 4970*a9643ea8Slogwang queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf, 4971*a9643ea8Slogwang CTLFLAG_RD, NULL, "Queue Name"); 4972*a9643ea8Slogwang queue_list = SYSCTL_CHILDREN(queue_node); 4973*a9643ea8Slogwang if (sctx->isc_flags & IFLIB_HAS_RXCQ) { 4974*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "rxq_cq_pidx", 4975*a9643ea8Slogwang CTLFLAG_RD, 4976*a9643ea8Slogwang &rxq->ifr_cq_pidx, 1, "Producer Index"); 4977*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "rxq_cq_cidx", 4978*a9643ea8Slogwang CTLFLAG_RD, 4979*a9643ea8Slogwang &rxq->ifr_cq_cidx, 1, "Consumer Index"); 4980*a9643ea8Slogwang } 4981*a9643ea8Slogwang for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) { 4982*a9643ea8Slogwang snprintf(namebuf, NAME_BUFLEN, "rxq_fl%d", j); 4983*a9643ea8Slogwang fl_node = SYSCTL_ADD_NODE(ctx_list, queue_list, OID_AUTO, namebuf, 4984*a9643ea8Slogwang CTLFLAG_RD, NULL, "freelist Name"); 4985*a9643ea8Slogwang fl_list = SYSCTL_CHILDREN(fl_node); 4986*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "pidx", 4987*a9643ea8Slogwang CTLFLAG_RD, 4988*a9643ea8Slogwang &fl->ifl_pidx, 1, "Producer Index"); 4989*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "cidx", 4990*a9643ea8Slogwang CTLFLAG_RD, 4991*a9643ea8Slogwang &fl->ifl_cidx, 1, "Consumer Index"); 4992*a9643ea8Slogwang SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "credits", 4993*a9643ea8Slogwang CTLFLAG_RD, 4994*a9643ea8Slogwang &fl->ifl_credits, 1, "credits available"); 4995*a9643ea8Slogwang #if MEMORY_LOGGING 4996*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_m_enqueued", 4997*a9643ea8Slogwang CTLFLAG_RD, 4998*a9643ea8Slogwang &fl->ifl_m_enqueued, "mbufs allocated"); 4999*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_m_dequeued", 5000*a9643ea8Slogwang CTLFLAG_RD, 5001*a9643ea8Slogwang &fl->ifl_m_dequeued, "mbufs freed"); 5002*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_cl_enqueued", 5003*a9643ea8Slogwang CTLFLAG_RD, 5004*a9643ea8Slogwang &fl->ifl_cl_enqueued, "clusters allocated"); 5005*a9643ea8Slogwang SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_cl_dequeued", 5006*a9643ea8Slogwang CTLFLAG_RD, 5007*a9643ea8Slogwang &fl->ifl_cl_dequeued, "clusters freed"); 5008*a9643ea8Slogwang #endif 5009*a9643ea8Slogwang 5010*a9643ea8Slogwang } 5011*a9643ea8Slogwang } 5012*a9643ea8Slogwang 5013*a9643ea8Slogwang } 5014