From 464c9f919321a3294dc29fd6c5d786e3323670a9 Mon Sep 17 00:00:00 2001 From: Nithin Dabilpuram Date: Tue, 6 Apr 2021 20:11:30 +0530 Subject: [PATCH] common/cnxk: support NIX TM dynamic update Add support for dynamic node update of shaper profile, RR quantum and also support to suspend or resume an active TM node. Signed-off-by: Nithin Dabilpuram --- drivers/common/cnxk/roc_nix.h | 10 ++ drivers/common/cnxk/roc_nix_tm_ops.c | 220 +++++++++++++++++++++++++++ drivers/common/cnxk/version.map | 3 + 3 files changed, 233 insertions(+) diff --git a/drivers/common/cnxk/roc_nix.h b/drivers/common/cnxk/roc_nix.h index 8992ad3026..ad00efe87a 100644 --- a/drivers/common/cnxk/roc_nix.h +++ b/drivers/common/cnxk/roc_nix.h @@ -375,6 +375,16 @@ int __roc_api roc_nix_tm_node_add(struct roc_nix *roc_nix, 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_free_resources(struct roc_nix *roc_nix, bool hw_only); +int __roc_api roc_nix_tm_node_suspend_resume(struct roc_nix *roc_nix, + uint32_t node_id, bool suspend); +int __roc_api roc_nix_tm_node_parent_update(struct roc_nix *roc_nix, + uint32_t node_id, + uint32_t new_parent_id, + uint32_t priority, uint32_t weight); +int __roc_api roc_nix_tm_node_shaper_update(struct roc_nix *roc_nix, + uint32_t node_id, + uint32_t profile_id, + bool force_update); 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( diff --git a/drivers/common/cnxk/roc_nix_tm_ops.c b/drivers/common/cnxk/roc_nix_tm_ops.c index d13cc8a42c..e4463d1752 100644 --- a/drivers/common/cnxk/roc_nix_tm_ops.c +++ b/drivers/common/cnxk/roc_nix_tm_ops.c @@ -544,6 +544,226 @@ skip_sq_update: return 0; } +int +roc_nix_tm_node_suspend_resume(struct roc_nix *roc_nix, uint32_t node_id, + bool suspend) +{ + struct nix *nix = roc_nix_to_nix_priv(roc_nix); + struct mbox *mbox = (&nix->dev)->mbox; + struct nix_txschq_config *req; + struct nix_tm_node *node; + uint16_t flags; + int rc; + + node = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER); + if (!node) + return NIX_ERR_TM_INVALID_NODE; + + flags = node->flags; + flags = suspend ? (flags & ~NIX_TM_NODE_ENABLED) : + (flags | NIX_TM_NODE_ENABLED); + + if (node->flags == flags) + return 0; + + /* send mbox for state change */ + req = mbox_alloc_msg_nix_txschq_cfg(mbox); + + req->lvl = node->hw_lvl; + req->num_regs = + nix_tm_sw_xoff_prep(node, suspend, req->reg, req->regval); + rc = mbox_process(mbox); + if (!rc) + node->flags = flags; + return rc; +} + +int +roc_nix_tm_node_shaper_update(struct roc_nix *roc_nix, uint32_t node_id, + uint32_t profile_id, bool force_update) +{ + struct nix *nix = roc_nix_to_nix_priv(roc_nix); + struct nix_tm_shaper_profile *profile = NULL; + struct mbox *mbox = (&nix->dev)->mbox; + struct nix_txschq_config *req; + struct nix_tm_node *node; + uint8_t k; + int rc; + + /* Shaper updates valid only for user nodes */ + node = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER); + if (!node || nix_tm_is_leaf(nix, node->lvl)) + return NIX_ERR_TM_INVALID_NODE; + + if (profile_id != ROC_NIX_TM_SHAPER_PROFILE_NONE) { + profile = nix_tm_shaper_profile_search(nix, profile_id); + if (!profile) + return NIX_ERR_TM_INVALID_SHAPER_PROFILE; + } + + /* Pkt mode should match existing node's pkt mode */ + if (profile && profile->pkt_mode != node->pkt_mode) + return NIX_ERR_TM_PKT_MODE_MISMATCH; + + if ((profile_id == node->shaper_profile_id) && !force_update) { + return 0; + } else if (profile_id != node->shaper_profile_id) { + struct nix_tm_shaper_profile *old; + + /* Find old shaper profile and reduce ref count */ + old = nix_tm_shaper_profile_search(nix, + node->shaper_profile_id); + if (old) + old->ref_cnt--; + + if (profile) + profile->ref_cnt++; + + /* Reduce older shaper ref count and increase new one */ + node->shaper_profile_id = profile_id; + } + + /* Nothing to do if hierarchy not yet enabled */ + if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA)) + return 0; + + node->flags &= ~NIX_TM_NODE_ENABLED; + + /* Flush the specific node with SW_XOFF */ + req = mbox_alloc_msg_nix_txschq_cfg(mbox); + req->lvl = node->hw_lvl; + k = nix_tm_sw_xoff_prep(node, true, req->reg, req->regval); + req->num_regs = k; + + rc = mbox_process(mbox); + if (rc) + return rc; + + /* Update the PIR/CIR and clear SW XOFF */ + req = mbox_alloc_msg_nix_txschq_cfg(mbox); + req->lvl = node->hw_lvl; + + k = nix_tm_shaper_reg_prep(node, profile, req->reg, req->regval); + + k += nix_tm_sw_xoff_prep(node, false, &req->reg[k], &req->regval[k]); + + req->num_regs = k; + rc = mbox_process(mbox); + if (!rc) + node->flags |= NIX_TM_NODE_ENABLED; + return rc; +} + +int +roc_nix_tm_node_parent_update(struct roc_nix *roc_nix, uint32_t node_id, + uint32_t new_parent_id, uint32_t priority, + uint32_t weight) +{ + struct nix *nix = roc_nix_to_nix_priv(roc_nix); + struct mbox *mbox = (&nix->dev)->mbox; + struct nix_tm_node *node, *sibling; + struct nix_tm_node *new_parent; + struct nix_txschq_config *req; + struct nix_tm_node_list *list; + uint8_t k; + int rc; + + node = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER); + if (!node) + return NIX_ERR_TM_INVALID_NODE; + + /* Parent id valid only for non root nodes */ + if (node->hw_lvl != nix->tm_root_lvl) { + new_parent = + nix_tm_node_search(nix, new_parent_id, ROC_NIX_TM_USER); + if (!new_parent) + return NIX_ERR_TM_INVALID_PARENT; + + /* Current support is only for dynamic weight update */ + if (node->parent != new_parent || node->priority != priority) + return NIX_ERR_TM_PARENT_PRIO_UPDATE; + } + + list = nix_tm_node_list(nix, ROC_NIX_TM_USER); + /* Skip if no change */ + if (node->weight == weight) + return 0; + + node->weight = weight; + + /* Nothing to do if hierarchy not yet enabled */ + if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA)) + return 0; + + /* For leaf nodes, SQ CTX needs update */ + if (nix_tm_is_leaf(nix, node->lvl)) { + /* Update SQ quantum data on the fly */ + rc = nix_tm_sq_sched_conf(nix, node, true); + if (rc) + return NIX_ERR_TM_SQ_UPDATE_FAIL; + } else { + /* XOFF Parent node */ + req = mbox_alloc_msg_nix_txschq_cfg(mbox); + req->lvl = node->parent->hw_lvl; + req->num_regs = nix_tm_sw_xoff_prep(node->parent, true, + req->reg, req->regval); + rc = mbox_process(mbox); + if (rc) + return rc; + + /* XOFF this node and all other siblings */ + req = mbox_alloc_msg_nix_txschq_cfg(mbox); + req->lvl = node->hw_lvl; + + k = 0; + TAILQ_FOREACH(sibling, list, node) { + if (sibling->parent != node->parent) + continue; + k += nix_tm_sw_xoff_prep(sibling, true, &req->reg[k], + &req->regval[k]); + } + req->num_regs = k; + rc = mbox_process(mbox); + if (rc) + return rc; + + /* Update new weight for current node */ + req = mbox_alloc_msg_nix_txschq_cfg(mbox); + req->lvl = node->hw_lvl; + req->num_regs = + nix_tm_sched_reg_prep(nix, node, req->reg, req->regval); + rc = mbox_process(mbox); + if (rc) + return rc; + + /* XON this node and all other siblings */ + req = mbox_alloc_msg_nix_txschq_cfg(mbox); + req->lvl = node->hw_lvl; + + k = 0; + TAILQ_FOREACH(sibling, list, node) { + if (sibling->parent != node->parent) + continue; + k += nix_tm_sw_xoff_prep(sibling, false, &req->reg[k], + &req->regval[k]); + } + req->num_regs = k; + rc = mbox_process(mbox); + if (rc) + return rc; + + /* XON Parent node */ + req = mbox_alloc_msg_nix_txschq_cfg(mbox); + req->lvl = node->parent->hw_lvl; + req->num_regs = nix_tm_sw_xoff_prep(node->parent, false, + req->reg, req->regval); + rc = mbox_process(mbox); + if (rc) + return rc; + } + return 0; +} + int roc_nix_tm_init(struct roc_nix *roc_nix) { diff --git a/drivers/common/cnxk/version.map b/drivers/common/cnxk/version.map index cb3ddb28a3..a5eb17e259 100644 --- a/drivers/common/cnxk/version.map +++ b/drivers/common/cnxk/version.map @@ -115,7 +115,10 @@ INTERNAL { roc_nix_tm_node_lvl; roc_nix_tm_node_name_get; roc_nix_tm_node_next; + roc_nix_tm_node_parent_update; roc_nix_tm_node_pkt_mode_update; + roc_nix_tm_node_shaper_update; + roc_nix_tm_node_suspend_resume; roc_nix_tm_rlimit_sq; roc_nix_tm_shaper_profile_add; roc_nix_tm_shaper_profile_delete; -- 2.20.1