[PATCH v6 06/20] net/sxe2: support TM hierarchy and shaping
liujie5 at linkdatatechnology.com
liujie5 at linkdatatechnology.com
Tue Jun 2 17:52:25 CEST 2026
From: Jie Liu <liujie5 at linkdatatechnology.com>
This patch implements the traffic management ops for example PMD.
It supports a 4-level hierarchy: port, vsi, queue group and queue.
- Support node add/delete and hierarchy commit.
- Support private shaper and rate limiting on each node.
The hardware requires all nodes to be configured before the hierarchy
is committed to the global registers.
Signed-off-by: Jie Liu <liujie5 at linkdatatechnology.com>
---
drivers/net/sxe2/meson.build | 1 +
drivers/net/sxe2/sxe2_cmd_chnl.c | 163 +++++
drivers/net/sxe2/sxe2_cmd_chnl.h | 6 +
drivers/net/sxe2/sxe2_drv_cmd.h | 26 +
drivers/net/sxe2/sxe2_ethdev.c | 82 +++
drivers/net/sxe2/sxe2_ethdev.h | 5 +
drivers/net/sxe2/sxe2_tm.c | 1151 ++++++++++++++++++++++++++++++
drivers/net/sxe2/sxe2_tm.h | 76 ++
drivers/net/sxe2/sxe2_tx.c | 1 -
9 files changed, 1510 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/sxe2/sxe2_tm.c
create mode 100644 drivers/net/sxe2/sxe2_tm.h
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index da7a690063..f03ea15356 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -63,4 +63,5 @@ sources += files(
'sxe2_mac.c',
'sxe2_filter.c',
'sxe2_rss.c',
+ 'sxe2_tm.c',
)
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index b997e7b044..19323ffcc4 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -230,6 +230,7 @@ static void sxe2_txq_ctxt_cfg_fill(struct sxe2_tx_queue *txq,
struct sxe2_drv_txq_cfg_req *req,
uint16_t txq_cnt)
{
+ struct sxe2_adapter *adapter = txq->vsi->adapter;
struct sxe2_drv_txq_ctxt *ctxt = req->cfg;
uint16_t q_idx = 0;
@@ -241,6 +242,8 @@ static void sxe2_txq_ctxt_cfg_fill(struct sxe2_tx_queue *txq,
ctxt->depth = txq[q_idx].ring_depth;
ctxt->dma_addr = txq[q_idx].base_addr;
ctxt->queue_id = txq[q_idx].queue_id;
+
+ ctxt->sched_mode = sxe2_sched_mode_get(adapter);
}
}
@@ -310,6 +313,7 @@ int32_t sxe2_drv_txq_switch(struct sxe2_adapter *adapter, struct sxe2_tx_queue *
req.q_idx = txq->queue_id;
req.is_enable = (uint8_t)enable;
+ req.sched_mode = sxe2_sched_mode_get(adapter);
sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_TXQ_DISABLE,
&req, sizeof(req), NULL, 0);
@@ -714,3 +718,162 @@ int32_t sxe2_drv_ptp_gettime(struct sxe2_adapter *adapter, struct sxe2_rx_queue
(void)rxq;
return 0;
}
+
+int32_t sxe2_drv_root_tree_alloc(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_tm_res tm_resp;
+ int32_t ret;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_SCHED_ROOT_TREE_ALLOC,
+ NULL, 0,
+ &tm_resp, sizeof(tm_resp));
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "add sched root failed, ret:%d", ret);
+ goto l_end;
+ }
+
+ tm_ctxt->root_teid = tm_resp.teid;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_drv_root_tree_release(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_tm_res tm_res = {0};
+ int32_t ret;
+
+ tm_res.teid = adapter->tm_ctxt.root_teid;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_SCHED_ROOT_TREE_RELEASE,
+ &tm_res, sizeof(tm_res),
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "release sched root failed, ret:%d", ret);
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
+static void sxe2_drv_tm_node_to_info(struct sxe2_adapter *adapter,
+ struct sxe2_tm_node *node, struct sxe2_tm_info *info)
+{
+ uint32_t rate = 0;
+
+ if (node->shaper_profile->profile.committed.rate == UINT64_MAX)
+ rate = UINT32_MAX;
+ else
+ rate = (uint32_t)(node->shaper_profile->profile.committed.rate * 8 / 1000);
+
+ info->committed = rte_cpu_to_le_32(rate);
+
+ if (node->shaper_profile->profile.peak.rate == UINT64_MAX)
+ rate = UINT32_MAX;
+ else
+ rate = (uint32_t)(node->shaper_profile->profile.peak.rate * 8 / 1000);
+
+ info->peak = rte_cpu_to_le_32(rate);
+
+ info->priority = (adapter->tm_ctxt.prio_max - 1 - node->priority);
+
+ info->weight = rte_cpu_to_le_16(node->hw_weight);
+}
+
+static int32_t sxe2_drv_tm_commit_node(struct sxe2_adapter *adapter,
+ struct sxe2_tm_node *tm_node)
+{
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_tm_add_mid_msg msg_mid = {0};
+ struct sxe2_tm_add_queue_msg msg_queue = {0};
+ struct sxe2_tm_res res = {0};
+ struct sxe2_common_device *cdev = adapter->cdev;
+ int32_t ret;
+ uint32_t i;
+
+ if (tm_node->type == SXE2_TM_NODE_TYPE_VSIG) {
+ goto l_add;
+ } else if (tm_node->type == SXE2_TM_NODE_TYPE_MID) {
+ sxe2_drv_tm_node_to_info(adapter, tm_node, &msg_mid.info);
+ msg_mid.parent_teid = rte_cpu_to_le_16(tm_node->parent->teid);
+ msg_mid.adj_lvl = adapter->sched_ctxt.adj_lvl;
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd,
+ SXE2_DRV_CMD_SCHED_TM_ADD_MID_NODE,
+ &msg_mid, sizeof(msg_mid),
+ &res, sizeof(res));
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "add tm mid node failed, ret:%d", ret);
+ goto l_end;
+ }
+ } else if (tm_node->type == SXE2_TM_NODE_TYPE_QUEUE) {
+ sxe2_drv_tm_node_to_info(adapter, tm_node, &msg_queue.info);
+ msg_queue.parent_teid = rte_cpu_to_le_16(tm_node->parent->teid);
+ msg_queue.queue_id = rte_cpu_to_le_16(tm_node->id);
+ msg_queue.adj_lvl = adapter->sched_ctxt.adj_lvl;
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd,
+ SXE2_DRV_CMD_SCHED_TM_ADD_QUEUE_NODE,
+ &msg_queue, sizeof(msg_queue),
+ &res, sizeof(res));
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "add tm queue failed, ret:%d", ret);
+ goto l_end;
+ }
+ } else {
+ PMD_LOG_ERR(DRV, "commit tm node failed, type:%d", tm_node->type);
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ tm_node->teid = rte_le_to_cpu_16(res.teid);
+
+l_add:
+ for (i = 0; i < tm_node->child_cnt; i++) {
+ ret = sxe2_drv_tm_commit_node(adapter, tm_node->children[i]);
+ if (ret)
+ goto l_end;
+ }
+l_end:
+ return ret;
+}
+
+int32_t sxe2_drv_tm_commit(struct sxe2_adapter *adapter)
+{
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_tm_res tm_res = {0};
+ int32_t ret;
+
+ tm_res.teid = adapter->tm_ctxt.root_teid;
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_SCHED_ROOT_CHILDREN_DELETE,
+ &tm_res, sizeof(tm_res),
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "del tm root failed, ret:%d", ret);
+ goto l_end;
+ }
+
+ ret = sxe2_drv_tm_commit_node(adapter, adapter->tm_ctxt.root);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "commit tm node failed, ret:%d", ret);
+ goto l_end;
+ }
+
+ PMD_LOG_DEBUG(DRV, "commit tm success");
+l_end:
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index 2546c65a6c..77e689abcd 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -38,6 +38,12 @@ int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter);
int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set);
+int32_t sxe2_drv_root_tree_release(struct rte_eth_dev *dev);
+
+int32_t sxe2_drv_root_tree_alloc(struct rte_eth_dev *dev);
+
+int32_t sxe2_drv_tm_commit(struct sxe2_adapter *adapter);
+
int32_t sxe2_drv_allmulti_config(struct sxe2_adapter *adapter, bool set);
int32_t sxe2_drv_uc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add);
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index b644b205c5..01b59124c6 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -349,6 +349,32 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_rss_hf_req {
uint8_t rsv1[3];
} __rte_packed_end;
+struct __rte_aligned(4) __rte_packed_begin sxe2_tm_res {
+ uint16_t teid;
+ uint8_t rsv[2];
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_tm_info {
+ uint32_t committed;
+ uint32_t peak;
+ uint8_t priority;
+ uint8_t reserve;
+ uint16_t weight;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_tm_add_mid_msg {
+ uint16_t parent_teid;
+ uint8_t adj_lvl;
+ struct sxe2_tm_info info;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_tm_add_queue_msg {
+ uint16_t parent_teid;
+ uint16_t queue_id;
+ uint8_t adj_lvl;
+ struct sxe2_tm_info info;
+} __rte_packed_end;
+
enum sxe2_drv_cmd_module {
SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index d48841b8e4..a095888c00 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -130,6 +130,8 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
.reta_query = sxe2_dev_rss_reta_query,
.rss_hash_update = sxe2_dev_rss_hash_update,
.rss_hash_conf_get = sxe2_dev_rss_hash_conf_get,
+
+ .tm_ops_get = sxe2_tm_ops_get,
};
static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
@@ -575,6 +577,14 @@ static void sxe2_drv_dev_caps_set(struct sxe2_adapter *adapter,
adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_FC_STATE;
}
+static void sxe2_sw_sched_hw_cap_set(struct sxe2_adapter *adapter,
+ struct sxe2_txsch_caps *txsch_caps)
+{
+ adapter->sched_ctxt.tm_layers = txsch_caps->layer_cap;
+ adapter->sched_ctxt.root_max_children = txsch_caps->tm_mid_node_num;
+ adapter->sched_ctxt.prio_max = txsch_caps->prio_num;
+}
+
static int32_t sxe2_func_caps_get(struct sxe2_adapter *adapter)
{
int32_t ret = -1;
@@ -594,6 +604,8 @@ static int32_t sxe2_func_caps_get(struct sxe2_adapter *adapter)
sxe2_sw_vsi_ctx_hw_cap_set(adapter, &dev_caps.vsi_caps);
+ sxe2_sw_sched_hw_cap_set(adapter, &dev_caps.txsch_caps);
+
l_end:
return ret;
}
@@ -930,6 +942,68 @@ void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev)
adapter->dev_info.dev_data = NULL;
}
+uint32_t sxe2_sched_mode_get(struct sxe2_adapter *adapter)
+{
+ uint32_t ret_mode = SXE2_SCHED_MODE_INVALID;
+ struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+
+ if (adapter->devargs.high_performance_mode)
+ ret_mode = SXE2_SCHED_MODE_HIGH_PERFORMANCE;
+ else if (tm_ctxt->committed)
+ ret_mode = SXE2_SCHED_MODE_TM;
+ else
+ ret_mode = SXE2_SCHED_MODE_DEFAULT;
+
+ return ret_mode;
+}
+
+static int32_t sxe2_sched_init(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+
+ adapter->sched_ctxt.adj_lvl = adapter->devargs.sched_layer_mode;
+
+ if (adapter->devargs.high_performance_mode) {
+ PMD_LOG_DEBUG(DRV, "TM feature will be disabled in high-performance mode.");
+ adapter->cap_flags &= ~(SXE2_DEV_CAPS_OFFLOAD_TM);
+ } else {
+ ret = sxe2_tm_init(dev);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_drv_root_tree_alloc(dev);
+ if (ret)
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_sched_uinit(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+
+ if (adapter->devargs.high_performance_mode == 0) {
+ ret = sxe2_tm_uninit(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to uninit tm, ret=%d", ret);
+ goto l_end;
+ }
+
+ ret = sxe2_drv_root_tree_release(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to release root tree, ret=%d", ret);
+ goto l_end;
+ }
+ }
+
+l_end:
+ return ret;
+}
+
static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
struct sxe2_dev_kvargs_info *kvargs __rte_unused)
{
@@ -985,8 +1059,15 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
goto init_rss_err;
}
+ ret = sxe2_sched_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to init sched, ret=%d", ret);
+ goto init_sched_err;
+ }
+
goto l_end;
+init_sched_err:
init_rss_err:
init_eth_err:
init_dev_info_err:
@@ -1002,6 +1083,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
(void)sxe2_dev_stop(dev);
(void)sxe2_queues_release(dev);
(void)sxe2_rss_disable(dev);
+ (void)sxe2_sched_uinit(dev);
sxe2_vsi_uninit(dev);
sxe2_dev_pci_map_uinit(dev);
sxe2_eth_uinit(dev);
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 3955788634..76e4cc8b33 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -20,6 +20,7 @@
#include "sxe2_queue.h"
#include "sxe2_mac.h"
#include "sxe2_osal.h"
+#include "sxe2_tm.h"
#include "sxe2_filter.h"
struct sxe2_link_msg {
@@ -309,6 +310,8 @@ struct sxe2_adapter {
struct sxe2_rss_context rss_ctxt;
struct sxe2_link_context link_ctxt;
struct sxe2_ptp_context ptp_ctxt;
+ struct sxe2_sched_hw_cap sched_ctxt;
+ struct sxe2_tm_context tm_ctxt;
struct sxe2_devargs devargs;
struct sxe2_switchdev_info switchdev_info;
bool rule_started;
@@ -335,6 +338,8 @@ void *sxe2_pci_map_addr_get(struct sxe2_adapter *adapter,
enum sxe2_pci_map_resource res_type,
uint16_t idx_in_func);
+uint32_t sxe2_sched_mode_get(struct sxe2_adapter *adapter);
+
struct sxe2_pci_map_bar_info *sxe2_dev_get_bar_info(struct sxe2_adapter *adapter,
enum sxe2_pci_map_resource res_type);
diff --git a/drivers/net/sxe2/sxe2_tm.c b/drivers/net/sxe2/sxe2_tm.c
new file mode 100644
index 0000000000..4c4f793cd5
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_tm.c
@@ -0,0 +1,1151 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_ethdev.h>
+#include <rte_tm_driver.h>
+
+#include "sxe2_tm.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_common_log.h"
+#include "sxe2_cmd_chnl.h"
+
+static uint16_t sxe2_tm_level_node_num_get(uint8_t level)
+{
+ uint16_t node_num = 0;
+
+ switch (level) {
+ case 0:
+ node_num = SXE2_TM_1L_NODE_NUM_MAX;
+ break;
+ case 1:
+ node_num = SXE2_TM_2L_NODE_NUM_MAX;
+ break;
+ case 2:
+ node_num = SXE2_TM_3L_NODE_NUM_MAX;
+ break;
+ case 3:
+ node_num = SXE2_TM_4L_NODE_NUM_MAX;
+ break;
+ }
+ return node_num;
+}
+
+static int32_t sxe2_tm_capabilities_get(struct rte_eth_dev *dev,
+ struct rte_tm_capabilities *cap,
+ struct rte_tm_error *error)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+ uint32_t i;
+
+ if (!cap || !error) {
+ PMD_LOG_ERR(DRV, "sxe2 get tm cap failed, cap or error is NULL.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+ PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "The TM capability is not supported.";
+ ret = ENOTSUP;
+ goto l_end;
+ }
+
+ error->type = RTE_TM_ERROR_TYPE_NONE;
+ memset(cap, 0, sizeof(struct rte_tm_capabilities));
+
+ for (i = 0; i < adapter->tm_ctxt.tm_layers; i++)
+ cap->n_nodes_max += sxe2_tm_level_node_num_get(i);
+
+ cap->n_levels_max = adapter->tm_ctxt.tm_layers;
+
+ cap->non_leaf_nodes_identical = 1;
+
+ cap->leaf_nodes_identical = 1;
+
+ cap->shaper_n_max = cap->n_nodes_max;
+
+ cap->shaper_private_n_max = cap->n_nodes_max;
+
+ cap->shaper_private_dual_rate_n_max = cap->n_nodes_max;
+
+ cap->shaper_private_rate_min = 0;
+
+ cap->shaper_private_rate_max = 12500000000ull;
+
+ cap->shaper_private_packet_mode_supported = 0;
+ cap->shaper_private_byte_mode_supported = 1;
+
+ cap->shaper_pkt_length_adjust_min = RTE_TM_ETH_FRAMING_OVERHEAD;
+
+ cap->shaper_pkt_length_adjust_max = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+ cap->shaper_shared_n_max = 0;
+ cap->shaper_shared_n_nodes_per_shaper_max = 0;
+ cap->shaper_shared_n_shapers_per_node_max = 0;
+ cap->shaper_shared_dual_rate_n_max = 0;
+ cap->shaper_shared_rate_min = 0;
+ cap->shaper_shared_rate_max = 0;
+ cap->shaper_shared_packet_mode_supported = 0;
+ cap->shaper_shared_byte_mode_supported = 0;
+
+ cap->sched_n_children_max = dev->data->nb_tx_queues;
+
+ cap->sched_sp_n_priorities_max = 7;
+
+ cap->sched_wfq_n_children_per_group_max = 1;
+ cap->sched_wfq_n_groups_max = 0;
+ cap->sched_wfq_weight_max = 0;
+ cap->sched_wfq_packet_mode_supported = 0;
+ cap->sched_wfq_byte_mode_supported = 0;
+
+ cap->cman_wred_packet_mode_supported = 0;
+ cap->cman_wred_byte_mode_supported = 0;
+ cap->cman_head_drop_supported = 0;
+ cap->cman_wred_context_n_max = 0;
+ cap->cman_wred_context_private_n_max = 0;
+ cap->cman_wred_context_shared_n_max = 0;
+ cap->cman_wred_context_shared_n_nodes_per_context_max = 0;
+ cap->cman_wred_context_shared_n_contexts_per_node_max = 0;
+
+ cap->dynamic_update_mask = 0;
+
+ cap->stats_mask = 0;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_level_capabilities_get(struct rte_eth_dev *dev,
+ uint32_t level_id, struct rte_tm_level_capabilities *cap,
+ struct rte_tm_error *error)
+{
+ int32_t ret = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (!cap || !error) {
+ PMD_LOG_ERR(DRV, "sxe2 get tm cap failed, cap or error is NULL.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+ PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "The TM capability is not supported.";
+ ret = ENOTSUP;
+ goto l_end;
+ }
+
+ if (level_id >= adapter->tm_ctxt.tm_layers) {
+ ret = -EINVAL;
+ error->type = RTE_TM_ERROR_TYPE_LEVEL_ID;
+ error->message = "too deep level";
+ goto l_end;
+ }
+
+ cap->n_nodes_max = sxe2_tm_level_node_num_get(level_id);
+
+ cap->non_leaf_nodes_identical = true;
+
+ cap->leaf_nodes_identical = true;
+
+ if (level_id != adapter->tm_ctxt.tm_layers - 1) {
+ cap->n_nodes_nonleaf_max = cap->n_nodes_max;
+ cap->n_nodes_leaf_max = 0;
+
+ cap->nonleaf.shaper_private_supported = true;
+ cap->nonleaf.shaper_private_dual_rate_supported = true;
+ cap->nonleaf.shaper_private_rate_min = 0;
+
+ cap->nonleaf.shaper_private_rate_max = 12500000000ull;
+ cap->nonleaf.shaper_private_packet_mode_supported = 0;
+ cap->nonleaf.shaper_private_byte_mode_supported = 1;
+
+ cap->nonleaf.shaper_shared_n_max = 0;
+ cap->nonleaf.shaper_shared_packet_mode_supported = 0;
+ cap->nonleaf.shaper_shared_byte_mode_supported = 0;
+
+ cap->nonleaf.sched_n_children_max = SXE2_TM_MAX_CHILDREN_COUNT;
+ cap->nonleaf.sched_sp_n_priorities_max = 7;
+
+ cap->nonleaf.sched_wfq_n_children_per_group_max = 0;
+ cap->nonleaf.sched_wfq_n_groups_max = 0;
+ cap->nonleaf.sched_wfq_weight_max = 0;
+ cap->nonleaf.sched_wfq_packet_mode_supported = 0;
+ cap->nonleaf.sched_wfq_byte_mode_supported = 0;
+
+ cap->nonleaf.stats_mask = 0;
+ } else {
+ cap->n_nodes_nonleaf_max = 0;
+ cap->n_nodes_leaf_max = cap->n_nodes_max;
+
+ cap->leaf.shaper_private_supported = true;
+ cap->leaf.shaper_private_dual_rate_supported = true;
+ cap->leaf.shaper_private_rate_min = 0;
+ cap->leaf.shaper_private_rate_max = 12500000000ull;
+ cap->leaf.shaper_private_packet_mode_supported = 0;
+ cap->leaf.shaper_private_byte_mode_supported = 1;
+
+ cap->leaf.shaper_shared_n_max = 0;
+ cap->leaf.shaper_shared_packet_mode_supported = 0;
+ cap->leaf.shaper_shared_byte_mode_supported = 0;
+
+ cap->leaf.cman_head_drop_supported = false;
+ cap->leaf.cman_wred_context_private_supported = false;
+ cap->leaf.cman_wred_context_shared_n_max = 0;
+
+ cap->leaf.stats_mask = 0;
+ }
+
+l_end:
+ return ret;
+}
+
+static struct sxe2_tm_node *sxe2_tm_find_node(struct sxe2_tm_node *parent, uint32_t id)
+{
+ struct sxe2_tm_node *node = NULL;
+ uint32_t i;
+
+ if (parent == NULL || parent->id == id) {
+ node = parent;
+ goto l_end;
+ }
+
+ for (i = 0; i < parent->child_cnt; i++) {
+ node = sxe2_tm_find_node(parent->children[i], id);
+ if (node)
+ goto l_end;
+ }
+
+l_end:
+ return node;
+}
+
+static int32_t sxe2_node_capabilities_get(struct rte_eth_dev *dev, uint32_t node_id,
+ struct rte_tm_node_capabilities *cap,
+ struct rte_tm_error *error)
+{
+ int32_t ret = -EINVAL;
+ struct sxe2_tm_node *tm_node;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (!cap || !error) {
+ PMD_LOG_ERR(DRV, "sxe2 get tm cap failed, cap or error is NULL.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+ PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "The TM capability is not supported.";
+ ret = ENOTSUP;
+ goto l_end;
+ }
+
+ if (node_id == RTE_TM_NODE_ID_NULL) {
+ PMD_LOG_ERR(DRV, "invalid node id");
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "invalid node id";
+ goto l_end;
+ }
+
+ tm_node = sxe2_tm_find_node(adapter->tm_ctxt.root, node_id);
+ if (!tm_node) {
+ PMD_LOG_ERR(DRV, "no such node");
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "no such node";
+ goto l_end;
+ }
+
+ cap->shaper_private_supported = true;
+ cap->shaper_private_dual_rate_supported = true;
+ cap->shaper_private_rate_min = 0;
+ cap->shaper_private_rate_max = 12500000000ull;
+ cap->shaper_private_packet_mode_supported = 0;
+ cap->shaper_private_byte_mode_supported = 1;
+
+ cap->shaper_shared_n_max = 0;
+ cap->shaper_shared_packet_mode_supported = 0;
+ cap->shaper_shared_byte_mode_supported = 0;
+
+ if (tm_node->level == adapter->tm_ctxt.tm_layers - 1) {
+ cap->leaf.cman_head_drop_supported = false;
+ cap->leaf.cman_wred_context_private_supported = false;
+ cap->leaf.cman_wred_context_shared_n_max = 0;
+ } else {
+ cap->nonleaf.sched_n_children_max = SXE2_TM_MAX_CHILDREN_COUNT;
+ cap->nonleaf.sched_sp_n_priorities_max = 7;
+ cap->nonleaf.sched_wfq_n_children_per_group_max = 0;
+ cap->nonleaf.sched_wfq_n_groups_max = 0;
+ cap->nonleaf.sched_wfq_weight_max = 0;
+ cap->nonleaf.sched_wfq_packet_mode_supported = 0;
+ cap->nonleaf.sched_wfq_byte_mode_supported = 0;
+ }
+ cap->stats_mask = 0;
+
+ ret = 0;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_tm_shaper_profile_param_check(const struct rte_tm_shaper_params *profile,
+ struct rte_tm_error *error)
+{
+ int32_t ret = 0;
+
+ if (profile->committed.size) {
+ PMD_LOG_ERR(DRV, "committed bucket size not supported.");
+ error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;
+ error->message = "committed bucket size not supported";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (profile->peak.size) {
+ PMD_LOG_ERR(DRV, "peak bucket size not supported.");
+ error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;
+ error->message = "peak bucket size not supported";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (profile->pkt_length_adjust) {
+ PMD_LOG_ERR(DRV, "packet length adjustment not supported.");
+ error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;
+ error->message = "packet length adjustment not supported";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (profile->committed.rate > SXE2_HW_RATE_MAX ||
+ profile->committed.rate < SXE2_HW_RATE_MIN) {
+ PMD_LOG_ERR(DRV, "The committed rate limit value is required to be in "
+ "the range [%" PRIu64 ", %" PRIu64 "].",
+ (uint64_t)SXE2_HW_RATE_MIN, (uint64_t)SXE2_HW_RATE_MAX);
+ error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE;
+ error->message = "invalid rate limit: value out of range.";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (profile->peak.rate > SXE2_HW_RATE_MAX ||
+ profile->peak.rate < SXE2_HW_RATE_MIN) {
+ PMD_LOG_ERR(DRV, "The peak rate limit value is required to be in "
+ "the range [%" PRIu64 ", %" PRIu64 "].",
+ (uint64_t)SXE2_HW_RATE_MIN, (uint64_t)SXE2_HW_RATE_MAX);
+ error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE;
+ error->message = "invalid rate limit: value out of range.";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (profile->committed.rate > profile->peak.rate) {
+ PMD_LOG_ERR(DRV, "committed rate can't be greater than peak rate.");
+ error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE;
+ error->message = "committed rate can't be greater than peak rate.";
+ ret = -EINVAL;
+ goto l_end;
+ }
+l_end:
+ return ret;
+}
+
+static inline struct sxe2_tm_shaper_profile *
+sxe2_tm_shaper_profile_search(struct rte_eth_dev *dev, uint32_t id)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_shaper_profile_list *shaper_profile_list =
+ &adapter->tm_ctxt.profile_list;
+ struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+
+ TAILQ_FOREACH(shaper_profile, shaper_profile_list, node) {
+ if (id == shaper_profile->id)
+ goto l_end;
+ }
+
+ shaper_profile = NULL;
+
+l_end:
+ return shaper_profile;
+}
+
+static int32_t sxe2_tm_shaper_profile_add(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
+ const struct rte_tm_shaper_params *profile,
+ struct rte_tm_error *error)
+{
+ int32_t ret = -EINVAL;
+ struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (!profile || !error) {
+ PMD_LOG_ERR(DRV, "Invalid input: profile:0x%p or error:0x%p is null.",
+ profile, error);
+ if (error) {
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "Invalid input: profile or error is null.";
+ }
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+ PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "The TM capability is not supported.";
+ ret = ENOTSUP;
+ goto l_end;
+ }
+
+ ret = sxe2_tm_shaper_profile_param_check(profile, error);
+ if (ret)
+ goto l_end;
+
+ shaper_profile = sxe2_tm_shaper_profile_search(dev, shaper_profile_id);
+ if (shaper_profile) {
+ PMD_LOG_ERR(DRV, "profile ID exist.");
+ error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
+ error->message = "profile ID exist";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ shaper_profile = rte_zmalloc("sxe2_tm_shaper_profile",
+ sizeof(struct sxe2_tm_shaper_profile), 0);
+ if (!shaper_profile) {
+ PMD_LOG_ERR(DRV, "Alloc shaper_profile memory failed.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "Alloc shaper_profile memory failed";
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ rte_memcpy(&shaper_profile->profile, profile,
+ sizeof(struct rte_tm_shaper_params));
+ shaper_profile->id = shaper_profile_id;
+
+ TAILQ_INSERT_TAIL(&adapter->tm_ctxt.profile_list, shaper_profile, node);
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_tm_shaper_profile_del(struct rte_eth_dev *dev,
+ uint32_t id, struct rte_tm_error *error)
+{
+ int32_t ret = -EINVAL;
+ struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (!error) {
+ PMD_LOG_ERR(DRV, "Error param is null.");
+ goto l_end;
+ }
+
+ if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+ PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "The TM capability is not supported.";
+ ret = ENOTSUP;
+ goto l_end;
+ }
+
+ shaper_profile = sxe2_tm_shaper_profile_search(dev, id);
+ if (!shaper_profile) {
+ PMD_LOG_ERR(DRV, "profile ID not exist.");
+ error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
+ error->message = "profile ID not exist";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (shaper_profile->ref_cnt) {
+ PMD_LOG_ERR(DRV, "profile in use.");
+ error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE;
+ error->message = "profile in use";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ TAILQ_REMOVE(&adapter->tm_ctxt.profile_list, shaper_profile, node);
+ rte_free(shaper_profile);
+
+ ret = 0;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_tm_node_param_check(struct rte_eth_dev *dev,
+ uint32_t parent_node_type,
+ uint32_t node_id, uint32_t priority, uint32_t weight,
+ const struct rte_tm_node_params *params,
+ bool is_leaf, struct rte_tm_error *error)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+ int32_t ret = -EINVAL;
+
+ if (node_id == RTE_TM_NODE_ID_NULL) {
+ PMD_LOG_ERR(DRV, "Invalid node id.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "invalid node id";
+ goto l_end;
+ }
+
+ if (parent_node_type == SXE2_TM_NODE_TYPE_VSIG &&
+ priority >= tm_ctxt->prio_max) {
+ PMD_LOG_ERR(DRV, "Priority should be less than %u.", tm_ctxt->prio_max);
+ error->type = RTE_TM_ERROR_TYPE_NODE_PRIORITY;
+ error->message = "The priority is too high.";
+ goto l_end;
+ }
+
+ if (priority > SXE2_TM_PRIO_MAX) {
+ PMD_LOG_ERR(DRV, "Priority should be less than %u.", SXE2_TM_PRIO_MAX);
+ error->type = RTE_TM_ERROR_TYPE_NODE_PRIORITY;
+ error->message = "The priority is too high.";
+ goto l_end;
+ }
+
+ if (weight > SXE2_TM_WEIGHT_MAX || weight < SXE2_TM_WEIGHT_MIN) {
+ PMD_LOG_ERR(DRV, "Weight must be between 1 and 200.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_WEIGHT;
+ error->message = "weight must be between 1 and 200";
+ goto l_end;
+ }
+
+ if (params->shared_shaper_id) {
+ PMD_LOG_ERR(DRV, "Shared shaper not supported.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;
+ error->message = "shared shaper not supported";
+ goto l_end;
+ }
+ if (params->n_shared_shapers) {
+ PMD_LOG_ERR(DRV, "Shared shaper not supported..");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;
+ error->message = "shared shaper not supported";
+ goto l_end;
+ }
+
+ if (!is_leaf) {
+ if (node_id <= dev->data->nb_tx_queues) {
+ PMD_LOG_ERR(DRV, "no leaf node id must bigger than queue id.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "no leaf node id must bigger than queue id.";
+ goto l_end;
+ }
+
+ if (params->nonleaf.wfq_weight_mode) {
+ PMD_LOG_ERR(DRV, "WFQ not supported.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;
+ error->message = "WFQ not supported";
+ goto l_end;
+ }
+
+ if (params->nonleaf.n_sp_priorities != 1) {
+ PMD_LOG_ERR(DRV, "SP priority not supported.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;
+ error->message = "SP priority not supported";
+ goto l_end;
+ }
+ } else {
+ if (node_id >= dev->data->nb_tx_queues) {
+ PMD_LOG_ERR(DRV, "leaf node id must be queue id.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "leaf node id must be queue id.";
+ goto l_end;
+ }
+
+ if (params->leaf.cman) {
+ PMD_LOG_ERR(DRV, "Congestion management not supported.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;
+ error->message = "Congestion management not supported";
+ goto l_end;
+ }
+ if (params->leaf.wred.wred_profile_id != RTE_TM_WRED_PROFILE_ID_NONE) {
+ PMD_LOG_ERR(DRV, "WRED not supported.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;
+ error->message = "WRED not supported";
+ goto l_end;
+ }
+ if (params->leaf.wred.shared_wred_context_id) {
+ PMD_LOG_ERR(DRV, "WRED not supported.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;
+ error->message = "WRED not supported";
+ goto l_end;
+ }
+ if (params->leaf.wred.n_shared_wred_contexts) {
+ PMD_LOG_ERR(DRV, "WRED not supported.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;
+ error->message = "WRED not supported";
+ goto l_end;
+ }
+ }
+ ret = 0;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_tm_add_child(struct sxe2_tm_node *parent,
+ struct sxe2_tm_node *child)
+{
+ int32_t ret = -1;
+ uint32_t i;
+ for (i = 0; i < SXE2_TM_MAX_CHILDREN_COUNT; i++) {
+ if (parent->children[i] == NULL) {
+ parent->children[i] = child;
+ child->index_in_parent = i;
+ parent->child_cnt++;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int32_t sxe2_tm_node_add(struct rte_eth_dev *dev, uint32_t node_id, uint32_t parent_node_id,
+ uint32_t priority, uint32_t weight, uint32_t level_id,
+ const struct rte_tm_node_params *params,
+ struct rte_tm_error *error)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+ struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+ struct sxe2_tm_node *tm_node = NULL;
+ struct sxe2_tm_node *parent_node = NULL;
+ int32_t ret = -EINVAL;
+ bool is_leaf;
+
+ if (!params || !error) {
+ PMD_LOG_ERR(DRV, "Invalid input: params:0x%p or error:0x%p is null.",
+ params, error);
+ if (error) {
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "Invalid input: params or error is null.";
+ }
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+ PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "The TM capability is not supported.";
+ ret = ENOTSUP;
+ goto l_end;
+ }
+
+ shaper_profile = sxe2_tm_shaper_profile_search(dev, params->shaper_profile_id);
+ if (!shaper_profile) {
+ PMD_LOG_ERR(DRV, "Shaper profile does not exist.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;
+ error->message = "shaper profile does not exist";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (parent_node_id == RTE_TM_NODE_ID_NULL) {
+ if (level_id != 0) {
+ PMD_LOG_ERR(DRV, "Wrong level, root node (NULL parent) must be at level 0.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
+ error->message = "Wrong level, root node (NULL parent) must be at level 0";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (tm_ctxt->root) {
+ PMD_LOG_ERR(DRV, "Already have a root.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
+ error->message = "already have a root";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = sxe2_tm_node_param_check(dev, SXE2_TM_NODE_TYPE_INVALID, node_id, priority,
+ weight, params, false, error);
+ if (ret)
+ goto l_end;
+
+ tm_node = rte_zmalloc("tm_node_root", sizeof(struct sxe2_tm_node), 0);
+ if (!tm_node) {
+ PMD_LOG_ERR(DRV, "Alloc tm_node memory failed.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "Alloc tm_node memory failed";
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ tm_node->id = node_id;
+ tm_node->level = 0;
+ tm_node->parent = NULL;
+ tm_node->child_cnt = 0;
+ tm_node->weight = weight;
+ tm_node->hw_weight = SXE2_TM_WEIGHT_SUM;
+ tm_node->type = SXE2_TM_NODE_TYPE_VSIG;
+ tm_node->priority = priority;
+ tm_node->shaper_profile = shaper_profile;
+
+ tm_node->teid = tm_ctxt->root_teid;
+
+ shaper_profile->ref_cnt++;
+ tm_ctxt->root = tm_node;
+ ret = 0;
+ goto l_end;
+ }
+
+ parent_node = sxe2_tm_find_node(tm_ctxt->root, parent_node_id);
+ if (!parent_node) {
+ PMD_LOG_ERR(DRV, "Parent not exist.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
+ error->message = "parent not exist";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (parent_node->child_cnt >= SXE2_TM_MAX_CHILDREN_COUNT ||
+ (parent_node->type == SXE2_TM_NODE_TYPE_VSIG &&
+ parent_node->child_cnt >= tm_ctxt->root_max_children)) {
+ PMD_LOG_ERR(DRV, "Parent node is full.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
+ error->message = "parent node is full";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (level_id == RTE_TM_NODE_LEVEL_ID_ANY) {
+ level_id = parent_node->level + 1;
+ } else if (level_id != parent_node->level + 1) {
+ PMD_LOG_ERR(DRV, "Wrong level.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
+ error->message = "Wrong level";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (level_id >= tm_ctxt->tm_layers) {
+ PMD_LOG_ERR(DRV, "The maximum number of TM configuration levels is %d",
+ tm_ctxt->tm_layers);
+ error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
+ error->message = "TM level exceeds supported hardware limit";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (level_id + 1 == tm_ctxt->tm_layers)
+ is_leaf = true;
+ else
+ is_leaf = false;
+
+ ret = sxe2_tm_node_param_check(dev, parent_node->type, node_id, priority, weight,
+ params, is_leaf, error);
+ if (ret)
+ goto l_end;
+
+ if (sxe2_tm_find_node(tm_ctxt->root, node_id)) {
+ PMD_LOG_ERR(DRV, "Node id already used.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "node id already used";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ tm_node = rte_zmalloc("tm_node_no_root", sizeof(struct sxe2_tm_node), 0);
+ if (!tm_node) {
+ PMD_LOG_ERR(DRV, "Alloc tm_node memory failed.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "Alloc tm_node memory failed";
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ if (level_id + 1 != tm_ctxt->tm_layers)
+ tm_node->type = SXE2_TM_NODE_TYPE_MID;
+ else
+ tm_node->type = SXE2_TM_NODE_TYPE_QUEUE;
+ tm_node->id = node_id;
+ tm_node->level = level_id;
+ tm_node->parent = parent_node;
+ tm_node->child_cnt = 0;
+ tm_node->weight = weight;
+ tm_node->priority = priority;
+ tm_node->shaper_profile = shaper_profile;
+ shaper_profile->ref_cnt++;
+
+ ret = sxe2_tm_add_child(parent_node, tm_node);
+ if (ret) {
+ shaper_profile->ref_cnt--;
+ rte_free(tm_node);
+ }
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_tm_tree_delete(struct sxe2_tm_node *tm_node)
+{
+ int32_t ret = 0;
+ uint32_t i, j;
+ struct sxe2_tm_node *parent = NULL;
+
+ if (!tm_node)
+ goto l_end;
+
+ parent = tm_node->parent;
+
+ if (tm_node->child_cnt != 0) {
+ for (i = SXE2_TM_MAX_CHILDREN_COUNT; i > 0; i--) {
+ if (tm_node->children[i - 1])
+ ret = sxe2_tm_tree_delete(tm_node->children[i - 1]);
+ }
+ }
+
+ if (tm_node->shaper_profile)
+ tm_node->shaper_profile->ref_cnt--;
+
+ if (tm_node->type != SXE2_TM_NODE_TYPE_VSIG && parent) {
+ for (i = 0; i < parent->child_cnt; i++) {
+ if (parent->children[i] == tm_node)
+ break;
+ }
+ for (j = i; j < parent->child_cnt - 1; j++)
+ parent->children[j] = parent->children[j + 1];
+
+ parent->children[parent->child_cnt - 1] = NULL;
+ parent->child_cnt--;
+ }
+ rte_free(tm_node);
+ tm_node = NULL;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_tm_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
+ struct rte_tm_error *error)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+ struct sxe2_tm_node *tm_node = NULL;
+ int32_t ret = -EINVAL;
+
+ if (!error) {
+ PMD_LOG_ERR(DRV, "Invalid input: error is null.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+ PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "The TM capability is not supported.";
+ ret = ENOTSUP;
+ goto l_end;
+ }
+
+ if (node_id == RTE_TM_NODE_ID_NULL) {
+ PMD_LOG_ERR(DRV, "Invalid node id. node_id = %u", node_id);
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "invalid node id";
+ goto l_end;
+ }
+
+ tm_node = sxe2_tm_find_node(tm_ctxt->root, node_id);
+ if (!tm_node) {
+ PMD_LOG_ERR(DRV, "No such node.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "no such node";
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = sxe2_tm_tree_delete(tm_node);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Delete node failed.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "Delete node failed";
+ goto l_end;
+ }
+
+ if (tm_node == tm_ctxt->root)
+ tm_ctxt->root = NULL;
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_tm_node_type_get(struct rte_eth_dev *dev, uint32_t node_id,
+ int32_t *is_leaf, struct rte_tm_error *error)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+ struct sxe2_tm_node *tm_node = NULL;
+ int32_t ret = -EINVAL;
+
+ if (!is_leaf || !error) {
+ PMD_LOG_ERR(DRV, "Invalid input: is_leaf:0x%p or error:0x%p is null.",
+ is_leaf, error);
+ if (error) {
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "Invalid input: is_leaf or error is null";
+ }
+ goto l_end;
+ }
+
+ if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+ PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "The TM capability is not supported.";
+ ret = ENOTSUP;
+ goto l_end;
+ }
+
+ if (node_id == RTE_TM_NODE_ID_NULL) {
+ PMD_LOG_ERR(DRV, "Invalid node id.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "invalid node id";
+ goto l_end;
+ }
+
+ tm_node = sxe2_tm_find_node(tm_ctxt->root, node_id);
+ if (!tm_node) {
+ PMD_LOG_ERR(DRV, "No such node.");
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "no such node";
+ goto l_end;
+ }
+
+ if (tm_node->level + 1 == tm_ctxt->tm_layers)
+ *is_leaf = true;
+ else
+ *is_leaf = false;
+ ret = 0;
+l_end:
+ return ret;
+}
+
+int32_t sxe2_tm_uninit(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+ struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+ int32_t ret = 0;
+
+ if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+ ret = 0;
+ goto l_end;
+ }
+
+ tm_ctxt->tm_layers = 0;
+ tm_ctxt->root_max_children = 0;
+ tm_ctxt->committed = false;
+
+ (void)sxe2_tm_tree_delete(tm_ctxt->root);
+
+ while ((shaper_profile = TAILQ_FIRST(&tm_ctxt->profile_list))) {
+ TAILQ_REMOVE(&tm_ctxt->profile_list, shaper_profile, node);
+ rte_free(shaper_profile);
+ }
+l_end:
+ return ret;
+}
+
+int32_t sxe2_tm_init(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_sched_hw_cap *sched_ctxt = &adapter->sched_ctxt;
+ struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+ int32_t ret = 0;
+ struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+
+ if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0)
+ goto l_end;
+
+ tm_ctxt->tm_layers = sched_ctxt->tm_layers;
+ tm_ctxt->root_max_children = sched_ctxt->root_max_children;
+ tm_ctxt->prio_max = sched_ctxt->prio_max;
+ tm_ctxt->committed = false;
+ TAILQ_INIT(&tm_ctxt->profile_list);
+ tm_ctxt->root = NULL;
+
+ shaper_profile = rte_zmalloc("sxe2_tm_shaper_profile",
+ sizeof(struct sxe2_tm_shaper_profile), 0);
+ if (!shaper_profile) {
+ PMD_LOG_ERR(DRV, "Alloc shaper_profile memory failed.");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ shaper_profile->id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+ shaper_profile->ref_cnt = 1;
+ shaper_profile->profile.committed.rate = UINT64_MAX;
+ shaper_profile->profile.peak.rate = UINT64_MAX;
+ TAILQ_INSERT_TAIL(&tm_ctxt->profile_list, shaper_profile, node);
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_tm_chk_all_leaf(struct rte_eth_dev *dev)
+{
+ int32_t ret = 0;
+ uint32_t i = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ for (i = 0; i < dev->data->nb_tx_queues; i++) {
+ if (!sxe2_tm_find_node(adapter->tm_ctxt.root, i)) {
+ ret = -1;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int32_t sxe2_tm_weight_calc(struct sxe2_tm_node *tm_node)
+{
+ int32_t ret = 0;
+ int32_t total_weight = 0;
+ int32_t total_weight2 = 0;
+ uint32_t i = 0;
+ uint32_t j = 0;
+ uint32_t k = 0;
+ uint32_t maxindex = 0;
+ uint32_t maxweight = 0;
+ struct sxe2_tm_node *cacl_node[SXE2_TM_MAX_CHILDREN_COUNT] = {NULL};
+
+ if (!tm_node) {
+ PMD_LOG_ERR(DRV, "Invalid input: tm_node is null.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (tm_node->child_cnt == 0)
+ goto l_end;
+
+ for (j = SXE2_TM_PRIO_MIN; j <= SXE2_TM_PRIO_MAX; j++) {
+ k = 0;
+ total_weight = 0;
+ total_weight2 = 0;
+ maxindex = 0;
+ maxweight = 0;
+
+ for (i = 0; i < tm_node->child_cnt; i++) {
+ if (tm_node->children[i]->priority == j)
+ cacl_node[k++] = tm_node->children[i];
+ }
+ if (k == 0)
+ continue;
+
+ for (i = 0; i < k; i++)
+ total_weight += cacl_node[i]->weight;
+
+ for (i = 0; i < k; i++) {
+ cacl_node[i]->hw_weight = cacl_node[i]->weight *
+ SXE2_TM_WEIGHT_SUM / total_weight;
+ total_weight2 += cacl_node[i]->hw_weight;
+ if (cacl_node[i]->hw_weight > maxweight) {
+ maxweight = cacl_node[i]->hw_weight;
+ maxindex = i;
+ }
+ }
+
+ cacl_node[maxindex]->hw_weight += SXE2_TM_WEIGHT_SUM - total_weight2;
+ }
+
+ for (i = 0; i < tm_node->child_cnt; i++) {
+ ret = sxe2_tm_weight_calc(tm_node->children[i]);
+ if (ret)
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_tm_hierarchy_commit(struct rte_eth_dev *dev,
+ int32_t clear_on_fail, struct rte_tm_error *error)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = -EINVAL;
+
+ if (!error) {
+ PMD_LOG_ERR(DRV, "Invalid input: error is null.");
+ ret = -EINVAL;
+ goto l_clear_on_fail;
+ }
+
+ if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+ PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "The TM capability is not supported.";
+ ret = ENOTSUP;
+ goto l_clear_on_fail;
+ }
+
+ if (dev->data->dev_started) {
+ PMD_LOG_ERR(DRV, "Device failed to Stop.");
+ error->message = "Device failed to Stop";
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ ret = -EPERM;
+ goto l_clear_on_fail;
+ }
+
+ ret = sxe2_tm_chk_all_leaf(dev);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "All tx queues need config.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "All tx queues need config.";
+ goto l_clear_on_fail;
+ }
+
+ ret = sxe2_tm_weight_calc(adapter->tm_ctxt.root);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "The weight in tree is wrong.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "The weight in tree is wrong.";
+ goto l_clear_on_fail;
+ }
+
+ ret = sxe2_drv_tm_commit(adapter);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Commit tree to fw failed.");
+ error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+ error->message = "Commit tree to fw failed.";
+ goto l_clear_on_fail;
+ }
+
+ adapter->tm_ctxt.committed = true;
+ ret = 0;
+ goto l_end;
+
+l_clear_on_fail:
+ if (clear_on_fail) {
+ (void)sxe2_tm_uninit(dev);
+ (void)sxe2_tm_init(dev);
+ }
+
+l_end:
+ return ret;
+}
+
+static const struct rte_tm_ops sxe2_tm_ops = {
+ .capabilities_get = sxe2_tm_capabilities_get,
+ .level_capabilities_get = sxe2_level_capabilities_get,
+ .node_capabilities_get = sxe2_node_capabilities_get,
+ .shaper_profile_add = sxe2_tm_shaper_profile_add,
+ .shaper_profile_delete = sxe2_tm_shaper_profile_del,
+ .node_add = sxe2_tm_node_add,
+ .node_delete = sxe2_tm_node_delete,
+ .node_type_get = sxe2_tm_node_type_get,
+
+ .hierarchy_commit = sxe2_tm_hierarchy_commit,
+};
+
+int32_t sxe2_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
+{
+ int32_t ret = 0;
+
+ if (!arg) {
+ ret = -EINVAL;
+ PMD_LOG_ERR(DRV, "%s failed because arg is NULL", __func__);
+ goto l_end;
+ }
+ *(const void **)arg = &sxe2_tm_ops;
+l_end:
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_tm.h b/drivers/net/sxe2/sxe2_tm.h
new file mode 100644
index 0000000000..c4f8da6a8e
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_tm.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_TM_H__
+#define __SXE2_TM_H__
+#include <ethdev_driver.h>
+#include <rte_flow_driver.h>
+#include "sxe2_osal.h"
+
+#define SXE2_TM_MAX_LEVEL 7
+#define SXE2_TM_1L_NODE_NUM_MAX 1
+#define SXE2_TM_2L_NODE_NUM_MAX 8
+#define SXE2_TM_3L_NODE_NUM_MAX 64
+#define SXE2_TM_4L_NODE_NUM_MAX 256
+
+#define SXE2_TM_MAX_CHILDREN_COUNT 8
+
+#define SXE2_TM_WEIGHT_MAX (200)
+#define SXE2_TM_WEIGHT_MIN (1)
+#define SXE2_TM_WEIGHT_SUM (32768)
+
+#define SXE2_HW_RATE_MIN 62500ull
+#define SXE2_HW_RATE_MAX 12500000000ull
+
+#define SXE2_TM_PRIO_MAX (7)
+#define SXE2_TM_PRIO_MIN (0)
+
+enum sxe2_tm_node_type {
+ SXE2_TM_NODE_TYPE_VSIG = 0,
+ SXE2_TM_NODE_TYPE_MID,
+ SXE2_TM_NODE_TYPE_QUEUE,
+ SXE2_TM_NODE_TYPE_INVALID,
+};
+
+struct sxe2_tm_shaper_profile {
+ TAILQ_ENTRY(sxe2_tm_shaper_profile) node;
+ uint32_t id;
+ uint32_t ref_cnt;
+ struct rte_tm_shaper_params profile;
+};
+
+TAILQ_HEAD(sxe2_shaper_profile_list, sxe2_tm_shaper_profile);
+
+struct sxe2_tm_node {
+ uint16_t id;
+ uint16_t teid;
+ uint32_t level;
+ uint32_t child_cnt;
+ uint32_t type;
+ uint16_t hw_weight;
+ uint16_t weight;
+ uint8_t priority;
+ struct sxe2_tm_node *parent;
+ uint8_t index_in_parent;
+ struct sxe2_tm_node *children[SXE2_TM_MAX_CHILDREN_COUNT];
+ struct sxe2_tm_shaper_profile *shaper_profile;
+};
+
+struct sxe2_tm_context {
+ uint32_t tm_layers;
+ uint16_t root_teid;
+ uint8_t root_max_children;
+ uint8_t prio_max;
+ bool committed;
+ struct sxe2_tm_node *root;
+ struct sxe2_shaper_profile_list profile_list;
+};
+
+int32_t sxe2_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg);
+
+int32_t sxe2_tm_init(struct rte_eth_dev *dev);
+
+int32_t sxe2_tm_uninit(struct rte_eth_dev *dev);
+
+#endif /* __SXE2_TM_H__ */
diff --git a/drivers/net/sxe2/sxe2_tx.c b/drivers/net/sxe2/sxe2_tx.c
index a05beb8c7a..a280edc9c5 100644
--- a/drivers/net/sxe2/sxe2_tx.c
+++ b/drivers/net/sxe2/sxe2_tx.c
@@ -304,7 +304,6 @@ int32_t __rte_cold sxe2_tx_queue_setup(struct rte_eth_dev *dev,
}
offloads = tx_conf->offloads | dev->data->dev_conf.txmode.offloads;
-
txq = sxe2_tx_queue_alloc(dev, queue_idx, nb_desc, socket_id);
if (txq == NULL) {
PMD_LOG_ERR(TX, "failed to alloc sxe2vf tx queue:%u resource", queue_idx);
--
2.52.0
More information about the dev
mailing list