/*
* 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);
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 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);
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.
return rc;
}
+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)
{
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, ®[k], ®val[k]);
+ flags &= ~NIX_TM_NODE_ENABLED;
+ goto exit;
+ }
+
+ if (!(flags & NIX_TM_NODE_ENABLED)) {
+ k += nix_tm_sw_xoff_prep(parent, false, ®[k], ®val[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, ®[k], ®val[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;
+}
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;
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;