]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
octeontx2-af: npc: cn20k: add subbank search order control
authorRatheesh Kannoth <rkannoth@marvell.com>
Tue, 9 Jun 2026 04:04:49 +0000 (09:34 +0530)
committerJakub Kicinski <kuba@kernel.org>
Sat, 13 Jun 2026 23:16:59 +0000 (16:16 -0700)
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 <rkannoth@marvell.com>
Link: https://patch.msgid.link/20260609040453.711932-6-rkannoth@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c

index 4f9babde3037de76ede0d3f933b33ec46eb7cf9e..f9b718efb04d9bead880b8654279214eca0a70a0 100644 (file)
@@ -3372,7 +3372,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)
 {
@@ -3384,7 +3384,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;
@@ -3902,6 +3902,122 @@ 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;
+       int rsrc[2][MAX_NUM_SUB_BANKS] = { };
+       u8 save[MAX_NUM_SUB_BANKS] = { };
+       struct npc_subbank *sb;
+       struct xarray *xa;
+       int prio, rc, err;
+       int sb_idx;
+       enum {
+               FREE = 0,
+               USED = 1,
+       };
+
+       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();
+
+       for (sb_idx = 0; sb_idx < cnt; sb_idx++) {
+               sb = &npc_priv.sb[sb_idx];
+               save[sb->idx] = sb->arr_idx;
+       }
+
+       for (prio = 0; prio < cnt; prio++) {
+               sb_idx = narr[prio];
+               sb = &npc_priv.sb[sb_idx];
+
+               if (sb->flags & NPC_SUBBANK_FLAG_USED)
+                       xa = &npc_priv.xa_sb_used;
+               else
+                       xa = &npc_priv.xa_sb_free;
+
+               rc = xa_err(xa_store(xa, prio,
+                                    xa_mk_value(sb_idx), GFP_KERNEL));
+               if (rc) {
+                       dev_err(rvu->dev,
+                               "Setting arr_idx=%d for sb=%d failed\n",
+                               sb->arr_idx, sb_idx);
+                       goto fail;
+               }
+
+               if (sb->flags & NPC_SUBBANK_FLAG_USED) {
+                       rsrc[USED][sb->arr_idx] -= 1;
+                       rsrc[USED][prio] += 1;
+               } else {
+                       rsrc[FREE][sb->arr_idx] -= 1;
+                       rsrc[FREE][prio] += 1;
+               }
+
+               sb->arr_idx = prio;
+       }
+
+       for (prio = 0; prio < cnt; prio++) {
+               if (rsrc[FREE][prio] == -1)
+                       xa_erase(&npc_priv.xa_sb_free, prio);
+
+               if (rsrc[USED][prio] == -1)
+                       xa_erase(&npc_priv.xa_sb_used, prio);
+       }
+
+       for (int i = 0; i < cnt; i++)
+               subbank_srch_order[i] = (u32)narr[i];
+
+       restrict_valid = false;
+
+       npc_unlock_all_subbank();
+       mutex_unlock(&mcam->lock);
+
+       return 0;
+
+fail:
+       for (prio = 0; prio < cnt; prio++) {
+               if (rsrc[FREE][prio] == 1)
+                       xa_erase(&npc_priv.xa_sb_free, prio);
+
+               if (rsrc[USED][prio] == 1)
+                       xa_erase(&npc_priv.xa_sb_used, prio);
+       }
+
+       for (sb_idx = 0; sb_idx < cnt; sb_idx++) {
+               sb = &npc_priv.sb[sb_idx];
+               sb->arr_idx = save[sb_idx];
+
+               if (sb->flags & NPC_SUBBANK_FLAG_USED)
+                       xa = &npc_priv.xa_sb_used;
+               else
+                       xa = &npc_priv.xa_sb_free;
+
+               /* Since the entry already exists, xa_store() replaces
+                * the value without a kmalloc(), making failure highly unlikely.
+                */
+               err = xa_err(xa_store(xa, sb->arr_idx,
+                                     xa_mk_value(sb->idx), GFP_KERNEL));
+               WARN(!!err, "Failed to rollback sb=%u idx=%u\n",
+                    sb->idx, sb->arr_idx);
+       }
+
+       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
  */
index 3e851950be64a7d4fb361dce0629f6f9976154c6..8bf857317e498253c192dba610099188189e6b0d 100644 (file)
@@ -347,5 +347,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 */
index a42404e6db7cc26df7c6726a892dfdecc7018fce..aa3ecab5ebd881b6f0359baf82178e6a45fbb857 100644 (file)
@@ -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 @@ done:
 
 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))