1ffe84fcbSChaoyong He /* SPDX-License-Identifier: BSD-3-Clause 2ffe84fcbSChaoyong He * Copyright (c) 2023 Corigine, Inc. 3ffe84fcbSChaoyong He * All rights reserved. 4ffe84fcbSChaoyong He */ 5ffe84fcbSChaoyong He 6df535ba5SChaoyong He #include "nfp_nfd3.h" 7df535ba5SChaoyong He 8ffe84fcbSChaoyong He #include <bus_pci_driver.h> 9ffe84fcbSChaoyong He #include <rte_malloc.h> 10ffe84fcbSChaoyong He 118ddfcd8fSChaoyong He #include "../flower/nfp_flower.h" 12df535ba5SChaoyong He #include "../nfp_logs.h" 13ddcd598fSLong Wu #include "../nfp_net_meta.h" 14df535ba5SChaoyong He 15df535ba5SChaoyong He /* Flags in the host TX descriptor */ 16df535ba5SChaoyong He #define NFD3_DESC_TX_CSUM RTE_BIT32(7) 17df535ba5SChaoyong He #define NFD3_DESC_TX_IP4_CSUM RTE_BIT32(6) 18df535ba5SChaoyong He #define NFD3_DESC_TX_TCP_CSUM RTE_BIT32(5) 19df535ba5SChaoyong He #define NFD3_DESC_TX_UDP_CSUM RTE_BIT32(4) 20df535ba5SChaoyong He #define NFD3_DESC_TX_VLAN RTE_BIT32(3) 21df535ba5SChaoyong He #define NFD3_DESC_TX_LSO RTE_BIT32(2) 22df535ba5SChaoyong He #define NFD3_DESC_TX_ENCAP RTE_BIT32(1) 23df535ba5SChaoyong He #define NFD3_DESC_TX_O_IP4_CSUM RTE_BIT32(0) 24df535ba5SChaoyong He 25df535ba5SChaoyong He /* Set NFD3 TX descriptor for TSO */ 26df535ba5SChaoyong He static void 27df535ba5SChaoyong He nfp_net_nfd3_tx_tso(struct nfp_net_txq *txq, 28df535ba5SChaoyong He struct nfp_net_nfd3_tx_desc *txd, 29df535ba5SChaoyong He struct rte_mbuf *mb) 30df535ba5SChaoyong He { 31df535ba5SChaoyong He uint64_t ol_flags; 32df535ba5SChaoyong He struct nfp_net_hw *hw = txq->hw; 33df535ba5SChaoyong He 34afa83796SChaoyong He if ((hw->super.ctrl & NFP_NET_CFG_CTRL_LSO_ANY) == 0) 35df535ba5SChaoyong He goto clean_txd; 36df535ba5SChaoyong He 37df535ba5SChaoyong He ol_flags = mb->ol_flags; 38df77f704SChaoyong He if ((ol_flags & RTE_MBUF_F_TX_TCP_SEG) == 0 && 39df77f704SChaoyong He (ol_flags & RTE_MBUF_F_TX_UDP_SEG) == 0) 40df535ba5SChaoyong He goto clean_txd; 41df535ba5SChaoyong He 42df535ba5SChaoyong He txd->l3_offset = mb->l2_len; 43df535ba5SChaoyong He txd->l4_offset = mb->l2_len + mb->l3_len; 44df535ba5SChaoyong He txd->lso_hdrlen = mb->l2_len + mb->l3_len + mb->l4_len; 45df535ba5SChaoyong He 46df535ba5SChaoyong He if ((ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) != 0) { 47df535ba5SChaoyong He txd->l3_offset += mb->outer_l2_len + mb->outer_l3_len; 48df535ba5SChaoyong He txd->l4_offset += mb->outer_l2_len + mb->outer_l3_len; 49df535ba5SChaoyong He txd->lso_hdrlen += mb->outer_l2_len + mb->outer_l3_len; 50df535ba5SChaoyong He } 51df535ba5SChaoyong He 52df535ba5SChaoyong He txd->mss = rte_cpu_to_le_16(mb->tso_segsz); 53df535ba5SChaoyong He txd->flags = NFD3_DESC_TX_LSO; 54df535ba5SChaoyong He 55df535ba5SChaoyong He return; 56df535ba5SChaoyong He 57df535ba5SChaoyong He clean_txd: 58df535ba5SChaoyong He txd->flags = 0; 59df535ba5SChaoyong He txd->l3_offset = 0; 60df535ba5SChaoyong He txd->l4_offset = 0; 61df535ba5SChaoyong He txd->lso_hdrlen = 0; 62df535ba5SChaoyong He txd->mss = 0; 63df535ba5SChaoyong He } 64df535ba5SChaoyong He 65df535ba5SChaoyong He /* Set TX CSUM offload flags in NFD3 TX descriptor */ 66df535ba5SChaoyong He static void 67df535ba5SChaoyong He nfp_net_nfd3_tx_cksum(struct nfp_net_txq *txq, 68df535ba5SChaoyong He struct nfp_net_nfd3_tx_desc *txd, 69df535ba5SChaoyong He struct rte_mbuf *mb) 70df535ba5SChaoyong He { 71df535ba5SChaoyong He uint64_t ol_flags; 72df535ba5SChaoyong He struct nfp_net_hw *hw = txq->hw; 73df535ba5SChaoyong He 74afa83796SChaoyong He if ((hw->super.ctrl & NFP_NET_CFG_CTRL_TXCSUM) == 0) 75df535ba5SChaoyong He return; 76df535ba5SChaoyong He 77df535ba5SChaoyong He ol_flags = mb->ol_flags; 78df535ba5SChaoyong He 79df535ba5SChaoyong He /* Set TCP csum offload if TSO enabled. */ 80df535ba5SChaoyong He if ((ol_flags & RTE_MBUF_F_TX_TCP_SEG) != 0) 81df535ba5SChaoyong He txd->flags |= NFD3_DESC_TX_TCP_CSUM; 82df535ba5SChaoyong He 83df77f704SChaoyong He /* Set UDP csum offload if UFO enabled. */ 84df77f704SChaoyong He if ((ol_flags & RTE_MBUF_F_TX_UDP_SEG) != 0) 85df77f704SChaoyong He txd->flags |= NFD3_DESC_TX_UDP_CSUM; 86df77f704SChaoyong He 87df535ba5SChaoyong He /* IPv6 does not need checksum */ 88df535ba5SChaoyong He if ((ol_flags & RTE_MBUF_F_TX_IP_CKSUM) != 0) 89df535ba5SChaoyong He txd->flags |= NFD3_DESC_TX_IP4_CSUM; 90df535ba5SChaoyong He 91df535ba5SChaoyong He if ((ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) != 0) 92df535ba5SChaoyong He txd->flags |= NFD3_DESC_TX_ENCAP; 93df535ba5SChaoyong He 94df535ba5SChaoyong He switch (ol_flags & RTE_MBUF_F_TX_L4_MASK) { 95df535ba5SChaoyong He case RTE_MBUF_F_TX_UDP_CKSUM: 96df535ba5SChaoyong He txd->flags |= NFD3_DESC_TX_UDP_CSUM; 97df535ba5SChaoyong He break; 98df535ba5SChaoyong He case RTE_MBUF_F_TX_TCP_CKSUM: 99df535ba5SChaoyong He txd->flags |= NFD3_DESC_TX_TCP_CSUM; 100df535ba5SChaoyong He break; 101df535ba5SChaoyong He } 102df535ba5SChaoyong He 103df535ba5SChaoyong He if ((ol_flags & (RTE_MBUF_F_TX_IP_CKSUM | RTE_MBUF_F_TX_L4_MASK)) != 0) 104df535ba5SChaoyong He txd->flags |= NFD3_DESC_TX_CSUM; 105df535ba5SChaoyong He } 106ffe84fcbSChaoyong He 1078ddfcd8fSChaoyong He uint32_t 1088ddfcd8fSChaoyong He nfp_flower_nfd3_pkt_add_metadata(struct rte_mbuf *mbuf, 1098ddfcd8fSChaoyong He uint32_t port_id) 1108ddfcd8fSChaoyong He { 1118ddfcd8fSChaoyong He char *meta_offset; 1128ddfcd8fSChaoyong He 1138ddfcd8fSChaoyong He meta_offset = rte_pktmbuf_prepend(mbuf, FLOWER_PKT_DATA_OFFSET); 1148ddfcd8fSChaoyong He *(rte_be32_t *)meta_offset = rte_cpu_to_be_32(NFP_NET_META_PORTID); 1158ddfcd8fSChaoyong He meta_offset += NFP_NET_META_HEADER_SIZE; 1168ddfcd8fSChaoyong He *(rte_be32_t *)meta_offset = rte_cpu_to_be_32(port_id); 1178ddfcd8fSChaoyong He 1188ddfcd8fSChaoyong He return FLOWER_PKT_DATA_OFFSET; 1198ddfcd8fSChaoyong He } 1208ddfcd8fSChaoyong He 121ffe84fcbSChaoyong He /* 12240688372SChaoyong He * Set vlan info in the nfd3 tx desc 123ffe84fcbSChaoyong He * 124ffe84fcbSChaoyong He * If enable NFP_NET_CFG_CTRL_TXVLAN_V2 12540688372SChaoyong He * Vlan_info is stored in the meta and is handled in the @nfp_net_nfd3_set_meta_vlan() 126ffe84fcbSChaoyong He * else if enable NFP_NET_CFG_CTRL_TXVLAN 12740688372SChaoyong He * Vlan_info is stored in the tx_desc and is handled in the @nfp_net_nfd3_tx_vlan() 128ffe84fcbSChaoyong He */ 1293745dd9dSChaoyong He static inline void 130ffe84fcbSChaoyong He nfp_net_nfd3_tx_vlan(struct nfp_net_txq *txq, 131ffe84fcbSChaoyong He struct nfp_net_nfd3_tx_desc *txd, 132ffe84fcbSChaoyong He struct rte_mbuf *mb) 133ffe84fcbSChaoyong He { 134ffe84fcbSChaoyong He struct nfp_net_hw *hw = txq->hw; 135ffe84fcbSChaoyong He 136afa83796SChaoyong He if ((hw->super.ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2) != 0 || 137afa83796SChaoyong He (hw->super.ctrl & NFP_NET_CFG_CTRL_TXVLAN) == 0) 138ffe84fcbSChaoyong He return; 139ffe84fcbSChaoyong He 140ffe84fcbSChaoyong He if ((mb->ol_flags & RTE_MBUF_F_TX_VLAN) != 0) { 1418b92d2a5SChaoyong He txd->flags |= NFD3_DESC_TX_VLAN; 142ffe84fcbSChaoyong He txd->vlan = mb->vlan_tci; 143ffe84fcbSChaoyong He } 144ffe84fcbSChaoyong He } 145ffe84fcbSChaoyong He 1467ecf3b90SChaoyong He static inline int 147ffe84fcbSChaoyong He nfp_net_nfd3_set_meta_data(struct nfp_net_meta_raw *meta_data, 148ffe84fcbSChaoyong He struct nfp_net_txq *txq, 149ffe84fcbSChaoyong He struct rte_mbuf *pkt) 150ffe84fcbSChaoyong He { 151ffe84fcbSChaoyong He char *meta; 1523745dd9dSChaoyong He uint8_t layer = 0; 1533745dd9dSChaoyong He uint32_t meta_info; 1543745dd9dSChaoyong He struct nfp_net_hw *hw; 1553745dd9dSChaoyong He uint8_t vlan_layer = 0; 156310a1780SShihong Wang uint8_t ipsec_layer = 0; 157ffe84fcbSChaoyong He 158ffe84fcbSChaoyong He hw = txq->hw; 159ffe84fcbSChaoyong He 160ffe84fcbSChaoyong He if ((pkt->ol_flags & RTE_MBUF_F_TX_VLAN) != 0 && 161b4b6988aSChaoyong He (hw->super.ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2) != 0) { 162ffe84fcbSChaoyong He if (meta_data->length == 0) 163ffe84fcbSChaoyong He meta_data->length = NFP_NET_META_HEADER_SIZE; 164ffe84fcbSChaoyong He meta_data->length += NFP_NET_META_FIELD_SIZE; 165ffe84fcbSChaoyong He meta_data->header |= NFP_NET_META_VLAN; 166ffe84fcbSChaoyong He } 167ffe84fcbSChaoyong He 168310a1780SShihong Wang if ((pkt->ol_flags & RTE_MBUF_F_TX_SEC_OFFLOAD) != 0 && 1699177c800SChaoyong He (hw->super.ctrl_ext & NFP_NET_CFG_CTRL_IPSEC) != 0) { 170310a1780SShihong Wang uint32_t ipsec_type = NFP_NET_META_IPSEC | 171310a1780SShihong Wang NFP_NET_META_IPSEC << NFP_NET_META_FIELD_SIZE | 172310a1780SShihong Wang NFP_NET_META_IPSEC << (2 * NFP_NET_META_FIELD_SIZE); 173310a1780SShihong Wang if (meta_data->length == 0) 174310a1780SShihong Wang meta_data->length = NFP_NET_META_FIELD_SIZE; 175310a1780SShihong Wang uint8_t ipsec_offset = meta_data->length - NFP_NET_META_FIELD_SIZE; 176310a1780SShihong Wang meta_data->header |= (ipsec_type << ipsec_offset); 177310a1780SShihong Wang meta_data->length += 3 * NFP_NET_META_FIELD_SIZE; 178310a1780SShihong Wang } 179310a1780SShihong Wang 180ffe84fcbSChaoyong He if (meta_data->length == 0) 1817ecf3b90SChaoyong He return 0; 182ffe84fcbSChaoyong He 183ffe84fcbSChaoyong He meta_info = meta_data->header; 184ffe84fcbSChaoyong He meta = rte_pktmbuf_prepend(pkt, meta_data->length); 185b5894ec0SLong Wu *(rte_be32_t *)meta = rte_cpu_to_be_32(meta_data->header); 186ffe84fcbSChaoyong He meta += NFP_NET_META_HEADER_SIZE; 187ffe84fcbSChaoyong He 188ffe84fcbSChaoyong He for (; meta_info != 0; meta_info >>= NFP_NET_META_FIELD_SIZE, layer++, 189ffe84fcbSChaoyong He meta += NFP_NET_META_FIELD_SIZE) { 190ffe84fcbSChaoyong He switch (meta_info & NFP_NET_META_FIELD_MASK) { 191ffe84fcbSChaoyong He case NFP_NET_META_VLAN: 192ffe84fcbSChaoyong He if (vlan_layer > 0) { 193*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "At most 1 layers of vlan is supported."); 1947ecf3b90SChaoyong He return -EINVAL; 195ffe84fcbSChaoyong He } 1960e131d77SLong Wu nfp_net_meta_set_vlan(meta_data, pkt, layer); 197ffe84fcbSChaoyong He vlan_layer++; 198ffe84fcbSChaoyong He break; 199310a1780SShihong Wang case NFP_NET_META_IPSEC: 200310a1780SShihong Wang if (ipsec_layer > 2) { 201310a1780SShihong Wang PMD_DRV_LOG(ERR, "At most 3 layers of ipsec is supported for now."); 2027ecf3b90SChaoyong He return -EINVAL; 203310a1780SShihong Wang } 204310a1780SShihong Wang 2050e131d77SLong Wu nfp_net_meta_set_ipsec(meta_data, txq, pkt, layer, ipsec_layer); 206310a1780SShihong Wang ipsec_layer++; 207310a1780SShihong Wang break; 208ffe84fcbSChaoyong He default: 209*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "The metadata type not supported."); 2107ecf3b90SChaoyong He return -ENOTSUP; 211ffe84fcbSChaoyong He } 212ffe84fcbSChaoyong He 213b5894ec0SLong Wu *(rte_be32_t *)meta = rte_cpu_to_be_32(meta_data->data[layer]); 214ffe84fcbSChaoyong He } 2157ecf3b90SChaoyong He 2167ecf3b90SChaoyong He return 0; 217ffe84fcbSChaoyong He } 218ffe84fcbSChaoyong He 219ffe84fcbSChaoyong He uint16_t 2203745dd9dSChaoyong He nfp_net_nfd3_xmit_pkts(void *tx_queue, 2213745dd9dSChaoyong He struct rte_mbuf **tx_pkts, 2223745dd9dSChaoyong He uint16_t nb_pkts) 223ffe84fcbSChaoyong He { 224dca135b3SChaoyong He return nfp_net_nfd3_xmit_pkts_common(tx_queue, tx_pkts, nb_pkts, false); 225dca135b3SChaoyong He } 226dca135b3SChaoyong He 227dca135b3SChaoyong He uint16_t 228dca135b3SChaoyong He nfp_net_nfd3_xmit_pkts_common(void *tx_queue, 229dca135b3SChaoyong He struct rte_mbuf **tx_pkts, 230dca135b3SChaoyong He uint16_t nb_pkts, 231dca135b3SChaoyong He bool repr_flag) 232dca135b3SChaoyong He { 2337ecf3b90SChaoyong He int ret; 2348ceb85c3SChaoyong He uint16_t i; 23549952141SChaoyong He uint8_t offset; 2368ceb85c3SChaoyong He uint32_t pkt_size; 2378ceb85c3SChaoyong He uint16_t dma_size; 2383745dd9dSChaoyong He uint64_t dma_addr; 2393745dd9dSChaoyong He uint16_t free_descs; 2403745dd9dSChaoyong He struct rte_mbuf *pkt; 24149952141SChaoyong He uint16_t issued_descs; 2423745dd9dSChaoyong He struct nfp_net_hw *hw; 2433745dd9dSChaoyong He struct rte_mbuf **lmbuf; 2443745dd9dSChaoyong He struct nfp_net_txq *txq; 2453745dd9dSChaoyong He struct nfp_net_nfd3_tx_desc txd; 2463745dd9dSChaoyong He struct nfp_net_nfd3_tx_desc *txds; 247ffe84fcbSChaoyong He 248ffe84fcbSChaoyong He txq = tx_queue; 249ffe84fcbSChaoyong He hw = txq->hw; 250ffe84fcbSChaoyong He txds = &txq->txds[txq->wr_p]; 251ffe84fcbSChaoyong He 252*b6de4353SZerun Fu PMD_TX_LOG(DEBUG, "Working for queue %hu at pos %d and %hu packets.", 253ffe84fcbSChaoyong He txq->qidx, txq->wr_p, nb_pkts); 254ffe84fcbSChaoyong He 2553745dd9dSChaoyong He if (nfp_net_nfd3_free_tx_desc(txq) < NFD3_TX_DESC_PER_PKT * nb_pkts || 256ffe84fcbSChaoyong He nfp_net_nfd3_txq_full(txq)) 257ffe84fcbSChaoyong He nfp_net_tx_free_bufs(txq); 258ffe84fcbSChaoyong He 2593745dd9dSChaoyong He free_descs = nfp_net_nfd3_free_tx_desc(txq); 260ffe84fcbSChaoyong He if (unlikely(free_descs == 0)) 261ffe84fcbSChaoyong He return 0; 262ffe84fcbSChaoyong He 263ffe84fcbSChaoyong He pkt = *tx_pkts; 264ffe84fcbSChaoyong He 265ffe84fcbSChaoyong He issued_descs = 0; 266*b6de4353SZerun Fu PMD_TX_LOG(DEBUG, "Queue: %hu. Sending %hu packets.", txq->qidx, nb_pkts); 2673745dd9dSChaoyong He 268ffe84fcbSChaoyong He /* Sending packets */ 269ffe84fcbSChaoyong He for (i = 0; i < nb_pkts && free_descs > 0; i++) { 270ffe84fcbSChaoyong He /* Grabbing the mbuf linked to the current descriptor */ 271ffe84fcbSChaoyong He lmbuf = &txq->txbufs[txq->wr_p].mbuf; 272ffe84fcbSChaoyong He /* Warming the cache for releasing the mbuf later on */ 273ffe84fcbSChaoyong He RTE_MBUF_PREFETCH_TO_FREE(*lmbuf); 274ffe84fcbSChaoyong He 275ffe84fcbSChaoyong He pkt = *(tx_pkts + i); 276ffe84fcbSChaoyong He 277dca135b3SChaoyong He if (!repr_flag) { 278dca135b3SChaoyong He struct nfp_net_meta_raw meta_data; 279dca135b3SChaoyong He memset(&meta_data, 0, sizeof(meta_data)); 2807ecf3b90SChaoyong He ret = nfp_net_nfd3_set_meta_data(&meta_data, txq, pkt); 2817ecf3b90SChaoyong He if (unlikely(ret != 0)) 2827ecf3b90SChaoyong He goto xmit_end; 2837ecf3b90SChaoyong He 284dca135b3SChaoyong He offset = meta_data.length; 285dca135b3SChaoyong He } else { 286dca135b3SChaoyong He offset = FLOWER_PKT_DATA_OFFSET; 287dca135b3SChaoyong He } 288ffe84fcbSChaoyong He 289ffe84fcbSChaoyong He if (unlikely(pkt->nb_segs > 1 && 290afa83796SChaoyong He (hw->super.ctrl & NFP_NET_CFG_CTRL_GATHER) == 0)) { 291*b6de4353SZerun Fu PMD_TX_LOG(ERR, "Multisegment packet not supported."); 292ffe84fcbSChaoyong He goto xmit_end; 293ffe84fcbSChaoyong He } 294ffe84fcbSChaoyong He 295ffe84fcbSChaoyong He /* Checking if we have enough descriptors */ 296ffe84fcbSChaoyong He if (unlikely(pkt->nb_segs > free_descs)) 297ffe84fcbSChaoyong He goto xmit_end; 298ffe84fcbSChaoyong He 299ffe84fcbSChaoyong He /* 300ffe84fcbSChaoyong He * Checksum and VLAN flags just in the first descriptor for a 301ffe84fcbSChaoyong He * multisegment packet, but TSO info needs to be in all of them. 302ffe84fcbSChaoyong He */ 303ffe84fcbSChaoyong He txd.data_len = pkt->pkt_len; 304ffe84fcbSChaoyong He nfp_net_nfd3_tx_tso(txq, &txd, pkt); 305ffe84fcbSChaoyong He nfp_net_nfd3_tx_cksum(txq, &txd, pkt); 306ffe84fcbSChaoyong He nfp_net_nfd3_tx_vlan(txq, &txd, pkt); 307ffe84fcbSChaoyong He 308ffe84fcbSChaoyong He /* 30940688372SChaoyong He * Mbuf data_len is the data in one segment and pkt_len data 310ffe84fcbSChaoyong He * in the whole packet. When the packet is just one segment, 31140688372SChaoyong He * then data_len = pkt_len. 312ffe84fcbSChaoyong He */ 313ffe84fcbSChaoyong He pkt_size = pkt->pkt_len; 314ffe84fcbSChaoyong He 315ffe84fcbSChaoyong He while (pkt != NULL && free_descs > 0) { 316ffe84fcbSChaoyong He /* Copying TSO, VLAN and cksum info */ 317ffe84fcbSChaoyong He *txds = txd; 318ffe84fcbSChaoyong He 319ffe84fcbSChaoyong He /* Releasing mbuf used by this descriptor previously */ 3203745dd9dSChaoyong He if (*lmbuf != NULL) 321ffe84fcbSChaoyong He rte_pktmbuf_free_seg(*lmbuf); 322ffe84fcbSChaoyong He 323ffe84fcbSChaoyong He /* 324ffe84fcbSChaoyong He * Linking mbuf with descriptor for being released 32540688372SChaoyong He * next time descriptor is used. 326ffe84fcbSChaoyong He */ 327ffe84fcbSChaoyong He *lmbuf = pkt; 328ffe84fcbSChaoyong He 329ffe84fcbSChaoyong He dma_size = pkt->data_len; 330ffe84fcbSChaoyong He dma_addr = rte_mbuf_data_iova(pkt); 331ffe84fcbSChaoyong He 332ffe84fcbSChaoyong He /* Filling descriptors fields */ 333ffe84fcbSChaoyong He txds->dma_len = dma_size; 334ffe84fcbSChaoyong He txds->data_len = txd.data_len; 335ffe84fcbSChaoyong He txds->dma_addr_hi = (dma_addr >> 32) & 0xff; 336ffe84fcbSChaoyong He txds->dma_addr_lo = (dma_addr & 0xffffffff); 337ffe84fcbSChaoyong He free_descs--; 338ffe84fcbSChaoyong He 339ffe84fcbSChaoyong He txq->wr_p++; 34040688372SChaoyong He if (unlikely(txq->wr_p == txq->tx_count)) /* Wrapping */ 341ffe84fcbSChaoyong He txq->wr_p = 0; 342ffe84fcbSChaoyong He 343ffe84fcbSChaoyong He pkt_size -= dma_size; 344ffe84fcbSChaoyong He 345ffe84fcbSChaoyong He /* 346ffe84fcbSChaoyong He * Making the EOP, packets with just one segment 34740688372SChaoyong He * the priority. 348ffe84fcbSChaoyong He */ 349ffe84fcbSChaoyong He if (likely(pkt_size == 0)) 3508b92d2a5SChaoyong He txds->offset_eop = NFD3_DESC_TX_EOP; 351ffe84fcbSChaoyong He else 352ffe84fcbSChaoyong He txds->offset_eop = 0; 353ffe84fcbSChaoyong He 354ffe84fcbSChaoyong He /* Set the meta_len */ 355dca135b3SChaoyong He txds->offset_eop |= offset; 356ffe84fcbSChaoyong He 357ffe84fcbSChaoyong He pkt = pkt->next; 358ffe84fcbSChaoyong He /* Referencing next free TX descriptor */ 359ffe84fcbSChaoyong He txds = &txq->txds[txq->wr_p]; 360ffe84fcbSChaoyong He lmbuf = &txq->txbufs[txq->wr_p].mbuf; 361ffe84fcbSChaoyong He issued_descs++; 362ffe84fcbSChaoyong He } 363ffe84fcbSChaoyong He } 364ffe84fcbSChaoyong He 365ffe84fcbSChaoyong He xmit_end: 366ffe84fcbSChaoyong He /* Increment write pointers. Force memory write before we let HW know */ 367ffe84fcbSChaoyong He rte_wmb(); 368ffe84fcbSChaoyong He nfp_qcp_ptr_add(txq->qcp_q, NFP_QCP_WRITE_PTR, issued_descs); 369ffe84fcbSChaoyong He 370ffe84fcbSChaoyong He return i; 371ffe84fcbSChaoyong He } 372ffe84fcbSChaoyong He 373ffe84fcbSChaoyong He int 3743745dd9dSChaoyong He nfp_net_nfd3_tx_queue_setup(struct rte_eth_dev *dev, 3753745dd9dSChaoyong He uint16_t queue_idx, 3763745dd9dSChaoyong He uint16_t nb_desc, 3773745dd9dSChaoyong He unsigned int socket_id, 378ffe84fcbSChaoyong He const struct rte_eth_txconf *tx_conf) 379ffe84fcbSChaoyong He { 3803745dd9dSChaoyong He size_t size; 3813745dd9dSChaoyong He uint32_t tx_desc_sz; 382ffe84fcbSChaoyong He uint16_t min_tx_desc; 383ffe84fcbSChaoyong He uint16_t max_tx_desc; 3843745dd9dSChaoyong He struct nfp_net_hw *hw; 385ffe84fcbSChaoyong He struct nfp_net_txq *txq; 386ffe84fcbSChaoyong He uint16_t tx_free_thresh; 3873745dd9dSChaoyong He const struct rte_memzone *tz; 388d81e2b51SChaoyong He struct nfp_net_hw_priv *hw_priv; 389ffe84fcbSChaoyong He 390c4de52ecSChaoyong He hw = nfp_net_get_hw(dev); 391d81e2b51SChaoyong He hw_priv = dev->process_private; 392ffe84fcbSChaoyong He 393000feb4cSChaoyong He nfp_net_tx_desc_limits(hw_priv, &min_tx_desc, &max_tx_desc); 394ffe84fcbSChaoyong He 395ffe84fcbSChaoyong He /* Validating number of descriptors */ 396ffe84fcbSChaoyong He tx_desc_sz = nb_desc * sizeof(struct nfp_net_nfd3_tx_desc); 3973745dd9dSChaoyong He if ((NFD3_TX_DESC_PER_PKT * tx_desc_sz) % NFP_ALIGN_RING_DESC != 0 || 398ffe84fcbSChaoyong He nb_desc > max_tx_desc || nb_desc < min_tx_desc) { 399*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Wrong nb_desc value."); 400ffe84fcbSChaoyong He return -EINVAL; 401ffe84fcbSChaoyong He } 402ffe84fcbSChaoyong He 4033745dd9dSChaoyong He tx_free_thresh = (tx_conf->tx_free_thresh != 0) ? 4043745dd9dSChaoyong He tx_conf->tx_free_thresh : DEFAULT_TX_FREE_THRESH; 4053745dd9dSChaoyong He if (tx_free_thresh > nb_desc) { 406f6272c7aSZerun Fu PMD_DRV_LOG(ERR, "The tx_free_thresh must be less than the number of TX " 4073745dd9dSChaoyong He "descriptors. (tx_free_thresh=%u port=%d queue=%d)", 4083745dd9dSChaoyong He tx_free_thresh, dev->data->port_id, queue_idx); 4093745dd9dSChaoyong He return -EINVAL; 410ffe84fcbSChaoyong He } 411ffe84fcbSChaoyong He 412ffe84fcbSChaoyong He /* 413ffe84fcbSChaoyong He * Free memory prior to re-allocation if needed. This is the case after 4143745dd9dSChaoyong He * calling nfp_net_stop(). 415ffe84fcbSChaoyong He */ 4163745dd9dSChaoyong He if (dev->data->tx_queues[queue_idx] != NULL) { 417*b6de4353SZerun Fu PMD_TX_LOG(DEBUG, "Freeing memory prior to re-allocation %d.", 418ffe84fcbSChaoyong He queue_idx); 419ffe84fcbSChaoyong He nfp_net_tx_queue_release(dev, queue_idx); 420ffe84fcbSChaoyong He dev->data->tx_queues[queue_idx] = NULL; 421ffe84fcbSChaoyong He } 422ffe84fcbSChaoyong He 423ffe84fcbSChaoyong He /* Allocating tx queue data structure */ 424ffe84fcbSChaoyong He txq = rte_zmalloc_socket("ethdev TX queue", sizeof(struct nfp_net_txq), 425ffe84fcbSChaoyong He RTE_CACHE_LINE_SIZE, socket_id); 426ffe84fcbSChaoyong He if (txq == NULL) { 427*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Error allocating tx dma."); 428ffe84fcbSChaoyong He return -ENOMEM; 429ffe84fcbSChaoyong He } 430ffe84fcbSChaoyong He 431ffe84fcbSChaoyong He dev->data->tx_queues[queue_idx] = txq; 432ffe84fcbSChaoyong He 433ffe84fcbSChaoyong He /* 434ffe84fcbSChaoyong He * Allocate TX ring hardware descriptors. A memzone large enough to 435ffe84fcbSChaoyong He * handle the maximum ring size is allocated in order to allow for 436ffe84fcbSChaoyong He * resizing in later calls to the queue setup function. 437ffe84fcbSChaoyong He */ 4383745dd9dSChaoyong He size = sizeof(struct nfp_net_nfd3_tx_desc) * NFD3_TX_DESC_PER_PKT * max_tx_desc; 4393745dd9dSChaoyong He tz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_idx, size, 4403745dd9dSChaoyong He NFP_MEMZONE_ALIGN, socket_id); 441ffe84fcbSChaoyong He if (tz == NULL) { 442*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Error allocating tx dma."); 443ffe84fcbSChaoyong He nfp_net_tx_queue_release(dev, queue_idx); 444ffe84fcbSChaoyong He dev->data->tx_queues[queue_idx] = NULL; 445ffe84fcbSChaoyong He return -ENOMEM; 446ffe84fcbSChaoyong He } 447ffe84fcbSChaoyong He 4483745dd9dSChaoyong He txq->tx_count = nb_desc * NFD3_TX_DESC_PER_PKT; 449ffe84fcbSChaoyong He txq->tx_free_thresh = tx_free_thresh; 450ffe84fcbSChaoyong He 45140688372SChaoyong He /* Queue mapping based on firmware configuration */ 452ffe84fcbSChaoyong He txq->qidx = queue_idx; 453ffe84fcbSChaoyong He txq->tx_qcidx = queue_idx * hw->stride_tx; 454ffe84fcbSChaoyong He txq->qcp_q = hw->tx_bar + NFP_QCP_QUEUE_OFF(txq->tx_qcidx); 455ffe84fcbSChaoyong He txq->port_id = dev->data->port_id; 456ffe84fcbSChaoyong He 457ffe84fcbSChaoyong He /* Saving physical and virtual addresses for the TX ring */ 4583745dd9dSChaoyong He txq->dma = tz->iova; 4593745dd9dSChaoyong He txq->txds = tz->addr; 460ffe84fcbSChaoyong He 46140688372SChaoyong He /* Mbuf pointers array for referencing mbufs linked to TX descriptors */ 462ffe84fcbSChaoyong He txq->txbufs = rte_zmalloc_socket("txq->txbufs", 463ffe84fcbSChaoyong He sizeof(*txq->txbufs) * txq->tx_count, 464ffe84fcbSChaoyong He RTE_CACHE_LINE_SIZE, socket_id); 465ffe84fcbSChaoyong He if (txq->txbufs == NULL) { 466ffe84fcbSChaoyong He nfp_net_tx_queue_release(dev, queue_idx); 467ffe84fcbSChaoyong He dev->data->tx_queues[queue_idx] = NULL; 468ffe84fcbSChaoyong He return -ENOMEM; 469ffe84fcbSChaoyong He } 470ffe84fcbSChaoyong He 471ffe84fcbSChaoyong He nfp_net_reset_tx_queue(txq); 472ffe84fcbSChaoyong He 473ffe84fcbSChaoyong He txq->hw = hw; 474ff9f5a56SChaoyong He txq->hw_priv = dev->process_private; 475ffe84fcbSChaoyong He 476ffe84fcbSChaoyong He /* 477ffe84fcbSChaoyong He * Telling the HW about the physical address of the TX ring and number 47840688372SChaoyong He * of descriptors in log2 format. 479ffe84fcbSChaoyong He */ 480f58bde00SChaoyong He nn_cfg_writeq(&hw->super, NFP_NET_CFG_TXR_ADDR(queue_idx), txq->dma); 481f58bde00SChaoyong He nn_cfg_writeb(&hw->super, NFP_NET_CFG_TXR_SZ(queue_idx), rte_log2_u32(txq->tx_count)); 482ffe84fcbSChaoyong He 483ffe84fcbSChaoyong He return 0; 484ffe84fcbSChaoyong He } 485