14c7070dbSScott Long /*-
27b610b60SSean Bruno * Copyright (c) 2014-2018, Matthew Macy <mmacy@mattmacy.io>
34c7070dbSScott Long * All rights reserved.
44c7070dbSScott Long *
54c7070dbSScott Long * Redistribution and use in source and binary forms, with or without
64c7070dbSScott Long * modification, are permitted provided that the following conditions are met:
74c7070dbSScott Long *
84c7070dbSScott Long * 1. Redistributions of source code must retain the above copyright notice,
94c7070dbSScott Long * this list of conditions and the following disclaimer.
104c7070dbSScott Long *
114c7070dbSScott Long * 2. Neither the name of Matthew Macy nor the names of its
124c7070dbSScott Long * contributors may be used to endorse or promote products derived from
134c7070dbSScott Long * this software without specific prior written permission.
144c7070dbSScott Long *
154c7070dbSScott Long * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
164c7070dbSScott Long * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
174c7070dbSScott Long * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
184c7070dbSScott Long * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
194c7070dbSScott Long * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
204c7070dbSScott Long * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
214c7070dbSScott Long * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
224c7070dbSScott Long * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
234c7070dbSScott Long * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
244c7070dbSScott Long * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
254c7070dbSScott Long * POSSIBILITY OF SUCH DAMAGE.
264c7070dbSScott Long */
274c7070dbSScott Long
284c7070dbSScott Long #include <sys/cdefs.h>
29aaeb188aSBjoern A. Zeeb #include "opt_inet.h"
30aaeb188aSBjoern A. Zeeb #include "opt_inet6.h"
31aaeb188aSBjoern A. Zeeb #include "opt_acpi.h"
32b103855eSStephen Hurd #include "opt_sched.h"
33aaeb188aSBjoern A. Zeeb
344c7070dbSScott Long #include <sys/param.h>
354c7070dbSScott Long #include <sys/types.h>
364c7070dbSScott Long #include <sys/bus.h>
374c7070dbSScott Long #include <sys/eventhandler.h>
384c7070dbSScott Long #include <sys/kernel.h>
394c7070dbSScott Long #include <sys/lock.h>
404c7070dbSScott Long #include <sys/mutex.h>
414c7070dbSScott Long #include <sys/module.h>
424c7070dbSScott Long #include <sys/kobj.h>
434c7070dbSScott Long #include <sys/rman.h>
444c7070dbSScott Long #include <sys/sbuf.h>
454c7070dbSScott Long #include <sys/smp.h>
464c7070dbSScott Long #include <sys/socket.h>
4709f6ff4fSMatt Macy #include <sys/sockio.h>
484c7070dbSScott Long #include <sys/sysctl.h>
494c7070dbSScott Long #include <sys/syslog.h>
504c7070dbSScott Long #include <sys/taskqueue.h>
5123ac9029SStephen Hurd #include <sys/limits.h>
524c7070dbSScott Long
534c7070dbSScott Long #include <net/if.h>
544c7070dbSScott Long #include <net/if_var.h>
552c2b37adSJustin Hibbits #include <net/if_private.h>
564c7070dbSScott Long #include <net/if_types.h>
574c7070dbSScott Long #include <net/if_media.h>
584c7070dbSScott Long #include <net/bpf.h>
594c7070dbSScott Long #include <net/ethernet.h>
604c7070dbSScott Long #include <net/mp_ring.h>
617790c8c1SConrad Meyer #include <net/debugnet.h>
626d49b41eSAndrew Gallatin #include <net/pfil.h>
6335e4e998SStephen Hurd #include <net/vnet.h>
644c7070dbSScott Long
654c7070dbSScott Long #include <netinet/in.h>
664c7070dbSScott Long #include <netinet/in_pcb.h>
674c7070dbSScott Long #include <netinet/tcp_lro.h>
684c7070dbSScott Long #include <netinet/in_systm.h>
694c7070dbSScott Long #include <netinet/if_ether.h>
704c7070dbSScott Long #include <netinet/ip.h>
714c7070dbSScott Long #include <netinet/ip6.h>
724c7070dbSScott Long #include <netinet/tcp.h>
7335e4e998SStephen Hurd #include <netinet/ip_var.h>
7435e4e998SStephen Hurd #include <netinet6/ip6_var.h>
754c7070dbSScott Long
764c7070dbSScott Long #include <machine/bus.h>
774c7070dbSScott Long #include <machine/in_cksum.h>
784c7070dbSScott Long
794c7070dbSScott Long #include <vm/vm.h>
804c7070dbSScott Long #include <vm/pmap.h>
814c7070dbSScott Long
824c7070dbSScott Long #include <dev/led/led.h>
834c7070dbSScott Long #include <dev/pci/pcireg.h>
844c7070dbSScott Long #include <dev/pci/pcivar.h>
854c7070dbSScott Long #include <dev/pci/pci_private.h>
864c7070dbSScott Long
874c7070dbSScott Long #include <net/iflib.h>
884c7070dbSScott Long
894c7070dbSScott Long #include "ifdi_if.h"
904c7070dbSScott Long
9177c1fcecSEric Joyner #ifdef PCI_IOV
9277c1fcecSEric Joyner #include <dev/pci/pci_iov.h>
9377c1fcecSEric Joyner #endif
9477c1fcecSEric Joyner
9587890dbaSSean Bruno #include <sys/bitstring.h>
964c7070dbSScott Long /*
9795246abbSSean Bruno * enable accounting of every mbuf as it comes in to and goes out of
9895246abbSSean Bruno * iflib's software descriptor references
994c7070dbSScott Long */
1004c7070dbSScott Long #define MEMORY_LOGGING 0
1014c7070dbSScott Long /*
1024c7070dbSScott Long * Enable mbuf vectors for compressing long mbuf chains
1034c7070dbSScott Long */
1044c7070dbSScott Long
1054c7070dbSScott Long /*
1064c7070dbSScott Long * NB:
1074c7070dbSScott Long * - Prefetching in tx cleaning should perhaps be a tunable. The distance ahead
1084c7070dbSScott Long * we prefetch needs to be determined by the time spent in m_free vis a vis
1094c7070dbSScott Long * the cost of a prefetch. This will of course vary based on the workload:
1104c7070dbSScott Long * - NFLX's m_free path is dominated by vm-based M_EXT manipulation which
1114c7070dbSScott Long * is quite expensive, thus suggesting very little prefetch.
1124c7070dbSScott Long * - small packet forwarding which is just returning a single mbuf to
1134c7070dbSScott Long * UMA will typically be very fast vis a vis the cost of a memory
1144c7070dbSScott Long * access.
1154c7070dbSScott Long */
1164c7070dbSScott Long
1174c7070dbSScott Long /*
1184c7070dbSScott Long * File organization:
1194c7070dbSScott Long * - private structures
1204c7070dbSScott Long * - iflib private utility functions
1214c7070dbSScott Long * - ifnet functions
1224c7070dbSScott Long * - vlan registry and other exported functions
1234c7070dbSScott Long * - iflib public core functions
1244c7070dbSScott Long *
1254c7070dbSScott Long *
1264c7070dbSScott Long */
1277ff9ae90SMarius Strobl static MALLOC_DEFINE(M_IFLIB, "iflib", "ifnet library");
1284c7070dbSScott Long
129fb1a29b4SHans Petter Selasky #define IFLIB_RXEOF_MORE (1U << 0)
130fb1a29b4SHans Petter Selasky #define IFLIB_RXEOF_EMPTY (2U << 0)
131fb1a29b4SHans Petter Selasky
1324c7070dbSScott Long struct iflib_txq;
1334c7070dbSScott Long typedef struct iflib_txq *iflib_txq_t;
1344c7070dbSScott Long struct iflib_rxq;
1354c7070dbSScott Long typedef struct iflib_rxq *iflib_rxq_t;
1364c7070dbSScott Long struct iflib_fl;
1374c7070dbSScott Long typedef struct iflib_fl *iflib_fl_t;
1384c7070dbSScott Long
1394ecb427aSSean Bruno struct iflib_ctx;
1404ecb427aSSean Bruno
1412d873474SStephen Hurd static void iru_init(if_rxd_update_t iru, iflib_rxq_t rxq, uint8_t flid);
142dd7fbcf1SStephen Hurd static void iflib_timer(void *arg);
14310254019SMark Johnston static void iflib_tqg_detach(if_ctx_t ctx);
1442d873474SStephen Hurd
1454c7070dbSScott Long typedef struct iflib_filter_info {
1464c7070dbSScott Long driver_filter_t *ifi_filter;
1474c7070dbSScott Long void *ifi_filter_arg;
1484c7070dbSScott Long struct grouptask *ifi_task;
14995246abbSSean Bruno void *ifi_ctx;
1504c7070dbSScott Long } *iflib_filter_info_t;
1514c7070dbSScott Long
1524c7070dbSScott Long struct iflib_ctx {
1534c7070dbSScott Long KOBJ_FIELDS;
1544c7070dbSScott Long /*
1554c7070dbSScott Long * Pointer to hardware driver's softc
1564c7070dbSScott Long */
1574c7070dbSScott Long void *ifc_softc;
1584c7070dbSScott Long device_t ifc_dev;
1594c7070dbSScott Long if_t ifc_ifp;
1604c7070dbSScott Long
1614c7070dbSScott Long cpuset_t ifc_cpus;
1624c7070dbSScott Long if_shared_ctx_t ifc_sctx;
1634c7070dbSScott Long struct if_softc_ctx ifc_softc_ctx;
1644c7070dbSScott Long
165aa8a24d3SStephen Hurd struct sx ifc_ctx_sx;
1667b610b60SSean Bruno struct mtx ifc_state_mtx;
1674c7070dbSScott Long
1684c7070dbSScott Long iflib_txq_t ifc_txqs;
1694c7070dbSScott Long iflib_rxq_t ifc_rxqs;
1704c7070dbSScott Long uint32_t ifc_if_flags;
1714c7070dbSScott Long uint32_t ifc_flags;
1724c7070dbSScott Long uint32_t ifc_max_fl_buf_size;
1731b9d9394SEric Joyner uint32_t ifc_rx_mbuf_sz;
1744c7070dbSScott Long
1754c7070dbSScott Long int ifc_link_state;
1764c7070dbSScott Long int ifc_watchdog_events;
1774c7070dbSScott Long struct cdev *ifc_led_dev;
1784c7070dbSScott Long struct resource *ifc_msix_mem;
1794c7070dbSScott Long
1804c7070dbSScott Long struct if_irq ifc_legacy_irq;
1814c7070dbSScott Long struct grouptask ifc_admin_task;
1824c7070dbSScott Long struct grouptask ifc_vflr_task;
1834c7070dbSScott Long struct iflib_filter_info ifc_filter_info;
1844c7070dbSScott Long struct ifmedia ifc_media;
185e2621d96SMatt Macy struct ifmedia *ifc_mediap;
1864c7070dbSScott Long
1874c7070dbSScott Long struct sysctl_oid *ifc_sysctl_node;
1884c7070dbSScott Long uint16_t ifc_sysctl_ntxqs;
1894c7070dbSScott Long uint16_t ifc_sysctl_nrxqs;
19023ac9029SStephen Hurd uint16_t ifc_sysctl_qs_eq_override;
191f4d2154eSStephen Hurd uint16_t ifc_sysctl_rx_budget;
192fe51d4cdSStephen Hurd uint16_t ifc_sysctl_tx_abdicate;
193f154ece0SStephen Hurd uint16_t ifc_sysctl_core_offset;
194f154ece0SStephen Hurd #define CORE_OFFSET_UNSPECIFIED 0xffff
195f154ece0SStephen Hurd uint8_t ifc_sysctl_separate_txrx;
196ca7005f1SPatrick Kelsey uint8_t ifc_sysctl_use_logical_cores;
1973c7da27aSEric Joyner uint16_t ifc_sysctl_extra_msix_vectors;
198ca7005f1SPatrick Kelsey bool ifc_cpus_are_physical_cores;
19923ac9029SStephen Hurd
20095246abbSSean Bruno qidx_t ifc_sysctl_ntxds[8];
20195246abbSSean Bruno qidx_t ifc_sysctl_nrxds[8];
2024c7070dbSScott Long struct if_txrx ifc_txrx;
2034c7070dbSScott Long #define isc_txd_encap ifc_txrx.ift_txd_encap
2044c7070dbSScott Long #define isc_txd_flush ifc_txrx.ift_txd_flush
2054c7070dbSScott Long #define isc_txd_credits_update ifc_txrx.ift_txd_credits_update
2064c7070dbSScott Long #define isc_rxd_available ifc_txrx.ift_rxd_available
2074c7070dbSScott Long #define isc_rxd_pkt_get ifc_txrx.ift_rxd_pkt_get
2084c7070dbSScott Long #define isc_rxd_refill ifc_txrx.ift_rxd_refill
2094c7070dbSScott Long #define isc_rxd_flush ifc_txrx.ift_rxd_flush
2104c7070dbSScott Long #define isc_legacy_intr ifc_txrx.ift_legacy_intr
211213e9139SEric Joyner #define isc_txq_select ifc_txrx.ift_txq_select
2129c950139SEric Joyner #define isc_txq_select_v2 ifc_txrx.ift_txq_select_v2
2137f527d48SEric Joyner
2144c7070dbSScott Long eventhandler_tag ifc_vlan_attach_event;
2154c7070dbSScott Long eventhandler_tag ifc_vlan_detach_event;
2161fd8c72cSKyle Evans struct ether_addr ifc_mac;
2174c7070dbSScott Long };
2184c7070dbSScott Long
2194c7070dbSScott Long void *
iflib_get_softc(if_ctx_t ctx)2204c7070dbSScott Long iflib_get_softc(if_ctx_t ctx)
2214c7070dbSScott Long {
2224c7070dbSScott Long
2234c7070dbSScott Long return (ctx->ifc_softc);
2244c7070dbSScott Long }
2254c7070dbSScott Long
2264c7070dbSScott Long device_t
iflib_get_dev(if_ctx_t ctx)2274c7070dbSScott Long iflib_get_dev(if_ctx_t ctx)
2284c7070dbSScott Long {
2294c7070dbSScott Long
2304c7070dbSScott Long return (ctx->ifc_dev);
2314c7070dbSScott Long }
2324c7070dbSScott Long
2334c7070dbSScott Long if_t
iflib_get_ifp(if_ctx_t ctx)2344c7070dbSScott Long iflib_get_ifp(if_ctx_t ctx)
2354c7070dbSScott Long {
2364c7070dbSScott Long
2374c7070dbSScott Long return (ctx->ifc_ifp);
2384c7070dbSScott Long }
2394c7070dbSScott Long
2404c7070dbSScott Long struct ifmedia *
iflib_get_media(if_ctx_t ctx)2414c7070dbSScott Long iflib_get_media(if_ctx_t ctx)
2424c7070dbSScott Long {
2434c7070dbSScott Long
244e2621d96SMatt Macy return (ctx->ifc_mediap);
2454c7070dbSScott Long }
2464c7070dbSScott Long
24709f6ff4fSMatt Macy void
iflib_set_mac(if_ctx_t ctx,uint8_t mac[ETHER_ADDR_LEN])2484c7070dbSScott Long iflib_set_mac(if_ctx_t ctx, uint8_t mac[ETHER_ADDR_LEN])
2494c7070dbSScott Long {
2504c7070dbSScott Long
2511fd8c72cSKyle Evans bcopy(mac, ctx->ifc_mac.octet, ETHER_ADDR_LEN);
2524c7070dbSScott Long }
2534c7070dbSScott Long
2544c7070dbSScott Long if_softc_ctx_t
iflib_get_softc_ctx(if_ctx_t ctx)2554c7070dbSScott Long iflib_get_softc_ctx(if_ctx_t ctx)
2564c7070dbSScott Long {
2574c7070dbSScott Long
2584c7070dbSScott Long return (&ctx->ifc_softc_ctx);
2594c7070dbSScott Long }
2604c7070dbSScott Long
2614c7070dbSScott Long if_shared_ctx_t
iflib_get_sctx(if_ctx_t ctx)2624c7070dbSScott Long iflib_get_sctx(if_ctx_t ctx)
2634c7070dbSScott Long {
2644c7070dbSScott Long
2654c7070dbSScott Long return (ctx->ifc_sctx);
2664c7070dbSScott Long }
2674c7070dbSScott Long
2683c7da27aSEric Joyner uint16_t
iflib_get_extra_msix_vectors_sysctl(if_ctx_t ctx)2693c7da27aSEric Joyner iflib_get_extra_msix_vectors_sysctl(if_ctx_t ctx)
2703c7da27aSEric Joyner {
2713c7da27aSEric Joyner
2723c7da27aSEric Joyner return (ctx->ifc_sysctl_extra_msix_vectors);
2733c7da27aSEric Joyner }
2743c7da27aSEric Joyner
27595246abbSSean Bruno #define IP_ALIGNED(m) ((((uintptr_t)(m)->m_data) & 0x3) == 0x2)
2764c7070dbSScott Long #define CACHE_PTR_INCREMENT (CACHE_LINE_SIZE / sizeof(void *))
2775e888388SSean Bruno #define CACHE_PTR_NEXT(ptr) ((void *)(((uintptr_t)(ptr) + CACHE_LINE_SIZE - 1) & (CACHE_LINE_SIZE - 1)))
2784c7070dbSScott Long
2794c7070dbSScott Long #define LINK_ACTIVE(ctx) ((ctx)->ifc_link_state == LINK_STATE_UP)
2804c7070dbSScott Long #define CTX_IS_VF(ctx) ((ctx)->ifc_sctx->isc_flags & IFLIB_IS_VF)
2814c7070dbSScott Long
282e035717eSSean Bruno typedef struct iflib_sw_rx_desc_array {
283e035717eSSean Bruno bus_dmamap_t *ifsd_map; /* bus_dma maps for packet */
284e035717eSSean Bruno struct mbuf **ifsd_m; /* pkthdr mbufs */
285e035717eSSean Bruno caddr_t *ifsd_cl; /* direct cluster pointer for rx */
286fbec776dSAndrew Gallatin bus_addr_t *ifsd_ba; /* bus addr of cluster for rx */
287e035717eSSean Bruno } iflib_rxsd_array_t;
2884c7070dbSScott Long
2894c7070dbSScott Long typedef struct iflib_sw_tx_desc_array {
2904c7070dbSScott Long bus_dmamap_t *ifsd_map; /* bus_dma maps for packet */
2918a04b53dSKonstantin Belousov bus_dmamap_t *ifsd_tso_map; /* bus_dma maps for TSO packet */
2924c7070dbSScott Long struct mbuf **ifsd_m; /* pkthdr mbufs */
29395246abbSSean Bruno } if_txsd_vec_t;
2944c7070dbSScott Long
2954c7070dbSScott Long /* magic number that should be high enough for any hardware */
2964c7070dbSScott Long #define IFLIB_MAX_TX_SEGS 128
29795246abbSSean Bruno #define IFLIB_RX_COPY_THRESH 128
2984c7070dbSScott Long #define IFLIB_MAX_RX_REFRESH 32
29995246abbSSean Bruno /* The minimum descriptors per second before we start coalescing */
30095246abbSSean Bruno #define IFLIB_MIN_DESC_SEC 16384
30195246abbSSean Bruno #define IFLIB_DEFAULT_TX_UPDATE_FREQ 16
3024c7070dbSScott Long #define IFLIB_QUEUE_IDLE 0
3034c7070dbSScott Long #define IFLIB_QUEUE_HUNG 1
3044c7070dbSScott Long #define IFLIB_QUEUE_WORKING 2
30595246abbSSean Bruno /* maximum number of txqs that can share an rx interrupt */
30695246abbSSean Bruno #define IFLIB_MAX_TX_SHARED_INTR 4
3074c7070dbSScott Long
30895246abbSSean Bruno /* this should really scale with ring size - this is a fairly arbitrary value */
30995246abbSSean Bruno #define TX_BATCH_SIZE 32
3104c7070dbSScott Long
3114c7070dbSScott Long #define IFLIB_RESTART_BUDGET 8
3124c7070dbSScott Long
3137ff9ae90SMarius Strobl #define IFC_LEGACY 0x001
3147ff9ae90SMarius Strobl #define IFC_QFLUSH 0x002
3157ff9ae90SMarius Strobl #define IFC_MULTISEG 0x004
3167ff9ae90SMarius Strobl #define IFC_SPARE1 0x008
3177ff9ae90SMarius Strobl #define IFC_SC_ALLOCATED 0x010
3187ff9ae90SMarius Strobl #define IFC_INIT_DONE 0x020
3197ff9ae90SMarius Strobl #define IFC_PREFETCH 0x040
3207ff9ae90SMarius Strobl #define IFC_DO_RESET 0x080
3217ff9ae90SMarius Strobl #define IFC_DO_WATCHDOG 0x100
3227ff9ae90SMarius Strobl #define IFC_SPARE0 0x200
3237ff9ae90SMarius Strobl #define IFC_SPARE2 0x400
3247ff9ae90SMarius Strobl #define IFC_IN_DETACH 0x800
3257ff9ae90SMarius Strobl
3267ff9ae90SMarius Strobl #define IFC_NETMAP_TX_IRQ 0x80000000
3277ff9ae90SMarius Strobl
3284c7070dbSScott Long #define CSUM_OFFLOAD (CSUM_IP_TSO | CSUM_IP6_TSO | CSUM_IP | \
3294c7070dbSScott Long CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP_SCTP | \
3304c7070dbSScott Long CSUM_IP6_UDP | CSUM_IP6_TCP | CSUM_IP6_SCTP)
3311722eeacSMarius Strobl
3324c7070dbSScott Long struct iflib_txq {
33395246abbSSean Bruno qidx_t ift_in_use;
33495246abbSSean Bruno qidx_t ift_cidx;
33595246abbSSean Bruno qidx_t ift_cidx_processed;
33695246abbSSean Bruno qidx_t ift_pidx;
3374c7070dbSScott Long uint8_t ift_gen;
33823ac9029SStephen Hurd uint8_t ift_br_offset;
33995246abbSSean Bruno uint16_t ift_npending;
34095246abbSSean Bruno uint16_t ift_db_pending;
34195246abbSSean Bruno uint16_t ift_rs_pending;
3424c7070dbSScott Long /* implicit pad */
34395246abbSSean Bruno uint8_t ift_txd_size[8];
3444c7070dbSScott Long uint64_t ift_processed;
3454c7070dbSScott Long uint64_t ift_cleaned;
34695246abbSSean Bruno uint64_t ift_cleaned_prev;
3474c7070dbSScott Long #if MEMORY_LOGGING
3484c7070dbSScott Long uint64_t ift_enqueued;
3494c7070dbSScott Long uint64_t ift_dequeued;
3504c7070dbSScott Long #endif
3514c7070dbSScott Long uint64_t ift_no_tx_dma_setup;
3524c7070dbSScott Long uint64_t ift_no_desc_avail;
3534c7070dbSScott Long uint64_t ift_mbuf_defrag_failed;
3544c7070dbSScott Long uint64_t ift_mbuf_defrag;
3554c7070dbSScott Long uint64_t ift_map_failed;
3564c7070dbSScott Long uint64_t ift_txd_encap_efbig;
3574c7070dbSScott Long uint64_t ift_pullups;
358618d49f5SAlexander Motin uint64_t ift_last_timer_tick;
3594c7070dbSScott Long
3604c7070dbSScott Long struct mtx ift_mtx;
3614c7070dbSScott Long struct mtx ift_db_mtx;
3624c7070dbSScott Long
3634c7070dbSScott Long /* constant values */
3644c7070dbSScott Long if_ctx_t ift_ctx;
36595246abbSSean Bruno struct ifmp_ring *ift_br;
3664c7070dbSScott Long struct grouptask ift_task;
36795246abbSSean Bruno qidx_t ift_size;
3684c7070dbSScott Long uint16_t ift_id;
3694c7070dbSScott Long struct callout ift_timer;
37017cec474SVincenzo Maffione #ifdef DEV_NETMAP
37117cec474SVincenzo Maffione struct callout ift_netmap_timer;
37217cec474SVincenzo Maffione #endif /* DEV_NETMAP */
3734c7070dbSScott Long
37495246abbSSean Bruno if_txsd_vec_t ift_sds;
3754c7070dbSScott Long uint8_t ift_qstatus;
3764c7070dbSScott Long uint8_t ift_closed;
37795246abbSSean Bruno uint8_t ift_update_freq;
3784c7070dbSScott Long struct iflib_filter_info ift_filter_info;
379bfce461eSMarius Strobl bus_dma_tag_t ift_buf_tag;
380bfce461eSMarius Strobl bus_dma_tag_t ift_tso_buf_tag;
3814c7070dbSScott Long iflib_dma_info_t ift_ifdi;
382814fa34dSMark Johnston #define MTX_NAME_LEN 32
3834c7070dbSScott Long char ift_mtx_name[MTX_NAME_LEN];
3844c7070dbSScott Long bus_dma_segment_t ift_segs[IFLIB_MAX_TX_SEGS] __aligned(CACHE_LINE_SIZE);
3851248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
3861248952aSSean Bruno uint64_t ift_cpu_exec_count[256];
3871248952aSSean Bruno #endif
3884c7070dbSScott Long } __aligned(CACHE_LINE_SIZE);
3894c7070dbSScott Long
3904c7070dbSScott Long struct iflib_fl {
39195246abbSSean Bruno qidx_t ifl_cidx;
39295246abbSSean Bruno qidx_t ifl_pidx;
39395246abbSSean Bruno qidx_t ifl_credits;
3944c7070dbSScott Long uint8_t ifl_gen;
39595246abbSSean Bruno uint8_t ifl_rxd_size;
3964c7070dbSScott Long #if MEMORY_LOGGING
3974c7070dbSScott Long uint64_t ifl_m_enqueued;
3984c7070dbSScott Long uint64_t ifl_m_dequeued;
3994c7070dbSScott Long uint64_t ifl_cl_enqueued;
4004c7070dbSScott Long uint64_t ifl_cl_dequeued;
4014c7070dbSScott Long #endif
4024c7070dbSScott Long /* implicit pad */
40387890dbaSSean Bruno bitstr_t *ifl_rx_bitmap;
40487890dbaSSean Bruno qidx_t ifl_fragidx;
4054c7070dbSScott Long /* constant */
40695246abbSSean Bruno qidx_t ifl_size;
4074c7070dbSScott Long uint16_t ifl_buf_size;
4084c7070dbSScott Long uint16_t ifl_cltype;
4094c7070dbSScott Long uma_zone_t ifl_zone;
410e035717eSSean Bruno iflib_rxsd_array_t ifl_sds;
4114c7070dbSScott Long iflib_rxq_t ifl_rxq;
4124c7070dbSScott Long uint8_t ifl_id;
413bfce461eSMarius Strobl bus_dma_tag_t ifl_buf_tag;
4144c7070dbSScott Long iflib_dma_info_t ifl_ifdi;
4154c7070dbSScott Long uint64_t ifl_bus_addrs[IFLIB_MAX_RX_REFRESH] __aligned(CACHE_LINE_SIZE);
41695246abbSSean Bruno qidx_t ifl_rxd_idxs[IFLIB_MAX_RX_REFRESH];
4174c7070dbSScott Long } __aligned(CACHE_LINE_SIZE);
4184c7070dbSScott Long
41995246abbSSean Bruno static inline qidx_t
get_inuse(int size,qidx_t cidx,qidx_t pidx,uint8_t gen)42095246abbSSean Bruno get_inuse(int size, qidx_t cidx, qidx_t pidx, uint8_t gen)
4214c7070dbSScott Long {
42295246abbSSean Bruno qidx_t used;
4234c7070dbSScott Long
4244c7070dbSScott Long if (pidx > cidx)
4254c7070dbSScott Long used = pidx - cidx;
4264c7070dbSScott Long else if (pidx < cidx)
4274c7070dbSScott Long used = size - cidx + pidx;
4284c7070dbSScott Long else if (gen == 0 && pidx == cidx)
4294c7070dbSScott Long used = 0;
4304c7070dbSScott Long else if (gen == 1 && pidx == cidx)
4314c7070dbSScott Long used = size;
4324c7070dbSScott Long else
4334c7070dbSScott Long panic("bad state");
4344c7070dbSScott Long
4354c7070dbSScott Long return (used);
4364c7070dbSScott Long }
4374c7070dbSScott Long
4384c7070dbSScott Long #define TXQ_AVAIL(txq) (txq->ift_size - get_inuse(txq->ift_size, txq->ift_cidx, txq->ift_pidx, txq->ift_gen))
4394c7070dbSScott Long
4404c7070dbSScott Long #define IDXDIFF(head, tail, wrap) \
4414c7070dbSScott Long ((head) >= (tail) ? (head) - (tail) : (wrap) - (tail) + (head))
4424c7070dbSScott Long
4434c7070dbSScott Long struct iflib_rxq {
4444c7070dbSScott Long if_ctx_t ifr_ctx;
4454c7070dbSScott Long iflib_fl_t ifr_fl;
4464c7070dbSScott Long uint64_t ifr_rx_irq;
4476d49b41eSAndrew Gallatin struct pfil_head *pfil;
4481722eeacSMarius Strobl /*
4491722eeacSMarius Strobl * If there is a separate completion queue (IFLIB_HAS_RXCQ), this is
4506d84e76aSVincenzo Maffione * the completion queue consumer index. Otherwise it's unused.
4511722eeacSMarius Strobl */
4521722eeacSMarius Strobl qidx_t ifr_cq_cidx;
4534c7070dbSScott Long uint16_t ifr_id;
4544c7070dbSScott Long uint8_t ifr_nfl;
45595246abbSSean Bruno uint8_t ifr_ntxqirq;
45695246abbSSean Bruno uint8_t ifr_txqid[IFLIB_MAX_TX_SHARED_INTR];
4571722eeacSMarius Strobl uint8_t ifr_fl_offset;
4584c7070dbSScott Long struct lro_ctrl ifr_lc;
4594c7070dbSScott Long struct grouptask ifr_task;
460fb1a29b4SHans Petter Selasky struct callout ifr_watchdog;
4614c7070dbSScott Long struct iflib_filter_info ifr_filter_info;
4624c7070dbSScott Long iflib_dma_info_t ifr_ifdi;
463ab2e3f79SStephen Hurd
4644c7070dbSScott Long /* dynamically allocate if any drivers need a value substantially larger than this */
4654c7070dbSScott Long struct if_rxd_frag ifr_frags[IFLIB_MAX_RX_SEGS] __aligned(CACHE_LINE_SIZE);
4661248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
4671248952aSSean Bruno uint64_t ifr_cpu_exec_count[256];
4681248952aSSean Bruno #endif
4694c7070dbSScott Long } __aligned(CACHE_LINE_SIZE);
4704c7070dbSScott Long
47195246abbSSean Bruno typedef struct if_rxsd {
47295246abbSSean Bruno caddr_t *ifsd_cl;
47395246abbSSean Bruno iflib_fl_t ifsd_fl;
47495246abbSSean Bruno } *if_rxsd_t;
47595246abbSSean Bruno
47695246abbSSean Bruno /* multiple of word size */
47795246abbSSean Bruno #ifdef __LP64__
478ab2e3f79SStephen Hurd #define PKT_INFO_SIZE 6
47995246abbSSean Bruno #define RXD_INFO_SIZE 5
48095246abbSSean Bruno #define PKT_TYPE uint64_t
48195246abbSSean Bruno #else
482ab2e3f79SStephen Hurd #define PKT_INFO_SIZE 11
48395246abbSSean Bruno #define RXD_INFO_SIZE 8
48495246abbSSean Bruno #define PKT_TYPE uint32_t
48595246abbSSean Bruno #endif
48695246abbSSean Bruno #define PKT_LOOP_BOUND ((PKT_INFO_SIZE / 3) * 3)
48795246abbSSean Bruno #define RXD_LOOP_BOUND ((RXD_INFO_SIZE / 4) * 4)
48895246abbSSean Bruno
48995246abbSSean Bruno typedef struct if_pkt_info_pad {
49095246abbSSean Bruno PKT_TYPE pkt_val[PKT_INFO_SIZE];
49195246abbSSean Bruno } *if_pkt_info_pad_t;
49295246abbSSean Bruno typedef struct if_rxd_info_pad {
49395246abbSSean Bruno PKT_TYPE rxd_val[RXD_INFO_SIZE];
49495246abbSSean Bruno } *if_rxd_info_pad_t;
49595246abbSSean Bruno
49695246abbSSean Bruno CTASSERT(sizeof(struct if_pkt_info_pad) == sizeof(struct if_pkt_info));
49795246abbSSean Bruno CTASSERT(sizeof(struct if_rxd_info_pad) == sizeof(struct if_rxd_info));
49895246abbSSean Bruno
49995246abbSSean Bruno static inline void
pkt_info_zero(if_pkt_info_t pi)50095246abbSSean Bruno pkt_info_zero(if_pkt_info_t pi)
50195246abbSSean Bruno {
50295246abbSSean Bruno if_pkt_info_pad_t pi_pad;
50395246abbSSean Bruno
50495246abbSSean Bruno pi_pad = (if_pkt_info_pad_t)pi;
50595246abbSSean Bruno pi_pad->pkt_val[0] = 0; pi_pad->pkt_val[1] = 0; pi_pad->pkt_val[2] = 0;
50695246abbSSean Bruno pi_pad->pkt_val[3] = 0; pi_pad->pkt_val[4] = 0; pi_pad->pkt_val[5] = 0;
50795246abbSSean Bruno #ifndef __LP64__
508ab2e3f79SStephen Hurd pi_pad->pkt_val[6] = 0; pi_pad->pkt_val[7] = 0; pi_pad->pkt_val[8] = 0;
509ab2e3f79SStephen Hurd pi_pad->pkt_val[9] = 0; pi_pad->pkt_val[10] = 0;
51095246abbSSean Bruno #endif
51195246abbSSean Bruno }
51295246abbSSean Bruno
51395246abbSSean Bruno static inline void
rxd_info_zero(if_rxd_info_t ri)51495246abbSSean Bruno rxd_info_zero(if_rxd_info_t ri)
51595246abbSSean Bruno {
51695246abbSSean Bruno if_rxd_info_pad_t ri_pad;
51795246abbSSean Bruno int i;
51895246abbSSean Bruno
51995246abbSSean Bruno ri_pad = (if_rxd_info_pad_t)ri;
52095246abbSSean Bruno for (i = 0; i < RXD_LOOP_BOUND; i += 4) {
52195246abbSSean Bruno ri_pad->rxd_val[i] = 0;
52295246abbSSean Bruno ri_pad->rxd_val[i + 1] = 0;
52395246abbSSean Bruno ri_pad->rxd_val[i + 2] = 0;
52495246abbSSean Bruno ri_pad->rxd_val[i + 3] = 0;
52595246abbSSean Bruno }
52695246abbSSean Bruno #ifdef __LP64__
52795246abbSSean Bruno ri_pad->rxd_val[RXD_INFO_SIZE - 1] = 0;
52895246abbSSean Bruno #endif
52995246abbSSean Bruno }
53095246abbSSean Bruno
5314c7070dbSScott Long /*
5324c7070dbSScott Long * Only allow a single packet to take up most 1/nth of the tx ring
5334c7070dbSScott Long */
5344c7070dbSScott Long #define MAX_SINGLE_PACKET_FRACTION 12
535fa7045f9SZhenlei Huang #define IF_BAD_DMA ((bus_addr_t)-1)
5364c7070dbSScott Long
5374c7070dbSScott Long #define CTX_ACTIVE(ctx) ((if_getdrvflags((ctx)->ifc_ifp) & IFF_DRV_RUNNING))
5384c7070dbSScott Long
539aa8a24d3SStephen Hurd #define CTX_LOCK_INIT(_sc) sx_init(&(_sc)->ifc_ctx_sx, "iflib ctx lock")
540aa8a24d3SStephen Hurd #define CTX_LOCK(ctx) sx_xlock(&(ctx)->ifc_ctx_sx)
541aa8a24d3SStephen Hurd #define CTX_UNLOCK(ctx) sx_xunlock(&(ctx)->ifc_ctx_sx)
542aa8a24d3SStephen Hurd #define CTX_LOCK_DESTROY(ctx) sx_destroy(&(ctx)->ifc_ctx_sx)
5434c7070dbSScott Long
5447b610b60SSean Bruno #define STATE_LOCK_INIT(_sc, _name) mtx_init(&(_sc)->ifc_state_mtx, _name, "iflib state lock", MTX_DEF)
5457b610b60SSean Bruno #define STATE_LOCK(ctx) mtx_lock(&(ctx)->ifc_state_mtx)
5467b610b60SSean Bruno #define STATE_UNLOCK(ctx) mtx_unlock(&(ctx)->ifc_state_mtx)
5477b610b60SSean Bruno #define STATE_LOCK_DESTROY(ctx) mtx_destroy(&(ctx)->ifc_state_mtx)
5487b610b60SSean Bruno
5494c7070dbSScott Long #define CALLOUT_LOCK(txq) mtx_lock(&txq->ift_mtx)
5504c7070dbSScott Long #define CALLOUT_UNLOCK(txq) mtx_unlock(&txq->ift_mtx)
5514c7070dbSScott Long
5524c7070dbSScott Long /* Our boot-time initialization hook */
5534c7070dbSScott Long static int iflib_module_event_handler(module_t, int, void *);
5544c7070dbSScott Long
5554c7070dbSScott Long static moduledata_t iflib_moduledata = {
5564c7070dbSScott Long "iflib",
5574c7070dbSScott Long iflib_module_event_handler,
5584c7070dbSScott Long NULL
5594c7070dbSScott Long };
5604c7070dbSScott Long
5614c7070dbSScott Long DECLARE_MODULE(iflib, iflib_moduledata, SI_SUB_INIT_IF, SI_ORDER_ANY);
5624c7070dbSScott Long MODULE_VERSION(iflib, 1);
5634c7070dbSScott Long
5644c7070dbSScott Long MODULE_DEPEND(iflib, pci, 1, 1, 1);
5654c7070dbSScott Long MODULE_DEPEND(iflib, ether, 1, 1, 1);
5664c7070dbSScott Long
567ab2e3f79SStephen Hurd TASKQGROUP_DEFINE(if_io_tqg, mp_ncpus, 1);
568ab2e3f79SStephen Hurd TASKQGROUP_DEFINE(if_config_tqg, 1, 1);
569ab2e3f79SStephen Hurd
5704c7070dbSScott Long #ifndef IFLIB_DEBUG_COUNTERS
5714c7070dbSScott Long #ifdef INVARIANTS
5724c7070dbSScott Long #define IFLIB_DEBUG_COUNTERS 1
5734c7070dbSScott Long #else
5744c7070dbSScott Long #define IFLIB_DEBUG_COUNTERS 0
5754c7070dbSScott Long #endif /* !INVARIANTS */
5764c7070dbSScott Long #endif
5774c7070dbSScott Long
5787029da5cSPawel Biernacki static SYSCTL_NODE(_net, OID_AUTO, iflib, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
579ab2e3f79SStephen Hurd "iflib driver parameters");
580ab2e3f79SStephen Hurd
5814c7070dbSScott Long /*
5824c7070dbSScott Long * XXX need to ensure that this can't accidentally cause the head to be moved backwards
5834c7070dbSScott Long */
5844c7070dbSScott Long static int iflib_min_tx_latency = 0;
5854c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, min_tx_latency, CTLFLAG_RW,
586e4a0c92eSStephen J. Kiernan &iflib_min_tx_latency, 0,
587e4a0c92eSStephen J. Kiernan "minimize transmit latency at the possible expense of throughput");
58895246abbSSean Bruno static int iflib_no_tx_batch = 0;
58995246abbSSean Bruno SYSCTL_INT(_net_iflib, OID_AUTO, no_tx_batch, CTLFLAG_RW,
590e4a0c92eSStephen J. Kiernan &iflib_no_tx_batch, 0,
591e4a0c92eSStephen J. Kiernan "minimize transmit latency at the possible expense of throughput");
592618d49f5SAlexander Motin static int iflib_timer_default = 1000;
593618d49f5SAlexander Motin SYSCTL_INT(_net_iflib, OID_AUTO, timer_default, CTLFLAG_RW,
594618d49f5SAlexander Motin &iflib_timer_default, 0, "number of ticks between iflib_timer calls");
59581be6552SMatt Macy
5964c7070dbSScott Long
5974c7070dbSScott Long #if IFLIB_DEBUG_COUNTERS
5984c7070dbSScott Long
5994c7070dbSScott Long static int iflib_tx_seen;
6004c7070dbSScott Long static int iflib_tx_sent;
6014c7070dbSScott Long static int iflib_tx_encap;
6024c7070dbSScott Long static int iflib_rx_allocs;
6034c7070dbSScott Long static int iflib_fl_refills;
6044c7070dbSScott Long static int iflib_fl_refills_large;
6054c7070dbSScott Long static int iflib_tx_frees;
6064c7070dbSScott Long
607e4a0c92eSStephen J. Kiernan SYSCTL_INT(_net_iflib, OID_AUTO, tx_seen, CTLFLAG_RD, &iflib_tx_seen, 0,
608e4a0c92eSStephen J. Kiernan "# TX mbufs seen");
609e4a0c92eSStephen J. Kiernan SYSCTL_INT(_net_iflib, OID_AUTO, tx_sent, CTLFLAG_RD, &iflib_tx_sent, 0,
610e4a0c92eSStephen J. Kiernan "# TX mbufs sent");
611e4a0c92eSStephen J. Kiernan SYSCTL_INT(_net_iflib, OID_AUTO, tx_encap, CTLFLAG_RD, &iflib_tx_encap, 0,
612e4a0c92eSStephen J. Kiernan "# TX mbufs encapped");
613e4a0c92eSStephen J. Kiernan SYSCTL_INT(_net_iflib, OID_AUTO, tx_frees, CTLFLAG_RD, &iflib_tx_frees, 0,
614e4a0c92eSStephen J. Kiernan "# TX frees");
615e4a0c92eSStephen J. Kiernan SYSCTL_INT(_net_iflib, OID_AUTO, rx_allocs, CTLFLAG_RD, &iflib_rx_allocs, 0,
616e4a0c92eSStephen J. Kiernan "# RX allocations");
617e4a0c92eSStephen J. Kiernan SYSCTL_INT(_net_iflib, OID_AUTO, fl_refills, CTLFLAG_RD, &iflib_fl_refills, 0,
618e4a0c92eSStephen J. Kiernan "# refills");
6194c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, fl_refills_large, CTLFLAG_RD,
6204c7070dbSScott Long &iflib_fl_refills_large, 0, "# large refills");
6214c7070dbSScott Long
6224c7070dbSScott Long static int iflib_txq_drain_flushing;
6234c7070dbSScott Long static int iflib_txq_drain_oactive;
6244c7070dbSScott Long static int iflib_txq_drain_notready;
6254c7070dbSScott Long
6264c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_flushing, CTLFLAG_RD,
6274c7070dbSScott Long &iflib_txq_drain_flushing, 0, "# drain flushes");
6284c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_oactive, CTLFLAG_RD,
6294c7070dbSScott Long &iflib_txq_drain_oactive, 0, "# drain oactives");
6304c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_notready, CTLFLAG_RD,
6314c7070dbSScott Long &iflib_txq_drain_notready, 0, "# drain notready");
6324c7070dbSScott Long
6334c7070dbSScott Long static int iflib_encap_load_mbuf_fail;
634d14c853bSStephen Hurd static int iflib_encap_pad_mbuf_fail;
6354c7070dbSScott Long static int iflib_encap_txq_avail_fail;
6364c7070dbSScott Long static int iflib_encap_txd_encap_fail;
6374c7070dbSScott Long
6384c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, encap_load_mbuf_fail, CTLFLAG_RD,
6394c7070dbSScott Long &iflib_encap_load_mbuf_fail, 0, "# busdma load failures");
640d14c853bSStephen Hurd SYSCTL_INT(_net_iflib, OID_AUTO, encap_pad_mbuf_fail, CTLFLAG_RD,
641d14c853bSStephen Hurd &iflib_encap_pad_mbuf_fail, 0, "# runt frame pad failures");
6424c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, encap_txq_avail_fail, CTLFLAG_RD,
6434c7070dbSScott Long &iflib_encap_txq_avail_fail, 0, "# txq avail failures");
6444c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, encap_txd_encap_fail, CTLFLAG_RD,
6454c7070dbSScott Long &iflib_encap_txd_encap_fail, 0, "# driver encap failures");
6464c7070dbSScott Long
6474c7070dbSScott Long static int iflib_task_fn_rxs;
6484c7070dbSScott Long static int iflib_rx_intr_enables;
6494c7070dbSScott Long static int iflib_fast_intrs;
6504c7070dbSScott Long static int iflib_rx_unavail;
6514c7070dbSScott Long static int iflib_rx_ctx_inactive;
6524c7070dbSScott Long static int iflib_rx_if_input;
6534c7070dbSScott Long static int iflib_rxd_flush;
6544c7070dbSScott Long
6554c7070dbSScott Long static int iflib_verbose_debug;
6564c7070dbSScott Long
657e4a0c92eSStephen J. Kiernan SYSCTL_INT(_net_iflib, OID_AUTO, task_fn_rx, CTLFLAG_RD, &iflib_task_fn_rxs, 0,
658e4a0c92eSStephen J. Kiernan "# task_fn_rx calls");
6594c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_intr_enables, CTLFLAG_RD,
6601722eeacSMarius Strobl &iflib_rx_intr_enables, 0, "# RX intr enables");
661e4a0c92eSStephen J. Kiernan SYSCTL_INT(_net_iflib, OID_AUTO, fast_intrs, CTLFLAG_RD, &iflib_fast_intrs, 0,
662e4a0c92eSStephen J. Kiernan "# fast_intr calls");
663e4a0c92eSStephen J. Kiernan SYSCTL_INT(_net_iflib, OID_AUTO, rx_unavail, CTLFLAG_RD, &iflib_rx_unavail, 0,
664e4a0c92eSStephen J. Kiernan "# times rxeof called with no available data");
6654c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_ctx_inactive, CTLFLAG_RD,
6664c7070dbSScott Long &iflib_rx_ctx_inactive, 0, "# times rxeof called with inactive context");
667e4a0c92eSStephen J. Kiernan SYSCTL_INT(_net_iflib, OID_AUTO, rx_if_input, CTLFLAG_RD, &iflib_rx_if_input,
668e4a0c92eSStephen J. Kiernan 0, "# times rxeof called if_input");
669e4a0c92eSStephen J. Kiernan SYSCTL_INT(_net_iflib, OID_AUTO, rxd_flush, CTLFLAG_RD, &iflib_rxd_flush, 0,
670e4a0c92eSStephen J. Kiernan "# times rxd_flush called");
6714c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, verbose_debug, CTLFLAG_RW,
6724c7070dbSScott Long &iflib_verbose_debug, 0, "enable verbose debugging");
6734c7070dbSScott Long
6744c7070dbSScott Long #define DBG_COUNTER_INC(name) atomic_add_int(&(iflib_ ## name), 1)
675da69b8f9SSean Bruno static void
iflib_debug_reset(void)676da69b8f9SSean Bruno iflib_debug_reset(void)
677da69b8f9SSean Bruno {
678da69b8f9SSean Bruno iflib_tx_seen = iflib_tx_sent = iflib_tx_encap = iflib_rx_allocs =
679da69b8f9SSean Bruno iflib_fl_refills = iflib_fl_refills_large = iflib_tx_frees =
680da69b8f9SSean Bruno iflib_txq_drain_flushing = iflib_txq_drain_oactive =
68164e6fc13SStephen Hurd iflib_txq_drain_notready =
682d14c853bSStephen Hurd iflib_encap_load_mbuf_fail = iflib_encap_pad_mbuf_fail =
683d14c853bSStephen Hurd iflib_encap_txq_avail_fail = iflib_encap_txd_encap_fail =
684d14c853bSStephen Hurd iflib_task_fn_rxs = iflib_rx_intr_enables = iflib_fast_intrs =
68564e6fc13SStephen Hurd iflib_rx_unavail =
68664e6fc13SStephen Hurd iflib_rx_ctx_inactive = iflib_rx_if_input =
6876d49b41eSAndrew Gallatin iflib_rxd_flush = 0;
688da69b8f9SSean Bruno }
6894c7070dbSScott Long
6904c7070dbSScott Long #else
6914c7070dbSScott Long #define DBG_COUNTER_INC(name)
iflib_debug_reset(void)692da69b8f9SSean Bruno static void iflib_debug_reset(void) {}
6934c7070dbSScott Long #endif
6944c7070dbSScott Long
6954c7070dbSScott Long #define IFLIB_DEBUG 0
6964c7070dbSScott Long
6974c7070dbSScott Long static void iflib_tx_structures_free(if_ctx_t ctx);
6984c7070dbSScott Long static void iflib_rx_structures_free(if_ctx_t ctx);
6994c7070dbSScott Long static int iflib_queues_alloc(if_ctx_t ctx);
7004c7070dbSScott Long static int iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq);
70195246abbSSean Bruno static int iflib_rxd_avail(if_ctx_t ctx, iflib_rxq_t rxq, qidx_t cidx, qidx_t budget);
7024c7070dbSScott Long static int iflib_qset_structures_setup(if_ctx_t ctx);
7034c7070dbSScott Long static int iflib_msix_init(if_ctx_t ctx);
7043e0e6330SStephen Hurd static int iflib_legacy_setup(if_ctx_t ctx, driver_filter_t filter, void *filterarg, int *rid, const char *str);
7054c7070dbSScott Long static void iflib_txq_check_drain(iflib_txq_t txq, int budget);
7064c7070dbSScott Long static uint32_t iflib_txq_can_drain(struct ifmp_ring *);
707b8ca4756SPatrick Kelsey #ifdef ALTQ
708b8ca4756SPatrick Kelsey static void iflib_altq_if_start(if_t ifp);
709b8ca4756SPatrick Kelsey static int iflib_altq_if_transmit(if_t ifp, struct mbuf *m);
710b8ca4756SPatrick Kelsey #endif
7114c7070dbSScott Long static int iflib_register(if_ctx_t);
71256614414SEric Joyner static void iflib_deregister(if_ctx_t);
7131558015eSEric Joyner static void iflib_unregister_vlan_handlers(if_ctx_t ctx);
714b3813609SPatrick Kelsey static uint16_t iflib_get_mbuf_size_for(unsigned int size);
7154c7070dbSScott Long static void iflib_init_locked(if_ctx_t ctx);
7164c7070dbSScott Long static void iflib_add_device_sysctl_pre(if_ctx_t ctx);
7174c7070dbSScott Long static void iflib_add_device_sysctl_post(if_ctx_t ctx);
718da69b8f9SSean Bruno static void iflib_ifmp_purge(iflib_txq_t txq);
7191248952aSSean Bruno static void _iflib_pre_assert(if_softc_ctx_t scctx);
7207ff9ae90SMarius Strobl static void iflib_stop(if_ctx_t ctx);
72195246abbSSean Bruno static void iflib_if_init_locked(if_ctx_t ctx);
72277c1fcecSEric Joyner static void iflib_free_intr_mem(if_ctx_t ctx);
72395246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
72495246abbSSean Bruno static struct mbuf *iflib_fixup_rx(struct mbuf *m);
72595246abbSSean Bruno #endif
7264c7070dbSScott Long
727f154ece0SStephen Hurd static SLIST_HEAD(cpu_offset_list, cpu_offset) cpu_offsets =
728f154ece0SStephen Hurd SLIST_HEAD_INITIALIZER(cpu_offsets);
729f154ece0SStephen Hurd struct cpu_offset {
730f154ece0SStephen Hurd SLIST_ENTRY(cpu_offset) entries;
731f154ece0SStephen Hurd cpuset_t set;
732f154ece0SStephen Hurd unsigned int refcount;
733ca7005f1SPatrick Kelsey uint16_t next_cpuid;
734f154ece0SStephen Hurd };
735f154ece0SStephen Hurd static struct mtx cpu_offset_mtx;
736f154ece0SStephen Hurd MTX_SYSINIT(iflib_cpu_offset, &cpu_offset_mtx, "iflib_cpu_offset lock",
737f154ece0SStephen Hurd MTX_DEF);
738f154ece0SStephen Hurd
7397790c8c1SConrad Meyer DEBUGNET_DEFINE(iflib);
74094618825SMark Johnston
741ac11d857SVincenzo Maffione static int
iflib_num_rx_descs(if_ctx_t ctx)742ac11d857SVincenzo Maffione iflib_num_rx_descs(if_ctx_t ctx)
743ac11d857SVincenzo Maffione {
744ac11d857SVincenzo Maffione if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
745ac11d857SVincenzo Maffione if_shared_ctx_t sctx = ctx->ifc_sctx;
746ac11d857SVincenzo Maffione uint16_t first_rxq = (sctx->isc_flags & IFLIB_HAS_RXCQ) ? 1 : 0;
747ac11d857SVincenzo Maffione
748fa7045f9SZhenlei Huang return (scctx->isc_nrxd[first_rxq]);
749ac11d857SVincenzo Maffione }
750ac11d857SVincenzo Maffione
751ac11d857SVincenzo Maffione static int
iflib_num_tx_descs(if_ctx_t ctx)752ac11d857SVincenzo Maffione iflib_num_tx_descs(if_ctx_t ctx)
753ac11d857SVincenzo Maffione {
754ac11d857SVincenzo Maffione if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
755ac11d857SVincenzo Maffione if_shared_ctx_t sctx = ctx->ifc_sctx;
756ac11d857SVincenzo Maffione uint16_t first_txq = (sctx->isc_flags & IFLIB_HAS_TXCQ) ? 1 : 0;
757ac11d857SVincenzo Maffione
758fa7045f9SZhenlei Huang return (scctx->isc_ntxd[first_txq]);
759ac11d857SVincenzo Maffione }
760ac11d857SVincenzo Maffione
7614c7070dbSScott Long #ifdef DEV_NETMAP
7624c7070dbSScott Long #include <sys/selinfo.h>
7634c7070dbSScott Long #include <net/netmap.h>
7644c7070dbSScott Long #include <dev/netmap/netmap_kern.h>
7654c7070dbSScott Long
7664c7070dbSScott Long MODULE_DEPEND(iflib, netmap, 1, 1, 1);
7674c7070dbSScott Long
768de5b4610SVincenzo Maffione static int netmap_fl_refill(iflib_rxq_t rxq, struct netmap_kring *kring, bool init);
76917cec474SVincenzo Maffione static void iflib_netmap_timer(void *arg);
7702d873474SStephen Hurd
7714c7070dbSScott Long /*
7724c7070dbSScott Long * device-specific sysctl variables:
7734c7070dbSScott Long *
77491d546a0SConrad Meyer * iflib_crcstrip: 0: keep CRC in rx frames (default), 1: strip it.
7754c7070dbSScott Long * During regular operations the CRC is stripped, but on some
7764c7070dbSScott Long * hardware reception of frames not multiple of 64 is slower,
7774c7070dbSScott Long * so using crcstrip=0 helps in benchmarks.
7784c7070dbSScott Long *
77991d546a0SConrad Meyer * iflib_rx_miss, iflib_rx_miss_bufs:
7804c7070dbSScott Long * count packets that might be missed due to lost interrupts.
7814c7070dbSScott Long */
7824c7070dbSScott Long SYSCTL_DECL(_dev_netmap);
7834c7070dbSScott Long /*
7844c7070dbSScott Long * The xl driver by default strips CRCs and we do not override it.
7854c7070dbSScott Long */
7864c7070dbSScott Long
7874c7070dbSScott Long int iflib_crcstrip = 1;
7884c7070dbSScott Long SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_crcstrip,
7891722eeacSMarius Strobl CTLFLAG_RW, &iflib_crcstrip, 1, "strip CRC on RX frames");
7904c7070dbSScott Long
7914c7070dbSScott Long int iflib_rx_miss, iflib_rx_miss_bufs;
7924c7070dbSScott Long SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_rx_miss,
7931722eeacSMarius Strobl CTLFLAG_RW, &iflib_rx_miss, 0, "potentially missed RX intr");
79491d546a0SConrad Meyer SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_rx_miss_bufs,
7951722eeacSMarius Strobl CTLFLAG_RW, &iflib_rx_miss_bufs, 0, "potentially missed RX intr bufs");
7964c7070dbSScott Long
7974c7070dbSScott Long /*
7984c7070dbSScott Long * Register/unregister. We are already under netmap lock.
7994c7070dbSScott Long * Only called on the first register or the last unregister.
8004c7070dbSScott Long */
8014c7070dbSScott Long static int
iflib_netmap_register(struct netmap_adapter * na,int onoff)8024c7070dbSScott Long iflib_netmap_register(struct netmap_adapter *na, int onoff)
8034c7070dbSScott Long {
8041722eeacSMarius Strobl if_t ifp = na->ifp;
805402810d3SJustin Hibbits if_ctx_t ctx = if_getsoftc(ifp);
80695246abbSSean Bruno int status;
8074c7070dbSScott Long
8084c7070dbSScott Long CTX_LOCK(ctx);
8094c7070dbSScott Long if (!CTX_IS_VF(ctx))
8101248952aSSean Bruno IFDI_CRCSTRIP_SET(ctx, onoff, iflib_crcstrip);
8114c7070dbSScott Long
8120a182b4cSVincenzo Maffione iflib_stop(ctx);
8130a182b4cSVincenzo Maffione
8140a182b4cSVincenzo Maffione /*
8150a182b4cSVincenzo Maffione * Enable (or disable) netmap flags, and intercept (or restore)
8160a182b4cSVincenzo Maffione * ifp->if_transmit. This is done once the device has been stopped
8173d65fd97SVincenzo Maffione * to prevent race conditions. Also, this must be done after
8183d65fd97SVincenzo Maffione * calling netmap_disable_all_rings() and before calling
8193d65fd97SVincenzo Maffione * netmap_enable_all_rings(), so that these two functions see the
8203d65fd97SVincenzo Maffione * updated state of the NAF_NETMAP_ON bit.
8210a182b4cSVincenzo Maffione */
8224c7070dbSScott Long if (onoff) {
8234c7070dbSScott Long nm_set_native_flags(na);
8244c7070dbSScott Long } else {
8254c7070dbSScott Long nm_clear_native_flags(na);
8264c7070dbSScott Long }
8270a182b4cSVincenzo Maffione
82895246abbSSean Bruno iflib_init_locked(ctx);
8291248952aSSean Bruno IFDI_CRCSTRIP_SET(ctx, onoff, iflib_crcstrip); // XXX why twice ?
830402810d3SJustin Hibbits status = if_getdrvflags(ifp) & IFF_DRV_RUNNING ? 0 : 1;
83195246abbSSean Bruno if (status)
83295246abbSSean Bruno nm_clear_native_flags(na);
8334c7070dbSScott Long CTX_UNLOCK(ctx);
83495246abbSSean Bruno return (status);
8354c7070dbSScott Long }
8364c7070dbSScott Long
8372d873474SStephen Hurd static int
iflib_netmap_config(struct netmap_adapter * na,struct nm_config_info * info)83821d0c012Syou@x iflib_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
83921d0c012Syou@x {
84021d0c012Syou@x if_t ifp = na->ifp;
841402810d3SJustin Hibbits if_ctx_t ctx = if_getsoftc(ifp);
84221d0c012Syou@x iflib_rxq_t rxq = &ctx->ifc_rxqs[0];
84321d0c012Syou@x iflib_fl_t fl = &rxq->ifr_fl[0];
84421d0c012Syou@x
84521d0c012Syou@x info->num_tx_rings = ctx->ifc_softc_ctx.isc_ntxqsets;
84621d0c012Syou@x info->num_rx_rings = ctx->ifc_softc_ctx.isc_nrxqsets;
84721d0c012Syou@x info->num_tx_descs = iflib_num_tx_descs(ctx);
84821d0c012Syou@x info->num_rx_descs = iflib_num_rx_descs(ctx);
84921d0c012Syou@x info->rx_buf_maxsize = fl->ifl_buf_size;
85021d0c012Syou@x nm_prinf("txr %u rxr %u txd %u rxd %u rbufsz %u",
85121d0c012Syou@x info->num_tx_rings, info->num_rx_rings, info->num_tx_descs,
85221d0c012Syou@x info->num_rx_descs, info->rx_buf_maxsize);
85321d0c012Syou@x
854fa7045f9SZhenlei Huang return (0);
85521d0c012Syou@x }
85621d0c012Syou@x
85721d0c012Syou@x static int
netmap_fl_refill(iflib_rxq_t rxq,struct netmap_kring * kring,bool init)858de5b4610SVincenzo Maffione netmap_fl_refill(iflib_rxq_t rxq, struct netmap_kring *kring, bool init)
8592d873474SStephen Hurd {
8602d873474SStephen Hurd struct netmap_adapter *na = kring->na;
8612d873474SStephen Hurd u_int const lim = kring->nkr_num_slots - 1;
8622d873474SStephen Hurd struct netmap_ring *ring = kring->ring;
8632d873474SStephen Hurd bus_dmamap_t *map;
8642d873474SStephen Hurd struct if_rxd_update iru;
8652d873474SStephen Hurd if_ctx_t ctx = rxq->ifr_ctx;
8662d873474SStephen Hurd iflib_fl_t fl = &rxq->ifr_fl[0];
867de5b4610SVincenzo Maffione u_int nic_i_first, nic_i;
86855f0ad5fSVincenzo Maffione u_int nm_i;
869ae750d5cSVincenzo Maffione int i, n;
87064e6fc13SStephen Hurd #if IFLIB_DEBUG_COUNTERS
87164e6fc13SStephen Hurd int rf_count = 0;
87264e6fc13SStephen Hurd #endif
8732d873474SStephen Hurd
874de5b4610SVincenzo Maffione /*
875ae750d5cSVincenzo Maffione * This function is used both at initialization and in rxsync.
876ae750d5cSVincenzo Maffione * At initialization we need to prepare (with isc_rxd_refill())
87755f0ad5fSVincenzo Maffione * all the netmap buffers currently owned by the kernel, in
87855f0ad5fSVincenzo Maffione * such a way to keep fl->ifl_pidx and kring->nr_hwcur in sync
87955f0ad5fSVincenzo Maffione * (except for kring->nkr_hwofs). These may be less than
88055f0ad5fSVincenzo Maffione * kring->nkr_num_slots if netmap_reset() was called while
88155f0ad5fSVincenzo Maffione * an application using the kring that still owned some
88255f0ad5fSVincenzo Maffione * buffers.
88355f0ad5fSVincenzo Maffione * At rxsync time, both indexes point to the next buffer to be
88455f0ad5fSVincenzo Maffione * refilled.
885ae750d5cSVincenzo Maffione * In any case we publish (with isc_rxd_flush()) up to
886ae750d5cSVincenzo Maffione * (fl->ifl_pidx - 1) % N (included), to avoid the NIC tail/prod
887ae750d5cSVincenzo Maffione * pointer to overrun the head/cons pointer, although this is
888ae750d5cSVincenzo Maffione * not necessary for some NICs (e.g. vmx).
889de5b4610SVincenzo Maffione */
89055f0ad5fSVincenzo Maffione if (__predict_false(init)) {
89155f0ad5fSVincenzo Maffione n = kring->nkr_num_slots - nm_kr_rxspace(kring);
89255f0ad5fSVincenzo Maffione } else {
89355f0ad5fSVincenzo Maffione n = kring->rhead - kring->nr_hwcur;
894ae750d5cSVincenzo Maffione if (n == 0)
895ae750d5cSVincenzo Maffione return (0); /* Nothing to do. */
896ae750d5cSVincenzo Maffione if (n < 0)
897ae750d5cSVincenzo Maffione n += kring->nkr_num_slots;
898de5b4610SVincenzo Maffione }
899530960beSVincenzo Maffione
9002d873474SStephen Hurd iru_init(&iru, rxq, 0 /* flid */);
9012d873474SStephen Hurd map = fl->ifl_sds.ifsd_map;
902ae750d5cSVincenzo Maffione nic_i = fl->ifl_pidx;
90355f0ad5fSVincenzo Maffione nm_i = netmap_idx_n2k(kring, nic_i);
90455f0ad5fSVincenzo Maffione if (__predict_false(init)) {
90555f0ad5fSVincenzo Maffione /*
90655f0ad5fSVincenzo Maffione * On init/reset, nic_i must be 0, and we must
90755f0ad5fSVincenzo Maffione * start to refill from hwtail (see netmap_reset()).
90855f0ad5fSVincenzo Maffione */
90955f0ad5fSVincenzo Maffione MPASS(nic_i == 0);
91055f0ad5fSVincenzo Maffione MPASS(nm_i == kring->nr_hwtail);
91155f0ad5fSVincenzo Maffione } else
91255f0ad5fSVincenzo Maffione MPASS(nm_i == kring->nr_hwcur);
91364e6fc13SStephen Hurd DBG_COUNTER_INC(fl_refills);
914ae750d5cSVincenzo Maffione while (n > 0) {
91564e6fc13SStephen Hurd #if IFLIB_DEBUG_COUNTERS
91664e6fc13SStephen Hurd if (++rf_count == 9)
91764e6fc13SStephen Hurd DBG_COUNTER_INC(fl_refills_large);
91864e6fc13SStephen Hurd #endif
919530960beSVincenzo Maffione nic_i_first = nic_i;
920ae750d5cSVincenzo Maffione for (i = 0; n > 0 && i < IFLIB_MAX_RX_REFRESH; n--, i++) {
9212d873474SStephen Hurd struct netmap_slot *slot = &ring->slot[nm_i];
922361e9501SVincenzo Maffione uint64_t paddr;
923361e9501SVincenzo Maffione void *addr = PNMB(na, slot, &paddr);
9242d873474SStephen Hurd
925530960beSVincenzo Maffione MPASS(i < IFLIB_MAX_RX_REFRESH);
9262d873474SStephen Hurd
9272d873474SStephen Hurd if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
928fa7045f9SZhenlei Huang return (netmap_ring_reinit(kring));
9292d873474SStephen Hurd
930361e9501SVincenzo Maffione fl->ifl_bus_addrs[i] = paddr +
931361e9501SVincenzo Maffione nm_get_offset(kring, slot);
932530960beSVincenzo Maffione fl->ifl_rxd_idxs[i] = nic_i;
933530960beSVincenzo Maffione
93495dcf343SMarius Strobl if (__predict_false(init)) {
93595dcf343SMarius Strobl netmap_load_map(na, fl->ifl_buf_tag,
93695dcf343SMarius Strobl map[nic_i], addr);
93795dcf343SMarius Strobl } else if (slot->flags & NS_BUF_CHANGED) {
9382d873474SStephen Hurd /* buffer has changed, reload map */
93995dcf343SMarius Strobl netmap_reload_map(na, fl->ifl_buf_tag,
94095dcf343SMarius Strobl map[nic_i], addr);
9412d873474SStephen Hurd }
942530960beSVincenzo Maffione bus_dmamap_sync(fl->ifl_buf_tag, map[nic_i],
943530960beSVincenzo Maffione BUS_DMASYNC_PREREAD);
9442d873474SStephen Hurd slot->flags &= ~NS_BUF_CHANGED;
9452d873474SStephen Hurd
9462d873474SStephen Hurd nm_i = nm_next(nm_i, lim);
947530960beSVincenzo Maffione nic_i = nm_next(nic_i, lim);
948530960beSVincenzo Maffione }
9492d873474SStephen Hurd
950530960beSVincenzo Maffione iru.iru_pidx = nic_i_first;
951530960beSVincenzo Maffione iru.iru_count = i;
9522d873474SStephen Hurd ctx->isc_rxd_refill(ctx->ifc_softc, &iru);
9532d873474SStephen Hurd }
954ae750d5cSVincenzo Maffione fl->ifl_pidx = nic_i;
95555f0ad5fSVincenzo Maffione /*
95655f0ad5fSVincenzo Maffione * At the end of the loop we must have refilled everything
95755f0ad5fSVincenzo Maffione * we could possibly refill.
95855f0ad5fSVincenzo Maffione */
959ae750d5cSVincenzo Maffione MPASS(nm_i == kring->rhead);
960ae750d5cSVincenzo Maffione kring->nr_hwcur = nm_i;
9612d873474SStephen Hurd
9622d873474SStephen Hurd bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
9632d873474SStephen Hurd BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
964de5b4610SVincenzo Maffione ctx->isc_rxd_flush(ctx->ifc_softc, rxq->ifr_id, fl->ifl_id,
965de5b4610SVincenzo Maffione nm_prev(nic_i, lim));
96664e6fc13SStephen Hurd DBG_COUNTER_INC(rxd_flush);
967530960beSVincenzo Maffione
9682d873474SStephen Hurd return (0);
9692d873474SStephen Hurd }
9702d873474SStephen Hurd
97117cec474SVincenzo Maffione #define NETMAP_TX_TIMER_US 90
97217cec474SVincenzo Maffione
9734c7070dbSScott Long /*
9744c7070dbSScott Long * Reconcile kernel and user view of the transmit ring.
9754c7070dbSScott Long *
9764c7070dbSScott Long * All information is in the kring.
9774c7070dbSScott Long * Userspace wants to send packets up to the one before kring->rhead,
9784c7070dbSScott Long * kernel knows kring->nr_hwcur is the first unsent packet.
9794c7070dbSScott Long *
9804c7070dbSScott Long * Here we push packets out (as many as possible), and possibly
9814c7070dbSScott Long * reclaim buffers from previously completed transmission.
9824c7070dbSScott Long *
9834c7070dbSScott Long * The caller (netmap) guarantees that there is only one instance
9844c7070dbSScott Long * running at any time. Any interference with other driver
9854c7070dbSScott Long * methods should be handled by the individual drivers.
9864c7070dbSScott Long */
9874c7070dbSScott Long static int
iflib_netmap_txsync(struct netmap_kring * kring,int flags)9884c7070dbSScott Long iflib_netmap_txsync(struct netmap_kring *kring, int flags)
9894c7070dbSScott Long {
9904c7070dbSScott Long struct netmap_adapter *na = kring->na;
9911722eeacSMarius Strobl if_t ifp = na->ifp;
9924c7070dbSScott Long struct netmap_ring *ring = kring->ring;
993dd7fbcf1SStephen Hurd u_int nm_i; /* index into the netmap kring */
9944c7070dbSScott Long u_int nic_i; /* index into the NIC ring */
9954c7070dbSScott Long u_int const lim = kring->nkr_num_slots - 1;
9964c7070dbSScott Long u_int const head = kring->rhead;
9974c7070dbSScott Long struct if_pkt_info pi;
99866fa12d8SStephan de Wit int tx_pkts = 0, tx_bytes = 0;
9994c7070dbSScott Long
10004c7070dbSScott Long /*
10014c7070dbSScott Long * interrupts on every tx packet are expensive so request
10024c7070dbSScott Long * them every half ring, or where NS_REPORT is set
10034c7070dbSScott Long */
10044c7070dbSScott Long u_int report_frequency = kring->nkr_num_slots >> 1;
10054c7070dbSScott Long /* device-specific */
1006402810d3SJustin Hibbits if_ctx_t ctx = if_getsoftc(ifp);
10074c7070dbSScott Long iflib_txq_t txq = &ctx->ifc_txqs[kring->ring_id];
10084c7070dbSScott Long
100995dcf343SMarius Strobl bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
10104c7070dbSScott Long BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
10114c7070dbSScott Long
10124c7070dbSScott Long /*
10134c7070dbSScott Long * First part: process new packets to send.
1014dd7fbcf1SStephen Hurd * nm_i is the current index in the netmap kring,
10154c7070dbSScott Long * nic_i is the corresponding index in the NIC ring.
10164c7070dbSScott Long *
10174c7070dbSScott Long * If we have packets to send (nm_i != head)
10184c7070dbSScott Long * iterate over the netmap ring, fetch length and update
10194c7070dbSScott Long * the corresponding slot in the NIC ring. Some drivers also
10204c7070dbSScott Long * need to update the buffer's physical address in the NIC slot
10214c7070dbSScott Long * even NS_BUF_CHANGED is not set (PNMB computes the addresses).
10224c7070dbSScott Long *
10234c7070dbSScott Long * The netmap_reload_map() calls is especially expensive,
10244c7070dbSScott Long * even when (as in this case) the tag is 0, so do only
10254c7070dbSScott Long * when the buffer has actually changed.
10264c7070dbSScott Long *
10274c7070dbSScott Long * If possible do not set the report/intr bit on all slots,
10284c7070dbSScott Long * but only a few times per ring or when NS_REPORT is set.
10294c7070dbSScott Long *
10304c7070dbSScott Long * Finally, on 10G and faster drivers, it might be useful
10314c7070dbSScott Long * to prefetch the next slot and txr entry.
10324c7070dbSScott Long */
10334c7070dbSScott Long
1034dd7fbcf1SStephen Hurd nm_i = kring->nr_hwcur;
10355ee36c68SStephen Hurd if (nm_i != head) { /* we have new packets to send */
1036aceaccabSVincenzo Maffione uint32_t pkt_len = 0, seg_idx = 0;
1037aceaccabSVincenzo Maffione int nic_i_start = -1, flags = 0;
103895246abbSSean Bruno pkt_info_zero(&pi);
103995246abbSSean Bruno pi.ipi_segs = txq->ift_segs;
104095246abbSSean Bruno pi.ipi_qsidx = kring->ring_id;
10414c7070dbSScott Long nic_i = netmap_idx_k2n(kring, nm_i);
10424c7070dbSScott Long
10434c7070dbSScott Long __builtin_prefetch(&ring->slot[nm_i]);
10444c7070dbSScott Long __builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i]);
10454c7070dbSScott Long __builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i]);
10464c7070dbSScott Long
10470294e95dSDimitry Andric while (nm_i != head) {
10484c7070dbSScott Long struct netmap_slot *slot = &ring->slot[nm_i];
1049361e9501SVincenzo Maffione uint64_t offset = nm_get_offset(kring, slot);
10504c7070dbSScott Long u_int len = slot->len;
10510a1b74a3SSean Bruno uint64_t paddr;
10524c7070dbSScott Long void *addr = PNMB(na, slot, &paddr);
1053aceaccabSVincenzo Maffione
1054aceaccabSVincenzo Maffione flags |= (slot->flags & NS_REPORT ||
10554c7070dbSScott Long nic_i == 0 || nic_i == report_frequency) ?
10564c7070dbSScott Long IPI_TX_INTR : 0;
10574c7070dbSScott Long
1058aceaccabSVincenzo Maffione /*
1059aceaccabSVincenzo Maffione * If this is the first packet fragment, save the
1060aceaccabSVincenzo Maffione * index of the first NIC slot for later.
1061aceaccabSVincenzo Maffione */
1062aceaccabSVincenzo Maffione if (nic_i_start < 0)
1063aceaccabSVincenzo Maffione nic_i_start = nic_i;
1064aceaccabSVincenzo Maffione
1065361e9501SVincenzo Maffione pi.ipi_segs[seg_idx].ds_addr = paddr + offset;
1066aceaccabSVincenzo Maffione pi.ipi_segs[seg_idx].ds_len = len;
1067aceaccabSVincenzo Maffione if (len) {
1068aceaccabSVincenzo Maffione pkt_len += len;
1069aceaccabSVincenzo Maffione seg_idx++;
1070aceaccabSVincenzo Maffione }
1071aceaccabSVincenzo Maffione
1072aceaccabSVincenzo Maffione if (!(slot->flags & NS_MOREFRAG)) {
1073aceaccabSVincenzo Maffione pi.ipi_len = pkt_len;
1074aceaccabSVincenzo Maffione pi.ipi_nsegs = seg_idx;
1075aceaccabSVincenzo Maffione pi.ipi_pidx = nic_i_start;
107695246abbSSean Bruno pi.ipi_ndescs = 0;
10774c7070dbSScott Long pi.ipi_flags = flags;
10784c7070dbSScott Long
1079aceaccabSVincenzo Maffione /* Prepare the NIC TX ring. */
10804c7070dbSScott Long ctx->isc_txd_encap(ctx->ifc_softc, &pi);
108164e6fc13SStephen Hurd DBG_COUNTER_INC(tx_encap);
10824c7070dbSScott Long
108366fa12d8SStephan de Wit /* Update transmit counters */
108466fa12d8SStephan de Wit tx_bytes += pi.ipi_len;
108566fa12d8SStephan de Wit tx_pkts++;
108666fa12d8SStephan de Wit
1087aceaccabSVincenzo Maffione /* Reinit per-packet info for the next one. */
1088aceaccabSVincenzo Maffione flags = seg_idx = pkt_len = 0;
1089aceaccabSVincenzo Maffione nic_i_start = -1;
1090aceaccabSVincenzo Maffione }
1091aceaccabSVincenzo Maffione
10924c7070dbSScott Long /* prefetch for next round */
10934c7070dbSScott Long __builtin_prefetch(&ring->slot[nm_i + 1]);
10944c7070dbSScott Long __builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i + 1]);
10954c7070dbSScott Long __builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i + 1]);
10964c7070dbSScott Long
1097361e9501SVincenzo Maffione NM_CHECK_ADDR_LEN_OFF(na, len, offset);
10984c7070dbSScott Long
10994c7070dbSScott Long if (slot->flags & NS_BUF_CHANGED) {
11004c7070dbSScott Long /* buffer has changed, reload map */
1101bfce461eSMarius Strobl netmap_reload_map(na, txq->ift_buf_tag,
1102bfce461eSMarius Strobl txq->ift_sds.ifsd_map[nic_i], addr);
11034c7070dbSScott Long }
11044c7070dbSScott Long /* make sure changes to the buffer are synced */
110595dcf343SMarius Strobl bus_dmamap_sync(txq->ift_buf_tag,
110695dcf343SMarius Strobl txq->ift_sds.ifsd_map[nic_i],
11074c7070dbSScott Long BUS_DMASYNC_PREWRITE);
110895dcf343SMarius Strobl
1109aceaccabSVincenzo Maffione slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
11104c7070dbSScott Long nm_i = nm_next(nm_i, lim);
11114c7070dbSScott Long nic_i = nm_next(nic_i, lim);
11124c7070dbSScott Long }
1113dd7fbcf1SStephen Hurd kring->nr_hwcur = nm_i;
11144c7070dbSScott Long
11154c7070dbSScott Long /* synchronize the NIC ring */
111695dcf343SMarius Strobl bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
11174c7070dbSScott Long BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11184c7070dbSScott Long
11194c7070dbSScott Long /* (re)start the tx unit up to slot nic_i (excluded) */
11204c7070dbSScott Long ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, nic_i);
11214c7070dbSScott Long }
11224c7070dbSScott Long
11234c7070dbSScott Long /*
11244c7070dbSScott Long * Second part: reclaim buffers for completed transmissions.
11255ee36c68SStephen Hurd *
11265ee36c68SStephen Hurd * If there are unclaimed buffers, attempt to reclaim them.
112717cec474SVincenzo Maffione * If we don't manage to reclaim them all, and TX IRQs are not in use,
112817cec474SVincenzo Maffione * trigger a per-tx-queue timer to try again later.
11294c7070dbSScott Long */
1130dd7fbcf1SStephen Hurd if (kring->nr_hwtail != nm_prev(kring->nr_hwcur, lim)) {
11314c7070dbSScott Long if (iflib_tx_credits_update(ctx, txq)) {
11324c7070dbSScott Long /* some tx completed, increment avail */
11334c7070dbSScott Long nic_i = txq->ift_cidx_processed;
11344c7070dbSScott Long kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
11354c7070dbSScott Long }
11365ee36c68SStephen Hurd }
113717cec474SVincenzo Maffione
1138dd7fbcf1SStephen Hurd if (!(ctx->ifc_flags & IFC_NETMAP_TX_IRQ))
1139dd7fbcf1SStephen Hurd if (kring->nr_hwtail != nm_prev(kring->nr_hwcur, lim)) {
1140be7a6b3dSVincenzo Maffione callout_reset_sbt_on(&txq->ift_netmap_timer,
114117cec474SVincenzo Maffione NETMAP_TX_TIMER_US * SBT_1US, SBT_1US,
1142be7a6b3dSVincenzo Maffione iflib_netmap_timer, txq,
1143be7a6b3dSVincenzo Maffione txq->ift_netmap_timer.c_cpu, 0);
11445ee36c68SStephen Hurd }
114566fa12d8SStephan de Wit
114666fa12d8SStephan de Wit if_inc_counter(ifp, IFCOUNTER_OBYTES, tx_bytes);
114766fa12d8SStephan de Wit if_inc_counter(ifp, IFCOUNTER_OPACKETS, tx_pkts);
114866fa12d8SStephan de Wit
11494c7070dbSScott Long return (0);
11504c7070dbSScott Long }
11514c7070dbSScott Long
11524c7070dbSScott Long /*
11534c7070dbSScott Long * Reconcile kernel and user view of the receive ring.
11544c7070dbSScott Long * Same as for the txsync, this routine must be efficient.
11554c7070dbSScott Long * The caller guarantees a single invocations, but races against
11564c7070dbSScott Long * the rest of the driver should be handled here.
11574c7070dbSScott Long *
11584c7070dbSScott Long * On call, kring->rhead is the first packet that userspace wants
11594c7070dbSScott Long * to keep, and kring->rcur is the wakeup point.
11604c7070dbSScott Long * The kernel has previously reported packets up to kring->rtail.
11614c7070dbSScott Long *
11624c7070dbSScott Long * If (flags & NAF_FORCE_READ) also check for incoming packets irrespective
11634c7070dbSScott Long * of whether or not we received an interrupt.
11644c7070dbSScott Long */
11654c7070dbSScott Long static int
iflib_netmap_rxsync(struct netmap_kring * kring,int flags)11664c7070dbSScott Long iflib_netmap_rxsync(struct netmap_kring *kring, int flags)
11674c7070dbSScott Long {
11684c7070dbSScott Long struct netmap_adapter *na = kring->na;
11694c7070dbSScott Long struct netmap_ring *ring = kring->ring;
11701722eeacSMarius Strobl if_t ifp = na->ifp;
117195246abbSSean Bruno uint32_t nm_i; /* index into the netmap ring */
11722d873474SStephen Hurd uint32_t nic_i; /* index into the NIC ring */
1173ee07345dSVincenzo Maffione u_int n;
11744c7070dbSScott Long u_int const lim = kring->nkr_num_slots - 1;
11754c7070dbSScott Long int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
117666fa12d8SStephan de Wit int i = 0, rx_bytes = 0, rx_pkts = 0;
117795246abbSSean Bruno
1178402810d3SJustin Hibbits if_ctx_t ctx = if_getsoftc(ifp);
11796d84e76aSVincenzo Maffione if_shared_ctx_t sctx = ctx->ifc_sctx;
11806d84e76aSVincenzo Maffione if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
11814c7070dbSScott Long iflib_rxq_t rxq = &ctx->ifc_rxqs[kring->ring_id];
1182ee07345dSVincenzo Maffione iflib_fl_t fl = &rxq->ifr_fl[0];
1183ee07345dSVincenzo Maffione struct if_rxd_info ri;
11846d84e76aSVincenzo Maffione qidx_t *cidxp;
1185ee07345dSVincenzo Maffione
118695dcf343SMarius Strobl /*
1187ee07345dSVincenzo Maffione * netmap only uses free list 0, to avoid out of order consumption
1188ee07345dSVincenzo Maffione * of receive buffers
118995dcf343SMarius Strobl */
119095dcf343SMarius Strobl
119195dcf343SMarius Strobl bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
11924c7070dbSScott Long BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
119395dcf343SMarius Strobl
11944c7070dbSScott Long /*
11954c7070dbSScott Long * First part: import newly received packets.
11964c7070dbSScott Long *
11974c7070dbSScott Long * nm_i is the index of the next free slot in the netmap ring,
11986d84e76aSVincenzo Maffione * nic_i is the index of the next received packet in the NIC ring
11996d84e76aSVincenzo Maffione * (or in the free list 0 if IFLIB_HAS_RXCQ is set), and they may
12006d84e76aSVincenzo Maffione * differ in case if_init() has been called while
12014c7070dbSScott Long * in netmap mode. For the receive ring we have
12024c7070dbSScott Long *
12036d84e76aSVincenzo Maffione * nic_i = fl->ifl_cidx;
12044c7070dbSScott Long * nm_i = kring->nr_hwtail (previous)
12054c7070dbSScott Long * and
12064c7070dbSScott Long * nm_i == (nic_i + kring->nkr_hwofs) % ring_size
12074c7070dbSScott Long *
12086d84e76aSVincenzo Maffione * fl->ifl_cidx is set to 0 on a ring reinit
12094c7070dbSScott Long */
12104c7070dbSScott Long if (netmap_no_pendintr || force_update) {
12110ff21267SVincenzo Maffione uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim);
12126d84e76aSVincenzo Maffione bool have_rxcq = sctx->isc_flags & IFLIB_HAS_RXCQ;
12134c7070dbSScott Long int crclen = iflib_crcstrip ? 0 : 4;
12144c7070dbSScott Long int error, avail;
12154c7070dbSScott Long
12166d84e76aSVincenzo Maffione /*
12176d84e76aSVincenzo Maffione * For the free list consumer index, we use the same
12186d84e76aSVincenzo Maffione * logic as in iflib_rxeof().
12196d84e76aSVincenzo Maffione */
12206d84e76aSVincenzo Maffione if (have_rxcq)
12216d84e76aSVincenzo Maffione cidxp = &rxq->ifr_cq_cidx;
12226d84e76aSVincenzo Maffione else
12236d84e76aSVincenzo Maffione cidxp = &fl->ifl_cidx;
12246d84e76aSVincenzo Maffione avail = ctx->isc_rxd_available(ctx->ifc_softc,
12256d84e76aSVincenzo Maffione rxq->ifr_id, *cidxp, USHRT_MAX);
12266d84e76aSVincenzo Maffione
12274c7070dbSScott Long nic_i = fl->ifl_cidx;
12284c7070dbSScott Long nm_i = netmap_idx_n2k(kring, nic_i);
1229de5b4610SVincenzo Maffione MPASS(nm_i == kring->nr_hwtail);
12300ff21267SVincenzo Maffione for (n = 0; avail > 0 && nm_i != hwtail_lim; n++, avail--) {
1231ab2e3f79SStephen Hurd rxd_info_zero(&ri);
1232ab2e3f79SStephen Hurd ri.iri_frags = rxq->ifr_frags;
1233ab2e3f79SStephen Hurd ri.iri_qsidx = kring->ring_id;
1234ab2e3f79SStephen Hurd ri.iri_ifp = ctx->ifc_ifp;
12356d84e76aSVincenzo Maffione ri.iri_cidx = *cidxp;
123695246abbSSean Bruno
1237ab2e3f79SStephen Hurd error = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri);
1238aceaccabSVincenzo Maffione for (i = 0; i < ri.iri_nfrags; i++) {
1239aceaccabSVincenzo Maffione if (error) {
1240aceaccabSVincenzo Maffione ring->slot[nm_i].len = 0;
12417cb7c6e3SNavdeep Parhar ring->slot[nm_i].flags = 0;
1242aceaccabSVincenzo Maffione } else {
1243aceaccabSVincenzo Maffione ring->slot[nm_i].len = ri.iri_frags[i].irf_len;
1244aceaccabSVincenzo Maffione if (i == (ri.iri_nfrags - 1)) {
1245aceaccabSVincenzo Maffione ring->slot[nm_i].len -= crclen;
1246aceaccabSVincenzo Maffione ring->slot[nm_i].flags = 0;
124766fa12d8SStephan de Wit
124866fa12d8SStephan de Wit /* Update receive counters */
124966fa12d8SStephan de Wit rx_bytes += ri.iri_len;
125066fa12d8SStephan de Wit rx_pkts++;
1251aceaccabSVincenzo Maffione } else
1252aceaccabSVincenzo Maffione ring->slot[nm_i].flags = NS_MOREFRAG;
1253aceaccabSVincenzo Maffione }
1254aceaccabSVincenzo Maffione
1255f80efe50SVincenzo Maffione bus_dmamap_sync(fl->ifl_buf_tag,
1256f80efe50SVincenzo Maffione fl->ifl_sds.ifsd_map[nic_i], BUS_DMASYNC_POSTREAD);
1257f80efe50SVincenzo Maffione nm_i = nm_next(nm_i, lim);
1258f80efe50SVincenzo Maffione fl->ifl_cidx = nic_i = nm_next(nic_i, lim);
1259f80efe50SVincenzo Maffione }
1260f80efe50SVincenzo Maffione
12616d84e76aSVincenzo Maffione if (have_rxcq) {
12626d84e76aSVincenzo Maffione *cidxp = ri.iri_cidx;
12636d84e76aSVincenzo Maffione while (*cidxp >= scctx->isc_nrxd[0])
12646d84e76aSVincenzo Maffione *cidxp -= scctx->isc_nrxd[0];
12656d84e76aSVincenzo Maffione }
1266aceaccabSVincenzo Maffione
1267aceaccabSVincenzo Maffione }
12684c7070dbSScott Long if (n) { /* update the state variables */
12694c7070dbSScott Long if (netmap_no_pendintr && !force_update) {
12704c7070dbSScott Long /* diagnostics */
12714c7070dbSScott Long iflib_rx_miss++;
12724c7070dbSScott Long iflib_rx_miss_bufs += n;
12734c7070dbSScott Long }
1274dd7fbcf1SStephen Hurd kring->nr_hwtail = nm_i;
12754c7070dbSScott Long }
12764c7070dbSScott Long kring->nr_kflags &= ~NKR_PENDINTR;
12774c7070dbSScott Long }
12784c7070dbSScott Long /*
12794c7070dbSScott Long * Second part: skip past packets that userspace has released.
12804c7070dbSScott Long * (kring->nr_hwcur to head excluded),
12814c7070dbSScott Long * and make the buffers available for reception.
12824c7070dbSScott Long * As usual nm_i is the index in the netmap ring,
12834c7070dbSScott Long * nic_i is the index in the NIC ring, and
12844c7070dbSScott Long * nm_i == (nic_i + kring->nkr_hwofs) % ring_size
12854c7070dbSScott Long */
1286de5b4610SVincenzo Maffione netmap_fl_refill(rxq, kring, false);
128795246abbSSean Bruno
128866fa12d8SStephan de Wit if_inc_counter(ifp, IFCOUNTER_IBYTES, rx_bytes);
128966fa12d8SStephan de Wit if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_pkts);
129066fa12d8SStephan de Wit
1291de5b4610SVincenzo Maffione return (0);
12924c7070dbSScott Long }
12934c7070dbSScott Long
129495246abbSSean Bruno static void
iflib_netmap_intr(struct netmap_adapter * na,int onoff)129595246abbSSean Bruno iflib_netmap_intr(struct netmap_adapter *na, int onoff)
129695246abbSSean Bruno {
1297402810d3SJustin Hibbits if_ctx_t ctx = if_getsoftc(na->ifp);
129895246abbSSean Bruno
1299ab2e3f79SStephen Hurd CTX_LOCK(ctx);
130095246abbSSean Bruno if (onoff) {
130195246abbSSean Bruno IFDI_INTR_ENABLE(ctx);
130295246abbSSean Bruno } else {
130395246abbSSean Bruno IFDI_INTR_DISABLE(ctx);
130495246abbSSean Bruno }
1305ab2e3f79SStephen Hurd CTX_UNLOCK(ctx);
130695246abbSSean Bruno }
130795246abbSSean Bruno
13084c7070dbSScott Long static int
iflib_netmap_attach(if_ctx_t ctx)13094c7070dbSScott Long iflib_netmap_attach(if_ctx_t ctx)
13104c7070dbSScott Long {
13114c7070dbSScott Long struct netmap_adapter na;
13124c7070dbSScott Long
13134c7070dbSScott Long bzero(&na, sizeof(na));
13144c7070dbSScott Long
13154c7070dbSScott Long na.ifp = ctx->ifc_ifp;
1316361e9501SVincenzo Maffione na.na_flags = NAF_BDG_MAYSLEEP | NAF_MOREFRAG | NAF_OFFSETS;
13174c7070dbSScott Long MPASS(ctx->ifc_softc_ctx.isc_ntxqsets);
13184c7070dbSScott Long MPASS(ctx->ifc_softc_ctx.isc_nrxqsets);
13194c7070dbSScott Long
1320ac11d857SVincenzo Maffione na.num_tx_desc = iflib_num_tx_descs(ctx);
1321ac11d857SVincenzo Maffione na.num_rx_desc = iflib_num_rx_descs(ctx);
13224c7070dbSScott Long na.nm_txsync = iflib_netmap_txsync;
13234c7070dbSScott Long na.nm_rxsync = iflib_netmap_rxsync;
13244c7070dbSScott Long na.nm_register = iflib_netmap_register;
132595246abbSSean Bruno na.nm_intr = iflib_netmap_intr;
132621d0c012Syou@x na.nm_config = iflib_netmap_config;
13274c7070dbSScott Long na.num_tx_rings = ctx->ifc_softc_ctx.isc_ntxqsets;
13284c7070dbSScott Long na.num_rx_rings = ctx->ifc_softc_ctx.isc_nrxqsets;
13294c7070dbSScott Long return (netmap_attach(&na));
13304c7070dbSScott Long }
13314c7070dbSScott Long
1332d8b2d26bSVincenzo Maffione static int
iflib_netmap_txq_init(if_ctx_t ctx,iflib_txq_t txq)13334c7070dbSScott Long iflib_netmap_txq_init(if_ctx_t ctx, iflib_txq_t txq)
13344c7070dbSScott Long {
13354c7070dbSScott Long struct netmap_adapter *na = NA(ctx->ifc_ifp);
13364c7070dbSScott Long struct netmap_slot *slot;
13374c7070dbSScott Long
13384c7070dbSScott Long slot = netmap_reset(na, NR_TX, txq->ift_id, 0);
1339e099b90bSPedro F. Giffuni if (slot == NULL)
1340d8b2d26bSVincenzo Maffione return (0);
134123ac9029SStephen Hurd for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxd[0]; i++) {
13424c7070dbSScott Long /*
13434c7070dbSScott Long * In netmap mode, set the map for the packet buffer.
13444c7070dbSScott Long * NOTE: Some drivers (not this one) also need to set
13454c7070dbSScott Long * the physical buffer address in the NIC ring.
13464c7070dbSScott Long * netmap_idx_n2k() maps a nic index, i, into the corresponding
13474c7070dbSScott Long * netmap slot index, si
13484c7070dbSScott Long */
13492ff91c17SVincenzo Maffione int si = netmap_idx_n2k(na->tx_rings[txq->ift_id], i);
1350bfce461eSMarius Strobl netmap_load_map(na, txq->ift_buf_tag, txq->ift_sds.ifsd_map[i],
1351bfce461eSMarius Strobl NMB(na, slot + si));
13524c7070dbSScott Long }
1353d8b2d26bSVincenzo Maffione return (1);
13544c7070dbSScott Long }
13552d873474SStephen Hurd
1356d8b2d26bSVincenzo Maffione static int
iflib_netmap_rxq_init(if_ctx_t ctx,iflib_rxq_t rxq)13574c7070dbSScott Long iflib_netmap_rxq_init(if_ctx_t ctx, iflib_rxq_t rxq)
13584c7070dbSScott Long {
13594c7070dbSScott Long struct netmap_adapter *na = NA(ctx->ifc_ifp);
1360d8b2d26bSVincenzo Maffione struct netmap_kring *kring;
13614c7070dbSScott Long struct netmap_slot *slot;
13624c7070dbSScott Long
13634c7070dbSScott Long slot = netmap_reset(na, NR_RX, rxq->ifr_id, 0);
1364e099b90bSPedro F. Giffuni if (slot == NULL)
1365d8b2d26bSVincenzo Maffione return (0);
1366d8b2d26bSVincenzo Maffione kring = na->rx_rings[rxq->ifr_id];
1367de5b4610SVincenzo Maffione netmap_fl_refill(rxq, kring, true);
1368d8b2d26bSVincenzo Maffione return (1);
13694c7070dbSScott Long }
13704c7070dbSScott Long
1371dd7fbcf1SStephen Hurd static void
iflib_netmap_timer(void * arg)137217cec474SVincenzo Maffione iflib_netmap_timer(void *arg)
1373dd7fbcf1SStephen Hurd {
137417cec474SVincenzo Maffione iflib_txq_t txq = arg;
137517cec474SVincenzo Maffione if_ctx_t ctx = txq->ift_ctx;
1376dd7fbcf1SStephen Hurd
137717cec474SVincenzo Maffione /*
137817cec474SVincenzo Maffione * Wake up the netmap application, to give it a chance to
137917cec474SVincenzo Maffione * call txsync and reclaim more completed TX buffers.
138017cec474SVincenzo Maffione */
138117cec474SVincenzo Maffione netmap_tx_irq(ctx->ifc_ifp, txq->ift_id);
1382dd7fbcf1SStephen Hurd }
1383dd7fbcf1SStephen Hurd
13844c7070dbSScott Long #define iflib_netmap_detach(ifp) netmap_detach(ifp)
13854c7070dbSScott Long
13864c7070dbSScott Long #else
1387d8b2d26bSVincenzo Maffione #define iflib_netmap_txq_init(ctx, txq) (0)
1388d8b2d26bSVincenzo Maffione #define iflib_netmap_rxq_init(ctx, rxq) (0)
13894c7070dbSScott Long #define iflib_netmap_detach(ifp)
13908aa8484cSVincenzo Maffione #define netmap_enable_all_rings(ifp)
13918aa8484cSVincenzo Maffione #define netmap_disable_all_rings(ifp)
13924c7070dbSScott Long
13934c7070dbSScott Long #define iflib_netmap_attach(ctx) (0)
13944c7070dbSScott Long #define netmap_rx_irq(ifp, qid, budget) (0)
13954c7070dbSScott Long #endif
13964c7070dbSScott Long
13974c7070dbSScott Long #if defined(__i386__) || defined(__amd64__)
13984c7070dbSScott Long static __inline void
prefetch(void * x)13994c7070dbSScott Long prefetch(void *x)
14004c7070dbSScott Long {
14014c7070dbSScott Long __asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
14024c7070dbSScott Long }
1403d08cb453SJohn Baldwin
14043429c02fSStephen Hurd static __inline void
prefetch2cachelines(void * x)14053429c02fSStephen Hurd prefetch2cachelines(void *x)
14063429c02fSStephen Hurd {
14073429c02fSStephen Hurd __asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
14083429c02fSStephen Hurd #if (CACHE_LINE_SIZE < 128)
14093429c02fSStephen Hurd __asm volatile("prefetcht0 %0" :: "m" (*(((unsigned long *)x) + CACHE_LINE_SIZE / (sizeof(unsigned long)))));
14103429c02fSStephen Hurd #endif
14113429c02fSStephen Hurd }
14124c7070dbSScott Long #else
1413d08cb453SJohn Baldwin static __inline void
prefetch(void * x)1414d08cb453SJohn Baldwin prefetch(void *x)
1415d08cb453SJohn Baldwin {
1416d08cb453SJohn Baldwin }
1417d08cb453SJohn Baldwin
1418d08cb453SJohn Baldwin static __inline void
prefetch2cachelines(void * x)1419d08cb453SJohn Baldwin prefetch2cachelines(void *x)
1420d08cb453SJohn Baldwin {
1421d08cb453SJohn Baldwin }
14224c7070dbSScott Long #endif
14234c7070dbSScott Long
14244c7070dbSScott Long static void
iru_init(if_rxd_update_t iru,iflib_rxq_t rxq,uint8_t flid)142510e0d938SStephen Hurd iru_init(if_rxd_update_t iru, iflib_rxq_t rxq, uint8_t flid)
142610e0d938SStephen Hurd {
142710e0d938SStephen Hurd iflib_fl_t fl;
142810e0d938SStephen Hurd
142910e0d938SStephen Hurd fl = &rxq->ifr_fl[flid];
143010e0d938SStephen Hurd iru->iru_paddrs = fl->ifl_bus_addrs;
143110e0d938SStephen Hurd iru->iru_idxs = fl->ifl_rxd_idxs;
143210e0d938SStephen Hurd iru->iru_qsidx = rxq->ifr_id;
143310e0d938SStephen Hurd iru->iru_buf_size = fl->ifl_buf_size;
143410e0d938SStephen Hurd iru->iru_flidx = fl->ifl_id;
143510e0d938SStephen Hurd }
143610e0d938SStephen Hurd
143710e0d938SStephen Hurd static void
_iflib_dmamap_cb(void * arg,bus_dma_segment_t * segs,int nseg,int err)14384c7070dbSScott Long _iflib_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
14394c7070dbSScott Long {
14404c7070dbSScott Long if (err)
14414c7070dbSScott Long return;
14424c7070dbSScott Long *(bus_addr_t *) arg = segs[0].ds_addr;
14434c7070dbSScott Long }
14444c7070dbSScott Long
14456dd69f00SMarcin Wojtas #define DMA_WIDTH_TO_BUS_LOWADDR(width) \
1446ef567155SMarcin Wojtas (((width) == 0) || (width) == flsll(BUS_SPACE_MAXADDR) ? \
14476dd69f00SMarcin Wojtas BUS_SPACE_MAXADDR : (1ULL << (width)) - 1ULL)
14486dd69f00SMarcin Wojtas
14494c7070dbSScott Long int
iflib_dma_alloc_align(if_ctx_t ctx,int size,int align,iflib_dma_info_t dma,int mapflags)14508f82136aSPatrick Kelsey iflib_dma_alloc_align(if_ctx_t ctx, int size, int align, iflib_dma_info_t dma, int mapflags)
14514c7070dbSScott Long {
14524c7070dbSScott Long int err;
14534c7070dbSScott Long device_t dev = ctx->ifc_dev;
14546dd69f00SMarcin Wojtas bus_addr_t lowaddr;
14556dd69f00SMarcin Wojtas
14566dd69f00SMarcin Wojtas lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(ctx->ifc_softc_ctx.isc_dma_width);
14574c7070dbSScott Long
14584c7070dbSScott Long err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
14598f82136aSPatrick Kelsey align, 0, /* alignment, bounds */
14606dd69f00SMarcin Wojtas lowaddr, /* lowaddr */
14614c7070dbSScott Long BUS_SPACE_MAXADDR, /* highaddr */
14624c7070dbSScott Long NULL, NULL, /* filter, filterarg */
14634c7070dbSScott Long size, /* maxsize */
14644c7070dbSScott Long 1, /* nsegments */
14654c7070dbSScott Long size, /* maxsegsize */
14664c7070dbSScott Long BUS_DMA_ALLOCNOW, /* flags */
14674c7070dbSScott Long NULL, /* lockfunc */
14684c7070dbSScott Long NULL, /* lockarg */
14694c7070dbSScott Long &dma->idi_tag);
14704c7070dbSScott Long if (err) {
14714c7070dbSScott Long device_printf(dev,
1472ed34a6b6SEric Joyner "%s: bus_dma_tag_create failed: %d (size=%d, align=%d)\n",
1473ed34a6b6SEric Joyner __func__, err, size, align);
14744c7070dbSScott Long goto fail_0;
14754c7070dbSScott Long }
14764c7070dbSScott Long
14774c7070dbSScott Long err = bus_dmamem_alloc(dma->idi_tag, (void **)&dma->idi_vaddr,
14784c7070dbSScott Long BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_ZERO, &dma->idi_map);
14794c7070dbSScott Long if (err) {
14804c7070dbSScott Long device_printf(dev,
14814c7070dbSScott Long "%s: bus_dmamem_alloc(%ju) failed: %d\n",
14824c7070dbSScott Long __func__, (uintmax_t)size, err);
14834c7070dbSScott Long goto fail_1;
14844c7070dbSScott Long }
14854c7070dbSScott Long
14864c7070dbSScott Long dma->idi_paddr = IF_BAD_DMA;
14874c7070dbSScott Long err = bus_dmamap_load(dma->idi_tag, dma->idi_map, dma->idi_vaddr,
14884c7070dbSScott Long size, _iflib_dmamap_cb, &dma->idi_paddr, mapflags | BUS_DMA_NOWAIT);
14894c7070dbSScott Long if (err || dma->idi_paddr == IF_BAD_DMA) {
14904c7070dbSScott Long device_printf(dev,
14914c7070dbSScott Long "%s: bus_dmamap_load failed: %d\n",
14924c7070dbSScott Long __func__, err);
14934c7070dbSScott Long goto fail_2;
14944c7070dbSScott Long }
14954c7070dbSScott Long
14964c7070dbSScott Long dma->idi_size = size;
14974c7070dbSScott Long return (0);
14984c7070dbSScott Long
14994c7070dbSScott Long fail_2:
15004c7070dbSScott Long bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map);
15014c7070dbSScott Long fail_1:
15024c7070dbSScott Long bus_dma_tag_destroy(dma->idi_tag);
15034c7070dbSScott Long fail_0:
15044c7070dbSScott Long dma->idi_tag = NULL;
15054c7070dbSScott Long
15064c7070dbSScott Long return (err);
15074c7070dbSScott Long }
15084c7070dbSScott Long
15094c7070dbSScott Long int
iflib_dma_alloc(if_ctx_t ctx,int size,iflib_dma_info_t dma,int mapflags)15108f82136aSPatrick Kelsey iflib_dma_alloc(if_ctx_t ctx, int size, iflib_dma_info_t dma, int mapflags)
15118f82136aSPatrick Kelsey {
15128f82136aSPatrick Kelsey if_shared_ctx_t sctx = ctx->ifc_sctx;
15138f82136aSPatrick Kelsey
15148f82136aSPatrick Kelsey KASSERT(sctx->isc_q_align != 0, ("alignment value not initialized"));
15158f82136aSPatrick Kelsey
15168f82136aSPatrick Kelsey return (iflib_dma_alloc_align(ctx, size, sctx->isc_q_align, dma, mapflags));
15178f82136aSPatrick Kelsey }
15188f82136aSPatrick Kelsey
15198f82136aSPatrick Kelsey int
iflib_dma_alloc_multi(if_ctx_t ctx,int * sizes,iflib_dma_info_t * dmalist,int mapflags,int count)15204c7070dbSScott Long iflib_dma_alloc_multi(if_ctx_t ctx, int *sizes, iflib_dma_info_t *dmalist, int mapflags, int count)
15214c7070dbSScott Long {
15224c7070dbSScott Long int i, err;
15234c7070dbSScott Long iflib_dma_info_t *dmaiter;
15244c7070dbSScott Long
15254c7070dbSScott Long dmaiter = dmalist;
15264c7070dbSScott Long for (i = 0; i < count; i++, dmaiter++) {
15274c7070dbSScott Long if ((err = iflib_dma_alloc(ctx, sizes[i], *dmaiter, mapflags)) != 0)
15284c7070dbSScott Long break;
15294c7070dbSScott Long }
15304c7070dbSScott Long if (err)
15314c7070dbSScott Long iflib_dma_free_multi(dmalist, i);
15324c7070dbSScott Long return (err);
15334c7070dbSScott Long }
15344c7070dbSScott Long
15354c7070dbSScott Long void
iflib_dma_free(iflib_dma_info_t dma)15364c7070dbSScott Long iflib_dma_free(iflib_dma_info_t dma)
15374c7070dbSScott Long {
15384c7070dbSScott Long if (dma->idi_tag == NULL)
15394c7070dbSScott Long return;
15404c7070dbSScott Long if (dma->idi_paddr != IF_BAD_DMA) {
15414c7070dbSScott Long bus_dmamap_sync(dma->idi_tag, dma->idi_map,
15424c7070dbSScott Long BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
15434c7070dbSScott Long bus_dmamap_unload(dma->idi_tag, dma->idi_map);
15444c7070dbSScott Long dma->idi_paddr = IF_BAD_DMA;
15454c7070dbSScott Long }
15464c7070dbSScott Long if (dma->idi_vaddr != NULL) {
15474c7070dbSScott Long bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map);
15484c7070dbSScott Long dma->idi_vaddr = NULL;
15494c7070dbSScott Long }
15504c7070dbSScott Long bus_dma_tag_destroy(dma->idi_tag);
15514c7070dbSScott Long dma->idi_tag = NULL;
15524c7070dbSScott Long }
15534c7070dbSScott Long
15544c7070dbSScott Long void
iflib_dma_free_multi(iflib_dma_info_t * dmalist,int count)15554c7070dbSScott Long iflib_dma_free_multi(iflib_dma_info_t *dmalist, int count)
15564c7070dbSScott Long {
15574c7070dbSScott Long int i;
15584c7070dbSScott Long iflib_dma_info_t *dmaiter = dmalist;
15594c7070dbSScott Long
15604c7070dbSScott Long for (i = 0; i < count; i++, dmaiter++)
15614c7070dbSScott Long iflib_dma_free(*dmaiter);
15624c7070dbSScott Long }
15634c7070dbSScott Long
15644c7070dbSScott Long static int
iflib_fast_intr(void * arg)15654c7070dbSScott Long iflib_fast_intr(void *arg)
15664c7070dbSScott Long {
15674c7070dbSScott Long iflib_filter_info_t info = arg;
15684c7070dbSScott Long struct grouptask *gtask = info->ifi_task;
1569ca62461bSStephen Hurd int result;
1570ca62461bSStephen Hurd
157195246abbSSean Bruno DBG_COUNTER_INC(fast_intrs);
1572ca62461bSStephen Hurd if (info->ifi_filter != NULL) {
1573ca62461bSStephen Hurd result = info->ifi_filter(info->ifi_filter_arg);
1574ca62461bSStephen Hurd if ((result & FILTER_SCHEDULE_THREAD) == 0)
1575ca62461bSStephen Hurd return (result);
1576ca62461bSStephen Hurd }
157795246abbSSean Bruno
157895246abbSSean Bruno GROUPTASK_ENQUEUE(gtask);
157995246abbSSean Bruno return (FILTER_HANDLED);
158095246abbSSean Bruno }
158195246abbSSean Bruno
158295246abbSSean Bruno static int
iflib_fast_intr_rxtx(void * arg)158395246abbSSean Bruno iflib_fast_intr_rxtx(void *arg)
158495246abbSSean Bruno {
158595246abbSSean Bruno iflib_filter_info_t info = arg;
158695246abbSSean Bruno struct grouptask *gtask = info->ifi_task;
158795dcf343SMarius Strobl if_ctx_t ctx;
158895246abbSSean Bruno iflib_rxq_t rxq = (iflib_rxq_t)info->ifi_ctx;
158995dcf343SMarius Strobl iflib_txq_t txq;
159095dcf343SMarius Strobl void *sc;
1591ca62461bSStephen Hurd int i, cidx, result;
159295dcf343SMarius Strobl qidx_t txqid;
15933d10e9edSMarius Strobl bool intr_enable, intr_legacy;
159495246abbSSean Bruno
159595246abbSSean Bruno DBG_COUNTER_INC(fast_intrs);
1596ca62461bSStephen Hurd if (info->ifi_filter != NULL) {
1597ca62461bSStephen Hurd result = info->ifi_filter(info->ifi_filter_arg);
1598ca62461bSStephen Hurd if ((result & FILTER_SCHEDULE_THREAD) == 0)
1599ca62461bSStephen Hurd return (result);
1600ca62461bSStephen Hurd }
160195246abbSSean Bruno
160295dcf343SMarius Strobl ctx = rxq->ifr_ctx;
160395dcf343SMarius Strobl sc = ctx->ifc_softc;
16043d10e9edSMarius Strobl intr_enable = false;
16053d10e9edSMarius Strobl intr_legacy = !!(ctx->ifc_flags & IFC_LEGACY);
16061ae4848cSMatt Macy MPASS(rxq->ifr_ntxqirq);
160795246abbSSean Bruno for (i = 0; i < rxq->ifr_ntxqirq; i++) {
160895dcf343SMarius Strobl txqid = rxq->ifr_txqid[i];
160995dcf343SMarius Strobl txq = &ctx->ifc_txqs[txqid];
161095dcf343SMarius Strobl bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
16118a04b53dSKonstantin Belousov BUS_DMASYNC_POSTREAD);
161295dcf343SMarius Strobl if (!ctx->isc_txd_credits_update(sc, txqid, false)) {
16133d10e9edSMarius Strobl if (intr_legacy)
16143d10e9edSMarius Strobl intr_enable = true;
16153d10e9edSMarius Strobl else
161695246abbSSean Bruno IFDI_TX_QUEUE_INTR_ENABLE(ctx, txqid);
161795246abbSSean Bruno continue;
161895246abbSSean Bruno }
161995dcf343SMarius Strobl GROUPTASK_ENQUEUE(&txq->ift_task);
162095246abbSSean Bruno }
162195246abbSSean Bruno if (ctx->ifc_sctx->isc_flags & IFLIB_HAS_RXCQ)
162295246abbSSean Bruno cidx = rxq->ifr_cq_cidx;
162395246abbSSean Bruno else
162495246abbSSean Bruno cidx = rxq->ifr_fl[0].ifl_cidx;
162595246abbSSean Bruno if (iflib_rxd_avail(ctx, rxq, cidx, 1))
162695246abbSSean Bruno GROUPTASK_ENQUEUE(gtask);
162764e6fc13SStephen Hurd else {
16283d10e9edSMarius Strobl if (intr_legacy)
16293d10e9edSMarius Strobl intr_enable = true;
16303d10e9edSMarius Strobl else
163195246abbSSean Bruno IFDI_RX_QUEUE_INTR_ENABLE(ctx, rxq->ifr_id);
163264e6fc13SStephen Hurd DBG_COUNTER_INC(rx_intr_enables);
163364e6fc13SStephen Hurd }
16343d10e9edSMarius Strobl if (intr_enable)
16353d10e9edSMarius Strobl IFDI_INTR_ENABLE(ctx);
163695246abbSSean Bruno return (FILTER_HANDLED);
163795246abbSSean Bruno }
163895246abbSSean Bruno
163995246abbSSean Bruno static int
iflib_fast_intr_ctx(void * arg)164095246abbSSean Bruno iflib_fast_intr_ctx(void *arg)
164195246abbSSean Bruno {
164295246abbSSean Bruno iflib_filter_info_t info = arg;
164395246abbSSean Bruno struct grouptask *gtask = info->ifi_task;
1644ca62461bSStephen Hurd int result;
16454c7070dbSScott Long
16464c7070dbSScott Long DBG_COUNTER_INC(fast_intrs);
1647ca62461bSStephen Hurd if (info->ifi_filter != NULL) {
1648ca62461bSStephen Hurd result = info->ifi_filter(info->ifi_filter_arg);
1649ca62461bSStephen Hurd if ((result & FILTER_SCHEDULE_THREAD) == 0)
1650ca62461bSStephen Hurd return (result);
1651ca62461bSStephen Hurd }
16524c7070dbSScott Long
165304d4e345SPrzemyslaw Lewandowski if (gtask->gt_taskqueue != NULL)
16544c7070dbSScott Long GROUPTASK_ENQUEUE(gtask);
16554c7070dbSScott Long return (FILTER_HANDLED);
16564c7070dbSScott Long }
16574c7070dbSScott Long
16584c7070dbSScott Long static int
_iflib_irq_alloc(if_ctx_t ctx,if_irq_t irq,int rid,driver_filter_t filter,driver_intr_t handler,void * arg,const char * name)16594c7070dbSScott Long _iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid,
16604c7070dbSScott Long driver_filter_t filter, driver_intr_t handler, void *arg,
16613e0e6330SStephen Hurd const char *name)
16624c7070dbSScott Long {
16634c7070dbSScott Long struct resource *res;
16642b2fc973SSean Bruno void *tag = NULL;
16654c7070dbSScott Long device_t dev = ctx->ifc_dev;
1666d49e83eaSMarius Strobl int flags, i, rc;
16674c7070dbSScott Long
16682b2fc973SSean Bruno flags = RF_ACTIVE;
16692b2fc973SSean Bruno if (ctx->ifc_flags & IFC_LEGACY)
16702b2fc973SSean Bruno flags |= RF_SHAREABLE;
16714c7070dbSScott Long MPASS(rid < 512);
1672d49e83eaSMarius Strobl i = rid;
1673d49e83eaSMarius Strobl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, flags);
16744c7070dbSScott Long if (res == NULL) {
16754c7070dbSScott Long device_printf(dev,
16764c7070dbSScott Long "failed to allocate IRQ for rid %d, name %s.\n", rid, name);
16774c7070dbSScott Long return (ENOMEM);
16784c7070dbSScott Long }
16794c7070dbSScott Long irq->ii_res = res;
16804c7070dbSScott Long KASSERT(filter == NULL || handler == NULL, ("filter and handler can't both be non-NULL"));
16814c7070dbSScott Long rc = bus_setup_intr(dev, res, INTR_MPSAFE | INTR_TYPE_NET,
16824c7070dbSScott Long filter, handler, arg, &tag);
16834c7070dbSScott Long if (rc != 0) {
16844c7070dbSScott Long device_printf(dev,
16854c7070dbSScott Long "failed to setup interrupt for rid %d, name %s: %d\n",
16864c7070dbSScott Long rid, name ? name : "unknown", rc);
16874c7070dbSScott Long return (rc);
16884c7070dbSScott Long } else if (name)
1689f454e7ebSJohn Baldwin bus_describe_intr(dev, res, tag, "%s", name);
16904c7070dbSScott Long
16914c7070dbSScott Long irq->ii_tag = tag;
16924c7070dbSScott Long return (0);
16934c7070dbSScott Long }
16944c7070dbSScott Long
16954c7070dbSScott Long /*********************************************************************
16964c7070dbSScott Long *
1697bfce461eSMarius Strobl * Allocate DMA resources for TX buffers as well as memory for the TX
1698bfce461eSMarius Strobl * mbuf map. TX DMA maps (non-TSO/TSO) and TX mbuf map are kept in a
1699bfce461eSMarius Strobl * iflib_sw_tx_desc_array structure, storing all the information that
1700bfce461eSMarius Strobl * is needed to transmit a packet on the wire. This is called only
1701bfce461eSMarius Strobl * once at attach, setup is done every reset.
17024c7070dbSScott Long *
17034c7070dbSScott Long **********************************************************************/
17044c7070dbSScott Long static int
iflib_txsd_alloc(iflib_txq_t txq)17054c7070dbSScott Long iflib_txsd_alloc(iflib_txq_t txq)
17064c7070dbSScott Long {
17074c7070dbSScott Long if_ctx_t ctx = txq->ift_ctx;
17084c7070dbSScott Long if_shared_ctx_t sctx = ctx->ifc_sctx;
17094c7070dbSScott Long if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
17104c7070dbSScott Long device_t dev = ctx->ifc_dev;
17117f87c040SMarius Strobl bus_size_t tsomaxsize;
17126dd69f00SMarcin Wojtas bus_addr_t lowaddr;
17134c7070dbSScott Long int err, nsegments, ntsosegments;
17148a04b53dSKonstantin Belousov bool tso;
17154c7070dbSScott Long
17164c7070dbSScott Long nsegments = scctx->isc_tx_nsegments;
17174c7070dbSScott Long ntsosegments = scctx->isc_tx_tso_segments_max;
17187f87c040SMarius Strobl tsomaxsize = scctx->isc_tx_tso_size_max;
17197f87c040SMarius Strobl if (if_getcapabilities(ctx->ifc_ifp) & IFCAP_VLAN_MTU)
17207f87c040SMarius Strobl tsomaxsize += sizeof(struct ether_vlan_header);
172123ac9029SStephen Hurd MPASS(scctx->isc_ntxd[0] > 0);
172223ac9029SStephen Hurd MPASS(scctx->isc_ntxd[txq->ift_br_offset] > 0);
17234c7070dbSScott Long MPASS(nsegments > 0);
17247f87c040SMarius Strobl if (if_getcapabilities(ctx->ifc_ifp) & IFCAP_TSO) {
17254c7070dbSScott Long MPASS(ntsosegments > 0);
17267f87c040SMarius Strobl MPASS(sctx->isc_tso_maxsize >= tsomaxsize);
17277f87c040SMarius Strobl }
17287f87c040SMarius Strobl
17296dd69f00SMarcin Wojtas lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(scctx->isc_dma_width);
17306dd69f00SMarcin Wojtas
17314c7070dbSScott Long /*
1732bfce461eSMarius Strobl * Set up DMA tags for TX buffers.
17334c7070dbSScott Long */
17344c7070dbSScott Long if ((err = bus_dma_tag_create(bus_get_dma_tag(dev),
17354c7070dbSScott Long 1, 0, /* alignment, bounds */
17366dd69f00SMarcin Wojtas lowaddr, /* lowaddr */
17374c7070dbSScott Long BUS_SPACE_MAXADDR, /* highaddr */
17384c7070dbSScott Long NULL, NULL, /* filter, filterarg */
17394c7070dbSScott Long sctx->isc_tx_maxsize, /* maxsize */
17404c7070dbSScott Long nsegments, /* nsegments */
17414c7070dbSScott Long sctx->isc_tx_maxsegsize, /* maxsegsize */
17424c7070dbSScott Long 0, /* flags */
17434c7070dbSScott Long NULL, /* lockfunc */
17444c7070dbSScott Long NULL, /* lockfuncarg */
1745bfce461eSMarius Strobl &txq->ift_buf_tag))) {
17464c7070dbSScott Long device_printf(dev, "Unable to allocate TX DMA tag: %d\n", err);
17479d0a88deSDimitry Andric device_printf(dev, "maxsize: %ju nsegments: %d maxsegsize: %ju\n",
17489d0a88deSDimitry Andric (uintmax_t)sctx->isc_tx_maxsize, nsegments, (uintmax_t)sctx->isc_tx_maxsegsize);
17494c7070dbSScott Long goto fail;
17504c7070dbSScott Long }
17518a04b53dSKonstantin Belousov tso = (if_getcapabilities(ctx->ifc_ifp) & IFCAP_TSO) != 0;
17528a04b53dSKonstantin Belousov if (tso && (err = bus_dma_tag_create(bus_get_dma_tag(dev),
17534c7070dbSScott Long 1, 0, /* alignment, bounds */
17546dd69f00SMarcin Wojtas lowaddr, /* lowaddr */
17554c7070dbSScott Long BUS_SPACE_MAXADDR, /* highaddr */
17564c7070dbSScott Long NULL, NULL, /* filter, filterarg */
17577f87c040SMarius Strobl tsomaxsize, /* maxsize */
17584c7070dbSScott Long ntsosegments, /* nsegments */
17597f87c040SMarius Strobl sctx->isc_tso_maxsegsize,/* maxsegsize */
17604c7070dbSScott Long 0, /* flags */
17614c7070dbSScott Long NULL, /* lockfunc */
17624c7070dbSScott Long NULL, /* lockfuncarg */
1763bfce461eSMarius Strobl &txq->ift_tso_buf_tag))) {
1764bfce461eSMarius Strobl device_printf(dev, "Unable to allocate TSO TX DMA tag: %d\n",
1765bfce461eSMarius Strobl err);
17664c7070dbSScott Long goto fail;
17674c7070dbSScott Long }
1768bfce461eSMarius Strobl
1769bfce461eSMarius Strobl /* Allocate memory for the TX mbuf map. */
17704c7070dbSScott Long if (!(txq->ift_sds.ifsd_m =
1771ac2fffa4SPedro F. Giffuni (struct mbuf **) malloc(sizeof(struct mbuf *) *
1772ac2fffa4SPedro F. Giffuni scctx->isc_ntxd[txq->ift_br_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1773bfce461eSMarius Strobl device_printf(dev, "Unable to allocate TX mbuf map memory\n");
17744c7070dbSScott Long err = ENOMEM;
17754c7070dbSScott Long goto fail;
17764c7070dbSScott Long }
17774c7070dbSScott Long
1778bfce461eSMarius Strobl /*
1779bfce461eSMarius Strobl * Create the DMA maps for TX buffers.
1780bfce461eSMarius Strobl */
17818a04b53dSKonstantin Belousov if ((txq->ift_sds.ifsd_map = (bus_dmamap_t *)malloc(
17828a04b53dSKonstantin Belousov sizeof(bus_dmamap_t) * scctx->isc_ntxd[txq->ift_br_offset],
17838a04b53dSKonstantin Belousov M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
1784bfce461eSMarius Strobl device_printf(dev,
1785bfce461eSMarius Strobl "Unable to allocate TX buffer DMA map memory\n");
17864c7070dbSScott Long err = ENOMEM;
17874c7070dbSScott Long goto fail;
17884c7070dbSScott Long }
17898a04b53dSKonstantin Belousov if (tso && (txq->ift_sds.ifsd_tso_map = (bus_dmamap_t *)malloc(
17908a04b53dSKonstantin Belousov sizeof(bus_dmamap_t) * scctx->isc_ntxd[txq->ift_br_offset],
17918a04b53dSKonstantin Belousov M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
1792bfce461eSMarius Strobl device_printf(dev,
1793bfce461eSMarius Strobl "Unable to allocate TSO TX buffer map memory\n");
17948a04b53dSKonstantin Belousov err = ENOMEM;
17958a04b53dSKonstantin Belousov goto fail;
17968a04b53dSKonstantin Belousov }
179723ac9029SStephen Hurd for (int i = 0; i < scctx->isc_ntxd[txq->ift_br_offset]; i++) {
1798bfce461eSMarius Strobl err = bus_dmamap_create(txq->ift_buf_tag, 0,
17998a04b53dSKonstantin Belousov &txq->ift_sds.ifsd_map[i]);
18004c7070dbSScott Long if (err != 0) {
18014c7070dbSScott Long device_printf(dev, "Unable to create TX DMA map\n");
18024c7070dbSScott Long goto fail;
18034c7070dbSScott Long }
18048a04b53dSKonstantin Belousov if (!tso)
18058a04b53dSKonstantin Belousov continue;
1806bfce461eSMarius Strobl err = bus_dmamap_create(txq->ift_tso_buf_tag, 0,
18078a04b53dSKonstantin Belousov &txq->ift_sds.ifsd_tso_map[i]);
18088a04b53dSKonstantin Belousov if (err != 0) {
18098a04b53dSKonstantin Belousov device_printf(dev, "Unable to create TSO TX DMA map\n");
18108a04b53dSKonstantin Belousov goto fail;
18118a04b53dSKonstantin Belousov }
18124c7070dbSScott Long }
18134c7070dbSScott Long return (0);
18144c7070dbSScott Long fail:
18154c7070dbSScott Long /* We free all, it handles case where we are in the middle */
18164c7070dbSScott Long iflib_tx_structures_free(ctx);
18174c7070dbSScott Long return (err);
18184c7070dbSScott Long }
18194c7070dbSScott Long
18204c7070dbSScott Long static void
iflib_txsd_destroy(if_ctx_t ctx,iflib_txq_t txq,int i)18214c7070dbSScott Long iflib_txsd_destroy(if_ctx_t ctx, iflib_txq_t txq, int i)
18224c7070dbSScott Long {
18234c7070dbSScott Long bus_dmamap_t map;
18244c7070dbSScott Long
1825db8e8f1eSEric Joyner if (txq->ift_sds.ifsd_map != NULL) {
18264c7070dbSScott Long map = txq->ift_sds.ifsd_map[i];
1827bfce461eSMarius Strobl bus_dmamap_sync(txq->ift_buf_tag, map, BUS_DMASYNC_POSTWRITE);
1828bfce461eSMarius Strobl bus_dmamap_unload(txq->ift_buf_tag, map);
1829bfce461eSMarius Strobl bus_dmamap_destroy(txq->ift_buf_tag, map);
18304c7070dbSScott Long txq->ift_sds.ifsd_map[i] = NULL;
18314c7070dbSScott Long }
18328a04b53dSKonstantin Belousov
1833db8e8f1eSEric Joyner if (txq->ift_sds.ifsd_tso_map != NULL) {
18348a04b53dSKonstantin Belousov map = txq->ift_sds.ifsd_tso_map[i];
1835bfce461eSMarius Strobl bus_dmamap_sync(txq->ift_tso_buf_tag, map,
18368a04b53dSKonstantin Belousov BUS_DMASYNC_POSTWRITE);
1837bfce461eSMarius Strobl bus_dmamap_unload(txq->ift_tso_buf_tag, map);
1838bfce461eSMarius Strobl bus_dmamap_destroy(txq->ift_tso_buf_tag, map);
18398a04b53dSKonstantin Belousov txq->ift_sds.ifsd_tso_map[i] = NULL;
18408a04b53dSKonstantin Belousov }
18414c7070dbSScott Long }
18424c7070dbSScott Long
18434c7070dbSScott Long static void
iflib_txq_destroy(iflib_txq_t txq)18444c7070dbSScott Long iflib_txq_destroy(iflib_txq_t txq)
18454c7070dbSScott Long {
18464c7070dbSScott Long if_ctx_t ctx = txq->ift_ctx;
18474c7070dbSScott Long
184823ac9029SStephen Hurd for (int i = 0; i < txq->ift_size; i++)
18494c7070dbSScott Long iflib_txsd_destroy(ctx, txq, i);
1850244e7cffSEric Joyner
1851244e7cffSEric Joyner if (txq->ift_br != NULL) {
1852244e7cffSEric Joyner ifmp_ring_free(txq->ift_br);
1853244e7cffSEric Joyner txq->ift_br = NULL;
1854244e7cffSEric Joyner }
1855244e7cffSEric Joyner
1856244e7cffSEric Joyner mtx_destroy(&txq->ift_mtx);
1857244e7cffSEric Joyner
18584c7070dbSScott Long if (txq->ift_sds.ifsd_map != NULL) {
18594c7070dbSScott Long free(txq->ift_sds.ifsd_map, M_IFLIB);
18604c7070dbSScott Long txq->ift_sds.ifsd_map = NULL;
18614c7070dbSScott Long }
18628a04b53dSKonstantin Belousov if (txq->ift_sds.ifsd_tso_map != NULL) {
18638a04b53dSKonstantin Belousov free(txq->ift_sds.ifsd_tso_map, M_IFLIB);
18648a04b53dSKonstantin Belousov txq->ift_sds.ifsd_tso_map = NULL;
18658a04b53dSKonstantin Belousov }
18664c7070dbSScott Long if (txq->ift_sds.ifsd_m != NULL) {
18674c7070dbSScott Long free(txq->ift_sds.ifsd_m, M_IFLIB);
18684c7070dbSScott Long txq->ift_sds.ifsd_m = NULL;
18694c7070dbSScott Long }
1870bfce461eSMarius Strobl if (txq->ift_buf_tag != NULL) {
1871bfce461eSMarius Strobl bus_dma_tag_destroy(txq->ift_buf_tag);
1872bfce461eSMarius Strobl txq->ift_buf_tag = NULL;
18734c7070dbSScott Long }
1874bfce461eSMarius Strobl if (txq->ift_tso_buf_tag != NULL) {
1875bfce461eSMarius Strobl bus_dma_tag_destroy(txq->ift_tso_buf_tag);
1876bfce461eSMarius Strobl txq->ift_tso_buf_tag = NULL;
18774c7070dbSScott Long }
1878244e7cffSEric Joyner if (txq->ift_ifdi != NULL) {
1879244e7cffSEric Joyner free(txq->ift_ifdi, M_IFLIB);
1880244e7cffSEric Joyner }
18814c7070dbSScott Long }
18824c7070dbSScott Long
18834c7070dbSScott Long static void
iflib_txsd_free(if_ctx_t ctx,iflib_txq_t txq,int i)18844c7070dbSScott Long iflib_txsd_free(if_ctx_t ctx, iflib_txq_t txq, int i)
18854c7070dbSScott Long {
18864c7070dbSScott Long struct mbuf **mp;
18874c7070dbSScott Long
18884c7070dbSScott Long mp = &txq->ift_sds.ifsd_m[i];
18894c7070dbSScott Long if (*mp == NULL)
18904c7070dbSScott Long return;
18914c7070dbSScott Long
18924c7070dbSScott Long if (txq->ift_sds.ifsd_map != NULL) {
1893bfce461eSMarius Strobl bus_dmamap_sync(txq->ift_buf_tag,
18948a04b53dSKonstantin Belousov txq->ift_sds.ifsd_map[i], BUS_DMASYNC_POSTWRITE);
1895bfce461eSMarius Strobl bus_dmamap_unload(txq->ift_buf_tag, txq->ift_sds.ifsd_map[i]);
18968a04b53dSKonstantin Belousov }
18978a04b53dSKonstantin Belousov if (txq->ift_sds.ifsd_tso_map != NULL) {
1898bfce461eSMarius Strobl bus_dmamap_sync(txq->ift_tso_buf_tag,
18998a04b53dSKonstantin Belousov txq->ift_sds.ifsd_tso_map[i], BUS_DMASYNC_POSTWRITE);
1900bfce461eSMarius Strobl bus_dmamap_unload(txq->ift_tso_buf_tag,
19018a04b53dSKonstantin Belousov txq->ift_sds.ifsd_tso_map[i]);
19024c7070dbSScott Long }
190354bf96fbSMark Johnston m_freem(*mp);
19044c7070dbSScott Long DBG_COUNTER_INC(tx_frees);
19054c7070dbSScott Long *mp = NULL;
19064c7070dbSScott Long }
19074c7070dbSScott Long
19084c7070dbSScott Long static int
iflib_txq_setup(iflib_txq_t txq)19094c7070dbSScott Long iflib_txq_setup(iflib_txq_t txq)
19104c7070dbSScott Long {
19114c7070dbSScott Long if_ctx_t ctx = txq->ift_ctx;
191223ac9029SStephen Hurd if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
19134d261ce2SStephen Hurd if_shared_ctx_t sctx = ctx->ifc_sctx;
19144c7070dbSScott Long iflib_dma_info_t di;
19154c7070dbSScott Long int i;
19164c7070dbSScott Long
19174c7070dbSScott Long /* Set number of descriptors available */
19184c7070dbSScott Long txq->ift_qstatus = IFLIB_QUEUE_IDLE;
191995246abbSSean Bruno /* XXX make configurable */
192095246abbSSean Bruno txq->ift_update_freq = IFLIB_DEFAULT_TX_UPDATE_FREQ;
19214c7070dbSScott Long
19224c7070dbSScott Long /* Reset indices */
192395246abbSSean Bruno txq->ift_cidx_processed = 0;
192495246abbSSean Bruno txq->ift_pidx = txq->ift_cidx = txq->ift_npending = 0;
192523ac9029SStephen Hurd txq->ift_size = scctx->isc_ntxd[txq->ift_br_offset];
19264c7070dbSScott Long
19274d261ce2SStephen Hurd for (i = 0, di = txq->ift_ifdi; i < sctx->isc_ntxqs; i++, di++)
19284c7070dbSScott Long bzero((void *)di->idi_vaddr, di->idi_size);
19294c7070dbSScott Long
19304c7070dbSScott Long IFDI_TXQ_SETUP(ctx, txq->ift_id);
19314d261ce2SStephen Hurd for (i = 0, di = txq->ift_ifdi; i < sctx->isc_ntxqs; i++, di++)
19324c7070dbSScott Long bus_dmamap_sync(di->idi_tag, di->idi_map,
19334c7070dbSScott Long BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
19344c7070dbSScott Long return (0);
19354c7070dbSScott Long }
19364c7070dbSScott Long
19374c7070dbSScott Long /*********************************************************************
19384c7070dbSScott Long *
1939bfce461eSMarius Strobl * Allocate DMA resources for RX buffers as well as memory for the RX
1940bfce461eSMarius Strobl * mbuf map, direct RX cluster pointer map and RX cluster bus address
1941bfce461eSMarius Strobl * map. RX DMA map, RX mbuf map, direct RX cluster pointer map and
1942bfce461eSMarius Strobl * RX cluster map are kept in a iflib_sw_rx_desc_array structure.
1943bfce461eSMarius Strobl * Since we use use one entry in iflib_sw_rx_desc_array per received
1944bfce461eSMarius Strobl * packet, the maximum number of entries we'll need is equal to the
1945bfce461eSMarius Strobl * number of hardware receive descriptors that we've allocated.
19464c7070dbSScott Long *
19474c7070dbSScott Long **********************************************************************/
19484c7070dbSScott Long static int
iflib_rxsd_alloc(iflib_rxq_t rxq)19494c7070dbSScott Long iflib_rxsd_alloc(iflib_rxq_t rxq)
19504c7070dbSScott Long {
19514c7070dbSScott Long if_ctx_t ctx = rxq->ifr_ctx;
19524c7070dbSScott Long if_shared_ctx_t sctx = ctx->ifc_sctx;
195323ac9029SStephen Hurd if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
19544c7070dbSScott Long device_t dev = ctx->ifc_dev;
19554c7070dbSScott Long iflib_fl_t fl;
19566dd69f00SMarcin Wojtas bus_addr_t lowaddr;
19574c7070dbSScott Long int err;
19584c7070dbSScott Long
195923ac9029SStephen Hurd MPASS(scctx->isc_nrxd[0] > 0);
196023ac9029SStephen Hurd MPASS(scctx->isc_nrxd[rxq->ifr_fl_offset] > 0);
19614c7070dbSScott Long
19626dd69f00SMarcin Wojtas lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(scctx->isc_dma_width);
19636dd69f00SMarcin Wojtas
19644c7070dbSScott Long fl = rxq->ifr_fl;
19654c7070dbSScott Long for (int i = 0; i < rxq->ifr_nfl; i++, fl++) {
196623ac9029SStephen Hurd fl->ifl_size = scctx->isc_nrxd[rxq->ifr_fl_offset]; /* this isn't necessarily the same */
1967bfce461eSMarius Strobl /* Set up DMA tag for RX buffers. */
19684c7070dbSScott Long err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
19694c7070dbSScott Long 1, 0, /* alignment, bounds */
19706dd69f00SMarcin Wojtas lowaddr, /* lowaddr */
19714c7070dbSScott Long BUS_SPACE_MAXADDR, /* highaddr */
19724c7070dbSScott Long NULL, NULL, /* filter, filterarg */
19734c7070dbSScott Long sctx->isc_rx_maxsize, /* maxsize */
19744c7070dbSScott Long sctx->isc_rx_nsegments, /* nsegments */
19754c7070dbSScott Long sctx->isc_rx_maxsegsize, /* maxsegsize */
19764c7070dbSScott Long 0, /* flags */
19774c7070dbSScott Long NULL, /* lockfunc */
19784c7070dbSScott Long NULL, /* lockarg */
1979bfce461eSMarius Strobl &fl->ifl_buf_tag);
19804c7070dbSScott Long if (err) {
1981bfce461eSMarius Strobl device_printf(dev,
1982bfce461eSMarius Strobl "Unable to allocate RX DMA tag: %d\n", err);
19834c7070dbSScott Long goto fail;
19844c7070dbSScott Long }
1985bfce461eSMarius Strobl
1986bfce461eSMarius Strobl /* Allocate memory for the RX mbuf map. */
1987e035717eSSean Bruno if (!(fl->ifl_sds.ifsd_m =
1988ac2fffa4SPedro F. Giffuni (struct mbuf **) malloc(sizeof(struct mbuf *) *
1989ac2fffa4SPedro F. Giffuni scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1990bfce461eSMarius Strobl device_printf(dev,
1991bfce461eSMarius Strobl "Unable to allocate RX mbuf map memory\n");
1992e035717eSSean Bruno err = ENOMEM;
1993e035717eSSean Bruno goto fail;
1994e035717eSSean Bruno }
1995bfce461eSMarius Strobl
1996bfce461eSMarius Strobl /* Allocate memory for the direct RX cluster pointer map. */
1997e035717eSSean Bruno if (!(fl->ifl_sds.ifsd_cl =
1998ac2fffa4SPedro F. Giffuni (caddr_t *) malloc(sizeof(caddr_t) *
1999ac2fffa4SPedro F. Giffuni scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
2000bfce461eSMarius Strobl device_printf(dev,
2001bfce461eSMarius Strobl "Unable to allocate RX cluster map memory\n");
2002e035717eSSean Bruno err = ENOMEM;
2003e035717eSSean Bruno goto fail;
2004e035717eSSean Bruno }
20054c7070dbSScott Long
2006bfce461eSMarius Strobl /* Allocate memory for the RX cluster bus address map. */
2007fbec776dSAndrew Gallatin if (!(fl->ifl_sds.ifsd_ba =
2008fbec776dSAndrew Gallatin (bus_addr_t *) malloc(sizeof(bus_addr_t) *
2009fbec776dSAndrew Gallatin scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
2010bfce461eSMarius Strobl device_printf(dev,
2011bfce461eSMarius Strobl "Unable to allocate RX bus address map memory\n");
2012fbec776dSAndrew Gallatin err = ENOMEM;
2013fbec776dSAndrew Gallatin goto fail;
2014fbec776dSAndrew Gallatin }
2015e035717eSSean Bruno
2016bfce461eSMarius Strobl /*
2017bfce461eSMarius Strobl * Create the DMA maps for RX buffers.
2018bfce461eSMarius Strobl */
2019e035717eSSean Bruno if (!(fl->ifl_sds.ifsd_map =
2020ac2fffa4SPedro F. Giffuni (bus_dmamap_t *) malloc(sizeof(bus_dmamap_t) * scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
2021bfce461eSMarius Strobl device_printf(dev,
2022bfce461eSMarius Strobl "Unable to allocate RX buffer DMA map memory\n");
2023e035717eSSean Bruno err = ENOMEM;
2024e035717eSSean Bruno goto fail;
2025e035717eSSean Bruno }
2026e035717eSSean Bruno for (int i = 0; i < scctx->isc_nrxd[rxq->ifr_fl_offset]; i++) {
2027bfce461eSMarius Strobl err = bus_dmamap_create(fl->ifl_buf_tag, 0,
2028bfce461eSMarius Strobl &fl->ifl_sds.ifsd_map[i]);
2029e035717eSSean Bruno if (err != 0) {
203095246abbSSean Bruno device_printf(dev, "Unable to create RX buffer DMA map\n");
20314c7070dbSScott Long goto fail;
20324c7070dbSScott Long }
20334c7070dbSScott Long }
2034835809f9SSean Bruno }
20354c7070dbSScott Long return (0);
20364c7070dbSScott Long
20374c7070dbSScott Long fail:
20384c7070dbSScott Long iflib_rx_structures_free(ctx);
20394c7070dbSScott Long return (err);
20404c7070dbSScott Long }
20414c7070dbSScott Long
20424c7070dbSScott Long /*
20434c7070dbSScott Long * Internal service routines
20444c7070dbSScott Long */
20454c7070dbSScott Long
20464c7070dbSScott Long struct rxq_refill_cb_arg {
20474c7070dbSScott Long int error;
20484c7070dbSScott Long bus_dma_segment_t seg;
20494c7070dbSScott Long int nseg;
20504c7070dbSScott Long };
20514c7070dbSScott Long
20524c7070dbSScott Long static void
_rxq_refill_cb(void * arg,bus_dma_segment_t * segs,int nseg,int error)20534c7070dbSScott Long _rxq_refill_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
20544c7070dbSScott Long {
20554c7070dbSScott Long struct rxq_refill_cb_arg *cb_arg = arg;
20564c7070dbSScott Long
20574c7070dbSScott Long cb_arg->error = error;
20584c7070dbSScott Long cb_arg->seg = segs[0];
20594c7070dbSScott Long cb_arg->nseg = nseg;
20604c7070dbSScott Long }
20614c7070dbSScott Long
20624c7070dbSScott Long /**
2063b256d25cSMark Johnston * iflib_fl_refill - refill an rxq free-buffer list
20644c7070dbSScott Long * @ctx: the iflib context
20651722eeacSMarius Strobl * @fl: the free list to refill
20661722eeacSMarius Strobl * @count: the number of new buffers to allocate
20674c7070dbSScott Long *
20681722eeacSMarius Strobl * (Re)populate an rxq free-buffer list with up to @count new packet buffers.
206935d8a463SVincenzo Maffione * The caller must assure that @count does not exceed the queue's capacity
207035d8a463SVincenzo Maffione * minus one (since we always leave a descriptor unavailable).
20714c7070dbSScott Long */
2072fb1a29b4SHans Petter Selasky static uint8_t
iflib_fl_refill(if_ctx_t ctx,iflib_fl_t fl,int count)2073b256d25cSMark Johnston iflib_fl_refill(if_ctx_t ctx, iflib_fl_t fl, int count)
20744c7070dbSScott Long {
207595246abbSSean Bruno struct if_rxd_update iru;
2076fbec776dSAndrew Gallatin struct rxq_refill_cb_arg cb_arg;
20773db348b5SMarius Strobl struct mbuf *m;
20783db348b5SMarius Strobl caddr_t cl, *sd_cl;
20793db348b5SMarius Strobl struct mbuf **sd_m;
2080e035717eSSean Bruno bus_dmamap_t *sd_map;
2081fbec776dSAndrew Gallatin bus_addr_t bus_addr, *sd_ba;
20823db348b5SMarius Strobl int err, frag_idx, i, idx, n, pidx;
2083a1b799caSStephen Hurd qidx_t credits;
20844c7070dbSScott Long
208535d8a463SVincenzo Maffione MPASS(count <= fl->ifl_size - fl->ifl_credits - 1);
208635d8a463SVincenzo Maffione
2087e035717eSSean Bruno sd_m = fl->ifl_sds.ifsd_m;
2088e035717eSSean Bruno sd_map = fl->ifl_sds.ifsd_map;
2089e035717eSSean Bruno sd_cl = fl->ifl_sds.ifsd_cl;
2090fbec776dSAndrew Gallatin sd_ba = fl->ifl_sds.ifsd_ba;
20913db348b5SMarius Strobl pidx = fl->ifl_pidx;
2092e035717eSSean Bruno idx = pidx;
20933db348b5SMarius Strobl frag_idx = fl->ifl_fragidx;
2094a1b799caSStephen Hurd credits = fl->ifl_credits;
2095e035717eSSean Bruno
20963db348b5SMarius Strobl i = 0;
20974c7070dbSScott Long n = count;
20984c7070dbSScott Long MPASS(n > 0);
2099a1b799caSStephen Hurd MPASS(credits + n <= fl->ifl_size);
21004c7070dbSScott Long
21014c7070dbSScott Long if (pidx < fl->ifl_cidx)
21024c7070dbSScott Long MPASS(pidx + n <= fl->ifl_cidx);
2103a1b799caSStephen Hurd if (pidx == fl->ifl_cidx && (credits < fl->ifl_size))
21044c7070dbSScott Long MPASS(fl->ifl_gen == 0);
21054c7070dbSScott Long if (pidx > fl->ifl_cidx)
21064c7070dbSScott Long MPASS(n <= fl->ifl_size - pidx + fl->ifl_cidx);
21074c7070dbSScott Long
21084c7070dbSScott Long DBG_COUNTER_INC(fl_refills);
21094c7070dbSScott Long if (n > 8)
21104c7070dbSScott Long DBG_COUNTER_INC(fl_refills_large);
21112d873474SStephen Hurd iru_init(&iru, fl->ifl_rxq, fl->ifl_id);
2112b256d25cSMark Johnston while (n-- > 0) {
21134c7070dbSScott Long /*
21144c7070dbSScott Long * We allocate an uninitialized mbuf + cluster, mbuf is
21154c7070dbSScott Long * initialized after rx.
21164c7070dbSScott Long *
2117b256d25cSMark Johnston * If the cluster is still set then we know a minimum sized
2118b256d25cSMark Johnston * packet was received
21194c7070dbSScott Long */
21203db348b5SMarius Strobl bit_ffc_at(fl->ifl_rx_bitmap, frag_idx, fl->ifl_size,
21213db348b5SMarius Strobl &frag_idx);
21223db348b5SMarius Strobl if (frag_idx < 0)
212387890dbaSSean Bruno bit_ffc(fl->ifl_rx_bitmap, fl->ifl_size, &frag_idx);
21243db348b5SMarius Strobl MPASS(frag_idx >= 0);
212587890dbaSSean Bruno if ((cl = sd_cl[frag_idx]) == NULL) {
2126b256d25cSMark Johnston cl = uma_zalloc(fl->ifl_zone, M_NOWAIT);
2127a363e1d4SMark Johnston if (__predict_false(cl == NULL))
21284c7070dbSScott Long break;
21294c7070dbSScott Long
21304c7070dbSScott Long cb_arg.error = 0;
213195246abbSSean Bruno MPASS(sd_map != NULL);
2132bfce461eSMarius Strobl err = bus_dmamap_load(fl->ifl_buf_tag, sd_map[frag_idx],
21338a04b53dSKonstantin Belousov cl, fl->ifl_buf_size, _rxq_refill_cb, &cb_arg,
21348a04b53dSKonstantin Belousov BUS_DMA_NOWAIT);
2135a363e1d4SMark Johnston if (__predict_false(err != 0 || cb_arg.error)) {
21364c7070dbSScott Long uma_zfree(fl->ifl_zone, cl);
2137fbec776dSAndrew Gallatin break;
21384c7070dbSScott Long }
21394c7070dbSScott Long
2140fbec776dSAndrew Gallatin sd_ba[frag_idx] = bus_addr = cb_arg.seg.ds_addr;
214187890dbaSSean Bruno sd_cl[frag_idx] = cl;
2142fbec776dSAndrew Gallatin #if MEMORY_LOGGING
2143fbec776dSAndrew Gallatin fl->ifl_cl_enqueued++;
2144fbec776dSAndrew Gallatin #endif
2145fbec776dSAndrew Gallatin } else {
2146fbec776dSAndrew Gallatin bus_addr = sd_ba[frag_idx];
2147fbec776dSAndrew Gallatin }
214895dcf343SMarius Strobl bus_dmamap_sync(fl->ifl_buf_tag, sd_map[frag_idx],
214995dcf343SMarius Strobl BUS_DMASYNC_PREREAD);
2150fbec776dSAndrew Gallatin
21516d49b41eSAndrew Gallatin if (sd_m[frag_idx] == NULL) {
2152a5688853SMateusz Guzik m = m_gethdr_raw(M_NOWAIT, 0);
2153a363e1d4SMark Johnston if (__predict_false(m == NULL))
2154fbec776dSAndrew Gallatin break;
215587890dbaSSean Bruno sd_m[frag_idx] = m;
21566d49b41eSAndrew Gallatin }
21573db348b5SMarius Strobl bit_set(fl->ifl_rx_bitmap, frag_idx);
2158fbec776dSAndrew Gallatin #if MEMORY_LOGGING
2159fbec776dSAndrew Gallatin fl->ifl_m_enqueued++;
2160fbec776dSAndrew Gallatin #endif
2161fbec776dSAndrew Gallatin
2162fbec776dSAndrew Gallatin DBG_COUNTER_INC(rx_allocs);
216387890dbaSSean Bruno fl->ifl_rxd_idxs[i] = frag_idx;
21644c7070dbSScott Long fl->ifl_bus_addrs[i] = bus_addr;
2165a1b799caSStephen Hurd credits++;
21664c7070dbSScott Long i++;
2167a1b799caSStephen Hurd MPASS(credits <= fl->ifl_size);
2168e035717eSSean Bruno if (++idx == fl->ifl_size) {
2169b256d25cSMark Johnston #ifdef INVARIANTS
21704c7070dbSScott Long fl->ifl_gen = 1;
2171b256d25cSMark Johnston #endif
2172e035717eSSean Bruno idx = 0;
21734c7070dbSScott Long }
21744c7070dbSScott Long if (n == 0 || i == IFLIB_MAX_RX_REFRESH) {
217595246abbSSean Bruno iru.iru_pidx = pidx;
217695246abbSSean Bruno iru.iru_count = i;
217795246abbSSean Bruno ctx->isc_rxd_refill(ctx->ifc_softc, &iru);
2178fa5416a8SSean Bruno fl->ifl_pidx = idx;
2179a1b799caSStephen Hurd fl->ifl_credits = credits;
2180b256d25cSMark Johnston pidx = idx;
2181b256d25cSMark Johnston i = 0;
218287890dbaSSean Bruno }
21834c7070dbSScott Long }
2184fbec776dSAndrew Gallatin
2185a363e1d4SMark Johnston if (n < count - 1) {
2186a363e1d4SMark Johnston if (i != 0) {
2187a1b799caSStephen Hurd iru.iru_pidx = pidx;
2188a1b799caSStephen Hurd iru.iru_count = i;
2189a1b799caSStephen Hurd ctx->isc_rxd_refill(ctx->ifc_softc, &iru);
2190a1b799caSStephen Hurd fl->ifl_pidx = idx;
2191a1b799caSStephen Hurd fl->ifl_credits = credits;
2192a1b799caSStephen Hurd }
21934c7070dbSScott Long DBG_COUNTER_INC(rxd_flush);
219495246abbSSean Bruno bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
219595246abbSSean Bruno BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2196a363e1d4SMark Johnston ctx->isc_rxd_flush(ctx->ifc_softc, fl->ifl_rxq->ifr_id,
219735d8a463SVincenzo Maffione fl->ifl_id, fl->ifl_pidx);
2198a363e1d4SMark Johnston if (__predict_true(bit_test(fl->ifl_rx_bitmap, frag_idx))) {
21999e9b738aSPatrick Kelsey fl->ifl_fragidx = frag_idx + 1;
22009e9b738aSPatrick Kelsey if (fl->ifl_fragidx == fl->ifl_size)
22019e9b738aSPatrick Kelsey fl->ifl_fragidx = 0;
2202a363e1d4SMark Johnston } else {
2203a363e1d4SMark Johnston fl->ifl_fragidx = frag_idx;
2204a363e1d4SMark Johnston }
2205a363e1d4SMark Johnston }
2206fb1a29b4SHans Petter Selasky
2207fb1a29b4SHans Petter Selasky return (n == -1 ? 0 : IFLIB_RXEOF_EMPTY);
22084c7070dbSScott Long }
22094c7070dbSScott Long
2210b256d25cSMark Johnston static inline uint8_t
iflib_fl_refill_all(if_ctx_t ctx,iflib_fl_t fl)2211b256d25cSMark Johnston iflib_fl_refill_all(if_ctx_t ctx, iflib_fl_t fl)
22124c7070dbSScott Long {
221335d8a463SVincenzo Maffione /*
221435d8a463SVincenzo Maffione * We leave an unused descriptor to avoid pidx to catch up with cidx.
221535d8a463SVincenzo Maffione * This is important as it confuses most NICs. For instance,
221635d8a463SVincenzo Maffione * Intel NICs have (per receive ring) RDH and RDT registers, where
221735d8a463SVincenzo Maffione * RDH points to the next receive descriptor to be used by the NIC,
221835d8a463SVincenzo Maffione * and RDT for the next receive descriptor to be published by the
221935d8a463SVincenzo Maffione * driver to the NIC (RDT - 1 is thus the last valid one).
222035d8a463SVincenzo Maffione * The condition RDH == RDT means no descriptors are available to
222135d8a463SVincenzo Maffione * the NIC, and thus it would be ambiguous if it also meant that
222235d8a463SVincenzo Maffione * all the descriptors are available to the NIC.
222335d8a463SVincenzo Maffione */
22244c7070dbSScott Long int32_t reclaimable = fl->ifl_size - fl->ifl_credits - 1;
22254c7070dbSScott Long #ifdef INVARIANTS
22264c7070dbSScott Long int32_t delta = fl->ifl_size - get_inuse(fl->ifl_size, fl->ifl_cidx, fl->ifl_pidx, fl->ifl_gen) - 1;
22274c7070dbSScott Long #endif
22284c7070dbSScott Long
22294c7070dbSScott Long MPASS(fl->ifl_credits <= fl->ifl_size);
22304c7070dbSScott Long MPASS(reclaimable == delta);
22314c7070dbSScott Long
22324c7070dbSScott Long if (reclaimable > 0)
2233b256d25cSMark Johnston return (iflib_fl_refill(ctx, fl, reclaimable));
2234fb1a29b4SHans Petter Selasky return (0);
22354c7070dbSScott Long }
22364c7070dbSScott Long
223777c1fcecSEric Joyner uint8_t
iflib_in_detach(if_ctx_t ctx)223877c1fcecSEric Joyner iflib_in_detach(if_ctx_t ctx)
223977c1fcecSEric Joyner {
224077c1fcecSEric Joyner bool in_detach;
22411722eeacSMarius Strobl
224277c1fcecSEric Joyner STATE_LOCK(ctx);
224377c1fcecSEric Joyner in_detach = !!(ctx->ifc_flags & IFC_IN_DETACH);
224477c1fcecSEric Joyner STATE_UNLOCK(ctx);
224577c1fcecSEric Joyner return (in_detach);
224677c1fcecSEric Joyner }
224777c1fcecSEric Joyner
22484c7070dbSScott Long static void
iflib_fl_bufs_free(iflib_fl_t fl)22494c7070dbSScott Long iflib_fl_bufs_free(iflib_fl_t fl)
22504c7070dbSScott Long {
22514c7070dbSScott Long iflib_dma_info_t idi = fl->ifl_ifdi;
22528a04b53dSKonstantin Belousov bus_dmamap_t sd_map;
22534c7070dbSScott Long uint32_t i;
22544c7070dbSScott Long
22554c7070dbSScott Long for (i = 0; i < fl->ifl_size; i++) {
2256e035717eSSean Bruno struct mbuf **sd_m = &fl->ifl_sds.ifsd_m[i];
2257e035717eSSean Bruno caddr_t *sd_cl = &fl->ifl_sds.ifsd_cl[i];
22584c7070dbSScott Long
2259fbec776dSAndrew Gallatin if (*sd_cl != NULL) {
22608a04b53dSKonstantin Belousov sd_map = fl->ifl_sds.ifsd_map[i];
2261bfce461eSMarius Strobl bus_dmamap_sync(fl->ifl_buf_tag, sd_map,
22628a04b53dSKonstantin Belousov BUS_DMASYNC_POSTREAD);
2263bfce461eSMarius Strobl bus_dmamap_unload(fl->ifl_buf_tag, sd_map);
2264fbec776dSAndrew Gallatin uma_zfree(fl->ifl_zone, *sd_cl);
2265b256d25cSMark Johnston *sd_cl = NULL;
2266e035717eSSean Bruno if (*sd_m != NULL) {
2267e035717eSSean Bruno m_init(*sd_m, M_NOWAIT, MT_DATA, 0);
2268bad5f0b6SMateusz Guzik m_free_raw(*sd_m);
2269b256d25cSMark Johnston *sd_m = NULL;
2270e035717eSSean Bruno }
22714c7070dbSScott Long } else {
2272e035717eSSean Bruno MPASS(*sd_m == NULL);
22734c7070dbSScott Long }
22744c7070dbSScott Long #if MEMORY_LOGGING
22754c7070dbSScott Long fl->ifl_m_dequeued++;
22764c7070dbSScott Long fl->ifl_cl_dequeued++;
22774c7070dbSScott Long #endif
22784c7070dbSScott Long }
227995246abbSSean Bruno #ifdef INVARIANTS
228095246abbSSean Bruno for (i = 0; i < fl->ifl_size; i++) {
228195246abbSSean Bruno MPASS(fl->ifl_sds.ifsd_cl[i] == NULL);
228295246abbSSean Bruno MPASS(fl->ifl_sds.ifsd_m[i] == NULL);
228395246abbSSean Bruno }
228495246abbSSean Bruno #endif
22854c7070dbSScott Long /*
22864c7070dbSScott Long * Reset free list values
22874c7070dbSScott Long */
228887890dbaSSean Bruno fl->ifl_credits = fl->ifl_cidx = fl->ifl_pidx = fl->ifl_gen = fl->ifl_fragidx = 0;
22894c7070dbSScott Long bzero(idi->idi_vaddr, idi->idi_size);
22904c7070dbSScott Long }
22914c7070dbSScott Long
22924c7070dbSScott Long /*********************************************************************
22934c7070dbSScott Long *
22941722eeacSMarius Strobl * Initialize a free list and its buffers.
22954c7070dbSScott Long *
22964c7070dbSScott Long **********************************************************************/
22974c7070dbSScott Long static int
iflib_fl_setup(iflib_fl_t fl)22984c7070dbSScott Long iflib_fl_setup(iflib_fl_t fl)
22994c7070dbSScott Long {
23004c7070dbSScott Long iflib_rxq_t rxq = fl->ifl_rxq;
23014c7070dbSScott Long if_ctx_t ctx = rxq->ifr_ctx;
2302b3813609SPatrick Kelsey if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
2303b3813609SPatrick Kelsey int qidx;
23044c7070dbSScott Long
23057274b2f6SStephen Hurd bit_nclear(fl->ifl_rx_bitmap, 0, fl->ifl_size - 1);
23064c7070dbSScott Long /*
2307fa7045f9SZhenlei Huang * Free current RX buffer structs and their mbufs
23084c7070dbSScott Long */
23094c7070dbSScott Long iflib_fl_bufs_free(fl);
23104c7070dbSScott Long /* Now replenish the mbufs */
23114c7070dbSScott Long MPASS(fl->ifl_credits == 0);
2312b3813609SPatrick Kelsey qidx = rxq->ifr_fl_offset + fl->ifl_id;
2313b3813609SPatrick Kelsey if (scctx->isc_rxd_buf_size[qidx] != 0)
2314b3813609SPatrick Kelsey fl->ifl_buf_size = scctx->isc_rxd_buf_size[qidx];
2315b3813609SPatrick Kelsey else
23161b9d9394SEric Joyner fl->ifl_buf_size = ctx->ifc_rx_mbuf_sz;
2317b3813609SPatrick Kelsey /*
2318b3813609SPatrick Kelsey * ifl_buf_size may be a driver-supplied value, so pull it up
2319b3813609SPatrick Kelsey * to the selected mbuf size.
2320b3813609SPatrick Kelsey */
2321b3813609SPatrick Kelsey fl->ifl_buf_size = iflib_get_mbuf_size_for(fl->ifl_buf_size);
23224c7070dbSScott Long if (fl->ifl_buf_size > ctx->ifc_max_fl_buf_size)
23234c7070dbSScott Long ctx->ifc_max_fl_buf_size = fl->ifl_buf_size;
23244c7070dbSScott Long fl->ifl_cltype = m_gettype(fl->ifl_buf_size);
23254c7070dbSScott Long fl->ifl_zone = m_getzone(fl->ifl_buf_size);
23264c7070dbSScott Long
232735d8a463SVincenzo Maffione /*
232835d8a463SVincenzo Maffione * Avoid pre-allocating zillions of clusters to an idle card
232935d8a463SVincenzo Maffione * potentially speeding up attach. In any case make sure
233035d8a463SVincenzo Maffione * to leave a descriptor unavailable. See the comment in
233135d8a463SVincenzo Maffione * iflib_fl_refill_all().
23324c7070dbSScott Long */
233335d8a463SVincenzo Maffione MPASS(fl->ifl_size > 0);
233435d8a463SVincenzo Maffione (void)iflib_fl_refill(ctx, fl, min(128, fl->ifl_size - 1));
233535d8a463SVincenzo Maffione if (min(128, fl->ifl_size - 1) != fl->ifl_credits)
23364c7070dbSScott Long return (ENOBUFS);
23374c7070dbSScott Long /*
23384c7070dbSScott Long * handle failure
23394c7070dbSScott Long */
23404c7070dbSScott Long MPASS(rxq != NULL);
23414c7070dbSScott Long MPASS(fl->ifl_ifdi != NULL);
23424c7070dbSScott Long bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
23434c7070dbSScott Long BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
23444c7070dbSScott Long return (0);
23454c7070dbSScott Long }
23464c7070dbSScott Long
23474c7070dbSScott Long /*********************************************************************
23484c7070dbSScott Long *
23494c7070dbSScott Long * Free receive ring data structures
23504c7070dbSScott Long *
23514c7070dbSScott Long **********************************************************************/
23524c7070dbSScott Long static void
iflib_rx_sds_free(iflib_rxq_t rxq)23534c7070dbSScott Long iflib_rx_sds_free(iflib_rxq_t rxq)
23544c7070dbSScott Long {
23554c7070dbSScott Long iflib_fl_t fl;
23568a04b53dSKonstantin Belousov int i, j;
23574c7070dbSScott Long
23584c7070dbSScott Long if (rxq->ifr_fl != NULL) {
23594c7070dbSScott Long for (i = 0; i < rxq->ifr_nfl; i++) {
23604c7070dbSScott Long fl = &rxq->ifr_fl[i];
2361bfce461eSMarius Strobl if (fl->ifl_buf_tag != NULL) {
23628a04b53dSKonstantin Belousov if (fl->ifl_sds.ifsd_map != NULL) {
236377102fd6SAndrew Gallatin for (j = 0; j < fl->ifl_size; j++) {
23648a04b53dSKonstantin Belousov bus_dmamap_sync(
2365bfce461eSMarius Strobl fl->ifl_buf_tag,
236677102fd6SAndrew Gallatin fl->ifl_sds.ifsd_map[j],
23678a04b53dSKonstantin Belousov BUS_DMASYNC_POSTREAD);
23688a04b53dSKonstantin Belousov bus_dmamap_unload(
2369bfce461eSMarius Strobl fl->ifl_buf_tag,
237077102fd6SAndrew Gallatin fl->ifl_sds.ifsd_map[j]);
2371db8e8f1eSEric Joyner bus_dmamap_destroy(
2372db8e8f1eSEric Joyner fl->ifl_buf_tag,
2373db8e8f1eSEric Joyner fl->ifl_sds.ifsd_map[j]);
23748a04b53dSKonstantin Belousov }
23758a04b53dSKonstantin Belousov }
2376bfce461eSMarius Strobl bus_dma_tag_destroy(fl->ifl_buf_tag);
2377bfce461eSMarius Strobl fl->ifl_buf_tag = NULL;
23784c7070dbSScott Long }
2379e035717eSSean Bruno free(fl->ifl_sds.ifsd_m, M_IFLIB);
2380e035717eSSean Bruno free(fl->ifl_sds.ifsd_cl, M_IFLIB);
2381fbec776dSAndrew Gallatin free(fl->ifl_sds.ifsd_ba, M_IFLIB);
2382e035717eSSean Bruno free(fl->ifl_sds.ifsd_map, M_IFLIB);
2383c065d4e5SMark Johnston free(fl->ifl_rx_bitmap, M_IFLIB);
2384e035717eSSean Bruno fl->ifl_sds.ifsd_m = NULL;
2385e035717eSSean Bruno fl->ifl_sds.ifsd_cl = NULL;
2386fbec776dSAndrew Gallatin fl->ifl_sds.ifsd_ba = NULL;
2387e035717eSSean Bruno fl->ifl_sds.ifsd_map = NULL;
2388c065d4e5SMark Johnston fl->ifl_rx_bitmap = NULL;
23894c7070dbSScott Long }
23904c7070dbSScott Long free(rxq->ifr_fl, M_IFLIB);
23914c7070dbSScott Long rxq->ifr_fl = NULL;
2392244e7cffSEric Joyner free(rxq->ifr_ifdi, M_IFLIB);
2393244e7cffSEric Joyner rxq->ifr_ifdi = NULL;
23941722eeacSMarius Strobl rxq->ifr_cq_cidx = 0;
23954c7070dbSScott Long }
23964c7070dbSScott Long }
23974c7070dbSScott Long
23984c7070dbSScott Long /*
23991722eeacSMarius Strobl * Timer routine
24004c7070dbSScott Long */
24014c7070dbSScott Long static void
iflib_timer(void * arg)24024c7070dbSScott Long iflib_timer(void *arg)
24034c7070dbSScott Long {
2404ab2e3f79SStephen Hurd iflib_txq_t txq = arg;
24054c7070dbSScott Long if_ctx_t ctx = txq->ift_ctx;
2406ab2e3f79SStephen Hurd if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
2407618d49f5SAlexander Motin uint64_t this_tick = ticks;
24084c7070dbSScott Long
24094c7070dbSScott Long if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))
24104c7070dbSScott Long return;
24111722eeacSMarius Strobl
24124c7070dbSScott Long /*
24134c7070dbSScott Long ** Check on the state of the TX queue(s), this
24144c7070dbSScott Long ** can be done without the lock because its RO
24154c7070dbSScott Long ** and the HUNG state will be static if set.
24164c7070dbSScott Long */
2417618d49f5SAlexander Motin if (this_tick - txq->ift_last_timer_tick >= iflib_timer_default) {
2418618d49f5SAlexander Motin txq->ift_last_timer_tick = this_tick;
2419ab2e3f79SStephen Hurd IFDI_TIMER(ctx, txq->ift_id);
2420ab2e3f79SStephen Hurd if ((txq->ift_qstatus == IFLIB_QUEUE_HUNG) &&
2421ab2e3f79SStephen Hurd ((txq->ift_cleaned_prev == txq->ift_cleaned) ||
2422ab2e3f79SStephen Hurd (sctx->isc_pause_frames == 0)))
2423ab2e3f79SStephen Hurd goto hung;
2424618d49f5SAlexander Motin
2425f6afed72SEric Joyner if (txq->ift_qstatus != IFLIB_QUEUE_IDLE &&
2426f6afed72SEric Joyner ifmp_ring_is_stalled(txq->ift_br)) {
242781be6552SMatt Macy KASSERT(ctx->ifc_link_state == LINK_STATE_UP,
242881be6552SMatt Macy ("queue can't be marked as hung if interface is down"));
2429ab2e3f79SStephen Hurd txq->ift_qstatus = IFLIB_QUEUE_HUNG;
2430f6afed72SEric Joyner }
2431ab2e3f79SStephen Hurd txq->ift_cleaned_prev = txq->ift_cleaned;
2432618d49f5SAlexander Motin }
2433ab2e3f79SStephen Hurd /* handle any laggards */
2434ab2e3f79SStephen Hurd if (txq->ift_db_pending)
2435ab2e3f79SStephen Hurd GROUPTASK_ENQUEUE(&txq->ift_task);
2436a9693502SSean Bruno
2437ab2e3f79SStephen Hurd sctx->isc_pause_frames = 0;
2438d300df01SStephen Hurd if (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)
2439618d49f5SAlexander Motin callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer,
2440618d49f5SAlexander Motin txq, txq->ift_timer.c_cpu);
2441ab2e3f79SStephen Hurd return;
24421722eeacSMarius Strobl
2443ab2e3f79SStephen Hurd hung:
24441722eeacSMarius Strobl device_printf(ctx->ifc_dev,
24451722eeacSMarius Strobl "Watchdog timeout (TX: %d desc avail: %d pidx: %d) -- resetting\n",
2446ab2e3f79SStephen Hurd txq->ift_id, TXQ_AVAIL(txq), txq->ift_pidx);
24477b610b60SSean Bruno STATE_LOCK(ctx);
24487b610b60SSean Bruno if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
24497b610b60SSean Bruno ctx->ifc_flags |= (IFC_DO_WATCHDOG | IFC_DO_RESET);
2450940f62d6SEric Joyner iflib_admin_intr_deferred(ctx);
245146fa0c25SEric Joyner STATE_UNLOCK(ctx);
24524c7070dbSScott Long }
24534c7070dbSScott Long
2454b3813609SPatrick Kelsey static uint16_t
iflib_get_mbuf_size_for(unsigned int size)2455b3813609SPatrick Kelsey iflib_get_mbuf_size_for(unsigned int size)
2456b3813609SPatrick Kelsey {
2457b3813609SPatrick Kelsey
2458b3813609SPatrick Kelsey if (size <= MCLBYTES)
2459b3813609SPatrick Kelsey return (MCLBYTES);
2460b3813609SPatrick Kelsey else
2461b3813609SPatrick Kelsey return (MJUMPAGESIZE);
2462b3813609SPatrick Kelsey }
2463b3813609SPatrick Kelsey
24644c7070dbSScott Long static void
iflib_calc_rx_mbuf_sz(if_ctx_t ctx)24651b9d9394SEric Joyner iflib_calc_rx_mbuf_sz(if_ctx_t ctx)
24661b9d9394SEric Joyner {
24671b9d9394SEric Joyner if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
24681b9d9394SEric Joyner
24691b9d9394SEric Joyner /*
24701b9d9394SEric Joyner * XXX don't set the max_frame_size to larger
24711b9d9394SEric Joyner * than the hardware can handle
24721b9d9394SEric Joyner */
2473b3813609SPatrick Kelsey ctx->ifc_rx_mbuf_sz =
2474b3813609SPatrick Kelsey iflib_get_mbuf_size_for(sctx->isc_max_frame_size);
24751b9d9394SEric Joyner }
24761b9d9394SEric Joyner
24771b9d9394SEric Joyner uint32_t
iflib_get_rx_mbuf_sz(if_ctx_t ctx)24781b9d9394SEric Joyner iflib_get_rx_mbuf_sz(if_ctx_t ctx)
24791b9d9394SEric Joyner {
24801722eeacSMarius Strobl
24811b9d9394SEric Joyner return (ctx->ifc_rx_mbuf_sz);
24821b9d9394SEric Joyner }
24831b9d9394SEric Joyner
24841b9d9394SEric Joyner static void
iflib_init_locked(if_ctx_t ctx)24854c7070dbSScott Long iflib_init_locked(if_ctx_t ctx)
24864c7070dbSScott Long {
24871248952aSSean Bruno if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
24884c7070dbSScott Long if_t ifp = ctx->ifc_ifp;
24894c7070dbSScott Long iflib_fl_t fl;
24904c7070dbSScott Long iflib_txq_t txq;
24914c7070dbSScott Long iflib_rxq_t rxq;
2492ab2e3f79SStephen Hurd int i, j, tx_ip_csum_flags, tx_ip6_csum_flags;
24934c7070dbSScott Long
24944c7070dbSScott Long if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
24954c7070dbSScott Long IFDI_INTR_DISABLE(ctx);
24964c7070dbSScott Long
24973d65fd97SVincenzo Maffione /*
24983d65fd97SVincenzo Maffione * See iflib_stop(). Useful in case iflib_init_locked() is
24993d65fd97SVincenzo Maffione * called without first calling iflib_stop().
25003d65fd97SVincenzo Maffione */
25013d65fd97SVincenzo Maffione netmap_disable_all_rings(ifp);
25023d65fd97SVincenzo Maffione
25031248952aSSean Bruno tx_ip_csum_flags = scctx->isc_tx_csum_flags & (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP);
25041248952aSSean Bruno tx_ip6_csum_flags = scctx->isc_tx_csum_flags & (CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_IP6_SCTP);
25054c7070dbSScott Long /* Set hardware offload abilities */
25064c7070dbSScott Long if_clearhwassist(ifp);
25074c7070dbSScott Long if (if_getcapenable(ifp) & IFCAP_TXCSUM)
25081248952aSSean Bruno if_sethwassistbits(ifp, tx_ip_csum_flags, 0);
25094c7070dbSScott Long if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6)
25101248952aSSean Bruno if_sethwassistbits(ifp, tx_ip6_csum_flags, 0);
25114c7070dbSScott Long if (if_getcapenable(ifp) & IFCAP_TSO4)
25124c7070dbSScott Long if_sethwassistbits(ifp, CSUM_IP_TSO, 0);
25134c7070dbSScott Long if (if_getcapenable(ifp) & IFCAP_TSO6)
25144c7070dbSScott Long if_sethwassistbits(ifp, CSUM_IP6_TSO, 0);
25154c7070dbSScott Long
2516d2dd3d5aSEric Joyner for (i = 0, txq = ctx->ifc_txqs; i < scctx->isc_ntxqsets; i++, txq++) {
25174c7070dbSScott Long CALLOUT_LOCK(txq);
25184c7070dbSScott Long callout_stop(&txq->ift_timer);
251917cec474SVincenzo Maffione #ifdef DEV_NETMAP
252017cec474SVincenzo Maffione callout_stop(&txq->ift_netmap_timer);
252117cec474SVincenzo Maffione #endif /* DEV_NETMAP */
25224c7070dbSScott Long CALLOUT_UNLOCK(txq);
25232ccf971aSJohn Baldwin (void)iflib_netmap_txq_init(ctx, txq);
25244c7070dbSScott Long }
25251b9d9394SEric Joyner
25261b9d9394SEric Joyner /*
25271b9d9394SEric Joyner * Calculate a suitable Rx mbuf size prior to calling IFDI_INIT, so
25281b9d9394SEric Joyner * that drivers can use the value when setting up the hardware receive
25291b9d9394SEric Joyner * buffers.
25301b9d9394SEric Joyner */
25311b9d9394SEric Joyner iflib_calc_rx_mbuf_sz(ctx);
25321b9d9394SEric Joyner
253323ac9029SStephen Hurd #ifdef INVARIANTS
253423ac9029SStephen Hurd i = if_getdrvflags(ifp);
253523ac9029SStephen Hurd #endif
25364c7070dbSScott Long IFDI_INIT(ctx);
253723ac9029SStephen Hurd MPASS(if_getdrvflags(ifp) == i);
2538d2dd3d5aSEric Joyner for (i = 0, rxq = ctx->ifc_rxqs; i < scctx->isc_nrxqsets; i++, rxq++) {
2539d8b2d26bSVincenzo Maffione if (iflib_netmap_rxq_init(ctx, rxq) > 0) {
2540d8b2d26bSVincenzo Maffione /* This rxq is in netmap mode. Skip normal init. */
254195246abbSSean Bruno continue;
2542d0d0ad0aSStephen Hurd }
25434c7070dbSScott Long for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) {
25444c7070dbSScott Long if (iflib_fl_setup(fl)) {
25453d10e9edSMarius Strobl device_printf(ctx->ifc_dev,
25463d10e9edSMarius Strobl "setting up free list %d failed - "
25473d10e9edSMarius Strobl "check cluster settings\n", j);
25484c7070dbSScott Long goto done;
25494c7070dbSScott Long }
25504c7070dbSScott Long }
25514c7070dbSScott Long }
25524c7070dbSScott Long done:
25534c7070dbSScott Long if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
25544c7070dbSScott Long IFDI_INTR_ENABLE(ctx);
25554c7070dbSScott Long txq = ctx->ifc_txqs;
2556d2dd3d5aSEric Joyner for (i = 0; i < scctx->isc_ntxqsets; i++, txq++)
2557618d49f5SAlexander Motin callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer, txq,
2558618d49f5SAlexander Motin txq->ift_timer.c_cpu);
25593d65fd97SVincenzo Maffione
25603d65fd97SVincenzo Maffione /* Re-enable txsync/rxsync. */
25613d65fd97SVincenzo Maffione netmap_enable_all_rings(ifp);
25624c7070dbSScott Long }
25634c7070dbSScott Long
25644c7070dbSScott Long static int
iflib_media_change(if_t ifp)25654c7070dbSScott Long iflib_media_change(if_t ifp)
25664c7070dbSScott Long {
25674c7070dbSScott Long if_ctx_t ctx = if_getsoftc(ifp);
25684c7070dbSScott Long int err;
25694c7070dbSScott Long
25704c7070dbSScott Long CTX_LOCK(ctx);
25714c7070dbSScott Long if ((err = IFDI_MEDIA_CHANGE(ctx)) == 0)
2572922cf8acSAllan Jude iflib_if_init_locked(ctx);
25734c7070dbSScott Long CTX_UNLOCK(ctx);
25744c7070dbSScott Long return (err);
25754c7070dbSScott Long }
25764c7070dbSScott Long
25774c7070dbSScott Long static void
iflib_media_status(if_t ifp,struct ifmediareq * ifmr)25784c7070dbSScott Long iflib_media_status(if_t ifp, struct ifmediareq *ifmr)
25794c7070dbSScott Long {
25804c7070dbSScott Long if_ctx_t ctx = if_getsoftc(ifp);
25814c7070dbSScott Long
25824c7070dbSScott Long CTX_LOCK(ctx);
2583ab2e3f79SStephen Hurd IFDI_UPDATE_ADMIN_STATUS(ctx);
25844c7070dbSScott Long IFDI_MEDIA_STATUS(ctx, ifmr);
25854c7070dbSScott Long CTX_UNLOCK(ctx);
25864c7070dbSScott Long }
25874c7070dbSScott Long
2588*81610008SZhenlei Huang static void
iflib_stop(if_ctx_t ctx)25894c7070dbSScott Long iflib_stop(if_ctx_t ctx)
25904c7070dbSScott Long {
25914c7070dbSScott Long iflib_txq_t txq = ctx->ifc_txqs;
25924c7070dbSScott Long iflib_rxq_t rxq = ctx->ifc_rxqs;
25934c7070dbSScott Long if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
25944d261ce2SStephen Hurd if_shared_ctx_t sctx = ctx->ifc_sctx;
25954c7070dbSScott Long iflib_dma_info_t di;
25964c7070dbSScott Long iflib_fl_t fl;
25974c7070dbSScott Long int i, j;
25984c7070dbSScott Long
25994c7070dbSScott Long /* Tell the stack that the interface is no longer active */
26004c7070dbSScott Long if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
26014c7070dbSScott Long
26024c7070dbSScott Long IFDI_INTR_DISABLE(ctx);
2603ab2e3f79SStephen Hurd DELAY(1000);
2604da69b8f9SSean Bruno IFDI_STOP(ctx);
2605ab2e3f79SStephen Hurd DELAY(1000);
26064c7070dbSScott Long
26073d65fd97SVincenzo Maffione /*
26083d65fd97SVincenzo Maffione * Stop any pending txsync/rxsync and prevent new ones
26093d65fd97SVincenzo Maffione * form starting. Processes blocked in poll() will get
26103d65fd97SVincenzo Maffione * POLLERR.
26113d65fd97SVincenzo Maffione */
26123d65fd97SVincenzo Maffione netmap_disable_all_rings(ctx->ifc_ifp);
26133d65fd97SVincenzo Maffione
2614da69b8f9SSean Bruno iflib_debug_reset();
26154c7070dbSScott Long /* Wait for current tx queue users to exit to disarm watchdog timer. */
26164c7070dbSScott Long for (i = 0; i < scctx->isc_ntxqsets; i++, txq++) {
26174c7070dbSScott Long /* make sure all transmitters have completed before proceeding XXX */
26184c7070dbSScott Long
2619226fb85dSStephen Hurd CALLOUT_LOCK(txq);
2620226fb85dSStephen Hurd callout_stop(&txq->ift_timer);
262117cec474SVincenzo Maffione #ifdef DEV_NETMAP
262217cec474SVincenzo Maffione callout_stop(&txq->ift_netmap_timer);
262317cec474SVincenzo Maffione #endif /* DEV_NETMAP */
2624226fb85dSStephen Hurd CALLOUT_UNLOCK(txq);
2625226fb85dSStephen Hurd
26264c7070dbSScott Long /* clean any enqueued buffers */
2627da69b8f9SSean Bruno iflib_ifmp_purge(txq);
26284c7070dbSScott Long /* Free any existing tx buffers. */
262923ac9029SStephen Hurd for (j = 0; j < txq->ift_size; j++) {
26304c7070dbSScott Long iflib_txsd_free(ctx, txq, j);
26314c7070dbSScott Long }
2632ab2e3f79SStephen Hurd txq->ift_processed = txq->ift_cleaned = txq->ift_cidx_processed = 0;
263358632fa7SMarcin Wojtas txq->ift_in_use = txq->ift_gen = txq->ift_no_desc_avail = 0;
263458632fa7SMarcin Wojtas if (sctx->isc_flags & IFLIB_PRESERVE_TX_INDICES)
263558632fa7SMarcin Wojtas txq->ift_cidx = txq->ift_pidx;
263658632fa7SMarcin Wojtas else
263758632fa7SMarcin Wojtas txq->ift_cidx = txq->ift_pidx = 0;
263858632fa7SMarcin Wojtas
26394c7070dbSScott Long txq->ift_closed = txq->ift_mbuf_defrag = txq->ift_mbuf_defrag_failed = 0;
26404c7070dbSScott Long txq->ift_no_tx_dma_setup = txq->ift_txd_encap_efbig = txq->ift_map_failed = 0;
2641ab2e3f79SStephen Hurd txq->ift_pullups = 0;
264295246abbSSean Bruno ifmp_ring_reset_stats(txq->ift_br);
26434d261ce2SStephen Hurd for (j = 0, di = txq->ift_ifdi; j < sctx->isc_ntxqs; j++, di++)
26444c7070dbSScott Long bzero((void *)di->idi_vaddr, di->idi_size);
26454c7070dbSScott Long }
26464c7070dbSScott Long for (i = 0; i < scctx->isc_nrxqsets; i++, rxq++) {
26479147969bSPrzemyslaw Lewandowski if (rxq->ifr_task.gt_taskqueue != NULL)
26481bfdb812SAndriy Gapon gtaskqueue_drain(rxq->ifr_task.gt_taskqueue,
26491bfdb812SAndriy Gapon &rxq->ifr_task.gt_task);
26504c7070dbSScott Long
26511722eeacSMarius Strobl rxq->ifr_cq_cidx = 0;
26524d261ce2SStephen Hurd for (j = 0, di = rxq->ifr_ifdi; j < sctx->isc_nrxqs; j++, di++)
26534c7070dbSScott Long bzero((void *)di->idi_vaddr, di->idi_size);
26544c7070dbSScott Long /* also resets the free lists pidx/cidx */
26554c7070dbSScott Long for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++)
26564c7070dbSScott Long iflib_fl_bufs_free(fl);
26574c7070dbSScott Long }
26584c7070dbSScott Long }
26594c7070dbSScott Long
266095246abbSSean Bruno static inline caddr_t
calc_next_rxd(iflib_fl_t fl,int cidx)266195246abbSSean Bruno calc_next_rxd(iflib_fl_t fl, int cidx)
266295246abbSSean Bruno {
266395246abbSSean Bruno qidx_t size;
266495246abbSSean Bruno int nrxd;
266595246abbSSean Bruno caddr_t start, end, cur, next;
266695246abbSSean Bruno
266795246abbSSean Bruno nrxd = fl->ifl_size;
266895246abbSSean Bruno size = fl->ifl_rxd_size;
266995246abbSSean Bruno start = fl->ifl_ifdi->idi_vaddr;
267095246abbSSean Bruno
267195246abbSSean Bruno if (__predict_false(size == 0))
267295246abbSSean Bruno return (start);
267395246abbSSean Bruno cur = start + size * cidx;
267495246abbSSean Bruno end = start + size * nrxd;
267595246abbSSean Bruno next = CACHE_PTR_NEXT(cur);
267695246abbSSean Bruno return (next < end ? next : start);
267795246abbSSean Bruno }
267895246abbSSean Bruno
2679e035717eSSean Bruno static inline void
prefetch_pkts(iflib_fl_t fl,int cidx)2680e035717eSSean Bruno prefetch_pkts(iflib_fl_t fl, int cidx)
2681e035717eSSean Bruno {
2682e035717eSSean Bruno int nextptr;
2683e035717eSSean Bruno int nrxd = fl->ifl_size;
268495246abbSSean Bruno caddr_t next_rxd;
268595246abbSSean Bruno
2686e035717eSSean Bruno nextptr = (cidx + CACHE_PTR_INCREMENT) & (nrxd - 1);
2687e035717eSSean Bruno prefetch(&fl->ifl_sds.ifsd_m[nextptr]);
2688e035717eSSean Bruno prefetch(&fl->ifl_sds.ifsd_cl[nextptr]);
268995246abbSSean Bruno next_rxd = calc_next_rxd(fl, cidx);
269095246abbSSean Bruno prefetch(next_rxd);
2691e035717eSSean Bruno prefetch(fl->ifl_sds.ifsd_m[(cidx + 1) & (nrxd - 1)]);
2692e035717eSSean Bruno prefetch(fl->ifl_sds.ifsd_m[(cidx + 2) & (nrxd - 1)]);
2693e035717eSSean Bruno prefetch(fl->ifl_sds.ifsd_m[(cidx + 3) & (nrxd - 1)]);
2694e035717eSSean Bruno prefetch(fl->ifl_sds.ifsd_m[(cidx + 4) & (nrxd - 1)]);
2695e035717eSSean Bruno prefetch(fl->ifl_sds.ifsd_cl[(cidx + 1) & (nrxd - 1)]);
2696e035717eSSean Bruno prefetch(fl->ifl_sds.ifsd_cl[(cidx + 2) & (nrxd - 1)]);
2697e035717eSSean Bruno prefetch(fl->ifl_sds.ifsd_cl[(cidx + 3) & (nrxd - 1)]);
2698e035717eSSean Bruno prefetch(fl->ifl_sds.ifsd_cl[(cidx + 4) & (nrxd - 1)]);
2699e035717eSSean Bruno }
2700e035717eSSean Bruno
27016d49b41eSAndrew Gallatin static struct mbuf *
rxd_frag_to_sd(iflib_rxq_t rxq,if_rxd_frag_t irf,bool unload,if_rxsd_t sd,int * pf_rv,if_rxd_info_t ri)27026d49b41eSAndrew Gallatin rxd_frag_to_sd(iflib_rxq_t rxq, if_rxd_frag_t irf, bool unload, if_rxsd_t sd,
27036d49b41eSAndrew Gallatin int *pf_rv, if_rxd_info_t ri)
27044c7070dbSScott Long {
2705e035717eSSean Bruno bus_dmamap_t map;
27064c7070dbSScott Long iflib_fl_t fl;
27076d49b41eSAndrew Gallatin caddr_t payload;
27086d49b41eSAndrew Gallatin struct mbuf *m;
27096d49b41eSAndrew Gallatin int flid, cidx, len, next;
27104c7070dbSScott Long
271195246abbSSean Bruno map = NULL;
27124c7070dbSScott Long flid = irf->irf_flid;
27134c7070dbSScott Long cidx = irf->irf_idx;
27144c7070dbSScott Long fl = &rxq->ifr_fl[flid];
271595246abbSSean Bruno sd->ifsd_fl = fl;
271695246abbSSean Bruno sd->ifsd_cl = &fl->ifl_sds.ifsd_cl[cidx];
27174c7070dbSScott Long fl->ifl_credits--;
27184c7070dbSScott Long #if MEMORY_LOGGING
27194c7070dbSScott Long fl->ifl_m_dequeued++;
27204c7070dbSScott Long #endif
272195246abbSSean Bruno if (rxq->ifr_ctx->ifc_flags & IFC_PREFETCH)
2722e035717eSSean Bruno prefetch_pkts(fl, cidx);
2723e035717eSSean Bruno next = (cidx + CACHE_PTR_INCREMENT) & (fl->ifl_size - 1);
2724e035717eSSean Bruno prefetch(&fl->ifl_sds.ifsd_map[next]);
2725e035717eSSean Bruno map = fl->ifl_sds.ifsd_map[cidx];
27264c7070dbSScott Long
2727bfce461eSMarius Strobl bus_dmamap_sync(fl->ifl_buf_tag, map, BUS_DMASYNC_POSTREAD);
27286d49b41eSAndrew Gallatin
27294f2beb72SPatrick Kelsey if (rxq->pfil != NULL && PFIL_HOOKED_IN(rxq->pfil) && pf_rv != NULL &&
27304f2beb72SPatrick Kelsey irf->irf_len != 0) {
27316d49b41eSAndrew Gallatin payload = *sd->ifsd_cl;
27326d49b41eSAndrew Gallatin payload += ri->iri_pad;
27336d49b41eSAndrew Gallatin len = ri->iri_len - ri->iri_pad;
2734caf32b26SGleb Smirnoff *pf_rv = pfil_mem_in(rxq->pfil, payload, len, ri->iri_ifp, &m);
27356d49b41eSAndrew Gallatin switch (*pf_rv) {
27366d49b41eSAndrew Gallatin case PFIL_DROPPED:
27376d49b41eSAndrew Gallatin case PFIL_CONSUMED:
27386d49b41eSAndrew Gallatin /*
27396d49b41eSAndrew Gallatin * The filter ate it. Everything is recycled.
27406d49b41eSAndrew Gallatin */
27416d49b41eSAndrew Gallatin m = NULL;
27426d49b41eSAndrew Gallatin unload = 0;
27436d49b41eSAndrew Gallatin break;
27446d49b41eSAndrew Gallatin case PFIL_REALLOCED:
27456d49b41eSAndrew Gallatin /*
27466d49b41eSAndrew Gallatin * The filter copied it. Everything is recycled.
2747caf32b26SGleb Smirnoff * 'm' points at new mbuf.
27486d49b41eSAndrew Gallatin */
27496d49b41eSAndrew Gallatin unload = 0;
27506d49b41eSAndrew Gallatin break;
27516d49b41eSAndrew Gallatin case PFIL_PASS:
27526d49b41eSAndrew Gallatin /*
27536d49b41eSAndrew Gallatin * Filter said it was OK, so receive like
27546d49b41eSAndrew Gallatin * normal
27556d49b41eSAndrew Gallatin */
27565f7bea29SGleb Smirnoff m = fl->ifl_sds.ifsd_m[cidx];
27576d49b41eSAndrew Gallatin fl->ifl_sds.ifsd_m[cidx] = NULL;
27586d49b41eSAndrew Gallatin break;
27596d49b41eSAndrew Gallatin default:
27606d49b41eSAndrew Gallatin MPASS(0);
27616d49b41eSAndrew Gallatin }
27626d49b41eSAndrew Gallatin } else {
27635f7bea29SGleb Smirnoff m = fl->ifl_sds.ifsd_m[cidx];
27646d49b41eSAndrew Gallatin fl->ifl_sds.ifsd_m[cidx] = NULL;
27650c864213SAndrew Gallatin if (pf_rv != NULL)
27666d49b41eSAndrew Gallatin *pf_rv = PFIL_PASS;
27676d49b41eSAndrew Gallatin }
27686d49b41eSAndrew Gallatin
27694f2beb72SPatrick Kelsey if (unload && irf->irf_len != 0)
2770bfce461eSMarius Strobl bus_dmamap_unload(fl->ifl_buf_tag, map);
277195246abbSSean Bruno fl->ifl_cidx = (fl->ifl_cidx + 1) & (fl->ifl_size - 1);
277295246abbSSean Bruno if (__predict_false(fl->ifl_cidx == 0))
27734c7070dbSScott Long fl->ifl_gen = 0;
277487890dbaSSean Bruno bit_clear(fl->ifl_rx_bitmap, cidx);
27756d49b41eSAndrew Gallatin return (m);
27764c7070dbSScott Long }
27774c7070dbSScott Long
27784c7070dbSScott Long static struct mbuf *
assemble_segments(iflib_rxq_t rxq,if_rxd_info_t ri,if_rxsd_t sd,int * pf_rv)27796d49b41eSAndrew Gallatin assemble_segments(iflib_rxq_t rxq, if_rxd_info_t ri, if_rxsd_t sd, int *pf_rv)
27804c7070dbSScott Long {
278195246abbSSean Bruno struct mbuf *m, *mh, *mt;
278295246abbSSean Bruno caddr_t cl;
27836d49b41eSAndrew Gallatin int *pf_rv_ptr, flags, i, padlen;
27846d49b41eSAndrew Gallatin bool consumed;
27854c7070dbSScott Long
27864c7070dbSScott Long i = 0;
278723ac9029SStephen Hurd mh = NULL;
27886d49b41eSAndrew Gallatin consumed = false;
27896d49b41eSAndrew Gallatin *pf_rv = PFIL_PASS;
27906d49b41eSAndrew Gallatin pf_rv_ptr = pf_rv;
27914c7070dbSScott Long do {
27926d49b41eSAndrew Gallatin m = rxd_frag_to_sd(rxq, &ri->iri_frags[i], !consumed, sd,
27936d49b41eSAndrew Gallatin pf_rv_ptr, ri);
27944c7070dbSScott Long
279595246abbSSean Bruno MPASS(*sd->ifsd_cl != NULL);
279623ac9029SStephen Hurd
27976d49b41eSAndrew Gallatin /*
27986d49b41eSAndrew Gallatin * Exclude zero-length frags & frags from
27996d49b41eSAndrew Gallatin * packets the filter has consumed or dropped
28006d49b41eSAndrew Gallatin */
28016d49b41eSAndrew Gallatin if (ri->iri_frags[i].irf_len == 0 || consumed ||
28026d49b41eSAndrew Gallatin *pf_rv == PFIL_CONSUMED || *pf_rv == PFIL_DROPPED) {
28036d49b41eSAndrew Gallatin if (mh == NULL) {
28046d49b41eSAndrew Gallatin /* everything saved here */
28056d49b41eSAndrew Gallatin consumed = true;
28066d49b41eSAndrew Gallatin pf_rv_ptr = NULL;
280723ac9029SStephen Hurd continue;
280823ac9029SStephen Hurd }
28096d49b41eSAndrew Gallatin /* XXX we can save the cluster here, but not the mbuf */
28106d49b41eSAndrew Gallatin m_init(m, M_NOWAIT, MT_DATA, 0);
28116d49b41eSAndrew Gallatin m_free(m);
28126d49b41eSAndrew Gallatin continue;
28136d49b41eSAndrew Gallatin }
281423ac9029SStephen Hurd if (mh == NULL) {
28154c7070dbSScott Long flags = M_PKTHDR | M_EXT;
28164c7070dbSScott Long mh = mt = m;
28174c7070dbSScott Long padlen = ri->iri_pad;
28184c7070dbSScott Long } else {
28194c7070dbSScott Long flags = M_EXT;
28204c7070dbSScott Long mt->m_next = m;
28214c7070dbSScott Long mt = m;
28224c7070dbSScott Long /* assuming padding is only on the first fragment */
28234c7070dbSScott Long padlen = 0;
28244c7070dbSScott Long }
282595246abbSSean Bruno cl = *sd->ifsd_cl;
282695246abbSSean Bruno *sd->ifsd_cl = NULL;
28274c7070dbSScott Long
28284c7070dbSScott Long /* Can these two be made one ? */
28294c7070dbSScott Long m_init(m, M_NOWAIT, MT_DATA, flags);
283095246abbSSean Bruno m_cljset(m, cl, sd->ifsd_fl->ifl_cltype);
28314c7070dbSScott Long /*
28324c7070dbSScott Long * These must follow m_init and m_cljset
28334c7070dbSScott Long */
28344c7070dbSScott Long m->m_data += padlen;
28354c7070dbSScott Long ri->iri_len -= padlen;
283623ac9029SStephen Hurd m->m_len = ri->iri_frags[i].irf_len;
28374c7070dbSScott Long } while (++i < ri->iri_nfrags);
28384c7070dbSScott Long
28394c7070dbSScott Long return (mh);
28404c7070dbSScott Long }
28414c7070dbSScott Long
28424c7070dbSScott Long /*
28434c7070dbSScott Long * Process one software descriptor
28444c7070dbSScott Long */
28454c7070dbSScott Long static struct mbuf *
iflib_rxd_pkt_get(iflib_rxq_t rxq,if_rxd_info_t ri)28464c7070dbSScott Long iflib_rxd_pkt_get(iflib_rxq_t rxq, if_rxd_info_t ri)
28474c7070dbSScott Long {
284895246abbSSean Bruno struct if_rxsd sd;
28494c7070dbSScott Long struct mbuf *m;
28506d49b41eSAndrew Gallatin int pf_rv;
28514c7070dbSScott Long
28524c7070dbSScott Long /* should I merge this back in now that the two paths are basically duplicated? */
285323ac9029SStephen Hurd if (ri->iri_nfrags == 1 &&
28544f2beb72SPatrick Kelsey ri->iri_frags[0].irf_len != 0 &&
285518628b74SMark Johnston ri->iri_frags[0].irf_len <= MIN(IFLIB_RX_COPY_THRESH, MHLEN)) {
28566d49b41eSAndrew Gallatin m = rxd_frag_to_sd(rxq, &ri->iri_frags[0], false, &sd,
28576d49b41eSAndrew Gallatin &pf_rv, ri);
28586d49b41eSAndrew Gallatin if (pf_rv != PFIL_PASS && pf_rv != PFIL_REALLOCED)
28596d49b41eSAndrew Gallatin return (m);
28606d49b41eSAndrew Gallatin if (pf_rv == PFIL_PASS) {
28614c7070dbSScott Long m_init(m, M_NOWAIT, MT_DATA, M_PKTHDR);
286295246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
2863cd945dc0SMarcin Wojtas if (!IP_ALIGNED(m) && ri->iri_pad == 0)
286495246abbSSean Bruno m->m_data += 2;
286595246abbSSean Bruno #endif
286695246abbSSean Bruno memcpy(m->m_data, *sd.ifsd_cl, ri->iri_len);
286723ac9029SStephen Hurd m->m_len = ri->iri_frags[0].irf_len;
2868cd945dc0SMarcin Wojtas m->m_data += ri->iri_pad;
2869cd945dc0SMarcin Wojtas ri->iri_len -= ri->iri_pad;
28706d49b41eSAndrew Gallatin }
28714c7070dbSScott Long } else {
28726d49b41eSAndrew Gallatin m = assemble_segments(rxq, ri, &sd, &pf_rv);
28734f2beb72SPatrick Kelsey if (m == NULL)
28744f2beb72SPatrick Kelsey return (NULL);
28756d49b41eSAndrew Gallatin if (pf_rv != PFIL_PASS && pf_rv != PFIL_REALLOCED)
28766d49b41eSAndrew Gallatin return (m);
28774c7070dbSScott Long }
28784c7070dbSScott Long m->m_pkthdr.len = ri->iri_len;
28794c7070dbSScott Long m->m_pkthdr.rcvif = ri->iri_ifp;
28804c7070dbSScott Long m->m_flags |= ri->iri_flags;
28814c7070dbSScott Long m->m_pkthdr.ether_vtag = ri->iri_vtag;
28824c7070dbSScott Long m->m_pkthdr.flowid = ri->iri_flowid;
28834c7070dbSScott Long M_HASHTYPE_SET(m, ri->iri_rsstype);
28844c7070dbSScott Long m->m_pkthdr.csum_flags = ri->iri_csum_flags;
28854c7070dbSScott Long m->m_pkthdr.csum_data = ri->iri_csum_data;
28864c7070dbSScott Long return (m);
28874c7070dbSScott Long }
28884c7070dbSScott Long
288935e4e998SStephen Hurd #if defined(INET6) || defined(INET)
2890fe1bcadaSStephen Hurd static void
iflib_get_ip_forwarding(struct lro_ctrl * lc,bool * v4,bool * v6)2891fe1bcadaSStephen Hurd iflib_get_ip_forwarding(struct lro_ctrl *lc, bool *v4, bool *v6)
2892fe1bcadaSStephen Hurd {
289325c92cd2SJustin Hibbits CURVNET_SET(if_getvnet(lc->ifp));
2894fe1bcadaSStephen Hurd #if defined(INET6)
2895188adcb7SMarko Zec *v6 = V_ip6_forwarding;
2896fe1bcadaSStephen Hurd #endif
2897fe1bcadaSStephen Hurd #if defined(INET)
2898188adcb7SMarko Zec *v4 = V_ipforwarding;
2899fe1bcadaSStephen Hurd #endif
2900fe1bcadaSStephen Hurd CURVNET_RESTORE();
2901fe1bcadaSStephen Hurd }
2902fe1bcadaSStephen Hurd
290335e4e998SStephen Hurd /*
290435e4e998SStephen Hurd * Returns true if it's possible this packet could be LROed.
290535e4e998SStephen Hurd * if it returns false, it is guaranteed that tcp_lro_rx()
290635e4e998SStephen Hurd * would not return zero.
290735e4e998SStephen Hurd */
290835e4e998SStephen Hurd static bool
iflib_check_lro_possible(struct mbuf * m,bool v4_forwarding,bool v6_forwarding)2909fe1bcadaSStephen Hurd iflib_check_lro_possible(struct mbuf *m, bool v4_forwarding, bool v6_forwarding)
291035e4e998SStephen Hurd {
291135e4e998SStephen Hurd struct ether_header *eh;
291235e4e998SStephen Hurd
291335e4e998SStephen Hurd eh = mtod(m, struct ether_header *);
29146aee0bfaSMarko Zec switch (eh->ether_type) {
2915abec4724SSean Bruno #if defined(INET6)
29166aee0bfaSMarko Zec case htons(ETHERTYPE_IPV6):
29176aee0bfaSMarko Zec return (!v6_forwarding);
2918abec4724SSean Bruno #endif
2919abec4724SSean Bruno #if defined(INET)
29206aee0bfaSMarko Zec case htons(ETHERTYPE_IP):
29216aee0bfaSMarko Zec return (!v4_forwarding);
2922abec4724SSean Bruno #endif
292335e4e998SStephen Hurd }
292435e4e998SStephen Hurd
2925fa7045f9SZhenlei Huang return (false);
292635e4e998SStephen Hurd }
2927fe1bcadaSStephen Hurd #else
2928fe1bcadaSStephen Hurd static void
iflib_get_ip_forwarding(struct lro_ctrl * lc __unused,bool * v4 __unused,bool * v6 __unused)2929fe1bcadaSStephen Hurd iflib_get_ip_forwarding(struct lro_ctrl *lc __unused, bool *v4 __unused, bool *v6 __unused)
2930fe1bcadaSStephen Hurd {
2931fe1bcadaSStephen Hurd }
293235e4e998SStephen Hurd #endif
293335e4e998SStephen Hurd
2934fb1a29b4SHans Petter Selasky static void
_task_fn_rx_watchdog(void * context)2935fb1a29b4SHans Petter Selasky _task_fn_rx_watchdog(void *context)
2936fb1a29b4SHans Petter Selasky {
2937fb1a29b4SHans Petter Selasky iflib_rxq_t rxq = context;
2938fb1a29b4SHans Petter Selasky
2939fb1a29b4SHans Petter Selasky GROUPTASK_ENQUEUE(&rxq->ifr_task);
2940fb1a29b4SHans Petter Selasky }
2941fb1a29b4SHans Petter Selasky
2942fb1a29b4SHans Petter Selasky static uint8_t
iflib_rxeof(iflib_rxq_t rxq,qidx_t budget)294395246abbSSean Bruno iflib_rxeof(iflib_rxq_t rxq, qidx_t budget)
29444c7070dbSScott Long {
29451722eeacSMarius Strobl if_t ifp;
29464c7070dbSScott Long if_ctx_t ctx = rxq->ifr_ctx;
29474c7070dbSScott Long if_shared_ctx_t sctx = ctx->ifc_sctx;
294823ac9029SStephen Hurd if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
29494c7070dbSScott Long int avail, i;
295095246abbSSean Bruno qidx_t *cidxp;
29514c7070dbSScott Long struct if_rxd_info ri;
29524c7070dbSScott Long int err, budget_left, rx_bytes, rx_pkts;
29534c7070dbSScott Long iflib_fl_t fl;
29544c7070dbSScott Long int lro_enabled;
2955f6cb0deaSMatt Macy bool v4_forwarding, v6_forwarding, lro_possible;
2956fb1a29b4SHans Petter Selasky uint8_t retval = 0;
295795246abbSSean Bruno
29584c7070dbSScott Long /*
29594c7070dbSScott Long * XXX early demux data packets so that if_input processing only handles
29604c7070dbSScott Long * acks in interrupt context
29614c7070dbSScott Long */
296220f63282SStephen Hurd struct mbuf *m, *mh, *mt, *mf;
29634c7070dbSScott Long
29640b8df657SGleb Smirnoff NET_EPOCH_ASSERT();
29650b8df657SGleb Smirnoff
2966f6cb0deaSMatt Macy lro_possible = v4_forwarding = v6_forwarding = false;
296795246abbSSean Bruno ifp = ctx->ifc_ifp;
29684c7070dbSScott Long mh = mt = NULL;
29694c7070dbSScott Long MPASS(budget > 0);
29704c7070dbSScott Long rx_pkts = rx_bytes = 0;
297123ac9029SStephen Hurd if (sctx->isc_flags & IFLIB_HAS_RXCQ)
29724c7070dbSScott Long cidxp = &rxq->ifr_cq_cidx;
29734c7070dbSScott Long else
29744c7070dbSScott Long cidxp = &rxq->ifr_fl[0].ifl_cidx;
297523ac9029SStephen Hurd if ((avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget)) == 0) {
29764c7070dbSScott Long for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++)
2977b256d25cSMark Johnston retval |= iflib_fl_refill_all(ctx, fl);
29784c7070dbSScott Long DBG_COUNTER_INC(rx_unavail);
2979fb1a29b4SHans Petter Selasky return (retval);
29804c7070dbSScott Long }
29814c7070dbSScott Long
29826d49b41eSAndrew Gallatin /* pfil needs the vnet to be set */
298325c92cd2SJustin Hibbits CURVNET_SET_QUIET(if_getvnet(ifp));
29848b8d9093SMarius Strobl for (budget_left = budget; budget_left > 0 && avail > 0;) {
29854c7070dbSScott Long if (__predict_false(!CTX_ACTIVE(ctx))) {
29864c7070dbSScott Long DBG_COUNTER_INC(rx_ctx_inactive);
29874c7070dbSScott Long break;
29884c7070dbSScott Long }
29894c7070dbSScott Long /*
29904c7070dbSScott Long * Reset client set fields to their default values
29914c7070dbSScott Long */
299295246abbSSean Bruno rxd_info_zero(&ri);
29934c7070dbSScott Long ri.iri_qsidx = rxq->ifr_id;
29944c7070dbSScott Long ri.iri_cidx = *cidxp;
299595246abbSSean Bruno ri.iri_ifp = ifp;
29964c7070dbSScott Long ri.iri_frags = rxq->ifr_frags;
29974c7070dbSScott Long err = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri);
29984c7070dbSScott Long
299995246abbSSean Bruno if (err)
300095246abbSSean Bruno goto err;
30016d49b41eSAndrew Gallatin rx_pkts += 1;
30026d49b41eSAndrew Gallatin rx_bytes += ri.iri_len;
300323ac9029SStephen Hurd if (sctx->isc_flags & IFLIB_HAS_RXCQ) {
300423ac9029SStephen Hurd *cidxp = ri.iri_cidx;
300523ac9029SStephen Hurd /* Update our consumer index */
300695246abbSSean Bruno /* XXX NB: shurd - check if this is still safe */
30071722eeacSMarius Strobl while (rxq->ifr_cq_cidx >= scctx->isc_nrxd[0])
300823ac9029SStephen Hurd rxq->ifr_cq_cidx -= scctx->isc_nrxd[0];
30094c7070dbSScott Long /* was this only a completion queue message? */
30104c7070dbSScott Long if (__predict_false(ri.iri_nfrags == 0))
30114c7070dbSScott Long continue;
30124c7070dbSScott Long }
30134c7070dbSScott Long MPASS(ri.iri_nfrags != 0);
30144c7070dbSScott Long MPASS(ri.iri_len != 0);
30154c7070dbSScott Long
30164c7070dbSScott Long /* will advance the cidx on the corresponding free lists */
30174c7070dbSScott Long m = iflib_rxd_pkt_get(rxq, &ri);
30188b8d9093SMarius Strobl avail--;
30198b8d9093SMarius Strobl budget_left--;
30204c7070dbSScott Long if (avail == 0 && budget_left)
302123ac9029SStephen Hurd avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget_left);
30224c7070dbSScott Long
30236d49b41eSAndrew Gallatin if (__predict_false(m == NULL))
30244c7070dbSScott Long continue;
30256d49b41eSAndrew Gallatin
30264c7070dbSScott Long /* imm_pkt: -- cxgb */
30274c7070dbSScott Long if (mh == NULL)
30284c7070dbSScott Long mh = mt = m;
30294c7070dbSScott Long else {
30304c7070dbSScott Long mt->m_nextpkt = m;
30314c7070dbSScott Long mt = m;
30324c7070dbSScott Long }
30334c7070dbSScott Long }
30346d49b41eSAndrew Gallatin CURVNET_RESTORE();
30354c7070dbSScott Long /* make sure that we can refill faster than drain */
30364c7070dbSScott Long for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++)
3037b256d25cSMark Johnston retval |= iflib_fl_refill_all(ctx, fl);
30384c7070dbSScott Long
30394c7070dbSScott Long lro_enabled = (if_getcapenable(ifp) & IFCAP_LRO);
3040fe1bcadaSStephen Hurd if (lro_enabled)
3041fe1bcadaSStephen Hurd iflib_get_ip_forwarding(&rxq->ifr_lc, &v4_forwarding, &v6_forwarding);
304220f63282SStephen Hurd mt = mf = NULL;
30434c7070dbSScott Long while (mh != NULL) {
30444c7070dbSScott Long m = mh;
30454c7070dbSScott Long mh = mh->m_nextpkt;
30464c7070dbSScott Long m->m_nextpkt = NULL;
304795246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
304895246abbSSean Bruno if (!IP_ALIGNED(m) && (m = iflib_fixup_rx(m)) == NULL)
304995246abbSSean Bruno continue;
305095246abbSSean Bruno #endif
3051aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
305235e4e998SStephen Hurd if (lro_enabled) {
305335e4e998SStephen Hurd if (!lro_possible) {
3054fe1bcadaSStephen Hurd lro_possible = iflib_check_lro_possible(m, v4_forwarding, v6_forwarding);
305535e4e998SStephen Hurd if (lro_possible && mf != NULL) {
3056402810d3SJustin Hibbits if_input(ifp, mf);
305735e4e998SStephen Hurd DBG_COUNTER_INC(rx_if_input);
305835e4e998SStephen Hurd mt = mf = NULL;
305935e4e998SStephen Hurd }
306035e4e998SStephen Hurd }
306125ac1dd5SStephen Hurd if ((m->m_pkthdr.csum_flags & (CSUM_L4_CALC | CSUM_L4_VALID)) ==
306225ac1dd5SStephen Hurd (CSUM_L4_CALC | CSUM_L4_VALID)) {
306335e4e998SStephen Hurd if (lro_possible && tcp_lro_rx(&rxq->ifr_lc, m, 0) == 0)
30644c7070dbSScott Long continue;
306520f63282SStephen Hurd }
306625ac1dd5SStephen Hurd }
3067aaeb188aSBjoern A. Zeeb #endif
306835e4e998SStephen Hurd if (lro_possible) {
3069402810d3SJustin Hibbits if_input(ifp, m);
307035e4e998SStephen Hurd DBG_COUNTER_INC(rx_if_input);
307135e4e998SStephen Hurd continue;
307235e4e998SStephen Hurd }
307335e4e998SStephen Hurd
307435e4e998SStephen Hurd if (mf == NULL)
307535e4e998SStephen Hurd mf = m;
307620f63282SStephen Hurd if (mt != NULL)
307720f63282SStephen Hurd mt->m_nextpkt = m;
307820f63282SStephen Hurd mt = m;
307920f63282SStephen Hurd }
308020f63282SStephen Hurd if (mf != NULL) {
3081402810d3SJustin Hibbits if_input(ifp, mf);
30824c7070dbSScott Long DBG_COUNTER_INC(rx_if_input);
30834c7070dbSScott Long }
308423ac9029SStephen Hurd
30854c7070dbSScott Long if_inc_counter(ifp, IFCOUNTER_IBYTES, rx_bytes);
30864c7070dbSScott Long if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_pkts);
30874c7070dbSScott Long
30884c7070dbSScott Long /*
30894c7070dbSScott Long * Flush any outstanding LRO work
30904c7070dbSScott Long */
3091aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
309223ac9029SStephen Hurd tcp_lro_flush_all(&rxq->ifr_lc);
3093aaeb188aSBjoern A. Zeeb #endif
3094fb1a29b4SHans Petter Selasky if (avail != 0 || iflib_rxd_avail(ctx, rxq, *cidxp, 1) != 0)
3095fb1a29b4SHans Petter Selasky retval |= IFLIB_RXEOF_MORE;
3096fb1a29b4SHans Petter Selasky return (retval);
309795246abbSSean Bruno err:
30987b610b60SSean Bruno STATE_LOCK(ctx);
3099ab2e3f79SStephen Hurd ctx->ifc_flags |= IFC_DO_RESET;
3100940f62d6SEric Joyner iflib_admin_intr_deferred(ctx);
310146fa0c25SEric Joyner STATE_UNLOCK(ctx);
3102fb1a29b4SHans Petter Selasky return (0);
310395246abbSSean Bruno }
310495246abbSSean Bruno
310595246abbSSean Bruno #define TXD_NOTIFY_COUNT(txq) (((txq)->ift_size / (txq)->ift_update_freq) - 1)
310695246abbSSean Bruno static inline qidx_t
txq_max_db_deferred(iflib_txq_t txq,qidx_t in_use)310795246abbSSean Bruno txq_max_db_deferred(iflib_txq_t txq, qidx_t in_use)
310895246abbSSean Bruno {
310995246abbSSean Bruno qidx_t notify_count = TXD_NOTIFY_COUNT(txq);
311095246abbSSean Bruno qidx_t minthresh = txq->ift_size / 8;
311195246abbSSean Bruno if (in_use > 4 * minthresh)
311295246abbSSean Bruno return (notify_count);
311395246abbSSean Bruno if (in_use > 2 * minthresh)
311495246abbSSean Bruno return (notify_count >> 1);
311595246abbSSean Bruno if (in_use > minthresh)
311695246abbSSean Bruno return (notify_count >> 3);
311795246abbSSean Bruno return (0);
311895246abbSSean Bruno }
311995246abbSSean Bruno
312095246abbSSean Bruno static inline qidx_t
txq_max_rs_deferred(iflib_txq_t txq)312195246abbSSean Bruno txq_max_rs_deferred(iflib_txq_t txq)
312295246abbSSean Bruno {
312395246abbSSean Bruno qidx_t notify_count = TXD_NOTIFY_COUNT(txq);
312495246abbSSean Bruno qidx_t minthresh = txq->ift_size / 8;
312595246abbSSean Bruno if (txq->ift_in_use > 4 * minthresh)
312695246abbSSean Bruno return (notify_count);
312795246abbSSean Bruno if (txq->ift_in_use > 2 * minthresh)
312895246abbSSean Bruno return (notify_count >> 1);
312995246abbSSean Bruno if (txq->ift_in_use > minthresh)
313095246abbSSean Bruno return (notify_count >> 2);
31312b2fc973SSean Bruno return (2);
31324c7070dbSScott Long }
31334c7070dbSScott Long
31344c7070dbSScott Long #define M_CSUM_FLAGS(m) ((m)->m_pkthdr.csum_flags)
31354c7070dbSScott Long #define M_HAS_VLANTAG(m) (m->m_flags & M_VLANTAG)
313695246abbSSean Bruno
313795246abbSSean Bruno #define TXQ_MAX_DB_DEFERRED(txq, in_use) txq_max_db_deferred((txq), (in_use))
313895246abbSSean Bruno #define TXQ_MAX_RS_DEFERRED(txq) txq_max_rs_deferred(txq)
313923ac9029SStephen Hurd #define TXQ_MAX_DB_CONSUMED(size) (size >> 4)
31404c7070dbSScott Long
314195246abbSSean Bruno /* forward compatibility for cxgb */
314295246abbSSean Bruno #define FIRST_QSET(ctx) 0
314395246abbSSean Bruno #define NTXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_ntxqsets)
314495246abbSSean Bruno #define NRXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_nrxqsets)
314595246abbSSean Bruno #define QIDX(ctx, m) ((((m)->m_pkthdr.flowid & ctx->ifc_softc_ctx.isc_rss_table_mask) % NTXQSETS(ctx)) + FIRST_QSET(ctx))
314695246abbSSean Bruno #define DESC_RECLAIMABLE(q) ((int)((q)->ift_processed - (q)->ift_cleaned - (q)->ift_ctx->ifc_softc_ctx.isc_tx_nsegments))
314795246abbSSean Bruno
314895246abbSSean Bruno /* XXX we should be setting this to something other than zero */
314995246abbSSean Bruno #define RECLAIM_THRESH(ctx) ((ctx)->ifc_sctx->isc_tx_reclaim_thresh)
315081be6552SMatt Macy #define MAX_TX_DESC(ctx) MAX((ctx)->ifc_softc_ctx.isc_tx_tso_segments_max, \
31517474544bSMarius Strobl (ctx)->ifc_softc_ctx.isc_tx_nsegments)
315295246abbSSean Bruno
315395246abbSSean Bruno static inline bool
iflib_txd_db_check(iflib_txq_t txq,int ring)315481be6552SMatt Macy iflib_txd_db_check(iflib_txq_t txq, int ring)
31554c7070dbSScott Long {
315681be6552SMatt Macy if_ctx_t ctx = txq->ift_ctx;
315795246abbSSean Bruno qidx_t dbval, max;
31584c7070dbSScott Long
315981be6552SMatt Macy max = TXQ_MAX_DB_DEFERRED(txq, txq->ift_in_use);
316081be6552SMatt Macy
316181be6552SMatt Macy /* force || threshold exceeded || at the edge of the ring */
316281be6552SMatt Macy if (ring || (txq->ift_db_pending >= max) || (TXQ_AVAIL(txq) <= MAX_TX_DESC(ctx) + 2)) {
316381be6552SMatt Macy
316481be6552SMatt Macy /*
316581be6552SMatt Macy * 'npending' is used if the card's doorbell is in terms of the number of descriptors
316681be6552SMatt Macy * pending flush (BRCM). 'pidx' is used in cases where the card's doorbeel uses the
316781be6552SMatt Macy * producer index explicitly (INTC).
316881be6552SMatt Macy */
31694c7070dbSScott Long dbval = txq->ift_npending ? txq->ift_npending : txq->ift_pidx;
317095dcf343SMarius Strobl bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
317195dcf343SMarius Strobl BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
31724c7070dbSScott Long ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, dbval);
317381be6552SMatt Macy
317481be6552SMatt Macy /*
317581be6552SMatt Macy * Absent bugs there are zero packets pending so reset pending counts to zero.
317681be6552SMatt Macy */
31774c7070dbSScott Long txq->ift_db_pending = txq->ift_npending = 0;
317881be6552SMatt Macy return (true);
31794c7070dbSScott Long }
318081be6552SMatt Macy return (false);
31814c7070dbSScott Long }
31824c7070dbSScott Long
31834c7070dbSScott Long #ifdef PKT_DEBUG
31844c7070dbSScott Long static void
print_pkt(if_pkt_info_t pi)31854c7070dbSScott Long print_pkt(if_pkt_info_t pi)
31864c7070dbSScott Long {
31874c7070dbSScott Long printf("pi len: %d qsidx: %d nsegs: %d ndescs: %d flags: %x pidx: %d\n",
31884c7070dbSScott Long pi->ipi_len, pi->ipi_qsidx, pi->ipi_nsegs, pi->ipi_ndescs, pi->ipi_flags, pi->ipi_pidx);
31894c7070dbSScott Long printf("pi new_pidx: %d csum_flags: %lx tso_segsz: %d mflags: %x vtag: %d\n",
31904c7070dbSScott Long pi->ipi_new_pidx, pi->ipi_csum_flags, pi->ipi_tso_segsz, pi->ipi_mflags, pi->ipi_vtag);
31914c7070dbSScott Long printf("pi etype: %d ehdrlen: %d ip_hlen: %d ipproto: %d\n",
31924c7070dbSScott Long pi->ipi_etype, pi->ipi_ehdrlen, pi->ipi_ip_hlen, pi->ipi_ipproto);
31934c7070dbSScott Long }
31944c7070dbSScott Long #endif
31954c7070dbSScott Long
31964c7070dbSScott Long #define IS_TSO4(pi) ((pi)->ipi_csum_flags & CSUM_IP_TSO)
3197a06424ddSEric Joyner #define IS_TX_OFFLOAD4(pi) ((pi)->ipi_csum_flags & (CSUM_IP_TCP | CSUM_IP_TSO))
31984c7070dbSScott Long #define IS_TSO6(pi) ((pi)->ipi_csum_flags & CSUM_IP6_TSO)
3199a06424ddSEric Joyner #define IS_TX_OFFLOAD6(pi) ((pi)->ipi_csum_flags & (CSUM_IP6_TCP | CSUM_IP6_TSO))
32004c7070dbSScott Long
32019c950139SEric Joyner /**
32029c950139SEric Joyner * Parses out ethernet header information in the given mbuf.
32039c950139SEric Joyner * Returns in pi: ipi_etype (EtherType) and ipi_ehdrlen (Ethernet header length)
32049c950139SEric Joyner *
32059c950139SEric Joyner * This will account for the VLAN header if present.
32069c950139SEric Joyner *
32079c950139SEric Joyner * XXX: This doesn't handle QinQ, which could prevent TX offloads for those
32089c950139SEric Joyner * types of packets.
32099c950139SEric Joyner */
32109c950139SEric Joyner static int
iflib_parse_ether_header(if_pkt_info_t pi,struct mbuf ** mp,uint64_t * pullups)32119c950139SEric Joyner iflib_parse_ether_header(if_pkt_info_t pi, struct mbuf **mp, uint64_t *pullups)
32129c950139SEric Joyner {
32139c950139SEric Joyner struct ether_vlan_header *eh;
32149c950139SEric Joyner struct mbuf *m;
32159c950139SEric Joyner
32169c950139SEric Joyner m = *mp;
32179c950139SEric Joyner if (__predict_false(m->m_len < sizeof(*eh))) {
32189c950139SEric Joyner (*pullups)++;
32199c950139SEric Joyner if (__predict_false((m = m_pullup(m, sizeof(*eh))) == NULL))
32209c950139SEric Joyner return (ENOMEM);
32219c950139SEric Joyner }
32229c950139SEric Joyner eh = mtod(m, struct ether_vlan_header *);
32239c950139SEric Joyner if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
32249c950139SEric Joyner pi->ipi_etype = ntohs(eh->evl_proto);
32259c950139SEric Joyner pi->ipi_ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
32269c950139SEric Joyner } else {
32279c950139SEric Joyner pi->ipi_etype = ntohs(eh->evl_encap_proto);
32289c950139SEric Joyner pi->ipi_ehdrlen = ETHER_HDR_LEN;
32299c950139SEric Joyner }
32309c950139SEric Joyner *mp = m;
32319c950139SEric Joyner
32329c950139SEric Joyner return (0);
32339c950139SEric Joyner }
32349c950139SEric Joyner
32359c950139SEric Joyner /**
32369c950139SEric Joyner * Parse up to the L3 header and extract IPv4/IPv6 header information into pi.
32379c950139SEric Joyner * Currently this information includes: IP ToS value, IP header version/presence
32389c950139SEric Joyner *
32399c950139SEric Joyner * This is missing some checks and doesn't edit the packet content as it goes,
32409c950139SEric Joyner * unlike iflib_parse_header(), in order to keep the amount of code here minimal.
32419c950139SEric Joyner */
32429c950139SEric Joyner static int
iflib_parse_header_partial(if_pkt_info_t pi,struct mbuf ** mp,uint64_t * pullups)32439c950139SEric Joyner iflib_parse_header_partial(if_pkt_info_t pi, struct mbuf **mp, uint64_t *pullups)
32449c950139SEric Joyner {
32459c950139SEric Joyner struct mbuf *m;
32469c950139SEric Joyner int err;
32479c950139SEric Joyner
32489c950139SEric Joyner *pullups = 0;
32499c950139SEric Joyner m = *mp;
32509c950139SEric Joyner if (!M_WRITABLE(m)) {
32519c950139SEric Joyner if ((m = m_dup(m, M_NOWAIT)) == NULL) {
32529c950139SEric Joyner return (ENOMEM);
32539c950139SEric Joyner } else {
32549c950139SEric Joyner m_freem(*mp);
32559c950139SEric Joyner DBG_COUNTER_INC(tx_frees);
32569c950139SEric Joyner *mp = m;
32579c950139SEric Joyner }
32589c950139SEric Joyner }
32599c950139SEric Joyner
32609c950139SEric Joyner /* Fills out pi->ipi_etype */
32619c950139SEric Joyner err = iflib_parse_ether_header(pi, mp, pullups);
32629c950139SEric Joyner if (err)
32639c950139SEric Joyner return (err);
32649c950139SEric Joyner m = *mp;
32659c950139SEric Joyner
32669c950139SEric Joyner switch (pi->ipi_etype) {
32679c950139SEric Joyner #ifdef INET
32689c950139SEric Joyner case ETHERTYPE_IP:
32699c950139SEric Joyner {
32709c950139SEric Joyner struct mbuf *n;
32719c950139SEric Joyner struct ip *ip = NULL;
32729c950139SEric Joyner int miniplen;
32739c950139SEric Joyner
32749c950139SEric Joyner miniplen = min(m->m_pkthdr.len, pi->ipi_ehdrlen + sizeof(*ip));
32759c950139SEric Joyner if (__predict_false(m->m_len < miniplen)) {
32769c950139SEric Joyner /*
32779c950139SEric Joyner * Check for common case where the first mbuf only contains
32789c950139SEric Joyner * the Ethernet header
32799c950139SEric Joyner */
32809c950139SEric Joyner if (m->m_len == pi->ipi_ehdrlen) {
32819c950139SEric Joyner n = m->m_next;
32829c950139SEric Joyner MPASS(n);
32839c950139SEric Joyner /* If next mbuf contains at least the minimal IP header, then stop */
32849c950139SEric Joyner if (n->m_len >= sizeof(*ip)) {
32859c950139SEric Joyner ip = (struct ip *)n->m_data;
32869c950139SEric Joyner } else {
32879c950139SEric Joyner (*pullups)++;
32889c950139SEric Joyner if (__predict_false((m = m_pullup(m, miniplen)) == NULL))
32899c950139SEric Joyner return (ENOMEM);
32909c950139SEric Joyner ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
32919c950139SEric Joyner }
32929c950139SEric Joyner } else {
32939c950139SEric Joyner (*pullups)++;
32949c950139SEric Joyner if (__predict_false((m = m_pullup(m, miniplen)) == NULL))
32959c950139SEric Joyner return (ENOMEM);
32969c950139SEric Joyner ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
32979c950139SEric Joyner }
32989c950139SEric Joyner } else {
32999c950139SEric Joyner ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
33009c950139SEric Joyner }
33019c950139SEric Joyner
33029c950139SEric Joyner /* Have the IPv4 header w/ no options here */
33039c950139SEric Joyner pi->ipi_ip_hlen = ip->ip_hl << 2;
33049c950139SEric Joyner pi->ipi_ipproto = ip->ip_p;
33059c950139SEric Joyner pi->ipi_ip_tos = ip->ip_tos;
33069c950139SEric Joyner pi->ipi_flags |= IPI_TX_IPV4;
33079c950139SEric Joyner
33089c950139SEric Joyner break;
33099c950139SEric Joyner }
33109c950139SEric Joyner #endif
33119c950139SEric Joyner #ifdef INET6
33129c950139SEric Joyner case ETHERTYPE_IPV6:
33139c950139SEric Joyner {
33149c950139SEric Joyner struct ip6_hdr *ip6;
33159c950139SEric Joyner
33169c950139SEric Joyner if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) {
33179c950139SEric Joyner (*pullups)++;
33189c950139SEric Joyner if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) == NULL))
33199c950139SEric Joyner return (ENOMEM);
33209c950139SEric Joyner }
33219c950139SEric Joyner ip6 = (struct ip6_hdr *)(m->m_data + pi->ipi_ehdrlen);
33229c950139SEric Joyner
33239c950139SEric Joyner /* Have the IPv6 fixed header here */
33249c950139SEric Joyner pi->ipi_ip_hlen = sizeof(struct ip6_hdr);
33259c950139SEric Joyner pi->ipi_ipproto = ip6->ip6_nxt;
33269c950139SEric Joyner pi->ipi_ip_tos = IPV6_TRAFFIC_CLASS(ip6);
33279c950139SEric Joyner pi->ipi_flags |= IPI_TX_IPV6;
33289c950139SEric Joyner
33299c950139SEric Joyner break;
33309c950139SEric Joyner }
33319c950139SEric Joyner #endif
33329c950139SEric Joyner default:
33339c950139SEric Joyner pi->ipi_csum_flags &= ~CSUM_OFFLOAD;
33349c950139SEric Joyner pi->ipi_ip_hlen = 0;
33359c950139SEric Joyner break;
33369c950139SEric Joyner }
33379c950139SEric Joyner *mp = m;
33389c950139SEric Joyner
33399c950139SEric Joyner return (0);
33409c950139SEric Joyner
33419c950139SEric Joyner }
33429c950139SEric Joyner
33434c7070dbSScott Long static int
iflib_parse_header(iflib_txq_t txq,if_pkt_info_t pi,struct mbuf ** mp)33444c7070dbSScott Long iflib_parse_header(iflib_txq_t txq, if_pkt_info_t pi, struct mbuf **mp)
33454c7070dbSScott Long {
3346ab2e3f79SStephen Hurd if_shared_ctx_t sctx = txq->ift_ctx->ifc_sctx;
3347c9a49a4fSMarius Strobl struct mbuf *m;
33489c950139SEric Joyner int err;
33494c7070dbSScott Long
33508b8d9093SMarius Strobl m = *mp;
3351ab2e3f79SStephen Hurd if ((sctx->isc_flags & IFLIB_NEED_SCRATCH) &&
3352ab2e3f79SStephen Hurd M_WRITABLE(m) == 0) {
3353ab2e3f79SStephen Hurd if ((m = m_dup(m, M_NOWAIT)) == NULL) {
3354ab2e3f79SStephen Hurd return (ENOMEM);
3355ab2e3f79SStephen Hurd } else {
3356ab2e3f79SStephen Hurd m_freem(*mp);
335764e6fc13SStephen Hurd DBG_COUNTER_INC(tx_frees);
33588b8d9093SMarius Strobl *mp = m;
3359ab2e3f79SStephen Hurd }
3360ab2e3f79SStephen Hurd }
33611248952aSSean Bruno
33629c950139SEric Joyner /* Fills out pi->ipi_etype */
33639c950139SEric Joyner err = iflib_parse_ether_header(pi, mp, &txq->ift_pullups);
33649c950139SEric Joyner if (__predict_false(err))
33659c950139SEric Joyner return (err);
33669c950139SEric Joyner m = *mp;
33674c7070dbSScott Long
33684c7070dbSScott Long switch (pi->ipi_etype) {
33694c7070dbSScott Long #ifdef INET
33704c7070dbSScott Long case ETHERTYPE_IP:
33714c7070dbSScott Long {
3372c9a49a4fSMarius Strobl struct mbuf *n;
33734c7070dbSScott Long struct ip *ip = NULL;
33744c7070dbSScott Long struct tcphdr *th = NULL;
33754c7070dbSScott Long int minthlen;
33764c7070dbSScott Long
33774c7070dbSScott Long minthlen = min(m->m_pkthdr.len, pi->ipi_ehdrlen + sizeof(*ip) + sizeof(*th));
33784c7070dbSScott Long if (__predict_false(m->m_len < minthlen)) {
33794c7070dbSScott Long /*
33804c7070dbSScott Long * if this code bloat is causing too much of a hit
33814c7070dbSScott Long * move it to a separate function and mark it noinline
33824c7070dbSScott Long */
33834c7070dbSScott Long if (m->m_len == pi->ipi_ehdrlen) {
33844c7070dbSScott Long n = m->m_next;
33854c7070dbSScott Long MPASS(n);
33864c7070dbSScott Long if (n->m_len >= sizeof(*ip)) {
33874c7070dbSScott Long ip = (struct ip *)n->m_data;
33884c7070dbSScott Long if (n->m_len >= (ip->ip_hl << 2) + sizeof(*th))
33894c7070dbSScott Long th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
33904c7070dbSScott Long } else {
33914c7070dbSScott Long txq->ift_pullups++;
33924c7070dbSScott Long if (__predict_false((m = m_pullup(m, minthlen)) == NULL))
33934c7070dbSScott Long return (ENOMEM);
33944c7070dbSScott Long ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
33954c7070dbSScott Long }
33964c7070dbSScott Long } else {
33974c7070dbSScott Long txq->ift_pullups++;
33984c7070dbSScott Long if (__predict_false((m = m_pullup(m, minthlen)) == NULL))
33994c7070dbSScott Long return (ENOMEM);
34004c7070dbSScott Long ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
34014c7070dbSScott Long if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th))
34024c7070dbSScott Long th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
34034c7070dbSScott Long }
34044c7070dbSScott Long } else {
34054c7070dbSScott Long ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
34064c7070dbSScott Long if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th))
34074c7070dbSScott Long th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
34084c7070dbSScott Long }
34094c7070dbSScott Long pi->ipi_ip_hlen = ip->ip_hl << 2;
34104c7070dbSScott Long pi->ipi_ipproto = ip->ip_p;
34119c950139SEric Joyner pi->ipi_ip_tos = ip->ip_tos;
34124c7070dbSScott Long pi->ipi_flags |= IPI_TX_IPV4;
34134c7070dbSScott Long
3414a06424ddSEric Joyner /* TCP checksum offload may require TCP header length */
3415a06424ddSEric Joyner if (IS_TX_OFFLOAD4(pi)) {
3416a06424ddSEric Joyner if (__predict_true(pi->ipi_ipproto == IPPROTO_TCP)) {
34174c7070dbSScott Long if (__predict_false(th == NULL)) {
34184c7070dbSScott Long txq->ift_pullups++;
34194c7070dbSScott Long if (__predict_false((m = m_pullup(m, (ip->ip_hl << 2) + sizeof(*th))) == NULL))
34204c7070dbSScott Long return (ENOMEM);
34214c7070dbSScott Long th = (struct tcphdr *)((caddr_t)ip + pi->ipi_ip_hlen);
34224c7070dbSScott Long }
34234c7070dbSScott Long pi->ipi_tcp_hflags = th->th_flags;
34244c7070dbSScott Long pi->ipi_tcp_hlen = th->th_off << 2;
34254c7070dbSScott Long pi->ipi_tcp_seq = th->th_seq;
34264c7070dbSScott Long }
3427a06424ddSEric Joyner if (IS_TSO4(pi)) {
34284c7070dbSScott Long if (__predict_false(ip->ip_p != IPPROTO_TCP))
34294c7070dbSScott Long return (ENXIO);
34308d4ceb9cSStephen Hurd /*
34318d4ceb9cSStephen Hurd * TSO always requires hardware checksum offload.
34328d4ceb9cSStephen Hurd */
34338d4ceb9cSStephen Hurd pi->ipi_csum_flags |= (CSUM_IP_TCP | CSUM_IP);
34344c7070dbSScott Long th->th_sum = in_pseudo(ip->ip_src.s_addr,
34354c7070dbSScott Long ip->ip_dst.s_addr, htons(IPPROTO_TCP));
34364c7070dbSScott Long pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz;
34371248952aSSean Bruno if (sctx->isc_flags & IFLIB_TSO_INIT_IP) {
34381248952aSSean Bruno ip->ip_sum = 0;
34391248952aSSean Bruno ip->ip_len = htons(pi->ipi_ip_hlen + pi->ipi_tcp_hlen + pi->ipi_tso_segsz);
34401248952aSSean Bruno }
34414c7070dbSScott Long }
3442a06424ddSEric Joyner }
34438d4ceb9cSStephen Hurd if ((sctx->isc_flags & IFLIB_NEED_ZERO_CSUM) && (pi->ipi_csum_flags & CSUM_IP))
34448d4ceb9cSStephen Hurd ip->ip_sum = 0;
34458d4ceb9cSStephen Hurd
34464c7070dbSScott Long break;
34474c7070dbSScott Long }
34484c7070dbSScott Long #endif
34494c7070dbSScott Long #ifdef INET6
34504c7070dbSScott Long case ETHERTYPE_IPV6:
34514c7070dbSScott Long {
34524c7070dbSScott Long struct ip6_hdr *ip6 = (struct ip6_hdr *)(m->m_data + pi->ipi_ehdrlen);
34534c7070dbSScott Long struct tcphdr *th;
34544c7070dbSScott Long pi->ipi_ip_hlen = sizeof(struct ip6_hdr);
34554c7070dbSScott Long
34564c7070dbSScott Long if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) {
345764e6fc13SStephen Hurd txq->ift_pullups++;
34584c7070dbSScott Long if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) == NULL))
34594c7070dbSScott Long return (ENOMEM);
34604c7070dbSScott Long }
34614c7070dbSScott Long th = (struct tcphdr *)((caddr_t)ip6 + pi->ipi_ip_hlen);
34624c7070dbSScott Long
34634c7070dbSScott Long /* XXX-BZ this will go badly in case of ext hdrs. */
34644c7070dbSScott Long pi->ipi_ipproto = ip6->ip6_nxt;
34659c950139SEric Joyner pi->ipi_ip_tos = IPV6_TRAFFIC_CLASS(ip6);
34664c7070dbSScott Long pi->ipi_flags |= IPI_TX_IPV6;
34674c7070dbSScott Long
3468a06424ddSEric Joyner /* TCP checksum offload may require TCP header length */
3469a06424ddSEric Joyner if (IS_TX_OFFLOAD6(pi)) {
34704c7070dbSScott Long if (pi->ipi_ipproto == IPPROTO_TCP) {
34714c7070dbSScott Long if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) {
3472a06424ddSEric Joyner txq->ift_pullups++;
34734c7070dbSScott Long if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) == NULL))
34744c7070dbSScott Long return (ENOMEM);
34754c7070dbSScott Long }
34764c7070dbSScott Long pi->ipi_tcp_hflags = th->th_flags;
34774c7070dbSScott Long pi->ipi_tcp_hlen = th->th_off << 2;
3478a06424ddSEric Joyner pi->ipi_tcp_seq = th->th_seq;
34794c7070dbSScott Long }
3480a06424ddSEric Joyner if (IS_TSO6(pi)) {
34814c7070dbSScott Long if (__predict_false(ip6->ip6_nxt != IPPROTO_TCP))
34824c7070dbSScott Long return (ENXIO);
34834c7070dbSScott Long /*
34848d4ceb9cSStephen Hurd * TSO always requires hardware checksum offload.
34854c7070dbSScott Long */
3486a06424ddSEric Joyner pi->ipi_csum_flags |= CSUM_IP6_TCP;
34874c7070dbSScott Long th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
34884c7070dbSScott Long pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz;
34894c7070dbSScott Long }
3490a06424ddSEric Joyner }
34914c7070dbSScott Long break;
34924c7070dbSScott Long }
34934c7070dbSScott Long #endif
34944c7070dbSScott Long default:
34954c7070dbSScott Long pi->ipi_csum_flags &= ~CSUM_OFFLOAD;
34964c7070dbSScott Long pi->ipi_ip_hlen = 0;
34974c7070dbSScott Long break;
34984c7070dbSScott Long }
34994c7070dbSScott Long *mp = m;
35001248952aSSean Bruno
35014c7070dbSScott Long return (0);
35024c7070dbSScott Long }
35034c7070dbSScott Long
35044c7070dbSScott Long /*
35054c7070dbSScott Long * If dodgy hardware rejects the scatter gather chain we've handed it
350623ac9029SStephen Hurd * we'll need to remove the mbuf chain from ifsg_m[] before we can add the
350723ac9029SStephen Hurd * m_defrag'd mbufs
35084c7070dbSScott Long */
35094c7070dbSScott Long static __noinline struct mbuf *
iflib_remove_mbuf(iflib_txq_t txq)351023ac9029SStephen Hurd iflib_remove_mbuf(iflib_txq_t txq)
35114c7070dbSScott Long {
3512fbec776dSAndrew Gallatin int ntxd, pidx;
3513fbec776dSAndrew Gallatin struct mbuf *m, **ifsd_m;
35144c7070dbSScott Long
35154c7070dbSScott Long ifsd_m = txq->ift_sds.ifsd_m;
351623ac9029SStephen Hurd ntxd = txq->ift_size;
3517fbec776dSAndrew Gallatin pidx = txq->ift_pidx & (ntxd - 1);
3518fbec776dSAndrew Gallatin ifsd_m = txq->ift_sds.ifsd_m;
3519fbec776dSAndrew Gallatin m = ifsd_m[pidx];
35204c7070dbSScott Long ifsd_m[pidx] = NULL;
3521bfce461eSMarius Strobl bus_dmamap_unload(txq->ift_buf_tag, txq->ift_sds.ifsd_map[pidx]);
35228a04b53dSKonstantin Belousov if (txq->ift_sds.ifsd_tso_map != NULL)
3523bfce461eSMarius Strobl bus_dmamap_unload(txq->ift_tso_buf_tag,
35248a04b53dSKonstantin Belousov txq->ift_sds.ifsd_tso_map[pidx]);
35254c7070dbSScott Long #if MEMORY_LOGGING
35264c7070dbSScott Long txq->ift_dequeued++;
35274c7070dbSScott Long #endif
3528fbec776dSAndrew Gallatin return (m);
35294c7070dbSScott Long }
35304c7070dbSScott Long
353195246abbSSean Bruno static inline caddr_t
calc_next_txd(iflib_txq_t txq,int cidx,uint8_t qid)353295246abbSSean Bruno calc_next_txd(iflib_txq_t txq, int cidx, uint8_t qid)
353395246abbSSean Bruno {
353495246abbSSean Bruno qidx_t size;
353595246abbSSean Bruno int ntxd;
353695246abbSSean Bruno caddr_t start, end, cur, next;
353795246abbSSean Bruno
353895246abbSSean Bruno ntxd = txq->ift_size;
353995246abbSSean Bruno size = txq->ift_txd_size[qid];
354095246abbSSean Bruno start = txq->ift_ifdi[qid].idi_vaddr;
354195246abbSSean Bruno
354295246abbSSean Bruno if (__predict_false(size == 0))
354395246abbSSean Bruno return (start);
354495246abbSSean Bruno cur = start + size * cidx;
354595246abbSSean Bruno end = start + size * ntxd;
354695246abbSSean Bruno next = CACHE_PTR_NEXT(cur);
354795246abbSSean Bruno return (next < end ? next : start);
354895246abbSSean Bruno }
354995246abbSSean Bruno
3550d14c853bSStephen Hurd /*
3551d14c853bSStephen Hurd * Pad an mbuf to ensure a minimum ethernet frame size.
3552d14c853bSStephen Hurd * min_frame_size is the frame size (less CRC) to pad the mbuf to
3553d14c853bSStephen Hurd */
3554d14c853bSStephen Hurd static __noinline int
iflib_ether_pad(device_t dev,struct mbuf ** m_head,uint16_t min_frame_size)3555a15fbbb8SStephen Hurd iflib_ether_pad(device_t dev, struct mbuf **m_head, uint16_t min_frame_size)
3556d14c853bSStephen Hurd {
3557d14c853bSStephen Hurd /*
3558d14c853bSStephen Hurd * 18 is enough bytes to pad an ARP packet to 46 bytes, and
3559d14c853bSStephen Hurd * and ARP message is the smallest common payload I can think of
3560d14c853bSStephen Hurd */
3561d14c853bSStephen Hurd static char pad[18]; /* just zeros */
3562d14c853bSStephen Hurd int n;
3563a15fbbb8SStephen Hurd struct mbuf *new_head;
3564d14c853bSStephen Hurd
3565a15fbbb8SStephen Hurd if (!M_WRITABLE(*m_head)) {
3566a15fbbb8SStephen Hurd new_head = m_dup(*m_head, M_NOWAIT);
3567a15fbbb8SStephen Hurd if (new_head == NULL) {
356804993890SStephen Hurd m_freem(*m_head);
3569a15fbbb8SStephen Hurd device_printf(dev, "cannot pad short frame, m_dup() failed");
357006c47d48SStephen Hurd DBG_COUNTER_INC(encap_pad_mbuf_fail);
357164e6fc13SStephen Hurd DBG_COUNTER_INC(tx_frees);
3572fa7045f9SZhenlei Huang return (ENOMEM);
3573a15fbbb8SStephen Hurd }
3574a15fbbb8SStephen Hurd m_freem(*m_head);
3575a15fbbb8SStephen Hurd *m_head = new_head;
3576a15fbbb8SStephen Hurd }
3577a15fbbb8SStephen Hurd
3578a15fbbb8SStephen Hurd for (n = min_frame_size - (*m_head)->m_pkthdr.len;
3579d14c853bSStephen Hurd n > 0; n -= sizeof(pad))
3580a15fbbb8SStephen Hurd if (!m_append(*m_head, min(n, sizeof(pad)), pad))
3581d14c853bSStephen Hurd break;
3582d14c853bSStephen Hurd
3583d14c853bSStephen Hurd if (n > 0) {
3584a15fbbb8SStephen Hurd m_freem(*m_head);
3585d14c853bSStephen Hurd device_printf(dev, "cannot pad short frame\n");
3586d14c853bSStephen Hurd DBG_COUNTER_INC(encap_pad_mbuf_fail);
358764e6fc13SStephen Hurd DBG_COUNTER_INC(tx_frees);
3588d14c853bSStephen Hurd return (ENOBUFS);
3589d14c853bSStephen Hurd }
3590d14c853bSStephen Hurd
3591fa7045f9SZhenlei Huang return (0);
3592d14c853bSStephen Hurd }
3593d14c853bSStephen Hurd
35944c7070dbSScott Long static int
iflib_encap(iflib_txq_t txq,struct mbuf ** m_headp)35954c7070dbSScott Long iflib_encap(iflib_txq_t txq, struct mbuf **m_headp)
35964c7070dbSScott Long {
35974c7070dbSScott Long if_ctx_t ctx;
35984c7070dbSScott Long if_shared_ctx_t sctx;
35994c7070dbSScott Long if_softc_ctx_t scctx;
3600bfce461eSMarius Strobl bus_dma_tag_t buf_tag;
36014c7070dbSScott Long bus_dma_segment_t *segs;
3602fbec776dSAndrew Gallatin struct mbuf *m_head, **ifsd_m;
360395246abbSSean Bruno void *next_txd;
36044c7070dbSScott Long bus_dmamap_t map;
36054c7070dbSScott Long struct if_pkt_info pi;
36064c7070dbSScott Long int remap = 0;
36074c7070dbSScott Long int err, nsegs, ndesc, max_segs, pidx, cidx, next, ntxd;
36084c7070dbSScott Long
36094c7070dbSScott Long ctx = txq->ift_ctx;
36104c7070dbSScott Long sctx = ctx->ifc_sctx;
36114c7070dbSScott Long scctx = &ctx->ifc_softc_ctx;
36124c7070dbSScott Long segs = txq->ift_segs;
361323ac9029SStephen Hurd ntxd = txq->ift_size;
36144c7070dbSScott Long m_head = *m_headp;
36154c7070dbSScott Long map = NULL;
36164c7070dbSScott Long
36174c7070dbSScott Long /*
36184c7070dbSScott Long * If we're doing TSO the next descriptor to clean may be quite far ahead
36194c7070dbSScott Long */
36204c7070dbSScott Long cidx = txq->ift_cidx;
36214c7070dbSScott Long pidx = txq->ift_pidx;
362295246abbSSean Bruno if (ctx->ifc_flags & IFC_PREFETCH) {
36234c7070dbSScott Long next = (cidx + CACHE_PTR_INCREMENT) & (ntxd - 1);
362495246abbSSean Bruno if (!(ctx->ifc_flags & IFLIB_HAS_TXCQ)) {
362595246abbSSean Bruno next_txd = calc_next_txd(txq, cidx, 0);
362695246abbSSean Bruno prefetch(next_txd);
362795246abbSSean Bruno }
36284c7070dbSScott Long
36294c7070dbSScott Long /* prefetch the next cache line of mbuf pointers and flags */
36304c7070dbSScott Long prefetch(&txq->ift_sds.ifsd_m[next]);
36314c7070dbSScott Long prefetch(&txq->ift_sds.ifsd_map[next]);
36324c7070dbSScott Long next = (cidx + CACHE_LINE_SIZE) & (ntxd - 1);
36334c7070dbSScott Long }
363495246abbSSean Bruno map = txq->ift_sds.ifsd_map[pidx];
3635fbec776dSAndrew Gallatin ifsd_m = txq->ift_sds.ifsd_m;
36364c7070dbSScott Long
36374c7070dbSScott Long if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
3638bfce461eSMarius Strobl buf_tag = txq->ift_tso_buf_tag;
36394c7070dbSScott Long max_segs = scctx->isc_tx_tso_segments_max;
36408a04b53dSKonstantin Belousov map = txq->ift_sds.ifsd_tso_map[pidx];
3641bfce461eSMarius Strobl MPASS(buf_tag != NULL);
36427f87c040SMarius Strobl MPASS(max_segs > 0);
36434c7070dbSScott Long } else {
3644bfce461eSMarius Strobl buf_tag = txq->ift_buf_tag;
36454c7070dbSScott Long max_segs = scctx->isc_tx_nsegments;
36468a04b53dSKonstantin Belousov map = txq->ift_sds.ifsd_map[pidx];
36474c7070dbSScott Long }
3648d14c853bSStephen Hurd if ((sctx->isc_flags & IFLIB_NEED_ETHER_PAD) &&
3649d14c853bSStephen Hurd __predict_false(m_head->m_pkthdr.len < scctx->isc_min_frame_size)) {
3650a15fbbb8SStephen Hurd err = iflib_ether_pad(ctx->ifc_dev, m_headp, scctx->isc_min_frame_size);
365164e6fc13SStephen Hurd if (err) {
365264e6fc13SStephen Hurd DBG_COUNTER_INC(encap_txd_encap_fail);
3653fa7045f9SZhenlei Huang return (err);
3654d14c853bSStephen Hurd }
365564e6fc13SStephen Hurd }
3656a15fbbb8SStephen Hurd m_head = *m_headp;
365795246abbSSean Bruno
365895246abbSSean Bruno pkt_info_zero(&pi);
3659ab2e3f79SStephen Hurd pi.ipi_mflags = (m_head->m_flags & (M_VLANTAG | M_BCAST | M_MCAST));
3660ab2e3f79SStephen Hurd pi.ipi_pidx = pidx;
3661ab2e3f79SStephen Hurd pi.ipi_qsidx = txq->ift_id;
36623429c02fSStephen Hurd pi.ipi_len = m_head->m_pkthdr.len;
36633429c02fSStephen Hurd pi.ipi_csum_flags = m_head->m_pkthdr.csum_flags;
36641722eeacSMarius Strobl pi.ipi_vtag = M_HAS_VLANTAG(m_head) ? m_head->m_pkthdr.ether_vtag : 0;
36654c7070dbSScott Long
36664c7070dbSScott Long /* deliberate bitwise OR to make one condition */
36674c7070dbSScott Long if (__predict_true((pi.ipi_csum_flags | pi.ipi_vtag))) {
366864e6fc13SStephen Hurd if (__predict_false((err = iflib_parse_header(txq, &pi, m_headp)) != 0)) {
366964e6fc13SStephen Hurd DBG_COUNTER_INC(encap_txd_encap_fail);
36704c7070dbSScott Long return (err);
367164e6fc13SStephen Hurd }
36724c7070dbSScott Long m_head = *m_headp;
36734c7070dbSScott Long }
36744c7070dbSScott Long
36754c7070dbSScott Long retry:
3676bfce461eSMarius Strobl err = bus_dmamap_load_mbuf_sg(buf_tag, map, m_head, segs, &nsegs,
3677fbec776dSAndrew Gallatin BUS_DMA_NOWAIT);
36784c7070dbSScott Long defrag:
36794c7070dbSScott Long if (__predict_false(err)) {
36804c7070dbSScott Long switch (err) {
36814c7070dbSScott Long case EFBIG:
36824c7070dbSScott Long /* try collapse once and defrag once */
3683f7594707SAndrew Gallatin if (remap == 0) {
36844c7070dbSScott Long m_head = m_collapse(*m_headp, M_NOWAIT, max_segs);
3685f7594707SAndrew Gallatin /* try defrag if collapsing fails */
3686f7594707SAndrew Gallatin if (m_head == NULL)
3687f7594707SAndrew Gallatin remap++;
3688f7594707SAndrew Gallatin }
368964e6fc13SStephen Hurd if (remap == 1) {
369064e6fc13SStephen Hurd txq->ift_mbuf_defrag++;
36914c7070dbSScott Long m_head = m_defrag(*m_headp, M_NOWAIT);
369264e6fc13SStephen Hurd }
36933e8d1baeSEric Joyner /*
36943e8d1baeSEric Joyner * remap should never be >1 unless bus_dmamap_load_mbuf_sg
36953e8d1baeSEric Joyner * failed to map an mbuf that was run through m_defrag
36963e8d1baeSEric Joyner */
36973e8d1baeSEric Joyner MPASS(remap <= 1);
36983e8d1baeSEric Joyner if (__predict_false(m_head == NULL || remap > 1))
36994c7070dbSScott Long goto defrag_failed;
37003e8d1baeSEric Joyner remap++;
37014c7070dbSScott Long *m_headp = m_head;
37024c7070dbSScott Long goto retry;
37034c7070dbSScott Long break;
37044c7070dbSScott Long case ENOMEM:
37054c7070dbSScott Long txq->ift_no_tx_dma_setup++;
37064c7070dbSScott Long break;
37074c7070dbSScott Long default:
37084c7070dbSScott Long txq->ift_no_tx_dma_setup++;
37094c7070dbSScott Long m_freem(*m_headp);
37104c7070dbSScott Long DBG_COUNTER_INC(tx_frees);
37114c7070dbSScott Long *m_headp = NULL;
37124c7070dbSScott Long break;
37134c7070dbSScott Long }
37144c7070dbSScott Long txq->ift_map_failed++;
37154c7070dbSScott Long DBG_COUNTER_INC(encap_load_mbuf_fail);
371664e6fc13SStephen Hurd DBG_COUNTER_INC(encap_txd_encap_fail);
37174c7070dbSScott Long return (err);
37184c7070dbSScott Long }
3719fbec776dSAndrew Gallatin ifsd_m[pidx] = m_head;
37204c7070dbSScott Long /*
37214c7070dbSScott Long * XXX assumes a 1 to 1 relationship between segments and
37224c7070dbSScott Long * descriptors - this does not hold true on all drivers, e.g.
37234c7070dbSScott Long * cxgb
37244c7070dbSScott Long */
37254c7070dbSScott Long if (__predict_false(nsegs + 2 > TXQ_AVAIL(txq))) {
37264c7070dbSScott Long txq->ift_no_desc_avail++;
3727bfce461eSMarius Strobl bus_dmamap_unload(buf_tag, map);
37284c7070dbSScott Long DBG_COUNTER_INC(encap_txq_avail_fail);
372964e6fc13SStephen Hurd DBG_COUNTER_INC(encap_txd_encap_fail);
373023ac9029SStephen Hurd if ((txq->ift_task.gt_task.ta_flags & TASK_ENQUEUED) == 0)
37314c7070dbSScott Long GROUPTASK_ENQUEUE(&txq->ift_task);
37324c7070dbSScott Long return (ENOBUFS);
37334c7070dbSScott Long }
373495246abbSSean Bruno /*
373595246abbSSean Bruno * On Intel cards we can greatly reduce the number of TX interrupts
373695246abbSSean Bruno * we see by only setting report status on every Nth descriptor.
373795246abbSSean Bruno * However, this also means that the driver will need to keep track
373895246abbSSean Bruno * of the descriptors that RS was set on to check them for the DD bit.
373995246abbSSean Bruno */
374095246abbSSean Bruno txq->ift_rs_pending += nsegs + 1;
374195246abbSSean Bruno if (txq->ift_rs_pending > TXQ_MAX_RS_DEFERRED(txq) ||
37421f7ce05dSAndrew Gallatin iflib_no_tx_batch || (TXQ_AVAIL(txq) - nsegs) <= MAX_TX_DESC(ctx) + 2) {
374395246abbSSean Bruno pi.ipi_flags |= IPI_TX_INTR;
374495246abbSSean Bruno txq->ift_rs_pending = 0;
374595246abbSSean Bruno }
374695246abbSSean Bruno
37474c7070dbSScott Long pi.ipi_segs = segs;
37484c7070dbSScott Long pi.ipi_nsegs = nsegs;
37494c7070dbSScott Long
375023ac9029SStephen Hurd MPASS(pidx >= 0 && pidx < txq->ift_size);
37514c7070dbSScott Long #ifdef PKT_DEBUG
37524c7070dbSScott Long print_pkt(&pi);
37534c7070dbSScott Long #endif
37544c7070dbSScott Long if ((err = ctx->isc_txd_encap(ctx->ifc_softc, &pi)) == 0) {
375595dcf343SMarius Strobl bus_dmamap_sync(buf_tag, map, BUS_DMASYNC_PREWRITE);
37564c7070dbSScott Long DBG_COUNTER_INC(tx_encap);
375795246abbSSean Bruno MPASS(pi.ipi_new_pidx < txq->ift_size);
37584c7070dbSScott Long
37594c7070dbSScott Long ndesc = pi.ipi_new_pidx - pi.ipi_pidx;
37604c7070dbSScott Long if (pi.ipi_new_pidx < pi.ipi_pidx) {
376123ac9029SStephen Hurd ndesc += txq->ift_size;
37624c7070dbSScott Long txq->ift_gen = 1;
37634c7070dbSScott Long }
37641248952aSSean Bruno /*
37651248952aSSean Bruno * drivers can need as many as
37661248952aSSean Bruno * two sentinels
37671248952aSSean Bruno */
37681248952aSSean Bruno MPASS(ndesc <= pi.ipi_nsegs + 2);
37694c7070dbSScott Long MPASS(pi.ipi_new_pidx != pidx);
37704c7070dbSScott Long MPASS(ndesc > 0);
37714c7070dbSScott Long txq->ift_in_use += ndesc;
377281be6552SMatt Macy txq->ift_db_pending += ndesc;
377395246abbSSean Bruno
37744c7070dbSScott Long /*
37754c7070dbSScott Long * We update the last software descriptor again here because there may
37764c7070dbSScott Long * be a sentinel and/or there may be more mbufs than segments
37774c7070dbSScott Long */
37784c7070dbSScott Long txq->ift_pidx = pi.ipi_new_pidx;
37794c7070dbSScott Long txq->ift_npending += pi.ipi_ndescs;
3780f7594707SAndrew Gallatin } else {
378123ac9029SStephen Hurd *m_headp = m_head = iflib_remove_mbuf(txq);
3782f7594707SAndrew Gallatin if (err == EFBIG) {
37834c7070dbSScott Long txq->ift_txd_encap_efbig++;
3784f7594707SAndrew Gallatin if (remap < 2) {
3785f7594707SAndrew Gallatin remap = 1;
37864c7070dbSScott Long goto defrag;
3787f7594707SAndrew Gallatin }
3788f7594707SAndrew Gallatin }
3789f7594707SAndrew Gallatin goto defrag_failed;
3790f7594707SAndrew Gallatin }
379164e6fc13SStephen Hurd /*
379264e6fc13SStephen Hurd * err can't possibly be non-zero here, so we don't neet to test it
379364e6fc13SStephen Hurd * to see if we need to DBG_COUNTER_INC(encap_txd_encap_fail).
379464e6fc13SStephen Hurd */
37954c7070dbSScott Long return (err);
37964c7070dbSScott Long
37974c7070dbSScott Long defrag_failed:
37984c7070dbSScott Long txq->ift_mbuf_defrag_failed++;
37994c7070dbSScott Long txq->ift_map_failed++;
38004c7070dbSScott Long m_freem(*m_headp);
38014c7070dbSScott Long DBG_COUNTER_INC(tx_frees);
38024c7070dbSScott Long *m_headp = NULL;
380364e6fc13SStephen Hurd DBG_COUNTER_INC(encap_txd_encap_fail);
38044c7070dbSScott Long return (ENOMEM);
38054c7070dbSScott Long }
38064c7070dbSScott Long
38074c7070dbSScott Long static void
iflib_tx_desc_free(iflib_txq_t txq,int n)38084c7070dbSScott Long iflib_tx_desc_free(iflib_txq_t txq, int n)
38094c7070dbSScott Long {
38104c7070dbSScott Long uint32_t qsize, cidx, mask, gen;
38114c7070dbSScott Long struct mbuf *m, **ifsd_m;
381295246abbSSean Bruno bool do_prefetch;
38134c7070dbSScott Long
38144c7070dbSScott Long cidx = txq->ift_cidx;
38154c7070dbSScott Long gen = txq->ift_gen;
381623ac9029SStephen Hurd qsize = txq->ift_size;
38174c7070dbSScott Long mask = qsize - 1;
38184c7070dbSScott Long ifsd_m = txq->ift_sds.ifsd_m;
381995246abbSSean Bruno do_prefetch = (txq->ift_ctx->ifc_flags & IFC_PREFETCH);
38204c7070dbSScott Long
382194618825SMark Johnston while (n-- > 0) {
382295246abbSSean Bruno if (do_prefetch) {
38234c7070dbSScott Long prefetch(ifsd_m[(cidx + 3) & mask]);
38244c7070dbSScott Long prefetch(ifsd_m[(cidx + 4) & mask]);
382595246abbSSean Bruno }
38264c7070dbSScott Long if ((m = ifsd_m[cidx]) != NULL) {
3827fbec776dSAndrew Gallatin prefetch(&ifsd_m[(cidx + CACHE_PTR_INCREMENT) & mask]);
38288a04b53dSKonstantin Belousov if (m->m_pkthdr.csum_flags & CSUM_TSO) {
3829bfce461eSMarius Strobl bus_dmamap_sync(txq->ift_tso_buf_tag,
38308a04b53dSKonstantin Belousov txq->ift_sds.ifsd_tso_map[cidx],
38318a04b53dSKonstantin Belousov BUS_DMASYNC_POSTWRITE);
3832bfce461eSMarius Strobl bus_dmamap_unload(txq->ift_tso_buf_tag,
38338a04b53dSKonstantin Belousov txq->ift_sds.ifsd_tso_map[cidx]);
38348a04b53dSKonstantin Belousov } else {
3835bfce461eSMarius Strobl bus_dmamap_sync(txq->ift_buf_tag,
38368a04b53dSKonstantin Belousov txq->ift_sds.ifsd_map[cidx],
38378a04b53dSKonstantin Belousov BUS_DMASYNC_POSTWRITE);
3838bfce461eSMarius Strobl bus_dmamap_unload(txq->ift_buf_tag,
38398a04b53dSKonstantin Belousov txq->ift_sds.ifsd_map[cidx]);
38408a04b53dSKonstantin Belousov }
38414c7070dbSScott Long /* XXX we don't support any drivers that batch packets yet */
38424c7070dbSScott Long MPASS(m->m_nextpkt == NULL);
38435c5ca36cSSean Bruno m_freem(m);
38444c7070dbSScott Long ifsd_m[cidx] = NULL;
38454c7070dbSScott Long #if MEMORY_LOGGING
38464c7070dbSScott Long txq->ift_dequeued++;
38474c7070dbSScott Long #endif
38484c7070dbSScott Long DBG_COUNTER_INC(tx_frees);
38494c7070dbSScott Long }
38504c7070dbSScott Long if (__predict_false(++cidx == qsize)) {
38514c7070dbSScott Long cidx = 0;
38524c7070dbSScott Long gen = 0;
38534c7070dbSScott Long }
38544c7070dbSScott Long }
38554c7070dbSScott Long txq->ift_cidx = cidx;
38564c7070dbSScott Long txq->ift_gen = gen;
38574c7070dbSScott Long }
38584c7070dbSScott Long
38594c7070dbSScott Long static __inline int
iflib_completed_tx_reclaim(iflib_txq_t txq,int thresh)38604c7070dbSScott Long iflib_completed_tx_reclaim(iflib_txq_t txq, int thresh)
38614c7070dbSScott Long {
38624c7070dbSScott Long int reclaim;
38634c7070dbSScott Long if_ctx_t ctx = txq->ift_ctx;
38644c7070dbSScott Long
38654c7070dbSScott Long KASSERT(thresh >= 0, ("invalid threshold to reclaim"));
38664c7070dbSScott Long MPASS(thresh /*+ MAX_TX_DESC(txq->ift_ctx) */ < txq->ift_size);
38674c7070dbSScott Long
38684c7070dbSScott Long /*
38694c7070dbSScott Long * Need a rate-limiting check so that this isn't called every time
38704c7070dbSScott Long */
38714c7070dbSScott Long iflib_tx_credits_update(ctx, txq);
38724c7070dbSScott Long reclaim = DESC_RECLAIMABLE(txq);
38734c7070dbSScott Long
38744c7070dbSScott Long if (reclaim <= thresh /* + MAX_TX_DESC(txq->ift_ctx) */) {
38754c7070dbSScott Long #ifdef INVARIANTS
38764c7070dbSScott Long if (iflib_verbose_debug) {
3877b90ba458SZhenlei Huang printf("%s processed=%ju cleaned=%ju tx_nsegments=%d reclaim=%d thresh=%d\n", __func__,
38784c7070dbSScott Long txq->ift_processed, txq->ift_cleaned, txq->ift_ctx->ifc_softc_ctx.isc_tx_nsegments,
38794c7070dbSScott Long reclaim, thresh);
38804c7070dbSScott Long }
38814c7070dbSScott Long #endif
38824c7070dbSScott Long return (0);
38834c7070dbSScott Long }
38844c7070dbSScott Long iflib_tx_desc_free(txq, reclaim);
38854c7070dbSScott Long txq->ift_cleaned += reclaim;
38864c7070dbSScott Long txq->ift_in_use -= reclaim;
38874c7070dbSScott Long
38884c7070dbSScott Long return (reclaim);
38894c7070dbSScott Long }
38904c7070dbSScott Long
38914c7070dbSScott Long static struct mbuf **
_ring_peek_one(struct ifmp_ring * r,int cidx,int offset,int remaining)389295246abbSSean Bruno _ring_peek_one(struct ifmp_ring *r, int cidx, int offset, int remaining)
38934c7070dbSScott Long {
389495246abbSSean Bruno int next, size;
389595246abbSSean Bruno struct mbuf **items;
38964c7070dbSScott Long
389795246abbSSean Bruno size = r->size;
389895246abbSSean Bruno next = (cidx + CACHE_PTR_INCREMENT) & (size - 1);
389995246abbSSean Bruno items = __DEVOLATILE(struct mbuf **, &r->items[0]);
390095246abbSSean Bruno
390195246abbSSean Bruno prefetch(items[(cidx + offset) & (size - 1)]);
390295246abbSSean Bruno if (remaining > 1) {
39033429c02fSStephen Hurd prefetch2cachelines(&items[next]);
39043429c02fSStephen Hurd prefetch2cachelines(items[(cidx + offset + 1) & (size - 1)]);
39053429c02fSStephen Hurd prefetch2cachelines(items[(cidx + offset + 2) & (size - 1)]);
39063429c02fSStephen Hurd prefetch2cachelines(items[(cidx + offset + 3) & (size - 1)]);
390795246abbSSean Bruno }
390895246abbSSean Bruno return (__DEVOLATILE(struct mbuf **, &r->items[(cidx + offset) & (size - 1)]));
39094c7070dbSScott Long }
39104c7070dbSScott Long
39114c7070dbSScott Long static void
iflib_txq_check_drain(iflib_txq_t txq,int budget)39124c7070dbSScott Long iflib_txq_check_drain(iflib_txq_t txq, int budget)
39134c7070dbSScott Long {
39144c7070dbSScott Long
391595246abbSSean Bruno ifmp_ring_check_drainage(txq->ift_br, budget);
39164c7070dbSScott Long }
39174c7070dbSScott Long
39184c7070dbSScott Long static uint32_t
iflib_txq_can_drain(struct ifmp_ring * r)39194c7070dbSScott Long iflib_txq_can_drain(struct ifmp_ring *r)
39204c7070dbSScott Long {
39214c7070dbSScott Long iflib_txq_t txq = r->cookie;
39224c7070dbSScott Long if_ctx_t ctx = txq->ift_ctx;
39234c7070dbSScott Long
392495dcf343SMarius Strobl if (TXQ_AVAIL(txq) > MAX_TX_DESC(ctx) + 2)
392595dcf343SMarius Strobl return (1);
39268a04b53dSKonstantin Belousov bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
39278a04b53dSKonstantin Belousov BUS_DMASYNC_POSTREAD);
392895dcf343SMarius Strobl return (ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id,
392995dcf343SMarius Strobl false));
39304c7070dbSScott Long }
39314c7070dbSScott Long
39324c7070dbSScott Long static uint32_t
iflib_txq_drain(struct ifmp_ring * r,uint32_t cidx,uint32_t pidx)39334c7070dbSScott Long iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
39344c7070dbSScott Long {
39354c7070dbSScott Long iflib_txq_t txq = r->cookie;
39364c7070dbSScott Long if_ctx_t ctx = txq->ift_ctx;
39371722eeacSMarius Strobl if_t ifp = ctx->ifc_ifp;
3938c2c5d1e7SMarius Strobl struct mbuf *m, **mp;
393981be6552SMatt Macy int avail, bytes_sent, skipped, count, err, i;
394081be6552SMatt Macy int mcast_sent, pkt_sent, reclaimed;
3941c2c5d1e7SMarius Strobl bool do_prefetch, rang, ring;
39424c7070dbSScott Long
39434c7070dbSScott Long if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING) ||
39444c7070dbSScott Long !LINK_ACTIVE(ctx))) {
39454c7070dbSScott Long DBG_COUNTER_INC(txq_drain_notready);
39464c7070dbSScott Long return (0);
39474c7070dbSScott Long }
394895246abbSSean Bruno reclaimed = iflib_completed_tx_reclaim(txq, RECLAIM_THRESH(ctx));
394981be6552SMatt Macy rang = iflib_txd_db_check(txq, reclaimed && txq->ift_db_pending);
39504c7070dbSScott Long avail = IDXDIFF(pidx, cidx, r->size);
395181be6552SMatt Macy
39524c7070dbSScott Long if (__predict_false(ctx->ifc_flags & IFC_QFLUSH)) {
395381be6552SMatt Macy /*
395481be6552SMatt Macy * The driver is unloading so we need to free all pending packets.
395581be6552SMatt Macy */
39564c7070dbSScott Long DBG_COUNTER_INC(txq_drain_flushing);
39574c7070dbSScott Long for (i = 0; i < avail; i++) {
3958bc0e855bSStephen Hurd if (__predict_true(r->items[(cidx + i) & (r->size - 1)] != (void *)txq))
395954bf96fbSMark Johnston m_freem(r->items[(cidx + i) & (r->size - 1)]);
39604c7070dbSScott Long r->items[(cidx + i) & (r->size - 1)] = NULL;
39614c7070dbSScott Long }
39624c7070dbSScott Long return (avail);
39634c7070dbSScott Long }
396495246abbSSean Bruno
39654c7070dbSScott Long if (__predict_false(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE)) {
39664c7070dbSScott Long txq->ift_qstatus = IFLIB_QUEUE_IDLE;
39674c7070dbSScott Long CALLOUT_LOCK(txq);
39684c7070dbSScott Long callout_stop(&txq->ift_timer);
39694c7070dbSScott Long CALLOUT_UNLOCK(txq);
39704c7070dbSScott Long DBG_COUNTER_INC(txq_drain_oactive);
39714c7070dbSScott Long return (0);
39724c7070dbSScott Long }
397381be6552SMatt Macy
397481be6552SMatt Macy /*
397581be6552SMatt Macy * If we've reclaimed any packets this queue cannot be hung.
397681be6552SMatt Macy */
397795246abbSSean Bruno if (reclaimed)
397895246abbSSean Bruno txq->ift_qstatus = IFLIB_QUEUE_IDLE;
397981be6552SMatt Macy skipped = mcast_sent = bytes_sent = pkt_sent = 0;
39804c7070dbSScott Long count = MIN(avail, TX_BATCH_SIZE);
3981da69b8f9SSean Bruno #ifdef INVARIANTS
3982da69b8f9SSean Bruno if (iflib_verbose_debug)
3983b90ba458SZhenlei Huang printf("%s avail=%d ifc_flags=%x txq_avail=%d ", __func__,
3984da69b8f9SSean Bruno avail, ctx->ifc_flags, TXQ_AVAIL(txq));
3985da69b8f9SSean Bruno #endif
398695246abbSSean Bruno do_prefetch = (ctx->ifc_flags & IFC_PREFETCH);
39871ae4848cSMatt Macy err = 0;
398881be6552SMatt Macy for (i = 0; i < count && TXQ_AVAIL(txq) >= MAX_TX_DESC(ctx) + 2; i++) {
39891ae4848cSMatt Macy int rem = do_prefetch ? count - i : 0;
39904c7070dbSScott Long
399195246abbSSean Bruno mp = _ring_peek_one(r, cidx, i, rem);
3992da69b8f9SSean Bruno MPASS(mp != NULL && *mp != NULL);
399381be6552SMatt Macy
399481be6552SMatt Macy /*
399581be6552SMatt Macy * Completion interrupts will use the address of the txq
399681be6552SMatt Macy * as a sentinel to enqueue _something_ in order to acquire
399781be6552SMatt Macy * the lock on the mp_ring (there's no direct lock call).
399881be6552SMatt Macy * We obviously whave to check for these sentinel cases
399981be6552SMatt Macy * and skip them.
400081be6552SMatt Macy */
400195246abbSSean Bruno if (__predict_false(*mp == (struct mbuf *)txq)) {
400281be6552SMatt Macy skipped++;
400395246abbSSean Bruno continue;
400495246abbSSean Bruno }
400595246abbSSean Bruno err = iflib_encap(txq, mp);
400695246abbSSean Bruno if (__predict_false(err)) {
4007da69b8f9SSean Bruno /* no room - bail out */
400895246abbSSean Bruno if (err == ENOBUFS)
40094c7070dbSScott Long break;
401081be6552SMatt Macy skipped++;
4011da69b8f9SSean Bruno /* we can't send this packet - skip it */
40124c7070dbSScott Long continue;
4013da69b8f9SSean Bruno }
40144c7070dbSScott Long pkt_sent++;
40154c7070dbSScott Long m = *mp;
40164c7070dbSScott Long DBG_COUNTER_INC(tx_sent);
40174c7070dbSScott Long bytes_sent += m->m_pkthdr.len;
401895246abbSSean Bruno mcast_sent += !!(m->m_flags & M_MCAST);
40194c7070dbSScott Long
4020402810d3SJustin Hibbits if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)))
40214c7070dbSScott Long break;
402281be6552SMatt Macy ETHER_BPF_MTAP(ifp, m);
402381be6552SMatt Macy rang = iflib_txd_db_check(txq, false);
40244c7070dbSScott Long }
40254c7070dbSScott Long
402695246abbSSean Bruno /* deliberate use of bitwise or to avoid gratuitous short-circuit */
402781be6552SMatt Macy ring = rang ? false : (iflib_min_tx_latency | err);
402881be6552SMatt Macy iflib_txd_db_check(txq, ring);
40294c7070dbSScott Long if_inc_counter(ifp, IFCOUNTER_OBYTES, bytes_sent);
40304c7070dbSScott Long if_inc_counter(ifp, IFCOUNTER_OPACKETS, pkt_sent);
40314c7070dbSScott Long if (mcast_sent)
40324c7070dbSScott Long if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast_sent);
4033da69b8f9SSean Bruno #ifdef INVARIANTS
4034da69b8f9SSean Bruno if (iflib_verbose_debug)
403581be6552SMatt Macy printf("consumed=%d\n", skipped + pkt_sent);
4036da69b8f9SSean Bruno #endif
403781be6552SMatt Macy return (skipped + pkt_sent);
40384c7070dbSScott Long }
40394c7070dbSScott Long
4040da69b8f9SSean Bruno static uint32_t
iflib_txq_drain_always(struct ifmp_ring * r)4041da69b8f9SSean Bruno iflib_txq_drain_always(struct ifmp_ring *r)
4042da69b8f9SSean Bruno {
4043da69b8f9SSean Bruno return (1);
4044da69b8f9SSean Bruno }
4045da69b8f9SSean Bruno
4046da69b8f9SSean Bruno static uint32_t
iflib_txq_drain_free(struct ifmp_ring * r,uint32_t cidx,uint32_t pidx)4047da69b8f9SSean Bruno iflib_txq_drain_free(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
4048da69b8f9SSean Bruno {
4049da69b8f9SSean Bruno int i, avail;
4050da69b8f9SSean Bruno struct mbuf **mp;
4051da69b8f9SSean Bruno iflib_txq_t txq;
4052da69b8f9SSean Bruno
4053da69b8f9SSean Bruno txq = r->cookie;
4054da69b8f9SSean Bruno
4055da69b8f9SSean Bruno txq->ift_qstatus = IFLIB_QUEUE_IDLE;
4056da69b8f9SSean Bruno CALLOUT_LOCK(txq);
4057da69b8f9SSean Bruno callout_stop(&txq->ift_timer);
4058da69b8f9SSean Bruno CALLOUT_UNLOCK(txq);
4059da69b8f9SSean Bruno
4060da69b8f9SSean Bruno avail = IDXDIFF(pidx, cidx, r->size);
4061da69b8f9SSean Bruno for (i = 0; i < avail; i++) {
406295246abbSSean Bruno mp = _ring_peek_one(r, cidx, i, avail - i);
406395246abbSSean Bruno if (__predict_false(*mp == (struct mbuf *)txq))
406495246abbSSean Bruno continue;
4065da69b8f9SSean Bruno m_freem(*mp);
406664e6fc13SStephen Hurd DBG_COUNTER_INC(tx_frees);
4067da69b8f9SSean Bruno }
4068da69b8f9SSean Bruno MPASS(ifmp_ring_is_stalled(r) == 0);
4069da69b8f9SSean Bruno return (avail);
4070da69b8f9SSean Bruno }
4071da69b8f9SSean Bruno
4072da69b8f9SSean Bruno static void
iflib_ifmp_purge(iflib_txq_t txq)4073da69b8f9SSean Bruno iflib_ifmp_purge(iflib_txq_t txq)
4074da69b8f9SSean Bruno {
4075da69b8f9SSean Bruno struct ifmp_ring *r;
4076da69b8f9SSean Bruno
407795246abbSSean Bruno r = txq->ift_br;
4078da69b8f9SSean Bruno r->drain = iflib_txq_drain_free;
4079da69b8f9SSean Bruno r->can_drain = iflib_txq_drain_always;
4080da69b8f9SSean Bruno
4081da69b8f9SSean Bruno ifmp_ring_check_drainage(r, r->size);
4082da69b8f9SSean Bruno
4083da69b8f9SSean Bruno r->drain = iflib_txq_drain;
4084da69b8f9SSean Bruno r->can_drain = iflib_txq_can_drain;
4085da69b8f9SSean Bruno }
4086da69b8f9SSean Bruno
40874c7070dbSScott Long static void
_task_fn_tx(void * context)408823ac9029SStephen Hurd _task_fn_tx(void *context)
40894c7070dbSScott Long {
40904c7070dbSScott Long iflib_txq_t txq = context;
40914c7070dbSScott Long if_ctx_t ctx = txq->ift_ctx;
4092a6611c93SMarius Strobl if_t ifp = ctx->ifc_ifp;
4093fe51d4cdSStephen Hurd int abdicate = ctx->ifc_sysctl_tx_abdicate;
40944c7070dbSScott Long
40951248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
40961248952aSSean Bruno txq->ift_cpu_exec_count[curcpu]++;
40971248952aSSean Bruno #endif
409888a68866SVincenzo Maffione if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
40994c7070dbSScott Long return;
410095dcf343SMarius Strobl #ifdef DEV_NETMAP
410188a68866SVincenzo Maffione if ((if_getcapenable(ifp) & IFCAP_NETMAP) &&
410288a68866SVincenzo Maffione netmap_tx_irq(ifp, txq->ift_id))
410388a68866SVincenzo Maffione goto skip_ifmp;
410495dcf343SMarius Strobl #endif
4105b8ca4756SPatrick Kelsey #ifdef ALTQ
410625c92cd2SJustin Hibbits if (if_altq_is_enabled(ifp))
4107b8ca4756SPatrick Kelsey iflib_altq_if_start(ifp);
4108b8ca4756SPatrick Kelsey #endif
410995246abbSSean Bruno if (txq->ift_db_pending)
4110fe51d4cdSStephen Hurd ifmp_ring_enqueue(txq->ift_br, (void **)&txq, 1, TX_BATCH_SIZE, abdicate);
4111fe51d4cdSStephen Hurd else if (!abdicate)
4112fe51d4cdSStephen Hurd ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
4113fe51d4cdSStephen Hurd /*
4114fe51d4cdSStephen Hurd * When abdicating, we always need to check drainage, not just when we don't enqueue
4115fe51d4cdSStephen Hurd */
4116fe51d4cdSStephen Hurd if (abdicate)
4117fe51d4cdSStephen Hurd ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
411888a68866SVincenzo Maffione #ifdef DEV_NETMAP
411988a68866SVincenzo Maffione skip_ifmp:
412088a68866SVincenzo Maffione #endif
412195246abbSSean Bruno if (ctx->ifc_flags & IFC_LEGACY)
412295246abbSSean Bruno IFDI_INTR_ENABLE(ctx);
41233d10e9edSMarius Strobl else
41241ae4848cSMatt Macy IFDI_TX_QUEUE_INTR_ENABLE(ctx, txq->ift_id);
41254c7070dbSScott Long }
41264c7070dbSScott Long
41274c7070dbSScott Long static void
_task_fn_rx(void * context)412823ac9029SStephen Hurd _task_fn_rx(void *context)
41294c7070dbSScott Long {
41304c7070dbSScott Long iflib_rxq_t rxq = context;
41314c7070dbSScott Long if_ctx_t ctx = rxq->ifr_ctx;
4132fb1a29b4SHans Petter Selasky uint8_t more;
4133f4d2154eSStephen Hurd uint16_t budget;
4134e136e9c8SVincenzo Maffione #ifdef DEV_NETMAP
4135e136e9c8SVincenzo Maffione u_int work = 0;
4136e136e9c8SVincenzo Maffione int nmirq;
4137e136e9c8SVincenzo Maffione #endif
41384c7070dbSScott Long
41391248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
41401248952aSSean Bruno rxq->ifr_cpu_exec_count[curcpu]++;
41411248952aSSean Bruno #endif
41424c7070dbSScott Long DBG_COUNTER_INC(task_fn_rxs);
41434c7070dbSScott Long if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
41444c7070dbSScott Long return;
4145d0d0ad0aSStephen Hurd #ifdef DEV_NETMAP
4146e136e9c8SVincenzo Maffione nmirq = netmap_rx_irq(ctx->ifc_ifp, rxq->ifr_id, &work);
4147e136e9c8SVincenzo Maffione if (nmirq != NM_IRQ_PASS) {
4148e136e9c8SVincenzo Maffione more = (nmirq == NM_IRQ_RESCHED) ? IFLIB_RXEOF_MORE : 0;
4149fb1a29b4SHans Petter Selasky goto skip_rxeof;
4150d0d0ad0aSStephen Hurd }
4151d0d0ad0aSStephen Hurd #endif
4152f4d2154eSStephen Hurd budget = ctx->ifc_sysctl_rx_budget;
4153f4d2154eSStephen Hurd if (budget == 0)
4154f4d2154eSStephen Hurd budget = 16; /* XXX */
4155fb1a29b4SHans Petter Selasky more = iflib_rxeof(rxq, budget);
4156fb1a29b4SHans Petter Selasky #ifdef DEV_NETMAP
4157fb1a29b4SHans Petter Selasky skip_rxeof:
4158fb1a29b4SHans Petter Selasky #endif
4159fb1a29b4SHans Petter Selasky if ((more & IFLIB_RXEOF_MORE) == 0) {
41604c7070dbSScott Long if (ctx->ifc_flags & IFC_LEGACY)
41614c7070dbSScott Long IFDI_INTR_ENABLE(ctx);
41623d10e9edSMarius Strobl else
41631ae4848cSMatt Macy IFDI_RX_QUEUE_INTR_ENABLE(ctx, rxq->ifr_id);
41641ae4848cSMatt Macy DBG_COUNTER_INC(rx_intr_enables);
41654c7070dbSScott Long }
41664c7070dbSScott Long if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
41674c7070dbSScott Long return;
4168fb1a29b4SHans Petter Selasky
4169fb1a29b4SHans Petter Selasky if (more & IFLIB_RXEOF_MORE)
41704c7070dbSScott Long GROUPTASK_ENQUEUE(&rxq->ifr_task);
4171fb1a29b4SHans Petter Selasky else if (more & IFLIB_RXEOF_EMPTY)
4172fb1a29b4SHans Petter Selasky callout_reset_curcpu(&rxq->ifr_watchdog, 1, &_task_fn_rx_watchdog, rxq);
41734c7070dbSScott Long }
41744c7070dbSScott Long
41754c7070dbSScott Long static void
_task_fn_admin(void * context)417623ac9029SStephen Hurd _task_fn_admin(void *context)
41774c7070dbSScott Long {
41784c7070dbSScott Long if_ctx_t ctx = context;
41794c7070dbSScott Long if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
41804c7070dbSScott Long iflib_txq_t txq;
4181ab2e3f79SStephen Hurd int i;
418277c1fcecSEric Joyner bool oactive, running, do_reset, do_watchdog, in_detach;
4183ab2e3f79SStephen Hurd
41847b610b60SSean Bruno STATE_LOCK(ctx);
41857b610b60SSean Bruno running = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING);
41867b610b60SSean Bruno oactive = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE);
41877b610b60SSean Bruno do_reset = (ctx->ifc_flags & IFC_DO_RESET);
41887b610b60SSean Bruno do_watchdog = (ctx->ifc_flags & IFC_DO_WATCHDOG);
418977c1fcecSEric Joyner in_detach = (ctx->ifc_flags & IFC_IN_DETACH);
41907b610b60SSean Bruno ctx->ifc_flags &= ~(IFC_DO_RESET | IFC_DO_WATCHDOG);
41917b610b60SSean Bruno STATE_UNLOCK(ctx);
41927b610b60SSean Bruno
419377c1fcecSEric Joyner if ((!running && !oactive) && !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
419477c1fcecSEric Joyner return;
419577c1fcecSEric Joyner if (in_detach)
4196ab2e3f79SStephen Hurd return;
41974c7070dbSScott Long
41984c7070dbSScott Long CTX_LOCK(ctx);
41994c7070dbSScott Long for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) {
42004c7070dbSScott Long CALLOUT_LOCK(txq);
42014c7070dbSScott Long callout_stop(&txq->ift_timer);
42024c7070dbSScott Long CALLOUT_UNLOCK(txq);
42034c7070dbSScott Long }
420409c3f04fSMarcin Wojtas if (ctx->ifc_sctx->isc_flags & IFLIB_HAS_ADMINCQ)
420509c3f04fSMarcin Wojtas IFDI_ADMIN_COMPLETION_HANDLE(ctx);
42067b610b60SSean Bruno if (do_watchdog) {
42077b610b60SSean Bruno ctx->ifc_watchdog_events++;
42087b610b60SSean Bruno IFDI_WATCHDOG_RESET(ctx);
42097b610b60SSean Bruno }
4210d300df01SStephen Hurd IFDI_UPDATE_ADMIN_STATUS(ctx);
4211dd7fbcf1SStephen Hurd for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) {
4212618d49f5SAlexander Motin callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer, txq,
4213618d49f5SAlexander Motin txq->ift_timer.c_cpu);
4214dd7fbcf1SStephen Hurd }
4215ab2e3f79SStephen Hurd IFDI_LINK_INTR_ENABLE(ctx);
42167b610b60SSean Bruno if (do_reset)
4217ab2e3f79SStephen Hurd iflib_if_init_locked(ctx);
42184c7070dbSScott Long CTX_UNLOCK(ctx);
42194c7070dbSScott Long
4220ab2e3f79SStephen Hurd if (LINK_ACTIVE(ctx) == 0)
42214c7070dbSScott Long return;
42224c7070dbSScott Long for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++)
42234c7070dbSScott Long iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET);
42244c7070dbSScott Long }
42254c7070dbSScott Long
42264c7070dbSScott Long static void
_task_fn_iov(void * context)422723ac9029SStephen Hurd _task_fn_iov(void *context)
42284c7070dbSScott Long {
42294c7070dbSScott Long if_ctx_t ctx = context;
42304c7070dbSScott Long
423177c1fcecSEric Joyner if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) &&
423277c1fcecSEric Joyner !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
42334c7070dbSScott Long return;
42344c7070dbSScott Long
42354c7070dbSScott Long CTX_LOCK(ctx);
42364c7070dbSScott Long IFDI_VFLR_HANDLE(ctx);
42374c7070dbSScott Long CTX_UNLOCK(ctx);
42384c7070dbSScott Long }
42394c7070dbSScott Long
42404c7070dbSScott Long static int
iflib_sysctl_int_delay(SYSCTL_HANDLER_ARGS)42414c7070dbSScott Long iflib_sysctl_int_delay(SYSCTL_HANDLER_ARGS)
42424c7070dbSScott Long {
42434c7070dbSScott Long int err;
42444c7070dbSScott Long if_int_delay_info_t info;
42454c7070dbSScott Long if_ctx_t ctx;
42464c7070dbSScott Long
42474c7070dbSScott Long info = (if_int_delay_info_t)arg1;
42484c7070dbSScott Long ctx = info->iidi_ctx;
42494c7070dbSScott Long info->iidi_req = req;
42504c7070dbSScott Long info->iidi_oidp = oidp;
42514c7070dbSScott Long CTX_LOCK(ctx);
42524c7070dbSScott Long err = IFDI_SYSCTL_INT_DELAY(ctx, info);
42534c7070dbSScott Long CTX_UNLOCK(ctx);
42544c7070dbSScott Long return (err);
42554c7070dbSScott Long }
42564c7070dbSScott Long
42574c7070dbSScott Long /*********************************************************************
42584c7070dbSScott Long *
42594c7070dbSScott Long * IFNET FUNCTIONS
42604c7070dbSScott Long *
42614c7070dbSScott Long **********************************************************************/
42624c7070dbSScott Long
42634c7070dbSScott Long static void
iflib_if_init_locked(if_ctx_t ctx)42644c7070dbSScott Long iflib_if_init_locked(if_ctx_t ctx)
42654c7070dbSScott Long {
42664c7070dbSScott Long iflib_stop(ctx);
42674c7070dbSScott Long iflib_init_locked(ctx);
42684c7070dbSScott Long }
42694c7070dbSScott Long
42704c7070dbSScott Long static void
iflib_if_init(void * arg)42714c7070dbSScott Long iflib_if_init(void *arg)
42724c7070dbSScott Long {
42734c7070dbSScott Long if_ctx_t ctx = arg;
42744c7070dbSScott Long
42754c7070dbSScott Long CTX_LOCK(ctx);
42764c7070dbSScott Long iflib_if_init_locked(ctx);
42774c7070dbSScott Long CTX_UNLOCK(ctx);
42784c7070dbSScott Long }
42794c7070dbSScott Long
42804c7070dbSScott Long static int
iflib_if_transmit(if_t ifp,struct mbuf * m)42814c7070dbSScott Long iflib_if_transmit(if_t ifp, struct mbuf *m)
42824c7070dbSScott Long {
42834c7070dbSScott Long if_ctx_t ctx = if_getsoftc(ifp);
42844c7070dbSScott Long iflib_txq_t txq;
428523ac9029SStephen Hurd int err, qidx;
42869c950139SEric Joyner int abdicate;
42874c7070dbSScott Long
4288402810d3SJustin Hibbits if (__predict_false((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0 || !LINK_ACTIVE(ctx))) {
42894c7070dbSScott Long DBG_COUNTER_INC(tx_frees);
42904c7070dbSScott Long m_freem(m);
4291225eae1bSEric Joyner return (ENETDOWN);
42924c7070dbSScott Long }
42934c7070dbSScott Long
429423ac9029SStephen Hurd MPASS(m->m_nextpkt == NULL);
4295b8ca4756SPatrick Kelsey /* ALTQ-enabled interfaces always use queue 0. */
42964c7070dbSScott Long qidx = 0;
4297213e9139SEric Joyner /* Use driver-supplied queue selection method if it exists */
42989c950139SEric Joyner if (ctx->isc_txq_select_v2) {
42999c950139SEric Joyner struct if_pkt_info pi;
43009c950139SEric Joyner uint64_t early_pullups = 0;
43019c950139SEric Joyner pkt_info_zero(&pi);
43029c950139SEric Joyner
43039c950139SEric Joyner err = iflib_parse_header_partial(&pi, &m, &early_pullups);
43049c950139SEric Joyner if (__predict_false(err != 0)) {
43059c950139SEric Joyner /* Assign pullups for bad pkts to default queue */
43069c950139SEric Joyner ctx->ifc_txqs[0].ift_pullups += early_pullups;
43079c950139SEric Joyner DBG_COUNTER_INC(encap_txd_encap_fail);
43089c950139SEric Joyner return (err);
43099c950139SEric Joyner }
43109c950139SEric Joyner /* Let driver make queueing decision */
43119c950139SEric Joyner qidx = ctx->isc_txq_select_v2(ctx->ifc_softc, m, &pi);
43129c950139SEric Joyner ctx->ifc_txqs[qidx].ift_pullups += early_pullups;
43139c950139SEric Joyner }
43149c950139SEric Joyner /* Backwards compatibility w/ simpler queue select */
43159c950139SEric Joyner else if (ctx->isc_txq_select)
4316213e9139SEric Joyner qidx = ctx->isc_txq_select(ctx->ifc_softc, m);
4317213e9139SEric Joyner /* If not, use iflib's standard method */
431825c92cd2SJustin Hibbits else if ((NTXQSETS(ctx) > 1) && M_HASHTYPE_GET(m) && !if_altq_is_enabled(ifp))
43194c7070dbSScott Long qidx = QIDX(ctx, m);
4320213e9139SEric Joyner
4321213e9139SEric Joyner /* Set TX queue */
43224c7070dbSScott Long txq = &ctx->ifc_txqs[qidx];
43234c7070dbSScott Long
43244c7070dbSScott Long #ifdef DRIVER_BACKPRESSURE
43254c7070dbSScott Long if (txq->ift_closed) {
43264c7070dbSScott Long while (m != NULL) {
43274c7070dbSScott Long next = m->m_nextpkt;
43284c7070dbSScott Long m->m_nextpkt = NULL;
43294c7070dbSScott Long m_freem(m);
433064e6fc13SStephen Hurd DBG_COUNTER_INC(tx_frees);
43314c7070dbSScott Long m = next;
43324c7070dbSScott Long }
43334c7070dbSScott Long return (ENOBUFS);
43344c7070dbSScott Long }
43354c7070dbSScott Long #endif
433623ac9029SStephen Hurd #ifdef notyet
43374c7070dbSScott Long qidx = count = 0;
43384c7070dbSScott Long mp = marr;
43394c7070dbSScott Long next = m;
43404c7070dbSScott Long do {
43414c7070dbSScott Long count++;
43424c7070dbSScott Long next = next->m_nextpkt;
43434c7070dbSScott Long } while (next != NULL);
43444c7070dbSScott Long
434516fb86abSConrad Meyer if (count > nitems(marr))
43464c7070dbSScott Long if ((mp = malloc(count * sizeof(struct mbuf *), M_IFLIB, M_NOWAIT)) == NULL) {
43474c7070dbSScott Long /* XXX check nextpkt */
43484c7070dbSScott Long m_freem(m);
43494c7070dbSScott Long /* XXX simplify for now */
43504c7070dbSScott Long DBG_COUNTER_INC(tx_frees);
43514c7070dbSScott Long return (ENOBUFS);
43524c7070dbSScott Long }
43534c7070dbSScott Long for (next = m, i = 0; next != NULL; i++) {
43544c7070dbSScott Long mp[i] = next;
43554c7070dbSScott Long next = next->m_nextpkt;
43564c7070dbSScott Long mp[i]->m_nextpkt = NULL;
43574c7070dbSScott Long }
435823ac9029SStephen Hurd #endif
43594c7070dbSScott Long DBG_COUNTER_INC(tx_seen);
43609c950139SEric Joyner abdicate = ctx->ifc_sysctl_tx_abdicate;
43619c950139SEric Joyner
4362fe51d4cdSStephen Hurd err = ifmp_ring_enqueue(txq->ift_br, (void **)&m, 1, TX_BATCH_SIZE, abdicate);
43634c7070dbSScott Long
4364fe51d4cdSStephen Hurd if (abdicate)
4365ab2e3f79SStephen Hurd GROUPTASK_ENQUEUE(&txq->ift_task);
43661225d9daSStephen Hurd if (err) {
4367fe51d4cdSStephen Hurd if (!abdicate)
4368fe51d4cdSStephen Hurd GROUPTASK_ENQUEUE(&txq->ift_task);
43694c7070dbSScott Long /* support forthcoming later */
43704c7070dbSScott Long #ifdef DRIVER_BACKPRESSURE
43714c7070dbSScott Long txq->ift_closed = TRUE;
43724c7070dbSScott Long #endif
437395246abbSSean Bruno ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
437423ac9029SStephen Hurd m_freem(m);
437564e6fc13SStephen Hurd DBG_COUNTER_INC(tx_frees);
43764c7070dbSScott Long }
43774c7070dbSScott Long
43784c7070dbSScott Long return (err);
43794c7070dbSScott Long }
43804c7070dbSScott Long
4381b8ca4756SPatrick Kelsey #ifdef ALTQ
4382b8ca4756SPatrick Kelsey /*
4383b8ca4756SPatrick Kelsey * The overall approach to integrating iflib with ALTQ is to continue to use
4384b8ca4756SPatrick Kelsey * the iflib mp_ring machinery between the ALTQ queue(s) and the hardware
4385b8ca4756SPatrick Kelsey * ring. Technically, when using ALTQ, queueing to an intermediate mp_ring
4386b8ca4756SPatrick Kelsey * is redundant/unnecessary, but doing so minimizes the amount of
4387b8ca4756SPatrick Kelsey * ALTQ-specific code required in iflib. It is assumed that the overhead of
4388b8ca4756SPatrick Kelsey * redundantly queueing to an intermediate mp_ring is swamped by the
4389b8ca4756SPatrick Kelsey * performance limitations inherent in using ALTQ.
4390b8ca4756SPatrick Kelsey *
4391b8ca4756SPatrick Kelsey * When ALTQ support is compiled in, all iflib drivers will use a transmit
4392b8ca4756SPatrick Kelsey * routine, iflib_altq_if_transmit(), that checks if ALTQ is enabled for the
4393b8ca4756SPatrick Kelsey * given interface. If ALTQ is enabled for an interface, then all
4394b8ca4756SPatrick Kelsey * transmitted packets for that interface will be submitted to the ALTQ
4395b8ca4756SPatrick Kelsey * subsystem via IFQ_ENQUEUE(). We don't use the legacy if_transmit()
4396b8ca4756SPatrick Kelsey * implementation because it uses IFQ_HANDOFF(), which will duplicatively
4397b8ca4756SPatrick Kelsey * update stats that the iflib machinery handles, and which is sensitve to
4398b8ca4756SPatrick Kelsey * the disused IFF_DRV_OACTIVE flag. Additionally, iflib_altq_if_start()
4399b8ca4756SPatrick Kelsey * will be installed as the start routine for use by ALTQ facilities that
4400b8ca4756SPatrick Kelsey * need to trigger queue drains on a scheduled basis.
4401b8ca4756SPatrick Kelsey *
4402b8ca4756SPatrick Kelsey */
4403b8ca4756SPatrick Kelsey static void
iflib_altq_if_start(if_t ifp)4404b8ca4756SPatrick Kelsey iflib_altq_if_start(if_t ifp)
4405b8ca4756SPatrick Kelsey {
4406402810d3SJustin Hibbits struct ifaltq *ifq = &ifp->if_snd; /* XXX - DRVAPI */
4407b8ca4756SPatrick Kelsey struct mbuf *m;
4408b8ca4756SPatrick Kelsey
4409b8ca4756SPatrick Kelsey IFQ_LOCK(ifq);
4410b8ca4756SPatrick Kelsey IFQ_DEQUEUE_NOLOCK(ifq, m);
4411b8ca4756SPatrick Kelsey while (m != NULL) {
4412b8ca4756SPatrick Kelsey iflib_if_transmit(ifp, m);
4413b8ca4756SPatrick Kelsey IFQ_DEQUEUE_NOLOCK(ifq, m);
4414b8ca4756SPatrick Kelsey }
4415b8ca4756SPatrick Kelsey IFQ_UNLOCK(ifq);
4416b8ca4756SPatrick Kelsey }
4417b8ca4756SPatrick Kelsey
4418b8ca4756SPatrick Kelsey static int
iflib_altq_if_transmit(if_t ifp,struct mbuf * m)4419b8ca4756SPatrick Kelsey iflib_altq_if_transmit(if_t ifp, struct mbuf *m)
4420b8ca4756SPatrick Kelsey {
4421b8ca4756SPatrick Kelsey int err;
4422b8ca4756SPatrick Kelsey
442325c92cd2SJustin Hibbits if (if_altq_is_enabled(ifp)) {
4424402810d3SJustin Hibbits IFQ_ENQUEUE(&ifp->if_snd, m, err); /* XXX - DRVAPI */
4425b8ca4756SPatrick Kelsey if (err == 0)
4426b8ca4756SPatrick Kelsey iflib_altq_if_start(ifp);
4427b8ca4756SPatrick Kelsey } else
4428b8ca4756SPatrick Kelsey err = iflib_if_transmit(ifp, m);
4429b8ca4756SPatrick Kelsey
4430b8ca4756SPatrick Kelsey return (err);
4431b8ca4756SPatrick Kelsey }
4432b8ca4756SPatrick Kelsey #endif /* ALTQ */
4433b8ca4756SPatrick Kelsey
44344c7070dbSScott Long static void
iflib_if_qflush(if_t ifp)44354c7070dbSScott Long iflib_if_qflush(if_t ifp)
44364c7070dbSScott Long {
44374c7070dbSScott Long if_ctx_t ctx = if_getsoftc(ifp);
44384c7070dbSScott Long iflib_txq_t txq = ctx->ifc_txqs;
44394c7070dbSScott Long int i;
44404c7070dbSScott Long
44417b610b60SSean Bruno STATE_LOCK(ctx);
44424c7070dbSScott Long ctx->ifc_flags |= IFC_QFLUSH;
44437b610b60SSean Bruno STATE_UNLOCK(ctx);
44444c7070dbSScott Long for (i = 0; i < NTXQSETS(ctx); i++, txq++)
444595246abbSSean Bruno while (!(ifmp_ring_is_idle(txq->ift_br) || ifmp_ring_is_stalled(txq->ift_br)))
44464c7070dbSScott Long iflib_txq_check_drain(txq, 0);
44477b610b60SSean Bruno STATE_LOCK(ctx);
44484c7070dbSScott Long ctx->ifc_flags &= ~IFC_QFLUSH;
44497b610b60SSean Bruno STATE_UNLOCK(ctx);
44504c7070dbSScott Long
4451b8ca4756SPatrick Kelsey /*
4452b8ca4756SPatrick Kelsey * When ALTQ is enabled, this will also take care of purging the
4453b8ca4756SPatrick Kelsey * ALTQ queue(s).
4454b8ca4756SPatrick Kelsey */
44554c7070dbSScott Long if_qflush(ifp);
44564c7070dbSScott Long }
44574c7070dbSScott Long
44580c919c23SStephen Hurd #define IFCAP_FLAGS (IFCAP_HWCSUM_IPV6 | IFCAP_HWCSUM | IFCAP_LRO | \
44590c919c23SStephen Hurd IFCAP_TSO | IFCAP_VLAN_HWTAGGING | IFCAP_HWSTATS | \
44600c919c23SStephen Hurd IFCAP_VLAN_MTU | IFCAP_VLAN_HWFILTER | \
44613f43ada9SGleb Smirnoff IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM | IFCAP_MEXTPG)
44624c7070dbSScott Long
44634c7070dbSScott Long static int
iflib_if_ioctl(if_t ifp,u_long command,caddr_t data)44644c7070dbSScott Long iflib_if_ioctl(if_t ifp, u_long command, caddr_t data)
44654c7070dbSScott Long {
44664c7070dbSScott Long if_ctx_t ctx = if_getsoftc(ifp);
44674c7070dbSScott Long struct ifreq *ifr = (struct ifreq *)data;
44684c7070dbSScott Long #if defined(INET) || defined(INET6)
44694c7070dbSScott Long struct ifaddr *ifa = (struct ifaddr *)data;
44704c7070dbSScott Long #endif
44711722eeacSMarius Strobl bool avoid_reset = false;
44724c7070dbSScott Long int err = 0, reinit = 0, bits;
44734c7070dbSScott Long
44744c7070dbSScott Long switch (command) {
44754c7070dbSScott Long case SIOCSIFADDR:
44764c7070dbSScott Long #ifdef INET
44774c7070dbSScott Long if (ifa->ifa_addr->sa_family == AF_INET)
44781722eeacSMarius Strobl avoid_reset = true;
44794c7070dbSScott Long #endif
44804c7070dbSScott Long #ifdef INET6
44814c7070dbSScott Long if (ifa->ifa_addr->sa_family == AF_INET6)
44821722eeacSMarius Strobl avoid_reset = true;
44834c7070dbSScott Long #endif
44844c7070dbSScott Long /*
4485fa7045f9SZhenlei Huang * Calling init results in link renegotiation,
4486fa7045f9SZhenlei Huang * so we avoid doing it when possible.
44874c7070dbSScott Long */
44884c7070dbSScott Long if (avoid_reset) {
44894c7070dbSScott Long if_setflagbits(ifp, IFF_UP, 0);
44904c7070dbSScott Long if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
44914c7070dbSScott Long reinit = 1;
44924c7070dbSScott Long #ifdef INET
44934c7070dbSScott Long if (!(if_getflags(ifp) & IFF_NOARP))
44944c7070dbSScott Long arp_ifinit(ifp, ifa);
44954c7070dbSScott Long #endif
44964c7070dbSScott Long } else
44974c7070dbSScott Long err = ether_ioctl(ifp, command, data);
44984c7070dbSScott Long break;
44994c7070dbSScott Long case SIOCSIFMTU:
45004c7070dbSScott Long CTX_LOCK(ctx);
45014c7070dbSScott Long if (ifr->ifr_mtu == if_getmtu(ifp)) {
45024c7070dbSScott Long CTX_UNLOCK(ctx);
45034c7070dbSScott Long break;
45044c7070dbSScott Long }
45054c7070dbSScott Long bits = if_getdrvflags(ifp);
45064c7070dbSScott Long /* stop the driver and free any clusters before proceeding */
45074c7070dbSScott Long iflib_stop(ctx);
45084c7070dbSScott Long
45094c7070dbSScott Long if ((err = IFDI_MTU_SET(ctx, ifr->ifr_mtu)) == 0) {
45107b610b60SSean Bruno STATE_LOCK(ctx);
45114c7070dbSScott Long if (ifr->ifr_mtu > ctx->ifc_max_fl_buf_size)
45124c7070dbSScott Long ctx->ifc_flags |= IFC_MULTISEG;
45134c7070dbSScott Long else
45144c7070dbSScott Long ctx->ifc_flags &= ~IFC_MULTISEG;
45157b610b60SSean Bruno STATE_UNLOCK(ctx);
45164c7070dbSScott Long err = if_setmtu(ifp, ifr->ifr_mtu);
45174c7070dbSScott Long }
45184c7070dbSScott Long iflib_init_locked(ctx);
45197b610b60SSean Bruno STATE_LOCK(ctx);
45204c7070dbSScott Long if_setdrvflags(ifp, bits);
45217b610b60SSean Bruno STATE_UNLOCK(ctx);
45224c7070dbSScott Long CTX_UNLOCK(ctx);
45234c7070dbSScott Long break;
45244c7070dbSScott Long case SIOCSIFFLAGS:
4525ab2e3f79SStephen Hurd CTX_LOCK(ctx);
4526ab2e3f79SStephen Hurd if (if_getflags(ifp) & IFF_UP) {
4527ab2e3f79SStephen Hurd if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4528ab2e3f79SStephen Hurd if ((if_getflags(ifp) ^ ctx->ifc_if_flags) &
4529ab2e3f79SStephen Hurd (IFF_PROMISC | IFF_ALLMULTI)) {
45300ae0e8d2SMatt Macy CTX_UNLOCK(ctx);
4531ab2e3f79SStephen Hurd err = IFDI_PROMISC_SET(ctx, if_getflags(ifp));
45320ae0e8d2SMatt Macy CTX_LOCK(ctx);
4533ab2e3f79SStephen Hurd }
4534ab2e3f79SStephen Hurd } else
4535ab2e3f79SStephen Hurd reinit = 1;
4536ab2e3f79SStephen Hurd } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4537ab2e3f79SStephen Hurd iflib_stop(ctx);
4538ab2e3f79SStephen Hurd }
4539ab2e3f79SStephen Hurd ctx->ifc_if_flags = if_getflags(ifp);
4540ab2e3f79SStephen Hurd CTX_UNLOCK(ctx);
45414c7070dbSScott Long break;
45424c7070dbSScott Long case SIOCADDMULTI:
45434c7070dbSScott Long case SIOCDELMULTI:
45444c7070dbSScott Long if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4545ab2e3f79SStephen Hurd CTX_LOCK(ctx);
4546ab2e3f79SStephen Hurd IFDI_INTR_DISABLE(ctx);
4547ab2e3f79SStephen Hurd IFDI_MULTI_SET(ctx);
4548ab2e3f79SStephen Hurd IFDI_INTR_ENABLE(ctx);
4549ab2e3f79SStephen Hurd CTX_UNLOCK(ctx);
45504c7070dbSScott Long }
45514c7070dbSScott Long break;
45524c7070dbSScott Long case SIOCSIFMEDIA:
45534c7070dbSScott Long CTX_LOCK(ctx);
45544c7070dbSScott Long IFDI_MEDIA_SET(ctx);
45554c7070dbSScott Long CTX_UNLOCK(ctx);
45561722eeacSMarius Strobl /* FALLTHROUGH */
45574c7070dbSScott Long case SIOCGIFMEDIA:
4558a027c8e9SStephen Hurd case SIOCGIFXMEDIA:
4559e2621d96SMatt Macy err = ifmedia_ioctl(ifp, ifr, ctx->ifc_mediap, command);
45604c7070dbSScott Long break;
45614c7070dbSScott Long case SIOCGI2C:
45624c7070dbSScott Long {
45634c7070dbSScott Long struct ifi2creq i2c;
45644c7070dbSScott Long
4565541d96aaSBrooks Davis err = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c));
45664c7070dbSScott Long if (err != 0)
45674c7070dbSScott Long break;
45684c7070dbSScott Long if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) {
45694c7070dbSScott Long err = EINVAL;
45704c7070dbSScott Long break;
45714c7070dbSScott Long }
45724c7070dbSScott Long if (i2c.len > sizeof(i2c.data)) {
45734c7070dbSScott Long err = EINVAL;
45744c7070dbSScott Long break;
45754c7070dbSScott Long }
45764c7070dbSScott Long
45774c7070dbSScott Long if ((err = IFDI_I2C_REQ(ctx, &i2c)) == 0)
4578541d96aaSBrooks Davis err = copyout(&i2c, ifr_data_get_ptr(ifr),
4579541d96aaSBrooks Davis sizeof(i2c));
45804c7070dbSScott Long break;
45814c7070dbSScott Long }
45824c7070dbSScott Long case SIOCSIFCAP:
45834c7070dbSScott Long {
45840c919c23SStephen Hurd int mask, setmask, oldmask;
45854c7070dbSScott Long
45860c919c23SStephen Hurd oldmask = if_getcapenable(ifp);
45870c919c23SStephen Hurd mask = ifr->ifr_reqcap ^ oldmask;
45883f43ada9SGleb Smirnoff mask &= ctx->ifc_softc_ctx.isc_capabilities | IFCAP_MEXTPG;
45894c7070dbSScott Long setmask = 0;
45904c7070dbSScott Long #ifdef TCP_OFFLOAD
45914c7070dbSScott Long setmask |= mask & (IFCAP_TOE4 | IFCAP_TOE6);
45924c7070dbSScott Long #endif
45934c7070dbSScott Long setmask |= (mask & IFCAP_FLAGS);
45940c919c23SStephen Hurd setmask |= (mask & IFCAP_WOL);
45954c7070dbSScott Long
45960c919c23SStephen Hurd /*
4597a42546dfSStephen Hurd * If any RX csum has changed, change all the ones that
4598a42546dfSStephen Hurd * are supported by the driver.
45990c919c23SStephen Hurd */
4600a42546dfSStephen Hurd if (setmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) {
4601a42546dfSStephen Hurd setmask |= ctx->ifc_softc_ctx.isc_capabilities &
4602a42546dfSStephen Hurd (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6);
4603a42546dfSStephen Hurd }
46040c919c23SStephen Hurd
46054c7070dbSScott Long /*
46064c7070dbSScott Long * want to ensure that traffic has stopped before we change any of the flags
46074c7070dbSScott Long */
46084c7070dbSScott Long if (setmask) {
46094c7070dbSScott Long CTX_LOCK(ctx);
46104c7070dbSScott Long bits = if_getdrvflags(ifp);
46110c919c23SStephen Hurd if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL)
46124c7070dbSScott Long iflib_stop(ctx);
46137b610b60SSean Bruno STATE_LOCK(ctx);
46144c7070dbSScott Long if_togglecapenable(ifp, setmask);
46154561c4f0SVincenzo Maffione ctx->ifc_softc_ctx.isc_capenable ^= setmask;
46167b610b60SSean Bruno STATE_UNLOCK(ctx);
46170c919c23SStephen Hurd if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL)
46184c7070dbSScott Long iflib_init_locked(ctx);
46197b610b60SSean Bruno STATE_LOCK(ctx);
46204c7070dbSScott Long if_setdrvflags(ifp, bits);
46217b610b60SSean Bruno STATE_UNLOCK(ctx);
46224c7070dbSScott Long CTX_UNLOCK(ctx);
46234c7070dbSScott Long }
46240c919c23SStephen Hurd if_vlancap(ifp);
46254c7070dbSScott Long break;
46264c7070dbSScott Long }
46274c7070dbSScott Long case SIOCGPRIVATE_0:
46284c7070dbSScott Long case SIOCSDRVSPEC:
46294c7070dbSScott Long case SIOCGDRVSPEC:
46304c7070dbSScott Long CTX_LOCK(ctx);
46314c7070dbSScott Long err = IFDI_PRIV_IOCTL(ctx, command, data);
46324c7070dbSScott Long CTX_UNLOCK(ctx);
46334c7070dbSScott Long break;
46344c7070dbSScott Long default:
46354c7070dbSScott Long err = ether_ioctl(ifp, command, data);
46364c7070dbSScott Long break;
46374c7070dbSScott Long }
46384c7070dbSScott Long if (reinit)
46394c7070dbSScott Long iflib_if_init(ctx);
46404c7070dbSScott Long return (err);
46414c7070dbSScott Long }
46424c7070dbSScott Long
46434c7070dbSScott Long static uint64_t
iflib_if_get_counter(if_t ifp,ift_counter cnt)46444c7070dbSScott Long iflib_if_get_counter(if_t ifp, ift_counter cnt)
46454c7070dbSScott Long {
46464c7070dbSScott Long if_ctx_t ctx = if_getsoftc(ifp);
46474c7070dbSScott Long
46484c7070dbSScott Long return (IFDI_GET_COUNTER(ctx, cnt));
46494c7070dbSScott Long }
46504c7070dbSScott Long
46514c7070dbSScott Long /*********************************************************************
46524c7070dbSScott Long *
46534c7070dbSScott Long * OTHER FUNCTIONS EXPORTED TO THE STACK
46544c7070dbSScott Long *
46554c7070dbSScott Long **********************************************************************/
46564c7070dbSScott Long
46574c7070dbSScott Long static void
iflib_vlan_register(void * arg,if_t ifp,uint16_t vtag)46584c7070dbSScott Long iflib_vlan_register(void *arg, if_t ifp, uint16_t vtag)
46594c7070dbSScott Long {
46604c7070dbSScott Long if_ctx_t ctx = if_getsoftc(ifp);
46614c7070dbSScott Long
46624c7070dbSScott Long if ((void *)ctx != arg)
46634c7070dbSScott Long return;
46644c7070dbSScott Long
46654c7070dbSScott Long if ((vtag == 0) || (vtag > 4095))
46664c7070dbSScott Long return;
46674c7070dbSScott Long
466853b5b9b0SEric Joyner if (iflib_in_detach(ctx))
466953b5b9b0SEric Joyner return;
467053b5b9b0SEric Joyner
46714c7070dbSScott Long CTX_LOCK(ctx);
467245818bf1SEric Joyner /* Driver may need all untagged packets to be flushed */
467345818bf1SEric Joyner if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
467445818bf1SEric Joyner iflib_stop(ctx);
46754c7070dbSScott Long IFDI_VLAN_REGISTER(ctx, vtag);
467645818bf1SEric Joyner /* Re-init to load the changes, if required */
467745818bf1SEric Joyner if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
467845818bf1SEric Joyner iflib_init_locked(ctx);
46794c7070dbSScott Long CTX_UNLOCK(ctx);
46804c7070dbSScott Long }
46814c7070dbSScott Long
46824c7070dbSScott Long static void
iflib_vlan_unregister(void * arg,if_t ifp,uint16_t vtag)46834c7070dbSScott Long iflib_vlan_unregister(void *arg, if_t ifp, uint16_t vtag)
46844c7070dbSScott Long {
46854c7070dbSScott Long if_ctx_t ctx = if_getsoftc(ifp);
46864c7070dbSScott Long
46874c7070dbSScott Long if ((void *)ctx != arg)
46884c7070dbSScott Long return;
46894c7070dbSScott Long
46904c7070dbSScott Long if ((vtag == 0) || (vtag > 4095))
46914c7070dbSScott Long return;
46924c7070dbSScott Long
46934c7070dbSScott Long CTX_LOCK(ctx);
469445818bf1SEric Joyner /* Driver may need all tagged packets to be flushed */
469545818bf1SEric Joyner if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
469645818bf1SEric Joyner iflib_stop(ctx);
46974c7070dbSScott Long IFDI_VLAN_UNREGISTER(ctx, vtag);
469845818bf1SEric Joyner /* Re-init to load the changes, if required */
469945818bf1SEric Joyner if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
470045818bf1SEric Joyner iflib_init_locked(ctx);
47014c7070dbSScott Long CTX_UNLOCK(ctx);
47024c7070dbSScott Long }
47034c7070dbSScott Long
47044c7070dbSScott Long static void
iflib_led_func(void * arg,int onoff)47054c7070dbSScott Long iflib_led_func(void *arg, int onoff)
47064c7070dbSScott Long {
47074c7070dbSScott Long if_ctx_t ctx = arg;
47084c7070dbSScott Long
47094c7070dbSScott Long CTX_LOCK(ctx);
47104c7070dbSScott Long IFDI_LED_FUNC(ctx, onoff);
47114c7070dbSScott Long CTX_UNLOCK(ctx);
47124c7070dbSScott Long }
47134c7070dbSScott Long
47144c7070dbSScott Long /*********************************************************************
47154c7070dbSScott Long *
47164c7070dbSScott Long * BUS FUNCTION DEFINITIONS
47174c7070dbSScott Long *
47184c7070dbSScott Long **********************************************************************/
47194c7070dbSScott Long
47204c7070dbSScott Long int
iflib_device_probe(device_t dev)47214c7070dbSScott Long iflib_device_probe(device_t dev)
47224c7070dbSScott Long {
4723d49e83eaSMarius Strobl const pci_vendor_info_t *ent;
47244c7070dbSScott Long if_shared_ctx_t sctx;
4725d49e83eaSMarius Strobl uint16_t pci_device_id, pci_rev_id, pci_subdevice_id, pci_subvendor_id;
4726d49e83eaSMarius Strobl uint16_t pci_vendor_id;
47274c7070dbSScott Long
47284c7070dbSScott Long if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC)
47294c7070dbSScott Long return (ENOTSUP);
47304c7070dbSScott Long
47314c7070dbSScott Long pci_vendor_id = pci_get_vendor(dev);
47324c7070dbSScott Long pci_device_id = pci_get_device(dev);
47334c7070dbSScott Long pci_subvendor_id = pci_get_subvendor(dev);
47344c7070dbSScott Long pci_subdevice_id = pci_get_subdevice(dev);
47354c7070dbSScott Long pci_rev_id = pci_get_revid(dev);
47364c7070dbSScott Long if (sctx->isc_parse_devinfo != NULL)
47374c7070dbSScott Long sctx->isc_parse_devinfo(&pci_device_id, &pci_subvendor_id, &pci_subdevice_id, &pci_rev_id);
47384c7070dbSScott Long
47394c7070dbSScott Long ent = sctx->isc_vendor_info;
47404c7070dbSScott Long while (ent->pvi_vendor_id != 0) {
47414c7070dbSScott Long if (pci_vendor_id != ent->pvi_vendor_id) {
47424c7070dbSScott Long ent++;
47434c7070dbSScott Long continue;
47444c7070dbSScott Long }
47454c7070dbSScott Long if ((pci_device_id == ent->pvi_device_id) &&
47464c7070dbSScott Long ((pci_subvendor_id == ent->pvi_subvendor_id) ||
47474c7070dbSScott Long (ent->pvi_subvendor_id == 0)) &&
47484c7070dbSScott Long ((pci_subdevice_id == ent->pvi_subdevice_id) ||
47494c7070dbSScott Long (ent->pvi_subdevice_id == 0)) &&
47504c7070dbSScott Long ((pci_rev_id == ent->pvi_rev_id) ||
47514c7070dbSScott Long (ent->pvi_rev_id == 0))) {
47524c7070dbSScott Long device_set_desc_copy(dev, ent->pvi_name);
47534c7070dbSScott Long /* this needs to be changed to zero if the bus probing code
47544c7070dbSScott Long * ever stops re-probing on best match because the sctx
47554c7070dbSScott Long * may have its values over written by register calls
47564c7070dbSScott Long * in subsequent probes
47574c7070dbSScott Long */
47584c7070dbSScott Long return (BUS_PROBE_DEFAULT);
47594c7070dbSScott Long }
47604c7070dbSScott Long ent++;
47614c7070dbSScott Long }
47624c7070dbSScott Long return (ENXIO);
47634c7070dbSScott Long }
47644c7070dbSScott Long
4765668d6dbbSEric Joyner int
iflib_device_probe_vendor(device_t dev)4766668d6dbbSEric Joyner iflib_device_probe_vendor(device_t dev)
4767668d6dbbSEric Joyner {
4768668d6dbbSEric Joyner int probe;
4769668d6dbbSEric Joyner
4770668d6dbbSEric Joyner probe = iflib_device_probe(dev);
4771668d6dbbSEric Joyner if (probe == BUS_PROBE_DEFAULT)
4772668d6dbbSEric Joyner return (BUS_PROBE_VENDOR);
4773668d6dbbSEric Joyner else
4774668d6dbbSEric Joyner return (probe);
4775668d6dbbSEric Joyner }
4776668d6dbbSEric Joyner
477709f6ff4fSMatt Macy static void
iflib_reset_qvalues(if_ctx_t ctx)477809f6ff4fSMatt Macy iflib_reset_qvalues(if_ctx_t ctx)
47794c7070dbSScott Long {
478009f6ff4fSMatt Macy if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
478109f6ff4fSMatt Macy if_shared_ctx_t sctx = ctx->ifc_sctx;
478209f6ff4fSMatt Macy device_t dev = ctx->ifc_dev;
478346d0f824SMatt Macy int i;
47844c7070dbSScott Long
478523ac9029SStephen Hurd if (ctx->ifc_sysctl_ntxqs != 0)
478623ac9029SStephen Hurd scctx->isc_ntxqsets = ctx->ifc_sysctl_ntxqs;
478723ac9029SStephen Hurd if (ctx->ifc_sysctl_nrxqs != 0)
478823ac9029SStephen Hurd scctx->isc_nrxqsets = ctx->ifc_sysctl_nrxqs;
478923ac9029SStephen Hurd
479023ac9029SStephen Hurd for (i = 0; i < sctx->isc_ntxqs; i++) {
479123ac9029SStephen Hurd if (ctx->ifc_sysctl_ntxds[i] != 0)
479223ac9029SStephen Hurd scctx->isc_ntxd[i] = ctx->ifc_sysctl_ntxds[i];
479323ac9029SStephen Hurd else
479423ac9029SStephen Hurd scctx->isc_ntxd[i] = sctx->isc_ntxd_default[i];
479523ac9029SStephen Hurd }
479623ac9029SStephen Hurd
479723ac9029SStephen Hurd for (i = 0; i < sctx->isc_nrxqs; i++) {
479823ac9029SStephen Hurd if (ctx->ifc_sysctl_nrxds[i] != 0)
479923ac9029SStephen Hurd scctx->isc_nrxd[i] = ctx->ifc_sysctl_nrxds[i];
480023ac9029SStephen Hurd else
480123ac9029SStephen Hurd scctx->isc_nrxd[i] = sctx->isc_nrxd_default[i];
480223ac9029SStephen Hurd }
480323ac9029SStephen Hurd
480423ac9029SStephen Hurd for (i = 0; i < sctx->isc_nrxqs; i++) {
480523ac9029SStephen Hurd if (scctx->isc_nrxd[i] < sctx->isc_nrxd_min[i]) {
480623ac9029SStephen Hurd device_printf(dev, "nrxd%d: %d less than nrxd_min %d - resetting to min\n",
480723ac9029SStephen Hurd i, scctx->isc_nrxd[i], sctx->isc_nrxd_min[i]);
480823ac9029SStephen Hurd scctx->isc_nrxd[i] = sctx->isc_nrxd_min[i];
480923ac9029SStephen Hurd }
481023ac9029SStephen Hurd if (scctx->isc_nrxd[i] > sctx->isc_nrxd_max[i]) {
481123ac9029SStephen Hurd device_printf(dev, "nrxd%d: %d greater than nrxd_max %d - resetting to max\n",
481223ac9029SStephen Hurd i, scctx->isc_nrxd[i], sctx->isc_nrxd_max[i]);
481323ac9029SStephen Hurd scctx->isc_nrxd[i] = sctx->isc_nrxd_max[i];
481423ac9029SStephen Hurd }
4815afb77372SEric Joyner if (!powerof2(scctx->isc_nrxd[i])) {
4816afb77372SEric Joyner device_printf(dev, "nrxd%d: %d is not a power of 2 - using default value of %d\n",
4817afb77372SEric Joyner i, scctx->isc_nrxd[i], sctx->isc_nrxd_default[i]);
4818afb77372SEric Joyner scctx->isc_nrxd[i] = sctx->isc_nrxd_default[i];
4819afb77372SEric Joyner }
482023ac9029SStephen Hurd }
482123ac9029SStephen Hurd
482223ac9029SStephen Hurd for (i = 0; i < sctx->isc_ntxqs; i++) {
482323ac9029SStephen Hurd if (scctx->isc_ntxd[i] < sctx->isc_ntxd_min[i]) {
482423ac9029SStephen Hurd device_printf(dev, "ntxd%d: %d less than ntxd_min %d - resetting to min\n",
482523ac9029SStephen Hurd i, scctx->isc_ntxd[i], sctx->isc_ntxd_min[i]);
482623ac9029SStephen Hurd scctx->isc_ntxd[i] = sctx->isc_ntxd_min[i];
482723ac9029SStephen Hurd }
482823ac9029SStephen Hurd if (scctx->isc_ntxd[i] > sctx->isc_ntxd_max[i]) {
482923ac9029SStephen Hurd device_printf(dev, "ntxd%d: %d greater than ntxd_max %d - resetting to max\n",
483023ac9029SStephen Hurd i, scctx->isc_ntxd[i], sctx->isc_ntxd_max[i]);
483123ac9029SStephen Hurd scctx->isc_ntxd[i] = sctx->isc_ntxd_max[i];
483223ac9029SStephen Hurd }
4833afb77372SEric Joyner if (!powerof2(scctx->isc_ntxd[i])) {
4834afb77372SEric Joyner device_printf(dev, "ntxd%d: %d is not a power of 2 - using default value of %d\n",
4835afb77372SEric Joyner i, scctx->isc_ntxd[i], sctx->isc_ntxd_default[i]);
4836afb77372SEric Joyner scctx->isc_ntxd[i] = sctx->isc_ntxd_default[i];
4837afb77372SEric Joyner }
483823ac9029SStephen Hurd }
483909f6ff4fSMatt Macy }
4840ab2e3f79SStephen Hurd
48416d49b41eSAndrew Gallatin static void
iflib_add_pfil(if_ctx_t ctx)48426d49b41eSAndrew Gallatin iflib_add_pfil(if_ctx_t ctx)
48436d49b41eSAndrew Gallatin {
48446d49b41eSAndrew Gallatin struct pfil_head *pfil;
48456d49b41eSAndrew Gallatin struct pfil_head_args pa;
48466d49b41eSAndrew Gallatin iflib_rxq_t rxq;
48476d49b41eSAndrew Gallatin int i;
48486d49b41eSAndrew Gallatin
48496d49b41eSAndrew Gallatin pa.pa_version = PFIL_VERSION;
48506d49b41eSAndrew Gallatin pa.pa_flags = PFIL_IN;
48516d49b41eSAndrew Gallatin pa.pa_type = PFIL_TYPE_ETHERNET;
4852402810d3SJustin Hibbits pa.pa_headname = if_name(ctx->ifc_ifp);
48536d49b41eSAndrew Gallatin pfil = pfil_head_register(&pa);
48546d49b41eSAndrew Gallatin
48556d49b41eSAndrew Gallatin for (i = 0, rxq = ctx->ifc_rxqs; i < NRXQSETS(ctx); i++, rxq++) {
48566d49b41eSAndrew Gallatin rxq->pfil = pfil;
48576d49b41eSAndrew Gallatin }
48586d49b41eSAndrew Gallatin }
48596d49b41eSAndrew Gallatin
48606d49b41eSAndrew Gallatin static void
iflib_rem_pfil(if_ctx_t ctx)48616d49b41eSAndrew Gallatin iflib_rem_pfil(if_ctx_t ctx)
48626d49b41eSAndrew Gallatin {
48636d49b41eSAndrew Gallatin struct pfil_head *pfil;
48646d49b41eSAndrew Gallatin iflib_rxq_t rxq;
48656d49b41eSAndrew Gallatin int i;
48666d49b41eSAndrew Gallatin
48676d49b41eSAndrew Gallatin rxq = ctx->ifc_rxqs;
48686d49b41eSAndrew Gallatin pfil = rxq->pfil;
48696d49b41eSAndrew Gallatin for (i = 0; i < NRXQSETS(ctx); i++, rxq++) {
48706d49b41eSAndrew Gallatin rxq->pfil = NULL;
48716d49b41eSAndrew Gallatin }
48726d49b41eSAndrew Gallatin pfil_head_unregister(pfil);
48736d49b41eSAndrew Gallatin }
48746d49b41eSAndrew Gallatin
4875ca7005f1SPatrick Kelsey
4876ca7005f1SPatrick Kelsey /*
4877ca7005f1SPatrick Kelsey * Advance forward by n members of the cpuset ctx->ifc_cpus starting from
4878ca7005f1SPatrick Kelsey * cpuid and wrapping as necessary.
4879ca7005f1SPatrick Kelsey */
4880ca7005f1SPatrick Kelsey static unsigned int
cpuid_advance(if_ctx_t ctx,unsigned int cpuid,unsigned int n)4881ca7005f1SPatrick Kelsey cpuid_advance(if_ctx_t ctx, unsigned int cpuid, unsigned int n)
4882ca7005f1SPatrick Kelsey {
4883ca7005f1SPatrick Kelsey unsigned int first_valid;
4884ca7005f1SPatrick Kelsey unsigned int last_valid;
4885ca7005f1SPatrick Kelsey
4886ca7005f1SPatrick Kelsey /* cpuid should always be in the valid set */
4887ca7005f1SPatrick Kelsey MPASS(CPU_ISSET(cpuid, &ctx->ifc_cpus));
4888ca7005f1SPatrick Kelsey
4889ca7005f1SPatrick Kelsey /* valid set should never be empty */
4890ca7005f1SPatrick Kelsey MPASS(!CPU_EMPTY(&ctx->ifc_cpus));
4891ca7005f1SPatrick Kelsey
4892ca7005f1SPatrick Kelsey first_valid = CPU_FFS(&ctx->ifc_cpus) - 1;
4893ca7005f1SPatrick Kelsey last_valid = CPU_FLS(&ctx->ifc_cpus) - 1;
4894ca7005f1SPatrick Kelsey n = n % CPU_COUNT(&ctx->ifc_cpus);
4895ca7005f1SPatrick Kelsey while (n > 0) {
4896ca7005f1SPatrick Kelsey do {
4897ca7005f1SPatrick Kelsey cpuid++;
4898ca7005f1SPatrick Kelsey if (cpuid > last_valid)
4899ca7005f1SPatrick Kelsey cpuid = first_valid;
4900ca7005f1SPatrick Kelsey } while (!CPU_ISSET(cpuid, &ctx->ifc_cpus));
4901ca7005f1SPatrick Kelsey n--;
4902ca7005f1SPatrick Kelsey }
4903ca7005f1SPatrick Kelsey
4904ca7005f1SPatrick Kelsey return (cpuid);
4905ca7005f1SPatrick Kelsey }
4906ca7005f1SPatrick Kelsey
4907ca7005f1SPatrick Kelsey #if defined(SMP) && defined(SCHED_ULE)
4908ca7005f1SPatrick Kelsey extern struct cpu_group *cpu_top; /* CPU topology */
4909ca7005f1SPatrick Kelsey
4910ca7005f1SPatrick Kelsey static int
find_child_with_core(int cpu,struct cpu_group * grp)4911ca7005f1SPatrick Kelsey find_child_with_core(int cpu, struct cpu_group *grp)
4912ca7005f1SPatrick Kelsey {
4913ca7005f1SPatrick Kelsey int i;
4914ca7005f1SPatrick Kelsey
4915ca7005f1SPatrick Kelsey if (grp->cg_children == 0)
4916fa7045f9SZhenlei Huang return (-1);
4917ca7005f1SPatrick Kelsey
4918ca7005f1SPatrick Kelsey MPASS(grp->cg_child);
4919ca7005f1SPatrick Kelsey for (i = 0; i < grp->cg_children; i++) {
4920ca7005f1SPatrick Kelsey if (CPU_ISSET(cpu, &grp->cg_child[i].cg_mask))
4921fa7045f9SZhenlei Huang return (i);
4922ca7005f1SPatrick Kelsey }
4923ca7005f1SPatrick Kelsey
4924fa7045f9SZhenlei Huang return (-1);
4925ca7005f1SPatrick Kelsey }
4926ca7005f1SPatrick Kelsey
4927ca7005f1SPatrick Kelsey
4928ca7005f1SPatrick Kelsey /*
4929ca7005f1SPatrick Kelsey * Find an L2 neighbor of the given CPU or return -1 if none found. This
4930ca7005f1SPatrick Kelsey * does not distinguish among multiple L2 neighbors if the given CPU has
4931ca7005f1SPatrick Kelsey * more than one (it will always return the same result in that case).
4932ca7005f1SPatrick Kelsey */
4933ca7005f1SPatrick Kelsey static int
find_l2_neighbor(int cpu)4934ca7005f1SPatrick Kelsey find_l2_neighbor(int cpu)
4935ca7005f1SPatrick Kelsey {
4936ca7005f1SPatrick Kelsey struct cpu_group *grp;
4937ca7005f1SPatrick Kelsey int i;
4938ca7005f1SPatrick Kelsey
4939ca7005f1SPatrick Kelsey grp = cpu_top;
4940ca7005f1SPatrick Kelsey if (grp == NULL)
4941fa7045f9SZhenlei Huang return (-1);
4942ca7005f1SPatrick Kelsey
4943ca7005f1SPatrick Kelsey /*
4944ca7005f1SPatrick Kelsey * Find the smallest CPU group that contains the given core.
4945ca7005f1SPatrick Kelsey */
4946ca7005f1SPatrick Kelsey i = 0;
4947ca7005f1SPatrick Kelsey while ((i = find_child_with_core(cpu, grp)) != -1) {
4948ca7005f1SPatrick Kelsey /*
4949ca7005f1SPatrick Kelsey * If the smallest group containing the given CPU has less
4950ca7005f1SPatrick Kelsey * than two members, we conclude the given CPU has no
4951ca7005f1SPatrick Kelsey * L2 neighbor.
4952ca7005f1SPatrick Kelsey */
4953ca7005f1SPatrick Kelsey if (grp->cg_child[i].cg_count <= 1)
4954ca7005f1SPatrick Kelsey return (-1);
4955ca7005f1SPatrick Kelsey grp = &grp->cg_child[i];
4956ca7005f1SPatrick Kelsey }
4957ca7005f1SPatrick Kelsey
4958ca7005f1SPatrick Kelsey /* Must share L2. */
4959ca7005f1SPatrick Kelsey if (grp->cg_level > CG_SHARE_L2 || grp->cg_level == CG_SHARE_NONE)
4960fa7045f9SZhenlei Huang return (-1);
4961ca7005f1SPatrick Kelsey
4962ca7005f1SPatrick Kelsey /*
4963ca7005f1SPatrick Kelsey * Select the first member of the set that isn't the reference
4964ca7005f1SPatrick Kelsey * CPU, which at this point is guaranteed to exist.
4965ca7005f1SPatrick Kelsey */
4966ca7005f1SPatrick Kelsey for (i = 0; i < CPU_SETSIZE; i++) {
4967ca7005f1SPatrick Kelsey if (CPU_ISSET(i, &grp->cg_mask) && i != cpu)
4968ca7005f1SPatrick Kelsey return (i);
4969ca7005f1SPatrick Kelsey }
4970ca7005f1SPatrick Kelsey
4971ca7005f1SPatrick Kelsey /* Should never be reached */
4972ca7005f1SPatrick Kelsey return (-1);
4973ca7005f1SPatrick Kelsey }
4974ca7005f1SPatrick Kelsey
4975ca7005f1SPatrick Kelsey #else
4976ca7005f1SPatrick Kelsey static int
find_l2_neighbor(int cpu)4977ca7005f1SPatrick Kelsey find_l2_neighbor(int cpu)
4978ca7005f1SPatrick Kelsey {
4979ca7005f1SPatrick Kelsey
4980ca7005f1SPatrick Kelsey return (-1);
4981ca7005f1SPatrick Kelsey }
4982ca7005f1SPatrick Kelsey #endif
4983ca7005f1SPatrick Kelsey
4984ca7005f1SPatrick Kelsey /*
4985ca7005f1SPatrick Kelsey * CPU mapping behaviors
4986ca7005f1SPatrick Kelsey * ---------------------
4987ca7005f1SPatrick Kelsey * 'separate txrx' refers to the separate_txrx sysctl
4988ca7005f1SPatrick Kelsey * 'use logical' refers to the use_logical_cores sysctl
4989ca7005f1SPatrick Kelsey * 'INTR CPUS' indicates whether bus_get_cpus(INTR_CPUS) succeeded
4990ca7005f1SPatrick Kelsey *
4991ca7005f1SPatrick Kelsey * separate use INTR
4992ca7005f1SPatrick Kelsey * txrx logical CPUS result
4993ca7005f1SPatrick Kelsey * ---------- --------- ------ ------------------------------------------------
4994ca7005f1SPatrick Kelsey * - - X RX and TX queues mapped to consecutive physical
4995ca7005f1SPatrick Kelsey * cores with RX/TX pairs on same core and excess
4996ca7005f1SPatrick Kelsey * of either following
4997ca7005f1SPatrick Kelsey * - X X RX and TX queues mapped to consecutive cores
4998ca7005f1SPatrick Kelsey * of any type with RX/TX pairs on same core and
4999ca7005f1SPatrick Kelsey * excess of either following
5000ca7005f1SPatrick Kelsey * X - X RX and TX queues mapped to consecutive physical
5001ca7005f1SPatrick Kelsey * cores; all RX then all TX
5002ca7005f1SPatrick Kelsey * X X X RX queues mapped to consecutive physical cores
5003ca7005f1SPatrick Kelsey * first, then TX queues mapped to L2 neighbor of
5004ca7005f1SPatrick Kelsey * the corresponding RX queue if one exists,
5005ca7005f1SPatrick Kelsey * otherwise to consecutive physical cores
5006ca7005f1SPatrick Kelsey * - n/a - RX and TX queues mapped to consecutive cores of
5007ca7005f1SPatrick Kelsey * any type with RX/TX pairs on same core and excess
5008ca7005f1SPatrick Kelsey * of either following
5009ca7005f1SPatrick Kelsey * X n/a - RX and TX queues mapped to consecutive cores of
5010ca7005f1SPatrick Kelsey * any type; all RX then all TX
5011ca7005f1SPatrick Kelsey */
5012ca7005f1SPatrick Kelsey static unsigned int
get_cpuid_for_queue(if_ctx_t ctx,unsigned int base_cpuid,unsigned int qid,bool is_tx)5013ca7005f1SPatrick Kelsey get_cpuid_for_queue(if_ctx_t ctx, unsigned int base_cpuid, unsigned int qid,
5014ca7005f1SPatrick Kelsey bool is_tx)
5015ca7005f1SPatrick Kelsey {
5016ca7005f1SPatrick Kelsey if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
5017ca7005f1SPatrick Kelsey unsigned int core_index;
5018ca7005f1SPatrick Kelsey
5019ca7005f1SPatrick Kelsey if (ctx->ifc_sysctl_separate_txrx) {
5020ca7005f1SPatrick Kelsey /*
5021ca7005f1SPatrick Kelsey * When using separate CPUs for TX and RX, the assignment
5022ca7005f1SPatrick Kelsey * will always be of a consecutive CPU out of the set of
5023ca7005f1SPatrick Kelsey * context CPUs, except for the specific case where the
5024ca7005f1SPatrick Kelsey * context CPUs are phsyical cores, the use of logical cores
5025ca7005f1SPatrick Kelsey * has been enabled, the assignment is for TX, the TX qid
5026ca7005f1SPatrick Kelsey * corresponds to an RX qid, and the CPU assigned to the
5027ca7005f1SPatrick Kelsey * corresponding RX queue has an L2 neighbor.
5028ca7005f1SPatrick Kelsey */
5029ca7005f1SPatrick Kelsey if (ctx->ifc_sysctl_use_logical_cores &&
5030ca7005f1SPatrick Kelsey ctx->ifc_cpus_are_physical_cores &&
5031ca7005f1SPatrick Kelsey is_tx && qid < scctx->isc_nrxqsets) {
5032ca7005f1SPatrick Kelsey int l2_neighbor;
5033ca7005f1SPatrick Kelsey unsigned int rx_cpuid;
5034ca7005f1SPatrick Kelsey
5035ca7005f1SPatrick Kelsey rx_cpuid = cpuid_advance(ctx, base_cpuid, qid);
5036ca7005f1SPatrick Kelsey l2_neighbor = find_l2_neighbor(rx_cpuid);
5037ca7005f1SPatrick Kelsey if (l2_neighbor != -1) {
5038ca7005f1SPatrick Kelsey return (l2_neighbor);
5039ca7005f1SPatrick Kelsey }
5040ca7005f1SPatrick Kelsey /*
5041ca7005f1SPatrick Kelsey * ... else fall through to the normal
5042ca7005f1SPatrick Kelsey * consecutive-after-RX assignment scheme.
5043ca7005f1SPatrick Kelsey *
5044ca7005f1SPatrick Kelsey * Note that we are assuming that all RX queue CPUs
5045ca7005f1SPatrick Kelsey * have an L2 neighbor, or all do not. If a mixed
5046ca7005f1SPatrick Kelsey * scenario is possible, we will have to keep track
5047ca7005f1SPatrick Kelsey * separately of how many queues prior to this one
5048ca7005f1SPatrick Kelsey * were not able to be assigned to an L2 neighbor.
5049ca7005f1SPatrick Kelsey */
5050ca7005f1SPatrick Kelsey }
5051ca7005f1SPatrick Kelsey if (is_tx)
5052ca7005f1SPatrick Kelsey core_index = scctx->isc_nrxqsets + qid;
5053ca7005f1SPatrick Kelsey else
5054ca7005f1SPatrick Kelsey core_index = qid;
5055ca7005f1SPatrick Kelsey } else {
5056ca7005f1SPatrick Kelsey core_index = qid;
5057ca7005f1SPatrick Kelsey }
5058ca7005f1SPatrick Kelsey
5059ca7005f1SPatrick Kelsey return (cpuid_advance(ctx, base_cpuid, core_index));
5060ca7005f1SPatrick Kelsey }
5061ca7005f1SPatrick Kelsey
5062f154ece0SStephen Hurd static uint16_t
get_ctx_core_offset(if_ctx_t ctx)5063f154ece0SStephen Hurd get_ctx_core_offset(if_ctx_t ctx)
5064f154ece0SStephen Hurd {
5065f154ece0SStephen Hurd if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
5066f154ece0SStephen Hurd struct cpu_offset *op;
5067ca7005f1SPatrick Kelsey cpuset_t assigned_cpus;
5068ca7005f1SPatrick Kelsey unsigned int cores_consumed;
5069ca7005f1SPatrick Kelsey unsigned int base_cpuid = ctx->ifc_sysctl_core_offset;
5070ca7005f1SPatrick Kelsey unsigned int first_valid;
5071ca7005f1SPatrick Kelsey unsigned int last_valid;
5072ca7005f1SPatrick Kelsey unsigned int i;
5073f154ece0SStephen Hurd
5074ca7005f1SPatrick Kelsey first_valid = CPU_FFS(&ctx->ifc_cpus) - 1;
5075ca7005f1SPatrick Kelsey last_valid = CPU_FLS(&ctx->ifc_cpus) - 1;
5076f154ece0SStephen Hurd
5077ca7005f1SPatrick Kelsey if (base_cpuid != CORE_OFFSET_UNSPECIFIED) {
5078ca7005f1SPatrick Kelsey /*
5079ca7005f1SPatrick Kelsey * Align the user-chosen base CPU ID to the next valid CPU
5080ca7005f1SPatrick Kelsey * for this device. If the chosen base CPU ID is smaller
5081ca7005f1SPatrick Kelsey * than the first valid CPU or larger than the last valid
5082ca7005f1SPatrick Kelsey * CPU, we assume the user does not know what the valid
5083ca7005f1SPatrick Kelsey * range is for this device and is thinking in terms of a
5084ca7005f1SPatrick Kelsey * zero-based reference frame, and so we shift the given
5085ca7005f1SPatrick Kelsey * value into the valid range (and wrap accordingly) so the
5086ca7005f1SPatrick Kelsey * intent is translated to the proper frame of reference.
5087ca7005f1SPatrick Kelsey * If the base CPU ID is within the valid first/last, but
5088ca7005f1SPatrick Kelsey * does not correspond to a valid CPU, it is advanced to the
5089ca7005f1SPatrick Kelsey * next valid CPU (wrapping if necessary).
5090ca7005f1SPatrick Kelsey */
5091ca7005f1SPatrick Kelsey if (base_cpuid < first_valid || base_cpuid > last_valid) {
5092ca7005f1SPatrick Kelsey /* shift from zero-based to first_valid-based */
5093ca7005f1SPatrick Kelsey base_cpuid += first_valid;
5094ca7005f1SPatrick Kelsey /* wrap to range [first_valid, last_valid] */
5095ca7005f1SPatrick Kelsey base_cpuid = (base_cpuid - first_valid) %
5096ca7005f1SPatrick Kelsey (last_valid - first_valid + 1);
5097ca7005f1SPatrick Kelsey }
5098ca7005f1SPatrick Kelsey if (!CPU_ISSET(base_cpuid, &ctx->ifc_cpus)) {
5099ca7005f1SPatrick Kelsey /*
5100ca7005f1SPatrick Kelsey * base_cpuid is in [first_valid, last_valid], but
5101ca7005f1SPatrick Kelsey * not a member of the valid set. In this case,
5102ca7005f1SPatrick Kelsey * there will always be a member of the valid set
5103ca7005f1SPatrick Kelsey * with a CPU ID that is greater than base_cpuid,
5104ca7005f1SPatrick Kelsey * and we simply advance to it.
5105ca7005f1SPatrick Kelsey */
5106ca7005f1SPatrick Kelsey while (!CPU_ISSET(base_cpuid, &ctx->ifc_cpus))
5107ca7005f1SPatrick Kelsey base_cpuid++;
5108ca7005f1SPatrick Kelsey }
5109ca7005f1SPatrick Kelsey return (base_cpuid);
5110ca7005f1SPatrick Kelsey }
5111ca7005f1SPatrick Kelsey
5112ca7005f1SPatrick Kelsey /*
5113ca7005f1SPatrick Kelsey * Determine how many cores will be consumed by performing the CPU
5114ca7005f1SPatrick Kelsey * assignments and counting how many of the assigned CPUs correspond
5115ca7005f1SPatrick Kelsey * to CPUs in the set of context CPUs. This is done using the CPU
5116ca7005f1SPatrick Kelsey * ID first_valid as the base CPU ID, as the base CPU must be within
5117ca7005f1SPatrick Kelsey * the set of context CPUs.
5118ca7005f1SPatrick Kelsey *
5119ca7005f1SPatrick Kelsey * Note not all assigned CPUs will be in the set of context CPUs
5120ca7005f1SPatrick Kelsey * when separate CPUs are being allocated to TX and RX queues,
5121ca7005f1SPatrick Kelsey * assignment to logical cores has been enabled, the set of context
5122ca7005f1SPatrick Kelsey * CPUs contains only physical CPUs, and TX queues are mapped to L2
5123ca7005f1SPatrick Kelsey * neighbors of CPUs that RX queues have been mapped to - in this
5124ca7005f1SPatrick Kelsey * case we do only want to count how many CPUs in the set of context
5125ca7005f1SPatrick Kelsey * CPUs have been consumed, as that determines the next CPU in that
5126ca7005f1SPatrick Kelsey * set to start allocating at for the next device for which
5127ca7005f1SPatrick Kelsey * core_offset is not set.
5128ca7005f1SPatrick Kelsey */
5129ca7005f1SPatrick Kelsey CPU_ZERO(&assigned_cpus);
5130ca7005f1SPatrick Kelsey for (i = 0; i < scctx->isc_ntxqsets; i++)
5131ca7005f1SPatrick Kelsey CPU_SET(get_cpuid_for_queue(ctx, first_valid, i, true),
5132ca7005f1SPatrick Kelsey &assigned_cpus);
5133ca7005f1SPatrick Kelsey for (i = 0; i < scctx->isc_nrxqsets; i++)
5134ca7005f1SPatrick Kelsey CPU_SET(get_cpuid_for_queue(ctx, first_valid, i, false),
5135ca7005f1SPatrick Kelsey &assigned_cpus);
5136e2650af1SStefan Eßer CPU_AND(&assigned_cpus, &assigned_cpus, &ctx->ifc_cpus);
5137ca7005f1SPatrick Kelsey cores_consumed = CPU_COUNT(&assigned_cpus);
5138f154ece0SStephen Hurd
5139f154ece0SStephen Hurd mtx_lock(&cpu_offset_mtx);
5140f154ece0SStephen Hurd SLIST_FOREACH(op, &cpu_offsets, entries) {
5141f154ece0SStephen Hurd if (CPU_CMP(&ctx->ifc_cpus, &op->set) == 0) {
5142ca7005f1SPatrick Kelsey base_cpuid = op->next_cpuid;
5143ca7005f1SPatrick Kelsey op->next_cpuid = cpuid_advance(ctx, op->next_cpuid,
5144ca7005f1SPatrick Kelsey cores_consumed);
5145f154ece0SStephen Hurd MPASS(op->refcount < UINT_MAX);
5146f154ece0SStephen Hurd op->refcount++;
5147f154ece0SStephen Hurd break;
5148f154ece0SStephen Hurd }
5149f154ece0SStephen Hurd }
5150ca7005f1SPatrick Kelsey if (base_cpuid == CORE_OFFSET_UNSPECIFIED) {
5151ca7005f1SPatrick Kelsey base_cpuid = first_valid;
5152f154ece0SStephen Hurd op = malloc(sizeof(struct cpu_offset), M_IFLIB,
5153f154ece0SStephen Hurd M_NOWAIT | M_ZERO);
5154f154ece0SStephen Hurd if (op == NULL) {
5155f154ece0SStephen Hurd device_printf(ctx->ifc_dev,
5156f154ece0SStephen Hurd "allocation for cpu offset failed.\n");
5157f154ece0SStephen Hurd } else {
5158ca7005f1SPatrick Kelsey op->next_cpuid = cpuid_advance(ctx, base_cpuid,
5159ca7005f1SPatrick Kelsey cores_consumed);
5160f154ece0SStephen Hurd op->refcount = 1;
5161f154ece0SStephen Hurd CPU_COPY(&ctx->ifc_cpus, &op->set);
5162f154ece0SStephen Hurd SLIST_INSERT_HEAD(&cpu_offsets, op, entries);
5163f154ece0SStephen Hurd }
5164f154ece0SStephen Hurd }
5165f154ece0SStephen Hurd mtx_unlock(&cpu_offset_mtx);
5166f154ece0SStephen Hurd
5167ca7005f1SPatrick Kelsey return (base_cpuid);
5168f154ece0SStephen Hurd }
5169f154ece0SStephen Hurd
5170f154ece0SStephen Hurd static void
unref_ctx_core_offset(if_ctx_t ctx)5171f154ece0SStephen Hurd unref_ctx_core_offset(if_ctx_t ctx)
5172f154ece0SStephen Hurd {
5173f154ece0SStephen Hurd struct cpu_offset *op, *top;
5174f154ece0SStephen Hurd
5175f154ece0SStephen Hurd mtx_lock(&cpu_offset_mtx);
5176f154ece0SStephen Hurd SLIST_FOREACH_SAFE(op, &cpu_offsets, entries, top) {
5177f154ece0SStephen Hurd if (CPU_CMP(&ctx->ifc_cpus, &op->set) == 0) {
5178f154ece0SStephen Hurd MPASS(op->refcount > 0);
5179f154ece0SStephen Hurd op->refcount--;
5180f154ece0SStephen Hurd if (op->refcount == 0) {
5181f154ece0SStephen Hurd SLIST_REMOVE(&cpu_offsets, op, cpu_offset, entries);
5182f154ece0SStephen Hurd free(op, M_IFLIB);
5183f154ece0SStephen Hurd }
5184f154ece0SStephen Hurd break;
5185f154ece0SStephen Hurd }
5186f154ece0SStephen Hurd }
5187f154ece0SStephen Hurd mtx_unlock(&cpu_offset_mtx);
5188f154ece0SStephen Hurd }
5189f154ece0SStephen Hurd
519009f6ff4fSMatt Macy int
iflib_device_register(device_t dev,void * sc,if_shared_ctx_t sctx,if_ctx_t * ctxp)519109f6ff4fSMatt Macy iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ctxp)
519209f6ff4fSMatt Macy {
519309f6ff4fSMatt Macy if_ctx_t ctx;
519409f6ff4fSMatt Macy if_t ifp;
519509f6ff4fSMatt Macy if_softc_ctx_t scctx;
51963d10e9edSMarius Strobl kobjop_desc_t kobj_desc;
51973d10e9edSMarius Strobl kobj_method_t *kobj_method;
5198afb77372SEric Joyner int err, msix, rid;
5199ac11d857SVincenzo Maffione int num_txd, num_rxd;
520009f6ff4fSMatt Macy
520109f6ff4fSMatt Macy ctx = malloc(sizeof(*ctx), M_IFLIB, M_WAITOK | M_ZERO);
520209f6ff4fSMatt Macy
520309f6ff4fSMatt Macy if (sc == NULL) {
520409f6ff4fSMatt Macy sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK | M_ZERO);
520509f6ff4fSMatt Macy device_set_softc(dev, ctx);
520609f6ff4fSMatt Macy ctx->ifc_flags |= IFC_SC_ALLOCATED;
520709f6ff4fSMatt Macy }
520809f6ff4fSMatt Macy
520909f6ff4fSMatt Macy ctx->ifc_sctx = sctx;
521009f6ff4fSMatt Macy ctx->ifc_dev = dev;
521109f6ff4fSMatt Macy ctx->ifc_softc = sc;
521209f6ff4fSMatt Macy
521309f6ff4fSMatt Macy if ((err = iflib_register(ctx)) != 0) {
521409f6ff4fSMatt Macy device_printf(dev, "iflib_register failed %d\n", err);
52157f3eb9daSPatrick Kelsey goto fail_ctx_free;
521609f6ff4fSMatt Macy }
521709f6ff4fSMatt Macy iflib_add_device_sysctl_pre(ctx);
521809f6ff4fSMatt Macy
521909f6ff4fSMatt Macy scctx = &ctx->ifc_softc_ctx;
522009f6ff4fSMatt Macy ifp = ctx->ifc_ifp;
522109f6ff4fSMatt Macy
522209f6ff4fSMatt Macy iflib_reset_qvalues(ctx);
5223e0e12405SVincenzo Maffione IFNET_WLOCK();
5224aa8a24d3SStephen Hurd CTX_LOCK(ctx);
5225ab2e3f79SStephen Hurd if ((err = IFDI_ATTACH_PRE(ctx)) != 0) {
52264c7070dbSScott Long device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err);
52277f3eb9daSPatrick Kelsey goto fail_unlock;
52284c7070dbSScott Long }
52291248952aSSean Bruno _iflib_pre_assert(scctx);
52301248952aSSean Bruno ctx->ifc_txrx = *scctx->isc_txrx;
52311248952aSSean Bruno
5232ef567155SMarcin Wojtas MPASS(scctx->isc_dma_width <= flsll(BUS_SPACE_MAXADDR));
52336dd69f00SMarcin Wojtas
5234e2621d96SMatt Macy if (sctx->isc_flags & IFLIB_DRIVER_MEDIA)
5235e2621d96SMatt Macy ctx->ifc_mediap = scctx->isc_media;
5236e2621d96SMatt Macy
52371248952aSSean Bruno #ifdef INVARIANTS
52387f87c040SMarius Strobl if (scctx->isc_capabilities & IFCAP_TXCSUM)
52391248952aSSean Bruno MPASS(scctx->isc_tx_csum_flags);
52401248952aSSean Bruno #endif
52411248952aSSean Bruno
52426554362cSAndrew Gallatin if_setcapabilities(ifp,
52433f43ada9SGleb Smirnoff scctx->isc_capabilities | IFCAP_HWSTATS | IFCAP_MEXTPG);
52446554362cSAndrew Gallatin if_setcapenable(ifp,
52453f43ada9SGleb Smirnoff scctx->isc_capenable | IFCAP_HWSTATS | IFCAP_MEXTPG);
52461248952aSSean Bruno
52471248952aSSean Bruno if (scctx->isc_ntxqsets == 0 || (scctx->isc_ntxqsets_max && scctx->isc_ntxqsets_max < scctx->isc_ntxqsets))
52481248952aSSean Bruno scctx->isc_ntxqsets = scctx->isc_ntxqsets_max;
52491248952aSSean Bruno if (scctx->isc_nrxqsets == 0 || (scctx->isc_nrxqsets_max && scctx->isc_nrxqsets_max < scctx->isc_nrxqsets))
52501248952aSSean Bruno scctx->isc_nrxqsets = scctx->isc_nrxqsets_max;
525123ac9029SStephen Hurd
5252ac11d857SVincenzo Maffione num_txd = iflib_num_tx_descs(ctx);
5253ac11d857SVincenzo Maffione num_rxd = iflib_num_rx_descs(ctx);
525423ac9029SStephen Hurd
525523ac9029SStephen Hurd /* XXX change for per-queue sizes */
52561722eeacSMarius Strobl device_printf(dev, "Using %d TX descriptors and %d RX descriptors\n",
5257ac11d857SVincenzo Maffione num_txd, num_rxd);
525823ac9029SStephen Hurd
5259ac11d857SVincenzo Maffione if (scctx->isc_tx_nsegments > num_txd / MAX_SINGLE_PACKET_FRACTION)
5260ac11d857SVincenzo Maffione scctx->isc_tx_nsegments = max(1, num_txd /
526123ac9029SStephen Hurd MAX_SINGLE_PACKET_FRACTION);
5262ac11d857SVincenzo Maffione if (scctx->isc_tx_tso_segments_max > num_txd /
526323ac9029SStephen Hurd MAX_SINGLE_PACKET_FRACTION)
526423ac9029SStephen Hurd scctx->isc_tx_tso_segments_max = max(1,
5265ac11d857SVincenzo Maffione num_txd / MAX_SINGLE_PACKET_FRACTION);
52664c7070dbSScott Long
52674c7070dbSScott Long /* TSO parameters - dig these out of the data sheet - simply correspond to tag setup */
52687f87c040SMarius Strobl if (if_getcapabilities(ifp) & IFCAP_TSO) {
52697f87c040SMarius Strobl /*
52707f87c040SMarius Strobl * The stack can't handle a TSO size larger than IP_MAXPACKET,
52717f87c040SMarius Strobl * but some MACs do.
52727f87c040SMarius Strobl */
52737f87c040SMarius Strobl if_sethwtsomax(ifp, min(scctx->isc_tx_tso_size_max,
52747f87c040SMarius Strobl IP_MAXPACKET));
52757f87c040SMarius Strobl /*
52767f87c040SMarius Strobl * Take maximum number of m_pullup(9)'s in iflib_parse_header()
52777f87c040SMarius Strobl * into account. In the worst case, each of these calls will
52787f87c040SMarius Strobl * add another mbuf and, thus, the requirement for another DMA
52797f87c040SMarius Strobl * segment. So for best performance, it doesn't make sense to
52807f87c040SMarius Strobl * advertize a maximum of TSO segments that typically will
52817f87c040SMarius Strobl * require defragmentation in iflib_encap().
52827f87c040SMarius Strobl */
52837f87c040SMarius Strobl if_sethwtsomaxsegcount(ifp, scctx->isc_tx_tso_segments_max - 3);
52847f87c040SMarius Strobl if_sethwtsomaxsegsize(ifp, scctx->isc_tx_tso_segsize_max);
52857f87c040SMarius Strobl }
52864c7070dbSScott Long if (scctx->isc_rss_table_size == 0)
52874c7070dbSScott Long scctx->isc_rss_table_size = 64;
528823ac9029SStephen Hurd scctx->isc_rss_table_mask = scctx->isc_rss_table_size - 1;
5289da69b8f9SSean Bruno
5290da69b8f9SSean Bruno GROUPTASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
5291da69b8f9SSean Bruno /* XXX format name */
5292f855ec81SMarius Strobl taskqgroup_attach(qgroup_if_config_tqg, &ctx->ifc_admin_task, ctx,
5293f855ec81SMarius Strobl NULL, NULL, "admin");
5294e516b535SStephen Hurd
5295772593dbSStephen Hurd /* Set up cpu set. If it fails, use the set of all CPUs. */
5296e516b535SStephen Hurd if (bus_get_cpus(dev, INTR_CPUS, sizeof(ctx->ifc_cpus), &ctx->ifc_cpus) != 0) {
5297e516b535SStephen Hurd device_printf(dev, "Unable to fetch CPU list\n");
5298e516b535SStephen Hurd CPU_COPY(&all_cpus, &ctx->ifc_cpus);
5299ca7005f1SPatrick Kelsey ctx->ifc_cpus_are_physical_cores = false;
5300ca7005f1SPatrick Kelsey } else
5301ca7005f1SPatrick Kelsey ctx->ifc_cpus_are_physical_cores = true;
5302e516b535SStephen Hurd MPASS(CPU_COUNT(&ctx->ifc_cpus) > 0);
5303e516b535SStephen Hurd
53044c7070dbSScott Long /*
5305fa7045f9SZhenlei Huang * Now set up MSI or MSI-X, should return us the number of supported
5306fa7045f9SZhenlei Huang * vectors (will be 1 for a legacy interrupt and MSI).
53074c7070dbSScott Long */
53084c7070dbSScott Long if (sctx->isc_flags & IFLIB_SKIP_MSIX) {
53094c7070dbSScott Long msix = scctx->isc_vectors;
53104c7070dbSScott Long } else if (scctx->isc_msix_bar != 0)
5311f7ae9a84SSean Bruno /*
5312f7ae9a84SSean Bruno * The simple fact that isc_msix_bar is not 0 does not mean we
5313f7ae9a84SSean Bruno * we have a good value there that is known to work.
5314f7ae9a84SSean Bruno */
53154c7070dbSScott Long msix = iflib_msix_init(ctx);
53164c7070dbSScott Long else {
53174c7070dbSScott Long scctx->isc_vectors = 1;
53184c7070dbSScott Long scctx->isc_ntxqsets = 1;
53194c7070dbSScott Long scctx->isc_nrxqsets = 1;
53204c7070dbSScott Long scctx->isc_intr = IFLIB_INTR_LEGACY;
53214c7070dbSScott Long msix = 0;
53224c7070dbSScott Long }
53234c7070dbSScott Long /* Get memory for the station queues */
53244c7070dbSScott Long if ((err = iflib_queues_alloc(ctx))) {
53254c7070dbSScott Long device_printf(dev, "Unable to allocate queue memory\n");
53267f3eb9daSPatrick Kelsey goto fail_intr_free;
53274c7070dbSScott Long }
53284c7070dbSScott Long
5329ac88e6daSStephen Hurd if ((err = iflib_qset_structures_setup(ctx)))
53304c7070dbSScott Long goto fail_queues;
533169b7fc3eSSean Bruno
5332bd84f700SSean Bruno /*
5333f154ece0SStephen Hurd * Now that we know how many queues there are, get the core offset.
5334f154ece0SStephen Hurd */
5335f154ece0SStephen Hurd ctx->ifc_sysctl_core_offset = get_ctx_core_offset(ctx);
5336f154ece0SStephen Hurd
53373d10e9edSMarius Strobl if (msix > 1) {
53383d10e9edSMarius Strobl /*
53393d10e9edSMarius Strobl * When using MSI-X, ensure that ifdi_{r,t}x_queue_intr_enable
53403d10e9edSMarius Strobl * aren't the default NULL implementation.
53413d10e9edSMarius Strobl */
53423d10e9edSMarius Strobl kobj_desc = &ifdi_rx_queue_intr_enable_desc;
53433d10e9edSMarius Strobl kobj_method = kobj_lookup_method(((kobj_t)ctx)->ops->cls, NULL,
53443d10e9edSMarius Strobl kobj_desc);
53453d10e9edSMarius Strobl if (kobj_method == &kobj_desc->deflt) {
53463d10e9edSMarius Strobl device_printf(dev,
53473d10e9edSMarius Strobl "MSI-X requires ifdi_rx_queue_intr_enable method");
53483d10e9edSMarius Strobl err = EOPNOTSUPP;
53497f3eb9daSPatrick Kelsey goto fail_queues;
53504c7070dbSScott Long }
53513d10e9edSMarius Strobl kobj_desc = &ifdi_tx_queue_intr_enable_desc;
53523d10e9edSMarius Strobl kobj_method = kobj_lookup_method(((kobj_t)ctx)->ops->cls, NULL,
53533d10e9edSMarius Strobl kobj_desc);
53543d10e9edSMarius Strobl if (kobj_method == &kobj_desc->deflt) {
53553d10e9edSMarius Strobl device_printf(dev,
53563d10e9edSMarius Strobl "MSI-X requires ifdi_tx_queue_intr_enable method");
53573d10e9edSMarius Strobl err = EOPNOTSUPP;
53583d10e9edSMarius Strobl goto fail_queues;
53593d10e9edSMarius Strobl }
53603d10e9edSMarius Strobl
53613d10e9edSMarius Strobl /*
53623d10e9edSMarius Strobl * Assign the MSI-X vectors.
53633d10e9edSMarius Strobl * Note that the default NULL ifdi_msix_intr_assign method will
53643d10e9edSMarius Strobl * fail here, too.
53653d10e9edSMarius Strobl */
53663d10e9edSMarius Strobl err = IFDI_MSIX_INTR_ASSIGN(ctx, msix);
53673d10e9edSMarius Strobl if (err != 0) {
53683d10e9edSMarius Strobl device_printf(dev, "IFDI_MSIX_INTR_ASSIGN failed %d\n",
53693d10e9edSMarius Strobl err);
53703d10e9edSMarius Strobl goto fail_queues;
53713d10e9edSMarius Strobl }
5372197c6798SEric Joyner } else if (scctx->isc_intr != IFLIB_INTR_MSIX) {
53734c7070dbSScott Long rid = 0;
53744c7070dbSScott Long if (scctx->isc_intr == IFLIB_INTR_MSI) {
53754c7070dbSScott Long MPASS(msix == 1);
53764c7070dbSScott Long rid = 1;
53774c7070dbSScott Long }
537823ac9029SStephen Hurd if ((err = iflib_legacy_setup(ctx, ctx->isc_legacy_intr, ctx->ifc_softc, &rid, "irq0")) != 0) {
53794c7070dbSScott Long device_printf(dev, "iflib_legacy_setup failed %d\n", err);
53807f3eb9daSPatrick Kelsey goto fail_queues;
53814c7070dbSScott Long }
5382197c6798SEric Joyner } else {
5383197c6798SEric Joyner device_printf(dev,
5384197c6798SEric Joyner "Cannot use iflib with only 1 MSI-X interrupt!\n");
5385197c6798SEric Joyner err = ENODEV;
538638bfc6deSSai Rajesh Tallamraju goto fail_queues;
53874c7070dbSScott Long }
53887f87c040SMarius Strobl
5389a52f23f4SEric Joyner /*
5390a52f23f4SEric Joyner * It prevents a double-locking panic with iflib_media_status when
5391a52f23f4SEric Joyner * the driver loads.
5392a52f23f4SEric Joyner */
5393a52f23f4SEric Joyner CTX_UNLOCK(ctx);
53941fd8c72cSKyle Evans ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet);
5395a52f23f4SEric Joyner CTX_LOCK(ctx);
53967f87c040SMarius Strobl
5397ab2e3f79SStephen Hurd if ((err = IFDI_ATTACH_POST(ctx)) != 0) {
53984c7070dbSScott Long device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
53994c7070dbSScott Long goto fail_detach;
54004c7070dbSScott Long }
54017f87c040SMarius Strobl
54027f87c040SMarius Strobl /*
54037f87c040SMarius Strobl * Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.
54047f87c040SMarius Strobl * This must appear after the call to ether_ifattach() because
54057f87c040SMarius Strobl * ether_ifattach() sets if_hdrlen to the default value.
54067f87c040SMarius Strobl */
54077f87c040SMarius Strobl if (if_getcapabilities(ifp) & IFCAP_VLAN_MTU)
54087f87c040SMarius Strobl if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
54097f87c040SMarius Strobl
54104c7070dbSScott Long if ((err = iflib_netmap_attach(ctx))) {
54114c7070dbSScott Long device_printf(ctx->ifc_dev, "netmap attach failed: %d\n", err);
54124c7070dbSScott Long goto fail_detach;
54134c7070dbSScott Long }
54144c7070dbSScott Long *ctxp = ctx;
54154c7070dbSScott Long
54167790c8c1SConrad Meyer DEBUGNET_SET(ctx->ifc_ifp, iflib);
541794618825SMark Johnston
541823ac9029SStephen Hurd if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
54194c7070dbSScott Long iflib_add_device_sysctl_post(ctx);
54206d49b41eSAndrew Gallatin iflib_add_pfil(ctx);
54214ecb427aSSean Bruno ctx->ifc_flags |= IFC_INIT_DONE;
5422aa8a24d3SStephen Hurd CTX_UNLOCK(ctx);
5423e0e12405SVincenzo Maffione IFNET_WUNLOCK();
54243d10e9edSMarius Strobl
54254c7070dbSScott Long return (0);
542677c1fcecSEric Joyner
54274c7070dbSScott Long fail_detach:
54284c7070dbSScott Long ether_ifdetach(ctx->ifc_ifp);
54294c7070dbSScott Long fail_queues:
543038bfc6deSSai Rajesh Tallamraju iflib_tqg_detach(ctx);
54316108c013SStephen Hurd iflib_tx_structures_free(ctx);
54326108c013SStephen Hurd iflib_rx_structures_free(ctx);
54334c7070dbSScott Long IFDI_DETACH(ctx);
543438bfc6deSSai Rajesh Tallamraju IFDI_QUEUES_FREE(ctx);
543538bfc6deSSai Rajesh Tallamraju fail_intr_free:
543638bfc6deSSai Rajesh Tallamraju iflib_free_intr_mem(ctx);
54377f3eb9daSPatrick Kelsey fail_unlock:
5438aa8a24d3SStephen Hurd CTX_UNLOCK(ctx);
5439e0e12405SVincenzo Maffione IFNET_WUNLOCK();
544056614414SEric Joyner iflib_deregister(ctx);
54417f3eb9daSPatrick Kelsey fail_ctx_free:
54427f3f6aadSEric Joyner device_set_softc(ctx->ifc_dev, NULL);
54437f3eb9daSPatrick Kelsey if (ctx->ifc_flags & IFC_SC_ALLOCATED)
54447f3eb9daSPatrick Kelsey free(ctx->ifc_softc, M_IFLIB);
54457f3eb9daSPatrick Kelsey free(ctx, M_IFLIB);
54464c7070dbSScott Long return (err);
54474c7070dbSScott Long }
54484c7070dbSScott Long
54494c7070dbSScott Long int
iflib_device_attach(device_t dev)54504c7070dbSScott Long iflib_device_attach(device_t dev)
54514c7070dbSScott Long {
54524c7070dbSScott Long if_ctx_t ctx;
54534c7070dbSScott Long if_shared_ctx_t sctx;
54544c7070dbSScott Long
54554c7070dbSScott Long if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC)
54564c7070dbSScott Long return (ENOTSUP);
54574c7070dbSScott Long
54584c7070dbSScott Long pci_enable_busmaster(dev);
54594c7070dbSScott Long
54604c7070dbSScott Long return (iflib_device_register(dev, NULL, sctx, &ctx));
54614c7070dbSScott Long }
54624c7070dbSScott Long
54634c7070dbSScott Long int
iflib_device_deregister(if_ctx_t ctx)54644c7070dbSScott Long iflib_device_deregister(if_ctx_t ctx)
54654c7070dbSScott Long {
54664c7070dbSScott Long if_t ifp = ctx->ifc_ifp;
54674c7070dbSScott Long device_t dev = ctx->ifc_dev;
54684c7070dbSScott Long
54694c7070dbSScott Long /* Make sure VLANS are not using driver */
54704c7070dbSScott Long if (if_vlantrunkinuse(ifp)) {
54714c7070dbSScott Long device_printf(dev, "Vlan in use, detach first\n");
54724c7070dbSScott Long return (EBUSY);
54734c7070dbSScott Long }
547477c1fcecSEric Joyner #ifdef PCI_IOV
547577c1fcecSEric Joyner if (!CTX_IS_VF(ctx) && pci_iov_detach(dev) != 0) {
547677c1fcecSEric Joyner device_printf(dev, "SR-IOV in use; detach first.\n");
547777c1fcecSEric Joyner return (EBUSY);
547877c1fcecSEric Joyner }
547977c1fcecSEric Joyner #endif
548077c1fcecSEric Joyner
548177c1fcecSEric Joyner STATE_LOCK(ctx);
548277c1fcecSEric Joyner ctx->ifc_flags |= IFC_IN_DETACH;
548377c1fcecSEric Joyner STATE_UNLOCK(ctx);
54844c7070dbSScott Long
54851558015eSEric Joyner /* Unregister VLAN handlers before calling iflib_stop() */
54861558015eSEric Joyner iflib_unregister_vlan_handlers(ctx);
54871558015eSEric Joyner
54881558015eSEric Joyner iflib_netmap_detach(ifp);
54891558015eSEric Joyner ether_ifdetach(ifp);
54901558015eSEric Joyner
54914c7070dbSScott Long CTX_LOCK(ctx);
54924c7070dbSScott Long iflib_stop(ctx);
54934c7070dbSScott Long CTX_UNLOCK(ctx);
54944c7070dbSScott Long
54956d49b41eSAndrew Gallatin iflib_rem_pfil(ctx);
54964c7070dbSScott Long if (ctx->ifc_led_dev != NULL)
54974c7070dbSScott Long led_destroy(ctx->ifc_led_dev);
549887890dbaSSean Bruno
549910254019SMark Johnston iflib_tqg_detach(ctx);
550038bfc6deSSai Rajesh Tallamraju iflib_tx_structures_free(ctx);
550138bfc6deSSai Rajesh Tallamraju iflib_rx_structures_free(ctx);
550238bfc6deSSai Rajesh Tallamraju
55036c3c3194SMatt Macy CTX_LOCK(ctx);
55044c7070dbSScott Long IFDI_DETACH(ctx);
550538bfc6deSSai Rajesh Tallamraju IFDI_QUEUES_FREE(ctx);
55066c3c3194SMatt Macy CTX_UNLOCK(ctx);
55076c3c3194SMatt Macy
55086c3c3194SMatt Macy /* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/
550977c1fcecSEric Joyner iflib_free_intr_mem(ctx);
551077c1fcecSEric Joyner
551177c1fcecSEric Joyner bus_generic_detach(dev);
551277c1fcecSEric Joyner
551356614414SEric Joyner iflib_deregister(ctx);
551456614414SEric Joyner
551556614414SEric Joyner device_set_softc(ctx->ifc_dev, NULL);
551677c1fcecSEric Joyner if (ctx->ifc_flags & IFC_SC_ALLOCATED)
551777c1fcecSEric Joyner free(ctx->ifc_softc, M_IFLIB);
5518f154ece0SStephen Hurd unref_ctx_core_offset(ctx);
551977c1fcecSEric Joyner free(ctx, M_IFLIB);
552077c1fcecSEric Joyner return (0);
552177c1fcecSEric Joyner }
552277c1fcecSEric Joyner
552377c1fcecSEric Joyner static void
iflib_tqg_detach(if_ctx_t ctx)552410254019SMark Johnston iflib_tqg_detach(if_ctx_t ctx)
552510254019SMark Johnston {
552610254019SMark Johnston iflib_txq_t txq;
552710254019SMark Johnston iflib_rxq_t rxq;
552810254019SMark Johnston int i;
552910254019SMark Johnston struct taskqgroup *tqg;
553010254019SMark Johnston
553110254019SMark Johnston /* XXX drain any dependent tasks */
553210254019SMark Johnston tqg = qgroup_if_io_tqg;
553310254019SMark Johnston for (txq = ctx->ifc_txqs, i = 0; i < NTXQSETS(ctx); i++, txq++) {
553410254019SMark Johnston callout_drain(&txq->ift_timer);
553510254019SMark Johnston #ifdef DEV_NETMAP
553610254019SMark Johnston callout_drain(&txq->ift_netmap_timer);
553710254019SMark Johnston #endif /* DEV_NETMAP */
553810254019SMark Johnston if (txq->ift_task.gt_uniq != NULL)
553910254019SMark Johnston taskqgroup_detach(tqg, &txq->ift_task);
554010254019SMark Johnston }
554110254019SMark Johnston for (i = 0, rxq = ctx->ifc_rxqs; i < NRXQSETS(ctx); i++, rxq++) {
554210254019SMark Johnston if (rxq->ifr_task.gt_uniq != NULL)
554310254019SMark Johnston taskqgroup_detach(tqg, &rxq->ifr_task);
554410254019SMark Johnston }
554510254019SMark Johnston tqg = qgroup_if_config_tqg;
554610254019SMark Johnston if (ctx->ifc_admin_task.gt_uniq != NULL)
554710254019SMark Johnston taskqgroup_detach(tqg, &ctx->ifc_admin_task);
554810254019SMark Johnston if (ctx->ifc_vflr_task.gt_uniq != NULL)
554910254019SMark Johnston taskqgroup_detach(tqg, &ctx->ifc_vflr_task);
555010254019SMark Johnston }
555110254019SMark Johnston
555210254019SMark Johnston static void
iflib_free_intr_mem(if_ctx_t ctx)555377c1fcecSEric Joyner iflib_free_intr_mem(if_ctx_t ctx)
555477c1fcecSEric Joyner {
555577c1fcecSEric Joyner
55564c7070dbSScott Long if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_MSIX) {
55574c7070dbSScott Long iflib_irq_free(ctx, &ctx->ifc_legacy_irq);
55584c7070dbSScott Long }
5559b97de13aSMarius Strobl if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_LEGACY) {
5560b97de13aSMarius Strobl pci_release_msi(ctx->ifc_dev);
5561b97de13aSMarius Strobl }
55624c7070dbSScott Long if (ctx->ifc_msix_mem != NULL) {
55634c7070dbSScott Long bus_release_resource(ctx->ifc_dev, SYS_RES_MEMORY,
5564b97de13aSMarius Strobl rman_get_rid(ctx->ifc_msix_mem), ctx->ifc_msix_mem);
55654c7070dbSScott Long ctx->ifc_msix_mem = NULL;
55664c7070dbSScott Long }
55674c7070dbSScott Long }
55684c7070dbSScott Long
55694c7070dbSScott Long int
iflib_device_detach(device_t dev)55704c7070dbSScott Long iflib_device_detach(device_t dev)
55714c7070dbSScott Long {
55724c7070dbSScott Long if_ctx_t ctx = device_get_softc(dev);
55734c7070dbSScott Long
55744c7070dbSScott Long return (iflib_device_deregister(ctx));
55754c7070dbSScott Long }
55764c7070dbSScott Long
55774c7070dbSScott Long int
iflib_device_suspend(device_t dev)55784c7070dbSScott Long iflib_device_suspend(device_t dev)
55794c7070dbSScott Long {
55804c7070dbSScott Long if_ctx_t ctx = device_get_softc(dev);
55814c7070dbSScott Long
55824c7070dbSScott Long CTX_LOCK(ctx);
55834c7070dbSScott Long IFDI_SUSPEND(ctx);
55844c7070dbSScott Long CTX_UNLOCK(ctx);
55854c7070dbSScott Long
5586fa7045f9SZhenlei Huang return (bus_generic_suspend(dev));
55874c7070dbSScott Long }
55884c7070dbSScott Long int
iflib_device_shutdown(device_t dev)55894c7070dbSScott Long iflib_device_shutdown(device_t dev)
55904c7070dbSScott Long {
55914c7070dbSScott Long if_ctx_t ctx = device_get_softc(dev);
55924c7070dbSScott Long
55934c7070dbSScott Long CTX_LOCK(ctx);
55944c7070dbSScott Long IFDI_SHUTDOWN(ctx);
55954c7070dbSScott Long CTX_UNLOCK(ctx);
55964c7070dbSScott Long
5597fa7045f9SZhenlei Huang return (bus_generic_suspend(dev));
55984c7070dbSScott Long }
55994c7070dbSScott Long
56004c7070dbSScott Long int
iflib_device_resume(device_t dev)56014c7070dbSScott Long iflib_device_resume(device_t dev)
56024c7070dbSScott Long {
56034c7070dbSScott Long if_ctx_t ctx = device_get_softc(dev);
56044c7070dbSScott Long iflib_txq_t txq = ctx->ifc_txqs;
56054c7070dbSScott Long
56064c7070dbSScott Long CTX_LOCK(ctx);
56074c7070dbSScott Long IFDI_RESUME(ctx);
5608cd28ea92SStephen Hurd iflib_if_init_locked(ctx);
56094c7070dbSScott Long CTX_UNLOCK(ctx);
56104c7070dbSScott Long for (int i = 0; i < NTXQSETS(ctx); i++, txq++)
56114c7070dbSScott Long iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET);
56124c7070dbSScott Long
56134c7070dbSScott Long return (bus_generic_resume(dev));
56144c7070dbSScott Long }
56154c7070dbSScott Long
56164c7070dbSScott Long int
iflib_device_iov_init(device_t dev,uint16_t num_vfs,const nvlist_t * params)56174c7070dbSScott Long iflib_device_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
56184c7070dbSScott Long {
56194c7070dbSScott Long int error;
56204c7070dbSScott Long if_ctx_t ctx = device_get_softc(dev);
56214c7070dbSScott Long
56224c7070dbSScott Long CTX_LOCK(ctx);
56234c7070dbSScott Long error = IFDI_IOV_INIT(ctx, num_vfs, params);
56244c7070dbSScott Long CTX_UNLOCK(ctx);
56254c7070dbSScott Long
56264c7070dbSScott Long return (error);
56274c7070dbSScott Long }
56284c7070dbSScott Long
56294c7070dbSScott Long void
iflib_device_iov_uninit(device_t dev)56304c7070dbSScott Long iflib_device_iov_uninit(device_t dev)
56314c7070dbSScott Long {
56324c7070dbSScott Long if_ctx_t ctx = device_get_softc(dev);
56334c7070dbSScott Long
56344c7070dbSScott Long CTX_LOCK(ctx);
56354c7070dbSScott Long IFDI_IOV_UNINIT(ctx);
56364c7070dbSScott Long CTX_UNLOCK(ctx);
56374c7070dbSScott Long }
56384c7070dbSScott Long
56394c7070dbSScott Long int
iflib_device_iov_add_vf(device_t dev,uint16_t vfnum,const nvlist_t * params)56404c7070dbSScott Long iflib_device_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
56414c7070dbSScott Long {
56424c7070dbSScott Long int error;
56434c7070dbSScott Long if_ctx_t ctx = device_get_softc(dev);
56444c7070dbSScott Long
56454c7070dbSScott Long CTX_LOCK(ctx);
56464c7070dbSScott Long error = IFDI_IOV_VF_ADD(ctx, vfnum, params);
56474c7070dbSScott Long CTX_UNLOCK(ctx);
56484c7070dbSScott Long
56494c7070dbSScott Long return (error);
56504c7070dbSScott Long }
56514c7070dbSScott Long
56524c7070dbSScott Long /*********************************************************************
56534c7070dbSScott Long *
56544c7070dbSScott Long * MODULE FUNCTION DEFINITIONS
56554c7070dbSScott Long *
56564c7070dbSScott Long **********************************************************************/
56574c7070dbSScott Long
5658ab2e3f79SStephen Hurd /*
5659ab2e3f79SStephen Hurd * - Start a fast taskqueue thread for each core
5660ab2e3f79SStephen Hurd * - Start a taskqueue for control operations
5661ab2e3f79SStephen Hurd */
56624c7070dbSScott Long static int
iflib_module_init(void)56634c7070dbSScott Long iflib_module_init(void)
56644c7070dbSScott Long {
5665618d49f5SAlexander Motin iflib_timer_default = hz / 2;
56664c7070dbSScott Long return (0);
56674c7070dbSScott Long }
56684c7070dbSScott Long
56694c7070dbSScott Long static int
iflib_module_event_handler(module_t mod,int what,void * arg)56704c7070dbSScott Long iflib_module_event_handler(module_t mod, int what, void *arg)
56714c7070dbSScott Long {
56724c7070dbSScott Long int err;
56734c7070dbSScott Long
56744c7070dbSScott Long switch (what) {
56754c7070dbSScott Long case MOD_LOAD:
56764c7070dbSScott Long if ((err = iflib_module_init()) != 0)
56774c7070dbSScott Long return (err);
56784c7070dbSScott Long break;
56794c7070dbSScott Long case MOD_UNLOAD:
56804c7070dbSScott Long return (EBUSY);
56814c7070dbSScott Long default:
56824c7070dbSScott Long return (EOPNOTSUPP);
56834c7070dbSScott Long }
56844c7070dbSScott Long
56854c7070dbSScott Long return (0);
56864c7070dbSScott Long }
56874c7070dbSScott Long
56884c7070dbSScott Long /*********************************************************************
56894c7070dbSScott Long *
56904c7070dbSScott Long * PUBLIC FUNCTION DEFINITIONS
56914c7070dbSScott Long * ordered as in iflib.h
56924c7070dbSScott Long *
56934c7070dbSScott Long **********************************************************************/
56944c7070dbSScott Long
56954c7070dbSScott Long static void
_iflib_assert(if_shared_ctx_t sctx)56964c7070dbSScott Long _iflib_assert(if_shared_ctx_t sctx)
56974c7070dbSScott Long {
5698afb77372SEric Joyner int i;
5699afb77372SEric Joyner
57004c7070dbSScott Long MPASS(sctx->isc_tx_maxsize);
57014c7070dbSScott Long MPASS(sctx->isc_tx_maxsegsize);
57024c7070dbSScott Long
57034c7070dbSScott Long MPASS(sctx->isc_rx_maxsize);
57044c7070dbSScott Long MPASS(sctx->isc_rx_nsegments);
57054c7070dbSScott Long MPASS(sctx->isc_rx_maxsegsize);
57064c7070dbSScott Long
5707afb77372SEric Joyner MPASS(sctx->isc_nrxqs >= 1 && sctx->isc_nrxqs <= 8);
5708afb77372SEric Joyner for (i = 0; i < sctx->isc_nrxqs; i++) {
5709afb77372SEric Joyner MPASS(sctx->isc_nrxd_min[i]);
5710afb77372SEric Joyner MPASS(powerof2(sctx->isc_nrxd_min[i]));
5711afb77372SEric Joyner MPASS(sctx->isc_nrxd_max[i]);
5712afb77372SEric Joyner MPASS(powerof2(sctx->isc_nrxd_max[i]));
5713afb77372SEric Joyner MPASS(sctx->isc_nrxd_default[i]);
5714afb77372SEric Joyner MPASS(powerof2(sctx->isc_nrxd_default[i]));
5715afb77372SEric Joyner }
5716afb77372SEric Joyner
5717afb77372SEric Joyner MPASS(sctx->isc_ntxqs >= 1 && sctx->isc_ntxqs <= 8);
5718afb77372SEric Joyner for (i = 0; i < sctx->isc_ntxqs; i++) {
5719afb77372SEric Joyner MPASS(sctx->isc_ntxd_min[i]);
5720afb77372SEric Joyner MPASS(powerof2(sctx->isc_ntxd_min[i]));
5721afb77372SEric Joyner MPASS(sctx->isc_ntxd_max[i]);
5722afb77372SEric Joyner MPASS(powerof2(sctx->isc_ntxd_max[i]));
5723afb77372SEric Joyner MPASS(sctx->isc_ntxd_default[i]);
5724afb77372SEric Joyner MPASS(powerof2(sctx->isc_ntxd_default[i]));
5725afb77372SEric Joyner }
57264c7070dbSScott Long }
57274c7070dbSScott Long
57281248952aSSean Bruno static void
_iflib_pre_assert(if_softc_ctx_t scctx)57291248952aSSean Bruno _iflib_pre_assert(if_softc_ctx_t scctx)
57301248952aSSean Bruno {
57311248952aSSean Bruno
57321248952aSSean Bruno MPASS(scctx->isc_txrx->ift_txd_encap);
57331248952aSSean Bruno MPASS(scctx->isc_txrx->ift_txd_flush);
57341248952aSSean Bruno MPASS(scctx->isc_txrx->ift_txd_credits_update);
57351248952aSSean Bruno MPASS(scctx->isc_txrx->ift_rxd_available);
57361248952aSSean Bruno MPASS(scctx->isc_txrx->ift_rxd_pkt_get);
57371248952aSSean Bruno MPASS(scctx->isc_txrx->ift_rxd_refill);
57381248952aSSean Bruno MPASS(scctx->isc_txrx->ift_rxd_flush);
57391248952aSSean Bruno }
57402fe66646SSean Bruno
57414c7070dbSScott Long static int
iflib_register(if_ctx_t ctx)57424c7070dbSScott Long iflib_register(if_ctx_t ctx)
57434c7070dbSScott Long {
57444c7070dbSScott Long if_shared_ctx_t sctx = ctx->ifc_sctx;
57454c7070dbSScott Long driver_t *driver = sctx->isc_driver;
57464c7070dbSScott Long device_t dev = ctx->ifc_dev;
57474c7070dbSScott Long if_t ifp;
57484c7070dbSScott Long
57494c7070dbSScott Long _iflib_assert(sctx);
57504c7070dbSScott Long
5751aa8a24d3SStephen Hurd CTX_LOCK_INIT(ctx);
57527b610b60SSean Bruno STATE_LOCK_INIT(ctx, device_get_nameunit(ctx->ifc_dev));
5753767723ddSMark Johnston ifp = ctx->ifc_ifp = if_alloc_dev(IFT_ETHER, dev);
57544c7070dbSScott Long
57554c7070dbSScott Long /*
57564c7070dbSScott Long * Initialize our context's device specific methods
57574c7070dbSScott Long */
57584c7070dbSScott Long kobj_init((kobj_t) ctx, (kobj_class_t) driver);
57594c7070dbSScott Long kobj_class_compile((kobj_class_t) driver);
57604c7070dbSScott Long
57614c7070dbSScott Long if_initname(ifp, device_get_name(dev), device_get_unit(dev));
57624c7070dbSScott Long if_setsoftc(ifp, ctx);
57634c7070dbSScott Long if_setdev(ifp, dev);
57644c7070dbSScott Long if_setinitfn(ifp, iflib_if_init);
57654c7070dbSScott Long if_setioctlfn(ifp, iflib_if_ioctl);
5766b8ca4756SPatrick Kelsey #ifdef ALTQ
5767b8ca4756SPatrick Kelsey if_setstartfn(ifp, iflib_altq_if_start);
5768b8ca4756SPatrick Kelsey if_settransmitfn(ifp, iflib_altq_if_transmit);
57698f410865SPatrick Kelsey if_setsendqready(ifp);
5770b8ca4756SPatrick Kelsey #else
57714c7070dbSScott Long if_settransmitfn(ifp, iflib_if_transmit);
5772b8ca4756SPatrick Kelsey #endif
57734c7070dbSScott Long if_setqflushfn(ifp, iflib_if_qflush);
57747ff9ae90SMarius Strobl if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
57754c7070dbSScott Long ctx->ifc_vlan_attach_event =
57764c7070dbSScott Long EVENTHANDLER_REGISTER(vlan_config, iflib_vlan_register, ctx,
57774c7070dbSScott Long EVENTHANDLER_PRI_FIRST);
57784c7070dbSScott Long ctx->ifc_vlan_detach_event =
57794c7070dbSScott Long EVENTHANDLER_REGISTER(vlan_unconfig, iflib_vlan_unregister, ctx,
57804c7070dbSScott Long EVENTHANDLER_PRI_FIRST);
57814c7070dbSScott Long
5782e2621d96SMatt Macy if ((sctx->isc_flags & IFLIB_DRIVER_MEDIA) == 0) {
5783e2621d96SMatt Macy ctx->ifc_mediap = &ctx->ifc_media;
5784e2621d96SMatt Macy ifmedia_init(ctx->ifc_mediap, IFM_IMASK,
57854c7070dbSScott Long iflib_media_change, iflib_media_status);
5786e2621d96SMatt Macy }
57874c7070dbSScott Long return (0);
57884c7070dbSScott Long }
57894c7070dbSScott Long
579056614414SEric Joyner static void
iflib_unregister_vlan_handlers(if_ctx_t ctx)57911558015eSEric Joyner iflib_unregister_vlan_handlers(if_ctx_t ctx)
579256614414SEric Joyner {
579356614414SEric Joyner /* Unregister VLAN events */
579456614414SEric Joyner if (ctx->ifc_vlan_attach_event != NULL) {
579556614414SEric Joyner EVENTHANDLER_DEREGISTER(vlan_config, ctx->ifc_vlan_attach_event);
579656614414SEric Joyner ctx->ifc_vlan_attach_event = NULL;
579756614414SEric Joyner }
579856614414SEric Joyner if (ctx->ifc_vlan_detach_event != NULL) {
579956614414SEric Joyner EVENTHANDLER_DEREGISTER(vlan_unconfig, ctx->ifc_vlan_detach_event);
580056614414SEric Joyner ctx->ifc_vlan_detach_event = NULL;
580156614414SEric Joyner }
580256614414SEric Joyner
58031558015eSEric Joyner }
58041558015eSEric Joyner
58051558015eSEric Joyner static void
iflib_deregister(if_ctx_t ctx)58061558015eSEric Joyner iflib_deregister(if_ctx_t ctx)
58071558015eSEric Joyner {
58081558015eSEric Joyner if_t ifp = ctx->ifc_ifp;
58091558015eSEric Joyner
58101558015eSEric Joyner /* Remove all media */
58111558015eSEric Joyner ifmedia_removeall(&ctx->ifc_media);
58121558015eSEric Joyner
58131558015eSEric Joyner /* Ensure that VLAN event handlers are unregistered */
58141558015eSEric Joyner iflib_unregister_vlan_handlers(ctx);
58151558015eSEric Joyner
581656614414SEric Joyner /* Release kobject reference */
581756614414SEric Joyner kobj_delete((kobj_t) ctx, NULL);
581856614414SEric Joyner
581956614414SEric Joyner /* Free the ifnet structure */
582056614414SEric Joyner if_free(ifp);
582156614414SEric Joyner
582256614414SEric Joyner STATE_LOCK_DESTROY(ctx);
582356614414SEric Joyner
582456614414SEric Joyner /* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/
582556614414SEric Joyner CTX_LOCK_DESTROY(ctx);
582656614414SEric Joyner }
582756614414SEric Joyner
58284c7070dbSScott Long static int
iflib_queues_alloc(if_ctx_t ctx)58294c7070dbSScott Long iflib_queues_alloc(if_ctx_t ctx)
58304c7070dbSScott Long {
58314c7070dbSScott Long if_shared_ctx_t sctx = ctx->ifc_sctx;
583223ac9029SStephen Hurd if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
58334c7070dbSScott Long device_t dev = ctx->ifc_dev;
583423ac9029SStephen Hurd int nrxqsets = scctx->isc_nrxqsets;
583523ac9029SStephen Hurd int ntxqsets = scctx->isc_ntxqsets;
58364c7070dbSScott Long iflib_txq_t txq;
58374c7070dbSScott Long iflib_rxq_t rxq;
58384c7070dbSScott Long iflib_fl_t fl = NULL;
583923ac9029SStephen Hurd int i, j, cpu, err, txconf, rxconf;
58404c7070dbSScott Long iflib_dma_info_t ifdip;
584123ac9029SStephen Hurd uint32_t *rxqsizes = scctx->isc_rxqsizes;
584223ac9029SStephen Hurd uint32_t *txqsizes = scctx->isc_txqsizes;
58434c7070dbSScott Long uint8_t nrxqs = sctx->isc_nrxqs;
58444c7070dbSScott Long uint8_t ntxqs = sctx->isc_ntxqs;
58454c7070dbSScott Long int nfree_lists = sctx->isc_nfl ? sctx->isc_nfl : 1;
58464ba9ad0dSVincenzo Maffione int fl_offset = (sctx->isc_flags & IFLIB_HAS_RXCQ ? 1 : 0);
58474c7070dbSScott Long caddr_t *vaddrs;
58484c7070dbSScott Long uint64_t *paddrs;
58494c7070dbSScott Long
585023ac9029SStephen Hurd KASSERT(ntxqs > 0, ("number of queues per qset must be at least 1"));
585123ac9029SStephen Hurd KASSERT(nrxqs > 0, ("number of queues per qset must be at least 1"));
58524ba9ad0dSVincenzo Maffione KASSERT(nrxqs >= fl_offset + nfree_lists,
58534ba9ad0dSVincenzo Maffione ("there must be at least a rxq for each free list"));
58544c7070dbSScott Long
58554c7070dbSScott Long /* Allocate the TX ring struct memory */
5856b89827a0SStephen Hurd if (!(ctx->ifc_txqs =
5857ac2fffa4SPedro F. Giffuni (iflib_txq_t) malloc(sizeof(struct iflib_txq) *
5858ac2fffa4SPedro F. Giffuni ntxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) {
58594c7070dbSScott Long device_printf(dev, "Unable to allocate TX ring memory\n");
58604c7070dbSScott Long err = ENOMEM;
58614c7070dbSScott Long goto fail;
58624c7070dbSScott Long }
58634c7070dbSScott Long
58644c7070dbSScott Long /* Now allocate the RX */
5865b89827a0SStephen Hurd if (!(ctx->ifc_rxqs =
5866ac2fffa4SPedro F. Giffuni (iflib_rxq_t) malloc(sizeof(struct iflib_rxq) *
5867ac2fffa4SPedro F. Giffuni nrxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) {
58684c7070dbSScott Long device_printf(dev, "Unable to allocate RX ring memory\n");
58694c7070dbSScott Long err = ENOMEM;
58704c7070dbSScott Long goto rx_fail;
58714c7070dbSScott Long }
58724c7070dbSScott Long
5873b89827a0SStephen Hurd txq = ctx->ifc_txqs;
5874b89827a0SStephen Hurd rxq = ctx->ifc_rxqs;
58754c7070dbSScott Long
58764c7070dbSScott Long /*
58774c7070dbSScott Long * XXX handle allocation failure
58784c7070dbSScott Long */
587996c85efbSNathan Whitehorn for (txconf = i = 0, cpu = CPU_FIRST(); i < ntxqsets; i++, txconf++, txq++, cpu = CPU_NEXT(cpu)) {
58804c7070dbSScott Long /* Set up some basics */
58814c7070dbSScott Long
5882bfce461eSMarius Strobl if ((ifdip = malloc(sizeof(struct iflib_dma_info) * ntxqs,
5883bfce461eSMarius Strobl M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
5884bfce461eSMarius Strobl device_printf(dev,
5885bfce461eSMarius Strobl "Unable to allocate TX DMA info memory\n");
58864c7070dbSScott Long err = ENOMEM;
58870d0338afSConrad Meyer goto err_tx_desc;
58884c7070dbSScott Long }
58894c7070dbSScott Long txq->ift_ifdi = ifdip;
58904c7070dbSScott Long for (j = 0; j < ntxqs; j++, ifdip++) {
5891bfce461eSMarius Strobl if (iflib_dma_alloc(ctx, txqsizes[j], ifdip, 0)) {
5892bfce461eSMarius Strobl device_printf(dev,
5893bfce461eSMarius Strobl "Unable to allocate TX descriptors\n");
58944c7070dbSScott Long err = ENOMEM;
58954c7070dbSScott Long goto err_tx_desc;
58964c7070dbSScott Long }
589795246abbSSean Bruno txq->ift_txd_size[j] = scctx->isc_txd_size[j];
58984c7070dbSScott Long bzero((void *)ifdip->idi_vaddr, txqsizes[j]);
58994c7070dbSScott Long }
59004c7070dbSScott Long txq->ift_ctx = ctx;
59014c7070dbSScott Long txq->ift_id = i;
590223ac9029SStephen Hurd if (sctx->isc_flags & IFLIB_HAS_TXCQ) {
590323ac9029SStephen Hurd txq->ift_br_offset = 1;
590423ac9029SStephen Hurd } else {
590523ac9029SStephen Hurd txq->ift_br_offset = 0;
590623ac9029SStephen Hurd }
59074c7070dbSScott Long
59084c7070dbSScott Long if (iflib_txsd_alloc(txq)) {
59094c7070dbSScott Long device_printf(dev, "Critical Failure setting up TX buffers\n");
59104c7070dbSScott Long err = ENOMEM;
59114c7070dbSScott Long goto err_tx_desc;
59124c7070dbSScott Long }
59134c7070dbSScott Long
59144c7070dbSScott Long /* Initialize the TX lock */
59151722eeacSMarius Strobl snprintf(txq->ift_mtx_name, MTX_NAME_LEN, "%s:TX(%d):callout",
59164c7070dbSScott Long device_get_nameunit(dev), txq->ift_id);
59174c7070dbSScott Long mtx_init(&txq->ift_mtx, txq->ift_mtx_name, NULL, MTX_DEF);
59184c7070dbSScott Long callout_init_mtx(&txq->ift_timer, &txq->ift_mtx, 0);
591917cec474SVincenzo Maffione txq->ift_timer.c_cpu = cpu;
592017cec474SVincenzo Maffione #ifdef DEV_NETMAP
592117cec474SVincenzo Maffione callout_init_mtx(&txq->ift_netmap_timer, &txq->ift_mtx, 0);
592217cec474SVincenzo Maffione txq->ift_netmap_timer.c_cpu = cpu;
592317cec474SVincenzo Maffione #endif /* DEV_NETMAP */
59244c7070dbSScott Long
592595246abbSSean Bruno err = ifmp_ring_alloc(&txq->ift_br, 2048, txq, iflib_txq_drain,
59264c7070dbSScott Long iflib_txq_can_drain, M_IFLIB, M_WAITOK);
59274c7070dbSScott Long if (err) {
59284c7070dbSScott Long /* XXX free any allocated rings */
59294c7070dbSScott Long device_printf(dev, "Unable to allocate buf_ring\n");
59300d0338afSConrad Meyer goto err_tx_desc;
59314c7070dbSScott Long }
59324c7070dbSScott Long }
59334c7070dbSScott Long
59344c7070dbSScott Long for (rxconf = i = 0; i < nrxqsets; i++, rxconf++, rxq++) {
59354c7070dbSScott Long /* Set up some basics */
5936fb1a29b4SHans Petter Selasky callout_init(&rxq->ifr_watchdog, 1);
59374c7070dbSScott Long
5938bfce461eSMarius Strobl if ((ifdip = malloc(sizeof(struct iflib_dma_info) * nrxqs,
5939bfce461eSMarius Strobl M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
5940bfce461eSMarius Strobl device_printf(dev,
5941bfce461eSMarius Strobl "Unable to allocate RX DMA info memory\n");
59424c7070dbSScott Long err = ENOMEM;
59430d0338afSConrad Meyer goto err_tx_desc;
59444c7070dbSScott Long }
59454c7070dbSScott Long
59464c7070dbSScott Long rxq->ifr_ifdi = ifdip;
594795246abbSSean Bruno /* XXX this needs to be changed if #rx queues != #tx queues */
594895246abbSSean Bruno rxq->ifr_ntxqirq = 1;
594995246abbSSean Bruno rxq->ifr_txqid[0] = i;
59504c7070dbSScott Long for (j = 0; j < nrxqs; j++, ifdip++) {
5951bfce461eSMarius Strobl if (iflib_dma_alloc(ctx, rxqsizes[j], ifdip, 0)) {
5952bfce461eSMarius Strobl device_printf(dev,
5953bfce461eSMarius Strobl "Unable to allocate RX descriptors\n");
59544c7070dbSScott Long err = ENOMEM;
59554c7070dbSScott Long goto err_tx_desc;
59564c7070dbSScott Long }
59574c7070dbSScott Long bzero((void *)ifdip->idi_vaddr, rxqsizes[j]);
59584c7070dbSScott Long }
59594c7070dbSScott Long rxq->ifr_ctx = ctx;
59604c7070dbSScott Long rxq->ifr_id = i;
59614ba9ad0dSVincenzo Maffione rxq->ifr_fl_offset = fl_offset;
59624c7070dbSScott Long rxq->ifr_nfl = nfree_lists;
59634c7070dbSScott Long if (!(fl =
5964ac2fffa4SPedro F. Giffuni (iflib_fl_t) malloc(sizeof(struct iflib_fl) * nfree_lists, M_IFLIB, M_NOWAIT | M_ZERO))) {
59654c7070dbSScott Long device_printf(dev, "Unable to allocate free list memory\n");
59664c7070dbSScott Long err = ENOMEM;
59670d0338afSConrad Meyer goto err_tx_desc;
59684c7070dbSScott Long }
59694c7070dbSScott Long rxq->ifr_fl = fl;
59704c7070dbSScott Long for (j = 0; j < nfree_lists; j++) {
597195246abbSSean Bruno fl[j].ifl_rxq = rxq;
597295246abbSSean Bruno fl[j].ifl_id = j;
597395246abbSSean Bruno fl[j].ifl_ifdi = &rxq->ifr_ifdi[j + rxq->ifr_fl_offset];
597495246abbSSean Bruno fl[j].ifl_rxd_size = scctx->isc_rxd_size[j];
59754c7070dbSScott Long }
59764c7070dbSScott Long /* Allocate receive buffers for the ring */
59774c7070dbSScott Long if (iflib_rxsd_alloc(rxq)) {
59784c7070dbSScott Long device_printf(dev,
59794c7070dbSScott Long "Critical Failure setting up receive buffers\n");
59804c7070dbSScott Long err = ENOMEM;
59814c7070dbSScott Long goto err_rx_desc;
59824c7070dbSScott Long }
598387890dbaSSean Bruno
598487890dbaSSean Bruno for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++)
59853db348b5SMarius Strobl fl->ifl_rx_bitmap = bit_alloc(fl->ifl_size, M_IFLIB,
59863db348b5SMarius Strobl M_WAITOK);
59874c7070dbSScott Long }
59884c7070dbSScott Long
59894c7070dbSScott Long /* TXQs */
59904c7070dbSScott Long vaddrs = malloc(sizeof(caddr_t) * ntxqsets * ntxqs, M_IFLIB, M_WAITOK);
59914c7070dbSScott Long paddrs = malloc(sizeof(uint64_t) * ntxqsets * ntxqs, M_IFLIB, M_WAITOK);
59924c7070dbSScott Long for (i = 0; i < ntxqsets; i++) {
59934c7070dbSScott Long iflib_dma_info_t di = ctx->ifc_txqs[i].ift_ifdi;
59944c7070dbSScott Long
59954c7070dbSScott Long for (j = 0; j < ntxqs; j++, di++) {
59964c7070dbSScott Long vaddrs[i * ntxqs + j] = di->idi_vaddr;
59974c7070dbSScott Long paddrs[i * ntxqs + j] = di->idi_paddr;
59984c7070dbSScott Long }
59994c7070dbSScott Long }
60004c7070dbSScott Long if ((err = IFDI_TX_QUEUES_ALLOC(ctx, vaddrs, paddrs, ntxqs, ntxqsets)) != 0) {
6001bfce461eSMarius Strobl device_printf(ctx->ifc_dev,
6002bfce461eSMarius Strobl "Unable to allocate device TX queue\n");
60034c7070dbSScott Long iflib_tx_structures_free(ctx);
60044c7070dbSScott Long free(vaddrs, M_IFLIB);
60054c7070dbSScott Long free(paddrs, M_IFLIB);
60064c7070dbSScott Long goto err_rx_desc;
60074c7070dbSScott Long }
60084c7070dbSScott Long free(vaddrs, M_IFLIB);
60094c7070dbSScott Long free(paddrs, M_IFLIB);
60104c7070dbSScott Long
60114c7070dbSScott Long /* RXQs */
60124c7070dbSScott Long vaddrs = malloc(sizeof(caddr_t) * nrxqsets * nrxqs, M_IFLIB, M_WAITOK);
60134c7070dbSScott Long paddrs = malloc(sizeof(uint64_t) * nrxqsets * nrxqs, M_IFLIB, M_WAITOK);
60144c7070dbSScott Long for (i = 0; i < nrxqsets; i++) {
60154c7070dbSScott Long iflib_dma_info_t di = ctx->ifc_rxqs[i].ifr_ifdi;
60164c7070dbSScott Long
60174c7070dbSScott Long for (j = 0; j < nrxqs; j++, di++) {
60184c7070dbSScott Long vaddrs[i * nrxqs + j] = di->idi_vaddr;
60194c7070dbSScott Long paddrs[i * nrxqs + j] = di->idi_paddr;
60204c7070dbSScott Long }
60214c7070dbSScott Long }
60224c7070dbSScott Long if ((err = IFDI_RX_QUEUES_ALLOC(ctx, vaddrs, paddrs, nrxqs, nrxqsets)) != 0) {
6023bfce461eSMarius Strobl device_printf(ctx->ifc_dev,
6024bfce461eSMarius Strobl "Unable to allocate device RX queue\n");
60254c7070dbSScott Long iflib_tx_structures_free(ctx);
60264c7070dbSScott Long free(vaddrs, M_IFLIB);
60274c7070dbSScott Long free(paddrs, M_IFLIB);
60284c7070dbSScott Long goto err_rx_desc;
60294c7070dbSScott Long }
60304c7070dbSScott Long free(vaddrs, M_IFLIB);
60314c7070dbSScott Long free(paddrs, M_IFLIB);
60324c7070dbSScott Long
60334c7070dbSScott Long return (0);
60344c7070dbSScott Long
60354c7070dbSScott Long /* XXX handle allocation failure changes */
60364c7070dbSScott Long err_rx_desc:
60374c7070dbSScott Long err_tx_desc:
6038b89827a0SStephen Hurd rx_fail:
60394c7070dbSScott Long if (ctx->ifc_rxqs != NULL)
60404c7070dbSScott Long free(ctx->ifc_rxqs, M_IFLIB);
60414c7070dbSScott Long ctx->ifc_rxqs = NULL;
60424c7070dbSScott Long if (ctx->ifc_txqs != NULL)
60434c7070dbSScott Long free(ctx->ifc_txqs, M_IFLIB);
60444c7070dbSScott Long ctx->ifc_txqs = NULL;
60454c7070dbSScott Long fail:
60464c7070dbSScott Long return (err);
60474c7070dbSScott Long }
60484c7070dbSScott Long
60494c7070dbSScott Long static int
iflib_tx_structures_setup(if_ctx_t ctx)60504c7070dbSScott Long iflib_tx_structures_setup(if_ctx_t ctx)
60514c7070dbSScott Long {
60524c7070dbSScott Long iflib_txq_t txq = ctx->ifc_txqs;
60534c7070dbSScott Long int i;
60544c7070dbSScott Long
60554c7070dbSScott Long for (i = 0; i < NTXQSETS(ctx); i++, txq++)
60564c7070dbSScott Long iflib_txq_setup(txq);
60574c7070dbSScott Long
60584c7070dbSScott Long return (0);
60594c7070dbSScott Long }
60604c7070dbSScott Long
60614c7070dbSScott Long static void
iflib_tx_structures_free(if_ctx_t ctx)60624c7070dbSScott Long iflib_tx_structures_free(if_ctx_t ctx)
60634c7070dbSScott Long {
60644c7070dbSScott Long iflib_txq_t txq = ctx->ifc_txqs;
60654d261ce2SStephen Hurd if_shared_ctx_t sctx = ctx->ifc_sctx;
60664c7070dbSScott Long int i, j;
60674c7070dbSScott Long
60684c7070dbSScott Long for (i = 0; i < NTXQSETS(ctx); i++, txq++) {
60694d261ce2SStephen Hurd for (j = 0; j < sctx->isc_ntxqs; j++)
60704c7070dbSScott Long iflib_dma_free(&txq->ift_ifdi[j]);
6071244e7cffSEric Joyner iflib_txq_destroy(txq);
60724c7070dbSScott Long }
60734c7070dbSScott Long free(ctx->ifc_txqs, M_IFLIB);
60744c7070dbSScott Long ctx->ifc_txqs = NULL;
60754c7070dbSScott Long }
60764c7070dbSScott Long
60774c7070dbSScott Long /*********************************************************************
60784c7070dbSScott Long *
60794c7070dbSScott Long * Initialize all receive rings.
60804c7070dbSScott Long *
60814c7070dbSScott Long **********************************************************************/
60824c7070dbSScott Long static int
iflib_rx_structures_setup(if_ctx_t ctx)60834c7070dbSScott Long iflib_rx_structures_setup(if_ctx_t ctx)
60844c7070dbSScott Long {
60854c7070dbSScott Long iflib_rxq_t rxq = ctx->ifc_rxqs;
6086aaeb188aSBjoern A. Zeeb int q;
6087aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
60883d10e9edSMarius Strobl int err, i;
6089aaeb188aSBjoern A. Zeeb #endif
60904c7070dbSScott Long
60914c7070dbSScott Long for (q = 0; q < ctx->ifc_softc_ctx.isc_nrxqsets; q++, rxq++) {
6092aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
60933d10e9edSMarius Strobl err = tcp_lro_init_args(&rxq->ifr_lc, ctx->ifc_ifp,
609423ac9029SStephen Hurd TCP_LRO_ENTRIES, min(1024,
60953d10e9edSMarius Strobl ctx->ifc_softc_ctx.isc_nrxd[rxq->ifr_fl_offset]));
60963d10e9edSMarius Strobl if (err != 0) {
60973d10e9edSMarius Strobl device_printf(ctx->ifc_dev,
60983d10e9edSMarius Strobl "LRO Initialization failed!\n");
60994c7070dbSScott Long goto fail;
61004c7070dbSScott Long }
6101aaeb188aSBjoern A. Zeeb #endif
61024c7070dbSScott Long IFDI_RXQ_SETUP(ctx, rxq->ifr_id);
61034c7070dbSScott Long }
61044c7070dbSScott Long return (0);
6105aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
61064c7070dbSScott Long fail:
61074c7070dbSScott Long /*
61083d10e9edSMarius Strobl * Free LRO resources allocated so far, we will only handle
61094c7070dbSScott Long * the rings that completed, the failing case will have
61104c7070dbSScott Long * cleaned up for itself. 'q' failed, so its the terminus.
61114c7070dbSScott Long */
61124c7070dbSScott Long rxq = ctx->ifc_rxqs;
61134c7070dbSScott Long for (i = 0; i < q; ++i, rxq++) {
61143d10e9edSMarius Strobl tcp_lro_free(&rxq->ifr_lc);
61154c7070dbSScott Long }
61164c7070dbSScott Long return (err);
6117aaeb188aSBjoern A. Zeeb #endif
61184c7070dbSScott Long }
61194c7070dbSScott Long
61204c7070dbSScott Long /*********************************************************************
61214c7070dbSScott Long *
61224c7070dbSScott Long * Free all receive rings.
61234c7070dbSScott Long *
61244c7070dbSScott Long **********************************************************************/
61254c7070dbSScott Long static void
iflib_rx_structures_free(if_ctx_t ctx)61264c7070dbSScott Long iflib_rx_structures_free(if_ctx_t ctx)
61274c7070dbSScott Long {
61284c7070dbSScott Long iflib_rxq_t rxq = ctx->ifc_rxqs;
6129db8e8f1eSEric Joyner if_shared_ctx_t sctx = ctx->ifc_sctx;
6130db8e8f1eSEric Joyner int i, j;
61314c7070dbSScott Long
61323d10e9edSMarius Strobl for (i = 0; i < ctx->ifc_softc_ctx.isc_nrxqsets; i++, rxq++) {
6133db8e8f1eSEric Joyner for (j = 0; j < sctx->isc_nrxqs; j++)
6134db8e8f1eSEric Joyner iflib_dma_free(&rxq->ifr_ifdi[j]);
61354c7070dbSScott Long iflib_rx_sds_free(rxq);
6136007b804fSMarius Strobl #if defined(INET6) || defined(INET)
61373d10e9edSMarius Strobl tcp_lro_free(&rxq->ifr_lc);
6138007b804fSMarius Strobl #endif
61394c7070dbSScott Long }
614077c1fcecSEric Joyner free(ctx->ifc_rxqs, M_IFLIB);
614177c1fcecSEric Joyner ctx->ifc_rxqs = NULL;
61424c7070dbSScott Long }
61434c7070dbSScott Long
61444c7070dbSScott Long static int
iflib_qset_structures_setup(if_ctx_t ctx)61454c7070dbSScott Long iflib_qset_structures_setup(if_ctx_t ctx)
61464c7070dbSScott Long {
61474c7070dbSScott Long int err;
61484c7070dbSScott Long
61496108c013SStephen Hurd /*
61506108c013SStephen Hurd * It is expected that the caller takes care of freeing queues if this
61516108c013SStephen Hurd * fails.
61526108c013SStephen Hurd */
6153ac88e6daSStephen Hurd if ((err = iflib_tx_structures_setup(ctx)) != 0) {
6154ac88e6daSStephen Hurd device_printf(ctx->ifc_dev, "iflib_tx_structures_setup failed: %d\n", err);
61554c7070dbSScott Long return (err);
6156ac88e6daSStephen Hurd }
61574c7070dbSScott Long
61586108c013SStephen Hurd if ((err = iflib_rx_structures_setup(ctx)) != 0)
61594c7070dbSScott Long device_printf(ctx->ifc_dev, "iflib_rx_structures_setup failed: %d\n", err);
61606108c013SStephen Hurd
61614c7070dbSScott Long return (err);
61624c7070dbSScott Long }
61634c7070dbSScott Long
61644c7070dbSScott Long int
iflib_irq_alloc(if_ctx_t ctx,if_irq_t irq,int rid,driver_filter_t filter,void * filter_arg,driver_intr_t handler,void * arg,const char * name)61654c7070dbSScott Long iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid,
61663e0e6330SStephen Hurd driver_filter_t filter, void *filter_arg, driver_intr_t handler, void *arg, const char *name)
61674c7070dbSScott Long {
61684c7070dbSScott Long
61694c7070dbSScott Long return (_iflib_irq_alloc(ctx, irq, rid, filter, handler, arg, name));
61704c7070dbSScott Long }
61714c7070dbSScott Long
6172b103855eSStephen Hurd /* Just to avoid copy/paste */
6173b103855eSStephen Hurd static inline int
iflib_irq_set_affinity(if_ctx_t ctx,if_irq_t irq,iflib_intr_type_t type,int qid,struct grouptask * gtask,struct taskqgroup * tqg,void * uniq,const char * name)6174f855ec81SMarius Strobl iflib_irq_set_affinity(if_ctx_t ctx, if_irq_t irq, iflib_intr_type_t type,
6175f855ec81SMarius Strobl int qid, struct grouptask *gtask, struct taskqgroup *tqg, void *uniq,
6176f855ec81SMarius Strobl const char *name)
6177b103855eSStephen Hurd {
6178f855ec81SMarius Strobl device_t dev;
6179ca7005f1SPatrick Kelsey unsigned int base_cpuid, cpuid;
6180ca7005f1SPatrick Kelsey int err;
6181b103855eSStephen Hurd
6182f855ec81SMarius Strobl dev = ctx->ifc_dev;
6183ca7005f1SPatrick Kelsey base_cpuid = ctx->ifc_sysctl_core_offset;
6184ca7005f1SPatrick Kelsey cpuid = get_cpuid_for_queue(ctx, base_cpuid, qid, type == IFLIB_INTR_TX);
6185ca7005f1SPatrick Kelsey err = taskqgroup_attach_cpu(tqg, gtask, uniq, cpuid, dev,
6186ca7005f1SPatrick Kelsey irq ? irq->ii_res : NULL, name);
6187b103855eSStephen Hurd if (err) {
6188f855ec81SMarius Strobl device_printf(dev, "taskqgroup_attach_cpu failed %d\n", err);
6189b103855eSStephen Hurd return (err);
6190b103855eSStephen Hurd }
6191b103855eSStephen Hurd #ifdef notyet
6192b103855eSStephen Hurd if (cpuid > ctx->ifc_cpuid_highest)
6193b103855eSStephen Hurd ctx->ifc_cpuid_highest = cpuid;
6194b103855eSStephen Hurd #endif
61953d10e9edSMarius Strobl return (0);
6196b103855eSStephen Hurd }
6197b103855eSStephen Hurd
6198ed34a6b6SEric Joyner /*
6199ed34a6b6SEric Joyner * Allocate a hardware interrupt for subctx using the parent (ctx)'s hardware
6200ed34a6b6SEric Joyner * resources.
6201ed34a6b6SEric Joyner *
6202ed34a6b6SEric Joyner * Similar to iflib_irq_alloc_generic(), but for interrupt type IFLIB_INTR_RXTX
6203ed34a6b6SEric Joyner * only.
6204ed34a6b6SEric Joyner *
6205ed34a6b6SEric Joyner * XXX: Could be removed if subctx's dev has its intr resource allocation
6206ed34a6b6SEric Joyner * methods replaced with custom ones?
6207ed34a6b6SEric Joyner */
6208ed34a6b6SEric Joyner int
iflib_irq_alloc_generic_subctx(if_ctx_t ctx,if_ctx_t subctx,if_irq_t irq,int rid,iflib_intr_type_t type,driver_filter_t * filter,void * filter_arg,int qid,const char * name)6209ed34a6b6SEric Joyner iflib_irq_alloc_generic_subctx(if_ctx_t ctx, if_ctx_t subctx, if_irq_t irq,
6210ed34a6b6SEric Joyner int rid, iflib_intr_type_t type,
6211ed34a6b6SEric Joyner driver_filter_t *filter, void *filter_arg,
6212ed34a6b6SEric Joyner int qid, const char *name)
6213ed34a6b6SEric Joyner {
6214ed34a6b6SEric Joyner device_t dev, subdev;
6215ed34a6b6SEric Joyner struct grouptask *gtask;
6216ed34a6b6SEric Joyner struct taskqgroup *tqg;
6217ed34a6b6SEric Joyner iflib_filter_info_t info;
6218ed34a6b6SEric Joyner gtask_fn_t *fn;
6219ed34a6b6SEric Joyner int tqrid, err;
6220ed34a6b6SEric Joyner driver_filter_t *intr_fast;
6221ed34a6b6SEric Joyner void *q;
6222ed34a6b6SEric Joyner
6223ed34a6b6SEric Joyner MPASS(ctx != NULL);
6224ed34a6b6SEric Joyner MPASS(subctx != NULL);
6225ed34a6b6SEric Joyner
6226ed34a6b6SEric Joyner tqrid = rid;
6227ed34a6b6SEric Joyner dev = ctx->ifc_dev;
6228ed34a6b6SEric Joyner subdev = subctx->ifc_dev;
6229ed34a6b6SEric Joyner
6230ed34a6b6SEric Joyner switch (type) {
6231ed34a6b6SEric Joyner case IFLIB_INTR_RXTX:
6232ed34a6b6SEric Joyner q = &subctx->ifc_rxqs[qid];
6233ed34a6b6SEric Joyner info = &subctx->ifc_rxqs[qid].ifr_filter_info;
6234ed34a6b6SEric Joyner gtask = &subctx->ifc_rxqs[qid].ifr_task;
6235ed34a6b6SEric Joyner tqg = qgroup_if_io_tqg;
6236ed34a6b6SEric Joyner fn = _task_fn_rx;
6237ed34a6b6SEric Joyner intr_fast = iflib_fast_intr_rxtx;
6238ed34a6b6SEric Joyner NET_GROUPTASK_INIT(gtask, 0, fn, q);
6239ed34a6b6SEric Joyner break;
6240ed34a6b6SEric Joyner default:
6241ed34a6b6SEric Joyner device_printf(dev, "%s: unknown net intr type for subctx %s (%d)\n",
6242ed34a6b6SEric Joyner __func__, device_get_nameunit(subdev), type);
6243ed34a6b6SEric Joyner return (EINVAL);
6244ed34a6b6SEric Joyner }
6245ed34a6b6SEric Joyner
6246ed34a6b6SEric Joyner info->ifi_filter = filter;
6247ed34a6b6SEric Joyner info->ifi_filter_arg = filter_arg;
6248ed34a6b6SEric Joyner info->ifi_task = gtask;
6249ed34a6b6SEric Joyner info->ifi_ctx = q;
6250ed34a6b6SEric Joyner
6251ed34a6b6SEric Joyner NET_GROUPTASK_INIT(gtask, 0, fn, q);
6252ed34a6b6SEric Joyner
6253ed34a6b6SEric Joyner /* Allocate interrupts from hardware using parent context */
6254ed34a6b6SEric Joyner err = _iflib_irq_alloc(ctx, irq, rid, intr_fast, NULL, info, name);
6255ed34a6b6SEric Joyner if (err != 0) {
6256ed34a6b6SEric Joyner device_printf(dev, "_iflib_irq_alloc failed for subctx %s: %d\n",
6257ed34a6b6SEric Joyner device_get_nameunit(subdev), err);
6258ed34a6b6SEric Joyner return (err);
6259ed34a6b6SEric Joyner }
6260ed34a6b6SEric Joyner
6261ed34a6b6SEric Joyner if (tqrid != -1) {
6262ed34a6b6SEric Joyner err = iflib_irq_set_affinity(ctx, irq, type, qid, gtask, tqg, q,
6263ed34a6b6SEric Joyner name);
6264ed34a6b6SEric Joyner if (err)
6265ed34a6b6SEric Joyner return (err);
6266ed34a6b6SEric Joyner } else {
6267ed34a6b6SEric Joyner taskqgroup_attach(tqg, gtask, q, dev, irq->ii_res, name);
6268ed34a6b6SEric Joyner }
6269ed34a6b6SEric Joyner
6270ed34a6b6SEric Joyner return (0);
6271ed34a6b6SEric Joyner }
6272ed34a6b6SEric Joyner
62734c7070dbSScott Long int
iflib_irq_alloc_generic(if_ctx_t ctx,if_irq_t irq,int rid,iflib_intr_type_t type,driver_filter_t * filter,void * filter_arg,int qid,const char * name)62744c7070dbSScott Long iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid,
62754c7070dbSScott Long iflib_intr_type_t type, driver_filter_t *filter,
62763e0e6330SStephen Hurd void *filter_arg, int qid, const char *name)
62774c7070dbSScott Long {
6278f855ec81SMarius Strobl device_t dev;
62794c7070dbSScott Long struct grouptask *gtask;
62804c7070dbSScott Long struct taskqgroup *tqg;
62814c7070dbSScott Long iflib_filter_info_t info;
628223ac9029SStephen Hurd gtask_fn_t *fn;
6283b103855eSStephen Hurd int tqrid, err;
628495246abbSSean Bruno driver_filter_t *intr_fast;
62854c7070dbSScott Long void *q;
62864c7070dbSScott Long
62874c7070dbSScott Long info = &ctx->ifc_filter_info;
6288add6f7d0SSean Bruno tqrid = rid;
62894c7070dbSScott Long
62904c7070dbSScott Long switch (type) {
62914c7070dbSScott Long /* XXX merge tx/rx for netmap? */
62924c7070dbSScott Long case IFLIB_INTR_TX:
62934c7070dbSScott Long q = &ctx->ifc_txqs[qid];
62944c7070dbSScott Long info = &ctx->ifc_txqs[qid].ift_filter_info;
62954c7070dbSScott Long gtask = &ctx->ifc_txqs[qid].ift_task;
6296ab2e3f79SStephen Hurd tqg = qgroup_if_io_tqg;
62974c7070dbSScott Long fn = _task_fn_tx;
629895246abbSSean Bruno intr_fast = iflib_fast_intr;
6299da69b8f9SSean Bruno GROUPTASK_INIT(gtask, 0, fn, q);
63005ee36c68SStephen Hurd ctx->ifc_flags |= IFC_NETMAP_TX_IRQ;
63014c7070dbSScott Long break;
63024c7070dbSScott Long case IFLIB_INTR_RX:
63034c7070dbSScott Long q = &ctx->ifc_rxqs[qid];
63044c7070dbSScott Long info = &ctx->ifc_rxqs[qid].ifr_filter_info;
63054c7070dbSScott Long gtask = &ctx->ifc_rxqs[qid].ifr_task;
6306ab2e3f79SStephen Hurd tqg = qgroup_if_io_tqg;
63074c7070dbSScott Long fn = _task_fn_rx;
6308ab2e3f79SStephen Hurd intr_fast = iflib_fast_intr;
63096c3e93cbSGleb Smirnoff NET_GROUPTASK_INIT(gtask, 0, fn, q);
631095246abbSSean Bruno break;
631195246abbSSean Bruno case IFLIB_INTR_RXTX:
631295246abbSSean Bruno q = &ctx->ifc_rxqs[qid];
631395246abbSSean Bruno info = &ctx->ifc_rxqs[qid].ifr_filter_info;
631495246abbSSean Bruno gtask = &ctx->ifc_rxqs[qid].ifr_task;
6315ab2e3f79SStephen Hurd tqg = qgroup_if_io_tqg;
631695246abbSSean Bruno fn = _task_fn_rx;
631795246abbSSean Bruno intr_fast = iflib_fast_intr_rxtx;
63186c3e93cbSGleb Smirnoff NET_GROUPTASK_INIT(gtask, 0, fn, q);
63194c7070dbSScott Long break;
63204c7070dbSScott Long case IFLIB_INTR_ADMIN:
63214c7070dbSScott Long q = ctx;
6322da69b8f9SSean Bruno tqrid = -1;
63234c7070dbSScott Long info = &ctx->ifc_filter_info;
63244c7070dbSScott Long gtask = &ctx->ifc_admin_task;
6325ab2e3f79SStephen Hurd tqg = qgroup_if_config_tqg;
63264c7070dbSScott Long fn = _task_fn_admin;
632795246abbSSean Bruno intr_fast = iflib_fast_intr_ctx;
63284c7070dbSScott Long break;
63294c7070dbSScott Long default:
63303d10e9edSMarius Strobl device_printf(ctx->ifc_dev, "%s: unknown net intr type\n",
63313d10e9edSMarius Strobl __func__);
63323d10e9edSMarius Strobl return (EINVAL);
63334c7070dbSScott Long }
63344c7070dbSScott Long
63354c7070dbSScott Long info->ifi_filter = filter;
63364c7070dbSScott Long info->ifi_filter_arg = filter_arg;
63374c7070dbSScott Long info->ifi_task = gtask;
633895246abbSSean Bruno info->ifi_ctx = q;
63394c7070dbSScott Long
6340f855ec81SMarius Strobl dev = ctx->ifc_dev;
634195246abbSSean Bruno err = _iflib_irq_alloc(ctx, irq, rid, intr_fast, NULL, info, name);
6342da69b8f9SSean Bruno if (err != 0) {
6343f855ec81SMarius Strobl device_printf(dev, "_iflib_irq_alloc failed %d\n", err);
63444c7070dbSScott Long return (err);
6345da69b8f9SSean Bruno }
6346da69b8f9SSean Bruno if (type == IFLIB_INTR_ADMIN)
6347da69b8f9SSean Bruno return (0);
6348da69b8f9SSean Bruno
63494c7070dbSScott Long if (tqrid != -1) {
6350ca7005f1SPatrick Kelsey err = iflib_irq_set_affinity(ctx, irq, type, qid, gtask, tqg, q,
6351ca7005f1SPatrick Kelsey name);
6352b103855eSStephen Hurd if (err)
6353b103855eSStephen Hurd return (err);
6354aa3c5dd8SSean Bruno } else {
6355f855ec81SMarius Strobl taskqgroup_attach(tqg, gtask, q, dev, irq->ii_res, name);
6356aa3c5dd8SSean Bruno }
63574c7070dbSScott Long
63584c7070dbSScott Long return (0);
63594c7070dbSScott Long }
63604c7070dbSScott Long
63614c7070dbSScott Long void
iflib_softirq_alloc_generic(if_ctx_t ctx,if_irq_t irq,iflib_intr_type_t type,void * arg,int qid,const char * name)63627f527d48SEric Joyner iflib_softirq_alloc_generic(if_ctx_t ctx, if_irq_t irq, iflib_intr_type_t type,
63637f527d48SEric Joyner void *arg, int qid, const char *name)
63644c7070dbSScott Long {
6365ca7005f1SPatrick Kelsey device_t dev;
63664c7070dbSScott Long struct grouptask *gtask;
63674c7070dbSScott Long struct taskqgroup *tqg;
636823ac9029SStephen Hurd gtask_fn_t *fn;
63694c7070dbSScott Long void *q;
6370b103855eSStephen Hurd int err;
63714c7070dbSScott Long
63724c7070dbSScott Long switch (type) {
63734c7070dbSScott Long case IFLIB_INTR_TX:
63744c7070dbSScott Long q = &ctx->ifc_txqs[qid];
63754c7070dbSScott Long gtask = &ctx->ifc_txqs[qid].ift_task;
6376ab2e3f79SStephen Hurd tqg = qgroup_if_io_tqg;
63774c7070dbSScott Long fn = _task_fn_tx;
6378f98977b5SHans Petter Selasky GROUPTASK_INIT(gtask, 0, fn, q);
63794c7070dbSScott Long break;
63804c7070dbSScott Long case IFLIB_INTR_RX:
63814c7070dbSScott Long q = &ctx->ifc_rxqs[qid];
63824c7070dbSScott Long gtask = &ctx->ifc_rxqs[qid].ifr_task;
6383ab2e3f79SStephen Hurd tqg = qgroup_if_io_tqg;
63844c7070dbSScott Long fn = _task_fn_rx;
6385f98977b5SHans Petter Selasky NET_GROUPTASK_INIT(gtask, 0, fn, q);
63864c7070dbSScott Long break;
63874c7070dbSScott Long case IFLIB_INTR_IOV:
63884c7070dbSScott Long q = ctx;
63894c7070dbSScott Long gtask = &ctx->ifc_vflr_task;
6390ab2e3f79SStephen Hurd tqg = qgroup_if_config_tqg;
63914c7070dbSScott Long fn = _task_fn_iov;
6392f98977b5SHans Petter Selasky GROUPTASK_INIT(gtask, 0, fn, q);
63934c7070dbSScott Long break;
63944c7070dbSScott Long default:
63954c7070dbSScott Long panic("unknown net intr type");
63964c7070dbSScott Long }
6397ca7005f1SPatrick Kelsey err = iflib_irq_set_affinity(ctx, irq, type, qid, gtask, tqg, q, name);
6398ca7005f1SPatrick Kelsey if (err) {
6399ca7005f1SPatrick Kelsey dev = ctx->ifc_dev;
6400ca7005f1SPatrick Kelsey taskqgroup_attach(tqg, gtask, q, dev, irq ? irq->ii_res : NULL,
6401ca7005f1SPatrick Kelsey name);
6402b103855eSStephen Hurd }
6403b103855eSStephen Hurd }
64044c7070dbSScott Long
64054c7070dbSScott Long void
iflib_irq_free(if_ctx_t ctx,if_irq_t irq)64064c7070dbSScott Long iflib_irq_free(if_ctx_t ctx, if_irq_t irq)
64074c7070dbSScott Long {
6408b97de13aSMarius Strobl
64094c7070dbSScott Long if (irq->ii_tag)
64104c7070dbSScott Long bus_teardown_intr(ctx->ifc_dev, irq->ii_res, irq->ii_tag);
64114c7070dbSScott Long
64124c7070dbSScott Long if (irq->ii_res)
6413b97de13aSMarius Strobl bus_release_resource(ctx->ifc_dev, SYS_RES_IRQ,
6414b97de13aSMarius Strobl rman_get_rid(irq->ii_res), irq->ii_res);
64154c7070dbSScott Long }
64164c7070dbSScott Long
64174c7070dbSScott Long static int
iflib_legacy_setup(if_ctx_t ctx,driver_filter_t filter,void * filter_arg,int * rid,const char * name)64183e0e6330SStephen Hurd iflib_legacy_setup(if_ctx_t ctx, driver_filter_t filter, void *filter_arg, int *rid, const char *name)
64194c7070dbSScott Long {
64204c7070dbSScott Long iflib_txq_t txq = ctx->ifc_txqs;
64214c7070dbSScott Long iflib_rxq_t rxq = ctx->ifc_rxqs;
64224c7070dbSScott Long if_irq_t irq = &ctx->ifc_legacy_irq;
64234c7070dbSScott Long iflib_filter_info_t info;
6424f855ec81SMarius Strobl device_t dev;
64254c7070dbSScott Long struct grouptask *gtask;
6426f855ec81SMarius Strobl struct resource *res;
6427d49e83eaSMarius Strobl int err, tqrid;
642841669133SMark Johnston bool rx_only;
64294c7070dbSScott Long
643036a00192SKrzysztof Galazka info = &rxq->ifr_filter_info;
643136a00192SKrzysztof Galazka gtask = &rxq->ifr_task;
6432d49e83eaSMarius Strobl tqrid = *rid;
643341669133SMark Johnston rx_only = (ctx->ifc_sctx->isc_flags & IFLIB_SINGLE_IRQ_RX_ONLY) != 0;
64344c7070dbSScott Long
64354c7070dbSScott Long ctx->ifc_flags |= IFC_LEGACY;
64364c7070dbSScott Long info->ifi_filter = filter;
64374c7070dbSScott Long info->ifi_filter_arg = filter_arg;
64384c7070dbSScott Long info->ifi_task = gtask;
643936a00192SKrzysztof Galazka info->ifi_ctx = rxq;
64404c7070dbSScott Long
6441f855ec81SMarius Strobl dev = ctx->ifc_dev;
64424c7070dbSScott Long /* We allocate a single interrupt resource */
644336a00192SKrzysztof Galazka err = _iflib_irq_alloc(ctx, irq, tqrid, rx_only ? iflib_fast_intr :
644441669133SMark Johnston iflib_fast_intr_rxtx, NULL, info, name);
644541669133SMark Johnston if (err != 0)
64464c7070dbSScott Long return (err);
644736a00192SKrzysztof Galazka NET_GROUPTASK_INIT(gtask, 0, _task_fn_rx, rxq);
6448f855ec81SMarius Strobl res = irq->ii_res;
644936a00192SKrzysztof Galazka taskqgroup_attach(qgroup_if_io_tqg, gtask, rxq, dev, res, name);
64504c7070dbSScott Long
64514c7070dbSScott Long GROUPTASK_INIT(&txq->ift_task, 0, _task_fn_tx, txq);
6452f855ec81SMarius Strobl taskqgroup_attach(qgroup_if_io_tqg, &txq->ift_task, txq, dev, res,
6453f855ec81SMarius Strobl "tx");
64544c7070dbSScott Long return (0);
64554c7070dbSScott Long }
64564c7070dbSScott Long
64574c7070dbSScott Long void
iflib_led_create(if_ctx_t ctx)64584c7070dbSScott Long iflib_led_create(if_ctx_t ctx)
64594c7070dbSScott Long {
64604c7070dbSScott Long
64614c7070dbSScott Long ctx->ifc_led_dev = led_create(iflib_led_func, ctx,
64624c7070dbSScott Long device_get_nameunit(ctx->ifc_dev));
64634c7070dbSScott Long }
64644c7070dbSScott Long
64654c7070dbSScott Long void
iflib_tx_intr_deferred(if_ctx_t ctx,int txqid)64664c7070dbSScott Long iflib_tx_intr_deferred(if_ctx_t ctx, int txqid)
64674c7070dbSScott Long {
64684c7070dbSScott Long
64694c7070dbSScott Long GROUPTASK_ENQUEUE(&ctx->ifc_txqs[txqid].ift_task);
64704c7070dbSScott Long }
64714c7070dbSScott Long
64724c7070dbSScott Long void
iflib_rx_intr_deferred(if_ctx_t ctx,int rxqid)64734c7070dbSScott Long iflib_rx_intr_deferred(if_ctx_t ctx, int rxqid)
64744c7070dbSScott Long {
64754c7070dbSScott Long
64764c7070dbSScott Long GROUPTASK_ENQUEUE(&ctx->ifc_rxqs[rxqid].ifr_task);
64774c7070dbSScott Long }
64784c7070dbSScott Long
64794c7070dbSScott Long void
iflib_admin_intr_deferred(if_ctx_t ctx)64804c7070dbSScott Long iflib_admin_intr_deferred(if_ctx_t ctx)
64814c7070dbSScott Long {
648246fa0c25SEric Joyner
6483ed6611ccSEd Maste MPASS(ctx->ifc_admin_task.gt_taskqueue != NULL);
64844c7070dbSScott Long GROUPTASK_ENQUEUE(&ctx->ifc_admin_task);
64854c7070dbSScott Long }
64864c7070dbSScott Long
64874c7070dbSScott Long void
iflib_iov_intr_deferred(if_ctx_t ctx)64884c7070dbSScott Long iflib_iov_intr_deferred(if_ctx_t ctx)
64894c7070dbSScott Long {
64904c7070dbSScott Long
64914c7070dbSScott Long GROUPTASK_ENQUEUE(&ctx->ifc_vflr_task);
64924c7070dbSScott Long }
64934c7070dbSScott Long
64944c7070dbSScott Long void
iflib_io_tqg_attach(struct grouptask * gt,void * uniq,int cpu,const char * name)6495d49e83eaSMarius Strobl iflib_io_tqg_attach(struct grouptask *gt, void *uniq, int cpu, const char *name)
64964c7070dbSScott Long {
64974c7070dbSScott Long
6498f855ec81SMarius Strobl taskqgroup_attach_cpu(qgroup_if_io_tqg, gt, uniq, cpu, NULL, NULL,
6499f855ec81SMarius Strobl name);
65004c7070dbSScott Long }
65014c7070dbSScott Long
65024c7070dbSScott Long void
iflib_config_gtask_init(void * ctx,struct grouptask * gtask,gtask_fn_t * fn,const char * name)6503aa8a24d3SStephen Hurd iflib_config_gtask_init(void *ctx, struct grouptask *gtask, gtask_fn_t *fn,
6504aa8a24d3SStephen Hurd const char *name)
65054c7070dbSScott Long {
65064c7070dbSScott Long
65074c7070dbSScott Long GROUPTASK_INIT(gtask, 0, fn, ctx);
6508f855ec81SMarius Strobl taskqgroup_attach(qgroup_if_config_tqg, gtask, gtask, NULL, NULL,
6509f855ec81SMarius Strobl name);
65104c7070dbSScott Long }
65114c7070dbSScott Long
65124c7070dbSScott Long void
iflib_config_gtask_deinit(struct grouptask * gtask)651323ac9029SStephen Hurd iflib_config_gtask_deinit(struct grouptask *gtask)
651423ac9029SStephen Hurd {
651523ac9029SStephen Hurd
6516ab2e3f79SStephen Hurd taskqgroup_detach(qgroup_if_config_tqg, gtask);
651723ac9029SStephen Hurd }
651823ac9029SStephen Hurd
651923ac9029SStephen Hurd void
iflib_link_state_change(if_ctx_t ctx,int link_state,uint64_t baudrate)652023ac9029SStephen Hurd iflib_link_state_change(if_ctx_t ctx, int link_state, uint64_t baudrate)
65214c7070dbSScott Long {
65224c7070dbSScott Long if_t ifp = ctx->ifc_ifp;
65234c7070dbSScott Long iflib_txq_t txq = ctx->ifc_txqs;
65244c7070dbSScott Long
65254c7070dbSScott Long if_setbaudrate(ifp, baudrate);
65267b610b60SSean Bruno if (baudrate >= IF_Gbps(10)) {
65277b610b60SSean Bruno STATE_LOCK(ctx);
652895246abbSSean Bruno ctx->ifc_flags |= IFC_PREFETCH;
65297b610b60SSean Bruno STATE_UNLOCK(ctx);
65307b610b60SSean Bruno }
65314c7070dbSScott Long /* If link down, disable watchdog */
65324c7070dbSScott Long if ((ctx->ifc_link_state == LINK_STATE_UP) && (link_state == LINK_STATE_DOWN)) {
65334c7070dbSScott Long for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxqsets; i++, txq++)
65344c7070dbSScott Long txq->ift_qstatus = IFLIB_QUEUE_IDLE;
65354c7070dbSScott Long }
65364c7070dbSScott Long ctx->ifc_link_state = link_state;
65374c7070dbSScott Long if_link_state_change(ifp, link_state);
65384c7070dbSScott Long }
65394c7070dbSScott Long
65404c7070dbSScott Long static int
iflib_tx_credits_update(if_ctx_t ctx,iflib_txq_t txq)65414c7070dbSScott Long iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq)
65424c7070dbSScott Long {
65434c7070dbSScott Long int credits;
65441248952aSSean Bruno #ifdef INVARIANTS
65451248952aSSean Bruno int credits_pre = txq->ift_cidx_processed;
65461248952aSSean Bruno #endif
65474c7070dbSScott Long
65488a04b53dSKonstantin Belousov bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
65498a04b53dSKonstantin Belousov BUS_DMASYNC_POSTREAD);
655095246abbSSean Bruno if ((credits = ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, true)) == 0)
65514c7070dbSScott Long return (0);
65524c7070dbSScott Long
65534c7070dbSScott Long txq->ift_processed += credits;
65544c7070dbSScott Long txq->ift_cidx_processed += credits;
65554c7070dbSScott Long
65561248952aSSean Bruno MPASS(credits_pre + credits == txq->ift_cidx_processed);
65574c7070dbSScott Long if (txq->ift_cidx_processed >= txq->ift_size)
65584c7070dbSScott Long txq->ift_cidx_processed -= txq->ift_size;
65594c7070dbSScott Long return (credits);
65604c7070dbSScott Long }
65614c7070dbSScott Long
65624c7070dbSScott Long static int
iflib_rxd_avail(if_ctx_t ctx,iflib_rxq_t rxq,qidx_t cidx,qidx_t budget)656395246abbSSean Bruno iflib_rxd_avail(if_ctx_t ctx, iflib_rxq_t rxq, qidx_t cidx, qidx_t budget)
65644c7070dbSScott Long {
656595dcf343SMarius Strobl iflib_fl_t fl;
656695dcf343SMarius Strobl u_int i;
65674c7070dbSScott Long
656895dcf343SMarius Strobl for (i = 0, fl = &rxq->ifr_fl[0]; i < rxq->ifr_nfl; i++, fl++)
656995dcf343SMarius Strobl bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
657095dcf343SMarius Strobl BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
657123ac9029SStephen Hurd return (ctx->isc_rxd_available(ctx->ifc_softc, rxq->ifr_id, cidx,
657223ac9029SStephen Hurd budget));
65734c7070dbSScott Long }
65744c7070dbSScott Long
65754c7070dbSScott Long void
iflib_add_int_delay_sysctl(if_ctx_t ctx,const char * name,const char * description,if_int_delay_info_t info,int offset,int value)65764c7070dbSScott Long iflib_add_int_delay_sysctl(if_ctx_t ctx, const char *name,
65774c7070dbSScott Long const char *description, if_int_delay_info_t info,
65784c7070dbSScott Long int offset, int value)
65794c7070dbSScott Long {
65804c7070dbSScott Long info->iidi_ctx = ctx;
65814c7070dbSScott Long info->iidi_offset = offset;
65824c7070dbSScott Long info->iidi_value = value;
65834c7070dbSScott Long SYSCTL_ADD_PROC(device_get_sysctl_ctx(ctx->ifc_dev),
65844c7070dbSScott Long SYSCTL_CHILDREN(device_get_sysctl_tree(ctx->ifc_dev)),
65857029da5cSPawel Biernacki OID_AUTO, name, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
65864c7070dbSScott Long info, 0, iflib_sysctl_int_delay, "I", description);
65874c7070dbSScott Long }
65884c7070dbSScott Long
6589aa8a24d3SStephen Hurd struct sx *
iflib_ctx_lock_get(if_ctx_t ctx)65904c7070dbSScott Long iflib_ctx_lock_get(if_ctx_t ctx)
65914c7070dbSScott Long {
65924c7070dbSScott Long
6593aa8a24d3SStephen Hurd return (&ctx->ifc_ctx_sx);
65944c7070dbSScott Long }
65954c7070dbSScott Long
65964c7070dbSScott Long static int
iflib_msix_init(if_ctx_t ctx)65974c7070dbSScott Long iflib_msix_init(if_ctx_t ctx)
65984c7070dbSScott Long {
65994c7070dbSScott Long device_t dev = ctx->ifc_dev;
66004c7070dbSScott Long if_shared_ctx_t sctx = ctx->ifc_sctx;
66014c7070dbSScott Long if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
66023d10e9edSMarius Strobl int admincnt, bar, err, iflib_num_rx_queues, iflib_num_tx_queues;
66033d10e9edSMarius Strobl int msgs, queuemsgs, queues, rx_queues, tx_queues, vectors;
66044c7070dbSScott Long
6605d2735264SStephen Hurd iflib_num_tx_queues = ctx->ifc_sysctl_ntxqs;
6606d2735264SStephen Hurd iflib_num_rx_queues = ctx->ifc_sysctl_nrxqs;
660723ac9029SStephen Hurd
6608b97de13aSMarius Strobl if (bootverbose)
6609b97de13aSMarius Strobl device_printf(dev, "msix_init qsets capped at %d\n",
6610b97de13aSMarius Strobl imax(scctx->isc_ntxqsets, scctx->isc_nrxqsets));
66111248952aSSean Bruno
66124c7070dbSScott Long /* Override by tuneable */
6613ea351d3fSSean Bruno if (scctx->isc_disable_msix)
66144c7070dbSScott Long goto msi;
66154c7070dbSScott Long
6616b97de13aSMarius Strobl /* First try MSI-X */
6617b97de13aSMarius Strobl if ((msgs = pci_msix_count(dev)) == 0) {
6618b97de13aSMarius Strobl if (bootverbose)
6619b97de13aSMarius Strobl device_printf(dev, "MSI-X not supported or disabled\n");
6620b97de13aSMarius Strobl goto msi;
6621b97de13aSMarius Strobl }
66223d10e9edSMarius Strobl
66233d10e9edSMarius Strobl bar = ctx->ifc_softc_ctx.isc_msix_bar;
66244c7070dbSScott Long /*
66254c7070dbSScott Long * bar == -1 => "trust me I know what I'm doing"
66264c7070dbSScott Long * Some drivers are for hardware that is so shoddily
66274c7070dbSScott Long * documented that no one knows which bars are which
66284c7070dbSScott Long * so the developer has to map all bars. This hack
6629b97de13aSMarius Strobl * allows shoddy garbage to use MSI-X in this framework.
66304c7070dbSScott Long */
66314c7070dbSScott Long if (bar != -1) {
66324c7070dbSScott Long ctx->ifc_msix_mem = bus_alloc_resource_any(dev,
66334c7070dbSScott Long SYS_RES_MEMORY, &bar, RF_ACTIVE);
66344c7070dbSScott Long if (ctx->ifc_msix_mem == NULL) {
6635b97de13aSMarius Strobl device_printf(dev, "Unable to map MSI-X table\n");
66364c7070dbSScott Long goto msi;
66374c7070dbSScott Long }
66384c7070dbSScott Long }
66393d10e9edSMarius Strobl
66403d10e9edSMarius Strobl admincnt = sctx->isc_admin_intrcnt;
66414c7070dbSScott Long #if IFLIB_DEBUG
66424c7070dbSScott Long /* use only 1 qset in debug mode */
66434c7070dbSScott Long queuemsgs = min(msgs - admincnt, 1);
66444c7070dbSScott Long #else
66454c7070dbSScott Long queuemsgs = msgs - admincnt;
66464c7070dbSScott Long #endif
66474c7070dbSScott Long #ifdef RSS
66484c7070dbSScott Long queues = imin(queuemsgs, rss_getnumbuckets());
66494c7070dbSScott Long #else
66504c7070dbSScott Long queues = queuemsgs;
66514c7070dbSScott Long #endif
66524c7070dbSScott Long queues = imin(CPU_COUNT(&ctx->ifc_cpus), queues);
6653b97de13aSMarius Strobl if (bootverbose)
6654b97de13aSMarius Strobl device_printf(dev,
6655b97de13aSMarius Strobl "intr CPUs: %d queue msgs: %d admincnt: %d\n",
66564c7070dbSScott Long CPU_COUNT(&ctx->ifc_cpus), queuemsgs, admincnt);
66574c7070dbSScott Long #ifdef RSS
66584c7070dbSScott Long /* If we're doing RSS, clamp at the number of RSS buckets */
66594c7070dbSScott Long if (queues > rss_getnumbuckets())
66604c7070dbSScott Long queues = rss_getnumbuckets();
66614c7070dbSScott Long #endif
666223ac9029SStephen Hurd if (iflib_num_rx_queues > 0 && iflib_num_rx_queues < queuemsgs - admincnt)
666323ac9029SStephen Hurd rx_queues = iflib_num_rx_queues;
66644c7070dbSScott Long else
66654c7070dbSScott Long rx_queues = queues;
6666d2735264SStephen Hurd
6667d2735264SStephen Hurd if (rx_queues > scctx->isc_nrxqsets)
6668d2735264SStephen Hurd rx_queues = scctx->isc_nrxqsets;
6669d2735264SStephen Hurd
667023ac9029SStephen Hurd /*
667123ac9029SStephen Hurd * We want this to be all logical CPUs by default
667223ac9029SStephen Hurd */
66734c7070dbSScott Long if (iflib_num_tx_queues > 0 && iflib_num_tx_queues < queues)
66744c7070dbSScott Long tx_queues = iflib_num_tx_queues;
66754c7070dbSScott Long else
667623ac9029SStephen Hurd tx_queues = mp_ncpus;
667723ac9029SStephen Hurd
6678d2735264SStephen Hurd if (tx_queues > scctx->isc_ntxqsets)
6679d2735264SStephen Hurd tx_queues = scctx->isc_ntxqsets;
6680d2735264SStephen Hurd
668123ac9029SStephen Hurd if (ctx->ifc_sysctl_qs_eq_override == 0) {
668223ac9029SStephen Hurd #ifdef INVARIANTS
668323ac9029SStephen Hurd if (tx_queues != rx_queues)
668477c1fcecSEric Joyner device_printf(dev,
668577c1fcecSEric Joyner "queue equality override not set, capping rx_queues at %d and tx_queues at %d\n",
668623ac9029SStephen Hurd min(rx_queues, tx_queues), min(rx_queues, tx_queues));
668723ac9029SStephen Hurd #endif
668823ac9029SStephen Hurd tx_queues = min(rx_queues, tx_queues);
668923ac9029SStephen Hurd rx_queues = min(rx_queues, tx_queues);
669023ac9029SStephen Hurd }
66914c7070dbSScott Long
66923d10e9edSMarius Strobl vectors = rx_queues + admincnt;
66933d10e9edSMarius Strobl if (msgs < vectors) {
66943d10e9edSMarius Strobl device_printf(dev,
66953d10e9edSMarius Strobl "insufficient number of MSI-X vectors "
66963d10e9edSMarius Strobl "(supported %d, need %d)\n", msgs, vectors);
66973d10e9edSMarius Strobl goto msi;
66983d10e9edSMarius Strobl }
66993d10e9edSMarius Strobl
67001722eeacSMarius Strobl device_printf(dev, "Using %d RX queues %d TX queues\n", rx_queues,
67011722eeacSMarius Strobl tx_queues);
67023d10e9edSMarius Strobl msgs = vectors;
67034c7070dbSScott Long if ((err = pci_alloc_msix(dev, &vectors)) == 0) {
67043d10e9edSMarius Strobl if (vectors != msgs) {
67053d10e9edSMarius Strobl device_printf(dev,
67063d10e9edSMarius Strobl "Unable to allocate sufficient MSI-X vectors "
67073d10e9edSMarius Strobl "(got %d, need %d)\n", vectors, msgs);
67083d10e9edSMarius Strobl pci_release_msi(dev);
67093d10e9edSMarius Strobl if (bar != -1) {
67103d10e9edSMarius Strobl bus_release_resource(dev, SYS_RES_MEMORY, bar,
67113d10e9edSMarius Strobl ctx->ifc_msix_mem);
67123d10e9edSMarius Strobl ctx->ifc_msix_mem = NULL;
67133d10e9edSMarius Strobl }
67143d10e9edSMarius Strobl goto msi;
67153d10e9edSMarius Strobl }
6716b97de13aSMarius Strobl device_printf(dev, "Using MSI-X interrupts with %d vectors\n",
6717b97de13aSMarius Strobl vectors);
67184c7070dbSScott Long scctx->isc_vectors = vectors;
67194c7070dbSScott Long scctx->isc_nrxqsets = rx_queues;
67204c7070dbSScott Long scctx->isc_ntxqsets = tx_queues;
67214c7070dbSScott Long scctx->isc_intr = IFLIB_INTR_MSIX;
672223ac9029SStephen Hurd
67234c7070dbSScott Long return (vectors);
67244c7070dbSScott Long } else {
672577c1fcecSEric Joyner device_printf(dev,
67263d10e9edSMarius Strobl "failed to allocate %d MSI-X vectors, err: %d\n", vectors,
67273d10e9edSMarius Strobl err);
67283d10e9edSMarius Strobl if (bar != -1) {
6729e4defe55SMarius Strobl bus_release_resource(dev, SYS_RES_MEMORY, bar,
6730e4defe55SMarius Strobl ctx->ifc_msix_mem);
6731e4defe55SMarius Strobl ctx->ifc_msix_mem = NULL;
67324c7070dbSScott Long }
67333d10e9edSMarius Strobl }
67343d10e9edSMarius Strobl
67354c7070dbSScott Long msi:
67364c7070dbSScott Long vectors = pci_msi_count(dev);
67374c7070dbSScott Long scctx->isc_nrxqsets = 1;
67384c7070dbSScott Long scctx->isc_ntxqsets = 1;
67394c7070dbSScott Long scctx->isc_vectors = vectors;
67404c7070dbSScott Long if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) {
67414c7070dbSScott Long device_printf(dev, "Using an MSI interrupt\n");
67424c7070dbSScott Long scctx->isc_intr = IFLIB_INTR_MSI;
67434c7070dbSScott Long } else {
6744e4defe55SMarius Strobl scctx->isc_vectors = 1;
67454c7070dbSScott Long device_printf(dev, "Using a Legacy interrupt\n");
67464c7070dbSScott Long scctx->isc_intr = IFLIB_INTR_LEGACY;
67474c7070dbSScott Long }
67484c7070dbSScott Long
67494c7070dbSScott Long return (vectors);
67504c7070dbSScott Long }
67514c7070dbSScott Long
6752e4defe55SMarius Strobl static const char *ring_states[] = { "IDLE", "BUSY", "STALLED", "ABDICATED" };
67534c7070dbSScott Long
67544c7070dbSScott Long static int
mp_ring_state_handler(SYSCTL_HANDLER_ARGS)67554c7070dbSScott Long mp_ring_state_handler(SYSCTL_HANDLER_ARGS)
67564c7070dbSScott Long {
67574c7070dbSScott Long int rc;
67584c7070dbSScott Long uint16_t *state = ((uint16_t *)oidp->oid_arg1);
67594c7070dbSScott Long struct sbuf *sb;
6760e4defe55SMarius Strobl const char *ring_state = "UNKNOWN";
67614c7070dbSScott Long
67624c7070dbSScott Long /* XXX needed ? */
67634c7070dbSScott Long rc = sysctl_wire_old_buffer(req, 0);
67644c7070dbSScott Long MPASS(rc == 0);
67654c7070dbSScott Long if (rc != 0)
67664c7070dbSScott Long return (rc);
67674c7070dbSScott Long sb = sbuf_new_for_sysctl(NULL, NULL, 80, req);
67684c7070dbSScott Long MPASS(sb != NULL);
67694c7070dbSScott Long if (sb == NULL)
67704c7070dbSScott Long return (ENOMEM);
67714c7070dbSScott Long if (state[3] <= 3)
67724c7070dbSScott Long ring_state = ring_states[state[3]];
67734c7070dbSScott Long
67744c7070dbSScott Long sbuf_printf(sb, "pidx_head: %04hd pidx_tail: %04hd cidx: %04hd state: %s",
67754c7070dbSScott Long state[0], state[1], state[2], ring_state);
67764c7070dbSScott Long rc = sbuf_finish(sb);
67774c7070dbSScott Long sbuf_delete(sb);
67784c7070dbSScott Long return (rc);
67794c7070dbSScott Long }
67804c7070dbSScott Long
678123ac9029SStephen Hurd enum iflib_ndesc_handler {
678223ac9029SStephen Hurd IFLIB_NTXD_HANDLER,
678323ac9029SStephen Hurd IFLIB_NRXD_HANDLER,
678423ac9029SStephen Hurd };
67854c7070dbSScott Long
678623ac9029SStephen Hurd static int
mp_ndesc_handler(SYSCTL_HANDLER_ARGS)678723ac9029SStephen Hurd mp_ndesc_handler(SYSCTL_HANDLER_ARGS)
678823ac9029SStephen Hurd {
678923ac9029SStephen Hurd if_ctx_t ctx = (void *)arg1;
679023ac9029SStephen Hurd enum iflib_ndesc_handler type = arg2;
679123ac9029SStephen Hurd char buf[256] = {0};
679295246abbSSean Bruno qidx_t *ndesc;
679323ac9029SStephen Hurd char *p, *next;
679423ac9029SStephen Hurd int nqs, rc, i;
679523ac9029SStephen Hurd
679623ac9029SStephen Hurd nqs = 8;
679723ac9029SStephen Hurd switch (type) {
679823ac9029SStephen Hurd case IFLIB_NTXD_HANDLER:
679923ac9029SStephen Hurd ndesc = ctx->ifc_sysctl_ntxds;
680023ac9029SStephen Hurd if (ctx->ifc_sctx)
680123ac9029SStephen Hurd nqs = ctx->ifc_sctx->isc_ntxqs;
680223ac9029SStephen Hurd break;
680323ac9029SStephen Hurd case IFLIB_NRXD_HANDLER:
680423ac9029SStephen Hurd ndesc = ctx->ifc_sysctl_nrxds;
680523ac9029SStephen Hurd if (ctx->ifc_sctx)
680623ac9029SStephen Hurd nqs = ctx->ifc_sctx->isc_nrxqs;
680723ac9029SStephen Hurd break;
68081ae4848cSMatt Macy default:
68093d10e9edSMarius Strobl printf("%s: unhandled type\n", __func__);
68103d10e9edSMarius Strobl return (EINVAL);
681123ac9029SStephen Hurd }
681223ac9029SStephen Hurd if (nqs == 0)
681323ac9029SStephen Hurd nqs = 8;
681423ac9029SStephen Hurd
681523ac9029SStephen Hurd for (i = 0; i < 8; i++) {
681623ac9029SStephen Hurd if (i >= nqs)
681723ac9029SStephen Hurd break;
681823ac9029SStephen Hurd if (i)
681923ac9029SStephen Hurd strcat(buf, ",");
682023ac9029SStephen Hurd sprintf(strchr(buf, 0), "%d", ndesc[i]);
682123ac9029SStephen Hurd }
682223ac9029SStephen Hurd
682323ac9029SStephen Hurd rc = sysctl_handle_string(oidp, buf, sizeof(buf), req);
682423ac9029SStephen Hurd if (rc || req->newptr == NULL)
6825fa7045f9SZhenlei Huang return (rc);
682623ac9029SStephen Hurd
682723ac9029SStephen Hurd for (i = 0, next = buf, p = strsep(&next, " ,"); i < 8 && p;
682823ac9029SStephen Hurd i++, p = strsep(&next, " ,")) {
682923ac9029SStephen Hurd ndesc[i] = strtoul(p, NULL, 10);
683023ac9029SStephen Hurd }
683123ac9029SStephen Hurd
683223ac9029SStephen Hurd return (rc);
683323ac9029SStephen Hurd }
68344c7070dbSScott Long
68354c7070dbSScott Long #define NAME_BUFLEN 32
68364c7070dbSScott Long static void
iflib_add_device_sysctl_pre(if_ctx_t ctx)68374c7070dbSScott Long iflib_add_device_sysctl_pre(if_ctx_t ctx)
68384c7070dbSScott Long {
68394c7070dbSScott Long device_t dev = iflib_get_dev(ctx);
68404c7070dbSScott Long struct sysctl_oid_list *child, *oid_list;
68414c7070dbSScott Long struct sysctl_ctx_list *ctx_list;
68424c7070dbSScott Long struct sysctl_oid *node;
68434c7070dbSScott Long
68444c7070dbSScott Long ctx_list = device_get_sysctl_ctx(dev);
68454c7070dbSScott Long child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
6846e4a0c92eSStephen J. Kiernan ctx->ifc_sysctl_node = node = SYSCTL_ADD_NODE(ctx_list, child,
6847e4a0c92eSStephen J. Kiernan OID_AUTO, "iflib", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
6848e4a0c92eSStephen J. Kiernan "IFLIB fields");
68494c7070dbSScott Long oid_list = SYSCTL_CHILDREN(node);
68504c7070dbSScott Long
685110a1e981SEric Joyner SYSCTL_ADD_CONST_STRING(ctx_list, oid_list, OID_AUTO, "driver_version",
6852e4a0c92eSStephen J. Kiernan CTLFLAG_RD, ctx->ifc_sctx->isc_driver_version, "driver version");
685323ac9029SStephen Hurd
68544c7070dbSScott Long SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_ntxqs",
68554c7070dbSScott Long CTLFLAG_RWTUN, &ctx->ifc_sysctl_ntxqs, 0,
68564c7070dbSScott Long "# of txqs to use, 0 => use default #");
68574c7070dbSScott Long SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_nrxqs",
685823ac9029SStephen Hurd CTLFLAG_RWTUN, &ctx->ifc_sysctl_nrxqs, 0,
685923ac9029SStephen Hurd "# of rxqs to use, 0 => use default #");
686023ac9029SStephen Hurd SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_qs_enable",
686123ac9029SStephen Hurd CTLFLAG_RWTUN, &ctx->ifc_sysctl_qs_eq_override, 0,
686223ac9029SStephen Hurd "permit #txq != #rxq");
6863ea351d3fSSean Bruno SYSCTL_ADD_INT(ctx_list, oid_list, OID_AUTO, "disable_msix",
6864ea351d3fSSean Bruno CTLFLAG_RWTUN, &ctx->ifc_softc_ctx.isc_disable_msix, 0,
6865b97de13aSMarius Strobl "disable MSI-X (default 0)");
6866f4d2154eSStephen Hurd SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "rx_budget",
6867e4a0c92eSStephen J. Kiernan CTLFLAG_RWTUN, &ctx->ifc_sysctl_rx_budget, 0, "set the RX budget");
6868fe51d4cdSStephen Hurd SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "tx_abdicate",
6869fe51d4cdSStephen Hurd CTLFLAG_RWTUN, &ctx->ifc_sysctl_tx_abdicate, 0,
68701722eeacSMarius Strobl "cause TX to abdicate instead of running to completion");
6871f154ece0SStephen Hurd ctx->ifc_sysctl_core_offset = CORE_OFFSET_UNSPECIFIED;
6872f154ece0SStephen Hurd SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "core_offset",
6873f154ece0SStephen Hurd CTLFLAG_RDTUN, &ctx->ifc_sysctl_core_offset, 0,
6874f154ece0SStephen Hurd "offset to start using cores at");
6875f154ece0SStephen Hurd SYSCTL_ADD_U8(ctx_list, oid_list, OID_AUTO, "separate_txrx",
6876f154ece0SStephen Hurd CTLFLAG_RDTUN, &ctx->ifc_sysctl_separate_txrx, 0,
6877f154ece0SStephen Hurd "use separate cores for TX and RX");
6878ca7005f1SPatrick Kelsey SYSCTL_ADD_U8(ctx_list, oid_list, OID_AUTO, "use_logical_cores",
6879ca7005f1SPatrick Kelsey CTLFLAG_RDTUN, &ctx->ifc_sysctl_use_logical_cores, 0,
6880ca7005f1SPatrick Kelsey "try to make use of logical cores for TX and RX");
68813c7da27aSEric Joyner SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "use_extra_msix_vectors",
68823c7da27aSEric Joyner CTLFLAG_RDTUN, &ctx->ifc_sysctl_extra_msix_vectors, 0,
68833c7da27aSEric Joyner "attempt to reserve the given number of extra MSI-X vectors during driver load for the creation of additional interfaces later");
68843c7da27aSEric Joyner SYSCTL_ADD_INT(ctx_list, oid_list, OID_AUTO, "allocated_msix_vectors",
68853c7da27aSEric Joyner CTLFLAG_RDTUN, &ctx->ifc_softc_ctx.isc_vectors, 0,
68863c7da27aSEric Joyner "total # of MSI-X vectors allocated by driver");
68874c7070dbSScott Long
688823ac9029SStephen Hurd /* XXX change for per-queue sizes */
688923ac9029SStephen Hurd SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_ntxds",
68907029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, ctx,
68917029da5cSPawel Biernacki IFLIB_NTXD_HANDLER, mp_ndesc_handler, "A",
68921722eeacSMarius Strobl "list of # of TX descriptors to use, 0 = use default #");
689323ac9029SStephen Hurd SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_nrxds",
68947029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, ctx,
68957029da5cSPawel Biernacki IFLIB_NRXD_HANDLER, mp_ndesc_handler, "A",
68961722eeacSMarius Strobl "list of # of RX descriptors to use, 0 = use default #");
68974c7070dbSScott Long }
68984c7070dbSScott Long
68994c7070dbSScott Long static void
iflib_add_device_sysctl_post(if_ctx_t ctx)69004c7070dbSScott Long iflib_add_device_sysctl_post(if_ctx_t ctx)
69014c7070dbSScott Long {
69024c7070dbSScott Long if_shared_ctx_t sctx = ctx->ifc_sctx;
69034c7070dbSScott Long if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
69044c7070dbSScott Long device_t dev = iflib_get_dev(ctx);
69054c7070dbSScott Long struct sysctl_oid_list *child;
69064c7070dbSScott Long struct sysctl_ctx_list *ctx_list;
69074c7070dbSScott Long iflib_fl_t fl;
69084c7070dbSScott Long iflib_txq_t txq;
69094c7070dbSScott Long iflib_rxq_t rxq;
69104c7070dbSScott Long int i, j;
69114c7070dbSScott Long char namebuf[NAME_BUFLEN];
69124c7070dbSScott Long char *qfmt;
69134c7070dbSScott Long struct sysctl_oid *queue_node, *fl_node, *node;
69144c7070dbSScott Long struct sysctl_oid_list *queue_list, *fl_list;
69154c7070dbSScott Long ctx_list = device_get_sysctl_ctx(dev);
69164c7070dbSScott Long
69174c7070dbSScott Long node = ctx->ifc_sysctl_node;
69184c7070dbSScott Long child = SYSCTL_CHILDREN(node);
69194c7070dbSScott Long
69204c7070dbSScott Long if (scctx->isc_ntxqsets > 100)
69214c7070dbSScott Long qfmt = "txq%03d";
69224c7070dbSScott Long else if (scctx->isc_ntxqsets > 10)
69234c7070dbSScott Long qfmt = "txq%02d";
69244c7070dbSScott Long else
69254c7070dbSScott Long qfmt = "txq%d";
69264c7070dbSScott Long for (i = 0, txq = ctx->ifc_txqs; i < scctx->isc_ntxqsets; i++, txq++) {
69274c7070dbSScott Long snprintf(namebuf, NAME_BUFLEN, qfmt, i);
69284c7070dbSScott Long queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf,
69297029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
69304c7070dbSScott Long queue_list = SYSCTL_CHILDREN(queue_node);
6931ca7005f1SPatrick Kelsey SYSCTL_ADD_INT(ctx_list, queue_list, OID_AUTO, "cpu",
6932e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &txq->ift_task.gt_cpu, 0,
6933e4a0c92eSStephen J. Kiernan "cpu this queue is bound to");
69344c7070dbSScott Long #if MEMORY_LOGGING
6935303dea74SStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, queue_list, OID_AUTO, "txq_dequeued",
6936e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &txq->ift_dequeued, "total mbufs freed");
6937303dea74SStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, queue_list, OID_AUTO, "txq_enqueued",
6938e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &txq->ift_enqueued, "total mbufs enqueued");
69394c7070dbSScott Long #endif
6940303dea74SStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, queue_list, OID_AUTO, "mbuf_defrag",
6941e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &txq->ift_mbuf_defrag,
6942e4a0c92eSStephen J. Kiernan "# of times m_defrag was called");
6943303dea74SStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, queue_list, OID_AUTO, "m_pullups",
6944e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &txq->ift_pullups,
6945e4a0c92eSStephen J. Kiernan "# of times m_pullup was called");
6946e4a0c92eSStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, queue_list, OID_AUTO,
6947e4a0c92eSStephen J. Kiernan "mbuf_defrag_failed", CTLFLAG_RD,
69484c7070dbSScott Long &txq->ift_mbuf_defrag_failed, "# of times m_defrag failed");
6949e4a0c92eSStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, queue_list, OID_AUTO,
6950e4a0c92eSStephen J. Kiernan "no_desc_avail", CTLFLAG_RD, &txq->ift_no_desc_avail,
6951e4a0c92eSStephen J. Kiernan "# of times no descriptors were available");
6952e4a0c92eSStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, queue_list, OID_AUTO,
6953e4a0c92eSStephen J. Kiernan "tx_map_failed", CTLFLAG_RD, &txq->ift_map_failed,
6954e4a0c92eSStephen J. Kiernan "# of times DMA map failed");
6955e4a0c92eSStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, queue_list, OID_AUTO,
6956e4a0c92eSStephen J. Kiernan "txd_encap_efbig", CTLFLAG_RD, &txq->ift_txd_encap_efbig,
6957e4a0c92eSStephen J. Kiernan "# of times txd_encap returned EFBIG");
6958e4a0c92eSStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, queue_list, OID_AUTO,
6959e4a0c92eSStephen J. Kiernan "no_tx_dma_setup", CTLFLAG_RD, &txq->ift_no_tx_dma_setup,
6960e4a0c92eSStephen J. Kiernan "# of times map failed for other than EFBIG");
69614c7070dbSScott Long SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_pidx",
6962e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &txq->ift_pidx, 1, "Producer Index");
69634c7070dbSScott Long SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_cidx",
6964e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &txq->ift_cidx, 1, "Consumer Index");
6965e4a0c92eSStephen J. Kiernan SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO,
6966e4a0c92eSStephen J. Kiernan "txq_cidx_processed", CTLFLAG_RD, &txq->ift_cidx_processed,
6967e4a0c92eSStephen J. Kiernan 1, "Consumer Index seen by credit update");
69684c7070dbSScott Long SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_in_use",
6969e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &txq->ift_in_use, 1, "descriptors in use");
6970e4a0c92eSStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, queue_list, OID_AUTO,
6971e4a0c92eSStephen J. Kiernan "txq_processed", CTLFLAG_RD, &txq->ift_processed,
6972e4a0c92eSStephen J. Kiernan "descriptors procesed for clean");
6973303dea74SStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, queue_list, OID_AUTO, "txq_cleaned",
6974e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &txq->ift_cleaned, "total cleaned");
69754c7070dbSScott Long SYSCTL_ADD_PROC(ctx_list, queue_list, OID_AUTO, "ring_state",
69767029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
69777029da5cSPawel Biernacki __DEVOLATILE(uint64_t *, &txq->ift_br->state), 0,
69787029da5cSPawel Biernacki mp_ring_state_handler, "A", "soft ring state");
6979e4a0c92eSStephen J. Kiernan SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO,
6980e4a0c92eSStephen J. Kiernan "r_enqueues", CTLFLAG_RD, &txq->ift_br->enqueues,
69814c7070dbSScott Long "# of enqueues to the mp_ring for this queue");
6982e4a0c92eSStephen J. Kiernan SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO,
6983e4a0c92eSStephen J. Kiernan "r_drops", CTLFLAG_RD, &txq->ift_br->drops,
69844c7070dbSScott Long "# of drops in the mp_ring for this queue");
6985e4a0c92eSStephen J. Kiernan SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO,
6986e4a0c92eSStephen J. Kiernan "r_starts", CTLFLAG_RD, &txq->ift_br->starts,
6987e4a0c92eSStephen J. Kiernan "# of normal consumer starts in mp_ring for this queue");
6988e4a0c92eSStephen J. Kiernan SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO,
6989e4a0c92eSStephen J. Kiernan "r_stalls", CTLFLAG_RD, &txq->ift_br->stalls,
69904c7070dbSScott Long "# of consumer stalls in the mp_ring for this queue");
6991e4a0c92eSStephen J. Kiernan SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO,
6992e4a0c92eSStephen J. Kiernan "r_restarts", CTLFLAG_RD, &txq->ift_br->restarts,
69934c7070dbSScott Long "# of consumer restarts in the mp_ring for this queue");
6994e4a0c92eSStephen J. Kiernan SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO,
6995e4a0c92eSStephen J. Kiernan "r_abdications", CTLFLAG_RD, &txq->ift_br->abdications,
69964c7070dbSScott Long "# of consumer abdications in the mp_ring for this queue");
69974c7070dbSScott Long }
69984c7070dbSScott Long
69994c7070dbSScott Long if (scctx->isc_nrxqsets > 100)
70004c7070dbSScott Long qfmt = "rxq%03d";
70014c7070dbSScott Long else if (scctx->isc_nrxqsets > 10)
70024c7070dbSScott Long qfmt = "rxq%02d";
70034c7070dbSScott Long else
70044c7070dbSScott Long qfmt = "rxq%d";
70054c7070dbSScott Long for (i = 0, rxq = ctx->ifc_rxqs; i < scctx->isc_nrxqsets; i++, rxq++) {
70064c7070dbSScott Long snprintf(namebuf, NAME_BUFLEN, qfmt, i);
70074c7070dbSScott Long queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf,
70087029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
70094c7070dbSScott Long queue_list = SYSCTL_CHILDREN(queue_node);
7010ca7005f1SPatrick Kelsey SYSCTL_ADD_INT(ctx_list, queue_list, OID_AUTO, "cpu",
7011e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &rxq->ifr_task.gt_cpu, 0,
7012e4a0c92eSStephen J. Kiernan "cpu this queue is bound to");
701323ac9029SStephen Hurd if (sctx->isc_flags & IFLIB_HAS_RXCQ) {
7014e4a0c92eSStephen J. Kiernan SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO,
7015e4a0c92eSStephen J. Kiernan "rxq_cq_cidx", CTLFLAG_RD, &rxq->ifr_cq_cidx, 1,
7016e4a0c92eSStephen J. Kiernan "Consumer Index");
70174c7070dbSScott Long }
7018da69b8f9SSean Bruno
70194c7070dbSScott Long for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) {
70204c7070dbSScott Long snprintf(namebuf, NAME_BUFLEN, "rxq_fl%d", j);
7021e4a0c92eSStephen J. Kiernan fl_node = SYSCTL_ADD_NODE(ctx_list, queue_list,
7022e4a0c92eSStephen J. Kiernan OID_AUTO, namebuf, CTLFLAG_RD | CTLFLAG_MPSAFE,
7023e4a0c92eSStephen J. Kiernan NULL, "freelist Name");
70244c7070dbSScott Long fl_list = SYSCTL_CHILDREN(fl_node);
70254c7070dbSScott Long SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "pidx",
7026e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &fl->ifl_pidx, 1, "Producer Index");
70274c7070dbSScott Long SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "cidx",
7028e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &fl->ifl_cidx, 1, "Consumer Index");
70294c7070dbSScott Long SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "credits",
7030e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &fl->ifl_credits, 1,
7031e4a0c92eSStephen J. Kiernan "credits available");
7032b3813609SPatrick Kelsey SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "buf_size",
7033e4a0c92eSStephen J. Kiernan CTLFLAG_RD, &fl->ifl_buf_size, 1, "buffer size");
70344c7070dbSScott Long #if MEMORY_LOGGING
7035e4a0c92eSStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, fl_list, OID_AUTO,
7036e4a0c92eSStephen J. Kiernan "fl_m_enqueued", CTLFLAG_RD, &fl->ifl_m_enqueued,
7037e4a0c92eSStephen J. Kiernan "mbufs allocated");
7038e4a0c92eSStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, fl_list, OID_AUTO,
7039e4a0c92eSStephen J. Kiernan "fl_m_dequeued", CTLFLAG_RD, &fl->ifl_m_dequeued,
7040e4a0c92eSStephen J. Kiernan "mbufs freed");
7041e4a0c92eSStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, fl_list, OID_AUTO,
7042e4a0c92eSStephen J. Kiernan "fl_cl_enqueued", CTLFLAG_RD, &fl->ifl_cl_enqueued,
7043e4a0c92eSStephen J. Kiernan "clusters allocated");
7044e4a0c92eSStephen J. Kiernan SYSCTL_ADD_UQUAD(ctx_list, fl_list, OID_AUTO,
7045e4a0c92eSStephen J. Kiernan "fl_cl_dequeued", CTLFLAG_RD, &fl->ifl_cl_dequeued,
7046e4a0c92eSStephen J. Kiernan "clusters freed");
70474c7070dbSScott Long #endif
70484c7070dbSScott Long }
70494c7070dbSScott Long }
70504c7070dbSScott Long
70514c7070dbSScott Long }
705295246abbSSean Bruno
705377c1fcecSEric Joyner void
iflib_request_reset(if_ctx_t ctx)705477c1fcecSEric Joyner iflib_request_reset(if_ctx_t ctx)
705577c1fcecSEric Joyner {
705677c1fcecSEric Joyner
705777c1fcecSEric Joyner STATE_LOCK(ctx);
705877c1fcecSEric Joyner ctx->ifc_flags |= IFC_DO_RESET;
705977c1fcecSEric Joyner STATE_UNLOCK(ctx);
706077c1fcecSEric Joyner }
706177c1fcecSEric Joyner
706295246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
706395246abbSSean Bruno static struct mbuf *
iflib_fixup_rx(struct mbuf * m)706495246abbSSean Bruno iflib_fixup_rx(struct mbuf *m)
706595246abbSSean Bruno {
706695246abbSSean Bruno struct mbuf *n;
706795246abbSSean Bruno
706895246abbSSean Bruno if (m->m_len <= (MCLBYTES - ETHER_HDR_LEN)) {
706995246abbSSean Bruno bcopy(m->m_data, m->m_data + ETHER_HDR_LEN, m->m_len);
707095246abbSSean Bruno m->m_data += ETHER_HDR_LEN;
707195246abbSSean Bruno n = m;
707295246abbSSean Bruno } else {
707395246abbSSean Bruno MGETHDR(n, M_NOWAIT, MT_DATA);
707495246abbSSean Bruno if (n == NULL) {
707595246abbSSean Bruno m_freem(m);
707695246abbSSean Bruno return (NULL);
707795246abbSSean Bruno }
707895246abbSSean Bruno bcopy(m->m_data, n->m_data, ETHER_HDR_LEN);
707995246abbSSean Bruno m->m_data += ETHER_HDR_LEN;
708095246abbSSean Bruno m->m_len -= ETHER_HDR_LEN;
708195246abbSSean Bruno n->m_len = ETHER_HDR_LEN;
708295246abbSSean Bruno M_MOVE_PKTHDR(n, m);
708395246abbSSean Bruno n->m_next = m;
708495246abbSSean Bruno }
708595246abbSSean Bruno return (n);
708695246abbSSean Bruno }
708795246abbSSean Bruno #endif
708894618825SMark Johnston
70897790c8c1SConrad Meyer #ifdef DEBUGNET
709094618825SMark Johnston static void
iflib_debugnet_init(if_t ifp,int * nrxr,int * ncl,int * clsize)70917790c8c1SConrad Meyer iflib_debugnet_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
709294618825SMark Johnston {
709394618825SMark Johnston if_ctx_t ctx;
709494618825SMark Johnston
709594618825SMark Johnston ctx = if_getsoftc(ifp);
709694618825SMark Johnston CTX_LOCK(ctx);
709794618825SMark Johnston *nrxr = NRXQSETS(ctx);
709894618825SMark Johnston *ncl = ctx->ifc_rxqs[0].ifr_fl->ifl_size;
709994618825SMark Johnston *clsize = ctx->ifc_rxqs[0].ifr_fl->ifl_buf_size;
710094618825SMark Johnston CTX_UNLOCK(ctx);
710194618825SMark Johnston }
710294618825SMark Johnston
710394618825SMark Johnston static void
iflib_debugnet_event(if_t ifp,enum debugnet_ev event)71047790c8c1SConrad Meyer iflib_debugnet_event(if_t ifp, enum debugnet_ev event)
710594618825SMark Johnston {
710694618825SMark Johnston if_ctx_t ctx;
710794618825SMark Johnston if_softc_ctx_t scctx;
710894618825SMark Johnston iflib_fl_t fl;
710994618825SMark Johnston iflib_rxq_t rxq;
711094618825SMark Johnston int i, j;
711194618825SMark Johnston
711294618825SMark Johnston ctx = if_getsoftc(ifp);
711394618825SMark Johnston scctx = &ctx->ifc_softc_ctx;
711494618825SMark Johnston
711594618825SMark Johnston switch (event) {
71167790c8c1SConrad Meyer case DEBUGNET_START:
711794618825SMark Johnston for (i = 0; i < scctx->isc_nrxqsets; i++) {
711894618825SMark Johnston rxq = &ctx->ifc_rxqs[i];
711994618825SMark Johnston for (j = 0; j < rxq->ifr_nfl; j++) {
712094618825SMark Johnston fl = rxq->ifr_fl;
712194618825SMark Johnston fl->ifl_zone = m_getzone(fl->ifl_buf_size);
712294618825SMark Johnston }
712394618825SMark Johnston }
712494618825SMark Johnston iflib_no_tx_batch = 1;
712594618825SMark Johnston break;
712694618825SMark Johnston default:
712794618825SMark Johnston break;
712894618825SMark Johnston }
712994618825SMark Johnston }
713094618825SMark Johnston
713194618825SMark Johnston static int
iflib_debugnet_transmit(if_t ifp,struct mbuf * m)71327790c8c1SConrad Meyer iflib_debugnet_transmit(if_t ifp, struct mbuf *m)
713394618825SMark Johnston {
713494618825SMark Johnston if_ctx_t ctx;
713594618825SMark Johnston iflib_txq_t txq;
713694618825SMark Johnston int error;
713794618825SMark Johnston
713894618825SMark Johnston ctx = if_getsoftc(ifp);
713994618825SMark Johnston if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
714094618825SMark Johnston IFF_DRV_RUNNING)
714194618825SMark Johnston return (EBUSY);
714294618825SMark Johnston
714394618825SMark Johnston txq = &ctx->ifc_txqs[0];
714494618825SMark Johnston error = iflib_encap(txq, &m);
714594618825SMark Johnston if (error == 0)
714681be6552SMatt Macy (void)iflib_txd_db_check(txq, true);
714794618825SMark Johnston return (error);
714894618825SMark Johnston }
714994618825SMark Johnston
715094618825SMark Johnston static int
iflib_debugnet_poll(if_t ifp,int count)71517790c8c1SConrad Meyer iflib_debugnet_poll(if_t ifp, int count)
715294618825SMark Johnston {
71530b8df657SGleb Smirnoff struct epoch_tracker et;
715494618825SMark Johnston if_ctx_t ctx;
715594618825SMark Johnston if_softc_ctx_t scctx;
715694618825SMark Johnston iflib_txq_t txq;
715794618825SMark Johnston int i;
715894618825SMark Johnston
715994618825SMark Johnston ctx = if_getsoftc(ifp);
716094618825SMark Johnston scctx = &ctx->ifc_softc_ctx;
716194618825SMark Johnston
716294618825SMark Johnston if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
716394618825SMark Johnston IFF_DRV_RUNNING)
716494618825SMark Johnston return (EBUSY);
716594618825SMark Johnston
716694618825SMark Johnston txq = &ctx->ifc_txqs[0];
716794618825SMark Johnston (void)iflib_completed_tx_reclaim(txq, RECLAIM_THRESH(ctx));
716894618825SMark Johnston
71690b8df657SGleb Smirnoff NET_EPOCH_ENTER(et);
717094618825SMark Johnston for (i = 0; i < scctx->isc_nrxqsets; i++)
717194618825SMark Johnston (void)iflib_rxeof(&ctx->ifc_rxqs[i], 16 /* XXX */);
71720b8df657SGleb Smirnoff NET_EPOCH_EXIT(et);
717394618825SMark Johnston return (0);
717494618825SMark Johnston }
71757790c8c1SConrad Meyer #endif /* DEBUGNET */
7176