xref: /freebsd/sys/net/iflib.c (revision 361e950180025b72cf78a41a3563d32f9beb0b05)
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;
19823ac9029SStephen Hurd 
19995246abbSSean Bruno 	qidx_t ifc_sysctl_ntxds[8];
20095246abbSSean Bruno 	qidx_t ifc_sysctl_nrxds[8];
2014c7070dbSScott Long 	struct if_txrx ifc_txrx;
2024c7070dbSScott Long #define isc_txd_encap  ifc_txrx.ift_txd_encap
2034c7070dbSScott Long #define isc_txd_flush  ifc_txrx.ift_txd_flush
2044c7070dbSScott Long #define isc_txd_credits_update  ifc_txrx.ift_txd_credits_update
2054c7070dbSScott Long #define isc_rxd_available ifc_txrx.ift_rxd_available
2064c7070dbSScott Long #define isc_rxd_pkt_get ifc_txrx.ift_rxd_pkt_get
2074c7070dbSScott Long #define isc_rxd_refill ifc_txrx.ift_rxd_refill
2084c7070dbSScott Long #define isc_rxd_flush ifc_txrx.ift_rxd_flush
2094c7070dbSScott Long #define isc_legacy_intr ifc_txrx.ift_legacy_intr
2104c7070dbSScott Long 	eventhandler_tag ifc_vlan_attach_event;
2114c7070dbSScott Long 	eventhandler_tag ifc_vlan_detach_event;
2121fd8c72cSKyle Evans 	struct ether_addr ifc_mac;
2134c7070dbSScott Long };
2144c7070dbSScott Long 
2154c7070dbSScott Long void *
2164c7070dbSScott Long iflib_get_softc(if_ctx_t ctx)
2174c7070dbSScott Long {
2184c7070dbSScott Long 
2194c7070dbSScott Long 	return (ctx->ifc_softc);
2204c7070dbSScott Long }
2214c7070dbSScott Long 
2224c7070dbSScott Long device_t
2234c7070dbSScott Long iflib_get_dev(if_ctx_t ctx)
2244c7070dbSScott Long {
2254c7070dbSScott Long 
2264c7070dbSScott Long 	return (ctx->ifc_dev);
2274c7070dbSScott Long }
2284c7070dbSScott Long 
2294c7070dbSScott Long if_t
2304c7070dbSScott Long iflib_get_ifp(if_ctx_t ctx)
2314c7070dbSScott Long {
2324c7070dbSScott Long 
2334c7070dbSScott Long 	return (ctx->ifc_ifp);
2344c7070dbSScott Long }
2354c7070dbSScott Long 
2364c7070dbSScott Long struct ifmedia *
2374c7070dbSScott Long iflib_get_media(if_ctx_t ctx)
2384c7070dbSScott Long {
2394c7070dbSScott Long 
240e2621d96SMatt Macy 	return (ctx->ifc_mediap);
2414c7070dbSScott Long }
2424c7070dbSScott Long 
24309f6ff4fSMatt Macy uint32_t
24409f6ff4fSMatt Macy iflib_get_flags(if_ctx_t ctx)
24509f6ff4fSMatt Macy {
24609f6ff4fSMatt Macy 	return (ctx->ifc_flags);
24709f6ff4fSMatt Macy }
24809f6ff4fSMatt Macy 
24909f6ff4fSMatt Macy void
2504c7070dbSScott Long iflib_set_mac(if_ctx_t ctx, uint8_t mac[ETHER_ADDR_LEN])
2514c7070dbSScott Long {
2524c7070dbSScott Long 
2531fd8c72cSKyle Evans 	bcopy(mac, ctx->ifc_mac.octet, ETHER_ADDR_LEN);
2544c7070dbSScott Long }
2554c7070dbSScott Long 
2564c7070dbSScott Long if_softc_ctx_t
2574c7070dbSScott Long iflib_get_softc_ctx(if_ctx_t ctx)
2584c7070dbSScott Long {
2594c7070dbSScott Long 
2604c7070dbSScott Long 	return (&ctx->ifc_softc_ctx);
2614c7070dbSScott Long }
2624c7070dbSScott Long 
2634c7070dbSScott Long if_shared_ctx_t
2644c7070dbSScott Long iflib_get_sctx(if_ctx_t ctx)
2654c7070dbSScott Long {
2664c7070dbSScott Long 
2674c7070dbSScott Long 	return (ctx->ifc_sctx);
2684c7070dbSScott Long }
2694c7070dbSScott Long 
27095246abbSSean Bruno #define IP_ALIGNED(m) ((((uintptr_t)(m)->m_data) & 0x3) == 0x2)
2714c7070dbSScott Long #define CACHE_PTR_INCREMENT (CACHE_LINE_SIZE/sizeof(void*))
2725e888388SSean Bruno #define CACHE_PTR_NEXT(ptr) ((void *)(((uintptr_t)(ptr)+CACHE_LINE_SIZE-1) & (CACHE_LINE_SIZE-1)))
2734c7070dbSScott Long 
2744c7070dbSScott Long #define LINK_ACTIVE(ctx) ((ctx)->ifc_link_state == LINK_STATE_UP)
2754c7070dbSScott Long #define CTX_IS_VF(ctx) ((ctx)->ifc_sctx->isc_flags & IFLIB_IS_VF)
2764c7070dbSScott Long 
277e035717eSSean Bruno typedef struct iflib_sw_rx_desc_array {
278e035717eSSean Bruno 	bus_dmamap_t	*ifsd_map;         /* bus_dma maps for packet */
279e035717eSSean Bruno 	struct mbuf	**ifsd_m;           /* pkthdr mbufs */
280e035717eSSean Bruno 	caddr_t		*ifsd_cl;          /* direct cluster pointer for rx */
281fbec776dSAndrew Gallatin 	bus_addr_t	*ifsd_ba;          /* bus addr of cluster for rx */
282e035717eSSean Bruno } iflib_rxsd_array_t;
2834c7070dbSScott Long 
2844c7070dbSScott Long typedef struct iflib_sw_tx_desc_array {
2854c7070dbSScott Long 	bus_dmamap_t    *ifsd_map;         /* bus_dma maps for packet */
2868a04b53dSKonstantin Belousov 	bus_dmamap_t	*ifsd_tso_map;     /* bus_dma maps for TSO packet */
2874c7070dbSScott Long 	struct mbuf    **ifsd_m;           /* pkthdr mbufs */
28895246abbSSean Bruno } if_txsd_vec_t;
2894c7070dbSScott Long 
2904c7070dbSScott Long /* magic number that should be high enough for any hardware */
2914c7070dbSScott Long #define IFLIB_MAX_TX_SEGS		128
29295246abbSSean Bruno #define IFLIB_RX_COPY_THRESH		128
2934c7070dbSScott Long #define IFLIB_MAX_RX_REFRESH		32
29495246abbSSean Bruno /* The minimum descriptors per second before we start coalescing */
29595246abbSSean Bruno #define IFLIB_MIN_DESC_SEC		16384
29695246abbSSean Bruno #define IFLIB_DEFAULT_TX_UPDATE_FREQ	16
2974c7070dbSScott Long #define IFLIB_QUEUE_IDLE		0
2984c7070dbSScott Long #define IFLIB_QUEUE_HUNG		1
2994c7070dbSScott Long #define IFLIB_QUEUE_WORKING		2
30095246abbSSean Bruno /* maximum number of txqs that can share an rx interrupt */
30195246abbSSean Bruno #define IFLIB_MAX_TX_SHARED_INTR	4
3024c7070dbSScott Long 
30395246abbSSean Bruno /* this should really scale with ring size - this is a fairly arbitrary value */
30495246abbSSean Bruno #define TX_BATCH_SIZE			32
3054c7070dbSScott Long 
3064c7070dbSScott Long #define IFLIB_RESTART_BUDGET		8
3074c7070dbSScott Long 
3084c7070dbSScott Long #define CSUM_OFFLOAD		(CSUM_IP_TSO|CSUM_IP6_TSO|CSUM_IP| \
3094c7070dbSScott Long 				 CSUM_IP_UDP|CSUM_IP_TCP|CSUM_IP_SCTP| \
3104c7070dbSScott Long 				 CSUM_IP6_UDP|CSUM_IP6_TCP|CSUM_IP6_SCTP)
3111722eeacSMarius Strobl 
3124c7070dbSScott Long struct iflib_txq {
31395246abbSSean Bruno 	qidx_t		ift_in_use;
31495246abbSSean Bruno 	qidx_t		ift_cidx;
31595246abbSSean Bruno 	qidx_t		ift_cidx_processed;
31695246abbSSean Bruno 	qidx_t		ift_pidx;
3174c7070dbSScott Long 	uint8_t		ift_gen;
31823ac9029SStephen Hurd 	uint8_t		ift_br_offset;
31995246abbSSean Bruno 	uint16_t	ift_npending;
32095246abbSSean Bruno 	uint16_t	ift_db_pending;
32195246abbSSean Bruno 	uint16_t	ift_rs_pending;
3224c7070dbSScott Long 	/* implicit pad */
32395246abbSSean Bruno 	uint8_t		ift_txd_size[8];
3244c7070dbSScott Long 	uint64_t	ift_processed;
3254c7070dbSScott Long 	uint64_t	ift_cleaned;
32695246abbSSean Bruno 	uint64_t	ift_cleaned_prev;
3274c7070dbSScott Long #if MEMORY_LOGGING
3284c7070dbSScott Long 	uint64_t	ift_enqueued;
3294c7070dbSScott Long 	uint64_t	ift_dequeued;
3304c7070dbSScott Long #endif
3314c7070dbSScott Long 	uint64_t	ift_no_tx_dma_setup;
3324c7070dbSScott Long 	uint64_t	ift_no_desc_avail;
3334c7070dbSScott Long 	uint64_t	ift_mbuf_defrag_failed;
3344c7070dbSScott Long 	uint64_t	ift_mbuf_defrag;
3354c7070dbSScott Long 	uint64_t	ift_map_failed;
3364c7070dbSScott Long 	uint64_t	ift_txd_encap_efbig;
3374c7070dbSScott Long 	uint64_t	ift_pullups;
338dd7fbcf1SStephen Hurd 	uint64_t	ift_last_timer_tick;
3394c7070dbSScott Long 
3404c7070dbSScott Long 	struct mtx	ift_mtx;
3414c7070dbSScott Long 	struct mtx	ift_db_mtx;
3424c7070dbSScott Long 
3434c7070dbSScott Long 	/* constant values */
3444c7070dbSScott Long 	if_ctx_t	ift_ctx;
34595246abbSSean Bruno 	struct ifmp_ring        *ift_br;
3464c7070dbSScott Long 	struct grouptask	ift_task;
34795246abbSSean Bruno 	qidx_t		ift_size;
3484c7070dbSScott Long 	uint16_t	ift_id;
3494c7070dbSScott Long 	struct callout	ift_timer;
35017cec474SVincenzo Maffione #ifdef DEV_NETMAP
35117cec474SVincenzo Maffione 	struct callout	ift_netmap_timer;
35217cec474SVincenzo Maffione #endif /* DEV_NETMAP */
3534c7070dbSScott Long 
35495246abbSSean Bruno 	if_txsd_vec_t	ift_sds;
3554c7070dbSScott Long 	uint8_t		ift_qstatus;
3564c7070dbSScott Long 	uint8_t		ift_closed;
35795246abbSSean Bruno 	uint8_t		ift_update_freq;
3584c7070dbSScott Long 	struct iflib_filter_info ift_filter_info;
359bfce461eSMarius Strobl 	bus_dma_tag_t	ift_buf_tag;
360bfce461eSMarius Strobl 	bus_dma_tag_t	ift_tso_buf_tag;
3614c7070dbSScott Long 	iflib_dma_info_t	ift_ifdi;
362814fa34dSMark Johnston #define	MTX_NAME_LEN	32
3634c7070dbSScott Long 	char                    ift_mtx_name[MTX_NAME_LEN];
3644c7070dbSScott Long 	bus_dma_segment_t	ift_segs[IFLIB_MAX_TX_SEGS]  __aligned(CACHE_LINE_SIZE);
3651248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
3661248952aSSean Bruno 	uint64_t ift_cpu_exec_count[256];
3671248952aSSean Bruno #endif
3684c7070dbSScott Long } __aligned(CACHE_LINE_SIZE);
3694c7070dbSScott Long 
3704c7070dbSScott Long struct iflib_fl {
37195246abbSSean Bruno 	qidx_t		ifl_cidx;
37295246abbSSean Bruno 	qidx_t		ifl_pidx;
37395246abbSSean Bruno 	qidx_t		ifl_credits;
3744c7070dbSScott Long 	uint8_t		ifl_gen;
37595246abbSSean Bruno 	uint8_t		ifl_rxd_size;
3764c7070dbSScott Long #if MEMORY_LOGGING
3774c7070dbSScott Long 	uint64_t	ifl_m_enqueued;
3784c7070dbSScott Long 	uint64_t	ifl_m_dequeued;
3794c7070dbSScott Long 	uint64_t	ifl_cl_enqueued;
3804c7070dbSScott Long 	uint64_t	ifl_cl_dequeued;
3814c7070dbSScott Long #endif
3824c7070dbSScott Long 	/* implicit pad */
38387890dbaSSean Bruno 	bitstr_t 	*ifl_rx_bitmap;
38487890dbaSSean Bruno 	qidx_t		ifl_fragidx;
3854c7070dbSScott Long 	/* constant */
38695246abbSSean Bruno 	qidx_t		ifl_size;
3874c7070dbSScott Long 	uint16_t	ifl_buf_size;
3884c7070dbSScott Long 	uint16_t	ifl_cltype;
3894c7070dbSScott Long 	uma_zone_t	ifl_zone;
390e035717eSSean Bruno 	iflib_rxsd_array_t	ifl_sds;
3914c7070dbSScott Long 	iflib_rxq_t	ifl_rxq;
3924c7070dbSScott Long 	uint8_t		ifl_id;
393bfce461eSMarius Strobl 	bus_dma_tag_t	ifl_buf_tag;
3944c7070dbSScott Long 	iflib_dma_info_t	ifl_ifdi;
3954c7070dbSScott Long 	uint64_t	ifl_bus_addrs[IFLIB_MAX_RX_REFRESH] __aligned(CACHE_LINE_SIZE);
39695246abbSSean Bruno 	qidx_t		ifl_rxd_idxs[IFLIB_MAX_RX_REFRESH];
3974c7070dbSScott Long }  __aligned(CACHE_LINE_SIZE);
3984c7070dbSScott Long 
39995246abbSSean Bruno static inline qidx_t
40095246abbSSean Bruno get_inuse(int size, qidx_t cidx, qidx_t pidx, uint8_t gen)
4014c7070dbSScott Long {
40295246abbSSean Bruno 	qidx_t used;
4034c7070dbSScott Long 
4044c7070dbSScott Long 	if (pidx > cidx)
4054c7070dbSScott Long 		used = pidx - cidx;
4064c7070dbSScott Long 	else if (pidx < cidx)
4074c7070dbSScott Long 		used = size - cidx + pidx;
4084c7070dbSScott Long 	else if (gen == 0 && pidx == cidx)
4094c7070dbSScott Long 		used = 0;
4104c7070dbSScott Long 	else if (gen == 1 && pidx == cidx)
4114c7070dbSScott Long 		used = size;
4124c7070dbSScott Long 	else
4134c7070dbSScott Long 		panic("bad state");
4144c7070dbSScott Long 
4154c7070dbSScott Long 	return (used);
4164c7070dbSScott Long }
4174c7070dbSScott Long 
4184c7070dbSScott Long #define TXQ_AVAIL(txq) (txq->ift_size - get_inuse(txq->ift_size, txq->ift_cidx, txq->ift_pidx, txq->ift_gen))
4194c7070dbSScott Long 
4204c7070dbSScott Long #define IDXDIFF(head, tail, wrap) \
4214c7070dbSScott Long 	((head) >= (tail) ? (head) - (tail) : (wrap) - (tail) + (head))
4224c7070dbSScott Long 
4234c7070dbSScott Long struct iflib_rxq {
4244c7070dbSScott Long 	if_ctx_t	ifr_ctx;
4254c7070dbSScott Long 	iflib_fl_t	ifr_fl;
4264c7070dbSScott Long 	uint64_t	ifr_rx_irq;
4276d49b41eSAndrew Gallatin 	struct pfil_head	*pfil;
4281722eeacSMarius Strobl 	/*
4291722eeacSMarius Strobl 	 * If there is a separate completion queue (IFLIB_HAS_RXCQ), this is
4306d84e76aSVincenzo Maffione 	 * the completion queue consumer index.  Otherwise it's unused.
4311722eeacSMarius Strobl 	 */
4321722eeacSMarius Strobl 	qidx_t		ifr_cq_cidx;
4334c7070dbSScott Long 	uint16_t	ifr_id;
4344c7070dbSScott Long 	uint8_t		ifr_nfl;
43595246abbSSean Bruno 	uint8_t		ifr_ntxqirq;
43695246abbSSean Bruno 	uint8_t		ifr_txqid[IFLIB_MAX_TX_SHARED_INTR];
4371722eeacSMarius Strobl 	uint8_t		ifr_fl_offset;
4384c7070dbSScott Long 	struct lro_ctrl			ifr_lc;
4394c7070dbSScott Long 	struct grouptask        ifr_task;
440fb1a29b4SHans Petter Selasky 	struct callout		ifr_watchdog;
4414c7070dbSScott Long 	struct iflib_filter_info ifr_filter_info;
4424c7070dbSScott Long 	iflib_dma_info_t		ifr_ifdi;
443ab2e3f79SStephen Hurd 
4444c7070dbSScott Long 	/* dynamically allocate if any drivers need a value substantially larger than this */
4454c7070dbSScott Long 	struct if_rxd_frag	ifr_frags[IFLIB_MAX_RX_SEGS] __aligned(CACHE_LINE_SIZE);
4461248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
4471248952aSSean Bruno 	uint64_t ifr_cpu_exec_count[256];
4481248952aSSean Bruno #endif
4494c7070dbSScott Long }  __aligned(CACHE_LINE_SIZE);
4504c7070dbSScott Long 
45195246abbSSean Bruno typedef struct if_rxsd {
45295246abbSSean Bruno 	caddr_t *ifsd_cl;
45395246abbSSean Bruno 	iflib_fl_t ifsd_fl;
45495246abbSSean Bruno } *if_rxsd_t;
45595246abbSSean Bruno 
45695246abbSSean Bruno /* multiple of word size */
45795246abbSSean Bruno #ifdef __LP64__
458ab2e3f79SStephen Hurd #define PKT_INFO_SIZE	6
45995246abbSSean Bruno #define RXD_INFO_SIZE	5
46095246abbSSean Bruno #define PKT_TYPE uint64_t
46195246abbSSean Bruno #else
462ab2e3f79SStephen Hurd #define PKT_INFO_SIZE	11
46395246abbSSean Bruno #define RXD_INFO_SIZE	8
46495246abbSSean Bruno #define PKT_TYPE uint32_t
46595246abbSSean Bruno #endif
46695246abbSSean Bruno #define PKT_LOOP_BOUND  ((PKT_INFO_SIZE/3)*3)
46795246abbSSean Bruno #define RXD_LOOP_BOUND  ((RXD_INFO_SIZE/4)*4)
46895246abbSSean Bruno 
46995246abbSSean Bruno typedef struct if_pkt_info_pad {
47095246abbSSean Bruno 	PKT_TYPE pkt_val[PKT_INFO_SIZE];
47195246abbSSean Bruno } *if_pkt_info_pad_t;
47295246abbSSean Bruno typedef struct if_rxd_info_pad {
47395246abbSSean Bruno 	PKT_TYPE rxd_val[RXD_INFO_SIZE];
47495246abbSSean Bruno } *if_rxd_info_pad_t;
47595246abbSSean Bruno 
47695246abbSSean Bruno CTASSERT(sizeof(struct if_pkt_info_pad) == sizeof(struct if_pkt_info));
47795246abbSSean Bruno CTASSERT(sizeof(struct if_rxd_info_pad) == sizeof(struct if_rxd_info));
47895246abbSSean Bruno 
47995246abbSSean Bruno static inline void
48095246abbSSean Bruno pkt_info_zero(if_pkt_info_t pi)
48195246abbSSean Bruno {
48295246abbSSean Bruno 	if_pkt_info_pad_t pi_pad;
48395246abbSSean Bruno 
48495246abbSSean Bruno 	pi_pad = (if_pkt_info_pad_t)pi;
48595246abbSSean Bruno 	pi_pad->pkt_val[0] = 0; pi_pad->pkt_val[1] = 0; pi_pad->pkt_val[2] = 0;
48695246abbSSean Bruno 	pi_pad->pkt_val[3] = 0; pi_pad->pkt_val[4] = 0; pi_pad->pkt_val[5] = 0;
48795246abbSSean Bruno #ifndef __LP64__
488ab2e3f79SStephen Hurd 	pi_pad->pkt_val[6] = 0; pi_pad->pkt_val[7] = 0; pi_pad->pkt_val[8] = 0;
489ab2e3f79SStephen Hurd 	pi_pad->pkt_val[9] = 0; pi_pad->pkt_val[10] = 0;
49095246abbSSean Bruno #endif
49195246abbSSean Bruno }
49295246abbSSean Bruno 
49309f6ff4fSMatt Macy static device_method_t iflib_pseudo_methods[] = {
49409f6ff4fSMatt Macy 	DEVMETHOD(device_attach, noop_attach),
49509f6ff4fSMatt Macy 	DEVMETHOD(device_detach, iflib_pseudo_detach),
49609f6ff4fSMatt Macy 	DEVMETHOD_END
49709f6ff4fSMatt Macy };
49809f6ff4fSMatt Macy 
49909f6ff4fSMatt Macy driver_t iflib_pseudodriver = {
50009f6ff4fSMatt Macy 	"iflib_pseudo", iflib_pseudo_methods, sizeof(struct iflib_ctx),
50109f6ff4fSMatt Macy };
50209f6ff4fSMatt Macy 
50395246abbSSean Bruno static inline void
50495246abbSSean Bruno rxd_info_zero(if_rxd_info_t ri)
50595246abbSSean Bruno {
50695246abbSSean Bruno 	if_rxd_info_pad_t ri_pad;
50795246abbSSean Bruno 	int i;
50895246abbSSean Bruno 
50995246abbSSean Bruno 	ri_pad = (if_rxd_info_pad_t)ri;
51095246abbSSean Bruno 	for (i = 0; i < RXD_LOOP_BOUND; i += 4) {
51195246abbSSean Bruno 		ri_pad->rxd_val[i] = 0;
51295246abbSSean Bruno 		ri_pad->rxd_val[i+1] = 0;
51395246abbSSean Bruno 		ri_pad->rxd_val[i+2] = 0;
51495246abbSSean Bruno 		ri_pad->rxd_val[i+3] = 0;
51595246abbSSean Bruno 	}
51695246abbSSean Bruno #ifdef __LP64__
51795246abbSSean Bruno 	ri_pad->rxd_val[RXD_INFO_SIZE-1] = 0;
51895246abbSSean Bruno #endif
51995246abbSSean Bruno }
52095246abbSSean Bruno 
5214c7070dbSScott Long /*
5224c7070dbSScott Long  * Only allow a single packet to take up most 1/nth of the tx ring
5234c7070dbSScott Long  */
5244c7070dbSScott Long #define MAX_SINGLE_PACKET_FRACTION 12
5254c7070dbSScott Long #define IF_BAD_DMA (bus_addr_t)-1
5264c7070dbSScott Long 
5274c7070dbSScott Long #define CTX_ACTIVE(ctx) ((if_getdrvflags((ctx)->ifc_ifp) & IFF_DRV_RUNNING))
5284c7070dbSScott Long 
529aa8a24d3SStephen Hurd #define CTX_LOCK_INIT(_sc)  sx_init(&(_sc)->ifc_ctx_sx, "iflib ctx lock")
530aa8a24d3SStephen Hurd #define CTX_LOCK(ctx) sx_xlock(&(ctx)->ifc_ctx_sx)
531aa8a24d3SStephen Hurd #define CTX_UNLOCK(ctx) sx_xunlock(&(ctx)->ifc_ctx_sx)
532aa8a24d3SStephen Hurd #define CTX_LOCK_DESTROY(ctx) sx_destroy(&(ctx)->ifc_ctx_sx)
5334c7070dbSScott Long 
5347b610b60SSean Bruno #define STATE_LOCK_INIT(_sc, _name)  mtx_init(&(_sc)->ifc_state_mtx, _name, "iflib state lock", MTX_DEF)
5357b610b60SSean Bruno #define STATE_LOCK(ctx) mtx_lock(&(ctx)->ifc_state_mtx)
5367b610b60SSean Bruno #define STATE_UNLOCK(ctx) mtx_unlock(&(ctx)->ifc_state_mtx)
5377b610b60SSean Bruno #define STATE_LOCK_DESTROY(ctx) mtx_destroy(&(ctx)->ifc_state_mtx)
5387b610b60SSean Bruno 
5394c7070dbSScott Long #define CALLOUT_LOCK(txq)	mtx_lock(&txq->ift_mtx)
5404c7070dbSScott Long #define CALLOUT_UNLOCK(txq) 	mtx_unlock(&txq->ift_mtx)
5414c7070dbSScott Long 
54277c1fcecSEric Joyner void
54377c1fcecSEric Joyner iflib_set_detach(if_ctx_t ctx)
54477c1fcecSEric Joyner {
54577c1fcecSEric Joyner 	STATE_LOCK(ctx);
54677c1fcecSEric Joyner 	ctx->ifc_flags |= IFC_IN_DETACH;
54777c1fcecSEric Joyner 	STATE_UNLOCK(ctx);
54877c1fcecSEric Joyner }
5494c7070dbSScott Long 
5504c7070dbSScott Long /* Our boot-time initialization hook */
5514c7070dbSScott Long static int	iflib_module_event_handler(module_t, int, void *);
5524c7070dbSScott Long 
5534c7070dbSScott Long static moduledata_t iflib_moduledata = {
5544c7070dbSScott Long 	"iflib",
5554c7070dbSScott Long 	iflib_module_event_handler,
5564c7070dbSScott Long 	NULL
5574c7070dbSScott Long };
5584c7070dbSScott Long 
5594c7070dbSScott Long DECLARE_MODULE(iflib, iflib_moduledata, SI_SUB_INIT_IF, SI_ORDER_ANY);
5604c7070dbSScott Long MODULE_VERSION(iflib, 1);
5614c7070dbSScott Long 
5624c7070dbSScott Long MODULE_DEPEND(iflib, pci, 1, 1, 1);
5634c7070dbSScott Long MODULE_DEPEND(iflib, ether, 1, 1, 1);
5644c7070dbSScott Long 
565ab2e3f79SStephen Hurd TASKQGROUP_DEFINE(if_io_tqg, mp_ncpus, 1);
566ab2e3f79SStephen Hurd TASKQGROUP_DEFINE(if_config_tqg, 1, 1);
567ab2e3f79SStephen Hurd 
5684c7070dbSScott Long #ifndef IFLIB_DEBUG_COUNTERS
5694c7070dbSScott Long #ifdef INVARIANTS
5704c7070dbSScott Long #define IFLIB_DEBUG_COUNTERS 1
5714c7070dbSScott Long #else
5724c7070dbSScott Long #define IFLIB_DEBUG_COUNTERS 0
5734c7070dbSScott Long #endif /* !INVARIANTS */
5744c7070dbSScott Long #endif
5754c7070dbSScott Long 
5767029da5cSPawel Biernacki static SYSCTL_NODE(_net, OID_AUTO, iflib, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
577ab2e3f79SStephen Hurd     "iflib driver parameters");
578ab2e3f79SStephen Hurd 
5794c7070dbSScott Long /*
5804c7070dbSScott Long  * XXX need to ensure that this can't accidentally cause the head to be moved backwards
5814c7070dbSScott Long  */
5824c7070dbSScott Long static int iflib_min_tx_latency = 0;
5834c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, min_tx_latency, CTLFLAG_RW,
584da69b8f9SSean Bruno 		   &iflib_min_tx_latency, 0, "minimize transmit latency at the possible expense of throughput");
58595246abbSSean Bruno static int iflib_no_tx_batch = 0;
58695246abbSSean Bruno SYSCTL_INT(_net_iflib, OID_AUTO, no_tx_batch, CTLFLAG_RW,
58795246abbSSean Bruno 		   &iflib_no_tx_batch, 0, "minimize transmit latency at the possible expense of throughput");
58881be6552SMatt Macy static int iflib_timer_default = 1000;
58981be6552SMatt Macy SYSCTL_INT(_net_iflib, OID_AUTO, timer_default, CTLFLAG_RW,
59081be6552SMatt Macy 		   &iflib_timer_default, 0, "number of ticks between iflib_timer calls");
59181be6552SMatt Macy 
5924c7070dbSScott Long 
5934c7070dbSScott Long #if IFLIB_DEBUG_COUNTERS
5944c7070dbSScott Long 
5954c7070dbSScott Long static int iflib_tx_seen;
5964c7070dbSScott Long static int iflib_tx_sent;
5974c7070dbSScott Long static int iflib_tx_encap;
5984c7070dbSScott Long static int iflib_rx_allocs;
5994c7070dbSScott Long static int iflib_fl_refills;
6004c7070dbSScott Long static int iflib_fl_refills_large;
6014c7070dbSScott Long static int iflib_tx_frees;
6024c7070dbSScott Long 
6034c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, tx_seen, CTLFLAG_RD,
6041722eeacSMarius Strobl 		   &iflib_tx_seen, 0, "# TX mbufs seen");
6054c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, tx_sent, CTLFLAG_RD,
6061722eeacSMarius Strobl 		   &iflib_tx_sent, 0, "# TX mbufs sent");
6074c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, tx_encap, CTLFLAG_RD,
6081722eeacSMarius Strobl 		   &iflib_tx_encap, 0, "# TX mbufs encapped");
6094c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, tx_frees, CTLFLAG_RD,
6101722eeacSMarius Strobl 		   &iflib_tx_frees, 0, "# TX frees");
6114c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_allocs, CTLFLAG_RD,
6121722eeacSMarius Strobl 		   &iflib_rx_allocs, 0, "# RX allocations");
6134c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, fl_refills, CTLFLAG_RD,
6144c7070dbSScott Long 		   &iflib_fl_refills, 0, "# refills");
6154c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, fl_refills_large, CTLFLAG_RD,
6164c7070dbSScott Long 		   &iflib_fl_refills_large, 0, "# large refills");
6174c7070dbSScott Long 
6184c7070dbSScott Long static int iflib_txq_drain_flushing;
6194c7070dbSScott Long static int iflib_txq_drain_oactive;
6204c7070dbSScott Long static int iflib_txq_drain_notready;
6214c7070dbSScott Long 
6224c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_flushing, CTLFLAG_RD,
6234c7070dbSScott Long 		   &iflib_txq_drain_flushing, 0, "# drain flushes");
6244c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_oactive, CTLFLAG_RD,
6254c7070dbSScott Long 		   &iflib_txq_drain_oactive, 0, "# drain oactives");
6264c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_notready, CTLFLAG_RD,
6274c7070dbSScott Long 		   &iflib_txq_drain_notready, 0, "# drain notready");
6284c7070dbSScott Long 
6294c7070dbSScott Long static int iflib_encap_load_mbuf_fail;
630d14c853bSStephen Hurd static int iflib_encap_pad_mbuf_fail;
6314c7070dbSScott Long static int iflib_encap_txq_avail_fail;
6324c7070dbSScott Long static int iflib_encap_txd_encap_fail;
6334c7070dbSScott Long 
6344c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, encap_load_mbuf_fail, CTLFLAG_RD,
6354c7070dbSScott Long 		   &iflib_encap_load_mbuf_fail, 0, "# busdma load failures");
636d14c853bSStephen Hurd SYSCTL_INT(_net_iflib, OID_AUTO, encap_pad_mbuf_fail, CTLFLAG_RD,
637d14c853bSStephen Hurd 		   &iflib_encap_pad_mbuf_fail, 0, "# runt frame pad failures");
6384c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, encap_txq_avail_fail, CTLFLAG_RD,
6394c7070dbSScott Long 		   &iflib_encap_txq_avail_fail, 0, "# txq avail failures");
6404c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, encap_txd_encap_fail, CTLFLAG_RD,
6414c7070dbSScott Long 		   &iflib_encap_txd_encap_fail, 0, "# driver encap failures");
6424c7070dbSScott Long 
6434c7070dbSScott Long static int iflib_task_fn_rxs;
6444c7070dbSScott Long static int iflib_rx_intr_enables;
6454c7070dbSScott Long static int iflib_fast_intrs;
6464c7070dbSScott Long static int iflib_rx_unavail;
6474c7070dbSScott Long static int iflib_rx_ctx_inactive;
6484c7070dbSScott Long static int iflib_rx_if_input;
6494c7070dbSScott Long static int iflib_rxd_flush;
6504c7070dbSScott Long 
6514c7070dbSScott Long static int iflib_verbose_debug;
6524c7070dbSScott Long 
6534c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, task_fn_rx, CTLFLAG_RD,
6544c7070dbSScott Long 		   &iflib_task_fn_rxs, 0, "# task_fn_rx calls");
6554c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_intr_enables, CTLFLAG_RD,
6561722eeacSMarius Strobl 		   &iflib_rx_intr_enables, 0, "# RX intr enables");
6574c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, fast_intrs, CTLFLAG_RD,
6584c7070dbSScott Long 		   &iflib_fast_intrs, 0, "# fast_intr calls");
6594c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_unavail, CTLFLAG_RD,
6604c7070dbSScott Long 		   &iflib_rx_unavail, 0, "# times rxeof called with no available data");
6614c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_ctx_inactive, CTLFLAG_RD,
6624c7070dbSScott Long 		   &iflib_rx_ctx_inactive, 0, "# times rxeof called with inactive context");
6634c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rx_if_input, CTLFLAG_RD,
6644c7070dbSScott Long 		   &iflib_rx_if_input, 0, "# times rxeof called if_input");
6654c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, rxd_flush, CTLFLAG_RD,
6664c7070dbSScott Long 	         &iflib_rxd_flush, 0, "# times rxd_flush called");
6674c7070dbSScott Long SYSCTL_INT(_net_iflib, OID_AUTO, verbose_debug, CTLFLAG_RW,
6684c7070dbSScott Long 		   &iflib_verbose_debug, 0, "enable verbose debugging");
6694c7070dbSScott Long 
6704c7070dbSScott Long #define DBG_COUNTER_INC(name) atomic_add_int(&(iflib_ ## name), 1)
671da69b8f9SSean Bruno static void
672da69b8f9SSean Bruno iflib_debug_reset(void)
673da69b8f9SSean Bruno {
674da69b8f9SSean Bruno 	iflib_tx_seen = iflib_tx_sent = iflib_tx_encap = iflib_rx_allocs =
675da69b8f9SSean Bruno 		iflib_fl_refills = iflib_fl_refills_large = iflib_tx_frees =
676da69b8f9SSean Bruno 		iflib_txq_drain_flushing = iflib_txq_drain_oactive =
67764e6fc13SStephen Hurd 		iflib_txq_drain_notready =
678d14c853bSStephen Hurd 		iflib_encap_load_mbuf_fail = iflib_encap_pad_mbuf_fail =
679d14c853bSStephen Hurd 		iflib_encap_txq_avail_fail = iflib_encap_txd_encap_fail =
680d14c853bSStephen Hurd 		iflib_task_fn_rxs = iflib_rx_intr_enables = iflib_fast_intrs =
68164e6fc13SStephen Hurd 		iflib_rx_unavail =
68264e6fc13SStephen Hurd 		iflib_rx_ctx_inactive = iflib_rx_if_input =
6836d49b41eSAndrew Gallatin 		iflib_rxd_flush = 0;
684da69b8f9SSean Bruno }
6854c7070dbSScott Long 
6864c7070dbSScott Long #else
6874c7070dbSScott Long #define DBG_COUNTER_INC(name)
688da69b8f9SSean Bruno static void iflib_debug_reset(void) {}
6894c7070dbSScott Long #endif
6904c7070dbSScott Long 
6914c7070dbSScott Long #define IFLIB_DEBUG 0
6924c7070dbSScott Long 
6934c7070dbSScott Long static void iflib_tx_structures_free(if_ctx_t ctx);
6944c7070dbSScott Long static void iflib_rx_structures_free(if_ctx_t ctx);
6954c7070dbSScott Long static int iflib_queues_alloc(if_ctx_t ctx);
6964c7070dbSScott Long static int iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq);
69795246abbSSean Bruno static int iflib_rxd_avail(if_ctx_t ctx, iflib_rxq_t rxq, qidx_t cidx, qidx_t budget);
6984c7070dbSScott Long static int iflib_qset_structures_setup(if_ctx_t ctx);
6994c7070dbSScott Long static int iflib_msix_init(if_ctx_t ctx);
7003e0e6330SStephen Hurd static int iflib_legacy_setup(if_ctx_t ctx, driver_filter_t filter, void *filterarg, int *rid, const char *str);
7014c7070dbSScott Long static void iflib_txq_check_drain(iflib_txq_t txq, int budget);
7024c7070dbSScott Long static uint32_t iflib_txq_can_drain(struct ifmp_ring *);
703b8ca4756SPatrick Kelsey #ifdef ALTQ
704b8ca4756SPatrick Kelsey static void iflib_altq_if_start(if_t ifp);
705b8ca4756SPatrick Kelsey static int iflib_altq_if_transmit(if_t ifp, struct mbuf *m);
706b8ca4756SPatrick Kelsey #endif
7074c7070dbSScott Long static int iflib_register(if_ctx_t);
70856614414SEric Joyner static void iflib_deregister(if_ctx_t);
7091558015eSEric Joyner static void iflib_unregister_vlan_handlers(if_ctx_t ctx);
710b3813609SPatrick Kelsey static uint16_t iflib_get_mbuf_size_for(unsigned int size);
7114c7070dbSScott Long static void iflib_init_locked(if_ctx_t ctx);
7124c7070dbSScott Long static void iflib_add_device_sysctl_pre(if_ctx_t ctx);
7134c7070dbSScott Long static void iflib_add_device_sysctl_post(if_ctx_t ctx);
714da69b8f9SSean Bruno static void iflib_ifmp_purge(iflib_txq_t txq);
7151248952aSSean Bruno static void _iflib_pre_assert(if_softc_ctx_t scctx);
71695246abbSSean Bruno static void iflib_if_init_locked(if_ctx_t ctx);
71777c1fcecSEric Joyner static void iflib_free_intr_mem(if_ctx_t ctx);
71895246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
71995246abbSSean Bruno static struct mbuf * iflib_fixup_rx(struct mbuf *m);
72095246abbSSean Bruno #endif
7214c7070dbSScott Long 
722f154ece0SStephen Hurd static SLIST_HEAD(cpu_offset_list, cpu_offset) cpu_offsets =
723f154ece0SStephen Hurd     SLIST_HEAD_INITIALIZER(cpu_offsets);
724f154ece0SStephen Hurd struct cpu_offset {
725f154ece0SStephen Hurd 	SLIST_ENTRY(cpu_offset) entries;
726f154ece0SStephen Hurd 	cpuset_t	set;
727f154ece0SStephen Hurd 	unsigned int	refcount;
728f154ece0SStephen Hurd 	uint16_t	offset;
729f154ece0SStephen Hurd };
730f154ece0SStephen Hurd static struct mtx cpu_offset_mtx;
731f154ece0SStephen Hurd MTX_SYSINIT(iflib_cpu_offset, &cpu_offset_mtx, "iflib_cpu_offset lock",
732f154ece0SStephen Hurd     MTX_DEF);
733f154ece0SStephen Hurd 
7347790c8c1SConrad Meyer DEBUGNET_DEFINE(iflib);
73594618825SMark Johnston 
736ac11d857SVincenzo Maffione static int
737ac11d857SVincenzo Maffione iflib_num_rx_descs(if_ctx_t ctx)
738ac11d857SVincenzo Maffione {
739ac11d857SVincenzo Maffione 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
740ac11d857SVincenzo Maffione 	if_shared_ctx_t sctx = ctx->ifc_sctx;
741ac11d857SVincenzo Maffione 	uint16_t first_rxq = (sctx->isc_flags & IFLIB_HAS_RXCQ) ? 1 : 0;
742ac11d857SVincenzo Maffione 
743ac11d857SVincenzo Maffione 	return scctx->isc_nrxd[first_rxq];
744ac11d857SVincenzo Maffione }
745ac11d857SVincenzo Maffione 
746ac11d857SVincenzo Maffione static int
747ac11d857SVincenzo Maffione iflib_num_tx_descs(if_ctx_t ctx)
748ac11d857SVincenzo Maffione {
749ac11d857SVincenzo Maffione 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
750ac11d857SVincenzo Maffione 	if_shared_ctx_t sctx = ctx->ifc_sctx;
751ac11d857SVincenzo Maffione 	uint16_t first_txq = (sctx->isc_flags & IFLIB_HAS_TXCQ) ? 1 : 0;
752ac11d857SVincenzo Maffione 
753ac11d857SVincenzo Maffione 	return scctx->isc_ntxd[first_txq];
754ac11d857SVincenzo Maffione }
755ac11d857SVincenzo Maffione 
7564c7070dbSScott Long #ifdef DEV_NETMAP
7574c7070dbSScott Long #include <sys/selinfo.h>
7584c7070dbSScott Long #include <net/netmap.h>
7594c7070dbSScott Long #include <dev/netmap/netmap_kern.h>
7604c7070dbSScott Long 
7614c7070dbSScott Long MODULE_DEPEND(iflib, netmap, 1, 1, 1);
7624c7070dbSScott Long 
763de5b4610SVincenzo Maffione static int netmap_fl_refill(iflib_rxq_t rxq, struct netmap_kring *kring, bool init);
76417cec474SVincenzo Maffione static void iflib_netmap_timer(void *arg);
7652d873474SStephen Hurd 
7664c7070dbSScott Long /*
7674c7070dbSScott Long  * device-specific sysctl variables:
7684c7070dbSScott Long  *
76991d546a0SConrad Meyer  * iflib_crcstrip: 0: keep CRC in rx frames (default), 1: strip it.
7704c7070dbSScott Long  *	During regular operations the CRC is stripped, but on some
7714c7070dbSScott Long  *	hardware reception of frames not multiple of 64 is slower,
7724c7070dbSScott Long  *	so using crcstrip=0 helps in benchmarks.
7734c7070dbSScott Long  *
77491d546a0SConrad Meyer  * iflib_rx_miss, iflib_rx_miss_bufs:
7754c7070dbSScott Long  *	count packets that might be missed due to lost interrupts.
7764c7070dbSScott Long  */
7774c7070dbSScott Long SYSCTL_DECL(_dev_netmap);
7784c7070dbSScott Long /*
7794c7070dbSScott Long  * The xl driver by default strips CRCs and we do not override it.
7804c7070dbSScott Long  */
7814c7070dbSScott Long 
7824c7070dbSScott Long int iflib_crcstrip = 1;
7834c7070dbSScott Long SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_crcstrip,
7841722eeacSMarius Strobl     CTLFLAG_RW, &iflib_crcstrip, 1, "strip CRC on RX frames");
7854c7070dbSScott Long 
7864c7070dbSScott Long int iflib_rx_miss, iflib_rx_miss_bufs;
7874c7070dbSScott Long SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_rx_miss,
7881722eeacSMarius Strobl     CTLFLAG_RW, &iflib_rx_miss, 0, "potentially missed RX intr");
78991d546a0SConrad Meyer SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_rx_miss_bufs,
7901722eeacSMarius Strobl     CTLFLAG_RW, &iflib_rx_miss_bufs, 0, "potentially missed RX intr bufs");
7914c7070dbSScott Long 
7924c7070dbSScott Long /*
7934c7070dbSScott Long  * Register/unregister. We are already under netmap lock.
7944c7070dbSScott Long  * Only called on the first register or the last unregister.
7954c7070dbSScott Long  */
7964c7070dbSScott Long static int
7974c7070dbSScott Long iflib_netmap_register(struct netmap_adapter *na, int onoff)
7984c7070dbSScott Long {
7991722eeacSMarius Strobl 	if_t ifp = na->ifp;
8004c7070dbSScott Long 	if_ctx_t ctx = ifp->if_softc;
80195246abbSSean Bruno 	int status;
8024c7070dbSScott Long 
8034c7070dbSScott Long 	CTX_LOCK(ctx);
8044c7070dbSScott Long 	if (!CTX_IS_VF(ctx))
8051248952aSSean Bruno 		IFDI_CRCSTRIP_SET(ctx, onoff, iflib_crcstrip);
8064c7070dbSScott Long 
8070a182b4cSVincenzo Maffione 	iflib_stop(ctx);
8080a182b4cSVincenzo Maffione 
8090a182b4cSVincenzo Maffione 	/*
8100a182b4cSVincenzo Maffione 	 * Enable (or disable) netmap flags, and intercept (or restore)
8110a182b4cSVincenzo Maffione 	 * ifp->if_transmit. This is done once the device has been stopped
8123d65fd97SVincenzo Maffione 	 * to prevent race conditions. Also, this must be done after
8133d65fd97SVincenzo Maffione 	 * calling netmap_disable_all_rings() and before calling
8143d65fd97SVincenzo Maffione 	 * netmap_enable_all_rings(), so that these two functions see the
8153d65fd97SVincenzo Maffione 	 * updated state of the NAF_NETMAP_ON bit.
8160a182b4cSVincenzo Maffione 	 */
8174c7070dbSScott Long 	if (onoff) {
8184c7070dbSScott Long 		nm_set_native_flags(na);
8194c7070dbSScott Long 	} else {
8204c7070dbSScott Long 		nm_clear_native_flags(na);
8214c7070dbSScott Long 	}
8220a182b4cSVincenzo Maffione 
82395246abbSSean Bruno 	iflib_init_locked(ctx);
8241248952aSSean Bruno 	IFDI_CRCSTRIP_SET(ctx, onoff, iflib_crcstrip); // XXX why twice ?
82595246abbSSean Bruno 	status = ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1;
82695246abbSSean Bruno 	if (status)
82795246abbSSean Bruno 		nm_clear_native_flags(na);
8284c7070dbSScott Long 	CTX_UNLOCK(ctx);
82995246abbSSean Bruno 	return (status);
8304c7070dbSScott Long }
8314c7070dbSScott Long 
8322d873474SStephen Hurd static int
83321d0c012Syou@x iflib_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
83421d0c012Syou@x {
83521d0c012Syou@x 	if_t ifp = na->ifp;
83621d0c012Syou@x 	if_ctx_t ctx = ifp->if_softc;
83721d0c012Syou@x 	iflib_rxq_t rxq = &ctx->ifc_rxqs[0];
83821d0c012Syou@x 	iflib_fl_t fl = &rxq->ifr_fl[0];
83921d0c012Syou@x 
84021d0c012Syou@x 	info->num_tx_rings = ctx->ifc_softc_ctx.isc_ntxqsets;
84121d0c012Syou@x 	info->num_rx_rings = ctx->ifc_softc_ctx.isc_nrxqsets;
84221d0c012Syou@x 	info->num_tx_descs = iflib_num_tx_descs(ctx);
84321d0c012Syou@x 	info->num_rx_descs = iflib_num_rx_descs(ctx);
84421d0c012Syou@x 	info->rx_buf_maxsize = fl->ifl_buf_size;
84521d0c012Syou@x 	nm_prinf("txr %u rxr %u txd %u rxd %u rbufsz %u",
84621d0c012Syou@x 		info->num_tx_rings, info->num_rx_rings, info->num_tx_descs,
84721d0c012Syou@x 		info->num_rx_descs, info->rx_buf_maxsize);
84821d0c012Syou@x 
84921d0c012Syou@x 	return 0;
85021d0c012Syou@x }
85121d0c012Syou@x 
85221d0c012Syou@x static int
853de5b4610SVincenzo Maffione netmap_fl_refill(iflib_rxq_t rxq, struct netmap_kring *kring, bool init)
8542d873474SStephen Hurd {
8552d873474SStephen Hurd 	struct netmap_adapter *na = kring->na;
8562d873474SStephen Hurd 	u_int const lim = kring->nkr_num_slots - 1;
8572d873474SStephen Hurd 	struct netmap_ring *ring = kring->ring;
8582d873474SStephen Hurd 	bus_dmamap_t *map;
8592d873474SStephen Hurd 	struct if_rxd_update iru;
8602d873474SStephen Hurd 	if_ctx_t ctx = rxq->ifr_ctx;
8612d873474SStephen Hurd 	iflib_fl_t fl = &rxq->ifr_fl[0];
862de5b4610SVincenzo Maffione 	u_int nic_i_first, nic_i;
86355f0ad5fSVincenzo Maffione 	u_int nm_i;
864ae750d5cSVincenzo Maffione 	int i, n;
86564e6fc13SStephen Hurd #if IFLIB_DEBUG_COUNTERS
86664e6fc13SStephen Hurd 	int rf_count = 0;
86764e6fc13SStephen Hurd #endif
8682d873474SStephen Hurd 
869de5b4610SVincenzo Maffione 	/*
870ae750d5cSVincenzo Maffione 	 * This function is used both at initialization and in rxsync.
871ae750d5cSVincenzo Maffione 	 * At initialization we need to prepare (with isc_rxd_refill())
87255f0ad5fSVincenzo Maffione 	 * all the netmap buffers currently owned by the kernel, in
87355f0ad5fSVincenzo Maffione 	 * such a way to keep fl->ifl_pidx and kring->nr_hwcur in sync
87455f0ad5fSVincenzo Maffione 	 * (except for kring->nkr_hwofs). These may be less than
87555f0ad5fSVincenzo Maffione 	 * kring->nkr_num_slots if netmap_reset() was called while
87655f0ad5fSVincenzo Maffione 	 * an application using the kring that still owned some
87755f0ad5fSVincenzo Maffione 	 * buffers.
87855f0ad5fSVincenzo Maffione 	 * At rxsync time, both indexes point to the next buffer to be
87955f0ad5fSVincenzo Maffione 	 * refilled.
880ae750d5cSVincenzo Maffione 	 * In any case we publish (with isc_rxd_flush()) up to
881ae750d5cSVincenzo Maffione 	 * (fl->ifl_pidx - 1) % N (included), to avoid the NIC tail/prod
882ae750d5cSVincenzo Maffione 	 * pointer to overrun the head/cons pointer, although this is
883ae750d5cSVincenzo Maffione 	 * not necessary for some NICs (e.g. vmx).
884de5b4610SVincenzo Maffione 	 */
88555f0ad5fSVincenzo Maffione 	if (__predict_false(init)) {
88655f0ad5fSVincenzo Maffione 		n = kring->nkr_num_slots - nm_kr_rxspace(kring);
88755f0ad5fSVincenzo Maffione 	} else {
88855f0ad5fSVincenzo Maffione 		n = kring->rhead - kring->nr_hwcur;
889ae750d5cSVincenzo Maffione 		if (n == 0)
890ae750d5cSVincenzo Maffione 			return (0); /* Nothing to do. */
891ae750d5cSVincenzo Maffione 		if (n < 0)
892ae750d5cSVincenzo Maffione 			n += kring->nkr_num_slots;
893de5b4610SVincenzo Maffione 	}
894530960beSVincenzo Maffione 
8952d873474SStephen Hurd 	iru_init(&iru, rxq, 0 /* flid */);
8962d873474SStephen Hurd 	map = fl->ifl_sds.ifsd_map;
897ae750d5cSVincenzo Maffione 	nic_i = fl->ifl_pidx;
89855f0ad5fSVincenzo Maffione 	nm_i = netmap_idx_n2k(kring, nic_i);
89955f0ad5fSVincenzo Maffione 	if (__predict_false(init)) {
90055f0ad5fSVincenzo Maffione 		/*
90155f0ad5fSVincenzo Maffione 		 * On init/reset, nic_i must be 0, and we must
90255f0ad5fSVincenzo Maffione 		 * start to refill from hwtail (see netmap_reset()).
90355f0ad5fSVincenzo Maffione 		 */
90455f0ad5fSVincenzo Maffione 		MPASS(nic_i == 0);
90555f0ad5fSVincenzo Maffione 		MPASS(nm_i == kring->nr_hwtail);
90655f0ad5fSVincenzo Maffione 	} else
90755f0ad5fSVincenzo Maffione 		MPASS(nm_i == kring->nr_hwcur);
90864e6fc13SStephen Hurd 	DBG_COUNTER_INC(fl_refills);
909ae750d5cSVincenzo Maffione 	while (n > 0) {
91064e6fc13SStephen Hurd #if IFLIB_DEBUG_COUNTERS
91164e6fc13SStephen Hurd 		if (++rf_count == 9)
91264e6fc13SStephen Hurd 			DBG_COUNTER_INC(fl_refills_large);
91364e6fc13SStephen Hurd #endif
914530960beSVincenzo Maffione 		nic_i_first = nic_i;
915ae750d5cSVincenzo Maffione 		for (i = 0; n > 0 && i < IFLIB_MAX_RX_REFRESH; n--, i++) {
9162d873474SStephen Hurd 			struct netmap_slot *slot = &ring->slot[nm_i];
917*361e9501SVincenzo Maffione 			uint64_t paddr;
918*361e9501SVincenzo Maffione 			void *addr = PNMB(na, slot, &paddr);
9192d873474SStephen Hurd 
920530960beSVincenzo Maffione 			MPASS(i < IFLIB_MAX_RX_REFRESH);
9212d873474SStephen Hurd 
9222d873474SStephen Hurd 			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
9232d873474SStephen Hurd 			        return netmap_ring_reinit(kring);
9242d873474SStephen Hurd 
925*361e9501SVincenzo Maffione 			fl->ifl_bus_addrs[i] = paddr +
926*361e9501SVincenzo Maffione 			    nm_get_offset(kring, slot);
927530960beSVincenzo Maffione 			fl->ifl_rxd_idxs[i] = nic_i;
928530960beSVincenzo Maffione 
92995dcf343SMarius Strobl 			if (__predict_false(init)) {
93095dcf343SMarius Strobl 				netmap_load_map(na, fl->ifl_buf_tag,
93195dcf343SMarius Strobl 				    map[nic_i], addr);
93295dcf343SMarius Strobl 			} else if (slot->flags & NS_BUF_CHANGED) {
9332d873474SStephen Hurd 				/* buffer has changed, reload map */
93495dcf343SMarius Strobl 				netmap_reload_map(na, fl->ifl_buf_tag,
93595dcf343SMarius Strobl 				    map[nic_i], addr);
9362d873474SStephen Hurd 			}
937530960beSVincenzo Maffione 			bus_dmamap_sync(fl->ifl_buf_tag, map[nic_i],
938530960beSVincenzo Maffione 			    BUS_DMASYNC_PREREAD);
9392d873474SStephen Hurd 			slot->flags &= ~NS_BUF_CHANGED;
9402d873474SStephen Hurd 
9412d873474SStephen Hurd 			nm_i = nm_next(nm_i, lim);
942530960beSVincenzo Maffione 			nic_i = nm_next(nic_i, lim);
943530960beSVincenzo Maffione 		}
9442d873474SStephen Hurd 
945530960beSVincenzo Maffione 		iru.iru_pidx = nic_i_first;
946530960beSVincenzo Maffione 		iru.iru_count = i;
9472d873474SStephen Hurd 		ctx->isc_rxd_refill(ctx->ifc_softc, &iru);
9482d873474SStephen Hurd 	}
949ae750d5cSVincenzo Maffione 	fl->ifl_pidx = nic_i;
95055f0ad5fSVincenzo Maffione 	/*
95155f0ad5fSVincenzo Maffione 	 * At the end of the loop we must have refilled everything
95255f0ad5fSVincenzo Maffione 	 * we could possibly refill.
95355f0ad5fSVincenzo Maffione 	 */
954ae750d5cSVincenzo Maffione 	MPASS(nm_i == kring->rhead);
955ae750d5cSVincenzo Maffione 	kring->nr_hwcur = nm_i;
9562d873474SStephen Hurd 
9572d873474SStephen Hurd 	bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
9582d873474SStephen Hurd 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
959de5b4610SVincenzo Maffione 	ctx->isc_rxd_flush(ctx->ifc_softc, rxq->ifr_id, fl->ifl_id,
960de5b4610SVincenzo Maffione 	    nm_prev(nic_i, lim));
96164e6fc13SStephen Hurd 	DBG_COUNTER_INC(rxd_flush);
962530960beSVincenzo Maffione 
9632d873474SStephen Hurd 	return (0);
9642d873474SStephen Hurd }
9652d873474SStephen Hurd 
96617cec474SVincenzo Maffione #define NETMAP_TX_TIMER_US	90
96717cec474SVincenzo Maffione 
9684c7070dbSScott Long /*
9694c7070dbSScott Long  * Reconcile kernel and user view of the transmit ring.
9704c7070dbSScott Long  *
9714c7070dbSScott Long  * All information is in the kring.
9724c7070dbSScott Long  * Userspace wants to send packets up to the one before kring->rhead,
9734c7070dbSScott Long  * kernel knows kring->nr_hwcur is the first unsent packet.
9744c7070dbSScott Long  *
9754c7070dbSScott Long  * Here we push packets out (as many as possible), and possibly
9764c7070dbSScott Long  * reclaim buffers from previously completed transmission.
9774c7070dbSScott Long  *
9784c7070dbSScott Long  * The caller (netmap) guarantees that there is only one instance
9794c7070dbSScott Long  * running at any time. Any interference with other driver
9804c7070dbSScott Long  * methods should be handled by the individual drivers.
9814c7070dbSScott Long  */
9824c7070dbSScott Long static int
9834c7070dbSScott Long iflib_netmap_txsync(struct netmap_kring *kring, int flags)
9844c7070dbSScott Long {
9854c7070dbSScott Long 	struct netmap_adapter *na = kring->na;
9861722eeacSMarius Strobl 	if_t ifp = na->ifp;
9874c7070dbSScott Long 	struct netmap_ring *ring = kring->ring;
988dd7fbcf1SStephen Hurd 	u_int nm_i;	/* index into the netmap kring */
9894c7070dbSScott Long 	u_int nic_i;	/* index into the NIC ring */
9904c7070dbSScott Long 	u_int n;
9914c7070dbSScott Long 	u_int const lim = kring->nkr_num_slots - 1;
9924c7070dbSScott Long 	u_int const head = kring->rhead;
9934c7070dbSScott Long 	struct if_pkt_info pi;
9944c7070dbSScott Long 
9954c7070dbSScott Long 	/*
9964c7070dbSScott Long 	 * interrupts on every tx packet are expensive so request
9974c7070dbSScott Long 	 * them every half ring, or where NS_REPORT is set
9984c7070dbSScott Long 	 */
9994c7070dbSScott Long 	u_int report_frequency = kring->nkr_num_slots >> 1;
10004c7070dbSScott Long 	/* device-specific */
10014c7070dbSScott Long 	if_ctx_t ctx = ifp->if_softc;
10024c7070dbSScott Long 	iflib_txq_t txq = &ctx->ifc_txqs[kring->ring_id];
10034c7070dbSScott Long 
100495dcf343SMarius Strobl 	bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
10054c7070dbSScott Long 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
10064c7070dbSScott Long 
10074c7070dbSScott Long 	/*
10084c7070dbSScott Long 	 * First part: process new packets to send.
1009dd7fbcf1SStephen Hurd 	 * nm_i is the current index in the netmap kring,
10104c7070dbSScott Long 	 * nic_i is the corresponding index in the NIC ring.
10114c7070dbSScott Long 	 *
10124c7070dbSScott Long 	 * If we have packets to send (nm_i != head)
10134c7070dbSScott Long 	 * iterate over the netmap ring, fetch length and update
10144c7070dbSScott Long 	 * the corresponding slot in the NIC ring. Some drivers also
10154c7070dbSScott Long 	 * need to update the buffer's physical address in the NIC slot
10164c7070dbSScott Long 	 * even NS_BUF_CHANGED is not set (PNMB computes the addresses).
10174c7070dbSScott Long 	 *
10184c7070dbSScott Long 	 * The netmap_reload_map() calls is especially expensive,
10194c7070dbSScott Long 	 * even when (as in this case) the tag is 0, so do only
10204c7070dbSScott Long 	 * when the buffer has actually changed.
10214c7070dbSScott Long 	 *
10224c7070dbSScott Long 	 * If possible do not set the report/intr bit on all slots,
10234c7070dbSScott Long 	 * but only a few times per ring or when NS_REPORT is set.
10244c7070dbSScott Long 	 *
10254c7070dbSScott Long 	 * Finally, on 10G and faster drivers, it might be useful
10264c7070dbSScott Long 	 * to prefetch the next slot and txr entry.
10274c7070dbSScott Long 	 */
10284c7070dbSScott Long 
1029dd7fbcf1SStephen Hurd 	nm_i = kring->nr_hwcur;
10305ee36c68SStephen Hurd 	if (nm_i != head) {	/* we have new packets to send */
1031aceaccabSVincenzo Maffione 		uint32_t pkt_len = 0, seg_idx = 0;
1032aceaccabSVincenzo Maffione 		int nic_i_start = -1, flags = 0;
103395246abbSSean Bruno 		pkt_info_zero(&pi);
103495246abbSSean Bruno 		pi.ipi_segs = txq->ift_segs;
103595246abbSSean Bruno 		pi.ipi_qsidx = kring->ring_id;
10364c7070dbSScott Long 		nic_i = netmap_idx_k2n(kring, nm_i);
10374c7070dbSScott Long 
10384c7070dbSScott Long 		__builtin_prefetch(&ring->slot[nm_i]);
10394c7070dbSScott Long 		__builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i]);
10404c7070dbSScott Long 		__builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i]);
10414c7070dbSScott Long 
10424c7070dbSScott Long 		for (n = 0; nm_i != head; n++) {
10434c7070dbSScott Long 			struct netmap_slot *slot = &ring->slot[nm_i];
1044*361e9501SVincenzo Maffione 			uint64_t offset = nm_get_offset(kring, slot);
10454c7070dbSScott Long 			u_int len = slot->len;
10460a1b74a3SSean Bruno 			uint64_t paddr;
10474c7070dbSScott Long 			void *addr = PNMB(na, slot, &paddr);
1048aceaccabSVincenzo Maffione 
1049aceaccabSVincenzo Maffione 			flags |= (slot->flags & NS_REPORT ||
10504c7070dbSScott Long 				nic_i == 0 || nic_i == report_frequency) ?
10514c7070dbSScott Long 				IPI_TX_INTR : 0;
10524c7070dbSScott Long 
1053aceaccabSVincenzo Maffione 			/*
1054aceaccabSVincenzo Maffione 			 * If this is the first packet fragment, save the
1055aceaccabSVincenzo Maffione 			 * index of the first NIC slot for later.
1056aceaccabSVincenzo Maffione 			 */
1057aceaccabSVincenzo Maffione 			if (nic_i_start < 0)
1058aceaccabSVincenzo Maffione 				nic_i_start = nic_i;
1059aceaccabSVincenzo Maffione 
1060*361e9501SVincenzo Maffione 			pi.ipi_segs[seg_idx].ds_addr = paddr + offset;
1061aceaccabSVincenzo Maffione 			pi.ipi_segs[seg_idx].ds_len = len;
1062aceaccabSVincenzo Maffione 			if (len) {
1063aceaccabSVincenzo Maffione 				pkt_len += len;
1064aceaccabSVincenzo Maffione 				seg_idx++;
1065aceaccabSVincenzo Maffione 			}
1066aceaccabSVincenzo Maffione 
1067aceaccabSVincenzo Maffione 			if (!(slot->flags & NS_MOREFRAG)) {
1068aceaccabSVincenzo Maffione 				pi.ipi_len = pkt_len;
1069aceaccabSVincenzo Maffione 				pi.ipi_nsegs = seg_idx;
1070aceaccabSVincenzo Maffione 				pi.ipi_pidx = nic_i_start;
107195246abbSSean Bruno 				pi.ipi_ndescs = 0;
10724c7070dbSScott Long 				pi.ipi_flags = flags;
10734c7070dbSScott Long 
1074aceaccabSVincenzo Maffione 				/* Prepare the NIC TX ring. */
10754c7070dbSScott Long 				ctx->isc_txd_encap(ctx->ifc_softc, &pi);
107664e6fc13SStephen Hurd 				DBG_COUNTER_INC(tx_encap);
10774c7070dbSScott Long 
1078aceaccabSVincenzo Maffione 				/* Reinit per-packet info for the next one. */
1079aceaccabSVincenzo Maffione 				flags = seg_idx = pkt_len = 0;
1080aceaccabSVincenzo Maffione 				nic_i_start = -1;
1081aceaccabSVincenzo Maffione 			}
1082aceaccabSVincenzo Maffione 
10834c7070dbSScott Long 			/* prefetch for next round */
10844c7070dbSScott Long 			__builtin_prefetch(&ring->slot[nm_i + 1]);
10854c7070dbSScott Long 			__builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i + 1]);
10864c7070dbSScott Long 			__builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i + 1]);
10874c7070dbSScott Long 
1088*361e9501SVincenzo Maffione 			NM_CHECK_ADDR_LEN_OFF(na, len, offset);
10894c7070dbSScott Long 
10904c7070dbSScott Long 			if (slot->flags & NS_BUF_CHANGED) {
10914c7070dbSScott Long 				/* buffer has changed, reload map */
1092bfce461eSMarius Strobl 				netmap_reload_map(na, txq->ift_buf_tag,
1093bfce461eSMarius Strobl 				    txq->ift_sds.ifsd_map[nic_i], addr);
10944c7070dbSScott Long 			}
10954c7070dbSScott Long 			/* make sure changes to the buffer are synced */
109695dcf343SMarius Strobl 			bus_dmamap_sync(txq->ift_buf_tag,
109795dcf343SMarius Strobl 			    txq->ift_sds.ifsd_map[nic_i],
10984c7070dbSScott Long 			    BUS_DMASYNC_PREWRITE);
109995dcf343SMarius Strobl 
1100aceaccabSVincenzo Maffione 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
11014c7070dbSScott Long 			nm_i = nm_next(nm_i, lim);
11024c7070dbSScott Long 			nic_i = nm_next(nic_i, lim);
11034c7070dbSScott Long 		}
1104dd7fbcf1SStephen Hurd 		kring->nr_hwcur = nm_i;
11054c7070dbSScott Long 
11064c7070dbSScott Long 		/* synchronize the NIC ring */
110795dcf343SMarius Strobl 		bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
11084c7070dbSScott Long 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11094c7070dbSScott Long 
11104c7070dbSScott Long 		/* (re)start the tx unit up to slot nic_i (excluded) */
11114c7070dbSScott Long 		ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, nic_i);
11124c7070dbSScott Long 	}
11134c7070dbSScott Long 
11144c7070dbSScott Long 	/*
11154c7070dbSScott Long 	 * Second part: reclaim buffers for completed transmissions.
11165ee36c68SStephen Hurd 	 *
11175ee36c68SStephen Hurd 	 * If there are unclaimed buffers, attempt to reclaim them.
111817cec474SVincenzo Maffione 	 * If we don't manage to reclaim them all, and TX IRQs are not in use,
111917cec474SVincenzo Maffione 	 * trigger a per-tx-queue timer to try again later.
11204c7070dbSScott Long 	 */
1121dd7fbcf1SStephen Hurd 	if (kring->nr_hwtail != nm_prev(kring->nr_hwcur, lim)) {
11224c7070dbSScott Long 		if (iflib_tx_credits_update(ctx, txq)) {
11234c7070dbSScott Long 			/* some tx completed, increment avail */
11244c7070dbSScott Long 			nic_i = txq->ift_cidx_processed;
11254c7070dbSScott Long 			kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
11264c7070dbSScott Long 		}
11275ee36c68SStephen Hurd 	}
112817cec474SVincenzo Maffione 
1129dd7fbcf1SStephen Hurd 	if (!(ctx->ifc_flags & IFC_NETMAP_TX_IRQ))
1130dd7fbcf1SStephen Hurd 		if (kring->nr_hwtail != nm_prev(kring->nr_hwcur, lim)) {
1131be7a6b3dSVincenzo Maffione 			callout_reset_sbt_on(&txq->ift_netmap_timer,
113217cec474SVincenzo Maffione 			    NETMAP_TX_TIMER_US * SBT_1US, SBT_1US,
1133be7a6b3dSVincenzo Maffione 			    iflib_netmap_timer, txq,
1134be7a6b3dSVincenzo Maffione 			    txq->ift_netmap_timer.c_cpu, 0);
11355ee36c68SStephen Hurd 		}
11364c7070dbSScott Long 	return (0);
11374c7070dbSScott Long }
11384c7070dbSScott Long 
11394c7070dbSScott Long /*
11404c7070dbSScott Long  * Reconcile kernel and user view of the receive ring.
11414c7070dbSScott Long  * Same as for the txsync, this routine must be efficient.
11424c7070dbSScott Long  * The caller guarantees a single invocations, but races against
11434c7070dbSScott Long  * the rest of the driver should be handled here.
11444c7070dbSScott Long  *
11454c7070dbSScott Long  * On call, kring->rhead is the first packet that userspace wants
11464c7070dbSScott Long  * to keep, and kring->rcur is the wakeup point.
11474c7070dbSScott Long  * The kernel has previously reported packets up to kring->rtail.
11484c7070dbSScott Long  *
11494c7070dbSScott Long  * If (flags & NAF_FORCE_READ) also check for incoming packets irrespective
11504c7070dbSScott Long  * of whether or not we received an interrupt.
11514c7070dbSScott Long  */
11524c7070dbSScott Long static int
11534c7070dbSScott Long iflib_netmap_rxsync(struct netmap_kring *kring, int flags)
11544c7070dbSScott Long {
11554c7070dbSScott Long 	struct netmap_adapter *na = kring->na;
11564c7070dbSScott Long 	struct netmap_ring *ring = kring->ring;
11571722eeacSMarius Strobl 	if_t ifp = na->ifp;
115895246abbSSean Bruno 	uint32_t nm_i;	/* index into the netmap ring */
11592d873474SStephen Hurd 	uint32_t nic_i;	/* index into the NIC ring */
1160ee07345dSVincenzo Maffione 	u_int n;
11614c7070dbSScott Long 	u_int const lim = kring->nkr_num_slots - 1;
11624c7070dbSScott Long 	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
1163aceaccabSVincenzo Maffione 	int i = 0;
116495246abbSSean Bruno 
11654c7070dbSScott Long 	if_ctx_t ctx = ifp->if_softc;
11666d84e76aSVincenzo Maffione 	if_shared_ctx_t sctx = ctx->ifc_sctx;
11676d84e76aSVincenzo Maffione 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
11684c7070dbSScott Long 	iflib_rxq_t rxq = &ctx->ifc_rxqs[kring->ring_id];
1169ee07345dSVincenzo Maffione 	iflib_fl_t fl = &rxq->ifr_fl[0];
1170ee07345dSVincenzo Maffione 	struct if_rxd_info ri;
11716d84e76aSVincenzo Maffione 	qidx_t *cidxp;
1172ee07345dSVincenzo Maffione 
117395dcf343SMarius Strobl 	/*
1174ee07345dSVincenzo Maffione 	 * netmap only uses free list 0, to avoid out of order consumption
1175ee07345dSVincenzo Maffione 	 * of receive buffers
117695dcf343SMarius Strobl 	 */
117795dcf343SMarius Strobl 
117895dcf343SMarius Strobl 	bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
11794c7070dbSScott Long 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
118095dcf343SMarius Strobl 
11814c7070dbSScott Long 	/*
11824c7070dbSScott Long 	 * First part: import newly received packets.
11834c7070dbSScott Long 	 *
11844c7070dbSScott Long 	 * nm_i is the index of the next free slot in the netmap ring,
11856d84e76aSVincenzo Maffione 	 * nic_i is the index of the next received packet in the NIC ring
11866d84e76aSVincenzo Maffione 	 * (or in the free list 0 if IFLIB_HAS_RXCQ is set), and they may
11876d84e76aSVincenzo Maffione 	 * differ in case if_init() has been called while
11884c7070dbSScott Long 	 * in netmap mode. For the receive ring we have
11894c7070dbSScott Long 	 *
11906d84e76aSVincenzo Maffione 	 *	nic_i = fl->ifl_cidx;
11914c7070dbSScott Long 	 *	nm_i = kring->nr_hwtail (previous)
11924c7070dbSScott Long 	 * and
11934c7070dbSScott Long 	 *	nm_i == (nic_i + kring->nkr_hwofs) % ring_size
11944c7070dbSScott Long 	 *
11956d84e76aSVincenzo Maffione 	 * fl->ifl_cidx is set to 0 on a ring reinit
11964c7070dbSScott Long 	 */
11974c7070dbSScott Long 	if (netmap_no_pendintr || force_update) {
11980ff21267SVincenzo Maffione 		uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim);
11996d84e76aSVincenzo Maffione 		bool have_rxcq = sctx->isc_flags & IFLIB_HAS_RXCQ;
12004c7070dbSScott Long 		int crclen = iflib_crcstrip ? 0 : 4;
12014c7070dbSScott Long 		int error, avail;
12024c7070dbSScott Long 
12036d84e76aSVincenzo Maffione 		/*
12046d84e76aSVincenzo Maffione 		 * For the free list consumer index, we use the same
12056d84e76aSVincenzo Maffione 		 * logic as in iflib_rxeof().
12066d84e76aSVincenzo Maffione 		 */
12076d84e76aSVincenzo Maffione 		if (have_rxcq)
12086d84e76aSVincenzo Maffione 			cidxp = &rxq->ifr_cq_cidx;
12096d84e76aSVincenzo Maffione 		else
12106d84e76aSVincenzo Maffione 			cidxp = &fl->ifl_cidx;
12116d84e76aSVincenzo Maffione 		avail = ctx->isc_rxd_available(ctx->ifc_softc,
12126d84e76aSVincenzo Maffione 		    rxq->ifr_id, *cidxp, USHRT_MAX);
12136d84e76aSVincenzo Maffione 
12144c7070dbSScott Long 		nic_i = fl->ifl_cidx;
12154c7070dbSScott Long 		nm_i = netmap_idx_n2k(kring, nic_i);
1216de5b4610SVincenzo Maffione 		MPASS(nm_i == kring->nr_hwtail);
12170ff21267SVincenzo Maffione 		for (n = 0; avail > 0 && nm_i != hwtail_lim; n++, avail--) {
1218ab2e3f79SStephen Hurd 			rxd_info_zero(&ri);
1219ab2e3f79SStephen Hurd 			ri.iri_frags = rxq->ifr_frags;
1220ab2e3f79SStephen Hurd 			ri.iri_qsidx = kring->ring_id;
1221ab2e3f79SStephen Hurd 			ri.iri_ifp = ctx->ifc_ifp;
12226d84e76aSVincenzo Maffione 			ri.iri_cidx = *cidxp;
122395246abbSSean Bruno 
1224ab2e3f79SStephen Hurd 			error = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri);
1225aceaccabSVincenzo Maffione 			for (i = 0; i < ri.iri_nfrags; i++) {
1226aceaccabSVincenzo Maffione 				if (error) {
1227aceaccabSVincenzo Maffione 					ring->slot[nm_i].len = 0;
12287cb7c6e3SNavdeep Parhar 					ring->slot[nm_i].flags = 0;
1229aceaccabSVincenzo Maffione 				} else {
1230aceaccabSVincenzo Maffione 					ring->slot[nm_i].len = ri.iri_frags[i].irf_len;
1231aceaccabSVincenzo Maffione 					if (i == (ri.iri_nfrags - 1)) {
1232aceaccabSVincenzo Maffione 						ring->slot[nm_i].len -= crclen;
1233aceaccabSVincenzo Maffione 						ring->slot[nm_i].flags = 0;
1234aceaccabSVincenzo Maffione 					} else
1235aceaccabSVincenzo Maffione 						ring->slot[nm_i].flags = NS_MOREFRAG;
1236aceaccabSVincenzo Maffione 				}
1237aceaccabSVincenzo Maffione 
1238f80efe50SVincenzo Maffione 				bus_dmamap_sync(fl->ifl_buf_tag,
1239f80efe50SVincenzo Maffione 				    fl->ifl_sds.ifsd_map[nic_i], BUS_DMASYNC_POSTREAD);
1240f80efe50SVincenzo Maffione 				nm_i = nm_next(nm_i, lim);
1241f80efe50SVincenzo Maffione 				fl->ifl_cidx = nic_i = nm_next(nic_i, lim);
1242f80efe50SVincenzo Maffione 			}
1243f80efe50SVincenzo Maffione 
12446d84e76aSVincenzo Maffione 			if (have_rxcq) {
12456d84e76aSVincenzo Maffione 				*cidxp = ri.iri_cidx;
12466d84e76aSVincenzo Maffione 				while (*cidxp >= scctx->isc_nrxd[0])
12476d84e76aSVincenzo Maffione 					*cidxp -= scctx->isc_nrxd[0];
12486d84e76aSVincenzo Maffione 			}
1249aceaccabSVincenzo Maffione 
1250aceaccabSVincenzo Maffione 		}
12514c7070dbSScott Long 		if (n) { /* update the state variables */
12524c7070dbSScott Long 			if (netmap_no_pendintr && !force_update) {
12534c7070dbSScott Long 				/* diagnostics */
12544c7070dbSScott Long 				iflib_rx_miss ++;
12554c7070dbSScott Long 				iflib_rx_miss_bufs += n;
12564c7070dbSScott Long 			}
1257dd7fbcf1SStephen Hurd 			kring->nr_hwtail = nm_i;
12584c7070dbSScott Long 		}
12594c7070dbSScott Long 		kring->nr_kflags &= ~NKR_PENDINTR;
12604c7070dbSScott Long 	}
12614c7070dbSScott Long 	/*
12624c7070dbSScott Long 	 * Second part: skip past packets that userspace has released.
12634c7070dbSScott Long 	 * (kring->nr_hwcur to head excluded),
12644c7070dbSScott Long 	 * and make the buffers available for reception.
12654c7070dbSScott Long 	 * As usual nm_i is the index in the netmap ring,
12664c7070dbSScott Long 	 * nic_i is the index in the NIC ring, and
12674c7070dbSScott Long 	 * nm_i == (nic_i + kring->nkr_hwofs) % ring_size
12684c7070dbSScott Long 	 */
1269de5b4610SVincenzo Maffione 	netmap_fl_refill(rxq, kring, false);
127095246abbSSean Bruno 
1271de5b4610SVincenzo Maffione 	return (0);
12724c7070dbSScott Long }
12734c7070dbSScott Long 
127495246abbSSean Bruno static void
127595246abbSSean Bruno iflib_netmap_intr(struct netmap_adapter *na, int onoff)
127695246abbSSean Bruno {
12771722eeacSMarius Strobl 	if_ctx_t ctx = na->ifp->if_softc;
127895246abbSSean Bruno 
1279ab2e3f79SStephen Hurd 	CTX_LOCK(ctx);
128095246abbSSean Bruno 	if (onoff) {
128195246abbSSean Bruno 		IFDI_INTR_ENABLE(ctx);
128295246abbSSean Bruno 	} else {
128395246abbSSean Bruno 		IFDI_INTR_DISABLE(ctx);
128495246abbSSean Bruno 	}
1285ab2e3f79SStephen Hurd 	CTX_UNLOCK(ctx);
128695246abbSSean Bruno }
128795246abbSSean Bruno 
12884c7070dbSScott Long static int
12894c7070dbSScott Long iflib_netmap_attach(if_ctx_t ctx)
12904c7070dbSScott Long {
12914c7070dbSScott Long 	struct netmap_adapter na;
12924c7070dbSScott Long 
12934c7070dbSScott Long 	bzero(&na, sizeof(na));
12944c7070dbSScott Long 
12954c7070dbSScott Long 	na.ifp = ctx->ifc_ifp;
1296*361e9501SVincenzo Maffione 	na.na_flags = NAF_BDG_MAYSLEEP | NAF_MOREFRAG | NAF_OFFSETS;
12974c7070dbSScott Long 	MPASS(ctx->ifc_softc_ctx.isc_ntxqsets);
12984c7070dbSScott Long 	MPASS(ctx->ifc_softc_ctx.isc_nrxqsets);
12994c7070dbSScott Long 
1300ac11d857SVincenzo Maffione 	na.num_tx_desc = iflib_num_tx_descs(ctx);
1301ac11d857SVincenzo Maffione 	na.num_rx_desc = iflib_num_rx_descs(ctx);
13024c7070dbSScott Long 	na.nm_txsync = iflib_netmap_txsync;
13034c7070dbSScott Long 	na.nm_rxsync = iflib_netmap_rxsync;
13044c7070dbSScott Long 	na.nm_register = iflib_netmap_register;
130595246abbSSean Bruno 	na.nm_intr = iflib_netmap_intr;
130621d0c012Syou@x 	na.nm_config = iflib_netmap_config;
13074c7070dbSScott Long 	na.num_tx_rings = ctx->ifc_softc_ctx.isc_ntxqsets;
13084c7070dbSScott Long 	na.num_rx_rings = ctx->ifc_softc_ctx.isc_nrxqsets;
13094c7070dbSScott Long 	return (netmap_attach(&na));
13104c7070dbSScott Long }
13114c7070dbSScott Long 
1312d8b2d26bSVincenzo Maffione static int
13134c7070dbSScott Long iflib_netmap_txq_init(if_ctx_t ctx, iflib_txq_t txq)
13144c7070dbSScott Long {
13154c7070dbSScott Long 	struct netmap_adapter *na = NA(ctx->ifc_ifp);
13164c7070dbSScott Long 	struct netmap_slot *slot;
13174c7070dbSScott Long 
13184c7070dbSScott Long 	slot = netmap_reset(na, NR_TX, txq->ift_id, 0);
1319e099b90bSPedro F. Giffuni 	if (slot == NULL)
1320d8b2d26bSVincenzo Maffione 		return (0);
132123ac9029SStephen Hurd 	for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxd[0]; i++) {
13224c7070dbSScott Long 		/*
13234c7070dbSScott Long 		 * In netmap mode, set the map for the packet buffer.
13244c7070dbSScott Long 		 * NOTE: Some drivers (not this one) also need to set
13254c7070dbSScott Long 		 * the physical buffer address in the NIC ring.
13264c7070dbSScott Long 		 * netmap_idx_n2k() maps a nic index, i, into the corresponding
13274c7070dbSScott Long 		 * netmap slot index, si
13284c7070dbSScott Long 		 */
13292ff91c17SVincenzo Maffione 		int si = netmap_idx_n2k(na->tx_rings[txq->ift_id], i);
1330bfce461eSMarius Strobl 		netmap_load_map(na, txq->ift_buf_tag, txq->ift_sds.ifsd_map[i],
1331bfce461eSMarius Strobl 		    NMB(na, slot + si));
13324c7070dbSScott Long 	}
1333d8b2d26bSVincenzo Maffione 	return (1);
13344c7070dbSScott Long }
13352d873474SStephen Hurd 
1336d8b2d26bSVincenzo Maffione static int
13374c7070dbSScott Long iflib_netmap_rxq_init(if_ctx_t ctx, iflib_rxq_t rxq)
13384c7070dbSScott Long {
13394c7070dbSScott Long 	struct netmap_adapter *na = NA(ctx->ifc_ifp);
1340d8b2d26bSVincenzo Maffione 	struct netmap_kring *kring;
13414c7070dbSScott Long 	struct netmap_slot *slot;
13424c7070dbSScott Long 
13434c7070dbSScott Long 	slot = netmap_reset(na, NR_RX, rxq->ifr_id, 0);
1344e099b90bSPedro F. Giffuni 	if (slot == NULL)
1345d8b2d26bSVincenzo Maffione 		return (0);
1346d8b2d26bSVincenzo Maffione 	kring = na->rx_rings[rxq->ifr_id];
1347de5b4610SVincenzo Maffione 	netmap_fl_refill(rxq, kring, true);
1348d8b2d26bSVincenzo Maffione 	return (1);
13494c7070dbSScott Long }
13504c7070dbSScott Long 
1351dd7fbcf1SStephen Hurd static void
135217cec474SVincenzo Maffione iflib_netmap_timer(void *arg)
1353dd7fbcf1SStephen Hurd {
135417cec474SVincenzo Maffione 	iflib_txq_t txq = arg;
135517cec474SVincenzo Maffione 	if_ctx_t ctx = txq->ift_ctx;
1356dd7fbcf1SStephen Hurd 
135717cec474SVincenzo Maffione 	/*
135817cec474SVincenzo Maffione 	 * Wake up the netmap application, to give it a chance to
135917cec474SVincenzo Maffione 	 * call txsync and reclaim more completed TX buffers.
136017cec474SVincenzo Maffione 	 */
136117cec474SVincenzo Maffione 	netmap_tx_irq(ctx->ifc_ifp, txq->ift_id);
1362dd7fbcf1SStephen Hurd }
1363dd7fbcf1SStephen Hurd 
13644c7070dbSScott Long #define iflib_netmap_detach(ifp) netmap_detach(ifp)
13654c7070dbSScott Long 
13664c7070dbSScott Long #else
1367d8b2d26bSVincenzo Maffione #define iflib_netmap_txq_init(ctx, txq) (0)
1368d8b2d26bSVincenzo Maffione #define iflib_netmap_rxq_init(ctx, rxq) (0)
13694c7070dbSScott Long #define iflib_netmap_detach(ifp)
13708aa8484cSVincenzo Maffione #define netmap_enable_all_rings(ifp)
13718aa8484cSVincenzo Maffione #define netmap_disable_all_rings(ifp)
13724c7070dbSScott Long 
13734c7070dbSScott Long #define iflib_netmap_attach(ctx) (0)
13744c7070dbSScott Long #define netmap_rx_irq(ifp, qid, budget) (0)
13754c7070dbSScott Long #endif
13764c7070dbSScott Long 
13774c7070dbSScott Long #if defined(__i386__) || defined(__amd64__)
13784c7070dbSScott Long static __inline void
13794c7070dbSScott Long prefetch(void *x)
13804c7070dbSScott Long {
13814c7070dbSScott Long 	__asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
13824c7070dbSScott Long }
13833429c02fSStephen Hurd static __inline void
13843429c02fSStephen Hurd prefetch2cachelines(void *x)
13853429c02fSStephen Hurd {
13863429c02fSStephen Hurd 	__asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
13873429c02fSStephen Hurd #if (CACHE_LINE_SIZE < 128)
13883429c02fSStephen Hurd 	__asm volatile("prefetcht0 %0" :: "m" (*(((unsigned long *)x)+CACHE_LINE_SIZE/(sizeof(unsigned long)))));
13893429c02fSStephen Hurd #endif
13903429c02fSStephen Hurd }
13914c7070dbSScott Long #else
13924c7070dbSScott Long #define prefetch(x)
13933429c02fSStephen Hurd #define prefetch2cachelines(x)
13944c7070dbSScott Long #endif
13954c7070dbSScott Long 
13964c7070dbSScott Long static void
139710e0d938SStephen Hurd iru_init(if_rxd_update_t iru, iflib_rxq_t rxq, uint8_t flid)
139810e0d938SStephen Hurd {
139910e0d938SStephen Hurd 	iflib_fl_t fl;
140010e0d938SStephen Hurd 
140110e0d938SStephen Hurd 	fl = &rxq->ifr_fl[flid];
140210e0d938SStephen Hurd 	iru->iru_paddrs = fl->ifl_bus_addrs;
140310e0d938SStephen Hurd 	iru->iru_idxs = fl->ifl_rxd_idxs;
140410e0d938SStephen Hurd 	iru->iru_qsidx = rxq->ifr_id;
140510e0d938SStephen Hurd 	iru->iru_buf_size = fl->ifl_buf_size;
140610e0d938SStephen Hurd 	iru->iru_flidx = fl->ifl_id;
140710e0d938SStephen Hurd }
140810e0d938SStephen Hurd 
140910e0d938SStephen Hurd static void
14104c7070dbSScott Long _iflib_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
14114c7070dbSScott Long {
14124c7070dbSScott Long 	if (err)
14134c7070dbSScott Long 		return;
14144c7070dbSScott Long 	*(bus_addr_t *) arg = segs[0].ds_addr;
14154c7070dbSScott Long }
14164c7070dbSScott Long 
14176dd69f00SMarcin Wojtas #define	DMA_WIDTH_TO_BUS_LOWADDR(width)				\
1418ef567155SMarcin Wojtas 	(((width) == 0) || (width) == flsll(BUS_SPACE_MAXADDR) ?	\
14196dd69f00SMarcin Wojtas 	    BUS_SPACE_MAXADDR : (1ULL << (width)) - 1ULL)
14206dd69f00SMarcin Wojtas 
14214c7070dbSScott Long int
14228f82136aSPatrick Kelsey iflib_dma_alloc_align(if_ctx_t ctx, int size, int align, iflib_dma_info_t dma, int mapflags)
14234c7070dbSScott Long {
14244c7070dbSScott Long 	int err;
14254c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
14266dd69f00SMarcin Wojtas 	bus_addr_t lowaddr;
14276dd69f00SMarcin Wojtas 
14286dd69f00SMarcin Wojtas 	lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(ctx->ifc_softc_ctx.isc_dma_width);
14294c7070dbSScott Long 
14304c7070dbSScott Long 	err = bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
14318f82136aSPatrick Kelsey 				align, 0,		/* alignment, bounds */
14326dd69f00SMarcin Wojtas 				lowaddr,		/* lowaddr */
14334c7070dbSScott Long 				BUS_SPACE_MAXADDR,	/* highaddr */
14344c7070dbSScott Long 				NULL, NULL,		/* filter, filterarg */
14354c7070dbSScott Long 				size,			/* maxsize */
14364c7070dbSScott Long 				1,			/* nsegments */
14374c7070dbSScott Long 				size,			/* maxsegsize */
14384c7070dbSScott Long 				BUS_DMA_ALLOCNOW,	/* flags */
14394c7070dbSScott Long 				NULL,			/* lockfunc */
14404c7070dbSScott Long 				NULL,			/* lockarg */
14414c7070dbSScott Long 				&dma->idi_tag);
14424c7070dbSScott Long 	if (err) {
14434c7070dbSScott Long 		device_printf(dev,
14444c7070dbSScott Long 		    "%s: bus_dma_tag_create failed: %d\n",
14454c7070dbSScott Long 		    __func__, err);
14464c7070dbSScott Long 		goto fail_0;
14474c7070dbSScott Long 	}
14484c7070dbSScott Long 
14494c7070dbSScott Long 	err = bus_dmamem_alloc(dma->idi_tag, (void**) &dma->idi_vaddr,
14504c7070dbSScott Long 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_ZERO, &dma->idi_map);
14514c7070dbSScott Long 	if (err) {
14524c7070dbSScott Long 		device_printf(dev,
14534c7070dbSScott Long 		    "%s: bus_dmamem_alloc(%ju) failed: %d\n",
14544c7070dbSScott Long 		    __func__, (uintmax_t)size, err);
14554c7070dbSScott Long 		goto fail_1;
14564c7070dbSScott Long 	}
14574c7070dbSScott Long 
14584c7070dbSScott Long 	dma->idi_paddr = IF_BAD_DMA;
14594c7070dbSScott Long 	err = bus_dmamap_load(dma->idi_tag, dma->idi_map, dma->idi_vaddr,
14604c7070dbSScott Long 	    size, _iflib_dmamap_cb, &dma->idi_paddr, mapflags | BUS_DMA_NOWAIT);
14614c7070dbSScott Long 	if (err || dma->idi_paddr == IF_BAD_DMA) {
14624c7070dbSScott Long 		device_printf(dev,
14634c7070dbSScott Long 		    "%s: bus_dmamap_load failed: %d\n",
14644c7070dbSScott Long 		    __func__, err);
14654c7070dbSScott Long 		goto fail_2;
14664c7070dbSScott Long 	}
14674c7070dbSScott Long 
14684c7070dbSScott Long 	dma->idi_size = size;
14694c7070dbSScott Long 	return (0);
14704c7070dbSScott Long 
14714c7070dbSScott Long fail_2:
14724c7070dbSScott Long 	bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map);
14734c7070dbSScott Long fail_1:
14744c7070dbSScott Long 	bus_dma_tag_destroy(dma->idi_tag);
14754c7070dbSScott Long fail_0:
14764c7070dbSScott Long 	dma->idi_tag = NULL;
14774c7070dbSScott Long 
14784c7070dbSScott Long 	return (err);
14794c7070dbSScott Long }
14804c7070dbSScott Long 
14814c7070dbSScott Long int
14828f82136aSPatrick Kelsey iflib_dma_alloc(if_ctx_t ctx, int size, iflib_dma_info_t dma, int mapflags)
14838f82136aSPatrick Kelsey {
14848f82136aSPatrick Kelsey 	if_shared_ctx_t sctx = ctx->ifc_sctx;
14858f82136aSPatrick Kelsey 
14868f82136aSPatrick Kelsey 	KASSERT(sctx->isc_q_align != 0, ("alignment value not initialized"));
14878f82136aSPatrick Kelsey 
14888f82136aSPatrick Kelsey 	return (iflib_dma_alloc_align(ctx, size, sctx->isc_q_align, dma, mapflags));
14898f82136aSPatrick Kelsey }
14908f82136aSPatrick Kelsey 
14918f82136aSPatrick Kelsey int
14924c7070dbSScott Long iflib_dma_alloc_multi(if_ctx_t ctx, int *sizes, iflib_dma_info_t *dmalist, int mapflags, int count)
14934c7070dbSScott Long {
14944c7070dbSScott Long 	int i, err;
14954c7070dbSScott Long 	iflib_dma_info_t *dmaiter;
14964c7070dbSScott Long 
14974c7070dbSScott Long 	dmaiter = dmalist;
14984c7070dbSScott Long 	for (i = 0; i < count; i++, dmaiter++) {
14994c7070dbSScott Long 		if ((err = iflib_dma_alloc(ctx, sizes[i], *dmaiter, mapflags)) != 0)
15004c7070dbSScott Long 			break;
15014c7070dbSScott Long 	}
15024c7070dbSScott Long 	if (err)
15034c7070dbSScott Long 		iflib_dma_free_multi(dmalist, i);
15044c7070dbSScott Long 	return (err);
15054c7070dbSScott Long }
15064c7070dbSScott Long 
15074c7070dbSScott Long void
15084c7070dbSScott Long iflib_dma_free(iflib_dma_info_t dma)
15094c7070dbSScott Long {
15104c7070dbSScott Long 	if (dma->idi_tag == NULL)
15114c7070dbSScott Long 		return;
15124c7070dbSScott Long 	if (dma->idi_paddr != IF_BAD_DMA) {
15134c7070dbSScott Long 		bus_dmamap_sync(dma->idi_tag, dma->idi_map,
15144c7070dbSScott Long 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
15154c7070dbSScott Long 		bus_dmamap_unload(dma->idi_tag, dma->idi_map);
15164c7070dbSScott Long 		dma->idi_paddr = IF_BAD_DMA;
15174c7070dbSScott Long 	}
15184c7070dbSScott Long 	if (dma->idi_vaddr != NULL) {
15194c7070dbSScott Long 		bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map);
15204c7070dbSScott Long 		dma->idi_vaddr = NULL;
15214c7070dbSScott Long 	}
15224c7070dbSScott Long 	bus_dma_tag_destroy(dma->idi_tag);
15234c7070dbSScott Long 	dma->idi_tag = NULL;
15244c7070dbSScott Long }
15254c7070dbSScott Long 
15264c7070dbSScott Long void
15274c7070dbSScott Long iflib_dma_free_multi(iflib_dma_info_t *dmalist, int count)
15284c7070dbSScott Long {
15294c7070dbSScott Long 	int i;
15304c7070dbSScott Long 	iflib_dma_info_t *dmaiter = dmalist;
15314c7070dbSScott Long 
15324c7070dbSScott Long 	for (i = 0; i < count; i++, dmaiter++)
15334c7070dbSScott Long 		iflib_dma_free(*dmaiter);
15344c7070dbSScott Long }
15354c7070dbSScott Long 
15364c7070dbSScott Long static int
15374c7070dbSScott Long iflib_fast_intr(void *arg)
15384c7070dbSScott Long {
15394c7070dbSScott Long 	iflib_filter_info_t info = arg;
15404c7070dbSScott Long 	struct grouptask *gtask = info->ifi_task;
1541ca62461bSStephen Hurd 	int result;
1542ca62461bSStephen Hurd 
154395246abbSSean Bruno 	DBG_COUNTER_INC(fast_intrs);
1544ca62461bSStephen Hurd 	if (info->ifi_filter != NULL) {
1545ca62461bSStephen Hurd 		result = info->ifi_filter(info->ifi_filter_arg);
1546ca62461bSStephen Hurd 		if ((result & FILTER_SCHEDULE_THREAD) == 0)
1547ca62461bSStephen Hurd 			return (result);
1548ca62461bSStephen Hurd 	}
154995246abbSSean Bruno 
155095246abbSSean Bruno 	GROUPTASK_ENQUEUE(gtask);
155195246abbSSean Bruno 	return (FILTER_HANDLED);
155295246abbSSean Bruno }
155395246abbSSean Bruno 
155495246abbSSean Bruno static int
155595246abbSSean Bruno iflib_fast_intr_rxtx(void *arg)
155695246abbSSean Bruno {
155795246abbSSean Bruno 	iflib_filter_info_t info = arg;
155895246abbSSean Bruno 	struct grouptask *gtask = info->ifi_task;
155995dcf343SMarius Strobl 	if_ctx_t ctx;
156095246abbSSean Bruno 	iflib_rxq_t rxq = (iflib_rxq_t)info->ifi_ctx;
156195dcf343SMarius Strobl 	iflib_txq_t txq;
156295dcf343SMarius Strobl 	void *sc;
1563ca62461bSStephen Hurd 	int i, cidx, result;
156495dcf343SMarius Strobl 	qidx_t txqid;
15653d10e9edSMarius Strobl 	bool intr_enable, intr_legacy;
156695246abbSSean Bruno 
156795246abbSSean Bruno 	DBG_COUNTER_INC(fast_intrs);
1568ca62461bSStephen Hurd 	if (info->ifi_filter != NULL) {
1569ca62461bSStephen Hurd 		result = info->ifi_filter(info->ifi_filter_arg);
1570ca62461bSStephen Hurd 		if ((result & FILTER_SCHEDULE_THREAD) == 0)
1571ca62461bSStephen Hurd 			return (result);
1572ca62461bSStephen Hurd 	}
157395246abbSSean Bruno 
157495dcf343SMarius Strobl 	ctx = rxq->ifr_ctx;
157595dcf343SMarius Strobl 	sc = ctx->ifc_softc;
15763d10e9edSMarius Strobl 	intr_enable = false;
15773d10e9edSMarius Strobl 	intr_legacy = !!(ctx->ifc_flags & IFC_LEGACY);
15781ae4848cSMatt Macy 	MPASS(rxq->ifr_ntxqirq);
157995246abbSSean Bruno 	for (i = 0; i < rxq->ifr_ntxqirq; i++) {
158095dcf343SMarius Strobl 		txqid = rxq->ifr_txqid[i];
158195dcf343SMarius Strobl 		txq = &ctx->ifc_txqs[txqid];
158295dcf343SMarius Strobl 		bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
15838a04b53dSKonstantin Belousov 		    BUS_DMASYNC_POSTREAD);
158495dcf343SMarius Strobl 		if (!ctx->isc_txd_credits_update(sc, txqid, false)) {
15853d10e9edSMarius Strobl 			if (intr_legacy)
15863d10e9edSMarius Strobl 				intr_enable = true;
15873d10e9edSMarius Strobl 			else
158895246abbSSean Bruno 				IFDI_TX_QUEUE_INTR_ENABLE(ctx, txqid);
158995246abbSSean Bruno 			continue;
159095246abbSSean Bruno 		}
159195dcf343SMarius Strobl 		GROUPTASK_ENQUEUE(&txq->ift_task);
159295246abbSSean Bruno 	}
159395246abbSSean Bruno 	if (ctx->ifc_sctx->isc_flags & IFLIB_HAS_RXCQ)
159495246abbSSean Bruno 		cidx = rxq->ifr_cq_cidx;
159595246abbSSean Bruno 	else
159695246abbSSean Bruno 		cidx = rxq->ifr_fl[0].ifl_cidx;
159795246abbSSean Bruno 	if (iflib_rxd_avail(ctx, rxq, cidx, 1))
159895246abbSSean Bruno 		GROUPTASK_ENQUEUE(gtask);
159964e6fc13SStephen Hurd 	else {
16003d10e9edSMarius Strobl 		if (intr_legacy)
16013d10e9edSMarius Strobl 			intr_enable = true;
16023d10e9edSMarius Strobl 		else
160395246abbSSean Bruno 			IFDI_RX_QUEUE_INTR_ENABLE(ctx, rxq->ifr_id);
160464e6fc13SStephen Hurd 		DBG_COUNTER_INC(rx_intr_enables);
160564e6fc13SStephen Hurd 	}
16063d10e9edSMarius Strobl 	if (intr_enable)
16073d10e9edSMarius Strobl 		IFDI_INTR_ENABLE(ctx);
160895246abbSSean Bruno 	return (FILTER_HANDLED);
160995246abbSSean Bruno }
161095246abbSSean Bruno 
161195246abbSSean Bruno static int
161295246abbSSean Bruno iflib_fast_intr_ctx(void *arg)
161395246abbSSean Bruno {
161495246abbSSean Bruno 	iflib_filter_info_t info = arg;
161595246abbSSean Bruno 	struct grouptask *gtask = info->ifi_task;
1616ca62461bSStephen Hurd 	int result;
16174c7070dbSScott Long 
16184c7070dbSScott Long 	DBG_COUNTER_INC(fast_intrs);
1619ca62461bSStephen Hurd 	if (info->ifi_filter != NULL) {
1620ca62461bSStephen Hurd 		result = info->ifi_filter(info->ifi_filter_arg);
1621ca62461bSStephen Hurd 		if ((result & FILTER_SCHEDULE_THREAD) == 0)
1622ca62461bSStephen Hurd 			return (result);
1623ca62461bSStephen Hurd 	}
16244c7070dbSScott Long 
16254c7070dbSScott Long 	GROUPTASK_ENQUEUE(gtask);
16264c7070dbSScott Long 	return (FILTER_HANDLED);
16274c7070dbSScott Long }
16284c7070dbSScott Long 
16294c7070dbSScott Long static int
16304c7070dbSScott Long _iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid,
16314c7070dbSScott Long 		 driver_filter_t filter, driver_intr_t handler, void *arg,
16323e0e6330SStephen Hurd 		 const char *name)
16334c7070dbSScott Long {
16344c7070dbSScott Long 	struct resource *res;
16352b2fc973SSean Bruno 	void *tag = NULL;
16364c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
1637d49e83eaSMarius Strobl 	int flags, i, rc;
16384c7070dbSScott Long 
16392b2fc973SSean Bruno 	flags = RF_ACTIVE;
16402b2fc973SSean Bruno 	if (ctx->ifc_flags & IFC_LEGACY)
16412b2fc973SSean Bruno 		flags |= RF_SHAREABLE;
16424c7070dbSScott Long 	MPASS(rid < 512);
1643d49e83eaSMarius Strobl 	i = rid;
1644d49e83eaSMarius Strobl 	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, flags);
16454c7070dbSScott Long 	if (res == NULL) {
16464c7070dbSScott Long 		device_printf(dev,
16474c7070dbSScott Long 		    "failed to allocate IRQ for rid %d, name %s.\n", rid, name);
16484c7070dbSScott Long 		return (ENOMEM);
16494c7070dbSScott Long 	}
16504c7070dbSScott Long 	irq->ii_res = res;
16514c7070dbSScott Long 	KASSERT(filter == NULL || handler == NULL, ("filter and handler can't both be non-NULL"));
16524c7070dbSScott Long 	rc = bus_setup_intr(dev, res, INTR_MPSAFE | INTR_TYPE_NET,
16534c7070dbSScott Long 						filter, handler, arg, &tag);
16544c7070dbSScott Long 	if (rc != 0) {
16554c7070dbSScott Long 		device_printf(dev,
16564c7070dbSScott Long 		    "failed to setup interrupt for rid %d, name %s: %d\n",
16574c7070dbSScott Long 					  rid, name ? name : "unknown", rc);
16584c7070dbSScott Long 		return (rc);
16594c7070dbSScott Long 	} else if (name)
1660f454e7ebSJohn Baldwin 		bus_describe_intr(dev, res, tag, "%s", name);
16614c7070dbSScott Long 
16624c7070dbSScott Long 	irq->ii_tag = tag;
16634c7070dbSScott Long 	return (0);
16644c7070dbSScott Long }
16654c7070dbSScott Long 
16664c7070dbSScott Long /*********************************************************************
16674c7070dbSScott Long  *
1668bfce461eSMarius Strobl  *  Allocate DMA resources for TX buffers as well as memory for the TX
1669bfce461eSMarius Strobl  *  mbuf map.  TX DMA maps (non-TSO/TSO) and TX mbuf map are kept in a
1670bfce461eSMarius Strobl  *  iflib_sw_tx_desc_array structure, storing all the information that
1671bfce461eSMarius Strobl  *  is needed to transmit a packet on the wire.  This is called only
1672bfce461eSMarius Strobl  *  once at attach, setup is done every reset.
16734c7070dbSScott Long  *
16744c7070dbSScott Long  **********************************************************************/
16754c7070dbSScott Long static int
16764c7070dbSScott Long iflib_txsd_alloc(iflib_txq_t txq)
16774c7070dbSScott Long {
16784c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
16794c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
16804c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
16814c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
16827f87c040SMarius Strobl 	bus_size_t tsomaxsize;
16836dd69f00SMarcin Wojtas 	bus_addr_t lowaddr;
16844c7070dbSScott Long 	int err, nsegments, ntsosegments;
16858a04b53dSKonstantin Belousov 	bool tso;
16864c7070dbSScott Long 
16874c7070dbSScott Long 	nsegments = scctx->isc_tx_nsegments;
16884c7070dbSScott Long 	ntsosegments = scctx->isc_tx_tso_segments_max;
16897f87c040SMarius Strobl 	tsomaxsize = scctx->isc_tx_tso_size_max;
16907f87c040SMarius Strobl 	if (if_getcapabilities(ctx->ifc_ifp) & IFCAP_VLAN_MTU)
16917f87c040SMarius Strobl 		tsomaxsize += sizeof(struct ether_vlan_header);
169223ac9029SStephen Hurd 	MPASS(scctx->isc_ntxd[0] > 0);
169323ac9029SStephen Hurd 	MPASS(scctx->isc_ntxd[txq->ift_br_offset] > 0);
16944c7070dbSScott Long 	MPASS(nsegments > 0);
16957f87c040SMarius Strobl 	if (if_getcapabilities(ctx->ifc_ifp) & IFCAP_TSO) {
16964c7070dbSScott Long 		MPASS(ntsosegments > 0);
16977f87c040SMarius Strobl 		MPASS(sctx->isc_tso_maxsize >= tsomaxsize);
16987f87c040SMarius Strobl 	}
16997f87c040SMarius Strobl 
17006dd69f00SMarcin Wojtas 	lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(scctx->isc_dma_width);
17016dd69f00SMarcin Wojtas 
17024c7070dbSScott Long 	/*
1703bfce461eSMarius Strobl 	 * Set up DMA tags for TX buffers.
17044c7070dbSScott Long 	 */
17054c7070dbSScott Long 	if ((err = bus_dma_tag_create(bus_get_dma_tag(dev),
17064c7070dbSScott Long 			       1, 0,			/* alignment, bounds */
17076dd69f00SMarcin Wojtas 			       lowaddr,			/* lowaddr */
17084c7070dbSScott Long 			       BUS_SPACE_MAXADDR,	/* highaddr */
17094c7070dbSScott Long 			       NULL, NULL,		/* filter, filterarg */
17104c7070dbSScott Long 			       sctx->isc_tx_maxsize,		/* maxsize */
17114c7070dbSScott Long 			       nsegments,	/* nsegments */
17124c7070dbSScott Long 			       sctx->isc_tx_maxsegsize,	/* maxsegsize */
17134c7070dbSScott Long 			       0,			/* flags */
17144c7070dbSScott Long 			       NULL,			/* lockfunc */
17154c7070dbSScott Long 			       NULL,			/* lockfuncarg */
1716bfce461eSMarius Strobl 			       &txq->ift_buf_tag))) {
17174c7070dbSScott Long 		device_printf(dev,"Unable to allocate TX DMA tag: %d\n", err);
17189d0a88deSDimitry Andric 		device_printf(dev,"maxsize: %ju nsegments: %d maxsegsize: %ju\n",
17199d0a88deSDimitry Andric 		    (uintmax_t)sctx->isc_tx_maxsize, nsegments, (uintmax_t)sctx->isc_tx_maxsegsize);
17204c7070dbSScott Long 		goto fail;
17214c7070dbSScott Long 	}
17228a04b53dSKonstantin Belousov 	tso = (if_getcapabilities(ctx->ifc_ifp) & IFCAP_TSO) != 0;
17238a04b53dSKonstantin Belousov 	if (tso && (err = bus_dma_tag_create(bus_get_dma_tag(dev),
17244c7070dbSScott Long 			       1, 0,			/* alignment, bounds */
17256dd69f00SMarcin Wojtas 			       lowaddr,			/* lowaddr */
17264c7070dbSScott Long 			       BUS_SPACE_MAXADDR,	/* highaddr */
17274c7070dbSScott Long 			       NULL, NULL,		/* filter, filterarg */
17287f87c040SMarius Strobl 			       tsomaxsize,		/* maxsize */
17294c7070dbSScott Long 			       ntsosegments,	/* nsegments */
17307f87c040SMarius Strobl 			       sctx->isc_tso_maxsegsize,/* maxsegsize */
17314c7070dbSScott Long 			       0,			/* flags */
17324c7070dbSScott Long 			       NULL,			/* lockfunc */
17334c7070dbSScott Long 			       NULL,			/* lockfuncarg */
1734bfce461eSMarius Strobl 			       &txq->ift_tso_buf_tag))) {
1735bfce461eSMarius Strobl 		device_printf(dev, "Unable to allocate TSO TX DMA tag: %d\n",
1736bfce461eSMarius Strobl 		    err);
17374c7070dbSScott Long 		goto fail;
17384c7070dbSScott Long 	}
1739bfce461eSMarius Strobl 
1740bfce461eSMarius Strobl 	/* Allocate memory for the TX mbuf map. */
17414c7070dbSScott Long 	if (!(txq->ift_sds.ifsd_m =
1742ac2fffa4SPedro F. Giffuni 	    (struct mbuf **) malloc(sizeof(struct mbuf *) *
1743ac2fffa4SPedro F. Giffuni 	    scctx->isc_ntxd[txq->ift_br_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1744bfce461eSMarius Strobl 		device_printf(dev, "Unable to allocate TX mbuf map memory\n");
17454c7070dbSScott Long 		err = ENOMEM;
17464c7070dbSScott Long 		goto fail;
17474c7070dbSScott Long 	}
17484c7070dbSScott Long 
1749bfce461eSMarius Strobl 	/*
1750bfce461eSMarius Strobl 	 * Create the DMA maps for TX buffers.
1751bfce461eSMarius Strobl 	 */
17528a04b53dSKonstantin Belousov 	if ((txq->ift_sds.ifsd_map = (bus_dmamap_t *)malloc(
17538a04b53dSKonstantin Belousov 	    sizeof(bus_dmamap_t) * scctx->isc_ntxd[txq->ift_br_offset],
17548a04b53dSKonstantin Belousov 	    M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
1755bfce461eSMarius Strobl 		device_printf(dev,
1756bfce461eSMarius Strobl 		    "Unable to allocate TX buffer DMA map memory\n");
17574c7070dbSScott Long 		err = ENOMEM;
17584c7070dbSScott Long 		goto fail;
17594c7070dbSScott Long 	}
17608a04b53dSKonstantin Belousov 	if (tso && (txq->ift_sds.ifsd_tso_map = (bus_dmamap_t *)malloc(
17618a04b53dSKonstantin Belousov 	    sizeof(bus_dmamap_t) * scctx->isc_ntxd[txq->ift_br_offset],
17628a04b53dSKonstantin Belousov 	    M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
1763bfce461eSMarius Strobl 		device_printf(dev,
1764bfce461eSMarius Strobl 		    "Unable to allocate TSO TX buffer map memory\n");
17658a04b53dSKonstantin Belousov 		err = ENOMEM;
17668a04b53dSKonstantin Belousov 		goto fail;
17678a04b53dSKonstantin Belousov 	}
176823ac9029SStephen Hurd 	for (int i = 0; i < scctx->isc_ntxd[txq->ift_br_offset]; i++) {
1769bfce461eSMarius Strobl 		err = bus_dmamap_create(txq->ift_buf_tag, 0,
17708a04b53dSKonstantin Belousov 		    &txq->ift_sds.ifsd_map[i]);
17714c7070dbSScott Long 		if (err != 0) {
17724c7070dbSScott Long 			device_printf(dev, "Unable to create TX DMA map\n");
17734c7070dbSScott Long 			goto fail;
17744c7070dbSScott Long 		}
17758a04b53dSKonstantin Belousov 		if (!tso)
17768a04b53dSKonstantin Belousov 			continue;
1777bfce461eSMarius Strobl 		err = bus_dmamap_create(txq->ift_tso_buf_tag, 0,
17788a04b53dSKonstantin Belousov 		    &txq->ift_sds.ifsd_tso_map[i]);
17798a04b53dSKonstantin Belousov 		if (err != 0) {
17808a04b53dSKonstantin Belousov 			device_printf(dev, "Unable to create TSO TX DMA map\n");
17818a04b53dSKonstantin Belousov 			goto fail;
17828a04b53dSKonstantin Belousov 		}
17834c7070dbSScott Long 	}
17844c7070dbSScott Long 	return (0);
17854c7070dbSScott Long fail:
17864c7070dbSScott Long 	/* We free all, it handles case where we are in the middle */
17874c7070dbSScott Long 	iflib_tx_structures_free(ctx);
17884c7070dbSScott Long 	return (err);
17894c7070dbSScott Long }
17904c7070dbSScott Long 
17914c7070dbSScott Long static void
17924c7070dbSScott Long iflib_txsd_destroy(if_ctx_t ctx, iflib_txq_t txq, int i)
17934c7070dbSScott Long {
17944c7070dbSScott Long 	bus_dmamap_t map;
17954c7070dbSScott Long 
1796db8e8f1eSEric Joyner 	if (txq->ift_sds.ifsd_map != NULL) {
17974c7070dbSScott Long 		map = txq->ift_sds.ifsd_map[i];
1798bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_buf_tag, map, BUS_DMASYNC_POSTWRITE);
1799bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_buf_tag, map);
1800bfce461eSMarius Strobl 		bus_dmamap_destroy(txq->ift_buf_tag, map);
18014c7070dbSScott Long 		txq->ift_sds.ifsd_map[i] = NULL;
18024c7070dbSScott Long 	}
18038a04b53dSKonstantin Belousov 
1804db8e8f1eSEric Joyner 	if (txq->ift_sds.ifsd_tso_map != NULL) {
18058a04b53dSKonstantin Belousov 		map = txq->ift_sds.ifsd_tso_map[i];
1806bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_tso_buf_tag, map,
18078a04b53dSKonstantin Belousov 		    BUS_DMASYNC_POSTWRITE);
1808bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_tso_buf_tag, map);
1809bfce461eSMarius Strobl 		bus_dmamap_destroy(txq->ift_tso_buf_tag, map);
18108a04b53dSKonstantin Belousov 		txq->ift_sds.ifsd_tso_map[i] = NULL;
18118a04b53dSKonstantin Belousov 	}
18124c7070dbSScott Long }
18134c7070dbSScott Long 
18144c7070dbSScott Long static void
18154c7070dbSScott Long iflib_txq_destroy(iflib_txq_t txq)
18164c7070dbSScott Long {
18174c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
18184c7070dbSScott Long 
181923ac9029SStephen Hurd 	for (int i = 0; i < txq->ift_size; i++)
18204c7070dbSScott Long 		iflib_txsd_destroy(ctx, txq, i);
1821244e7cffSEric Joyner 
1822244e7cffSEric Joyner 	if (txq->ift_br != NULL) {
1823244e7cffSEric Joyner 		ifmp_ring_free(txq->ift_br);
1824244e7cffSEric Joyner 		txq->ift_br = NULL;
1825244e7cffSEric Joyner 	}
1826244e7cffSEric Joyner 
1827244e7cffSEric Joyner 	mtx_destroy(&txq->ift_mtx);
1828244e7cffSEric Joyner 
18294c7070dbSScott Long 	if (txq->ift_sds.ifsd_map != NULL) {
18304c7070dbSScott Long 		free(txq->ift_sds.ifsd_map, M_IFLIB);
18314c7070dbSScott Long 		txq->ift_sds.ifsd_map = NULL;
18324c7070dbSScott Long 	}
18338a04b53dSKonstantin Belousov 	if (txq->ift_sds.ifsd_tso_map != NULL) {
18348a04b53dSKonstantin Belousov 		free(txq->ift_sds.ifsd_tso_map, M_IFLIB);
18358a04b53dSKonstantin Belousov 		txq->ift_sds.ifsd_tso_map = NULL;
18368a04b53dSKonstantin Belousov 	}
18374c7070dbSScott Long 	if (txq->ift_sds.ifsd_m != NULL) {
18384c7070dbSScott Long 		free(txq->ift_sds.ifsd_m, M_IFLIB);
18394c7070dbSScott Long 		txq->ift_sds.ifsd_m = NULL;
18404c7070dbSScott Long 	}
1841bfce461eSMarius Strobl 	if (txq->ift_buf_tag != NULL) {
1842bfce461eSMarius Strobl 		bus_dma_tag_destroy(txq->ift_buf_tag);
1843bfce461eSMarius Strobl 		txq->ift_buf_tag = NULL;
18444c7070dbSScott Long 	}
1845bfce461eSMarius Strobl 	if (txq->ift_tso_buf_tag != NULL) {
1846bfce461eSMarius Strobl 		bus_dma_tag_destroy(txq->ift_tso_buf_tag);
1847bfce461eSMarius Strobl 		txq->ift_tso_buf_tag = NULL;
18484c7070dbSScott Long 	}
1849244e7cffSEric Joyner 	if (txq->ift_ifdi != NULL) {
1850244e7cffSEric Joyner 		free(txq->ift_ifdi, M_IFLIB);
1851244e7cffSEric Joyner 	}
18524c7070dbSScott Long }
18534c7070dbSScott Long 
18544c7070dbSScott Long static void
18554c7070dbSScott Long iflib_txsd_free(if_ctx_t ctx, iflib_txq_t txq, int i)
18564c7070dbSScott Long {
18574c7070dbSScott Long 	struct mbuf **mp;
18584c7070dbSScott Long 
18594c7070dbSScott Long 	mp = &txq->ift_sds.ifsd_m[i];
18604c7070dbSScott Long 	if (*mp == NULL)
18614c7070dbSScott Long 		return;
18624c7070dbSScott Long 
18634c7070dbSScott Long 	if (txq->ift_sds.ifsd_map != NULL) {
1864bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_buf_tag,
18658a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_map[i], BUS_DMASYNC_POSTWRITE);
1866bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_buf_tag, txq->ift_sds.ifsd_map[i]);
18678a04b53dSKonstantin Belousov 	}
18688a04b53dSKonstantin Belousov 	if (txq->ift_sds.ifsd_tso_map != NULL) {
1869bfce461eSMarius Strobl 		bus_dmamap_sync(txq->ift_tso_buf_tag,
18708a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_tso_map[i], BUS_DMASYNC_POSTWRITE);
1871bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_tso_buf_tag,
18728a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_tso_map[i]);
18734c7070dbSScott Long 	}
187454bf96fbSMark Johnston 	m_freem(*mp);
18754c7070dbSScott Long 	DBG_COUNTER_INC(tx_frees);
18764c7070dbSScott Long 	*mp = NULL;
18774c7070dbSScott Long }
18784c7070dbSScott Long 
18794c7070dbSScott Long static int
18804c7070dbSScott Long iflib_txq_setup(iflib_txq_t txq)
18814c7070dbSScott Long {
18824c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
188323ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
18844d261ce2SStephen Hurd 	if_shared_ctx_t sctx = ctx->ifc_sctx;
18854c7070dbSScott Long 	iflib_dma_info_t di;
18864c7070dbSScott Long 	int i;
18874c7070dbSScott Long 
18884c7070dbSScott Long 	/* Set number of descriptors available */
18894c7070dbSScott Long 	txq->ift_qstatus = IFLIB_QUEUE_IDLE;
189095246abbSSean Bruno 	/* XXX make configurable */
189195246abbSSean Bruno 	txq->ift_update_freq = IFLIB_DEFAULT_TX_UPDATE_FREQ;
18924c7070dbSScott Long 
18934c7070dbSScott Long 	/* Reset indices */
189495246abbSSean Bruno 	txq->ift_cidx_processed = 0;
189595246abbSSean Bruno 	txq->ift_pidx = txq->ift_cidx = txq->ift_npending = 0;
189623ac9029SStephen Hurd 	txq->ift_size = scctx->isc_ntxd[txq->ift_br_offset];
18974c7070dbSScott Long 
18984d261ce2SStephen Hurd 	for (i = 0, di = txq->ift_ifdi; i < sctx->isc_ntxqs; i++, di++)
18994c7070dbSScott Long 		bzero((void *)di->idi_vaddr, di->idi_size);
19004c7070dbSScott Long 
19014c7070dbSScott Long 	IFDI_TXQ_SETUP(ctx, txq->ift_id);
19024d261ce2SStephen Hurd 	for (i = 0, di = txq->ift_ifdi; i < sctx->isc_ntxqs; i++, di++)
19034c7070dbSScott Long 		bus_dmamap_sync(di->idi_tag, di->idi_map,
19044c7070dbSScott Long 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
19054c7070dbSScott Long 	return (0);
19064c7070dbSScott Long }
19074c7070dbSScott Long 
19084c7070dbSScott Long /*********************************************************************
19094c7070dbSScott Long  *
1910bfce461eSMarius Strobl  *  Allocate DMA resources for RX buffers as well as memory for the RX
1911bfce461eSMarius Strobl  *  mbuf map, direct RX cluster pointer map and RX cluster bus address
1912bfce461eSMarius Strobl  *  map.  RX DMA map, RX mbuf map, direct RX cluster pointer map and
1913bfce461eSMarius Strobl  *  RX cluster map are kept in a iflib_sw_rx_desc_array structure.
1914bfce461eSMarius Strobl  *  Since we use use one entry in iflib_sw_rx_desc_array per received
1915bfce461eSMarius Strobl  *  packet, the maximum number of entries we'll need is equal to the
1916bfce461eSMarius Strobl  *  number of hardware receive descriptors that we've allocated.
19174c7070dbSScott Long  *
19184c7070dbSScott Long  **********************************************************************/
19194c7070dbSScott Long static int
19204c7070dbSScott Long iflib_rxsd_alloc(iflib_rxq_t rxq)
19214c7070dbSScott Long {
19224c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
19234c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
192423ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
19254c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
19264c7070dbSScott Long 	iflib_fl_t fl;
19276dd69f00SMarcin Wojtas 	bus_addr_t lowaddr;
19284c7070dbSScott Long 	int			err;
19294c7070dbSScott Long 
193023ac9029SStephen Hurd 	MPASS(scctx->isc_nrxd[0] > 0);
193123ac9029SStephen Hurd 	MPASS(scctx->isc_nrxd[rxq->ifr_fl_offset] > 0);
19324c7070dbSScott Long 
19336dd69f00SMarcin Wojtas 	lowaddr = DMA_WIDTH_TO_BUS_LOWADDR(scctx->isc_dma_width);
19346dd69f00SMarcin Wojtas 
19354c7070dbSScott Long 	fl = rxq->ifr_fl;
19364c7070dbSScott Long 	for (int i = 0; i <  rxq->ifr_nfl; i++, fl++) {
193723ac9029SStephen Hurd 		fl->ifl_size = scctx->isc_nrxd[rxq->ifr_fl_offset]; /* this isn't necessarily the same */
1938bfce461eSMarius Strobl 		/* Set up DMA tag for RX buffers. */
19394c7070dbSScott Long 		err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
19404c7070dbSScott Long 					 1, 0,			/* alignment, bounds */
19416dd69f00SMarcin Wojtas 					 lowaddr,		/* lowaddr */
19424c7070dbSScott Long 					 BUS_SPACE_MAXADDR,	/* highaddr */
19434c7070dbSScott Long 					 NULL, NULL,		/* filter, filterarg */
19444c7070dbSScott Long 					 sctx->isc_rx_maxsize,	/* maxsize */
19454c7070dbSScott Long 					 sctx->isc_rx_nsegments,	/* nsegments */
19464c7070dbSScott Long 					 sctx->isc_rx_maxsegsize,	/* maxsegsize */
19474c7070dbSScott Long 					 0,			/* flags */
19484c7070dbSScott Long 					 NULL,			/* lockfunc */
19494c7070dbSScott Long 					 NULL,			/* lockarg */
1950bfce461eSMarius Strobl 					 &fl->ifl_buf_tag);
19514c7070dbSScott Long 		if (err) {
1952bfce461eSMarius Strobl 			device_printf(dev,
1953bfce461eSMarius Strobl 			    "Unable to allocate RX DMA tag: %d\n", err);
19544c7070dbSScott Long 			goto fail;
19554c7070dbSScott Long 		}
1956bfce461eSMarius Strobl 
1957bfce461eSMarius Strobl 		/* Allocate memory for the RX mbuf map. */
1958e035717eSSean Bruno 		if (!(fl->ifl_sds.ifsd_m =
1959ac2fffa4SPedro F. Giffuni 		      (struct mbuf **) malloc(sizeof(struct mbuf *) *
1960ac2fffa4SPedro F. Giffuni 					      scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1961bfce461eSMarius Strobl 			device_printf(dev,
1962bfce461eSMarius Strobl 			    "Unable to allocate RX mbuf map memory\n");
1963e035717eSSean Bruno 			err = ENOMEM;
1964e035717eSSean Bruno 			goto fail;
1965e035717eSSean Bruno 		}
1966bfce461eSMarius Strobl 
1967bfce461eSMarius Strobl 		/* Allocate memory for the direct RX cluster pointer map. */
1968e035717eSSean Bruno 		if (!(fl->ifl_sds.ifsd_cl =
1969ac2fffa4SPedro F. Giffuni 		      (caddr_t *) malloc(sizeof(caddr_t) *
1970ac2fffa4SPedro F. Giffuni 					      scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1971bfce461eSMarius Strobl 			device_printf(dev,
1972bfce461eSMarius Strobl 			    "Unable to allocate RX cluster map memory\n");
1973e035717eSSean Bruno 			err = ENOMEM;
1974e035717eSSean Bruno 			goto fail;
1975e035717eSSean Bruno 		}
19764c7070dbSScott Long 
1977bfce461eSMarius Strobl 		/* Allocate memory for the RX cluster bus address map. */
1978fbec776dSAndrew Gallatin 		if (!(fl->ifl_sds.ifsd_ba =
1979fbec776dSAndrew Gallatin 		      (bus_addr_t *) malloc(sizeof(bus_addr_t) *
1980fbec776dSAndrew Gallatin 					      scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1981bfce461eSMarius Strobl 			device_printf(dev,
1982bfce461eSMarius Strobl 			    "Unable to allocate RX bus address map memory\n");
1983fbec776dSAndrew Gallatin 			err = ENOMEM;
1984fbec776dSAndrew Gallatin 			goto fail;
1985fbec776dSAndrew Gallatin 		}
1986e035717eSSean Bruno 
1987bfce461eSMarius Strobl 		/*
1988bfce461eSMarius Strobl 		 * Create the DMA maps for RX buffers.
1989bfce461eSMarius Strobl 		 */
1990e035717eSSean Bruno 		if (!(fl->ifl_sds.ifsd_map =
1991ac2fffa4SPedro F. Giffuni 		      (bus_dmamap_t *) malloc(sizeof(bus_dmamap_t) * scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) {
1992bfce461eSMarius Strobl 			device_printf(dev,
1993bfce461eSMarius Strobl 			    "Unable to allocate RX buffer DMA map memory\n");
1994e035717eSSean Bruno 			err = ENOMEM;
1995e035717eSSean Bruno 			goto fail;
1996e035717eSSean Bruno 		}
1997e035717eSSean Bruno 		for (int i = 0; i < scctx->isc_nrxd[rxq->ifr_fl_offset]; i++) {
1998bfce461eSMarius Strobl 			err = bus_dmamap_create(fl->ifl_buf_tag, 0,
1999bfce461eSMarius Strobl 			    &fl->ifl_sds.ifsd_map[i]);
2000e035717eSSean Bruno 			if (err != 0) {
200195246abbSSean Bruno 				device_printf(dev, "Unable to create RX buffer DMA map\n");
20024c7070dbSScott Long 				goto fail;
20034c7070dbSScott Long 			}
20044c7070dbSScott Long 		}
2005835809f9SSean Bruno 	}
20064c7070dbSScott Long 	return (0);
20074c7070dbSScott Long 
20084c7070dbSScott Long fail:
20094c7070dbSScott Long 	iflib_rx_structures_free(ctx);
20104c7070dbSScott Long 	return (err);
20114c7070dbSScott Long }
20124c7070dbSScott Long 
20134c7070dbSScott Long /*
20144c7070dbSScott Long  * Internal service routines
20154c7070dbSScott Long  */
20164c7070dbSScott Long 
20174c7070dbSScott Long struct rxq_refill_cb_arg {
20184c7070dbSScott Long 	int               error;
20194c7070dbSScott Long 	bus_dma_segment_t seg;
20204c7070dbSScott Long 	int               nseg;
20214c7070dbSScott Long };
20224c7070dbSScott Long 
20234c7070dbSScott Long static void
20244c7070dbSScott Long _rxq_refill_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
20254c7070dbSScott Long {
20264c7070dbSScott Long 	struct rxq_refill_cb_arg *cb_arg = arg;
20274c7070dbSScott Long 
20284c7070dbSScott Long 	cb_arg->error = error;
20294c7070dbSScott Long 	cb_arg->seg = segs[0];
20304c7070dbSScott Long 	cb_arg->nseg = nseg;
20314c7070dbSScott Long }
20324c7070dbSScott Long 
20334c7070dbSScott Long /**
2034b256d25cSMark Johnston  * iflib_fl_refill - refill an rxq free-buffer list
20354c7070dbSScott Long  * @ctx: the iflib context
20361722eeacSMarius Strobl  * @fl: the free list to refill
20371722eeacSMarius Strobl  * @count: the number of new buffers to allocate
20384c7070dbSScott Long  *
20391722eeacSMarius Strobl  * (Re)populate an rxq free-buffer list with up to @count new packet buffers.
204035d8a463SVincenzo Maffione  * The caller must assure that @count does not exceed the queue's capacity
204135d8a463SVincenzo Maffione  * minus one (since we always leave a descriptor unavailable).
20424c7070dbSScott Long  */
2043fb1a29b4SHans Petter Selasky static uint8_t
2044b256d25cSMark Johnston iflib_fl_refill(if_ctx_t ctx, iflib_fl_t fl, int count)
20454c7070dbSScott Long {
204695246abbSSean Bruno 	struct if_rxd_update iru;
2047fbec776dSAndrew Gallatin 	struct rxq_refill_cb_arg cb_arg;
20483db348b5SMarius Strobl 	struct mbuf *m;
20493db348b5SMarius Strobl 	caddr_t cl, *sd_cl;
20503db348b5SMarius Strobl 	struct mbuf **sd_m;
2051e035717eSSean Bruno 	bus_dmamap_t *sd_map;
2052fbec776dSAndrew Gallatin 	bus_addr_t bus_addr, *sd_ba;
20533db348b5SMarius Strobl 	int err, frag_idx, i, idx, n, pidx;
2054a1b799caSStephen Hurd 	qidx_t credits;
20554c7070dbSScott Long 
205635d8a463SVincenzo Maffione 	MPASS(count <= fl->ifl_size - fl->ifl_credits - 1);
205735d8a463SVincenzo Maffione 
2058e035717eSSean Bruno 	sd_m = fl->ifl_sds.ifsd_m;
2059e035717eSSean Bruno 	sd_map = fl->ifl_sds.ifsd_map;
2060e035717eSSean Bruno 	sd_cl = fl->ifl_sds.ifsd_cl;
2061fbec776dSAndrew Gallatin 	sd_ba = fl->ifl_sds.ifsd_ba;
20623db348b5SMarius Strobl 	pidx = fl->ifl_pidx;
2063e035717eSSean Bruno 	idx = pidx;
20643db348b5SMarius Strobl 	frag_idx = fl->ifl_fragidx;
2065a1b799caSStephen Hurd 	credits = fl->ifl_credits;
2066e035717eSSean Bruno 
20673db348b5SMarius Strobl 	i = 0;
20684c7070dbSScott Long 	n = count;
20694c7070dbSScott Long 	MPASS(n > 0);
2070a1b799caSStephen Hurd 	MPASS(credits + n <= fl->ifl_size);
20714c7070dbSScott Long 
20724c7070dbSScott Long 	if (pidx < fl->ifl_cidx)
20734c7070dbSScott Long 		MPASS(pidx + n <= fl->ifl_cidx);
2074a1b799caSStephen Hurd 	if (pidx == fl->ifl_cidx && (credits < fl->ifl_size))
20754c7070dbSScott Long 		MPASS(fl->ifl_gen == 0);
20764c7070dbSScott Long 	if (pidx > fl->ifl_cidx)
20774c7070dbSScott Long 		MPASS(n <= fl->ifl_size - pidx + fl->ifl_cidx);
20784c7070dbSScott Long 
20794c7070dbSScott Long 	DBG_COUNTER_INC(fl_refills);
20804c7070dbSScott Long 	if (n > 8)
20814c7070dbSScott Long 		DBG_COUNTER_INC(fl_refills_large);
20822d873474SStephen Hurd 	iru_init(&iru, fl->ifl_rxq, fl->ifl_id);
2083b256d25cSMark Johnston 	while (n-- > 0) {
20844c7070dbSScott Long 		/*
20854c7070dbSScott Long 		 * We allocate an uninitialized mbuf + cluster, mbuf is
20864c7070dbSScott Long 		 * initialized after rx.
20874c7070dbSScott Long 		 *
2088b256d25cSMark Johnston 		 * If the cluster is still set then we know a minimum sized
2089b256d25cSMark Johnston 		 * packet was received
20904c7070dbSScott Long 		 */
20913db348b5SMarius Strobl 		bit_ffc_at(fl->ifl_rx_bitmap, frag_idx, fl->ifl_size,
20923db348b5SMarius Strobl 		    &frag_idx);
20933db348b5SMarius Strobl 		if (frag_idx < 0)
209487890dbaSSean Bruno 			bit_ffc(fl->ifl_rx_bitmap, fl->ifl_size, &frag_idx);
20953db348b5SMarius Strobl 		MPASS(frag_idx >= 0);
209687890dbaSSean Bruno 		if ((cl = sd_cl[frag_idx]) == NULL) {
2097b256d25cSMark Johnston 			cl = uma_zalloc(fl->ifl_zone, M_NOWAIT);
2098a363e1d4SMark Johnston 			if (__predict_false(cl == NULL))
20994c7070dbSScott Long 				break;
21004c7070dbSScott Long 
21014c7070dbSScott Long 			cb_arg.error = 0;
210295246abbSSean Bruno 			MPASS(sd_map != NULL);
2103bfce461eSMarius Strobl 			err = bus_dmamap_load(fl->ifl_buf_tag, sd_map[frag_idx],
21048a04b53dSKonstantin Belousov 			    cl, fl->ifl_buf_size, _rxq_refill_cb, &cb_arg,
21058a04b53dSKonstantin Belousov 			    BUS_DMA_NOWAIT);
2106a363e1d4SMark Johnston 			if (__predict_false(err != 0 || cb_arg.error)) {
21074c7070dbSScott Long 				uma_zfree(fl->ifl_zone, cl);
2108fbec776dSAndrew Gallatin 				break;
21094c7070dbSScott Long 			}
21104c7070dbSScott Long 
2111fbec776dSAndrew Gallatin 			sd_ba[frag_idx] = bus_addr = cb_arg.seg.ds_addr;
211287890dbaSSean Bruno 			sd_cl[frag_idx] = cl;
2113fbec776dSAndrew Gallatin #if MEMORY_LOGGING
2114fbec776dSAndrew Gallatin 			fl->ifl_cl_enqueued++;
2115fbec776dSAndrew Gallatin #endif
2116fbec776dSAndrew Gallatin 		} else {
2117fbec776dSAndrew Gallatin 			bus_addr = sd_ba[frag_idx];
2118fbec776dSAndrew Gallatin 		}
211995dcf343SMarius Strobl 		bus_dmamap_sync(fl->ifl_buf_tag, sd_map[frag_idx],
212095dcf343SMarius Strobl 		    BUS_DMASYNC_PREREAD);
2121fbec776dSAndrew Gallatin 
21226d49b41eSAndrew Gallatin 		if (sd_m[frag_idx] == NULL) {
2123a363e1d4SMark Johnston 			m = m_gethdr(M_NOWAIT, MT_NOINIT);
2124a363e1d4SMark Johnston 			if (__predict_false(m == NULL))
2125fbec776dSAndrew Gallatin 				break;
212687890dbaSSean Bruno 			sd_m[frag_idx] = m;
21276d49b41eSAndrew Gallatin 		}
21283db348b5SMarius Strobl 		bit_set(fl->ifl_rx_bitmap, frag_idx);
2129fbec776dSAndrew Gallatin #if MEMORY_LOGGING
2130fbec776dSAndrew Gallatin 		fl->ifl_m_enqueued++;
2131fbec776dSAndrew Gallatin #endif
2132fbec776dSAndrew Gallatin 
2133fbec776dSAndrew Gallatin 		DBG_COUNTER_INC(rx_allocs);
213487890dbaSSean Bruno 		fl->ifl_rxd_idxs[i] = frag_idx;
21354c7070dbSScott Long 		fl->ifl_bus_addrs[i] = bus_addr;
2136a1b799caSStephen Hurd 		credits++;
21374c7070dbSScott Long 		i++;
2138a1b799caSStephen Hurd 		MPASS(credits <= fl->ifl_size);
2139e035717eSSean Bruno 		if (++idx == fl->ifl_size) {
2140b256d25cSMark Johnston #ifdef INVARIANTS
21414c7070dbSScott Long 			fl->ifl_gen = 1;
2142b256d25cSMark Johnston #endif
2143e035717eSSean Bruno 			idx = 0;
21444c7070dbSScott Long 		}
21454c7070dbSScott Long 		if (n == 0 || i == IFLIB_MAX_RX_REFRESH) {
214695246abbSSean Bruno 			iru.iru_pidx = pidx;
214795246abbSSean Bruno 			iru.iru_count = i;
214895246abbSSean Bruno 			ctx->isc_rxd_refill(ctx->ifc_softc, &iru);
2149fa5416a8SSean Bruno 			fl->ifl_pidx = idx;
2150a1b799caSStephen Hurd 			fl->ifl_credits = credits;
2151b256d25cSMark Johnston 			pidx = idx;
2152b256d25cSMark Johnston 			i = 0;
215387890dbaSSean Bruno 		}
21544c7070dbSScott Long 	}
2155fbec776dSAndrew Gallatin 
2156a363e1d4SMark Johnston 	if (n < count - 1) {
2157a363e1d4SMark Johnston 		if (i != 0) {
2158a1b799caSStephen Hurd 			iru.iru_pidx = pidx;
2159a1b799caSStephen Hurd 			iru.iru_count = i;
2160a1b799caSStephen Hurd 			ctx->isc_rxd_refill(ctx->ifc_softc, &iru);
2161a1b799caSStephen Hurd 			fl->ifl_pidx = idx;
2162a1b799caSStephen Hurd 			fl->ifl_credits = credits;
2163a1b799caSStephen Hurd 		}
21644c7070dbSScott Long 		DBG_COUNTER_INC(rxd_flush);
216595246abbSSean Bruno 		bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
216695246abbSSean Bruno 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2167a363e1d4SMark Johnston 		ctx->isc_rxd_flush(ctx->ifc_softc, fl->ifl_rxq->ifr_id,
216835d8a463SVincenzo Maffione 		    fl->ifl_id, fl->ifl_pidx);
2169a363e1d4SMark Johnston 		if (__predict_true(bit_test(fl->ifl_rx_bitmap, frag_idx))) {
21709e9b738aSPatrick Kelsey 			fl->ifl_fragidx = frag_idx + 1;
21719e9b738aSPatrick Kelsey 			if (fl->ifl_fragidx == fl->ifl_size)
21729e9b738aSPatrick Kelsey 				fl->ifl_fragidx = 0;
2173a363e1d4SMark Johnston 		} else {
2174a363e1d4SMark Johnston 			fl->ifl_fragidx = frag_idx;
2175a363e1d4SMark Johnston 		}
2176a363e1d4SMark Johnston 	}
2177fb1a29b4SHans Petter Selasky 
2178fb1a29b4SHans Petter Selasky 	return (n == -1 ? 0 : IFLIB_RXEOF_EMPTY);
21794c7070dbSScott Long }
21804c7070dbSScott Long 
2181b256d25cSMark Johnston static inline uint8_t
2182b256d25cSMark Johnston iflib_fl_refill_all(if_ctx_t ctx, iflib_fl_t fl)
21834c7070dbSScott Long {
218435d8a463SVincenzo Maffione 	/*
218535d8a463SVincenzo Maffione 	 * We leave an unused descriptor to avoid pidx to catch up with cidx.
218635d8a463SVincenzo Maffione 	 * This is important as it confuses most NICs. For instance,
218735d8a463SVincenzo Maffione 	 * Intel NICs have (per receive ring) RDH and RDT registers, where
218835d8a463SVincenzo Maffione 	 * RDH points to the next receive descriptor to be used by the NIC,
218935d8a463SVincenzo Maffione 	 * and RDT for the next receive descriptor to be published by the
219035d8a463SVincenzo Maffione 	 * driver to the NIC (RDT - 1 is thus the last valid one).
219135d8a463SVincenzo Maffione 	 * The condition RDH == RDT means no descriptors are available to
219235d8a463SVincenzo Maffione 	 * the NIC, and thus it would be ambiguous if it also meant that
219335d8a463SVincenzo Maffione 	 * all the descriptors are available to the NIC.
219435d8a463SVincenzo Maffione 	 */
21954c7070dbSScott Long 	int32_t reclaimable = fl->ifl_size - fl->ifl_credits - 1;
21964c7070dbSScott Long #ifdef INVARIANTS
21974c7070dbSScott Long 	int32_t delta = fl->ifl_size - get_inuse(fl->ifl_size, fl->ifl_cidx, fl->ifl_pidx, fl->ifl_gen) - 1;
21984c7070dbSScott Long #endif
21994c7070dbSScott Long 
22004c7070dbSScott Long 	MPASS(fl->ifl_credits <= fl->ifl_size);
22014c7070dbSScott Long 	MPASS(reclaimable == delta);
22024c7070dbSScott Long 
22034c7070dbSScott Long 	if (reclaimable > 0)
2204b256d25cSMark Johnston 		return (iflib_fl_refill(ctx, fl, reclaimable));
2205fb1a29b4SHans Petter Selasky 	return (0);
22064c7070dbSScott Long }
22074c7070dbSScott Long 
220877c1fcecSEric Joyner uint8_t
220977c1fcecSEric Joyner iflib_in_detach(if_ctx_t ctx)
221077c1fcecSEric Joyner {
221177c1fcecSEric Joyner 	bool in_detach;
22121722eeacSMarius Strobl 
221377c1fcecSEric Joyner 	STATE_LOCK(ctx);
221477c1fcecSEric Joyner 	in_detach = !!(ctx->ifc_flags & IFC_IN_DETACH);
221577c1fcecSEric Joyner 	STATE_UNLOCK(ctx);
221677c1fcecSEric Joyner 	return (in_detach);
221777c1fcecSEric Joyner }
221877c1fcecSEric Joyner 
22194c7070dbSScott Long static void
22204c7070dbSScott Long iflib_fl_bufs_free(iflib_fl_t fl)
22214c7070dbSScott Long {
22224c7070dbSScott Long 	iflib_dma_info_t idi = fl->ifl_ifdi;
22238a04b53dSKonstantin Belousov 	bus_dmamap_t sd_map;
22244c7070dbSScott Long 	uint32_t i;
22254c7070dbSScott Long 
22264c7070dbSScott Long 	for (i = 0; i < fl->ifl_size; i++) {
2227e035717eSSean Bruno 		struct mbuf **sd_m = &fl->ifl_sds.ifsd_m[i];
2228e035717eSSean Bruno 		caddr_t *sd_cl = &fl->ifl_sds.ifsd_cl[i];
22294c7070dbSScott Long 
2230fbec776dSAndrew Gallatin 		if (*sd_cl != NULL) {
22318a04b53dSKonstantin Belousov 			sd_map = fl->ifl_sds.ifsd_map[i];
2232bfce461eSMarius Strobl 			bus_dmamap_sync(fl->ifl_buf_tag, sd_map,
22338a04b53dSKonstantin Belousov 			    BUS_DMASYNC_POSTREAD);
2234bfce461eSMarius Strobl 			bus_dmamap_unload(fl->ifl_buf_tag, sd_map);
2235fbec776dSAndrew Gallatin 			uma_zfree(fl->ifl_zone, *sd_cl);
2236b256d25cSMark Johnston 			*sd_cl = NULL;
2237e035717eSSean Bruno 			if (*sd_m != NULL) {
2238e035717eSSean Bruno 				m_init(*sd_m, M_NOWAIT, MT_DATA, 0);
2239e035717eSSean Bruno 				uma_zfree(zone_mbuf, *sd_m);
2240b256d25cSMark Johnston 				*sd_m = NULL;
2241e035717eSSean Bruno 			}
22424c7070dbSScott Long 		} else {
2243e035717eSSean Bruno 			MPASS(*sd_m == NULL);
22444c7070dbSScott Long 		}
22454c7070dbSScott Long #if MEMORY_LOGGING
22464c7070dbSScott Long 		fl->ifl_m_dequeued++;
22474c7070dbSScott Long 		fl->ifl_cl_dequeued++;
22484c7070dbSScott Long #endif
22494c7070dbSScott Long 	}
225095246abbSSean Bruno #ifdef INVARIANTS
225195246abbSSean Bruno 	for (i = 0; i < fl->ifl_size; i++) {
225295246abbSSean Bruno 		MPASS(fl->ifl_sds.ifsd_cl[i] == NULL);
225395246abbSSean Bruno 		MPASS(fl->ifl_sds.ifsd_m[i] == NULL);
225495246abbSSean Bruno 	}
225595246abbSSean Bruno #endif
22564c7070dbSScott Long 	/*
22574c7070dbSScott Long 	 * Reset free list values
22584c7070dbSScott Long 	 */
225987890dbaSSean Bruno 	fl->ifl_credits = fl->ifl_cidx = fl->ifl_pidx = fl->ifl_gen = fl->ifl_fragidx = 0;
22604c7070dbSScott Long 	bzero(idi->idi_vaddr, idi->idi_size);
22614c7070dbSScott Long }
22624c7070dbSScott Long 
22634c7070dbSScott Long /*********************************************************************
22644c7070dbSScott Long  *
22651722eeacSMarius Strobl  *  Initialize a free list and its buffers.
22664c7070dbSScott Long  *
22674c7070dbSScott Long  **********************************************************************/
22684c7070dbSScott Long static int
22694c7070dbSScott Long iflib_fl_setup(iflib_fl_t fl)
22704c7070dbSScott Long {
22714c7070dbSScott Long 	iflib_rxq_t rxq = fl->ifl_rxq;
22724c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
2273b3813609SPatrick Kelsey 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
2274b3813609SPatrick Kelsey 	int qidx;
22754c7070dbSScott Long 
22767274b2f6SStephen Hurd 	bit_nclear(fl->ifl_rx_bitmap, 0, fl->ifl_size - 1);
22774c7070dbSScott Long 	/*
22784c7070dbSScott Long 	** Free current RX buffer structs and their mbufs
22794c7070dbSScott Long 	*/
22804c7070dbSScott Long 	iflib_fl_bufs_free(fl);
22814c7070dbSScott Long 	/* Now replenish the mbufs */
22824c7070dbSScott Long 	MPASS(fl->ifl_credits == 0);
2283b3813609SPatrick Kelsey 	qidx = rxq->ifr_fl_offset + fl->ifl_id;
2284b3813609SPatrick Kelsey 	if (scctx->isc_rxd_buf_size[qidx] != 0)
2285b3813609SPatrick Kelsey 		fl->ifl_buf_size = scctx->isc_rxd_buf_size[qidx];
2286b3813609SPatrick Kelsey 	else
22871b9d9394SEric Joyner 		fl->ifl_buf_size = ctx->ifc_rx_mbuf_sz;
2288b3813609SPatrick Kelsey 	/*
2289b3813609SPatrick Kelsey 	 * ifl_buf_size may be a driver-supplied value, so pull it up
2290b3813609SPatrick Kelsey 	 * to the selected mbuf size.
2291b3813609SPatrick Kelsey 	 */
2292b3813609SPatrick Kelsey 	fl->ifl_buf_size = iflib_get_mbuf_size_for(fl->ifl_buf_size);
22934c7070dbSScott Long 	if (fl->ifl_buf_size > ctx->ifc_max_fl_buf_size)
22944c7070dbSScott Long 		ctx->ifc_max_fl_buf_size = fl->ifl_buf_size;
22954c7070dbSScott Long 	fl->ifl_cltype = m_gettype(fl->ifl_buf_size);
22964c7070dbSScott Long 	fl->ifl_zone = m_getzone(fl->ifl_buf_size);
22974c7070dbSScott Long 
229835d8a463SVincenzo Maffione 	/*
229935d8a463SVincenzo Maffione 	 * Avoid pre-allocating zillions of clusters to an idle card
230035d8a463SVincenzo Maffione 	 * potentially speeding up attach. In any case make sure
230135d8a463SVincenzo Maffione 	 * to leave a descriptor unavailable. See the comment in
230235d8a463SVincenzo Maffione 	 * iflib_fl_refill_all().
23034c7070dbSScott Long 	 */
230435d8a463SVincenzo Maffione 	MPASS(fl->ifl_size > 0);
230535d8a463SVincenzo Maffione 	(void)iflib_fl_refill(ctx, fl, min(128, fl->ifl_size - 1));
230635d8a463SVincenzo Maffione 	if (min(128, fl->ifl_size - 1) != fl->ifl_credits)
23074c7070dbSScott Long 		return (ENOBUFS);
23084c7070dbSScott Long 	/*
23094c7070dbSScott Long 	 * handle failure
23104c7070dbSScott Long 	 */
23114c7070dbSScott Long 	MPASS(rxq != NULL);
23124c7070dbSScott Long 	MPASS(fl->ifl_ifdi != NULL);
23134c7070dbSScott Long 	bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
23144c7070dbSScott Long 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
23154c7070dbSScott Long 	return (0);
23164c7070dbSScott Long }
23174c7070dbSScott Long 
23184c7070dbSScott Long /*********************************************************************
23194c7070dbSScott Long  *
23204c7070dbSScott Long  *  Free receive ring data structures
23214c7070dbSScott Long  *
23224c7070dbSScott Long  **********************************************************************/
23234c7070dbSScott Long static void
23244c7070dbSScott Long iflib_rx_sds_free(iflib_rxq_t rxq)
23254c7070dbSScott Long {
23264c7070dbSScott Long 	iflib_fl_t fl;
23278a04b53dSKonstantin Belousov 	int i, j;
23284c7070dbSScott Long 
23294c7070dbSScott Long 	if (rxq->ifr_fl != NULL) {
23304c7070dbSScott Long 		for (i = 0; i < rxq->ifr_nfl; i++) {
23314c7070dbSScott Long 			fl = &rxq->ifr_fl[i];
2332bfce461eSMarius Strobl 			if (fl->ifl_buf_tag != NULL) {
23338a04b53dSKonstantin Belousov 				if (fl->ifl_sds.ifsd_map != NULL) {
233477102fd6SAndrew Gallatin 					for (j = 0; j < fl->ifl_size; j++) {
23358a04b53dSKonstantin Belousov 						bus_dmamap_sync(
2336bfce461eSMarius Strobl 						    fl->ifl_buf_tag,
233777102fd6SAndrew Gallatin 						    fl->ifl_sds.ifsd_map[j],
23388a04b53dSKonstantin Belousov 						    BUS_DMASYNC_POSTREAD);
23398a04b53dSKonstantin Belousov 						bus_dmamap_unload(
2340bfce461eSMarius Strobl 						    fl->ifl_buf_tag,
234177102fd6SAndrew Gallatin 						    fl->ifl_sds.ifsd_map[j]);
2342db8e8f1eSEric Joyner 						bus_dmamap_destroy(
2343db8e8f1eSEric Joyner 						    fl->ifl_buf_tag,
2344db8e8f1eSEric Joyner 						    fl->ifl_sds.ifsd_map[j]);
23458a04b53dSKonstantin Belousov 					}
23468a04b53dSKonstantin Belousov 				}
2347bfce461eSMarius Strobl 				bus_dma_tag_destroy(fl->ifl_buf_tag);
2348bfce461eSMarius Strobl 				fl->ifl_buf_tag = NULL;
23494c7070dbSScott Long 			}
2350e035717eSSean Bruno 			free(fl->ifl_sds.ifsd_m, M_IFLIB);
2351e035717eSSean Bruno 			free(fl->ifl_sds.ifsd_cl, M_IFLIB);
2352fbec776dSAndrew Gallatin 			free(fl->ifl_sds.ifsd_ba, M_IFLIB);
2353e035717eSSean Bruno 			free(fl->ifl_sds.ifsd_map, M_IFLIB);
2354c065d4e5SMark Johnston 			free(fl->ifl_rx_bitmap, M_IFLIB);
2355e035717eSSean Bruno 			fl->ifl_sds.ifsd_m = NULL;
2356e035717eSSean Bruno 			fl->ifl_sds.ifsd_cl = NULL;
2357fbec776dSAndrew Gallatin 			fl->ifl_sds.ifsd_ba = NULL;
2358e035717eSSean Bruno 			fl->ifl_sds.ifsd_map = NULL;
2359c065d4e5SMark Johnston 			fl->ifl_rx_bitmap = NULL;
23604c7070dbSScott Long 		}
23614c7070dbSScott Long 		free(rxq->ifr_fl, M_IFLIB);
23624c7070dbSScott Long 		rxq->ifr_fl = NULL;
2363244e7cffSEric Joyner 		free(rxq->ifr_ifdi, M_IFLIB);
2364244e7cffSEric Joyner 		rxq->ifr_ifdi = NULL;
23651722eeacSMarius Strobl 		rxq->ifr_cq_cidx = 0;
23664c7070dbSScott Long 	}
23674c7070dbSScott Long }
23684c7070dbSScott Long 
23694c7070dbSScott Long /*
23701722eeacSMarius Strobl  * Timer routine
23714c7070dbSScott Long  */
23724c7070dbSScott Long static void
23734c7070dbSScott Long iflib_timer(void *arg)
23744c7070dbSScott Long {
2375ab2e3f79SStephen Hurd 	iflib_txq_t txq = arg;
23764c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
2377ab2e3f79SStephen Hurd 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
2378dd7fbcf1SStephen Hurd 	uint64_t this_tick = ticks;
23794c7070dbSScott Long 
23804c7070dbSScott Long 	if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))
23814c7070dbSScott Long 		return;
23821722eeacSMarius Strobl 
23834c7070dbSScott Long 	/*
23844c7070dbSScott Long 	** Check on the state of the TX queue(s), this
23854c7070dbSScott Long 	** can be done without the lock because its RO
23864c7070dbSScott Long 	** and the HUNG state will be static if set.
23874c7070dbSScott Long 	*/
238881be6552SMatt Macy 	if (this_tick - txq->ift_last_timer_tick >= iflib_timer_default) {
2389dd7fbcf1SStephen Hurd 		txq->ift_last_timer_tick = this_tick;
2390ab2e3f79SStephen Hurd 		IFDI_TIMER(ctx, txq->ift_id);
2391ab2e3f79SStephen Hurd 		if ((txq->ift_qstatus == IFLIB_QUEUE_HUNG) &&
2392ab2e3f79SStephen Hurd 		    ((txq->ift_cleaned_prev == txq->ift_cleaned) ||
2393ab2e3f79SStephen Hurd 		     (sctx->isc_pause_frames == 0)))
2394ab2e3f79SStephen Hurd 			goto hung;
2395a9693502SSean Bruno 
2396f6afed72SEric Joyner 		if (txq->ift_qstatus != IFLIB_QUEUE_IDLE &&
2397f6afed72SEric Joyner 		    ifmp_ring_is_stalled(txq->ift_br)) {
239881be6552SMatt Macy 			KASSERT(ctx->ifc_link_state == LINK_STATE_UP,
239981be6552SMatt Macy 			    ("queue can't be marked as hung if interface is down"));
2400ab2e3f79SStephen Hurd 			txq->ift_qstatus = IFLIB_QUEUE_HUNG;
2401f6afed72SEric Joyner 		}
2402ab2e3f79SStephen Hurd 		txq->ift_cleaned_prev = txq->ift_cleaned;
2403dd7fbcf1SStephen Hurd 	}
2404ab2e3f79SStephen Hurd 	/* handle any laggards */
2405ab2e3f79SStephen Hurd 	if (txq->ift_db_pending)
2406ab2e3f79SStephen Hurd 		GROUPTASK_ENQUEUE(&txq->ift_task);
2407a9693502SSean Bruno 
2408ab2e3f79SStephen Hurd 	sctx->isc_pause_frames = 0;
2409d300df01SStephen Hurd 	if (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)
241081be6552SMatt Macy 		callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer,
241181be6552SMatt Macy 		    txq, txq->ift_timer.c_cpu);
2412ab2e3f79SStephen Hurd 	return;
24131722eeacSMarius Strobl 
2414ab2e3f79SStephen Hurd  hung:
24151722eeacSMarius Strobl 	device_printf(ctx->ifc_dev,
24161722eeacSMarius Strobl 	    "Watchdog timeout (TX: %d desc avail: %d pidx: %d) -- resetting\n",
2417ab2e3f79SStephen Hurd 	    txq->ift_id, TXQ_AVAIL(txq), txq->ift_pidx);
24187b610b60SSean Bruno 	STATE_LOCK(ctx);
24197b610b60SSean Bruno 	if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
24207b610b60SSean Bruno 	ctx->ifc_flags |= (IFC_DO_WATCHDOG|IFC_DO_RESET);
2421940f62d6SEric Joyner 	iflib_admin_intr_deferred(ctx);
242246fa0c25SEric Joyner 	STATE_UNLOCK(ctx);
24234c7070dbSScott Long }
24244c7070dbSScott Long 
2425b3813609SPatrick Kelsey static uint16_t
2426b3813609SPatrick Kelsey iflib_get_mbuf_size_for(unsigned int size)
2427b3813609SPatrick Kelsey {
2428b3813609SPatrick Kelsey 
2429b3813609SPatrick Kelsey 	if (size <= MCLBYTES)
2430b3813609SPatrick Kelsey 		return (MCLBYTES);
2431b3813609SPatrick Kelsey 	else
2432b3813609SPatrick Kelsey 		return (MJUMPAGESIZE);
2433b3813609SPatrick Kelsey }
2434b3813609SPatrick Kelsey 
24354c7070dbSScott Long static void
24361b9d9394SEric Joyner iflib_calc_rx_mbuf_sz(if_ctx_t ctx)
24371b9d9394SEric Joyner {
24381b9d9394SEric Joyner 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
24391b9d9394SEric Joyner 
24401b9d9394SEric Joyner 	/*
24411b9d9394SEric Joyner 	 * XXX don't set the max_frame_size to larger
24421b9d9394SEric Joyner 	 * than the hardware can handle
24431b9d9394SEric Joyner 	 */
2444b3813609SPatrick Kelsey 	ctx->ifc_rx_mbuf_sz =
2445b3813609SPatrick Kelsey 	    iflib_get_mbuf_size_for(sctx->isc_max_frame_size);
24461b9d9394SEric Joyner }
24471b9d9394SEric Joyner 
24481b9d9394SEric Joyner uint32_t
24491b9d9394SEric Joyner iflib_get_rx_mbuf_sz(if_ctx_t ctx)
24501b9d9394SEric Joyner {
24511722eeacSMarius Strobl 
24521b9d9394SEric Joyner 	return (ctx->ifc_rx_mbuf_sz);
24531b9d9394SEric Joyner }
24541b9d9394SEric Joyner 
24551b9d9394SEric Joyner static void
24564c7070dbSScott Long iflib_init_locked(if_ctx_t ctx)
24574c7070dbSScott Long {
24584c7070dbSScott Long 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
24591248952aSSean Bruno 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
24604c7070dbSScott Long 	if_t ifp = ctx->ifc_ifp;
24614c7070dbSScott Long 	iflib_fl_t fl;
24624c7070dbSScott Long 	iflib_txq_t txq;
24634c7070dbSScott Long 	iflib_rxq_t rxq;
2464ab2e3f79SStephen Hurd 	int i, j, tx_ip_csum_flags, tx_ip6_csum_flags;
24654c7070dbSScott Long 
24664c7070dbSScott Long 	if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
24674c7070dbSScott Long 	IFDI_INTR_DISABLE(ctx);
24684c7070dbSScott Long 
24693d65fd97SVincenzo Maffione 	/*
24703d65fd97SVincenzo Maffione 	 * See iflib_stop(). Useful in case iflib_init_locked() is
24713d65fd97SVincenzo Maffione 	 * called without first calling iflib_stop().
24723d65fd97SVincenzo Maffione 	 */
24733d65fd97SVincenzo Maffione 	netmap_disable_all_rings(ifp);
24743d65fd97SVincenzo Maffione 
24751248952aSSean Bruno 	tx_ip_csum_flags = scctx->isc_tx_csum_flags & (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP);
24761248952aSSean Bruno 	tx_ip6_csum_flags = scctx->isc_tx_csum_flags & (CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_IP6_SCTP);
24774c7070dbSScott Long 	/* Set hardware offload abilities */
24784c7070dbSScott Long 	if_clearhwassist(ifp);
24794c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TXCSUM)
24801248952aSSean Bruno 		if_sethwassistbits(ifp, tx_ip_csum_flags, 0);
24814c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6)
24821248952aSSean Bruno 		if_sethwassistbits(ifp,  tx_ip6_csum_flags, 0);
24834c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TSO4)
24844c7070dbSScott Long 		if_sethwassistbits(ifp, CSUM_IP_TSO, 0);
24854c7070dbSScott Long 	if (if_getcapenable(ifp) & IFCAP_TSO6)
24864c7070dbSScott Long 		if_sethwassistbits(ifp, CSUM_IP6_TSO, 0);
24874c7070dbSScott Long 
24884c7070dbSScott Long 	for (i = 0, txq = ctx->ifc_txqs; i < sctx->isc_ntxqsets; i++, txq++) {
24894c7070dbSScott Long 		CALLOUT_LOCK(txq);
24904c7070dbSScott Long 		callout_stop(&txq->ift_timer);
249117cec474SVincenzo Maffione #ifdef DEV_NETMAP
249217cec474SVincenzo Maffione 		callout_stop(&txq->ift_netmap_timer);
249317cec474SVincenzo Maffione #endif /* DEV_NETMAP */
24944c7070dbSScott Long 		CALLOUT_UNLOCK(txq);
24952ccf971aSJohn Baldwin 		(void)iflib_netmap_txq_init(ctx, txq);
24964c7070dbSScott Long 	}
24971b9d9394SEric Joyner 
24981b9d9394SEric Joyner 	/*
24991b9d9394SEric Joyner 	 * Calculate a suitable Rx mbuf size prior to calling IFDI_INIT, so
25001b9d9394SEric Joyner 	 * that drivers can use the value when setting up the hardware receive
25011b9d9394SEric Joyner 	 * buffers.
25021b9d9394SEric Joyner 	 */
25031b9d9394SEric Joyner 	iflib_calc_rx_mbuf_sz(ctx);
25041b9d9394SEric Joyner 
250523ac9029SStephen Hurd #ifdef INVARIANTS
250623ac9029SStephen Hurd 	i = if_getdrvflags(ifp);
250723ac9029SStephen Hurd #endif
25084c7070dbSScott Long 	IFDI_INIT(ctx);
250923ac9029SStephen Hurd 	MPASS(if_getdrvflags(ifp) == i);
25104c7070dbSScott Long 	for (i = 0, rxq = ctx->ifc_rxqs; i < sctx->isc_nrxqsets; i++, rxq++) {
2511d8b2d26bSVincenzo Maffione 		if (iflib_netmap_rxq_init(ctx, rxq) > 0) {
2512d8b2d26bSVincenzo Maffione 			/* This rxq is in netmap mode. Skip normal init. */
251395246abbSSean Bruno 			continue;
2514d0d0ad0aSStephen Hurd 		}
25154c7070dbSScott Long 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) {
25164c7070dbSScott Long 			if (iflib_fl_setup(fl)) {
25173d10e9edSMarius Strobl 				device_printf(ctx->ifc_dev,
25183d10e9edSMarius Strobl 				    "setting up free list %d failed - "
25193d10e9edSMarius Strobl 				    "check cluster settings\n", j);
25204c7070dbSScott Long 				goto done;
25214c7070dbSScott Long 			}
25224c7070dbSScott Long 		}
25234c7070dbSScott Long 	}
25244c7070dbSScott Long done:
25254c7070dbSScott Long 	if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
25264c7070dbSScott Long 	IFDI_INTR_ENABLE(ctx);
25274c7070dbSScott Long 	txq = ctx->ifc_txqs;
25284c7070dbSScott Long 	for (i = 0; i < sctx->isc_ntxqsets; i++, txq++)
252981be6552SMatt Macy 		callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer, txq,
2530ab2e3f79SStephen Hurd 			txq->ift_timer.c_cpu);
25313d65fd97SVincenzo Maffione 
25323d65fd97SVincenzo Maffione         /* Re-enable txsync/rxsync. */
25333d65fd97SVincenzo Maffione 	netmap_enable_all_rings(ifp);
25344c7070dbSScott Long }
25354c7070dbSScott Long 
25364c7070dbSScott Long static int
25374c7070dbSScott Long iflib_media_change(if_t ifp)
25384c7070dbSScott Long {
25394c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
25404c7070dbSScott Long 	int err;
25414c7070dbSScott Long 
25424c7070dbSScott Long 	CTX_LOCK(ctx);
25434c7070dbSScott Long 	if ((err = IFDI_MEDIA_CHANGE(ctx)) == 0)
2544922cf8acSAllan Jude 		iflib_if_init_locked(ctx);
25454c7070dbSScott Long 	CTX_UNLOCK(ctx);
25464c7070dbSScott Long 	return (err);
25474c7070dbSScott Long }
25484c7070dbSScott Long 
25494c7070dbSScott Long static void
25504c7070dbSScott Long iflib_media_status(if_t ifp, struct ifmediareq *ifmr)
25514c7070dbSScott Long {
25524c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
25534c7070dbSScott Long 
25544c7070dbSScott Long 	CTX_LOCK(ctx);
2555ab2e3f79SStephen Hurd 	IFDI_UPDATE_ADMIN_STATUS(ctx);
25564c7070dbSScott Long 	IFDI_MEDIA_STATUS(ctx, ifmr);
25574c7070dbSScott Long 	CTX_UNLOCK(ctx);
25584c7070dbSScott Long }
25594c7070dbSScott Long 
256009f6ff4fSMatt Macy void
25614c7070dbSScott Long iflib_stop(if_ctx_t ctx)
25624c7070dbSScott Long {
25634c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
25644c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
25654c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
25664d261ce2SStephen Hurd 	if_shared_ctx_t sctx = ctx->ifc_sctx;
25674c7070dbSScott Long 	iflib_dma_info_t di;
25684c7070dbSScott Long 	iflib_fl_t fl;
25694c7070dbSScott Long 	int i, j;
25704c7070dbSScott Long 
25714c7070dbSScott Long 	/* Tell the stack that the interface is no longer active */
25724c7070dbSScott Long 	if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
25734c7070dbSScott Long 
25744c7070dbSScott Long 	IFDI_INTR_DISABLE(ctx);
2575ab2e3f79SStephen Hurd 	DELAY(1000);
2576da69b8f9SSean Bruno 	IFDI_STOP(ctx);
2577ab2e3f79SStephen Hurd 	DELAY(1000);
25784c7070dbSScott Long 
25793d65fd97SVincenzo Maffione 	/*
25803d65fd97SVincenzo Maffione 	 * Stop any pending txsync/rxsync and prevent new ones
25813d65fd97SVincenzo Maffione 	 * form starting. Processes blocked in poll() will get
25823d65fd97SVincenzo Maffione 	 * POLLERR.
25833d65fd97SVincenzo Maffione 	 */
25843d65fd97SVincenzo Maffione 	netmap_disable_all_rings(ctx->ifc_ifp);
25853d65fd97SVincenzo Maffione 
2586da69b8f9SSean Bruno 	iflib_debug_reset();
25874c7070dbSScott Long 	/* Wait for current tx queue users to exit to disarm watchdog timer. */
25884c7070dbSScott Long 	for (i = 0; i < scctx->isc_ntxqsets; i++, txq++) {
25894c7070dbSScott Long 		/* make sure all transmitters have completed before proceeding XXX */
25904c7070dbSScott Long 
2591226fb85dSStephen Hurd 		CALLOUT_LOCK(txq);
2592226fb85dSStephen Hurd 		callout_stop(&txq->ift_timer);
259317cec474SVincenzo Maffione #ifdef DEV_NETMAP
259417cec474SVincenzo Maffione 		callout_stop(&txq->ift_netmap_timer);
259517cec474SVincenzo Maffione #endif /* DEV_NETMAP */
2596226fb85dSStephen Hurd 		CALLOUT_UNLOCK(txq);
2597226fb85dSStephen Hurd 
25984c7070dbSScott Long 		/* clean any enqueued buffers */
2599da69b8f9SSean Bruno 		iflib_ifmp_purge(txq);
26004c7070dbSScott Long 		/* Free any existing tx buffers. */
260123ac9029SStephen Hurd 		for (j = 0; j < txq->ift_size; j++) {
26024c7070dbSScott Long 			iflib_txsd_free(ctx, txq, j);
26034c7070dbSScott Long 		}
2604ab2e3f79SStephen Hurd 		txq->ift_processed = txq->ift_cleaned = txq->ift_cidx_processed = 0;
2605ab2e3f79SStephen Hurd 		txq->ift_in_use = txq->ift_gen = txq->ift_cidx = txq->ift_pidx = txq->ift_no_desc_avail = 0;
26064c7070dbSScott Long 		txq->ift_closed = txq->ift_mbuf_defrag = txq->ift_mbuf_defrag_failed = 0;
26074c7070dbSScott Long 		txq->ift_no_tx_dma_setup = txq->ift_txd_encap_efbig = txq->ift_map_failed = 0;
2608ab2e3f79SStephen Hurd 		txq->ift_pullups = 0;
260995246abbSSean Bruno 		ifmp_ring_reset_stats(txq->ift_br);
26104d261ce2SStephen Hurd 		for (j = 0, di = txq->ift_ifdi; j < sctx->isc_ntxqs; j++, di++)
26114c7070dbSScott Long 			bzero((void *)di->idi_vaddr, di->idi_size);
26124c7070dbSScott Long 	}
26134c7070dbSScott Long 	for (i = 0; i < scctx->isc_nrxqsets; i++, rxq++) {
26144c7070dbSScott Long 		/* make sure all transmitters have completed before proceeding XXX */
26154c7070dbSScott Long 
26161722eeacSMarius Strobl 		rxq->ifr_cq_cidx = 0;
26174d261ce2SStephen Hurd 		for (j = 0, di = rxq->ifr_ifdi; j < sctx->isc_nrxqs; j++, di++)
26184c7070dbSScott Long 			bzero((void *)di->idi_vaddr, di->idi_size);
26194c7070dbSScott Long 		/* also resets the free lists pidx/cidx */
26204c7070dbSScott Long 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++)
26214c7070dbSScott Long 			iflib_fl_bufs_free(fl);
26224c7070dbSScott Long 	}
26234c7070dbSScott Long }
26244c7070dbSScott Long 
262595246abbSSean Bruno static inline caddr_t
262695246abbSSean Bruno calc_next_rxd(iflib_fl_t fl, int cidx)
262795246abbSSean Bruno {
262895246abbSSean Bruno 	qidx_t size;
262995246abbSSean Bruno 	int nrxd;
263095246abbSSean Bruno 	caddr_t start, end, cur, next;
263195246abbSSean Bruno 
263295246abbSSean Bruno 	nrxd = fl->ifl_size;
263395246abbSSean Bruno 	size = fl->ifl_rxd_size;
263495246abbSSean Bruno 	start = fl->ifl_ifdi->idi_vaddr;
263595246abbSSean Bruno 
263695246abbSSean Bruno 	if (__predict_false(size == 0))
263795246abbSSean Bruno 		return (start);
263895246abbSSean Bruno 	cur = start + size*cidx;
263995246abbSSean Bruno 	end = start + size*nrxd;
264095246abbSSean Bruno 	next = CACHE_PTR_NEXT(cur);
264195246abbSSean Bruno 	return (next < end ? next : start);
264295246abbSSean Bruno }
264395246abbSSean Bruno 
2644e035717eSSean Bruno static inline void
2645e035717eSSean Bruno prefetch_pkts(iflib_fl_t fl, int cidx)
2646e035717eSSean Bruno {
2647e035717eSSean Bruno 	int nextptr;
2648e035717eSSean Bruno 	int nrxd = fl->ifl_size;
264995246abbSSean Bruno 	caddr_t next_rxd;
265095246abbSSean Bruno 
2651e035717eSSean Bruno 	nextptr = (cidx + CACHE_PTR_INCREMENT) & (nrxd-1);
2652e035717eSSean Bruno 	prefetch(&fl->ifl_sds.ifsd_m[nextptr]);
2653e035717eSSean Bruno 	prefetch(&fl->ifl_sds.ifsd_cl[nextptr]);
265495246abbSSean Bruno 	next_rxd = calc_next_rxd(fl, cidx);
265595246abbSSean Bruno 	prefetch(next_rxd);
2656e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 1) & (nrxd-1)]);
2657e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 2) & (nrxd-1)]);
2658e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 3) & (nrxd-1)]);
2659e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_m[(cidx + 4) & (nrxd-1)]);
2660e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 1) & (nrxd-1)]);
2661e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 2) & (nrxd-1)]);
2662e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 3) & (nrxd-1)]);
2663e035717eSSean Bruno 	prefetch(fl->ifl_sds.ifsd_cl[(cidx + 4) & (nrxd-1)]);
2664e035717eSSean Bruno }
2665e035717eSSean Bruno 
26666d49b41eSAndrew Gallatin static struct mbuf *
26676d49b41eSAndrew Gallatin rxd_frag_to_sd(iflib_rxq_t rxq, if_rxd_frag_t irf, bool unload, if_rxsd_t sd,
26686d49b41eSAndrew Gallatin     int *pf_rv, if_rxd_info_t ri)
26694c7070dbSScott Long {
2670e035717eSSean Bruno 	bus_dmamap_t map;
26714c7070dbSScott Long 	iflib_fl_t fl;
26726d49b41eSAndrew Gallatin 	caddr_t payload;
26736d49b41eSAndrew Gallatin 	struct mbuf *m;
26746d49b41eSAndrew Gallatin 	int flid, cidx, len, next;
26754c7070dbSScott Long 
267695246abbSSean Bruno 	map = NULL;
26774c7070dbSScott Long 	flid = irf->irf_flid;
26784c7070dbSScott Long 	cidx = irf->irf_idx;
26794c7070dbSScott Long 	fl = &rxq->ifr_fl[flid];
268095246abbSSean Bruno 	sd->ifsd_fl = fl;
26816d49b41eSAndrew Gallatin 	m = fl->ifl_sds.ifsd_m[cidx];
268295246abbSSean Bruno 	sd->ifsd_cl = &fl->ifl_sds.ifsd_cl[cidx];
26834c7070dbSScott Long 	fl->ifl_credits--;
26844c7070dbSScott Long #if MEMORY_LOGGING
26854c7070dbSScott Long 	fl->ifl_m_dequeued++;
26864c7070dbSScott Long #endif
268795246abbSSean Bruno 	if (rxq->ifr_ctx->ifc_flags & IFC_PREFETCH)
2688e035717eSSean Bruno 		prefetch_pkts(fl, cidx);
2689e035717eSSean Bruno 	next = (cidx + CACHE_PTR_INCREMENT) & (fl->ifl_size-1);
2690e035717eSSean Bruno 	prefetch(&fl->ifl_sds.ifsd_map[next]);
2691e035717eSSean Bruno 	map = fl->ifl_sds.ifsd_map[cidx];
26924c7070dbSScott Long 
2693bfce461eSMarius Strobl 	bus_dmamap_sync(fl->ifl_buf_tag, map, BUS_DMASYNC_POSTREAD);
26946d49b41eSAndrew Gallatin 
26954f2beb72SPatrick Kelsey 	if (rxq->pfil != NULL && PFIL_HOOKED_IN(rxq->pfil) && pf_rv != NULL &&
26964f2beb72SPatrick Kelsey 	    irf->irf_len != 0) {
26976d49b41eSAndrew Gallatin 		payload  = *sd->ifsd_cl;
26986d49b41eSAndrew Gallatin 		payload +=  ri->iri_pad;
26996d49b41eSAndrew Gallatin 		len = ri->iri_len - ri->iri_pad;
27006d49b41eSAndrew Gallatin 		*pf_rv = pfil_run_hooks(rxq->pfil, payload, ri->iri_ifp,
27016d49b41eSAndrew Gallatin 		    len | PFIL_MEMPTR | PFIL_IN, NULL);
27026d49b41eSAndrew Gallatin 		switch (*pf_rv) {
27036d49b41eSAndrew Gallatin 		case PFIL_DROPPED:
27046d49b41eSAndrew Gallatin 		case PFIL_CONSUMED:
27056d49b41eSAndrew Gallatin 			/*
27066d49b41eSAndrew Gallatin 			 * The filter ate it.  Everything is recycled.
27076d49b41eSAndrew Gallatin 			 */
27086d49b41eSAndrew Gallatin 			m = NULL;
27096d49b41eSAndrew Gallatin 			unload = 0;
27106d49b41eSAndrew Gallatin 			break;
27116d49b41eSAndrew Gallatin 		case PFIL_REALLOCED:
27126d49b41eSAndrew Gallatin 			/*
27136d49b41eSAndrew Gallatin 			 * The filter copied it.  Everything is recycled.
27146d49b41eSAndrew Gallatin 			 */
27156d49b41eSAndrew Gallatin 			m = pfil_mem2mbuf(payload);
27166d49b41eSAndrew Gallatin 			unload = 0;
27176d49b41eSAndrew Gallatin 			break;
27186d49b41eSAndrew Gallatin 		case PFIL_PASS:
27196d49b41eSAndrew Gallatin 			/*
27206d49b41eSAndrew Gallatin 			 * Filter said it was OK, so receive like
27216d49b41eSAndrew Gallatin 			 * normal
27226d49b41eSAndrew Gallatin 			 */
27236d49b41eSAndrew Gallatin 			fl->ifl_sds.ifsd_m[cidx] = NULL;
27246d49b41eSAndrew Gallatin 			break;
27256d49b41eSAndrew Gallatin 		default:
27266d49b41eSAndrew Gallatin 			MPASS(0);
27276d49b41eSAndrew Gallatin 		}
27286d49b41eSAndrew Gallatin 	} else {
27296d49b41eSAndrew Gallatin 		fl->ifl_sds.ifsd_m[cidx] = NULL;
27300c864213SAndrew Gallatin 		if (pf_rv != NULL)
27316d49b41eSAndrew Gallatin 			*pf_rv = PFIL_PASS;
27326d49b41eSAndrew Gallatin 	}
27336d49b41eSAndrew Gallatin 
27344f2beb72SPatrick Kelsey 	if (unload && irf->irf_len != 0)
2735bfce461eSMarius Strobl 		bus_dmamap_unload(fl->ifl_buf_tag, map);
273695246abbSSean Bruno 	fl->ifl_cidx = (fl->ifl_cidx + 1) & (fl->ifl_size-1);
273795246abbSSean Bruno 	if (__predict_false(fl->ifl_cidx == 0))
27384c7070dbSScott Long 		fl->ifl_gen = 0;
273987890dbaSSean Bruno 	bit_clear(fl->ifl_rx_bitmap, cidx);
27406d49b41eSAndrew Gallatin 	return (m);
27414c7070dbSScott Long }
27424c7070dbSScott Long 
27434c7070dbSScott Long static struct mbuf *
27446d49b41eSAndrew Gallatin assemble_segments(iflib_rxq_t rxq, if_rxd_info_t ri, if_rxsd_t sd, int *pf_rv)
27454c7070dbSScott Long {
274695246abbSSean Bruno 	struct mbuf *m, *mh, *mt;
274795246abbSSean Bruno 	caddr_t cl;
27486d49b41eSAndrew Gallatin 	int  *pf_rv_ptr, flags, i, padlen;
27496d49b41eSAndrew Gallatin 	bool consumed;
27504c7070dbSScott Long 
27514c7070dbSScott Long 	i = 0;
275223ac9029SStephen Hurd 	mh = NULL;
27536d49b41eSAndrew Gallatin 	consumed = false;
27546d49b41eSAndrew Gallatin 	*pf_rv = PFIL_PASS;
27556d49b41eSAndrew Gallatin 	pf_rv_ptr = pf_rv;
27564c7070dbSScott Long 	do {
27576d49b41eSAndrew Gallatin 		m = rxd_frag_to_sd(rxq, &ri->iri_frags[i], !consumed, sd,
27586d49b41eSAndrew Gallatin 		    pf_rv_ptr, ri);
27594c7070dbSScott Long 
276095246abbSSean Bruno 		MPASS(*sd->ifsd_cl != NULL);
276123ac9029SStephen Hurd 
27626d49b41eSAndrew Gallatin 		/*
27636d49b41eSAndrew Gallatin 		 * Exclude zero-length frags & frags from
27646d49b41eSAndrew Gallatin 		 * packets the filter has consumed or dropped
27656d49b41eSAndrew Gallatin 		 */
27666d49b41eSAndrew Gallatin 		if (ri->iri_frags[i].irf_len == 0 || consumed ||
27676d49b41eSAndrew Gallatin 		    *pf_rv == PFIL_CONSUMED || *pf_rv == PFIL_DROPPED) {
27686d49b41eSAndrew Gallatin 			if (mh == NULL) {
27696d49b41eSAndrew Gallatin 				/* everything saved here */
27706d49b41eSAndrew Gallatin 				consumed = true;
27716d49b41eSAndrew Gallatin 				pf_rv_ptr = NULL;
277223ac9029SStephen Hurd 				continue;
277323ac9029SStephen Hurd 			}
27746d49b41eSAndrew Gallatin 			/* XXX we can save the cluster here, but not the mbuf */
27756d49b41eSAndrew Gallatin 			m_init(m, M_NOWAIT, MT_DATA, 0);
27766d49b41eSAndrew Gallatin 			m_free(m);
27776d49b41eSAndrew Gallatin 			continue;
27786d49b41eSAndrew Gallatin 		}
277923ac9029SStephen Hurd 		if (mh == NULL) {
27804c7070dbSScott Long 			flags = M_PKTHDR|M_EXT;
27814c7070dbSScott Long 			mh = mt = m;
27824c7070dbSScott Long 			padlen = ri->iri_pad;
27834c7070dbSScott Long 		} else {
27844c7070dbSScott Long 			flags = M_EXT;
27854c7070dbSScott Long 			mt->m_next = m;
27864c7070dbSScott Long 			mt = m;
27874c7070dbSScott Long 			/* assuming padding is only on the first fragment */
27884c7070dbSScott Long 			padlen = 0;
27894c7070dbSScott Long 		}
279095246abbSSean Bruno 		cl = *sd->ifsd_cl;
279195246abbSSean Bruno 		*sd->ifsd_cl = NULL;
27924c7070dbSScott Long 
27934c7070dbSScott Long 		/* Can these two be made one ? */
27944c7070dbSScott Long 		m_init(m, M_NOWAIT, MT_DATA, flags);
279595246abbSSean Bruno 		m_cljset(m, cl, sd->ifsd_fl->ifl_cltype);
27964c7070dbSScott Long 		/*
27974c7070dbSScott Long 		 * These must follow m_init and m_cljset
27984c7070dbSScott Long 		 */
27994c7070dbSScott Long 		m->m_data += padlen;
28004c7070dbSScott Long 		ri->iri_len -= padlen;
280123ac9029SStephen Hurd 		m->m_len = ri->iri_frags[i].irf_len;
28024c7070dbSScott Long 	} while (++i < ri->iri_nfrags);
28034c7070dbSScott Long 
28044c7070dbSScott Long 	return (mh);
28054c7070dbSScott Long }
28064c7070dbSScott Long 
28074c7070dbSScott Long /*
28084c7070dbSScott Long  * Process one software descriptor
28094c7070dbSScott Long  */
28104c7070dbSScott Long static struct mbuf *
28114c7070dbSScott Long iflib_rxd_pkt_get(iflib_rxq_t rxq, if_rxd_info_t ri)
28124c7070dbSScott Long {
281395246abbSSean Bruno 	struct if_rxsd sd;
28144c7070dbSScott Long 	struct mbuf *m;
28156d49b41eSAndrew Gallatin 	int pf_rv;
28164c7070dbSScott Long 
28174c7070dbSScott Long 	/* should I merge this back in now that the two paths are basically duplicated? */
281823ac9029SStephen Hurd 	if (ri->iri_nfrags == 1 &&
28194f2beb72SPatrick Kelsey 	    ri->iri_frags[0].irf_len != 0 &&
282018628b74SMark Johnston 	    ri->iri_frags[0].irf_len <= MIN(IFLIB_RX_COPY_THRESH, MHLEN)) {
28216d49b41eSAndrew Gallatin 		m = rxd_frag_to_sd(rxq, &ri->iri_frags[0], false, &sd,
28226d49b41eSAndrew Gallatin 		    &pf_rv, ri);
28236d49b41eSAndrew Gallatin 		if (pf_rv != PFIL_PASS && pf_rv != PFIL_REALLOCED)
28246d49b41eSAndrew Gallatin 			return (m);
28256d49b41eSAndrew Gallatin 		if (pf_rv == PFIL_PASS) {
28264c7070dbSScott Long 			m_init(m, M_NOWAIT, MT_DATA, M_PKTHDR);
282795246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
282895246abbSSean Bruno 			if (!IP_ALIGNED(m))
282995246abbSSean Bruno 				m->m_data += 2;
283095246abbSSean Bruno #endif
283195246abbSSean Bruno 			memcpy(m->m_data, *sd.ifsd_cl, ri->iri_len);
283223ac9029SStephen Hurd 			m->m_len = ri->iri_frags[0].irf_len;
28336d49b41eSAndrew Gallatin 		}
28344c7070dbSScott Long 	} else {
28356d49b41eSAndrew Gallatin 		m = assemble_segments(rxq, ri, &sd, &pf_rv);
28364f2beb72SPatrick Kelsey 		if (m == NULL)
28374f2beb72SPatrick Kelsey 			return (NULL);
28386d49b41eSAndrew Gallatin 		if (pf_rv != PFIL_PASS && pf_rv != PFIL_REALLOCED)
28396d49b41eSAndrew Gallatin 			return (m);
28404c7070dbSScott Long 	}
28414c7070dbSScott Long 	m->m_pkthdr.len = ri->iri_len;
28424c7070dbSScott Long 	m->m_pkthdr.rcvif = ri->iri_ifp;
28434c7070dbSScott Long 	m->m_flags |= ri->iri_flags;
28444c7070dbSScott Long 	m->m_pkthdr.ether_vtag = ri->iri_vtag;
28454c7070dbSScott Long 	m->m_pkthdr.flowid = ri->iri_flowid;
28464c7070dbSScott Long 	M_HASHTYPE_SET(m, ri->iri_rsstype);
28474c7070dbSScott Long 	m->m_pkthdr.csum_flags = ri->iri_csum_flags;
28484c7070dbSScott Long 	m->m_pkthdr.csum_data = ri->iri_csum_data;
28494c7070dbSScott Long 	return (m);
28504c7070dbSScott Long }
28514c7070dbSScott Long 
285235e4e998SStephen Hurd #if defined(INET6) || defined(INET)
2853fe1bcadaSStephen Hurd static void
2854fe1bcadaSStephen Hurd iflib_get_ip_forwarding(struct lro_ctrl *lc, bool *v4, bool *v6)
2855fe1bcadaSStephen Hurd {
2856fe1bcadaSStephen Hurd 	CURVNET_SET(lc->ifp->if_vnet);
2857fe1bcadaSStephen Hurd #if defined(INET6)
2858188adcb7SMarko Zec 	*v6 = V_ip6_forwarding;
2859fe1bcadaSStephen Hurd #endif
2860fe1bcadaSStephen Hurd #if defined(INET)
2861188adcb7SMarko Zec 	*v4 = V_ipforwarding;
2862fe1bcadaSStephen Hurd #endif
2863fe1bcadaSStephen Hurd 	CURVNET_RESTORE();
2864fe1bcadaSStephen Hurd }
2865fe1bcadaSStephen Hurd 
286635e4e998SStephen Hurd /*
286735e4e998SStephen Hurd  * Returns true if it's possible this packet could be LROed.
286835e4e998SStephen Hurd  * if it returns false, it is guaranteed that tcp_lro_rx()
286935e4e998SStephen Hurd  * would not return zero.
287035e4e998SStephen Hurd  */
287135e4e998SStephen Hurd static bool
2872fe1bcadaSStephen Hurd iflib_check_lro_possible(struct mbuf *m, bool v4_forwarding, bool v6_forwarding)
287335e4e998SStephen Hurd {
287435e4e998SStephen Hurd 	struct ether_header *eh;
287535e4e998SStephen Hurd 
287635e4e998SStephen Hurd 	eh = mtod(m, struct ether_header *);
28776aee0bfaSMarko Zec 	switch (eh->ether_type) {
2878abec4724SSean Bruno #if defined(INET6)
28796aee0bfaSMarko Zec 		case htons(ETHERTYPE_IPV6):
28806aee0bfaSMarko Zec 			return (!v6_forwarding);
2881abec4724SSean Bruno #endif
2882abec4724SSean Bruno #if defined (INET)
28836aee0bfaSMarko Zec 		case htons(ETHERTYPE_IP):
28846aee0bfaSMarko Zec 			return (!v4_forwarding);
2885abec4724SSean Bruno #endif
288635e4e998SStephen Hurd 	}
288735e4e998SStephen Hurd 
288835e4e998SStephen Hurd 	return false;
288935e4e998SStephen Hurd }
2890fe1bcadaSStephen Hurd #else
2891fe1bcadaSStephen Hurd static void
2892fe1bcadaSStephen Hurd iflib_get_ip_forwarding(struct lro_ctrl *lc __unused, bool *v4 __unused, bool *v6 __unused)
2893fe1bcadaSStephen Hurd {
2894fe1bcadaSStephen Hurd }
289535e4e998SStephen Hurd #endif
289635e4e998SStephen Hurd 
2897fb1a29b4SHans Petter Selasky static void
2898fb1a29b4SHans Petter Selasky _task_fn_rx_watchdog(void *context)
2899fb1a29b4SHans Petter Selasky {
2900fb1a29b4SHans Petter Selasky 	iflib_rxq_t rxq = context;
2901fb1a29b4SHans Petter Selasky 
2902fb1a29b4SHans Petter Selasky 	GROUPTASK_ENQUEUE(&rxq->ifr_task);
2903fb1a29b4SHans Petter Selasky }
2904fb1a29b4SHans Petter Selasky 
2905fb1a29b4SHans Petter Selasky static uint8_t
290695246abbSSean Bruno iflib_rxeof(iflib_rxq_t rxq, qidx_t budget)
29074c7070dbSScott Long {
29081722eeacSMarius Strobl 	if_t ifp;
29094c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
29104c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
291123ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
29124c7070dbSScott Long 	int avail, i;
291395246abbSSean Bruno 	qidx_t *cidxp;
29144c7070dbSScott Long 	struct if_rxd_info ri;
29154c7070dbSScott Long 	int err, budget_left, rx_bytes, rx_pkts;
29164c7070dbSScott Long 	iflib_fl_t fl;
29174c7070dbSScott Long 	int lro_enabled;
2918f6cb0deaSMatt Macy 	bool v4_forwarding, v6_forwarding, lro_possible;
2919fb1a29b4SHans Petter Selasky 	uint8_t retval = 0;
292095246abbSSean Bruno 
29214c7070dbSScott Long 	/*
29224c7070dbSScott Long 	 * XXX early demux data packets so that if_input processing only handles
29234c7070dbSScott Long 	 * acks in interrupt context
29244c7070dbSScott Long 	 */
292520f63282SStephen Hurd 	struct mbuf *m, *mh, *mt, *mf;
29264c7070dbSScott Long 
29270b8df657SGleb Smirnoff 	NET_EPOCH_ASSERT();
29280b8df657SGleb Smirnoff 
2929f6cb0deaSMatt Macy 	lro_possible = v4_forwarding = v6_forwarding = false;
293095246abbSSean Bruno 	ifp = ctx->ifc_ifp;
29314c7070dbSScott Long 	mh = mt = NULL;
29324c7070dbSScott Long 	MPASS(budget > 0);
29334c7070dbSScott Long 	rx_pkts	= rx_bytes = 0;
293423ac9029SStephen Hurd 	if (sctx->isc_flags & IFLIB_HAS_RXCQ)
29354c7070dbSScott Long 		cidxp = &rxq->ifr_cq_cidx;
29364c7070dbSScott Long 	else
29374c7070dbSScott Long 		cidxp = &rxq->ifr_fl[0].ifl_cidx;
293823ac9029SStephen Hurd 	if ((avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget)) == 0) {
29394c7070dbSScott Long 		for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++)
2940b256d25cSMark Johnston 			retval |= iflib_fl_refill_all(ctx, fl);
29414c7070dbSScott Long 		DBG_COUNTER_INC(rx_unavail);
2942fb1a29b4SHans Petter Selasky 		return (retval);
29434c7070dbSScott Long 	}
29444c7070dbSScott Long 
29456d49b41eSAndrew Gallatin 	/* pfil needs the vnet to be set */
29466d49b41eSAndrew Gallatin 	CURVNET_SET_QUIET(ifp->if_vnet);
29478b8d9093SMarius Strobl 	for (budget_left = budget; budget_left > 0 && avail > 0;) {
29484c7070dbSScott Long 		if (__predict_false(!CTX_ACTIVE(ctx))) {
29494c7070dbSScott Long 			DBG_COUNTER_INC(rx_ctx_inactive);
29504c7070dbSScott Long 			break;
29514c7070dbSScott Long 		}
29524c7070dbSScott Long 		/*
29534c7070dbSScott Long 		 * Reset client set fields to their default values
29544c7070dbSScott Long 		 */
295595246abbSSean Bruno 		rxd_info_zero(&ri);
29564c7070dbSScott Long 		ri.iri_qsidx = rxq->ifr_id;
29574c7070dbSScott Long 		ri.iri_cidx = *cidxp;
295895246abbSSean Bruno 		ri.iri_ifp = ifp;
29594c7070dbSScott Long 		ri.iri_frags = rxq->ifr_frags;
29604c7070dbSScott Long 		err = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri);
29614c7070dbSScott Long 
296295246abbSSean Bruno 		if (err)
296395246abbSSean Bruno 			goto err;
29646d49b41eSAndrew Gallatin 		rx_pkts += 1;
29656d49b41eSAndrew Gallatin 		rx_bytes += ri.iri_len;
296623ac9029SStephen Hurd 		if (sctx->isc_flags & IFLIB_HAS_RXCQ) {
296723ac9029SStephen Hurd 			*cidxp = ri.iri_cidx;
296823ac9029SStephen Hurd 			/* Update our consumer index */
296995246abbSSean Bruno 			/* XXX NB: shurd - check if this is still safe */
29701722eeacSMarius Strobl 			while (rxq->ifr_cq_cidx >= scctx->isc_nrxd[0])
297123ac9029SStephen Hurd 				rxq->ifr_cq_cidx -= scctx->isc_nrxd[0];
29724c7070dbSScott Long 			/* was this only a completion queue message? */
29734c7070dbSScott Long 			if (__predict_false(ri.iri_nfrags == 0))
29744c7070dbSScott Long 				continue;
29754c7070dbSScott Long 		}
29764c7070dbSScott Long 		MPASS(ri.iri_nfrags != 0);
29774c7070dbSScott Long 		MPASS(ri.iri_len != 0);
29784c7070dbSScott Long 
29794c7070dbSScott Long 		/* will advance the cidx on the corresponding free lists */
29804c7070dbSScott Long 		m = iflib_rxd_pkt_get(rxq, &ri);
29818b8d9093SMarius Strobl 		avail--;
29828b8d9093SMarius Strobl 		budget_left--;
29834c7070dbSScott Long 		if (avail == 0 && budget_left)
298423ac9029SStephen Hurd 			avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget_left);
29854c7070dbSScott Long 
29866d49b41eSAndrew Gallatin 		if (__predict_false(m == NULL))
29874c7070dbSScott Long 			continue;
29886d49b41eSAndrew Gallatin 
29894c7070dbSScott Long 		/* imm_pkt: -- cxgb */
29904c7070dbSScott Long 		if (mh == NULL)
29914c7070dbSScott Long 			mh = mt = m;
29924c7070dbSScott Long 		else {
29934c7070dbSScott Long 			mt->m_nextpkt = m;
29944c7070dbSScott Long 			mt = m;
29954c7070dbSScott Long 		}
29964c7070dbSScott Long 	}
29976d49b41eSAndrew Gallatin 	CURVNET_RESTORE();
29984c7070dbSScott Long 	/* make sure that we can refill faster than drain */
29994c7070dbSScott Long 	for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++)
3000b256d25cSMark Johnston 		retval |= iflib_fl_refill_all(ctx, fl);
30014c7070dbSScott Long 
30024c7070dbSScott Long 	lro_enabled = (if_getcapenable(ifp) & IFCAP_LRO);
3003fe1bcadaSStephen Hurd 	if (lro_enabled)
3004fe1bcadaSStephen Hurd 		iflib_get_ip_forwarding(&rxq->ifr_lc, &v4_forwarding, &v6_forwarding);
300520f63282SStephen Hurd 	mt = mf = NULL;
30064c7070dbSScott Long 	while (mh != NULL) {
30074c7070dbSScott Long 		m = mh;
30084c7070dbSScott Long 		mh = mh->m_nextpkt;
30094c7070dbSScott Long 		m->m_nextpkt = NULL;
301095246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
301195246abbSSean Bruno 		if (!IP_ALIGNED(m) && (m = iflib_fixup_rx(m)) == NULL)
301295246abbSSean Bruno 			continue;
301395246abbSSean Bruno #endif
3014aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
301535e4e998SStephen Hurd 		if (lro_enabled) {
301635e4e998SStephen Hurd 			if (!lro_possible) {
3017fe1bcadaSStephen Hurd 				lro_possible = iflib_check_lro_possible(m, v4_forwarding, v6_forwarding);
301835e4e998SStephen Hurd 				if (lro_possible && mf != NULL) {
301935e4e998SStephen Hurd 					ifp->if_input(ifp, mf);
302035e4e998SStephen Hurd 					DBG_COUNTER_INC(rx_if_input);
302135e4e998SStephen Hurd 					mt = mf = NULL;
302235e4e998SStephen Hurd 				}
302335e4e998SStephen Hurd 			}
302425ac1dd5SStephen Hurd 			if ((m->m_pkthdr.csum_flags & (CSUM_L4_CALC|CSUM_L4_VALID)) ==
302525ac1dd5SStephen Hurd 			    (CSUM_L4_CALC|CSUM_L4_VALID)) {
302635e4e998SStephen Hurd 				if (lro_possible && tcp_lro_rx(&rxq->ifr_lc, m, 0) == 0)
30274c7070dbSScott Long 					continue;
302820f63282SStephen Hurd 			}
302925ac1dd5SStephen Hurd 		}
3030aaeb188aSBjoern A. Zeeb #endif
303135e4e998SStephen Hurd 		if (lro_possible) {
303235e4e998SStephen Hurd 			ifp->if_input(ifp, m);
303335e4e998SStephen Hurd 			DBG_COUNTER_INC(rx_if_input);
303435e4e998SStephen Hurd 			continue;
303535e4e998SStephen Hurd 		}
303635e4e998SStephen Hurd 
303735e4e998SStephen Hurd 		if (mf == NULL)
303835e4e998SStephen Hurd 			mf = m;
303920f63282SStephen Hurd 		if (mt != NULL)
304020f63282SStephen Hurd 			mt->m_nextpkt = m;
304120f63282SStephen Hurd 		mt = m;
304220f63282SStephen Hurd 	}
304320f63282SStephen Hurd 	if (mf != NULL) {
304420f63282SStephen Hurd 		ifp->if_input(ifp, mf);
30454c7070dbSScott Long 		DBG_COUNTER_INC(rx_if_input);
30464c7070dbSScott Long 	}
304723ac9029SStephen Hurd 
30484c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_IBYTES, rx_bytes);
30494c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_pkts);
30504c7070dbSScott Long 
30514c7070dbSScott Long 	/*
30524c7070dbSScott Long 	 * Flush any outstanding LRO work
30534c7070dbSScott Long 	 */
3054aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
305523ac9029SStephen Hurd 	tcp_lro_flush_all(&rxq->ifr_lc);
3056aaeb188aSBjoern A. Zeeb #endif
3057fb1a29b4SHans Petter Selasky 	if (avail != 0 || iflib_rxd_avail(ctx, rxq, *cidxp, 1) != 0)
3058fb1a29b4SHans Petter Selasky 		retval |= IFLIB_RXEOF_MORE;
3059fb1a29b4SHans Petter Selasky 	return (retval);
306095246abbSSean Bruno err:
30617b610b60SSean Bruno 	STATE_LOCK(ctx);
3062ab2e3f79SStephen Hurd 	ctx->ifc_flags |= IFC_DO_RESET;
3063940f62d6SEric Joyner 	iflib_admin_intr_deferred(ctx);
306446fa0c25SEric Joyner 	STATE_UNLOCK(ctx);
3065fb1a29b4SHans Petter Selasky 	return (0);
306695246abbSSean Bruno }
306795246abbSSean Bruno 
306895246abbSSean Bruno #define TXD_NOTIFY_COUNT(txq) (((txq)->ift_size / (txq)->ift_update_freq)-1)
306995246abbSSean Bruno static inline qidx_t
307095246abbSSean Bruno txq_max_db_deferred(iflib_txq_t txq, qidx_t in_use)
307195246abbSSean Bruno {
307295246abbSSean Bruno 	qidx_t notify_count = TXD_NOTIFY_COUNT(txq);
307395246abbSSean Bruno 	qidx_t minthresh = txq->ift_size / 8;
307495246abbSSean Bruno 	if (in_use > 4*minthresh)
307595246abbSSean Bruno 		return (notify_count);
307695246abbSSean Bruno 	if (in_use > 2*minthresh)
307795246abbSSean Bruno 		return (notify_count >> 1);
307895246abbSSean Bruno 	if (in_use > minthresh)
307995246abbSSean Bruno 		return (notify_count >> 3);
308095246abbSSean Bruno 	return (0);
308195246abbSSean Bruno }
308295246abbSSean Bruno 
308395246abbSSean Bruno static inline qidx_t
308495246abbSSean Bruno txq_max_rs_deferred(iflib_txq_t txq)
308595246abbSSean Bruno {
308695246abbSSean Bruno 	qidx_t notify_count = TXD_NOTIFY_COUNT(txq);
308795246abbSSean Bruno 	qidx_t minthresh = txq->ift_size / 8;
308895246abbSSean Bruno 	if (txq->ift_in_use > 4*minthresh)
308995246abbSSean Bruno 		return (notify_count);
309095246abbSSean Bruno 	if (txq->ift_in_use > 2*minthresh)
309195246abbSSean Bruno 		return (notify_count >> 1);
309295246abbSSean Bruno 	if (txq->ift_in_use > minthresh)
309395246abbSSean Bruno 		return (notify_count >> 2);
30942b2fc973SSean Bruno 	return (2);
30954c7070dbSScott Long }
30964c7070dbSScott Long 
30974c7070dbSScott Long #define M_CSUM_FLAGS(m) ((m)->m_pkthdr.csum_flags)
30984c7070dbSScott Long #define M_HAS_VLANTAG(m) (m->m_flags & M_VLANTAG)
309995246abbSSean Bruno 
310095246abbSSean Bruno #define TXQ_MAX_DB_DEFERRED(txq, in_use) txq_max_db_deferred((txq), (in_use))
310195246abbSSean Bruno #define TXQ_MAX_RS_DEFERRED(txq) txq_max_rs_deferred(txq)
310223ac9029SStephen Hurd #define TXQ_MAX_DB_CONSUMED(size) (size >> 4)
31034c7070dbSScott Long 
310495246abbSSean Bruno /* forward compatibility for cxgb */
310595246abbSSean Bruno #define FIRST_QSET(ctx) 0
310695246abbSSean Bruno #define NTXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_ntxqsets)
310795246abbSSean Bruno #define NRXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_nrxqsets)
310895246abbSSean Bruno #define QIDX(ctx, m) ((((m)->m_pkthdr.flowid & ctx->ifc_softc_ctx.isc_rss_table_mask) % NTXQSETS(ctx)) + FIRST_QSET(ctx))
310995246abbSSean Bruno #define DESC_RECLAIMABLE(q) ((int)((q)->ift_processed - (q)->ift_cleaned - (q)->ift_ctx->ifc_softc_ctx.isc_tx_nsegments))
311095246abbSSean Bruno 
311195246abbSSean Bruno /* XXX we should be setting this to something other than zero */
311295246abbSSean Bruno #define RECLAIM_THRESH(ctx) ((ctx)->ifc_sctx->isc_tx_reclaim_thresh)
311381be6552SMatt Macy #define	MAX_TX_DESC(ctx) MAX((ctx)->ifc_softc_ctx.isc_tx_tso_segments_max, \
31147474544bSMarius Strobl     (ctx)->ifc_softc_ctx.isc_tx_nsegments)
311595246abbSSean Bruno 
311695246abbSSean Bruno static inline bool
311781be6552SMatt Macy iflib_txd_db_check(iflib_txq_t txq, int ring)
31184c7070dbSScott Long {
311981be6552SMatt Macy 	if_ctx_t ctx = txq->ift_ctx;
312095246abbSSean Bruno 	qidx_t dbval, max;
31214c7070dbSScott Long 
312281be6552SMatt Macy 	max = TXQ_MAX_DB_DEFERRED(txq, txq->ift_in_use);
312381be6552SMatt Macy 
312481be6552SMatt Macy 	/* force || threshold exceeded || at the edge of the ring */
312581be6552SMatt Macy 	if (ring || (txq->ift_db_pending >= max) || (TXQ_AVAIL(txq) <= MAX_TX_DESC(ctx) + 2)) {
312681be6552SMatt Macy 
312781be6552SMatt Macy 		/*
312881be6552SMatt Macy 		 * 'npending' is used if the card's doorbell is in terms of the number of descriptors
312981be6552SMatt Macy 		 * pending flush (BRCM). 'pidx' is used in cases where the card's doorbeel uses the
313081be6552SMatt Macy 		 * producer index explicitly (INTC).
313181be6552SMatt Macy 		 */
31324c7070dbSScott Long 		dbval = txq->ift_npending ? txq->ift_npending : txq->ift_pidx;
313395dcf343SMarius Strobl 		bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
313495dcf343SMarius Strobl 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
31354c7070dbSScott Long 		ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, dbval);
313681be6552SMatt Macy 
313781be6552SMatt Macy 		/*
313881be6552SMatt Macy 		 * Absent bugs there are zero packets pending so reset pending counts to zero.
313981be6552SMatt Macy 		 */
31404c7070dbSScott Long 		txq->ift_db_pending = txq->ift_npending = 0;
314181be6552SMatt Macy 		return (true);
31424c7070dbSScott Long 	}
314381be6552SMatt Macy 	return (false);
31444c7070dbSScott Long }
31454c7070dbSScott Long 
31464c7070dbSScott Long #ifdef PKT_DEBUG
31474c7070dbSScott Long static void
31484c7070dbSScott Long print_pkt(if_pkt_info_t pi)
31494c7070dbSScott Long {
31504c7070dbSScott Long 	printf("pi len:  %d qsidx: %d nsegs: %d ndescs: %d flags: %x pidx: %d\n",
31514c7070dbSScott Long 	       pi->ipi_len, pi->ipi_qsidx, pi->ipi_nsegs, pi->ipi_ndescs, pi->ipi_flags, pi->ipi_pidx);
31524c7070dbSScott Long 	printf("pi new_pidx: %d csum_flags: %lx tso_segsz: %d mflags: %x vtag: %d\n",
31534c7070dbSScott Long 	       pi->ipi_new_pidx, pi->ipi_csum_flags, pi->ipi_tso_segsz, pi->ipi_mflags, pi->ipi_vtag);
31544c7070dbSScott Long 	printf("pi etype: %d ehdrlen: %d ip_hlen: %d ipproto: %d\n",
31554c7070dbSScott Long 	       pi->ipi_etype, pi->ipi_ehdrlen, pi->ipi_ip_hlen, pi->ipi_ipproto);
31564c7070dbSScott Long }
31574c7070dbSScott Long #endif
31584c7070dbSScott Long 
31594c7070dbSScott Long #define IS_TSO4(pi) ((pi)->ipi_csum_flags & CSUM_IP_TSO)
3160a06424ddSEric Joyner #define IS_TX_OFFLOAD4(pi) ((pi)->ipi_csum_flags & (CSUM_IP_TCP | CSUM_IP_TSO))
31614c7070dbSScott Long #define IS_TSO6(pi) ((pi)->ipi_csum_flags & CSUM_IP6_TSO)
3162a06424ddSEric Joyner #define IS_TX_OFFLOAD6(pi) ((pi)->ipi_csum_flags & (CSUM_IP6_TCP | CSUM_IP6_TSO))
31634c7070dbSScott Long 
31644c7070dbSScott Long static int
31654c7070dbSScott Long iflib_parse_header(iflib_txq_t txq, if_pkt_info_t pi, struct mbuf **mp)
31664c7070dbSScott Long {
3167ab2e3f79SStephen Hurd 	if_shared_ctx_t sctx = txq->ift_ctx->ifc_sctx;
31684c7070dbSScott Long 	struct ether_vlan_header *eh;
3169c9a49a4fSMarius Strobl 	struct mbuf *m;
31704c7070dbSScott Long 
31718b8d9093SMarius Strobl 	m = *mp;
3172ab2e3f79SStephen Hurd 	if ((sctx->isc_flags & IFLIB_NEED_SCRATCH) &&
3173ab2e3f79SStephen Hurd 	    M_WRITABLE(m) == 0) {
3174ab2e3f79SStephen Hurd 		if ((m = m_dup(m, M_NOWAIT)) == NULL) {
3175ab2e3f79SStephen Hurd 			return (ENOMEM);
3176ab2e3f79SStephen Hurd 		} else {
3177ab2e3f79SStephen Hurd 			m_freem(*mp);
317864e6fc13SStephen Hurd 			DBG_COUNTER_INC(tx_frees);
31798b8d9093SMarius Strobl 			*mp = m;
3180ab2e3f79SStephen Hurd 		}
3181ab2e3f79SStephen Hurd 	}
31821248952aSSean Bruno 
31834c7070dbSScott Long 	/*
31844c7070dbSScott Long 	 * Determine where frame payload starts.
31854c7070dbSScott Long 	 * Jump over vlan headers if already present,
31864c7070dbSScott Long 	 * helpful for QinQ too.
31874c7070dbSScott Long 	 */
31884c7070dbSScott Long 	if (__predict_false(m->m_len < sizeof(*eh))) {
31894c7070dbSScott Long 		txq->ift_pullups++;
31904c7070dbSScott Long 		if (__predict_false((m = m_pullup(m, sizeof(*eh))) == NULL))
31914c7070dbSScott Long 			return (ENOMEM);
31924c7070dbSScott Long 	}
31934c7070dbSScott Long 	eh = mtod(m, struct ether_vlan_header *);
31944c7070dbSScott Long 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
31954c7070dbSScott Long 		pi->ipi_etype = ntohs(eh->evl_proto);
31964c7070dbSScott Long 		pi->ipi_ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
31974c7070dbSScott Long 	} else {
31984c7070dbSScott Long 		pi->ipi_etype = ntohs(eh->evl_encap_proto);
31994c7070dbSScott Long 		pi->ipi_ehdrlen = ETHER_HDR_LEN;
32004c7070dbSScott Long 	}
32014c7070dbSScott Long 
32024c7070dbSScott Long 	switch (pi->ipi_etype) {
32034c7070dbSScott Long #ifdef INET
32044c7070dbSScott Long 	case ETHERTYPE_IP:
32054c7070dbSScott Long 	{
3206c9a49a4fSMarius Strobl 		struct mbuf *n;
32074c7070dbSScott Long 		struct ip *ip = NULL;
32084c7070dbSScott Long 		struct tcphdr *th = NULL;
32094c7070dbSScott Long 		int minthlen;
32104c7070dbSScott Long 
32114c7070dbSScott Long 		minthlen = min(m->m_pkthdr.len, pi->ipi_ehdrlen + sizeof(*ip) + sizeof(*th));
32124c7070dbSScott Long 		if (__predict_false(m->m_len < minthlen)) {
32134c7070dbSScott Long 			/*
32144c7070dbSScott Long 			 * if this code bloat is causing too much of a hit
32154c7070dbSScott Long 			 * move it to a separate function and mark it noinline
32164c7070dbSScott Long 			 */
32174c7070dbSScott Long 			if (m->m_len == pi->ipi_ehdrlen) {
32184c7070dbSScott Long 				n = m->m_next;
32194c7070dbSScott Long 				MPASS(n);
32204c7070dbSScott Long 				if (n->m_len >= sizeof(*ip))  {
32214c7070dbSScott Long 					ip = (struct ip *)n->m_data;
32224c7070dbSScott Long 					if (n->m_len >= (ip->ip_hl << 2) + sizeof(*th))
32234c7070dbSScott Long 						th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
32244c7070dbSScott Long 				} else {
32254c7070dbSScott Long 					txq->ift_pullups++;
32264c7070dbSScott Long 					if (__predict_false((m = m_pullup(m, minthlen)) == NULL))
32274c7070dbSScott Long 						return (ENOMEM);
32284c7070dbSScott Long 					ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
32294c7070dbSScott Long 				}
32304c7070dbSScott Long 			} else {
32314c7070dbSScott Long 				txq->ift_pullups++;
32324c7070dbSScott Long 				if (__predict_false((m = m_pullup(m, minthlen)) == NULL))
32334c7070dbSScott Long 					return (ENOMEM);
32344c7070dbSScott Long 				ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
32354c7070dbSScott Long 				if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th))
32364c7070dbSScott Long 					th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
32374c7070dbSScott Long 			}
32384c7070dbSScott Long 		} else {
32394c7070dbSScott Long 			ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen);
32404c7070dbSScott Long 			if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th))
32414c7070dbSScott Long 				th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
32424c7070dbSScott Long 		}
32434c7070dbSScott Long 		pi->ipi_ip_hlen = ip->ip_hl << 2;
32444c7070dbSScott Long 		pi->ipi_ipproto = ip->ip_p;
32454c7070dbSScott Long 		pi->ipi_flags |= IPI_TX_IPV4;
32464c7070dbSScott Long 
3247a06424ddSEric Joyner 		/* TCP checksum offload may require TCP header length */
3248a06424ddSEric Joyner 		if (IS_TX_OFFLOAD4(pi)) {
3249a06424ddSEric Joyner 			if (__predict_true(pi->ipi_ipproto == IPPROTO_TCP)) {
32504c7070dbSScott Long 				if (__predict_false(th == NULL)) {
32514c7070dbSScott Long 					txq->ift_pullups++;
32524c7070dbSScott Long 					if (__predict_false((m = m_pullup(m, (ip->ip_hl << 2) + sizeof(*th))) == NULL))
32534c7070dbSScott Long 						return (ENOMEM);
32544c7070dbSScott Long 					th = (struct tcphdr *)((caddr_t)ip + pi->ipi_ip_hlen);
32554c7070dbSScott Long 				}
32564c7070dbSScott Long 				pi->ipi_tcp_hflags = th->th_flags;
32574c7070dbSScott Long 				pi->ipi_tcp_hlen = th->th_off << 2;
32584c7070dbSScott Long 				pi->ipi_tcp_seq = th->th_seq;
32594c7070dbSScott Long 			}
3260a06424ddSEric Joyner 			if (IS_TSO4(pi)) {
32614c7070dbSScott Long 				if (__predict_false(ip->ip_p != IPPROTO_TCP))
32624c7070dbSScott Long 					return (ENXIO);
32638d4ceb9cSStephen Hurd 				/*
32648d4ceb9cSStephen Hurd 				 * TSO always requires hardware checksum offload.
32658d4ceb9cSStephen Hurd 				 */
32668d4ceb9cSStephen Hurd 				pi->ipi_csum_flags |= (CSUM_IP_TCP | CSUM_IP);
32674c7070dbSScott Long 				th->th_sum = in_pseudo(ip->ip_src.s_addr,
32684c7070dbSScott Long 						       ip->ip_dst.s_addr, htons(IPPROTO_TCP));
32694c7070dbSScott Long 				pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz;
32701248952aSSean Bruno 				if (sctx->isc_flags & IFLIB_TSO_INIT_IP) {
32711248952aSSean Bruno 					ip->ip_sum = 0;
32721248952aSSean Bruno 					ip->ip_len = htons(pi->ipi_ip_hlen + pi->ipi_tcp_hlen + pi->ipi_tso_segsz);
32731248952aSSean Bruno 				}
32744c7070dbSScott Long 			}
3275a06424ddSEric Joyner 		}
32768d4ceb9cSStephen Hurd 		if ((sctx->isc_flags & IFLIB_NEED_ZERO_CSUM) && (pi->ipi_csum_flags & CSUM_IP))
32778d4ceb9cSStephen Hurd                        ip->ip_sum = 0;
32788d4ceb9cSStephen Hurd 
32794c7070dbSScott Long 		break;
32804c7070dbSScott Long 	}
32814c7070dbSScott Long #endif
32824c7070dbSScott Long #ifdef INET6
32834c7070dbSScott Long 	case ETHERTYPE_IPV6:
32844c7070dbSScott Long 	{
32854c7070dbSScott Long 		struct ip6_hdr *ip6 = (struct ip6_hdr *)(m->m_data + pi->ipi_ehdrlen);
32864c7070dbSScott Long 		struct tcphdr *th;
32874c7070dbSScott Long 		pi->ipi_ip_hlen = sizeof(struct ip6_hdr);
32884c7070dbSScott Long 
32894c7070dbSScott Long 		if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) {
329064e6fc13SStephen Hurd 			txq->ift_pullups++;
32914c7070dbSScott Long 			if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) == NULL))
32924c7070dbSScott Long 				return (ENOMEM);
32934c7070dbSScott Long 		}
32944c7070dbSScott Long 		th = (struct tcphdr *)((caddr_t)ip6 + pi->ipi_ip_hlen);
32954c7070dbSScott Long 
32964c7070dbSScott Long 		/* XXX-BZ this will go badly in case of ext hdrs. */
32974c7070dbSScott Long 		pi->ipi_ipproto = ip6->ip6_nxt;
32984c7070dbSScott Long 		pi->ipi_flags |= IPI_TX_IPV6;
32994c7070dbSScott Long 
3300a06424ddSEric Joyner 		/* TCP checksum offload may require TCP header length */
3301a06424ddSEric Joyner 		if (IS_TX_OFFLOAD6(pi)) {
33024c7070dbSScott Long 			if (pi->ipi_ipproto == IPPROTO_TCP) {
33034c7070dbSScott Long 				if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) {
3304a06424ddSEric Joyner 					txq->ift_pullups++;
33054c7070dbSScott Long 					if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) == NULL))
33064c7070dbSScott Long 						return (ENOMEM);
33074c7070dbSScott Long 				}
33084c7070dbSScott Long 				pi->ipi_tcp_hflags = th->th_flags;
33094c7070dbSScott Long 				pi->ipi_tcp_hlen = th->th_off << 2;
3310a06424ddSEric Joyner 				pi->ipi_tcp_seq = th->th_seq;
33114c7070dbSScott Long 			}
3312a06424ddSEric Joyner 			if (IS_TSO6(pi)) {
33134c7070dbSScott Long 				if (__predict_false(ip6->ip6_nxt != IPPROTO_TCP))
33144c7070dbSScott Long 					return (ENXIO);
33154c7070dbSScott Long 				/*
33168d4ceb9cSStephen Hurd 				 * TSO always requires hardware checksum offload.
33174c7070dbSScott Long 				 */
3318a06424ddSEric Joyner 				pi->ipi_csum_flags |= CSUM_IP6_TCP;
33194c7070dbSScott Long 				th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
33204c7070dbSScott Long 				pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz;
33214c7070dbSScott Long 			}
3322a06424ddSEric Joyner 		}
33234c7070dbSScott Long 		break;
33244c7070dbSScott Long 	}
33254c7070dbSScott Long #endif
33264c7070dbSScott Long 	default:
33274c7070dbSScott Long 		pi->ipi_csum_flags &= ~CSUM_OFFLOAD;
33284c7070dbSScott Long 		pi->ipi_ip_hlen = 0;
33294c7070dbSScott Long 		break;
33304c7070dbSScott Long 	}
33314c7070dbSScott Long 	*mp = m;
33321248952aSSean Bruno 
33334c7070dbSScott Long 	return (0);
33344c7070dbSScott Long }
33354c7070dbSScott Long 
33364c7070dbSScott Long /*
33374c7070dbSScott Long  * If dodgy hardware rejects the scatter gather chain we've handed it
333823ac9029SStephen Hurd  * we'll need to remove the mbuf chain from ifsg_m[] before we can add the
333923ac9029SStephen Hurd  * m_defrag'd mbufs
33404c7070dbSScott Long  */
33414c7070dbSScott Long static __noinline struct mbuf *
334223ac9029SStephen Hurd iflib_remove_mbuf(iflib_txq_t txq)
33434c7070dbSScott Long {
3344fbec776dSAndrew Gallatin 	int ntxd, pidx;
3345fbec776dSAndrew Gallatin 	struct mbuf *m, **ifsd_m;
33464c7070dbSScott Long 
33474c7070dbSScott Long 	ifsd_m = txq->ift_sds.ifsd_m;
334823ac9029SStephen Hurd 	ntxd = txq->ift_size;
3349fbec776dSAndrew Gallatin 	pidx = txq->ift_pidx & (ntxd - 1);
3350fbec776dSAndrew Gallatin 	ifsd_m = txq->ift_sds.ifsd_m;
3351fbec776dSAndrew Gallatin 	m = ifsd_m[pidx];
33524c7070dbSScott Long 	ifsd_m[pidx] = NULL;
3353bfce461eSMarius Strobl 	bus_dmamap_unload(txq->ift_buf_tag, txq->ift_sds.ifsd_map[pidx]);
33548a04b53dSKonstantin Belousov 	if (txq->ift_sds.ifsd_tso_map != NULL)
3355bfce461eSMarius Strobl 		bus_dmamap_unload(txq->ift_tso_buf_tag,
33568a04b53dSKonstantin Belousov 		    txq->ift_sds.ifsd_tso_map[pidx]);
33574c7070dbSScott Long #if MEMORY_LOGGING
33584c7070dbSScott Long 	txq->ift_dequeued++;
33594c7070dbSScott Long #endif
3360fbec776dSAndrew Gallatin 	return (m);
33614c7070dbSScott Long }
33624c7070dbSScott Long 
336395246abbSSean Bruno static inline caddr_t
336495246abbSSean Bruno calc_next_txd(iflib_txq_t txq, int cidx, uint8_t qid)
336595246abbSSean Bruno {
336695246abbSSean Bruno 	qidx_t size;
336795246abbSSean Bruno 	int ntxd;
336895246abbSSean Bruno 	caddr_t start, end, cur, next;
336995246abbSSean Bruno 
337095246abbSSean Bruno 	ntxd = txq->ift_size;
337195246abbSSean Bruno 	size = txq->ift_txd_size[qid];
337295246abbSSean Bruno 	start = txq->ift_ifdi[qid].idi_vaddr;
337395246abbSSean Bruno 
337495246abbSSean Bruno 	if (__predict_false(size == 0))
337595246abbSSean Bruno 		return (start);
337695246abbSSean Bruno 	cur = start + size*cidx;
337795246abbSSean Bruno 	end = start + size*ntxd;
337895246abbSSean Bruno 	next = CACHE_PTR_NEXT(cur);
337995246abbSSean Bruno 	return (next < end ? next : start);
338095246abbSSean Bruno }
338195246abbSSean Bruno 
3382d14c853bSStephen Hurd /*
3383d14c853bSStephen Hurd  * Pad an mbuf to ensure a minimum ethernet frame size.
3384d14c853bSStephen Hurd  * min_frame_size is the frame size (less CRC) to pad the mbuf to
3385d14c853bSStephen Hurd  */
3386d14c853bSStephen Hurd static __noinline int
3387a15fbbb8SStephen Hurd iflib_ether_pad(device_t dev, struct mbuf **m_head, uint16_t min_frame_size)
3388d14c853bSStephen Hurd {
3389d14c853bSStephen Hurd 	/*
3390d14c853bSStephen Hurd 	 * 18 is enough bytes to pad an ARP packet to 46 bytes, and
3391d14c853bSStephen Hurd 	 * and ARP message is the smallest common payload I can think of
3392d14c853bSStephen Hurd 	 */
3393d14c853bSStephen Hurd 	static char pad[18];	/* just zeros */
3394d14c853bSStephen Hurd 	int n;
3395a15fbbb8SStephen Hurd 	struct mbuf *new_head;
3396d14c853bSStephen Hurd 
3397a15fbbb8SStephen Hurd 	if (!M_WRITABLE(*m_head)) {
3398a15fbbb8SStephen Hurd 		new_head = m_dup(*m_head, M_NOWAIT);
3399a15fbbb8SStephen Hurd 		if (new_head == NULL) {
340004993890SStephen Hurd 			m_freem(*m_head);
3401a15fbbb8SStephen Hurd 			device_printf(dev, "cannot pad short frame, m_dup() failed");
340206c47d48SStephen Hurd 			DBG_COUNTER_INC(encap_pad_mbuf_fail);
340364e6fc13SStephen Hurd 			DBG_COUNTER_INC(tx_frees);
3404a15fbbb8SStephen Hurd 			return ENOMEM;
3405a15fbbb8SStephen Hurd 		}
3406a15fbbb8SStephen Hurd 		m_freem(*m_head);
3407a15fbbb8SStephen Hurd 		*m_head = new_head;
3408a15fbbb8SStephen Hurd 	}
3409a15fbbb8SStephen Hurd 
3410a15fbbb8SStephen Hurd 	for (n = min_frame_size - (*m_head)->m_pkthdr.len;
3411d14c853bSStephen Hurd 	     n > 0; n -= sizeof(pad))
3412a15fbbb8SStephen Hurd 		if (!m_append(*m_head, min(n, sizeof(pad)), pad))
3413d14c853bSStephen Hurd 			break;
3414d14c853bSStephen Hurd 
3415d14c853bSStephen Hurd 	if (n > 0) {
3416a15fbbb8SStephen Hurd 		m_freem(*m_head);
3417d14c853bSStephen Hurd 		device_printf(dev, "cannot pad short frame\n");
3418d14c853bSStephen Hurd 		DBG_COUNTER_INC(encap_pad_mbuf_fail);
341964e6fc13SStephen Hurd 		DBG_COUNTER_INC(tx_frees);
3420d14c853bSStephen Hurd 		return (ENOBUFS);
3421d14c853bSStephen Hurd 	}
3422d14c853bSStephen Hurd 
3423d14c853bSStephen Hurd 	return 0;
3424d14c853bSStephen Hurd }
3425d14c853bSStephen Hurd 
34264c7070dbSScott Long static int
34274c7070dbSScott Long iflib_encap(iflib_txq_t txq, struct mbuf **m_headp)
34284c7070dbSScott Long {
34294c7070dbSScott Long 	if_ctx_t		ctx;
34304c7070dbSScott Long 	if_shared_ctx_t		sctx;
34314c7070dbSScott Long 	if_softc_ctx_t		scctx;
3432bfce461eSMarius Strobl 	bus_dma_tag_t		buf_tag;
34334c7070dbSScott Long 	bus_dma_segment_t	*segs;
3434fbec776dSAndrew Gallatin 	struct mbuf		*m_head, **ifsd_m;
343595246abbSSean Bruno 	void			*next_txd;
34364c7070dbSScott Long 	bus_dmamap_t		map;
34374c7070dbSScott Long 	struct if_pkt_info	pi;
34384c7070dbSScott Long 	int remap = 0;
34394c7070dbSScott Long 	int err, nsegs, ndesc, max_segs, pidx, cidx, next, ntxd;
34404c7070dbSScott Long 
34414c7070dbSScott Long 	ctx = txq->ift_ctx;
34424c7070dbSScott Long 	sctx = ctx->ifc_sctx;
34434c7070dbSScott Long 	scctx = &ctx->ifc_softc_ctx;
34444c7070dbSScott Long 	segs = txq->ift_segs;
344523ac9029SStephen Hurd 	ntxd = txq->ift_size;
34464c7070dbSScott Long 	m_head = *m_headp;
34474c7070dbSScott Long 	map = NULL;
34484c7070dbSScott Long 
34494c7070dbSScott Long 	/*
34504c7070dbSScott Long 	 * If we're doing TSO the next descriptor to clean may be quite far ahead
34514c7070dbSScott Long 	 */
34524c7070dbSScott Long 	cidx = txq->ift_cidx;
34534c7070dbSScott Long 	pidx = txq->ift_pidx;
345495246abbSSean Bruno 	if (ctx->ifc_flags & IFC_PREFETCH) {
34554c7070dbSScott Long 		next = (cidx + CACHE_PTR_INCREMENT) & (ntxd-1);
345695246abbSSean Bruno 		if (!(ctx->ifc_flags & IFLIB_HAS_TXCQ)) {
345795246abbSSean Bruno 			next_txd = calc_next_txd(txq, cidx, 0);
345895246abbSSean Bruno 			prefetch(next_txd);
345995246abbSSean Bruno 		}
34604c7070dbSScott Long 
34614c7070dbSScott Long 		/* prefetch the next cache line of mbuf pointers and flags */
34624c7070dbSScott Long 		prefetch(&txq->ift_sds.ifsd_m[next]);
34634c7070dbSScott Long 		prefetch(&txq->ift_sds.ifsd_map[next]);
34644c7070dbSScott Long 		next = (cidx + CACHE_LINE_SIZE) & (ntxd-1);
34654c7070dbSScott Long 	}
346695246abbSSean Bruno 	map = txq->ift_sds.ifsd_map[pidx];
3467fbec776dSAndrew Gallatin 	ifsd_m = txq->ift_sds.ifsd_m;
34684c7070dbSScott Long 
34694c7070dbSScott Long 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
3470bfce461eSMarius Strobl 		buf_tag = txq->ift_tso_buf_tag;
34714c7070dbSScott Long 		max_segs = scctx->isc_tx_tso_segments_max;
34728a04b53dSKonstantin Belousov 		map = txq->ift_sds.ifsd_tso_map[pidx];
3473bfce461eSMarius Strobl 		MPASS(buf_tag != NULL);
34747f87c040SMarius Strobl 		MPASS(max_segs > 0);
34754c7070dbSScott Long 	} else {
3476bfce461eSMarius Strobl 		buf_tag = txq->ift_buf_tag;
34774c7070dbSScott Long 		max_segs = scctx->isc_tx_nsegments;
34788a04b53dSKonstantin Belousov 		map = txq->ift_sds.ifsd_map[pidx];
34794c7070dbSScott Long 	}
3480d14c853bSStephen Hurd 	if ((sctx->isc_flags & IFLIB_NEED_ETHER_PAD) &&
3481d14c853bSStephen Hurd 	    __predict_false(m_head->m_pkthdr.len < scctx->isc_min_frame_size)) {
3482a15fbbb8SStephen Hurd 		err = iflib_ether_pad(ctx->ifc_dev, m_headp, scctx->isc_min_frame_size);
348364e6fc13SStephen Hurd 		if (err) {
348464e6fc13SStephen Hurd 			DBG_COUNTER_INC(encap_txd_encap_fail);
3485d14c853bSStephen Hurd 			return err;
3486d14c853bSStephen Hurd 		}
348764e6fc13SStephen Hurd 	}
3488a15fbbb8SStephen Hurd 	m_head = *m_headp;
348995246abbSSean Bruno 
349095246abbSSean Bruno 	pkt_info_zero(&pi);
3491ab2e3f79SStephen Hurd 	pi.ipi_mflags = (m_head->m_flags & (M_VLANTAG|M_BCAST|M_MCAST));
3492ab2e3f79SStephen Hurd 	pi.ipi_pidx = pidx;
3493ab2e3f79SStephen Hurd 	pi.ipi_qsidx = txq->ift_id;
34943429c02fSStephen Hurd 	pi.ipi_len = m_head->m_pkthdr.len;
34953429c02fSStephen Hurd 	pi.ipi_csum_flags = m_head->m_pkthdr.csum_flags;
34961722eeacSMarius Strobl 	pi.ipi_vtag = M_HAS_VLANTAG(m_head) ? m_head->m_pkthdr.ether_vtag : 0;
34974c7070dbSScott Long 
34984c7070dbSScott Long 	/* deliberate bitwise OR to make one condition */
34994c7070dbSScott Long 	if (__predict_true((pi.ipi_csum_flags | pi.ipi_vtag))) {
350064e6fc13SStephen Hurd 		if (__predict_false((err = iflib_parse_header(txq, &pi, m_headp)) != 0)) {
350164e6fc13SStephen Hurd 			DBG_COUNTER_INC(encap_txd_encap_fail);
35024c7070dbSScott Long 			return (err);
350364e6fc13SStephen Hurd 		}
35044c7070dbSScott Long 		m_head = *m_headp;
35054c7070dbSScott Long 	}
35064c7070dbSScott Long 
35074c7070dbSScott Long retry:
3508bfce461eSMarius Strobl 	err = bus_dmamap_load_mbuf_sg(buf_tag, map, m_head, segs, &nsegs,
3509fbec776dSAndrew Gallatin 	    BUS_DMA_NOWAIT);
35104c7070dbSScott Long defrag:
35114c7070dbSScott Long 	if (__predict_false(err)) {
35124c7070dbSScott Long 		switch (err) {
35134c7070dbSScott Long 		case EFBIG:
35144c7070dbSScott Long 			/* try collapse once and defrag once */
3515f7594707SAndrew Gallatin 			if (remap == 0) {
35164c7070dbSScott Long 				m_head = m_collapse(*m_headp, M_NOWAIT, max_segs);
3517f7594707SAndrew Gallatin 				/* try defrag if collapsing fails */
3518f7594707SAndrew Gallatin 				if (m_head == NULL)
3519f7594707SAndrew Gallatin 					remap++;
3520f7594707SAndrew Gallatin 			}
352164e6fc13SStephen Hurd 			if (remap == 1) {
352264e6fc13SStephen Hurd 				txq->ift_mbuf_defrag++;
35234c7070dbSScott Long 				m_head = m_defrag(*m_headp, M_NOWAIT);
352464e6fc13SStephen Hurd 			}
35253e8d1baeSEric Joyner 			/*
35263e8d1baeSEric Joyner 			 * remap should never be >1 unless bus_dmamap_load_mbuf_sg
35273e8d1baeSEric Joyner 			 * failed to map an mbuf that was run through m_defrag
35283e8d1baeSEric Joyner 			 */
35293e8d1baeSEric Joyner 			MPASS(remap <= 1);
35303e8d1baeSEric Joyner 			if (__predict_false(m_head == NULL || remap > 1))
35314c7070dbSScott Long 				goto defrag_failed;
35323e8d1baeSEric Joyner 			remap++;
35334c7070dbSScott Long 			*m_headp = m_head;
35344c7070dbSScott Long 			goto retry;
35354c7070dbSScott Long 			break;
35364c7070dbSScott Long 		case ENOMEM:
35374c7070dbSScott Long 			txq->ift_no_tx_dma_setup++;
35384c7070dbSScott Long 			break;
35394c7070dbSScott Long 		default:
35404c7070dbSScott Long 			txq->ift_no_tx_dma_setup++;
35414c7070dbSScott Long 			m_freem(*m_headp);
35424c7070dbSScott Long 			DBG_COUNTER_INC(tx_frees);
35434c7070dbSScott Long 			*m_headp = NULL;
35444c7070dbSScott Long 			break;
35454c7070dbSScott Long 		}
35464c7070dbSScott Long 		txq->ift_map_failed++;
35474c7070dbSScott Long 		DBG_COUNTER_INC(encap_load_mbuf_fail);
354864e6fc13SStephen Hurd 		DBG_COUNTER_INC(encap_txd_encap_fail);
35494c7070dbSScott Long 		return (err);
35504c7070dbSScott Long 	}
3551fbec776dSAndrew Gallatin 	ifsd_m[pidx] = m_head;
35524c7070dbSScott Long 	/*
35534c7070dbSScott Long 	 * XXX assumes a 1 to 1 relationship between segments and
35544c7070dbSScott Long 	 *        descriptors - this does not hold true on all drivers, e.g.
35554c7070dbSScott Long 	 *        cxgb
35564c7070dbSScott Long 	 */
35574c7070dbSScott Long 	if (__predict_false(nsegs + 2 > TXQ_AVAIL(txq))) {
35584c7070dbSScott Long 		txq->ift_no_desc_avail++;
3559bfce461eSMarius Strobl 		bus_dmamap_unload(buf_tag, map);
35604c7070dbSScott Long 		DBG_COUNTER_INC(encap_txq_avail_fail);
356164e6fc13SStephen Hurd 		DBG_COUNTER_INC(encap_txd_encap_fail);
356223ac9029SStephen Hurd 		if ((txq->ift_task.gt_task.ta_flags & TASK_ENQUEUED) == 0)
35634c7070dbSScott Long 			GROUPTASK_ENQUEUE(&txq->ift_task);
35644c7070dbSScott Long 		return (ENOBUFS);
35654c7070dbSScott Long 	}
356695246abbSSean Bruno 	/*
356795246abbSSean Bruno 	 * On Intel cards we can greatly reduce the number of TX interrupts
356895246abbSSean Bruno 	 * we see by only setting report status on every Nth descriptor.
356995246abbSSean Bruno 	 * However, this also means that the driver will need to keep track
357095246abbSSean Bruno 	 * of the descriptors that RS was set on to check them for the DD bit.
357195246abbSSean Bruno 	 */
357295246abbSSean Bruno 	txq->ift_rs_pending += nsegs + 1;
357395246abbSSean Bruno 	if (txq->ift_rs_pending > TXQ_MAX_RS_DEFERRED(txq) ||
35741f7ce05dSAndrew Gallatin 	     iflib_no_tx_batch || (TXQ_AVAIL(txq) - nsegs) <= MAX_TX_DESC(ctx) + 2) {
357595246abbSSean Bruno 		pi.ipi_flags |= IPI_TX_INTR;
357695246abbSSean Bruno 		txq->ift_rs_pending = 0;
357795246abbSSean Bruno 	}
357895246abbSSean Bruno 
35794c7070dbSScott Long 	pi.ipi_segs = segs;
35804c7070dbSScott Long 	pi.ipi_nsegs = nsegs;
35814c7070dbSScott Long 
358223ac9029SStephen Hurd 	MPASS(pidx >= 0 && pidx < txq->ift_size);
35834c7070dbSScott Long #ifdef PKT_DEBUG
35844c7070dbSScott Long 	print_pkt(&pi);
35854c7070dbSScott Long #endif
35864c7070dbSScott Long 	if ((err = ctx->isc_txd_encap(ctx->ifc_softc, &pi)) == 0) {
358795dcf343SMarius Strobl 		bus_dmamap_sync(buf_tag, map, BUS_DMASYNC_PREWRITE);
35884c7070dbSScott Long 		DBG_COUNTER_INC(tx_encap);
358995246abbSSean Bruno 		MPASS(pi.ipi_new_pidx < txq->ift_size);
35904c7070dbSScott Long 
35914c7070dbSScott Long 		ndesc = pi.ipi_new_pidx - pi.ipi_pidx;
35924c7070dbSScott Long 		if (pi.ipi_new_pidx < pi.ipi_pidx) {
359323ac9029SStephen Hurd 			ndesc += txq->ift_size;
35944c7070dbSScott Long 			txq->ift_gen = 1;
35954c7070dbSScott Long 		}
35961248952aSSean Bruno 		/*
35971248952aSSean Bruno 		 * drivers can need as many as
35981248952aSSean Bruno 		 * two sentinels
35991248952aSSean Bruno 		 */
36001248952aSSean Bruno 		MPASS(ndesc <= pi.ipi_nsegs + 2);
36014c7070dbSScott Long 		MPASS(pi.ipi_new_pidx != pidx);
36024c7070dbSScott Long 		MPASS(ndesc > 0);
36034c7070dbSScott Long 		txq->ift_in_use += ndesc;
360481be6552SMatt Macy 		txq->ift_db_pending += ndesc;
360595246abbSSean Bruno 
36064c7070dbSScott Long 		/*
36074c7070dbSScott Long 		 * We update the last software descriptor again here because there may
36084c7070dbSScott Long 		 * be a sentinel and/or there may be more mbufs than segments
36094c7070dbSScott Long 		 */
36104c7070dbSScott Long 		txq->ift_pidx = pi.ipi_new_pidx;
36114c7070dbSScott Long 		txq->ift_npending += pi.ipi_ndescs;
3612f7594707SAndrew Gallatin 	} else {
361323ac9029SStephen Hurd 		*m_headp = m_head = iflib_remove_mbuf(txq);
3614f7594707SAndrew Gallatin 		if (err == EFBIG) {
36154c7070dbSScott Long 			txq->ift_txd_encap_efbig++;
3616f7594707SAndrew Gallatin 			if (remap < 2) {
3617f7594707SAndrew Gallatin 				remap = 1;
36184c7070dbSScott Long 				goto defrag;
3619f7594707SAndrew Gallatin 			}
3620f7594707SAndrew Gallatin 		}
3621f7594707SAndrew Gallatin 		goto defrag_failed;
3622f7594707SAndrew Gallatin 	}
362364e6fc13SStephen Hurd 	/*
362464e6fc13SStephen Hurd 	 * err can't possibly be non-zero here, so we don't neet to test it
362564e6fc13SStephen Hurd 	 * to see if we need to DBG_COUNTER_INC(encap_txd_encap_fail).
362664e6fc13SStephen Hurd 	 */
36274c7070dbSScott Long 	return (err);
36284c7070dbSScott Long 
36294c7070dbSScott Long defrag_failed:
36304c7070dbSScott Long 	txq->ift_mbuf_defrag_failed++;
36314c7070dbSScott Long 	txq->ift_map_failed++;
36324c7070dbSScott Long 	m_freem(*m_headp);
36334c7070dbSScott Long 	DBG_COUNTER_INC(tx_frees);
36344c7070dbSScott Long 	*m_headp = NULL;
363564e6fc13SStephen Hurd 	DBG_COUNTER_INC(encap_txd_encap_fail);
36364c7070dbSScott Long 	return (ENOMEM);
36374c7070dbSScott Long }
36384c7070dbSScott Long 
36394c7070dbSScott Long static void
36404c7070dbSScott Long iflib_tx_desc_free(iflib_txq_t txq, int n)
36414c7070dbSScott Long {
36424c7070dbSScott Long 	uint32_t qsize, cidx, mask, gen;
36434c7070dbSScott Long 	struct mbuf *m, **ifsd_m;
364495246abbSSean Bruno 	bool do_prefetch;
36454c7070dbSScott Long 
36464c7070dbSScott Long 	cidx = txq->ift_cidx;
36474c7070dbSScott Long 	gen = txq->ift_gen;
364823ac9029SStephen Hurd 	qsize = txq->ift_size;
36494c7070dbSScott Long 	mask = qsize-1;
36504c7070dbSScott Long 	ifsd_m = txq->ift_sds.ifsd_m;
365195246abbSSean Bruno 	do_prefetch = (txq->ift_ctx->ifc_flags & IFC_PREFETCH);
36524c7070dbSScott Long 
365394618825SMark Johnston 	while (n-- > 0) {
365495246abbSSean Bruno 		if (do_prefetch) {
36554c7070dbSScott Long 			prefetch(ifsd_m[(cidx + 3) & mask]);
36564c7070dbSScott Long 			prefetch(ifsd_m[(cidx + 4) & mask]);
365795246abbSSean Bruno 		}
36584c7070dbSScott Long 		if ((m = ifsd_m[cidx]) != NULL) {
3659fbec776dSAndrew Gallatin 			prefetch(&ifsd_m[(cidx + CACHE_PTR_INCREMENT) & mask]);
36608a04b53dSKonstantin Belousov 			if (m->m_pkthdr.csum_flags & CSUM_TSO) {
3661bfce461eSMarius Strobl 				bus_dmamap_sync(txq->ift_tso_buf_tag,
36628a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_tso_map[cidx],
36638a04b53dSKonstantin Belousov 				    BUS_DMASYNC_POSTWRITE);
3664bfce461eSMarius Strobl 				bus_dmamap_unload(txq->ift_tso_buf_tag,
36658a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_tso_map[cidx]);
36668a04b53dSKonstantin Belousov 			} else {
3667bfce461eSMarius Strobl 				bus_dmamap_sync(txq->ift_buf_tag,
36688a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_map[cidx],
36698a04b53dSKonstantin Belousov 				    BUS_DMASYNC_POSTWRITE);
3670bfce461eSMarius Strobl 				bus_dmamap_unload(txq->ift_buf_tag,
36718a04b53dSKonstantin Belousov 				    txq->ift_sds.ifsd_map[cidx]);
36728a04b53dSKonstantin Belousov 			}
36734c7070dbSScott Long 			/* XXX we don't support any drivers that batch packets yet */
36744c7070dbSScott Long 			MPASS(m->m_nextpkt == NULL);
36755c5ca36cSSean Bruno 			m_freem(m);
36764c7070dbSScott Long 			ifsd_m[cidx] = NULL;
36774c7070dbSScott Long #if MEMORY_LOGGING
36784c7070dbSScott Long 			txq->ift_dequeued++;
36794c7070dbSScott Long #endif
36804c7070dbSScott Long 			DBG_COUNTER_INC(tx_frees);
36814c7070dbSScott Long 		}
36824c7070dbSScott Long 		if (__predict_false(++cidx == qsize)) {
36834c7070dbSScott Long 			cidx = 0;
36844c7070dbSScott Long 			gen = 0;
36854c7070dbSScott Long 		}
36864c7070dbSScott Long 	}
36874c7070dbSScott Long 	txq->ift_cidx = cidx;
36884c7070dbSScott Long 	txq->ift_gen = gen;
36894c7070dbSScott Long }
36904c7070dbSScott Long 
36914c7070dbSScott Long static __inline int
36924c7070dbSScott Long iflib_completed_tx_reclaim(iflib_txq_t txq, int thresh)
36934c7070dbSScott Long {
36944c7070dbSScott Long 	int reclaim;
36954c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
36964c7070dbSScott Long 
36974c7070dbSScott Long 	KASSERT(thresh >= 0, ("invalid threshold to reclaim"));
36984c7070dbSScott Long 	MPASS(thresh /*+ MAX_TX_DESC(txq->ift_ctx) */ < txq->ift_size);
36994c7070dbSScott Long 
37004c7070dbSScott Long 	/*
37014c7070dbSScott Long 	 * Need a rate-limiting check so that this isn't called every time
37024c7070dbSScott Long 	 */
37034c7070dbSScott Long 	iflib_tx_credits_update(ctx, txq);
37044c7070dbSScott Long 	reclaim = DESC_RECLAIMABLE(txq);
37054c7070dbSScott Long 
37064c7070dbSScott Long 	if (reclaim <= thresh /* + MAX_TX_DESC(txq->ift_ctx) */) {
37074c7070dbSScott Long #ifdef INVARIANTS
37084c7070dbSScott Long 		if (iflib_verbose_debug) {
37094c7070dbSScott Long 			printf("%s processed=%ju cleaned=%ju tx_nsegments=%d reclaim=%d thresh=%d\n", __FUNCTION__,
37104c7070dbSScott Long 			       txq->ift_processed, txq->ift_cleaned, txq->ift_ctx->ifc_softc_ctx.isc_tx_nsegments,
37114c7070dbSScott Long 			       reclaim, thresh);
37124c7070dbSScott Long 		}
37134c7070dbSScott Long #endif
37144c7070dbSScott Long 		return (0);
37154c7070dbSScott Long 	}
37164c7070dbSScott Long 	iflib_tx_desc_free(txq, reclaim);
37174c7070dbSScott Long 	txq->ift_cleaned += reclaim;
37184c7070dbSScott Long 	txq->ift_in_use -= reclaim;
37194c7070dbSScott Long 
37204c7070dbSScott Long 	return (reclaim);
37214c7070dbSScott Long }
37224c7070dbSScott Long 
37234c7070dbSScott Long static struct mbuf **
372495246abbSSean Bruno _ring_peek_one(struct ifmp_ring *r, int cidx, int offset, int remaining)
37254c7070dbSScott Long {
372695246abbSSean Bruno 	int next, size;
372795246abbSSean Bruno 	struct mbuf **items;
37284c7070dbSScott Long 
372995246abbSSean Bruno 	size = r->size;
373095246abbSSean Bruno 	next = (cidx + CACHE_PTR_INCREMENT) & (size-1);
373195246abbSSean Bruno 	items = __DEVOLATILE(struct mbuf **, &r->items[0]);
373295246abbSSean Bruno 
373395246abbSSean Bruno 	prefetch(items[(cidx + offset) & (size-1)]);
373495246abbSSean Bruno 	if (remaining > 1) {
37353429c02fSStephen Hurd 		prefetch2cachelines(&items[next]);
37363429c02fSStephen Hurd 		prefetch2cachelines(items[(cidx + offset + 1) & (size-1)]);
37373429c02fSStephen Hurd 		prefetch2cachelines(items[(cidx + offset + 2) & (size-1)]);
37383429c02fSStephen Hurd 		prefetch2cachelines(items[(cidx + offset + 3) & (size-1)]);
373995246abbSSean Bruno 	}
374095246abbSSean Bruno 	return (__DEVOLATILE(struct mbuf **, &r->items[(cidx + offset) & (size-1)]));
37414c7070dbSScott Long }
37424c7070dbSScott Long 
37434c7070dbSScott Long static void
37444c7070dbSScott Long iflib_txq_check_drain(iflib_txq_t txq, int budget)
37454c7070dbSScott Long {
37464c7070dbSScott Long 
374795246abbSSean Bruno 	ifmp_ring_check_drainage(txq->ift_br, budget);
37484c7070dbSScott Long }
37494c7070dbSScott Long 
37504c7070dbSScott Long static uint32_t
37514c7070dbSScott Long iflib_txq_can_drain(struct ifmp_ring *r)
37524c7070dbSScott Long {
37534c7070dbSScott Long 	iflib_txq_t txq = r->cookie;
37544c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
37554c7070dbSScott Long 
375695dcf343SMarius Strobl 	if (TXQ_AVAIL(txq) > MAX_TX_DESC(ctx) + 2)
375795dcf343SMarius Strobl 		return (1);
37588a04b53dSKonstantin Belousov 	bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
37598a04b53dSKonstantin Belousov 	    BUS_DMASYNC_POSTREAD);
376095dcf343SMarius Strobl 	return (ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id,
376195dcf343SMarius Strobl 	    false));
37624c7070dbSScott Long }
37634c7070dbSScott Long 
37644c7070dbSScott Long static uint32_t
37654c7070dbSScott Long iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
37664c7070dbSScott Long {
37674c7070dbSScott Long 	iflib_txq_t txq = r->cookie;
37684c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
37691722eeacSMarius Strobl 	if_t ifp = ctx->ifc_ifp;
3770c2c5d1e7SMarius Strobl 	struct mbuf *m, **mp;
377181be6552SMatt Macy 	int avail, bytes_sent, skipped, count, err, i;
377281be6552SMatt Macy 	int mcast_sent, pkt_sent, reclaimed;
3773c2c5d1e7SMarius Strobl 	bool do_prefetch, rang, ring;
37744c7070dbSScott Long 
37754c7070dbSScott Long 	if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING) ||
37764c7070dbSScott Long 			    !LINK_ACTIVE(ctx))) {
37774c7070dbSScott Long 		DBG_COUNTER_INC(txq_drain_notready);
37784c7070dbSScott Long 		return (0);
37794c7070dbSScott Long 	}
378095246abbSSean Bruno 	reclaimed = iflib_completed_tx_reclaim(txq, RECLAIM_THRESH(ctx));
378181be6552SMatt Macy 	rang = iflib_txd_db_check(txq, reclaimed && txq->ift_db_pending);
37824c7070dbSScott Long 	avail = IDXDIFF(pidx, cidx, r->size);
378381be6552SMatt Macy 
37844c7070dbSScott Long 	if (__predict_false(ctx->ifc_flags & IFC_QFLUSH)) {
378581be6552SMatt Macy 		/*
378681be6552SMatt Macy 		 * The driver is unloading so we need to free all pending packets.
378781be6552SMatt Macy 		 */
37884c7070dbSScott Long 		DBG_COUNTER_INC(txq_drain_flushing);
37894c7070dbSScott Long 		for (i = 0; i < avail; i++) {
3790bc0e855bSStephen Hurd 			if (__predict_true(r->items[(cidx + i) & (r->size-1)] != (void *)txq))
379154bf96fbSMark Johnston 				m_freem(r->items[(cidx + i) & (r->size-1)]);
37924c7070dbSScott Long 			r->items[(cidx + i) & (r->size-1)] = NULL;
37934c7070dbSScott Long 		}
37944c7070dbSScott Long 		return (avail);
37954c7070dbSScott Long 	}
379695246abbSSean Bruno 
37974c7070dbSScott Long 	if (__predict_false(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE)) {
37984c7070dbSScott Long 		txq->ift_qstatus = IFLIB_QUEUE_IDLE;
37994c7070dbSScott Long 		CALLOUT_LOCK(txq);
38004c7070dbSScott Long 		callout_stop(&txq->ift_timer);
38014c7070dbSScott Long 		CALLOUT_UNLOCK(txq);
38024c7070dbSScott Long 		DBG_COUNTER_INC(txq_drain_oactive);
38034c7070dbSScott Long 		return (0);
38044c7070dbSScott Long 	}
380581be6552SMatt Macy 
380681be6552SMatt Macy 	/*
380781be6552SMatt Macy 	 * If we've reclaimed any packets this queue cannot be hung.
380881be6552SMatt Macy 	 */
380995246abbSSean Bruno 	if (reclaimed)
381095246abbSSean Bruno 		txq->ift_qstatus = IFLIB_QUEUE_IDLE;
381181be6552SMatt Macy 	skipped = mcast_sent = bytes_sent = pkt_sent = 0;
38124c7070dbSScott Long 	count = MIN(avail, TX_BATCH_SIZE);
3813da69b8f9SSean Bruno #ifdef INVARIANTS
3814da69b8f9SSean Bruno 	if (iflib_verbose_debug)
3815da69b8f9SSean Bruno 		printf("%s avail=%d ifc_flags=%x txq_avail=%d ", __FUNCTION__,
3816da69b8f9SSean Bruno 		       avail, ctx->ifc_flags, TXQ_AVAIL(txq));
3817da69b8f9SSean Bruno #endif
381895246abbSSean Bruno 	do_prefetch = (ctx->ifc_flags & IFC_PREFETCH);
38191ae4848cSMatt Macy 	err = 0;
382081be6552SMatt Macy 	for (i = 0; i < count && TXQ_AVAIL(txq) >= MAX_TX_DESC(ctx) + 2; i++) {
38211ae4848cSMatt Macy 		int rem = do_prefetch ? count - i : 0;
38224c7070dbSScott Long 
382395246abbSSean Bruno 		mp = _ring_peek_one(r, cidx, i, rem);
3824da69b8f9SSean Bruno 		MPASS(mp != NULL && *mp != NULL);
382581be6552SMatt Macy 
382681be6552SMatt Macy 		/*
382781be6552SMatt Macy 		 * Completion interrupts will use the address of the txq
382881be6552SMatt Macy 		 * as a sentinel to enqueue _something_ in order to acquire
382981be6552SMatt Macy 		 * the lock on the mp_ring (there's no direct lock call).
383081be6552SMatt Macy 		 * We obviously whave to check for these sentinel cases
383181be6552SMatt Macy 		 * and skip them.
383281be6552SMatt Macy 		 */
383395246abbSSean Bruno 		if (__predict_false(*mp == (struct mbuf *)txq)) {
383481be6552SMatt Macy 			skipped++;
383595246abbSSean Bruno 			continue;
383695246abbSSean Bruno 		}
383795246abbSSean Bruno 		err = iflib_encap(txq, mp);
383895246abbSSean Bruno 		if (__predict_false(err)) {
3839da69b8f9SSean Bruno 			/* no room - bail out */
384095246abbSSean Bruno 			if (err == ENOBUFS)
38414c7070dbSScott Long 				break;
384281be6552SMatt Macy 			skipped++;
3843da69b8f9SSean Bruno 			/* we can't send this packet - skip it */
38444c7070dbSScott Long 			continue;
3845da69b8f9SSean Bruno 		}
38464c7070dbSScott Long 		pkt_sent++;
38474c7070dbSScott Long 		m = *mp;
38484c7070dbSScott Long 		DBG_COUNTER_INC(tx_sent);
38494c7070dbSScott Long 		bytes_sent += m->m_pkthdr.len;
385095246abbSSean Bruno 		mcast_sent += !!(m->m_flags & M_MCAST);
38514c7070dbSScott Long 
385295246abbSSean Bruno 		if (__predict_false(!(ifp->if_drv_flags & IFF_DRV_RUNNING)))
38534c7070dbSScott Long 			break;
385481be6552SMatt Macy 		ETHER_BPF_MTAP(ifp, m);
385581be6552SMatt Macy 		rang = iflib_txd_db_check(txq, false);
38564c7070dbSScott Long 	}
38574c7070dbSScott Long 
385895246abbSSean Bruno 	/* deliberate use of bitwise or to avoid gratuitous short-circuit */
385981be6552SMatt Macy 	ring = rang ? false  : (iflib_min_tx_latency | err);
386081be6552SMatt Macy 	iflib_txd_db_check(txq, ring);
38614c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_OBYTES, bytes_sent);
38624c7070dbSScott Long 	if_inc_counter(ifp, IFCOUNTER_OPACKETS, pkt_sent);
38634c7070dbSScott Long 	if (mcast_sent)
38644c7070dbSScott Long 		if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast_sent);
3865da69b8f9SSean Bruno #ifdef INVARIANTS
3866da69b8f9SSean Bruno 	if (iflib_verbose_debug)
386781be6552SMatt Macy 		printf("consumed=%d\n", skipped + pkt_sent);
3868da69b8f9SSean Bruno #endif
386981be6552SMatt Macy 	return (skipped + pkt_sent);
38704c7070dbSScott Long }
38714c7070dbSScott Long 
3872da69b8f9SSean Bruno static uint32_t
3873da69b8f9SSean Bruno iflib_txq_drain_always(struct ifmp_ring *r)
3874da69b8f9SSean Bruno {
3875da69b8f9SSean Bruno 	return (1);
3876da69b8f9SSean Bruno }
3877da69b8f9SSean Bruno 
3878da69b8f9SSean Bruno static uint32_t
3879da69b8f9SSean Bruno iflib_txq_drain_free(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
3880da69b8f9SSean Bruno {
3881da69b8f9SSean Bruno 	int i, avail;
3882da69b8f9SSean Bruno 	struct mbuf **mp;
3883da69b8f9SSean Bruno 	iflib_txq_t txq;
3884da69b8f9SSean Bruno 
3885da69b8f9SSean Bruno 	txq = r->cookie;
3886da69b8f9SSean Bruno 
3887da69b8f9SSean Bruno 	txq->ift_qstatus = IFLIB_QUEUE_IDLE;
3888da69b8f9SSean Bruno 	CALLOUT_LOCK(txq);
3889da69b8f9SSean Bruno 	callout_stop(&txq->ift_timer);
3890da69b8f9SSean Bruno 	CALLOUT_UNLOCK(txq);
3891da69b8f9SSean Bruno 
3892da69b8f9SSean Bruno 	avail = IDXDIFF(pidx, cidx, r->size);
3893da69b8f9SSean Bruno 	for (i = 0; i < avail; i++) {
389495246abbSSean Bruno 		mp = _ring_peek_one(r, cidx, i, avail - i);
389595246abbSSean Bruno 		if (__predict_false(*mp == (struct mbuf *)txq))
389695246abbSSean Bruno 			continue;
3897da69b8f9SSean Bruno 		m_freem(*mp);
389864e6fc13SStephen Hurd 		DBG_COUNTER_INC(tx_frees);
3899da69b8f9SSean Bruno 	}
3900da69b8f9SSean Bruno 	MPASS(ifmp_ring_is_stalled(r) == 0);
3901da69b8f9SSean Bruno 	return (avail);
3902da69b8f9SSean Bruno }
3903da69b8f9SSean Bruno 
3904da69b8f9SSean Bruno static void
3905da69b8f9SSean Bruno iflib_ifmp_purge(iflib_txq_t txq)
3906da69b8f9SSean Bruno {
3907da69b8f9SSean Bruno 	struct ifmp_ring *r;
3908da69b8f9SSean Bruno 
390995246abbSSean Bruno 	r = txq->ift_br;
3910da69b8f9SSean Bruno 	r->drain = iflib_txq_drain_free;
3911da69b8f9SSean Bruno 	r->can_drain = iflib_txq_drain_always;
3912da69b8f9SSean Bruno 
3913da69b8f9SSean Bruno 	ifmp_ring_check_drainage(r, r->size);
3914da69b8f9SSean Bruno 
3915da69b8f9SSean Bruno 	r->drain = iflib_txq_drain;
3916da69b8f9SSean Bruno 	r->can_drain = iflib_txq_can_drain;
3917da69b8f9SSean Bruno }
3918da69b8f9SSean Bruno 
39194c7070dbSScott Long static void
392023ac9029SStephen Hurd _task_fn_tx(void *context)
39214c7070dbSScott Long {
39224c7070dbSScott Long 	iflib_txq_t txq = context;
39234c7070dbSScott Long 	if_ctx_t ctx = txq->ift_ctx;
3924a6611c93SMarius Strobl 	if_t ifp = ctx->ifc_ifp;
3925fe51d4cdSStephen Hurd 	int abdicate = ctx->ifc_sysctl_tx_abdicate;
39264c7070dbSScott Long 
39271248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
39281248952aSSean Bruno 	txq->ift_cpu_exec_count[curcpu]++;
39291248952aSSean Bruno #endif
393088a68866SVincenzo Maffione 	if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
39314c7070dbSScott Long 		return;
393295dcf343SMarius Strobl #ifdef DEV_NETMAP
393388a68866SVincenzo Maffione 	if ((if_getcapenable(ifp) & IFCAP_NETMAP) &&
393488a68866SVincenzo Maffione 	    netmap_tx_irq(ifp, txq->ift_id))
393588a68866SVincenzo Maffione 		goto skip_ifmp;
393695dcf343SMarius Strobl #endif
3937b8ca4756SPatrick Kelsey #ifdef ALTQ
3938b8ca4756SPatrick Kelsey 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
3939b8ca4756SPatrick Kelsey 		iflib_altq_if_start(ifp);
3940b8ca4756SPatrick Kelsey #endif
394195246abbSSean Bruno 	if (txq->ift_db_pending)
3942fe51d4cdSStephen Hurd 		ifmp_ring_enqueue(txq->ift_br, (void **)&txq, 1, TX_BATCH_SIZE, abdicate);
3943fe51d4cdSStephen Hurd 	else if (!abdicate)
3944fe51d4cdSStephen Hurd 		ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
3945fe51d4cdSStephen Hurd 	/*
3946fe51d4cdSStephen Hurd 	 * When abdicating, we always need to check drainage, not just when we don't enqueue
3947fe51d4cdSStephen Hurd 	 */
3948fe51d4cdSStephen Hurd 	if (abdicate)
3949fe51d4cdSStephen Hurd 		ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
395088a68866SVincenzo Maffione #ifdef DEV_NETMAP
395188a68866SVincenzo Maffione skip_ifmp:
395288a68866SVincenzo Maffione #endif
395395246abbSSean Bruno 	if (ctx->ifc_flags & IFC_LEGACY)
395495246abbSSean Bruno 		IFDI_INTR_ENABLE(ctx);
39553d10e9edSMarius Strobl 	else
39561ae4848cSMatt Macy 		IFDI_TX_QUEUE_INTR_ENABLE(ctx, txq->ift_id);
39574c7070dbSScott Long }
39584c7070dbSScott Long 
39594c7070dbSScott Long static void
396023ac9029SStephen Hurd _task_fn_rx(void *context)
39614c7070dbSScott Long {
39624c7070dbSScott Long 	iflib_rxq_t rxq = context;
39634c7070dbSScott Long 	if_ctx_t ctx = rxq->ifr_ctx;
3964fb1a29b4SHans Petter Selasky 	uint8_t more;
3965f4d2154eSStephen Hurd 	uint16_t budget;
3966e136e9c8SVincenzo Maffione #ifdef DEV_NETMAP
3967e136e9c8SVincenzo Maffione 	u_int work = 0;
3968e136e9c8SVincenzo Maffione 	int nmirq;
3969e136e9c8SVincenzo Maffione #endif
39704c7070dbSScott Long 
39711248952aSSean Bruno #ifdef IFLIB_DIAGNOSTICS
39721248952aSSean Bruno 	rxq->ifr_cpu_exec_count[curcpu]++;
39731248952aSSean Bruno #endif
39744c7070dbSScott Long 	DBG_COUNTER_INC(task_fn_rxs);
39754c7070dbSScott Long 	if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
39764c7070dbSScott Long 		return;
3977d0d0ad0aSStephen Hurd #ifdef DEV_NETMAP
3978e136e9c8SVincenzo Maffione 	nmirq = netmap_rx_irq(ctx->ifc_ifp, rxq->ifr_id, &work);
3979e136e9c8SVincenzo Maffione 	if (nmirq != NM_IRQ_PASS) {
3980e136e9c8SVincenzo Maffione 		more = (nmirq == NM_IRQ_RESCHED) ? IFLIB_RXEOF_MORE : 0;
3981fb1a29b4SHans Petter Selasky 		goto skip_rxeof;
3982d0d0ad0aSStephen Hurd 	}
3983d0d0ad0aSStephen Hurd #endif
3984f4d2154eSStephen Hurd 	budget = ctx->ifc_sysctl_rx_budget;
3985f4d2154eSStephen Hurd 	if (budget == 0)
3986f4d2154eSStephen Hurd 		budget = 16;	/* XXX */
3987fb1a29b4SHans Petter Selasky 	more = iflib_rxeof(rxq, budget);
3988fb1a29b4SHans Petter Selasky #ifdef DEV_NETMAP
3989fb1a29b4SHans Petter Selasky skip_rxeof:
3990fb1a29b4SHans Petter Selasky #endif
3991fb1a29b4SHans Petter Selasky 	if ((more & IFLIB_RXEOF_MORE) == 0) {
39924c7070dbSScott Long 		if (ctx->ifc_flags & IFC_LEGACY)
39934c7070dbSScott Long 			IFDI_INTR_ENABLE(ctx);
39943d10e9edSMarius Strobl 		else
39951ae4848cSMatt Macy 			IFDI_RX_QUEUE_INTR_ENABLE(ctx, rxq->ifr_id);
39961ae4848cSMatt Macy 		DBG_COUNTER_INC(rx_intr_enables);
39974c7070dbSScott Long 	}
39984c7070dbSScott Long 	if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)))
39994c7070dbSScott Long 		return;
4000fb1a29b4SHans Petter Selasky 
4001fb1a29b4SHans Petter Selasky 	if (more & IFLIB_RXEOF_MORE)
40024c7070dbSScott Long 		GROUPTASK_ENQUEUE(&rxq->ifr_task);
4003fb1a29b4SHans Petter Selasky 	else if (more & IFLIB_RXEOF_EMPTY)
4004fb1a29b4SHans Petter Selasky 		callout_reset_curcpu(&rxq->ifr_watchdog, 1, &_task_fn_rx_watchdog, rxq);
40054c7070dbSScott Long }
40064c7070dbSScott Long 
40074c7070dbSScott Long static void
400823ac9029SStephen Hurd _task_fn_admin(void *context)
40094c7070dbSScott Long {
40104c7070dbSScott Long 	if_ctx_t ctx = context;
40114c7070dbSScott Long 	if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
40124c7070dbSScott Long 	iflib_txq_t txq;
4013ab2e3f79SStephen Hurd 	int i;
401477c1fcecSEric Joyner 	bool oactive, running, do_reset, do_watchdog, in_detach;
4015ab2e3f79SStephen Hurd 
40167b610b60SSean Bruno 	STATE_LOCK(ctx);
40177b610b60SSean Bruno 	running = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING);
40187b610b60SSean Bruno 	oactive = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE);
40197b610b60SSean Bruno 	do_reset = (ctx->ifc_flags & IFC_DO_RESET);
40207b610b60SSean Bruno 	do_watchdog = (ctx->ifc_flags & IFC_DO_WATCHDOG);
402177c1fcecSEric Joyner 	in_detach = (ctx->ifc_flags & IFC_IN_DETACH);
40227b610b60SSean Bruno 	ctx->ifc_flags &= ~(IFC_DO_RESET|IFC_DO_WATCHDOG);
40237b610b60SSean Bruno 	STATE_UNLOCK(ctx);
40247b610b60SSean Bruno 
402577c1fcecSEric Joyner 	if ((!running && !oactive) && !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
402677c1fcecSEric Joyner 		return;
402777c1fcecSEric Joyner 	if (in_detach)
4028ab2e3f79SStephen Hurd 		return;
40294c7070dbSScott Long 
40304c7070dbSScott Long 	CTX_LOCK(ctx);
40314c7070dbSScott Long 	for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) {
40324c7070dbSScott Long 		CALLOUT_LOCK(txq);
40334c7070dbSScott Long 		callout_stop(&txq->ift_timer);
40344c7070dbSScott Long 		CALLOUT_UNLOCK(txq);
40354c7070dbSScott Long 	}
403609c3f04fSMarcin Wojtas 	if (ctx->ifc_sctx->isc_flags & IFLIB_HAS_ADMINCQ)
403709c3f04fSMarcin Wojtas 		IFDI_ADMIN_COMPLETION_HANDLE(ctx);
40387b610b60SSean Bruno 	if (do_watchdog) {
40397b610b60SSean Bruno 		ctx->ifc_watchdog_events++;
40407b610b60SSean Bruno 		IFDI_WATCHDOG_RESET(ctx);
40417b610b60SSean Bruno 	}
4042d300df01SStephen Hurd 	IFDI_UPDATE_ADMIN_STATUS(ctx);
4043dd7fbcf1SStephen Hurd 	for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) {
404481be6552SMatt Macy 		callout_reset_on(&txq->ift_timer, iflib_timer_default, iflib_timer, txq,
404517cec474SVincenzo Maffione 		    txq->ift_timer.c_cpu);
4046dd7fbcf1SStephen Hurd 	}
4047ab2e3f79SStephen Hurd 	IFDI_LINK_INTR_ENABLE(ctx);
40487b610b60SSean Bruno 	if (do_reset)
4049ab2e3f79SStephen Hurd 		iflib_if_init_locked(ctx);
40504c7070dbSScott Long 	CTX_UNLOCK(ctx);
40514c7070dbSScott Long 
4052ab2e3f79SStephen Hurd 	if (LINK_ACTIVE(ctx) == 0)
40534c7070dbSScott Long 		return;
40544c7070dbSScott Long 	for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++)
40554c7070dbSScott Long 		iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET);
40564c7070dbSScott Long }
40574c7070dbSScott Long 
40584c7070dbSScott Long static void
405923ac9029SStephen Hurd _task_fn_iov(void *context)
40604c7070dbSScott Long {
40614c7070dbSScott Long 	if_ctx_t ctx = context;
40624c7070dbSScott Long 
406377c1fcecSEric Joyner 	if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) &&
406477c1fcecSEric Joyner 	    !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
40654c7070dbSScott Long 		return;
40664c7070dbSScott Long 
40674c7070dbSScott Long 	CTX_LOCK(ctx);
40684c7070dbSScott Long 	IFDI_VFLR_HANDLE(ctx);
40694c7070dbSScott Long 	CTX_UNLOCK(ctx);
40704c7070dbSScott Long }
40714c7070dbSScott Long 
40724c7070dbSScott Long static int
40734c7070dbSScott Long iflib_sysctl_int_delay(SYSCTL_HANDLER_ARGS)
40744c7070dbSScott Long {
40754c7070dbSScott Long 	int err;
40764c7070dbSScott Long 	if_int_delay_info_t info;
40774c7070dbSScott Long 	if_ctx_t ctx;
40784c7070dbSScott Long 
40794c7070dbSScott Long 	info = (if_int_delay_info_t)arg1;
40804c7070dbSScott Long 	ctx = info->iidi_ctx;
40814c7070dbSScott Long 	info->iidi_req = req;
40824c7070dbSScott Long 	info->iidi_oidp = oidp;
40834c7070dbSScott Long 	CTX_LOCK(ctx);
40844c7070dbSScott Long 	err = IFDI_SYSCTL_INT_DELAY(ctx, info);
40854c7070dbSScott Long 	CTX_UNLOCK(ctx);
40864c7070dbSScott Long 	return (err);
40874c7070dbSScott Long }
40884c7070dbSScott Long 
40894c7070dbSScott Long /*********************************************************************
40904c7070dbSScott Long  *
40914c7070dbSScott Long  *  IFNET FUNCTIONS
40924c7070dbSScott Long  *
40934c7070dbSScott Long  **********************************************************************/
40944c7070dbSScott Long 
40954c7070dbSScott Long static void
40964c7070dbSScott Long iflib_if_init_locked(if_ctx_t ctx)
40974c7070dbSScott Long {
40984c7070dbSScott Long 	iflib_stop(ctx);
40994c7070dbSScott Long 	iflib_init_locked(ctx);
41004c7070dbSScott Long }
41014c7070dbSScott Long 
41024c7070dbSScott Long static void
41034c7070dbSScott Long iflib_if_init(void *arg)
41044c7070dbSScott Long {
41054c7070dbSScott Long 	if_ctx_t ctx = arg;
41064c7070dbSScott Long 
41074c7070dbSScott Long 	CTX_LOCK(ctx);
41084c7070dbSScott Long 	iflib_if_init_locked(ctx);
41094c7070dbSScott Long 	CTX_UNLOCK(ctx);
41104c7070dbSScott Long }
41114c7070dbSScott Long 
41124c7070dbSScott Long static int
41134c7070dbSScott Long iflib_if_transmit(if_t ifp, struct mbuf *m)
41144c7070dbSScott Long {
41154c7070dbSScott Long 	if_ctx_t	ctx = if_getsoftc(ifp);
41164c7070dbSScott Long 
41174c7070dbSScott Long 	iflib_txq_t txq;
411823ac9029SStephen Hurd 	int err, qidx;
4119fe51d4cdSStephen Hurd 	int abdicate = ctx->ifc_sysctl_tx_abdicate;
41204c7070dbSScott Long 
41214c7070dbSScott Long 	if (__predict_false((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || !LINK_ACTIVE(ctx))) {
41224c7070dbSScott Long 		DBG_COUNTER_INC(tx_frees);
41234c7070dbSScott Long 		m_freem(m);
4124225eae1bSEric Joyner 		return (ENETDOWN);
41254c7070dbSScott Long 	}
41264c7070dbSScott Long 
412723ac9029SStephen Hurd 	MPASS(m->m_nextpkt == NULL);
4128b8ca4756SPatrick Kelsey 	/* ALTQ-enabled interfaces always use queue 0. */
41294c7070dbSScott Long 	qidx = 0;
4130b8ca4756SPatrick Kelsey 	if ((NTXQSETS(ctx) > 1) && M_HASHTYPE_GET(m) && !ALTQ_IS_ENABLED(&ifp->if_snd))
41314c7070dbSScott Long 		qidx = QIDX(ctx, m);
41324c7070dbSScott Long 	/*
41334c7070dbSScott Long 	 * XXX calculate buf_ring based on flowid (divvy up bits?)
41344c7070dbSScott Long 	 */
41354c7070dbSScott Long 	txq = &ctx->ifc_txqs[qidx];
41364c7070dbSScott Long 
41374c7070dbSScott Long #ifdef DRIVER_BACKPRESSURE
41384c7070dbSScott Long 	if (txq->ift_closed) {
41394c7070dbSScott Long 		while (m != NULL) {
41404c7070dbSScott Long 			next = m->m_nextpkt;
41414c7070dbSScott Long 			m->m_nextpkt = NULL;
41424c7070dbSScott Long 			m_freem(m);
414364e6fc13SStephen Hurd 			DBG_COUNTER_INC(tx_frees);
41444c7070dbSScott Long 			m = next;
41454c7070dbSScott Long 		}
41464c7070dbSScott Long 		return (ENOBUFS);
41474c7070dbSScott Long 	}
41484c7070dbSScott Long #endif
414923ac9029SStephen Hurd #ifdef notyet
41504c7070dbSScott Long 	qidx = count = 0;
41514c7070dbSScott Long 	mp = marr;
41524c7070dbSScott Long 	next = m;
41534c7070dbSScott Long 	do {
41544c7070dbSScott Long 		count++;
41554c7070dbSScott Long 		next = next->m_nextpkt;
41564c7070dbSScott Long 	} while (next != NULL);
41574c7070dbSScott Long 
415816fb86abSConrad Meyer 	if (count > nitems(marr))
41594c7070dbSScott Long 		if ((mp = malloc(count*sizeof(struct mbuf *), M_IFLIB, M_NOWAIT)) == NULL) {
41604c7070dbSScott Long 			/* XXX check nextpkt */
41614c7070dbSScott Long 			m_freem(m);
41624c7070dbSScott Long 			/* XXX simplify for now */
41634c7070dbSScott Long 			DBG_COUNTER_INC(tx_frees);
41644c7070dbSScott Long 			return (ENOBUFS);
41654c7070dbSScott Long 		}
41664c7070dbSScott Long 	for (next = m, i = 0; next != NULL; i++) {
41674c7070dbSScott Long 		mp[i] = next;
41684c7070dbSScott Long 		next = next->m_nextpkt;
41694c7070dbSScott Long 		mp[i]->m_nextpkt = NULL;
41704c7070dbSScott Long 	}
417123ac9029SStephen Hurd #endif
41724c7070dbSScott Long 	DBG_COUNTER_INC(tx_seen);
4173fe51d4cdSStephen Hurd 	err = ifmp_ring_enqueue(txq->ift_br, (void **)&m, 1, TX_BATCH_SIZE, abdicate);
41744c7070dbSScott Long 
4175fe51d4cdSStephen Hurd 	if (abdicate)
4176ab2e3f79SStephen Hurd 		GROUPTASK_ENQUEUE(&txq->ift_task);
41771225d9daSStephen Hurd  	if (err) {
4178fe51d4cdSStephen Hurd 		if (!abdicate)
4179fe51d4cdSStephen Hurd 			GROUPTASK_ENQUEUE(&txq->ift_task);
41804c7070dbSScott Long 		/* support forthcoming later */
41814c7070dbSScott Long #ifdef DRIVER_BACKPRESSURE
41824c7070dbSScott Long 		txq->ift_closed = TRUE;
41834c7070dbSScott Long #endif
418495246abbSSean Bruno 		ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE);
418523ac9029SStephen Hurd 		m_freem(m);
418664e6fc13SStephen Hurd 		DBG_COUNTER_INC(tx_frees);
41874c7070dbSScott Long 	}
41884c7070dbSScott Long 
41894c7070dbSScott Long 	return (err);
41904c7070dbSScott Long }
41914c7070dbSScott Long 
4192b8ca4756SPatrick Kelsey #ifdef ALTQ
4193b8ca4756SPatrick Kelsey /*
4194b8ca4756SPatrick Kelsey  * The overall approach to integrating iflib with ALTQ is to continue to use
4195b8ca4756SPatrick Kelsey  * the iflib mp_ring machinery between the ALTQ queue(s) and the hardware
4196b8ca4756SPatrick Kelsey  * ring.  Technically, when using ALTQ, queueing to an intermediate mp_ring
4197b8ca4756SPatrick Kelsey  * is redundant/unnecessary, but doing so minimizes the amount of
4198b8ca4756SPatrick Kelsey  * ALTQ-specific code required in iflib.  It is assumed that the overhead of
4199b8ca4756SPatrick Kelsey  * redundantly queueing to an intermediate mp_ring is swamped by the
4200b8ca4756SPatrick Kelsey  * performance limitations inherent in using ALTQ.
4201b8ca4756SPatrick Kelsey  *
4202b8ca4756SPatrick Kelsey  * When ALTQ support is compiled in, all iflib drivers will use a transmit
4203b8ca4756SPatrick Kelsey  * routine, iflib_altq_if_transmit(), that checks if ALTQ is enabled for the
4204b8ca4756SPatrick Kelsey  * given interface.  If ALTQ is enabled for an interface, then all
4205b8ca4756SPatrick Kelsey  * transmitted packets for that interface will be submitted to the ALTQ
4206b8ca4756SPatrick Kelsey  * subsystem via IFQ_ENQUEUE().  We don't use the legacy if_transmit()
4207b8ca4756SPatrick Kelsey  * implementation because it uses IFQ_HANDOFF(), which will duplicatively
4208b8ca4756SPatrick Kelsey  * update stats that the iflib machinery handles, and which is sensitve to
4209b8ca4756SPatrick Kelsey  * the disused IFF_DRV_OACTIVE flag.  Additionally, iflib_altq_if_start()
4210b8ca4756SPatrick Kelsey  * will be installed as the start routine for use by ALTQ facilities that
4211b8ca4756SPatrick Kelsey  * need to trigger queue drains on a scheduled basis.
4212b8ca4756SPatrick Kelsey  *
4213b8ca4756SPatrick Kelsey  */
4214b8ca4756SPatrick Kelsey static void
4215b8ca4756SPatrick Kelsey iflib_altq_if_start(if_t ifp)
4216b8ca4756SPatrick Kelsey {
4217b8ca4756SPatrick Kelsey 	struct ifaltq *ifq = &ifp->if_snd;
4218b8ca4756SPatrick Kelsey 	struct mbuf *m;
4219b8ca4756SPatrick Kelsey 
4220b8ca4756SPatrick Kelsey 	IFQ_LOCK(ifq);
4221b8ca4756SPatrick Kelsey 	IFQ_DEQUEUE_NOLOCK(ifq, m);
4222b8ca4756SPatrick Kelsey 	while (m != NULL) {
4223b8ca4756SPatrick Kelsey 		iflib_if_transmit(ifp, m);
4224b8ca4756SPatrick Kelsey 		IFQ_DEQUEUE_NOLOCK(ifq, m);
4225b8ca4756SPatrick Kelsey 	}
4226b8ca4756SPatrick Kelsey 	IFQ_UNLOCK(ifq);
4227b8ca4756SPatrick Kelsey }
4228b8ca4756SPatrick Kelsey 
4229b8ca4756SPatrick Kelsey static int
4230b8ca4756SPatrick Kelsey iflib_altq_if_transmit(if_t ifp, struct mbuf *m)
4231b8ca4756SPatrick Kelsey {
4232b8ca4756SPatrick Kelsey 	int err;
4233b8ca4756SPatrick Kelsey 
4234b8ca4756SPatrick Kelsey 	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
4235b8ca4756SPatrick Kelsey 		IFQ_ENQUEUE(&ifp->if_snd, m, err);
4236b8ca4756SPatrick Kelsey 		if (err == 0)
4237b8ca4756SPatrick Kelsey 			iflib_altq_if_start(ifp);
4238b8ca4756SPatrick Kelsey 	} else
4239b8ca4756SPatrick Kelsey 		err = iflib_if_transmit(ifp, m);
4240b8ca4756SPatrick Kelsey 
4241b8ca4756SPatrick Kelsey 	return (err);
4242b8ca4756SPatrick Kelsey }
4243b8ca4756SPatrick Kelsey #endif /* ALTQ */
4244b8ca4756SPatrick Kelsey 
42454c7070dbSScott Long static void
42464c7070dbSScott Long iflib_if_qflush(if_t ifp)
42474c7070dbSScott Long {
42484c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
42494c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
42504c7070dbSScott Long 	int i;
42514c7070dbSScott Long 
42527b610b60SSean Bruno 	STATE_LOCK(ctx);
42534c7070dbSScott Long 	ctx->ifc_flags |= IFC_QFLUSH;
42547b610b60SSean Bruno 	STATE_UNLOCK(ctx);
42554c7070dbSScott Long 	for (i = 0; i < NTXQSETS(ctx); i++, txq++)
425695246abbSSean Bruno 		while (!(ifmp_ring_is_idle(txq->ift_br) || ifmp_ring_is_stalled(txq->ift_br)))
42574c7070dbSScott Long 			iflib_txq_check_drain(txq, 0);
42587b610b60SSean Bruno 	STATE_LOCK(ctx);
42594c7070dbSScott Long 	ctx->ifc_flags &= ~IFC_QFLUSH;
42607b610b60SSean Bruno 	STATE_UNLOCK(ctx);
42614c7070dbSScott Long 
4262b8ca4756SPatrick Kelsey 	/*
4263b8ca4756SPatrick Kelsey 	 * When ALTQ is enabled, this will also take care of purging the
4264b8ca4756SPatrick Kelsey 	 * ALTQ queue(s).
4265b8ca4756SPatrick Kelsey 	 */
42664c7070dbSScott Long 	if_qflush(ifp);
42674c7070dbSScott Long }
42684c7070dbSScott Long 
42690c919c23SStephen Hurd #define IFCAP_FLAGS (IFCAP_HWCSUM_IPV6 | IFCAP_HWCSUM | IFCAP_LRO | \
42700c919c23SStephen Hurd 		     IFCAP_TSO | IFCAP_VLAN_HWTAGGING | IFCAP_HWSTATS | \
42710c919c23SStephen Hurd 		     IFCAP_VLAN_MTU | IFCAP_VLAN_HWFILTER | \
42723f43ada9SGleb Smirnoff 		     IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM | IFCAP_MEXTPG)
42734c7070dbSScott Long 
42744c7070dbSScott Long static int
42754c7070dbSScott Long iflib_if_ioctl(if_t ifp, u_long command, caddr_t data)
42764c7070dbSScott Long {
42774c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
42784c7070dbSScott Long 	struct ifreq	*ifr = (struct ifreq *)data;
42794c7070dbSScott Long #if defined(INET) || defined(INET6)
42804c7070dbSScott Long 	struct ifaddr	*ifa = (struct ifaddr *)data;
42814c7070dbSScott Long #endif
42821722eeacSMarius Strobl 	bool		avoid_reset = false;
42834c7070dbSScott Long 	int		err = 0, reinit = 0, bits;
42844c7070dbSScott Long 
42854c7070dbSScott Long 	switch (command) {
42864c7070dbSScott Long 	case SIOCSIFADDR:
42874c7070dbSScott Long #ifdef INET
42884c7070dbSScott Long 		if (ifa->ifa_addr->sa_family == AF_INET)
42891722eeacSMarius Strobl 			avoid_reset = true;
42904c7070dbSScott Long #endif
42914c7070dbSScott Long #ifdef INET6
42924c7070dbSScott Long 		if (ifa->ifa_addr->sa_family == AF_INET6)
42931722eeacSMarius Strobl 			avoid_reset = true;
42944c7070dbSScott Long #endif
42954c7070dbSScott Long 		/*
42964c7070dbSScott Long 		** Calling init results in link renegotiation,
42974c7070dbSScott Long 		** so we avoid doing it when possible.
42984c7070dbSScott Long 		*/
42994c7070dbSScott Long 		if (avoid_reset) {
43004c7070dbSScott Long 			if_setflagbits(ifp, IFF_UP,0);
43014c7070dbSScott Long 			if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
43024c7070dbSScott Long 				reinit = 1;
43034c7070dbSScott Long #ifdef INET
43044c7070dbSScott Long 			if (!(if_getflags(ifp) & IFF_NOARP))
43054c7070dbSScott Long 				arp_ifinit(ifp, ifa);
43064c7070dbSScott Long #endif
43074c7070dbSScott Long 		} else
43084c7070dbSScott Long 			err = ether_ioctl(ifp, command, data);
43094c7070dbSScott Long 		break;
43104c7070dbSScott Long 	case SIOCSIFMTU:
43114c7070dbSScott Long 		CTX_LOCK(ctx);
43124c7070dbSScott Long 		if (ifr->ifr_mtu == if_getmtu(ifp)) {
43134c7070dbSScott Long 			CTX_UNLOCK(ctx);
43144c7070dbSScott Long 			break;
43154c7070dbSScott Long 		}
43164c7070dbSScott Long 		bits = if_getdrvflags(ifp);
43174c7070dbSScott Long 		/* stop the driver and free any clusters before proceeding */
43184c7070dbSScott Long 		iflib_stop(ctx);
43194c7070dbSScott Long 
43204c7070dbSScott Long 		if ((err = IFDI_MTU_SET(ctx, ifr->ifr_mtu)) == 0) {
43217b610b60SSean Bruno 			STATE_LOCK(ctx);
43224c7070dbSScott Long 			if (ifr->ifr_mtu > ctx->ifc_max_fl_buf_size)
43234c7070dbSScott Long 				ctx->ifc_flags |= IFC_MULTISEG;
43244c7070dbSScott Long 			else
43254c7070dbSScott Long 				ctx->ifc_flags &= ~IFC_MULTISEG;
43267b610b60SSean Bruno 			STATE_UNLOCK(ctx);
43274c7070dbSScott Long 			err = if_setmtu(ifp, ifr->ifr_mtu);
43284c7070dbSScott Long 		}
43294c7070dbSScott Long 		iflib_init_locked(ctx);
43307b610b60SSean Bruno 		STATE_LOCK(ctx);
43314c7070dbSScott Long 		if_setdrvflags(ifp, bits);
43327b610b60SSean Bruno 		STATE_UNLOCK(ctx);
43334c7070dbSScott Long 		CTX_UNLOCK(ctx);
43344c7070dbSScott Long 		break;
43354c7070dbSScott Long 	case SIOCSIFFLAGS:
4336ab2e3f79SStephen Hurd 		CTX_LOCK(ctx);
4337ab2e3f79SStephen Hurd 		if (if_getflags(ifp) & IFF_UP) {
4338ab2e3f79SStephen Hurd 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4339ab2e3f79SStephen Hurd 				if ((if_getflags(ifp) ^ ctx->ifc_if_flags) &
4340ab2e3f79SStephen Hurd 				    (IFF_PROMISC | IFF_ALLMULTI)) {
43410ae0e8d2SMatt Macy 					CTX_UNLOCK(ctx);
4342ab2e3f79SStephen Hurd 					err = IFDI_PROMISC_SET(ctx, if_getflags(ifp));
43430ae0e8d2SMatt Macy 					CTX_LOCK(ctx);
4344ab2e3f79SStephen Hurd 				}
4345ab2e3f79SStephen Hurd 			} else
4346ab2e3f79SStephen Hurd 				reinit = 1;
4347ab2e3f79SStephen Hurd 		} else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4348ab2e3f79SStephen Hurd 			iflib_stop(ctx);
4349ab2e3f79SStephen Hurd 		}
4350ab2e3f79SStephen Hurd 		ctx->ifc_if_flags = if_getflags(ifp);
4351ab2e3f79SStephen Hurd 		CTX_UNLOCK(ctx);
43524c7070dbSScott Long 		break;
43534c7070dbSScott Long 	case SIOCADDMULTI:
43544c7070dbSScott Long 	case SIOCDELMULTI:
43554c7070dbSScott Long 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
4356ab2e3f79SStephen Hurd 			CTX_LOCK(ctx);
4357ab2e3f79SStephen Hurd 			IFDI_INTR_DISABLE(ctx);
4358ab2e3f79SStephen Hurd 			IFDI_MULTI_SET(ctx);
4359ab2e3f79SStephen Hurd 			IFDI_INTR_ENABLE(ctx);
4360ab2e3f79SStephen Hurd 			CTX_UNLOCK(ctx);
43614c7070dbSScott Long 		}
43624c7070dbSScott Long 		break;
43634c7070dbSScott Long 	case SIOCSIFMEDIA:
43644c7070dbSScott Long 		CTX_LOCK(ctx);
43654c7070dbSScott Long 		IFDI_MEDIA_SET(ctx);
43664c7070dbSScott Long 		CTX_UNLOCK(ctx);
43671722eeacSMarius Strobl 		/* FALLTHROUGH */
43684c7070dbSScott Long 	case SIOCGIFMEDIA:
4369a027c8e9SStephen Hurd 	case SIOCGIFXMEDIA:
4370e2621d96SMatt Macy 		err = ifmedia_ioctl(ifp, ifr, ctx->ifc_mediap, command);
43714c7070dbSScott Long 		break;
43724c7070dbSScott Long 	case SIOCGI2C:
43734c7070dbSScott Long 	{
43744c7070dbSScott Long 		struct ifi2creq i2c;
43754c7070dbSScott Long 
4376541d96aaSBrooks Davis 		err = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c));
43774c7070dbSScott Long 		if (err != 0)
43784c7070dbSScott Long 			break;
43794c7070dbSScott Long 		if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) {
43804c7070dbSScott Long 			err = EINVAL;
43814c7070dbSScott Long 			break;
43824c7070dbSScott Long 		}
43834c7070dbSScott Long 		if (i2c.len > sizeof(i2c.data)) {
43844c7070dbSScott Long 			err = EINVAL;
43854c7070dbSScott Long 			break;
43864c7070dbSScott Long 		}
43874c7070dbSScott Long 
43884c7070dbSScott Long 		if ((err = IFDI_I2C_REQ(ctx, &i2c)) == 0)
4389541d96aaSBrooks Davis 			err = copyout(&i2c, ifr_data_get_ptr(ifr),
4390541d96aaSBrooks Davis 			    sizeof(i2c));
43914c7070dbSScott Long 		break;
43924c7070dbSScott Long 	}
43934c7070dbSScott Long 	case SIOCSIFCAP:
43944c7070dbSScott Long 	{
43950c919c23SStephen Hurd 		int mask, setmask, oldmask;
43964c7070dbSScott Long 
43970c919c23SStephen Hurd 		oldmask = if_getcapenable(ifp);
43980c919c23SStephen Hurd 		mask = ifr->ifr_reqcap ^ oldmask;
43993f43ada9SGleb Smirnoff 		mask &= ctx->ifc_softc_ctx.isc_capabilities | IFCAP_MEXTPG;
44004c7070dbSScott Long 		setmask = 0;
44014c7070dbSScott Long #ifdef TCP_OFFLOAD
44024c7070dbSScott Long 		setmask |= mask & (IFCAP_TOE4|IFCAP_TOE6);
44034c7070dbSScott Long #endif
44044c7070dbSScott Long 		setmask |= (mask & IFCAP_FLAGS);
44050c919c23SStephen Hurd 		setmask |= (mask & IFCAP_WOL);
44064c7070dbSScott Long 
44070c919c23SStephen Hurd 		/*
4408a42546dfSStephen Hurd 		 * If any RX csum has changed, change all the ones that
4409a42546dfSStephen Hurd 		 * are supported by the driver.
44100c919c23SStephen Hurd 		 */
4411a42546dfSStephen Hurd 		if (setmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) {
4412a42546dfSStephen Hurd 			setmask |= ctx->ifc_softc_ctx.isc_capabilities &
4413a42546dfSStephen Hurd 			    (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6);
4414a42546dfSStephen Hurd 		}
44150c919c23SStephen Hurd 
44164c7070dbSScott Long 		/*
44174c7070dbSScott Long 		 * want to ensure that traffic has stopped before we change any of the flags
44184c7070dbSScott Long 		 */
44194c7070dbSScott Long 		if (setmask) {
44204c7070dbSScott Long 			CTX_LOCK(ctx);
44214c7070dbSScott Long 			bits = if_getdrvflags(ifp);
44220c919c23SStephen Hurd 			if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL)
44234c7070dbSScott Long 				iflib_stop(ctx);
44247b610b60SSean Bruno 			STATE_LOCK(ctx);
44254c7070dbSScott Long 			if_togglecapenable(ifp, setmask);
44267b610b60SSean Bruno 			STATE_UNLOCK(ctx);
44270c919c23SStephen Hurd 			if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL)
44284c7070dbSScott Long 				iflib_init_locked(ctx);
44297b610b60SSean Bruno 			STATE_LOCK(ctx);
44304c7070dbSScott Long 			if_setdrvflags(ifp, bits);
44317b610b60SSean Bruno 			STATE_UNLOCK(ctx);
44324c7070dbSScott Long 			CTX_UNLOCK(ctx);
44334c7070dbSScott Long 		}
44340c919c23SStephen Hurd 		if_vlancap(ifp);
44354c7070dbSScott Long 		break;
44364c7070dbSScott Long 	}
44374c7070dbSScott Long 	case SIOCGPRIVATE_0:
44384c7070dbSScott Long 	case SIOCSDRVSPEC:
44394c7070dbSScott Long 	case SIOCGDRVSPEC:
44404c7070dbSScott Long 		CTX_LOCK(ctx);
44414c7070dbSScott Long 		err = IFDI_PRIV_IOCTL(ctx, command, data);
44424c7070dbSScott Long 		CTX_UNLOCK(ctx);
44434c7070dbSScott Long 		break;
44444c7070dbSScott Long 	default:
44454c7070dbSScott Long 		err = ether_ioctl(ifp, command, data);
44464c7070dbSScott Long 		break;
44474c7070dbSScott Long 	}
44484c7070dbSScott Long 	if (reinit)
44494c7070dbSScott Long 		iflib_if_init(ctx);
44504c7070dbSScott Long 	return (err);
44514c7070dbSScott Long }
44524c7070dbSScott Long 
44534c7070dbSScott Long static uint64_t
44544c7070dbSScott Long iflib_if_get_counter(if_t ifp, ift_counter cnt)
44554c7070dbSScott Long {
44564c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
44574c7070dbSScott Long 
44584c7070dbSScott Long 	return (IFDI_GET_COUNTER(ctx, cnt));
44594c7070dbSScott Long }
44604c7070dbSScott Long 
44614c7070dbSScott Long /*********************************************************************
44624c7070dbSScott Long  *
44634c7070dbSScott Long  *  OTHER FUNCTIONS EXPORTED TO THE STACK
44644c7070dbSScott Long  *
44654c7070dbSScott Long  **********************************************************************/
44664c7070dbSScott Long 
44674c7070dbSScott Long static void
44684c7070dbSScott Long iflib_vlan_register(void *arg, if_t ifp, uint16_t vtag)
44694c7070dbSScott Long {
44704c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
44714c7070dbSScott Long 
44724c7070dbSScott Long 	if ((void *)ctx != arg)
44734c7070dbSScott Long 		return;
44744c7070dbSScott Long 
44754c7070dbSScott Long 	if ((vtag == 0) || (vtag > 4095))
44764c7070dbSScott Long 		return;
44774c7070dbSScott Long 
447853b5b9b0SEric Joyner 	if (iflib_in_detach(ctx))
447953b5b9b0SEric Joyner 		return;
448053b5b9b0SEric Joyner 
44814c7070dbSScott Long 	CTX_LOCK(ctx);
448245818bf1SEric Joyner 	/* Driver may need all untagged packets to be flushed */
448345818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
448445818bf1SEric Joyner 		iflib_stop(ctx);
44854c7070dbSScott Long 	IFDI_VLAN_REGISTER(ctx, vtag);
448645818bf1SEric Joyner 	/* Re-init to load the changes, if required */
448745818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
448845818bf1SEric Joyner 		iflib_init_locked(ctx);
44894c7070dbSScott Long 	CTX_UNLOCK(ctx);
44904c7070dbSScott Long }
44914c7070dbSScott Long 
44924c7070dbSScott Long static void
44934c7070dbSScott Long iflib_vlan_unregister(void *arg, if_t ifp, uint16_t vtag)
44944c7070dbSScott Long {
44954c7070dbSScott Long 	if_ctx_t ctx = if_getsoftc(ifp);
44964c7070dbSScott Long 
44974c7070dbSScott Long 	if ((void *)ctx != arg)
44984c7070dbSScott Long 		return;
44994c7070dbSScott Long 
45004c7070dbSScott Long 	if ((vtag == 0) || (vtag > 4095))
45014c7070dbSScott Long 		return;
45024c7070dbSScott Long 
45034c7070dbSScott Long 	CTX_LOCK(ctx);
450445818bf1SEric Joyner 	/* Driver may need all tagged packets to be flushed */
450545818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
450645818bf1SEric Joyner 		iflib_stop(ctx);
45074c7070dbSScott Long 	IFDI_VLAN_UNREGISTER(ctx, vtag);
450845818bf1SEric Joyner 	/* Re-init to load the changes, if required */
450945818bf1SEric Joyner 	if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG))
451045818bf1SEric Joyner 		iflib_init_locked(ctx);
45114c7070dbSScott Long 	CTX_UNLOCK(ctx);
45124c7070dbSScott Long }
45134c7070dbSScott Long 
45144c7070dbSScott Long static void
45154c7070dbSScott Long iflib_led_func(void *arg, int onoff)
45164c7070dbSScott Long {
45174c7070dbSScott Long 	if_ctx_t ctx = arg;
45184c7070dbSScott Long 
45194c7070dbSScott Long 	CTX_LOCK(ctx);
45204c7070dbSScott Long 	IFDI_LED_FUNC(ctx, onoff);
45214c7070dbSScott Long 	CTX_UNLOCK(ctx);
45224c7070dbSScott Long }
45234c7070dbSScott Long 
45244c7070dbSScott Long /*********************************************************************
45254c7070dbSScott Long  *
45264c7070dbSScott Long  *  BUS FUNCTION DEFINITIONS
45274c7070dbSScott Long  *
45284c7070dbSScott Long  **********************************************************************/
45294c7070dbSScott Long 
45304c7070dbSScott Long int
45314c7070dbSScott Long iflib_device_probe(device_t dev)
45324c7070dbSScott Long {
4533d49e83eaSMarius Strobl 	const pci_vendor_info_t *ent;
45344c7070dbSScott Long 	if_shared_ctx_t sctx;
4535d49e83eaSMarius Strobl 	uint16_t pci_device_id, pci_rev_id, pci_subdevice_id, pci_subvendor_id;
4536d49e83eaSMarius Strobl 	uint16_t pci_vendor_id;
45374c7070dbSScott Long 
45384c7070dbSScott Long 	if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC)
45394c7070dbSScott Long 		return (ENOTSUP);
45404c7070dbSScott Long 
45414c7070dbSScott Long 	pci_vendor_id = pci_get_vendor(dev);
45424c7070dbSScott Long 	pci_device_id = pci_get_device(dev);
45434c7070dbSScott Long 	pci_subvendor_id = pci_get_subvendor(dev);
45444c7070dbSScott Long 	pci_subdevice_id = pci_get_subdevice(dev);
45454c7070dbSScott Long 	pci_rev_id = pci_get_revid(dev);
45464c7070dbSScott Long 	if (sctx->isc_parse_devinfo != NULL)
45474c7070dbSScott Long 		sctx->isc_parse_devinfo(&pci_device_id, &pci_subvendor_id, &pci_subdevice_id, &pci_rev_id);
45484c7070dbSScott Long 
45494c7070dbSScott Long 	ent = sctx->isc_vendor_info;
45504c7070dbSScott Long 	while (ent->pvi_vendor_id != 0) {
45514c7070dbSScott Long 		if (pci_vendor_id != ent->pvi_vendor_id) {
45524c7070dbSScott Long 			ent++;
45534c7070dbSScott Long 			continue;
45544c7070dbSScott Long 		}
45554c7070dbSScott Long 		if ((pci_device_id == ent->pvi_device_id) &&
45564c7070dbSScott Long 		    ((pci_subvendor_id == ent->pvi_subvendor_id) ||
45574c7070dbSScott Long 		     (ent->pvi_subvendor_id == 0)) &&
45584c7070dbSScott Long 		    ((pci_subdevice_id == ent->pvi_subdevice_id) ||
45594c7070dbSScott Long 		     (ent->pvi_subdevice_id == 0)) &&
45604c7070dbSScott Long 		    ((pci_rev_id == ent->pvi_rev_id) ||
45614c7070dbSScott Long 		     (ent->pvi_rev_id == 0))) {
45624c7070dbSScott Long 			device_set_desc_copy(dev, ent->pvi_name);
45634c7070dbSScott Long 			/* this needs to be changed to zero if the bus probing code
45644c7070dbSScott Long 			 * ever stops re-probing on best match because the sctx
45654c7070dbSScott Long 			 * may have its values over written by register calls
45664c7070dbSScott Long 			 * in subsequent probes
45674c7070dbSScott Long 			 */
45684c7070dbSScott Long 			return (BUS_PROBE_DEFAULT);
45694c7070dbSScott Long 		}
45704c7070dbSScott Long 		ent++;
45714c7070dbSScott Long 	}
45724c7070dbSScott Long 	return (ENXIO);
45734c7070dbSScott Long }
45744c7070dbSScott Long 
4575668d6dbbSEric Joyner int
4576668d6dbbSEric Joyner iflib_device_probe_vendor(device_t dev)
4577668d6dbbSEric Joyner {
4578668d6dbbSEric Joyner 	int probe;
4579668d6dbbSEric Joyner 
4580668d6dbbSEric Joyner 	probe = iflib_device_probe(dev);
4581668d6dbbSEric Joyner 	if (probe == BUS_PROBE_DEFAULT)
4582668d6dbbSEric Joyner 		return (BUS_PROBE_VENDOR);
4583668d6dbbSEric Joyner 	else
4584668d6dbbSEric Joyner 		return (probe);
4585668d6dbbSEric Joyner }
4586668d6dbbSEric Joyner 
458709f6ff4fSMatt Macy static void
458809f6ff4fSMatt Macy iflib_reset_qvalues(if_ctx_t ctx)
45894c7070dbSScott Long {
459009f6ff4fSMatt Macy 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
459109f6ff4fSMatt Macy 	if_shared_ctx_t sctx = ctx->ifc_sctx;
459209f6ff4fSMatt Macy 	device_t dev = ctx->ifc_dev;
459346d0f824SMatt Macy 	int i;
45944c7070dbSScott Long 
459523ac9029SStephen Hurd 	if (ctx->ifc_sysctl_ntxqs != 0)
459623ac9029SStephen Hurd 		scctx->isc_ntxqsets = ctx->ifc_sysctl_ntxqs;
459723ac9029SStephen Hurd 	if (ctx->ifc_sysctl_nrxqs != 0)
459823ac9029SStephen Hurd 		scctx->isc_nrxqsets = ctx->ifc_sysctl_nrxqs;
459923ac9029SStephen Hurd 
460023ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_ntxqs; i++) {
460123ac9029SStephen Hurd 		if (ctx->ifc_sysctl_ntxds[i] != 0)
460223ac9029SStephen Hurd 			scctx->isc_ntxd[i] = ctx->ifc_sysctl_ntxds[i];
460323ac9029SStephen Hurd 		else
460423ac9029SStephen Hurd 			scctx->isc_ntxd[i] = sctx->isc_ntxd_default[i];
460523ac9029SStephen Hurd 	}
460623ac9029SStephen Hurd 
460723ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_nrxqs; i++) {
460823ac9029SStephen Hurd 		if (ctx->ifc_sysctl_nrxds[i] != 0)
460923ac9029SStephen Hurd 			scctx->isc_nrxd[i] = ctx->ifc_sysctl_nrxds[i];
461023ac9029SStephen Hurd 		else
461123ac9029SStephen Hurd 			scctx->isc_nrxd[i] = sctx->isc_nrxd_default[i];
461223ac9029SStephen Hurd 	}
461323ac9029SStephen Hurd 
461423ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_nrxqs; i++) {
461523ac9029SStephen Hurd 		if (scctx->isc_nrxd[i] < sctx->isc_nrxd_min[i]) {
461623ac9029SStephen Hurd 			device_printf(dev, "nrxd%d: %d less than nrxd_min %d - resetting to min\n",
461723ac9029SStephen Hurd 				      i, scctx->isc_nrxd[i], sctx->isc_nrxd_min[i]);
461823ac9029SStephen Hurd 			scctx->isc_nrxd[i] = sctx->isc_nrxd_min[i];
461923ac9029SStephen Hurd 		}
462023ac9029SStephen Hurd 		if (scctx->isc_nrxd[i] > sctx->isc_nrxd_max[i]) {
462123ac9029SStephen Hurd 			device_printf(dev, "nrxd%d: %d greater than nrxd_max %d - resetting to max\n",
462223ac9029SStephen Hurd 				      i, scctx->isc_nrxd[i], sctx->isc_nrxd_max[i]);
462323ac9029SStephen Hurd 			scctx->isc_nrxd[i] = sctx->isc_nrxd_max[i];
462423ac9029SStephen Hurd 		}
4625afb77372SEric Joyner 		if (!powerof2(scctx->isc_nrxd[i])) {
4626afb77372SEric Joyner 			device_printf(dev, "nrxd%d: %d is not a power of 2 - using default value of %d\n",
4627afb77372SEric Joyner 				      i, scctx->isc_nrxd[i], sctx->isc_nrxd_default[i]);
4628afb77372SEric Joyner 			scctx->isc_nrxd[i] = sctx->isc_nrxd_default[i];
4629afb77372SEric Joyner 		}
463023ac9029SStephen Hurd 	}
463123ac9029SStephen Hurd 
463223ac9029SStephen Hurd 	for (i = 0; i < sctx->isc_ntxqs; i++) {
463323ac9029SStephen Hurd 		if (scctx->isc_ntxd[i] < sctx->isc_ntxd_min[i]) {
463423ac9029SStephen Hurd 			device_printf(dev, "ntxd%d: %d less than ntxd_min %d - resetting to min\n",
463523ac9029SStephen Hurd 				      i, scctx->isc_ntxd[i], sctx->isc_ntxd_min[i]);
463623ac9029SStephen Hurd 			scctx->isc_ntxd[i] = sctx->isc_ntxd_min[i];
463723ac9029SStephen Hurd 		}
463823ac9029SStephen Hurd 		if (scctx->isc_ntxd[i] > sctx->isc_ntxd_max[i]) {
463923ac9029SStephen Hurd 			device_printf(dev, "ntxd%d: %d greater than ntxd_max %d - resetting to max\n",
464023ac9029SStephen Hurd 				      i, scctx->isc_ntxd[i], sctx->isc_ntxd_max[i]);
464123ac9029SStephen Hurd 			scctx->isc_ntxd[i] = sctx->isc_ntxd_max[i];
464223ac9029SStephen Hurd 		}
4643afb77372SEric Joyner 		if (!powerof2(scctx->isc_ntxd[i])) {
4644afb77372SEric Joyner 			device_printf(dev, "ntxd%d: %d is not a power of 2 - using default value of %d\n",
4645afb77372SEric Joyner 				      i, scctx->isc_ntxd[i], sctx->isc_ntxd_default[i]);
4646afb77372SEric Joyner 			scctx->isc_ntxd[i] = sctx->isc_ntxd_default[i];
4647afb77372SEric Joyner 		}
464823ac9029SStephen Hurd 	}
464909f6ff4fSMatt Macy }
4650ab2e3f79SStephen Hurd 
46516d49b41eSAndrew Gallatin static void
46526d49b41eSAndrew Gallatin iflib_add_pfil(if_ctx_t ctx)
46536d49b41eSAndrew Gallatin {
46546d49b41eSAndrew Gallatin 	struct pfil_head *pfil;
46556d49b41eSAndrew Gallatin 	struct pfil_head_args pa;
46566d49b41eSAndrew Gallatin 	iflib_rxq_t rxq;
46576d49b41eSAndrew Gallatin 	int i;
46586d49b41eSAndrew Gallatin 
46596d49b41eSAndrew Gallatin 	pa.pa_version = PFIL_VERSION;
46606d49b41eSAndrew Gallatin 	pa.pa_flags = PFIL_IN;
46616d49b41eSAndrew Gallatin 	pa.pa_type = PFIL_TYPE_ETHERNET;
46626d49b41eSAndrew Gallatin 	pa.pa_headname = ctx->ifc_ifp->if_xname;
46636d49b41eSAndrew Gallatin 	pfil = pfil_head_register(&pa);
46646d49b41eSAndrew Gallatin 
46656d49b41eSAndrew Gallatin 	for (i = 0, rxq = ctx->ifc_rxqs; i < NRXQSETS(ctx); i++, rxq++) {
46666d49b41eSAndrew Gallatin 		rxq->pfil = pfil;
46676d49b41eSAndrew Gallatin 	}
46686d49b41eSAndrew Gallatin }
46696d49b41eSAndrew Gallatin 
46706d49b41eSAndrew Gallatin static void
46716d49b41eSAndrew Gallatin iflib_rem_pfil(if_ctx_t ctx)
46726d49b41eSAndrew Gallatin {
46736d49b41eSAndrew Gallatin 	struct pfil_head *pfil;
46746d49b41eSAndrew Gallatin 	iflib_rxq_t rxq;
46756d49b41eSAndrew Gallatin 	int i;
46766d49b41eSAndrew Gallatin 
46776d49b41eSAndrew Gallatin 	rxq = ctx->ifc_rxqs;
46786d49b41eSAndrew Gallatin 	pfil = rxq->pfil;
46796d49b41eSAndrew Gallatin 	for (i = 0; i < NRXQSETS(ctx); i++, rxq++) {
46806d49b41eSAndrew Gallatin 		rxq->pfil = NULL;
46816d49b41eSAndrew Gallatin 	}
46826d49b41eSAndrew Gallatin 	pfil_head_unregister(pfil);
46836d49b41eSAndrew Gallatin }
46846d49b41eSAndrew Gallatin 
4685f154ece0SStephen Hurd static uint16_t
4686f154ece0SStephen Hurd get_ctx_core_offset(if_ctx_t ctx)
4687f154ece0SStephen Hurd {
4688f154ece0SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
4689f154ece0SStephen Hurd 	struct cpu_offset *op;
4690f154ece0SStephen Hurd 	uint16_t qc;
4691f154ece0SStephen Hurd 	uint16_t ret = ctx->ifc_sysctl_core_offset;
4692f154ece0SStephen Hurd 
4693f154ece0SStephen Hurd 	if (ret != CORE_OFFSET_UNSPECIFIED)
4694f154ece0SStephen Hurd 		return (ret);
4695f154ece0SStephen Hurd 
4696f154ece0SStephen Hurd 	if (ctx->ifc_sysctl_separate_txrx)
4697f154ece0SStephen Hurd 		qc = scctx->isc_ntxqsets + scctx->isc_nrxqsets;
4698f154ece0SStephen Hurd 	else
4699f154ece0SStephen Hurd 		qc = max(scctx->isc_ntxqsets, scctx->isc_nrxqsets);
4700f154ece0SStephen Hurd 
4701f154ece0SStephen Hurd 	mtx_lock(&cpu_offset_mtx);
4702f154ece0SStephen Hurd 	SLIST_FOREACH(op, &cpu_offsets, entries) {
4703f154ece0SStephen Hurd 		if (CPU_CMP(&ctx->ifc_cpus, &op->set) == 0) {
4704f154ece0SStephen Hurd 			ret = op->offset;
4705f154ece0SStephen Hurd 			op->offset += qc;
4706f154ece0SStephen Hurd 			MPASS(op->refcount < UINT_MAX);
4707f154ece0SStephen Hurd 			op->refcount++;
4708f154ece0SStephen Hurd 			break;
4709f154ece0SStephen Hurd 		}
4710f154ece0SStephen Hurd 	}
4711f154ece0SStephen Hurd 	if (ret == CORE_OFFSET_UNSPECIFIED) {
4712f154ece0SStephen Hurd 		ret = 0;
4713f154ece0SStephen Hurd 		op = malloc(sizeof(struct cpu_offset), M_IFLIB,
4714f154ece0SStephen Hurd 		    M_NOWAIT | M_ZERO);
4715f154ece0SStephen Hurd 		if (op == NULL) {
4716f154ece0SStephen Hurd 			device_printf(ctx->ifc_dev,
4717f154ece0SStephen Hurd 			    "allocation for cpu offset failed.\n");
4718f154ece0SStephen Hurd 		} else {
4719f154ece0SStephen Hurd 			op->offset = qc;
4720f154ece0SStephen Hurd 			op->refcount = 1;
4721f154ece0SStephen Hurd 			CPU_COPY(&ctx->ifc_cpus, &op->set);
4722f154ece0SStephen Hurd 			SLIST_INSERT_HEAD(&cpu_offsets, op, entries);
4723f154ece0SStephen Hurd 		}
4724f154ece0SStephen Hurd 	}
4725f154ece0SStephen Hurd 	mtx_unlock(&cpu_offset_mtx);
4726f154ece0SStephen Hurd 
4727f154ece0SStephen Hurd 	return (ret);
4728f154ece0SStephen Hurd }
4729f154ece0SStephen Hurd 
4730f154ece0SStephen Hurd static void
4731f154ece0SStephen Hurd unref_ctx_core_offset(if_ctx_t ctx)
4732f154ece0SStephen Hurd {
4733f154ece0SStephen Hurd 	struct cpu_offset *op, *top;
4734f154ece0SStephen Hurd 
4735f154ece0SStephen Hurd 	mtx_lock(&cpu_offset_mtx);
4736f154ece0SStephen Hurd 	SLIST_FOREACH_SAFE(op, &cpu_offsets, entries, top) {
4737f154ece0SStephen Hurd 		if (CPU_CMP(&ctx->ifc_cpus, &op->set) == 0) {
4738f154ece0SStephen Hurd 			MPASS(op->refcount > 0);
4739f154ece0SStephen Hurd 			op->refcount--;
4740f154ece0SStephen Hurd 			if (op->refcount == 0) {
4741f154ece0SStephen Hurd 				SLIST_REMOVE(&cpu_offsets, op, cpu_offset, entries);
4742f154ece0SStephen Hurd 				free(op, M_IFLIB);
4743f154ece0SStephen Hurd 			}
4744f154ece0SStephen Hurd 			break;
4745f154ece0SStephen Hurd 		}
4746f154ece0SStephen Hurd 	}
4747f154ece0SStephen Hurd 	mtx_unlock(&cpu_offset_mtx);
4748f154ece0SStephen Hurd }
4749f154ece0SStephen Hurd 
475009f6ff4fSMatt Macy int
475109f6ff4fSMatt Macy iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ctxp)
475209f6ff4fSMatt Macy {
475309f6ff4fSMatt Macy 	if_ctx_t ctx;
475409f6ff4fSMatt Macy 	if_t ifp;
475509f6ff4fSMatt Macy 	if_softc_ctx_t scctx;
47563d10e9edSMarius Strobl 	kobjop_desc_t kobj_desc;
47573d10e9edSMarius Strobl 	kobj_method_t *kobj_method;
4758afb77372SEric Joyner 	int err, msix, rid;
4759ac11d857SVincenzo Maffione 	int num_txd, num_rxd;
476009f6ff4fSMatt Macy 
476109f6ff4fSMatt Macy 	ctx = malloc(sizeof(* ctx), M_IFLIB, M_WAITOK|M_ZERO);
476209f6ff4fSMatt Macy 
476309f6ff4fSMatt Macy 	if (sc == NULL) {
476409f6ff4fSMatt Macy 		sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK|M_ZERO);
476509f6ff4fSMatt Macy 		device_set_softc(dev, ctx);
476609f6ff4fSMatt Macy 		ctx->ifc_flags |= IFC_SC_ALLOCATED;
476709f6ff4fSMatt Macy 	}
476809f6ff4fSMatt Macy 
476909f6ff4fSMatt Macy 	ctx->ifc_sctx = sctx;
477009f6ff4fSMatt Macy 	ctx->ifc_dev = dev;
477109f6ff4fSMatt Macy 	ctx->ifc_softc = sc;
477209f6ff4fSMatt Macy 
477309f6ff4fSMatt Macy 	if ((err = iflib_register(ctx)) != 0) {
477409f6ff4fSMatt Macy 		device_printf(dev, "iflib_register failed %d\n", err);
47757f3eb9daSPatrick Kelsey 		goto fail_ctx_free;
477609f6ff4fSMatt Macy 	}
477709f6ff4fSMatt Macy 	iflib_add_device_sysctl_pre(ctx);
477809f6ff4fSMatt Macy 
477909f6ff4fSMatt Macy 	scctx = &ctx->ifc_softc_ctx;
478009f6ff4fSMatt Macy 	ifp = ctx->ifc_ifp;
478109f6ff4fSMatt Macy 
478209f6ff4fSMatt Macy 	iflib_reset_qvalues(ctx);
4783aa8a24d3SStephen Hurd 	CTX_LOCK(ctx);
4784ab2e3f79SStephen Hurd 	if ((err = IFDI_ATTACH_PRE(ctx)) != 0) {
47854c7070dbSScott Long 		device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err);
47867f3eb9daSPatrick Kelsey 		goto fail_unlock;
47874c7070dbSScott Long 	}
47881248952aSSean Bruno 	_iflib_pre_assert(scctx);
47891248952aSSean Bruno 	ctx->ifc_txrx = *scctx->isc_txrx;
47901248952aSSean Bruno 
4791ef567155SMarcin Wojtas 	MPASS(scctx->isc_dma_width <= flsll(BUS_SPACE_MAXADDR));
47926dd69f00SMarcin Wojtas 
4793e2621d96SMatt Macy 	if (sctx->isc_flags & IFLIB_DRIVER_MEDIA)
4794e2621d96SMatt Macy 		ctx->ifc_mediap = scctx->isc_media;
4795e2621d96SMatt Macy 
47961248952aSSean Bruno #ifdef INVARIANTS
47977f87c040SMarius Strobl 	if (scctx->isc_capabilities & IFCAP_TXCSUM)
47981248952aSSean Bruno 		MPASS(scctx->isc_tx_csum_flags);
47991248952aSSean Bruno #endif
48001248952aSSean Bruno 
48016554362cSAndrew Gallatin 	if_setcapabilities(ifp,
48023f43ada9SGleb Smirnoff 	    scctx->isc_capabilities | IFCAP_HWSTATS | IFCAP_MEXTPG);
48036554362cSAndrew Gallatin 	if_setcapenable(ifp,
48043f43ada9SGleb Smirnoff 	    scctx->isc_capenable | IFCAP_HWSTATS | IFCAP_MEXTPG);
48051248952aSSean Bruno 
48061248952aSSean Bruno 	if (scctx->isc_ntxqsets == 0 || (scctx->isc_ntxqsets_max && scctx->isc_ntxqsets_max < scctx->isc_ntxqsets))
48071248952aSSean Bruno 		scctx->isc_ntxqsets = scctx->isc_ntxqsets_max;
48081248952aSSean Bruno 	if (scctx->isc_nrxqsets == 0 || (scctx->isc_nrxqsets_max && scctx->isc_nrxqsets_max < scctx->isc_nrxqsets))
48091248952aSSean Bruno 		scctx->isc_nrxqsets = scctx->isc_nrxqsets_max;
481023ac9029SStephen Hurd 
4811ac11d857SVincenzo Maffione 	num_txd = iflib_num_tx_descs(ctx);
4812ac11d857SVincenzo Maffione 	num_rxd = iflib_num_rx_descs(ctx);
481323ac9029SStephen Hurd 
481423ac9029SStephen Hurd 	/* XXX change for per-queue sizes */
48151722eeacSMarius Strobl 	device_printf(dev, "Using %d TX descriptors and %d RX descriptors\n",
4816ac11d857SVincenzo Maffione 	    num_txd, num_rxd);
481723ac9029SStephen Hurd 
4818ac11d857SVincenzo Maffione 	if (scctx->isc_tx_nsegments > num_txd / MAX_SINGLE_PACKET_FRACTION)
4819ac11d857SVincenzo Maffione 		scctx->isc_tx_nsegments = max(1, num_txd /
482023ac9029SStephen Hurd 		    MAX_SINGLE_PACKET_FRACTION);
4821ac11d857SVincenzo Maffione 	if (scctx->isc_tx_tso_segments_max > num_txd /
482223ac9029SStephen Hurd 	    MAX_SINGLE_PACKET_FRACTION)
482323ac9029SStephen Hurd 		scctx->isc_tx_tso_segments_max = max(1,
4824ac11d857SVincenzo Maffione 		    num_txd / MAX_SINGLE_PACKET_FRACTION);
48254c7070dbSScott Long 
48264c7070dbSScott Long 	/* TSO parameters - dig these out of the data sheet - simply correspond to tag setup */
48277f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_TSO) {
48287f87c040SMarius Strobl 		/*
48297f87c040SMarius Strobl 		 * The stack can't handle a TSO size larger than IP_MAXPACKET,
48307f87c040SMarius Strobl 		 * but some MACs do.
48317f87c040SMarius Strobl 		 */
48327f87c040SMarius Strobl 		if_sethwtsomax(ifp, min(scctx->isc_tx_tso_size_max,
48337f87c040SMarius Strobl 		    IP_MAXPACKET));
48347f87c040SMarius Strobl 		/*
48357f87c040SMarius Strobl 		 * Take maximum number of m_pullup(9)'s in iflib_parse_header()
48367f87c040SMarius Strobl 		 * into account.  In the worst case, each of these calls will
48377f87c040SMarius Strobl 		 * add another mbuf and, thus, the requirement for another DMA
48387f87c040SMarius Strobl 		 * segment.  So for best performance, it doesn't make sense to
48397f87c040SMarius Strobl 		 * advertize a maximum of TSO segments that typically will
48407f87c040SMarius Strobl 		 * require defragmentation in iflib_encap().
48417f87c040SMarius Strobl 		 */
48427f87c040SMarius Strobl 		if_sethwtsomaxsegcount(ifp, scctx->isc_tx_tso_segments_max - 3);
48437f87c040SMarius Strobl 		if_sethwtsomaxsegsize(ifp, scctx->isc_tx_tso_segsize_max);
48447f87c040SMarius Strobl 	}
48454c7070dbSScott Long 	if (scctx->isc_rss_table_size == 0)
48464c7070dbSScott Long 		scctx->isc_rss_table_size = 64;
484723ac9029SStephen Hurd 	scctx->isc_rss_table_mask = scctx->isc_rss_table_size-1;
4848da69b8f9SSean Bruno 
4849da69b8f9SSean Bruno 	GROUPTASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
4850da69b8f9SSean Bruno 	/* XXX format name */
4851f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_config_tqg, &ctx->ifc_admin_task, ctx,
4852f855ec81SMarius Strobl 	    NULL, NULL, "admin");
4853e516b535SStephen Hurd 
4854772593dbSStephen Hurd 	/* Set up cpu set.  If it fails, use the set of all CPUs. */
4855e516b535SStephen Hurd 	if (bus_get_cpus(dev, INTR_CPUS, sizeof(ctx->ifc_cpus), &ctx->ifc_cpus) != 0) {
4856e516b535SStephen Hurd 		device_printf(dev, "Unable to fetch CPU list\n");
4857e516b535SStephen Hurd 		CPU_COPY(&all_cpus, &ctx->ifc_cpus);
4858e516b535SStephen Hurd 	}
4859e516b535SStephen Hurd 	MPASS(CPU_COUNT(&ctx->ifc_cpus) > 0);
4860e516b535SStephen Hurd 
48614c7070dbSScott Long 	/*
4862b97de13aSMarius Strobl 	** Now set up MSI or MSI-X, should return us the number of supported
4863b97de13aSMarius Strobl 	** vectors (will be 1 for a legacy interrupt and MSI).
48644c7070dbSScott Long 	*/
48654c7070dbSScott Long 	if (sctx->isc_flags & IFLIB_SKIP_MSIX) {
48664c7070dbSScott Long 		msix = scctx->isc_vectors;
48674c7070dbSScott Long 	} else if (scctx->isc_msix_bar != 0)
4868f7ae9a84SSean Bruno 	       /*
4869f7ae9a84SSean Bruno 		* The simple fact that isc_msix_bar is not 0 does not mean we
4870f7ae9a84SSean Bruno 		* we have a good value there that is known to work.
4871f7ae9a84SSean Bruno 		*/
48724c7070dbSScott Long 		msix = iflib_msix_init(ctx);
48734c7070dbSScott Long 	else {
48744c7070dbSScott Long 		scctx->isc_vectors = 1;
48754c7070dbSScott Long 		scctx->isc_ntxqsets = 1;
48764c7070dbSScott Long 		scctx->isc_nrxqsets = 1;
48774c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_LEGACY;
48784c7070dbSScott Long 		msix = 0;
48794c7070dbSScott Long 	}
48804c7070dbSScott Long 	/* Get memory for the station queues */
48814c7070dbSScott Long 	if ((err = iflib_queues_alloc(ctx))) {
48824c7070dbSScott Long 		device_printf(dev, "Unable to allocate queue memory\n");
48837f3eb9daSPatrick Kelsey 		goto fail_intr_free;
48844c7070dbSScott Long 	}
48854c7070dbSScott Long 
4886ac88e6daSStephen Hurd 	if ((err = iflib_qset_structures_setup(ctx)))
48874c7070dbSScott Long 		goto fail_queues;
488869b7fc3eSSean Bruno 
4889bd84f700SSean Bruno 	/*
4890f154ece0SStephen Hurd 	 * Now that we know how many queues there are, get the core offset.
4891f154ece0SStephen Hurd 	 */
4892f154ece0SStephen Hurd 	ctx->ifc_sysctl_core_offset = get_ctx_core_offset(ctx);
4893f154ece0SStephen Hurd 
48943d10e9edSMarius Strobl 	if (msix > 1) {
48953d10e9edSMarius Strobl 		/*
48963d10e9edSMarius Strobl 		 * When using MSI-X, ensure that ifdi_{r,t}x_queue_intr_enable
48973d10e9edSMarius Strobl 		 * aren't the default NULL implementation.
48983d10e9edSMarius Strobl 		 */
48993d10e9edSMarius Strobl 		kobj_desc = &ifdi_rx_queue_intr_enable_desc;
49003d10e9edSMarius Strobl 		kobj_method = kobj_lookup_method(((kobj_t)ctx)->ops->cls, NULL,
49013d10e9edSMarius Strobl 		    kobj_desc);
49023d10e9edSMarius Strobl 		if (kobj_method == &kobj_desc->deflt) {
49033d10e9edSMarius Strobl 			device_printf(dev,
49043d10e9edSMarius Strobl 			    "MSI-X requires ifdi_rx_queue_intr_enable method");
49053d10e9edSMarius Strobl 			err = EOPNOTSUPP;
49067f3eb9daSPatrick Kelsey 			goto fail_queues;
49074c7070dbSScott Long 		}
49083d10e9edSMarius Strobl 		kobj_desc = &ifdi_tx_queue_intr_enable_desc;
49093d10e9edSMarius Strobl 		kobj_method = kobj_lookup_method(((kobj_t)ctx)->ops->cls, NULL,
49103d10e9edSMarius Strobl 		    kobj_desc);
49113d10e9edSMarius Strobl 		if (kobj_method == &kobj_desc->deflt) {
49123d10e9edSMarius Strobl 			device_printf(dev,
49133d10e9edSMarius Strobl 			    "MSI-X requires ifdi_tx_queue_intr_enable method");
49143d10e9edSMarius Strobl 			err = EOPNOTSUPP;
49153d10e9edSMarius Strobl 			goto fail_queues;
49163d10e9edSMarius Strobl 		}
49173d10e9edSMarius Strobl 
49183d10e9edSMarius Strobl 		/*
49193d10e9edSMarius Strobl 		 * Assign the MSI-X vectors.
49203d10e9edSMarius Strobl 		 * Note that the default NULL ifdi_msix_intr_assign method will
49213d10e9edSMarius Strobl 		 * fail here, too.
49223d10e9edSMarius Strobl 		 */
49233d10e9edSMarius Strobl 		err = IFDI_MSIX_INTR_ASSIGN(ctx, msix);
49243d10e9edSMarius Strobl 		if (err != 0) {
49253d10e9edSMarius Strobl 			device_printf(dev, "IFDI_MSIX_INTR_ASSIGN failed %d\n",
49263d10e9edSMarius Strobl 			    err);
49273d10e9edSMarius Strobl 			goto fail_queues;
49283d10e9edSMarius Strobl 		}
4929197c6798SEric Joyner 	} else if (scctx->isc_intr != IFLIB_INTR_MSIX) {
49304c7070dbSScott Long 		rid = 0;
49314c7070dbSScott Long 		if (scctx->isc_intr == IFLIB_INTR_MSI) {
49324c7070dbSScott Long 			MPASS(msix == 1);
49334c7070dbSScott Long 			rid = 1;
49344c7070dbSScott Long 		}
493523ac9029SStephen Hurd 		if ((err = iflib_legacy_setup(ctx, ctx->isc_legacy_intr, ctx->ifc_softc, &rid, "irq0")) != 0) {
49364c7070dbSScott Long 			device_printf(dev, "iflib_legacy_setup failed %d\n", err);
49377f3eb9daSPatrick Kelsey 			goto fail_queues;
49384c7070dbSScott Long 		}
4939197c6798SEric Joyner 	} else {
4940197c6798SEric Joyner 		device_printf(dev,
4941197c6798SEric Joyner 		    "Cannot use iflib with only 1 MSI-X interrupt!\n");
4942197c6798SEric Joyner 		err = ENODEV;
494338bfc6deSSai Rajesh Tallamraju 		goto fail_queues;
49444c7070dbSScott Long 	}
49457f87c040SMarius Strobl 
49461fd8c72cSKyle Evans 	ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet);
49477f87c040SMarius Strobl 
4948ab2e3f79SStephen Hurd 	if ((err = IFDI_ATTACH_POST(ctx)) != 0) {
49494c7070dbSScott Long 		device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
49504c7070dbSScott Long 		goto fail_detach;
49514c7070dbSScott Long 	}
49527f87c040SMarius Strobl 
49537f87c040SMarius Strobl 	/*
49547f87c040SMarius Strobl 	 * Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.
49557f87c040SMarius Strobl 	 * This must appear after the call to ether_ifattach() because
49567f87c040SMarius Strobl 	 * ether_ifattach() sets if_hdrlen to the default value.
49577f87c040SMarius Strobl 	 */
49587f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_VLAN_MTU)
49597f87c040SMarius Strobl 		if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
49607f87c040SMarius Strobl 
49614c7070dbSScott Long 	if ((err = iflib_netmap_attach(ctx))) {
49624c7070dbSScott Long 		device_printf(ctx->ifc_dev, "netmap attach failed: %d\n", err);
49634c7070dbSScott Long 		goto fail_detach;
49644c7070dbSScott Long 	}
49654c7070dbSScott Long 	*ctxp = ctx;
49664c7070dbSScott Long 
49677790c8c1SConrad Meyer 	DEBUGNET_SET(ctx->ifc_ifp, iflib);
496894618825SMark Johnston 
496923ac9029SStephen Hurd 	if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
49704c7070dbSScott Long 	iflib_add_device_sysctl_post(ctx);
49716d49b41eSAndrew Gallatin 	iflib_add_pfil(ctx);
49724ecb427aSSean Bruno 	ctx->ifc_flags |= IFC_INIT_DONE;
4973aa8a24d3SStephen Hurd 	CTX_UNLOCK(ctx);
49743d10e9edSMarius Strobl 
49754c7070dbSScott Long 	return (0);
497677c1fcecSEric Joyner 
49774c7070dbSScott Long fail_detach:
49784c7070dbSScott Long 	ether_ifdetach(ctx->ifc_ifp);
49794c7070dbSScott Long fail_queues:
498038bfc6deSSai Rajesh Tallamraju 	iflib_tqg_detach(ctx);
49816108c013SStephen Hurd 	iflib_tx_structures_free(ctx);
49826108c013SStephen Hurd 	iflib_rx_structures_free(ctx);
49834c7070dbSScott Long 	IFDI_DETACH(ctx);
498438bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
498538bfc6deSSai Rajesh Tallamraju fail_intr_free:
498638bfc6deSSai Rajesh Tallamraju 	iflib_free_intr_mem(ctx);
49877f3eb9daSPatrick Kelsey fail_unlock:
4988aa8a24d3SStephen Hurd 	CTX_UNLOCK(ctx);
498956614414SEric Joyner 	iflib_deregister(ctx);
49907f3eb9daSPatrick Kelsey fail_ctx_free:
49917f3f6aadSEric Joyner 	device_set_softc(ctx->ifc_dev, NULL);
49927f3eb9daSPatrick Kelsey         if (ctx->ifc_flags & IFC_SC_ALLOCATED)
49937f3eb9daSPatrick Kelsey                 free(ctx->ifc_softc, M_IFLIB);
49947f3eb9daSPatrick Kelsey         free(ctx, M_IFLIB);
49954c7070dbSScott Long 	return (err);
49964c7070dbSScott Long }
49974c7070dbSScott Long 
49984c7070dbSScott Long int
499909f6ff4fSMatt Macy iflib_pseudo_register(device_t dev, if_shared_ctx_t sctx, if_ctx_t *ctxp,
500009f6ff4fSMatt Macy 					  struct iflib_cloneattach_ctx *clctx)
500109f6ff4fSMatt Macy {
5002ac11d857SVincenzo Maffione 	int num_txd, num_rxd;
500309f6ff4fSMatt Macy 	int err;
500409f6ff4fSMatt Macy 	if_ctx_t ctx;
500509f6ff4fSMatt Macy 	if_t ifp;
500609f6ff4fSMatt Macy 	if_softc_ctx_t scctx;
500709f6ff4fSMatt Macy 	int i;
500809f6ff4fSMatt Macy 	void *sc;
500909f6ff4fSMatt Macy 
501009f6ff4fSMatt Macy 	ctx = malloc(sizeof(*ctx), M_IFLIB, M_WAITOK|M_ZERO);
501109f6ff4fSMatt Macy 	sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK|M_ZERO);
501209f6ff4fSMatt Macy 	ctx->ifc_flags |= IFC_SC_ALLOCATED;
501309f6ff4fSMatt Macy 	if (sctx->isc_flags & (IFLIB_PSEUDO|IFLIB_VIRTUAL))
501409f6ff4fSMatt Macy 		ctx->ifc_flags |= IFC_PSEUDO;
501509f6ff4fSMatt Macy 
501609f6ff4fSMatt Macy 	ctx->ifc_sctx = sctx;
501709f6ff4fSMatt Macy 	ctx->ifc_softc = sc;
501809f6ff4fSMatt Macy 	ctx->ifc_dev = dev;
501909f6ff4fSMatt Macy 
502009f6ff4fSMatt Macy 	if ((err = iflib_register(ctx)) != 0) {
502109f6ff4fSMatt Macy 		device_printf(dev, "%s: iflib_register failed %d\n", __func__, err);
50227f3eb9daSPatrick Kelsey 		goto fail_ctx_free;
502309f6ff4fSMatt Macy 	}
502409f6ff4fSMatt Macy 	iflib_add_device_sysctl_pre(ctx);
502509f6ff4fSMatt Macy 
502609f6ff4fSMatt Macy 	scctx = &ctx->ifc_softc_ctx;
502709f6ff4fSMatt Macy 	ifp = ctx->ifc_ifp;
502809f6ff4fSMatt Macy 
502909f6ff4fSMatt Macy 	iflib_reset_qvalues(ctx);
5030aac9c817SEric Joyner 	CTX_LOCK(ctx);
503109f6ff4fSMatt Macy 	if ((err = IFDI_ATTACH_PRE(ctx)) != 0) {
503209f6ff4fSMatt Macy 		device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err);
5033aac9c817SEric Joyner 		goto fail_unlock;
503409f6ff4fSMatt Macy 	}
503509f6ff4fSMatt Macy 	if (sctx->isc_flags & IFLIB_GEN_MAC)
50361fd8c72cSKyle Evans 		ether_gen_addr(ifp, &ctx->ifc_mac);
503709f6ff4fSMatt Macy 	if ((err = IFDI_CLONEATTACH(ctx, clctx->cc_ifc, clctx->cc_name,
503809f6ff4fSMatt Macy 								clctx->cc_params)) != 0) {
503909f6ff4fSMatt Macy 		device_printf(dev, "IFDI_CLONEATTACH failed %d\n", err);
50409aeca213SMatt Macy 		goto fail_unlock;
504109f6ff4fSMatt Macy 	}
504209f6ff4fSMatt Macy #ifdef INVARIANTS
50437f87c040SMarius Strobl 	if (scctx->isc_capabilities & IFCAP_TXCSUM)
504409f6ff4fSMatt Macy 		MPASS(scctx->isc_tx_csum_flags);
504509f6ff4fSMatt Macy #endif
504609f6ff4fSMatt Macy 
50477f87c040SMarius Strobl 	if_setcapabilities(ifp, scctx->isc_capabilities | IFCAP_HWSTATS | IFCAP_LINKSTATE);
504809f6ff4fSMatt Macy 	if_setcapenable(ifp, scctx->isc_capenable | IFCAP_HWSTATS | IFCAP_LINKSTATE);
504909f6ff4fSMatt Macy 
505009f6ff4fSMatt Macy 	ifp->if_flags |= IFF_NOGROUP;
505109f6ff4fSMatt Macy 	if (sctx->isc_flags & IFLIB_PSEUDO) {
50529aeca213SMatt Macy 		ifmedia_add(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO, 0, NULL);
50539aeca213SMatt Macy 		ifmedia_set(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO);
50549aeca213SMatt Macy 		if (sctx->isc_flags & IFLIB_PSEUDO_ETHER) {
50551fd8c72cSKyle Evans 			ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet);
50569aeca213SMatt Macy 		} else {
50579aeca213SMatt Macy 			if_attach(ctx->ifc_ifp);
50589aeca213SMatt Macy 			bpfattach(ctx->ifc_ifp, DLT_NULL, sizeof(u_int32_t));
50599aeca213SMatt Macy 		}
506009f6ff4fSMatt Macy 
506109f6ff4fSMatt Macy 		if ((err = IFDI_ATTACH_POST(ctx)) != 0) {
506209f6ff4fSMatt Macy 			device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
506309f6ff4fSMatt Macy 			goto fail_detach;
506409f6ff4fSMatt Macy 		}
506509f6ff4fSMatt Macy 		*ctxp = ctx;
506609f6ff4fSMatt Macy 
50677f87c040SMarius Strobl 		/*
50687f87c040SMarius Strobl 		 * Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.
50697f87c040SMarius Strobl 		 * This must appear after the call to ether_ifattach() because
50707f87c040SMarius Strobl 		 * ether_ifattach() sets if_hdrlen to the default value.
50717f87c040SMarius Strobl 		 */
50727f87c040SMarius Strobl 		if (if_getcapabilities(ifp) & IFCAP_VLAN_MTU)
50737f87c040SMarius Strobl 			if_setifheaderlen(ifp,
50747f87c040SMarius Strobl 			    sizeof(struct ether_vlan_header));
50757f87c040SMarius Strobl 
507609f6ff4fSMatt Macy 		if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
507709f6ff4fSMatt Macy 		iflib_add_device_sysctl_post(ctx);
507809f6ff4fSMatt Macy 		ctx->ifc_flags |= IFC_INIT_DONE;
50791f93e931SMatt Macy 		CTX_UNLOCK(ctx);
508009f6ff4fSMatt Macy 		return (0);
508109f6ff4fSMatt Macy 	}
50829aeca213SMatt Macy 	ifmedia_add(ctx->ifc_mediap, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
50839aeca213SMatt Macy 	ifmedia_add(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO, 0, NULL);
50849aeca213SMatt Macy 	ifmedia_set(ctx->ifc_mediap, IFM_ETHER | IFM_AUTO);
50859aeca213SMatt Macy 
508609f6ff4fSMatt Macy 	_iflib_pre_assert(scctx);
508709f6ff4fSMatt Macy 	ctx->ifc_txrx = *scctx->isc_txrx;
508809f6ff4fSMatt Macy 
508909f6ff4fSMatt Macy 	if (scctx->isc_ntxqsets == 0 || (scctx->isc_ntxqsets_max && scctx->isc_ntxqsets_max < scctx->isc_ntxqsets))
509009f6ff4fSMatt Macy 		scctx->isc_ntxqsets = scctx->isc_ntxqsets_max;
509109f6ff4fSMatt Macy 	if (scctx->isc_nrxqsets == 0 || (scctx->isc_nrxqsets_max && scctx->isc_nrxqsets_max < scctx->isc_nrxqsets))
509209f6ff4fSMatt Macy 		scctx->isc_nrxqsets = scctx->isc_nrxqsets_max;
509309f6ff4fSMatt Macy 
5094ac11d857SVincenzo Maffione 	num_txd = iflib_num_tx_descs(ctx);
5095ac11d857SVincenzo Maffione 	num_rxd = iflib_num_rx_descs(ctx);
509609f6ff4fSMatt Macy 
509709f6ff4fSMatt Macy 	/* XXX change for per-queue sizes */
50981722eeacSMarius Strobl 	device_printf(dev, "Using %d TX descriptors and %d RX descriptors\n",
5099ac11d857SVincenzo Maffione 	    num_txd, num_rxd);
510009f6ff4fSMatt Macy 
5101ac11d857SVincenzo Maffione 	if (scctx->isc_tx_nsegments > num_txd / MAX_SINGLE_PACKET_FRACTION)
5102ac11d857SVincenzo Maffione 		scctx->isc_tx_nsegments = max(1, num_txd /
510309f6ff4fSMatt Macy 		    MAX_SINGLE_PACKET_FRACTION);
5104ac11d857SVincenzo Maffione 	if (scctx->isc_tx_tso_segments_max > num_txd /
510509f6ff4fSMatt Macy 	    MAX_SINGLE_PACKET_FRACTION)
510609f6ff4fSMatt Macy 		scctx->isc_tx_tso_segments_max = max(1,
5107ac11d857SVincenzo Maffione 		    num_txd / MAX_SINGLE_PACKET_FRACTION);
510809f6ff4fSMatt Macy 
510909f6ff4fSMatt Macy 	/* TSO parameters - dig these out of the data sheet - simply correspond to tag setup */
51107f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_TSO) {
51117f87c040SMarius Strobl 		/*
51127f87c040SMarius Strobl 		 * The stack can't handle a TSO size larger than IP_MAXPACKET,
51137f87c040SMarius Strobl 		 * but some MACs do.
51147f87c040SMarius Strobl 		 */
51157f87c040SMarius Strobl 		if_sethwtsomax(ifp, min(scctx->isc_tx_tso_size_max,
51167f87c040SMarius Strobl 		    IP_MAXPACKET));
51177f87c040SMarius Strobl 		/*
51187f87c040SMarius Strobl 		 * Take maximum number of m_pullup(9)'s in iflib_parse_header()
51197f87c040SMarius Strobl 		 * into account.  In the worst case, each of these calls will
51207f87c040SMarius Strobl 		 * add another mbuf and, thus, the requirement for another DMA
51217f87c040SMarius Strobl 		 * segment.  So for best performance, it doesn't make sense to
51227f87c040SMarius Strobl 		 * advertize a maximum of TSO segments that typically will
51237f87c040SMarius Strobl 		 * require defragmentation in iflib_encap().
51247f87c040SMarius Strobl 		 */
51257f87c040SMarius Strobl 		if_sethwtsomaxsegcount(ifp, scctx->isc_tx_tso_segments_max - 3);
51267f87c040SMarius Strobl 		if_sethwtsomaxsegsize(ifp, scctx->isc_tx_tso_segsize_max);
51277f87c040SMarius Strobl 	}
512809f6ff4fSMatt Macy 	if (scctx->isc_rss_table_size == 0)
512909f6ff4fSMatt Macy 		scctx->isc_rss_table_size = 64;
513009f6ff4fSMatt Macy 	scctx->isc_rss_table_mask = scctx->isc_rss_table_size-1;
513109f6ff4fSMatt Macy 
513209f6ff4fSMatt Macy 	GROUPTASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
513309f6ff4fSMatt Macy 	/* XXX format name */
5134f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_config_tqg, &ctx->ifc_admin_task, ctx,
5135f855ec81SMarius Strobl 	    NULL, NULL, "admin");
513609f6ff4fSMatt Macy 
513709f6ff4fSMatt Macy 	/* XXX --- can support > 1 -- but keep it simple for now */
513809f6ff4fSMatt Macy 	scctx->isc_intr = IFLIB_INTR_LEGACY;
513909f6ff4fSMatt Macy 
514009f6ff4fSMatt Macy 	/* Get memory for the station queues */
514109f6ff4fSMatt Macy 	if ((err = iflib_queues_alloc(ctx))) {
514209f6ff4fSMatt Macy 		device_printf(dev, "Unable to allocate queue memory\n");
51437f3eb9daSPatrick Kelsey 		goto fail_iflib_detach;
514409f6ff4fSMatt Macy 	}
514509f6ff4fSMatt Macy 
514609f6ff4fSMatt Macy 	if ((err = iflib_qset_structures_setup(ctx))) {
514709f6ff4fSMatt Macy 		device_printf(dev, "qset structure setup failed %d\n", err);
514809f6ff4fSMatt Macy 		goto fail_queues;
514909f6ff4fSMatt Macy 	}
51507f87c040SMarius Strobl 
515109f6ff4fSMatt Macy 	/*
515209f6ff4fSMatt Macy 	 * XXX What if anything do we want to do about interrupts?
515309f6ff4fSMatt Macy 	 */
51541fd8c72cSKyle Evans 	ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet);
515509f6ff4fSMatt Macy 	if ((err = IFDI_ATTACH_POST(ctx)) != 0) {
515609f6ff4fSMatt Macy 		device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err);
515709f6ff4fSMatt Macy 		goto fail_detach;
515809f6ff4fSMatt Macy 	}
51597f87c040SMarius Strobl 
51607f87c040SMarius Strobl 	/*
51617f87c040SMarius Strobl 	 * Tell the upper layer(s) if IFCAP_VLAN_MTU is supported.
51627f87c040SMarius Strobl 	 * This must appear after the call to ether_ifattach() because
51637f87c040SMarius Strobl 	 * ether_ifattach() sets if_hdrlen to the default value.
51647f87c040SMarius Strobl 	 */
51657f87c040SMarius Strobl 	if (if_getcapabilities(ifp) & IFCAP_VLAN_MTU)
51667f87c040SMarius Strobl 		if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
51677f87c040SMarius Strobl 
516809f6ff4fSMatt Macy 	/* XXX handle more than one queue */
516909f6ff4fSMatt Macy 	for (i = 0; i < scctx->isc_nrxqsets; i++)
517009f6ff4fSMatt Macy 		IFDI_RX_CLSET(ctx, 0, i, ctx->ifc_rxqs[i].ifr_fl[0].ifl_sds.ifsd_cl);
517109f6ff4fSMatt Macy 
517209f6ff4fSMatt Macy 	*ctxp = ctx;
517309f6ff4fSMatt Macy 
517409f6ff4fSMatt Macy 	if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
517509f6ff4fSMatt Macy 	iflib_add_device_sysctl_post(ctx);
517609f6ff4fSMatt Macy 	ctx->ifc_flags |= IFC_INIT_DONE;
5177aac9c817SEric Joyner 	CTX_UNLOCK(ctx);
51783d10e9edSMarius Strobl 
517909f6ff4fSMatt Macy 	return (0);
518009f6ff4fSMatt Macy fail_detach:
518109f6ff4fSMatt Macy 	ether_ifdetach(ctx->ifc_ifp);
518209f6ff4fSMatt Macy fail_queues:
518338bfc6deSSai Rajesh Tallamraju 	iflib_tqg_detach(ctx);
518409f6ff4fSMatt Macy 	iflib_tx_structures_free(ctx);
518509f6ff4fSMatt Macy 	iflib_rx_structures_free(ctx);
51867f3eb9daSPatrick Kelsey fail_iflib_detach:
518709f6ff4fSMatt Macy 	IFDI_DETACH(ctx);
518838bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
5189aac9c817SEric Joyner fail_unlock:
5190aac9c817SEric Joyner 	CTX_UNLOCK(ctx);
519156614414SEric Joyner 	iflib_deregister(ctx);
51927f3eb9daSPatrick Kelsey fail_ctx_free:
51937f3eb9daSPatrick Kelsey 	free(ctx->ifc_softc, M_IFLIB);
51947f3eb9daSPatrick Kelsey 	free(ctx, M_IFLIB);
519509f6ff4fSMatt Macy 	return (err);
519609f6ff4fSMatt Macy }
519709f6ff4fSMatt Macy 
519809f6ff4fSMatt Macy int
519909f6ff4fSMatt Macy iflib_pseudo_deregister(if_ctx_t ctx)
520009f6ff4fSMatt Macy {
520109f6ff4fSMatt Macy 	if_t ifp = ctx->ifc_ifp;
52029aeca213SMatt Macy 	if_shared_ctx_t sctx = ctx->ifc_sctx;
520309f6ff4fSMatt Macy 
52041558015eSEric Joyner 	/* Unregister VLAN event handlers early */
52051558015eSEric Joyner 	iflib_unregister_vlan_handlers(ctx);
52061558015eSEric Joyner 
52079aeca213SMatt Macy 	if ((sctx->isc_flags & IFLIB_PSEUDO)  &&
52089aeca213SMatt Macy 		(sctx->isc_flags & IFLIB_PSEUDO_ETHER) == 0) {
52099aeca213SMatt Macy 		bpfdetach(ifp);
52109aeca213SMatt Macy 		if_detach(ifp);
52119aeca213SMatt Macy 	} else {
521209f6ff4fSMatt Macy 		ether_ifdetach(ifp);
52139aeca213SMatt Macy 	}
521409f6ff4fSMatt Macy 
521510254019SMark Johnston 	iflib_tqg_detach(ctx);
521609f6ff4fSMatt Macy 	iflib_tx_structures_free(ctx);
521709f6ff4fSMatt Macy 	iflib_rx_structures_free(ctx);
521838bfc6deSSai Rajesh Tallamraju 	IFDI_DETACH(ctx);
521938bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
522056614414SEric Joyner 
522156614414SEric Joyner 	iflib_deregister(ctx);
522256614414SEric Joyner 
522309f6ff4fSMatt Macy 	if (ctx->ifc_flags & IFC_SC_ALLOCATED)
522409f6ff4fSMatt Macy 		free(ctx->ifc_softc, M_IFLIB);
522509f6ff4fSMatt Macy 	free(ctx, M_IFLIB);
522609f6ff4fSMatt Macy 	return (0);
522709f6ff4fSMatt Macy }
522809f6ff4fSMatt Macy 
522909f6ff4fSMatt Macy int
52304c7070dbSScott Long iflib_device_attach(device_t dev)
52314c7070dbSScott Long {
52324c7070dbSScott Long 	if_ctx_t ctx;
52334c7070dbSScott Long 	if_shared_ctx_t sctx;
52344c7070dbSScott Long 
52354c7070dbSScott Long 	if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC)
52364c7070dbSScott Long 		return (ENOTSUP);
52374c7070dbSScott Long 
52384c7070dbSScott Long 	pci_enable_busmaster(dev);
52394c7070dbSScott Long 
52404c7070dbSScott Long 	return (iflib_device_register(dev, NULL, sctx, &ctx));
52414c7070dbSScott Long }
52424c7070dbSScott Long 
52434c7070dbSScott Long int
52444c7070dbSScott Long iflib_device_deregister(if_ctx_t ctx)
52454c7070dbSScott Long {
52464c7070dbSScott Long 	if_t ifp = ctx->ifc_ifp;
52474c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
52484c7070dbSScott Long 
52494c7070dbSScott Long 	/* Make sure VLANS are not using driver */
52504c7070dbSScott Long 	if (if_vlantrunkinuse(ifp)) {
52514c7070dbSScott Long 		device_printf(dev, "Vlan in use, detach first\n");
52524c7070dbSScott Long 		return (EBUSY);
52534c7070dbSScott Long 	}
525477c1fcecSEric Joyner #ifdef PCI_IOV
525577c1fcecSEric Joyner 	if (!CTX_IS_VF(ctx) && pci_iov_detach(dev) != 0) {
525677c1fcecSEric Joyner 		device_printf(dev, "SR-IOV in use; detach first.\n");
525777c1fcecSEric Joyner 		return (EBUSY);
525877c1fcecSEric Joyner 	}
525977c1fcecSEric Joyner #endif
526077c1fcecSEric Joyner 
526177c1fcecSEric Joyner 	STATE_LOCK(ctx);
526277c1fcecSEric Joyner 	ctx->ifc_flags |= IFC_IN_DETACH;
526377c1fcecSEric Joyner 	STATE_UNLOCK(ctx);
52644c7070dbSScott Long 
52651558015eSEric Joyner 	/* Unregister VLAN handlers before calling iflib_stop() */
52661558015eSEric Joyner 	iflib_unregister_vlan_handlers(ctx);
52671558015eSEric Joyner 
52681558015eSEric Joyner 	iflib_netmap_detach(ifp);
52691558015eSEric Joyner 	ether_ifdetach(ifp);
52701558015eSEric Joyner 
52714c7070dbSScott Long 	CTX_LOCK(ctx);
52724c7070dbSScott Long 	iflib_stop(ctx);
52734c7070dbSScott Long 	CTX_UNLOCK(ctx);
52744c7070dbSScott Long 
52756d49b41eSAndrew Gallatin 	iflib_rem_pfil(ctx);
52764c7070dbSScott Long 	if (ctx->ifc_led_dev != NULL)
52774c7070dbSScott Long 		led_destroy(ctx->ifc_led_dev);
527887890dbaSSean Bruno 
527910254019SMark Johnston 	iflib_tqg_detach(ctx);
528038bfc6deSSai Rajesh Tallamraju 	iflib_tx_structures_free(ctx);
528138bfc6deSSai Rajesh Tallamraju 	iflib_rx_structures_free(ctx);
528238bfc6deSSai Rajesh Tallamraju 
52836c3c3194SMatt Macy 	CTX_LOCK(ctx);
52844c7070dbSScott Long 	IFDI_DETACH(ctx);
528538bfc6deSSai Rajesh Tallamraju 	IFDI_QUEUES_FREE(ctx);
52866c3c3194SMatt Macy 	CTX_UNLOCK(ctx);
52876c3c3194SMatt Macy 
52886c3c3194SMatt Macy 	/* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/
528977c1fcecSEric Joyner 	iflib_free_intr_mem(ctx);
529077c1fcecSEric Joyner 
529177c1fcecSEric Joyner 	bus_generic_detach(dev);
529277c1fcecSEric Joyner 
529356614414SEric Joyner 	iflib_deregister(ctx);
529456614414SEric Joyner 
529556614414SEric Joyner 	device_set_softc(ctx->ifc_dev, NULL);
529677c1fcecSEric Joyner 	if (ctx->ifc_flags & IFC_SC_ALLOCATED)
529777c1fcecSEric Joyner 		free(ctx->ifc_softc, M_IFLIB);
5298f154ece0SStephen Hurd 	unref_ctx_core_offset(ctx);
529977c1fcecSEric Joyner 	free(ctx, M_IFLIB);
530077c1fcecSEric Joyner 	return (0);
530177c1fcecSEric Joyner }
530277c1fcecSEric Joyner 
530377c1fcecSEric Joyner static void
530410254019SMark Johnston iflib_tqg_detach(if_ctx_t ctx)
530510254019SMark Johnston {
530610254019SMark Johnston 	iflib_txq_t txq;
530710254019SMark Johnston 	iflib_rxq_t rxq;
530810254019SMark Johnston 	int i;
530910254019SMark Johnston 	struct taskqgroup *tqg;
531010254019SMark Johnston 
531110254019SMark Johnston 	/* XXX drain any dependent tasks */
531210254019SMark Johnston 	tqg = qgroup_if_io_tqg;
531310254019SMark Johnston 	for (txq = ctx->ifc_txqs, i = 0; i < NTXQSETS(ctx); i++, txq++) {
531410254019SMark Johnston 		callout_drain(&txq->ift_timer);
531510254019SMark Johnston #ifdef DEV_NETMAP
531610254019SMark Johnston 		callout_drain(&txq->ift_netmap_timer);
531710254019SMark Johnston #endif /* DEV_NETMAP */
531810254019SMark Johnston 		if (txq->ift_task.gt_uniq != NULL)
531910254019SMark Johnston 			taskqgroup_detach(tqg, &txq->ift_task);
532010254019SMark Johnston 	}
532110254019SMark Johnston 	for (i = 0, rxq = ctx->ifc_rxqs; i < NRXQSETS(ctx); i++, rxq++) {
532210254019SMark Johnston 		if (rxq->ifr_task.gt_uniq != NULL)
532310254019SMark Johnston 			taskqgroup_detach(tqg, &rxq->ifr_task);
532410254019SMark Johnston 	}
532510254019SMark Johnston 	tqg = qgroup_if_config_tqg;
532610254019SMark Johnston 	if (ctx->ifc_admin_task.gt_uniq != NULL)
532710254019SMark Johnston 		taskqgroup_detach(tqg, &ctx->ifc_admin_task);
532810254019SMark Johnston 	if (ctx->ifc_vflr_task.gt_uniq != NULL)
532910254019SMark Johnston 		taskqgroup_detach(tqg, &ctx->ifc_vflr_task);
533010254019SMark Johnston }
533110254019SMark Johnston 
533210254019SMark Johnston static void
533377c1fcecSEric Joyner iflib_free_intr_mem(if_ctx_t ctx)
533477c1fcecSEric Joyner {
533577c1fcecSEric Joyner 
53364c7070dbSScott Long 	if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_MSIX) {
53374c7070dbSScott Long 		iflib_irq_free(ctx, &ctx->ifc_legacy_irq);
53384c7070dbSScott Long 	}
5339b97de13aSMarius Strobl 	if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_LEGACY) {
5340b97de13aSMarius Strobl 		pci_release_msi(ctx->ifc_dev);
5341b97de13aSMarius Strobl 	}
53424c7070dbSScott Long 	if (ctx->ifc_msix_mem != NULL) {
53434c7070dbSScott Long 		bus_release_resource(ctx->ifc_dev, SYS_RES_MEMORY,
5344b97de13aSMarius Strobl 		    rman_get_rid(ctx->ifc_msix_mem), ctx->ifc_msix_mem);
53454c7070dbSScott Long 		ctx->ifc_msix_mem = NULL;
53464c7070dbSScott Long 	}
53474c7070dbSScott Long }
53484c7070dbSScott Long 
53494c7070dbSScott Long int
53504c7070dbSScott Long iflib_device_detach(device_t dev)
53514c7070dbSScott Long {
53524c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
53534c7070dbSScott Long 
53544c7070dbSScott Long 	return (iflib_device_deregister(ctx));
53554c7070dbSScott Long }
53564c7070dbSScott Long 
53574c7070dbSScott Long int
53584c7070dbSScott Long iflib_device_suspend(device_t dev)
53594c7070dbSScott Long {
53604c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
53614c7070dbSScott Long 
53624c7070dbSScott Long 	CTX_LOCK(ctx);
53634c7070dbSScott Long 	IFDI_SUSPEND(ctx);
53644c7070dbSScott Long 	CTX_UNLOCK(ctx);
53654c7070dbSScott Long 
53664c7070dbSScott Long 	return bus_generic_suspend(dev);
53674c7070dbSScott Long }
53684c7070dbSScott Long int
53694c7070dbSScott Long iflib_device_shutdown(device_t dev)
53704c7070dbSScott Long {
53714c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
53724c7070dbSScott Long 
53734c7070dbSScott Long 	CTX_LOCK(ctx);
53744c7070dbSScott Long 	IFDI_SHUTDOWN(ctx);
53754c7070dbSScott Long 	CTX_UNLOCK(ctx);
53764c7070dbSScott Long 
53774c7070dbSScott Long 	return bus_generic_suspend(dev);
53784c7070dbSScott Long }
53794c7070dbSScott Long 
53804c7070dbSScott Long int
53814c7070dbSScott Long iflib_device_resume(device_t dev)
53824c7070dbSScott Long {
53834c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
53844c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
53854c7070dbSScott Long 
53864c7070dbSScott Long 	CTX_LOCK(ctx);
53874c7070dbSScott Long 	IFDI_RESUME(ctx);
5388cd28ea92SStephen Hurd 	iflib_if_init_locked(ctx);
53894c7070dbSScott Long 	CTX_UNLOCK(ctx);
53904c7070dbSScott Long 	for (int i = 0; i < NTXQSETS(ctx); i++, txq++)
53914c7070dbSScott Long 		iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET);
53924c7070dbSScott Long 
53934c7070dbSScott Long 	return (bus_generic_resume(dev));
53944c7070dbSScott Long }
53954c7070dbSScott Long 
53964c7070dbSScott Long int
53974c7070dbSScott Long iflib_device_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
53984c7070dbSScott Long {
53994c7070dbSScott Long 	int error;
54004c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
54014c7070dbSScott Long 
54024c7070dbSScott Long 	CTX_LOCK(ctx);
54034c7070dbSScott Long 	error = IFDI_IOV_INIT(ctx, num_vfs, params);
54044c7070dbSScott Long 	CTX_UNLOCK(ctx);
54054c7070dbSScott Long 
54064c7070dbSScott Long 	return (error);
54074c7070dbSScott Long }
54084c7070dbSScott Long 
54094c7070dbSScott Long void
54104c7070dbSScott Long iflib_device_iov_uninit(device_t dev)
54114c7070dbSScott Long {
54124c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
54134c7070dbSScott Long 
54144c7070dbSScott Long 	CTX_LOCK(ctx);
54154c7070dbSScott Long 	IFDI_IOV_UNINIT(ctx);
54164c7070dbSScott Long 	CTX_UNLOCK(ctx);
54174c7070dbSScott Long }
54184c7070dbSScott Long 
54194c7070dbSScott Long int
54204c7070dbSScott Long iflib_device_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
54214c7070dbSScott Long {
54224c7070dbSScott Long 	int error;
54234c7070dbSScott Long 	if_ctx_t ctx = device_get_softc(dev);
54244c7070dbSScott Long 
54254c7070dbSScott Long 	CTX_LOCK(ctx);
54264c7070dbSScott Long 	error = IFDI_IOV_VF_ADD(ctx, vfnum, params);
54274c7070dbSScott Long 	CTX_UNLOCK(ctx);
54284c7070dbSScott Long 
54294c7070dbSScott Long 	return (error);
54304c7070dbSScott Long }
54314c7070dbSScott Long 
54324c7070dbSScott Long /*********************************************************************
54334c7070dbSScott Long  *
54344c7070dbSScott Long  *  MODULE FUNCTION DEFINITIONS
54354c7070dbSScott Long  *
54364c7070dbSScott Long  **********************************************************************/
54374c7070dbSScott Long 
5438ab2e3f79SStephen Hurd /*
5439ab2e3f79SStephen Hurd  * - Start a fast taskqueue thread for each core
5440ab2e3f79SStephen Hurd  * - Start a taskqueue for control operations
5441ab2e3f79SStephen Hurd  */
54424c7070dbSScott Long static int
54434c7070dbSScott Long iflib_module_init(void)
54444c7070dbSScott Long {
544581be6552SMatt Macy 	iflib_timer_default = hz / 2;
54464c7070dbSScott Long 	return (0);
54474c7070dbSScott Long }
54484c7070dbSScott Long 
54494c7070dbSScott Long static int
54504c7070dbSScott Long iflib_module_event_handler(module_t mod, int what, void *arg)
54514c7070dbSScott Long {
54524c7070dbSScott Long 	int err;
54534c7070dbSScott Long 
54544c7070dbSScott Long 	switch (what) {
54554c7070dbSScott Long 	case MOD_LOAD:
54564c7070dbSScott Long 		if ((err = iflib_module_init()) != 0)
54574c7070dbSScott Long 			return (err);
54584c7070dbSScott Long 		break;
54594c7070dbSScott Long 	case MOD_UNLOAD:
54604c7070dbSScott Long 		return (EBUSY);
54614c7070dbSScott Long 	default:
54624c7070dbSScott Long 		return (EOPNOTSUPP);
54634c7070dbSScott Long 	}
54644c7070dbSScott Long 
54654c7070dbSScott Long 	return (0);
54664c7070dbSScott Long }
54674c7070dbSScott Long 
54684c7070dbSScott Long /*********************************************************************
54694c7070dbSScott Long  *
54704c7070dbSScott Long  *  PUBLIC FUNCTION DEFINITIONS
54714c7070dbSScott Long  *     ordered as in iflib.h
54724c7070dbSScott Long  *
54734c7070dbSScott Long  **********************************************************************/
54744c7070dbSScott Long 
54754c7070dbSScott Long static void
54764c7070dbSScott Long _iflib_assert(if_shared_ctx_t sctx)
54774c7070dbSScott Long {
5478afb77372SEric Joyner 	int i;
5479afb77372SEric Joyner 
54804c7070dbSScott Long 	MPASS(sctx->isc_tx_maxsize);
54814c7070dbSScott Long 	MPASS(sctx->isc_tx_maxsegsize);
54824c7070dbSScott Long 
54834c7070dbSScott Long 	MPASS(sctx->isc_rx_maxsize);
54844c7070dbSScott Long 	MPASS(sctx->isc_rx_nsegments);
54854c7070dbSScott Long 	MPASS(sctx->isc_rx_maxsegsize);
54864c7070dbSScott Long 
5487afb77372SEric Joyner 	MPASS(sctx->isc_nrxqs >= 1 && sctx->isc_nrxqs <= 8);
5488afb77372SEric Joyner 	for (i = 0; i < sctx->isc_nrxqs; i++) {
5489afb77372SEric Joyner 		MPASS(sctx->isc_nrxd_min[i]);
5490afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_nrxd_min[i]));
5491afb77372SEric Joyner 		MPASS(sctx->isc_nrxd_max[i]);
5492afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_nrxd_max[i]));
5493afb77372SEric Joyner 		MPASS(sctx->isc_nrxd_default[i]);
5494afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_nrxd_default[i]));
5495afb77372SEric Joyner 	}
5496afb77372SEric Joyner 
5497afb77372SEric Joyner 	MPASS(sctx->isc_ntxqs >= 1 && sctx->isc_ntxqs <= 8);
5498afb77372SEric Joyner 	for (i = 0; i < sctx->isc_ntxqs; i++) {
5499afb77372SEric Joyner 		MPASS(sctx->isc_ntxd_min[i]);
5500afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_ntxd_min[i]));
5501afb77372SEric Joyner 		MPASS(sctx->isc_ntxd_max[i]);
5502afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_ntxd_max[i]));
5503afb77372SEric Joyner 		MPASS(sctx->isc_ntxd_default[i]);
5504afb77372SEric Joyner 		MPASS(powerof2(sctx->isc_ntxd_default[i]));
5505afb77372SEric Joyner 	}
55064c7070dbSScott Long }
55074c7070dbSScott Long 
55081248952aSSean Bruno static void
55091248952aSSean Bruno _iflib_pre_assert(if_softc_ctx_t scctx)
55101248952aSSean Bruno {
55111248952aSSean Bruno 
55121248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_txd_encap);
55131248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_txd_flush);
55141248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_txd_credits_update);
55151248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_available);
55161248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_pkt_get);
55171248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_refill);
55181248952aSSean Bruno 	MPASS(scctx->isc_txrx->ift_rxd_flush);
55191248952aSSean Bruno }
55202fe66646SSean Bruno 
55214c7070dbSScott Long static int
55224c7070dbSScott Long iflib_register(if_ctx_t ctx)
55234c7070dbSScott Long {
55244c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
55254c7070dbSScott Long 	driver_t *driver = sctx->isc_driver;
55264c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
55274c7070dbSScott Long 	if_t ifp;
55289aeca213SMatt Macy 	u_char type;
55299aeca213SMatt Macy 	int iflags;
55304c7070dbSScott Long 
55311f93e931SMatt Macy 	if ((sctx->isc_flags & IFLIB_PSEUDO) == 0)
55324c7070dbSScott Long 		_iflib_assert(sctx);
55334c7070dbSScott Long 
5534aa8a24d3SStephen Hurd 	CTX_LOCK_INIT(ctx);
55357b610b60SSean Bruno 	STATE_LOCK_INIT(ctx, device_get_nameunit(ctx->ifc_dev));
55369aeca213SMatt Macy 	if (sctx->isc_flags & IFLIB_PSEUDO) {
55379aeca213SMatt Macy 		if (sctx->isc_flags & IFLIB_PSEUDO_ETHER)
55389aeca213SMatt Macy 			type = IFT_ETHER;
55399aeca213SMatt Macy 		else
55409aeca213SMatt Macy 			type = IFT_PPP;
55419aeca213SMatt Macy 	} else
55429aeca213SMatt Macy 		type = IFT_ETHER;
55439aeca213SMatt Macy 	ifp = ctx->ifc_ifp = if_alloc(type);
55444c7070dbSScott Long 	if (ifp == NULL) {
55454c7070dbSScott Long 		device_printf(dev, "can not allocate ifnet structure\n");
55464c7070dbSScott Long 		return (ENOMEM);
55474c7070dbSScott Long 	}
55484c7070dbSScott Long 
55494c7070dbSScott Long 	/*
55504c7070dbSScott Long 	 * Initialize our context's device specific methods
55514c7070dbSScott Long 	 */
55524c7070dbSScott Long 	kobj_init((kobj_t) ctx, (kobj_class_t) driver);
55534c7070dbSScott Long 	kobj_class_compile((kobj_class_t) driver);
55544c7070dbSScott Long 
55554c7070dbSScott Long 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
55564c7070dbSScott Long 	if_setsoftc(ifp, ctx);
55574c7070dbSScott Long 	if_setdev(ifp, dev);
55584c7070dbSScott Long 	if_setinitfn(ifp, iflib_if_init);
55594c7070dbSScott Long 	if_setioctlfn(ifp, iflib_if_ioctl);
5560b8ca4756SPatrick Kelsey #ifdef ALTQ
5561b8ca4756SPatrick Kelsey 	if_setstartfn(ifp, iflib_altq_if_start);
5562b8ca4756SPatrick Kelsey 	if_settransmitfn(ifp, iflib_altq_if_transmit);
55638f410865SPatrick Kelsey 	if_setsendqready(ifp);
5564b8ca4756SPatrick Kelsey #else
55654c7070dbSScott Long 	if_settransmitfn(ifp, iflib_if_transmit);
5566b8ca4756SPatrick Kelsey #endif
55674c7070dbSScott Long 	if_setqflushfn(ifp, iflib_if_qflush);
55689aeca213SMatt Macy 	iflags = IFF_MULTICAST | IFF_KNOWSEPOCH;
55694c7070dbSScott Long 
55709aeca213SMatt Macy 	if ((sctx->isc_flags & IFLIB_PSEUDO) &&
55719aeca213SMatt Macy 		(sctx->isc_flags & IFLIB_PSEUDO_ETHER) == 0)
55729aeca213SMatt Macy 		iflags |= IFF_POINTOPOINT;
55739aeca213SMatt Macy 	else
55749aeca213SMatt Macy 		iflags |= IFF_BROADCAST | IFF_SIMPLEX;
55759aeca213SMatt Macy 	if_setflags(ifp, iflags);
55764c7070dbSScott Long 	ctx->ifc_vlan_attach_event =
55774c7070dbSScott Long 		EVENTHANDLER_REGISTER(vlan_config, iflib_vlan_register, ctx,
55784c7070dbSScott Long 							  EVENTHANDLER_PRI_FIRST);
55794c7070dbSScott Long 	ctx->ifc_vlan_detach_event =
55804c7070dbSScott Long 		EVENTHANDLER_REGISTER(vlan_unconfig, iflib_vlan_unregister, ctx,
55814c7070dbSScott Long 							  EVENTHANDLER_PRI_FIRST);
55824c7070dbSScott Long 
5583e2621d96SMatt Macy 	if ((sctx->isc_flags & IFLIB_DRIVER_MEDIA) == 0) {
5584e2621d96SMatt Macy 		ctx->ifc_mediap = &ctx->ifc_media;
5585e2621d96SMatt Macy 		ifmedia_init(ctx->ifc_mediap, IFM_IMASK,
55864c7070dbSScott Long 		    iflib_media_change, iflib_media_status);
5587e2621d96SMatt Macy 	}
55884c7070dbSScott Long 	return (0);
55894c7070dbSScott Long }
55904c7070dbSScott Long 
559156614414SEric Joyner static void
55921558015eSEric Joyner iflib_unregister_vlan_handlers(if_ctx_t ctx)
559356614414SEric Joyner {
559456614414SEric Joyner 	/* Unregister VLAN events */
559556614414SEric Joyner 	if (ctx->ifc_vlan_attach_event != NULL) {
559656614414SEric Joyner 		EVENTHANDLER_DEREGISTER(vlan_config, ctx->ifc_vlan_attach_event);
559756614414SEric Joyner 		ctx->ifc_vlan_attach_event = NULL;
559856614414SEric Joyner 	}
559956614414SEric Joyner 	if (ctx->ifc_vlan_detach_event != NULL) {
560056614414SEric Joyner 		EVENTHANDLER_DEREGISTER(vlan_unconfig, ctx->ifc_vlan_detach_event);
560156614414SEric Joyner 		ctx->ifc_vlan_detach_event = NULL;
560256614414SEric Joyner 	}
560356614414SEric Joyner 
56041558015eSEric Joyner }
56051558015eSEric Joyner 
56061558015eSEric Joyner static void
56071558015eSEric Joyner iflib_deregister(if_ctx_t ctx)
56081558015eSEric Joyner {
56091558015eSEric Joyner 	if_t ifp = ctx->ifc_ifp;
56101558015eSEric Joyner 
56111558015eSEric Joyner 	/* Remove all media */
56121558015eSEric Joyner 	ifmedia_removeall(&ctx->ifc_media);
56131558015eSEric Joyner 
56141558015eSEric Joyner 	/* Ensure that VLAN event handlers are unregistered */
56151558015eSEric Joyner 	iflib_unregister_vlan_handlers(ctx);
56161558015eSEric Joyner 
561756614414SEric Joyner 	/* Release kobject reference */
561856614414SEric Joyner 	kobj_delete((kobj_t) ctx, NULL);
561956614414SEric Joyner 
562056614414SEric Joyner 	/* Free the ifnet structure */
562156614414SEric Joyner 	if_free(ifp);
562256614414SEric Joyner 
562356614414SEric Joyner 	STATE_LOCK_DESTROY(ctx);
562456614414SEric Joyner 
562556614414SEric Joyner 	/* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/
562656614414SEric Joyner 	CTX_LOCK_DESTROY(ctx);
562756614414SEric Joyner }
562856614414SEric Joyner 
56294c7070dbSScott Long static int
56304c7070dbSScott Long iflib_queues_alloc(if_ctx_t ctx)
56314c7070dbSScott Long {
56324c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
563323ac9029SStephen Hurd 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
56344c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
563523ac9029SStephen Hurd 	int nrxqsets = scctx->isc_nrxqsets;
563623ac9029SStephen Hurd 	int ntxqsets = scctx->isc_ntxqsets;
56374c7070dbSScott Long 	iflib_txq_t txq;
56384c7070dbSScott Long 	iflib_rxq_t rxq;
56394c7070dbSScott Long 	iflib_fl_t fl = NULL;
564023ac9029SStephen Hurd 	int i, j, cpu, err, txconf, rxconf;
56414c7070dbSScott Long 	iflib_dma_info_t ifdip;
564223ac9029SStephen Hurd 	uint32_t *rxqsizes = scctx->isc_rxqsizes;
564323ac9029SStephen Hurd 	uint32_t *txqsizes = scctx->isc_txqsizes;
56444c7070dbSScott Long 	uint8_t nrxqs = sctx->isc_nrxqs;
56454c7070dbSScott Long 	uint8_t ntxqs = sctx->isc_ntxqs;
56464c7070dbSScott Long 	int nfree_lists = sctx->isc_nfl ? sctx->isc_nfl : 1;
56474ba9ad0dSVincenzo Maffione 	int fl_offset = (sctx->isc_flags & IFLIB_HAS_RXCQ ? 1 : 0);
56484c7070dbSScott Long 	caddr_t *vaddrs;
56494c7070dbSScott Long 	uint64_t *paddrs;
56504c7070dbSScott Long 
565123ac9029SStephen Hurd 	KASSERT(ntxqs > 0, ("number of queues per qset must be at least 1"));
565223ac9029SStephen Hurd 	KASSERT(nrxqs > 0, ("number of queues per qset must be at least 1"));
56534ba9ad0dSVincenzo Maffione 	KASSERT(nrxqs >= fl_offset + nfree_lists,
56544ba9ad0dSVincenzo Maffione            ("there must be at least a rxq for each free list"));
56554c7070dbSScott Long 
56564c7070dbSScott Long 	/* Allocate the TX ring struct memory */
5657b89827a0SStephen Hurd 	if (!(ctx->ifc_txqs =
5658ac2fffa4SPedro F. Giffuni 	    (iflib_txq_t) malloc(sizeof(struct iflib_txq) *
5659ac2fffa4SPedro F. Giffuni 	    ntxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) {
56604c7070dbSScott Long 		device_printf(dev, "Unable to allocate TX ring memory\n");
56614c7070dbSScott Long 		err = ENOMEM;
56624c7070dbSScott Long 		goto fail;
56634c7070dbSScott Long 	}
56644c7070dbSScott Long 
56654c7070dbSScott Long 	/* Now allocate the RX */
5666b89827a0SStephen Hurd 	if (!(ctx->ifc_rxqs =
5667ac2fffa4SPedro F. Giffuni 	    (iflib_rxq_t) malloc(sizeof(struct iflib_rxq) *
5668ac2fffa4SPedro F. Giffuni 	    nrxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) {
56694c7070dbSScott Long 		device_printf(dev, "Unable to allocate RX ring memory\n");
56704c7070dbSScott Long 		err = ENOMEM;
56714c7070dbSScott Long 		goto rx_fail;
56724c7070dbSScott Long 	}
56734c7070dbSScott Long 
5674b89827a0SStephen Hurd 	txq = ctx->ifc_txqs;
5675b89827a0SStephen Hurd 	rxq = ctx->ifc_rxqs;
56764c7070dbSScott Long 
56774c7070dbSScott Long 	/*
56784c7070dbSScott Long 	 * XXX handle allocation failure
56794c7070dbSScott Long 	 */
568096c85efbSNathan Whitehorn 	for (txconf = i = 0, cpu = CPU_FIRST(); i < ntxqsets; i++, txconf++, txq++, cpu = CPU_NEXT(cpu)) {
56814c7070dbSScott Long 		/* Set up some basics */
56824c7070dbSScott Long 
5683bfce461eSMarius Strobl 		if ((ifdip = malloc(sizeof(struct iflib_dma_info) * ntxqs,
5684bfce461eSMarius Strobl 		    M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
5685bfce461eSMarius Strobl 			device_printf(dev,
5686bfce461eSMarius Strobl 			    "Unable to allocate TX DMA info memory\n");
56874c7070dbSScott Long 			err = ENOMEM;
56880d0338afSConrad Meyer 			goto err_tx_desc;
56894c7070dbSScott Long 		}
56904c7070dbSScott Long 		txq->ift_ifdi = ifdip;
56914c7070dbSScott Long 		for (j = 0; j < ntxqs; j++, ifdip++) {
5692bfce461eSMarius Strobl 			if (iflib_dma_alloc(ctx, txqsizes[j], ifdip, 0)) {
5693bfce461eSMarius Strobl 				device_printf(dev,
5694bfce461eSMarius Strobl 				    "Unable to allocate TX descriptors\n");
56954c7070dbSScott Long 				err = ENOMEM;
56964c7070dbSScott Long 				goto err_tx_desc;
56974c7070dbSScott Long 			}
569895246abbSSean Bruno 			txq->ift_txd_size[j] = scctx->isc_txd_size[j];
56994c7070dbSScott Long 			bzero((void *)ifdip->idi_vaddr, txqsizes[j]);
57004c7070dbSScott Long 		}
57014c7070dbSScott Long 		txq->ift_ctx = ctx;
57024c7070dbSScott Long 		txq->ift_id = i;
570323ac9029SStephen Hurd 		if (sctx->isc_flags & IFLIB_HAS_TXCQ) {
570423ac9029SStephen Hurd 			txq->ift_br_offset = 1;
570523ac9029SStephen Hurd 		} else {
570623ac9029SStephen Hurd 			txq->ift_br_offset = 0;
570723ac9029SStephen Hurd 		}
57084c7070dbSScott Long 
57094c7070dbSScott Long 		if (iflib_txsd_alloc(txq)) {
57104c7070dbSScott Long 			device_printf(dev, "Critical Failure setting up TX buffers\n");
57114c7070dbSScott Long 			err = ENOMEM;
57124c7070dbSScott Long 			goto err_tx_desc;
57134c7070dbSScott Long 		}
57144c7070dbSScott Long 
57154c7070dbSScott Long 		/* Initialize the TX lock */
57161722eeacSMarius Strobl 		snprintf(txq->ift_mtx_name, MTX_NAME_LEN, "%s:TX(%d):callout",
57174c7070dbSScott Long 		    device_get_nameunit(dev), txq->ift_id);
57184c7070dbSScott Long 		mtx_init(&txq->ift_mtx, txq->ift_mtx_name, NULL, MTX_DEF);
57194c7070dbSScott Long 		callout_init_mtx(&txq->ift_timer, &txq->ift_mtx, 0);
572017cec474SVincenzo Maffione 		txq->ift_timer.c_cpu = cpu;
572117cec474SVincenzo Maffione #ifdef DEV_NETMAP
572217cec474SVincenzo Maffione 		callout_init_mtx(&txq->ift_netmap_timer, &txq->ift_mtx, 0);
572317cec474SVincenzo Maffione 		txq->ift_netmap_timer.c_cpu = cpu;
572417cec474SVincenzo Maffione #endif /* DEV_NETMAP */
57254c7070dbSScott Long 
572695246abbSSean Bruno 		err = ifmp_ring_alloc(&txq->ift_br, 2048, txq, iflib_txq_drain,
57274c7070dbSScott Long 				      iflib_txq_can_drain, M_IFLIB, M_WAITOK);
57284c7070dbSScott Long 		if (err) {
57294c7070dbSScott Long 			/* XXX free any allocated rings */
57304c7070dbSScott Long 			device_printf(dev, "Unable to allocate buf_ring\n");
57310d0338afSConrad Meyer 			goto err_tx_desc;
57324c7070dbSScott Long 		}
57334c7070dbSScott Long 	}
57344c7070dbSScott Long 
57354c7070dbSScott Long 	for (rxconf = i = 0; i < nrxqsets; i++, rxconf++, rxq++) {
57364c7070dbSScott Long 		/* Set up some basics */
5737fb1a29b4SHans Petter Selasky 		callout_init(&rxq->ifr_watchdog, 1);
57384c7070dbSScott Long 
5739bfce461eSMarius Strobl 		if ((ifdip = malloc(sizeof(struct iflib_dma_info) * nrxqs,
5740bfce461eSMarius Strobl 		   M_IFLIB, M_NOWAIT | M_ZERO)) == NULL) {
5741bfce461eSMarius Strobl 			device_printf(dev,
5742bfce461eSMarius Strobl 			    "Unable to allocate RX DMA info memory\n");
57434c7070dbSScott Long 			err = ENOMEM;
57440d0338afSConrad Meyer 			goto err_tx_desc;
57454c7070dbSScott Long 		}
57464c7070dbSScott Long 
57474c7070dbSScott Long 		rxq->ifr_ifdi = ifdip;
574895246abbSSean Bruno 		/* XXX this needs to be changed if #rx queues != #tx queues */
574995246abbSSean Bruno 		rxq->ifr_ntxqirq = 1;
575095246abbSSean Bruno 		rxq->ifr_txqid[0] = i;
57514c7070dbSScott Long 		for (j = 0; j < nrxqs; j++, ifdip++) {
5752bfce461eSMarius Strobl 			if (iflib_dma_alloc(ctx, rxqsizes[j], ifdip, 0)) {
5753bfce461eSMarius Strobl 				device_printf(dev,
5754bfce461eSMarius Strobl 				    "Unable to allocate RX descriptors\n");
57554c7070dbSScott Long 				err = ENOMEM;
57564c7070dbSScott Long 				goto err_tx_desc;
57574c7070dbSScott Long 			}
57584c7070dbSScott Long 			bzero((void *)ifdip->idi_vaddr, rxqsizes[j]);
57594c7070dbSScott Long 		}
57604c7070dbSScott Long 		rxq->ifr_ctx = ctx;
57614c7070dbSScott Long 		rxq->ifr_id = i;
57624ba9ad0dSVincenzo Maffione 		rxq->ifr_fl_offset = fl_offset;
57634c7070dbSScott Long 		rxq->ifr_nfl = nfree_lists;
57644c7070dbSScott Long 		if (!(fl =
5765ac2fffa4SPedro F. Giffuni 			  (iflib_fl_t) malloc(sizeof(struct iflib_fl) * nfree_lists, M_IFLIB, M_NOWAIT | M_ZERO))) {
57664c7070dbSScott Long 			device_printf(dev, "Unable to allocate free list memory\n");
57674c7070dbSScott Long 			err = ENOMEM;
57680d0338afSConrad Meyer 			goto err_tx_desc;
57694c7070dbSScott Long 		}
57704c7070dbSScott Long 		rxq->ifr_fl = fl;
57714c7070dbSScott Long 		for (j = 0; j < nfree_lists; j++) {
577295246abbSSean Bruno 			fl[j].ifl_rxq = rxq;
577395246abbSSean Bruno 			fl[j].ifl_id = j;
577495246abbSSean Bruno 			fl[j].ifl_ifdi = &rxq->ifr_ifdi[j + rxq->ifr_fl_offset];
577595246abbSSean Bruno 			fl[j].ifl_rxd_size = scctx->isc_rxd_size[j];
57764c7070dbSScott Long 		}
57774c7070dbSScott Long 		/* Allocate receive buffers for the ring */
57784c7070dbSScott Long 		if (iflib_rxsd_alloc(rxq)) {
57794c7070dbSScott Long 			device_printf(dev,
57804c7070dbSScott Long 			    "Critical Failure setting up receive buffers\n");
57814c7070dbSScott Long 			err = ENOMEM;
57824c7070dbSScott Long 			goto err_rx_desc;
57834c7070dbSScott Long 		}
578487890dbaSSean Bruno 
578587890dbaSSean Bruno 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++)
57863db348b5SMarius Strobl 			fl->ifl_rx_bitmap = bit_alloc(fl->ifl_size, M_IFLIB,
57873db348b5SMarius Strobl 			    M_WAITOK);
57884c7070dbSScott Long 	}
57894c7070dbSScott Long 
57904c7070dbSScott Long 	/* TXQs */
57914c7070dbSScott Long 	vaddrs = malloc(sizeof(caddr_t)*ntxqsets*ntxqs, M_IFLIB, M_WAITOK);
57924c7070dbSScott Long 	paddrs = malloc(sizeof(uint64_t)*ntxqsets*ntxqs, M_IFLIB, M_WAITOK);
57934c7070dbSScott Long 	for (i = 0; i < ntxqsets; i++) {
57944c7070dbSScott Long 		iflib_dma_info_t di = ctx->ifc_txqs[i].ift_ifdi;
57954c7070dbSScott Long 
57964c7070dbSScott Long 		for (j = 0; j < ntxqs; j++, di++) {
57974c7070dbSScott Long 			vaddrs[i*ntxqs + j] = di->idi_vaddr;
57984c7070dbSScott Long 			paddrs[i*ntxqs + j] = di->idi_paddr;
57994c7070dbSScott Long 		}
58004c7070dbSScott Long 	}
58014c7070dbSScott Long 	if ((err = IFDI_TX_QUEUES_ALLOC(ctx, vaddrs, paddrs, ntxqs, ntxqsets)) != 0) {
5802bfce461eSMarius Strobl 		device_printf(ctx->ifc_dev,
5803bfce461eSMarius Strobl 		    "Unable to allocate device TX queue\n");
58044c7070dbSScott Long 		iflib_tx_structures_free(ctx);
58054c7070dbSScott Long 		free(vaddrs, M_IFLIB);
58064c7070dbSScott Long 		free(paddrs, M_IFLIB);
58074c7070dbSScott Long 		goto err_rx_desc;
58084c7070dbSScott Long 	}
58094c7070dbSScott Long 	free(vaddrs, M_IFLIB);
58104c7070dbSScott Long 	free(paddrs, M_IFLIB);
58114c7070dbSScott Long 
58124c7070dbSScott Long 	/* RXQs */
58134c7070dbSScott Long 	vaddrs = malloc(sizeof(caddr_t)*nrxqsets*nrxqs, M_IFLIB, M_WAITOK);
58144c7070dbSScott Long 	paddrs = malloc(sizeof(uint64_t)*nrxqsets*nrxqs, M_IFLIB, M_WAITOK);
58154c7070dbSScott Long 	for (i = 0; i < nrxqsets; i++) {
58164c7070dbSScott Long 		iflib_dma_info_t di = ctx->ifc_rxqs[i].ifr_ifdi;
58174c7070dbSScott Long 
58184c7070dbSScott Long 		for (j = 0; j < nrxqs; j++, di++) {
58194c7070dbSScott Long 			vaddrs[i*nrxqs + j] = di->idi_vaddr;
58204c7070dbSScott Long 			paddrs[i*nrxqs + j] = di->idi_paddr;
58214c7070dbSScott Long 		}
58224c7070dbSScott Long 	}
58234c7070dbSScott Long 	if ((err = IFDI_RX_QUEUES_ALLOC(ctx, vaddrs, paddrs, nrxqs, nrxqsets)) != 0) {
5824bfce461eSMarius Strobl 		device_printf(ctx->ifc_dev,
5825bfce461eSMarius Strobl 		    "Unable to allocate device RX queue\n");
58264c7070dbSScott Long 		iflib_tx_structures_free(ctx);
58274c7070dbSScott Long 		free(vaddrs, M_IFLIB);
58284c7070dbSScott Long 		free(paddrs, M_IFLIB);
58294c7070dbSScott Long 		goto err_rx_desc;
58304c7070dbSScott Long 	}
58314c7070dbSScott Long 	free(vaddrs, M_IFLIB);
58324c7070dbSScott Long 	free(paddrs, M_IFLIB);
58334c7070dbSScott Long 
58344c7070dbSScott Long 	return (0);
58354c7070dbSScott Long 
58364c7070dbSScott Long /* XXX handle allocation failure changes */
58374c7070dbSScott Long err_rx_desc:
58384c7070dbSScott Long err_tx_desc:
5839b89827a0SStephen Hurd rx_fail:
58404c7070dbSScott Long 	if (ctx->ifc_rxqs != NULL)
58414c7070dbSScott Long 		free(ctx->ifc_rxqs, M_IFLIB);
58424c7070dbSScott Long 	ctx->ifc_rxqs = NULL;
58434c7070dbSScott Long 	if (ctx->ifc_txqs != NULL)
58444c7070dbSScott Long 		free(ctx->ifc_txqs, M_IFLIB);
58454c7070dbSScott Long 	ctx->ifc_txqs = NULL;
58464c7070dbSScott Long fail:
58474c7070dbSScott Long 	return (err);
58484c7070dbSScott Long }
58494c7070dbSScott Long 
58504c7070dbSScott Long static int
58514c7070dbSScott Long iflib_tx_structures_setup(if_ctx_t ctx)
58524c7070dbSScott Long {
58534c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
58544c7070dbSScott Long 	int i;
58554c7070dbSScott Long 
58564c7070dbSScott Long 	for (i = 0; i < NTXQSETS(ctx); i++, txq++)
58574c7070dbSScott Long 		iflib_txq_setup(txq);
58584c7070dbSScott Long 
58594c7070dbSScott Long 	return (0);
58604c7070dbSScott Long }
58614c7070dbSScott Long 
58624c7070dbSScott Long static void
58634c7070dbSScott Long iflib_tx_structures_free(if_ctx_t ctx)
58644c7070dbSScott Long {
58654c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
58664d261ce2SStephen Hurd 	if_shared_ctx_t sctx = ctx->ifc_sctx;
58674c7070dbSScott Long 	int i, j;
58684c7070dbSScott Long 
58694c7070dbSScott Long 	for (i = 0; i < NTXQSETS(ctx); i++, txq++) {
58704d261ce2SStephen Hurd 		for (j = 0; j < sctx->isc_ntxqs; j++)
58714c7070dbSScott Long 			iflib_dma_free(&txq->ift_ifdi[j]);
5872244e7cffSEric Joyner 		iflib_txq_destroy(txq);
58734c7070dbSScott Long 	}
58744c7070dbSScott Long 	free(ctx->ifc_txqs, M_IFLIB);
58754c7070dbSScott Long 	ctx->ifc_txqs = NULL;
58764c7070dbSScott Long }
58774c7070dbSScott Long 
58784c7070dbSScott Long /*********************************************************************
58794c7070dbSScott Long  *
58804c7070dbSScott Long  *  Initialize all receive rings.
58814c7070dbSScott Long  *
58824c7070dbSScott Long  **********************************************************************/
58834c7070dbSScott Long static int
58844c7070dbSScott Long iflib_rx_structures_setup(if_ctx_t ctx)
58854c7070dbSScott Long {
58864c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
5887aaeb188aSBjoern A. Zeeb 	int q;
5888aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
58893d10e9edSMarius Strobl 	int err, i;
5890aaeb188aSBjoern A. Zeeb #endif
58914c7070dbSScott Long 
58924c7070dbSScott Long 	for (q = 0; q < ctx->ifc_softc_ctx.isc_nrxqsets; q++, rxq++) {
5893aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
58943d10e9edSMarius Strobl 		if (if_getcapabilities(ctx->ifc_ifp) & IFCAP_LRO) {
58953d10e9edSMarius Strobl 			err = tcp_lro_init_args(&rxq->ifr_lc, ctx->ifc_ifp,
589623ac9029SStephen Hurd 			    TCP_LRO_ENTRIES, min(1024,
58973d10e9edSMarius Strobl 			    ctx->ifc_softc_ctx.isc_nrxd[rxq->ifr_fl_offset]));
58983d10e9edSMarius Strobl 			if (err != 0) {
58993d10e9edSMarius Strobl 				device_printf(ctx->ifc_dev,
59003d10e9edSMarius Strobl 				    "LRO Initialization failed!\n");
59014c7070dbSScott Long 				goto fail;
59024c7070dbSScott Long 			}
59033d10e9edSMarius Strobl 		}
5904aaeb188aSBjoern A. Zeeb #endif
59054c7070dbSScott Long 		IFDI_RXQ_SETUP(ctx, rxq->ifr_id);
59064c7070dbSScott Long 	}
59074c7070dbSScott Long 	return (0);
5908aaeb188aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
59094c7070dbSScott Long fail:
59104c7070dbSScott Long 	/*
59113d10e9edSMarius Strobl 	 * Free LRO resources allocated so far, we will only handle
59124c7070dbSScott Long 	 * the rings that completed, the failing case will have
59134c7070dbSScott Long 	 * cleaned up for itself.  'q' failed, so its the terminus.
59144c7070dbSScott Long 	 */
59154c7070dbSScott Long 	rxq = ctx->ifc_rxqs;
59164c7070dbSScott Long 	for (i = 0; i < q; ++i, rxq++) {
59173d10e9edSMarius Strobl 		if (if_getcapabilities(ctx->ifc_ifp) & IFCAP_LRO)
59183d10e9edSMarius Strobl 			tcp_lro_free(&rxq->ifr_lc);
59194c7070dbSScott Long 	}
59204c7070dbSScott Long 	return (err);
5921aaeb188aSBjoern A. Zeeb #endif
59224c7070dbSScott Long }
59234c7070dbSScott Long 
59244c7070dbSScott Long /*********************************************************************
59254c7070dbSScott Long  *
59264c7070dbSScott Long  *  Free all receive rings.
59274c7070dbSScott Long  *
59284c7070dbSScott Long  **********************************************************************/
59294c7070dbSScott Long static void
59304c7070dbSScott Long iflib_rx_structures_free(if_ctx_t ctx)
59314c7070dbSScott Long {
59324c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
5933db8e8f1eSEric Joyner 	if_shared_ctx_t sctx = ctx->ifc_sctx;
5934db8e8f1eSEric Joyner 	int i, j;
59354c7070dbSScott Long 
59363d10e9edSMarius Strobl 	for (i = 0; i < ctx->ifc_softc_ctx.isc_nrxqsets; i++, rxq++) {
5937db8e8f1eSEric Joyner 		for (j = 0; j < sctx->isc_nrxqs; j++)
5938db8e8f1eSEric Joyner 			iflib_dma_free(&rxq->ifr_ifdi[j]);
59394c7070dbSScott Long 		iflib_rx_sds_free(rxq);
5940007b804fSMarius Strobl #if defined(INET6) || defined(INET)
59413d10e9edSMarius Strobl 		if (if_getcapabilities(ctx->ifc_ifp) & IFCAP_LRO)
59423d10e9edSMarius Strobl 			tcp_lro_free(&rxq->ifr_lc);
5943007b804fSMarius Strobl #endif
59444c7070dbSScott Long 	}
594577c1fcecSEric Joyner 	free(ctx->ifc_rxqs, M_IFLIB);
594677c1fcecSEric Joyner 	ctx->ifc_rxqs = NULL;
59474c7070dbSScott Long }
59484c7070dbSScott Long 
59494c7070dbSScott Long static int
59504c7070dbSScott Long iflib_qset_structures_setup(if_ctx_t ctx)
59514c7070dbSScott Long {
59524c7070dbSScott Long 	int err;
59534c7070dbSScott Long 
59546108c013SStephen Hurd 	/*
59556108c013SStephen Hurd 	 * It is expected that the caller takes care of freeing queues if this
59566108c013SStephen Hurd 	 * fails.
59576108c013SStephen Hurd 	 */
5958ac88e6daSStephen Hurd 	if ((err = iflib_tx_structures_setup(ctx)) != 0) {
5959ac88e6daSStephen Hurd 		device_printf(ctx->ifc_dev, "iflib_tx_structures_setup failed: %d\n", err);
59604c7070dbSScott Long 		return (err);
5961ac88e6daSStephen Hurd 	}
59624c7070dbSScott Long 
59636108c013SStephen Hurd 	if ((err = iflib_rx_structures_setup(ctx)) != 0)
59644c7070dbSScott Long 		device_printf(ctx->ifc_dev, "iflib_rx_structures_setup failed: %d\n", err);
59656108c013SStephen Hurd 
59664c7070dbSScott Long 	return (err);
59674c7070dbSScott Long }
59684c7070dbSScott Long 
59694c7070dbSScott Long int
59704c7070dbSScott Long iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid,
59713e0e6330SStephen Hurd 		driver_filter_t filter, void *filter_arg, driver_intr_t handler, void *arg, const char *name)
59724c7070dbSScott Long {
59734c7070dbSScott Long 
59744c7070dbSScott Long 	return (_iflib_irq_alloc(ctx, irq, rid, filter, handler, arg, name));
59754c7070dbSScott Long }
59764c7070dbSScott Long 
5977b103855eSStephen Hurd #ifdef SMP
5978aa3c5dd8SSean Bruno static int
5979b103855eSStephen Hurd find_nth(if_ctx_t ctx, int qid)
59804c7070dbSScott Long {
5981b103855eSStephen Hurd 	cpuset_t cpus;
5982aa3c5dd8SSean Bruno 	int i, cpuid, eqid, count;
59834c7070dbSScott Long 
5984b103855eSStephen Hurd 	CPU_COPY(&ctx->ifc_cpus, &cpus);
5985b103855eSStephen Hurd 	count = CPU_COUNT(&cpus);
5986aa3c5dd8SSean Bruno 	eqid = qid % count;
59874c7070dbSScott Long 	/* clear up to the qid'th bit */
5988aa3c5dd8SSean Bruno 	for (i = 0; i < eqid; i++) {
5989b103855eSStephen Hurd 		cpuid = CPU_FFS(&cpus);
5990aa3c5dd8SSean Bruno 		MPASS(cpuid != 0);
5991b103855eSStephen Hurd 		CPU_CLR(cpuid-1, &cpus);
59924c7070dbSScott Long 	}
5993b103855eSStephen Hurd 	cpuid = CPU_FFS(&cpus);
5994aa3c5dd8SSean Bruno 	MPASS(cpuid != 0);
5995aa3c5dd8SSean Bruno 	return (cpuid-1);
59964c7070dbSScott Long }
59974c7070dbSScott Long 
5998b103855eSStephen Hurd #ifdef SCHED_ULE
5999b103855eSStephen Hurd extern struct cpu_group *cpu_top;              /* CPU topology */
6000b103855eSStephen Hurd 
6001b103855eSStephen Hurd static int
6002b103855eSStephen Hurd find_child_with_core(int cpu, struct cpu_group *grp)
6003b103855eSStephen Hurd {
6004b103855eSStephen Hurd 	int i;
6005b103855eSStephen Hurd 
6006b103855eSStephen Hurd 	if (grp->cg_children == 0)
6007b103855eSStephen Hurd 		return -1;
6008b103855eSStephen Hurd 
6009b103855eSStephen Hurd 	MPASS(grp->cg_child);
6010b103855eSStephen Hurd 	for (i = 0; i < grp->cg_children; i++) {
6011b103855eSStephen Hurd 		if (CPU_ISSET(cpu, &grp->cg_child[i].cg_mask))
6012b103855eSStephen Hurd 			return i;
6013b103855eSStephen Hurd 	}
6014b103855eSStephen Hurd 
6015b103855eSStephen Hurd 	return -1;
6016b103855eSStephen Hurd }
6017b103855eSStephen Hurd 
6018b103855eSStephen Hurd /*
60190b75ac77SStephen Hurd  * Find the nth "close" core to the specified core
60200b75ac77SStephen Hurd  * "close" is defined as the deepest level that shares
60210b75ac77SStephen Hurd  * at least an L2 cache.  With threads, this will be
6022f154ece0SStephen Hurd  * threads on the same core.  If the shared cache is L3
60230b75ac77SStephen Hurd  * or higher, simply returns the same core.
6024b103855eSStephen Hurd  */
6025b103855eSStephen Hurd static int
60260b75ac77SStephen Hurd find_close_core(int cpu, int core_offset)
6027b103855eSStephen Hurd {
6028b103855eSStephen Hurd 	struct cpu_group *grp;
6029b103855eSStephen Hurd 	int i;
60300b75ac77SStephen Hurd 	int fcpu;
6031b103855eSStephen Hurd 	cpuset_t cs;
6032b103855eSStephen Hurd 
6033b103855eSStephen Hurd 	grp = cpu_top;
6034b103855eSStephen Hurd 	if (grp == NULL)
6035b103855eSStephen Hurd 		return cpu;
6036b103855eSStephen Hurd 	i = 0;
6037b103855eSStephen Hurd 	while ((i = find_child_with_core(cpu, grp)) != -1) {
6038b103855eSStephen Hurd 		/* If the child only has one cpu, don't descend */
6039b103855eSStephen Hurd 		if (grp->cg_child[i].cg_count <= 1)
6040b103855eSStephen Hurd 			break;
6041b103855eSStephen Hurd 		grp = &grp->cg_child[i];
6042b103855eSStephen Hurd 	}
6043b103855eSStephen Hurd 
6044b103855eSStephen Hurd 	/* If they don't share at least an L2 cache, use the same CPU */
6045b103855eSStephen Hurd 	if (grp->cg_level > CG_SHARE_L2 || grp->cg_level == CG_SHARE_NONE)
6046b103855eSStephen Hurd 		return cpu;
6047b103855eSStephen Hurd 
6048b103855eSStephen Hurd 	/* Now pick one */
6049b103855eSStephen Hurd 	CPU_COPY(&grp->cg_mask, &cs);
60500b75ac77SStephen Hurd 
60510b75ac77SStephen Hurd 	/* Add the selected CPU offset to core offset. */
60520b75ac77SStephen Hurd 	for (i = 0; (fcpu = CPU_FFS(&cs)) != 0; i++) {
60530b75ac77SStephen Hurd 		if (fcpu - 1 == cpu)
60540b75ac77SStephen Hurd 			break;
60550b75ac77SStephen Hurd 		CPU_CLR(fcpu - 1, &cs);
60560b75ac77SStephen Hurd 	}
60570b75ac77SStephen Hurd 	MPASS(fcpu);
60580b75ac77SStephen Hurd 
60590b75ac77SStephen Hurd 	core_offset += i;
60600b75ac77SStephen Hurd 
60610b75ac77SStephen Hurd 	CPU_COPY(&grp->cg_mask, &cs);
60620b75ac77SStephen Hurd 	for (i = core_offset % grp->cg_count; i > 0; i--) {
6063b103855eSStephen Hurd 		MPASS(CPU_FFS(&cs));
6064b103855eSStephen Hurd 		CPU_CLR(CPU_FFS(&cs) - 1, &cs);
6065b103855eSStephen Hurd 	}
6066b103855eSStephen Hurd 	MPASS(CPU_FFS(&cs));
6067b103855eSStephen Hurd 	return CPU_FFS(&cs) - 1;
6068b103855eSStephen Hurd }
6069b103855eSStephen Hurd #else
6070b103855eSStephen Hurd static int
60710b75ac77SStephen Hurd find_close_core(int cpu, int core_offset __unused)
6072b103855eSStephen Hurd {
607397755e83SKonstantin Belousov 	return cpu;
6074b103855eSStephen Hurd }
6075b103855eSStephen Hurd #endif
6076b103855eSStephen Hurd 
6077b103855eSStephen Hurd static int
60780b75ac77SStephen Hurd get_core_offset(if_ctx_t ctx, iflib_intr_type_t type, int qid)
6079b103855eSStephen Hurd {
6080b103855eSStephen Hurd 	switch (type) {
6081b103855eSStephen Hurd 	case IFLIB_INTR_TX:
60820b75ac77SStephen Hurd 		/* TX queues get cores which share at least an L2 cache with the corresponding RX queue */
60830b75ac77SStephen Hurd 		/* XXX handle multiple RX threads per core and more than two core per L2 group */
6084b103855eSStephen Hurd 		return qid / CPU_COUNT(&ctx->ifc_cpus) + 1;
6085b103855eSStephen Hurd 	case IFLIB_INTR_RX:
6086b103855eSStephen Hurd 	case IFLIB_INTR_RXTX:
60870b75ac77SStephen Hurd 		/* RX queues get the specified core */
6088b103855eSStephen Hurd 		return qid / CPU_COUNT(&ctx->ifc_cpus);
6089b103855eSStephen Hurd 	default:
6090b103855eSStephen Hurd 		return -1;
6091b103855eSStephen Hurd 	}
6092b103855eSStephen Hurd }
6093b103855eSStephen Hurd #else
60940b75ac77SStephen Hurd #define get_core_offset(ctx, type, qid)	CPU_FIRST()
60950b75ac77SStephen Hurd #define find_close_core(cpuid, tid)	CPU_FIRST()
6096b103855eSStephen Hurd #define find_nth(ctx, gid)		CPU_FIRST()
6097b103855eSStephen Hurd #endif
6098b103855eSStephen Hurd 
6099b103855eSStephen Hurd /* Just to avoid copy/paste */
6100b103855eSStephen Hurd static inline int
6101f855ec81SMarius Strobl iflib_irq_set_affinity(if_ctx_t ctx, if_irq_t irq, iflib_intr_type_t type,
6102f855ec81SMarius Strobl     int qid, struct grouptask *gtask, struct taskqgroup *tqg, void *uniq,
6103f855ec81SMarius Strobl     const char *name)
6104b103855eSStephen Hurd {
6105f855ec81SMarius Strobl 	device_t dev;
6106f154ece0SStephen Hurd 	int co, cpuid, err, tid;
6107b103855eSStephen Hurd 
6108f855ec81SMarius Strobl 	dev = ctx->ifc_dev;
6109f154ece0SStephen Hurd 	co = ctx->ifc_sysctl_core_offset;
6110f154ece0SStephen Hurd 	if (ctx->ifc_sysctl_separate_txrx && type == IFLIB_INTR_TX)
6111f154ece0SStephen Hurd 		co += ctx->ifc_softc_ctx.isc_nrxqsets;
6112f154ece0SStephen Hurd 	cpuid = find_nth(ctx, qid + co);
61130b75ac77SStephen Hurd 	tid = get_core_offset(ctx, type, qid);
61143d10e9edSMarius Strobl 	if (tid < 0) {
61153d10e9edSMarius Strobl 		device_printf(dev, "get_core_offset failed\n");
61163d10e9edSMarius Strobl 		return (EOPNOTSUPP);
61173d10e9edSMarius Strobl 	}
61180b75ac77SStephen Hurd 	cpuid = find_close_core(cpuid, tid);
6119f855ec81SMarius Strobl 	err = taskqgroup_attach_cpu(tqg, gtask, uniq, cpuid, dev, irq->ii_res,
6120f855ec81SMarius Strobl 	    name);
6121b103855eSStephen Hurd 	if (err) {
6122f855ec81SMarius Strobl 		device_printf(dev, "taskqgroup_attach_cpu failed %d\n", err);
6123b103855eSStephen Hurd 		return (err);
6124b103855eSStephen Hurd 	}
6125b103855eSStephen Hurd #ifdef notyet
6126b103855eSStephen Hurd 	if (cpuid > ctx->ifc_cpuid_highest)
6127b103855eSStephen Hurd 		ctx->ifc_cpuid_highest = cpuid;
6128b103855eSStephen Hurd #endif
61293d10e9edSMarius Strobl 	return (0);
6130b103855eSStephen Hurd }
6131b103855eSStephen Hurd 
61324c7070dbSScott Long int
61334c7070dbSScott Long iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid,
61344c7070dbSScott Long 			iflib_intr_type_t type, driver_filter_t *filter,
61353e0e6330SStephen Hurd 			void *filter_arg, int qid, const char *name)
61364c7070dbSScott Long {
6137f855ec81SMarius Strobl 	device_t dev;
61384c7070dbSScott Long 	struct grouptask *gtask;
61394c7070dbSScott Long 	struct taskqgroup *tqg;
61404c7070dbSScott Long 	iflib_filter_info_t info;
614123ac9029SStephen Hurd 	gtask_fn_t *fn;
6142b103855eSStephen Hurd 	int tqrid, err;
614395246abbSSean Bruno 	driver_filter_t *intr_fast;
61444c7070dbSScott Long 	void *q;
61454c7070dbSScott Long 
61464c7070dbSScott Long 	info = &ctx->ifc_filter_info;
6147add6f7d0SSean Bruno 	tqrid = rid;
61484c7070dbSScott Long 
61494c7070dbSScott Long 	switch (type) {
61504c7070dbSScott Long 	/* XXX merge tx/rx for netmap? */
61514c7070dbSScott Long 	case IFLIB_INTR_TX:
61524c7070dbSScott Long 		q = &ctx->ifc_txqs[qid];
61534c7070dbSScott Long 		info = &ctx->ifc_txqs[qid].ift_filter_info;
61544c7070dbSScott Long 		gtask = &ctx->ifc_txqs[qid].ift_task;
6155ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
61564c7070dbSScott Long 		fn = _task_fn_tx;
615795246abbSSean Bruno 		intr_fast = iflib_fast_intr;
6158da69b8f9SSean Bruno 		GROUPTASK_INIT(gtask, 0, fn, q);
61595ee36c68SStephen Hurd 		ctx->ifc_flags |= IFC_NETMAP_TX_IRQ;
61604c7070dbSScott Long 		break;
61614c7070dbSScott Long 	case IFLIB_INTR_RX:
61624c7070dbSScott Long 		q = &ctx->ifc_rxqs[qid];
61634c7070dbSScott Long 		info = &ctx->ifc_rxqs[qid].ifr_filter_info;
61644c7070dbSScott Long 		gtask = &ctx->ifc_rxqs[qid].ifr_task;
6165ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
61664c7070dbSScott Long 		fn = _task_fn_rx;
6167ab2e3f79SStephen Hurd 		intr_fast = iflib_fast_intr;
61686c3e93cbSGleb Smirnoff 		NET_GROUPTASK_INIT(gtask, 0, fn, q);
616995246abbSSean Bruno 		break;
617095246abbSSean Bruno 	case IFLIB_INTR_RXTX:
617195246abbSSean Bruno 		q = &ctx->ifc_rxqs[qid];
617295246abbSSean Bruno 		info = &ctx->ifc_rxqs[qid].ifr_filter_info;
617395246abbSSean Bruno 		gtask = &ctx->ifc_rxqs[qid].ifr_task;
6174ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
617595246abbSSean Bruno 		fn = _task_fn_rx;
617695246abbSSean Bruno 		intr_fast = iflib_fast_intr_rxtx;
61776c3e93cbSGleb Smirnoff 		NET_GROUPTASK_INIT(gtask, 0, fn, q);
61784c7070dbSScott Long 		break;
61794c7070dbSScott Long 	case IFLIB_INTR_ADMIN:
61804c7070dbSScott Long 		q = ctx;
6181da69b8f9SSean Bruno 		tqrid = -1;
61824c7070dbSScott Long 		info = &ctx->ifc_filter_info;
61834c7070dbSScott Long 		gtask = &ctx->ifc_admin_task;
6184ab2e3f79SStephen Hurd 		tqg = qgroup_if_config_tqg;
61854c7070dbSScott Long 		fn = _task_fn_admin;
618695246abbSSean Bruno 		intr_fast = iflib_fast_intr_ctx;
61874c7070dbSScott Long 		break;
61884c7070dbSScott Long 	default:
61893d10e9edSMarius Strobl 		device_printf(ctx->ifc_dev, "%s: unknown net intr type\n",
61903d10e9edSMarius Strobl 		    __func__);
61913d10e9edSMarius Strobl 		return (EINVAL);
61924c7070dbSScott Long 	}
61934c7070dbSScott Long 
61944c7070dbSScott Long 	info->ifi_filter = filter;
61954c7070dbSScott Long 	info->ifi_filter_arg = filter_arg;
61964c7070dbSScott Long 	info->ifi_task = gtask;
619795246abbSSean Bruno 	info->ifi_ctx = q;
61984c7070dbSScott Long 
6199f855ec81SMarius Strobl 	dev = ctx->ifc_dev;
620095246abbSSean Bruno 	err = _iflib_irq_alloc(ctx, irq, rid, intr_fast, NULL, info,  name);
6201da69b8f9SSean Bruno 	if (err != 0) {
6202f855ec81SMarius Strobl 		device_printf(dev, "_iflib_irq_alloc failed %d\n", err);
62034c7070dbSScott Long 		return (err);
6204da69b8f9SSean Bruno 	}
6205da69b8f9SSean Bruno 	if (type == IFLIB_INTR_ADMIN)
6206da69b8f9SSean Bruno 		return (0);
6207da69b8f9SSean Bruno 
62084c7070dbSScott Long 	if (tqrid != -1) {
6209f855ec81SMarius Strobl 		err = iflib_irq_set_affinity(ctx, irq, type, qid, gtask, tqg,
6210f855ec81SMarius Strobl 		    q, name);
6211b103855eSStephen Hurd 		if (err)
6212b103855eSStephen Hurd 			return (err);
6213aa3c5dd8SSean Bruno 	} else {
6214f855ec81SMarius Strobl 		taskqgroup_attach(tqg, gtask, q, dev, irq->ii_res, name);
6215aa3c5dd8SSean Bruno 	}
62164c7070dbSScott Long 
62174c7070dbSScott Long 	return (0);
62184c7070dbSScott Long }
62194c7070dbSScott Long 
62204c7070dbSScott Long void
62213e0e6330SStephen 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)
62224c7070dbSScott Long {
62234c7070dbSScott Long 	struct grouptask *gtask;
62244c7070dbSScott Long 	struct taskqgroup *tqg;
622523ac9029SStephen Hurd 	gtask_fn_t *fn;
62264c7070dbSScott Long 	void *q;
6227b103855eSStephen Hurd 	int err;
62284c7070dbSScott Long 
62294c7070dbSScott Long 	switch (type) {
62304c7070dbSScott Long 	case IFLIB_INTR_TX:
62314c7070dbSScott Long 		q = &ctx->ifc_txqs[qid];
62324c7070dbSScott Long 		gtask = &ctx->ifc_txqs[qid].ift_task;
6233ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
62344c7070dbSScott Long 		fn = _task_fn_tx;
6235f98977b5SHans Petter Selasky 		GROUPTASK_INIT(gtask, 0, fn, q);
62364c7070dbSScott Long 		break;
62374c7070dbSScott Long 	case IFLIB_INTR_RX:
62384c7070dbSScott Long 		q = &ctx->ifc_rxqs[qid];
62394c7070dbSScott Long 		gtask = &ctx->ifc_rxqs[qid].ifr_task;
6240ab2e3f79SStephen Hurd 		tqg = qgroup_if_io_tqg;
62414c7070dbSScott Long 		fn = _task_fn_rx;
6242f98977b5SHans Petter Selasky 		NET_GROUPTASK_INIT(gtask, 0, fn, q);
62434c7070dbSScott Long 		break;
62444c7070dbSScott Long 	case IFLIB_INTR_IOV:
62454c7070dbSScott Long 		q = ctx;
62464c7070dbSScott Long 		gtask = &ctx->ifc_vflr_task;
6247ab2e3f79SStephen Hurd 		tqg = qgroup_if_config_tqg;
62484c7070dbSScott Long 		fn = _task_fn_iov;
6249f98977b5SHans Petter Selasky 		GROUPTASK_INIT(gtask, 0, fn, q);
62504c7070dbSScott Long 		break;
62514c7070dbSScott Long 	default:
62524c7070dbSScott Long 		panic("unknown net intr type");
62534c7070dbSScott Long 	}
6254f855ec81SMarius Strobl 	if (irq != NULL) {
6255f855ec81SMarius Strobl 		err = iflib_irq_set_affinity(ctx, irq, type, qid, gtask, tqg,
6256f855ec81SMarius Strobl 		    q, name);
6257b103855eSStephen Hurd 		if (err)
6258f855ec81SMarius Strobl 			taskqgroup_attach(tqg, gtask, q, ctx->ifc_dev,
6259f855ec81SMarius Strobl 			    irq->ii_res, name);
6260f855ec81SMarius Strobl 	} else {
6261f855ec81SMarius Strobl 		taskqgroup_attach(tqg, gtask, q, NULL, NULL, name);
6262b103855eSStephen Hurd 	}
6263b103855eSStephen Hurd }
62644c7070dbSScott Long 
62654c7070dbSScott Long void
62664c7070dbSScott Long iflib_irq_free(if_ctx_t ctx, if_irq_t irq)
62674c7070dbSScott Long {
6268b97de13aSMarius Strobl 
62694c7070dbSScott Long 	if (irq->ii_tag)
62704c7070dbSScott Long 		bus_teardown_intr(ctx->ifc_dev, irq->ii_res, irq->ii_tag);
62714c7070dbSScott Long 
62724c7070dbSScott Long 	if (irq->ii_res)
6273b97de13aSMarius Strobl 		bus_release_resource(ctx->ifc_dev, SYS_RES_IRQ,
6274b97de13aSMarius Strobl 		    rman_get_rid(irq->ii_res), irq->ii_res);
62754c7070dbSScott Long }
62764c7070dbSScott Long 
62774c7070dbSScott Long static int
62783e0e6330SStephen Hurd iflib_legacy_setup(if_ctx_t ctx, driver_filter_t filter, void *filter_arg, int *rid, const char *name)
62794c7070dbSScott Long {
62804c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
62814c7070dbSScott Long 	iflib_rxq_t rxq = ctx->ifc_rxqs;
62824c7070dbSScott Long 	if_irq_t irq = &ctx->ifc_legacy_irq;
62834c7070dbSScott Long 	iflib_filter_info_t info;
6284f855ec81SMarius Strobl 	device_t dev;
62854c7070dbSScott Long 	struct grouptask *gtask;
6286f855ec81SMarius Strobl 	struct resource *res;
62874c7070dbSScott Long 	struct taskqgroup *tqg;
62884c7070dbSScott Long 	void *q;
6289d49e83eaSMarius Strobl 	int err, tqrid;
629041669133SMark Johnston 	bool rx_only;
62914c7070dbSScott Long 
62924c7070dbSScott Long 	q = &ctx->ifc_rxqs[0];
62934c7070dbSScott Long 	info = &rxq[0].ifr_filter_info;
62944c7070dbSScott Long 	gtask = &rxq[0].ifr_task;
6295ab2e3f79SStephen Hurd 	tqg = qgroup_if_io_tqg;
6296d49e83eaSMarius Strobl 	tqrid = *rid;
629741669133SMark Johnston 	rx_only = (ctx->ifc_sctx->isc_flags & IFLIB_SINGLE_IRQ_RX_ONLY) != 0;
62984c7070dbSScott Long 
62994c7070dbSScott Long 	ctx->ifc_flags |= IFC_LEGACY;
63004c7070dbSScott Long 	info->ifi_filter = filter;
63014c7070dbSScott Long 	info->ifi_filter_arg = filter_arg;
63024c7070dbSScott Long 	info->ifi_task = gtask;
630341669133SMark Johnston 	info->ifi_ctx = rx_only ? ctx : q;
63044c7070dbSScott Long 
6305f855ec81SMarius Strobl 	dev = ctx->ifc_dev;
63064c7070dbSScott Long 	/* We allocate a single interrupt resource */
630741669133SMark Johnston 	err = _iflib_irq_alloc(ctx, irq, tqrid, rx_only ? iflib_fast_intr_ctx :
630841669133SMark Johnston 	    iflib_fast_intr_rxtx, NULL, info, name);
630941669133SMark Johnston 	if (err != 0)
63104c7070dbSScott Long 		return (err);
6311f98977b5SHans Petter Selasky 	NET_GROUPTASK_INIT(gtask, 0, _task_fn_rx, q);
6312f855ec81SMarius Strobl 	res = irq->ii_res;
6313f855ec81SMarius Strobl 	taskqgroup_attach(tqg, gtask, q, dev, res, name);
63144c7070dbSScott Long 
63154c7070dbSScott Long 	GROUPTASK_INIT(&txq->ift_task, 0, _task_fn_tx, txq);
6316f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_io_tqg, &txq->ift_task, txq, dev, res,
6317f855ec81SMarius Strobl 	    "tx");
63184c7070dbSScott Long 	return (0);
63194c7070dbSScott Long }
63204c7070dbSScott Long 
63214c7070dbSScott Long void
63224c7070dbSScott Long iflib_led_create(if_ctx_t ctx)
63234c7070dbSScott Long {
63244c7070dbSScott Long 
63254c7070dbSScott Long 	ctx->ifc_led_dev = led_create(iflib_led_func, ctx,
63264c7070dbSScott Long 	    device_get_nameunit(ctx->ifc_dev));
63274c7070dbSScott Long }
63284c7070dbSScott Long 
63294c7070dbSScott Long void
63304c7070dbSScott Long iflib_tx_intr_deferred(if_ctx_t ctx, int txqid)
63314c7070dbSScott Long {
63324c7070dbSScott Long 
63334c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_txqs[txqid].ift_task);
63344c7070dbSScott Long }
63354c7070dbSScott Long 
63364c7070dbSScott Long void
63374c7070dbSScott Long iflib_rx_intr_deferred(if_ctx_t ctx, int rxqid)
63384c7070dbSScott Long {
63394c7070dbSScott Long 
63404c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_rxqs[rxqid].ifr_task);
63414c7070dbSScott Long }
63424c7070dbSScott Long 
63434c7070dbSScott Long void
63444c7070dbSScott Long iflib_admin_intr_deferred(if_ctx_t ctx)
63454c7070dbSScott Long {
634646fa0c25SEric Joyner 
6347ed6611ccSEd Maste 	MPASS(ctx->ifc_admin_task.gt_taskqueue != NULL);
63484c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_admin_task);
63494c7070dbSScott Long }
63504c7070dbSScott Long 
63514c7070dbSScott Long void
63524c7070dbSScott Long iflib_iov_intr_deferred(if_ctx_t ctx)
63534c7070dbSScott Long {
63544c7070dbSScott Long 
63554c7070dbSScott Long 	GROUPTASK_ENQUEUE(&ctx->ifc_vflr_task);
63564c7070dbSScott Long }
63574c7070dbSScott Long 
63584c7070dbSScott Long void
6359d49e83eaSMarius Strobl iflib_io_tqg_attach(struct grouptask *gt, void *uniq, int cpu, const char *name)
63604c7070dbSScott Long {
63614c7070dbSScott Long 
6362f855ec81SMarius Strobl 	taskqgroup_attach_cpu(qgroup_if_io_tqg, gt, uniq, cpu, NULL, NULL,
6363f855ec81SMarius Strobl 	    name);
63644c7070dbSScott Long }
63654c7070dbSScott Long 
63664c7070dbSScott Long void
6367aa8a24d3SStephen Hurd iflib_config_gtask_init(void *ctx, struct grouptask *gtask, gtask_fn_t *fn,
6368aa8a24d3SStephen Hurd 	const char *name)
63694c7070dbSScott Long {
63704c7070dbSScott Long 
63714c7070dbSScott Long 	GROUPTASK_INIT(gtask, 0, fn, ctx);
6372f855ec81SMarius Strobl 	taskqgroup_attach(qgroup_if_config_tqg, gtask, gtask, NULL, NULL,
6373f855ec81SMarius Strobl 	    name);
63744c7070dbSScott Long }
63754c7070dbSScott Long 
63764c7070dbSScott Long void
637723ac9029SStephen Hurd iflib_config_gtask_deinit(struct grouptask *gtask)
637823ac9029SStephen Hurd {
637923ac9029SStephen Hurd 
6380ab2e3f79SStephen Hurd 	taskqgroup_detach(qgroup_if_config_tqg, gtask);
638123ac9029SStephen Hurd }
638223ac9029SStephen Hurd 
638323ac9029SStephen Hurd void
638423ac9029SStephen Hurd iflib_link_state_change(if_ctx_t ctx, int link_state, uint64_t baudrate)
63854c7070dbSScott Long {
63864c7070dbSScott Long 	if_t ifp = ctx->ifc_ifp;
63874c7070dbSScott Long 	iflib_txq_t txq = ctx->ifc_txqs;
63884c7070dbSScott Long 
63894c7070dbSScott Long 	if_setbaudrate(ifp, baudrate);
63907b610b60SSean Bruno 	if (baudrate >= IF_Gbps(10)) {
63917b610b60SSean Bruno 		STATE_LOCK(ctx);
639295246abbSSean Bruno 		ctx->ifc_flags |= IFC_PREFETCH;
63937b610b60SSean Bruno 		STATE_UNLOCK(ctx);
63947b610b60SSean Bruno 	}
63954c7070dbSScott Long 	/* If link down, disable watchdog */
63964c7070dbSScott Long 	if ((ctx->ifc_link_state == LINK_STATE_UP) && (link_state == LINK_STATE_DOWN)) {
63974c7070dbSScott Long 		for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxqsets; i++, txq++)
63984c7070dbSScott Long 			txq->ift_qstatus = IFLIB_QUEUE_IDLE;
63994c7070dbSScott Long 	}
64004c7070dbSScott Long 	ctx->ifc_link_state = link_state;
64014c7070dbSScott Long 	if_link_state_change(ifp, link_state);
64024c7070dbSScott Long }
64034c7070dbSScott Long 
64044c7070dbSScott Long static int
64054c7070dbSScott Long iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq)
64064c7070dbSScott Long {
64074c7070dbSScott Long 	int credits;
64081248952aSSean Bruno #ifdef INVARIANTS
64091248952aSSean Bruno 	int credits_pre = txq->ift_cidx_processed;
64101248952aSSean Bruno #endif
64114c7070dbSScott Long 
64128a04b53dSKonstantin Belousov 	bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map,
64138a04b53dSKonstantin Belousov 	    BUS_DMASYNC_POSTREAD);
641495246abbSSean Bruno 	if ((credits = ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, true)) == 0)
64154c7070dbSScott Long 		return (0);
64164c7070dbSScott Long 
64174c7070dbSScott Long 	txq->ift_processed += credits;
64184c7070dbSScott Long 	txq->ift_cidx_processed += credits;
64194c7070dbSScott Long 
64201248952aSSean Bruno 	MPASS(credits_pre + credits == txq->ift_cidx_processed);
64214c7070dbSScott Long 	if (txq->ift_cidx_processed >= txq->ift_size)
64224c7070dbSScott Long 		txq->ift_cidx_processed -= txq->ift_size;
64234c7070dbSScott Long 	return (credits);
64244c7070dbSScott Long }
64254c7070dbSScott Long 
64264c7070dbSScott Long static int
642795246abbSSean Bruno iflib_rxd_avail(if_ctx_t ctx, iflib_rxq_t rxq, qidx_t cidx, qidx_t budget)
64284c7070dbSScott Long {
642995dcf343SMarius Strobl 	iflib_fl_t fl;
643095dcf343SMarius Strobl 	u_int i;
64314c7070dbSScott Long 
643295dcf343SMarius Strobl 	for (i = 0, fl = &rxq->ifr_fl[0]; i < rxq->ifr_nfl; i++, fl++)
643395dcf343SMarius Strobl 		bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map,
643495dcf343SMarius Strobl 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
643523ac9029SStephen Hurd 	return (ctx->isc_rxd_available(ctx->ifc_softc, rxq->ifr_id, cidx,
643623ac9029SStephen Hurd 	    budget));
64374c7070dbSScott Long }
64384c7070dbSScott Long 
64394c7070dbSScott Long void
64404c7070dbSScott Long iflib_add_int_delay_sysctl(if_ctx_t ctx, const char *name,
64414c7070dbSScott Long 	const char *description, if_int_delay_info_t info,
64424c7070dbSScott Long 	int offset, int value)
64434c7070dbSScott Long {
64444c7070dbSScott Long 	info->iidi_ctx = ctx;
64454c7070dbSScott Long 	info->iidi_offset = offset;
64464c7070dbSScott Long 	info->iidi_value = value;
64474c7070dbSScott Long 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(ctx->ifc_dev),
64484c7070dbSScott Long 	    SYSCTL_CHILDREN(device_get_sysctl_tree(ctx->ifc_dev)),
64497029da5cSPawel Biernacki 	    OID_AUTO, name, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
64504c7070dbSScott Long 	    info, 0, iflib_sysctl_int_delay, "I", description);
64514c7070dbSScott Long }
64524c7070dbSScott Long 
6453aa8a24d3SStephen Hurd struct sx *
64544c7070dbSScott Long iflib_ctx_lock_get(if_ctx_t ctx)
64554c7070dbSScott Long {
64564c7070dbSScott Long 
6457aa8a24d3SStephen Hurd 	return (&ctx->ifc_ctx_sx);
64584c7070dbSScott Long }
64594c7070dbSScott Long 
64604c7070dbSScott Long static int
64614c7070dbSScott Long iflib_msix_init(if_ctx_t ctx)
64624c7070dbSScott Long {
64634c7070dbSScott Long 	device_t dev = ctx->ifc_dev;
64644c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
64654c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
64663d10e9edSMarius Strobl 	int admincnt, bar, err, iflib_num_rx_queues, iflib_num_tx_queues;
64673d10e9edSMarius Strobl 	int msgs, queuemsgs, queues, rx_queues, tx_queues, vectors;
64684c7070dbSScott Long 
6469d2735264SStephen Hurd 	iflib_num_tx_queues = ctx->ifc_sysctl_ntxqs;
6470d2735264SStephen Hurd 	iflib_num_rx_queues = ctx->ifc_sysctl_nrxqs;
647123ac9029SStephen Hurd 
6472b97de13aSMarius Strobl 	if (bootverbose)
6473b97de13aSMarius Strobl 		device_printf(dev, "msix_init qsets capped at %d\n",
6474b97de13aSMarius Strobl 		    imax(scctx->isc_ntxqsets, scctx->isc_nrxqsets));
64751248952aSSean Bruno 
64764c7070dbSScott Long 	/* Override by tuneable */
6477ea351d3fSSean Bruno 	if (scctx->isc_disable_msix)
64784c7070dbSScott Long 		goto msi;
64794c7070dbSScott Long 
6480b97de13aSMarius Strobl 	/* First try MSI-X */
6481b97de13aSMarius Strobl 	if ((msgs = pci_msix_count(dev)) == 0) {
6482b97de13aSMarius Strobl 		if (bootverbose)
6483b97de13aSMarius Strobl 			device_printf(dev, "MSI-X not supported or disabled\n");
6484b97de13aSMarius Strobl 		goto msi;
6485b97de13aSMarius Strobl 	}
64863d10e9edSMarius Strobl 
64873d10e9edSMarius Strobl 	bar = ctx->ifc_softc_ctx.isc_msix_bar;
64884c7070dbSScott Long 	/*
64894c7070dbSScott Long 	 * bar == -1 => "trust me I know what I'm doing"
64904c7070dbSScott Long 	 * Some drivers are for hardware that is so shoddily
64914c7070dbSScott Long 	 * documented that no one knows which bars are which
64924c7070dbSScott Long 	 * so the developer has to map all bars. This hack
6493b97de13aSMarius Strobl 	 * allows shoddy garbage to use MSI-X in this framework.
64944c7070dbSScott Long 	 */
64954c7070dbSScott Long 	if (bar != -1) {
64964c7070dbSScott Long 		ctx->ifc_msix_mem = bus_alloc_resource_any(dev,
64974c7070dbSScott Long 	            SYS_RES_MEMORY, &bar, RF_ACTIVE);
64984c7070dbSScott Long 		if (ctx->ifc_msix_mem == NULL) {
6499b97de13aSMarius Strobl 			device_printf(dev, "Unable to map MSI-X table\n");
65004c7070dbSScott Long 			goto msi;
65014c7070dbSScott Long 		}
65024c7070dbSScott Long 	}
65033d10e9edSMarius Strobl 
65043d10e9edSMarius Strobl 	admincnt = sctx->isc_admin_intrcnt;
65054c7070dbSScott Long #if IFLIB_DEBUG
65064c7070dbSScott Long 	/* use only 1 qset in debug mode */
65074c7070dbSScott Long 	queuemsgs = min(msgs - admincnt, 1);
65084c7070dbSScott Long #else
65094c7070dbSScott Long 	queuemsgs = msgs - admincnt;
65104c7070dbSScott Long #endif
65114c7070dbSScott Long #ifdef RSS
65124c7070dbSScott Long 	queues = imin(queuemsgs, rss_getnumbuckets());
65134c7070dbSScott Long #else
65144c7070dbSScott Long 	queues = queuemsgs;
65154c7070dbSScott Long #endif
65164c7070dbSScott Long 	queues = imin(CPU_COUNT(&ctx->ifc_cpus), queues);
6517b97de13aSMarius Strobl 	if (bootverbose)
6518b97de13aSMarius Strobl 		device_printf(dev,
6519b97de13aSMarius Strobl 		    "intr CPUs: %d queue msgs: %d admincnt: %d\n",
65204c7070dbSScott Long 		    CPU_COUNT(&ctx->ifc_cpus), queuemsgs, admincnt);
65214c7070dbSScott Long #ifdef  RSS
65224c7070dbSScott Long 	/* If we're doing RSS, clamp at the number of RSS buckets */
65234c7070dbSScott Long 	if (queues > rss_getnumbuckets())
65244c7070dbSScott Long 		queues = rss_getnumbuckets();
65254c7070dbSScott Long #endif
652623ac9029SStephen Hurd 	if (iflib_num_rx_queues > 0 && iflib_num_rx_queues < queuemsgs - admincnt)
652723ac9029SStephen Hurd 		rx_queues = iflib_num_rx_queues;
65284c7070dbSScott Long 	else
65294c7070dbSScott Long 		rx_queues = queues;
6530d2735264SStephen Hurd 
6531d2735264SStephen Hurd 	if (rx_queues > scctx->isc_nrxqsets)
6532d2735264SStephen Hurd 		rx_queues = scctx->isc_nrxqsets;
6533d2735264SStephen Hurd 
653423ac9029SStephen Hurd 	/*
653523ac9029SStephen Hurd 	 * We want this to be all logical CPUs by default
653623ac9029SStephen Hurd 	 */
65374c7070dbSScott Long 	if (iflib_num_tx_queues > 0 && iflib_num_tx_queues < queues)
65384c7070dbSScott Long 		tx_queues = iflib_num_tx_queues;
65394c7070dbSScott Long 	else
654023ac9029SStephen Hurd 		tx_queues = mp_ncpus;
654123ac9029SStephen Hurd 
6542d2735264SStephen Hurd 	if (tx_queues > scctx->isc_ntxqsets)
6543d2735264SStephen Hurd 		tx_queues = scctx->isc_ntxqsets;
6544d2735264SStephen Hurd 
654523ac9029SStephen Hurd 	if (ctx->ifc_sysctl_qs_eq_override == 0) {
654623ac9029SStephen Hurd #ifdef INVARIANTS
654723ac9029SStephen Hurd 		if (tx_queues != rx_queues)
654877c1fcecSEric Joyner 			device_printf(dev,
654977c1fcecSEric Joyner 			    "queue equality override not set, capping rx_queues at %d and tx_queues at %d\n",
655023ac9029SStephen Hurd 			    min(rx_queues, tx_queues), min(rx_queues, tx_queues));
655123ac9029SStephen Hurd #endif
655223ac9029SStephen Hurd 		tx_queues = min(rx_queues, tx_queues);
655323ac9029SStephen Hurd 		rx_queues = min(rx_queues, tx_queues);
655423ac9029SStephen Hurd 	}
65554c7070dbSScott Long 
65563d10e9edSMarius Strobl 	vectors = rx_queues + admincnt;
65573d10e9edSMarius Strobl 	if (msgs < vectors) {
65583d10e9edSMarius Strobl 		device_printf(dev,
65593d10e9edSMarius Strobl 		    "insufficient number of MSI-X vectors "
65603d10e9edSMarius Strobl 		    "(supported %d, need %d)\n", msgs, vectors);
65613d10e9edSMarius Strobl 		goto msi;
65623d10e9edSMarius Strobl 	}
65633d10e9edSMarius Strobl 
65641722eeacSMarius Strobl 	device_printf(dev, "Using %d RX queues %d TX queues\n", rx_queues,
65651722eeacSMarius Strobl 	    tx_queues);
65663d10e9edSMarius Strobl 	msgs = vectors;
65674c7070dbSScott Long 	if ((err = pci_alloc_msix(dev, &vectors)) == 0) {
65683d10e9edSMarius Strobl 		if (vectors != msgs) {
65693d10e9edSMarius Strobl 			device_printf(dev,
65703d10e9edSMarius Strobl 			    "Unable to allocate sufficient MSI-X vectors "
65713d10e9edSMarius Strobl 			    "(got %d, need %d)\n", vectors, msgs);
65723d10e9edSMarius Strobl 			pci_release_msi(dev);
65733d10e9edSMarius Strobl 			if (bar != -1) {
65743d10e9edSMarius Strobl 				bus_release_resource(dev, SYS_RES_MEMORY, bar,
65753d10e9edSMarius Strobl 				    ctx->ifc_msix_mem);
65763d10e9edSMarius Strobl 				ctx->ifc_msix_mem = NULL;
65773d10e9edSMarius Strobl 			}
65783d10e9edSMarius Strobl 			goto msi;
65793d10e9edSMarius Strobl 		}
6580b97de13aSMarius Strobl 		device_printf(dev, "Using MSI-X interrupts with %d vectors\n",
6581b97de13aSMarius Strobl 		    vectors);
65824c7070dbSScott Long 		scctx->isc_vectors = vectors;
65834c7070dbSScott Long 		scctx->isc_nrxqsets = rx_queues;
65844c7070dbSScott Long 		scctx->isc_ntxqsets = tx_queues;
65854c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_MSIX;
658623ac9029SStephen Hurd 
65874c7070dbSScott Long 		return (vectors);
65884c7070dbSScott Long 	} else {
658977c1fcecSEric Joyner 		device_printf(dev,
65903d10e9edSMarius Strobl 		    "failed to allocate %d MSI-X vectors, err: %d\n", vectors,
65913d10e9edSMarius Strobl 		    err);
65923d10e9edSMarius Strobl 		if (bar != -1) {
6593e4defe55SMarius Strobl 			bus_release_resource(dev, SYS_RES_MEMORY, bar,
6594e4defe55SMarius Strobl 			    ctx->ifc_msix_mem);
6595e4defe55SMarius Strobl 			ctx->ifc_msix_mem = NULL;
65964c7070dbSScott Long 		}
65973d10e9edSMarius Strobl 	}
65983d10e9edSMarius Strobl 
65994c7070dbSScott Long msi:
66004c7070dbSScott Long 	vectors = pci_msi_count(dev);
66014c7070dbSScott Long 	scctx->isc_nrxqsets = 1;
66024c7070dbSScott Long 	scctx->isc_ntxqsets = 1;
66034c7070dbSScott Long 	scctx->isc_vectors = vectors;
66044c7070dbSScott Long 	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) {
66054c7070dbSScott Long 		device_printf(dev,"Using an MSI interrupt\n");
66064c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_MSI;
66074c7070dbSScott Long 	} else {
6608e4defe55SMarius Strobl 		scctx->isc_vectors = 1;
66094c7070dbSScott Long 		device_printf(dev,"Using a Legacy interrupt\n");
66104c7070dbSScott Long 		scctx->isc_intr = IFLIB_INTR_LEGACY;
66114c7070dbSScott Long 	}
66124c7070dbSScott Long 
66134c7070dbSScott Long 	return (vectors);
66144c7070dbSScott Long }
66154c7070dbSScott Long 
6616e4defe55SMarius Strobl static const char *ring_states[] = { "IDLE", "BUSY", "STALLED", "ABDICATED" };
66174c7070dbSScott Long 
66184c7070dbSScott Long static int
66194c7070dbSScott Long mp_ring_state_handler(SYSCTL_HANDLER_ARGS)
66204c7070dbSScott Long {
66214c7070dbSScott Long 	int rc;
66224c7070dbSScott Long 	uint16_t *state = ((uint16_t *)oidp->oid_arg1);
66234c7070dbSScott Long 	struct sbuf *sb;
6624e4defe55SMarius Strobl 	const char *ring_state = "UNKNOWN";
66254c7070dbSScott Long 
66264c7070dbSScott Long 	/* XXX needed ? */
66274c7070dbSScott Long 	rc = sysctl_wire_old_buffer(req, 0);
66284c7070dbSScott Long 	MPASS(rc == 0);
66294c7070dbSScott Long 	if (rc != 0)
66304c7070dbSScott Long 		return (rc);
66314c7070dbSScott Long 	sb = sbuf_new_for_sysctl(NULL, NULL, 80, req);
66324c7070dbSScott Long 	MPASS(sb != NULL);
66334c7070dbSScott Long 	if (sb == NULL)
66344c7070dbSScott Long 		return (ENOMEM);
66354c7070dbSScott Long 	if (state[3] <= 3)
66364c7070dbSScott Long 		ring_state = ring_states[state[3]];
66374c7070dbSScott Long 
66384c7070dbSScott Long 	sbuf_printf(sb, "pidx_head: %04hd pidx_tail: %04hd cidx: %04hd state: %s",
66394c7070dbSScott Long 		    state[0], state[1], state[2], ring_state);
66404c7070dbSScott Long 	rc = sbuf_finish(sb);
66414c7070dbSScott Long 	sbuf_delete(sb);
66424c7070dbSScott Long         return(rc);
66434c7070dbSScott Long }
66444c7070dbSScott Long 
664523ac9029SStephen Hurd enum iflib_ndesc_handler {
664623ac9029SStephen Hurd 	IFLIB_NTXD_HANDLER,
664723ac9029SStephen Hurd 	IFLIB_NRXD_HANDLER,
664823ac9029SStephen Hurd };
66494c7070dbSScott Long 
665023ac9029SStephen Hurd static int
665123ac9029SStephen Hurd mp_ndesc_handler(SYSCTL_HANDLER_ARGS)
665223ac9029SStephen Hurd {
665323ac9029SStephen Hurd 	if_ctx_t ctx = (void *)arg1;
665423ac9029SStephen Hurd 	enum iflib_ndesc_handler type = arg2;
665523ac9029SStephen Hurd 	char buf[256] = {0};
665695246abbSSean Bruno 	qidx_t *ndesc;
665723ac9029SStephen Hurd 	char *p, *next;
665823ac9029SStephen Hurd 	int nqs, rc, i;
665923ac9029SStephen Hurd 
666023ac9029SStephen Hurd 	nqs = 8;
666123ac9029SStephen Hurd 	switch(type) {
666223ac9029SStephen Hurd 	case IFLIB_NTXD_HANDLER:
666323ac9029SStephen Hurd 		ndesc = ctx->ifc_sysctl_ntxds;
666423ac9029SStephen Hurd 		if (ctx->ifc_sctx)
666523ac9029SStephen Hurd 			nqs = ctx->ifc_sctx->isc_ntxqs;
666623ac9029SStephen Hurd 		break;
666723ac9029SStephen Hurd 	case IFLIB_NRXD_HANDLER:
666823ac9029SStephen Hurd 		ndesc = ctx->ifc_sysctl_nrxds;
666923ac9029SStephen Hurd 		if (ctx->ifc_sctx)
667023ac9029SStephen Hurd 			nqs = ctx->ifc_sctx->isc_nrxqs;
667123ac9029SStephen Hurd 		break;
66721ae4848cSMatt Macy 	default:
66733d10e9edSMarius Strobl 		printf("%s: unhandled type\n", __func__);
66743d10e9edSMarius Strobl 		return (EINVAL);
667523ac9029SStephen Hurd 	}
667623ac9029SStephen Hurd 	if (nqs == 0)
667723ac9029SStephen Hurd 		nqs = 8;
667823ac9029SStephen Hurd 
667923ac9029SStephen Hurd 	for (i=0; i<8; i++) {
668023ac9029SStephen Hurd 		if (i >= nqs)
668123ac9029SStephen Hurd 			break;
668223ac9029SStephen Hurd 		if (i)
668323ac9029SStephen Hurd 			strcat(buf, ",");
668423ac9029SStephen Hurd 		sprintf(strchr(buf, 0), "%d", ndesc[i]);
668523ac9029SStephen Hurd 	}
668623ac9029SStephen Hurd 
668723ac9029SStephen Hurd 	rc = sysctl_handle_string(oidp, buf, sizeof(buf), req);
668823ac9029SStephen Hurd 	if (rc || req->newptr == NULL)
668923ac9029SStephen Hurd 		return rc;
669023ac9029SStephen Hurd 
669123ac9029SStephen Hurd 	for (i = 0, next = buf, p = strsep(&next, " ,"); i < 8 && p;
669223ac9029SStephen Hurd 	    i++, p = strsep(&next, " ,")) {
669323ac9029SStephen Hurd 		ndesc[i] = strtoul(p, NULL, 10);
669423ac9029SStephen Hurd 	}
669523ac9029SStephen Hurd 
669623ac9029SStephen Hurd 	return(rc);
669723ac9029SStephen Hurd }
66984c7070dbSScott Long 
66994c7070dbSScott Long #define NAME_BUFLEN 32
67004c7070dbSScott Long static void
67014c7070dbSScott Long iflib_add_device_sysctl_pre(if_ctx_t ctx)
67024c7070dbSScott Long {
67034c7070dbSScott Long         device_t dev = iflib_get_dev(ctx);
67044c7070dbSScott Long 	struct sysctl_oid_list *child, *oid_list;
67054c7070dbSScott Long 	struct sysctl_ctx_list *ctx_list;
67064c7070dbSScott Long 	struct sysctl_oid *node;
67074c7070dbSScott Long 
67084c7070dbSScott Long 	ctx_list = device_get_sysctl_ctx(dev);
67094c7070dbSScott Long 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
67104c7070dbSScott Long 	ctx->ifc_sysctl_node = node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, "iflib",
67117029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "IFLIB fields");
67124c7070dbSScott Long 	oid_list = SYSCTL_CHILDREN(node);
67134c7070dbSScott Long 
671410a1e981SEric Joyner 	SYSCTL_ADD_CONST_STRING(ctx_list, oid_list, OID_AUTO, "driver_version",
671510a1e981SEric Joyner 		       CTLFLAG_RD, ctx->ifc_sctx->isc_driver_version,
671623ac9029SStephen Hurd 		       "driver version");
671723ac9029SStephen Hurd 
67184c7070dbSScott Long 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_ntxqs",
67194c7070dbSScott Long 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_ntxqs, 0,
67204c7070dbSScott Long 			"# of txqs to use, 0 => use default #");
67214c7070dbSScott Long 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_nrxqs",
672223ac9029SStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_nrxqs, 0,
672323ac9029SStephen Hurd 			"# of rxqs to use, 0 => use default #");
672423ac9029SStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_qs_enable",
672523ac9029SStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_qs_eq_override, 0,
672623ac9029SStephen Hurd                        "permit #txq != #rxq");
6727ea351d3fSSean Bruno 	SYSCTL_ADD_INT(ctx_list, oid_list, OID_AUTO, "disable_msix",
6728ea351d3fSSean Bruno                       CTLFLAG_RWTUN, &ctx->ifc_softc_ctx.isc_disable_msix, 0,
6729b97de13aSMarius Strobl                       "disable MSI-X (default 0)");
6730f4d2154eSStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "rx_budget",
6731f4d2154eSStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_rx_budget, 0,
67321722eeacSMarius Strobl 		       "set the RX budget");
6733fe51d4cdSStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "tx_abdicate",
6734fe51d4cdSStephen Hurd 		       CTLFLAG_RWTUN, &ctx->ifc_sysctl_tx_abdicate, 0,
67351722eeacSMarius Strobl 		       "cause TX to abdicate instead of running to completion");
6736f154ece0SStephen Hurd 	ctx->ifc_sysctl_core_offset = CORE_OFFSET_UNSPECIFIED;
6737f154ece0SStephen Hurd 	SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "core_offset",
6738f154ece0SStephen Hurd 		       CTLFLAG_RDTUN, &ctx->ifc_sysctl_core_offset, 0,
6739f154ece0SStephen Hurd 		       "offset to start using cores at");
6740f154ece0SStephen Hurd 	SYSCTL_ADD_U8(ctx_list, oid_list, OID_AUTO, "separate_txrx",
6741f154ece0SStephen Hurd 		       CTLFLAG_RDTUN, &ctx->ifc_sysctl_separate_txrx, 0,
6742f154ece0SStephen Hurd 		       "use separate cores for TX and RX");
67434c7070dbSScott Long 
674423ac9029SStephen Hurd 	/* XXX change for per-queue sizes */
674523ac9029SStephen Hurd 	SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_ntxds",
67467029da5cSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, ctx,
67477029da5cSPawel Biernacki 	    IFLIB_NTXD_HANDLER, mp_ndesc_handler, "A",
67481722eeacSMarius Strobl 	    "list of # of TX descriptors to use, 0 = use default #");
674923ac9029SStephen Hurd 	SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_nrxds",
67507029da5cSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, ctx,
67517029da5cSPawel Biernacki 	    IFLIB_NRXD_HANDLER, mp_ndesc_handler, "A",
67521722eeacSMarius Strobl 	    "list of # of RX descriptors to use, 0 = use default #");
67534c7070dbSScott Long }
67544c7070dbSScott Long 
67554c7070dbSScott Long static void
67564c7070dbSScott Long iflib_add_device_sysctl_post(if_ctx_t ctx)
67574c7070dbSScott Long {
67584c7070dbSScott Long 	if_shared_ctx_t sctx = ctx->ifc_sctx;
67594c7070dbSScott Long 	if_softc_ctx_t scctx = &ctx->ifc_softc_ctx;
67604c7070dbSScott Long         device_t dev = iflib_get_dev(ctx);
67614c7070dbSScott Long 	struct sysctl_oid_list *child;
67624c7070dbSScott Long 	struct sysctl_ctx_list *ctx_list;
67634c7070dbSScott Long 	iflib_fl_t fl;
67644c7070dbSScott Long 	iflib_txq_t txq;
67654c7070dbSScott Long 	iflib_rxq_t rxq;
67664c7070dbSScott Long 	int i, j;
67674c7070dbSScott Long 	char namebuf[NAME_BUFLEN];
67684c7070dbSScott Long 	char *qfmt;
67694c7070dbSScott Long 	struct sysctl_oid *queue_node, *fl_node, *node;
67704c7070dbSScott Long 	struct sysctl_oid_list *queue_list, *fl_list;
67714c7070dbSScott Long 	ctx_list = device_get_sysctl_ctx(dev);
67724c7070dbSScott Long 
67734c7070dbSScott Long 	node = ctx->ifc_sysctl_node;
67744c7070dbSScott Long 	child = SYSCTL_CHILDREN(node);
67754c7070dbSScott Long 
67764c7070dbSScott Long 	if (scctx->isc_ntxqsets > 100)
67774c7070dbSScott Long 		qfmt = "txq%03d";
67784c7070dbSScott Long 	else if (scctx->isc_ntxqsets > 10)
67794c7070dbSScott Long 		qfmt = "txq%02d";
67804c7070dbSScott Long 	else
67814c7070dbSScott Long 		qfmt = "txq%d";
67824c7070dbSScott Long 	for (i = 0, txq = ctx->ifc_txqs; i < scctx->isc_ntxqsets; i++, txq++) {
67834c7070dbSScott Long 		snprintf(namebuf, NAME_BUFLEN, qfmt, i);
67844c7070dbSScott Long 		queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf,
67857029da5cSPawel Biernacki 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
67864c7070dbSScott Long 		queue_list = SYSCTL_CHILDREN(queue_node);
67874c7070dbSScott Long #if MEMORY_LOGGING
67884c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_dequeued",
67894c7070dbSScott Long 				CTLFLAG_RD,
67904c7070dbSScott Long 				&txq->ift_dequeued, "total mbufs freed");
67914c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_enqueued",
67924c7070dbSScott Long 				CTLFLAG_RD,
67934c7070dbSScott Long 				&txq->ift_enqueued, "total mbufs enqueued");
67944c7070dbSScott Long #endif
67954c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "mbuf_defrag",
67964c7070dbSScott Long 				   CTLFLAG_RD,
67974c7070dbSScott Long 				   &txq->ift_mbuf_defrag, "# of times m_defrag was called");
67984c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "m_pullups",
67994c7070dbSScott Long 				   CTLFLAG_RD,
68004c7070dbSScott Long 				   &txq->ift_pullups, "# of times m_pullup was called");
68014c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "mbuf_defrag_failed",
68024c7070dbSScott Long 				   CTLFLAG_RD,
68034c7070dbSScott Long 				   &txq->ift_mbuf_defrag_failed, "# of times m_defrag failed");
68044c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "no_desc_avail",
68054c7070dbSScott Long 				   CTLFLAG_RD,
680623ac9029SStephen Hurd 				   &txq->ift_no_desc_avail, "# of times no descriptors were available");
68074c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "tx_map_failed",
68084c7070dbSScott Long 				   CTLFLAG_RD,
68091722eeacSMarius Strobl 				   &txq->ift_map_failed, "# of times DMA map failed");
68104c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txd_encap_efbig",
68114c7070dbSScott Long 				   CTLFLAG_RD,
68124c7070dbSScott Long 				   &txq->ift_txd_encap_efbig, "# of times txd_encap returned EFBIG");
68134c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "no_tx_dma_setup",
68144c7070dbSScott Long 				   CTLFLAG_RD,
68154c7070dbSScott Long 				   &txq->ift_no_tx_dma_setup, "# of times map failed for other than EFBIG");
68164c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_pidx",
68174c7070dbSScott Long 				   CTLFLAG_RD,
68184c7070dbSScott Long 				   &txq->ift_pidx, 1, "Producer Index");
68194c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_cidx",
68204c7070dbSScott Long 				   CTLFLAG_RD,
68214c7070dbSScott Long 				   &txq->ift_cidx, 1, "Consumer Index");
68224c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_cidx_processed",
68234c7070dbSScott Long 				   CTLFLAG_RD,
68244c7070dbSScott Long 				   &txq->ift_cidx_processed, 1, "Consumer Index seen by credit update");
68254c7070dbSScott Long 		SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_in_use",
68264c7070dbSScott Long 				   CTLFLAG_RD,
68274c7070dbSScott Long 				   &txq->ift_in_use, 1, "descriptors in use");
68284c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_processed",
68294c7070dbSScott Long 				   CTLFLAG_RD,
68304c7070dbSScott Long 				   &txq->ift_processed, "descriptors procesed for clean");
68314c7070dbSScott Long 		SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_cleaned",
68324c7070dbSScott Long 				   CTLFLAG_RD,
68334c7070dbSScott Long 				   &txq->ift_cleaned, "total cleaned");
68344c7070dbSScott Long 		SYSCTL_ADD_PROC(ctx_list, queue_list, OID_AUTO, "ring_state",
68357029da5cSPawel Biernacki 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
68367029da5cSPawel Biernacki 		    __DEVOLATILE(uint64_t *, &txq->ift_br->state), 0,
68377029da5cSPawel Biernacki 		    mp_ring_state_handler, "A", "soft ring state");
68384c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_enqueues",
683995246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->enqueues,
68404c7070dbSScott Long 				       "# of enqueues to the mp_ring for this queue");
68414c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_drops",
684295246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->drops,
68434c7070dbSScott Long 				       "# of drops in the mp_ring for this queue");
68444c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_starts",
684595246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->starts,
68464c7070dbSScott Long 				       "# of normal consumer starts in the mp_ring for this queue");
68474c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_stalls",
684895246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->stalls,
68494c7070dbSScott Long 					       "# of consumer stalls in the mp_ring for this queue");
68504c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_restarts",
685195246abbSSean Bruno 			       CTLFLAG_RD, &txq->ift_br->restarts,
68524c7070dbSScott Long 				       "# of consumer restarts in the mp_ring for this queue");
68534c7070dbSScott Long 		SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_abdications",
685495246abbSSean Bruno 				       CTLFLAG_RD, &txq->ift_br->abdications,
68554c7070dbSScott Long 				       "# of consumer abdications in the mp_ring for this queue");
68564c7070dbSScott Long 	}
68574c7070dbSScott Long 
68584c7070dbSScott Long 	if (scctx->isc_nrxqsets > 100)
68594c7070dbSScott Long 		qfmt = "rxq%03d";
68604c7070dbSScott Long 	else if (scctx->isc_nrxqsets > 10)
68614c7070dbSScott Long 		qfmt = "rxq%02d";
68624c7070dbSScott Long 	else
68634c7070dbSScott Long 		qfmt = "rxq%d";
68644c7070dbSScott Long 	for (i = 0, rxq = ctx->ifc_rxqs; i < scctx->isc_nrxqsets; i++, rxq++) {
68654c7070dbSScott Long 		snprintf(namebuf, NAME_BUFLEN, qfmt, i);
68664c7070dbSScott Long 		queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf,
68677029da5cSPawel Biernacki 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
68684c7070dbSScott Long 		queue_list = SYSCTL_CHILDREN(queue_node);
686923ac9029SStephen Hurd 		if (sctx->isc_flags & IFLIB_HAS_RXCQ) {
68704c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "rxq_cq_cidx",
68714c7070dbSScott Long 				       CTLFLAG_RD,
68724c7070dbSScott Long 				       &rxq->ifr_cq_cidx, 1, "Consumer Index");
68734c7070dbSScott Long 		}
6874da69b8f9SSean Bruno 
68754c7070dbSScott Long 		for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) {
68764c7070dbSScott Long 			snprintf(namebuf, NAME_BUFLEN, "rxq_fl%d", j);
68774c7070dbSScott Long 			fl_node = SYSCTL_ADD_NODE(ctx_list, queue_list, OID_AUTO, namebuf,
68787029da5cSPawel Biernacki 			    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "freelist Name");
68794c7070dbSScott Long 			fl_list = SYSCTL_CHILDREN(fl_node);
68804c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "pidx",
68814c7070dbSScott Long 				       CTLFLAG_RD,
68824c7070dbSScott Long 				       &fl->ifl_pidx, 1, "Producer Index");
68834c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "cidx",
68844c7070dbSScott Long 				       CTLFLAG_RD,
68854c7070dbSScott Long 				       &fl->ifl_cidx, 1, "Consumer Index");
68864c7070dbSScott Long 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "credits",
68874c7070dbSScott Long 				       CTLFLAG_RD,
68884c7070dbSScott Long 				       &fl->ifl_credits, 1, "credits available");
6889b3813609SPatrick Kelsey 			SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "buf_size",
6890b3813609SPatrick Kelsey 				       CTLFLAG_RD,
6891b3813609SPatrick Kelsey 				       &fl->ifl_buf_size, 1, "buffer size");
68924c7070dbSScott Long #if MEMORY_LOGGING
68934c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_m_enqueued",
68944c7070dbSScott Long 					CTLFLAG_RD,
68954c7070dbSScott Long 					&fl->ifl_m_enqueued, "mbufs allocated");
68964c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_m_dequeued",
68974c7070dbSScott Long 					CTLFLAG_RD,
68984c7070dbSScott Long 					&fl->ifl_m_dequeued, "mbufs freed");
68994c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_cl_enqueued",
69004c7070dbSScott Long 					CTLFLAG_RD,
69014c7070dbSScott Long 					&fl->ifl_cl_enqueued, "clusters allocated");
69024c7070dbSScott Long 			SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_cl_dequeued",
69034c7070dbSScott Long 					CTLFLAG_RD,
69044c7070dbSScott Long 					&fl->ifl_cl_dequeued, "clusters freed");
69054c7070dbSScott Long #endif
69064c7070dbSScott Long 		}
69074c7070dbSScott Long 	}
69084c7070dbSScott Long 
69094c7070dbSScott Long }
691095246abbSSean Bruno 
691177c1fcecSEric Joyner void
691277c1fcecSEric Joyner iflib_request_reset(if_ctx_t ctx)
691377c1fcecSEric Joyner {
691477c1fcecSEric Joyner 
691577c1fcecSEric Joyner 	STATE_LOCK(ctx);
691677c1fcecSEric Joyner 	ctx->ifc_flags |= IFC_DO_RESET;
691777c1fcecSEric Joyner 	STATE_UNLOCK(ctx);
691877c1fcecSEric Joyner }
691977c1fcecSEric Joyner 
692095246abbSSean Bruno #ifndef __NO_STRICT_ALIGNMENT
692195246abbSSean Bruno static struct mbuf *
692295246abbSSean Bruno iflib_fixup_rx(struct mbuf *m)
692395246abbSSean Bruno {
692495246abbSSean Bruno 	struct mbuf *n;
692595246abbSSean Bruno 
692695246abbSSean Bruno 	if (m->m_len <= (MCLBYTES - ETHER_HDR_LEN)) {
692795246abbSSean Bruno 		bcopy(m->m_data, m->m_data + ETHER_HDR_LEN, m->m_len);
692895246abbSSean Bruno 		m->m_data += ETHER_HDR_LEN;
692995246abbSSean Bruno 		n = m;
693095246abbSSean Bruno 	} else {
693195246abbSSean Bruno 		MGETHDR(n, M_NOWAIT, MT_DATA);
693295246abbSSean Bruno 		if (n == NULL) {
693395246abbSSean Bruno 			m_freem(m);
693495246abbSSean Bruno 			return (NULL);
693595246abbSSean Bruno 		}
693695246abbSSean Bruno 		bcopy(m->m_data, n->m_data, ETHER_HDR_LEN);
693795246abbSSean Bruno 		m->m_data += ETHER_HDR_LEN;
693895246abbSSean Bruno 		m->m_len -= ETHER_HDR_LEN;
693995246abbSSean Bruno 		n->m_len = ETHER_HDR_LEN;
694095246abbSSean Bruno 		M_MOVE_PKTHDR(n, m);
694195246abbSSean Bruno 		n->m_next = m;
694295246abbSSean Bruno 	}
694395246abbSSean Bruno 	return (n);
694495246abbSSean Bruno }
694595246abbSSean Bruno #endif
694694618825SMark Johnston 
69477790c8c1SConrad Meyer #ifdef DEBUGNET
694894618825SMark Johnston static void
69497790c8c1SConrad Meyer iflib_debugnet_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
695094618825SMark Johnston {
695194618825SMark Johnston 	if_ctx_t ctx;
695294618825SMark Johnston 
695394618825SMark Johnston 	ctx = if_getsoftc(ifp);
695494618825SMark Johnston 	CTX_LOCK(ctx);
695594618825SMark Johnston 	*nrxr = NRXQSETS(ctx);
695694618825SMark Johnston 	*ncl = ctx->ifc_rxqs[0].ifr_fl->ifl_size;
695794618825SMark Johnston 	*clsize = ctx->ifc_rxqs[0].ifr_fl->ifl_buf_size;
695894618825SMark Johnston 	CTX_UNLOCK(ctx);
695994618825SMark Johnston }
696094618825SMark Johnston 
696194618825SMark Johnston static void
69627790c8c1SConrad Meyer iflib_debugnet_event(if_t ifp, enum debugnet_ev event)
696394618825SMark Johnston {
696494618825SMark Johnston 	if_ctx_t ctx;
696594618825SMark Johnston 	if_softc_ctx_t scctx;
696694618825SMark Johnston 	iflib_fl_t fl;
696794618825SMark Johnston 	iflib_rxq_t rxq;
696894618825SMark Johnston 	int i, j;
696994618825SMark Johnston 
697094618825SMark Johnston 	ctx = if_getsoftc(ifp);
697194618825SMark Johnston 	scctx = &ctx->ifc_softc_ctx;
697294618825SMark Johnston 
697394618825SMark Johnston 	switch (event) {
69747790c8c1SConrad Meyer 	case DEBUGNET_START:
697594618825SMark Johnston 		for (i = 0; i < scctx->isc_nrxqsets; i++) {
697694618825SMark Johnston 			rxq = &ctx->ifc_rxqs[i];
697794618825SMark Johnston 			for (j = 0; j < rxq->ifr_nfl; j++) {
697894618825SMark Johnston 				fl = rxq->ifr_fl;
697994618825SMark Johnston 				fl->ifl_zone = m_getzone(fl->ifl_buf_size);
698094618825SMark Johnston 			}
698194618825SMark Johnston 		}
698294618825SMark Johnston 		iflib_no_tx_batch = 1;
698394618825SMark Johnston 		break;
698494618825SMark Johnston 	default:
698594618825SMark Johnston 		break;
698694618825SMark Johnston 	}
698794618825SMark Johnston }
698894618825SMark Johnston 
698994618825SMark Johnston static int
69907790c8c1SConrad Meyer iflib_debugnet_transmit(if_t ifp, struct mbuf *m)
699194618825SMark Johnston {
699294618825SMark Johnston 	if_ctx_t ctx;
699394618825SMark Johnston 	iflib_txq_t txq;
699494618825SMark Johnston 	int error;
699594618825SMark Johnston 
699694618825SMark Johnston 	ctx = if_getsoftc(ifp);
699794618825SMark Johnston 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
699894618825SMark Johnston 	    IFF_DRV_RUNNING)
699994618825SMark Johnston 		return (EBUSY);
700094618825SMark Johnston 
700194618825SMark Johnston 	txq = &ctx->ifc_txqs[0];
700294618825SMark Johnston 	error = iflib_encap(txq, &m);
700394618825SMark Johnston 	if (error == 0)
700481be6552SMatt Macy 		(void)iflib_txd_db_check(txq, true);
700594618825SMark Johnston 	return (error);
700694618825SMark Johnston }
700794618825SMark Johnston 
700894618825SMark Johnston static int
70097790c8c1SConrad Meyer iflib_debugnet_poll(if_t ifp, int count)
701094618825SMark Johnston {
70110b8df657SGleb Smirnoff 	struct epoch_tracker et;
701294618825SMark Johnston 	if_ctx_t ctx;
701394618825SMark Johnston 	if_softc_ctx_t scctx;
701494618825SMark Johnston 	iflib_txq_t txq;
701594618825SMark Johnston 	int i;
701694618825SMark Johnston 
701794618825SMark Johnston 	ctx = if_getsoftc(ifp);
701894618825SMark Johnston 	scctx = &ctx->ifc_softc_ctx;
701994618825SMark Johnston 
702094618825SMark Johnston 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
702194618825SMark Johnston 	    IFF_DRV_RUNNING)
702294618825SMark Johnston 		return (EBUSY);
702394618825SMark Johnston 
702494618825SMark Johnston 	txq = &ctx->ifc_txqs[0];
702594618825SMark Johnston 	(void)iflib_completed_tx_reclaim(txq, RECLAIM_THRESH(ctx));
702694618825SMark Johnston 
70270b8df657SGleb Smirnoff 	NET_EPOCH_ENTER(et);
702894618825SMark Johnston 	for (i = 0; i < scctx->isc_nrxqsets; i++)
702994618825SMark Johnston 		(void)iflib_rxeof(&ctx->ifc_rxqs[i], 16 /* XXX */);
70300b8df657SGleb Smirnoff 	NET_EPOCH_EXIT(et);
703194618825SMark Johnston 	return (0);
703294618825SMark Johnston }
70337790c8c1SConrad Meyer #endif /* DEBUGNET */
7034