diff mbox series

[v4,34/52] common/cnxk: add nix tm shaper profile add support

Message ID 20210406114131.25874-35-ndabilpuram@marvell.com (mailing list archive)
State Superseded
Delegated to: Jerin Jacob
Headers show
Series Add Marvell CNXK common driver | expand

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Nithin Dabilpuram April 6, 2021, 11:41 a.m. UTC
From: Satha Rao <skoteshwar@marvell.com>

Add support to add/delete/update shaper profile for
a given NIX. Also add support to walk through existing
shaper profiles.

Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
Signed-off-by: Satha Rao <skoteshwar@marvell.com>
---
 drivers/common/cnxk/roc_nix.h          |  25 +++++
 drivers/common/cnxk/roc_nix_priv.h     |   8 ++
 drivers/common/cnxk/roc_nix_tm.c       |  18 ++++
 drivers/common/cnxk/roc_nix_tm_ops.c   | 145 ++++++++++++++++++++++++++++
 drivers/common/cnxk/roc_nix_tm_utils.c | 167 +++++++++++++++++++++++++++++++++
 drivers/common/cnxk/version.map        |   5 +
 6 files changed, 368 insertions(+)
diff mbox series

Patch

diff --git a/drivers/common/cnxk/roc_nix.h b/drivers/common/cnxk/roc_nix.h
index d656909..ea34cd2 100644
--- a/drivers/common/cnxk/roc_nix.h
+++ b/drivers/common/cnxk/roc_nix.h
@@ -353,17 +353,42 @@  struct roc_nix_tm_node {
 	void (*free_fn)(void *node);
 };
 
+struct roc_nix_tm_shaper_profile {
+#define ROC_NIX_TM_SHAPER_PROFILE_SZ (128)
+	uint8_t reserved[ROC_NIX_TM_SHAPER_PROFILE_SZ];
+
+	uint32_t id;
+	uint64_t commit_rate;
+	uint64_t commit_sz;
+	uint64_t peak_rate;
+	uint64_t peak_sz;
+	int32_t pkt_len_adj;
+	bool pkt_mode;
+	/* Function to free this memory */
+	void (*free_fn)(void *profile);
+};
+
 int __roc_api roc_nix_tm_node_add(struct roc_nix *roc_nix,
 				  struct roc_nix_tm_node *roc_node);
 int __roc_api roc_nix_tm_node_delete(struct roc_nix *roc_nix, uint32_t node_id,
 				     bool free);
 int __roc_api roc_nix_tm_node_pkt_mode_update(struct roc_nix *roc_nix,
 					      uint32_t node_id, bool pkt_mode);
+int __roc_api roc_nix_tm_shaper_profile_add(
+	struct roc_nix *roc_nix, struct roc_nix_tm_shaper_profile *profile);
+int __roc_api roc_nix_tm_shaper_profile_update(
+	struct roc_nix *roc_nix, struct roc_nix_tm_shaper_profile *profile);
+int __roc_api roc_nix_tm_shaper_profile_delete(struct roc_nix *roc_nix,
+					       uint32_t id);
 
 struct roc_nix_tm_node *__roc_api roc_nix_tm_node_get(struct roc_nix *roc_nix,
 						      uint32_t node_id);
 struct roc_nix_tm_node *__roc_api
 roc_nix_tm_node_next(struct roc_nix *roc_nix, struct roc_nix_tm_node *__prev);
+struct roc_nix_tm_shaper_profile *__roc_api
+roc_nix_tm_shaper_profile_get(struct roc_nix *roc_nix, uint32_t profile_id);
+struct roc_nix_tm_shaper_profile *__roc_api roc_nix_tm_shaper_profile_next(
+	struct roc_nix *roc_nix, struct roc_nix_tm_shaper_profile *__prev);
 
 /*
  * TM utilities API.
diff --git a/drivers/common/cnxk/roc_nix_priv.h b/drivers/common/cnxk/roc_nix_priv.h
index cee73ae..cd1eaa5 100644
--- a/drivers/common/cnxk/roc_nix_priv.h
+++ b/drivers/common/cnxk/roc_nix_priv.h
@@ -331,6 +331,7 @@  int nix_tm_node_delete(struct roc_nix *roc_nix, uint32_t node_id,
 		       enum roc_nix_tm_tree tree, bool free);
 int nix_tm_free_node_resource(struct nix *nix, struct nix_tm_node *node);
 int nix_tm_clear_path_xoff(struct nix *nix, struct nix_tm_node *node);
+void nix_tm_clear_shaper_profiles(struct nix *nix);
 
 /*
  * TM priv utils.
@@ -347,7 +348,14 @@  struct nix_tm_shaper_profile *nix_tm_shaper_profile_search(struct nix *nix,
 							   uint32_t id);
 uint8_t nix_tm_sw_xoff_prep(struct nix_tm_node *node, bool enable,
 			    volatile uint64_t *reg, volatile uint64_t *regval);
+uint64_t nix_tm_shaper_profile_rate_min(struct nix *nix);
+uint64_t nix_tm_shaper_rate_conv(uint64_t value, uint64_t *exponent_p,
+				 uint64_t *mantissa_p, uint64_t *div_exp_p);
+uint64_t nix_tm_shaper_burst_conv(uint64_t value, uint64_t *exponent_p,
+				  uint64_t *mantissa_p);
 struct nix_tm_node *nix_tm_node_alloc(void);
 void nix_tm_node_free(struct nix_tm_node *node);
+struct nix_tm_shaper_profile *nix_tm_shaper_profile_alloc(void);
+void nix_tm_shaper_profile_free(struct nix_tm_shaper_profile *profile);
 
 #endif /* _ROC_NIX_PRIV_H_ */
