LCOV - code coverage report
Current view: top level - drivers/net/gve - gve_tx_dqo.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 287 0.0 %
Date: 2025-10-01 17:51:42 Functions: 0 13 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 130 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright (c) 2022-2023 Google LLC
       3                 :            :  * Copyright (c) 2022-2023 Intel Corporation
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "gve_ethdev.h"
       7                 :            : #include "base/gve_adminq.h"
       8                 :            : #include "rte_malloc.h"
       9                 :            : 
      10                 :            : static inline void
      11                 :            : gve_free_compl_tags_init(struct gve_tx_queue *txq)
      12                 :            : {
      13                 :          0 :         uint16_t sw_mask = txq->sw_size - 1;
      14                 :            :         int i;
      15                 :            : 
      16         [ #  # ]:          0 :         for (i = 0; i < sw_mask; i++)
      17                 :          0 :                 txq->pkt_ring_dqo[i].next_avail_pkt = (i + 1) & sw_mask;
      18                 :            : 
      19                 :          0 :         txq->pkt_ring_dqo[sw_mask].next_avail_pkt = -1;
      20                 :          0 :         txq->free_compl_tags_head = 0;
      21                 :          0 :         txq->num_free_compl_tags = txq->sw_size;
      22                 :            : }
      23                 :            : 
      24                 :            : /* Removes first item from the buffer free list, and return its array index. */
      25                 :            : static inline bool
      26                 :          0 : gve_free_compl_tags_pop(struct gve_tx_queue *txq, uint16_t *compl_tag)
      27                 :            : {
      28                 :          0 :         int16_t head = txq->free_compl_tags_head;
      29         [ #  # ]:          0 :         if (likely(head != -1)) {
      30                 :          0 :                 struct gve_tx_pkt *head_pkt = &txq->pkt_ring_dqo[head];
      31                 :            : 
      32                 :          0 :                 txq->free_compl_tags_head = head_pkt->next_avail_pkt;
      33                 :          0 :                 txq->num_free_compl_tags--;
      34                 :          0 :                 *compl_tag = head;
      35                 :          0 :                 return true;
      36                 :            :         }
      37                 :            : 
      38                 :          0 :         PMD_DRV_DP_LOG(ERR, "Completion tags list is empty!");
      39                 :          0 :         return false;
      40                 :            : }
      41                 :            : 
      42                 :            : /* Adds gve_tx_pkt in pkt_ring to free list. Assumes that
      43                 :            :  * buf_id < txq->sw_size.
      44                 :            :  */
      45                 :            : static inline void
      46                 :            : gve_free_compl_tags_push(struct gve_tx_queue *txq, uint16_t compl_tag)
      47                 :            : {
      48                 :          0 :         txq->pkt_ring_dqo[compl_tag].next_avail_pkt = txq->free_compl_tags_head;
      49                 :          0 :         txq->free_compl_tags_head = compl_tag;
      50                 :          0 :         txq->num_free_compl_tags++;
      51                 :          0 : }
      52                 :            : 
      53                 :            : static inline void
      54                 :          0 : gve_tx_clean_dqo(struct gve_tx_queue *txq)
      55                 :            : {
      56                 :            :         struct gve_tx_compl_desc *compl_ring;
      57                 :            :         struct gve_tx_compl_desc *compl_desc;
      58                 :            :         struct gve_tx_queue *aim_txq;
      59                 :            :         struct gve_tx_pkt *pkt;
      60                 :            :         uint16_t new_tx_head;
      61                 :            :         uint16_t compl_tag;
      62                 :            :         uint16_t next;
      63                 :            : 
      64                 :          0 :         next = txq->complq_tail;
      65                 :          0 :         compl_ring = txq->compl_ring;
      66                 :          0 :         compl_desc = &compl_ring[next];
      67                 :            : 
      68         [ #  # ]:          0 :         if (compl_desc->generation != txq->cur_gen_bit)
      69                 :            :                 return;
      70                 :            : 
      71                 :          0 :         rte_io_rmb();
      72                 :            : 
      73                 :          0 :         aim_txq = txq->txqs[compl_desc->id];
      74                 :            : 
      75   [ #  #  #  # ]:          0 :         switch (compl_desc->type) {
      76                 :          0 :         case GVE_COMPL_TYPE_DQO_DESC:
      77                 :          0 :                 new_tx_head = rte_le_to_cpu_16(compl_desc->tx_head);
      78                 :          0 :                 aim_txq->nb_free +=
      79                 :          0 :                         (new_tx_head - aim_txq->last_desc_cleaned)
      80                 :          0 :                                 & (aim_txq->nb_tx_desc - 1);
      81                 :          0 :                 aim_txq->last_desc_cleaned = new_tx_head;
      82                 :          0 :                 break;
      83                 :          0 :         case GVE_COMPL_TYPE_DQO_REINJECTION:
      84                 :            :                 PMD_DRV_DP_LOG(DEBUG, "GVE_COMPL_TYPE_DQO_REINJECTION !!!");
      85                 :            :                 /* FALLTHROUGH */
      86                 :            :         case GVE_COMPL_TYPE_DQO_PKT:
      87                 :            :                 /* The first segment has buf_id == completion_tag. */
      88                 :          0 :                 compl_tag = rte_le_to_cpu_16(compl_desc->completion_tag);
      89         [ #  # ]:          0 :                 if (unlikely(compl_tag >= txq->sw_size)) {
      90                 :          0 :                         PMD_DRV_DP_LOG(ERR, "Invalid completion tag %d",
      91                 :            :                                        compl_tag);
      92                 :          0 :                         break;
      93                 :            :                 }
      94                 :            : 
      95                 :            :                 /* Free packet.*/
      96                 :          0 :                 pkt = &aim_txq->pkt_ring_dqo[compl_tag];
      97         [ #  # ]:          0 :                 if (unlikely(!pkt->mbuf)) {
      98                 :          0 :                         PMD_DRV_DP_LOG(ERR, "No outstanding packet for completion tag %d",
      99                 :            :                                        compl_tag);
     100                 :          0 :                         break;
     101                 :            :                 }
     102                 :          0 :                 rte_pktmbuf_free(pkt->mbuf);
     103                 :          0 :                 pkt->mbuf = NULL;
     104                 :            :                 gve_free_compl_tags_push(txq, compl_tag);
     105                 :            :                 break;
     106                 :          0 :         case GVE_COMPL_TYPE_DQO_MISS:
     107                 :          0 :                 rte_delay_us_sleep(1);
     108                 :            :                 PMD_DRV_DP_LOG(DEBUG, "GVE_COMPL_TYPE_DQO_MISS ignored !!!");
     109                 :          0 :                 break;
     110                 :          0 :         default:
     111                 :          0 :                 PMD_DRV_DP_LOG(ERR, "unknown completion type.");
     112                 :          0 :                 return;
     113                 :            :         }
     114                 :            : 
     115                 :          0 :         next++;
     116         [ #  # ]:          0 :         if (next == txq->nb_complq_desc) {
     117                 :            :                 next = 0;
     118                 :          0 :                 txq->cur_gen_bit ^= 1;
     119                 :            :         }
     120                 :          0 :         txq->complq_tail = next;
     121                 :            : }
     122                 :            : 
     123                 :            : static inline void
     124                 :            : gve_tx_clean_descs_dqo(struct gve_tx_queue *txq, uint16_t nb_descs) {
     125   [ #  #  #  # ]:          0 :         while (--nb_descs)
     126                 :          0 :                 gve_tx_clean_dqo(txq);
     127                 :            : }
     128                 :            : 
     129                 :            : /* GVE expects at most 10 data descriptors per mtu-sized segment. Beyond this,
     130                 :            :  * the hardware will assume the driver is malicious and stop transmitting
     131                 :            :  * packets altogether. Validate that a packet can be sent to avoid sending
     132                 :            :  * posting descriptors for an invalid packet.
     133                 :            :  */
     134                 :            : static inline bool
     135                 :          0 : gve_tx_validate_descs(struct rte_mbuf *tx_pkt, uint16_t nb_descs, bool is_tso)
     136                 :            : {
     137         [ #  # ]:          0 :         if (!is_tso)
     138                 :          0 :                 return nb_descs <= GVE_TX_MAX_DATA_DESCS;
     139                 :            : 
     140                 :          0 :         int tso_segsz = tx_pkt->tso_segsz;
     141                 :            :         int num_descs, seg_offset, mbuf_len;
     142                 :          0 :         int headlen = tx_pkt->l2_len + tx_pkt->l3_len + tx_pkt->l4_len;
     143                 :            : 
     144                 :            :         /* Headers will be split into their own buffer. */
     145                 :            :         num_descs = 1;
     146                 :            :         seg_offset = 0;
     147                 :          0 :         mbuf_len = tx_pkt->data_len - headlen;
     148                 :            : 
     149         [ #  # ]:          0 :         while (tx_pkt) {
     150         [ #  # ]:          0 :                 if (!mbuf_len)
     151                 :          0 :                         goto next_mbuf;
     152                 :            : 
     153                 :          0 :                 int seg_remain = tso_segsz - seg_offset;
     154         [ #  # ]:          0 :                 if (num_descs == GVE_TX_MAX_DATA_DESCS && seg_remain)
     155                 :            :                         return false;
     156                 :            : 
     157         [ #  # ]:          0 :                 if (seg_remain < mbuf_len) {
     158                 :          0 :                         seg_offset = mbuf_len % tso_segsz;
     159                 :            :                         /* The MSS is bound from above by 9728B, so a
     160                 :            :                          * single TSO segment in the middle of an mbuf
     161                 :            :                          * will be part of at most two descriptors, and
     162                 :            :                          * is not at risk of defying this limitation.
     163                 :            :                          * Thus, such segments are ignored.
     164                 :            :                          */
     165                 :          0 :                         int mbuf_remain = tx_pkt->data_len % GVE_TX_MAX_BUF_SIZE_DQO;
     166                 :            : 
     167                 :            :                         /* For each TSO segment, HW will prepend
     168                 :            :                          * headers. The remaining bytes of this mbuf
     169                 :            :                          * will be the start of the payload of the next
     170                 :            :                          * TSO segment. In addition, if the final
     171                 :            :                          * segment in this mbuf is divided between two
     172                 :            :                          * descriptors, both must be counted.
     173                 :            :                          */
     174         [ #  # ]:          0 :                         num_descs = 1 + !!(seg_offset) +
     175                 :          0 :                                 (mbuf_remain < seg_offset && mbuf_remain);
     176                 :            :                 } else {
     177                 :          0 :                         seg_offset += mbuf_len;
     178                 :          0 :                         num_descs++;
     179                 :            :                 }
     180                 :            : 
     181                 :          0 : next_mbuf:
     182                 :          0 :                 tx_pkt = tx_pkt->next;
     183         [ #  # ]:          0 :                 if (tx_pkt)
     184                 :          0 :                         mbuf_len = tx_pkt->data_len;
     185                 :            :         }
     186                 :            : 
     187                 :            : 
     188                 :            :         return true;
     189                 :            : }
     190                 :            : 
     191                 :            : static uint16_t
     192                 :            : gve_tx_pkt_nb_data_descs(struct rte_mbuf *tx_pkt)
     193                 :            : {
     194                 :            :         int nb_descs = 0;
     195                 :            : 
     196         [ #  # ]:          0 :         while (tx_pkt) {
     197                 :          0 :                 nb_descs += (GVE_TX_MAX_BUF_SIZE_DQO - 1 + tx_pkt->data_len) /
     198                 :            :                         GVE_TX_MAX_BUF_SIZE_DQO;
     199                 :          0 :                 tx_pkt = tx_pkt->next;
     200                 :            :         }
     201                 :          0 :         return nb_descs;
     202                 :            : }
     203                 :            : 
     204                 :            : static inline bool
     205                 :            : gve_can_tx(struct gve_tx_queue *txq, uint16_t nb_desc, uint16_t nb_pkts)
     206                 :            : {
     207   [ #  #  #  #  :          0 :         return txq->nb_free >= nb_desc && txq->num_free_compl_tags >= nb_pkts;
             #  #  #  # ]
     208                 :            : }
     209                 :            : 
     210                 :            : static inline void
     211                 :            : gve_tx_fill_seg_desc_dqo(volatile union gve_tx_desc_dqo *desc, struct rte_mbuf *tx_pkt)
     212                 :            : {
     213                 :          0 :         uint32_t hlen = tx_pkt->l2_len + tx_pkt->l3_len + tx_pkt->l4_len;
     214                 :            : 
     215                 :          0 :         desc->tso_ctx = (struct gve_tx_tso_context_desc_dqo) {};
     216                 :          0 :         desc->tso_ctx.cmd_dtype.dtype = GVE_TX_TSO_CTX_DESC_DTYPE_DQO;
     217                 :          0 :         desc->tso_ctx.cmd_dtype.tso = 1;
     218                 :          0 :         desc->tso_ctx.mss = (uint16_t)tx_pkt->tso_segsz;
     219                 :          0 :         desc->tso_ctx.tso_total_len = tx_pkt->pkt_len - hlen;
     220                 :          0 :         desc->tso_ctx.header_len = (uint8_t)hlen;
     221                 :            : }
     222                 :            : 
     223                 :            : static void
     224                 :          0 : gve_fill_tx_pkt_desc(struct gve_tx_queue *txq, uint16_t *tx_id,
     225                 :            :                      struct rte_mbuf *tx_pkt, uint16_t compl_tag,
     226                 :            :                      bool checksum_offload_enable)
     227                 :            : {
     228                 :            :         volatile union gve_tx_desc_dqo *desc;
     229                 :          0 :         uint16_t mask = txq->nb_tx_desc - 1;
     230                 :            :         int mbuf_offset = 0;
     231                 :            : 
     232         [ #  # ]:          0 :         while (mbuf_offset < tx_pkt->data_len) {
     233                 :          0 :                 uint64_t buf_addr = rte_mbuf_data_iova(tx_pkt) + mbuf_offset;
     234                 :            : 
     235                 :          0 :                 desc = &txq->tx_ring[*tx_id];
     236                 :          0 :                 desc->pkt = (struct gve_tx_pkt_desc_dqo) {};
     237                 :          0 :                 desc->pkt.buf_addr = rte_cpu_to_le_64(buf_addr);
     238                 :          0 :                 desc->pkt.compl_tag = rte_cpu_to_le_16(compl_tag);
     239                 :          0 :                 desc->pkt.dtype = GVE_TX_PKT_DESC_DTYPE_DQO;
     240                 :          0 :                 desc->pkt.buf_size = RTE_MIN(tx_pkt->data_len - mbuf_offset,
     241                 :            :                                              GVE_TX_MAX_BUF_SIZE_DQO);
     242                 :          0 :                 desc->pkt.end_of_packet = 0;
     243                 :          0 :                 desc->pkt.checksum_offload_enable = checksum_offload_enable;
     244                 :            : 
     245                 :          0 :                 mbuf_offset += desc->pkt.buf_size;
     246                 :          0 :                 *tx_id = (*tx_id + 1) & mask;
     247                 :            :         }
     248                 :          0 : }
     249                 :            : 
     250                 :            : uint16_t
     251                 :          0 : gve_tx_burst_dqo(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
     252                 :            : {
     253                 :            :         struct gve_tx_queue *txq = tx_queue;
     254                 :            :         volatile union gve_tx_desc_dqo *txr;
     255                 :            :         volatile union gve_tx_desc_dqo *txd;
     256                 :          0 :         uint16_t mask = txq->nb_tx_desc - 1;
     257                 :            :         struct gve_tx_pkt *pkts;
     258                 :            :         struct rte_mbuf *tx_pkt;
     259                 :            :         uint16_t compl_tag;
     260                 :            :         const char *reason;
     261                 :            :         uint16_t nb_tx = 0;
     262                 :            :         uint64_t bytes = 0;
     263                 :            :         uint64_t ol_flags;
     264                 :            :         uint16_t nb_descs;
     265                 :            :         bool csum, tso;
     266                 :            :         uint16_t tx_id;
     267                 :            : 
     268                 :          0 :         pkts = txq->pkt_ring_dqo;
     269                 :          0 :         txr = txq->tx_ring;
     270                 :            : 
     271                 :          0 :         tx_id = txq->tx_tail;
     272                 :            : 
     273         [ #  # ]:          0 :         for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
     274                 :          0 :                 tx_pkt = tx_pkts[nb_tx];
     275                 :            : 
     276   [ #  #  #  # ]:          0 :                 if (!gve_can_tx(txq, txq->free_thresh, nb_pkts - nb_tx))
     277                 :          0 :                         gve_tx_clean_descs_dqo(txq, DQO_TX_MULTIPLIER *
     278                 :          0 :                                                txq->rs_thresh);
     279                 :            : 
     280                 :            : 
     281         [ #  # ]:          0 :                 if (rte_mbuf_check(tx_pkt, true, &reason)) {
     282                 :            :                         PMD_DRV_DP_LOG(DEBUG, "Invalid mbuf: %s", reason);
     283                 :            :                         break;
     284                 :            :                 }
     285                 :            : 
     286                 :          0 :                 ol_flags = tx_pkt->ol_flags;
     287                 :          0 :                 tso = !!(ol_flags & RTE_MBUF_F_TX_TCP_SEG);
     288                 :          0 :                 csum = !!(ol_flags & GVE_TX_CKSUM_OFFLOAD_MASK_DQO);
     289                 :            : 
     290                 :            :                 nb_descs = gve_tx_pkt_nb_data_descs(tx_pkt);
     291                 :          0 :                 nb_descs += tso;
     292                 :            : 
     293                 :            :                 /* Clean if there aren't enough descriptors to send the packet. */
     294   [ #  #  #  # ]:          0 :                 if (unlikely(!gve_can_tx(txq, nb_descs, 1))) {
     295                 :          0 :                         int nb_to_clean = RTE_MAX(DQO_TX_MULTIPLIER * txq->rs_thresh,
     296                 :            :                                                   nb_descs);
     297                 :            : 
     298                 :          0 :                         gve_tx_clean_descs_dqo(txq, nb_to_clean);
     299         [ #  # ]:          0 :                         if (!gve_can_tx(txq, nb_descs, 1))
     300                 :            :                                 break;
     301                 :            :                 }
     302                 :            : 
     303                 :            :                 /* Drop packet if it doesn't adhere to hardware limits. */
     304         [ #  # ]:          0 :                 if (!gve_tx_validate_descs(tx_pkt, nb_descs, tso)) {
     305                 :          0 :                         txq->stats.too_many_descs++;
     306                 :          0 :                         break;
     307                 :            :                 }
     308                 :            : 
     309         [ #  # ]:          0 :                 if (tso) {
     310                 :          0 :                         txd = &txr[tx_id];
     311                 :            :                         gve_tx_fill_seg_desc_dqo(txd, tx_pkt);
     312                 :          0 :                         tx_id = (tx_id + 1) & mask;
     313                 :            :                 }
     314                 :            : 
     315         [ #  # ]:          0 :                 if (!gve_free_compl_tags_pop(txq, &compl_tag))
     316                 :            :                         break;
     317                 :            : 
     318                 :          0 :                 pkts[compl_tag].mbuf = tx_pkt;
     319         [ #  # ]:          0 :                 while (tx_pkt) {
     320                 :            :                         /* Skip writing descriptors if mbuf has no data. */
     321         [ #  # ]:          0 :                         if (!tx_pkt->data_len) {
     322                 :          0 :                                 tx_pkt = tx_pkt->next;
     323                 :          0 :                                 continue;
     324                 :            :                         }
     325                 :          0 :                         gve_fill_tx_pkt_desc(txq, &tx_id, tx_pkt, compl_tag,
     326                 :            :                                              csum);
     327                 :          0 :                         bytes += tx_pkt->data_len;
     328                 :          0 :                         tx_pkt = tx_pkt->next;
     329                 :            :                 }
     330                 :            :                 /* fill the last written descriptor with End of Packet (EOP) bit */
     331                 :          0 :                 txd = &txr[(tx_id - 1) & mask];
     332                 :          0 :                 txd->pkt.end_of_packet = 1;
     333                 :            : 
     334                 :          0 :                 txq->nb_free -= nb_descs;
     335                 :          0 :                 txq->nb_used += nb_descs;
     336                 :            :         }
     337                 :            : 
     338                 :            :         /* update the tail pointer if any packets were processed */
     339         [ #  # ]:          0 :         if (nb_tx > 0) {
     340                 :            :                 /* Request a descriptor completion on the last descriptor */
     341                 :          0 :                 txq->re_cnt += nb_tx;
     342         [ #  # ]:          0 :                 if (txq->re_cnt >= GVE_TX_MIN_RE_INTERVAL) {
     343                 :          0 :                         txd = &txr[(tx_id - 1) & mask];
     344                 :          0 :                         txd->pkt.report_event = true;
     345                 :          0 :                         txq->re_cnt = 0;
     346                 :            :                 }
     347                 :            : 
     348                 :          0 :                 rte_write32(tx_id, txq->qtx_tail);
     349                 :          0 :                 txq->tx_tail = tx_id;
     350                 :            : 
     351                 :          0 :                 txq->stats.packets += nb_tx;
     352                 :          0 :                 txq->stats.bytes += bytes;
     353                 :          0 :                 txq->stats.errors += nb_pkts - nb_tx;
     354                 :            :         }
     355                 :            : 
     356                 :          0 :         return nb_tx;
     357                 :            : }
     358                 :            : 
     359                 :            : static inline void
     360                 :            : gve_release_txq_mbufs_dqo(struct gve_tx_queue *txq)
     361                 :            : {
     362                 :            :         uint16_t i;
     363                 :            : 
     364   [ #  #  #  # ]:          0 :         for (i = 0; i < txq->sw_size; i++)
     365                 :          0 :                 rte_pktmbuf_free(txq->pkt_ring_dqo[i].mbuf);
     366                 :            : }
     367                 :            : 
     368                 :            : void
     369                 :          0 : gve_tx_queue_release_dqo(struct rte_eth_dev *dev, uint16_t qid)
     370                 :            : {
     371                 :          0 :         struct gve_tx_queue *q = dev->data->tx_queues[qid];
     372                 :            : 
     373         [ #  # ]:          0 :         if (q == NULL)
     374                 :            :                 return;
     375                 :            : 
     376                 :            :         gve_release_txq_mbufs_dqo(q);
     377                 :          0 :         rte_free(q->pkt_ring_dqo);
     378                 :          0 :         rte_memzone_free(q->mz);
     379                 :          0 :         rte_memzone_free(q->compl_ring_mz);
     380                 :          0 :         rte_memzone_free(q->qres_mz);
     381                 :          0 :         q->qres = NULL;
     382                 :          0 :         rte_free(q);
     383                 :            : }
     384                 :            : 
     385                 :            : static int
     386                 :          0 : check_tx_thresh_dqo(uint16_t nb_desc, uint16_t tx_rs_thresh,
     387                 :            :                     uint16_t tx_free_thresh)
     388                 :            : {
     389         [ #  # ]:          0 :         if (tx_rs_thresh >= (nb_desc - 2)) {
     390                 :          0 :                 PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be less than the "
     391                 :            :                             "number of TX descriptors (%u) minus 2",
     392                 :            :                             tx_rs_thresh, nb_desc);
     393                 :          0 :                 return -EINVAL;
     394                 :            :         }
     395         [ #  # ]:          0 :         if (tx_free_thresh >= (nb_desc - 3)) {
     396                 :          0 :                 PMD_DRV_LOG(ERR, "tx_free_thresh (%u) must be less than the "
     397                 :            :                             "number of TX descriptors (%u) minus 3.",
     398                 :            :                             tx_free_thresh, nb_desc);
     399                 :          0 :                 return -EINVAL;
     400                 :            :         }
     401         [ #  # ]:          0 :         if (tx_rs_thresh > tx_free_thresh) {
     402                 :          0 :                 PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be less than or "
     403                 :            :                             "equal to tx_free_thresh (%u).",
     404                 :            :                             tx_rs_thresh, tx_free_thresh);
     405                 :          0 :                 return -EINVAL;
     406                 :            :         }
     407         [ #  # ]:          0 :         if ((nb_desc % tx_rs_thresh) != 0) {
     408                 :          0 :                 PMD_DRV_LOG(ERR, "tx_rs_thresh (%u) must be a divisor of the "
     409                 :            :                             "number of TX descriptors (%u).",
     410                 :            :                             tx_rs_thresh, nb_desc);
     411                 :          0 :                 return -EINVAL;
     412                 :            :         }
     413                 :            : 
     414                 :            :         return 0;
     415                 :            : }
     416                 :            : 
     417                 :            : static void
     418                 :          0 : gve_reset_tx_ring_state_dqo(struct gve_tx_queue *txq)
     419                 :            : {
     420                 :            :         struct gve_tx_pkt *pkt_ring_dqo;
     421                 :            :         uint32_t size, i;
     422                 :            : 
     423         [ #  # ]:          0 :         if (txq == NULL) {
     424                 :          0 :                 PMD_DRV_LOG(ERR, "Pointer to txq is NULL");
     425                 :          0 :                 return;
     426                 :            :         }
     427                 :            : 
     428                 :          0 :         size = txq->nb_tx_desc * sizeof(union gve_tx_desc_dqo);
     429         [ #  # ]:          0 :         for (i = 0; i < size; i++)
     430                 :          0 :                 ((volatile char *)txq->tx_ring)[i] = 0;
     431                 :            : 
     432                 :          0 :         size = txq->nb_complq_desc * sizeof(struct gve_tx_compl_desc);
     433         [ #  # ]:          0 :         for (i = 0; i < size; i++)
     434                 :          0 :                 ((volatile char *)txq->compl_ring)[i] = 0;
     435                 :            : 
     436                 :          0 :         pkt_ring_dqo = txq->pkt_ring_dqo;
     437         [ #  # ]:          0 :         for (i = 0; i < txq->sw_size; i++)
     438                 :          0 :                 pkt_ring_dqo[i].mbuf = NULL;
     439                 :            : 
     440                 :            :         gve_free_compl_tags_init(txq);
     441                 :            : 
     442                 :          0 :         txq->tx_tail = 0;
     443                 :          0 :         txq->nb_used = 0;
     444                 :            : 
     445                 :          0 :         txq->last_desc_cleaned = 0;
     446                 :          0 :         txq->nb_free = txq->nb_tx_desc - 1;
     447                 :            : 
     448                 :          0 :         txq->complq_tail = 0;
     449                 :          0 :         txq->cur_gen_bit = 1;
     450                 :            : }
     451                 :            : 
     452                 :            : int
     453                 :          0 : gve_tx_queue_setup_dqo(struct rte_eth_dev *dev, uint16_t queue_id,
     454                 :            :                        uint16_t nb_desc, unsigned int socket_id,
     455                 :            :                        const struct rte_eth_txconf *conf)
     456                 :            : {
     457                 :          0 :         struct gve_priv *hw = dev->data->dev_private;
     458                 :            :         const struct rte_memzone *mz;
     459                 :            :         struct gve_tx_queue *txq;
     460                 :            :         uint16_t free_thresh;
     461                 :            :         uint16_t rs_thresh;
     462                 :            :         uint16_t sw_size;
     463                 :            :         int err = 0;
     464                 :            : 
     465                 :            :         /* Free memory if needed. */
     466         [ #  # ]:          0 :         if (dev->data->tx_queues[queue_id]) {
     467                 :          0 :                 gve_tx_queue_release_dqo(dev, queue_id);
     468                 :          0 :                 dev->data->tx_queues[queue_id] = NULL;
     469                 :            :         }
     470                 :            : 
     471                 :            :         /* Allocate the TX queue data structure. */
     472                 :          0 :         txq = rte_zmalloc_socket("gve txq",
     473                 :            :                                  sizeof(struct gve_tx_queue),
     474                 :            :                                  RTE_CACHE_LINE_SIZE, socket_id);
     475         [ #  # ]:          0 :         if (txq == NULL) {
     476                 :          0 :                 PMD_DRV_LOG(ERR, "Failed to allocate memory for tx queue structure");
     477                 :          0 :                 return -ENOMEM;
     478                 :            :         }
     479                 :            : 
     480                 :            :         /* need to check free_thresh here */
     481         [ #  # ]:          0 :         free_thresh = conf->tx_free_thresh ?
     482                 :            :                         conf->tx_free_thresh : GVE_DEFAULT_TX_FREE_THRESH;
     483         [ #  # ]:          0 :         rs_thresh = conf->tx_rs_thresh ?
     484                 :            :                         conf->tx_rs_thresh : GVE_DEFAULT_TX_RS_THRESH;
     485         [ #  # ]:          0 :         if (check_tx_thresh_dqo(nb_desc, rs_thresh, free_thresh))
     486                 :            :                 return -EINVAL;
     487                 :            : 
     488                 :          0 :         txq->nb_tx_desc = nb_desc;
     489                 :          0 :         txq->nb_complq_desc = nb_desc * DQO_TX_MULTIPLIER;
     490                 :          0 :         txq->free_thresh = free_thresh;
     491                 :          0 :         txq->rs_thresh = rs_thresh;
     492                 :          0 :         txq->queue_id = queue_id;
     493                 :          0 :         txq->port_id = dev->data->port_id;
     494                 :          0 :         txq->ntfy_id = queue_id;
     495                 :          0 :         txq->hw = hw;
     496         [ #  # ]:          0 :         txq->ntfy_addr = &hw->db_bar2[rte_be_to_cpu_32(hw->irq_dbs[txq->ntfy_id].id)];
     497                 :            : 
     498                 :            :         /* Allocate software ring */
     499                 :            :         sw_size = nb_desc;
     500                 :          0 :         txq->pkt_ring_dqo = rte_zmalloc_socket("gve tx sw ring",
     501                 :            :                                           sw_size * sizeof(struct gve_tx_pkt),
     502                 :            :                                           RTE_CACHE_LINE_SIZE, socket_id);
     503         [ #  # ]:          0 :         if (txq->pkt_ring_dqo == NULL) {
     504                 :          0 :                 PMD_DRV_LOG(ERR, "Failed to allocate memory for SW TX ring");
     505                 :            :                 err = -ENOMEM;
     506                 :          0 :                 goto free_txq;
     507                 :            :         }
     508                 :          0 :         txq->sw_size = sw_size;
     509                 :            : 
     510                 :            :         /* Allocate TX hardware ring descriptors. */
     511                 :          0 :         mz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_id,
     512                 :            :                                       nb_desc * sizeof(union gve_tx_desc_dqo),
     513                 :            :                                       PAGE_SIZE, socket_id);
     514         [ #  # ]:          0 :         if (mz == NULL) {
     515                 :          0 :                 PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX");
     516                 :            :                 err = -ENOMEM;
     517                 :          0 :                 goto free_txq_pkt_ring;
     518                 :            :         }
     519                 :          0 :         txq->tx_ring = (union gve_tx_desc_dqo *)mz->addr;
     520                 :          0 :         txq->tx_ring_phys_addr = mz->iova;
     521                 :          0 :         txq->mz = mz;
     522                 :            : 
     523                 :            :         /* Allocate TX completion ring descriptors. */
     524                 :          0 :         mz = rte_eth_dma_zone_reserve(dev, "tx_compl_ring", queue_id,
     525                 :          0 :                                        txq->nb_complq_desc * sizeof(struct gve_tx_compl_desc),
     526                 :            :                                       PAGE_SIZE, socket_id);
     527         [ #  # ]:          0 :         if (mz == NULL) {
     528                 :          0 :                 PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX completion queue");
     529                 :            :                 err = -ENOMEM;
     530                 :          0 :                 goto free_txq_mz;
     531                 :            :         }
     532                 :          0 :         txq->compl_ring = (struct gve_tx_compl_desc *)mz->addr;
     533                 :          0 :         txq->compl_ring_phys_addr = mz->iova;
     534                 :          0 :         txq->compl_ring_mz = mz;
     535                 :          0 :         txq->txqs = dev->data->tx_queues;
     536                 :            : 
     537                 :          0 :         mz = rte_eth_dma_zone_reserve(dev, "txq_res", queue_id,
     538                 :            :                                       sizeof(struct gve_queue_resources),
     539                 :            :                                       PAGE_SIZE, socket_id);
     540         [ #  # ]:          0 :         if (mz == NULL) {
     541                 :          0 :                 PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX resource");
     542                 :            :                 err = -ENOMEM;
     543                 :          0 :                 goto free_txq_cq_mz;
     544                 :            :         }
     545                 :          0 :         txq->qres = (struct gve_queue_resources *)mz->addr;
     546                 :          0 :         txq->qres_mz = mz;
     547                 :            : 
     548                 :          0 :         gve_reset_tx_ring_state_dqo(txq);
     549                 :            : 
     550                 :          0 :         dev->data->tx_queues[queue_id] = txq;
     551                 :            : 
     552                 :          0 :         return 0;
     553                 :            : 
     554                 :            : free_txq_cq_mz:
     555                 :          0 :         rte_memzone_free(txq->compl_ring_mz);
     556                 :          0 : free_txq_mz:
     557                 :          0 :         rte_memzone_free(txq->mz);
     558                 :          0 : free_txq_pkt_ring:
     559                 :          0 :         rte_free(txq->pkt_ring_dqo);
     560                 :          0 : free_txq:
     561                 :          0 :         rte_free(txq);
     562                 :          0 :         return err;
     563                 :            : }
     564                 :            : 
     565                 :            : int
     566                 :          0 : gve_tx_queue_start_dqo(struct rte_eth_dev *dev, uint16_t tx_queue_id)
     567                 :            : {
     568                 :          0 :         struct gve_priv *hw = dev->data->dev_private;
     569                 :            :         struct gve_tx_queue *txq;
     570                 :            : 
     571         [ #  # ]:          0 :         if (tx_queue_id >= dev->data->nb_tx_queues)
     572                 :            :                 return -EINVAL;
     573                 :            : 
     574                 :          0 :         txq = dev->data->tx_queues[tx_queue_id];
     575                 :            : 
     576         [ #  # ]:          0 :         txq->qtx_tail = &hw->db_bar2[rte_be_to_cpu_32(txq->qres->db_index)];
     577                 :          0 :         txq->qtx_head =
     578         [ #  # ]:          0 :                 &hw->cnt_array[rte_be_to_cpu_32(txq->qres->counter_index)];
     579                 :            : 
     580                 :            :         rte_write32(rte_cpu_to_le_32(GVE_NO_INT_MODE_DQO |
     581                 :            :                                      GVE_ITR_NO_UPDATE_DQO),
     582                 :          0 :                     txq->ntfy_addr);
     583                 :            : 
     584                 :          0 :         dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
     585                 :            : 
     586                 :          0 :         return 0;
     587                 :            : }
     588                 :            : 
     589                 :            : int
     590                 :          0 : gve_tx_queue_stop_dqo(struct rte_eth_dev *dev, uint16_t tx_queue_id)
     591                 :            : {
     592                 :            :         struct gve_tx_queue *txq;
     593                 :            : 
     594         [ #  # ]:          0 :         if (tx_queue_id >= dev->data->nb_tx_queues)
     595                 :            :                 return -EINVAL;
     596                 :            : 
     597                 :          0 :         txq = dev->data->tx_queues[tx_queue_id];
     598                 :            :         gve_release_txq_mbufs_dqo(txq);
     599                 :          0 :         gve_reset_tx_ring_state_dqo(txq);
     600                 :            : 
     601                 :          0 :         dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
     602                 :            : 
     603                 :          0 :         return 0;
     604                 :            : }
     605                 :            : 
     606                 :            : void
     607                 :          0 : gve_stop_tx_queues_dqo(struct rte_eth_dev *dev)
     608                 :            : {
     609                 :          0 :         struct gve_priv *hw = dev->data->dev_private;
     610                 :            :         uint16_t i;
     611                 :            :         int err;
     612                 :            : 
     613                 :          0 :         err = gve_adminq_destroy_tx_queues(hw, dev->data->nb_tx_queues);
     614         [ #  # ]:          0 :         if (err != 0)
     615                 :          0 :                 PMD_DRV_LOG(WARNING, "failed to destroy txqs");
     616                 :            : 
     617         [ #  # ]:          0 :         for (i = 0; i < dev->data->nb_tx_queues; i++)
     618         [ #  # ]:          0 :                 if (gve_tx_queue_stop_dqo(dev, i) != 0)
     619                 :          0 :                         PMD_DRV_LOG(WARNING, "Fail to stop Tx queue %d", i);
     620                 :          0 : }
     621                 :            : 
     622                 :            : void
     623                 :          0 : gve_set_tx_function_dqo(struct rte_eth_dev *dev)
     624                 :            : {
     625                 :          0 :         dev->tx_pkt_burst = gve_tx_burst_dqo;
     626                 :          0 : }

Generated by: LCOV version 1.14