14bec2d0bSJunfeng Guo /* SPDX-License-Identifier: BSD-3-Clause 24bec2d0bSJunfeng Guo * Copyright(C) 2022 Intel Corporation 34bec2d0bSJunfeng Guo */ 44bec2d0bSJunfeng Guo 54bec2d0bSJunfeng Guo #include "gve_ethdev.h" 64bec2d0bSJunfeng Guo #include "base/gve_adminq.h" 74bec2d0bSJunfeng Guo 84bec2d0bSJunfeng Guo static inline void 9a46583cfSJunfeng Guo gve_free_bulk_mbuf(struct rte_mbuf **txep, int num) 10a46583cfSJunfeng Guo { 11a46583cfSJunfeng Guo struct rte_mbuf *m, *free[GVE_TX_MAX_FREE_SZ]; 12a46583cfSJunfeng Guo int nb_free = 0; 13a46583cfSJunfeng Guo int i, s; 14a46583cfSJunfeng Guo 15a46583cfSJunfeng Guo if (unlikely(num == 0)) 16a46583cfSJunfeng Guo return; 17a46583cfSJunfeng Guo 18a46583cfSJunfeng Guo /* Find the 1st mbuf which needs to be free */ 19a46583cfSJunfeng Guo for (s = 0; s < num; s++) { 20a46583cfSJunfeng Guo if (txep[s] != NULL) { 21a46583cfSJunfeng Guo m = rte_pktmbuf_prefree_seg(txep[s]); 22a46583cfSJunfeng Guo if (m != NULL) 23a46583cfSJunfeng Guo break; 24a46583cfSJunfeng Guo } 25a46583cfSJunfeng Guo } 26a46583cfSJunfeng Guo 27a46583cfSJunfeng Guo if (s == num) 28a46583cfSJunfeng Guo return; 29a46583cfSJunfeng Guo 30a46583cfSJunfeng Guo free[0] = m; 31a46583cfSJunfeng Guo nb_free = 1; 32a46583cfSJunfeng Guo for (i = s + 1; i < num; i++) { 33a46583cfSJunfeng Guo if (likely(txep[i] != NULL)) { 34a46583cfSJunfeng Guo m = rte_pktmbuf_prefree_seg(txep[i]); 35a46583cfSJunfeng Guo if (likely(m != NULL)) { 36a46583cfSJunfeng Guo if (likely(m->pool == free[0]->pool)) { 37a46583cfSJunfeng Guo free[nb_free++] = m; 38a46583cfSJunfeng Guo } else { 39a46583cfSJunfeng Guo rte_mempool_put_bulk(free[0]->pool, (void *)free, nb_free); 40a46583cfSJunfeng Guo free[0] = m; 41a46583cfSJunfeng Guo nb_free = 1; 42a46583cfSJunfeng Guo } 43a46583cfSJunfeng Guo } 44a46583cfSJunfeng Guo txep[i] = NULL; 45a46583cfSJunfeng Guo } 46a46583cfSJunfeng Guo } 47a46583cfSJunfeng Guo rte_mempool_put_bulk(free[0]->pool, (void **)free, nb_free); 48a46583cfSJunfeng Guo } 49a46583cfSJunfeng Guo 50a46583cfSJunfeng Guo static inline void 51a46583cfSJunfeng Guo gve_tx_clean(struct gve_tx_queue *txq) 52a46583cfSJunfeng Guo { 53a46583cfSJunfeng Guo uint16_t mask = txq->nb_tx_desc - 1; 54a46583cfSJunfeng Guo uint32_t start = txq->next_to_clean & mask; 55a46583cfSJunfeng Guo uint32_t ntc, nb_clean, i; 56a46583cfSJunfeng Guo struct gve_tx_iovec *iov; 57a46583cfSJunfeng Guo 58a46583cfSJunfeng Guo ntc = rte_be_to_cpu_32(rte_read32(txq->qtx_head)); 59a46583cfSJunfeng Guo ntc = ntc & mask; 60a46583cfSJunfeng Guo 61a46583cfSJunfeng Guo if (ntc == start) 62a46583cfSJunfeng Guo return; 63a46583cfSJunfeng Guo 64a46583cfSJunfeng Guo /* if wrap around, free twice. */ 65a46583cfSJunfeng Guo if (ntc < start) { 66a46583cfSJunfeng Guo nb_clean = txq->nb_tx_desc - start; 67a46583cfSJunfeng Guo if (nb_clean > GVE_TX_MAX_FREE_SZ) 68a46583cfSJunfeng Guo nb_clean = GVE_TX_MAX_FREE_SZ; 69a46583cfSJunfeng Guo if (txq->is_gqi_qpl) { 70a46583cfSJunfeng Guo for (i = start; i < start + nb_clean; i++) { 71a46583cfSJunfeng Guo iov = &txq->iov_ring[i]; 72a46583cfSJunfeng Guo txq->fifo_avail += iov->iov_len; 73a46583cfSJunfeng Guo iov->iov_base = 0; 74a46583cfSJunfeng Guo iov->iov_len = 0; 75a46583cfSJunfeng Guo } 76a46583cfSJunfeng Guo } else { 77a46583cfSJunfeng Guo gve_free_bulk_mbuf(&txq->sw_ring[start], nb_clean); 78a46583cfSJunfeng Guo } 79a46583cfSJunfeng Guo txq->nb_free += nb_clean; 80a46583cfSJunfeng Guo start += nb_clean; 81a46583cfSJunfeng Guo if (start == txq->nb_tx_desc) 82a46583cfSJunfeng Guo start = 0; 83a46583cfSJunfeng Guo txq->next_to_clean += nb_clean; 84a46583cfSJunfeng Guo } 85a46583cfSJunfeng Guo 86a46583cfSJunfeng Guo if (ntc > start) { 87a46583cfSJunfeng Guo nb_clean = ntc - start; 88a46583cfSJunfeng Guo if (nb_clean > GVE_TX_MAX_FREE_SZ) 89a46583cfSJunfeng Guo nb_clean = GVE_TX_MAX_FREE_SZ; 90a46583cfSJunfeng Guo if (txq->is_gqi_qpl) { 91a46583cfSJunfeng Guo for (i = start; i < start + nb_clean; i++) { 92a46583cfSJunfeng Guo iov = &txq->iov_ring[i]; 93a46583cfSJunfeng Guo txq->fifo_avail += iov->iov_len; 94a46583cfSJunfeng Guo iov->iov_base = 0; 95a46583cfSJunfeng Guo iov->iov_len = 0; 96a46583cfSJunfeng Guo } 97a46583cfSJunfeng Guo } else { 98a46583cfSJunfeng Guo gve_free_bulk_mbuf(&txq->sw_ring[start], nb_clean); 99a46583cfSJunfeng Guo } 100a46583cfSJunfeng Guo txq->nb_free += nb_clean; 101a46583cfSJunfeng Guo txq->next_to_clean += nb_clean; 102a46583cfSJunfeng Guo } 103a46583cfSJunfeng Guo } 104a46583cfSJunfeng Guo 105a46583cfSJunfeng Guo static inline void 106a46583cfSJunfeng Guo gve_tx_clean_swr_qpl(struct gve_tx_queue *txq) 107a46583cfSJunfeng Guo { 108a46583cfSJunfeng Guo uint32_t start = txq->sw_ntc; 109a46583cfSJunfeng Guo uint32_t ntc, nb_clean; 110a46583cfSJunfeng Guo 111a46583cfSJunfeng Guo ntc = txq->sw_tail; 112a46583cfSJunfeng Guo 113a46583cfSJunfeng Guo if (ntc == start) 114a46583cfSJunfeng Guo return; 115a46583cfSJunfeng Guo 116a46583cfSJunfeng Guo /* if wrap around, free twice. */ 117a46583cfSJunfeng Guo if (ntc < start) { 118a46583cfSJunfeng Guo nb_clean = txq->nb_tx_desc - start; 119a46583cfSJunfeng Guo if (nb_clean > GVE_TX_MAX_FREE_SZ) 120a46583cfSJunfeng Guo nb_clean = GVE_TX_MAX_FREE_SZ; 121a46583cfSJunfeng Guo gve_free_bulk_mbuf(&txq->sw_ring[start], nb_clean); 122a46583cfSJunfeng Guo 123a46583cfSJunfeng Guo txq->sw_nb_free += nb_clean; 124a46583cfSJunfeng Guo start += nb_clean; 125a46583cfSJunfeng Guo if (start == txq->nb_tx_desc) 126a46583cfSJunfeng Guo start = 0; 127a46583cfSJunfeng Guo txq->sw_ntc = start; 128a46583cfSJunfeng Guo } 129a46583cfSJunfeng Guo 130a46583cfSJunfeng Guo if (ntc > start) { 131a46583cfSJunfeng Guo nb_clean = ntc - start; 132a46583cfSJunfeng Guo if (nb_clean > GVE_TX_MAX_FREE_SZ) 133a46583cfSJunfeng Guo nb_clean = GVE_TX_MAX_FREE_SZ; 134a46583cfSJunfeng Guo gve_free_bulk_mbuf(&txq->sw_ring[start], nb_clean); 135a46583cfSJunfeng Guo txq->sw_nb_free += nb_clean; 136a46583cfSJunfeng Guo start += nb_clean; 137a46583cfSJunfeng Guo txq->sw_ntc = start; 138a46583cfSJunfeng Guo } 139a46583cfSJunfeng Guo } 140a46583cfSJunfeng Guo 141a46583cfSJunfeng Guo static inline void 142a46583cfSJunfeng Guo gve_tx_fill_pkt_desc(volatile union gve_tx_desc *desc, struct rte_mbuf *mbuf, 143a46583cfSJunfeng Guo uint8_t desc_cnt, uint16_t len, uint64_t addr) 144a46583cfSJunfeng Guo { 145a46583cfSJunfeng Guo uint64_t csum_l4 = mbuf->ol_flags & RTE_MBUF_F_TX_L4_MASK; 146a46583cfSJunfeng Guo uint8_t l4_csum_offset = 0; 147a46583cfSJunfeng Guo uint8_t l4_hdr_offset = 0; 148a46583cfSJunfeng Guo 149a46583cfSJunfeng Guo if (mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG) 150a46583cfSJunfeng Guo csum_l4 |= RTE_MBUF_F_TX_TCP_CKSUM; 151a46583cfSJunfeng Guo 152a46583cfSJunfeng Guo switch (csum_l4) { 153a46583cfSJunfeng Guo case RTE_MBUF_F_TX_TCP_CKSUM: 154a46583cfSJunfeng Guo l4_csum_offset = offsetof(struct rte_tcp_hdr, cksum); 155a46583cfSJunfeng Guo l4_hdr_offset = mbuf->l2_len + mbuf->l3_len; 156a46583cfSJunfeng Guo break; 157a46583cfSJunfeng Guo case RTE_MBUF_F_TX_UDP_CKSUM: 158a46583cfSJunfeng Guo l4_csum_offset = offsetof(struct rte_udp_hdr, dgram_cksum); 159a46583cfSJunfeng Guo l4_hdr_offset = mbuf->l2_len + mbuf->l3_len; 160a46583cfSJunfeng Guo break; 161a46583cfSJunfeng Guo case RTE_MBUF_F_TX_SCTP_CKSUM: 162a46583cfSJunfeng Guo l4_csum_offset = offsetof(struct rte_sctp_hdr, cksum); 163a46583cfSJunfeng Guo l4_hdr_offset = mbuf->l2_len + mbuf->l3_len; 164a46583cfSJunfeng Guo break; 165a46583cfSJunfeng Guo } 166a46583cfSJunfeng Guo 167a46583cfSJunfeng Guo if (mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG) { 168a46583cfSJunfeng Guo desc->pkt.type_flags = GVE_TXD_TSO | GVE_TXF_L4CSUM; 169a46583cfSJunfeng Guo desc->pkt.l4_csum_offset = l4_csum_offset >> 1; 170a46583cfSJunfeng Guo desc->pkt.l4_hdr_offset = l4_hdr_offset >> 1; 171a46583cfSJunfeng Guo } else if (mbuf->ol_flags & RTE_MBUF_F_TX_L4_MASK) { 172a46583cfSJunfeng Guo desc->pkt.type_flags = GVE_TXD_STD | GVE_TXF_L4CSUM; 173a46583cfSJunfeng Guo desc->pkt.l4_csum_offset = l4_csum_offset >> 1; 174a46583cfSJunfeng Guo desc->pkt.l4_hdr_offset = l4_hdr_offset >> 1; 175a46583cfSJunfeng Guo } else { 176a46583cfSJunfeng Guo desc->pkt.type_flags = GVE_TXD_STD; 177a46583cfSJunfeng Guo desc->pkt.l4_csum_offset = 0; 178a46583cfSJunfeng Guo desc->pkt.l4_hdr_offset = 0; 179a46583cfSJunfeng Guo } 180a46583cfSJunfeng Guo desc->pkt.desc_cnt = desc_cnt; 181a46583cfSJunfeng Guo desc->pkt.len = rte_cpu_to_be_16(mbuf->pkt_len); 182a46583cfSJunfeng Guo desc->pkt.seg_len = rte_cpu_to_be_16(len); 183a46583cfSJunfeng Guo desc->pkt.seg_addr = rte_cpu_to_be_64(addr); 184a46583cfSJunfeng Guo } 185a46583cfSJunfeng Guo 186a46583cfSJunfeng Guo static inline void 187a46583cfSJunfeng Guo gve_tx_fill_seg_desc(volatile union gve_tx_desc *desc, uint64_t ol_flags, 188a46583cfSJunfeng Guo union gve_tx_offload tx_offload, 189a46583cfSJunfeng Guo uint16_t len, uint64_t addr) 190a46583cfSJunfeng Guo { 191a46583cfSJunfeng Guo desc->seg.type_flags = GVE_TXD_SEG; 192a46583cfSJunfeng Guo if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { 193a46583cfSJunfeng Guo if (ol_flags & RTE_MBUF_F_TX_IPV6) 194a46583cfSJunfeng Guo desc->seg.type_flags |= GVE_TXSF_IPV6; 195a46583cfSJunfeng Guo desc->seg.l3_offset = tx_offload.l2_len >> 1; 196a46583cfSJunfeng Guo desc->seg.mss = rte_cpu_to_be_16(tx_offload.tso_segsz); 197a46583cfSJunfeng Guo } 198a46583cfSJunfeng Guo desc->seg.seg_len = rte_cpu_to_be_16(len); 199a46583cfSJunfeng Guo desc->seg.seg_addr = rte_cpu_to_be_64(addr); 200a46583cfSJunfeng Guo } 201a46583cfSJunfeng Guo 202a46583cfSJunfeng Guo static inline bool 203a46583cfSJunfeng Guo is_fifo_avail(struct gve_tx_queue *txq, uint16_t len) 204a46583cfSJunfeng Guo { 205a46583cfSJunfeng Guo if (txq->fifo_avail < len) 206a46583cfSJunfeng Guo return false; 207a46583cfSJunfeng Guo /* Don't split segment. */ 208a46583cfSJunfeng Guo if (txq->fifo_head + len > txq->fifo_size && 209a46583cfSJunfeng Guo txq->fifo_size - txq->fifo_head + len > txq->fifo_avail) 210a46583cfSJunfeng Guo return false; 211a46583cfSJunfeng Guo return true; 212a46583cfSJunfeng Guo } 213a46583cfSJunfeng Guo static inline uint64_t 214a46583cfSJunfeng Guo gve_tx_alloc_from_fifo(struct gve_tx_queue *txq, uint16_t tx_id, uint16_t len) 215a46583cfSJunfeng Guo { 216a46583cfSJunfeng Guo uint32_t head = txq->fifo_head; 217a46583cfSJunfeng Guo uint32_t size = txq->fifo_size; 218a46583cfSJunfeng Guo struct gve_tx_iovec *iov; 219a46583cfSJunfeng Guo uint32_t aligned_head; 220a46583cfSJunfeng Guo uint32_t iov_len = 0; 221a46583cfSJunfeng Guo uint64_t fifo_addr; 222a46583cfSJunfeng Guo 223a46583cfSJunfeng Guo iov = &txq->iov_ring[tx_id]; 224a46583cfSJunfeng Guo 225a46583cfSJunfeng Guo /* Don't split segment */ 226a46583cfSJunfeng Guo if (head + len > size) { 227a46583cfSJunfeng Guo iov_len += (size - head); 228a46583cfSJunfeng Guo head = 0; 229a46583cfSJunfeng Guo } 230a46583cfSJunfeng Guo 231a46583cfSJunfeng Guo fifo_addr = head; 232a46583cfSJunfeng Guo iov_len += len; 233a46583cfSJunfeng Guo iov->iov_base = head; 234a46583cfSJunfeng Guo 235a46583cfSJunfeng Guo /* Re-align to a cacheline for next head */ 236a46583cfSJunfeng Guo head += len; 237a46583cfSJunfeng Guo aligned_head = RTE_ALIGN(head, RTE_CACHE_LINE_SIZE); 238a46583cfSJunfeng Guo iov_len += (aligned_head - head); 239a46583cfSJunfeng Guo iov->iov_len = iov_len; 240a46583cfSJunfeng Guo 241a46583cfSJunfeng Guo if (aligned_head == txq->fifo_size) 242a46583cfSJunfeng Guo aligned_head = 0; 243a46583cfSJunfeng Guo txq->fifo_head = aligned_head; 244a46583cfSJunfeng Guo txq->fifo_avail -= iov_len; 245a46583cfSJunfeng Guo 246a46583cfSJunfeng Guo return fifo_addr; 247a46583cfSJunfeng Guo } 248a46583cfSJunfeng Guo 249a46583cfSJunfeng Guo static inline uint16_t 250a46583cfSJunfeng Guo gve_tx_burst_qpl(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) 251a46583cfSJunfeng Guo { 252a46583cfSJunfeng Guo union gve_tx_offload tx_offload = {0}; 253a46583cfSJunfeng Guo volatile union gve_tx_desc *txr, *txd; 254a46583cfSJunfeng Guo struct gve_tx_queue *txq = tx_queue; 255a46583cfSJunfeng Guo struct rte_mbuf **sw_ring = txq->sw_ring; 256a46583cfSJunfeng Guo uint16_t mask = txq->nb_tx_desc - 1; 257a46583cfSJunfeng Guo uint16_t tx_id = txq->tx_tail & mask; 258a46583cfSJunfeng Guo uint64_t ol_flags, addr, fifo_addr; 259a46583cfSJunfeng Guo uint32_t tx_tail = txq->tx_tail; 260a46583cfSJunfeng Guo struct rte_mbuf *tx_pkt, *first; 261a46583cfSJunfeng Guo uint16_t sw_id = txq->sw_tail; 262a46583cfSJunfeng Guo uint16_t nb_used, i; 2634f6b1dd8SJunfeng Guo uint64_t bytes = 0; 264a46583cfSJunfeng Guo uint16_t nb_tx = 0; 265a46583cfSJunfeng Guo uint32_t hlen; 266a46583cfSJunfeng Guo 267a46583cfSJunfeng Guo txr = txq->tx_desc_ring; 268a46583cfSJunfeng Guo 269a46583cfSJunfeng Guo if (txq->nb_free < txq->free_thresh || txq->fifo_avail == 0) 270a46583cfSJunfeng Guo gve_tx_clean(txq); 271a46583cfSJunfeng Guo 272a46583cfSJunfeng Guo if (txq->sw_nb_free < txq->free_thresh) 273a46583cfSJunfeng Guo gve_tx_clean_swr_qpl(txq); 274a46583cfSJunfeng Guo 275a46583cfSJunfeng Guo for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) { 276a46583cfSJunfeng Guo tx_pkt = *tx_pkts++; 277a46583cfSJunfeng Guo ol_flags = tx_pkt->ol_flags; 278a46583cfSJunfeng Guo 279a46583cfSJunfeng Guo if (txq->sw_nb_free < tx_pkt->nb_segs) { 280a46583cfSJunfeng Guo gve_tx_clean_swr_qpl(txq); 281a46583cfSJunfeng Guo if (txq->sw_nb_free < tx_pkt->nb_segs) 282a46583cfSJunfeng Guo goto end_of_tx; 283a46583cfSJunfeng Guo } 284a46583cfSJunfeng Guo 285a46583cfSJunfeng Guo /* Even for multi-segs, use 1 qpl buf for data */ 286a46583cfSJunfeng Guo nb_used = 1; 287a46583cfSJunfeng Guo if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) 288a46583cfSJunfeng Guo nb_used++; 289a46583cfSJunfeng Guo 290a46583cfSJunfeng Guo if (txq->nb_free < nb_used) 291a46583cfSJunfeng Guo goto end_of_tx; 292a46583cfSJunfeng Guo 293a46583cfSJunfeng Guo tx_offload.l2_len = tx_pkt->l2_len; 294a46583cfSJunfeng Guo tx_offload.l3_len = tx_pkt->l3_len; 295a46583cfSJunfeng Guo tx_offload.l4_len = tx_pkt->l4_len; 296a46583cfSJunfeng Guo tx_offload.tso_segsz = tx_pkt->tso_segsz; 297a46583cfSJunfeng Guo 298a46583cfSJunfeng Guo first = tx_pkt; 299a46583cfSJunfeng Guo txd = &txr[tx_id]; 300a46583cfSJunfeng Guo hlen = ol_flags & RTE_MBUF_F_TX_TCP_SEG ? 301a46583cfSJunfeng Guo (uint32_t)(tx_offload.l2_len + tx_offload.l3_len + tx_offload.l4_len) : 302a46583cfSJunfeng Guo tx_pkt->pkt_len; 303a46583cfSJunfeng Guo 304a46583cfSJunfeng Guo sw_ring[sw_id] = tx_pkt; 305a46583cfSJunfeng Guo if (!is_fifo_avail(txq, hlen)) { 306a46583cfSJunfeng Guo gve_tx_clean(txq); 307a46583cfSJunfeng Guo if (!is_fifo_avail(txq, hlen)) 308a46583cfSJunfeng Guo goto end_of_tx; 309a46583cfSJunfeng Guo } 310a46583cfSJunfeng Guo addr = (uint64_t)(tx_pkt->buf_addr) + tx_pkt->data_off; 311a46583cfSJunfeng Guo fifo_addr = gve_tx_alloc_from_fifo(txq, tx_id, hlen); 312a46583cfSJunfeng Guo 313a46583cfSJunfeng Guo /* For TSO, check if there's enough fifo space for data first */ 314a46583cfSJunfeng Guo if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { 315a46583cfSJunfeng Guo if (!is_fifo_avail(txq, tx_pkt->pkt_len - hlen)) { 316a46583cfSJunfeng Guo gve_tx_clean(txq); 317a46583cfSJunfeng Guo if (!is_fifo_avail(txq, tx_pkt->pkt_len - hlen)) 318a46583cfSJunfeng Guo goto end_of_tx; 319a46583cfSJunfeng Guo } 320a46583cfSJunfeng Guo } 321a46583cfSJunfeng Guo if (tx_pkt->nb_segs == 1 || ol_flags & RTE_MBUF_F_TX_TCP_SEG) 322a46583cfSJunfeng Guo rte_memcpy((void *)(size_t)(fifo_addr + txq->fifo_base), 323a46583cfSJunfeng Guo (void *)(size_t)addr, hlen); 324a46583cfSJunfeng Guo else 325a46583cfSJunfeng Guo rte_pktmbuf_read(tx_pkt, 0, hlen, 326a46583cfSJunfeng Guo (void *)(size_t)(fifo_addr + txq->fifo_base)); 327a46583cfSJunfeng Guo gve_tx_fill_pkt_desc(txd, tx_pkt, nb_used, hlen, fifo_addr); 328a46583cfSJunfeng Guo 329a46583cfSJunfeng Guo if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { 330a46583cfSJunfeng Guo tx_id = (tx_id + 1) & mask; 331a46583cfSJunfeng Guo txd = &txr[tx_id]; 332a46583cfSJunfeng Guo addr = (uint64_t)(tx_pkt->buf_addr) + tx_pkt->data_off + hlen; 333a46583cfSJunfeng Guo fifo_addr = gve_tx_alloc_from_fifo(txq, tx_id, tx_pkt->pkt_len - hlen); 334a46583cfSJunfeng Guo if (tx_pkt->nb_segs == 1) 335a46583cfSJunfeng Guo rte_memcpy((void *)(size_t)(fifo_addr + txq->fifo_base), 336a46583cfSJunfeng Guo (void *)(size_t)addr, 337a46583cfSJunfeng Guo tx_pkt->pkt_len - hlen); 338a46583cfSJunfeng Guo else 339a46583cfSJunfeng Guo rte_pktmbuf_read(tx_pkt, hlen, tx_pkt->pkt_len - hlen, 340a46583cfSJunfeng Guo (void *)(size_t)(fifo_addr + txq->fifo_base)); 341a46583cfSJunfeng Guo 342a46583cfSJunfeng Guo gve_tx_fill_seg_desc(txd, ol_flags, tx_offload, 343a46583cfSJunfeng Guo tx_pkt->pkt_len - hlen, fifo_addr); 344a46583cfSJunfeng Guo } 345a46583cfSJunfeng Guo 346a46583cfSJunfeng Guo /* record mbuf in sw_ring for free */ 347a46583cfSJunfeng Guo for (i = 1; i < first->nb_segs; i++) { 348a46583cfSJunfeng Guo sw_id = (sw_id + 1) & mask; 349a46583cfSJunfeng Guo tx_pkt = tx_pkt->next; 350a46583cfSJunfeng Guo sw_ring[sw_id] = tx_pkt; 351a46583cfSJunfeng Guo } 352a46583cfSJunfeng Guo 353a46583cfSJunfeng Guo sw_id = (sw_id + 1) & mask; 354a46583cfSJunfeng Guo tx_id = (tx_id + 1) & mask; 355a46583cfSJunfeng Guo 356a46583cfSJunfeng Guo txq->nb_free -= nb_used; 357a46583cfSJunfeng Guo txq->sw_nb_free -= first->nb_segs; 358a46583cfSJunfeng Guo tx_tail += nb_used; 3594f6b1dd8SJunfeng Guo 3604f6b1dd8SJunfeng Guo bytes += first->pkt_len; 361a46583cfSJunfeng Guo } 362a46583cfSJunfeng Guo 363a46583cfSJunfeng Guo end_of_tx: 364a46583cfSJunfeng Guo if (nb_tx) { 365a46583cfSJunfeng Guo rte_write32(rte_cpu_to_be_32(tx_tail), txq->qtx_tail); 366a46583cfSJunfeng Guo txq->tx_tail = tx_tail; 367a46583cfSJunfeng Guo txq->sw_tail = sw_id; 3684f6b1dd8SJunfeng Guo 369c222ea9cSLevend Sayar txq->stats.packets += nb_tx; 370c222ea9cSLevend Sayar txq->stats.bytes += bytes; 371c222ea9cSLevend Sayar txq->stats.errors += nb_pkts - nb_tx; 372a46583cfSJunfeng Guo } 373a46583cfSJunfeng Guo 374a46583cfSJunfeng Guo return nb_tx; 375a46583cfSJunfeng Guo } 376a46583cfSJunfeng Guo 377a46583cfSJunfeng Guo static inline uint16_t 378a46583cfSJunfeng Guo gve_tx_burst_ra(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) 379a46583cfSJunfeng Guo { 380a46583cfSJunfeng Guo union gve_tx_offload tx_offload = {0}; 381a46583cfSJunfeng Guo volatile union gve_tx_desc *txr, *txd; 382a46583cfSJunfeng Guo struct gve_tx_queue *txq = tx_queue; 383a46583cfSJunfeng Guo struct rte_mbuf **sw_ring = txq->sw_ring; 384a46583cfSJunfeng Guo uint16_t mask = txq->nb_tx_desc - 1; 385a46583cfSJunfeng Guo uint16_t tx_id = txq->tx_tail & mask; 386a46583cfSJunfeng Guo uint32_t tx_tail = txq->tx_tail; 387a46583cfSJunfeng Guo struct rte_mbuf *tx_pkt, *first; 388a46583cfSJunfeng Guo uint16_t nb_used, hlen, i; 389a46583cfSJunfeng Guo uint64_t ol_flags, addr; 3904f6b1dd8SJunfeng Guo uint64_t bytes = 0; 391a46583cfSJunfeng Guo uint16_t nb_tx = 0; 392a46583cfSJunfeng Guo 393a46583cfSJunfeng Guo txr = txq->tx_desc_ring; 394a46583cfSJunfeng Guo 395a46583cfSJunfeng Guo if (txq->nb_free < txq->free_thresh) 396a46583cfSJunfeng Guo gve_tx_clean(txq); 397a46583cfSJunfeng Guo 398a46583cfSJunfeng Guo for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) { 399a46583cfSJunfeng Guo tx_pkt = *tx_pkts++; 400a46583cfSJunfeng Guo ol_flags = tx_pkt->ol_flags; 401a46583cfSJunfeng Guo 402a46583cfSJunfeng Guo nb_used = tx_pkt->nb_segs; 403a46583cfSJunfeng Guo if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) 404a46583cfSJunfeng Guo nb_used++; 405a46583cfSJunfeng Guo 406a46583cfSJunfeng Guo if (txq->nb_free < nb_used) 407a46583cfSJunfeng Guo goto end_of_tx; 408a46583cfSJunfeng Guo 409a46583cfSJunfeng Guo tx_offload.l2_len = tx_pkt->l2_len; 410a46583cfSJunfeng Guo tx_offload.l3_len = tx_pkt->l3_len; 411a46583cfSJunfeng Guo tx_offload.l4_len = tx_pkt->l4_len; 412a46583cfSJunfeng Guo tx_offload.tso_segsz = tx_pkt->tso_segsz; 413a46583cfSJunfeng Guo 414a46583cfSJunfeng Guo first = tx_pkt; 415a46583cfSJunfeng Guo txd = &txr[tx_id]; 416a46583cfSJunfeng Guo 417a46583cfSJunfeng Guo hlen = ol_flags & RTE_MBUF_F_TX_TCP_SEG ? 418a46583cfSJunfeng Guo (uint32_t)(tx_offload.l2_len + tx_offload.l3_len + tx_offload.l4_len) : 419a46583cfSJunfeng Guo tx_pkt->pkt_len; 420a46583cfSJunfeng Guo /* 421a46583cfSJunfeng Guo * if tso, the driver needs to fill 2 descs for 1 mbuf 422a46583cfSJunfeng Guo * so only put this mbuf into the 1st tx entry in sw ring 423a46583cfSJunfeng Guo */ 424a46583cfSJunfeng Guo sw_ring[tx_id] = tx_pkt; 425a46583cfSJunfeng Guo addr = rte_mbuf_data_iova(tx_pkt); 426a46583cfSJunfeng Guo gve_tx_fill_pkt_desc(txd, tx_pkt, nb_used, hlen, addr); 427a46583cfSJunfeng Guo 428a46583cfSJunfeng Guo if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { 429a46583cfSJunfeng Guo tx_id = (tx_id + 1) & mask; 430a46583cfSJunfeng Guo txd = &txr[tx_id]; 431a46583cfSJunfeng Guo addr = rte_mbuf_data_iova(tx_pkt) + hlen; 432a46583cfSJunfeng Guo gve_tx_fill_seg_desc(txd, ol_flags, tx_offload, 433a46583cfSJunfeng Guo tx_pkt->data_len - hlen, addr); 434a46583cfSJunfeng Guo } 435a46583cfSJunfeng Guo 436a46583cfSJunfeng Guo for (i = 1; i < first->nb_segs; i++) { 437a46583cfSJunfeng Guo tx_id = (tx_id + 1) & mask; 438a46583cfSJunfeng Guo txd = &txr[tx_id]; 439a46583cfSJunfeng Guo tx_pkt = tx_pkt->next; 440a46583cfSJunfeng Guo sw_ring[tx_id] = tx_pkt; 441a46583cfSJunfeng Guo addr = rte_mbuf_data_iova(tx_pkt); 442a46583cfSJunfeng Guo gve_tx_fill_seg_desc(txd, ol_flags, tx_offload, 443a46583cfSJunfeng Guo tx_pkt->data_len, addr); 444a46583cfSJunfeng Guo } 445a46583cfSJunfeng Guo tx_id = (tx_id + 1) & mask; 446a46583cfSJunfeng Guo 447a46583cfSJunfeng Guo txq->nb_free -= nb_used; 448a46583cfSJunfeng Guo tx_tail += nb_used; 4494f6b1dd8SJunfeng Guo 4504f6b1dd8SJunfeng Guo bytes += first->pkt_len; 451a46583cfSJunfeng Guo } 452a46583cfSJunfeng Guo 453a46583cfSJunfeng Guo end_of_tx: 454a46583cfSJunfeng Guo if (nb_tx) { 455a46583cfSJunfeng Guo rte_write32(rte_cpu_to_be_32(tx_tail), txq->qtx_tail); 456a46583cfSJunfeng Guo txq->tx_tail = tx_tail; 4574f6b1dd8SJunfeng Guo 458c222ea9cSLevend Sayar txq->stats.packets += nb_tx; 459c222ea9cSLevend Sayar txq->stats.bytes += bytes; 460c222ea9cSLevend Sayar txq->stats.errors += nb_pkts - nb_tx; 461a46583cfSJunfeng Guo } 462a46583cfSJunfeng Guo 463a46583cfSJunfeng Guo return nb_tx; 464a46583cfSJunfeng Guo } 465a46583cfSJunfeng Guo 466a46583cfSJunfeng Guo uint16_t 467a46583cfSJunfeng Guo gve_tx_burst(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) 468a46583cfSJunfeng Guo { 469a46583cfSJunfeng Guo struct gve_tx_queue *txq = tx_queue; 470a46583cfSJunfeng Guo 471a46583cfSJunfeng Guo if (txq->is_gqi_qpl) 472a46583cfSJunfeng Guo return gve_tx_burst_qpl(tx_queue, tx_pkts, nb_pkts); 473a46583cfSJunfeng Guo 474a46583cfSJunfeng Guo return gve_tx_burst_ra(tx_queue, tx_pkts, nb_pkts); 475a46583cfSJunfeng Guo } 476a46583cfSJunfeng Guo 477a46583cfSJunfeng Guo static inline void 4784bec2d0bSJunfeng Guo gve_reset_txq(struct gve_tx_queue *txq) 4794bec2d0bSJunfeng Guo { 4800cfde775SJunfeng Guo struct rte_mbuf **sw_ring; 4814bec2d0bSJunfeng Guo uint32_t size, i; 4824bec2d0bSJunfeng Guo 4834bec2d0bSJunfeng Guo if (txq == NULL) { 4844bec2d0bSJunfeng Guo PMD_DRV_LOG(ERR, "Pointer to txq is NULL"); 4854bec2d0bSJunfeng Guo return; 4864bec2d0bSJunfeng Guo } 4874bec2d0bSJunfeng Guo 4884bec2d0bSJunfeng Guo size = txq->nb_tx_desc * sizeof(union gve_tx_desc); 4894bec2d0bSJunfeng Guo for (i = 0; i < size; i++) 4904bec2d0bSJunfeng Guo ((volatile char *)txq->tx_desc_ring)[i] = 0; 4914bec2d0bSJunfeng Guo 4920cfde775SJunfeng Guo sw_ring = txq->sw_ring; 4934bec2d0bSJunfeng Guo for (i = 0; i < txq->nb_tx_desc; i++) { 4944bec2d0bSJunfeng Guo sw_ring[i] = NULL; 4954bec2d0bSJunfeng Guo if (txq->is_gqi_qpl) { 4964bec2d0bSJunfeng Guo txq->iov_ring[i].iov_base = 0; 4974bec2d0bSJunfeng Guo txq->iov_ring[i].iov_len = 0; 4984bec2d0bSJunfeng Guo } 4994bec2d0bSJunfeng Guo } 5004bec2d0bSJunfeng Guo 5014bec2d0bSJunfeng Guo txq->tx_tail = 0; 5024bec2d0bSJunfeng Guo txq->nb_free = txq->nb_tx_desc - 1; 5034bec2d0bSJunfeng Guo txq->next_to_clean = 0; 5044bec2d0bSJunfeng Guo 5054bec2d0bSJunfeng Guo if (txq->is_gqi_qpl) { 5064bec2d0bSJunfeng Guo txq->fifo_size = PAGE_SIZE * txq->hw->tx_pages_per_qpl; 5074bec2d0bSJunfeng Guo txq->fifo_avail = txq->fifo_size; 5084bec2d0bSJunfeng Guo txq->fifo_head = 0; 5094bec2d0bSJunfeng Guo txq->fifo_base = (uint64_t)(txq->qpl->mz->addr); 5104bec2d0bSJunfeng Guo 5114bec2d0bSJunfeng Guo txq->sw_tail = 0; 5124bec2d0bSJunfeng Guo txq->sw_nb_free = txq->nb_tx_desc - 1; 5134bec2d0bSJunfeng Guo txq->sw_ntc = 0; 5144bec2d0bSJunfeng Guo } 5154bec2d0bSJunfeng Guo } 5164bec2d0bSJunfeng Guo 5174bec2d0bSJunfeng Guo static inline void 5184bec2d0bSJunfeng Guo gve_release_txq_mbufs(struct gve_tx_queue *txq) 5194bec2d0bSJunfeng Guo { 5204bec2d0bSJunfeng Guo uint16_t i; 5214bec2d0bSJunfeng Guo 5224bec2d0bSJunfeng Guo for (i = 0; i < txq->nb_tx_desc; i++) { 5234bec2d0bSJunfeng Guo if (txq->sw_ring[i]) { 5244bec2d0bSJunfeng Guo rte_pktmbuf_free_seg(txq->sw_ring[i]); 5254bec2d0bSJunfeng Guo txq->sw_ring[i] = NULL; 5264bec2d0bSJunfeng Guo } 5274bec2d0bSJunfeng Guo } 5284bec2d0bSJunfeng Guo } 5294bec2d0bSJunfeng Guo 5304bec2d0bSJunfeng Guo void 53110d9e91aSJunfeng Guo gve_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid) 5324bec2d0bSJunfeng Guo { 53310d9e91aSJunfeng Guo struct gve_tx_queue *q = dev->data->tx_queues[qid]; 5344bec2d0bSJunfeng Guo 5354bec2d0bSJunfeng Guo if (!q) 5364bec2d0bSJunfeng Guo return; 5374bec2d0bSJunfeng Guo 5384bec2d0bSJunfeng Guo if (q->is_gqi_qpl) { 5397f369975SJoshua Washington gve_teardown_queue_page_list(q->hw, q->qpl); 5404bec2d0bSJunfeng Guo rte_free(q->iov_ring); 5414bec2d0bSJunfeng Guo q->qpl = NULL; 5424bec2d0bSJunfeng Guo } 5434bec2d0bSJunfeng Guo 5444bec2d0bSJunfeng Guo gve_release_txq_mbufs(q); 5454bec2d0bSJunfeng Guo rte_free(q->sw_ring); 5464bec2d0bSJunfeng Guo rte_memzone_free(q->mz); 5474bec2d0bSJunfeng Guo rte_memzone_free(q->qres_mz); 5484bec2d0bSJunfeng Guo q->qres = NULL; 5494bec2d0bSJunfeng Guo rte_free(q); 5504bec2d0bSJunfeng Guo } 5514bec2d0bSJunfeng Guo 5524bec2d0bSJunfeng Guo int 5534bec2d0bSJunfeng Guo gve_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_id, uint16_t nb_desc, 5544bec2d0bSJunfeng Guo unsigned int socket_id, const struct rte_eth_txconf *conf) 5554bec2d0bSJunfeng Guo { 5564bec2d0bSJunfeng Guo struct gve_priv *hw = dev->data->dev_private; 5574bec2d0bSJunfeng Guo const struct rte_memzone *mz; 5584bec2d0bSJunfeng Guo struct gve_tx_queue *txq; 5594bec2d0bSJunfeng Guo uint16_t free_thresh; 5604bec2d0bSJunfeng Guo int err = 0; 5614bec2d0bSJunfeng Guo 562cde01d16SJoshua Washington /* Ring size is required to be a power of two. */ 563cde01d16SJoshua Washington if (!rte_is_power_of_2(nb_desc)) { 564*f665790aSDavid Marchand PMD_DRV_LOG(ERR, "Invalid ring size %u. GVE ring size must be a power of 2.", 565cde01d16SJoshua Washington nb_desc); 566cde01d16SJoshua Washington return -EINVAL; 5674bec2d0bSJunfeng Guo } 5684bec2d0bSJunfeng Guo 5694bec2d0bSJunfeng Guo /* Free memory if needed. */ 5704bec2d0bSJunfeng Guo if (dev->data->tx_queues[queue_id]) { 57110d9e91aSJunfeng Guo gve_tx_queue_release(dev, queue_id); 5724bec2d0bSJunfeng Guo dev->data->tx_queues[queue_id] = NULL; 5734bec2d0bSJunfeng Guo } 5744bec2d0bSJunfeng Guo 5754bec2d0bSJunfeng Guo /* Allocate the TX queue data structure. */ 5764bec2d0bSJunfeng Guo txq = rte_zmalloc_socket("gve txq", sizeof(struct gve_tx_queue), 5774bec2d0bSJunfeng Guo RTE_CACHE_LINE_SIZE, socket_id); 5784bec2d0bSJunfeng Guo if (!txq) { 5794bec2d0bSJunfeng Guo PMD_DRV_LOG(ERR, "Failed to allocate memory for tx queue structure"); 5804bec2d0bSJunfeng Guo err = -ENOMEM; 5814bec2d0bSJunfeng Guo goto err_txq; 5824bec2d0bSJunfeng Guo } 5834bec2d0bSJunfeng Guo 5844bec2d0bSJunfeng Guo free_thresh = conf->tx_free_thresh ? conf->tx_free_thresh : GVE_DEFAULT_TX_FREE_THRESH; 5854bec2d0bSJunfeng Guo if (free_thresh >= nb_desc - 3) { 5864bec2d0bSJunfeng Guo PMD_DRV_LOG(ERR, "tx_free_thresh (%u) must be less than nb_desc (%u) minus 3.", 5874bec2d0bSJunfeng Guo free_thresh, txq->nb_tx_desc); 5884bec2d0bSJunfeng Guo err = -EINVAL; 5894bec2d0bSJunfeng Guo goto err_txq; 5904bec2d0bSJunfeng Guo } 5914bec2d0bSJunfeng Guo 5924bec2d0bSJunfeng Guo txq->nb_tx_desc = nb_desc; 5934bec2d0bSJunfeng Guo txq->free_thresh = free_thresh; 5944bec2d0bSJunfeng Guo txq->queue_id = queue_id; 5954bec2d0bSJunfeng Guo txq->port_id = dev->data->port_id; 5964bec2d0bSJunfeng Guo txq->ntfy_id = queue_id; 5974bec2d0bSJunfeng Guo txq->is_gqi_qpl = hw->queue_format == GVE_GQI_QPL_FORMAT; 5984bec2d0bSJunfeng Guo txq->hw = hw; 5994bec2d0bSJunfeng Guo txq->ntfy_addr = &hw->db_bar2[rte_be_to_cpu_32(hw->irq_dbs[txq->ntfy_id].id)]; 6004bec2d0bSJunfeng Guo 6014bec2d0bSJunfeng Guo /* Allocate software ring */ 6024bec2d0bSJunfeng Guo txq->sw_ring = rte_zmalloc_socket("gve tx sw ring", 6034bec2d0bSJunfeng Guo sizeof(struct rte_mbuf *) * nb_desc, 6044bec2d0bSJunfeng Guo RTE_CACHE_LINE_SIZE, socket_id); 6054bec2d0bSJunfeng Guo if (!txq->sw_ring) { 6064bec2d0bSJunfeng Guo PMD_DRV_LOG(ERR, "Failed to allocate memory for SW TX ring"); 6074bec2d0bSJunfeng Guo err = -ENOMEM; 6084bec2d0bSJunfeng Guo goto err_txq; 6094bec2d0bSJunfeng Guo } 6104bec2d0bSJunfeng Guo 6114bec2d0bSJunfeng Guo mz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_id, 6124bec2d0bSJunfeng Guo nb_desc * sizeof(union gve_tx_desc), 6134bec2d0bSJunfeng Guo PAGE_SIZE, socket_id); 6144bec2d0bSJunfeng Guo if (mz == NULL) { 6154bec2d0bSJunfeng Guo PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX"); 6164bec2d0bSJunfeng Guo err = -ENOMEM; 6174bec2d0bSJunfeng Guo goto err_sw_ring; 6184bec2d0bSJunfeng Guo } 6194bec2d0bSJunfeng Guo txq->tx_desc_ring = (union gve_tx_desc *)mz->addr; 6204bec2d0bSJunfeng Guo txq->tx_ring_phys_addr = mz->iova; 6214bec2d0bSJunfeng Guo txq->mz = mz; 6224bec2d0bSJunfeng Guo 6237f369975SJoshua Washington /* QPL-specific allocations. */ 6244bec2d0bSJunfeng Guo if (txq->is_gqi_qpl) { 6254bec2d0bSJunfeng Guo txq->iov_ring = rte_zmalloc_socket("gve tx iov ring", 6264bec2d0bSJunfeng Guo sizeof(struct gve_tx_iovec) * nb_desc, 6274bec2d0bSJunfeng Guo RTE_CACHE_LINE_SIZE, socket_id); 6284bec2d0bSJunfeng Guo if (!txq->iov_ring) { 6294bec2d0bSJunfeng Guo PMD_DRV_LOG(ERR, "Failed to allocate memory for SW TX ring"); 6304bec2d0bSJunfeng Guo err = -ENOMEM; 6314bec2d0bSJunfeng Guo goto err_tx_ring; 6324bec2d0bSJunfeng Guo } 6337f369975SJoshua Washington 6347f369975SJoshua Washington txq->qpl = gve_setup_queue_page_list(hw, queue_id, false, 6357f369975SJoshua Washington hw->tx_pages_per_qpl); 6367f369975SJoshua Washington if (!txq->qpl) { 637cde01d16SJoshua Washington err = -ENOMEM; 6387f369975SJoshua Washington PMD_DRV_LOG(ERR, "Failed to alloc tx qpl for queue %hu.", 6397f369975SJoshua Washington queue_id); 6404bec2d0bSJunfeng Guo goto err_iov_ring; 6414bec2d0bSJunfeng Guo } 6424bec2d0bSJunfeng Guo } 6434bec2d0bSJunfeng Guo 6444bec2d0bSJunfeng Guo mz = rte_eth_dma_zone_reserve(dev, "txq_res", queue_id, sizeof(struct gve_queue_resources), 6454bec2d0bSJunfeng Guo PAGE_SIZE, socket_id); 6464bec2d0bSJunfeng Guo if (mz == NULL) { 6474bec2d0bSJunfeng Guo PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX resource"); 6484bec2d0bSJunfeng Guo err = -ENOMEM; 6497f369975SJoshua Washington goto err_qpl; 6504bec2d0bSJunfeng Guo } 6514bec2d0bSJunfeng Guo txq->qres = (struct gve_queue_resources *)mz->addr; 6524bec2d0bSJunfeng Guo txq->qres_mz = mz; 6534bec2d0bSJunfeng Guo 6544bec2d0bSJunfeng Guo gve_reset_txq(txq); 6554bec2d0bSJunfeng Guo 6564bec2d0bSJunfeng Guo dev->data->tx_queues[queue_id] = txq; 6574bec2d0bSJunfeng Guo 6584bec2d0bSJunfeng Guo return 0; 6597f369975SJoshua Washington err_qpl: 6607f369975SJoshua Washington if (txq->is_gqi_qpl) { 6617f369975SJoshua Washington gve_teardown_queue_page_list(hw, txq->qpl); 6627f369975SJoshua Washington txq->qpl = NULL; 6637f369975SJoshua Washington } 6644bec2d0bSJunfeng Guo err_iov_ring: 6654bec2d0bSJunfeng Guo if (txq->is_gqi_qpl) 6664bec2d0bSJunfeng Guo rte_free(txq->iov_ring); 6674bec2d0bSJunfeng Guo err_tx_ring: 6684bec2d0bSJunfeng Guo rte_memzone_free(txq->mz); 6694bec2d0bSJunfeng Guo err_sw_ring: 6704bec2d0bSJunfeng Guo rte_free(txq->sw_ring); 6714bec2d0bSJunfeng Guo err_txq: 6724bec2d0bSJunfeng Guo rte_free(txq); 6734bec2d0bSJunfeng Guo return err; 6744bec2d0bSJunfeng Guo } 6754bec2d0bSJunfeng Guo 676b044845bSJunfeng Guo int 677b044845bSJunfeng Guo gve_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id) 678b044845bSJunfeng Guo { 679b044845bSJunfeng Guo struct gve_priv *hw = dev->data->dev_private; 680b044845bSJunfeng Guo struct gve_tx_queue *txq; 681b044845bSJunfeng Guo 682b044845bSJunfeng Guo if (tx_queue_id >= dev->data->nb_tx_queues) 683b044845bSJunfeng Guo return -EINVAL; 684b044845bSJunfeng Guo 685b044845bSJunfeng Guo txq = dev->data->tx_queues[tx_queue_id]; 686b044845bSJunfeng Guo 687b044845bSJunfeng Guo txq->qtx_tail = &hw->db_bar2[rte_be_to_cpu_32(txq->qres->db_index)]; 688b044845bSJunfeng Guo txq->qtx_head = 689b044845bSJunfeng Guo &hw->cnt_array[rte_be_to_cpu_32(txq->qres->counter_index)]; 690b044845bSJunfeng Guo 691b044845bSJunfeng Guo rte_write32(rte_cpu_to_be_32(GVE_IRQ_MASK), txq->ntfy_addr); 692b044845bSJunfeng Guo 6933caa72d3STathagat Priyadarshi dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED; 694b044845bSJunfeng Guo 695b044845bSJunfeng Guo return 0; 696b044845bSJunfeng Guo } 697b044845bSJunfeng Guo 698b044845bSJunfeng Guo int 699b044845bSJunfeng Guo gve_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id) 700b044845bSJunfeng Guo { 701b044845bSJunfeng Guo struct gve_tx_queue *txq; 702b044845bSJunfeng Guo 703b044845bSJunfeng Guo if (tx_queue_id >= dev->data->nb_tx_queues) 704b044845bSJunfeng Guo return -EINVAL; 705b044845bSJunfeng Guo 706b044845bSJunfeng Guo txq = dev->data->tx_queues[tx_queue_id]; 707b044845bSJunfeng Guo gve_release_txq_mbufs(txq); 708b044845bSJunfeng Guo gve_reset_txq(txq); 709b044845bSJunfeng Guo 710b044845bSJunfeng Guo dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED; 711b044845bSJunfeng Guo 712b044845bSJunfeng Guo return 0; 713b044845bSJunfeng Guo } 714b044845bSJunfeng Guo 7154bec2d0bSJunfeng Guo void 7164bec2d0bSJunfeng Guo gve_stop_tx_queues(struct rte_eth_dev *dev) 7174bec2d0bSJunfeng Guo { 7184bec2d0bSJunfeng Guo struct gve_priv *hw = dev->data->dev_private; 7194bec2d0bSJunfeng Guo uint16_t i; 7204bec2d0bSJunfeng Guo int err; 7214bec2d0bSJunfeng Guo 7221e27182eSJunfeng Guo if (!gve_is_gqi(hw)) 7231e27182eSJunfeng Guo return gve_stop_tx_queues_dqo(dev); 7241e27182eSJunfeng Guo 7254bec2d0bSJunfeng Guo err = gve_adminq_destroy_tx_queues(hw, dev->data->nb_tx_queues); 7264bec2d0bSJunfeng Guo if (err != 0) 7274bec2d0bSJunfeng Guo PMD_DRV_LOG(WARNING, "failed to destroy txqs"); 7284bec2d0bSJunfeng Guo 729b044845bSJunfeng Guo for (i = 0; i < dev->data->nb_tx_queues; i++) 730b044845bSJunfeng Guo if (gve_tx_queue_stop(dev, i) != 0) 731b044845bSJunfeng Guo PMD_DRV_LOG(WARNING, "Fail to stop Tx queue %d", i); 7324bec2d0bSJunfeng Guo } 733b044845bSJunfeng Guo 734b044845bSJunfeng Guo void 735b044845bSJunfeng Guo gve_set_tx_function(struct rte_eth_dev *dev) 736b044845bSJunfeng Guo { 737b044845bSJunfeng Guo dev->tx_pkt_burst = gve_tx_burst; 7384bec2d0bSJunfeng Guo } 739