net/ngbe: support Tx queue setup/release
authorJiawen Wu <jiawenwu@trustnetic.com>
Thu, 8 Jul 2021 09:32:33 +0000 (17:32 +0800)
committerAndrew Rybchenko <Andrew.Rybchenko@oktetlabs.ru>
Mon, 12 Jul 2021 15:55:22 +0000 (17:55 +0200)
Setup device Tx queue and release Tx queue.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
drivers/net/ngbe/ngbe_ethdev.c
drivers/net/ngbe/ngbe_ethdev.h
drivers/net/ngbe/ngbe_rxtx.c
drivers/net/ngbe/ngbe_rxtx.h

index 015b179..aa042f8 100644 (file)
@@ -44,6 +44,14 @@ static const struct rte_eth_desc_lim rx_desc_lim = {
        .nb_align = NGBE_RXD_ALIGN,
 };
 
+static const struct rte_eth_desc_lim tx_desc_lim = {
+       .nb_max = NGBE_RING_DESC_MAX,
+       .nb_min = NGBE_RING_DESC_MIN,
+       .nb_align = NGBE_TXD_ALIGN,
+       .nb_seg_max = NGBE_TX_MAX_SEG,
+       .nb_mtu_seg_max = NGBE_TX_MAX_SEG,
+};
+
 static const struct eth_dev_ops ngbe_eth_dev_ops;
 
 static inline void
@@ -283,6 +291,7 @@ ngbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        struct ngbe_hw *hw = ngbe_dev_hw(dev);
 
        dev_info->max_rx_queues = (uint16_t)hw->mac.max_rx_queues;
+       dev_info->max_tx_queues = (uint16_t)hw->mac.max_tx_queues;
 
        dev_info->default_rxconf = (struct rte_eth_rxconf) {
                .rx_thresh = {
@@ -295,14 +304,27 @@ ngbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                .offloads = 0,
        };
 
+       dev_info->default_txconf = (struct rte_eth_txconf) {
+               .tx_thresh = {
+                       .pthresh = NGBE_DEFAULT_TX_PTHRESH,
+                       .hthresh = NGBE_DEFAULT_TX_HTHRESH,
+                       .wthresh = NGBE_DEFAULT_TX_WTHRESH,
+               },
+               .tx_free_thresh = NGBE_DEFAULT_TX_FREE_THRESH,
+               .offloads = 0,
+       };
+
        dev_info->rx_desc_lim = rx_desc_lim;
+       dev_info->tx_desc_lim = tx_desc_lim;
 
        dev_info->speed_capa = ETH_LINK_SPEED_1G | ETH_LINK_SPEED_100M |
                                ETH_LINK_SPEED_10M;
 
        /* Driver-preferred Rx/Tx parameters */
        dev_info->default_rxportconf.nb_queues = 1;
+       dev_info->default_txportconf.nb_queues = 1;
        dev_info->default_rxportconf.ring_size = 256;
+       dev_info->default_txportconf.ring_size = 256;
 
        return 0;
 }
@@ -594,6 +616,8 @@ static const struct eth_dev_ops ngbe_eth_dev_ops = {
        .link_update                = ngbe_dev_link_update,
        .rx_queue_setup             = ngbe_dev_rx_queue_setup,
        .rx_queue_release           = ngbe_dev_rx_queue_release,
+       .tx_queue_setup             = ngbe_dev_tx_queue_setup,
+       .tx_queue_release           = ngbe_dev_tx_queue_release,
 };
 
 RTE_PMD_REGISTER_PCI(net_ngbe, rte_ngbe_pmd);
index 6d9aa5e..304ee48 100644 (file)
@@ -61,11 +61,17 @@ ngbe_dev_intr(struct rte_eth_dev *dev)
 
 void ngbe_dev_rx_queue_release(void *rxq);
 
+void ngbe_dev_tx_queue_release(void *txq);
+
 int  ngbe_dev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
                uint16_t nb_rx_desc, unsigned int socket_id,
                const struct rte_eth_rxconf *rx_conf,
                struct rte_mempool *mb_pool);
 
+int  ngbe_dev_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+               uint16_t nb_tx_desc, unsigned int socket_id,
+               const struct rte_eth_txconf *tx_conf);
+
 int
 ngbe_dev_link_update_share(struct rte_eth_dev *dev,
                int wait_to_complete);
