CN20K NPC MCAM is split into 32 subbanks that are searched in a
predefined order during allocation. Lower-numbered subbanks have
higher priority than higher-numbered ones.

Add a runtime "srch_order" to control the order in which
subbanks are searched during MCAM allocation.

Signed-off-by: Ratheesh Kannoth <[email protected]>
---
 .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 54 ++++++++++-
 .../ethernet/marvell/octeontx2/af/cn20k/npc.h |  3 +
 .../marvell/octeontx2/af/rvu_devlink.c        | 92 +++++++++++++++++--
 3 files changed, 137 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c 
b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index e9aad0ad3fa6..6f8f42234b06 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -3376,7 +3376,7 @@ rvu_mbox_handler_npc_cn20k_get_kex_cfg(struct rvu *rvu,
        return 0;
 }
 
-static int *subbank_srch_order;
+static u32 *subbank_srch_order;
 
 static void npc_populate_restricted_idxs(int num_subbanks)
 {
@@ -3388,7 +3388,7 @@ static int npc_create_srch_order(int cnt)
 {
        int val = 0;
 
-       subbank_srch_order = kcalloc(cnt, sizeof(int),
+       subbank_srch_order = kcalloc(cnt, sizeof(u32),
                                     GFP_KERNEL);
        if (!subbank_srch_order)
                return -ENOMEM;
@@ -3906,6 +3906,56 @@ static void npc_unlock_all_subbank(void)
                mutex_unlock(&npc_priv.sb[i].lock);
 }
 
+int npc_cn20k_search_order_set(struct rvu *rvu,
+                              u64 narr[MAX_NUM_SUB_BANKS], int cnt)
+{
+       struct npc_mcam *mcam = &rvu->hw->mcam;
+       struct npc_subbank *sb;
+       struct xarray *xa;
+       int sb_idx, rc;
+
+       if (cnt != npc_priv.num_subbanks) {
+               dev_err(rvu->dev, "Number of entries(%u) != %u\n",
+                       cnt, npc_priv.num_subbanks);
+               return -EINVAL;
+       }
+
+       mutex_lock(&mcam->lock);
+       npc_lock_all_subbank();
+       restrict_valid = false;
+
+       for (sb_idx = 0; sb_idx < cnt; sb_idx++) {
+               sb = &npc_priv.sb[sb_idx];
+
+               xa = &npc_priv.xa_sb_free;
+               if (sb->flags & NPC_SUBBANK_FLAG_USED)
+                       xa = &npc_priv.xa_sb_used;
+
+               sb->arr_idx = narr[sb_idx];
+
+               rc = xa_err(xa_store(xa, sb->arr_idx,
+                                    xa_mk_value(sb_idx), GFP_KERNEL));
+               if (rc)
+                       goto fail;
+       }
+
+       for (int i = 0; i < cnt; i++)
+               subbank_srch_order[i] = (u32)narr[i];
+
+fail:
+       npc_unlock_all_subbank();
+       mutex_unlock(&mcam->lock);
+
+       return rc;
+}
+
+const u32 *npc_cn20k_search_order_get(bool *restricted_order, u32 *sz)
+{
+       *restricted_order = restrict_valid;
+       *sz = npc_priv.num_subbanks;
+       return subbank_srch_order;
+}
+
 /* Only non-ref non-contigous mcam indexes
  * are picked for defrag process
  */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h 
b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 9567a2d80b58..bf030e40fbf9 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -343,5 +343,8 @@ bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc);
 int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
                               struct npc_subbank **sb,
                               int *sb_off);
+const u32 *npc_cn20k_search_order_get(bool *restricted_order, u32 *sz);
+int npc_cn20k_search_order_set(struct rvu *rvu, u64 narr[MAX_NUM_SUB_BANKS],
+                              int cnt);
 
 #endif /* NPC_CN20K_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c 
b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
index a42404e6db7c..aa3ecab5ebd8 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
@@ -1258,6 +1258,7 @@ enum rvu_af_dl_param_id {
        RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE,
        RVU_AF_DEVLINK_PARAM_ID_NPC_DEF_RULE_CNTR_ENABLE,
        RVU_AF_DEVLINK_PARAM_ID_NPC_DEFRAG,
+       RVU_AF_DEVLINK_PARAM_ID_NPC_SRCH_ORDER,
        RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF,
 };
 
@@ -1619,12 +1620,83 @@ static int rvu_devlink_eswitch_mode_set(struct devlink 
*devlink, u16 mode,
        return 0;
 }
 
