Implement NFP3800 card packet transmit function for firmware
with NFDk.

Signed-off-by: Jin Liu <jin....@corigine.com>
Signed-off-by: Diana Wang <na.w...@corigine.com>
Signed-off-by: Peng Zhang <peng.zh...@corigine.com>
Signed-off-by: Chaoyong He <chaoyong...@corigine.com>
Signed-off-by: Niklas Söderlund <niklas.soderl...@corigine.com>
---
 drivers/net/nfp/nfp_ethdev.c    |   3 +-
 drivers/net/nfp/nfp_ethdev_vf.c |   3 +-
 drivers/net/nfp/nfp_rxtx.c      | 283 ++++++++++++++++++++++++++++++++
 drivers/net/nfp/nfp_rxtx.h      |   3 +
 4 files changed, 290 insertions(+), 2 deletions(-)

diff --git a/drivers/net/nfp/nfp_ethdev.c b/drivers/net/nfp/nfp_ethdev.c
index e8a8368d0f..b6817c10da 100644
--- a/drivers/net/nfp/nfp_ethdev.c
+++ b/drivers/net/nfp/nfp_ethdev.c
@@ -374,6 +374,7 @@ nfp_net_ethdev_ops_mount(struct nfp_net_hw *hw, struct 
rte_eth_dev *eth_dev)
        switch (NFD_CFG_CLASS_VER_of(hw->ver)) {
        case NFP_NET_CFG_VERSION_DP_NFD3:
                eth_dev->dev_ops = &nfp_net_nfd3_eth_dev_ops;
+               eth_dev->tx_pkt_burst = &nfp_net_nfd3_xmit_pkts;
                break;
        case NFP_NET_CFG_VERSION_DP_NFDK:
                if (NFD_CFG_MAJOR_VERSION_of(hw->ver) < 5) {
@@ -382,6 +383,7 @@ nfp_net_ethdev_ops_mount(struct nfp_net_hw *hw, struct 
rte_eth_dev *eth_dev)
                        return -EINVAL;
                }
                eth_dev->dev_ops = &nfp_net_nfdk_eth_dev_ops;
+               eth_dev->tx_pkt_burst = &nfp_net_nfdk_xmit_pkts;
                break;
        default:
                PMD_DRV_LOG(ERR, "The version of firmware is not correct.");
@@ -390,7 +392,6 @@ nfp_net_ethdev_ops_mount(struct nfp_net_hw *hw, struct 
rte_eth_dev *eth_dev)
 
        eth_dev->rx_queue_count = nfp_net_rx_queue_count;
        eth_dev->rx_pkt_burst = &nfp_net_recv_pkts;
-       eth_dev->tx_pkt_burst = &nfp_net_nfd3_xmit_pkts;
 
        return 0;
 }
diff --git a/drivers/net/nfp/nfp_ethdev_vf.c b/drivers/net/nfp/nfp_ethdev_vf.c
index 56428814b7..66a1c0a36b 100644
--- a/drivers/net/nfp/nfp_ethdev_vf.c
+++ b/drivers/net/nfp/nfp_ethdev_vf.c
@@ -279,6 +279,7 @@ nfp_netvf_ethdev_ops_mount(struct nfp_net_hw *hw, struct 
rte_eth_dev *eth_dev)
        switch (NFD_CFG_CLASS_VER_of(hw->ver)) {
        case NFP_NET_CFG_VERSION_DP_NFD3:
                eth_dev->dev_ops = &nfp_netvf_nfd3_eth_dev_ops;
+               eth_dev->tx_pkt_burst = &nfp_net_nfd3_xmit_pkts;
                break;
        case NFP_NET_CFG_VERSION_DP_NFDK:
                if (NFD_CFG_MAJOR_VERSION_of(hw->ver) < 5) {
@@ -287,6 +288,7 @@ nfp_netvf_ethdev_ops_mount(struct nfp_net_hw *hw, struct 
rte_eth_dev *eth_dev)
                        return -EINVAL;
                }
                eth_dev->dev_ops = &nfp_netvf_nfdk_eth_dev_ops;
+               eth_dev->tx_pkt_burst = &nfp_net_nfdk_xmit_pkts;
                break;
        default:
                PMD_DRV_LOG(ERR, "The version of firmware is not correct.");
@@ -295,7 +297,6 @@ nfp_netvf_ethdev_ops_mount(struct nfp_net_hw *hw, struct 
rte_eth_dev *eth_dev)
 
        eth_dev->rx_queue_count = nfp_net_rx_queue_count;
        eth_dev->rx_pkt_burst = &nfp_net_recv_pkts;
-       eth_dev->tx_pkt_burst = &nfp_net_nfd3_xmit_pkts;
 
        return 0;
 }
