The traffic management specific functions of the softnic driver are
supplied through set of pointers contained in the generic structure
of type 'rte_tm_ops'. These functions help to build and manage the
hierarchical QoS scheduler for traffic management.

Signed-off-by: Jasvinder Singh <jasvinder.si...@intel.com>
Signed-off-by: Cristian Dumitrescu <cristian.dumitre...@intel.com>
---
v2 changes:
- add TM functions for hierarchical QoS scheduler

 drivers/net/softnic/Makefile                    |    1 +
 drivers/net/softnic/rte_eth_softnic.c           |   48 +-
 drivers/net/softnic/rte_eth_softnic_internals.h |   81 ++
 drivers/net/softnic/rte_eth_softnic_tm.c        | 1145 +++++++++++++++++++++++
 4 files changed, 1274 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/softnic/rte_eth_softnic_tm.c

diff --git a/drivers/net/softnic/Makefile b/drivers/net/softnic/Makefile
index 809112c..e59766d 100644
--- a/drivers/net/softnic/Makefile
+++ b/drivers/net/softnic/Makefile
@@ -47,6 +47,7 @@ LIBABIVER := 1
 # all source are stored in SRCS-y
 #
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_tm.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_default.c
 
 #
diff --git a/drivers/net/softnic/rte_eth_softnic.c 
b/drivers/net/softnic/rte_eth_softnic.c
index d4ac100..24abb8e 100644
--- a/drivers/net/softnic/rte_eth_softnic.c
+++ b/drivers/net/softnic/rte_eth_softnic.c
@@ -41,6 +41,8 @@
 #include <rte_vdev.h>
 #include <rte_kvargs.h>
 #include <rte_errno.h>
+#include <rte_tm_driver.h>
+#include <rte_sched.h>
 
 #include "rte_eth_softnic.h"
 #include "rte_eth_softnic_internals.h"
@@ -59,6 +61,10 @@ static const char *pmd_valid_args[] = {
 static struct rte_vdev_driver pmd_drv;
 static struct rte_device *device;
 
+#ifndef TM
+#define TM                                             0
+#endif
+
 static int
 pmd_eth_dev_configure(struct rte_eth_dev *dev)
 {
@@ -114,6 +120,14 @@ pmd_eth_dev_start(struct rte_eth_dev *dev)
 {
        struct pmd_internals *p = dev->data->dev_private;
 
+#if TM
+       /* Initialize the Traffic Manager for the overlay device */
+       int status = tm_init(p);
+
+       if (status)
+               return status;
+#endif
+
        /* Clone dev->data from underlay to overlay */
        memcpy(dev->data->mac_pool_sel,
                p->udev->data->mac_pool_sel,
@@ -132,6 +146,11 @@ pmd_eth_dev_stop(struct rte_eth_dev *dev)
 
        /* Call the current function for the underlay device */
        rte_eth_dev_stop(p->uport_id);
+
+#if TM
+       /* Free the Traffic Manager for the overlay device */
+       tm_free(p);
+#endif
 }
 
 static void
@@ -247,6 +266,14 @@ pmd_eth_dev_mac_addr_remove(struct rte_eth_dev *dev, 
uint32_t index)
        rte_eth_dev_mac_addr_remove(p->uport_id, &dev->data->mac_addrs[index]);
 }
 
+static int
+pmd_eth_dev_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
+{
+       *(const struct rte_tm_ops **)arg = &pmd_tm_ops;
+
+       return 0;
+}
+
 static uint16_t
 pmd_eth_dev_tx_burst(void *txq,
        struct rte_mbuf **tx_pkts,
@@ -254,12 +281,30 @@ pmd_eth_dev_tx_burst(void *txq,
 {
        struct pmd_internals *p = txq;
 
+#if TM
+       rte_sched_port_enqueue(p->sched, tx_pkts, nb_pkts);
+       rte_eth_softnic_run(p->oport_id);
+       return nb_pkts;
+#else
        return rte_eth_tx_burst(p->uport_id, p->txq_id, tx_pkts, nb_pkts);
+#endif
 }
 
 int
-rte_eth_softnic_run(uint8_t port_id __rte_unused)
+rte_eth_softnic_run(uint8_t port_id)
 {
+       struct rte_eth_dev *odev = &rte_eth_devices[port_id];
+       struct pmd_internals *p = odev->data->dev_private;
+       uint32_t n_pkts, n_pkts_deq;
+
+       n_pkts_deq = rte_sched_port_dequeue(p->sched, p->pkts, p->deq_bsz);
+
+       for (n_pkts = 0; n_pkts < n_pkts_deq;)
+               n_pkts += rte_eth_tx_burst(p->uport_id,
+                       p->txq_id,
+                       &p->pkts[n_pkts],
+                       (uint16_t)(n_pkts_deq - n_pkts));
+
        return 0;
 }
 
@@ -284,6 +329,7 @@ pmd_ops_build(struct eth_dev_ops *o, const struct 
eth_dev_ops *u)
        o->mac_addr_set = pmd_eth_dev_mac_addr_set;
        o->mac_addr_add = pmd_eth_dev_mac_addr_add;
        o->mac_addr_remove = pmd_eth_dev_mac_addr_remove;
+       o->tm_ops_get = pmd_eth_dev_tm_ops_get;
 }
 
 int
diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h 
b/drivers/net/softnic/rte_eth_softnic_internals.h
index d456a54..5ca5121 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -38,9 +38,73 @@
 
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
+#include <rte_sched.h>
 
+#include <rte_tm_driver.h>
 #include "rte_eth_softnic.h"
 
+#ifndef TM_MAX_SUBPORTS
+#define TM_MAX_SUBPORTS                                        8
+#endif
+
+#ifndef TM_MAX_PIPES_PER_SUBPORT
+#define TM_MAX_PIPES_PER_SUBPORT               4096
+#endif
+
+#ifndef TM_MAX_QUEUE_SIZE
+#define TM_MAX_QUEUE_SIZE                              64
+#endif
+
+/* TM Shaper Profile. */
+struct tm_shaper_profile {
+       TAILQ_ENTRY(tm_shaper_profile) node;
+       uint32_t shaper_profile_id;
+       uint32_t shared_shaper_id;
+       uint32_t n_users;
+       struct rte_tm_shaper_params params;
+};
+
+/* TM Node */
+struct tm_node {
+       TAILQ_ENTRY(tm_node) node;
+       uint32_t id;
+       uint32_t priority;
+       uint32_t weight;
+       uint32_t level;
+       uint32_t n_child;
+       struct tm_node *parent_node;
+       struct tm_shaper_profile *shaper_profile;
+       struct rte_tm_node_params params;
+};
+
+TAILQ_HEAD(tm_nodes, tm_node);
+TAILQ_HEAD(tm_shaper_profiles, tm_shaper_profile);
+
+/* TM node levels */
+enum tm_node_level {
+       TM_NODE_LEVEL_PORT = 0,
+       TM_NODE_LEVEL_SUBPORT,
+       TM_NODE_LEVEL_PIPE,
+       TM_NODE_LEVEL_TC,
+       TM_NODE_LEVEL_QUEUE,
+       TM_NODE_LEVEL_MAX,
+};
+
+/* TM Configuration */
+struct tm_conf {
+       struct tm_shaper_profiles shaper_profiles;      /*< TM shaper profile */
+       struct tm_nodes tm_nodes;       /*< TM nodes */
+       uint32_t n_tm_nodes[TM_NODE_LEVEL_MAX]; /*< TM nodes per level */
+};
+
+struct tm_params {
+       struct rte_sched_port_params port_params;
+       struct rte_sched_subport_params subport_params[TM_MAX_SUBPORTS];
+       struct rte_sched_pipe_params
+               pipe_profiles[RTE_SCHED_PIPE_PROFILES_PER_PORT];
+       int pipe_to_profile[TM_MAX_SUBPORTS * TM_MAX_PIPES_PER_SUBPORT];
+};
+
 struct pmd_internals {
        /* Devices */
        struct rte_eth_dev *odev;
@@ -54,10 +118,27 @@ struct pmd_internals {
 
        /* Operation */
        struct rte_mbuf *pkts[RTE_ETH_SOFTNIC_DEQ_BSZ_MAX];
+       struct tm_params tm_params;
+       struct rte_sched_port *sched;
+       struct tm_conf tm_conf;
        uint32_t deq_bsz;
        uint32_t txq_id;
 };
 
+extern const struct rte_tm_ops pmd_tm_ops;
+
+void
+tm_conf_init(struct rte_eth_dev *dev);
+
+void
+tm_conf_uninit(struct rte_eth_dev *dev);
+
+int
+tm_init(struct pmd_internals *p);
+
+void
+tm_free(struct pmd_internals *p);
+
 void
 pmd_ops_inherit(struct eth_dev_ops *o, const struct eth_dev_ops *u);
 
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c 
b/drivers/net/softnic/rte_eth_softnic_tm.c
new file mode 100644
index 0000000..7c55cfd
--- /dev/null
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -0,0 +1,1145 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+
+#include <rte_malloc.h>
+#include <rte_sched.h>
+
+#include "rte_eth_softnic_internals.h"
+#include "rte_eth_softnic.h"
+
+void
+tm_conf_init(struct rte_eth_dev *dev)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+
+       /* Initialize shaper profiles list */
+       TAILQ_INIT(&p->tm_conf.shaper_profiles);
+
+       /* Initialize TM nodes */
+       TAILQ_INIT(&p->tm_conf.tm_nodes);
+
+       memset(p->tm_conf.n_tm_nodes, 0, TM_NODE_LEVEL_MAX);
+}
+
+void
+tm_conf_uninit(struct rte_eth_dev *dev)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_shaper_profile *shaper_profile;
+       struct tm_node *tm_node;
+
+       /* Remove all tm shaper profiles */
+       while ((shaper_profile =
+              TAILQ_FIRST(&p->tm_conf.shaper_profiles))) {
+               TAILQ_REMOVE(&p->tm_conf.shaper_profiles,
+                            shaper_profile, node);
+               rte_free(shaper_profile);
+       }
+
+       /* Remove all tm nodes*/
+       while ((tm_node =
+              TAILQ_FIRST(&p->tm_conf.tm_nodes))) {
+               TAILQ_REMOVE(&p->tm_conf.tm_nodes,
+                            tm_node, node);
+               rte_free(tm_node);
+       }
+
+       memset(p->tm_conf.n_tm_nodes, 0, TM_NODE_LEVEL_MAX);
+}
+
+static struct tm_shaper_profile *
+tm_shaper_profile_search(struct rte_eth_dev *dev, uint32_t shaper_profile_id)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_shaper_profiles *shaper_profile_list =
+               &p->tm_conf.shaper_profiles;
+       struct tm_shaper_profile *sp;
+
+       TAILQ_FOREACH(sp, shaper_profile_list, node) {
+               if (shaper_profile_id == sp->shaper_profile_id)
+                       return sp;
+       }
+
+       return NULL;
+}
+
+static int
+tm_shaper_profile_count(struct rte_eth_dev *dev)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_shaper_profiles *shaper_profile_list =
+               &p->tm_conf.shaper_profiles;
+       struct tm_shaper_profile *sp;
+       int n_shapers = 0;
+
+       /* Private Shaper Profile */
+       TAILQ_FOREACH(sp, shaper_profile_list, node) {
+               if (sp->shared_shaper_id == RTE_TM_SHAPER_PROFILE_ID_NONE)
+                       n_shapers++;
+       }
+
+       return n_shapers;
+}
+
+static int
+tm_shared_shaper_count(struct rte_eth_dev *dev)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_shaper_profiles *shaper_profile_list =
+               &p->tm_conf.shaper_profiles;
+       struct tm_shaper_profile *sp;
+       int n_shapers = 0;
+
+       /* Shared Shaper */
+       TAILQ_FOREACH(sp, shaper_profile_list, node) {
+               if (sp->shared_shaper_id != RTE_TM_SHAPER_PROFILE_ID_NONE)
+                       n_shapers++;
+       }
+
+       return n_shapers;
+}
+
+static struct tm_shaper_profile *
+tm_shared_shaper_search(struct rte_eth_dev *dev, uint32_t shared_shaper_id)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_shaper_profiles *shaper_profile_list =
+               &p->tm_conf.shaper_profiles;
+       struct tm_shaper_profile *sp;
+
+       TAILQ_FOREACH(sp, shaper_profile_list, node) {
+               if (shared_shaper_id == sp->shared_shaper_id)
+                       return sp;
+       }
+
+       return NULL;
+}
+
+static struct tm_node *
+tm_node_search(struct rte_eth_dev *dev, uint32_t node_id)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_nodes *tm_nodes_list = &p->tm_conf.tm_nodes;
+       struct tm_node *tm_node;
+
+       TAILQ_FOREACH(tm_node, tm_nodes_list, node) {
+               if (tm_node->id == node_id)
+                       return tm_node;
+       }
+
+       return NULL;
+}
+
+static int
+tm_node_get_child(struct rte_eth_dev *dev, uint32_t parent_id)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_nodes *tm_nodes_list = &p->tm_conf.tm_nodes;
+       struct tm_node *tm_node;
+       int n_child = 0;
+
+       TAILQ_FOREACH(tm_node, tm_nodes_list, node) {
+               if (tm_node->parent_node->id == parent_id)
+                       n_child++;
+       }
+
+       return n_child;
+}
+
+static struct tm_node *
+tm_root_node_present(struct rte_eth_dev *dev)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_nodes *tm_nodes_list = &p->tm_conf.tm_nodes;
+       struct tm_node *tm_node;
+
+       TAILQ_FOREACH(tm_node, tm_nodes_list, node) {
+               if (tm_node->parent_node->id == RTE_TM_NODE_ID_NULL)
+                       return tm_node;
+       }
+       return NULL;
+}
+
+int
+tm_init(struct pmd_internals *p)
+{
+       struct tm_params *t = &p->tm_params;
+       struct tm_nodes *tm_nodes_list = &p->tm_conf.tm_nodes;
+       uint32_t n_subports, subport_id, n_pipes;
+       struct tm_node *tm_node;
+       int status;
+
+       /* Port */
+       t->port_params.name = p->odev->data->name;
+       t->port_params.socket = p->udev->data->numa_node;
+       t->port_params.rate = p->udev->data->dev_link.link_speed;
+       t->port_params.mtu = p->udev->data->mtu;
+
+       p->sched = rte_sched_port_config(&t->port_params);
+       if (!p->sched)
+               return -EINVAL;
+
+       /* Subport */
+       n_subports = t->port_params.n_subports_per_port;
+       for (subport_id = 0; subport_id < n_subports; subport_id++) {
+               uint32_t n_pipes_per_subport
+                       = t->port_params.n_pipes_per_subport;
+               uint32_t pipe_id;
+
+               status = rte_sched_subport_config(p->sched,
+                               subport_id,
+                               &t->subport_params[subport_id]);
+               if (status) {
+                       rte_sched_port_free(p->sched);
+                       return -EINVAL;
+               }
+
+               /* Pipe */
+               n_pipes = 0;
+               pipe_id = n_subports + 1;
+               for (; pipe_id < n_pipes_per_subport; pipe_id++) {
+                       TAILQ_FOREACH(tm_node, tm_nodes_list, node) {
+                               if (tm_node->parent_node->id == subport_id)
+                               n_pipes++;
+                       }
+
+                       uint32_t pos = subport_id * n_pipes + pipe_id;
+                       int profile_id = t->pipe_to_profile[pos];
+
+                       if (profile_id < 0)
+                               continue;
+
+                       status = rte_sched_pipe_config(p->sched,
+                               subport_id,
+                               pipe_id,
+                               profile_id);
+                       if (status) {
+                               rte_sched_port_free(p->sched);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+void
+tm_free(struct pmd_internals *p)
+{
+       if (p->sched)
+               rte_sched_port_free(p->sched);
+}
+
+/* Traffic manager node type get */
+static int
+pmd_tm_node_type_get(struct rte_eth_dev *dev __rte_unused,
+       uint32_t node_id,
+       int *is_leaf,
+       struct rte_tm_error *error)
+{
+       struct tm_node *tm_node;
+
+       if (!is_leaf || !error)
+               return -EINVAL;
+
+       /* Check: node id */
+       if (node_id == RTE_TM_NODE_ID_NULL) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+               error->message = "node id invalid!";
+               return -EINVAL;
+       }
+
+       tm_node = tm_node_search(dev, node_id);
+       if (!tm_node) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+               error->message = "node doesn't exists!";
+               return -EINVAL;
+       }
+
+       if (tm_node->n_child)
+               *is_leaf = 0;
+       else
+               *is_leaf = 1;
+
+       return 0;
+}
+
+/* Traffic manager capabilities get */
+static int
+pmd_tm_capabilities_get(struct rte_eth_dev *dev,
+       struct rte_tm_capabilities *cap,
+       struct rte_tm_error *error __rte_unused)
+{
+       uint64_t n_nodes_level1 = TM_MAX_SUBPORTS;
+       uint64_t n_nodes_level2 = n_nodes_level1 * TM_MAX_PIPES_PER_SUBPORT;
+       uint64_t n_nodes_level3 = n_nodes_level2 * RTE_SCHED_QUEUES_PER_PIPE;
+       struct pmd_internals *p = dev->data->dev_private;
+       uint32_t ls = p->udev->data->dev_link.link_speed;
+       int i;
+
+       if (!cap || !error)
+               return -EINVAL;
+
+       memset(cap, 0, sizeof(struct rte_tm_capabilities));
+
+       /* TM  capabilities */
+       cap->n_nodes_max = n_nodes_level1 + n_nodes_level2 + n_nodes_level3 + 1;
+       cap->n_levels_max = TM_NODE_LEVEL_MAX;
+       cap->non_leaf_nodes_identical = 0;
+       cap->leaf_nodes_identical = 1;
+       cap->shaper_n_max = n_nodes_level1 + n_nodes_level2;
+       cap->shaper_private_n_max = n_nodes_level2;
+       cap->shaper_private_dual_rate_n_max = 0;
+       cap->shaper_private_rate_min = 0;
+       cap->shaper_private_rate_max = (ls * 1000000) / 8;
+       cap->shaper_shared_n_max = n_nodes_level1;
+       cap->shaper_shared_n_nodes_per_shaper_max = TM_MAX_PIPES_PER_SUBPORT;
+       cap->shaper_shared_n_shapers_per_node_max = n_nodes_level1;
+       cap->shaper_shared_dual_rate_n_max = 0;
+       cap->shaper_shared_rate_min = 0;
+       cap->shaper_shared_rate_max = (ls * 1000000) / 8;
+       cap->shaper_pkt_length_adjust_min = 0;
+       cap->shaper_pkt_length_adjust_max = RTE_SCHED_FRAME_OVERHEAD_DEFAULT;
+       cap->sched_n_children_max = TM_MAX_PIPES_PER_SUBPORT;
+       cap->sched_sp_n_priorities_max = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+       cap->sched_wfq_n_children_per_group_max = TM_MAX_PIPES_PER_SUBPORT;
+       cap->sched_wfq_n_groups_max = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+       cap->sched_wfq_weight_max = 1;
+       cap->cman_head_drop_supported = 0;
+       cap->cman_wred_context_n_max = n_nodes_level3;
+       cap->cman_wred_context_private_n_max = n_nodes_level3;
+       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;
+
+       for (i = 0; i < RTE_TM_COLORS; i++) {
+               cap->mark_vlan_dei_supported[i] = 0;
+               cap->mark_ip_ecn_tcp_supported[i] = 0;
+               cap->mark_ip_ecn_sctp_supported[i] = 0;
+               cap->mark_ip_dscp_supported[i] = 0;
+       }
+
+       cap->dynamic_update_mask = 0;
+       cap->stats_mask = 0;
+
+       return 0;
+}
+
+/* Traffic manager level capabilities get */
+static int
+pmd_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 pmd_internals *p = dev->data->dev_private;
+       uint32_t ls = p->udev->data->dev_link.link_speed;
+
+       if (!cap || !error)
+               return -EINVAL;
+
+       if (level_id >= TM_NODE_LEVEL_MAX) {
+               error->type = RTE_TM_ERROR_TYPE_LEVEL_ID;
+               error->message = "level id invalid!";
+               return -EINVAL;
+       }
+
+       memset(cap, 0, sizeof(struct rte_tm_capabilities));
+
+       if (level_id == TM_NODE_LEVEL_PORT) {
+               /* Root node */
+               cap->n_nodes_max = 1;
+               cap->n_nodes_nonleaf_max = 1;
+               cap->n_nodes_leaf_max = 0;
+               cap->non_leaf_nodes_identical = 1;
+               cap->leaf_nodes_identical = 0;
+               cap->nonleaf.shaper_private_supported = 1;
+               cap->nonleaf.shaper_private_dual_rate_supported = 0;
+               cap->nonleaf.shaper_private_rate_min = 0;
+
+               cap->nonleaf.shaper_private_rate_max = (ls * 1000000) / 8;
+               cap->nonleaf.shaper_shared_n_max = 0;
+               cap->nonleaf.sched_n_children_max = TM_MAX_SUBPORTS;
+               cap->nonleaf.sched_sp_n_priorities_max = 0;
+               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 = 0;
+
+       } else if (level_id == TM_NODE_LEVEL_SUBPORT) {
+               /* Subport */
+               cap->n_nodes_max = TM_MAX_SUBPORTS;
+               cap->n_nodes_nonleaf_max = TM_MAX_SUBPORTS;
+               cap->n_nodes_leaf_max = 0;
+               cap->non_leaf_nodes_identical = 1;
+               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 = 0;
+               cap->nonleaf.shaper_private_rate_max = (ls * 1000000) / 8;
+               cap->nonleaf.shaper_shared_n_max = 1;
+               cap->nonleaf.sched_n_children_max = TM_MAX_PIPES_PER_SUBPORT;
+               cap->nonleaf.sched_sp_n_priorities_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_n_children_per_group_max
+                       = TM_MAX_PIPES_PER_SUBPORT;
+               cap->nonleaf.sched_wfq_n_groups_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_weight_max = 1;
+               cap->nonleaf.stats_mask = 0;
+
+       } else if (level_id == TM_NODE_LEVEL_PIPE) {
+               /* Pipe */
+               cap->n_nodes_max
+                       = TM_MAX_PIPES_PER_SUBPORT * TM_MAX_SUBPORTS;
+               cap->n_nodes_nonleaf_max
+                       = TM_MAX_PIPES_PER_SUBPORT * TM_MAX_SUBPORTS;
+               cap->n_nodes_leaf_max = 0;
+               cap->non_leaf_nodes_identical = 1;
+               cap->leaf_nodes_identical = 0;
+               cap->nonleaf.shaper_private_supported = 1;
+               cap->nonleaf.shaper_private_dual_rate_supported = 0;
+               cap->nonleaf.shaper_private_rate_min = 0;
+               cap->nonleaf.shaper_private_rate_max
+                       = (ls * 1000000) / (8 * TM_MAX_PIPES_PER_SUBPORT);
+               cap->nonleaf.shaper_shared_n_max = 1;
+               cap->nonleaf.sched_n_children_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_sp_n_priorities_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_n_children_per_group_max = 1;
+               cap->nonleaf.sched_wfq_n_groups_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_weight_max = 1;
+               cap->nonleaf.stats_mask = 0;
+
+       } else if (level_id == TM_NODE_LEVEL_TC) {
+               /* Traffic Class */
+               cap->n_nodes_max
+                       = TM_MAX_SUBPORTS
+                       * TM_MAX_PIPES_PER_SUBPORT
+                       * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->n_nodes_nonleaf_max
+                       = TM_MAX_SUBPORTS
+                       * TM_MAX_PIPES_PER_SUBPORT
+                       * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->n_nodes_leaf_max = 0;
+               cap->non_leaf_nodes_identical = 1;
+               cap->leaf_nodes_identical = 0;
+               cap->nonleaf.shaper_private_supported = 1;
+               cap->nonleaf.shaper_private_dual_rate_supported = 0;
+               cap->nonleaf.shaper_private_rate_min = 0;
+               cap->nonleaf.shaper_private_rate_max
+                       = (ls * 1000000) / (8 * TM_MAX_PIPES_PER_SUBPORT);
+               cap->nonleaf.shaper_shared_n_max = 0;
+               cap->nonleaf.sched_n_children_max = RTE_SCHED_QUEUES_PER_PIPE;
+               cap->nonleaf.sched_sp_n_priorities_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_n_children_per_group_max
+                       = RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS;
+               cap->nonleaf.sched_wfq_n_groups_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_weight_max = 1;
+               cap->nonleaf.stats_mask = 0;
+
+               } else {
+               /* TM Queues */
+               cap->n_nodes_max
+                       = TM_MAX_SUBPORTS
+                       * TM_MAX_PIPES_PER_SUBPORT
+                       * RTE_SCHED_QUEUES_PER_PIPE;
+               cap->n_nodes_nonleaf_max = 0;
+               cap->n_nodes_leaf_max = cap->n_nodes_max;
+               cap->non_leaf_nodes_identical = 0;
+               cap->leaf_nodes_identical = 1;
+               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_context_private_supported = 1;
+               cap->leaf.cman_wred_context_shared_n_max = 0;
+               cap->nonleaf.stats_mask = 0;
+       }
+       return 0;
+}
+
+/* Traffic manager node capabilities get */
+static int
+pmd_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 pmd_internals *p = dev->data->dev_private;
+       uint32_t ls = p->udev->data->dev_link.link_speed;
+       struct tm_node *tm_node;
+
+       if (!cap || !error)
+               return -EINVAL;
+
+       tm_node = tm_node_search(dev, node_id);
+
+       /* Check: node validity */
+       if ((node_id == RTE_TM_NODE_ID_NULL) || (!tm_node)) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+               error->message = "node id invalid!";
+               return -EINVAL;
+       }
+
+       memset(cap, 0, sizeof(struct rte_tm_capabilities));
+
+       /* Check: node level */
+       if (tm_node->level == 0) {
+               /* Root node */
+               cap->shaper_private_supported = 1;
+               cap->shaper_private_dual_rate_supported = 0;
+               cap->shaper_private_rate_min = 0;
+               cap->shaper_private_rate_max = (ls * 1000000) / 8;
+               cap->shaper_shared_n_max = 0;
+               cap->nonleaf.sched_n_children_max = TM_MAX_SUBPORTS;
+               cap->nonleaf.sched_sp_n_priorities_max = 0;
+               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;
+
+       } else if (tm_node->level == 1) {
+               /* Subport */
+               cap->shaper_private_supported = 0;
+               cap->shaper_private_dual_rate_supported = 0;
+               cap->shaper_private_rate_min = 0;
+               cap->shaper_private_rate_max = (ls * 1000000) / 8;
+               cap->shaper_shared_n_max = 1;
+               cap->nonleaf.sched_n_children_max = TM_MAX_PIPES_PER_SUBPORT;
+               cap->nonleaf.sched_sp_n_priorities_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_n_children_per_group_max
+                       = TM_MAX_PIPES_PER_SUBPORT;
+               cap->nonleaf.sched_wfq_n_groups_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_weight_max = 1;
+
+       } else if (tm_node->level == 2) {
+               /* Pipe */
+               cap->shaper_private_supported = 1;
+               cap->shaper_private_dual_rate_supported = 0;
+               cap->shaper_private_rate_min = 0;
+               cap->shaper_private_rate_max
+                       = (ls * 1000000) / (8 * TM_MAX_PIPES_PER_SUBPORT);
+               cap->shaper_shared_n_max = 0;
+               cap->nonleaf.sched_n_children_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_sp_n_priorities_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_n_children_per_group_max = 1;
+               cap->nonleaf.sched_wfq_n_groups_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_weight_max = 1;
+
+       } else if (tm_node->level == 3) {
+               /* Traffic Class */
+               cap->shaper_private_supported = 0;
+               cap->shaper_private_dual_rate_supported = 0;
+               cap->shaper_private_rate_min = 0;
+               cap->shaper_private_rate_max
+                       = (ls * 1000000) / (8 * TM_MAX_PIPES_PER_SUBPORT);
+               cap->shaper_shared_n_max = 0;
+               cap->nonleaf.sched_n_children_max
+                       = RTE_SCHED_QUEUES_PER_PIPE;
+               cap->nonleaf.sched_sp_n_priorities_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_n_children_per_group_max
+                       = RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS;
+               cap->nonleaf.sched_wfq_n_groups_max
+                       = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+               cap->nonleaf.sched_wfq_weight_max = 1;
+       } else {
+               /* Queue */
+               cap->shaper_private_supported = 1;
+               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 = 1;
+               cap->leaf.cman_wred_context_private_supported = 0;
+               cap->leaf.cman_wred_context_shared_n_max = 0;
+       }
+       cap->stats_mask = 0;
+
+       return 0;
+}
+
+/* Traffic manager shaper profile add */
+static int
+pmd_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 pmd_internals *p = dev->data->dev_private;
+       struct tm_shaper_profile *sp;
+       struct tm_shaper_profiles *spl = &p->tm_conf.shaper_profiles;
+       char shaper_name[256];
+
+       if (!profile || !error)
+               return -EINVAL;
+
+       /* Shaper Rate */
+       if (!profile->peak.rate) {
+               error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE;
+               error->message = "rate not specified!";
+               return -EINVAL;
+       }
+
+       /* Shaper Bucket Size */
+       if (!profile->peak.size) {
+               error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;
+               error->message = "bucket size not specified!";
+               return -EINVAL;
+       }
+
+       /* Shaper Committed Rate */
+       if (profile->committed.rate) {
+               error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE;
+               error->message = "dual rate shaper not supported!";
+               return -EINVAL;
+       }
+
+       /* Shaper Committed Size */
+       if (profile->committed.size) {
+               error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;
+               error->message = "dual rate shaper not supported!";
+               return -EINVAL;
+       }
+
+       sp = tm_shaper_profile_search(dev, shaper_profile_id);
+
+       if (sp) {
+               error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
+               error->message = "profile ID exist";
+               return -EINVAL;
+       }
+
+       snprintf(shaper_name, sizeof(shaper_name),
+               "tm_shaper_profile_%u", shaper_profile_id);
+
+       sp = rte_zmalloc(shaper_name, sizeof(struct tm_shaper_profile), 0);
+       if (!sp)
+               return -ENOMEM;
+
+       sp->shaper_profile_id = shaper_profile_id;
+       sp->shared_shaper_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+
+       (void)rte_memcpy(&sp->params, profile,
+                        sizeof(struct rte_tm_shaper_params));
+
+       if (!spl->tqh_first)
+               tm_conf_init(dev);
+
+       TAILQ_INSERT_TAIL(spl, sp, node);
+
+       return 0;
+}
+
+/* Traffic manager shaper profile delete */
+static int
+pmd_tm_shaper_profile_delete(struct rte_eth_dev *dev,
+       uint32_t shaper_profile_id,
+       struct rte_tm_error *error)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_shaper_profile *sp;
+
+       if (!error)
+               return -EINVAL;
+
+       sp = tm_shaper_profile_search(dev, shaper_profile_id);
+
+       if (!sp) {
+               error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
+               error->message = "profile ID not exist";
+               return -EINVAL;
+       }
+
+       /* Check: profile usage */
+       if (sp->n_users) {
+               error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE;
+               error->message = "profile in use!";
+               return -EINVAL;
+       }
+
+       TAILQ_REMOVE(&p->tm_conf.shaper_profiles, sp, node);
+       rte_free(sp);
+
+       return 0;
+}
+
+/* Traffic manager shared shaper add/update */
+static int
+pmd_tm_shared_shaper_add_update(struct rte_eth_dev *dev,
+       uint32_t shared_shaper_id,
+       uint32_t shaper_profile_id,
+       struct rte_tm_error *error)
+{
+       struct tm_shaper_profile *sp;
+       uint32_t n_shared_shapers;
+
+       if (!error)
+               return -EINVAL;
+
+       sp = tm_shaper_profile_search(dev, shaper_profile_id);
+
+       if (!sp) {
+               error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
+               error->message = "shaper profile doesn't exist!";
+               return -EINVAL;
+       }
+
+       /* Shared shaper add/update */
+       n_shared_shapers = tm_shared_shaper_count(dev);
+       if (sp->shared_shaper_id == RTE_TM_SHAPER_PROFILE_ID_NONE)
+               sp->shared_shaper_id = n_shared_shapers;
+       else
+               sp->shared_shaper_id = shared_shaper_id;
+
+       return 0;
+}
+
+/* Traffic manager shared shaper delete */
+static int
+pmd_tm_shared_shaper_delete(struct rte_eth_dev *dev,
+       uint32_t shared_shaper_id,
+       struct rte_tm_error *error)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_shaper_profile *sp;
+
+       if (!error)
+               return -EINVAL;
+
+       sp = tm_shared_shaper_search(dev, shared_shaper_id);
+
+       if (!sp) {
+               error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
+               error->message = "shared shaper not exist";
+               return -EINVAL;
+       }
+
+       /* Check: profile usage */
+       if (sp->n_users) {
+               error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE;
+               error->message = "profile in use!";
+               return -EINVAL;
+       }
+
+       TAILQ_REMOVE(&p->tm_conf.shaper_profiles, sp, node);
+       rte_free(sp);
+
+       return 0;
+}
+
+/* Traffic manager node add */
+static int
+pmd_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 tm_node *tm_node, *parent_node;
+       struct tm_shaper_profile *sp;
+       uint64_t nodes_l1 = TM_MAX_SUBPORTS;
+       uint64_t nodes_l2 = nodes_l1 * TM_MAX_PIPES_PER_SUBPORT;
+       uint64_t nodes_l3 = nodes_l2 * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE;
+       uint64_t nodes_l4 = nodes_l2 * RTE_SCHED_QUEUES_PER_PIPE;
+       char node_name[256];
+
+       struct pmd_internals *p = dev->data->dev_private;
+
+       if (!params || !error)
+               return -EINVAL;
+
+       /* Check: node id NULL*/
+       if (node_id == RTE_TM_NODE_ID_NULL) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+               error->message = "invalid node id!";
+               return -EINVAL;
+       }
+
+       /* Check: node priority */
+       if (!priority) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_PRIORITY;
+               error->message = "priority not supported!";
+               return -EINVAL;
+       }
+
+       /* Check: node weight */
+       if (weight < 1) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_WEIGHT;
+               error->message = "weight not supported!";
+               return -EINVAL;
+       }
+
+       /* Check: node ID used */
+       if (tm_node_search(dev, node_id)) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+               error->message = "node id already used!";
+               return -EINVAL;
+       }
+
+       /* Check: level */
+       if ((level_id != RTE_TM_NODE_LEVEL_ID_ANY) &&
+               (level_id >= TM_NODE_LEVEL_MAX)) {
+               error->type = RTE_TM_ERROR_TYPE_LEVEL_ID;
+               error->message = "levels exceeds the maximum allowed!";
+               return -EINVAL;
+       }
+
+       /* Check: number of nodes at levels*/
+       if (((level_id == TM_NODE_LEVEL_PORT) &&
+               (p->tm_conf.n_tm_nodes[TM_NODE_LEVEL_PORT] > 1)) ||
+               ((level_id == TM_NODE_LEVEL_SUBPORT) &&
+               (p->tm_conf.n_tm_nodes[TM_NODE_LEVEL_SUBPORT] > nodes_l1)) ||
+               ((level_id == TM_NODE_LEVEL_PIPE) &&
+               (p->tm_conf.n_tm_nodes[TM_NODE_LEVEL_PIPE] > nodes_l2)) ||
+               ((level_id == TM_NODE_LEVEL_TC) &&
+               (p->tm_conf.n_tm_nodes[TM_NODE_LEVEL_TC] > nodes_l3)) ||
+               ((level_id == TM_NODE_LEVEL_QUEUE) &&
+               (p->tm_conf.n_tm_nodes[TM_NODE_LEVEL_QUEUE] > nodes_l4))) {
+               error->type = RTE_TM_ERROR_TYPE_LEVEL_ID;
+               error->message = "nodes exceeds the max at this level!";
+               return -EINVAL;
+       }
+
+       /* Check: node shaper profile */
+       sp = tm_shaper_profile_search(dev, params->shaper_profile_id);
+       if (!sp) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;
+               error->message = "shaper profile invalid! ";
+               return -EINVAL;
+       }
+
+       /* Check: root node */
+       if (parent_node_id == RTE_TM_NODE_ID_NULL) {
+               /* Check: level id */
+               if (level_id) {
+                       error->type = RTE_TM_ERROR_TYPE_LEVEL_ID;
+                       error->message = "level id invalid! ";
+                       return -EINVAL;
+               }
+
+               /* Check: root node shaper params */
+               if ((!sp) || (sp->params.committed.size > 0) ||
+                       (sp->params.committed.rate > 0) ||
+                       (params->n_shared_shapers > 0) ||
+                       (params->shared_shaper_id) ||
+                       (params->shaper_profile_id
+                               == RTE_TM_SHAPER_PROFILE_ID_NONE)) {
+                       error->type
+                        = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;
+                       error->message = "root node shaper invalid! ";
+                       return -EINVAL;
+               }
+
+               /* Check: root node */
+               if (tm_root_node_present(dev)) {
+                       error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
+                       error->message = "root node already present!";
+                       return -EINVAL;
+               }
+       }
+
+       /* Node add */
+       snprintf(node_name, sizeof(node_name), "node_%u", node_id);
+       tm_node = rte_zmalloc(node_name, sizeof(struct tm_node), 0);
+       if (!tm_node)
+               return -ENOMEM;
+
+       /*  Check: parent node */
+       if (parent_node_id != RTE_TM_NODE_ID_NULL) {
+               parent_node = tm_node_search(dev, parent_node_id);
+
+               if ((level_id != RTE_TM_NODE_LEVEL_ID_ANY) &&
+                       (level_id != parent_node->level + 1)) {
+                       error->type = RTE_TM_ERROR_TYPE_LEVEL_ID;
+                       error->message = "level id invalid! ";
+                       rte_free(tm_node);
+                       return -EINVAL;
+               }
+
+               tm_node->parent_node = parent_node;
+               parent_node->n_child += 1;
+
+       } else {
+               tm_node->parent_node = NULL;
+       }
+
+       tm_node->id = node_id;
+       tm_node->priority = priority;
+       tm_node->weight = weight;
+       tm_node->n_child = 0;
+       tm_node->level = level_id;
+
+       (void)rte_memcpy(&tm_node->params,
+               params, sizeof(struct rte_tm_node_params));
+
+       /* Update:  shaper profile users */
+       sp->n_users++;
+
+       /* Update: number of nodes */
+       p->tm_conf.n_tm_nodes[tm_node->level] += 1;
+
+       return 0;
+}
+
+/* Traffic manager node delete */
+static int
+pmd_tm_node_delete(struct rte_eth_dev *dev,
+       uint32_t node_id,
+       struct rte_tm_error *error)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_node *tm_node;
+
+       if (!error)
+               return -EINVAL;
+
+       if (node_id == RTE_TM_NODE_ID_NULL) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+               error->message = "invalid node id";
+               return -EINVAL;
+       }
+
+       /* Check: node id */
+       tm_node = tm_node_search(dev, node_id);
+       if (!tm_node) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+               error->message = "node id invalid!";
+               return -EINVAL;
+       }
+
+       /* Check: node child */
+       if (tm_node->n_child) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+               error->message = "node children exist!";
+               return -EINVAL;
+       }
+
+       /* Delete node */
+       tm_node->shaper_profile->n_users--;
+       tm_node->parent_node->n_child--;
+       TAILQ_REMOVE(&p->tm_conf.tm_nodes, tm_node, node);
+       p->tm_conf.n_tm_nodes[tm_node->level]--;
+       rte_free(tm_node);
+
+       return 0;
+}
+
+/* Traffic manager hierarchy commit */
+static int
+pmd_tm_hierarchy_commit(struct rte_eth_dev *dev,
+       int clear_on_fail,
+       struct rte_tm_error *error)
+{
+       struct pmd_internals *p = dev->data->dev_private;
+       struct tm_params *t = &p->tm_params;
+       struct tm_conf *tm_conf = &p->tm_conf;
+       struct tm_node *tm_node;
+       struct tm_shaper_profile *sp;
+       uint32_t i, pid = 0, subport_id, pipe_id, n_subports;
+       uint32_t n_subports_per_port, n_pipes_per_subport, n_pipe_profiles;
+       struct tm_shaper_profiles *sp_list = &tm_conf->shaper_profiles;
+
+       if (!error) {
+               if (clear_on_fail)
+                       goto fail_clear;
+               return -EINVAL;
+       }
+
+       /* TM Port */
+       tm_node = tm_root_node_present(dev);
+       if (!tm_node) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
+               error->message = "root node not exists!";
+               if (clear_on_fail)
+                       goto fail_clear;
+               return -EINVAL;
+       }
+
+       n_subports_per_port = tm_conf->n_tm_nodes[1];
+       if (n_subports_per_port > TM_MAX_SUBPORTS) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
+               error->message = "Number of subports exceeded!";
+               if (clear_on_fail)
+                       goto fail_clear;
+               return -EINVAL;
+       }
+
+       n_pipes_per_subport = tm_conf->n_tm_nodes[2];
+       if (n_pipes_per_subport > TM_MAX_PIPES_PER_SUBPORT) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
+               error->message = "Number of pipes exceeded!";
+               if (clear_on_fail)
+                       goto fail_clear;
+               return -EINVAL;
+       }
+       n_pipe_profiles = tm_shaper_profile_count(dev);
+       if (n_pipe_profiles > RTE_SCHED_PIPE_PROFILES_PER_PORT) {
+               error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
+               error->message = "Number of pipe profiles exceeded!";
+               if (clear_on_fail)
+                       goto fail_clear;
+               return -EINVAL;
+       }
+
+       t->port_params.n_subports_per_port = n_subports_per_port;
+       t->port_params.n_pipes_per_subport = n_pipes_per_subport;
+       t->port_params.n_pipe_profiles = n_pipe_profiles;
+       t->port_params.frame_overhead = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+       for (i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++)
+               t->port_params.qsize[i] = TM_MAX_QUEUE_SIZE;
+
+       TAILQ_FOREACH(sp, sp_list, node) {
+               if (sp->shared_shaper_id == RTE_TM_SHAPER_PROFILE_ID_NONE) {
+                       t->port_params.pipe_profiles[pid].tb_rate
+                               = sp->params.peak.rate;
+                       t->port_params.pipe_profiles[pid].tb_size
+                               = sp->params.peak.size;
+
+                       for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+                               t->port_params.pipe_profiles[pid].tc_rate[i]
+                                       = sp->params.peak.rate;
+
+                       t->port_params.pipe_profiles[pid].tc_period = 40;
+
+                       for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
+                               t->port_params.pipe_profiles[pid].wrr_weights[i]
+                                       = 1;
+
+                       pid++;
+               }
+       }
+
+       /* TM Subport */
+       n_subports = t->port_params.n_subports_per_port;
+       for (subport_id = 0; subport_id < n_subports; subport_id++) {
+               struct tm_node *subport = tm_node_search(dev, subport_id + 1);
+               uint32_t n_shapers = subport->params.n_shared_shapers;
+
+               for (i = 0; i < n_shapers; i++) {
+                       struct tm_shaper_profile *sp
+                               = tm_shared_shaper_search(dev,
+                                       subport->params.shared_shaper_id[i]);
+
+                       t->subport_params[subport_id].tb_rate
+                               = sp->params.peak.rate;
+                       t->subport_params[subport_id].tb_size
+                               = sp->params.peak.size;
+                       for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+                               t->subport_params[subport_id].tc_rate[i]
+                                       = sp->params.peak.rate;
+
+                       t->subport_params[subport_id].tc_period = 10;
+               }
+
+               /* TM Pipe */
+               n_pipes_per_subport = t->port_params.n_pipes_per_subport;
+               pipe_id = n_subports + 1;
+               for (; pipe_id < n_pipes_per_subport; pipe_id++) {
+                       uint32_t n_max_pipes
+                               = tm_node_get_child(dev, subport_id);
+                       uint32_t pos = subport_id * n_max_pipes + pipe_id;
+                       struct tm_node *pipe = tm_node_search(dev, pos);
+
+                       t->pipe_to_profile[pos]
+                               = pipe->shaper_profile->shaper_profile_id;
+               }
+       }
+
+       return 0;
+
+fail_clear:
+       if (clear_on_fail) {
+               tm_conf_uninit(dev);
+               tm_conf_init(dev);
+       }
+       return -EINVAL;
+}
+
+/* Traffic manager read stats counters for specific node */
+static int
+pmd_tm_node_stats_read(struct rte_eth_dev *dev __rte_unused,
+       uint32_t node_id __rte_unused,
+       struct rte_tm_node_stats *stats __rte_unused,
+       uint64_t *stats_mask __rte_unused,
+       int clear __rte_unused,
+       struct rte_tm_error *error __rte_unused)
+{
+       return 0;
+}
+
+const struct rte_tm_ops pmd_tm_ops = {
+       .node_type_get = pmd_tm_node_type_get,
+       .capabilities_get = pmd_tm_capabilities_get,
+       .level_capabilities_get = pmd_tm_level_capabilities_get,
+       .node_capabilities_get = pmd_tm_node_capabilities_get,
+
+       .wred_profile_add = NULL,
+       .wred_profile_delete = NULL,
+       .shared_wred_context_add_update = NULL,
+       .shared_wred_context_delete = NULL,
+
+       .shaper_profile_add = pmd_tm_shaper_profile_add,
+       .shaper_profile_delete = pmd_tm_shaper_profile_delete,
+       .shared_shaper_add_update = pmd_tm_shared_shaper_add_update,
+       .shared_shaper_delete = pmd_tm_shared_shaper_delete,
+
+       .node_add = pmd_tm_node_add,
+       .node_delete = pmd_tm_node_delete,
+       .node_suspend = NULL,
+       .node_resume = NULL,
+       .hierarchy_commit = pmd_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 = pmd_tm_node_stats_read,
+};
-- 
2.9.3

Reply via email to