All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tomasz Duszynski <tdu@semihalf.com>
To: dev@dpdk.org
Cc: nsamsono@marvell.com, mw@semihalf.com,
	Tomasz Duszynski <tdu@semihalf.com>
Subject: [PATCH 3/8] net/mvpp2: add metering support
Date: Tue,  4 Sep 2018 09:10:11 +0200	[thread overview]
Message-ID: <1536045016-32008-4-git-send-email-tdu@semihalf.com> (raw)
In-Reply-To: <1536045016-32008-1-git-send-email-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 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

  parent reply	other threads:[~2018-09-04  7:10 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-04  7:10 [PATCH 0/8] net/mvpp2: add new features Tomasz Duszynski
2018-09-04  7:10 ` [PATCH 1/8] net/mvpp2: initialize ppio only once Tomasz Duszynski
2018-09-04  7:10 ` [PATCH 2/8] net/mvpp2: move common code Tomasz Duszynski
2018-09-04  7:10 ` Tomasz Duszynski [this message]
2018-09-04  7:10 ` [PATCH 4/8] net/mvpp2: change default policer configuration Tomasz Duszynski
2018-09-04  7:10 ` [PATCH 5/8] net/mvpp2: add init and deinit to flow Tomasz Duszynski
2018-09-04  7:10 ` [PATCH 6/8] net/mvpp2: add traffic manager support Tomasz Duszynski
2018-09-04  7:10 ` [PATCH 7/8] net/mvpp2: detach tx_qos from rx cls/qos config Tomasz Duszynski
2018-09-04  7:10 ` [PATCH 8/8] net/mvpp2: update MTU and MRU related calculations Tomasz Duszynski
2018-09-04 13:49 ` [PATCH v2 00/12] net/mvpp2: add new features Tomasz Duszynski
2018-09-04 13:49   ` [PATCH v2 01/12] net/mvpp2: initialize ppio only once Tomasz Duszynski
2018-09-04 13:49   ` [PATCH v2 02/12] net/mvpp2: move common code Tomasz Duszynski
2018-09-04 13:49   ` [PATCH v2 03/12] net/mvpp2: add metering support Tomasz Duszynski
2018-09-04 13:49   ` [PATCH v2 04/12] net/mvpp2: change default policer configuration Tomasz Duszynski
2018-09-04 13:49   ` [PATCH v2 05/12] net/mvpp2: add init and deinit to flow Tomasz Duszynski
2018-09-04 13:49   ` [PATCH v2 06/12] net/mvpp2: add traffic manager support Tomasz Duszynski
2018-09-04 13:49   ` [PATCH v2 07/12] net/mvpp2: detach tx_qos from rx cls/qos config Tomasz Duszynski
2018-09-04 13:49   ` [PATCH v2 08/12] net/mvpp2: update MTU and MRU related calculations Tomasz Duszynski
2018-09-04 13:49   ` [PATCH v2 09/12] net/mvpp2: align with MUSDK 18.09 Tomasz Duszynski
2018-09-04 13:49   ` [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   ` [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   ` [PATCH v2 12/12] net/mvpp2: add Tx S/G support Tomasz Duszynski
2018-09-19 17:24   ` [PATCH v2 00/12] net/mvpp2: add new features Ferruh Yigit
2018-09-25  7:04   ` [PATCH v3 00/13] " Andrzej Ostruszka
2018-09-25  7:04     ` [PATCH v3 01/13] net/mvpp2: initialize ppio only once Andrzej Ostruszka
2018-09-25  7:04     ` [PATCH v3 02/13] net/mvpp2: move common code Andrzej Ostruszka
2018-09-25  7:04     ` [PATCH v3 03/13] net/mvpp2: add metering support Andrzej Ostruszka
2018-09-25  7:05     ` [PATCH v3 04/13] net/mvpp2: change default policer configuration Andrzej Ostruszka
2018-09-25  7:05     ` [PATCH v3 05/13] net/mvpp2: add init and deinit to flow Andrzej Ostruszka
2018-09-25  7:05     ` [PATCH v3 06/13] net/mvpp2: add traffic manager support Andrzej Ostruszka
2018-09-25  7:05     ` [PATCH v3 07/13] net/mvpp2: detach Tx QoS from Rx cls/QoS config Andrzej Ostruszka
2018-09-25  7:05     ` [PATCH v3 08/13] net/mvpp2: update MTU and MRU related calculations Andrzej Ostruszka
2018-09-25  7:05     ` [PATCH v3 09/13] net/mvpp2: align with MUSDK 18.09 Andrzej Ostruszka
2018-09-25  7:05     ` [PATCH v3 10/13] crypto/mvsam: get number of CIOs dynamically Andrzej Ostruszka
2018-09-25  7:05     ` [PATCH v3 11/13] net/mvpp2: align documentation with MUSDK 18.09 Andrzej Ostruszka
2018-09-25  7:05     ` [PATCH v3 12/13] net/mvpp2: document MTR and TM usage Andrzej Ostruszka
2018-09-25  7:05     ` [PATCH v3 13/13] net/mvpp2: add Tx scatter/gather support Andrzej Ostruszka
2018-09-25 16:12     ` [PATCH v3 00/13] net/mvpp2: add new features Ferruh Yigit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1536045016-32008-4-git-send-email-tdu@semihalf.com \
    --to=tdu@semihalf.com \
    --cc=dev@dpdk.org \
    --cc=mw@semihalf.com \
    --cc=nsamsono@marvell.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.