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 {ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
86677c1fcecSEric Joyner {ð_stats->rx_unicast, "ucast_pkts_rcvd",
86777c1fcecSEric Joyner "Unicast Packets Received"},
86877c1fcecSEric Joyner {ð_stats->rx_multicast, "mcast_pkts_rcvd",
86977c1fcecSEric Joyner "Multicast Packets Received"},
87077c1fcecSEric Joyner {ð_stats->rx_broadcast, "bcast_pkts_rcvd",
87177c1fcecSEric Joyner "Broadcast Packets Received"},
87277c1fcecSEric Joyner {ð_stats->rx_discards, "rx_discards", "Discarded RX packets"},
87377c1fcecSEric Joyner {ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
87477c1fcecSEric Joyner {ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
87577c1fcecSEric Joyner {ð_stats->tx_multicast, "mcast_pkts_txd",
87677c1fcecSEric Joyner "Multicast Packets Transmitted"},
87777c1fcecSEric Joyner {ð_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