@@ -82,4 +88,9 @@ ngbe_dev_link_update_share(struct rte_eth_dev *dev,
 #define NGBE_DEFAULT_RX_HTHRESH      8
 #define NGBE_DEFAULT_RX_WTHRESH      0
 
+#define NGBE_DEFAULT_TX_FREE_THRESH  32
+#define NGBE_DEFAULT_TX_PTHRESH      32
+#define NGBE_DEFAULT_TX_HTHRESH      0
+#define NGBE_DEFAULT_TX_WTHRESH      0
+
 #endif /* _NGBE_ETHDEV_H_ */
index 7b37394..99fbd53 100644 (file)
 #include "ngbe_ethdev.h"
 #include "ngbe_rxtx.h"
 
+/*********************************************************************
+ *
+ *  Queue management functions
+ *
+ **********************************************************************/
+
+static void
+ngbe_tx_queue_release_mbufs(struct ngbe_tx_queue *txq)
+{
+       unsigned int i;
+
+       if (txq->sw_ring != NULL) {
+               for (i = 0; i < txq->nb_tx_desc; i++) {
+                       if (txq->sw_ring[i].mbuf != NULL) {
+                               rte_pktmbuf_free_seg(txq->sw_ring[i].mbuf);
+                               txq->sw_ring[i].mbuf = NULL;
+                       }
+               }
+       }
+}
+
+static void
+ngbe_tx_free_swring(struct ngbe_tx_queue *txq)
+{
+       if (txq != NULL)
+               rte_free(txq->sw_ring);
+}
+
+static void
+ngbe_tx_queue_release(struct ngbe_tx_queue *txq)
+{
+       if (txq != NULL) {
+               if (txq->ops != NULL) {
+                       txq->ops->release_mbufs(txq);
+                       txq->ops->free_swring(txq);
+               }
+               rte_free(txq);
+       }
+}
+
+void
+ngbe_dev_tx_queue_release(void *txq)
+{
+       ngbe_tx_queue_release(txq);
+}
+
+/* (Re)set dynamic ngbe_tx_queue fields to defaults */
+static void
+ngbe_reset_tx_queue(struct ngbe_tx_queue *txq)
+{
+       static const struct ngbe_tx_desc zeroed_desc = {0};
+       struct ngbe_tx_entry *txe = txq->sw_ring;
+       uint16_t prev, i;
+
+       /* Zero out HW ring memory */
+       for (i = 0; i < txq->nb_tx_desc; i++)
+               txq->tx_ring[i] = zeroed_desc;
+
+       /* Initialize SW ring entries */
+       prev = (uint16_t)(txq->nb_tx_desc - 1);
+       for (i = 0; i < txq->nb_tx_desc; i++) {
+               /* the ring can also be modified by hardware */
+               volatile struct ngbe_tx_desc *txd = &txq->tx_ring[i];
+
+               txd->dw3 = rte_cpu_to_le_32(NGBE_TXD_DD);
+               txe[i].mbuf = NULL;
+               txe[i].last_id = i;
+               txe[prev].next_id = i;
+               prev = i;
+       }
+
+       txq->tx_next_dd = (uint16_t)(txq->tx_free_thresh - 1);
+       txq->tx_tail = 0;
+
+       /*
+        * Always allow 1 descriptor to be un-allocated to avoid
+        * a H/W race condition
+        */
+       txq->last_desc_cleaned = (uint16_t)(txq->nb_tx_desc - 1);
+       txq->nb_tx_free = (uint16_t)(txq->nb_tx_desc - 1);
+       txq->ctx_curr = 0;
+       memset((void *)&txq->ctx_cache, 0,
+               NGBE_CTX_NUM * sizeof(struct ngbe_ctx_info));
+}
+
+static const struct ngbe_txq_ops def_txq_ops = {
+       .release_mbufs = ngbe_tx_queue_release_mbufs,
+       .free_swring = ngbe_tx_free_swring,
+       .reset = ngbe_reset_tx_queue,
+};
+
+int
+ngbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
+                        uint16_t queue_idx,
+                        uint16_t nb_desc,
+                        unsigned int socket_id,
+                        const struct rte_eth_txconf *tx_conf)
+{
+       const struct rte_memzone *tz;
+       struct ngbe_tx_queue *txq;
+       struct ngbe_hw     *hw;
+       uint16_t tx_free_thresh;
+
+       PMD_INIT_FUNC_TRACE();
+       hw = ngbe_dev_hw(dev);
+
+       /*
+        * The Tx descriptor ring will be cleaned after txq->tx_free_thresh
+        * descriptors are used or if the number of descriptors required
+        * to transmit a packet is greater than the number of free Tx
+        * descriptors.
+        * One descriptor in the Tx ring is used as a sentinel to avoid a
+        * H/W race condition, hence the maximum threshold constraints.
+        * When set to zero use default values.
+        */
+       tx_free_thresh = (uint16_t)((tx_conf->tx_free_thresh) ?
+                       tx_conf->tx_free_thresh : DEFAULT_TX_FREE_THRESH);
+       if (tx_free_thresh >= (nb_desc - 3)) {
+               PMD_INIT_LOG(ERR,
+                            "tx_free_thresh must be less than the number of TX descriptors minus 3. (tx_free_thresh=%u port=%d queue=%d)",
+                            (unsigned int)tx_free_thresh,
+                            (int)dev->data->port_id, (int)queue_idx);
+               return -(EINVAL);
+       }
+
+       if (nb_desc % tx_free_thresh != 0) {
+               PMD_INIT_LOG(ERR,
+                            "tx_free_thresh must be a divisor of the number of Tx descriptors. (tx_free_thresh=%u port=%d queue=%d)",
+                            (unsigned int)tx_free_thresh,
+                            (int)dev->data->port_id, (int)queue_idx);
+               return -(EINVAL);
+       }
+
+       /* Free memory prior to re-allocation if needed... */
+       if (dev->data->tx_queues[queue_idx] != NULL) {
+               ngbe_tx_queue_release(dev->data->tx_queues[queue_idx]);
+               dev->data->tx_queues[queue_idx] = NULL;
+       }
+
+       /* First allocate the Tx queue data structure */
+       txq = rte_zmalloc_socket("ethdev Tx queue",
+                                sizeof(struct ngbe_tx_queue),
+                                RTE_CACHE_LINE_SIZE, socket_id);
+       if (txq == NULL)
+               return -ENOMEM;
+
+       /*
+        * Allocate Tx ring hardware descriptors. A memzone large enough to
+        * handle the maximum ring size is allocated in order to allow for
+        * resizing in later calls to the queue setup function.
+        */
+       tz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_idx,
+                       sizeof(struct ngbe_tx_desc) * NGBE_RING_DESC_MAX,
+                       NGBE_ALIGN, socket_id);
+       if (tz == NULL) {
+               ngbe_tx_queue_release(txq);
+               return -ENOMEM;
+       }
+
+       txq->nb_tx_desc = nb_desc;
+       txq->tx_free_thresh = tx_free_thresh;
+       txq->pthresh = tx_conf->tx_thresh.pthresh;
+       txq->hthresh = tx_conf->tx_thresh.hthresh;
+       txq->wthresh = tx_conf->tx_thresh.wthresh;
+       txq->queue_id = queue_idx;
+       txq->reg_idx = queue_idx;
+       txq->port_id = dev->data->port_id;
+       txq->ops = &def_txq_ops;
+       txq->tx_deferred_start = tx_conf->tx_deferred_start;
+
+       txq->tdt_reg_addr = NGBE_REG_ADDR(hw, NGBE_TXWP(txq->reg_idx));
+       txq->tdc_reg_addr = NGBE_REG_ADDR(hw, NGBE_TXCFG(txq->reg_idx));
+
+       txq->tx_ring_phys_addr = TMZ_PADDR(tz);
+       txq->tx_ring = (struct ngbe_tx_desc *)TMZ_VADDR(tz);
+
+       /* Allocate software ring */
+       txq->sw_ring = rte_zmalloc_socket("txq->sw_ring",
+                               sizeof(struct ngbe_tx_entry) * nb_desc,
+                               RTE_CACHE_LINE_SIZE, socket_id);
+       if (txq->sw_ring == NULL) {
+               ngbe_tx_queue_release(txq);
+               return -ENOMEM;
+       }
+       PMD_INIT_LOG(DEBUG,
+                    "sw_ring=%p hw_ring=%p dma_addr=0x%" PRIx64,
+                    txq->sw_ring, txq->tx_ring, txq->tx_ring_phys_addr);
+
+       txq->ops->reset(txq);
+
+       dev->data->tx_queues[queue_idx] = txq;
+
+       return 0;
+}
+
 /**
  * ngbe_free_sc_cluster - free the not-yet-completed scattered cluster
  *
index 2ad6890..4b824d4 100644 (file)
@@ -43,11 +43,41 @@ struct ngbe_rx_desc {
        } qw1; /* also as r.hdr_addr */
 };
 
