xref: /freebsd/sys/net/iflib.c (revision ca7005f1893d199b7c28d5b159e1bdbb55e74543)
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;
198*ca7005f1SPatrick Kelsey 	uint8_t  ifc_sysctl_use_logical_cores;
199*ca7005f1SPatrick 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;
340dd7fbcf1SStephen Hurd 	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");
59081be6552SMatt Macy static int iflib_timer_default = 1000;
59181be6552SMatt Macy SYSCTL_INT(_net_iflib, OID_AUTO, timer_default, CTLFLAG_RW,
59281be6552SMatt Macy 		   &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;
730*ca7005f1SPatrick 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;
9964c7070dbSScott Long 
9974c7070dbSScott Long 	/*
9984c7070dbSScott Long 	 * interrupts on every tx packet are expensive so request
9994c7070dbSScott Long 	 * them every half ring, or where NS_REPORT is set
10004c7070dbSScott Long 	 */
10014c7070dbSScott Long 	u_int report_frequency = kring->nkr_num_slots >> 1;
10024c7070dbSScott Long 	/* device-specific */
10034c7070dbSScott Long 	if_ctx_t ctx = ifp->if_softc;
10044c7070dbSScott Long 	iflib_txq_t txq = &ctx->ifc_txqs[kring->ring_id];
10054c7070dbSScott Long 
100695dcf343SMarius Strobl 	bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
10074c7070dbSScott Long 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
10084c7070dbSScott Long 
10094c7070dbSScott Long 	/*
10104c7070dbSScott Long 	 * First part: process new packets to send.
1011dd7fbcf1SStephen Hurd 	 * nm_i is the current index in the netmap kring,
10124c7070dbSScott Long 	 * nic_i is the corresponding index in the NIC ring.
10134c7070dbSScott Long 	 *
10144c7070dbSScott Long 	 * If we have packets to send (nm_i != head)
10154c7070dbSScott Long 	 * iterate over the netmap ring, fetch length and update
10164c7070dbSScott Long 	 * the corresponding slot in the NIC ring. Some drivers also
10174c7070dbSScott Long 	 * need to update the buffer's physical address in the NIC slot
10184c7070dbSScott Long 	 * even NS_BUF_CHANGED is not set (PNMB computes the addresses).
10194c7070dbSScott Long 	 *
10204c7070dbSScott Long 	 * The netmap_reload_map() calls is especially expensive,
10214c7070dbSScott Long 	 * even when (as in this case) the tag is 0, so do only
10224c7070dbSScott Long 	 * when the buffer has actually changed.
10234c7070dbSScott Long 	 *
10244c7070dbSScott Long 	 * If possible do not set the report/intr bit on all slots,
10254c7070dbSScott Long 	 * but only a few times per ring or when NS_REPORT is set.
10264c7070dbSScott Long 	 *
10274c7070dbSScott Long 	 * Finally, on 10G and faster drivers, it might be useful
10284c7070dbSScott Long 	 * to prefetch the next slot and txr entry.
10294c7070dbSScott Long 	 */
10304c7070dbSScott Long 
1031dd7fbcf1SStephen Hurd 	nm_i = kring->nr_hwcur;
10325ee36c68SStephen Hurd 	if (nm_i != head) {	/* we have new packets to send */
1033aceaccabSVincenzo Maffione 		uint32_t pkt_len = 0, seg_idx = 0;
1034aceaccabSVincenzo Maffione 		int nic_i_start = -1, flags = 0;
103595246abbSSean Bruno 		pkt_info_zero(&pi);
103695246abbSSean Bruno 		pi.ipi_segs = txq->ift_segs;
103795246abbSSean Bruno 		pi.ipi_qsidx = kring->ring_id;
10384c7070dbSScott Long 		nic_i = netmap_idx_k2n(kring, nm_i);
10394c7070dbSScott Long 
10404c7070dbSScott Long 		__builtin_prefetch(&ring->slot[nm_i]);
10414c7070dbSScott Long 		__builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i]);
10424c7070dbSScott Long 		__builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i]);
10434c7070dbSScott Long 
10444c7070dbSScott Long 		for (n = 0; nm_i != head; n++) {
10454c7070dbSScott Long 			struct netmap_slot *slot = &ring->slot[nm_i];
1046361e9501SVincenzo Maffione 			uint64_t offset = nm_get_offset(kring, slot);
10474c7070dbSScott Long 			u_int len = slot->len;
10480a1b74a3SSean Bruno 			uint64_t paddr;
10494c7070dbSScott Long 			void *addr = PNMB(na, slot, &paddr);
1050aceaccabSVincenzo Maffione 
1051aceaccabSVincenzo Maffione 			flags |= (slot->flags & NS_REPORT ||
10524c7070dbSScott Long 				nic_i == 0 || nic_i == report_frequency) ?
10534c7070dbSScott Long 				IPI_TX_INTR : 0;
10544c7070dbSScott Long 
1055aceaccabSVincenzo Maffione 			/*
1056aceaccabSVincenzo Maffione 			 * If this is the first packet fragment, save the
1057aceaccabSVincenzo Maffione 			 * index of the first NIC slot for later.
1058aceaccabSVincenzo Maffione 			 */
1059aceaccabSVincenzo Maffione 			if (nic_i_start < 0)
1060aceaccabSVincenzo Maffione 				nic_i_start = nic_i;
1061aceaccabSVincenzo Maffione 
1062361e9501SVincenzo Maffione 			pi.ipi_segs[seg_idx].ds_addr = paddr + offset;
1063aceaccabSVincenzo Maffione 			pi.ipi_segs[seg_idx].ds_len = len;
1064aceaccabSVincenzo Maffione 			if (len) {
1065aceaccabSVincenzo Maffione 				pkt_len += len;
1066aceaccabSVincenzo Maffione 				seg_idx++;
1067aceaccabSVincenzo Maffione 			}
1068aceaccabSVincenzo Maffione 
1069aceaccabSVincenzo Maffione 			if (!(slot->flags & NS_MOREFRAG)) {
1070aceaccabSVincenzo Maffione 				pi.ipi_len = pkt_len;
1071aceaccabSVincenzo Maffione 				pi.ipi_nsegs = seg_idx;
1072aceaccabSVincenzo Maffione 				pi.ipi_pidx = nic_i_start;
107395246abbSSean Bruno 				pi.ipi_ndescs = 0;
10744c7070dbSScott Long 				pi.ipi_flags = flags;
10754c7070dbSScott Long 
1076aceaccabSVincenzo Maffione 				/* Prepare the NIC TX ring. */
10774c7070dbSScott Long 				ctx->isc_txd_encap(ctx->ifc_softc, &pi);
107864e6fc13SStephen Hurd 				DBG_COUNTER_INC(tx_encap);
10794c7070dbSScott Long 
1080aceaccabSVincenzo Maffione 				/* Reinit per-packet info for the next one. */
1081aceaccabSVincenzo Maffione 				flags = seg_idx = pkt_len = 0;
1082aceaccabSVincenzo Maffione 				nic_i_start = -1;
1083aceaccabSVincenzo Maffione 			}
1084aceaccabSVincenzo Maffione 
10854c7070dbSScott Long 			/* prefetch for next round */
10864c7070dbSScott Long 			__builtin_prefetch(&ring->slot[nm_i + 1]);
10874c7070dbSScott Long 			__builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i + 1]);
10884c7070dbSScott Long 			__builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i + 1]);
10894c7070dbSScott Long 
1090361e9501SVincenzo Maffione 			NM_CHECK_ADDR_LEN_OFF(na, len, offset);
10914c7070dbSScott Long 
10924c7070dbSScott Long 			if (slot->flags & NS_BUF_CHANGED) {
10934c7070dbSScott Long 				/* buffer has changed, reload map */
1094bfce461eSMarius Strobl 				netmap_reload_map(na, txq->ift_buf_tag,
1095bfce461eSMarius Strobl 				    txq->ift_sds.ifsd_map[nic_i], addr);
10964c7070dbSScott Long 			}
10974c7070dbSScott Long 			/* make sure changes to the buffer are synced */
109895dcf343SMarius Strobl 			bus_dmamap_sync(txq->ift_buf_tag,
109995dcf343SMarius Strobl 			    txq->ift_sds.ifsd_map[nic_i],
11004c7070dbSScott Long 			    BUS_DMASYNC_PREWRITE);
110195dcf343SMarius Strobl 
1102aceaccabSVincenzo Maffione 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
11034c7070dbSScott Long 			nm_i = nm_next(nm_i, lim);
11044c7070dbSScott Long 			nic_i = nm_next(nic_i, lim);
11054c7070dbSScott Long 		}
1106dd7fbcf1SStephen Hurd 		kring->nr_hwcur = nm_i;
11074c7070dbSScott Long 
11084c7070dbSScott Long 		/* synchronize the NIC ring */
110995dcf343SMarius Strobl 		bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
11104c7070dbSScott Long 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11114c7070dbSScott Long 
11124c7070dbSScott Long 		/* (re)start the tx unit up to slot nic_i (excluded) */
11134c7070dbSScott Long 		ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, nic_i);
11144c7070dbSScott Long 	}
11154c7070dbSScott Long 
11164c7070dbSScott Long 	/*
11174c7070dbSScott Long 	 * Second part: reclaim buffers for completed transmissions.
11185ee36c68SStephen Hurd 	 *
11195ee36c68SStephen Hurd 	 * If there are unclaimed buffers, attempt to reclaim them.
112017cec474SVincenzo Maffione 	 * If we don't manage to reclaim them all, and TX IRQs are not in use,
112117cec474SVincenzo Maffione 	 * trigger a per-tx-queue timer to try again later.
11224c7070dbSScott Long 	 */
1123dd7fbcf1SStephen Hurd 	if (kring->nr_hwtail != nm_prev(kring->nr_hwcur, lim)) {
11244c7070dbSScott Long 		if (iflib_tx_credits_update(ctx, txq)) {
11254c7070dbSScott Long 			/* some tx completed, increment avail */
11264c7070dbSScott Long 			nic_i = txq->ift_cidx_processed;
11274c7070dbSScott Long 			kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
11284c7070dbSScott Long 		}
11295ee36c68SStephen Hurd 	}
113017cec474SVincenzo Maffione 
1131dd7fbcf1SStephen Hurd 	if (!(ctx->ifc_flags & IFC_NETMAP_TX_IRQ))
1132dd7fbcf1SStephen Hurd 		if (kring->nr_hwtail != nm_prev(kring->nr_hwcur, lim)) {
1133be7a6b3dSVincenzo Maffione 			callout_reset_sbt_on(&txq->ift_netmap_timer,
113417cec474SVincenzo Maffione 			    NETMAP_TX_TIMER_US * SBT_1US, SBT_1US,
1135be7a6b3dSVincenzo Maffione 			    iflib_netmap_timer, txq,
1136be7a6b3dSVincenzo Maffione 			    txq->ift_netmap_timer.c_cpu, 0);
11375ee36c68SStephen Hurd 		}
11384c7070dbSScott Long 	return (0);
11394c7070dbSScott Long }
11404c7070dbSScott Long 
11414c7070dbSScott Long /*
11424c7070dbSScott Long  * Reconcile kernel and user view of the receive ring.
11434c7070dbSScott Long  * Same as for the txsync, this routine must be efficient.
11444c7070dbSScott Long  * The caller guarantees a single invocations, but races against
11454c7070dbSScott Long  * the rest of the driver should be handled here.
11464c7070dbSScott Long  *
11474c7070dbSScott Long  * On call, kring->rhead is the first packet that userspace wants
11484c7070dbSScott Long  * to keep, and kring->rcur is the wakeup point.
11494c7070dbSScott Long  * The kernel has previously reported packets up to kring->rtail.
11504c7070dbSScott Long  *
11514c7070dbSScott Long  * If (flags & NAF_FORCE_READ) also check for incoming packets irrespective
11524c7070dbSScott Long  * of whether or not we received an interrupt.
11534c7070dbSScott Long  */
11544c7070dbSScott Long static int
11554c7070dbSScott Long iflib_netmap_rxsync(struct netmap_kring *kring, int flags)
11564c7070dbSScott Long {
11574c7070dbSScott Long 	struct netmap_adapter *na = kring->na;
11584c7070dbSScott Long 	struct netmap_ring *ring = kring->ring;
11591722eeacSMarius Strobl 	if_t ifp = na->ifp;
116095246abbSSean Bruno 	uint32_t nm_i;	/* index into the netmap ring */
11612d873474SStephen Hurd 	uint32_t nic_i;	/* index into the NIC ring */
1162ee07345dSVincenzo Maffione 	u_int n;
11634c7070dbSScott Long 	u_int const lim = kring->nkr_num_slots - 1;
11644c7070dbSScott Long 	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
1165aceaccabSVincenzo Maffione 	int i = 0;
116695246abbSSean Bruno 
11674c7070dbSScott Long 	if_ctx_t ctx = ifp->if_softc;
11686d84e76aSVincenzo Maffione 	if_shared_ctx_t sctx = ctx->ifc_sctx;
11696d84e76aSVincenzo Maffione 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
11704c7070dbSScott Long 	iflib_rxq_t rxq = &ctx->ifc_rxqs[kring->ring_id];
1171ee07345dSVincenzo Maffione 	iflib_fl_t fl = &rxq->ifr_fl[0];
1172ee07345dSVincenzo Maffione 	struct if_rxd_info ri;
11736d84e76aSVincenzo Maffione 	qidx_t *cidxp;
1174ee07345dSVincenzo Maffione 
117595dcf343SMarius Strobl 	/*
1176ee07345dSVincenzo Maffione 	 * netmap only uses free list 0, to avoid out of order consumption
1177ee07345dSVincenzo Maffione 	 * of receive buffers
117895dcf343SMarius Strobl 	 */
117995dcf343SMarius Strobl 
118095dcf343SMarius Strobl 	bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
11814c7070dbSScott Long 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
118295dcf343SMarius Strobl 
11834c7070dbSScott Long 	/*
11844c7070dbSScott Long 	 * First part: import newly received packets.
11854c7070dbSScott Long 	 *
11864c7070dbSScott Long 	 * nm_i is the index of the next free slot in the netmap ring,
11876d84e76aSVincenzo Maffione 	 * nic_i is the index of the next received packet in the NIC ring
11886d84e76aSVincenzo Maffione 	 * (or in the free list 0 if IFLIB_HAS_RXCQ is set), and they may
11896d84e76aSVincenzo Maffione 	 * differ in case if_init() has been called while
11904c7070dbSScott Long 	 * in netmap mode. For the receive ring we have
11914c7070dbSScott Long 	 *
11926d84e76aSVincenzo Maffione 	 *	nic_i = fl->ifl_cidx;
11934c7070dbSScott Long 	 *	nm_i = kring->nr_hwtail (previous)
11944c7070dbSScott Long 	 * and
11954c7070dbSScott Long 	 *	nm_i == (nic_i + kring->nkr_hwofs) % ring_size
11964c7070dbSScott Long 	 *
11976d84e76aSVincenzo Maffione 	 * fl->ifl_cidx is set to 0 on a ring reinit
11984c7070dbSScott Long 	 */
11994c7070dbSScott Long 	if (netmap_no_pendintr || force_update) {
12000ff21267SVincenzo Maffione 		uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim);
12016d84e76aSVincenzo Maffione 		bool have_rxcq = sctx->isc_flags & IFLIB_HAS_RXCQ;
12024c7070dbSScott Long 		int crclen = iflib_crcstrip ? 0 : 4;
12034c7070dbSScott Long 		int error, avail;
12044c7070dbSScott Long 
12056d84e76aSVincenzo Maffione 		/*
12066d84e76aSVincenzo Maffione 		 * For the free list consumer index, we use the same
12076d84e76aSVincenzo Maffione 		 * logic as in iflib_rxeof().
12086d84e76aSVincenzo Maffione 		 */
12096d84e76aSVincenzo Maffione 		if (have_rxcq)
12106d84e76aSVincenzo Maffione 			cidxp = &rxq->ifr_cq_cidx;
12116d84e76aSVincenzo Maffione 		else
12126d84e76aSVincenzo Maffione 			cidxp = &fl->ifl_cidx;
12136d84e76aSVincenzo Maffione 		avail = ctx->isc_rxd_available(ctx->ifc_softc,
12146d84e76aSVincenzo Maffione 		    rxq->ifr_id, *cidxp, USHRT_MAX);
12156d84e76aSVincenzo Maffione 
12164c7070dbSScott Long 		nic_i = fl->ifl_cidx;
12174c7070dbSScott Long 		nm_i = netmap_idx_n2k(kring, nic_i);
1218de5b4610SVincenzo Maffione 		MPASS(nm_i == kring->nr_hwtail);
12190ff21267SVincenzo Maffione 		for (n = 0; avail > 0 && nm_i != hwtail_lim; n++, avail--) {
1220ab2e3f79SStephen Hurd 			rxd_info_zero(&ri);
1221ab2e3f79SStephen Hurd 			ri.iri_frags = rxq->ifr_frags;
1222ab2e3f79SStephen Hurd 			ri.iri_qsidx = kring->ring_id;
1223ab2e3f79SStephen Hurd 			ri.iri_ifp = ctx->ifc_ifp;
12246d84e76aSVincenzo Maffione 			ri.iri_cidx = *cidxp;
122595246abbSSean Bruno 
1226ab2e3f79SStephen Hurd 			error = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri);
1227aceaccabSVincenzo Maffione 			for (i = 0; i < ri.iri_nfrags; i++) {
1228aceaccabSVincenzo Maffione 				if (error) {
1229aceaccabSVincenzo Maffione 					ring->slot[nm_i].len = 0;
12307cb7c6e3SNavdeep Parhar 					ring->slot[nm_i].flags = 0;
1231aceaccabSVincenzo Maffione 				} else {
1232aceaccabSVincenzo Maffione 					ring->slot[nm_i].len = ri.iri_frags[i].irf_len;
1233aceaccabSVincenzo Maffione 					if (i == (ri.iri_nfrags - 1)) {
1234aceaccabSVincenzo Maffione 						ring->slot[nm_i].len -= crclen;
1235aceaccabSVincenzo Maffione 						ring->slot[nm_i].flags = 0;
1236aceaccabSVincenzo Maffione 					} else
1237aceaccabSVincenzo Maffione 						ring->slot[nm_i].flags = NS_MOREFRAG;
1238aceaccabSVincenzo Maffione 				}
1239aceaccabSVincenzo Maffione 
1240f80efe50SVincenzo Maffione 				bus_dmamap_sync(fl->ifl_buf_tag,
1241f80efe50SVincenzo Maffione 				    fl->ifl_sds.ifsd_map[nic_i], BUS_DMASYNC_POSTREAD);
1242f80efe50SVincenzo Maffione 				nm_i = nm_next(nm_i, lim);
1243f80efe50SVincenzo Maffione 				fl->ifl_cidx = nic_i = nm_next(nic_i, lim);
1244f80efe50SVincenzo Maffione 			}
1245f80efe50SVincenzo Maffione 
12466d84e76aSVincenzo Maffione 			if (have_rxcq) {
12476d84e76aSVincenzo Maffione 				*cidxp = ri.iri_cidx;
12486d84e76aSVincenzo Maffione 				while (*cidxp >= scctx->isc_nrxd[0])
12496d84e76aSVincenzo Maffione 					*cidxp -= scctx->isc_nrxd[0];
12506d84e76aSVincenzo Maffione 			}
1251aceaccabSVincenzo Maffione 
1252aceaccabSVincenzo Maffione 		}
12534c7070dbSScott Long 		if (n) { /* update the state variables */
12544c7070dbSScott Long 			if (netmap_no_pendintr && !force_update) {
12554c7070dbSScott Long 				/* diagnostics */
12564c7070dbSScott Long 				iflib_rx_miss ++;
12574c7070dbSScott Long 				iflib_rx_miss_bufs += n;
12584c7070dbSScott Long 			}
1259dd7fbcf1SStephen Hurd 			kring->nr_hwtail = nm_i;
12604c7070dbSScott Long 		}
12614c7070dbSScott Long 		kring->nr_kflags &= ~NKR_PENDINTR;
12624c7070dbSScott Long 	}
12634c7070dbSScott Long 	/*
12644c7070dbSScott Long 	 * Second part: skip past packets that userspace has released.
12654c7070dbSScott Long 	 * (kring->nr_hwcur to head excluded),
12664c7070dbSScott Long 	 * and make the buffers available for reception.
12674c7070dbSScott Long 	 * As usual nm_i is the index in the netmap ring,
12684c7070dbSScott Long 	 * nic_i is the index in the NIC ring, and
12694c7070dbSScott Long 	 * nm_i == (nic_i + kring->nkr_hwofs) % ring_size
12704c7070dbSScott Long 	 */
1271de5b4610SVincenzo Maffione 	netmap_fl_refill(rxq, kring, false);
127295246abbSSean Bruno 
1273de5b4610SVincenzo Maffione 	return (0);
12744c7070dbSScott Long }
12754c7070dbSScott Long 
127695246abbSSean Bruno static void
127795246abbSSean Bruno iflib_netmap_intr(struct netmap_adapter *na, int onoff)
127895246abbSSean Bruno {
12791722eeacSMarius Strobl 	if_ctx_t ctx = na->ifp->if_softc;
128095246abbSSean Bruno 
1281ab2e3f79SStephen Hurd 	CTX_LOCK(ctx);
128295246abbSSean Bruno 	if (onoff) {
128395246abbSSean Bruno 		IFDI_INTR_ENABLE(ctx);
128495246abbSSean Bruno 	} else {
128595246abbSSean Bruno 		IFDI_INTR_DISABLE(ctx);
128695246abbSSean Bruno 	}
1287ab2e3f79SStephen Hurd 	CTX_UNLOCK(ctx);
128895246abbSSean Bruno }
128995246abbSSean Bruno 
12904c7070dbSScott Long static int
12914c7070dbSScott Long iflib_netmap_attach(if_ctx_t ctx)
12924c7070dbSScott Long {
12934c7070dbSScott Long 	struct netmap_adapter na;
12944c7070dbSScott Long 
12954c7070dbSScott Long 	bzero(&na, sizeof(na));
12964c7070dbSScott Long 
12974c7070dbSScott Long 	na.ifp = ctx->ifc_ifp;
1298361e9501SVincenzo Maffione 	na.na_flags = NAF_BDG_MAYSLEEP | NAF_MOREFRAG | NAF_OFFSETS;
12994c7070dbSScott Long 	MPASS(ctx->ifc_softc_ctx.isc_ntxqsets);
13004c7070dbSScott Long 	MPASS(ctx->ifc_softc_ctx.isc_nrxqsets);
13014c7070dbSScott Long 
1302ac11d857SVincenzo Maffione 	na.num_tx_desc = iflib_num_tx_descs(ctx);
1303ac11d857SVincenzo Maffione 	na.num_rx_desc = iflib_num_rx_descs(ctx);
13044c7070dbSScott Long 	na.nm_txsync = iflib_netmap_txsync;
13054c7070dbSScott Long 	na.nm_rxsync = iflib_netmap_rxsync;
13064c7070dbSScott Long 	na.nm_register = iflib_netmap_register;
130795246abbSSean Bruno 	na.nm_intr = iflib_netmap_intr;
130821d0c012Syou@x 	na.nm_config = iflib_netmap_config;
13094c7070dbSScott Long 	na.num_tx_rings = ctx->ifc_softc_ctx.isc_ntxqsets;
13104c7070dbSScott Long 	na.num_rx_rings = ctx->ifc_softc_ctx.isc_nrxqsets;
13114c7070dbSScott Long 	return (netmap_attach(&na));
13124c7070dbSScott Long }
13134c7070dbSScott Long 
1314d8b2d26bSVincenzo Maffione static int
13154c7070dbSScott Long iflib_netmap_txq_init(if_ctx_t ctx, iflib_txq_t txq)
13164c7070dbSScott Long {
13174c7070dbSScott Long 	struct netmap_adapter *na = NA(ctx->ifc_ifp);
13184c7070dbSScott Long 	struct netmap_slot *slot;
13194c7070dbSScott Long 
13204c7070dbSScott Long 	slot = netmap_reset(na, NR_TX, txq->ift_id, 0);
1321e099b90bSPedro F. Giffuni 	if (slot == NULL)
1322d8b2d26bSVincenzo Maffione 		return (0);
132323ac9029SStephen Hurd 	for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxd[0]; i++) {
13244c7070dbSScott Long 		/*
13254c7070dbSScott Long 		 * In netmap mode, set the map for the packet buffer.
13264c7070dbSScott Long 		 * NOTE: Some drivers (not this one) also need to set
13274c7070dbSScott Long 		 * the physical buffer address in the NIC ring.
13284c7070dbSScott Long 		 * netmap_idx_n2k() maps a nic index, i, into the corresponding
13294c7070dbSScott Long 		 * netmap slot index, si
13304c7070dbSScott Long 		 */
13312ff91c17SVincenzo Maffione 		int si = netmap_idx_n2k(na->tx_rings[txq->ift_id], i);
1332bfce461eSMarius Strobl 		netmap_load_map(na, txq->ift_buf_tag, txq->ift_sds.ifsd_map[i],
1333bfce461eSMarius Strobl 		    NMB(na, slot + si));
13344c7070dbSScott Long 	}
1335d8b2d26bSVincenzo Maffione 	return (1);
13364c7070dbSScott Long }
13372d873474SStephen Hurd 
1338d8b2d26bSVincenzo Maffione static int
13394c7070dbSScott Long iflib_netmap_rxq_init(if_ctx_t ctx, iflib_rxq_t rxq)
13404c7070dbSScott Long {
13414c7070dbSScott Long 	struct netmap_adapter *na = NA(ctx->ifc_ifp);
1342d8b2d26bSVincenzo Maffione 	struct netmap_kring *kring;
13434c7070dbSScott Long 	struct netmap_slot *slot;
13444c7070dbSScott Long 
13454c7070dbSScott Long 	slot = netmap_reset(na, NR_RX, rxq->ifr_id, 0);
1346e099b90bSPedro F. Giffuni 	if (slot == NULL)
1347d8b2d26bSVincenzo Maffione 		return (0);
1348d8b2d26bSVincenzo Maffione 	kring = na->rx_rings[rxq->ifr_id];
1349de5b4610SVincenzo Maffione 	netmap_fl_refill(rxq, kring, true);
1350d8b2d26bSVincenzo Maffione 	return (1);
13514c7070dbSScott Long }
13524c7070dbSScott Long 
1353dd7fbcf1SStephen Hurd static void
135417cec474SVincenzo Maffione iflib_netmap_timer(void *arg)
1355dd7fbcf1SStephen Hurd {
135617cec474SVincenzo Maffione 	iflib_txq_t txq = arg;
135717cec474SVincenzo Maffione 	if_ctx_t ctx = txq->ift_ctx;
1358dd7fbcf1SStephen Hurd 
135917cec474SVincenzo Maffione 	/*
136017cec474SVincenzo Maffione 	 * Wake up the netmap application, to give it a chance to
136117cec474SVincenzo Maffione 	 * call txsync and reclaim more completed TX buffers.
136217cec474SVincenzo Maffione 	 */
136317cec474SVincenzo Maffione 	netmap_tx_irq(ctx->ifc_ifp, txq->ift_id);
1364dd7fbcf1SStephen Hurd }
1365dd7fbcf1SStephen Hurd 
13664c7070dbSScott Long #define iflib_netmap_detach(ifp) netmap_detach(ifp)
13674c7070dbSScott Long 
13684c7070dbSScott Long #else
1369d8b2d26bSVincenzo Maffione #define iflib_netmap_txq_init(ctx, txq) (0)
1370d8b2d26bSVincenzo Maffione #define iflib_netmap_rxq_init(ctx, rxq) (0)
13714c7070dbSScott Long #define iflib_netmap_detach(ifp)
13728aa8484cSVincenzo Maffione #define netmap_enable_all_rings(ifp)
13738aa8484cSVincenzo Maffione #define netmap_disable_all_rings(ifp)
13744c7070dbSScott Long 
13754c7070dbSScott Long #define iflib_netmap_attach(ctx) (0)
13764c7070dbSScott Long #define netmap_rx_irq(ifp, qid, budget) (0)
13774c7070dbSScott Long #endif
13784c7070dbSScott Long 
13794c7070dbSScott Long #if defined(__i386__) || defined(__amd64__)
13804c7070dbSScott Long static __inline void
13814c7070dbSScott Long prefetch(void *x)
13824c7070dbSScott Long {
13834c7070dbSScott Long 	__asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
13844c7070dbSScott Long }
13853429c02fSStephen Hurd static __inline void
13863429c02fSStephen Hurd prefetch2cachelines(void *x)
13873429c02fSStephen Hurd {
13883429c02fSStephen Hurd 	__asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
13893429c02fSStephen Hurd #if (CACHE_LINE_SIZE < 128)
13903429c02fSStephen Hurd 	__asm volatile("prefetcht0 %0" :: "m" (*(((unsigned long *)x)+CACHE_LINE_SIZE/(sizeof(unsigned long)))));
13913429c02fSStephen Hurd #endif
13923429c02fSStephen Hurd }
13934c7070dbSScott Long #else
13944c7070dbSScott Long #define prefetch(x)
13953429c02fSStephen Hurd #define prefetch2cachelines(x)
13964c7070dbSScott Long #endif
13974c7070dbSScott Long 
13984c7070dbSScott Long static void
139910e0d938SStephen Hurd iru_init(if_rxd_update_t iru, iflib_rxq_t rxq, uint8_t flid)
140010e0d938SStephen Hurd {
140110e0d938SStephen Hurd 	iflib_fl_t fl;
140210e0d938SStephen Hurd 
140310e0d938SStephen Hurd 	fl = &rxq->ifr_fl[flid];
140410e0d938SStephen Hurd 	iru->iru_paddrs = fl->ifl_bus_addrs;
140510e0d938SStephen Hurd 	iru->iru_idxs = fl->ifl_rxd_idxs;
140610e0d938SStephen Hurd 	iru->iru_qsidx = rxq->ifr_id;
140710e0d938SStephen Hurd 	iru->iru_buf_size = fl->ifl_buf_size;
140810e0d938SStephen Hurd 	iru->iru_flidx = fl->ifl_id;
140910e0d938SStephen Hurd }
141010e0d938SStephen Hurd 
141110e0d938SStephen Hurd static void
14124c7070dbSScott Long _iflib_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
14134c7070dbSScott Long {
14144c7070dbSScott Long 	if (err)
14154c7070dbSScott Long 		return;
14164c7070dbSScott Long 	*(bus_addr_t *) arg = segs[0].ds_addr;
14174c7070dbSScott Long }
14184c7070dbSScott Long 
14196dd69f00SMarcin Wojtas #define	DMA_WIDTH_TO_BUS_LOWADDR(width)				\
1420ef567155SMarcin Wojtas 	(((width) == 0) || (width) == flsll(BUS_SPACE_MAXADDR) ?	\
14216dd69f00SMarcin Wojtas 	    BUS_SPACE_MAXADDR : (1ULL << (width)) - 1ULL)
14226dd69f00SMarcin Wojtas 
14234c7070dbSScott Long int
14248f82136aSPatrick Kelsey iflib_dma_alloc_align(if_ctx_t ctx, int size, int align, iflib_dma_info_t dma, int mapflags)
14254c7070dbSScott Long {
14264c7070dbSScott Long 	int err;
14274c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
14286dd69f00SMarcin Wojtas 	bus_addr_t lowaddr;
14296dd69f00SMarcin Wojtas 
14306dd69f00SMarcin Wojtas 	lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(ctx->ifc_softc_ctx.isc_dma_width);
14314c7070dbSScott Long 
14324c7070dbSScott Long 	err = bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
14338f82136aSPatrick Kelsey 				align, 0,		/* alignment, bounds */
14346dd69f00SMarcin Wojtas 				lowaddr,		/* lowaddr */
14354c7070dbSScott Long 				BUS_SPACE_MAXADDR,	/* highaddr */
14364c7070dbSScott Long 				NULL, NULL,		/* filter, filterarg */
14374c7070dbSScott Long 				size,			/* maxsize */
14384c7070dbSScott Long 				1,			/* nsegments */
14394c7070dbSScott Long 				size,			/* maxsegsize */
14404c7070dbSScott Long 				BUS_DMA_ALLOCNOW,	/* flags */
14414c7070dbSScott Long 				NULL,			/* lockfunc */
14424c7070dbSScott Long 				NULL,			/* lockarg */
14434c7070dbSScott Long 				&dma->idi_tag);
14444c7070dbSScott Long 	if (err) {
14454c7070dbSScott Long 		device_printf(dev,
14464c7070dbSScott Long 		    "%s: bus_dma_tag_create failed: %d\n",
14474c7070dbSScott Long 		    __func__, err);
14484c7070dbSScott Long 		goto fail_0;
14494c7070dbSScott Long 	}
14504c7070dbSScott Long 
14514c7070dbSScott Long 	err = bus_dmamem_alloc(dma->idi_tag, (void**) &dma->idi_vaddr,
14524c7070dbSScott Long 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_ZERO, &dma->idi_map);
14534c7070dbSScott Long 	if (err) {
14544c7070dbSScott Long 		device_printf(dev,
14554c7070dbSScott Long 		    "%s: bus_dmamem_alloc(%ju) failed: %d\n",
14564c7070dbSScott Long 		    __func__, (uintmax_t)size, err);
14574c7070dbSScott Long 		goto fail_1;
14584c7070dbSScott Long 	}
14594c7070dbSScott Long 
14604c7070dbSScott Long 	dma->idi_paddr = IF_BAD_DMA;
14614c7070dbSScott Long 	err = bus_dmamap_load(dma->idi_tag, dma->idi_map, dma->idi_vaddr,
14624c7070dbSScott Long 	    size, _iflib_dmamap_cb, &dma->idi_paddr, mapflags | BUS_DMA_NOWAIT);
14634c7070dbSScott Long 	if (err || dma->idi_paddr == IF_BAD_DMA) {
14644c7070dbSScott Long 		device_printf(dev,
14654c7070dbSScott Long 		    "%s: bus_dmamap_load failed: %d\n",
14664c7070dbSScott Long 		    __func__, err);
14674c7070dbSScott Long 		goto fail_2;
14684c7070dbSScott Long 	}
14694c7070dbSScott Long 
14704c7070dbSScott Long 	dma->idi_size = size;
14714c7070dbSScott Long 	return (0);
14724c7070dbSScott Long 
14734c7070dbSScott Long fail_2:
14744c7070dbSScott Long 	bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map);
14754c7070dbSScott Long fail_1:
14764c7070dbSScott Long 	bus_dma_tag_destroy(dma->idi_tag);
14774c7070dbSScott Long fail_0:
14784c7070dbSScott Long 	dma->idi_tag = NULL;
14794c7070dbSScott Long 
14804c7070dbSScott Long 	return (err);
14814c7070dbSScott Long }
14824c7070dbSScott Long 
14834c7070dbSScott Long int
14848f82136aSPatrick Kelsey iflib_dma_alloc(if_ctx_t ctx, int size, iflib_dma_info_t dma, int mapflags)
14858f82136aSPatrick Kelsey {
14868f82136aSPatrick Kelsey 	if_shared_ctx_t sctx = ctx->ifc_sctx;
14878f82136aSPatrick Kelsey 
14888f82136aSPatrick Kelsey 	KASSERT(sctx->isc_q_align != 0, ("alignment value not initialized"));
14898f82136aSPatrick Kelsey 
14908f82136aSPatrick Kelsey 	return (iflib_dma_alloc_align(ctx, size, sctx->isc_q_align, dma, mapflags));
14918f82136aSPatrick Kelsey }
14928f82136aSPatrick Kelsey 
14938f82136aSPatrick Kelsey int
14944c7070dbSScott Long iflib_dma_alloc_multi(if_ctx_t ctx, int *sizes, iflib_dma_info_t *dmalist, int mapflags, int count)
14954c7070dbSScott Long {
14964c7070dbSScott Long 	int i, err;
14974c7070dbSScott Long 	iflib_dma_info_t *dmaiter;
14984c7070dbSScott Long 
14994c7070dbSScott Long 	dmaiter = dmalist;
15004c7070dbSScott Long 	for (i = 0; i < count; i++, dmaiter++) {
15014c7070dbSScott Long 		if ((err = iflib_dma_alloc(ctx, sizes[i], *dmaiter, mapflags)) != 0)
15024c7070dbSScott Long 			break;
15034c7070dbSScott Long 	}
15044c7070dbSScott Long 	if (err)
15054c7070dbSScott Long 		iflib_dma_free_multi(dmalist, i);
15064c7070dbSScott Long 	return (err);
15074c7070dbSScott Long }
15084c7070dbSScott Long 
15094c7070dbSScott Long void
15104c7070dbSScott Long iflib_dma_free(iflib_dma_info_t dma)
15114c7070dbSScott Long {
15124c7070dbSScott Long 	if (dma->idi_tag == NULL)
15134c7070dbSScott Long 		return;
15144c7070dbSScott Long 	if (dma->idi_paddr != IF_BAD_DMA) {
15154c7070dbSScott Long 		bus_dmamap_sync(dma->idi_tag, dma->idi_map,
15164c7070dbSScott Long 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
15174c7070dbSScott Long 		bus_dmamap_unload(dma->idi_tag, dma->idi_map);
15184c7070dbSScott Long 		dma->idi_paddr = IF_BAD_DMA;
15194c7070dbSScott Long 	}
15204c7070dbSScott Long 	if (dma->idi_vaddr != NULL) {
15214c7070dbSScott Long 		bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map);
15224c7070dbSScott Long 		dma->idi_vaddr = NULL;
15234c7070dbSScott Long 	}
15244c7070dbSScott Long 	bus_dma_tag_destroy(dma->idi_tag);
15254c7070dbSScott Long 	dma->idi_tag = NULL;
15264c7070dbSScott Long }
15274c7070dbSScott Long 
15284c7070dbSScott Long void
15294c7070dbSScott Long iflib_dma_free_multi(iflib_dma_info_t *dmalist, int count)
15304c7070dbSScott Long {
15314c7070dbSScott Long 	int i;
15324c7070dbSScott Long 	iflib_dma_info_t *dmaiter = dmalist;
15334c7070dbSScott Long 
15344c7070dbSScott Long 	for (i = 0; i < count; i++, dmaiter++)
15354c7070dbSScott Long 		iflib_dma_free(*dmaiter);
15364c7070dbSScott Long }
15374c7070dbSScott Long 
15384c7070dbSScott Long static int
15394c7070dbSScott Long iflib_fast_intr(void *arg)
15404c7070dbSScott Long {
15414c7070dbSScott Long 	iflib_filter_info_t info = arg;
15424c7070dbSScott Long 	struct grouptask *gtask = info->ifi_task;
1543ca62461bSStephen Hurd 	int result;
1544ca62461bSStephen Hurd 
154595246abbSSean Bruno 	DBG_COUNTER_INC(fast_intrs);
1546ca62461bSStephen Hurd 	if (info->ifi_filter != NULL) {
1547ca62461bSStephen Hurd 		result = info->ifi_filter(info->ifi_filter_arg);
1548ca62461bSStephen Hurd 		if ((result & FILTER_SCHEDULE_THREAD) == 0)
1549ca62461bSStephen Hurd 			return (result);
1550ca62461bSStephen Hurd 	}
155195246abbSSean Bruno 
155295246abbSSean Bruno 	GROUPTASK_ENQUEUE(gtask);
155395246abbSSean Bruno 	return (FILTER_HANDLED);
155495246abbSSean Bruno }
155595246abbSSean Bruno 
155695246abbSSean Bruno static int
155795246abbSSean Bruno iflib_fast_intr_rxtx(void *arg)
155895246abbSSean Bruno {
155995246abbSSean Bruno 	iflib_filter_info_t info = arg;
156095246abbSSean Bruno 	struct grouptask *gtask = info->ifi_task;
156195dcf343SMarius Strobl 	if_ctx_t ctx;
156295246abbSSean Bruno 	iflib_rxq_t rxq = (iflib_rxq_t)info->ifi_ctx;
156395dcf343SMarius Strobl 	iflib_txq_t txq;
156495dcf343SMarius Strobl 	void *sc;
1565ca62461bSStephen Hurd 	int i, cidx, result;
156695dcf343SMarius Strobl 	qidx_t txqid;
15673d10e9edSMarius Strobl 	bool intr_enable, intr_legacy;
156895246abbSSean Bruno 
156995246abbSSean Bruno 	DBG_COUNTER_INC(fast_intrs);
1570ca62461bSStephen Hurd 	if (info->ifi_filter != NULL) {
1571ca62461bSStephen Hurd 		result = info->ifi_filter(info->ifi_filter_arg);
1572ca62461bSStephen Hurd 		if ((result & FILTER_SCHEDULE_THREAD) == 0)
1573ca62461bSStephen Hurd 			return (result);
1574ca62461bSStephen Hurd 	}
157595246abbSSean Bruno 
157695dcf343SMarius Strobl 	ctx = rxq->ifr_ctx;
157795dcf343SMarius Strobl 	sc = ctx->ifc_softc;
15783d10e9edSMarius Strobl 	intr_enable = false;
15793d10e9edSMarius Strobl 	intr_legacy = !!(ctx->ifc_flags & IFC_LEGACY);
15801ae4848cSMatt Macy 	MPASS(rxq->ifr_ntxqirq);
158195246abbSSean Bruno 	for (i = 0; i < rxq->ifr_ntxqirq; i++) {
158295dcf343SMarius Strobl 		txqid = rxq->ifr_txqid[i];
158395dcf343SMarius Strobl 		txq = &ctx->ifc_txqs[txqid];
158495dcf343SMarius Strobl 		bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
15858a04b53dSKonstantin Belousov 		    BUS_DMASYNC_POSTREAD);
158695dcf343SMarius Strobl 		if (!ctx->isc_txd_credits_update(sc, txqid, false)) {
15873d10e9edSMarius Strobl 			if (intr_legacy)
15883d10e9edSMarius Strobl 				intr_enable = true;
15893d10e9edSMarius Strobl 			else
159095246abbSSean Bruno 				IFDI_TX_QUEUE_INTR_ENABLE(ctx, txqid);
159195246abbSSean Bruno 			continue;
159295246abbSSean Bruno 		}
159395dcf343SMarius Strobl 		GROUPTASK_ENQUEUE(&txq->ift_task);
159495246abbSSean Bruno 	}
159595246abbSSean Bruno 	if (ctx->ifc_sctx->isc_flags & IFLIB_HAS_RXCQ)
159695246abbSSean Bruno 		cidx = rxq->ifr_cq_cidx;
159795246abbSSean Bruno 	else
159895246abbSSean Bruno 		cidx = rxq->ifr_fl[0].ifl_cidx;
159995246abbSSean Bruno 	if (iflib_rxd_avail(ctx, rxq, cidx, 1))
160095246abbSSean Bruno 		GROUPTASK_ENQUEUE(gtask);
160164e6fc13SStephen Hurd 	else {
16023d10e9edSMarius Strobl 		if (intr_legacy)
16033d10e9edSMarius Strobl 			intr_enable = true;
16043d10e9edSMarius Strobl 		else
160595246abbSSean Bruno 			IFDI_RX_QUEUE_INTR_ENABLE(ctx, rxq->ifr_id);
160664e6fc13SStephen Hurd 		DBG_COUNTER_INC(rx_intr_enables);
160764e6fc13SStephen Hurd 	}
16083d10e9edSMarius Strobl 	if (intr_enable)
16093d10e9edSMarius Strobl 		IFDI_INTR_ENABLE(ctx);
161095246abbSSean Bruno 	return (FILTER_HANDLED);
161195246abbSSean Bruno }
161295246abbSSean Bruno 
161395246abbSSean Bruno static int
161495246abbSSean Bruno iflib_fast_intr_ctx(void *arg)
161595246abbSSean Bruno {
161695246abbSSean Bruno 	iflib_filter_info_t info = arg;
161795246abbSSean Bruno 	struct grouptask *gtask = info->ifi_task;
1618ca62461bSStephen Hurd 	int result;
16194c7070dbSScott Long 
16204c7070dbSScott Long 	DBG_COUNTER_INC(fast_intrs);
1621ca62461bSStephen Hurd 	if (info->ifi_filter != NULL) {
1622ca62461bSStephen Hurd 		result = info->ifi_filter(info->ifi_filter_arg);
1623ca62461bSStephen Hurd 		if ((result & FILTER_SCHEDULE_THREAD) == 0)
1624ca62461bSStephen Hurd 			return (result);
1625ca62461bSStephen Hurd 	}
16264c7070dbSScott Long 
16274c7070dbSScott Long 	GROUPTASK_ENQUEUE(gtask);
16284c7070dbSScott Long 	return (FILTER_HANDLED);
16294c7070dbSScott Long }
16304c7070dbSScott Long 
16314c7070dbSScott Long static int
16324c7070dbSScott Long _iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid,
16334c7070dbSScott Long 		 driver_filter_t filter, driver_intr_t handler, void *arg,
16343e0e6330SStephen Hurd 		 const char *name)
16354c7070dbSScott Long {
16364c7070dbSScott Long 	struct resource *res;
16372b2fc973SSean Bruno 	void *tag = NULL;
16384c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
1639d49e83eaSMarius Strobl 	int flags, i, rc;
16404c7070dbSScott Long 
16412b2fc973SSean Bruno 	flags = RF_ACTIVE;
16422b2fc973SSean Bruno 	if (ctx->ifc_flags & IFC_LEGACY)
16432b2fc973SSean Bruno 		flags |= RF_SHAREABLE;
16444c7070dbSScott Long 	MPASS(rid < 512);
1645d49e83eaSMarius Strobl 	i = rid;
1646d49e83eaSMarius Strobl 	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, flags);
16474c7070dbSScott Long 	if (res == NULL) {
16484c7070dbSScott Long 		device_printf(dev,
16494c7070dbSScott Long 		    "failed to allocate IRQ for rid %d, name %s.\n", rid, name);
16504c7070dbSScott Long 		return (ENOMEM);
16514c7070dbSScott Long 	}
16524c7070dbSScott Long 	irq->ii_res = res;
16534c7070dbSScott Long 	KASSERT(filter == NULL || handler == NULL, ("filter and handler can't both be non-NULL"));
16544c7070dbSScott Long 	rc = bus_setup_intr(dev, res, INTR_MPSAFE | INTR_TYPE_NET,
16554c7070dbSScott Long 						filter, handler, arg, &tag);
16564c7070dbSScott Long 	if (rc != 0) {
16574c7070dbSScott Long 		device_printf(dev,
16584c7070dbSScott Long 		    "failed to setup interrupt for rid %d, name %s: %d\n",
16594c7070dbSScott Long 					  rid, name ? name : "unknown", rc);
16604c7070dbSScott Long 		return (rc);
16614c7070dbSScott Long 	} else if (name)
1662f454e7ebSJohn Baldwin 		bus_describe_intr(dev, res, tag, "%s", name);
16634c7070dbSScott Long 
16644c7070dbSScott Long 	irq->ii_tag = tag;
16654c7070dbSScott Long 	return (0);
16664c7070dbSScott Long }
16674c7070dbSScott Long 
16684c7070dbSScott Long /*********************************************************************
16694c7070dbSScott Long  *
1670bfce461eSMarius Strobl  *  Allocate DMA resources for TX buffers as well as memory for the TX
1671bfce461eSMarius Strobl  *  mbuf map.  TX DMA maps (non-TSO/TSO) and TX mbuf map are kept in a
1672bfce461eSMarius Strobl  *  iflib_sw_tx_desc_array structure, storing all the information that
1673bfce461eSMarius Strobl  *  is needed to transmit a packet on the wire.  This is called only
1674bfce461eSMarius Strobl  *  once at attach, setup is done every reset.
16754c7070dbSScott Long  *
16764c7070dbSScott Long  **********************************************************************/
16774c7070dbSScott Long static int
16784c7070dbSScott Long iflib_txsd_alloc(iflib_txq_t txq)
16794c7070dbSScott Long {
16804c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
16814c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
16824c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
16834c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
16847f87c040SMarius Strobl 	bus_size_t tsomaxsize;
16856dd69f00SMarcin Wojtas 	bus_addr_t lowaddr;
16864c7070dbSScott Long 	int err, nsegments, ntsosegments;
16878a04b53dSKonstantin Belousov 	bool tso;
16884c7070dbSScott Long 
16894c7070dbSScott Long 	nsegments = scctx->isc_tx_nsegments;
16904c7070dbSScott Long 	ntsosegments = scctx->isc_tx_tso_segments_max;
16917f87c040SMarius Strobl 	tsomaxsize = scctx->isc_tx_tso_size_max;
16927f87c040SMarius Strobl 	if (if_getcapabilities(ctx->ifc_ifp) & IFCAP_VLAN_MTU)
16937f87c040SMarius Strobl 		tsomaxsize += sizeof(struct ether_vlan_header);
169423ac9029SStephen Hurd 	MPASS(scctx->isc_ntxd[0] > 0);
169523ac9029SStephen Hurd 	MPASS(scctx->isc_ntxd[txq->ift_br_offset] > 0);
16964c7070dbSScott Long 	MPASS(nsegments > 0);
16977f87c040SMarius Strobl 	if (if_getcapabilities(ctx->ifc_ifp) & IFCAP_TSO) {
16984c7070dbSScott Long 		MPASS(ntsosegments > 0);
16997f87c040SMarius Strobl 		MPASS(sctx->isc_tso_maxsize >= tsomaxsize);
17007f87c040SMarius Strobl 	}
17017f87c040SMarius Strobl 
17026dd69f00SMarcin Wojtas 	lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(scctx->isc_dma_width);
17036dd69f00SMarcin Wojtas 
17044c7070dbSScott Long 	/*
1705bfce461eSMarius Strobl 	 * Set up DMA tags for TX buffers.
17064c7070dbSScott Long 	 */
17074c7070dbSScott Long 	if ((err = bus_dma_tag_create(bus_get_dma_tag(dev),
17084c7070dbSScott Long 			       1, 0,			/* alignment, bounds */
17096dd69f00SMarcin Wojtas 			       lowaddr,			/* lowaddr */
17104c7070dbSScott Long 			       BUS_SPACE_MAXADDR,	/* highaddr */
17114c7070dbSScott Long 			       NULL, NULL,		/* filter, filterarg */
17124c7070dbSScott Long 			       sctx->isc_tx_maxsize,		/* maxsize */
17134c7070dbSScott Long 			       nsegments,	/* nsegments */
17144c7070dbSScott Long 			       sctx->isc_tx_maxsegsize,	/* maxsegsize */
17154c7070dbSScott Long 			       0,			/* flags */
17164c7070dbSScott Long 			       NULL,			/* lockfunc */
17174c7070dbSScott Long 			       NULL,			/* lockfuncarg */
1718bfce461eSMarius Strobl 			       &txq->ift_buf_tag))) {
17194c7070dbSScott Long 		device_printf(dev,"Unable to allocate TX DMA tag: %d\n", err);
17209d0a88deSDimitry Andric 		device_printf(dev,"maxsize: %ju nsegments: %d maxsegsize: %ju\n",
17219d0a88deSDimitry Andric 		    (uintmax_t)sctx->isc_tx_maxsize, nsegments, (uintmax_t)sctx->isc_tx_maxsegsize);
17224c7070dbSScott Long 		goto fail;
17234c7070dbSScott Long 	}
17248a04b53dSKonstantin Belousov 	tso = (if_getcapabilities(ctx->ifc_ifp) & IFCAP_TSO) != 0;
17258a04b53dSKonstantin Belousov 	if (tso && (err = bus_dma_tag_create(bus_get_dma_tag(dev),
17264c7070dbSScott Long 			       1, 0,			/* alignment, bounds */
17276dd69f00SMarcin Wojtas 			       lowaddr,			/* lowaddr */
17284c7070dbSScott Long 			       BUS_SPACE_MAXADDR,	/* highaddr */
17294c7070dbSScott Long 			       NULL, NULL,		/* filter, filterarg */
17307f87c040SMarius Strobl 			       tsomaxsize,		/* maxsize */
17314c7070dbSScott Long 			       ntsosegments,	/* nsegments */
17327f87c040SMarius Strobl 			       sctx->isc_tso_maxsegsize,/* maxsegsize */
17334c7070dbSScott Long 			       0,			/* flags */
17344c7070dbSScott Long 			       NULL,			/* lockfunc */
17354c7070dbSScott Long 			       NULL,			/* lockfuncarg */
1736bfce461eSMarius Strobl 			       &txq->ift_tso_buf_tag))) {
1737bfce461eSMarius Strobl 		device_printf(dev, "Unable to allocate TSO TX DMA tag: %d\n",
1738bfce461eSMarius Strobl 		    err);
17394c7070dbSScott Long 		goto fail;
17404c7070dbSScott Long 	}
1741bfce461eSMarius Strobl 
1742bfce461eSMarius Strobl 	/* Allocate memory for the TX mbuf map. */
17434c7070dbSScott Long 	if (!(txq->ift_sds.ifsd_m =
1744ac2fffa4SPedro F. Giffuni 	    (struct mbuf **) malloc(sizeof(struct mbuf *) *
1745ac2fffa4SPedro F. Giffuni 	    scctx->isc_ntxd[txq->ift_br_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1746bfce461eSMarius Strobl 		device_printf(dev, "Unable to allocate TX mbuf map memory\n");
17474c7070dbSScott Long 		err = ENOMEM;
17484c7070dbSScott Long 		goto fail;
17494c7070dbSScott Long 	}
17504c7070dbSScott Long 
1751bfce461eSMarius Strobl 	/*
1752bfce461eSMarius Strobl 	 * Create the DMA maps for TX buffers.
1753bfce461eSMarius Strobl 	 */
17548a04b53dSKonstantin Belousov 	if ((txq->ift_sds.ifsd_map = (bus_dmamap_t *)malloc(
17558a04b53dSKonstantin Belousov 	    sizeof(bus_dmamap_t) * scctx->isc_ntxd[txq->ift_br_offset],
17568a04b53dSKonstantin Belousov 	    M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
1757bfce461eSMarius Strobl 		device_printf(dev,
1758bfce461eSMarius Strobl 		    "Unable to allocate TX buffer DMA map memory\n");
17594c7070dbSScott Long 		err = ENOMEM;
17604c7070dbSScott Long 		goto fail;
17614c7070dbSScott Long 	}
17628a04b53dSKonstantin Belousov 	if (tso && (txq->ift_sds.ifsd_tso_map = (bus_dmamap_t *)malloc(
17638a04b53dSKonstantin Belousov 	    sizeof(bus_dmamap_t) * scctx->isc_ntxd[txq->ift_br_offset],
17648a04b53dSKonstantin Belousov 	    M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
1765bfce461eSMarius Strobl 		device_printf(dev,
1766bfce461eSMarius Strobl 		    "Unable to allocate TSO TX buffer map memory\n");
17678a04b53dSKonstantin Belousov 		err = ENOMEM;
17688a04b53dSKonstantin Belousov 		goto fail;
17698a04b53dSKonstantin Belousov 	}
177023ac9029SStephen Hurd 	for (int i = 0; i < scctx->isc_ntxd[txq->ift_br_offset]; i++) {
1771bfce461eSMarius Strobl 		err = bus_dmamap_create(txq->ift_buf_tag, 0,
17728a04b53dSKonstantin Belousov 		    &txq->ift_sds.ifsd_map[i]);
17734c7070dbSScott Long 		if (err != 0) {
17744c7070dbSScott Long 			device_printf(dev, "Unable to create TX DMA map\n");
17754c7070dbSScott Long 			goto fail;
17764c7070dbSScott Long 		}
17778a04b53dSKonstantin Belousov 		if (!tso)
17788a04b53dSKonstantin Belousov 			continue;
1779bfce461eSMarius Strobl 		err = bus_dmamap_create(txq->ift_tso_buf_tag, 0,
17808a04b53dSKonstantin Belousov 		    &txq->ift_sds.ifsd_tso_map[i]);
17818a04b53dSKonstantin Belousov 		if (err != 0) {
17828a04b53dSKonstantin Belousov 			device_printf(dev, "Unable to create TSO TX DMA map\n");
17838a04b53dSKonstantin Belousov 			goto fail;
17848a04b53dSKonstantin Belousov 		}
17854c7070dbSScott Long 	}
17864c7070dbSScott Long 	return (0);
17874c7070dbSScott Long fail:
17884c7070dbSScott Long 	/* We free all, it handles case where we are in the middle */
17894c7070dbSScott Long 	iflib_tx_structures_free(ctx);
17904c7070dbSScott Long 	return (err);
17914c7070dbSScott Long }
17924c7070dbSScott Long 
17934c7070dbSScott Long static void
17944c7070dbSScott Long iflib_txsd_destroy(if_ctx_t ctx, iflib_txq_t txq, int i)
17954c7070dbSScott Long {
17964c7070dbSScott Long 	bus_dmamap_t map;
17974c7070dbSScott Long 
1798db8e8f1eSEric Joyner 	if (txq->ift_sds.ifsd_map != NULL) {
17994c7070dbSScott Long 		map = txq->ift_sds.ifsd_map[i];
1800bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_buf_tag, map, BUS_DMASYNC_POSTWRITE);
1801bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_buf_tag, map);
1802bfce461eSMarius Strobl 		bus_dmamap_destroy(txq->ift_buf_tag, map);
18034c7070dbSScott Long 		txq->ift_sds.ifsd_map[i] = NULL;
18044c7070dbSScott Long 	}
18058a04b53dSKonstantin Belousov 
1806db8e8f1eSEric Joyner 	if (txq->ift_sds.ifsd_tso_map != NULL) {
18078a04b53dSKonstantin Belousov 		map = txq->ift_sds.ifsd_tso_map[i];
1808bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_tso_buf_tag, map,
18098a04b53dSKonstantin Belousov 		    BUS_DMASYNC_POSTWRITE);
1810bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_tso_buf_tag, map);
1811bfce461eSMarius Strobl 		bus_dmamap_destroy(txq->ift_tso_buf_tag, map);
18128a04b53dSKonstantin Belousov 		txq->ift_sds.ifsd_tso_map[i] = NULL;
18138a04b53dSKonstantin Belousov 	}
18144c7070dbSScott Long }
18154c7070dbSScott Long 
18164c7070dbSScott Long static void
18174c7070dbSScott Long iflib_txq_destroy(iflib_txq_t txq)
18184c7070dbSScott Long {
18194c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
18204c7070dbSScott Long 
182123ac9029SStephen Hurd 	for (int i = 0; i < txq->ift_size; i++)
18224c7070dbSScott Long 		iflib_txsd_destroy(ctx, txq, i);
1823244e7cffSEric Joyner 
1824244e7cffSEric Joyner 	if (txq->ift_br != NULL) {
1825244e7cffSEric Joyner 		ifmp_ring_free(txq->ift_br);
1826244e7cffSEric Joyner 		txq->ift_br = NULL;
1827244e7cffSEric Joyner 	}
1828244e7cffSEric Joyner 
1829244e7cffSEric Joyner 	mtx_destroy(&txq->ift_mtx);
1830244e7cffSEric Joyner 
18314c7070dbSScott Long 	if (txq->ift_sds.ifsd_map != NULL) {
18324c7070dbSScott Long 		free(txq->ift_sds.ifsd_map, M_IFLIB);
18334c7070dbSScott Long 		txq->ift_sds.ifsd_map = NULL;
18344c7070dbSScott Long 	}
18358a04b53dSKonstantin Belousov 	if (txq->ift_sds.ifsd_tso_map != NULL) {
18368a04b53dSKonstantin Belousov 		free(txq->ift_sds.ifsd_tso_map, M_IFLIB);
18378a04b53dSKonstantin Belousov 		txq->ift_sds.ifsd_tso_map = NULL;
18388a04b53dSKonstantin Belousov 	}
18394c7070dbSScott Long 	if (txq->ift_sds.ifsd_m != NULL) {
18404c7070dbSScott Long 		free(txq->ift_sds.ifsd_m, M_IFLIB);
18414c7070dbSScott Long 		txq->ift_sds.ifsd_m = NULL;
18424c7070dbSScott Long 	}
1843bfce461eSMarius Strobl 	if (txq->ift_buf_tag != NULL) {
1844bfce461eSMarius Strobl 		bus_dma_tag_destroy(txq->ift_buf_tag);
1845bfce461eSMarius Strobl 		txq->ift_buf_tag = NULL;
18464c7070dbSScott Long 	}
1847bfce461eSMarius Strobl 	if (txq->ift_tso_buf_tag != NULL) {
1848bfce461eSMarius Strobl 		bus_dma_tag_destroy(txq->ift_tso_buf_tag);
1849bfce461eSMarius Strobl 		txq->ift_tso_buf_tag = NULL;
18504c7070dbSScott Long 	}
1851244e7cffSEric Joyner 	if (txq->ift_ifdi != NULL) {
1852244e7cffSEric Joyner 		free(txq->ift_ifdi, M_IFLIB);
1853244e7cffSEric Joyner 	}
18544c7070dbSScott Long }
18554c7070dbSScott Long 
18564c7070dbSScott Long static void
18574c7070dbSScott Long iflib_txsd_free(if_ctx_t ctx, iflib_txq_t txq, int i)
18584c7070dbSScott Long {
18594c7070dbSScott Long 	struct mbuf **mp;
18604c7070dbSScott Long 
18614c7070dbSScott Long 	mp = &txq->ift_sds.ifsd_m[i];
18624c7070dbSScott Long 	if (*mp == NULL)
18634c7070dbSScott Long 		return;
18644c7070dbSScott Long 
18654c7070dbSScott Long 	if (txq->ift_sds.ifsd_map != NULL) {
1866bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_buf_tag,
18678a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_map[i], BUS_DMASYNC_POSTWRITE);
1868bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_buf_tag, txq->ift_sds.ifsd_map[i]);
18698a04b53dSKonstantin Belousov 	}
18708a04b53dSKonstantin Belousov 	if (txq->ift_sds.ifsd_tso_map != NULL) {
1871bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_tso_buf_tag,
18728a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_tso_map[i], BUS_DMASYNC_POSTWRITE);
1873bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_tso_buf_tag,
18748a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_tso_map[i]);
18754c7070dbSScott Long 	}
187654bf96fbSMark Johnston 	m_freem(*mp);
18774c7070dbSScott Long 	DBG_COUNTER_INC(tx_frees);
18784c7070dbSScott Long 	*mp = NULL;
18794c7070dbSScott Long }
18804c7070dbSScott Long 
18814c7070dbSScott Long static int
18824c7070dbSScott Long iflib_txq_setup(iflib_txq_t txq)
18834c7070dbSScott Long {
18844c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
188523ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
18864d261ce2SStephen Hurd 	if_shared_ctx_t sctx = ctx->ifc_sctx;
18874c7070dbSScott Long 	iflib_dma_info_t di;
18884c7070dbSScott Long 	int i;
18894c7070dbSScott Long 
18904c7070dbSScott Long 	/* Set number of descriptors available */
18914c7070dbSScott Long 	txq->ift_qstatus = IFLIB_QUEUE_IDLE;
189295246abbSSean Bruno 	/* XXX make configurable */
189395246abbSSean Bruno 	txq->ift_update_freq = IFLIB_DEFAULT_TX_UPDATE_FREQ;
18944c7070dbSScott Long 
18954c7070dbSScott Long 	/* Reset indices */
189695246abbSSean Bruno 	txq->ift_cidx_processed = 0;
189795246abbSSean Bruno 	txq->ift_pidx = txq->ift_cidx = txq->ift_npending = 0;
189823ac9029SStephen Hurd 	txq->ift_size = scctx->isc_ntxd[txq->ift_br_offset];
18994c7070dbSScott Long 
19004d261ce2SStephen Hurd 	for (i = 0, di = txq->ift_ifdi; i < sctx->isc_ntxqs; i++, di++)
19014c7070dbSScott Long 		bzero((void *)di->idi_vaddr, di->idi_size);
19024c7070dbSScott Long 
19034c7070dbSScott Long 	IFDI_TXQ_SETUP(ctx, txq->ift_id);
19044d261ce2SStephen Hurd 	for (i = 0, di = txq->ift_ifdi; i < sctx->isc_ntxqs; i++, di++)
19054c7070dbSScott Long 		bus_dmamap_sync(di->idi_tag, di->idi_map,
19064c7070dbSScott Long 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
19074c7070dbSScott Long 	return (0);
19084c7070dbSScott Long }
19094c7070dbSScott Long 
19104c7070dbSScott Long /*********************************************************************
19114c7070dbSScott Long  *
1912bfce461eSMarius Strobl  *  Allocate DMA resources for RX buffers as well as memory for the RX
1913bfce461eSMarius Strobl  *  mbuf map, direct RX cluster pointer map and RX cluster bus address
1914bfce461eSMarius Strobl  *  map.  RX DMA map, RX mbuf map, direct RX cluster pointer map and
1915bfce461eSMarius Strobl  *  RX cluster map are kept in a iflib_sw_rx_desc_array structure.
1916bfce461eSMarius Strobl  *  Since we use use one entry in iflib_sw_rx_desc_array per received
1917bfce461eSMarius Strobl  *  packet, the maximum number of entries we'll need is equal to the
1918bfce461eSMarius Strobl  *  number of hardware receive descriptors that we've allocated.
19194c7070dbSScott Long  *
19204c7070dbSScott Long  **********************************************************************/
19214c7070dbSScott Long static int
19224c7070dbSScott Long iflib_rxsd_alloc(iflib_rxq_t rxq)
19234c7070dbSScott Long {
19244c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
19254c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
192623ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
19274c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
19284c7070dbSScott Long 	iflib_fl_t fl;
19296dd69f00SMarcin Wojtas 	bus_addr_t lowaddr;
19304c7070dbSScott Long 	int			err;
19314c7070dbSScott Long 
193223ac9029SStephen Hurd 	MPASS(scctx->isc_nrxd[0] > 0);
193323ac9029SStephen Hurd 	MPASS(scctx->isc_nrxd[rxq->ifr_fl_offset] > 0);
19344c7070dbSScott Long 
19356dd69f00SMarcin Wojtas 	lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(scctx->isc_dma_width);
19366dd69f00SMarcin Wojtas 
19374c7070dbSScott Long 	fl = rxq->ifr_fl;
19384c7070dbSScott Long 	for (int i = 0; i <  rxq->ifr_nfl; i++, fl++) {
193923ac9029SStephen Hurd 		fl->ifl_size = scctx->isc_nrxd[rxq->ifr_fl_offset]; /* this isn't necessarily the same */
1940bfce461eSMarius Strobl 		/* Set up DMA tag for RX buffers. */
19414c7070dbSScott Long 		err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
19424c7070dbSScott Long 					 1, 0,			/* alignment, bounds */
19436dd69f00SMarcin Wojtas 					 lowaddr,		/* lowaddr */
19444c7070dbSScott Long 					 BUS_SPACE_MAXADDR,	/* highaddr */
19454c7070dbSScott Long 					 NULL, NULL,		/* filter, filterarg */
19464c7070dbSScott Long 					 sctx->isc_rx_maxsize,	/* maxsize */
19474c7070dbSScott Long 					 sctx->isc_rx_nsegments,	/* nsegments */
19484c7070dbSScott Long 					 sctx->isc_rx_maxsegsize,	/* maxsegsize */
19494c7070dbSScott Long 					 0,			/* flags */
19504c7070dbSScott Long 					 NULL,			/* lockfunc */
19514c7070dbSScott Long 					 NULL,			/* lockarg */
1952bfce461eSMarius Strobl 					 &fl->ifl_buf_tag);
19534c7070dbSScott Long 		if (err) {
1954bfce461eSMarius Strobl 			device_printf(dev,
1955bfce461eSMarius Strobl 			    "Unable to allocate RX DMA tag: %d\n", err);
19564c7070dbSScott Long 			goto fail;
19574c7070dbSScott Long 		}
1958bfce461eSMarius Strobl 
1959bfce461eSMarius Strobl 		/* Allocate memory for the RX mbuf map. */
1960e035717eSSean Bruno 		if (!(fl->ifl_sds.ifsd_m =
1961ac2fffa4SPedro F. Giffuni 		      (struct mbuf **) malloc(sizeof(struct mbuf *) *
1962ac2fffa4SPedro F. Giffuni 					      scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1963bfce461eSMarius Strobl 			device_printf(dev,
1964bfce461eSMarius Strobl 			    "Unable to allocate RX mbuf map memory\n");
1965e035717eSSean Bruno 			err = ENOMEM;
1966e035717eSSean Bruno 			goto fail;
1967e035717eSSean Bruno 		}
1968bfce461eSMarius Strobl 
1969bfce461eSMarius Strobl 		/* Allocate memory for the direct RX cluster pointer map. */
1970e035717eSSean Bruno 		if (!(fl->ifl_sds.ifsd_cl =
1971ac2fffa4SPedro F. Giffuni 		      (caddr_t *) malloc(sizeof(caddr_t) *
1972ac2fffa4SPedro F. Giffuni 					      scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1973bfce461eSMarius Strobl 			device_printf(dev,
1974bfce461eSMarius Strobl 			    "Unable to allocate RX cluster map memory\n");
1975e035717eSSean Bruno 			err = ENOMEM;
1976e035717eSSean Bruno 			goto fail;
1977e035717eSSean Bruno 		}
19784c7070dbSScott Long 
1979bfce461eSMarius Strobl 		/* Allocate memory for the RX cluster bus address map. */
1980fbec776dSAndrew Gallatin 		if (!(fl->ifl_sds.ifsd_ba =
1981fbec776dSAndrew Gallatin 		      (bus_addr_t *) malloc(sizeof(bus_addr_t) *
1982fbec776dSAndrew Gallatin 					      scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1983bfce461eSMarius Strobl 			device_printf(dev,
1984bfce461eSMarius Strobl 			    "Unable to allocate RX bus address map memory\n");
1985fbec776dSAndrew Gallatin 			err = ENOMEM;
1986fbec776dSAndrew Gallatin 			goto fail;
1987fbec776dSAndrew Gallatin 		}
1988e035717eSSean Bruno 
1989bfce461eSMarius Strobl 		/*
1990bfce461eSMarius Strobl 		 * Create the DMA maps for RX buffers.
1991bfce461eSMarius Strobl 		 */
1992e035717eSSean Bruno 		if (!(fl->ifl_sds.ifsd_map =
1993ac2fffa4SPedro F. Giffuni 		      (bus_dmamap_t *) malloc(sizeof(bus_dmamap_t) * scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1994bfce461eSMarius Strobl 			device_printf(dev,
1995bfce461eSMarius Strobl 			    "Unable to allocate RX buffer DMA map memory\n");
1996e035717eSSean Bruno 			err = ENOMEM;
1997e035717eSSean Bruno 			goto fail;
1998e035717eSSean Bruno 		}
1999e035717eSSean Bruno 		for (int i = 0; i < scctx->isc_nrxd[rxq->ifr_fl_offset]; i++) {
2000bfce461eSMarius Strobl 			err = bus_dmamap_create(fl->ifl_buf_tag, 0,
2001bfce461eSMarius Strobl 			    &fl->ifl_sds.ifsd_map[i]);
2002e035717eSSean Bruno 			if (err != 0) {
200395246abbSSean Bruno 				device_printf(dev, "Unable to create RX buffer DMA map\n");
20044c7070dbSScott Long 				goto fail;
20054c7070dbSScott Long 			}
20064c7070dbSScott Long 		}
2007835809f9SSean Bruno 	}
20084c7070dbSScott Long 	return (0);
20094c7070dbSScott Long 
20104c7070dbSScott Long fail:
20114c7070dbSScott Long 	iflib_rx_structures_free(ctx);
20124c7070dbSScott Long 	return (err);
20134c7070dbSScott Long }
20144c7070dbSScott Long 
20154c7070dbSScott Long /*
20164c7070dbSScott Long  * Internal service routines
20174c7070dbSScott Long  */
20184c7070dbSScott Long 
20194c7070dbSScott Long struct rxq_refill_cb_arg {
20204c7070dbSScott Long 	int               error;
20214c7070dbSScott Long 	bus_dma_segment_t seg;
20224c7070dbSScott Long 	int               nseg;
20234c7070dbSScott Long };
20244c7070dbSScott Long 
20254c7070dbSScott Long static void
20264c7070dbSScott Long _rxq_refill_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
20274c7070dbSScott Long {
20284c7070dbSScott Long 	struct rxq_refill_cb_arg *cb_arg = arg;
20294c7070dbSScott Long 
20304c7070dbSScott Long 	cb_arg->error = error;
20314c7070dbSScott Long 	cb_arg->seg = segs[0];
20324c7070dbSScott Long 	cb_arg->nseg = nseg;
20334c7070dbSScott Long }
20344c7070dbSScott Long 
20354c7070dbSScott Long /**
2036b256d25cSMark Johnston  * iflib_fl_refill - refill an rxq free-buffer list
20374c7070dbSScott Long  * @ctx: the iflib context
20381722eeacSMarius Strobl  * @fl: the free list to refill
20391722eeacSMarius Strobl  * @count: the number of new buffers to allocate
20404c7070dbSScott Long  *
20411722eeacSMarius Strobl  * (Re)populate an rxq free-buffer list with up to @count new packet buffers.
204235d8a463SVincenzo Maffione  * The caller must assure that @count does not exceed the queue's capacity
204335d8a463SVincenzo Maffione  * minus one (since we always leave a descriptor unavailable).
20444c7070dbSScott Long  */
2045fb1a29b4SHans Petter Selasky static uint8_t
2046b256d25cSMark Johnston iflib_fl_refill(if_ctx_t ctx, iflib_fl_t fl, int count)
20474c7070dbSScott Long {
204895246abbSSean Bruno 	struct if_rxd_update iru;
2049fbec776dSAndrew Gallatin 	struct rxq_refill_cb_arg cb_arg;
20503db348b5SMarius Strobl 	struct mbuf *m;
20513db348b5SMarius Strobl 	caddr_t cl, *sd_cl;
20523db348b5SMarius Strobl 	struct mbuf **sd_m;
2053e035717eSSean Bruno 	bus_dmamap_t *sd_map;
2054fbec776dSAndrew Gallatin 	bus_addr_t bus_addr, *sd_ba;
20553db348b5SMarius Strobl 	int err, frag_idx, i, idx, n, pidx;
2056a1b799caSStephen Hurd 	qidx_t credits;
20574c7070dbSScott Long 
205835d8a463SVincenzo Maffione 	MPASS(count <= fl->ifl_size - fl->ifl_credits - 1);
205935d8a463SVincenzo Maffione 
2060e035717eSSean Bruno 	sd_m = fl->ifl_sds.ifsd_m;
2061e035717eSSean Bruno 	sd_map = fl->ifl_sds.ifsd_map;
2062e035717eSSean Bruno 	sd_cl = fl->ifl_sds.ifsd_cl;
2063fbec776dSAndrew Gallatin 	sd_ba = fl->ifl_sds.ifsd_ba;
20643db348b5SMarius Strobl 	pidx = fl->ifl_pidx;
2065e035717eSSean Bruno 	idx = pidx;
20663db348b5SMarius Strobl 	frag_idx = fl->ifl_fragidx;
2067a1b799caSStephen Hurd 	credits = fl->ifl_credits;
2068e035717eSSean Bruno 
20693db348b5SMarius Strobl 	i = 0;
20704c7070dbSScott Long 	n = count;
20714c7070dbSScott Long 	MPASS(n > 0);
2072a1b799caSStephen Hurd 	MPASS(credits + n <= fl->ifl_size);
20734c7070dbSScott Long 
20744c7070dbSScott Long 	if (pidx < fl->ifl_cidx)
20754c7070dbSScott Long 		MPASS(pidx + n <= fl->ifl_cidx);
2076a1b799caSStephen Hurd 	if (pidx == fl->ifl_cidx && (credits < fl->ifl_size))
20774c7070dbSScott Long 		MPASS(fl->ifl_gen == 0);
20784c7070dbSScott Long 	if (pidx > fl->ifl_cidx)
20794c7070dbSScott Long 		MPASS(n <= fl->ifl_size - pidx + fl->ifl_cidx);
20804c7070dbSScott Long 
20814c7070dbSScott Long 	DBG_COUNTER_INC(fl_refills);
20824c7070dbSScott Long 	if (n > 8)
20834c7070dbSScott Long 		DBG_COUNTER_INC(fl_refills_large);
20842d873474SStephen Hurd 	iru_init(&iru, fl->ifl_rxq, fl->ifl_id);
2085b256d25cSMark Johnston 	while (n-- > 0) {
20864c7070dbSScott Long 		/*
20874c7070dbSScott Long 		 * We allocate an uninitialized mbuf + cluster, mbuf is
20884c7070dbSScott Long 		 * initialized after rx.
20894c7070dbSScott Long 		 *
2090b256d25cSMark Johnston 		 * If the cluster is still set then we know a minimum sized
2091b256d25cSMark Johnston 		 * packet was received
20924c7070dbSScott Long 		 */
20933db348b5SMarius Strobl 		bit_ffc_at(fl->ifl_rx_bitmap, frag_idx, fl->ifl_size,
20943db348b5SMarius Strobl 		    &frag_idx);
20953db348b5SMarius Strobl 		if (frag_idx < 0)
209687890dbaSSean Bruno 			bit_ffc(fl->ifl_rx_bitmap, fl->ifl_size, &frag_idx);
20973db348b5SMarius Strobl 		MPASS(frag_idx >= 0);
209887890dbaSSean Bruno 		if ((cl = sd_cl[frag_idx]) == NULL) {
2099b256d25cSMark Johnston 			cl = uma_zalloc(fl->ifl_zone, M_NOWAIT);
2100a363e1d4SMark Johnston 			if (__predict_false(cl == NULL))
21014c7070dbSScott Long 				break;
21024c7070dbSScott Long 
21034c7070dbSScott Long 			cb_arg.error = 0;
210495246abbSSean Bruno 			MPASS(sd_map != NULL);
2105bfce461eSMarius Strobl 			err = bus_dmamap_load(fl->ifl_buf_tag, sd_map[frag_idx],
21068a04b53dSKonstantin Belousov 			    cl, fl->ifl_buf_size, _rxq_refill_cb, &cb_arg,
21078a04b53dSKonstantin Belousov 			    BUS_DMA_NOWAIT);
2108a363e1d4SMark Johnston 			if (__predict_false(err != 0 || cb_arg.error)) {
21094c7070dbSScott Long 				uma_zfree(fl->ifl_zone, cl);
2110fbec776dSAndrew Gallatin 				break;
21114c7070dbSScott Long 			}
21124c7070dbSScott Long 
2113fbec776dSAndrew Gallatin 			sd_ba[frag_idx] = bus_addr = cb_arg.seg.ds_addr;
211487890dbaSSean Bruno 			sd_cl[frag_idx] = cl;
2115fbec776dSAndrew Gallatin #if MEMORY_LOGGING
2116fbec776dSAndrew Gallatin 			fl->ifl_cl_enqueued++;
2117fbec776dSAndrew Gallatin #endif
2118fbec776dSAndrew Gallatin 		} else {
2119fbec776dSAndrew Gallatin 			bus_addr = sd_ba[frag_idx];
2120fbec776dSAndrew Gallatin 		}
212195dcf343SMarius Strobl 		bus_dmamap_sync(fl->ifl_buf_tag, sd_map[frag_idx],
212295dcf343SMarius Strobl 		    BUS_DMASYNC_PREREAD);
2123fbec776dSAndrew Gallatin 
21246d49b41eSAndrew Gallatin 		if (sd_m[frag_idx] == NULL) {
2125a363e1d4SMark Johnston 			m = m_gethdr(M_NOWAIT, MT_NOINIT);
2126a363e1d4SMark Johnston 			if (__predict_false(m == NULL))
2127fbec776dSAndrew Gallatin 				break;
212887890dbaSSean Bruno 			sd_m[frag_idx] = m;
21296d49b41eSAndrew Gallatin 		}
21303db348b5SMarius Strobl 		bit_set(fl->ifl_rx_bitmap, frag_idx);
2131fbec776dSAndrew Gallatin #if MEMORY_LOGGING
2132fbec776dSAndrew Gallatin 		fl->ifl_m_enqueued++;
2133fbec776dSAndrew Gallatin #endif
2134fbec776dSAndrew Gallatin 
2135fbec776dSAndrew Gallatin 		DBG_COUNTER_INC(rx_allocs);
213687890dbaSSean Bruno 		fl->ifl_rxd_idxs[i] = frag_idx;
21374c7070dbSScott Long 		fl->ifl_bus_addrs[i] = bus_addr;
2138a1b799caSStephen Hurd 		credits++;
21394c7070dbSScott Long 		i++;
2140a1b799caSStephen Hurd 		MPASS(credits <= fl->ifl_size);
2141e035717eSSean Bruno 		if (++idx == fl->ifl_size) {
2142b256d25cSMark Johnston #ifdef INVARIANTS
21434c7070dbSScott Long 			fl->ifl_gen = 1;
2144b256d25cSMark Johnston #endif
2145e035717eSSean Bruno 			idx = 0;
21464c7070dbSScott Long 		}
21474c7070dbSScott Long 		if (n == 0 || i == IFLIB_MAX_RX_REFRESH) {
214895246abbSSean Bruno 			iru.iru_pidx = pidx;
214995246abbSSean Bruno 			iru.iru_count = i;
215095246abbSSean Bruno 			ctx->isc_rxd_refill(ctx->ifc_softc, &iru);
2151fa5416a8SSean Bruno 			fl->ifl_pidx = idx;
2152a1b799caSStephen Hurd 			fl->ifl_credits = credits;
2153b256d25cSMark Johnston 			pidx = idx;
2154b256d25cSMark Johnston 			i = 0;
215587890dbaSSean Bruno 		}
21564c7070dbSScott Long 	}
2157fbec776dSAndrew Gallatin 
2158a363e1d4SMark Johnston 	if (n < count - 1) {
2159a363e1d4SMark Johnston 		if (i != 0) {
2160a1b799caSStephen Hurd 			iru.iru_pidx = pidx;
2161a1b799caSStephen Hurd 			iru.iru_count = i;
2162a1b799caSStephen Hurd 			ctx->isc_rxd_refill(ctx->ifc_softc, &iru);
2163a1b799caSStephen Hurd 			fl->ifl_pidx = idx;
2164a1b799caSStephen Hurd 			fl->ifl_credits = credits;
2165a1b799caSStephen Hurd 		}
21664c7070dbSScott Long 		DBG_COUNTER_INC(rxd_flush);
216795246abbSSean Bruno 		bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
216895246abbSSean Bruno 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2169a363e1d4SMark Johnston 		ctx->isc_rxd_flush(ctx->ifc_softc, fl->ifl_rxq->ifr_id,
217035d8a463SVincenzo Maffione 		    fl->ifl_id, fl->ifl_pidx);
2171a363e1d4SMark Johnston 		if (__predict_true(bit_test(fl->ifl_rx_bitmap, frag_idx))) {
21729e9b738aSPatrick Kelsey 			fl->ifl_fragidx = frag_idx + 1;
21739e9b738aSPatrick Kelsey 			if (fl->ifl_fragidx == fl->ifl_size)
21749e9b738aSPatrick Kelsey 				fl->ifl_fragidx = 0;
2175a363e1d4SMark Johnston 		} else {
2176a363e1d4SMark Johnston 			fl->ifl_fragidx = frag_idx;
2177a363e1d4SMark Johnston 		}
2178a363e1d4SMark Johnston 	}
2179fb1a29b4SHans Petter Selasky 
2180fb1a29b4SHans Petter Selasky 	return (n == -1 ? 0 : IFLIB_RXEOF_EMPTY);
21814c7070dbSScott Long }
21824c7070dbSScott Long 
2183b256d25cSMark Johnston static inline uint8_t
2184b256d25cSMark Johnston iflib_fl_refill_all(if_ctx_t ctx, iflib_fl_t fl)
21854c7070dbSScott Long {
218635d8a463SVincenzo Maffione 	/*
218735d8a463SVincenzo Maffione 	 * We leave an unused descriptor to avoid pidx to catch up with cidx.
218835d8a463SVincenzo Maffione 	 * This is important as it confuses most NICs. For instance,
218935d8a463SVincenzo Maffione 	 * Intel NICs have (per receive ring) RDH and RDT registers, where
219035d8a463SVincenzo Maffione 	 * RDH points to the next receive descriptor to be used by the NIC,
219135d8a463SVincenzo Maffione 	 * and RDT for the next receive descriptor to be published by the
219235d8a463SVincenzo Maffione 	 * driver to the NIC (RDT - 1 is thus the last valid one).
219335d8a463SVincenzo Maffione 	 * The condition RDH == RDT means no descriptors are available to
219435d8a463SVincenzo Maffione 	 * the NIC, and thus it would be ambiguous if it also meant that
219535d8a463SVincenzo Maffione 	 * all the descriptors are available to the NIC.
219635d8a463SVincenzo Maffione 	 */
21974c7070dbSScott Long 	int32_t reclaimable = fl->ifl_size - fl->ifl_credits - 1;
21984c7070dbSScott Long #ifdef INVARIANTS
21994c7070dbSScott Long 	int32_t delta = fl->ifl_size - get_inuse(fl->ifl_size, fl->ifl_cidx, fl->ifl_pidx, fl->ifl_gen) - 1;
22004c7070dbSScott Long #endif
22014c7070dbSScott Long 
22024c7070dbSScott Long 	MPASS(fl->ifl_credits <= fl->ifl_size);
22034c7070dbSScott Long 	MPASS(reclaimable == delta);
22044c7070dbSScott Long 
22054c7070dbSScott Long 	if (reclaimable > 0)
2206b256d25cSMark Johnston 		return (iflib_fl_refill(ctx, fl, reclaimable));
2207fb1a29b4SHans Petter Selasky 	return (0);
22084c7070dbSScott Long }
22094c7070dbSScott Long 
221077c1fcecSEric Joyner uint8_t
221177c1fcecSEric Joyner iflib_in_detach(if_ctx_t ctx)
221277c1fcecSEric Joyner {
221377c1fcecSEric Joyner 	bool in_detach;
22141722eeacSMarius Strobl 
221577c1fcecSEric Joyner 	STATE_LOCK(ctx);
221677c1fcecSEric Joyner 	in_detach = !!(ctx->ifc_flags & IFC_IN_DETACH);
221777c1fcecSEric Joyner 	STATE_UNLOCK(ctx);
221877c1fcecSEric Joyner 	return (in_detach);
221977c1fcecSEric Joyner }
222077c1fcecSEric Joyner 
22214c7070dbSScott Long static void
22224c7070dbSScott Long iflib_fl_bufs_free(iflib_fl_t fl)
22234c7070dbSScott Long {
22244c7070dbSScott Long 	iflib_dma_info_t idi = fl->ifl_ifdi;
22258a04b53dSKonstantin Belousov 	bus_dmamap_t sd_map;
22264c7070dbSScott Long 	uint32_t i;
22274c7070dbSScott Long 
22284c7070dbSScott Long 	for (i = 0; i < fl->ifl_size; i++) {
2229e035717eSSean Bruno 		struct mbuf **sd_m = &fl->ifl_sds.ifsd_m[i];
2230e035717eSSean Bruno 		caddr_t *sd_cl = &fl->ifl_sds.ifsd_cl[i];
22314c7070dbSScott Long 
2232fbec776dSAndrew Gallatin 		if (*sd_cl != NULL) {
22338a04b53dSKonstantin Belousov 			sd_map = fl->ifl_sds.ifsd_map[i];
2234bfce461eSMarius Strobl 			bus_dmamap_sync(fl->ifl_buf_tag, sd_map,
22358a04b53dSKonstantin Belousov 			    BUS_DMASYNC_POSTREAD);
2236bfce461eSMarius Strobl 			bus_dmamap_unload(fl->ifl_buf_tag, sd_map);
2237fbec776dSAndrew Gallatin 			uma_zfree(fl->ifl_zone, *sd_cl);
2238b256d25cSMark Johnston 			*sd_cl = NULL;
2239e035717eSSean Bruno 			if (*sd_m != NULL) {
2240e035717eSSean Bruno 				m_init(*sd_m, M_NOWAIT, MT_DATA, 0);
2241e035717eSSean Bruno 				uma_zfree(zone_mbuf, *sd_m);
2242b256d25cSMark Johnston 				*sd_m = NULL;
2243e035717eSSean Bruno 			}
22444c7070dbSScott Long 		} else {
2245e035717eSSean Bruno 			MPASS(*sd_m == NULL);
22464c7070dbSScott Long 		}
22474c7070dbSScott Long #if MEMORY_LOGGING
22484c7070dbSScott Long 		fl->ifl_m_dequeued++;
22494c7070dbSScott Long 		fl->ifl_cl_dequeued++;
22504c7070dbSScott Long #endif
22514c7070dbSScott Long 	}
225295246abbSSean Bruno #ifdef INVARIANTS
225395246abbSSean Bruno 	for (i = 0; i < fl->ifl_size; i++) {
225495246abbSSean Bruno 		MPASS(fl->ifl_sds.ifsd_cl[i] == NULL);
225595246abbSSean Bruno 		MPASS(fl->ifl_sds.ifsd_m[i] == NULL);
225695246abbSSean Bruno 	}
225795246abbSSean Bruno #endif
22584c7070dbSScott Long 	/*
22594c7070dbSScott Long 	 * Reset free list values
22604c7070dbSScott Long 	 */
226187890dbaSSean Bruno 	fl->ifl_credits = fl->ifl_cidx = fl->ifl_pidx = fl->ifl_gen = fl->ifl_fragidx = 0;
22624c7070dbSScott Long 	bzero(idi->idi_vaddr, idi->idi_size);
22634c7070dbSScott Long }
22644c7070dbSScott Long 
22654c7070dbSScott Long /*********************************************************************
22664c7070dbSScott Long  *
22671722eeacSMarius Strobl  *  Initialize a free list and its buffers.
22684c7070dbSScott Long  *
22694c7070dbSScott Long  **********************************************************************/
22704c7070dbSScott Long static int
22714c7070dbSScott Long iflib_fl_setup(iflib_fl_t fl)
22724c7070dbSScott Long {
22734c7070dbSScott Long 	iflib_rxq_t rxq = fl->ifl_rxq;
22744c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
2275b3813609SPatrick Kelsey 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
2276b3813609SPatrick Kelsey 	int qidx;
22774c7070dbSScott Long 
22787274b2f6SStephen Hurd 	bit_nclear(fl->ifl_rx_bitmap, 0, fl->ifl_size - 1);
22794c7070dbSScott Long 	/*
22804c7070dbSScott Long 	** Free current RX buffer structs and their mbufs
22814c7070dbSScott Long 	*/
22824c7070dbSScott Long 	iflib_fl_bufs_free(fl);
22834c7070dbSScott Long 	/* Now replenish the mbufs */
22844c7070dbSScott Long 	MPASS(fl->ifl_credits == 0);
2285b3813609SPatrick Kelsey 	qidx = rxq->ifr_fl_offset + fl->ifl_id;
2286b3813609SPatrick Kelsey 	if (scctx->isc_rxd_buf_size[qidx] != 0)
2287b3813609SPatrick Kelsey 		fl->ifl_buf_size = scctx->isc_rxd_buf_size[qidx];
2288b3813609SPatrick Kelsey 	else
22891b9d9394SEric Joyner 		fl->ifl_buf_size = ctx->ifc_rx_mbuf_sz;
2290b3813609SPatrick Kelsey 	/*
2291b3813609SPatrick Kelsey 	 * ifl_buf_size may be a driver-supplied value, so pull it up
2292b3813609SPatrick Kelsey 	 * to the selected mbuf size.
2293b3813609SPatrick Kelsey 	 */
2294b3813609SPatrick Kelsey 	fl->ifl_buf_size = iflib_get_mbuf_size_for(fl->ifl_buf_size);
22954c7070dbSScott Long 	if (fl->ifl_buf_size > ctx->ifc_max_fl_buf_size)
22964c7070dbSScott Long 		ctx->ifc_max_fl_buf_size = fl->ifl_buf_size;
22974c7070dbSScott Long 	fl->ifl_cltype = m_gettype(fl->ifl_buf_size);
22984c7070dbSScott Long 	fl->ifl_zone = m_getzone(fl->ifl_buf_size);
22994c7070dbSScott Long 
230035d8a463SVincenzo Maffione 	/*
230135d8a463SVincenzo Maffione 	 * Avoid pre-allocating zillions of clusters to an idle card
230235d8a463SVincenzo Maffione 	 * potentially speeding up attach. In any case make sure
230335d8a463SVincenzo Maffione 	 * to leave a descriptor unavailable. See the comment in
230435d8a463SVincenzo Maffione 	 * iflib_fl_refill_all().
23054c7070dbSScott Long 	 */
230635d8a463SVincenzo Maffione 	MPASS(fl->ifl_size > 0);
230735d8a463SVincenzo Maffione 	(void)iflib_fl_refill(ctx, fl, min(128, fl->ifl_size - 1));
230835d8a463SVincenzo Maffione 	if (min(128, fl->ifl_size - 1) != fl->ifl_credits)
23094c7070dbSScott Long 		return (ENOBUFS);
23104c7070dbSScott Long 	/*
23114c7070dbSScott Long 	 * handle failure
23124c7070dbSScott Long 	 */
23134c7070dbSScott Long 	MPASS(rxq != NULL);
23144c7070dbSScott Long 	MPASS(fl->ifl_ifdi != NULL);
23154c7070dbSScott Long 	bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
23164c7070dbSScott Long 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
23174c7070dbSScott Long 	return (0);
23184c7070dbSScott Long }
23194c7070dbSScott Long 
23204c7070dbSScott Long /*********************************************************************
23214c7070dbSScott Long  *
23224c7070dbSScott Long  *  Free receive ring data structures
23234c7070dbSScott Long  *
23244c7070dbSScott Long  **********************************************************************/
23254c7070dbSScott Long static void
23264c7070dbSScott Long iflib_rx_sds_free(iflib_rxq_t rxq)
23274c7070dbSScott Long {
23284c7070dbSScott Long 	iflib_fl_t fl;
23298a04b53dSKonstantin Belousov 	int i, j;
23304c7070dbSScott Long 
23314c7070dbSScott Long 	if (rxq->ifr_fl != NULL) {
23324c7070dbSScott Long 		for (i = 0; i < rxq->ifr_nfl; i++) {
23334c7070dbSScott Long 			fl = &rxq->ifr_fl[i];
2334bfce461eSMarius Strobl 			if (fl->ifl_buf_tag != NULL) {
23358a04b53dSKonstantin Belousov 				if (fl->ifl_sds.ifsd_map != NULL) {
233677102fd6SAndrew Gallatin 					for (j = 0; j < fl->ifl_size; j++) {
23378a04b53dSKonstantin Belousov 						bus_dmamap_sync(
2338bfce461eSMarius Strobl 						    fl->ifl_buf_tag,
233977102fd6SAndrew Gallatin 						    fl->ifl_sds.ifsd_map[j],
23408a04b53dSKonstantin Belousov 						    BUS_DMASYNC_POSTREAD);
23418a04b53dSKonstantin Belousov 						bus_dmamap_unload(
2342bfce461eSMarius Strobl 						    fl->ifl_buf_tag,
234377102fd6SAndrew Gallatin 						    fl->ifl_sds.ifsd_map[j]);
2344db8e8f1eSEric Joyner 						bus_dmamap_destroy(
2345db8e8f1eSEric Joyner 						    fl->ifl_buf_tag,
2346db8e8f1eSEric Joyner 						    fl->ifl_sds.ifsd_map[j]);
23478a04b53dSKonstantin Belousov 					}
23488a04b53dSKonstantin Belousov 				}
2349bfce461eSMarius Strobl 				bus_dma_tag_destroy(fl->ifl_buf_tag);
2350bfce461eSMarius Strobl 				fl->ifl_buf_tag = NULL;
23514c7070dbSScott Long 			}
2352e035717eSSean Bruno 			free(fl->ifl_sds.ifsd_m, M_IFLIB);
2353e035717eSSean Bruno 			free(fl->ifl_sds.ifsd_cl, M_IFLIB);
2354fbec776dSAndrew Gallatin 			free(fl->ifl_sds.ifsd_ba, M_IFLIB);
2355e035717eSSean Bruno 			free(fl->ifl_sds.ifsd_map, M_IFLIB);
2356c065d4e5SMark Johnston 			free(fl->ifl_rx_bitmap, M_IFLIB);
2357e035717eSSean Bruno 			fl->ifl_sds.ifsd_m = NULL;
2358e035717eSSean Bruno 			fl->ifl_sds.ifsd_cl = NULL;
2359fbec776dSAndrew Gallatin 			fl->ifl_sds.ifsd_ba = NULL;
2360e035717eSSean Bruno 			fl->ifl_sds.ifsd_map = NULL;
2361c065d4e5SMark Johnston 			fl->ifl_rx_bitmap = NULL;
23624c7070dbSScott Long 		}
23634c7070dbSScott Long 		free(rxq->ifr_fl, M_IFLIB);
23644c7070dbSScott Long 		rxq->ifr_fl = NULL;
2365244e7cffSEric Joyner 		free(rxq->ifr_ifdi, M_IFLIB);
2366244e7cffSEric Joyner 		rxq->ifr_ifdi = NULL;
23671722eeacSMarius Strobl 		rxq->ifr_cq_cidx = 0;
23684c7070dbSScott Long 	}
23694c7070dbSScott Long }
23704c7070dbSScott Long 
23714c7070dbSScott Long /*
23721722eeacSMarius Strobl  * Timer routine
23734c7070dbSScott Long  */
23744c7070dbSScott Long static void
23754c7070dbSScott Long iflib_timer(void *arg)
23764c7070dbSScott Long {
2377ab2e3f79SStephen Hurd 	iflib_txq_t txq = arg;
23784c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
2379ab2e3f79SStephen Hurd 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
2380dd7fbcf1SStephen Hurd 	uint64_t this_tick = ticks;
23814c7070dbSScott Long 
23824c7070dbSScott Long 	if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))
23834c7070dbSScott Long 		return;
23841722eeacSMarius Strobl 
23854c7070dbSScott Long 	/*
23864c7070dbSScott Long 	** Check on the state of the TX queue(s), this
23874c7070dbSScott Long 	** can be done without the lock because its RO
23884c7070dbSScott Long 	** and the HUNG state will be static if set.
23894c7070dbSScott Long 	*/
239081be6552SMatt Macy 	if (this_tick - txq->ift_last_timer_tick >= iflib_timer_default) {
2391dd7fbcf1SStephen Hurd 		txq->ift_last_timer_tick = this_tick;
2392ab2e3f79SStephen Hurd 		IFDI_TIMER(ctx, txq->ift_id);
2393ab2e3f79SStephen Hurd 		if ((txq->ift_qstatus == IFLIB_QUEUE_HUNG) &&
2394ab2e3f79SStephen Hurd 		    ((txq->ift_cleaned_prev == txq->ift_cleaned) ||
2395ab2e3f79SStephen Hurd 		     (sctx->isc_pause_frames == 0)))
2396ab2e3f79SStephen Hurd 			goto hung;
2397a9693502SSean Bruno 
2398f6afed72SEric Joyner 		if (txq->ift_qstatus != IFLIB_QUEUE_IDLE &&
2399f6afed72SEric Joyner 		    ifmp_ring_is_stalled(txq->ift_br)) {
240081be6552SMatt Macy 			KASSERT(ctx->ifc_link_state == LINK_STATE_UP,
240181be6552SMatt Macy 			    ("queue can't be marked as hung if interface is down"));
2402ab2e3f79SStephen Hurd 			txq->ift_qstatus = IFLIB_QUEUE_HUNG;
2403f6afed72SEric Joyner 		}
2404ab2e3f79SStephen Hurd 		txq->ift_cleaned_prev = txq->ift_cleaned;
2405dd7fbcf1SStephen Hurd 	}
2406ab2e3f79SStephen Hurd 	/* handle any laggards */
2407ab2e3f79SStephen Hurd 	if (txq->ift_db_pending)
2408ab2e3f79SStephen Hurd 		GROUPTASK_ENQUEUE(&txq->ift_task);
2409a9693502SSean Bruno 
2410ab2e3f79SStephen Hurd 	sctx->isc_pause_frames = 0;
2411d300df01SStephen Hurd 	if (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)
241281be6552SMatt Macy 		callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer,
241381be6552SMatt Macy 		    txq, txq->ift_timer.c_cpu);
2414ab2e3f79SStephen Hurd 	return;
24151722eeacSMarius Strobl 
2416ab2e3f79SStephen Hurd  hung:
24171722eeacSMarius Strobl 	device_printf(ctx->ifc_dev,
24181722eeacSMarius Strobl 	    "Watchdog timeout (TX: %d desc avail: %d pidx: %d) -- resetting\n",
2419ab2e3f79SStephen Hurd 	    txq->ift_id, TXQ_AVAIL(txq), txq->ift_pidx);
24207b610b60SSean Bruno 	STATE_LOCK(ctx);
24217b610b60SSean Bruno 	if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
24227b610b60SSean Bruno 	ctx->ifc_flags |= (IFC_DO_WATCHDOG|IFC_DO_RESET);
2423940f62d6SEric Joyner 	iflib_admin_intr_deferred(ctx);
242446fa0c25SEric Joyner 	STATE_UNLOCK(ctx);
24254c7070dbSScott Long }
24264c7070dbSScott Long 
2427b3813609SPatrick Kelsey static uint16_t
2428b3813609SPatrick Kelsey iflib_get_mbuf_size_for(unsigned int size)
2429b3813609SPatrick Kelsey {
2430b3813609SPatrick Kelsey 
2431b3813609SPatrick Kelsey 	if (size <= MCLBYTES)
2432b3813609SPatrick Kelsey 		return (MCLBYTES);
2433b3813609SPatrick Kelsey 	else
2434b3813609SPatrick Kelsey 		return (MJUMPAGESIZE);
2435b3813609SPatrick Kelsey }
2436b3813609SPatrick Kelsey 
24374c7070dbSScott Long static void
24381b9d9394SEric Joyner iflib_calc_rx_mbuf_sz(if_ctx_t ctx)
24391b9d9394SEric Joyner {
24401b9d9394SEric Joyner 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
24411b9d9394SEric Joyner 
24421b9d9394SEric Joyner 	/*
24431b9d9394SEric Joyner 	 * XXX don't set the max_frame_size to larger
24441b9d9394SEric Joyner 	 * than the hardware can handle
24451b9d9394SEric Joyner 	 */
2446b3813609SPatrick Kelsey 	ctx->ifc_rx_mbuf_sz =
2447b3813609SPatrick Kelsey 	    iflib_get_mbuf_size_for(sctx->isc_max_frame_size);
24481b9d9394SEric Joyner }
24491b9d9394SEric Joyner 
24501b9d9394SEric Joyner uint32_t
24511b9d9394SEric Joyner iflib_get_rx_mbuf_sz(if_ctx_t ctx)
24521b9d9394SEric Joyner {
24531722eeacSMarius Strobl 
24541b9d9394SEric Joyner 	return (ctx->ifc_rx_mbuf_sz);
24551b9d9394SEric Joyner }
24561b9d9394SEric Joyner 
24571b9d9394SEric Joyner static void
24584c7070dbSScott Long iflib_init_locked(if_ctx_t ctx)
24594c7070dbSScott Long {
24604c7070dbSScott Long 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
24611248952aSSean Bruno 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
24624c7070dbSScott Long 	if_t ifp = ctx->ifc_ifp;
24634c7070dbSScott Long 	iflib_fl_t fl;
24644c7070dbSScott Long 	iflib_txq_t txq;
24654c7070dbSScott Long 	iflib_rxq_t rxq;
2466ab2e3f79SStephen Hurd 	int i, j, tx_ip_csum_flags, tx_ip6_csum_flags;
24674c7070dbSScott Long 
24684c7070dbSScott Long 	if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
24694c7070dbSScott Long 	IFDI_INTR_DISABLE(ctx);
24704c7070dbSScott Long 
24713d65fd97SVincenzo Maffione 	/*
24723d65fd97SVincenzo Maffione 	 * See iflib_stop(). Useful in case iflib_init_locked() is
24733d65fd97SVincenzo Maffione 	 * called without first calling iflib_stop().
24743d65fd97SVincenzo Maffione 	 */
24753d65fd97SVincenzo Maffione 	netmap_disable_all_rings(ifp);
24763d65fd97SVincenzo Maffione 
24771248952aSSean Bruno 	tx_ip_csum_flags = scctx->isc_tx_csum_flags & (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP);
24781248952aSSean Bruno 	tx_ip6_csum_flags = scctx->isc_tx_csum_flags & (CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_IP6_SCTP);
24794c7070dbSScott Long 	/* Set hardware offload abilities */
24804c7070dbSScott Long 	if_clearhwassist(ifp);
24814c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TXCSUM)
24821248952aSSean Bruno 		if_sethwassistbits(ifp, tx_ip_csum_flags, 0);
24834c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6)
24841248952aSSean Bruno 		if_sethwassistbits(ifp,  tx_ip6_csum_flags, 0);
24854c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TSO4)
24864c7070dbSScott Long 		if_sethwassistbits(ifp, CSUM_IP_TSO, 0);
24874c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TSO6)
24884c7070dbSScott Long 		if_sethwassistbits(ifp, CSUM_IP6_TSO, 0);
24894c7070dbSScott Long 
24904c7070dbSScott Long 	for (i = 0, txq = ctx->ifc_txqs; i < sctx->isc_ntxqsets; i++, txq++) {
24914c7070dbSScott Long 		CALLOUT_LOCK(txq);
24924c7070dbSScott Long 		callout_stop(&txq->ift_timer);
249317cec474SVincenzo Maffione #ifdef DEV_NETMAP
249417cec474SVincenzo Maffione 		callout_stop(&txq->ift_netmap_timer);
249517cec474SVincenzo Maffione #endif /* DEV_NETMAP */
24964c7070dbSScott Long 		CALLOUT_UNLOCK(txq);
24972ccf971aSJohn Baldwin 		(void)iflib_netmap_txq_init(ctx, txq);
24984c7070dbSScott Long 	}
24991b9d9394SEric Joyner 
25001b9d9394SEric Joyner 	/*
25011b9d9394SEric Joyner 	 * Calculate a suitable Rx mbuf size prior to calling IFDI_INIT, so
25021b9d9394SEric Joyner 	 * that drivers can use the value when setting up the hardware receive
25031b9d9394SEric Joyner 	 * buffers.
25041b9d9394SEric Joyner 	 */
25051b9d9394SEric Joyner 	iflib_calc_rx_mbuf_sz(ctx);
25061b9d9394SEric Joyner 
250723ac9029SStephen Hurd #ifdef INVARIANTS
250823ac9029SStephen Hurd 	i = if_getdrvflags(ifp);
250923ac9029SStephen Hurd #endif
25104c7070dbSScott Long 	IFDI_INIT(ctx);
251123ac9029SStephen Hurd 	MPASS(if_getdrvflags(ifp) == i);
25124c7070dbSScott Long 	for (i = 0, rxq = ctx->ifc_rxqs; i < sctx->isc_nrxqsets; i++, rxq++) {
2513d8b2d26bSVincenzo Maffione 		if (iflib_netmap_rxq_init(ctx, rxq) > 0) {
2514d8b2d26bSVincenzo Maffione 			/* This rxq is in netmap mode. Skip normal init. */
251595246abbSSean Bruno 			continue;
2516d0d0ad0aSStephen Hurd 		}
25174c7070dbSScott Long 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) {
25184c7070dbSScott Long 			if (iflib_fl_setup(fl)) {
25193d10e9edSMarius Strobl 				device_printf(ctx->ifc_dev,
25203d10e9edSMarius Strobl 				    "setting up free list %d failed - "
25213d10e9edSMarius Strobl 				    "check cluster settings\n", j);
25224c7070dbSScott Long 				goto done;
25234c7070dbSScott Long 			}
25244c7070dbSScott Long 		}
25254c7070dbSScott Long 	}
25264c7070dbSScott Long done:
25274c7070dbSScott Long 	if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
25284c7070dbSScott Long 	IFDI_INTR_ENABLE(ctx);
25294c7070dbSScott Long 	txq = ctx->ifc_txqs;
25304c7070dbSScott Long 	for (i = 0; i < sctx->isc_ntxqsets; i++, txq++)
253181be6552SMatt Macy 		callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer, txq,
2532ab2e3f79SStephen Hurd 			txq->ift_timer.c_cpu);
25333d65fd97SVincenzo Maffione 
25343d65fd97SVincenzo Maffione         /* Re-enable txsync/rxsync. */
25353d65fd97SVincenzo Maffione 	netmap_enable_all_rings(ifp);
25364c7070dbSScott Long }
25374c7070dbSScott Long 
25384c7070dbSScott Long static int
25394c7070dbSScott Long iflib_media_change(if_t ifp)
25404c7070dbSScott Long {
25414c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
25424c7070dbSScott Long 	int err;
25434c7070dbSScott Long 
25444c7070dbSScott Long 	CTX_LOCK(ctx);
25454c7070dbSScott Long 	if ((err = IFDI_MEDIA_CHANGE(ctx)) == 0)
2546922cf8acSAllan Jude 		iflib_if_init_locked(ctx);
25474c7070dbSScott Long 	CTX_UNLOCK(ctx);
25484c7070dbSScott Long 	return (err);
25494c7070dbSScott Long }
25504c7070dbSScott Long 
25514c7070dbSScott Long static void
25524c7070dbSScott Long iflib_media_status(if_t ifp, struct ifmediareq *ifmr)
25534c7070dbSScott Long {
25544c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
25554c7070dbSScott Long 
25564c7070dbSScott Long 	CTX_LOCK(ctx);
2557ab2e3f79SStephen Hurd 	IFDI_UPDATE_ADMIN_STATUS(ctx);
25584c7070dbSScott Long 	IFDI_MEDIA_STATUS(ctx, ifmr);
25594c7070dbSScott Long 	CTX_UNLOCK(ctx);
25604c7070dbSScott Long }
25614c7070dbSScott Long 
256209f6ff4fSMatt Macy void
25634c7070dbSScott Long iflib_stop(if_ctx_t ctx)
25644c7070dbSScott Long {
25654c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
25664c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
25674c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
25684d261ce2SStephen Hurd 	if_shared_ctx_t sctx = ctx->ifc_sctx;
25694c7070dbSScott Long 	iflib_dma_info_t di;
25704c7070dbSScott Long 	iflib_fl_t fl;
25714c7070dbSScott Long 	int i, j;
25724c7070dbSScott Long 
25734c7070dbSScott Long 	/* Tell the stack that the interface is no longer active */
25744c7070dbSScott Long 	if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
25754c7070dbSScott Long 
25764c7070dbSScott Long 	IFDI_INTR_DISABLE(ctx);
2577ab2e3f79SStephen Hurd 	DELAY(1000);
2578da69b8f9SSean Bruno 	IFDI_STOP(ctx);
2579ab2e3f79SStephen Hurd 	DELAY(1000);
25804c7070dbSScott Long 
25813d65fd97SVincenzo Maffione 	/*
25823d65fd97SVincenzo Maffione 	 * Stop any pending txsync/rxsync and prevent new ones
25833d65fd97SVincenzo Maffione 	 * form starting. Processes blocked in poll() will get
25843d65fd97SVincenzo Maffione 	 * POLLERR.
25853d65fd97SVincenzo Maffione 	 */
25863d65fd97SVincenzo Maffione 	netmap_disable_all_rings(ctx->ifc_ifp);
25873d65fd97SVincenzo Maffione 
2588da69b8f9SSean Bruno 	iflib_debug_reset();
25894c7070dbSScott Long 	/* Wait for current tx queue users to exit to disarm watchdog timer. */
25904c7070dbSScott Long 	for (i = 0; i < scctx->isc_ntxqsets; i++, txq++) {
25914c7070dbSScott Long 		/* make sure all transmitters have completed before proceeding XXX */
25924c7070dbSScott Long 
2593226fb85dSStephen Hurd 		CALLOUT_LOCK(txq);
2594226fb85dSStephen Hurd 		callout_stop(&txq->ift_timer);
259517cec474SVincenzo Maffione #ifdef DEV_NETMAP
259617cec474SVincenzo Maffione 		callout_stop(&txq->ift_netmap_timer);
259717cec474SVincenzo Maffione #endif /* DEV_NETMAP */
2598226fb85dSStephen Hurd 		CALLOUT_UNLOCK(txq);
2599226fb85dSStephen Hurd 
26004c7070dbSScott Long 		/* clean any enqueued buffers */
2601da69b8f9SSean Bruno 		iflib_ifmp_purge(txq);
26024c7070dbSScott Long 		/* Free any existing tx buffers. */
260323ac9029SStephen Hurd 		for (j = 0; j < txq->ift_size; j++) {
26044c7070dbSScott Long 			iflib_txsd_free(ctx, txq, j);
26054c7070dbSScott Long 		}
2606ab2e3f79SStephen Hurd 		txq->ift_processed = txq->ift_cleaned = txq->ift_cidx_processed = 0;
2607ab2e3f79SStephen Hurd 		txq->ift_in_use = txq->ift_gen = txq->ift_cidx = txq->ift_pidx = txq->ift_no_desc_avail = 0;
26084c7070dbSScott Long 		txq->ift_closed = txq->ift_mbuf_defrag = txq->ift_mbuf_defrag_failed = 0;
26094c7070dbSScott Long 		txq->ift_no_tx_dma_setup = txq->ift_txd_encap_efbig = txq->ift_map_failed = 0;
2610ab2e3f79SStephen Hurd 		txq->ift_pullups = 0;
261195246abbSSean Bruno 		ifmp_ring_reset_stats(txq->ift_br);
26124d261ce2SStephen Hurd 		for (j = 0, di = txq->ift_ifdi; j < sctx->isc_ntxqs; j++, di++)
26134c7070dbSScott Long 			bzero((void *)di->idi_vaddr, di->idi_size);
26144c7070dbSScott Long 	}
26154c7070dbSScott Long 	for (i = 0; i < scctx->isc_nrxqsets; i++, rxq++) {
26164c7070dbSScott Long 		/* make sure all transmitters have completed before proceeding XXX */
26174c7070dbSScott Long 
26181722eeacSMarius Strobl 		rxq->ifr_cq_cidx = 0;
26194d261ce2SStephen Hurd 		for (j = 0, di = rxq->ifr_ifdi; j < sctx->isc_nrxqs; j++, di++)
26204c7070dbSScott Long 			bzero((void *)di->idi_vaddr, di->idi_size);
26214c7070dbSScott Long 		/* also resets the free lists pidx/cidx */
26224c7070dbSScott Long 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++)
26234c7070dbSScott Long 			iflib_fl_bufs_free(fl);
26244c7070dbSScott Long 	}
26254c7070dbSScott Long }
26264c7070dbSScott Long 
262795246abbSSean Bruno static inline caddr_t
262895246abbSSean Bruno calc_next_rxd(iflib_fl_t fl, int cidx)
262995246abbSSean Bruno {
263095246abbSSean Bruno 	qidx_t size;
263195246abbSSean Bruno 	int nrxd;
263295246abbSSean Bruno 	caddr_t start, end, cur, next;
263395246abbSSean Bruno 
263495246abbSSean Bruno 	nrxd = fl->ifl_size;
263595246abbSSean Bruno 	size = fl->ifl_rxd_size;
263695246abbSSean Bruno 	start = fl->ifl_ifdi->idi_vaddr;
263795246abbSSean Bruno 
263895246abbSSean Bruno 	if (__predict_false(size == 0))
263995246abbSSean Bruno 		return (start);
264095246abbSSean Bruno 	cur = start + size*cidx;
264195246abbSSean Bruno 	end = start + size*nrxd;
264295246abbSSean Bruno 	next = CACHE_PTR_NEXT(cur);
264395246abbSSean Bruno 	return (next < end ? next : start);
264495246abbSSean Bruno }
264595246abbSSean Bruno 
2646e035717eSSean Bruno static inline void
2647e035717eSSean Bruno prefetch_pkts(iflib_fl_t fl, int cidx)
2648e035717eSSean Bruno {
2649e035717eSSean Bruno 	int nextptr;
2650e035717eSSean Bruno 	int nrxd = fl->ifl_size;
265195246abbSSean Bruno 	caddr_t next_rxd;
265295246abbSSean Bruno 
2653e035717eSSean Bruno 	nextptr = (cidx + CACHE_PTR_INCREMENT) & (nrxd-1);
2654e035717eSSean Bruno 	prefetch(&fl->ifl_sds.ifsd_m[nextptr]);
2655e035717eSSean Bruno 	prefetch(&fl->ifl_sds.ifsd_cl[nextptr]);
265695246abbSSean Bruno 	next_rxd = calc_next_rxd(fl, cidx);
265795246abbSSean Bruno 	prefetch(next_rxd);
2658e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 1) & (nrxd-1)]);
2659e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 2) & (nrxd-1)]);
2660e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 3) & (nrxd-1)]);
2661e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 4) & (nrxd-1)]);
2662e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 1) & (nrxd-1)]);
2663e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 2) & (nrxd-1)]);
2664e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 3) & (nrxd-1)]);
2665e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 4) & (nrxd-1)]);
2666e035717eSSean Bruno }
2667e035717eSSean Bruno 
26686d49b41eSAndrew Gallatin static struct mbuf *
26696d49b41eSAndrew Gallatin rxd_frag_to_sd(iflib_rxq_t rxq, if_rxd_frag_t irf, bool unload, if_rxsd_t sd,
26706d49b41eSAndrew Gallatin     int *pf_rv, if_rxd_info_t ri)
26714c7070dbSScott Long {
2672e035717eSSean Bruno 	bus_dmamap_t map;
26734c7070dbSScott Long 	iflib_fl_t fl;
26746d49b41eSAndrew Gallatin 	caddr_t payload;
26756d49b41eSAndrew Gallatin 	struct mbuf *m;
26766d49b41eSAndrew Gallatin 	int flid, cidx, len, next;
26774c7070dbSScott Long 
267895246abbSSean Bruno 	map = NULL;
26794c7070dbSScott Long 	flid = irf->irf_flid;
26804c7070dbSScott Long 	cidx = irf->irf_idx;
26814c7070dbSScott Long 	fl = &rxq->ifr_fl[flid];
268295246abbSSean Bruno 	sd->ifsd_fl = fl;
26836d49b41eSAndrew Gallatin 	m = fl->ifl_sds.ifsd_m[cidx];
268495246abbSSean Bruno 	sd->ifsd_cl = &fl->ifl_sds.ifsd_cl[cidx];
26854c7070dbSScott Long 	fl->ifl_credits--;
26864c7070dbSScott Long #if MEMORY_LOGGING
26874c7070dbSScott Long 	fl->ifl_m_dequeued++;
26884c7070dbSScott Long #endif
268995246abbSSean Bruno 	if (rxq->ifr_ctx->ifc_flags & IFC_PREFETCH)
2690e035717eSSean Bruno 		prefetch_pkts(fl, cidx);
2691e035717eSSean Bruno 	next = (cidx + CACHE_PTR_INCREMENT) & (fl->ifl_size-1);
2692e035717eSSean Bruno 	prefetch(&fl->ifl_sds.ifsd_map[next]);
2693e035717eSSean Bruno 	map = fl->ifl_sds.ifsd_map[cidx];
26944c7070dbSScott Long 
2695bfce461eSMarius Strobl 	bus_dmamap_sync(fl->ifl_buf_tag, map, BUS_DMASYNC_POSTREAD);
26966d49b41eSAndrew Gallatin 
26974f2beb72SPatrick Kelsey 	if (rxq->pfil != NULL && PFIL_HOOKED_IN(rxq->pfil) && pf_rv != NULL &&
26984f2beb72SPatrick Kelsey 	    irf->irf_len != 0) {
26996d49b41eSAndrew Gallatin 		payload  = *sd->ifsd_cl;
27006d49b41eSAndrew Gallatin 		payload +=  ri->iri_pad;
27016d49b41eSAndrew Gallatin 		len = ri->iri_len - ri->iri_pad;
27026d49b41eSAndrew Gallatin 		*pf_rv = pfil_run_hooks(rxq->pfil, payload, ri->iri_ifp,
27036d49b41eSAndrew Gallatin 		    len | PFIL_MEMPTR | PFIL_IN, NULL);
27046d49b41eSAndrew Gallatin 		switch (*pf_rv) {
27056d49b41eSAndrew Gallatin 		case PFIL_DROPPED:
27066d49b41eSAndrew Gallatin 		case PFIL_CONSUMED:
27076d49b41eSAndrew Gallatin 			/*
27086d49b41eSAndrew Gallatin 			 * The filter ate it.  Everything is recycled.
27096d49b41eSAndrew Gallatin 			 */
27106d49b41eSAndrew Gallatin 			m = NULL;
27116d49b41eSAndrew Gallatin 			unload = 0;
27126d49b41eSAndrew Gallatin 			break;
27136d49b41eSAndrew Gallatin 		case PFIL_REALLOCED:
27146d49b41eSAndrew Gallatin 			/*
27156d49b41eSAndrew Gallatin 			 * The filter copied it.  Everything is recycled.
27166d49b41eSAndrew Gallatin 			 */
27176d49b41eSAndrew Gallatin 			m = pfil_mem2mbuf(payload);
27186d49b41eSAndrew Gallatin 			unload = 0;
27196d49b41eSAndrew Gallatin 			break;
27206d49b41eSAndrew Gallatin 		case PFIL_PASS:
27216d49b41eSAndrew Gallatin 			/*
27226d49b41eSAndrew Gallatin 			 * Filter said it was OK, so receive like
27236d49b41eSAndrew Gallatin 			 * normal
27246d49b41eSAndrew Gallatin 			 */
27256d49b41eSAndrew Gallatin 			fl->ifl_sds.ifsd_m[cidx] = NULL;
27266d49b41eSAndrew Gallatin 			break;
27276d49b41eSAndrew Gallatin 		default:
27286d49b41eSAndrew Gallatin 			MPASS(0);
27296d49b41eSAndrew Gallatin 		}
27306d49b41eSAndrew Gallatin 	} else {
27316d49b41eSAndrew Gallatin 		fl->ifl_sds.ifsd_m[cidx] = NULL;
27320c864213SAndrew Gallatin 		if (pf_rv != NULL)
27336d49b41eSAndrew Gallatin 			*pf_rv = PFIL_PASS;
27346d49b41eSAndrew Gallatin 	}
27356d49b41eSAndrew Gallatin 
27364f2beb72SPatrick Kelsey 	if (unload && irf->irf_len != 0)
2737bfce461eSMarius Strobl 		bus_dmamap_unload(fl->ifl_buf_tag, map);
273895246abbSSean Bruno 	fl->ifl_cidx = (fl->ifl_cidx + 1) & (fl->ifl_size-1);
273995246abbSSean Bruno 	if (__predict_false(fl->ifl_cidx == 0))
27404c7070dbSScott Long 		fl->ifl_gen = 0;
274187890dbaSSean Bruno 	bit_clear(fl->ifl_rx_bitmap, cidx);
27426d49b41eSAndrew Gallatin 	return (m);
27434c7070dbSScott Long }
27444c7070dbSScott Long 
27454c7070dbSScott Long static struct mbuf *
27466d49b41eSAndrew Gallatin assemble_segments(iflib_rxq_t rxq, if_rxd_info_t ri, if_rxsd_t sd, int *pf_rv)
27474c7070dbSScott Long {
274895246abbSSean Bruno 	struct mbuf *m, *mh, *mt;
274995246abbSSean Bruno 	caddr_t cl;
27506d49b41eSAndrew Gallatin 	int  *pf_rv_ptr, flags, i, padlen;
27516d49b41eSAndrew Gallatin 	bool consumed;
27524c7070dbSScott Long 
27534c7070dbSScott Long 	i = 0;
275423ac9029SStephen Hurd 	mh = NULL;
27556d49b41eSAndrew Gallatin 	consumed = false;
27566d49b41eSAndrew Gallatin 	*pf_rv = PFIL_PASS;
27576d49b41eSAndrew Gallatin 	pf_rv_ptr = pf_rv;
27584c7070dbSScott Long 	do {
27596d49b41eSAndrew Gallatin 		m = rxd_frag_to_sd(rxq, &ri->iri_frags[i], !consumed, sd,
27606d49b41eSAndrew Gallatin 		    pf_rv_ptr, ri);
27614c7070dbSScott Long 
276295246abbSSean Bruno 		MPASS(*sd->ifsd_cl != NULL);
276323ac9029SStephen Hurd 
27646d49b41eSAndrew Gallatin 		/*
27656d49b41eSAndrew Gallatin 		 * Exclude zero-length frags & frags from
27666d49b41eSAndrew Gallatin 		 * packets the filter has consumed or dropped
27676d49b41eSAndrew Gallatin 		 */
27686d49b41eSAndrew Gallatin 		if (ri->iri_frags[i].irf_len == 0 || consumed ||
27696d49b41eSAndrew Gallatin 		    *pf_rv == PFIL_CONSUMED || *pf_rv == PFIL_DROPPED) {
27706d49b41eSAndrew Gallatin 			if (mh == NULL) {
27716d49b41eSAndrew Gallatin 				/* everything saved here */
27726d49b41eSAndrew Gallatin 				consumed = true;
27736d49b41eSAndrew Gallatin 				pf_rv_ptr = NULL;
277423ac9029SStephen Hurd 				continue;
277523ac9029SStephen Hurd 			}
27766d49b41eSAndrew Gallatin 			/* XXX we can save the cluster here, but not the mbuf */
27776d49b41eSAndrew Gallatin 			m_init(m, M_NOWAIT, MT_DATA, 0);
27786d49b41eSAndrew Gallatin 			m_free(m);
27796d49b41eSAndrew Gallatin 			continue;
27806d49b41eSAndrew Gallatin 		}
278123ac9029SStephen Hurd 		if (mh == NULL) {
27824c7070dbSScott Long 			flags = M_PKTHDR|M_EXT;
27834c7070dbSScott Long 			mh = mt = m;
27844c7070dbSScott Long 			padlen = ri->iri_pad;
27854c7070dbSScott Long 		} else {
27864c7070dbSScott Long 			flags = M_EXT;
27874c7070dbSScott Long 			mt->m_next = m;
27884c7070dbSScott Long 			mt = m;
27894c7070dbSScott Long 			/* assuming padding is only on the first fragment */
27904c7070dbSScott Long 			padlen = 0;
27914c7070dbSScott Long 		}
279295246abbSSean Bruno 		cl = *sd->ifsd_cl;
279395246abbSSean Bruno 		*sd->ifsd_cl = NULL;
27944c7070dbSScott Long 
27954c7070dbSScott Long 		/* Can these two be made one ? */
27964c7070dbSScott Long 		m_init(m, M_NOWAIT, MT_DATA, flags);
279795246abbSSean Bruno 		m_cljset(m, cl, sd->ifsd_fl->ifl_cltype);
27984c7070dbSScott Long 		/*
27994c7070dbSScott Long 		 * These must follow m_init and m_cljset
28004c7070dbSScott Long 		 */
28014c7070dbSScott Long 		m->m_data += padlen;
28024c7070dbSScott Long 		ri->iri_len -= padlen;
280323ac9029SStephen Hurd 		m->m_len = ri->iri_frags[i].irf_len;
28044c7070dbSScott Long 	} while (++i < ri->iri_nfrags);
28054c7070dbSScott Long 
28064c7070dbSScott Long 	return (mh);
28074c7070dbSScott Long }
28084c7070dbSScott Long 
28094c7070dbSScott Long /*
28104c7070dbSScott Long  * Process one software descriptor
28114c7070dbSScott Long  */
28124c7070dbSScott Long static struct mbuf *
28134c7070dbSScott Long iflib_rxd_pkt_get(iflib_rxq_t rxq, if_rxd_info_t ri)
28144c7070dbSScott Long {
281595246abbSSean Bruno 	struct if_rxsd sd;
28164c7070dbSScott Long 	struct mbuf *m;
28176d49b41eSAndrew Gallatin 	int pf_rv;
28184c7070dbSScott Long 
28194c7070dbSScott Long 	/* should I merge this back in now that the two paths are basically duplicated? */
282023ac9029SStephen Hurd 	if (ri->iri_nfrags == 1 &&
28214f2beb72SPatrick Kelsey 	    ri->iri_frags[0].irf_len != 0 &&
282218628b74SMark Johnston 	    ri->iri_frags[0].irf_len <= MIN(IFLIB_RX_COPY_THRESH, MHLEN)) {
28236d49b41eSAndrew Gallatin 		m = rxd_frag_to_sd(rxq, &ri->iri_frags[0], false, &sd,
28246d49b41eSAndrew Gallatin 		    &pf_rv, ri);
28256d49b41eSAndrew Gallatin 		if (pf_rv != PFIL_PASS && pf_rv != PFIL_REALLOCED)
28266d49b41eSAndrew Gallatin 			return (m);
28276d49b41eSAndrew Gallatin 		if (pf_rv == PFIL_PASS) {
28284c7070dbSScott Long 			m_init(m, M_NOWAIT, MT_DATA, M_PKTHDR);
282995246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
283095246abbSSean Bruno 			if (!IP_ALIGNED(m))
283195246abbSSean Bruno 				m->m_data += 2;
283295246abbSSean Bruno #endif
283395246abbSSean Bruno 			memcpy(m->m_data, *sd.ifsd_cl, ri->iri_len);
283423ac9029SStephen Hurd 			m->m_len = ri->iri_frags[0].irf_len;
28356d49b41eSAndrew Gallatin 		}
28364c7070dbSScott Long 	} else {
28376d49b41eSAndrew Gallatin 		m = assemble_segments(rxq, ri, &sd, &pf_rv);
28384f2beb72SPatrick Kelsey 		if (m == NULL)
28394f2beb72SPatrick Kelsey 			return (NULL);
28406d49b41eSAndrew Gallatin 		if (pf_rv != PFIL_PASS && pf_rv != PFIL_REALLOCED)
28416d49b41eSAndrew Gallatin 			return (m);
28424c7070dbSScott Long 	}
28434c7070dbSScott Long 	m->m_pkthdr.len = ri->iri_len;
28444c7070dbSScott Long 	m->m_pkthdr.rcvif = ri->iri_ifp;
28454c7070dbSScott Long 	m->m_flags |= ri->iri_flags;
28464c7070dbSScott Long 	m->m_pkthdr.ether_vtag = ri->iri_vtag;
28474c7070dbSScott Long 	m->m_pkthdr.flowid = ri->iri_flowid;
28484c7070dbSScott Long 	M_HASHTYPE_SET(m, ri->iri_rsstype);
28494c7070dbSScott Long 	m->m_pkthdr.csum_flags = ri->iri_csum_flags;
28504c7070dbSScott Long 	m->m_pkthdr.csum_data = ri->iri_csum_data;
28514c7070dbSScott Long 	return (m);
28524c7070dbSScott Long }
28534c7070dbSScott Long 
285435e4e998SStephen Hurd #if defined(INET6) || defined(INET)
2855fe1bcadaSStephen Hurd static void
2856fe1bcadaSStephen Hurd iflib_get_ip_forwarding(struct lro_ctrl *lc, bool *v4, bool *v6)
2857fe1bcadaSStephen Hurd {
2858fe1bcadaSStephen Hurd 	CURVNET_SET(lc->ifp->if_vnet);
2859fe1bcadaSStephen Hurd #if defined(INET6)
2860188adcb7SMarko Zec 	*v6 = V_ip6_forwarding;
2861fe1bcadaSStephen Hurd #endif
2862fe1bcadaSStephen Hurd #if defined(INET)
2863188adcb7SMarko Zec 	*v4 = V_ipforwarding;
2864fe1bcadaSStephen Hurd #endif
2865fe1bcadaSStephen Hurd 	CURVNET_RESTORE();
2866fe1bcadaSStephen Hurd }
2867fe1bcadaSStephen Hurd 
286835e4e998SStephen Hurd /*
286935e4e998SStephen Hurd  * Returns true if it's possible this packet could be LROed.
287035e4e998SStephen Hurd  * if it returns false, it is guaranteed that tcp_lro_rx()
287135e4e998SStephen Hurd  * would not return zero.
287235e4e998SStephen Hurd  */
287335e4e998SStephen Hurd static bool
2874fe1bcadaSStephen Hurd iflib_check_lro_possible(struct mbuf *m, bool v4_forwarding, bool v6_forwarding)
287535e4e998SStephen Hurd {
287635e4e998SStephen Hurd 	struct ether_header *eh;
287735e4e998SStephen Hurd 
287835e4e998SStephen Hurd 	eh = mtod(m, struct ether_header *);
28796aee0bfaSMarko Zec 	switch (eh->ether_type) {
2880abec4724SSean Bruno #if defined(INET6)
28816aee0bfaSMarko Zec 		case htons(ETHERTYPE_IPV6):
28826aee0bfaSMarko Zec 			return (!v6_forwarding);
2883abec4724SSean Bruno #endif
2884abec4724SSean Bruno #if defined (INET)
28856aee0bfaSMarko Zec 		case htons(ETHERTYPE_IP):
28866aee0bfaSMarko Zec 			return (!v4_forwarding);
2887abec4724SSean Bruno #endif
288835e4e998SStephen Hurd 	}
288935e4e998SStephen Hurd 
289035e4e998SStephen Hurd 	return false;
289135e4e998SStephen Hurd }
2892fe1bcadaSStephen Hurd #else
2893fe1bcadaSStephen Hurd static void
2894fe1bcadaSStephen Hurd iflib_get_ip_forwarding(struct lro_ctrl *lc __unused, bool *v4 __unused, bool *v6 __unused)
2895fe1bcadaSStephen Hurd {
2896fe1bcadaSStephen Hurd }
289735e4e998SStephen Hurd #endif
289835e4e998SStephen Hurd 
2899fb1a29b4SHans Petter Selasky static void
2900fb1a29b4SHans Petter Selasky _task_fn_rx_watchdog(void *context)
2901fb1a29b4SHans Petter Selasky {
2902fb1a29b4SHans Petter Selasky 	iflib_rxq_t rxq = context;
2903fb1a29b4SHans Petter Selasky 
2904fb1a29b4SHans Petter Selasky 	GROUPTASK_ENQUEUE(&rxq->ifr_task);
2905fb1a29b4SHans Petter Selasky }
2906fb1a29b4SHans Petter Selasky 
2907fb1a29b4SHans Petter Selasky static uint8_t
290895246abbSSean Bruno iflib_rxeof(iflib_rxq_t rxq, qidx_t budget)
29094c7070dbSScott Long {
29101722eeacSMarius Strobl 	if_t ifp;
29114c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
29124c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
291323ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
29144c7070dbSScott Long 	int avail, i;
291595246abbSSean Bruno 	qidx_t *cidxp;
29164c7070dbSScott Long 	struct if_rxd_info ri;
29174c7070dbSScott Long 	int err, budget_left, rx_bytes, rx_pkts;
29184c7070dbSScott Long 	iflib_fl_t fl;
29194c7070dbSScott Long 	int lro_enabled;
2920f6cb0deaSMatt Macy 	bool v4_forwarding, v6_forwarding, lro_possible;
2921fb1a29b4SHans Petter Selasky 	uint8_t retval = 0;
292295246abbSSean Bruno 
29234c7070dbSScott Long 	/*
29244c7070dbSScott Long 	 * XXX early demux data packets so that if_input processing only handles
29254c7070dbSScott Long 	 * acks in interrupt context
29264c7070dbSScott Long 	 */
292720f63282SStephen Hurd 	struct mbuf *m, *mh, *mt, *mf;
29284c7070dbSScott Long 
29290b8df657SGleb Smirnoff 	NET_EPOCH_ASSERT();
29300b8df657SGleb Smirnoff 
2931f6cb0deaSMatt Macy 	lro_possible = v4_forwarding = v6_forwarding = false;
293295246abbSSean Bruno 	ifp = ctx->ifc_ifp;
29334c7070dbSScott Long 	mh = mt = NULL;
29344c7070dbSScott Long 	MPASS(budget > 0);
29354c7070dbSScott Long 	rx_pkts	= rx_bytes = 0;
293623ac9029SStephen Hurd 	if (sctx->isc_flags & IFLIB_HAS_RXCQ)
29374c7070dbSScott Long 		cidxp = &rxq->ifr_cq_cidx;
29384c7070dbSScott Long 	else
29394c7070dbSScott Long 		cidxp = &rxq->ifr_fl[0].ifl_cidx;
294023ac9029SStephen Hurd 	if ((avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget)) == 0) {
29414c7070dbSScott Long 		for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++)
2942b256d25cSMark Johnston 			retval |= iflib_fl_refill_all(ctx, fl);
29434c7070dbSScott Long 		DBG_COUNTER_INC(rx_unavail);
2944fb1a29b4SHans Petter Selasky 		return (retval);
29454c7070dbSScott Long 	}
29464c7070dbSScott Long 
29476d49b41eSAndrew Gallatin 	/* pfil needs the vnet to be set */
29486d49b41eSAndrew Gallatin 	CURVNET_SET_QUIET(ifp->if_vnet);
29498b8d9093SMarius Strobl 	for (budget_left = budget; budget_left > 0 && avail > 0;) {
29504c7070dbSScott Long 		if (__predict_false(!CTX_ACTIVE(ctx))) {
29514c7070dbSScott Long 			DBG_COUNTER_INC(rx_ctx_inactive);
29524c7070dbSScott Long 			break;
29534c7070dbSScott Long 		}
29544c7070dbSScott Long 		/*
29554c7070dbSScott Long 		 * Reset client set fields to their default values
29564c7070dbSScott Long 		 */
295795246abbSSean Bruno 		rxd_info_zero(&ri);
29584c7070dbSScott Long 		ri.iri_qsidx = rxq->ifr_id;
29594c7070dbSScott Long 		ri.iri_cidx = *cidxp;
296095246abbSSean Bruno 		ri.iri_ifp = ifp;
29614c7070dbSScott Long 		ri.iri_frags = rxq->ifr_frags;
29624c7070dbSScott Long 		err = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri);
29634c7070dbSScott Long 
296495246abbSSean Bruno 		if (err)
296595246abbSSean Bruno 			goto err;
29666d49b41eSAndrew Gallatin 		rx_pkts += 1;
29676d49b41eSAndrew Gallatin 		rx_bytes += ri.iri_len;
296823ac9029SStephen Hurd 		if (sctx->isc_flags & IFLIB_HAS_RXCQ) {
296923ac9029SStephen Hurd 			*cidxp = ri.iri_cidx;
297023ac9029SStephen Hurd 			/* Update our consumer index */
297195246abbSSean Bruno 			/* XXX NB: shurd - check if this is still safe */
29721722eeacSMarius Strobl 			while (rxq->ifr_cq_cidx >= scctx->isc_nrxd[0])
297323ac9029SStephen Hurd 				rxq->ifr_cq_cidx -= scctx->isc_nrxd[0];
29744c7070dbSScott Long 			/* was this only a completion queue message? */
29754c7070dbSScott Long 			if (__predict_false(ri.iri_nfrags == 0))
29764c7070dbSScott Long 				continue;
29774c7070dbSScott Long 		}
29784c7070dbSScott Long 		MPASS(ri.iri_nfrags != 0);
29794c7070dbSScott Long 		MPASS(ri.iri_len != 0);
29804c7070dbSScott Long 
29814c7070dbSScott Long 		/* will advance the cidx on the corresponding free lists */
29824c7070dbSScott Long 		m = iflib_rxd_pkt_get(rxq, &ri);
29838b8d9093SMarius Strobl 		avail--;
29848b8d9093SMarius Strobl 		budget_left--;
29854c7070dbSScott Long 		if (avail == 0 && budget_left)
298623ac9029SStephen Hurd 			avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget_left);
29874c7070dbSScott Long 
29886d49b41eSAndrew Gallatin 		if (__predict_false(m == NULL))
29894c7070dbSScott Long 			continue;
29906d49b41eSAndrew Gallatin 
29914c7070dbSScott Long 		/* imm_pkt: -- cxgb */
29924c7070dbSScott Long 		if (mh == NULL)
29934c7070dbSScott Long 			mh = mt = m;
29944c7070dbSScott Long 		else {
29954c7070dbSScott Long 			mt->m_nextpkt = m;
29964c7070dbSScott Long 			mt = m;
29974c7070dbSScott Long 		}
29984c7070dbSScott Long 	}
29996d49b41eSAndrew Gallatin 	CURVNET_RESTORE();
30004c7070dbSScott Long 	/* make sure that we can refill faster than drain */
30014c7070dbSScott Long 	for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++)
3002b256d25cSMark Johnston 		retval |= iflib_fl_refill_all(ctx, fl);
30034c7070dbSScott Long 
30044c7070dbSScott Long 	lro_enabled = (if_getcapenable(ifp) & IFCAP_LRO);
3005fe1bcadaSStephen Hurd 	if (lro_enabled)
3006fe1bcadaSStephen Hurd 		iflib_get_ip_forwarding(&rxq->ifr_lc, &v4_forwarding, &v6_forwarding);
300720f63282SStephen Hurd 	mt = mf = NULL;
30084c7070dbSScott Long 	while (mh != NULL) {
30094c7070dbSScott Long 		m = mh;
30104c7070dbSScott Long 		mh = mh->m_nextpkt;
30114c7070dbSScott Long 		m->m_nextpkt = NULL;
301295246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
301395246abbSSean Bruno 		if (!IP_ALIGNED(m) && (m = iflib_fixup_rx(m)) == NULL)
301495246abbSSean Bruno 			continue;
301595246abbSSean Bruno #endif
3016aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
301735e4e998SStephen Hurd 		if (lro_enabled) {
301835e4e998SStephen Hurd 			if (!lro_possible) {
3019fe1bcadaSStephen Hurd 				lro_possible = iflib_check_lro_possible(m, v4_forwarding, v6_forwarding);
302035e4e998SStephen Hurd 				if (lro_possible && mf != NULL) {
302135e4e998SStephen Hurd 					ifp->if_input(ifp, mf);
302235e4e998SStephen Hurd 					DBG_COUNTER_INC(rx_if_input);
302335e4e998SStephen Hurd 					mt = mf = NULL;
302435e4e998SStephen Hurd 				}
302535e4e998SStephen Hurd 			}
302625ac1dd5SStephen Hurd 			if ((m->m_pkthdr.csum_flags & (CSUM_L4_CALC|CSUM_L4_VALID)) ==
302725ac1dd5SStephen Hurd 			    (CSUM_L4_CALC|CSUM_L4_VALID)) {
302835e4e998SStephen Hurd 				if (lro_possible && tcp_lro_rx(&rxq->ifr_lc, m, 0) == 0)
30294c7070dbSScott Long 					continue;
303020f63282SStephen Hurd 			}
303125ac1dd5SStephen Hurd 		}
3032aaeb188aSBjoern A. Zeeb #endif
303335e4e998SStephen Hurd 		if (lro_possible) {
303435e4e998SStephen Hurd 			ifp->if_input(ifp, m);
303535e4e998SStephen Hurd 			DBG_COUNTER_INC(rx_if_input);
303635e4e998SStephen Hurd 			continue;
303735e4e998SStephen Hurd 		}
303835e4e998SStephen Hurd 
303935e4e998SStephen Hurd 		if (mf == NULL)
304035e4e998SStephen Hurd 			mf = m;
304120f63282SStephen Hurd 		if (mt != NULL)
304220f63282SStephen Hurd 			mt->m_nextpkt = m;
304320f63282SStephen Hurd 		mt = m;
304420f63282SStephen Hurd 	}
304520f63282SStephen Hurd 	if (mf != NULL) {
304620f63282SStephen Hurd 		ifp->if_input(ifp, mf);
30474c7070dbSScott Long 		DBG_COUNTER_INC(rx_if_input);
30484c7070dbSScott Long 	}
304923ac9029SStephen Hurd 
30504c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_IBYTES, rx_bytes);
30514c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_pkts);
30524c7070dbSScott Long 
30534c7070dbSScott Long 	/*
30544c7070dbSScott Long 	 * Flush any outstanding LRO work
30554c7070dbSScott Long 	 */
3056aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
305723ac9029SStephen Hurd 	tcp_lro_flush_all(&rxq->ifr_lc);
3058aaeb188aSBjoern A. Zeeb #endif
3059fb1a29b4SHans Petter Selasky 	if (avail != 0 || iflib_rxd_avail(ctx, rxq, *cidxp, 1) != 0)
3060fb1a29b4SHans Petter Selasky 		retval |= IFLIB_RXEOF_MORE;
3061fb1a29b4SHans Petter Selasky 	return (retval);
306295246abbSSean Bruno err:
30637b610b60SSean Bruno 	STATE_LOCK(ctx);
3064ab2e3f79SStephen Hurd 	ctx->ifc_flags |= IFC_DO_RESET;
3065940f62d6SEric Joyner 	iflib_admin_intr_deferred(ctx);
306646fa0c25SEric Joyner 	STATE_UNLOCK(ctx);
3067fb1a29b4SHans Petter Selasky 	return (0);
306895246abbSSean Bruno }
306995246abbSSean Bruno 
307095246abbSSean Bruno #define TXD_NOTIFY_COUNT(txq) (((txq)->ift_size / (txq)->ift_update_freq)-1)
307195246abbSSean Bruno static inline qidx_t
307295246abbSSean Bruno txq_max_db_deferred(iflib_txq_t txq, qidx_t in_use)
307395246abbSSean Bruno {
307495246abbSSean Bruno 	qidx_t notify_count = TXD_NOTIFY_COUNT(txq);
307595246abbSSean Bruno 	qidx_t minthresh = txq->ift_size / 8;
307695246abbSSean Bruno 	if (in_use > 4*minthresh)
307795246abbSSean Bruno 		return (notify_count);
307895246abbSSean Bruno 	if (in_use > 2*minthresh)
307995246abbSSean Bruno 		return (notify_count >> 1);
308095246abbSSean Bruno 	if (in_use > minthresh)
308195246abbSSean Bruno 		return (notify_count >> 3);
308295246abbSSean Bruno 	return (0);
308395246abbSSean Bruno }
308495246abbSSean Bruno 
308595246abbSSean Bruno static inline qidx_t
308695246abbSSean Bruno txq_max_rs_deferred(iflib_txq_t txq)
308795246abbSSean Bruno {
308895246abbSSean Bruno 	qidx_t notify_count = TXD_NOTIFY_COUNT(txq);
308995246abbSSean Bruno 	qidx_t minthresh = txq->ift_size / 8;
309095246abbSSean Bruno 	if (txq->ift_in_use > 4*minthresh)
309195246abbSSean Bruno 		return (notify_count);
309295246abbSSean Bruno 	if (txq->ift_in_use > 2*minthresh)
309395246abbSSean Bruno 		return (notify_count >> 1);
309495246abbSSean Bruno 	if (txq->ift_in_use > minthresh)
309595246abbSSean Bruno 		return (notify_count >> 2);
30962b2fc973SSean Bruno 	return (2);
30974c7070dbSScott Long }
30984c7070dbSScott Long 
30994c7070dbSScott Long #define M_CSUM_FLAGS(m) ((m)->m_pkthdr.csum_flags)
31004c7070dbSScott Long #define M_HAS_VLANTAG(m) (m->m_flags & M_VLANTAG)
310195246abbSSean Bruno 
310295246abbSSean Bruno #define TXQ_MAX_DB_DEFERRED(txq, in_use) txq_max_db_deferred((txq), (in_use))
310395246abbSSean Bruno #define TXQ_MAX_RS_DEFERRED(txq) txq_max_rs_deferred(txq)
310423ac9029SStephen Hurd #define TXQ_MAX_DB_CONSUMED(size) (size >> 4)
31054c7070dbSScott Long 
310695246abbSSean Bruno /* forward compatibility for cxgb */
310795246abbSSean Bruno #define FIRST_QSET(ctx) 0
310895246abbSSean Bruno #define NTXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_ntxqsets)
310995246abbSSean Bruno #define NRXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_nrxqsets)
311095246abbSSean Bruno #define QIDX(ctx, m) ((((m)->m_pkthdr.flowid & ctx->ifc_softc_ctx.isc_rss_table_mask) % NTXQSETS(ctx)) + FIRST_QSET(ctx))
311195246abbSSean Bruno #define DESC_RECLAIMABLE(q) ((int)((q)->ift_processed - (q)->ift_cleaned - (q)->ift_ctx->ifc_softc_ctx.isc_tx_nsegments))
311295246abbSSean Bruno 
311395246abbSSean Bruno /* XXX we should be setting this to something other than zero */
311495246abbSSean Bruno #define RECLAIM_THRESH(ctx) ((ctx)->ifc_sctx->isc_tx_reclaim_thresh)
311581be6552SMatt Macy #define	MAX_TX_DESC(ctx) MAX((ctx)->ifc_softc_ctx.isc_tx_tso_segments_max, \
31167474544bSMarius Strobl     (ctx)->ifc_softc_ctx.isc_tx_nsegments)
311795246abbSSean Bruno 
311895246abbSSean Bruno static inline bool
311981be6552SMatt Macy iflib_txd_db_check(iflib_txq_t txq, int ring)
31204c7070dbSScott Long {
312181be6552SMatt Macy 	if_ctx_t ctx = txq->ift_ctx;
312295246abbSSean Bruno 	qidx_t dbval, max;
31234c7070dbSScott Long 
312481be6552SMatt Macy 	max = TXQ_MAX_DB_DEFERRED(txq, txq->ift_in_use);
312581be6552SMatt Macy 
312681be6552SMatt Macy 	/* force || threshold exceeded || at the edge of the ring */
312781be6552SMatt Macy 	if (ring || (txq->ift_db_pending >= max) || (TXQ_AVAIL(txq) <= MAX_TX_DESC(ctx) + 2)) {
312881be6552SMatt Macy 
312981be6552SMatt Macy 		/*
313081be6552SMatt Macy 		 * 'npending' is used if the card's doorbell is in terms of the number of descriptors
313181be6552SMatt Macy 		 * pending flush (BRCM). 'pidx' is used in cases where the card's doorbeel uses the
313281be6552SMatt Macy 		 * producer index explicitly (INTC).
313381be6552SMatt Macy 		 */
31344c7070dbSScott Long 		dbval = txq->ift_npending ? txq->ift_npending : txq->ift_pidx;
313595dcf343SMarius Strobl 		bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
313695dcf343SMarius Strobl 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
31374c7070dbSScott Long 		ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, dbval);
313881be6552SMatt Macy 
313981be6552SMatt Macy 		/*
314081be6552SMatt Macy 		 * Absent bugs there are zero packets pending so reset pending counts to zero.
314181be6552SMatt Macy 		 */
31424c7070dbSScott Long 		txq->ift_db_pending = txq->ift_npending = 0;
314381be6552SMatt Macy 		return (true);
31444c7070dbSScott Long 	}
314581be6552SMatt Macy 	return (false);
31464c7070dbSScott Long }
31474c7070dbSScott Long 
31484c7070dbSScott Long #ifdef PKT_DEBUG
31494c7070dbSScott Long static void
31504c7070dbSScott Long print_pkt(if_pkt_info_t pi)
31514c7070dbSScott Long {
31524c7070dbSScott Long 	printf("pi len:  %d qsidx: %d nsegs: %d ndescs: %d flags: %x pidx: %d\n",
31534c7070dbSScott Long 	       pi->ipi_len, pi->ipi_qsidx, pi->ipi_nsegs, pi->ipi_ndescs, pi->ipi_flags, pi->ipi_pidx);
31544c7070dbSScott Long 	printf("pi new_pidx: %d csum_flags: %lx tso_segsz: %d mflags: %x vtag: %d\n",
31554c7070dbSScott Long 	       pi->ipi_new_pidx, pi->ipi_csum_flags, pi->ipi_tso_segsz, pi->ipi_mflags, pi->ipi_vtag);
31564c7070dbSScott Long 	printf("pi etype: %d ehdrlen: %d ip_hlen: %d ipproto: %d\n",
31574c7070dbSScott Long 	       pi->ipi_etype, pi->ipi_ehdrlen, pi->ipi_ip_hlen, pi->ipi_ipproto);
31584c7070dbSScott Long }
31594c7070dbSScott Long #endif
31604c7070dbSScott Long 
31614c7070dbSScott Long #define IS_TSO4(pi) ((pi)->ipi_csum_flags & CSUM_IP_TSO)
3162a06424ddSEric Joyner #define IS_TX_OFFLOAD4(pi) ((pi)->ipi_csum_flags & (CSUM_IP_TCP | CSUM_IP_TSO))
31634c7070dbSScott Long #define IS_TSO6(pi) ((pi)->ipi_csum_flags & CSUM_IP6_TSO)
3164a06424ddSEric Joyner #define IS_TX_OFFLOAD6(pi) ((pi)->ipi_csum_flags & (CSUM_IP6_TCP | CSUM_IP6_TSO))
31654c7070dbSScott Long 
31664c7070dbSScott Long static int
31674c7070dbSScott Long iflib_parse_header(iflib_txq_t txq, if_pkt_info_t pi, struct mbuf **mp)
31684c7070dbSScott Long {
3169ab2e3f79SStephen Hurd 	if_shared_ctx_t sctx = txq->ift_ctx->ifc_sctx;
31704c7070dbSScott Long 	struct ether_vlan_header *eh;
3171c9a49a4fSMarius Strobl 	struct mbuf *m;
31724c7070dbSScott Long 
31738b8d9093SMarius Strobl 	m = *mp;
3174ab2e3f79SStephen Hurd 	if ((sctx->isc_flags & IFLIB_NEED_SCRATCH) &&
3175ab2e3f79SStephen Hurd 	    M_WRITABLE(m) == 0) {
3176ab2e3f79SStephen Hurd 		if ((m = m_dup(m, M_NOWAIT)) == NULL) {
3177ab2e3f79SStephen Hurd 			return (ENOMEM);
3178ab2e3f79SStephen Hurd 		} else {
3179ab2e3f79SStephen Hurd 			m_freem(*mp);
318064e6fc13SStephen Hurd 			DBG_COUNTER_INC(tx_frees);
31818b8d9093SMarius Strobl 			*mp = m;
3182ab2e3f79SStephen Hurd 		}
3183ab2e3f79SStephen Hurd 	}
31841248952aSSean Bruno 
31854c7070dbSScott Long 	/*
31864c7070dbSScott Long 	 * Determine where frame payload starts.
31874c7070dbSScott Long 	 * Jump over vlan headers if already present,
31884c7070dbSScott Long 	 * helpful for QinQ too.
31894c7070dbSScott Long 	 */
31904c7070dbSScott Long 	if (__predict_false(m->m_len < sizeof(*eh))) {
31914c7070dbSScott Long 		txq->ift_pullups++;
31924c7070dbSScott Long 		if (__predict_false((m = m_pullup(m, sizeof(*eh))) == NULL))
31934c7070dbSScott Long 			return (ENOMEM);
31944c7070dbSScott Long 	}
31954c7070dbSScott Long 	eh = mtod(m, struct ether_vlan_header *);
31964c7070dbSScott Long 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
31974c7070dbSScott Long 		pi->ipi_etype = ntohs(eh->evl_proto);
31984c7070dbSScott Long 		pi->ipi_ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
31994c7070dbSScott Long 	} else {
32004c7070dbSScott Long 		pi->ipi_etype = ntohs(eh->evl_encap_proto);
32014c7070dbSScott Long 		pi->ipi_ehdrlen = ETHER_HDR_LEN;
32024c7070dbSScott Long 	}
32034c7070dbSScott Long 
32044c7070dbSScott Long 	switch (pi->ipi_etype) {
32054c7070dbSScott Long #ifdef INET
32064c7070dbSScott Long 	case ETHERTYPE_IP:
32074c7070dbSScott Long 	{
3208c9a49a4fSMarius Strobl 		struct mbuf *n;
32094c7070dbSScott Long 		struct ip *ip = NULL;
32104c7070dbSScott Long 		struct tcphdr *th = NULL;
32114c7070dbSScott Long 		int minthlen;
32124c7070dbSScott Long 
32134c7070dbSScott Long 		minthlen = min(m->m_pkthdr.len, pi->ipi_ehdrlen + sizeof(*ip) + sizeof(*th));
32144c7070dbSScott Long 		if (__predict_false(m->m_len < minthlen)) {
32154c7070dbSScott Long 			/*
32164c7070dbSScott Long 			 * if this code bloat is causing too much of a hit
32174c7070dbSScott Long 			 * move it to a separate function and mark it noinline
32184c7070dbSScott Long 			 */
32194c7070dbSScott Long 			if (m->m_len == pi->ipi_ehdrlen) {
32204c7070dbSScott Long 				n = m->m_next;
32214c7070dbSScott Long 				MPASS(n);
32224c7070dbSScott Long 				if (n->m_len >= sizeof(*ip))  {
32234c7070dbSScott Long 					ip = (struct ip *)n->m_data;
32244c7070dbSScott Long 					if (n->m_len >= (ip->ip_hl << 2) + sizeof(*th))
32254c7070dbSScott Long 						th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
32264c7070dbSScott Long 				} else {
32274c7070dbSScott Long 					txq->ift_pullups++;
32284c7070dbSScott Long 					if (__predict_false((m = m_pullup(m, minthlen)) == NULL))
32294c7070dbSScott Long 						return (ENOMEM);
32304c7070dbSScott Long 					ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
32314c7070dbSScott Long 				}
32324c7070dbSScott Long 			} else {
32334c7070dbSScott Long 				txq->ift_pullups++;
32344c7070dbSScott Long 				if (__predict_false((m = m_pullup(m, minthlen)) == NULL))
32354c7070dbSScott Long 					return (ENOMEM);
32364c7070dbSScott Long 				ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
32374c7070dbSScott Long 				if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th))
32384c7070dbSScott Long 					th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
32394c7070dbSScott Long 			}
32404c7070dbSScott Long 		} else {
32414c7070dbSScott Long 			ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
32424c7070dbSScott Long 			if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th))
32434c7070dbSScott Long 				th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
32444c7070dbSScott Long 		}
32454c7070dbSScott Long 		pi->ipi_ip_hlen = ip->ip_hl << 2;
32464c7070dbSScott Long 		pi->ipi_ipproto = ip->ip_p;
32474c7070dbSScott Long 		pi->ipi_flags |= IPI_TX_IPV4;
32484c7070dbSScott Long 
3249a06424ddSEric Joyner 		/* TCP checksum offload may require TCP header length */
3250a06424ddSEric Joyner 		if (IS_TX_OFFLOAD4(pi)) {
3251a06424ddSEric Joyner 			if (__predict_true(pi->ipi_ipproto == IPPROTO_TCP)) {
32524c7070dbSScott Long 				if (__predict_false(th == NULL)) {
32534c7070dbSScott Long 					txq->ift_pullups++;
32544c7070dbSScott Long 					if (__predict_false((m = m_pullup(m, (ip->ip_hl << 2) + sizeof(*th))) == NULL))
32554c7070dbSScott Long 						return (ENOMEM);
32564c7070dbSScott Long 					th = (struct tcphdr *)((caddr_t)ip + pi->ipi_ip_hlen);
32574c7070dbSScott Long 				}
32584c7070dbSScott Long 				pi->ipi_tcp_hflags = th->th_flags;
32594c7070dbSScott Long 				pi->ipi_tcp_hlen = th->th_off << 2;
32604c7070dbSScott Long 				pi->ipi_tcp_seq = th->th_seq;
32614c7070dbSScott Long 			}
3262a06424ddSEric Joyner 			if (IS_TSO4(pi)) {
32634c7070dbSScott Long 				if (__predict_false(ip->ip_p != IPPROTO_TCP))
32644c7070dbSScott Long 					return (ENXIO);
32658d4ceb9cSStephen Hurd 				/*
32668d4ceb9cSStephen Hurd 				 * TSO always requires hardware checksum offload.
32678d4ceb9cSStephen Hurd 				 */
32688d4ceb9cSStephen Hurd 				pi->ipi_csum_flags |= (CSUM_IP_TCP | CSUM_IP);
32694c7070dbSScott Long 				th->th_sum = in_pseudo(ip->ip_src.s_addr,
32704c7070dbSScott Long 						       ip->ip_dst.s_addr, htons(IPPROTO_TCP));
32714c7070dbSScott Long 				pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz;
32721248952aSSean Bruno 				if (sctx->isc_flags & IFLIB_TSO_INIT_IP) {
32731248952aSSean Bruno 					ip->ip_sum = 0;
32741248952aSSean Bruno 					ip->ip_len = htons(pi->ipi_ip_hlen + pi->ipi_tcp_hlen + pi->ipi_tso_segsz);
32751248952aSSean Bruno 				}
32764c7070dbSScott Long 			}
3277a06424ddSEric Joyner 		}
32788d4ceb9cSStephen Hurd 		if ((sctx->isc_flags & IFLIB_NEED_ZERO_CSUM) && (pi->ipi_csum_flags & CSUM_IP))
32798d4ceb9cSStephen Hurd                        ip->ip_sum = 0;
32808d4ceb9cSStephen Hurd 
32814c7070dbSScott Long 		break;
32824c7070dbSScott Long 	}
32834c7070dbSScott Long #endif
32844c7070dbSScott Long #ifdef INET6
32854c7070dbSScott Long 	case ETHERTYPE_IPV6:
32864c7070dbSScott Long 	{
32874c7070dbSScott Long 		struct ip6_hdr *ip6 = (struct ip6_hdr *)(m->m_data + pi->ipi_ehdrlen);
32884c7070dbSScott Long 		struct tcphdr *th;
32894c7070dbSScott Long 		pi->ipi_ip_hlen = sizeof(struct ip6_hdr);
32904c7070dbSScott Long 
32914c7070dbSScott Long 		if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) {
329264e6fc13SStephen Hurd 			txq->ift_pullups++;
32934c7070dbSScott Long 			if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) == NULL))
32944c7070dbSScott Long 				return (ENOMEM);
32954c7070dbSScott Long 		}
32964c7070dbSScott Long 		th = (struct tcphdr *)((caddr_t)ip6 + pi->ipi_ip_hlen);
32974c7070dbSScott Long 
32984c7070dbSScott Long 		/* XXX-BZ this will go badly in case of ext hdrs. */
32994c7070dbSScott Long 		pi->ipi_ipproto = ip6->ip6_nxt;
33004c7070dbSScott Long 		pi->ipi_flags |= IPI_TX_IPV6;
33014c7070dbSScott Long 
3302a06424ddSEric Joyner 		/* TCP checksum offload may require TCP header length */
3303a06424ddSEric Joyner 		if (IS_TX_OFFLOAD6(pi)) {
33044c7070dbSScott Long 			if (pi->ipi_ipproto == IPPROTO_TCP) {
33054c7070dbSScott Long 				if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) {
3306a06424ddSEric Joyner 					txq->ift_pullups++;
33074c7070dbSScott Long 					if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) == NULL))
33084c7070dbSScott Long 						return (ENOMEM);
33094c7070dbSScott Long 				}
33104c7070dbSScott Long 				pi->ipi_tcp_hflags = th->th_flags;
33114c7070dbSScott Long 				pi->ipi_tcp_hlen = th->th_off << 2;
3312a06424ddSEric Joyner 				pi->ipi_tcp_seq = th->th_seq;
33134c7070dbSScott Long 			}
3314a06424ddSEric Joyner 			if (IS_TSO6(pi)) {
33154c7070dbSScott Long 				if (__predict_false(ip6->ip6_nxt != IPPROTO_TCP))
33164c7070dbSScott Long 					return (ENXIO);
33174c7070dbSScott Long 				/*
33188d4ceb9cSStephen Hurd 				 * TSO always requires hardware checksum offload.
33194c7070dbSScott Long 				 */
3320a06424ddSEric Joyner 				pi->ipi_csum_flags |= CSUM_IP6_TCP;
33214c7070dbSScott Long 				th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
33224c7070dbSScott Long 				pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz;
33234c7070dbSScott Long 			}
3324a06424ddSEric Joyner 		}
33254c7070dbSScott Long 		break;
33264c7070dbSScott Long 	}
33274c7070dbSScott Long #endif
33284c7070dbSScott Long 	default:
33294c7070dbSScott Long 		pi->ipi_csum_flags &= ~CSUM_OFFLOAD;
33304c7070dbSScott Long 		pi->ipi_ip_hlen = 0;
33314c7070dbSScott Long 		break;
33324c7070dbSScott Long 	}
33334c7070dbSScott Long 	*mp = m;
33341248952aSSean Bruno 
33354c7070dbSScott Long 	return (0);
33364c7070dbSScott Long }
33374c7070dbSScott Long 
33384c7070dbSScott Long /*
33394c7070dbSScott Long  * If dodgy hardware rejects the scatter gather chain we've handed it
334023ac9029SStephen Hurd  * we'll need to remove the mbuf chain from ifsg_m[] before we can add the
334123ac9029SStephen Hurd  * m_defrag'd mbufs
33424c7070dbSScott Long  */
33434c7070dbSScott Long static __noinline struct mbuf *
334423ac9029SStephen Hurd iflib_remove_mbuf(iflib_txq_t txq)
33454c7070dbSScott Long {
3346fbec776dSAndrew Gallatin 	int ntxd, pidx;
3347fbec776dSAndrew Gallatin 	struct mbuf *m, **ifsd_m;
33484c7070dbSScott Long 
33494c7070dbSScott Long 	ifsd_m = txq->ift_sds.ifsd_m;
335023ac9029SStephen Hurd 	ntxd = txq->ift_size;
3351fbec776dSAndrew Gallatin 	pidx = txq->ift_pidx & (ntxd - 1);
3352fbec776dSAndrew Gallatin 	ifsd_m = txq->ift_sds.ifsd_m;
3353fbec776dSAndrew Gallatin 	m = ifsd_m[pidx];
33544c7070dbSScott Long 	ifsd_m[pidx] = NULL;
3355bfce461eSMarius Strobl 	bus_dmamap_unload(txq->ift_buf_tag, txq->ift_sds.ifsd_map[pidx]);
33568a04b53dSKonstantin Belousov 	if (txq->ift_sds.ifsd_tso_map != NULL)
3357bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_tso_buf_tag,
33588a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_tso_map[pidx]);
33594c7070dbSScott Long #if MEMORY_LOGGING
33604c7070dbSScott Long 	txq->ift_dequeued++;
33614c7070dbSScott Long #endif
3362fbec776dSAndrew Gallatin 	return (m);
33634c7070dbSScott Long }
33644c7070dbSScott Long 
336595246abbSSean Bruno static inline caddr_t
336695246abbSSean Bruno calc_next_txd(iflib_txq_t txq, int cidx, uint8_t qid)
336795246abbSSean Bruno {
336895246abbSSean Bruno 	qidx_t size;
336995246abbSSean Bruno 	int ntxd;
337095246abbSSean Bruno 	caddr_t start, end, cur, next;
337195246abbSSean Bruno 
337295246abbSSean Bruno 	ntxd = txq->ift_size;
337395246abbSSean Bruno 	size = txq->ift_txd_size[qid];
337495246abbSSean Bruno 	start = txq->ift_ifdi[qid].idi_vaddr;
337595246abbSSean Bruno 
337695246abbSSean Bruno 	if (__predict_false(size == 0))
337795246abbSSean Bruno 		return (start);
337895246abbSSean Bruno 	cur = start + size*cidx;
337995246abbSSean Bruno 	end = start + size*ntxd;
338095246abbSSean Bruno 	next = CACHE_PTR_NEXT(cur);
338195246abbSSean Bruno 	return (next < end ? next : start);
338295246abbSSean Bruno }
338395246abbSSean Bruno 
3384d14c853bSStephen Hurd /*
3385d14c853bSStephen Hurd  * Pad an mbuf to ensure a minimum ethernet frame size.
3386d14c853bSStephen Hurd  * min_frame_size is the frame size (less CRC) to pad the mbuf to
3387d14c853bSStephen Hurd  */
3388d14c853bSStephen Hurd static __noinline int
3389a15fbbb8SStephen Hurd iflib_ether_pad(device_t dev, struct mbuf **m_head, uint16_t min_frame_size)
3390d14c853bSStephen Hurd {
3391d14c853bSStephen Hurd 	/*
3392d14c853bSStephen Hurd 	 * 18 is enough bytes to pad an ARP packet to 46 bytes, and
3393d14c853bSStephen Hurd 	 * and ARP message is the smallest common payload I can think of
3394d14c853bSStephen Hurd 	 */
3395d14c853bSStephen Hurd 	static char pad[18];	/* just zeros */
3396d14c853bSStephen Hurd 	int n;
3397a15fbbb8SStephen Hurd 	struct mbuf *new_head;
3398d14c853bSStephen Hurd 
3399a15fbbb8SStephen Hurd 	if (!M_WRITABLE(*m_head)) {
3400a15fbbb8SStephen Hurd 		new_head = m_dup(*m_head, M_NOWAIT);
3401a15fbbb8SStephen Hurd 		if (new_head == NULL) {
340204993890SStephen Hurd 			m_freem(*m_head);
3403a15fbbb8SStephen Hurd 			device_printf(dev, "cannot pad short frame, m_dup() failed");
340406c47d48SStephen Hurd 			DBG_COUNTER_INC(encap_pad_mbuf_fail);
340564e6fc13SStephen Hurd 			DBG_COUNTER_INC(tx_frees);
3406a15fbbb8SStephen Hurd 			return ENOMEM;
3407a15fbbb8SStephen Hurd 		}
3408a15fbbb8SStephen Hurd 		m_freem(*m_head);
3409a15fbbb8SStephen Hurd 		*m_head = new_head;
3410a15fbbb8SStephen Hurd 	}
3411a15fbbb8SStephen Hurd 
3412a15fbbb8SStephen Hurd 	for (n = min_frame_size - (*m_head)->m_pkthdr.len;
3413d14c853bSStephen Hurd 	     n > 0; n -= sizeof(pad))
3414a15fbbb8SStephen Hurd 		if (!m_append(*m_head, min(n, sizeof(pad)), pad))
3415d14c853bSStephen Hurd 			break;
3416d14c853bSStephen Hurd 
3417d14c853bSStephen Hurd 	if (n > 0) {
3418a15fbbb8SStephen Hurd 		m_freem(*m_head);
3419d14c853bSStephen Hurd 		device_printf(dev, "cannot pad short frame\n");
3420d14c853bSStephen Hurd 		DBG_COUNTER_INC(encap_pad_mbuf_fail);
342164e6fc13SStephen Hurd 		DBG_COUNTER_INC(tx_frees);
3422d14c853bSStephen Hurd 		return (ENOBUFS);
3423d14c853bSStephen Hurd 	}
3424d14c853bSStephen Hurd 
3425d14c853bSStephen Hurd 	return 0;
3426d14c853bSStephen Hurd }
3427d14c853bSStephen Hurd 
34284c7070dbSScott Long static int
34294c7070dbSScott Long iflib_encap(iflib_txq_t txq, struct mbuf **m_headp)
34304c7070dbSScott Long {
34314c7070dbSScott Long 	if_ctx_t		ctx;
34324c7070dbSScott Long 	if_shared_ctx_t		sctx;
34334c7070dbSScott Long 	if_softc_ctx_t		scctx;
3434bfce461eSMarius Strobl 	bus_dma_tag_t		buf_tag;
34354c7070dbSScott Long 	bus_dma_segment_t	*segs;
3436fbec776dSAndrew Gallatin 	struct mbuf		*m_head, **ifsd_m;
343795246abbSSean Bruno 	void			*next_txd;
34384c7070dbSScott Long 	bus_dmamap_t		map;
34394c7070dbSScott Long 	struct if_pkt_info	pi;
34404c7070dbSScott Long 	int remap = 0;
34414c7070dbSScott Long 	int err, nsegs, ndesc, max_segs, pidx, cidx, next, ntxd;
34424c7070dbSScott Long 
34434c7070dbSScott Long 	ctx = txq->ift_ctx;
34444c7070dbSScott Long 	sctx = ctx->ifc_sctx;
34454c7070dbSScott Long 	scctx = &ctx->ifc_softc_ctx;
34464c7070dbSScott Long 	segs = txq->ift_segs;
344723ac9029SStephen Hurd 	ntxd = txq->ift_size;
34484c7070dbSScott Long 	m_head = *m_headp;
34494c7070dbSScott Long 	map = NULL;
34504c7070dbSScott Long 
34514c7070dbSScott Long 	/*
34524c7070dbSScott Long 	 * If we're doing TSO the next descriptor to clean may be quite far ahead
34534c7070dbSScott Long 	 */
34544c7070dbSScott Long 	cidx = txq->ift_cidx;
34554c7070dbSScott Long 	pidx = txq->ift_pidx;
345695246abbSSean Bruno 	if (ctx->ifc_flags & IFC_PREFETCH) {
34574c7070dbSScott Long 		next = (cidx + CACHE_PTR_INCREMENT) & (ntxd-1);
345895246abbSSean Bruno 		if (!(ctx->ifc_flags & IFLIB_HAS_TXCQ)) {
345995246abbSSean Bruno 			next_txd = calc_next_txd(txq, cidx, 0);
346095246abbSSean Bruno 			prefetch(next_txd);
346195246abbSSean Bruno 		}
34624c7070dbSScott Long 
34634c7070dbSScott Long 		/* prefetch the next cache line of mbuf pointers and flags */
34644c7070dbSScott Long 		prefetch(&txq->ift_sds.ifsd_m[next]);
34654c7070dbSScott Long 		prefetch(&txq->ift_sds.ifsd_map[next]);
34664c7070dbSScott Long 		next = (cidx + CACHE_LINE_SIZE) & (ntxd-1);
34674c7070dbSScott Long 	}
346895246abbSSean Bruno 	map = txq->ift_sds.ifsd_map[pidx];
3469fbec776dSAndrew Gallatin 	ifsd_m = txq->ift_sds.ifsd_m;
34704c7070dbSScott Long 
34714c7070dbSScott Long 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
3472bfce461eSMarius Strobl 		buf_tag = txq->ift_tso_buf_tag;
34734c7070dbSScott Long 		max_segs = scctx->isc_tx_tso_segments_max;
34748a04b53dSKonstantin Belousov 		map = txq->ift_sds.ifsd_tso_map[pidx];
3475bfce461eSMarius Strobl 		MPASS(buf_tag != NULL);
34767f87c040SMarius Strobl 		MPASS(max_segs > 0);
34774c7070dbSScott Long 	} else {
3478bfce461eSMarius Strobl 		buf_tag = txq->ift_buf_tag;
34794c7070dbSScott Long 		max_segs = scctx->isc_tx_nsegments;
34808a04b53dSKonstantin Belousov 		map = txq->ift_sds.ifsd_map[pidx];
34814c7070dbSScott Long 	}
3482d14c853bSStephen Hurd 	if ((sctx->isc_flags & IFLIB_NEED_ETHER_PAD) &&
3483d14c853bSStephen Hurd 	    __predict_false(m_head->m_pkthdr.len < scctx->isc_min_frame_size)) {
3484a15fbbb8SStephen Hurd 		err = iflib_ether_pad(ctx->ifc_dev, m_headp, scctx->isc_min_frame_size);
348564e6fc13SStephen Hurd 		if (err) {
348664e6fc13SStephen Hurd 			DBG_COUNTER_INC(encap_txd_encap_fail);
3487d14c853bSStephen Hurd 			return err;
3488d14c853bSStephen Hurd 		}
348964e6fc13SStephen Hurd 	}
3490a15fbbb8SStephen Hurd 	m_head = *m_headp;
349195246abbSSean Bruno 
349295246abbSSean Bruno 	pkt_info_zero(&pi);
3493ab2e3f79SStephen Hurd 	pi.ipi_mflags = (m_head->m_flags & (M_VLANTAG|M_BCAST|M_MCAST));
3494ab2e3f79SStephen Hurd 	pi.ipi_pidx = pidx;
3495ab2e3f79SStephen Hurd 	pi.ipi_qsidx = txq->ift_id;
34963429c02fSStephen Hurd 	pi.ipi_len = m_head->m_pkthdr.len;
34973429c02fSStephen Hurd 	pi.ipi_csum_flags = m_head->m_pkthdr.csum_flags;
34981722eeacSMarius Strobl 	pi.ipi_vtag = M_HAS_VLANTAG(m_head) ? m_head->m_pkthdr.ether_vtag : 0;
34994c7070dbSScott Long 
35004c7070dbSScott Long 	/* deliberate bitwise OR to make one condition */
35014c7070dbSScott Long 	if (__predict_true((pi.ipi_csum_flags | pi.ipi_vtag))) {
350264e6fc13SStephen Hurd 		if (__predict_false((err = iflib_parse_header(txq, &pi, m_headp)) != 0)) {
350364e6fc13SStephen Hurd 			DBG_COUNTER_INC(encap_txd_encap_fail);
35044c7070dbSScott Long 			return (err);
350564e6fc13SStephen Hurd 		}
35064c7070dbSScott Long 		m_head = *m_headp;
35074c7070dbSScott Long 	}
35084c7070dbSScott Long 
35094c7070dbSScott Long retry:
3510bfce461eSMarius Strobl 	err = bus_dmamap_load_mbuf_sg(buf_tag, map, m_head, segs, &nsegs,
3511fbec776dSAndrew Gallatin 	    BUS_DMA_NOWAIT);
35124c7070dbSScott Long defrag:
35134c7070dbSScott Long 	if (__predict_false(err)) {
35144c7070dbSScott Long 		switch (err) {
35154c7070dbSScott Long 		case EFBIG:
35164c7070dbSScott Long 			/* try collapse once and defrag once */
3517f7594707SAndrew Gallatin 			if (remap == 0) {
35184c7070dbSScott Long 				m_head = m_collapse(*m_headp, M_NOWAIT, max_segs);
3519f7594707SAndrew Gallatin 				/* try defrag if collapsing fails */
3520f7594707SAndrew Gallatin 				if (m_head == NULL)
3521f7594707SAndrew Gallatin 					remap++;
3522f7594707SAndrew Gallatin 			}
352364e6fc13SStephen Hurd 			if (remap == 1) {
352464e6fc13SStephen Hurd 				txq->ift_mbuf_defrag++;
35254c7070dbSScott Long 				m_head = m_defrag(*m_headp, M_NOWAIT);
352664e6fc13SStephen Hurd 			}
35273e8d1baeSEric Joyner 			/*
35283e8d1baeSEric Joyner 			 * remap should never be >1 unless bus_dmamap_load_mbuf_sg
35293e8d1baeSEric Joyner 			 * failed to map an mbuf that was run through m_defrag
35303e8d1baeSEric Joyner 			 */
35313e8d1baeSEric Joyner 			MPASS(remap <= 1);
35323e8d1baeSEric Joyner 			if (__predict_false(m_head == NULL || remap > 1))
35334c7070dbSScott Long 				goto defrag_failed;
35343e8d1baeSEric Joyner 			remap++;
35354c7070dbSScott Long 			*m_headp = m_head;
35364c7070dbSScott Long 			goto retry;
35374c7070dbSScott Long 			break;
35384c7070dbSScott Long 		case ENOMEM:
35394c7070dbSScott Long 			txq->ift_no_tx_dma_setup++;
35404c7070dbSScott Long 			break;
35414c7070dbSScott Long 		default:
35424c7070dbSScott Long 			txq->ift_no_tx_dma_setup++;
35434c7070dbSScott Long 			m_freem(*m_headp);
35444c7070dbSScott Long 			DBG_COUNTER_INC(tx_frees);
35454c7070dbSScott Long 			*m_headp = NULL;
35464c7070dbSScott Long 			break;
35474c7070dbSScott Long 		}
35484c7070dbSScott Long 		txq->ift_map_failed++;
35494c7070dbSScott Long 		DBG_COUNTER_INC(encap_load_mbuf_fail);
355064e6fc13SStephen Hurd 		DBG_COUNTER_INC(encap_txd_encap_fail);
35514c7070dbSScott Long 		return (err);
35524c7070dbSScott Long 	}
3553fbec776dSAndrew Gallatin 	ifsd_m[pidx] = m_head;
35544c7070dbSScott Long 	/*
35554c7070dbSScott Long 	 * XXX assumes a 1 to 1 relationship between segments and
35564c7070dbSScott Long 	 *        descriptors - this does not hold true on all drivers, e.g.
35574c7070dbSScott Long 	 *        cxgb
35584c7070dbSScott Long 	 */
35594c7070dbSScott Long 	if (__predict_false(nsegs + 2 > TXQ_AVAIL(txq))) {
35604c7070dbSScott Long 		txq->ift_no_desc_avail++;
3561bfce461eSMarius Strobl 		bus_dmamap_unload(buf_tag, map);
35624c7070dbSScott Long 		DBG_COUNTER_INC(encap_txq_avail_fail);
356364e6fc13SStephen Hurd 		DBG_COUNTER_INC(encap_txd_encap_fail);
356423ac9029SStephen Hurd 		if ((txq->ift_task.gt_task.ta_flags & TASK_ENQUEUED) == 0)
35654c7070dbSScott Long 			GROUPTASK_ENQUEUE(&txq->ift_task);
35664c7070dbSScott Long 		return (ENOBUFS);
35674c7070dbSScott Long 	}
356895246abbSSean Bruno 	/*
356995246abbSSean Bruno 	 * On Intel cards we can greatly reduce the number of TX interrupts
357095246abbSSean Bruno 	 * we see by only setting report status on every Nth descriptor.
357195246abbSSean Bruno 	 * However, this also means that the driver will need to keep track
357295246abbSSean Bruno 	 * of the descriptors that RS was set on to check them for the DD bit.
357395246abbSSean Bruno 	 */
357495246abbSSean Bruno 	txq->ift_rs_pending += nsegs + 1;
357595246abbSSean Bruno 	if (txq->ift_rs_pending > TXQ_MAX_RS_DEFERRED(txq) ||
35761f7ce05dSAndrew Gallatin 	     iflib_no_tx_batch || (TXQ_AVAIL(txq) - nsegs) <= MAX_TX_DESC(ctx) + 2) {
357795246abbSSean Bruno 		pi.ipi_flags |= IPI_TX_INTR;
357895246abbSSean Bruno 		txq->ift_rs_pending = 0;
357995246abbSSean Bruno 	}
358095246abbSSean Bruno 
35814c7070dbSScott Long 	pi.ipi_segs = segs;
35824c7070dbSScott Long 	pi.ipi_nsegs = nsegs;
35834c7070dbSScott Long 
358423ac9029SStephen Hurd 	MPASS(pidx >= 0 && pidx < txq->ift_size);
35854c7070dbSScott Long #ifdef PKT_DEBUG
35864c7070dbSScott Long 	print_pkt(&pi);
35874c7070dbSScott Long #endif
35884c7070dbSScott Long 	if ((err = ctx->isc_txd_encap(ctx->ifc_softc, &pi)) == 0) {
358995dcf343SMarius Strobl 		bus_dmamap_sync(buf_tag, map, BUS_DMASYNC_PREWRITE);
35904c7070dbSScott Long 		DBG_COUNTER_INC(tx_encap);
359195246abbSSean Bruno 		MPASS(pi.ipi_new_pidx < txq->ift_size);
35924c7070dbSScott Long 
35934c7070dbSScott Long 		ndesc = pi.ipi_new_pidx - pi.ipi_pidx;
35944c7070dbSScott Long 		if (pi.ipi_new_pidx < pi.ipi_pidx) {
359523ac9029SStephen Hurd 			ndesc += txq->ift_size;
35964c7070dbSScott Long 			txq->ift_gen = 1;
35974c7070dbSScott Long 		}
35981248952aSSean Bruno 		/*
35991248952aSSean Bruno 		 * drivers can need as many as
36001248952aSSean Bruno 		 * two sentinels
36011248952aSSean Bruno 		 */
36021248952aSSean Bruno 		MPASS(ndesc <= pi.ipi_nsegs + 2);
36034c7070dbSScott Long 		MPASS(pi.ipi_new_pidx != pidx);
36044c7070dbSScott Long 		MPASS(ndesc > 0);
36054c7070dbSScott Long 		txq->ift_in_use += ndesc;
360681be6552SMatt Macy 		txq->ift_db_pending += ndesc;
360795246abbSSean Bruno 
36084c7070dbSScott Long 		/*
36094c7070dbSScott Long 		 * We update the last software descriptor again here because there may
36104c7070dbSScott Long 		 * be a sentinel and/or there may be more mbufs than segments
36114c7070dbSScott Long 		 */
36124c7070dbSScott Long 		txq->ift_pidx = pi.ipi_new_pidx;
36134c7070dbSScott Long 		txq->ift_npending += pi.ipi_ndescs;
3614f7594707SAndrew Gallatin 	} else {
361523ac9029SStephen Hurd 		*m_headp = m_head = iflib_remove_mbuf(txq);
3616f7594707SAndrew Gallatin 		if (err == EFBIG) {
36174c7070dbSScott Long 			txq->ift_txd_encap_efbig++;
3618f7594707SAndrew Gallatin 			if (remap < 2) {
3619f7594707SAndrew Gallatin 				remap = 1;
36204c7070dbSScott Long 				goto defrag;
3621f7594707SAndrew Gallatin 			}
3622f7594707SAndrew Gallatin 		}
3623f7594707SAndrew Gallatin 		goto defrag_failed;
3624f7594707SAndrew Gallatin 	}
362564e6fc13SStephen Hurd 	/*
362664e6fc13SStephen Hurd 	 * err can't possibly be non-zero here, so we don't neet to test it
362764e6fc13SStephen Hurd 	 * to see if we need to DBG_COUNTER_INC(encap_txd_encap_fail).
362864e6fc13SStephen Hurd 	 */
36294c7070dbSScott Long 	return (err);
36304c7070dbSScott Long 
36314c7070dbSScott Long defrag_failed:
36324c7070dbSScott Long 	txq->ift_mbuf_defrag_failed++;
36334c7070dbSScott Long 	txq->ift_map_failed++;
36344c7070dbSScott Long 	m_freem(*m_headp);
36354c7070dbSScott Long 	DBG_COUNTER_INC(tx_frees);
36364c7070dbSScott Long 	*m_headp = NULL;
363764e6fc13SStephen Hurd 	DBG_COUNTER_INC(encap_txd_encap_fail);
36384c7070dbSScott Long 	return (ENOMEM);
36394c7070dbSScott Long }
36404c7070dbSScott Long 
36414c7070dbSScott Long static void
36424c7070dbSScott Long iflib_tx_desc_free(iflib_txq_t txq, int n)
36434c7070dbSScott Long {
36444c7070dbSScott Long 	uint32_t qsize, cidx, mask, gen;
36454c7070dbSScott Long 	struct mbuf *m, **ifsd_m;
364695246abbSSean Bruno 	bool do_prefetch;
36474c7070dbSScott Long 
36484c7070dbSScott Long 	cidx = txq->ift_cidx;
36494c7070dbSScott Long 	gen = txq->ift_gen;
365023ac9029SStephen Hurd 	qsize = txq->ift_size;
36514c7070dbSScott Long 	mask = qsize-1;
36524c7070dbSScott Long 	ifsd_m = txq->ift_sds.ifsd_m;
365395246abbSSean Bruno 	do_prefetch = (txq->ift_ctx->ifc_flags & IFC_PREFETCH);
36544c7070dbSScott Long 
365594618825SMark Johnston 	while (n-- > 0) {
365695246abbSSean Bruno 		if (do_prefetch) {
36574c7070dbSScott Long 			prefetch(ifsd_m[(cidx + 3) & mask]);
36584c7070dbSScott Long 			prefetch(ifsd_m[(cidx + 4) & mask]);
365995246abbSSean Bruno 		}
36604c7070dbSScott Long 		if ((m = ifsd_m[cidx]) != NULL) {
3661fbec776dSAndrew Gallatin 			prefetch(&ifsd_m[(cidx + CACHE_PTR_INCREMENT) & mask]);
36628a04b53dSKonstantin Belousov 			if (m->m_pkthdr.csum_flags & CSUM_TSO) {
3663bfce461eSMarius Strobl 				bus_dmamap_sync(txq->ift_tso_buf_tag,
36648a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_tso_map[cidx],
36658a04b53dSKonstantin Belousov 				    BUS_DMASYNC_POSTWRITE);
3666bfce461eSMarius Strobl 				bus_dmamap_unload(txq->ift_tso_buf_tag,
36678a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_tso_map[cidx]);
36688a04b53dSKonstantin Belousov 			} else {
3669bfce461eSMarius Strobl 				bus_dmamap_sync(txq->ift_buf_tag,
36708a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_map[cidx],
36718a04b53dSKonstantin Belousov 				    BUS_DMASYNC_POSTWRITE);
3672bfce461eSMarius Strobl 				bus_dmamap_unload(txq->ift_buf_tag,
36738a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_map[cidx]);
36748a04b53dSKonstantin Belousov 			}
36754c7070dbSScott Long 			/* XXX we don't support any drivers that batch packets yet */
36764c7070dbSScott Long 			MPASS(m->m_nextpkt == NULL);
36775c5ca36cSSean Bruno 			m_freem(m);
36784c7070dbSScott Long 			ifsd_m[cidx] = NULL;
36794c7070dbSScott Long #if MEMORY_LOGGING
36804c7070dbSScott Long 			txq->ift_dequeued++;
36814c7070dbSScott Long #endif
36824c7070dbSScott Long 			DBG_COUNTER_INC(tx_frees);
36834c7070dbSScott Long 		}
36844c7070dbSScott Long 		if (__predict_false(++cidx == qsize)) {
36854c7070dbSScott Long 			cidx = 0;
36864c7070dbSScott Long 			gen = 0;
36874c7070dbSScott Long 		}
36884c7070dbSScott Long 	}
36894c7070dbSScott Long 	txq->ift_cidx = cidx;
36904c7070dbSScott Long 	txq->ift_gen = gen;
36914c7070dbSScott Long }
36924c7070dbSScott Long 
36934c7070dbSScott Long static __inline int
36944c7070dbSScott Long iflib_completed_tx_reclaim(iflib_txq_t txq, int thresh)
36954c7070dbSScott Long {
36964c7070dbSScott Long 	int reclaim;
36974c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
36984c7070dbSScott Long 
36994c7070dbSScott Long 	KASSERT(thresh >= 0, ("invalid threshold to reclaim"));
37004c7070dbSScott Long 	MPASS(thresh /*+ MAX_TX_DESC(txq->ift_ctx) */ < txq->ift_size);
37014c7070dbSScott Long 
37024c7070dbSScott Long 	/*
37034c7070dbSScott Long 	 * Need a rate-limiting check so that this isn't called every time
37044c7070dbSScott Long 	 */
37054c7070dbSScott Long 	iflib_tx_credits_update(ctx, txq);
37064c7070dbSScott Long 	reclaim = DESC_RECLAIMABLE(txq);
37074c7070dbSScott Long 
37084c7070dbSScott Long 	if (reclaim <= thresh /* + MAX_TX_DESC(txq->ift_ctx) */) {
37094c7070dbSScott Long #ifdef INVARIANTS
37104c7070dbSScott Long 		if (iflib_verbose_debug) {
37114c7070dbSScott Long 			printf("%s processed=%ju cleaned=%ju tx_nsegments=%d reclaim=%d thresh=%d\n", __FUNCTION__,
37124c7070dbSScott Long 			       txq->ift_processed, txq->ift_cleaned, txq->ift_ctx->ifc_softc_ctx.isc_tx_nsegments,
37134c7070dbSScott Long 			       reclaim, thresh);
37144c7070dbSScott Long 		}
37154c7070dbSScott Long #endif
37164c7070dbSScott Long 		return (0);
37174c7070dbSScott Long 	}
37184c7070dbSScott Long 	iflib_tx_desc_free(txq, reclaim);
37194c7070dbSScott Long 	txq->ift_cleaned += reclaim;
37204c7070dbSScott Long 	txq->ift_in_use -= reclaim;
37214c7070dbSScott Long 
37224c7070dbSScott Long 	return (reclaim);
37234c7070dbSScott Long }
37244c7070dbSScott Long 
37254c7070dbSScott Long static struct mbuf **
372695246abbSSean Bruno _ring_peek_one(struct ifmp_ring *r, int cidx, int offset, int remaining)
37274c7070dbSScott Long {
372895246abbSSean Bruno 	int next, size;
372995246abbSSean Bruno 	struct mbuf **items;
37304c7070dbSScott Long 
373195246abbSSean Bruno 	size = r->size;
373295246abbSSean Bruno 	next = (cidx + CACHE_PTR_INCREMENT) & (size-1);
373395246abbSSean Bruno 	items = __DEVOLATILE(struct mbuf **, &r->items[0]);
373495246abbSSean Bruno 
373595246abbSSean Bruno 	prefetch(items[(cidx + offset) & (size-1)]);
373695246abbSSean Bruno 	if (remaining > 1) {
37373429c02fSStephen Hurd 		prefetch2cachelines(&items[next]);
37383429c02fSStephen Hurd 		prefetch2cachelines(items[(cidx + offset + 1) & (size-1)]);
37393429c02fSStephen Hurd 		prefetch2cachelines(items[(cidx + offset + 2) & (size-1)]);
37403429c02fSStephen Hurd 		prefetch2cachelines(items[(cidx + offset + 3) & (size-1)]);
374195246abbSSean Bruno 	}
374295246abbSSean Bruno 	return (__DEVOLATILE(struct mbuf **, &r->items[(cidx + offset) & (size-1)]));
37434c7070dbSScott Long }
37444c7070dbSScott Long 
37454c7070dbSScott Long static void
37464c7070dbSScott Long iflib_txq_check_drain(iflib_txq_t txq, int budget)
37474c7070dbSScott Long {
37484c7070dbSScott Long 
374995246abbSSean Bruno 	ifmp_ring_check_drainage(txq->ift_br, budget);
37504c7070dbSScott Long }
37514c7070dbSScott Long 
37524c7070dbSScott Long static uint32_t
37534c7070dbSScott Long iflib_txq_can_drain(struct ifmp_ring *r)
37544c7070dbSScott Long {
37554c7070dbSScott Long 	iflib_txq_t txq = r->cookie;
37564c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
37574c7070dbSScott Long 
375895dcf343SMarius Strobl 	if (TXQ_AVAIL(txq) > MAX_TX_DESC(ctx) + 2)
375995dcf343SMarius Strobl 		return (1);
37608a04b53dSKonstantin Belousov 	bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
37618a04b53dSKonstantin Belousov 	    BUS_DMASYNC_POSTREAD);
376295dcf343SMarius Strobl 	return (ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id,
376395dcf343SMarius Strobl 	    false));
37644c7070dbSScott Long }
37654c7070dbSScott Long 
37664c7070dbSScott Long static uint32_t
37674c7070dbSScott Long iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
37684c7070dbSScott Long {
37694c7070dbSScott Long 	iflib_txq_t txq = r->cookie;
37704c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
37711722eeacSMarius Strobl 	if_t ifp = ctx->ifc_ifp;
3772c2c5d1e7SMarius Strobl 	struct mbuf *m, **mp;
377381be6552SMatt Macy 	int avail, bytes_sent, skipped, count, err, i;
377481be6552SMatt Macy 	int mcast_sent, pkt_sent, reclaimed;
3775c2c5d1e7SMarius Strobl 	bool do_prefetch, rang, ring;
37764c7070dbSScott Long 
37774c7070dbSScott Long 	if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING) ||
37784c7070dbSScott Long 			    !LINK_ACTIVE(ctx))) {
37794c7070dbSScott Long 		DBG_COUNTER_INC(txq_drain_notready);
37804c7070dbSScott Long 		return (0);
37814c7070dbSScott Long 	}
378295246abbSSean Bruno 	reclaimed = iflib_completed_tx_reclaim(txq, RECLAIM_THRESH(ctx));
378381be6552SMatt Macy 	rang = iflib_txd_db_check(txq, reclaimed && txq->ift_db_pending);
37844c7070dbSScott Long 	avail = IDXDIFF(pidx, cidx, r->size);
378581be6552SMatt Macy 
37864c7070dbSScott Long 	if (__predict_false(ctx->ifc_flags & IFC_QFLUSH)) {
378781be6552SMatt Macy 		/*
378881be6552SMatt Macy 		 * The driver is unloading so we need to free all pending packets.
378981be6552SMatt Macy 		 */
37904c7070dbSScott Long 		DBG_COUNTER_INC(txq_drain_flushing);
37914c7070dbSScott Long 		for (i = 0; i < avail; i++) {
3792bc0e855bSStephen Hurd 			if (__predict_true(r->items[(cidx + i) & (r->size-1)] != (void *)txq))
379354bf96fbSMark Johnston 				m_freem(r->items[(cidx + i) & (r->size-1)]);
37944c7070dbSScott Long 			r->items[(cidx + i) & (r->size-1)] = NULL;
37954c7070dbSScott Long 		}
37964c7070dbSScott Long 		return (avail);
37974c7070dbSScott Long 	}
379895246abbSSean Bruno 
37994c7070dbSScott Long 	if (__predict_false(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE)) {
38004c7070dbSScott Long 		txq->ift_qstatus = IFLIB_QUEUE_IDLE;
38014c7070dbSScott Long 		CALLOUT_LOCK(txq);
38024c7070dbSScott Long 		callout_stop(&txq->ift_timer);
38034c7070dbSScott Long 		CALLOUT_UNLOCK(txq);
38044c7070dbSScott Long 		DBG_COUNTER_INC(txq_drain_oactive);
38054c7070dbSScott Long 		return (0);
38064c7070dbSScott Long 	}
380781be6552SMatt Macy 
380881be6552SMatt Macy 	/*
380981be6552SMatt Macy 	 * If we've reclaimed any packets this queue cannot be hung.
381081be6552SMatt Macy 	 */
381195246abbSSean Bruno 	if (reclaimed)
381295246abbSSean Bruno 		txq->ift_qstatus = IFLIB_QUEUE_IDLE;
381381be6552SMatt Macy 	skipped = mcast_sent = bytes_sent = pkt_sent = 0;
38144c7070dbSScott Long 	count = MIN(avail, TX_BATCH_SIZE);
3815da69b8f9SSean Bruno #ifdef INVARIANTS
3816da69b8f9SSean Bruno 	if (iflib_verbose_debug)
3817da69b8f9SSean Bruno 		printf("%s avail=%d ifc_flags=%x txq_avail=%d ", __FUNCTION__,
3818da69b8f9SSean Bruno 		       avail, ctx->ifc_flags, TXQ_AVAIL(txq));
3819da69b8f9SSean Bruno #endif
382095246abbSSean Bruno 	do_prefetch = (ctx->ifc_flags & IFC_PREFETCH);
38211ae4848cSMatt Macy 	err = 0;
382281be6552SMatt Macy 	for (i = 0; i < count && TXQ_AVAIL(txq) >= MAX_TX_DESC(ctx) + 2; i++) {
38231ae4848cSMatt Macy 		int rem = do_prefetch ? count - i : 0;
38244c7070dbSScott Long 
382595246abbSSean Bruno 		mp = _ring_peek_one(r, cidx, i, rem);
3826da69b8f9SSean Bruno 		MPASS(mp != NULL && *mp != NULL);
382781be6552SMatt Macy 
382881be6552SMatt Macy 		/*
382981be6552SMatt Macy 		 * Completion interrupts will use the address of the txq
383081be6552SMatt Macy 		 * as a sentinel to enqueue _something_ in order to acquire
383181be6552SMatt Macy 		 * the lock on the mp_ring (there's no direct lock call).
383281be6552SMatt Macy 		 * We obviously whave to check for these sentinel cases
383381be6552SMatt Macy 		 * and skip them.
383481be6552SMatt Macy 		 */
383595246abbSSean Bruno 		if (__predict_false(*mp == (struct mbuf *)txq)) {
383681be6552SMatt Macy 			skipped++;
383795246abbSSean Bruno 			continue;
383895246abbSSean Bruno 		}
383995246abbSSean Bruno 		err = iflib_encap(txq, mp);
384095246abbSSean Bruno 		if (__predict_false(err)) {
3841da69b8f9SSean Bruno 			/* no room - bail out */
384295246abbSSean Bruno 			if (err == ENOBUFS)
38434c7070dbSScott Long 				break;
384481be6552SMatt Macy 			skipped++;
3845da69b8f9SSean Bruno 			/* we can't send this packet - skip it */
38464c7070dbSScott Long 			continue;
3847da69b8f9SSean Bruno 		}
38484c7070dbSScott Long 		pkt_sent++;
38494c7070dbSScott Long 		m = *mp;
38504c7070dbSScott Long 		DBG_COUNTER_INC(tx_sent);
38514c7070dbSScott Long 		bytes_sent += m->m_pkthdr.len;
385295246abbSSean Bruno 		mcast_sent += !!(m->m_flags & M_MCAST);
38534c7070dbSScott Long 
385495246abbSSean Bruno 		if (__predict_false(!(ifp->if_drv_flags & IFF_DRV_RUNNING)))
38554c7070dbSScott Long 			break;
385681be6552SMatt Macy 		ETHER_BPF_MTAP(ifp, m);
385781be6552SMatt Macy 		rang = iflib_txd_db_check(txq, false);
38584c7070dbSScott Long 	}
38594c7070dbSScott Long 
386095246abbSSean Bruno 	/* deliberate use of bitwise or to avoid gratuitous short-circuit */
386181be6552SMatt Macy 	ring = rang ? false  : (iflib_min_tx_latency | err);
386281be6552SMatt Macy 	iflib_txd_db_check(txq, ring);
38634c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_OBYTES, bytes_sent);
38644c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_OPACKETS, pkt_sent);
38654c7070dbSScott Long 	if (mcast_sent)
38664c7070dbSScott Long 		if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast_sent);
3867da69b8f9SSean Bruno #ifdef INVARIANTS
3868da69b8f9SSean Bruno 	if (iflib_verbose_debug)
386981be6552SMatt Macy 		printf("consumed=%d\n", skipped + pkt_sent);
3870da69b8f9SSean Bruno #endif
387181be6552SMatt Macy 	return (skipped + pkt_sent);
38724c7070dbSScott Long }
38734c7070dbSScott Long 
3874da69b8f9SSean Bruno static uint32_t
3875da69b8f9SSean Bruno iflib_txq_drain_always(struct ifmp_ring *r)
3876da69b8f9SSean Bruno {
3877da69b8f9SSean Bruno 	return (1);
3878da69b8f9SSean Bruno }
3879da69b8f9SSean Bruno 
3880da69b8f9SSean Bruno static uint32_t
3881da69b8f9SSean Bruno iflib_txq_drain_free(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
3882da69b8f9SSean Bruno {
3883da69b8f9SSean Bruno 	int i, avail;
3884da69b8f9SSean Bruno 	struct mbuf **mp;
3885da69b8f9SSean Bruno 	iflib_txq_t txq;
3886da69b8f9SSean Bruno 
3887da69b8f9SSean Bruno 	txq = r->cookie;
3888da69b8f9SSean Bruno 
3889da69b8f9SSean Bruno 	txq->ift_qstatus = IFLIB_QUEUE_IDLE;
3890da69b8f9SSean Bruno 	CALLOUT_LOCK(txq);
3891da69b8f9SSean Bruno 	callout_stop(&txq->ift_timer);
3892da69b8f9SSean Bruno 	CALLOUT_UNLOCK(txq);
3893da69b8f9SSean Bruno 
3894da69b8f9SSean Bruno 	avail = IDXDIFF(pidx, cidx, r->size);
3895da69b8f9SSean Bruno 	for (i = 0; i < avail; i++) {
389695246abbSSean Bruno 		mp = _ring_peek_one(r, cidx, i, avail - i);
389795246abbSSean Bruno 		if (__predict_false(*mp == (struct mbuf *)txq))
389895246abbSSean Bruno 			continue;
3899da69b8f9SSean Bruno 		m_freem(*mp);
390064e6fc13SStephen Hurd 		DBG_COUNTER_INC(tx_frees);
3901da69b8f9SSean Bruno 	}
3902da69b8f9SSean Bruno 	MPASS(ifmp_ring_is_stalled(r) == 0);
3903da69b8f9SSean Bruno 	return (avail);
3904da69b8f9SSean Bruno }
3905da69b8f9SSean Bruno 
3906da69b8f9SSean Bruno static void
3907da69b8f9SSean Bruno iflib_ifmp_purge(iflib_txq_t txq)
3908da69b8f9SSean Bruno {
3909da69b8f9SSean Bruno 	struct ifmp_ring *r;
3910da69b8f9SSean Bruno 
391195246abbSSean Bruno 	r = txq->ift_br;
3912da69b8f9SSean Bruno 	r->drain = iflib_txq_drain_free;
3913da69b8f9SSean Bruno 	r->can_drain = iflib_txq_drain_always;
3914da69b8f9SSean Bruno 
3915da69b8f9SSean Bruno 	ifmp_ring_check_drainage(r, r->size);
3916da69b8f9SSean Bruno 
3917da69b8f9SSean Bruno 	r->drain = iflib_txq_drain;
3918da69b8f9SSean Bruno 	r->can_drain = iflib_txq_can_drain;
3919da69b8f9SSean Bruno }
3920da69b8f9SSean Bruno 
39214c7070dbSScott Long static void
392223ac9029SStephen Hurd _task_fn_tx(void *context)
39234c7070dbSScott Long {
39244c7070dbSScott Long 	iflib_txq_t txq = context;
39254c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
3926a6611c93SMarius Strobl 	if_t ifp = ctx->ifc_ifp;
3927fe51d4cdSStephen Hurd 	int abdicate = ctx->ifc_sysctl_tx_abdicate;
39284c7070dbSScott Long 
39291248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
39301248952aSSean Bruno 	txq->ift_cpu_exec_count[curcpu]++;
39311248952aSSean Bruno #endif
393288a68866SVincenzo Maffione 	if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
39334c7070dbSScott Long 		return;
393495dcf343SMarius Strobl #ifdef DEV_NETMAP
393588a68866SVincenzo Maffione 	if ((if_getcapenable(ifp) & IFCAP_NETMAP) &&
393688a68866SVincenzo Maffione 	    netmap_tx_irq(ifp, txq->ift_id))
393788a68866SVincenzo Maffione 		goto skip_ifmp;
393895dcf343SMarius Strobl #endif
3939b8ca4756SPatrick Kelsey #ifdef ALTQ
3940b8ca4756SPatrick Kelsey 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
3941b8ca4756SPatrick Kelsey 		iflib_altq_if_start(ifp);
3942b8ca4756SPatrick Kelsey #endif
394395246abbSSean Bruno 	if (txq->ift_db_pending)
3944fe51d4cdSStephen Hurd 		ifmp_ring_enqueue(txq->ift_br, (void **)&txq, 1, TX_BATCH_SIZE, abdicate);
3945fe51d4cdSStephen Hurd 	else if (!abdicate)
3946fe51d4cdSStephen Hurd 		ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
3947fe51d4cdSStephen Hurd 	/*
3948fe51d4cdSStephen Hurd 	 * When abdicating, we always need to check drainage, not just when we don't enqueue
3949fe51d4cdSStephen Hurd 	 */
3950fe51d4cdSStephen Hurd 	if (abdicate)
3951fe51d4cdSStephen Hurd 		ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
395288a68866SVincenzo Maffione #ifdef DEV_NETMAP
395388a68866SVincenzo Maffione skip_ifmp:
395488a68866SVincenzo Maffione #endif
395595246abbSSean Bruno 	if (ctx->ifc_flags & IFC_LEGACY)
395695246abbSSean Bruno 		IFDI_INTR_ENABLE(ctx);
39573d10e9edSMarius Strobl 	else
39581ae4848cSMatt Macy 		IFDI_TX_QUEUE_INTR_ENABLE(ctx, txq->ift_id);
39594c7070dbSScott Long }
39604c7070dbSScott Long 
39614c7070dbSScott Long static void
396223ac9029SStephen Hurd _task_fn_rx(void *context)
39634c7070dbSScott Long {
39644c7070dbSScott Long 	iflib_rxq_t rxq = context;
39654c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
3966fb1a29b4SHans Petter Selasky 	uint8_t more;
3967f4d2154eSStephen Hurd 	uint16_t budget;
3968e136e9c8SVincenzo Maffione #ifdef DEV_NETMAP
3969e136e9c8SVincenzo Maffione 	u_int work = 0;
3970e136e9c8SVincenzo Maffione 	int nmirq;
3971e136e9c8SVincenzo Maffione #endif
39724c7070dbSScott Long 
39731248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
39741248952aSSean Bruno 	rxq->ifr_cpu_exec_count[curcpu]++;
39751248952aSSean Bruno #endif
39764c7070dbSScott Long 	DBG_COUNTER_INC(task_fn_rxs);
39774c7070dbSScott Long 	if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
39784c7070dbSScott Long 		return;
3979d0d0ad0aSStephen Hurd #ifdef DEV_NETMAP
3980e136e9c8SVincenzo Maffione 	nmirq = netmap_rx_irq(ctx->ifc_ifp, rxq->ifr_id, &work);
3981e136e9c8SVincenzo Maffione 	if (nmirq != NM_IRQ_PASS) {
3982e136e9c8SVincenzo Maffione 		more = (nmirq == NM_IRQ_RESCHED) ? IFLIB_RXEOF_MORE : 0;
3983fb1a29b4SHans Petter Selasky 		goto skip_rxeof;
3984d0d0ad0aSStephen Hurd 	}
3985d0d0ad0aSStephen Hurd #endif
3986f4d2154eSStephen Hurd 	budget = ctx->ifc_sysctl_rx_budget;
3987f4d2154eSStephen Hurd 	if (budget == 0)
3988f4d2154eSStephen Hurd 		budget = 16;	/* XXX */
3989fb1a29b4SHans Petter Selasky 	more = iflib_rxeof(rxq, budget);
3990fb1a29b4SHans Petter Selasky #ifdef DEV_NETMAP
3991fb1a29b4SHans Petter Selasky skip_rxeof:
3992fb1a29b4SHans Petter Selasky #endif
3993fb1a29b4SHans Petter Selasky 	if ((more & IFLIB_RXEOF_MORE) == 0) {
39944c7070dbSScott Long 		if (ctx->ifc_flags & IFC_LEGACY)
39954c7070dbSScott Long 			IFDI_INTR_ENABLE(ctx);
39963d10e9edSMarius Strobl 		else
39971ae4848cSMatt Macy 			IFDI_RX_QUEUE_INTR_ENABLE(ctx, rxq->ifr_id);
39981ae4848cSMatt Macy 		DBG_COUNTER_INC(rx_intr_enables);
39994c7070dbSScott Long 	}
40004c7070dbSScott Long 	if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
40014c7070dbSScott Long 		return;
4002fb1a29b4SHans Petter Selasky 
4003fb1a29b4SHans Petter Selasky 	if (more & IFLIB_RXEOF_MORE)
40044c7070dbSScott Long 		GROUPTASK_ENQUEUE(&rxq->ifr_task);
4005fb1a29b4SHans Petter Selasky 	else if (more & IFLIB_RXEOF_EMPTY)
4006fb1a29b4SHans Petter Selasky 		callout_reset_curcpu(&rxq->ifr_watchdog, 1, &_task_fn_rx_watchdog, rxq);
40074c7070dbSScott Long }
40084c7070dbSScott Long 
40094c7070dbSScott Long static void
401023ac9029SStephen Hurd _task_fn_admin(void *context)
40114c7070dbSScott Long {
40124c7070dbSScott Long 	if_ctx_t ctx = context;
40134c7070dbSScott Long 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
40144c7070dbSScott Long 	iflib_txq_t txq;
4015ab2e3f79SStephen Hurd 	int i;
401677c1fcecSEric Joyner 	bool oactive, running, do_reset, do_watchdog, in_detach;
4017ab2e3f79SStephen Hurd 
40187b610b60SSean Bruno 	STATE_LOCK(ctx);
40197b610b60SSean Bruno 	running = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING);
40207b610b60SSean Bruno 	oactive = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE);
40217b610b60SSean Bruno 	do_reset = (ctx->ifc_flags & IFC_DO_RESET);
40227b610b60SSean Bruno 	do_watchdog = (ctx->ifc_flags & IFC_DO_WATCHDOG);
402377c1fcecSEric Joyner 	in_detach = (ctx->ifc_flags & IFC_IN_DETACH);
40247b610b60SSean Bruno 	ctx->ifc_flags &= ~(IFC_DO_RESET|IFC_DO_WATCHDOG);
40257b610b60SSean Bruno 	STATE_UNLOCK(ctx);
40267b610b60SSean Bruno 
402777c1fcecSEric Joyner 	if ((!running && !oactive) && !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
402877c1fcecSEric Joyner 		return;
402977c1fcecSEric Joyner 	if (in_detach)
4030ab2e3f79SStephen Hurd 		return;
40314c7070dbSScott Long 
40324c7070dbSScott Long 	CTX_LOCK(ctx);
40334c7070dbSScott Long 	for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) {
40344c7070dbSScott Long 		CALLOUT_LOCK(txq);
40354c7070dbSScott Long 		callout_stop(&txq->ift_timer);
40364c7070dbSScott Long 		CALLOUT_UNLOCK(txq);
40374c7070dbSScott Long 	}
403809c3f04fSMarcin Wojtas 	if (ctx->ifc_sctx->isc_flags & IFLIB_HAS_ADMINCQ)
403909c3f04fSMarcin Wojtas 		IFDI_ADMIN_COMPLETION_HANDLE(ctx);
40407b610b60SSean Bruno 	if (do_watchdog) {
40417b610b60SSean Bruno 		ctx->ifc_watchdog_events++;
40427b610b60SSean Bruno 		IFDI_WATCHDOG_RESET(ctx);
40437b610b60SSean Bruno 	}
4044d300df01SStephen Hurd 	IFDI_UPDATE_ADMIN_STATUS(ctx);
4045dd7fbcf1SStephen Hurd 	for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) {
404681be6552SMatt Macy 		callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer, txq,
404717cec474SVincenzo Maffione 		    txq->ift_timer.c_cpu);
4048dd7fbcf1SStephen Hurd 	}
4049ab2e3f79SStephen Hurd 	IFDI_LINK_INTR_ENABLE(ctx);
40507b610b60SSean Bruno 	if (do_reset)
4051ab2e3f79SStephen Hurd 		iflib_if_init_locked(ctx);
40524c7070dbSScott Long 	CTX_UNLOCK(ctx);
40534c7070dbSScott Long 
4054ab2e3f79SStephen Hurd 	if (LINK_ACTIVE(ctx) == 0)
40554c7070dbSScott Long 		return;
40564c7070dbSScott Long 	for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++)
40574c7070dbSScott Long 		iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET);
40584c7070dbSScott Long }
40594c7070dbSScott Long 
40604c7070dbSScott Long static void
406123ac9029SStephen Hurd _task_fn_iov(void *context)
40624c7070dbSScott Long {
40634c7070dbSScott Long 	if_ctx_t ctx = context;
40644c7070dbSScott Long 
406577c1fcecSEric Joyner 	if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) &&
406677c1fcecSEric Joyner 	    !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
40674c7070dbSScott Long 		return;
40684c7070dbSScott Long 
40694c7070dbSScott Long 	CTX_LOCK(ctx);
40704c7070dbSScott Long 	IFDI_VFLR_HANDLE(ctx);
40714c7070dbSScott Long 	CTX_UNLOCK(ctx);
40724c7070dbSScott Long }
40734c7070dbSScott Long 
40744c7070dbSScott Long static int
40754c7070dbSScott Long iflib_sysctl_int_delay(SYSCTL_HANDLER_ARGS)
40764c7070dbSScott Long {
40774c7070dbSScott Long 	int err;
40784c7070dbSScott Long 	if_int_delay_info_t info;
40794c7070dbSScott Long 	if_ctx_t ctx;
40804c7070dbSScott Long 
40814c7070dbSScott Long 	info = (if_int_delay_info_t)arg1;
40824c7070dbSScott Long 	ctx = info->iidi_ctx;
40834c7070dbSScott Long 	info->iidi_req = req;
40844c7070dbSScott Long 	info->iidi_oidp = oidp;
40854c7070dbSScott Long 	CTX_LOCK(ctx);
40864c7070dbSScott Long 	err = IFDI_SYSCTL_INT_DELAY(ctx, info);
40874c7070dbSScott Long 	CTX_UNLOCK(ctx);
40884c7070dbSScott Long 	return (err);
40894c7070dbSScott Long }
40904c7070dbSScott Long 
40914c7070dbSScott Long /*********************************************************************
40924c7070dbSScott Long  *
40934c7070dbSScott Long  *  IFNET FUNCTIONS
40944c7070dbSScott Long  *
40954c7070dbSScott Long  **********************************************************************/
40964c7070dbSScott Long 
40974c7070dbSScott Long static void
40984c7070dbSScott Long iflib_if_init_locked(if_ctx_t ctx)
40994c7070dbSScott Long {
41004c7070dbSScott Long 	iflib_stop(ctx);
41014c7070dbSScott Long 	iflib_init_locked(ctx);
41024c7070dbSScott Long }
41034c7070dbSScott Long 
41044c7070dbSScott Long static void
41054c7070dbSScott Long iflib_if_init(void *arg)
41064c7070dbSScott Long {
41074c7070dbSScott Long 	if_ctx_t ctx = arg;
41084c7070dbSScott Long 
41094c7070dbSScott Long 	CTX_LOCK(ctx);
41104c7070dbSScott Long 	iflib_if_init_locked(ctx);
41114c7070dbSScott Long 	CTX_UNLOCK(ctx);
41124c7070dbSScott Long }
41134c7070dbSScott Long 
41144c7070dbSScott Long static int
41154c7070dbSScott Long iflib_if_transmit(if_t ifp, struct mbuf *m)
41164c7070dbSScott Long {
41174c7070dbSScott Long 	if_ctx_t	ctx = if_getsoftc(ifp);
41184c7070dbSScott Long 
41194c7070dbSScott Long 	iflib_txq_t txq;
412023ac9029SStephen Hurd 	int err, qidx;
4121fe51d4cdSStephen Hurd 	int abdicate = ctx->ifc_sysctl_tx_abdicate;
41224c7070dbSScott Long 
41234c7070dbSScott Long 	if (__predict_false((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || !LINK_ACTIVE(ctx))) {
41244c7070dbSScott Long 		DBG_COUNTER_INC(tx_frees);
41254c7070dbSScott Long 		m_freem(m);
4126225eae1bSEric Joyner 		return (ENETDOWN);
41274c7070dbSScott Long 	}
41284c7070dbSScott Long 
412923ac9029SStephen Hurd 	MPASS(m->m_nextpkt == NULL);
4130b8ca4756SPatrick Kelsey 	/* ALTQ-enabled interfaces always use queue 0. */
41314c7070dbSScott Long 	qidx = 0;
4132b8ca4756SPatrick Kelsey 	if ((NTXQSETS(ctx) > 1) && M_HASHTYPE_GET(m) && !ALTQ_IS_ENABLED(&ifp->if_snd))
41334c7070dbSScott Long 		qidx = QIDX(ctx, m);
41344c7070dbSScott Long 	/*
41354c7070dbSScott Long 	 * XXX calculate buf_ring based on flowid (divvy up bits?)
41364c7070dbSScott Long 	 */
41374c7070dbSScott Long 	txq = &ctx->ifc_txqs[qidx];
41384c7070dbSScott Long 
41394c7070dbSScott Long #ifdef DRIVER_BACKPRESSURE
41404c7070dbSScott Long 	if (txq->ift_closed) {
41414c7070dbSScott Long 		while (m != NULL) {
41424c7070dbSScott Long 			next = m->m_nextpkt;
41434c7070dbSScott Long 			m->m_nextpkt = NULL;
41444c7070dbSScott Long 			m_freem(m);
414564e6fc13SStephen Hurd 			DBG_COUNTER_INC(tx_frees);
41464c7070dbSScott Long 			m = next;
41474c7070dbSScott Long 		}
41484c7070dbSScott Long 		return (ENOBUFS);
41494c7070dbSScott Long 	}
41504c7070dbSScott Long #endif
415123ac9029SStephen Hurd #ifdef notyet
41524c7070dbSScott Long 	qidx = count = 0;
41534c7070dbSScott Long 	mp = marr;
41544c7070dbSScott Long 	next = m;
41554c7070dbSScott Long 	do {
41564c7070dbSScott Long 		count++;
41574c7070dbSScott Long 		next = next->m_nextpkt;
41584c7070dbSScott Long 	} while (next != NULL);
41594c7070dbSScott Long 
416016fb86abSConrad Meyer 	if (count > nitems(marr))
41614c7070dbSScott Long 		if ((mp = malloc(count*sizeof(struct mbuf *), M_IFLIB, M_NOWAIT)) == NULL) {
41624c7070dbSScott Long 			/* XXX check nextpkt */
41634c7070dbSScott Long 			m_freem(m);
41644c7070dbSScott Long 			/* XXX simplify for now */
41654c7070dbSScott Long 			DBG_COUNTER_INC(tx_frees);
41664c7070dbSScott Long 			return (ENOBUFS);
41674c7070dbSScott Long 		}
41684c7070dbSScott Long 	for (next = m, i = 0; next != NULL; i++) {
41694c7070dbSScott Long 		mp[i] = next;
41704c7070dbSScott Long 		next = next->m_nextpkt;
41714c7070dbSScott Long 		mp[i]->m_nextpkt = NULL;
41724c7070dbSScott Long 	}
417323ac9029SStephen Hurd #endif
41744c7070dbSScott Long 	DBG_COUNTER_INC(tx_seen);
4175fe51d4cdSStephen Hurd 	err = ifmp_ring_enqueue(txq->ift_br, (void **)&m, 1, TX_BATCH_SIZE, abdicate);
41764c7070dbSScott Long 
4177fe51d4cdSStephen Hurd 	if (abdicate)
4178ab2e3f79SStephen Hurd 		GROUPTASK_ENQUEUE(&txq->ift_task);
41791225d9daSStephen Hurd  	if (err) {
4180fe51d4cdSStephen Hurd 		if (!abdicate)
4181fe51d4cdSStephen Hurd 			GROUPTASK_ENQUEUE(&txq->ift_task);
41824c7070dbSScott Long 		/* support forthcoming later */
41834c7070dbSScott Long #ifdef DRIVER_BACKPRESSURE
41844c7070dbSScott Long 		txq->ift_closed = TRUE;
41854c7070dbSScott Long #endif
418695246abbSSean Bruno 		ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
418723ac9029SStephen Hurd 		m_freem(m);
418864e6fc13SStephen Hurd 		DBG_COUNTER_INC(tx_frees);
41894c7070dbSScott Long 	}
41904c7070dbSScott Long 
41914c7070dbSScott Long 	return (err);
41924c7070dbSScott Long }
41934c7070dbSScott Long 
4194b8ca4756SPatrick Kelsey #ifdef ALTQ
4195b8ca4756SPatrick Kelsey /*
4196b8ca4756SPatrick Kelsey  * The overall approach to integrating iflib with ALTQ is to continue to use
4197b8ca4756SPatrick Kelsey  * the iflib mp_ring machinery between the ALTQ queue(s) and the hardware
4198b8ca4756SPatrick Kelsey  * ring.  Technically, when using ALTQ, queueing to an intermediate mp_ring
4199b8ca4756SPatrick Kelsey  * is redundant/unnecessary, but doing so minimizes the amount of
4200b8ca4756SPatrick Kelsey  * ALTQ-specific code required in iflib.  It is assumed that the overhead of
4201b8ca4756SPatrick Kelsey  * redundantly queueing to an intermediate mp_ring is swamped by the
4202b8ca4756SPatrick Kelsey  * performance limitations inherent in using ALTQ.
4203b8ca4756SPatrick Kelsey  *
4204b8ca4756SPatrick Kelsey  * When ALTQ support is compiled in, all iflib drivers will use a transmit
4205b8ca4756SPatrick Kelsey  * routine, iflib_altq_if_transmit(), that checks if ALTQ is enabled for the
4206b8ca4756SPatrick Kelsey  * given interface.  If ALTQ is enabled for an interface, then all
4207b8ca4756SPatrick Kelsey  * transmitted packets for that interface will be submitted to the ALTQ
4208b8ca4756SPatrick Kelsey  * subsystem via IFQ_ENQUEUE().  We don't use the legacy if_transmit()
4209b8ca4756SPatrick Kelsey  * implementation because it uses IFQ_HANDOFF(), which will duplicatively
4210b8ca4756SPatrick Kelsey  * update stats that the iflib machinery handles, and which is sensitve to
4211b8ca4756SPatrick Kelsey  * the disused IFF_DRV_OACTIVE flag.  Additionally, iflib_altq_if_start()
4212b8ca4756SPatrick Kelsey  * will be installed as the start routine for use by ALTQ facilities that
4213b8ca4756SPatrick Kelsey  * need to trigger queue drains on a scheduled basis.
4214b8ca4756SPatrick Kelsey  *
4215b8ca4756SPatrick Kelsey  */
4216b8ca4756SPatrick Kelsey static void
4217b8ca4756SPatrick Kelsey iflib_altq_if_start(if_t ifp)
4218b8ca4756SPatrick Kelsey {
4219b8ca4756SPatrick Kelsey 	struct ifaltq *ifq = &ifp->if_snd;
4220b8ca4756SPatrick Kelsey 	struct mbuf *m;
4221b8ca4756SPatrick Kelsey 
4222b8ca4756SPatrick Kelsey 	IFQ_LOCK(ifq);
4223b8ca4756SPatrick Kelsey 	IFQ_DEQUEUE_NOLOCK(ifq, m);
4224b8ca4756SPatrick Kelsey 	while (m != NULL) {
4225b8ca4756SPatrick Kelsey 		iflib_if_transmit(ifp, m);
4226b8ca4756SPatrick Kelsey 		IFQ_DEQUEUE_NOLOCK(ifq, m);
4227b8ca4756SPatrick Kelsey 	}
4228b8ca4756SPatrick Kelsey 	IFQ_UNLOCK(ifq);
4229b8ca4756SPatrick Kelsey }
4230b8ca4756SPatrick Kelsey 
4231b8ca4756SPatrick Kelsey static int
4232b8ca4756SPatrick Kelsey iflib_altq_if_transmit(if_t ifp, struct mbuf *m)
4233b8ca4756SPatrick Kelsey {
4234b8ca4756SPatrick Kelsey 	int err;
4235b8ca4756SPatrick Kelsey 
4236b8ca4756SPatrick Kelsey 	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
4237b8ca4756SPatrick Kelsey 		IFQ_ENQUEUE(&ifp->if_snd, m, err);
4238b8ca4756SPatrick Kelsey 		if (err == 0)
4239b8ca4756SPatrick Kelsey 			iflib_altq_if_start(ifp);
4240b8ca4756SPatrick Kelsey 	} else
4241b8ca4756SPatrick Kelsey 		err = iflib_if_transmit(ifp, m);
4242b8ca4756SPatrick Kelsey 
4243b8ca4756SPatrick Kelsey 	return (err);
4244b8ca4756SPatrick Kelsey }
4245b8ca4756SPatrick Kelsey #endif /* ALTQ */
4246b8ca4756SPatrick Kelsey 
42474c7070dbSScott Long static void
42484c7070dbSScott Long iflib_if_qflush(if_t ifp)
42494c7070dbSScott Long {
42504c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
42514c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
42524c7070dbSScott Long 	int i;
42534c7070dbSScott Long 
42547b610b60SSean Bruno 	STATE_LOCK(ctx);
42554c7070dbSScott Long 	ctx->ifc_flags |= IFC_QFLUSH;
42567b610b60SSean Bruno 	STATE_UNLOCK(ctx);
42574c7070dbSScott Long 	for (i = 0; i < NTXQSETS(ctx); i++, txq++)
425895246abbSSean Bruno 		while (!(ifmp_ring_is_idle(txq->ift_br) || ifmp_ring_is_stalled(txq->ift_br)))
42594c7070dbSScott Long 			iflib_txq_check_drain(txq, 0);
42607b610b60SSean Bruno 	STATE_LOCK(ctx);
42614c7070dbSScott Long 	ctx->ifc_flags &= ~IFC_QFLUSH;
42627b610b60SSean Bruno 	STATE_UNLOCK(ctx);
42634c7070dbSScott Long 
4264b8ca4756SPatrick Kelsey 	/*
4265b8ca4756SPatrick Kelsey 	 * When ALTQ is enabled, this will also take care of purging the
4266b8ca4756SPatrick Kelsey 	 * ALTQ queue(s).
4267b8ca4756SPatrick Kelsey 	 */
42684c7070dbSScott Long 	if_qflush(ifp);
42694c7070dbSScott Long }
42704c7070dbSScott Long 
42710c919c23SStephen Hurd #define IFCAP_FLAGS (IFCAP_HWCSUM_IPV6 | IFCAP_HWCSUM | IFCAP_LRO | \
42720c919c23SStephen Hurd 		     IFCAP_TSO | IFCAP_VLAN_HWTAGGING | IFCAP_HWSTATS | \
42730c919c23SStephen Hurd 		     IFCAP_VLAN_MTU | IFCAP_VLAN_HWFILTER | \
42743f43ada9SGleb Smirnoff 		     IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM | IFCAP_MEXTPG)
42754c7070dbSScott Long 
42764c7070dbSScott Long static int
42774c7070dbSScott Long iflib_if_ioctl(if_t ifp, u_long command, caddr_t data)
42784c7070dbSScott Long {
42794c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
42804c7070dbSScott Long 	struct ifreq	*ifr = (struct ifreq *)data;
42814c7070dbSScott Long #if defined(INET) || defined(INET6)
42824c7070dbSScott Long 	struct ifaddr	*ifa = (struct ifaddr *)data;
42834c7070dbSScott Long #endif
42841722eeacSMarius Strobl 	bool		avoid_reset = false;
42854c7070dbSScott Long 	int		err = 0, reinit = 0, bits;
42864c7070dbSScott Long 
42874c7070dbSScott Long 	switch (command) {
42884c7070dbSScott Long 	case SIOCSIFADDR:
42894c7070dbSScott Long #ifdef INET
42904c7070dbSScott Long 		if (ifa->ifa_addr->sa_family == AF_INET)
42911722eeacSMarius Strobl 			avoid_reset = true;
42924c7070dbSScott Long #endif
42934c7070dbSScott Long #ifdef INET6
42944c7070dbSScott Long 		if (ifa->ifa_addr->sa_family == AF_INET6)
42951722eeacSMarius Strobl 			avoid_reset = true;
42964c7070dbSScott Long #endif
42974c7070dbSScott Long 		/*
42984c7070dbSScott Long 		** Calling init results in link renegotiation,
42994c7070dbSScott Long 		** so we avoid doing it when possible.
43004c7070dbSScott Long 		*/
43014c7070dbSScott Long 		if (avoid_reset) {
43024c7070dbSScott Long 			if_setflagbits(ifp, IFF_UP,0);
43034c7070dbSScott Long 			if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
43044c7070dbSScott Long 				reinit = 1;
43054c7070dbSScott Long #ifdef INET
43064c7070dbSScott Long 			if (!(if_getflags(ifp) & IFF_NOARP))
43074c7070dbSScott Long 				arp_ifinit(ifp, ifa);
43084c7070dbSScott Long #endif
43094c7070dbSScott Long 		} else
43104c7070dbSScott Long 			err = ether_ioctl(ifp, command, data);
43114c7070dbSScott Long 		break;
43124c7070dbSScott Long 	case SIOCSIFMTU:
43134c7070dbSScott Long 		CTX_LOCK(ctx);
43144c7070dbSScott Long 		if (ifr->ifr_mtu == if_getmtu(ifp)) {
43154c7070dbSScott Long 			CTX_UNLOCK(ctx);
43164c7070dbSScott Long 			break;
43174c7070dbSScott Long 		}
43184c7070dbSScott Long 		bits = if_getdrvflags(ifp);
43194c7070dbSScott Long 		/* stop the driver and free any clusters before proceeding */
43204c7070dbSScott Long 		iflib_stop(ctx);
43214c7070dbSScott Long 
43224c7070dbSScott Long 		if ((err = IFDI_MTU_SET(ctx, ifr->ifr_mtu)) == 0) {
43237b610b60SSean Bruno 			STATE_LOCK(ctx);
43244c7070dbSScott Long 			if (ifr->ifr_mtu > ctx->ifc_max_fl_buf_size)
43254c7070dbSScott Long 				ctx->ifc_flags |= IFC_MULTISEG;
43264c7070dbSScott Long 			else
43274c7070dbSScott Long 				ctx->ifc_flags &= ~IFC_MULTISEG;
43287b610b60SSean Bruno 			STATE_UNLOCK(ctx);
43294c7070dbSScott Long 			err = if_setmtu(ifp, ifr->ifr_mtu);
43304c7070dbSScott Long 		}
43314c7070dbSScott Long 		iflib_init_locked(ctx);
43327b610b60SSean Bruno 		STATE_LOCK(ctx);
43334c7070dbSScott Long 		if_setdrvflags(ifp, bits);
43347b610b60SSean Bruno 		STATE_UNLOCK(ctx);
43354c7070dbSScott Long 		CTX_UNLOCK(ctx);
43364c7070dbSScott Long 		break;
43374c7070dbSScott Long 	case SIOCSIFFLAGS:
4338ab2e3f79SStephen Hurd 		CTX_LOCK(ctx);
4339ab2e3f79SStephen Hurd 		if (if_getflags(ifp) & IFF_UP) {
4340ab2e3f79SStephen Hurd 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4341ab2e3f79SStephen Hurd 				if ((if_getflags(ifp) ^ ctx->ifc_if_flags) &
4342ab2e3f79SStephen Hurd 				    (IFF_PROMISC | IFF_ALLMULTI)) {
43430ae0e8d2SMatt Macy 					CTX_UNLOCK(ctx);
4344ab2e3f79SStephen Hurd 					err = IFDI_PROMISC_SET(ctx, if_getflags(ifp));
43450ae0e8d2SMatt Macy 					CTX_LOCK(ctx);
4346ab2e3f79SStephen Hurd 				}
4347ab2e3f79SStephen Hurd 			} else
4348ab2e3f79SStephen Hurd 				reinit = 1;
4349ab2e3f79SStephen Hurd 		} else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4350ab2e3f79SStephen Hurd 			iflib_stop(ctx);
4351ab2e3f79SStephen Hurd 		}
4352ab2e3f79SStephen Hurd 		ctx->ifc_if_flags = if_getflags(ifp);
4353ab2e3f79SStephen Hurd 		CTX_UNLOCK(ctx);
43544c7070dbSScott Long 		break;
43554c7070dbSScott Long 	case SIOCADDMULTI:
43564c7070dbSScott Long 	case SIOCDELMULTI:
43574c7070dbSScott Long 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4358ab2e3f79SStephen Hurd 			CTX_LOCK(ctx);
4359ab2e3f79SStephen Hurd 			IFDI_INTR_DISABLE(ctx);
4360ab2e3f79SStephen Hurd 			IFDI_MULTI_SET(ctx);
4361ab2e3f79SStephen Hurd 			IFDI_INTR_ENABLE(ctx);
4362ab2e3f79SStephen Hurd 			CTX_UNLOCK(ctx);
43634c7070dbSScott Long 		}
43644c7070dbSScott Long 		break;
43654c7070dbSScott Long 	case SIOCSIFMEDIA:
43664c7070dbSScott Long 		CTX_LOCK(ctx);
43674c7070dbSScott Long 		IFDI_MEDIA_SET(ctx);
43684c7070dbSScott Long 		CTX_UNLOCK(ctx);
43691722eeacSMarius Strobl 		/* FALLTHROUGH */
43704c7070dbSScott Long 	case SIOCGIFMEDIA:
4371a027c8e9SStephen Hurd 	case SIOCGIFXMEDIA:
4372e2621d96SMatt Macy 		err = ifmedia_ioctl(ifp, ifr, ctx->ifc_mediap, command);
43734c7070dbSScott Long 		break;
43744c7070dbSScott Long 	case SIOCGI2C:
43754c7070dbSScott Long 	{
43764c7070dbSScott Long 		struct ifi2creq i2c;
43774c7070dbSScott Long 
4378541d96aaSBrooks Davis 		err = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c));
43794c7070dbSScott Long 		if (err != 0)
43804c7070dbSScott Long 			break;
43814c7070dbSScott Long 		if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) {
43824c7070dbSScott Long 			err = EINVAL;
43834c7070dbSScott Long 			break;
43844c7070dbSScott Long 		}
43854c7070dbSScott Long 		if (i2c.len > sizeof(i2c.data)) {
43864c7070dbSScott Long 			err = EINVAL;
43874c7070dbSScott Long 			break;
43884c7070dbSScott Long 		}
43894c7070dbSScott Long 
43904c7070dbSScott Long 		if ((err = IFDI_I2C_REQ(ctx, &i2c)) == 0)
4391541d96aaSBrooks Davis 			err = copyout(&i2c, ifr_data_get_ptr(ifr),
4392541d96aaSBrooks Davis 			    sizeof(i2c));
43934c7070dbSScott Long 		break;
43944c7070dbSScott Long 	}
43954c7070dbSScott Long 	case SIOCSIFCAP:
43964c7070dbSScott Long 	{
43970c919c23SStephen Hurd 		int mask, setmask, oldmask;
43984c7070dbSScott Long 
43990c919c23SStephen Hurd 		oldmask = if_getcapenable(ifp);
44000c919c23SStephen Hurd 		mask = ifr->ifr_reqcap ^ oldmask;
44013f43ada9SGleb Smirnoff 		mask &= ctx->ifc_softc_ctx.isc_capabilities | IFCAP_MEXTPG;
44024c7070dbSScott Long 		setmask = 0;
44034c7070dbSScott Long #ifdef TCP_OFFLOAD
44044c7070dbSScott Long 		setmask |= mask & (IFCAP_TOE4|IFCAP_TOE6);
44054c7070dbSScott Long #endif
44064c7070dbSScott Long 		setmask |= (mask & IFCAP_FLAGS);
44070c919c23SStephen Hurd 		setmask |= (mask & IFCAP_WOL);
44084c7070dbSScott Long 
44090c919c23SStephen Hurd 		/*
4410a42546dfSStephen Hurd 		 * If any RX csum has changed, change all the ones that
4411a42546dfSStephen Hurd 		 * are supported by the driver.
44120c919c23SStephen Hurd 		 */
4413a42546dfSStephen Hurd 		if (setmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) {
4414a42546dfSStephen Hurd 			setmask |= ctx->ifc_softc_ctx.isc_capabilities &
4415a42546dfSStephen Hurd 			    (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6);
4416a42546dfSStephen Hurd 		}
44170c919c23SStephen Hurd 
44184c7070dbSScott Long 		/*
44194c7070dbSScott Long 		 * want to ensure that traffic has stopped before we change any of the flags
44204c7070dbSScott Long 		 */
44214c7070dbSScott Long 		if (setmask) {
44224c7070dbSScott Long 			CTX_LOCK(ctx);
44234c7070dbSScott Long 			bits = if_getdrvflags(ifp);
44240c919c23SStephen Hurd 			if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL)
44254c7070dbSScott Long 				iflib_stop(ctx);
44267b610b60SSean Bruno 			STATE_LOCK(ctx);
44274c7070dbSScott Long 			if_togglecapenable(ifp, setmask);
44287b610b60SSean Bruno 			STATE_UNLOCK(ctx);
44290c919c23SStephen Hurd 			if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL)
44304c7070dbSScott Long 				iflib_init_locked(ctx);
44317b610b60SSean Bruno 			STATE_LOCK(ctx);
44324c7070dbSScott Long 			if_setdrvflags(ifp, bits);
44337b610b60SSean Bruno 			STATE_UNLOCK(ctx);
44344c7070dbSScott Long 			CTX_UNLOCK(ctx);
44354c7070dbSScott Long 		}
44360c919c23SStephen Hurd 		if_vlancap(ifp);
44374c7070dbSScott Long 		break;
44384c7070dbSScott Long 	}
44394c7070dbSScott Long 	case SIOCGPRIVATE_0:
44404c7070dbSScott Long 	case SIOCSDRVSPEC:
44414c7070dbSScott Long 	case SIOCGDRVSPEC:
44424c7070dbSScott Long 		CTX_LOCK(ctx);
44434c7070dbSScott Long 		err = IFDI_PRIV_IOCTL(ctx, command, data);
44444c7070dbSScott Long 		CTX_UNLOCK(ctx);
44454c7070dbSScott Long 		break;
44464c7070dbSScott Long 	default:
44474c7070dbSScott Long 		err = ether_ioctl(ifp, command, data);
44484c7070dbSScott Long 		break;
44494c7070dbSScott Long 	}
44504c7070dbSScott Long 	if (reinit)
44514c7070dbSScott Long 		iflib_if_init(ctx);
44524c7070dbSScott Long 	return (err);
44534c7070dbSScott Long }
44544c7070dbSScott Long 
44554c7070dbSScott Long static uint64_t
44564c7070dbSScott Long iflib_if_get_counter(if_t ifp, ift_counter cnt)
44574c7070dbSScott Long {
44584c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
44594c7070dbSScott Long 
44604c7070dbSScott Long 	return (IFDI_GET_COUNTER(ctx, cnt));
44614c7070dbSScott Long }
44624c7070dbSScott Long 
44634c7070dbSScott Long /*********************************************************************
44644c7070dbSScott Long  *
44654c7070dbSScott Long  *  OTHER FUNCTIONS EXPORTED TO THE STACK
44664c7070dbSScott Long  *
44674c7070dbSScott Long  **********************************************************************/
44684c7070dbSScott Long 
44694c7070dbSScott Long static void
44704c7070dbSScott Long iflib_vlan_register(void *arg, if_t ifp, uint16_t vtag)
44714c7070dbSScott Long {
44724c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
44734c7070dbSScott Long 
44744c7070dbSScott Long 	if ((void *)ctx != arg)
44754c7070dbSScott Long 		return;
44764c7070dbSScott Long 
44774c7070dbSScott Long 	if ((vtag == 0) || (vtag > 4095))
44784c7070dbSScott Long 		return;
44794c7070dbSScott Long 
448053b5b9b0SEric Joyner 	if (iflib_in_detach(ctx))
448153b5b9b0SEric Joyner 		return;
448253b5b9b0SEric Joyner 
44834c7070dbSScott Long 	CTX_LOCK(ctx);
448445818bf1SEric Joyner 	/* Driver may need all untagged packets to be flushed */
448545818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
448645818bf1SEric Joyner 		iflib_stop(ctx);
44874c7070dbSScott Long 	IFDI_VLAN_REGISTER(ctx, vtag);
448845818bf1SEric Joyner 	/* Re-init to load the changes, if required */
448945818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
449045818bf1SEric Joyner 		iflib_init_locked(ctx);
44914c7070dbSScott Long 	CTX_UNLOCK(ctx);
44924c7070dbSScott Long }
44934c7070dbSScott Long 
44944c7070dbSScott Long static void
44954c7070dbSScott Long iflib_vlan_unregister(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 
45054c7070dbSScott Long 	CTX_LOCK(ctx);
450645818bf1SEric Joyner 	/* Driver may need all tagged packets to be flushed */
450745818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
450845818bf1SEric Joyner 		iflib_stop(ctx);
45094c7070dbSScott Long 	IFDI_VLAN_UNREGISTER(ctx, vtag);
451045818bf1SEric Joyner 	/* Re-init to load the changes, if required */
451145818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
451245818bf1SEric Joyner 		iflib_init_locked(ctx);
45134c7070dbSScott Long 	CTX_UNLOCK(ctx);
45144c7070dbSScott Long }
45154c7070dbSScott Long 
45164c7070dbSScott Long static void
45174c7070dbSScott Long iflib_led_func(void *arg, int onoff)
45184c7070dbSScott Long {
45194c7070dbSScott Long 	if_ctx_t ctx = arg;
45204c7070dbSScott Long 
45214c7070dbSScott Long 	CTX_LOCK(ctx);
45224c7070dbSScott Long 	IFDI_LED_FUNC(ctx, onoff);
45234c7070dbSScott Long 	CTX_UNLOCK(ctx);
45244c7070dbSScott Long }
45254c7070dbSScott Long 
45264c7070dbSScott Long /*********************************************************************
45274c7070dbSScott Long  *
45284c7070dbSScott Long  *  BUS FUNCTION DEFINITIONS
45294c7070dbSScott Long  *
45304c7070dbSScott Long  **********************************************************************/
45314c7070dbSScott Long 
45324c7070dbSScott Long int
45334c7070dbSScott Long iflib_device_probe(device_t dev)
45344c7070dbSScott Long {
4535d49e83eaSMarius Strobl 	const pci_vendor_info_t *ent;
45364c7070dbSScott Long 	if_shared_ctx_t sctx;
4537d49e83eaSMarius Strobl 	uint16_t pci_device_id, pci_rev_id, pci_subdevice_id, pci_subvendor_id;
4538d49e83eaSMarius Strobl 	uint16_t pci_vendor_id;
45394c7070dbSScott Long 
45404c7070dbSScott Long 	if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC)
45414c7070dbSScott Long 		return (ENOTSUP);
45424c7070dbSScott Long 
45434c7070dbSScott Long 	pci_vendor_id = pci_get_vendor(dev);
45444c7070dbSScott Long 	pci_device_id = pci_get_device(dev);
45454c7070dbSScott Long 	pci_subvendor_id = pci_get_subvendor(dev);
45464c7070dbSScott Long 	pci_subdevice_id = pci_get_subdevice(dev);
45474c7070dbSScott Long 	pci_rev_id = pci_get_revid(dev);
45484c7070dbSScott Long 	if (sctx->isc_parse_devinfo != NULL)
45494c7070dbSScott Long 		sctx->isc_parse_devinfo(&pci_device_id, &pci_subvendor_id, &pci_subdevice_id, &pci_rev_id);
45504c7070dbSScott Long 
45514c7070dbSScott Long 	ent = sctx->isc_vendor_info;
45524c7070dbSScott Long 	while (ent->pvi_vendor_id != 0) {
45534c7070dbSScott Long 		if (pci_vendor_id != ent->pvi_vendor_id) {
45544c7070dbSScott Long 			ent++;
45554c7070dbSScott Long 			continue;
45564c7070dbSScott Long 		}
45574c7070dbSScott Long 		if ((pci_device_id == ent->pvi_device_id) &&
45584c7070dbSScott Long 		    ((pci_subvendor_id == ent->pvi_subvendor_id) ||
45594c7070dbSScott Long 		     (ent->pvi_subvendor_id == 0)) &&
45604c7070dbSScott Long 		    ((pci_subdevice_id == ent->pvi_subdevice_id) ||
45614c7070dbSScott Long 		     (ent->pvi_subdevice_id == 0)) &&
45624c7070dbSScott Long 		    ((pci_rev_id == ent->pvi_rev_id) ||
45634c7070dbSScott Long 		     (ent->pvi_rev_id == 0))) {
45644c7070dbSScott Long 			device_set_desc_copy(dev, ent->pvi_name);
45654c7070dbSScott Long 			/* this needs to be changed to zero if the bus probing code
45664c7070dbSScott Long 			 * ever stops re-probing on best match because the sctx
45674c7070dbSScott Long 			 * may have its values over written by register calls
45684c7070dbSScott Long 			 * in subsequent probes
45694c7070dbSScott Long 			 */
45704c7070dbSScott Long 			return (BUS_PROBE_DEFAULT);
45714c7070dbSScott Long 		}
45724c7070dbSScott Long 		ent++;
45734c7070dbSScott Long 	}
45744c7070dbSScott Long 	return (ENXIO);
45754c7070dbSScott Long }
45764c7070dbSScott Long 
4577668d6dbbSEric Joyner int
4578668d6dbbSEric Joyner iflib_device_probe_vendor(device_t dev)
4579668d6dbbSEric Joyner {
4580668d6dbbSEric Joyner 	int probe;
4581668d6dbbSEric Joyner 
4582668d6dbbSEric Joyner 	probe = iflib_device_probe(dev);
4583668d6dbbSEric Joyner 	if (probe == BUS_PROBE_DEFAULT)
4584668d6dbbSEric Joyner 		return (BUS_PROBE_VENDOR);
4585668d6dbbSEric Joyner 	else
4586668d6dbbSEric Joyner 		return (probe);
4587668d6dbbSEric Joyner }
4588668d6dbbSEric Joyner 
458909f6ff4fSMatt Macy static void
459009f6ff4fSMatt Macy iflib_reset_qvalues(if_ctx_t ctx)
45914c7070dbSScott Long {
459209f6ff4fSMatt Macy 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
459309f6ff4fSMatt Macy 	if_shared_ctx_t sctx = ctx->ifc_sctx;
459409f6ff4fSMatt Macy 	device_t dev = ctx->ifc_dev;
459546d0f824SMatt Macy 	int i;
45964c7070dbSScott Long 
459723ac9029SStephen Hurd 	if (ctx->ifc_sysctl_ntxqs != 0)
459823ac9029SStephen Hurd 		scctx->isc_ntxqsets = ctx->ifc_sysctl_ntxqs;
459923ac9029SStephen Hurd 	if (ctx->ifc_sysctl_nrxqs != 0)
460023ac9029SStephen Hurd 		scctx->isc_nrxqsets = ctx->ifc_sysctl_nrxqs;
460123ac9029SStephen Hurd 
460223ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_ntxqs; i++) {
460323ac9029SStephen Hurd 		if (ctx->ifc_sysctl_ntxds[i] != 0)
460423ac9029SStephen Hurd 			scctx->isc_ntxd[i] = ctx->ifc_sysctl_ntxds[i];
460523ac9029SStephen Hurd 		else
460623ac9029SStephen Hurd 			scctx->isc_ntxd[i] = sctx->isc_ntxd_default[i];
460723ac9029SStephen Hurd 	}
460823ac9029SStephen Hurd 
460923ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_nrxqs; i++) {
461023ac9029SStephen Hurd 		if (ctx->ifc_sysctl_nrxds[i] != 0)
461123ac9029SStephen Hurd 			scctx->isc_nrxd[i] = ctx->ifc_sysctl_nrxds[i];
461223ac9029SStephen Hurd 		else
461323ac9029SStephen Hurd 			scctx->isc_nrxd[i] = sctx->isc_nrxd_default[i];
461423ac9029SStephen Hurd 	}
461523ac9029SStephen Hurd 
461623ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_nrxqs; i++) {
461723ac9029SStephen Hurd 		if (scctx->isc_nrxd[i] < sctx->isc_nrxd_min[i]) {
461823ac9029SStephen Hurd 			device_printf(dev, "nrxd%d: %d less than nrxd_min %d - resetting to min\n",
461923ac9029SStephen Hurd 				      i, scctx->isc_nrxd[i], sctx->isc_nrxd_min[i]);
462023ac9029SStephen Hurd 			scctx->isc_nrxd[i] = sctx->isc_nrxd_min[i];
462123ac9029SStephen Hurd 		}
462223ac9029SStephen Hurd 		if (scctx->isc_nrxd[i] > sctx->isc_nrxd_max[i]) {
462323ac9029SStephen Hurd 			device_printf(dev, "nrxd%d: %d greater than nrxd_max %d - resetting to max\n",
462423ac9029SStephen Hurd 				      i, scctx->isc_nrxd[i], sctx->isc_nrxd_max[i]);
462523ac9029SStephen Hurd 			scctx->isc_nrxd[i] = sctx->isc_nrxd_max[i];
462623ac9029SStephen Hurd 		}
4627afb77372SEric Joyner 		if (!powerof2(scctx->isc_nrxd[i])) {
4628afb77372SEric Joyner 			device_printf(dev, "nrxd%d: %d is not a power of 2 - using default value of %d\n",
4629afb77372SEric Joyner 				      i, scctx->isc_nrxd[i], sctx->isc_nrxd_default[i]);
4630afb77372SEric Joyner 			scctx->isc_nrxd[i] = sctx->isc_nrxd_default[i];
4631afb77372SEric Joyner 		}
463223ac9029SStephen Hurd 	}
463323ac9029SStephen Hurd 
463423ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_ntxqs; i++) {
463523ac9029SStephen Hurd 		if (scctx->isc_ntxd[i] < sctx->isc_ntxd_min[i]) {
463623ac9029SStephen Hurd 			device_printf(dev, "ntxd%d: %d less than ntxd_min %d - resetting to min\n",
463723ac9029SStephen Hurd 				      i, scctx->isc_ntxd[i], sctx->isc_ntxd_min[i]);
463823ac9029SStephen Hurd 			scctx->isc_ntxd[i] = sctx->isc_ntxd_min[i];
463923ac9029SStephen Hurd 		}
464023ac9029SStephen Hurd 		if (scctx->isc_ntxd[i] > sctx->isc_ntxd_max[i]) {
464123ac9029SStephen Hurd 			device_printf(dev, "ntxd%d: %d greater than ntxd_max %d - resetting to max\n",
464223ac9029SStephen Hurd 				      i, scctx->isc_ntxd[i], sctx->isc_ntxd_max[i]);
464323ac9029SStephen Hurd 			scctx->isc_ntxd[i] = sctx->isc_ntxd_max[i];
464423ac9029SStephen Hurd 		}
4645afb77372SEric Joyner 		if (!powerof2(scctx->isc_ntxd[i])) {
4646afb77372SEric Joyner 			device_printf(dev, "ntxd%d: %d is not a power of 2 - using default value of %d\n",
4647afb77372SEric Joyner 				      i, scctx->isc_ntxd[i], sctx->isc_ntxd_default[i]);
4648afb77372SEric Joyner 			scctx->isc_ntxd[i] = sctx->isc_ntxd_default[i];
4649afb77372SEric Joyner 		}
465023ac9029SStephen Hurd 	}
465109f6ff4fSMatt Macy }
4652ab2e3f79SStephen Hurd 
46536d49b41eSAndrew Gallatin static void
46546d49b41eSAndrew Gallatin iflib_add_pfil(if_ctx_t ctx)
46556d49b41eSAndrew Gallatin {
46566d49b41eSAndrew Gallatin 	struct pfil_head *pfil;
46576d49b41eSAndrew Gallatin 	struct pfil_head_args pa;
46586d49b41eSAndrew Gallatin 	iflib_rxq_t rxq;
46596d49b41eSAndrew Gallatin 	int i;
46606d49b41eSAndrew Gallatin 
46616d49b41eSAndrew Gallatin 	pa.pa_version = PFIL_VERSION;
46626d49b41eSAndrew Gallatin 	pa.pa_flags = PFIL_IN;
46636d49b41eSAndrew Gallatin 	pa.pa_type = PFIL_TYPE_ETHERNET;
46646d49b41eSAndrew Gallatin 	pa.pa_headname = ctx->ifc_ifp->if_xname;
46656d49b41eSAndrew Gallatin 	pfil = pfil_head_register(&pa);
46666d49b41eSAndrew Gallatin 
46676d49b41eSAndrew Gallatin 	for (i = 0, rxq = ctx->ifc_rxqs; i < NRXQSETS(ctx); i++, rxq++) {
46686d49b41eSAndrew Gallatin 		rxq->pfil = pfil;
46696d49b41eSAndrew Gallatin 	}
46706d49b41eSAndrew Gallatin }
46716d49b41eSAndrew Gallatin 
46726d49b41eSAndrew Gallatin static void
46736d49b41eSAndrew Gallatin iflib_rem_pfil(if_ctx_t ctx)
46746d49b41eSAndrew Gallatin {
46756d49b41eSAndrew Gallatin 	struct pfil_head *pfil;
46766d49b41eSAndrew Gallatin 	iflib_rxq_t rxq;
46776d49b41eSAndrew Gallatin 	int i;
46786d49b41eSAndrew Gallatin 
46796d49b41eSAndrew Gallatin 	rxq = ctx->ifc_rxqs;
46806d49b41eSAndrew Gallatin 	pfil = rxq->pfil;
46816d49b41eSAndrew Gallatin 	for (i = 0; i < NRXQSETS(ctx); i++, rxq++) {
46826d49b41eSAndrew Gallatin 		rxq->pfil = NULL;
46836d49b41eSAndrew Gallatin 	}
46846d49b41eSAndrew Gallatin 	pfil_head_unregister(pfil);
46856d49b41eSAndrew Gallatin }
46866d49b41eSAndrew Gallatin 
4687*ca7005f1SPatrick Kelsey 
4688*ca7005f1SPatrick Kelsey /*
4689*ca7005f1SPatrick Kelsey  * Advance forward by n members of the cpuset ctx->ifc_cpus starting from
4690*ca7005f1SPatrick Kelsey  * cpuid and wrapping as necessary.
4691*ca7005f1SPatrick Kelsey  */
4692*ca7005f1SPatrick Kelsey static unsigned int
4693*ca7005f1SPatrick Kelsey cpuid_advance(if_ctx_t ctx, unsigned int cpuid, unsigned int n)
4694*ca7005f1SPatrick Kelsey {
4695*ca7005f1SPatrick Kelsey 	unsigned int first_valid;
4696*ca7005f1SPatrick Kelsey 	unsigned int last_valid;
4697*ca7005f1SPatrick Kelsey 
4698*ca7005f1SPatrick Kelsey 	/* cpuid should always be in the valid set */
4699*ca7005f1SPatrick Kelsey 	MPASS(CPU_ISSET(cpuid, &ctx->ifc_cpus));
4700*ca7005f1SPatrick Kelsey 
4701*ca7005f1SPatrick Kelsey 	/* valid set should never be empty */
4702*ca7005f1SPatrick Kelsey 	MPASS(!CPU_EMPTY(&ctx->ifc_cpus));
4703*ca7005f1SPatrick Kelsey 
4704*ca7005f1SPatrick Kelsey 	first_valid = CPU_FFS(&ctx->ifc_cpus) - 1;
4705*ca7005f1SPatrick Kelsey 	last_valid = CPU_FLS(&ctx->ifc_cpus) - 1;
4706*ca7005f1SPatrick Kelsey 	n = n % CPU_COUNT(&ctx->ifc_cpus);
4707*ca7005f1SPatrick Kelsey 	while (n > 0) {
4708*ca7005f1SPatrick Kelsey 		do {
4709*ca7005f1SPatrick Kelsey 			cpuid++;
4710*ca7005f1SPatrick Kelsey 			if (cpuid > last_valid)
4711*ca7005f1SPatrick Kelsey 				cpuid = first_valid;
4712*ca7005f1SPatrick Kelsey 		} while (!CPU_ISSET(cpuid, &ctx->ifc_cpus));
4713*ca7005f1SPatrick Kelsey 		n--;
4714*ca7005f1SPatrick Kelsey 	}
4715*ca7005f1SPatrick Kelsey 
4716*ca7005f1SPatrick Kelsey 	return (cpuid);
4717*ca7005f1SPatrick Kelsey }
4718*ca7005f1SPatrick Kelsey 
4719*ca7005f1SPatrick Kelsey #if defined(SMP) && defined(SCHED_ULE)
4720*ca7005f1SPatrick Kelsey extern struct cpu_group *cpu_top;              /* CPU topology */
4721*ca7005f1SPatrick Kelsey 
4722*ca7005f1SPatrick Kelsey static int
4723*ca7005f1SPatrick Kelsey find_child_with_core(int cpu, struct cpu_group *grp)
4724*ca7005f1SPatrick Kelsey {
4725*ca7005f1SPatrick Kelsey 	int i;
4726*ca7005f1SPatrick Kelsey 
4727*ca7005f1SPatrick Kelsey 	if (grp->cg_children == 0)
4728*ca7005f1SPatrick Kelsey 		return -1;
4729*ca7005f1SPatrick Kelsey 
4730*ca7005f1SPatrick Kelsey 	MPASS(grp->cg_child);
4731*ca7005f1SPatrick Kelsey 	for (i = 0; i < grp->cg_children; i++) {
4732*ca7005f1SPatrick Kelsey 		if (CPU_ISSET(cpu, &grp->cg_child[i].cg_mask))
4733*ca7005f1SPatrick Kelsey 			return i;
4734*ca7005f1SPatrick Kelsey 	}
4735*ca7005f1SPatrick Kelsey 
4736*ca7005f1SPatrick Kelsey 	return -1;
4737*ca7005f1SPatrick Kelsey }
4738*ca7005f1SPatrick Kelsey 
4739*ca7005f1SPatrick Kelsey 
4740*ca7005f1SPatrick Kelsey /*
4741*ca7005f1SPatrick Kelsey  * Find an L2 neighbor of the given CPU or return -1 if none found.  This
4742*ca7005f1SPatrick Kelsey  * does not distinguish among multiple L2 neighbors if the given CPU has
4743*ca7005f1SPatrick Kelsey  * more than one (it will always return the same result in that case).
4744*ca7005f1SPatrick Kelsey  */
4745*ca7005f1SPatrick Kelsey static int
4746*ca7005f1SPatrick Kelsey find_l2_neighbor(int cpu)
4747*ca7005f1SPatrick Kelsey {
4748*ca7005f1SPatrick Kelsey 	struct cpu_group *grp;
4749*ca7005f1SPatrick Kelsey 	int i;
4750*ca7005f1SPatrick Kelsey 
4751*ca7005f1SPatrick Kelsey 	grp = cpu_top;
4752*ca7005f1SPatrick Kelsey 	if (grp == NULL)
4753*ca7005f1SPatrick Kelsey 		return -1;
4754*ca7005f1SPatrick Kelsey 
4755*ca7005f1SPatrick Kelsey 	/*
4756*ca7005f1SPatrick Kelsey 	 * Find the smallest CPU group that contains the given core.
4757*ca7005f1SPatrick Kelsey 	 */
4758*ca7005f1SPatrick Kelsey 	i = 0;
4759*ca7005f1SPatrick Kelsey 	while ((i = find_child_with_core(cpu, grp)) != -1) {
4760*ca7005f1SPatrick Kelsey 		/*
4761*ca7005f1SPatrick Kelsey 		 * If the smallest group containing the given CPU has less
4762*ca7005f1SPatrick Kelsey 		 * than two members, we conclude the given CPU has no
4763*ca7005f1SPatrick Kelsey 		 * L2 neighbor.
4764*ca7005f1SPatrick Kelsey 		 */
4765*ca7005f1SPatrick Kelsey 		if (grp->cg_child[i].cg_count <= 1)
4766*ca7005f1SPatrick Kelsey 			return (-1);
4767*ca7005f1SPatrick Kelsey 		grp = &grp->cg_child[i];
4768*ca7005f1SPatrick Kelsey 	}
4769*ca7005f1SPatrick Kelsey 
4770*ca7005f1SPatrick Kelsey 	/* Must share L2. */
4771*ca7005f1SPatrick Kelsey 	if (grp->cg_level > CG_SHARE_L2 || grp->cg_level == CG_SHARE_NONE)
4772*ca7005f1SPatrick Kelsey 		return -1;
4773*ca7005f1SPatrick Kelsey 
4774*ca7005f1SPatrick Kelsey 	/*
4775*ca7005f1SPatrick Kelsey 	 * Select the first member of the set that isn't the reference
4776*ca7005f1SPatrick Kelsey 	 * CPU, which at this point is guaranteed to exist.
4777*ca7005f1SPatrick Kelsey 	 */
4778*ca7005f1SPatrick Kelsey 	for (i = 0; i < CPU_SETSIZE; i++) {
4779*ca7005f1SPatrick Kelsey 		if (CPU_ISSET(i, &grp->cg_mask) && i != cpu)
4780*ca7005f1SPatrick Kelsey 			return (i);
4781*ca7005f1SPatrick Kelsey 	}
4782*ca7005f1SPatrick Kelsey 
4783*ca7005f1SPatrick Kelsey 	/* Should never be reached */
4784*ca7005f1SPatrick Kelsey 	return (-1);
4785*ca7005f1SPatrick Kelsey }
4786*ca7005f1SPatrick Kelsey 
4787*ca7005f1SPatrick Kelsey #else
4788*ca7005f1SPatrick Kelsey static int
4789*ca7005f1SPatrick Kelsey find_l2_neighbor(int cpu)
4790*ca7005f1SPatrick Kelsey {
4791*ca7005f1SPatrick Kelsey 
4792*ca7005f1SPatrick Kelsey 	return (-1);
4793*ca7005f1SPatrick Kelsey }
4794*ca7005f1SPatrick Kelsey #endif
4795*ca7005f1SPatrick Kelsey 
4796*ca7005f1SPatrick Kelsey /*
4797*ca7005f1SPatrick Kelsey  * CPU mapping behaviors
4798*ca7005f1SPatrick Kelsey  * ---------------------
4799*ca7005f1SPatrick Kelsey  * 'separate txrx' refers to the separate_txrx sysctl
4800*ca7005f1SPatrick Kelsey  * 'use logical' refers to the use_logical_cores sysctl
4801*ca7005f1SPatrick Kelsey  * 'INTR CPUS' indicates whether bus_get_cpus(INTR_CPUS) succeeded
4802*ca7005f1SPatrick Kelsey  *
4803*ca7005f1SPatrick Kelsey  *  separate     use     INTR
4804*ca7005f1SPatrick Kelsey  *    txrx     logical   CPUS   result
4805*ca7005f1SPatrick Kelsey  * ---------- --------- ------ ------------------------------------------------
4806*ca7005f1SPatrick Kelsey  *     -          -       X     RX and TX queues mapped to consecutive physical
4807*ca7005f1SPatrick Kelsey  *                              cores with RX/TX pairs on same core and excess
4808*ca7005f1SPatrick Kelsey  *                              of either following
4809*ca7005f1SPatrick Kelsey  *     -          X       X     RX and TX queues mapped to consecutive cores
4810*ca7005f1SPatrick Kelsey  *                              of any type with RX/TX pairs on same core and
4811*ca7005f1SPatrick Kelsey  *                              excess of either following
4812*ca7005f1SPatrick Kelsey  *     X          -       X     RX and TX queues mapped to consecutive physical
4813*ca7005f1SPatrick Kelsey  *                              cores; all RX then all TX
4814*ca7005f1SPatrick Kelsey  *     X          X       X     RX queues mapped to consecutive physical cores
4815*ca7005f1SPatrick Kelsey  *                              first, then TX queues mapped to L2 neighbor of
4816*ca7005f1SPatrick Kelsey  *                              the corresponding RX queue if one exists,
4817*ca7005f1SPatrick Kelsey  *                              otherwise to consecutive physical cores
4818*ca7005f1SPatrick Kelsey  *     -         n/a      -     RX and TX queues mapped to consecutive cores of
4819*ca7005f1SPatrick Kelsey  *                              any type with RX/TX pairs on same core and excess
4820*ca7005f1SPatrick Kelsey  *                              of either following
4821*ca7005f1SPatrick Kelsey  *     X         n/a      -     RX and TX queues mapped to consecutive cores of
4822*ca7005f1SPatrick Kelsey  *                              any type; all RX then all TX
4823*ca7005f1SPatrick Kelsey  */
4824*ca7005f1SPatrick Kelsey static unsigned int
4825*ca7005f1SPatrick Kelsey get_cpuid_for_queue(if_ctx_t ctx, unsigned int base_cpuid, unsigned int qid,
4826*ca7005f1SPatrick Kelsey     bool is_tx)
4827*ca7005f1SPatrick Kelsey {
4828*ca7005f1SPatrick Kelsey 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
4829*ca7005f1SPatrick Kelsey 	unsigned int core_index;
4830*ca7005f1SPatrick Kelsey 
4831*ca7005f1SPatrick Kelsey 	if (ctx->ifc_sysctl_separate_txrx) {
4832*ca7005f1SPatrick Kelsey 		/*
4833*ca7005f1SPatrick Kelsey 		 * When using separate CPUs for TX and RX, the assignment
4834*ca7005f1SPatrick Kelsey 		 * will always be of a consecutive CPU out of the set of
4835*ca7005f1SPatrick Kelsey 		 * context CPUs, except for the specific case where the
4836*ca7005f1SPatrick Kelsey 		 * context CPUs are phsyical cores, the use of logical cores
4837*ca7005f1SPatrick Kelsey 		 * has been enabled, the assignment is for TX, the TX qid
4838*ca7005f1SPatrick Kelsey 		 * corresponds to an RX qid, and the CPU assigned to the
4839*ca7005f1SPatrick Kelsey 		 * corresponding RX queue has an L2 neighbor.
4840*ca7005f1SPatrick Kelsey 		 */
4841*ca7005f1SPatrick Kelsey 		if (ctx->ifc_sysctl_use_logical_cores &&
4842*ca7005f1SPatrick Kelsey 		    ctx->ifc_cpus_are_physical_cores &&
4843*ca7005f1SPatrick Kelsey 		    is_tx && qid < scctx->isc_nrxqsets) {
4844*ca7005f1SPatrick Kelsey 			int l2_neighbor;
4845*ca7005f1SPatrick Kelsey 			unsigned int rx_cpuid;
4846*ca7005f1SPatrick Kelsey 
4847*ca7005f1SPatrick Kelsey 			rx_cpuid = cpuid_advance(ctx, base_cpuid, qid);
4848*ca7005f1SPatrick Kelsey 			l2_neighbor = find_l2_neighbor(rx_cpuid);
4849*ca7005f1SPatrick Kelsey 			if (l2_neighbor != -1) {
4850*ca7005f1SPatrick Kelsey 				return (l2_neighbor);
4851*ca7005f1SPatrick Kelsey 			}
4852*ca7005f1SPatrick Kelsey 			/*
4853*ca7005f1SPatrick Kelsey 			 * ... else fall through to the normal
4854*ca7005f1SPatrick Kelsey 			 * consecutive-after-RX assignment scheme.
4855*ca7005f1SPatrick Kelsey 			 *
4856*ca7005f1SPatrick Kelsey 			 * Note that we are assuming that all RX queue CPUs
4857*ca7005f1SPatrick Kelsey 			 * have an L2 neighbor, or all do not.  If a mixed
4858*ca7005f1SPatrick Kelsey 			 * scenario is possible, we will have to keep track
4859*ca7005f1SPatrick Kelsey 			 * separately of how many queues prior to this one
4860*ca7005f1SPatrick Kelsey 			 * were not able to be assigned to an L2 neighbor.
4861*ca7005f1SPatrick Kelsey 			 */
4862*ca7005f1SPatrick Kelsey 		}
4863*ca7005f1SPatrick Kelsey 		if (is_tx)
4864*ca7005f1SPatrick Kelsey 			core_index = scctx->isc_nrxqsets + qid;
4865*ca7005f1SPatrick Kelsey 		else
4866*ca7005f1SPatrick Kelsey 			core_index = qid;
4867*ca7005f1SPatrick Kelsey 	} else {
4868*ca7005f1SPatrick Kelsey 		core_index = qid;
4869*ca7005f1SPatrick Kelsey 	}
4870*ca7005f1SPatrick Kelsey 
4871*ca7005f1SPatrick Kelsey 	return (cpuid_advance(ctx, base_cpuid, core_index));
4872*ca7005f1SPatrick Kelsey }
4873*ca7005f1SPatrick Kelsey 
4874f154ece0SStephen Hurd static uint16_t
4875f154ece0SStephen Hurd get_ctx_core_offset(if_ctx_t ctx)
4876f154ece0SStephen Hurd {
4877f154ece0SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
4878f154ece0SStephen Hurd 	struct cpu_offset *op;
4879*ca7005f1SPatrick Kelsey 	cpuset_t assigned_cpus;
4880*ca7005f1SPatrick Kelsey 	unsigned int cores_consumed;
4881*ca7005f1SPatrick Kelsey 	unsigned int base_cpuid = ctx->ifc_sysctl_core_offset;
4882*ca7005f1SPatrick Kelsey 	unsigned int first_valid;
4883*ca7005f1SPatrick Kelsey 	unsigned int last_valid;
4884*ca7005f1SPatrick Kelsey 	unsigned int i;
4885f154ece0SStephen Hurd 
4886*ca7005f1SPatrick Kelsey 	first_valid = CPU_FFS(&ctx->ifc_cpus) - 1;
4887*ca7005f1SPatrick Kelsey 	last_valid = CPU_FLS(&ctx->ifc_cpus) - 1;
4888f154ece0SStephen Hurd 
4889*ca7005f1SPatrick Kelsey 	if (base_cpuid != CORE_OFFSET_UNSPECIFIED) {
4890*ca7005f1SPatrick Kelsey 		/*
4891*ca7005f1SPatrick Kelsey 		 * Align the user-chosen base CPU ID to the next valid CPU
4892*ca7005f1SPatrick Kelsey 		 * for this device.  If the chosen base CPU ID is smaller
4893*ca7005f1SPatrick Kelsey 		 * than the first valid CPU or larger than the last valid
4894*ca7005f1SPatrick Kelsey 		 * CPU, we assume the user does not know what the valid
4895*ca7005f1SPatrick Kelsey 		 * range is for this device and is thinking in terms of a
4896*ca7005f1SPatrick Kelsey 		 * zero-based reference frame, and so we shift the given
4897*ca7005f1SPatrick Kelsey 		 * value into the valid range (and wrap accordingly) so the
4898*ca7005f1SPatrick Kelsey 		 * intent is translated to the proper frame of reference.
4899*ca7005f1SPatrick Kelsey 		 * If the base CPU ID is within the valid first/last, but
4900*ca7005f1SPatrick Kelsey 		 * does not correspond to a valid CPU, it is advanced to the
4901*ca7005f1SPatrick Kelsey 		 * next valid CPU (wrapping if necessary).
4902*ca7005f1SPatrick Kelsey 		 */
4903*ca7005f1SPatrick Kelsey 		if (base_cpuid < first_valid || base_cpuid > last_valid) {
4904*ca7005f1SPatrick Kelsey 			/* shift from zero-based to first_valid-based */
4905*ca7005f1SPatrick Kelsey 			base_cpuid += first_valid;
4906*ca7005f1SPatrick Kelsey 			/* wrap to range [first_valid, last_valid] */
4907*ca7005f1SPatrick Kelsey 			base_cpuid = (base_cpuid - first_valid) %
4908*ca7005f1SPatrick Kelsey 			    (last_valid - first_valid + 1);
4909*ca7005f1SPatrick Kelsey 		}
4910*ca7005f1SPatrick Kelsey 		if (!CPU_ISSET(base_cpuid, &ctx->ifc_cpus)) {
4911*ca7005f1SPatrick Kelsey 			/*
4912*ca7005f1SPatrick Kelsey 			 * base_cpuid is in [first_valid, last_valid], but
4913*ca7005f1SPatrick Kelsey 			 * not a member of the valid set.  In this case,
4914*ca7005f1SPatrick Kelsey 			 * there will always be a member of the valid set
4915*ca7005f1SPatrick Kelsey 			 * with a CPU ID that is greater than base_cpuid,
4916*ca7005f1SPatrick Kelsey 			 * and we simply advance to it.
4917*ca7005f1SPatrick Kelsey 			 */
4918*ca7005f1SPatrick Kelsey 			while (!CPU_ISSET(base_cpuid, &ctx->ifc_cpus))
4919*ca7005f1SPatrick Kelsey 				base_cpuid++;
4920*ca7005f1SPatrick Kelsey 		}
4921*ca7005f1SPatrick Kelsey 		return (base_cpuid);
4922*ca7005f1SPatrick Kelsey 	}
4923*ca7005f1SPatrick Kelsey 
4924*ca7005f1SPatrick Kelsey 	/*
4925*ca7005f1SPatrick Kelsey 	 * Determine how many cores will be consumed by performing the CPU
4926*ca7005f1SPatrick Kelsey 	 * assignments and counting how many of the assigned CPUs correspond
4927*ca7005f1SPatrick Kelsey 	 * to CPUs in the set of context CPUs.  This is done using the CPU
4928*ca7005f1SPatrick Kelsey 	 * ID first_valid as the base CPU ID, as the base CPU must be within
4929*ca7005f1SPatrick Kelsey 	 * the set of context CPUs.
4930*ca7005f1SPatrick Kelsey 	 *
4931*ca7005f1SPatrick Kelsey 	 * Note not all assigned CPUs will be in the set of context CPUs
4932*ca7005f1SPatrick Kelsey 	 * when separate CPUs are being allocated to TX and RX queues,
4933*ca7005f1SPatrick Kelsey 	 * assignment to logical cores has been enabled, the set of context
4934*ca7005f1SPatrick Kelsey 	 * CPUs contains only physical CPUs, and TX queues are mapped to L2
4935*ca7005f1SPatrick Kelsey 	 * neighbors of CPUs that RX queues have been mapped to - in this
4936*ca7005f1SPatrick Kelsey 	 * case we do only want to count how many CPUs in the set of context
4937*ca7005f1SPatrick Kelsey 	 * CPUs have been consumed, as that determines the next CPU in that
4938*ca7005f1SPatrick Kelsey 	 * set to start allocating at for the next device for which
4939*ca7005f1SPatrick Kelsey 	 * core_offset is not set.
4940*ca7005f1SPatrick Kelsey 	 */
4941*ca7005f1SPatrick Kelsey 	CPU_ZERO(&assigned_cpus);
4942*ca7005f1SPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++)
4943*ca7005f1SPatrick Kelsey 		CPU_SET(get_cpuid_for_queue(ctx, first_valid, i, true),
4944*ca7005f1SPatrick Kelsey 		    &assigned_cpus);
4945*ca7005f1SPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++)
4946*ca7005f1SPatrick Kelsey 		CPU_SET(get_cpuid_for_queue(ctx, first_valid, i, false),
4947*ca7005f1SPatrick Kelsey 		    &assigned_cpus);
4948*ca7005f1SPatrick Kelsey 	CPU_AND(&assigned_cpus, &ctx->ifc_cpus);
4949*ca7005f1SPatrick Kelsey 	cores_consumed = CPU_COUNT(&assigned_cpus);
4950f154ece0SStephen Hurd 
4951f154ece0SStephen Hurd 	mtx_lock(&cpu_offset_mtx);
4952f154ece0SStephen Hurd 	SLIST_FOREACH(op, &cpu_offsets, entries) {
4953f154ece0SStephen Hurd 		if (CPU_CMP(&ctx->ifc_cpus, &op->set) == 0) {
4954*ca7005f1SPatrick Kelsey 			base_cpuid = op->next_cpuid;
4955*ca7005f1SPatrick Kelsey 			op->next_cpuid = cpuid_advance(ctx, op->next_cpuid,
4956*ca7005f1SPatrick Kelsey 			    cores_consumed);
4957f154ece0SStephen Hurd 			MPASS(op->refcount < UINT_MAX);
4958f154ece0SStephen Hurd 			op->refcount++;
4959f154ece0SStephen Hurd 			break;
4960f154ece0SStephen Hurd 		}
4961f154ece0SStephen Hurd 	}
4962*ca7005f1SPatrick Kelsey 	if (base_cpuid == CORE_OFFSET_UNSPECIFIED) {
4963*ca7005f1SPatrick Kelsey 		base_cpuid = first_valid;
4964f154ece0SStephen Hurd 		op = malloc(sizeof(struct cpu_offset), M_IFLIB,
4965f154ece0SStephen Hurd 		    M_NOWAIT | M_ZERO);
4966f154ece0SStephen Hurd 		if (op == NULL) {
4967f154ece0SStephen Hurd 			device_printf(ctx->ifc_dev,
4968f154ece0SStephen Hurd 			    "allocation for cpu offset failed.\n");
4969f154ece0SStephen Hurd 		} else {
4970*ca7005f1SPatrick Kelsey 			op->next_cpuid = cpuid_advance(ctx, base_cpuid,
4971*ca7005f1SPatrick Kelsey 			    cores_consumed);
4972f154ece0SStephen Hurd 			op->refcount = 1;
4973f154ece0SStephen Hurd 			CPU_COPY(&ctx->ifc_cpus, &op->set);
4974f154ece0SStephen Hurd 			SLIST_INSERT_HEAD(&cpu_offsets, op, entries);
4975f154ece0SStephen Hurd 		}
4976f154ece0SStephen Hurd 	}
4977f154ece0SStephen Hurd 	mtx_unlock(&cpu_offset_mtx);
4978f154ece0SStephen Hurd 
4979*ca7005f1SPatrick Kelsey 	return (base_cpuid);
4980f154ece0SStephen Hurd }
4981f154ece0SStephen Hurd 
4982f154ece0SStephen Hurd static void
4983f154ece0SStephen Hurd unref_ctx_core_offset(if_ctx_t ctx)
4984f154ece0SStephen Hurd {
4985f154ece0SStephen Hurd 	struct cpu_offset *op, *top;
4986f154ece0SStephen Hurd 
4987f154ece0SStephen Hurd 	mtx_lock(&cpu_offset_mtx);
4988f154ece0SStephen Hurd 	SLIST_FOREACH_SAFE(op, &cpu_offsets, entries, top) {
4989f154ece0SStephen Hurd 		if (CPU_CMP(&ctx->ifc_cpus, &op->set) == 0) {
4990f154ece0SStephen Hurd 			MPASS(op->refcount > 0);
4991f154ece0SStephen Hurd 			op->refcount--;
4992f154ece0SStephen Hurd 			if (op->refcount == 0) {
4993f154ece0SStephen Hurd 				SLIST_REMOVE(&cpu_offsets, op, cpu_offset, entries);
4994f154ece0SStephen Hurd 				free(op, M_IFLIB);
4995f154ece0SStephen Hurd 			}
4996f154ece0SStephen Hurd 			break;
4997f154ece0SStephen Hurd 		}
4998f154ece0SStephen Hurd 	}
4999f154ece0SStephen Hurd 	mtx_unlock(&cpu_offset_mtx);
5000f154ece0SStephen Hurd }
5001f154ece0SStephen Hurd 
500209f6ff4fSMatt Macy int
500309f6ff4fSMatt Macy iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ctxp)
500409f6ff4fSMatt Macy {
500509f6ff4fSMatt Macy 	if_ctx_t ctx;
500609f6ff4fSMatt Macy 	if_t ifp;
500709f6ff4fSMatt Macy 	if_softc_ctx_t scctx;
50083d10e9edSMarius Strobl 	kobjop_desc_t kobj_desc;
50093d10e9edSMarius Strobl 	kobj_method_t *kobj_method;
5010afb77372SEric Joyner 	int err, msix, rid;
5011ac11d857SVincenzo Maffione 	int num_txd, num_rxd;
501209f6ff4fSMatt Macy 
501309f6ff4fSMatt Macy 	ctx = malloc(sizeof(* ctx), M_IFLIB, M_WAITOK|M_ZERO);
501409f6ff4fSMatt Macy 
501509f6ff4fSMatt Macy 	if (sc == NULL) {
501609f6ff4fSMatt Macy 		sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK|M_ZERO);
501709f6ff4fSMatt Macy 		device_set_softc(dev, ctx);
501809f6ff4fSMatt Macy 		ctx->ifc_flags |= IFC_SC_ALLOCATED;
501909f6ff4fSMatt Macy 	}
502009f6ff4fSMatt Macy 
502109f6ff4fSMatt Macy 	ctx->ifc_sctx = sctx;
502209f6ff4fSMatt Macy 	ctx->ifc_dev = dev;
502309f6ff4fSMatt Macy 	ctx->ifc_softc = sc;
502409f6ff4fSMatt Macy 
502509f6ff4fSMatt Macy 	if ((err = iflib_register(ctx)) != 0) {
502609f6ff4fSMatt Macy 		device_printf(dev, "iflib_register failed %d\n", err);
50277f3eb9daSPatrick Kelsey 		goto fail_ctx_free;
502809f6ff4fSMatt Macy 	}
502909f6ff4fSMatt Macy 	iflib_add_device_sysctl_pre(ctx);
503009f6ff4fSMatt Macy 
503109f6ff4fSMatt Macy 	scctx = &ctx->ifc_softc_ctx;
503209f6ff4fSMatt Macy 	ifp = ctx->ifc_ifp;
503309f6ff4fSMatt Macy 
503409f6ff4fSMatt Macy 	iflib_reset_qvalues(ctx);
5035aa8a24d3SStephen Hurd 	CTX_LOCK(ctx);
5036ab2e3f79SStephen Hurd 	if ((err = IFDI_ATTACH_PRE(ctx)) != 0) {
50374c7070dbSScott Long 		device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err);
50387f3eb9daSPatrick Kelsey 		goto fail_unlock;
50394c7070dbSScott Long 	}
50401248952aSSean Bruno 	_iflib_pre_assert(scctx);
50411248952aSSean Bruno 	ctx->ifc_txrx = *scctx->isc_txrx;
50421248952aSSean Bruno 
5043ef567155SMarcin Wojtas 	MPASS(scctx->isc_dma_width <= flsll(BUS_SPACE_MAXADDR));
50446dd69f00SMarcin Wojtas 
5045e2621d96SMatt Macy 	if (sctx->isc_flags & IFLIB_DRIVER_MEDIA)
5046e2621d96SMatt Macy 		ctx->ifc_mediap = scctx->isc_media;
5047e2621d96SMatt Macy 
50481248952aSSean Bruno #ifdef INVARIANTS
50497f87c040SMarius Strobl 	if (scctx->isc_capabilities & IFCAP_TXCSUM)
50501248952aSSean Bruno 		MPASS(scctx->isc_tx_csum_flags);
50511248952aSSean Bruno #endif
50521248952aSSean Bruno 
50536554362cSAndrew Gallatin 	if_setcapabilities(ifp,
50543f43ada9SGleb Smirnoff 	    scctx->isc_capabilities | IFCAP_HWSTATS | IFCAP_MEXTPG);
50556554362cSAndrew Gallatin 	if_setcapenable(ifp,
50563f43ada9SGleb Smirnoff 	    scctx->isc_capenable | IFCAP_HWSTATS | IFCAP_MEXTPG);
50571248952aSSean Bruno 
50581248952aSSean Bruno 	if (scctx->isc_ntxqsets == 0 || (scctx->isc_ntxqsets_max && scctx->isc_ntxqsets_max < scctx->isc_ntxqsets))
50591248952aSSean Bruno 		scctx->isc_ntxqsets = scctx->isc_ntxqsets_max;
50601248952aSSean Bruno 	if (scctx->isc_nrxqsets == 0 || (scctx->isc_nrxqsets_max && scctx->isc_nrxqsets_max < scctx->isc_nrxqsets))
50611248952aSSean Bruno 		scctx->isc_nrxqsets = scctx->isc_nrxqsets_max;
506223ac9029SStephen Hurd 
5063ac11d857SVincenzo Maffione 	num_txd = iflib_num_tx_descs(ctx);
5064ac11d857SVincenzo Maffione 	num_rxd = iflib_num_rx_descs(ctx);
506523ac9029SStephen Hurd 
506623ac9029SStephen Hurd 	/* XXX change for per-queue sizes */
50671722eeacSMarius Strobl 	device_printf(dev, "Using %d TX descriptors and %d RX descriptors\n",
5068ac11d857SVincenzo Maffione 	    num_txd, num_rxd);
506923ac9029SStephen Hurd 
5070ac11d857SVincenzo Maffione 	if (scctx->isc_tx_nsegments > num_txd / MAX_SINGLE_PACKET_FRACTION)
5071ac11d857SVincenzo Maffione 		scctx->isc_tx_nsegments = max(1, num_txd /
507223ac9029SStephen Hurd 		    MAX_SINGLE_PACKET_FRACTION);
5073ac11d857SVincenzo Maffione 	if (scctx->isc_tx_tso_segments_max > num_txd /
507423ac9029SStephen Hurd 	    MAX_SINGLE_PACKET_FRACTION)
507523ac9029SStephen Hurd 		scctx->isc_tx_tso_segments_max = max(1,
5076ac11d857SVincenzo Maffione 		    num_txd / MAX_SINGLE_PACKET_FRACTION);
50774c7070dbSScott Long 
50784c7070dbSScott Long 	/* TSO parameters - dig these out of the data sheet - simply correspond to tag setup */
50797f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_TSO) {
50807f87c040SMarius Strobl 		/*
50817f87c040SMarius Strobl 		 * The stack can't handle a TSO size larger than IP_MAXPACKET,
50827f87c040SMarius Strobl 		 * but some MACs do.
50837f87c040SMarius Strobl 		 */
50847f87c040SMarius Strobl 		if_sethwtsomax(ifp, min(scctx->isc_tx_tso_size_max,
50857f87c040SMarius Strobl 		    IP_MAXPACKET));
50867f87c040SMarius Strobl 		/*
50877f87c040SMarius Strobl 		 * Take maximum number of m_pullup(9)'s in iflib_parse_header()
50887f87c040SMarius Strobl 		 * into account.  In the worst case, each of these calls will
50897f87c040SMarius Strobl 		 * add another mbuf and, thus, the requirement for another DMA
50907f87c040SMarius Strobl 		 * segment.  So for best performance, it doesn't make sense to
50917f87c040SMarius Strobl 		 * advertize a maximum of TSO segments that typically will
50927f87c040SMarius Strobl 		 * require defragmentation in iflib_encap().
50937f87c040SMarius Strobl 		 */
50947f87c040SMarius Strobl 		if_sethwtsomaxsegcount(ifp, scctx->isc_tx_tso_segments_max - 3);
50957f87c040SMarius Strobl 		if_sethwtsomaxsegsize(ifp, scctx->isc_tx_tso_segsize_max);
50967f87c040SMarius Strobl 	}
50974c7070dbSScott Long 	if (scctx->isc_rss_table_size == 0)
50984c7070dbSScott Long 		scctx->isc_rss_table_size = 64;
509923ac9029SStephen Hurd 	scctx->isc_rss_table_mask = scctx->isc_rss_table_size-1;
5100da69b8f9SSean Bruno 
5101da69b8f9SSean Bruno 	GROUPTASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
5102da69b8f9SSean Bruno 	/* XXX format name */
5103f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_config_tqg, &ctx->ifc_admin_task, ctx,
5104f855ec81SMarius Strobl 	    NULL, NULL, "admin");
5105e516b535SStephen Hurd 
5106772593dbSStephen Hurd 	/* Set up cpu set.  If it fails, use the set of all CPUs. */
5107e516b535SStephen Hurd 	if (bus_get_cpus(dev, INTR_CPUS, sizeof(ctx->ifc_cpus), &ctx->ifc_cpus) != 0) {
5108e516b535SStephen Hurd 		device_printf(dev, "Unable to fetch CPU list\n");
5109e516b535SStephen Hurd 		CPU_COPY(&all_cpus, &ctx->ifc_cpus);
5110*ca7005f1SPatrick Kelsey 		ctx->ifc_cpus_are_physical_cores = false;
5111*ca7005f1SPatrick Kelsey 	} else
5112*ca7005f1SPatrick Kelsey 		ctx->ifc_cpus_are_physical_cores = true;
5113e516b535SStephen Hurd 	MPASS(CPU_COUNT(&ctx->ifc_cpus) > 0);
5114e516b535SStephen Hurd 
51154c7070dbSScott Long 	/*
5116b97de13aSMarius Strobl 	** Now set up MSI or MSI-X, should return us the number of supported
5117b97de13aSMarius Strobl 	** vectors (will be 1 for a legacy interrupt and MSI).
51184c7070dbSScott Long 	*/
51194c7070dbSScott Long 	if (sctx->isc_flags & IFLIB_SKIP_MSIX) {
51204c7070dbSScott Long 		msix = scctx->isc_vectors;
51214c7070dbSScott Long 	} else if (scctx->isc_msix_bar != 0)
5122f7ae9a84SSean Bruno 	       /*
5123f7ae9a84SSean Bruno 		* The simple fact that isc_msix_bar is not 0 does not mean we
5124f7ae9a84SSean Bruno 		* we have a good value there that is known to work.
5125f7ae9a84SSean Bruno 		*/
51264c7070dbSScott Long 		msix = iflib_msix_init(ctx);
51274c7070dbSScott Long 	else {
51284c7070dbSScott Long 		scctx->isc_vectors = 1;
51294c7070dbSScott Long 		scctx->isc_ntxqsets = 1;
51304c7070dbSScott Long 		scctx->isc_nrxqsets = 1;
51314c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_LEGACY;
51324c7070dbSScott Long 		msix = 0;
51334c7070dbSScott Long 	}
51344c7070dbSScott Long 	/* Get memory for the station queues */
51354c7070dbSScott Long 	if ((err = iflib_queues_alloc(ctx))) {
51364c7070dbSScott Long 		device_printf(dev, "Unable to allocate queue memory\n");
51377f3eb9daSPatrick Kelsey 		goto fail_intr_free;
51384c7070dbSScott Long 	}
51394c7070dbSScott Long 
5140ac88e6daSStephen Hurd 	if ((err = iflib_qset_structures_setup(ctx)))
51414c7070dbSScott Long 		goto fail_queues;
514269b7fc3eSSean Bruno 
5143bd84f700SSean Bruno 	/*
5144f154ece0SStephen Hurd 	 * Now that we know how many queues there are, get the core offset.
5145f154ece0SStephen Hurd 	 */
5146f154ece0SStephen Hurd 	ctx->ifc_sysctl_core_offset = get_ctx_core_offset(ctx);
5147f154ece0SStephen Hurd 
51483d10e9edSMarius Strobl 	if (msix > 1) {
51493d10e9edSMarius Strobl 		/*
51503d10e9edSMarius Strobl 		 * When using MSI-X, ensure that ifdi_{r,t}x_queue_intr_enable
51513d10e9edSMarius Strobl 		 * aren't the default NULL implementation.
51523d10e9edSMarius Strobl 		 */
51533d10e9edSMarius Strobl 		kobj_desc = &ifdi_rx_queue_intr_enable_desc;
51543d10e9edSMarius Strobl 		kobj_method = kobj_lookup_method(((kobj_t)ctx)->ops->cls, NULL,
51553d10e9edSMarius Strobl 		    kobj_desc);
51563d10e9edSMarius Strobl 		if (kobj_method == &kobj_desc->deflt) {
51573d10e9edSMarius Strobl 			device_printf(dev,
51583d10e9edSMarius Strobl 			    "MSI-X requires ifdi_rx_queue_intr_enable method");
51593d10e9edSMarius Strobl 			err = EOPNOTSUPP;
51607f3eb9daSPatrick Kelsey 			goto fail_queues;
51614c7070dbSScott Long 		}
51623d10e9edSMarius Strobl 		kobj_desc = &ifdi_tx_queue_intr_enable_desc;
51633d10e9edSMarius Strobl 		kobj_method = kobj_lookup_method(((kobj_t)ctx)->ops->cls, NULL,
51643d10e9edSMarius Strobl 		    kobj_desc);
51653d10e9edSMarius Strobl 		if (kobj_method == &kobj_desc->deflt) {
51663d10e9edSMarius Strobl 			device_printf(dev,
51673d10e9edSMarius Strobl 			    "MSI-X requires ifdi_tx_queue_intr_enable method");
51683d10e9edSMarius Strobl 			err = EOPNOTSUPP;
51693d10e9edSMarius Strobl 			goto fail_queues;
51703d10e9edSMarius Strobl 		}
51713d10e9edSMarius Strobl 
51723d10e9edSMarius Strobl 		/*
51733d10e9edSMarius Strobl 		 * Assign the MSI-X vectors.
51743d10e9edSMarius Strobl 		 * Note that the default NULL ifdi_msix_intr_assign method will
51753d10e9edSMarius Strobl 		 * fail here, too.
51763d10e9edSMarius Strobl 		 */
51773d10e9edSMarius Strobl 		err = IFDI_MSIX_INTR_ASSIGN(ctx, msix);
51783d10e9edSMarius Strobl 		if (err != 0) {
51793d10e9edSMarius Strobl 			device_printf(dev, "IFDI_MSIX_INTR_ASSIGN failed %d\n",
51803d10e9edSMarius Strobl 			    err);
51813d10e9edSMarius Strobl 			goto fail_queues;
51823d10e9edSMarius Strobl 		}
5183197c6798SEric Joyner 	} else if (scctx->isc_intr != IFLIB_INTR_MSIX) {
51844c7070dbSScott Long 		rid = 0;
51854c7070dbSScott Long 		if (scctx->isc_intr == IFLIB_INTR_MSI) {
51864c7070dbSScott Long 			MPASS(msix == 1);
51874c7070dbSScott Long 			rid = 1;
51884c7070dbSScott Long 		}
518923ac9029SStephen Hurd 		if ((err = iflib_legacy_setup(ctx, ctx->isc_legacy_intr, ctx->ifc_softc, &rid, "irq0")) != 0) {
51904c7070dbSScott Long 			device_printf(dev, "iflib_legacy_setup failed %d\n", err);
51917f3eb9daSPatrick Kelsey 			goto fail_queues;
51924c7070dbSScott Long 		}
5193197c6798SEric Joyner 	} else {
5194197c6798SEric Joyner 		device_printf(dev,
5195197c6798SEric Joyner 		    "Cannot use iflib with only 1 MSI-X interrupt!\n");
5196197c6798SEric Joyner 		err = ENODEV;
519738bfc6deSSai Rajesh Tallamraju 		goto fail_queues;
51984c7070dbSScott Long 	}
51997f87c040SMarius Strobl 
52001fd8c72cSKyle Evans 	ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet);
52017f87c040SMarius Strobl 
5202ab2e3f79SStephen Hurd 	if ((err = IFDI_ATTACH_POST(ctx)) != 0) {
52034c7070dbSScott Long 		device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
52044c7070dbSScott Long 		goto fail_detach;
52054c7070dbSScott Long 	}
52067f87c040SMarius Strobl 
52077f87c040SMarius Strobl 	/*
52087f87c040SMarius Strobl 	 * Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.
52097f87c040SMarius Strobl 	 * This must appear after the call to ether_ifattach() because
52107f87c040SMarius Strobl 	 * ether_ifattach() sets if_hdrlen to the default value.
52117f87c040SMarius Strobl 	 */
52127f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_VLAN_MTU)
52137f87c040SMarius Strobl 		if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
52147f87c040SMarius Strobl 
52154c7070dbSScott Long 	if ((err = iflib_netmap_attach(ctx))) {
52164c7070dbSScott Long 		device_printf(ctx->ifc_dev, "netmap attach failed: %d\n", err);
52174c7070dbSScott Long 		goto fail_detach;
52184c7070dbSScott Long 	}
52194c7070dbSScott Long 	*ctxp = ctx;
52204c7070dbSScott Long 
52217790c8c1SConrad Meyer 	DEBUGNET_SET(ctx->ifc_ifp, iflib);
522294618825SMark Johnston 
522323ac9029SStephen Hurd 	if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
52244c7070dbSScott Long 	iflib_add_device_sysctl_post(ctx);
52256d49b41eSAndrew Gallatin 	iflib_add_pfil(ctx);
52264ecb427aSSean Bruno 	ctx->ifc_flags |= IFC_INIT_DONE;
5227aa8a24d3SStephen Hurd 	CTX_UNLOCK(ctx);
52283d10e9edSMarius Strobl 
52294c7070dbSScott Long 	return (0);
523077c1fcecSEric Joyner 
52314c7070dbSScott Long fail_detach:
52324c7070dbSScott Long 	ether_ifdetach(ctx->ifc_ifp);
52334c7070dbSScott Long fail_queues:
523438bfc6deSSai Rajesh Tallamraju 	iflib_tqg_detach(ctx);
52356108c013SStephen Hurd 	iflib_tx_structures_free(ctx);
52366108c013SStephen Hurd 	iflib_rx_structures_free(ctx);
52374c7070dbSScott Long 	IFDI_DETACH(ctx);
523838bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
523938bfc6deSSai Rajesh Tallamraju fail_intr_free:
524038bfc6deSSai Rajesh Tallamraju 	iflib_free_intr_mem(ctx);
52417f3eb9daSPatrick Kelsey fail_unlock:
5242aa8a24d3SStephen Hurd 	CTX_UNLOCK(ctx);
524356614414SEric Joyner 	iflib_deregister(ctx);
52447f3eb9daSPatrick Kelsey fail_ctx_free:
52457f3f6aadSEric Joyner 	device_set_softc(ctx->ifc_dev, NULL);
52467f3eb9daSPatrick Kelsey         if (ctx->ifc_flags & IFC_SC_ALLOCATED)
52477f3eb9daSPatrick Kelsey                 free(ctx->ifc_softc, M_IFLIB);
52487f3eb9daSPatrick Kelsey         free(ctx, M_IFLIB);
52494c7070dbSScott Long 	return (err);
52504c7070dbSScott Long }
52514c7070dbSScott Long 
52524c7070dbSScott Long int
525309f6ff4fSMatt Macy iflib_pseudo_register(device_t dev, if_shared_ctx_t sctx, if_ctx_t *ctxp,
525409f6ff4fSMatt Macy 					  struct iflib_cloneattach_ctx *clctx)
525509f6ff4fSMatt Macy {
5256ac11d857SVincenzo Maffione 	int num_txd, num_rxd;
525709f6ff4fSMatt Macy 	int err;
525809f6ff4fSMatt Macy 	if_ctx_t ctx;
525909f6ff4fSMatt Macy 	if_t ifp;
526009f6ff4fSMatt Macy 	if_softc_ctx_t scctx;
526109f6ff4fSMatt Macy 	int i;
526209f6ff4fSMatt Macy 	void *sc;
526309f6ff4fSMatt Macy 
526409f6ff4fSMatt Macy 	ctx = malloc(sizeof(*ctx), M_IFLIB, M_WAITOK|M_ZERO);
526509f6ff4fSMatt Macy 	sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK|M_ZERO);
526609f6ff4fSMatt Macy 	ctx->ifc_flags |= IFC_SC_ALLOCATED;
526709f6ff4fSMatt Macy 	if (sctx->isc_flags & (IFLIB_PSEUDO|IFLIB_VIRTUAL))
526809f6ff4fSMatt Macy 		ctx->ifc_flags |= IFC_PSEUDO;
526909f6ff4fSMatt Macy 
527009f6ff4fSMatt Macy 	ctx->ifc_sctx = sctx;
527109f6ff4fSMatt Macy 	ctx->ifc_softc = sc;
527209f6ff4fSMatt Macy 	ctx->ifc_dev = dev;
527309f6ff4fSMatt Macy 
527409f6ff4fSMatt Macy 	if ((err = iflib_register(ctx)) != 0) {
527509f6ff4fSMatt Macy 		device_printf(dev, "%s: iflib_register failed %d\n", __func__, err);
52767f3eb9daSPatrick Kelsey 		goto fail_ctx_free;
527709f6ff4fSMatt Macy 	}
527809f6ff4fSMatt Macy 	iflib_add_device_sysctl_pre(ctx);
527909f6ff4fSMatt Macy 
528009f6ff4fSMatt Macy 	scctx = &ctx->ifc_softc_ctx;
528109f6ff4fSMatt Macy 	ifp = ctx->ifc_ifp;
528209f6ff4fSMatt Macy 
528309f6ff4fSMatt Macy 	iflib_reset_qvalues(ctx);
5284aac9c817SEric Joyner 	CTX_LOCK(ctx);
528509f6ff4fSMatt Macy 	if ((err = IFDI_ATTACH_PRE(ctx)) != 0) {
528609f6ff4fSMatt Macy 		device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err);
5287aac9c817SEric Joyner 		goto fail_unlock;
528809f6ff4fSMatt Macy 	}
528909f6ff4fSMatt Macy 	if (sctx->isc_flags & IFLIB_GEN_MAC)
52901fd8c72cSKyle Evans 		ether_gen_addr(ifp, &ctx->ifc_mac);
529109f6ff4fSMatt Macy 	if ((err = IFDI_CLONEATTACH(ctx, clctx->cc_ifc, clctx->cc_name,
529209f6ff4fSMatt Macy 								clctx->cc_params)) != 0) {
529309f6ff4fSMatt Macy 		device_printf(dev, "IFDI_CLONEATTACH failed %d\n", err);
52949aeca213SMatt Macy 		goto fail_unlock;
529509f6ff4fSMatt Macy 	}
529609f6ff4fSMatt Macy #ifdef INVARIANTS
52977f87c040SMarius Strobl 	if (scctx->isc_capabilities & IFCAP_TXCSUM)
529809f6ff4fSMatt Macy 		MPASS(scctx->isc_tx_csum_flags);
529909f6ff4fSMatt Macy #endif
530009f6ff4fSMatt Macy 
53017f87c040SMarius Strobl 	if_setcapabilities(ifp, scctx->isc_capabilities | IFCAP_HWSTATS | IFCAP_LINKSTATE);
530209f6ff4fSMatt Macy 	if_setcapenable(ifp, scctx->isc_capenable | IFCAP_HWSTATS | IFCAP_LINKSTATE);
530309f6ff4fSMatt Macy 
530409f6ff4fSMatt Macy 	ifp->if_flags |= IFF_NOGROUP;
530509f6ff4fSMatt Macy 	if (sctx->isc_flags & IFLIB_PSEUDO) {
53069aeca213SMatt Macy 		ifmedia_add(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO, 0, NULL);
53079aeca213SMatt Macy 		ifmedia_set(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO);
53089aeca213SMatt Macy 		if (sctx->isc_flags & IFLIB_PSEUDO_ETHER) {
53091fd8c72cSKyle Evans 			ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet);
53109aeca213SMatt Macy 		} else {
53119aeca213SMatt Macy 			if_attach(ctx->ifc_ifp);
53129aeca213SMatt Macy 			bpfattach(ctx->ifc_ifp, DLT_NULL, sizeof(u_int32_t));
53139aeca213SMatt Macy 		}
531409f6ff4fSMatt Macy 
531509f6ff4fSMatt Macy 		if ((err = IFDI_ATTACH_POST(ctx)) != 0) {
531609f6ff4fSMatt Macy 			device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
531709f6ff4fSMatt Macy 			goto fail_detach;
531809f6ff4fSMatt Macy 		}
531909f6ff4fSMatt Macy 		*ctxp = ctx;
532009f6ff4fSMatt Macy 
53217f87c040SMarius Strobl 		/*
53227f87c040SMarius Strobl 		 * Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.
53237f87c040SMarius Strobl 		 * This must appear after the call to ether_ifattach() because
53247f87c040SMarius Strobl 		 * ether_ifattach() sets if_hdrlen to the default value.
53257f87c040SMarius Strobl 		 */
53267f87c040SMarius Strobl 		if (if_getcapabilities(ifp) & IFCAP_VLAN_MTU)
53277f87c040SMarius Strobl 			if_setifheaderlen(ifp,
53287f87c040SMarius Strobl 			    sizeof(struct ether_vlan_header));
53297f87c040SMarius Strobl 
533009f6ff4fSMatt Macy 		if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
533109f6ff4fSMatt Macy 		iflib_add_device_sysctl_post(ctx);
533209f6ff4fSMatt Macy 		ctx->ifc_flags |= IFC_INIT_DONE;
53331f93e931SMatt Macy 		CTX_UNLOCK(ctx);
533409f6ff4fSMatt Macy 		return (0);
533509f6ff4fSMatt Macy 	}
53369aeca213SMatt Macy 	ifmedia_add(ctx->ifc_mediap, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
53379aeca213SMatt Macy 	ifmedia_add(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO, 0, NULL);
53389aeca213SMatt Macy 	ifmedia_set(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO);
53399aeca213SMatt Macy 
534009f6ff4fSMatt Macy 	_iflib_pre_assert(scctx);
534109f6ff4fSMatt Macy 	ctx->ifc_txrx = *scctx->isc_txrx;
534209f6ff4fSMatt Macy 
534309f6ff4fSMatt Macy 	if (scctx->isc_ntxqsets == 0 || (scctx->isc_ntxqsets_max && scctx->isc_ntxqsets_max < scctx->isc_ntxqsets))
534409f6ff4fSMatt Macy 		scctx->isc_ntxqsets = scctx->isc_ntxqsets_max;
534509f6ff4fSMatt Macy 	if (scctx->isc_nrxqsets == 0 || (scctx->isc_nrxqsets_max && scctx->isc_nrxqsets_max < scctx->isc_nrxqsets))
534609f6ff4fSMatt Macy 		scctx->isc_nrxqsets = scctx->isc_nrxqsets_max;
534709f6ff4fSMatt Macy 
5348ac11d857SVincenzo Maffione 	num_txd = iflib_num_tx_descs(ctx);
5349ac11d857SVincenzo Maffione 	num_rxd = iflib_num_rx_descs(ctx);
535009f6ff4fSMatt Macy 
535109f6ff4fSMatt Macy 	/* XXX change for per-queue sizes */
53521722eeacSMarius Strobl 	device_printf(dev, "Using %d TX descriptors and %d RX descriptors\n",
5353ac11d857SVincenzo Maffione 	    num_txd, num_rxd);
535409f6ff4fSMatt Macy 
5355ac11d857SVincenzo Maffione 	if (scctx->isc_tx_nsegments > num_txd / MAX_SINGLE_PACKET_FRACTION)
5356ac11d857SVincenzo Maffione 		scctx->isc_tx_nsegments = max(1, num_txd /
535709f6ff4fSMatt Macy 		    MAX_SINGLE_PACKET_FRACTION);
5358ac11d857SVincenzo Maffione 	if (scctx->isc_tx_tso_segments_max > num_txd /
535909f6ff4fSMatt Macy 	    MAX_SINGLE_PACKET_FRACTION)
536009f6ff4fSMatt Macy 		scctx->isc_tx_tso_segments_max = max(1,
5361ac11d857SVincenzo Maffione 		    num_txd / MAX_SINGLE_PACKET_FRACTION);
536209f6ff4fSMatt Macy 
536309f6ff4fSMatt Macy 	/* TSO parameters - dig these out of the data sheet - simply correspond to tag setup */
53647f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_TSO) {
53657f87c040SMarius Strobl 		/*
53667f87c040SMarius Strobl 		 * The stack can't handle a TSO size larger than IP_MAXPACKET,
53677f87c040SMarius Strobl 		 * but some MACs do.
53687f87c040SMarius Strobl 		 */
53697f87c040SMarius Strobl 		if_sethwtsomax(ifp, min(scctx->isc_tx_tso_size_max,
53707f87c040SMarius Strobl 		    IP_MAXPACKET));
53717f87c040SMarius Strobl 		/*
53727f87c040SMarius Strobl 		 * Take maximum number of m_pullup(9)'s in iflib_parse_header()
53737f87c040SMarius Strobl 		 * into account.  In the worst case, each of these calls will
53747f87c040SMarius Strobl 		 * add another mbuf and, thus, the requirement for another DMA
53757f87c040SMarius Strobl 		 * segment.  So for best performance, it doesn't make sense to
53767f87c040SMarius Strobl 		 * advertize a maximum of TSO segments that typically will
53777f87c040SMarius Strobl 		 * require defragmentation in iflib_encap().
53787f87c040SMarius Strobl 		 */
53797f87c040SMarius Strobl 		if_sethwtsomaxsegcount(ifp, scctx->isc_tx_tso_segments_max - 3);
53807f87c040SMarius Strobl 		if_sethwtsomaxsegsize(ifp, scctx->isc_tx_tso_segsize_max);
53817f87c040SMarius Strobl 	}
538209f6ff4fSMatt Macy 	if (scctx->isc_rss_table_size == 0)
538309f6ff4fSMatt Macy 		scctx->isc_rss_table_size = 64;
538409f6ff4fSMatt Macy 	scctx->isc_rss_table_mask = scctx->isc_rss_table_size-1;
538509f6ff4fSMatt Macy 
538609f6ff4fSMatt Macy 	GROUPTASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
538709f6ff4fSMatt Macy 	/* XXX format name */
5388f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_config_tqg, &ctx->ifc_admin_task, ctx,
5389f855ec81SMarius Strobl 	    NULL, NULL, "admin");
539009f6ff4fSMatt Macy 
539109f6ff4fSMatt Macy 	/* XXX --- can support > 1 -- but keep it simple for now */
539209f6ff4fSMatt Macy 	scctx->isc_intr = IFLIB_INTR_LEGACY;
539309f6ff4fSMatt Macy 
539409f6ff4fSMatt Macy 	/* Get memory for the station queues */
539509f6ff4fSMatt Macy 	if ((err = iflib_queues_alloc(ctx))) {
539609f6ff4fSMatt Macy 		device_printf(dev, "Unable to allocate queue memory\n");
53977f3eb9daSPatrick Kelsey 		goto fail_iflib_detach;
539809f6ff4fSMatt Macy 	}
539909f6ff4fSMatt Macy 
540009f6ff4fSMatt Macy 	if ((err = iflib_qset_structures_setup(ctx))) {
540109f6ff4fSMatt Macy 		device_printf(dev, "qset structure setup failed %d\n", err);
540209f6ff4fSMatt Macy 		goto fail_queues;
540309f6ff4fSMatt Macy 	}
54047f87c040SMarius Strobl 
540509f6ff4fSMatt Macy 	/*
540609f6ff4fSMatt Macy 	 * XXX What if anything do we want to do about interrupts?
540709f6ff4fSMatt Macy 	 */
54081fd8c72cSKyle Evans 	ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet);
540909f6ff4fSMatt Macy 	if ((err = IFDI_ATTACH_POST(ctx)) != 0) {
541009f6ff4fSMatt Macy 		device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
541109f6ff4fSMatt Macy 		goto fail_detach;
541209f6ff4fSMatt Macy 	}
54137f87c040SMarius Strobl 
54147f87c040SMarius Strobl 	/*
54157f87c040SMarius Strobl 	 * Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.
54167f87c040SMarius Strobl 	 * This must appear after the call to ether_ifattach() because
54177f87c040SMarius Strobl 	 * ether_ifattach() sets if_hdrlen to the default value.
54187f87c040SMarius Strobl 	 */
54197f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_VLAN_MTU)
54207f87c040SMarius Strobl 		if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
54217f87c040SMarius Strobl 
542209f6ff4fSMatt Macy 	/* XXX handle more than one queue */
542309f6ff4fSMatt Macy 	for (i = 0; i < scctx->isc_nrxqsets; i++)
542409f6ff4fSMatt Macy 		IFDI_RX_CLSET(ctx, 0, i, ctx->ifc_rxqs[i].ifr_fl[0].ifl_sds.ifsd_cl);
542509f6ff4fSMatt Macy 
542609f6ff4fSMatt Macy 	*ctxp = ctx;
542709f6ff4fSMatt Macy 
542809f6ff4fSMatt Macy 	if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
542909f6ff4fSMatt Macy 	iflib_add_device_sysctl_post(ctx);
543009f6ff4fSMatt Macy 	ctx->ifc_flags |= IFC_INIT_DONE;
5431aac9c817SEric Joyner 	CTX_UNLOCK(ctx);
54323d10e9edSMarius Strobl 
543309f6ff4fSMatt Macy 	return (0);
543409f6ff4fSMatt Macy fail_detach:
543509f6ff4fSMatt Macy 	ether_ifdetach(ctx->ifc_ifp);
543609f6ff4fSMatt Macy fail_queues:
543738bfc6deSSai Rajesh Tallamraju 	iflib_tqg_detach(ctx);
543809f6ff4fSMatt Macy 	iflib_tx_structures_free(ctx);
543909f6ff4fSMatt Macy 	iflib_rx_structures_free(ctx);
54407f3eb9daSPatrick Kelsey fail_iflib_detach:
544109f6ff4fSMatt Macy 	IFDI_DETACH(ctx);
544238bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
5443aac9c817SEric Joyner fail_unlock:
5444aac9c817SEric Joyner 	CTX_UNLOCK(ctx);
544556614414SEric Joyner 	iflib_deregister(ctx);
54467f3eb9daSPatrick Kelsey fail_ctx_free:
54477f3eb9daSPatrick Kelsey 	free(ctx->ifc_softc, M_IFLIB);
54487f3eb9daSPatrick Kelsey 	free(ctx, M_IFLIB);
544909f6ff4fSMatt Macy 	return (err);
545009f6ff4fSMatt Macy }
545109f6ff4fSMatt Macy 
545209f6ff4fSMatt Macy int
545309f6ff4fSMatt Macy iflib_pseudo_deregister(if_ctx_t ctx)
545409f6ff4fSMatt Macy {
545509f6ff4fSMatt Macy 	if_t ifp = ctx->ifc_ifp;
54569aeca213SMatt Macy 	if_shared_ctx_t sctx = ctx->ifc_sctx;
545709f6ff4fSMatt Macy 
54581558015eSEric Joyner 	/* Unregister VLAN event handlers early */
54591558015eSEric Joyner 	iflib_unregister_vlan_handlers(ctx);
54601558015eSEric Joyner 
54619aeca213SMatt Macy 	if ((sctx->isc_flags & IFLIB_PSEUDO)  &&
54629aeca213SMatt Macy 		(sctx->isc_flags & IFLIB_PSEUDO_ETHER) == 0) {
54639aeca213SMatt Macy 		bpfdetach(ifp);
54649aeca213SMatt Macy 		if_detach(ifp);
54659aeca213SMatt Macy 	} else {
546609f6ff4fSMatt Macy 		ether_ifdetach(ifp);
54679aeca213SMatt Macy 	}
546809f6ff4fSMatt Macy 
546910254019SMark Johnston 	iflib_tqg_detach(ctx);
547009f6ff4fSMatt Macy 	iflib_tx_structures_free(ctx);
547109f6ff4fSMatt Macy 	iflib_rx_structures_free(ctx);
547238bfc6deSSai Rajesh Tallamraju 	IFDI_DETACH(ctx);
547338bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
547456614414SEric Joyner 
547556614414SEric Joyner 	iflib_deregister(ctx);
547656614414SEric Joyner 
547709f6ff4fSMatt Macy 	if (ctx->ifc_flags & IFC_SC_ALLOCATED)
547809f6ff4fSMatt Macy 		free(ctx->ifc_softc, M_IFLIB);
547909f6ff4fSMatt Macy 	free(ctx, M_IFLIB);
548009f6ff4fSMatt Macy 	return (0);
548109f6ff4fSMatt Macy }
548209f6ff4fSMatt Macy 
548309f6ff4fSMatt Macy int
54844c7070dbSScott Long iflib_device_attach(device_t dev)
54854c7070dbSScott Long {
54864c7070dbSScott Long 	if_ctx_t ctx;
54874c7070dbSScott Long 	if_shared_ctx_t sctx;
54884c7070dbSScott Long 
54894c7070dbSScott Long 	if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC)
54904c7070dbSScott Long 		return (ENOTSUP);
54914c7070dbSScott Long 
54924c7070dbSScott Long 	pci_enable_busmaster(dev);
54934c7070dbSScott Long 
54944c7070dbSScott Long 	return (iflib_device_register(dev, NULL, sctx, &ctx));
54954c7070dbSScott Long }
54964c7070dbSScott Long 
54974c7070dbSScott Long int
54984c7070dbSScott Long iflib_device_deregister(if_ctx_t ctx)
54994c7070dbSScott Long {
55004c7070dbSScott Long 	if_t ifp = ctx->ifc_ifp;
55014c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
55024c7070dbSScott Long 
55034c7070dbSScott Long 	/* Make sure VLANS are not using driver */
55044c7070dbSScott Long 	if (if_vlantrunkinuse(ifp)) {
55054c7070dbSScott Long 		device_printf(dev, "Vlan in use, detach first\n");
55064c7070dbSScott Long 		return (EBUSY);
55074c7070dbSScott Long 	}
550877c1fcecSEric Joyner #ifdef PCI_IOV
550977c1fcecSEric Joyner 	if (!CTX_IS_VF(ctx) && pci_iov_detach(dev) != 0) {
551077c1fcecSEric Joyner 		device_printf(dev, "SR-IOV in use; detach first.\n");
551177c1fcecSEric Joyner 		return (EBUSY);
551277c1fcecSEric Joyner 	}
551377c1fcecSEric Joyner #endif
551477c1fcecSEric Joyner 
551577c1fcecSEric Joyner 	STATE_LOCK(ctx);
551677c1fcecSEric Joyner 	ctx->ifc_flags |= IFC_IN_DETACH;
551777c1fcecSEric Joyner 	STATE_UNLOCK(ctx);
55184c7070dbSScott Long 
55191558015eSEric Joyner 	/* Unregister VLAN handlers before calling iflib_stop() */
55201558015eSEric Joyner 	iflib_unregister_vlan_handlers(ctx);
55211558015eSEric Joyner 
55221558015eSEric Joyner 	iflib_netmap_detach(ifp);
55231558015eSEric Joyner 	ether_ifdetach(ifp);
55241558015eSEric Joyner 
55254c7070dbSScott Long 	CTX_LOCK(ctx);
55264c7070dbSScott Long 	iflib_stop(ctx);
55274c7070dbSScott Long 	CTX_UNLOCK(ctx);
55284c7070dbSScott Long 
55296d49b41eSAndrew Gallatin 	iflib_rem_pfil(ctx);
55304c7070dbSScott Long 	if (ctx->ifc_led_dev != NULL)
55314c7070dbSScott Long 		led_destroy(ctx->ifc_led_dev);
553287890dbaSSean Bruno 
553310254019SMark Johnston 	iflib_tqg_detach(ctx);
553438bfc6deSSai Rajesh Tallamraju 	iflib_tx_structures_free(ctx);
553538bfc6deSSai Rajesh Tallamraju 	iflib_rx_structures_free(ctx);
553638bfc6deSSai Rajesh Tallamraju 
55376c3c3194SMatt Macy 	CTX_LOCK(ctx);
55384c7070dbSScott Long 	IFDI_DETACH(ctx);
553938bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
55406c3c3194SMatt Macy 	CTX_UNLOCK(ctx);
55416c3c3194SMatt Macy 
55426c3c3194SMatt Macy 	/* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/
554377c1fcecSEric Joyner 	iflib_free_intr_mem(ctx);
554477c1fcecSEric Joyner 
554577c1fcecSEric Joyner 	bus_generic_detach(dev);
554677c1fcecSEric Joyner 
554756614414SEric Joyner 	iflib_deregister(ctx);
554856614414SEric Joyner 
554956614414SEric Joyner 	device_set_softc(ctx->ifc_dev, NULL);
555077c1fcecSEric Joyner 	if (ctx->ifc_flags & IFC_SC_ALLOCATED)
555177c1fcecSEric Joyner 		free(ctx->ifc_softc, M_IFLIB);
5552f154ece0SStephen Hurd 	unref_ctx_core_offset(ctx);
555377c1fcecSEric Joyner 	free(ctx, M_IFLIB);
555477c1fcecSEric Joyner 	return (0);
555577c1fcecSEric Joyner }
555677c1fcecSEric Joyner 
555777c1fcecSEric Joyner static void
555810254019SMark Johnston iflib_tqg_detach(if_ctx_t ctx)
555910254019SMark Johnston {
556010254019SMark Johnston 	iflib_txq_t txq;
556110254019SMark Johnston 	iflib_rxq_t rxq;
556210254019SMark Johnston 	int i;
556310254019SMark Johnston 	struct taskqgroup *tqg;
556410254019SMark Johnston 
556510254019SMark Johnston 	/* XXX drain any dependent tasks */
556610254019SMark Johnston 	tqg = qgroup_if_io_tqg;
556710254019SMark Johnston 	for (txq = ctx->ifc_txqs, i = 0; i < NTXQSETS(ctx); i++, txq++) {
556810254019SMark Johnston 		callout_drain(&txq->ift_timer);
556910254019SMark Johnston #ifdef DEV_NETMAP
557010254019SMark Johnston 		callout_drain(&txq->ift_netmap_timer);
557110254019SMark Johnston #endif /* DEV_NETMAP */
557210254019SMark Johnston 		if (txq->ift_task.gt_uniq != NULL)
557310254019SMark Johnston 			taskqgroup_detach(tqg, &txq->ift_task);
557410254019SMark Johnston 	}
557510254019SMark Johnston 	for (i = 0, rxq = ctx->ifc_rxqs; i < NRXQSETS(ctx); i++, rxq++) {
557610254019SMark Johnston 		if (rxq->ifr_task.gt_uniq != NULL)
557710254019SMark Johnston 			taskqgroup_detach(tqg, &rxq->ifr_task);
557810254019SMark Johnston 	}
557910254019SMark Johnston 	tqg = qgroup_if_config_tqg;
558010254019SMark Johnston 	if (ctx->ifc_admin_task.gt_uniq != NULL)
558110254019SMark Johnston 		taskqgroup_detach(tqg, &ctx->ifc_admin_task);
558210254019SMark Johnston 	if (ctx->ifc_vflr_task.gt_uniq != NULL)
558310254019SMark Johnston 		taskqgroup_detach(tqg, &ctx->ifc_vflr_task);
558410254019SMark Johnston }
558510254019SMark Johnston 
558610254019SMark Johnston static void
558777c1fcecSEric Joyner iflib_free_intr_mem(if_ctx_t ctx)
558877c1fcecSEric Joyner {
558977c1fcecSEric Joyner 
55904c7070dbSScott Long 	if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_MSIX) {
55914c7070dbSScott Long 		iflib_irq_free(ctx, &ctx->ifc_legacy_irq);
55924c7070dbSScott Long 	}
5593b97de13aSMarius Strobl 	if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_LEGACY) {
5594b97de13aSMarius Strobl 		pci_release_msi(ctx->ifc_dev);
5595b97de13aSMarius Strobl 	}
55964c7070dbSScott Long 	if (ctx->ifc_msix_mem != NULL) {
55974c7070dbSScott Long 		bus_release_resource(ctx->ifc_dev, SYS_RES_MEMORY,
5598b97de13aSMarius Strobl 		    rman_get_rid(ctx->ifc_msix_mem), ctx->ifc_msix_mem);
55994c7070dbSScott Long 		ctx->ifc_msix_mem = NULL;
56004c7070dbSScott Long 	}
56014c7070dbSScott Long }
56024c7070dbSScott Long 
56034c7070dbSScott Long int
56044c7070dbSScott Long iflib_device_detach(device_t dev)
56054c7070dbSScott Long {
56064c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56074c7070dbSScott Long 
56084c7070dbSScott Long 	return (iflib_device_deregister(ctx));
56094c7070dbSScott Long }
56104c7070dbSScott Long 
56114c7070dbSScott Long int
56124c7070dbSScott Long iflib_device_suspend(device_t dev)
56134c7070dbSScott Long {
56144c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56154c7070dbSScott Long 
56164c7070dbSScott Long 	CTX_LOCK(ctx);
56174c7070dbSScott Long 	IFDI_SUSPEND(ctx);
56184c7070dbSScott Long 	CTX_UNLOCK(ctx);
56194c7070dbSScott Long 
56204c7070dbSScott Long 	return bus_generic_suspend(dev);
56214c7070dbSScott Long }
56224c7070dbSScott Long int
56234c7070dbSScott Long iflib_device_shutdown(device_t dev)
56244c7070dbSScott Long {
56254c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56264c7070dbSScott Long 
56274c7070dbSScott Long 	CTX_LOCK(ctx);
56284c7070dbSScott Long 	IFDI_SHUTDOWN(ctx);
56294c7070dbSScott Long 	CTX_UNLOCK(ctx);
56304c7070dbSScott Long 
56314c7070dbSScott Long 	return bus_generic_suspend(dev);
56324c7070dbSScott Long }
56334c7070dbSScott Long 
56344c7070dbSScott Long int
56354c7070dbSScott Long iflib_device_resume(device_t dev)
56364c7070dbSScott Long {
56374c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56384c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
56394c7070dbSScott Long 
56404c7070dbSScott Long 	CTX_LOCK(ctx);
56414c7070dbSScott Long 	IFDI_RESUME(ctx);
5642cd28ea92SStephen Hurd 	iflib_if_init_locked(ctx);
56434c7070dbSScott Long 	CTX_UNLOCK(ctx);
56444c7070dbSScott Long 	for (int i = 0; i < NTXQSETS(ctx); i++, txq++)
56454c7070dbSScott Long 		iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET);
56464c7070dbSScott Long 
56474c7070dbSScott Long 	return (bus_generic_resume(dev));
56484c7070dbSScott Long }
56494c7070dbSScott Long 
56504c7070dbSScott Long int
56514c7070dbSScott Long iflib_device_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
56524c7070dbSScott Long {
56534c7070dbSScott Long 	int error;
56544c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56554c7070dbSScott Long 
56564c7070dbSScott Long 	CTX_LOCK(ctx);
56574c7070dbSScott Long 	error = IFDI_IOV_INIT(ctx, num_vfs, params);
56584c7070dbSScott Long 	CTX_UNLOCK(ctx);
56594c7070dbSScott Long 
56604c7070dbSScott Long 	return (error);
56614c7070dbSScott Long }
56624c7070dbSScott Long 
56634c7070dbSScott Long void
56644c7070dbSScott Long iflib_device_iov_uninit(device_t dev)
56654c7070dbSScott Long {
56664c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56674c7070dbSScott Long 
56684c7070dbSScott Long 	CTX_LOCK(ctx);
56694c7070dbSScott Long 	IFDI_IOV_UNINIT(ctx);
56704c7070dbSScott Long 	CTX_UNLOCK(ctx);
56714c7070dbSScott Long }
56724c7070dbSScott Long 
56734c7070dbSScott Long int
56744c7070dbSScott Long iflib_device_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
56754c7070dbSScott Long {
56764c7070dbSScott Long 	int error;
56774c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
56784c7070dbSScott Long 
56794c7070dbSScott Long 	CTX_LOCK(ctx);
56804c7070dbSScott Long 	error = IFDI_IOV_VF_ADD(ctx, vfnum, params);
56814c7070dbSScott Long 	CTX_UNLOCK(ctx);
56824c7070dbSScott Long 
56834c7070dbSScott Long 	return (error);
56844c7070dbSScott Long }
56854c7070dbSScott Long 
56864c7070dbSScott Long /*********************************************************************
56874c7070dbSScott Long  *
56884c7070dbSScott Long  *  MODULE FUNCTION DEFINITIONS
56894c7070dbSScott Long  *
56904c7070dbSScott Long  **********************************************************************/
56914c7070dbSScott Long 
5692ab2e3f79SStephen Hurd /*
5693ab2e3f79SStephen Hurd  * - Start a fast taskqueue thread for each core
5694ab2e3f79SStephen Hurd  * - Start a taskqueue for control operations
5695ab2e3f79SStephen Hurd  */
56964c7070dbSScott Long static int
56974c7070dbSScott Long iflib_module_init(void)
56984c7070dbSScott Long {
569981be6552SMatt Macy 	iflib_timer_default = hz / 2;
57004c7070dbSScott Long 	return (0);
57014c7070dbSScott Long }
57024c7070dbSScott Long 
57034c7070dbSScott Long static int
57044c7070dbSScott Long iflib_module_event_handler(module_t mod, int what, void *arg)
57054c7070dbSScott Long {
57064c7070dbSScott Long 	int err;
57074c7070dbSScott Long 
57084c7070dbSScott Long 	switch (what) {
57094c7070dbSScott Long 	case MOD_LOAD:
57104c7070dbSScott Long 		if ((err = iflib_module_init()) != 0)
57114c7070dbSScott Long 			return (err);
57124c7070dbSScott Long 		break;
57134c7070dbSScott Long 	case MOD_UNLOAD:
57144c7070dbSScott Long 		return (EBUSY);
57154c7070dbSScott Long 	default:
57164c7070dbSScott Long 		return (EOPNOTSUPP);
57174c7070dbSScott Long 	}
57184c7070dbSScott Long 
57194c7070dbSScott Long 	return (0);
57204c7070dbSScott Long }
57214c7070dbSScott Long 
57224c7070dbSScott Long /*********************************************************************
57234c7070dbSScott Long  *
57244c7070dbSScott Long  *  PUBLIC FUNCTION DEFINITIONS
57254c7070dbSScott Long  *     ordered as in iflib.h
57264c7070dbSScott Long  *
57274c7070dbSScott Long  **********************************************************************/
57284c7070dbSScott Long 
57294c7070dbSScott Long static void
57304c7070dbSScott Long _iflib_assert(if_shared_ctx_t sctx)
57314c7070dbSScott Long {
5732afb77372SEric Joyner 	int i;
5733afb77372SEric Joyner 
57344c7070dbSScott Long 	MPASS(sctx->isc_tx_maxsize);
57354c7070dbSScott Long 	MPASS(sctx->isc_tx_maxsegsize);
57364c7070dbSScott Long 
57374c7070dbSScott Long 	MPASS(sctx->isc_rx_maxsize);
57384c7070dbSScott Long 	MPASS(sctx->isc_rx_nsegments);
57394c7070dbSScott Long 	MPASS(sctx->isc_rx_maxsegsize);
57404c7070dbSScott Long 
5741afb77372SEric Joyner 	MPASS(sctx->isc_nrxqs >= 1 && sctx->isc_nrxqs <= 8);
5742afb77372SEric Joyner 	for (i = 0; i < sctx->isc_nrxqs; i++) {
5743afb77372SEric Joyner 		MPASS(sctx->isc_nrxd_min[i]);
5744afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_nrxd_min[i]));
5745afb77372SEric Joyner 		MPASS(sctx->isc_nrxd_max[i]);
5746afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_nrxd_max[i]));
5747afb77372SEric Joyner 		MPASS(sctx->isc_nrxd_default[i]);
5748afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_nrxd_default[i]));
5749afb77372SEric Joyner 	}
5750afb77372SEric Joyner 
5751afb77372SEric Joyner 	MPASS(sctx->isc_ntxqs >= 1 && sctx->isc_ntxqs <= 8);
5752afb77372SEric Joyner 	for (i = 0; i < sctx->isc_ntxqs; i++) {
5753afb77372SEric Joyner 		MPASS(sctx->isc_ntxd_min[i]);
5754afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_ntxd_min[i]));
5755afb77372SEric Joyner 		MPASS(sctx->isc_ntxd_max[i]);
5756afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_ntxd_max[i]));
5757afb77372SEric Joyner 		MPASS(sctx->isc_ntxd_default[i]);
5758afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_ntxd_default[i]));
5759afb77372SEric Joyner 	}
57604c7070dbSScott Long }
57614c7070dbSScott Long 
57621248952aSSean Bruno static void
57631248952aSSean Bruno _iflib_pre_assert(if_softc_ctx_t scctx)
57641248952aSSean Bruno {
57651248952aSSean Bruno 
57661248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_txd_encap);
57671248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_txd_flush);
57681248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_txd_credits_update);
57691248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_available);
57701248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_pkt_get);
57711248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_refill);
57721248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_flush);
57731248952aSSean Bruno }
57742fe66646SSean Bruno 
57754c7070dbSScott Long static int
57764c7070dbSScott Long iflib_register(if_ctx_t ctx)
57774c7070dbSScott Long {
57784c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
57794c7070dbSScott Long 	driver_t *driver = sctx->isc_driver;
57804c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
57814c7070dbSScott Long 	if_t ifp;
57829aeca213SMatt Macy 	u_char type;
57839aeca213SMatt Macy 	int iflags;
57844c7070dbSScott Long 
57851f93e931SMatt Macy 	if ((sctx->isc_flags & IFLIB_PSEUDO) == 0)
57864c7070dbSScott Long 		_iflib_assert(sctx);
57874c7070dbSScott Long 
5788aa8a24d3SStephen Hurd 	CTX_LOCK_INIT(ctx);
57897b610b60SSean Bruno 	STATE_LOCK_INIT(ctx, device_get_nameunit(ctx->ifc_dev));
57909aeca213SMatt Macy 	if (sctx->isc_flags & IFLIB_PSEUDO) {
57919aeca213SMatt Macy 		if (sctx->isc_flags & IFLIB_PSEUDO_ETHER)
57929aeca213SMatt Macy 			type = IFT_ETHER;
57939aeca213SMatt Macy 		else
57949aeca213SMatt Macy 			type = IFT_PPP;
57959aeca213SMatt Macy 	} else
57969aeca213SMatt Macy 		type = IFT_ETHER;
57979aeca213SMatt Macy 	ifp = ctx->ifc_ifp = if_alloc(type);
57984c7070dbSScott Long 	if (ifp == NULL) {
57994c7070dbSScott Long 		device_printf(dev, "can not allocate ifnet structure\n");
58004c7070dbSScott Long 		return (ENOMEM);
58014c7070dbSScott Long 	}
58024c7070dbSScott Long 
58034c7070dbSScott Long 	/*
58044c7070dbSScott Long 	 * Initialize our context's device specific methods
58054c7070dbSScott Long 	 */
58064c7070dbSScott Long 	kobj_init((kobj_t) ctx, (kobj_class_t) driver);
58074c7070dbSScott Long 	kobj_class_compile((kobj_class_t) driver);
58084c7070dbSScott Long 
58094c7070dbSScott Long 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
58104c7070dbSScott Long 	if_setsoftc(ifp, ctx);
58114c7070dbSScott Long 	if_setdev(ifp, dev);
58124c7070dbSScott Long 	if_setinitfn(ifp, iflib_if_init);
58134c7070dbSScott Long 	if_setioctlfn(ifp, iflib_if_ioctl);
5814b8ca4756SPatrick Kelsey #ifdef ALTQ
5815b8ca4756SPatrick Kelsey 	if_setstartfn(ifp, iflib_altq_if_start);
5816b8ca4756SPatrick Kelsey 	if_settransmitfn(ifp, iflib_altq_if_transmit);
58178f410865SPatrick Kelsey 	if_setsendqready(ifp);
5818b8ca4756SPatrick Kelsey #else
58194c7070dbSScott Long 	if_settransmitfn(ifp, iflib_if_transmit);
5820b8ca4756SPatrick Kelsey #endif
58214c7070dbSScott Long 	if_setqflushfn(ifp, iflib_if_qflush);
58229aeca213SMatt Macy 	iflags = IFF_MULTICAST | IFF_KNOWSEPOCH;
58234c7070dbSScott Long 
58249aeca213SMatt Macy 	if ((sctx->isc_flags & IFLIB_PSEUDO) &&
58259aeca213SMatt Macy 		(sctx->isc_flags & IFLIB_PSEUDO_ETHER) == 0)
58269aeca213SMatt Macy 		iflags |= IFF_POINTOPOINT;
58279aeca213SMatt Macy 	else
58289aeca213SMatt Macy 		iflags |= IFF_BROADCAST | IFF_SIMPLEX;
58299aeca213SMatt Macy 	if_setflags(ifp, iflags);
58304c7070dbSScott Long 	ctx->ifc_vlan_attach_event =
58314c7070dbSScott Long 		EVENTHANDLER_REGISTER(vlan_config, iflib_vlan_register, ctx,
58324c7070dbSScott Long 							  EVENTHANDLER_PRI_FIRST);
58334c7070dbSScott Long 	ctx->ifc_vlan_detach_event =
58344c7070dbSScott Long 		EVENTHANDLER_REGISTER(vlan_unconfig, iflib_vlan_unregister, ctx,
58354c7070dbSScott Long 							  EVENTHANDLER_PRI_FIRST);
58364c7070dbSScott Long 
5837e2621d96SMatt Macy 	if ((sctx->isc_flags & IFLIB_DRIVER_MEDIA) == 0) {
5838e2621d96SMatt Macy 		ctx->ifc_mediap = &ctx->ifc_media;
5839e2621d96SMatt Macy 		ifmedia_init(ctx->ifc_mediap, IFM_IMASK,
58404c7070dbSScott Long 		    iflib_media_change, iflib_media_status);
5841e2621d96SMatt Macy 	}
58424c7070dbSScott Long 	return (0);
58434c7070dbSScott Long }
58444c7070dbSScott Long 
584556614414SEric Joyner static void
58461558015eSEric Joyner iflib_unregister_vlan_handlers(if_ctx_t ctx)
584756614414SEric Joyner {
584856614414SEric Joyner 	/* Unregister VLAN events */
584956614414SEric Joyner 	if (ctx->ifc_vlan_attach_event != NULL) {
585056614414SEric Joyner 		EVENTHANDLER_DEREGISTER(vlan_config, ctx->ifc_vlan_attach_event);
585156614414SEric Joyner 		ctx->ifc_vlan_attach_event = NULL;
585256614414SEric Joyner 	}
585356614414SEric Joyner 	if (ctx->ifc_vlan_detach_event != NULL) {
585456614414SEric Joyner 		EVENTHANDLER_DEREGISTER(vlan_unconfig, ctx->ifc_vlan_detach_event);
585556614414SEric Joyner 		ctx->ifc_vlan_detach_event = NULL;
585656614414SEric Joyner 	}
585756614414SEric Joyner 
58581558015eSEric Joyner }
58591558015eSEric Joyner 
58601558015eSEric Joyner static void
58611558015eSEric Joyner iflib_deregister(if_ctx_t ctx)
58621558015eSEric Joyner {
58631558015eSEric Joyner 	if_t ifp = ctx->ifc_ifp;
58641558015eSEric Joyner 
58651558015eSEric Joyner 	/* Remove all media */
58661558015eSEric Joyner 	ifmedia_removeall(&ctx->ifc_media);
58671558015eSEric Joyner 
58681558015eSEric Joyner 	/* Ensure that VLAN event handlers are unregistered */
58691558015eSEric Joyner 	iflib_unregister_vlan_handlers(ctx);
58701558015eSEric Joyner 
587156614414SEric Joyner 	/* Release kobject reference */
587256614414SEric Joyner 	kobj_delete((kobj_t) ctx, NULL);
587356614414SEric Joyner 
587456614414SEric Joyner 	/* Free the ifnet structure */
587556614414SEric Joyner 	if_free(ifp);
587656614414SEric Joyner 
587756614414SEric Joyner 	STATE_LOCK_DESTROY(ctx);
587856614414SEric Joyner 
587956614414SEric Joyner 	/* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/
588056614414SEric Joyner 	CTX_LOCK_DESTROY(ctx);
588156614414SEric Joyner }
588256614414SEric Joyner 
58834c7070dbSScott Long static int
58844c7070dbSScott Long iflib_queues_alloc(if_ctx_t ctx)
58854c7070dbSScott Long {
58864c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
588723ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
58884c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
588923ac9029SStephen Hurd 	int nrxqsets = scctx->isc_nrxqsets;
589023ac9029SStephen Hurd 	int ntxqsets = scctx->isc_ntxqsets;
58914c7070dbSScott Long 	iflib_txq_t txq;
58924c7070dbSScott Long 	iflib_rxq_t rxq;
58934c7070dbSScott Long 	iflib_fl_t fl = NULL;
589423ac9029SStephen Hurd 	int i, j, cpu, err, txconf, rxconf;
58954c7070dbSScott Long 	iflib_dma_info_t ifdip;
589623ac9029SStephen Hurd 	uint32_t *rxqsizes = scctx->isc_rxqsizes;
589723ac9029SStephen Hurd 	uint32_t *txqsizes = scctx->isc_txqsizes;
58984c7070dbSScott Long 	uint8_t nrxqs = sctx->isc_nrxqs;
58994c7070dbSScott Long 	uint8_t ntxqs = sctx->isc_ntxqs;
59004c7070dbSScott Long 	int nfree_lists = sctx->isc_nfl ? sctx->isc_nfl : 1;
59014ba9ad0dSVincenzo Maffione 	int fl_offset = (sctx->isc_flags & IFLIB_HAS_RXCQ ? 1 : 0);
59024c7070dbSScott Long 	caddr_t *vaddrs;
59034c7070dbSScott Long 	uint64_t *paddrs;
59044c7070dbSScott Long 
590523ac9029SStephen Hurd 	KASSERT(ntxqs > 0, ("number of queues per qset must be at least 1"));
590623ac9029SStephen Hurd 	KASSERT(nrxqs > 0, ("number of queues per qset must be at least 1"));
59074ba9ad0dSVincenzo Maffione 	KASSERT(nrxqs >= fl_offset + nfree_lists,
59084ba9ad0dSVincenzo Maffione            ("there must be at least a rxq for each free list"));
59094c7070dbSScott Long 
59104c7070dbSScott Long 	/* Allocate the TX ring struct memory */
5911b89827a0SStephen Hurd 	if (!(ctx->ifc_txqs =
5912ac2fffa4SPedro F. Giffuni 	    (iflib_txq_t) malloc(sizeof(struct iflib_txq) *
5913ac2fffa4SPedro F. Giffuni 	    ntxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) {
59144c7070dbSScott Long 		device_printf(dev, "Unable to allocate TX ring memory\n");
59154c7070dbSScott Long 		err = ENOMEM;
59164c7070dbSScott Long 		goto fail;
59174c7070dbSScott Long 	}
59184c7070dbSScott Long 
59194c7070dbSScott Long 	/* Now allocate the RX */
5920b89827a0SStephen Hurd 	if (!(ctx->ifc_rxqs =
5921ac2fffa4SPedro F. Giffuni 	    (iflib_rxq_t) malloc(sizeof(struct iflib_rxq) *
5922ac2fffa4SPedro F. Giffuni 	    nrxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) {
59234c7070dbSScott Long 		device_printf(dev, "Unable to allocate RX ring memory\n");
59244c7070dbSScott Long 		err = ENOMEM;
59254c7070dbSScott Long 		goto rx_fail;
59264c7070dbSScott Long 	}
59274c7070dbSScott Long 
5928b89827a0SStephen Hurd 	txq = ctx->ifc_txqs;
5929b89827a0SStephen Hurd 	rxq = ctx->ifc_rxqs;
59304c7070dbSScott Long 
59314c7070dbSScott Long 	/*
59324c7070dbSScott Long 	 * XXX handle allocation failure
59334c7070dbSScott Long 	 */
593496c85efbSNathan Whitehorn 	for (txconf = i = 0, cpu = CPU_FIRST(); i < ntxqsets; i++, txconf++, txq++, cpu = CPU_NEXT(cpu)) {
59354c7070dbSScott Long 		/* Set up some basics */
59364c7070dbSScott Long 
5937bfce461eSMarius Strobl 		if ((ifdip = malloc(sizeof(struct iflib_dma_info) * ntxqs,
5938bfce461eSMarius Strobl 		    M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
5939bfce461eSMarius Strobl 			device_printf(dev,
5940bfce461eSMarius Strobl 			    "Unable to allocate TX DMA info memory\n");
59414c7070dbSScott Long 			err = ENOMEM;
59420d0338afSConrad Meyer 			goto err_tx_desc;
59434c7070dbSScott Long 		}
59444c7070dbSScott Long 		txq->ift_ifdi = ifdip;
59454c7070dbSScott Long 		for (j = 0; j < ntxqs; j++, ifdip++) {
5946bfce461eSMarius Strobl 			if (iflib_dma_alloc(ctx, txqsizes[j], ifdip, 0)) {
5947bfce461eSMarius Strobl 				device_printf(dev,
5948bfce461eSMarius Strobl 				    "Unable to allocate TX descriptors\n");
59494c7070dbSScott Long 				err = ENOMEM;
59504c7070dbSScott Long 				goto err_tx_desc;
59514c7070dbSScott Long 			}
595295246abbSSean Bruno 			txq->ift_txd_size[j] = scctx->isc_txd_size[j];
59534c7070dbSScott Long 			bzero((void *)ifdip->idi_vaddr, txqsizes[j]);
59544c7070dbSScott Long 		}
59554c7070dbSScott Long 		txq->ift_ctx = ctx;
59564c7070dbSScott Long 		txq->ift_id = i;
595723ac9029SStephen Hurd 		if (sctx->isc_flags & IFLIB_HAS_TXCQ) {
595823ac9029SStephen Hurd 			txq->ift_br_offset = 1;
595923ac9029SStephen Hurd 		} else {
596023ac9029SStephen Hurd 			txq->ift_br_offset = 0;
596123ac9029SStephen Hurd 		}
59624c7070dbSScott Long 
59634c7070dbSScott Long 		if (iflib_txsd_alloc(txq)) {
59644c7070dbSScott Long 			device_printf(dev, "Critical Failure setting up TX buffers\n");
59654c7070dbSScott Long 			err = ENOMEM;
59664c7070dbSScott Long 			goto err_tx_desc;
59674c7070dbSScott Long 		}
59684c7070dbSScott Long 
59694c7070dbSScott Long 		/* Initialize the TX lock */
59701722eeacSMarius Strobl 		snprintf(txq->ift_mtx_name, MTX_NAME_LEN, "%s:TX(%d):callout",
59714c7070dbSScott Long 		    device_get_nameunit(dev), txq->ift_id);
59724c7070dbSScott Long 		mtx_init(&txq->ift_mtx, txq->ift_mtx_name, NULL, MTX_DEF);
59734c7070dbSScott Long 		callout_init_mtx(&txq->ift_timer, &txq->ift_mtx, 0);
597417cec474SVincenzo Maffione 		txq->ift_timer.c_cpu = cpu;
597517cec474SVincenzo Maffione #ifdef DEV_NETMAP
597617cec474SVincenzo Maffione 		callout_init_mtx(&txq->ift_netmap_timer, &txq->ift_mtx, 0);
597717cec474SVincenzo Maffione 		txq->ift_netmap_timer.c_cpu = cpu;
597817cec474SVincenzo Maffione #endif /* DEV_NETMAP */
59794c7070dbSScott Long 
598095246abbSSean Bruno 		err = ifmp_ring_alloc(&txq->ift_br, 2048, txq, iflib_txq_drain,
59814c7070dbSScott Long 				      iflib_txq_can_drain, M_IFLIB, M_WAITOK);
59824c7070dbSScott Long 		if (err) {
59834c7070dbSScott Long 			/* XXX free any allocated rings */
59844c7070dbSScott Long 			device_printf(dev, "Unable to allocate buf_ring\n");
59850d0338afSConrad Meyer 			goto err_tx_desc;
59864c7070dbSScott Long 		}
59874c7070dbSScott Long 	}
59884c7070dbSScott Long 
59894c7070dbSScott Long 	for (rxconf = i = 0; i < nrxqsets; i++, rxconf++, rxq++) {
59904c7070dbSScott Long 		/* Set up some basics */
5991fb1a29b4SHans Petter Selasky 		callout_init(&rxq->ifr_watchdog, 1);
59924c7070dbSScott Long 
5993bfce461eSMarius Strobl 		if ((ifdip = malloc(sizeof(struct iflib_dma_info) * nrxqs,
5994bfce461eSMarius Strobl 		   M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
5995bfce461eSMarius Strobl 			device_printf(dev,
5996bfce461eSMarius Strobl 			    "Unable to allocate RX DMA info memory\n");
59974c7070dbSScott Long 			err = ENOMEM;
59980d0338afSConrad Meyer 			goto err_tx_desc;
59994c7070dbSScott Long 		}
60004c7070dbSScott Long 
60014c7070dbSScott Long 		rxq->ifr_ifdi = ifdip;
600295246abbSSean Bruno 		/* XXX this needs to be changed if #rx queues != #tx queues */
600395246abbSSean Bruno 		rxq->ifr_ntxqirq = 1;
600495246abbSSean Bruno 		rxq->ifr_txqid[0] = i;
60054c7070dbSScott Long 		for (j = 0; j < nrxqs; j++, ifdip++) {
6006bfce461eSMarius Strobl 			if (iflib_dma_alloc(ctx, rxqsizes[j], ifdip, 0)) {
6007bfce461eSMarius Strobl 				device_printf(dev,
6008bfce461eSMarius Strobl 				    "Unable to allocate RX descriptors\n");
60094c7070dbSScott Long 				err = ENOMEM;
60104c7070dbSScott Long 				goto err_tx_desc;
60114c7070dbSScott Long 			}
60124c7070dbSScott Long 			bzero((void *)ifdip->idi_vaddr, rxqsizes[j]);
60134c7070dbSScott Long 		}
60144c7070dbSScott Long 		rxq->ifr_ctx = ctx;
60154c7070dbSScott Long 		rxq->ifr_id = i;
60164ba9ad0dSVincenzo Maffione 		rxq->ifr_fl_offset = fl_offset;
60174c7070dbSScott Long 		rxq->ifr_nfl = nfree_lists;
60184c7070dbSScott Long 		if (!(fl =
6019ac2fffa4SPedro F. Giffuni 			  (iflib_fl_t) malloc(sizeof(struct iflib_fl) * nfree_lists, M_IFLIB, M_NOWAIT | M_ZERO))) {
60204c7070dbSScott Long 			device_printf(dev, "Unable to allocate free list memory\n");
60214c7070dbSScott Long 			err = ENOMEM;
60220d0338afSConrad Meyer 			goto err_tx_desc;
60234c7070dbSScott Long 		}
60244c7070dbSScott Long 		rxq->ifr_fl = fl;
60254c7070dbSScott Long 		for (j = 0; j < nfree_lists; j++) {
602695246abbSSean Bruno 			fl[j].ifl_rxq = rxq;
602795246abbSSean Bruno 			fl[j].ifl_id = j;
602895246abbSSean Bruno 			fl[j].ifl_ifdi = &rxq->ifr_ifdi[j + rxq->ifr_fl_offset];
602995246abbSSean Bruno 			fl[j].ifl_rxd_size = scctx->isc_rxd_size[j];
60304c7070dbSScott Long 		}
60314c7070dbSScott Long 		/* Allocate receive buffers for the ring */
60324c7070dbSScott Long 		if (iflib_rxsd_alloc(rxq)) {
60334c7070dbSScott Long 			device_printf(dev,
60344c7070dbSScott Long 			    "Critical Failure setting up receive buffers\n");
60354c7070dbSScott Long 			err = ENOMEM;
60364c7070dbSScott Long 			goto err_rx_desc;
60374c7070dbSScott Long 		}
603887890dbaSSean Bruno 
603987890dbaSSean Bruno 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++)
60403db348b5SMarius Strobl 			fl->ifl_rx_bitmap = bit_alloc(fl->ifl_size, M_IFLIB,
60413db348b5SMarius Strobl 			    M_WAITOK);
60424c7070dbSScott Long 	}
60434c7070dbSScott Long 
60444c7070dbSScott Long 	/* TXQs */
60454c7070dbSScott Long 	vaddrs = malloc(sizeof(caddr_t)*ntxqsets*ntxqs, M_IFLIB, M_WAITOK);
60464c7070dbSScott Long 	paddrs = malloc(sizeof(uint64_t)*ntxqsets*ntxqs, M_IFLIB, M_WAITOK);
60474c7070dbSScott Long 	for (i = 0; i < ntxqsets; i++) {
60484c7070dbSScott Long 		iflib_dma_info_t di = ctx->ifc_txqs[i].ift_ifdi;
60494c7070dbSScott Long 
60504c7070dbSScott Long 		for (j = 0; j < ntxqs; j++, di++) {
60514c7070dbSScott Long 			vaddrs[i*ntxqs + j] = di->idi_vaddr;
60524c7070dbSScott Long 			paddrs[i*ntxqs + j] = di->idi_paddr;
60534c7070dbSScott Long 		}
60544c7070dbSScott Long 	}
60554c7070dbSScott Long 	if ((err = IFDI_TX_QUEUES_ALLOC(ctx, vaddrs, paddrs, ntxqs, ntxqsets)) != 0) {
6056bfce461eSMarius Strobl 		device_printf(ctx->ifc_dev,
6057bfce461eSMarius Strobl 		    "Unable to allocate device TX queue\n");
60584c7070dbSScott Long 		iflib_tx_structures_free(ctx);
60594c7070dbSScott Long 		free(vaddrs, M_IFLIB);
60604c7070dbSScott Long 		free(paddrs, M_IFLIB);
60614c7070dbSScott Long 		goto err_rx_desc;
60624c7070dbSScott Long 	}
60634c7070dbSScott Long 	free(vaddrs, M_IFLIB);
60644c7070dbSScott Long 	free(paddrs, M_IFLIB);
60654c7070dbSScott Long 
60664c7070dbSScott Long 	/* RXQs */
60674c7070dbSScott Long 	vaddrs = malloc(sizeof(caddr_t)*nrxqsets*nrxqs, M_IFLIB, M_WAITOK);
60684c7070dbSScott Long 	paddrs = malloc(sizeof(uint64_t)*nrxqsets*nrxqs, M_IFLIB, M_WAITOK);
60694c7070dbSScott Long 	for (i = 0; i < nrxqsets; i++) {
60704c7070dbSScott Long 		iflib_dma_info_t di = ctx->ifc_rxqs[i].ifr_ifdi;
60714c7070dbSScott Long 
60724c7070dbSScott Long 		for (j = 0; j < nrxqs; j++, di++) {
60734c7070dbSScott Long 			vaddrs[i*nrxqs + j] = di->idi_vaddr;
60744c7070dbSScott Long 			paddrs[i*nrxqs + j] = di->idi_paddr;
60754c7070dbSScott Long 		}
60764c7070dbSScott Long 	}
60774c7070dbSScott Long 	if ((err = IFDI_RX_QUEUES_ALLOC(ctx, vaddrs, paddrs, nrxqs, nrxqsets)) != 0) {
6078bfce461eSMarius Strobl 		device_printf(ctx->ifc_dev,
6079bfce461eSMarius Strobl 		    "Unable to allocate device RX queue\n");
60804c7070dbSScott Long 		iflib_tx_structures_free(ctx);
60814c7070dbSScott Long 		free(vaddrs, M_IFLIB);
60824c7070dbSScott Long 		free(paddrs, M_IFLIB);
60834c7070dbSScott Long 		goto err_rx_desc;
60844c7070dbSScott Long 	}
60854c7070dbSScott Long 	free(vaddrs, M_IFLIB);
60864c7070dbSScott Long 	free(paddrs, M_IFLIB);
60874c7070dbSScott Long 
60884c7070dbSScott Long 	return (0);
60894c7070dbSScott Long 
60904c7070dbSScott Long /* XXX handle allocation failure changes */
60914c7070dbSScott Long err_rx_desc:
60924c7070dbSScott Long err_tx_desc:
6093b89827a0SStephen Hurd rx_fail:
60944c7070dbSScott Long 	if (ctx->ifc_rxqs != NULL)
60954c7070dbSScott Long 		free(ctx->ifc_rxqs, M_IFLIB);
60964c7070dbSScott Long 	ctx->ifc_rxqs = NULL;
60974c7070dbSScott Long 	if (ctx->ifc_txqs != NULL)
60984c7070dbSScott Long 		free(ctx->ifc_txqs, M_IFLIB);
60994c7070dbSScott Long 	ctx->ifc_txqs = NULL;
61004c7070dbSScott Long fail:
61014c7070dbSScott Long 	return (err);
61024c7070dbSScott Long }
61034c7070dbSScott Long 
61044c7070dbSScott Long static int
61054c7070dbSScott Long iflib_tx_structures_setup(if_ctx_t ctx)
61064c7070dbSScott Long {
61074c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
61084c7070dbSScott Long 	int i;
61094c7070dbSScott Long 
61104c7070dbSScott Long 	for (i = 0; i < NTXQSETS(ctx); i++, txq++)
61114c7070dbSScott Long 		iflib_txq_setup(txq);
61124c7070dbSScott Long 
61134c7070dbSScott Long 	return (0);
61144c7070dbSScott Long }
61154c7070dbSScott Long 
61164c7070dbSScott Long static void
61174c7070dbSScott Long iflib_tx_structures_free(if_ctx_t ctx)
61184c7070dbSScott Long {
61194c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
61204d261ce2SStephen Hurd 	if_shared_ctx_t sctx = ctx->ifc_sctx;
61214c7070dbSScott Long 	int i, j;
61224c7070dbSScott Long 
61234c7070dbSScott Long 	for (i = 0; i < NTXQSETS(ctx); i++, txq++) {
61244d261ce2SStephen Hurd 		for (j = 0; j < sctx->isc_ntxqs; j++)
61254c7070dbSScott Long 			iflib_dma_free(&txq->ift_ifdi[j]);
6126244e7cffSEric Joyner 		iflib_txq_destroy(txq);
61274c7070dbSScott Long 	}
61284c7070dbSScott Long 	free(ctx->ifc_txqs, M_IFLIB);
61294c7070dbSScott Long 	ctx->ifc_txqs = NULL;
61304c7070dbSScott Long }
61314c7070dbSScott Long 
61324c7070dbSScott Long /*********************************************************************
61334c7070dbSScott Long  *
61344c7070dbSScott Long  *  Initialize all receive rings.
61354c7070dbSScott Long  *
61364c7070dbSScott Long  **********************************************************************/
61374c7070dbSScott Long static int
61384c7070dbSScott Long iflib_rx_structures_setup(if_ctx_t ctx)
61394c7070dbSScott Long {
61404c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
6141aaeb188aSBjoern A. Zeeb 	int q;
6142aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
61433d10e9edSMarius Strobl 	int err, i;
6144aaeb188aSBjoern A. Zeeb #endif
61454c7070dbSScott Long 
61464c7070dbSScott Long 	for (q = 0; q < ctx->ifc_softc_ctx.isc_nrxqsets; q++, rxq++) {
6147aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
61483d10e9edSMarius Strobl 		err = tcp_lro_init_args(&rxq->ifr_lc, ctx->ifc_ifp,
614923ac9029SStephen Hurd 		    TCP_LRO_ENTRIES, min(1024,
61503d10e9edSMarius Strobl 		    ctx->ifc_softc_ctx.isc_nrxd[rxq->ifr_fl_offset]));
61513d10e9edSMarius Strobl 		if (err != 0) {
61523d10e9edSMarius Strobl 			device_printf(ctx->ifc_dev,
61533d10e9edSMarius Strobl 			    "LRO Initialization failed!\n");
61544c7070dbSScott Long 			goto fail;
61554c7070dbSScott Long 		}
6156aaeb188aSBjoern A. Zeeb #endif
61574c7070dbSScott Long 		IFDI_RXQ_SETUP(ctx, rxq->ifr_id);
61584c7070dbSScott Long 	}
61594c7070dbSScott Long 	return (0);
6160aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
61614c7070dbSScott Long fail:
61624c7070dbSScott Long 	/*
61633d10e9edSMarius Strobl 	 * Free LRO resources allocated so far, we will only handle
61644c7070dbSScott Long 	 * the rings that completed, the failing case will have
61654c7070dbSScott Long 	 * cleaned up for itself.  'q' failed, so its the terminus.
61664c7070dbSScott Long 	 */
61674c7070dbSScott Long 	rxq = ctx->ifc_rxqs;
61684c7070dbSScott Long 	for (i = 0; i < q; ++i, rxq++) {
61693d10e9edSMarius Strobl 		tcp_lro_free(&rxq->ifr_lc);
61704c7070dbSScott Long 	}
61714c7070dbSScott Long 	return (err);
6172aaeb188aSBjoern A. Zeeb #endif
61734c7070dbSScott Long }
61744c7070dbSScott Long 
61754c7070dbSScott Long /*********************************************************************
61764c7070dbSScott Long  *
61774c7070dbSScott Long  *  Free all receive rings.
61784c7070dbSScott Long  *
61794c7070dbSScott Long  **********************************************************************/
61804c7070dbSScott Long static void
61814c7070dbSScott Long iflib_rx_structures_free(if_ctx_t ctx)
61824c7070dbSScott Long {
61834c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
6184db8e8f1eSEric Joyner 	if_shared_ctx_t sctx = ctx->ifc_sctx;
6185db8e8f1eSEric Joyner 	int i, j;
61864c7070dbSScott Long 
61873d10e9edSMarius Strobl 	for (i = 0; i < ctx->ifc_softc_ctx.isc_nrxqsets; i++, rxq++) {
6188db8e8f1eSEric Joyner 		for (j = 0; j < sctx->isc_nrxqs; j++)
6189db8e8f1eSEric Joyner 			iflib_dma_free(&rxq->ifr_ifdi[j]);
61904c7070dbSScott Long 		iflib_rx_sds_free(rxq);
6191007b804fSMarius Strobl #if defined(INET6) || defined(INET)
61923d10e9edSMarius Strobl 		tcp_lro_free(&rxq->ifr_lc);
6193007b804fSMarius Strobl #endif
61944c7070dbSScott Long 	}
619577c1fcecSEric Joyner 	free(ctx->ifc_rxqs, M_IFLIB);
619677c1fcecSEric Joyner 	ctx->ifc_rxqs = NULL;
61974c7070dbSScott Long }
61984c7070dbSScott Long 
61994c7070dbSScott Long static int
62004c7070dbSScott Long iflib_qset_structures_setup(if_ctx_t ctx)
62014c7070dbSScott Long {
62024c7070dbSScott Long 	int err;
62034c7070dbSScott Long 
62046108c013SStephen Hurd 	/*
62056108c013SStephen Hurd 	 * It is expected that the caller takes care of freeing queues if this
62066108c013SStephen Hurd 	 * fails.
62076108c013SStephen Hurd 	 */
6208ac88e6daSStephen Hurd 	if ((err = iflib_tx_structures_setup(ctx)) != 0) {
6209ac88e6daSStephen Hurd 		device_printf(ctx->ifc_dev, "iflib_tx_structures_setup failed: %d\n", err);
62104c7070dbSScott Long 		return (err);
6211ac88e6daSStephen Hurd 	}
62124c7070dbSScott Long 
62136108c013SStephen Hurd 	if ((err = iflib_rx_structures_setup(ctx)) != 0)
62144c7070dbSScott Long 		device_printf(ctx->ifc_dev, "iflib_rx_structures_setup failed: %d\n", err);
62156108c013SStephen Hurd 
62164c7070dbSScott Long 	return (err);
62174c7070dbSScott Long }
62184c7070dbSScott Long 
62194c7070dbSScott Long int
62204c7070dbSScott Long iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid,
62213e0e6330SStephen Hurd 		driver_filter_t filter, void *filter_arg, driver_intr_t handler, void *arg, const char *name)
62224c7070dbSScott Long {
62234c7070dbSScott Long 
62244c7070dbSScott Long 	return (_iflib_irq_alloc(ctx, irq, rid, filter, handler, arg, name));
62254c7070dbSScott Long }
62264c7070dbSScott Long 
6227b103855eSStephen Hurd /* Just to avoid copy/paste */
6228b103855eSStephen Hurd static inline int
6229f855ec81SMarius Strobl iflib_irq_set_affinity(if_ctx_t ctx, if_irq_t irq, iflib_intr_type_t type,
6230f855ec81SMarius Strobl     int qid, struct grouptask *gtask, struct taskqgroup *tqg, void *uniq,
6231f855ec81SMarius Strobl     const char *name)
6232b103855eSStephen Hurd {
6233f855ec81SMarius Strobl 	device_t dev;
6234*ca7005f1SPatrick Kelsey 	unsigned int base_cpuid, cpuid;
6235*ca7005f1SPatrick Kelsey 	int err;
6236b103855eSStephen Hurd 
6237f855ec81SMarius Strobl 	dev = ctx->ifc_dev;
6238*ca7005f1SPatrick Kelsey 	base_cpuid = ctx->ifc_sysctl_core_offset;
6239*ca7005f1SPatrick Kelsey 	cpuid = get_cpuid_for_queue(ctx, base_cpuid, qid, type == IFLIB_INTR_TX);
6240*ca7005f1SPatrick Kelsey 	err = taskqgroup_attach_cpu(tqg, gtask, uniq, cpuid, dev,
6241*ca7005f1SPatrick Kelsey 	    irq ? irq->ii_res : NULL, name);
6242b103855eSStephen Hurd 	if (err) {
6243f855ec81SMarius Strobl 		device_printf(dev, "taskqgroup_attach_cpu failed %d\n", err);
6244b103855eSStephen Hurd 		return (err);
6245b103855eSStephen Hurd 	}
6246b103855eSStephen Hurd #ifdef notyet
6247b103855eSStephen Hurd 	if (cpuid > ctx->ifc_cpuid_highest)
6248b103855eSStephen Hurd 		ctx->ifc_cpuid_highest = cpuid;
6249b103855eSStephen Hurd #endif
62503d10e9edSMarius Strobl 	return (0);
6251b103855eSStephen Hurd }
6252b103855eSStephen Hurd 
62534c7070dbSScott Long int
62544c7070dbSScott Long iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid,
62554c7070dbSScott Long 			iflib_intr_type_t type, driver_filter_t *filter,
62563e0e6330SStephen Hurd 			void *filter_arg, int qid, const char *name)
62574c7070dbSScott Long {
6258f855ec81SMarius Strobl 	device_t dev;
62594c7070dbSScott Long 	struct grouptask *gtask;
62604c7070dbSScott Long 	struct taskqgroup *tqg;
62614c7070dbSScott Long 	iflib_filter_info_t info;
626223ac9029SStephen Hurd 	gtask_fn_t *fn;
6263b103855eSStephen Hurd 	int tqrid, err;
626495246abbSSean Bruno 	driver_filter_t *intr_fast;
62654c7070dbSScott Long 	void *q;
62664c7070dbSScott Long 
62674c7070dbSScott Long 	info = &ctx->ifc_filter_info;
6268add6f7d0SSean Bruno 	tqrid = rid;
62694c7070dbSScott Long 
62704c7070dbSScott Long 	switch (type) {
62714c7070dbSScott Long 	/* XXX merge tx/rx for netmap? */
62724c7070dbSScott Long 	case IFLIB_INTR_TX:
62734c7070dbSScott Long 		q = &ctx->ifc_txqs[qid];
62744c7070dbSScott Long 		info = &ctx->ifc_txqs[qid].ift_filter_info;
62754c7070dbSScott Long 		gtask = &ctx->ifc_txqs[qid].ift_task;
6276ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
62774c7070dbSScott Long 		fn = _task_fn_tx;
627895246abbSSean Bruno 		intr_fast = iflib_fast_intr;
6279da69b8f9SSean Bruno 		GROUPTASK_INIT(gtask, 0, fn, q);
62805ee36c68SStephen Hurd 		ctx->ifc_flags |= IFC_NETMAP_TX_IRQ;
62814c7070dbSScott Long 		break;
62824c7070dbSScott Long 	case IFLIB_INTR_RX:
62834c7070dbSScott Long 		q = &ctx->ifc_rxqs[qid];
62844c7070dbSScott Long 		info = &ctx->ifc_rxqs[qid].ifr_filter_info;
62854c7070dbSScott Long 		gtask = &ctx->ifc_rxqs[qid].ifr_task;
6286ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
62874c7070dbSScott Long 		fn = _task_fn_rx;
6288ab2e3f79SStephen Hurd 		intr_fast = iflib_fast_intr;
62896c3e93cbSGleb Smirnoff 		NET_GROUPTASK_INIT(gtask, 0, fn, q);
629095246abbSSean Bruno 		break;
629195246abbSSean Bruno 	case IFLIB_INTR_RXTX:
629295246abbSSean Bruno 		q = &ctx->ifc_rxqs[qid];
629395246abbSSean Bruno 		info = &ctx->ifc_rxqs[qid].ifr_filter_info;
629495246abbSSean Bruno 		gtask = &ctx->ifc_rxqs[qid].ifr_task;
6295ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
629695246abbSSean Bruno 		fn = _task_fn_rx;
629795246abbSSean Bruno 		intr_fast = iflib_fast_intr_rxtx;
62986c3e93cbSGleb Smirnoff 		NET_GROUPTASK_INIT(gtask, 0, fn, q);
62994c7070dbSScott Long 		break;
63004c7070dbSScott Long 	case IFLIB_INTR_ADMIN:
63014c7070dbSScott Long 		q = ctx;
6302da69b8f9SSean Bruno 		tqrid = -1;
63034c7070dbSScott Long 		info = &ctx->ifc_filter_info;
63044c7070dbSScott Long 		gtask = &ctx->ifc_admin_task;
6305ab2e3f79SStephen Hurd 		tqg = qgroup_if_config_tqg;
63064c7070dbSScott Long 		fn = _task_fn_admin;
630795246abbSSean Bruno 		intr_fast = iflib_fast_intr_ctx;
63084c7070dbSScott Long 		break;
63094c7070dbSScott Long 	default:
63103d10e9edSMarius Strobl 		device_printf(ctx->ifc_dev, "%s: unknown net intr type\n",
63113d10e9edSMarius Strobl 		    __func__);
63123d10e9edSMarius Strobl 		return (EINVAL);
63134c7070dbSScott Long 	}
63144c7070dbSScott Long 
63154c7070dbSScott Long 	info->ifi_filter = filter;
63164c7070dbSScott Long 	info->ifi_filter_arg = filter_arg;
63174c7070dbSScott Long 	info->ifi_task = gtask;
631895246abbSSean Bruno 	info->ifi_ctx = q;
63194c7070dbSScott Long 
6320f855ec81SMarius Strobl 	dev = ctx->ifc_dev;
632195246abbSSean Bruno 	err = _iflib_irq_alloc(ctx, irq, rid, intr_fast, NULL, info,  name);
6322da69b8f9SSean Bruno 	if (err != 0) {
6323f855ec81SMarius Strobl 		device_printf(dev, "_iflib_irq_alloc failed %d\n", err);
63244c7070dbSScott Long 		return (err);
6325da69b8f9SSean Bruno 	}
6326da69b8f9SSean Bruno 	if (type == IFLIB_INTR_ADMIN)
6327da69b8f9SSean Bruno 		return (0);
6328da69b8f9SSean Bruno 
63294c7070dbSScott Long 	if (tqrid != -1) {
6330*ca7005f1SPatrick Kelsey 		err = iflib_irq_set_affinity(ctx, irq, type, qid, gtask, tqg, q,
6331*ca7005f1SPatrick Kelsey 		    name);
6332b103855eSStephen Hurd 		if (err)
6333b103855eSStephen Hurd 			return (err);
6334aa3c5dd8SSean Bruno 	} else {
6335f855ec81SMarius Strobl 		taskqgroup_attach(tqg, gtask, q, dev, irq->ii_res, name);
6336aa3c5dd8SSean Bruno 	}
63374c7070dbSScott Long 
63384c7070dbSScott Long 	return (0);
63394c7070dbSScott Long }
63404c7070dbSScott Long 
63414c7070dbSScott Long void
63423e0e6330SStephen 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)
63434c7070dbSScott Long {
6344*ca7005f1SPatrick Kelsey 	device_t dev;
63454c7070dbSScott Long 	struct grouptask *gtask;
63464c7070dbSScott Long 	struct taskqgroup *tqg;
634723ac9029SStephen Hurd 	gtask_fn_t *fn;
63484c7070dbSScott Long 	void *q;
6349b103855eSStephen Hurd 	int err;
63504c7070dbSScott Long 
63514c7070dbSScott Long 	switch (type) {
63524c7070dbSScott Long 	case IFLIB_INTR_TX:
63534c7070dbSScott Long 		q = &ctx->ifc_txqs[qid];
63544c7070dbSScott Long 		gtask = &ctx->ifc_txqs[qid].ift_task;
6355ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
63564c7070dbSScott Long 		fn = _task_fn_tx;
6357f98977b5SHans Petter Selasky 		GROUPTASK_INIT(gtask, 0, fn, q);
63584c7070dbSScott Long 		break;
63594c7070dbSScott Long 	case IFLIB_INTR_RX:
63604c7070dbSScott Long 		q = &ctx->ifc_rxqs[qid];
63614c7070dbSScott Long 		gtask = &ctx->ifc_rxqs[qid].ifr_task;
6362ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
63634c7070dbSScott Long 		fn = _task_fn_rx;
6364f98977b5SHans Petter Selasky 		NET_GROUPTASK_INIT(gtask, 0, fn, q);
63654c7070dbSScott Long 		break;
63664c7070dbSScott Long 	case IFLIB_INTR_IOV:
63674c7070dbSScott Long 		q = ctx;
63684c7070dbSScott Long 		gtask = &ctx->ifc_vflr_task;
6369ab2e3f79SStephen Hurd 		tqg = qgroup_if_config_tqg;
63704c7070dbSScott Long 		fn = _task_fn_iov;
6371f98977b5SHans Petter Selasky 		GROUPTASK_INIT(gtask, 0, fn, q);
63724c7070dbSScott Long 		break;
63734c7070dbSScott Long 	default:
63744c7070dbSScott Long 		panic("unknown net intr type");
63754c7070dbSScott Long 	}
6376*ca7005f1SPatrick Kelsey 	err = iflib_irq_set_affinity(ctx, irq, type, qid, gtask, tqg, q, name);
6377*ca7005f1SPatrick Kelsey 	if (err) {
6378*ca7005f1SPatrick Kelsey 		dev = ctx->ifc_dev;
6379*ca7005f1SPatrick Kelsey 		taskqgroup_attach(tqg, gtask, q, dev, irq ? irq->ii_res : NULL,
6380*ca7005f1SPatrick Kelsey 		    name);
6381b103855eSStephen Hurd 	}
6382b103855eSStephen Hurd }
63834c7070dbSScott Long 
63844c7070dbSScott Long void
63854c7070dbSScott Long iflib_irq_free(if_ctx_t ctx, if_irq_t irq)
63864c7070dbSScott Long {
6387b97de13aSMarius Strobl 
63884c7070dbSScott Long 	if (irq->ii_tag)
63894c7070dbSScott Long 		bus_teardown_intr(ctx->ifc_dev, irq->ii_res, irq->ii_tag);
63904c7070dbSScott Long 
63914c7070dbSScott Long 	if (irq->ii_res)
6392b97de13aSMarius Strobl 		bus_release_resource(ctx->ifc_dev, SYS_RES_IRQ,
6393b97de13aSMarius Strobl 		    rman_get_rid(irq->ii_res), irq->ii_res);
63944c7070dbSScott Long }
63954c7070dbSScott Long 
63964c7070dbSScott Long static int
63973e0e6330SStephen Hurd iflib_legacy_setup(if_ctx_t ctx, driver_filter_t filter, void *filter_arg, int *rid, const char *name)
63984c7070dbSScott Long {
63994c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
64004c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
64014c7070dbSScott Long 	if_irq_t irq = &ctx->ifc_legacy_irq;
64024c7070dbSScott Long 	iflib_filter_info_t info;
6403f855ec81SMarius Strobl 	device_t dev;
64044c7070dbSScott Long 	struct grouptask *gtask;
6405f855ec81SMarius Strobl 	struct resource *res;
64064c7070dbSScott Long 	struct taskqgroup *tqg;
64074c7070dbSScott Long 	void *q;
6408d49e83eaSMarius Strobl 	int err, tqrid;
640941669133SMark Johnston 	bool rx_only;
64104c7070dbSScott Long 
64114c7070dbSScott Long 	q = &ctx->ifc_rxqs[0];
64124c7070dbSScott Long 	info = &rxq[0].ifr_filter_info;
64134c7070dbSScott Long 	gtask = &rxq[0].ifr_task;
6414ab2e3f79SStephen Hurd 	tqg = qgroup_if_io_tqg;
6415d49e83eaSMarius Strobl 	tqrid = *rid;
641641669133SMark Johnston 	rx_only = (ctx->ifc_sctx->isc_flags & IFLIB_SINGLE_IRQ_RX_ONLY) != 0;
64174c7070dbSScott Long 
64184c7070dbSScott Long 	ctx->ifc_flags |= IFC_LEGACY;
64194c7070dbSScott Long 	info->ifi_filter = filter;
64204c7070dbSScott Long 	info->ifi_filter_arg = filter_arg;
64214c7070dbSScott Long 	info->ifi_task = gtask;
642241669133SMark Johnston 	info->ifi_ctx = rx_only ? ctx : q;
64234c7070dbSScott Long 
6424f855ec81SMarius Strobl 	dev = ctx->ifc_dev;
64254c7070dbSScott Long 	/* We allocate a single interrupt resource */
642641669133SMark Johnston 	err = _iflib_irq_alloc(ctx, irq, tqrid, rx_only ? iflib_fast_intr_ctx :
642741669133SMark Johnston 	    iflib_fast_intr_rxtx, NULL, info, name);
642841669133SMark Johnston 	if (err != 0)
64294c7070dbSScott Long 		return (err);
6430f98977b5SHans Petter Selasky 	NET_GROUPTASK_INIT(gtask, 0, _task_fn_rx, q);
6431f855ec81SMarius Strobl 	res = irq->ii_res;
6432f855ec81SMarius Strobl 	taskqgroup_attach(tqg, gtask, q, dev, res, name);
64334c7070dbSScott Long 
64344c7070dbSScott Long 	GROUPTASK_INIT(&txq->ift_task, 0, _task_fn_tx, txq);
6435f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_io_tqg, &txq->ift_task, txq, dev, res,
6436f855ec81SMarius Strobl 	    "tx");
64374c7070dbSScott Long 	return (0);
64384c7070dbSScott Long }
64394c7070dbSScott Long 
64404c7070dbSScott Long void
64414c7070dbSScott Long iflib_led_create(if_ctx_t ctx)
64424c7070dbSScott Long {
64434c7070dbSScott Long 
64444c7070dbSScott Long 	ctx->ifc_led_dev = led_create(iflib_led_func, ctx,
64454c7070dbSScott Long 	    device_get_nameunit(ctx->ifc_dev));
64464c7070dbSScott Long }
64474c7070dbSScott Long 
64484c7070dbSScott Long void
64494c7070dbSScott Long iflib_tx_intr_deferred(if_ctx_t ctx, int txqid)
64504c7070dbSScott Long {
64514c7070dbSScott Long 
64524c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_txqs[txqid].ift_task);
64534c7070dbSScott Long }
64544c7070dbSScott Long 
64554c7070dbSScott Long void
64564c7070dbSScott Long iflib_rx_intr_deferred(if_ctx_t ctx, int rxqid)
64574c7070dbSScott Long {
64584c7070dbSScott Long 
64594c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_rxqs[rxqid].ifr_task);
64604c7070dbSScott Long }
64614c7070dbSScott Long 
64624c7070dbSScott Long void
64634c7070dbSScott Long iflib_admin_intr_deferred(if_ctx_t ctx)
64644c7070dbSScott Long {
646546fa0c25SEric Joyner 
6466ed6611ccSEd Maste 	MPASS(ctx->ifc_admin_task.gt_taskqueue != NULL);
64674c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_admin_task);
64684c7070dbSScott Long }
64694c7070dbSScott Long 
64704c7070dbSScott Long void
64714c7070dbSScott Long iflib_iov_intr_deferred(if_ctx_t ctx)
64724c7070dbSScott Long {
64734c7070dbSScott Long 
64744c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_vflr_task);
64754c7070dbSScott Long }
64764c7070dbSScott Long 
64774c7070dbSScott Long void
6478d49e83eaSMarius Strobl iflib_io_tqg_attach(struct grouptask *gt, void *uniq, int cpu, const char *name)
64794c7070dbSScott Long {
64804c7070dbSScott Long 
6481f855ec81SMarius Strobl 	taskqgroup_attach_cpu(qgroup_if_io_tqg, gt, uniq, cpu, NULL, NULL,
6482f855ec81SMarius Strobl 	    name);
64834c7070dbSScott Long }
64844c7070dbSScott Long 
64854c7070dbSScott Long void
6486aa8a24d3SStephen Hurd iflib_config_gtask_init(void *ctx, struct grouptask *gtask, gtask_fn_t *fn,
6487aa8a24d3SStephen Hurd 	const char *name)
64884c7070dbSScott Long {
64894c7070dbSScott Long 
64904c7070dbSScott Long 	GROUPTASK_INIT(gtask, 0, fn, ctx);
6491f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_config_tqg, gtask, gtask, NULL, NULL,
6492f855ec81SMarius Strobl 	    name);
64934c7070dbSScott Long }
64944c7070dbSScott Long 
64954c7070dbSScott Long void
649623ac9029SStephen Hurd iflib_config_gtask_deinit(struct grouptask *gtask)
649723ac9029SStephen Hurd {
649823ac9029SStephen Hurd 
6499ab2e3f79SStephen Hurd 	taskqgroup_detach(qgroup_if_config_tqg, gtask);
650023ac9029SStephen Hurd }
650123ac9029SStephen Hurd 
650223ac9029SStephen Hurd void
650323ac9029SStephen Hurd iflib_link_state_change(if_ctx_t ctx, int link_state, uint64_t baudrate)
65044c7070dbSScott Long {
65054c7070dbSScott Long 	if_t ifp = ctx->ifc_ifp;
65064c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
65074c7070dbSScott Long 
65084c7070dbSScott Long 	if_setbaudrate(ifp, baudrate);
65097b610b60SSean Bruno 	if (baudrate >= IF_Gbps(10)) {
65107b610b60SSean Bruno 		STATE_LOCK(ctx);
651195246abbSSean Bruno 		ctx->ifc_flags |= IFC_PREFETCH;
65127b610b60SSean Bruno 		STATE_UNLOCK(ctx);
65137b610b60SSean Bruno 	}
65144c7070dbSScott Long 	/* If link down, disable watchdog */
65154c7070dbSScott Long 	if ((ctx->ifc_link_state == LINK_STATE_UP) && (link_state == LINK_STATE_DOWN)) {
65164c7070dbSScott Long 		for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxqsets; i++, txq++)
65174c7070dbSScott Long 			txq->ift_qstatus = IFLIB_QUEUE_IDLE;
65184c7070dbSScott Long 	}
65194c7070dbSScott Long 	ctx->ifc_link_state = link_state;
65204c7070dbSScott Long 	if_link_state_change(ifp, link_state);
65214c7070dbSScott Long }
65224c7070dbSScott Long 
65234c7070dbSScott Long static int
65244c7070dbSScott Long iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq)
65254c7070dbSScott Long {
65264c7070dbSScott Long 	int credits;
65271248952aSSean Bruno #ifdef INVARIANTS
65281248952aSSean Bruno 	int credits_pre = txq->ift_cidx_processed;
65291248952aSSean Bruno #endif
65304c7070dbSScott Long 
65318a04b53dSKonstantin Belousov 	bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
65328a04b53dSKonstantin Belousov 	    BUS_DMASYNC_POSTREAD);
653395246abbSSean Bruno 	if ((credits = ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, true)) == 0)
65344c7070dbSScott Long 		return (0);
65354c7070dbSScott Long 
65364c7070dbSScott Long 	txq->ift_processed += credits;
65374c7070dbSScott Long 	txq->ift_cidx_processed += credits;
65384c7070dbSScott Long 
65391248952aSSean Bruno 	MPASS(credits_pre + credits == txq->ift_cidx_processed);
65404c7070dbSScott Long 	if (txq->ift_cidx_processed >= txq->ift_size)
65414c7070dbSScott Long 		txq->ift_cidx_processed -= txq->ift_size;
65424c7070dbSScott Long 	return (credits);
65434c7070dbSScott Long }
65444c7070dbSScott Long 
65454c7070dbSScott Long static int
654695246abbSSean Bruno iflib_rxd_avail(if_ctx_t ctx, iflib_rxq_t rxq, qidx_t cidx, qidx_t budget)
65474c7070dbSScott Long {
654895dcf343SMarius Strobl 	iflib_fl_t fl;
654995dcf343SMarius Strobl 	u_int i;
65504c7070dbSScott Long 
655195dcf343SMarius Strobl 	for (i = 0, fl = &rxq->ifr_fl[0]; i < rxq->ifr_nfl; i++, fl++)
655295dcf343SMarius Strobl 		bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
655395dcf343SMarius Strobl 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
655423ac9029SStephen Hurd 	return (ctx->isc_rxd_available(ctx->ifc_softc, rxq->ifr_id, cidx,
655523ac9029SStephen Hurd 	    budget));
65564c7070dbSScott Long }
65574c7070dbSScott Long 
65584c7070dbSScott Long void
65594c7070dbSScott Long iflib_add_int_delay_sysctl(if_ctx_t ctx, const char *name,
65604c7070dbSScott Long 	const char *description, if_int_delay_info_t info,
65614c7070dbSScott Long 	int offset, int value)
65624c7070dbSScott Long {
65634c7070dbSScott Long 	info->iidi_ctx = ctx;
65644c7070dbSScott Long 	info->iidi_offset = offset;
65654c7070dbSScott Long 	info->iidi_value = value;
65664c7070dbSScott Long 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(ctx->ifc_dev),
65674c7070dbSScott Long 	    SYSCTL_CHILDREN(device_get_sysctl_tree(ctx->ifc_dev)),
65687029da5cSPawel Biernacki 	    OID_AUTO, name, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
65694c7070dbSScott Long 	    info, 0, iflib_sysctl_int_delay, "I", description);
65704c7070dbSScott Long }
65714c7070dbSScott Long 
6572aa8a24d3SStephen Hurd struct sx *
65734c7070dbSScott Long iflib_ctx_lock_get(if_ctx_t ctx)
65744c7070dbSScott Long {
65754c7070dbSScott Long 
6576aa8a24d3SStephen Hurd 	return (&ctx->ifc_ctx_sx);
65774c7070dbSScott Long }
65784c7070dbSScott Long 
65794c7070dbSScott Long static int
65804c7070dbSScott Long iflib_msix_init(if_ctx_t ctx)
65814c7070dbSScott Long {
65824c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
65834c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
65844c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
65853d10e9edSMarius Strobl 	int admincnt, bar, err, iflib_num_rx_queues, iflib_num_tx_queues;
65863d10e9edSMarius Strobl 	int msgs, queuemsgs, queues, rx_queues, tx_queues, vectors;
65874c7070dbSScott Long 
6588d2735264SStephen Hurd 	iflib_num_tx_queues = ctx->ifc_sysctl_ntxqs;
6589d2735264SStephen Hurd 	iflib_num_rx_queues = ctx->ifc_sysctl_nrxqs;
659023ac9029SStephen Hurd 
6591b97de13aSMarius Strobl 	if (bootverbose)
6592b97de13aSMarius Strobl 		device_printf(dev, "msix_init qsets capped at %d\n",
6593b97de13aSMarius Strobl 		    imax(scctx->isc_ntxqsets, scctx->isc_nrxqsets));
65941248952aSSean Bruno 
65954c7070dbSScott Long 	/* Override by tuneable */
6596ea351d3fSSean Bruno 	if (scctx->isc_disable_msix)
65974c7070dbSScott Long 		goto msi;
65984c7070dbSScott Long 
6599b97de13aSMarius Strobl 	/* First try MSI-X */
6600b97de13aSMarius Strobl 	if ((msgs = pci_msix_count(dev)) == 0) {
6601b97de13aSMarius Strobl 		if (bootverbose)
6602b97de13aSMarius Strobl 			device_printf(dev, "MSI-X not supported or disabled\n");
6603b97de13aSMarius Strobl 		goto msi;
6604b97de13aSMarius Strobl 	}
66053d10e9edSMarius Strobl 
66063d10e9edSMarius Strobl 	bar = ctx->ifc_softc_ctx.isc_msix_bar;
66074c7070dbSScott Long 	/*
66084c7070dbSScott Long 	 * bar == -1 => "trust me I know what I'm doing"
66094c7070dbSScott Long 	 * Some drivers are for hardware that is so shoddily
66104c7070dbSScott Long 	 * documented that no one knows which bars are which
66114c7070dbSScott Long 	 * so the developer has to map all bars. This hack
6612b97de13aSMarius Strobl 	 * allows shoddy garbage to use MSI-X in this framework.
66134c7070dbSScott Long 	 */
66144c7070dbSScott Long 	if (bar != -1) {
66154c7070dbSScott Long 		ctx->ifc_msix_mem = bus_alloc_resource_any(dev,
66164c7070dbSScott Long 	            SYS_RES_MEMORY, &bar, RF_ACTIVE);
66174c7070dbSScott Long 		if (ctx->ifc_msix_mem == NULL) {
6618b97de13aSMarius Strobl 			device_printf(dev, "Unable to map MSI-X table\n");
66194c7070dbSScott Long 			goto msi;
66204c7070dbSScott Long 		}
66214c7070dbSScott Long 	}
66223d10e9edSMarius Strobl 
66233d10e9edSMarius Strobl 	admincnt = sctx->isc_admin_intrcnt;
66244c7070dbSScott Long #if IFLIB_DEBUG
66254c7070dbSScott Long 	/* use only 1 qset in debug mode */
66264c7070dbSScott Long 	queuemsgs = min(msgs - admincnt, 1);
66274c7070dbSScott Long #else
66284c7070dbSScott Long 	queuemsgs = msgs - admincnt;
66294c7070dbSScott Long #endif
66304c7070dbSScott Long #ifdef RSS
66314c7070dbSScott Long 	queues = imin(queuemsgs, rss_getnumbuckets());
66324c7070dbSScott Long #else
66334c7070dbSScott Long 	queues = queuemsgs;
66344c7070dbSScott Long #endif
66354c7070dbSScott Long 	queues = imin(CPU_COUNT(&ctx->ifc_cpus), queues);
6636b97de13aSMarius Strobl 	if (bootverbose)
6637b97de13aSMarius Strobl 		device_printf(dev,
6638b97de13aSMarius Strobl 		    "intr CPUs: %d queue msgs: %d admincnt: %d\n",
66394c7070dbSScott Long 		    CPU_COUNT(&ctx->ifc_cpus), queuemsgs, admincnt);
66404c7070dbSScott Long #ifdef  RSS
66414c7070dbSScott Long 	/* If we're doing RSS, clamp at the number of RSS buckets */
66424c7070dbSScott Long 	if (queues > rss_getnumbuckets())
66434c7070dbSScott Long 		queues = rss_getnumbuckets();
66444c7070dbSScott Long #endif
664523ac9029SStephen Hurd 	if (iflib_num_rx_queues > 0 && iflib_num_rx_queues < queuemsgs - admincnt)
664623ac9029SStephen Hurd 		rx_queues = iflib_num_rx_queues;
66474c7070dbSScott Long 	else
66484c7070dbSScott Long 		rx_queues = queues;
6649d2735264SStephen Hurd 
6650d2735264SStephen Hurd 	if (rx_queues > scctx->isc_nrxqsets)
6651d2735264SStephen Hurd 		rx_queues = scctx->isc_nrxqsets;
6652d2735264SStephen Hurd 
665323ac9029SStephen Hurd 	/*
665423ac9029SStephen Hurd 	 * We want this to be all logical CPUs by default
665523ac9029SStephen Hurd 	 */
66564c7070dbSScott Long 	if (iflib_num_tx_queues > 0 && iflib_num_tx_queues < queues)
66574c7070dbSScott Long 		tx_queues = iflib_num_tx_queues;
66584c7070dbSScott Long 	else
665923ac9029SStephen Hurd 		tx_queues = mp_ncpus;
666023ac9029SStephen Hurd 
6661d2735264SStephen Hurd 	if (tx_queues > scctx->isc_ntxqsets)
6662d2735264SStephen Hurd 		tx_queues = scctx->isc_ntxqsets;
6663d2735264SStephen Hurd 
666423ac9029SStephen Hurd 	if (ctx->ifc_sysctl_qs_eq_override == 0) {
666523ac9029SStephen Hurd #ifdef INVARIANTS
666623ac9029SStephen Hurd 		if (tx_queues != rx_queues)
666777c1fcecSEric Joyner 			device_printf(dev,
666877c1fcecSEric Joyner 			    "queue equality override not set, capping rx_queues at %d and tx_queues at %d\n",
666923ac9029SStephen Hurd 			    min(rx_queues, tx_queues), min(rx_queues, tx_queues));
667023ac9029SStephen Hurd #endif
667123ac9029SStephen Hurd 		tx_queues = min(rx_queues, tx_queues);
667223ac9029SStephen Hurd 		rx_queues = min(rx_queues, tx_queues);
667323ac9029SStephen Hurd 	}
66744c7070dbSScott Long 
66753d10e9edSMarius Strobl 	vectors = rx_queues + admincnt;
66763d10e9edSMarius Strobl 	if (msgs < vectors) {
66773d10e9edSMarius Strobl 		device_printf(dev,
66783d10e9edSMarius Strobl 		    "insufficient number of MSI-X vectors "
66793d10e9edSMarius Strobl 		    "(supported %d, need %d)\n", msgs, vectors);
66803d10e9edSMarius Strobl 		goto msi;
66813d10e9edSMarius Strobl 	}
66823d10e9edSMarius Strobl 
66831722eeacSMarius Strobl 	device_printf(dev, "Using %d RX queues %d TX queues\n", rx_queues,
66841722eeacSMarius Strobl 	    tx_queues);
66853d10e9edSMarius Strobl 	msgs = vectors;
66864c7070dbSScott Long 	if ((err = pci_alloc_msix(dev, &vectors)) == 0) {
66873d10e9edSMarius Strobl 		if (vectors != msgs) {
66883d10e9edSMarius Strobl 			device_printf(dev,
66893d10e9edSMarius Strobl 			    "Unable to allocate sufficient MSI-X vectors "
66903d10e9edSMarius Strobl 			    "(got %d, need %d)\n", vectors, msgs);
66913d10e9edSMarius Strobl 			pci_release_msi(dev);
66923d10e9edSMarius Strobl 			if (bar != -1) {
66933d10e9edSMarius Strobl 				bus_release_resource(dev, SYS_RES_MEMORY, bar,
66943d10e9edSMarius Strobl 				    ctx->ifc_msix_mem);
66953d10e9edSMarius Strobl 				ctx->ifc_msix_mem = NULL;
66963d10e9edSMarius Strobl 			}
66973d10e9edSMarius Strobl 			goto msi;
66983d10e9edSMarius Strobl 		}
6699b97de13aSMarius Strobl 		device_printf(dev, "Using MSI-X interrupts with %d vectors\n",
6700b97de13aSMarius Strobl 		    vectors);
67014c7070dbSScott Long 		scctx->isc_vectors = vectors;
67024c7070dbSScott Long 		scctx->isc_nrxqsets = rx_queues;
67034c7070dbSScott Long 		scctx->isc_ntxqsets = tx_queues;
67044c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_MSIX;
670523ac9029SStephen Hurd 
67064c7070dbSScott Long 		return (vectors);
67074c7070dbSScott Long 	} else {
670877c1fcecSEric Joyner 		device_printf(dev,
67093d10e9edSMarius Strobl 		    "failed to allocate %d MSI-X vectors, err: %d\n", vectors,
67103d10e9edSMarius Strobl 		    err);
67113d10e9edSMarius Strobl 		if (bar != -1) {
6712e4defe55SMarius Strobl 			bus_release_resource(dev, SYS_RES_MEMORY, bar,
6713e4defe55SMarius Strobl 			    ctx->ifc_msix_mem);
6714e4defe55SMarius Strobl 			ctx->ifc_msix_mem = NULL;
67154c7070dbSScott Long 		}
67163d10e9edSMarius Strobl 	}
67173d10e9edSMarius Strobl 
67184c7070dbSScott Long msi:
67194c7070dbSScott Long 	vectors = pci_msi_count(dev);
67204c7070dbSScott Long 	scctx->isc_nrxqsets = 1;
67214c7070dbSScott Long 	scctx->isc_ntxqsets = 1;
67224c7070dbSScott Long 	scctx->isc_vectors = vectors;
67234c7070dbSScott Long 	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) {
67244c7070dbSScott Long 		device_printf(dev,"Using an MSI interrupt\n");
67254c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_MSI;
67264c7070dbSScott Long 	} else {
6727e4defe55SMarius Strobl 		scctx->isc_vectors = 1;
67284c7070dbSScott Long 		device_printf(dev,"Using a Legacy interrupt\n");
67294c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_LEGACY;
67304c7070dbSScott Long 	}
67314c7070dbSScott Long 
67324c7070dbSScott Long 	return (vectors);
67334c7070dbSScott Long }
67344c7070dbSScott Long 
6735e4defe55SMarius Strobl static const char *ring_states[] = { "IDLE", "BUSY", "STALLED", "ABDICATED" };
67364c7070dbSScott Long 
67374c7070dbSScott Long static int
67384c7070dbSScott Long mp_ring_state_handler(SYSCTL_HANDLER_ARGS)
67394c7070dbSScott Long {
67404c7070dbSScott Long 	int rc;
67414c7070dbSScott Long 	uint16_t *state = ((uint16_t *)oidp->oid_arg1);
67424c7070dbSScott Long 	struct sbuf *sb;
6743e4defe55SMarius Strobl 	const char *ring_state = "UNKNOWN";
67444c7070dbSScott Long 
67454c7070dbSScott Long 	/* XXX needed ? */
67464c7070dbSScott Long 	rc = sysctl_wire_old_buffer(req, 0);
67474c7070dbSScott Long 	MPASS(rc == 0);
67484c7070dbSScott Long 	if (rc != 0)
67494c7070dbSScott Long 		return (rc);
67504c7070dbSScott Long 	sb = sbuf_new_for_sysctl(NULL, NULL, 80, req);
67514c7070dbSScott Long 	MPASS(sb != NULL);
67524c7070dbSScott Long 	if (sb == NULL)
67534c7070dbSScott Long 		return (ENOMEM);
67544c7070dbSScott Long 	if (state[3] <= 3)
67554c7070dbSScott Long 		ring_state = ring_states[state[3]];
67564c7070dbSScott Long 
67574c7070dbSScott Long 	sbuf_printf(sb, "pidx_head: %04hd pidx_tail: %04hd cidx: %04hd state: %s",
67584c7070dbSScott Long 		    state[0], state[1], state[2], ring_state);
67594c7070dbSScott Long 	rc = sbuf_finish(sb);
67604c7070dbSScott Long 	sbuf_delete(sb);
67614c7070dbSScott Long         return(rc);
67624c7070dbSScott Long }
67634c7070dbSScott Long 
676423ac9029SStephen Hurd enum iflib_ndesc_handler {
676523ac9029SStephen Hurd 	IFLIB_NTXD_HANDLER,
676623ac9029SStephen Hurd 	IFLIB_NRXD_HANDLER,
676723ac9029SStephen Hurd };
67684c7070dbSScott Long 
676923ac9029SStephen Hurd static int
677023ac9029SStephen Hurd mp_ndesc_handler(SYSCTL_HANDLER_ARGS)
677123ac9029SStephen Hurd {
677223ac9029SStephen Hurd 	if_ctx_t ctx = (void *)arg1;
677323ac9029SStephen Hurd 	enum iflib_ndesc_handler type = arg2;
677423ac9029SStephen Hurd 	char buf[256] = {0};
677595246abbSSean Bruno 	qidx_t *ndesc;
677623ac9029SStephen Hurd 	char *p, *next;
677723ac9029SStephen Hurd 	int nqs, rc, i;
677823ac9029SStephen Hurd 
677923ac9029SStephen Hurd 	nqs = 8;
678023ac9029SStephen Hurd 	switch(type) {
678123ac9029SStephen Hurd 	case IFLIB_NTXD_HANDLER:
678223ac9029SStephen Hurd 		ndesc = ctx->ifc_sysctl_ntxds;
678323ac9029SStephen Hurd 		if (ctx->ifc_sctx)
678423ac9029SStephen Hurd 			nqs = ctx->ifc_sctx->isc_ntxqs;
678523ac9029SStephen Hurd 		break;
678623ac9029SStephen Hurd 	case IFLIB_NRXD_HANDLER:
678723ac9029SStephen Hurd 		ndesc = ctx->ifc_sysctl_nrxds;
678823ac9029SStephen Hurd 		if (ctx->ifc_sctx)
678923ac9029SStephen Hurd 			nqs = ctx->ifc_sctx->isc_nrxqs;
679023ac9029SStephen Hurd 		break;
67911ae4848cSMatt Macy 	default:
67923d10e9edSMarius Strobl 		printf("%s: unhandled type\n", __func__);
67933d10e9edSMarius Strobl 		return (EINVAL);
679423ac9029SStephen Hurd 	}
679523ac9029SStephen Hurd 	if (nqs == 0)
679623ac9029SStephen Hurd 		nqs = 8;
679723ac9029SStephen Hurd 
679823ac9029SStephen Hurd 	for (i=0; i<8; i++) {
679923ac9029SStephen Hurd 		if (i >= nqs)
680023ac9029SStephen Hurd 			break;
680123ac9029SStephen Hurd 		if (i)
680223ac9029SStephen Hurd 			strcat(buf, ",");
680323ac9029SStephen Hurd 		sprintf(strchr(buf, 0), "%d", ndesc[i]);
680423ac9029SStephen Hurd 	}
680523ac9029SStephen Hurd 
680623ac9029SStephen Hurd 	rc = sysctl_handle_string(oidp, buf, sizeof(buf), req);
680723ac9029SStephen Hurd 	if (rc || req->newptr == NULL)
680823ac9029SStephen Hurd 		return rc;
680923ac9029SStephen Hurd 
681023ac9029SStephen Hurd 	for (i = 0, next = buf, p = strsep(&next, " ,"); i < 8 && p;
681123ac9029SStephen Hurd 	    i++, p = strsep(&next, " ,")) {
681223ac9029SStephen Hurd 		ndesc[i] = strtoul(p, NULL, 10);
681323ac9029SStephen Hurd 	}
681423ac9029SStephen Hurd 
681523ac9029SStephen Hurd 	return(rc);
681623ac9029SStephen Hurd }
68174c7070dbSScott Long 
68184c7070dbSScott Long #define NAME_BUFLEN 32
68194c7070dbSScott Long static void
68204c7070dbSScott Long iflib_add_device_sysctl_pre(if_ctx_t ctx)
68214c7070dbSScott Long {
68224c7070dbSScott Long         device_t dev = iflib_get_dev(ctx);
68234c7070dbSScott Long 	struct sysctl_oid_list *child, *oid_list;
68244c7070dbSScott Long 	struct sysctl_ctx_list *ctx_list;
68254c7070dbSScott Long 	struct sysctl_oid *node;
68264c7070dbSScott Long 
68274c7070dbSScott Long 	ctx_list = device_get_sysctl_ctx(dev);
68284c7070dbSScott Long 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
68294c7070dbSScott Long 	ctx->ifc_sysctl_node = node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, "iflib",
68307029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "IFLIB fields");
68314c7070dbSScott Long 	oid_list = SYSCTL_CHILDREN(node);
68324c7070dbSScott Long 
683310a1e981SEric Joyner 	SYSCTL_ADD_CONST_STRING(ctx_list, oid_list, OID_AUTO, "driver_version",
683410a1e981SEric Joyner 		       CTLFLAG_RD, ctx->ifc_sctx->isc_driver_version,
683523ac9029SStephen Hurd 		       "driver version");
683623ac9029SStephen Hurd 
68374c7070dbSScott Long 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_ntxqs",
68384c7070dbSScott Long 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_ntxqs, 0,
68394c7070dbSScott Long 			"# of txqs to use, 0 => use default #");
68404c7070dbSScott Long 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_nrxqs",
684123ac9029SStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_nrxqs, 0,
684223ac9029SStephen Hurd 			"# of rxqs to use, 0 => use default #");
684323ac9029SStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_qs_enable",
684423ac9029SStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_qs_eq_override, 0,
684523ac9029SStephen Hurd                        "permit #txq != #rxq");
6846ea351d3fSSean Bruno 	SYSCTL_ADD_INT(ctx_list, oid_list, OID_AUTO, "disable_msix",
6847ea351d3fSSean Bruno                       CTLFLAG_RWTUN, &ctx->ifc_softc_ctx.isc_disable_msix, 0,
6848b97de13aSMarius Strobl                       "disable MSI-X (default 0)");
6849f4d2154eSStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "rx_budget",
6850f4d2154eSStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_rx_budget, 0,
68511722eeacSMarius Strobl 		       "set the RX budget");
6852fe51d4cdSStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "tx_abdicate",
6853fe51d4cdSStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_tx_abdicate, 0,
68541722eeacSMarius Strobl 		       "cause TX to abdicate instead of running to completion");
6855f154ece0SStephen Hurd 	ctx->ifc_sysctl_core_offset = CORE_OFFSET_UNSPECIFIED;
6856f154ece0SStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "core_offset",
6857f154ece0SStephen Hurd 		       CTLFLAG_RDTUN, &ctx->ifc_sysctl_core_offset, 0,
6858f154ece0SStephen Hurd 		       "offset to start using cores at");
6859f154ece0SStephen Hurd 	SYSCTL_ADD_U8(ctx_list, oid_list, OID_AUTO, "separate_txrx",
6860f154ece0SStephen Hurd 		       CTLFLAG_RDTUN, &ctx->ifc_sysctl_separate_txrx, 0,
6861f154ece0SStephen Hurd 		       "use separate cores for TX and RX");
6862*ca7005f1SPatrick Kelsey 	SYSCTL_ADD_U8(ctx_list, oid_list, OID_AUTO, "use_logical_cores",
6863*ca7005f1SPatrick Kelsey 		      CTLFLAG_RDTUN, &ctx->ifc_sysctl_use_logical_cores, 0,
6864*ca7005f1SPatrick Kelsey 		      "try to make use of logical cores for TX and RX");
68654c7070dbSScott Long 
686623ac9029SStephen Hurd 	/* XXX change for per-queue sizes */
686723ac9029SStephen Hurd 	SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_ntxds",
68687029da5cSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, ctx,
68697029da5cSPawel Biernacki 	    IFLIB_NTXD_HANDLER, mp_ndesc_handler, "A",
68701722eeacSMarius Strobl 	    "list of # of TX descriptors to use, 0 = use default #");
687123ac9029SStephen Hurd 	SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_nrxds",
68727029da5cSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, ctx,
68737029da5cSPawel Biernacki 	    IFLIB_NRXD_HANDLER, mp_ndesc_handler, "A",
68741722eeacSMarius Strobl 	    "list of # of RX descriptors to use, 0 = use default #");
68754c7070dbSScott Long }
68764c7070dbSScott Long 
68774c7070dbSScott Long static void
68784c7070dbSScott Long iflib_add_device_sysctl_post(if_ctx_t ctx)
68794c7070dbSScott Long {
68804c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
68814c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
68824c7070dbSScott Long         device_t dev = iflib_get_dev(ctx);
68834c7070dbSScott Long 	struct sysctl_oid_list *child;
68844c7070dbSScott Long 	struct sysctl_ctx_list *ctx_list;
68854c7070dbSScott Long 	iflib_fl_t fl;
68864c7070dbSScott Long 	iflib_txq_t txq;
68874c7070dbSScott Long 	iflib_rxq_t rxq;
68884c7070dbSScott Long 	int i, j;
68894c7070dbSScott Long 	char namebuf[NAME_BUFLEN];
68904c7070dbSScott Long 	char *qfmt;
68914c7070dbSScott Long 	struct sysctl_oid *queue_node, *fl_node, *node;
68924c7070dbSScott Long 	struct sysctl_oid_list *queue_list, *fl_list;
68934c7070dbSScott Long 	ctx_list = device_get_sysctl_ctx(dev);
68944c7070dbSScott Long 
68954c7070dbSScott Long 	node = ctx->ifc_sysctl_node;
68964c7070dbSScott Long 	child = SYSCTL_CHILDREN(node);
68974c7070dbSScott Long 
68984c7070dbSScott Long 	if (scctx->isc_ntxqsets > 100)
68994c7070dbSScott Long 		qfmt = "txq%03d";
69004c7070dbSScott Long 	else if (scctx->isc_ntxqsets > 10)
69014c7070dbSScott Long 		qfmt = "txq%02d";
69024c7070dbSScott Long 	else
69034c7070dbSScott Long 		qfmt = "txq%d";
69044c7070dbSScott Long 	for (i = 0, txq = ctx->ifc_txqs; i < scctx->isc_ntxqsets; i++, txq++) {
69054c7070dbSScott Long 		snprintf(namebuf, NAME_BUFLEN, qfmt, i);
69064c7070dbSScott Long 		queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf,
69077029da5cSPawel Biernacki 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
69084c7070dbSScott Long 		queue_list = SYSCTL_CHILDREN(queue_node);
6909*ca7005f1SPatrick Kelsey 		SYSCTL_ADD_INT(ctx_list, queue_list, OID_AUTO, "cpu",
6910*ca7005f1SPatrick Kelsey 			       CTLFLAG_RD,
6911*ca7005f1SPatrick Kelsey 			       &txq->ift_task.gt_cpu, 0, "cpu this queue is bound to");
69124c7070dbSScott Long #if MEMORY_LOGGING
69134c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_dequeued",
69144c7070dbSScott Long 				CTLFLAG_RD,
69154c7070dbSScott Long 				&txq->ift_dequeued, "total mbufs freed");
69164c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_enqueued",
69174c7070dbSScott Long 				CTLFLAG_RD,
69184c7070dbSScott Long 				&txq->ift_enqueued, "total mbufs enqueued");
69194c7070dbSScott Long #endif
69204c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "mbuf_defrag",
69214c7070dbSScott Long 				   CTLFLAG_RD,
69224c7070dbSScott Long 				   &txq->ift_mbuf_defrag, "# of times m_defrag was called");
69234c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "m_pullups",
69244c7070dbSScott Long 				   CTLFLAG_RD,
69254c7070dbSScott Long 				   &txq->ift_pullups, "# of times m_pullup was called");
69264c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "mbuf_defrag_failed",
69274c7070dbSScott Long 				   CTLFLAG_RD,
69284c7070dbSScott Long 				   &txq->ift_mbuf_defrag_failed, "# of times m_defrag failed");
69294c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "no_desc_avail",
69304c7070dbSScott Long 				   CTLFLAG_RD,
693123ac9029SStephen Hurd 				   &txq->ift_no_desc_avail, "# of times no descriptors were available");
69324c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "tx_map_failed",
69334c7070dbSScott Long 				   CTLFLAG_RD,
69341722eeacSMarius Strobl 				   &txq->ift_map_failed, "# of times DMA map failed");
69354c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txd_encap_efbig",
69364c7070dbSScott Long 				   CTLFLAG_RD,
69374c7070dbSScott Long 				   &txq->ift_txd_encap_efbig, "# of times txd_encap returned EFBIG");
69384c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "no_tx_dma_setup",
69394c7070dbSScott Long 				   CTLFLAG_RD,
69404c7070dbSScott Long 				   &txq->ift_no_tx_dma_setup, "# of times map failed for other than EFBIG");
69414c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_pidx",
69424c7070dbSScott Long 				   CTLFLAG_RD,
69434c7070dbSScott Long 				   &txq->ift_pidx, 1, "Producer Index");
69444c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_cidx",
69454c7070dbSScott Long 				   CTLFLAG_RD,
69464c7070dbSScott Long 				   &txq->ift_cidx, 1, "Consumer Index");
69474c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_cidx_processed",
69484c7070dbSScott Long 				   CTLFLAG_RD,
69494c7070dbSScott Long 				   &txq->ift_cidx_processed, 1, "Consumer Index seen by credit update");
69504c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_in_use",
69514c7070dbSScott Long 				   CTLFLAG_RD,
69524c7070dbSScott Long 				   &txq->ift_in_use, 1, "descriptors in use");
69534c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_processed",
69544c7070dbSScott Long 				   CTLFLAG_RD,
69554c7070dbSScott Long 				   &txq->ift_processed, "descriptors procesed for clean");
69564c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_cleaned",
69574c7070dbSScott Long 				   CTLFLAG_RD,
69584c7070dbSScott Long 				   &txq->ift_cleaned, "total cleaned");
69594c7070dbSScott Long 		SYSCTL_ADD_PROC(ctx_list, queue_list, OID_AUTO, "ring_state",
69607029da5cSPawel Biernacki 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
69617029da5cSPawel Biernacki 		    __DEVOLATILE(uint64_t *, &txq->ift_br->state), 0,
69627029da5cSPawel Biernacki 		    mp_ring_state_handler, "A", "soft ring state");
69634c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_enqueues",
696495246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->enqueues,
69654c7070dbSScott Long 				       "# of enqueues to the mp_ring for this queue");
69664c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_drops",
696795246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->drops,
69684c7070dbSScott Long 				       "# of drops in the mp_ring for this queue");
69694c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_starts",
697095246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->starts,
69714c7070dbSScott Long 				       "# of normal consumer starts in the mp_ring for this queue");
69724c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_stalls",
697395246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->stalls,
69744c7070dbSScott Long 					       "# of consumer stalls in the mp_ring for this queue");
69754c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_restarts",
697695246abbSSean Bruno 			       CTLFLAG_RD, &txq->ift_br->restarts,
69774c7070dbSScott Long 				       "# of consumer restarts in the mp_ring for this queue");
69784c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_abdications",
697995246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->abdications,
69804c7070dbSScott Long 				       "# of consumer abdications in the mp_ring for this queue");
69814c7070dbSScott Long 	}
69824c7070dbSScott Long 
69834c7070dbSScott Long 	if (scctx->isc_nrxqsets > 100)
69844c7070dbSScott Long 		qfmt = "rxq%03d";
69854c7070dbSScott Long 	else if (scctx->isc_nrxqsets > 10)
69864c7070dbSScott Long 		qfmt = "rxq%02d";
69874c7070dbSScott Long 	else
69884c7070dbSScott Long 		qfmt = "rxq%d";
69894c7070dbSScott Long 	for (i = 0, rxq = ctx->ifc_rxqs; i < scctx->isc_nrxqsets; i++, rxq++) {
69904c7070dbSScott Long 		snprintf(namebuf, NAME_BUFLEN, qfmt, i);
69914c7070dbSScott Long 		queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf,
69927029da5cSPawel Biernacki 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
69934c7070dbSScott Long 		queue_list = SYSCTL_CHILDREN(queue_node);
6994*ca7005f1SPatrick Kelsey 		SYSCTL_ADD_INT(ctx_list, queue_list, OID_AUTO, "cpu",
6995*ca7005f1SPatrick Kelsey 			       CTLFLAG_RD,
6996*ca7005f1SPatrick Kelsey 			       &rxq->ifr_task.gt_cpu, 0, "cpu this queue is bound to");
699723ac9029SStephen Hurd 		if (sctx->isc_flags & IFLIB_HAS_RXCQ) {
69984c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "rxq_cq_cidx",
69994c7070dbSScott Long 				       CTLFLAG_RD,
70004c7070dbSScott Long 				       &rxq->ifr_cq_cidx, 1, "Consumer Index");
70014c7070dbSScott Long 		}
7002da69b8f9SSean Bruno 
70034c7070dbSScott Long 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) {
70044c7070dbSScott Long 			snprintf(namebuf, NAME_BUFLEN, "rxq_fl%d", j);
70054c7070dbSScott Long 			fl_node = SYSCTL_ADD_NODE(ctx_list, queue_list, OID_AUTO, namebuf,
70067029da5cSPawel Biernacki 			    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "freelist Name");
70074c7070dbSScott Long 			fl_list = SYSCTL_CHILDREN(fl_node);
70084c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "pidx",
70094c7070dbSScott Long 				       CTLFLAG_RD,
70104c7070dbSScott Long 				       &fl->ifl_pidx, 1, "Producer Index");
70114c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "cidx",
70124c7070dbSScott Long 				       CTLFLAG_RD,
70134c7070dbSScott Long 				       &fl->ifl_cidx, 1, "Consumer Index");
70144c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "credits",
70154c7070dbSScott Long 				       CTLFLAG_RD,
70164c7070dbSScott Long 				       &fl->ifl_credits, 1, "credits available");
7017b3813609SPatrick Kelsey 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "buf_size",
7018b3813609SPatrick Kelsey 				       CTLFLAG_RD,
7019b3813609SPatrick Kelsey 				       &fl->ifl_buf_size, 1, "buffer size");
70204c7070dbSScott Long #if MEMORY_LOGGING
70214c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_m_enqueued",
70224c7070dbSScott Long 					CTLFLAG_RD,
70234c7070dbSScott Long 					&fl->ifl_m_enqueued, "mbufs allocated");
70244c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_m_dequeued",
70254c7070dbSScott Long 					CTLFLAG_RD,
70264c7070dbSScott Long 					&fl->ifl_m_dequeued, "mbufs freed");
70274c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_cl_enqueued",
70284c7070dbSScott Long 					CTLFLAG_RD,
70294c7070dbSScott Long 					&fl->ifl_cl_enqueued, "clusters allocated");
70304c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_cl_dequeued",
70314c7070dbSScott Long 					CTLFLAG_RD,
70324c7070dbSScott Long 					&fl->ifl_cl_dequeued, "clusters freed");
70334c7070dbSScott Long #endif
70344c7070dbSScott Long 		}
70354c7070dbSScott Long 	}
70364c7070dbSScott Long 
70374c7070dbSScott Long }
703895246abbSSean Bruno 
703977c1fcecSEric Joyner void
704077c1fcecSEric Joyner iflib_request_reset(if_ctx_t ctx)
704177c1fcecSEric Joyner {
704277c1fcecSEric Joyner 
704377c1fcecSEric Joyner 	STATE_LOCK(ctx);
704477c1fcecSEric Joyner 	ctx->ifc_flags |= IFC_DO_RESET;
704577c1fcecSEric Joyner 	STATE_UNLOCK(ctx);
704677c1fcecSEric Joyner }
704777c1fcecSEric Joyner 
704895246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
704995246abbSSean Bruno static struct mbuf *
705095246abbSSean Bruno iflib_fixup_rx(struct mbuf *m)
705195246abbSSean Bruno {
705295246abbSSean Bruno 	struct mbuf *n;
705395246abbSSean Bruno 
705495246abbSSean Bruno 	if (m->m_len <= (MCLBYTES - ETHER_HDR_LEN)) {
705595246abbSSean Bruno 		bcopy(m->m_data, m->m_data + ETHER_HDR_LEN, m->m_len);
705695246abbSSean Bruno 		m->m_data += ETHER_HDR_LEN;
705795246abbSSean Bruno 		n = m;
705895246abbSSean Bruno 	} else {
705995246abbSSean Bruno 		MGETHDR(n, M_NOWAIT, MT_DATA);
706095246abbSSean Bruno 		if (n == NULL) {
706195246abbSSean Bruno 			m_freem(m);
706295246abbSSean Bruno 			return (NULL);
706395246abbSSean Bruno 		}
706495246abbSSean Bruno 		bcopy(m->m_data, n->m_data, ETHER_HDR_LEN);
706595246abbSSean Bruno 		m->m_data += ETHER_HDR_LEN;
706695246abbSSean Bruno 		m->m_len -= ETHER_HDR_LEN;
706795246abbSSean Bruno 		n->m_len = ETHER_HDR_LEN;
706895246abbSSean Bruno 		M_MOVE_PKTHDR(n, m);
706995246abbSSean Bruno 		n->m_next = m;
707095246abbSSean Bruno 	}
707195246abbSSean Bruno 	return (n);
707295246abbSSean Bruno }
707395246abbSSean Bruno #endif
707494618825SMark Johnston 
70757790c8c1SConrad Meyer #ifdef DEBUGNET
707694618825SMark Johnston static void
70777790c8c1SConrad Meyer iflib_debugnet_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
707894618825SMark Johnston {
707994618825SMark Johnston 	if_ctx_t ctx;
708094618825SMark Johnston 
708194618825SMark Johnston 	ctx = if_getsoftc(ifp);
708294618825SMark Johnston 	CTX_LOCK(ctx);
708394618825SMark Johnston 	*nrxr = NRXQSETS(ctx);
708494618825SMark Johnston 	*ncl = ctx->ifc_rxqs[0].ifr_fl->ifl_size;
708594618825SMark Johnston 	*clsize = ctx->ifc_rxqs[0].ifr_fl->ifl_buf_size;
708694618825SMark Johnston 	CTX_UNLOCK(ctx);
708794618825SMark Johnston }
708894618825SMark Johnston 
708994618825SMark Johnston static void
70907790c8c1SConrad Meyer iflib_debugnet_event(if_t ifp, enum debugnet_ev event)
709194618825SMark Johnston {
709294618825SMark Johnston 	if_ctx_t ctx;
709394618825SMark Johnston 	if_softc_ctx_t scctx;
709494618825SMark Johnston 	iflib_fl_t fl;
709594618825SMark Johnston 	iflib_rxq_t rxq;
709694618825SMark Johnston 	int i, j;
709794618825SMark Johnston 
709894618825SMark Johnston 	ctx = if_getsoftc(ifp);
709994618825SMark Johnston 	scctx = &ctx->ifc_softc_ctx;
710094618825SMark Johnston 
710194618825SMark Johnston 	switch (event) {
71027790c8c1SConrad Meyer 	case DEBUGNET_START:
710394618825SMark Johnston 		for (i = 0; i < scctx->isc_nrxqsets; i++) {
710494618825SMark Johnston 			rxq = &ctx->ifc_rxqs[i];
710594618825SMark Johnston 			for (j = 0; j < rxq->ifr_nfl; j++) {
710694618825SMark Johnston 				fl = rxq->ifr_fl;
710794618825SMark Johnston 				fl->ifl_zone = m_getzone(fl->ifl_buf_size);
710894618825SMark Johnston 			}
710994618825SMark Johnston 		}
711094618825SMark Johnston 		iflib_no_tx_batch = 1;
711194618825SMark Johnston 		break;
711294618825SMark Johnston 	default:
711394618825SMark Johnston 		break;
711494618825SMark Johnston 	}
711594618825SMark Johnston }
711694618825SMark Johnston 
711794618825SMark Johnston static int
71187790c8c1SConrad Meyer iflib_debugnet_transmit(if_t ifp, struct mbuf *m)
711994618825SMark Johnston {
712094618825SMark Johnston 	if_ctx_t ctx;
712194618825SMark Johnston 	iflib_txq_t txq;
712294618825SMark Johnston 	int error;
712394618825SMark Johnston 
712494618825SMark Johnston 	ctx = if_getsoftc(ifp);
712594618825SMark Johnston 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
712694618825SMark Johnston 	    IFF_DRV_RUNNING)
712794618825SMark Johnston 		return (EBUSY);
712894618825SMark Johnston 
712994618825SMark Johnston 	txq = &ctx->ifc_txqs[0];
713094618825SMark Johnston 	error = iflib_encap(txq, &m);
713194618825SMark Johnston 	if (error == 0)
713281be6552SMatt Macy 		(void)iflib_txd_db_check(txq, true);
713394618825SMark Johnston 	return (error);
713494618825SMark Johnston }
713594618825SMark Johnston 
713694618825SMark Johnston static int
71377790c8c1SConrad Meyer iflib_debugnet_poll(if_t ifp, int count)
713894618825SMark Johnston {
71390b8df657SGleb Smirnoff 	struct epoch_tracker et;
714094618825SMark Johnston 	if_ctx_t ctx;
714194618825SMark Johnston 	if_softc_ctx_t scctx;
714294618825SMark Johnston 	iflib_txq_t txq;
714394618825SMark Johnston 	int i;
714494618825SMark Johnston 
714594618825SMark Johnston 	ctx = if_getsoftc(ifp);
714694618825SMark Johnston 	scctx = &ctx->ifc_softc_ctx;
714794618825SMark Johnston 
714894618825SMark Johnston 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
714994618825SMark Johnston 	    IFF_DRV_RUNNING)
715094618825SMark Johnston 		return (EBUSY);
715194618825SMark Johnston 
715294618825SMark Johnston 	txq = &ctx->ifc_txqs[0];
715394618825SMark Johnston 	(void)iflib_completed_tx_reclaim(txq, RECLAIM_THRESH(ctx));
715494618825SMark Johnston 
71550b8df657SGleb Smirnoff 	NET_EPOCH_ENTER(et);
715694618825SMark Johnston 	for (i = 0; i < scctx->isc_nrxqsets; i++)
715794618825SMark Johnston 		(void)iflib_rxeof(&ctx->ifc_rxqs[i], 16 /* XXX */);
71580b8df657SGleb Smirnoff 	NET_EPOCH_EXIT(et);
715994618825SMark Johnston 	return (0);
716094618825SMark Johnston }
71617790c8c1SConrad Meyer #endif /* DEBUGNET */
7162