--- /dev/null
+/* 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_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_COLOR_GREEN; color <= RTE_COLOR_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_COLOR_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;
+}
+