xref: /freebsd/sys/net/iflib.c (revision 618d49f5cad1dfd59eab6561ecf93d053610609d)
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>
294c7070dbSScott Long __FBSDID("$FreeBSD$");
304c7070dbSScott Long 
31aaeb188aSBjoern A. Zeeb #include "opt_inet.h"
32aaeb188aSBjoern A. Zeeb #include "opt_inet6.h"
33aaeb188aSBjoern A. Zeeb #include "opt_acpi.h"
34b103855eSStephen Hurd #include "opt_sched.h"
35aaeb188aSBjoern A. Zeeb 
364c7070dbSScott Long #include <sys/param.h>
374c7070dbSScott Long #include <sys/types.h>
384c7070dbSScott Long #include <sys/bus.h>
394c7070dbSScott Long #include <sys/eventhandler.h>
404c7070dbSScott Long #include <sys/kernel.h>
414c7070dbSScott Long #include <sys/lock.h>
424c7070dbSScott Long #include <sys/mutex.h>
434c7070dbSScott Long #include <sys/module.h>
444c7070dbSScott Long #include <sys/kobj.h>
454c7070dbSScott Long #include <sys/rman.h>
464c7070dbSScott Long #include <sys/sbuf.h>
474c7070dbSScott Long #include <sys/smp.h>
484c7070dbSScott Long #include <sys/socket.h>
4909f6ff4fSMatt Macy #include <sys/sockio.h>
504c7070dbSScott Long #include <sys/sysctl.h>
514c7070dbSScott Long #include <sys/syslog.h>
524c7070dbSScott Long #include <sys/taskqueue.h>
5323ac9029SStephen Hurd #include <sys/limits.h>
544c7070dbSScott Long 
554c7070dbSScott Long #include <net/if.h>
564c7070dbSScott Long #include <net/if_var.h>
574c7070dbSScott Long #include <net/if_types.h>
584c7070dbSScott Long #include <net/if_media.h>
594c7070dbSScott Long #include <net/bpf.h>
604c7070dbSScott Long #include <net/ethernet.h>
614c7070dbSScott Long #include <net/mp_ring.h>
627790c8c1SConrad Meyer #include <net/debugnet.h>
636d49b41eSAndrew Gallatin #include <net/pfil.h>
6435e4e998SStephen Hurd #include <net/vnet.h>
654c7070dbSScott Long 
664c7070dbSScott Long #include <netinet/in.h>
674c7070dbSScott Long #include <netinet/in_pcb.h>
684c7070dbSScott Long #include <netinet/tcp_lro.h>
694c7070dbSScott Long #include <netinet/in_systm.h>
704c7070dbSScott Long #include <netinet/if_ether.h>
714c7070dbSScott Long #include <netinet/ip.h>
724c7070dbSScott Long #include <netinet/ip6.h>
734c7070dbSScott Long #include <netinet/tcp.h>
7435e4e998SStephen Hurd #include <netinet/ip_var.h>
7535e4e998SStephen Hurd #include <netinet6/ip6_var.h>
764c7070dbSScott Long 
774c7070dbSScott Long #include <machine/bus.h>
784c7070dbSScott Long #include <machine/in_cksum.h>
794c7070dbSScott Long 
804c7070dbSScott Long #include <vm/vm.h>
814c7070dbSScott Long #include <vm/pmap.h>
824c7070dbSScott Long 
834c7070dbSScott Long #include <dev/led/led.h>
844c7070dbSScott Long #include <dev/pci/pcireg.h>
854c7070dbSScott Long #include <dev/pci/pcivar.h>
864c7070dbSScott Long #include <dev/pci/pci_private.h>
874c7070dbSScott Long 
884c7070dbSScott Long #include <net/iflib.h>
8909f6ff4fSMatt Macy #include <net/iflib_private.h>
904c7070dbSScott Long 
914c7070dbSScott Long #include "ifdi_if.h"
924c7070dbSScott Long 
9377c1fcecSEric Joyner #ifdef PCI_IOV
9477c1fcecSEric Joyner #include <dev/pci/pci_iov.h>
9577c1fcecSEric Joyner #endif
9677c1fcecSEric Joyner 
9787890dbaSSean Bruno #include <sys/bitstring.h>
984c7070dbSScott Long /*
9995246abbSSean Bruno  * enable accounting of every mbuf as it comes in to and goes out of
10095246abbSSean Bruno  * iflib's software descriptor references
1014c7070dbSScott Long  */
1024c7070dbSScott Long #define MEMORY_LOGGING 0
1034c7070dbSScott Long /*
1044c7070dbSScott Long  * Enable mbuf vectors for compressing long mbuf chains
1054c7070dbSScott Long  */
1064c7070dbSScott Long 
1074c7070dbSScott Long /*
1084c7070dbSScott Long  * NB:
1094c7070dbSScott Long  * - Prefetching in tx cleaning should perhaps be a tunable. The distance ahead
1104c7070dbSScott Long  *   we prefetch needs to be determined by the time spent in m_free vis a vis
1114c7070dbSScott Long  *   the cost of a prefetch. This will of course vary based on the workload:
1124c7070dbSScott Long  *      - NFLX's m_free path is dominated by vm-based M_EXT manipulation which
1134c7070dbSScott Long  *        is quite expensive, thus suggesting very little prefetch.
1144c7070dbSScott Long  *      - small packet forwarding which is just returning a single mbuf to
1154c7070dbSScott Long  *        UMA will typically be very fast vis a vis the cost of a memory
1164c7070dbSScott Long  *        access.
1174c7070dbSScott Long  */
1184c7070dbSScott Long 
1194c7070dbSScott Long /*
1204c7070dbSScott Long  * File organization:
1214c7070dbSScott Long  *  - private structures
1224c7070dbSScott Long  *  - iflib private utility functions
1234c7070dbSScott Long  *  - ifnet functions
1244c7070dbSScott Long  *  - vlan registry and other exported functions
1254c7070dbSScott Long  *  - iflib public core functions
1264c7070dbSScott Long  *
1274c7070dbSScott Long  *
1284c7070dbSScott Long  */
12909f6ff4fSMatt Macy MALLOC_DEFINE(M_IFLIB, "iflib", "ifnet library");
1304c7070dbSScott Long 
131fb1a29b4SHans Petter Selasky #define	IFLIB_RXEOF_MORE (1U << 0)
132fb1a29b4SHans Petter Selasky #define	IFLIB_RXEOF_EMPTY (2U << 0)
133fb1a29b4SHans Petter Selasky 
1344c7070dbSScott Long struct iflib_txq;
1354c7070dbSScott Long typedef struct iflib_txq *iflib_txq_t;
1364c7070dbSScott Long struct iflib_rxq;
1374c7070dbSScott Long typedef struct iflib_rxq *iflib_rxq_t;
1384c7070dbSScott Long struct iflib_fl;
1394c7070dbSScott Long typedef struct iflib_fl *iflib_fl_t;
1404c7070dbSScott Long 
1414ecb427aSSean Bruno struct iflib_ctx;
1424ecb427aSSean Bruno 
1432d873474SStephen Hurd static void iru_init(if_rxd_update_t iru, iflib_rxq_t rxq, uint8_t flid);
144dd7fbcf1SStephen Hurd static void iflib_timer(void *arg);
14510254019SMark Johnston static void iflib_tqg_detach(if_ctx_t ctx);
1462d873474SStephen Hurd 
1474c7070dbSScott Long typedef struct iflib_filter_info {
1484c7070dbSScott Long 	driver_filter_t *ifi_filter;
1494c7070dbSScott Long 	void *ifi_filter_arg;
1504c7070dbSScott Long 	struct grouptask *ifi_task;
15195246abbSSean Bruno 	void *ifi_ctx;
1524c7070dbSScott Long } *iflib_filter_info_t;
1534c7070dbSScott Long 
1544c7070dbSScott Long struct iflib_ctx {
1554c7070dbSScott Long 	KOBJ_FIELDS;
1564c7070dbSScott Long 	/*
1574c7070dbSScott Long 	 * Pointer to hardware driver's softc
1584c7070dbSScott Long 	 */
1594c7070dbSScott Long 	void *ifc_softc;
1604c7070dbSScott Long 	device_t ifc_dev;
1614c7070dbSScott Long 	if_t ifc_ifp;
1624c7070dbSScott Long 
1634c7070dbSScott Long 	cpuset_t ifc_cpus;
1644c7070dbSScott Long 	if_shared_ctx_t ifc_sctx;
1654c7070dbSScott Long 	struct if_softc_ctx ifc_softc_ctx;
1664c7070dbSScott Long 
167aa8a24d3SStephen Hurd 	struct sx ifc_ctx_sx;
1687b610b60SSean Bruno 	struct mtx ifc_state_mtx;
1694c7070dbSScott Long 
1704c7070dbSScott Long 	iflib_txq_t ifc_txqs;
1714c7070dbSScott Long 	iflib_rxq_t ifc_rxqs;
1724c7070dbSScott Long 	uint32_t ifc_if_flags;
1734c7070dbSScott Long 	uint32_t ifc_flags;
1744c7070dbSScott Long 	uint32_t ifc_max_fl_buf_size;
1751b9d9394SEric Joyner 	uint32_t ifc_rx_mbuf_sz;
1764c7070dbSScott Long 
1774c7070dbSScott Long 	int ifc_link_state;
1784c7070dbSScott Long 	int ifc_watchdog_events;
1794c7070dbSScott Long 	struct cdev *ifc_led_dev;
1804c7070dbSScott Long 	struct resource *ifc_msix_mem;
1814c7070dbSScott Long 
1824c7070dbSScott Long 	struct if_irq ifc_legacy_irq;
1834c7070dbSScott Long 	struct grouptask ifc_admin_task;
1844c7070dbSScott Long 	struct grouptask ifc_vflr_task;
1854c7070dbSScott Long 	struct iflib_filter_info ifc_filter_info;
1864c7070dbSScott Long 	struct ifmedia	ifc_media;
187e2621d96SMatt Macy 	struct ifmedia	*ifc_mediap;
1884c7070dbSScott Long 
1894c7070dbSScott Long 	struct sysctl_oid *ifc_sysctl_node;
1904c7070dbSScott Long 	uint16_t ifc_sysctl_ntxqs;
1914c7070dbSScott Long 	uint16_t ifc_sysctl_nrxqs;
19223ac9029SStephen Hurd 	uint16_t ifc_sysctl_qs_eq_override;
193f4d2154eSStephen Hurd 	uint16_t ifc_sysctl_rx_budget;
194fe51d4cdSStephen Hurd 	uint16_t ifc_sysctl_tx_abdicate;
195f154ece0SStephen Hurd 	uint16_t ifc_sysctl_core_offset;
196f154ece0SStephen Hurd #define	CORE_OFFSET_UNSPECIFIED	0xffff
197f154ece0SStephen Hurd 	uint8_t  ifc_sysctl_separate_txrx;
198ca7005f1SPatrick Kelsey 	uint8_t  ifc_sysctl_use_logical_cores;
199ca7005f1SPatrick Kelsey 	bool	 ifc_cpus_are_physical_cores;
20023ac9029SStephen Hurd 
20195246abbSSean Bruno 	qidx_t ifc_sysctl_ntxds[8];
20295246abbSSean Bruno 	qidx_t ifc_sysctl_nrxds[8];
2034c7070dbSScott Long 	struct if_txrx ifc_txrx;
2044c7070dbSScott Long #define isc_txd_encap  ifc_txrx.ift_txd_encap
2054c7070dbSScott Long #define isc_txd_flush  ifc_txrx.ift_txd_flush
2064c7070dbSScott Long #define isc_txd_credits_update  ifc_txrx.ift_txd_credits_update
2074c7070dbSScott Long #define isc_rxd_available ifc_txrx.ift_rxd_available
2084c7070dbSScott Long #define isc_rxd_pkt_get ifc_txrx.ift_rxd_pkt_get
2094c7070dbSScott Long #define isc_rxd_refill ifc_txrx.ift_rxd_refill
2104c7070dbSScott Long #define isc_rxd_flush ifc_txrx.ift_rxd_flush
2114c7070dbSScott Long #define isc_legacy_intr ifc_txrx.ift_legacy_intr
2124c7070dbSScott Long 	eventhandler_tag ifc_vlan_attach_event;
2134c7070dbSScott Long 	eventhandler_tag ifc_vlan_detach_event;
2141fd8c72cSKyle Evans 	struct ether_addr ifc_mac;
2154c7070dbSScott Long };
2164c7070dbSScott Long 
2174c7070dbSScott Long void *
2184c7070dbSScott Long iflib_get_softc(if_ctx_t ctx)
2194c7070dbSScott Long {
2204c7070dbSScott Long 
2214c7070dbSScott Long 	return (ctx->ifc_softc);
2224c7070dbSScott Long }
2234c7070dbSScott Long 
2244c7070dbSScott Long device_t
2254c7070dbSScott Long iflib_get_dev(if_ctx_t ctx)
2264c7070dbSScott Long {
2274c7070dbSScott Long 
2284c7070dbSScott Long 	return (ctx->ifc_dev);
2294c7070dbSScott Long }
2304c7070dbSScott Long 
2314c7070dbSScott Long if_t
2324c7070dbSScott Long iflib_get_ifp(if_ctx_t ctx)
2334c7070dbSScott Long {
2344c7070dbSScott Long 
2354c7070dbSScott Long 	return (ctx->ifc_ifp);
2364c7070dbSScott Long }
2374c7070dbSScott Long 
2384c7070dbSScott Long struct ifmedia *
2394c7070dbSScott Long iflib_get_media(if_ctx_t ctx)
2404c7070dbSScott Long {
2414c7070dbSScott Long 
242e2621d96SMatt Macy 	return (ctx->ifc_mediap);
2434c7070dbSScott Long }
2444c7070dbSScott Long 
24509f6ff4fSMatt Macy uint32_t
24609f6ff4fSMatt Macy iflib_get_flags(if_ctx_t ctx)
24709f6ff4fSMatt Macy {
24809f6ff4fSMatt Macy 	return (ctx->ifc_flags);
24909f6ff4fSMatt Macy }
25009f6ff4fSMatt Macy 
25109f6ff4fSMatt Macy void
2524c7070dbSScott Long iflib_set_mac(if_ctx_t ctx, uint8_t mac[ETHER_ADDR_LEN])
2534c7070dbSScott Long {
2544c7070dbSScott Long 
2551fd8c72cSKyle Evans 	bcopy(mac, ctx->ifc_mac.octet, ETHER_ADDR_LEN);
2564c7070dbSScott Long }
2574c7070dbSScott Long 
2584c7070dbSScott Long if_softc_ctx_t
2594c7070dbSScott Long iflib_get_softc_ctx(if_ctx_t ctx)
2604c7070dbSScott Long {
2614c7070dbSScott Long 
2624c7070dbSScott Long 	return (&ctx->ifc_softc_ctx);
2634c7070dbSScott Long }
2644c7070dbSScott Long 
2654c7070dbSScott Long if_shared_ctx_t
2664c7070dbSScott Long iflib_get_sctx(if_ctx_t ctx)
2674c7070dbSScott Long {
2684c7070dbSScott Long 
2694c7070dbSScott Long 	return (ctx->ifc_sctx);
2704c7070dbSScott Long }
2714c7070dbSScott Long 
27295246abbSSean Bruno #define IP_ALIGNED(m) ((((uintptr_t)(m)->m_data) & 0x3) == 0x2)
2734c7070dbSScott Long #define CACHE_PTR_INCREMENT (CACHE_LINE_SIZE/sizeof(void*))
2745e888388SSean Bruno #define CACHE_PTR_NEXT(ptr) ((void *)(((uintptr_t)(ptr)+CACHE_LINE_SIZE-1) & (CACHE_LINE_SIZE-1)))
2754c7070dbSScott Long 
2764c7070dbSScott Long #define LINK_ACTIVE(ctx) ((ctx)->ifc_link_state == LINK_STATE_UP)
2774c7070dbSScott Long #define CTX_IS_VF(ctx) ((ctx)->ifc_sctx->isc_flags & IFLIB_IS_VF)
2784c7070dbSScott Long 
279e035717eSSean Bruno typedef struct iflib_sw_rx_desc_array {
280e035717eSSean Bruno 	bus_dmamap_t	*ifsd_map;         /* bus_dma maps for packet */
281e035717eSSean Bruno 	struct mbuf	**ifsd_m;           /* pkthdr mbufs */
282e035717eSSean Bruno 	caddr_t		*ifsd_cl;          /* direct cluster pointer for rx */
283fbec776dSAndrew Gallatin 	bus_addr_t	*ifsd_ba;          /* bus addr of cluster for rx */
284e035717eSSean Bruno } iflib_rxsd_array_t;
2854c7070dbSScott Long 
2864c7070dbSScott Long typedef struct iflib_sw_tx_desc_array {
2874c7070dbSScott Long 	bus_dmamap_t    *ifsd_map;         /* bus_dma maps for packet */
2888a04b53dSKonstantin Belousov 	bus_dmamap_t	*ifsd_tso_map;     /* bus_dma maps for TSO packet */
2894c7070dbSScott Long 	struct mbuf    **ifsd_m;           /* pkthdr mbufs */
29095246abbSSean Bruno } if_txsd_vec_t;
2914c7070dbSScott Long 
2924c7070dbSScott Long /* magic number that should be high enough for any hardware */
2934c7070dbSScott Long #define IFLIB_MAX_TX_SEGS		128
29495246abbSSean Bruno #define IFLIB_RX_COPY_THRESH		128
2954c7070dbSScott Long #define IFLIB_MAX_RX_REFRESH		32
29695246abbSSean Bruno /* The minimum descriptors per second before we start coalescing */
29795246abbSSean Bruno #define IFLIB_MIN_DESC_SEC		16384
29895246abbSSean Bruno #define IFLIB_DEFAULT_TX_UPDATE_FREQ	16
2994c7070dbSScott Long #define IFLIB_QUEUE_IDLE		0
3004c7070dbSScott Long #define IFLIB_QUEUE_HUNG		1
3014c7070dbSScott Long #define IFLIB_QUEUE_WORKING		2
30295246abbSSean Bruno /* maximum number of txqs that can share an rx interrupt */
30395246abbSSean Bruno #define IFLIB_MAX_TX_SHARED_INTR	4
3044c7070dbSScott Long 
30595246abbSSean Bruno /* this should really scale with ring size - this is a fairly arbitrary value */
30695246abbSSean Bruno #define TX_BATCH_SIZE			32
3074c7070dbSScott Long 
3084c7070dbSScott Long #define IFLIB_RESTART_BUDGET		8
3094c7070dbSScott Long 
3104c7070dbSScott Long #define CSUM_OFFLOAD		(CSUM_IP_TSO|CSUM_IP6_TSO|CSUM_IP| \
3114c7070dbSScott Long 				 CSUM_IP_UDP|CSUM_IP_TCP|CSUM_IP_SCTP| \
3124c7070dbSScott Long 				 CSUM_IP6_UDP|CSUM_IP6_TCP|CSUM_IP6_SCTP)
3131722eeacSMarius Strobl 
3144c7070dbSScott Long struct iflib_txq {
31595246abbSSean Bruno 	qidx_t		ift_in_use;
31695246abbSSean Bruno 	qidx_t		ift_cidx;
31795246abbSSean Bruno 	qidx_t		ift_cidx_processed;
31895246abbSSean Bruno 	qidx_t		ift_pidx;
3194c7070dbSScott Long 	uint8_t		ift_gen;
32023ac9029SStephen Hurd 	uint8_t		ift_br_offset;
32195246abbSSean Bruno 	uint16_t	ift_npending;
32295246abbSSean Bruno 	uint16_t	ift_db_pending;
32395246abbSSean Bruno 	uint16_t	ift_rs_pending;
3244c7070dbSScott Long 	/* implicit pad */
32595246abbSSean Bruno 	uint8_t		ift_txd_size[8];
3264c7070dbSScott Long 	uint64_t	ift_processed;
3274c7070dbSScott Long 	uint64_t	ift_cleaned;
32895246abbSSean Bruno 	uint64_t	ift_cleaned_prev;
3294c7070dbSScott Long #if MEMORY_LOGGING
3304c7070dbSScott Long 	uint64_t	ift_enqueued;
3314c7070dbSScott Long 	uint64_t	ift_dequeued;
3324c7070dbSScott Long #endif
3334c7070dbSScott Long 	uint64_t	ift_no_tx_dma_setup;
3344c7070dbSScott Long 	uint64_t	ift_no_desc_avail;
3354c7070dbSScott Long 	uint64_t	ift_mbuf_defrag_failed;
3364c7070dbSScott Long 	uint64_t	ift_mbuf_defrag;
3374c7070dbSScott Long 	uint64_t	ift_map_failed;
3384c7070dbSScott Long 	uint64_t	ift_txd_encap_efbig;
3394c7070dbSScott Long 	uint64_t	ift_pullups;
340*618d49f5SAlexander Motin 	uint64_t	ift_last_timer_tick;
3414c7070dbSScott Long 
3424c7070dbSScott Long 	struct mtx	ift_mtx;
3434c7070dbSScott Long 	struct mtx	ift_db_mtx;
3444c7070dbSScott Long 
3454c7070dbSScott Long 	/* constant values */
3464c7070dbSScott Long 	if_ctx_t	ift_ctx;
34795246abbSSean Bruno 	struct ifmp_ring        *ift_br;
3484c7070dbSScott Long 	struct grouptask	ift_task;
34995246abbSSean Bruno 	qidx_t		ift_size;
3504c7070dbSScott Long 	uint16_t	ift_id;
3514c7070dbSScott Long 	struct callout	ift_timer;
35217cec474SVincenzo Maffione #ifdef DEV_NETMAP
35317cec474SVincenzo Maffione 	struct callout	ift_netmap_timer;
35417cec474SVincenzo Maffione #endif /* DEV_NETMAP */
3554c7070dbSScott Long 
35695246abbSSean Bruno 	if_txsd_vec_t	ift_sds;
3574c7070dbSScott Long 	uint8_t		ift_qstatus;
3584c7070dbSScott Long 	uint8_t		ift_closed;
35995246abbSSean Bruno 	uint8_t		ift_update_freq;
3604c7070dbSScott Long 	struct iflib_filter_info ift_filter_info;
361bfce461eSMarius Strobl 	bus_dma_tag_t	ift_buf_tag;
362bfce461eSMarius Strobl 	bus_dma_tag_t	ift_tso_buf_tag;
3634c7070dbSScott Long 	iflib_dma_info_t	ift_ifdi;
364814fa34dSMark Johnston #define	MTX_NAME_LEN	32
3654c7070dbSScott Long 	char                    ift_mtx_name[MTX_NAME_LEN];
3664c7070dbSScott Long 	bus_dma_segment_t	ift_segs[IFLIB_MAX_TX_SEGS]  __aligned(CACHE_LINE_SIZE);
3671248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
3681248952aSSean Bruno 	uint64_t ift_cpu_exec_count[256];
3691248952aSSean Bruno #endif
3704c7070dbSScott Long } __aligned(CACHE_LINE_SIZE);
3714c7070dbSScott Long 
3724c7070dbSScott Long struct iflib_fl {
37395246abbSSean Bruno 	qidx_t		ifl_cidx;
37495246abbSSean Bruno 	qidx_t		ifl_pidx;
37595246abbSSean Bruno 	qidx_t		ifl_credits;
3764c7070dbSScott Long 	uint8_t		ifl_gen;
37795246abbSSean Bruno 	uint8_t		ifl_rxd_size;
3784c7070dbSScott Long #if MEMORY_LOGGING
3794c7070dbSScott Long 	uint64_t	ifl_m_enqueued;
3804c7070dbSScott Long 	uint64_t	ifl_m_dequeued;
3814c7070dbSScott Long 	uint64_t	ifl_cl_enqueued;
3824c7070dbSScott Long 	uint64_t	ifl_cl_dequeued;
3834c7070dbSScott Long #endif
3844c7070dbSScott Long 	/* implicit pad */
38587890dbaSSean Bruno 	bitstr_t 	*ifl_rx_bitmap;
38687890dbaSSean Bruno 	qidx_t		ifl_fragidx;
3874c7070dbSScott Long 	/* constant */
38895246abbSSean Bruno 	qidx_t		ifl_size;
3894c7070dbSScott Long 	uint16_t	ifl_buf_size;
3904c7070dbSScott Long 	uint16_t	ifl_cltype;
3914c7070dbSScott Long 	uma_zone_t	ifl_zone;
392e035717eSSean Bruno 	iflib_rxsd_array_t	ifl_sds;
3934c7070dbSScott Long 	iflib_rxq_t	ifl_rxq;
3944c7070dbSScott Long 	uint8_t		ifl_id;
395bfce461eSMarius Strobl 	bus_dma_tag_t	ifl_buf_tag;
3964c7070dbSScott Long 	iflib_dma_info_t	ifl_ifdi;
3974c7070dbSScott Long 	uint64_t	ifl_bus_addrs[IFLIB_MAX_RX_REFRESH] __aligned(CACHE_LINE_SIZE);
39895246abbSSean Bruno 	qidx_t		ifl_rxd_idxs[IFLIB_MAX_RX_REFRESH];
3994c7070dbSScott Long }  __aligned(CACHE_LINE_SIZE);
4004c7070dbSScott Long 
40195246abbSSean Bruno static inline qidx_t
40295246abbSSean Bruno get_inuse(int size, qidx_t cidx, qidx_t pidx, uint8_t gen)
4034c7070dbSScott Long {
40495246abbSSean Bruno 	qidx_t used;
4054c7070dbSScott Long 
4064c7070dbSScott Long 	if (pidx > cidx)
4074c7070dbSScott Long 		used = pidx - cidx;
4084c7070dbSScott Long 	else if (pidx < cidx)
4094c7070dbSScott Long 		used = size - cidx + pidx;
4104c7070dbSScott Long 	else if (gen == 0 && pidx == cidx)
4114c7070dbSScott Long 		used = 0;
4124c7070dbSScott Long 	else if (gen == 1 && pidx == cidx)
4134c7070dbSScott Long 		used = size;
4144c7070dbSScott Long 	else
4154c7070dbSScott Long 		panic("bad state");
4164c7070dbSScott Long 
4174c7070dbSScott Long 	return (used);
4184c7070dbSScott Long }
4194c7070dbSScott Long 
4204c7070dbSScott Long #define TXQ_AVAIL(txq) (txq->ift_size - get_inuse(txq->ift_size, txq->ift_cidx, txq->ift_pidx, txq->ift_gen))
4214c7070dbSScott Long 
4224c7070dbSScott Long #define IDXDIFF(head, tail, wrap) \
4234c7070dbSScott Long 	((head) >= (tail) ? (head) - (tail) : (wrap) - (tail) + (head))
4244c7070dbSScott Long 
4254c7070dbSScott Long struct iflib_rxq {
4264c7070dbSScott Long 	if_ctx_t	ifr_ctx;
4274c7070dbSScott Long 	iflib_fl_t	ifr_fl;
4284c7070dbSScott Long 	uint64_t	ifr_rx_irq;
4296d49b41eSAndrew Gallatin 	struct pfil_head	*pfil;
4301722eeacSMarius Strobl 	/*
4311722eeacSMarius Strobl 	 * If there is a separate completion queue (IFLIB_HAS_RXCQ), this is
4326d84e76aSVincenzo Maffione 	 * the completion queue consumer index.  Otherwise it's unused.
4331722eeacSMarius Strobl 	 */
4341722eeacSMarius Strobl 	qidx_t		ifr_cq_cidx;
4354c7070dbSScott Long 	uint16_t	ifr_id;
4364c7070dbSScott Long 	uint8_t		ifr_nfl;
43795246abbSSean Bruno 	uint8_t		ifr_ntxqirq;
43895246abbSSean Bruno 	uint8_t		ifr_txqid[IFLIB_MAX_TX_SHARED_INTR];
4391722eeacSMarius Strobl 	uint8_t		ifr_fl_offset;
4404c7070dbSScott Long 	struct lro_ctrl			ifr_lc;
4414c7070dbSScott Long 	struct grouptask        ifr_task;
442fb1a29b4SHans Petter Selasky 	struct callout		ifr_watchdog;
4434c7070dbSScott Long 	struct iflib_filter_info ifr_filter_info;
4444c7070dbSScott Long 	iflib_dma_info_t		ifr_ifdi;
445ab2e3f79SStephen Hurd 
4464c7070dbSScott Long 	/* dynamically allocate if any drivers need a value substantially larger than this */
4474c7070dbSScott Long 	struct if_rxd_frag	ifr_frags[IFLIB_MAX_RX_SEGS] __aligned(CACHE_LINE_SIZE);
4481248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
4491248952aSSean Bruno 	uint64_t ifr_cpu_exec_count[256];
4501248952aSSean Bruno #endif
4514c7070dbSScott Long }  __aligned(CACHE_LINE_SIZE);
4524c7070dbSScott Long 
45395246abbSSean Bruno typedef struct if_rxsd {
45495246abbSSean Bruno 	caddr_t *ifsd_cl;
45595246abbSSean Bruno 	iflib_fl_t ifsd_fl;
45695246abbSSean Bruno } *if_rxsd_t;
45795246abbSSean Bruno 
45895246abbSSean Bruno /* multiple of word size */
45995246abbSSean Bruno #ifdef __LP64__
460ab2e3f79SStephen Hurd #define PKT_INFO_SIZE	6
46195246abbSSean Bruno #define RXD_INFO_SIZE	5
46295246abbSSean Bruno #define PKT_TYPE uint64_t
46395246abbSSean Bruno #else
464ab2e3f79SStephen Hurd #define PKT_INFO_SIZE	11
46595246abbSSean Bruno #define RXD_INFO_SIZE	8
46695246abbSSean Bruno #define PKT_TYPE uint32_t
46795246abbSSean Bruno #endif
46895246abbSSean Bruno #define PKT_LOOP_BOUND  ((PKT_INFO_SIZE/3)*3)
46995246abbSSean Bruno #define RXD_LOOP_BOUND  ((RXD_INFO_SIZE/4)*4)
47095246abbSSean Bruno 
47195246abbSSean Bruno typedef struct if_pkt_info_pad {
47295246abbSSean Bruno 	PKT_TYPE pkt_val[PKT_INFO_SIZE];
47395246abbSSean Bruno } *if_pkt_info_pad_t;
47495246abbSSean Bruno typedef struct if_rxd_info_pad {
47595246abbSSean Bruno 	PKT_TYPE rxd_val[RXD_INFO_SIZE];
47695246abbSSean Bruno } *if_rxd_info_pad_t;
47795246abbSSean Bruno 
47895246abbSSean Bruno CTASSERT(sizeof(struct if_pkt_info_pad) == sizeof(struct if_pkt_info));
47995246abbSSean Bruno CTASSERT(sizeof(struct if_rxd_info_pad) == sizeof(struct if_rxd_info));
48095246abbSSean Bruno 
48195246abbSSean Bruno static inline void
48295246abbSSean Bruno pkt_info_zero(if_pkt_info_t pi)
48395246abbSSean Bruno {
48495246abbSSean Bruno 	if_pkt_info_pad_t pi_pad;
48595246abbSSean Bruno 
48695246abbSSean Bruno 	pi_pad = (if_pkt_info_pad_t)pi;
48795246abbSSean Bruno 	pi_pad->pkt_val[0] = 0; pi_pad->pkt_val[1] = 0; pi_pad->pkt_val[2] = 0;
48895246abbSSean Bruno 	pi_pad->pkt_val[3] = 0; pi_pad->pkt_val[4] = 0; pi_pad->pkt_val[5] = 0;
48995246abbSSean Bruno #ifndef __LP64__
490ab2e3f79SStephen Hurd 	pi_pad->pkt_val[6] = 0; pi_pad->pkt_val[7] = 0; pi_pad->pkt_val[8] = 0;
491ab2e3f79SStephen Hurd 	pi_pad->pkt_val[9] = 0; pi_pad->pkt_val[10] = 0;
49295246abbSSean Bruno #endif
49395246abbSSean Bruno }
49495246abbSSean Bruno 
49509f6ff4fSMatt Macy static device_method_t iflib_pseudo_methods[] = {
49609f6ff4fSMatt Macy 	DEVMETHOD(device_attach, noop_attach),
49709f6ff4fSMatt Macy 	DEVMETHOD(device_detach, iflib_pseudo_detach),
49809f6ff4fSMatt Macy 	DEVMETHOD_END
49909f6ff4fSMatt Macy };
50009f6ff4fSMatt Macy 
50109f6ff4fSMatt Macy driver_t iflib_pseudodriver = {
50209f6ff4fSMatt Macy 	"iflib_pseudo", iflib_pseudo_methods, sizeof(struct iflib_ctx),
50309f6ff4fSMatt Macy };
50409f6ff4fSMatt Macy 
50595246abbSSean Bruno static inline void
50695246abbSSean Bruno rxd_info_zero(if_rxd_info_t ri)
50795246abbSSean Bruno {
50895246abbSSean Bruno 	if_rxd_info_pad_t ri_pad;
50995246abbSSean Bruno 	int i;
51095246abbSSean Bruno 
51195246abbSSean Bruno 	ri_pad = (if_rxd_info_pad_t)ri;
51295246abbSSean Bruno 	for (i = 0; i < RXD_LOOP_BOUND; i += 4) {
51395246abbSSean Bruno 		ri_pad->rxd_val[i] = 0;
51495246abbSSean Bruno 		ri_pad->rxd_val[i+1] = 0;
51595246abbSSean Bruno 		ri_pad->rxd_val[i+2] = 0;
51695246abbSSean Bruno 		ri_pad->rxd_val[i+3] = 0;
51795246abbSSean Bruno 	}
51895246abbSSean Bruno #ifdef __LP64__
51995246abbSSean Bruno 	ri_pad->rxd_val[RXD_INFO_SIZE-1] = 0;
52095246abbSSean Bruno #endif
52195246abbSSean Bruno }
52295246abbSSean Bruno 
5234c7070dbSScott Long /*
5244c7070dbSScott Long  * Only allow a single packet to take up most 1/nth of the tx ring
5254c7070dbSScott Long  */
5264c7070dbSScott Long #define MAX_SINGLE_PACKET_FRACTION 12
5274c7070dbSScott Long #define IF_BAD_DMA (bus_addr_t)-1
5284c7070dbSScott Long 
5294c7070dbSScott Long #define CTX_ACTIVE(ctx) ((if_getdrvflags((ctx)->ifc_ifp) & IFF_DRV_RUNNING))
5304c7070dbSScott Long 
531aa8a24d3SStephen Hurd #define CTX_LOCK_INIT(_sc)  sx_init(&(_sc)->ifc_ctx_sx, "iflib ctx lock")
532aa8a24d3SStephen Hurd #define CTX_LOCK(ctx) sx_xlock(&(ctx)->ifc_ctx_sx)
533aa8a24d3SStephen Hurd #define CTX_UNLOCK(ctx) sx_xunlock(&(ctx)->ifc_ctx_sx)
534aa8a24d3SStephen Hurd #define CTX_LOCK_DESTROY(ctx) sx_destroy(&(ctx)->ifc_ctx_sx)
5354c7070dbSScott Long 
5367b610b60SSean Bruno #define STATE_LOCK_INIT(_sc, _name)  mtx_init(&(_sc)->ifc_state_mtx, _name, "iflib state lock", MTX_DEF)
5377b610b60SSean Bruno #define STATE_LOCK(ctx) mtx_lock(&(ctx)->ifc_state_mtx)
5387b610b60SSean Bruno #define STATE_UNLOCK(ctx) mtx_unlock(&(ctx)->ifc_state_mtx)
5397b610b60SSean Bruno #define STATE_LOCK_DESTROY(ctx) mtx_destroy(&(ctx)->ifc_state_mtx)
5407b610b60SSean Bruno 
5414c7070dbSScott Long #define CALLOUT_LOCK(txq)	mtx_lock(&txq->ift_mtx)
5424c7070dbSScott Long #define CALLOUT_UNLOCK(txq) 	mtx_unlock(&txq->ift_mtx)
5434c7070dbSScott Long 
54477c1fcecSEric Joyner void
54577c1fcecSEric Joyner iflib_set_detach(if_ctx_t ctx)
54677c1fcecSEric Joyner {
54777c1fcecSEric Joyner 	STATE_LOCK(ctx);
54877c1fcecSEric Joyner 	ctx->ifc_flags |= IFC_IN_DETACH;
54977c1fcecSEric Joyner 	STATE_UNLOCK(ctx);
55077c1fcecSEric Joyner }
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,
586da69b8f9SSean Bruno 		   &iflib_min_tx_latency, 0, "minimize transmit latency at the possible expense of throughput");
58795246abbSSean Bruno static int iflib_no_tx_batch = 0;
58895246abbSSean Bruno SYSCTL_INT(_net_iflib, OID_AUTO, no_tx_batch, CTLFLAG_RW,
58995246abbSSean Bruno 		   &iflib_no_tx_batch, 0, "minimize transmit latency at the possible expense of throughput");
590*618d49f5SAlexander Motin static int iflib_timer_default = 1000;
591*618d49f5SAlexander Motin SYSCTL_INT(_net_iflib, OID_AUTO, timer_default, CTLFLAG_RW,
592*618d49f5SAlexander Motin 		   &iflib_timer_default, 0, "number of ticks between iflib_timer calls");
59381be6552SMatt Macy 
5944c7070dbSScott Long 
5954c7070dbSScott Long #if IFLIB_DEBUG_COUNTERS
5964c7070dbSScott Long 
5974c7070dbSScott Long static int iflib_tx_seen;
5984c7070dbSScott Long static int iflib_tx_sent;
5994c7070dbSScott Long static int iflib_tx_encap;
6004c7070dbSScott Long static int iflib_rx_allocs;
6014c7070dbSScott Long static int iflib_fl_refills;
6024c7070dbSScott Long static int iflib_fl_refills_large;
6034c7070dbSScott Long static int iflib_tx_frees;
6044c7070dbSScott Long 
6054c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, tx_seen, CTLFLAG_RD,
6061722eeacSMarius Strobl 		   &iflib_tx_seen, 0, "# TX mbufs seen");
6074c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, tx_sent, CTLFLAG_RD,
6081722eeacSMarius Strobl 		   &iflib_tx_sent, 0, "# TX mbufs sent");
6094c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, tx_encap, CTLFLAG_RD,
6101722eeacSMarius Strobl 		   &iflib_tx_encap, 0, "# TX mbufs encapped");
6114c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, tx_frees, CTLFLAG_RD,
6121722eeacSMarius Strobl 		   &iflib_tx_frees, 0, "# TX frees");
6134c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_allocs, CTLFLAG_RD,
6141722eeacSMarius Strobl 		   &iflib_rx_allocs, 0, "# RX allocations");
6154c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, fl_refills, CTLFLAG_RD,
6164c7070dbSScott Long 		   &iflib_fl_refills, 0, "# refills");
6174c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, fl_refills_large, CTLFLAG_RD,
6184c7070dbSScott Long 		   &iflib_fl_refills_large, 0, "# large refills");
6194c7070dbSScott Long 
6204c7070dbSScott Long static int iflib_txq_drain_flushing;
6214c7070dbSScott Long static int iflib_txq_drain_oactive;
6224c7070dbSScott Long static int iflib_txq_drain_notready;
6234c7070dbSScott Long 
6244c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_flushing, CTLFLAG_RD,
6254c7070dbSScott Long 		   &iflib_txq_drain_flushing, 0, "# drain flushes");
6264c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_oactive, CTLFLAG_RD,
6274c7070dbSScott Long 		   &iflib_txq_drain_oactive, 0, "# drain oactives");
6284c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_notready, CTLFLAG_RD,
6294c7070dbSScott Long 		   &iflib_txq_drain_notready, 0, "# drain notready");
6304c7070dbSScott Long 
6314c7070dbSScott Long static int iflib_encap_load_mbuf_fail;
632d14c853bSStephen Hurd static int iflib_encap_pad_mbuf_fail;
6334c7070dbSScott Long static int iflib_encap_txq_avail_fail;
6344c7070dbSScott Long static int iflib_encap_txd_encap_fail;
6354c7070dbSScott Long 
6364c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, encap_load_mbuf_fail, CTLFLAG_RD,
6374c7070dbSScott Long 		   &iflib_encap_load_mbuf_fail, 0, "# busdma load failures");
638d14c853bSStephen Hurd SYSCTL_INT(_net_iflib, OID_AUTO, encap_pad_mbuf_fail, CTLFLAG_RD,
639d14c853bSStephen Hurd 		   &iflib_encap_pad_mbuf_fail, 0, "# runt frame pad failures");
6404c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, encap_txq_avail_fail, CTLFLAG_RD,
6414c7070dbSScott Long 		   &iflib_encap_txq_avail_fail, 0, "# txq avail failures");
6424c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, encap_txd_encap_fail, CTLFLAG_RD,
6434c7070dbSScott Long 		   &iflib_encap_txd_encap_fail, 0, "# driver encap failures");
6444c7070dbSScott Long 
6454c7070dbSScott Long static int iflib_task_fn_rxs;
6464c7070dbSScott Long static int iflib_rx_intr_enables;
6474c7070dbSScott Long static int iflib_fast_intrs;
6484c7070dbSScott Long static int iflib_rx_unavail;
6494c7070dbSScott Long static int iflib_rx_ctx_inactive;
6504c7070dbSScott Long static int iflib_rx_if_input;
6514c7070dbSScott Long static int iflib_rxd_flush;
6524c7070dbSScott Long 
6534c7070dbSScott Long static int iflib_verbose_debug;
6544c7070dbSScott Long 
6554c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, task_fn_rx, CTLFLAG_RD,
6564c7070dbSScott Long 		   &iflib_task_fn_rxs, 0, "# task_fn_rx calls");
6574c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_intr_enables, CTLFLAG_RD,
6581722eeacSMarius Strobl 		   &iflib_rx_intr_enables, 0, "# RX intr enables");
6594c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, fast_intrs, CTLFLAG_RD,
6604c7070dbSScott Long 		   &iflib_fast_intrs, 0, "# fast_intr calls");
6614c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_unavail, CTLFLAG_RD,
6624c7070dbSScott Long 		   &iflib_rx_unavail, 0, "# times rxeof called with no available data");
6634c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_ctx_inactive, CTLFLAG_RD,
6644c7070dbSScott Long 		   &iflib_rx_ctx_inactive, 0, "# times rxeof called with inactive context");
6654c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_if_input, CTLFLAG_RD,
6664c7070dbSScott Long 		   &iflib_rx_if_input, 0, "# times rxeof called if_input");
6674c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rxd_flush, CTLFLAG_RD,
6684c7070dbSScott Long 	         &iflib_rxd_flush, 0, "# times rxd_flush called");
6694c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, verbose_debug, CTLFLAG_RW,
6704c7070dbSScott Long 		   &iflib_verbose_debug, 0, "enable verbose debugging");
6714c7070dbSScott Long 
6724c7070dbSScott Long #define DBG_COUNTER_INC(name) atomic_add_int(&(iflib_ ## name), 1)
673da69b8f9SSean Bruno static void
674da69b8f9SSean Bruno iflib_debug_reset(void)
675da69b8f9SSean Bruno {
676da69b8f9SSean Bruno 	iflib_tx_seen = iflib_tx_sent = iflib_tx_encap = iflib_rx_allocs =
677da69b8f9SSean Bruno 		iflib_fl_refills = iflib_fl_refills_large = iflib_tx_frees =
678da69b8f9SSean Bruno 		iflib_txq_drain_flushing = iflib_txq_drain_oactive =
67964e6fc13SStephen Hurd 		iflib_txq_drain_notready =
680d14c853bSStephen Hurd 		iflib_encap_load_mbuf_fail = iflib_encap_pad_mbuf_fail =
681d14c853bSStephen Hurd 		iflib_encap_txq_avail_fail = iflib_encap_txd_encap_fail =
682d14c853bSStephen Hurd 		iflib_task_fn_rxs = iflib_rx_intr_enables = iflib_fast_intrs =
68364e6fc13SStephen Hurd 		iflib_rx_unavail =
68464e6fc13SStephen Hurd 		iflib_rx_ctx_inactive = iflib_rx_if_input =
6856d49b41eSAndrew Gallatin 		iflib_rxd_flush = 0;
686da69b8f9SSean Bruno }
6874c7070dbSScott Long 
6884c7070dbSScott Long #else
6894c7070dbSScott Long #define DBG_COUNTER_INC(name)
690da69b8f9SSean Bruno static void iflib_debug_reset(void) {}
6914c7070dbSScott Long #endif
6924c7070dbSScott Long 
6934c7070dbSScott Long #define IFLIB_DEBUG 0
6944c7070dbSScott Long 
6954c7070dbSScott Long static void iflib_tx_structures_free(if_ctx_t ctx);
6964c7070dbSScott Long static void iflib_rx_structures_free(if_ctx_t ctx);
6974c7070dbSScott Long static int iflib_queues_alloc(if_ctx_t ctx);
6984c7070dbSScott Long static int iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq);
69995246abbSSean Bruno static int iflib_rxd_avail(if_ctx_t ctx, iflib_rxq_t rxq, qidx_t cidx, qidx_t budget);
7004c7070dbSScott Long static int iflib_qset_structures_setup(if_ctx_t ctx);
7014c7070dbSScott Long static int iflib_msix_init(if_ctx_t ctx);
7023e0e6330SStephen Hurd static int iflib_legacy_setup(if_ctx_t ctx, driver_filter_t filter, void *filterarg, int *rid, const char *str);
7034c7070dbSScott Long static void iflib_txq_check_drain(iflib_txq_t txq, int budget);
7044c7070dbSScott Long static uint32_t iflib_txq_can_drain(struct ifmp_ring *);
705b8ca4756SPatrick Kelsey #ifdef ALTQ
706b8ca4756SPatrick Kelsey static void iflib_altq_if_start(if_t ifp);
707b8ca4756SPatrick Kelsey static int iflib_altq_if_transmit(if_t ifp, struct mbuf *m);
708b8ca4756SPatrick Kelsey #endif
7094c7070dbSScott Long static int iflib_register(if_ctx_t);
71056614414SEric Joyner static void iflib_deregister(if_ctx_t);
7111558015eSEric Joyner static void iflib_unregister_vlan_handlers(if_ctx_t ctx);
712b3813609SPatrick Kelsey static uint16_t iflib_get_mbuf_size_for(unsigned int size);
7134c7070dbSScott Long static void iflib_init_locked(if_ctx_t ctx);
7144c7070dbSScott Long static void iflib_add_device_sysctl_pre(if_ctx_t ctx);
7154c7070dbSScott Long static void iflib_add_device_sysctl_post(if_ctx_t ctx);
716da69b8f9SSean Bruno static void iflib_ifmp_purge(iflib_txq_t txq);
7171248952aSSean Bruno static void _iflib_pre_assert(if_softc_ctx_t scctx);
71895246abbSSean Bruno static void iflib_if_init_locked(if_ctx_t ctx);
71977c1fcecSEric Joyner static void iflib_free_intr_mem(if_ctx_t ctx);
72095246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
72195246abbSSean Bruno static struct mbuf * iflib_fixup_rx(struct mbuf *m);
72295246abbSSean Bruno #endif
7234c7070dbSScott Long 
724f154ece0SStephen Hurd static SLIST_HEAD(cpu_offset_list, cpu_offset) cpu_offsets =
725f154ece0SStephen Hurd     SLIST_HEAD_INITIALIZER(cpu_offsets);
726f154ece0SStephen Hurd struct cpu_offset {
727f154ece0SStephen Hurd 	SLIST_ENTRY(cpu_offset) entries;
728f154ece0SStephen Hurd 	cpuset_t	set;
729f154ece0SStephen Hurd 	unsigned int	refcount;
730ca7005f1SPatrick Kelsey 	uint16_t	next_cpuid;
731f154ece0SStephen Hurd };
732f154ece0SStephen Hurd static struct mtx cpu_offset_mtx;
733f154ece0SStephen Hurd MTX_SYSINIT(iflib_cpu_offset, &cpu_offset_mtx, "iflib_cpu_offset lock",
734f154ece0SStephen Hurd     MTX_DEF);
735f154ece0SStephen Hurd 
7367790c8c1SConrad Meyer DEBUGNET_DEFINE(iflib);
73794618825SMark Johnston 
738ac11d857SVincenzo Maffione static int
739ac11d857SVincenzo Maffione iflib_num_rx_descs(if_ctx_t ctx)
740ac11d857SVincenzo Maffione {
741ac11d857SVincenzo Maffione 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
742ac11d857SVincenzo Maffione 	if_shared_ctx_t sctx = ctx->ifc_sctx;
743ac11d857SVincenzo Maffione 	uint16_t first_rxq = (sctx->isc_flags & IFLIB_HAS_RXCQ) ? 1 : 0;
744ac11d857SVincenzo Maffione 
745ac11d857SVincenzo Maffione 	return scctx->isc_nrxd[first_rxq];
746ac11d857SVincenzo Maffione }
747ac11d857SVincenzo Maffione 
748ac11d857SVincenzo Maffione static int
749ac11d857SVincenzo Maffione iflib_num_tx_descs(if_ctx_t ctx)
750ac11d857SVincenzo Maffione {
751ac11d857SVincenzo Maffione 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
752ac11d857SVincenzo Maffione 	if_shared_ctx_t sctx = ctx->ifc_sctx;
753ac11d857SVincenzo Maffione 	uint16_t first_txq = (sctx->isc_flags & IFLIB_HAS_TXCQ) ? 1 : 0;
754ac11d857SVincenzo Maffione 
755ac11d857SVincenzo Maffione 	return scctx->isc_ntxd[first_txq];
756ac11d857SVincenzo Maffione }
757ac11d857SVincenzo Maffione 
7584c7070dbSScott Long #ifdef DEV_NETMAP
7594c7070dbSScott Long #include <sys/selinfo.h>
7604c7070dbSScott Long #include <net/netmap.h>
7614c7070dbSScott Long #include <dev/netmap/netmap_kern.h>
7624c7070dbSScott Long 
7634c7070dbSScott Long MODULE_DEPEND(iflib, netmap, 1, 1, 1);
7644c7070dbSScott Long 
765de5b4610SVincenzo Maffione static int netmap_fl_refill(iflib_rxq_t rxq, struct netmap_kring *kring, bool init);
76617cec474SVincenzo Maffione static void iflib_netmap_timer(void *arg);
7672d873474SStephen Hurd 
7684c7070dbSScott Long /*
7694c7070dbSScott Long  * device-specific sysctl variables:
7704c7070dbSScott Long  *
77191d546a0SConrad Meyer  * iflib_crcstrip: 0: keep CRC in rx frames (default), 1: strip it.
7724c7070dbSScott Long  *	During regular operations the CRC is stripped, but on some
7734c7070dbSScott Long  *	hardware reception of frames not multiple of 64 is slower,
7744c7070dbSScott Long  *	so using crcstrip=0 helps in benchmarks.
7754c7070dbSScott Long  *
77691d546a0SConrad Meyer  * iflib_rx_miss, iflib_rx_miss_bufs:
7774c7070dbSScott Long  *	count packets that might be missed due to lost interrupts.
7784c7070dbSScott Long  */
7794c7070dbSScott Long SYSCTL_DECL(_dev_netmap);
7804c7070dbSScott Long /*
7814c7070dbSScott Long  * The xl driver by default strips CRCs and we do not override it.
7824c7070dbSScott Long  */
7834c7070dbSScott Long 
7844c7070dbSScott Long int iflib_crcstrip = 1;
7854c7070dbSScott Long SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_crcstrip,
7861722eeacSMarius Strobl     CTLFLAG_RW, &iflib_crcstrip, 1, "strip CRC on RX frames");
7874c7070dbSScott Long 
7884c7070dbSScott Long int iflib_rx_miss, iflib_rx_miss_bufs;
7894c7070dbSScott Long SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_rx_miss,
7901722eeacSMarius Strobl     CTLFLAG_RW, &iflib_rx_miss, 0, "potentially missed RX intr");
79191d546a0SConrad Meyer SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_rx_miss_bufs,
7921722eeacSMarius Strobl     CTLFLAG_RW, &iflib_rx_miss_bufs, 0, "potentially missed RX intr bufs");
7934c7070dbSScott Long 
7944c7070dbSScott Long /*
7954c7070dbSScott Long  * Register/unregister. We are already under netmap lock.
7964c7070dbSScott Long  * Only called on the first register or the last unregister.
7974c7070dbSScott Long  */
7984c7070dbSScott Long static int
7994c7070dbSScott Long iflib_netmap_register(struct netmap_adapter *na, int onoff)
8004c7070dbSScott Long {
8011722eeacSMarius Strobl 	if_t ifp = na->ifp;
8024c7070dbSScott Long 	if_ctx_t ctx = ifp->if_softc;
80395246abbSSean Bruno 	int status;
8044c7070dbSScott Long 
8054c7070dbSScott Long 	CTX_LOCK(ctx);
8064c7070dbSScott Long 	if (!CTX_IS_VF(ctx))
8071248952aSSean Bruno 		IFDI_CRCSTRIP_SET(ctx, onoff, iflib_crcstrip);
8084c7070dbSScott Long 
8090a182b4cSVincenzo Maffione 	iflib_stop(ctx);
8100a182b4cSVincenzo Maffione 
8110a182b4cSVincenzo Maffione 	/*
8120a182b4cSVincenzo Maffione 	 * Enable (or disable) netmap flags, and intercept (or restore)
8130a182b4cSVincenzo Maffione 	 * ifp->if_transmit. This is done once the device has been stopped
8143d65fd97SVincenzo Maffione 	 * to prevent race conditions. Also, this must be done after
8153d65fd97SVincenzo Maffione 	 * calling netmap_disable_all_rings() and before calling
8163d65fd97SVincenzo Maffione 	 * netmap_enable_all_rings(), so that these two functions see the
8173d65fd97SVincenzo Maffione 	 * updated state of the NAF_NETMAP_ON bit.
8180a182b4cSVincenzo Maffione 	 */
8194c7070dbSScott Long 	if (onoff) {
8204c7070dbSScott Long 		nm_set_native_flags(na);
8214c7070dbSScott Long 	} else {
8224c7070dbSScott Long 		nm_clear_native_flags(na);
8234c7070dbSScott Long 	}
8240a182b4cSVincenzo Maffione 
82595246abbSSean Bruno 	iflib_init_locked(ctx);
8261248952aSSean Bruno 	IFDI_CRCSTRIP_SET(ctx, onoff, iflib_crcstrip); // XXX why twice ?
82795246abbSSean Bruno 	status = ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1;
82895246abbSSean Bruno 	if (status)
82995246abbSSean Bruno 		nm_clear_native_flags(na);
8304c7070dbSScott Long 	CTX_UNLOCK(ctx);
83195246abbSSean Bruno 	return (status);
8324c7070dbSScott Long }
8334c7070dbSScott Long 
8342d873474SStephen Hurd static int
83521d0c012Syou@x iflib_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
83621d0c012Syou@x {
83721d0c012Syou@x 	if_t ifp = na->ifp;
83821d0c012Syou@x 	if_ctx_t ctx = ifp->if_softc;
83921d0c012Syou@x 	iflib_rxq_t rxq = &ctx->ifc_rxqs[0];
84021d0c012Syou@x 	iflib_fl_t fl = &rxq->ifr_fl[0];
84121d0c012Syou@x 
84221d0c012Syou@x 	info->num_tx_rings = ctx->ifc_softc_ctx.isc_ntxqsets;
84321d0c012Syou@x 	info->num_rx_rings = ctx->ifc_softc_ctx.isc_nrxqsets;
84421d0c012Syou@x 	info->num_tx_descs = iflib_num_tx_descs(ctx);
84521d0c012Syou@x 	info->num_rx_descs = iflib_num_rx_descs(ctx);
84621d0c012Syou@x 	info->rx_buf_maxsize = fl->ifl_buf_size;
84721d0c012Syou@x 	nm_prinf("txr %u rxr %u txd %u rxd %u rbufsz %u",
84821d0c012Syou@x 		info->num_tx_rings, info->num_rx_rings, info->num_tx_descs,
84921d0c012Syou@x 		info->num_rx_descs, info->rx_buf_maxsize);
85021d0c012Syou@x 
85121d0c012Syou@x 	return 0;
85221d0c012Syou@x }
85321d0c012Syou@x 
85421d0c012Syou@x static int
855de5b4610SVincenzo Maffione netmap_fl_refill(iflib_rxq_t rxq, struct netmap_kring *kring, bool init)
8562d873474SStephen Hurd {
8572d873474SStephen Hurd 	struct netmap_adapter *na = kring->na;
8582d873474SStephen Hurd 	u_int const lim = kring->nkr_num_slots - 1;
8592d873474SStephen Hurd 	struct netmap_ring *ring = kring->ring;
8602d873474SStephen Hurd 	bus_dmamap_t *map;
8612d873474SStephen Hurd 	struct if_rxd_update iru;
8622d873474SStephen Hurd 	if_ctx_t ctx = rxq->ifr_ctx;
8632d873474SStephen Hurd 	iflib_fl_t fl = &rxq->ifr_fl[0];
864de5b4610SVincenzo Maffione 	u_int nic_i_first, nic_i;
86555f0ad5fSVincenzo Maffione 	u_int nm_i;
866ae750d5cSVincenzo Maffione 	int i, n;
86764e6fc13SStephen Hurd #if IFLIB_DEBUG_COUNTERS
86864e6fc13SStephen Hurd 	int rf_count = 0;
86964e6fc13SStephen Hurd #endif
8702d873474SStephen Hurd 
871de5b4610SVincenzo Maffione 	/*
872ae750d5cSVincenzo Maffione 	 * This function is used both at initialization and in rxsync.
873ae750d5cSVincenzo Maffione 	 * At initialization we need to prepare (with isc_rxd_refill())
87455f0ad5fSVincenzo Maffione 	 * all the netmap buffers currently owned by the kernel, in
87555f0ad5fSVincenzo Maffione 	 * such a way to keep fl->ifl_pidx and kring->nr_hwcur in sync
87655f0ad5fSVincenzo Maffione 	 * (except for kring->nkr_hwofs). These may be less than
87755f0ad5fSVincenzo Maffione 	 * kring->nkr_num_slots if netmap_reset() was called while
87855f0ad5fSVincenzo Maffione 	 * an application using the kring that still owned some
87955f0ad5fSVincenzo Maffione 	 * buffers.
88055f0ad5fSVincenzo Maffione 	 * At rxsync time, both indexes point to the next buffer to be
88155f0ad5fSVincenzo Maffione 	 * refilled.
882ae750d5cSVincenzo Maffione 	 * In any case we publish (with isc_rxd_flush()) up to
883ae750d5cSVincenzo Maffione 	 * (fl->ifl_pidx - 1) % N (included), to avoid the NIC tail/prod
884ae750d5cSVincenzo Maffione 	 * pointer to overrun the head/cons pointer, although this is
885ae750d5cSVincenzo Maffione 	 * not necessary for some NICs (e.g. vmx).
886de5b4610SVincenzo Maffione 	 */
88755f0ad5fSVincenzo Maffione 	if (__predict_false(init)) {
88855f0ad5fSVincenzo Maffione 		n = kring->nkr_num_slots - nm_kr_rxspace(kring);
88955f0ad5fSVincenzo Maffione 	} else {
89055f0ad5fSVincenzo Maffione 		n = kring->rhead - kring->nr_hwcur;
891ae750d5cSVincenzo Maffione 		if (n == 0)
892ae750d5cSVincenzo Maffione 			return (0); /* Nothing to do. */
893ae750d5cSVincenzo Maffione 		if (n < 0)
894ae750d5cSVincenzo Maffione 			n += kring->nkr_num_slots;
895de5b4610SVincenzo Maffione 	}
896530960beSVincenzo Maffione 
8972d873474SStephen Hurd 	iru_init(&iru, rxq, 0 /* flid */);
8982d873474SStephen Hurd 	map = fl->ifl_sds.ifsd_map;
899ae750d5cSVincenzo Maffione 	nic_i = fl->ifl_pidx;
90055f0ad5fSVincenzo Maffione 	nm_i = netmap_idx_n2k(kring, nic_i);
90155f0ad5fSVincenzo Maffione 	if (__predict_false(init)) {
90255f0ad5fSVincenzo Maffione 		/*
90355f0ad5fSVincenzo Maffione 		 * On init/reset, nic_i must be 0, and we must
90455f0ad5fSVincenzo Maffione 		 * start to refill from hwtail (see netmap_reset()).
90555f0ad5fSVincenzo Maffione 		 */
90655f0ad5fSVincenzo Maffione 		MPASS(nic_i == 0);
90755f0ad5fSVincenzo Maffione 		MPASS(nm_i == kring->nr_hwtail);
90855f0ad5fSVincenzo Maffione 	} else
90955f0ad5fSVincenzo Maffione 		MPASS(nm_i == kring->nr_hwcur);
91064e6fc13SStephen Hurd 	DBG_COUNTER_INC(fl_refills);
911ae750d5cSVincenzo Maffione 	while (n > 0) {
91264e6fc13SStephen Hurd #if IFLIB_DEBUG_COUNTERS
91364e6fc13SStephen Hurd 		if (++rf_count == 9)
91464e6fc13SStephen Hurd 			DBG_COUNTER_INC(fl_refills_large);
91564e6fc13SStephen Hurd #endif
916530960beSVincenzo Maffione 		nic_i_first = nic_i;
917ae750d5cSVincenzo Maffione 		for (i = 0; n > 0 && i < IFLIB_MAX_RX_REFRESH; n--, i++) {
9182d873474SStephen Hurd 			struct netmap_slot *slot = &ring->slot[nm_i];
919361e9501SVincenzo Maffione 			uint64_t paddr;
920361e9501SVincenzo Maffione 			void *addr = PNMB(na, slot, &paddr);
9212d873474SStephen Hurd 
922530960beSVincenzo Maffione 			MPASS(i < IFLIB_MAX_RX_REFRESH);
9232d873474SStephen Hurd 
9242d873474SStephen Hurd 			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
9252d873474SStephen Hurd 			        return netmap_ring_reinit(kring);
9262d873474SStephen Hurd 
927361e9501SVincenzo Maffione 			fl->ifl_bus_addrs[i] = paddr +
928361e9501SVincenzo Maffione 			    nm_get_offset(kring, slot);
929530960beSVincenzo Maffione 			fl->ifl_rxd_idxs[i] = nic_i;
930530960beSVincenzo Maffione 
93195dcf343SMarius Strobl 			if (__predict_false(init)) {
93295dcf343SMarius Strobl 				netmap_load_map(na, fl->ifl_buf_tag,
93395dcf343SMarius Strobl 				    map[nic_i], addr);
93495dcf343SMarius Strobl 			} else if (slot->flags & NS_BUF_CHANGED) {
9352d873474SStephen Hurd 				/* buffer has changed, reload map */
93695dcf343SMarius Strobl 				netmap_reload_map(na, fl->ifl_buf_tag,
93795dcf343SMarius Strobl 				    map[nic_i], addr);
9382d873474SStephen Hurd 			}
939530960beSVincenzo Maffione 			bus_dmamap_sync(fl->ifl_buf_tag, map[nic_i],
940530960beSVincenzo Maffione 			    BUS_DMASYNC_PREREAD);
9412d873474SStephen Hurd 			slot->flags &= ~NS_BUF_CHANGED;
9422d873474SStephen Hurd 
9432d873474SStephen Hurd 			nm_i = nm_next(nm_i, lim);
944530960beSVincenzo Maffione 			nic_i = nm_next(nic_i, lim);
945530960beSVincenzo Maffione 		}
9462d873474SStephen Hurd 
947530960beSVincenzo Maffione 		iru.iru_pidx = nic_i_first;
948530960beSVincenzo Maffione 		iru.iru_count = i;
9492d873474SStephen Hurd 		ctx->isc_rxd_refill(ctx->ifc_softc, &iru);
9502d873474SStephen Hurd 	}
951ae750d5cSVincenzo Maffione 	fl->ifl_pidx = nic_i;
95255f0ad5fSVincenzo Maffione 	/*
95355f0ad5fSVincenzo Maffione 	 * At the end of the loop we must have refilled everything
95455f0ad5fSVincenzo Maffione 	 * we could possibly refill.
95555f0ad5fSVincenzo Maffione 	 */
956ae750d5cSVincenzo Maffione 	MPASS(nm_i == kring->rhead);
957ae750d5cSVincenzo Maffione 	kring->nr_hwcur = nm_i;
9582d873474SStephen Hurd 
9592d873474SStephen Hurd 	bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
9602d873474SStephen Hurd 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
961de5b4610SVincenzo Maffione 	ctx->isc_rxd_flush(ctx->ifc_softc, rxq->ifr_id, fl->ifl_id,
962de5b4610SVincenzo Maffione 	    nm_prev(nic_i, lim));
96364e6fc13SStephen Hurd 	DBG_COUNTER_INC(rxd_flush);
964530960beSVincenzo Maffione 
9652d873474SStephen Hurd 	return (0);
9662d873474SStephen Hurd }
9672d873474SStephen Hurd 
96817cec474SVincenzo Maffione #define NETMAP_TX_TIMER_US	90
96917cec474SVincenzo Maffione 
9704c7070dbSScott Long /*
9714c7070dbSScott Long  * Reconcile kernel and user view of the transmit ring.
9724c7070dbSScott Long  *
9734c7070dbSScott Long  * All information is in the kring.
9744c7070dbSScott Long  * Userspace wants to send packets up to the one before kring->rhead,
9754c7070dbSScott Long  * kernel knows kring->nr_hwcur is the first unsent packet.
9764c7070dbSScott Long  *
9774c7070dbSScott Long  * Here we push packets out (as many as possible), and possibly
9784c7070dbSScott Long  * reclaim buffers from previously completed transmission.
9794c7070dbSScott Long  *
9804c7070dbSScott Long  * The caller (netmap) guarantees that there is only one instance
9814c7070dbSScott Long  * running at any time. Any interference with other driver
9824c7070dbSScott Long  * methods should be handled by the individual drivers.
9834c7070dbSScott Long  */
9844c7070dbSScott Long static int
9854c7070dbSScott Long iflib_netmap_txsync(struct netmap_kring *kring, int flags)
9864c7070dbSScott Long {
9874c7070dbSScott Long 	struct netmap_adapter *na = kring->na;
9881722eeacSMarius Strobl 	if_t ifp = na->ifp;
9894c7070dbSScott Long 	struct netmap_ring *ring = kring->ring;
990dd7fbcf1SStephen Hurd 	u_int nm_i;	/* index into the netmap kring */
9914c7070dbSScott Long 	u_int nic_i;	/* index into the NIC ring */
9924c7070dbSScott Long 	u_int n;
9934c7070dbSScott Long 	u_int const lim = kring->nkr_num_slots - 1;
9944c7070dbSScott Long 	u_int const head = kring->rhead;
9954c7070dbSScott Long 	struct if_pkt_info pi;
99666fa12d8SStephan de Wit 	int tx_pkts = 0, tx_bytes = 0;
9974c7070dbSScott Long 
9984c7070dbSScott Long 	/*
9994c7070dbSScott Long 	 * interrupts on every tx packet are expensive so request
10004c7070dbSScott Long 	 * them every half ring, or where NS_REPORT is set
10014c7070dbSScott Long 	 */
10024c7070dbSScott Long 	u_int report_frequency = kring->nkr_num_slots >> 1;
10034c7070dbSScott Long 	/* device-specific */
10044c7070dbSScott Long 	if_ctx_t ctx = ifp->if_softc;
10054c7070dbSScott Long 	iflib_txq_t txq = &ctx->ifc_txqs[kring->ring_id];
10064c7070dbSScott Long 
100795dcf343SMarius Strobl 	bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
10084c7070dbSScott Long 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
10094c7070dbSScott Long 
10104c7070dbSScott Long 	/*
10114c7070dbSScott Long 	 * First part: process new packets to send.
1012dd7fbcf1SStephen Hurd 	 * nm_i is the current index in the netmap kring,
10134c7070dbSScott Long 	 * nic_i is the corresponding index in the NIC ring.
10144c7070dbSScott Long 	 *
10154c7070dbSScott Long 	 * If we have packets to send (nm_i != head)
10164c7070dbSScott Long 	 * iterate over the netmap ring, fetch length and update
10174c7070dbSScott Long 	 * the corresponding slot in the NIC ring. Some drivers also
10184c7070dbSScott Long 	 * need to update the buffer's physical address in the NIC slot
10194c7070dbSScott Long 	 * even NS_BUF_CHANGED is not set (PNMB computes the addresses).
10204c7070dbSScott Long 	 *
10214c7070dbSScott Long 	 * The netmap_reload_map() calls is especially expensive,
10224c7070dbSScott Long 	 * even when (as in this case) the tag is 0, so do only
10234c7070dbSScott Long 	 * when the buffer has actually changed.
10244c7070dbSScott Long 	 *
10254c7070dbSScott Long 	 * If possible do not set the report/intr bit on all slots,
10264c7070dbSScott Long 	 * but only a few times per ring or when NS_REPORT is set.
10274c7070dbSScott Long 	 *
10284c7070dbSScott Long 	 * Finally, on 10G and faster drivers, it might be useful
10294c7070dbSScott Long 	 * to prefetch the next slot and txr entry.
10304c7070dbSScott Long 	 */
10314c7070dbSScott Long 
1032dd7fbcf1SStephen Hurd 	nm_i = kring->nr_hwcur;
10335ee36c68SStephen Hurd 	if (nm_i != head) {	/* we have new packets to send */
1034aceaccabSVincenzo Maffione 		uint32_t pkt_len = 0, seg_idx = 0;
1035aceaccabSVincenzo Maffione 		int nic_i_start = -1, flags = 0;
103695246abbSSean Bruno 		pkt_info_zero(&pi);
103795246abbSSean Bruno 		pi.ipi_segs = txq->ift_segs;
103895246abbSSean Bruno 		pi.ipi_qsidx = kring->ring_id;
10394c7070dbSScott Long 		nic_i = netmap_idx_k2n(kring, nm_i);
10404c7070dbSScott Long 
10414c7070dbSScott Long 		__builtin_prefetch(&ring->slot[nm_i]);
10424c7070dbSScott Long 		__builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i]);
10434c7070dbSScott Long 		__builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i]);
10444c7070dbSScott Long 
10454c7070dbSScott Long 		for (n = 0; nm_i != head; n++) {
10464c7070dbSScott Long 			struct netmap_slot *slot = &ring->slot[nm_i];
1047361e9501SVincenzo Maffione 			uint64_t offset = nm_get_offset(kring, slot);
10484c7070dbSScott Long 			u_int len = slot->len;
10490a1b74a3SSean Bruno 			uint64_t paddr;
10504c7070dbSScott Long 			void *addr = PNMB(na, slot, &paddr);
1051aceaccabSVincenzo Maffione 
1052aceaccabSVincenzo Maffione 			flags |= (slot->flags & NS_REPORT ||
10534c7070dbSScott Long 				nic_i == 0 || nic_i == report_frequency) ?
10544c7070dbSScott Long 				IPI_TX_INTR : 0;
10554c7070dbSScott Long 
1056aceaccabSVincenzo Maffione 			/*
1057aceaccabSVincenzo Maffione 			 * If this is the first packet fragment, save the
1058aceaccabSVincenzo Maffione 			 * index of the first NIC slot for later.
1059aceaccabSVincenzo Maffione 			 */
1060aceaccabSVincenzo Maffione 			if (nic_i_start < 0)
1061aceaccabSVincenzo Maffione 				nic_i_start = nic_i;
1062aceaccabSVincenzo Maffione 
1063361e9501SVincenzo Maffione 			pi.ipi_segs[seg_idx].ds_addr = paddr + offset;
1064aceaccabSVincenzo Maffione 			pi.ipi_segs[seg_idx].ds_len = len;
1065aceaccabSVincenzo Maffione 			if (len) {
1066aceaccabSVincenzo Maffione 				pkt_len += len;
1067aceaccabSVincenzo Maffione 				seg_idx++;
1068aceaccabSVincenzo Maffione 			}
1069aceaccabSVincenzo Maffione 
1070aceaccabSVincenzo Maffione 			if (!(slot->flags & NS_MOREFRAG)) {
1071aceaccabSVincenzo Maffione 				pi.ipi_len = pkt_len;
1072aceaccabSVincenzo Maffione 				pi.ipi_nsegs = seg_idx;
1073aceaccabSVincenzo Maffione 				pi.ipi_pidx = nic_i_start;
107495246abbSSean Bruno 				pi.ipi_ndescs = 0;
10754c7070dbSScott Long 				pi.ipi_flags = flags;
10764c7070dbSScott Long 
1077aceaccabSVincenzo Maffione 				/* Prepare the NIC TX ring. */
10784c7070dbSScott Long 				ctx->isc_txd_encap(ctx->ifc_softc, &pi);
107964e6fc13SStephen Hurd 				DBG_COUNTER_INC(tx_encap);
10804c7070dbSScott Long 
108166fa12d8SStephan de Wit 				/* Update transmit counters */
108266fa12d8SStephan de Wit 				tx_bytes += pi.ipi_len;
108366fa12d8SStephan de Wit 				tx_pkts++;
108466fa12d8SStephan de Wit 
1085aceaccabSVincenzo Maffione 				/* Reinit per-packet info for the next one. */
1086aceaccabSVincenzo Maffione 				flags = seg_idx = pkt_len = 0;
1087aceaccabSVincenzo Maffione 				nic_i_start = -1;
1088aceaccabSVincenzo Maffione 			}
1089aceaccabSVincenzo Maffione 
10904c7070dbSScott Long 			/* prefetch for next round */
10914c7070dbSScott Long 			__builtin_prefetch(&ring->slot[nm_i + 1]);
10924c7070dbSScott Long 			__builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i + 1]);
10934c7070dbSScott Long 			__builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i + 1]);
10944c7070dbSScott Long 
1095361e9501SVincenzo Maffione 			NM_CHECK_ADDR_LEN_OFF(na, len, offset);
10964c7070dbSScott Long 
10974c7070dbSScott Long 			if (slot->flags & NS_BUF_CHANGED) {
10984c7070dbSScott Long 				/* buffer has changed, reload map */
1099bfce461eSMarius Strobl 				netmap_reload_map(na, txq->ift_buf_tag,
1100bfce461eSMarius Strobl 				    txq->ift_sds.ifsd_map[nic_i], addr);
11014c7070dbSScott Long 			}
11024c7070dbSScott Long 			/* make sure changes to the buffer are synced */
110395dcf343SMarius Strobl 			bus_dmamap_sync(txq->ift_buf_tag,
110495dcf343SMarius Strobl 			    txq->ift_sds.ifsd_map[nic_i],
11054c7070dbSScott Long 			    BUS_DMASYNC_PREWRITE);
110695dcf343SMarius Strobl 
1107aceaccabSVincenzo Maffione 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
11084c7070dbSScott Long 			nm_i = nm_next(nm_i, lim);
11094c7070dbSScott Long 			nic_i = nm_next(nic_i, lim);
11104c7070dbSScott Long 		}
1111dd7fbcf1SStephen Hurd 		kring->nr_hwcur = nm_i;
11124c7070dbSScott Long 
11134c7070dbSScott Long 		/* synchronize the NIC ring */
111495dcf343SMarius Strobl 		bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
11154c7070dbSScott Long 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11164c7070dbSScott Long 
11174c7070dbSScott Long 		/* (re)start the tx unit up to slot nic_i (excluded) */
11184c7070dbSScott Long 		ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, nic_i);
11194c7070dbSScott Long 	}
11204c7070dbSScott Long 
11214c7070dbSScott Long 	/*
11224c7070dbSScott Long 	 * Second part: reclaim buffers for completed transmissions.
11235ee36c68SStephen Hurd 	 *
11245ee36c68SStephen Hurd 	 * If there are unclaimed buffers, attempt to reclaim them.
112517cec474SVincenzo Maffione 	 * If we don't manage to reclaim them all, and TX IRQs are not in use,
112617cec474SVincenzo Maffione 	 * trigger a per-tx-queue timer to try again later.
11274c7070dbSScott Long 	 */
1128dd7fbcf1SStephen Hurd 	if (kring->nr_hwtail != nm_prev(kring->nr_hwcur, lim)) {
11294c7070dbSScott Long 		if (iflib_tx_credits_update(ctx, txq)) {
11304c7070dbSScott Long 			/* some tx completed, increment avail */
11314c7070dbSScott Long 			nic_i = txq->ift_cidx_processed;
11324c7070dbSScott Long 			kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
11334c7070dbSScott Long 		}
11345ee36c68SStephen Hurd 	}
113517cec474SVincenzo Maffione 
1136dd7fbcf1SStephen Hurd 	if (!(ctx->ifc_flags & IFC_NETMAP_TX_IRQ))
1137dd7fbcf1SStephen Hurd 		if (kring->nr_hwtail != nm_prev(kring->nr_hwcur, lim)) {
1138be7a6b3dSVincenzo Maffione 			callout_reset_sbt_on(&txq->ift_netmap_timer,
113917cec474SVincenzo Maffione 			    NETMAP_TX_TIMER_US * SBT_1US, SBT_1US,
1140be7a6b3dSVincenzo Maffione 			    iflib_netmap_timer, txq,
1141be7a6b3dSVincenzo Maffione 			    txq->ift_netmap_timer.c_cpu, 0);
11425ee36c68SStephen Hurd 		}
114366fa12d8SStephan de Wit 
114466fa12d8SStephan de Wit 	if_inc_counter(ifp, IFCOUNTER_OBYTES, tx_bytes);
114566fa12d8SStephan de Wit 	if_inc_counter(ifp, IFCOUNTER_OPACKETS, tx_pkts);
114666fa12d8SStephan de Wit 
11474c7070dbSScott Long 	return (0);
11484c7070dbSScott Long }
11494c7070dbSScott Long 
11504c7070dbSScott Long /*
11514c7070dbSScott Long  * Reconcile kernel and user view of the receive ring.
11524c7070dbSScott Long  * Same as for the txsync, this routine must be efficient.
11534c7070dbSScott Long  * The caller guarantees a single invocations, but races against
11544c7070dbSScott Long  * the rest of the driver should be handled here.
11554c7070dbSScott Long  *
11564c7070dbSScott Long  * On call, kring->rhead is the first packet that userspace wants
11574c7070dbSScott Long  * to keep, and kring->rcur is the wakeup point.
11584c7070dbSScott Long  * The kernel has previously reported packets up to kring->rtail.
11594c7070dbSScott Long  *
11604c7070dbSScott Long  * If (flags & NAF_FORCE_READ) also check for incoming packets irrespective
11614c7070dbSScott Long  * of whether or not we received an interrupt.
11624c7070dbSScott Long  */
11634c7070dbSScott Long static int
11644c7070dbSScott Long iflib_netmap_rxsync(struct netmap_kring *kring, int flags)
11654c7070dbSScott Long {
11664c7070dbSScott Long 	struct netmap_adapter *na = kring->na;
11674c7070dbSScott Long 	struct netmap_ring *ring = kring->ring;
11681722eeacSMarius Strobl 	if_t ifp = na->ifp;
116995246abbSSean Bruno 	uint32_t nm_i;	/* index into the netmap ring */
11702d873474SStephen Hurd 	uint32_t nic_i;	/* index into the NIC ring */
1171ee07345dSVincenzo Maffione 	u_int n;
11724c7070dbSScott Long 	u_int const lim = kring->nkr_num_slots - 1;
11734c7070dbSScott Long 	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
117466fa12d8SStephan de Wit 	int i = 0, rx_bytes = 0, rx_pkts = 0;
117595246abbSSean Bruno 
11764c7070dbSScott Long 	if_ctx_t ctx = ifp->if_softc;
11776d84e76aSVincenzo Maffione 	if_shared_ctx_t sctx = ctx->ifc_sctx;
11786d84e76aSVincenzo Maffione 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
11794c7070dbSScott Long 	iflib_rxq_t rxq = &ctx->ifc_rxqs[kring->ring_id];
1180ee07345dSVincenzo Maffione 	iflib_fl_t fl = &rxq->ifr_fl[0];
1181ee07345dSVincenzo Maffione 	struct if_rxd_info ri;
11826d84e76aSVincenzo Maffione 	qidx_t *cidxp;
1183ee07345dSVincenzo Maffione 
118495dcf343SMarius Strobl 	/*
1185ee07345dSVincenzo Maffione 	 * netmap only uses free list 0, to avoid out of order consumption
1186ee07345dSVincenzo Maffione 	 * of receive buffers
118795dcf343SMarius Strobl 	 */
118895dcf343SMarius Strobl 
118995dcf343SMarius Strobl 	bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
11904c7070dbSScott Long 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
119195dcf343SMarius Strobl 
11924c7070dbSScott Long 	/*
11934c7070dbSScott Long 	 * First part: import newly received packets.
11944c7070dbSScott Long 	 *
11954c7070dbSScott Long 	 * nm_i is the index of the next free slot in the netmap ring,
11966d84e76aSVincenzo Maffione 	 * nic_i is the index of the next received packet in the NIC ring
11976d84e76aSVincenzo Maffione 	 * (or in the free list 0 if IFLIB_HAS_RXCQ is set), and they may
11986d84e76aSVincenzo Maffione 	 * differ in case if_init() has been called while
11994c7070dbSScott Long 	 * in netmap mode. For the receive ring we have
12004c7070dbSScott Long 	 *
12016d84e76aSVincenzo Maffione 	 *	nic_i = fl->ifl_cidx;
12024c7070dbSScott Long 	 *	nm_i = kring->nr_hwtail (previous)
12034c7070dbSScott Long 	 * and
12044c7070dbSScott Long 	 *	nm_i == (nic_i + kring->nkr_hwofs) % ring_size
12054c7070dbSScott Long 	 *
12066d84e76aSVincenzo Maffione 	 * fl->ifl_cidx is set to 0 on a ring reinit
12074c7070dbSScott Long 	 */
12084c7070dbSScott Long 	if (netmap_no_pendintr || force_update) {
12090ff21267SVincenzo Maffione 		uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim);
12106d84e76aSVincenzo Maffione 		bool have_rxcq = sctx->isc_flags & IFLIB_HAS_RXCQ;
12114c7070dbSScott Long 		int crclen = iflib_crcstrip ? 0 : 4;
12124c7070dbSScott Long 		int error, avail;
12134c7070dbSScott Long 
12146d84e76aSVincenzo Maffione 		/*
12156d84e76aSVincenzo Maffione 		 * For the free list consumer index, we use the same
12166d84e76aSVincenzo Maffione 		 * logic as in iflib_rxeof().
12176d84e76aSVincenzo Maffione 		 */
12186d84e76aSVincenzo Maffione 		if (have_rxcq)
12196d84e76aSVincenzo Maffione 			cidxp = &rxq->ifr_cq_cidx;
12206d84e76aSVincenzo Maffione 		else
12216d84e76aSVincenzo Maffione 			cidxp = &fl->ifl_cidx;
12226d84e76aSVincenzo Maffione 		avail = ctx->isc_rxd_available(ctx->ifc_softc,
12236d84e76aSVincenzo Maffione 		    rxq->ifr_id, *cidxp, USHRT_MAX);
12246d84e76aSVincenzo Maffione 
12254c7070dbSScott Long 		nic_i = fl->ifl_cidx;
12264c7070dbSScott Long 		nm_i = netmap_idx_n2k(kring, nic_i);
1227de5b4610SVincenzo Maffione 		MPASS(nm_i == kring->nr_hwtail);
12280ff21267SVincenzo Maffione 		for (n = 0; avail > 0 && nm_i != hwtail_lim; n++, avail--) {
1229ab2e3f79SStephen Hurd 			rxd_info_zero(&ri);
1230ab2e3f79SStephen Hurd 			ri.iri_frags = rxq->ifr_frags;
1231ab2e3f79SStephen Hurd 			ri.iri_qsidx = kring->ring_id;
1232ab2e3f79SStephen Hurd 			ri.iri_ifp = ctx->ifc_ifp;
12336d84e76aSVincenzo Maffione 			ri.iri_cidx = *cidxp;
123495246abbSSean Bruno 
1235ab2e3f79SStephen Hurd 			error = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri);
1236aceaccabSVincenzo Maffione 			for (i = 0; i < ri.iri_nfrags; i++) {
1237aceaccabSVincenzo Maffione 				if (error) {
1238aceaccabSVincenzo Maffione 					ring->slot[nm_i].len = 0;
12397cb7c6e3SNavdeep Parhar 					ring->slot[nm_i].flags = 0;
1240aceaccabSVincenzo Maffione 				} else {
1241aceaccabSVincenzo Maffione 					ring->slot[nm_i].len = ri.iri_frags[i].irf_len;
1242aceaccabSVincenzo Maffione 					if (i == (ri.iri_nfrags - 1)) {
1243aceaccabSVincenzo Maffione 						ring->slot[nm_i].len -= crclen;
1244aceaccabSVincenzo Maffione 						ring->slot[nm_i].flags = 0;
124566fa12d8SStephan de Wit 
124666fa12d8SStephan de Wit 						/* Update receive counters */
124766fa12d8SStephan de Wit 						rx_bytes += ri.iri_len;
124866fa12d8SStephan de Wit 						rx_pkts++;
1249aceaccabSVincenzo Maffione 					} else
1250aceaccabSVincenzo Maffione 						ring->slot[nm_i].flags = NS_MOREFRAG;
1251aceaccabSVincenzo Maffione 				}
1252aceaccabSVincenzo Maffione 
1253f80efe50SVincenzo Maffione 				bus_dmamap_sync(fl->ifl_buf_tag,
1254f80efe50SVincenzo Maffione 				    fl->ifl_sds.ifsd_map[nic_i], BUS_DMASYNC_POSTREAD);
1255f80efe50SVincenzo Maffione 				nm_i = nm_next(nm_i, lim);
1256f80efe50SVincenzo Maffione 				fl->ifl_cidx = nic_i = nm_next(nic_i, lim);
1257f80efe50SVincenzo Maffione 			}
1258f80efe50SVincenzo Maffione 
12596d84e76aSVincenzo Maffione 			if (have_rxcq) {
12606d84e76aSVincenzo Maffione 				*cidxp = ri.iri_cidx;
12616d84e76aSVincenzo Maffione 				while (*cidxp >= scctx->isc_nrxd[0])
12626d84e76aSVincenzo Maffione 					*cidxp -= scctx->isc_nrxd[0];
12636d84e76aSVincenzo Maffione 			}
1264aceaccabSVincenzo Maffione 
1265aceaccabSVincenzo Maffione 		}
12664c7070dbSScott Long 		if (n) { /* update the state variables */
12674c7070dbSScott Long 			if (netmap_no_pendintr && !force_update) {
12684c7070dbSScott Long 				/* diagnostics */
12694c7070dbSScott Long 				iflib_rx_miss ++;
12704c7070dbSScott Long 				iflib_rx_miss_bufs += n;
12714c7070dbSScott Long 			}
1272dd7fbcf1SStephen Hurd 			kring->nr_hwtail = nm_i;
12734c7070dbSScott Long 		}
12744c7070dbSScott Long 		kring->nr_kflags &= ~NKR_PENDINTR;
12754c7070dbSScott Long 	}
12764c7070dbSScott Long 	/*
12774c7070dbSScott Long 	 * Second part: skip past packets that userspace has released.
12784c7070dbSScott Long 	 * (kring->nr_hwcur to head excluded),
12794c7070dbSScott Long 	 * and make the buffers available for reception.
12804c7070dbSScott Long 	 * As usual nm_i is the index in the netmap ring,
12814c7070dbSScott Long 	 * nic_i is the index in the NIC ring, and
12824c7070dbSScott Long 	 * nm_i == (nic_i + kring->nkr_hwofs) % ring_size
12834c7070dbSScott Long 	 */
1284de5b4610SVincenzo Maffione 	netmap_fl_refill(rxq, kring, false);
128595246abbSSean Bruno 
128666fa12d8SStephan de Wit 	if_inc_counter(ifp, IFCOUNTER_IBYTES, rx_bytes);
128766fa12d8SStephan de Wit 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_pkts);
128866fa12d8SStephan de Wit 
1289de5b4610SVincenzo Maffione 	return (0);
12904c7070dbSScott Long }
12914c7070dbSScott Long 
129295246abbSSean Bruno static void
129395246abbSSean Bruno iflib_netmap_intr(struct netmap_adapter *na, int onoff)
129495246abbSSean Bruno {
12951722eeacSMarius Strobl 	if_ctx_t ctx = na->ifp->if_softc;
129695246abbSSean Bruno 
1297ab2e3f79SStephen Hurd 	CTX_LOCK(ctx);
129895246abbSSean Bruno 	if (onoff) {
129995246abbSSean Bruno 		IFDI_INTR_ENABLE(ctx);
130095246abbSSean Bruno 	} else {
130195246abbSSean Bruno 		IFDI_INTR_DISABLE(ctx);
130295246abbSSean Bruno 	}
1303ab2e3f79SStephen Hurd 	CTX_UNLOCK(ctx);
130495246abbSSean Bruno }
130595246abbSSean Bruno 
13064c7070dbSScott Long static int
13074c7070dbSScott Long iflib_netmap_attach(if_ctx_t ctx)
13084c7070dbSScott Long {
13094c7070dbSScott Long 	struct netmap_adapter na;
13104c7070dbSScott Long 
13114c7070dbSScott Long 	bzero(&na, sizeof(na));
13124c7070dbSScott Long 
13134c7070dbSScott Long 	na.ifp = ctx->ifc_ifp;
1314361e9501SVincenzo Maffione 	na.na_flags = NAF_BDG_MAYSLEEP | NAF_MOREFRAG | NAF_OFFSETS;
13154c7070dbSScott Long 	MPASS(ctx->ifc_softc_ctx.isc_ntxqsets);
13164c7070dbSScott Long 	MPASS(ctx->ifc_softc_ctx.isc_nrxqsets);
13174c7070dbSScott Long 
1318ac11d857SVincenzo Maffione 	na.num_tx_desc = iflib_num_tx_descs(ctx);
1319ac11d857SVincenzo Maffione 	na.num_rx_desc = iflib_num_rx_descs(ctx);
13204c7070dbSScott Long 	na.nm_txsync = iflib_netmap_txsync;
13214c7070dbSScott Long 	na.nm_rxsync = iflib_netmap_rxsync;
13224c7070dbSScott Long 	na.nm_register = iflib_netmap_register;
132395246abbSSean Bruno 	na.nm_intr = iflib_netmap_intr;
132421d0c012Syou@x 	na.nm_config = iflib_netmap_config;
13254c7070dbSScott Long 	na.num_tx_rings = ctx->ifc_softc_ctx.isc_ntxqsets;
13264c7070dbSScott Long 	na.num_rx_rings = ctx->ifc_softc_ctx.isc_nrxqsets;
13274c7070dbSScott Long 	return (netmap_attach(&na));
13284c7070dbSScott Long }
13294c7070dbSScott Long 
1330d8b2d26bSVincenzo Maffione static int
13314c7070dbSScott Long iflib_netmap_txq_init(if_ctx_t ctx, iflib_txq_t txq)
13324c7070dbSScott Long {
13334c7070dbSScott Long 	struct netmap_adapter *na = NA(ctx->ifc_ifp);
13344c7070dbSScott Long 	struct netmap_slot *slot;
13354c7070dbSScott Long 
13364c7070dbSScott Long 	slot = netmap_reset(na, NR_TX, txq->ift_id, 0);
1337e099b90bSPedro F. Giffuni 	if (slot == NULL)
1338d8b2d26bSVincenzo Maffione 		return (0);
133923ac9029SStephen Hurd 	for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxd[0]; i++) {
13404c7070dbSScott Long 		/*
13414c7070dbSScott Long 		 * In netmap mode, set the map for the packet buffer.
13424c7070dbSScott Long 		 * NOTE: Some drivers (not this one) also need to set
13434c7070dbSScott Long 		 * the physical buffer address in the NIC ring.
13444c7070dbSScott Long 		 * netmap_idx_n2k() maps a nic index, i, into the corresponding
13454c7070dbSScott Long 		 * netmap slot index, si
13464c7070dbSScott Long 		 */
13472ff91c17SVincenzo Maffione 		int si = netmap_idx_n2k(na->tx_rings[txq->ift_id], i);
1348bfce461eSMarius Strobl 		netmap_load_map(na, txq->ift_buf_tag, txq->ift_sds.ifsd_map[i],
1349bfce461eSMarius Strobl 		    NMB(na, slot + si));
13504c7070dbSScott Long 	}
1351d8b2d26bSVincenzo Maffione 	return (1);
13524c7070dbSScott Long }
13532d873474SStephen Hurd 
1354d8b2d26bSVincenzo Maffione static int
13554c7070dbSScott Long iflib_netmap_rxq_init(if_ctx_t ctx, iflib_rxq_t rxq)
13564c7070dbSScott Long {
13574c7070dbSScott Long 	struct netmap_adapter *na = NA(ctx->ifc_ifp);
1358d8b2d26bSVincenzo Maffione 	struct netmap_kring *kring;
13594c7070dbSScott Long 	struct netmap_slot *slot;
13604c7070dbSScott Long 
13614c7070dbSScott Long 	slot = netmap_reset(na, NR_RX, rxq->ifr_id, 0);
1362e099b90bSPedro F. Giffuni 	if (slot == NULL)
1363d8b2d26bSVincenzo Maffione 		return (0);
1364d8b2d26bSVincenzo Maffione 	kring = na->rx_rings[rxq->ifr_id];
1365de5b4610SVincenzo Maffione 	netmap_fl_refill(rxq, kring, true);
1366d8b2d26bSVincenzo Maffione 	return (1);
13674c7070dbSScott Long }
13684c7070dbSScott Long 
1369dd7fbcf1SStephen Hurd static void
137017cec474SVincenzo Maffione iflib_netmap_timer(void *arg)
1371dd7fbcf1SStephen Hurd {
137217cec474SVincenzo Maffione 	iflib_txq_t txq = arg;
137317cec474SVincenzo Maffione 	if_ctx_t ctx = txq->ift_ctx;
1374dd7fbcf1SStephen Hurd 
137517cec474SVincenzo Maffione 	/*
137617cec474SVincenzo Maffione 	 * Wake up the netmap application, to give it a chance to
137717cec474SVincenzo Maffione 	 * call txsync and reclaim more completed TX buffers.
137817cec474SVincenzo Maffione 	 */
137917cec474SVincenzo Maffione 	netmap_tx_irq(ctx->ifc_ifp, txq->ift_id);
1380dd7fbcf1SStephen Hurd }
1381dd7fbcf1SStephen Hurd 
13824c7070dbSScott Long #define iflib_netmap_detach(ifp) netmap_detach(ifp)
13834c7070dbSScott Long 
13844c7070dbSScott Long #else
1385d8b2d26bSVincenzo Maffione #define iflib_netmap_txq_init(ctx, txq) (0)
1386d8b2d26bSVincenzo Maffione #define iflib_netmap_rxq_init(ctx, rxq) (0)
13874c7070dbSScott Long #define iflib_netmap_detach(ifp)
13888aa8484cSVincenzo Maffione #define netmap_enable_all_rings(ifp)
13898aa8484cSVincenzo Maffione #define netmap_disable_all_rings(ifp)
13904c7070dbSScott Long 
13914c7070dbSScott Long #define iflib_netmap_attach(ctx) (0)
13924c7070dbSScott Long #define netmap_rx_irq(ifp, qid, budget) (0)
13934c7070dbSScott Long #endif
13944c7070dbSScott Long 
13954c7070dbSScott Long #if defined(__i386__) || defined(__amd64__)
13964c7070dbSScott Long static __inline void
13974c7070dbSScott Long prefetch(void *x)
13984c7070dbSScott Long {
13994c7070dbSScott Long 	__asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
14004c7070dbSScott Long }
14013429c02fSStephen Hurd static __inline void
14023429c02fSStephen Hurd prefetch2cachelines(void *x)
14033429c02fSStephen Hurd {
14043429c02fSStephen Hurd 	__asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
14053429c02fSStephen Hurd #if (CACHE_LINE_SIZE < 128)
14063429c02fSStephen Hurd 	__asm volatile("prefetcht0 %0" :: "m" (*(((unsigned long *)x)+CACHE_LINE_SIZE/(sizeof(unsigned long)))));
14073429c02fSStephen Hurd #endif
14083429c02fSStephen Hurd }
14094c7070dbSScott Long #else
14104c7070dbSScott Long #define prefetch(x)
14113429c02fSStephen Hurd #define prefetch2cachelines(x)
14124c7070dbSScott Long #endif
14134c7070dbSScott Long 
14144c7070dbSScott Long static void
141510e0d938SStephen Hurd iru_init(if_rxd_update_t iru, iflib_rxq_t rxq, uint8_t flid)
141610e0d938SStephen Hurd {
141710e0d938SStephen Hurd 	iflib_fl_t fl;
141810e0d938SStephen Hurd 
141910e0d938SStephen Hurd 	fl = &rxq->ifr_fl[flid];
142010e0d938SStephen Hurd 	iru->iru_paddrs = fl->ifl_bus_addrs;
142110e0d938SStephen Hurd 	iru->iru_idxs = fl->ifl_rxd_idxs;
142210e0d938SStephen Hurd 	iru->iru_qsidx = rxq->ifr_id;
142310e0d938SStephen Hurd 	iru->iru_buf_size = fl->ifl_buf_size;
142410e0d938SStephen Hurd 	iru->iru_flidx = fl->ifl_id;
142510e0d938SStephen Hurd }
142610e0d938SStephen Hurd 
142710e0d938SStephen Hurd static void
14284c7070dbSScott Long _iflib_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
14294c7070dbSScott Long {
14304c7070dbSScott Long 	if (err)
14314c7070dbSScott Long 		return;
14324c7070dbSScott Long 	*(bus_addr_t *) arg = segs[0].ds_addr;
14334c7070dbSScott Long }
14344c7070dbSScott Long 
14356dd69f00SMarcin Wojtas #define	DMA_WIDTH_TO_BUS_LOWADDR(width)				\
1436ef567155SMarcin Wojtas 	(((width) == 0) || (width) == flsll(BUS_SPACE_MAXADDR) ?	\
14376dd69f00SMarcin Wojtas 	    BUS_SPACE_MAXADDR : (1ULL << (width)) - 1ULL)
14386dd69f00SMarcin Wojtas 
14394c7070dbSScott Long int
14408f82136aSPatrick Kelsey iflib_dma_alloc_align(if_ctx_t ctx, int size, int align, iflib_dma_info_t dma, int mapflags)
14414c7070dbSScott Long {
14424c7070dbSScott Long 	int err;
14434c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
14446dd69f00SMarcin Wojtas 	bus_addr_t lowaddr;
14456dd69f00SMarcin Wojtas 
14466dd69f00SMarcin Wojtas 	lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(ctx->ifc_softc_ctx.isc_dma_width);
14474c7070dbSScott Long 
14484c7070dbSScott Long 	err = bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
14498f82136aSPatrick Kelsey 				align, 0,		/* alignment, bounds */
14506dd69f00SMarcin Wojtas 				lowaddr,		/* lowaddr */
14514c7070dbSScott Long 				BUS_SPACE_MAXADDR,	/* highaddr */
14524c7070dbSScott Long 				NULL, NULL,		/* filter, filterarg */
14534c7070dbSScott Long 				size,			/* maxsize */
14544c7070dbSScott Long 				1,			/* nsegments */
14554c7070dbSScott Long 				size,			/* maxsegsize */
14564c7070dbSScott Long 				BUS_DMA_ALLOCNOW,	/* flags */
14574c7070dbSScott Long 				NULL,			/* lockfunc */
14584c7070dbSScott Long 				NULL,			/* lockarg */
14594c7070dbSScott Long 				&dma->idi_tag);
14604c7070dbSScott Long 	if (err) {
14614c7070dbSScott Long 		device_printf(dev,
14624c7070dbSScott Long 		    "%s: bus_dma_tag_create failed: %d\n",
14634c7070dbSScott Long 		    __func__, err);
14644c7070dbSScott Long 		goto fail_0;
14654c7070dbSScott Long 	}
14664c7070dbSScott Long 
14674c7070dbSScott Long 	err = bus_dmamem_alloc(dma->idi_tag, (void**) &dma->idi_vaddr,
14684c7070dbSScott Long 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_ZERO, &dma->idi_map);
14694c7070dbSScott Long 	if (err) {
14704c7070dbSScott Long 		device_printf(dev,
14714c7070dbSScott Long 		    "%s: bus_dmamem_alloc(%ju) failed: %d\n",
14724c7070dbSScott Long 		    __func__, (uintmax_t)size, err);
14734c7070dbSScott Long 		goto fail_1;
14744c7070dbSScott Long 	}
14754c7070dbSScott Long 
14764c7070dbSScott Long 	dma->idi_paddr = IF_BAD_DMA;
14774c7070dbSScott Long 	err = bus_dmamap_load(dma->idi_tag, dma->idi_map, dma->idi_vaddr,
14784c7070dbSScott Long 	    size, _iflib_dmamap_cb, &dma->idi_paddr, mapflags | BUS_DMA_NOWAIT);
14794c7070dbSScott Long 	if (err || dma->idi_paddr == IF_BAD_DMA) {
14804c7070dbSScott Long 		device_printf(dev,
14814c7070dbSScott Long 		    "%s: bus_dmamap_load failed: %d\n",
14824c7070dbSScott Long 		    __func__, err);
14834c7070dbSScott Long 		goto fail_2;
14844c7070dbSScott Long 	}
14854c7070dbSScott Long 
14864c7070dbSScott Long 	dma->idi_size = size;
14874c7070dbSScott Long 	return (0);
14884c7070dbSScott Long 
14894c7070dbSScott Long fail_2:
14904c7070dbSScott Long 	bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map);
14914c7070dbSScott Long fail_1:
14924c7070dbSScott Long 	bus_dma_tag_destroy(dma->idi_tag);
14934c7070dbSScott Long fail_0:
14944c7070dbSScott Long 	dma->idi_tag = NULL;
14954c7070dbSScott Long 
14964c7070dbSScott Long 	return (err);
14974c7070dbSScott Long }
14984c7070dbSScott Long 
14994c7070dbSScott Long int
15008f82136aSPatrick Kelsey iflib_dma_alloc(if_ctx_t ctx, int size, iflib_dma_info_t dma, int mapflags)
15018f82136aSPatrick Kelsey {
15028f82136aSPatrick Kelsey 	if_shared_ctx_t sctx = ctx->ifc_sctx;
15038f82136aSPatrick Kelsey 
15048f82136aSPatrick Kelsey 	KASSERT(sctx->isc_q_align != 0, ("alignment value not initialized"));
15058f82136aSPatrick Kelsey 
15068f82136aSPatrick Kelsey 	return (iflib_dma_alloc_align(ctx, size, sctx->isc_q_align, dma, mapflags));
15078f82136aSPatrick Kelsey }
15088f82136aSPatrick Kelsey 
15098f82136aSPatrick Kelsey int
15104c7070dbSScott Long iflib_dma_alloc_multi(if_ctx_t ctx, int *sizes, iflib_dma_info_t *dmalist, int mapflags, int count)
15114c7070dbSScott Long {
15124c7070dbSScott Long 	int i, err;
15134c7070dbSScott Long 	iflib_dma_info_t *dmaiter;
15144c7070dbSScott Long 
15154c7070dbSScott Long 	dmaiter = dmalist;
15164c7070dbSScott Long 	for (i = 0; i < count; i++, dmaiter++) {
15174c7070dbSScott Long 		if ((err = iflib_dma_alloc(ctx, sizes[i], *dmaiter, mapflags)) != 0)
15184c7070dbSScott Long 			break;
15194c7070dbSScott Long 	}
15204c7070dbSScott Long 	if (err)
15214c7070dbSScott Long 		iflib_dma_free_multi(dmalist, i);
15224c7070dbSScott Long 	return (err);
15234c7070dbSScott Long }
15244c7070dbSScott Long 
15254c7070dbSScott Long void
15264c7070dbSScott Long iflib_dma_free(iflib_dma_info_t dma)
15274c7070dbSScott Long {
15284c7070dbSScott Long 	if (dma->idi_tag == NULL)
15294c7070dbSScott Long 		return;
15304c7070dbSScott Long 	if (dma->idi_paddr != IF_BAD_DMA) {
15314c7070dbSScott Long 		bus_dmamap_sync(dma->idi_tag, dma->idi_map,
15324c7070dbSScott Long 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
15334c7070dbSScott Long 		bus_dmamap_unload(dma->idi_tag, dma->idi_map);
15344c7070dbSScott Long 		dma->idi_paddr = IF_BAD_DMA;
15354c7070dbSScott Long 	}
15364c7070dbSScott Long 	if (dma->idi_vaddr != NULL) {
15374c7070dbSScott Long 		bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map);
15384c7070dbSScott Long 		dma->idi_vaddr = NULL;
15394c7070dbSScott Long 	}
15404c7070dbSScott Long 	bus_dma_tag_destroy(dma->idi_tag);
15414c7070dbSScott Long 	dma->idi_tag = NULL;
15424c7070dbSScott Long }
15434c7070dbSScott Long 
15444c7070dbSScott Long void
15454c7070dbSScott Long iflib_dma_free_multi(iflib_dma_info_t *dmalist, int count)
15464c7070dbSScott Long {
15474c7070dbSScott Long 	int i;
15484c7070dbSScott Long 	iflib_dma_info_t *dmaiter = dmalist;
15494c7070dbSScott Long 
15504c7070dbSScott Long 	for (i = 0; i < count; i++, dmaiter++)
15514c7070dbSScott Long 		iflib_dma_free(*dmaiter);
15524c7070dbSScott Long }
15534c7070dbSScott Long 
15544c7070dbSScott Long static int
15554c7070dbSScott Long iflib_fast_intr(void *arg)
15564c7070dbSScott Long {
15574c7070dbSScott Long 	iflib_filter_info_t info = arg;
15584c7070dbSScott Long 	struct grouptask *gtask = info->ifi_task;
1559ca62461bSStephen Hurd 	int result;
1560ca62461bSStephen Hurd 
156195246abbSSean Bruno 	DBG_COUNTER_INC(fast_intrs);
1562ca62461bSStephen Hurd 	if (info->ifi_filter != NULL) {
1563ca62461bSStephen Hurd 		result = info->ifi_filter(info->ifi_filter_arg);
1564ca62461bSStephen Hurd 		if ((result & FILTER_SCHEDULE_THREAD) == 0)
1565ca62461bSStephen Hurd 			return (result);
1566ca62461bSStephen Hurd 	}
156795246abbSSean Bruno 
156895246abbSSean Bruno 	GROUPTASK_ENQUEUE(gtask);
156995246abbSSean Bruno 	return (FILTER_HANDLED);
157095246abbSSean Bruno }
157195246abbSSean Bruno 
157295246abbSSean Bruno static int
157395246abbSSean Bruno iflib_fast_intr_rxtx(void *arg)
157495246abbSSean Bruno {
157595246abbSSean Bruno 	iflib_filter_info_t info = arg;
157695246abbSSean Bruno 	struct grouptask *gtask = info->ifi_task;
157795dcf343SMarius Strobl 	if_ctx_t ctx;
157895246abbSSean Bruno 	iflib_rxq_t rxq = (iflib_rxq_t)info->ifi_ctx;
157995dcf343SMarius Strobl 	iflib_txq_t txq;
158095dcf343SMarius Strobl 	void *sc;
1581ca62461bSStephen Hurd 	int i, cidx, result;
158295dcf343SMarius Strobl 	qidx_t txqid;
15833d10e9edSMarius Strobl 	bool intr_enable, intr_legacy;
158495246abbSSean Bruno 
158595246abbSSean Bruno 	DBG_COUNTER_INC(fast_intrs);
1586ca62461bSStephen Hurd 	if (info->ifi_filter != NULL) {
1587ca62461bSStephen Hurd 		result = info->ifi_filter(info->ifi_filter_arg);
1588ca62461bSStephen Hurd 		if ((result & FILTER_SCHEDULE_THREAD) == 0)
1589ca62461bSStephen Hurd 			return (result);
1590ca62461bSStephen Hurd 	}
159195246abbSSean Bruno 
159295dcf343SMarius Strobl 	ctx = rxq->ifr_ctx;
159395dcf343SMarius Strobl 	sc = ctx->ifc_softc;
15943d10e9edSMarius Strobl 	intr_enable = false;
15953d10e9edSMarius Strobl 	intr_legacy = !!(ctx->ifc_flags & IFC_LEGACY);
15961ae4848cSMatt Macy 	MPASS(rxq->ifr_ntxqirq);
159795246abbSSean Bruno 	for (i = 0; i < rxq->ifr_ntxqirq; i++) {
159895dcf343SMarius Strobl 		txqid = rxq->ifr_txqid[i];
159995dcf343SMarius Strobl 		txq = &ctx->ifc_txqs[txqid];
160095dcf343SMarius Strobl 		bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
16018a04b53dSKonstantin Belousov 		    BUS_DMASYNC_POSTREAD);
160295dcf343SMarius Strobl 		if (!ctx->isc_txd_credits_update(sc, txqid, false)) {
16033d10e9edSMarius Strobl 			if (intr_legacy)
16043d10e9edSMarius Strobl 				intr_enable = true;
16053d10e9edSMarius Strobl 			else
160695246abbSSean Bruno 				IFDI_TX_QUEUE_INTR_ENABLE(ctx, txqid);
160795246abbSSean Bruno 			continue;
160895246abbSSean Bruno 		}
160995dcf343SMarius Strobl 		GROUPTASK_ENQUEUE(&txq->ift_task);
161095246abbSSean Bruno 	}
161195246abbSSean Bruno 	if (ctx->ifc_sctx->isc_flags & IFLIB_HAS_RXCQ)
161295246abbSSean Bruno 		cidx = rxq->ifr_cq_cidx;
161395246abbSSean Bruno 	else
161495246abbSSean Bruno 		cidx = rxq->ifr_fl[0].ifl_cidx;
161595246abbSSean Bruno 	if (iflib_rxd_avail(ctx, rxq, cidx, 1))
161695246abbSSean Bruno 		GROUPTASK_ENQUEUE(gtask);
161764e6fc13SStephen Hurd 	else {
16183d10e9edSMarius Strobl 		if (intr_legacy)
16193d10e9edSMarius Strobl 			intr_enable = true;
16203d10e9edSMarius Strobl 		else
162195246abbSSean Bruno 			IFDI_RX_QUEUE_INTR_ENABLE(ctx, rxq->ifr_id);
162264e6fc13SStephen Hurd 		DBG_COUNTER_INC(rx_intr_enables);
162364e6fc13SStephen Hurd 	}
16243d10e9edSMarius Strobl 	if (intr_enable)
16253d10e9edSMarius Strobl 		IFDI_INTR_ENABLE(ctx);
162695246abbSSean Bruno 	return (FILTER_HANDLED);
162795246abbSSean Bruno }
162895246abbSSean Bruno 
162995246abbSSean Bruno static int
163095246abbSSean Bruno iflib_fast_intr_ctx(void *arg)
163195246abbSSean Bruno {
163295246abbSSean Bruno 	iflib_filter_info_t info = arg;
163395246abbSSean Bruno 	struct grouptask *gtask = info->ifi_task;
1634ca62461bSStephen Hurd 	int result;
16354c7070dbSScott Long 
16364c7070dbSScott Long 	DBG_COUNTER_INC(fast_intrs);
1637ca62461bSStephen Hurd 	if (info->ifi_filter != NULL) {
1638ca62461bSStephen Hurd 		result = info->ifi_filter(info->ifi_filter_arg);
1639ca62461bSStephen Hurd 		if ((result & FILTER_SCHEDULE_THREAD) == 0)
1640ca62461bSStephen Hurd 			return (result);
1641ca62461bSStephen Hurd 	}
16424c7070dbSScott Long 
16434c7070dbSScott Long 	GROUPTASK_ENQUEUE(gtask);
16444c7070dbSScott Long 	return (FILTER_HANDLED);
16454c7070dbSScott Long }
16464c7070dbSScott Long 
16474c7070dbSScott Long static int
16484c7070dbSScott Long _iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid,
16494c7070dbSScott Long 		 driver_filter_t filter, driver_intr_t handler, void *arg,
16503e0e6330SStephen Hurd 		 const char *name)
16514c7070dbSScott Long {
16524c7070dbSScott Long 	struct resource *res;
16532b2fc973SSean Bruno 	void *tag = NULL;
16544c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
1655d49e83eaSMarius Strobl 	int flags, i, rc;
16564c7070dbSScott Long 
16572b2fc973SSean Bruno 	flags = RF_ACTIVE;
16582b2fc973SSean Bruno 	if (ctx->ifc_flags & IFC_LEGACY)
16592b2fc973SSean Bruno 		flags |= RF_SHAREABLE;
16604c7070dbSScott Long 	MPASS(rid < 512);
1661d49e83eaSMarius Strobl 	i = rid;
1662d49e83eaSMarius Strobl 	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, flags);
16634c7070dbSScott Long 	if (res == NULL) {
16644c7070dbSScott Long 		device_printf(dev,
16654c7070dbSScott Long 		    "failed to allocate IRQ for rid %d, name %s.\n", rid, name);
16664c7070dbSScott Long 		return (ENOMEM);
16674c7070dbSScott Long 	}
16684c7070dbSScott Long 	irq->ii_res = res;
16694c7070dbSScott Long 	KASSERT(filter == NULL || handler == NULL, ("filter and handler can't both be non-NULL"));
16704c7070dbSScott Long 	rc = bus_setup_intr(dev, res, INTR_MPSAFE | INTR_TYPE_NET,
16714c7070dbSScott Long 						filter, handler, arg, &tag);
16724c7070dbSScott Long 	if (rc != 0) {
16734c7070dbSScott Long 		device_printf(dev,
16744c7070dbSScott Long 		    "failed to setup interrupt for rid %d, name %s: %d\n",
16754c7070dbSScott Long 					  rid, name ? name : "unknown", rc);
16764c7070dbSScott Long 		return (rc);
16774c7070dbSScott Long 	} else if (name)
1678f454e7ebSJohn Baldwin 		bus_describe_intr(dev, res, tag, "%s", name);
16794c7070dbSScott Long 
16804c7070dbSScott Long 	irq->ii_tag = tag;
16814c7070dbSScott Long 	return (0);
16824c7070dbSScott Long }
16834c7070dbSScott Long 
16844c7070dbSScott Long /*********************************************************************
16854c7070dbSScott Long  *
1686bfce461eSMarius Strobl  *  Allocate DMA resources for TX buffers as well as memory for the TX
1687bfce461eSMarius Strobl  *  mbuf map.  TX DMA maps (non-TSO/TSO) and TX mbuf map are kept in a
1688bfce461eSMarius Strobl  *  iflib_sw_tx_desc_array structure, storing all the information that
1689bfce461eSMarius Strobl  *  is needed to transmit a packet on the wire.  This is called only
1690bfce461eSMarius Strobl  *  once at attach, setup is done every reset.
16914c7070dbSScott Long  *
16924c7070dbSScott Long  **********************************************************************/
16934c7070dbSScott Long static int
16944c7070dbSScott Long iflib_txsd_alloc(iflib_txq_t txq)
16954c7070dbSScott Long {
16964c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
16974c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
16984c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
16994c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
17007f87c040SMarius Strobl 	bus_size_t tsomaxsize;
17016dd69f00SMarcin Wojtas 	bus_addr_t lowaddr;
17024c7070dbSScott Long 	int err, nsegments, ntsosegments;
17038a04b53dSKonstantin Belousov 	bool tso;
17044c7070dbSScott Long 
17054c7070dbSScott Long 	nsegments = scctx->isc_tx_nsegments;
17064c7070dbSScott Long 	ntsosegments = scctx->isc_tx_tso_segments_max;
17077f87c040SMarius Strobl 	tsomaxsize = scctx->isc_tx_tso_size_max;
17087f87c040SMarius Strobl 	if (if_getcapabilities(ctx->ifc_ifp) & IFCAP_VLAN_MTU)
17097f87c040SMarius Strobl 		tsomaxsize += sizeof(struct ether_vlan_header);
171023ac9029SStephen Hurd 	MPASS(scctx->isc_ntxd[0] > 0);
171123ac9029SStephen Hurd 	MPASS(scctx->isc_ntxd[txq->ift_br_offset] > 0);
17124c7070dbSScott Long 	MPASS(nsegments > 0);
17137f87c040SMarius Strobl 	if (if_getcapabilities(ctx->ifc_ifp) & IFCAP_TSO) {
17144c7070dbSScott Long 		MPASS(ntsosegments > 0);
17157f87c040SMarius Strobl 		MPASS(sctx->isc_tso_maxsize >= tsomaxsize);
17167f87c040SMarius Strobl 	}
17177f87c040SMarius Strobl 
17186dd69f00SMarcin Wojtas 	lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(scctx->isc_dma_width);
17196dd69f00SMarcin Wojtas 
17204c7070dbSScott Long 	/*
1721bfce461eSMarius Strobl 	 * Set up DMA tags for TX buffers.
17224c7070dbSScott Long 	 */
17234c7070dbSScott Long 	if ((err = bus_dma_tag_create(bus_get_dma_tag(dev),
17244c7070dbSScott Long 			       1, 0,			/* alignment, bounds */
17256dd69f00SMarcin Wojtas 			       lowaddr,			/* lowaddr */
17264c7070dbSScott Long 			       BUS_SPACE_MAXADDR,	/* highaddr */
17274c7070dbSScott Long 			       NULL, NULL,		/* filter, filterarg */
17284c7070dbSScott Long 			       sctx->isc_tx_maxsize,		/* maxsize */
17294c7070dbSScott Long 			       nsegments,	/* nsegments */
17304c7070dbSScott Long 			       sctx->isc_tx_maxsegsize,	/* maxsegsize */
17314c7070dbSScott Long 			       0,			/* flags */
17324c7070dbSScott Long 			       NULL,			/* lockfunc */
17334c7070dbSScott Long 			       NULL,			/* lockfuncarg */
1734bfce461eSMarius Strobl 			       &txq->ift_buf_tag))) {
17354c7070dbSScott Long 		device_printf(dev,"Unable to allocate TX DMA tag: %d\n", err);
17369d0a88deSDimitry Andric 		device_printf(dev,"maxsize: %ju nsegments: %d maxsegsize: %ju\n",
17379d0a88deSDimitry Andric 		    (uintmax_t)sctx->isc_tx_maxsize, nsegments, (uintmax_t)sctx->isc_tx_maxsegsize);
17384c7070dbSScott Long 		goto fail;
17394c7070dbSScott Long 	}
17408a04b53dSKonstantin Belousov 	tso = (if_getcapabilities(ctx->ifc_ifp) & IFCAP_TSO) != 0;
17418a04b53dSKonstantin Belousov 	if (tso && (err = bus_dma_tag_create(bus_get_dma_tag(dev),
17424c7070dbSScott Long 			       1, 0,			/* alignment, bounds */
17436dd69f00SMarcin Wojtas 			       lowaddr,			/* lowaddr */
17444c7070dbSScott Long 			       BUS_SPACE_MAXADDR,	/* highaddr */
17454c7070dbSScott Long 			       NULL, NULL,		/* filter, filterarg */
17467f87c040SMarius Strobl 			       tsomaxsize,		/* maxsize */
17474c7070dbSScott Long 			       ntsosegments,	/* nsegments */
17487f87c040SMarius Strobl 			       sctx->isc_tso_maxsegsize,/* maxsegsize */
17494c7070dbSScott Long 			       0,			/* flags */
17504c7070dbSScott Long 			       NULL,			/* lockfunc */
17514c7070dbSScott Long 			       NULL,			/* lockfuncarg */
1752bfce461eSMarius Strobl 			       &txq->ift_tso_buf_tag))) {
1753bfce461eSMarius Strobl 		device_printf(dev, "Unable to allocate TSO TX DMA tag: %d\n",
1754bfce461eSMarius Strobl 		    err);
17554c7070dbSScott Long 		goto fail;
17564c7070dbSScott Long 	}
1757bfce461eSMarius Strobl 
1758bfce461eSMarius Strobl 	/* Allocate memory for the TX mbuf map. */
17594c7070dbSScott Long 	if (!(txq->ift_sds.ifsd_m =
1760ac2fffa4SPedro F. Giffuni 	    (struct mbuf **) malloc(sizeof(struct mbuf *) *
1761ac2fffa4SPedro F. Giffuni 	    scctx->isc_ntxd[txq->ift_br_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1762bfce461eSMarius Strobl 		device_printf(dev, "Unable to allocate TX mbuf map memory\n");
17634c7070dbSScott Long 		err = ENOMEM;
17644c7070dbSScott Long 		goto fail;
17654c7070dbSScott Long 	}
17664c7070dbSScott Long 
1767bfce461eSMarius Strobl 	/*
1768bfce461eSMarius Strobl 	 * Create the DMA maps for TX buffers.
1769bfce461eSMarius Strobl 	 */
17708a04b53dSKonstantin Belousov 	if ((txq->ift_sds.ifsd_map = (bus_dmamap_t *)malloc(
17718a04b53dSKonstantin Belousov 	    sizeof(bus_dmamap_t) * scctx->isc_ntxd[txq->ift_br_offset],
17728a04b53dSKonstantin Belousov 	    M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
1773bfce461eSMarius Strobl 		device_printf(dev,
1774bfce461eSMarius Strobl 		    "Unable to allocate TX buffer DMA map memory\n");
17754c7070dbSScott Long 		err = ENOMEM;
17764c7070dbSScott Long 		goto fail;
17774c7070dbSScott Long 	}
17788a04b53dSKonstantin Belousov 	if (tso && (txq->ift_sds.ifsd_tso_map = (bus_dmamap_t *)malloc(
17798a04b53dSKonstantin Belousov 	    sizeof(bus_dmamap_t) * scctx->isc_ntxd[txq->ift_br_offset],
17808a04b53dSKonstantin Belousov 	    M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
1781bfce461eSMarius Strobl 		device_printf(dev,
1782bfce461eSMarius Strobl 		    "Unable to allocate TSO TX buffer map memory\n");
17838a04b53dSKonstantin Belousov 		err = ENOMEM;
17848a04b53dSKonstantin Belousov 		goto fail;
17858a04b53dSKonstantin Belousov 	}
178623ac9029SStephen Hurd 	for (int i = 0; i < scctx->isc_ntxd[txq->ift_br_offset]; i++) {
1787bfce461eSMarius Strobl 		err = bus_dmamap_create(txq->ift_buf_tag, 0,
17888a04b53dSKonstantin Belousov 		    &txq->ift_sds.ifsd_map[i]);
17894c7070dbSScott Long 		if (err != 0) {
17904c7070dbSScott Long 			device_printf(dev, "Unable to create TX DMA map\n");
17914c7070dbSScott Long 			goto fail;
17924c7070dbSScott Long 		}
17938a04b53dSKonstantin Belousov 		if (!tso)
17948a04b53dSKonstantin Belousov 			continue;
1795bfce461eSMarius Strobl 		err = bus_dmamap_create(txq->ift_tso_buf_tag, 0,
17968a04b53dSKonstantin Belousov 		    &txq->ift_sds.ifsd_tso_map[i]);
17978a04b53dSKonstantin Belousov 		if (err != 0) {
17988a04b53dSKonstantin Belousov 			device_printf(dev, "Unable to create TSO TX DMA map\n");
17998a04b53dSKonstantin Belousov 			goto fail;
18008a04b53dSKonstantin Belousov 		}
18014c7070dbSScott Long 	}
18024c7070dbSScott Long 	return (0);
18034c7070dbSScott Long fail:
18044c7070dbSScott Long 	/* We free all, it handles case where we are in the middle */
18054c7070dbSScott Long 	iflib_tx_structures_free(ctx);
18064c7070dbSScott Long 	return (err);
18074c7070dbSScott Long }
18084c7070dbSScott Long 
18094c7070dbSScott Long static void
18104c7070dbSScott Long iflib_txsd_destroy(if_ctx_t ctx, iflib_txq_t txq, int i)
18114c7070dbSScott Long {
18124c7070dbSScott Long 	bus_dmamap_t map;
18134c7070dbSScott Long 
1814db8e8f1eSEric Joyner 	if (txq->ift_sds.ifsd_map != NULL) {
18154c7070dbSScott Long 		map = txq->ift_sds.ifsd_map[i];
1816bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_buf_tag, map, BUS_DMASYNC_POSTWRITE);
1817bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_buf_tag, map);
1818bfce461eSMarius Strobl 		bus_dmamap_destroy(txq->ift_buf_tag, map);
18194c7070dbSScott Long 		txq->ift_sds.ifsd_map[i] = NULL;
18204c7070dbSScott Long 	}
18218a04b53dSKonstantin Belousov 
1822db8e8f1eSEric Joyner 	if (txq->ift_sds.ifsd_tso_map != NULL) {
18238a04b53dSKonstantin Belousov 		map = txq->ift_sds.ifsd_tso_map[i];
1824bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_tso_buf_tag, map,
18258a04b53dSKonstantin Belousov 		    BUS_DMASYNC_POSTWRITE);
1826bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_tso_buf_tag, map);
1827bfce461eSMarius Strobl 		bus_dmamap_destroy(txq->ift_tso_buf_tag, map);
18288a04b53dSKonstantin Belousov 		txq->ift_sds.ifsd_tso_map[i] = NULL;
18298a04b53dSKonstantin Belousov 	}
18304c7070dbSScott Long }
18314c7070dbSScott Long 
18324c7070dbSScott Long static void
18334c7070dbSScott Long iflib_txq_destroy(iflib_txq_t txq)
18344c7070dbSScott Long {
18354c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
18364c7070dbSScott Long 
183723ac9029SStephen Hurd 	for (int i = 0; i < txq->ift_size; i++)
18384c7070dbSScott Long 		iflib_txsd_destroy(ctx, txq, i);
1839244e7cffSEric Joyner 
1840244e7cffSEric Joyner 	if (txq->ift_br != NULL) {
1841244e7cffSEric Joyner 		ifmp_ring_free(txq->ift_br);
1842244e7cffSEric Joyner 		txq->ift_br = NULL;
1843244e7cffSEric Joyner 	}
1844244e7cffSEric Joyner 
1845244e7cffSEric Joyner 	mtx_destroy(&txq->ift_mtx);
1846244e7cffSEric Joyner 
18474c7070dbSScott Long 	if (txq->ift_sds.ifsd_map != NULL) {
18484c7070dbSScott Long 		free(txq->ift_sds.ifsd_map, M_IFLIB);
18494c7070dbSScott Long 		txq->ift_sds.ifsd_map = NULL;
18504c7070dbSScott Long 	}
18518a04b53dSKonstantin Belousov 	if (txq->ift_sds.ifsd_tso_map != NULL) {
18528a04b53dSKonstantin Belousov 		free(txq->ift_sds.ifsd_tso_map, M_IFLIB);
18538a04b53dSKonstantin Belousov 		txq->ift_sds.ifsd_tso_map = NULL;
18548a04b53dSKonstantin Belousov 	}
18554c7070dbSScott Long 	if (txq->ift_sds.ifsd_m != NULL) {
18564c7070dbSScott Long 		free(txq->ift_sds.ifsd_m, M_IFLIB);
18574c7070dbSScott Long 		txq->ift_sds.ifsd_m = NULL;
18584c7070dbSScott Long 	}
1859bfce461eSMarius Strobl 	if (txq->ift_buf_tag != NULL) {
1860bfce461eSMarius Strobl 		bus_dma_tag_destroy(txq->ift_buf_tag);
1861bfce461eSMarius Strobl 		txq->ift_buf_tag = NULL;
18624c7070dbSScott Long 	}
1863bfce461eSMarius Strobl 	if (txq->ift_tso_buf_tag != NULL) {
1864bfce461eSMarius Strobl 		bus_dma_tag_destroy(txq->ift_tso_buf_tag);
1865bfce461eSMarius Strobl 		txq->ift_tso_buf_tag = NULL;
18664c7070dbSScott Long 	}
1867244e7cffSEric Joyner 	if (txq->ift_ifdi != NULL) {
1868244e7cffSEric Joyner 		free(txq->ift_ifdi, M_IFLIB);
1869244e7cffSEric Joyner 	}
18704c7070dbSScott Long }
18714c7070dbSScott Long 
18724c7070dbSScott Long static void
18734c7070dbSScott Long iflib_txsd_free(if_ctx_t ctx, iflib_txq_t txq, int i)
18744c7070dbSScott Long {
18754c7070dbSScott Long 	struct mbuf **mp;
18764c7070dbSScott Long 
18774c7070dbSScott Long 	mp = &txq->ift_sds.ifsd_m[i];
18784c7070dbSScott Long 	if (*mp == NULL)
18794c7070dbSScott Long 		return;
18804c7070dbSScott Long 
18814c7070dbSScott Long 	if (txq->ift_sds.ifsd_map != NULL) {
1882bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_buf_tag,
18838a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_map[i], BUS_DMASYNC_POSTWRITE);
1884bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_buf_tag, txq->ift_sds.ifsd_map[i]);
18858a04b53dSKonstantin Belousov 	}
18868a04b53dSKonstantin Belousov 	if (txq->ift_sds.ifsd_tso_map != NULL) {
1887bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_tso_buf_tag,
18888a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_tso_map[i], BUS_DMASYNC_POSTWRITE);
1889bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_tso_buf_tag,
18908a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_tso_map[i]);
18914c7070dbSScott Long 	}
189254bf96fbSMark Johnston 	m_freem(*mp);
18934c7070dbSScott Long 	DBG_COUNTER_INC(tx_frees);
18944c7070dbSScott Long 	*mp = NULL;
18954c7070dbSScott Long }
18964c7070dbSScott Long 
18974c7070dbSScott Long static int
18984c7070dbSScott Long iflib_txq_setup(iflib_txq_t txq)
18994c7070dbSScott Long {
19004c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
190123ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
19024d261ce2SStephen Hurd 	if_shared_ctx_t sctx = ctx->ifc_sctx;
19034c7070dbSScott Long 	iflib_dma_info_t di;
19044c7070dbSScott Long 	int i;
19054c7070dbSScott Long 
19064c7070dbSScott Long 	/* Set number of descriptors available */
19074c7070dbSScott Long 	txq->ift_qstatus = IFLIB_QUEUE_IDLE;
190895246abbSSean Bruno 	/* XXX make configurable */
190995246abbSSean Bruno 	txq->ift_update_freq = IFLIB_DEFAULT_TX_UPDATE_FREQ;
19104c7070dbSScott Long 
19114c7070dbSScott Long 	/* Reset indices */
191295246abbSSean Bruno 	txq->ift_cidx_processed = 0;
191395246abbSSean Bruno 	txq->ift_pidx = txq->ift_cidx = txq->ift_npending = 0;
191423ac9029SStephen Hurd 	txq->ift_size = scctx->isc_ntxd[txq->ift_br_offset];
19154c7070dbSScott Long 
19164d261ce2SStephen Hurd 	for (i = 0, di = txq->ift_ifdi; i < sctx->isc_ntxqs; i++, di++)
19174c7070dbSScott Long 		bzero((void *)di->idi_vaddr, di->idi_size);
19184c7070dbSScott Long 
19194c7070dbSScott Long 	IFDI_TXQ_SETUP(ctx, txq->ift_id);
19204d261ce2SStephen Hurd 	for (i = 0, di = txq->ift_ifdi; i < sctx->isc_ntxqs; i++, di++)
19214c7070dbSScott Long 		bus_dmamap_sync(di->idi_tag, di->idi_map,
19224c7070dbSScott Long 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
19234c7070dbSScott Long 	return (0);
19244c7070dbSScott Long }
19254c7070dbSScott Long 
19264c7070dbSScott Long /*********************************************************************
19274c7070dbSScott Long  *
1928bfce461eSMarius Strobl  *  Allocate DMA resources for RX buffers as well as memory for the RX
1929bfce461eSMarius Strobl  *  mbuf map, direct RX cluster pointer map and RX cluster bus address
1930bfce461eSMarius Strobl  *  map.  RX DMA map, RX mbuf map, direct RX cluster pointer map and
1931bfce461eSMarius Strobl  *  RX cluster map are kept in a iflib_sw_rx_desc_array structure.
1932bfce461eSMarius Strobl  *  Since we use use one entry in iflib_sw_rx_desc_array per received
1933bfce461eSMarius Strobl  *  packet, the maximum number of entries we'll need is equal to the
1934bfce461eSMarius Strobl  *  number of hardware receive descriptors that we've allocated.
19354c7070dbSScott Long  *
19364c7070dbSScott Long  **********************************************************************/
19374c7070dbSScott Long static int
19384c7070dbSScott Long iflib_rxsd_alloc(iflib_rxq_t rxq)
19394c7070dbSScott Long {
19404c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
19414c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
194223ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
19434c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
19444c7070dbSScott Long 	iflib_fl_t fl;
19456dd69f00SMarcin Wojtas 	bus_addr_t lowaddr;
19464c7070dbSScott Long 	int			err;
19474c7070dbSScott Long 
194823ac9029SStephen Hurd 	MPASS(scctx->isc_nrxd[0] > 0);
194923ac9029SStephen Hurd 	MPASS(scctx->isc_nrxd[rxq->ifr_fl_offset] > 0);
19504c7070dbSScott Long 
19516dd69f00SMarcin Wojtas 	lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(scctx->isc_dma_width);
19526dd69f00SMarcin Wojtas 
19534c7070dbSScott Long 	fl = rxq->ifr_fl;
19544c7070dbSScott Long 	for (int i = 0; i <  rxq->ifr_nfl; i++, fl++) {
195523ac9029SStephen Hurd 		fl->ifl_size = scctx->isc_nrxd[rxq->ifr_fl_offset]; /* this isn't necessarily the same */
1956bfce461eSMarius Strobl 		/* Set up DMA tag for RX buffers. */
19574c7070dbSScott Long 		err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
19584c7070dbSScott Long 					 1, 0,			/* alignment, bounds */
19596dd69f00SMarcin Wojtas 					 lowaddr,		/* lowaddr */
19604c7070dbSScott Long 					 BUS_SPACE_MAXADDR,	/* highaddr */
19614c7070dbSScott Long 					 NULL, NULL,		/* filter, filterarg */
19624c7070dbSScott Long 					 sctx->isc_rx_maxsize,	/* maxsize */
19634c7070dbSScott Long 					 sctx->isc_rx_nsegments,	/* nsegments */
19644c7070dbSScott Long 					 sctx->isc_rx_maxsegsize,	/* maxsegsize */
19654c7070dbSScott Long 					 0,			/* flags */
19664c7070dbSScott Long 					 NULL,			/* lockfunc */
19674c7070dbSScott Long 					 NULL,			/* lockarg */
1968bfce461eSMarius Strobl 					 &fl->ifl_buf_tag);
19694c7070dbSScott Long 		if (err) {
1970bfce461eSMarius Strobl 			device_printf(dev,
1971bfce461eSMarius Strobl 			    "Unable to allocate RX DMA tag: %d\n", err);
19724c7070dbSScott Long 			goto fail;
19734c7070dbSScott Long 		}
1974bfce461eSMarius Strobl 
1975bfce461eSMarius Strobl 		/* Allocate memory for the RX mbuf map. */
1976e035717eSSean Bruno 		if (!(fl->ifl_sds.ifsd_m =
1977ac2fffa4SPedro F. Giffuni 		      (struct mbuf **) malloc(sizeof(struct mbuf *) *
1978ac2fffa4SPedro F. Giffuni 					      scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1979bfce461eSMarius Strobl 			device_printf(dev,
1980bfce461eSMarius Strobl 			    "Unable to allocate RX mbuf map memory\n");
1981e035717eSSean Bruno 			err = ENOMEM;
1982e035717eSSean Bruno 			goto fail;
1983e035717eSSean Bruno 		}
1984bfce461eSMarius Strobl 
1985bfce461eSMarius Strobl 		/* Allocate memory for the direct RX cluster pointer map. */
1986e035717eSSean Bruno 		if (!(fl->ifl_sds.ifsd_cl =
1987ac2fffa4SPedro F. Giffuni 		      (caddr_t *) malloc(sizeof(caddr_t) *
1988ac2fffa4SPedro F. Giffuni 					      scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1989bfce461eSMarius Strobl 			device_printf(dev,
1990bfce461eSMarius Strobl 			    "Unable to allocate RX cluster map memory\n");
1991e035717eSSean Bruno 			err = ENOMEM;
1992e035717eSSean Bruno 			goto fail;
1993e035717eSSean Bruno 		}
19944c7070dbSScott Long 
1995bfce461eSMarius Strobl 		/* Allocate memory for the RX cluster bus address map. */
1996fbec776dSAndrew Gallatin 		if (!(fl->ifl_sds.ifsd_ba =
1997fbec776dSAndrew Gallatin 		      (bus_addr_t *) malloc(sizeof(bus_addr_t) *
1998fbec776dSAndrew Gallatin 					      scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1999bfce461eSMarius Strobl 			device_printf(dev,
2000bfce461eSMarius Strobl 			    "Unable to allocate RX bus address map memory\n");
2001fbec776dSAndrew Gallatin 			err = ENOMEM;
2002fbec776dSAndrew Gallatin 			goto fail;
2003fbec776dSAndrew Gallatin 		}
2004e035717eSSean Bruno 
2005bfce461eSMarius Strobl 		/*
2006bfce461eSMarius Strobl 		 * Create the DMA maps for RX buffers.
2007bfce461eSMarius Strobl 		 */
2008e035717eSSean Bruno 		if (!(fl->ifl_sds.ifsd_map =
2009ac2fffa4SPedro F. Giffuni 		      (bus_dmamap_t *) malloc(sizeof(bus_dmamap_t) * scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
2010bfce461eSMarius Strobl 			device_printf(dev,
2011bfce461eSMarius Strobl 			    "Unable to allocate RX buffer DMA map memory\n");
2012e035717eSSean Bruno 			err = ENOMEM;
2013e035717eSSean Bruno 			goto fail;
2014e035717eSSean Bruno 		}
2015e035717eSSean Bruno 		for (int i = 0; i < scctx->isc_nrxd[rxq->ifr_fl_offset]; i++) {
2016bfce461eSMarius Strobl 			err = bus_dmamap_create(fl->ifl_buf_tag, 0,
2017bfce461eSMarius Strobl 			    &fl->ifl_sds.ifsd_map[i]);
2018e035717eSSean Bruno 			if (err != 0) {
201995246abbSSean Bruno 				device_printf(dev, "Unable to create RX buffer DMA map\n");
20204c7070dbSScott Long 				goto fail;
20214c7070dbSScott Long 			}
20224c7070dbSScott Long 		}
2023835809f9SSean Bruno 	}
20244c7070dbSScott Long 	return (0);
20254c7070dbSScott Long 
20264c7070dbSScott Long fail:
20274c7070dbSScott Long 	iflib_rx_structures_free(ctx);
20284c7070dbSScott Long 	return (err);
20294c7070dbSScott Long }
20304c7070dbSScott Long 
20314c7070dbSScott Long /*
20324c7070dbSScott Long  * Internal service routines
20334c7070dbSScott Long  */
20344c7070dbSScott Long 
20354c7070dbSScott Long struct rxq_refill_cb_arg {
20364c7070dbSScott Long 	int               error;
20374c7070dbSScott Long 	bus_dma_segment_t seg;
20384c7070dbSScott Long 	int               nseg;
20394c7070dbSScott Long };
20404c7070dbSScott Long 
20414c7070dbSScott Long static void
20424c7070dbSScott Long _rxq_refill_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
20434c7070dbSScott Long {
20444c7070dbSScott Long 	struct rxq_refill_cb_arg *cb_arg = arg;
20454c7070dbSScott Long 
20464c7070dbSScott Long 	cb_arg->error = error;
20474c7070dbSScott Long 	cb_arg->seg = segs[0];
20484c7070dbSScott Long 	cb_arg->nseg = nseg;
20494c7070dbSScott Long }
20504c7070dbSScott Long 
20514c7070dbSScott Long /**
2052b256d25cSMark Johnston  * iflib_fl_refill - refill an rxq free-buffer list
20534c7070dbSScott Long  * @ctx: the iflib context
20541722eeacSMarius Strobl  * @fl: the free list to refill
20551722eeacSMarius Strobl  * @count: the number of new buffers to allocate
20564c7070dbSScott Long  *
20571722eeacSMarius Strobl  * (Re)populate an rxq free-buffer list with up to @count new packet buffers.
205835d8a463SVincenzo Maffione  * The caller must assure that @count does not exceed the queue's capacity
205935d8a463SVincenzo Maffione  * minus one (since we always leave a descriptor unavailable).
20604c7070dbSScott Long  */
2061fb1a29b4SHans Petter Selasky static uint8_t
2062b256d25cSMark Johnston iflib_fl_refill(if_ctx_t ctx, iflib_fl_t fl, int count)
20634c7070dbSScott Long {
206495246abbSSean Bruno 	struct if_rxd_update iru;
2065fbec776dSAndrew Gallatin 	struct rxq_refill_cb_arg cb_arg;
20663db348b5SMarius Strobl 	struct mbuf *m;
20673db348b5SMarius Strobl 	caddr_t cl, *sd_cl;
20683db348b5SMarius Strobl 	struct mbuf **sd_m;
2069e035717eSSean Bruno 	bus_dmamap_t *sd_map;
2070fbec776dSAndrew Gallatin 	bus_addr_t bus_addr, *sd_ba;
20713db348b5SMarius Strobl 	int err, frag_idx, i, idx, n, pidx;
2072a1b799caSStephen Hurd 	qidx_t credits;
20734c7070dbSScott Long 
207435d8a463SVincenzo Maffione 	MPASS(count <= fl->ifl_size - fl->ifl_credits - 1);
207535d8a463SVincenzo Maffione 
2076e035717eSSean Bruno 	sd_m = fl->ifl_sds.ifsd_m;
2077e035717eSSean Bruno 	sd_map = fl->ifl_sds.ifsd_map;
2078e035717eSSean Bruno 	sd_cl = fl->ifl_sds.ifsd_cl;
2079fbec776dSAndrew Gallatin 	sd_ba = fl->ifl_sds.ifsd_ba;
20803db348b5SMarius Strobl 	pidx = fl->ifl_pidx;
2081e035717eSSean Bruno 	idx = pidx;
20823db348b5SMarius Strobl 	frag_idx = fl->ifl_fragidx;
2083a1b799caSStephen Hurd 	credits = fl->ifl_credits;
2084e035717eSSean Bruno 
20853db348b5SMarius Strobl 	i = 0;
20864c7070dbSScott Long 	n = count;
20874c7070dbSScott Long 	MPASS(n > 0);
2088a1b799caSStephen Hurd 	MPASS(credits + n <= fl->ifl_size);
20894c7070dbSScott Long 
20904c7070dbSScott Long 	if (pidx < fl->ifl_cidx)
20914c7070dbSScott Long 		MPASS(pidx + n <= fl->ifl_cidx);
2092a1b799caSStephen Hurd 	if (pidx == fl->ifl_cidx && (credits < fl->ifl_size))
20934c7070dbSScott Long 		MPASS(fl->ifl_gen == 0);
20944c7070dbSScott Long 	if (pidx > fl->ifl_cidx)
20954c7070dbSScott Long 		MPASS(n <= fl->ifl_size - pidx + fl->ifl_cidx);
20964c7070dbSScott Long 
20974c7070dbSScott Long 	DBG_COUNTER_INC(fl_refills);
20984c7070dbSScott Long 	if (n > 8)
20994c7070dbSScott Long 		DBG_COUNTER_INC(fl_refills_large);
21002d873474SStephen Hurd 	iru_init(&iru, fl->ifl_rxq, fl->ifl_id);
2101b256d25cSMark Johnston 	while (n-- > 0) {
21024c7070dbSScott Long 		/*
21034c7070dbSScott Long 		 * We allocate an uninitialized mbuf + cluster, mbuf is
21044c7070dbSScott Long 		 * initialized after rx.
21054c7070dbSScott Long 		 *
2106b256d25cSMark Johnston 		 * If the cluster is still set then we know a minimum sized
2107b256d25cSMark Johnston 		 * packet was received
21084c7070dbSScott Long 		 */
21093db348b5SMarius Strobl 		bit_ffc_at(fl->ifl_rx_bitmap, frag_idx, fl->ifl_size,
21103db348b5SMarius Strobl 		    &frag_idx);
21113db348b5SMarius Strobl 		if (frag_idx < 0)
211287890dbaSSean Bruno 			bit_ffc(fl->ifl_rx_bitmap, fl->ifl_size, &frag_idx);
21133db348b5SMarius Strobl 		MPASS(frag_idx >= 0);
211487890dbaSSean Bruno 		if ((cl = sd_cl[frag_idx]) == NULL) {
2115b256d25cSMark Johnston 			cl = uma_zalloc(fl->ifl_zone, M_NOWAIT);
2116a363e1d4SMark Johnston 			if (__predict_false(cl == NULL))
21174c7070dbSScott Long 				break;
21184c7070dbSScott Long 
21194c7070dbSScott Long 			cb_arg.error = 0;
212095246abbSSean Bruno 			MPASS(sd_map != NULL);
2121bfce461eSMarius Strobl 			err = bus_dmamap_load(fl->ifl_buf_tag, sd_map[frag_idx],
21228a04b53dSKonstantin Belousov 			    cl, fl->ifl_buf_size, _rxq_refill_cb, &cb_arg,
21238a04b53dSKonstantin Belousov 			    BUS_DMA_NOWAIT);
2124a363e1d4SMark Johnston 			if (__predict_false(err != 0 || cb_arg.error)) {
21254c7070dbSScott Long 				uma_zfree(fl->ifl_zone, cl);
2126fbec776dSAndrew Gallatin 				break;
21274c7070dbSScott Long 			}
21284c7070dbSScott Long 
2129fbec776dSAndrew Gallatin 			sd_ba[frag_idx] = bus_addr = cb_arg.seg.ds_addr;
213087890dbaSSean Bruno 			sd_cl[frag_idx] = cl;
2131fbec776dSAndrew Gallatin #if MEMORY_LOGGING
2132fbec776dSAndrew Gallatin 			fl->ifl_cl_enqueued++;
2133fbec776dSAndrew Gallatin #endif
2134fbec776dSAndrew Gallatin 		} else {
2135fbec776dSAndrew Gallatin 			bus_addr = sd_ba[frag_idx];
2136fbec776dSAndrew Gallatin 		}
213795dcf343SMarius Strobl 		bus_dmamap_sync(fl->ifl_buf_tag, sd_map[frag_idx],
213895dcf343SMarius Strobl 		    BUS_DMASYNC_PREREAD);
2139fbec776dSAndrew Gallatin 
21406d49b41eSAndrew Gallatin 		if (sd_m[frag_idx] == NULL) {
2141a5688853SMateusz Guzik 			m = m_gethdr_raw(M_NOWAIT, 0);
2142a363e1d4SMark Johnston 			if (__predict_false(m == NULL))
2143fbec776dSAndrew Gallatin 				break;
214487890dbaSSean Bruno 			sd_m[frag_idx] = m;
21456d49b41eSAndrew Gallatin 		}
21463db348b5SMarius Strobl 		bit_set(fl->ifl_rx_bitmap, frag_idx);
2147fbec776dSAndrew Gallatin #if MEMORY_LOGGING
2148fbec776dSAndrew Gallatin 		fl->ifl_m_enqueued++;
2149fbec776dSAndrew Gallatin #endif
2150fbec776dSAndrew Gallatin 
2151fbec776dSAndrew Gallatin 		DBG_COUNTER_INC(rx_allocs);
215287890dbaSSean Bruno 		fl->ifl_rxd_idxs[i] = frag_idx;
21534c7070dbSScott Long 		fl->ifl_bus_addrs[i] = bus_addr;
2154a1b799caSStephen Hurd 		credits++;
21554c7070dbSScott Long 		i++;
2156a1b799caSStephen Hurd 		MPASS(credits <= fl->ifl_size);
2157e035717eSSean Bruno 		if (++idx == fl->ifl_size) {
2158b256d25cSMark Johnston #ifdef INVARIANTS
21594c7070dbSScott Long 			fl->ifl_gen = 1;
2160b256d25cSMark Johnston #endif
2161e035717eSSean Bruno 			idx = 0;
21624c7070dbSScott Long 		}
21634c7070dbSScott Long 		if (n == 0 || i == IFLIB_MAX_RX_REFRESH) {
216495246abbSSean Bruno 			iru.iru_pidx = pidx;
216595246abbSSean Bruno 			iru.iru_count = i;
216695246abbSSean Bruno 			ctx->isc_rxd_refill(ctx->ifc_softc, &iru);
2167fa5416a8SSean Bruno 			fl->ifl_pidx = idx;
2168a1b799caSStephen Hurd 			fl->ifl_credits = credits;
2169b256d25cSMark Johnston 			pidx = idx;
2170b256d25cSMark Johnston 			i = 0;
217187890dbaSSean Bruno 		}
21724c7070dbSScott Long 	}
2173fbec776dSAndrew Gallatin 
2174a363e1d4SMark Johnston 	if (n < count - 1) {
2175a363e1d4SMark Johnston 		if (i != 0) {
2176a1b799caSStephen Hurd 			iru.iru_pidx = pidx;
2177a1b799caSStephen Hurd 			iru.iru_count = i;
2178a1b799caSStephen Hurd 			ctx->isc_rxd_refill(ctx->ifc_softc, &iru);
2179a1b799caSStephen Hurd 			fl->ifl_pidx = idx;
2180a1b799caSStephen Hurd 			fl->ifl_credits = credits;
2181a1b799caSStephen Hurd 		}
21824c7070dbSScott Long 		DBG_COUNTER_INC(rxd_flush);
218395246abbSSean Bruno 		bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
218495246abbSSean Bruno 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2185a363e1d4SMark Johnston 		ctx->isc_rxd_flush(ctx->ifc_softc, fl->ifl_rxq->ifr_id,
218635d8a463SVincenzo Maffione 		    fl->ifl_id, fl->ifl_pidx);
2187a363e1d4SMark Johnston 		if (__predict_true(bit_test(fl->ifl_rx_bitmap, frag_idx))) {
21889e9b738aSPatrick Kelsey 			fl->ifl_fragidx = frag_idx + 1;
21899e9b738aSPatrick Kelsey 			if (fl->ifl_fragidx == fl->ifl_size)
21909e9b738aSPatrick Kelsey 				fl->ifl_fragidx = 0;
2191a363e1d4SMark Johnston 		} else {
2192a363e1d4SMark Johnston 			fl->ifl_fragidx = frag_idx;
2193a363e1d4SMark Johnston 		}
2194a363e1d4SMark Johnston 	}
2195fb1a29b4SHans Petter Selasky 
2196fb1a29b4SHans Petter Selasky 	return (n == -1 ? 0 : IFLIB_RXEOF_EMPTY);
21974c7070dbSScott Long }
21984c7070dbSScott Long 
2199b256d25cSMark Johnston static inline uint8_t
2200b256d25cSMark Johnston iflib_fl_refill_all(if_ctx_t ctx, iflib_fl_t fl)
22014c7070dbSScott Long {
220235d8a463SVincenzo Maffione 	/*
220335d8a463SVincenzo Maffione 	 * We leave an unused descriptor to avoid pidx to catch up with cidx.
220435d8a463SVincenzo Maffione 	 * This is important as it confuses most NICs. For instance,
220535d8a463SVincenzo Maffione 	 * Intel NICs have (per receive ring) RDH and RDT registers, where
220635d8a463SVincenzo Maffione 	 * RDH points to the next receive descriptor to be used by the NIC,
220735d8a463SVincenzo Maffione 	 * and RDT for the next receive descriptor to be published by the
220835d8a463SVincenzo Maffione 	 * driver to the NIC (RDT - 1 is thus the last valid one).
220935d8a463SVincenzo Maffione 	 * The condition RDH == RDT means no descriptors are available to
221035d8a463SVincenzo Maffione 	 * the NIC, and thus it would be ambiguous if it also meant that
221135d8a463SVincenzo Maffione 	 * all the descriptors are available to the NIC.
221235d8a463SVincenzo Maffione 	 */
22134c7070dbSScott Long 	int32_t reclaimable = fl->ifl_size - fl->ifl_credits - 1;
22144c7070dbSScott Long #ifdef INVARIANTS
22154c7070dbSScott Long 	int32_t delta = fl->ifl_size - get_inuse(fl->ifl_size, fl->ifl_cidx, fl->ifl_pidx, fl->ifl_gen) - 1;
22164c7070dbSScott Long #endif
22174c7070dbSScott Long 
22184c7070dbSScott Long 	MPASS(fl->ifl_credits <= fl->ifl_size);
22194c7070dbSScott Long 	MPASS(reclaimable == delta);
22204c7070dbSScott Long 
22214c7070dbSScott Long 	if (reclaimable > 0)
2222b256d25cSMark Johnston 		return (iflib_fl_refill(ctx, fl, reclaimable));
2223fb1a29b4SHans Petter Selasky 	return (0);
22244c7070dbSScott Long }
22254c7070dbSScott Long 
222677c1fcecSEric Joyner uint8_t
222777c1fcecSEric Joyner iflib_in_detach(if_ctx_t ctx)
222877c1fcecSEric Joyner {
222977c1fcecSEric Joyner 	bool in_detach;
22301722eeacSMarius Strobl 
223177c1fcecSEric Joyner 	STATE_LOCK(ctx);
223277c1fcecSEric Joyner 	in_detach = !!(ctx->ifc_flags & IFC_IN_DETACH);
223377c1fcecSEric Joyner 	STATE_UNLOCK(ctx);
223477c1fcecSEric Joyner 	return (in_detach);
223577c1fcecSEric Joyner }
223677c1fcecSEric Joyner 
22374c7070dbSScott Long static void
22384c7070dbSScott Long iflib_fl_bufs_free(iflib_fl_t fl)
22394c7070dbSScott Long {
22404c7070dbSScott Long 	iflib_dma_info_t idi = fl->ifl_ifdi;
22418a04b53dSKonstantin Belousov 	bus_dmamap_t sd_map;
22424c7070dbSScott Long 	uint32_t i;
22434c7070dbSScott Long 
22444c7070dbSScott Long 	for (i = 0; i < fl->ifl_size; i++) {
2245e035717eSSean Bruno 		struct mbuf **sd_m = &fl->ifl_sds.ifsd_m[i];
2246e035717eSSean Bruno 		caddr_t *sd_cl = &fl->ifl_sds.ifsd_cl[i];
22474c7070dbSScott Long 
2248fbec776dSAndrew Gallatin 		if (*sd_cl != NULL) {
22498a04b53dSKonstantin Belousov 			sd_map = fl->ifl_sds.ifsd_map[i];
2250bfce461eSMarius Strobl 			bus_dmamap_sync(fl->ifl_buf_tag, sd_map,
22518a04b53dSKonstantin Belousov 			    BUS_DMASYNC_POSTREAD);
2252bfce461eSMarius Strobl 			bus_dmamap_unload(fl->ifl_buf_tag, sd_map);
2253fbec776dSAndrew Gallatin 			uma_zfree(fl->ifl_zone, *sd_cl);
2254b256d25cSMark Johnston 			*sd_cl = NULL;
2255e035717eSSean Bruno 			if (*sd_m != NULL) {
2256e035717eSSean Bruno 				m_init(*sd_m, M_NOWAIT, MT_DATA, 0);
2257bad5f0b6SMateusz Guzik 				m_free_raw(*sd_m);
2258b256d25cSMark Johnston 				*sd_m = NULL;
2259e035717eSSean Bruno 			}
22604c7070dbSScott Long 		} else {
2261e035717eSSean Bruno 			MPASS(*sd_m == NULL);
22624c7070dbSScott Long 		}
22634c7070dbSScott Long #if MEMORY_LOGGING
22644c7070dbSScott Long 		fl->ifl_m_dequeued++;
22654c7070dbSScott Long 		fl->ifl_cl_dequeued++;
22664c7070dbSScott Long #endif
22674c7070dbSScott Long 	}
226895246abbSSean Bruno #ifdef INVARIANTS
226995246abbSSean Bruno 	for (i = 0; i < fl->ifl_size; i++) {
227095246abbSSean Bruno 		MPASS(fl->ifl_sds.ifsd_cl[i] == NULL);
227195246abbSSean Bruno 		MPASS(fl->ifl_sds.ifsd_m[i] == NULL);
227295246abbSSean Bruno 	}
227395246abbSSean Bruno #endif
22744c7070dbSScott Long 	/*
22754c7070dbSScott Long 	 * Reset free list values
22764c7070dbSScott Long 	 */
227787890dbaSSean Bruno 	fl->ifl_credits = fl->ifl_cidx = fl->ifl_pidx = fl->ifl_gen = fl->ifl_fragidx = 0;
22784c7070dbSScott Long 	bzero(idi->idi_vaddr, idi->idi_size);
22794c7070dbSScott Long }
22804c7070dbSScott Long 
22814c7070dbSScott Long /*********************************************************************
22824c7070dbSScott Long  *
22831722eeacSMarius Strobl  *  Initialize a free list and its buffers.
22844c7070dbSScott Long  *
22854c7070dbSScott Long  **********************************************************************/
22864c7070dbSScott Long static int
22874c7070dbSScott Long iflib_fl_setup(iflib_fl_t fl)
22884c7070dbSScott Long {
22894c7070dbSScott Long 	iflib_rxq_t rxq = fl->ifl_rxq;
22904c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
2291b3813609SPatrick Kelsey 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
2292b3813609SPatrick Kelsey 	int qidx;
22934c7070dbSScott Long 
22947274b2f6SStephen Hurd 	bit_nclear(fl->ifl_rx_bitmap, 0, fl->ifl_size - 1);
22954c7070dbSScott Long 	/*
22964c7070dbSScott Long 	** Free current RX buffer structs and their mbufs
22974c7070dbSScott Long 	*/
22984c7070dbSScott Long 	iflib_fl_bufs_free(fl);
22994c7070dbSScott Long 	/* Now replenish the mbufs */
23004c7070dbSScott Long 	MPASS(fl->ifl_credits == 0);
2301b3813609SPatrick Kelsey 	qidx = rxq->ifr_fl_offset + fl->ifl_id;
2302b3813609SPatrick Kelsey 	if (scctx->isc_rxd_buf_size[qidx] != 0)
2303b3813609SPatrick Kelsey 		fl->ifl_buf_size = scctx->isc_rxd_buf_size[qidx];
2304b3813609SPatrick Kelsey 	else
23051b9d9394SEric Joyner 		fl->ifl_buf_size = ctx->ifc_rx_mbuf_sz;
2306b3813609SPatrick Kelsey 	/*
2307b3813609SPatrick Kelsey 	 * ifl_buf_size may be a driver-supplied value, so pull it up
2308b3813609SPatrick Kelsey 	 * to the selected mbuf size.
2309b3813609SPatrick Kelsey 	 */
2310b3813609SPatrick Kelsey 	fl->ifl_buf_size = iflib_get_mbuf_size_for(fl->ifl_buf_size);
23114c7070dbSScott Long 	if (fl->ifl_buf_size > ctx->ifc_max_fl_buf_size)
23124c7070dbSScott Long 		ctx->ifc_max_fl_buf_size = fl->ifl_buf_size;
23134c7070dbSScott Long 	fl->ifl_cltype = m_gettype(fl->ifl_buf_size);
23144c7070dbSScott Long 	fl->ifl_zone = m_getzone(fl->ifl_buf_size);
23154c7070dbSScott Long 
231635d8a463SVincenzo Maffione 	/*
231735d8a463SVincenzo Maffione 	 * Avoid pre-allocating zillions of clusters to an idle card
231835d8a463SVincenzo Maffione 	 * potentially speeding up attach. In any case make sure
231935d8a463SVincenzo Maffione 	 * to leave a descriptor unavailable. See the comment in
232035d8a463SVincenzo Maffione 	 * iflib_fl_refill_all().
23214c7070dbSScott Long 	 */
232235d8a463SVincenzo Maffione 	MPASS(fl->ifl_size > 0);
232335d8a463SVincenzo Maffione 	(void)iflib_fl_refill(ctx, fl, min(128, fl->ifl_size - 1));
232435d8a463SVincenzo Maffione 	if (min(128, fl->ifl_size - 1) != fl->ifl_credits)
23254c7070dbSScott Long 		return (ENOBUFS);
23264c7070dbSScott Long 	/*
23274c7070dbSScott Long 	 * handle failure
23284c7070dbSScott Long 	 */
23294c7070dbSScott Long 	MPASS(rxq != NULL);
23304c7070dbSScott Long 	MPASS(fl->ifl_ifdi != NULL);
23314c7070dbSScott Long 	bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
23324c7070dbSScott Long 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
23334c7070dbSScott Long 	return (0);
23344c7070dbSScott Long }
23354c7070dbSScott Long 
23364c7070dbSScott Long /*********************************************************************
23374c7070dbSScott Long  *
23384c7070dbSScott Long  *  Free receive ring data structures
23394c7070dbSScott Long  *
23404c7070dbSScott Long  **********************************************************************/
23414c7070dbSScott Long static void
23424c7070dbSScott Long iflib_rx_sds_free(iflib_rxq_t rxq)
23434c7070dbSScott Long {
23444c7070dbSScott Long 	iflib_fl_t fl;
23458a04b53dSKonstantin Belousov 	int i, j;
23464c7070dbSScott Long 
23474c7070dbSScott Long 	if (rxq->ifr_fl != NULL) {
23484c7070dbSScott Long 		for (i = 0; i < rxq->ifr_nfl; i++) {
23494c7070dbSScott Long 			fl = &rxq->ifr_fl[i];
2350bfce461eSMarius Strobl 			if (fl->ifl_buf_tag != NULL) {
23518a04b53dSKonstantin Belousov 				if (fl->ifl_sds.ifsd_map != NULL) {
235277102fd6SAndrew Gallatin 					for (j = 0; j < fl->ifl_size; j++) {
23538a04b53dSKonstantin Belousov 						bus_dmamap_sync(
2354bfce461eSMarius Strobl 						    fl->ifl_buf_tag,
235577102fd6SAndrew Gallatin 						    fl->ifl_sds.ifsd_map[j],
23568a04b53dSKonstantin Belousov 						    BUS_DMASYNC_POSTREAD);
23578a04b53dSKonstantin Belousov 						bus_dmamap_unload(
2358bfce461eSMarius Strobl 						    fl->ifl_buf_tag,
235977102fd6SAndrew Gallatin 						    fl->ifl_sds.ifsd_map[j]);
2360db8e8f1eSEric Joyner 						bus_dmamap_destroy(
2361db8e8f1eSEric Joyner 						    fl->ifl_buf_tag,
2362db8e8f1eSEric Joyner 						    fl->ifl_sds.ifsd_map[j]);
23638a04b53dSKonstantin Belousov 					}
23648a04b53dSKonstantin Belousov 				}
2365bfce461eSMarius Strobl 				bus_dma_tag_destroy(fl->ifl_buf_tag);
2366bfce461eSMarius Strobl 				fl->ifl_buf_tag = NULL;
23674c7070dbSScott Long 			}
2368e035717eSSean Bruno 			free(fl->ifl_sds.ifsd_m, M_IFLIB);
2369e035717eSSean Bruno 			free(fl->ifl_sds.ifsd_cl, M_IFLIB);
2370fbec776dSAndrew Gallatin 			free(fl->ifl_sds.ifsd_ba, M_IFLIB);
2371e035717eSSean Bruno 			free(fl->ifl_sds.ifsd_map, M_IFLIB);
2372c065d4e5SMark Johnston 			free(fl->ifl_rx_bitmap, M_IFLIB);
2373e035717eSSean Bruno 			fl->ifl_sds.ifsd_m = NULL;
2374e035717eSSean Bruno 			fl->ifl_sds.ifsd_cl = NULL;
2375fbec776dSAndrew Gallatin 			fl->ifl_sds.ifsd_ba = NULL;
2376e035717eSSean Bruno 			fl->ifl_sds.ifsd_map = NULL;
2377c065d4e5SMark Johnston 			fl->ifl_rx_bitmap = NULL;
23784c7070dbSScott Long 		}
23794c7070dbSScott Long 		free(rxq->ifr_fl, M_IFLIB);
23804c7070dbSScott Long 		rxq->ifr_fl = NULL;
2381244e7cffSEric Joyner 		free(rxq->ifr_ifdi, M_IFLIB);
2382244e7cffSEric Joyner 		rxq->ifr_ifdi = NULL;
23831722eeacSMarius Strobl 		rxq->ifr_cq_cidx = 0;
23844c7070dbSScott Long 	}
23854c7070dbSScott Long }
23864c7070dbSScott Long 
23874c7070dbSScott Long /*
23881722eeacSMarius Strobl  * Timer routine
23894c7070dbSScott Long  */
23904c7070dbSScott Long static void
23914c7070dbSScott Long iflib_timer(void *arg)
23924c7070dbSScott Long {
2393ab2e3f79SStephen Hurd 	iflib_txq_t txq = arg;
23944c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
2395ab2e3f79SStephen Hurd 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
2396*618d49f5SAlexander Motin 	uint64_t this_tick = ticks;
23974c7070dbSScott Long 
23984c7070dbSScott Long 	if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))
23994c7070dbSScott Long 		return;
24001722eeacSMarius Strobl 
24014c7070dbSScott Long 	/*
24024c7070dbSScott Long 	** Check on the state of the TX queue(s), this
24034c7070dbSScott Long 	** can be done without the lock because its RO
24044c7070dbSScott Long 	** and the HUNG state will be static if set.
24054c7070dbSScott Long 	*/
2406*618d49f5SAlexander Motin 	if (this_tick - txq->ift_last_timer_tick >= iflib_timer_default) {
2407*618d49f5SAlexander Motin 		txq->ift_last_timer_tick = this_tick;
2408ab2e3f79SStephen Hurd 		IFDI_TIMER(ctx, txq->ift_id);
2409ab2e3f79SStephen Hurd 		if ((txq->ift_qstatus == IFLIB_QUEUE_HUNG) &&
2410ab2e3f79SStephen Hurd 		    ((txq->ift_cleaned_prev == txq->ift_cleaned) ||
2411ab2e3f79SStephen Hurd 		     (sctx->isc_pause_frames == 0)))
2412ab2e3f79SStephen Hurd 			goto hung;
2413*618d49f5SAlexander Motin 
2414f6afed72SEric Joyner 		if (txq->ift_qstatus != IFLIB_QUEUE_IDLE &&
2415f6afed72SEric Joyner 		    ifmp_ring_is_stalled(txq->ift_br)) {
241681be6552SMatt Macy 			KASSERT(ctx->ifc_link_state == LINK_STATE_UP,
241781be6552SMatt Macy 			    ("queue can't be marked as hung if interface is down"));
2418ab2e3f79SStephen Hurd 			txq->ift_qstatus = IFLIB_QUEUE_HUNG;
2419f6afed72SEric Joyner 		}
2420ab2e3f79SStephen Hurd 		txq->ift_cleaned_prev = txq->ift_cleaned;
2421*618d49f5SAlexander Motin 	}
2422ab2e3f79SStephen Hurd 	/* handle any laggards */
2423ab2e3f79SStephen Hurd 	if (txq->ift_db_pending)
2424ab2e3f79SStephen Hurd 		GROUPTASK_ENQUEUE(&txq->ift_task);
2425a9693502SSean Bruno 
2426ab2e3f79SStephen Hurd 	sctx->isc_pause_frames = 0;
2427d300df01SStephen Hurd 	if (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)
2428*618d49f5SAlexander Motin 		callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer,
2429*618d49f5SAlexander Motin 		    txq, txq->ift_timer.c_cpu);
2430ab2e3f79SStephen Hurd 	return;
24311722eeacSMarius Strobl 
2432ab2e3f79SStephen Hurd  hung:
24331722eeacSMarius Strobl 	device_printf(ctx->ifc_dev,
24341722eeacSMarius Strobl 	    "Watchdog timeout (TX: %d desc avail: %d pidx: %d) -- resetting\n",
2435ab2e3f79SStephen Hurd 	    txq->ift_id, TXQ_AVAIL(txq), txq->ift_pidx);
24367b610b60SSean Bruno 	STATE_LOCK(ctx);
24377b610b60SSean Bruno 	if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
24387b610b60SSean Bruno 	ctx->ifc_flags |= (IFC_DO_WATCHDOG|IFC_DO_RESET);
2439940f62d6SEric Joyner 	iflib_admin_intr_deferred(ctx);
244046fa0c25SEric Joyner 	STATE_UNLOCK(ctx);
24414c7070dbSScott Long }
24424c7070dbSScott Long 
2443b3813609SPatrick Kelsey static uint16_t
2444b3813609SPatrick Kelsey iflib_get_mbuf_size_for(unsigned int size)
2445b3813609SPatrick Kelsey {
2446b3813609SPatrick Kelsey 
2447b3813609SPatrick Kelsey 	if (size <= MCLBYTES)
2448b3813609SPatrick Kelsey 		return (MCLBYTES);
2449b3813609SPatrick Kelsey 	else
2450b3813609SPatrick Kelsey 		return (MJUMPAGESIZE);
2451b3813609SPatrick Kelsey }
2452b3813609SPatrick Kelsey 
24534c7070dbSScott Long static void
24541b9d9394SEric Joyner iflib_calc_rx_mbuf_sz(if_ctx_t ctx)
24551b9d9394SEric Joyner {
24561b9d9394SEric Joyner 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
24571b9d9394SEric Joyner 
24581b9d9394SEric Joyner 	/*
24591b9d9394SEric Joyner 	 * XXX don't set the max_frame_size to larger
24601b9d9394SEric Joyner 	 * than the hardware can handle
24611b9d9394SEric Joyner 	 */
2462b3813609SPatrick Kelsey 	ctx->ifc_rx_mbuf_sz =
2463b3813609SPatrick Kelsey 	    iflib_get_mbuf_size_for(sctx->isc_max_frame_size);
24641b9d9394SEric Joyner }
24651b9d9394SEric Joyner 
24661b9d9394SEric Joyner uint32_t
24671b9d9394SEric Joyner iflib_get_rx_mbuf_sz(if_ctx_t ctx)
24681b9d9394SEric Joyner {
24691722eeacSMarius Strobl 
24701b9d9394SEric Joyner 	return (ctx->ifc_rx_mbuf_sz);
24711b9d9394SEric Joyner }
24721b9d9394SEric Joyner 
24731b9d9394SEric Joyner static void
24744c7070dbSScott Long iflib_init_locked(if_ctx_t ctx)
24754c7070dbSScott Long {
24764c7070dbSScott Long 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
24771248952aSSean Bruno 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
24784c7070dbSScott Long 	if_t ifp = ctx->ifc_ifp;
24794c7070dbSScott Long 	iflib_fl_t fl;
24804c7070dbSScott Long 	iflib_txq_t txq;
24814c7070dbSScott Long 	iflib_rxq_t rxq;
2482ab2e3f79SStephen Hurd 	int i, j, tx_ip_csum_flags, tx_ip6_csum_flags;
24834c7070dbSScott Long 
24844c7070dbSScott Long 	if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
24854c7070dbSScott Long 	IFDI_INTR_DISABLE(ctx);
24864c7070dbSScott Long 
24873d65fd97SVincenzo Maffione 	/*
24883d65fd97SVincenzo Maffione 	 * See iflib_stop(). Useful in case iflib_init_locked() is
24893d65fd97SVincenzo Maffione 	 * called without first calling iflib_stop().
24903d65fd97SVincenzo Maffione 	 */
24913d65fd97SVincenzo Maffione 	netmap_disable_all_rings(ifp);
24923d65fd97SVincenzo Maffione 
24931248952aSSean Bruno 	tx_ip_csum_flags = scctx->isc_tx_csum_flags & (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP);
24941248952aSSean Bruno 	tx_ip6_csum_flags = scctx->isc_tx_csum_flags & (CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_IP6_SCTP);
24954c7070dbSScott Long 	/* Set hardware offload abilities */
24964c7070dbSScott Long 	if_clearhwassist(ifp);
24974c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TXCSUM)
24981248952aSSean Bruno 		if_sethwassistbits(ifp, tx_ip_csum_flags, 0);
24994c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6)
25001248952aSSean Bruno 		if_sethwassistbits(ifp,  tx_ip6_csum_flags, 0);
25014c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TSO4)
25024c7070dbSScott Long 		if_sethwassistbits(ifp, CSUM_IP_TSO, 0);
25034c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TSO6)
25044c7070dbSScott Long 		if_sethwassistbits(ifp, CSUM_IP6_TSO, 0);
25054c7070dbSScott Long 
25064c7070dbSScott Long 	for (i = 0, txq = ctx->ifc_txqs; i < sctx->isc_ntxqsets; i++, txq++) {
25074c7070dbSScott Long 		CALLOUT_LOCK(txq);
25084c7070dbSScott Long 		callout_stop(&txq->ift_timer);
250917cec474SVincenzo Maffione #ifdef DEV_NETMAP
251017cec474SVincenzo Maffione 		callout_stop(&txq->ift_netmap_timer);
251117cec474SVincenzo Maffione #endif /* DEV_NETMAP */
25124c7070dbSScott Long 		CALLOUT_UNLOCK(txq);
25132ccf971aSJohn Baldwin 		(void)iflib_netmap_txq_init(ctx, txq);
25144c7070dbSScott Long 	}
25151b9d9394SEric Joyner 
25161b9d9394SEric Joyner 	/*
25171b9d9394SEric Joyner 	 * Calculate a suitable Rx mbuf size prior to calling IFDI_INIT, so
25181b9d9394SEric Joyner 	 * that drivers can use the value when setting up the hardware receive
25191b9d9394SEric Joyner 	 * buffers.
25201b9d9394SEric Joyner 	 */
25211b9d9394SEric Joyner 	iflib_calc_rx_mbuf_sz(ctx);
25221b9d9394SEric Joyner 
252323ac9029SStephen Hurd #ifdef INVARIANTS
252423ac9029SStephen Hurd 	i = if_getdrvflags(ifp);
252523ac9029SStephen Hurd #endif
25264c7070dbSScott Long 	IFDI_INIT(ctx);
252723ac9029SStephen Hurd 	MPASS(if_getdrvflags(ifp) == i);
25284c7070dbSScott Long 	for (i = 0, rxq = ctx->ifc_rxqs; i < sctx->isc_nrxqsets; i++, rxq++) {
2529d8b2d26bSVincenzo Maffione 		if (iflib_netmap_rxq_init(ctx, rxq) > 0) {
2530d8b2d26bSVincenzo Maffione 			/* This rxq is in netmap mode. Skip normal init. */
253195246abbSSean Bruno 			continue;
2532d0d0ad0aSStephen Hurd 		}
25334c7070dbSScott Long 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) {
25344c7070dbSScott Long 			if (iflib_fl_setup(fl)) {
25353d10e9edSMarius Strobl 				device_printf(ctx->ifc_dev,
25363d10e9edSMarius Strobl 				    "setting up free list %d failed - "
25373d10e9edSMarius Strobl 				    "check cluster settings\n", j);
25384c7070dbSScott Long 				goto done;
25394c7070dbSScott Long 			}
25404c7070dbSScott Long 		}
25414c7070dbSScott Long 	}
25424c7070dbSScott Long done:
25434c7070dbSScott Long 	if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
25444c7070dbSScott Long 	IFDI_INTR_ENABLE(ctx);
25454c7070dbSScott Long 	txq = ctx->ifc_txqs;
25464c7070dbSScott Long 	for (i = 0; i < sctx->isc_ntxqsets; i++, txq++)
2547*618d49f5SAlexander Motin 		callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer, txq,
2548*618d49f5SAlexander Motin 			txq->ift_timer.c_cpu);
25493d65fd97SVincenzo Maffione 
25503d65fd97SVincenzo Maffione         /* Re-enable txsync/rxsync. */
25513d65fd97SVincenzo Maffione 	netmap_enable_all_rings(ifp);
25524c7070dbSScott Long }
25534c7070dbSScott Long 
25544c7070dbSScott Long static int
25554c7070dbSScott Long iflib_media_change(if_t ifp)
25564c7070dbSScott Long {
25574c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
25584c7070dbSScott Long 	int err;
25594c7070dbSScott Long 
25604c7070dbSScott Long 	CTX_LOCK(ctx);
25614c7070dbSScott Long 	if ((err = IFDI_MEDIA_CHANGE(ctx)) == 0)
2562922cf8acSAllan Jude 		iflib_if_init_locked(ctx);
25634c7070dbSScott Long 	CTX_UNLOCK(ctx);
25644c7070dbSScott Long 	return (err);
25654c7070dbSScott Long }
25664c7070dbSScott Long 
25674c7070dbSScott Long static void
25684c7070dbSScott Long iflib_media_status(if_t ifp, struct ifmediareq *ifmr)
25694c7070dbSScott Long {
25704c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
25714c7070dbSScott Long 
25724c7070dbSScott Long 	CTX_LOCK(ctx);
2573ab2e3f79SStephen Hurd 	IFDI_UPDATE_ADMIN_STATUS(ctx);
25744c7070dbSScott Long 	IFDI_MEDIA_STATUS(ctx, ifmr);
25754c7070dbSScott Long 	CTX_UNLOCK(ctx);
25764c7070dbSScott Long }
25774c7070dbSScott Long 
257809f6ff4fSMatt Macy void
25794c7070dbSScott Long iflib_stop(if_ctx_t ctx)
25804c7070dbSScott Long {
25814c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
25824c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
25834c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
25844d261ce2SStephen Hurd 	if_shared_ctx_t sctx = ctx->ifc_sctx;
25854c7070dbSScott Long 	iflib_dma_info_t di;
25864c7070dbSScott Long 	iflib_fl_t fl;
25874c7070dbSScott Long 	int i, j;
25884c7070dbSScott Long 
25894c7070dbSScott Long 	/* Tell the stack that the interface is no longer active */
25904c7070dbSScott Long 	if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
25914c7070dbSScott Long 
25924c7070dbSScott Long 	IFDI_INTR_DISABLE(ctx);
2593ab2e3f79SStephen Hurd 	DELAY(1000);
2594da69b8f9SSean Bruno 	IFDI_STOP(ctx);
2595ab2e3f79SStephen Hurd 	DELAY(1000);
25964c7070dbSScott Long 
25973d65fd97SVincenzo Maffione 	/*
25983d65fd97SVincenzo Maffione 	 * Stop any pending txsync/rxsync and prevent new ones
25993d65fd97SVincenzo Maffione 	 * form starting. Processes blocked in poll() will get
26003d65fd97SVincenzo Maffione 	 * POLLERR.
26013d65fd97SVincenzo Maffione 	 */
26023d65fd97SVincenzo Maffione 	netmap_disable_all_rings(ctx->ifc_ifp);
26033d65fd97SVincenzo Maffione 
2604da69b8f9SSean Bruno 	iflib_debug_reset();
26054c7070dbSScott Long 	/* Wait for current tx queue users to exit to disarm watchdog timer. */
26064c7070dbSScott Long 	for (i = 0; i < scctx->isc_ntxqsets; i++, txq++) {
26074c7070dbSScott Long 		/* make sure all transmitters have completed before proceeding XXX */
26084c7070dbSScott Long 
2609226fb85dSStephen Hurd 		CALLOUT_LOCK(txq);
2610226fb85dSStephen Hurd 		callout_stop(&txq->ift_timer);
261117cec474SVincenzo Maffione #ifdef DEV_NETMAP
261217cec474SVincenzo Maffione 		callout_stop(&txq->ift_netmap_timer);
261317cec474SVincenzo Maffione #endif /* DEV_NETMAP */
2614226fb85dSStephen Hurd 		CALLOUT_UNLOCK(txq);
2615226fb85dSStephen Hurd 
26164c7070dbSScott Long 		/* clean any enqueued buffers */
2617da69b8f9SSean Bruno 		iflib_ifmp_purge(txq);
26184c7070dbSScott Long 		/* Free any existing tx buffers. */
261923ac9029SStephen Hurd 		for (j = 0; j < txq->ift_size; j++) {
26204c7070dbSScott Long 			iflib_txsd_free(ctx, txq, j);
26214c7070dbSScott Long 		}
2622ab2e3f79SStephen Hurd 		txq->ift_processed = txq->ift_cleaned = txq->ift_cidx_processed = 0;
262358632fa7SMarcin Wojtas 		txq->ift_in_use = txq->ift_gen = txq->ift_no_desc_avail = 0;
262458632fa7SMarcin Wojtas 		if (sctx->isc_flags & IFLIB_PRESERVE_TX_INDICES)
262558632fa7SMarcin Wojtas 			txq->ift_cidx = txq->ift_pidx;
262658632fa7SMarcin Wojtas 		else
262758632fa7SMarcin Wojtas 			txq->ift_cidx = txq->ift_pidx = 0;
262858632fa7SMarcin Wojtas 
26294c7070dbSScott Long 		txq->ift_closed = txq->ift_mbuf_defrag = txq->ift_mbuf_defrag_failed = 0;
26304c7070dbSScott Long 		txq->ift_no_tx_dma_setup = txq->ift_txd_encap_efbig = txq->ift_map_failed = 0;
2631ab2e3f79SStephen Hurd 		txq->ift_pullups = 0;
263295246abbSSean Bruno 		ifmp_ring_reset_stats(txq->ift_br);
26334d261ce2SStephen Hurd 		for (j = 0, di = txq->ift_ifdi; j < sctx->isc_ntxqs; j++, di++)
26344c7070dbSScott Long 			bzero((void *)di->idi_vaddr, di->idi_size);
26354c7070dbSScott Long 	}
26364c7070dbSScott Long 	for (i = 0; i < scctx->isc_nrxqsets; i++, rxq++) {
26371bfdb812SAndriy Gapon 		gtaskqueue_drain(rxq->ifr_task.gt_taskqueue,
26381bfdb812SAndriy Gapon 		    &rxq->ifr_task.gt_task);
26394c7070dbSScott Long 
26401722eeacSMarius Strobl 		rxq->ifr_cq_cidx = 0;
26414d261ce2SStephen Hurd 		for (j = 0, di = rxq->ifr_ifdi; j < sctx->isc_nrxqs; j++, di++)
26424c7070dbSScott Long 			bzero((void *)di->idi_vaddr, di->idi_size);
26434c7070dbSScott Long 		/* also resets the free lists pidx/cidx */
26444c7070dbSScott Long 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++)
26454c7070dbSScott Long 			iflib_fl_bufs_free(fl);
26464c7070dbSScott Long 	}
26474c7070dbSScott Long }
26484c7070dbSScott Long 
264995246abbSSean Bruno static inline caddr_t
265095246abbSSean Bruno calc_next_rxd(iflib_fl_t fl, int cidx)
265195246abbSSean Bruno {
265295246abbSSean Bruno 	qidx_t size;
265395246abbSSean Bruno 	int nrxd;
265495246abbSSean Bruno 	caddr_t start, end, cur, next;
265595246abbSSean Bruno 
265695246abbSSean Bruno 	nrxd = fl->ifl_size;
265795246abbSSean Bruno 	size = fl->ifl_rxd_size;
265895246abbSSean Bruno 	start = fl->ifl_ifdi->idi_vaddr;
265995246abbSSean Bruno 
266095246abbSSean Bruno 	if (__predict_false(size == 0))
266195246abbSSean Bruno 		return (start);
266295246abbSSean Bruno 	cur = start + size*cidx;
266395246abbSSean Bruno 	end = start + size*nrxd;
266495246abbSSean Bruno 	next = CACHE_PTR_NEXT(cur);
266595246abbSSean Bruno 	return (next < end ? next : start);
266695246abbSSean Bruno }
266795246abbSSean Bruno 
2668e035717eSSean Bruno static inline void
2669e035717eSSean Bruno prefetch_pkts(iflib_fl_t fl, int cidx)
2670e035717eSSean Bruno {
2671e035717eSSean Bruno 	int nextptr;
2672e035717eSSean Bruno 	int nrxd = fl->ifl_size;
267395246abbSSean Bruno 	caddr_t next_rxd;
267495246abbSSean Bruno 
2675e035717eSSean Bruno 	nextptr = (cidx + CACHE_PTR_INCREMENT) & (nrxd-1);
2676e035717eSSean Bruno 	prefetch(&fl->ifl_sds.ifsd_m[nextptr]);
2677e035717eSSean Bruno 	prefetch(&fl->ifl_sds.ifsd_cl[nextptr]);
267895246abbSSean Bruno 	next_rxd = calc_next_rxd(fl, cidx);
267995246abbSSean Bruno 	prefetch(next_rxd);
2680e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 1) & (nrxd-1)]);
2681e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 2) & (nrxd-1)]);
2682e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 3) & (nrxd-1)]);
2683e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 4) & (nrxd-1)]);
2684e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 1) & (nrxd-1)]);
2685e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 2) & (nrxd-1)]);
2686e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 3) & (nrxd-1)]);
2687e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 4) & (nrxd-1)]);
2688e035717eSSean Bruno }
2689e035717eSSean Bruno 
26906d49b41eSAndrew Gallatin static struct mbuf *
26916d49b41eSAndrew Gallatin rxd_frag_to_sd(iflib_rxq_t rxq, if_rxd_frag_t irf, bool unload, if_rxsd_t sd,
26926d49b41eSAndrew Gallatin     int *pf_rv, if_rxd_info_t ri)
26934c7070dbSScott Long {
2694e035717eSSean Bruno 	bus_dmamap_t map;
26954c7070dbSScott Long 	iflib_fl_t fl;
26966d49b41eSAndrew Gallatin 	caddr_t payload;
26976d49b41eSAndrew Gallatin 	struct mbuf *m;
26986d49b41eSAndrew Gallatin 	int flid, cidx, len, next;
26994c7070dbSScott Long 
270095246abbSSean Bruno 	map = NULL;
27014c7070dbSScott Long 	flid = irf->irf_flid;
27024c7070dbSScott Long 	cidx = irf->irf_idx;
27034c7070dbSScott Long 	fl = &rxq->ifr_fl[flid];
270495246abbSSean Bruno 	sd->ifsd_fl = fl;
27056d49b41eSAndrew Gallatin 	m = fl->ifl_sds.ifsd_m[cidx];
270695246abbSSean Bruno 	sd->ifsd_cl = &fl->ifl_sds.ifsd_cl[cidx];
27074c7070dbSScott Long 	fl->ifl_credits--;
27084c7070dbSScott Long #if MEMORY_LOGGING
27094c7070dbSScott Long 	fl->ifl_m_dequeued++;
27104c7070dbSScott Long #endif
271195246abbSSean Bruno 	if (rxq->ifr_ctx->ifc_flags & IFC_PREFETCH)
2712e035717eSSean Bruno 		prefetch_pkts(fl, cidx);
2713e035717eSSean Bruno 	next = (cidx + CACHE_PTR_INCREMENT) & (fl->ifl_size-1);
2714e035717eSSean Bruno 	prefetch(&fl->ifl_sds.ifsd_map[next]);
2715e035717eSSean Bruno 	map = fl->ifl_sds.ifsd_map[cidx];
27164c7070dbSScott Long 
2717bfce461eSMarius Strobl 	bus_dmamap_sync(fl->ifl_buf_tag, map, BUS_DMASYNC_POSTREAD);
27186d49b41eSAndrew Gallatin 
27194f2beb72SPatrick Kelsey 	if (rxq->pfil != NULL && PFIL_HOOKED_IN(rxq->pfil) && pf_rv != NULL &&
27204f2beb72SPatrick Kelsey 	    irf->irf_len != 0) {
27216d49b41eSAndrew Gallatin 		payload  = *sd->ifsd_cl;
27226d49b41eSAndrew Gallatin 		payload +=  ri->iri_pad;
27236d49b41eSAndrew Gallatin 		len = ri->iri_len - ri->iri_pad;
27246d49b41eSAndrew Gallatin 		*pf_rv = pfil_run_hooks(rxq->pfil, payload, ri->iri_ifp,
27256d49b41eSAndrew Gallatin 		    len | PFIL_MEMPTR | PFIL_IN, NULL);
27266d49b41eSAndrew Gallatin 		switch (*pf_rv) {
27276d49b41eSAndrew Gallatin 		case PFIL_DROPPED:
27286d49b41eSAndrew Gallatin 		case PFIL_CONSUMED:
27296d49b41eSAndrew Gallatin 			/*
27306d49b41eSAndrew Gallatin 			 * The filter ate it.  Everything is recycled.
27316d49b41eSAndrew Gallatin 			 */
27326d49b41eSAndrew Gallatin 			m = NULL;
27336d49b41eSAndrew Gallatin 			unload = 0;
27346d49b41eSAndrew Gallatin 			break;
27356d49b41eSAndrew Gallatin 		case PFIL_REALLOCED:
27366d49b41eSAndrew Gallatin 			/*
27376d49b41eSAndrew Gallatin 			 * The filter copied it.  Everything is recycled.
27386d49b41eSAndrew Gallatin 			 */
27396d49b41eSAndrew Gallatin 			m = pfil_mem2mbuf(payload);
27406d49b41eSAndrew Gallatin 			unload = 0;
27416d49b41eSAndrew Gallatin 			break;
27426d49b41eSAndrew Gallatin 		case PFIL_PASS:
27436d49b41eSAndrew Gallatin 			/*
27446d49b41eSAndrew Gallatin 			 * Filter said it was OK, so receive like
27456d49b41eSAndrew Gallatin 			 * normal
27466d49b41eSAndrew Gallatin 			 */
27476d49b41eSAndrew Gallatin 			fl->ifl_sds.ifsd_m[cidx] = NULL;
27486d49b41eSAndrew Gallatin 			break;
27496d49b41eSAndrew Gallatin 		default:
27506d49b41eSAndrew Gallatin 			MPASS(0);
27516d49b41eSAndrew Gallatin 		}
27526d49b41eSAndrew Gallatin 	} else {
27536d49b41eSAndrew Gallatin 		fl->ifl_sds.ifsd_m[cidx] = NULL;
27540c864213SAndrew Gallatin 		if (pf_rv != NULL)
27556d49b41eSAndrew Gallatin 			*pf_rv = PFIL_PASS;
27566d49b41eSAndrew Gallatin 	}
27576d49b41eSAndrew Gallatin 
27584f2beb72SPatrick Kelsey 	if (unload && irf->irf_len != 0)
2759bfce461eSMarius Strobl 		bus_dmamap_unload(fl->ifl_buf_tag, map);
276095246abbSSean Bruno 	fl->ifl_cidx = (fl->ifl_cidx + 1) & (fl->ifl_size-1);
276195246abbSSean Bruno 	if (__predict_false(fl->ifl_cidx == 0))
27624c7070dbSScott Long 		fl->ifl_gen = 0;
276387890dbaSSean Bruno 	bit_clear(fl->ifl_rx_bitmap, cidx);
27646d49b41eSAndrew Gallatin 	return (m);
27654c7070dbSScott Long }
27664c7070dbSScott Long 
27674c7070dbSScott Long static struct mbuf *
27686d49b41eSAndrew Gallatin assemble_segments(iflib_rxq_t rxq, if_rxd_info_t ri, if_rxsd_t sd, int *pf_rv)
27694c7070dbSScott Long {
277095246abbSSean Bruno 	struct mbuf *m, *mh, *mt;
277195246abbSSean Bruno 	caddr_t cl;
27726d49b41eSAndrew Gallatin 	int  *pf_rv_ptr, flags, i, padlen;
27736d49b41eSAndrew Gallatin 	bool consumed;
27744c7070dbSScott Long 
27754c7070dbSScott Long 	i = 0;
277623ac9029SStephen Hurd 	mh = NULL;
27776d49b41eSAndrew Gallatin 	consumed = false;
27786d49b41eSAndrew Gallatin 	*pf_rv = PFIL_PASS;
27796d49b41eSAndrew Gallatin 	pf_rv_ptr = pf_rv;
27804c7070dbSScott Long 	do {
27816d49b41eSAndrew Gallatin 		m = rxd_frag_to_sd(rxq, &ri->iri_frags[i], !consumed, sd,
27826d49b41eSAndrew Gallatin 		    pf_rv_ptr, ri);
27834c7070dbSScott Long 
278495246abbSSean Bruno 		MPASS(*sd->ifsd_cl != NULL);
278523ac9029SStephen Hurd 
27866d49b41eSAndrew Gallatin 		/*
27876d49b41eSAndrew Gallatin 		 * Exclude zero-length frags & frags from
27886d49b41eSAndrew Gallatin 		 * packets the filter has consumed or dropped
27896d49b41eSAndrew Gallatin 		 */
27906d49b41eSAndrew Gallatin 		if (ri->iri_frags[i].irf_len == 0 || consumed ||
27916d49b41eSAndrew Gallatin 		    *pf_rv == PFIL_CONSUMED || *pf_rv == PFIL_DROPPED) {
27926d49b41eSAndrew Gallatin 			if (mh == NULL) {
27936d49b41eSAndrew Gallatin 				/* everything saved here */
27946d49b41eSAndrew Gallatin 				consumed = true;
27956d49b41eSAndrew Gallatin 				pf_rv_ptr = NULL;
279623ac9029SStephen Hurd 				continue;
279723ac9029SStephen Hurd 			}
27986d49b41eSAndrew Gallatin 			/* XXX we can save the cluster here, but not the mbuf */
27996d49b41eSAndrew Gallatin 			m_init(m, M_NOWAIT, MT_DATA, 0);
28006d49b41eSAndrew Gallatin 			m_free(m);
28016d49b41eSAndrew Gallatin 			continue;
28026d49b41eSAndrew Gallatin 		}
280323ac9029SStephen Hurd 		if (mh == NULL) {
28044c7070dbSScott Long 			flags = M_PKTHDR|M_EXT;
28054c7070dbSScott Long 			mh = mt = m;
28064c7070dbSScott Long 			padlen = ri->iri_pad;
28074c7070dbSScott Long 		} else {
28084c7070dbSScott Long 			flags = M_EXT;
28094c7070dbSScott Long 			mt->m_next = m;
28104c7070dbSScott Long 			mt = m;
28114c7070dbSScott Long 			/* assuming padding is only on the first fragment */
28124c7070dbSScott Long 			padlen = 0;
28134c7070dbSScott Long 		}
281495246abbSSean Bruno 		cl = *sd->ifsd_cl;
281595246abbSSean Bruno 		*sd->ifsd_cl = NULL;
28164c7070dbSScott Long 
28174c7070dbSScott Long 		/* Can these two be made one ? */
28184c7070dbSScott Long 		m_init(m, M_NOWAIT, MT_DATA, flags);
281995246abbSSean Bruno 		m_cljset(m, cl, sd->ifsd_fl->ifl_cltype);
28204c7070dbSScott Long 		/*
28214c7070dbSScott Long 		 * These must follow m_init and m_cljset
28224c7070dbSScott Long 		 */
28234c7070dbSScott Long 		m->m_data += padlen;
28244c7070dbSScott Long 		ri->iri_len -= padlen;
282523ac9029SStephen Hurd 		m->m_len = ri->iri_frags[i].irf_len;
28264c7070dbSScott Long 	} while (++i < ri->iri_nfrags);
28274c7070dbSScott Long 
28284c7070dbSScott Long 	return (mh);
28294c7070dbSScott Long }
28304c7070dbSScott Long 
28314c7070dbSScott Long /*
28324c7070dbSScott Long  * Process one software descriptor
28334c7070dbSScott Long  */
28344c7070dbSScott Long static struct mbuf *
28354c7070dbSScott Long iflib_rxd_pkt_get(iflib_rxq_t rxq, if_rxd_info_t ri)
28364c7070dbSScott Long {
283795246abbSSean Bruno 	struct if_rxsd sd;
28384c7070dbSScott Long 	struct mbuf *m;
28396d49b41eSAndrew Gallatin 	int pf_rv;
28404c7070dbSScott Long 
28414c7070dbSScott Long 	/* should I merge this back in now that the two paths are basically duplicated? */
284223ac9029SStephen Hurd 	if (ri->iri_nfrags == 1 &&
28434f2beb72SPatrick Kelsey 	    ri->iri_frags[0].irf_len != 0 &&
284418628b74SMark Johnston 	    ri->iri_frags[0].irf_len <= MIN(IFLIB_RX_COPY_THRESH, MHLEN)) {
28456d49b41eSAndrew Gallatin 		m = rxd_frag_to_sd(rxq, &ri->iri_frags[0], false, &sd,
28466d49b41eSAndrew Gallatin 		    &pf_rv, ri);
28476d49b41eSAndrew Gallatin 		if (pf_rv != PFIL_PASS && pf_rv != PFIL_REALLOCED)
28486d49b41eSAndrew Gallatin 			return (m);
28496d49b41eSAndrew Gallatin 		if (pf_rv == PFIL_PASS) {
28504c7070dbSScott Long 			m_init(m, M_NOWAIT, MT_DATA, M_PKTHDR);
285195246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
2852cd945dc0SMarcin Wojtas 			if (!IP_ALIGNED(m) && ri->iri_pad == 0)
285395246abbSSean Bruno 				m->m_data += 2;
285495246abbSSean Bruno #endif
285595246abbSSean Bruno 			memcpy(m->m_data, *sd.ifsd_cl, ri->iri_len);
285623ac9029SStephen Hurd 			m->m_len = ri->iri_frags[0].irf_len;
2857cd945dc0SMarcin Wojtas 			m->m_data += ri->iri_pad;
2858cd945dc0SMarcin Wojtas 			ri->iri_len -= ri->iri_pad;
28596d49b41eSAndrew Gallatin 		}
28604c7070dbSScott Long 	} else {
28616d49b41eSAndrew Gallatin 		m = assemble_segments(rxq, ri, &sd, &pf_rv);
28624f2beb72SPatrick Kelsey 		if (m == NULL)
28634f2beb72SPatrick Kelsey 			return (NULL);
28646d49b41eSAndrew Gallatin 		if (pf_rv != PFIL_PASS && pf_rv != PFIL_REALLOCED)
28656d49b41eSAndrew Gallatin 			return (m);
28664c7070dbSScott Long 	}
28674c7070dbSScott Long 	m->m_pkthdr.len = ri->iri_len;
28684c7070dbSScott Long 	m->m_pkthdr.rcvif = ri->iri_ifp;
28694c7070dbSScott Long 	m->m_flags |= ri->iri_flags;
28704c7070dbSScott Long 	m->m_pkthdr.ether_vtag = ri->iri_vtag;
28714c7070dbSScott Long 	m->m_pkthdr.flowid = ri->iri_flowid;
28724c7070dbSScott Long 	M_HASHTYPE_SET(m, ri->iri_rsstype);
28734c7070dbSScott Long 	m->m_pkthdr.csum_flags = ri->iri_csum_flags;
28744c7070dbSScott Long 	m->m_pkthdr.csum_data = ri->iri_csum_data;
28754c7070dbSScott Long 	return (m);
28764c7070dbSScott Long }
28774c7070dbSScott Long 
287835e4e998SStephen Hurd #if defined(INET6) || defined(INET)
2879fe1bcadaSStephen Hurd static void
2880fe1bcadaSStephen Hurd iflib_get_ip_forwarding(struct lro_ctrl *lc, bool *v4, bool *v6)
2881fe1bcadaSStephen Hurd {
2882fe1bcadaSStephen Hurd 	CURVNET_SET(lc->ifp->if_vnet);
2883fe1bcadaSStephen Hurd #if defined(INET6)
2884188adcb7SMarko Zec 	*v6 = V_ip6_forwarding;
2885fe1bcadaSStephen Hurd #endif
2886fe1bcadaSStephen Hurd #if defined(INET)
2887188adcb7SMarko Zec 	*v4 = V_ipforwarding;
2888fe1bcadaSStephen Hurd #endif
2889fe1bcadaSStephen Hurd 	CURVNET_RESTORE();
2890fe1bcadaSStephen Hurd }
2891fe1bcadaSStephen Hurd 
289235e4e998SStephen Hurd /*
289335e4e998SStephen Hurd  * Returns true if it's possible this packet could be LROed.
289435e4e998SStephen Hurd  * if it returns false, it is guaranteed that tcp_lro_rx()
289535e4e998SStephen Hurd  * would not return zero.
289635e4e998SStephen Hurd  */
289735e4e998SStephen Hurd static bool
2898fe1bcadaSStephen Hurd iflib_check_lro_possible(struct mbuf *m, bool v4_forwarding, bool v6_forwarding)
289935e4e998SStephen Hurd {
290035e4e998SStephen Hurd 	struct ether_header *eh;
290135e4e998SStephen Hurd 
290235e4e998SStephen Hurd 	eh = mtod(m, struct ether_header *);
29036aee0bfaSMarko Zec 	switch (eh->ether_type) {
2904abec4724SSean Bruno #if defined(INET6)
29056aee0bfaSMarko Zec 		case htons(ETHERTYPE_IPV6):
29066aee0bfaSMarko Zec 			return (!v6_forwarding);
2907abec4724SSean Bruno #endif
2908abec4724SSean Bruno #if defined (INET)
29096aee0bfaSMarko Zec 		case htons(ETHERTYPE_IP):
29106aee0bfaSMarko Zec 			return (!v4_forwarding);
2911abec4724SSean Bruno #endif
291235e4e998SStephen Hurd 	}
291335e4e998SStephen Hurd 
291435e4e998SStephen Hurd 	return false;
291535e4e998SStephen Hurd }
2916fe1bcadaSStephen Hurd #else
2917fe1bcadaSStephen Hurd static void
2918fe1bcadaSStephen Hurd iflib_get_ip_forwarding(struct lro_ctrl *lc __unused, bool *v4 __unused, bool *v6 __unused)
2919fe1bcadaSStephen Hurd {
2920fe1bcadaSStephen Hurd }
292135e4e998SStephen Hurd #endif
292235e4e998SStephen Hurd 
2923fb1a29b4SHans Petter Selasky static void
2924fb1a29b4SHans Petter Selasky _task_fn_rx_watchdog(void *context)
2925fb1a29b4SHans Petter Selasky {
2926fb1a29b4SHans Petter Selasky 	iflib_rxq_t rxq = context;
2927fb1a29b4SHans Petter Selasky 
2928fb1a29b4SHans Petter Selasky 	GROUPTASK_ENQUEUE(&rxq->ifr_task);
2929fb1a29b4SHans Petter Selasky }
2930fb1a29b4SHans Petter Selasky 
2931fb1a29b4SHans Petter Selasky static uint8_t
293295246abbSSean Bruno iflib_rxeof(iflib_rxq_t rxq, qidx_t budget)
29334c7070dbSScott Long {
29341722eeacSMarius Strobl 	if_t ifp;
29354c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
29364c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
293723ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
29384c7070dbSScott Long 	int avail, i;
293995246abbSSean Bruno 	qidx_t *cidxp;
29404c7070dbSScott Long 	struct if_rxd_info ri;
29414c7070dbSScott Long 	int err, budget_left, rx_bytes, rx_pkts;
29424c7070dbSScott Long 	iflib_fl_t fl;
29434c7070dbSScott Long 	int lro_enabled;
2944f6cb0deaSMatt Macy 	bool v4_forwarding, v6_forwarding, lro_possible;
2945fb1a29b4SHans Petter Selasky 	uint8_t retval = 0;
294695246abbSSean Bruno 
29474c7070dbSScott Long 	/*
29484c7070dbSScott Long 	 * XXX early demux data packets so that if_input processing only handles
29494c7070dbSScott Long 	 * acks in interrupt context
29504c7070dbSScott Long 	 */
295120f63282SStephen Hurd 	struct mbuf *m, *mh, *mt, *mf;
29524c7070dbSScott Long 
29530b8df657SGleb Smirnoff 	NET_EPOCH_ASSERT();
29540b8df657SGleb Smirnoff 
2955f6cb0deaSMatt Macy 	lro_possible = v4_forwarding = v6_forwarding = false;
295695246abbSSean Bruno 	ifp = ctx->ifc_ifp;
29574c7070dbSScott Long 	mh = mt = NULL;
29584c7070dbSScott Long 	MPASS(budget > 0);
29594c7070dbSScott Long 	rx_pkts	= rx_bytes = 0;
296023ac9029SStephen Hurd 	if (sctx->isc_flags & IFLIB_HAS_RXCQ)
29614c7070dbSScott Long 		cidxp = &rxq->ifr_cq_cidx;
29624c7070dbSScott Long 	else
29634c7070dbSScott Long 		cidxp = &rxq->ifr_fl[0].ifl_cidx;
296423ac9029SStephen Hurd 	if ((avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget)) == 0) {
29654c7070dbSScott Long 		for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++)
2966b256d25cSMark Johnston 			retval |= iflib_fl_refill_all(ctx, fl);
29674c7070dbSScott Long 		DBG_COUNTER_INC(rx_unavail);
2968fb1a29b4SHans Petter Selasky 		return (retval);
29694c7070dbSScott Long 	}
29704c7070dbSScott Long 
29716d49b41eSAndrew Gallatin 	/* pfil needs the vnet to be set */
29726d49b41eSAndrew Gallatin 	CURVNET_SET_QUIET(ifp->if_vnet);
29738b8d9093SMarius Strobl 	for (budget_left = budget; budget_left > 0 && avail > 0;) {
29744c7070dbSScott Long 		if (__predict_false(!CTX_ACTIVE(ctx))) {
29754c7070dbSScott Long 			DBG_COUNTER_INC(rx_ctx_inactive);
29764c7070dbSScott Long 			break;
29774c7070dbSScott Long 		}
29784c7070dbSScott Long 		/*
29794c7070dbSScott Long 		 * Reset client set fields to their default values
29804c7070dbSScott Long 		 */
298195246abbSSean Bruno 		rxd_info_zero(&ri);
29824c7070dbSScott Long 		ri.iri_qsidx = rxq->ifr_id;
29834c7070dbSScott Long 		ri.iri_cidx = *cidxp;
298495246abbSSean Bruno 		ri.iri_ifp = ifp;
29854c7070dbSScott Long 		ri.iri_frags = rxq->ifr_frags;
29864c7070dbSScott Long 		err = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri);
29874c7070dbSScott Long 
298895246abbSSean Bruno 		if (err)
298995246abbSSean Bruno 			goto err;
29906d49b41eSAndrew Gallatin 		rx_pkts += 1;
29916d49b41eSAndrew Gallatin 		rx_bytes += ri.iri_len;
299223ac9029SStephen Hurd 		if (sctx->isc_flags & IFLIB_HAS_RXCQ) {
299323ac9029SStephen Hurd 			*cidxp = ri.iri_cidx;
299423ac9029SStephen Hurd 			/* Update our consumer index */
299595246abbSSean Bruno 			/* XXX NB: shurd - check if this is still safe */
29961722eeacSMarius Strobl 			while (rxq->ifr_cq_cidx >= scctx->isc_nrxd[0])
299723ac9029SStephen Hurd 				rxq->ifr_cq_cidx -= scctx->isc_nrxd[0];
29984c7070dbSScott Long 			/* was this only a completion queue message? */
29994c7070dbSScott Long 			if (__predict_false(ri.iri_nfrags == 0))
30004c7070dbSScott Long 				continue;
30014c7070dbSScott Long 		}
30024c7070dbSScott Long 		MPASS(ri.iri_nfrags != 0);
30034c7070dbSScott Long 		MPASS(ri.iri_len != 0);
30044c7070dbSScott Long 
30054c7070dbSScott Long 		/* will advance the cidx on the corresponding free lists */
30064c7070dbSScott Long 		m = iflib_rxd_pkt_get(rxq, &ri);
30078b8d9093SMarius Strobl 		avail--;
30088b8d9093SMarius Strobl 		budget_left--;
30094c7070dbSScott Long 		if (avail == 0 && budget_left)
301023ac9029SStephen Hurd 			avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget_left);
30114c7070dbSScott Long 
30126d49b41eSAndrew Gallatin 		if (__predict_false(m == NULL))
30134c7070dbSScott Long 			continue;
30146d49b41eSAndrew Gallatin 
30154c7070dbSScott Long 		/* imm_pkt: -- cxgb */
30164c7070dbSScott Long 		if (mh == NULL)
30174c7070dbSScott Long 			mh = mt = m;
30184c7070dbSScott Long 		else {
30194c7070dbSScott Long 			mt->m_nextpkt = m;
30204c7070dbSScott Long 			mt = m;
30214c7070dbSScott Long 		}
30224c7070dbSScott Long 	}
30236d49b41eSAndrew Gallatin 	CURVNET_RESTORE();
30244c7070dbSScott Long 	/* make sure that we can refill faster than drain */
30254c7070dbSScott Long 	for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++)
3026b256d25cSMark Johnston 		retval |= iflib_fl_refill_all(ctx, fl);
30274c7070dbSScott Long 
30284c7070dbSScott Long 	lro_enabled = (if_getcapenable(ifp) & IFCAP_LRO);
3029fe1bcadaSStephen Hurd 	if (lro_enabled)
3030fe1bcadaSStephen Hurd 		iflib_get_ip_forwarding(&rxq->ifr_lc, &v4_forwarding, &v6_forwarding);
303120f63282SStephen Hurd 	mt = mf = NULL;
30324c7070dbSScott Long 	while (mh != NULL) {
30334c7070dbSScott Long 		m = mh;
30344c7070dbSScott Long 		mh = mh->m_nextpkt;
30354c7070dbSScott Long 		m->m_nextpkt = NULL;
303695246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
303795246abbSSean Bruno 		if (!IP_ALIGNED(m) && (m = iflib_fixup_rx(m)) == NULL)
303895246abbSSean Bruno 			continue;
303995246abbSSean Bruno #endif
3040aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
304135e4e998SStephen Hurd 		if (lro_enabled) {
304235e4e998SStephen Hurd 			if (!lro_possible) {
3043fe1bcadaSStephen Hurd 				lro_possible = iflib_check_lro_possible(m, v4_forwarding, v6_forwarding);
304435e4e998SStephen Hurd 				if (lro_possible && mf != NULL) {
304535e4e998SStephen Hurd 					ifp->if_input(ifp, mf);
304635e4e998SStephen Hurd 					DBG_COUNTER_INC(rx_if_input);
304735e4e998SStephen Hurd 					mt = mf = NULL;
304835e4e998SStephen Hurd 				}
304935e4e998SStephen Hurd 			}
305025ac1dd5SStephen Hurd 			if ((m->m_pkthdr.csum_flags & (CSUM_L4_CALC|CSUM_L4_VALID)) ==
305125ac1dd5SStephen Hurd 			    (CSUM_L4_CALC|CSUM_L4_VALID)) {
305235e4e998SStephen Hurd 				if (lro_possible && tcp_lro_rx(&rxq->ifr_lc, m, 0) == 0)
30534c7070dbSScott Long 					continue;
305420f63282SStephen Hurd 			}
305525ac1dd5SStephen Hurd 		}
3056aaeb188aSBjoern A. Zeeb #endif
305735e4e998SStephen Hurd 		if (lro_possible) {
305835e4e998SStephen Hurd 			ifp->if_input(ifp, m);
305935e4e998SStephen Hurd 			DBG_COUNTER_INC(rx_if_input);
306035e4e998SStephen Hurd 			continue;
306135e4e998SStephen Hurd 		}
306235e4e998SStephen Hurd 
306335e4e998SStephen Hurd 		if (mf == NULL)
306435e4e998SStephen Hurd 			mf = m;
306520f63282SStephen Hurd 		if (mt != NULL)
306620f63282SStephen Hurd 			mt->m_nextpkt = m;
306720f63282SStephen Hurd 		mt = m;
306820f63282SStephen Hurd 	}
306920f63282SStephen Hurd 	if (mf != NULL) {
307020f63282SStephen Hurd 		ifp->if_input(ifp, mf);
30714c7070dbSScott Long 		DBG_COUNTER_INC(rx_if_input);
30724c7070dbSScott Long 	}
307323ac9029SStephen Hurd 
30744c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_IBYTES, rx_bytes);
30754c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_pkts);
30764c7070dbSScott Long 
30774c7070dbSScott Long 	/*
30784c7070dbSScott Long 	 * Flush any outstanding LRO work
30794c7070dbSScott Long 	 */
3080aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
308123ac9029SStephen Hurd 	tcp_lro_flush_all(&rxq->ifr_lc);
3082aaeb188aSBjoern A. Zeeb #endif
3083fb1a29b4SHans Petter Selasky 	if (avail != 0 || iflib_rxd_avail(ctx, rxq, *cidxp, 1) != 0)
3084fb1a29b4SHans Petter Selasky 		retval |= IFLIB_RXEOF_MORE;
3085fb1a29b4SHans Petter Selasky 	return (retval);
308695246abbSSean Bruno err:
30877b610b60SSean Bruno 	STATE_LOCK(ctx);
3088ab2e3f79SStephen Hurd 	ctx->ifc_flags |= IFC_DO_RESET;
3089940f62d6SEric Joyner 	iflib_admin_intr_deferred(ctx);
309046fa0c25SEric Joyner 	STATE_UNLOCK(ctx);
3091fb1a29b4SHans Petter Selasky 	return (0);
309295246abbSSean Bruno }
309395246abbSSean Bruno 
309495246abbSSean Bruno #define TXD_NOTIFY_COUNT(txq) (((txq)->ift_size / (txq)->ift_update_freq)-1)
309595246abbSSean Bruno static inline qidx_t
309695246abbSSean Bruno txq_max_db_deferred(iflib_txq_t txq, qidx_t in_use)
309795246abbSSean Bruno {
309895246abbSSean Bruno 	qidx_t notify_count = TXD_NOTIFY_COUNT(txq);
309995246abbSSean Bruno 	qidx_t minthresh = txq->ift_size / 8;
310095246abbSSean Bruno 	if (in_use > 4*minthresh)
310195246abbSSean Bruno 		return (notify_count);
310295246abbSSean Bruno 	if (in_use > 2*minthresh)
310395246abbSSean Bruno 		return (notify_count >> 1);
310495246abbSSean Bruno 	if (in_use > minthresh)
310595246abbSSean Bruno 		return (notify_count >> 3);
310695246abbSSean Bruno 	return (0);
310795246abbSSean Bruno }
310895246abbSSean Bruno 
310995246abbSSean Bruno static inline qidx_t
311095246abbSSean Bruno txq_max_rs_deferred(iflib_txq_t txq)
311195246abbSSean Bruno {
311295246abbSSean Bruno 	qidx_t notify_count = TXD_NOTIFY_COUNT(txq);
311395246abbSSean Bruno 	qidx_t minthresh = txq->ift_size / 8;
311495246abbSSean Bruno 	if (txq->ift_in_use > 4*minthresh)
311595246abbSSean Bruno 		return (notify_count);
311695246abbSSean Bruno 	if (txq->ift_in_use > 2*minthresh)
311795246abbSSean Bruno 		return (notify_count >> 1);
311895246abbSSean Bruno 	if (txq->ift_in_use > minthresh)
311995246abbSSean Bruno 		return (notify_count >> 2);
31202b2fc973SSean Bruno 	return (2);
31214c7070dbSScott Long }
31224c7070dbSScott Long 
31234c7070dbSScott Long #define M_CSUM_FLAGS(m) ((m)->m_pkthdr.csum_flags)
31244c7070dbSScott Long #define M_HAS_VLANTAG(m) (m->m_flags & M_VLANTAG)
312595246abbSSean Bruno 
312695246abbSSean Bruno #define TXQ_MAX_DB_DEFERRED(txq, in_use) txq_max_db_deferred((txq), (in_use))
312795246abbSSean Bruno #define TXQ_MAX_RS_DEFERRED(txq) txq_max_rs_deferred(txq)
312823ac9029SStephen Hurd #define TXQ_MAX_DB_CONSUMED(size) (size >> 4)
31294c7070dbSScott Long 
313095246abbSSean Bruno /* forward compatibility for cxgb */
313195246abbSSean Bruno #define FIRST_QSET(ctx) 0
313295246abbSSean Bruno #define NTXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_ntxqsets)
313395246abbSSean Bruno #define NRXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_nrxqsets)
313495246abbSSean Bruno #define QIDX(ctx, m) ((((m)->m_pkthdr.flowid & ctx->ifc_softc_ctx.isc_rss_table_mask) % NTXQSETS(ctx)) + FIRST_QSET(ctx))
313595246abbSSean Bruno #define DESC_RECLAIMABLE(q) ((int)((q)->ift_processed - (q)->ift_cleaned - (q)->ift_ctx->ifc_softc_ctx.isc_tx_nsegments))
313695246abbSSean Bruno 
313795246abbSSean Bruno /* XXX we should be setting this to something other than zero */
313895246abbSSean Bruno #define RECLAIM_THRESH(ctx) ((ctx)->ifc_sctx->isc_tx_reclaim_thresh)
313981be6552SMatt Macy #define	MAX_TX_DESC(ctx) MAX((ctx)->ifc_softc_ctx.isc_tx_tso_segments_max, \
31407474544bSMarius Strobl     (ctx)->ifc_softc_ctx.isc_tx_nsegments)
314195246abbSSean Bruno 
314295246abbSSean Bruno static inline bool
314381be6552SMatt Macy iflib_txd_db_check(iflib_txq_t txq, int ring)
31444c7070dbSScott Long {
314581be6552SMatt Macy 	if_ctx_t ctx = txq->ift_ctx;
314695246abbSSean Bruno 	qidx_t dbval, max;
31474c7070dbSScott Long 
314881be6552SMatt Macy 	max = TXQ_MAX_DB_DEFERRED(txq, txq->ift_in_use);
314981be6552SMatt Macy 
315081be6552SMatt Macy 	/* force || threshold exceeded || at the edge of the ring */
315181be6552SMatt Macy 	if (ring || (txq->ift_db_pending >= max) || (TXQ_AVAIL(txq) <= MAX_TX_DESC(ctx) + 2)) {
315281be6552SMatt Macy 
315381be6552SMatt Macy 		/*
315481be6552SMatt Macy 		 * 'npending' is used if the card's doorbell is in terms of the number of descriptors
315581be6552SMatt Macy 		 * pending flush (BRCM). 'pidx' is used in cases where the card's doorbeel uses the
315681be6552SMatt Macy 		 * producer index explicitly (INTC).
315781be6552SMatt Macy 		 */
31584c7070dbSScott Long 		dbval = txq->ift_npending ? txq->ift_npending : txq->ift_pidx;
315995dcf343SMarius Strobl 		bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
316095dcf343SMarius Strobl 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
31614c7070dbSScott Long 		ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, dbval);
316281be6552SMatt Macy 
316381be6552SMatt Macy 		/*
316481be6552SMatt Macy 		 * Absent bugs there are zero packets pending so reset pending counts to zero.
316581be6552SMatt Macy 		 */
31664c7070dbSScott Long 		txq->ift_db_pending = txq->ift_npending = 0;
316781be6552SMatt Macy 		return (true);
31684c7070dbSScott Long 	}
316981be6552SMatt Macy 	return (false);
31704c7070dbSScott Long }
31714c7070dbSScott Long 
31724c7070dbSScott Long #ifdef PKT_DEBUG
31734c7070dbSScott Long static void
31744c7070dbSScott Long print_pkt(if_pkt_info_t pi)
31754c7070dbSScott Long {
31764c7070dbSScott Long 	printf("pi len:  %d qsidx: %d nsegs: %d ndescs: %d flags: %x pidx: %d\n",
31774c7070dbSScott Long 	       pi->ipi_len, pi->ipi_qsidx, pi->ipi_nsegs, pi->ipi_ndescs, pi->ipi_flags, pi->ipi_pidx);
31784c7070dbSScott Long 	printf("pi new_pidx: %d csum_flags: %lx tso_segsz: %d mflags: %x vtag: %d\n",
31794c7070dbSScott Long 	       pi->ipi_new_pidx, pi->ipi_csum_flags, pi->ipi_tso_segsz, pi->ipi_mflags, pi->ipi_vtag);
31804c7070dbSScott Long 	printf("pi etype: %d ehdrlen: %d ip_hlen: %d ipproto: %d\n",
31814c7070dbSScott Long 	       pi->ipi_etype, pi->ipi_ehdrlen, pi->ipi_ip_hlen, pi->ipi_ipproto);
31824c7070dbSScott Long }
31834c7070dbSScott Long #endif
31844c7070dbSScott Long 
31854c7070dbSScott Long #define IS_TSO4(pi) ((pi)->ipi_csum_flags & CSUM_IP_TSO)
3186a06424ddSEric Joyner #define IS_TX_OFFLOAD4(pi) ((pi)->ipi_csum_flags & (CSUM_IP_TCP | CSUM_IP_TSO))
31874c7070dbSScott Long #define IS_TSO6(pi) ((pi)->ipi_csum_flags & CSUM_IP6_TSO)
3188a06424ddSEric Joyner #define IS_TX_OFFLOAD6(pi) ((pi)->ipi_csum_flags & (CSUM_IP6_TCP | CSUM_IP6_TSO))
31894c7070dbSScott Long 
31904c7070dbSScott Long static int
31914c7070dbSScott Long iflib_parse_header(iflib_txq_t txq, if_pkt_info_t pi, struct mbuf **mp)
31924c7070dbSScott Long {
3193ab2e3f79SStephen Hurd 	if_shared_ctx_t sctx = txq->ift_ctx->ifc_sctx;
31944c7070dbSScott Long 	struct ether_vlan_header *eh;
3195c9a49a4fSMarius Strobl 	struct mbuf *m;
31964c7070dbSScott Long 
31978b8d9093SMarius Strobl 	m = *mp;
3198ab2e3f79SStephen Hurd 	if ((sctx->isc_flags & IFLIB_NEED_SCRATCH) &&
3199ab2e3f79SStephen Hurd 	    M_WRITABLE(m) == 0) {
3200ab2e3f79SStephen Hurd 		if ((m = m_dup(m, M_NOWAIT)) == NULL) {
3201ab2e3f79SStephen Hurd 			return (ENOMEM);
3202ab2e3f79SStephen Hurd 		} else {
3203ab2e3f79SStephen Hurd 			m_freem(*mp);
320464e6fc13SStephen Hurd 			DBG_COUNTER_INC(tx_frees);
32058b8d9093SMarius Strobl 			*mp = m;
3206ab2e3f79SStephen Hurd 		}
3207ab2e3f79SStephen Hurd 	}
32081248952aSSean Bruno 
32094c7070dbSScott Long 	/*
32104c7070dbSScott Long 	 * Determine where frame payload starts.
32114c7070dbSScott Long 	 * Jump over vlan headers if already present,
32124c7070dbSScott Long 	 * helpful for QinQ too.
32134c7070dbSScott Long 	 */
32144c7070dbSScott Long 	if (__predict_false(m->m_len < sizeof(*eh))) {
32154c7070dbSScott Long 		txq->ift_pullups++;
32164c7070dbSScott Long 		if (__predict_false((m = m_pullup(m, sizeof(*eh))) == NULL))
32174c7070dbSScott Long 			return (ENOMEM);
32184c7070dbSScott Long 	}
32194c7070dbSScott Long 	eh = mtod(m, struct ether_vlan_header *);
32204c7070dbSScott Long 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
32214c7070dbSScott Long 		pi->ipi_etype = ntohs(eh->evl_proto);
32224c7070dbSScott Long 		pi->ipi_ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
32234c7070dbSScott Long 	} else {
32244c7070dbSScott Long 		pi->ipi_etype = ntohs(eh->evl_encap_proto);
32254c7070dbSScott Long 		pi->ipi_ehdrlen = ETHER_HDR_LEN;
32264c7070dbSScott Long 	}
32274c7070dbSScott Long 
32284c7070dbSScott Long 	switch (pi->ipi_etype) {
32294c7070dbSScott Long #ifdef INET
32304c7070dbSScott Long 	case ETHERTYPE_IP:
32314c7070dbSScott Long 	{
3232c9a49a4fSMarius Strobl 		struct mbuf *n;
32334c7070dbSScott Long 		struct ip *ip = NULL;
32344c7070dbSScott Long 		struct tcphdr *th = NULL;
32354c7070dbSScott Long 		int minthlen;
32364c7070dbSScott Long 
32374c7070dbSScott Long 		minthlen = min(m->m_pkthdr.len, pi->ipi_ehdrlen + sizeof(*ip) + sizeof(*th));
32384c7070dbSScott Long 		if (__predict_false(m->m_len < minthlen)) {
32394c7070dbSScott Long 			/*
32404c7070dbSScott Long 			 * if this code bloat is causing too much of a hit
32414c7070dbSScott Long 			 * move it to a separate function and mark it noinline
32424c7070dbSScott Long 			 */
32434c7070dbSScott Long 			if (m->m_len == pi->ipi_ehdrlen) {
32444c7070dbSScott Long 				n = m->m_next;
32454c7070dbSScott Long 				MPASS(n);
32464c7070dbSScott Long 				if (n->m_len >= sizeof(*ip))  {
32474c7070dbSScott Long 					ip = (struct ip *)n->m_data;
32484c7070dbSScott Long 					if (n->m_len >= (ip->ip_hl << 2) + sizeof(*th))
32494c7070dbSScott Long 						th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
32504c7070dbSScott Long 				} else {
32514c7070dbSScott Long 					txq->ift_pullups++;
32524c7070dbSScott Long 					if (__predict_false((m = m_pullup(m, minthlen)) == NULL))
32534c7070dbSScott Long 						return (ENOMEM);
32544c7070dbSScott Long 					ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
32554c7070dbSScott Long 				}
32564c7070dbSScott Long 			} else {
32574c7070dbSScott Long 				txq->ift_pullups++;
32584c7070dbSScott Long 				if (__predict_false((m = m_pullup(m, minthlen)) == NULL))
32594c7070dbSScott Long 					return (ENOMEM);
32604c7070dbSScott Long 				ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
32614c7070dbSScott Long 				if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th))
32624c7070dbSScott Long 					th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
32634c7070dbSScott Long 			}
32644c7070dbSScott Long 		} else {
32654c7070dbSScott Long 			ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
32664c7070dbSScott Long 			if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th))
32674c7070dbSScott Long 				th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
32684c7070dbSScott Long 		}
32694c7070dbSScott Long 		pi->ipi_ip_hlen = ip->ip_hl << 2;
32704c7070dbSScott Long 		pi->ipi_ipproto = ip->ip_p;
32714c7070dbSScott Long 		pi->ipi_flags |= IPI_TX_IPV4;
32724c7070dbSScott Long 
3273a06424ddSEric Joyner 		/* TCP checksum offload may require TCP header length */
3274a06424ddSEric Joyner 		if (IS_TX_OFFLOAD4(pi)) {
3275a06424ddSEric Joyner 			if (__predict_true(pi->ipi_ipproto == IPPROTO_TCP)) {
32764c7070dbSScott Long 				if (__predict_false(th == NULL)) {
32774c7070dbSScott Long 					txq->ift_pullups++;
32784c7070dbSScott Long 					if (__predict_false((m = m_pullup(m, (ip->ip_hl << 2) + sizeof(*th))) == NULL))
32794c7070dbSScott Long 						return (ENOMEM);
32804c7070dbSScott Long 					th = (struct tcphdr *)((caddr_t)ip + pi->ipi_ip_hlen);
32814c7070dbSScott Long 				}
32824c7070dbSScott Long 				pi->ipi_tcp_hflags = th->th_flags;
32834c7070dbSScott Long 				pi->ipi_tcp_hlen = th->th_off << 2;
32844c7070dbSScott Long 				pi->ipi_tcp_seq = th->th_seq;
32854c7070dbSScott Long 			}
3286a06424ddSEric Joyner 			if (IS_TSO4(pi)) {
32874c7070dbSScott Long 				if (__predict_false(ip->ip_p != IPPROTO_TCP))
32884c7070dbSScott Long 					return (ENXIO);
32898d4ceb9cSStephen Hurd 				/*
32908d4ceb9cSStephen Hurd 				 * TSO always requires hardware checksum offload.
32918d4ceb9cSStephen Hurd 				 */
32928d4ceb9cSStephen Hurd 				pi->ipi_csum_flags |= (CSUM_IP_TCP | CSUM_IP);
32934c7070dbSScott Long 				th->th_sum = in_pseudo(ip->ip_src.s_addr,
32944c7070dbSScott Long 						       ip->ip_dst.s_addr, htons(IPPROTO_TCP));
32954c7070dbSScott Long 				pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz;
32961248952aSSean Bruno 				if (sctx->isc_flags & IFLIB_TSO_INIT_IP) {
32971248952aSSean Bruno 					ip->ip_sum = 0;
32981248952aSSean Bruno 					ip->ip_len = htons(pi->ipi_ip_hlen + pi->ipi_tcp_hlen + pi->ipi_tso_segsz);
32991248952aSSean Bruno 				}
33004c7070dbSScott Long 			}
3301a06424ddSEric Joyner 		}
33028d4ceb9cSStephen Hurd 		if ((sctx->isc_flags & IFLIB_NEED_ZERO_CSUM) && (pi->ipi_csum_flags & CSUM_IP))
33038d4ceb9cSStephen Hurd                        ip->ip_sum = 0;
33048d4ceb9cSStephen Hurd 
33054c7070dbSScott Long 		break;
33064c7070dbSScott Long 	}
33074c7070dbSScott Long #endif
33084c7070dbSScott Long #ifdef INET6
33094c7070dbSScott Long 	case ETHERTYPE_IPV6:
33104c7070dbSScott Long 	{
33114c7070dbSScott Long 		struct ip6_hdr *ip6 = (struct ip6_hdr *)(m->m_data + pi->ipi_ehdrlen);
33124c7070dbSScott Long 		struct tcphdr *th;
33134c7070dbSScott Long 		pi->ipi_ip_hlen = sizeof(struct ip6_hdr);
33144c7070dbSScott Long 
33154c7070dbSScott Long 		if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) {
331664e6fc13SStephen Hurd 			txq->ift_pullups++;
33174c7070dbSScott Long 			if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) == NULL))
33184c7070dbSScott Long 				return (ENOMEM);
33194c7070dbSScott Long 		}
33204c7070dbSScott Long 		th = (struct tcphdr *)((caddr_t)ip6 + pi->ipi_ip_hlen);
33214c7070dbSScott Long 
33224c7070dbSScott Long 		/* XXX-BZ this will go badly in case of ext hdrs. */
33234c7070dbSScott Long 		pi->ipi_ipproto = ip6->ip6_nxt;
33244c7070dbSScott Long 		pi->ipi_flags |= IPI_TX_IPV6;
33254c7070dbSScott Long 
3326a06424ddSEric Joyner 		/* TCP checksum offload may require TCP header length */
3327a06424ddSEric Joyner 		if (IS_TX_OFFLOAD6(pi)) {
33284c7070dbSScott Long 			if (pi->ipi_ipproto == IPPROTO_TCP) {
33294c7070dbSScott Long 				if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) {
3330a06424ddSEric Joyner 					txq->ift_pullups++;
33314c7070dbSScott Long 					if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) == NULL))
33324c7070dbSScott Long 						return (ENOMEM);
33334c7070dbSScott Long 				}
33344c7070dbSScott Long 				pi->ipi_tcp_hflags = th->th_flags;
33354c7070dbSScott Long 				pi->ipi_tcp_hlen = th->th_off << 2;
3336a06424ddSEric Joyner 				pi->ipi_tcp_seq = th->th_seq;
33374c7070dbSScott Long 			}
3338a06424ddSEric Joyner 			if (IS_TSO6(pi)) {
33394c7070dbSScott Long 				if (__predict_false(ip6->ip6_nxt != IPPROTO_TCP))
33404c7070dbSScott Long 					return (ENXIO);
33414c7070dbSScott Long 				/*
33428d4ceb9cSStephen Hurd 				 * TSO always requires hardware checksum offload.
33434c7070dbSScott Long 				 */
3344a06424ddSEric Joyner 				pi->ipi_csum_flags |= CSUM_IP6_TCP;
33454c7070dbSScott Long 				th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
33464c7070dbSScott Long 				pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz;
33474c7070dbSScott Long 			}
3348a06424ddSEric Joyner 		}
33494c7070dbSScott Long 		break;
33504c7070dbSScott Long 	}
33514c7070dbSScott Long #endif
33524c7070dbSScott Long 	default:
33534c7070dbSScott Long 		pi->ipi_csum_flags &= ~CSUM_OFFLOAD;
33544c7070dbSScott Long 		pi->ipi_ip_hlen = 0;
33554c7070dbSScott Long 		break;
33564c7070dbSScott Long 	}
33574c7070dbSScott Long 	*mp = m;
33581248952aSSean Bruno 
33594c7070dbSScott Long 	return (0);
33604c7070dbSScott Long }
33614c7070dbSScott Long 
33624c7070dbSScott Long /*
33634c7070dbSScott Long  * If dodgy hardware rejects the scatter gather chain we've handed it
336423ac9029SStephen Hurd  * we'll need to remove the mbuf chain from ifsg_m[] before we can add the
336523ac9029SStephen Hurd  * m_defrag'd mbufs
33664c7070dbSScott Long  */
33674c7070dbSScott Long static __noinline struct mbuf *
336823ac9029SStephen Hurd iflib_remove_mbuf(iflib_txq_t txq)
33694c7070dbSScott Long {
3370fbec776dSAndrew Gallatin 	int ntxd, pidx;
3371fbec776dSAndrew Gallatin 	struct mbuf *m, **ifsd_m;
33724c7070dbSScott Long 
33734c7070dbSScott Long 	ifsd_m = txq->ift_sds.ifsd_m;
337423ac9029SStephen Hurd 	ntxd = txq->ift_size;
3375fbec776dSAndrew Gallatin 	pidx = txq->ift_pidx & (ntxd - 1);
3376fbec776dSAndrew Gallatin 	ifsd_m = txq->ift_sds.ifsd_m;
3377fbec776dSAndrew Gallatin 	m = ifsd_m[pidx];
33784c7070dbSScott Long 	ifsd_m[pidx] = NULL;
3379bfce461eSMarius Strobl 	bus_dmamap_unload(txq->ift_buf_tag, txq->ift_sds.ifsd_map[pidx]);
33808a04b53dSKonstantin Belousov 	if (txq->ift_sds.ifsd_tso_map != NULL)
3381bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_tso_buf_tag,
33828a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_tso_map[pidx]);
33834c7070dbSScott Long #if MEMORY_LOGGING
33844c7070dbSScott Long 	txq->ift_dequeued++;
33854c7070dbSScott Long #endif
3386fbec776dSAndrew Gallatin 	return (m);
33874c7070dbSScott Long }
33884c7070dbSScott Long 
338995246abbSSean Bruno static inline caddr_t
339095246abbSSean Bruno calc_next_txd(iflib_txq_t txq, int cidx, uint8_t qid)
339195246abbSSean Bruno {
339295246abbSSean Bruno 	qidx_t size;
339395246abbSSean Bruno 	int ntxd;
339495246abbSSean Bruno 	caddr_t start, end, cur, next;
339595246abbSSean Bruno 
339695246abbSSean Bruno 	ntxd = txq->ift_size;
339795246abbSSean Bruno 	size = txq->ift_txd_size[qid];
339895246abbSSean Bruno 	start = txq->ift_ifdi[qid].idi_vaddr;
339995246abbSSean Bruno 
340095246abbSSean Bruno 	if (__predict_false(size == 0))
340195246abbSSean Bruno 		return (start);
340295246abbSSean Bruno 	cur = start + size*cidx;
340395246abbSSean Bruno 	end = start + size*ntxd;
340495246abbSSean Bruno 	next = CACHE_PTR_NEXT(cur);
340595246abbSSean Bruno 	return (next < end ? next : start);
340695246abbSSean Bruno }
340795246abbSSean Bruno 
3408d14c853bSStephen Hurd /*
3409d14c853bSStephen Hurd  * Pad an mbuf to ensure a minimum ethernet frame size.
3410d14c853bSStephen Hurd  * min_frame_size is the frame size (less CRC) to pad the mbuf to
3411d14c853bSStephen Hurd  */
3412d14c853bSStephen Hurd static __noinline int
3413a15fbbb8SStephen Hurd iflib_ether_pad(device_t dev, struct mbuf **m_head, uint16_t min_frame_size)
3414d14c853bSStephen Hurd {
3415d14c853bSStephen Hurd 	/*
3416d14c853bSStephen Hurd 	 * 18 is enough bytes to pad an ARP packet to 46 bytes, and
3417d14c853bSStephen Hurd 	 * and ARP message is the smallest common payload I can think of
3418d14c853bSStephen Hurd 	 */
3419d14c853bSStephen Hurd 	static char pad[18];	/* just zeros */
3420d14c853bSStephen Hurd 	int n;
3421a15fbbb8SStephen Hurd 	struct mbuf *new_head;
3422d14c853bSStephen Hurd 
3423a15fbbb8SStephen Hurd 	if (!M_WRITABLE(*m_head)) {
3424a15fbbb8SStephen Hurd 		new_head = m_dup(*m_head, M_NOWAIT);
3425a15fbbb8SStephen Hurd 		if (new_head == NULL) {
342604993890SStephen Hurd 			m_freem(*m_head);
3427a15fbbb8SStephen Hurd 			device_printf(dev, "cannot pad short frame, m_dup() failed");
342806c47d48SStephen Hurd 			DBG_COUNTER_INC(encap_pad_mbuf_fail);
342964e6fc13SStephen Hurd 			DBG_COUNTER_INC(tx_frees);
3430a15fbbb8SStephen Hurd 			return ENOMEM;
3431a15fbbb8SStephen Hurd 		}
3432a15fbbb8SStephen Hurd 		m_freem(*m_head);
3433a15fbbb8SStephen Hurd 		*m_head = new_head;
3434a15fbbb8SStephen Hurd 	}
3435a15fbbb8SStephen Hurd 
3436a15fbbb8SStephen Hurd 	for (n = min_frame_size - (*m_head)->m_pkthdr.len;
3437d14c853bSStephen Hurd 	     n > 0; n -= sizeof(pad))
3438a15fbbb8SStephen Hurd 		if (!m_append(*m_head, min(n, sizeof(pad)), pad))
3439d14c853bSStephen Hurd 			break;
3440d14c853bSStephen Hurd 
3441d14c853bSStephen Hurd 	if (n > 0) {
3442a15fbbb8SStephen Hurd 		m_freem(*m_head);
3443d14c853bSStephen Hurd 		device_printf(dev, "cannot pad short frame\n");
3444d14c853bSStephen Hurd 		DBG_COUNTER_INC(encap_pad_mbuf_fail);
344564e6fc13SStephen Hurd 		DBG_COUNTER_INC(tx_frees);
3446d14c853bSStephen Hurd 		return (ENOBUFS);
3447d14c853bSStephen Hurd 	}
3448d14c853bSStephen Hurd 
3449d14c853bSStephen Hurd 	return 0;
3450d14c853bSStephen Hurd }
3451d14c853bSStephen Hurd 
34524c7070dbSScott Long static int
34534c7070dbSScott Long iflib_encap(iflib_txq_t txq, struct mbuf **m_headp)
34544c7070dbSScott Long {
34554c7070dbSScott Long 	if_ctx_t		ctx;
34564c7070dbSScott Long 	if_shared_ctx_t		sctx;
34574c7070dbSScott Long 	if_softc_ctx_t		scctx;
3458bfce461eSMarius Strobl 	bus_dma_tag_t		buf_tag;
34594c7070dbSScott Long 	bus_dma_segment_t	*segs;
3460fbec776dSAndrew Gallatin 	struct mbuf		*m_head, **ifsd_m;
346195246abbSSean Bruno 	void			*next_txd;
34624c7070dbSScott Long 	bus_dmamap_t		map;
34634c7070dbSScott Long 	struct if_pkt_info	pi;
34644c7070dbSScott Long 	int remap = 0;
34654c7070dbSScott Long 	int err, nsegs, ndesc, max_segs, pidx, cidx, next, ntxd;
34664c7070dbSScott Long 
34674c7070dbSScott Long 	ctx = txq->ift_ctx;
34684c7070dbSScott Long 	sctx = ctx->ifc_sctx;
34694c7070dbSScott Long 	scctx = &ctx->ifc_softc_ctx;
34704c7070dbSScott Long 	segs = txq->ift_segs;
347123ac9029SStephen Hurd 	ntxd = txq->ift_size;
34724c7070dbSScott Long 	m_head = *m_headp;
34734c7070dbSScott Long 	map = NULL;
34744c7070dbSScott Long 
34754c7070dbSScott Long 	/*
34764c7070dbSScott Long 	 * If we're doing TSO the next descriptor to clean may be quite far ahead
34774c7070dbSScott Long 	 */
34784c7070dbSScott Long 	cidx = txq->ift_cidx;
34794c7070dbSScott Long 	pidx = txq->ift_pidx;
348095246abbSSean Bruno 	if (ctx->ifc_flags & IFC_PREFETCH) {
34814c7070dbSScott Long 		next = (cidx + CACHE_PTR_INCREMENT) & (ntxd-1);
348295246abbSSean Bruno 		if (!(ctx->ifc_flags & IFLIB_HAS_TXCQ)) {
348395246abbSSean Bruno 			next_txd = calc_next_txd(txq, cidx, 0);
348495246abbSSean Bruno 			prefetch(next_txd);
348595246abbSSean Bruno 		}
34864c7070dbSScott Long 
34874c7070dbSScott Long 		/* prefetch the next cache line of mbuf pointers and flags */
34884c7070dbSScott Long 		prefetch(&txq->ift_sds.ifsd_m[next]);
34894c7070dbSScott Long 		prefetch(&txq->ift_sds.ifsd_map[next]);
34904c7070dbSScott Long 		next = (cidx + CACHE_LINE_SIZE) & (ntxd-1);
34914c7070dbSScott Long 	}
349295246abbSSean Bruno 	map = txq->ift_sds.ifsd_map[pidx];
3493fbec776dSAndrew Gallatin 	ifsd_m = txq->ift_sds.ifsd_m;
34944c7070dbSScott Long 
34954c7070dbSScott Long 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
3496bfce461eSMarius Strobl 		buf_tag = txq->ift_tso_buf_tag;
34974c7070dbSScott Long 		max_segs = scctx->isc_tx_tso_segments_max;
34988a04b53dSKonstantin Belousov 		map = txq->ift_sds.ifsd_tso_map[pidx];
3499bfce461eSMarius Strobl 		MPASS(buf_tag != NULL);
35007f87c040SMarius Strobl 		MPASS(max_segs > 0);
35014c7070dbSScott Long 	} else {
3502bfce461eSMarius Strobl 		buf_tag = txq->ift_buf_tag;
35034c7070dbSScott Long 		max_segs = scctx->isc_tx_nsegments;
35048a04b53dSKonstantin Belousov 		map = txq->ift_sds.ifsd_map[pidx];
35054c7070dbSScott Long 	}
3506d14c853bSStephen Hurd 	if ((sctx->isc_flags & IFLIB_NEED_ETHER_PAD) &&
3507d14c853bSStephen Hurd 	    __predict_false(m_head->m_pkthdr.len < scctx->isc_min_frame_size)) {
3508a15fbbb8SStephen Hurd 		err = iflib_ether_pad(ctx->ifc_dev, m_headp, scctx->isc_min_frame_size);
350964e6fc13SStephen Hurd 		if (err) {
351064e6fc13SStephen Hurd 			DBG_COUNTER_INC(encap_txd_encap_fail);
3511d14c853bSStephen Hurd 			return err;
3512d14c853bSStephen Hurd 		}
351364e6fc13SStephen Hurd 	}
3514a15fbbb8SStephen Hurd 	m_head = *m_headp;
351595246abbSSean Bruno 
351695246abbSSean Bruno 	pkt_info_zero(&pi);
3517ab2e3f79SStephen Hurd 	pi.ipi_mflags = (m_head->m_flags & (M_VLANTAG|M_BCAST|M_MCAST));
3518ab2e3f79SStephen Hurd 	pi.ipi_pidx = pidx;
3519ab2e3f79SStephen Hurd 	pi.ipi_qsidx = txq->ift_id;
35203429c02fSStephen Hurd 	pi.ipi_len = m_head->m_pkthdr.len;
35213429c02fSStephen Hurd 	pi.ipi_csum_flags = m_head->m_pkthdr.csum_flags;
35221722eeacSMarius Strobl 	pi.ipi_vtag = M_HAS_VLANTAG(m_head) ? m_head->m_pkthdr.ether_vtag : 0;
35234c7070dbSScott Long 
35244c7070dbSScott Long 	/* deliberate bitwise OR to make one condition */
35254c7070dbSScott Long 	if (__predict_true((pi.ipi_csum_flags | pi.ipi_vtag))) {
352664e6fc13SStephen Hurd 		if (__predict_false((err = iflib_parse_header(txq, &pi, m_headp)) != 0)) {
352764e6fc13SStephen Hurd 			DBG_COUNTER_INC(encap_txd_encap_fail);
35284c7070dbSScott Long 			return (err);
352964e6fc13SStephen Hurd 		}
35304c7070dbSScott Long 		m_head = *m_headp;
35314c7070dbSScott Long 	}
35324c7070dbSScott Long 
35334c7070dbSScott Long retry:
3534bfce461eSMarius Strobl 	err = bus_dmamap_load_mbuf_sg(buf_tag, map, m_head, segs, &nsegs,
3535fbec776dSAndrew Gallatin 	    BUS_DMA_NOWAIT);
35364c7070dbSScott Long defrag:
35374c7070dbSScott Long 	if (__predict_false(err)) {
35384c7070dbSScott Long 		switch (err) {
35394c7070dbSScott Long 		case EFBIG:
35404c7070dbSScott Long 			/* try collapse once and defrag once */
3541f7594707SAndrew Gallatin 			if (remap == 0) {
35424c7070dbSScott Long 				m_head = m_collapse(*m_headp, M_NOWAIT, max_segs);
3543f7594707SAndrew Gallatin 				/* try defrag if collapsing fails */
3544f7594707SAndrew Gallatin 				if (m_head == NULL)
3545f7594707SAndrew Gallatin 					remap++;
3546f7594707SAndrew Gallatin 			}
354764e6fc13SStephen Hurd 			if (remap == 1) {
354864e6fc13SStephen Hurd 				txq->ift_mbuf_defrag++;
35494c7070dbSScott Long 				m_head = m_defrag(*m_headp, M_NOWAIT);
355064e6fc13SStephen Hurd 			}
35513e8d1baeSEric Joyner 			/*
35523e8d1baeSEric Joyner 			 * remap should never be >1 unless bus_dmamap_load_mbuf_sg
35533e8d1baeSEric Joyner 			 * failed to map an mbuf that was run through m_defrag
35543e8d1baeSEric Joyner 			 */
35553e8d1baeSEric Joyner 			MPASS(remap <= 1);
35563e8d1baeSEric Joyner 			if (__predict_false(m_head == NULL || remap > 1))
35574c7070dbSScott Long 				goto defrag_failed;
35583e8d1baeSEric Joyner 			remap++;
35594c7070dbSScott Long 			*m_headp = m_head;
35604c7070dbSScott Long 			goto retry;
35614c7070dbSScott Long 			break;
35624c7070dbSScott Long 		case ENOMEM:
35634c7070dbSScott Long 			txq->ift_no_tx_dma_setup++;
35644c7070dbSScott Long 			break;
35654c7070dbSScott Long 		default:
35664c7070dbSScott Long 			txq->ift_no_tx_dma_setup++;
35674c7070dbSScott Long 			m_freem(*m_headp);
35684c7070dbSScott Long 			DBG_COUNTER_INC(tx_frees);
35694c7070dbSScott Long 			*m_headp = NULL;
35704c7070dbSScott Long 			break;
35714c7070dbSScott Long 		}
35724c7070dbSScott Long 		txq->ift_map_failed++;
35734c7070dbSScott Long 		DBG_COUNTER_INC(encap_load_mbuf_fail);
357464e6fc13SStephen Hurd 		DBG_COUNTER_INC(encap_txd_encap_fail);
35754c7070dbSScott Long 		return (err);
35764c7070dbSScott Long 	}
3577fbec776dSAndrew Gallatin 	ifsd_m[pidx] = m_head;
35784c7070dbSScott Long 	/*
35794c7070dbSScott Long 	 * XXX assumes a 1 to 1 relationship between segments and
35804c7070dbSScott Long 	 *        descriptors - this does not hold true on all drivers, e.g.
35814c7070dbSScott Long 	 *        cxgb
35824c7070dbSScott Long 	 */
35834c7070dbSScott Long 	if (__predict_false(nsegs + 2 > TXQ_AVAIL(txq))) {
35844c7070dbSScott Long 		txq->ift_no_desc_avail++;
3585bfce461eSMarius Strobl 		bus_dmamap_unload(buf_tag, map);
35864c7070dbSScott Long 		DBG_COUNTER_INC(encap_txq_avail_fail);
358764e6fc13SStephen Hurd 		DBG_COUNTER_INC(encap_txd_encap_fail);
358823ac9029SStephen Hurd 		if ((txq->ift_task.gt_task.ta_flags & TASK_ENQUEUED) == 0)
35894c7070dbSScott Long 			GROUPTASK_ENQUEUE(&txq->ift_task);
35904c7070dbSScott Long 		return (ENOBUFS);
35914c7070dbSScott Long 	}
359295246abbSSean Bruno 	/*
359395246abbSSean Bruno 	 * On Intel cards we can greatly reduce the number of TX interrupts
359495246abbSSean Bruno 	 * we see by only setting report status on every Nth descriptor.
359595246abbSSean Bruno 	 * However, this also means that the driver will need to keep track
359695246abbSSean Bruno 	 * of the descriptors that RS was set on to check them for the DD bit.
359795246abbSSean Bruno 	 */
359895246abbSSean Bruno 	txq->ift_rs_pending += nsegs + 1;
359995246abbSSean Bruno 	if (txq->ift_rs_pending > TXQ_MAX_RS_DEFERRED(txq) ||
36001f7ce05dSAndrew Gallatin 	     iflib_no_tx_batch || (TXQ_AVAIL(txq) - nsegs) <= MAX_TX_DESC(ctx) + 2) {
360195246abbSSean Bruno 		pi.ipi_flags |= IPI_TX_INTR;
360295246abbSSean Bruno 		txq->ift_rs_pending = 0;
360395246abbSSean Bruno 	}
360495246abbSSean Bruno 
36054c7070dbSScott Long 	pi.ipi_segs = segs;
36064c7070dbSScott Long 	pi.ipi_nsegs = nsegs;
36074c7070dbSScott Long 
360823ac9029SStephen Hurd 	MPASS(pidx >= 0 && pidx < txq->ift_size);
36094c7070dbSScott Long #ifdef PKT_DEBUG
36104c7070dbSScott Long 	print_pkt(&pi);
36114c7070dbSScott Long #endif
36124c7070dbSScott Long 	if ((err = ctx->isc_txd_encap(ctx->ifc_softc, &pi)) == 0) {
361395dcf343SMarius Strobl 		bus_dmamap_sync(buf_tag, map, BUS_DMASYNC_PREWRITE);
36144c7070dbSScott Long 		DBG_COUNTER_INC(tx_encap);
361595246abbSSean Bruno 		MPASS(pi.ipi_new_pidx < txq->ift_size);
36164c7070dbSScott Long 
36174c7070dbSScott Long 		ndesc = pi.ipi_new_pidx - pi.ipi_pidx;
36184c7070dbSScott Long 		if (pi.ipi_new_pidx < pi.ipi_pidx) {
361923ac9029SStephen Hurd 			ndesc += txq->ift_size;
36204c7070dbSScott Long 			txq->ift_gen = 1;
36214c7070dbSScott Long 		}
36221248952aSSean Bruno 		/*
36231248952aSSean Bruno 		 * drivers can need as many as
36241248952aSSean Bruno 		 * two sentinels
36251248952aSSean Bruno 		 */
36261248952aSSean Bruno 		MPASS(ndesc <= pi.ipi_nsegs + 2);
36274c7070dbSScott Long 		MPASS(pi.ipi_new_pidx != pidx);
36284c7070dbSScott Long 		MPASS(ndesc > 0);
36294c7070dbSScott Long 		txq->ift_in_use += ndesc;
363081be6552SMatt Macy 		txq->ift_db_pending += ndesc;
363195246abbSSean Bruno 
36324c7070dbSScott Long 		/*
36334c7070dbSScott Long 		 * We update the last software descriptor again here because there may
36344c7070dbSScott Long 		 * be a sentinel and/or there may be more mbufs than segments
36354c7070dbSScott Long 		 */
36364c7070dbSScott Long 		txq->ift_pidx = pi.ipi_new_pidx;
36374c7070dbSScott Long 		txq->ift_npending += pi.ipi_ndescs;
3638f7594707SAndrew Gallatin 	} else {
363923ac9029SStephen Hurd 		*m_headp = m_head = iflib_remove_mbuf(txq);
3640f7594707SAndrew Gallatin 		if (err == EFBIG) {
36414c7070dbSScott Long 			txq->ift_txd_encap_efbig++;
3642f7594707SAndrew Gallatin 			if (remap < 2) {
3643f7594707SAndrew Gallatin 				remap = 1;
36444c7070dbSScott Long 				goto defrag;
3645f7594707SAndrew Gallatin 			}
3646f7594707SAndrew Gallatin 		}
3647f7594707SAndrew Gallatin 		goto defrag_failed;
3648f7594707SAndrew Gallatin 	}
364964e6fc13SStephen Hurd 	/*
365064e6fc13SStephen Hurd 	 * err can't possibly be non-zero here, so we don't neet to test it
365164e6fc13SStephen Hurd 	 * to see if we need to DBG_COUNTER_INC(encap_txd_encap_fail).
365264e6fc13SStephen Hurd 	 */
36534c7070dbSScott Long 	return (err);
36544c7070dbSScott Long 
36554c7070dbSScott Long defrag_failed:
36564c7070dbSScott Long 	txq->ift_mbuf_defrag_failed++;
36574c7070dbSScott Long 	txq->ift_map_failed++;
36584c7070dbSScott Long 	m_freem(*m_headp);
36594c7070dbSScott Long 	DBG_COUNTER_INC(tx_frees);
36604c7070dbSScott Long 	*m_headp = NULL;
366164e6fc13SStephen Hurd 	DBG_COUNTER_INC(encap_txd_encap_fail);
36624c7070dbSScott Long 	return (ENOMEM);
36634c7070dbSScott Long }
36644c7070dbSScott Long 
36654c7070dbSScott Long static void
36664c7070dbSScott Long iflib_tx_desc_free(iflib_txq_t txq, int n)
36674c7070dbSScott Long {
36684c7070dbSScott Long 	uint32_t qsize, cidx, mask, gen;
36694c7070dbSScott Long 	struct mbuf *m, **ifsd_m;
367095246abbSSean Bruno 	bool do_prefetch;
36714c7070dbSScott Long 
36724c7070dbSScott Long 	cidx = txq->ift_cidx;
36734c7070dbSScott Long 	gen = txq->ift_gen;
367423ac9029SStephen Hurd 	qsize = txq->ift_size;
36754c7070dbSScott Long 	mask = qsize-1;
36764c7070dbSScott Long 	ifsd_m = txq->ift_sds.ifsd_m;
367795246abbSSean Bruno 	do_prefetch = (txq->ift_ctx->ifc_flags & IFC_PREFETCH);
36784c7070dbSScott Long 
367994618825SMark Johnston 	while (n-- > 0) {
368095246abbSSean Bruno 		if (do_prefetch) {
36814c7070dbSScott Long 			prefetch(ifsd_m[(cidx + 3) & mask]);
36824c7070dbSScott Long 			prefetch(ifsd_m[(cidx + 4) & mask]);
368395246abbSSean Bruno 		}
36844c7070dbSScott Long 		if ((m = ifsd_m[cidx]) != NULL) {
3685fbec776dSAndrew Gallatin 			prefetch(&ifsd_m[(cidx + CACHE_PTR_INCREMENT) & mask]);
36868a04b53dSKonstantin Belousov 			if (m->m_pkthdr.csum_flags & CSUM_TSO) {
3687bfce461eSMarius Strobl 				bus_dmamap_sync(txq->ift_tso_buf_tag,
36888a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_tso_map[cidx],
36898a04b53dSKonstantin Belousov 				    BUS_DMASYNC_POSTWRITE);
3690bfce461eSMarius Strobl 				bus_dmamap_unload(txq->ift_tso_buf_tag,
36918a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_tso_map[cidx]);
36928a04b53dSKonstantin Belousov 			} else {
3693bfce461eSMarius Strobl 				bus_dmamap_sync(txq->ift_buf_tag,
36948a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_map[cidx],
36958a04b53dSKonstantin Belousov 				    BUS_DMASYNC_POSTWRITE);
3696bfce461eSMarius Strobl 				bus_dmamap_unload(txq->ift_buf_tag,
36978a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_map[cidx]);
36988a04b53dSKonstantin Belousov 			}
36994c7070dbSScott Long 			/* XXX we don't support any drivers that batch packets yet */
37004c7070dbSScott Long 			MPASS(m->m_nextpkt == NULL);
37015c5ca36cSSean Bruno 			m_freem(m);
37024c7070dbSScott Long 			ifsd_m[cidx] = NULL;
37034c7070dbSScott Long #if MEMORY_LOGGING
37044c7070dbSScott Long 			txq->ift_dequeued++;
37054c7070dbSScott Long #endif
37064c7070dbSScott Long 			DBG_COUNTER_INC(tx_frees);
37074c7070dbSScott Long 		}
37084c7070dbSScott Long 		if (__predict_false(++cidx == qsize)) {
37094c7070dbSScott Long 			cidx = 0;
37104c7070dbSScott Long 			gen = 0;
37114c7070dbSScott Long 		}
37124c7070dbSScott Long 	}
37134c7070dbSScott Long 	txq->ift_cidx = cidx;
37144c7070dbSScott Long 	txq->ift_gen = gen;
37154c7070dbSScott Long }
37164c7070dbSScott Long 
37174c7070dbSScott Long static __inline int
37184c7070dbSScott Long iflib_completed_tx_reclaim(iflib_txq_t txq, int thresh)
37194c7070dbSScott Long {
37204c7070dbSScott Long 	int reclaim;
37214c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
37224c7070dbSScott Long 
37234c7070dbSScott Long 	KASSERT(thresh >= 0, ("invalid threshold to reclaim"));
37244c7070dbSScott Long 	MPASS(thresh /*+ MAX_TX_DESC(txq->ift_ctx) */ < txq->ift_size);
37254c7070dbSScott Long 
37264c7070dbSScott Long 	/*
37274c7070dbSScott Long 	 * Need a rate-limiting check so that this isn't called every time
37284c7070dbSScott Long 	 */
37294c7070dbSScott Long 	iflib_tx_credits_update(ctx, txq);
37304c7070dbSScott Long 	reclaim = DESC_RECLAIMABLE(txq);
37314c7070dbSScott Long 
37324c7070dbSScott Long 	if (reclaim <= thresh /* + MAX_TX_DESC(txq->ift_ctx) */) {
37334c7070dbSScott Long #ifdef INVARIANTS
37344c7070dbSScott Long 		if (iflib_verbose_debug) {
37354c7070dbSScott Long 			printf("%s processed=%ju cleaned=%ju tx_nsegments=%d reclaim=%d thresh=%d\n", __FUNCTION__,
37364c7070dbSScott Long 			       txq->ift_processed, txq->ift_cleaned, txq->ift_ctx->ifc_softc_ctx.isc_tx_nsegments,
37374c7070dbSScott Long 			       reclaim, thresh);
37384c7070dbSScott Long 		}
37394c7070dbSScott Long #endif
37404c7070dbSScott Long 		return (0);
37414c7070dbSScott Long 	}
37424c7070dbSScott Long 	iflib_tx_desc_free(txq, reclaim);
37434c7070dbSScott Long 	txq->ift_cleaned += reclaim;
37444c7070dbSScott Long 	txq->ift_in_use -= reclaim;
37454c7070dbSScott Long 
37464c7070dbSScott Long 	return (reclaim);
37474c7070dbSScott Long }
37484c7070dbSScott Long 
37494c7070dbSScott Long static struct mbuf **
375095246abbSSean Bruno _ring_peek_one(struct ifmp_ring *r, int cidx, int offset, int remaining)
37514c7070dbSScott Long {
375295246abbSSean Bruno 	int next, size;
375395246abbSSean Bruno 	struct mbuf **items;
37544c7070dbSScott Long 
375595246abbSSean Bruno 	size = r->size;
375695246abbSSean Bruno 	next = (cidx + CACHE_PTR_INCREMENT) & (size-1);
375795246abbSSean Bruno 	items = __DEVOLATILE(struct mbuf **, &r->items[0]);
375895246abbSSean Bruno 
375995246abbSSean Bruno 	prefetch(items[(cidx + offset) & (size-1)]);
376095246abbSSean Bruno 	if (remaining > 1) {
37613429c02fSStephen Hurd 		prefetch2cachelines(&items[next]);
37623429c02fSStephen Hurd 		prefetch2cachelines(items[(cidx + offset + 1) & (size-1)]);
37633429c02fSStephen Hurd 		prefetch2cachelines(items[(cidx + offset + 2) & (size-1)]);
37643429c02fSStephen Hurd 		prefetch2cachelines(items[(cidx + offset + 3) & (size-1)]);
376595246abbSSean Bruno 	}
376695246abbSSean Bruno 	return (__DEVOLATILE(struct mbuf **, &r->items[(cidx + offset) & (size-1)]));
37674c7070dbSScott Long }
37684c7070dbSScott Long 
37694c7070dbSScott Long static void
37704c7070dbSScott Long iflib_txq_check_drain(iflib_txq_t txq, int budget)
37714c7070dbSScott Long {
37724c7070dbSScott Long 
377395246abbSSean Bruno 	ifmp_ring_check_drainage(txq->ift_br, budget);
37744c7070dbSScott Long }
37754c7070dbSScott Long 
37764c7070dbSScott Long static uint32_t
37774c7070dbSScott Long iflib_txq_can_drain(struct ifmp_ring *r)
37784c7070dbSScott Long {
37794c7070dbSScott Long 	iflib_txq_t txq = r->cookie;
37804c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
37814c7070dbSScott Long 
378295dcf343SMarius Strobl 	if (TXQ_AVAIL(txq) > MAX_TX_DESC(ctx) + 2)
378395dcf343SMarius Strobl 		return (1);
37848a04b53dSKonstantin Belousov 	bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
37858a04b53dSKonstantin Belousov 	    BUS_DMASYNC_POSTREAD);
378695dcf343SMarius Strobl 	return (ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id,
378795dcf343SMarius Strobl 	    false));
37884c7070dbSScott Long }
37894c7070dbSScott Long 
37904c7070dbSScott Long static uint32_t
37914c7070dbSScott Long iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
37924c7070dbSScott Long {
37934c7070dbSScott Long 	iflib_txq_t txq = r->cookie;
37944c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
37951722eeacSMarius Strobl 	if_t ifp = ctx->ifc_ifp;
3796c2c5d1e7SMarius Strobl 	struct mbuf *m, **mp;
379781be6552SMatt Macy 	int avail, bytes_sent, skipped, count, err, i;
379881be6552SMatt Macy 	int mcast_sent, pkt_sent, reclaimed;
3799c2c5d1e7SMarius Strobl 	bool do_prefetch, rang, ring;
38004c7070dbSScott Long 
38014c7070dbSScott Long 	if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING) ||
38024c7070dbSScott Long 			    !LINK_ACTIVE(ctx))) {
38034c7070dbSScott Long 		DBG_COUNTER_INC(txq_drain_notready);
38044c7070dbSScott Long 		return (0);
38054c7070dbSScott Long 	}
380695246abbSSean Bruno 	reclaimed = iflib_completed_tx_reclaim(txq, RECLAIM_THRESH(ctx));
380781be6552SMatt Macy 	rang = iflib_txd_db_check(txq, reclaimed && txq->ift_db_pending);
38084c7070dbSScott Long 	avail = IDXDIFF(pidx, cidx, r->size);
380981be6552SMatt Macy 
38104c7070dbSScott Long 	if (__predict_false(ctx->ifc_flags & IFC_QFLUSH)) {
381181be6552SMatt Macy 		/*
381281be6552SMatt Macy 		 * The driver is unloading so we need to free all pending packets.
381381be6552SMatt Macy 		 */
38144c7070dbSScott Long 		DBG_COUNTER_INC(txq_drain_flushing);
38154c7070dbSScott Long 		for (i = 0; i < avail; i++) {
3816bc0e855bSStephen Hurd 			if (__predict_true(r->items[(cidx + i) & (r->size-1)] != (void *)txq))
381754bf96fbSMark Johnston 				m_freem(r->items[(cidx + i) & (r->size-1)]);
38184c7070dbSScott Long 			r->items[(cidx + i) & (r->size-1)] = NULL;
38194c7070dbSScott Long 		}
38204c7070dbSScott Long 		return (avail);
38214c7070dbSScott Long 	}
382295246abbSSean Bruno 
38234c7070dbSScott Long 	if (__predict_false(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE)) {
38244c7070dbSScott Long 		txq->ift_qstatus = IFLIB_QUEUE_IDLE;
38254c7070dbSScott Long 		CALLOUT_LOCK(txq);
38264c7070dbSScott Long 		callout_stop(&txq->ift_timer);
38274c7070dbSScott Long 		CALLOUT_UNLOCK(txq);
38284c7070dbSScott Long 		DBG_COUNTER_INC(txq_drain_oactive);
38294c7070dbSScott Long 		return (0);
38304c7070dbSScott Long 	}
383181be6552SMatt Macy 
383281be6552SMatt Macy 	/*
383381be6552SMatt Macy 	 * If we've reclaimed any packets this queue cannot be hung.
383481be6552SMatt Macy 	 */
383595246abbSSean Bruno 	if (reclaimed)
383695246abbSSean Bruno 		txq->ift_qstatus = IFLIB_QUEUE_IDLE;
383781be6552SMatt Macy 	skipped = mcast_sent = bytes_sent = pkt_sent = 0;
38384c7070dbSScott Long 	count = MIN(avail, TX_BATCH_SIZE);
3839da69b8f9SSean Bruno #ifdef INVARIANTS
3840da69b8f9SSean Bruno 	if (iflib_verbose_debug)
3841da69b8f9SSean Bruno 		printf("%s avail=%d ifc_flags=%x txq_avail=%d ", __FUNCTION__,
3842da69b8f9SSean Bruno 		       avail, ctx->ifc_flags, TXQ_AVAIL(txq));
3843da69b8f9SSean Bruno #endif
384495246abbSSean Bruno 	do_prefetch = (ctx->ifc_flags & IFC_PREFETCH);
38451ae4848cSMatt Macy 	err = 0;
384681be6552SMatt Macy 	for (i = 0; i < count && TXQ_AVAIL(txq) >= MAX_TX_DESC(ctx) + 2; i++) {
38471ae4848cSMatt Macy 		int rem = do_prefetch ? count - i : 0;
38484c7070dbSScott Long 
384995246abbSSean Bruno 		mp = _ring_peek_one(r, cidx, i, rem);
3850da69b8f9SSean Bruno 		MPASS(mp != NULL && *mp != NULL);
385181be6552SMatt Macy 
385281be6552SMatt Macy 		/*
385381be6552SMatt Macy 		 * Completion interrupts will use the address of the txq
385481be6552SMatt Macy 		 * as a sentinel to enqueue _something_ in order to acquire
385581be6552SMatt Macy 		 * the lock on the mp_ring (there's no direct lock call).
385681be6552SMatt Macy 		 * We obviously whave to check for these sentinel cases
385781be6552SMatt Macy 		 * and skip them.
385881be6552SMatt Macy 		 */
385995246abbSSean Bruno 		if (__predict_false(*mp == (struct mbuf *)txq)) {
386081be6552SMatt Macy 			skipped++;
386195246abbSSean Bruno 			continue;
386295246abbSSean Bruno 		}
386395246abbSSean Bruno 		err = iflib_encap(txq, mp);
386495246abbSSean Bruno 		if (__predict_false(err)) {
3865da69b8f9SSean Bruno 			/* no room - bail out */
386695246abbSSean Bruno 			if (err == ENOBUFS)
38674c7070dbSScott Long 				break;
386881be6552SMatt Macy 			skipped++;
3869da69b8f9SSean Bruno 			/* we can't send this packet - skip it */
38704c7070dbSScott Long 			continue;
3871da69b8f9SSean Bruno 		}
38724c7070dbSScott Long 		pkt_sent++;
38734c7070dbSScott Long 		m = *mp;
38744c7070dbSScott Long 		DBG_COUNTER_INC(tx_sent);
38754c7070dbSScott Long 		bytes_sent += m->m_pkthdr.len;
387695246abbSSean Bruno 		mcast_sent += !!(m->m_flags & M_MCAST);
38774c7070dbSScott Long 
387895246abbSSean Bruno 		if (__predict_false(!(ifp->if_drv_flags & IFF_DRV_RUNNING)))
38794c7070dbSScott Long 			break;
388081be6552SMatt Macy 		ETHER_BPF_MTAP(ifp, m);
388181be6552SMatt Macy 		rang = iflib_txd_db_check(txq, false);
38824c7070dbSScott Long 	}
38834c7070dbSScott Long 
388495246abbSSean Bruno 	/* deliberate use of bitwise or to avoid gratuitous short-circuit */
388581be6552SMatt Macy 	ring = rang ? false  : (iflib_min_tx_latency | err);
388681be6552SMatt Macy 	iflib_txd_db_check(txq, ring);
38874c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_OBYTES, bytes_sent);
38884c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_OPACKETS, pkt_sent);
38894c7070dbSScott Long 	if (mcast_sent)
38904c7070dbSScott Long 		if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast_sent);
3891da69b8f9SSean Bruno #ifdef INVARIANTS
3892da69b8f9SSean Bruno 	if (iflib_verbose_debug)
389381be6552SMatt Macy 		printf("consumed=%d\n", skipped + pkt_sent);
3894da69b8f9SSean Bruno #endif
389581be6552SMatt Macy 	return (skipped + pkt_sent);
38964c7070dbSScott Long }
38974c7070dbSScott Long 
3898da69b8f9SSean Bruno static uint32_t
3899da69b8f9SSean Bruno iflib_txq_drain_always(struct ifmp_ring *r)
3900da69b8f9SSean Bruno {
3901da69b8f9SSean Bruno 	return (1);
3902da69b8f9SSean Bruno }
3903da69b8f9SSean Bruno 
3904da69b8f9SSean Bruno static uint32_t
3905da69b8f9SSean Bruno iflib_txq_drain_free(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
3906da69b8f9SSean Bruno {
3907da69b8f9SSean Bruno 	int i, avail;
3908da69b8f9SSean Bruno 	struct mbuf **mp;
3909da69b8f9SSean Bruno 	iflib_txq_t txq;
3910da69b8f9SSean Bruno 
3911da69b8f9SSean Bruno 	txq = r->cookie;
3912da69b8f9SSean Bruno 
3913da69b8f9SSean Bruno 	txq->ift_qstatus = IFLIB_QUEUE_IDLE;
3914da69b8f9SSean Bruno 	CALLOUT_LOCK(txq);
3915da69b8f9SSean Bruno 	callout_stop(&txq->ift_timer);
3916da69b8f9SSean Bruno 	CALLOUT_UNLOCK(txq);
3917da69b8f9SSean Bruno 
3918da69b8f9SSean Bruno 	avail = IDXDIFF(pidx, cidx, r->size);
3919da69b8f9SSean Bruno 	for (i = 0; i < avail; i++) {
392095246abbSSean Bruno 		mp = _ring_peek_one(r, cidx, i, avail - i);
392195246abbSSean Bruno 		if (__predict_false(*mp == (struct mbuf *)txq))
392295246abbSSean Bruno 			continue;
3923da69b8f9SSean Bruno 		m_freem(*mp);
392464e6fc13SStephen Hurd 		DBG_COUNTER_INC(tx_frees);
3925da69b8f9SSean Bruno 	}
3926da69b8f9SSean Bruno 	MPASS(ifmp_ring_is_stalled(r) == 0);
3927da69b8f9SSean Bruno 	return (avail);
3928da69b8f9SSean Bruno }
3929da69b8f9SSean Bruno 
3930da69b8f9SSean Bruno static void
3931da69b8f9SSean Bruno iflib_ifmp_purge(iflib_txq_t txq)
3932da69b8f9SSean Bruno {
3933da69b8f9SSean Bruno 	struct ifmp_ring *r;
3934da69b8f9SSean Bruno 
393595246abbSSean Bruno 	r = txq->ift_br;
3936da69b8f9SSean Bruno 	r->drain = iflib_txq_drain_free;
3937da69b8f9SSean Bruno 	r->can_drain = iflib_txq_drain_always;
3938da69b8f9SSean Bruno 
3939da69b8f9SSean Bruno 	ifmp_ring_check_drainage(r, r->size);
3940da69b8f9SSean Bruno 
3941da69b8f9SSean Bruno 	r->drain = iflib_txq_drain;
3942da69b8f9SSean Bruno 	r->can_drain = iflib_txq_can_drain;
3943da69b8f9SSean Bruno }
3944da69b8f9SSean Bruno 
39454c7070dbSScott Long static void
394623ac9029SStephen Hurd _task_fn_tx(void *context)
39474c7070dbSScott Long {
39484c7070dbSScott Long 	iflib_txq_t txq = context;
39494c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
3950a6611c93SMarius Strobl 	if_t ifp = ctx->ifc_ifp;
3951fe51d4cdSStephen Hurd 	int abdicate = ctx->ifc_sysctl_tx_abdicate;
39524c7070dbSScott Long 
39531248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
39541248952aSSean Bruno 	txq->ift_cpu_exec_count[curcpu]++;
39551248952aSSean Bruno #endif
395688a68866SVincenzo Maffione 	if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
39574c7070dbSScott Long 		return;
395895dcf343SMarius Strobl #ifdef DEV_NETMAP
395988a68866SVincenzo Maffione 	if ((if_getcapenable(ifp) & IFCAP_NETMAP) &&
396088a68866SVincenzo Maffione 	    netmap_tx_irq(ifp, txq->ift_id))
396188a68866SVincenzo Maffione 		goto skip_ifmp;
396295dcf343SMarius Strobl #endif
3963b8ca4756SPatrick Kelsey #ifdef ALTQ
3964b8ca4756SPatrick Kelsey 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
3965b8ca4756SPatrick Kelsey 		iflib_altq_if_start(ifp);
3966b8ca4756SPatrick Kelsey #endif
396795246abbSSean Bruno 	if (txq->ift_db_pending)
3968fe51d4cdSStephen Hurd 		ifmp_ring_enqueue(txq->ift_br, (void **)&txq, 1, TX_BATCH_SIZE, abdicate);
3969fe51d4cdSStephen Hurd 	else if (!abdicate)
3970fe51d4cdSStephen Hurd 		ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
3971fe51d4cdSStephen Hurd 	/*
3972fe51d4cdSStephen Hurd 	 * When abdicating, we always need to check drainage, not just when we don't enqueue
3973fe51d4cdSStephen Hurd 	 */
3974fe51d4cdSStephen Hurd 	if (abdicate)
3975fe51d4cdSStephen Hurd 		ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
397688a68866SVincenzo Maffione #ifdef DEV_NETMAP
397788a68866SVincenzo Maffione skip_ifmp:
397888a68866SVincenzo Maffione #endif
397995246abbSSean Bruno 	if (ctx->ifc_flags & IFC_LEGACY)
398095246abbSSean Bruno 		IFDI_INTR_ENABLE(ctx);
39813d10e9edSMarius Strobl 	else
39821ae4848cSMatt Macy 		IFDI_TX_QUEUE_INTR_ENABLE(ctx, txq->ift_id);
39834c7070dbSScott Long }
39844c7070dbSScott Long 
39854c7070dbSScott Long static void
398623ac9029SStephen Hurd _task_fn_rx(void *context)
39874c7070dbSScott Long {
39884c7070dbSScott Long 	iflib_rxq_t rxq = context;
39894c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
3990fb1a29b4SHans Petter Selasky 	uint8_t more;
3991f4d2154eSStephen Hurd 	uint16_t budget;
3992e136e9c8SVincenzo Maffione #ifdef DEV_NETMAP
3993e136e9c8SVincenzo Maffione 	u_int work = 0;
3994e136e9c8SVincenzo Maffione 	int nmirq;
3995e136e9c8SVincenzo Maffione #endif
39964c7070dbSScott Long 
39971248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
39981248952aSSean Bruno 	rxq->ifr_cpu_exec_count[curcpu]++;
39991248952aSSean Bruno #endif
40004c7070dbSScott Long 	DBG_COUNTER_INC(task_fn_rxs);
40014c7070dbSScott Long 	if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
40024c7070dbSScott Long 		return;
4003d0d0ad0aSStephen Hurd #ifdef DEV_NETMAP
4004e136e9c8SVincenzo Maffione 	nmirq = netmap_rx_irq(ctx->ifc_ifp, rxq->ifr_id, &work);
4005e136e9c8SVincenzo Maffione 	if (nmirq != NM_IRQ_PASS) {
4006e136e9c8SVincenzo Maffione 		more = (nmirq == NM_IRQ_RESCHED) ? IFLIB_RXEOF_MORE : 0;
4007fb1a29b4SHans Petter Selasky 		goto skip_rxeof;
4008d0d0ad0aSStephen Hurd 	}
4009d0d0ad0aSStephen Hurd #endif
4010f4d2154eSStephen Hurd 	budget = ctx->ifc_sysctl_rx_budget;
4011f4d2154eSStephen Hurd 	if (budget == 0)
4012f4d2154eSStephen Hurd 		budget = 16;	/* XXX */
4013fb1a29b4SHans Petter Selasky 	more = iflib_rxeof(rxq, budget);
4014fb1a29b4SHans Petter Selasky #ifdef DEV_NETMAP
4015fb1a29b4SHans Petter Selasky skip_rxeof:
4016fb1a29b4SHans Petter Selasky #endif
4017fb1a29b4SHans Petter Selasky 	if ((more & IFLIB_RXEOF_MORE) == 0) {
40184c7070dbSScott Long 		if (ctx->ifc_flags & IFC_LEGACY)
40194c7070dbSScott Long 			IFDI_INTR_ENABLE(ctx);
40203d10e9edSMarius Strobl 		else
40211ae4848cSMatt Macy 			IFDI_RX_QUEUE_INTR_ENABLE(ctx, rxq->ifr_id);
40221ae4848cSMatt Macy 		DBG_COUNTER_INC(rx_intr_enables);
40234c7070dbSScott Long 	}
40244c7070dbSScott Long 	if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
40254c7070dbSScott Long 		return;
4026fb1a29b4SHans Petter Selasky 
4027fb1a29b4SHans Petter Selasky 	if (more & IFLIB_RXEOF_MORE)
40284c7070dbSScott Long 		GROUPTASK_ENQUEUE(&rxq->ifr_task);
4029fb1a29b4SHans Petter Selasky 	else if (more & IFLIB_RXEOF_EMPTY)
4030fb1a29b4SHans Petter Selasky 		callout_reset_curcpu(&rxq->ifr_watchdog, 1, &_task_fn_rx_watchdog, rxq);
40314c7070dbSScott Long }
40324c7070dbSScott Long 
40334c7070dbSScott Long static void
403423ac9029SStephen Hurd _task_fn_admin(void *context)
40354c7070dbSScott Long {
40364c7070dbSScott Long 	if_ctx_t ctx = context;
40374c7070dbSScott Long 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
40384c7070dbSScott Long 	iflib_txq_t txq;
4039ab2e3f79SStephen Hurd 	int i;
404077c1fcecSEric Joyner 	bool oactive, running, do_reset, do_watchdog, in_detach;
4041ab2e3f79SStephen Hurd 
40427b610b60SSean Bruno 	STATE_LOCK(ctx);
40437b610b60SSean Bruno 	running = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING);
40447b610b60SSean Bruno 	oactive = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE);
40457b610b60SSean Bruno 	do_reset = (ctx->ifc_flags & IFC_DO_RESET);
40467b610b60SSean Bruno 	do_watchdog = (ctx->ifc_flags & IFC_DO_WATCHDOG);
404777c1fcecSEric Joyner 	in_detach = (ctx->ifc_flags & IFC_IN_DETACH);
40487b610b60SSean Bruno 	ctx->ifc_flags &= ~(IFC_DO_RESET|IFC_DO_WATCHDOG);
40497b610b60SSean Bruno 	STATE_UNLOCK(ctx);
40507b610b60SSean Bruno 
405177c1fcecSEric Joyner 	if ((!running && !oactive) && !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
405277c1fcecSEric Joyner 		return;
405377c1fcecSEric Joyner 	if (in_detach)
4054ab2e3f79SStephen Hurd 		return;
40554c7070dbSScott Long 
40564c7070dbSScott Long 	CTX_LOCK(ctx);
40574c7070dbSScott Long 	for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) {
40584c7070dbSScott Long 		CALLOUT_LOCK(txq);
40594c7070dbSScott Long 		callout_stop(&txq->ift_timer);
40604c7070dbSScott Long 		CALLOUT_UNLOCK(txq);
40614c7070dbSScott Long 	}
406209c3f04fSMarcin Wojtas 	if (ctx->ifc_sctx->isc_flags & IFLIB_HAS_ADMINCQ)
406309c3f04fSMarcin Wojtas 		IFDI_ADMIN_COMPLETION_HANDLE(ctx);
40647b610b60SSean Bruno 	if (do_watchdog) {
40657b610b60SSean Bruno 		ctx->ifc_watchdog_events++;
40667b610b60SSean Bruno 		IFDI_WATCHDOG_RESET(ctx);
40677b610b60SSean Bruno 	}
4068d300df01SStephen Hurd 	IFDI_UPDATE_ADMIN_STATUS(ctx);
4069dd7fbcf1SStephen Hurd 	for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) {
4070*618d49f5SAlexander Motin 		callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer, txq,
4071*618d49f5SAlexander Motin 		    txq->ift_timer.c_cpu);
4072dd7fbcf1SStephen Hurd 	}
4073ab2e3f79SStephen Hurd 	IFDI_LINK_INTR_ENABLE(ctx);
40747b610b60SSean Bruno 	if (do_reset)
4075ab2e3f79SStephen Hurd 		iflib_if_init_locked(ctx);
40764c7070dbSScott Long 	CTX_UNLOCK(ctx);
40774c7070dbSScott Long 
4078ab2e3f79SStephen Hurd 	if (LINK_ACTIVE(ctx) == 0)
40794c7070dbSScott Long 		return;
40804c7070dbSScott Long 	for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++)
40814c7070dbSScott Long 		iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET);
40824c7070dbSScott Long }
40834c7070dbSScott Long 
40844c7070dbSScott Long static void
408523ac9029SStephen Hurd _task_fn_iov(void *context)
40864c7070dbSScott Long {
40874c7070dbSScott Long 	if_ctx_t ctx = context;
40884c7070dbSScott Long 
408977c1fcecSEric Joyner 	if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) &&
409077c1fcecSEric Joyner 	    !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
40914c7070dbSScott Long 		return;
40924c7070dbSScott Long 
40934c7070dbSScott Long 	CTX_LOCK(ctx);
40944c7070dbSScott Long 	IFDI_VFLR_HANDLE(ctx);
40954c7070dbSScott Long 	CTX_UNLOCK(ctx);
40964c7070dbSScott Long }
40974c7070dbSScott Long 
40984c7070dbSScott Long static int
40994c7070dbSScott Long iflib_sysctl_int_delay(SYSCTL_HANDLER_ARGS)
41004c7070dbSScott Long {
41014c7070dbSScott Long 	int err;
41024c7070dbSScott Long 	if_int_delay_info_t info;
41034c7070dbSScott Long 	if_ctx_t ctx;
41044c7070dbSScott Long 
41054c7070dbSScott Long 	info = (if_int_delay_info_t)arg1;
41064c7070dbSScott Long 	ctx = info->iidi_ctx;
41074c7070dbSScott Long 	info->iidi_req = req;
41084c7070dbSScott Long 	info->iidi_oidp = oidp;
41094c7070dbSScott Long 	CTX_LOCK(ctx);
41104c7070dbSScott Long 	err = IFDI_SYSCTL_INT_DELAY(ctx, info);
41114c7070dbSScott Long 	CTX_UNLOCK(ctx);
41124c7070dbSScott Long 	return (err);
41134c7070dbSScott Long }
41144c7070dbSScott Long 
41154c7070dbSScott Long /*********************************************************************
41164c7070dbSScott Long  *
41174c7070dbSScott Long  *  IFNET FUNCTIONS
41184c7070dbSScott Long  *
41194c7070dbSScott Long  **********************************************************************/
41204c7070dbSScott Long 
41214c7070dbSScott Long static void
41224c7070dbSScott Long iflib_if_init_locked(if_ctx_t ctx)
41234c7070dbSScott Long {
41244c7070dbSScott Long 	iflib_stop(ctx);
41254c7070dbSScott Long 	iflib_init_locked(ctx);
41264c7070dbSScott Long }
41274c7070dbSScott Long 
41284c7070dbSScott Long static void
41294c7070dbSScott Long iflib_if_init(void *arg)
41304c7070dbSScott Long {
41314c7070dbSScott Long 	if_ctx_t ctx = arg;
41324c7070dbSScott Long 
41334c7070dbSScott Long 	CTX_LOCK(ctx);
41344c7070dbSScott Long 	iflib_if_init_locked(ctx);
41354c7070dbSScott Long 	CTX_UNLOCK(ctx);
41364c7070dbSScott Long }
41374c7070dbSScott Long 
41384c7070dbSScott Long static int
41394c7070dbSScott Long iflib_if_transmit(if_t ifp, struct mbuf *m)
41404c7070dbSScott Long {
41414c7070dbSScott Long 	if_ctx_t	ctx = if_getsoftc(ifp);
41424c7070dbSScott Long 
41434c7070dbSScott Long 	iflib_txq_t txq;
414423ac9029SStephen Hurd 	int err, qidx;
4145fe51d4cdSStephen Hurd 	int abdicate = ctx->ifc_sysctl_tx_abdicate;
41464c7070dbSScott Long 
41474c7070dbSScott Long 	if (__predict_false((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || !LINK_ACTIVE(ctx))) {
41484c7070dbSScott Long 		DBG_COUNTER_INC(tx_frees);
41494c7070dbSScott Long 		m_freem(m);
4150225eae1bSEric Joyner 		return (ENETDOWN);
41514c7070dbSScott Long 	}
41524c7070dbSScott Long 
415323ac9029SStephen Hurd 	MPASS(m->m_nextpkt == NULL);
4154b8ca4756SPatrick Kelsey 	/* ALTQ-enabled interfaces always use queue 0. */
41554c7070dbSScott Long 	qidx = 0;
4156b8ca4756SPatrick Kelsey 	if ((NTXQSETS(ctx) > 1) && M_HASHTYPE_GET(m) && !ALTQ_IS_ENABLED(&ifp->if_snd))
41574c7070dbSScott Long 		qidx = QIDX(ctx, m);
41584c7070dbSScott Long 	/*
41594c7070dbSScott Long 	 * XXX calculate buf_ring based on flowid (divvy up bits?)
41604c7070dbSScott Long 	 */
41614c7070dbSScott Long 	txq = &ctx->ifc_txqs[qidx];
41624c7070dbSScott Long 
41634c7070dbSScott Long #ifdef DRIVER_BACKPRESSURE
41644c7070dbSScott Long 	if (txq->ift_closed) {
41654c7070dbSScott Long 		while (m != NULL) {
41664c7070dbSScott Long 			next = m->m_nextpkt;
41674c7070dbSScott Long 			m->m_nextpkt = NULL;
41684c7070dbSScott Long 			m_freem(m);
416964e6fc13SStephen Hurd 			DBG_COUNTER_INC(tx_frees);
41704c7070dbSScott Long 			m = next;
41714c7070dbSScott Long 		}
41724c7070dbSScott Long 		return (ENOBUFS);
41734c7070dbSScott Long 	}
41744c7070dbSScott Long #endif
417523ac9029SStephen Hurd #ifdef notyet
41764c7070dbSScott Long 	qidx = count = 0;
41774c7070dbSScott Long 	mp = marr;
41784c7070dbSScott Long 	next = m;
41794c7070dbSScott Long 	do {
41804c7070dbSScott Long 		count++;
41814c7070dbSScott Long 		next = next->m_nextpkt;
41824c7070dbSScott Long 	} while (next != NULL);
41834c7070dbSScott Long 
418416fb86abSConrad Meyer 	if (count > nitems(marr))
41854c7070dbSScott Long 		if ((mp = malloc(count*sizeof(struct mbuf *), M_IFLIB, M_NOWAIT)) == NULL) {
41864c7070dbSScott Long 			/* XXX check nextpkt */
41874c7070dbSScott Long 			m_freem(m);
41884c7070dbSScott Long 			/* XXX simplify for now */
41894c7070dbSScott Long 			DBG_COUNTER_INC(tx_frees);
41904c7070dbSScott Long 			return (ENOBUFS);
41914c7070dbSScott Long 		}
41924c7070dbSScott Long 	for (next = m, i = 0; next != NULL; i++) {
41934c7070dbSScott Long 		mp[i] = next;
41944c7070dbSScott Long 		next = next->m_nextpkt;
41954c7070dbSScott Long 		mp[i]->m_nextpkt = NULL;
41964c7070dbSScott Long 	}
419723ac9029SStephen Hurd #endif
41984c7070dbSScott Long 	DBG_COUNTER_INC(tx_seen);
4199fe51d4cdSStephen Hurd 	err = ifmp_ring_enqueue(txq->ift_br, (void **)&m, 1, TX_BATCH_SIZE, abdicate);
42004c7070dbSScott Long 
4201fe51d4cdSStephen Hurd 	if (abdicate)
4202ab2e3f79SStephen Hurd 		GROUPTASK_ENQUEUE(&txq->ift_task);
42031225d9daSStephen Hurd  	if (err) {
4204fe51d4cdSStephen Hurd 		if (!abdicate)
4205fe51d4cdSStephen Hurd 			GROUPTASK_ENQUEUE(&txq->ift_task);
42064c7070dbSScott Long 		/* support forthcoming later */
42074c7070dbSScott Long #ifdef DRIVER_BACKPRESSURE
42084c7070dbSScott Long 		txq->ift_closed = TRUE;
42094c7070dbSScott Long #endif
421095246abbSSean Bruno 		ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
421123ac9029SStephen Hurd 		m_freem(m);
421264e6fc13SStephen Hurd 		DBG_COUNTER_INC(tx_frees);
42134c7070dbSScott Long 	}
42144c7070dbSScott Long 
42154c7070dbSScott Long 	return (err);
42164c7070dbSScott Long }
42174c7070dbSScott Long 
4218b8ca4756SPatrick Kelsey #ifdef ALTQ
4219b8ca4756SPatrick Kelsey /*
4220b8ca4756SPatrick Kelsey  * The overall approach to integrating iflib with ALTQ is to continue to use
4221b8ca4756SPatrick Kelsey  * the iflib mp_ring machinery between the ALTQ queue(s) and the hardware
4222b8ca4756SPatrick Kelsey  * ring.  Technically, when using ALTQ, queueing to an intermediate mp_ring
4223b8ca4756SPatrick Kelsey  * is redundant/unnecessary, but doing so minimizes the amount of
4224b8ca4756SPatrick Kelsey  * ALTQ-specific code required in iflib.  It is assumed that the overhead of
4225b8ca4756SPatrick Kelsey  * redundantly queueing to an intermediate mp_ring is swamped by the
4226b8ca4756SPatrick Kelsey  * performance limitations inherent in using ALTQ.
4227b8ca4756SPatrick Kelsey  *
4228b8ca4756SPatrick Kelsey  * When ALTQ support is compiled in, all iflib drivers will use a transmit
4229b8ca4756SPatrick Kelsey  * routine, iflib_altq_if_transmit(), that checks if ALTQ is enabled for the
4230b8ca4756SPatrick Kelsey  * given interface.  If ALTQ is enabled for an interface, then all
4231b8ca4756SPatrick Kelsey  * transmitted packets for that interface will be submitted to the ALTQ
4232b8ca4756SPatrick Kelsey  * subsystem via IFQ_ENQUEUE().  We don't use the legacy if_transmit()
4233b8ca4756SPatrick Kelsey  * implementation because it uses IFQ_HANDOFF(), which will duplicatively
4234b8ca4756SPatrick Kelsey  * update stats that the iflib machinery handles, and which is sensitve to
4235b8ca4756SPatrick Kelsey  * the disused IFF_DRV_OACTIVE flag.  Additionally, iflib_altq_if_start()
4236b8ca4756SPatrick Kelsey  * will be installed as the start routine for use by ALTQ facilities that
4237b8ca4756SPatrick Kelsey  * need to trigger queue drains on a scheduled basis.
4238b8ca4756SPatrick Kelsey  *
4239b8ca4756SPatrick Kelsey  */
4240b8ca4756SPatrick Kelsey static void
4241b8ca4756SPatrick Kelsey iflib_altq_if_start(if_t ifp)
4242b8ca4756SPatrick Kelsey {
4243b8ca4756SPatrick Kelsey 	struct ifaltq *ifq = &ifp->if_snd;
4244b8ca4756SPatrick Kelsey 	struct mbuf *m;
4245b8ca4756SPatrick Kelsey 
4246b8ca4756SPatrick Kelsey 	IFQ_LOCK(ifq);
4247b8ca4756SPatrick Kelsey 	IFQ_DEQUEUE_NOLOCK(ifq, m);
4248b8ca4756SPatrick Kelsey 	while (m != NULL) {
4249b8ca4756SPatrick Kelsey 		iflib_if_transmit(ifp, m);
4250b8ca4756SPatrick Kelsey 		IFQ_DEQUEUE_NOLOCK(ifq, m);
4251b8ca4756SPatrick Kelsey 	}
4252b8ca4756SPatrick Kelsey 	IFQ_UNLOCK(ifq);
4253b8ca4756SPatrick Kelsey }
4254b8ca4756SPatrick Kelsey 
4255b8ca4756SPatrick Kelsey static int
4256b8ca4756SPatrick Kelsey iflib_altq_if_transmit(if_t ifp, struct mbuf *m)
4257b8ca4756SPatrick Kelsey {
4258b8ca4756SPatrick Kelsey 	int err;
4259b8ca4756SPatrick Kelsey 
4260b8ca4756SPatrick Kelsey 	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
4261b8ca4756SPatrick Kelsey 		IFQ_ENQUEUE(&ifp->if_snd, m, err);
4262b8ca4756SPatrick Kelsey 		if (err == 0)
4263b8ca4756SPatrick Kelsey 			iflib_altq_if_start(ifp);
4264b8ca4756SPatrick Kelsey 	} else
4265b8ca4756SPatrick Kelsey 		err = iflib_if_transmit(ifp, m);
4266b8ca4756SPatrick Kelsey 
4267b8ca4756SPatrick Kelsey 	return (err);
4268b8ca4756SPatrick Kelsey }
4269b8ca4756SPatrick Kelsey #endif /* ALTQ */
4270b8ca4756SPatrick Kelsey 
42714c7070dbSScott Long static void
42724c7070dbSScott Long iflib_if_qflush(if_t ifp)
42734c7070dbSScott Long {
42744c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
42754c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
42764c7070dbSScott Long 	int i;
42774c7070dbSScott Long 
42787b610b60SSean Bruno 	STATE_LOCK(ctx);
42794c7070dbSScott Long 	ctx->ifc_flags |= IFC_QFLUSH;
42807b610b60SSean Bruno 	STATE_UNLOCK(ctx);
42814c7070dbSScott Long 	for (i = 0; i < NTXQSETS(ctx); i++, txq++)
428295246abbSSean Bruno 		while (!(ifmp_ring_is_idle(txq->ift_br) || ifmp_ring_is_stalled(txq->ift_br)))
42834c7070dbSScott Long 			iflib_txq_check_drain(txq, 0);
42847b610b60SSean Bruno 	STATE_LOCK(ctx);
42854c7070dbSScott Long 	ctx->ifc_flags &= ~IFC_QFLUSH;
42867b610b60SSean Bruno 	STATE_UNLOCK(ctx);
42874c7070dbSScott Long 
4288b8ca4756SPatrick Kelsey 	/*
4289b8ca4756SPatrick Kelsey 	 * When ALTQ is enabled, this will also take care of purging the
4290b8ca4756SPatrick Kelsey 	 * ALTQ queue(s).
4291b8ca4756SPatrick Kelsey 	 */
42924c7070dbSScott Long 	if_qflush(ifp);
42934c7070dbSScott Long }
42944c7070dbSScott Long 
42950c919c23SStephen Hurd #define IFCAP_FLAGS (IFCAP_HWCSUM_IPV6 | IFCAP_HWCSUM | IFCAP_LRO | \
42960c919c23SStephen Hurd 		     IFCAP_TSO | IFCAP_VLAN_HWTAGGING | IFCAP_HWSTATS | \
42970c919c23SStephen Hurd 		     IFCAP_VLAN_MTU | IFCAP_VLAN_HWFILTER | \
42983f43ada9SGleb Smirnoff 		     IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM | IFCAP_MEXTPG)
42994c7070dbSScott Long 
43004c7070dbSScott Long static int
43014c7070dbSScott Long iflib_if_ioctl(if_t ifp, u_long command, caddr_t data)
43024c7070dbSScott Long {
43034c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
43044c7070dbSScott Long 	struct ifreq	*ifr = (struct ifreq *)data;
43054c7070dbSScott Long #if defined(INET) || defined(INET6)
43064c7070dbSScott Long 	struct ifaddr	*ifa = (struct ifaddr *)data;
43074c7070dbSScott Long #endif
43081722eeacSMarius Strobl 	bool		avoid_reset = false;
43094c7070dbSScott Long 	int		err = 0, reinit = 0, bits;
43104c7070dbSScott Long 
43114c7070dbSScott Long 	switch (command) {
43124c7070dbSScott Long 	case SIOCSIFADDR:
43134c7070dbSScott Long #ifdef INET
43144c7070dbSScott Long 		if (ifa->ifa_addr->sa_family == AF_INET)
43151722eeacSMarius Strobl 			avoid_reset = true;
43164c7070dbSScott Long #endif
43174c7070dbSScott Long #ifdef INET6
43184c7070dbSScott Long 		if (ifa->ifa_addr->sa_family == AF_INET6)
43191722eeacSMarius Strobl 			avoid_reset = true;
43204c7070dbSScott Long #endif
43214c7070dbSScott Long 		/*
43224c7070dbSScott Long 		** Calling init results in link renegotiation,
43234c7070dbSScott Long 		** so we avoid doing it when possible.
43244c7070dbSScott Long 		*/
43254c7070dbSScott Long 		if (avoid_reset) {
43264c7070dbSScott Long 			if_setflagbits(ifp, IFF_UP,0);
43274c7070dbSScott Long 			if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
43284c7070dbSScott Long 				reinit = 1;
43294c7070dbSScott Long #ifdef INET
43304c7070dbSScott Long 			if (!(if_getflags(ifp) & IFF_NOARP))
43314c7070dbSScott Long 				arp_ifinit(ifp, ifa);
43324c7070dbSScott Long #endif
43334c7070dbSScott Long 		} else
43344c7070dbSScott Long 			err = ether_ioctl(ifp, command, data);
43354c7070dbSScott Long 		break;
43364c7070dbSScott Long 	case SIOCSIFMTU:
43374c7070dbSScott Long 		CTX_LOCK(ctx);
43384c7070dbSScott Long 		if (ifr->ifr_mtu == if_getmtu(ifp)) {
43394c7070dbSScott Long 			CTX_UNLOCK(ctx);
43404c7070dbSScott Long 			break;
43414c7070dbSScott Long 		}
43424c7070dbSScott Long 		bits = if_getdrvflags(ifp);
43434c7070dbSScott Long 		/* stop the driver and free any clusters before proceeding */
43444c7070dbSScott Long 		iflib_stop(ctx);
43454c7070dbSScott Long 
43464c7070dbSScott Long 		if ((err = IFDI_MTU_SET(ctx, ifr->ifr_mtu)) == 0) {
43477b610b60SSean Bruno 			STATE_LOCK(ctx);
43484c7070dbSScott Long 			if (ifr->ifr_mtu > ctx->ifc_max_fl_buf_size)
43494c7070dbSScott Long 				ctx->ifc_flags |= IFC_MULTISEG;
43504c7070dbSScott Long 			else
43514c7070dbSScott Long 				ctx->ifc_flags &= ~IFC_MULTISEG;
43527b610b60SSean Bruno 			STATE_UNLOCK(ctx);
43534c7070dbSScott Long 			err = if_setmtu(ifp, ifr->ifr_mtu);
43544c7070dbSScott Long 		}
43554c7070dbSScott Long 		iflib_init_locked(ctx);
43567b610b60SSean Bruno 		STATE_LOCK(ctx);
43574c7070dbSScott Long 		if_setdrvflags(ifp, bits);
43587b610b60SSean Bruno 		STATE_UNLOCK(ctx);
43594c7070dbSScott Long 		CTX_UNLOCK(ctx);
43604c7070dbSScott Long 		break;
43614c7070dbSScott Long 	case SIOCSIFFLAGS:
4362ab2e3f79SStephen Hurd 		CTX_LOCK(ctx);
4363ab2e3f79SStephen Hurd 		if (if_getflags(ifp) & IFF_UP) {
4364ab2e3f79SStephen Hurd 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4365ab2e3f79SStephen Hurd 				if ((if_getflags(ifp) ^ ctx->ifc_if_flags) &
4366ab2e3f79SStephen Hurd 				    (IFF_PROMISC | IFF_ALLMULTI)) {
43670ae0e8d2SMatt Macy 					CTX_UNLOCK(ctx);
4368ab2e3f79SStephen Hurd 					err = IFDI_PROMISC_SET(ctx, if_getflags(ifp));
43690ae0e8d2SMatt Macy 					CTX_LOCK(ctx);
4370ab2e3f79SStephen Hurd 				}
4371ab2e3f79SStephen Hurd 			} else
4372ab2e3f79SStephen Hurd 				reinit = 1;
4373ab2e3f79SStephen Hurd 		} else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4374ab2e3f79SStephen Hurd 			iflib_stop(ctx);
4375ab2e3f79SStephen Hurd 		}
4376ab2e3f79SStephen Hurd 		ctx->ifc_if_flags = if_getflags(ifp);
4377ab2e3f79SStephen Hurd 		CTX_UNLOCK(ctx);
43784c7070dbSScott Long 		break;
43794c7070dbSScott Long 	case SIOCADDMULTI:
43804c7070dbSScott Long 	case SIOCDELMULTI:
43814c7070dbSScott Long 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4382ab2e3f79SStephen Hurd 			CTX_LOCK(ctx);
4383ab2e3f79SStephen Hurd 			IFDI_INTR_DISABLE(ctx);
4384ab2e3f79SStephen Hurd 			IFDI_MULTI_SET(ctx);
4385ab2e3f79SStephen Hurd 			IFDI_INTR_ENABLE(ctx);
4386ab2e3f79SStephen Hurd 			CTX_UNLOCK(ctx);
43874c7070dbSScott Long 		}
43884c7070dbSScott Long 		break;
43894c7070dbSScott Long 	case SIOCSIFMEDIA:
43904c7070dbSScott Long 		CTX_LOCK(ctx);
43914c7070dbSScott Long 		IFDI_MEDIA_SET(ctx);
43924c7070dbSScott Long 		CTX_UNLOCK(ctx);
43931722eeacSMarius Strobl 		/* FALLTHROUGH */
43944c7070dbSScott Long 	case SIOCGIFMEDIA:
4395a027c8e9SStephen Hurd 	case SIOCGIFXMEDIA:
4396e2621d96SMatt Macy 		err = ifmedia_ioctl(ifp, ifr, ctx->ifc_mediap, command);
43974c7070dbSScott Long 		break;
43984c7070dbSScott Long 	case SIOCGI2C:
43994c7070dbSScott Long 	{
44004c7070dbSScott Long 		struct ifi2creq i2c;
44014c7070dbSScott Long 
4402541d96aaSBrooks Davis 		err = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c));
44034c7070dbSScott Long 		if (err != 0)
44044c7070dbSScott Long 			break;
44054c7070dbSScott Long 		if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) {
44064c7070dbSScott Long 			err = EINVAL;
44074c7070dbSScott Long 			break;
44084c7070dbSScott Long 		}
44094c7070dbSScott Long 		if (i2c.len > sizeof(i2c.data)) {
44104c7070dbSScott Long 			err = EINVAL;
44114c7070dbSScott Long 			break;
44124c7070dbSScott Long 		}
44134c7070dbSScott Long 
44144c7070dbSScott Long 		if ((err = IFDI_I2C_REQ(ctx, &i2c)) == 0)
4415541d96aaSBrooks Davis 			err = copyout(&i2c, ifr_data_get_ptr(ifr),
4416541d96aaSBrooks Davis 			    sizeof(i2c));
44174c7070dbSScott Long 		break;
44184c7070dbSScott Long 	}
44194c7070dbSScott Long 	case SIOCSIFCAP:
44204c7070dbSScott Long 	{
44210c919c23SStephen Hurd 		int mask, setmask, oldmask;
44224c7070dbSScott Long 
44230c919c23SStephen Hurd 		oldmask = if_getcapenable(ifp);
44240c919c23SStephen Hurd 		mask = ifr->ifr_reqcap ^ oldmask;
44253f43ada9SGleb Smirnoff 		mask &= ctx->ifc_softc_ctx.isc_capabilities | IFCAP_MEXTPG;
44264c7070dbSScott Long 		setmask = 0;
44274c7070dbSScott Long #ifdef TCP_OFFLOAD
44284c7070dbSScott Long 		setmask |= mask & (IFCAP_TOE4|IFCAP_TOE6);
44294c7070dbSScott Long #endif
44304c7070dbSScott Long 		setmask |= (mask & IFCAP_FLAGS);
44310c919c23SStephen Hurd 		setmask |= (mask & IFCAP_WOL);
44324c7070dbSScott Long 
44330c919c23SStephen Hurd 		/*
4434a42546dfSStephen Hurd 		 * If any RX csum has changed, change all the ones that
4435a42546dfSStephen Hurd 		 * are supported by the driver.
44360c919c23SStephen Hurd 		 */
4437a42546dfSStephen Hurd 		if (setmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) {
4438a42546dfSStephen Hurd 			setmask |= ctx->ifc_softc_ctx.isc_capabilities &
4439a42546dfSStephen Hurd 			    (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6);
4440a42546dfSStephen Hurd 		}
44410c919c23SStephen Hurd 
44424c7070dbSScott Long 		/*
44434c7070dbSScott Long 		 * want to ensure that traffic has stopped before we change any of the flags
44444c7070dbSScott Long 		 */
44454c7070dbSScott Long 		if (setmask) {
44464c7070dbSScott Long 			CTX_LOCK(ctx);
44474c7070dbSScott Long 			bits = if_getdrvflags(ifp);
44480c919c23SStephen Hurd 			if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL)
44494c7070dbSScott Long 				iflib_stop(ctx);
44507b610b60SSean Bruno 			STATE_LOCK(ctx);
44514c7070dbSScott Long 			if_togglecapenable(ifp, setmask);
44524561c4f0SVincenzo Maffione 			ctx->ifc_softc_ctx.isc_capenable ^= setmask;
44537b610b60SSean Bruno 			STATE_UNLOCK(ctx);
44540c919c23SStephen Hurd 			if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL)
44554c7070dbSScott Long 				iflib_init_locked(ctx);
44567b610b60SSean Bruno 			STATE_LOCK(ctx);
44574c7070dbSScott Long 			if_setdrvflags(ifp, bits);
44587b610b60SSean Bruno 			STATE_UNLOCK(ctx);
44594c7070dbSScott Long 			CTX_UNLOCK(ctx);
44604c7070dbSScott Long 		}
44610c919c23SStephen Hurd 		if_vlancap(ifp);
44624c7070dbSScott Long 		break;
44634c7070dbSScott Long 	}
44644c7070dbSScott Long 	case SIOCGPRIVATE_0:
44654c7070dbSScott Long 	case SIOCSDRVSPEC:
44664c7070dbSScott Long 	case SIOCGDRVSPEC:
44674c7070dbSScott Long 		CTX_LOCK(ctx);
44684c7070dbSScott Long 		err = IFDI_PRIV_IOCTL(ctx, command, data);
44694c7070dbSScott Long 		CTX_UNLOCK(ctx);
44704c7070dbSScott Long 		break;
44714c7070dbSScott Long 	default:
44724c7070dbSScott Long 		err = ether_ioctl(ifp, command, data);
44734c7070dbSScott Long 		break;
44744c7070dbSScott Long 	}
44754c7070dbSScott Long 	if (reinit)
44764c7070dbSScott Long 		iflib_if_init(ctx);
44774c7070dbSScott Long 	return (err);
44784c7070dbSScott Long }
44794c7070dbSScott Long 
44804c7070dbSScott Long static uint64_t
44814c7070dbSScott Long iflib_if_get_counter(if_t ifp, ift_counter cnt)
44824c7070dbSScott Long {
44834c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
44844c7070dbSScott Long 
44854c7070dbSScott Long 	return (IFDI_GET_COUNTER(ctx, cnt));
44864c7070dbSScott Long }
44874c7070dbSScott Long 
44884c7070dbSScott Long /*********************************************************************
44894c7070dbSScott Long  *
44904c7070dbSScott Long  *  OTHER FUNCTIONS EXPORTED TO THE STACK
44914c7070dbSScott Long  *
44924c7070dbSScott Long  **********************************************************************/
44934c7070dbSScott Long 
44944c7070dbSScott Long static void
44954c7070dbSScott Long iflib_vlan_register(void *arg, if_t ifp, uint16_t vtag)
44964c7070dbSScott Long {
44974c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
44984c7070dbSScott Long 
44994c7070dbSScott Long 	if ((void *)ctx != arg)
45004c7070dbSScott Long 		return;
45014c7070dbSScott Long 
45024c7070dbSScott Long 	if ((vtag == 0) || (vtag > 4095))
45034c7070dbSScott Long 		return;
45044c7070dbSScott Long 
450553b5b9b0SEric Joyner 	if (iflib_in_detach(ctx))
450653b5b9b0SEric Joyner 		return;
450753b5b9b0SEric Joyner 
45084c7070dbSScott Long 	CTX_LOCK(ctx);
450945818bf1SEric Joyner 	/* Driver may need all untagged packets to be flushed */
451045818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
451145818bf1SEric Joyner 		iflib_stop(ctx);
45124c7070dbSScott Long 	IFDI_VLAN_REGISTER(ctx, vtag);
451345818bf1SEric Joyner 	/* Re-init to load the changes, if required */
451445818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
451545818bf1SEric Joyner 		iflib_init_locked(ctx);
45164c7070dbSScott Long 	CTX_UNLOCK(ctx);
45174c7070dbSScott Long }
45184c7070dbSScott Long 
45194c7070dbSScott Long static void
45204c7070dbSScott Long iflib_vlan_unregister(void *arg, if_t ifp, uint16_t vtag)
45214c7070dbSScott Long {
45224c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
45234c7070dbSScott Long 
45244c7070dbSScott Long 	if ((void *)ctx != arg)
45254c7070dbSScott Long 		return;
45264c7070dbSScott Long 
45274c7070dbSScott Long 	if ((vtag == 0) || (vtag > 4095))
45284c7070dbSScott Long 		return;
45294c7070dbSScott Long 
45304c7070dbSScott Long 	CTX_LOCK(ctx);
453145818bf1SEric Joyner 	/* Driver may need all tagged packets to be flushed */
453245818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
453345818bf1SEric Joyner 		iflib_stop(ctx);
45344c7070dbSScott Long 	IFDI_VLAN_UNREGISTER(ctx, vtag);
453545818bf1SEric Joyner 	/* Re-init to load the changes, if required */
453645818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
453745818bf1SEric Joyner 		iflib_init_locked(ctx);
45384c7070dbSScott Long 	CTX_UNLOCK(ctx);
45394c7070dbSScott Long }
45404c7070dbSScott Long 
45414c7070dbSScott Long static void
45424c7070dbSScott Long iflib_led_func(void *arg, int onoff)
45434c7070dbSScott Long {
45444c7070dbSScott Long 	if_ctx_t ctx = arg;
45454c7070dbSScott Long 
45464c7070dbSScott Long 	CTX_LOCK(ctx);
45474c7070dbSScott Long 	IFDI_LED_FUNC(ctx, onoff);
45484c7070dbSScott Long 	CTX_UNLOCK(ctx);
45494c7070dbSScott Long }
45504c7070dbSScott Long 
45514c7070dbSScott Long /*********************************************************************
45524c7070dbSScott Long  *
45534c7070dbSScott Long  *  BUS FUNCTION DEFINITIONS
45544c7070dbSScott Long  *
45554c7070dbSScott Long  **********************************************************************/
45564c7070dbSScott Long 
45574c7070dbSScott Long int
45584c7070dbSScott Long iflib_device_probe(device_t dev)
45594c7070dbSScott Long {
4560d49e83eaSMarius Strobl 	const pci_vendor_info_t *ent;
45614c7070dbSScott Long 	if_shared_ctx_t sctx;
4562d49e83eaSMarius Strobl 	uint16_t pci_device_id, pci_rev_id, pci_subdevice_id, pci_subvendor_id;
4563d49e83eaSMarius Strobl 	uint16_t pci_vendor_id;
45644c7070dbSScott Long 
45654c7070dbSScott Long 	if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC)
45664c7070dbSScott Long 		return (ENOTSUP);
45674c7070dbSScott Long 
45684c7070dbSScott Long 	pci_vendor_id = pci_get_vendor(dev);
45694c7070dbSScott Long 	pci_device_id = pci_get_device(dev);
45704c7070dbSScott Long 	pci_subvendor_id = pci_get_subvendor(dev);
45714c7070dbSScott Long 	pci_subdevice_id = pci_get_subdevice(dev);
45724c7070dbSScott Long 	pci_rev_id = pci_get_revid(dev);
45734c7070dbSScott Long 	if (sctx->isc_parse_devinfo != NULL)
45744c7070dbSScott Long 		sctx->isc_parse_devinfo(&pci_device_id, &pci_subvendor_id, &pci_subdevice_id, &pci_rev_id);
45754c7070dbSScott Long 
45764c7070dbSScott Long 	ent = sctx->isc_vendor_info;
45774c7070dbSScott Long 	while (ent->pvi_vendor_id != 0) {
45784c7070dbSScott Long 		if (pci_vendor_id != ent->pvi_vendor_id) {
45794c7070dbSScott Long 			ent++;
45804c7070dbSScott Long 			continue;
45814c7070dbSScott Long 		}
45824c7070dbSScott Long 		if ((pci_device_id == ent->pvi_device_id) &&
45834c7070dbSScott Long 		    ((pci_subvendor_id == ent->pvi_subvendor_id) ||
45844c7070dbSScott Long 		     (ent->pvi_subvendor_id == 0)) &&
45854c7070dbSScott Long 		    ((pci_subdevice_id == ent->pvi_subdevice_id) ||
45864c7070dbSScott Long 		     (ent->pvi_subdevice_id == 0)) &&
45874c7070dbSScott Long 		    ((pci_rev_id == ent->pvi_rev_id) ||
45884c7070dbSScott Long 		     (ent->pvi_rev_id == 0))) {
45894c7070dbSScott Long 			device_set_desc_copy(dev, ent->pvi_name);
45904c7070dbSScott Long 			/* this needs to be changed to zero if the bus probing code
45914c7070dbSScott Long 			 * ever stops re-probing on best match because the sctx
45924c7070dbSScott Long 			 * may have its values over written by register calls
45934c7070dbSScott Long 			 * in subsequent probes
45944c7070dbSScott Long 			 */
45954c7070dbSScott Long 			return (BUS_PROBE_DEFAULT);
45964c7070dbSScott Long 		}
45974c7070dbSScott Long 		ent++;
45984c7070dbSScott Long 	}
45994c7070dbSScott Long 	return (ENXIO);
46004c7070dbSScott Long }
46014c7070dbSScott Long 
4602668d6dbbSEric Joyner int
4603668d6dbbSEric Joyner iflib_device_probe_vendor(device_t dev)
4604668d6dbbSEric Joyner {
4605668d6dbbSEric Joyner 	int probe;
4606668d6dbbSEric Joyner 
4607668d6dbbSEric Joyner 	probe = iflib_device_probe(dev);
4608668d6dbbSEric Joyner 	if (probe == BUS_PROBE_DEFAULT)
4609668d6dbbSEric Joyner 		return (BUS_PROBE_VENDOR);
4610668d6dbbSEric Joyner 	else
4611668d6dbbSEric Joyner 		return (probe);
4612668d6dbbSEric Joyner }
4613668d6dbbSEric Joyner 
461409f6ff4fSMatt Macy static void
461509f6ff4fSMatt Macy iflib_reset_qvalues(if_ctx_t ctx)
46164c7070dbSScott Long {
461709f6ff4fSMatt Macy 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
461809f6ff4fSMatt Macy 	if_shared_ctx_t sctx = ctx->ifc_sctx;
461909f6ff4fSMatt Macy 	device_t dev = ctx->ifc_dev;
462046d0f824SMatt Macy 	int i;
46214c7070dbSScott Long 
462223ac9029SStephen Hurd 	if (ctx->ifc_sysctl_ntxqs != 0)
462323ac9029SStephen Hurd 		scctx->isc_ntxqsets = ctx->ifc_sysctl_ntxqs;
462423ac9029SStephen Hurd 	if (ctx->ifc_sysctl_nrxqs != 0)
462523ac9029SStephen Hurd 		scctx->isc_nrxqsets = ctx->ifc_sysctl_nrxqs;
462623ac9029SStephen Hurd 
462723ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_ntxqs; i++) {
462823ac9029SStephen Hurd 		if (ctx->ifc_sysctl_ntxds[i] != 0)
462923ac9029SStephen Hurd 			scctx->isc_ntxd[i] = ctx->ifc_sysctl_ntxds[i];
463023ac9029SStephen Hurd 		else
463123ac9029SStephen Hurd 			scctx->isc_ntxd[i] = sctx->isc_ntxd_default[i];
463223ac9029SStephen Hurd 	}
463323ac9029SStephen Hurd 
463423ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_nrxqs; i++) {
463523ac9029SStephen Hurd 		if (ctx->ifc_sysctl_nrxds[i] != 0)
463623ac9029SStephen Hurd 			scctx->isc_nrxd[i] = ctx->ifc_sysctl_nrxds[i];
463723ac9029SStephen Hurd 		else
463823ac9029SStephen Hurd 			scctx->isc_nrxd[i] = sctx->isc_nrxd_default[i];
463923ac9029SStephen Hurd 	}
464023ac9029SStephen Hurd 
464123ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_nrxqs; i++) {
464223ac9029SStephen Hurd 		if (scctx->isc_nrxd[i] < sctx->isc_nrxd_min[i]) {
464323ac9029SStephen Hurd 			device_printf(dev, "nrxd%d: %d less than nrxd_min %d - resetting to min\n",
464423ac9029SStephen Hurd 				      i, scctx->isc_nrxd[i], sctx->isc_nrxd_min[i]);
464523ac9029SStephen Hurd 			scctx->isc_nrxd[i] = sctx->isc_nrxd_min[i];
464623ac9029SStephen Hurd 		}
464723ac9029SStephen Hurd 		if (scctx->isc_nrxd[i] > sctx->isc_nrxd_max[i]) {
464823ac9029SStephen Hurd 			device_printf(dev, "nrxd%d: %d greater than nrxd_max %d - resetting to max\n",
464923ac9029SStephen Hurd 				      i, scctx->isc_nrxd[i], sctx->isc_nrxd_max[i]);
465023ac9029SStephen Hurd 			scctx->isc_nrxd[i] = sctx->isc_nrxd_max[i];
465123ac9029SStephen Hurd 		}
4652afb77372SEric Joyner 		if (!powerof2(scctx->isc_nrxd[i])) {
4653afb77372SEric Joyner 			device_printf(dev, "nrxd%d: %d is not a power of 2 - using default value of %d\n",
4654afb77372SEric Joyner 				      i, scctx->isc_nrxd[i], sctx->isc_nrxd_default[i]);
4655afb77372SEric Joyner 			scctx->isc_nrxd[i] = sctx->isc_nrxd_default[i];
4656afb77372SEric Joyner 		}
465723ac9029SStephen Hurd 	}
465823ac9029SStephen Hurd 
465923ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_ntxqs; i++) {
466023ac9029SStephen Hurd 		if (scctx->isc_ntxd[i] < sctx->isc_ntxd_min[i]) {
466123ac9029SStephen Hurd 			device_printf(dev, "ntxd%d: %d less than ntxd_min %d - resetting to min\n",
466223ac9029SStephen Hurd 				      i, scctx->isc_ntxd[i], sctx->isc_ntxd_min[i]);
466323ac9029SStephen Hurd 			scctx->isc_ntxd[i] = sctx->isc_ntxd_min[i];
466423ac9029SStephen Hurd 		}
466523ac9029SStephen Hurd 		if (scctx->isc_ntxd[i] > sctx->isc_ntxd_max[i]) {
466623ac9029SStephen Hurd 			device_printf(dev, "ntxd%d: %d greater than ntxd_max %d - resetting to max\n",
466723ac9029SStephen Hurd 				      i, scctx->isc_ntxd[i], sctx->isc_ntxd_max[i]);
466823ac9029SStephen Hurd 			scctx->isc_ntxd[i] = sctx->isc_ntxd_max[i];
466923ac9029SStephen Hurd 		}
4670afb77372SEric Joyner 		if (!powerof2(scctx->isc_ntxd[i])) {
4671afb77372SEric Joyner 			device_printf(dev, "ntxd%d: %d is not a power of 2 - using default value of %d\n",
4672afb77372SEric Joyner 				      i, scctx->isc_ntxd[i], sctx->isc_ntxd_default[i]);
4673afb77372SEric Joyner 			scctx->isc_ntxd[i] = sctx->isc_ntxd_default[i];
4674afb77372SEric Joyner 		}
467523ac9029SStephen Hurd 	}
467609f6ff4fSMatt Macy }
4677ab2e3f79SStephen Hurd 
46786d49b41eSAndrew Gallatin static void
46796d49b41eSAndrew Gallatin iflib_add_pfil(if_ctx_t ctx)
46806d49b41eSAndrew Gallatin {
46816d49b41eSAndrew Gallatin 	struct pfil_head *pfil;
46826d49b41eSAndrew Gallatin 	struct pfil_head_args pa;
46836d49b41eSAndrew Gallatin 	iflib_rxq_t rxq;
46846d49b41eSAndrew Gallatin 	int i;
46856d49b41eSAndrew Gallatin 
46866d49b41eSAndrew Gallatin 	pa.pa_version = PFIL_VERSION;
46876d49b41eSAndrew Gallatin 	pa.pa_flags = PFIL_IN;
46886d49b41eSAndrew Gallatin 	pa.pa_type = PFIL_TYPE_ETHERNET;
46896d49b41eSAndrew Gallatin 	pa.pa_headname = ctx->ifc_ifp->if_xname;
46906d49b41eSAndrew Gallatin 	pfil = pfil_head_register(&pa);
46916d49b41eSAndrew Gallatin 
46926d49b41eSAndrew Gallatin 	for (i = 0, rxq = ctx->ifc_rxqs; i < NRXQSETS(ctx); i++, rxq++) {
46936d49b41eSAndrew Gallatin 		rxq->pfil = pfil;
46946d49b41eSAndrew Gallatin 	}
46956d49b41eSAndrew Gallatin }
46966d49b41eSAndrew Gallatin 
46976d49b41eSAndrew Gallatin static void
46986d49b41eSAndrew Gallatin iflib_rem_pfil(if_ctx_t ctx)
46996d49b41eSAndrew Gallatin {
47006d49b41eSAndrew Gallatin 	struct pfil_head *pfil;
47016d49b41eSAndrew Gallatin 	iflib_rxq_t rxq;
47026d49b41eSAndrew Gallatin 	int i;
47036d49b41eSAndrew Gallatin 
47046d49b41eSAndrew Gallatin 	rxq = ctx->ifc_rxqs;
47056d49b41eSAndrew Gallatin 	pfil = rxq->pfil;
47066d49b41eSAndrew Gallatin 	for (i = 0; i < NRXQSETS(ctx); i++, rxq++) {
47076d49b41eSAndrew Gallatin 		rxq->pfil = NULL;
47086d49b41eSAndrew Gallatin 	}
47096d49b41eSAndrew Gallatin 	pfil_head_unregister(pfil);
47106d49b41eSAndrew Gallatin }
47116d49b41eSAndrew Gallatin 
4712ca7005f1SPatrick Kelsey 
4713ca7005f1SPatrick Kelsey /*
4714ca7005f1SPatrick Kelsey  * Advance forward by n members of the cpuset ctx->ifc_cpus starting from
4715ca7005f1SPatrick Kelsey  * cpuid and wrapping as necessary.
4716ca7005f1SPatrick Kelsey  */
4717ca7005f1SPatrick Kelsey static unsigned int
4718ca7005f1SPatrick Kelsey cpuid_advance(if_ctx_t ctx, unsigned int cpuid, unsigned int n)
4719ca7005f1SPatrick Kelsey {
4720ca7005f1SPatrick Kelsey 	unsigned int first_valid;
4721ca7005f1SPatrick Kelsey 	unsigned int last_valid;
4722ca7005f1SPatrick Kelsey 
4723ca7005f1SPatrick Kelsey 	/* cpuid should always be in the valid set */
4724ca7005f1SPatrick Kelsey 	MPASS(CPU_ISSET(cpuid, &ctx->ifc_cpus));
4725ca7005f1SPatrick Kelsey 
4726ca7005f1SPatrick Kelsey 	/* valid set should never be empty */
4727ca7005f1SPatrick Kelsey 	MPASS(!CPU_EMPTY(&ctx->ifc_cpus));
4728ca7005f1SPatrick Kelsey 
4729ca7005f1SPatrick Kelsey 	first_valid = CPU_FFS(&ctx->ifc_cpus) - 1;
4730ca7005f1SPatrick Kelsey 	last_valid = CPU_FLS(&ctx->ifc_cpus) - 1;
4731ca7005f1SPatrick Kelsey 	n = n % CPU_COUNT(&ctx->ifc_cpus);
4732ca7005f1SPatrick Kelsey 	while (n > 0) {
4733ca7005f1SPatrick Kelsey 		do {
4734ca7005f1SPatrick Kelsey 			cpuid++;
4735ca7005f1SPatrick Kelsey 			if (cpuid > last_valid)
4736ca7005f1SPatrick Kelsey 				cpuid = first_valid;
4737ca7005f1SPatrick Kelsey 		} while (!CPU_ISSET(cpuid, &ctx->ifc_cpus));
4738ca7005f1SPatrick Kelsey 		n--;
4739ca7005f1SPatrick Kelsey 	}
4740ca7005f1SPatrick Kelsey 
4741ca7005f1SPatrick Kelsey 	return (cpuid);
4742ca7005f1SPatrick Kelsey }
4743ca7005f1SPatrick Kelsey 
4744ca7005f1SPatrick Kelsey #if defined(SMP) && defined(SCHED_ULE)
4745ca7005f1SPatrick Kelsey extern struct cpu_group *cpu_top;              /* CPU topology */
4746ca7005f1SPatrick Kelsey 
4747ca7005f1SPatrick Kelsey static int
4748ca7005f1SPatrick Kelsey find_child_with_core(int cpu, struct cpu_group *grp)
4749ca7005f1SPatrick Kelsey {
4750ca7005f1SPatrick Kelsey 	int i;
4751ca7005f1SPatrick Kelsey 
4752ca7005f1SPatrick Kelsey 	if (grp->cg_children == 0)
4753ca7005f1SPatrick Kelsey 		return -1;
4754ca7005f1SPatrick Kelsey 
4755ca7005f1SPatrick Kelsey 	MPASS(grp->cg_child);
4756ca7005f1SPatrick Kelsey 	for (i = 0; i < grp->cg_children; i++) {
4757ca7005f1SPatrick Kelsey 		if (CPU_ISSET(cpu, &grp->cg_child[i].cg_mask))
4758ca7005f1SPatrick Kelsey 			return i;
4759ca7005f1SPatrick Kelsey 	}
4760ca7005f1SPatrick Kelsey 
4761ca7005f1SPatrick Kelsey 	return -1;
4762ca7005f1SPatrick Kelsey }
4763ca7005f1SPatrick Kelsey 
4764ca7005f1SPatrick Kelsey 
4765ca7005f1SPatrick Kelsey /*
4766ca7005f1SPatrick Kelsey  * Find an L2 neighbor of the given CPU or return -1 if none found.  This
4767ca7005f1SPatrick Kelsey  * does not distinguish among multiple L2 neighbors if the given CPU has
4768ca7005f1SPatrick Kelsey  * more than one (it will always return the same result in that case).
4769ca7005f1SPatrick Kelsey  */
4770ca7005f1SPatrick Kelsey static int
4771ca7005f1SPatrick Kelsey find_l2_neighbor(int cpu)
4772ca7005f1SPatrick Kelsey {
4773ca7005f1SPatrick Kelsey 	struct cpu_group *grp;
4774ca7005f1SPatrick Kelsey 	int i;
4775ca7005f1SPatrick Kelsey 
4776ca7005f1SPatrick Kelsey 	grp = cpu_top;
4777ca7005f1SPatrick Kelsey 	if (grp == NULL)
4778ca7005f1SPatrick Kelsey 		return -1;
4779ca7005f1SPatrick Kelsey 
4780ca7005f1SPatrick Kelsey 	/*
4781ca7005f1SPatrick Kelsey 	 * Find the smallest CPU group that contains the given core.
4782ca7005f1SPatrick Kelsey 	 */
4783ca7005f1SPatrick Kelsey 	i = 0;
4784ca7005f1SPatrick Kelsey 	while ((i = find_child_with_core(cpu, grp)) != -1) {
4785ca7005f1SPatrick Kelsey 		/*
4786ca7005f1SPatrick Kelsey 		 * If the smallest group containing the given CPU has less
4787ca7005f1SPatrick Kelsey 		 * than two members, we conclude the given CPU has no
4788ca7005f1SPatrick Kelsey 		 * L2 neighbor.
4789ca7005f1SPatrick Kelsey 		 */
4790ca7005f1SPatrick Kelsey 		if (grp->cg_child[i].cg_count <= 1)
4791ca7005f1SPatrick Kelsey 			return (-1);
4792ca7005f1SPatrick Kelsey 		grp = &grp->cg_child[i];
4793ca7005f1SPatrick Kelsey 	}
4794ca7005f1SPatrick Kelsey 
4795ca7005f1SPatrick Kelsey 	/* Must share L2. */
4796ca7005f1SPatrick Kelsey 	if (grp->cg_level > CG_SHARE_L2 || grp->cg_level == CG_SHARE_NONE)
4797ca7005f1SPatrick Kelsey 		return -1;
4798ca7005f1SPatrick Kelsey 
4799ca7005f1SPatrick Kelsey 	/*
4800ca7005f1SPatrick Kelsey 	 * Select the first member of the set that isn't the reference
4801ca7005f1SPatrick Kelsey 	 * CPU, which at this point is guaranteed to exist.
4802ca7005f1SPatrick Kelsey 	 */
4803ca7005f1SPatrick Kelsey 	for (i = 0; i < CPU_SETSIZE; i++) {
4804ca7005f1SPatrick Kelsey 		if (CPU_ISSET(i, &grp->cg_mask) && i != cpu)
4805ca7005f1SPatrick Kelsey 			return (i);
4806ca7005f1SPatrick Kelsey 	}
4807ca7005f1SPatrick Kelsey 
4808ca7005f1SPatrick Kelsey 	/* Should never be reached */
4809ca7005f1SPatrick Kelsey 	return (-1);
4810ca7005f1SPatrick Kelsey }
4811ca7005f1SPatrick Kelsey 
4812ca7005f1SPatrick Kelsey #else
4813ca7005f1SPatrick Kelsey static int
4814ca7005f1SPatrick Kelsey find_l2_neighbor(int cpu)
4815ca7005f1SPatrick Kelsey {
4816ca7005f1SPatrick Kelsey 
4817ca7005f1SPatrick Kelsey 	return (-1);
4818ca7005f1SPatrick Kelsey }
4819ca7005f1SPatrick Kelsey #endif
4820ca7005f1SPatrick Kelsey 
4821ca7005f1SPatrick Kelsey /*
4822ca7005f1SPatrick Kelsey  * CPU mapping behaviors
4823ca7005f1SPatrick Kelsey  * ---------------------
4824ca7005f1SPatrick Kelsey  * 'separate txrx' refers to the separate_txrx sysctl
4825ca7005f1SPatrick Kelsey  * 'use logical' refers to the use_logical_cores sysctl
4826ca7005f1SPatrick Kelsey  * 'INTR CPUS' indicates whether bus_get_cpus(INTR_CPUS) succeeded
4827ca7005f1SPatrick Kelsey  *
4828ca7005f1SPatrick Kelsey  *  separate     use     INTR
4829ca7005f1SPatrick Kelsey  *    txrx     logical   CPUS   result
4830ca7005f1SPatrick Kelsey  * ---------- --------- ------ ------------------------------------------------
4831ca7005f1SPatrick Kelsey  *     -          -       X     RX and TX queues mapped to consecutive physical
4832ca7005f1SPatrick Kelsey  *                              cores with RX/TX pairs on same core and excess
4833ca7005f1SPatrick Kelsey  *                              of either following
4834ca7005f1SPatrick Kelsey  *     -          X       X     RX and TX queues mapped to consecutive cores
4835ca7005f1SPatrick Kelsey  *                              of any type with RX/TX pairs on same core and
4836ca7005f1SPatrick Kelsey  *                              excess of either following
4837ca7005f1SPatrick Kelsey  *     X          -       X     RX and TX queues mapped to consecutive physical
4838ca7005f1SPatrick Kelsey  *                              cores; all RX then all TX
4839ca7005f1SPatrick Kelsey  *     X          X       X     RX queues mapped to consecutive physical cores
4840ca7005f1SPatrick Kelsey  *                              first, then TX queues mapped to L2 neighbor of
4841ca7005f1SPatrick Kelsey  *                              the corresponding RX queue if one exists,
4842ca7005f1SPatrick Kelsey  *                              otherwise to consecutive physical cores
4843ca7005f1SPatrick Kelsey  *     -         n/a      -     RX and TX queues mapped to consecutive cores of
4844ca7005f1SPatrick Kelsey  *                              any type with RX/TX pairs on same core and excess
4845ca7005f1SPatrick Kelsey  *                              of either following
4846ca7005f1SPatrick Kelsey  *     X         n/a      -     RX and TX queues mapped to consecutive cores of
4847ca7005f1SPatrick Kelsey  *                              any type; all RX then all TX
4848ca7005f1SPatrick Kelsey  */
4849ca7005f1SPatrick Kelsey static unsigned int
4850ca7005f1SPatrick Kelsey get_cpuid_for_queue(if_ctx_t ctx, unsigned int base_cpuid, unsigned int qid,
4851ca7005f1SPatrick Kelsey     bool is_tx)
4852ca7005f1SPatrick Kelsey {
4853ca7005f1SPatrick Kelsey 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
4854ca7005f1SPatrick Kelsey 	unsigned int core_index;
4855ca7005f1SPatrick Kelsey 
4856ca7005f1SPatrick Kelsey 	if (ctx->ifc_sysctl_separate_txrx) {
4857ca7005f1SPatrick Kelsey 		/*
4858ca7005f1SPatrick Kelsey 		 * When using separate CPUs for TX and RX, the assignment
4859ca7005f1SPatrick Kelsey 		 * will always be of a consecutive CPU out of the set of
4860ca7005f1SPatrick Kelsey 		 * context CPUs, except for the specific case where the
4861ca7005f1SPatrick Kelsey 		 * context CPUs are phsyical cores, the use of logical cores
4862ca7005f1SPatrick Kelsey 		 * has been enabled, the assignment is for TX, the TX qid
4863ca7005f1SPatrick Kelsey 		 * corresponds to an RX qid, and the CPU assigned to the
4864ca7005f1SPatrick Kelsey 		 * corresponding RX queue has an L2 neighbor.
4865ca7005f1SPatrick Kelsey 		 */
4866ca7005f1SPatrick Kelsey 		if (ctx->ifc_sysctl_use_logical_cores &&
4867ca7005f1SPatrick Kelsey 		    ctx->ifc_cpus_are_physical_cores &&
4868ca7005f1SPatrick Kelsey 		    is_tx && qid < scctx->isc_nrxqsets) {
4869ca7005f1SPatrick Kelsey 			int l2_neighbor;
4870ca7005f1SPatrick Kelsey 			unsigned int rx_cpuid;
4871ca7005f1SPatrick Kelsey 
4872ca7005f1SPatrick Kelsey 			rx_cpuid = cpuid_advance(ctx, base_cpuid, qid);
4873ca7005f1SPatrick Kelsey 			l2_neighbor = find_l2_neighbor(rx_cpuid);
4874ca7005f1SPatrick Kelsey 			if (l2_neighbor != -1) {
4875ca7005f1SPatrick Kelsey 				return (l2_neighbor);
4876ca7005f1SPatrick Kelsey 			}
4877ca7005f1SPatrick Kelsey 			/*
4878ca7005f1SPatrick Kelsey 			 * ... else fall through to the normal
4879ca7005f1SPatrick Kelsey 			 * consecutive-after-RX assignment scheme.
4880ca7005f1SPatrick Kelsey 			 *
4881ca7005f1SPatrick Kelsey 			 * Note that we are assuming that all RX queue CPUs
4882ca7005f1SPatrick Kelsey 			 * have an L2 neighbor, or all do not.  If a mixed
4883ca7005f1SPatrick Kelsey 			 * scenario is possible, we will have to keep track
4884ca7005f1SPatrick Kelsey 			 * separately of how many queues prior to this one
4885ca7005f1SPatrick Kelsey 			 * were not able to be assigned to an L2 neighbor.
4886ca7005f1SPatrick Kelsey 			 */
4887ca7005f1SPatrick Kelsey 		}
4888ca7005f1SPatrick Kelsey 		if (is_tx)
4889ca7005f1SPatrick Kelsey 			core_index = scctx->isc_nrxqsets + qid;
4890ca7005f1SPatrick Kelsey 		else
4891ca7005f1SPatrick Kelsey 			core_index = qid;
4892ca7005f1SPatrick Kelsey 	} else {
4893ca7005f1SPatrick Kelsey 		core_index = qid;
4894ca7005f1SPatrick Kelsey 	}
4895ca7005f1SPatrick Kelsey 
4896ca7005f1SPatrick Kelsey 	return (cpuid_advance(ctx, base_cpuid, core_index));
4897ca7005f1SPatrick Kelsey }
4898ca7005f1SPatrick Kelsey 
4899f154ece0SStephen Hurd static uint16_t
4900f154ece0SStephen Hurd get_ctx_core_offset(if_ctx_t ctx)
4901f154ece0SStephen Hurd {
4902f154ece0SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
4903f154ece0SStephen Hurd 	struct cpu_offset *op;
4904ca7005f1SPatrick Kelsey 	cpuset_t assigned_cpus;
4905ca7005f1SPatrick Kelsey 	unsigned int cores_consumed;
4906ca7005f1SPatrick Kelsey 	unsigned int base_cpuid = ctx->ifc_sysctl_core_offset;
4907ca7005f1SPatrick Kelsey 	unsigned int first_valid;
4908ca7005f1SPatrick Kelsey 	unsigned int last_valid;
4909ca7005f1SPatrick Kelsey 	unsigned int i;
4910f154ece0SStephen Hurd 
4911ca7005f1SPatrick Kelsey 	first_valid = CPU_FFS(&ctx->ifc_cpus) - 1;
4912ca7005f1SPatrick Kelsey 	last_valid = CPU_FLS(&ctx->ifc_cpus) - 1;
4913f154ece0SStephen Hurd 
4914ca7005f1SPatrick Kelsey 	if (base_cpuid != CORE_OFFSET_UNSPECIFIED) {
4915ca7005f1SPatrick Kelsey 		/*
4916ca7005f1SPatrick Kelsey 		 * Align the user-chosen base CPU ID to the next valid CPU
4917ca7005f1SPatrick Kelsey 		 * for this device.  If the chosen base CPU ID is smaller
4918ca7005f1SPatrick Kelsey 		 * than the first valid CPU or larger than the last valid
4919ca7005f1SPatrick Kelsey 		 * CPU, we assume the user does not know what the valid
4920ca7005f1SPatrick Kelsey 		 * range is for this device and is thinking in terms of a
4921ca7005f1SPatrick Kelsey 		 * zero-based reference frame, and so we shift the given
4922ca7005f1SPatrick Kelsey 		 * value into the valid range (and wrap accordingly) so the
4923ca7005f1SPatrick Kelsey 		 * intent is translated to the proper frame of reference.
4924ca7005f1SPatrick Kelsey 		 * If the base CPU ID is within the valid first/last, but
4925ca7005f1SPatrick Kelsey 		 * does not correspond to a valid CPU, it is advanced to the
4926ca7005f1SPatrick Kelsey 		 * next valid CPU (wrapping if necessary).
4927ca7005f1SPatrick Kelsey 		 */
4928ca7005f1SPatrick Kelsey 		if (base_cpuid < first_valid || base_cpuid > last_valid) {
4929ca7005f1SPatrick Kelsey 			/* shift from zero-based to first_valid-based */
4930ca7005f1SPatrick Kelsey 			base_cpuid += first_valid;
4931ca7005f1SPatrick Kelsey 			/* wrap to range [first_valid, last_valid] */
4932ca7005f1SPatrick Kelsey 			base_cpuid = (base_cpuid - first_valid) %
4933ca7005f1SPatrick Kelsey 			    (last_valid - first_valid + 1);
4934ca7005f1SPatrick Kelsey 		}
4935ca7005f1SPatrick Kelsey 		if (!CPU_ISSET(base_cpuid, &ctx->ifc_cpus)) {
4936ca7005f1SPatrick Kelsey 			/*
4937ca7005f1SPatrick Kelsey 			 * base_cpuid is in [first_valid, last_valid], but
4938ca7005f1SPatrick Kelsey 			 * not a member of the valid set.  In this case,
4939ca7005f1SPatrick Kelsey 			 * there will always be a member of the valid set
4940ca7005f1SPatrick Kelsey 			 * with a CPU ID that is greater than base_cpuid,
4941ca7005f1SPatrick Kelsey 			 * and we simply advance to it.
4942ca7005f1SPatrick Kelsey 			 */
4943ca7005f1SPatrick Kelsey 			while (!CPU_ISSET(base_cpuid, &ctx->ifc_cpus))
4944ca7005f1SPatrick Kelsey 				base_cpuid++;
4945ca7005f1SPatrick Kelsey 		}
4946ca7005f1SPatrick Kelsey 		return (base_cpuid);
4947ca7005f1SPatrick Kelsey 	}
4948ca7005f1SPatrick Kelsey 
4949ca7005f1SPatrick Kelsey 	/*
4950ca7005f1SPatrick Kelsey 	 * Determine how many cores will be consumed by performing the CPU
4951ca7005f1SPatrick Kelsey 	 * assignments and counting how many of the assigned CPUs correspond
4952ca7005f1SPatrick Kelsey 	 * to CPUs in the set of context CPUs.  This is done using the CPU
4953ca7005f1SPatrick Kelsey 	 * ID first_valid as the base CPU ID, as the base CPU must be within
4954ca7005f1SPatrick Kelsey 	 * the set of context CPUs.
4955ca7005f1SPatrick Kelsey 	 *
4956ca7005f1SPatrick Kelsey 	 * Note not all assigned CPUs will be in the set of context CPUs
4957ca7005f1SPatrick Kelsey 	 * when separate CPUs are being allocated to TX and RX queues,
4958ca7005f1SPatrick Kelsey 	 * assignment to logical cores has been enabled, the set of context
4959ca7005f1SPatrick Kelsey 	 * CPUs contains only physical CPUs, and TX queues are mapped to L2
4960ca7005f1SPatrick Kelsey 	 * neighbors of CPUs that RX queues have been mapped to - in this
4961ca7005f1SPatrick Kelsey 	 * case we do only want to count how many CPUs in the set of context
4962ca7005f1SPatrick Kelsey 	 * CPUs have been consumed, as that determines the next CPU in that
4963ca7005f1SPatrick Kelsey 	 * set to start allocating at for the next device for which
4964ca7005f1SPatrick Kelsey 	 * core_offset is not set.
4965ca7005f1SPatrick Kelsey 	 */
4966ca7005f1SPatrick Kelsey 	CPU_ZERO(&assigned_cpus);
4967ca7005f1SPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++)
4968ca7005f1SPatrick Kelsey 		CPU_SET(get_cpuid_for_queue(ctx, first_valid, i, true),
4969ca7005f1SPatrick Kelsey 		    &assigned_cpus);
4970ca7005f1SPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++)
4971ca7005f1SPatrick Kelsey 		CPU_SET(get_cpuid_for_queue(ctx, first_valid, i, false),
4972ca7005f1SPatrick Kelsey 		    &assigned_cpus);
4973e2650af1SStefan Eßer 	CPU_AND(&assigned_cpus, &assigned_cpus, &ctx->ifc_cpus);
4974ca7005f1SPatrick Kelsey 	cores_consumed = CPU_COUNT(&assigned_cpus);
4975f154ece0SStephen Hurd 
4976f154ece0SStephen Hurd 	mtx_lock(&cpu_offset_mtx);
4977f154ece0SStephen Hurd 	SLIST_FOREACH(op, &cpu_offsets, entries) {
4978f154ece0SStephen Hurd 		if (CPU_CMP(&ctx->ifc_cpus, &op->set) == 0) {
4979ca7005f1SPatrick Kelsey 			base_cpuid = op->next_cpuid;
4980ca7005f1SPatrick Kelsey 			op->next_cpuid = cpuid_advance(ctx, op->next_cpuid,
4981ca7005f1SPatrick Kelsey 			    cores_consumed);
4982f154ece0SStephen Hurd 			MPASS(op->refcount < UINT_MAX);
4983f154ece0SStephen Hurd 			op->refcount++;
4984f154ece0SStephen Hurd 			break;
4985f154ece0SStephen Hurd 		}
4986f154ece0SStephen Hurd 	}
4987ca7005f1SPatrick Kelsey 	if (base_cpuid == CORE_OFFSET_UNSPECIFIED) {
4988ca7005f1SPatrick Kelsey 		base_cpuid = first_valid;
4989f154ece0SStephen Hurd 		op = malloc(sizeof(struct cpu_offset), M_IFLIB,
4990f154ece0SStephen Hurd 		    M_NOWAIT | M_ZERO);
4991f154ece0SStephen Hurd 		if (op == NULL) {
4992f154ece0SStephen Hurd 			device_printf(ctx->ifc_dev,
4993f154ece0SStephen Hurd 			    "allocation for cpu offset failed.\n");
4994f154ece0SStephen Hurd 		} else {
4995ca7005f1SPatrick Kelsey 			op->next_cpuid = cpuid_advance(ctx, base_cpuid,
4996ca7005f1SPatrick Kelsey 			    cores_consumed);
4997f154ece0SStephen Hurd 			op->refcount = 1;
4998f154ece0SStephen Hurd 			CPU_COPY(&ctx->ifc_cpus, &op->set);
4999f154ece0SStephen Hurd 			SLIST_INSERT_HEAD(&cpu_offsets, op, entries);
5000f154ece0SStephen Hurd 		}
5001f154ece0SStephen Hurd 	}
5002f154ece0SStephen Hurd 	mtx_unlock(&cpu_offset_mtx);
5003f154ece0SStephen Hurd 
5004ca7005f1SPatrick Kelsey 	return (base_cpuid);
5005f154ece0SStephen Hurd }
5006f154ece0SStephen Hurd 
5007f154ece0SStephen Hurd static void
5008f154ece0SStephen Hurd unref_ctx_core_offset(if_ctx_t ctx)
5009f154ece0SStephen Hurd {
5010f154ece0SStephen Hurd 	struct cpu_offset *op, *top;
5011f154ece0SStephen Hurd 
5012f154ece0SStephen Hurd 	mtx_lock(&cpu_offset_mtx);
5013f154ece0SStephen Hurd 	SLIST_FOREACH_SAFE(op, &cpu_offsets, entries, top) {
5014f154ece0SStephen Hurd 		if (CPU_CMP(&ctx->ifc_cpus, &op->set) == 0) {
5015f154ece0SStephen Hurd 			MPASS(op->refcount > 0);
5016f154ece0SStephen Hurd 			op->refcount--;
5017f154ece0SStephen Hurd 			if (op->refcount == 0) {
5018f154ece0SStephen Hurd 				SLIST_REMOVE(&cpu_offsets, op, cpu_offset, entries);
5019f154ece0SStephen Hurd 				free(op, M_IFLIB);
5020f154ece0SStephen Hurd 			}
5021f154ece0SStephen Hurd 			break;
5022f154ece0SStephen Hurd 		}
5023f154ece0SStephen Hurd 	}
5024f154ece0SStephen Hurd 	mtx_unlock(&cpu_offset_mtx);
5025f154ece0SStephen Hurd }
5026f154ece0SStephen Hurd 
502709f6ff4fSMatt Macy int
502809f6ff4fSMatt Macy iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ctxp)
502909f6ff4fSMatt Macy {
503009f6ff4fSMatt Macy 	if_ctx_t ctx;
503109f6ff4fSMatt Macy 	if_t ifp;
503209f6ff4fSMatt Macy 	if_softc_ctx_t scctx;
50333d10e9edSMarius Strobl 	kobjop_desc_t kobj_desc;
50343d10e9edSMarius Strobl 	kobj_method_t *kobj_method;
5035afb77372SEric Joyner 	int err, msix, rid;
5036ac11d857SVincenzo Maffione 	int num_txd, num_rxd;
503709f6ff4fSMatt Macy 
503809f6ff4fSMatt Macy 	ctx = malloc(sizeof(* ctx), M_IFLIB, M_WAITOK|M_ZERO);
503909f6ff4fSMatt Macy 
504009f6ff4fSMatt Macy 	if (sc == NULL) {
504109f6ff4fSMatt Macy 		sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK|M_ZERO);
504209f6ff4fSMatt Macy 		device_set_softc(dev, ctx);
504309f6ff4fSMatt Macy 		ctx->ifc_flags |= IFC_SC_ALLOCATED;
504409f6ff4fSMatt Macy 	}
504509f6ff4fSMatt Macy 
504609f6ff4fSMatt Macy 	ctx->ifc_sctx = sctx;
504709f6ff4fSMatt Macy 	ctx->ifc_dev = dev;
504809f6ff4fSMatt Macy 	ctx->ifc_softc = sc;
504909f6ff4fSMatt Macy 
505009f6ff4fSMatt Macy 	if ((err = iflib_register(ctx)) != 0) {
505109f6ff4fSMatt Macy 		device_printf(dev, "iflib_register failed %d\n", err);
50527f3eb9daSPatrick Kelsey 		goto fail_ctx_free;
505309f6ff4fSMatt Macy 	}
505409f6ff4fSMatt Macy 	iflib_add_device_sysctl_pre(ctx);
505509f6ff4fSMatt Macy 
505609f6ff4fSMatt Macy 	scctx = &ctx->ifc_softc_ctx;
505709f6ff4fSMatt Macy 	ifp = ctx->ifc_ifp;
505809f6ff4fSMatt Macy 
505909f6ff4fSMatt Macy 	iflib_reset_qvalues(ctx);
5060aa8a24d3SStephen Hurd 	CTX_LOCK(ctx);
5061ab2e3f79SStephen Hurd 	if ((err = IFDI_ATTACH_PRE(ctx)) != 0) {
50624c7070dbSScott Long 		device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err);
50637f3eb9daSPatrick Kelsey 		goto fail_unlock;
50644c7070dbSScott Long 	}
50651248952aSSean Bruno 	_iflib_pre_assert(scctx);
50661248952aSSean Bruno 	ctx->ifc_txrx = *scctx->isc_txrx;
50671248952aSSean Bruno 
5068ef567155SMarcin Wojtas 	MPASS(scctx->isc_dma_width <= flsll(BUS_SPACE_MAXADDR));
50696dd69f00SMarcin Wojtas 
5070e2621d96SMatt Macy 	if (sctx->isc_flags & IFLIB_DRIVER_MEDIA)
5071e2621d96SMatt Macy 		ctx->ifc_mediap = scctx->isc_media;
5072e2621d96SMatt Macy 
50731248952aSSean Bruno #ifdef INVARIANTS
50747f87c040SMarius Strobl 	if (scctx->isc_capabilities & IFCAP_TXCSUM)
50751248952aSSean Bruno 		MPASS(scctx->isc_tx_csum_flags);
50761248952aSSean Bruno #endif
50771248952aSSean Bruno 
50786554362cSAndrew Gallatin 	if_setcapabilities(ifp,
50793f43ada9SGleb Smirnoff 	    scctx->isc_capabilities | IFCAP_HWSTATS | IFCAP_MEXTPG);
50806554362cSAndrew Gallatin 	if_setcapenable(ifp,
50813f43ada9SGleb Smirnoff 	    scctx->isc_capenable | IFCAP_HWSTATS | IFCAP_MEXTPG);
50821248952aSSean Bruno 
50831248952aSSean Bruno 	if (scctx->isc_ntxqsets == 0 || (scctx->isc_ntxqsets_max && scctx->isc_ntxqsets_max < scctx->isc_ntxqsets))
50841248952aSSean Bruno 		scctx->isc_ntxqsets = scctx->isc_ntxqsets_max;
50851248952aSSean Bruno 	if (scctx->isc_nrxqsets == 0 || (scctx->isc_nrxqsets_max && scctx->isc_nrxqsets_max < scctx->isc_nrxqsets))
50861248952aSSean Bruno 		scctx->isc_nrxqsets = scctx->isc_nrxqsets_max;
508723ac9029SStephen Hurd 
5088ac11d857SVincenzo Maffione 	num_txd = iflib_num_tx_descs(ctx);
5089ac11d857SVincenzo Maffione 	num_rxd = iflib_num_rx_descs(ctx);
509023ac9029SStephen Hurd 
509123ac9029SStephen Hurd 	/* XXX change for per-queue sizes */
50921722eeacSMarius Strobl 	device_printf(dev, "Using %d TX descriptors and %d RX descriptors\n",
5093ac11d857SVincenzo Maffione 	    num_txd, num_rxd);
509423ac9029SStephen Hurd 
5095ac11d857SVincenzo Maffione 	if (scctx->isc_tx_nsegments > num_txd / MAX_SINGLE_PACKET_FRACTION)
5096ac11d857SVincenzo Maffione 		scctx->isc_tx_nsegments = max(1, num_txd /
509723ac9029SStephen Hurd 		    MAX_SINGLE_PACKET_FRACTION);
5098ac11d857SVincenzo Maffione 	if (scctx->isc_tx_tso_segments_max > num_txd /
509923ac9029SStephen Hurd 	    MAX_SINGLE_PACKET_FRACTION)
510023ac9029SStephen Hurd 		scctx->isc_tx_tso_segments_max = max(1,
5101ac11d857SVincenzo Maffione 		    num_txd / MAX_SINGLE_PACKET_FRACTION);
51024c7070dbSScott Long 
51034c7070dbSScott Long 	/* TSO parameters - dig these out of the data sheet - simply correspond to tag setup */
51047f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_TSO) {
51057f87c040SMarius Strobl 		/*
51067f87c040SMarius Strobl 		 * The stack can't handle a TSO size larger than IP_MAXPACKET,
51077f87c040SMarius Strobl 		 * but some MACs do.
51087f87c040SMarius Strobl 		 */
51097f87c040SMarius Strobl 		if_sethwtsomax(ifp, min(scctx->isc_tx_tso_size_max,
51107f87c040SMarius Strobl 		    IP_MAXPACKET));
51117f87c040SMarius Strobl 		/*
51127f87c040SMarius Strobl 		 * Take maximum number of m_pullup(9)'s in iflib_parse_header()
51137f87c040SMarius Strobl 		 * into account.  In the worst case, each of these calls will
51147f87c040SMarius Strobl 		 * add another mbuf and, thus, the requirement for another DMA
51157f87c040SMarius Strobl 		 * segment.  So for best performance, it doesn't make sense to
51167f87c040SMarius Strobl 		 * advertize a maximum of TSO segments that typically will
51177f87c040SMarius Strobl 		 * require defragmentation in iflib_encap().
51187f87c040SMarius Strobl 		 */
51197f87c040SMarius Strobl 		if_sethwtsomaxsegcount(ifp, scctx->isc_tx_tso_segments_max - 3);
51207f87c040SMarius Strobl 		if_sethwtsomaxsegsize(ifp, scctx->isc_tx_tso_segsize_max);
51217f87c040SMarius Strobl 	}
51224c7070dbSScott Long 	if (scctx->isc_rss_table_size == 0)
51234c7070dbSScott Long 		scctx->isc_rss_table_size = 64;
512423ac9029SStephen Hurd 	scctx->isc_rss_table_mask = scctx->isc_rss_table_size-1;
5125da69b8f9SSean Bruno 
5126da69b8f9SSean Bruno 	GROUPTASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
5127da69b8f9SSean Bruno 	/* XXX format name */
5128f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_config_tqg, &ctx->ifc_admin_task, ctx,
5129f855ec81SMarius Strobl 	    NULL, NULL, "admin");
5130e516b535SStephen Hurd 
5131772593dbSStephen Hurd 	/* Set up cpu set.  If it fails, use the set of all CPUs. */
5132e516b535SStephen Hurd 	if (bus_get_cpus(dev, INTR_CPUS, sizeof(ctx->ifc_cpus), &ctx->ifc_cpus) != 0) {
5133e516b535SStephen Hurd 		device_printf(dev, "Unable to fetch CPU list\n");
5134e516b535SStephen Hurd 		CPU_COPY(&all_cpus, &ctx->ifc_cpus);
5135ca7005f1SPatrick Kelsey 		ctx->ifc_cpus_are_physical_cores = false;
5136ca7005f1SPatrick Kelsey 	} else
5137ca7005f1SPatrick Kelsey 		ctx->ifc_cpus_are_physical_cores = true;
5138e516b535SStephen Hurd 	MPASS(CPU_COUNT(&ctx->ifc_cpus) > 0);
5139e516b535SStephen Hurd 
51404c7070dbSScott Long 	/*
5141b97de13aSMarius Strobl 	** Now set up MSI or MSI-X, should return us the number of supported
5142b97de13aSMarius Strobl 	** vectors (will be 1 for a legacy interrupt and MSI).
51434c7070dbSScott Long 	*/
51444c7070dbSScott Long 	if (sctx->isc_flags & IFLIB_SKIP_MSIX) {
51454c7070dbSScott Long 		msix = scctx->isc_vectors;
51464c7070dbSScott Long 	} else if (scctx->isc_msix_bar != 0)
5147f7ae9a84SSean Bruno 	       /*
5148f7ae9a84SSean Bruno 		* The simple fact that isc_msix_bar is not 0 does not mean we
5149f7ae9a84SSean Bruno 		* we have a good value there that is known to work.
5150f7ae9a84SSean Bruno 		*/
51514c7070dbSScott Long 		msix = iflib_msix_init(ctx);
51524c7070dbSScott Long 	else {
51534c7070dbSScott Long 		scctx->isc_vectors = 1;
51544c7070dbSScott Long 		scctx->isc_ntxqsets = 1;
51554c7070dbSScott Long 		scctx->isc_nrxqsets = 1;
51564c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_LEGACY;
51574c7070dbSScott Long 		msix = 0;
51584c7070dbSScott Long 	}
51594c7070dbSScott Long 	/* Get memory for the station queues */
51604c7070dbSScott Long 	if ((err = iflib_queues_alloc(ctx))) {
51614c7070dbSScott Long 		device_printf(dev, "Unable to allocate queue memory\n");
51627f3eb9daSPatrick Kelsey 		goto fail_intr_free;
51634c7070dbSScott Long 	}
51644c7070dbSScott Long 
5165ac88e6daSStephen Hurd 	if ((err = iflib_qset_structures_setup(ctx)))
51664c7070dbSScott Long 		goto fail_queues;
516769b7fc3eSSean Bruno 
5168bd84f700SSean Bruno 	/*
5169f154ece0SStephen Hurd 	 * Now that we know how many queues there are, get the core offset.
5170f154ece0SStephen Hurd 	 */
5171f154ece0SStephen Hurd 	ctx->ifc_sysctl_core_offset = get_ctx_core_offset(ctx);
5172f154ece0SStephen Hurd 
51733d10e9edSMarius Strobl 	if (msix > 1) {
51743d10e9edSMarius Strobl 		/*
51753d10e9edSMarius Strobl 		 * When using MSI-X, ensure that ifdi_{r,t}x_queue_intr_enable
51763d10e9edSMarius Strobl 		 * aren't the default NULL implementation.
51773d10e9edSMarius Strobl 		 */
51783d10e9edSMarius Strobl 		kobj_desc = &ifdi_rx_queue_intr_enable_desc;
51793d10e9edSMarius Strobl 		kobj_method = kobj_lookup_method(((kobj_t)ctx)->ops->cls, NULL,
51803d10e9edSMarius Strobl 		    kobj_desc);
51813d10e9edSMarius Strobl 		if (kobj_method == &kobj_desc->deflt) {
51823d10e9edSMarius Strobl 			device_printf(dev,
51833d10e9edSMarius Strobl 			    "MSI-X requires ifdi_rx_queue_intr_enable method");
51843d10e9edSMarius Strobl 			err = EOPNOTSUPP;
51857f3eb9daSPatrick Kelsey 			goto fail_queues;
51864c7070dbSScott Long 		}
51873d10e9edSMarius Strobl 		kobj_desc = &ifdi_tx_queue_intr_enable_desc;
51883d10e9edSMarius Strobl 		kobj_method = kobj_lookup_method(((kobj_t)ctx)->ops->cls, NULL,
51893d10e9edSMarius Strobl 		    kobj_desc);
51903d10e9edSMarius Strobl 		if (kobj_method == &kobj_desc->deflt) {
51913d10e9edSMarius Strobl 			device_printf(dev,
51923d10e9edSMarius Strobl 			    "MSI-X requires ifdi_tx_queue_intr_enable method");
51933d10e9edSMarius Strobl 			err = EOPNOTSUPP;
51943d10e9edSMarius Strobl 			goto fail_queues;
51953d10e9edSMarius Strobl 		}
51963d10e9edSMarius Strobl 
51973d10e9edSMarius Strobl 		/*
51983d10e9edSMarius Strobl 		 * Assign the MSI-X vectors.
51993d10e9edSMarius Strobl 		 * Note that the default NULL ifdi_msix_intr_assign method will
52003d10e9edSMarius Strobl 		 * fail here, too.
52013d10e9edSMarius Strobl 		 */
52023d10e9edSMarius Strobl 		err = IFDI_MSIX_INTR_ASSIGN(ctx, msix);
52033d10e9edSMarius Strobl 		if (err != 0) {
52043d10e9edSMarius Strobl 			device_printf(dev, "IFDI_MSIX_INTR_ASSIGN failed %d\n",
52053d10e9edSMarius Strobl 			    err);
52063d10e9edSMarius Strobl 			goto fail_queues;
52073d10e9edSMarius Strobl 		}
5208197c6798SEric Joyner 	} else if (scctx->isc_intr != IFLIB_INTR_MSIX) {
52094c7070dbSScott Long 		rid = 0;
52104c7070dbSScott Long 		if (scctx->isc_intr == IFLIB_INTR_MSI) {
52114c7070dbSScott Long 			MPASS(msix == 1);
52124c7070dbSScott Long 			rid = 1;
52134c7070dbSScott Long 		}
521423ac9029SStephen Hurd 		if ((err = iflib_legacy_setup(ctx, ctx->isc_legacy_intr, ctx->ifc_softc, &rid, "irq0")) != 0) {
52154c7070dbSScott Long 			device_printf(dev, "iflib_legacy_setup failed %d\n", err);
52167f3eb9daSPatrick Kelsey 			goto fail_queues;
52174c7070dbSScott Long 		}
5218197c6798SEric Joyner 	} else {
5219197c6798SEric Joyner 		device_printf(dev,
5220197c6798SEric Joyner 		    "Cannot use iflib with only 1 MSI-X interrupt!\n");
5221197c6798SEric Joyner 		err = ENODEV;
522238bfc6deSSai Rajesh Tallamraju 		goto fail_queues;
52234c7070dbSScott Long 	}
52247f87c040SMarius Strobl 
52251fd8c72cSKyle Evans 	ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet);
52267f87c040SMarius Strobl 
5227ab2e3f79SStephen Hurd 	if ((err = IFDI_ATTACH_POST(ctx)) != 0) {
52284c7070dbSScott Long 		device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
52294c7070dbSScott Long 		goto fail_detach;
52304c7070dbSScott Long 	}
52317f87c040SMarius Strobl 
52327f87c040SMarius Strobl 	/*
52337f87c040SMarius Strobl 	 * Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.
52347f87c040SMarius Strobl 	 * This must appear after the call to ether_ifattach() because
52357f87c040SMarius Strobl 	 * ether_ifattach() sets if_hdrlen to the default value.
52367f87c040SMarius Strobl 	 */
52377f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_VLAN_MTU)
52387f87c040SMarius Strobl 		if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
52397f87c040SMarius Strobl 
52404c7070dbSScott Long 	if ((err = iflib_netmap_attach(ctx))) {
52414c7070dbSScott Long 		device_printf(ctx->ifc_dev, "netmap attach failed: %d\n", err);
52424c7070dbSScott Long 		goto fail_detach;
52434c7070dbSScott Long 	}
52444c7070dbSScott Long 	*ctxp = ctx;
52454c7070dbSScott Long 
52467790c8c1SConrad Meyer 	DEBUGNET_SET(ctx->ifc_ifp, iflib);
524794618825SMark Johnston 
524823ac9029SStephen Hurd 	if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
52494c7070dbSScott Long 	iflib_add_device_sysctl_post(ctx);
52506d49b41eSAndrew Gallatin 	iflib_add_pfil(ctx);
52514ecb427aSSean Bruno 	ctx->ifc_flags |= IFC_INIT_DONE;
5252aa8a24d3SStephen Hurd 	CTX_UNLOCK(ctx);
52533d10e9edSMarius Strobl 
52544c7070dbSScott Long 	return (0);
525577c1fcecSEric Joyner 
52564c7070dbSScott Long fail_detach:
52574c7070dbSScott Long 	ether_ifdetach(ctx->ifc_ifp);
52584c7070dbSScott Long fail_queues:
525938bfc6deSSai Rajesh Tallamraju 	iflib_tqg_detach(ctx);
52606108c013SStephen Hurd 	iflib_tx_structures_free(ctx);
52616108c013SStephen Hurd 	iflib_rx_structures_free(ctx);
52624c7070dbSScott Long 	IFDI_DETACH(ctx);
526338bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
526438bfc6deSSai Rajesh Tallamraju fail_intr_free:
526538bfc6deSSai Rajesh Tallamraju 	iflib_free_intr_mem(ctx);
52667f3eb9daSPatrick Kelsey fail_unlock:
5267aa8a24d3SStephen Hurd 	CTX_UNLOCK(ctx);
526856614414SEric Joyner 	iflib_deregister(ctx);
52697f3eb9daSPatrick Kelsey fail_ctx_free:
52707f3f6aadSEric Joyner 	device_set_softc(ctx->ifc_dev, NULL);
52717f3eb9daSPatrick Kelsey         if (ctx->ifc_flags & IFC_SC_ALLOCATED)
52727f3eb9daSPatrick Kelsey                 free(ctx->ifc_softc, M_IFLIB);
52737f3eb9daSPatrick Kelsey         free(ctx, M_IFLIB);
52744c7070dbSScott Long 	return (err);
52754c7070dbSScott Long }
52764c7070dbSScott Long 
52774c7070dbSScott Long int
527809f6ff4fSMatt Macy iflib_pseudo_register(device_t dev, if_shared_ctx_t sctx, if_ctx_t *ctxp,
527909f6ff4fSMatt Macy 					  struct iflib_cloneattach_ctx *clctx)
528009f6ff4fSMatt Macy {
5281ac11d857SVincenzo Maffione 	int num_txd, num_rxd;
528209f6ff4fSMatt Macy 	int err;
528309f6ff4fSMatt Macy 	if_ctx_t ctx;
528409f6ff4fSMatt Macy 	if_t ifp;
528509f6ff4fSMatt Macy 	if_softc_ctx_t scctx;
528609f6ff4fSMatt Macy 	int i;
528709f6ff4fSMatt Macy 	void *sc;
528809f6ff4fSMatt Macy 
528909f6ff4fSMatt Macy 	ctx = malloc(sizeof(*ctx), M_IFLIB, M_WAITOK|M_ZERO);
529009f6ff4fSMatt Macy 	sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK|M_ZERO);
529109f6ff4fSMatt Macy 	ctx->ifc_flags |= IFC_SC_ALLOCATED;
529209f6ff4fSMatt Macy 	if (sctx->isc_flags & (IFLIB_PSEUDO|IFLIB_VIRTUAL))
529309f6ff4fSMatt Macy 		ctx->ifc_flags |= IFC_PSEUDO;
529409f6ff4fSMatt Macy 
529509f6ff4fSMatt Macy 	ctx->ifc_sctx = sctx;
529609f6ff4fSMatt Macy 	ctx->ifc_softc = sc;
529709f6ff4fSMatt Macy 	ctx->ifc_dev = dev;
529809f6ff4fSMatt Macy 
529909f6ff4fSMatt Macy 	if ((err = iflib_register(ctx)) != 0) {
530009f6ff4fSMatt Macy 		device_printf(dev, "%s: iflib_register failed %d\n", __func__, err);
53017f3eb9daSPatrick Kelsey 		goto fail_ctx_free;
530209f6ff4fSMatt Macy 	}
530309f6ff4fSMatt Macy 	iflib_add_device_sysctl_pre(ctx);
530409f6ff4fSMatt Macy 
530509f6ff4fSMatt Macy 	scctx = &ctx->ifc_softc_ctx;
530609f6ff4fSMatt Macy 	ifp = ctx->ifc_ifp;
530709f6ff4fSMatt Macy 
530809f6ff4fSMatt Macy 	iflib_reset_qvalues(ctx);
5309aac9c817SEric Joyner 	CTX_LOCK(ctx);
531009f6ff4fSMatt Macy 	if ((err = IFDI_ATTACH_PRE(ctx)) != 0) {
531109f6ff4fSMatt Macy 		device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err);
5312aac9c817SEric Joyner 		goto fail_unlock;
531309f6ff4fSMatt Macy 	}
531409f6ff4fSMatt Macy 	if (sctx->isc_flags & IFLIB_GEN_MAC)
53151fd8c72cSKyle Evans 		ether_gen_addr(ifp, &ctx->ifc_mac);
531609f6ff4fSMatt Macy 	if ((err = IFDI_CLONEATTACH(ctx, clctx->cc_ifc, clctx->cc_name,
531709f6ff4fSMatt Macy 								clctx->cc_params)) != 0) {
531809f6ff4fSMatt Macy 		device_printf(dev, "IFDI_CLONEATTACH failed %d\n", err);
53199aeca213SMatt Macy 		goto fail_unlock;
532009f6ff4fSMatt Macy 	}
532109f6ff4fSMatt Macy #ifdef INVARIANTS
53227f87c040SMarius Strobl 	if (scctx->isc_capabilities & IFCAP_TXCSUM)
532309f6ff4fSMatt Macy 		MPASS(scctx->isc_tx_csum_flags);
532409f6ff4fSMatt Macy #endif
532509f6ff4fSMatt Macy 
53267f87c040SMarius Strobl 	if_setcapabilities(ifp, scctx->isc_capabilities | IFCAP_HWSTATS | IFCAP_LINKSTATE);
532709f6ff4fSMatt Macy 	if_setcapenable(ifp, scctx->isc_capenable | IFCAP_HWSTATS | IFCAP_LINKSTATE);
532809f6ff4fSMatt Macy 
532909f6ff4fSMatt Macy 	ifp->if_flags |= IFF_NOGROUP;
533009f6ff4fSMatt Macy 	if (sctx->isc_flags & IFLIB_PSEUDO) {
53319aeca213SMatt Macy 		ifmedia_add(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO, 0, NULL);
53329aeca213SMatt Macy 		ifmedia_set(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO);
53339aeca213SMatt Macy 		if (sctx->isc_flags & IFLIB_PSEUDO_ETHER) {
53341fd8c72cSKyle Evans 			ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet);
53359aeca213SMatt Macy 		} else {
53369aeca213SMatt Macy 			if_attach(ctx->ifc_ifp);
53379aeca213SMatt Macy 			bpfattach(ctx->ifc_ifp, DLT_NULL, sizeof(u_int32_t));
53389aeca213SMatt Macy 		}
533909f6ff4fSMatt Macy 
534009f6ff4fSMatt Macy 		if ((err = IFDI_ATTACH_POST(ctx)) != 0) {
534109f6ff4fSMatt Macy 			device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
534209f6ff4fSMatt Macy 			goto fail_detach;
534309f6ff4fSMatt Macy 		}
534409f6ff4fSMatt Macy 		*ctxp = ctx;
534509f6ff4fSMatt Macy 
53467f87c040SMarius Strobl 		/*
53477f87c040SMarius Strobl 		 * Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.
53487f87c040SMarius Strobl 		 * This must appear after the call to ether_ifattach() because
53497f87c040SMarius Strobl 		 * ether_ifattach() sets if_hdrlen to the default value.
53507f87c040SMarius Strobl 		 */
53517f87c040SMarius Strobl 		if (if_getcapabilities(ifp) & IFCAP_VLAN_MTU)
53527f87c040SMarius Strobl 			if_setifheaderlen(ifp,
53537f87c040SMarius Strobl 			    sizeof(struct ether_vlan_header));
53547f87c040SMarius Strobl 
535509f6ff4fSMatt Macy 		if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
535609f6ff4fSMatt Macy 		iflib_add_device_sysctl_post(ctx);
535709f6ff4fSMatt Macy 		ctx->ifc_flags |= IFC_INIT_DONE;
53581f93e931SMatt Macy 		CTX_UNLOCK(ctx);
535909f6ff4fSMatt Macy 		return (0);
536009f6ff4fSMatt Macy 	}
53619aeca213SMatt Macy 	ifmedia_add(ctx->ifc_mediap, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
53629aeca213SMatt Macy 	ifmedia_add(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO, 0, NULL);
53639aeca213SMatt Macy 	ifmedia_set(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO);
53649aeca213SMatt Macy 
536509f6ff4fSMatt Macy 	_iflib_pre_assert(scctx);
536609f6ff4fSMatt Macy 	ctx->ifc_txrx = *scctx->isc_txrx;
536709f6ff4fSMatt Macy 
536809f6ff4fSMatt Macy 	if (scctx->isc_ntxqsets == 0 || (scctx->isc_ntxqsets_max && scctx->isc_ntxqsets_max < scctx->isc_ntxqsets))
536909f6ff4fSMatt Macy 		scctx->isc_ntxqsets = scctx->isc_ntxqsets_max;
537009f6ff4fSMatt Macy 	if (scctx->isc_nrxqsets == 0 || (scctx->isc_nrxqsets_max && scctx->isc_nrxqsets_max < scctx->isc_nrxqsets))
537109f6ff4fSMatt Macy 		scctx->isc_nrxqsets = scctx->isc_nrxqsets_max;
537209f6ff4fSMatt Macy 
5373ac11d857SVincenzo Maffione 	num_txd = iflib_num_tx_descs(ctx);
5374ac11d857SVincenzo Maffione 	num_rxd = iflib_num_rx_descs(ctx);
537509f6ff4fSMatt Macy 
537609f6ff4fSMatt Macy 	/* XXX change for per-queue sizes */
53771722eeacSMarius Strobl 	device_printf(dev, "Using %d TX descriptors and %d RX descriptors\n",
5378ac11d857SVincenzo Maffione 	    num_txd, num_rxd);
537909f6ff4fSMatt Macy 
5380ac11d857SVincenzo Maffione 	if (scctx->isc_tx_nsegments > num_txd / MAX_SINGLE_PACKET_FRACTION)
5381ac11d857SVincenzo Maffione 		scctx->isc_tx_nsegments = max(1, num_txd /
538209f6ff4fSMatt Macy 		    MAX_SINGLE_PACKET_FRACTION);
5383ac11d857SVincenzo Maffione 	if (scctx->isc_tx_tso_segments_max > num_txd /
538409f6ff4fSMatt Macy 	    MAX_SINGLE_PACKET_FRACTION)
538509f6ff4fSMatt Macy 		scctx->isc_tx_tso_segments_max = max(1,
5386ac11d857SVincenzo Maffione 		    num_txd / MAX_SINGLE_PACKET_FRACTION);
538709f6ff4fSMatt Macy 
538809f6ff4fSMatt Macy 	/* TSO parameters - dig these out of the data sheet - simply correspond to tag setup */
53897f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_TSO) {
53907f87c040SMarius Strobl 		/*
53917f87c040SMarius Strobl 		 * The stack can't handle a TSO size larger than IP_MAXPACKET,
53927f87c040SMarius Strobl 		 * but some MACs do.
53937f87c040SMarius Strobl 		 */
53947f87c040SMarius Strobl 		if_sethwtsomax(ifp, min(scctx->isc_tx_tso_size_max,
53957f87c040SMarius Strobl 		    IP_MAXPACKET));
53967f87c040SMarius Strobl 		/*
53977f87c040SMarius Strobl 		 * Take maximum number of m_pullup(9)'s in iflib_parse_header()
53987f87c040SMarius Strobl 		 * into account.  In the worst case, each of these calls will
53997f87c040SMarius Strobl 		 * add another mbuf and, thus, the requirement for another DMA
54007f87c040SMarius Strobl 		 * segment.  So for best performance, it doesn't make sense to
54017f87c040SMarius Strobl 		 * advertize a maximum of TSO segments that typically will
54027f87c040SMarius Strobl 		 * require defragmentation in iflib_encap().
54037f87c040SMarius Strobl 		 */
54047f87c040SMarius Strobl 		if_sethwtsomaxsegcount(ifp, scctx->isc_tx_tso_segments_max - 3);
54057f87c040SMarius Strobl 		if_sethwtsomaxsegsize(ifp, scctx->isc_tx_tso_segsize_max);
54067f87c040SMarius Strobl 	}
540709f6ff4fSMatt Macy 	if (scctx->isc_rss_table_size == 0)
540809f6ff4fSMatt Macy 		scctx->isc_rss_table_size = 64;
540909f6ff4fSMatt Macy 	scctx->isc_rss_table_mask = scctx->isc_rss_table_size-1;
541009f6ff4fSMatt Macy 
541109f6ff4fSMatt Macy 	GROUPTASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
541209f6ff4fSMatt Macy 	/* XXX format name */
5413f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_config_tqg, &ctx->ifc_admin_task, ctx,
5414f855ec81SMarius Strobl 	    NULL, NULL, "admin");
541509f6ff4fSMatt Macy 
541609f6ff4fSMatt Macy 	/* XXX --- can support > 1 -- but keep it simple for now */
541709f6ff4fSMatt Macy 	scctx->isc_intr = IFLIB_INTR_LEGACY;
541809f6ff4fSMatt Macy 
541909f6ff4fSMatt Macy 	/* Get memory for the station queues */
542009f6ff4fSMatt Macy 	if ((err = iflib_queues_alloc(ctx))) {
542109f6ff4fSMatt Macy 		device_printf(dev, "Unable to allocate queue memory\n");
54227f3eb9daSPatrick Kelsey 		goto fail_iflib_detach;
542309f6ff4fSMatt Macy 	}
542409f6ff4fSMatt Macy 
542509f6ff4fSMatt Macy 	if ((err = iflib_qset_structures_setup(ctx))) {
542609f6ff4fSMatt Macy 		device_printf(dev, "qset structure setup failed %d\n", err);
542709f6ff4fSMatt Macy 		goto fail_queues;
542809f6ff4fSMatt Macy 	}
54297f87c040SMarius Strobl 
543009f6ff4fSMatt Macy 	/*
543109f6ff4fSMatt Macy 	 * XXX What if anything do we want to do about interrupts?
543209f6ff4fSMatt Macy 	 */
54331fd8c72cSKyle Evans 	ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet);
543409f6ff4fSMatt Macy 	if ((err = IFDI_ATTACH_POST(ctx)) != 0) {
543509f6ff4fSMatt Macy 		device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
543609f6ff4fSMatt Macy 		goto fail_detach;
543709f6ff4fSMatt Macy 	}
54387f87c040SMarius Strobl 
54397f87c040SMarius Strobl 	/*
54407f87c040SMarius Strobl 	 * Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.
54417f87c040SMarius Strobl 	 * This must appear after the call to ether_ifattach() because
54427f87c040SMarius Strobl 	 * ether_ifattach() sets if_hdrlen to the default value.
54437f87c040SMarius Strobl 	 */
54447f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_VLAN_MTU)
54457f87c040SMarius Strobl 		if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
54467f87c040SMarius Strobl 
544709f6ff4fSMatt Macy 	/* XXX handle more than one queue */
544809f6ff4fSMatt Macy 	for (i = 0; i < scctx->isc_nrxqsets; i++)
544909f6ff4fSMatt Macy 		IFDI_RX_CLSET(ctx, 0, i, ctx->ifc_rxqs[i].ifr_fl[0].ifl_sds.ifsd_cl);
545009f6ff4fSMatt Macy 
545109f6ff4fSMatt Macy 	*ctxp = ctx;
545209f6ff4fSMatt Macy 
545309f6ff4fSMatt Macy 	if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
545409f6ff4fSMatt Macy 	iflib_add_device_sysctl_post(ctx);
545509f6ff4fSMatt Macy 	ctx->ifc_flags |= IFC_INIT_DONE;
5456aac9c817SEric Joyner 	CTX_UNLOCK(ctx);
54573d10e9edSMarius Strobl 
545809f6ff4fSMatt Macy 	return (0);
545909f6ff4fSMatt Macy fail_detach:
546009f6ff4fSMatt Macy 	ether_ifdetach(ctx->ifc_ifp);
546109f6ff4fSMatt Macy fail_queues:
546238bfc6deSSai Rajesh Tallamraju 	iflib_tqg_detach(ctx);
546309f6ff4fSMatt Macy 	iflib_tx_structures_free(ctx);
546409f6ff4fSMatt Macy 	iflib_rx_structures_free(ctx);
54657f3eb9daSPatrick Kelsey fail_iflib_detach:
546609f6ff4fSMatt Macy 	IFDI_DETACH(ctx);
546738bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
5468aac9c817SEric Joyner fail_unlock:
5469aac9c817SEric Joyner 	CTX_UNLOCK(ctx);
547056614414SEric Joyner 	iflib_deregister(ctx);
54717f3eb9daSPatrick Kelsey fail_ctx_free:
54727f3eb9daSPatrick Kelsey 	free(ctx->ifc_softc, M_IFLIB);
54737f3eb9daSPatrick Kelsey 	free(ctx, M_IFLIB);
547409f6ff4fSMatt Macy 	return (err);
547509f6ff4fSMatt Macy }
547609f6ff4fSMatt Macy 
547709f6ff4fSMatt Macy int
547809f6ff4fSMatt Macy iflib_pseudo_deregister(if_ctx_t ctx)
547909f6ff4fSMatt Macy {
548009f6ff4fSMatt Macy 	if_t ifp = ctx->ifc_ifp;
54819aeca213SMatt Macy 	if_shared_ctx_t sctx = ctx->ifc_sctx;
548209f6ff4fSMatt Macy 
54831558015eSEric Joyner 	/* Unregister VLAN event handlers early */
54841558015eSEric Joyner 	iflib_unregister_vlan_handlers(ctx);
54851558015eSEric Joyner 
54869aeca213SMatt Macy 	if ((sctx->isc_flags & IFLIB_PSEUDO)  &&
54879aeca213SMatt Macy 		(sctx->isc_flags & IFLIB_PSEUDO_ETHER) == 0) {
54889aeca213SMatt Macy 		bpfdetach(ifp);
54899aeca213SMatt Macy 		if_detach(ifp);
54909aeca213SMatt Macy 	} else {
549109f6ff4fSMatt Macy 		ether_ifdetach(ifp);
54929aeca213SMatt Macy 	}
549309f6ff4fSMatt Macy 
549410254019SMark Johnston 	iflib_tqg_detach(ctx);
549509f6ff4fSMatt Macy 	iflib_tx_structures_free(ctx);
549609f6ff4fSMatt Macy 	iflib_rx_structures_free(ctx);
549738bfc6deSSai Rajesh Tallamraju 	IFDI_DETACH(ctx);
549838bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
549956614414SEric Joyner 
550056614414SEric Joyner 	iflib_deregister(ctx);
550156614414SEric Joyner 
550209f6ff4fSMatt Macy 	if (ctx->ifc_flags & IFC_SC_ALLOCATED)
550309f6ff4fSMatt Macy 		free(ctx->ifc_softc, M_IFLIB);
550409f6ff4fSMatt Macy 	free(ctx, M_IFLIB);
550509f6ff4fSMatt Macy 	return (0);
550609f6ff4fSMatt Macy }
550709f6ff4fSMatt Macy 
550809f6ff4fSMatt Macy int
55094c7070dbSScott Long iflib_device_attach(device_t dev)
55104c7070dbSScott Long {
55114c7070dbSScott Long 	if_ctx_t ctx;
55124c7070dbSScott Long 	if_shared_ctx_t sctx;
55134c7070dbSScott Long 
55144c7070dbSScott Long 	if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC)
55154c7070dbSScott Long 		return (ENOTSUP);
55164c7070dbSScott Long 
55174c7070dbSScott Long 	pci_enable_busmaster(dev);
55184c7070dbSScott Long 
55194c7070dbSScott Long 	return (iflib_device_register(dev, NULL, sctx, &ctx));
55204c7070dbSScott Long }
55214c7070dbSScott Long 
55224c7070dbSScott Long int
55234c7070dbSScott Long iflib_device_deregister(if_ctx_t ctx)
55244c7070dbSScott Long {
55254c7070dbSScott Long 	if_t ifp = ctx->ifc_ifp;
55264c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
55274c7070dbSScott Long 
55284c7070dbSScott Long 	/* Make sure VLANS are not using driver */
55294c7070dbSScott Long 	if (if_vlantrunkinuse(ifp)) {
55304c7070dbSScott Long 		device_printf(dev, "Vlan in use, detach first\n");
55314c7070dbSScott Long 		return (EBUSY);
55324c7070dbSScott Long 	}
553377c1fcecSEric Joyner #ifdef PCI_IOV
553477c1fcecSEric Joyner 	if (!CTX_IS_VF(ctx) && pci_iov_detach(dev) != 0) {
553577c1fcecSEric Joyner 		device_printf(dev, "SR-IOV in use; detach first.\n");
553677c1fcecSEric Joyner 		return (EBUSY);
553777c1fcecSEric Joyner 	}
553877c1fcecSEric Joyner #endif
553977c1fcecSEric Joyner 
554077c1fcecSEric Joyner 	STATE_LOCK(ctx);
554177c1fcecSEric Joyner 	ctx->ifc_flags |= IFC_IN_DETACH;
554277c1fcecSEric Joyner 	STATE_UNLOCK(ctx);
55434c7070dbSScott Long 
55441558015eSEric Joyner 	/* Unregister VLAN handlers before calling iflib_stop() */
55451558015eSEric Joyner 	iflib_unregister_vlan_handlers(ctx);
55461558015eSEric Joyner 
55471558015eSEric Joyner 	iflib_netmap_detach(ifp);
55481558015eSEric Joyner 	ether_ifdetach(ifp);
55491558015eSEric Joyner 
55504c7070dbSScott Long 	CTX_LOCK(ctx);
55514c7070dbSScott Long 	iflib_stop(ctx);
55524c7070dbSScott Long 	CTX_UNLOCK(ctx);
55534c7070dbSScott Long 
55546d49b41eSAndrew Gallatin 	iflib_rem_pfil(ctx);
55554c7070dbSScott Long 	if (ctx->ifc_led_dev != NULL)
55564c7070dbSScott Long 		led_destroy(ctx->ifc_led_dev);
555787890dbaSSean Bruno 
555810254019SMark Johnston 	iflib_tqg_detach(ctx);
555938bfc6deSSai Rajesh Tallamraju 	iflib_tx_structures_free(ctx);
556038bfc6deSSai Rajesh Tallamraju 	iflib_rx_structures_free(ctx);
556138bfc6deSSai Rajesh Tallamraju 
55626c3c3194SMatt Macy 	CTX_LOCK(ctx);
55634c7070dbSScott Long 	IFDI_DETACH(ctx);
556438bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
55656c3c3194SMatt Macy 	CTX_UNLOCK(ctx);
55666c3c3194SMatt Macy 
55676c3c3194SMatt Macy 	/* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/
556877c1fcecSEric Joyner 	iflib_free_intr_mem(ctx);
556977c1fcecSEric Joyner 
557077c1fcecSEric Joyner 	bus_generic_detach(dev);
557177c1fcecSEric Joyner 
557256614414SEric Joyner 	iflib_deregister(ctx);
557356614414SEric Joyner 
557456614414SEric Joyner 	device_set_softc(ctx->ifc_dev, NULL);
557577c1fcecSEric Joyner 	if (ctx->ifc_flags & IFC_SC_ALLOCATED)
557677c1fcecSEric Joyner 		free(ctx->ifc_softc, M_IFLIB);
5577f154ece0SStephen Hurd 	unref_ctx_core_offset(ctx);
557877c1fcecSEric Joyner 	free(ctx, M_IFLIB);
557977c1fcecSEric Joyner 	return (0);
558077c1fcecSEric Joyner }
558177c1fcecSEric Joyner 
558277c1fcecSEric Joyner static void
558310254019SMark Johnston iflib_tqg_detach(if_ctx_t ctx)
558410254019SMark Johnston {
558510254019SMark Johnston 	iflib_txq_t txq;
558610254019SMark Johnston 	iflib_rxq_t rxq;
558710254019SMark Johnston 	int i;
558810254019SMark Johnston 	struct taskqgroup *tqg;
558910254019SMark Johnston 
559010254019SMark Johnston 	/* XXX drain any dependent tasks */
559110254019SMark Johnston 	tqg = qgroup_if_io_tqg;
559210254019SMark Johnston 	for (txq = ctx->ifc_txqs, i = 0; i < NTXQSETS(ctx); i++, txq++) {
559310254019SMark Johnston 		callout_drain(&txq->ift_timer);
559410254019SMark Johnston #ifdef DEV_NETMAP
559510254019SMark Johnston 		callout_drain(&txq->ift_netmap_timer);
559610254019SMark Johnston #endif /* DEV_NETMAP */
559710254019SMark Johnston 		if (txq->ift_task.gt_uniq != NULL)
559810254019SMark Johnston 			taskqgroup_detach(tqg, &txq->ift_task);
559910254019SMark Johnston 	}
560010254019SMark Johnston 	for (i = 0, rxq = ctx->ifc_rxqs; i < NRXQSETS(ctx); i++, rxq++) {
560110254019SMark Johnston 		if (rxq->ifr_task.gt_uniq != NULL)
560210254019SMark Johnston 			taskqgroup_detach(tqg, &rxq->ifr_task);
560310254019SMark Johnston 	}
560410254019SMark Johnston 	tqg = qgroup_if_config_tqg;
560510254019SMark Johnston 	if (ctx->ifc_admin_task.gt_uniq != NULL)
560610254019SMark Johnston 		taskqgroup_detach(tqg, &ctx->ifc_admin_task);
560710254019SMark Johnston 	if (ctx->ifc_vflr_task.gt_uniq != NULL)
560810254019SMark Johnston 		taskqgroup_detach(tqg, &ctx->ifc_vflr_task);
560910254019SMark Johnston }
561010254019SMark Johnston 
561110254019SMark Johnston static void
561277c1fcecSEric Joyner iflib_free_intr_mem(if_ctx_t ctx)
561377c1fcecSEric Joyner {
561477c1fcecSEric Joyner 
56154c7070dbSScott Long 	if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_MSIX) {
56164c7070dbSScott Long 		iflib_irq_free(ctx, &ctx->ifc_legacy_irq);
56174c7070dbSScott Long 	}
5618b97de13aSMarius Strobl 	if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_LEGACY) {
5619b97de13aSMarius Strobl 		pci_release_msi(ctx->ifc_dev);
5620b97de13aSMarius Strobl 	}
56214c7070dbSScott Long 	if (ctx->ifc_msix_mem != NULL) {
56224c7070dbSScott Long 		bus_release_resource(ctx->ifc_dev, SYS_RES_MEMORY,
5623b97de13aSMarius Strobl 		    rman_get_rid(ctx->ifc_msix_mem), ctx->ifc_msix_mem);
56244c7070dbSScott Long 		ctx->ifc_msix_mem = NULL;
56254c7070dbSScott Long 	}
56264c7070dbSScott Long }
56274c7070dbSScott Long 
56284c7070dbSScott Long int
56294c7070dbSScott Long iflib_device_detach(device_t dev)
56304c7070dbSScott Long {
56314c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56324c7070dbSScott Long 
56334c7070dbSScott Long 	return (iflib_device_deregister(ctx));
56344c7070dbSScott Long }
56354c7070dbSScott Long 
56364c7070dbSScott Long int
56374c7070dbSScott Long iflib_device_suspend(device_t dev)
56384c7070dbSScott Long {
56394c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56404c7070dbSScott Long 
56414c7070dbSScott Long 	CTX_LOCK(ctx);
56424c7070dbSScott Long 	IFDI_SUSPEND(ctx);
56434c7070dbSScott Long 	CTX_UNLOCK(ctx);
56444c7070dbSScott Long 
56454c7070dbSScott Long 	return bus_generic_suspend(dev);
56464c7070dbSScott Long }
56474c7070dbSScott Long int
56484c7070dbSScott Long iflib_device_shutdown(device_t dev)
56494c7070dbSScott Long {
56504c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56514c7070dbSScott Long 
56524c7070dbSScott Long 	CTX_LOCK(ctx);
56534c7070dbSScott Long 	IFDI_SHUTDOWN(ctx);
56544c7070dbSScott Long 	CTX_UNLOCK(ctx);
56554c7070dbSScott Long 
56564c7070dbSScott Long 	return bus_generic_suspend(dev);
56574c7070dbSScott Long }
56584c7070dbSScott Long 
56594c7070dbSScott Long int
56604c7070dbSScott Long iflib_device_resume(device_t dev)
56614c7070dbSScott Long {
56624c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56634c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
56644c7070dbSScott Long 
56654c7070dbSScott Long 	CTX_LOCK(ctx);
56664c7070dbSScott Long 	IFDI_RESUME(ctx);
5667cd28ea92SStephen Hurd 	iflib_if_init_locked(ctx);
56684c7070dbSScott Long 	CTX_UNLOCK(ctx);
56694c7070dbSScott Long 	for (int i = 0; i < NTXQSETS(ctx); i++, txq++)
56704c7070dbSScott Long 		iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET);
56714c7070dbSScott Long 
56724c7070dbSScott Long 	return (bus_generic_resume(dev));
56734c7070dbSScott Long }
56744c7070dbSScott Long 
56754c7070dbSScott Long int
56764c7070dbSScott Long iflib_device_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
56774c7070dbSScott Long {
56784c7070dbSScott Long 	int error;
56794c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56804c7070dbSScott Long 
56814c7070dbSScott Long 	CTX_LOCK(ctx);
56824c7070dbSScott Long 	error = IFDI_IOV_INIT(ctx, num_vfs, params);
56834c7070dbSScott Long 	CTX_UNLOCK(ctx);
56844c7070dbSScott Long 
56854c7070dbSScott Long 	return (error);
56864c7070dbSScott Long }
56874c7070dbSScott Long 
56884c7070dbSScott Long void
56894c7070dbSScott Long iflib_device_iov_uninit(device_t dev)
56904c7070dbSScott Long {
56914c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56924c7070dbSScott Long 
56934c7070dbSScott Long 	CTX_LOCK(ctx);
56944c7070dbSScott Long 	IFDI_IOV_UNINIT(ctx);
56954c7070dbSScott Long 	CTX_UNLOCK(ctx);
56964c7070dbSScott Long }
56974c7070dbSScott Long 
56984c7070dbSScott Long int
56994c7070dbSScott Long iflib_device_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
57004c7070dbSScott Long {
57014c7070dbSScott Long 	int error;
57024c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
57034c7070dbSScott Long 
57044c7070dbSScott Long 	CTX_LOCK(ctx);
57054c7070dbSScott Long 	error = IFDI_IOV_VF_ADD(ctx, vfnum, params);
57064c7070dbSScott Long 	CTX_UNLOCK(ctx);
57074c7070dbSScott Long 
57084c7070dbSScott Long 	return (error);
57094c7070dbSScott Long }
57104c7070dbSScott Long 
57114c7070dbSScott Long /*********************************************************************
57124c7070dbSScott Long  *
57134c7070dbSScott Long  *  MODULE FUNCTION DEFINITIONS
57144c7070dbSScott Long  *
57154c7070dbSScott Long  **********************************************************************/
57164c7070dbSScott Long 
5717ab2e3f79SStephen Hurd /*
5718ab2e3f79SStephen Hurd  * - Start a fast taskqueue thread for each core
5719ab2e3f79SStephen Hurd  * - Start a taskqueue for control operations
5720ab2e3f79SStephen Hurd  */
57214c7070dbSScott Long static int
57224c7070dbSScott Long iflib_module_init(void)
57234c7070dbSScott Long {
5724*618d49f5SAlexander Motin 	iflib_timer_default = hz / 2;
57254c7070dbSScott Long 	return (0);
57264c7070dbSScott Long }
57274c7070dbSScott Long 
57284c7070dbSScott Long static int
57294c7070dbSScott Long iflib_module_event_handler(module_t mod, int what, void *arg)
57304c7070dbSScott Long {
57314c7070dbSScott Long 	int err;
57324c7070dbSScott Long 
57334c7070dbSScott Long 	switch (what) {
57344c7070dbSScott Long 	case MOD_LOAD:
57354c7070dbSScott Long 		if ((err = iflib_module_init()) != 0)
57364c7070dbSScott Long 			return (err);
57374c7070dbSScott Long 		break;
57384c7070dbSScott Long 	case MOD_UNLOAD:
57394c7070dbSScott Long 		return (EBUSY);
57404c7070dbSScott Long 	default:
57414c7070dbSScott Long 		return (EOPNOTSUPP);
57424c7070dbSScott Long 	}
57434c7070dbSScott Long 
57444c7070dbSScott Long 	return (0);
57454c7070dbSScott Long }
57464c7070dbSScott Long 
57474c7070dbSScott Long /*********************************************************************
57484c7070dbSScott Long  *
57494c7070dbSScott Long  *  PUBLIC FUNCTION DEFINITIONS
57504c7070dbSScott Long  *     ordered as in iflib.h
57514c7070dbSScott Long  *
57524c7070dbSScott Long  **********************************************************************/
57534c7070dbSScott Long 
57544c7070dbSScott Long static void
57554c7070dbSScott Long _iflib_assert(if_shared_ctx_t sctx)
57564c7070dbSScott Long {
5757afb77372SEric Joyner 	int i;
5758afb77372SEric Joyner 
57594c7070dbSScott Long 	MPASS(sctx->isc_tx_maxsize);
57604c7070dbSScott Long 	MPASS(sctx->isc_tx_maxsegsize);
57614c7070dbSScott Long 
57624c7070dbSScott Long 	MPASS(sctx->isc_rx_maxsize);
57634c7070dbSScott Long 	MPASS(sctx->isc_rx_nsegments);
57644c7070dbSScott Long 	MPASS(sctx->isc_rx_maxsegsize);
57654c7070dbSScott Long 
5766afb77372SEric Joyner 	MPASS(sctx->isc_nrxqs >= 1 && sctx->isc_nrxqs <= 8);
5767afb77372SEric Joyner 	for (i = 0; i < sctx->isc_nrxqs; i++) {
5768afb77372SEric Joyner 		MPASS(sctx->isc_nrxd_min[i]);
5769afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_nrxd_min[i]));
5770afb77372SEric Joyner 		MPASS(sctx->isc_nrxd_max[i]);
5771afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_nrxd_max[i]));
5772afb77372SEric Joyner 		MPASS(sctx->isc_nrxd_default[i]);
5773afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_nrxd_default[i]));
5774afb77372SEric Joyner 	}
5775afb77372SEric Joyner 
5776afb77372SEric Joyner 	MPASS(sctx->isc_ntxqs >= 1 && sctx->isc_ntxqs <= 8);
5777afb77372SEric Joyner 	for (i = 0; i < sctx->isc_ntxqs; i++) {
5778afb77372SEric Joyner 		MPASS(sctx->isc_ntxd_min[i]);
5779afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_ntxd_min[i]));
5780afb77372SEric Joyner 		MPASS(sctx->isc_ntxd_max[i]);
5781afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_ntxd_max[i]));
5782afb77372SEric Joyner 		MPASS(sctx->isc_ntxd_default[i]);
5783afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_ntxd_default[i]));
5784afb77372SEric Joyner 	}
57854c7070dbSScott Long }
57864c7070dbSScott Long 
57871248952aSSean Bruno static void
57881248952aSSean Bruno _iflib_pre_assert(if_softc_ctx_t scctx)
57891248952aSSean Bruno {
57901248952aSSean Bruno 
57911248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_txd_encap);
57921248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_txd_flush);
57931248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_txd_credits_update);
57941248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_available);
57951248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_pkt_get);
57961248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_refill);
57971248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_flush);
57981248952aSSean Bruno }
57992fe66646SSean Bruno 
58004c7070dbSScott Long static int
58014c7070dbSScott Long iflib_register(if_ctx_t ctx)
58024c7070dbSScott Long {
58034c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
58044c7070dbSScott Long 	driver_t *driver = sctx->isc_driver;
58054c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
58064c7070dbSScott Long 	if_t ifp;
58079aeca213SMatt Macy 	u_char type;
58089aeca213SMatt Macy 	int iflags;
58094c7070dbSScott Long 
58101f93e931SMatt Macy 	if ((sctx->isc_flags & IFLIB_PSEUDO) == 0)
58114c7070dbSScott Long 		_iflib_assert(sctx);
58124c7070dbSScott Long 
5813aa8a24d3SStephen Hurd 	CTX_LOCK_INIT(ctx);
58147b610b60SSean Bruno 	STATE_LOCK_INIT(ctx, device_get_nameunit(ctx->ifc_dev));
58159aeca213SMatt Macy 	if (sctx->isc_flags & IFLIB_PSEUDO) {
58169aeca213SMatt Macy 		if (sctx->isc_flags & IFLIB_PSEUDO_ETHER)
58179aeca213SMatt Macy 			type = IFT_ETHER;
58189aeca213SMatt Macy 		else
58199aeca213SMatt Macy 			type = IFT_PPP;
58209aeca213SMatt Macy 	} else
58219aeca213SMatt Macy 		type = IFT_ETHER;
58229aeca213SMatt Macy 	ifp = ctx->ifc_ifp = if_alloc(type);
58234c7070dbSScott Long 	if (ifp == NULL) {
58244c7070dbSScott Long 		device_printf(dev, "can not allocate ifnet structure\n");
58254c7070dbSScott Long 		return (ENOMEM);
58264c7070dbSScott Long 	}
58274c7070dbSScott Long 
58284c7070dbSScott Long 	/*
58294c7070dbSScott Long 	 * Initialize our context's device specific methods
58304c7070dbSScott Long 	 */
58314c7070dbSScott Long 	kobj_init((kobj_t) ctx, (kobj_class_t) driver);
58324c7070dbSScott Long 	kobj_class_compile((kobj_class_t) driver);
58334c7070dbSScott Long 
58344c7070dbSScott Long 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
58354c7070dbSScott Long 	if_setsoftc(ifp, ctx);
58364c7070dbSScott Long 	if_setdev(ifp, dev);
58374c7070dbSScott Long 	if_setinitfn(ifp, iflib_if_init);
58384c7070dbSScott Long 	if_setioctlfn(ifp, iflib_if_ioctl);
5839b8ca4756SPatrick Kelsey #ifdef ALTQ
5840b8ca4756SPatrick Kelsey 	if_setstartfn(ifp, iflib_altq_if_start);
5841b8ca4756SPatrick Kelsey 	if_settransmitfn(ifp, iflib_altq_if_transmit);
58428f410865SPatrick Kelsey 	if_setsendqready(ifp);
5843b8ca4756SPatrick Kelsey #else
58444c7070dbSScott Long 	if_settransmitfn(ifp, iflib_if_transmit);
5845b8ca4756SPatrick Kelsey #endif
58464c7070dbSScott Long 	if_setqflushfn(ifp, iflib_if_qflush);
58479aeca213SMatt Macy 	iflags = IFF_MULTICAST | IFF_KNOWSEPOCH;
58484c7070dbSScott Long 
58499aeca213SMatt Macy 	if ((sctx->isc_flags & IFLIB_PSEUDO) &&
58509aeca213SMatt Macy 		(sctx->isc_flags & IFLIB_PSEUDO_ETHER) == 0)
58519aeca213SMatt Macy 		iflags |= IFF_POINTOPOINT;
58529aeca213SMatt Macy 	else
58539aeca213SMatt Macy 		iflags |= IFF_BROADCAST | IFF_SIMPLEX;
58549aeca213SMatt Macy 	if_setflags(ifp, iflags);
58554c7070dbSScott Long 	ctx->ifc_vlan_attach_event =
58564c7070dbSScott Long 		EVENTHANDLER_REGISTER(vlan_config, iflib_vlan_register, ctx,
58574c7070dbSScott Long 							  EVENTHANDLER_PRI_FIRST);
58584c7070dbSScott Long 	ctx->ifc_vlan_detach_event =
58594c7070dbSScott Long 		EVENTHANDLER_REGISTER(vlan_unconfig, iflib_vlan_unregister, ctx,
58604c7070dbSScott Long 							  EVENTHANDLER_PRI_FIRST);
58614c7070dbSScott Long 
5862e2621d96SMatt Macy 	if ((sctx->isc_flags & IFLIB_DRIVER_MEDIA) == 0) {
5863e2621d96SMatt Macy 		ctx->ifc_mediap = &ctx->ifc_media;
5864e2621d96SMatt Macy 		ifmedia_init(ctx->ifc_mediap, IFM_IMASK,
58654c7070dbSScott Long 		    iflib_media_change, iflib_media_status);
5866e2621d96SMatt Macy 	}
58674c7070dbSScott Long 	return (0);
58684c7070dbSScott Long }
58694c7070dbSScott Long 
587056614414SEric Joyner static void
58711558015eSEric Joyner iflib_unregister_vlan_handlers(if_ctx_t ctx)
587256614414SEric Joyner {
587356614414SEric Joyner 	/* Unregister VLAN events */
587456614414SEric Joyner 	if (ctx->ifc_vlan_attach_event != NULL) {
587556614414SEric Joyner 		EVENTHANDLER_DEREGISTER(vlan_config, ctx->ifc_vlan_attach_event);
587656614414SEric Joyner 		ctx->ifc_vlan_attach_event = NULL;
587756614414SEric Joyner 	}
587856614414SEric Joyner 	if (ctx->ifc_vlan_detach_event != NULL) {
587956614414SEric Joyner 		EVENTHANDLER_DEREGISTER(vlan_unconfig, ctx->ifc_vlan_detach_event);
588056614414SEric Joyner 		ctx->ifc_vlan_detach_event = NULL;
588156614414SEric Joyner 	}
588256614414SEric Joyner 
58831558015eSEric Joyner }
58841558015eSEric Joyner 
58851558015eSEric Joyner static void
58861558015eSEric Joyner iflib_deregister(if_ctx_t ctx)
58871558015eSEric Joyner {
58881558015eSEric Joyner 	if_t ifp = ctx->ifc_ifp;
58891558015eSEric Joyner 
58901558015eSEric Joyner 	/* Remove all media */
58911558015eSEric Joyner 	ifmedia_removeall(&ctx->ifc_media);
58921558015eSEric Joyner 
58931558015eSEric Joyner 	/* Ensure that VLAN event handlers are unregistered */
58941558015eSEric Joyner 	iflib_unregister_vlan_handlers(ctx);
58951558015eSEric Joyner 
589656614414SEric Joyner 	/* Release kobject reference */
589756614414SEric Joyner 	kobj_delete((kobj_t) ctx, NULL);
589856614414SEric Joyner 
589956614414SEric Joyner 	/* Free the ifnet structure */
590056614414SEric Joyner 	if_free(ifp);
590156614414SEric Joyner 
590256614414SEric Joyner 	STATE_LOCK_DESTROY(ctx);
590356614414SEric Joyner 
590456614414SEric Joyner 	/* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/
590556614414SEric Joyner 	CTX_LOCK_DESTROY(ctx);
590656614414SEric Joyner }
590756614414SEric Joyner 
59084c7070dbSScott Long static int
59094c7070dbSScott Long iflib_queues_alloc(if_ctx_t ctx)
59104c7070dbSScott Long {
59114c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
591223ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
59134c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
591423ac9029SStephen Hurd 	int nrxqsets = scctx->isc_nrxqsets;
591523ac9029SStephen Hurd 	int ntxqsets = scctx->isc_ntxqsets;
59164c7070dbSScott Long 	iflib_txq_t txq;
59174c7070dbSScott Long 	iflib_rxq_t rxq;
59184c7070dbSScott Long 	iflib_fl_t fl = NULL;
591923ac9029SStephen Hurd 	int i, j, cpu, err, txconf, rxconf;
59204c7070dbSScott Long 	iflib_dma_info_t ifdip;
592123ac9029SStephen Hurd 	uint32_t *rxqsizes = scctx->isc_rxqsizes;
592223ac9029SStephen Hurd 	uint32_t *txqsizes = scctx->isc_txqsizes;
59234c7070dbSScott Long 	uint8_t nrxqs = sctx->isc_nrxqs;
59244c7070dbSScott Long 	uint8_t ntxqs = sctx->isc_ntxqs;
59254c7070dbSScott Long 	int nfree_lists = sctx->isc_nfl ? sctx->isc_nfl : 1;
59264ba9ad0dSVincenzo Maffione 	int fl_offset = (sctx->isc_flags & IFLIB_HAS_RXCQ ? 1 : 0);
59274c7070dbSScott Long 	caddr_t *vaddrs;
59284c7070dbSScott Long 	uint64_t *paddrs;
59294c7070dbSScott Long 
593023ac9029SStephen Hurd 	KASSERT(ntxqs > 0, ("number of queues per qset must be at least 1"));
593123ac9029SStephen Hurd 	KASSERT(nrxqs > 0, ("number of queues per qset must be at least 1"));
59324ba9ad0dSVincenzo Maffione 	KASSERT(nrxqs >= fl_offset + nfree_lists,
59334ba9ad0dSVincenzo Maffione            ("there must be at least a rxq for each free list"));
59344c7070dbSScott Long 
59354c7070dbSScott Long 	/* Allocate the TX ring struct memory */
5936b89827a0SStephen Hurd 	if (!(ctx->ifc_txqs =
5937ac2fffa4SPedro F. Giffuni 	    (iflib_txq_t) malloc(sizeof(struct iflib_txq) *
5938ac2fffa4SPedro F. Giffuni 	    ntxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) {
59394c7070dbSScott Long 		device_printf(dev, "Unable to allocate TX ring memory\n");
59404c7070dbSScott Long 		err = ENOMEM;
59414c7070dbSScott Long 		goto fail;
59424c7070dbSScott Long 	}
59434c7070dbSScott Long 
59444c7070dbSScott Long 	/* Now allocate the RX */
5945b89827a0SStephen Hurd 	if (!(ctx->ifc_rxqs =
5946ac2fffa4SPedro F. Giffuni 	    (iflib_rxq_t) malloc(sizeof(struct iflib_rxq) *
5947ac2fffa4SPedro F. Giffuni 	    nrxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) {
59484c7070dbSScott Long 		device_printf(dev, "Unable to allocate RX ring memory\n");
59494c7070dbSScott Long 		err = ENOMEM;
59504c7070dbSScott Long 		goto rx_fail;
59514c7070dbSScott Long 	}
59524c7070dbSScott Long 
5953b89827a0SStephen Hurd 	txq = ctx->ifc_txqs;
5954b89827a0SStephen Hurd 	rxq = ctx->ifc_rxqs;
59554c7070dbSScott Long 
59564c7070dbSScott Long 	/*
59574c7070dbSScott Long 	 * XXX handle allocation failure
59584c7070dbSScott Long 	 */
595996c85efbSNathan Whitehorn 	for (txconf = i = 0, cpu = CPU_FIRST(); i < ntxqsets; i++, txconf++, txq++, cpu = CPU_NEXT(cpu)) {
59604c7070dbSScott Long 		/* Set up some basics */
59614c7070dbSScott Long 
5962bfce461eSMarius Strobl 		if ((ifdip = malloc(sizeof(struct iflib_dma_info) * ntxqs,
5963bfce461eSMarius Strobl 		    M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
5964bfce461eSMarius Strobl 			device_printf(dev,
5965bfce461eSMarius Strobl 			    "Unable to allocate TX DMA info memory\n");
59664c7070dbSScott Long 			err = ENOMEM;
59670d0338afSConrad Meyer 			goto err_tx_desc;
59684c7070dbSScott Long 		}
59694c7070dbSScott Long 		txq->ift_ifdi = ifdip;
59704c7070dbSScott Long 		for (j = 0; j < ntxqs; j++, ifdip++) {
5971bfce461eSMarius Strobl 			if (iflib_dma_alloc(ctx, txqsizes[j], ifdip, 0)) {
5972bfce461eSMarius Strobl 				device_printf(dev,
5973bfce461eSMarius Strobl 				    "Unable to allocate TX descriptors\n");
59744c7070dbSScott Long 				err = ENOMEM;
59754c7070dbSScott Long 				goto err_tx_desc;
59764c7070dbSScott Long 			}
597795246abbSSean Bruno 			txq->ift_txd_size[j] = scctx->isc_txd_size[j];
59784c7070dbSScott Long 			bzero((void *)ifdip->idi_vaddr, txqsizes[j]);
59794c7070dbSScott Long 		}
59804c7070dbSScott Long 		txq->ift_ctx = ctx;
59814c7070dbSScott Long 		txq->ift_id = i;
598223ac9029SStephen Hurd 		if (sctx->isc_flags & IFLIB_HAS_TXCQ) {
598323ac9029SStephen Hurd 			txq->ift_br_offset = 1;
598423ac9029SStephen Hurd 		} else {
598523ac9029SStephen Hurd 			txq->ift_br_offset = 0;
598623ac9029SStephen Hurd 		}
59874c7070dbSScott Long 
59884c7070dbSScott Long 		if (iflib_txsd_alloc(txq)) {
59894c7070dbSScott Long 			device_printf(dev, "Critical Failure setting up TX buffers\n");
59904c7070dbSScott Long 			err = ENOMEM;
59914c7070dbSScott Long 			goto err_tx_desc;
59924c7070dbSScott Long 		}
59934c7070dbSScott Long 
59944c7070dbSScott Long 		/* Initialize the TX lock */
59951722eeacSMarius Strobl 		snprintf(txq->ift_mtx_name, MTX_NAME_LEN, "%s:TX(%d):callout",
59964c7070dbSScott Long 		    device_get_nameunit(dev), txq->ift_id);
59974c7070dbSScott Long 		mtx_init(&txq->ift_mtx, txq->ift_mtx_name, NULL, MTX_DEF);
59984c7070dbSScott Long 		callout_init_mtx(&txq->ift_timer, &txq->ift_mtx, 0);
599917cec474SVincenzo Maffione 		txq->ift_timer.c_cpu = cpu;
600017cec474SVincenzo Maffione #ifdef DEV_NETMAP
600117cec474SVincenzo Maffione 		callout_init_mtx(&txq->ift_netmap_timer, &txq->ift_mtx, 0);
600217cec474SVincenzo Maffione 		txq->ift_netmap_timer.c_cpu = cpu;
600317cec474SVincenzo Maffione #endif /* DEV_NETMAP */
60044c7070dbSScott Long 
600595246abbSSean Bruno 		err = ifmp_ring_alloc(&txq->ift_br, 2048, txq, iflib_txq_drain,
60064c7070dbSScott Long 				      iflib_txq_can_drain, M_IFLIB, M_WAITOK);
60074c7070dbSScott Long 		if (err) {
60084c7070dbSScott Long 			/* XXX free any allocated rings */
60094c7070dbSScott Long 			device_printf(dev, "Unable to allocate buf_ring\n");
60100d0338afSConrad Meyer 			goto err_tx_desc;
60114c7070dbSScott Long 		}
60124c7070dbSScott Long 	}
60134c7070dbSScott Long 
60144c7070dbSScott Long 	for (rxconf = i = 0; i < nrxqsets; i++, rxconf++, rxq++) {
60154c7070dbSScott Long 		/* Set up some basics */
6016fb1a29b4SHans Petter Selasky 		callout_init(&rxq->ifr_watchdog, 1);
60174c7070dbSScott Long 
6018bfce461eSMarius Strobl 		if ((ifdip = malloc(sizeof(struct iflib_dma_info) * nrxqs,
6019bfce461eSMarius Strobl 		   M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
6020bfce461eSMarius Strobl 			device_printf(dev,
6021bfce461eSMarius Strobl 			    "Unable to allocate RX DMA info memory\n");
60224c7070dbSScott Long 			err = ENOMEM;
60230d0338afSConrad Meyer 			goto err_tx_desc;
60244c7070dbSScott Long 		}
60254c7070dbSScott Long 
60264c7070dbSScott Long 		rxq->ifr_ifdi = ifdip;
602795246abbSSean Bruno 		/* XXX this needs to be changed if #rx queues != #tx queues */
602895246abbSSean Bruno 		rxq->ifr_ntxqirq = 1;
602995246abbSSean Bruno 		rxq->ifr_txqid[0] = i;
60304c7070dbSScott Long 		for (j = 0; j < nrxqs; j++, ifdip++) {
6031bfce461eSMarius Strobl 			if (iflib_dma_alloc(ctx, rxqsizes[j], ifdip, 0)) {
6032bfce461eSMarius Strobl 				device_printf(dev,
6033bfce461eSMarius Strobl 				    "Unable to allocate RX descriptors\n");
60344c7070dbSScott Long 				err = ENOMEM;
60354c7070dbSScott Long 				goto err_tx_desc;
60364c7070dbSScott Long 			}
60374c7070dbSScott Long 			bzero((void *)ifdip->idi_vaddr, rxqsizes[j]);
60384c7070dbSScott Long 		}
60394c7070dbSScott Long 		rxq->ifr_ctx = ctx;
60404c7070dbSScott Long 		rxq->ifr_id = i;
60414ba9ad0dSVincenzo Maffione 		rxq->ifr_fl_offset = fl_offset;
60424c7070dbSScott Long 		rxq->ifr_nfl = nfree_lists;
60434c7070dbSScott Long 		if (!(fl =
6044ac2fffa4SPedro F. Giffuni 			  (iflib_fl_t) malloc(sizeof(struct iflib_fl) * nfree_lists, M_IFLIB, M_NOWAIT | M_ZERO))) {
60454c7070dbSScott Long 			device_printf(dev, "Unable to allocate free list memory\n");
60464c7070dbSScott Long 			err = ENOMEM;
60470d0338afSConrad Meyer 			goto err_tx_desc;
60484c7070dbSScott Long 		}
60494c7070dbSScott Long 		rxq->ifr_fl = fl;
60504c7070dbSScott Long 		for (j = 0; j < nfree_lists; j++) {
605195246abbSSean Bruno 			fl[j].ifl_rxq = rxq;
605295246abbSSean Bruno 			fl[j].ifl_id = j;
605395246abbSSean Bruno 			fl[j].ifl_ifdi = &rxq->ifr_ifdi[j + rxq->ifr_fl_offset];
605495246abbSSean Bruno 			fl[j].ifl_rxd_size = scctx->isc_rxd_size[j];
60554c7070dbSScott Long 		}
60564c7070dbSScott Long 		/* Allocate receive buffers for the ring */
60574c7070dbSScott Long 		if (iflib_rxsd_alloc(rxq)) {
60584c7070dbSScott Long 			device_printf(dev,
60594c7070dbSScott Long 			    "Critical Failure setting up receive buffers\n");
60604c7070dbSScott Long 			err = ENOMEM;
60614c7070dbSScott Long 			goto err_rx_desc;
60624c7070dbSScott Long 		}
606387890dbaSSean Bruno 
606487890dbaSSean Bruno 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++)
60653db348b5SMarius Strobl 			fl->ifl_rx_bitmap = bit_alloc(fl->ifl_size, M_IFLIB,
60663db348b5SMarius Strobl 			    M_WAITOK);
60674c7070dbSScott Long 	}
60684c7070dbSScott Long 
60694c7070dbSScott Long 	/* TXQs */
60704c7070dbSScott Long 	vaddrs = malloc(sizeof(caddr_t)*ntxqsets*ntxqs, M_IFLIB, M_WAITOK);
60714c7070dbSScott Long 	paddrs = malloc(sizeof(uint64_t)*ntxqsets*ntxqs, M_IFLIB, M_WAITOK);
60724c7070dbSScott Long 	for (i = 0; i < ntxqsets; i++) {
60734c7070dbSScott Long 		iflib_dma_info_t di = ctx->ifc_txqs[i].ift_ifdi;
60744c7070dbSScott Long 
60754c7070dbSScott Long 		for (j = 0; j < ntxqs; j++, di++) {
60764c7070dbSScott Long 			vaddrs[i*ntxqs + j] = di->idi_vaddr;
60774c7070dbSScott Long 			paddrs[i*ntxqs + j] = di->idi_paddr;
60784c7070dbSScott Long 		}
60794c7070dbSScott Long 	}
60804c7070dbSScott Long 	if ((err = IFDI_TX_QUEUES_ALLOC(ctx, vaddrs, paddrs, ntxqs, ntxqsets)) != 0) {
6081bfce461eSMarius Strobl 		device_printf(ctx->ifc_dev,
6082bfce461eSMarius Strobl 		    "Unable to allocate device TX queue\n");
60834c7070dbSScott Long 		iflib_tx_structures_free(ctx);
60844c7070dbSScott Long 		free(vaddrs, M_IFLIB);
60854c7070dbSScott Long 		free(paddrs, M_IFLIB);
60864c7070dbSScott Long 		goto err_rx_desc;
60874c7070dbSScott Long 	}
60884c7070dbSScott Long 	free(vaddrs, M_IFLIB);
60894c7070dbSScott Long 	free(paddrs, M_IFLIB);
60904c7070dbSScott Long 
60914c7070dbSScott Long 	/* RXQs */
60924c7070dbSScott Long 	vaddrs = malloc(sizeof(caddr_t)*nrxqsets*nrxqs, M_IFLIB, M_WAITOK);
60934c7070dbSScott Long 	paddrs = malloc(sizeof(uint64_t)*nrxqsets*nrxqs, M_IFLIB, M_WAITOK);
60944c7070dbSScott Long 	for (i = 0; i < nrxqsets; i++) {
60954c7070dbSScott Long 		iflib_dma_info_t di = ctx->ifc_rxqs[i].ifr_ifdi;
60964c7070dbSScott Long 
60974c7070dbSScott Long 		for (j = 0; j < nrxqs; j++, di++) {
60984c7070dbSScott Long 			vaddrs[i*nrxqs + j] = di->idi_vaddr;
60994c7070dbSScott Long 			paddrs[i*nrxqs + j] = di->idi_paddr;
61004c7070dbSScott Long 		}
61014c7070dbSScott Long 	}
61024c7070dbSScott Long 	if ((err = IFDI_RX_QUEUES_ALLOC(ctx, vaddrs, paddrs, nrxqs, nrxqsets)) != 0) {
6103bfce461eSMarius Strobl 		device_printf(ctx->ifc_dev,
6104bfce461eSMarius Strobl 		    "Unable to allocate device RX queue\n");
61054c7070dbSScott Long 		iflib_tx_structures_free(ctx);
61064c7070dbSScott Long 		free(vaddrs, M_IFLIB);
61074c7070dbSScott Long 		free(paddrs, M_IFLIB);
61084c7070dbSScott Long 		goto err_rx_desc;
61094c7070dbSScott Long 	}
61104c7070dbSScott Long 	free(vaddrs, M_IFLIB);
61114c7070dbSScott Long 	free(paddrs, M_IFLIB);
61124c7070dbSScott Long 
61134c7070dbSScott Long 	return (0);
61144c7070dbSScott Long 
61154c7070dbSScott Long /* XXX handle allocation failure changes */
61164c7070dbSScott Long err_rx_desc:
61174c7070dbSScott Long err_tx_desc:
6118b89827a0SStephen Hurd rx_fail:
61194c7070dbSScott Long 	if (ctx->ifc_rxqs != NULL)
61204c7070dbSScott Long 		free(ctx->ifc_rxqs, M_IFLIB);
61214c7070dbSScott Long 	ctx->ifc_rxqs = NULL;
61224c7070dbSScott Long 	if (ctx->ifc_txqs != NULL)
61234c7070dbSScott Long 		free(ctx->ifc_txqs, M_IFLIB);
61244c7070dbSScott Long 	ctx->ifc_txqs = NULL;
61254c7070dbSScott Long fail:
61264c7070dbSScott Long 	return (err);
61274c7070dbSScott Long }
61284c7070dbSScott Long 
61294c7070dbSScott Long static int
61304c7070dbSScott Long iflib_tx_structures_setup(if_ctx_t ctx)
61314c7070dbSScott Long {
61324c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
61334c7070dbSScott Long 	int i;
61344c7070dbSScott Long 
61354c7070dbSScott Long 	for (i = 0; i < NTXQSETS(ctx); i++, txq++)
61364c7070dbSScott Long 		iflib_txq_setup(txq);
61374c7070dbSScott Long 
61384c7070dbSScott Long 	return (0);
61394c7070dbSScott Long }
61404c7070dbSScott Long 
61414c7070dbSScott Long static void
61424c7070dbSScott Long iflib_tx_structures_free(if_ctx_t ctx)
61434c7070dbSScott Long {
61444c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
61454d261ce2SStephen Hurd 	if_shared_ctx_t sctx = ctx->ifc_sctx;
61464c7070dbSScott Long 	int i, j;
61474c7070dbSScott Long 
61484c7070dbSScott Long 	for (i = 0; i < NTXQSETS(ctx); i++, txq++) {
61494d261ce2SStephen Hurd 		for (j = 0; j < sctx->isc_ntxqs; j++)
61504c7070dbSScott Long 			iflib_dma_free(&txq->ift_ifdi[j]);
6151244e7cffSEric Joyner 		iflib_txq_destroy(txq);
61524c7070dbSScott Long 	}
61534c7070dbSScott Long 	free(ctx->ifc_txqs, M_IFLIB);
61544c7070dbSScott Long 	ctx->ifc_txqs = NULL;
61554c7070dbSScott Long }
61564c7070dbSScott Long 
61574c7070dbSScott Long /*********************************************************************
61584c7070dbSScott Long  *
61594c7070dbSScott Long  *  Initialize all receive rings.
61604c7070dbSScott Long  *
61614c7070dbSScott Long  **********************************************************************/
61624c7070dbSScott Long static int
61634c7070dbSScott Long iflib_rx_structures_setup(if_ctx_t ctx)
61644c7070dbSScott Long {
61654c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
6166aaeb188aSBjoern A. Zeeb 	int q;
6167aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
61683d10e9edSMarius Strobl 	int err, i;
6169aaeb188aSBjoern A. Zeeb #endif
61704c7070dbSScott Long 
61714c7070dbSScott Long 	for (q = 0; q < ctx->ifc_softc_ctx.isc_nrxqsets; q++, rxq++) {
6172aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
61733d10e9edSMarius Strobl 		err = tcp_lro_init_args(&rxq->ifr_lc, ctx->ifc_ifp,
617423ac9029SStephen Hurd 		    TCP_LRO_ENTRIES, min(1024,
61753d10e9edSMarius Strobl 		    ctx->ifc_softc_ctx.isc_nrxd[rxq->ifr_fl_offset]));
61763d10e9edSMarius Strobl 		if (err != 0) {
61773d10e9edSMarius Strobl 			device_printf(ctx->ifc_dev,
61783d10e9edSMarius Strobl 			    "LRO Initialization failed!\n");
61794c7070dbSScott Long 			goto fail;
61804c7070dbSScott Long 		}
6181aaeb188aSBjoern A. Zeeb #endif
61824c7070dbSScott Long 		IFDI_RXQ_SETUP(ctx, rxq->ifr_id);
61834c7070dbSScott Long 	}
61844c7070dbSScott Long 	return (0);
6185aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
61864c7070dbSScott Long fail:
61874c7070dbSScott Long 	/*
61883d10e9edSMarius Strobl 	 * Free LRO resources allocated so far, we will only handle
61894c7070dbSScott Long 	 * the rings that completed, the failing case will have
61904c7070dbSScott Long 	 * cleaned up for itself.  'q' failed, so its the terminus.
61914c7070dbSScott Long 	 */
61924c7070dbSScott Long 	rxq = ctx->ifc_rxqs;
61934c7070dbSScott Long 	for (i = 0; i < q; ++i, rxq++) {
61943d10e9edSMarius Strobl 		tcp_lro_free(&rxq->ifr_lc);
61954c7070dbSScott Long 	}
61964c7070dbSScott Long 	return (err);
6197aaeb188aSBjoern A. Zeeb #endif
61984c7070dbSScott Long }
61994c7070dbSScott Long 
62004c7070dbSScott Long /*********************************************************************
62014c7070dbSScott Long  *
62024c7070dbSScott Long  *  Free all receive rings.
62034c7070dbSScott Long  *
62044c7070dbSScott Long  **********************************************************************/
62054c7070dbSScott Long static void
62064c7070dbSScott Long iflib_rx_structures_free(if_ctx_t ctx)
62074c7070dbSScott Long {
62084c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
6209db8e8f1eSEric Joyner 	if_shared_ctx_t sctx = ctx->ifc_sctx;
6210db8e8f1eSEric Joyner 	int i, j;
62114c7070dbSScott Long 
62123d10e9edSMarius Strobl 	for (i = 0; i < ctx->ifc_softc_ctx.isc_nrxqsets; i++, rxq++) {
6213db8e8f1eSEric Joyner 		for (j = 0; j < sctx->isc_nrxqs; j++)
6214db8e8f1eSEric Joyner 			iflib_dma_free(&rxq->ifr_ifdi[j]);
62154c7070dbSScott Long 		iflib_rx_sds_free(rxq);
6216007b804fSMarius Strobl #if defined(INET6) || defined(INET)
62173d10e9edSMarius Strobl 		tcp_lro_free(&rxq->ifr_lc);
6218007b804fSMarius Strobl #endif
62194c7070dbSScott Long 	}
622077c1fcecSEric Joyner 	free(ctx->ifc_rxqs, M_IFLIB);
622177c1fcecSEric Joyner 	ctx->ifc_rxqs = NULL;
62224c7070dbSScott Long }
62234c7070dbSScott Long 
62244c7070dbSScott Long static int
62254c7070dbSScott Long iflib_qset_structures_setup(if_ctx_t ctx)
62264c7070dbSScott Long {
62274c7070dbSScott Long 	int err;
62284c7070dbSScott Long 
62296108c013SStephen Hurd 	/*
62306108c013SStephen Hurd 	 * It is expected that the caller takes care of freeing queues if this
62316108c013SStephen Hurd 	 * fails.
62326108c013SStephen Hurd 	 */
6233ac88e6daSStephen Hurd 	if ((err = iflib_tx_structures_setup(ctx)) != 0) {
6234ac88e6daSStephen Hurd 		device_printf(ctx->ifc_dev, "iflib_tx_structures_setup failed: %d\n", err);
62354c7070dbSScott Long 		return (err);
6236ac88e6daSStephen Hurd 	}
62374c7070dbSScott Long 
62386108c013SStephen Hurd 	if ((err = iflib_rx_structures_setup(ctx)) != 0)
62394c7070dbSScott Long 		device_printf(ctx->ifc_dev, "iflib_rx_structures_setup failed: %d\n", err);
62406108c013SStephen Hurd 
62414c7070dbSScott Long 	return (err);
62424c7070dbSScott Long }
62434c7070dbSScott Long 
62444c7070dbSScott Long int
62454c7070dbSScott Long iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid,
62463e0e6330SStephen Hurd 		driver_filter_t filter, void *filter_arg, driver_intr_t handler, void *arg, const char *name)
62474c7070dbSScott Long {
62484c7070dbSScott Long 
62494c7070dbSScott Long 	return (_iflib_irq_alloc(ctx, irq, rid, filter, handler, arg, name));
62504c7070dbSScott Long }
62514c7070dbSScott Long 
6252b103855eSStephen Hurd /* Just to avoid copy/paste */
6253b103855eSStephen Hurd static inline int
6254f855ec81SMarius Strobl iflib_irq_set_affinity(if_ctx_t ctx, if_irq_t irq, iflib_intr_type_t type,
6255f855ec81SMarius Strobl     int qid, struct grouptask *gtask, struct taskqgroup *tqg, void *uniq,
6256f855ec81SMarius Strobl     const char *name)
6257b103855eSStephen Hurd {
6258f855ec81SMarius Strobl 	device_t dev;
6259ca7005f1SPatrick Kelsey 	unsigned int base_cpuid, cpuid;
6260ca7005f1SPatrick Kelsey 	int err;
6261b103855eSStephen Hurd 
6262f855ec81SMarius Strobl 	dev = ctx->ifc_dev;
6263ca7005f1SPatrick Kelsey 	base_cpuid = ctx->ifc_sysctl_core_offset;
6264ca7005f1SPatrick Kelsey 	cpuid = get_cpuid_for_queue(ctx, base_cpuid, qid, type == IFLIB_INTR_TX);
6265ca7005f1SPatrick Kelsey 	err = taskqgroup_attach_cpu(tqg, gtask, uniq, cpuid, dev,
6266ca7005f1SPatrick Kelsey 	    irq ? irq->ii_res : NULL, name);
6267b103855eSStephen Hurd 	if (err) {
6268f855ec81SMarius Strobl 		device_printf(dev, "taskqgroup_attach_cpu failed %d\n", err);
6269b103855eSStephen Hurd 		return (err);
6270b103855eSStephen Hurd 	}
6271b103855eSStephen Hurd #ifdef notyet
6272b103855eSStephen Hurd 	if (cpuid > ctx->ifc_cpuid_highest)
6273b103855eSStephen Hurd 		ctx->ifc_cpuid_highest = cpuid;
6274b103855eSStephen Hurd #endif
62753d10e9edSMarius Strobl 	return (0);
6276b103855eSStephen Hurd }
6277b103855eSStephen Hurd 
62784c7070dbSScott Long int
62794c7070dbSScott Long iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid,
62804c7070dbSScott Long 			iflib_intr_type_t type, driver_filter_t *filter,
62813e0e6330SStephen Hurd 			void *filter_arg, int qid, const char *name)
62824c7070dbSScott Long {
6283f855ec81SMarius Strobl 	device_t dev;
62844c7070dbSScott Long 	struct grouptask *gtask;
62854c7070dbSScott Long 	struct taskqgroup *tqg;
62864c7070dbSScott Long 	iflib_filter_info_t info;
628723ac9029SStephen Hurd 	gtask_fn_t *fn;
6288b103855eSStephen Hurd 	int tqrid, err;
628995246abbSSean Bruno 	driver_filter_t *intr_fast;
62904c7070dbSScott Long 	void *q;
62914c7070dbSScott Long 
62924c7070dbSScott Long 	info = &ctx->ifc_filter_info;
6293add6f7d0SSean Bruno 	tqrid = rid;
62944c7070dbSScott Long 
62954c7070dbSScott Long 	switch (type) {
62964c7070dbSScott Long 	/* XXX merge tx/rx for netmap? */
62974c7070dbSScott Long 	case IFLIB_INTR_TX:
62984c7070dbSScott Long 		q = &ctx->ifc_txqs[qid];
62994c7070dbSScott Long 		info = &ctx->ifc_txqs[qid].ift_filter_info;
63004c7070dbSScott Long 		gtask = &ctx->ifc_txqs[qid].ift_task;
6301ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
63024c7070dbSScott Long 		fn = _task_fn_tx;
630395246abbSSean Bruno 		intr_fast = iflib_fast_intr;
6304da69b8f9SSean Bruno 		GROUPTASK_INIT(gtask, 0, fn, q);
63055ee36c68SStephen Hurd 		ctx->ifc_flags |= IFC_NETMAP_TX_IRQ;
63064c7070dbSScott Long 		break;
63074c7070dbSScott Long 	case IFLIB_INTR_RX:
63084c7070dbSScott Long 		q = &ctx->ifc_rxqs[qid];
63094c7070dbSScott Long 		info = &ctx->ifc_rxqs[qid].ifr_filter_info;
63104c7070dbSScott Long 		gtask = &ctx->ifc_rxqs[qid].ifr_task;
6311ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
63124c7070dbSScott Long 		fn = _task_fn_rx;
6313ab2e3f79SStephen Hurd 		intr_fast = iflib_fast_intr;
63146c3e93cbSGleb Smirnoff 		NET_GROUPTASK_INIT(gtask, 0, fn, q);
631595246abbSSean Bruno 		break;
631695246abbSSean Bruno 	case IFLIB_INTR_RXTX:
631795246abbSSean Bruno 		q = &ctx->ifc_rxqs[qid];
631895246abbSSean Bruno 		info = &ctx->ifc_rxqs[qid].ifr_filter_info;
631995246abbSSean Bruno 		gtask = &ctx->ifc_rxqs[qid].ifr_task;
6320ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
632195246abbSSean Bruno 		fn = _task_fn_rx;
632295246abbSSean Bruno 		intr_fast = iflib_fast_intr_rxtx;
63236c3e93cbSGleb Smirnoff 		NET_GROUPTASK_INIT(gtask, 0, fn, q);
63244c7070dbSScott Long 		break;
63254c7070dbSScott Long 	case IFLIB_INTR_ADMIN:
63264c7070dbSScott Long 		q = ctx;
6327da69b8f9SSean Bruno 		tqrid = -1;
63284c7070dbSScott Long 		info = &ctx->ifc_filter_info;
63294c7070dbSScott Long 		gtask = &ctx->ifc_admin_task;
6330ab2e3f79SStephen Hurd 		tqg = qgroup_if_config_tqg;
63314c7070dbSScott Long 		fn = _task_fn_admin;
633295246abbSSean Bruno 		intr_fast = iflib_fast_intr_ctx;
63334c7070dbSScott Long 		break;
63344c7070dbSScott Long 	default:
63353d10e9edSMarius Strobl 		device_printf(ctx->ifc_dev, "%s: unknown net intr type\n",
63363d10e9edSMarius Strobl 		    __func__);
63373d10e9edSMarius Strobl 		return (EINVAL);
63384c7070dbSScott Long 	}
63394c7070dbSScott Long 
63404c7070dbSScott Long 	info->ifi_filter = filter;
63414c7070dbSScott Long 	info->ifi_filter_arg = filter_arg;
63424c7070dbSScott Long 	info->ifi_task = gtask;
634395246abbSSean Bruno 	info->ifi_ctx = q;
63444c7070dbSScott Long 
6345f855ec81SMarius Strobl 	dev = ctx->ifc_dev;
634695246abbSSean Bruno 	err = _iflib_irq_alloc(ctx, irq, rid, intr_fast, NULL, info,  name);
6347da69b8f9SSean Bruno 	if (err != 0) {
6348f855ec81SMarius Strobl 		device_printf(dev, "_iflib_irq_alloc failed %d\n", err);
63494c7070dbSScott Long 		return (err);
6350da69b8f9SSean Bruno 	}
6351da69b8f9SSean Bruno 	if (type == IFLIB_INTR_ADMIN)
6352da69b8f9SSean Bruno 		return (0);
6353da69b8f9SSean Bruno 
63544c7070dbSScott Long 	if (tqrid != -1) {
6355ca7005f1SPatrick Kelsey 		err = iflib_irq_set_affinity(ctx, irq, type, qid, gtask, tqg, q,
6356ca7005f1SPatrick Kelsey 		    name);
6357b103855eSStephen Hurd 		if (err)
6358b103855eSStephen Hurd 			return (err);
6359aa3c5dd8SSean Bruno 	} else {
6360f855ec81SMarius Strobl 		taskqgroup_attach(tqg, gtask, q, dev, irq->ii_res, name);
6361aa3c5dd8SSean Bruno 	}
63624c7070dbSScott Long 
63634c7070dbSScott Long 	return (0);
63644c7070dbSScott Long }
63654c7070dbSScott Long 
63664c7070dbSScott Long void
63673e0e6330SStephen Hurd iflib_softirq_alloc_generic(if_ctx_t ctx, if_irq_t irq, iflib_intr_type_t type, void *arg, int qid, const char *name)
63684c7070dbSScott Long {
6369ca7005f1SPatrick Kelsey 	device_t dev;
63704c7070dbSScott Long 	struct grouptask *gtask;
63714c7070dbSScott Long 	struct taskqgroup *tqg;
637223ac9029SStephen Hurd 	gtask_fn_t *fn;
63734c7070dbSScott Long 	void *q;
6374b103855eSStephen Hurd 	int err;
63754c7070dbSScott Long 
63764c7070dbSScott Long 	switch (type) {
63774c7070dbSScott Long 	case IFLIB_INTR_TX:
63784c7070dbSScott Long 		q = &ctx->ifc_txqs[qid];
63794c7070dbSScott Long 		gtask = &ctx->ifc_txqs[qid].ift_task;
6380ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
63814c7070dbSScott Long 		fn = _task_fn_tx;
6382f98977b5SHans Petter Selasky 		GROUPTASK_INIT(gtask, 0, fn, q);
63834c7070dbSScott Long 		break;
63844c7070dbSScott Long 	case IFLIB_INTR_RX:
63854c7070dbSScott Long 		q = &ctx->ifc_rxqs[qid];
63864c7070dbSScott Long 		gtask = &ctx->ifc_rxqs[qid].ifr_task;
6387ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
63884c7070dbSScott Long 		fn = _task_fn_rx;
6389f98977b5SHans Petter Selasky 		NET_GROUPTASK_INIT(gtask, 0, fn, q);
63904c7070dbSScott Long 		break;
63914c7070dbSScott Long 	case IFLIB_INTR_IOV:
63924c7070dbSScott Long 		q = ctx;
63934c7070dbSScott Long 		gtask = &ctx->ifc_vflr_task;
6394ab2e3f79SStephen Hurd 		tqg = qgroup_if_config_tqg;
63954c7070dbSScott Long 		fn = _task_fn_iov;
6396f98977b5SHans Petter Selasky 		GROUPTASK_INIT(gtask, 0, fn, q);
63974c7070dbSScott Long 		break;
63984c7070dbSScott Long 	default:
63994c7070dbSScott Long 		panic("unknown net intr type");
64004c7070dbSScott Long 	}
6401ca7005f1SPatrick Kelsey 	err = iflib_irq_set_affinity(ctx, irq, type, qid, gtask, tqg, q, name);
6402ca7005f1SPatrick Kelsey 	if (err) {
6403ca7005f1SPatrick Kelsey 		dev = ctx->ifc_dev;
6404ca7005f1SPatrick Kelsey 		taskqgroup_attach(tqg, gtask, q, dev, irq ? irq->ii_res : NULL,
6405ca7005f1SPatrick Kelsey 		    name);
6406b103855eSStephen Hurd 	}
6407b103855eSStephen Hurd }
64084c7070dbSScott Long 
64094c7070dbSScott Long void
64104c7070dbSScott Long iflib_irq_free(if_ctx_t ctx, if_irq_t irq)
64114c7070dbSScott Long {
6412b97de13aSMarius Strobl 
64134c7070dbSScott Long 	if (irq->ii_tag)
64144c7070dbSScott Long 		bus_teardown_intr(ctx->ifc_dev, irq->ii_res, irq->ii_tag);
64154c7070dbSScott Long 
64164c7070dbSScott Long 	if (irq->ii_res)
6417b97de13aSMarius Strobl 		bus_release_resource(ctx->ifc_dev, SYS_RES_IRQ,
6418b97de13aSMarius Strobl 		    rman_get_rid(irq->ii_res), irq->ii_res);
64194c7070dbSScott Long }
64204c7070dbSScott Long 
64214c7070dbSScott Long static int
64223e0e6330SStephen Hurd iflib_legacy_setup(if_ctx_t ctx, driver_filter_t filter, void *filter_arg, int *rid, const char *name)
64234c7070dbSScott Long {
64244c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
64254c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
64264c7070dbSScott Long 	if_irq_t irq = &ctx->ifc_legacy_irq;
64274c7070dbSScott Long 	iflib_filter_info_t info;
6428f855ec81SMarius Strobl 	device_t dev;
64294c7070dbSScott Long 	struct grouptask *gtask;
6430f855ec81SMarius Strobl 	struct resource *res;
64314c7070dbSScott Long 	struct taskqgroup *tqg;
64324c7070dbSScott Long 	void *q;
6433d49e83eaSMarius Strobl 	int err, tqrid;
643441669133SMark Johnston 	bool rx_only;
64354c7070dbSScott Long 
64364c7070dbSScott Long 	q = &ctx->ifc_rxqs[0];
64374c7070dbSScott Long 	info = &rxq[0].ifr_filter_info;
64384c7070dbSScott Long 	gtask = &rxq[0].ifr_task;
6439ab2e3f79SStephen Hurd 	tqg = qgroup_if_io_tqg;
6440d49e83eaSMarius Strobl 	tqrid = *rid;
644141669133SMark Johnston 	rx_only = (ctx->ifc_sctx->isc_flags & IFLIB_SINGLE_IRQ_RX_ONLY) != 0;
64424c7070dbSScott Long 
64434c7070dbSScott Long 	ctx->ifc_flags |= IFC_LEGACY;
64444c7070dbSScott Long 	info->ifi_filter = filter;
64454c7070dbSScott Long 	info->ifi_filter_arg = filter_arg;
64464c7070dbSScott Long 	info->ifi_task = gtask;
644741669133SMark Johnston 	info->ifi_ctx = rx_only ? ctx : q;
64484c7070dbSScott Long 
6449f855ec81SMarius Strobl 	dev = ctx->ifc_dev;
64504c7070dbSScott Long 	/* We allocate a single interrupt resource */
645141669133SMark Johnston 	err = _iflib_irq_alloc(ctx, irq, tqrid, rx_only ? iflib_fast_intr_ctx :
645241669133SMark Johnston 	    iflib_fast_intr_rxtx, NULL, info, name);
645341669133SMark Johnston 	if (err != 0)
64544c7070dbSScott Long 		return (err);
6455f98977b5SHans Petter Selasky 	NET_GROUPTASK_INIT(gtask, 0, _task_fn_rx, q);
6456f855ec81SMarius Strobl 	res = irq->ii_res;
6457f855ec81SMarius Strobl 	taskqgroup_attach(tqg, gtask, q, dev, res, name);
64584c7070dbSScott Long 
64594c7070dbSScott Long 	GROUPTASK_INIT(&txq->ift_task, 0, _task_fn_tx, txq);
6460f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_io_tqg, &txq->ift_task, txq, dev, res,
6461f855ec81SMarius Strobl 	    "tx");
64624c7070dbSScott Long 	return (0);
64634c7070dbSScott Long }
64644c7070dbSScott Long 
64654c7070dbSScott Long void
64664c7070dbSScott Long iflib_led_create(if_ctx_t ctx)
64674c7070dbSScott Long {
64684c7070dbSScott Long 
64694c7070dbSScott Long 	ctx->ifc_led_dev = led_create(iflib_led_func, ctx,
64704c7070dbSScott Long 	    device_get_nameunit(ctx->ifc_dev));
64714c7070dbSScott Long }
64724c7070dbSScott Long 
64734c7070dbSScott Long void
64744c7070dbSScott Long iflib_tx_intr_deferred(if_ctx_t ctx, int txqid)
64754c7070dbSScott Long {
64764c7070dbSScott Long 
64774c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_txqs[txqid].ift_task);
64784c7070dbSScott Long }
64794c7070dbSScott Long 
64804c7070dbSScott Long void
64814c7070dbSScott Long iflib_rx_intr_deferred(if_ctx_t ctx, int rxqid)
64824c7070dbSScott Long {
64834c7070dbSScott Long 
64844c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_rxqs[rxqid].ifr_task);
64854c7070dbSScott Long }
64864c7070dbSScott Long 
64874c7070dbSScott Long void
64884c7070dbSScott Long iflib_admin_intr_deferred(if_ctx_t ctx)
64894c7070dbSScott Long {
649046fa0c25SEric Joyner 
6491ed6611ccSEd Maste 	MPASS(ctx->ifc_admin_task.gt_taskqueue != NULL);
64924c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_admin_task);
64934c7070dbSScott Long }
64944c7070dbSScott Long 
64954c7070dbSScott Long void
64964c7070dbSScott Long iflib_iov_intr_deferred(if_ctx_t ctx)
64974c7070dbSScott Long {
64984c7070dbSScott Long 
64994c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_vflr_task);
65004c7070dbSScott Long }
65014c7070dbSScott Long 
65024c7070dbSScott Long void
6503d49e83eaSMarius Strobl iflib_io_tqg_attach(struct grouptask *gt, void *uniq, int cpu, const char *name)
65044c7070dbSScott Long {
65054c7070dbSScott Long 
6506f855ec81SMarius Strobl 	taskqgroup_attach_cpu(qgroup_if_io_tqg, gt, uniq, cpu, NULL, NULL,
6507f855ec81SMarius Strobl 	    name);
65084c7070dbSScott Long }
65094c7070dbSScott Long 
65104c7070dbSScott Long void
6511aa8a24d3SStephen Hurd iflib_config_gtask_init(void *ctx, struct grouptask *gtask, gtask_fn_t *fn,
6512aa8a24d3SStephen Hurd 	const char *name)
65134c7070dbSScott Long {
65144c7070dbSScott Long 
65154c7070dbSScott Long 	GROUPTASK_INIT(gtask, 0, fn, ctx);
6516f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_config_tqg, gtask, gtask, NULL, NULL,
6517f855ec81SMarius Strobl 	    name);
65184c7070dbSScott Long }
65194c7070dbSScott Long 
65204c7070dbSScott Long void
652123ac9029SStephen Hurd iflib_config_gtask_deinit(struct grouptask *gtask)
652223ac9029SStephen Hurd {
652323ac9029SStephen Hurd 
6524ab2e3f79SStephen Hurd 	taskqgroup_detach(qgroup_if_config_tqg, gtask);
652523ac9029SStephen Hurd }
652623ac9029SStephen Hurd 
652723ac9029SStephen Hurd void
652823ac9029SStephen Hurd iflib_link_state_change(if_ctx_t ctx, int link_state, uint64_t baudrate)
65294c7070dbSScott Long {
65304c7070dbSScott Long 	if_t ifp = ctx->ifc_ifp;
65314c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
65324c7070dbSScott Long 
65334c7070dbSScott Long 	if_setbaudrate(ifp, baudrate);
65347b610b60SSean Bruno 	if (baudrate >= IF_Gbps(10)) {
65357b610b60SSean Bruno 		STATE_LOCK(ctx);
653695246abbSSean Bruno 		ctx->ifc_flags |= IFC_PREFETCH;
65377b610b60SSean Bruno 		STATE_UNLOCK(ctx);
65387b610b60SSean Bruno 	}
65394c7070dbSScott Long 	/* If link down, disable watchdog */
65404c7070dbSScott Long 	if ((ctx->ifc_link_state == LINK_STATE_UP) && (link_state == LINK_STATE_DOWN)) {
65414c7070dbSScott Long 		for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxqsets; i++, txq++)
65424c7070dbSScott Long 			txq->ift_qstatus = IFLIB_QUEUE_IDLE;
65434c7070dbSScott Long 	}
65444c7070dbSScott Long 	ctx->ifc_link_state = link_state;
65454c7070dbSScott Long 	if_link_state_change(ifp, link_state);
65464c7070dbSScott Long }
65474c7070dbSScott Long 
65484c7070dbSScott Long static int
65494c7070dbSScott Long iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq)
65504c7070dbSScott Long {
65514c7070dbSScott Long 	int credits;
65521248952aSSean Bruno #ifdef INVARIANTS
65531248952aSSean Bruno 	int credits_pre = txq->ift_cidx_processed;
65541248952aSSean Bruno #endif
65554c7070dbSScott Long 
65568a04b53dSKonstantin Belousov 	bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
65578a04b53dSKonstantin Belousov 	    BUS_DMASYNC_POSTREAD);
655895246abbSSean Bruno 	if ((credits = ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, true)) == 0)
65594c7070dbSScott Long 		return (0);
65604c7070dbSScott Long 
65614c7070dbSScott Long 	txq->ift_processed += credits;
65624c7070dbSScott Long 	txq->ift_cidx_processed += credits;
65634c7070dbSScott Long 
65641248952aSSean Bruno 	MPASS(credits_pre + credits == txq->ift_cidx_processed);
65654c7070dbSScott Long 	if (txq->ift_cidx_processed >= txq->ift_size)
65664c7070dbSScott Long 		txq->ift_cidx_processed -= txq->ift_size;
65674c7070dbSScott Long 	return (credits);
65684c7070dbSScott Long }
65694c7070dbSScott Long 
65704c7070dbSScott Long static int
657195246abbSSean Bruno iflib_rxd_avail(if_ctx_t ctx, iflib_rxq_t rxq, qidx_t cidx, qidx_t budget)
65724c7070dbSScott Long {
657395dcf343SMarius Strobl 	iflib_fl_t fl;
657495dcf343SMarius Strobl 	u_int i;
65754c7070dbSScott Long 
657695dcf343SMarius Strobl 	for (i = 0, fl = &rxq->ifr_fl[0]; i < rxq->ifr_nfl; i++, fl++)
657795dcf343SMarius Strobl 		bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
657895dcf343SMarius Strobl 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
657923ac9029SStephen Hurd 	return (ctx->isc_rxd_available(ctx->ifc_softc, rxq->ifr_id, cidx,
658023ac9029SStephen Hurd 	    budget));
65814c7070dbSScott Long }
65824c7070dbSScott Long 
65834c7070dbSScott Long void
65844c7070dbSScott Long iflib_add_int_delay_sysctl(if_ctx_t ctx, const char *name,
65854c7070dbSScott Long 	const char *description, if_int_delay_info_t info,
65864c7070dbSScott Long 	int offset, int value)
65874c7070dbSScott Long {
65884c7070dbSScott Long 	info->iidi_ctx = ctx;
65894c7070dbSScott Long 	info->iidi_offset = offset;
65904c7070dbSScott Long 	info->iidi_value = value;
65914c7070dbSScott Long 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(ctx->ifc_dev),
65924c7070dbSScott Long 	    SYSCTL_CHILDREN(device_get_sysctl_tree(ctx->ifc_dev)),
65937029da5cSPawel Biernacki 	    OID_AUTO, name, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
65944c7070dbSScott Long 	    info, 0, iflib_sysctl_int_delay, "I", description);
65954c7070dbSScott Long }
65964c7070dbSScott Long 
6597aa8a24d3SStephen Hurd struct sx *
65984c7070dbSScott Long iflib_ctx_lock_get(if_ctx_t ctx)
65994c7070dbSScott Long {
66004c7070dbSScott Long 
6601aa8a24d3SStephen Hurd 	return (&ctx->ifc_ctx_sx);
66024c7070dbSScott Long }
66034c7070dbSScott Long 
66044c7070dbSScott Long static int
66054c7070dbSScott Long iflib_msix_init(if_ctx_t ctx)
66064c7070dbSScott Long {
66074c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
66084c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
66094c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
66103d10e9edSMarius Strobl 	int admincnt, bar, err, iflib_num_rx_queues, iflib_num_tx_queues;
66113d10e9edSMarius Strobl 	int msgs, queuemsgs, queues, rx_queues, tx_queues, vectors;
66124c7070dbSScott Long 
6613d2735264SStephen Hurd 	iflib_num_tx_queues = ctx->ifc_sysctl_ntxqs;
6614d2735264SStephen Hurd 	iflib_num_rx_queues = ctx->ifc_sysctl_nrxqs;
661523ac9029SStephen Hurd 
6616b97de13aSMarius Strobl 	if (bootverbose)
6617b97de13aSMarius Strobl 		device_printf(dev, "msix_init qsets capped at %d\n",
6618b97de13aSMarius Strobl 		    imax(scctx->isc_ntxqsets, scctx->isc_nrxqsets));
66191248952aSSean Bruno 
66204c7070dbSScott Long 	/* Override by tuneable */
6621ea351d3fSSean Bruno 	if (scctx->isc_disable_msix)
66224c7070dbSScott Long 		goto msi;
66234c7070dbSScott Long 
6624b97de13aSMarius Strobl 	/* First try MSI-X */
6625b97de13aSMarius Strobl 	if ((msgs = pci_msix_count(dev)) == 0) {
6626b97de13aSMarius Strobl 		if (bootverbose)
6627b97de13aSMarius Strobl 			device_printf(dev, "MSI-X not supported or disabled\n");
6628b97de13aSMarius Strobl 		goto msi;
6629b97de13aSMarius Strobl 	}
66303d10e9edSMarius Strobl 
66313d10e9edSMarius Strobl 	bar = ctx->ifc_softc_ctx.isc_msix_bar;
66324c7070dbSScott Long 	/*
66334c7070dbSScott Long 	 * bar == -1 => "trust me I know what I'm doing"
66344c7070dbSScott Long 	 * Some drivers are for hardware that is so shoddily
66354c7070dbSScott Long 	 * documented that no one knows which bars are which
66364c7070dbSScott Long 	 * so the developer has to map all bars. This hack
6637b97de13aSMarius Strobl 	 * allows shoddy garbage to use MSI-X in this framework.
66384c7070dbSScott Long 	 */
66394c7070dbSScott Long 	if (bar != -1) {
66404c7070dbSScott Long 		ctx->ifc_msix_mem = bus_alloc_resource_any(dev,
66414c7070dbSScott Long 	            SYS_RES_MEMORY, &bar, RF_ACTIVE);
66424c7070dbSScott Long 		if (ctx->ifc_msix_mem == NULL) {
6643b97de13aSMarius Strobl 			device_printf(dev, "Unable to map MSI-X table\n");
66444c7070dbSScott Long 			goto msi;
66454c7070dbSScott Long 		}
66464c7070dbSScott Long 	}
66473d10e9edSMarius Strobl 
66483d10e9edSMarius Strobl 	admincnt = sctx->isc_admin_intrcnt;
66494c7070dbSScott Long #if IFLIB_DEBUG
66504c7070dbSScott Long 	/* use only 1 qset in debug mode */
66514c7070dbSScott Long 	queuemsgs = min(msgs - admincnt, 1);
66524c7070dbSScott Long #else
66534c7070dbSScott Long 	queuemsgs = msgs - admincnt;
66544c7070dbSScott Long #endif
66554c7070dbSScott Long #ifdef RSS
66564c7070dbSScott Long 	queues = imin(queuemsgs, rss_getnumbuckets());
66574c7070dbSScott Long #else
66584c7070dbSScott Long 	queues = queuemsgs;
66594c7070dbSScott Long #endif
66604c7070dbSScott Long 	queues = imin(CPU_COUNT(&ctx->ifc_cpus), queues);
6661b97de13aSMarius Strobl 	if (bootverbose)
6662b97de13aSMarius Strobl 		device_printf(dev,
6663b97de13aSMarius Strobl 		    "intr CPUs: %d queue msgs: %d admincnt: %d\n",
66644c7070dbSScott Long 		    CPU_COUNT(&ctx->ifc_cpus), queuemsgs, admincnt);
66654c7070dbSScott Long #ifdef  RSS
66664c7070dbSScott Long 	/* If we're doing RSS, clamp at the number of RSS buckets */
66674c7070dbSScott Long 	if (queues > rss_getnumbuckets())
66684c7070dbSScott Long 		queues = rss_getnumbuckets();
66694c7070dbSScott Long #endif
667023ac9029SStephen Hurd 	if (iflib_num_rx_queues > 0 && iflib_num_rx_queues < queuemsgs - admincnt)
667123ac9029SStephen Hurd 		rx_queues = iflib_num_rx_queues;
66724c7070dbSScott Long 	else
66734c7070dbSScott Long 		rx_queues = queues;
6674d2735264SStephen Hurd 
6675d2735264SStephen Hurd 	if (rx_queues > scctx->isc_nrxqsets)
6676d2735264SStephen Hurd 		rx_queues = scctx->isc_nrxqsets;
6677d2735264SStephen Hurd 
667823ac9029SStephen Hurd 	/*
667923ac9029SStephen Hurd 	 * We want this to be all logical CPUs by default
668023ac9029SStephen Hurd 	 */
66814c7070dbSScott Long 	if (iflib_num_tx_queues > 0 && iflib_num_tx_queues < queues)
66824c7070dbSScott Long 		tx_queues = iflib_num_tx_queues;
66834c7070dbSScott Long 	else
668423ac9029SStephen Hurd 		tx_queues = mp_ncpus;
668523ac9029SStephen Hurd 
6686d2735264SStephen Hurd 	if (tx_queues > scctx->isc_ntxqsets)
6687d2735264SStephen Hurd 		tx_queues = scctx->isc_ntxqsets;
6688d2735264SStephen Hurd 
668923ac9029SStephen Hurd 	if (ctx->ifc_sysctl_qs_eq_override == 0) {
669023ac9029SStephen Hurd #ifdef INVARIANTS
669123ac9029SStephen Hurd 		if (tx_queues != rx_queues)
669277c1fcecSEric Joyner 			device_printf(dev,
669377c1fcecSEric Joyner 			    "queue equality override not set, capping rx_queues at %d and tx_queues at %d\n",
669423ac9029SStephen Hurd 			    min(rx_queues, tx_queues), min(rx_queues, tx_queues));
669523ac9029SStephen Hurd #endif
669623ac9029SStephen Hurd 		tx_queues = min(rx_queues, tx_queues);
669723ac9029SStephen Hurd 		rx_queues = min(rx_queues, tx_queues);
669823ac9029SStephen Hurd 	}
66994c7070dbSScott Long 
67003d10e9edSMarius Strobl 	vectors = rx_queues + admincnt;
67013d10e9edSMarius Strobl 	if (msgs < vectors) {
67023d10e9edSMarius Strobl 		device_printf(dev,
67033d10e9edSMarius Strobl 		    "insufficient number of MSI-X vectors "
67043d10e9edSMarius Strobl 		    "(supported %d, need %d)\n", msgs, vectors);
67053d10e9edSMarius Strobl 		goto msi;
67063d10e9edSMarius Strobl 	}
67073d10e9edSMarius Strobl 
67081722eeacSMarius Strobl 	device_printf(dev, "Using %d RX queues %d TX queues\n", rx_queues,
67091722eeacSMarius Strobl 	    tx_queues);
67103d10e9edSMarius Strobl 	msgs = vectors;
67114c7070dbSScott Long 	if ((err = pci_alloc_msix(dev, &vectors)) == 0) {
67123d10e9edSMarius Strobl 		if (vectors != msgs) {
67133d10e9edSMarius Strobl 			device_printf(dev,
67143d10e9edSMarius Strobl 			    "Unable to allocate sufficient MSI-X vectors "
67153d10e9edSMarius Strobl 			    "(got %d, need %d)\n", vectors, msgs);
67163d10e9edSMarius Strobl 			pci_release_msi(dev);
67173d10e9edSMarius Strobl 			if (bar != -1) {
67183d10e9edSMarius Strobl 				bus_release_resource(dev, SYS_RES_MEMORY, bar,
67193d10e9edSMarius Strobl 				    ctx->ifc_msix_mem);
67203d10e9edSMarius Strobl 				ctx->ifc_msix_mem = NULL;
67213d10e9edSMarius Strobl 			}
67223d10e9edSMarius Strobl 			goto msi;
67233d10e9edSMarius Strobl 		}
6724b97de13aSMarius Strobl 		device_printf(dev, "Using MSI-X interrupts with %d vectors\n",
6725b97de13aSMarius Strobl 		    vectors);
67264c7070dbSScott Long 		scctx->isc_vectors = vectors;
67274c7070dbSScott Long 		scctx->isc_nrxqsets = rx_queues;
67284c7070dbSScott Long 		scctx->isc_ntxqsets = tx_queues;
67294c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_MSIX;
673023ac9029SStephen Hurd 
67314c7070dbSScott Long 		return (vectors);
67324c7070dbSScott Long 	} else {
673377c1fcecSEric Joyner 		device_printf(dev,
67343d10e9edSMarius Strobl 		    "failed to allocate %d MSI-X vectors, err: %d\n", vectors,
67353d10e9edSMarius Strobl 		    err);
67363d10e9edSMarius Strobl 		if (bar != -1) {
6737e4defe55SMarius Strobl 			bus_release_resource(dev, SYS_RES_MEMORY, bar,
6738e4defe55SMarius Strobl 			    ctx->ifc_msix_mem);
6739e4defe55SMarius Strobl 			ctx->ifc_msix_mem = NULL;
67404c7070dbSScott Long 		}
67413d10e9edSMarius Strobl 	}
67423d10e9edSMarius Strobl 
67434c7070dbSScott Long msi:
67444c7070dbSScott Long 	vectors = pci_msi_count(dev);
67454c7070dbSScott Long 	scctx->isc_nrxqsets = 1;
67464c7070dbSScott Long 	scctx->isc_ntxqsets = 1;
67474c7070dbSScott Long 	scctx->isc_vectors = vectors;
67484c7070dbSScott Long 	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) {
67494c7070dbSScott Long 		device_printf(dev,"Using an MSI interrupt\n");
67504c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_MSI;
67514c7070dbSScott Long 	} else {
6752e4defe55SMarius Strobl 		scctx->isc_vectors = 1;
67534c7070dbSScott Long 		device_printf(dev,"Using a Legacy interrupt\n");
67544c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_LEGACY;
67554c7070dbSScott Long 	}
67564c7070dbSScott Long 
67574c7070dbSScott Long 	return (vectors);
67584c7070dbSScott Long }
67594c7070dbSScott Long 
6760e4defe55SMarius Strobl static const char *ring_states[] = { "IDLE", "BUSY", "STALLED", "ABDICATED" };
67614c7070dbSScott Long 
67624c7070dbSScott Long static int
67634c7070dbSScott Long mp_ring_state_handler(SYSCTL_HANDLER_ARGS)
67644c7070dbSScott Long {
67654c7070dbSScott Long 	int rc;
67664c7070dbSScott Long 	uint16_t *state = ((uint16_t *)oidp->oid_arg1);
67674c7070dbSScott Long 	struct sbuf *sb;
6768e4defe55SMarius Strobl 	const char *ring_state = "UNKNOWN";
67694c7070dbSScott Long 
67704c7070dbSScott Long 	/* XXX needed ? */
67714c7070dbSScott Long 	rc = sysctl_wire_old_buffer(req, 0);
67724c7070dbSScott Long 	MPASS(rc == 0);
67734c7070dbSScott Long 	if (rc != 0)
67744c7070dbSScott Long 		return (rc);
67754c7070dbSScott Long 	sb = sbuf_new_for_sysctl(NULL, NULL, 80, req);
67764c7070dbSScott Long 	MPASS(sb != NULL);
67774c7070dbSScott Long 	if (sb == NULL)
67784c7070dbSScott Long 		return (ENOMEM);
67794c7070dbSScott Long 	if (state[3] <= 3)
67804c7070dbSScott Long 		ring_state = ring_states[state[3]];
67814c7070dbSScott Long 
67824c7070dbSScott Long 	sbuf_printf(sb, "pidx_head: %04hd pidx_tail: %04hd cidx: %04hd state: %s",
67834c7070dbSScott Long 		    state[0], state[1], state[2], ring_state);
67844c7070dbSScott Long 	rc = sbuf_finish(sb);
67854c7070dbSScott Long 	sbuf_delete(sb);
67864c7070dbSScott Long         return(rc);
67874c7070dbSScott Long }
67884c7070dbSScott Long 
678923ac9029SStephen Hurd enum iflib_ndesc_handler {
679023ac9029SStephen Hurd 	IFLIB_NTXD_HANDLER,
679123ac9029SStephen Hurd 	IFLIB_NRXD_HANDLER,
679223ac9029SStephen Hurd };
67934c7070dbSScott Long 
679423ac9029SStephen Hurd static int
679523ac9029SStephen Hurd mp_ndesc_handler(SYSCTL_HANDLER_ARGS)
679623ac9029SStephen Hurd {
679723ac9029SStephen Hurd 	if_ctx_t ctx = (void *)arg1;
679823ac9029SStephen Hurd 	enum iflib_ndesc_handler type = arg2;
679923ac9029SStephen Hurd 	char buf[256] = {0};
680095246abbSSean Bruno 	qidx_t *ndesc;
680123ac9029SStephen Hurd 	char *p, *next;
680223ac9029SStephen Hurd 	int nqs, rc, i;
680323ac9029SStephen Hurd 
680423ac9029SStephen Hurd 	nqs = 8;
680523ac9029SStephen Hurd 	switch(type) {
680623ac9029SStephen Hurd 	case IFLIB_NTXD_HANDLER:
680723ac9029SStephen Hurd 		ndesc = ctx->ifc_sysctl_ntxds;
680823ac9029SStephen Hurd 		if (ctx->ifc_sctx)
680923ac9029SStephen Hurd 			nqs = ctx->ifc_sctx->isc_ntxqs;
681023ac9029SStephen Hurd 		break;
681123ac9029SStephen Hurd 	case IFLIB_NRXD_HANDLER:
681223ac9029SStephen Hurd 		ndesc = ctx->ifc_sysctl_nrxds;
681323ac9029SStephen Hurd 		if (ctx->ifc_sctx)
681423ac9029SStephen Hurd 			nqs = ctx->ifc_sctx->isc_nrxqs;
681523ac9029SStephen Hurd 		break;
68161ae4848cSMatt Macy 	default:
68173d10e9edSMarius Strobl 		printf("%s: unhandled type\n", __func__);
68183d10e9edSMarius Strobl 		return (EINVAL);
681923ac9029SStephen Hurd 	}
682023ac9029SStephen Hurd 	if (nqs == 0)
682123ac9029SStephen Hurd 		nqs = 8;
682223ac9029SStephen Hurd 
682323ac9029SStephen Hurd 	for (i=0; i<8; i++) {
682423ac9029SStephen Hurd 		if (i >= nqs)
682523ac9029SStephen Hurd 			break;
682623ac9029SStephen Hurd 		if (i)
682723ac9029SStephen Hurd 			strcat(buf, ",");
682823ac9029SStephen Hurd 		sprintf(strchr(buf, 0), "%d", ndesc[i]);
682923ac9029SStephen Hurd 	}
683023ac9029SStephen Hurd 
683123ac9029SStephen Hurd 	rc = sysctl_handle_string(oidp, buf, sizeof(buf), req);
683223ac9029SStephen Hurd 	if (rc || req->newptr == NULL)
683323ac9029SStephen Hurd 		return rc;
683423ac9029SStephen Hurd 
683523ac9029SStephen Hurd 	for (i = 0, next = buf, p = strsep(&next, " ,"); i < 8 && p;
683623ac9029SStephen Hurd 	    i++, p = strsep(&next, " ,")) {
683723ac9029SStephen Hurd 		ndesc[i] = strtoul(p, NULL, 10);
683823ac9029SStephen Hurd 	}
683923ac9029SStephen Hurd 
684023ac9029SStephen Hurd 	return(rc);
684123ac9029SStephen Hurd }
68424c7070dbSScott Long 
68434c7070dbSScott Long #define NAME_BUFLEN 32
68444c7070dbSScott Long static void
68454c7070dbSScott Long iflib_add_device_sysctl_pre(if_ctx_t ctx)
68464c7070dbSScott Long {
68474c7070dbSScott Long         device_t dev = iflib_get_dev(ctx);
68484c7070dbSScott Long 	struct sysctl_oid_list *child, *oid_list;
68494c7070dbSScott Long 	struct sysctl_ctx_list *ctx_list;
68504c7070dbSScott Long 	struct sysctl_oid *node;
68514c7070dbSScott Long 
68524c7070dbSScott Long 	ctx_list = device_get_sysctl_ctx(dev);
68534c7070dbSScott Long 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
68544c7070dbSScott Long 	ctx->ifc_sysctl_node = node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, "iflib",
68557029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "IFLIB fields");
68564c7070dbSScott Long 	oid_list = SYSCTL_CHILDREN(node);
68574c7070dbSScott Long 
685810a1e981SEric Joyner 	SYSCTL_ADD_CONST_STRING(ctx_list, oid_list, OID_AUTO, "driver_version",
685910a1e981SEric Joyner 		       CTLFLAG_RD, ctx->ifc_sctx->isc_driver_version,
686023ac9029SStephen Hurd 		       "driver version");
686123ac9029SStephen Hurd 
68624c7070dbSScott Long 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_ntxqs",
68634c7070dbSScott Long 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_ntxqs, 0,
68644c7070dbSScott Long 			"# of txqs to use, 0 => use default #");
68654c7070dbSScott Long 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_nrxqs",
686623ac9029SStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_nrxqs, 0,
686723ac9029SStephen Hurd 			"# of rxqs to use, 0 => use default #");
686823ac9029SStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_qs_enable",
686923ac9029SStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_qs_eq_override, 0,
687023ac9029SStephen Hurd                        "permit #txq != #rxq");
6871ea351d3fSSean Bruno 	SYSCTL_ADD_INT(ctx_list, oid_list, OID_AUTO, "disable_msix",
6872ea351d3fSSean Bruno                       CTLFLAG_RWTUN, &ctx->ifc_softc_ctx.isc_disable_msix, 0,
6873b97de13aSMarius Strobl                       "disable MSI-X (default 0)");
6874f4d2154eSStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "rx_budget",
6875f4d2154eSStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_rx_budget, 0,
68761722eeacSMarius Strobl 		       "set the RX budget");
6877fe51d4cdSStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "tx_abdicate",
6878fe51d4cdSStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_tx_abdicate, 0,
68791722eeacSMarius Strobl 		       "cause TX to abdicate instead of running to completion");
6880f154ece0SStephen Hurd 	ctx->ifc_sysctl_core_offset = CORE_OFFSET_UNSPECIFIED;
6881f154ece0SStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "core_offset",
6882f154ece0SStephen Hurd 		       CTLFLAG_RDTUN, &ctx->ifc_sysctl_core_offset, 0,
6883f154ece0SStephen Hurd 		       "offset to start using cores at");
6884f154ece0SStephen Hurd 	SYSCTL_ADD_U8(ctx_list, oid_list, OID_AUTO, "separate_txrx",
6885f154ece0SStephen Hurd 		       CTLFLAG_RDTUN, &ctx->ifc_sysctl_separate_txrx, 0,
6886f154ece0SStephen Hurd 		       "use separate cores for TX and RX");
6887ca7005f1SPatrick Kelsey 	SYSCTL_ADD_U8(ctx_list, oid_list, OID_AUTO, "use_logical_cores",
6888ca7005f1SPatrick Kelsey 		      CTLFLAG_RDTUN, &ctx->ifc_sysctl_use_logical_cores, 0,
6889ca7005f1SPatrick Kelsey 		      "try to make use of logical cores for TX and RX");
68904c7070dbSScott Long 
689123ac9029SStephen Hurd 	/* XXX change for per-queue sizes */
689223ac9029SStephen Hurd 	SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_ntxds",
68937029da5cSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, ctx,
68947029da5cSPawel Biernacki 	    IFLIB_NTXD_HANDLER, mp_ndesc_handler, "A",
68951722eeacSMarius Strobl 	    "list of # of TX descriptors to use, 0 = use default #");
689623ac9029SStephen Hurd 	SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_nrxds",
68977029da5cSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, ctx,
68987029da5cSPawel Biernacki 	    IFLIB_NRXD_HANDLER, mp_ndesc_handler, "A",
68991722eeacSMarius Strobl 	    "list of # of RX descriptors to use, 0 = use default #");
69004c7070dbSScott Long }
69014c7070dbSScott Long 
69024c7070dbSScott Long static void
69034c7070dbSScott Long iflib_add_device_sysctl_post(if_ctx_t ctx)
69044c7070dbSScott Long {
69054c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
69064c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
69074c7070dbSScott Long         device_t dev = iflib_get_dev(ctx);
69084c7070dbSScott Long 	struct sysctl_oid_list *child;
69094c7070dbSScott Long 	struct sysctl_ctx_list *ctx_list;
69104c7070dbSScott Long 	iflib_fl_t fl;
69114c7070dbSScott Long 	iflib_txq_t txq;
69124c7070dbSScott Long 	iflib_rxq_t rxq;
69134c7070dbSScott Long 	int i, j;
69144c7070dbSScott Long 	char namebuf[NAME_BUFLEN];
69154c7070dbSScott Long 	char *qfmt;
69164c7070dbSScott Long 	struct sysctl_oid *queue_node, *fl_node, *node;
69174c7070dbSScott Long 	struct sysctl_oid_list *queue_list, *fl_list;
69184c7070dbSScott Long 	ctx_list = device_get_sysctl_ctx(dev);
69194c7070dbSScott Long 
69204c7070dbSScott Long 	node = ctx->ifc_sysctl_node;
69214c7070dbSScott Long 	child = SYSCTL_CHILDREN(node);
69224c7070dbSScott Long 
69234c7070dbSScott Long 	if (scctx->isc_ntxqsets > 100)
69244c7070dbSScott Long 		qfmt = "txq%03d";
69254c7070dbSScott Long 	else if (scctx->isc_ntxqsets > 10)
69264c7070dbSScott Long 		qfmt = "txq%02d";
69274c7070dbSScott Long 	else
69284c7070dbSScott Long 		qfmt = "txq%d";
69294c7070dbSScott Long 	for (i = 0, txq = ctx->ifc_txqs; i < scctx->isc_ntxqsets; i++, txq++) {
69304c7070dbSScott Long 		snprintf(namebuf, NAME_BUFLEN, qfmt, i);
69314c7070dbSScott Long 		queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf,
69327029da5cSPawel Biernacki 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
69334c7070dbSScott Long 		queue_list = SYSCTL_CHILDREN(queue_node);
6934ca7005f1SPatrick Kelsey 		SYSCTL_ADD_INT(ctx_list, queue_list, OID_AUTO, "cpu",
6935ca7005f1SPatrick Kelsey 			       CTLFLAG_RD,
6936ca7005f1SPatrick Kelsey 			       &txq->ift_task.gt_cpu, 0, "cpu this queue is bound to");
69374c7070dbSScott Long #if MEMORY_LOGGING
69384c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_dequeued",
69394c7070dbSScott Long 				CTLFLAG_RD,
69404c7070dbSScott Long 				&txq->ift_dequeued, "total mbufs freed");
69414c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_enqueued",
69424c7070dbSScott Long 				CTLFLAG_RD,
69434c7070dbSScott Long 				&txq->ift_enqueued, "total mbufs enqueued");
69444c7070dbSScott Long #endif
69454c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "mbuf_defrag",
69464c7070dbSScott Long 				   CTLFLAG_RD,
69474c7070dbSScott Long 				   &txq->ift_mbuf_defrag, "# of times m_defrag was called");
69484c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "m_pullups",
69494c7070dbSScott Long 				   CTLFLAG_RD,
69504c7070dbSScott Long 				   &txq->ift_pullups, "# of times m_pullup was called");
69514c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "mbuf_defrag_failed",
69524c7070dbSScott Long 				   CTLFLAG_RD,
69534c7070dbSScott Long 				   &txq->ift_mbuf_defrag_failed, "# of times m_defrag failed");
69544c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "no_desc_avail",
69554c7070dbSScott Long 				   CTLFLAG_RD,
695623ac9029SStephen Hurd 				   &txq->ift_no_desc_avail, "# of times no descriptors were available");
69574c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "tx_map_failed",
69584c7070dbSScott Long 				   CTLFLAG_RD,
69591722eeacSMarius Strobl 				   &txq->ift_map_failed, "# of times DMA map failed");
69604c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txd_encap_efbig",
69614c7070dbSScott Long 				   CTLFLAG_RD,
69624c7070dbSScott Long 				   &txq->ift_txd_encap_efbig, "# of times txd_encap returned EFBIG");
69634c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "no_tx_dma_setup",
69644c7070dbSScott Long 				   CTLFLAG_RD,
69654c7070dbSScott Long 				   &txq->ift_no_tx_dma_setup, "# of times map failed for other than EFBIG");
69664c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_pidx",
69674c7070dbSScott Long 				   CTLFLAG_RD,
69684c7070dbSScott Long 				   &txq->ift_pidx, 1, "Producer Index");
69694c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_cidx",
69704c7070dbSScott Long 				   CTLFLAG_RD,
69714c7070dbSScott Long 				   &txq->ift_cidx, 1, "Consumer Index");
69724c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_cidx_processed",
69734c7070dbSScott Long 				   CTLFLAG_RD,
69744c7070dbSScott Long 				   &txq->ift_cidx_processed, 1, "Consumer Index seen by credit update");
69754c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_in_use",
69764c7070dbSScott Long 				   CTLFLAG_RD,
69774c7070dbSScott Long 				   &txq->ift_in_use, 1, "descriptors in use");
69784c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_processed",
69794c7070dbSScott Long 				   CTLFLAG_RD,
69804c7070dbSScott Long 				   &txq->ift_processed, "descriptors procesed for clean");
69814c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_cleaned",
69824c7070dbSScott Long 				   CTLFLAG_RD,
69834c7070dbSScott Long 				   &txq->ift_cleaned, "total cleaned");
69844c7070dbSScott Long 		SYSCTL_ADD_PROC(ctx_list, queue_list, OID_AUTO, "ring_state",
69857029da5cSPawel Biernacki 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
69867029da5cSPawel Biernacki 		    __DEVOLATILE(uint64_t *, &txq->ift_br->state), 0,
69877029da5cSPawel Biernacki 		    mp_ring_state_handler, "A", "soft ring state");
69884c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_enqueues",
698995246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->enqueues,
69904c7070dbSScott Long 				       "# of enqueues to the mp_ring for this queue");
69914c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_drops",
699295246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->drops,
69934c7070dbSScott Long 				       "# of drops in the mp_ring for this queue");
69944c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_starts",
699595246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->starts,
69964c7070dbSScott Long 				       "# of normal consumer starts in the mp_ring for this queue");
69974c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_stalls",
699895246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->stalls,
69994c7070dbSScott Long 					       "# of consumer stalls in the mp_ring for this queue");
70004c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_restarts",
700195246abbSSean Bruno 			       CTLFLAG_RD, &txq->ift_br->restarts,
70024c7070dbSScott Long 				       "# of consumer restarts in the mp_ring for this queue");
70034c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_abdications",
700495246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->abdications,
70054c7070dbSScott Long 				       "# of consumer abdications in the mp_ring for this queue");
70064c7070dbSScott Long 	}
70074c7070dbSScott Long 
70084c7070dbSScott Long 	if (scctx->isc_nrxqsets > 100)
70094c7070dbSScott Long 		qfmt = "rxq%03d";
70104c7070dbSScott Long 	else if (scctx->isc_nrxqsets > 10)
70114c7070dbSScott Long 		qfmt = "rxq%02d";
70124c7070dbSScott Long 	else
70134c7070dbSScott Long 		qfmt = "rxq%d";
70144c7070dbSScott Long 	for (i = 0, rxq = ctx->ifc_rxqs; i < scctx->isc_nrxqsets; i++, rxq++) {
70154c7070dbSScott Long 		snprintf(namebuf, NAME_BUFLEN, qfmt, i);
70164c7070dbSScott Long 		queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf,
70177029da5cSPawel Biernacki 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
70184c7070dbSScott Long 		queue_list = SYSCTL_CHILDREN(queue_node);
7019ca7005f1SPatrick Kelsey 		SYSCTL_ADD_INT(ctx_list, queue_list, OID_AUTO, "cpu",
7020ca7005f1SPatrick Kelsey 			       CTLFLAG_RD,
7021ca7005f1SPatrick Kelsey 			       &rxq->ifr_task.gt_cpu, 0, "cpu this queue is bound to");
702223ac9029SStephen Hurd 		if (sctx->isc_flags & IFLIB_HAS_RXCQ) {
70234c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "rxq_cq_cidx",
70244c7070dbSScott Long 				       CTLFLAG_RD,
70254c7070dbSScott Long 				       &rxq->ifr_cq_cidx, 1, "Consumer Index");
70264c7070dbSScott Long 		}
7027da69b8f9SSean Bruno 
70284c7070dbSScott Long 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) {
70294c7070dbSScott Long 			snprintf(namebuf, NAME_BUFLEN, "rxq_fl%d", j);
70304c7070dbSScott Long 			fl_node = SYSCTL_ADD_NODE(ctx_list, queue_list, OID_AUTO, namebuf,
70317029da5cSPawel Biernacki 			    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "freelist Name");
70324c7070dbSScott Long 			fl_list = SYSCTL_CHILDREN(fl_node);
70334c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "pidx",
70344c7070dbSScott Long 				       CTLFLAG_RD,
70354c7070dbSScott Long 				       &fl->ifl_pidx, 1, "Producer Index");
70364c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "cidx",
70374c7070dbSScott Long 				       CTLFLAG_RD,
70384c7070dbSScott Long 				       &fl->ifl_cidx, 1, "Consumer Index");
70394c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "credits",
70404c7070dbSScott Long 				       CTLFLAG_RD,
70414c7070dbSScott Long 				       &fl->ifl_credits, 1, "credits available");
7042b3813609SPatrick Kelsey 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "buf_size",
7043b3813609SPatrick Kelsey 				       CTLFLAG_RD,
7044b3813609SPatrick Kelsey 				       &fl->ifl_buf_size, 1, "buffer size");
70454c7070dbSScott Long #if MEMORY_LOGGING
70464c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_m_enqueued",
70474c7070dbSScott Long 					CTLFLAG_RD,
70484c7070dbSScott Long 					&fl->ifl_m_enqueued, "mbufs allocated");
70494c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_m_dequeued",
70504c7070dbSScott Long 					CTLFLAG_RD,
70514c7070dbSScott Long 					&fl->ifl_m_dequeued, "mbufs freed");
70524c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_cl_enqueued",
70534c7070dbSScott Long 					CTLFLAG_RD,
70544c7070dbSScott Long 					&fl->ifl_cl_enqueued, "clusters allocated");
70554c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_cl_dequeued",
70564c7070dbSScott Long 					CTLFLAG_RD,
70574c7070dbSScott Long 					&fl->ifl_cl_dequeued, "clusters freed");
70584c7070dbSScott Long #endif
70594c7070dbSScott Long 		}
70604c7070dbSScott Long 	}
70614c7070dbSScott Long 
70624c7070dbSScott Long }
706395246abbSSean Bruno 
706477c1fcecSEric Joyner void
706577c1fcecSEric Joyner iflib_request_reset(if_ctx_t ctx)
706677c1fcecSEric Joyner {
706777c1fcecSEric Joyner 
706877c1fcecSEric Joyner 	STATE_LOCK(ctx);
706977c1fcecSEric Joyner 	ctx->ifc_flags |= IFC_DO_RESET;
707077c1fcecSEric Joyner 	STATE_UNLOCK(ctx);
707177c1fcecSEric Joyner }
707277c1fcecSEric Joyner 
707395246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
707495246abbSSean Bruno static struct mbuf *
707595246abbSSean Bruno iflib_fixup_rx(struct mbuf *m)
707695246abbSSean Bruno {
707795246abbSSean Bruno 	struct mbuf *n;
707895246abbSSean Bruno 
707995246abbSSean Bruno 	if (m->m_len <= (MCLBYTES - ETHER_HDR_LEN)) {
708095246abbSSean Bruno 		bcopy(m->m_data, m->m_data + ETHER_HDR_LEN, m->m_len);
708195246abbSSean Bruno 		m->m_data += ETHER_HDR_LEN;
708295246abbSSean Bruno 		n = m;
708395246abbSSean Bruno 	} else {
708495246abbSSean Bruno 		MGETHDR(n, M_NOWAIT, MT_DATA);
708595246abbSSean Bruno 		if (n == NULL) {
708695246abbSSean Bruno 			m_freem(m);
708795246abbSSean Bruno 			return (NULL);
708895246abbSSean Bruno 		}
708995246abbSSean Bruno 		bcopy(m->m_data, n->m_data, ETHER_HDR_LEN);
709095246abbSSean Bruno 		m->m_data += ETHER_HDR_LEN;
709195246abbSSean Bruno 		m->m_len -= ETHER_HDR_LEN;
709295246abbSSean Bruno 		n->m_len = ETHER_HDR_LEN;
709395246abbSSean Bruno 		M_MOVE_PKTHDR(n, m);
709495246abbSSean Bruno 		n->m_next = m;
709595246abbSSean Bruno 	}
709695246abbSSean Bruno 	return (n);
709795246abbSSean Bruno }
709895246abbSSean Bruno #endif
709994618825SMark Johnston 
71007790c8c1SConrad Meyer #ifdef DEBUGNET
710194618825SMark Johnston static void
71027790c8c1SConrad Meyer iflib_debugnet_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
710394618825SMark Johnston {
710494618825SMark Johnston 	if_ctx_t ctx;
710594618825SMark Johnston 
710694618825SMark Johnston 	ctx = if_getsoftc(ifp);
710794618825SMark Johnston 	CTX_LOCK(ctx);
710894618825SMark Johnston 	*nrxr = NRXQSETS(ctx);
710994618825SMark Johnston 	*ncl = ctx->ifc_rxqs[0].ifr_fl->ifl_size;
711094618825SMark Johnston 	*clsize = ctx->ifc_rxqs[0].ifr_fl->ifl_buf_size;
711194618825SMark Johnston 	CTX_UNLOCK(ctx);
711294618825SMark Johnston }
711394618825SMark Johnston 
711494618825SMark Johnston static void
71157790c8c1SConrad Meyer iflib_debugnet_event(if_t ifp, enum debugnet_ev event)
711694618825SMark Johnston {
711794618825SMark Johnston 	if_ctx_t ctx;
711894618825SMark Johnston 	if_softc_ctx_t scctx;
711994618825SMark Johnston 	iflib_fl_t fl;
712094618825SMark Johnston 	iflib_rxq_t rxq;
712194618825SMark Johnston 	int i, j;
712294618825SMark Johnston 
712394618825SMark Johnston 	ctx = if_getsoftc(ifp);
712494618825SMark Johnston 	scctx = &ctx->ifc_softc_ctx;
712594618825SMark Johnston 
712694618825SMark Johnston 	switch (event) {
71277790c8c1SConrad Meyer 	case DEBUGNET_START:
712894618825SMark Johnston 		for (i = 0; i < scctx->isc_nrxqsets; i++) {
712994618825SMark Johnston 			rxq = &ctx->ifc_rxqs[i];
713094618825SMark Johnston 			for (j = 0; j < rxq->ifr_nfl; j++) {
713194618825SMark Johnston 				fl = rxq->ifr_fl;
713294618825SMark Johnston 				fl->ifl_zone = m_getzone(fl->ifl_buf_size);
713394618825SMark Johnston 			}
713494618825SMark Johnston 		}
713594618825SMark Johnston 		iflib_no_tx_batch = 1;
713694618825SMark Johnston 		break;
713794618825SMark Johnston 	default:
713894618825SMark Johnston 		break;
713994618825SMark Johnston 	}
714094618825SMark Johnston }
714194618825SMark Johnston 
714294618825SMark Johnston static int
71437790c8c1SConrad Meyer iflib_debugnet_transmit(if_t ifp, struct mbuf *m)
714494618825SMark Johnston {
714594618825SMark Johnston 	if_ctx_t ctx;
714694618825SMark Johnston 	iflib_txq_t txq;
714794618825SMark Johnston 	int error;
714894618825SMark Johnston 
714994618825SMark Johnston 	ctx = if_getsoftc(ifp);
715094618825SMark Johnston 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
715194618825SMark Johnston 	    IFF_DRV_RUNNING)
715294618825SMark Johnston 		return (EBUSY);
715394618825SMark Johnston 
715494618825SMark Johnston 	txq = &ctx->ifc_txqs[0];
715594618825SMark Johnston 	error = iflib_encap(txq, &m);
715694618825SMark Johnston 	if (error == 0)
715781be6552SMatt Macy 		(void)iflib_txd_db_check(txq, true);
715894618825SMark Johnston 	return (error);
715994618825SMark Johnston }
716094618825SMark Johnston 
716194618825SMark Johnston static int
71627790c8c1SConrad Meyer iflib_debugnet_poll(if_t ifp, int count)
716394618825SMark Johnston {
71640b8df657SGleb Smirnoff 	struct epoch_tracker et;
716594618825SMark Johnston 	if_ctx_t ctx;
716694618825SMark Johnston 	if_softc_ctx_t scctx;
716794618825SMark Johnston 	iflib_txq_t txq;
716894618825SMark Johnston 	int i;
716994618825SMark Johnston 
717094618825SMark Johnston 	ctx = if_getsoftc(ifp);
717194618825SMark Johnston 	scctx = &ctx->ifc_softc_ctx;
717294618825SMark Johnston 
717394618825SMark Johnston 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
717494618825SMark Johnston 	    IFF_DRV_RUNNING)
717594618825SMark Johnston 		return (EBUSY);
717694618825SMark Johnston 
717794618825SMark Johnston 	txq = &ctx->ifc_txqs[0];
717894618825SMark Johnston 	(void)iflib_completed_tx_reclaim(txq, RECLAIM_THRESH(ctx));
717994618825SMark Johnston 
71800b8df657SGleb Smirnoff 	NET_EPOCH_ENTER(et);
718194618825SMark Johnston 	for (i = 0; i < scctx->isc_nrxqsets; i++)
718294618825SMark Johnston 		(void)iflib_rxeof(&ctx->ifc_rxqs[i], 16 /* XXX */);
71830b8df657SGleb Smirnoff 	NET_EPOCH_EXIT(et);
718494618825SMark Johnston 	return (0);
718594618825SMark Johnston }
71867790c8c1SConrad Meyer #endif /* DEBUGNET */
7187