DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/8] net/mvpp2: add new features
@ 2018-09-04  7:10 Tomasz Duszynski
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 1/8] net/mvpp2: initialize ppio only once Tomasz Duszynski
                   ` (8 more replies)
  0 siblings, 9 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04  7:10 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

This patch series introduces fixes and adds support for traffic metering
and traffic manager.

Natalie Samsonov (2):
  net/mvpp2: initialize ppio only once
  net/mvpp2: update MTU and MRU related calculations

Tomasz Duszynski (5):
  net/mvpp2: move common code
  net/mvpp2: add metering support
  net/mvpp2: change default policer configuration
  net/mvpp2: add init and deinit to flow
  net/mvpp2: add traffic manager support

Yuval Caduri (1):
  net/mvpp2: detach tx_qos from rx cls/qos config

 doc/guides/nics/mvpp2.rst       |   31 +-
 drivers/net/mvpp2/Makefile      |    2 +
 drivers/net/mvpp2/meson.build   |    4 +-
 drivers/net/mvpp2/mrvl_ethdev.c |  188 ++++++--
 drivers/net/mvpp2/mrvl_ethdev.h |  122 ++++-
 drivers/net/mvpp2/mrvl_flow.c   |  129 +++--
 drivers/net/mvpp2/mrvl_flow.h   |   15 +
 drivers/net/mvpp2/mrvl_mtr.c    |  512 ++++++++++++++++++++
 drivers/net/mvpp2/mrvl_mtr.h    |   15 +
 drivers/net/mvpp2/mrvl_qos.c    |  244 +++++-----
 drivers/net/mvpp2/mrvl_qos.h    |    2 +-
 drivers/net/mvpp2/mrvl_tm.c     | 1009 +++++++++++++++++++++++++++++++++++++++
 drivers/net/mvpp2/mrvl_tm.h     |   15 +
 13 files changed, 2064 insertions(+), 224 deletions(-)
 create mode 100644 drivers/net/mvpp2/mrvl_flow.h
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.c
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.h
 create mode 100644 drivers/net/mvpp2/mrvl_tm.c
 create mode 100644 drivers/net/mvpp2/mrvl_tm.h

--
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH 1/8] net/mvpp2: initialize ppio only once
  2018-09-04  7:10 [dpdk-dev] [PATCH 0/8] net/mvpp2: add new features Tomasz Duszynski
@ 2018-09-04  7:10 ` Tomasz Duszynski
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 2/8] net/mvpp2: move common code Tomasz Duszynski
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04  7:10 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw

From: Natalie Samsonov <nsamsono@marvell.com>

This changes stop/start/configure behavior due to issue in MUSDK
library itself.  From now on, ppio can be reconfigured only after interface
is closed.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Yuval Caduri <cyuval@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c | 53 +++++++++++++++++++++++++----------------
 1 file changed, 32 insertions(+), 21 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 6824445..f022cad 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -304,6 +304,11 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 	struct mrvl_priv *priv = dev->data->dev_private;
 	int ret;
 
+	if (priv->ppio) {
+		MRVL_LOG(INFO, "Device reconfiguration is not supported");
+		return -EINVAL;
+	}
+
 	if (dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_NONE &&
 	    dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) {
 		MRVL_LOG(INFO, "Unsupported rx multi queue mode %d",
@@ -525,6 +530,9 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 	char match[MRVL_MATCH_LEN];
 	int ret = 0, i, def_init_size;
 
+	if (priv->ppio)
+		return mrvl_dev_set_link_up(dev);
+
 	snprintf(match, sizeof(match), "ppio-%d:%d",
 		 priv->pp_id, priv->ppio_id);
 	priv->ppio_params.match = match;
@@ -749,28 +757,7 @@ mrvl_flush_bpool(struct rte_eth_dev *dev)
 static void
 mrvl_dev_stop(struct rte_eth_dev *dev)
 {
-	struct mrvl_priv *priv = dev->data->dev_private;
-
 	mrvl_dev_set_link_down(dev);
-	mrvl_flush_rx_queues(dev);
-	mrvl_flush_tx_shadow_queues(dev);
-	if (priv->cls_tbl) {
-		pp2_cls_tbl_deinit(priv->cls_tbl);
-		priv->cls_tbl = NULL;
-	}
-	if (priv->qos_tbl) {
-		pp2_cls_qos_tbl_deinit(priv->qos_tbl);
-		priv->qos_tbl = NULL;
-	}
-	if (priv->ppio)
-		pp2_ppio_deinit(priv->ppio);
-	priv->ppio = NULL;
-
-	/* policer must be released after ppio deinitialization */
-	if (priv->policer) {
-		pp2_cls_plcr_deinit(priv->policer);
-		priv->policer = NULL;
-	}
 }
 
 /**
@@ -785,6 +772,9 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 	struct mrvl_priv *priv = dev->data->dev_private;
 	size_t i;
 
+	mrvl_flush_rx_queues(dev);
+	mrvl_flush_tx_shadow_queues(dev);
+
 	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
 		struct pp2_ppio_tc_params *tc_params =
 			&priv->ppio_params.inqs_params.tcs_params[i];
@@ -795,7 +785,28 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 		}
 	}
 
+	if (priv->cls_tbl) {
+		pp2_cls_tbl_deinit(priv->cls_tbl);
+		priv->cls_tbl = NULL;
+	}
+
+	if (priv->qos_tbl) {
+		pp2_cls_qos_tbl_deinit(priv->qos_tbl);
+		priv->qos_tbl = NULL;
+	}
+
 	mrvl_flush_bpool(dev);
+
+	if (priv->ppio) {
+		pp2_ppio_deinit(priv->ppio);
+		priv->ppio = NULL;
+	}
+
+	/* policer must be released after ppio deinitialization */
+	if (priv->policer) {
+		pp2_cls_plcr_deinit(priv->policer);
+		priv->policer = NULL;
+	}
 }
 
 /**
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH 2/8] net/mvpp2: move common code
  2018-09-04  7:10 [dpdk-dev] [PATCH 0/8] net/mvpp2: add new features Tomasz Duszynski
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 1/8] net/mvpp2: initialize ppio only once Tomasz Duszynski
@ 2018-09-04  7:10 ` Tomasz Duszynski
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 3/8] net/mvpp2: add metering support Tomasz Duszynski
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04  7:10 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

Cleanup sources by moving common code to the pmd
header file.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c |  9 ---------
 drivers/net/mvpp2/mrvl_ethdev.h | 11 +++++++++++
 drivers/net/mvpp2/mrvl_flow.c   |  5 -----
 drivers/net/mvpp2/mrvl_qos.c    |  9 ---------
 4 files changed, 11 insertions(+), 23 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index f022cad..adb07d0 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -10,15 +10,6 @@
 #include <rte_malloc.h>
 #include <rte_bus_vdev.h>
 
-/* Unluckily, container_of is defined by both DPDK and MUSDK,
- * we'll declare only one version.
- *
- * Note that it is not used in this PMD anyway.
- */
-#ifdef container_of
-#undef container_of
-#endif
-
 #include <fcntl.h>
 #include <linux/ethtool.h>
 #include <linux/sockios.h>
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index 3726f78..2204be2 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -10,12 +10,23 @@
 #include <rte_spinlock.h>
 #include <rte_flow_driver.h>
 
+/*
+ * container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+
 #include <env/mv_autogen_comp_flags.h>
 #include <drivers/mv_pp2.h>
 #include <drivers/mv_pp2_bpool.h>
 #include <drivers/mv_pp2_cls.h>
 #include <drivers/mv_pp2_hif.h>
 #include <drivers/mv_pp2_ppio.h>
+#include "env/mv_common.h" /* for BIT() */
 
 /** Maximum number of rx queues per port */
 #define MRVL_PP2_RXQ_MAX 32
diff --git a/drivers/net/mvpp2/mrvl_flow.c b/drivers/net/mvpp2/mrvl_flow.c
index 13295e6..db750f4 100644
--- a/drivers/net/mvpp2/mrvl_flow.c
+++ b/drivers/net/mvpp2/mrvl_flow.c
@@ -11,13 +11,8 @@
 
 #include <arpa/inet.h>
 
-#ifdef container_of
-#undef container_of
-#endif
-
 #include "mrvl_ethdev.h"
 #include "mrvl_qos.h"
-#include "env/mv_common.h" /* for BIT() */
 
 /** Number of rules in the classifier table. */
 #define MRVL_CLS_MAX_NUM_RULES 20
diff --git a/drivers/net/mvpp2/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c
index 71856c1..eeb46f8 100644
--- a/drivers/net/mvpp2/mrvl_qos.c
+++ b/drivers/net/mvpp2/mrvl_qos.c
@@ -15,15 +15,6 @@
 #include <rte_malloc.h>
 #include <rte_string_fns.h>
 
-/* Unluckily, container_of is defined by both DPDK and MUSDK,
- * we'll declare only one version.
- *
- * Note that it is not used in this PMD anyway.
- */
-#ifdef container_of
-#undef container_of
-#endif
-
 #include "mrvl_qos.h"
 
 /* Parsing tokens. Defined conveniently, so that any correction is easy. */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH 3/8] net/mvpp2: add metering support
  2018-09-04  7:10 [dpdk-dev] [PATCH 0/8] net/mvpp2: add new features Tomasz Duszynski
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 1/8] net/mvpp2: initialize ppio only once Tomasz Duszynski
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 2/8] net/mvpp2: move common code Tomasz Duszynski
@ 2018-09-04  7:10 ` Tomasz Duszynski
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 4/8] net/mvpp2: change default policer configuration Tomasz Duszynski
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04  7:10 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

Add support for configuring plcr via DPDK generic metering API.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 drivers/net/mvpp2/Makefile      |   1 +
 drivers/net/mvpp2/meson.build   |   3 +-
 drivers/net/mvpp2/mrvl_ethdev.c |  24 ++
 drivers/net/mvpp2/mrvl_ethdev.h |  71 ++++++
 drivers/net/mvpp2/mrvl_flow.c   |  91 +++----
 drivers/net/mvpp2/mrvl_mtr.c    | 512 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/mvpp2/mrvl_mtr.h    |  15 ++
 7 files changed, 673 insertions(+), 44 deletions(-)
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.c
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.h

diff --git a/drivers/net/mvpp2/Makefile b/drivers/net/mvpp2/Makefile
index 211d398..4848d65 100644
--- a/drivers/net/mvpp2/Makefile
+++ b/drivers/net/mvpp2/Makefile
@@ -39,5 +39,6 @@ LDLIBS += -lrte_bus_vdev -lrte_common_mvep
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_qos.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_mtr.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/mvpp2/meson.build b/drivers/net/mvpp2/meson.build
index 3620659..f475511 100644
--- a/drivers/net/mvpp2/meson.build
+++ b/drivers/net/mvpp2/meson.build
@@ -19,7 +19,8 @@ endif
 sources = files(
 	'mrvl_ethdev.c',
 	'mrvl_flow.c',
-	'mrvl_qos.c'
+	'mrvl_qos.c',
+	'mrvl_mtr.c'
 )
 
 deps += ['cfgfile', 'common_mvep']
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index adb07d0..a4951d3 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -23,6 +23,7 @@
 #include <rte_mvep_common.h>
 #include "mrvl_ethdev.h"
 #include "mrvl_qos.h"
+#include "mrvl_mtr.h"
 
 /* bitmask with reserved hifs */
 #define MRVL_MUSDK_HIFS_RESERVED 0x0F
@@ -627,6 +628,8 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 			goto out;
 	}
 
+	mrvl_mtr_init(dev);
+
 	return 0;
 out:
 	MRVL_LOG(ERR, "Failed to start device");
@@ -765,6 +768,7 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 
 	mrvl_flush_rx_queues(dev);
 	mrvl_flush_tx_shadow_queues(dev);
+	mrvl_mtr_deinit(dev);
 
 	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
 		struct pp2_ppio_tc_params *tc_params =
@@ -1868,6 +1872,25 @@ mrvl_eth_filter_ctrl(struct rte_eth_dev *dev __rte_unused,
 	}
 }
 
+/**
+ * DPDK callback to get rte_mtr callbacks.
+ *
+ * @param dev
+ *   Pointer to the device structure.
+ * @param ops
+ *   Pointer to pass the mtr ops.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_mtr_ops_get(struct rte_eth_dev *dev __rte_unused, void *ops)
+{
+	*(const void **)ops = &mrvl_mtr_ops;
+
+	return 0;
+}
+
 static const struct eth_dev_ops mrvl_ops = {
 	.dev_configure = mrvl_dev_configure,
 	.dev_start = mrvl_dev_start,
@@ -1905,6 +1928,7 @@ static const struct eth_dev_ops mrvl_ops = {
 	.rss_hash_update = mrvl_rss_hash_update,
 	.rss_hash_conf_get = mrvl_rss_hash_conf_get,
 	.filter_ctrl = mrvl_eth_filter_ctrl,
+	.mtr_ops_get = mrvl_mtr_ops_get,
 };
 
 /**
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index 2204be2..ecb8fdc 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -9,6 +9,7 @@
 
 #include <rte_spinlock.h>
 #include <rte_flow_driver.h>
+#include <rte_mtr_driver.h>
 
 /*
  * container_of is defined by both DPDK and MUSDK,
@@ -70,6 +71,69 @@
 /** Minimum number of sent buffers to release from shadow queue to BM */
 #define MRVL_PP2_BUF_RELEASE_BURST_SIZE	64
 
+/** Maximum length of a match string */
+#define MRVL_MATCH_LEN 16
+
+/** Parsed fields in processed rte_flow_item. */
+enum mrvl_parsed_fields {
+	/* eth flags */
+	F_DMAC =         BIT(0),
+	F_SMAC =         BIT(1),
+	F_TYPE =         BIT(2),
+	/* vlan flags */
+	F_VLAN_PRI =     BIT(3),
+	F_VLAN_ID =      BIT(4),
+	F_VLAN_TCI =     BIT(5), /* not supported by MUSDK yet */
+	/* ip4 flags */
+	F_IP4_TOS =      BIT(6),
+	F_IP4_SIP =      BIT(7),
+	F_IP4_DIP =      BIT(8),
+	F_IP4_PROTO =    BIT(9),
+	/* ip6 flags */
+	F_IP6_TC =       BIT(10), /* not supported by MUSDK yet */
+	F_IP6_SIP =      BIT(11),
+	F_IP6_DIP =      BIT(12),
+	F_IP6_FLOW =     BIT(13),
+	F_IP6_NEXT_HDR = BIT(14),
+	/* tcp flags */
+	F_TCP_SPORT =    BIT(15),
+	F_TCP_DPORT =    BIT(16),
+	/* udp flags */
+	F_UDP_SPORT =    BIT(17),
+	F_UDP_DPORT =    BIT(18),
+};
+
+/** PMD-specific definition of a flow rule handle. */
+struct mrvl_mtr;
+struct rte_flow {
+	LIST_ENTRY(rte_flow) next;
+	struct mrvl_mtr *mtr;
+
+	enum mrvl_parsed_fields pattern;
+
+	struct pp2_cls_tbl_rule rule;
+	struct pp2_cls_cos_desc cos;
+	struct pp2_cls_tbl_action action;
+};
+
+struct mrvl_mtr_profile {
+	LIST_ENTRY(mrvl_mtr_profile) next;
+	uint32_t profile_id;
+	int refcnt;
+	struct rte_mtr_meter_profile profile;
+};
+
+struct mrvl_mtr {
+	LIST_ENTRY(mrvl_mtr) next;
+	uint32_t mtr_id;
+	int refcnt;
+	int shared;
+	int enabled;
+	int plcr_bit;
+	struct mrvl_mtr_profile *profile;
+	struct pp2_cls_plcr *plcr;
+};
+
 struct mrvl_priv {
 	/* Hot fields, used in fast path. */
 	struct pp2_bpool *bpool;  /**< BPool pointer */
@@ -105,11 +169,18 @@ struct mrvl_priv {
 	LIST_HEAD(mrvl_flows, rte_flow) flows;
 
 	struct pp2_cls_plcr *policer;
+
+	LIST_HEAD(profiles, mrvl_mtr_profile) profiles;
+	LIST_HEAD(mtrs, mrvl_mtr) mtrs;
+	uint32_t used_plcrs;
 };
 
 /** Flow operations forward declaration. */
 extern const struct rte_flow_ops mrvl_flow_ops;
 
+/** Meter operations forward declaration. */
+extern const struct rte_mtr_ops mrvl_mtr_ops;
+
 /** Current log type. */
 extern int mrvl_logtype;
 
diff --git a/drivers/net/mvpp2/mrvl_flow.c b/drivers/net/mvpp2/mrvl_flow.c
index db750f4..e6953e4 100644
--- a/drivers/net/mvpp2/mrvl_flow.c
+++ b/drivers/net/mvpp2/mrvl_flow.c
@@ -20,46 +20,6 @@
 /** Size of the classifier key and mask strings. */
 #define MRVL_CLS_STR_SIZE_MAX 40
 
-/** Parsed fields in processed rte_flow_item. */
-enum mrvl_parsed_fields {
-	/* eth flags */
-	F_DMAC =         BIT(0),
-	F_SMAC =         BIT(1),
-	F_TYPE =         BIT(2),
-	/* vlan flags */
-	F_VLAN_ID =      BIT(3),
-	F_VLAN_PRI =     BIT(4),
-	F_VLAN_TCI =     BIT(5), /* not supported by MUSDK yet */
-	/* ip4 flags */
-	F_IP4_TOS =      BIT(6),
-	F_IP4_SIP =      BIT(7),
-	F_IP4_DIP =      BIT(8),
-	F_IP4_PROTO =    BIT(9),
-	/* ip6 flags */
-	F_IP6_TC =       BIT(10), /* not supported by MUSDK yet */
-	F_IP6_SIP =      BIT(11),
-	F_IP6_DIP =      BIT(12),
-	F_IP6_FLOW =     BIT(13),
-	F_IP6_NEXT_HDR = BIT(14),
-	/* tcp flags */
-	F_TCP_SPORT =    BIT(15),
-	F_TCP_DPORT =    BIT(16),
-	/* udp flags */
-	F_UDP_SPORT =    BIT(17),
-	F_UDP_DPORT =    BIT(18),
-};
-
-/** PMD-specific definition of a flow rule handle. */
-struct rte_flow {
-	LIST_ENTRY(rte_flow) next;
-
-	enum mrvl_parsed_fields pattern;
-
-	struct pp2_cls_tbl_rule rule;
-	struct pp2_cls_cos_desc cos;
-	struct pp2_cls_tbl_action action;
-};
-
 static const enum rte_flow_item_type pattern_eth[] = {
 	RTE_FLOW_ITEM_TYPE_ETH,
 	RTE_FLOW_ITEM_TYPE_END
@@ -2295,19 +2255,59 @@ mrvl_flow_parse_actions(struct mrvl_priv *priv,
 			flow->action.type = PP2_CLS_TBL_ACT_DONE;
 			flow->action.cos = &flow->cos;
 			specified++;
+		} else if (action->type == RTE_FLOW_ACTION_TYPE_METER) {
+			const struct rte_flow_action_meter *meter;
+			struct mrvl_mtr *mtr;
+
+			meter = action->conf;
+			if (!meter)
+				return -rte_flow_error_set(error, EINVAL,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL, "Invalid meter\n");
+
+			LIST_FOREACH(mtr, &priv->mtrs, next)
+				if (mtr->mtr_id == meter->mtr_id)
+					break;
+
+			if (!mtr)
+				return -rte_flow_error_set(error, EINVAL,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL,
+						"Meter id does not exist\n");
+
+			if (!mtr->shared && mtr->refcnt)
+				return -rte_flow_error_set(error, EPERM,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL,
+						"Meter cannot be shared\n");
+
+			/*
+			 * In case cos has already been set
+			 * do not modify it.
+			 */
+			if (!flow->cos.ppio) {
+				flow->cos.ppio = priv->ppio;
+				flow->cos.tc = 0;
+			}
+
+			flow->action.type = PP2_CLS_TBL_ACT_DONE;
+			flow->action.cos = &flow->cos;
+			flow->action.plcr = mtr->enabled ? mtr->plcr : NULL;
+			flow->mtr = mtr;
+			mtr->refcnt++;
+			specified++;
 		} else {
 			rte_flow_error_set(error, ENOTSUP,
 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
 					   "Action not supported");
 			return -rte_errno;
 		}
-
 	}
 
 	if (!specified) {
 		rte_flow_error_set(error, EINVAL,
-				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
-				   NULL, "Action not specified");
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Action not specified");
 		return -rte_errno;
 	}
 
@@ -2657,6 +2657,11 @@ mrvl_flow_remove(struct mrvl_priv *priv, struct rte_flow *flow,
 
 	mrvl_free_all_key_mask(&flow->rule);
 
+	if (flow->mtr) {
+		flow->mtr->refcnt--;
+		flow->mtr = NULL;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/mvpp2/mrvl_mtr.c b/drivers/net/mvpp2/mrvl_mtr.c
new file mode 100644
index 0000000..9cd53be
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_mtr.c
@@ -0,0 +1,512 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#include <rte_log.h>
+#include <rte_malloc.h>
+
+#include "mrvl_mtr.h"
+
+/** Maximum meter rate */
+#define MRVL_SRTCM_RFC2697_CIR_MAX 1023000
+
+/** Invalid plcr bit */
+#define MRVL_PLCR_BIT_INVALID -1
+
+/**
+ * Return meter object capabilities.
+ *
+ * @param dev Pointer to the device (unused).
+ * @param cap Pointer to the meter object capabilities.
+ * @param error Pointer to the error (unused).
+ * @returns 0 always.
+ */
+static int
+mrvl_capabilities_get(struct rte_eth_dev *dev __rte_unused,
+			  struct rte_mtr_capabilities *cap,
+			  struct rte_mtr_error *error __rte_unused)
+{
+	struct rte_mtr_capabilities capa = {
+		.n_max = PP2_CLS_PLCR_NUM,
+		.n_shared_max = PP2_CLS_PLCR_NUM,
+		.shared_n_flows_per_mtr_max = -1,
+		.meter_srtcm_rfc2697_n_max = PP2_CLS_PLCR_NUM,
+		.meter_rate_max = MRVL_SRTCM_RFC2697_CIR_MAX,
+	};
+
+	memcpy(cap, &capa, sizeof(capa));
+
+	return 0;
+}
+
+/**
+ * Get profile using it's id.
+ *
+ * @param priv Pointer to the port's private data.
+ * @param meter_profile_id Profile id used by the meter.
+ * @returns Pointer to the profile if exists, NULL otherwise.
+ */
+static struct mrvl_mtr_profile *
+mrvl_mtr_profile_from_id(struct mrvl_priv *priv, uint32_t meter_profile_id)
+{
+	struct mrvl_mtr_profile *profile = NULL;
+
+	LIST_FOREACH(profile, &priv->profiles, next)
+		if (profile->profile_id == meter_profile_id)
+			break;
+
+	return profile;
+}
+
+/**
+ * Add profile to the list of profiles.
+ *
+ * @param dev Pointer to the device.
+ * @param meter_profile_id Id of the new profile.
+ * @param profile Pointer to the profile configuration.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_profile_add(struct rte_eth_dev *dev, uint32_t meter_profile_id,
+		       struct rte_mtr_meter_profile *profile,
+		       struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *prof;
+
+	if (!profile)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, NULL);
+
+	if (profile->alg != RTE_MTR_SRTCM_RFC2697)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
+					  "Only srTCM RFC 2697 is supported\n");
+
+	prof = mrvl_mtr_profile_from_id(priv, meter_profile_id);
+	if (prof)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id already exists\n");
+
+	prof = rte_zmalloc_socket(NULL, sizeof(*prof), 0, rte_socket_id());
+	if (!prof)
+		return -rte_mtr_error_set(error, ENOMEM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, NULL);
+
+	prof->profile_id = meter_profile_id;
+	memcpy(&prof->profile, profile, sizeof(*profile));
+
+	LIST_INSERT_HEAD(&priv->profiles, prof, next);
+
+	return 0;
+}
+
+/**
+ * Remove profile from the list of profiles.
+ *
+ * @param dev Pointer to the device.
+ * @param meter_profile_id Id of the profile to remove.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_profile_delete(struct rte_eth_dev *dev,
+			      uint32_t meter_profile_id,
+			      struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile;
+
+	profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
+	if (!profile)
+		return -rte_mtr_error_set(error, ENODEV,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id does not exist\n");
+
+	if (profile->refcnt)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile is used\n");
+
+	LIST_REMOVE(profile, next);
+	rte_free(profile);
+
+	return 0;
+}
+
+/**
+ * Get meter using it's id.
+ *
+ * @param priv Pointer to port's private data.
+ * @param mtr_id Id of the meter.
+ * @returns Pointer to the meter if exists, NULL otherwise.
+ */
+static struct mrvl_mtr *
+mrvl_mtr_from_id(struct mrvl_priv *priv, uint32_t mtr_id)
+{
+	struct mrvl_mtr *mtr = NULL;
+
+	LIST_FOREACH(mtr, &priv->mtrs, next)
+		if (mtr->mtr_id == mtr_id)
+			break;
+
+	return mtr;
+}
+
+/**
+ * Reserve a policer bit in a bitmap.
+ *
+ * @param plcrs Pointer to the policers bitmap.
+ * @returns Reserved bit number on success, negative value otherwise.
+ */
+static int
+mrvl_reserve_plcr(uint32_t *plcrs)
+{
+	uint32_t i, num;
+
+	num = PP2_CLS_PLCR_NUM;
+	if (num > sizeof(uint32_t) * 8) {
+		num = sizeof(uint32_t) * 8;
+		MRVL_LOG(WARNING, "Plcrs number was limited to 32.");
+	}
+
+	for (i = 0; i < num; i++) {
+		uint32_t bit = BIT(i);
+
+		if (!(*plcrs & bit)) {
+			*plcrs |= bit;
+
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+/**
+ * Enable meter object.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter.
+ * @param error Pointer to the error.
+ * @returns 0 in success, negative value otherwise.
+ */
+static int
+mrvl_meter_enable(struct rte_eth_dev *dev, uint32_t mtr_id,
+		  struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
+	struct pp2_cls_plcr_params params;
+	char match[MRVL_MATCH_LEN];
+	struct rte_flow *flow;
+	int ret;
+
+	if (!priv->ppio)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Port is uninitialized\n");
+
+	if (!mtr)
+		return -rte_mtr_error_set(error, ENODEV,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	if (mtr->plcr)
+		goto skip;
+
+	mtr->plcr_bit = mrvl_reserve_plcr(&priv->used_plcrs);
+	if (mtr->plcr_bit < 0)
+		return -rte_mtr_error_set(error, ENOSPC,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
+					  "Failed to reserve plcr entry\n");
+
+	memset(&params, 0, sizeof(params));
+	snprintf(match, sizeof(match), "policer-%d:%d", priv->pp_id,
+		 mtr->plcr_bit);
+	params.match = match;
+	params.token_unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
+	params.color_mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
+	params.cir = mtr->profile->profile.srtcm_rfc2697.cir;
+	params.cbs = mtr->profile->profile.srtcm_rfc2697.cbs;
+	params.ebs = mtr->profile->profile.srtcm_rfc2697.ebs;
+
+	ret = pp2_cls_plcr_init(&params, &mtr->plcr);
+	if (ret) {
+		priv->used_plcrs &= ~BIT(mtr->plcr_bit);
+		mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
+
+		return -rte_mtr_error_set(error, -ret,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Failed to setup policer\n");
+	}
+
+	mtr->enabled = 1;
+skip:
+	/* iterate over flows that have this mtr attached */
+	LIST_FOREACH(flow, &priv->flows, next) {
+		if (flow->mtr != mtr)
+			continue;
+
+		flow->action.plcr = mtr->plcr;
+
+		ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
+					      &flow->action);
+		if (ret)
+			return -rte_mtr_error_set(error, -ret,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Failed to update cls rule\n");
+	}
+
+	return 0;
+}
+
+/**
+ * Disable meter object.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr Id of the meter.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_disable(struct rte_eth_dev *dev, uint32_t mtr_id,
+		       struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
+	struct rte_flow *flow;
+	int ret;
+
+	if (!mtr)
+		return -rte_mtr_error_set(error, ENODEV,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	LIST_FOREACH(flow, &priv->flows, next) {
+		if (flow->mtr != mtr)
+			continue;
+
+		flow->action.plcr = NULL;
+
+		ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
+					      &flow->action);
+		if (ret)
+			return -rte_mtr_error_set(error, -ret,
+					RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					NULL, "Failed to disable meter\n");
+	}
+
+	mtr->enabled = 0;
+
+	return 0;
+}
+
+/**
+ * Create new meter.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter.
+ * @param params Pointer to the meter parameters.
+ * @param shared Flags indicating whether meter is shared.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_create(struct rte_eth_dev *dev, uint32_t mtr_id,
+	    struct rte_mtr_params *params, int shared,
+	    struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile;
+	struct mrvl_mtr *mtr;
+
+	mtr = mrvl_mtr_from_id(priv, mtr_id);
+	if (mtr)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id already exists\n");
+
+	mtr = rte_zmalloc_socket(NULL, sizeof(*mtr), 0, rte_socket_id());
+	if (!mtr)
+		return -rte_mtr_error_set(error, ENOMEM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, NULL);
+
+	profile = mrvl_mtr_profile_from_id(priv, params->meter_profile_id);
+	if (!profile)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id does not exist\n");
+
+	mtr->shared = shared;
+	mtr->mtr_id = mtr_id;
+	mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
+	mtr->profile = profile;
+	profile->refcnt++;
+	LIST_INSERT_HEAD(&priv->mtrs, mtr, next);
+
+	if (params->meter_enable)
+		return mrvl_meter_enable(dev, mtr_id, error);
+
+	return 0;
+}
+
+/**
+ * Destroy meter object.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter object.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_destroy(struct rte_eth_dev *dev, uint32_t mtr_id,
+		 struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr *mtr;
+
+	if (!priv->ppio)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Port is uninitialized\n");
+
+	mtr = mrvl_mtr_from_id(priv, mtr_id);
+	if (!mtr)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	if (mtr->refcnt)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter is used\n");
+
+	LIST_REMOVE(mtr, next);
+	mtr->profile->refcnt--;
+
+	if (mtr->plcr_bit != MRVL_PLCR_BIT_INVALID)
+		priv->used_plcrs &= ~BIT(mtr->plcr_bit);
+
+	if (mtr->plcr)
+		pp2_cls_plcr_deinit(mtr->plcr);
+
+	rte_free(mtr);
+
+	return 0;
+}
+
+/**
+ * Update profile used by the meter.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter object.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_profile_update(struct rte_eth_dev *dev, uint32_t mtr_id,
+			  uint32_t meter_profile_id,
+			  struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile;
+	struct mrvl_mtr *mtr;
+	int ret, enabled;
+
+	if (!priv->ppio)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Port is uninitialized\n");
+
+	mtr = mrvl_mtr_from_id(priv, mtr_id);
+	if (!mtr)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
+	if (!profile)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id does not exist\n");
+
+	ret = mrvl_meter_disable(dev, mtr_id, error);
+	if (ret)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  NULL);
+
+	if (mtr->plcr) {
+		enabled = 1;
+		pp2_cls_plcr_deinit(mtr->plcr);
+		mtr->plcr = NULL;
+	}
+
+	mtr->profile->refcnt--;
+	mtr->profile = profile;
+	profile->refcnt++;
+
+	if (enabled)
+		return mrvl_meter_enable(dev, mtr_id, error);
+
+	return 0;
+}
+
+const struct rte_mtr_ops mrvl_mtr_ops = {
+	.capabilities_get = mrvl_capabilities_get,
+	.meter_profile_add = mrvl_meter_profile_add,
+	.meter_profile_delete = mrvl_meter_profile_delete,
+	.create = mrvl_create,
+	.destroy = mrvl_destroy,
+	.meter_enable = mrvl_meter_enable,
+	.meter_disable = mrvl_meter_disable,
+	.meter_profile_update = mrvl_meter_profile_update,
+};
+
+/**
+ * Initialize metering resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_mtr_init(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	LIST_INIT(&priv->profiles);
+	LIST_INIT(&priv->mtrs);
+}
+
+/**
+ * Cleanup metering resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_mtr_deinit(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile, *tmp_profile;
+	struct mrvl_mtr *mtr, *tmp_mtr;
+
+	for (mtr = LIST_FIRST(&priv->mtrs);
+	     mtr && (tmp_mtr = LIST_NEXT(mtr, next), 1);
+	     mtr = tmp_mtr)
+		mrvl_destroy(dev, mtr->mtr_id, NULL);
+
+	for (profile = LIST_FIRST(&priv->profiles);
+	     profile && (tmp_profile = LIST_NEXT(profile, next), 1);
+	     profile = tmp_profile)
+		mrvl_meter_profile_delete(dev, profile->profile_id, NULL);
+}
diff --git a/drivers/net/mvpp2/mrvl_mtr.h b/drivers/net/mvpp2/mrvl_mtr.h
new file mode 100644
index 0000000..302a20f
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_mtr.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#ifndef _MRVL_MTR_H_
+#define _MRVL_MTR_H_
+
+#include "mrvl_ethdev.h"
+
+void mrvl_mtr_init(struct rte_eth_dev *dev);
+void mrvl_mtr_deinit(struct rte_eth_dev *dev);
+
+#endif /* _MRVL_MTR_H_ */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH 4/8] net/mvpp2: change default policer configuration
  2018-09-04  7:10 [dpdk-dev] [PATCH 0/8] net/mvpp2: add new features Tomasz Duszynski
                   ` (2 preceding siblings ...)
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 3/8] net/mvpp2: add metering support Tomasz Duszynski
@ 2018-09-04  7:10 ` Tomasz Duszynski
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 5/8] net/mvpp2: add init and deinit to flow Tomasz Duszynski
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04  7:10 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

Change QoS configuration file syntax for port's default policer
setup.

Since default policer configuration is performed before
any other policer configuration we can pick a default id.

This simplifies default policer configuration since user
no longer has to choose ids from range [0, PP2_CLS_PLCR_NUM].

Explicitly document values for rate_limit_enable field.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 doc/guides/nics/mvpp2.rst       |  31 ++++---
 drivers/net/mvpp2/mrvl_ethdev.c |   6 +-
 drivers/net/mvpp2/mrvl_ethdev.h |   2 +-
 drivers/net/mvpp2/mrvl_qos.c    | 198 ++++++++++++++++++++++------------------
 drivers/net/mvpp2/mrvl_qos.h    |   2 +-
 5 files changed, 134 insertions(+), 105 deletions(-)

diff --git a/doc/guides/nics/mvpp2.rst b/doc/guides/nics/mvpp2.rst
index 0408752..a452c8a 100644
--- a/doc/guides/nics/mvpp2.rst
+++ b/doc/guides/nics/mvpp2.rst
@@ -152,20 +152,23 @@ Configuration syntax
 
 .. code-block:: console
 
-   [port <portnum> default]
-   default_tc = <default_tc>
-   mapping_priority = <mapping_priority>
-   policer_enable = <policer_enable>
+   [policer <policer_id>]
    token_unit = <token_unit>
    color = <color_mode>
    cir = <cir>
    ebs = <ebs>
    cbs = <cbs>
 
+   [port <portnum> default]
+   default_tc = <default_tc>
+   mapping_priority = <mapping_priority>
+
    rate_limit_enable = <rate_limit_enable>
    rate_limit = <rate_limit>
    burst_size = <burst_size>
 
+   default_policer = <policer_id>
+
    [port <portnum> tc <traffic_class>]
    rxq = <rx_queue_list>
    pcp = <pcp_list>
@@ -201,7 +204,9 @@ Where:
 
 - ``<dscp_list>``: List of DSCP values to handle in particular TC (e.g. 0-12 32-48 63).
 
-- ``<policer_enable>``: Enable ingress policer.
+- ``<default_policer>``: Id of the policer configuration section to be used as default.
+
+- ``<policer_id>``: Id of the policer configuration section (0..31).
 
 - ``<token_unit>``: Policer token unit (`bytes` or `packets`).
 
@@ -215,7 +220,7 @@ Where:
 
 - ``<default_color>``: Default color for specific tc.
 
-- ``<rate_limit_enable>``: Enables per port or per txq rate limiting.
+- ``<rate_limit_enable>``: Enables per port or per txq rate limiting (`0`/`1` to disable/enable).
 
 - ``<rate_limit>``: Committed information rate, in kilo bits per second.
 
@@ -234,6 +239,13 @@ Configuration file example
 
 .. code-block:: console
 
+   [policer 0]
+   token_unit = bytes
+   color = blind
+   cir = 100000
+   ebs = 64
+   cbs = 64
+
    [port 0 default]
    default_tc = 0
    mapping_priority = ip
@@ -265,12 +277,7 @@ Configuration file example
    default_tc = 0
    mapping_priority = vlan/ip
 
-   policer_enable = 1
-   token_unit = bytes
-   color = blind
-   cir = 100000
-   ebs = 64
-   cbs = 64
+   default_policer = 0
 
    [port 1 tc 0]
    rxq = 0
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index a4951d3..1464385 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -798,9 +798,9 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 	}
 
 	/* policer must be released after ppio deinitialization */
-	if (priv->policer) {
-		pp2_cls_plcr_deinit(priv->policer);
-		priv->policer = NULL;
+	if (priv->default_policer) {
+		pp2_cls_plcr_deinit(priv->default_policer);
+		priv->default_policer = NULL;
 	}
 }
 
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index ecb8fdc..de423a9 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -168,7 +168,7 @@ struct mrvl_priv {
 	uint32_t cls_tbl_pattern;
 	LIST_HEAD(mrvl_flows, rte_flow) flows;
 
-	struct pp2_cls_plcr *policer;
+	struct pp2_cls_plcr *default_policer;
 
 	LIST_HEAD(profiles, mrvl_mtr_profile) profiles;
 	LIST_HEAD(mtrs, mrvl_mtr) mtrs;
diff --git a/drivers/net/mvpp2/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c
index eeb46f8..e039635 100644
--- a/drivers/net/mvpp2/mrvl_qos.c
+++ b/drivers/net/mvpp2/mrvl_qos.c
@@ -42,7 +42,8 @@
 #define MRVL_TOK_WRR_WEIGHT "wrr_weight"
 
 /* policer specific configuration tokens */
-#define MRVL_TOK_PLCR_ENABLE "policer_enable"
+#define MRVL_TOK_PLCR "policer"
+#define MRVL_TOK_PLCR_DEFAULT "default_policer"
 #define MRVL_TOK_PLCR_UNIT "token_unit"
 #define MRVL_TOK_PLCR_UNIT_BYTES "bytes"
 #define MRVL_TOK_PLCR_UNIT_PACKETS "packets"
@@ -368,6 +369,9 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
 		cfg->port[port].tc[tc].dscps = n;
 	}
 
+	if (!cfg->port[port].setup_policer)
+		return 0;
+
 	entry = rte_cfgfile_get_entry(file, sec_name,
 			MRVL_TOK_PLCR_DEFAULT_COLOR);
 	if (entry) {
@@ -390,6 +394,85 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
 }
 
 /**
+ * Parse default port policer.
+ *
+ * @param file Config file handle.
+ * @param sec_name Section name with policer configuration
+ * @param port Port number.
+ * @param cfg[out] Parsing results.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
+		struct mrvl_qos_cfg *cfg)
+{
+	const char *entry;
+	uint32_t val;
+
+	/* Read policer token unit */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_UNIT);
+	if (entry) {
+		if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
+					sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
+			cfg->port[port].policer_params.token_unit =
+				PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
+		} else if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_PACKETS,
+					sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
+			cfg->port[port].policer_params.token_unit =
+				PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
+		} else {
+			RTE_LOG(ERR, PMD, "Unknown token: %s\n", entry);
+			return -1;
+		}
+	}
+
+	/* Read policer color mode */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_COLOR);
+	if (entry) {
+		if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
+					sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
+			cfg->port[port].policer_params.color_mode =
+				PP2_CLS_PLCR_COLOR_BLIND_MODE;
+		} else if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_AWARE,
+					sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
+			cfg->port[port].policer_params.color_mode =
+				PP2_CLS_PLCR_COLOR_AWARE_MODE;
+		} else {
+			RTE_LOG(ERR, PMD, "Error in parsing: %s\n", entry);
+			return -1;
+		}
+	}
+
+	/* Read policer cir */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CIR);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].policer_params.cir = val;
+	}
+
+	/* Read policer cbs */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CBS);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].policer_params.cbs = val;
+	}
+
+	/* Read policer ebs */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_EBS);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].policer_params.ebs = val;
+	}
+
+	cfg->port[port].setup_policer = 1;
+
+	return 0;
+}
+
+/**
  * Parse QoS configuration - rte_kvargs_process handler.
  *
  * Opens configuration file and parses its content.
@@ -457,88 +540,6 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 			return -1;
 		}
 
-		entry = rte_cfgfile_get_entry(file, sec_name,
-				MRVL_TOK_PLCR_ENABLE);
-		if (entry) {
-			if (get_val_securely(entry, &val) < 0)
-				return -1;
-			(*cfg)->port[n].policer_enable = val;
-		}
-
-		if ((*cfg)->port[n].policer_enable) {
-			enum pp2_cls_plcr_token_unit unit;
-
-			/* Read policer token unit */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_UNIT);
-			if (entry) {
-				if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
-					sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
-					unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
-				} else if (!strncmp(entry,
-						MRVL_TOK_PLCR_UNIT_PACKETS,
-					sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
-					unit = PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
-				} else {
-					MRVL_LOG(ERR, "Unknown token: %s",
-						entry);
-					return -1;
-				}
-				(*cfg)->port[n].policer_params.token_unit =
-					unit;
-			}
-
-			/* Read policer color mode */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_COLOR);
-			if (entry) {
-				enum pp2_cls_plcr_color_mode mode;
-
-				if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
-					sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
-					mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
-				} else if (!strncmp(entry,
-						MRVL_TOK_PLCR_COLOR_AWARE,
-					sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
-					mode = PP2_CLS_PLCR_COLOR_AWARE_MODE;
-				} else {
-					MRVL_LOG(ERR,
-						"Error in parsing: %s",
-						entry);
-					return -1;
-				}
-				(*cfg)->port[n].policer_params.color_mode =
-					mode;
-			}
-
-			/* Read policer cir */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_CIR);
-			if (entry) {
-				if (get_val_securely(entry, &val) < 0)
-					return -1;
-				(*cfg)->port[n].policer_params.cir = val;
-			}
-
-			/* Read policer cbs */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_CBS);
-			if (entry) {
-				if (get_val_securely(entry, &val) < 0)
-					return -1;
-				(*cfg)->port[n].policer_params.cbs = val;
-			}
-
-			/* Read policer ebs */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_EBS);
-			if (entry) {
-				if (get_val_securely(entry, &val) < 0)
-					return -1;
-				(*cfg)->port[n].policer_params.ebs = val;
-			}
-		}
-
 		/*
 		 * Read per-port rate limiting. Setting that will
 		 * disable per-queue rate limiting.
@@ -597,6 +598,20 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
 		}
 
+		/* Parse policer configuration (if any) */
+		entry = rte_cfgfile_get_entry(file, sec_name,
+				MRVL_TOK_PLCR_DEFAULT);
+		if (entry) {
+			if (get_val_securely(entry, &val) < 0)
+				return -1;
+
+			snprintf(sec_name, sizeof(sec_name), "%s %d",
+					MRVL_TOK_PLCR, val);
+			ret = parse_policer(file, n, sec_name, *cfg);
+			if (ret)
+				return -1;
+		}
+
 		for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
 			ret = get_outq_cfg(file, n, i, *cfg);
 			if (ret < 0)
@@ -659,6 +674,7 @@ setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
  *
  * @param priv Port's private data.
  * @param params Pointer to the policer's configuration.
+ * @param plcr_id Policer id.
  * @returns 0 in case of success, negative values otherwise.
  */
 static int
@@ -667,17 +683,23 @@ setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
 	char match[16];
 	int ret;
 
-	snprintf(match, sizeof(match), "policer-%d:%d\n",
-			priv->pp_id, priv->ppio_id);
+	/*
+	 * At this point no other policers are used which means
+	 * any policer can be picked up and used as a default one.
+	 *
+	 * Lets use 0th then.
+	 */
+	sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
 	params->match = match;
 
-	ret = pp2_cls_plcr_init(params, &priv->policer);
+	ret = pp2_cls_plcr_init(params, &priv->default_policer);
 	if (ret) {
 		MRVL_LOG(ERR, "Failed to setup %s", match);
 		return -1;
 	}
 
-	priv->ppio_params.inqs_params.plcr = priv->policer;
+	priv->ppio_params.inqs_params.plcr = priv->default_policer;
+	priv->used_plcrs = BIT(0);
 
 	return 0;
 }
@@ -809,7 +831,7 @@ mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
 
 	priv->ppio_params.inqs_params.num_tcs = i;
 
-	if (port_cfg->policer_enable)
+	if (port_cfg->setup_policer)
 		return setup_policer(priv, &port_cfg->policer_params);
 
 	return 0;
diff --git a/drivers/net/mvpp2/mrvl_qos.h b/drivers/net/mvpp2/mrvl_qos.h
index fa9ddec..f03e773 100644
--- a/drivers/net/mvpp2/mrvl_qos.h
+++ b/drivers/net/mvpp2/mrvl_qos.h
@@ -43,7 +43,7 @@ struct mrvl_qos_cfg {
 		uint8_t default_tc;
 		uint8_t use_global_defaults;
 		struct pp2_cls_plcr_params policer_params;
-		uint8_t policer_enable;
+		uint8_t setup_policer;
 	} port[RTE_MAX_ETHPORTS];
 };
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH 5/8] net/mvpp2: add init and deinit to flow
  2018-09-04  7:10 [dpdk-dev] [PATCH 0/8] net/mvpp2: add new features Tomasz Duszynski
                   ` (3 preceding siblings ...)
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 4/8] net/mvpp2: change default policer configuration Tomasz Duszynski
@ 2018-09-04  7:10 ` Tomasz Duszynski
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 6/8] net/mvpp2: add traffic manager support Tomasz Duszynski
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04  7:10 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

Add init and deinit functionality to flow implementation.

Init puts structures used by flow in a sane sate.
Deinit deallocates all resources used by flow.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
Reviewed-by: Shlomi Gridish <sgridish@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c |  3 +++
 drivers/net/mvpp2/mrvl_flow.c   | 33 ++++++++++++++++++++++++++++++++-
 drivers/net/mvpp2/mrvl_flow.h   | 15 +++++++++++++++
 3 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/mvpp2/mrvl_flow.h

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 1464385..5e3a106 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -23,6 +23,7 @@
 #include <rte_mvep_common.h>
 #include "mrvl_ethdev.h"
 #include "mrvl_qos.h"
+#include "mrvl_flow.h"
 #include "mrvl_mtr.h"
 
 /* bitmask with reserved hifs */
@@ -628,6 +629,7 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 			goto out;
 	}
 
+	mrvl_flow_init(dev);
 	mrvl_mtr_init(dev);
 
 	return 0;
@@ -768,6 +770,7 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 
 	mrvl_flush_rx_queues(dev);
 	mrvl_flush_tx_shadow_queues(dev);
+	mrvl_flow_deinit(dev);
 	mrvl_mtr_deinit(dev);
 
 	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
diff --git a/drivers/net/mvpp2/mrvl_flow.c b/drivers/net/mvpp2/mrvl_flow.c
index e6953e4..065b1aa 100644
--- a/drivers/net/mvpp2/mrvl_flow.c
+++ b/drivers/net/mvpp2/mrvl_flow.c
@@ -11,7 +11,7 @@
 
 #include <arpa/inet.h>
 
-#include "mrvl_ethdev.h"
+#include "mrvl_flow.h"
 #include "mrvl_qos.h"
 
 /** Number of rules in the classifier table. */
@@ -2790,3 +2790,34 @@ const struct rte_flow_ops mrvl_flow_ops = {
 	.flush = mrvl_flow_flush,
 	.isolate = mrvl_flow_isolate
 };
+
+/**
+ * Initialize flow resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_flow_init(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	LIST_INIT(&priv->flows);
+}
+
+/**
+ * Cleanup flow resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_flow_deinit(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	mrvl_flow_flush(dev, NULL);
+
+	if (priv->cls_tbl) {
+		pp2_cls_tbl_deinit(priv->cls_tbl);
+		priv->cls_tbl = NULL;
+	}
+}
diff --git a/drivers/net/mvpp2/mrvl_flow.h b/drivers/net/mvpp2/mrvl_flow.h
new file mode 100644
index 0000000..f63747c
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_flow.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#ifndef _MRVL_FLOW_H_
+#define _MRVL_FLOW_H_
+
+#include "mrvl_ethdev.h"
+
+void mrvl_flow_init(struct rte_eth_dev *dev);
+void mrvl_flow_deinit(struct rte_eth_dev *dev);
+
+#endif /* _MRVL_FLOW_H_ */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH 6/8] net/mvpp2: add traffic manager support
  2018-09-04  7:10 [dpdk-dev] [PATCH 0/8] net/mvpp2: add new features Tomasz Duszynski
                   ` (4 preceding siblings ...)
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 5/8] net/mvpp2: add init and deinit to flow Tomasz Duszynski
@ 2018-09-04  7:10 ` Tomasz Duszynski
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 7/8] net/mvpp2: detach tx_qos from rx cls/qos config Tomasz Duszynski
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04  7:10 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

Add traffic manager support.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 drivers/net/mvpp2/Makefile      |    1 +
 drivers/net/mvpp2/meson.build   |    3 +-
 drivers/net/mvpp2/mrvl_ethdev.c |   26 +
 drivers/net/mvpp2/mrvl_ethdev.h |   31 ++
 drivers/net/mvpp2/mrvl_tm.c     | 1009 +++++++++++++++++++++++++++++++++++++++
 drivers/net/mvpp2/mrvl_tm.h     |   15 +
 6 files changed, 1084 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/mvpp2/mrvl_tm.c
 create mode 100644 drivers/net/mvpp2/mrvl_tm.h

diff --git a/drivers/net/mvpp2/Makefile b/drivers/net/mvpp2/Makefile
index 4848d65..661d2cd 100644
--- a/drivers/net/mvpp2/Makefile
+++ b/drivers/net/mvpp2/Makefile
@@ -40,5 +40,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_qos.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_mtr.c
+SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_tm.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/mvpp2/meson.build b/drivers/net/mvpp2/meson.build
index f475511..70ef2d6 100644
--- a/drivers/net/mvpp2/meson.build
+++ b/drivers/net/mvpp2/meson.build
@@ -20,7 +20,8 @@ sources = files(
 	'mrvl_ethdev.c',
 	'mrvl_flow.c',
 	'mrvl_qos.c',
-	'mrvl_mtr.c'
+	'mrvl_mtr.c',
+	'mrvl_tm.c'
 )
 
 deps += ['cfgfile', 'common_mvep']
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 5e3a106..a1dc6b1 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -25,6 +25,7 @@
 #include "mrvl_qos.h"
 #include "mrvl_flow.h"
 #include "mrvl_mtr.h"
+#include "mrvl_tm.h"
 
 /* bitmask with reserved hifs */
 #define MRVL_MUSDK_HIFS_RESERVED 0x0F
@@ -340,6 +341,10 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 	priv->ppio_params.maintain_stats = 1;
 	priv->nb_rx_queues = dev->data->nb_rx_queues;
 
+	ret = mrvl_tm_init(dev);
+	if (ret < 0)
+		return ret;
+
 	if (dev->data->nb_rx_queues == 1 &&
 	    dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_RSS) {
 		MRVL_LOG(WARNING, "Disabling hash for 1 rx queue");
@@ -794,6 +799,7 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 	}
 
 	mrvl_flush_bpool(dev);
+	mrvl_tm_deinit(dev);
 
 	if (priv->ppio) {
 		pp2_ppio_deinit(priv->ppio);
@@ -1894,6 +1900,25 @@ mrvl_mtr_ops_get(struct rte_eth_dev *dev __rte_unused, void *ops)
 	return 0;
 }
 
+/**
+ * DPDK callback to get rte_tm callbacks.
+ *
+ * @param dev
+ *   Pointer to the device structure.
+ * @param ops
+ *   Pointer to pass the tm ops.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *ops)
+{
+	*(const void **)ops = &mrvl_tm_ops;
+
+	return 0;
+}
+
 static const struct eth_dev_ops mrvl_ops = {
 	.dev_configure = mrvl_dev_configure,
 	.dev_start = mrvl_dev_start,
@@ -1932,6 +1957,7 @@ static const struct eth_dev_ops mrvl_ops = {
 	.rss_hash_conf_get = mrvl_rss_hash_conf_get,
 	.filter_ctrl = mrvl_eth_filter_ctrl,
 	.mtr_ops_get = mrvl_mtr_ops_get,
+	.tm_ops_get = mrvl_tm_ops_get,
 };
 
 /**
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index de423a9..984f31e 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -10,6 +10,7 @@
 #include <rte_spinlock.h>
 #include <rte_flow_driver.h>
 #include <rte_mtr_driver.h>
+#include <rte_tm_driver.h>
 
 /*
  * container_of is defined by both DPDK and MUSDK,
@@ -134,6 +135,29 @@ struct mrvl_mtr {
 	struct pp2_cls_plcr *plcr;
 };
 
+struct mrvl_tm_shaper_profile {
+	LIST_ENTRY(mrvl_tm_shaper_profile) next;
+	uint32_t id;
+	int refcnt;
+	struct rte_tm_shaper_params params;
+};
+
+enum {
+	MRVL_NODE_PORT,
+	MRVL_NODE_QUEUE,
+};
+
+struct mrvl_tm_node {
+	LIST_ENTRY(mrvl_tm_node) next;
+	uint32_t id;
+	uint32_t type;
+	int refcnt;
+	struct mrvl_tm_node *parent;
+	struct mrvl_tm_shaper_profile *profile;
+	uint8_t weight;
+	uint64_t stats_mask;
+};
+
 struct mrvl_priv {
 	/* Hot fields, used in fast path. */
 	struct pp2_bpool *bpool;  /**< BPool pointer */
@@ -173,6 +197,10 @@ struct mrvl_priv {
 	LIST_HEAD(profiles, mrvl_mtr_profile) profiles;
 	LIST_HEAD(mtrs, mrvl_mtr) mtrs;
 	uint32_t used_plcrs;
+
+	LIST_HEAD(shaper_profiles, mrvl_tm_shaper_profile) shaper_profiles;
+	LIST_HEAD(nodes, mrvl_tm_node) nodes;
+	uint64_t rate_max;
 };
 
 /** Flow operations forward declaration. */
@@ -181,6 +209,9 @@ extern const struct rte_flow_ops mrvl_flow_ops;
 /** Meter operations forward declaration. */
 extern const struct rte_mtr_ops mrvl_mtr_ops;
 
+/** Traffic manager operations forward declaration. */
+extern const struct rte_tm_ops mrvl_tm_ops;
+
 /** Current log type. */
 extern int mrvl_logtype;
 
diff --git a/drivers/net/mvpp2/mrvl_tm.c b/drivers/net/mvpp2/mrvl_tm.c
new file mode 100644
index 0000000..3de8997
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_tm.c
@@ -0,0 +1,1009 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#include <rte_malloc.h>
+
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "mrvl_tm.h"
+
+/** Minimum rate value in Bytes/s */
+#define MRVL_RATE_MIN (PP2_PPIO_MIN_CIR * 1000 / 8)
+
+/** Minimum burst size in Bytes */
+#define MRVL_BURST_MIN (PP2_PPIO_MIN_CBS * 1000)
+
+/** Maximum burst size in Bytes */
+#define MRVL_BURST_MAX 256000000
+
+/** Maximum WRR weight */
+#define MRVL_WEIGHT_MAX 255
+
+/**
+ * Get maximum port rate in Bytes/s.
+ *
+ * @param dev Pointer to the device.
+ * @param rate Pointer to the rate.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_get_max_rate(struct rte_eth_dev *dev, uint64_t *rate)
+{
+	struct ethtool_cmd edata;
+	struct ifreq req;
+	int ret, fd;
+
+	memset(&edata, 0, sizeof(edata));
+	memset(&req, 0, sizeof(req));
+	edata.cmd = ETHTOOL_GSET;
+	strcpy(req.ifr_name, dev->data->name);
+	req.ifr_data = (void *)&edata;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd == -1)
+		return -1;
+
+	ret = ioctl(fd, SIOCETHTOOL, &req);
+	if (ret == -1) {
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+
+	*rate = ethtool_cmd_speed(&edata) * 1000 * 1000 / 8;
+
+	return 0;
+}
+
+/**
+ * Initialize traffic manager related data.
+ *
+ * @param dev Pointer to the device.
+ * @returns 0 on success, failure otherwise.
+ */
+int
+mrvl_tm_init(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	LIST_INIT(&priv->shaper_profiles);
+	LIST_INIT(&priv->nodes);
+
+	if (priv->rate_max)
+		return 0;
+
+	return mrvl_get_max_rate(dev, &priv->rate_max);
+}
+
+/**
+ * Cleanup traffic manager related data.
+ *
+ * @param dev Pointer to the device.
+ */
+void mrvl_tm_deinit(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile =
+		LIST_FIRST(&priv->shaper_profiles);
+	struct mrvl_tm_node *node = LIST_FIRST(&priv->nodes);
+
+	while (profile) {
+		struct mrvl_tm_shaper_profile *next = LIST_NEXT(profile, next);
+
+		LIST_REMOVE(profile, next);
+		rte_free(profile);
+		profile = next;
+	}
+
+	while (node) {
+		struct mrvl_tm_node *next = LIST_NEXT(node, next);
+
+		LIST_REMOVE(node, next);
+		rte_free(node);
+		node = next;
+	}
+}
+
+/**
+ * Get node using its id.
+ *
+ * @param priv Pointer to the port's private data.
+ * @param node_id Id used by this node.
+ * @returns Pointer to the node if exists, NULL otherwise.
+ */
+static struct mrvl_tm_node *
+mrvl_node_from_id(struct mrvl_priv *priv, uint32_t node_id)
+{
+	struct mrvl_tm_node *node;
+
+	LIST_FOREACH(node, &priv->nodes, next)
+		if (node->id == node_id)
+			return node;
+
+	return NULL;
+}
+
+/**
+ * Check whether node is leaf or root.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id used by this node.
+ * @param is_leaf Pointer to flag indicating whether node is a leaf.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_type_get(struct rte_eth_dev *dev, uint32_t node_id, int *is_leaf,
+		   struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	if (!is_leaf)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	*is_leaf = node->type == MRVL_NODE_QUEUE ? 1 : 0;
+
+	return 0;
+}
+
+/**
+ * Get traffic manager capabilities.
+ *
+ * @param dev Pointer to the device (unused).
+ * @param cap Pointer to the capabilities.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_capabilities_get(struct rte_eth_dev *dev,
+		      struct rte_tm_capabilities *cap,
+		      struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	if (!cap)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Capabilities are missing\n");
+
+	memset(cap, 0, sizeof(*cap));
+
+	cap->n_nodes_max = 1 + dev->data->nb_tx_queues; /* port + txqs number */
+	cap->n_levels_max = 2; /* port level + txqs level */
+	cap->non_leaf_nodes_identical = 1;
+	cap->leaf_nodes_identical = 1;
+
+	cap->shaper_n_max = cap->n_nodes_max;
+	cap->shaper_private_n_max = cap->shaper_n_max;
+	cap->shaper_private_rate_min = MRVL_RATE_MIN;
+	cap->shaper_private_rate_max = priv->rate_max;
+
+	cap->sched_n_children_max = dev->data->nb_tx_queues;
+	cap->sched_sp_n_priorities_max = dev->data->nb_tx_queues;
+	cap->sched_wfq_n_children_per_group_max = dev->data->nb_tx_queues;
+	cap->sched_wfq_n_groups_max = 1;
+	cap->sched_wfq_weight_max = MRVL_WEIGHT_MAX;
+
+	cap->dynamic_update_mask = RTE_TM_UPDATE_NODE_SUSPEND_RESUME |
+				   RTE_TM_UPDATE_NODE_STATS;
+	cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
+
+	return 0;
+}
+
+/**
+ * Get traffic manager hierarchy level capabilities.
+ *
+ * @param dev Pointer to the device.
+ * @param level_id Id of the level.
+ * @param cap Pointer to the level capabilities.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_level_capabilities_get(struct rte_eth_dev *dev,
+			    uint32_t level_id,
+			    struct rte_tm_level_capabilities *cap,
+			    struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	if (!cap)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	memset(cap, 0, sizeof(*cap));
+
+	if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_LEVEL_ID,
+					 NULL, "Wrong level id\n");
+
+	if (level_id == MRVL_NODE_PORT) {
+		cap->n_nodes_max = 1;
+		cap->n_nodes_nonleaf_max = 1;
+		cap->non_leaf_nodes_identical = 1;
+
+		cap->nonleaf.shaper_private_supported = 1;
+		cap->nonleaf.shaper_private_rate_min = MRVL_RATE_MIN;
+		cap->nonleaf.shaper_private_rate_max = priv->rate_max;
+
+		cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
+		cap->nonleaf.sched_sp_n_priorities_max = 1;
+		cap->nonleaf.sched_wfq_n_children_per_group_max =
+			dev->data->nb_tx_queues;
+		cap->nonleaf.sched_wfq_n_groups_max = 1;
+		cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
+		cap->nonleaf.stats_mask = RTE_TM_STATS_N_PKTS |
+					  RTE_TM_STATS_N_BYTES;
+	} else { /* level_id == MRVL_NODE_QUEUE */
+		cap->n_nodes_max = dev->data->nb_tx_queues;
+		cap->n_nodes_leaf_max = dev->data->nb_tx_queues;
+		cap->leaf_nodes_identical = 1;
+
+		cap->leaf.shaper_private_supported = 1;
+		cap->leaf.shaper_private_rate_min = MRVL_RATE_MIN;
+		cap->leaf.shaper_private_rate_max = priv->rate_max;
+		cap->leaf.stats_mask = RTE_TM_STATS_N_PKTS;
+	}
+
+	return 0;
+}
+
+/**
+ * Get node capabilities.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param cap Pointer to the capabilities.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_capabilities_get(struct rte_eth_dev *dev, uint32_t node_id,
+			   struct rte_tm_node_capabilities *cap,
+			   struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	if (!cap)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	memset(cap, 0, sizeof(*cap));
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	cap->shaper_private_supported = 1;
+	cap->shaper_private_rate_min = MRVL_RATE_MIN;
+	cap->shaper_private_rate_max = priv->rate_max;
+
+	if (node->type == MRVL_NODE_PORT) {
+		cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
+		cap->nonleaf.sched_sp_n_priorities_max = 1;
+		cap->nonleaf.sched_wfq_n_children_per_group_max =
+			dev->data->nb_tx_queues;
+		cap->nonleaf.sched_wfq_n_groups_max = 1;
+		cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
+		cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
+	} else {
+		cap->stats_mask = RTE_TM_STATS_N_PKTS;
+	}
+
+	return 0;
+}
+
+/**
+ * Get shaper profile using its id.
+ *
+ * @param priv Pointer to the port's private data.
+ * @param shaper_profile_id Id used by the shaper.
+ * @returns Pointer to the shaper profile if exists, NULL otherwise.
+ */
+static struct mrvl_tm_shaper_profile *
+mrvl_shaper_profile_from_id(struct mrvl_priv *priv, uint32_t shaper_profile_id)
+{
+	struct mrvl_tm_shaper_profile *profile;
+
+	LIST_FOREACH(profile, &priv->shaper_profiles, next)
+		if (profile->id == shaper_profile_id)
+			return profile;
+
+	return NULL;
+}
+
+/**
+ * Add a new shaper profile.
+ *
+ * @param dev Pointer to the device.
+ * @param shaper_profile_id Id of the new profile.
+ * @param params Pointer to the shaper profile parameters.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_shaper_profile_add(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
+			struct rte_tm_shaper_params *params,
+			struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile;
+
+	if (!params)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	if (params->committed.rate)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE,
+				NULL, "Committed rate not supported\n");
+
+	if (params->committed.size)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE,
+				NULL, "Committed bucket size not supported\n");
+
+	if (params->peak.rate < MRVL_RATE_MIN ||
+	    params->peak.rate > priv->rate_max)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE,
+				NULL, "Peak rate is out of range\n");
+
+	if (params->peak.size < MRVL_BURST_MIN ||
+	    params->peak.size > MRVL_BURST_MAX)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE,
+				NULL, "Peak size is out of range\n");
+
+	if (shaper_profile_id == RTE_TM_SHAPER_PROFILE_ID_NONE)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Wrong shaper profile id\n");
+
+	profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
+	if (profile)
+		return -rte_tm_error_set(error, EEXIST,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Profile id already exists\n");
+
+	profile = rte_zmalloc_socket(NULL, sizeof(*profile), 0,
+				     rte_socket_id());
+	if (!profile)
+		return -rte_tm_error_set(error, ENOMEM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	profile->id = shaper_profile_id;
+	rte_memcpy(&profile->params, params, sizeof(profile->params));
+
+	LIST_INSERT_HEAD(&priv->shaper_profiles, profile, next);
+
+	return 0;
+}
+
+/**
+ * Remove a shaper profile.
+ *
+ * @param dev Pointer to the device.
+ * @param shaper_profile_id Id of the shaper profile.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_shaper_profile_delete(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
+			   struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile;
+
+	profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
+	if (!profile)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Profile id does not exist\n");
+
+	if (profile->refcnt)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Profile is used\n");
+
+	LIST_REMOVE(profile, next);
+	rte_free(profile);
+
+	return 0;
+}
+
+/**
+ * Check node parameters.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id used by the node.
+ * @param priority Priority value.
+ * @param weight Weight value.
+ * @param level_id Id of the level.
+ * @param params Pointer to the node parameters.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_check_params(struct rte_eth_dev *dev, uint32_t node_id,
+		       uint32_t priority, uint32_t weight, uint32_t level_id,
+		       struct rte_tm_node_params *params,
+		       struct rte_tm_error *error)
+{
+	if (node_id == RTE_TM_NODE_ID_NULL)
+		return -rte_tm_error_set(error, EINVAL, RTE_TM_NODE_ID_NULL,
+					 NULL, "Node id is invalid\n");
+
+	if (priority)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_NODE_PRIORITY,
+					 NULL, "Priority should be 0\n");
+
+	if (weight > MRVL_WEIGHT_MAX)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_NODE_WEIGHT,
+					 NULL, "Weight is out of range\n");
+
+	if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_LEVEL_ID,
+					 NULL, "Wrong level id\n");
+
+	if (!params)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	if (params->shared_shaper_id)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID,
+				NULL, "Shared shaper is not supported\n");
+
+	if (params->n_shared_shapers)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS,
+				NULL, "Shared shaper is not supported\n");
+
+	/* verify port (root node) settings */
+	if (node_id >= dev->data->nb_tx_queues) {
+		if (params->nonleaf.wfq_weight_mode)
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE,
+				NULL, "WFQ is not supported\n");
+
+		if (params->nonleaf.n_sp_priorities != 1)
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES,
+				NULL, "SP is not supported\n");
+
+		if (params->stats_mask & ~(RTE_TM_STATS_N_PKTS |
+					   RTE_TM_STATS_N_BYTES))
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+				NULL,
+				"Requested port stats are not supported\n");
+
+		return 0;
+	}
+
+	/* verify txq (leaf node) settings */
+	if (params->leaf.cman)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN,
+					 NULL,
+					 "Congestion mngmt is not supported\n");
+
+	if (params->leaf.wred.wred_profile_id)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID,
+				NULL, "WRED is not supported\n");
+
+	if (params->leaf.wred.shared_wred_context_id)
+		return -rte_tm_error_set(error, EINVAL,
+			RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID,
+			NULL, "WRED is not supported\n");
+
+	if (params->leaf.wred.n_shared_wred_contexts)
+		return -rte_tm_error_set(error, EINVAL,
+			RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS,
+			NULL, "WRED is not supported\n");
+
+	if (params->stats_mask & ~RTE_TM_STATS_N_PKTS)
+		return -rte_tm_error_set(error, EINVAL,
+			RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+			NULL,
+			"Requested txq stats are not supported\n");
+
+	return 0;
+}
+
+/**
+ * Add a new node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param parent_node_id Id of the parent node.
+ * @param priority Priority value.
+ * @param weight Weight value.
+ * @param level_id Id of the level.
+ * @param params Pointer to the node parameters.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_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 mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile = NULL;
+	struct mrvl_tm_node *node, *parent = NULL;
+	int ret;
+
+	if (priv->ppio)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Port is already started\n");
+
+	ret = mrvl_node_check_params(dev, node_id, priority, weight, level_id,
+				     params, error);
+	if (ret)
+		return ret;
+
+	if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE) {
+		profile = mrvl_shaper_profile_from_id(priv,
+						 params->shaper_profile_id);
+		if (!profile)
+			return -rte_tm_error_set(error, ENODEV,
+					RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					NULL, "Shaper id does not exist\n");
+	}
+
+	if (parent_node_id == RTE_TM_NODE_ID_NULL) {
+		LIST_FOREACH(node, &priv->nodes, next) {
+			if (node->type != MRVL_NODE_PORT)
+				continue;
+
+			return -rte_tm_error_set(error, EINVAL,
+						 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						 NULL, "Root node exists\n");
+		}
+	} else {
+		parent = mrvl_node_from_id(priv, parent_node_id);
+		if (!parent)
+			return -rte_tm_error_set(error, EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
+					NULL, "Node id does not exist\n");
+	}
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id already exists\n");
+
+	node = rte_zmalloc_socket(NULL, sizeof(*node), 0, rte_socket_id());
+	if (!node)
+		return -rte_tm_error_set(error, ENOMEM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	node->id = node_id;
+	node->type = parent_node_id == RTE_TM_NODE_ID_NULL ? MRVL_NODE_PORT :
+							     MRVL_NODE_QUEUE;
+
+	if (parent) {
+		node->parent = parent;
+		parent->refcnt++;
+	}
+
+	if (profile) {
+		node->profile = profile;
+		profile->refcnt++;
+	}
+
+	node->weight = weight;
+	node->stats_mask = params->stats_mask;
+
+	LIST_INSERT_HEAD(&priv->nodes, node, next);
+
+	return 0;
+}
+
+/**
+ * Delete a node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
+		 struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	if (priv->ppio) {
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Port is already started\n");
+	}
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (node->refcnt)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id is used\n");
+
+	if (node->parent)
+		node->parent->refcnt--;
+
+	if (node->profile)
+		node->profile->refcnt--;
+
+	LIST_REMOVE(node, next);
+	rte_free(node);
+
+	return 0;
+}
+
+/**
+ * Helper for suspending specific tx queue.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id used by this node.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int mrvl_node_suspend_one(struct rte_eth_dev *dev, uint32_t node_id,
+				 struct rte_tm_error *error)
+{
+	int ret = dev->dev_ops->tx_queue_stop(dev, node_id);
+	if (ret)
+		return -rte_tm_error_set(error, ret,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Failed to suspend a txq\n");
+
+	return 0;
+}
+
+/**
+ * Suspend a node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param error Pointer to the error.
+ * returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_suspend(struct rte_eth_dev *dev, uint32_t node_id,
+		  struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node, *tmp;
+	int ret;
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (!node->parent) {
+		LIST_FOREACH(tmp, &priv->nodes, next) {
+			if (!tmp->parent)
+				continue;
+
+			if (node != tmp->parent)
+				continue;
+
+			ret = mrvl_node_suspend_one(dev, tmp->id, error);
+			if (ret)
+				return ret;
+		}
+
+		return 0;
+	}
+
+	return mrvl_node_suspend_one(dev, node_id, error);
+}
+
+/**
+ * Resume a node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param error Pointer to the error.
+ * returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_resume(struct rte_eth_dev *dev, uint32_t node_id,
+		 struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+	int ret;
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+
+	if (!node->parent)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Cannot suspend a port\n");
+
+	ret = dev->dev_ops->tx_queue_start(dev, node_id);
+	if (ret)
+		return -rte_tm_error_set(error, ret,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Failed to resume a txq\n");
+	return 0;
+}
+
+/**
+ * Apply traffic manager hierarchy.
+ *
+ * @param dev Pointer to the device.
+ * @param clear_on_fail Flag indicating whether to do cleanup on the failure.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_hierarchy_commit(struct rte_eth_dev *dev, int clear_on_fail,
+		      struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+	int ret;
+
+	if (priv->ppio) {
+		ret = -rte_tm_error_set(error, EPERM,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					NULL, "Port is already started\n");
+		goto out;
+	}
+
+	LIST_FOREACH(node, &priv->nodes, next) {
+		struct pp2_ppio_outq_params *p;
+
+		if (node->type == MRVL_NODE_PORT) {
+			if (!node->profile)
+				continue;
+
+			priv->ppio_params.rate_limit_enable = 1;
+			priv->ppio_params.rate_limit_params.cir =
+				node->profile->params.peak.rate * 8 / 1000;
+			priv->ppio_params.rate_limit_params.cbs =
+				node->profile->params.peak.size / 1000;
+
+			MRVL_LOG(INFO,
+				"Port rate limit overrides txqs rate limit");
+
+			continue;
+		}
+
+		if (node->id >= dev->data->nb_tx_queues) {
+			ret = -rte_tm_error_set(error, EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_ID, NULL,
+					"Not enough txqs are configured\n");
+			goto out;
+		}
+
+		p = &priv->ppio_params.outqs_params.outqs_params[node->id];
+
+		if (node->weight) {
+			p->sched_mode = PP2_PPIO_SCHED_M_WRR;
+			p->weight = node->weight;
+		} else {
+			p->sched_mode = PP2_PPIO_SCHED_M_SP;
+			p->weight = 0;
+		}
+
+		if (node->profile) {
+			p->rate_limit_enable = 1;
+			/* convert Bytes/s to kilo bits/s */
+			p->rate_limit_params.cir =
+				node->profile->params.peak.rate * 8 / 1000;
+			/* convert bits to kilo bits */
+			p->rate_limit_params.cbs =
+				node->profile->params.peak.size / 1000;
+		} else {
+			p->rate_limit_enable = 0;
+			p->rate_limit_params.cir = 0;
+			p->rate_limit_params.cbs = 0;
+		}
+	}
+
+	/* reset to defaults in case applied tm hierarchy is empty */
+	if (LIST_EMPTY(&priv->nodes)) {
+		int i;
+
+		for (i = 0; i < priv->ppio_params.outqs_params.num_outqs; i++) {
+			struct pp2_ppio_outq_params *p =
+				&priv->ppio_params.outqs_params.outqs_params[i];
+
+			p->sched_mode = PP2_PPIO_SCHED_M_WRR;
+			p->weight = 0;
+			p->rate_limit_enable = 0;
+			p->rate_limit_params.cir = 0;
+			p->rate_limit_params.cbs = 0;
+		}
+	}
+
+	return 0;
+out:
+	if (clear_on_fail) {
+		mrvl_tm_deinit(dev);
+		mrvl_tm_init(dev);
+	}
+
+	return ret;
+}
+
+/**
+ * Read statistics counters for current node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param stats Pointer to the statistics counters.
+ * @param stats_mask Pointer to mask of enabled statistics counters
+ *                   that are retrieved.
+ * @param clear Flag indicating whether to clear statistics.
+ *              Non-zero value clears statistics.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_stats_read(struct rte_eth_dev *dev, uint32_t node_id,
+		     struct rte_tm_node_stats *stats, uint64_t *stats_mask,
+		     int clear, struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+	int ret;
+
+	if (!priv->ppio) {
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Port is not started\n");
+	}
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (stats_mask)
+		*stats_mask = node->stats_mask;
+
+	if (!stats)
+		return 0;
+
+	memset(stats, 0, sizeof(*stats));
+
+	if (!node->parent) {
+		struct pp2_ppio_statistics s;
+
+		memset(&s, 0, sizeof(s));
+		ret = pp2_ppio_get_statistics(priv->ppio, &s, clear);
+		if (ret)
+			return -rte_tm_error_set(error, -ret,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to read port statistics\n");
+
+		if (node->stats_mask & RTE_TM_STATS_N_PKTS)
+			stats->n_pkts = s.tx_packets;
+
+		if (node->stats_mask & RTE_TM_STATS_N_BYTES)
+			stats->n_bytes = s.tx_bytes;
+	} else {
+		struct pp2_ppio_outq_statistics s;
+
+		memset(&s, 0, sizeof(s));
+		ret = pp2_ppio_outq_get_statistics(priv->ppio, node_id, &s,
+						   clear);
+		if (ret)
+			return -rte_tm_error_set(error, -ret,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to read txq statistics\n");
+
+		if (node->stats_mask & RTE_TM_STATS_N_PKTS)
+			stats->n_pkts = s.deq_desc;
+	}
+
+	return 0;
+}
+
+/**
+ * Update node statistics.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param stats_mask Bitmask of statistics counters to be enabled.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_stats_update(struct rte_eth_dev *dev, uint32_t node_id,
+		       uint64_t stats_mask, struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (!node->parent) {
+		if (stats_mask & ~(RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES))
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+				NULL,
+				"Requested port stats are not supported\n");
+	} else {
+		if (stats_mask & ~RTE_TM_STATS_N_PKTS)
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+				NULL,
+				"Requested txq stats are not supported\n");
+	}
+
+	node->stats_mask = stats_mask;
+
+	return 0;
+}
+
+const struct rte_tm_ops mrvl_tm_ops = {
+	.node_type_get = mrvl_node_type_get,
+	.capabilities_get = mrvl_capabilities_get,
+	.level_capabilities_get = mrvl_level_capabilities_get,
+	.node_capabilities_get = mrvl_node_capabilities_get,
+	.shaper_profile_add = mrvl_shaper_profile_add,
+	.shaper_profile_delete = mrvl_shaper_profile_delete,
+	.node_add = mrvl_node_add,
+	.node_delete = mrvl_node_delete,
+	.node_suspend = mrvl_node_suspend,
+	.node_resume = mrvl_node_resume,
+	.hierarchy_commit = mrvl_hierarchy_commit,
+	.node_stats_update = mrvl_node_stats_update,
+	.node_stats_read = mrvl_node_stats_read,
+};
diff --git a/drivers/net/mvpp2/mrvl_tm.h b/drivers/net/mvpp2/mrvl_tm.h
new file mode 100644
index 0000000..9d81ede
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_tm.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#ifndef _MRVL_TM_H_
+#define _MRVL_TM_H_
+
+#include "mrvl_ethdev.h"
+
+int mrvl_tm_init(struct rte_eth_dev *dev);
+void mrvl_tm_deinit(struct rte_eth_dev *dev);
+
+#endif /* _MRVL_TM_H_ */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH 7/8] net/mvpp2: detach tx_qos from rx cls/qos config
  2018-09-04  7:10 [dpdk-dev] [PATCH 0/8] net/mvpp2: add new features Tomasz Duszynski
                   ` (5 preceding siblings ...)
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 6/8] net/mvpp2: add traffic manager support Tomasz Duszynski
@ 2018-09-04  7:10 ` Tomasz Duszynski
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 8/8] net/mvpp2: update MTU and MRU related calculations Tomasz Duszynski
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
  8 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04  7:10 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Yuval Caduri

From: Yuval Caduri <cyuval@marvell.com>

Functional change:
Open receive cls/qos related features, only if the
config file contains an rx_related configuration entry.
This allows to configure tx_related entries, w/o unintentionally
opening rx cls/qos.

Code:
'use_global_defaults' is by default set to '1'.
Only if an rx_related entry was configured, it is updated to '0'.
rx cls/qos is performed only if 'use_global_defaults' is '0'.
Default TC configuration is now only mandatory when
'use_global_defaults' is '0'.

Signed-off-by: Yuval Caduri <cyuval@marvell.com>
Reviewed-by: Natalie Samsonov <nsamsono@marvell.com>
Tested-by: Natalie Samsonov <nsamsono@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c |  3 ++-
 drivers/net/mvpp2/mrvl_qos.c    | 41 +++++++++++++++++++++++------------------
 2 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index a1dc6b1..5643e7d 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -602,7 +602,8 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 	}
 
 	/* For default QoS config, don't start classifier. */
-	if (mrvl_qos_cfg) {
+	if (mrvl_qos_cfg  &&
+	    mrvl_qos_cfg->port[dev->data->port_id].use_global_defaults == 0) {
 		ret = mrvl_start_qos_mapping(priv);
 		if (ret) {
 			MRVL_LOG(ERR, "Failed to setup QoS mapping");
diff --git a/drivers/net/mvpp2/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c
index e039635..5d80c3e 100644
--- a/drivers/net/mvpp2/mrvl_qos.c
+++ b/drivers/net/mvpp2/mrvl_qos.c
@@ -324,6 +324,7 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
 	if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
 		return 0;
 
+	cfg->port[port].use_global_defaults = 0;
 	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
 	if (entry) {
 		n = get_entry_values(entry,
@@ -421,7 +422,7 @@ parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
 			cfg->port[port].policer_params.token_unit =
 				PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
 		} else {
-			RTE_LOG(ERR, PMD, "Unknown token: %s\n", entry);
+			MRVL_LOG(ERR, "Unknown token: %s", entry);
 			return -1;
 		}
 	}
@@ -438,7 +439,7 @@ parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
 			cfg->port[port].policer_params.color_mode =
 				PP2_CLS_PLCR_COLOR_AWARE_MODE;
 		} else {
-			RTE_LOG(ERR, PMD, "Error in parsing: %s\n", entry);
+			MRVL_LOG(ERR, "Error in parsing: %s", entry);
 			return -1;
 		}
 	}
@@ -518,28 +519,15 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 		snprintf(sec_name, sizeof(sec_name), "%s %d %s",
 			MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
 
+		/* Use global defaults, unless an override occurs */
+		(*cfg)->port[n].use_global_defaults = 1;
+
 		/* Skip ports non-existing in configuration. */
 		if (rte_cfgfile_num_sections(file, sec_name,
 				strlen(sec_name)) <= 0) {
-			(*cfg)->port[n].use_global_defaults = 1;
-			(*cfg)->port[n].mapping_priority =
-				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
 			continue;
 		}
 
-		entry = rte_cfgfile_get_entry(file, sec_name,
-				MRVL_TOK_DEFAULT_TC);
-		if (entry) {
-			if (get_val_securely(entry, &val) < 0 ||
-				val > USHRT_MAX)
-				return -1;
-			(*cfg)->port[n].default_tc = (uint8_t)val;
-		} else {
-			MRVL_LOG(ERR,
-				"Default Traffic Class required in custom configuration!");
-			return -1;
-		}
-
 		/*
 		 * Read per-port rate limiting. Setting that will
 		 * disable per-queue rate limiting.
@@ -573,6 +561,7 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 		entry = rte_cfgfile_get_entry(file, sec_name,
 				MRVL_TOK_MAPPING_PRIORITY);
 		if (entry) {
+			(*cfg)->port[n].use_global_defaults = 0;
 			if (!strncmp(entry, MRVL_TOK_VLAN_IP,
 				sizeof(MRVL_TOK_VLAN_IP)))
 				(*cfg)->port[n].mapping_priority =
@@ -602,6 +591,7 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 		entry = rte_cfgfile_get_entry(file, sec_name,
 				MRVL_TOK_PLCR_DEFAULT);
 		if (entry) {
+			(*cfg)->port[n].use_global_defaults = 0;
 			if (get_val_securely(entry, &val) < 0)
 				return -1;
 
@@ -627,6 +617,21 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 					"Error %d parsing port %d tc %d!\n",
 					ret, n, i);
 		}
+
+		entry = rte_cfgfile_get_entry(file, sec_name,
+					      MRVL_TOK_DEFAULT_TC);
+		if (entry) {
+			if (get_val_securely(entry, &val) < 0 ||
+			    val > USHRT_MAX)
+				return -1;
+			(*cfg)->port[n].default_tc = (uint8_t)val;
+		} else {
+			if ((*cfg)->port[n].use_global_defaults == 0) {
+				MRVL_LOG(ERR,
+					 "Default Traffic Class required in custom configuration!");
+				return -1;
+			}
+		}
 	}
 
 	return 0;
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH 8/8] net/mvpp2: update MTU and MRU related calculations
  2018-09-04  7:10 [dpdk-dev] [PATCH 0/8] net/mvpp2: add new features Tomasz Duszynski
                   ` (6 preceding siblings ...)
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 7/8] net/mvpp2: detach tx_qos from rx cls/qos config Tomasz Duszynski
@ 2018-09-04  7:10 ` Tomasz Duszynski
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
  8 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04  7:10 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw

From: Natalie Samsonov <nsamsono@marvell.com>

This commit updates MTU and MRU related calculations.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Yelena Krivosheev <yelena@marvell.com>
Reviewed-by: Dmitri Epshtein <dima@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c | 70 +++++++++++++++++++++++++++++++----------
 drivers/net/mvpp2/mrvl_ethdev.h |  7 +++++
 2 files changed, 61 insertions(+), 16 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 5643e7d..035ee81 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -325,7 +325,7 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 
 	if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME)
 		dev->data->mtu = dev->data->dev_conf.rxmode.max_rx_pkt_len -
-				 ETHER_HDR_LEN - ETHER_CRC_LEN;
+				 MRVL_PP2_ETH_HDRS_LEN;
 
 	ret = mrvl_configure_rxqs(priv, dev->data->port_id,
 				  dev->data->nb_rx_queues);
@@ -375,21 +375,55 @@ static int
 mrvl_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
 	struct mrvl_priv *priv = dev->data->dev_private;
-	/* extra MV_MH_SIZE bytes are required for Marvell tag */
-	uint16_t mru = mtu + MV_MH_SIZE + ETHER_HDR_LEN + ETHER_CRC_LEN;
+	uint16_t mru;
+	uint16_t mbuf_data_size = 0; /* SW buffer size */
 	int ret;
 
-	if (mtu < ETHER_MIN_MTU || mru > MRVL_PKT_SIZE_MAX)
+	mru = MRVL_PP2_MTU_TO_MRU(mtu);
+	/*
+	 * min_rx_buf_size is equal to mbuf data size
+	 * if pmd didn't set it differently
+	 */
+	mbuf_data_size = dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM;
+	/* Prevent PMD from:
+	 * - setting mru greater than the mbuf size resulting in
+	 * hw and sw buffer size mismatch
+	 * - setting mtu that requires the support of scattered packets
+	 * when this feature has not been enabled/supported so far
+	 * (TODO check scattered_rx flag here once scattered RX is supported).
+	 */
+	if (mru + MRVL_PKT_OFFS > mbuf_data_size) {
+		mru = mbuf_data_size - MRVL_PKT_OFFS;
+		mtu = MRVL_PP2_MRU_TO_MTU(mru);
+		MRVL_LOG(WARNING, "MTU too big, max MTU possible limitted "
+			"by current mbuf size: %u. Set MTU to %u, MRU to %u",
+			mbuf_data_size, mtu, mru);
+	}
+
+	if (mtu < ETHER_MIN_MTU || mru > MRVL_PKT_SIZE_MAX) {
+		MRVL_LOG(ERR, "Invalid MTU [%u] or MRU [%u]", mtu, mru);
 		return -EINVAL;
+	}
+
+	dev->data->mtu = mtu;
+	dev->data->dev_conf.rxmode.max_rx_pkt_len = mru - MV_MH_SIZE;
 
 	if (!priv->ppio)
 		return 0;
 
 	ret = pp2_ppio_set_mru(priv->ppio, mru);
-	if (ret)
+	if (ret) {
+		MRVL_LOG(ERR, "Failed to change MRU");
 		return ret;
+	}
+
+	ret = pp2_ppio_set_mtu(priv->ppio, mtu);
+	if (ret) {
+		MRVL_LOG(ERR, "Failed to change MTU");
+		return ret;
+	}
 
-	return pp2_ppio_set_mtu(priv->ppio, mtu);
+	return 0;
 }
 
 /**
@@ -600,6 +634,9 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 		}
 		priv->vlan_flushed = 1;
 	}
+	ret = mrvl_mtu_set(dev, dev->data->mtu);
+	if (ret)
+		MRVL_LOG(ERR, "Failed to set MTU to %d", dev->data->mtu);
 
 	/* For default QoS config, don't start classifier. */
 	if (mrvl_qos_cfg  &&
@@ -1552,8 +1589,8 @@ mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 {
 	struct mrvl_priv *priv = dev->data->dev_private;
 	struct mrvl_rxq *rxq;
-	uint32_t min_size,
-		 max_rx_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	uint32_t frame_size, buf_size = rte_pktmbuf_data_room_size(mp);
+	uint32_t max_rx_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
 	int ret, tc, inq;
 	uint64_t offloads;
 
@@ -1568,15 +1605,16 @@ mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		return -EFAULT;
 	}
 
-	min_size = rte_pktmbuf_data_room_size(mp) - RTE_PKTMBUF_HEADROOM -
-		   MRVL_PKT_EFFEC_OFFS;
-	if (min_size < max_rx_pkt_len) {
-		MRVL_LOG(ERR,
-			"Mbuf size must be increased to %u bytes to hold up to %u bytes of data.",
-			max_rx_pkt_len + RTE_PKTMBUF_HEADROOM +
-			MRVL_PKT_EFFEC_OFFS,
+	frame_size = buf_size - RTE_PKTMBUF_HEADROOM - MRVL_PKT_EFFEC_OFFS;
+	if (frame_size < max_rx_pkt_len) {
+		MRVL_LOG(WARNING,
+			"Mbuf size must be increased to %u bytes to hold up "
+			"to %u bytes of data.",
+			buf_size + max_rx_pkt_len - frame_size,
 			max_rx_pkt_len);
-		return -EINVAL;
+		dev->data->dev_conf.rxmode.max_rx_pkt_len = frame_size;
+		MRVL_LOG(INFO, "Setting max rx pkt len to %u",
+			dev->data->dev_conf.rxmode.max_rx_pkt_len);
 	}
 
 	if (dev->data->rx_queues[idx]) {
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index 984f31e..f0ae983 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -72,6 +72,13 @@
 /** Minimum number of sent buffers to release from shadow queue to BM */
 #define MRVL_PP2_BUF_RELEASE_BURST_SIZE	64
 
+#define MRVL_PP2_VLAN_TAG_LEN		4
+#define MRVL_PP2_ETH_HDRS_LEN		(ETHER_HDR_LEN + ETHER_CRC_LEN + \
+					(2 * MRVL_PP2_VLAN_TAG_LEN))
+#define MRVL_PP2_HDRS_LEN		(MV_MH_SIZE + MRVL_PP2_ETH_HDRS_LEN)
+#define MRVL_PP2_MTU_TO_MRU(mtu)	((mtu) + MRVL_PP2_HDRS_LEN)
+#define MRVL_PP2_MRU_TO_MTU(mru)	((mru) - MRVL_PP2_HDRS_LEN)
+
 /** Maximum length of a match string */
 #define MRVL_MATCH_LEN 16
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features
  2018-09-04  7:10 [dpdk-dev] [PATCH 0/8] net/mvpp2: add new features Tomasz Duszynski
                   ` (7 preceding siblings ...)
  2018-09-04  7:10 ` [dpdk-dev] [PATCH 8/8] net/mvpp2: update MTU and MRU related calculations Tomasz Duszynski
@ 2018-09-04 13:49 ` Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 01/12] net/mvpp2: initialize ppio only once Tomasz Duszynski
                     ` (13 more replies)
  8 siblings, 14 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

This patch series introduces fixes and adds support for traffic metering,
traffic manager and Tx S/G. Additionally it aligns with for MUSDK 18.09.

Changes since v2:
* Align with MUSDK 18.09 library
* Add support for Tx Gather.
* Add documentation related to MTR and TM.
* Align documentation with MUSDK 18.09

Natalie Samsonov (4):
  net/mvpp2: initialize ppio only once
  net/mvpp2: update MTU and MRU related calculations
  net/mvpp2: align documentation with MUSDK 18.09
  net/mvpp2: document MTR and TM usage

Tomasz Duszynski (6):
  net/mvpp2: move common code
  net/mvpp2: add metering support
  net/mvpp2: change default policer configuration
  net/mvpp2: add init and deinit to flow
  net/mvpp2: add traffic manager support
  net/mvpp2: align with MUSDK 18.09

Yuval Caduri (1):
  net/mvpp2: detach tx_qos from rx cls/qos config

Zyta Szpak (1):
  net/mvpp2: add Tx S/G support

 doc/guides/nics/img/mvpp2_tm.png |  Bin 0 -> 5355 bytes
 doc/guides/nics/mvpp2.rst        |  433 +++++++++++++---
 drivers/net/mvpp2/Makefile       |    2 +
 drivers/net/mvpp2/meson.build    |    4 +-
 drivers/net/mvpp2/mrvl_ethdev.c  |  427 +++++++++++++---
 drivers/net/mvpp2/mrvl_ethdev.h  |  123 ++++-
 drivers/net/mvpp2/mrvl_flow.c    |  132 +++--
 drivers/net/mvpp2/mrvl_flow.h    |   15 +
 drivers/net/mvpp2/mrvl_mtr.c     |  512 +++++++++++++++++++
 drivers/net/mvpp2/mrvl_mtr.h     |   15 +
 drivers/net/mvpp2/mrvl_qos.c     |  246 +++++-----
 drivers/net/mvpp2/mrvl_qos.h     |    2 +-
 drivers/net/mvpp2/mrvl_tm.c      | 1009 ++++++++++++++++++++++++++++++++++++++
 drivers/net/mvpp2/mrvl_tm.h      |   15 +
 14 files changed, 2624 insertions(+), 311 deletions(-)
 create mode 100644 doc/guides/nics/img/mvpp2_tm.png
 create mode 100644 drivers/net/mvpp2/mrvl_flow.h
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.c
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.h
 create mode 100644 drivers/net/mvpp2/mrvl_tm.c
 create mode 100644 drivers/net/mvpp2/mrvl_tm.h

--
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 01/12] net/mvpp2: initialize ppio only once
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 02/12] net/mvpp2: move common code Tomasz Duszynski
                     ` (12 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw

From: Natalie Samsonov <nsamsono@marvell.com>

This changes stop/start/configure behavior due to issue in MUSDK
library itself.  From now on, ppio can be reconfigured only after interface
is closed.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Yuval Caduri <cyuval@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c | 53 +++++++++++++++++++++++++----------------
 1 file changed, 32 insertions(+), 21 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 6824445..f022cad 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -304,6 +304,11 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 	struct mrvl_priv *priv = dev->data->dev_private;
 	int ret;
 
+	if (priv->ppio) {
+		MRVL_LOG(INFO, "Device reconfiguration is not supported");
+		return -EINVAL;
+	}
+
 	if (dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_NONE &&
 	    dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) {
 		MRVL_LOG(INFO, "Unsupported rx multi queue mode %d",
@@ -525,6 +530,9 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 	char match[MRVL_MATCH_LEN];
 	int ret = 0, i, def_init_size;
 
+	if (priv->ppio)
+		return mrvl_dev_set_link_up(dev);
+
 	snprintf(match, sizeof(match), "ppio-%d:%d",
 		 priv->pp_id, priv->ppio_id);
 	priv->ppio_params.match = match;
@@ -749,28 +757,7 @@ mrvl_flush_bpool(struct rte_eth_dev *dev)
 static void
 mrvl_dev_stop(struct rte_eth_dev *dev)
 {
-	struct mrvl_priv *priv = dev->data->dev_private;
-
 	mrvl_dev_set_link_down(dev);
-	mrvl_flush_rx_queues(dev);
-	mrvl_flush_tx_shadow_queues(dev);
-	if (priv->cls_tbl) {
-		pp2_cls_tbl_deinit(priv->cls_tbl);
-		priv->cls_tbl = NULL;
-	}
-	if (priv->qos_tbl) {
-		pp2_cls_qos_tbl_deinit(priv->qos_tbl);
-		priv->qos_tbl = NULL;
-	}
-	if (priv->ppio)
-		pp2_ppio_deinit(priv->ppio);
-	priv->ppio = NULL;
-
-	/* policer must be released after ppio deinitialization */
-	if (priv->policer) {
-		pp2_cls_plcr_deinit(priv->policer);
-		priv->policer = NULL;
-	}
 }
 
 /**
@@ -785,6 +772,9 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 	struct mrvl_priv *priv = dev->data->dev_private;
 	size_t i;
 
+	mrvl_flush_rx_queues(dev);
+	mrvl_flush_tx_shadow_queues(dev);
+
 	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
 		struct pp2_ppio_tc_params *tc_params =
 			&priv->ppio_params.inqs_params.tcs_params[i];
@@ -795,7 +785,28 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 		}
 	}
 
+	if (priv->cls_tbl) {
+		pp2_cls_tbl_deinit(priv->cls_tbl);
+		priv->cls_tbl = NULL;
+	}
+
+	if (priv->qos_tbl) {
+		pp2_cls_qos_tbl_deinit(priv->qos_tbl);
+		priv->qos_tbl = NULL;
+	}
+
 	mrvl_flush_bpool(dev);
+
+	if (priv->ppio) {
+		pp2_ppio_deinit(priv->ppio);
+		priv->ppio = NULL;
+	}
+
+	/* policer must be released after ppio deinitialization */
+	if (priv->policer) {
+		pp2_cls_plcr_deinit(priv->policer);
+		priv->policer = NULL;
+	}
 }
 
 /**
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 02/12] net/mvpp2: move common code
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 01/12] net/mvpp2: initialize ppio only once Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 03/12] net/mvpp2: add metering support Tomasz Duszynski
                     ` (11 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

Cleanup sources by moving common code to the pmd
header file.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c |  9 ---------
 drivers/net/mvpp2/mrvl_ethdev.h | 11 +++++++++++
 drivers/net/mvpp2/mrvl_flow.c   |  5 -----
 drivers/net/mvpp2/mrvl_qos.c    |  9 ---------
 4 files changed, 11 insertions(+), 23 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index f022cad..adb07d0 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -10,15 +10,6 @@
 #include <rte_malloc.h>
 #include <rte_bus_vdev.h>
 
-/* Unluckily, container_of is defined by both DPDK and MUSDK,
- * we'll declare only one version.
- *
- * Note that it is not used in this PMD anyway.
- */
-#ifdef container_of
-#undef container_of
-#endif
-
 #include <fcntl.h>
 #include <linux/ethtool.h>
 #include <linux/sockios.h>
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index 3726f78..2204be2 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -10,12 +10,23 @@
 #include <rte_spinlock.h>
 #include <rte_flow_driver.h>
 
+/*
+ * container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+
 #include <env/mv_autogen_comp_flags.h>
 #include <drivers/mv_pp2.h>
 #include <drivers/mv_pp2_bpool.h>
 #include <drivers/mv_pp2_cls.h>
 #include <drivers/mv_pp2_hif.h>
 #include <drivers/mv_pp2_ppio.h>
+#include "env/mv_common.h" /* for BIT() */
 
 /** Maximum number of rx queues per port */
 #define MRVL_PP2_RXQ_MAX 32
diff --git a/drivers/net/mvpp2/mrvl_flow.c b/drivers/net/mvpp2/mrvl_flow.c
index 13295e6..db750f4 100644
--- a/drivers/net/mvpp2/mrvl_flow.c
+++ b/drivers/net/mvpp2/mrvl_flow.c
@@ -11,13 +11,8 @@
 
 #include <arpa/inet.h>
 
-#ifdef container_of
-#undef container_of
-#endif
-
 #include "mrvl_ethdev.h"
 #include "mrvl_qos.h"
-#include "env/mv_common.h" /* for BIT() */
 
 /** Number of rules in the classifier table. */
 #define MRVL_CLS_MAX_NUM_RULES 20
diff --git a/drivers/net/mvpp2/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c
index 71856c1..eeb46f8 100644
--- a/drivers/net/mvpp2/mrvl_qos.c
+++ b/drivers/net/mvpp2/mrvl_qos.c
@@ -15,15 +15,6 @@
 #include <rte_malloc.h>
 #include <rte_string_fns.h>
 
-/* Unluckily, container_of is defined by both DPDK and MUSDK,
- * we'll declare only one version.
- *
- * Note that it is not used in this PMD anyway.
- */
-#ifdef container_of
-#undef container_of
-#endif
-
 #include "mrvl_qos.h"
 
 /* Parsing tokens. Defined conveniently, so that any correction is easy. */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 03/12] net/mvpp2: add metering support
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 01/12] net/mvpp2: initialize ppio only once Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 02/12] net/mvpp2: move common code Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 04/12] net/mvpp2: change default policer configuration Tomasz Duszynski
                     ` (10 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

Add support for configuring plcr via DPDK generic metering API.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 drivers/net/mvpp2/Makefile      |   1 +
 drivers/net/mvpp2/meson.build   |   3 +-
 drivers/net/mvpp2/mrvl_ethdev.c |  24 ++
 drivers/net/mvpp2/mrvl_ethdev.h |  71 ++++++
 drivers/net/mvpp2/mrvl_flow.c   |  91 +++----
 drivers/net/mvpp2/mrvl_mtr.c    | 512 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/mvpp2/mrvl_mtr.h    |  15 ++
 7 files changed, 673 insertions(+), 44 deletions(-)
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.c
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.h

diff --git a/drivers/net/mvpp2/Makefile b/drivers/net/mvpp2/Makefile
index 211d398..4848d65 100644
--- a/drivers/net/mvpp2/Makefile
+++ b/drivers/net/mvpp2/Makefile
@@ -39,5 +39,6 @@ LDLIBS += -lrte_bus_vdev -lrte_common_mvep
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_qos.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_mtr.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/mvpp2/meson.build b/drivers/net/mvpp2/meson.build
index 3620659..f475511 100644
--- a/drivers/net/mvpp2/meson.build
+++ b/drivers/net/mvpp2/meson.build
@@ -19,7 +19,8 @@ endif
 sources = files(
 	'mrvl_ethdev.c',
 	'mrvl_flow.c',
-	'mrvl_qos.c'
+	'mrvl_qos.c',
+	'mrvl_mtr.c'
 )
 
 deps += ['cfgfile', 'common_mvep']
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index adb07d0..a4951d3 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -23,6 +23,7 @@
 #include <rte_mvep_common.h>
 #include "mrvl_ethdev.h"
 #include "mrvl_qos.h"
+#include "mrvl_mtr.h"
 
 /* bitmask with reserved hifs */
 #define MRVL_MUSDK_HIFS_RESERVED 0x0F
@@ -627,6 +628,8 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 			goto out;
 	}
 
+	mrvl_mtr_init(dev);
+
 	return 0;
 out:
 	MRVL_LOG(ERR, "Failed to start device");
@@ -765,6 +768,7 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 
 	mrvl_flush_rx_queues(dev);
 	mrvl_flush_tx_shadow_queues(dev);
+	mrvl_mtr_deinit(dev);
 
 	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
 		struct pp2_ppio_tc_params *tc_params =
@@ -1868,6 +1872,25 @@ mrvl_eth_filter_ctrl(struct rte_eth_dev *dev __rte_unused,
 	}
 }
 
+/**
+ * DPDK callback to get rte_mtr callbacks.
+ *
+ * @param dev
+ *   Pointer to the device structure.
+ * @param ops
+ *   Pointer to pass the mtr ops.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_mtr_ops_get(struct rte_eth_dev *dev __rte_unused, void *ops)
+{
+	*(const void **)ops = &mrvl_mtr_ops;
+
+	return 0;
+}
+
 static const struct eth_dev_ops mrvl_ops = {
 	.dev_configure = mrvl_dev_configure,
 	.dev_start = mrvl_dev_start,
@@ -1905,6 +1928,7 @@ static const struct eth_dev_ops mrvl_ops = {
 	.rss_hash_update = mrvl_rss_hash_update,
 	.rss_hash_conf_get = mrvl_rss_hash_conf_get,
 	.filter_ctrl = mrvl_eth_filter_ctrl,
+	.mtr_ops_get = mrvl_mtr_ops_get,
 };
 
 /**
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index 2204be2..ecb8fdc 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -9,6 +9,7 @@
 
 #include <rte_spinlock.h>
 #include <rte_flow_driver.h>
+#include <rte_mtr_driver.h>
 
 /*
  * container_of is defined by both DPDK and MUSDK,
@@ -70,6 +71,69 @@
 /** Minimum number of sent buffers to release from shadow queue to BM */
 #define MRVL_PP2_BUF_RELEASE_BURST_SIZE	64
 
+/** Maximum length of a match string */
+#define MRVL_MATCH_LEN 16
+
+/** Parsed fields in processed rte_flow_item. */
+enum mrvl_parsed_fields {
+	/* eth flags */
+	F_DMAC =         BIT(0),
+	F_SMAC =         BIT(1),
+	F_TYPE =         BIT(2),
+	/* vlan flags */
+	F_VLAN_PRI =     BIT(3),
+	F_VLAN_ID =      BIT(4),
+	F_VLAN_TCI =     BIT(5), /* not supported by MUSDK yet */
+	/* ip4 flags */
+	F_IP4_TOS =      BIT(6),
+	F_IP4_SIP =      BIT(7),
+	F_IP4_DIP =      BIT(8),
+	F_IP4_PROTO =    BIT(9),
+	/* ip6 flags */
+	F_IP6_TC =       BIT(10), /* not supported by MUSDK yet */
+	F_IP6_SIP =      BIT(11),
+	F_IP6_DIP =      BIT(12),
+	F_IP6_FLOW =     BIT(13),
+	F_IP6_NEXT_HDR = BIT(14),
+	/* tcp flags */
+	F_TCP_SPORT =    BIT(15),
+	F_TCP_DPORT =    BIT(16),
+	/* udp flags */
+	F_UDP_SPORT =    BIT(17),
+	F_UDP_DPORT =    BIT(18),
+};
+
+/** PMD-specific definition of a flow rule handle. */
+struct mrvl_mtr;
+struct rte_flow {
+	LIST_ENTRY(rte_flow) next;
+	struct mrvl_mtr *mtr;
+
+	enum mrvl_parsed_fields pattern;
+
+	struct pp2_cls_tbl_rule rule;
+	struct pp2_cls_cos_desc cos;
+	struct pp2_cls_tbl_action action;
+};
+
+struct mrvl_mtr_profile {
+	LIST_ENTRY(mrvl_mtr_profile) next;
+	uint32_t profile_id;
+	int refcnt;
+	struct rte_mtr_meter_profile profile;
+};
+
+struct mrvl_mtr {
+	LIST_ENTRY(mrvl_mtr) next;
+	uint32_t mtr_id;
+	int refcnt;
+	int shared;
+	int enabled;
+	int plcr_bit;
+	struct mrvl_mtr_profile *profile;
+	struct pp2_cls_plcr *plcr;
+};
+
 struct mrvl_priv {
 	/* Hot fields, used in fast path. */
 	struct pp2_bpool *bpool;  /**< BPool pointer */
@@ -105,11 +169,18 @@ struct mrvl_priv {
 	LIST_HEAD(mrvl_flows, rte_flow) flows;
 
 	struct pp2_cls_plcr *policer;
+
+	LIST_HEAD(profiles, mrvl_mtr_profile) profiles;
+	LIST_HEAD(mtrs, mrvl_mtr) mtrs;
+	uint32_t used_plcrs;
 };
 
 /** Flow operations forward declaration. */
 extern const struct rte_flow_ops mrvl_flow_ops;
 
+/** Meter operations forward declaration. */
+extern const struct rte_mtr_ops mrvl_mtr_ops;
+
 /** Current log type. */
 extern int mrvl_logtype;
 
diff --git a/drivers/net/mvpp2/mrvl_flow.c b/drivers/net/mvpp2/mrvl_flow.c
index db750f4..e6953e4 100644
--- a/drivers/net/mvpp2/mrvl_flow.c
+++ b/drivers/net/mvpp2/mrvl_flow.c
@@ -20,46 +20,6 @@
 /** Size of the classifier key and mask strings. */
 #define MRVL_CLS_STR_SIZE_MAX 40
 
-/** Parsed fields in processed rte_flow_item. */
-enum mrvl_parsed_fields {
-	/* eth flags */
-	F_DMAC =         BIT(0),
-	F_SMAC =         BIT(1),
-	F_TYPE =         BIT(2),
-	/* vlan flags */
-	F_VLAN_ID =      BIT(3),
-	F_VLAN_PRI =     BIT(4),
-	F_VLAN_TCI =     BIT(5), /* not supported by MUSDK yet */
-	/* ip4 flags */
-	F_IP4_TOS =      BIT(6),
-	F_IP4_SIP =      BIT(7),
-	F_IP4_DIP =      BIT(8),
-	F_IP4_PROTO =    BIT(9),
-	/* ip6 flags */
-	F_IP6_TC =       BIT(10), /* not supported by MUSDK yet */
-	F_IP6_SIP =      BIT(11),
-	F_IP6_DIP =      BIT(12),
-	F_IP6_FLOW =     BIT(13),
-	F_IP6_NEXT_HDR = BIT(14),
-	/* tcp flags */
-	F_TCP_SPORT =    BIT(15),
-	F_TCP_DPORT =    BIT(16),
-	/* udp flags */
-	F_UDP_SPORT =    BIT(17),
-	F_UDP_DPORT =    BIT(18),
-};
-
-/** PMD-specific definition of a flow rule handle. */
-struct rte_flow {
-	LIST_ENTRY(rte_flow) next;
-
-	enum mrvl_parsed_fields pattern;
-
-	struct pp2_cls_tbl_rule rule;
-	struct pp2_cls_cos_desc cos;
-	struct pp2_cls_tbl_action action;
-};
-
 static const enum rte_flow_item_type pattern_eth[] = {
 	RTE_FLOW_ITEM_TYPE_ETH,
 	RTE_FLOW_ITEM_TYPE_END
@@ -2295,19 +2255,59 @@ mrvl_flow_parse_actions(struct mrvl_priv *priv,
 			flow->action.type = PP2_CLS_TBL_ACT_DONE;
 			flow->action.cos = &flow->cos;
 			specified++;
+		} else if (action->type == RTE_FLOW_ACTION_TYPE_METER) {
+			const struct rte_flow_action_meter *meter;
+			struct mrvl_mtr *mtr;
+
+			meter = action->conf;
+			if (!meter)
+				return -rte_flow_error_set(error, EINVAL,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL, "Invalid meter\n");
+
+			LIST_FOREACH(mtr, &priv->mtrs, next)
+				if (mtr->mtr_id == meter->mtr_id)
+					break;
+
+			if (!mtr)
+				return -rte_flow_error_set(error, EINVAL,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL,
+						"Meter id does not exist\n");
+
+			if (!mtr->shared && mtr->refcnt)
+				return -rte_flow_error_set(error, EPERM,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL,
+						"Meter cannot be shared\n");
+
+			/*
+			 * In case cos has already been set
+			 * do not modify it.
+			 */
+			if (!flow->cos.ppio) {
+				flow->cos.ppio = priv->ppio;
+				flow->cos.tc = 0;
+			}
+
+			flow->action.type = PP2_CLS_TBL_ACT_DONE;
+			flow->action.cos = &flow->cos;
+			flow->action.plcr = mtr->enabled ? mtr->plcr : NULL;
+			flow->mtr = mtr;
+			mtr->refcnt++;
+			specified++;
 		} else {
 			rte_flow_error_set(error, ENOTSUP,
 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
 					   "Action not supported");
 			return -rte_errno;
 		}
-
 	}
 
 	if (!specified) {
 		rte_flow_error_set(error, EINVAL,
-				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
-				   NULL, "Action not specified");
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Action not specified");
 		return -rte_errno;
 	}
 
@@ -2657,6 +2657,11 @@ mrvl_flow_remove(struct mrvl_priv *priv, struct rte_flow *flow,
 
 	mrvl_free_all_key_mask(&flow->rule);
 
+	if (flow->mtr) {
+		flow->mtr->refcnt--;
+		flow->mtr = NULL;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/mvpp2/mrvl_mtr.c b/drivers/net/mvpp2/mrvl_mtr.c
new file mode 100644
index 0000000..9cd53be
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_mtr.c
@@ -0,0 +1,512 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#include <rte_log.h>
+#include <rte_malloc.h>
+
+#include "mrvl_mtr.h"
+
+/** Maximum meter rate */
+#define MRVL_SRTCM_RFC2697_CIR_MAX 1023000
+
+/** Invalid plcr bit */
+#define MRVL_PLCR_BIT_INVALID -1
+
+/**
+ * Return meter object capabilities.
+ *
+ * @param dev Pointer to the device (unused).
+ * @param cap Pointer to the meter object capabilities.
+ * @param error Pointer to the error (unused).
+ * @returns 0 always.
+ */
+static int
+mrvl_capabilities_get(struct rte_eth_dev *dev __rte_unused,
+			  struct rte_mtr_capabilities *cap,
+			  struct rte_mtr_error *error __rte_unused)
+{
+	struct rte_mtr_capabilities capa = {
+		.n_max = PP2_CLS_PLCR_NUM,
+		.n_shared_max = PP2_CLS_PLCR_NUM,
+		.shared_n_flows_per_mtr_max = -1,
+		.meter_srtcm_rfc2697_n_max = PP2_CLS_PLCR_NUM,
+		.meter_rate_max = MRVL_SRTCM_RFC2697_CIR_MAX,
+	};
+
+	memcpy(cap, &capa, sizeof(capa));
+
+	return 0;
+}
+
+/**
+ * Get profile using it's id.
+ *
+ * @param priv Pointer to the port's private data.
+ * @param meter_profile_id Profile id used by the meter.
+ * @returns Pointer to the profile if exists, NULL otherwise.
+ */
+static struct mrvl_mtr_profile *
+mrvl_mtr_profile_from_id(struct mrvl_priv *priv, uint32_t meter_profile_id)
+{
+	struct mrvl_mtr_profile *profile = NULL;
+
+	LIST_FOREACH(profile, &priv->profiles, next)
+		if (profile->profile_id == meter_profile_id)
+			break;
+
+	return profile;
+}
+
+/**
+ * Add profile to the list of profiles.
+ *
+ * @param dev Pointer to the device.
+ * @param meter_profile_id Id of the new profile.
+ * @param profile Pointer to the profile configuration.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_profile_add(struct rte_eth_dev *dev, uint32_t meter_profile_id,
+		       struct rte_mtr_meter_profile *profile,
+		       struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *prof;
+
+	if (!profile)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, NULL);
+
+	if (profile->alg != RTE_MTR_SRTCM_RFC2697)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
+					  "Only srTCM RFC 2697 is supported\n");
+
+	prof = mrvl_mtr_profile_from_id(priv, meter_profile_id);
+	if (prof)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id already exists\n");
+
+	prof = rte_zmalloc_socket(NULL, sizeof(*prof), 0, rte_socket_id());
+	if (!prof)
+		return -rte_mtr_error_set(error, ENOMEM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, NULL);
+
+	prof->profile_id = meter_profile_id;
+	memcpy(&prof->profile, profile, sizeof(*profile));
+
+	LIST_INSERT_HEAD(&priv->profiles, prof, next);
+
+	return 0;
+}
+
+/**
+ * Remove profile from the list of profiles.
+ *
+ * @param dev Pointer to the device.
+ * @param meter_profile_id Id of the profile to remove.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_profile_delete(struct rte_eth_dev *dev,
+			      uint32_t meter_profile_id,
+			      struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile;
+
+	profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
+	if (!profile)
+		return -rte_mtr_error_set(error, ENODEV,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id does not exist\n");
+
+	if (profile->refcnt)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile is used\n");
+
+	LIST_REMOVE(profile, next);
+	rte_free(profile);
+
+	return 0;
+}
+
+/**
+ * Get meter using it's id.
+ *
+ * @param priv Pointer to port's private data.
+ * @param mtr_id Id of the meter.
+ * @returns Pointer to the meter if exists, NULL otherwise.
+ */
+static struct mrvl_mtr *
+mrvl_mtr_from_id(struct mrvl_priv *priv, uint32_t mtr_id)
+{
+	struct mrvl_mtr *mtr = NULL;
+
+	LIST_FOREACH(mtr, &priv->mtrs, next)
+		if (mtr->mtr_id == mtr_id)
+			break;
+
+	return mtr;
+}
+
+/**
+ * Reserve a policer bit in a bitmap.
+ *
+ * @param plcrs Pointer to the policers bitmap.
+ * @returns Reserved bit number on success, negative value otherwise.
+ */
+static int
+mrvl_reserve_plcr(uint32_t *plcrs)
+{
+	uint32_t i, num;
+
+	num = PP2_CLS_PLCR_NUM;
+	if (num > sizeof(uint32_t) * 8) {
+		num = sizeof(uint32_t) * 8;
+		MRVL_LOG(WARNING, "Plcrs number was limited to 32.");
+	}
+
+	for (i = 0; i < num; i++) {
+		uint32_t bit = BIT(i);
+
+		if (!(*plcrs & bit)) {
+			*plcrs |= bit;
+
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+/**
+ * Enable meter object.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter.
+ * @param error Pointer to the error.
+ * @returns 0 in success, negative value otherwise.
+ */
+static int
+mrvl_meter_enable(struct rte_eth_dev *dev, uint32_t mtr_id,
+		  struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
+	struct pp2_cls_plcr_params params;
+	char match[MRVL_MATCH_LEN];
+	struct rte_flow *flow;
+	int ret;
+
+	if (!priv->ppio)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Port is uninitialized\n");
+
+	if (!mtr)
+		return -rte_mtr_error_set(error, ENODEV,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	if (mtr->plcr)
+		goto skip;
+
+	mtr->plcr_bit = mrvl_reserve_plcr(&priv->used_plcrs);
+	if (mtr->plcr_bit < 0)
+		return -rte_mtr_error_set(error, ENOSPC,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
+					  "Failed to reserve plcr entry\n");
+
+	memset(&params, 0, sizeof(params));
+	snprintf(match, sizeof(match), "policer-%d:%d", priv->pp_id,
+		 mtr->plcr_bit);
+	params.match = match;
+	params.token_unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
+	params.color_mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
+	params.cir = mtr->profile->profile.srtcm_rfc2697.cir;
+	params.cbs = mtr->profile->profile.srtcm_rfc2697.cbs;
+	params.ebs = mtr->profile->profile.srtcm_rfc2697.ebs;
+
+	ret = pp2_cls_plcr_init(&params, &mtr->plcr);
+	if (ret) {
+		priv->used_plcrs &= ~BIT(mtr->plcr_bit);
+		mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
+
+		return -rte_mtr_error_set(error, -ret,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Failed to setup policer\n");
+	}
+
+	mtr->enabled = 1;
+skip:
+	/* iterate over flows that have this mtr attached */
+	LIST_FOREACH(flow, &priv->flows, next) {
+		if (flow->mtr != mtr)
+			continue;
+
+		flow->action.plcr = mtr->plcr;
+
+		ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
+					      &flow->action);
+		if (ret)
+			return -rte_mtr_error_set(error, -ret,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Failed to update cls rule\n");
+	}
+
+	return 0;
+}
+
+/**
+ * Disable meter object.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr Id of the meter.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_disable(struct rte_eth_dev *dev, uint32_t mtr_id,
+		       struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
+	struct rte_flow *flow;
+	int ret;
+
+	if (!mtr)
+		return -rte_mtr_error_set(error, ENODEV,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	LIST_FOREACH(flow, &priv->flows, next) {
+		if (flow->mtr != mtr)
+			continue;
+
+		flow->action.plcr = NULL;
+
+		ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
+					      &flow->action);
+		if (ret)
+			return -rte_mtr_error_set(error, -ret,
+					RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					NULL, "Failed to disable meter\n");
+	}
+
+	mtr->enabled = 0;
+
+	return 0;
+}
+
+/**
+ * Create new meter.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter.
+ * @param params Pointer to the meter parameters.
+ * @param shared Flags indicating whether meter is shared.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_create(struct rte_eth_dev *dev, uint32_t mtr_id,
+	    struct rte_mtr_params *params, int shared,
+	    struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile;
+	struct mrvl_mtr *mtr;
+
+	mtr = mrvl_mtr_from_id(priv, mtr_id);
+	if (mtr)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id already exists\n");
+
+	mtr = rte_zmalloc_socket(NULL, sizeof(*mtr), 0, rte_socket_id());
+	if (!mtr)
+		return -rte_mtr_error_set(error, ENOMEM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, NULL);
+
+	profile = mrvl_mtr_profile_from_id(priv, params->meter_profile_id);
+	if (!profile)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id does not exist\n");
+
+	mtr->shared = shared;
+	mtr->mtr_id = mtr_id;
+	mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
+	mtr->profile = profile;
+	profile->refcnt++;
+	LIST_INSERT_HEAD(&priv->mtrs, mtr, next);
+
+	if (params->meter_enable)
+		return mrvl_meter_enable(dev, mtr_id, error);
+
+	return 0;
+}
+
+/**
+ * Destroy meter object.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter object.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_destroy(struct rte_eth_dev *dev, uint32_t mtr_id,
+		 struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr *mtr;
+
+	if (!priv->ppio)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Port is uninitialized\n");
+
+	mtr = mrvl_mtr_from_id(priv, mtr_id);
+	if (!mtr)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	if (mtr->refcnt)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter is used\n");
+
+	LIST_REMOVE(mtr, next);
+	mtr->profile->refcnt--;
+
+	if (mtr->plcr_bit != MRVL_PLCR_BIT_INVALID)
+		priv->used_plcrs &= ~BIT(mtr->plcr_bit);
+
+	if (mtr->plcr)
+		pp2_cls_plcr_deinit(mtr->plcr);
+
+	rte_free(mtr);
+
+	return 0;
+}
+
+/**
+ * Update profile used by the meter.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter object.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_profile_update(struct rte_eth_dev *dev, uint32_t mtr_id,
+			  uint32_t meter_profile_id,
+			  struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile;
+	struct mrvl_mtr *mtr;
+	int ret, enabled;
+
+	if (!priv->ppio)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Port is uninitialized\n");
+
+	mtr = mrvl_mtr_from_id(priv, mtr_id);
+	if (!mtr)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
+	if (!profile)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id does not exist\n");
+
+	ret = mrvl_meter_disable(dev, mtr_id, error);
+	if (ret)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  NULL);
+
+	if (mtr->plcr) {
+		enabled = 1;
+		pp2_cls_plcr_deinit(mtr->plcr);
+		mtr->plcr = NULL;
+	}
+
+	mtr->profile->refcnt--;
+	mtr->profile = profile;
+	profile->refcnt++;
+
+	if (enabled)
+		return mrvl_meter_enable(dev, mtr_id, error);
+
+	return 0;
+}
+
+const struct rte_mtr_ops mrvl_mtr_ops = {
+	.capabilities_get = mrvl_capabilities_get,
+	.meter_profile_add = mrvl_meter_profile_add,
+	.meter_profile_delete = mrvl_meter_profile_delete,
+	.create = mrvl_create,
+	.destroy = mrvl_destroy,
+	.meter_enable = mrvl_meter_enable,
+	.meter_disable = mrvl_meter_disable,
+	.meter_profile_update = mrvl_meter_profile_update,
+};
+
+/**
+ * Initialize metering resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_mtr_init(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	LIST_INIT(&priv->profiles);
+	LIST_INIT(&priv->mtrs);
+}
+
+/**
+ * Cleanup metering resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_mtr_deinit(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile, *tmp_profile;
+	struct mrvl_mtr *mtr, *tmp_mtr;
+
+	for (mtr = LIST_FIRST(&priv->mtrs);
+	     mtr && (tmp_mtr = LIST_NEXT(mtr, next), 1);
+	     mtr = tmp_mtr)
+		mrvl_destroy(dev, mtr->mtr_id, NULL);
+
+	for (profile = LIST_FIRST(&priv->profiles);
+	     profile && (tmp_profile = LIST_NEXT(profile, next), 1);
+	     profile = tmp_profile)
+		mrvl_meter_profile_delete(dev, profile->profile_id, NULL);
+}
diff --git a/drivers/net/mvpp2/mrvl_mtr.h b/drivers/net/mvpp2/mrvl_mtr.h
new file mode 100644
index 0000000..302a20f
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_mtr.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#ifndef _MRVL_MTR_H_
+#define _MRVL_MTR_H_
+
+#include "mrvl_ethdev.h"
+
+void mrvl_mtr_init(struct rte_eth_dev *dev);
+void mrvl_mtr_deinit(struct rte_eth_dev *dev);
+
+#endif /* _MRVL_MTR_H_ */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 04/12] net/mvpp2: change default policer configuration
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
                     ` (2 preceding siblings ...)
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 03/12] net/mvpp2: add metering support Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 05/12] net/mvpp2: add init and deinit to flow Tomasz Duszynski
                     ` (9 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

Change QoS configuration file syntax for port's default policer
setup.

Since default policer configuration is performed before
any other policer configuration we can pick a default id.

This simplifies default policer configuration since user
no longer has to choose ids from range [0, PP2_CLS_PLCR_NUM].

Explicitly document values for rate_limit_enable field.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 doc/guides/nics/mvpp2.rst       |  31 ++++---
 drivers/net/mvpp2/mrvl_ethdev.c |   6 +-
 drivers/net/mvpp2/mrvl_ethdev.h |   2 +-
 drivers/net/mvpp2/mrvl_qos.c    | 198 ++++++++++++++++++++++------------------
 drivers/net/mvpp2/mrvl_qos.h    |   2 +-
 5 files changed, 134 insertions(+), 105 deletions(-)

diff --git a/doc/guides/nics/mvpp2.rst b/doc/guides/nics/mvpp2.rst
index 0408752..a452c8a 100644
--- a/doc/guides/nics/mvpp2.rst
+++ b/doc/guides/nics/mvpp2.rst
@@ -152,20 +152,23 @@ Configuration syntax
 
 .. code-block:: console
 
-   [port <portnum> default]
-   default_tc = <default_tc>
-   mapping_priority = <mapping_priority>
-   policer_enable = <policer_enable>
+   [policer <policer_id>]
    token_unit = <token_unit>
    color = <color_mode>
    cir = <cir>
    ebs = <ebs>
    cbs = <cbs>
 
+   [port <portnum> default]
+   default_tc = <default_tc>
+   mapping_priority = <mapping_priority>
+
    rate_limit_enable = <rate_limit_enable>
    rate_limit = <rate_limit>
    burst_size = <burst_size>
 
+   default_policer = <policer_id>
+
    [port <portnum> tc <traffic_class>]
    rxq = <rx_queue_list>
    pcp = <pcp_list>
@@ -201,7 +204,9 @@ Where:
 
 - ``<dscp_list>``: List of DSCP values to handle in particular TC (e.g. 0-12 32-48 63).
 
-- ``<policer_enable>``: Enable ingress policer.
+- ``<default_policer>``: Id of the policer configuration section to be used as default.
+
+- ``<policer_id>``: Id of the policer configuration section (0..31).
 
 - ``<token_unit>``: Policer token unit (`bytes` or `packets`).
 
@@ -215,7 +220,7 @@ Where:
 
 - ``<default_color>``: Default color for specific tc.
 
-- ``<rate_limit_enable>``: Enables per port or per txq rate limiting.
+- ``<rate_limit_enable>``: Enables per port or per txq rate limiting (`0`/`1` to disable/enable).
 
 - ``<rate_limit>``: Committed information rate, in kilo bits per second.
 
@@ -234,6 +239,13 @@ Configuration file example
 
 .. code-block:: console
 
+   [policer 0]
+   token_unit = bytes
+   color = blind
+   cir = 100000
+   ebs = 64
+   cbs = 64
+
    [port 0 default]
    default_tc = 0
    mapping_priority = ip
@@ -265,12 +277,7 @@ Configuration file example
    default_tc = 0
    mapping_priority = vlan/ip
 
-   policer_enable = 1
-   token_unit = bytes
-   color = blind
-   cir = 100000
-   ebs = 64
-   cbs = 64
+   default_policer = 0
 
    [port 1 tc 0]
    rxq = 0
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index a4951d3..1464385 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -798,9 +798,9 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 	}
 
 	/* policer must be released after ppio deinitialization */
-	if (priv->policer) {
-		pp2_cls_plcr_deinit(priv->policer);
-		priv->policer = NULL;
+	if (priv->default_policer) {
+		pp2_cls_plcr_deinit(priv->default_policer);
+		priv->default_policer = NULL;
 	}
 }
 
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index ecb8fdc..de423a9 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -168,7 +168,7 @@ struct mrvl_priv {
 	uint32_t cls_tbl_pattern;
 	LIST_HEAD(mrvl_flows, rte_flow) flows;
 
-	struct pp2_cls_plcr *policer;
+	struct pp2_cls_plcr *default_policer;
 
 	LIST_HEAD(profiles, mrvl_mtr_profile) profiles;
 	LIST_HEAD(mtrs, mrvl_mtr) mtrs;
diff --git a/drivers/net/mvpp2/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c
index eeb46f8..e039635 100644
--- a/drivers/net/mvpp2/mrvl_qos.c
+++ b/drivers/net/mvpp2/mrvl_qos.c
@@ -42,7 +42,8 @@
 #define MRVL_TOK_WRR_WEIGHT "wrr_weight"
 
 /* policer specific configuration tokens */
-#define MRVL_TOK_PLCR_ENABLE "policer_enable"
+#define MRVL_TOK_PLCR "policer"
+#define MRVL_TOK_PLCR_DEFAULT "default_policer"
 #define MRVL_TOK_PLCR_UNIT "token_unit"
 #define MRVL_TOK_PLCR_UNIT_BYTES "bytes"
 #define MRVL_TOK_PLCR_UNIT_PACKETS "packets"
@@ -368,6 +369,9 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
 		cfg->port[port].tc[tc].dscps = n;
 	}
 
+	if (!cfg->port[port].setup_policer)
+		return 0;
+
 	entry = rte_cfgfile_get_entry(file, sec_name,
 			MRVL_TOK_PLCR_DEFAULT_COLOR);
 	if (entry) {
@@ -390,6 +394,85 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
 }
 
 /**
+ * Parse default port policer.
+ *
+ * @param file Config file handle.
+ * @param sec_name Section name with policer configuration
+ * @param port Port number.
+ * @param cfg[out] Parsing results.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
+		struct mrvl_qos_cfg *cfg)
+{
+	const char *entry;
+	uint32_t val;
+
+	/* Read policer token unit */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_UNIT);
+	if (entry) {
+		if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
+					sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
+			cfg->port[port].policer_params.token_unit =
+				PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
+		} else if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_PACKETS,
+					sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
+			cfg->port[port].policer_params.token_unit =
+				PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
+		} else {
+			RTE_LOG(ERR, PMD, "Unknown token: %s\n", entry);
+			return -1;
+		}
+	}
+
+	/* Read policer color mode */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_COLOR);
+	if (entry) {
+		if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
+					sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
+			cfg->port[port].policer_params.color_mode =
+				PP2_CLS_PLCR_COLOR_BLIND_MODE;
+		} else if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_AWARE,
+					sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
+			cfg->port[port].policer_params.color_mode =
+				PP2_CLS_PLCR_COLOR_AWARE_MODE;
+		} else {
+			RTE_LOG(ERR, PMD, "Error in parsing: %s\n", entry);
+			return -1;
+		}
+	}
+
+	/* Read policer cir */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CIR);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].policer_params.cir = val;
+	}
+
+	/* Read policer cbs */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CBS);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].policer_params.cbs = val;
+	}
+
+	/* Read policer ebs */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_EBS);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].policer_params.ebs = val;
+	}
+
+	cfg->port[port].setup_policer = 1;
+
+	return 0;
+}
+
+/**
  * Parse QoS configuration - rte_kvargs_process handler.
  *
  * Opens configuration file and parses its content.
@@ -457,88 +540,6 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 			return -1;
 		}
 
-		entry = rte_cfgfile_get_entry(file, sec_name,
-				MRVL_TOK_PLCR_ENABLE);
-		if (entry) {
-			if (get_val_securely(entry, &val) < 0)
-				return -1;
-			(*cfg)->port[n].policer_enable = val;
-		}
-
-		if ((*cfg)->port[n].policer_enable) {
-			enum pp2_cls_plcr_token_unit unit;
-
-			/* Read policer token unit */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_UNIT);
-			if (entry) {
-				if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
-					sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
-					unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
-				} else if (!strncmp(entry,
-						MRVL_TOK_PLCR_UNIT_PACKETS,
-					sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
-					unit = PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
-				} else {
-					MRVL_LOG(ERR, "Unknown token: %s",
-						entry);
-					return -1;
-				}
-				(*cfg)->port[n].policer_params.token_unit =
-					unit;
-			}
-
-			/* Read policer color mode */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_COLOR);
-			if (entry) {
-				enum pp2_cls_plcr_color_mode mode;
-
-				if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
-					sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
-					mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
-				} else if (!strncmp(entry,
-						MRVL_TOK_PLCR_COLOR_AWARE,
-					sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
-					mode = PP2_CLS_PLCR_COLOR_AWARE_MODE;
-				} else {
-					MRVL_LOG(ERR,
-						"Error in parsing: %s",
-						entry);
-					return -1;
-				}
-				(*cfg)->port[n].policer_params.color_mode =
-					mode;
-			}
-
-			/* Read policer cir */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_CIR);
-			if (entry) {
-				if (get_val_securely(entry, &val) < 0)
-					return -1;
-				(*cfg)->port[n].policer_params.cir = val;
-			}
-
-			/* Read policer cbs */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_CBS);
-			if (entry) {
-				if (get_val_securely(entry, &val) < 0)
-					return -1;
-				(*cfg)->port[n].policer_params.cbs = val;
-			}
-
-			/* Read policer ebs */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_EBS);
-			if (entry) {
-				if (get_val_securely(entry, &val) < 0)
-					return -1;
-				(*cfg)->port[n].policer_params.ebs = val;
-			}
-		}
-
 		/*
 		 * Read per-port rate limiting. Setting that will
 		 * disable per-queue rate limiting.
@@ -597,6 +598,20 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
 		}
 
+		/* Parse policer configuration (if any) */
+		entry = rte_cfgfile_get_entry(file, sec_name,
+				MRVL_TOK_PLCR_DEFAULT);
+		if (entry) {
+			if (get_val_securely(entry, &val) < 0)
+				return -1;
+
+			snprintf(sec_name, sizeof(sec_name), "%s %d",
+					MRVL_TOK_PLCR, val);
+			ret = parse_policer(file, n, sec_name, *cfg);
+			if (ret)
+				return -1;
+		}
+
 		for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
 			ret = get_outq_cfg(file, n, i, *cfg);
 			if (ret < 0)
@@ -659,6 +674,7 @@ setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
  *
  * @param priv Port's private data.
  * @param params Pointer to the policer's configuration.
+ * @param plcr_id Policer id.
  * @returns 0 in case of success, negative values otherwise.
  */
 static int
@@ -667,17 +683,23 @@ setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
 	char match[16];
 	int ret;
 
-	snprintf(match, sizeof(match), "policer-%d:%d\n",
-			priv->pp_id, priv->ppio_id);
+	/*
+	 * At this point no other policers are used which means
+	 * any policer can be picked up and used as a default one.
+	 *
+	 * Lets use 0th then.
+	 */
+	sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
 	params->match = match;
 
-	ret = pp2_cls_plcr_init(params, &priv->policer);
+	ret = pp2_cls_plcr_init(params, &priv->default_policer);
 	if (ret) {
 		MRVL_LOG(ERR, "Failed to setup %s", match);
 		return -1;
 	}
 
-	priv->ppio_params.inqs_params.plcr = priv->policer;
+	priv->ppio_params.inqs_params.plcr = priv->default_policer;
+	priv->used_plcrs = BIT(0);
 
 	return 0;
 }
@@ -809,7 +831,7 @@ mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
 
 	priv->ppio_params.inqs_params.num_tcs = i;
 
-	if (port_cfg->policer_enable)
+	if (port_cfg->setup_policer)
 		return setup_policer(priv, &port_cfg->policer_params);
 
 	return 0;
diff --git a/drivers/net/mvpp2/mrvl_qos.h b/drivers/net/mvpp2/mrvl_qos.h
index fa9ddec..f03e773 100644
--- a/drivers/net/mvpp2/mrvl_qos.h
+++ b/drivers/net/mvpp2/mrvl_qos.h
@@ -43,7 +43,7 @@ struct mrvl_qos_cfg {
 		uint8_t default_tc;
 		uint8_t use_global_defaults;
 		struct pp2_cls_plcr_params policer_params;
-		uint8_t policer_enable;
+		uint8_t setup_policer;
 	} port[RTE_MAX_ETHPORTS];
 };
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 05/12] net/mvpp2: add init and deinit to flow
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
                     ` (3 preceding siblings ...)
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 04/12] net/mvpp2: change default policer configuration Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 06/12] net/mvpp2: add traffic manager support Tomasz Duszynski
                     ` (8 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

Add init and deinit functionality to flow implementation.

Init puts structures used by flow in a sane sate.
Deinit deallocates all resources used by flow.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
Reviewed-by: Shlomi Gridish <sgridish@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c |  3 +++
 drivers/net/mvpp2/mrvl_flow.c   | 33 ++++++++++++++++++++++++++++++++-
 drivers/net/mvpp2/mrvl_flow.h   | 15 +++++++++++++++
 3 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/mvpp2/mrvl_flow.h

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 1464385..5e3a106 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -23,6 +23,7 @@
 #include <rte_mvep_common.h>
 #include "mrvl_ethdev.h"
 #include "mrvl_qos.h"
+#include "mrvl_flow.h"
 #include "mrvl_mtr.h"
 
 /* bitmask with reserved hifs */
@@ -628,6 +629,7 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 			goto out;
 	}
 
+	mrvl_flow_init(dev);
 	mrvl_mtr_init(dev);
 
 	return 0;
@@ -768,6 +770,7 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 
 	mrvl_flush_rx_queues(dev);
 	mrvl_flush_tx_shadow_queues(dev);
+	mrvl_flow_deinit(dev);
 	mrvl_mtr_deinit(dev);
 
 	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
diff --git a/drivers/net/mvpp2/mrvl_flow.c b/drivers/net/mvpp2/mrvl_flow.c
index e6953e4..065b1aa 100644
--- a/drivers/net/mvpp2/mrvl_flow.c
+++ b/drivers/net/mvpp2/mrvl_flow.c
@@ -11,7 +11,7 @@
 
 #include <arpa/inet.h>
 
-#include "mrvl_ethdev.h"
+#include "mrvl_flow.h"
 #include "mrvl_qos.h"
 
 /** Number of rules in the classifier table. */
@@ -2790,3 +2790,34 @@ const struct rte_flow_ops mrvl_flow_ops = {
 	.flush = mrvl_flow_flush,
 	.isolate = mrvl_flow_isolate
 };
+
+/**
+ * Initialize flow resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_flow_init(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	LIST_INIT(&priv->flows);
+}
+
+/**
+ * Cleanup flow resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_flow_deinit(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	mrvl_flow_flush(dev, NULL);
+
+	if (priv->cls_tbl) {
+		pp2_cls_tbl_deinit(priv->cls_tbl);
+		priv->cls_tbl = NULL;
+	}
+}
diff --git a/drivers/net/mvpp2/mrvl_flow.h b/drivers/net/mvpp2/mrvl_flow.h
new file mode 100644
index 0000000..f63747c
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_flow.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#ifndef _MRVL_FLOW_H_
+#define _MRVL_FLOW_H_
+
+#include "mrvl_ethdev.h"
+
+void mrvl_flow_init(struct rte_eth_dev *dev);
+void mrvl_flow_deinit(struct rte_eth_dev *dev);
+
+#endif /* _MRVL_FLOW_H_ */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 06/12] net/mvpp2: add traffic manager support
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
                     ` (4 preceding siblings ...)
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 05/12] net/mvpp2: add init and deinit to flow Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 07/12] net/mvpp2: detach tx_qos from rx cls/qos config Tomasz Duszynski
                     ` (7 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski

Add traffic manager support.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 drivers/net/mvpp2/Makefile      |    1 +
 drivers/net/mvpp2/meson.build   |    3 +-
 drivers/net/mvpp2/mrvl_ethdev.c |   26 +
 drivers/net/mvpp2/mrvl_ethdev.h |   31 ++
 drivers/net/mvpp2/mrvl_tm.c     | 1009 +++++++++++++++++++++++++++++++++++++++
 drivers/net/mvpp2/mrvl_tm.h     |   15 +
 6 files changed, 1084 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/mvpp2/mrvl_tm.c
 create mode 100644 drivers/net/mvpp2/mrvl_tm.h

diff --git a/drivers/net/mvpp2/Makefile b/drivers/net/mvpp2/Makefile
index 4848d65..661d2cd 100644
--- a/drivers/net/mvpp2/Makefile
+++ b/drivers/net/mvpp2/Makefile
@@ -40,5 +40,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_qos.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_mtr.c
+SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_tm.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/mvpp2/meson.build b/drivers/net/mvpp2/meson.build
index f475511..70ef2d6 100644
--- a/drivers/net/mvpp2/meson.build
+++ b/drivers/net/mvpp2/meson.build
@@ -20,7 +20,8 @@ sources = files(
 	'mrvl_ethdev.c',
 	'mrvl_flow.c',
 	'mrvl_qos.c',
-	'mrvl_mtr.c'
+	'mrvl_mtr.c',
+	'mrvl_tm.c'
 )
 
 deps += ['cfgfile', 'common_mvep']
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 5e3a106..a1dc6b1 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -25,6 +25,7 @@
 #include "mrvl_qos.h"
 #include "mrvl_flow.h"
 #include "mrvl_mtr.h"
+#include "mrvl_tm.h"
 
 /* bitmask with reserved hifs */
 #define MRVL_MUSDK_HIFS_RESERVED 0x0F
@@ -340,6 +341,10 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 	priv->ppio_params.maintain_stats = 1;
 	priv->nb_rx_queues = dev->data->nb_rx_queues;
 
+	ret = mrvl_tm_init(dev);
+	if (ret < 0)
+		return ret;
+
 	if (dev->data->nb_rx_queues == 1 &&
 	    dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_RSS) {
 		MRVL_LOG(WARNING, "Disabling hash for 1 rx queue");
@@ -794,6 +799,7 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 	}
 
 	mrvl_flush_bpool(dev);
+	mrvl_tm_deinit(dev);
 
 	if (priv->ppio) {
 		pp2_ppio_deinit(priv->ppio);
@@ -1894,6 +1900,25 @@ mrvl_mtr_ops_get(struct rte_eth_dev *dev __rte_unused, void *ops)
 	return 0;
 }
 
+/**
+ * DPDK callback to get rte_tm callbacks.
+ *
+ * @param dev
+ *   Pointer to the device structure.
+ * @param ops
+ *   Pointer to pass the tm ops.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *ops)
+{
+	*(const void **)ops = &mrvl_tm_ops;
+
+	return 0;
+}
+
 static const struct eth_dev_ops mrvl_ops = {
 	.dev_configure = mrvl_dev_configure,
 	.dev_start = mrvl_dev_start,
@@ -1932,6 +1957,7 @@ static const struct eth_dev_ops mrvl_ops = {
 	.rss_hash_conf_get = mrvl_rss_hash_conf_get,
 	.filter_ctrl = mrvl_eth_filter_ctrl,
 	.mtr_ops_get = mrvl_mtr_ops_get,
+	.tm_ops_get = mrvl_tm_ops_get,
 };
 
 /**
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index de423a9..984f31e 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -10,6 +10,7 @@
 #include <rte_spinlock.h>
 #include <rte_flow_driver.h>
 #include <rte_mtr_driver.h>
+#include <rte_tm_driver.h>
 
 /*
  * container_of is defined by both DPDK and MUSDK,
@@ -134,6 +135,29 @@ struct mrvl_mtr {
 	struct pp2_cls_plcr *plcr;
 };
 
+struct mrvl_tm_shaper_profile {
+	LIST_ENTRY(mrvl_tm_shaper_profile) next;
+	uint32_t id;
+	int refcnt;
+	struct rte_tm_shaper_params params;
+};
+
+enum {
+	MRVL_NODE_PORT,
+	MRVL_NODE_QUEUE,
+};
+
+struct mrvl_tm_node {
+	LIST_ENTRY(mrvl_tm_node) next;
+	uint32_t id;
+	uint32_t type;
+	int refcnt;
+	struct mrvl_tm_node *parent;
+	struct mrvl_tm_shaper_profile *profile;
+	uint8_t weight;
+	uint64_t stats_mask;
+};
+
 struct mrvl_priv {
 	/* Hot fields, used in fast path. */
 	struct pp2_bpool *bpool;  /**< BPool pointer */
@@ -173,6 +197,10 @@ struct mrvl_priv {
 	LIST_HEAD(profiles, mrvl_mtr_profile) profiles;
 	LIST_HEAD(mtrs, mrvl_mtr) mtrs;
 	uint32_t used_plcrs;
+
+	LIST_HEAD(shaper_profiles, mrvl_tm_shaper_profile) shaper_profiles;
+	LIST_HEAD(nodes, mrvl_tm_node) nodes;
+	uint64_t rate_max;
 };
 
 /** Flow operations forward declaration. */
@@ -181,6 +209,9 @@ extern const struct rte_flow_ops mrvl_flow_ops;
 /** Meter operations forward declaration. */
 extern const struct rte_mtr_ops mrvl_mtr_ops;
 
+/** Traffic manager operations forward declaration. */
+extern const struct rte_tm_ops mrvl_tm_ops;
+
 /** Current log type. */
 extern int mrvl_logtype;
 
diff --git a/drivers/net/mvpp2/mrvl_tm.c b/drivers/net/mvpp2/mrvl_tm.c
new file mode 100644
index 0000000..3de8997
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_tm.c
@@ -0,0 +1,1009 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#include <rte_malloc.h>
+
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "mrvl_tm.h"
+
+/** Minimum rate value in Bytes/s */
+#define MRVL_RATE_MIN (PP2_PPIO_MIN_CIR * 1000 / 8)
+
+/** Minimum burst size in Bytes */
+#define MRVL_BURST_MIN (PP2_PPIO_MIN_CBS * 1000)
+
+/** Maximum burst size in Bytes */
+#define MRVL_BURST_MAX 256000000
+
+/** Maximum WRR weight */
+#define MRVL_WEIGHT_MAX 255
+
+/**
+ * Get maximum port rate in Bytes/s.
+ *
+ * @param dev Pointer to the device.
+ * @param rate Pointer to the rate.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_get_max_rate(struct rte_eth_dev *dev, uint64_t *rate)
+{
+	struct ethtool_cmd edata;
+	struct ifreq req;
+	int ret, fd;
+
+	memset(&edata, 0, sizeof(edata));
+	memset(&req, 0, sizeof(req));
+	edata.cmd = ETHTOOL_GSET;
+	strcpy(req.ifr_name, dev->data->name);
+	req.ifr_data = (void *)&edata;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd == -1)
+		return -1;
+
+	ret = ioctl(fd, SIOCETHTOOL, &req);
+	if (ret == -1) {
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+
+	*rate = ethtool_cmd_speed(&edata) * 1000 * 1000 / 8;
+
+	return 0;
+}
+
+/**
+ * Initialize traffic manager related data.
+ *
+ * @param dev Pointer to the device.
+ * @returns 0 on success, failure otherwise.
+ */
+int
+mrvl_tm_init(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	LIST_INIT(&priv->shaper_profiles);
+	LIST_INIT(&priv->nodes);
+
+	if (priv->rate_max)
+		return 0;
+
+	return mrvl_get_max_rate(dev, &priv->rate_max);
+}
+
+/**
+ * Cleanup traffic manager related data.
+ *
+ * @param dev Pointer to the device.
+ */
+void mrvl_tm_deinit(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile =
+		LIST_FIRST(&priv->shaper_profiles);
+	struct mrvl_tm_node *node = LIST_FIRST(&priv->nodes);
+
+	while (profile) {
+		struct mrvl_tm_shaper_profile *next = LIST_NEXT(profile, next);
+
+		LIST_REMOVE(profile, next);
+		rte_free(profile);
+		profile = next;
+	}
+
+	while (node) {
+		struct mrvl_tm_node *next = LIST_NEXT(node, next);
+
+		LIST_REMOVE(node, next);
+		rte_free(node);
+		node = next;
+	}
+}
+
+/**
+ * Get node using its id.
+ *
+ * @param priv Pointer to the port's private data.
+ * @param node_id Id used by this node.
+ * @returns Pointer to the node if exists, NULL otherwise.
+ */
+static struct mrvl_tm_node *
+mrvl_node_from_id(struct mrvl_priv *priv, uint32_t node_id)
+{
+	struct mrvl_tm_node *node;
+
+	LIST_FOREACH(node, &priv->nodes, next)
+		if (node->id == node_id)
+			return node;
+
+	return NULL;
+}
+
+/**
+ * Check whether node is leaf or root.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id used by this node.
+ * @param is_leaf Pointer to flag indicating whether node is a leaf.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_type_get(struct rte_eth_dev *dev, uint32_t node_id, int *is_leaf,
+		   struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	if (!is_leaf)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	*is_leaf = node->type == MRVL_NODE_QUEUE ? 1 : 0;
+
+	return 0;
+}
+
+/**
+ * Get traffic manager capabilities.
+ *
+ * @param dev Pointer to the device (unused).
+ * @param cap Pointer to the capabilities.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_capabilities_get(struct rte_eth_dev *dev,
+		      struct rte_tm_capabilities *cap,
+		      struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	if (!cap)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Capabilities are missing\n");
+
+	memset(cap, 0, sizeof(*cap));
+
+	cap->n_nodes_max = 1 + dev->data->nb_tx_queues; /* port + txqs number */
+	cap->n_levels_max = 2; /* port level + txqs level */
+	cap->non_leaf_nodes_identical = 1;
+	cap->leaf_nodes_identical = 1;
+
+	cap->shaper_n_max = cap->n_nodes_max;
+	cap->shaper_private_n_max = cap->shaper_n_max;
+	cap->shaper_private_rate_min = MRVL_RATE_MIN;
+	cap->shaper_private_rate_max = priv->rate_max;
+
+	cap->sched_n_children_max = dev->data->nb_tx_queues;
+	cap->sched_sp_n_priorities_max = dev->data->nb_tx_queues;
+	cap->sched_wfq_n_children_per_group_max = dev->data->nb_tx_queues;
+	cap->sched_wfq_n_groups_max = 1;
+	cap->sched_wfq_weight_max = MRVL_WEIGHT_MAX;
+
+	cap->dynamic_update_mask = RTE_TM_UPDATE_NODE_SUSPEND_RESUME |
+				   RTE_TM_UPDATE_NODE_STATS;
+	cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
+
+	return 0;
+}
+
+/**
+ * Get traffic manager hierarchy level capabilities.
+ *
+ * @param dev Pointer to the device.
+ * @param level_id Id of the level.
+ * @param cap Pointer to the level capabilities.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_level_capabilities_get(struct rte_eth_dev *dev,
+			    uint32_t level_id,
+			    struct rte_tm_level_capabilities *cap,
+			    struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	if (!cap)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	memset(cap, 0, sizeof(*cap));
+
+	if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_LEVEL_ID,
+					 NULL, "Wrong level id\n");
+
+	if (level_id == MRVL_NODE_PORT) {
+		cap->n_nodes_max = 1;
+		cap->n_nodes_nonleaf_max = 1;
+		cap->non_leaf_nodes_identical = 1;
+
+		cap->nonleaf.shaper_private_supported = 1;
+		cap->nonleaf.shaper_private_rate_min = MRVL_RATE_MIN;
+		cap->nonleaf.shaper_private_rate_max = priv->rate_max;
+
+		cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
+		cap->nonleaf.sched_sp_n_priorities_max = 1;
+		cap->nonleaf.sched_wfq_n_children_per_group_max =
+			dev->data->nb_tx_queues;
+		cap->nonleaf.sched_wfq_n_groups_max = 1;
+		cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
+		cap->nonleaf.stats_mask = RTE_TM_STATS_N_PKTS |
+					  RTE_TM_STATS_N_BYTES;
+	} else { /* level_id == MRVL_NODE_QUEUE */
+		cap->n_nodes_max = dev->data->nb_tx_queues;
+		cap->n_nodes_leaf_max = dev->data->nb_tx_queues;
+		cap->leaf_nodes_identical = 1;
+
+		cap->leaf.shaper_private_supported = 1;
+		cap->leaf.shaper_private_rate_min = MRVL_RATE_MIN;
+		cap->leaf.shaper_private_rate_max = priv->rate_max;
+		cap->leaf.stats_mask = RTE_TM_STATS_N_PKTS;
+	}
+
+	return 0;
+}
+
+/**
+ * Get node capabilities.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param cap Pointer to the capabilities.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_capabilities_get(struct rte_eth_dev *dev, uint32_t node_id,
+			   struct rte_tm_node_capabilities *cap,
+			   struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	if (!cap)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	memset(cap, 0, sizeof(*cap));
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	cap->shaper_private_supported = 1;
+	cap->shaper_private_rate_min = MRVL_RATE_MIN;
+	cap->shaper_private_rate_max = priv->rate_max;
+
+	if (node->type == MRVL_NODE_PORT) {
+		cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
+		cap->nonleaf.sched_sp_n_priorities_max = 1;
+		cap->nonleaf.sched_wfq_n_children_per_group_max =
+			dev->data->nb_tx_queues;
+		cap->nonleaf.sched_wfq_n_groups_max = 1;
+		cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
+		cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
+	} else {
+		cap->stats_mask = RTE_TM_STATS_N_PKTS;
+	}
+
+	return 0;
+}
+
+/**
+ * Get shaper profile using its id.
+ *
+ * @param priv Pointer to the port's private data.
+ * @param shaper_profile_id Id used by the shaper.
+ * @returns Pointer to the shaper profile if exists, NULL otherwise.
+ */
+static struct mrvl_tm_shaper_profile *
+mrvl_shaper_profile_from_id(struct mrvl_priv *priv, uint32_t shaper_profile_id)
+{
+	struct mrvl_tm_shaper_profile *profile;
+
+	LIST_FOREACH(profile, &priv->shaper_profiles, next)
+		if (profile->id == shaper_profile_id)
+			return profile;
+
+	return NULL;
+}
+
+/**
+ * Add a new shaper profile.
+ *
+ * @param dev Pointer to the device.
+ * @param shaper_profile_id Id of the new profile.
+ * @param params Pointer to the shaper profile parameters.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_shaper_profile_add(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
+			struct rte_tm_shaper_params *params,
+			struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile;
+
+	if (!params)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	if (params->committed.rate)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE,
+				NULL, "Committed rate not supported\n");
+
+	if (params->committed.size)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE,
+				NULL, "Committed bucket size not supported\n");
+
+	if (params->peak.rate < MRVL_RATE_MIN ||
+	    params->peak.rate > priv->rate_max)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE,
+				NULL, "Peak rate is out of range\n");
+
+	if (params->peak.size < MRVL_BURST_MIN ||
+	    params->peak.size > MRVL_BURST_MAX)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE,
+				NULL, "Peak size is out of range\n");
+
+	if (shaper_profile_id == RTE_TM_SHAPER_PROFILE_ID_NONE)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Wrong shaper profile id\n");
+
+	profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
+	if (profile)
+		return -rte_tm_error_set(error, EEXIST,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Profile id already exists\n");
+
+	profile = rte_zmalloc_socket(NULL, sizeof(*profile), 0,
+				     rte_socket_id());
+	if (!profile)
+		return -rte_tm_error_set(error, ENOMEM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	profile->id = shaper_profile_id;
+	rte_memcpy(&profile->params, params, sizeof(profile->params));
+
+	LIST_INSERT_HEAD(&priv->shaper_profiles, profile, next);
+
+	return 0;
+}
+
+/**
+ * Remove a shaper profile.
+ *
+ * @param dev Pointer to the device.
+ * @param shaper_profile_id Id of the shaper profile.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_shaper_profile_delete(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
+			   struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile;
+
+	profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
+	if (!profile)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Profile id does not exist\n");
+
+	if (profile->refcnt)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Profile is used\n");
+
+	LIST_REMOVE(profile, next);
+	rte_free(profile);
+
+	return 0;
+}
+
+/**
+ * Check node parameters.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id used by the node.
+ * @param priority Priority value.
+ * @param weight Weight value.
+ * @param level_id Id of the level.
+ * @param params Pointer to the node parameters.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_check_params(struct rte_eth_dev *dev, uint32_t node_id,
+		       uint32_t priority, uint32_t weight, uint32_t level_id,
+		       struct rte_tm_node_params *params,
+		       struct rte_tm_error *error)
+{
+	if (node_id == RTE_TM_NODE_ID_NULL)
+		return -rte_tm_error_set(error, EINVAL, RTE_TM_NODE_ID_NULL,
+					 NULL, "Node id is invalid\n");
+
+	if (priority)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_NODE_PRIORITY,
+					 NULL, "Priority should be 0\n");
+
+	if (weight > MRVL_WEIGHT_MAX)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_NODE_WEIGHT,
+					 NULL, "Weight is out of range\n");
+
+	if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_LEVEL_ID,
+					 NULL, "Wrong level id\n");
+
+	if (!params)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	if (params->shared_shaper_id)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID,
+				NULL, "Shared shaper is not supported\n");
+
+	if (params->n_shared_shapers)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS,
+				NULL, "Shared shaper is not supported\n");
+
+	/* verify port (root node) settings */
+	if (node_id >= dev->data->nb_tx_queues) {
+		if (params->nonleaf.wfq_weight_mode)
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE,
+				NULL, "WFQ is not supported\n");
+
+		if (params->nonleaf.n_sp_priorities != 1)
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES,
+				NULL, "SP is not supported\n");
+
+		if (params->stats_mask & ~(RTE_TM_STATS_N_PKTS |
+					   RTE_TM_STATS_N_BYTES))
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+				NULL,
+				"Requested port stats are not supported\n");
+
+		return 0;
+	}
+
+	/* verify txq (leaf node) settings */
+	if (params->leaf.cman)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN,
+					 NULL,
+					 "Congestion mngmt is not supported\n");
+
+	if (params->leaf.wred.wred_profile_id)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID,
+				NULL, "WRED is not supported\n");
+
+	if (params->leaf.wred.shared_wred_context_id)
+		return -rte_tm_error_set(error, EINVAL,
+			RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID,
+			NULL, "WRED is not supported\n");
+
+	if (params->leaf.wred.n_shared_wred_contexts)
+		return -rte_tm_error_set(error, EINVAL,
+			RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS,
+			NULL, "WRED is not supported\n");
+
+	if (params->stats_mask & ~RTE_TM_STATS_N_PKTS)
+		return -rte_tm_error_set(error, EINVAL,
+			RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+			NULL,
+			"Requested txq stats are not supported\n");
+
+	return 0;
+}
+
+/**
+ * Add a new node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param parent_node_id Id of the parent node.
+ * @param priority Priority value.
+ * @param weight Weight value.
+ * @param level_id Id of the level.
+ * @param params Pointer to the node parameters.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_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 mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile = NULL;
+	struct mrvl_tm_node *node, *parent = NULL;
+	int ret;
+
+	if (priv->ppio)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Port is already started\n");
+
+	ret = mrvl_node_check_params(dev, node_id, priority, weight, level_id,
+				     params, error);
+	if (ret)
+		return ret;
+
+	if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE) {
+		profile = mrvl_shaper_profile_from_id(priv,
+						 params->shaper_profile_id);
+		if (!profile)
+			return -rte_tm_error_set(error, ENODEV,
+					RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					NULL, "Shaper id does not exist\n");
+	}
+
+	if (parent_node_id == RTE_TM_NODE_ID_NULL) {
+		LIST_FOREACH(node, &priv->nodes, next) {
+			if (node->type != MRVL_NODE_PORT)
+				continue;
+
+			return -rte_tm_error_set(error, EINVAL,
+						 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						 NULL, "Root node exists\n");
+		}
+	} else {
+		parent = mrvl_node_from_id(priv, parent_node_id);
+		if (!parent)
+			return -rte_tm_error_set(error, EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
+					NULL, "Node id does not exist\n");
+	}
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id already exists\n");
+
+	node = rte_zmalloc_socket(NULL, sizeof(*node), 0, rte_socket_id());
+	if (!node)
+		return -rte_tm_error_set(error, ENOMEM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	node->id = node_id;
+	node->type = parent_node_id == RTE_TM_NODE_ID_NULL ? MRVL_NODE_PORT :
+							     MRVL_NODE_QUEUE;
+
+	if (parent) {
+		node->parent = parent;
+		parent->refcnt++;
+	}
+
+	if (profile) {
+		node->profile = profile;
+		profile->refcnt++;
+	}
+
+	node->weight = weight;
+	node->stats_mask = params->stats_mask;
+
+	LIST_INSERT_HEAD(&priv->nodes, node, next);
+
+	return 0;
+}
+
+/**
+ * Delete a node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
+		 struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	if (priv->ppio) {
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Port is already started\n");
+	}
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (node->refcnt)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id is used\n");
+
+	if (node->parent)
+		node->parent->refcnt--;
+
+	if (node->profile)
+		node->profile->refcnt--;
+
+	LIST_REMOVE(node, next);
+	rte_free(node);
+
+	return 0;
+}
+
+/**
+ * Helper for suspending specific tx queue.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id used by this node.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int mrvl_node_suspend_one(struct rte_eth_dev *dev, uint32_t node_id,
+				 struct rte_tm_error *error)
+{
+	int ret = dev->dev_ops->tx_queue_stop(dev, node_id);
+	if (ret)
+		return -rte_tm_error_set(error, ret,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Failed to suspend a txq\n");
+
+	return 0;
+}
+
+/**
+ * Suspend a node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param error Pointer to the error.
+ * returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_suspend(struct rte_eth_dev *dev, uint32_t node_id,
+		  struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node, *tmp;
+	int ret;
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (!node->parent) {
+		LIST_FOREACH(tmp, &priv->nodes, next) {
+			if (!tmp->parent)
+				continue;
+
+			if (node != tmp->parent)
+				continue;
+
+			ret = mrvl_node_suspend_one(dev, tmp->id, error);
+			if (ret)
+				return ret;
+		}
+
+		return 0;
+	}
+
+	return mrvl_node_suspend_one(dev, node_id, error);
+}
+
+/**
+ * Resume a node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param error Pointer to the error.
+ * returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_resume(struct rte_eth_dev *dev, uint32_t node_id,
+		 struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+	int ret;
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+
+	if (!node->parent)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Cannot suspend a port\n");
+
+	ret = dev->dev_ops->tx_queue_start(dev, node_id);
+	if (ret)
+		return -rte_tm_error_set(error, ret,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Failed to resume a txq\n");
+	return 0;
+}
+
+/**
+ * Apply traffic manager hierarchy.
+ *
+ * @param dev Pointer to the device.
+ * @param clear_on_fail Flag indicating whether to do cleanup on the failure.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_hierarchy_commit(struct rte_eth_dev *dev, int clear_on_fail,
+		      struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+	int ret;
+
+	if (priv->ppio) {
+		ret = -rte_tm_error_set(error, EPERM,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					NULL, "Port is already started\n");
+		goto out;
+	}
+
+	LIST_FOREACH(node, &priv->nodes, next) {
+		struct pp2_ppio_outq_params *p;
+
+		if (node->type == MRVL_NODE_PORT) {
+			if (!node->profile)
+				continue;
+
+			priv->ppio_params.rate_limit_enable = 1;
+			priv->ppio_params.rate_limit_params.cir =
+				node->profile->params.peak.rate * 8 / 1000;
+			priv->ppio_params.rate_limit_params.cbs =
+				node->profile->params.peak.size / 1000;
+
+			MRVL_LOG(INFO,
+				"Port rate limit overrides txqs rate limit");
+
+			continue;
+		}
+
+		if (node->id >= dev->data->nb_tx_queues) {
+			ret = -rte_tm_error_set(error, EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_ID, NULL,
+					"Not enough txqs are configured\n");
+			goto out;
+		}
+
+		p = &priv->ppio_params.outqs_params.outqs_params[node->id];
+
+		if (node->weight) {
+			p->sched_mode = PP2_PPIO_SCHED_M_WRR;
+			p->weight = node->weight;
+		} else {
+			p->sched_mode = PP2_PPIO_SCHED_M_SP;
+			p->weight = 0;
+		}
+
+		if (node->profile) {
+			p->rate_limit_enable = 1;
+			/* convert Bytes/s to kilo bits/s */
+			p->rate_limit_params.cir =
+				node->profile->params.peak.rate * 8 / 1000;
+			/* convert bits to kilo bits */
+			p->rate_limit_params.cbs =
+				node->profile->params.peak.size / 1000;
+		} else {
+			p->rate_limit_enable = 0;
+			p->rate_limit_params.cir = 0;
+			p->rate_limit_params.cbs = 0;
+		}
+	}
+
+	/* reset to defaults in case applied tm hierarchy is empty */
+	if (LIST_EMPTY(&priv->nodes)) {
+		int i;
+
+		for (i = 0; i < priv->ppio_params.outqs_params.num_outqs; i++) {
+			struct pp2_ppio_outq_params *p =
+				&priv->ppio_params.outqs_params.outqs_params[i];
+
+			p->sched_mode = PP2_PPIO_SCHED_M_WRR;
+			p->weight = 0;
+			p->rate_limit_enable = 0;
+			p->rate_limit_params.cir = 0;
+			p->rate_limit_params.cbs = 0;
+		}
+	}
+
+	return 0;
+out:
+	if (clear_on_fail) {
+		mrvl_tm_deinit(dev);
+		mrvl_tm_init(dev);
+	}
+
+	return ret;
+}
+
+/**
+ * Read statistics counters for current node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param stats Pointer to the statistics counters.
+ * @param stats_mask Pointer to mask of enabled statistics counters
+ *                   that are retrieved.
+ * @param clear Flag indicating whether to clear statistics.
+ *              Non-zero value clears statistics.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_stats_read(struct rte_eth_dev *dev, uint32_t node_id,
+		     struct rte_tm_node_stats *stats, uint64_t *stats_mask,
+		     int clear, struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+	int ret;
+
+	if (!priv->ppio) {
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Port is not started\n");
+	}
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (stats_mask)
+		*stats_mask = node->stats_mask;
+
+	if (!stats)
+		return 0;
+
+	memset(stats, 0, sizeof(*stats));
+
+	if (!node->parent) {
+		struct pp2_ppio_statistics s;
+
+		memset(&s, 0, sizeof(s));
+		ret = pp2_ppio_get_statistics(priv->ppio, &s, clear);
+		if (ret)
+			return -rte_tm_error_set(error, -ret,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to read port statistics\n");
+
+		if (node->stats_mask & RTE_TM_STATS_N_PKTS)
+			stats->n_pkts = s.tx_packets;
+
+		if (node->stats_mask & RTE_TM_STATS_N_BYTES)
+			stats->n_bytes = s.tx_bytes;
+	} else {
+		struct pp2_ppio_outq_statistics s;
+
+		memset(&s, 0, sizeof(s));
+		ret = pp2_ppio_outq_get_statistics(priv->ppio, node_id, &s,
+						   clear);
+		if (ret)
+			return -rte_tm_error_set(error, -ret,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to read txq statistics\n");
+
+		if (node->stats_mask & RTE_TM_STATS_N_PKTS)
+			stats->n_pkts = s.deq_desc;
+	}
+
+	return 0;
+}
+
+/**
+ * Update node statistics.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param stats_mask Bitmask of statistics counters to be enabled.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_stats_update(struct rte_eth_dev *dev, uint32_t node_id,
+		       uint64_t stats_mask, struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (!node->parent) {
+		if (stats_mask & ~(RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES))
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+				NULL,
+				"Requested port stats are not supported\n");
+	} else {
+		if (stats_mask & ~RTE_TM_STATS_N_PKTS)
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+				NULL,
+				"Requested txq stats are not supported\n");
+	}
+
+	node->stats_mask = stats_mask;
+
+	return 0;
+}
+
+const struct rte_tm_ops mrvl_tm_ops = {
+	.node_type_get = mrvl_node_type_get,
+	.capabilities_get = mrvl_capabilities_get,
+	.level_capabilities_get = mrvl_level_capabilities_get,
+	.node_capabilities_get = mrvl_node_capabilities_get,
+	.shaper_profile_add = mrvl_shaper_profile_add,
+	.shaper_profile_delete = mrvl_shaper_profile_delete,
+	.node_add = mrvl_node_add,
+	.node_delete = mrvl_node_delete,
+	.node_suspend = mrvl_node_suspend,
+	.node_resume = mrvl_node_resume,
+	.hierarchy_commit = mrvl_hierarchy_commit,
+	.node_stats_update = mrvl_node_stats_update,
+	.node_stats_read = mrvl_node_stats_read,
+};
diff --git a/drivers/net/mvpp2/mrvl_tm.h b/drivers/net/mvpp2/mrvl_tm.h
new file mode 100644
index 0000000..9d81ede
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_tm.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#ifndef _MRVL_TM_H_
+#define _MRVL_TM_H_
+
+#include "mrvl_ethdev.h"
+
+int mrvl_tm_init(struct rte_eth_dev *dev);
+void mrvl_tm_deinit(struct rte_eth_dev *dev);
+
+#endif /* _MRVL_TM_H_ */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 07/12] net/mvpp2: detach tx_qos from rx cls/qos config
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
                     ` (5 preceding siblings ...)
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 06/12] net/mvpp2: add traffic manager support Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 08/12] net/mvpp2: update MTU and MRU related calculations Tomasz Duszynski
                     ` (6 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Yuval Caduri

From: Yuval Caduri <cyuval@marvell.com>

Functional change:
Open receive cls/qos related features, only if the
config file contains an rx_related configuration entry.
This allows to configure tx_related entries, w/o unintentionally
opening rx cls/qos.

Code:
'use_global_defaults' is by default set to '1'.
Only if an rx_related entry was configured, it is updated to '0'.
rx cls/qos is performed only if 'use_global_defaults' is '0'.
Default TC configuration is now only mandatory when
'use_global_defaults' is '0'.

Signed-off-by: Yuval Caduri <cyuval@marvell.com>
Reviewed-by: Natalie Samsonov <nsamsono@marvell.com>
Tested-by: Natalie Samsonov <nsamsono@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c |  3 ++-
 drivers/net/mvpp2/mrvl_qos.c    | 41 +++++++++++++++++++++++------------------
 2 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index a1dc6b1..5643e7d 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -602,7 +602,8 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 	}
 
 	/* For default QoS config, don't start classifier. */
-	if (mrvl_qos_cfg) {
+	if (mrvl_qos_cfg  &&
+	    mrvl_qos_cfg->port[dev->data->port_id].use_global_defaults == 0) {
 		ret = mrvl_start_qos_mapping(priv);
 		if (ret) {
 			MRVL_LOG(ERR, "Failed to setup QoS mapping");
diff --git a/drivers/net/mvpp2/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c
index e039635..5d80c3e 100644
--- a/drivers/net/mvpp2/mrvl_qos.c
+++ b/drivers/net/mvpp2/mrvl_qos.c
@@ -324,6 +324,7 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
 	if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
 		return 0;
 
+	cfg->port[port].use_global_defaults = 0;
 	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
 	if (entry) {
 		n = get_entry_values(entry,
@@ -421,7 +422,7 @@ parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
 			cfg->port[port].policer_params.token_unit =
 				PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
 		} else {
-			RTE_LOG(ERR, PMD, "Unknown token: %s\n", entry);
+			MRVL_LOG(ERR, "Unknown token: %s", entry);
 			return -1;
 		}
 	}
@@ -438,7 +439,7 @@ parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
 			cfg->port[port].policer_params.color_mode =
 				PP2_CLS_PLCR_COLOR_AWARE_MODE;
 		} else {
-			RTE_LOG(ERR, PMD, "Error in parsing: %s\n", entry);
+			MRVL_LOG(ERR, "Error in parsing: %s", entry);
 			return -1;
 		}
 	}
@@ -518,28 +519,15 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 		snprintf(sec_name, sizeof(sec_name), "%s %d %s",
 			MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
 
+		/* Use global defaults, unless an override occurs */
+		(*cfg)->port[n].use_global_defaults = 1;
+
 		/* Skip ports non-existing in configuration. */
 		if (rte_cfgfile_num_sections(file, sec_name,
 				strlen(sec_name)) <= 0) {
-			(*cfg)->port[n].use_global_defaults = 1;
-			(*cfg)->port[n].mapping_priority =
-				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
 			continue;
 		}
 
-		entry = rte_cfgfile_get_entry(file, sec_name,
-				MRVL_TOK_DEFAULT_TC);
-		if (entry) {
-			if (get_val_securely(entry, &val) < 0 ||
-				val > USHRT_MAX)
-				return -1;
-			(*cfg)->port[n].default_tc = (uint8_t)val;
-		} else {
-			MRVL_LOG(ERR,
-				"Default Traffic Class required in custom configuration!");
-			return -1;
-		}
-
 		/*
 		 * Read per-port rate limiting. Setting that will
 		 * disable per-queue rate limiting.
@@ -573,6 +561,7 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 		entry = rte_cfgfile_get_entry(file, sec_name,
 				MRVL_TOK_MAPPING_PRIORITY);
 		if (entry) {
+			(*cfg)->port[n].use_global_defaults = 0;
 			if (!strncmp(entry, MRVL_TOK_VLAN_IP,
 				sizeof(MRVL_TOK_VLAN_IP)))
 				(*cfg)->port[n].mapping_priority =
@@ -602,6 +591,7 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 		entry = rte_cfgfile_get_entry(file, sec_name,
 				MRVL_TOK_PLCR_DEFAULT);
 		if (entry) {
+			(*cfg)->port[n].use_global_defaults = 0;
 			if (get_val_securely(entry, &val) < 0)
 				return -1;
 
@@ -627,6 +617,21 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 					"Error %d parsing port %d tc %d!\n",
 					ret, n, i);
 		}
+
+		entry = rte_cfgfile_get_entry(file, sec_name,
+					      MRVL_TOK_DEFAULT_TC);
+		if (entry) {
+			if (get_val_securely(entry, &val) < 0 ||
+			    val > USHRT_MAX)
+				return -1;
+			(*cfg)->port[n].default_tc = (uint8_t)val;
+		} else {
+			if ((*cfg)->port[n].use_global_defaults == 0) {
+				MRVL_LOG(ERR,
+					 "Default Traffic Class required in custom configuration!");
+				return -1;
+			}
+		}
 	}
 
 	return 0;
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 08/12] net/mvpp2: update MTU and MRU related calculations
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
                     ` (6 preceding siblings ...)
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 07/12] net/mvpp2: detach tx_qos from rx cls/qos config Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 09/12] net/mvpp2: align with MUSDK 18.09 Tomasz Duszynski
                     ` (5 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw

From: Natalie Samsonov <nsamsono@marvell.com>

This commit updates MTU and MRU related calculations.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Yelena Krivosheev <yelena@marvell.com>
Reviewed-by: Dmitri Epshtein <dima@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c | 70 +++++++++++++++++++++++++++++++----------
 drivers/net/mvpp2/mrvl_ethdev.h |  7 +++++
 2 files changed, 61 insertions(+), 16 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 5643e7d..035ee81 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -325,7 +325,7 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 
 	if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME)
 		dev->data->mtu = dev->data->dev_conf.rxmode.max_rx_pkt_len -
-				 ETHER_HDR_LEN - ETHER_CRC_LEN;
+				 MRVL_PP2_ETH_HDRS_LEN;
 
 	ret = mrvl_configure_rxqs(priv, dev->data->port_id,
 				  dev->data->nb_rx_queues);
@@ -375,21 +375,55 @@ static int
 mrvl_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
 	struct mrvl_priv *priv = dev->data->dev_private;
-	/* extra MV_MH_SIZE bytes are required for Marvell tag */
-	uint16_t mru = mtu + MV_MH_SIZE + ETHER_HDR_LEN + ETHER_CRC_LEN;
+	uint16_t mru;
+	uint16_t mbuf_data_size = 0; /* SW buffer size */
 	int ret;
 
-	if (mtu < ETHER_MIN_MTU || mru > MRVL_PKT_SIZE_MAX)
+	mru = MRVL_PP2_MTU_TO_MRU(mtu);
+	/*
+	 * min_rx_buf_size is equal to mbuf data size
+	 * if pmd didn't set it differently
+	 */
+	mbuf_data_size = dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM;
+	/* Prevent PMD from:
+	 * - setting mru greater than the mbuf size resulting in
+	 * hw and sw buffer size mismatch
+	 * - setting mtu that requires the support of scattered packets
+	 * when this feature has not been enabled/supported so far
+	 * (TODO check scattered_rx flag here once scattered RX is supported).
+	 */
+	if (mru + MRVL_PKT_OFFS > mbuf_data_size) {
+		mru = mbuf_data_size - MRVL_PKT_OFFS;
+		mtu = MRVL_PP2_MRU_TO_MTU(mru);
+		MRVL_LOG(WARNING, "MTU too big, max MTU possible limitted "
+			"by current mbuf size: %u. Set MTU to %u, MRU to %u",
+			mbuf_data_size, mtu, mru);
+	}
+
+	if (mtu < ETHER_MIN_MTU || mru > MRVL_PKT_SIZE_MAX) {
+		MRVL_LOG(ERR, "Invalid MTU [%u] or MRU [%u]", mtu, mru);
 		return -EINVAL;
+	}
+
+	dev->data->mtu = mtu;
+	dev->data->dev_conf.rxmode.max_rx_pkt_len = mru - MV_MH_SIZE;
 
 	if (!priv->ppio)
 		return 0;
 
 	ret = pp2_ppio_set_mru(priv->ppio, mru);
-	if (ret)
+	if (ret) {
+		MRVL_LOG(ERR, "Failed to change MRU");
 		return ret;
+	}
+
+	ret = pp2_ppio_set_mtu(priv->ppio, mtu);
+	if (ret) {
+		MRVL_LOG(ERR, "Failed to change MTU");
+		return ret;
+	}
 
-	return pp2_ppio_set_mtu(priv->ppio, mtu);
+	return 0;
 }
 
 /**
@@ -600,6 +634,9 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 		}
 		priv->vlan_flushed = 1;
 	}
+	ret = mrvl_mtu_set(dev, dev->data->mtu);
+	if (ret)
+		MRVL_LOG(ERR, "Failed to set MTU to %d", dev->data->mtu);
 
 	/* For default QoS config, don't start classifier. */
 	if (mrvl_qos_cfg  &&
@@ -1552,8 +1589,8 @@ mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 {
 	struct mrvl_priv *priv = dev->data->dev_private;
 	struct mrvl_rxq *rxq;
-	uint32_t min_size,
-		 max_rx_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	uint32_t frame_size, buf_size = rte_pktmbuf_data_room_size(mp);
+	uint32_t max_rx_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
 	int ret, tc, inq;
 	uint64_t offloads;
 
@@ -1568,15 +1605,16 @@ mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		return -EFAULT;
 	}
 
-	min_size = rte_pktmbuf_data_room_size(mp) - RTE_PKTMBUF_HEADROOM -
-		   MRVL_PKT_EFFEC_OFFS;
-	if (min_size < max_rx_pkt_len) {
-		MRVL_LOG(ERR,
-			"Mbuf size must be increased to %u bytes to hold up to %u bytes of data.",
-			max_rx_pkt_len + RTE_PKTMBUF_HEADROOM +
-			MRVL_PKT_EFFEC_OFFS,
+	frame_size = buf_size - RTE_PKTMBUF_HEADROOM - MRVL_PKT_EFFEC_OFFS;
+	if (frame_size < max_rx_pkt_len) {
+		MRVL_LOG(WARNING,
+			"Mbuf size must be increased to %u bytes to hold up "
+			"to %u bytes of data.",
+			buf_size + max_rx_pkt_len - frame_size,
 			max_rx_pkt_len);
-		return -EINVAL;
+		dev->data->dev_conf.rxmode.max_rx_pkt_len = frame_size;
+		MRVL_LOG(INFO, "Setting max rx pkt len to %u",
+			dev->data->dev_conf.rxmode.max_rx_pkt_len);
 	}
 
 	if (dev->data->rx_queues[idx]) {
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index 984f31e..f0ae983 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -72,6 +72,13 @@
 /** Minimum number of sent buffers to release from shadow queue to BM */
 #define MRVL_PP2_BUF_RELEASE_BURST_SIZE	64
 
+#define MRVL_PP2_VLAN_TAG_LEN		4
+#define MRVL_PP2_ETH_HDRS_LEN		(ETHER_HDR_LEN + ETHER_CRC_LEN + \
+					(2 * MRVL_PP2_VLAN_TAG_LEN))
+#define MRVL_PP2_HDRS_LEN		(MV_MH_SIZE + MRVL_PP2_ETH_HDRS_LEN)
+#define MRVL_PP2_MTU_TO_MRU(mtu)	((mtu) + MRVL_PP2_HDRS_LEN)
+#define MRVL_PP2_MRU_TO_MTU(mru)	((mru) - MRVL_PP2_HDRS_LEN)
+
 /** Maximum length of a match string */
 #define MRVL_MATCH_LEN 16
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 09/12] net/mvpp2: align with MUSDK 18.09
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
                     ` (7 preceding siblings ...)
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 08/12] net/mvpp2: update MTU and MRU related calculations Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation " Tomasz Duszynski
                     ` (4 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Tomasz Duszynski, Yuval Caduri

This patch introduces necessary changes required by MUSDK 18.09 library.

* As of MUSDK 18.09, pp2_cookie_t is no longer available. Now
  RX descriptor cookie is defined as plain u64 so existing cast
  is no longer valid.

* MUSDK 18.09 increased number of available bpools (buffer hw pools) by
  introducing dma regions support. Update mvpp2 driver accordingly.

* replace MV_NET_IP4_F_TOS with MV_NET_IP4_F_DSCP

  Before this patch, API allowed to configure a classification rule
  according to IPv4 TOS, which was not supported in classifier. This patch
  fixes this by using proper field.

* use 48 bit address mask

  We cannot get pointers exceeding 48 bits thus using 48 bit
  mask for extracting higher IOVA address bits is enough.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Signed-off-by: Yuval Caduri <cyuval@marvell.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Reviewed-by: Shlomi Gridish <sgridish@marvell.com>
Reviewed-by: Alan Winkowski <walan@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c | 10 ++++------
 drivers/net/mvpp2/mrvl_flow.c   |  3 ++-
 drivers/net/mvpp2/mrvl_qos.c    |  2 +-
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 035ee81..899a9e4 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -54,9 +54,7 @@
 #define MRVL_ARP_LENGTH 28
 
 #define MRVL_COOKIE_ADDR_INVALID ~0ULL
-
-#define MRVL_COOKIE_HIGH_ADDR_SHIFT	(sizeof(pp2_cookie_t) * 8)
-#define MRVL_COOKIE_HIGH_ADDR_MASK	(~0ULL << MRVL_COOKIE_HIGH_ADDR_SHIFT)
+#define MRVL_COOKIE_HIGH_ADDR_MASK 0xffffff0000000000
 
 /** Port Rx offload capabilities */
 #define MRVL_RX_OFFLOADS (DEV_RX_OFFLOAD_VLAN_FILTER | \
@@ -1544,7 +1542,7 @@ mrvl_fill_bpool(struct mrvl_rxq *rxq, int num)
 
 		entries[i].buff.addr =
 			rte_mbuf_data_iova_default(mbufs[i]);
-		entries[i].buff.cookie = (pp2_cookie_t)(uint64_t)mbufs[i];
+		entries[i].buff.cookie = (uint64_t)mbufs[i];
 		entries[i].bpool = bpool;
 	}
 
@@ -2180,7 +2178,7 @@ mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 		if (unlikely(status != PP2_DESC_ERR_OK)) {
 			struct pp2_buff_inf binf = {
 				.addr = rte_mbuf_data_iova_default(mbuf),
-				.cookie = (pp2_cookie_t)(uint64_t)mbuf,
+				.cookie = (uint64_t)mbuf,
 			};
 
 			pp2_bpool_put_buff(hif, bpool, &binf);
@@ -2441,7 +2439,7 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 			rte_mbuf_prefetch_part2(pref_pkt_hdr);
 		}
 
-		sq->ent[sq->head].buff.cookie = (pp2_cookie_t)(uint64_t)mbuf;
+		sq->ent[sq->head].buff.cookie = (uint64_t)mbuf;
 		sq->ent[sq->head].buff.addr =
 			rte_mbuf_data_iova_default(mbuf);
 		sq->ent[sq->head].bpool =
diff --git a/drivers/net/mvpp2/mrvl_flow.c b/drivers/net/mvpp2/mrvl_flow.c
index 065b1aa..ffd1dab 100644
--- a/drivers/net/mvpp2/mrvl_flow.c
+++ b/drivers/net/mvpp2/mrvl_flow.c
@@ -2437,7 +2437,8 @@ mrvl_create_cls_table(struct rte_eth_dev *dev, struct rte_flow *first_flow)
 
 	if (first_flow->pattern & F_IP4_TOS) {
 		key->proto_field[key->num_fields].proto = MV_NET_PROTO_IP4;
-		key->proto_field[key->num_fields].field.ipv4 = MV_NET_IP4_F_TOS;
+		key->proto_field[key->num_fields].field.ipv4 =
+							MV_NET_IP4_F_DSCP;
 		key->key_size += 1;
 		key->num_fields += 1;
 	}
diff --git a/drivers/net/mvpp2/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c
index 5d80c3e..7fd9703 100644
--- a/drivers/net/mvpp2/mrvl_qos.c
+++ b/drivers/net/mvpp2/mrvl_qos.c
@@ -654,7 +654,7 @@ setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
 	struct pp2_ppio_inq_params *inq_params;
 
 	param->pkt_offset = MRVL_PKT_OFFS;
-	param->pools[0] = bpool;
+	param->pools[0][0] = bpool;
 	param->default_color = color;
 
 	inq_params = rte_zmalloc_socket("inq_params",
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation with MUSDK 18.09
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
                     ` (8 preceding siblings ...)
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 09/12] net/mvpp2: align with MUSDK 18.09 Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-19 17:15     ` Ferruh Yigit
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 11/12] net/mvpp2: document MTR and TM usage Tomasz Duszynski
                     ` (3 subsequent siblings)
  13 siblings, 1 reply; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw

From: Natalie Samsonov <nsamsono@marvell.com>

Update documentation to align with MUSDK 18.09.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
---
 doc/guides/nics/mvpp2.rst | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/doc/guides/nics/mvpp2.rst b/doc/guides/nics/mvpp2.rst
index a452c8a..3b3f8c6 100644
--- a/doc/guides/nics/mvpp2.rst
+++ b/doc/guides/nics/mvpp2.rst
@@ -74,6 +74,7 @@ Features of the MVPP2 PMD are:
 - QoS
 - RX flow control
 - TX queue start/stop
+- Scattered TX frames
 
 
 Limitations
@@ -96,19 +97,19 @@ Prerequisites
 
   .. code-block:: console
 
-     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.52-armada-17.10
+     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.120-armada-18.09
 
 - Out of tree `mvpp2x_sysfs` kernel module sources
 
   .. code-block:: console
 
-     git clone https://github.com/MarvellEmbeddedProcessors/mvpp2x-marvell.git -b mvpp2x-armada-17.10
+     git clone https://github.com/MarvellEmbeddedProcessors/mvpp2x-marvell.git -b mvpp2x-armada-18.09
 
 - MUSDK (Marvell User-Space SDK) sources
 
   .. code-block:: console
 
-     git clone https://github.com/MarvellEmbeddedProcessors/musdk-marvell.git -b musdk-armada-17.10
+     git clone https://github.com/MarvellEmbeddedProcessors/musdk-marvell.git -b musdk-armada-18.09
 
   MUSDK is a light-weight library that provides direct access to Marvell's
   PPv2 (Packet Processor v2). Alternatively prebuilt MUSDK library can be
@@ -119,12 +120,6 @@ Prerequisites
   To get better understanding of the library one can consult documentation
   available in the ``doc`` top level directory of the MUSDK sources.
 
-  MUSDK must be configured with the following features:
-
-  .. code-block:: console
-
-     --enable-bpool-dma=64
-
 - DPDK environment
 
   Follow the DPDK :ref:`Getting Started Guide for Linux <linux_gsg>` to setup
@@ -140,6 +135,9 @@ The following options can be modified in the ``config`` file.
 
     Toggle compilation of the librte mvpp2 driver.
 
+    .. Note::
+
+       When MVPP2 PMD is enabled ``CONFIG_RTE_LIBRTE_MVNETA_PMD`` must be disabled
 
 QoS Configuration
 -----------------
@@ -314,7 +312,7 @@ Driver needs precompiled MUSDK library during compilation.
 
    export CROSS_COMPILE=<toolchain>/bin/aarch64-linux-gnu-
    ./bootstrap
-   ./configure --host=aarch64-linux-gnu --enable-bpool-dma=64
+   ./configure --host=aarch64-linux-gnu
    make install
 
 MUSDK will be installed to `usr/local` under current directory.
@@ -328,7 +326,8 @@ the path to the MUSDK installation directory needs to be exported.
    export LIBMUSDK_PATH=<musdk>/usr/local
    export CROSS=aarch64-linux-gnu-
    make config T=arm64-armv8a-linuxapp-gcc
-   sed -ri 's,(MVPP2_PMD=)n,\1y,' build/.config
+   sed -i "s/MVNETA_PMD=y/MVNETA_PMD=n/" build/.config
+   sed -i "s/MVPP2_PMD=n/MVPP2_PMD=y/" build/.config
    make
 
 Flow API
@@ -500,15 +499,14 @@ Usage Example
 -------------
 
 MVPP2 PMD requires extra out of tree kernel modules to function properly.
-`musdk_uio` and `mv_pp_uio` sources are part of the MUSDK. Please consult
+`musdk_cma` sources are part of the MUSDK. Please consult
 ``doc/musdk_get_started.txt`` for the detailed build instructions.
 For `mvpp2x_sysfs` please consult ``Documentation/pp22_sysfs.txt`` for the
 detailed build instructions.
 
 .. code-block:: console
 
-   insmod musdk_uio.ko
-   insmod mv_pp_uio.ko
+   insmod musdk_cma.ko
    insmod mvpp2x_sysfs.ko
 
 Additionally interfaces used by DPDK application need to be put up:
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 11/12] net/mvpp2: document MTR and TM usage
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
                     ` (9 preceding siblings ...)
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation " Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-23 22:45     ` Thomas Monjalon
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 12/12] net/mvpp2: add Tx S/G support Tomasz Duszynski
                     ` (2 subsequent siblings)
  13 siblings, 1 reply; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw

From: Natalie Samsonov <nsamsono@marvell.com>

Document MTR (metering) and TM (traffic management) usage plus
do some small updates here and there.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
---
 doc/guides/nics/img/mvpp2_tm.png | Bin 0 -> 5355 bytes
 doc/guides/nics/mvpp2.rst        | 386 +++++++++++++++++++++++++++++++++------
 2 files changed, 335 insertions(+), 51 deletions(-)
 create mode 100644 doc/guides/nics/img/mvpp2_tm.png

diff --git a/doc/guides/nics/img/mvpp2_tm.png b/doc/guides/nics/img/mvpp2_tm.png
new file mode 100644
index 0000000000000000000000000000000000000000..3c709bab43950c39578a6726ab570008bc722e2f
GIT binary patch
literal 5355
zcmeHL=U-FX(%vBudXXkgk$yk~Q3z53C{4tG2UHXUA}B>dITY!TXatcaBA^CDq^Ssr
zCm^CUrK6#X3B82Sh0sfYyYXJ{?|ttda6jD-N!EJy+B5T;HS^3&;x1U3^KwaW0RX^j
zan{5J03dj9oy`FQzty7x?ZF>NfQ|VXprlP|8r-nDpGKYrfOpB<%<F96{)p>Y8zcaP
zDFOfn2LM|jgqZ?>pyL2Ag8~5ECjfBJFZ1J{`T!v8X<>5uVu;gxmWHpCwopu(RsOlO
zTRdWBT=}-w#kM&8XB8m>H1-e8(tgE_My<kX7hxrLE-DX-`6+*}Q7JkP98}Xj94Uq!
zD-X6@Iz^jfX!t#}Zo&_aS1udq4OD#(?$$iCm@F<93ftY?UYL%RjykomJ{)cSJf<Xj
zXKZY21l;VE%vuru>K7NFETZ_#dTX7dceJvyv!n4WfgP@VK0ZDLsi{Kr==N21k2U?z
zh;Odm{jBgv8E*7eTXazv8@$#ngcrb9yRn0SArZn-XZ+&Qf!{!Mk#1cFrf*RKfJc(~
zC@WdfC@5=8tWlBdZ(#3oP)rV_Y*Y(CZ#_FioYvc`g>mrkV=tTj8z`RPF^1l%^8zR<
zT6(DN;9V@QfY@P{;s^f*9KMUkz<OeS0K{pp+qDG?OsM3M<NB=jB9Pxe`J0nGysvl(
z5LEY%ISg`mlO1k^3gIYKVfhXCUUC<cxFG2Stt}u>A^7TLel(_bQNZI8>u+HAP1|wJ
z7w}3L2I)+K!Xqc8DFAj<rsECAZ=mK<)^!gf?-1S)EO~jdz0f@Q@F3#3L1fr^$o86d
zuQM@X{pa9ZNZcl!jAtjbtQkaXJQNxJ@&v<66d%H=a>YN{<@(BvW>q6N*HmjqQ`NEc
zh1S`Rut$KW-A~TUfg;xlU)L~+hKQd<=76v+epG8j1n#0MBfx6HA{5$e@O8GU`0RSF
z<3ppHe5d-TI08h{s9O+SCyD&p;^trw-!FuAstODG;oWSUUe7AnmB``YR2>n@E*5%>
z8Of38ot0Q==k#Mj6E$v|ygegS8`B2fZpa;ENVQq*i%AqK&#3=1Ba0U@0$dqG=_t7o
zn+p(0)PE>A<A)17a2z-3Abg^N*qN`56(llVH$|>;qKw^7R>FD#yx*o}`^4G8lk9kP
z=W6D#DN7d_r>Mx_<Kz2agxT`FyhnzY5=!X-#d}j7pf>=#uH^KsJfY4clk`rLa1AuA
z(yEfCIPOB3@|Up7Eq1Q)V!Y6!H23*N@J1!`A2GjSqaR@IHoAK@XDY1BDXrTzno5rn
zeshqL@J6ZHog^Jpnm4RRnL5~<4s)ncGrwwCT;-ILyRACDs&Z&{M{YMtl#Muzx7!aj
zht0kjl-xtkQQ2V)fsu~U1eq)GU%=QcgM#5+V~Qj<e7i$_KXG*W96h~eY*@X4(o4k+
ztKTQ|a6(Ewo$Zk-{a5W6U^;BFfB{pJ=B!X>rh9);4`67gt>Vdy3K8)_$0nPE{F|CO
z*+SV<kLRZ?YzN;bPy=6<eXsvJYgJePH09_oQ$jBZqE}ke7G+uHPxSPN$d3j?Xb;5i
z8J|nAq0|e!B#9eWmOWsltbFI*PouIK4`nMsG(1RH=KRW1tH9aou_=ObY;gZJ#oY^d
z7xl;xCuw7vWhe|D83d+U+n!BiPZ)v|zQuODDge#24K^b%GA6^C?B@e*T=Ht&e8iEc
zlk7S6sV12_YA{r{cFlgGl`oacQ~oenfngcegI71rNJGIELqbD^$_kBw=sd4ycM~%#
z%N-OF=X;J>p=^T<0#-TqiNmM*T$9pgGo(Rv-}&^;F(HNv^JAsx?r7m-F-zisCuB$Z
zH#Ugt{j!TR%LOpgR`<RA%fKB7ny#C%$VFIm!)#5oiov<kD)>wYZr%B1r$CKgj<##Y
z1fK6hPFJ@YFskqxtk-e{!0aprZ(!LuH^#<g;Ikq#pp>yGRu%k+DNMl;W_O-`;hnzZ
z9xy!P{2<5f!?8hv@=)@I^=Q|0g3ORGwlDz#8o;t|^|{0zvD8R8D{PA(Px|e*W;|DI
z`hyJ9*HV8p{Q>fbcKbg)Qh}zF_G!F783Q0_;^1{i>|aOmEs$W>RsU-o#R@k!H}Bru
ztY|T=#xZx+hw=64k?)iC=BT9UmQ*FT?daRL;aQoP5zCbt=YxCNbt*d(o`o2!8@mdP
zTtTR*s~2{6cYklJ`S|f!QgSkR&6&QlwIxBB(?Mg&&y~bptr*(BcPbzywV$wy=AAb_
z1eHYHg(YaAc%ic!wJ=H#=8%~yT2t$hNkY)UPg*>0$D#P3+4lHo;6Kg*qW?Sh-}DRZ
zSmWyIsywVo&YN%lmY0{8eLYJxj(JfAhK8(SV`GD}u}xc(BV%JOTU)C|PY-KPOHstc
zF=_8Y?#DA|l1V_5N^mbRWoLJTA;*3&+#eGZ5utBUek<P`1-<y@&=o1Evwz@o1IOs?
zUfh(28O+L%EE3p3pvJXy=6=+jfx@d3*eM&WvB5O}TuRw)R{w1SA3EZxB$1KEKfBeh
zWk7_$Yhk>?o&W{FO92qcgo0)df0N5zs#%HZ0pROPe-^d99RuSCitaE<fq}KN1tLWJ
z?C~H$(fmePV;6Pfgf?pYsC3!PHx<7BC+ztDg#FKF|2H&zt}i!9N1vaZoLuL}A~&u%
zm8<ZKwMkA-OiV=bSy@{b=H}+I>r_-%D=LMwW)(&-HyBtrA3uK~iA35S-dXGSMV5~B
zjvN;^H1{emFHZ&Bx{aNboV}M7FvE|N$H!flARa%fc4mJNg4yNpD@(gO+lpZj`27<W
z(5{wmahIa_J^JpL(ZlgrCUd!+hWi+G;fLYQN;i6^^^twi7V^Zi%X)RU`|y`%GWWJ-
z2_%=a;lf7LwLzxO2?3qhx@$kOX3N?q3#>LWoTEGoL{N1HE<A$4kLAC^^|trWd2kA)
zQJafAdB`lkA_dK-c==q0e%zeHr?CeaU02R{X|D(9W}g&D@7SW(lcXE6{Jtt^qKxfQ
zgNO&z_eBg-T%gxEi=(Y7S(JX_9Mp2aUN4mmAEKP7P`cYFD#2mtv9mlXq8V^7t@Ik0
z*tLq>a9J_ObFQ4^*mw6VJymlyo8#O^Jd_5)IC;TjMpLG2BrH9m5|F$&1x-U82A9-4
z&O!Z`SYF9r?<K#B!xC|HC26PALTdSCPN3AIF^Tt0lWv6TM==>qYW->LD&<3q_TLcx
zGX0>>3=0pcI|Y8_EN@h1A2i%!cI*2hX4dKSf`~_zqD+o$g%@!P_e6$@(Aj(H>p@GD
zOOB3?gFy$Y=(|*s`{4UyI^sD$RSm`)8XDx+-_PdbMf=mXiHIns8088_vo5_kcym6e
zsV_gXmCQ3S(9-oGG9v2}CS&{6lbz~puhbH=8F)B3N;>|gcQz+w;KRuv)ZL878yv)|
zjEaOuIKn&vEQKLms#!=K4=gY7uR#XrLMXbGcc^>d*DCWCCIG&BKE16#U#Yh7b!UjK
z>~w{CAUqI`SUu<~2|CR?jK+c$fr?N-!n5^Rd`?elb89f0vp9Qsn+1(YOnZNBtc&{i
zE<gCZje6=kFo|wWEM}EgUVy+SbRcl6L`BmLxr7{24vCQ$0O~&FPAcqR1sRs|ShBLP
zLb8Muy16tVpFCu-u`=Dg0)8x_3g*6k3SPK27u;IiD+NVkkVwS5M0{I;R7BlpGajeI
zpC0)9SdZRVye>G}+Ma*q1idrYTx~7f)7h(r4?OLSoEHS`!P9P*mVE{%9qr&32U5Z@
zG_`y7OGEa=PAi*bf?>8{bT!9z{!Y~D%y;>}^0u!@;Fq_mosS&pOIns`_bS$}jNFEY
zP8`uvuPs2JRRdo}9eGzb5WUOP@oG@+CEs13=6x~4sla5%8_ripZ2H&Of-}?es&G%{
zwzr0ju4J6j3r;1yT|fMqLRm;<auJ*4X6A{>rH;&*Wk<S^rtD_t2d#x$pB9KI&$^`U
zx8*z0LT9>`-dA#ND7dw@p0?V>BEu<HrfziKO6l>RdC;Bd^Y?W*^UJaqu?bHqo}}vA
zjWo~xl_8@j=ZZ`CTgXzw1|=jqsCc#&ep5Pt%MI!3^~KDv{M*e_?k?xA+sP6vN+x9X
zGGb}6u(-o)p4URF%nI`uYlq-De6GhI(@k6+T%W?q5|v|(y|Z8a)uz}RN3)N#nfX&s
zWHYO$SU=+<51tLNc+vV&d;0L~!nvSSHc6_6j00NrdN{%Lj2I3$7nj0<KTdsp=&Cn%
zCFutXTo#VF@DR!q`fAbStxJT)i!+~Rq&$Odz1qxTke*gIety3q@19@qPB}IZKC$>W
zCb74mw@BY^zIks|)8y@4zk9|Ig@yjrBMRK`kAeB~Rl7Y_rlzm5tT(QuLujGrcu=W|
zeWJvaOpBji;*Y!d-9IwUcj7P<-Q}<AP7APfQqYOx@4z5Kt!^FC^pxVJOsPClODx)p
zDN_NctdfY}+(Yj?d@}AnR;4t@(56i54c9y3Y+vBa@(KC%0Nm5GgA4AjDRtQB8<v&A
zRCgDR*7xRvE9hL+L)SCYfv5f@8aK~-KT&NU-AN2QK1Tg0Tw*z#W9NG(@wQ3d_o?N4
zDfHIctHcxq;RCx}^`1oqvnwD^DQjR7)hTCpSD2a4^Z44ol7rwcQ!X6!znEv~XSrn&
z8cDmUiEugAViD3|cT1uwy>rDVs6T4<^dg)$Kf$6CMb@}XOws91GSPcX<SP$?>l!e3
zZ<5-~9M(@!|E^;wJl)c>K!+qLDZq#fs3ams^-HS0%8iSdzJ@l(`!X;2PK!K850qUn
zk0Gn+Ts?`dw@oj3X$i4ted4(KbUTWh;xRwH^fatgt;iy>&CyY`<Qgu~c(u)pFw%9~
zGCD>{w9Zl^D0Y0|PmYU$EytdRRNX<UPbRqb+(~o_!{ax~63VZbrRG0aoO!%q)4y0j
zvsjbyA=hoDG9FDndy%ps_gT^4L%){NiD)ggoTOPCH)|K4;3P92hNh?2eeu3WupFGx
zd0JtmQ4)|yiuXCJnmc{THNaUho}kv93l;w~%^mKthF3%M#&fOI2Z+h7-`2wWkU%nP
z$c7Gh6I<d^Pu`ZN(7wed&8G;VY@K|yP_{2q9n%~9%bTRF9T-U6W4icjkm)6RvO2n8
z4oal@pdTgof*dt_H&L~vahPQBy5^AvNK7Ag@d&&L?>>>$|6wx(stD*RB3ZO}74JU<
z@DC)2A66<ZzjJ5;J4H8qBL-=j`%aC1sygFlX>WFTDK~4_H{TXGNVpLAQCRDH8U&B`
z?Y4Cq5nae9fn8?2ltcXuaq?9e2l-I426&8-=d6qO?_iNcjc-N3_FKk+fe{4x(Eh6N
zHSB`~IlBcU*-2K)DJ=<Wb9u!2y|$RPg2LS~Z*c6XV`B;DLW0zaK~{VYf2OC4M`(Fk
z%l6-N23u3AsbSf$rMoSk!7uI|zX;7FDQmy)d)OIL`!CMFBJ#Bl<nRtESSUb^nIx*M
z2WZN_%0wr1?zKg@AXRO9zk8UTn(`3LNm@Ilub=7T>sy1&Rwq^bb3}{%8arj}KXy#o
ti<%uDA3wda5=aON0EaxVnuTof6LM+ivt4^5!G9wG3sWnTk~63~{{Y^!D~|vG

literal 0
HcmV?d00001

diff --git a/doc/guides/nics/mvpp2.rst b/doc/guides/nics/mvpp2.rst
index 3b3f8c6..e7f45c3 100644
--- a/doc/guides/nics/mvpp2.rst
+++ b/doc/guides/nics/mvpp2.rst
@@ -56,7 +56,7 @@ Features of the MVPP2 PMD are:
 
 - Speed capabilities
 - Link status
-- Queue start/stop
+- Tx Queue start/stop
 - MTU update
 - Jumbo frame
 - Promiscuous mode
@@ -70,12 +70,13 @@ Features of the MVPP2 PMD are:
 - L4 checksum offload
 - Packet type parsing
 - Basic stats
-- Extended stats
-- QoS
+- :ref:`Extended stats <extstats>`
 - RX flow control
-- TX queue start/stop
 - Scattered TX frames
-
+- :ref:`QoS <qossupport>`
+- :ref:`Flow API <flowapi>`
+- :ref:`Traffic metering and policing <mtrapi>`
+- :ref:`Traffic Management API <tmapi>`
 
 Limitations
 -----------
@@ -89,6 +90,20 @@ Limitations
   functionality. Current workaround is to reset board so that PPv2 has a
   chance to start in a sane state.
 
+- MUSDK architecture does not support changing configuration in run time.
+  All nessesary configurations should be done before first dev_start().
+
+- RX queue start/stop is not supported.
+
+- Current implementation does not support replacement of buffers in the HW buffer pool
+  at run time, so it is responsibility of the application to ensure that MTU does not exceed the configured buffer size.
+
+- Configuring TX flow control currently is not supported.
+
+- In current implementation, mechanism for acknowledging transmitted packets (``tx_done_cleanup``) is not supported.
+
+- Running more than one DPDK-MUSDK application simultaneously is not supported.
+
 
 Prerequisites
 -------------
@@ -139,6 +154,92 @@ The following options can be modified in the ``config`` file.
 
        When MVPP2 PMD is enabled ``CONFIG_RTE_LIBRTE_MVNETA_PMD`` must be disabled
 
+
+Building DPDK
+-------------
+
+Driver needs precompiled MUSDK library during compilation.
+
+.. code-block:: console
+
+   export CROSS_COMPILE=<toolchain>/bin/aarch64-linux-gnu-
+   ./bootstrap
+   ./configure --host=aarch64-linux-gnu
+   make install
+
+MUSDK will be installed to `usr/local` under current directory.
+For the detailed build instructions please consult ``doc/musdk_get_started.txt``.
+
+Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
+the path to the MUSDK installation directory needs to be exported.
+
+For additional instructions regarding DPDK cross compilation please refer to :doc:`Cross compile DPDK for ARM64 <../linux_gsg/cross_build_dpdk_for_arm64>`.
+
+.. code-block:: console
+
+   export LIBMUSDK_PATH=<musdk>/usr/local
+   export CROSS=<toolchain>/bin/aarch64-linux-gnu-
+   export RTE_KERNELDIR=<kernel-dir>
+   export RTE_TARGET=arm64-armv8a-linuxapp-gcc
+
+   make config T=arm64-armv8a-linuxapp-gcc
+   sed -i "s/MVNETA_PMD=y/MVNETA_PMD=n/" build/.config
+   sed -i "s/MVPP2_PMD=n/MVPP2_PMD=y/" build/.config
+   make
+
+Usage Example
+-------------
+
+MVPP2 PMD requires extra out of tree kernel modules to function properly.
+`musdk_cma` sources are part of the MUSDK. Please consult
+``doc/musdk_get_started.txt`` for the detailed build instructions.
+For `mvpp2x_sysfs` please consult ``Documentation/pp22_sysfs.txt`` for the
+detailed build instructions.
+
+.. code-block:: console
+
+   insmod musdk_cma.ko
+   insmod mvpp2x_sysfs.ko
+
+Additionally interfaces used by DPDK application need to be put up:
+
+.. code-block:: console
+
+   ip link set eth0 up
+   ip link set eth2 up
+
+In order to run testpmd example application following command can be used:
+
+.. code-block:: console
+
+   ./testpmd --vdev=eth_mvpp2,iface=eth0,iface=eth2 -c 7 -- \
+     --burst=128 --txd=2048 --rxd=1024 --rxq=2 --txq=2  --nb-cores=2 \
+     -i -a --rss-udp
+
+.. _extstats:
+
+Extended stats
+--------------
+
+MVPP2 PMD supports the following extended statistics:
+
+	- ``rx_bytes``:	number of RX bytes
+	- ``rx_packets``: number of RX packets
+	- ``rx_unicast_packets``: number of RX unicast packets
+	- ``rx_errors``: number of RX MAC errors
+	- ``rx_fullq_dropped``: number of RX packets dropped due to full RX queue
+	- ``rx_bm_dropped``: number of RX packets dropped due to no available buffers in the HW pool
+	- ``rx_early_dropped``: number of RX packets that were early dropped
+	- ``rx_fifo_dropped``: number of RX packets dropped due to RX fifo overrun
+	- ``rx_cls_dropped``: number of RX packets dropped by classifier
+	- ``tx_bytes``: number of TX bytes
+	- ``tx_packets``: number of TX packets
+	- ``tx_unicast_packets``: number of TX unicast packets
+	- ``tx_errors``: number of TX MAC errors
+
+
+.. _qossupport:
+
 QoS Configuration
 -----------------
 
@@ -302,39 +403,14 @@ Usage example
    ./testpmd --vdev=eth_mvpp2,iface=eth0,iface=eth2,cfg=/home/user/mrvl.conf \
      -c 7 -- -i -a --disable-hw-vlan-strip --rxq=3 --txq=3
 
-
-Building DPDK
--------------
-
-Driver needs precompiled MUSDK library during compilation.
-
-.. code-block:: console
-
-   export CROSS_COMPILE=<toolchain>/bin/aarch64-linux-gnu-
-   ./bootstrap
-   ./configure --host=aarch64-linux-gnu
-   make install
-
-MUSDK will be installed to `usr/local` under current directory.
-For the detailed build instructions please consult ``doc/musdk_get_started.txt``.
-
-Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
-the path to the MUSDK installation directory needs to be exported.
-
-.. code-block:: console
-
-   export LIBMUSDK_PATH=<musdk>/usr/local
-   export CROSS=aarch64-linux-gnu-
-   make config T=arm64-armv8a-linuxapp-gcc
-   sed -i "s/MVNETA_PMD=y/MVNETA_PMD=n/" build/.config
-   sed -i "s/MVPP2_PMD=n/MVPP2_PMD=y/" build/.config
-   make
+.. _flowapi:
 
 Flow API
 --------
 
 PPv2 offers packet classification capabilities via classifier engine which
 can be configured via generic flow API offered by DPDK.
+For an additional description please refer to DPDK :ref:`Generic flow API <Generic_flow_API>`.
 
 Supported flow actions
 ~~~~~~~~~~~~~~~~~~~~~~
@@ -495,31 +571,239 @@ Following limitations need to be taken into account while creating flow rules:
 For additional information about classifier please consult
 ``doc/musdk_cls_user_guide.txt``.
 
-Usage Example
--------------
+.. _mtrapi:
 
-MVPP2 PMD requires extra out of tree kernel modules to function properly.
-`musdk_cma` sources are part of the MUSDK. Please consult
-``doc/musdk_get_started.txt`` for the detailed build instructions.
-For `mvpp2x_sysfs` please consult ``Documentation/pp22_sysfs.txt`` for the
-detailed build instructions.
+Traffic metering and policing
+-----------------------------
 
-.. code-block:: console
+MVPP2 PMD supports DPDK traffic metering and policing that allows the following:
 
-   insmod musdk_cma.ko
-   insmod mvpp2x_sysfs.ko
+1. Meter ingress traffic.
+2. Do policing.
+3. Gather statistics.
 
-Additionally interfaces used by DPDK application need to be put up:
+For an additional description please refer to DPDK :doc:`Traffic Metering and Policing API <../prog_guide/traffic_metering_and_policing>`.
 
-.. code-block:: console
+The policer objects defined by this feature can work with the default policer defined via config file as discribed in :ref:`QoS Support <qossupport>`.
 
-   ip link set eth0 up
-   ip link set eth2 up
+Limitations
+~~~~~~~~~~~
 
-In order to run testpmd example application following command can be used:
+The following capabilities are not supported:
 
-.. code-block:: console
+- MTR object meter DSCP table update
+- MTR object policer action update
+- MTR object enabled statistics
 
-   ./testpmd --vdev=eth_mvpp2,iface=eth0,iface=eth2 -c 7 -- \
-     --burst=128 --txd=2048 --rxd=1024 --rxq=2 --txq=2  --nb-cores=2 \
-     -i -a --rss-udp
+Usage example
+~~~~~~~~~~~~~
+
+1. Run testpmd user app:
+
+   .. code-block:: console
+
+		./testpmd --vdev=eth_mvpp2,iface=eth0,iface=eth2 -c 6 -- -i -p 3 -a --txd 1024 --rxd 1024
+
+2. Create meter profile:
+
+   .. code-block:: console
+
+		testpmd> add port meter profile 0 0 srtcm_rfc2697 2000 256 256
+
+3. Create meter:
+
+   .. code-block:: console
+
+		testpmd> create port meter 0 0 0 yes d d d 0 1 0
+
+4. Create flow rule witch meter attached:
+
+   .. code-block:: console
+
+		testpmd> flow create 0 ingress pattern ipv4 src is 10.10.10.1 / end actions meter mtr_id 0 / end
+
+For a detailed usage description please refer to "Traffic Metering and Policing" section in DPDK :doc:`Testpmd Runtime Functions <../testpmd_app_ug/testpmd_funcs>`.
+
+
+
+.. _tmapi:
+
+Traffic Management API
+----------------------
+
+MVPP2 PMD supports generic DPDK Traffic Management API which allows to
+configure the following features:
+
+1. Hierarchical scheduling
+2. Traffic shaping
+3. Congestion management
+4. Packet marking
+
+Internally TM is represented by a hierarchy (tree) of nodes.
+Node which has a parent is called a leaf whereas node without
+parent is called a non-leaf (root).
+MVPP2 PMD supports two level hierarchy where level 0 represents ports and level 1 represents tx queues of a given port.
+
+.. figure:: img/mvpp2_tm.png
+
+Nodes hold following types of settings:
+
+- for egress scheduler configuration: weight
+- for egress rate limiter: private shaper
+- bitmask indicating which statistics counters will be read
+
+Hierarchy is always constructed from the top, i.e first a root node is added
+then some number of leaf nodes. Number of leaf nodes cannot exceed number
+of configured tx queues.
+
+After hierarchy is complete it can be committed.
+
+
+For an additional description please refer to DPDK :doc:`Traffic Management API <../prog_guide/traffic_management>`.
+
+Limitations
+~~~~~~~~~~~
+
+The following capabilities are not supported:
+
+- Traffic manager WRED profile and WRED context
+- Traffic manager shared shaper update
+- Traffic manager packet marking
+- Maximum number of levels in hierarchy is 2
+- Currently dynamic change of a hierarchy is not supported
+
+Usage example
+~~~~~~~~~~~~~
+
+For a detailed usage description please refer to "Traffic Management" section in DPDK :doc:`Testpmd Runtime Functions <../testpmd_app_ug/testpmd_funcs>`.
+
+1. Run testpmd as follows:
+
+   .. code-block:: console
+
+		./testpmd --vdev=net_mrvl,iface=eth0,iface=eth2,cfg=./qos_config -c 7 -- \
+		-i -p 3 --disable-hw-vlan-strip --rxq 3 --txq 3 --txd 1024 --rxd 1024
+
+2. Stop all ports:
+
+   .. code-block:: console
+
+		testpmd> port stop all
+
+3. Add shaper profile:
+
+   .. code-block:: console
+
+		testpmd> add port tm node shaper profile 0 0 900000 70000 0
+
+   Parameters have following meaning::
+
+		0       - Id of a port.
+		0       - Id of a new shaper profile.
+		900000  - Shaper rate in bytes/s.
+		70000   - Bucket size in bytes.
+		0       - Packet length adjustment - ignored.
+
+4. Add non-leaf node for port 0:
+
+   .. code-block:: console
+
+		testpmd> add port tm nonleaf node 0 3 -1 0 0 0 0 0 1 3 0
+
+   Parameters have following meaning::
+
+		 0  - Id of a port
+		 3  - Id of a new node.
+		-1  - Indicate that root does not have a parent.
+		 0  - Priority of the node.
+		 0  - Weight of the node.
+		 0  - Id of a level. Since this is a root 0 is passed.
+		 0  - Id of the shaper profile.
+		 0  - Number of SP priorities.
+		 3  - Enable statistics for both number of transmitted packets and bytes.
+		 0  - Number of shared shapers.
+
+5. Add leaf node for tx queue 0:
+
+   .. code-block:: console
+
+		testpmd> add port tm leaf node 0 0 3 0 30 1 -1 0 0 1 0
+
+   Parameters have following meaning::
+
+		 0  - Id of a port.
+		 0  - Id of a new node.
+		 3  - Id of the parent node.
+		 0  - Priority of a node.
+		 30 - WRR weight.
+		 1  - Id of a level. Since this is a leaf node 1 is passed.
+		-1  - Id of a shaper. -1 indicates that shaper is not attached.
+		 0  - Congestion management is not supported.
+		 0  - Congestion management is not supported.
+		 1  - Enable statistics counter for number of transmitted packets.
+		 0  - Number of shared shapers.
+
+6. Add leaf node for tx queue 1:
+
+   .. code-block:: console
+
+	testpmd> add port tm leaf node 0 1 3 0 60 1 -1 0 0 1 0
+
+   Parameters have following meaning::
+
+		 0  - Id of a port.
+		 1  - Id of a new node.
+		 3  - Id of the parent node.
+		 0  - Priority of a node.
+		 60 - WRR weight.
+		 1  - Id of a level. Since this is a leaf node 1 is passed.
+		-1  - Id of a shaper. -1 indicates that shaper is not attached.
+		 0  - Congestion management is not supported.
+		 0  - Congestion management is not supported.
+		 1  - Enable statistics counter for number of transmitted packets.
+		 0  - Number of shared shapers.
+
+7. Add leaf node for tx queue 2:
+
+   .. code-block:: console
+
+		testpmd> add port tm leaf node 0 2 3 0 99 1 -1 0 0 1 0
+
+   Parameters have following meaning::
+
+		 0  - Id of a port.
+		 2  - Id of a new node.
+		 3  - Id of the parent node.
+		 0  - Priority of a node.
+		 99 - WRR weight.
+		 1  - Id of a level. Since this is a leaf node 1 is passed.
+		-1  - Id of a shaper. -1 indicates that shaper is not attached.
+		 0  - Congestion management is not supported.
+		 0  - Congestion management is not supported.
+		 1  - Enable statistics counter for number of transmitted packets.
+		 0  - Number of shared shapers.
+
+8. Commit hierarchy:
+
+   .. code-block:: console
+
+		testpmd> port tm hierarchy commit 0 no
+
+  Parameters have following meaning::
+
+		0  - Id of a port.
+		no - Do not flush TM hierarchy if commit fails.
+
+9. Start all ports
+
+   .. code-block:: console
+
+		testpmd> port start all
+
+
+
+10. Enable forwarding
+
+   .. code-block:: console
+
+		testpmd> start
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 12/12] net/mvpp2: add Tx S/G support
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
                     ` (10 preceding siblings ...)
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 11/12] net/mvpp2: document MTR and TM usage Tomasz Duszynski
@ 2018-09-04 13:49   ` Tomasz Duszynski
  2018-09-19 17:24   ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Ferruh Yigit
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
  13 siblings, 0 replies; 48+ messages in thread
From: Tomasz Duszynski @ 2018-09-04 13:49 UTC (permalink / raw)
  To: dev; +Cc: nsamsono, mw, Zyta Szpak

From: Zyta Szpak <zr@semihalf.com>

The patch introduces scatter/gather support on transmit path.
A separate Tx callback is added and set if the application
requests multisegment Tx offload. Multiple descriptors are
sent per one packet.

Signed-off-by: Zyta Szpak <zr@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Yelena Krivosheev <yelena@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c | 231 ++++++++++++++++++++++++++++++++++++----
 drivers/net/mvpp2/mrvl_ethdev.h |   1 +
 2 files changed, 212 insertions(+), 20 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 899a9e4..56b190e 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -65,7 +65,8 @@
 /** Port Tx offloads capabilities */
 #define MRVL_TX_OFFLOADS (DEV_TX_OFFLOAD_IPV4_CKSUM | \
 			  DEV_TX_OFFLOAD_UDP_CKSUM | \
-			  DEV_TX_OFFLOAD_TCP_CKSUM)
+			  DEV_TX_OFFLOAD_TCP_CKSUM | \
+			  DEV_TX_OFFLOAD_MULTI_SEGS)
 
 static const char * const valid_args[] = {
 	MRVL_IFACE_NAME_ARG,
@@ -105,7 +106,9 @@ struct mrvl_shadow_txq {
 	int head;           /* write index - used when sending buffers */
 	int tail;           /* read index - used when releasing buffers */
 	u16 size;           /* queue occupied size */
-	u16 num_to_release; /* number of buffers sent, that can be released */
+	u16 num_to_release; /* number of descriptors sent, that can be
+			     * released
+			     */
 	struct buff_release_entry ent[MRVL_PP2_TX_SHADOWQ_SIZE]; /* q entries */
 };
 
@@ -137,6 +140,12 @@ static inline void mrvl_free_sent_buffers(struct pp2_ppio *ppio,
 			struct pp2_hif *hif, unsigned int core_id,
 			struct mrvl_shadow_txq *sq, int qid, int force);
 
+static uint16_t mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts,
+				  uint16_t nb_pkts);
+static uint16_t mrvl_tx_sg_pkt_burst(void *txq,	struct rte_mbuf **tx_pkts,
+				     uint16_t nb_pkts);
+
+
 #define MRVL_XSTATS_TBL_ENTRY(name) { \
 	#name, offsetof(struct pp2_ppio_statistics, name),	\
 	sizeof(((struct pp2_ppio_statistics *)0)->name)		\
@@ -163,6 +172,31 @@ static struct {
 	MRVL_XSTATS_TBL_ENTRY(tx_errors)
 };
 
+static inline void
+mrvl_fill_shadowq(struct mrvl_shadow_txq *sq, struct rte_mbuf *buf)
+{
+	sq->ent[sq->head].buff.cookie = (uint64_t)buf;
+	sq->ent[sq->head].buff.addr = buf ?
+		rte_mbuf_data_iova_default(buf) : 0;
+
+	sq->ent[sq->head].bpool =
+		(unlikely(!buf || buf->port >= RTE_MAX_ETHPORTS ||
+		 buf->refcnt > 1)) ? NULL :
+		 mrvl_port_to_bpool_lookup[buf->port];
+
+	sq->head = (sq->head + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
+	sq->size++;
+}
+
+static inline void
+mrvl_fill_desc(struct pp2_ppio_desc *desc, struct rte_mbuf *buf)
+{
+	pp2_ppio_outq_desc_reset(desc);
+	pp2_ppio_outq_desc_set_phys_addr(desc, rte_pktmbuf_iova(buf));
+	pp2_ppio_outq_desc_set_pkt_offset(desc, 0);
+	pp2_ppio_outq_desc_set_pkt_len(desc, rte_pktmbuf_data_len(buf));
+}
+
 static inline int
 mrvl_get_bpool_size(int pp2_id, int pool_id)
 {
@@ -242,6 +276,27 @@ mrvl_get_hif(struct mrvl_priv *priv, int core_id)
 }
 
 /**
+ * Set tx burst function according to offload flag
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_set_tx_function(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	/* Use a simple Tx queue (no offloads, no multi segs) if possible */
+	if (priv->multiseg) {
+		RTE_LOG(INFO, PMD, "Using multi-segment tx callback\n");
+		dev->tx_pkt_burst = mrvl_tx_sg_pkt_burst;
+	} else {
+		RTE_LOG(INFO, PMD, "Using single-segment tx callback\n");
+		dev->tx_pkt_burst = mrvl_tx_pkt_burst;
+	}
+}
+
+/**
  * Configure rss based on dpdk rss configuration.
  *
  * @param priv
@@ -325,6 +380,9 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 		dev->data->mtu = dev->data->dev_conf.rxmode.max_rx_pkt_len -
 				 MRVL_PP2_ETH_HDRS_LEN;
 
+	if (dev->data->dev_conf.txmode.offloads & DEV_TX_OFFLOAD_MULTI_SEGS)
+		priv->multiseg = 1;
+
 	ret = mrvl_configure_rxqs(priv, dev->data->port_id,
 				  dev->data->nb_rx_queues);
 	if (ret < 0)
@@ -672,6 +730,7 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 
 	mrvl_flow_init(dev);
 	mrvl_mtr_init(dev);
+	mrvl_set_tx_function(dev);
 
 	return 0;
 out:
@@ -2439,22 +2498,8 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 			rte_mbuf_prefetch_part2(pref_pkt_hdr);
 		}
 
-		sq->ent[sq->head].buff.cookie = (uint64_t)mbuf;
-		sq->ent[sq->head].buff.addr =
-			rte_mbuf_data_iova_default(mbuf);
-		sq->ent[sq->head].bpool =
-			(unlikely(mbuf->port >= RTE_MAX_ETHPORTS ||
-			 mbuf->refcnt > 1)) ? NULL :
-			 mrvl_port_to_bpool_lookup[mbuf->port];
-		sq->head = (sq->head + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
-		sq->size++;
-
-		pp2_ppio_outq_desc_reset(&descs[i]);
-		pp2_ppio_outq_desc_set_phys_addr(&descs[i],
-						 rte_pktmbuf_iova(mbuf));
-		pp2_ppio_outq_desc_set_pkt_offset(&descs[i], 0);
-		pp2_ppio_outq_desc_set_pkt_len(&descs[i],
-					       rte_pktmbuf_pkt_len(mbuf));
+		mrvl_fill_shadowq(sq, mbuf);
+		mrvl_fill_desc(&descs[i], mbuf);
 
 		bytes_sent += rte_pktmbuf_pkt_len(mbuf);
 		/*
@@ -2492,6 +2537,152 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 	return nb_pkts;
 }
 
+/** DPDK callback for S/G transmit.
+ *
+ * @param txq
+ *   Generic pointer transmit queue.
+ * @param tx_pkts
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted.
+ */
+static uint16_t
+mrvl_tx_sg_pkt_burst(void *txq, struct rte_mbuf **tx_pkts,
+		     uint16_t nb_pkts)
+{
+	struct mrvl_txq *q = txq;
+	struct mrvl_shadow_txq *sq;
+	struct pp2_hif *hif;
+	struct pp2_ppio_desc descs[nb_pkts * PP2_PPIO_DESC_NUM_FRAGS];
+	struct pp2_ppio_sg_pkts pkts;
+	uint8_t frags[nb_pkts];
+	unsigned int core_id = rte_lcore_id();
+	int i, j, ret, bytes_sent = 0;
+	int tail, tail_first;
+	uint16_t num, sq_free_size;
+	uint16_t nb_segs, total_descs = 0;
+	uint64_t addr;
+
+	hif = mrvl_get_hif(q->priv, core_id);
+	sq = &q->shadow_txqs[core_id];
+	pkts.frags = frags;
+	pkts.num = 0;
+
+	if (unlikely(!q->priv->ppio || !hif))
+		return 0;
+
+	if (sq->size)
+		mrvl_free_sent_buffers(q->priv->ppio, hif, core_id,
+				       sq, q->queue_id, 0);
+
+	/* Save shadow queue free size */
+	sq_free_size = MRVL_PP2_TX_SHADOWQ_SIZE - sq->size - 1;
+
+	tail = 0;
+	for (i = 0; i < nb_pkts; i++) {
+		struct rte_mbuf *mbuf = tx_pkts[i];
+		struct rte_mbuf *seg = NULL;
+		int gen_l3_cksum, gen_l4_cksum;
+		enum pp2_outq_l3_type l3_type;
+		enum pp2_outq_l4_type l4_type;
+
+		nb_segs = mbuf->nb_segs;
+		tail_first = tail;
+		total_descs += nb_segs;
+
+		/*
+		 * Check if total_descs does not exceed
+		 * shadow queue free size
+		 */
+		if (unlikely(total_descs > sq_free_size)) {
+			total_descs -= nb_segs;
+			RTE_LOG(DEBUG, PMD,
+				"No room in shadow queue for %d packets! "
+				"%d packets will be sent.\n",
+				nb_pkts, i);
+			break;
+		}
+
+		/* Check if nb_segs does not exceed the max nb of desc per
+		 * fragmented packet
+		 */
+		if (nb_segs > PP2_PPIO_DESC_NUM_FRAGS) {
+			total_descs -= nb_segs;
+			RTE_LOG(ERR, PMD,
+				"Too many segments. Packet won't be sent.\n");
+			break;
+		}
+
+		if (likely(nb_pkts - i > MRVL_MUSDK_PREFETCH_SHIFT)) {
+			struct rte_mbuf *pref_pkt_hdr;
+
+			pref_pkt_hdr = tx_pkts[i + MRVL_MUSDK_PREFETCH_SHIFT];
+			rte_mbuf_prefetch_part1(pref_pkt_hdr);
+			rte_mbuf_prefetch_part2(pref_pkt_hdr);
+		}
+
+		pkts.frags[pkts.num] = nb_segs;
+		pkts.num++;
+
+		seg = mbuf;
+		for (j = 0; j < nb_segs - 1; j++) {
+			/* For the subsequent segments, set shadow queue
+			 * buffer to NULL
+			 */
+			mrvl_fill_shadowq(sq, NULL);
+			mrvl_fill_desc(&descs[tail], seg);
+
+			tail++;
+			seg = seg->next;
+		}
+		/* Put first mbuf info in last shadow queue entry */
+		mrvl_fill_shadowq(sq, mbuf);
+		/* Update descriptor with last segment */
+		mrvl_fill_desc(&descs[tail++], seg);
+
+		bytes_sent += rte_pktmbuf_pkt_len(mbuf);
+		/* In case unsupported ol_flags were passed
+		 * do not update descriptor offload information
+		 */
+		ret = mrvl_prepare_proto_info(mbuf->ol_flags, mbuf->packet_type,
+					      &l3_type, &l4_type, &gen_l3_cksum,
+					      &gen_l4_cksum);
+		if (unlikely(ret))
+			continue;
+
+		pp2_ppio_outq_desc_set_proto_info(&descs[tail_first], l3_type,
+						  l4_type, mbuf->l2_len,
+						  mbuf->l2_len + mbuf->l3_len,
+						  gen_l3_cksum, gen_l4_cksum);
+	}
+
+	num = total_descs;
+	pp2_ppio_send_sg(q->priv->ppio, hif, q->queue_id, descs,
+			 &total_descs, &pkts);
+	/* number of packets that were not sent */
+	if (unlikely(num > total_descs)) {
+		for (i = total_descs; i < num; i++) {
+			sq->head = (MRVL_PP2_TX_SHADOWQ_SIZE + sq->head - 1) &
+				MRVL_PP2_TX_SHADOWQ_MASK;
+
+			addr = sq->ent[sq->head].buff.cookie;
+			if (addr)
+				bytes_sent -=
+					rte_pktmbuf_pkt_len((struct rte_mbuf *)
+						(cookie_addr_high | addr));
+		}
+		sq->size -= num - total_descs;
+		nb_pkts = pkts.num;
+	}
+
+	q->bytes_sent += bytes_sent;
+
+	return nb_pkts;
+}
+
 /**
  * Initialize packet processor.
  *
@@ -2620,11 +2811,11 @@ mrvl_eth_dev_create(struct rte_vdev_device *vdev, const char *name)
 	memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
 	       req.ifr_addr.sa_data, ETHER_ADDR_LEN);
 
-	eth_dev->rx_pkt_burst = mrvl_rx_pkt_burst;
-	eth_dev->tx_pkt_burst = mrvl_tx_pkt_burst;
 	eth_dev->data->kdrv = RTE_KDRV_NONE;
 	eth_dev->data->dev_private = priv;
 	eth_dev->device = &vdev->device;
+	eth_dev->rx_pkt_burst = mrvl_rx_pkt_burst;
+	mrvl_set_tx_function(eth_dev);
 	eth_dev->dev_ops = &mrvl_ops;
 
 	rte_eth_dev_probing_finish(eth_dev);
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index f0ae983..0120b9e 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -188,6 +188,7 @@ struct mrvl_priv {
 	uint8_t uc_mc_flushed;
 	uint8_t vlan_flushed;
 	uint8_t isolated;
+	uint8_t multiseg;
 
 	struct pp2_ppio_params ppio_params;
 	struct pp2_cls_qos_tbl_params qos_tbl_params;
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation with MUSDK 18.09
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation " Tomasz Duszynski
@ 2018-09-19 17:15     ` Ferruh Yigit
  2018-09-23 22:40       ` Thomas Monjalon
  0 siblings, 1 reply; 48+ messages in thread
From: Ferruh Yigit @ 2018-09-19 17:15 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: nsamsono, mw

On 9/4/2018 2:49 PM, Tomasz Duszynski wrote:
> From: Natalie Samsonov <nsamsono@marvell.com>
> 
> Update documentation to align with MUSDK 18.09.
> 
> Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
> ---
>  doc/guides/nics/mvpp2.rst | 26 ++++++++++++--------------
>  1 file changed, 12 insertions(+), 14 deletions(-)
> 
> diff --git a/doc/guides/nics/mvpp2.rst b/doc/guides/nics/mvpp2.rst
> index a452c8a..3b3f8c6 100644
> --- a/doc/guides/nics/mvpp2.rst
> +++ b/doc/guides/nics/mvpp2.rst
> @@ -74,6 +74,7 @@ Features of the MVPP2 PMD are:
>  - QoS
>  - RX flow control
>  - TX queue start/stop
> +- Scattered TX frames
>  
>  
>  Limitations
> @@ -96,19 +97,19 @@ Prerequisites
>  
>    .. code-block:: console
>  
> -     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.52-armada-17.10
> +     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.120-armada-18.09

There is a strict dependency to MUSDK 18.09, dpdk18.11 won't compile with older
versions. It is hard to trace this dependency, what do you think having a matrix
in DPDK documentation showing which DPDK version supports which MUSDK?

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
                     ` (11 preceding siblings ...)
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 12/12] net/mvpp2: add Tx S/G support Tomasz Duszynski
@ 2018-09-19 17:24   ` Ferruh Yigit
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
  13 siblings, 0 replies; 48+ messages in thread
From: Ferruh Yigit @ 2018-09-19 17:24 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: nsamsono, mw

On 9/4/2018 2:49 PM, Tomasz Duszynski wrote:
> This patch series introduces fixes and adds support for traffic metering,
> traffic manager and Tx S/G. Additionally it aligns with for MUSDK 18.09.
> 
> Changes since v2:
> * Align with MUSDK 18.09 library
> * Add support for Tx Gather.
> * Add documentation related to MTR and TM.
> * Align documentation with MUSDK 18.09
> 
> Natalie Samsonov (4):
>   net/mvpp2: initialize ppio only once
>   net/mvpp2: update MTU and MRU related calculations
>   net/mvpp2: align documentation with MUSDK 18.09
>   net/mvpp2: document MTR and TM usage
> 
> Tomasz Duszynski (6):
>   net/mvpp2: move common code
>   net/mvpp2: add metering support
>   net/mvpp2: change default policer configuration
>   net/mvpp2: add init and deinit to flow
>   net/mvpp2: add traffic manager support
>   net/mvpp2: align with MUSDK 18.09
> 
> Yuval Caduri (1):
>   net/mvpp2: detach tx_qos from rx cls/qos config
> 
> Zyta Szpak (1):
>   net/mvpp2: add Tx S/G support

Series applied to dpdk-next-net/master, thanks.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation with MUSDK 18.09
  2018-09-19 17:15     ` Ferruh Yigit
@ 2018-09-23 22:40       ` Thomas Monjalon
  2018-09-24 11:36         ` Ferruh Yigit
  0 siblings, 1 reply; 48+ messages in thread
From: Thomas Monjalon @ 2018-09-23 22:40 UTC (permalink / raw)
  To: Ferruh Yigit, Tomasz Duszynski, nsamsono; +Cc: dev, mw

19/09/2018 19:15, Ferruh Yigit:
> On 9/4/2018 2:49 PM, Tomasz Duszynski wrote:
> > From: Natalie Samsonov <nsamsono@marvell.com>
> > --- a/doc/guides/nics/mvpp2.rst
> > +++ b/doc/guides/nics/mvpp2.rst
> > -     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.52-armada-17.10
> > +     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.120-armada-18.09
> 
> There is a strict dependency to MUSDK 18.09, dpdk18.11 won't compile with older
> versions. It is hard to trace this dependency, what do you think having a matrix
> in DPDK documentation showing which DPDK version supports which MUSDK?

It does not compile even with MUSDK 18.09.

With MUSDK 18.09, the error is:
	drivers/crypto/mvsam/rte_mrvl_pmd.c:867:26: error: 'SAM_HW_RING_NUM' undeclared

The explanation is in MUSDK:
commit 9bf8b3ca4ddfa00619c0023dfb08ae1601054fce
Author: Dmitri Epshtein <dima@marvell.com>
Date:   Mon Nov 20 10:38:31 2017 +0200

    sam: remove SAM_HW_RING_NUM from APIs
    
    Use function:
    u32 sam_get_num_cios(u32 inst);

As a consequence, next-net cannot be pulled!

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 11/12] net/mvpp2: document MTR and TM usage
  2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 11/12] net/mvpp2: document MTR and TM usage Tomasz Duszynski
@ 2018-09-23 22:45     ` Thomas Monjalon
  0 siblings, 0 replies; 48+ messages in thread
From: Thomas Monjalon @ 2018-09-23 22:45 UTC (permalink / raw)
  To: Tomasz Duszynski, nsamsono; +Cc: dev, mw, ferruh.yigit

04/09/2018 15:49, Tomasz Duszynski:
> From: Natalie Samsonov <nsamsono@marvell.com>
> 
> Document MTR (metering) and TM (traffic management) usage plus
> do some small updates here and there.
> 
> Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
> ---
>  doc/guides/nics/img/mvpp2_tm.png | Bin 0 -> 5355 bytes
>  doc/guides/nics/mvpp2.rst        | 386 +++++++++++++++++++++++++++++++++------
>  2 files changed, 335 insertions(+), 51 deletions(-)
>  create mode 100644 doc/guides/nics/img/mvpp2_tm.png
> 
> diff --git a/doc/guides/nics/img/mvpp2_tm.png b/doc/guides/nics/img/mvpp2_tm.png
> new file mode 100644

Sorry, it is forbidden to add new binary file.
As an Open Source project, everything must be open including the source
of the figures. Please could you provide a SVG version?

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation with MUSDK 18.09
  2018-09-23 22:40       ` Thomas Monjalon
@ 2018-09-24 11:36         ` Ferruh Yigit
  2018-09-24 11:51           ` Marcin Wojtas
  2018-09-24 12:44           ` Thomas Monjalon
  0 siblings, 2 replies; 48+ messages in thread
From: Ferruh Yigit @ 2018-09-24 11:36 UTC (permalink / raw)
  To: Thomas Monjalon, Tomasz Duszynski, nsamsono; +Cc: dev, mw

On 9/23/2018 11:40 PM, Thomas Monjalon wrote:
> 19/09/2018 19:15, Ferruh Yigit:
>> On 9/4/2018 2:49 PM, Tomasz Duszynski wrote:
>>> From: Natalie Samsonov <nsamsono@marvell.com>
>>> --- a/doc/guides/nics/mvpp2.rst
>>> +++ b/doc/guides/nics/mvpp2.rst
>>> -     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.52-armada-17.10
>>> +     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.120-armada-18.09
>>
>> There is a strict dependency to MUSDK 18.09, dpdk18.11 won't compile with older
>> versions. It is hard to trace this dependency, what do you think having a matrix
>> in DPDK documentation showing which DPDK version supports which MUSDK?
> 
> It does not compile even with MUSDK 18.09.
> 
> With MUSDK 18.09, the error is:
> 	drivers/crypto/mvsam/rte_mrvl_pmd.c:867:26: error: 'SAM_HW_RING_NUM' undeclared

I confirm same error. I wasn't building with crypto PMD enabled so not caught it.

> 
> The explanation is in MUSDK:
> commit 9bf8b3ca4ddfa00619c0023dfb08ae1601054fce
> Author: Dmitri Epshtein <dima@marvell.com>
> Date:   Mon Nov 20 10:38:31 2017 +0200
> 
>     sam: remove SAM_HW_RING_NUM from APIs
>     
>     Use function:
>     u32 sam_get_num_cios(u32 inst);
> 
> As a consequence, next-net cannot be pulled!

Got it, should I drop the patchset from tree?

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation with MUSDK 18.09
  2018-09-24 11:36         ` Ferruh Yigit
@ 2018-09-24 11:51           ` Marcin Wojtas
  2018-09-24 12:38             ` Ferruh Yigit
  2018-09-24 12:44           ` Thomas Monjalon
  1 sibling, 1 reply; 48+ messages in thread
From: Marcin Wojtas @ 2018-09-24 11:51 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: thomas, Tomasz Duszyński, Natalie Samsonov, dev, Andrzej Ostruszka

Hi Ferruh,

pon., 24 wrz 2018 o 13:38 Ferruh Yigit <ferruh.yigit@intel.com> napisał(a):
>
> On 9/23/2018 11:40 PM, Thomas Monjalon wrote:
> > 19/09/2018 19:15, Ferruh Yigit:
> >> On 9/4/2018 2:49 PM, Tomasz Duszynski wrote:
> >>> From: Natalie Samsonov <nsamsono@marvell.com>
> >>> --- a/doc/guides/nics/mvpp2.rst
> >>> +++ b/doc/guides/nics/mvpp2.rst
> >>> -     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.52-armada-17.10
> >>> +     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.120-armada-18.09
> >>
> >> There is a strict dependency to MUSDK 18.09, dpdk18.11 won't compile with older
> >> versions. It is hard to trace this dependency, what do you think having a matrix
> >> in DPDK documentation showing which DPDK version supports which MUSDK?
> >
> > It does not compile even with MUSDK 18.09.
> >
> > With MUSDK 18.09, the error is:
> >       drivers/crypto/mvsam/rte_mrvl_pmd.c:867:26: error: 'SAM_HW_RING_NUM' undeclared
>
> I confirm same error. I wasn't building with crypto PMD enabled so not caught it.
>
> >
> > The explanation is in MUSDK:
> > commit 9bf8b3ca4ddfa00619c0023dfb08ae1601054fce
> > Author: Dmitri Epshtein <dima@marvell.com>
> > Date:   Mon Nov 20 10:38:31 2017 +0200
> >
> >     sam: remove SAM_HW_RING_NUM from APIs
> >
> >     Use function:
> >     u32 sam_get_num_cios(u32 inst);
> >
> > As a consequence, next-net cannot be pulled!
>
> Got it, should I drop the patchset from tree?

We're checking the error and will provide fix asap. Please let know if
this should be another version of the entire patchset or fix on top.
Sorry for the problems.

Best regards,
Marcin

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation with MUSDK 18.09
  2018-09-24 11:51           ` Marcin Wojtas
@ 2018-09-24 12:38             ` Ferruh Yigit
  0 siblings, 0 replies; 48+ messages in thread
From: Ferruh Yigit @ 2018-09-24 12:38 UTC (permalink / raw)
  To: Marcin Wojtas
  Cc: thomas, Tomasz Duszyński, Natalie Samsonov, dev, Andrzej Ostruszka

On 9/24/2018 12:51 PM, Marcin Wojtas wrote:
> Hi Ferruh,
> 
> pon., 24 wrz 2018 o 13:38 Ferruh Yigit <ferruh.yigit@intel.com> napisał(a):
>>
>> On 9/23/2018 11:40 PM, Thomas Monjalon wrote:
>>> 19/09/2018 19:15, Ferruh Yigit:
>>>> On 9/4/2018 2:49 PM, Tomasz Duszynski wrote:
>>>>> From: Natalie Samsonov <nsamsono@marvell.com>
>>>>> --- a/doc/guides/nics/mvpp2.rst
>>>>> +++ b/doc/guides/nics/mvpp2.rst
>>>>> -     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.52-armada-17.10
>>>>> +     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.120-armada-18.09
>>>>
>>>> There is a strict dependency to MUSDK 18.09, dpdk18.11 won't compile with older
>>>> versions. It is hard to trace this dependency, what do you think having a matrix
>>>> in DPDK documentation showing which DPDK version supports which MUSDK?
>>>
>>> It does not compile even with MUSDK 18.09.
>>>
>>> With MUSDK 18.09, the error is:
>>>       drivers/crypto/mvsam/rte_mrvl_pmd.c:867:26: error: 'SAM_HW_RING_NUM' undeclared
>>
>> I confirm same error. I wasn't building with crypto PMD enabled so not caught it.
>>
>>>
>>> The explanation is in MUSDK:
>>> commit 9bf8b3ca4ddfa00619c0023dfb08ae1601054fce
>>> Author: Dmitri Epshtein <dima@marvell.com>
>>> Date:   Mon Nov 20 10:38:31 2017 +0200
>>>
>>>     sam: remove SAM_HW_RING_NUM from APIs
>>>
>>>     Use function:
>>>     u32 sam_get_num_cios(u32 inst);
>>>
>>> As a consequence, next-net cannot be pulled!
>>
>> Got it, should I drop the patchset from tree?
> 
> We're checking the error and will provide fix asap. Please let know if
> this should be another version of the entire patchset or fix on top.

There is another comment from Thomas (mvpp2_tm.png).

Both "fix on top" and "new version" is OK for me, pick whichever easy for you.
For "fix on top", I will squash fixes to original commits, so fixes should be
separate patches with a information which commit it targets.

But overall build should not be broken, it should be clear in which commit
dependency changed to 18.09. Let call the commit that switch happens X,
all commits before X should compile successfully with 17.10, commit X and all
following commits should be compile successfully with 18.09.

> Sorry for the problems.
> 
> Best regards,
> Marcin
> 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation with MUSDK 18.09
  2018-09-24 11:36         ` Ferruh Yigit
  2018-09-24 11:51           ` Marcin Wojtas
@ 2018-09-24 12:44           ` Thomas Monjalon
  2018-09-24 12:48             ` Marcin Wojtas
  1 sibling, 1 reply; 48+ messages in thread
From: Thomas Monjalon @ 2018-09-24 12:44 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: Tomasz Duszynski, nsamsono, dev, mw

24/09/2018 13:36, Ferruh Yigit:
> On 9/23/2018 11:40 PM, Thomas Monjalon wrote:
> > As a consequence, next-net cannot be pulled!
> 
> Got it, should I drop the patchset from tree?

Yes I think it's better to re-consider this patchset later.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation with MUSDK 18.09
  2018-09-24 12:44           ` Thomas Monjalon
@ 2018-09-24 12:48             ` Marcin Wojtas
  2018-09-24 12:50               ` Ferruh Yigit
  0 siblings, 1 reply; 48+ messages in thread
From: Marcin Wojtas @ 2018-09-24 12:48 UTC (permalink / raw)
  To: thomas
  Cc: Ferruh Yigit, Tomasz Duszyński, Natalie Samsonov, dev,
	Andrzej Ostruszka

pon., 24 wrz 2018 o 14:44 Thomas Monjalon <thomas@monjalon.net> napisał(a):
>
> 24/09/2018 13:36, Ferruh Yigit:
> > On 9/23/2018 11:40 PM, Thomas Monjalon wrote:
> > > As a consequence, next-net cannot be pulled!
> >
> > Got it, should I drop the patchset from tree?
>
> Yes I think it's better to re-consider this patchset later.
>
>

Ok, complete, new version of it will be re-sent to the lists.

Best regards,
Marcin

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation with MUSDK 18.09
  2018-09-24 12:48             ` Marcin Wojtas
@ 2018-09-24 12:50               ` Ferruh Yigit
  2018-09-24 13:11                 ` Andrzej Ostruszka
  0 siblings, 1 reply; 48+ messages in thread
From: Ferruh Yigit @ 2018-09-24 12:50 UTC (permalink / raw)
  To: Marcin Wojtas, thomas
  Cc: Tomasz Duszyński, Natalie Samsonov, dev, Andrzej Ostruszka

On 9/24/2018 1:48 PM, Marcin Wojtas wrote:
> pon., 24 wrz 2018 o 14:44 Thomas Monjalon <thomas@monjalon.net> napisał(a):
>>
>> 24/09/2018 13:36, Ferruh Yigit:
>>> On 9/23/2018 11:40 PM, Thomas Monjalon wrote:
>>>> As a consequence, next-net cannot be pulled!
>>>
>>> Got it, should I drop the patchset from tree?
>>
>> Yes I think it's better to re-consider this patchset later.
>>
>>
> 
> Ok, complete, new version of it will be re-sent to the lists.

OK, patch will be dropped from the next-net for now.

> 
> Best regards,
> Marcin
> 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation with MUSDK 18.09
  2018-09-24 12:50               ` Ferruh Yigit
@ 2018-09-24 13:11                 ` Andrzej Ostruszka
  0 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-24 13:11 UTC (permalink / raw)
  To: Ferruh Yigit, Marcin Wojtas, thomas
  Cc: Tomasz Duszyński, Natalie Samsonov, dev

On 24.09.2018 14:50, Ferruh Yigit wrote:
> On 9/24/2018 1:48 PM, Marcin Wojtas wrote:
>> pon., 24 wrz 2018 o 14:44 Thomas Monjalon <thomas@monjalon.net> napisał(a):
>>>
>>> 24/09/2018 13:36, Ferruh Yigit:
>>>> On 9/23/2018 11:40 PM, Thomas Monjalon wrote:
>>>>> As a consequence, next-net cannot be pulled!
>>>>
>>>> Got it, should I drop the patchset from tree?
>>>
>>> Yes I think it's better to re-consider this patchset later.
>>>
>>>
>>
>> Ok, complete, new version of it will be re-sent to the lists.
> 
> OK, patch will be dropped from the next-net for now.

I will provide the new patchset shortly with following patch:
http://patches.dpdk.org/patch/44255/
already "squashed"/applied.  This is the patch for updating mvsam to
MUSDK 18.09 which solves the problem you experience but I guess it goes
to next-crypto.  That way I hope there would be no problem with merging
next-crypto and next-net will be able to compile.

Best regards
Andrzej

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 00/13] net/mvpp2: add new features
  2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
                     ` (12 preceding siblings ...)
  2018-09-19 17:24   ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Ferruh Yigit
@ 2018-09-25  7:04   ` Andrzej Ostruszka
  2018-09-25  7:04     ` [dpdk-dev] [PATCH v3 01/13] net/mvpp2: initialize ppio only once Andrzej Ostruszka
                       ` (13 more replies)
  13 siblings, 14 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:04 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh

This patch series introduces fixes and adds support for traffic metering,
traffic manager and Tx S/G. Additionally it aligns with for MUSDK 18.09.

Changes in v3:
* change the format of image referred in doc (png -> svg)
* "cherry-pick" http://patches.dpdk.org/patch/44255/ to be part of this
  patch set so that next-net can compile with new MUSDK also when mvsam
  is enabled

Changes since v2:
* Align with MUSDK 18.09 library
* Add support for Tx Gather.
* Add documentation related to MTR and TM.
* Align documentation with MUSDK 18.09

Dmitri Epshtein (1):
  crypto/mvsam: get number of CIOs dynamically

Natalie Samsonov (4):
  net/mvpp2: initialize ppio only once
  net/mvpp2: update MTU and MRU related calculations
  net/mvpp2: align documentation with MUSDK 18.09
  net/mvpp2: document MTR and TM usage

Tomasz Duszynski (6):
  net/mvpp2: move common code
  net/mvpp2: add metering support
  net/mvpp2: change default policer configuration
  net/mvpp2: add init and deinit to flow
  net/mvpp2: add traffic manager support
  net/mvpp2: align with MUSDK 18.09

Yuval Caduri (1):
  net/mvpp2: detach Tx QoS from Rx cls/QoS config

Zyta Szpak (1):
  net/mvpp2: add Tx scatter/gather support

 doc/guides/nics/img/mvpp2_tm.svg    |   71 +++
 doc/guides/nics/mvpp2.rst           |  433 ++++++++++++---
 drivers/crypto/mvsam/rte_mrvl_pmd.c |    2 +-
 drivers/net/mvpp2/Makefile          |    2 +
 drivers/net/mvpp2/meson.build       |    4 +-
 drivers/net/mvpp2/mrvl_ethdev.c     |  427 ++++++++++++---
 drivers/net/mvpp2/mrvl_ethdev.h     |  123 ++++-
 drivers/net/mvpp2/mrvl_flow.c       |  132 +++--
 drivers/net/mvpp2/mrvl_flow.h       |   15 +
 drivers/net/mvpp2/mrvl_mtr.c        |  512 ++++++++++++++++++
 drivers/net/mvpp2/mrvl_mtr.h        |   15 +
 drivers/net/mvpp2/mrvl_qos.c        |  246 +++++----
 drivers/net/mvpp2/mrvl_qos.h        |    2 +-
 drivers/net/mvpp2/mrvl_tm.c         | 1009 +++++++++++++++++++++++++++++++++++
 drivers/net/mvpp2/mrvl_tm.h         |   15 +
 15 files changed, 2696 insertions(+), 312 deletions(-)
 create mode 100644 doc/guides/nics/img/mvpp2_tm.svg
 create mode 100644 drivers/net/mvpp2/mrvl_flow.h
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.c
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.h
 create mode 100644 drivers/net/mvpp2/mrvl_tm.c
 create mode 100644 drivers/net/mvpp2/mrvl_tm.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 01/13] net/mvpp2: initialize ppio only once
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
@ 2018-09-25  7:04     ` Andrzej Ostruszka
  2018-09-25  7:04     ` [dpdk-dev] [PATCH v3 02/13] net/mvpp2: move common code Andrzej Ostruszka
                       ` (12 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:04 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Natalie Samsonov

From: Natalie Samsonov <nsamsono@marvell.com>

This changes stop/start/configure behavior due to issue in MUSDK
library itself.  From now on, ppio can be reconfigured only after interface
is closed.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Yuval Caduri <cyuval@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c | 53 +++++++++++++++++++++++++----------------
 1 file changed, 32 insertions(+), 21 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index fa4af49..dca3ccc 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -303,6 +303,11 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 	struct mrvl_priv *priv = dev->data->dev_private;
 	int ret;
 
+	if (priv->ppio) {
+		MRVL_LOG(INFO, "Device reconfiguration is not supported");
+		return -EINVAL;
+	}
+
 	if (dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_NONE &&
 	    dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) {
 		MRVL_LOG(INFO, "Unsupported rx multi queue mode %d",
@@ -516,6 +521,9 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 	char match[MRVL_MATCH_LEN];
 	int ret = 0, i, def_init_size;
 
+	if (priv->ppio)
+		return mrvl_dev_set_link_up(dev);
+
 	snprintf(match, sizeof(match), "ppio-%d:%d",
 		 priv->pp_id, priv->ppio_id);
 	priv->ppio_params.match = match;
@@ -740,28 +748,7 @@ mrvl_flush_bpool(struct rte_eth_dev *dev)
 static void
 mrvl_dev_stop(struct rte_eth_dev *dev)
 {
-	struct mrvl_priv *priv = dev->data->dev_private;
-
 	mrvl_dev_set_link_down(dev);
-	mrvl_flush_rx_queues(dev);
-	mrvl_flush_tx_shadow_queues(dev);
-	if (priv->cls_tbl) {
-		pp2_cls_tbl_deinit(priv->cls_tbl);
-		priv->cls_tbl = NULL;
-	}
-	if (priv->qos_tbl) {
-		pp2_cls_qos_tbl_deinit(priv->qos_tbl);
-		priv->qos_tbl = NULL;
-	}
-	if (priv->ppio)
-		pp2_ppio_deinit(priv->ppio);
-	priv->ppio = NULL;
-
-	/* policer must be released after ppio deinitialization */
-	if (priv->policer) {
-		pp2_cls_plcr_deinit(priv->policer);
-		priv->policer = NULL;
-	}
 }
 
 /**
@@ -776,6 +763,9 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 	struct mrvl_priv *priv = dev->data->dev_private;
 	size_t i;
 
+	mrvl_flush_rx_queues(dev);
+	mrvl_flush_tx_shadow_queues(dev);
+
 	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
 		struct pp2_ppio_tc_params *tc_params =
 			&priv->ppio_params.inqs_params.tcs_params[i];
@@ -786,7 +776,28 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 		}
 	}
 
+	if (priv->cls_tbl) {
+		pp2_cls_tbl_deinit(priv->cls_tbl);
+		priv->cls_tbl = NULL;
+	}
+
+	if (priv->qos_tbl) {
+		pp2_cls_qos_tbl_deinit(priv->qos_tbl);
+		priv->qos_tbl = NULL;
+	}
+
 	mrvl_flush_bpool(dev);
+
+	if (priv->ppio) {
+		pp2_ppio_deinit(priv->ppio);
+		priv->ppio = NULL;
+	}
+
+	/* policer must be released after ppio deinitialization */
+	if (priv->policer) {
+		pp2_cls_plcr_deinit(priv->policer);
+		priv->policer = NULL;
+	}
 }
 
 /**
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 02/13] net/mvpp2: move common code
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
  2018-09-25  7:04     ` [dpdk-dev] [PATCH v3 01/13] net/mvpp2: initialize ppio only once Andrzej Ostruszka
@ 2018-09-25  7:04     ` Andrzej Ostruszka
  2018-09-25  7:04     ` [dpdk-dev] [PATCH v3 03/13] net/mvpp2: add metering support Andrzej Ostruszka
                       ` (11 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:04 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Tomasz Duszynski, Natalie Samsonov

From: Tomasz Duszynski <tdu@semihalf.com>

Cleanup sources by moving common code to the pmd
header file.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c |  9 ---------
 drivers/net/mvpp2/mrvl_ethdev.h | 11 +++++++++++
 drivers/net/mvpp2/mrvl_flow.c   |  5 -----
 drivers/net/mvpp2/mrvl_qos.c    |  9 ---------
 4 files changed, 11 insertions(+), 23 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index dca3ccc..c8c8548 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -10,15 +10,6 @@
 #include <rte_malloc.h>
 #include <rte_bus_vdev.h>
 
-/* Unluckily, container_of is defined by both DPDK and MUSDK,
- * we'll declare only one version.
- *
- * Note that it is not used in this PMD anyway.
- */
-#ifdef container_of
-#undef container_of
-#endif
-
 #include <fcntl.h>
 #include <linux/ethtool.h>
 #include <linux/sockios.h>
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index 3726f78..2204be2 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -10,12 +10,23 @@
 #include <rte_spinlock.h>
 #include <rte_flow_driver.h>
 
+/*
+ * container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+
 #include <env/mv_autogen_comp_flags.h>
 #include <drivers/mv_pp2.h>
 #include <drivers/mv_pp2_bpool.h>
 #include <drivers/mv_pp2_cls.h>
 #include <drivers/mv_pp2_hif.h>
 #include <drivers/mv_pp2_ppio.h>
+#include "env/mv_common.h" /* for BIT() */
 
 /** Maximum number of rx queues per port */
 #define MRVL_PP2_RXQ_MAX 32
diff --git a/drivers/net/mvpp2/mrvl_flow.c b/drivers/net/mvpp2/mrvl_flow.c
index 13295e6..db750f4 100644
--- a/drivers/net/mvpp2/mrvl_flow.c
+++ b/drivers/net/mvpp2/mrvl_flow.c
@@ -11,13 +11,8 @@
 
 #include <arpa/inet.h>
 
-#ifdef container_of
-#undef container_of
-#endif
-
 #include "mrvl_ethdev.h"
 #include "mrvl_qos.h"
-#include "env/mv_common.h" /* for BIT() */
 
 /** Number of rules in the classifier table. */
 #define MRVL_CLS_MAX_NUM_RULES 20
diff --git a/drivers/net/mvpp2/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c
index 71856c1..eeb46f8 100644
--- a/drivers/net/mvpp2/mrvl_qos.c
+++ b/drivers/net/mvpp2/mrvl_qos.c
@@ -15,15 +15,6 @@
 #include <rte_malloc.h>
 #include <rte_string_fns.h>
 
-/* Unluckily, container_of is defined by both DPDK and MUSDK,
- * we'll declare only one version.
- *
- * Note that it is not used in this PMD anyway.
- */
-#ifdef container_of
-#undef container_of
-#endif
-
 #include "mrvl_qos.h"
 
 /* Parsing tokens. Defined conveniently, so that any correction is easy. */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 03/13] net/mvpp2: add metering support
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
  2018-09-25  7:04     ` [dpdk-dev] [PATCH v3 01/13] net/mvpp2: initialize ppio only once Andrzej Ostruszka
  2018-09-25  7:04     ` [dpdk-dev] [PATCH v3 02/13] net/mvpp2: move common code Andrzej Ostruszka
@ 2018-09-25  7:04     ` Andrzej Ostruszka
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 04/13] net/mvpp2: change default policer configuration Andrzej Ostruszka
                       ` (10 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:04 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Tomasz Duszynski, Natalie Samsonov

From: Tomasz Duszynski <tdu@semihalf.com>

Add support for configuring plcr via DPDK generic metering API.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 drivers/net/mvpp2/Makefile      |   1 +
 drivers/net/mvpp2/meson.build   |   3 +-
 drivers/net/mvpp2/mrvl_ethdev.c |  24 ++
 drivers/net/mvpp2/mrvl_ethdev.h |  71 ++++++
 drivers/net/mvpp2/mrvl_flow.c   |  91 +++----
 drivers/net/mvpp2/mrvl_mtr.c    | 512 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/mvpp2/mrvl_mtr.h    |  15 ++
 7 files changed, 673 insertions(+), 44 deletions(-)
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.c
 create mode 100644 drivers/net/mvpp2/mrvl_mtr.h

diff --git a/drivers/net/mvpp2/Makefile b/drivers/net/mvpp2/Makefile
index 211d398..4848d65 100644
--- a/drivers/net/mvpp2/Makefile
+++ b/drivers/net/mvpp2/Makefile
@@ -39,5 +39,6 @@ LDLIBS += -lrte_bus_vdev -lrte_common_mvep
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_qos.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_mtr.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/mvpp2/meson.build b/drivers/net/mvpp2/meson.build
index 3620659..f475511 100644
--- a/drivers/net/mvpp2/meson.build
+++ b/drivers/net/mvpp2/meson.build
@@ -19,7 +19,8 @@ endif
 sources = files(
 	'mrvl_ethdev.c',
 	'mrvl_flow.c',
-	'mrvl_qos.c'
+	'mrvl_qos.c',
+	'mrvl_mtr.c'
 )
 
 deps += ['cfgfile', 'common_mvep']
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index c8c8548..a6cc550 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -23,6 +23,7 @@
 #include <rte_mvep_common.h>
 #include "mrvl_ethdev.h"
 #include "mrvl_qos.h"
+#include "mrvl_mtr.h"
 
 /* bitmask with reserved hifs */
 #define MRVL_MUSDK_HIFS_RESERVED 0x0F
@@ -618,6 +619,8 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 			goto out;
 	}
 
+	mrvl_mtr_init(dev);
+
 	return 0;
 out:
 	MRVL_LOG(ERR, "Failed to start device");
@@ -756,6 +759,7 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 
 	mrvl_flush_rx_queues(dev);
 	mrvl_flush_tx_shadow_queues(dev);
+	mrvl_mtr_deinit(dev);
 
 	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
 		struct pp2_ppio_tc_params *tc_params =
@@ -1858,6 +1862,25 @@ mrvl_eth_filter_ctrl(struct rte_eth_dev *dev __rte_unused,
 	}
 }
 
+/**
+ * DPDK callback to get rte_mtr callbacks.
+ *
+ * @param dev
+ *   Pointer to the device structure.
+ * @param ops
+ *   Pointer to pass the mtr ops.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_mtr_ops_get(struct rte_eth_dev *dev __rte_unused, void *ops)
+{
+	*(const void **)ops = &mrvl_mtr_ops;
+
+	return 0;
+}
+
 static const struct eth_dev_ops mrvl_ops = {
 	.dev_configure = mrvl_dev_configure,
 	.dev_start = mrvl_dev_start,
@@ -1895,6 +1918,7 @@ static const struct eth_dev_ops mrvl_ops = {
 	.rss_hash_update = mrvl_rss_hash_update,
 	.rss_hash_conf_get = mrvl_rss_hash_conf_get,
 	.filter_ctrl = mrvl_eth_filter_ctrl,
+	.mtr_ops_get = mrvl_mtr_ops_get,
 };
 
 /**
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index 2204be2..ecb8fdc 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -9,6 +9,7 @@
 
 #include <rte_spinlock.h>
 #include <rte_flow_driver.h>
+#include <rte_mtr_driver.h>
 
 /*
  * container_of is defined by both DPDK and MUSDK,
@@ -70,6 +71,69 @@
 /** Minimum number of sent buffers to release from shadow queue to BM */
 #define MRVL_PP2_BUF_RELEASE_BURST_SIZE	64
 
+/** Maximum length of a match string */
+#define MRVL_MATCH_LEN 16
+
+/** Parsed fields in processed rte_flow_item. */
+enum mrvl_parsed_fields {
+	/* eth flags */
+	F_DMAC =         BIT(0),
+	F_SMAC =         BIT(1),
+	F_TYPE =         BIT(2),
+	/* vlan flags */
+	F_VLAN_PRI =     BIT(3),
+	F_VLAN_ID =      BIT(4),
+	F_VLAN_TCI =     BIT(5), /* not supported by MUSDK yet */
+	/* ip4 flags */
+	F_IP4_TOS =      BIT(6),
+	F_IP4_SIP =      BIT(7),
+	F_IP4_DIP =      BIT(8),
+	F_IP4_PROTO =    BIT(9),
+	/* ip6 flags */
+	F_IP6_TC =       BIT(10), /* not supported by MUSDK yet */
+	F_IP6_SIP =      BIT(11),
+	F_IP6_DIP =      BIT(12),
+	F_IP6_FLOW =     BIT(13),
+	F_IP6_NEXT_HDR = BIT(14),
+	/* tcp flags */
+	F_TCP_SPORT =    BIT(15),
+	F_TCP_DPORT =    BIT(16),
+	/* udp flags */
+	F_UDP_SPORT =    BIT(17),
+	F_UDP_DPORT =    BIT(18),
+};
+
+/** PMD-specific definition of a flow rule handle. */
+struct mrvl_mtr;
+struct rte_flow {
+	LIST_ENTRY(rte_flow) next;
+	struct mrvl_mtr *mtr;
+
+	enum mrvl_parsed_fields pattern;
+
+	struct pp2_cls_tbl_rule rule;
+	struct pp2_cls_cos_desc cos;
+	struct pp2_cls_tbl_action action;
+};
+
+struct mrvl_mtr_profile {
+	LIST_ENTRY(mrvl_mtr_profile) next;
+	uint32_t profile_id;
+	int refcnt;
+	struct rte_mtr_meter_profile profile;
+};
+
+struct mrvl_mtr {
+	LIST_ENTRY(mrvl_mtr) next;
+	uint32_t mtr_id;
+	int refcnt;
+	int shared;
+	int enabled;
+	int plcr_bit;
+	struct mrvl_mtr_profile *profile;
+	struct pp2_cls_plcr *plcr;
+};
+
 struct mrvl_priv {
 	/* Hot fields, used in fast path. */
 	struct pp2_bpool *bpool;  /**< BPool pointer */
@@ -105,11 +169,18 @@ struct mrvl_priv {
 	LIST_HEAD(mrvl_flows, rte_flow) flows;
 
 	struct pp2_cls_plcr *policer;
+
+	LIST_HEAD(profiles, mrvl_mtr_profile) profiles;
+	LIST_HEAD(mtrs, mrvl_mtr) mtrs;
+	uint32_t used_plcrs;
 };
 
 /** Flow operations forward declaration. */
 extern const struct rte_flow_ops mrvl_flow_ops;
 
+/** Meter operations forward declaration. */
+extern const struct rte_mtr_ops mrvl_mtr_ops;
+
 /** Current log type. */
 extern int mrvl_logtype;
 
diff --git a/drivers/net/mvpp2/mrvl_flow.c b/drivers/net/mvpp2/mrvl_flow.c
index db750f4..e6953e4 100644
--- a/drivers/net/mvpp2/mrvl_flow.c
+++ b/drivers/net/mvpp2/mrvl_flow.c
@@ -20,46 +20,6 @@
 /** Size of the classifier key and mask strings. */
 #define MRVL_CLS_STR_SIZE_MAX 40
 
-/** Parsed fields in processed rte_flow_item. */
-enum mrvl_parsed_fields {
-	/* eth flags */
-	F_DMAC =         BIT(0),
-	F_SMAC =         BIT(1),
-	F_TYPE =         BIT(2),
-	/* vlan flags */
-	F_VLAN_ID =      BIT(3),
-	F_VLAN_PRI =     BIT(4),
-	F_VLAN_TCI =     BIT(5), /* not supported by MUSDK yet */
-	/* ip4 flags */
-	F_IP4_TOS =      BIT(6),
-	F_IP4_SIP =      BIT(7),
-	F_IP4_DIP =      BIT(8),
-	F_IP4_PROTO =    BIT(9),
-	/* ip6 flags */
-	F_IP6_TC =       BIT(10), /* not supported by MUSDK yet */
-	F_IP6_SIP =      BIT(11),
-	F_IP6_DIP =      BIT(12),
-	F_IP6_FLOW =     BIT(13),
-	F_IP6_NEXT_HDR = BIT(14),
-	/* tcp flags */
-	F_TCP_SPORT =    BIT(15),
-	F_TCP_DPORT =    BIT(16),
-	/* udp flags */
-	F_UDP_SPORT =    BIT(17),
-	F_UDP_DPORT =    BIT(18),
-};
-
-/** PMD-specific definition of a flow rule handle. */
-struct rte_flow {
-	LIST_ENTRY(rte_flow) next;
-
-	enum mrvl_parsed_fields pattern;
-
-	struct pp2_cls_tbl_rule rule;
-	struct pp2_cls_cos_desc cos;
-	struct pp2_cls_tbl_action action;
-};
-
 static const enum rte_flow_item_type pattern_eth[] = {
 	RTE_FLOW_ITEM_TYPE_ETH,
 	RTE_FLOW_ITEM_TYPE_END
@@ -2295,19 +2255,59 @@ mrvl_flow_parse_actions(struct mrvl_priv *priv,
 			flow->action.type = PP2_CLS_TBL_ACT_DONE;
 			flow->action.cos = &flow->cos;
 			specified++;
+		} else if (action->type == RTE_FLOW_ACTION_TYPE_METER) {
+			const struct rte_flow_action_meter *meter;
+			struct mrvl_mtr *mtr;
+
+			meter = action->conf;
+			if (!meter)
+				return -rte_flow_error_set(error, EINVAL,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL, "Invalid meter\n");
+
+			LIST_FOREACH(mtr, &priv->mtrs, next)
+				if (mtr->mtr_id == meter->mtr_id)
+					break;
+
+			if (!mtr)
+				return -rte_flow_error_set(error, EINVAL,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL,
+						"Meter id does not exist\n");
+
+			if (!mtr->shared && mtr->refcnt)
+				return -rte_flow_error_set(error, EPERM,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL,
+						"Meter cannot be shared\n");
+
+			/*
+			 * In case cos has already been set
+			 * do not modify it.
+			 */
+			if (!flow->cos.ppio) {
+				flow->cos.ppio = priv->ppio;
+				flow->cos.tc = 0;
+			}
+
+			flow->action.type = PP2_CLS_TBL_ACT_DONE;
+			flow->action.cos = &flow->cos;
+			flow->action.plcr = mtr->enabled ? mtr->plcr : NULL;
+			flow->mtr = mtr;
+			mtr->refcnt++;
+			specified++;
 		} else {
 			rte_flow_error_set(error, ENOTSUP,
 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
 					   "Action not supported");
 			return -rte_errno;
 		}
-
 	}
 
 	if (!specified) {
 		rte_flow_error_set(error, EINVAL,
-				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
-				   NULL, "Action not specified");
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Action not specified");
 		return -rte_errno;
 	}
 
@@ -2657,6 +2657,11 @@ mrvl_flow_remove(struct mrvl_priv *priv, struct rte_flow *flow,
 
 	mrvl_free_all_key_mask(&flow->rule);
 
+	if (flow->mtr) {
+		flow->mtr->refcnt--;
+		flow->mtr = NULL;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/mvpp2/mrvl_mtr.c b/drivers/net/mvpp2/mrvl_mtr.c
new file mode 100644
index 0000000..9cd53be
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_mtr.c
@@ -0,0 +1,512 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#include <rte_log.h>
+#include <rte_malloc.h>
+
+#include "mrvl_mtr.h"
+
+/** Maximum meter rate */
+#define MRVL_SRTCM_RFC2697_CIR_MAX 1023000
+
+/** Invalid plcr bit */
+#define MRVL_PLCR_BIT_INVALID -1
+
+/**
+ * Return meter object capabilities.
+ *
+ * @param dev Pointer to the device (unused).
+ * @param cap Pointer to the meter object capabilities.
+ * @param error Pointer to the error (unused).
+ * @returns 0 always.
+ */
+static int
+mrvl_capabilities_get(struct rte_eth_dev *dev __rte_unused,
+			  struct rte_mtr_capabilities *cap,
+			  struct rte_mtr_error *error __rte_unused)
+{
+	struct rte_mtr_capabilities capa = {
+		.n_max = PP2_CLS_PLCR_NUM,
+		.n_shared_max = PP2_CLS_PLCR_NUM,
+		.shared_n_flows_per_mtr_max = -1,
+		.meter_srtcm_rfc2697_n_max = PP2_CLS_PLCR_NUM,
+		.meter_rate_max = MRVL_SRTCM_RFC2697_CIR_MAX,
+	};
+
+	memcpy(cap, &capa, sizeof(capa));
+
+	return 0;
+}
+
+/**
+ * Get profile using it's id.
+ *
+ * @param priv Pointer to the port's private data.
+ * @param meter_profile_id Profile id used by the meter.
+ * @returns Pointer to the profile if exists, NULL otherwise.
+ */
+static struct mrvl_mtr_profile *
+mrvl_mtr_profile_from_id(struct mrvl_priv *priv, uint32_t meter_profile_id)
+{
+	struct mrvl_mtr_profile *profile = NULL;
+
+	LIST_FOREACH(profile, &priv->profiles, next)
+		if (profile->profile_id == meter_profile_id)
+			break;
+
+	return profile;
+}
+
+/**
+ * Add profile to the list of profiles.
+ *
+ * @param dev Pointer to the device.
+ * @param meter_profile_id Id of the new profile.
+ * @param profile Pointer to the profile configuration.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_profile_add(struct rte_eth_dev *dev, uint32_t meter_profile_id,
+		       struct rte_mtr_meter_profile *profile,
+		       struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *prof;
+
+	if (!profile)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, NULL);
+
+	if (profile->alg != RTE_MTR_SRTCM_RFC2697)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
+					  "Only srTCM RFC 2697 is supported\n");
+
+	prof = mrvl_mtr_profile_from_id(priv, meter_profile_id);
+	if (prof)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id already exists\n");
+
+	prof = rte_zmalloc_socket(NULL, sizeof(*prof), 0, rte_socket_id());
+	if (!prof)
+		return -rte_mtr_error_set(error, ENOMEM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, NULL);
+
+	prof->profile_id = meter_profile_id;
+	memcpy(&prof->profile, profile, sizeof(*profile));
+
+	LIST_INSERT_HEAD(&priv->profiles, prof, next);
+
+	return 0;
+}
+
+/**
+ * Remove profile from the list of profiles.
+ *
+ * @param dev Pointer to the device.
+ * @param meter_profile_id Id of the profile to remove.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_profile_delete(struct rte_eth_dev *dev,
+			      uint32_t meter_profile_id,
+			      struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile;
+
+	profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
+	if (!profile)
+		return -rte_mtr_error_set(error, ENODEV,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id does not exist\n");
+
+	if (profile->refcnt)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile is used\n");
+
+	LIST_REMOVE(profile, next);
+	rte_free(profile);
+
+	return 0;
+}
+
+/**
+ * Get meter using it's id.
+ *
+ * @param priv Pointer to port's private data.
+ * @param mtr_id Id of the meter.
+ * @returns Pointer to the meter if exists, NULL otherwise.
+ */
+static struct mrvl_mtr *
+mrvl_mtr_from_id(struct mrvl_priv *priv, uint32_t mtr_id)
+{
+	struct mrvl_mtr *mtr = NULL;
+
+	LIST_FOREACH(mtr, &priv->mtrs, next)
+		if (mtr->mtr_id == mtr_id)
+			break;
+
+	return mtr;
+}
+
+/**
+ * Reserve a policer bit in a bitmap.
+ *
+ * @param plcrs Pointer to the policers bitmap.
+ * @returns Reserved bit number on success, negative value otherwise.
+ */
+static int
+mrvl_reserve_plcr(uint32_t *plcrs)
+{
+	uint32_t i, num;
+
+	num = PP2_CLS_PLCR_NUM;
+	if (num > sizeof(uint32_t) * 8) {
+		num = sizeof(uint32_t) * 8;
+		MRVL_LOG(WARNING, "Plcrs number was limited to 32.");
+	}
+
+	for (i = 0; i < num; i++) {
+		uint32_t bit = BIT(i);
+
+		if (!(*plcrs & bit)) {
+			*plcrs |= bit;
+
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+/**
+ * Enable meter object.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter.
+ * @param error Pointer to the error.
+ * @returns 0 in success, negative value otherwise.
+ */
+static int
+mrvl_meter_enable(struct rte_eth_dev *dev, uint32_t mtr_id,
+		  struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
+	struct pp2_cls_plcr_params params;
+	char match[MRVL_MATCH_LEN];
+	struct rte_flow *flow;
+	int ret;
+
+	if (!priv->ppio)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Port is uninitialized\n");
+
+	if (!mtr)
+		return -rte_mtr_error_set(error, ENODEV,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	if (mtr->plcr)
+		goto skip;
+
+	mtr->plcr_bit = mrvl_reserve_plcr(&priv->used_plcrs);
+	if (mtr->plcr_bit < 0)
+		return -rte_mtr_error_set(error, ENOSPC,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
+					  "Failed to reserve plcr entry\n");
+
+	memset(&params, 0, sizeof(params));
+	snprintf(match, sizeof(match), "policer-%d:%d", priv->pp_id,
+		 mtr->plcr_bit);
+	params.match = match;
+	params.token_unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
+	params.color_mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
+	params.cir = mtr->profile->profile.srtcm_rfc2697.cir;
+	params.cbs = mtr->profile->profile.srtcm_rfc2697.cbs;
+	params.ebs = mtr->profile->profile.srtcm_rfc2697.ebs;
+
+	ret = pp2_cls_plcr_init(&params, &mtr->plcr);
+	if (ret) {
+		priv->used_plcrs &= ~BIT(mtr->plcr_bit);
+		mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
+
+		return -rte_mtr_error_set(error, -ret,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Failed to setup policer\n");
+	}
+
+	mtr->enabled = 1;
+skip:
+	/* iterate over flows that have this mtr attached */
+	LIST_FOREACH(flow, &priv->flows, next) {
+		if (flow->mtr != mtr)
+			continue;
+
+		flow->action.plcr = mtr->plcr;
+
+		ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
+					      &flow->action);
+		if (ret)
+			return -rte_mtr_error_set(error, -ret,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Failed to update cls rule\n");
+	}
+
+	return 0;
+}
+
+/**
+ * Disable meter object.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr Id of the meter.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_disable(struct rte_eth_dev *dev, uint32_t mtr_id,
+		       struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
+	struct rte_flow *flow;
+	int ret;
+
+	if (!mtr)
+		return -rte_mtr_error_set(error, ENODEV,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	LIST_FOREACH(flow, &priv->flows, next) {
+		if (flow->mtr != mtr)
+			continue;
+
+		flow->action.plcr = NULL;
+
+		ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
+					      &flow->action);
+		if (ret)
+			return -rte_mtr_error_set(error, -ret,
+					RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					NULL, "Failed to disable meter\n");
+	}
+
+	mtr->enabled = 0;
+
+	return 0;
+}
+
+/**
+ * Create new meter.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter.
+ * @param params Pointer to the meter parameters.
+ * @param shared Flags indicating whether meter is shared.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_create(struct rte_eth_dev *dev, uint32_t mtr_id,
+	    struct rte_mtr_params *params, int shared,
+	    struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile;
+	struct mrvl_mtr *mtr;
+
+	mtr = mrvl_mtr_from_id(priv, mtr_id);
+	if (mtr)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id already exists\n");
+
+	mtr = rte_zmalloc_socket(NULL, sizeof(*mtr), 0, rte_socket_id());
+	if (!mtr)
+		return -rte_mtr_error_set(error, ENOMEM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, NULL);
+
+	profile = mrvl_mtr_profile_from_id(priv, params->meter_profile_id);
+	if (!profile)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id does not exist\n");
+
+	mtr->shared = shared;
+	mtr->mtr_id = mtr_id;
+	mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
+	mtr->profile = profile;
+	profile->refcnt++;
+	LIST_INSERT_HEAD(&priv->mtrs, mtr, next);
+
+	if (params->meter_enable)
+		return mrvl_meter_enable(dev, mtr_id, error);
+
+	return 0;
+}
+
+/**
+ * Destroy meter object.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter object.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_destroy(struct rte_eth_dev *dev, uint32_t mtr_id,
+		 struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr *mtr;
+
+	if (!priv->ppio)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Port is uninitialized\n");
+
+	mtr = mrvl_mtr_from_id(priv, mtr_id);
+	if (!mtr)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	if (mtr->refcnt)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter is used\n");
+
+	LIST_REMOVE(mtr, next);
+	mtr->profile->refcnt--;
+
+	if (mtr->plcr_bit != MRVL_PLCR_BIT_INVALID)
+		priv->used_plcrs &= ~BIT(mtr->plcr_bit);
+
+	if (mtr->plcr)
+		pp2_cls_plcr_deinit(mtr->plcr);
+
+	rte_free(mtr);
+
+	return 0;
+}
+
+/**
+ * Update profile used by the meter.
+ *
+ * @param dev Pointer to the device.
+ * @param mtr_id Id of the meter object.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_meter_profile_update(struct rte_eth_dev *dev, uint32_t mtr_id,
+			  uint32_t meter_profile_id,
+			  struct rte_mtr_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile;
+	struct mrvl_mtr *mtr;
+	int ret, enabled;
+
+	if (!priv->ppio)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Port is uninitialized\n");
+
+	mtr = mrvl_mtr_from_id(priv, mtr_id);
+	if (!mtr)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Meter id does not exist\n");
+
+	profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
+	if (!profile)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Profile id does not exist\n");
+
+	ret = mrvl_meter_disable(dev, mtr_id, error);
+	if (ret)
+		return -rte_mtr_error_set(error, EPERM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  NULL);
+
+	if (mtr->plcr) {
+		enabled = 1;
+		pp2_cls_plcr_deinit(mtr->plcr);
+		mtr->plcr = NULL;
+	}
+
+	mtr->profile->refcnt--;
+	mtr->profile = profile;
+	profile->refcnt++;
+
+	if (enabled)
+		return mrvl_meter_enable(dev, mtr_id, error);
+
+	return 0;
+}
+
+const struct rte_mtr_ops mrvl_mtr_ops = {
+	.capabilities_get = mrvl_capabilities_get,
+	.meter_profile_add = mrvl_meter_profile_add,
+	.meter_profile_delete = mrvl_meter_profile_delete,
+	.create = mrvl_create,
+	.destroy = mrvl_destroy,
+	.meter_enable = mrvl_meter_enable,
+	.meter_disable = mrvl_meter_disable,
+	.meter_profile_update = mrvl_meter_profile_update,
+};
+
+/**
+ * Initialize metering resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_mtr_init(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	LIST_INIT(&priv->profiles);
+	LIST_INIT(&priv->mtrs);
+}
+
+/**
+ * Cleanup metering resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_mtr_deinit(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_mtr_profile *profile, *tmp_profile;
+	struct mrvl_mtr *mtr, *tmp_mtr;
+
+	for (mtr = LIST_FIRST(&priv->mtrs);
+	     mtr && (tmp_mtr = LIST_NEXT(mtr, next), 1);
+	     mtr = tmp_mtr)
+		mrvl_destroy(dev, mtr->mtr_id, NULL);
+
+	for (profile = LIST_FIRST(&priv->profiles);
+	     profile && (tmp_profile = LIST_NEXT(profile, next), 1);
+	     profile = tmp_profile)
+		mrvl_meter_profile_delete(dev, profile->profile_id, NULL);
+}
diff --git a/drivers/net/mvpp2/mrvl_mtr.h b/drivers/net/mvpp2/mrvl_mtr.h
new file mode 100644
index 0000000..302a20f
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_mtr.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#ifndef _MRVL_MTR_H_
+#define _MRVL_MTR_H_
+
+#include "mrvl_ethdev.h"
+
+void mrvl_mtr_init(struct rte_eth_dev *dev);
+void mrvl_mtr_deinit(struct rte_eth_dev *dev);
+
+#endif /* _MRVL_MTR_H_ */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 04/13] net/mvpp2: change default policer configuration
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
                       ` (2 preceding siblings ...)
  2018-09-25  7:04     ` [dpdk-dev] [PATCH v3 03/13] net/mvpp2: add metering support Andrzej Ostruszka
@ 2018-09-25  7:05     ` Andrzej Ostruszka
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 05/13] net/mvpp2: add init and deinit to flow Andrzej Ostruszka
                       ` (9 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:05 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Tomasz Duszynski, Natalie Samsonov

From: Tomasz Duszynski <tdu@semihalf.com>

Change QoS configuration file syntax for port's default policer
setup.

Since default policer configuration is performed before
any other policer configuration we can pick a default id.

This simplifies default policer configuration since user
no longer has to choose ids from range [0, PP2_CLS_PLCR_NUM].

Explicitly document values for rate_limit_enable field.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 doc/guides/nics/mvpp2.rst       |  31 ++++---
 drivers/net/mvpp2/mrvl_ethdev.c |   6 +-
 drivers/net/mvpp2/mrvl_ethdev.h |   2 +-
 drivers/net/mvpp2/mrvl_qos.c    | 198 ++++++++++++++++++++++------------------
 drivers/net/mvpp2/mrvl_qos.h    |   2 +-
 5 files changed, 134 insertions(+), 105 deletions(-)

diff --git a/doc/guides/nics/mvpp2.rst b/doc/guides/nics/mvpp2.rst
index 0408752..a452c8a 100644
--- a/doc/guides/nics/mvpp2.rst
+++ b/doc/guides/nics/mvpp2.rst
@@ -152,20 +152,23 @@ Configuration syntax
 
 .. code-block:: console
 
-   [port <portnum> default]
-   default_tc = <default_tc>
-   mapping_priority = <mapping_priority>
-   policer_enable = <policer_enable>
+   [policer <policer_id>]
    token_unit = <token_unit>
    color = <color_mode>
    cir = <cir>
    ebs = <ebs>
    cbs = <cbs>
 
+   [port <portnum> default]
+   default_tc = <default_tc>
+   mapping_priority = <mapping_priority>
+
    rate_limit_enable = <rate_limit_enable>
    rate_limit = <rate_limit>
    burst_size = <burst_size>
 
+   default_policer = <policer_id>
+
    [port <portnum> tc <traffic_class>]
    rxq = <rx_queue_list>
    pcp = <pcp_list>
@@ -201,7 +204,9 @@ Where:
 
 - ``<dscp_list>``: List of DSCP values to handle in particular TC (e.g. 0-12 32-48 63).
 
-- ``<policer_enable>``: Enable ingress policer.
+- ``<default_policer>``: Id of the policer configuration section to be used as default.
+
+- ``<policer_id>``: Id of the policer configuration section (0..31).
 
 - ``<token_unit>``: Policer token unit (`bytes` or `packets`).
 
@@ -215,7 +220,7 @@ Where:
 
 - ``<default_color>``: Default color for specific tc.
 
-- ``<rate_limit_enable>``: Enables per port or per txq rate limiting.
+- ``<rate_limit_enable>``: Enables per port or per txq rate limiting (`0`/`1` to disable/enable).
 
 - ``<rate_limit>``: Committed information rate, in kilo bits per second.
 
@@ -234,6 +239,13 @@ Configuration file example
 
 .. code-block:: console
 
+   [policer 0]
+   token_unit = bytes
+   color = blind
+   cir = 100000
+   ebs = 64
+   cbs = 64
+
    [port 0 default]
    default_tc = 0
    mapping_priority = ip
@@ -265,12 +277,7 @@ Configuration file example
    default_tc = 0
    mapping_priority = vlan/ip
 
-   policer_enable = 1
-   token_unit = bytes
-   color = blind
-   cir = 100000
-   ebs = 64
-   cbs = 64
+   default_policer = 0
 
    [port 1 tc 0]
    rxq = 0
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index a6cc550..0571635 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -789,9 +789,9 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 	}
 
 	/* policer must be released after ppio deinitialization */
-	if (priv->policer) {
-		pp2_cls_plcr_deinit(priv->policer);
-		priv->policer = NULL;
+	if (priv->default_policer) {
+		pp2_cls_plcr_deinit(priv->default_policer);
+		priv->default_policer = NULL;
 	}
 }
 
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index ecb8fdc..de423a9 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -168,7 +168,7 @@ struct mrvl_priv {
 	uint32_t cls_tbl_pattern;
 	LIST_HEAD(mrvl_flows, rte_flow) flows;
 
-	struct pp2_cls_plcr *policer;
+	struct pp2_cls_plcr *default_policer;
 
 	LIST_HEAD(profiles, mrvl_mtr_profile) profiles;
 	LIST_HEAD(mtrs, mrvl_mtr) mtrs;
diff --git a/drivers/net/mvpp2/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c
index eeb46f8..e039635 100644
--- a/drivers/net/mvpp2/mrvl_qos.c
+++ b/drivers/net/mvpp2/mrvl_qos.c
@@ -42,7 +42,8 @@
 #define MRVL_TOK_WRR_WEIGHT "wrr_weight"
 
 /* policer specific configuration tokens */
-#define MRVL_TOK_PLCR_ENABLE "policer_enable"
+#define MRVL_TOK_PLCR "policer"
+#define MRVL_TOK_PLCR_DEFAULT "default_policer"
 #define MRVL_TOK_PLCR_UNIT "token_unit"
 #define MRVL_TOK_PLCR_UNIT_BYTES "bytes"
 #define MRVL_TOK_PLCR_UNIT_PACKETS "packets"
@@ -368,6 +369,9 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
 		cfg->port[port].tc[tc].dscps = n;
 	}
 
+	if (!cfg->port[port].setup_policer)
+		return 0;
+
 	entry = rte_cfgfile_get_entry(file, sec_name,
 			MRVL_TOK_PLCR_DEFAULT_COLOR);
 	if (entry) {
@@ -390,6 +394,85 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
 }
 
 /**
+ * Parse default port policer.
+ *
+ * @param file Config file handle.
+ * @param sec_name Section name with policer configuration
+ * @param port Port number.
+ * @param cfg[out] Parsing results.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
+		struct mrvl_qos_cfg *cfg)
+{
+	const char *entry;
+	uint32_t val;
+
+	/* Read policer token unit */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_UNIT);
+	if (entry) {
+		if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
+					sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
+			cfg->port[port].policer_params.token_unit =
+				PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
+		} else if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_PACKETS,
+					sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
+			cfg->port[port].policer_params.token_unit =
+				PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
+		} else {
+			RTE_LOG(ERR, PMD, "Unknown token: %s\n", entry);
+			return -1;
+		}
+	}
+
+	/* Read policer color mode */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_COLOR);
+	if (entry) {
+		if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
+					sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
+			cfg->port[port].policer_params.color_mode =
+				PP2_CLS_PLCR_COLOR_BLIND_MODE;
+		} else if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_AWARE,
+					sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
+			cfg->port[port].policer_params.color_mode =
+				PP2_CLS_PLCR_COLOR_AWARE_MODE;
+		} else {
+			RTE_LOG(ERR, PMD, "Error in parsing: %s\n", entry);
+			return -1;
+		}
+	}
+
+	/* Read policer cir */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CIR);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].policer_params.cir = val;
+	}
+
+	/* Read policer cbs */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CBS);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].policer_params.cbs = val;
+	}
+
+	/* Read policer ebs */
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_EBS);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].policer_params.ebs = val;
+	}
+
+	cfg->port[port].setup_policer = 1;
+
+	return 0;
+}
+
+/**
  * Parse QoS configuration - rte_kvargs_process handler.
  *
  * Opens configuration file and parses its content.
@@ -457,88 +540,6 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 			return -1;
 		}
 
-		entry = rte_cfgfile_get_entry(file, sec_name,
-				MRVL_TOK_PLCR_ENABLE);
-		if (entry) {
-			if (get_val_securely(entry, &val) < 0)
-				return -1;
-			(*cfg)->port[n].policer_enable = val;
-		}
-
-		if ((*cfg)->port[n].policer_enable) {
-			enum pp2_cls_plcr_token_unit unit;
-
-			/* Read policer token unit */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_UNIT);
-			if (entry) {
-				if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
-					sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
-					unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
-				} else if (!strncmp(entry,
-						MRVL_TOK_PLCR_UNIT_PACKETS,
-					sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
-					unit = PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
-				} else {
-					MRVL_LOG(ERR, "Unknown token: %s",
-						entry);
-					return -1;
-				}
-				(*cfg)->port[n].policer_params.token_unit =
-					unit;
-			}
-
-			/* Read policer color mode */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_COLOR);
-			if (entry) {
-				enum pp2_cls_plcr_color_mode mode;
-
-				if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
-					sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
-					mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
-				} else if (!strncmp(entry,
-						MRVL_TOK_PLCR_COLOR_AWARE,
-					sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
-					mode = PP2_CLS_PLCR_COLOR_AWARE_MODE;
-				} else {
-					MRVL_LOG(ERR,
-						"Error in parsing: %s",
-						entry);
-					return -1;
-				}
-				(*cfg)->port[n].policer_params.color_mode =
-					mode;
-			}
-
-			/* Read policer cir */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_CIR);
-			if (entry) {
-				if (get_val_securely(entry, &val) < 0)
-					return -1;
-				(*cfg)->port[n].policer_params.cir = val;
-			}
-
-			/* Read policer cbs */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_CBS);
-			if (entry) {
-				if (get_val_securely(entry, &val) < 0)
-					return -1;
-				(*cfg)->port[n].policer_params.cbs = val;
-			}
-
-			/* Read policer ebs */
-			entry = rte_cfgfile_get_entry(file, sec_name,
-					MRVL_TOK_PLCR_EBS);
-			if (entry) {
-				if (get_val_securely(entry, &val) < 0)
-					return -1;
-				(*cfg)->port[n].policer_params.ebs = val;
-			}
-		}
-
 		/*
 		 * Read per-port rate limiting. Setting that will
 		 * disable per-queue rate limiting.
@@ -597,6 +598,20 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
 		}
 
+		/* Parse policer configuration (if any) */
+		entry = rte_cfgfile_get_entry(file, sec_name,
+				MRVL_TOK_PLCR_DEFAULT);
+		if (entry) {
+			if (get_val_securely(entry, &val) < 0)
+				return -1;
+
+			snprintf(sec_name, sizeof(sec_name), "%s %d",
+					MRVL_TOK_PLCR, val);
+			ret = parse_policer(file, n, sec_name, *cfg);
+			if (ret)
+				return -1;
+		}
+
 		for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
 			ret = get_outq_cfg(file, n, i, *cfg);
 			if (ret < 0)
@@ -659,6 +674,7 @@ setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
  *
  * @param priv Port's private data.
  * @param params Pointer to the policer's configuration.
+ * @param plcr_id Policer id.
  * @returns 0 in case of success, negative values otherwise.
  */
 static int
@@ -667,17 +683,23 @@ setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
 	char match[16];
 	int ret;
 
-	snprintf(match, sizeof(match), "policer-%d:%d\n",
-			priv->pp_id, priv->ppio_id);
+	/*
+	 * At this point no other policers are used which means
+	 * any policer can be picked up and used as a default one.
+	 *
+	 * Lets use 0th then.
+	 */
+	sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
 	params->match = match;
 
-	ret = pp2_cls_plcr_init(params, &priv->policer);
+	ret = pp2_cls_plcr_init(params, &priv->default_policer);
 	if (ret) {
 		MRVL_LOG(ERR, "Failed to setup %s", match);
 		return -1;
 	}
 
-	priv->ppio_params.inqs_params.plcr = priv->policer;
+	priv->ppio_params.inqs_params.plcr = priv->default_policer;
+	priv->used_plcrs = BIT(0);
 
 	return 0;
 }
@@ -809,7 +831,7 @@ mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
 
 	priv->ppio_params.inqs_params.num_tcs = i;
 
-	if (port_cfg->policer_enable)
+	if (port_cfg->setup_policer)
 		return setup_policer(priv, &port_cfg->policer_params);
 
 	return 0;
diff --git a/drivers/net/mvpp2/mrvl_qos.h b/drivers/net/mvpp2/mrvl_qos.h
index fa9ddec..f03e773 100644
--- a/drivers/net/mvpp2/mrvl_qos.h
+++ b/drivers/net/mvpp2/mrvl_qos.h
@@ -43,7 +43,7 @@ struct mrvl_qos_cfg {
 		uint8_t default_tc;
 		uint8_t use_global_defaults;
 		struct pp2_cls_plcr_params policer_params;
-		uint8_t policer_enable;
+		uint8_t setup_policer;
 	} port[RTE_MAX_ETHPORTS];
 };
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 05/13] net/mvpp2: add init and deinit to flow
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
                       ` (3 preceding siblings ...)
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 04/13] net/mvpp2: change default policer configuration Andrzej Ostruszka
@ 2018-09-25  7:05     ` Andrzej Ostruszka
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 06/13] net/mvpp2: add traffic manager support Andrzej Ostruszka
                       ` (8 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:05 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Tomasz Duszynski, Natalie Samsonov

From: Tomasz Duszynski <tdu@semihalf.com>

Add init and deinit functionality to flow implementation.

Init puts structures used by flow in a sane sate.
Deinit deallocates all resources used by flow.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
Reviewed-by: Shlomi Gridish <sgridish@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c |  3 +++
 drivers/net/mvpp2/mrvl_flow.c   | 33 ++++++++++++++++++++++++++++++++-
 drivers/net/mvpp2/mrvl_flow.h   | 15 +++++++++++++++
 3 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/mvpp2/mrvl_flow.h

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 0571635..461f297 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -23,6 +23,7 @@
 #include <rte_mvep_common.h>
 #include "mrvl_ethdev.h"
 #include "mrvl_qos.h"
+#include "mrvl_flow.h"
 #include "mrvl_mtr.h"
 
 /* bitmask with reserved hifs */
@@ -619,6 +620,7 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 			goto out;
 	}
 
+	mrvl_flow_init(dev);
 	mrvl_mtr_init(dev);
 
 	return 0;
@@ -759,6 +761,7 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 
 	mrvl_flush_rx_queues(dev);
 	mrvl_flush_tx_shadow_queues(dev);
+	mrvl_flow_deinit(dev);
 	mrvl_mtr_deinit(dev);
 
 	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
diff --git a/drivers/net/mvpp2/mrvl_flow.c b/drivers/net/mvpp2/mrvl_flow.c
index e6953e4..065b1aa 100644
--- a/drivers/net/mvpp2/mrvl_flow.c
+++ b/drivers/net/mvpp2/mrvl_flow.c
@@ -11,7 +11,7 @@
 
 #include <arpa/inet.h>
 
-#include "mrvl_ethdev.h"
+#include "mrvl_flow.h"
 #include "mrvl_qos.h"
 
 /** Number of rules in the classifier table. */
@@ -2790,3 +2790,34 @@ const struct rte_flow_ops mrvl_flow_ops = {
 	.flush = mrvl_flow_flush,
 	.isolate = mrvl_flow_isolate
 };
+
+/**
+ * Initialize flow resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_flow_init(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	LIST_INIT(&priv->flows);
+}
+
+/**
+ * Cleanup flow resources.
+ *
+ * @param dev Pointer to the device.
+ */
+void
+mrvl_flow_deinit(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	mrvl_flow_flush(dev, NULL);
+
+	if (priv->cls_tbl) {
+		pp2_cls_tbl_deinit(priv->cls_tbl);
+		priv->cls_tbl = NULL;
+	}
+}
diff --git a/drivers/net/mvpp2/mrvl_flow.h b/drivers/net/mvpp2/mrvl_flow.h
new file mode 100644
index 0000000..f63747c
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_flow.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#ifndef _MRVL_FLOW_H_
+#define _MRVL_FLOW_H_
+
+#include "mrvl_ethdev.h"
+
+void mrvl_flow_init(struct rte_eth_dev *dev);
+void mrvl_flow_deinit(struct rte_eth_dev *dev);
+
+#endif /* _MRVL_FLOW_H_ */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 06/13] net/mvpp2: add traffic manager support
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
                       ` (4 preceding siblings ...)
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 05/13] net/mvpp2: add init and deinit to flow Andrzej Ostruszka
@ 2018-09-25  7:05     ` Andrzej Ostruszka
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 07/13] net/mvpp2: detach Tx QoS from Rx cls/QoS config Andrzej Ostruszka
                       ` (7 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:05 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Tomasz Duszynski, Natalie Samsonov

From: Tomasz Duszynski <tdu@semihalf.com>

Add traffic manager support.

Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 drivers/net/mvpp2/Makefile      |    1 +
 drivers/net/mvpp2/meson.build   |    3 +-
 drivers/net/mvpp2/mrvl_ethdev.c |   26 +
 drivers/net/mvpp2/mrvl_ethdev.h |   31 ++
 drivers/net/mvpp2/mrvl_tm.c     | 1009 +++++++++++++++++++++++++++++++++++++++
 drivers/net/mvpp2/mrvl_tm.h     |   15 +
 6 files changed, 1084 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/mvpp2/mrvl_tm.c
 create mode 100644 drivers/net/mvpp2/mrvl_tm.h

diff --git a/drivers/net/mvpp2/Makefile b/drivers/net/mvpp2/Makefile
index 4848d65..661d2cd 100644
--- a/drivers/net/mvpp2/Makefile
+++ b/drivers/net/mvpp2/Makefile
@@ -40,5 +40,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_qos.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_mtr.c
+SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_tm.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/mvpp2/meson.build b/drivers/net/mvpp2/meson.build
index f475511..70ef2d6 100644
--- a/drivers/net/mvpp2/meson.build
+++ b/drivers/net/mvpp2/meson.build
@@ -20,7 +20,8 @@ sources = files(
 	'mrvl_ethdev.c',
 	'mrvl_flow.c',
 	'mrvl_qos.c',
-	'mrvl_mtr.c'
+	'mrvl_mtr.c',
+	'mrvl_tm.c'
 )
 
 deps += ['cfgfile', 'common_mvep']
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 461f297..4d1e84a 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -25,6 +25,7 @@
 #include "mrvl_qos.h"
 #include "mrvl_flow.h"
 #include "mrvl_mtr.h"
+#include "mrvl_tm.h"
 
 /* bitmask with reserved hifs */
 #define MRVL_MUSDK_HIFS_RESERVED 0x0F
@@ -331,6 +332,10 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 	priv->ppio_params.maintain_stats = 1;
 	priv->nb_rx_queues = dev->data->nb_rx_queues;
 
+	ret = mrvl_tm_init(dev);
+	if (ret < 0)
+		return ret;
+
 	if (dev->data->nb_rx_queues == 1 &&
 	    dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_RSS) {
 		MRVL_LOG(WARNING, "Disabling hash for 1 rx queue");
@@ -785,6 +790,7 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 	}
 
 	mrvl_flush_bpool(dev);
+	mrvl_tm_deinit(dev);
 
 	if (priv->ppio) {
 		pp2_ppio_deinit(priv->ppio);
@@ -1884,6 +1890,25 @@ mrvl_mtr_ops_get(struct rte_eth_dev *dev __rte_unused, void *ops)
 	return 0;
 }
 
+/**
+ * DPDK callback to get rte_tm callbacks.
+ *
+ * @param dev
+ *   Pointer to the device structure.
+ * @param ops
+ *   Pointer to pass the tm ops.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *ops)
+{
+	*(const void **)ops = &mrvl_tm_ops;
+
+	return 0;
+}
+
 static const struct eth_dev_ops mrvl_ops = {
 	.dev_configure = mrvl_dev_configure,
 	.dev_start = mrvl_dev_start,
@@ -1922,6 +1947,7 @@ static const struct eth_dev_ops mrvl_ops = {
 	.rss_hash_conf_get = mrvl_rss_hash_conf_get,
 	.filter_ctrl = mrvl_eth_filter_ctrl,
 	.mtr_ops_get = mrvl_mtr_ops_get,
+	.tm_ops_get = mrvl_tm_ops_get,
 };
 
 /**
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index de423a9..984f31e 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -10,6 +10,7 @@
 #include <rte_spinlock.h>
 #include <rte_flow_driver.h>
 #include <rte_mtr_driver.h>
+#include <rte_tm_driver.h>
 
 /*
  * container_of is defined by both DPDK and MUSDK,
@@ -134,6 +135,29 @@ struct mrvl_mtr {
 	struct pp2_cls_plcr *plcr;
 };
 
+struct mrvl_tm_shaper_profile {
+	LIST_ENTRY(mrvl_tm_shaper_profile) next;
+	uint32_t id;
+	int refcnt;
+	struct rte_tm_shaper_params params;
+};
+
+enum {
+	MRVL_NODE_PORT,
+	MRVL_NODE_QUEUE,
+};
+
+struct mrvl_tm_node {
+	LIST_ENTRY(mrvl_tm_node) next;
+	uint32_t id;
+	uint32_t type;
+	int refcnt;
+	struct mrvl_tm_node *parent;
+	struct mrvl_tm_shaper_profile *profile;
+	uint8_t weight;
+	uint64_t stats_mask;
+};
+
 struct mrvl_priv {
 	/* Hot fields, used in fast path. */
 	struct pp2_bpool *bpool;  /**< BPool pointer */
@@ -173,6 +197,10 @@ struct mrvl_priv {
 	LIST_HEAD(profiles, mrvl_mtr_profile) profiles;
 	LIST_HEAD(mtrs, mrvl_mtr) mtrs;
 	uint32_t used_plcrs;
+
+	LIST_HEAD(shaper_profiles, mrvl_tm_shaper_profile) shaper_profiles;
+	LIST_HEAD(nodes, mrvl_tm_node) nodes;
+	uint64_t rate_max;
 };
 
 /** Flow operations forward declaration. */
@@ -181,6 +209,9 @@ extern const struct rte_flow_ops mrvl_flow_ops;
 /** Meter operations forward declaration. */
 extern const struct rte_mtr_ops mrvl_mtr_ops;
 
+/** Traffic manager operations forward declaration. */
+extern const struct rte_tm_ops mrvl_tm_ops;
+
 /** Current log type. */
 extern int mrvl_logtype;
 
diff --git a/drivers/net/mvpp2/mrvl_tm.c b/drivers/net/mvpp2/mrvl_tm.c
new file mode 100644
index 0000000..3de8997
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_tm.c
@@ -0,0 +1,1009 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#include <rte_malloc.h>
+
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "mrvl_tm.h"
+
+/** Minimum rate value in Bytes/s */
+#define MRVL_RATE_MIN (PP2_PPIO_MIN_CIR * 1000 / 8)
+
+/** Minimum burst size in Bytes */
+#define MRVL_BURST_MIN (PP2_PPIO_MIN_CBS * 1000)
+
+/** Maximum burst size in Bytes */
+#define MRVL_BURST_MAX 256000000
+
+/** Maximum WRR weight */
+#define MRVL_WEIGHT_MAX 255
+
+/**
+ * Get maximum port rate in Bytes/s.
+ *
+ * @param dev Pointer to the device.
+ * @param rate Pointer to the rate.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_get_max_rate(struct rte_eth_dev *dev, uint64_t *rate)
+{
+	struct ethtool_cmd edata;
+	struct ifreq req;
+	int ret, fd;
+
+	memset(&edata, 0, sizeof(edata));
+	memset(&req, 0, sizeof(req));
+	edata.cmd = ETHTOOL_GSET;
+	strcpy(req.ifr_name, dev->data->name);
+	req.ifr_data = (void *)&edata;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd == -1)
+		return -1;
+
+	ret = ioctl(fd, SIOCETHTOOL, &req);
+	if (ret == -1) {
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+
+	*rate = ethtool_cmd_speed(&edata) * 1000 * 1000 / 8;
+
+	return 0;
+}
+
+/**
+ * Initialize traffic manager related data.
+ *
+ * @param dev Pointer to the device.
+ * @returns 0 on success, failure otherwise.
+ */
+int
+mrvl_tm_init(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	LIST_INIT(&priv->shaper_profiles);
+	LIST_INIT(&priv->nodes);
+
+	if (priv->rate_max)
+		return 0;
+
+	return mrvl_get_max_rate(dev, &priv->rate_max);
+}
+
+/**
+ * Cleanup traffic manager related data.
+ *
+ * @param dev Pointer to the device.
+ */
+void mrvl_tm_deinit(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile =
+		LIST_FIRST(&priv->shaper_profiles);
+	struct mrvl_tm_node *node = LIST_FIRST(&priv->nodes);
+
+	while (profile) {
+		struct mrvl_tm_shaper_profile *next = LIST_NEXT(profile, next);
+
+		LIST_REMOVE(profile, next);
+		rte_free(profile);
+		profile = next;
+	}
+
+	while (node) {
+		struct mrvl_tm_node *next = LIST_NEXT(node, next);
+
+		LIST_REMOVE(node, next);
+		rte_free(node);
+		node = next;
+	}
+}
+
+/**
+ * Get node using its id.
+ *
+ * @param priv Pointer to the port's private data.
+ * @param node_id Id used by this node.
+ * @returns Pointer to the node if exists, NULL otherwise.
+ */
+static struct mrvl_tm_node *
+mrvl_node_from_id(struct mrvl_priv *priv, uint32_t node_id)
+{
+	struct mrvl_tm_node *node;
+
+	LIST_FOREACH(node, &priv->nodes, next)
+		if (node->id == node_id)
+			return node;
+
+	return NULL;
+}
+
+/**
+ * Check whether node is leaf or root.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id used by this node.
+ * @param is_leaf Pointer to flag indicating whether node is a leaf.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_type_get(struct rte_eth_dev *dev, uint32_t node_id, int *is_leaf,
+		   struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	if (!is_leaf)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	*is_leaf = node->type == MRVL_NODE_QUEUE ? 1 : 0;
+
+	return 0;
+}
+
+/**
+ * Get traffic manager capabilities.
+ *
+ * @param dev Pointer to the device (unused).
+ * @param cap Pointer to the capabilities.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_capabilities_get(struct rte_eth_dev *dev,
+		      struct rte_tm_capabilities *cap,
+		      struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	if (!cap)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Capabilities are missing\n");
+
+	memset(cap, 0, sizeof(*cap));
+
+	cap->n_nodes_max = 1 + dev->data->nb_tx_queues; /* port + txqs number */
+	cap->n_levels_max = 2; /* port level + txqs level */
+	cap->non_leaf_nodes_identical = 1;
+	cap->leaf_nodes_identical = 1;
+
+	cap->shaper_n_max = cap->n_nodes_max;
+	cap->shaper_private_n_max = cap->shaper_n_max;
+	cap->shaper_private_rate_min = MRVL_RATE_MIN;
+	cap->shaper_private_rate_max = priv->rate_max;
+
+	cap->sched_n_children_max = dev->data->nb_tx_queues;
+	cap->sched_sp_n_priorities_max = dev->data->nb_tx_queues;
+	cap->sched_wfq_n_children_per_group_max = dev->data->nb_tx_queues;
+	cap->sched_wfq_n_groups_max = 1;
+	cap->sched_wfq_weight_max = MRVL_WEIGHT_MAX;
+
+	cap->dynamic_update_mask = RTE_TM_UPDATE_NODE_SUSPEND_RESUME |
+				   RTE_TM_UPDATE_NODE_STATS;
+	cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
+
+	return 0;
+}
+
+/**
+ * Get traffic manager hierarchy level capabilities.
+ *
+ * @param dev Pointer to the device.
+ * @param level_id Id of the level.
+ * @param cap Pointer to the level capabilities.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_level_capabilities_get(struct rte_eth_dev *dev,
+			    uint32_t level_id,
+			    struct rte_tm_level_capabilities *cap,
+			    struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	if (!cap)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	memset(cap, 0, sizeof(*cap));
+
+	if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_LEVEL_ID,
+					 NULL, "Wrong level id\n");
+
+	if (level_id == MRVL_NODE_PORT) {
+		cap->n_nodes_max = 1;
+		cap->n_nodes_nonleaf_max = 1;
+		cap->non_leaf_nodes_identical = 1;
+
+		cap->nonleaf.shaper_private_supported = 1;
+		cap->nonleaf.shaper_private_rate_min = MRVL_RATE_MIN;
+		cap->nonleaf.shaper_private_rate_max = priv->rate_max;
+
+		cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
+		cap->nonleaf.sched_sp_n_priorities_max = 1;
+		cap->nonleaf.sched_wfq_n_children_per_group_max =
+			dev->data->nb_tx_queues;
+		cap->nonleaf.sched_wfq_n_groups_max = 1;
+		cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
+		cap->nonleaf.stats_mask = RTE_TM_STATS_N_PKTS |
+					  RTE_TM_STATS_N_BYTES;
+	} else { /* level_id == MRVL_NODE_QUEUE */
+		cap->n_nodes_max = dev->data->nb_tx_queues;
+		cap->n_nodes_leaf_max = dev->data->nb_tx_queues;
+		cap->leaf_nodes_identical = 1;
+
+		cap->leaf.shaper_private_supported = 1;
+		cap->leaf.shaper_private_rate_min = MRVL_RATE_MIN;
+		cap->leaf.shaper_private_rate_max = priv->rate_max;
+		cap->leaf.stats_mask = RTE_TM_STATS_N_PKTS;
+	}
+
+	return 0;
+}
+
+/**
+ * Get node capabilities.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param cap Pointer to the capabilities.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_capabilities_get(struct rte_eth_dev *dev, uint32_t node_id,
+			   struct rte_tm_node_capabilities *cap,
+			   struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	if (!cap)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	memset(cap, 0, sizeof(*cap));
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	cap->shaper_private_supported = 1;
+	cap->shaper_private_rate_min = MRVL_RATE_MIN;
+	cap->shaper_private_rate_max = priv->rate_max;
+
+	if (node->type == MRVL_NODE_PORT) {
+		cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
+		cap->nonleaf.sched_sp_n_priorities_max = 1;
+		cap->nonleaf.sched_wfq_n_children_per_group_max =
+			dev->data->nb_tx_queues;
+		cap->nonleaf.sched_wfq_n_groups_max = 1;
+		cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
+		cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
+	} else {
+		cap->stats_mask = RTE_TM_STATS_N_PKTS;
+	}
+
+	return 0;
+}
+
+/**
+ * Get shaper profile using its id.
+ *
+ * @param priv Pointer to the port's private data.
+ * @param shaper_profile_id Id used by the shaper.
+ * @returns Pointer to the shaper profile if exists, NULL otherwise.
+ */
+static struct mrvl_tm_shaper_profile *
+mrvl_shaper_profile_from_id(struct mrvl_priv *priv, uint32_t shaper_profile_id)
+{
+	struct mrvl_tm_shaper_profile *profile;
+
+	LIST_FOREACH(profile, &priv->shaper_profiles, next)
+		if (profile->id == shaper_profile_id)
+			return profile;
+
+	return NULL;
+}
+
+/**
+ * Add a new shaper profile.
+ *
+ * @param dev Pointer to the device.
+ * @param shaper_profile_id Id of the new profile.
+ * @param params Pointer to the shaper profile parameters.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_shaper_profile_add(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
+			struct rte_tm_shaper_params *params,
+			struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile;
+
+	if (!params)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	if (params->committed.rate)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE,
+				NULL, "Committed rate not supported\n");
+
+	if (params->committed.size)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE,
+				NULL, "Committed bucket size not supported\n");
+
+	if (params->peak.rate < MRVL_RATE_MIN ||
+	    params->peak.rate > priv->rate_max)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE,
+				NULL, "Peak rate is out of range\n");
+
+	if (params->peak.size < MRVL_BURST_MIN ||
+	    params->peak.size > MRVL_BURST_MAX)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE,
+				NULL, "Peak size is out of range\n");
+
+	if (shaper_profile_id == RTE_TM_SHAPER_PROFILE_ID_NONE)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Wrong shaper profile id\n");
+
+	profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
+	if (profile)
+		return -rte_tm_error_set(error, EEXIST,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Profile id already exists\n");
+
+	profile = rte_zmalloc_socket(NULL, sizeof(*profile), 0,
+				     rte_socket_id());
+	if (!profile)
+		return -rte_tm_error_set(error, ENOMEM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	profile->id = shaper_profile_id;
+	rte_memcpy(&profile->params, params, sizeof(profile->params));
+
+	LIST_INSERT_HEAD(&priv->shaper_profiles, profile, next);
+
+	return 0;
+}
+
+/**
+ * Remove a shaper profile.
+ *
+ * @param dev Pointer to the device.
+ * @param shaper_profile_id Id of the shaper profile.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_shaper_profile_delete(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
+			   struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile;
+
+	profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
+	if (!profile)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Profile id does not exist\n");
+
+	if (profile->refcnt)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					 NULL, "Profile is used\n");
+
+	LIST_REMOVE(profile, next);
+	rte_free(profile);
+
+	return 0;
+}
+
+/**
+ * Check node parameters.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id used by the node.
+ * @param priority Priority value.
+ * @param weight Weight value.
+ * @param level_id Id of the level.
+ * @param params Pointer to the node parameters.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_check_params(struct rte_eth_dev *dev, uint32_t node_id,
+		       uint32_t priority, uint32_t weight, uint32_t level_id,
+		       struct rte_tm_node_params *params,
+		       struct rte_tm_error *error)
+{
+	if (node_id == RTE_TM_NODE_ID_NULL)
+		return -rte_tm_error_set(error, EINVAL, RTE_TM_NODE_ID_NULL,
+					 NULL, "Node id is invalid\n");
+
+	if (priority)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_NODE_PRIORITY,
+					 NULL, "Priority should be 0\n");
+
+	if (weight > MRVL_WEIGHT_MAX)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_NODE_WEIGHT,
+					 NULL, "Weight is out of range\n");
+
+	if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_LEVEL_ID,
+					 NULL, "Wrong level id\n");
+
+	if (!params)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	if (params->shared_shaper_id)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID,
+				NULL, "Shared shaper is not supported\n");
+
+	if (params->n_shared_shapers)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS,
+				NULL, "Shared shaper is not supported\n");
+
+	/* verify port (root node) settings */
+	if (node_id >= dev->data->nb_tx_queues) {
+		if (params->nonleaf.wfq_weight_mode)
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE,
+				NULL, "WFQ is not supported\n");
+
+		if (params->nonleaf.n_sp_priorities != 1)
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES,
+				NULL, "SP is not supported\n");
+
+		if (params->stats_mask & ~(RTE_TM_STATS_N_PKTS |
+					   RTE_TM_STATS_N_BYTES))
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+				NULL,
+				"Requested port stats are not supported\n");
+
+		return 0;
+	}
+
+	/* verify txq (leaf node) settings */
+	if (params->leaf.cman)
+		return -rte_tm_error_set(error, EINVAL,
+					 RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN,
+					 NULL,
+					 "Congestion mngmt is not supported\n");
+
+	if (params->leaf.wred.wred_profile_id)
+		return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID,
+				NULL, "WRED is not supported\n");
+
+	if (params->leaf.wred.shared_wred_context_id)
+		return -rte_tm_error_set(error, EINVAL,
+			RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID,
+			NULL, "WRED is not supported\n");
+
+	if (params->leaf.wred.n_shared_wred_contexts)
+		return -rte_tm_error_set(error, EINVAL,
+			RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS,
+			NULL, "WRED is not supported\n");
+
+	if (params->stats_mask & ~RTE_TM_STATS_N_PKTS)
+		return -rte_tm_error_set(error, EINVAL,
+			RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+			NULL,
+			"Requested txq stats are not supported\n");
+
+	return 0;
+}
+
+/**
+ * Add a new node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param parent_node_id Id of the parent node.
+ * @param priority Priority value.
+ * @param weight Weight value.
+ * @param level_id Id of the level.
+ * @param params Pointer to the node parameters.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_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 mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_shaper_profile *profile = NULL;
+	struct mrvl_tm_node *node, *parent = NULL;
+	int ret;
+
+	if (priv->ppio)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Port is already started\n");
+
+	ret = mrvl_node_check_params(dev, node_id, priority, weight, level_id,
+				     params, error);
+	if (ret)
+		return ret;
+
+	if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE) {
+		profile = mrvl_shaper_profile_from_id(priv,
+						 params->shaper_profile_id);
+		if (!profile)
+			return -rte_tm_error_set(error, ENODEV,
+					RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
+					NULL, "Shaper id does not exist\n");
+	}
+
+	if (parent_node_id == RTE_TM_NODE_ID_NULL) {
+		LIST_FOREACH(node, &priv->nodes, next) {
+			if (node->type != MRVL_NODE_PORT)
+				continue;
+
+			return -rte_tm_error_set(error, EINVAL,
+						 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+						 NULL, "Root node exists\n");
+		}
+	} else {
+		parent = mrvl_node_from_id(priv, parent_node_id);
+		if (!parent)
+			return -rte_tm_error_set(error, EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
+					NULL, "Node id does not exist\n");
+	}
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id already exists\n");
+
+	node = rte_zmalloc_socket(NULL, sizeof(*node), 0, rte_socket_id());
+	if (!node)
+		return -rte_tm_error_set(error, ENOMEM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, NULL);
+
+	node->id = node_id;
+	node->type = parent_node_id == RTE_TM_NODE_ID_NULL ? MRVL_NODE_PORT :
+							     MRVL_NODE_QUEUE;
+
+	if (parent) {
+		node->parent = parent;
+		parent->refcnt++;
+	}
+
+	if (profile) {
+		node->profile = profile;
+		profile->refcnt++;
+	}
+
+	node->weight = weight;
+	node->stats_mask = params->stats_mask;
+
+	LIST_INSERT_HEAD(&priv->nodes, node, next);
+
+	return 0;
+}
+
+/**
+ * Delete a node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
+		 struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	if (priv->ppio) {
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Port is already started\n");
+	}
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (node->refcnt)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id is used\n");
+
+	if (node->parent)
+		node->parent->refcnt--;
+
+	if (node->profile)
+		node->profile->refcnt--;
+
+	LIST_REMOVE(node, next);
+	rte_free(node);
+
+	return 0;
+}
+
+/**
+ * Helper for suspending specific tx queue.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id used by this node.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int mrvl_node_suspend_one(struct rte_eth_dev *dev, uint32_t node_id,
+				 struct rte_tm_error *error)
+{
+	int ret = dev->dev_ops->tx_queue_stop(dev, node_id);
+	if (ret)
+		return -rte_tm_error_set(error, ret,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Failed to suspend a txq\n");
+
+	return 0;
+}
+
+/**
+ * Suspend a node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param error Pointer to the error.
+ * returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_suspend(struct rte_eth_dev *dev, uint32_t node_id,
+		  struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node, *tmp;
+	int ret;
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (!node->parent) {
+		LIST_FOREACH(tmp, &priv->nodes, next) {
+			if (!tmp->parent)
+				continue;
+
+			if (node != tmp->parent)
+				continue;
+
+			ret = mrvl_node_suspend_one(dev, tmp->id, error);
+			if (ret)
+				return ret;
+		}
+
+		return 0;
+	}
+
+	return mrvl_node_suspend_one(dev, node_id, error);
+}
+
+/**
+ * Resume a node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param error Pointer to the error.
+ * returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_resume(struct rte_eth_dev *dev, uint32_t node_id,
+		 struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+	int ret;
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+
+	if (!node->parent)
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Cannot suspend a port\n");
+
+	ret = dev->dev_ops->tx_queue_start(dev, node_id);
+	if (ret)
+		return -rte_tm_error_set(error, ret,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Failed to resume a txq\n");
+	return 0;
+}
+
+/**
+ * Apply traffic manager hierarchy.
+ *
+ * @param dev Pointer to the device.
+ * @param clear_on_fail Flag indicating whether to do cleanup on the failure.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_hierarchy_commit(struct rte_eth_dev *dev, int clear_on_fail,
+		      struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+	int ret;
+
+	if (priv->ppio) {
+		ret = -rte_tm_error_set(error, EPERM,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					NULL, "Port is already started\n");
+		goto out;
+	}
+
+	LIST_FOREACH(node, &priv->nodes, next) {
+		struct pp2_ppio_outq_params *p;
+
+		if (node->type == MRVL_NODE_PORT) {
+			if (!node->profile)
+				continue;
+
+			priv->ppio_params.rate_limit_enable = 1;
+			priv->ppio_params.rate_limit_params.cir =
+				node->profile->params.peak.rate * 8 / 1000;
+			priv->ppio_params.rate_limit_params.cbs =
+				node->profile->params.peak.size / 1000;
+
+			MRVL_LOG(INFO,
+				"Port rate limit overrides txqs rate limit");
+
+			continue;
+		}
+
+		if (node->id >= dev->data->nb_tx_queues) {
+			ret = -rte_tm_error_set(error, EINVAL,
+					RTE_TM_ERROR_TYPE_NODE_ID, NULL,
+					"Not enough txqs are configured\n");
+			goto out;
+		}
+
+		p = &priv->ppio_params.outqs_params.outqs_params[node->id];
+
+		if (node->weight) {
+			p->sched_mode = PP2_PPIO_SCHED_M_WRR;
+			p->weight = node->weight;
+		} else {
+			p->sched_mode = PP2_PPIO_SCHED_M_SP;
+			p->weight = 0;
+		}
+
+		if (node->profile) {
+			p->rate_limit_enable = 1;
+			/* convert Bytes/s to kilo bits/s */
+			p->rate_limit_params.cir =
+				node->profile->params.peak.rate * 8 / 1000;
+			/* convert bits to kilo bits */
+			p->rate_limit_params.cbs =
+				node->profile->params.peak.size / 1000;
+		} else {
+			p->rate_limit_enable = 0;
+			p->rate_limit_params.cir = 0;
+			p->rate_limit_params.cbs = 0;
+		}
+	}
+
+	/* reset to defaults in case applied tm hierarchy is empty */
+	if (LIST_EMPTY(&priv->nodes)) {
+		int i;
+
+		for (i = 0; i < priv->ppio_params.outqs_params.num_outqs; i++) {
+			struct pp2_ppio_outq_params *p =
+				&priv->ppio_params.outqs_params.outqs_params[i];
+
+			p->sched_mode = PP2_PPIO_SCHED_M_WRR;
+			p->weight = 0;
+			p->rate_limit_enable = 0;
+			p->rate_limit_params.cir = 0;
+			p->rate_limit_params.cbs = 0;
+		}
+	}
+
+	return 0;
+out:
+	if (clear_on_fail) {
+		mrvl_tm_deinit(dev);
+		mrvl_tm_init(dev);
+	}
+
+	return ret;
+}
+
+/**
+ * Read statistics counters for current node.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param stats Pointer to the statistics counters.
+ * @param stats_mask Pointer to mask of enabled statistics counters
+ *                   that are retrieved.
+ * @param clear Flag indicating whether to clear statistics.
+ *              Non-zero value clears statistics.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_stats_read(struct rte_eth_dev *dev, uint32_t node_id,
+		     struct rte_tm_node_stats *stats, uint64_t *stats_mask,
+		     int clear, struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+	int ret;
+
+	if (!priv->ppio) {
+		return -rte_tm_error_set(error, EPERM,
+					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
+					 NULL, "Port is not started\n");
+	}
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (stats_mask)
+		*stats_mask = node->stats_mask;
+
+	if (!stats)
+		return 0;
+
+	memset(stats, 0, sizeof(*stats));
+
+	if (!node->parent) {
+		struct pp2_ppio_statistics s;
+
+		memset(&s, 0, sizeof(s));
+		ret = pp2_ppio_get_statistics(priv->ppio, &s, clear);
+		if (ret)
+			return -rte_tm_error_set(error, -ret,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to read port statistics\n");
+
+		if (node->stats_mask & RTE_TM_STATS_N_PKTS)
+			stats->n_pkts = s.tx_packets;
+
+		if (node->stats_mask & RTE_TM_STATS_N_BYTES)
+			stats->n_bytes = s.tx_bytes;
+	} else {
+		struct pp2_ppio_outq_statistics s;
+
+		memset(&s, 0, sizeof(s));
+		ret = pp2_ppio_outq_get_statistics(priv->ppio, node_id, &s,
+						   clear);
+		if (ret)
+			return -rte_tm_error_set(error, -ret,
+					RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to read txq statistics\n");
+
+		if (node->stats_mask & RTE_TM_STATS_N_PKTS)
+			stats->n_pkts = s.deq_desc;
+	}
+
+	return 0;
+}
+
+/**
+ * Update node statistics.
+ *
+ * @param dev Pointer to the device.
+ * @param node_id Id of the node.
+ * @param stats_mask Bitmask of statistics counters to be enabled.
+ * @param error Pointer to the error.
+ * @returns 0 on success, negative value otherwise.
+ */
+static int
+mrvl_node_stats_update(struct rte_eth_dev *dev, uint32_t node_id,
+		       uint64_t stats_mask, struct rte_tm_error *error)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_tm_node *node;
+
+	node = mrvl_node_from_id(priv, node_id);
+	if (!node)
+		return -rte_tm_error_set(error, ENODEV,
+					 RTE_TM_ERROR_TYPE_NODE_ID,
+					 NULL, "Node id does not exist\n");
+
+	if (!node->parent) {
+		if (stats_mask & ~(RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES))
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+				NULL,
+				"Requested port stats are not supported\n");
+	} else {
+		if (stats_mask & ~RTE_TM_STATS_N_PKTS)
+			return -rte_tm_error_set(error, EINVAL,
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
+				NULL,
+				"Requested txq stats are not supported\n");
+	}
+
+	node->stats_mask = stats_mask;
+
+	return 0;
+}
+
+const struct rte_tm_ops mrvl_tm_ops = {
+	.node_type_get = mrvl_node_type_get,
+	.capabilities_get = mrvl_capabilities_get,
+	.level_capabilities_get = mrvl_level_capabilities_get,
+	.node_capabilities_get = mrvl_node_capabilities_get,
+	.shaper_profile_add = mrvl_shaper_profile_add,
+	.shaper_profile_delete = mrvl_shaper_profile_delete,
+	.node_add = mrvl_node_add,
+	.node_delete = mrvl_node_delete,
+	.node_suspend = mrvl_node_suspend,
+	.node_resume = mrvl_node_resume,
+	.hierarchy_commit = mrvl_hierarchy_commit,
+	.node_stats_update = mrvl_node_stats_update,
+	.node_stats_read = mrvl_node_stats_read,
+};
diff --git a/drivers/net/mvpp2/mrvl_tm.h b/drivers/net/mvpp2/mrvl_tm.h
new file mode 100644
index 0000000..9d81ede
--- /dev/null
+++ b/drivers/net/mvpp2/mrvl_tm.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Marvell International Ltd.
+ * Copyright(c) 2018 Semihalf.
+ * All rights reserved.
+ */
+
+#ifndef _MRVL_TM_H_
+#define _MRVL_TM_H_
+
+#include "mrvl_ethdev.h"
+
+int mrvl_tm_init(struct rte_eth_dev *dev);
+void mrvl_tm_deinit(struct rte_eth_dev *dev);
+
+#endif /* _MRVL_TM_H_ */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 07/13] net/mvpp2: detach Tx QoS from Rx cls/QoS config
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
                       ` (5 preceding siblings ...)
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 06/13] net/mvpp2: add traffic manager support Andrzej Ostruszka
@ 2018-09-25  7:05     ` Andrzej Ostruszka
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 08/13] net/mvpp2: update MTU and MRU related calculations Andrzej Ostruszka
                       ` (6 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:05 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Yuval Caduri

From: Yuval Caduri <cyuval@marvell.com>

Functional change:
Open receive cls/qos related features, only if the
config file contains an rx_related configuration entry.
This allows to configure tx_related entries, w/o unintentionally
opening rx cls/qos.

Code:
'use_global_defaults' is by default set to '1'.
Only if an rx_related entry was configured, it is updated to '0'.
rx cls/qos is performed only if 'use_global_defaults' is '0'.
Default TC configuration is now only mandatory when
'use_global_defaults' is '0'.

Signed-off-by: Yuval Caduri <cyuval@marvell.com>
Reviewed-by: Natalie Samsonov <nsamsono@marvell.com>
Tested-by: Natalie Samsonov <nsamsono@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c |  3 ++-
 drivers/net/mvpp2/mrvl_qos.c    | 41 +++++++++++++++++++++++------------------
 2 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 4d1e84a..64c6f0f 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -593,7 +593,8 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 	}
 
 	/* For default QoS config, don't start classifier. */
-	if (mrvl_qos_cfg) {
+	if (mrvl_qos_cfg  &&
+	    mrvl_qos_cfg->port[dev->data->port_id].use_global_defaults == 0) {
 		ret = mrvl_start_qos_mapping(priv);
 		if (ret) {
 			MRVL_LOG(ERR, "Failed to setup QoS mapping");
diff --git a/drivers/net/mvpp2/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c
index e039635..5d80c3e 100644
--- a/drivers/net/mvpp2/mrvl_qos.c
+++ b/drivers/net/mvpp2/mrvl_qos.c
@@ -324,6 +324,7 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
 	if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
 		return 0;
 
+	cfg->port[port].use_global_defaults = 0;
 	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
 	if (entry) {
 		n = get_entry_values(entry,
@@ -421,7 +422,7 @@ parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
 			cfg->port[port].policer_params.token_unit =
 				PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
 		} else {
-			RTE_LOG(ERR, PMD, "Unknown token: %s\n", entry);
+			MRVL_LOG(ERR, "Unknown token: %s", entry);
 			return -1;
 		}
 	}
@@ -438,7 +439,7 @@ parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
 			cfg->port[port].policer_params.color_mode =
 				PP2_CLS_PLCR_COLOR_AWARE_MODE;
 		} else {
-			RTE_LOG(ERR, PMD, "Error in parsing: %s\n", entry);
+			MRVL_LOG(ERR, "Error in parsing: %s", entry);
 			return -1;
 		}
 	}
@@ -518,28 +519,15 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 		snprintf(sec_name, sizeof(sec_name), "%s %d %s",
 			MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
 
+		/* Use global defaults, unless an override occurs */
+		(*cfg)->port[n].use_global_defaults = 1;
+
 		/* Skip ports non-existing in configuration. */
 		if (rte_cfgfile_num_sections(file, sec_name,
 				strlen(sec_name)) <= 0) {
-			(*cfg)->port[n].use_global_defaults = 1;
-			(*cfg)->port[n].mapping_priority =
-				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
 			continue;
 		}
 
-		entry = rte_cfgfile_get_entry(file, sec_name,
-				MRVL_TOK_DEFAULT_TC);
-		if (entry) {
-			if (get_val_securely(entry, &val) < 0 ||
-				val > USHRT_MAX)
-				return -1;
-			(*cfg)->port[n].default_tc = (uint8_t)val;
-		} else {
-			MRVL_LOG(ERR,
-				"Default Traffic Class required in custom configuration!");
-			return -1;
-		}
-
 		/*
 		 * Read per-port rate limiting. Setting that will
 		 * disable per-queue rate limiting.
@@ -573,6 +561,7 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 		entry = rte_cfgfile_get_entry(file, sec_name,
 				MRVL_TOK_MAPPING_PRIORITY);
 		if (entry) {
+			(*cfg)->port[n].use_global_defaults = 0;
 			if (!strncmp(entry, MRVL_TOK_VLAN_IP,
 				sizeof(MRVL_TOK_VLAN_IP)))
 				(*cfg)->port[n].mapping_priority =
@@ -602,6 +591,7 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 		entry = rte_cfgfile_get_entry(file, sec_name,
 				MRVL_TOK_PLCR_DEFAULT);
 		if (entry) {
+			(*cfg)->port[n].use_global_defaults = 0;
 			if (get_val_securely(entry, &val) < 0)
 				return -1;
 
@@ -627,6 +617,21 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
 					"Error %d parsing port %d tc %d!\n",
 					ret, n, i);
 		}
+
+		entry = rte_cfgfile_get_entry(file, sec_name,
+					      MRVL_TOK_DEFAULT_TC);
+		if (entry) {
+			if (get_val_securely(entry, &val) < 0 ||
+			    val > USHRT_MAX)
+				return -1;
+			(*cfg)->port[n].default_tc = (uint8_t)val;
+		} else {
+			if ((*cfg)->port[n].use_global_defaults == 0) {
+				MRVL_LOG(ERR,
+					 "Default Traffic Class required in custom configuration!");
+				return -1;
+			}
+		}
 	}
 
 	return 0;
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 08/13] net/mvpp2: update MTU and MRU related calculations
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
                       ` (6 preceding siblings ...)
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 07/13] net/mvpp2: detach Tx QoS from Rx cls/QoS config Andrzej Ostruszka
@ 2018-09-25  7:05     ` Andrzej Ostruszka
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 09/13] net/mvpp2: align with MUSDK 18.09 Andrzej Ostruszka
                       ` (5 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:05 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Natalie Samsonov

From: Natalie Samsonov <nsamsono@marvell.com>

This commit updates MTU and MRU related calculations.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Yelena Krivosheev <yelena@marvell.com>
Reviewed-by: Dmitri Epshtein <dima@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c | 70 +++++++++++++++++++++++++++++++----------
 drivers/net/mvpp2/mrvl_ethdev.h |  7 +++++
 2 files changed, 61 insertions(+), 16 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 64c6f0f..24bd0a5 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -316,7 +316,7 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 
 	if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME)
 		dev->data->mtu = dev->data->dev_conf.rxmode.max_rx_pkt_len -
-				 ETHER_HDR_LEN - ETHER_CRC_LEN;
+				 MRVL_PP2_ETH_HDRS_LEN;
 
 	ret = mrvl_configure_rxqs(priv, dev->data->port_id,
 				  dev->data->nb_rx_queues);
@@ -366,21 +366,55 @@ static int
 mrvl_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
 	struct mrvl_priv *priv = dev->data->dev_private;
-	/* extra MV_MH_SIZE bytes are required for Marvell tag */
-	uint16_t mru = mtu + MV_MH_SIZE + ETHER_HDR_LEN + ETHER_CRC_LEN;
+	uint16_t mru;
+	uint16_t mbuf_data_size = 0; /* SW buffer size */
 	int ret;
 
-	if (mtu < ETHER_MIN_MTU || mru > MRVL_PKT_SIZE_MAX)
+	mru = MRVL_PP2_MTU_TO_MRU(mtu);
+	/*
+	 * min_rx_buf_size is equal to mbuf data size
+	 * if pmd didn't set it differently
+	 */
+	mbuf_data_size = dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM;
+	/* Prevent PMD from:
+	 * - setting mru greater than the mbuf size resulting in
+	 * hw and sw buffer size mismatch
+	 * - setting mtu that requires the support of scattered packets
+	 * when this feature has not been enabled/supported so far
+	 * (TODO check scattered_rx flag here once scattered RX is supported).
+	 */
+	if (mru + MRVL_PKT_OFFS > mbuf_data_size) {
+		mru = mbuf_data_size - MRVL_PKT_OFFS;
+		mtu = MRVL_PP2_MRU_TO_MTU(mru);
+		MRVL_LOG(WARNING, "MTU too big, max MTU possible limitted "
+			"by current mbuf size: %u. Set MTU to %u, MRU to %u",
+			mbuf_data_size, mtu, mru);
+	}
+
+	if (mtu < ETHER_MIN_MTU || mru > MRVL_PKT_SIZE_MAX) {
+		MRVL_LOG(ERR, "Invalid MTU [%u] or MRU [%u]", mtu, mru);
 		return -EINVAL;
+	}
+
+	dev->data->mtu = mtu;
+	dev->data->dev_conf.rxmode.max_rx_pkt_len = mru - MV_MH_SIZE;
 
 	if (!priv->ppio)
 		return 0;
 
 	ret = pp2_ppio_set_mru(priv->ppio, mru);
-	if (ret)
+	if (ret) {
+		MRVL_LOG(ERR, "Failed to change MRU");
 		return ret;
+	}
+
+	ret = pp2_ppio_set_mtu(priv->ppio, mtu);
+	if (ret) {
+		MRVL_LOG(ERR, "Failed to change MTU");
+		return ret;
+	}
 
-	return pp2_ppio_set_mtu(priv->ppio, mtu);
+	return 0;
 }
 
 /**
@@ -591,6 +625,9 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 		}
 		priv->vlan_flushed = 1;
 	}
+	ret = mrvl_mtu_set(dev, dev->data->mtu);
+	if (ret)
+		MRVL_LOG(ERR, "Failed to set MTU to %d", dev->data->mtu);
 
 	/* For default QoS config, don't start classifier. */
 	if (mrvl_qos_cfg  &&
@@ -1542,8 +1579,8 @@ mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 {
 	struct mrvl_priv *priv = dev->data->dev_private;
 	struct mrvl_rxq *rxq;
-	uint32_t min_size,
-		 max_rx_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	uint32_t frame_size, buf_size = rte_pktmbuf_data_room_size(mp);
+	uint32_t max_rx_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
 	int ret, tc, inq;
 	uint64_t offloads;
 
@@ -1558,15 +1595,16 @@ mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		return -EFAULT;
 	}
 
-	min_size = rte_pktmbuf_data_room_size(mp) - RTE_PKTMBUF_HEADROOM -
-		   MRVL_PKT_EFFEC_OFFS;
-	if (min_size < max_rx_pkt_len) {
-		MRVL_LOG(ERR,
-			"Mbuf size must be increased to %u bytes to hold up to %u bytes of data.",
-			max_rx_pkt_len + RTE_PKTMBUF_HEADROOM +
-			MRVL_PKT_EFFEC_OFFS,
+	frame_size = buf_size - RTE_PKTMBUF_HEADROOM - MRVL_PKT_EFFEC_OFFS;
+	if (frame_size < max_rx_pkt_len) {
+		MRVL_LOG(WARNING,
+			"Mbuf size must be increased to %u bytes to hold up "
+			"to %u bytes of data.",
+			buf_size + max_rx_pkt_len - frame_size,
 			max_rx_pkt_len);
-		return -EINVAL;
+		dev->data->dev_conf.rxmode.max_rx_pkt_len = frame_size;
+		MRVL_LOG(INFO, "Setting max rx pkt len to %u",
+			dev->data->dev_conf.rxmode.max_rx_pkt_len);
 	}
 
 	if (dev->data->rx_queues[idx]) {
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index 984f31e..f0ae983 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -72,6 +72,13 @@
 /** Minimum number of sent buffers to release from shadow queue to BM */
 #define MRVL_PP2_BUF_RELEASE_BURST_SIZE	64
 
+#define MRVL_PP2_VLAN_TAG_LEN		4
+#define MRVL_PP2_ETH_HDRS_LEN		(ETHER_HDR_LEN + ETHER_CRC_LEN + \
+					(2 * MRVL_PP2_VLAN_TAG_LEN))
+#define MRVL_PP2_HDRS_LEN		(MV_MH_SIZE + MRVL_PP2_ETH_HDRS_LEN)
+#define MRVL_PP2_MTU_TO_MRU(mtu)	((mtu) + MRVL_PP2_HDRS_LEN)
+#define MRVL_PP2_MRU_TO_MTU(mru)	((mru) - MRVL_PP2_HDRS_LEN)
+
 /** Maximum length of a match string */
 #define MRVL_MATCH_LEN 16
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 09/13] net/mvpp2: align with MUSDK 18.09
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
                       ` (7 preceding siblings ...)
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 08/13] net/mvpp2: update MTU and MRU related calculations Andrzej Ostruszka
@ 2018-09-25  7:05     ` Andrzej Ostruszka
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 10/13] crypto/mvsam: get number of CIOs dynamically Andrzej Ostruszka
                       ` (4 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:05 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Tomasz Duszynski, Natalie Samsonov, Yuval Caduri

From: Tomasz Duszynski <tdu@semihalf.com>

This patch introduces necessary changes required by MUSDK 18.09 library.

* As of MUSDK 18.09, pp2_cookie_t is no longer available. Now
  RX descriptor cookie is defined as plain u64 so existing cast
  is no longer valid.

* MUSDK 18.09 increased number of available bpools (buffer hw pools) by
  introducing dma regions support. Update mvpp2 driver accordingly.

* replace MV_NET_IP4_F_TOS with MV_NET_IP4_F_DSCP

  Before this patch, API allowed to configure a classification rule
  according to IPv4 TOS, which was not supported in classifier. This patch
  fixes this by using proper field.

* use 48 bit address mask

  We cannot get pointers exceeding 48 bits thus using 48 bit
  mask for extracting higher IOVA address bits is enough.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Signed-off-by: Yuval Caduri <cyuval@marvell.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
Reviewed-by: Shlomi Gridish <sgridish@marvell.com>
Reviewed-by: Alan Winkowski <walan@marvell.com>
Reviewed-by: Liron Himi <lironh@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c | 10 ++++------
 drivers/net/mvpp2/mrvl_flow.c   |  3 ++-
 drivers/net/mvpp2/mrvl_qos.c    |  2 +-
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 24bd0a5..26497ef 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -54,9 +54,7 @@
 #define MRVL_ARP_LENGTH 28
 
 #define MRVL_COOKIE_ADDR_INVALID ~0ULL
-
-#define MRVL_COOKIE_HIGH_ADDR_SHIFT	(sizeof(pp2_cookie_t) * 8)
-#define MRVL_COOKIE_HIGH_ADDR_MASK	(~0ULL << MRVL_COOKIE_HIGH_ADDR_SHIFT)
+#define MRVL_COOKIE_HIGH_ADDR_MASK 0xffffff0000000000
 
 /** Port Rx offload capabilities */
 #define MRVL_RX_OFFLOADS (DEV_RX_OFFLOAD_VLAN_FILTER | \
@@ -1534,7 +1532,7 @@ mrvl_fill_bpool(struct mrvl_rxq *rxq, int num)
 
 		entries[i].buff.addr =
 			rte_mbuf_data_iova_default(mbufs[i]);
-		entries[i].buff.cookie = (pp2_cookie_t)(uint64_t)mbufs[i];
+		entries[i].buff.cookie = (uint64_t)mbufs[i];
 		entries[i].bpool = bpool;
 	}
 
@@ -2170,7 +2168,7 @@ mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 		if (unlikely(status != PP2_DESC_ERR_OK)) {
 			struct pp2_buff_inf binf = {
 				.addr = rte_mbuf_data_iova_default(mbuf),
-				.cookie = (pp2_cookie_t)(uint64_t)mbuf,
+				.cookie = (uint64_t)mbuf,
 			};
 
 			pp2_bpool_put_buff(hif, bpool, &binf);
@@ -2431,7 +2429,7 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 			rte_mbuf_prefetch_part2(pref_pkt_hdr);
 		}
 
-		sq->ent[sq->head].buff.cookie = (pp2_cookie_t)(uint64_t)mbuf;
+		sq->ent[sq->head].buff.cookie = (uint64_t)mbuf;
 		sq->ent[sq->head].buff.addr =
 			rte_mbuf_data_iova_default(mbuf);
 		sq->ent[sq->head].bpool =
diff --git a/drivers/net/mvpp2/mrvl_flow.c b/drivers/net/mvpp2/mrvl_flow.c
index 065b1aa..ffd1dab 100644
--- a/drivers/net/mvpp2/mrvl_flow.c
+++ b/drivers/net/mvpp2/mrvl_flow.c
@@ -2437,7 +2437,8 @@ mrvl_create_cls_table(struct rte_eth_dev *dev, struct rte_flow *first_flow)
 
 	if (first_flow->pattern & F_IP4_TOS) {
 		key->proto_field[key->num_fields].proto = MV_NET_PROTO_IP4;
-		key->proto_field[key->num_fields].field.ipv4 = MV_NET_IP4_F_TOS;
+		key->proto_field[key->num_fields].field.ipv4 =
+							MV_NET_IP4_F_DSCP;
 		key->key_size += 1;
 		key->num_fields += 1;
 	}
diff --git a/drivers/net/mvpp2/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c
index 5d80c3e..7fd9703 100644
--- a/drivers/net/mvpp2/mrvl_qos.c
+++ b/drivers/net/mvpp2/mrvl_qos.c
@@ -654,7 +654,7 @@ setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
 	struct pp2_ppio_inq_params *inq_params;
 
 	param->pkt_offset = MRVL_PKT_OFFS;
-	param->pools[0] = bpool;
+	param->pools[0][0] = bpool;
 	param->default_color = color;
 
 	inq_params = rte_zmalloc_socket("inq_params",
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 10/13] crypto/mvsam: get number of CIOs dynamically
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
                       ` (8 preceding siblings ...)
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 09/13] net/mvpp2: align with MUSDK 18.09 Andrzej Ostruszka
@ 2018-09-25  7:05     ` Andrzej Ostruszka
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 11/13] net/mvpp2: align documentation with MUSDK 18.09 Andrzej Ostruszka
                       ` (3 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:05 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Dmitri Epshtein

From: Dmitri Epshtein <dima@marvell.com>

MUSDK 18.09 introduced API for getting CIOs number dynamically.
Use that instead of predefined constant.

Signed-off-by: Dmitri Epshtein <dima@marvell.com>
Reviewed-by: Natalie Samsonov <nsamsono@marvell.com>
Tested-by: Natalie Samsonov <nsamsono@marvell.com>
---
 drivers/crypto/mvsam/rte_mrvl_pmd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/crypto/mvsam/rte_mrvl_pmd.c b/drivers/crypto/mvsam/rte_mrvl_pmd.c
index 73eff75..6d54c06 100644
--- a/drivers/crypto/mvsam/rte_mrvl_pmd.c
+++ b/drivers/crypto/mvsam/rte_mrvl_pmd.c
@@ -864,7 +864,7 @@ cryptodev_mrvl_crypto_init(struct rte_vdev_device *vdev)
 			.private_data_size =
 				sizeof(struct mrvl_crypto_private),
 			.max_nb_queue_pairs =
-				sam_get_num_inst() * SAM_HW_RING_NUM,
+				sam_get_num_inst() * sam_get_num_cios(0),
 			.socket_id = rte_socket_id()
 		},
 		.max_nb_sessions = MRVL_PMD_DEFAULT_MAX_NB_SESSIONS
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 11/13] net/mvpp2: align documentation with MUSDK 18.09
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
                       ` (9 preceding siblings ...)
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 10/13] crypto/mvsam: get number of CIOs dynamically Andrzej Ostruszka
@ 2018-09-25  7:05     ` Andrzej Ostruszka
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 12/13] net/mvpp2: document MTR and TM usage Andrzej Ostruszka
                       ` (2 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:05 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Natalie Samsonov

From: Natalie Samsonov <nsamsono@marvell.com>

Update documentation to align with MUSDK 18.09.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
---
 doc/guides/nics/mvpp2.rst | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/doc/guides/nics/mvpp2.rst b/doc/guides/nics/mvpp2.rst
index a452c8a..3b3f8c6 100644
--- a/doc/guides/nics/mvpp2.rst
+++ b/doc/guides/nics/mvpp2.rst
@@ -74,6 +74,7 @@ Features of the MVPP2 PMD are:
 - QoS
 - RX flow control
 - TX queue start/stop
+- Scattered TX frames
 
 
 Limitations
@@ -96,19 +97,19 @@ Prerequisites
 
   .. code-block:: console
 
-     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.52-armada-17.10
+     git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.120-armada-18.09
 
 - Out of tree `mvpp2x_sysfs` kernel module sources
 
   .. code-block:: console
 
-     git clone https://github.com/MarvellEmbeddedProcessors/mvpp2x-marvell.git -b mvpp2x-armada-17.10
+     git clone https://github.com/MarvellEmbeddedProcessors/mvpp2x-marvell.git -b mvpp2x-armada-18.09
 
 - MUSDK (Marvell User-Space SDK) sources
 
   .. code-block:: console
 
-     git clone https://github.com/MarvellEmbeddedProcessors/musdk-marvell.git -b musdk-armada-17.10
+     git clone https://github.com/MarvellEmbeddedProcessors/musdk-marvell.git -b musdk-armada-18.09
 
   MUSDK is a light-weight library that provides direct access to Marvell's
   PPv2 (Packet Processor v2). Alternatively prebuilt MUSDK library can be
@@ -119,12 +120,6 @@ Prerequisites
   To get better understanding of the library one can consult documentation
   available in the ``doc`` top level directory of the MUSDK sources.
 
-  MUSDK must be configured with the following features:
-
-  .. code-block:: console
-
-     --enable-bpool-dma=64
-
 - DPDK environment
 
   Follow the DPDK :ref:`Getting Started Guide for Linux <linux_gsg>` to setup
@@ -140,6 +135,9 @@ The following options can be modified in the ``config`` file.
 
     Toggle compilation of the librte mvpp2 driver.
 
+    .. Note::
+
+       When MVPP2 PMD is enabled ``CONFIG_RTE_LIBRTE_MVNETA_PMD`` must be disabled
 
 QoS Configuration
 -----------------
@@ -314,7 +312,7 @@ Driver needs precompiled MUSDK library during compilation.
 
    export CROSS_COMPILE=<toolchain>/bin/aarch64-linux-gnu-
    ./bootstrap
-   ./configure --host=aarch64-linux-gnu --enable-bpool-dma=64
+   ./configure --host=aarch64-linux-gnu
    make install
 
 MUSDK will be installed to `usr/local` under current directory.
@@ -328,7 +326,8 @@ the path to the MUSDK installation directory needs to be exported.
    export LIBMUSDK_PATH=<musdk>/usr/local
    export CROSS=aarch64-linux-gnu-
    make config T=arm64-armv8a-linuxapp-gcc
-   sed -ri 's,(MVPP2_PMD=)n,\1y,' build/.config
+   sed -i "s/MVNETA_PMD=y/MVNETA_PMD=n/" build/.config
+   sed -i "s/MVPP2_PMD=n/MVPP2_PMD=y/" build/.config
    make
 
 Flow API
@@ -500,15 +499,14 @@ Usage Example
 -------------
 
 MVPP2 PMD requires extra out of tree kernel modules to function properly.
-`musdk_uio` and `mv_pp_uio` sources are part of the MUSDK. Please consult
+`musdk_cma` sources are part of the MUSDK. Please consult
 ``doc/musdk_get_started.txt`` for the detailed build instructions.
 For `mvpp2x_sysfs` please consult ``Documentation/pp22_sysfs.txt`` for the
 detailed build instructions.
 
 .. code-block:: console
 
-   insmod musdk_uio.ko
-   insmod mv_pp_uio.ko
+   insmod musdk_cma.ko
    insmod mvpp2x_sysfs.ko
 
 Additionally interfaces used by DPDK application need to be put up:
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 12/13] net/mvpp2: document MTR and TM usage
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
                       ` (10 preceding siblings ...)
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 11/13] net/mvpp2: align documentation with MUSDK 18.09 Andrzej Ostruszka
@ 2018-09-25  7:05     ` Andrzej Ostruszka
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 13/13] net/mvpp2: add Tx scatter/gather support Andrzej Ostruszka
  2018-09-25 16:12     ` [dpdk-dev] [PATCH v3 00/13] net/mvpp2: add new features Ferruh Yigit
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:05 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Natalie Samsonov

From: Natalie Samsonov <nsamsono@marvell.com>

Document MTR (metering) and TM (traffic management) usage plus
do some small updates here and there.

Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
---
 doc/guides/nics/img/mvpp2_tm.svg |  71 +++++++
 doc/guides/nics/mvpp2.rst        | 386 +++++++++++++++++++++++++++++++++------
 2 files changed, 406 insertions(+), 51 deletions(-)
 create mode 100644 doc/guides/nics/img/mvpp2_tm.svg

diff --git a/doc/guides/nics/img/mvpp2_tm.svg b/doc/guides/nics/img/mvpp2_tm.svg
new file mode 100644
index 0000000..4aa9272
--- /dev/null
+++ b/doc/guides/nics/img/mvpp2_tm.svg
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="16cm" height="4cm" viewBox="-1 -1 309 75" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+  <g>
+    <polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="159.661,12.6759 141.655,12.6759 141.655,35.5606 88.1561,35.5606 88.1561,44.9245 "/>
+    <polygon style="fill: #000000" points="88.1561,49.4245 85.1561,43.4245 88.1561,44.9245 91.1561,43.4245 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="88.1561,49.4245 85.1561,43.4245 88.1561,44.9245 91.1561,43.4245 "/>
+  </g>
+  <g>
+    <polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="159.661,12.6759 176.28,12.6759 176.28,35.5606 281.681,35.5606 281.681,44.9245 "/>
+    <polygon style="fill: #000000" points="281.681,49.4245 278.681,43.4245 281.681,44.9245 284.681,43.4245 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="281.681,49.4245 278.681,43.4245 281.681,44.9245 284.681,43.4245 "/>
+  </g>
+  <g>
+    <rect style="fill: #ffffff" x="126.066" y="0.98102" width="67.1901" height="23.3899"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="126.066" y="0.98102" width="67.1901" height="23.3899"/>
+  </g>
+  <text font-size="12.7998" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="159.661" y="17.1259">
+    <tspan x="159.661" y="17.1259">Port N</tspan>
+  </text>
+  <text font-size="12.7998" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="304.581" y="68.168">
+    <tspan x="304.581" y="68.168"></tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="62.5504" y="51.5478" width="51.2114" height="22.0925"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="62.5504" y="51.5478" width="51.2114" height="22.0925"/>
+  </g>
+  <text font-size="12.7998" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="88.1561" y="67.044">
+    <tspan x="88.1561" y="67.044">Txq 0</tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="134.1" y="51.355" width="51.1213" height="22.478"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="134.1" y="51.355" width="51.1213" height="22.478"/>
+  </g>
+  <text font-size="12.7998" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="159.661" y="67.044">
+    <tspan x="159.661" y="67.044">Txq 1</tspan>
+  </text>
+  <g>
+    <rect style="fill: #ffffff" x="256.416" y="51.5478" width="50.5306" height="22.0925"/>
+    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="256.416" y="51.5478" width="50.5306" height="22.0925"/>
+  </g>
+  <text font-size="12.7998" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="281.681" y="67.044">
+    <tspan x="281.681" y="67.044">Txq M</tspan>
+  </text>
+  <text font-size="12.7998" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="101.822" y="67.044">
+    <tspan x="101.822" y="67.044"></tspan>
+  </text>
+  <text font-size="12.7998" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="-0.537645" y="17.1259">
+    <tspan x="-0.537645" y="17.1259">Level 0:</tspan>
+  </text>
+  <text font-size="12.7998" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="-0.746688" y="67.044">
+    <tspan x="-0.746688" y="67.044">Level 1:</tspan>
+  </text>
+  <g>
+    <ellipse style="fill: #000000" cx="207.645" cy="62.594" rx="0.425344" ry="0.425344"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="207.645" cy="62.594" rx="0.425344" ry="0.425344"/>
+  </g>
+  <g>
+    <ellipse style="fill: #000000" cx="219.525" cy="62.594" rx="0.425344" ry="0.425344"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="219.525" cy="62.594" rx="0.425344" ry="0.425344"/>
+  </g>
+  <g>
+    <ellipse style="fill: #000000" cx="231.405" cy="62.594" rx="0.425345" ry="0.425345"/>
+    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="231.405" cy="62.594" rx="0.425345" ry="0.425345"/>
+  </g>
+  <g>
+    <line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="159.661" y1="24.3709" x2="159.661" y2="45.737"/>
+    <polygon style="fill: #000000" points="159.661,50.237 156.661,44.237 159.661,45.737 162.661,44.237 "/>
+    <polygon style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="159.661,50.237 156.661,44.237 159.661,45.737 162.661,44.237 "/>
+  </g>
+</svg>
diff --git a/doc/guides/nics/mvpp2.rst b/doc/guides/nics/mvpp2.rst
index 3b3f8c6..59fa0e1 100644
--- a/doc/guides/nics/mvpp2.rst
+++ b/doc/guides/nics/mvpp2.rst
@@ -56,7 +56,7 @@ Features of the MVPP2 PMD are:
 
 - Speed capabilities
 - Link status
-- Queue start/stop
+- Tx Queue start/stop
 - MTU update
 - Jumbo frame
 - Promiscuous mode
@@ -70,12 +70,13 @@ Features of the MVPP2 PMD are:
 - L4 checksum offload
 - Packet type parsing
 - Basic stats
-- Extended stats
-- QoS
+- :ref:`Extended stats <extstats>`
 - RX flow control
-- TX queue start/stop
 - Scattered TX frames
-
+- :ref:`QoS <qossupport>`
+- :ref:`Flow API <flowapi>`
+- :ref:`Traffic metering and policing <mtrapi>`
+- :ref:`Traffic Management API <tmapi>`
 
 Limitations
 -----------
@@ -89,6 +90,20 @@ Limitations
   functionality. Current workaround is to reset board so that PPv2 has a
   chance to start in a sane state.
 
+- MUSDK architecture does not support changing configuration in run time.
+  All nessesary configurations should be done before first dev_start().
+
+- RX queue start/stop is not supported.
+
+- Current implementation does not support replacement of buffers in the HW buffer pool
+  at run time, so it is responsibility of the application to ensure that MTU does not exceed the configured buffer size.
+
+- Configuring TX flow control currently is not supported.
+
+- In current implementation, mechanism for acknowledging transmitted packets (``tx_done_cleanup``) is not supported.
+
+- Running more than one DPDK-MUSDK application simultaneously is not supported.
+
 
 Prerequisites
 -------------
@@ -139,6 +154,92 @@ The following options can be modified in the ``config`` file.
 
        When MVPP2 PMD is enabled ``CONFIG_RTE_LIBRTE_MVNETA_PMD`` must be disabled
 
+
+Building DPDK
+-------------
+
+Driver needs precompiled MUSDK library during compilation.
+
+.. code-block:: console
+
+   export CROSS_COMPILE=<toolchain>/bin/aarch64-linux-gnu-
+   ./bootstrap
+   ./configure --host=aarch64-linux-gnu
+   make install
+
+MUSDK will be installed to `usr/local` under current directory.
+For the detailed build instructions please consult ``doc/musdk_get_started.txt``.
+
+Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
+the path to the MUSDK installation directory needs to be exported.
+
+For additional instructions regarding DPDK cross compilation please refer to :doc:`Cross compile DPDK for ARM64 <../linux_gsg/cross_build_dpdk_for_arm64>`.
+
+.. code-block:: console
+
+   export LIBMUSDK_PATH=<musdk>/usr/local
+   export CROSS=<toolchain>/bin/aarch64-linux-gnu-
+   export RTE_KERNELDIR=<kernel-dir>
+   export RTE_TARGET=arm64-armv8a-linuxapp-gcc
+
+   make config T=arm64-armv8a-linuxapp-gcc
+   sed -i "s/MVNETA_PMD=y/MVNETA_PMD=n/" build/.config
+   sed -i "s/MVPP2_PMD=n/MVPP2_PMD=y/" build/.config
+   make
+
+Usage Example
+-------------
+
+MVPP2 PMD requires extra out of tree kernel modules to function properly.
+`musdk_cma` sources are part of the MUSDK. Please consult
+``doc/musdk_get_started.txt`` for the detailed build instructions.
+For `mvpp2x_sysfs` please consult ``Documentation/pp22_sysfs.txt`` for the
+detailed build instructions.
+
+.. code-block:: console
+
+   insmod musdk_cma.ko
+   insmod mvpp2x_sysfs.ko
+
+Additionally interfaces used by DPDK application need to be put up:
+
+.. code-block:: console
+
+   ip link set eth0 up
+   ip link set eth2 up
+
+In order to run testpmd example application following command can be used:
+
+.. code-block:: console
+
+   ./testpmd --vdev=eth_mvpp2,iface=eth0,iface=eth2 -c 7 -- \
+     --burst=128 --txd=2048 --rxd=1024 --rxq=2 --txq=2  --nb-cores=2 \
+     -i -a --rss-udp
+
+.. _extstats:
+
+Extended stats
+--------------
+
+MVPP2 PMD supports the following extended statistics:
+
+	- ``rx_bytes``:	number of RX bytes
+	- ``rx_packets``: number of RX packets
+	- ``rx_unicast_packets``: number of RX unicast packets
+	- ``rx_errors``: number of RX MAC errors
+	- ``rx_fullq_dropped``: number of RX packets dropped due to full RX queue
+	- ``rx_bm_dropped``: number of RX packets dropped due to no available buffers in the HW pool
+	- ``rx_early_dropped``: number of RX packets that were early dropped
+	- ``rx_fifo_dropped``: number of RX packets dropped due to RX fifo overrun
+	- ``rx_cls_dropped``: number of RX packets dropped by classifier
+	- ``tx_bytes``: number of TX bytes
+	- ``tx_packets``: number of TX packets
+	- ``tx_unicast_packets``: number of TX unicast packets
+	- ``tx_errors``: number of TX MAC errors
+
+
+.. _qossupport:
+
 QoS Configuration
 -----------------
 
@@ -302,39 +403,14 @@ Usage example
    ./testpmd --vdev=eth_mvpp2,iface=eth0,iface=eth2,cfg=/home/user/mrvl.conf \
      -c 7 -- -i -a --disable-hw-vlan-strip --rxq=3 --txq=3
 
-
-Building DPDK
--------------
-
-Driver needs precompiled MUSDK library during compilation.
-
-.. code-block:: console
-
-   export CROSS_COMPILE=<toolchain>/bin/aarch64-linux-gnu-
-   ./bootstrap
-   ./configure --host=aarch64-linux-gnu
-   make install
-
-MUSDK will be installed to `usr/local` under current directory.
-For the detailed build instructions please consult ``doc/musdk_get_started.txt``.
-
-Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
-the path to the MUSDK installation directory needs to be exported.
-
-.. code-block:: console
-
-   export LIBMUSDK_PATH=<musdk>/usr/local
-   export CROSS=aarch64-linux-gnu-
-   make config T=arm64-armv8a-linuxapp-gcc
-   sed -i "s/MVNETA_PMD=y/MVNETA_PMD=n/" build/.config
-   sed -i "s/MVPP2_PMD=n/MVPP2_PMD=y/" build/.config
-   make
+.. _flowapi:
 
 Flow API
 --------
 
 PPv2 offers packet classification capabilities via classifier engine which
 can be configured via generic flow API offered by DPDK.
+For an additional description please refer to DPDK :ref:`Generic flow API <Generic_flow_API>`.
 
 Supported flow actions
 ~~~~~~~~~~~~~~~~~~~~~~
@@ -495,31 +571,239 @@ Following limitations need to be taken into account while creating flow rules:
 For additional information about classifier please consult
 ``doc/musdk_cls_user_guide.txt``.
 
-Usage Example
--------------
+.. _mtrapi:
 
-MVPP2 PMD requires extra out of tree kernel modules to function properly.
-`musdk_cma` sources are part of the MUSDK. Please consult
-``doc/musdk_get_started.txt`` for the detailed build instructions.
-For `mvpp2x_sysfs` please consult ``Documentation/pp22_sysfs.txt`` for the
-detailed build instructions.
+Traffic metering and policing
+-----------------------------
 
-.. code-block:: console
+MVPP2 PMD supports DPDK traffic metering and policing that allows the following:
 
-   insmod musdk_cma.ko
-   insmod mvpp2x_sysfs.ko
+1. Meter ingress traffic.
+2. Do policing.
+3. Gather statistics.
 
-Additionally interfaces used by DPDK application need to be put up:
+For an additional description please refer to DPDK :doc:`Traffic Metering and Policing API <../prog_guide/traffic_metering_and_policing>`.
 
-.. code-block:: console
+The policer objects defined by this feature can work with the default policer defined via config file as discribed in :ref:`QoS Support <qossupport>`.
 
-   ip link set eth0 up
-   ip link set eth2 up
+Limitations
+~~~~~~~~~~~
 
-In order to run testpmd example application following command can be used:
+The following capabilities are not supported:
 
-.. code-block:: console
+- MTR object meter DSCP table update
+- MTR object policer action update
+- MTR object enabled statistics
 
-   ./testpmd --vdev=eth_mvpp2,iface=eth0,iface=eth2 -c 7 -- \
-     --burst=128 --txd=2048 --rxd=1024 --rxq=2 --txq=2  --nb-cores=2 \
-     -i -a --rss-udp
+Usage example
+~~~~~~~~~~~~~
+
+1. Run testpmd user app:
+
+   .. code-block:: console
+
+		./testpmd --vdev=eth_mvpp2,iface=eth0,iface=eth2 -c 6 -- -i -p 3 -a --txd 1024 --rxd 1024
+
+2. Create meter profile:
+
+   .. code-block:: console
+
+		testpmd> add port meter profile 0 0 srtcm_rfc2697 2000 256 256
+
+3. Create meter:
+
+   .. code-block:: console
+
+		testpmd> create port meter 0 0 0 yes d d d 0 1 0
+
+4. Create flow rule witch meter attached:
+
+   .. code-block:: console
+
+		testpmd> flow create 0 ingress pattern ipv4 src is 10.10.10.1 / end actions meter mtr_id 0 / end
+
+For a detailed usage description please refer to "Traffic Metering and Policing" section in DPDK :doc:`Testpmd Runtime Functions <../testpmd_app_ug/testpmd_funcs>`.
+
+
+
+.. _tmapi:
+
+Traffic Management API
+----------------------
+
+MVPP2 PMD supports generic DPDK Traffic Management API which allows to
+configure the following features:
+
+1. Hierarchical scheduling
+2. Traffic shaping
+3. Congestion management
+4. Packet marking
+
+Internally TM is represented by a hierarchy (tree) of nodes.
+Node which has a parent is called a leaf whereas node without
+parent is called a non-leaf (root).
+MVPP2 PMD supports two level hierarchy where level 0 represents ports and level 1 represents tx queues of a given port.
+
+.. figure:: img/mvpp2_tm.svg
+
+Nodes hold following types of settings:
+
+- for egress scheduler configuration: weight
+- for egress rate limiter: private shaper
+- bitmask indicating which statistics counters will be read
+
+Hierarchy is always constructed from the top, i.e first a root node is added
+then some number of leaf nodes. Number of leaf nodes cannot exceed number
+of configured tx queues.
+
+After hierarchy is complete it can be committed.
+
+
+For an additional description please refer to DPDK :doc:`Traffic Management API <../prog_guide/traffic_management>`.
+
+Limitations
+~~~~~~~~~~~
+
+The following capabilities are not supported:
+
+- Traffic manager WRED profile and WRED context
+- Traffic manager shared shaper update
+- Traffic manager packet marking
+- Maximum number of levels in hierarchy is 2
+- Currently dynamic change of a hierarchy is not supported
+
+Usage example
+~~~~~~~~~~~~~
+
+For a detailed usage description please refer to "Traffic Management" section in DPDK :doc:`Testpmd Runtime Functions <../testpmd_app_ug/testpmd_funcs>`.
+
+1. Run testpmd as follows:
+
+   .. code-block:: console
+
+		./testpmd --vdev=net_mrvl,iface=eth0,iface=eth2,cfg=./qos_config -c 7 -- \
+		-i -p 3 --disable-hw-vlan-strip --rxq 3 --txq 3 --txd 1024 --rxd 1024
+
+2. Stop all ports:
+
+   .. code-block:: console
+
+		testpmd> port stop all
+
+3. Add shaper profile:
+
+   .. code-block:: console
+
+		testpmd> add port tm node shaper profile 0 0 900000 70000 0
+
+   Parameters have following meaning::
+
+		0       - Id of a port.
+		0       - Id of a new shaper profile.
+		900000  - Shaper rate in bytes/s.
+		70000   - Bucket size in bytes.
+		0       - Packet length adjustment - ignored.
+
+4. Add non-leaf node for port 0:
+
+   .. code-block:: console
+
+		testpmd> add port tm nonleaf node 0 3 -1 0 0 0 0 0 1 3 0
+
+   Parameters have following meaning::
+
+		 0  - Id of a port
+		 3  - Id of a new node.
+		-1  - Indicate that root does not have a parent.
+		 0  - Priority of the node.
+		 0  - Weight of the node.
+		 0  - Id of a level. Since this is a root 0 is passed.
+		 0  - Id of the shaper profile.
+		 0  - Number of SP priorities.
+		 3  - Enable statistics for both number of transmitted packets and bytes.
+		 0  - Number of shared shapers.
+
+5. Add leaf node for tx queue 0:
+
+   .. code-block:: console
+
+		testpmd> add port tm leaf node 0 0 3 0 30 1 -1 0 0 1 0
+
+   Parameters have following meaning::
+
+		 0  - Id of a port.
+		 0  - Id of a new node.
+		 3  - Id of the parent node.
+		 0  - Priority of a node.
+		 30 - WRR weight.
+		 1  - Id of a level. Since this is a leaf node 1 is passed.
+		-1  - Id of a shaper. -1 indicates that shaper is not attached.
+		 0  - Congestion management is not supported.
+		 0  - Congestion management is not supported.
+		 1  - Enable statistics counter for number of transmitted packets.
+		 0  - Number of shared shapers.
+
+6. Add leaf node for tx queue 1:
+
+   .. code-block:: console
+
+	testpmd> add port tm leaf node 0 1 3 0 60 1 -1 0 0 1 0
+
+   Parameters have following meaning::
+
+		 0  - Id of a port.
+		 1  - Id of a new node.
+		 3  - Id of the parent node.
+		 0  - Priority of a node.
+		 60 - WRR weight.
+		 1  - Id of a level. Since this is a leaf node 1 is passed.
+		-1  - Id of a shaper. -1 indicates that shaper is not attached.
+		 0  - Congestion management is not supported.
+		 0  - Congestion management is not supported.
+		 1  - Enable statistics counter for number of transmitted packets.
+		 0  - Number of shared shapers.
+
+7. Add leaf node for tx queue 2:
+
+   .. code-block:: console
+
+		testpmd> add port tm leaf node 0 2 3 0 99 1 -1 0 0 1 0
+
+   Parameters have following meaning::
+
+		 0  - Id of a port.
+		 2  - Id of a new node.
+		 3  - Id of the parent node.
+		 0  - Priority of a node.
+		 99 - WRR weight.
+		 1  - Id of a level. Since this is a leaf node 1 is passed.
+		-1  - Id of a shaper. -1 indicates that shaper is not attached.
+		 0  - Congestion management is not supported.
+		 0  - Congestion management is not supported.
+		 1  - Enable statistics counter for number of transmitted packets.
+		 0  - Number of shared shapers.
+
+8. Commit hierarchy:
+
+   .. code-block:: console
+
+		testpmd> port tm hierarchy commit 0 no
+
+  Parameters have following meaning::
+
+		0  - Id of a port.
+		no - Do not flush TM hierarchy if commit fails.
+
+9. Start all ports
+
+   .. code-block:: console
+
+		testpmd> port start all
+
+
+
+10. Enable forwarding
+
+   .. code-block:: console
+
+		testpmd> start
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 13/13] net/mvpp2: add Tx scatter/gather support
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
                       ` (11 preceding siblings ...)
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 12/13] net/mvpp2: document MTR and TM usage Andrzej Ostruszka
@ 2018-09-25  7:05     ` Andrzej Ostruszka
  2018-09-25 16:12     ` [dpdk-dev] [PATCH v3 00/13] net/mvpp2: add new features Ferruh Yigit
  13 siblings, 0 replies; 48+ messages in thread
From: Andrzej Ostruszka @ 2018-09-25  7:05 UTC (permalink / raw)
  To: dev; +Cc: mw, nadavh, Zyta Szpak, Natalie Samsonov

From: Zyta Szpak <zr@semihalf.com>

The patch introduces scatter/gather support on transmit path.
A separate Tx callback is added and set if the application
requests multisegment Tx offload. Multiple descriptors are
sent per one packet.

Signed-off-by: Zyta Szpak <zr@semihalf.com>
Signed-off-by: Natalie Samsonov <nsamsono@marvell.com>
Reviewed-by: Yelena Krivosheev <yelena@marvell.com>
---
 drivers/net/mvpp2/mrvl_ethdev.c | 231 ++++++++++++++++++++++++++++++++++++----
 drivers/net/mvpp2/mrvl_ethdev.h |   1 +
 2 files changed, 212 insertions(+), 20 deletions(-)

diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 26497ef..0682c63 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -64,7 +64,8 @@
 /** Port Tx offloads capabilities */
 #define MRVL_TX_OFFLOADS (DEV_TX_OFFLOAD_IPV4_CKSUM | \
 			  DEV_TX_OFFLOAD_UDP_CKSUM | \
-			  DEV_TX_OFFLOAD_TCP_CKSUM)
+			  DEV_TX_OFFLOAD_TCP_CKSUM | \
+			  DEV_TX_OFFLOAD_MULTI_SEGS)
 
 static const char * const valid_args[] = {
 	MRVL_IFACE_NAME_ARG,
@@ -104,7 +105,9 @@ struct mrvl_shadow_txq {
 	int head;           /* write index - used when sending buffers */
 	int tail;           /* read index - used when releasing buffers */
 	u16 size;           /* queue occupied size */
-	u16 num_to_release; /* number of buffers sent, that can be released */
+	u16 num_to_release; /* number of descriptors sent, that can be
+			     * released
+			     */
 	struct buff_release_entry ent[MRVL_PP2_TX_SHADOWQ_SIZE]; /* q entries */
 };
 
@@ -136,6 +139,12 @@ static inline void mrvl_free_sent_buffers(struct pp2_ppio *ppio,
 			struct pp2_hif *hif, unsigned int core_id,
 			struct mrvl_shadow_txq *sq, int qid, int force);
 
+static uint16_t mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts,
+				  uint16_t nb_pkts);
+static uint16_t mrvl_tx_sg_pkt_burst(void *txq,	struct rte_mbuf **tx_pkts,
+				     uint16_t nb_pkts);
+
+
 #define MRVL_XSTATS_TBL_ENTRY(name) { \
 	#name, offsetof(struct pp2_ppio_statistics, name),	\
 	sizeof(((struct pp2_ppio_statistics *)0)->name)		\
@@ -162,6 +171,31 @@ static struct {
 	MRVL_XSTATS_TBL_ENTRY(tx_errors)
 };
 
+static inline void
+mrvl_fill_shadowq(struct mrvl_shadow_txq *sq, struct rte_mbuf *buf)
+{
+	sq->ent[sq->head].buff.cookie = (uint64_t)buf;
+	sq->ent[sq->head].buff.addr = buf ?
+		rte_mbuf_data_iova_default(buf) : 0;
+
+	sq->ent[sq->head].bpool =
+		(unlikely(!buf || buf->port >= RTE_MAX_ETHPORTS ||
+		 buf->refcnt > 1)) ? NULL :
+		 mrvl_port_to_bpool_lookup[buf->port];
+
+	sq->head = (sq->head + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
+	sq->size++;
+}
+
+static inline void
+mrvl_fill_desc(struct pp2_ppio_desc *desc, struct rte_mbuf *buf)
+{
+	pp2_ppio_outq_desc_reset(desc);
+	pp2_ppio_outq_desc_set_phys_addr(desc, rte_pktmbuf_iova(buf));
+	pp2_ppio_outq_desc_set_pkt_offset(desc, 0);
+	pp2_ppio_outq_desc_set_pkt_len(desc, rte_pktmbuf_data_len(buf));
+}
+
 static inline int
 mrvl_get_bpool_size(int pp2_id, int pool_id)
 {
@@ -241,6 +275,27 @@ mrvl_get_hif(struct mrvl_priv *priv, int core_id)
 }
 
 /**
+ * Set tx burst function according to offload flag
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_set_tx_function(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	/* Use a simple Tx queue (no offloads, no multi segs) if possible */
+	if (priv->multiseg) {
+		RTE_LOG(INFO, PMD, "Using multi-segment tx callback\n");
+		dev->tx_pkt_burst = mrvl_tx_sg_pkt_burst;
+	} else {
+		RTE_LOG(INFO, PMD, "Using single-segment tx callback\n");
+		dev->tx_pkt_burst = mrvl_tx_pkt_burst;
+	}
+}
+
+/**
  * Configure rss based on dpdk rss configuration.
  *
  * @param priv
@@ -316,6 +371,9 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 		dev->data->mtu = dev->data->dev_conf.rxmode.max_rx_pkt_len -
 				 MRVL_PP2_ETH_HDRS_LEN;
 
+	if (dev->data->dev_conf.txmode.offloads & DEV_TX_OFFLOAD_MULTI_SEGS)
+		priv->multiseg = 1;
+
 	ret = mrvl_configure_rxqs(priv, dev->data->port_id,
 				  dev->data->nb_rx_queues);
 	if (ret < 0)
@@ -663,6 +721,7 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 
 	mrvl_flow_init(dev);
 	mrvl_mtr_init(dev);
+	mrvl_set_tx_function(dev);
 
 	return 0;
 out:
@@ -2429,22 +2488,8 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 			rte_mbuf_prefetch_part2(pref_pkt_hdr);
 		}
 
-		sq->ent[sq->head].buff.cookie = (uint64_t)mbuf;
-		sq->ent[sq->head].buff.addr =
-			rte_mbuf_data_iova_default(mbuf);
-		sq->ent[sq->head].bpool =
-			(unlikely(mbuf->port >= RTE_MAX_ETHPORTS ||
-			 mbuf->refcnt > 1)) ? NULL :
-			 mrvl_port_to_bpool_lookup[mbuf->port];
-		sq->head = (sq->head + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
-		sq->size++;
-
-		pp2_ppio_outq_desc_reset(&descs[i]);
-		pp2_ppio_outq_desc_set_phys_addr(&descs[i],
-						 rte_pktmbuf_iova(mbuf));
-		pp2_ppio_outq_desc_set_pkt_offset(&descs[i], 0);
-		pp2_ppio_outq_desc_set_pkt_len(&descs[i],
-					       rte_pktmbuf_pkt_len(mbuf));
+		mrvl_fill_shadowq(sq, mbuf);
+		mrvl_fill_desc(&descs[i], mbuf);
 
 		bytes_sent += rte_pktmbuf_pkt_len(mbuf);
 		/*
@@ -2482,6 +2527,152 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 	return nb_pkts;
 }
 
+/** DPDK callback for S/G transmit.
+ *
+ * @param txq
+ *   Generic pointer transmit queue.
+ * @param tx_pkts
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted.
+ */
+static uint16_t
+mrvl_tx_sg_pkt_burst(void *txq, struct rte_mbuf **tx_pkts,
+		     uint16_t nb_pkts)
+{
+	struct mrvl_txq *q = txq;
+	struct mrvl_shadow_txq *sq;
+	struct pp2_hif *hif;
+	struct pp2_ppio_desc descs[nb_pkts * PP2_PPIO_DESC_NUM_FRAGS];
+	struct pp2_ppio_sg_pkts pkts;
+	uint8_t frags[nb_pkts];
+	unsigned int core_id = rte_lcore_id();
+	int i, j, ret, bytes_sent = 0;
+	int tail, tail_first;
+	uint16_t num, sq_free_size;
+	uint16_t nb_segs, total_descs = 0;
+	uint64_t addr;
+
+	hif = mrvl_get_hif(q->priv, core_id);
+	sq = &q->shadow_txqs[core_id];
+	pkts.frags = frags;
+	pkts.num = 0;
+
+	if (unlikely(!q->priv->ppio || !hif))
+		return 0;
+
+	if (sq->size)
+		mrvl_free_sent_buffers(q->priv->ppio, hif, core_id,
+				       sq, q->queue_id, 0);
+
+	/* Save shadow queue free size */
+	sq_free_size = MRVL_PP2_TX_SHADOWQ_SIZE - sq->size - 1;
+
+	tail = 0;
+	for (i = 0; i < nb_pkts; i++) {
+		struct rte_mbuf *mbuf = tx_pkts[i];
+		struct rte_mbuf *seg = NULL;
+		int gen_l3_cksum, gen_l4_cksum;
+		enum pp2_outq_l3_type l3_type;
+		enum pp2_outq_l4_type l4_type;
+
+		nb_segs = mbuf->nb_segs;
+		tail_first = tail;
+		total_descs += nb_segs;
+
+		/*
+		 * Check if total_descs does not exceed
+		 * shadow queue free size
+		 */
+		if (unlikely(total_descs > sq_free_size)) {
+			total_descs -= nb_segs;
+			RTE_LOG(DEBUG, PMD,
+				"No room in shadow queue for %d packets! "
+				"%d packets will be sent.\n",
+				nb_pkts, i);
+			break;
+		}
+
+		/* Check if nb_segs does not exceed the max nb of desc per
+		 * fragmented packet
+		 */
+		if (nb_segs > PP2_PPIO_DESC_NUM_FRAGS) {
+			total_descs -= nb_segs;
+			RTE_LOG(ERR, PMD,
+				"Too many segments. Packet won't be sent.\n");
+			break;
+		}
+
+		if (likely(nb_pkts - i > MRVL_MUSDK_PREFETCH_SHIFT)) {
+			struct rte_mbuf *pref_pkt_hdr;
+
+			pref_pkt_hdr = tx_pkts[i + MRVL_MUSDK_PREFETCH_SHIFT];
+			rte_mbuf_prefetch_part1(pref_pkt_hdr);
+			rte_mbuf_prefetch_part2(pref_pkt_hdr);
+		}
+
+		pkts.frags[pkts.num] = nb_segs;
+		pkts.num++;
+
+		seg = mbuf;
+		for (j = 0; j < nb_segs - 1; j++) {
+			/* For the subsequent segments, set shadow queue
+			 * buffer to NULL
+			 */
+			mrvl_fill_shadowq(sq, NULL);
+			mrvl_fill_desc(&descs[tail], seg);
+
+			tail++;
+			seg = seg->next;
+		}
+		/* Put first mbuf info in last shadow queue entry */
+		mrvl_fill_shadowq(sq, mbuf);
+		/* Update descriptor with last segment */
+		mrvl_fill_desc(&descs[tail++], seg);
+
+		bytes_sent += rte_pktmbuf_pkt_len(mbuf);
+		/* In case unsupported ol_flags were passed
+		 * do not update descriptor offload information
+		 */
+		ret = mrvl_prepare_proto_info(mbuf->ol_flags, mbuf->packet_type,
+					      &l3_type, &l4_type, &gen_l3_cksum,
+					      &gen_l4_cksum);
+		if (unlikely(ret))
+			continue;
+
+		pp2_ppio_outq_desc_set_proto_info(&descs[tail_first], l3_type,
+						  l4_type, mbuf->l2_len,
+						  mbuf->l2_len + mbuf->l3_len,
+						  gen_l3_cksum, gen_l4_cksum);
+	}
+
+	num = total_descs;
+	pp2_ppio_send_sg(q->priv->ppio, hif, q->queue_id, descs,
+			 &total_descs, &pkts);
+	/* number of packets that were not sent */
+	if (unlikely(num > total_descs)) {
+		for (i = total_descs; i < num; i++) {
+			sq->head = (MRVL_PP2_TX_SHADOWQ_SIZE + sq->head - 1) &
+				MRVL_PP2_TX_SHADOWQ_MASK;
+
+			addr = sq->ent[sq->head].buff.cookie;
+			if (addr)
+				bytes_sent -=
+					rte_pktmbuf_pkt_len((struct rte_mbuf *)
+						(cookie_addr_high | addr));
+		}
+		sq->size -= num - total_descs;
+		nb_pkts = pkts.num;
+	}
+
+	q->bytes_sent += bytes_sent;
+
+	return nb_pkts;
+}
+
 /**
  * Initialize packet processor.
  *
@@ -2610,11 +2801,11 @@ mrvl_eth_dev_create(struct rte_vdev_device *vdev, const char *name)
 	memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
 	       req.ifr_addr.sa_data, ETHER_ADDR_LEN);
 
-	eth_dev->rx_pkt_burst = mrvl_rx_pkt_burst;
-	eth_dev->tx_pkt_burst = mrvl_tx_pkt_burst;
 	eth_dev->data->kdrv = RTE_KDRV_NONE;
 	eth_dev->data->dev_private = priv;
 	eth_dev->device = &vdev->device;
+	eth_dev->rx_pkt_burst = mrvl_rx_pkt_burst;
+	mrvl_set_tx_function(eth_dev);
 	eth_dev->dev_ops = &mrvl_ops;
 
 	rte_eth_dev_probing_finish(eth_dev);
diff --git a/drivers/net/mvpp2/mrvl_ethdev.h b/drivers/net/mvpp2/mrvl_ethdev.h
index f0ae983..0120b9e 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.h
+++ b/drivers/net/mvpp2/mrvl_ethdev.h
@@ -188,6 +188,7 @@ struct mrvl_priv {
 	uint8_t uc_mc_flushed;
 	uint8_t vlan_flushed;
 	uint8_t isolated;
+	uint8_t multiseg;
 
 	struct pp2_ppio_params ppio_params;
 	struct pp2_cls_qos_tbl_params qos_tbl_params;
-- 
2.7.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v3 00/13] net/mvpp2: add new features
  2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
                       ` (12 preceding siblings ...)
  2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 13/13] net/mvpp2: add Tx scatter/gather support Andrzej Ostruszka
@ 2018-09-25 16:12     ` Ferruh Yigit
  13 siblings, 0 replies; 48+ messages in thread
From: Ferruh Yigit @ 2018-09-25 16:12 UTC (permalink / raw)
  To: Andrzej Ostruszka, dev; +Cc: mw, nadavh, Akhil Goyal

On 9/25/2018 8:04 AM, Andrzej Ostruszka wrote:
> This patch series introduces fixes and adds support for traffic metering,
> traffic manager and Tx S/G. Additionally it aligns with for MUSDK 18.09.
> 
> Changes in v3:
> * change the format of image referred in doc (png -> svg)
> * "cherry-pick" http://patches.dpdk.org/patch/44255/ to be part of this
>   patch set so that next-net can compile with new MUSDK also when mvsam
>   is enabled
> 
> Changes since v2:
> * Align with MUSDK 18.09 library
> * Add support for Tx Gather.
> * Add documentation related to MTR and TM.
> * Align documentation with MUSDK 18.09
> 
> Dmitri Epshtein (1):
>   crypto/mvsam: get number of CIOs dynamically
> 
> Natalie Samsonov (4):
>   net/mvpp2: initialize ppio only once
>   net/mvpp2: update MTU and MRU related calculations
>   net/mvpp2: align documentation with MUSDK 18.09
>   net/mvpp2: document MTR and TM usage
> 
> Tomasz Duszynski (6):
>   net/mvpp2: move common code
>   net/mvpp2: add metering support
>   net/mvpp2: change default policer configuration
>   net/mvpp2: add init and deinit to flow
>   net/mvpp2: add traffic manager support
>   net/mvpp2: align with MUSDK 18.09
> 
> Yuval Caduri (1):
>   net/mvpp2: detach Tx QoS from Rx cls/QoS config
> 
> Zyta Szpak (1):
>   net/mvpp2: add Tx scatter/gather support

Series applied to dpdk-next-net/master (again), thanks.

patch 10/13 (crypto one) squashed into 9/13 (align with MUSDK 18.09)

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2018-09-25 16:12 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-04  7:10 [dpdk-dev] [PATCH 0/8] net/mvpp2: add new features Tomasz Duszynski
2018-09-04  7:10 ` [dpdk-dev] [PATCH 1/8] net/mvpp2: initialize ppio only once Tomasz Duszynski
2018-09-04  7:10 ` [dpdk-dev] [PATCH 2/8] net/mvpp2: move common code Tomasz Duszynski
2018-09-04  7:10 ` [dpdk-dev] [PATCH 3/8] net/mvpp2: add metering support Tomasz Duszynski
2018-09-04  7:10 ` [dpdk-dev] [PATCH 4/8] net/mvpp2: change default policer configuration Tomasz Duszynski
2018-09-04  7:10 ` [dpdk-dev] [PATCH 5/8] net/mvpp2: add init and deinit to flow Tomasz Duszynski
2018-09-04  7:10 ` [dpdk-dev] [PATCH 6/8] net/mvpp2: add traffic manager support Tomasz Duszynski
2018-09-04  7:10 ` [dpdk-dev] [PATCH 7/8] net/mvpp2: detach tx_qos from rx cls/qos config Tomasz Duszynski
2018-09-04  7:10 ` [dpdk-dev] [PATCH 8/8] net/mvpp2: update MTU and MRU related calculations Tomasz Duszynski
2018-09-04 13:49 ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 01/12] net/mvpp2: initialize ppio only once Tomasz Duszynski
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 02/12] net/mvpp2: move common code Tomasz Duszynski
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 03/12] net/mvpp2: add metering support Tomasz Duszynski
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 04/12] net/mvpp2: change default policer configuration Tomasz Duszynski
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 05/12] net/mvpp2: add init and deinit to flow Tomasz Duszynski
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 06/12] net/mvpp2: add traffic manager support Tomasz Duszynski
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 07/12] net/mvpp2: detach tx_qos from rx cls/qos config Tomasz Duszynski
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 08/12] net/mvpp2: update MTU and MRU related calculations Tomasz Duszynski
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 09/12] net/mvpp2: align with MUSDK 18.09 Tomasz Duszynski
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 10/12] net/mvpp2: align documentation " Tomasz Duszynski
2018-09-19 17:15     ` Ferruh Yigit
2018-09-23 22:40       ` Thomas Monjalon
2018-09-24 11:36         ` Ferruh Yigit
2018-09-24 11:51           ` Marcin Wojtas
2018-09-24 12:38             ` Ferruh Yigit
2018-09-24 12:44           ` Thomas Monjalon
2018-09-24 12:48             ` Marcin Wojtas
2018-09-24 12:50               ` Ferruh Yigit
2018-09-24 13:11                 ` Andrzej Ostruszka
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 11/12] net/mvpp2: document MTR and TM usage Tomasz Duszynski
2018-09-23 22:45     ` Thomas Monjalon
2018-09-04 13:49   ` [dpdk-dev] [PATCH v2 12/12] net/mvpp2: add Tx S/G support Tomasz Duszynski
2018-09-19 17:24   ` [dpdk-dev] [PATCH v2 00/12] net/mvpp2: add new features Ferruh Yigit
2018-09-25  7:04   ` [dpdk-dev] [PATCH v3 00/13] " Andrzej Ostruszka
2018-09-25  7:04     ` [dpdk-dev] [PATCH v3 01/13] net/mvpp2: initialize ppio only once Andrzej Ostruszka
2018-09-25  7:04     ` [dpdk-dev] [PATCH v3 02/13] net/mvpp2: move common code Andrzej Ostruszka
2018-09-25  7:04     ` [dpdk-dev] [PATCH v3 03/13] net/mvpp2: add metering support Andrzej Ostruszka
2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 04/13] net/mvpp2: change default policer configuration Andrzej Ostruszka
2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 05/13] net/mvpp2: add init and deinit to flow Andrzej Ostruszka
2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 06/13] net/mvpp2: add traffic manager support Andrzej Ostruszka
2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 07/13] net/mvpp2: detach Tx QoS from Rx cls/QoS config Andrzej Ostruszka
2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 08/13] net/mvpp2: update MTU and MRU related calculations Andrzej Ostruszka
2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 09/13] net/mvpp2: align with MUSDK 18.09 Andrzej Ostruszka
2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 10/13] crypto/mvsam: get number of CIOs dynamically Andrzej Ostruszka
2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 11/13] net/mvpp2: align documentation with MUSDK 18.09 Andrzej Ostruszka
2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 12/13] net/mvpp2: document MTR and TM usage Andrzej Ostruszka
2018-09-25  7:05     ` [dpdk-dev] [PATCH v3 13/13] net/mvpp2: add Tx scatter/gather support Andrzej Ostruszka
2018-09-25 16:12     ` [dpdk-dev] [PATCH v3 00/13] net/mvpp2: add new features Ferruh Yigit

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).