diff mbox series

[v3,37/52] common/cnxk: add nix tm support for internal hierarchy

Message ID 20210401123817.14348-38-ndabilpuram@marvell.com (mailing list archive)
State Changes Requested, archived
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 Kumar Dabilpuram April 1, 2021, 12:38 p.m. UTC
Add support to create internal TM default hierarchy and ratelimit
hierarchy and API to ratelimit SQ to a given rate. This will be
used by cnxk ethdev driver's tx queue ratelimit op.

Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
---
 drivers/common/cnxk/roc_nix.h        |   7 ++
 drivers/common/cnxk/roc_nix_priv.h   |   2 +
 drivers/common/cnxk/roc_nix_tm.c     | 156 +++++++++++++++++++++++++++++++++++
 drivers/common/cnxk/roc_nix_tm_ops.c | 141 +++++++++++++++++++++++++++++++
 drivers/common/cnxk/version.map      |   3 +
 5 files changed, 309 insertions(+)
diff mbox series

Patch

diff --git a/drivers/common/cnxk/roc_nix.h b/drivers/common/cnxk/roc_nix.h
index 7bf3435..8992ad3 100644
--- a/drivers/common/cnxk/roc_nix.h
+++ b/drivers/common/cnxk/roc_nix.h
@@ -330,6 +330,8 @@  enum roc_tm_node_level {
 /*
  * TM runtime hierarchy init API.
  */
+int __roc_api roc_nix_tm_init(struct roc_nix *roc_nix);
+void __roc_api roc_nix_tm_fini(struct roc_nix *roc_nix);
 int __roc_api roc_nix_tm_sq_aura_fc(struct roc_nix_sq *sq, bool enable);
 int __roc_api roc_nix_tm_sq_flush_spin(struct roc_nix_sq *sq);
 
@@ -392,6 +394,11 @@  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 ratelimit tree API.
+ */
+int __roc_api roc_nix_tm_rlimit_sq(struct roc_nix *roc_nix, uint16_t qid,
+				   uint64_t rate);
+/*
  * TM hierarchy enable/disable API.
  */
 int __roc_api roc_nix_tm_hierarchy_disable(struct roc_nix *roc_nix);
diff --git a/drivers/common/cnxk/roc_nix_priv.h b/drivers/common/cnxk/roc_nix_priv.h
index a40621c..4e1485f 100644
--- a/drivers/common/cnxk/roc_nix_priv.h
+++ b/drivers/common/cnxk/roc_nix_priv.h
@@ -326,6 +326,7 @@  int nix_tm_leaf_data_get(struct nix *nix, uint16_t sq, uint32_t *rr_quantum,
 int nix_tm_sq_flush_pre(struct roc_nix_sq *sq);
 int nix_tm_sq_flush_post(struct roc_nix_sq *sq);
 int nix_tm_smq_xoff(struct nix *nix, struct nix_tm_node *node, bool enable);
+int nix_tm_prepare_default_tree(struct roc_nix *roc_nix);
 int nix_tm_node_add(struct roc_nix *roc_nix, struct nix_tm_node *node);
 int nix_tm_node_delete(struct roc_nix *roc_nix, uint32_t node_id,
 		       enum roc_nix_tm_tree tree, bool free);
@@ -344,6 +345,7 @@  int nix_tm_txsch_reg_config(struct nix *nix, enum roc_nix_tm_tree tree);
 int nix_tm_update_parent_info(struct nix *nix, enum roc_nix_tm_tree tree);
 int nix_tm_sq_sched_conf(struct nix *nix, struct nix_tm_node *node,
 			 bool rr_quantum_only);
+int nix_tm_prepare_rate_limited_tree(struct roc_nix *roc_nix);
 
 /*
  * TM priv utils.
diff --git a/drivers/common/cnxk/roc_nix_tm.c b/drivers/common/cnxk/roc_nix_tm.c
index 762c85a..9b328c9 100644
--- a/drivers/common/cnxk/roc_nix_tm.c
+++ b/drivers/common/cnxk/roc_nix_tm.c
@@ -1089,6 +1089,162 @@  nix_tm_alloc_txschq(struct nix *nix, enum roc_nix_tm_tree tree)
 }
 
 int
+nix_tm_prepare_default_tree(struct roc_nix *roc_nix)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	uint32_t nonleaf_id = nix->nb_tx_queues;
+	struct nix_tm_node *node = NULL;
+	uint8_t leaf_lvl, lvl, lvl_end;
+	uint32_t parent, i;
+	int rc = 0;
+
+	/* Add ROOT, SCH1, SCH2, SCH3, [SCH4]  nodes */
+	parent = ROC_NIX_TM_NODE_ID_INVALID;
+	/* With TL1 access we have an extra level */
+	lvl_end = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH4 :
+						       ROC_TM_LVL_SCH3);
+
+	for (lvl = ROC_TM_LVL_ROOT; lvl <= lvl_end; lvl++) {
+		rc = -ENOMEM;
+		node = nix_tm_node_alloc();
+		if (!node)
+			goto error;
+
+		node->id = nonleaf_id;
+		node->parent_id = parent;
+		node->priority = 0;
+		node->weight = NIX_TM_DFLT_RR_WT;
+		node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
+		node->lvl = lvl;
+		node->tree = ROC_NIX_TM_DEFAULT;
+
+		rc = nix_tm_node_add(roc_nix, node);
+		if (rc)
+			goto error;
+		parent = nonleaf_id;
+		nonleaf_id++;
+	}
+
+	parent = nonleaf_id - 1;
+	leaf_lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_QUEUE :
+							ROC_TM_LVL_SCH4);
+
+	/* Add leaf nodes */
+	for (i = 0; i < nix->nb_tx_queues; i++) {
+		rc = -ENOMEM;
+		node = nix_tm_node_alloc();
+		if (!node)
+			goto error;
+
+		node->id = i;
+		node->parent_id = parent;
+		node->priority = 0;
+		node->weight = NIX_TM_DFLT_RR_WT;
+		node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
+		node->lvl = leaf_lvl;
+		node->tree = ROC_NIX_TM_DEFAULT;
+
+		rc = nix_tm_node_add(roc_nix, node);
+		if (rc)
+			goto error;
+	}
+
+	return 0;
+error:
+	nix_tm_node_free(node);
+	return rc;
+}
+
+int
+nix_tm_prepare_rate_limited_tree(struct roc_nix *roc_nix)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	uint32_t nonleaf_id = nix->nb_tx_queues;
+	struct nix_tm_node *node = NULL;
+	uint8_t leaf_lvl, lvl, lvl_end;
+	uint32_t parent, i;
+	int rc = 0;
+
+	/* Add ROOT, SCH1, SCH2 nodes */
+	parent = ROC_NIX_TM_NODE_ID_INVALID;
+	lvl_end = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH3 :
+						       ROC_TM_LVL_SCH2);
+
+	for (lvl = ROC_TM_LVL_ROOT; lvl <= lvl_end; lvl++) {
+		rc = -ENOMEM;
+		node = nix_tm_node_alloc();
+		if (!node)
+			goto error;
+
+		node->id = nonleaf_id;
+		node->parent_id = parent;
+		node->priority = 0;
+		node->weight = NIX_TM_DFLT_RR_WT;
+		node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
+		node->lvl = lvl;
+		node->tree = ROC_NIX_TM_RLIMIT;
+
+		rc = nix_tm_node_add(roc_nix, node);
+		if (rc)
+			goto error;
+		parent = nonleaf_id;
+		nonleaf_id++;
+	}
+
+	/* SMQ is mapped to SCH4 when we have TL1 access and SCH3 otherwise */
+	lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_SCH4 : ROC_TM_LVL_SCH3);
+
+	/* Add per queue SMQ nodes i.e SCH4 / SCH3 */
+	for (i = 0; i < nix->nb_tx_queues; i++) {
+		rc = -ENOMEM;
+		node = nix_tm_node_alloc();
+		if (!node)
+			goto error;
+
+		node->id = nonleaf_id + i;
+		node->parent_id = parent;
+		node->priority = 0;
+		node->weight = NIX_TM_DFLT_RR_WT;
+		node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
+		node->lvl = lvl;
+		node->tree = ROC_NIX_TM_RLIMIT;
+
+		rc = nix_tm_node_add(roc_nix, node);
+		if (rc)
+			goto error;
+	}
+
+	parent = nonleaf_id;
+	leaf_lvl = (nix_tm_have_tl1_access(nix) ? ROC_TM_LVL_QUEUE :
+							ROC_TM_LVL_SCH4);
+
+	/* Add leaf nodes */
+	for (i = 0; i < nix->nb_tx_queues; i++) {
+		rc = -ENOMEM;
+		node = nix_tm_node_alloc();
+		if (!node)
+			goto error;
+
+		node->id = i;
+		node->parent_id = parent;
+		node->priority = 0;
+		node->weight = NIX_TM_DFLT_RR_WT;
+		node->shaper_profile_id = ROC_NIX_TM_SHAPER_PROFILE_NONE;
+		node->lvl = leaf_lvl;
+		node->tree = ROC_NIX_TM_RLIMIT;
+
+		rc = nix_tm_node_add(roc_nix, node);
+		if (rc)
+			goto error;
+	}
+
+	return 0;
+error:
+	nix_tm_node_free(node);
+	return rc;
+}
+
+int
 nix_tm_free_resources(struct roc_nix *roc_nix, uint32_t tree_mask, bool hw_only)
 {
 	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
diff --git a/drivers/common/cnxk/roc_nix_tm_ops.c b/drivers/common/cnxk/roc_nix_tm_ops.c
index 6bb0766..d13cc8a 100644
--- a/drivers/common/cnxk/roc_nix_tm_ops.c
+++ b/drivers/common/cnxk/roc_nix_tm_ops.c
@@ -543,3 +543,144 @@  roc_nix_tm_hierarchy_enable(struct roc_nix *roc_nix, enum roc_nix_tm_tree tree,
 	nix->tm_flags |= NIX_TM_HIERARCHY_ENA;
 	return 0;
 }
+
+int
+roc_nix_tm_init(struct roc_nix *roc_nix)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	uint32_t tree_mask;
+	int rc;
+
+	if (nix->tm_flags & NIX_TM_HIERARCHY_ENA) {
+		plt_err("Cannot init while existing hierarchy is enabled");
+		return -EBUSY;
+	}
+
+	/* Free up all user resources already held */
+	tree_mask = NIX_TM_TREE_MASK_ALL;
+	rc = nix_tm_free_resources(roc_nix, tree_mask, false);
+	if (rc) {
+		plt_err("Failed to freeup all nodes and resources, rc=%d", rc);
+		return rc;
+	}
+
+	/* Prepare default tree */
+	rc = nix_tm_prepare_default_tree(roc_nix);
+	if (rc) {
+		plt_err("failed to prepare default tm tree, rc=%d", rc);
+		return rc;
+	}
+
+	/* Prepare rlimit tree */
+	rc = nix_tm_prepare_rate_limited_tree(roc_nix);
+	if (rc) {
+		plt_err("failed to prepare rlimit tm tree, rc=%d", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+int
+roc_nix_tm_rlimit_sq(struct roc_nix *roc_nix, uint16_t qid, uint64_t rate)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct nix_tm_shaper_profile profile;
+	struct mbox *mbox = (&nix->dev)->mbox;
+	struct nix_tm_node *node, *parent;
+
+	volatile uint64_t *reg, *regval;
+	struct nix_txschq_config *req;
+	uint16_t flags;
+	uint8_t k = 0;
+	int rc;
+
+	if (nix->tm_tree != ROC_NIX_TM_RLIMIT ||
+	    !(nix->tm_flags & NIX_TM_HIERARCHY_ENA))
+		return NIX_ERR_TM_INVALID_TREE;
+
+	node = nix_tm_node_search(nix, qid, ROC_NIX_TM_RLIMIT);
+
+	/* check if we found a valid leaf node */
+	if (!node || !nix_tm_is_leaf(nix, node->lvl) || !node->parent ||
+	    node->parent->hw_id == NIX_TM_HW_ID_INVALID)
+		return NIX_ERR_TM_INVALID_NODE;
+
+	parent = node->parent;
+	flags = parent->flags;
+
+	req = mbox_alloc_msg_nix_txschq_cfg(mbox);
+	req->lvl = NIX_TXSCH_LVL_MDQ;
+	reg = req->reg;
+	regval = req->regval;
+
+	if (rate == 0) {
+		k += nix_tm_sw_xoff_prep(parent, true, &reg[k], &regval[k]);
+		flags &= ~NIX_TM_NODE_ENABLED;
+		goto exit;
+	}
+
+	if (!(flags & NIX_TM_NODE_ENABLED)) {
+		k += nix_tm_sw_xoff_prep(parent, false, &reg[k], &regval[k]);
+		flags |= NIX_TM_NODE_ENABLED;
+	}
+
+	/* Use only PIR for rate limit */
+	memset(&profile, 0, sizeof(profile));
+	profile.peak.rate = rate;
+	/* Minimum burst of ~4us Bytes of Tx */
+	profile.peak.size = PLT_MAX((uint64_t)roc_nix_max_pkt_len(roc_nix),
+				    (4ul * rate) / ((uint64_t)1E6 * 8));
+	if (!nix->tm_rate_min || nix->tm_rate_min > rate)
+		nix->tm_rate_min = rate;
+
+	k += nix_tm_shaper_reg_prep(parent, &profile, &reg[k], &regval[k]);
+exit:
+	req->num_regs = k;
+	rc = mbox_process(mbox);
+	if (rc)
+		return rc;
+
+	parent->flags = flags;
+	return 0;
+}
+
+void
+roc_nix_tm_fini(struct roc_nix *roc_nix)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct mbox *mbox = (&nix->dev)->mbox;
+	struct nix_txsch_free_req *req;
+	uint32_t tree_mask;
+	uint8_t hw_lvl;
+	int rc;
+
+	/* Xmit is assumed to be disabled */
+	/* Free up resources already held */
+	tree_mask = NIX_TM_TREE_MASK_ALL;
+	rc = nix_tm_free_resources(roc_nix, tree_mask, false);
+	if (rc)
+		plt_err("Failed to freeup existing nodes or rsrcs, rc=%d", rc);
+
+	/* Free all other hw resources */
+	req = mbox_alloc_msg_nix_txsch_free(mbox);
+	if (req == NULL)
+		return;
+
+	req->flags = TXSCHQ_FREE_ALL;
+	rc = mbox_process(mbox);
+	if (rc)
+		plt_err("Failed to freeup all res, rc=%d", rc);
+
+	for (hw_lvl = 0; hw_lvl < NIX_TXSCH_LVL_CNT; hw_lvl++) {
+		plt_bitmap_reset(nix->schq_bmp[hw_lvl]);
+		plt_bitmap_reset(nix->schq_contig_bmp[hw_lvl]);
+		nix->contig_rsvd[hw_lvl] = 0;
+		nix->discontig_rsvd[hw_lvl] = 0;
+	}
+
+	/* Clear shaper profiles */
+	nix_tm_clear_shaper_profiles(nix);
+	nix->tm_tree = 0;
+	nix->tm_flags &= ~NIX_TM_HIERARCHY_ENA;
+}
diff --git a/drivers/common/cnxk/version.map b/drivers/common/cnxk/version.map
index 9c860ff..854c3c1 100644
--- a/drivers/common/cnxk/version.map
+++ b/drivers/common/cnxk/version.map
@@ -104,9 +104,11 @@  INTERNAL {
 	roc_nix_xstats_names_get;
 	roc_nix_switch_hdr_set;
 	roc_nix_eeprom_info_get;
+	roc_nix_tm_fini;
 	roc_nix_tm_free_resources;
 	roc_nix_tm_hierarchy_disable;
 	roc_nix_tm_hierarchy_enable;
+	roc_nix_tm_init;
 	roc_nix_tm_node_add;
 	roc_nix_tm_node_delete;
 	roc_nix_tm_node_get;
@@ -114,6 +116,7 @@  INTERNAL {
 	roc_nix_tm_node_name_get;
 	roc_nix_tm_node_next;
 	roc_nix_tm_node_pkt_mode_update;
+	roc_nix_tm_rlimit_sq;
 	roc_nix_tm_shaper_profile_add;
 	roc_nix_tm_shaper_profile_delete;
 	roc_nix_tm_shaper_profile_get;