diff --git a/drivers/common/cnxk/roc_nix_tm.c b/drivers/common/cnxk/roc_nix_tm.c
index f103e02..d2e2250 100644
--- a/drivers/common/cnxk/roc_nix_tm.c
+++ b/drivers/common/cnxk/roc_nix_tm.c
@@ -5,6 +5,22 @@ 
 #include "roc_api.h"
 #include "roc_priv.h"
 
+void
+nix_tm_clear_shaper_profiles(struct nix *nix)
+{
+	struct nix_tm_shaper_profile *shaper_profile;
+
+	shaper_profile = TAILQ_FIRST(&nix->shaper_profile_list);
+	while (shaper_profile != NULL) {
+		if (shaper_profile->ref_cnt)
+			plt_warn("Shaper profile %u has non zero references",
+				 shaper_profile->id);
+		TAILQ_REMOVE(&nix->shaper_profile_list, shaper_profile, shaper);
+		nix_tm_shaper_profile_free(shaper_profile);
+		shaper_profile = TAILQ_FIRST(&nix->shaper_profile_list);
+	}
+}
+
 int
 nix_tm_node_add(struct roc_nix *roc_nix, struct nix_tm_node *node)
 {
@@ -532,6 +548,8 @@  nix_tm_conf_init(struct roc_nix *roc_nix)
 	int rc, i;
 
 	PLT_STATIC_ASSERT(sizeof(struct nix_tm_node) <= ROC_NIX_TM_NODE_SZ);
+	PLT_STATIC_ASSERT(sizeof(struct nix_tm_shaper_profile) <=
+			  ROC_NIX_TM_SHAPER_PROFILE_SZ);
 
 	nix->tm_flags = 0;
 	for (i = 0; i < ROC_NIX_TM_TREE_MAX; i++)
diff --git a/drivers/common/cnxk/roc_nix_tm_ops.c b/drivers/common/cnxk/roc_nix_tm_ops.c
index d0941c0..896ddf2 100644
--- a/drivers/common/cnxk/roc_nix_tm_ops.c
+++ b/drivers/common/cnxk/roc_nix_tm_ops.c
@@ -66,6 +66,151 @@  roc_nix_tm_sq_aura_fc(struct roc_nix_sq *sq, bool enable)
 	return 0;
 }
 
