xref: /freebsd/sys/dev/ixl/ixl_txrx.c (revision 71625ec9ad2a9bc8c09784fbd23b759830e0ee5f)
161ae650dSJack F Vogel /******************************************************************************
261ae650dSJack F Vogel 
3f4cc2d17SEric Joyner   Copyright (c) 2013-2018, Intel Corporation
461ae650dSJack F Vogel   All rights reserved.
561ae650dSJack F Vogel 
661ae650dSJack F Vogel   Redistribution and use in source and binary forms, with or without
761ae650dSJack F Vogel   modification, are permitted provided that the following conditions are met:
861ae650dSJack F Vogel 
961ae650dSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
1061ae650dSJack F Vogel       this list of conditions and the following disclaimer.
1161ae650dSJack F Vogel 
1261ae650dSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
1361ae650dSJack F Vogel       notice, this list of conditions and the following disclaimer in the
1461ae650dSJack F Vogel       documentation and/or other materials provided with the distribution.
1561ae650dSJack F Vogel 
1661ae650dSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
1761ae650dSJack F Vogel       contributors may be used to endorse or promote products derived from
1861ae650dSJack F Vogel       this software without specific prior written permission.
1961ae650dSJack F Vogel 
2061ae650dSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2161ae650dSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2261ae650dSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2361ae650dSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2461ae650dSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2561ae650dSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2661ae650dSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2761ae650dSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2861ae650dSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2961ae650dSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3061ae650dSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
3161ae650dSJack F Vogel 
3261ae650dSJack F Vogel ******************************************************************************/
3361ae650dSJack F Vogel 
3461ae650dSJack F Vogel /*
3561ae650dSJack F Vogel **	IXL driver TX/RX Routines:
3661ae650dSJack F Vogel **	    This was seperated to allow usage by
374294f337SSean Bruno ** 	    both the PF and VF drivers.
3861ae650dSJack F Vogel */
3961ae650dSJack F Vogel 
40b6c8f260SJack F Vogel #ifndef IXL_STANDALONE_BUILD
4161ae650dSJack F Vogel #include "opt_inet.h"
4261ae650dSJack F Vogel #include "opt_inet6.h"
43df1d7a71SJack F Vogel #include "opt_rss.h"
44b6c8f260SJack F Vogel #endif
45b6c8f260SJack F Vogel 
4661ae650dSJack F Vogel #include "ixl.h"
4761ae650dSJack F Vogel 
48dcd7b3b2SJack F Vogel #ifdef RSS
49dcd7b3b2SJack F Vogel #include <net/rss_config.h>
50dcd7b3b2SJack F Vogel #endif
51dcd7b3b2SJack F Vogel 
5261ae650dSJack F Vogel /* Local Prototypes */
539f99061eSKrzysztof Galazka static u8	ixl_rx_checksum(if_rxd_info_t ri, u32 status, u32 error, u8 ptype);
5461ae650dSJack F Vogel 
551031d839SEric Joyner static int	ixl_isc_txd_encap(void *arg, if_pkt_info_t pi);
561031d839SEric Joyner static void	ixl_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx);
571031d839SEric Joyner static int	ixl_isc_txd_credits_update_hwb(void *arg, uint16_t txqid, bool clear);
581031d839SEric Joyner static int	ixl_isc_txd_credits_update_dwb(void *arg, uint16_t txqid, bool clear);
5961ae650dSJack F Vogel 
601031d839SEric Joyner static void	ixl_isc_rxd_refill(void *arg, if_rxd_update_t iru);
611031d839SEric Joyner static void	ixl_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused,
621031d839SEric Joyner 				  qidx_t pidx);
631031d839SEric Joyner static int	ixl_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx,
641031d839SEric Joyner 				      qidx_t budget);
651031d839SEric Joyner static int	ixl_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri);
664294f337SSean Bruno 
671031d839SEric Joyner struct if_txrx ixl_txrx_hwb = {
681031d839SEric Joyner 	ixl_isc_txd_encap,
691031d839SEric Joyner 	ixl_isc_txd_flush,
701031d839SEric Joyner 	ixl_isc_txd_credits_update_hwb,
711031d839SEric Joyner 	ixl_isc_rxd_available,
721031d839SEric Joyner 	ixl_isc_rxd_pkt_get,
731031d839SEric Joyner 	ixl_isc_rxd_refill,
741031d839SEric Joyner 	ixl_isc_rxd_flush,
7577c1fcecSEric Joyner 	NULL
761031d839SEric Joyner };
771031d839SEric Joyner 
781031d839SEric Joyner struct if_txrx ixl_txrx_dwb = {
791031d839SEric Joyner 	ixl_isc_txd_encap,
801031d839SEric Joyner 	ixl_isc_txd_flush,
811031d839SEric Joyner 	ixl_isc_txd_credits_update_dwb,
821031d839SEric Joyner 	ixl_isc_rxd_available,
831031d839SEric Joyner 	ixl_isc_rxd_pkt_get,
841031d839SEric Joyner 	ixl_isc_rxd_refill,
851031d839SEric Joyner 	ixl_isc_rxd_flush,
8677c1fcecSEric Joyner 	NULL
871031d839SEric Joyner };
88bc8b78d3SLuigi Rizzo 
8961ae650dSJack F Vogel /*
904294f337SSean Bruno  * @key key is saved into this parameter
914294f337SSean Bruno  */
924294f337SSean Bruno void
ixl_get_default_rss_key(u32 * key)934294f337SSean Bruno ixl_get_default_rss_key(u32 *key)
944294f337SSean Bruno {
954294f337SSean Bruno 	MPASS(key != NULL);
964294f337SSean Bruno 
974294f337SSean Bruno 	u32 rss_seed[IXL_RSS_KEY_SIZE_REG] = {0x41b01687,
984294f337SSean Bruno 	    0x183cfd8c, 0xce880440, 0x580cbc3c,
994294f337SSean Bruno 	    0x35897377, 0x328b25e1, 0x4fa98922,
1004294f337SSean Bruno 	    0xb7d90c14, 0xd5bad70d, 0xcd15a2c1,
1014294f337SSean Bruno 	    0x0, 0x0, 0x0};
1024294f337SSean Bruno 
1034294f337SSean Bruno 	bcopy(rss_seed, key, IXL_RSS_KEY_SIZE);
1044294f337SSean Bruno }
1054294f337SSean Bruno 
106ceebc2f3SEric Joyner /**
107ceebc2f3SEric Joyner  * i40e_vc_stat_str - convert virtchnl status err code to a string
108ceebc2f3SEric Joyner  * @hw: pointer to the HW structure
109ceebc2f3SEric Joyner  * @stat_err: the status error code to convert
110ceebc2f3SEric Joyner  **/
111ceebc2f3SEric Joyner const char *
i40e_vc_stat_str(struct i40e_hw * hw,enum virtchnl_status_code stat_err)112ceebc2f3SEric Joyner i40e_vc_stat_str(struct i40e_hw *hw, enum virtchnl_status_code stat_err)
113ceebc2f3SEric Joyner {
114ceebc2f3SEric Joyner 	switch (stat_err) {
115ceebc2f3SEric Joyner 	case VIRTCHNL_STATUS_SUCCESS:
116ceebc2f3SEric Joyner 		return "OK";
117ceebc2f3SEric Joyner 	case VIRTCHNL_ERR_PARAM:
118ceebc2f3SEric Joyner 		return "VIRTCHNL_ERR_PARAM";
119ceebc2f3SEric Joyner 	case VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH:
120ceebc2f3SEric Joyner 		return "VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH";
121ceebc2f3SEric Joyner 	case VIRTCHNL_STATUS_ERR_CQP_COMPL_ERROR:
122ceebc2f3SEric Joyner 		return "VIRTCHNL_STATUS_ERR_CQP_COMPL_ERROR";
123ceebc2f3SEric Joyner 	case VIRTCHNL_STATUS_ERR_INVALID_VF_ID:
124ceebc2f3SEric Joyner 		return "VIRTCHNL_STATUS_ERR_INVALID_VF_ID";
125ceebc2f3SEric Joyner 	case VIRTCHNL_STATUS_NOT_SUPPORTED:
126ceebc2f3SEric Joyner 		return "VIRTCHNL_STATUS_NOT_SUPPORTED";
127ceebc2f3SEric Joyner 	}
128ceebc2f3SEric Joyner 
129ceebc2f3SEric Joyner 	snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err);
130ceebc2f3SEric Joyner 	return hw->err_str;
131ceebc2f3SEric Joyner }
132ceebc2f3SEric Joyner 
13377c1fcecSEric Joyner void
ixl_debug_core(device_t dev,u32 enabled_mask,u32 mask,char * fmt,...)13477c1fcecSEric Joyner ixl_debug_core(device_t dev, u32 enabled_mask, u32 mask, char *fmt, ...)
13577c1fcecSEric Joyner {
13677c1fcecSEric Joyner 	va_list args;
13777c1fcecSEric Joyner 
13877c1fcecSEric Joyner 	if (!(mask & enabled_mask))
13977c1fcecSEric Joyner 		return;
14077c1fcecSEric Joyner 
14177c1fcecSEric Joyner 	/* Re-implement device_printf() */
14277c1fcecSEric Joyner 	device_print_prettyname(dev);
14377c1fcecSEric Joyner 	va_start(args, fmt);
14477c1fcecSEric Joyner 	vprintf(fmt, args);
14577c1fcecSEric Joyner 	va_end(args);
14677c1fcecSEric Joyner }
14777c1fcecSEric Joyner 
1481031d839SEric Joyner static bool
ixl_is_tx_desc_done(struct tx_ring * txr,int idx)1491031d839SEric Joyner ixl_is_tx_desc_done(struct tx_ring *txr, int idx)
150ceebc2f3SEric Joyner {
1511031d839SEric Joyner 	return (((txr->tx_base[idx].cmd_type_offset_bsz >> I40E_TXD_QW1_DTYPE_SHIFT)
1521031d839SEric Joyner 	    & I40E_TXD_QW1_DTYPE_MASK) == I40E_TX_DESC_DTYPE_DESC_DONE);
153ceebc2f3SEric Joyner }
154ceebc2f3SEric Joyner 
1551031d839SEric Joyner static int
ixl_tso_detect_sparse(bus_dma_segment_t * segs,int nsegs,if_pkt_info_t pi)1561031d839SEric Joyner ixl_tso_detect_sparse(bus_dma_segment_t *segs, int nsegs, if_pkt_info_t pi)
157ceebc2f3SEric Joyner {
1581031d839SEric Joyner 	int	count, curseg, i, hlen, segsz, seglen, tsolen;
159ceebc2f3SEric Joyner 
1601031d839SEric Joyner 	if (nsegs <= IXL_MAX_TX_SEGS-2)
1611031d839SEric Joyner 		return (0);
1621031d839SEric Joyner 	segsz = pi->ipi_tso_segsz;
1631031d839SEric Joyner 	curseg = count = 0;
1641031d839SEric Joyner 
1651031d839SEric Joyner 	hlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen;
1661031d839SEric Joyner 	tsolen = pi->ipi_len - hlen;
1671031d839SEric Joyner 
1681031d839SEric Joyner 	i = 0;
1691031d839SEric Joyner 	curseg = segs[0].ds_len;
1701031d839SEric Joyner 	while (hlen > 0) {
1711031d839SEric Joyner 		count++;
1721031d839SEric Joyner 		if (count > IXL_MAX_TX_SEGS - 2)
1731031d839SEric Joyner 			return (1);
1741031d839SEric Joyner 		if (curseg == 0) {
1751031d839SEric Joyner 			i++;
1761031d839SEric Joyner 			if (__predict_false(i == nsegs))
1771031d839SEric Joyner 				return (1);
1781031d839SEric Joyner 
1791031d839SEric Joyner 			curseg = segs[i].ds_len;
180ceebc2f3SEric Joyner 		}
1811031d839SEric Joyner 		seglen = min(curseg, hlen);
1821031d839SEric Joyner 		curseg -= seglen;
1831031d839SEric Joyner 		hlen -= seglen;
1841031d839SEric Joyner 		// printf("H:seglen = %d, count=%d\n", seglen, count);
1851031d839SEric Joyner 	}
1861031d839SEric Joyner 	while (tsolen > 0) {
1871031d839SEric Joyner 		segsz = pi->ipi_tso_segsz;
1881031d839SEric Joyner 		while (segsz > 0 && tsolen != 0) {
1891031d839SEric Joyner 			count++;
1901031d839SEric Joyner 			if (count > IXL_MAX_TX_SEGS - 2) {
1911031d839SEric Joyner 				// printf("bad: count = %d\n", count);
1921031d839SEric Joyner 				return (1);
1931031d839SEric Joyner 			}
1941031d839SEric Joyner 			if (curseg == 0) {
1951031d839SEric Joyner 				i++;
1961031d839SEric Joyner 				if (__predict_false(i == nsegs)) {
1971031d839SEric Joyner 					// printf("bad: tsolen = %d", tsolen);
1981031d839SEric Joyner 					return (1);
1991031d839SEric Joyner 				}
2001031d839SEric Joyner 				curseg = segs[i].ds_len;
2011031d839SEric Joyner 			}
2021031d839SEric Joyner 			seglen = min(curseg, segsz);
2031031d839SEric Joyner 			segsz -= seglen;
2041031d839SEric Joyner 			curseg -= seglen;
2051031d839SEric Joyner 			tsolen -= seglen;
2061031d839SEric Joyner 			// printf("D:seglen = %d, count=%d\n", seglen, count);
2071031d839SEric Joyner 		}
2081031d839SEric Joyner 		count = 0;
2091031d839SEric Joyner 	}
21061ae650dSJack F Vogel 
21161ae650dSJack F Vogel  	return (0);
21261ae650dSJack F Vogel }
21361ae650dSJack F Vogel 
2141031d839SEric Joyner /*********************************************************************
2151031d839SEric Joyner  *
2161031d839SEric Joyner  *  Setup descriptor for hw offloads
2171031d839SEric Joyner  *
2181031d839SEric Joyner  **********************************************************************/
2191031d839SEric Joyner 
2201031d839SEric Joyner static void
ixl_tx_setup_offload(struct ixl_tx_queue * que,if_pkt_info_t pi,u32 * cmd,u32 * off)2211031d839SEric Joyner ixl_tx_setup_offload(struct ixl_tx_queue *que,
2221031d839SEric Joyner     if_pkt_info_t pi, u32 *cmd, u32 *off)
22361ae650dSJack F Vogel {
2241031d839SEric Joyner 	switch (pi->ipi_etype) {
2251031d839SEric Joyner #ifdef INET
2261031d839SEric Joyner 		case ETHERTYPE_IP:
22737761e2eSEric Joyner 			if (pi->ipi_csum_flags & IXL_CSUM_IPV4)
2281031d839SEric Joyner 				*cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
22961ae650dSJack F Vogel 			else
2301031d839SEric Joyner 				*cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
23161ae650dSJack F Vogel 			break;
2321031d839SEric Joyner #endif
2331031d839SEric Joyner #ifdef INET6
2341031d839SEric Joyner 		case ETHERTYPE_IPV6:
2351031d839SEric Joyner 			*cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
2361031d839SEric Joyner 			break;
2371031d839SEric Joyner #endif
2381031d839SEric Joyner 		default:
23961ae650dSJack F Vogel 			break;
24061ae650dSJack F Vogel 	}
24161ae650dSJack F Vogel 
2421031d839SEric Joyner 	*off |= (pi->ipi_ehdrlen >> 1) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
2431031d839SEric Joyner 	*off |= (pi->ipi_ip_hlen >> 2) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
24461ae650dSJack F Vogel 
2451031d839SEric Joyner 	switch (pi->ipi_ipproto) {
2461031d839SEric Joyner 		case IPPROTO_TCP:
2471031d839SEric Joyner 			if (pi->ipi_csum_flags & IXL_CSUM_TCP) {
2481031d839SEric Joyner 				*cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
2491031d839SEric Joyner 				*off |= (pi->ipi_tcp_hlen >> 2) <<
2501031d839SEric Joyner 				    I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
25177c1fcecSEric Joyner 				/* Check for NO_HEAD MDD event */
25277c1fcecSEric Joyner 				MPASS(pi->ipi_tcp_hlen != 0);
25361ae650dSJack F Vogel 			}
254cb6b8299SEric Joyner 			break;
2551031d839SEric Joyner 		case IPPROTO_UDP:
2561031d839SEric Joyner 			if (pi->ipi_csum_flags & IXL_CSUM_UDP) {
2571031d839SEric Joyner 				*cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
2581031d839SEric Joyner 				*off |= (sizeof(struct udphdr) >> 2) <<
2591031d839SEric Joyner 				    I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
2601031d839SEric Joyner 			}
2611031d839SEric Joyner 			break;
2621031d839SEric Joyner 		case IPPROTO_SCTP:
2631031d839SEric Joyner 			if (pi->ipi_csum_flags & IXL_CSUM_SCTP) {
2641031d839SEric Joyner 				*cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
2651031d839SEric Joyner 				*off |= (sizeof(struct sctphdr) >> 2) <<
2661031d839SEric Joyner 				    I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
2671031d839SEric Joyner 			}
2681031d839SEric Joyner 			/* Fall Thru */
2691031d839SEric Joyner 		default:
2701031d839SEric Joyner 			break;
271cb6b8299SEric Joyner 	}
272cb6b8299SEric Joyner }
273cb6b8299SEric Joyner 
2741031d839SEric Joyner /**********************************************************************
2751031d839SEric Joyner  *
2761031d839SEric Joyner  *  Setup context for hardware segmentation offload (TSO)
2771031d839SEric Joyner  *
2781031d839SEric Joyner  **********************************************************************/
2791031d839SEric Joyner static int
ixl_tso_setup(struct tx_ring * txr,if_pkt_info_t pi)2801031d839SEric Joyner ixl_tso_setup(struct tx_ring *txr, if_pkt_info_t pi)
2811031d839SEric Joyner {
2821031d839SEric Joyner 	if_softc_ctx_t			scctx;
2831031d839SEric Joyner 	struct i40e_tx_context_desc	*TXD;
2841031d839SEric Joyner 	u32				cmd, mss, type, tsolen;
28577c1fcecSEric Joyner 	int				idx, total_hdr_len;
2861031d839SEric Joyner 	u64				type_cmd_tso_mss;
28761ae650dSJack F Vogel 
2881031d839SEric Joyner 	idx = pi->ipi_pidx;
2891031d839SEric Joyner 	TXD = (struct i40e_tx_context_desc *) &txr->tx_base[idx];
29077c1fcecSEric Joyner 	total_hdr_len = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen;
29177c1fcecSEric Joyner 	tsolen = pi->ipi_len - total_hdr_len;
2921031d839SEric Joyner 	scctx = txr->que->vsi->shared;
2931031d839SEric Joyner 
2941031d839SEric Joyner 	type = I40E_TX_DESC_DTYPE_CONTEXT;
2951031d839SEric Joyner 	cmd = I40E_TX_CTX_DESC_TSO;
29677c1fcecSEric Joyner 	/*
29777c1fcecSEric Joyner 	 * TSO MSS must not be less than 64; this prevents a
29877c1fcecSEric Joyner 	 * BAD_LSO_MSS MDD event when the MSS is too small.
29977c1fcecSEric Joyner 	 */
3001031d839SEric Joyner 	if (pi->ipi_tso_segsz < IXL_MIN_TSO_MSS) {
3011031d839SEric Joyner 		txr->mss_too_small++;
3021031d839SEric Joyner 		pi->ipi_tso_segsz = IXL_MIN_TSO_MSS;
3031031d839SEric Joyner 	}
3041031d839SEric Joyner 	mss = pi->ipi_tso_segsz;
3051031d839SEric Joyner 
30677c1fcecSEric Joyner 	/* Check for BAD_LS0_MSS MDD event (mss too large) */
30777c1fcecSEric Joyner 	MPASS(mss <= IXL_MAX_TSO_MSS);
30877c1fcecSEric Joyner 	/* Check for NO_HEAD MDD event (header lengths are 0) */
30977c1fcecSEric Joyner 	MPASS(pi->ipi_ehdrlen != 0);
31077c1fcecSEric Joyner 	MPASS(pi->ipi_ip_hlen != 0);
31177c1fcecSEric Joyner 	/* Partial check for BAD_LSO_LEN MDD event */
31277c1fcecSEric Joyner 	MPASS(tsolen != 0);
31377c1fcecSEric Joyner 	/* Partial check for WRONG_SIZE MDD event (during TSO) */
31477c1fcecSEric Joyner 	MPASS(total_hdr_len + mss <= IXL_MAX_FRAME);
31577c1fcecSEric Joyner 
3161031d839SEric Joyner 	type_cmd_tso_mss = ((u64)type << I40E_TXD_CTX_QW1_DTYPE_SHIFT) |
3171031d839SEric Joyner 	    ((u64)cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
3181031d839SEric Joyner 	    ((u64)tsolen << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
3191031d839SEric Joyner 	    ((u64)mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
3201031d839SEric Joyner 	TXD->type_cmd_tso_mss = htole64(type_cmd_tso_mss);
3211031d839SEric Joyner 
3221031d839SEric Joyner 	TXD->tunneling_params = htole32(0);
3231031d839SEric Joyner 	txr->que->tso++;
3241031d839SEric Joyner 
3251031d839SEric Joyner 	return ((idx + 1) & (scctx->isc_ntxd[0]-1));
3261031d839SEric Joyner }
32761ae650dSJack F Vogel 
32861ae650dSJack F Vogel /*********************************************************************
32961ae650dSJack F Vogel   *
33061ae650dSJack F Vogel  *  This routine maps the mbufs to tx descriptors, allowing the
33161ae650dSJack F Vogel  *  TX engine to transmit the packets.
33261ae650dSJack F Vogel  *  	- return 0 on success, positive on failure
33361ae650dSJack F Vogel   *
33461ae650dSJack F Vogel   **********************************************************************/
33561ae650dSJack F Vogel #define IXL_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
33661ae650dSJack F Vogel 
33761ae650dSJack F Vogel static int
ixl_isc_txd_encap(void * arg,if_pkt_info_t pi)3381031d839SEric Joyner ixl_isc_txd_encap(void *arg, if_pkt_info_t pi)
33961ae650dSJack F Vogel {
3401031d839SEric Joyner 	struct ixl_vsi		*vsi = arg;
3411031d839SEric Joyner 	if_softc_ctx_t		scctx = vsi->shared;
3421031d839SEric Joyner 	struct ixl_tx_queue	*que = &vsi->tx_queues[pi->ipi_qsidx];
34361ae650dSJack F Vogel  	struct tx_ring		*txr = &que->txr;
3441031d839SEric Joyner 	int			nsegs = pi->ipi_nsegs;
3451031d839SEric Joyner 	bus_dma_segment_t *segs = pi->ipi_segs;
34661ae650dSJack F Vogel 	struct i40e_tx_desc	*txd = NULL;
3471031d839SEric Joyner 	int             	i, j, mask, pidx_last;
3481031d839SEric Joyner 	u32			cmd, off, tx_intr;
3491031d839SEric Joyner 
35061ae650dSJack F Vogel 	cmd = off = 0;
3511031d839SEric Joyner 	i = pi->ipi_pidx;
35261ae650dSJack F Vogel 
3531031d839SEric Joyner 	tx_intr = (pi->ipi_flags & IPI_TX_INTR);
35461ae650dSJack F Vogel 
35561ae650dSJack F Vogel 	/* Set up the TSO/CSUM offload */
3561031d839SEric Joyner 	if (pi->ipi_csum_flags & CSUM_OFFLOAD) {
3571031d839SEric Joyner 		/* Set up the TSO context descriptor if required */
3581031d839SEric Joyner 		if (pi->ipi_csum_flags & CSUM_TSO) {
35977c1fcecSEric Joyner 			/* Prevent MAX_BUFF MDD event (for TSO) */
3601031d839SEric Joyner 			if (ixl_tso_detect_sparse(segs, nsegs, pi))
3611031d839SEric Joyner 				return (EFBIG);
3621031d839SEric Joyner 			i = ixl_tso_setup(txr, pi);
36361ae650dSJack F Vogel 		}
3641031d839SEric Joyner 		ixl_tx_setup_offload(que, pi, &cmd, &off);
3651031d839SEric Joyner 	}
3661031d839SEric Joyner 	if (pi->ipi_mflags & M_VLANTAG)
3671031d839SEric Joyner 		cmd |= I40E_TX_DESC_CMD_IL2TAG1;
36861ae650dSJack F Vogel 
36961ae650dSJack F Vogel 	cmd |= I40E_TX_DESC_CMD_ICRC;
3701031d839SEric Joyner 	mask = scctx->isc_ntxd[0] - 1;
37177c1fcecSEric Joyner 	/* Check for WRONG_SIZE MDD event */
37277c1fcecSEric Joyner 	MPASS(pi->ipi_len >= IXL_MIN_FRAME);
37377c1fcecSEric Joyner #ifdef INVARIANTS
37477c1fcecSEric Joyner 	if (!(pi->ipi_csum_flags & CSUM_TSO))
37577c1fcecSEric Joyner 		MPASS(pi->ipi_len <= IXL_MAX_FRAME);
37677c1fcecSEric Joyner #endif
37761ae650dSJack F Vogel 	for (j = 0; j < nsegs; j++) {
37861ae650dSJack F Vogel 		bus_size_t seglen;
37961ae650dSJack F Vogel 
3801031d839SEric Joyner 		txd = &txr->tx_base[i];
38161ae650dSJack F Vogel 		seglen = segs[j].ds_len;
38261ae650dSJack F Vogel 
38377c1fcecSEric Joyner 		/* Check for ZERO_BSIZE MDD event */
38477c1fcecSEric Joyner 		MPASS(seglen != 0);
38577c1fcecSEric Joyner 
38661ae650dSJack F Vogel 		txd->buffer_addr = htole64(segs[j].ds_addr);
38761ae650dSJack F Vogel 		txd->cmd_type_offset_bsz =
38861ae650dSJack F Vogel 		    htole64(I40E_TX_DESC_DTYPE_DATA
38961ae650dSJack F Vogel 		    | ((u64)cmd  << I40E_TXD_QW1_CMD_SHIFT)
39061ae650dSJack F Vogel 		    | ((u64)off << I40E_TXD_QW1_OFFSET_SHIFT)
39161ae650dSJack F Vogel 		    | ((u64)seglen  << I40E_TXD_QW1_TX_BUF_SZ_SHIFT)
3921031d839SEric Joyner 	            | ((u64)htole16(pi->ipi_vtag) << I40E_TXD_QW1_L2TAG1_SHIFT));
39361ae650dSJack F Vogel 
3941031d839SEric Joyner 		txr->tx_bytes += seglen;
3951031d839SEric Joyner 		pidx_last = i;
3961031d839SEric Joyner 		i = (i+1) & mask;
39761ae650dSJack F Vogel 	}
39861ae650dSJack F Vogel 	/* Set the last descriptor for report */
39961ae650dSJack F Vogel 	txd->cmd_type_offset_bsz |=
40061ae650dSJack F Vogel 	    htole64(((u64)IXL_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT));
4011031d839SEric Joyner 	/* Add to report status array (if using TX interrupts) */
4021031d839SEric Joyner 	if (!vsi->enable_head_writeback && tx_intr) {
4031031d839SEric Joyner 		txr->tx_rsq[txr->tx_rs_pidx] = pidx_last;
4041031d839SEric Joyner 		txr->tx_rs_pidx = (txr->tx_rs_pidx+1) & mask;
4051031d839SEric Joyner 		MPASS(txr->tx_rs_pidx != txr->tx_rs_cidx);
4061031d839SEric Joyner  	}
4071031d839SEric Joyner 	pi->ipi_new_pidx = i;
40861ae650dSJack F Vogel 
4091031d839SEric Joyner 	++txr->tx_packets;
4101031d839SEric Joyner 	return (0);
4111031d839SEric Joyner }
41261ae650dSJack F Vogel 
4131031d839SEric Joyner static void
ixl_isc_txd_flush(void * arg,uint16_t txqid,qidx_t pidx)4141031d839SEric Joyner ixl_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx)
4151031d839SEric Joyner {
4161031d839SEric Joyner 	struct ixl_vsi *vsi = arg;
4171031d839SEric Joyner 	struct tx_ring *txr = &vsi->tx_queues[txqid].txr;
41861ae650dSJack F Vogel 
41961ae650dSJack F Vogel  	/*
42061ae650dSJack F Vogel 	 * Advance the Transmit Descriptor Tail (Tdt), this tells the
42161ae650dSJack F Vogel 	 * hardware that this frame is available to transmit.
42261ae650dSJack F Vogel  	 */
42377c1fcecSEric Joyner 	/* Check for ENDLESS_TX MDD event */
42477c1fcecSEric Joyner 	MPASS(pidx < vsi->shared->isc_ntxd[0]);
4251031d839SEric Joyner 	wr32(vsi->hw, txr->tail, pidx);
42661ae650dSJack F Vogel }
42761ae650dSJack F Vogel 
42861ae650dSJack F Vogel 
42961ae650dSJack F Vogel /*********************************************************************
43061ae650dSJack F Vogel  *
4311031d839SEric Joyner  *  (Re)Initialize a queue transmit ring by clearing its memory.
43261ae650dSJack F Vogel  *
43361ae650dSJack F Vogel  **********************************************************************/
43461ae650dSJack F Vogel void
ixl_init_tx_ring(struct ixl_vsi * vsi,struct ixl_tx_queue * que)4351031d839SEric Joyner ixl_init_tx_ring(struct ixl_vsi *vsi, struct ixl_tx_queue *que)
43661ae650dSJack F Vogel {
43761ae650dSJack F Vogel 	struct tx_ring *txr = &que->txr;
43861ae650dSJack F Vogel 
43961ae650dSJack F Vogel 	/* Clear the old ring contents */
4401031d839SEric Joyner 	bzero((void *)txr->tx_base,
4411031d839SEric Joyner 	      (sizeof(struct i40e_tx_desc)) *
4421031d839SEric Joyner 	      (vsi->shared->isc_ntxd[0] + (vsi->enable_head_writeback ? 1 : 0)));
44356c2c47bSJack F Vogel 
4441031d839SEric Joyner 	wr32(vsi->hw, txr->tail, 0);
44561ae650dSJack F Vogel }
44661ae650dSJack F Vogel 
44761ae650dSJack F Vogel /*
448ceebc2f3SEric Joyner  * ixl_get_tx_head - Retrieve the value from the
449ceebc2f3SEric Joyner  *    location the HW records its HEAD index
45061ae650dSJack F Vogel  */
45161ae650dSJack F Vogel static inline u32
ixl_get_tx_head(struct ixl_tx_queue * que)4521031d839SEric Joyner ixl_get_tx_head(struct ixl_tx_queue *que)
45361ae650dSJack F Vogel {
4541031d839SEric Joyner 	if_softc_ctx_t          scctx = que->vsi->shared;
45561ae650dSJack F Vogel 	struct tx_ring  *txr = &que->txr;
4561031d839SEric Joyner 	void *head = &txr->tx_base[scctx->isc_ntxd[0]];
4571031d839SEric Joyner 
45861ae650dSJack F Vogel 	return LE32_TO_CPU(*(volatile __le32 *)head);
45961ae650dSJack F Vogel }
46061ae650dSJack F Vogel 
4611031d839SEric Joyner static int
ixl_isc_txd_credits_update_hwb(void * arg,uint16_t qid,bool clear)4621031d839SEric Joyner ixl_isc_txd_credits_update_hwb(void *arg, uint16_t qid, bool clear)
46361ae650dSJack F Vogel {
4641031d839SEric Joyner 	struct ixl_vsi          *vsi = arg;
4651031d839SEric Joyner 	if_softc_ctx_t          scctx = vsi->shared;
4661031d839SEric Joyner 	struct ixl_tx_queue     *que = &vsi->tx_queues[qid];
46761ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
4681031d839SEric Joyner 	int			 head, credits;
469ceebc2f3SEric Joyner 
47061ae650dSJack F Vogel 	/* Get the Head WB value */
47161ae650dSJack F Vogel 	head = ixl_get_tx_head(que);
47261ae650dSJack F Vogel 
4731031d839SEric Joyner 	credits = head - txr->tx_cidx_processed;
4741031d839SEric Joyner 	if (credits < 0)
4751031d839SEric Joyner 		credits += scctx->isc_ntxd[0];
4761031d839SEric Joyner 	if (clear)
4771031d839SEric Joyner 		txr->tx_cidx_processed = head;
47861ae650dSJack F Vogel 
4791031d839SEric Joyner 	return (credits);
48061ae650dSJack F Vogel }
48161ae650dSJack F Vogel 
4821031d839SEric Joyner static int
ixl_isc_txd_credits_update_dwb(void * arg,uint16_t txqid,bool clear)4831031d839SEric Joyner ixl_isc_txd_credits_update_dwb(void *arg, uint16_t txqid, bool clear)
484ceebc2f3SEric Joyner {
4851031d839SEric Joyner 	struct ixl_vsi *vsi = arg;
4861031d839SEric Joyner 	struct ixl_tx_queue *tx_que = &vsi->tx_queues[txqid];
4871031d839SEric Joyner 	if_softc_ctx_t scctx = vsi->shared;
4881031d839SEric Joyner 	struct tx_ring *txr = &tx_que->txr;
489ceebc2f3SEric Joyner 
4901031d839SEric Joyner 	qidx_t processed = 0;
4911031d839SEric Joyner 	qidx_t cur, prev, ntxd, rs_cidx;
4921031d839SEric Joyner 	int32_t delta;
4931031d839SEric Joyner 	bool is_done;
494ceebc2f3SEric Joyner 
4951031d839SEric Joyner 	rs_cidx = txr->tx_rs_cidx;
4961031d839SEric Joyner #if 0
4971031d839SEric Joyner 	device_printf(iflib_get_dev(vsi->ctx), "%s: (q%d) rs_cidx %d, txr->tx_rs_pidx %d\n", __func__,
4981031d839SEric Joyner 	    txr->me, rs_cidx, txr->tx_rs_pidx);
4991031d839SEric Joyner #endif
5001031d839SEric Joyner 	if (rs_cidx == txr->tx_rs_pidx)
5011031d839SEric Joyner 		return (0);
5021031d839SEric Joyner 	cur = txr->tx_rsq[rs_cidx];
5031031d839SEric Joyner 	MPASS(cur != QIDX_INVALID);
5041031d839SEric Joyner 	is_done = ixl_is_tx_desc_done(txr, cur);
505ceebc2f3SEric Joyner 
50677c1fcecSEric Joyner 	if (!is_done)
5071031d839SEric Joyner 		return (0);
508ceebc2f3SEric Joyner 
50977c1fcecSEric Joyner 	/* If clear is false just let caller know that there
51077c1fcecSEric Joyner 	 * are descriptors to reclaim */
51177c1fcecSEric Joyner 	if (!clear)
51277c1fcecSEric Joyner 		return (1);
51377c1fcecSEric Joyner 
5141031d839SEric Joyner 	prev = txr->tx_cidx_processed;
5151031d839SEric Joyner 	ntxd = scctx->isc_ntxd[0];
516ceebc2f3SEric Joyner 	do {
517088a0b27SEric Joyner 		MPASS(prev != cur);
5181031d839SEric Joyner 		delta = (int32_t)cur - (int32_t)prev;
5191031d839SEric Joyner 		if (delta < 0)
5201031d839SEric Joyner 			delta += ntxd;
521088a0b27SEric Joyner 		MPASS(delta > 0);
5221031d839SEric Joyner #if 0
5231031d839SEric Joyner 		device_printf(iflib_get_dev(vsi->ctx),
5241031d839SEric Joyner 			      "%s: (q%d) cidx_processed=%u cur=%u clear=%d delta=%d\n",
5251031d839SEric Joyner 			      __func__, txr->me, prev, cur, clear, delta);
5261031d839SEric Joyner #endif
5271031d839SEric Joyner 		processed += delta;
5281031d839SEric Joyner 		prev = cur;
5291031d839SEric Joyner 		rs_cidx = (rs_cidx + 1) & (ntxd-1);
5301031d839SEric Joyner 		if (rs_cidx == txr->tx_rs_pidx)
531ceebc2f3SEric Joyner 			break;
5321031d839SEric Joyner 		cur = txr->tx_rsq[rs_cidx];
5331031d839SEric Joyner 		MPASS(cur != QIDX_INVALID);
5341031d839SEric Joyner 		is_done = ixl_is_tx_desc_done(txr, cur);
5351031d839SEric Joyner 	} while (is_done);
536ceebc2f3SEric Joyner 
5371031d839SEric Joyner 	txr->tx_rs_cidx = rs_cidx;
5381031d839SEric Joyner 	txr->tx_cidx_processed = prev;
539ceebc2f3SEric Joyner 
5401031d839SEric Joyner #if 0
5411031d839SEric Joyner 	device_printf(iflib_get_dev(vsi->ctx), "%s: (q%d) processed %d\n", __func__, txr->me, processed);
5421031d839SEric Joyner #endif
5431031d839SEric Joyner 	return (processed);
544ceebc2f3SEric Joyner }
545ceebc2f3SEric Joyner 
54661ae650dSJack F Vogel static void
ixl_isc_rxd_refill(void * arg,if_rxd_update_t iru)5471031d839SEric Joyner ixl_isc_rxd_refill(void *arg, if_rxd_update_t iru)
54861ae650dSJack F Vogel {
5491031d839SEric Joyner 	struct ixl_vsi *vsi = arg;
5501031d839SEric Joyner 	if_softc_ctx_t scctx = vsi->shared;
5511031d839SEric Joyner 	struct rx_ring *rxr = &((vsi->rx_queues[iru->iru_qsidx]).rxr);
5521031d839SEric Joyner 	uint64_t *paddrs;
5531031d839SEric Joyner 	uint32_t next_pidx, pidx;
5541031d839SEric Joyner 	uint16_t count;
5551031d839SEric Joyner 	int i;
55661ae650dSJack F Vogel 
5571031d839SEric Joyner 	paddrs = iru->iru_paddrs;
5581031d839SEric Joyner 	pidx = iru->iru_pidx;
5591031d839SEric Joyner 	count = iru->iru_count;
56061ae650dSJack F Vogel 
5611031d839SEric Joyner 	for (i = 0, next_pidx = pidx; i < count; i++) {
5621031d839SEric Joyner 		rxr->rx_base[next_pidx].read.pkt_addr = htole64(paddrs[i]);
5631031d839SEric Joyner 		if (++next_pidx == scctx->isc_nrxd[0])
5641031d839SEric Joyner 			next_pidx = 0;
56561ae650dSJack F Vogel  	}
56661ae650dSJack F Vogel }
56761ae650dSJack F Vogel 
5681031d839SEric Joyner static void
ixl_isc_rxd_flush(void * arg,uint16_t rxqid,uint8_t flid __unused,qidx_t pidx)5691031d839SEric Joyner ixl_isc_rxd_flush(void * arg, uint16_t rxqid, uint8_t flid __unused, qidx_t pidx)
57061ae650dSJack F Vogel {
5711031d839SEric Joyner 	struct ixl_vsi		*vsi = arg;
5721031d839SEric Joyner 	struct rx_ring		*rxr = &vsi->rx_queues[rxqid].rxr;
57361ae650dSJack F Vogel 
5741031d839SEric Joyner 	wr32(vsi->hw, rxr->tail, pidx);
57561ae650dSJack F Vogel }
57661ae650dSJack F Vogel 
5771031d839SEric Joyner static int
ixl_isc_rxd_available(void * arg,uint16_t rxqid,qidx_t idx,qidx_t budget)5781031d839SEric Joyner ixl_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget)
57961ae650dSJack F Vogel {
5801031d839SEric Joyner 	struct ixl_vsi *vsi = arg;
5811031d839SEric Joyner 	struct rx_ring *rxr = &vsi->rx_queues[rxqid].rxr;
5821031d839SEric Joyner 	union i40e_rx_desc *rxd;
5831031d839SEric Joyner 	u64 qword;
5841031d839SEric Joyner 	uint32_t status;
5851031d839SEric Joyner 	int cnt, i, nrxd;
58661ae650dSJack F Vogel 
5871031d839SEric Joyner 	nrxd = vsi->shared->isc_nrxd[0];
5881031d839SEric Joyner 
5891031d839SEric Joyner 	for (cnt = 0, i = idx; cnt < nrxd - 1 && cnt <= budget;) {
5901031d839SEric Joyner 		rxd = &rxr->rx_base[i];
5911031d839SEric Joyner 		qword = le64toh(rxd->wb.qword1.status_error_len);
5921031d839SEric Joyner 		status = (qword & I40E_RXD_QW1_STATUS_MASK)
5931031d839SEric Joyner 			>> I40E_RXD_QW1_STATUS_SHIFT;
59461ae650dSJack F Vogel 
5951031d839SEric Joyner 		if ((status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) == 0)
5961031d839SEric Joyner 			break;
5971031d839SEric Joyner 		if (++i == nrxd)
5981031d839SEric Joyner 			i = 0;
5991031d839SEric Joyner 		if (status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT))
6001031d839SEric Joyner 			cnt++;
60161ae650dSJack F Vogel 	}
60261ae650dSJack F Vogel 
6031031d839SEric Joyner 	return (cnt);
60461ae650dSJack F Vogel }
60561ae650dSJack F Vogel 
6066b30e6aeSJack F Vogel /*
607b6c8f260SJack F Vogel ** i40e_ptype_to_hash: parse the packet type
6086b30e6aeSJack F Vogel ** to determine the appropriate hash.
6096b30e6aeSJack F Vogel */
6106b30e6aeSJack F Vogel static inline int
ixl_ptype_to_hash(u8 ptype)6116b30e6aeSJack F Vogel ixl_ptype_to_hash(u8 ptype)
6126b30e6aeSJack F Vogel {
6136b30e6aeSJack F Vogel         struct i40e_rx_ptype_decoded	decoded;
6146b30e6aeSJack F Vogel 
615dcd7b3b2SJack F Vogel 	decoded = decode_rx_desc_ptype(ptype);
6166b30e6aeSJack F Vogel 
6176b30e6aeSJack F Vogel 	if (!decoded.known)
6181031d839SEric Joyner 		return M_HASHTYPE_OPAQUE;
6196b30e6aeSJack F Vogel 
6206b30e6aeSJack F Vogel 	if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_L2)
6211031d839SEric Joyner 		return M_HASHTYPE_OPAQUE;
6226b30e6aeSJack F Vogel 
6236b30e6aeSJack F Vogel 	/* Note: anything that gets to this point is IP */
6246b30e6aeSJack F Vogel         if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) {
6256b30e6aeSJack F Vogel 		switch (decoded.inner_prot) {
6266b30e6aeSJack F Vogel 		case I40E_RX_PTYPE_INNER_PROT_TCP:
6276b30e6aeSJack F Vogel 			return M_HASHTYPE_RSS_TCP_IPV6;
6286b30e6aeSJack F Vogel 		case I40E_RX_PTYPE_INNER_PROT_UDP:
6296b30e6aeSJack F Vogel 			return M_HASHTYPE_RSS_UDP_IPV6;
6306b30e6aeSJack F Vogel 		default:
6316b30e6aeSJack F Vogel 			return M_HASHTYPE_RSS_IPV6;
6326b30e6aeSJack F Vogel 		}
6336b30e6aeSJack F Vogel 	}
6346b30e6aeSJack F Vogel         if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4) {
6356b30e6aeSJack F Vogel 		switch (decoded.inner_prot) {
6366b30e6aeSJack F Vogel 		case I40E_RX_PTYPE_INNER_PROT_TCP:
6376b30e6aeSJack F Vogel 			return M_HASHTYPE_RSS_TCP_IPV4;
6386b30e6aeSJack F Vogel 		case I40E_RX_PTYPE_INNER_PROT_UDP:
6396b30e6aeSJack F Vogel 			return M_HASHTYPE_RSS_UDP_IPV4;
6406b30e6aeSJack F Vogel 		default:
6416b30e6aeSJack F Vogel 			return M_HASHTYPE_RSS_IPV4;
6426b30e6aeSJack F Vogel 		}
6436b30e6aeSJack F Vogel 	}
6446b30e6aeSJack F Vogel 	/* We should never get here!! */
6451031d839SEric Joyner 	return M_HASHTYPE_OPAQUE;
6466b30e6aeSJack F Vogel }
64761ae650dSJack F Vogel 
64861ae650dSJack F Vogel /*********************************************************************
64961ae650dSJack F Vogel  *
6501031d839SEric Joyner  *  This routine executes in ithread context. It sends data which has been
65161ae650dSJack F Vogel  *  dma'ed into host memory to upper layer.
65261ae650dSJack F Vogel  *
6531031d839SEric Joyner  *  Returns 0 upon success, errno on failure
65461ae650dSJack F Vogel  *
65561ae650dSJack F Vogel  *********************************************************************/
6561031d839SEric Joyner static int
ixl_isc_rxd_pkt_get(void * arg,if_rxd_info_t ri)6571031d839SEric Joyner ixl_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
65861ae650dSJack F Vogel {
6591031d839SEric Joyner 	struct ixl_vsi		*vsi = arg;
66052f45d8aSVincenzo Maffione 	if_softc_ctx_t		scctx = vsi->shared;
6611031d839SEric Joyner 	struct ixl_rx_queue	*que = &vsi->rx_queues[ri->iri_qsidx];
66261ae650dSJack F Vogel 	struct rx_ring		*rxr = &que->rxr;
66361ae650dSJack F Vogel 	union i40e_rx_desc	*cur;
6644294f337SSean Bruno 	u32		status, error;
665*f7926a6dSVincenzo Maffione 	u16		plen;
66661ae650dSJack F Vogel 	u64		qword;
66761ae650dSJack F Vogel 	u8		ptype;
66861ae650dSJack F Vogel 	bool		eop;
6691031d839SEric Joyner 	int i, cidx;
67061ae650dSJack F Vogel 
6711031d839SEric Joyner 	cidx = ri->iri_cidx;
6721031d839SEric Joyner 	i = 0;
6731031d839SEric Joyner 	do {
6741031d839SEric Joyner 		/* 5 descriptor receive limit */
6751031d839SEric Joyner 		MPASS(i < IXL_MAX_RX_SEGS);
67661ae650dSJack F Vogel 
6771031d839SEric Joyner 		cur = &rxr->rx_base[cidx];
67861ae650dSJack F Vogel 		qword = le64toh(cur->wb.qword1.status_error_len);
67961ae650dSJack F Vogel 		status = (qword & I40E_RXD_QW1_STATUS_MASK)
68061ae650dSJack F Vogel 		    >> I40E_RXD_QW1_STATUS_SHIFT;
68161ae650dSJack F Vogel 		error = (qword & I40E_RXD_QW1_ERROR_MASK)
68261ae650dSJack F Vogel 		    >> I40E_RXD_QW1_ERROR_SHIFT;
68361ae650dSJack F Vogel 		plen = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK)
68461ae650dSJack F Vogel 		    >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT;
68561ae650dSJack F Vogel 		ptype = (qword & I40E_RXD_QW1_PTYPE_MASK)
68661ae650dSJack F Vogel 		    >> I40E_RXD_QW1_PTYPE_SHIFT;
68761ae650dSJack F Vogel 
6881031d839SEric Joyner 		/* we should never be called without a valid descriptor */
6891031d839SEric Joyner 		MPASS((status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) != 0);
69061ae650dSJack F Vogel 
6911031d839SEric Joyner 		ri->iri_len += plen;
69277c1fcecSEric Joyner 		rxr->rx_bytes += plen;
6931031d839SEric Joyner 
69461ae650dSJack F Vogel 		cur->wb.qword1.status_error_len = 0;
69561ae650dSJack F Vogel 		eop = (status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT));
69661ae650dSJack F Vogel 
69761ae650dSJack F Vogel 		/*
69861ae650dSJack F Vogel 		** Make sure bad packets are discarded,
69961ae650dSJack F Vogel 		** note that only EOP descriptor has valid
70061ae650dSJack F Vogel 		** error results.
70161ae650dSJack F Vogel 		*/
70261ae650dSJack F Vogel 		if (eop && (error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) {
7036d011ad5SEric Joyner 			rxr->desc_errs++;
7041031d839SEric Joyner 			return (EBADMSG);
70561ae650dSJack F Vogel 		}
7061031d839SEric Joyner 		ri->iri_frags[i].irf_flid = 0;
7071031d839SEric Joyner 		ri->iri_frags[i].irf_idx = cidx;
7081031d839SEric Joyner 		ri->iri_frags[i].irf_len = plen;
7091031d839SEric Joyner 		if (++cidx == vsi->shared->isc_nrxd[0])
7101031d839SEric Joyner 			cidx = 0;
7111031d839SEric Joyner 		i++;
7121031d839SEric Joyner 	} while (!eop);
71361ae650dSJack F Vogel 
71461ae650dSJack F Vogel 	/* capture data for dynamic ITR adjustment */
71561ae650dSJack F Vogel 	rxr->packets++;
7161031d839SEric Joyner 	rxr->rx_packets++;
7171031d839SEric Joyner 
71852f45d8aSVincenzo Maffione 	if ((scctx->isc_capenable & IFCAP_RXCSUM) != 0)
7199f99061eSKrzysztof Galazka 		rxr->csum_errs += ixl_rx_checksum(ri, status, error, ptype);
7201031d839SEric Joyner 	ri->iri_flowid = le32toh(cur->wb.qword0.hi_dword.rss);
7211031d839SEric Joyner 	ri->iri_rsstype = ixl_ptype_to_hash(ptype);
722*f7926a6dSVincenzo Maffione 	if (status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) {
723*f7926a6dSVincenzo Maffione 		ri->iri_vtag = le16toh(cur->wb.qword0.lo_dword.l2tag1);
7241031d839SEric Joyner 		ri->iri_flags |= M_VLANTAG;
725*f7926a6dSVincenzo Maffione 	}
726*f7926a6dSVincenzo Maffione 	ri->iri_nfrags = i;
7271031d839SEric Joyner 	return (0);
7284294f337SSean Bruno }
72961ae650dSJack F Vogel 
73061ae650dSJack F Vogel /*********************************************************************
73161ae650dSJack F Vogel  *
73261ae650dSJack F Vogel  *  Verify that the hardware indicated that the checksum is valid.
73361ae650dSJack F Vogel  *  Inform the stack about the status of checksum so that stack
73461ae650dSJack F Vogel  *  doesn't spend time verifying the checksum.
73561ae650dSJack F Vogel  *
73661ae650dSJack F Vogel  *********************************************************************/
7379f99061eSKrzysztof Galazka static u8
ixl_rx_checksum(if_rxd_info_t ri,u32 status,u32 error,u8 ptype)7381031d839SEric Joyner ixl_rx_checksum(if_rxd_info_t ri, u32 status, u32 error, u8 ptype)
73961ae650dSJack F Vogel {
74061ae650dSJack F Vogel 	struct i40e_rx_ptype_decoded decoded;
74161ae650dSJack F Vogel 
7421031d839SEric Joyner 	ri->iri_csum_flags = 0;
74361ae650dSJack F Vogel 
7441031d839SEric Joyner 	/* No L3 or L4 checksum was calculated */
7451031d839SEric Joyner 	if (!(status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
7469f99061eSKrzysztof Galazka 		return (0);
7471031d839SEric Joyner 
7481031d839SEric Joyner 	decoded = decode_rx_desc_ptype(ptype);
74961ae650dSJack F Vogel 
75061ae650dSJack F Vogel 	/* IPv6 with extension headers likely have bad csum */
75161ae650dSJack F Vogel 	if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
7521031d839SEric Joyner 	    decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) {
75361ae650dSJack F Vogel 		if (status &
75461ae650dSJack F Vogel 		    (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) {
7551031d839SEric Joyner 			ri->iri_csum_flags = 0;
7569f99061eSKrzysztof Galazka 			return (1);
75761ae650dSJack F Vogel 		}
75861ae650dSJack F Vogel 	}
7591031d839SEric Joyner 
7601031d839SEric Joyner 	ri->iri_csum_flags |= CSUM_L3_CALC;
7611031d839SEric Joyner 
7621031d839SEric Joyner 	/* IPv4 checksum error */
7631031d839SEric Joyner 	if (error & (1 << I40E_RX_DESC_ERROR_IPE_SHIFT))
7649f99061eSKrzysztof Galazka 		return (1);
7654b443922SGleb Smirnoff 
7661031d839SEric Joyner 	ri->iri_csum_flags |= CSUM_L3_VALID;
7671031d839SEric Joyner 	ri->iri_csum_flags |= CSUM_L4_CALC;
7684b443922SGleb Smirnoff 
7691031d839SEric Joyner 	/* L4 checksum error */
7701031d839SEric Joyner 	if (error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT))
7719f99061eSKrzysztof Galazka 		return (1);
7724b443922SGleb Smirnoff 
7731031d839SEric Joyner 	ri->iri_csum_flags |= CSUM_L4_VALID;
7741031d839SEric Joyner 	ri->iri_csum_data |= htons(0xffff);
7759f99061eSKrzysztof Galazka 
7769f99061eSKrzysztof Galazka 	return (0);
7774b443922SGleb Smirnoff }
778e5100ee2SJack F Vogel 
77977c1fcecSEric Joyner /* Set Report Status queue fields to 0 */
78077c1fcecSEric Joyner void
ixl_init_tx_rsqs(struct ixl_vsi * vsi)78177c1fcecSEric Joyner ixl_init_tx_rsqs(struct ixl_vsi *vsi)
78277c1fcecSEric Joyner {
78377c1fcecSEric Joyner 	if_softc_ctx_t scctx = vsi->shared;
78477c1fcecSEric Joyner 	struct ixl_tx_queue *tx_que;
78577c1fcecSEric Joyner 	int i, j;
78677c1fcecSEric Joyner 
78777c1fcecSEric Joyner 	for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) {
78877c1fcecSEric Joyner 		struct tx_ring *txr = &tx_que->txr;
78977c1fcecSEric Joyner 
790088a0b27SEric Joyner 		txr->tx_rs_cidx = txr->tx_rs_pidx;
791088a0b27SEric Joyner 
792088a0b27SEric Joyner 		/* Initialize the last processed descriptor to be the end of
793088a0b27SEric Joyner 		 * the ring, rather than the start, so that we avoid an
794088a0b27SEric Joyner 		 * off-by-one error when calculating how many descriptors are
795088a0b27SEric Joyner 		 * done in the credits_update function.
796088a0b27SEric Joyner 		 */
797088a0b27SEric Joyner 		txr->tx_cidx_processed = scctx->isc_ntxd[0] - 1;
79877c1fcecSEric Joyner 
79977c1fcecSEric Joyner 		for (j = 0; j < scctx->isc_ntxd[0]; j++)
80077c1fcecSEric Joyner 			txr->tx_rsq[j] = QIDX_INVALID;
80177c1fcecSEric Joyner 	}
80277c1fcecSEric Joyner }
80377c1fcecSEric Joyner 
80477c1fcecSEric Joyner void
ixl_init_tx_cidx(struct ixl_vsi * vsi)80577c1fcecSEric Joyner ixl_init_tx_cidx(struct ixl_vsi *vsi)
80677c1fcecSEric Joyner {
807088a0b27SEric Joyner 	if_softc_ctx_t scctx = vsi->shared;
80877c1fcecSEric Joyner 	struct ixl_tx_queue *tx_que;
80977c1fcecSEric Joyner 	int i;
81077c1fcecSEric Joyner 
81177c1fcecSEric Joyner 	for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) {
81277c1fcecSEric Joyner 		struct tx_ring *txr = &tx_que->txr;
81377c1fcecSEric Joyner 
814088a0b27SEric Joyner 		txr->tx_cidx_processed = scctx->isc_ntxd[0] - 1;
81577c1fcecSEric Joyner 	}
81677c1fcecSEric Joyner }
81777c1fcecSEric Joyner 
818ceebc2f3SEric Joyner /*
81977c1fcecSEric Joyner  * Input: bitmap of enum virtchnl_link_speed
820ceebc2f3SEric Joyner  */
8211031d839SEric Joyner u64
ixl_max_vc_speed_to_value(u8 link_speeds)82277c1fcecSEric Joyner ixl_max_vc_speed_to_value(u8 link_speeds)
823ceebc2f3SEric Joyner {
82477c1fcecSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_40GB)
8251031d839SEric Joyner 		return IF_Gbps(40);
82677c1fcecSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_25GB)
8271031d839SEric Joyner 		return IF_Gbps(25);
82877c1fcecSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_20GB)
8291031d839SEric Joyner 		return IF_Gbps(20);
83077c1fcecSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_10GB)
8311031d839SEric Joyner 		return IF_Gbps(10);
83277c1fcecSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_1GB)
8331031d839SEric Joyner 		return IF_Gbps(1);
83477c1fcecSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_100MB)
8351031d839SEric Joyner 		return IF_Mbps(100);
8361031d839SEric Joyner 	else
8371031d839SEric Joyner 		/* Minimum supported link speed */
8381031d839SEric Joyner 		return IF_Mbps(100);
839ceebc2f3SEric Joyner }
84077c1fcecSEric Joyner 
84177c1fcecSEric Joyner void
ixl_add_vsi_sysctls(device_t dev,struct ixl_vsi * vsi,struct sysctl_ctx_list * ctx,const char * sysctl_name)84277c1fcecSEric Joyner ixl_add_vsi_sysctls(device_t dev, struct ixl_vsi *vsi,
84377c1fcecSEric Joyner     struct sysctl_ctx_list *ctx, const char *sysctl_name)
84477c1fcecSEric Joyner {
84577c1fcecSEric Joyner 	struct sysctl_oid *tree;
84677c1fcecSEric Joyner 	struct sysctl_oid_list *child;
84777c1fcecSEric Joyner 	struct sysctl_oid_list *vsi_list;
84877c1fcecSEric Joyner 
84977c1fcecSEric Joyner 	tree = device_get_sysctl_tree(dev);
85077c1fcecSEric Joyner 	child = SYSCTL_CHILDREN(tree);
85177c1fcecSEric Joyner 	vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name,
85220b91f0aSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "VSI Number");
85377c1fcecSEric Joyner 	vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
85477c1fcecSEric Joyner 
85577c1fcecSEric Joyner 	ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats);
85677c1fcecSEric Joyner }
85777c1fcecSEric Joyner 
85877c1fcecSEric Joyner void
ixl_add_sysctls_eth_stats(struct sysctl_ctx_list * ctx,struct sysctl_oid_list * child,struct i40e_eth_stats * eth_stats)85977c1fcecSEric Joyner ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
86077c1fcecSEric Joyner 	struct sysctl_oid_list *child,
86177c1fcecSEric Joyner 	struct i40e_eth_stats *eth_stats)
86277c1fcecSEric Joyner {
86377c1fcecSEric Joyner 	struct ixl_sysctl_info ctls[] =
86477c1fcecSEric Joyner 	{
86577c1fcecSEric Joyner 		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
86677c1fcecSEric Joyner 		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
86777c1fcecSEric Joyner 			"Unicast Packets Received"},
86877c1fcecSEric Joyner 		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
86977c1fcecSEric Joyner 			"Multicast Packets Received"},
87077c1fcecSEric Joyner 		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
87177c1fcecSEric Joyner 			"Broadcast Packets Received"},
87277c1fcecSEric Joyner 		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
87377c1fcecSEric Joyner 		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
87477c1fcecSEric Joyner 		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
87577c1fcecSEric Joyner 		{&eth_stats->tx_multicast, "mcast_pkts_txd",
87677c1fcecSEric Joyner 			"Multicast Packets Transmitted"},
87777c1fcecSEric Joyner 		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
87877c1fcecSEric Joyner 			"Broadcast Packets Transmitted"},
87977c1fcecSEric Joyner 		// end
88077c1fcecSEric Joyner 		{0,0,0}
88177c1fcecSEric Joyner 	};
88277c1fcecSEric Joyner 
88377c1fcecSEric Joyner 	struct ixl_sysctl_info *entry = ctls;
88477c1fcecSEric Joyner 	while (entry->stat != 0)
88577c1fcecSEric Joyner 	{
88677c1fcecSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
88777c1fcecSEric Joyner 				CTLFLAG_RD, entry->stat,
88877c1fcecSEric Joyner 				entry->description);
88977c1fcecSEric Joyner 		entry++;
89077c1fcecSEric Joyner 	}
89177c1fcecSEric Joyner }
89277c1fcecSEric Joyner 
89377c1fcecSEric Joyner void
ixl_vsi_add_queues_stats(struct ixl_vsi * vsi,struct sysctl_ctx_list * ctx)894b4a7ce06SEric Joyner ixl_vsi_add_queues_stats(struct ixl_vsi *vsi, struct sysctl_ctx_list *ctx)
89577c1fcecSEric Joyner {
89677c1fcecSEric Joyner 	struct sysctl_oid_list *vsi_list, *queue_list;
89777c1fcecSEric Joyner 	struct sysctl_oid *queue_node;
898b4a7ce06SEric Joyner 	char queue_namebuf[IXL_QUEUE_NAME_LEN];
89977c1fcecSEric Joyner 
90077c1fcecSEric Joyner 	struct ixl_rx_queue *rx_que;
90177c1fcecSEric Joyner 	struct ixl_tx_queue *tx_que;
90277c1fcecSEric Joyner 	struct tx_ring *txr;
90377c1fcecSEric Joyner 	struct rx_ring *rxr;
90477c1fcecSEric Joyner 
90577c1fcecSEric Joyner 	vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
90677c1fcecSEric Joyner 
90777c1fcecSEric Joyner 	/* Queue statistics */
90877c1fcecSEric Joyner 	for (int q = 0; q < vsi->num_rx_queues; q++) {
90977c1fcecSEric Joyner 		bzero(queue_namebuf, sizeof(queue_namebuf));
910b4a7ce06SEric Joyner 		snprintf(queue_namebuf, sizeof(queue_namebuf), "rxq%02d", q);
91177c1fcecSEric Joyner 		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
91220b91f0aSPawel Biernacki 		    OID_AUTO, queue_namebuf, CTLFLAG_RD | CTLFLAG_MPSAFE,
91320b91f0aSPawel Biernacki 		    NULL, "RX Queue #");
91477c1fcecSEric Joyner 		queue_list = SYSCTL_CHILDREN(queue_node);
91577c1fcecSEric Joyner 
91677c1fcecSEric Joyner 		rx_que = &(vsi->rx_queues[q]);
91777c1fcecSEric Joyner 		rxr = &(rx_que->rxr);
91877c1fcecSEric Joyner 
91977c1fcecSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
92077c1fcecSEric Joyner 				CTLFLAG_RD, &(rx_que->irqs),
92177c1fcecSEric Joyner 				"irqs on this queue (both Tx and Rx)");
92277c1fcecSEric Joyner 
92377c1fcecSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "packets",
92477c1fcecSEric Joyner 				CTLFLAG_RD, &(rxr->rx_packets),
92577c1fcecSEric Joyner 				"Queue Packets Received");
92677c1fcecSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "bytes",
92777c1fcecSEric Joyner 				CTLFLAG_RD, &(rxr->rx_bytes),
92877c1fcecSEric Joyner 				"Queue Bytes Received");
92977c1fcecSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "desc_err",
93077c1fcecSEric Joyner 				CTLFLAG_RD, &(rxr->desc_errs),
93177c1fcecSEric Joyner 				"Queue Rx Descriptor Errors");
93277c1fcecSEric Joyner 		SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "itr",
93377c1fcecSEric Joyner 				CTLFLAG_RD, &(rxr->itr), 0,
93477c1fcecSEric Joyner 				"Queue Rx ITR Interval");
93577c1fcecSEric Joyner 	}
93677c1fcecSEric Joyner 	for (int q = 0; q < vsi->num_tx_queues; q++) {
93777c1fcecSEric Joyner 		bzero(queue_namebuf, sizeof(queue_namebuf));
938b4a7ce06SEric Joyner 		snprintf(queue_namebuf, sizeof(queue_namebuf), "txq%02d", q);
93977c1fcecSEric Joyner 		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
94020b91f0aSPawel Biernacki 		    OID_AUTO, queue_namebuf, CTLFLAG_RD | CTLFLAG_MPSAFE,
94120b91f0aSPawel Biernacki 		    NULL, "TX Queue #");
94277c1fcecSEric Joyner 		queue_list = SYSCTL_CHILDREN(queue_node);
94377c1fcecSEric Joyner 
94477c1fcecSEric Joyner 		tx_que = &(vsi->tx_queues[q]);
94577c1fcecSEric Joyner 		txr = &(tx_que->txr);
94677c1fcecSEric Joyner 
94777c1fcecSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso",
94877c1fcecSEric Joyner 				CTLFLAG_RD, &(tx_que->tso),
94977c1fcecSEric Joyner 				"TSO");
95077c1fcecSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mss_too_small",
95177c1fcecSEric Joyner 				CTLFLAG_RD, &(txr->mss_too_small),
95277c1fcecSEric Joyner 				"TSO sends with an MSS less than 64");
95377c1fcecSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "packets",
95477c1fcecSEric Joyner 				CTLFLAG_RD, &(txr->tx_packets),
95577c1fcecSEric Joyner 				"Queue Packets Transmitted");
95677c1fcecSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "bytes",
95777c1fcecSEric Joyner 				CTLFLAG_RD, &(txr->tx_bytes),
95877c1fcecSEric Joyner 				"Queue Bytes Transmitted");
95977c1fcecSEric Joyner 		SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "itr",
96077c1fcecSEric Joyner 				CTLFLAG_RD, &(txr->itr), 0,
96177c1fcecSEric Joyner 				"Queue Tx ITR Interval");
96277c1fcecSEric Joyner 	}
96377c1fcecSEric Joyner }
964