common/cnxk: support NIX TM shaper profile
authorSatha Rao <skoteshwar@marvell.com>
Tue, 6 Apr 2021 14:41:26 +0000 (20:11 +0530)
committerJerin Jacob <jerinj@marvell.com>
Fri, 9 Apr 2021 06:32:24 +0000 (08:32 +0200)
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
drivers/common/cnxk/roc_nix_priv.h
drivers/common/cnxk/roc_nix_tm.c
drivers/common/cnxk/roc_nix_tm_ops.c
drivers/common/cnxk/roc_nix_tm_utils.c
drivers/common/cnxk/version.map

index d656909..ea34cd2 100644 (file)
@@ -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.
index cee73ae..cd1eaa5 100644 (file)
@@ -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_ */
index f103e02..d2e2250 100644 (file)
@@ -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++)
index d0941c0..896ddf2 100644 (file)
@@ -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)
 {
index bea23be..7a7e786 100644 (file)
@@ -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);
+}
index 2bc50bf..5bf8717 100644 (file)
@@ -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;