@@ -4,6 +4,7 @@
; Refer to default.ini for the full list of available PMD features.
;
[Features]
+RSS hash = Y
Packet type parsing = Y
Basic stats = Y
L3 checksum offload = Y
@@ -110,6 +110,17 @@
#define ENETC4_SITFRM0 0x328
#define ENETC4_SITDFCR 0x340
+/* Control BDR regs */
+#define ENETC4_SICBDRMR 0x800
+#define ENETC4_SICBDRSR 0x804 /* RO */
+#define ENETC4_SICBDRBAR0 0x810
+#define ENETC4_SICBDRBAR1 0x814
+#define ENETC4_SICBDRPIR 0x818
+#define ENETC4_SICBDRCIR 0x81c
+#define ENETC4_SICBDRLENR 0x820
+#define ENETC4_SICTR0 0x18
+#define ENETC4_SICTR1 0x1c
+
/* general register accessors */
#define enetc4_rd_reg(reg) rte_read32((void *)(reg))
#define enetc4_wr_reg(reg, val) rte_write32((val), (void *)(reg))
@@ -22,6 +22,10 @@
/* SI regs, offset: 0h */
#define ENETC_SIMR 0x0
#define ENETC_SIMR_EN BIT(31)
+#define ENETC_SIMR_RSSE BIT(0)
+
+/* BDR grouping*/
+#define ENETC_SIRBGCR 0x38
#define ENETC_SICAR0 0x40
#define ENETC_SICAR0_COHERENT 0x2B2B6727
@@ -29,6 +33,7 @@
#define ENETC_SIPMAR1 0x84
#define ENETC_SICAPR0 0x900
+#define ENETC_SICAPR0_BDR_MASK 0xFF
#define ENETC_SICAPR1 0x904
#define ENETC_SIMSITRV(n) (0xB00 + (n) * 0x4)
@@ -36,6 +41,11 @@
#define ENETC_SICCAPR 0x1200
+#define ENETC_SIPCAPR0 0x20
+#define ENETC_SIPCAPR0_RSS BIT(8)
+#define ENETC_SIRSSCAPR 0x1600
+#define ENETC_SIRSSCAPR_GET_NUM_RSS(val) (BIT((val) & 0xf) * 32)
+
/* enum for BD type */
enum enetc_bdr_type {TX, RX};
@@ -44,6 +54,7 @@ enum enetc_bdr_type {TX, RX};
/* RX BDR reg offsets */
#define ENETC_RBMR 0x0 /* RX BDR mode register*/
#define ENETC_RBMR_EN BIT(31)
+#define ENETC_BMR_RESET 0x0 /* BDR reset*/
#define ENETC_RBSR 0x4 /* Rx BDR status register*/
#define ENETC_RBBSR 0x8 /* Rx BDR buffer size register*/
@@ -231,15 +242,6 @@ struct enetc_eth_mac_info {
uint8_t get_link_status;
};
-struct enetc_eth_hw {
- struct rte_eth_dev *ndev;
- struct enetc_hw hw;
- uint16_t device_id;
- uint16_t vendor_id;
- uint8_t revision_id;
- struct enetc_eth_mac_info mac;
-};
-
/* Transmit Descriptor */
struct enetc_tx_desc {
uint64_t addr;
@@ -292,5 +294,4 @@ union enetc_rx_bd {
};
} r;
};
-
#endif
@@ -10,7 +10,9 @@
#include "compat.h"
#include "base/enetc_hw.h"
+#include "base/enetc4_hw.h"
#include "enetc_logs.h"
+#include "ntmp.h"
#define PCI_VENDOR_ID_FREESCALE 0x1957
@@ -50,6 +52,18 @@
RTE_MBUF_F_TX_TCP_CKSUM | \
RTE_MBUF_F_TX_UDP_CKSUM)
+#define ENETC_CBD(R, i) (&(((struct enetc_cbd *)((R).bd_base))[i]))
+#define ENETC_CBDR_TIMEOUT 1000 /* In multiple of ENETC_CBDR_DELAY */
+#define ENETC_CBDR_DELAY 100 /* usecs */
+#define ENETC_CBDR_SIZE 64
+#define ENETC_CBDR_ALIGN 128
+
+/* supported RSS */
+#define ENETC_RSS_OFFLOAD_ALL ( \
+ RTE_ETH_RSS_IP | \
+ RTE_ETH_RSS_UDP | \
+ RTE_ETH_RSS_TCP)
+
struct enetc_swbd {
struct rte_mbuf *buffer_addr;
};
@@ -76,6 +90,19 @@ struct enetc_bdr {
uint64_t ierrors;
};
+struct enetc_eth_hw {
+ struct rte_eth_dev *ndev;
+ struct enetc_hw hw;
+ uint16_t device_id;
+ uint16_t vendor_id;
+ uint8_t revision_id;
+ struct enetc_eth_mac_info mac;
+ struct netc_cbdr cbdr;
+ uint32_t num_rss;
+ uint32_t max_rx_queues;
+ uint32_t max_tx_queues;
+};
+
/*
* Structure to store private data for each driver instance (for each port).
*/
@@ -102,7 +129,7 @@ struct enetc_eth_adapter {
int enetc4_pci_remove(struct rte_pci_device *pci_dev);
int enetc4_dev_configure(struct rte_eth_dev *dev);
int enetc4_dev_close(struct rte_eth_dev *dev);
-int enetc4_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
+int enetc4_dev_infos_get(struct rte_eth_dev *dev,
struct rte_eth_dev_info *dev_info);
int enetc4_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
uint16_t nb_rx_desc, unsigned int socket_id __rte_unused,
@@ -149,4 +176,12 @@ enetc_bd_unused(struct enetc_bdr *bdr)
return bdr->bd_count + bdr->next_to_clean - bdr->next_to_use - 1;
}
+
+/* CBDR prototypes */
+int enetc4_setup_cbdr(struct rte_eth_dev *dev, struct enetc_hw *hw,
+ int bd_count, struct netc_cbdr *cbdr);
+void netc_free_cbdr(struct netc_cbdr *cbdr);
+int ntmp_rsst_query_or_update_entry(struct netc_cbdr *cbdr, uint32_t *table,
+ int count, bool query);
+
#endif /* _ENETC_H_ */
@@ -7,7 +7,6 @@
#include <dpaax_iova_table.h>
#include "kpage_ncache_api.h"
-#include "base/enetc4_hw.h"
#include "enetc_logs.h"
#include "enetc.h"
@@ -134,10 +133,14 @@ enetc4_mac_init(struct enetc_eth_hw *hw, struct rte_eth_dev *eth_dev)
}
int
-enetc4_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
+enetc4_dev_infos_get(struct rte_eth_dev *dev,
struct rte_eth_dev_info *dev_info)
{
+ struct enetc_eth_hw *hw =
+ ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
PMD_INIT_FUNC_TRACE();
+
dev_info->rx_desc_lim = (struct rte_eth_desc_lim) {
.nb_max = MAX_BD_COUNT,
.nb_min = MIN_BD_COUNT,
@@ -148,11 +151,12 @@ enetc4_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
.nb_min = MIN_BD_COUNT,
.nb_align = BD_ALIGN,
};
- dev_info->max_rx_queues = MAX_RX_RINGS;
- dev_info->max_tx_queues = MAX_TX_RINGS;
+ dev_info->max_rx_queues = hw->max_rx_queues;
+ dev_info->max_tx_queues = hw->max_tx_queues;
dev_info->max_rx_pktlen = ENETC4_MAC_MAXFRM_SIZE;
dev_info->rx_offload_capa = dev_rx_offloads_sup;
dev_info->tx_offload_capa = dev_tx_offloads_sup;
+ dev_info->flow_type_rss_offloads = ENETC_RSS_OFFLOAD_ALL;
return 0;
}
@@ -178,6 +182,11 @@ mark_memory_ncache(struct enetc_bdr *bdr, const char *mz_name, unsigned int size
mz->hugepage_sz);
bdr->mz = mz;
+ /* Double check memzone alignment and hugepage size */
+ if (!rte_is_aligned(bdr->bd_base, size))
+ ENETC_PMD_WARN("Memzone is not aligned to %x", size);
+
+ ENETC_PMD_DEBUG("Ring Hugepage start address = %p", bdr->bd_base);
/* Mark memory NON-CACHEABLE */
huge_page =
(uint64_t)RTE_PTR_ALIGN_FLOOR(bdr->bd_base, size);
@@ -197,7 +206,7 @@ enetc4_alloc_txbdr(uint16_t port_id, struct enetc_bdr *txr, uint16_t nb_desc)
if (txr->q_swbd == NULL)
return -ENOMEM;
- snprintf(mz_name, sizeof(mz_name), "bdt_addr_%d", port_id);
+ snprintf(mz_name, sizeof(mz_name), "bdt_addr_%d_%d", port_id, txr->index);
if (mark_memory_ncache(txr, mz_name, SIZE_2MB)) {
ENETC_PMD_ERR("Failed to mark BD memory non-cacheable!");
rte_free(txr->q_swbd);
@@ -298,17 +307,20 @@ void
enetc4_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
{
void *txq = dev->data->tx_queues[qid];
+ struct enetc_hw *hw;
+ struct enetc_swbd *tx_swbd;
+ int i;
+ uint32_t val;
+ struct enetc_bdr *tx_ring;
+ struct enetc_eth_hw *eth_hw;
+ PMD_INIT_FUNC_TRACE();
if (txq == NULL)
return;
- struct enetc_bdr *tx_ring = (struct enetc_bdr *)txq;
- struct enetc_eth_hw *eth_hw =
+ tx_ring = (struct enetc_bdr *)txq;
+ eth_hw =
ENETC_DEV_PRIVATE_TO_HW(tx_ring->ndev->data->dev_private);
- struct enetc_hw *hw;
- struct enetc_swbd *tx_swbd;
- int i;
- uint32_t val;
/* Disable the ring */
hw = ð_hw->hw;
@@ -346,7 +358,7 @@ enetc4_alloc_rxbdr(uint16_t port_id, struct enetc_bdr *rxr,
if (rxr->q_swbd == NULL)
return -ENOMEM;
- snprintf(mz_name, sizeof(mz_name), "bdr_addr_%d", port_id);
+ snprintf(mz_name, sizeof(mz_name), "bdr_addr_%d_%d", port_id, rxr->index);
if (mark_memory_ncache(rxr, mz_name, SIZE_2MB)) {
ENETC_PMD_ERR("Failed to mark BD memory non-cacheable!");
rte_free(rxr->q_swbd);
@@ -448,17 +460,20 @@ void
enetc4_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
{
void *rxq = dev->data->rx_queues[qid];
+ struct enetc_swbd *q_swbd;
+ struct enetc_hw *hw;
+ uint32_t val;
+ int i;
+ struct enetc_bdr *rx_ring;
+ struct enetc_eth_hw *eth_hw;
+ PMD_INIT_FUNC_TRACE();
if (rxq == NULL)
return;
- struct enetc_bdr *rx_ring = (struct enetc_bdr *)rxq;
- struct enetc_eth_hw *eth_hw =
+ rx_ring = (struct enetc_bdr *)rxq;
+ eth_hw =
ENETC_DEV_PRIVATE_TO_HW(rx_ring->ndev->data->dev_private);
- struct enetc_swbd *q_swbd;
- struct enetc_hw *hw;
- uint32_t val;
- int i;
/* Disable the ring */
hw = ð_hw->hw;
@@ -524,10 +539,22 @@ enetc4_stats_reset(struct rte_eth_dev *dev)
return 0;
}
+static void
+enetc4_rss_configure(struct enetc_hw *hw, int enable)
+{
+ uint32_t reg;
+
+ reg = enetc4_rd(hw, ENETC_SIMR);
+ reg &= ~ENETC_SIMR_RSSE;
+ reg |= (enable) ? ENETC_SIMR_RSSE : 0;
+ enetc4_wr(hw, ENETC_SIMR, reg);
+}
+
int
enetc4_dev_close(struct rte_eth_dev *dev)
{
struct enetc_eth_hw *hw = ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct enetc_hw *enetc_hw = &hw->hw;
uint16_t i;
int ret;
@@ -540,6 +567,13 @@ enetc4_dev_close(struct rte_eth_dev *dev)
else
ret = enetc4_dev_stop(dev);
+ if (dev->data->nb_rx_queues > 1) {
+ /* Disable RSS */
+ enetc4_rss_configure(enetc_hw, false);
+ /* Free CBDR */
+ netc_free_cbdr(&hw->cbdr);
+ }
+
for (i = 0; i < dev->data->nb_rx_queues; i++) {
enetc4_rx_queue_release(dev, i);
dev->data->rx_queues[i] = NULL;
@@ -569,7 +603,9 @@ enetc4_dev_configure(struct rte_eth_dev *dev)
uint32_t checksum = L3_CKSUM | L4_CKSUM;
struct enetc_hw *enetc_hw = &hw->hw;
uint32_t max_len;
- uint32_t val;
+ uint32_t val, num_rss;
+ uint32_t ret = 0, i;
+ uint32_t *rss_table;
PMD_INIT_FUNC_TRACE();
@@ -602,6 +638,69 @@ enetc4_dev_configure(struct rte_eth_dev *dev)
enetc4_port_wr(enetc_hw, ENETC4_PARCSCR, checksum);
+ /* Disable and reset RX and TX rings */
+ for (i = 0; i < dev->data->nb_rx_queues; i++)
+ enetc4_rxbdr_wr(enetc_hw, i, ENETC_RBMR, ENETC_BMR_RESET);
+
+ for (i = 0; i < dev->data->nb_tx_queues; i++)
+ enetc4_rxbdr_wr(enetc_hw, i, ENETC_TBMR, ENETC_BMR_RESET);
+
+ if (dev->data->nb_rx_queues <= 1)
+ return 0;
+
+ /* Setup RSS */
+ /* Setup control BDR */
+ ret = enetc4_setup_cbdr(dev, enetc_hw, ENETC_CBDR_SIZE, &hw->cbdr);
+ if (ret) {
+ /* Disable RSS */
+ enetc4_rss_configure(enetc_hw, false);
+ return ret;
+ }
+
+ /* Reset CIR again after enable CBDR*/
+ rte_delay_us(ENETC_CBDR_DELAY);
+ ENETC_PMD_DEBUG("CIR %x after CBDR enable", rte_read32(hw->cbdr.regs.cir));
+ rte_write32(0, hw->cbdr.regs.cir);
+ ENETC_PMD_DEBUG("CIR %x after reset", rte_read32(hw->cbdr.regs.cir));
+
+ val = enetc_rd(enetc_hw, ENETC_SIPCAPR0);
+ if (val & ENETC_SIPCAPR0_RSS) {
+ num_rss = enetc_rd(enetc_hw, ENETC_SIRSSCAPR);
+ hw->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(num_rss);
+ ENETC_PMD_DEBUG("num_rss = %d", hw->num_rss);
+
+ /* Add number of BDR groups */
+ enetc4_wr(enetc_hw, ENETC_SIRBGCR, dev->data->nb_rx_queues);
+
+
+ /* Configuring indirecton table with default values
+ * Hash algorithm and RSS secret key to be filled by PF
+ */
+ rss_table = rte_malloc(NULL, hw->num_rss * sizeof(*rss_table), ENETC_CBDR_ALIGN);
+ if (!rss_table) {
+ enetc4_rss_configure(enetc_hw, false);
+ netc_free_cbdr(&hw->cbdr);
+ return -ENOMEM;
+ }
+
+ ENETC_PMD_DEBUG("Enabling RSS for port %s with queues = %d", dev->device->name,
+ dev->data->nb_rx_queues);
+ for (i = 0; i < hw->num_rss; i++)
+ rss_table[i] = i % dev->data->nb_rx_queues;
+
+ ret = ntmp_rsst_query_or_update_entry(&hw->cbdr, rss_table, hw->num_rss, false);
+ if (ret) {
+ ENETC_PMD_WARN("RSS indirection table update fails,"
+ "Scaling behaviour is undefined");
+ enetc4_rss_configure(enetc_hw, false);
+ netc_free_cbdr(&hw->cbdr);
+ }
+ rte_free(rss_table);
+
+ /* Enable RSS */
+ enetc4_rss_configure(enetc_hw, true);
+ }
+
return 0;
}
@@ -786,11 +885,19 @@ enetc4_dev_init(struct rte_eth_dev *eth_dev)
ENETC_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
int error = 0;
+ uint32_t si_cap;
+ struct enetc_hw *enetc_hw = &hw->hw;
PMD_INIT_FUNC_TRACE();
eth_dev->dev_ops = &enetc4_ops;
enetc4_dev_hw_init(eth_dev);
+ si_cap = enetc_rd(enetc_hw, ENETC_SICAPR0);
+ hw->max_tx_queues = si_cap & ENETC_SICAPR0_BDR_MASK;
+ hw->max_rx_queues = (si_cap >> 16) & ENETC_SICAPR0_BDR_MASK;
+
+ ENETC_PMD_DEBUG("Max RX queues = %d Max TX queues = %d",
+ hw->max_rx_queues, hw->max_tx_queues);
error = enetc4_mac_init(hw, eth_dev);
if (error != 0) {
ENETC_PMD_ERR("MAC initialization failed");
@@ -5,8 +5,6 @@
#include <stdbool.h>
#include <rte_random.h>
#include <dpaax_iova_table.h>
-#include "base/enetc4_hw.h"
-#include "base/enetc_hw.h"
#include "enetc_logs.h"
#include "enetc.h"
@@ -137,11 +135,19 @@ enetc4_vf_dev_init(struct rte_eth_dev *eth_dev)
ENETC_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
int error = 0;
+ uint32_t si_cap;
+ struct enetc_hw *enetc_hw = &hw->hw;
PMD_INIT_FUNC_TRACE();
eth_dev->dev_ops = &enetc4_vf_ops;
enetc4_dev_hw_init(eth_dev);
+ si_cap = enetc_rd(enetc_hw, ENETC_SICAPR0);
+ hw->max_tx_queues = si_cap & ENETC_SICAPR0_BDR_MASK;
+ hw->max_rx_queues = (si_cap >> 16) & ENETC_SICAPR0_BDR_MASK;
+
+ ENETC_PMD_DEBUG("Max RX queues = %d Max TX queues = %d",
+ hw->max_rx_queues, hw->max_tx_queues);
error = enetc4_vf_mac_init(hw, eth_dev);
if (error != 0) {
ENETC_PMD_ERR("MAC initialization failed!!");
new file mode 100644
@@ -0,0 +1,311 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2024 NXP
+ */
+
+#include <ethdev_pci.h>
+
+#include "enetc_logs.h"
+#include "enetc.h"
+
+#define NTMP_RSST_ID 3
+
+/* Define NTMP Access Method */
+#define NTMP_AM_ENTRY_ID 0
+#define NTMP_AM_EXACT_KEY 1
+#define NTMP_AM_SEARCH 2
+#define NTMP_AM_TERNARY_KEY 3
+
+/* Define NTMP Header Version */
+#define NTMP_HEADER_VERSION2 2
+
+#define NTMP_REQ_HDR_NPF BIT(15)
+
+#define NTMP_RESP_LEN_MASK GENMASK(19, 0)
+#define NTMP_REQ_LEN_MASK GENMASK(31, 20)
+
+#define ENETC_NTMP_ENTRY_ID_SIZE 4
+
+#define ENETC_RSS_TABLE_ENTRY_NUM 64
+#define ENETC_RSS_CFGEU BIT(0)
+#define ENETC_RSS_STSEU BIT(1)
+#define ENETC_RSS_STSE_DATA_SIZE(n) ((n) * 8)
+#define ENETC_RSS_CFGE_DATA_SIZE(n) (n)
+
+#define NTMP_REQ_RESP_LEN(req, resp) (((req) << 20 & NTMP_REQ_LEN_MASK) | \
+ ((resp) & NTMP_RESP_LEN_MASK))
+
+static inline uint32_t
+netc_cbdr_read(void *reg)
+{
+ return rte_read32(reg);
+}
+
+static inline void
+netc_cbdr_write(void *reg, uint32_t val)
+{
+ rte_write32(val, reg);
+}
+
+static inline void
+ntmp_fill_request_headr(union netc_cbd *cbd, dma_addr_t dma,
+ int len, int table_id, int cmd,
+ int access_method)
+{
+ dma_addr_t dma_align;
+
+ memset(cbd, 0, sizeof(*cbd));
+ dma_align = dma;
+ cbd->ntmp_req_hdr.addr = dma_align;
+ cbd->ntmp_req_hdr.len = len;
+ cbd->ntmp_req_hdr.cmd = cmd;
+ cbd->ntmp_req_hdr.access_method = access_method;
+ cbd->ntmp_req_hdr.table_id = table_id;
+ cbd->ntmp_req_hdr.hdr_ver = NTMP_HEADER_VERSION2;
+ cbd->ntmp_req_hdr.cci = 0;
+ cbd->ntmp_req_hdr.rr = 0; /* Must be set to 0 by SW. */
+ /* For NTMP version 2.0 or later version */
+ cbd->ntmp_req_hdr.npf = NTMP_REQ_HDR_NPF;
+}
+
+static inline int
+netc_get_free_cbd_num(struct netc_cbdr *cbdr)
+{
+ return (cbdr->next_to_clean - cbdr->next_to_use - 1 + cbdr->bd_num) %
+ cbdr->bd_num;
+}
+
+static inline union
+netc_cbd *netc_get_cbd(struct netc_cbdr *cbdr, int index)
+{
+ return &((union netc_cbd *)(cbdr->addr_base_align))[index];
+}
+
+static void
+netc_clean_cbdr(struct netc_cbdr *cbdr)
+{
+ union netc_cbd *cbd;
+ uint32_t i;
+
+ i = cbdr->next_to_clean;
+ while (netc_cbdr_read(cbdr->regs.cir) != i) {
+ cbd = netc_get_cbd(cbdr, i);
+ memset(cbd, 0, sizeof(*cbd));
+ dcbf(cbd);
+ i = (i + 1) % cbdr->bd_num;
+ }
+
+ cbdr->next_to_clean = i;
+}
+
+static int
+netc_xmit_ntmp_cmd(struct netc_cbdr *cbdr, union netc_cbd *cbd)
+{
+ union netc_cbd *ring_cbd;
+ uint32_t i, err = 0;
+ uint16_t status;
+ uint32_t timeout = cbdr->timeout;
+ uint32_t delay = cbdr->delay;
+
+ if (unlikely(!cbdr->addr_base))
+ return -EFAULT;
+
+ rte_spinlock_lock(&cbdr->ring_lock);
+
+ if (unlikely(!netc_get_free_cbd_num(cbdr)))
+ netc_clean_cbdr(cbdr);
+
+ i = cbdr->next_to_use;
+ ring_cbd = netc_get_cbd(cbdr, i);
+
+ /* Copy command BD to the ring */
+ *ring_cbd = *cbd;
+ /* Update producer index of both software and hardware */
+ i = (i + 1) % cbdr->bd_num;
+ dcbf(ring_cbd);
+ cbdr->next_to_use = i;
+ netc_cbdr_write(cbdr->regs.pir, i);
+ ENETC_PMD_DEBUG("Control msg sent PIR = %d, CIR = %d", netc_cbdr_read(cbdr->regs.pir),
+ netc_cbdr_read(cbdr->regs.cir));
+ do {
+ if (netc_cbdr_read(cbdr->regs.cir) == i) {
+ dccivac(ring_cbd);
+ ENETC_PMD_DEBUG("got response");
+ ENETC_PMD_DEBUG("Matched = %d, status = 0x%x",
+ ring_cbd->ntmp_resp_hdr.num_matched,
+ ring_cbd->ntmp_resp_hdr.error_rr);
+ break;
+ }
+ rte_delay_us(delay);
+ } while (timeout--);
+
+ if (timeout <= 0)
+ ENETC_PMD_ERR("no response of RSS configuration");
+
+ ENETC_PMD_DEBUG("CIR after receive = %d, SICBDRSR = 0x%x",
+ netc_cbdr_read(cbdr->regs.cir),
+ netc_cbdr_read(cbdr->regs.st));
+ /* Check the writeback error status */
+ status = ring_cbd->ntmp_resp_hdr.error_rr & NTMP_RESP_HDR_ERR;
+ if (unlikely(status)) {
+ ENETC_PMD_ERR("Command BD error: 0x%04x", status);
+ err = -EIO;
+ }
+
+ netc_clean_cbdr(cbdr);
+ rte_spinlock_unlock(&cbdr->ring_lock);
+
+ return err;
+}
+
+int
+ntmp_rsst_query_or_update_entry(struct netc_cbdr *cbdr, uint32_t *table,
+ int count, bool query)
+{
+ struct rsst_req_update *requ;
+ struct rsst_req_query *req;
+ union netc_cbd cbd;
+ uint32_t len, data_size;
+ dma_addr_t dma;
+ int err, i;
+ void *tmp;
+
+ if (count != ENETC_RSS_TABLE_ENTRY_NUM)
+ /* HW only takes in a full 64 entry table */
+ return -EINVAL;
+
+ if (query)
+ data_size = ENETC_NTMP_ENTRY_ID_SIZE + ENETC_RSS_STSE_DATA_SIZE(count) +
+ ENETC_RSS_CFGE_DATA_SIZE(count);
+ else
+ data_size = sizeof(*requ) + count * sizeof(uint8_t);
+
+ tmp = rte_malloc(NULL, data_size, ENETC_CBDR_ALIGN);
+ if (!tmp)
+ return -ENOMEM;
+
+ dma = rte_mem_virt2iova(tmp);
+ req = tmp;
+ /* Set the request data buffer */
+ if (query) {
+ len = NTMP_REQ_RESP_LEN(sizeof(*req), data_size);
+ ntmp_fill_request_headr(&cbd, dma, len, NTMP_RSST_ID,
+ NTMP_CMD_QUERY, NTMP_AM_ENTRY_ID);
+ } else {
+ requ = (struct rsst_req_update *)req;
+ requ->crd.update_act = (ENETC_RSS_CFGEU | ENETC_RSS_STSEU);
+ for (i = 0; i < count; i++)
+ requ->groups[i] = (uint8_t)(table[i]);
+
+ len = NTMP_REQ_RESP_LEN(data_size, 0);
+ ntmp_fill_request_headr(&cbd, dma, len, NTMP_RSST_ID,
+ NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID);
+ dcbf(requ);
+ }
+
+ err = netc_xmit_ntmp_cmd(cbdr, &cbd);
+ if (err) {
+ ENETC_PMD_ERR("%s RSS table entry failed (%d)!",
+ query ? "Query" : "Update", err);
+ goto end;
+ }
+
+ if (query) {
+ uint8_t *group = (uint8_t *)req;
+
+ group += ENETC_NTMP_ENTRY_ID_SIZE + ENETC_RSS_STSE_DATA_SIZE(count);
+ for (i = 0; i < count; i++)
+ table[i] = group[i];
+ }
+end:
+ rte_free(tmp);
+
+ return err;
+}
+
+static int
+netc_setup_cbdr(struct rte_eth_dev *dev, int cbd_num,
+ struct netc_cbdr_regs *regs,
+ struct netc_cbdr *cbdr)
+{
+ int size;
+
+ size = cbd_num * sizeof(union netc_cbd) +
+ NETC_CBDR_BASE_ADDR_ALIGN;
+
+ cbdr->addr_base = rte_malloc(NULL, size, ENETC_CBDR_ALIGN);
+ if (!cbdr->addr_base)
+ return -ENOMEM;
+
+ cbdr->dma_base = rte_mem_virt2iova(cbdr->addr_base);
+ cbdr->dma_size = size;
+ cbdr->bd_num = cbd_num;
+ cbdr->regs = *regs;
+ cbdr->dma_dev = dev;
+ cbdr->timeout = ENETC_CBDR_TIMEOUT;
+ cbdr->delay = ENETC_CBDR_DELAY;
+
+ if (getenv("ENETC4_CBDR_TIMEOUT"))
+ cbdr->timeout = atoi(getenv("ENETC4_CBDR_TIMEOUT"));
+
+ if (getenv("ENETC4_CBDR_DELAY"))
+ cbdr->delay = atoi(getenv("ENETC4_CBDR_DELAY"));
+
+
+ ENETC_PMD_DEBUG("CBDR timeout = %u and delay = %u", cbdr->timeout,
+ cbdr->delay);
+ /* The base address of the Control BD Ring must be 128 bytes aligned */
+ cbdr->dma_base_align = cbdr->dma_base;
+ cbdr->addr_base_align = cbdr->addr_base;
+
+ cbdr->next_to_clean = 0;
+ cbdr->next_to_use = 0;
+ rte_spinlock_init(&cbdr->ring_lock);
+
+ netc_cbdr_write(cbdr->regs.mr, ~((uint32_t)NETC_CBDRMR_EN));
+ /* Step 1: Configure the base address of the Control BD Ring */
+ netc_cbdr_write(cbdr->regs.bar0, lower_32_bits(cbdr->dma_base_align));
+ netc_cbdr_write(cbdr->regs.bar1, upper_32_bits(cbdr->dma_base_align));
+
+ /* Step 2: Configure the producer index register */
+ netc_cbdr_write(cbdr->regs.pir, cbdr->next_to_clean);
+
+ /* Step 3: Configure the consumer index register */
+ netc_cbdr_write(cbdr->regs.cir, cbdr->next_to_use);
+ /* Step4: Configure the number of BDs of the Control BD Ring */
+ netc_cbdr_write(cbdr->regs.lenr, cbdr->bd_num);
+
+ /* Step 5: Enable the Control BD Ring */
+ netc_cbdr_write(cbdr->regs.mr, NETC_CBDRMR_EN);
+
+ return 0;
+}
+
+void
+netc_free_cbdr(struct netc_cbdr *cbdr)
+{
+ /* Disable the Control BD Ring */
+ if (cbdr->regs.mr != NULL) {
+ netc_cbdr_write(cbdr->regs.mr, 0);
+ rte_free(cbdr->addr_base);
+ memset(cbdr, 0, sizeof(*cbdr));
+ }
+}
+
+int
+enetc4_setup_cbdr(struct rte_eth_dev *dev, struct enetc_hw *hw,
+ int bd_count, struct netc_cbdr *cbdr)
+{
+ struct netc_cbdr_regs regs;
+
+ regs.pir = (void *)((size_t)hw->reg + ENETC4_SICBDRPIR);
+ regs.cir = (void *)((size_t)hw->reg + ENETC4_SICBDRCIR);
+ regs.mr = (void *)((size_t)hw->reg + ENETC4_SICBDRMR);
+ regs.st = (void *)((size_t)hw->reg + ENETC4_SICBDRSR);
+ regs.bar0 = (void *)((size_t)hw->reg + ENETC4_SICBDRBAR0);
+ regs.bar1 = (void *)((size_t)hw->reg + ENETC4_SICBDRBAR1);
+ regs.lenr = (void *)((size_t)hw->reg + ENETC4_SICBDRLENR);
+ regs.sictr0 = (void *)((size_t)hw->reg + ENETC4_SICTR0);
+ regs.sictr1 = (void *)((size_t)hw->reg + ENETC4_SICTR1);
+
+ return netc_setup_cbdr(dev, bd_count, ®s, cbdr);
+}
@@ -8,10 +8,11 @@ endif
deps += ['common_dpaax']
sources = files(
- 'enetc4_ethdev.c',
- 'enetc4_vf.c',
+ 'enetc4_ethdev.c',
+ 'enetc4_vf.c',
'enetc_ethdev.c',
'enetc_rxtx.c',
+ 'enetc_cbdr.c',
)
includes += include_directories('base')
new file mode 100644
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2024 NXP
+ */
+
+#ifndef ENETC_NTMP_H
+#define ENETC_NTMP_H
+
+#include "compat.h"
+#include <linux/types.h>
+
+#define BITS_PER_LONG (__SIZEOF_LONG__ * 8)
+#define BITS_PER_LONG_LONG (__SIZEOF_LONG_LONG__ * 8)
+#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+
+/* define NTMP Operation Commands */
+#define NTMP_CMD_DELETE BIT(0)
+#define NTMP_CMD_UPDATE BIT(1)
+#define NTMP_CMD_QUERY BIT(2)
+
+#define NETC_CBDR_TIMEOUT 1000 /* us */
+#define NETC_CBDR_BD_NUM 256
+#define NETC_CBDR_BASE_ADDR_ALIGN 128
+#define NETC_CBD_DATA_ADDR_ALIGN 16
+#define NETC_CBDRMR_EN BIT(31)
+
+#define NTMP_RESP_HDR_ERR GENMASK(11, 0)
+
+struct common_req_data {
+ uint16_t update_act;
+ uint8_t dbg_opt;
+ uint8_t query_act:4;
+ uint8_t tbl_ver:4;
+};
+
+/* RSS Table Request and Response Data Buffer Format */
+struct rsst_req_query {
+ struct common_req_data crd;
+ uint32_t entry_id;
+};
+
+/* struct for update operation */
+struct rsst_req_update {
+ struct common_req_data crd;
+ uint32_t entry_id;
+ uint8_t groups[];
+};
+
+/* The format of conctrol buffer descriptor */
+union netc_cbd {
+ struct {
+ uint64_t addr;
+ uint32_t len;
+ uint8_t cmd;
+ uint8_t resv1:4;
+ uint8_t access_method:4;
+ uint8_t table_id;
+ uint8_t hdr_ver:6;
+ uint8_t cci:1;
+ uint8_t rr:1;
+ uint32_t resv2[3];
+ uint32_t npf;
+ } ntmp_req_hdr; /* NTMP Request Message Header Format */
+
+ struct {
+ uint32_t resv1[3];
+ uint16_t num_matched;
+ uint16_t error_rr; /* bit0~11: error, bit12~14: reserved, bit15: rr */
+ uint32_t resv3[4];
+ } ntmp_resp_hdr; /* NTMP Response Message Header Format */
+};
+
+struct netc_cbdr_regs {
+ void *pir;
+ void *cir;
+ void *mr;
+ void *st;
+
+ void *bar0;
+ void *bar1;
+ void *lenr;
+
+ /* station interface current time register */
+ void *sictr0;
+ void *sictr1;
+};
+
+struct netc_cbdr {
+ struct netc_cbdr_regs regs;
+
+ int bd_num;
+ int next_to_use;
+ int next_to_clean;
+
+ int dma_size;
+ void *addr_base;
+ void *addr_base_align;
+ dma_addr_t dma_base;
+ dma_addr_t dma_base_align;
+ struct rte_eth_dev *dma_dev;
+
+ rte_spinlock_t ring_lock; /* Avoid race condition */
+
+ /* bitmap of used words of SGCL table */
+ unsigned long *sgclt_used_words;
+ uint32_t sgclt_words_num;
+ uint32_t timeout;
+ uint32_t delay;
+};
+
+#endif /* ENETC_NTMP_H */