+static int
+nix_tm_shaper_profile_add(struct roc_nix *roc_nix,
+			  struct nix_tm_shaper_profile *profile, int skip_ins)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	uint64_t commit_rate, commit_sz;
+	uint64_t peak_rate, peak_sz;
+	uint32_t id;
+
+	id = profile->id;
+	commit_rate = profile->commit.rate;
+	commit_sz = profile->commit.size;
+	peak_rate = profile->peak.rate;
+	peak_sz = profile->peak.size;
+
+	if (nix_tm_shaper_profile_search(nix, id) && !skip_ins)
+		return NIX_ERR_TM_SHAPER_PROFILE_EXISTS;
+
+	if (profile->pkt_len_adj < NIX_TM_LENGTH_ADJUST_MIN ||
+	    profile->pkt_len_adj > NIX_TM_LENGTH_ADJUST_MAX)
+		return NIX_ERR_TM_SHAPER_PKT_LEN_ADJUST;
+
+	/* We cannot support both pkt length adjust and pkt mode */
+	if (profile->pkt_mode && profile->pkt_len_adj)
+		return NIX_ERR_TM_SHAPER_PKT_LEN_ADJUST;
+
+	/* commit rate and burst size can be enabled/disabled */
+	if (commit_rate || commit_sz) {
+		if (commit_sz < NIX_TM_MIN_SHAPER_BURST ||
+		    commit_sz > NIX_TM_MAX_SHAPER_BURST)
+			return NIX_ERR_TM_INVALID_COMMIT_SZ;
+		else if (!nix_tm_shaper_rate_conv(commit_rate, NULL, NULL,
+						  NULL))
+			return NIX_ERR_TM_INVALID_COMMIT_RATE;
+	}
+
+	/* Peak rate and burst size can be enabled/disabled */
+	if (peak_sz || peak_rate) {
+		if (peak_sz < NIX_TM_MIN_SHAPER_BURST ||
+		    peak_sz > NIX_TM_MAX_SHAPER_BURST)
+			return NIX_ERR_TM_INVALID_PEAK_SZ;
+		else if (!nix_tm_shaper_rate_conv(peak_rate, NULL, NULL, NULL))
+			return NIX_ERR_TM_INVALID_PEAK_RATE;
+	}
+
+	if (!skip_ins)
+		TAILQ_INSERT_TAIL(&nix->shaper_profile_list, profile, shaper);
+
+	plt_tm_dbg("Added TM shaper profile %u, "
+		   " pir %" PRIu64 " , pbs %" PRIu64 ", cir %" PRIu64
+		   ", cbs %" PRIu64 " , adj %u, pkt_mode %u",
+		   id, profile->peak.rate, profile->peak.size,
+		   profile->commit.rate, profile->commit.size,
+		   profile->pkt_len_adj, profile->pkt_mode);
+
+	/* Always use PIR for single rate shaping */
+	if (!peak_rate && commit_rate) {
+		profile->peak.rate = profile->commit.rate;
+		profile->peak.size = profile->commit.size;
+		profile->commit.rate = 0;
+		profile->commit.size = 0;
+	}
+
+	/* update min rate */
+	nix->tm_rate_min = nix_tm_shaper_profile_rate_min(nix);
+	return 0;
+}
+
+int
+roc_nix_tm_shaper_profile_add(struct roc_nix *roc_nix,
+			      struct roc_nix_tm_shaper_profile *roc_profile)
+{
+	struct nix_tm_shaper_profile *profile;
+
+	profile = (struct nix_tm_shaper_profile *)roc_profile->reserved;
+
+	profile->ref_cnt = 0;
+	profile->id = roc_profile->id;
+	if (roc_profile->pkt_mode) {
+		/* Each packet accomulate single count, whereas HW
+		 * considers each unit as Byte, so we need convert
+		 * user pps to bps
+		 */
+		profile->commit.rate = roc_profile->commit_rate * 8;
+		profile->peak.rate = roc_profile->peak_rate * 8;
+	} else {
+		profile->commit.rate = roc_profile->commit_rate;
+		profile->peak.rate = roc_profile->peak_rate;
+	}
+	profile->commit.size = roc_profile->commit_sz;
+	profile->peak.size = roc_profile->peak_sz;
+	profile->pkt_len_adj = roc_profile->pkt_len_adj;
+	profile->pkt_mode = roc_profile->pkt_mode;
+	profile->free_fn = roc_profile->free_fn;
+
+	return nix_tm_shaper_profile_add(roc_nix, profile, 0);
+}
+
+int
+roc_nix_tm_shaper_profile_update(struct roc_nix *roc_nix,
+				 struct roc_nix_tm_shaper_profile *roc_profile)
+{
+	struct nix_tm_shaper_profile *profile;
+
+	profile = (struct nix_tm_shaper_profile *)roc_profile->reserved;
+
+	if (roc_profile->pkt_mode) {
+		/* Each packet accomulate single count, whereas HW
+		 * considers each unit as Byte, so we need convert
+		 * user pps to bps
+		 */
+		profile->commit.rate = roc_profile->commit_rate * 8;
+		profile->peak.rate = roc_profile->peak_rate * 8;
+	} else {
+		profile->commit.rate = roc_profile->commit_rate;
+		profile->peak.rate = roc_profile->peak_rate;
+	}
+	profile->commit.size = roc_profile->commit_sz;
+	profile->peak.size = roc_profile->peak_sz;
+
+	return nix_tm_shaper_profile_add(roc_nix, profile, 1);
+}
+
+int
+roc_nix_tm_shaper_profile_delete(struct roc_nix *roc_nix, uint32_t id)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct nix_tm_shaper_profile *profile;
+
+	profile = nix_tm_shaper_profile_search(nix, id);
+	if (!profile)
+		return NIX_ERR_TM_INVALID_SHAPER_PROFILE;
+
+	if (profile->ref_cnt)
+		return NIX_ERR_TM_SHAPER_PROFILE_IN_USE;
+
+	plt_tm_dbg("Removing TM shaper profile %u", id);
+	TAILQ_REMOVE(&nix->shaper_profile_list, profile, shaper);
+	nix_tm_shaper_profile_free(profile);
+
+	/* update min rate */
+	nix->tm_rate_min = nix_tm_shaper_profile_rate_min(nix);
+	return 0;
+}
+
 int
 roc_nix_tm_node_add(struct roc_nix *roc_nix, struct roc_nix_tm_node *roc_node)
 {
diff --git a/drivers/common/cnxk/roc_nix_tm_utils.c b/drivers/common/cnxk/roc_nix_tm_utils.c
index bea23be..7a7e786 100644
--- a/drivers/common/cnxk/roc_nix_tm_utils.c
+++ b/drivers/common/cnxk/roc_nix_tm_utils.c
@@ -77,6 +77,106 @@  nix_tm_node_search(struct nix *nix, uint32_t node_id, enum roc_nix_tm_tree tree)
 	return NULL;
 }
 