+static int rvu_af_dl_npc_srch_order_set(struct devlink *devlink, u32 id,
+                                       struct devlink_param_gset_ctx *ctx,
+                                       struct netlink_ext_ack *extack)
+{
+       struct rvu_devlink *rvu_dl = devlink_priv(devlink);
+       struct rvu *rvu = rvu_dl->rvu;
+
+       return npc_cn20k_search_order_set(rvu,
+                                         ctx->val.u64arr.val,
+                                         ctx->val.u64arr.size);
+}
+
+static int rvu_af_dl_npc_srch_order_get(struct devlink *devlink, u32 id,
+                                       struct devlink_param_gset_ctx *ctx,
+                                       struct netlink_ext_ack *extack)
+{
+       bool restricted_order;
+       const u32 *order;
+       u32 sz;
+
+       order = npc_cn20k_search_order_get(&restricted_order, &sz);
+       ctx->val.u64arr.size = sz;
+       for (int i = 0; i < sz; i++)
+               ctx->val.u64arr.val[i] = order[i];
+
+       return 0;
+}
+
+static int rvu_af_dl_npc_srch_order_validate(struct devlink *devlink, u32 id,
+                                            union devlink_param_value *val,
+                                            struct netlink_ext_ack *extack)
+{
+       struct rvu_devlink *rvu_dl = devlink_priv(devlink);
+       struct rvu *rvu = rvu_dl->rvu;
+       bool restricted_order;
+       unsigned long w = 0;
+       u64 *arr;
+       u32 sz;
+
+       npc_cn20k_search_order_get(&restricted_order, &sz);
+       if (sz != val->u64arr.size) {
+               dev_err(rvu->dev,
+                       "Wrong size %llu, should be %u\n",
+                       val->u64arr.size, sz);
+               return -EINVAL;
+       }
+
+       arr = val->u64arr.val;
+       for (int i = 0; i < sz; i++) {
+               if (arr[i] >= sz)
+                       return -EINVAL;
+
+               w |= BIT_ULL(arr[i]);
+       }
+
+       if (bitmap_weight(&w, sz) != sz) {
+               dev_err(rvu->dev,
+                       "Duplicate or out-of-range subbank index. %lu\n",
+                       find_first_zero_bit(&w, sz));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct devlink_ops rvu_devlink_ops = {
        .eswitch_mode_get = rvu_devlink_eswitch_mode_get,
        .eswitch_mode_set = rvu_devlink_eswitch_mode_set,
 };
 
-static const struct devlink_param rvu_af_dl_param_defrag[] = {
+static const struct devlink_param rvu_af_dl_cn20k_params[] = {
+       DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_SRCH_ORDER,
+                            "npc_srch_order", DEVLINK_PARAM_TYPE_U64_ARRAY,
+                            BIT(DEVLINK_PARAM_CMODE_RUNTIME),
+                            rvu_af_dl_npc_srch_order_get,
+                            rvu_af_dl_npc_srch_order_set,
+                            rvu_af_dl_npc_srch_order_validate),
        DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_DEFRAG,
                             "npc_defrag", DEVLINK_PARAM_TYPE_STRING,
                             BIT(DEVLINK_PARAM_CMODE_RUNTIME),
@@ -1666,13 +1738,13 @@ int rvu_register_dl(struct rvu *rvu)
        }
 
        if (is_cn20k(rvu->pdev)) {
-               err = devlink_params_register(dl, rvu_af_dl_param_defrag,
-                                             
ARRAY_SIZE(rvu_af_dl_param_defrag));
+               err = devlink_params_register(dl, rvu_af_dl_cn20k_params,
+                                             
ARRAY_SIZE(rvu_af_dl_cn20k_params));
                if (err) {
                        dev_err(rvu->dev,
-                               "devlink defrag params register failed with 
error %d",
+                               "devlink cn20k params register failed with 
error %d",
                                err);
-                       goto err_dl_defrag;
+                       goto err_dl_cn20k_params;
                }
        }
 
@@ -1695,10 +1767,10 @@ int rvu_register_dl(struct rvu *rvu)
 
 err_dl_exact_match:
        if (is_cn20k(rvu->pdev))
-               devlink_params_unregister(dl, rvu_af_dl_param_defrag,
-                                         ARRAY_SIZE(rvu_af_dl_param_defrag));
+               devlink_params_unregister(dl, rvu_af_dl_cn20k_params,
+                                         ARRAY_SIZE(rvu_af_dl_cn20k_params));
 
-err_dl_defrag:
+err_dl_cn20k_params:
        devlink_params_unregister(dl, rvu_af_dl_params, 
ARRAY_SIZE(rvu_af_dl_params));
 
 err_dl_health:
@@ -1717,8 +1789,8 @@ void rvu_unregister_dl(struct rvu *rvu)
        devlink_params_unregister(dl, rvu_af_dl_params, 
ARRAY_SIZE(rvu_af_dl_params));
 
        if (is_cn20k(rvu->pdev))
-               devlink_params_unregister(dl, rvu_af_dl_param_defrag,
-                                         ARRAY_SIZE(rvu_af_dl_param_defrag));
+               devlink_params_unregister(dl, rvu_af_dl_cn20k_params,
+                                         ARRAY_SIZE(rvu_af_dl_cn20k_params));
 
        /* Unregister exact match devlink only for CN10K-B */
        if (rvu_npc_exact_has_match_table(rvu))
-- 
2.43.0

Reply via email to