octeontx2-af: npc: cn20k: add subbank search order control

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>
This commit is contained in:
Ratheesh Kannoth 2026-06-09 09:34:49 +05:30 committed by Jakub Kicinski
parent eb7b4d458e
commit 7ac9d4c407
3 changed files with 203 additions and 12 deletions

View 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
*/

View 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 */

View 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 @@ 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))