From c2460d14293919df3e5948e899e25b55e75a48fe Mon Sep 17 00:00:00 2001 From: Satha Rao Date: Tue, 6 Apr 2021 20:11:26 +0530 Subject: [PATCH] common/cnxk: support NIX TM shaper profile 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 Signed-off-by: Satha Rao --- 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 --git a/drivers/common/cnxk/roc_nix.h b/drivers/common/cnxk/roc_nix.h index d656909114..ea34cd2e63 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 cee73ae1e5..cd1eaa5123 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 f103e02741..d2e22505b2 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 d0941c0635..896ddf24d3 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 bea23be805..7a7e786eea 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 2bc50bf2aa..5bf87179d9 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; -- 2.20.1