diff --git a/drivers/net/nfp/nfp_rxtx.c b/drivers/net/nfp/nfp_rxtx.c
index 4f422c5090..63729261c8 100644
--- a/drivers/net/nfp/nfp_rxtx.c
+++ b/drivers/net/nfp/nfp_rxtx.c
@@ -20,6 +20,9 @@
 #include "nfp_rxtx.h"
 #include "nfp_logs.h"
 #include "nfp_ctrl.h"
+#include "nfpcore/nfp_mip.h"
+#include "nfpcore/nfp_rtsym.h"
+#include "nfpcore/nfp-common/nfp_platform.h"
 
 static int
 nfp_net_rx_fill_freelist(struct nfp_net_rxq *rxq)
@@ -1104,3 +1107,283 @@ nfp_net_nfdk_tx_queue_setup(struct rte_eth_dev *dev,
 
        return 0;
 }
+
+static inline uint32_t
+nfp_net_nfdk_free_tx_desc(struct nfp_net_txq *txq)
+{
+       uint32_t free_desc;
+
+       if (txq->wr_p >= txq->rd_p)
+               free_desc = txq->tx_count - (txq->wr_p - txq->rd_p);
+       else
+               free_desc = txq->rd_p - txq->wr_p;
+
+       return (free_desc > NFDK_TX_DESC_STOP_CNT) ?
+               (free_desc - NFDK_TX_DESC_STOP_CNT) : 0;
+}
+
+static inline uint32_t
+nfp_net_nfdk_txq_full(struct nfp_net_txq *txq)
+{
+       return (nfp_net_nfdk_free_tx_desc(txq) < txq->tx_free_thresh);
+}
+
+static inline int
+nfp_net_nfdk_headlen_to_segs(unsigned int headlen)
+{
+       return DIV_ROUND_UP(headlen +
+                       NFDK_TX_MAX_DATA_PER_DESC -
+                       NFDK_TX_MAX_DATA_PER_HEAD,
+                       NFDK_TX_MAX_DATA_PER_DESC);
+}
+
+static int
+nfp_net_nfdk_tx_maybe_close_block(struct nfp_net_txq *txq, struct rte_mbuf 
*pkt)
+{
+       unsigned int n_descs, wr_p, i, nop_slots;
+       struct rte_mbuf *pkt_temp;
+
+       pkt_temp = pkt;
+       n_descs = nfp_net_nfdk_headlen_to_segs(pkt_temp->data_len);
+       while (pkt_temp->next) {
+               pkt_temp = pkt_temp->next;
+               n_descs += DIV_ROUND_UP(pkt_temp->data_len, 
NFDK_TX_MAX_DATA_PER_DESC);
+       }
+
+       if (unlikely(n_descs > NFDK_TX_DESC_GATHER_MAX))
+               return -EINVAL;
+
+       n_descs += !!(pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG);
+
+       if (round_down(txq->wr_p, NFDK_TX_DESC_BLOCK_CNT) !=
+                       round_down(txq->wr_p + n_descs, NFDK_TX_DESC_BLOCK_CNT))
+               goto close_block;
+
+       if ((uint32_t)txq->data_pending + pkt->pkt_len > 
NFDK_TX_MAX_DATA_PER_BLOCK)
+               goto close_block;
+
+       return 0;
+
+close_block:
+       wr_p = txq->wr_p;
+       nop_slots = D_BLOCK_CPL(wr_p);
+
+       memset(&txq->ktxds[wr_p], 0, nop_slots * sizeof(struct 
nfp_net_nfdk_tx_desc));
+       for (i = wr_p; i < nop_slots + wr_p; i++) {
+               if (txq->txbufs[i].mbuf) {
+                       rte_pktmbuf_free_seg(txq->txbufs[i].mbuf);
+                       txq->txbufs[i].mbuf = NULL;
+               }
+       }
+       txq->data_pending = 0;
+       txq->wr_p = D_IDX(txq, txq->wr_p + nop_slots);
+
+       return nop_slots;
+}
+
+static inline uint64_t
+nfp_net_nfdk_tx_cksum(struct nfp_net_txq *txq, struct rte_mbuf *mb,
+               uint64_t flags)
+{
+       uint64_t ol_flags;
+       struct nfp_net_hw *hw = txq->hw;
+
+       if (!(hw->cap & NFP_NET_CFG_CTRL_TXCSUM))
+               return flags;
+
+       ol_flags = mb->ol_flags;
+
+       /* IPv6 does not need checksum */
+       if (ol_flags & RTE_MBUF_F_TX_IP_CKSUM)
+               flags |= NFDK_DESC_TX_L3_CSUM;
+
+       if (ol_flags & RTE_MBUF_F_TX_L4_MASK)
+               flags |= NFDK_DESC_TX_L4_CSUM;
+
+       return flags;
+}
+
+static inline uint64_t
+nfp_net_nfdk_tx_tso(struct nfp_net_txq *txq, struct rte_mbuf *mb)
+{
+       uint64_t ol_flags;
+       struct nfp_net_nfdk_tx_desc txd;
+       struct nfp_net_hw *hw = txq->hw;
+
+       if (!(hw->cap & NFP_NET_CFG_CTRL_LSO_ANY))
+               goto clean_txd;
+
+       ol_flags = mb->ol_flags;
+
+       if (!(ol_flags & RTE_MBUF_F_TX_TCP_SEG))
+               goto clean_txd;
+
+       txd.l3_offset = mb->l2_len;
+       txd.l4_offset = mb->l2_len + mb->l3_len;
+       txd.lso_meta_res = 0;
+       txd.mss = rte_cpu_to_le_16(mb->tso_segsz);
+       txd.lso_hdrlen = mb->l2_len + mb->l3_len + mb->l4_len;
+       txd.lso_totsegs = (mb->pkt_len + mb->tso_segsz) / mb->tso_segsz;
+
+clean_txd:
+       txd.l3_offset = 0;
+       txd.l4_offset = 0;
+       txd.lso_hdrlen = 0;
+       txd.mss = 0;
+       txd.lso_totsegs = 0;
+       txd.lso_meta_res = 0;
+
+       return txd.raw;
+}
+
+uint16_t
+nfp_net_nfdk_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t 
nb_pkts)
+{
+       uint32_t buf_idx;
+       uint64_t dma_addr;
+       uint16_t free_descs;
+       uint32_t npkts = 0;
+       uint64_t metadata = 0;
+       uint16_t issued_descs = 0;
+       struct nfp_net_txq *txq;
+       struct nfp_net_hw *hw;
+       struct nfp_net_nfdk_tx_desc *ktxds;
+       struct rte_mbuf *pkt, *temp_pkt;
+       struct rte_mbuf **lmbuf;
+
+       txq = tx_queue;
+       hw = txq->hw;
+
+       PMD_TX_LOG(DEBUG, "working for queue %u at pos %d and %u packets",
+               txq->qidx, txq->wr_p, nb_pkts);
+
+       if ((nfp_net_nfdk_free_tx_desc(txq) < NFDK_TX_DESC_PER_SIMPLE_PKT *
+                       nb_pkts) || (nfp_net_nfdk_txq_full(txq)))
+               nfp_net_tx_free_bufs(txq);
+
+       free_descs = (uint16_t)nfp_net_nfdk_free_tx_desc(txq);
+       if (unlikely(free_descs == 0))
+               return 0;
+
+       PMD_TX_LOG(DEBUG, "queue: %u. Sending %u packets", txq->qidx, nb_pkts);
+       /* Sending packets */
+       while ((npkts < nb_pkts) && free_descs) {
+               uint32_t type, dma_len, dlen_type, tmp_dlen;
+               int nop_descs, used_descs;
+
+               pkt = *(tx_pkts + npkts);
+               nop_descs = nfp_net_nfdk_tx_maybe_close_block(txq, pkt);
+               if (nop_descs < 0)
+                       goto xmit_end;
+
+               issued_descs += nop_descs;
+               ktxds = &txq->ktxds[txq->wr_p];
+               /* Grabbing the mbuf linked to the current descriptor */
+               buf_idx = txq->wr_p;
+               lmbuf = &txq->txbufs[buf_idx++].mbuf;
+               /* Warming the cache for releasing the mbuf later on */
+               RTE_MBUF_PREFETCH_TO_FREE(*lmbuf);
+
+               temp_pkt = pkt;
+
+               if (unlikely(pkt->nb_segs > 1 &&
+                               !(hw->cap & NFP_NET_CFG_CTRL_GATHER))) {
+                       PMD_INIT_LOG(INFO, "NFP_NET_CFG_CTRL_GATHER not set");
+                       PMD_INIT_LOG(INFO, "Multisegment packet unsupported");
+                       goto xmit_end;
+               }
+
+               /*
+                * Checksum and VLAN flags just in the first descriptor for a
+                * multisegment packet, but TSO info needs to be in all of them.
+                */
+
+               dma_len = pkt->data_len;
+               if ((hw->cap & NFP_NET_CFG_CTRL_LSO_ANY) &&
+                               (pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG)) {
+                       type = NFDK_DESC_TX_TYPE_TSO;
+               } else if (!pkt->next && dma_len < NFDK_TX_MAX_DATA_PER_HEAD) {
+                       type = NFDK_DESC_TX_TYPE_SIMPLE;
+               } else {
+                       type = NFDK_DESC_TX_TYPE_GATHER;
+               }
+               dma_len -= 1;
+               dlen_type = (NFDK_DESC_TX_DMA_LEN_HEAD & dma_len) |
+                       (NFDK_DESC_TX_TYPE_HEAD & (type << 12));
+               ktxds->dma_len_type = rte_cpu_to_le_16(dlen_type);
+               dma_addr = rte_mbuf_data_iova(pkt);
+               PMD_TX_LOG(DEBUG, "Working with mbuf at dma address:"
+                               "%" PRIx64 "", dma_addr);
+               ktxds->dma_addr_hi = rte_cpu_to_le_16(dma_addr >> 32);
+               ktxds->dma_addr_lo = rte_cpu_to_le_32(dma_addr & 0xffffffff);
+               ktxds++;
+
+               tmp_dlen = dlen_type & NFDK_DESC_TX_DMA_LEN_HEAD;
+               dma_len -= tmp_dlen;
+               dma_addr += tmp_dlen + 1;
+
+               while (pkt) {
+                       if (*lmbuf)
+                               rte_pktmbuf_free_seg(*lmbuf);
+                       *lmbuf = pkt;
+                       while (dma_len > 0) {
+                               dma_len -= 1;
+                               dlen_type = NFDK_DESC_TX_DMA_LEN & dma_len;
+
+                               ktxds->dma_len_type = 
rte_cpu_to_le_16(dlen_type);
+                               ktxds->dma_addr_hi = rte_cpu_to_le_16(dma_addr 
>> 32);
+                               ktxds->dma_addr_lo = rte_cpu_to_le_32(dma_addr 
& 0xffffffff);
+                               ktxds++;
+
+                               dma_len -= dlen_type;
+                               dma_addr += dlen_type + 1;
+                       }
+
+                       if (!pkt->next)
+                               break;
+
+                       pkt = pkt->next;
+                       dma_len = pkt->data_len;
+                       dma_addr = rte_mbuf_data_iova(pkt);
+                       PMD_TX_LOG(DEBUG, "Working with mbuf at dma address:"
+                               "%" PRIx64 "", dma_addr);
+
+                       lmbuf = &txq->txbufs[buf_idx++].mbuf;
+               }
+
+               (ktxds - 1)->dma_len_type = rte_cpu_to_le_16(dlen_type | 
NFDK_DESC_TX_EOP);
+
+               ktxds->raw = rte_cpu_to_le_64(nfp_net_nfdk_tx_cksum(txq, 
temp_pkt, metadata));
+               ktxds++;
+
+               if ((hw->cap & NFP_NET_CFG_CTRL_LSO_ANY) &&
+                               (temp_pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG)) {
+                       ktxds->raw = rte_cpu_to_le_64(nfp_net_nfdk_tx_tso(txq, 
temp_pkt));
+                       ktxds++;
+               }
+
+               used_descs = ktxds - txq->ktxds - txq->wr_p;
+               if (round_down(txq->wr_p, NFDK_TX_DESC_BLOCK_CNT) !=
+                       round_down(txq->wr_p + used_descs - 1, 
NFDK_TX_DESC_BLOCK_CNT)) {
+                       PMD_INIT_LOG(INFO, "Used descs cross block boundary");
+                       goto xmit_end;
+               }
+
+               txq->wr_p = D_IDX(txq, txq->wr_p + used_descs);
+               if (txq->wr_p % NFDK_TX_DESC_BLOCK_CNT)
+                       txq->data_pending += temp_pkt->pkt_len;
+               else
+                       txq->data_pending = 0;
+
+               issued_descs += used_descs;
+               npkts++;
+               free_descs = (uint16_t)nfp_net_nfdk_free_tx_desc(txq);
+       }
+
+xmit_end:
+       /* Increment write pointers. Force memory write before we let HW know */
+       rte_wmb();
+       nfp_qcp_ptr_add(txq->qcp_q, NFP_QCP_WRITE_PTR, issued_descs);
+
+       return npkts;
+}
diff --git a/drivers/net/nfp/nfp_rxtx.h b/drivers/net/nfp/nfp_rxtx.h
index ba8ffbd1ff..5c005d74e7 100644
--- a/drivers/net/nfp/nfp_rxtx.h
+++ b/drivers/net/nfp/nfp_rxtx.h
@@ -352,6 +352,9 @@ int nfp_net_nfdk_tx_queue_setup(struct rte_eth_dev *dev,
                uint16_t nb_desc,
                unsigned int socket_id,
                const struct rte_eth_txconf *tx_conf);
+uint16_t nfp_net_nfdk_xmit_pkts(void *tx_queue,
+               struct rte_mbuf **tx_pkts,
+               uint16_t nb_pkts);
 
 #endif /* _NFP_RXTX_H_ */
 /*
-- 
2.27.0

Reply via email to