+uint64_t
+nix_tm_shaper_rate_conv(uint64_t value, uint64_t *exponent_p,
+			uint64_t *mantissa_p, uint64_t *div_exp_p)
+{
+	uint64_t div_exp, exponent, mantissa;
+
+	/* Boundary checks */
+	if (value < NIX_TM_MIN_SHAPER_RATE || value > NIX_TM_MAX_SHAPER_RATE)
+		return 0;
+
+	if (value <= NIX_TM_SHAPER_RATE(0, 0, 0)) {
+		/* Calculate rate div_exp and mantissa using
+		 * the following formula:
+		 *
+		 * value = (2E6 * (256 + mantissa)
+		 *              / ((1 << div_exp) * 256))
+		 */
+		div_exp = 0;
+		exponent = 0;
+		mantissa = NIX_TM_MAX_RATE_MANTISSA;
+
+		while (value < (NIX_TM_SHAPER_RATE_CONST / (1 << div_exp)))
+			div_exp += 1;
+
+		while (value < ((NIX_TM_SHAPER_RATE_CONST * (256 + mantissa)) /
+				((1 << div_exp) * 256)))
+			mantissa -= 1;
+	} else {
+		/* Calculate rate exponent and mantissa using
+		 * the following formula:
+		 *
+		 * value = (2E6 * ((256 + mantissa) << exponent)) / 256
+		 *
+		 */
+		div_exp = 0;
+		exponent = NIX_TM_MAX_RATE_EXPONENT;
+		mantissa = NIX_TM_MAX_RATE_MANTISSA;
+
+		while (value < (NIX_TM_SHAPER_RATE_CONST * (1 << exponent)))
+			exponent -= 1;
+
+		while (value < ((NIX_TM_SHAPER_RATE_CONST *
+				 ((256 + mantissa) << exponent)) /
+				256))
+			mantissa -= 1;
+	}
+
+	if (div_exp > NIX_TM_MAX_RATE_DIV_EXP ||
+	    exponent > NIX_TM_MAX_RATE_EXPONENT ||
+	    mantissa > NIX_TM_MAX_RATE_MANTISSA)
+		return 0;
+
+	if (div_exp_p)
+		*div_exp_p = div_exp;
+	if (exponent_p)
+		*exponent_p = exponent;
+	if (mantissa_p)
+		*mantissa_p = mantissa;
+
+	/* Calculate real rate value */
+	return NIX_TM_SHAPER_RATE(exponent, mantissa, div_exp);
+}
+
+uint64_t
+nix_tm_shaper_burst_conv(uint64_t value, uint64_t *exponent_p,
+			 uint64_t *mantissa_p)
+{
+	uint64_t exponent, mantissa;
+
+	if (value < NIX_TM_MIN_SHAPER_BURST || value > NIX_TM_MAX_SHAPER_BURST)
+		return 0;
+
+	/* Calculate burst exponent and mantissa using
+	 * the following formula:
+	 *
+	 * value = (((256 + mantissa) << (exponent + 1)
+	 / 256)
+	 *
+	 */
+	exponent = NIX_TM_MAX_BURST_EXPONENT;
+	mantissa = NIX_TM_MAX_BURST_MANTISSA;
+
+	while (value < (1ull << (exponent + 1)))
+		exponent -= 1;
+
+	while (value < ((256 + mantissa) << (exponent + 1)) / 256)
+		mantissa -= 1;
+
+	if (exponent > NIX_TM_MAX_BURST_EXPONENT ||
+	    mantissa > NIX_TM_MAX_BURST_MANTISSA)
+		return 0;
+
+	if (exponent_p)
+		*exponent_p = exponent;
+	if (mantissa_p)
+		*mantissa_p = mantissa;
+
+	return NIX_TM_SHAPER_BURST(exponent, mantissa);
+}
+
 static uint16_t
 nix_tm_max_prio(struct nix *nix, uint16_t hw_lvl)
 {
@@ -183,6 +283,23 @@  nix_tm_sw_xoff_prep(struct nix_tm_node *node, bool enable,
 	return k;
 }
 
+/* Search for min rate in topology */
+uint64_t
+nix_tm_shaper_profile_rate_min(struct nix *nix)
+{
+	struct nix_tm_shaper_profile *profile;
+	uint64_t rate_min = 1E9; /* 1 Gbps */
+
+	TAILQ_FOREACH(profile, &nix->shaper_profile_list, shaper) {
+		if (profile->peak.rate && profile->peak.rate < rate_min)
+			rate_min = profile->peak.rate;
+
+		if (profile->commit.rate && profile->commit.rate < rate_min)
+			rate_min = profile->commit.rate;
+	}
+	return rate_min;
+}
+
 uint16_t
 nix_tm_resource_avail(struct nix *nix, uint8_t hw_lvl, bool contig)
 {
@@ -251,6 +368,34 @@  roc_nix_tm_node_next(struct roc_nix *roc_nix, struct roc_nix_tm_node *__prev)
 	return (struct roc_nix_tm_node *)TAILQ_NEXT(prev, node);
 }
 
+struct roc_nix_tm_shaper_profile *
+roc_nix_tm_shaper_profile_get(struct roc_nix *roc_nix, uint32_t profile_id)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct nix_tm_shaper_profile *profile;
+
+	profile = nix_tm_shaper_profile_search(nix, profile_id);
+	return (struct roc_nix_tm_shaper_profile *)profile;
+}
+
+struct roc_nix_tm_shaper_profile *
+roc_nix_tm_shaper_profile_next(struct roc_nix *roc_nix,
+			       struct roc_nix_tm_shaper_profile *__prev)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct nix_tm_shaper_profile_list *list;
+	struct nix_tm_shaper_profile *prev;
+
+	prev = (struct nix_tm_shaper_profile *)__prev;
+	list = &nix->shaper_profile_list;
+
+	/* HEAD of the list */
+	if (!prev)
+		return (struct roc_nix_tm_shaper_profile *)TAILQ_FIRST(list);
+
+	return (struct roc_nix_tm_shaper_profile *)TAILQ_NEXT(prev, shaper);
+}
+
 struct nix_tm_node *
 nix_tm_node_alloc(void)
 {
@@ -272,3 +417,25 @@  nix_tm_node_free(struct nix_tm_node *node)
 
 	(node->free_fn)(node);
 }
