From: Simon Horman <horms@kernel.org>
To: Ratheesh Kannoth <rkannoth@marvell.com>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
sgoutham@marvell.com, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, andrew+netdev@lunn.ch,
sumang@marvell.com
Subject: Re: [PATCH net-next 01/13] octeontx2-af: npc: cn20k: Index management
Date: Thu, 8 Jan 2026 17:53:57 +0000 [thread overview]
Message-ID: <20260108175357.GJ345651@kernel.org> (raw)
In-Reply-To: <20260105023254.1426488-2-rkannoth@marvell.com>
On Mon, Jan 05, 2026 at 08:02:42AM +0530, Ratheesh Kannoth wrote:
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
> index 498968bf4cf5..c7c59a98d969 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
> @@ -11,7 +11,189 @@
> #include <linux/pci.h>
>
> #include "struct.h"
> +#include "rvu.h"
> #include "debugfs.h"
> +#include "cn20k/npc.h"
> +
> +static void npc_subbank_srch_order_dbgfs_usage(void)
> +{
> + pr_err("Usage: echo \"[0]=[8],[1]=7,[2]=30,...[31]=0\" > <debugfs>/subbank_srch_order\n");
> +}
> +
> +static int
> +npc_subbank_srch_order_parse_n_fill(struct rvu *rvu, char *options,
> + int num_subbanks)
> +{
> + unsigned long w1 = 0, w2 = 0;
> + char *p, *t1, *t2;
> + int (*arr)[2];
> + int idx, val;
> + int cnt, ret;
> +
> + cnt = 0;
> +
> + options[strcspn(options, "\r\n")] = 0;
> +
> + arr = kcalloc(num_subbanks, sizeof(*arr), GFP_KERNEL);
> + if (!arr)
> + return -ENOMEM;
> +
> + while ((p = strsep(&options, " ,")) != NULL) {
> + if (!*p)
> + continue;
> +
> + t1 = strsep(&p, "=");
> + t2 = strsep(&p, "");
> +
> + if (strlen(t1) < 3) {
> + pr_err("%s:%d Bad Token %s=%s\n",
> + __func__, __LINE__, t1, t2);
> + goto err;
> + }
> +
> + if (t1[0] != '[' || t1[strlen(t1) - 1] != ']') {
> + pr_err("%s:%d Bad Token %s=%s\n",
> + __func__, __LINE__, t1, t2);
Hi Ratheesh,
FWIIW, I would advocate slightly more descriptive and thus unique
error messages and dropping __func__ and __LINE__ from logs,
here and elsewhere.
The __func__, and in particular __LINE__ information will only
tend to change as the file is up dated, and so any debugging will
need to know the source that the kernel was compiled from.
And I'd say that given the state of debugging functionality in the kernel -
e..g dynamic tracepoints - this is not as useful as it may seem at first.
...
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
...
> +static int npc_multi_subbank_ref_alloc(struct rvu *rvu, int key_type,
> + int ref, int limit, int prio,
> + bool contig, int count,
> + u16 *mcam_idx)
> +{
> + struct npc_subbank *sb;
> + unsigned long *bmap;
> + int sb_off, off, rc;
> + int cnt = 0;
> + bool bitset;
> +
> + if (prio != NPC_MCAM_HIGHER_PRIO) {
> + while (ref <= limit) {
> + /* Calculate subbank and subbank index */
> + rc = npc_mcam_idx_2_subbank_idx(rvu, ref,
> + &sb, &sb_off);
> + if (rc)
> + goto err;
> +
> + /* If subbank is not suitable for requested key type
> + * restart search from next subbank
> + */
> + if (!npc_subbank_suits(sb, key_type)) {
> + ref = SB_ALIGN_UP(ref);
> + if (contig) {
> + rc = npc_idx_free(rvu, mcam_idx,
> + cnt, false);
> + if (rc)
> + return rc;
> + cnt = 0;
> + }
> + continue;
> + }
> +
> + mutex_lock(&sb->lock);
> +
> + /* If subbank is free; mark it as used */
> + if (sb->flags & NPC_SUBBANK_FLAG_FREE) {
> + rc = __npc_subbank_mark_used(rvu, sb,
> + key_type);
> + if (rc) {
> + mutex_unlock(&sb->lock);
> + dev_err(rvu->dev,
> + "%s:%d Error to add to use array\n",
> + __func__, __LINE__);
> + goto err;
> + }
> + }
> +
> + /* Find correct bmap */
> + __npc_subbank_sboff_2_off(rvu, sb, sb_off, &bmap, &off);
> +
> + /* if bit is already set, reset 'cnt' */
> + bitset = test_bit(off, bmap);
> + if (bitset) {
> + mutex_unlock(&sb->lock);
> + if (contig) {
> + rc = npc_idx_free(rvu, mcam_idx,
> + cnt, false);
> + if (rc)
> + return rc;
> + cnt = 0;
> + }
> +
> + ref++;
> + continue;
> + }
> +
> + set_bit(off, bmap);
> + sb->free_cnt--;
> + mcam_idx[cnt++] = ref;
> + mutex_unlock(&sb->lock);
> +
> + if (cnt == count)
> + return 0;
> + ref++;
> + }
> +
> + /* Could not allocate request count slots */
> + goto err;
> + }
> + while (ref >= limit) {
> + rc = npc_mcam_idx_2_subbank_idx(rvu, ref,
> + &sb, &sb_off);
> + if (rc)
> + goto err;
> +
> + if (!npc_subbank_suits(sb, key_type)) {
> + ref = SB_ALIGN_DOWN(ref) - 1;
> + if (contig) {
> + rc = npc_idx_free(rvu, mcam_idx, cnt, false);
> + if (rc)
> + return rc;
> +
> + cnt = 0;
> + }
> + continue;
> + }
> +
> + mutex_lock(&sb->lock);
> +
> + if (sb->flags & NPC_SUBBANK_FLAG_FREE) {
> + rc = __npc_subbank_mark_used(rvu, sb, key_type);
> + if (rc) {
> + mutex_unlock(&sb->lock);
> + dev_err(rvu->dev,
> + "%s:%d Error to add to use array\n",
> + __func__, __LINE__);
> + goto err;
> + }
> + }
> +
> + __npc_subbank_sboff_2_off(rvu, sb, sb_off, &bmap, &off);
> + bitset = test_bit(off, bmap);
> + if (bitset) {
> + mutex_unlock(&sb->lock);
> + if (contig) {
> + cnt = 0;
> + rc = npc_idx_free(rvu, mcam_idx, cnt, false);
> + if (rc)
> + return rc;
Claude Code with Review Prompts [1] flags that the call to npc_idx_free()
is a noop because count is reset to 0 before (rather than after) it is
called.
> + }
> + ref--;
> + continue;
> + }
> +
> + mcam_idx[cnt++] = ref;
> + sb->free_cnt--;
> + set_bit(off, bmap);
> + mutex_unlock(&sb->lock);
> +
> + if (cnt == count)
> + return 0;
> + ref--;
> + }
> +
> +err:
> + rc = npc_idx_free(rvu, mcam_idx, cnt, false);
> + if (rc)
> + dev_err(rvu->dev,
> + "%s:%d Error happened while freeing cnt=%u indexes\n",
> + __func__, __LINE__, cnt);
> +
> + return -ENOSPC;
> +}
> +
> +static int npc_subbank_free_cnt(struct rvu *rvu, struct npc_subbank *sb,
> + int key_type)
> +{
> + int cnt, spd;
> +
> + spd = npc_priv.subbank_depth;
> + mutex_lock(&sb->lock);
> +
> + if (sb->flags & NPC_SUBBANK_FLAG_FREE)
> + cnt = key_type == NPC_MCAM_KEY_X4 ? spd : 2 * spd;
> + else
> + cnt = sb->free_cnt;
> +
> + mutex_unlock(&sb->lock);
> + return cnt;
> +}
> +
> +static int npc_subbank_ref_alloc(struct rvu *rvu, int key_type,
> + int ref, int limit, int prio,
> + bool contig, int count,
> + u16 *mcam_idx)
> +{
> + struct npc_subbank *sb1, *sb2;
> + bool max_alloc, start, stop;
> + int r, l, sb_idx1, sb_idx2;
> + int tot = 0, rc;
> + int alloc_cnt;
> +
> + max_alloc = !contig;
> +
> + start = true;
> + stop = false;
> +
> + /* Loop until we cross the ref/limit boundary */
> + while (!stop) {
> + rc = npc_subbank_iter(rvu, key_type, ref, limit, prio,
> + &r, &l, &start, &stop);
> +
> + dev_dbg(rvu->dev,
> + "%s:%d ref=%d limit=%d r=%d l=%d start=%d stop=%d tot=%d count=%d rc=%d\n",
> + __func__, __LINE__, ref, limit, r, l,
> + start, stop, tot, count, rc);
> +
> + if (rc)
> + goto err;
> +
> + /* Find subbank and subbank index for ref */
> + rc = npc_mcam_idx_2_subbank_idx(rvu, r, &sb1,
> + &sb_idx1);
> + if (rc)
> + goto err;
> +
> + dev_dbg(rvu->dev,
> + "%s:%d ref subbank=%d off=%d\n",
> + __func__, __LINE__, sb1->idx, sb_idx1);
> +
> + /* Skip subbank if it is not available for the keytype */
> + if (!npc_subbank_suits(sb1, key_type)) {
> + dev_dbg(rvu->dev,
> + "%s:%d not suitable sb=%d key_type=%d\n",
> + __func__, __LINE__, sb1->idx, key_type);
> + continue;
> + }
> +
> + /* Find subbank and subbank index for limit */
> + rc = npc_mcam_idx_2_subbank_idx(rvu, l, &sb2,
> + &sb_idx2);
> + if (rc)
> + goto err;
> +
> + dev_dbg(rvu->dev,
> + "%s:%d limit subbank=%d off=%d\n",
> + __func__, __LINE__, sb_idx1, sb_idx2);
> +
> + /* subbank of ref and limit should be same */
> + if (sb1 != sb2) {
> + dev_err(rvu->dev,
> + "%s:%d l(%d) and r(%d) are not in same subbank\n",
> + __func__, __LINE__, r, l);
> + goto err;
> + }
> +
> + if (contig &&
> + npc_subbank_free_cnt(rvu, sb1, key_type) < count) {
> + dev_dbg(rvu->dev, "%s:%d less count =%d\n",
> + __func__, __LINE__,
> + npc_subbank_free_cnt(rvu, sb1, key_type));
> + continue;
> + }
> +
> + /* Try in one bank of a subbank */
> + alloc_cnt = 0;
> + rc = npc_subbank_alloc(rvu, sb1, key_type,
> + r, l, prio, contig,
> + count - tot, mcam_idx + tot,
> + count - tot, max_alloc,
> + &alloc_cnt);
> +
> + tot += alloc_cnt;
> +
> + dev_dbg(rvu->dev, "%s:%d Allocated tot=%d alloc_cnt=%d\n",
> + __func__, __LINE__, tot, alloc_cnt);
> +
> + if (!rc && count == tot)
> + return 0;
> + }
> +err:
> + dev_dbg(rvu->dev, "%s:%d Error to allocate\n",
> + __func__, __LINE__);
> +
> + /* non contiguous allocation fails. We need to do clean up */
> + if (max_alloc) {
> + rc = npc_idx_free(rvu, mcam_idx, tot, false);
> + if (rc)
> + dev_err(rvu->dev,
> + "%s:%d failed to free %u indexes\n",
> + __func__, __LINE__, tot);
> + }
> +
> + return -EFAULT;
> +}
> +
> +/* Minimize allocation from bottom and top subbanks for noref allocations.
> + * Default allocations are ref based, and will be allocated from top
> + * subbanks (least priority subbanks). Since default allocation is at very
> + * early stage of kernel netdev probes, this subbanks will be moved to
> + * used subbanks list. This will pave a way for noref allocation from these
> + * used subbanks. Skip allocation for these top and bottom, and try free
> + * bank next. If none slot is available, come back and search in these
> + * subbanks.
> + */
> +
> +static int npc_subbank_restricted_idxs[2];
> +static bool restrict_valid = true;
> +
> +static bool npc_subbank_restrict_usage(struct rvu *rvu, int index)
> +{
> + int i;
> +
> + if (!restrict_valid)
> + return false;
> +
> + for (i = 0; i < ARRAY_SIZE(npc_subbank_restricted_idxs); i++) {
> + if (index == npc_subbank_restricted_idxs[i])
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static int npc_subbank_noref_alloc(struct rvu *rvu, int key_type, bool contig,
> + int count, u16 *mcam_idx)
> +{
> + struct npc_subbank *sb;
> + unsigned long index;
> + int tot = 0, rc;
> + bool max_alloc;
> + int alloc_cnt;
> + int idx, i;
> + void *val;
> +
> + max_alloc = !contig;
> +
> + /* Check used subbanks for free slots */
> + xa_for_each(&npc_priv.xa_sb_used, index, val) {
> + idx = xa_to_value(val);
> +
> + /* Minimize allocation from restricted subbanks
> + * in noref allocations.
> + */
> + if (npc_subbank_restrict_usage(rvu, idx))
> + continue;
> +
> + sb = &npc_priv.sb[idx];
> +
> + /* Skip if not suitable subbank */
> + if (!npc_subbank_suits(sb, key_type))
> + continue;
> +
> + if (contig && npc_subbank_free_cnt(rvu, sb, key_type) < count)
> + continue;
> +
> + /* try in bank 0. Try passing ref and limit equal to
> + * subbank boundaries
> + */
> + alloc_cnt = 0;
> + rc = npc_subbank_alloc(rvu, sb, key_type,
> + sb->b0b, sb->b0t, 0,
> + contig, count - tot,
> + mcam_idx + tot,
> + count - tot,
> + max_alloc, &alloc_cnt);
> +
> + /* Non contiguous allocation may allocate less than
> + * requested 'count'.
> + */
> + tot += alloc_cnt;
> +
> + dev_dbg(rvu->dev,
> + "%s:%d Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, __LINE__, alloc_cnt, sb->idx, tot, count);
> +
> + /* Successfully allocated */
> + if (!rc && count == tot)
> + return 0;
> +
> + /* x4 entries can be allocated from bank 0 only */
> + if (key_type == NPC_MCAM_KEY_X4)
> + continue;
> +
> + /* try in bank 1 for x2 */
> + alloc_cnt = 0;
> + rc = npc_subbank_alloc(rvu, sb, key_type,
> + sb->b1b, sb->b1t, 0,
> + contig, count - tot,
> + mcam_idx + tot,
> + count - tot, max_alloc,
> + &alloc_cnt);
> +
> + tot += alloc_cnt;
> +
> + dev_dbg(rvu->dev,
> + "%s:%d Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, __LINE__, alloc_cnt, sb->idx, tot, count);
> +
> + if (!rc && count == tot)
> + return 0;
> + }
> +
> + /* Allocate in free subbanks */
> + xa_for_each(&npc_priv.xa_sb_free, index, val) {
> + idx = xa_to_value(val);
> + sb = &npc_priv.sb[idx];
> +
> + /* Minimize allocation from restricted subbanks
> + * in noref allocations.
> + */
> + if (npc_subbank_restrict_usage(rvu, idx))
> + continue;
> +
> + if (!npc_subbank_suits(sb, key_type))
> + continue;
> +
> + /* try in bank 0 */
> + alloc_cnt = 0;
> + rc = npc_subbank_alloc(rvu, sb, key_type,
> + sb->b0b, sb->b0t, 0,
> + contig, count - tot,
> + mcam_idx + tot,
> + count - tot,
> + max_alloc, &alloc_cnt);
> +
> + tot += alloc_cnt;
> +
> + dev_dbg(rvu->dev,
> + "%s:%d Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, __LINE__, alloc_cnt, sb->idx, tot, count);
> +
> + /* Successfully allocated */
> + if (!rc && count == tot)
> + return 0;
> +
> + /* x4 entries can be allocated from bank 0 only */
> + if (key_type == NPC_MCAM_KEY_X4)
> + continue;
> +
> + /* try in bank 1 for x2 */
> + alloc_cnt = 0;
> + rc = npc_subbank_alloc(rvu, sb,
> + key_type, sb->b1b, sb->b1t, 0,
> + contig, count - tot,
> + mcam_idx + tot, count - tot,
> + max_alloc, &alloc_cnt);
> +
> + tot += alloc_cnt;
> +
> + dev_dbg(rvu->dev,
> + "%s:%d Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, __LINE__, alloc_cnt, sb->idx, tot, count);
> +
> + if (!rc && count == tot)
> + return 0;
> + }
> +
> + /* Allocate from restricted subbanks */
> + for (i = 0; restrict_valid &&
> + (i < ARRAY_SIZE(npc_subbank_restricted_idxs)); i++) {
> + idx = npc_subbank_restricted_idxs[i];
> + sb = &npc_priv.sb[idx];
> +
> + /* Skip if not suitable subbank */
> + if (!npc_subbank_suits(sb, key_type))
> + continue;
> +
> + if (contig && npc_subbank_free_cnt(rvu, sb, key_type) < count)
> + continue;
> +
> + /* try in bank 0. Try passing ref and limit equal to
> + * subbank boundaries
> + */
> + alloc_cnt = 0;
> + rc = npc_subbank_alloc(rvu, sb, key_type,
> + sb->b0b, sb->b0t, 0,
> + contig, count - tot,
> + mcam_idx + tot,
> + count - tot,
> + max_alloc, &alloc_cnt);
> +
> + /* Non contiguous allocation may allocate less than
> + * requested 'count'.
> + */
> + tot += alloc_cnt;
> +
> + dev_dbg(rvu->dev,
> + "%s:%d Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, __LINE__, alloc_cnt, sb->idx, tot, count);
> +
> + /* Successfully allocated */
> + if (!rc && count == tot)
> + return 0;
> +
> + /* x4 entries can be allocated from bank 0 only */
> + if (key_type == NPC_MCAM_KEY_X4)
> + continue;
> +
> + /* try in bank 1 for x2 */
> + alloc_cnt = 0;
> + rc = npc_subbank_alloc(rvu, sb, key_type,
> + sb->b1b, sb->b1t, 0,
> + contig, count - tot,
> + mcam_idx + tot,
> + count - tot, max_alloc,
> + &alloc_cnt);
> +
> + tot += alloc_cnt;
> +
> + dev_dbg(rvu->dev,
> + "%s:%d Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, __LINE__, alloc_cnt, sb->idx, tot, count);
> +
> + if (!rc && count == tot)
> + return 0;
> + }
> +
> + /* non contiguous allocation fails. We need to do clean up */
> + if (max_alloc)
> + npc_idx_free(rvu, mcam_idx, tot, false);
> +
> + dev_dbg(rvu->dev, "%s:%d non-contig allocation fails\n",
> + __func__, __LINE__);
> +
> + return -EFAULT;
> +}
> +
> +int npc_cn20k_idx_free(struct rvu *rvu, u16 *mcam_idx, int count)
> +{
> + return npc_idx_free(rvu, mcam_idx, count, true);
> +}
> +
> +int npc_cn20k_ref_idx_alloc(struct rvu *rvu, int pcifunc, int key_type,
> + int prio, u16 *mcam_idx, int ref, int limit,
> + bool contig, int count)
> +{
> + int i, eidx, rc, bd;
> + bool ref_valid;
> +
> + bd = npc_priv.bank_depth;
> +
> + /* Special case: ref == 0 && limit= 0 && prio == HIGH && count == 1
> + * Here user wants to allocate 0th entry
> + */
> + if (!ref && !limit && prio == NPC_MCAM_HIGHER_PRIO &&
> + count == 1) {
> + rc = npc_subbank_ref_alloc(rvu, key_type, ref, limit,
> + prio, contig, count, mcam_idx);
> +
> + if (rc)
> + return rc;
> + goto add2map;
> + }
> +
> + ref_valid = !!(limit || ref);
> + if (!ref_valid) {
> + if (contig && count > npc_priv.subbank_depth)
> + goto try_noref_multi_subbank;
> +
> + rc = npc_subbank_noref_alloc(rvu, key_type, contig,
> + count, mcam_idx);
> + if (!rc)
> + goto add2map;
> +
> +try_noref_multi_subbank:
> + eidx = (key_type == NPC_MCAM_KEY_X4) ? bd - 1 : 2 * bd - 1;
> +
> + if (prio == NPC_MCAM_HIGHER_PRIO)
> + rc = npc_multi_subbank_ref_alloc(rvu, key_type,
> + eidx, 0,
> + NPC_MCAM_HIGHER_PRIO,
> + contig, count,
> + mcam_idx);
> + else
> + rc = npc_multi_subbank_ref_alloc(rvu, key_type,
> + 0, eidx,
> + NPC_MCAM_LOWER_PRIO,
> + contig, count,
> + mcam_idx);
> +
> + if (!rc)
> + goto add2map;
> +
> + return rc;
> + }
> +
> + if ((prio == NPC_MCAM_LOWER_PRIO && ref > limit) ||
> + (prio == NPC_MCAM_HIGHER_PRIO && ref < limit)) {
> + dev_err(rvu->dev, "%s:%d Wrong ref_enty(%d) or limit(%d)\n",
> + __func__, __LINE__, ref, limit);
> + return -EINVAL;
> + }
> +
> + if ((key_type == NPC_MCAM_KEY_X4 && (ref >= bd || limit >= bd)) ||
> + (key_type == NPC_MCAM_KEY_X2 &&
> + (ref >= 2 * bd || limit >= 2 * bd))) {
> + dev_err(rvu->dev, "%s:%d Wrong ref_enty(%d) or limit(%d)\n",
> + __func__, __LINE__, ref, limit);
> + return -EINVAL;
> + }
> +
> + if (contig && count > npc_priv.subbank_depth)
> + goto try_ref_multi_subbank;
> +
> + rc = npc_subbank_ref_alloc(rvu, key_type, ref, limit,
> + prio, contig, count, mcam_idx);
> + if (!rc)
> + goto add2map;
> +
> +try_ref_multi_subbank:
> + rc = npc_multi_subbank_ref_alloc(rvu, key_type,
> + ref, limit, prio,
> + contig, count, mcam_idx);
> + if (!rc)
> + goto add2map;
> +
> + return rc;
> +
> +add2map:
> + for (i = 0; i < count; i++) {
> + rc = npc_add_to_pf_maps(rvu, mcam_idx[i], pcifunc);
> + if (rc)
> + return rc;
> + }
> +
> + return 0;
> +}
> +
> +void npc_cn20k_subbank_calc_free(struct rvu *rvu, int *x2_free,
> + int *x4_free, int *sb_free)
> +{
> + struct npc_subbank *sb;
> + int i;
> +
> + /* Reset all stats to zero */
> + *x2_free = 0;
> + *x4_free = 0;
> + *sb_free = 0;
> +
> + for (i = 0; i < npc_priv.num_subbanks; i++) {
> + sb = &npc_priv.sb[i];
> + mutex_lock(&sb->lock);
> +
> + /* Count number of free subbanks */
> + if (sb->flags & NPC_SUBBANK_FLAG_FREE) {
> + (*sb_free)++;
> + goto next;
> + }
> +
> + /* Sumup x4 free count */
> + if (sb->key_type == NPC_MCAM_KEY_X4) {
> + (*x4_free) += sb->free_cnt;
> + goto next;
> + }
> +
> + /* Sumup x2 free counts */
> + (*x2_free) += sb->free_cnt;
> +next:
> + mutex_unlock(&sb->lock);
> + }
> +}
> +
> +int
> +rvu_mbox_handler_npc_cn20k_get_free_count(struct rvu *rvu,
> + struct msg_req *req,
> + struct npc_cn20k_get_free_count_rsp *rsp)
> +{
> + npc_cn20k_subbank_calc_free(rvu, &rsp->free_x2,
> + &rsp->free_x4, &rsp->free_subbanks);
> + return 0;
> +}
> +
> +static void npc_lock_all_subbank(void)
> +{
> + int i;
> +
> + for (i = 0; i < npc_priv.num_subbanks; i++)
> + mutex_lock(&npc_priv.sb[i].lock);
> +}
> +
> +static void npc_unlock_all_subbank(void)
> +{
> + int i;
> +
> + for (i = npc_priv.num_subbanks - 1; i >= 0; i--)
> + mutex_unlock(&npc_priv.sb[i].lock);
> +}
> +
> +static int *subbank_srch_order;
> +
> +int npc_cn20k_search_order_set(struct rvu *rvu, int (*arr)[2], int cnt)
> +{
> + struct npc_mcam *mcam = &rvu->hw->mcam;
> + u8 (*fslots)[2], (*uslots)[2];
> + int fcnt = 0, ucnt = 0;
> + struct npc_subbank *sb;
> + unsigned long index;
> + int idx, val;
> + void *v;
> +
> + if (cnt != npc_priv.num_subbanks)
> + return -EINVAL;
> +
> + fslots = kcalloc(cnt, sizeof(*fslots), GFP_KERNEL);
> + if (!fslots)
> + return -ENOMEM;
> +
> + uslots = kcalloc(cnt, sizeof(*uslots), GFP_KERNEL);
> + if (!uslots)
> + return -ENOMEM;
> +
> + for (int i = 0; i < cnt; i++, arr++) {
> + idx = (*arr)[0];
> + val = (*arr)[1];
FWIIW, I think this would be slightly more clearly expressed as:
idx = arr[i][0];
val = arr[i][0];
Likewise for uslots and fslots below.
> +
> + subbank_srch_order[idx] = val;
> + }
> +
> + /* Lock mcam */
> + mutex_lock(&mcam->lock);
> + npc_lock_all_subbank();
> +
> + restrict_valid = false;
> +
> + xa_for_each(&npc_priv.xa_sb_used, index, v) {
> + val = xa_to_value(v);
> + (*(uslots + ucnt))[0] = index;
> + (*(uslots + ucnt))[1] = val;
> + xa_erase(&npc_priv.xa_sb_used, index);
> + ucnt++;
> + }
> +
> + xa_for_each(&npc_priv.xa_sb_free, index, v) {
> + val = xa_to_value(v);
> + (*(fslots + fcnt))[0] = index;
> + (*(fslots + fcnt))[1] = val;
> + xa_erase(&npc_priv.xa_sb_free, index);
> + fcnt++;
> + }
> +
> + for (int i = 0; i < ucnt; i++) {
> + idx = (*(uslots + i))[1];
> + sb = &npc_priv.sb[idx];
> + sb->arr_idx = subbank_srch_order[sb->idx];
> + xa_store(&npc_priv.xa_sb_used, sb->arr_idx,
> + xa_mk_value(sb->idx), GFP_KERNEL);
> + }
> +
> + for (int i = 0; i < fcnt; i++) {
> + idx = (*(fslots + i))[1];
> + sb = &npc_priv.sb[idx];
> + sb->arr_idx = subbank_srch_order[sb->idx];
> + xa_store(&npc_priv.xa_sb_free, sb->arr_idx,
> + xa_mk_value(sb->idx), GFP_KERNEL);
> + }
> +
> + npc_unlock_all_subbank();
> + mutex_unlock(&mcam->lock);
> +
> + kfree(fslots);
> + kfree(uslots);
> +
> + return 0;
> +}
...
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
> new file mode 100644
> index 000000000000..e1191d3d03cb
> --- /dev/null
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
> @@ -0,0 +1,65 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Marvell RVU Admin Function driver
> + *
> + * Copyright (C) 2026 Marvell.
> + *
> + */
> +
> +#ifndef NPC_CN20K_H
> +#define NPC_CN20K_H
> +
> +#define MAX_NUM_BANKS 2
> +#define MAX_NUM_SUB_BANKS 32
> +#define MAX_SUBBANK_DEPTH 256
> +
> +enum npc_subbank_flag {
> + NPC_SUBBANK_FLAG_UNINIT, // npc_subbank is not initialized yet.
> + NPC_SUBBANK_FLAG_FREE = BIT(0), // No slot allocated
> + NPC_SUBBANK_FLAG_USED = BIT(1), // At least one slot allocated
> +};
I would suggest using Kernel doc formatting for the documentation
the enum above and two structs below.
> +
> +struct npc_subbank {
> + u16 b0t, b0b, b1t, b1b; // mcam indexes of this subbank
> + enum npc_subbank_flag flags;
> + struct mutex lock; // for flags & rsrc modification
> + DECLARE_BITMAP(b0map, MAX_SUBBANK_DEPTH); // for x4 and x2
> + DECLARE_BITMAP(b1map, MAX_SUBBANK_DEPTH); // for x2 only
> + u16 idx; // subbank index, 0 to npc_priv.subbank - 1
> + u16 arr_idx; // Index to the free array or used array
> + u16 free_cnt; // number of free slots;
> + u8 key_type; //NPC_MCAM_KEY_X4 or NPC_MCAM_KEY_X2
> +};
> +
> +struct npc_priv_t {
> + int bank_depth;
> + const int num_banks;
> + int num_subbanks;
> + int subbank_depth;
> + u8 kw; // Kex configure Keywidth.
> + struct npc_subbank *sb; // Array of subbanks
> + struct xarray xa_sb_used; // xarray of used subbanks
> + struct xarray xa_sb_free; // xarray of free subbanks
> + struct xarray *xa_pf2idx_map; // Each PF to map its mcam idxes
> + struct xarray xa_idx2pf_map; // Mcam idxes to pf map.
> + struct xarray xa_pf_map; // pcifunc to index map.
> + int pf_cnt;
> + bool init_done;
> +};
...
next prev parent reply other threads:[~2026-01-08 17:54 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-05 2:32 [PATCH net-next 00/13] NPC HW block support for cn20k Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 01/13] octeontx2-af: npc: cn20k: Index management Ratheesh Kannoth
2026-01-05 15:15 ` Andrew Lunn
2026-01-06 3:29 ` Ratheesh Kannoth
2026-01-06 8:15 ` Kalesh Anakkur Purayil
2026-01-06 9:32 ` Ratheesh Kannoth
2026-01-08 17:53 ` Simon Horman [this message]
2026-01-09 2:40 ` Ratheesh Kannoth
2026-01-13 13:09 ` Simon Horman
2026-01-05 2:32 ` [PATCH net-next 02/13] octeontx2-af: npc: cn20k: KPM profile changes Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 03/13] octeontx2-af: npc: cn20k: Add default profile Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 04/13] ocetontx2-af: npc: cn20k: MKEX profile support Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 05/13] octeontx2-af: npc: cn20k: Allocate default MCAM indexes Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 06/13] octeontx2-af: npc: cn20k: Use common APIs Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 07/13] octeontx2-af: npc: cn20k: Prepare for new SoC Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 08/13] octeontx2-af: npc: cn20k: Add new mailboxes for CN20K silicon Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 09/13] octeontx2-af: npc: cn20k: virtual index support Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 10/13] octeontx2-af: npc: cn20k: Allocate MCAM entry for flow installation Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 11/13] octeontx2-pf: cn20k: Add TC rules support Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 12/13] octeontx2-af: npc: cn20k: add debugfs support Ratheesh Kannoth
2026-01-05 2:32 ` [PATCH net-next 13/13] octeontx-af: npc: Use common structures Ratheesh Kannoth
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260108175357.GJ345651@kernel.org \
--to=horms@kernel.org \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=rkannoth@marvell.com \
--cc=sgoutham@marvell.com \
--cc=sumang@marvell.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox