[dpdk-dev] [PATCH v2 2/2] net/softnic: add traffic management ops
Jasvinder Singh
jasvinder.singh at intel.com
Mon Jun 26 18:43:34 CEST 2017
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.singh at intel.com>
Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu at 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
More information about the dev
mailing list