+
+struct nix_tm_shaper_profile *
+nix_tm_shaper_profile_alloc(void)
+{
+	struct nix_tm_shaper_profile *profile;
+
+	profile = plt_zmalloc(sizeof(struct nix_tm_shaper_profile), 0);
+	if (!profile)
+		return NULL;
+
+	profile->free_fn = plt_free;
+	return profile;
+}
+
+void
+nix_tm_shaper_profile_free(struct nix_tm_shaper_profile *profile)
+{
+	if (!profile || !profile->free_fn)
+		return;
+
+	(profile->free_fn)(profile);
+}
diff --git a/drivers/common/cnxk/version.map b/drivers/common/cnxk/version.map
index 2bc50bf..5bf8717 100644
--- a/drivers/common/cnxk/version.map
+++ b/drivers/common/cnxk/version.map
@@ -111,6 +111,11 @@  INTERNAL {
 	roc_nix_tm_node_name_get;
 	roc_nix_tm_node_next;
 	roc_nix_tm_node_pkt_mode_update;
+	roc_nix_tm_shaper_profile_add;
+	roc_nix_tm_shaper_profile_delete;
+	roc_nix_tm_shaper_profile_get;
+	roc_nix_tm_shaper_profile_next;
+	roc_nix_tm_shaper_profile_update;
 	roc_nix_tm_sq_aura_fc;
 	roc_nix_tm_sq_flush_spin;
 	roc_nix_unregister_cq_irqs;