+/*****************************************************************************
+ * Transmit Descriptor
+ *****************************************************************************/
+/**
+ * Transmit Context Descriptor (NGBE_TXD_TYP=CTXT)
+ **/
+struct ngbe_tx_ctx_desc {
+       rte_le32_t dw0; /* w.vlan_macip_lens  */
+       rte_le32_t dw1; /* w.seqnum_seed      */
+       rte_le32_t dw2; /* w.type_tucmd_mlhl  */
+       rte_le32_t dw3; /* w.mss_l4len_idx    */
+};
+
+/* @ngbe_tx_ctx_desc.dw3 */
+#define NGBE_TXD_DD               MS(0, 0x1) /* descriptor done */
+
+/**
+ * Transmit Data Descriptor (NGBE_TXD_TYP=DATA)
+ **/
+struct ngbe_tx_desc {
+       rte_le64_t qw0; /* r.buffer_addr ,  w.reserved    */
+       rte_le32_t dw2; /* r.cmd_type_len,  w.nxtseq_seed */
+       rte_le32_t dw3; /* r.olinfo_status, w.status      */
+};
+
 #define RTE_PMD_NGBE_RX_MAX_BURST 32
 
 #define RX_RING_SZ ((NGBE_RING_DESC_MAX + RTE_PMD_NGBE_RX_MAX_BURST) * \
                    sizeof(struct ngbe_rx_desc))
 
