The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/iavf/iavf_txrx_iflib.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* SPDX-License-Identifier: BSD-3-Clause */
    2 /*  Copyright (c) 2021, Intel Corporation
    3  *  All rights reserved.
    4  *
    5  *  Redistribution and use in source and binary forms, with or without
    6  *  modification, are permitted provided that the following conditions are met:
    7  *
    8  *   1. Redistributions of source code must retain the above copyright notice,
    9  *      this list of conditions and the following disclaimer.
   10  *
   11  *   2. Redistributions in binary form must reproduce the above copyright
   12  *      notice, this list of conditions and the following disclaimer in the
   13  *      documentation and/or other materials provided with the distribution.
   14  *
   15  *   3. Neither the name of the Intel Corporation nor the names of its
   16  *      contributors may be used to endorse or promote products derived from
   17  *      this software without specific prior written permission.
   18  *
   19  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   20  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   23  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  *  POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 /*$FreeBSD$*/
   32 
   33 /**
   34  * @file iavf_txrx_iflib.c
   35  * @brief Tx/Rx hotpath implementation for the iflib driver
   36  *
   37  * Contains functions used to implement the Tx and Rx hotpaths of the iflib
   38  * driver implementation.
   39  */
   40 #include "iavf_iflib.h"
   41 #include "iavf_txrx_common.h"
   42 
   43 #ifdef RSS
   44 #include <net/rss_config.h>
   45 #endif
   46 
   47 /* Local Prototypes */
   48 static void     iavf_rx_checksum(if_rxd_info_t ri, u32 status, u32 error, u8 ptype);
   49 
   50 static int      iavf_isc_txd_encap(void *arg, if_pkt_info_t pi);
   51 static void     iavf_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx);
   52 static int      iavf_isc_txd_credits_update_hwb(void *arg, uint16_t txqid, bool clear);
   53 static int      iavf_isc_txd_credits_update_dwb(void *arg, uint16_t txqid, bool clear);
   54 
   55 static void     iavf_isc_rxd_refill(void *arg, if_rxd_update_t iru);
   56 static void     iavf_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused,
   57                                   qidx_t pidx);
   58 static int      iavf_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx,
   59                                       qidx_t budget);
   60 static int      iavf_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri);
   61 
   62 /**
   63  * @var iavf_txrx_hwb
   64  * @brief iflib Tx/Rx operations for head write back
   65  *
   66  * iflib ops structure for when operating the device in head write back mode.
   67  */
   68 struct if_txrx iavf_txrx_hwb = {
   69         iavf_isc_txd_encap,
   70         iavf_isc_txd_flush,
   71         iavf_isc_txd_credits_update_hwb,
   72         iavf_isc_rxd_available,
   73         iavf_isc_rxd_pkt_get,
   74         iavf_isc_rxd_refill,
   75         iavf_isc_rxd_flush,
   76         NULL
   77 };
   78 
   79 /**
   80  * @var iavf_txrx_dwb
   81  * @brief iflib Tx/Rx operations for descriptor write back
   82  *
   83  * iflib ops structure for when operating the device in descriptor write back
   84  * mode.
   85  */
   86 struct if_txrx iavf_txrx_dwb = {
   87         iavf_isc_txd_encap,
   88         iavf_isc_txd_flush,
   89         iavf_isc_txd_credits_update_dwb,
   90         iavf_isc_rxd_available,
   91         iavf_isc_rxd_pkt_get,
   92         iavf_isc_rxd_refill,
   93         iavf_isc_rxd_flush,
   94         NULL
   95 };
   96 
   97 /**
   98  * iavf_is_tx_desc_done - Check if a Tx descriptor is ready
   99  * @txr: the Tx ring to check in
  100  * @idx: ring index to check
  101  *
  102  * @returns true if the descriptor has been written back by hardware, and
  103  * false otherwise.
  104  */
  105 static bool
  106 iavf_is_tx_desc_done(struct tx_ring *txr, int idx)
  107 {
  108         return (((txr->tx_base[idx].cmd_type_offset_bsz >> IAVF_TXD_QW1_DTYPE_SHIFT)
  109             & IAVF_TXD_QW1_DTYPE_MASK) == IAVF_TX_DESC_DTYPE_DESC_DONE);
  110 }
  111 
  112 
  113 /**
  114  * iavf_tso_detect_sparse - detect TSO packets with too many segments
  115  * @segs: packet segments array
  116  * @nsegs: number of packet segments
  117  * @pi: packet information
  118  *
  119  * Hardware only transmits packets with a maximum of 8 descriptors. For TSO
  120  * packets, hardware needs to be able to build the split packets using 8 or
  121  * fewer descriptors. Additionally, the header must be contained within at
  122  * most 3 descriptors.
  123  *
  124  * To verify this, we walk the headers to find out how many descriptors the
  125  * headers require (usually 1). Then we ensure that, for each TSO segment, its
  126  * data plus the headers are contained within 8 or fewer descriptors.
  127  *
  128  * @returns zero if the packet is valid, one otherwise.
  129  */
  130 static int
  131 iavf_tso_detect_sparse(bus_dma_segment_t *segs, int nsegs, if_pkt_info_t pi)
  132 {
  133         int     count, curseg, i, hlen, segsz, seglen, tsolen;
  134 
  135         if (nsegs <= IAVF_MAX_TX_SEGS-2)
  136                 return (0);
  137         segsz = pi->ipi_tso_segsz;
  138         curseg = count = 0;
  139 
  140         hlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen;
  141         tsolen = pi->ipi_len - hlen;
  142 
  143         i = 0;
  144         curseg = segs[0].ds_len;
  145         while (hlen > 0) {
  146                 count++;
  147                 if (count > IAVF_MAX_TX_SEGS - 2)
  148                         return (1);
  149                 if (curseg == 0) {
  150                         i++;
  151                         if (__predict_false(i == nsegs))
  152                                 return (1);
  153 
  154                         curseg = segs[i].ds_len;
  155                 }
  156                 seglen = min(curseg, hlen);
  157                 curseg -= seglen;
  158                 hlen -= seglen;
  159         }
  160         while (tsolen > 0) {
  161                 segsz = pi->ipi_tso_segsz;
  162                 while (segsz > 0 && tsolen != 0) {
  163                         count++;
  164                         if (count > IAVF_MAX_TX_SEGS - 2) {
  165                                 return (1);
  166                         }
  167                         if (curseg == 0) {
  168                                 i++;
  169                                 if (__predict_false(i == nsegs)) {
  170                                         return (1);
  171                                 }
  172                                 curseg = segs[i].ds_len;
  173                         }
  174                         seglen = min(curseg, segsz);
  175                         segsz -= seglen;
  176                         curseg -= seglen;
  177                         tsolen -= seglen;
  178                 }
  179                 count = 0;
  180         }
  181 
  182         return (0);
  183 }
  184 
  185 /**
  186  * iavf_tx_setup_offload - Setup Tx offload parameters
  187  * @que: pointer to the Tx queue
  188  * @pi: Tx packet info
  189  * @cmd: pointer to command descriptor value
  190  * @off: pointer to offset descriptor value
  191  *
  192  * Based on packet type and Tx offloads requested, sets up the command and
  193  * offset values for a Tx descriptor to enable the requested offloads.
  194  */
  195 static void
  196 iavf_tx_setup_offload(struct iavf_tx_queue *que __unused,
  197     if_pkt_info_t pi, u32 *cmd, u32 *off)
  198 {
  199         switch (pi->ipi_etype) {
  200 #ifdef INET
  201                 case ETHERTYPE_IP:
  202                         if (pi->ipi_csum_flags & IAVF_CSUM_IPV4)
  203                                 *cmd |= IAVF_TX_DESC_CMD_IIPT_IPV4_CSUM;
  204                         else
  205                                 *cmd |= IAVF_TX_DESC_CMD_IIPT_IPV4;
  206                         break;
  207 #endif
  208 #ifdef INET6
  209                 case ETHERTYPE_IPV6:
  210                         *cmd |= IAVF_TX_DESC_CMD_IIPT_IPV6;
  211                         break;
  212 #endif
  213                 default:
  214                         break;
  215         }
  216 
  217         *off |= (pi->ipi_ehdrlen >> 1) << IAVF_TX_DESC_LENGTH_MACLEN_SHIFT;
  218         *off |= (pi->ipi_ip_hlen >> 2) << IAVF_TX_DESC_LENGTH_IPLEN_SHIFT;
  219 
  220         switch (pi->ipi_ipproto) {
  221                 case IPPROTO_TCP:
  222                         if (pi->ipi_csum_flags & IAVF_CSUM_TCP) {
  223                                 *cmd |= IAVF_TX_DESC_CMD_L4T_EOFT_TCP;
  224                                 *off |= (pi->ipi_tcp_hlen >> 2) <<
  225                                     IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
  226                                 /* Check for NO_HEAD MDD event */
  227                                 MPASS(pi->ipi_tcp_hlen != 0);
  228                         }
  229                         break;
  230                 case IPPROTO_UDP:
  231                         if (pi->ipi_csum_flags & IAVF_CSUM_UDP) {
  232                                 *cmd |= IAVF_TX_DESC_CMD_L4T_EOFT_UDP;
  233                                 *off |= (sizeof(struct udphdr) >> 2) <<
  234                                     IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
  235                         }
  236                         break;
  237                 case IPPROTO_SCTP:
  238                         if (pi->ipi_csum_flags & IAVF_CSUM_SCTP) {
  239                                 *cmd |= IAVF_TX_DESC_CMD_L4T_EOFT_SCTP;
  240                                 *off |= (sizeof(struct sctphdr) >> 2) <<
  241                                     IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
  242                         }
  243                         /* Fall Thru */
  244                 default:
  245                         break;
  246         }
  247 }
  248 
  249 /**
  250  * iavf_tso_setup - Setup TSO context descriptor
  251  * @txr: the Tx ring to process
  252  * @pi: packet info structure
  253  *
  254  * Enable hardware segmentation offload (TSO) for a given packet by creating
  255  * a context descriptor with the necessary details for offloading.
  256  *
  257  * @returns the new ring index to use for the data descriptor.
  258  */
  259 static int
  260 iavf_tso_setup(struct tx_ring *txr, if_pkt_info_t pi)
  261 {
  262         if_softc_ctx_t                  scctx;
  263         struct iavf_tx_context_desc     *TXD;
  264         u32                             cmd, mss, type, tsolen;
  265         int                             idx, total_hdr_len;
  266         u64                             type_cmd_tso_mss;
  267 
  268         idx = pi->ipi_pidx;
  269         TXD = (struct iavf_tx_context_desc *) &txr->tx_base[idx];
  270         total_hdr_len = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen;
  271         tsolen = pi->ipi_len - total_hdr_len;
  272         scctx = txr->que->vsi->shared;
  273 
  274         type = IAVF_TX_DESC_DTYPE_CONTEXT;
  275         cmd = IAVF_TX_CTX_DESC_TSO;
  276         /*
  277          * TSO MSS must not be less than 64; this prevents a
  278          * BAD_LSO_MSS MDD event when the MSS is too small.
  279          */
  280         if (pi->ipi_tso_segsz < IAVF_MIN_TSO_MSS) {
  281                 txr->mss_too_small++;
  282                 pi->ipi_tso_segsz = IAVF_MIN_TSO_MSS;
  283         }
  284         mss = pi->ipi_tso_segsz;
  285 
  286         /* Check for BAD_LS0_MSS MDD event (mss too large) */
  287         MPASS(mss <= IAVF_MAX_TSO_MSS);
  288         /* Check for NO_HEAD MDD event (header lengths are 0) */
  289         MPASS(pi->ipi_ehdrlen != 0);
  290         MPASS(pi->ipi_ip_hlen != 0);
  291         /* Partial check for BAD_LSO_LEN MDD event */
  292         MPASS(tsolen != 0);
  293         /* Partial check for WRONG_SIZE MDD event (during TSO) */
  294         MPASS(total_hdr_len + mss <= IAVF_MAX_FRAME);
  295 
  296         type_cmd_tso_mss = ((u64)type << IAVF_TXD_CTX_QW1_DTYPE_SHIFT) |
  297             ((u64)cmd << IAVF_TXD_CTX_QW1_CMD_SHIFT) |
  298             ((u64)tsolen << IAVF_TXD_CTX_QW1_TSO_LEN_SHIFT) |
  299             ((u64)mss << IAVF_TXD_CTX_QW1_MSS_SHIFT);
  300         TXD->type_cmd_tso_mss = htole64(type_cmd_tso_mss);
  301 
  302         TXD->tunneling_params = htole32(0);
  303         txr->que->tso++;
  304 
  305         return ((idx + 1) & (scctx->isc_ntxd[0]-1));
  306 }
  307 
  308 #define IAVF_TXD_CMD (IAVF_TX_DESC_CMD_EOP | IAVF_TX_DESC_CMD_RS)
  309 
  310 /**
  311  * iavf_isc_txd_encap - Encapsulate a Tx packet into descriptors
  312  * @arg: void pointer to the VSI structure
  313  * @pi: packet info to encapsulate
  314  *
  315  * This routine maps the mbufs to tx descriptors, allowing the
  316  * TX engine to transmit the packets.
  317  *
  318  * @returns 0 on success, positive on failure
  319  */
  320 static int
  321 iavf_isc_txd_encap(void *arg, if_pkt_info_t pi)
  322 {
  323         struct iavf_vsi         *vsi = arg;
  324         if_softc_ctx_t          scctx = vsi->shared;
  325         struct iavf_tx_queue    *que = &vsi->tx_queues[pi->ipi_qsidx];
  326         struct tx_ring          *txr = &que->txr;
  327         int                     nsegs = pi->ipi_nsegs;
  328         bus_dma_segment_t *segs = pi->ipi_segs;
  329         struct iavf_tx_desc     *txd = NULL;
  330         int                     i, j, mask, pidx_last;
  331         u32                     cmd, off, tx_intr;
  332 
  333         if (__predict_false(pi->ipi_len < IAVF_MIN_FRAME)) {
  334                 que->pkt_too_small++;
  335                 return (EINVAL);
  336         }
  337 
  338         cmd = off = 0;
  339         i = pi->ipi_pidx;
  340 
  341         tx_intr = (pi->ipi_flags & IPI_TX_INTR);
  342 
  343         /* Set up the TSO/CSUM offload */
  344         if (pi->ipi_csum_flags & CSUM_OFFLOAD) {
  345                 /* Set up the TSO context descriptor if required */
  346                 if (pi->ipi_csum_flags & CSUM_TSO) {
  347                         /* Prevent MAX_BUFF MDD event (for TSO) */
  348                         if (iavf_tso_detect_sparse(segs, nsegs, pi))
  349                                 return (EFBIG);
  350                         i = iavf_tso_setup(txr, pi);
  351                 }
  352                 iavf_tx_setup_offload(que, pi, &cmd, &off);
  353         }
  354         if (pi->ipi_mflags & M_VLANTAG)
  355                 cmd |= IAVF_TX_DESC_CMD_IL2TAG1;
  356 
  357         cmd |= IAVF_TX_DESC_CMD_ICRC;
  358         mask = scctx->isc_ntxd[0] - 1;
  359         /* Check for WRONG_SIZE MDD event */
  360         MPASS(pi->ipi_len >= IAVF_MIN_FRAME);
  361 #ifdef INVARIANTS
  362         if (!(pi->ipi_csum_flags & CSUM_TSO))
  363                 MPASS(pi->ipi_len <= IAVF_MAX_FRAME);
  364 #endif
  365         for (j = 0; j < nsegs; j++) {
  366                 bus_size_t seglen;
  367 
  368                 txd = &txr->tx_base[i];
  369                 seglen = segs[j].ds_len;
  370 
  371                 /* Check for ZERO_BSIZE MDD event */
  372                 MPASS(seglen != 0);
  373 
  374                 txd->buffer_addr = htole64(segs[j].ds_addr);
  375                 txd->cmd_type_offset_bsz =
  376                     htole64(IAVF_TX_DESC_DTYPE_DATA
  377                     | ((u64)cmd  << IAVF_TXD_QW1_CMD_SHIFT)
  378                     | ((u64)off << IAVF_TXD_QW1_OFFSET_SHIFT)
  379                     | ((u64)seglen  << IAVF_TXD_QW1_TX_BUF_SZ_SHIFT)
  380                     | ((u64)htole16(pi->ipi_vtag) << IAVF_TXD_QW1_L2TAG1_SHIFT));
  381 
  382                 txr->tx_bytes += seglen;
  383                 pidx_last = i;
  384                 i = (i+1) & mask;
  385         }
  386         /* Set the last descriptor for report */
  387         txd->cmd_type_offset_bsz |=
  388             htole64(((u64)IAVF_TXD_CMD << IAVF_TXD_QW1_CMD_SHIFT));
  389         /* Add to report status array (if using TX interrupts) */
  390         if (!vsi->enable_head_writeback && tx_intr) {
  391                 txr->tx_rsq[txr->tx_rs_pidx] = pidx_last;
  392                 txr->tx_rs_pidx = (txr->tx_rs_pidx+1) & mask;
  393                 MPASS(txr->tx_rs_pidx != txr->tx_rs_cidx);
  394         }
  395         pi->ipi_new_pidx = i;
  396 
  397         ++txr->tx_packets;
  398         return (0);
  399 }
  400 
  401 /**
  402  * iavf_isc_txd_flush - Flush Tx ring
  403  * @arg: void pointer to the VSI
  404  * @txqid: the Tx queue to flush
  405  * @pidx: the ring index to flush to
  406  *
  407  * Advance the Transmit Descriptor Tail (Tdt), this tells the
  408  * hardware that this frame is available to transmit.
  409  */
  410 static void
  411 iavf_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx)
  412 {
  413         struct iavf_vsi *vsi = arg;
  414         struct tx_ring *txr = &vsi->tx_queues[txqid].txr;
  415 
  416         /* Check for ENDLESS_TX MDD event */
  417         MPASS(pidx < vsi->shared->isc_ntxd[0]);
  418         wr32(vsi->hw, txr->tail, pidx);
  419 }
  420 
  421 /**
  422  * iavf_init_tx_ring - Initialize queue Tx ring
  423  * @vsi: pointer to the VSI
  424  * @que: pointer to queue to initialize
  425  *
  426  * (Re)Initialize a queue transmit ring by clearing its memory.
  427  */
  428 void
  429 iavf_init_tx_ring(struct iavf_vsi *vsi, struct iavf_tx_queue *que)
  430 {
  431         struct tx_ring *txr = &que->txr;
  432 
  433         /* Clear the old ring contents */
  434         bzero((void *)txr->tx_base,
  435               (sizeof(struct iavf_tx_desc)) *
  436               (vsi->shared->isc_ntxd[0] + (vsi->enable_head_writeback ? 1 : 0)));
  437 
  438         wr32(vsi->hw, txr->tail, 0);
  439 }
  440 
  441 /**
  442  * iavf_get_tx_head - Get the index of the head of a ring
  443  * @que: queue to read
  444  *
  445  * Retrieve the value from the location the HW records its HEAD index
  446  *
  447  * @returns the index of the HW head of the Tx queue
  448  */
  449 static inline u32
  450 iavf_get_tx_head(struct iavf_tx_queue *que)
  451 {
  452         if_softc_ctx_t          scctx = que->vsi->shared;
  453         struct tx_ring  *txr = &que->txr;
  454         void *head = &txr->tx_base[scctx->isc_ntxd[0]];
  455 
  456         return LE32_TO_CPU(*(volatile __le32 *)head);
  457 }
  458 
  459 /**
  460  * iavf_isc_txd_credits_update_hwb - Update Tx ring credits
  461  * @arg: void pointer to the VSI
  462  * @qid: the queue id to update
  463  * @clear: whether to update or only report current status
  464  *
  465  * Checks the number of packets in the queue that could be cleaned up.
  466  *
  467  * if clear is true, the iflib stack has cleaned the packets and is
  468  * notifying the driver to update its processed ring pointer.
  469  *
  470  * @returns the number of packets in the ring that can be cleaned.
  471  *
  472  * @remark this function is intended for the head write back mode.
  473  */
  474 static int
  475 iavf_isc_txd_credits_update_hwb(void *arg, uint16_t qid, bool clear)
  476 {
  477         struct iavf_vsi          *vsi = arg;
  478         if_softc_ctx_t          scctx = vsi->shared;
  479         struct iavf_tx_queue     *que = &vsi->tx_queues[qid];
  480         struct tx_ring          *txr = &que->txr;
  481         int                      head, credits;
  482 
  483         /* Get the Head WB value */
  484         head = iavf_get_tx_head(que);
  485 
  486         credits = head - txr->tx_cidx_processed;
  487         if (credits < 0)
  488                 credits += scctx->isc_ntxd[0];
  489         if (clear)
  490                 txr->tx_cidx_processed = head;
  491 
  492         return (credits);
  493 }
  494 
  495 /**
  496  * iavf_isc_txd_credits_update_dwb - Update Tx ring credits
  497  * @arg: void pointer to the VSI
  498  * @txqid: the queue id to update
  499  * @clear: whether to update or only report current status
  500  *
  501  * Checks the number of packets in the queue that could be cleaned up.
  502  *
  503  * if clear is true, the iflib stack has cleaned the packets and is
  504  * notifying the driver to update its processed ring pointer.
  505  *
  506  * @returns the number of packets in the ring that can be cleaned.
  507  *
  508  * @remark this function is intended for the descriptor write back mode.
  509  */
  510 static int
  511 iavf_isc_txd_credits_update_dwb(void *arg, uint16_t txqid, bool clear)
  512 {
  513         struct iavf_vsi *vsi = arg;
  514         struct iavf_tx_queue *tx_que = &vsi->tx_queues[txqid];
  515         if_softc_ctx_t scctx = vsi->shared;
  516         struct tx_ring *txr = &tx_que->txr;
  517 
  518         qidx_t processed = 0;
  519         qidx_t cur, prev, ntxd, rs_cidx;
  520         int32_t delta;
  521         bool is_done;
  522 
  523         rs_cidx = txr->tx_rs_cidx;
  524         if (rs_cidx == txr->tx_rs_pidx)
  525                 return (0);
  526         cur = txr->tx_rsq[rs_cidx];
  527         MPASS(cur != QIDX_INVALID);
  528         is_done = iavf_is_tx_desc_done(txr, cur);
  529 
  530         if (!is_done)
  531                 return (0);
  532 
  533         /* If clear is false just let caller know that there
  534          * are descriptors to reclaim */
  535         if (!clear)
  536                 return (1);
  537 
  538         prev = txr->tx_cidx_processed;
  539         ntxd = scctx->isc_ntxd[0];
  540         do {
  541                 MPASS(prev != cur);
  542                 delta = (int32_t)cur - (int32_t)prev;
  543                 if (delta < 0)
  544                         delta += ntxd;
  545                 MPASS(delta > 0);
  546                 processed += delta;
  547                 prev = cur;
  548                 rs_cidx = (rs_cidx + 1) & (ntxd-1);
  549                 if (rs_cidx == txr->tx_rs_pidx)
  550                         break;
  551                 cur = txr->tx_rsq[rs_cidx];
  552                 MPASS(cur != QIDX_INVALID);
  553                 is_done = iavf_is_tx_desc_done(txr, cur);
  554         } while (is_done);
  555 
  556         txr->tx_rs_cidx = rs_cidx;
  557         txr->tx_cidx_processed = prev;
  558 
  559         return (processed);
  560 }
  561 
  562 /**
  563  * iavf_isc_rxd_refill - Prepare descriptors for re-use
  564  * @arg: void pointer to the VSI
  565  * @iru: the Rx descriptor update structure
  566  *
  567  * Update Rx descriptors for a given queue so that they can be re-used by
  568  * hardware for future packets.
  569  */
  570 static void
  571 iavf_isc_rxd_refill(void *arg, if_rxd_update_t iru)
  572 {
  573         struct iavf_vsi *vsi = arg;
  574         if_softc_ctx_t scctx = vsi->shared;
  575         struct rx_ring *rxr = &((vsi->rx_queues[iru->iru_qsidx]).rxr);
  576         uint64_t *paddrs;
  577         uint16_t next_pidx, pidx;
  578         uint16_t count;
  579         int i;
  580 
  581         paddrs = iru->iru_paddrs;
  582         pidx = iru->iru_pidx;
  583         count = iru->iru_count;
  584 
  585         for (i = 0, next_pidx = pidx; i < count; i++) {
  586                 rxr->rx_base[next_pidx].read.pkt_addr = htole64(paddrs[i]);
  587                 if (++next_pidx == scctx->isc_nrxd[0])
  588                         next_pidx = 0;
  589         }
  590 }
  591 
  592 /**
  593  * iavf_isc_rxd_flush - Notify hardware of new Rx descriptors
  594  * @arg: void pointer to the VSI
  595  * @rxqid: Rx queue to update
  596  * @flid: unused parameter
  597  * @pidx: ring index to update to
  598  *
  599  * Updates the tail pointer of the Rx ring, notifying hardware of new
  600  * descriptors available for receiving packets.
  601  */
  602 static void
  603 iavf_isc_rxd_flush(void * arg, uint16_t rxqid, uint8_t flid __unused, qidx_t pidx)
  604 {
  605         struct iavf_vsi         *vsi = arg;
  606         struct rx_ring          *rxr = &vsi->rx_queues[rxqid].rxr;
  607 
  608         wr32(vsi->hw, rxr->tail, pidx);
  609 }
  610 
  611 /**
  612  * iavf_isc_rxd_available - Calculate number of available Rx descriptors
  613  * @arg: void pointer to the VSI
  614  * @rxqid: Rx queue to check
  615  * @idx: starting index to check from
  616  * @budget: maximum Rx budget
  617  *
  618  * Determines how many packets are ready to be processed in the Rx queue, up
  619  * to the specified budget.
  620  *
  621  * @returns the number of packets ready to be processed, up to the budget.
  622  */
  623 static int
  624 iavf_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget)
  625 {
  626         struct iavf_vsi *vsi = arg;
  627         struct rx_ring *rxr = &vsi->rx_queues[rxqid].rxr;
  628         union iavf_rx_desc *rxd;
  629         u64 qword;
  630         uint32_t status;
  631         int cnt, i, nrxd;
  632 
  633         nrxd = vsi->shared->isc_nrxd[0];
  634 
  635         for (cnt = 0, i = idx; cnt < nrxd - 1 && cnt <= budget;) {
  636                 rxd = &rxr->rx_base[i];
  637                 qword = le64toh(rxd->wb.qword1.status_error_len);
  638                 status = (qword & IAVF_RXD_QW1_STATUS_MASK)
  639                         >> IAVF_RXD_QW1_STATUS_SHIFT;
  640 
  641                 if ((status & (1 << IAVF_RX_DESC_STATUS_DD_SHIFT)) == 0)
  642                         break;
  643                 if (++i == nrxd)
  644                         i = 0;
  645                 if (status & (1 << IAVF_RX_DESC_STATUS_EOF_SHIFT))
  646                         cnt++;
  647         }
  648 
  649         return (cnt);
  650 }
  651 
  652 /**
  653  * iavf_isc_rxd_pkt_get - Decapsulate packet from Rx descriptors
  654  * @arg: void pointer to the VSI
  655  * @ri: packet info structure
  656  *
  657  * Read packet data from the Rx ring descriptors and fill in the packet info
  658  * structure so that the iflib stack can process the packet.
  659  *
  660  * @remark this routine executes in ithread context.
  661  *
  662  * @returns zero success, or EBADMSG if the packet is corrupted.
  663  */
  664 static int
  665 iavf_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
  666 {
  667         struct iavf_vsi         *vsi = arg;
  668         if_softc_ctx_t          scctx = vsi->shared;
  669         struct iavf_rx_queue    *que = &vsi->rx_queues[ri->iri_qsidx];
  670         struct rx_ring          *rxr = &que->rxr;
  671         union iavf_rx_desc      *cur;
  672         u32             status, error;
  673         u16             plen;
  674         u64             qword;
  675         u8              ptype;
  676         bool            eop;
  677         int i, cidx;
  678 
  679         cidx = ri->iri_cidx;
  680         i = 0;
  681         do {
  682                 /* 5 descriptor receive limit */
  683                 MPASS(i < IAVF_MAX_RX_SEGS);
  684 
  685                 cur = &rxr->rx_base[cidx];
  686                 qword = le64toh(cur->wb.qword1.status_error_len);
  687                 status = (qword & IAVF_RXD_QW1_STATUS_MASK)
  688                     >> IAVF_RXD_QW1_STATUS_SHIFT;
  689                 error = (qword & IAVF_RXD_QW1_ERROR_MASK)
  690                     >> IAVF_RXD_QW1_ERROR_SHIFT;
  691                 plen = (qword & IAVF_RXD_QW1_LENGTH_PBUF_MASK)
  692                     >> IAVF_RXD_QW1_LENGTH_PBUF_SHIFT;
  693                 ptype = (qword & IAVF_RXD_QW1_PTYPE_MASK)
  694                     >> IAVF_RXD_QW1_PTYPE_SHIFT;
  695 
  696                 /* we should never be called without a valid descriptor */
  697                 MPASS((status & (1 << IAVF_RX_DESC_STATUS_DD_SHIFT)) != 0);
  698 
  699                 ri->iri_len += plen;
  700                 rxr->rx_bytes += plen;
  701 
  702                 cur->wb.qword1.status_error_len = 0;
  703                 eop = (status & (1 << IAVF_RX_DESC_STATUS_EOF_SHIFT));
  704 
  705                 /*
  706                 ** Make sure bad packets are discarded,
  707                 ** note that only EOP descriptor has valid
  708                 ** error results.
  709                 */
  710                 if (eop && (error & (1 << IAVF_RX_DESC_ERROR_RXE_SHIFT))) {
  711                         rxr->desc_errs++;
  712                         return (EBADMSG);
  713                 }
  714                 ri->iri_frags[i].irf_flid = 0;
  715                 ri->iri_frags[i].irf_idx = cidx;
  716                 ri->iri_frags[i].irf_len = plen;
  717                 if (++cidx == vsi->shared->isc_nrxd[0])
  718                         cidx = 0;
  719                 i++;
  720         } while (!eop);
  721 
  722         /* capture data for dynamic ITR adjustment */
  723         rxr->packets++;
  724         rxr->rx_packets++;
  725 
  726         if ((scctx->isc_capenable & IFCAP_RXCSUM) != 0)
  727                 iavf_rx_checksum(ri, status, error, ptype);
  728         ri->iri_flowid = le32toh(cur->wb.qword0.hi_dword.rss);
  729         ri->iri_rsstype = iavf_ptype_to_hash(ptype);
  730         if (status & (1 << IAVF_RX_DESC_STATUS_L2TAG1P_SHIFT)) {
  731                 ri->iri_vtag = le16toh(cur->wb.qword0.lo_dword.l2tag1);
  732                 ri->iri_flags |= M_VLANTAG;
  733         }
  734         ri->iri_nfrags = i;
  735         return (0);
  736 }
  737 
  738 /**
  739  * iavf_rx_checksum - Handle Rx hardware checksum indication
  740  * @ri: Rx packet info structure
  741  * @status: status from Rx descriptor
  742  * @error: error from Rx descriptor
  743  * @ptype: packet type
  744  *
  745  * Verify that the hardware indicated that the checksum is valid.
  746  * Inform the stack about the status of checksum so that stack
  747  * doesn't spend time verifying the checksum.
  748  */
  749 static void
  750 iavf_rx_checksum(if_rxd_info_t ri, u32 status, u32 error, u8 ptype)
  751 {
  752         struct iavf_rx_ptype_decoded decoded;
  753 
  754         ri->iri_csum_flags = 0;
  755 
  756         /* No L3 or L4 checksum was calculated */
  757         if (!(status & (1 << IAVF_RX_DESC_STATUS_L3L4P_SHIFT)))
  758                 return;
  759 
  760         decoded = decode_rx_desc_ptype(ptype);
  761 
  762         /* IPv6 with extension headers likely have bad csum */
  763         if (decoded.outer_ip == IAVF_RX_PTYPE_OUTER_IP &&
  764             decoded.outer_ip_ver == IAVF_RX_PTYPE_OUTER_IPV6) {
  765                 if (status &
  766                     (1 << IAVF_RX_DESC_STATUS_IPV6EXADD_SHIFT)) {
  767                         ri->iri_csum_flags = 0;
  768                         return;
  769                 }
  770         }
  771 
  772         ri->iri_csum_flags |= CSUM_L3_CALC;
  773 
  774         /* IPv4 checksum error */
  775         if (error & (1 << IAVF_RX_DESC_ERROR_IPE_SHIFT))
  776                 return;
  777 
  778         ri->iri_csum_flags |= CSUM_L3_VALID;
  779         ri->iri_csum_flags |= CSUM_L4_CALC;
  780 
  781         /* L4 checksum error */
  782         if (error & (1 << IAVF_RX_DESC_ERROR_L4E_SHIFT))
  783                 return;
  784 
  785         ri->iri_csum_flags |= CSUM_L4_VALID;
  786         ri->iri_csum_data |= htons(0xffff);
  787 }

Cache object: 5903bef95776c0d91488a2ff31d4282b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.