[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <08870c7a-8410-46b1-9558-ea3fe6487619@oracle.com>
Date: Wed, 28 Jan 2026 16:57:27 +0530
From: ALOK TIWARI <alok.a.tiwari@...cle.com>
To: Ratheesh Kannoth <rkannoth@...vell.com>, netdev@...r.kernel.org,
linux-kernel@...r.kernel.org
Cc: sgoutham@...vell.com, davem@...emloft.net, edumazet@...gle.com,
kuba@...nel.org, pabeni@...hat.com, andrew+netdev@...n.ch
Subject: Re: [PATCH net-next v6 01/13] octeontx2-af: npc: cn20k: Index
management
> +
> +static int __npc_subbank_contig_alloc(struct rvu *rvu,
> + struct npc_subbank *sb,
> + int key_type, int sidx,
> + int eidx, int prio,
> + int count, int t, int b,
> + unsigned long *bmap,
> + u16 *save)
> +{
> + int k, offset, delta = 0;
> + int cnt = 0, sbd;
> +
> + sbd = npc_priv.subbank_depth;
> +
> + if (sidx >= npc_priv.bank_depth)
> + delta = sbd;
> +
> + switch (prio) {
> + case NPC_MCAM_LOWER_PRIO:
> + case NPC_MCAM_ANY_PRIO:
> + /* Find an area of size 'count' from sidx to eidx */
> + offset = bitmap_find_next_zero_area(bmap, sbd, sidx - b,
> + count, 0);
> +
> + if (offset >= sbd) {
> + dev_err(rvu->dev,
> + "%s: Could not find contiguous(%d) entries\n",
> + __func__, count);
> + return -EFAULT;
> + }
> +
> + dev_dbg(rvu->dev,
> + "%s: sidx=%d eidx=%d t=%d b=%d offset=%d count=%d delta=%d\n",
> + __func__, sidx, eidx, t, b, offset,
> + count, delta);
> +
> + for (cnt = 0; cnt < count; cnt++)
> + save[cnt] = offset + cnt + delta;
> +
> + break;
> +
> + case NPC_MCAM_HIGHER_PRIO:
> + /* Find an area of 'count' from eidx to sidx */
> + for (k = eidx - b; cnt < count && k >= (sidx - b); k--) {
> + /* If an intermediate slot is not free,
> + * reset the counter (cnt) to zero as
> + * request is for contiguous.
> + */
> + if (test_bit(k, bmap)) {
> + cnt = 0;
> + continue;
> + }
> +
> + save[cnt++] = k + delta;
> + }
> + break;
> + }
> +
> + /* Found 'count' number of free slots */
> + if (cnt == count)
> + return 0;
> +
> + dev_dbg(rvu->dev,
> + "%s: Could not find contiguous(%d) entries in subbbank=%u\n",
typo subbbank -> subbank
> + __func__, count, sb->idx);
> + return -EFAULT;
> +}
> +
> +static int __npc_subbank_non_contig_alloc(struct rvu *rvu,
> + struct npc_subbank *sb,
> + int key_type, int sidx,
> + int eidx, int prio,
> + int t, int b,
> + unsigned long *bmap,
> + int count, u16 *save,
> + bool max_alloc, int *alloc_cnt)
> +{
> + unsigned long index;
> + int cnt = 0, delta;
> + int k, sbd;
> +
> + sbd = npc_priv.subbank_depth;
> + delta = sidx >= npc_priv.bank_depth ? sbd : 0;
> +
> + switch (prio) {
> + /* Find an area of size 'count' from sidx to eidx */
> + case NPC_MCAM_LOWER_PRIO:
> + case NPC_MCAM_ANY_PRIO:
> + index = find_next_zero_bit(bmap, sbd, sidx - b);
> + if (index >= sbd) {
> + dev_err(rvu->dev,
> + "%s: Error happened to alloc %u, bitmap_weight=%u, sb->idx=%u\n",
> + __func__, count,
> + bitmap_weight(bmap, sbd),
> + sb->idx);
> + break;
> + }
> +
> + for (k = index; cnt < count && k <= (eidx - b); k++) {
> + /* Skip used slots */
> + if (test_bit(k, bmap))
> + continue;
> +
> + save[cnt++] = k + delta;
> + }
> + break;
> +
> + /* Find an area of 'count' from eidx to sidx */
> + case NPC_MCAM_HIGHER_PRIO:
> + for (k = eidx - b; cnt < count && k >= (sidx - b); k--) {
> + /* Skip used slots */
> + if (test_bit(k, bmap))
> + continue;
> +
> + save[cnt++] = k + delta;
> + }
> + break;
> + }
> +
> + /* Update allocated 'cnt' to alloc_cnt */
> + *alloc_cnt = cnt;
> +
> + /* Successfully allocated requested count slots */
> + if (cnt == count)
> + return 0;
> +
> + /* Allocation successful for cnt < count */
> + if (max_alloc && cnt > 0)
> + return 0;
> +
> + dev_dbg(rvu->dev,
> + "%s: Could not find non contiguous entries(%u) in subbank(%u) cnt=%d max_alloc=%d\n",
> + __func__, count, sb->idx, cnt, max_alloc);
> +
> + return -EFAULT;
> +}
> +
> +static void __npc_subbank_sboff_2_off(struct rvu *rvu, struct npc_subbank *sb,
> + int sb_off, unsigned long **bmap,
> + int *off)
> +{
> + int sbd;
> +
> + sbd = npc_priv.subbank_depth;
> +
> + *off = sb_off & (sbd - 1);
> + *bmap = (sb_off >= sbd) ? sb->b1map : sb->b0map;
> +}
> +
> +/* set/clear bitmap */
> +static bool __npc_subbank_mark_slot(struct rvu *rvu,
> + struct npc_subbank *sb,
> + int sb_off, bool set)
> +{
> + unsigned long *bmap;
> + int off;
> +
> + /* if sb_off >= subbank.depth, then slots are in
> + * bank1
> + */
> + __npc_subbank_sboff_2_off(rvu, sb, sb_off, &bmap, &off);
> +
> + dev_dbg(rvu->dev,
> + "%s: Marking set=%d sb_off=%d sb->idx=%d off=%d\n",
> + __func__, set, sb_off, sb->idx, off);
> +
> + if (set) {
> + /* Slot is already used */
> + if (test_bit(off, bmap))
> + return false;
> +
> + sb->free_cnt--;
> + set_bit(off, bmap);
> + return true;
> + }
> +
> + /* Slot is already free */
> + if (!test_bit(off, bmap))
> + return false;
> +
> + sb->free_cnt++;
> + clear_bit(off, bmap);
> + return true;
> +}
> +
> +static int __npc_subbank_mark_free(struct rvu *rvu, struct npc_subbank *sb)
> +{
> + int rc, blkaddr;
> + void *val;
> +
> + sb->flags = NPC_SUBBANK_FLAG_FREE;
> + sb->key_type = 0;
> +
> + bitmap_clear(sb->b0map, 0, npc_priv.subbank_depth);
> + bitmap_clear(sb->b1map, 0, npc_priv.subbank_depth);
> +
> + if (!xa_erase(&npc_priv.xa_sb_used, sb->arr_idx)) {
> + dev_err(rvu->dev,
> + "%s: Error to delete from xa_sb_used array\n",
> + __func__);
> + return -EFAULT;
> + }
> +
> + rc = xa_insert(&npc_priv.xa_sb_free, sb->arr_idx,
> + xa_mk_value(sb->idx), GFP_KERNEL);
> + if (rc) {
> + val = xa_load(&npc_priv.xa_sb_free, sb->arr_idx);
> + dev_err(rvu->dev,
> + "%s: Error to add sb(%u) to xa_sb_free array at arr_idx=%d, val=%lu\n",
> + __func__, sb->idx, sb->arr_idx, xa_to_value(val));
> + }
> +
> + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
> + rvu_write64(rvu, blkaddr,
> + NPC_AF_MCAM_SECTIONX_CFG_EXT(sb->idx),
> + NPC_MCAM_KEY_X2);
> +
> + return rc;
> +}
> +
> +static int __npc_subbank_mark_used(struct rvu *rvu, struct npc_subbank *sb,
> + int key_type)
> +
remove extra \n
> +{
> + int rc;
> +
> + sb->flags = NPC_SUBBANK_FLAG_USED;
> + sb->key_type = key_type;
> + if (key_type == NPC_MCAM_KEY_X4)
> + sb->free_cnt = npc_priv.subbank_depth;
> + else
> + sb->free_cnt = 2 * npc_priv.subbank_depth;
> +
> + bitmap_clear(sb->b0map, 0, npc_priv.subbank_depth);
> + bitmap_clear(sb->b1map, 0, npc_priv.subbank_depth);
> +
> + if (!xa_erase(&npc_priv.xa_sb_free, sb->arr_idx)) {
> + dev_err(rvu->dev,
> + "%s: Error to delete from xa_sb_free array\n",
> + __func__);
> + return -EFAULT;
> + }
> +
> + rc = xa_insert(&npc_priv.xa_sb_used, sb->arr_idx,
> + xa_mk_value(sb->idx), GFP_KERNEL);
> + if (rc)
> + dev_err(rvu->dev,
> + "%s: Error to add to xa_sb_used array\n", __func__);
> +
> + return rc;
> +}
> +
> +static bool __npc_subbank_free(struct rvu *rvu, struct npc_subbank *sb,
> + u16 sb_off)
> +{
> + bool deleted = false;
> + unsigned long *bmap;
> + int rc, off;
> +
> + deleted = __npc_subbank_mark_slot(rvu, sb, sb_off, false);
> + if (!deleted)
> + goto done;
> +
> + __npc_subbank_sboff_2_off(rvu, sb, sb_off, &bmap, &off);
> +
> + /* Check whether we can mark whole subbank as free */
> + if (sb->key_type == NPC_MCAM_KEY_X4) {
> + if (sb->free_cnt < npc_priv.subbank_depth)
> + goto done;
> + } else {
> + if (sb->free_cnt < 2 * npc_priv.subbank_depth)
> + goto done;
> + }
> +
> + /* All slots in subbank are unused. Mark the subbank as free
> + * and add to free pool
> + */
> + rc = __npc_subbank_mark_free(rvu, sb);
> + if (rc)
> + dev_err(rvu->dev, "%s: Error to free subbank\n", __func__);
> +
> +done:
> + return deleted;
> +}
> +
> +static int
> +npc_subbank_free(struct rvu *rvu, struct npc_subbank *sb, u16 sb_off)
> +{
> + bool deleted;
> +
> + mutex_lock(&sb->lock);
> + deleted = __npc_subbank_free(rvu, sb, sb_off);
> + mutex_unlock(&sb->lock);
> +
> + return deleted ? 0 : -EFAULT;
> +}
> +
> +static int __npc_subbank_alloc(struct rvu *rvu, struct npc_subbank *sb,
> + int key_type, int ref, int limit, int prio,
> + bool contig, int count, u16 *mcam_idx,
> + int idx_sz, bool max_alloc, int *alloc_cnt)
> +{
> + int cnt, t, b, i, blkaddr;
> + bool new_sub_bank = false;
> + unsigned long *bmap;
> + u16 *save = NULL;
> + int sidx, eidx;
> + bool diffbank;
> + int bw, bfree;
> + int rc = 0;
> + bool ret;
> +
> + /* Check if enough space is there to return requested number of
> + * mcam indexes in case of contiguous allocation
> + */
> + if (!max_alloc && count > idx_sz) {
> + dev_err(rvu->dev,
> + "%s: Less space, count=%d idx_sz=%d sb_id=%d\n",
> + __func__, count, idx_sz, sb->idx);
> + return -ENOSPC;
> + }
> +
> + /* Allocation on multiple subbank is not supported by this function.
> + * it means that ref and limit should be on same subbank.
> + *
> + * ref and limit values should be validated w.r.t prio as below.
> + * say ref = 100, limit = 200,
> + * if NPC_MCAM_LOWER_PRIO, allocate index 100
> + * if NPC_MCAM_HIGHER_PRIO, below sanity test returns error.
> + * if NPC_MCAM_ANY_PRIO, allocate index 100
> + *
> + * say ref = 200, limit = 100
> + * if NPC_MCAM_LOWER_PRIO, below sanity test returns error.
> + * if NPC_MCAM_HIGHER_PRIO, allocate index 200
> + * if NPC_MCAM_ANY_PRIO, allocate index 100
> + *
> + * Please note that NPC_MCAM_ANY_PRIO does not have any restriction
> + * on "ref" and "limit" values. ie, ref > limit and limit > ref
> + * are valid cases.
> + */
> + if ((prio == NPC_MCAM_LOWER_PRIO && ref > limit) ||
> + (prio == NPC_MCAM_HIGHER_PRIO && ref < limit)) {
> + dev_err(rvu->dev, "%s: Wrong ref_enty(%d) or limit(%d)\n",
> + __func__, ref, limit);
> + return -EINVAL;
> + }
> +
> + /* x4 indexes are from 0 to bank size as it combines two x2 banks */
> + if (key_type == NPC_MCAM_KEY_X4 &&
> + (ref >= npc_priv.bank_depth || limit >= npc_priv.bank_depth)) {
> + dev_err(rvu->dev,
> + "%s: Wrong ref_enty(%d) or limit(%d) for x4\n",
> + __func__, ref, limit);
> + return -EINVAL;
> + }
> +
> + /* This function is called either bank0 or bank1 portion of a subbank.
> + * so ref and limit should be on same bank.
> + */
> + diffbank = !!((ref & npc_priv.bank_depth) ^
> + (limit & npc_priv.bank_depth));
> + if (diffbank) {
> + dev_err(rvu->dev,
> + "%s: request ref and limit should be from same bank\n",
> + __func__);
> + return -EINVAL;
> + }
> +
> + sidx = min_t(int, limit, ref);
> + eidx = max_t(int, limit, ref);
> +
> + /* Find total number of slots available; both used and free */
> + cnt = eidx - sidx + 1;
> + if (contig && cnt < count) {
> + dev_err(rvu->dev,
> + "%s: Wrong ref_enty(%d) or limit(%d) for count(%d)\n",
> + __func__, ref, limit, count);
> + return -EINVAL;
> + }
> +
> + /* If subbank is free, check if requested number of indexes is less than
> + * or equal to mcam entries available in the subbank if contig.
> + */
> + if (sb->flags & NPC_SUBBANK_FLAG_FREE) {
> + if (contig && count > npc_priv.subbank_depth) {
> + dev_err(rvu->dev, "%s: Less number of entries\n",
> + __func__);
> + goto err;
> + }
> +
> + new_sub_bank = true;
> + goto process;
> + }
> +
> + /* Flag should be set for all used subbanks */
> + WARN_ONCE(!(sb->flags & NPC_SUBBANK_FLAG_USED),
> + "Used flag is not set(%#x)\n", sb->flags);
> +
> + /* If subbank key type does not match with requested key_type,
> + * return error
> + */
> + if (sb->key_type != key_type) {
> + dev_dbg(rvu->dev, "%s: subbank key_type mismatch\n", __func__);
> + rc = -EINVAL;
> + goto err;
> + }
> +
> +process:
> + /* if ref or limit >= npc_priv.bank_depth, index are in bank1.
> + * else bank0.
> + */
> + if (ref >= npc_priv.bank_depth) {
> + bmap = sb->b1map;
> + t = sb->b1t;
> + b = sb->b1b;
> + } else {
> + bmap = sb->b0map;
> + t = sb->b0t;
> + b = sb->b0b;
> + }
> +
> + /* Calculate free slots */
> + bw = bitmap_weight(bmap, npc_priv.subbank_depth);
> + bfree = npc_priv.subbank_depth - bw;
> +
> + if (!bfree) {
> + rc = -ENOSPC;
> + goto err;
> + }
> +
> + /* If request is for contiguous , then max we can allocate is
> + * equal to subbank_depth
> + */
> + if (contig && bfree < count) {
> + rc = -ENOSPC;
> + dev_err(rvu->dev, "%s: no space for entry\n", __func__);
> + goto err;
> + }
> +
> + /* 'save' array stores available indexes temporarily before
> + * marking it as allocated
> + */
> + save = kcalloc(count, sizeof(u16), GFP_KERNEL);
> + if (!save) {
> + rc = -ENOMEM;
> + goto err;
> + }
> +
> + if (contig) {
> + rc = __npc_subbank_contig_alloc(rvu, sb, key_type,
> + sidx, eidx, prio,
> + count, t, b,
> + bmap, save);
> + /* contiguous allocation success means that
> + * requested number of free slots got
> + * allocated
> + */
> + if (!rc)
> + *alloc_cnt = count;
> +
> + } else {
> + rc = __npc_subbank_non_contig_alloc(rvu, sb, key_type,
> + sidx, eidx, prio,
> + t, b, bmap,
> + count, save,
> + max_alloc, alloc_cnt);
> + }
> +
> + if (rc)
> + goto err;
> +
> + /* Mark new subbank bank as used */
> + if (new_sub_bank) {
> + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
> + if (blkaddr < 0) {
> + dev_err(rvu->dev,
> + "%s: NPC block not implemented\n", __func__);
> + goto err;
> + }
> +
> + rc = __npc_subbank_mark_used(rvu, sb, key_type);
> + if (rc) {
> + dev_err(rvu->dev,
> + "%s: Error to mark subbank as used\n",
> + __func__);
> + goto err;
> + }
> +
> + /* Configure section type to key_type */
> + rvu_write64(rvu, blkaddr,
> + NPC_AF_MCAM_SECTIONX_CFG_EXT(sb->idx),
> + key_type);
> + }
> +
> + for (i = 0; i < *alloc_cnt; i++) {
> + rc = npc_subbank_idx_2_mcam_idx(rvu, sb, save[i],
> + &mcam_idx[i]);
> + if (rc) {
> + dev_err(rvu->dev,
> + "%s: Error to find mcam idx for %u\n",
> + __func__, save[i]);
> + /* TODO: handle err case gracefully */
> + goto err;
> + }
> +
> + /* Mark all slots as used */
> + ret = __npc_subbank_mark_slot(rvu, sb, save[i], true);
> + if (!ret) {
> + dev_err(rvu->dev, "%s: Error to mark mcam_idx %u\n",
> + __func__, mcam_idx[i]);
> + rc = -EFAULT;
> + goto err;
> + }
> + }
> +
> +err:
> + kfree(save);
> + return rc;
> +}
> +
> +static int
> +npc_subbank_alloc(struct rvu *rvu, struct npc_subbank *sb,
> + int key_type, int ref, int limit, int prio,
> + bool contig, int count, u16 *mcam_idx,
> + int idx_sz, bool max_alloc, int *alloc_cnt)
> +{
> + int rc;
> +
> + mutex_lock(&sb->lock);
> + rc = __npc_subbank_alloc(rvu, sb, key_type, ref, limit, prio,
> + contig, count, mcam_idx, idx_sz,
> + max_alloc, alloc_cnt);
> + mutex_unlock(&sb->lock);
> +
> + return rc;
> +}
> +
> +static int
> +npc_del_from_pf_maps(struct rvu *rvu, u16 mcam_idx)
> +{
> + int pcifunc, idx;
> + void *map;
> +
> + map = xa_erase(&npc_priv.xa_idx2pf_map, mcam_idx);
> + if (!map) {
> + dev_err(rvu->dev,
> + "%s: failed to erase mcam_idx(%u) from xa_idx2pf map\n",
> + __func__, mcam_idx);
> + return -EFAULT;
> + }
> +
> + pcifunc = xa_to_value(map);
> + map = xa_load(&npc_priv.xa_pf_map, pcifunc);
> + idx = xa_to_value(map);
> +
> + map = xa_erase(&npc_priv.xa_pf2idx_map[idx], mcam_idx);
> + if (!map) {
> + dev_err(rvu->dev,
> + "%s: failed to erase mcam_idx(%u) from xa_pf2idx_map map\n",
> + __func__, mcam_idx);
> + return -EFAULT;
> + }
> + return 0;
> +}
> +
> +static int
> +npc_add_to_pf_maps(struct rvu *rvu, u16 mcam_idx, int pcifunc)
> +{
> + int rc, idx;
> + void *map;
> +
> + dev_dbg(rvu->dev,
> + "%s: add2maps mcam_idx(%u) to xa_idx2pf map pcifunc=%#x\n",
> + __func__, mcam_idx, pcifunc);
> +
> + rc = xa_insert(&npc_priv.xa_idx2pf_map, mcam_idx,
> + xa_mk_value(pcifunc), GFP_KERNEL);
> +
> + if (rc) {
> + map = xa_load(&npc_priv.xa_idx2pf_map, mcam_idx);
> + dev_err(rvu->dev,
> + "%s: failed to insert mcam_idx(%u) to xa_idx2pf map, existing value=%lu\n",
> + __func__, mcam_idx, xa_to_value(map));
> + return -EFAULT;
> + }
> +
> + map = xa_load(&npc_priv.xa_pf_map, pcifunc);
> + idx = xa_to_value(map);
> +
> + rc = xa_insert(&npc_priv.xa_pf2idx_map[idx], mcam_idx,
> + xa_mk_value(pcifunc), GFP_KERNEL);
> +
> + if (rc) {
> + map = xa_load(&npc_priv.xa_pf2idx_map[idx], mcam_idx);
> + xa_erase(&npc_priv.xa_idx2pf_map, mcam_idx);
> + dev_err(rvu->dev,
> + "%s: failed to insert mcam_idx(%u) to xa_pf2idx_map map, earlier value=%lu idx=%u\n",
> + __func__, mcam_idx, xa_to_value(map), idx);
> +
> + return -EFAULT;
> + }
> +
> + return 0;
> +}
> +
> +static bool
> +npc_subbank_suits(struct npc_subbank *sb, int key_type)
> +{
> + mutex_lock(&sb->lock);
> +
> + if (!sb->key_type) {
> + mutex_unlock(&sb->lock);
> + return true;
> + }
> +
> + if (sb->key_type == key_type) {
> + mutex_unlock(&sb->lock);
> + return true;
> + }
> +
> + mutex_unlock(&sb->lock);
> + return false;
> +}
> +
> +#define SB_ALIGN_UP(val) (((val) + npc_priv.subbank_depth) & \
> + ~((npc_priv.subbank_depth) - 1))
> +#define SB_ALIGN_DOWN(val) ALIGN_DOWN((val), npc_priv.subbank_depth)
> +
> +static void npc_subbank_iter_down(struct rvu *rvu,
> + int ref, int limit,
> + int *cur_ref, int *cur_limit,
> + bool *start, bool *stop)
> +{
> + int align;
> +
> + *stop = false;
> +
> + /* ALIGN_DOWN the limit to current subbank boundary bottom index */
> + if (*start) {
> + *start = false;
> + *cur_ref = ref;
> + align = SB_ALIGN_DOWN(ref);
> + if (align < limit) {
> + *stop = true;
> + *cur_limit = limit;
> + return;
> + }
> + *cur_limit = align;
> + return;
> + }
> +
> + *cur_ref = *cur_limit - 1;
> + align = *cur_ref - npc_priv.subbank_depth + 1;
> + if (align <= limit) {
> + *stop = true;
> + *cur_limit = limit;
> + return;
> + }
> +
> + *cur_limit = align;
> +}
> +
> +static void npc_subbank_iter_up(struct rvu *rvu,
> + int ref, int limit,
> + int *cur_ref, int *cur_limit,
> + bool *start, bool *stop)
> +{
> + int align;
> +
> + *stop = false;
> +
> + /* ALIGN_UP the limit to current subbank boundary top index */
> + if (*start) {
> + *start = false;
> + *cur_ref = ref;
> +
> + /* Find next lower prio subbank's bottom index */
> + align = SB_ALIGN_UP(ref);
> +
> + /* Crosses limit ? */
> + if (align - 1 > limit) {
> + *stop = true;
> + *cur_limit = limit;
> + return;
> + }
> +
> + /* Current subbank's top index */
> + *cur_limit = align - 1;
> + return;
> + }
> +
> + *cur_ref = *cur_limit + 1;
> + align = *cur_ref + npc_priv.subbank_depth - 1;
> +
> + if (align >= limit) {
> + *stop = true;
> + *cur_limit = limit;
> + return;
> + }
> +
> + *cur_limit = align;
> +}
> +
> +static int
> +npc_subbank_iter(struct rvu *rvu, int key_type,
> + int ref, int limit, int prio,
> + int *cur_ref, int *cur_limit,
> + bool *start, bool *stop)
> +{
> + if (prio != NPC_MCAM_HIGHER_PRIO)
> + npc_subbank_iter_up(rvu, ref, limit,
> + cur_ref, cur_limit,
> + start, stop);
> + else
> + npc_subbank_iter_down(rvu, ref, limit,
> + cur_ref, cur_limit,
> + start, stop);
> +
> + /* limit and ref should < bank_depth for x4 */
> + if (key_type == NPC_MCAM_KEY_X4) {
> + if (*cur_ref >= npc_priv.bank_depth)
> + return -EINVAL;
> +
> + if (*cur_limit >= npc_priv.bank_depth)
> + return -EINVAL;
> + }
> + /* limit and ref should < 2 * bank_depth, for x2 */
> + if (*cur_ref >= 2 * npc_priv.bank_depth)
> + return -EINVAL;
> +
> + if (*cur_limit >= 2 * npc_priv.bank_depth)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int npc_idx_free(struct rvu *rvu, u16 *mcam_idx, int count,
> + bool maps_del)
> +{
> + struct npc_subbank *sb;
> + int idx, i;
> + bool ret;
> + int rc;
> +
> + /* Check if we can dealloc indexes properly ? */
> + for (i = 0; i < count; i++) {
> + rc = npc_mcam_idx_2_subbank_idx(rvu, mcam_idx[i],
> + &sb, &idx);
> + if (rc) {
> + dev_err(rvu->dev,
> + "Failed to free mcam idx=%u\n", mcam_idx[i]);
> + return rc;
> + }
> + }
> +
> + for (i = 0; i < count; i++) {
> + rc = npc_mcam_idx_2_subbank_idx(rvu, mcam_idx[i],
> + &sb, &idx);
> + if (rc)
> + return rc;
> +
> + ret = npc_subbank_free(rvu, sb, idx);
> + if (ret)
> + return -EINVAL;
> +
> + if (!maps_del)
> + continue;
> +
> + rc = npc_del_from_pf_maps(rvu, mcam_idx[i]);
> + if (rc)
> + return rc;
> + }
> +
> + return 0;
> +}
> +
> +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:Error to add to use array\n",
use ' ' before Error %s:Error
> + __func__);
> + 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:Error to add to use array\n",
> + __func__);
> + 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) {
> + rc = npc_idx_free(rvu, mcam_idx, cnt, false);
> + if (rc)
> + return rc;
> +
> + cnt = 0;
> + }
> + 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: Error happened while freeing cnt=%u indexes\n",
> + __func__, 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: ref=%d limit=%d r=%d l=%d start=%d stop=%d tot=%d count=%d rc=%d\n",
> + __func__, 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: ref subbank=%d off=%d\n",
> + __func__, 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: not suitable sb=%d key_type=%d\n",
> + __func__, 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: limit subbank=%d off=%d\n",
> + __func__, sb_idx1, sb_idx2);
sb_idx1 -> sb2->idx
> +
> + /* subbank of ref and limit should be same */
> + if (sb1 != sb2) {
> + dev_err(rvu->dev,
> + "%s: l(%d) and r(%d) are not in same subbank\n",
> + __func__, r, l);
> + goto err;
> + }
> +
> + if (contig &&
> + npc_subbank_free_cnt(rvu, sb1, key_type) < count) {
> + dev_dbg(rvu->dev, "%s: less count =%d\n",
> + __func__,
> + 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: Allocated tot=%d alloc_cnt=%d\n",
> + __func__, tot, alloc_cnt);
> +
> + if (!rc && count == tot)
> + return 0;
> + }
> +err:
> + dev_dbg(rvu->dev, "%s: Error to allocate\n",
> + __func__);
> +
> + /* 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: failed to free %u indexes\n",
> + __func__, 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: Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, 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: Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, 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: Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, 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: Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, 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: Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, 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: Allocated %d from subbank %d, tot=%d count=%d\n",
> + __func__, 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: non-contig allocation fails\n",
> + __func__);
> +
> + return -EFAULT;
> +}
> +
> +
> +void npc_cn20k_deinit(struct rvu *rvu)
> +{
> + int i;
> +
> + xa_destroy(&npc_priv.xa_sb_used);
> + xa_destroy(&npc_priv.xa_sb_free);
> + xa_destroy(&npc_priv.xa_idx2pf_map);
> + xa_destroy(&npc_priv.xa_pf_map);
> +
> + for (i = 0; i < npc_priv.pf_cnt; i++)
> + xa_destroy(&npc_priv.xa_pf2idx_map[i]);
> +
> + kfree(npc_priv.xa_pf2idx_map);
> + kfree(npc_priv.sb);
> + kfree(subbank_srch_order);
> +}
> +
> +int npc_cn20k_init(struct rvu *rvu)
> +{
> + int err;
> +
> + err = npc_priv_init(rvu);
> + if (err) {
> + dev_err(rvu->dev, "%s: Error to init\n",
> + __func__);
> + return err;
> + }
> +
> + npc_priv.init_done = true;
> +
> + 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..26da0a2c717a
> --- /dev/null
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
> @@ -0,0 +1,110 @@
> +/* 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 status
> + *
> + * subbank flag indicates whether the subbank is free
> + * or used.
> + *
> + * @NPC_SUBBANK_FLAG_UNINIT: Subbank is not initialized.
> + * @NPC_SUBBANK_FLAG_FREE: Subbank is free.
> + * @NPC_SUBBANK_FLAG_USED: Subbank is used.
> + */
> +enum npc_subbank_flag {
> + NPC_SUBBANK_FLAG_UNINIT,
> + NPC_SUBBANK_FLAG_FREE = BIT(0),
> + NPC_SUBBANK_FLAG_USED = BIT(1),
> +};
> +
> +/**
> + * struct npc_subbank - Subbank fields.
> + * @b0b: Subbanks bottom index for bank0
> + * @b1b: Subbanks bottom index for bank1
> + * @b0t: Subbanks top index for bank0
> + * @b1t: Subbanks top index for bank1
> + * @flags: Subbank flags
> + * @lock: Mutex lock for flags and rsrc mofiication
mofiication -> modification
> + * @b0map: Bitmap map for bank0 indexes
> + * @b1map: Bitmap map for bank1 indexes
> + * @idx: Subbank index
> + * @arr_idx: Index to the free array or used array
> + * @free_cnt: Number of free slots in the subbank.
> + * @key_type: X4 or X2 subbank.
> + *
> + * MCAM resource is divided horizontally into mutltiple subbanks and
mutltiple -> multiple
> + * Resource allocation from each subbank is managed by this data
> + * structure.
> + */
> +struct npc_subbank {
> + u16 b0t, b0b, b1t, b1b;
> + enum npc_subbank_flag flags;
> + struct mutex lock; /* Protect subbank resources */
> + DECLARE_BITMAP(b0map, MAX_SUBBANK_DEPTH);
> + DECLARE_BITMAP(b1map, MAX_SUBBANK_DEPTH);
> + u16 idx;
> + u16 arr_idx;
> + u16 free_cnt;
> + u8 key_type;
> +};
> +
> +/**
> + * struct npc_priv_t - NPC private structure.
> + * @bank_depth: Total entries in each bank.
> + * @num_banks: Number of banks.
> + * @num_subbanks: Number of subbanks.
> + * @subbank_depth: Depth of subbank.
> + * @kw: Kex configured key type.
> + * @sb: Subbank array.
> + * @xa_sb_used: Array of used subbanks.
> + * @xa_sb_free: Array of free subbanks.
> + * @xa_pf2idx_map: PF to mcam index map.
> + * @xa_idx2pf_map: Mcam index to PF map.
> + * @xa_pf_map: Pcifunc to index map.
> + * @pf_cnt: Number of PFs.A
remove extra A
> + * @init_done: Indicates MCAM initialization is done.
> + *
> + * This structure is populated during probing time by reading
> + * HW csr registers.
> + */
> +struct npc_priv_t {
> + int bank_depth;
> + const int num_banks;
> + int num_subbanks;
> + int subbank_depth;
> + u8 kw;
> + struct npc_subbank *sb;
> + struct xarray xa_sb_used;
> + struct xarray xa_sb_free;
> + struct xarray *xa_pf2idx_map;
> + struct xarray xa_idx2pf_map;
> + struct xarray xa_pf_map;
> + int pf_cnt;
> + bool init_done;
> +};
> +
> +struct rvu;
> +
> +struct npc_priv_t *npc_priv_get(void);
> +int npc_cn20k_init(struct rvu *rvu);
> +void npc_cn20k_deinit(struct rvu *rvu);
> +
> +void npc_cn20k_subbank_calc_free(struct rvu *rvu, int *x2_free,
> + int *x4_free, int *sb_free);
> +
> +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 npc_cn20k_idx_free(struct rvu *rvu, u16 *mcam_idx, int count);
> +#endif /* NPC_CN20K_H */
Thanks,
Alok
Powered by blists - more mailing lists