From patchwork Tue Apr 9 12:41:20 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52475 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id D3A535920; Tue, 9 Apr 2019 14:40:49 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by dpdk.org (Postfix) with ESMTP id 04CED58EC for ; Tue, 9 Apr 2019 14:40:47 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 05:40:47 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,329,1549958400"; d="scan'208";a="141243836" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by orsmga003.jf.intel.com with ESMTP; 09 Apr 2019 05:40:44 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Tue, 9 Apr 2019 20:41:20 +0800 Message-Id: <1554813689-26834-6-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554813689-26834-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554813689-26834-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v6 05/14] net/ipn3ke: add IPN3KE TM of PMD driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add Intel FPGA Acceleration NIC IPN3KE TM of PMD driver. Signed-off-by: Rosen Xu Signed-off-by: Andy Pei Signed-off-by: Dan Wei --- drivers/net/ipn3ke/Makefile | 1 + drivers/net/ipn3ke/ipn3ke_ethdev.c | 3 + drivers/net/ipn3ke/ipn3ke_ethdev.h | 7 + drivers/net/ipn3ke/ipn3ke_representor.c | 5 + drivers/net/ipn3ke/ipn3ke_tm.c | 2068 +++++++++++++++++++++++++++++++ drivers/net/ipn3ke/meson.build | 3 +- 6 files changed, 2086 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ipn3ke/ipn3ke_tm.c diff --git a/drivers/net/ipn3ke/Makefile b/drivers/net/ipn3ke/Makefile index 221567d..38d9384 100644 --- a/drivers/net/ipn3ke/Makefile +++ b/drivers/net/ipn3ke/Makefile @@ -34,5 +34,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 146d796..29828f3 100644 --- a/drivers/net/ipn3ke/ipn3ke_ethdev.c +++ b/drivers/net/ipn3ke/ipn3ke_ethdev.c @@ -274,6 +274,9 @@ 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; hw->flow_hw_enable = 1; } diff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.h b/drivers/net/ipn3ke/ipn3ke_ethdev.h index 4c2c94b..6985a25 100644 --- a/drivers/net/ipn3ke/ipn3ke_ethdev.h +++ b/drivers/net/ipn3ke/ipn3ke_ethdev.h @@ -555,6 +555,13 @@ static inline void _ipn3ke_indrct_write(struct ipn3ke_hw *hw, ipn3ke_rpst_init(struct rte_eth_dev *ethdev, void *init_params); int ipn3ke_rpst_uninit(struct rte_eth_dev *ethdev); +int +ipn3ke_hw_tm_init(struct ipn3ke_hw *hw); +void +ipn3ke_tm_init(struct ipn3ke_rpst *rpst); +int +ipn3ke_tm_ops_get(struct rte_eth_dev *ethdev, + void *arg); /* IPN3KE_MASK is a macro used on 32 bit registers */ diff --git a/drivers/net/ipn3ke/ipn3ke_representor.c b/drivers/net/ipn3ke/ipn3ke_representor.c index 3831982..63098bf 100644 --- a/drivers/net/ipn3ke/ipn3ke_representor.c +++ b/drivers/net/ipn3ke/ipn3ke_representor.c @@ -801,6 +801,8 @@ .allmulticast_disable = ipn3ke_rpst_allmulticast_disable, .mac_addr_set = ipn3ke_rpst_mac_addr_set, .mtu_set = ipn3ke_rpst_mtu_set, + + .tm_ops_get = ipn3ke_tm_ops_get, }; static uint16_t ipn3ke_rpst_recv_pkts(__rte_unused void *rx_q, @@ -840,6 +842,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); + /* Set representor device ops */ ethdev->dev_ops = &ipn3ke_rpst_dev_ops; diff --git a/drivers/net/ipn3ke/ipn3ke_tm.c b/drivers/net/ipn3ke/ipn3ke_tm.c new file mode 100644 index 0000000..4ca4c97 --- /dev/null +++ b/drivers/net/ipn3ke/ipn3ke_tm.c @@ -0,0 +1,2068 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 ec77390..3a95efc 100644 --- a/drivers/net/ipn3ke/meson.build +++ b/drivers/net/ipn3ke/meson.build @@ -11,5 +11,6 @@ allow_experimental_apis = true sources += files('ipn3ke_ethdev.c', - 'ipn3ke_representor.c') + 'ipn3ke_representor.c', + 'ipn3ke_tm.c') deps += ['bus_ifpga', 'sched']