[dpdk-dev] [PATCH v4 05/14] drivers/net/ipn3ke: add IPN3KE TM of PMD driver

Rosen Xu rosen.xu at intel.com
Wed Apr 3 10:46:35 CEST 2019


Add Intel FPGA Acceleration NIC IPN3KE TM of PMD driver.

Signed-off-by: Rosen Xu <rosen.xu at intel.com>
Signed-off-by: Andy Pei <andy.pei at intel.com>
Signed-off-by: Dan Wei <dan.wei at intel.com>
---
 drivers/net/ipn3ke/Makefile             |    1 +
 drivers/net/ipn3ke/ipn3ke_ethdev.c      |    3 +
 drivers/net/ipn3ke/ipn3ke_ethdev.h      |    6 +
 drivers/net/ipn3ke/ipn3ke_representor.c |    5 +-
 drivers/net/ipn3ke/ipn3ke_tm.c          | 2086 +++++++++++++++++++++++++++++++
 drivers/net/ipn3ke/meson.build          |    3 +-
 6 files changed, 2102 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ipn3ke/ipn3ke_tm.c

diff --git a/drivers/net/ipn3ke/Makefile b/drivers/net/ipn3ke/Makefile
index 828df3a..903ec39 100644
--- a/drivers/net/ipn3ke/Makefile
+++ b/drivers/net/ipn3ke/Makefile
@@ -33,5 +33,6 @@ LIBABIVER := 1
 #
 SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_representor.c
+SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_tm.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.c b/drivers/net/ipn3ke/ipn3ke_ethdev.c
index dc20009..55e83db 100644
--- a/drivers/net/ipn3ke/ipn3ke_ethdev.c
+++ b/drivers/net/ipn3ke/ipn3ke_ethdev.c
@@ -314,6 +314,9 @@ static int ipn3ke_indirect_mac_write(struct ipn3ke_hw *hw,
 	hw->flow_hw_enable = 0;
 	if (afu_dev->id.uuid.uuid_low == IPN3KE_UUID_VBNG_LOW &&
 		afu_dev->id.uuid.uuid_high == IPN3KE_UUID_VBNG_HIGH) {
+		ret = ipn3ke_hw_tm_init(hw);
+		if (ret)
+			return ret;
 		hw->tm_hw_enable = 1;
 	}
 
diff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.h b/drivers/net/ipn3ke/ipn3ke_ethdev.h
index 3baa9fe..95bc188 100644
--- a/drivers/net/ipn3ke/ipn3ke_ethdev.h
+++ b/drivers/net/ipn3ke/ipn3ke_ethdev.h
@@ -148,6 +148,12 @@ enum ipn3ke_tm_node_priority {
 
 #define IPN3KE_TM_NODE_WEIGHT_MAX UINT8_MAX
 
+void
+ipn3ke_tm_init(struct ipn3ke_rpst *rpst);
+int
+ipn3ke_tm_ops_get(struct rte_eth_dev *ethdev,
+		void *arg);
+
 /** Set a bit in the uint32 variable */
 #define IPN3KE_BIT_SET(var, pos) \
 	((var) |= ((uint32_t)1 << ((pos))))
diff --git a/drivers/net/ipn3ke/ipn3ke_representor.c b/drivers/net/ipn3ke/ipn3ke_representor.c
index fdb4b5c..0d527eb 100644
--- a/drivers/net/ipn3ke/ipn3ke_representor.c
+++ b/drivers/net/ipn3ke/ipn3ke_representor.c
@@ -869,7 +869,7 @@ struct eth_dev_ops ipn3ke_rpst_dev_ops = {
 	.mac_addr_set         = ipn3ke_rpst_mac_addr_set,
 	.mtu_set              = ipn3ke_rpst_mtu_set,
 
-	.tm_ops_get           = NULL,
+	.tm_ops_get           = ipn3ke_tm_ops_get,
 };
 
 static uint16_t ipn3ke_rpst_recv_pkts(__rte_unused void *rx_q,
@@ -909,6 +909,9 @@ static uint16_t ipn3ke_rpst_recv_pkts(__rte_unused void *rx_q,
 		return -ENODEV;
 	}
 
+	if (rpst->hw->tm_hw_enable)
+		ipn3ke_tm_init(rpst);
+
 	/** representor shares the same driver as it's PF device */
 	/**
 	 * ethdev->device->driver = rpst->hw->eth_dev->device->driver;
diff --git a/drivers/net/ipn3ke/ipn3ke_tm.c b/drivers/net/ipn3ke/ipn3ke_tm.c
new file mode 100644
index 0000000..54409ea
--- /dev/null
+++ b/drivers/net/ipn3ke/ipn3ke_tm.c
@@ -0,0 +1,2086 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_bus_pci.h>
+#include <rte_ethdev.h>
+#include <rte_pci.h>
+#include <rte_malloc.h>
+#include <rte_tm_driver.h>
+
+#include <rte_mbuf.h>
+#include <rte_sched.h>
+#include <rte_ethdev_driver.h>
+
+#include <rte_io.h>
+#include <rte_rawdev.h>
+#include <rte_rawdev_pmd.h>
+#include <rte_bus_ifpga.h>
+#include <ifpga_logs.h>
+
+#include "ipn3ke_rawdev_api.h"
+#include "ipn3ke_logs.h"
+#include "ipn3ke_ethdev.h"
+
+#define BYTES_IN_MBPS     (1000 * 1000 / 8)
+#define SUBPORT_TC_PERIOD 10
+#define PIPE_TC_PERIOD    40
+
+struct ipn3ke_tm_shaper_params_range_type {
+	uint32_t m1;
+	uint32_t m2;
+	uint32_t exp;
+	uint32_t exp2;
+	uint32_t low;
+	uint32_t high;
+};
+struct ipn3ke_tm_shaper_params_range_type ipn3ke_tm_shaper_params_rang[] = {
+	{  0,       1,     0,        1,           0,            4},
+	{  2,       3,     0,        1,           8,           12},
+	{  4,       7,     0,        1,          16,           28},
+	{  8,      15,     0,        1,          32,           60},
+	{ 16,      31,     0,        1,          64,          124},
+	{ 32,      63,     0,        1,         128,          252},
+	{ 64,     127,     0,        1,         256,          508},
+	{128,     255,     0,        1,         512,         1020},
+	{256,     511,     0,        1,        1024,         2044},
+	{512,    1023,     0,        1,        2048,         4092},
+	{512,    1023,     1,        2,        4096,         8184},
+	{512,    1023,     2,        4,        8192,        16368},
+	{512,    1023,     3,        8,       16384,        32736},
+	{512,    1023,     4,       16,       32768,        65472},
+	{512,    1023,     5,       32,       65536,       130944},
+	{512,    1023,     6,       64,      131072,       261888},
+	{512,    1023,     7,      128,      262144,       523776},
+	{512,    1023,     8,      256,      524288,      1047552},
+	{512,    1023,     9,      512,     1048576,      2095104},
+	{512,    1023,    10,     1024,     2097152,      4190208},
+	{512,    1023,    11,     2048,     4194304,      8380416},
+	{512,    1023,    12,     4096,     8388608,     16760832},
+	{512,    1023,    13,     8192,    16777216,     33521664},
+	{512,    1023,    14,    16384,    33554432,     67043328},
+	{512,    1023,    15,    32768,    67108864,    134086656},
+};
+
+#define IPN3KE_TM_SHAPER_RANGE_NUM (sizeof(ipn3ke_tm_shaper_params_rang) / \
+	sizeof(struct ipn3ke_tm_shaper_params_range_type))
+
+#define IPN3KE_TM_SHAPER_COMMITTED_RATE_MAX \
+	(ipn3ke_tm_shaper_params_rang[IPN3KE_TM_SHAPER_RANGE_NUM - 1].high)
+
+#define IPN3KE_TM_SHAPER_PEAK_RATE_MAX \
+	(ipn3ke_tm_shaper_params_rang[IPN3KE_TM_SHAPER_RANGE_NUM - 1].high)
+
+int
+ipn3ke_hw_tm_init(struct ipn3ke_hw *hw)
+{
+#define SCRATCH_DATA 0xABCDEF
+	struct ipn3ke_tm_node *nodes;
+	struct ipn3ke_tm_tdrop_profile *tdrop_profile;
+	int node_num;
+	int i;
+
+	if (hw == NULL)
+		return -EINVAL;
+#if IPN3KE_TM_SCRATCH_RW
+	uint32_t scratch_data;
+	IPN3KE_MASK_WRITE_REG(hw,
+					IPN3KE_TM_SCRATCH,
+					0,
+					SCRATCH_DATA,
+					0xFFFFFFFF);
+	scratch_data = IPN3KE_MASK_READ_REG(hw,
+					IPN3KE_TM_SCRATCH,
+					0,
+					0xFFFFFFFF);
+	if (scratch_data != SCRATCH_DATA)
+		return -EINVAL;
+#endif
+	/* alloc memory for all hierarchy nodes */
+	node_num = hw->port_num +
+		IPN3KE_TM_VT_NODE_NUM +
+		IPN3KE_TM_COS_NODE_NUM;
+
+	nodes = rte_zmalloc("ipn3ke_tm_nodes",
+			sizeof(struct ipn3ke_tm_node) * node_num,
+			0);
+	if (!nodes)
+		return -ENOMEM;
+
+	/* alloc memory for Tail Drop Profile */
+	tdrop_profile = rte_zmalloc("ipn3ke_tm_tdrop_profile",
+				sizeof(struct ipn3ke_tm_tdrop_profile) *
+				IPN3KE_TM_TDROP_PROFILE_NUM,
+				0);
+	if (!tdrop_profile) {
+		rte_free(nodes);
+		return -ENOMEM;
+	}
+
+	hw->nodes = nodes;
+	hw->port_nodes = nodes;
+	hw->vt_nodes = hw->port_nodes + hw->port_num;
+	hw->cos_nodes = hw->vt_nodes + IPN3KE_TM_VT_NODE_NUM;
+	hw->tdrop_profile = tdrop_profile;
+	hw->tdrop_profile_num = IPN3KE_TM_TDROP_PROFILE_NUM;
+
+	for (i = 0, nodes = hw->port_nodes;
+		i < hw->port_num;
+		i++, nodes++) {
+		nodes->node_index = i;
+		nodes->level = IPN3KE_TM_NODE_LEVEL_PORT;
+		nodes->tm_id = RTE_TM_NODE_ID_NULL;
+		nodes->node_state = IPN3KE_TM_NODE_STATE_IDLE;
+		nodes->parent_node_id = RTE_TM_NODE_ID_NULL;
+		nodes->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
+		nodes->weight = 0;
+		nodes->parent_node = NULL;
+		nodes->shaper_profile.valid = 0;
+		nodes->tdrop_profile = NULL;
+		nodes->n_children = 0;
+		TAILQ_INIT(&nodes->children_node_list);
+	}
+
+	for (i = 0, nodes = hw->vt_nodes;
+		i < IPN3KE_TM_VT_NODE_NUM;
+		i++, nodes++) {
+		nodes->node_index = i;
+		nodes->level = IPN3KE_TM_NODE_LEVEL_VT;
+		nodes->tm_id = RTE_TM_NODE_ID_NULL;
+		nodes->node_state = IPN3KE_TM_NODE_STATE_IDLE;
+		nodes->parent_node_id = RTE_TM_NODE_ID_NULL;
+		nodes->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
+		nodes->weight = 0;
+		nodes->parent_node = NULL;
+		nodes->shaper_profile.valid = 0;
+		nodes->tdrop_profile = NULL;
+		nodes->n_children = 0;
+		TAILQ_INIT(&nodes->children_node_list);
+	}
+
+	for (i = 0, nodes = hw->cos_nodes;
+		i < IPN3KE_TM_COS_NODE_NUM;
+		i++, nodes++) {
+		nodes->node_index = i;
+		nodes->level = IPN3KE_TM_NODE_LEVEL_COS;
+		nodes->tm_id = RTE_TM_NODE_ID_NULL;
+		nodes->node_state = IPN3KE_TM_NODE_STATE_IDLE;
+		nodes->parent_node_id = RTE_TM_NODE_ID_NULL;
+		nodes->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
+		nodes->weight = 0;
+		nodes->parent_node = NULL;
+		nodes->shaper_profile.valid = 0;
+		nodes->tdrop_profile = NULL;
+		nodes->n_children = 0;
+		TAILQ_INIT(&nodes->children_node_list);
+	}
+
+	for (i = 0, tdrop_profile = hw->tdrop_profile;
+		i < IPN3KE_TM_TDROP_PROFILE_NUM;
+		i++, tdrop_profile++) {
+		tdrop_profile->tdrop_profile_id = i;
+		tdrop_profile->n_users = 0;
+		tdrop_profile->valid = 0;
+	}
+
+	return 0;
+}
+void
+ipn3ke_tm_init(struct ipn3ke_rpst *rpst)
+{
+	struct ipn3ke_tm_internals *tm;
+	struct ipn3ke_tm_node *port_node;
+
+	tm = &rpst->tm;
+
+	port_node = &rpst->hw->port_nodes[rpst->port_id];
+	tm->h.port_node = port_node;
+
+	tm->h.n_shaper_profiles = 0;
+	tm->h.n_tdrop_profiles = 0;
+	tm->h.n_vt_nodes = 0;
+	tm->h.n_cos_nodes = 0;
+
+	tm->h.port_commit_node = NULL;
+	TAILQ_INIT(&tm->h.vt_commit_node_list);
+	TAILQ_INIT(&tm->h.cos_commit_node_list);
+
+	tm->hierarchy_frozen = 0;
+	tm->tm_started = 1;
+	tm->tm_id = rpst->port_id;
+}
+
+static struct ipn3ke_tm_shaper_profile *
+ipn3ke_hw_tm_shaper_profile_search(struct ipn3ke_hw *hw,
+						uint32_t shaper_profile_id,
+						struct rte_tm_error *error)
+{
+	struct ipn3ke_tm_shaper_profile *sp = NULL;
+	uint32_t level_of_node_id;
+	uint32_t node_index;
+
+	/* Shaper profile ID must not be NONE. */
+	if (shaper_profile_id == RTE_TM_SHAPER_PROFILE_ID_NONE) {
+		rte_tm_error_set(error,
+				EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+				NULL,
+				rte_strerror(EINVAL));
+
+		return NULL;
+	}
+
+	level_of_node_id = shaper_profile_id / IPN3KE_TM_NODE_LEVEL_MOD;
+	node_index = shaper_profile_id % IPN3KE_TM_NODE_LEVEL_MOD;
+
+	switch (level_of_node_id) {
+	case IPN3KE_TM_NODE_LEVEL_PORT:
+		if (node_index >= hw->port_num)
+			rte_tm_error_set(error,
+					EEXIST,
+					RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					NULL,
+					rte_strerror(EEXIST));
+		else
+			sp = &hw->port_nodes[node_index].shaper_profile;
+
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_VT:
+		if (node_index >= IPN3KE_TM_VT_NODE_NUM)
+			rte_tm_error_set(error,
+					EEXIST,
+					RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					NULL,
+					rte_strerror(EEXIST));
+		else
+			sp = &hw->vt_nodes[node_index].shaper_profile;
+
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_COS:
+		if (node_index >= IPN3KE_TM_COS_NODE_NUM)
+			rte_tm_error_set(error,
+					EEXIST,
+					RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					NULL,
+					rte_strerror(EEXIST));
+		else
+			sp = &hw->cos_nodes[node_index].shaper_profile;
+
+		break;
+	default:
+		rte_tm_error_set(error,
+				EEXIST,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+				NULL,
+				rte_strerror(EEXIST));
+	}
+
+	return sp;
+}
+
+static struct ipn3ke_tm_tdrop_profile *
+ipn3ke_hw_tm_tdrop_profile_search(struct ipn3ke_hw *hw,
+	uint32_t tdrop_profile_id)
+{
+	struct ipn3ke_tm_tdrop_profile *tdrop_profile;
+
+	if (tdrop_profile_id >= hw->tdrop_profile_num)
+		return NULL;
+
+	tdrop_profile = &hw->tdrop_profile[tdrop_profile_id];
+	if (tdrop_profile->valid)
+		return tdrop_profile;
+
+	return NULL;
+}
+
+static struct ipn3ke_tm_node *
+ipn3ke_hw_tm_node_search(struct ipn3ke_hw *hw, uint32_t tm_id,
+	uint32_t node_id, uint32_t state_mask)
+{
+	uint32_t level_of_node_id;
+	uint32_t node_index;
+	struct ipn3ke_tm_node *n;
+
+	level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD;
+	node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD;
+
+	switch (level_of_node_id) {
+	case IPN3KE_TM_NODE_LEVEL_PORT:
+		if (node_index >= hw->port_num)
+			return NULL;
+		n = &hw->port_nodes[node_index];
+
+		break;
+	case IPN3KE_TM_NODE_LEVEL_VT:
+		if (node_index >= IPN3KE_TM_VT_NODE_NUM)
+			return NULL;
+		n = &hw->vt_nodes[node_index];
+
+		break;
+	case IPN3KE_TM_NODE_LEVEL_COS:
+		if (node_index >= IPN3KE_TM_COS_NODE_NUM)
+			return NULL;
+		n = &hw->cos_nodes[node_index];
+
+		break;
+	default:
+		return NULL;
+	}
+
+	/* Check tm node status */
+	if (n->node_state == IPN3KE_TM_NODE_STATE_IDLE) {
+		if (n->tm_id != RTE_TM_NODE_ID_NULL ||
+		n->parent_node_id != RTE_TM_NODE_ID_NULL ||
+		n->parent_node != NULL ||
+		n->n_children > 0) {
+			IPN3KE_AFU_PMD_ERR("tm node check error %d", 1);
+		}
+	} else if (n->node_state < IPN3KE_TM_NODE_STATE_MAX) {
+		if (n->tm_id == RTE_TM_NODE_ID_NULL ||
+		(level_of_node_id != IPN3KE_TM_NODE_LEVEL_PORT &&
+			n->parent_node_id == RTE_TM_NODE_ID_NULL) ||
+		(level_of_node_id != IPN3KE_TM_NODE_LEVEL_PORT &&
+			n->parent_node == NULL)) {
+			IPN3KE_AFU_PMD_ERR("tm node check error %d", 1);
+		}
+	} else {
+		IPN3KE_AFU_PMD_ERR("tm node check error %d", 1);
+	}
+
+	if (IPN3KE_BIT_ISSET(state_mask, n->node_state)) {
+		if (n->node_state == IPN3KE_TM_NODE_STATE_IDLE)
+			return n;
+		else if (n->tm_id == tm_id)
+			return n;
+		else
+			return NULL;
+	} else {
+		return NULL;
+	}
+}
+
+/* Traffic manager node type get */
+static int
+ipn3ke_pmd_tm_node_type_get(struct rte_eth_dev *dev,
+	uint32_t node_id,
+	int *is_leaf,
+	struct rte_tm_error *error)
+{
+	struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	uint32_t tm_id;
+	struct ipn3ke_tm_node *node;
+	uint32_t state_mask;
+
+	if (is_leaf == NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					NULL,
+					rte_strerror(EINVAL));
+
+	tm_id = tm->tm_id;
+
+	state_mask = 0;
+	IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED);
+	node = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask);
+	if (node_id == RTE_TM_NODE_ID_NULL ||
+		node == NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	*is_leaf = (node->level == IPN3KE_TM_NODE_LEVEL_COS) ? 1 : 0;
+
+	return 0;
+}
+
+#define WRED_SUPPORTED    0
+
+#define STATS_MASK_DEFAULT \
+	(RTE_TM_STATS_N_PKTS | \
+	RTE_TM_STATS_N_BYTES | \
+	RTE_TM_STATS_N_PKTS_GREEN_DROPPED | \
+	RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+
+#define STATS_MASK_QUEUE \
+	(STATS_MASK_DEFAULT | RTE_TM_STATS_N_PKTS_QUEUED)
+
+/* Traffic manager capabilities get */
+static int
+ipn3ke_tm_capabilities_get(__rte_unused struct rte_eth_dev *dev,
+	struct rte_tm_capabilities *cap,
+	struct rte_tm_error *error)
+{
+	if (cap == NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_CAPABILITIES,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* set all the parameters to 0 first. */
+	memset(cap, 0, sizeof(*cap));
+
+	cap->n_nodes_max = 1 + IPN3KE_TM_COS_NODE_NUM + IPN3KE_TM_VT_NODE_NUM;
+	cap->n_levels_max = IPN3KE_TM_NODE_LEVEL_MAX;
+
+	cap->non_leaf_nodes_identical = 0;
+	cap->leaf_nodes_identical = 1;
+
+	cap->shaper_n_max = 1 + IPN3KE_TM_VT_NODE_NUM;
+	cap->shaper_private_n_max = 1 + IPN3KE_TM_VT_NODE_NUM;
+	cap->shaper_private_dual_rate_n_max = 0;
+	cap->shaper_private_rate_min = 1;
+	cap->shaper_private_rate_max = 1 + IPN3KE_TM_VT_NODE_NUM;
+
+	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_pkt_length_adjust_min = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+	cap->shaper_pkt_length_adjust_max = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	cap->sched_n_children_max = IPN3KE_TM_COS_NODE_NUM;
+	cap->sched_sp_n_priorities_max = 3;
+	cap->sched_wfq_n_children_per_group_max = UINT32_MAX;
+	cap->sched_wfq_n_groups_max = 1;
+	cap->sched_wfq_weight_max = UINT32_MAX;
+
+	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->mark_vlan_dei_supported = {0, 0, 0};
+	 * cap->mark_ip_ecn_tcp_supported = {0, 0, 0};
+	 * cap->mark_ip_ecn_sctp_supported = {0, 0, 0};
+	 * cap->mark_ip_dscp_supported = {0, 0, 0};
+	 */
+
+	cap->dynamic_update_mask = 0;
+
+	cap->stats_mask = 0;
+
+	return 0;
+}
+
+/* Traffic manager level capabilities get */
+static int
+ipn3ke_tm_level_capabilities_get(struct rte_eth_dev *dev,
+	uint32_t level_id,
+	struct rte_tm_level_capabilities *cap,
+	struct rte_tm_error *error)
+{
+	struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
+
+	if (cap == NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_CAPABILITIES,
+					NULL,
+					rte_strerror(EINVAL));
+
+	if (level_id >= IPN3KE_TM_NODE_LEVEL_MAX)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_LEVEL_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* set all the parameters to 0 first. */
+	memset(cap, 0, sizeof(*cap));
+
+	switch (level_id) {
+	case IPN3KE_TM_NODE_LEVEL_PORT:
+		cap->n_nodes_max = hw->port_num;
+		cap->n_nodes_nonleaf_max = IPN3KE_TM_VT_NODE_NUM;
+		cap->n_nodes_leaf_max = 0;
+		cap->non_leaf_nodes_identical = 0;
+		cap->leaf_nodes_identical = 0;
+
+		cap->nonleaf.shaper_private_supported = 0;
+		cap->nonleaf.shaper_private_dual_rate_supported = 0;
+		cap->nonleaf.shaper_private_rate_min = 1;
+		cap->nonleaf.shaper_private_rate_max = UINT32_MAX;
+		cap->nonleaf.shaper_shared_n_max = 0;
+
+		cap->nonleaf.sched_n_children_max = IPN3KE_TM_VT_NODE_NUM;
+		cap->nonleaf.sched_sp_n_priorities_max = 1;
+		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.stats_mask = STATS_MASK_DEFAULT;
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_VT:
+		cap->n_nodes_max = IPN3KE_TM_VT_NODE_NUM;
+		cap->n_nodes_nonleaf_max = IPN3KE_TM_COS_NODE_NUM;
+		cap->n_nodes_leaf_max = 0;
+		cap->non_leaf_nodes_identical = 0;
+		cap->leaf_nodes_identical = 0;
+
+		cap->nonleaf.shaper_private_supported = 0;
+		cap->nonleaf.shaper_private_dual_rate_supported = 0;
+		cap->nonleaf.shaper_private_rate_min = 1;
+		cap->nonleaf.shaper_private_rate_max = UINT32_MAX;
+		cap->nonleaf.shaper_shared_n_max = 0;
+
+		cap->nonleaf.sched_n_children_max = IPN3KE_TM_COS_NODE_NUM;
+		cap->nonleaf.sched_sp_n_priorities_max = 1;
+		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.stats_mask = STATS_MASK_DEFAULT;
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_COS:
+		cap->n_nodes_max = IPN3KE_TM_COS_NODE_NUM;
+		cap->n_nodes_nonleaf_max = 0;
+		cap->n_nodes_leaf_max = IPN3KE_TM_COS_NODE_NUM;
+		cap->non_leaf_nodes_identical = 0;
+		cap->leaf_nodes_identical = 0;
+
+		cap->leaf.shaper_private_supported = 0;
+		cap->leaf.shaper_private_dual_rate_supported = 0;
+		cap->leaf.shaper_private_rate_min = 0;
+		cap->leaf.shaper_private_rate_max = 0;
+		cap->leaf.shaper_shared_n_max = 0;
+
+		cap->leaf.cman_head_drop_supported = 0;
+		cap->leaf.cman_wred_packet_mode_supported = WRED_SUPPORTED;
+		cap->leaf.cman_wred_byte_mode_supported = 0;
+		cap->leaf.cman_wred_context_private_supported = WRED_SUPPORTED;
+		cap->leaf.cman_wred_context_shared_n_max = 0;
+
+		cap->leaf.stats_mask = STATS_MASK_QUEUE;
+		break;
+
+	default:
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_LEVEL_ID,
+					NULL,
+					rte_strerror(EINVAL));
+		break;
+	}
+
+	return 0;
+}
+
+/* Traffic manager node capabilities get */
+static int
+ipn3ke_tm_node_capabilities_get(struct rte_eth_dev *dev,
+	uint32_t node_id,
+	struct rte_tm_node_capabilities *cap,
+	struct rte_tm_error *error)
+{
+	struct ipn3ke_rpst *representor = IPN3KE_DEV_PRIVATE_TO_RPST(dev);
+	struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	uint32_t tm_id;
+	struct ipn3ke_tm_node *tm_node;
+	uint32_t state_mask;
+
+	if (cap == NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_CAPABILITIES,
+					NULL,
+					rte_strerror(EINVAL));
+
+	tm_id = tm->tm_id;
+
+	state_mask = 0;
+	IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED);
+	tm_node = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask);
+	if (tm_node == NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	if (tm_node->tm_id != representor->port_id)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* set all the parameters to 0 first. */
+	memset(cap, 0, sizeof(*cap));
+
+	switch (tm_node->level) {
+	case IPN3KE_TM_NODE_LEVEL_PORT:
+		cap->shaper_private_supported = 1;
+		cap->shaper_private_dual_rate_supported = 0;
+		cap->shaper_private_rate_min = 1;
+		cap->shaper_private_rate_max = UINT32_MAX;
+		cap->shaper_shared_n_max = 0;
+
+		cap->nonleaf.sched_n_children_max = IPN3KE_TM_VT_NODE_NUM;
+		cap->nonleaf.sched_sp_n_priorities_max = 1;
+		cap->nonleaf.sched_wfq_n_children_per_group_max =
+			IPN3KE_TM_VT_NODE_NUM;
+		cap->nonleaf.sched_wfq_n_groups_max = 1;
+		cap->nonleaf.sched_wfq_weight_max = 1;
+
+		cap->stats_mask = STATS_MASK_DEFAULT;
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_VT:
+		cap->shaper_private_supported = 1;
+		cap->shaper_private_dual_rate_supported = 0;
+		cap->shaper_private_rate_min = 1;
+		cap->shaper_private_rate_max = UINT32_MAX;
+		cap->shaper_shared_n_max = 0;
+
+		cap->nonleaf.sched_n_children_max = IPN3KE_TM_COS_NODE_NUM;
+		cap->nonleaf.sched_sp_n_priorities_max = 1;
+		cap->nonleaf.sched_wfq_n_children_per_group_max =
+			IPN3KE_TM_COS_NODE_NUM;
+		cap->nonleaf.sched_wfq_n_groups_max = 1;
+		cap->nonleaf.sched_wfq_weight_max = 1;
+
+		cap->stats_mask = STATS_MASK_DEFAULT;
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_COS:
+		cap->shaper_private_supported = 0;
+		cap->shaper_private_dual_rate_supported = 0;
+		cap->shaper_private_rate_min = 0;
+		cap->shaper_private_rate_max = 0;
+		cap->shaper_shared_n_max = 0;
+
+		cap->leaf.cman_head_drop_supported = 0;
+		cap->leaf.cman_wred_packet_mode_supported = WRED_SUPPORTED;
+		cap->leaf.cman_wred_byte_mode_supported = 0;
+		cap->leaf.cman_wred_context_private_supported = WRED_SUPPORTED;
+		cap->leaf.cman_wred_context_shared_n_max = 0;
+
+		cap->stats_mask = STATS_MASK_QUEUE;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int
+ipn3ke_tm_shaper_parame_trans(struct rte_tm_shaper_params *profile,
+	struct ipn3ke_tm_shaper_profile *local_profile,
+	const struct ipn3ke_tm_shaper_params_range_type *ref_data)
+{
+	uint32_t i;
+	const struct ipn3ke_tm_shaper_params_range_type *r;
+	uint64_t rate;
+
+	rate = profile->peak.rate;
+	for (i = 0, r = ref_data; i < IPN3KE_TM_SHAPER_RANGE_NUM; i++, r++) {
+		if (rate >= r->low &&
+		rate <= r->high) {
+			local_profile->m = (rate / 4) / r->exp2;
+			local_profile->e = r->exp;
+			local_profile->rate = rate;
+
+			return 0;
+		}
+	}
+
+	return -1;
+}
+static int
+ipn3ke_tm_shaper_profile_add(struct rte_eth_dev *dev,
+	uint32_t shaper_profile_id,
+	struct rte_tm_shaper_params *profile,
+	struct rte_tm_error *error)
+{
+	struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	struct ipn3ke_tm_shaper_profile *sp;
+
+	/* Shaper profile must not exist. */
+	sp = ipn3ke_hw_tm_shaper_profile_search(hw, shaper_profile_id, error);
+	if (!sp || (sp && sp->valid))
+		return -rte_tm_error_set(error,
+					EEXIST,
+					RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					NULL,
+					rte_strerror(EEXIST));
+
+	/* Profile must not be NULL. */
+	if (profile == NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_SHAPER_PROFILE,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* Peak rate: non-zero, 32-bit */
+	if (profile->peak.rate == 0 ||
+		profile->peak.rate >= IPN3KE_TM_SHAPER_PEAK_RATE_MAX)
+		return -rte_tm_error_set(error,
+				EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE,
+				NULL,
+				rte_strerror(EINVAL));
+
+	/* Peak size: non-zero, 32-bit */
+	if (profile->peak.size != 0)
+		return -rte_tm_error_set(error,
+				EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE,
+				NULL,
+				rte_strerror(EINVAL));
+
+	/* Dual-rate profiles are not supported. */
+	if (profile->committed.rate >= IPN3KE_TM_SHAPER_COMMITTED_RATE_MAX)
+		return -rte_tm_error_set(error,
+				EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE,
+				NULL,
+				rte_strerror(EINVAL));
+
+	/* Packet length adjust: 24 bytes */
+	if (profile->pkt_length_adjust != 0)
+		return -rte_tm_error_set(error,
+				EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN,
+				NULL,
+				rte_strerror(EINVAL));
+
+	if (ipn3ke_tm_shaper_parame_trans(profile,
+					sp,
+					ipn3ke_tm_shaper_params_rang)) {
+		return -rte_tm_error_set(error,
+				EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE,
+				NULL,
+				rte_strerror(EINVAL));
+	} else {
+		sp->valid = 1;
+		rte_memcpy(&sp->params, profile, sizeof(sp->params));
+	}
+
+	tm->h.n_shaper_profiles++;
+
+	return 0;
+}
+
+/* Traffic manager shaper profile delete */
+static int
+ipn3ke_tm_shaper_profile_delete(struct rte_eth_dev *dev,
+	uint32_t shaper_profile_id,
+	struct rte_tm_error *error)
+{
+	struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	struct ipn3ke_tm_shaper_profile *sp;
+
+	/* Check existing */
+	sp = ipn3ke_hw_tm_shaper_profile_search(hw, shaper_profile_id, error);
+	if (!sp || (sp && !sp->valid))
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	sp->valid = 0;
+	tm->h.n_shaper_profiles--;
+
+	return 0;
+}
+
+static int
+ipn3ke_tm_tdrop_profile_check(__rte_unused struct rte_eth_dev *dev,
+	uint32_t tdrop_profile_id,
+	struct rte_tm_wred_params *profile,
+	struct rte_tm_error *error)
+{
+	enum rte_tm_color color;
+
+	/* TDROP profile ID must not be NONE. */
+	if (tdrop_profile_id == RTE_TM_WRED_PROFILE_ID_NONE)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_WRED_PROFILE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* Profile must not be NULL. */
+	if (profile == NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_WRED_PROFILE,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* TDROP profile should be in packet mode */
+	if (profile->packet_mode != 0)
+		return -rte_tm_error_set(error,
+					ENOTSUP,
+					RTE_TM_ERROR_TYPE_WRED_PROFILE,
+					NULL,
+					rte_strerror(ENOTSUP));
+
+	/* min_th <= max_th, max_th > 0  */
+	for (color = RTE_TM_GREEN; color <= RTE_TM_GREEN; color++) {
+		uint64_t min_th = profile->red_params[color].min_th;
+		uint64_t max_th = profile->red_params[color].max_th;
+
+		if (((min_th >> IPN3KE_TDROP_TH1_SHIFT) >>
+				IPN3KE_TDROP_TH1_SHIFT) ||
+			max_th != 0)
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_WRED_PROFILE,
+						NULL,
+						rte_strerror(EINVAL));
+	}
+
+	return 0;
+}
+
+static int
+ipn3ke_hw_tm_tdrop_wr(struct ipn3ke_hw *hw,
+				struct ipn3ke_tm_tdrop_profile *tp)
+{
+	if (tp->valid) {
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_CCB_PROFILE_MS,
+				0,
+				tp->th2,
+				IPN3KE_CCB_PROFILE_MS_MASK);
+
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_CCB_PROFILE_P,
+				tp->tdrop_profile_id,
+				tp->th1,
+				IPN3KE_CCB_PROFILE_MASK);
+	} else {
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_CCB_PROFILE_MS,
+				0,
+				0,
+				IPN3KE_CCB_PROFILE_MS_MASK);
+
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_CCB_PROFILE_P,
+				tp->tdrop_profile_id,
+				0,
+				IPN3KE_CCB_PROFILE_MASK);
+	}
+
+	return 0;
+}
+
+/* Traffic manager TDROP profile add */
+static int
+ipn3ke_tm_tdrop_profile_add(struct rte_eth_dev *dev,
+	uint32_t tdrop_profile_id,
+	struct rte_tm_wred_params *profile,
+	struct rte_tm_error *error)
+{
+	struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	struct ipn3ke_tm_tdrop_profile *tp;
+	int status;
+	uint64_t min_th;
+	uint32_t th1, th2;
+
+	/* Check input params */
+	status = ipn3ke_tm_tdrop_profile_check(dev,
+					tdrop_profile_id,
+					profile,
+					error);
+	if (status)
+		return status;
+
+	/* Memory allocation */
+	tp = &hw->tdrop_profile[tdrop_profile_id];
+
+	/* Fill in */
+	tp->valid = 1;
+	min_th = profile->red_params[RTE_TM_GREEN].min_th;
+	th1 = (uint32_t)(min_th & IPN3KE_TDROP_TH1_MASK);
+	th2 = (uint32_t)((min_th >> IPN3KE_TDROP_TH1_SHIFT) &
+			IPN3KE_TDROP_TH2_MASK);
+	tp->th1 = th1;
+	tp->th2 = th2;
+	rte_memcpy(&tp->params, profile, sizeof(tp->params));
+
+	/* Add to list */
+	tm->h.n_tdrop_profiles++;
+
+	/* Write FPGA */
+	ipn3ke_hw_tm_tdrop_wr(hw, tp);
+
+	return 0;
+}
+
+/* Traffic manager TDROP profile delete */
+static int
+ipn3ke_tm_tdrop_profile_delete(struct rte_eth_dev *dev,
+	uint32_t tdrop_profile_id,
+	struct rte_tm_error *error)
+{
+	struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	struct ipn3ke_tm_tdrop_profile *tp;
+
+	/* Check existing */
+	tp = ipn3ke_hw_tm_tdrop_profile_search(hw, tdrop_profile_id);
+	if (tp == NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_WRED_PROFILE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* Check unused */
+	if (tp->n_users)
+		return -rte_tm_error_set(error,
+					EBUSY,
+					RTE_TM_ERROR_TYPE_WRED_PROFILE_ID,
+					NULL,
+					rte_strerror(EBUSY));
+
+	/* Set free */
+	tp->valid = 0;
+	tm->h.n_tdrop_profiles--;
+
+	/* Write FPGA */
+	ipn3ke_hw_tm_tdrop_wr(hw, tp);
+
+	return 0;
+}
+
+static int
+ipn3ke_tm_node_add_check_parameter(uint32_t tm_id,
+	uint32_t node_id,
+	uint32_t parent_node_id,
+	uint32_t priority,
+	uint32_t weight,
+	uint32_t level_id,
+	struct rte_tm_node_params *params,
+	struct rte_tm_error *error)
+{
+	uint32_t level_of_node_id;
+	uint32_t node_index;
+	uint32_t parent_level_id;
+
+	if (node_id == RTE_TM_NODE_ID_NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* priority: must be 0, 1, 2, 3 */
+	if (priority > IPN3KE_TM_NODE_PRIORITY_HIGHEST)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PRIORITY,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* weight: must be 1 .. 255 */
+	if (weight > IPN3KE_TM_NODE_WEIGHT_MAX)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_WEIGHT,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* check node id and parent id*/
+	level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD;
+	if (level_of_node_id != level_id)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+	node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD;
+	parent_level_id = parent_node_id / IPN3KE_TM_NODE_LEVEL_MOD;
+	switch (level_id) {
+	case IPN3KE_TM_NODE_LEVEL_PORT:
+		if (node_index != tm_id)
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_NODE_ID,
+						NULL,
+						rte_strerror(EINVAL));
+		if (parent_node_id != RTE_TM_NODE_ID_NULL)
+			return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_VT:
+		if (node_index >= IPN3KE_TM_VT_NODE_NUM)
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_NODE_ID,
+						NULL,
+						rte_strerror(EINVAL));
+		if (parent_level_id != IPN3KE_TM_NODE_LEVEL_PORT)
+			return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_COS:
+		if (node_index >= IPN3KE_TM_COS_NODE_NUM)
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_NODE_ID,
+						NULL,
+						rte_strerror(EINVAL));
+		if (parent_level_id != IPN3KE_TM_NODE_LEVEL_VT)
+			return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+		break;
+	default:
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_LEVEL_ID,
+					NULL,
+					rte_strerror(EINVAL));
+	}
+
+	/* params: must not be NULL */
+	if (params == NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PARAMS,
+					NULL,
+					rte_strerror(EINVAL));
+	/* No shared shapers */
+	if (params->n_shared_shapers != 0)
+		return -rte_tm_error_set(error,
+				EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS,
+				NULL,
+				rte_strerror(EINVAL));
+	return 0;
+}
+static int
+ipn3ke_tm_node_add_check_mount(uint32_t tm_id,
+	uint32_t node_id,
+	uint32_t parent_node_id,
+	uint32_t level_id,
+	struct rte_tm_error *error)
+{
+	/*struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);*/
+	uint32_t node_index;
+	uint32_t parent_index;
+	uint32_t parent_index1;
+
+	node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD;
+	parent_index = parent_node_id % IPN3KE_TM_NODE_LEVEL_MOD;
+	parent_index1 = node_index / IPN3KE_TM_NODE_MOUNT_MAX;
+	switch (level_id) {
+	case IPN3KE_TM_NODE_LEVEL_PORT:
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_VT:
+		if (parent_index != tm_id)
+			return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_COS:
+		if (parent_index != parent_index1)
+			return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+		break;
+	default:
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_LEVEL_ID,
+					NULL,
+					rte_strerror(EINVAL));
+	}
+
+	return 0;
+}
+
+/* Traffic manager node add */
+static int
+ipn3ke_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,
+	struct rte_tm_node_params *params,
+	struct rte_tm_error *error)
+{
+	struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	uint32_t tm_id;
+	struct ipn3ke_tm_node *n, *parent_node;
+	uint32_t node_state, state_mask;
+	int status;
+
+	/* Checks */
+	if (tm->hierarchy_frozen)
+		return -rte_tm_error_set(error,
+					EBUSY,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					NULL,
+					rte_strerror(EBUSY));
+
+	tm_id = tm->tm_id;
+
+	status = ipn3ke_tm_node_add_check_parameter(tm_id,
+						node_id,
+						parent_node_id,
+						priority,
+						weight,
+						level_id,
+						params,
+						error);
+	if (status)
+		return status;
+
+	status = ipn3ke_tm_node_add_check_mount(tm_id,
+						node_id,
+						parent_node_id,
+						level_id,
+						error);
+	if (status)
+		return status;
+
+	/* Shaper profile ID must not be NONE. */
+	if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE &&
+		params->shaper_profile_id != node_id)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* Memory allocation */
+	state_mask = 0;
+	IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_IDLE);
+	IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_DEL);
+	n = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask);
+	if (!n)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					NULL,
+					rte_strerror(EINVAL));
+	node_state = n->node_state;
+
+	/* Check parent node */
+	state_mask = 0;
+	IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_ADD);
+	IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED);
+	if (parent_node_id != RTE_TM_NODE_ID_NULL) {
+		parent_node = ipn3ke_hw_tm_node_search(hw,
+							tm_id,
+							parent_node_id,
+							state_mask);
+		if (!parent_node)
+			return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+	} else {
+		parent_node = NULL;
+	}
+
+	switch (level_id) {
+	case IPN3KE_TM_NODE_LEVEL_PORT:
+		n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_ADD;
+		n->tm_id = tm_id;
+		tm->h.port_commit_node = n;
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_VT:
+		if (node_state == IPN3KE_TM_NODE_STATE_IDLE) {
+			TAILQ_INSERT_TAIL(&tm->h.vt_commit_node_list, n, node);
+			if (parent_node)
+				parent_node->n_children++;
+			tm->h.n_vt_nodes++;
+		} else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
+			if (parent_node)
+				parent_node->n_children++;
+			tm->h.n_vt_nodes++;
+		}
+		n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_ADD;
+		n->parent_node_id = parent_node_id;
+		n->tm_id = tm_id;
+		n->parent_node = parent_node;
+
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_COS:
+		if (node_state == IPN3KE_TM_NODE_STATE_IDLE) {
+			TAILQ_INSERT_TAIL(&tm->h.cos_commit_node_list,
+				n, node);
+			if (parent_node)
+				parent_node->n_children++;
+			tm->h.n_cos_nodes++;
+		} else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
+			if (parent_node)
+				parent_node->n_children++;
+			tm->h.n_cos_nodes++;
+		}
+		n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_ADD;
+		n->parent_node_id = parent_node_id;
+		n->tm_id = tm_id;
+		n->parent_node = parent_node;
+
+		break;
+	default:
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_LEVEL_ID,
+					NULL,
+					rte_strerror(EINVAL));
+	}
+
+	/* Fill in */
+	n->priority = priority;
+	n->weight = weight;
+
+	if (n->level == IPN3KE_TM_NODE_LEVEL_COS &&
+		params->leaf.cman == RTE_TM_CMAN_TAIL_DROP)
+		n->tdrop_profile = ipn3ke_hw_tm_tdrop_profile_search(hw,
+			params->leaf.wred.wred_profile_id);
+
+	rte_memcpy(&n->params, params, sizeof(n->params));
+
+	return 0;
+}
+
+static int
+ipn3ke_tm_node_del_check_parameter(uint32_t tm_id,
+	uint32_t node_id,
+	struct rte_tm_error *error)
+{
+	uint32_t level_of_node_id;
+	uint32_t node_index;
+
+	if (node_id == RTE_TM_NODE_ID_NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	/* check node id and parent id*/
+	level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD;
+	node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD;
+	switch (level_of_node_id) {
+	case IPN3KE_TM_NODE_LEVEL_PORT:
+		if (node_index != tm_id)
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_NODE_ID,
+						NULL,
+						rte_strerror(EINVAL));
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_VT:
+		if (node_index >= IPN3KE_TM_VT_NODE_NUM)
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_NODE_ID,
+						NULL,
+						rte_strerror(EINVAL));
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_COS:
+		if (node_index >= IPN3KE_TM_COS_NODE_NUM)
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_NODE_ID,
+						NULL,
+						rte_strerror(EINVAL));
+		break;
+	default:
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_LEVEL_ID,
+					NULL,
+					rte_strerror(EINVAL));
+	}
+
+	return 0;
+}
+
+/* Traffic manager node delete */
+static int
+ipn3ke_pmd_tm_node_delete(struct rte_eth_dev *dev,
+	uint32_t node_id,
+	struct rte_tm_error *error)
+{
+	struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	struct ipn3ke_tm_node *n, *parent_node;
+	uint32_t tm_id;
+	int status;
+	uint32_t level_of_node_id;
+	uint32_t node_state;
+	uint32_t state_mask;
+
+	/* Check hierarchy changes are currently allowed */
+	if (tm->hierarchy_frozen)
+		return -rte_tm_error_set(error,
+					EBUSY,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					NULL,
+					rte_strerror(EBUSY));
+
+	tm_id = tm->tm_id;
+
+	status = ipn3ke_tm_node_del_check_parameter(tm_id,
+						node_id,
+						error);
+	if (status)
+		return status;
+
+	/* Check existing */
+	state_mask = 0;
+	IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_ADD);
+	IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED);
+	n = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask);
+	if (n == NULL)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	if (n->n_children > 0)
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+
+	node_state = n->node_state;
+
+	level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD;
+
+	/* Check parent node */
+	if (n->parent_node_id != RTE_TM_NODE_ID_NULL) {
+		state_mask = 0;
+		IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_ADD);
+		IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED);
+		parent_node = ipn3ke_hw_tm_node_search(hw,
+						tm_id,
+						n->parent_node_id,
+						state_mask);
+		if (!parent_node)
+			return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
+					NULL,
+					rte_strerror(EINVAL));
+		if (n->parent_node != parent_node)
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_NODE_ID,
+						NULL,
+						rte_strerror(EINVAL));
+	} else {
+		parent_node = NULL;
+	}
+
+	switch (level_of_node_id) {
+	case IPN3KE_TM_NODE_LEVEL_PORT:
+		if (tm->h.port_node != n)
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_NODE_ID,
+						NULL,
+						rte_strerror(EINVAL));
+		n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_DEL;
+		tm->h.port_commit_node = n;
+
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_VT:
+		if (node_state == IPN3KE_TM_NODE_STATE_COMMITTED) {
+			if (parent_node)
+				TAILQ_REMOVE(&parent_node->children_node_list,
+					n, node);
+			TAILQ_INSERT_TAIL(&tm->h.vt_commit_node_list, n, node);
+			if (parent_node)
+				parent_node->n_children--;
+			tm->h.n_vt_nodes--;
+		} else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
+			if (parent_node)
+				parent_node->n_children--;
+			tm->h.n_vt_nodes--;
+		}
+		n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_DEL;
+
+		break;
+
+	case IPN3KE_TM_NODE_LEVEL_COS:
+		if (node_state == IPN3KE_TM_NODE_STATE_COMMITTED) {
+			if (parent_node)
+				TAILQ_REMOVE(&parent_node->children_node_list,
+					n, node);
+			TAILQ_INSERT_TAIL(&tm->h.cos_commit_node_list,
+				n, node);
+			if (parent_node)
+				parent_node->n_children--;
+			tm->h.n_cos_nodes--;
+		} else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
+			if (parent_node)
+				parent_node->n_children--;
+			tm->h.n_cos_nodes--;
+		}
+		n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_DEL;
+
+		break;
+	default:
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_LEVEL_ID,
+					NULL,
+					rte_strerror(EINVAL));
+	}
+
+	return 0;
+}
+static int
+ipn3ke_tm_hierarchy_commit_check(struct rte_eth_dev *dev,
+						struct rte_tm_error *error)
+{
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	uint32_t tm_id;
+	struct ipn3ke_tm_node_list *nl;
+	struct ipn3ke_tm_node *n, *parent_node;
+
+	tm_id = tm->tm_id;
+
+	nl = &tm->h.cos_commit_node_list;
+	TAILQ_FOREACH(n, nl, node) {
+		parent_node = n->parent_node;
+		if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
+			if (n->parent_node_id == RTE_TM_NODE_ID_NULL ||
+				n->level != IPN3KE_TM_NODE_LEVEL_COS ||
+				n->tm_id != tm_id ||
+				parent_node == NULL ||
+				(parent_node &&
+					parent_node->node_state ==
+					IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) ||
+				(parent_node &&
+					parent_node->node_state ==
+						IPN3KE_TM_NODE_STATE_IDLE) ||
+				n->shaper_profile.valid == 0) {
+				return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						NULL,
+						rte_strerror(EINVAL));
+			}
+		} else if (n->node_state ==
+				IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
+			if (n->level != IPN3KE_TM_NODE_LEVEL_COS ||
+				n->n_children != 0) {
+				return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						NULL,
+						rte_strerror(EINVAL));
+			} else {
+				return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						NULL,
+						rte_strerror(EINVAL));
+			}
+		}
+	}
+
+	nl = &tm->h.vt_commit_node_list;
+	TAILQ_FOREACH(n, nl, node) {
+		parent_node = n->parent_node;
+		if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
+			if (n->parent_node_id == RTE_TM_NODE_ID_NULL ||
+				n->level != IPN3KE_TM_NODE_LEVEL_VT ||
+				n->tm_id != tm_id ||
+				parent_node == NULL ||
+				(parent_node &&
+					parent_node->node_state ==
+					IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) ||
+				(parent_node &&
+					parent_node->node_state ==
+						IPN3KE_TM_NODE_STATE_IDLE) ||
+				n->shaper_profile.valid == 0) {
+				return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						NULL,
+						rte_strerror(EINVAL));
+			}
+		} else if (n->node_state ==
+			IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
+			if (n->level != IPN3KE_TM_NODE_LEVEL_VT ||
+				n->n_children != 0) {
+				return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						NULL,
+						rte_strerror(EINVAL));
+			} else {
+				return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						NULL,
+						rte_strerror(EINVAL));
+			}
+		}
+	}
+
+	n = tm->h.port_commit_node;
+	if (n &&
+		(n->parent_node_id != RTE_TM_NODE_ID_NULL ||
+		n->level != IPN3KE_TM_NODE_LEVEL_PORT ||
+		n->tm_id != tm_id ||
+		n->parent_node != NULL ||
+		n->shaper_profile.valid == 0)) {
+		return -rte_tm_error_set(error,
+					EINVAL,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					NULL,
+					rte_strerror(EINVAL));
+	}
+
+	return 0;
+}
+static int
+ipn3ke_hw_tm_node_wr(struct ipn3ke_hw *hw,
+				struct ipn3ke_tm_node *n)
+{
+	uint32_t level;
+
+	level = n->level;
+
+	switch (level) {
+	case IPN3KE_TM_NODE_LEVEL_PORT:
+		/**
+		 * Configure Type
+		 */
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_QOS_TYPE_L3_X,
+				n->node_index,
+				n->priority,
+				IPN3KE_QOS_TYPE_MASK);
+
+		/**
+		 * Configure Sch_wt
+		 */
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_QOS_SCH_WT_L3_X,
+				n->node_index,
+				n->weight,
+				IPN3KE_QOS_SCH_WT_MASK);
+
+		/**
+		 * Configure Shap_wt
+		 */
+		if (n->shaper_profile.valid)
+			IPN3KE_MASK_WRITE_REG(hw,
+					IPN3KE_QOS_SHAP_WT_L3_X,
+					n->node_index,
+					((n->shaper_profile.e << 10) |
+						n->shaper_profile.m),
+					IPN3KE_QOS_SHAP_WT_MASK);
+
+		break;
+	case IPN3KE_TM_NODE_LEVEL_VT:
+		/**
+		 * Configure Type
+		 */
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_QOS_TYPE_L2_X,
+				n->node_index,
+				n->priority,
+				IPN3KE_QOS_TYPE_MASK);
+
+		/**
+		 * Configure Sch_wt
+		 */
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_QOS_SCH_WT_L2_X,
+				n->node_index,
+				n->weight,
+				IPN3KE_QOS_SCH_WT_MASK);
+
+		/**
+		 * Configure Shap_wt
+		 */
+		if (n->shaper_profile.valid)
+			IPN3KE_MASK_WRITE_REG(hw,
+					IPN3KE_QOS_SHAP_WT_L2_X,
+					n->node_index,
+					((n->shaper_profile.e << 10) |
+						n->shaper_profile.m),
+					IPN3KE_QOS_SHAP_WT_MASK);
+
+		/**
+		 * Configure Map
+		 */
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_QOS_MAP_L2_X,
+				n->node_index,
+				n->parent_node->node_index,
+				IPN3KE_QOS_MAP_L2_MASK);
+
+		break;
+	case IPN3KE_TM_NODE_LEVEL_COS:
+		/**
+		 * Configure Tail Drop mapping
+		 */
+		if (n->tdrop_profile && n->tdrop_profile->valid) {
+			IPN3KE_MASK_WRITE_REG(hw,
+					IPN3KE_CCB_QPROFILE_Q,
+					n->node_index,
+					n->tdrop_profile->tdrop_profile_id,
+					IPN3KE_CCB_QPROFILE_MASK);
+		}
+
+		/**
+		 * Configure Type
+		 */
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_QOS_TYPE_L1_X,
+				n->node_index,
+				n->priority,
+				IPN3KE_QOS_TYPE_MASK);
+
+		/**
+		 * Configure Sch_wt
+		 */
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_QOS_SCH_WT_L1_X,
+				n->node_index,
+				n->weight,
+				IPN3KE_QOS_SCH_WT_MASK);
+
+		/**
+		 * Configure Shap_wt
+		 */
+		if (n->shaper_profile.valid)
+			IPN3KE_MASK_WRITE_REG(hw,
+					IPN3KE_QOS_SHAP_WT_L1_X,
+					n->node_index,
+					((n->shaper_profile.e << 10) |
+						n->shaper_profile.m),
+					IPN3KE_QOS_SHAP_WT_MASK);
+
+		/**
+		 * Configure COS queue to port
+		 */
+		while (IPN3KE_MASK_READ_REG(hw,
+					IPN3KE_QM_UID_CONFIG_CTRL,
+					0,
+					0x80000000))
+			;
+
+		IPN3KE_MASK_WRITE_REG(hw,
+			IPN3KE_QM_UID_CONFIG_DATA,
+			0,
+			(1 << 8 | n->parent_node->parent_node->node_index),
+			0x1FF);
+
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_QM_UID_CONFIG_CTRL,
+				0,
+				n->node_index,
+				0xFFFFF);
+
+		while (IPN3KE_MASK_READ_REG(hw,
+					IPN3KE_QM_UID_CONFIG_CTRL,
+					0,
+					0x80000000))
+			;
+
+		/**
+		 * Configure Map
+		 */
+		IPN3KE_MASK_WRITE_REG(hw,
+				IPN3KE_QOS_MAP_L1_X,
+				n->node_index,
+				n->parent_node->node_index,
+				IPN3KE_QOS_MAP_L1_MASK);
+
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+ipn3ke_tm_hierarchy_hw_commit(struct rte_eth_dev *dev,
+					struct rte_tm_error *error)
+{
+	struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	struct ipn3ke_tm_node_list *nl;
+	struct ipn3ke_tm_node *n, *nn, *parent_node;
+
+	n = tm->h.port_commit_node;
+	if (n) {
+		if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
+			tm->h.port_commit_node = NULL;
+
+			n->node_state = IPN3KE_TM_NODE_STATE_COMMITTED;
+		} else if (n->node_state ==
+					IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
+			tm->h.port_commit_node = NULL;
+
+			n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
+			n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
+			n->weight = 0;
+			n->tm_id = RTE_TM_NODE_ID_NULL;
+		} else {
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						NULL,
+						rte_strerror(EINVAL));
+		}
+		ipn3ke_hw_tm_node_wr(hw, n);
+	}
+
+	nl = &tm->h.vt_commit_node_list;
+	for (n = TAILQ_FIRST(nl); n != NULL; n = nn) {
+		nn = TAILQ_NEXT(n, node);
+		if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
+			n->node_state = IPN3KE_TM_NODE_STATE_COMMITTED;
+			parent_node = n->parent_node;
+			TAILQ_REMOVE(nl, n, node);
+			TAILQ_INSERT_TAIL(&parent_node->children_node_list,
+						n, node);
+		} else if (n->node_state ==
+					IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
+			parent_node = n->parent_node;
+			TAILQ_REMOVE(nl, n, node);
+
+			n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
+			n->parent_node_id = RTE_TM_NODE_ID_NULL;
+			n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
+			n->weight = 0;
+			n->tm_id = RTE_TM_NODE_ID_NULL;
+			n->parent_node = NULL;
+		} else {
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						NULL,
+						rte_strerror(EINVAL));
+		}
+		ipn3ke_hw_tm_node_wr(hw, n);
+	}
+
+	nl = &tm->h.cos_commit_node_list;
+	for (n = TAILQ_FIRST(nl); n != NULL; n = nn) {
+		nn = TAILQ_NEXT(n, node);
+		if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
+			n->node_state = IPN3KE_TM_NODE_STATE_COMMITTED;
+			parent_node = n->parent_node;
+			TAILQ_REMOVE(nl, n, node);
+			TAILQ_INSERT_TAIL(&parent_node->children_node_list,
+					n, node);
+		} else if (n->node_state ==
+					IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
+			n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
+			parent_node = n->parent_node;
+			TAILQ_REMOVE(nl, n, node);
+
+			n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
+			n->parent_node_id = RTE_TM_NODE_ID_NULL;
+			n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
+			n->weight = 0;
+			n->tm_id = RTE_TM_NODE_ID_NULL;
+			n->parent_node = NULL;
+
+			if (n->tdrop_profile)
+				n->tdrop_profile->n_users--;
+		} else {
+			return -rte_tm_error_set(error,
+						EINVAL,
+						RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						NULL,
+						rte_strerror(EINVAL));
+		}
+		ipn3ke_hw_tm_node_wr(hw, n);
+	}
+
+	return 0;
+}
+
+static int
+ipn3ke_tm_hierarchy_commit_clear(struct rte_eth_dev *dev)
+{
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	struct ipn3ke_tm_node_list *nl;
+	struct ipn3ke_tm_node *n;
+	struct ipn3ke_tm_node *nn;
+
+	n = tm->h.port_commit_node;
+	if (n) {
+		n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
+		n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
+		n->weight = 0;
+		n->tm_id = RTE_TM_NODE_ID_NULL;
+		n->n_children = 0;
+
+		tm->h.port_commit_node = NULL;
+	}
+
+	nl = &tm->h.vt_commit_node_list;
+	for (n = TAILQ_FIRST(nl); n != NULL; n = nn) {
+		nn = TAILQ_NEXT(n, node);
+
+		n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
+		n->parent_node_id = RTE_TM_NODE_ID_NULL;
+		n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
+		n->weight = 0;
+		n->tm_id = RTE_TM_NODE_ID_NULL;
+		n->parent_node = NULL;
+		n->n_children = 0;
+		tm->h.n_vt_nodes--;
+
+		TAILQ_REMOVE(nl, n, node);
+	}
+
+	nl = &tm->h.cos_commit_node_list;
+	for (n = TAILQ_FIRST(nl); n != NULL; n = nn) {
+		nn = TAILQ_NEXT(n, node);
+
+		n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
+		n->parent_node_id = RTE_TM_NODE_ID_NULL;
+		n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
+		n->weight = 0;
+		n->tm_id = RTE_TM_NODE_ID_NULL;
+		n->parent_node = NULL;
+		tm->h.n_cos_nodes--;
+
+		TAILQ_REMOVE(nl, n, node);
+	}
+
+	return 0;
+}
+
+static void
+ipn3ke_tm_show(struct rte_eth_dev *dev)
+{
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	uint32_t tm_id;
+	struct ipn3ke_tm_node_list *vt_nl, *cos_nl;
+	struct ipn3ke_tm_node *port_n, *vt_n, *cos_n;
+	const char *str_state[IPN3KE_TM_NODE_STATE_MAX] = {"Idle",
+						"CfgAdd",
+						"CfgDel",
+						"Committed"};
+
+	tm_id = tm->tm_id;
+
+	IPN3KE_AFU_PMD_DEBUG("***HQoS Tree(%d)***\n", tm_id);
+
+	port_n = tm->h.port_node;
+	IPN3KE_AFU_PMD_DEBUG("Port: (%d|%s)\n", port_n->node_index,
+				str_state[port_n->node_state]);
+
+	vt_nl = &tm->h.port_node->children_node_list;
+	TAILQ_FOREACH(vt_n, vt_nl, node) {
+		cos_nl = &vt_n->children_node_list;
+		IPN3KE_AFU_PMD_DEBUG("    VT%d: ", vt_n->node_index);
+		TAILQ_FOREACH(cos_n, cos_nl, node) {
+			if (cos_n->parent_node_id !=
+				(vt_n->node_index + IPN3KE_TM_NODE_LEVEL_MOD))
+				IPN3KE_AFU_PMD_ERR("(%d|%s), ",
+					cos_n->node_index,
+					str_state[cos_n->node_state]);
+		}
+		IPN3KE_AFU_PMD_DEBUG("\n");
+	}
+}
+static void
+ipn3ke_tm_show_commmit(struct rte_eth_dev *dev)
+{
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	uint32_t tm_id;
+	struct ipn3ke_tm_node_list *nl;
+	struct ipn3ke_tm_node *n;
+	const char *str_state[IPN3KE_TM_NODE_STATE_MAX] = {"Idle",
+						"CfgAdd",
+						"CfgDel",
+						"Committed"};
+
+	tm_id = tm->tm_id;
+
+	IPN3KE_AFU_PMD_DEBUG("***Commit Tree(%d)***\n", tm_id);
+	n = tm->h.port_commit_node;
+	IPN3KE_AFU_PMD_DEBUG("Port: ");
+	if (n)
+		IPN3KE_AFU_PMD_DEBUG("(%d|%s)",
+			n->node_index,
+			str_state[n->node_state]);
+	IPN3KE_AFU_PMD_DEBUG("\n");
+
+	nl = &tm->h.vt_commit_node_list;
+	IPN3KE_AFU_PMD_DEBUG("VT  : ");
+	TAILQ_FOREACH(n, nl, node) {
+		IPN3KE_AFU_PMD_DEBUG("(%d|%s), ",
+				n->node_index,
+				str_state[n->node_state]);
+	}
+	IPN3KE_AFU_PMD_DEBUG("\n");
+
+	nl = &tm->h.cos_commit_node_list;
+	IPN3KE_AFU_PMD_DEBUG("COS : ");
+	TAILQ_FOREACH(n, nl, node) {
+		IPN3KE_AFU_PMD_DEBUG("(%d|%s), ",
+				n->node_index,
+				str_state[n->node_state]);
+	}
+	IPN3KE_AFU_PMD_DEBUG("\n");
+}
+
+/* Traffic manager hierarchy commit */
+static int
+ipn3ke_tm_hierarchy_commit(struct rte_eth_dev *dev,
+	int clear_on_fail,
+	struct rte_tm_error *error)
+{
+	struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
+	int status;
+
+	/* Checks */
+	if (tm->hierarchy_frozen)
+		return -rte_tm_error_set(error,
+					EBUSY,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					NULL,
+					rte_strerror(EBUSY));
+
+	ipn3ke_tm_show_commmit(dev);
+
+	status = ipn3ke_tm_hierarchy_commit_check(dev, error);
+	if (status) {
+		if (clear_on_fail)
+			ipn3ke_tm_hierarchy_commit_clear(dev);
+		return status;
+	}
+
+	ipn3ke_tm_hierarchy_hw_commit(dev, error);
+	ipn3ke_tm_show(dev);
+
+	return 0;
+}
+
+const struct rte_tm_ops ipn3ke_tm_ops = {
+	.node_type_get = ipn3ke_pmd_tm_node_type_get,
+	.capabilities_get = ipn3ke_tm_capabilities_get,
+	.level_capabilities_get = ipn3ke_tm_level_capabilities_get,
+	.node_capabilities_get = ipn3ke_tm_node_capabilities_get,
+
+	.wred_profile_add = ipn3ke_tm_tdrop_profile_add,
+	.wred_profile_delete = ipn3ke_tm_tdrop_profile_delete,
+	.shared_wred_context_add_update = NULL,
+	.shared_wred_context_delete = NULL,
+
+	.shaper_profile_add = ipn3ke_tm_shaper_profile_add,
+	.shaper_profile_delete = ipn3ke_tm_shaper_profile_delete,
+	.shared_shaper_add_update = NULL,
+	.shared_shaper_delete = NULL,
+
+	.node_add = ipn3ke_tm_node_add,
+	.node_delete = ipn3ke_pmd_tm_node_delete,
+	.node_suspend = NULL,
+	.node_resume = NULL,
+	.hierarchy_commit = ipn3ke_tm_hierarchy_commit,
+
+	.node_parent_update = NULL,
+	.node_shaper_update = NULL,
+	.node_shared_shaper_update = NULL,
+	.node_stats_update = NULL,
+	.node_wfq_weight_mode_update = NULL,
+	.node_cman_update = NULL,
+	.node_wred_context_update = NULL,
+	.node_shared_wred_context_update = NULL,
+
+	.node_stats_read = NULL,
+};
+
+int
+ipn3ke_tm_ops_get(struct rte_eth_dev *ethdev,
+		void *arg)
+{
+	struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(ethdev);
+	struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev);
+	struct rte_eth_dev *i40e_pf_eth;
+	const struct rte_tm_ops *ops;
+
+	if (!arg)
+		return -EINVAL;
+
+	if (hw->acc_tm) {
+		*(const void **)arg = &ipn3ke_tm_ops;
+	} else if (rpst->i40e_pf_eth) {
+		i40e_pf_eth = rpst->i40e_pf_eth;
+		if (i40e_pf_eth->dev_ops->tm_ops_get == NULL ||
+			i40e_pf_eth->dev_ops->tm_ops_get(i40e_pf_eth,
+			&ops) != 0 ||
+			ops == NULL) {
+			return -EINVAL;
+		}
+		*(const void **)arg = ops;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
diff --git a/drivers/net/ipn3ke/meson.build b/drivers/net/ipn3ke/meson.build
index 7ba4ca9..093ddbc 100644
--- a/drivers/net/ipn3ke/meson.build
+++ b/drivers/net/ipn3ke/meson.build
@@ -3,5 +3,6 @@
 
 allow_experimental_apis = true
 sources += files('ipn3ke_ethdev.c',
-	'ipn3ke_representor.c')
+	'ipn3ke_representor.c',
+	'ipn3ke_tm.c')
 deps += ['bus_ifpga', 'sched']
-- 
1.8.3.1



More information about the dev mailing list