+#define NGBE_TX_MAX_SEG                    40
+
+#ifndef DEFAULT_TX_FREE_THRESH
+#define DEFAULT_TX_FREE_THRESH 32
+#endif
 
 /**
  * Structure associated with each descriptor of the Rx ring of a Rx queue.
@@ -60,6 +90,15 @@ struct ngbe_scattered_rx_entry {
        struct rte_mbuf *fbuf; /**< First segment of the fragmented packet. */
 };
 
+/**
+ * Structure associated with each descriptor of the Tx ring of a Tx queue.
+ */
+struct ngbe_tx_entry {
+       struct rte_mbuf *mbuf; /**< mbuf associated with Tx desc, if any. */
+       uint16_t next_id; /**< Index of next descriptor in ring. */
+       uint16_t last_id; /**< Index of last scattered descriptor. */
+};
+
 /**
  * Structure associated with each Rx queue.
  */
@@ -97,4 +136,63 @@ struct ngbe_rx_queue {
        struct rte_mbuf *rx_stage[RTE_PMD_NGBE_RX_MAX_BURST * 2];
 };
 
+/**
+ * NGBE CTX Constants
+ */
+enum ngbe_ctx_num {
+       NGBE_CTX_0    = 0, /**< CTX0 */
+       NGBE_CTX_1    = 1, /**< CTX1  */
+       NGBE_CTX_NUM  = 2, /**< CTX NUMBER  */
+};
+
+/**
+ * Structure to check if new context need be built
+ */
+struct ngbe_ctx_info {
+       uint64_t flags;           /**< ol_flags for context build. */
+};
+
+/**
+ * Structure associated with each Tx queue.
+ */
+struct ngbe_tx_queue {
+       /** Tx ring virtual address */
+       volatile struct ngbe_tx_desc *tx_ring;
+
+       uint64_t             tx_ring_phys_addr; /**< Tx ring DMA address */
+       struct ngbe_tx_entry *sw_ring; /**< address of SW ring for scalar PMD */
+       volatile uint32_t    *tdt_reg_addr; /**< Address of TDT register */
+       volatile uint32_t    *tdc_reg_addr; /**< Address of TDC register */
+       uint16_t             nb_tx_desc;    /**< number of Tx descriptors */
+       uint16_t             tx_tail;       /**< current value of TDT reg */
+       /**
+        * Start freeing Tx buffers if there are less free descriptors than
+        * this value.
+        */
+       uint16_t             tx_free_thresh;
+       /** Index to last Tx descriptor to have been cleaned */
+       uint16_t             last_desc_cleaned;
+       /** Total number of Tx descriptors ready to be allocated */
+       uint16_t             nb_tx_free;
+       uint16_t             tx_next_dd;    /**< next desc to scan for DD bit */
+       uint16_t             queue_id;      /**< Tx queue index */
+       uint16_t             reg_idx;       /**< Tx queue register index */
+       uint16_t             port_id;       /**< Device port identifier */
+       uint8_t              pthresh;       /**< Prefetch threshold register */
+       uint8_t              hthresh;       /**< Host threshold register */
+       uint8_t              wthresh;       /**< Write-back threshold reg */
+       uint32_t             ctx_curr;      /**< Hardware context states */
+       /** Hardware context0 history */
+       struct ngbe_ctx_info ctx_cache[NGBE_CTX_NUM];
+       uint8_t              tx_deferred_start; /**< not in global dev start */
+
+       const struct ngbe_txq_ops *ops;       /**< txq ops */
+};
+
+struct ngbe_txq_ops {
+       void (*release_mbufs)(struct ngbe_tx_queue *txq);
+       void (*free_swring)(struct ngbe_tx_queue *txq);
+       void (*reset)(struct ngbe_tx_queue *txq);
+};
+
 #endif /* _NGBE_RXTX_H_ */