[PATCH net-next 01/13] octeontx2-af: npc: cn20k: Index management

Ratheesh Kannoth posted 13 patches 2 days, 20 hours ago
There is a newer version of this series
[PATCH net-next 01/13] octeontx2-af: npc: cn20k: Index management
Posted by Ratheesh Kannoth 2 days, 20 hours ago
In CN20K silicon, the MCAM is divided vertically into two banks.
Each bank has a depth of 8192.

The MCAM is divided horizontally into 32 subbanks, with each subbank
having a depth of 256.

Each subbank can accommodate either x2 keys or x4 keys. x2 keys are
256 bits in size, and x4 keys are 512 bits in size.

    Bank1                   Bank0
    |-----------------------------|
    |               |             | subbank 31 { depth 256 }
    |               |             |
    |-----------------------------|
    |               |             | subbank 30
    |               |             |
    ------------------------------
    ...............................

    |-----------------------------|
    |               |             | subbank 0
    |               |             |
    ------------------------------|

This patch implements the following allocation schemes in NPC.
The allocation API accepts reference (ref), limit, contig, priority,
and count values. For example, specifying ref=100, limit=200,
contig=1, priority=LOW, and count=20 will allocate 20 contiguous
MCAM entries between entries 100 and 200.

1. Contiguous allocation with ref, limit, and priority.
2. Non-contiguous allocation with ref, limit, and priority.
3. Non-contiguous allocation without ref.
4. Contiguous allocation without ref.

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
 MAINTAINERS                                   |    2 +-
 .../ethernet/marvell/octeontx2/af/Makefile    |    2 +-
 .../marvell/octeontx2/af/cn20k/debugfs.c      |  182 ++
 .../marvell/octeontx2/af/cn20k/debugfs.h      |    3 +
 .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 1798 +++++++++++++++++
 .../ethernet/marvell/octeontx2/af/cn20k/npc.h |   65 +
 .../ethernet/marvell/octeontx2/af/cn20k/reg.h |    3 +
 .../ethernet/marvell/octeontx2/af/common.h    |    4 -
 .../net/ethernet/marvell/octeontx2/af/mbox.h  |   18 +
 .../marvell/octeontx2/af/rvu_debugfs.c        |    3 +
 .../ethernet/marvell/octeontx2/af/rvu_npc.c   |    8 +-
 11 files changed, 2081 insertions(+), 7 deletions(-)
 create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
 create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 454b8ed119e9..0111506e8fe4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15304,7 +15304,7 @@ M:	Subbaraya Sundeep <sbhatta@marvell.com>
 L:	netdev@vger.kernel.org
 S:	Maintained
 F:	Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst
-F:	drivers/net/ethernet/marvell/octeontx2/af/
+F:	drivers/net/ethernet/marvell/octeontx2/af/*
 
 MARVELL PEM PMU DRIVER
 M:	Linu Cherian <lcherian@marvell.com>
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
index 244de500963e..91b7d6e96a61 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile
+++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
@@ -13,4 +13,4 @@ rvu_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \
 		  rvu_cpt.o rvu_devlink.o rpm.o rvu_cn10k.o rvu_switch.o \
 		  rvu_sdp.o rvu_npc_hash.o mcs.o mcs_rvu_if.o mcs_cnf10kb.o \
 		  rvu_rep.o cn20k/mbox_init.o cn20k/nix.o cn20k/debugfs.o \
-		  cn20k/npa.o
+		  cn20k/npa.o cn20k/npc.o
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);
+			goto err;
+		}
+
+		t1[0] = ' ';
+		t1[strlen(t1) - 1] = ' ';
+		t1 = strim(t1);
+
+		ret = kstrtoint(t1, 10, &idx);
+		if (ret) {
+			pr_err("%s:%d Bad Token %s=%s\n",
+			       __func__, __LINE__, t1, t2);
+			goto err;
+		}
+
+		ret = kstrtoint(t2, 10, &val);
+		if (ret) {
+			pr_err("%s:%d Bad Token %s=%s\n",
+			       __func__, __LINE__, t1, t2);
+			goto err;
+		}
+
+		(*(arr + cnt))[0] = idx;
+		(*(arr + cnt))[1] = val;
+
+		cnt++;
+	}
+
+	if (cnt != num_subbanks) {
+		pr_err("Could find %u tokens, but exact %u tokens needed\n",
+		       cnt, num_subbanks);
+		goto err;
+	}
+
+	for (int i = 0; i < cnt; i++) {
+		w1 |= BIT_ULL((*(arr + i))[0]);
+		w2 |= BIT_ULL((*(arr + i))[1]);
+	}
+
+	if (bitmap_weight(&w1, cnt) != cnt) {
+		pr_err("Missed to fill for [%lu]=\n",
+		       find_first_zero_bit(&w1, cnt));
+		goto err;
+	}
+
+	if (bitmap_weight(&w2, cnt) != cnt) {
+		pr_err("Missed to fill value %lu\n",
+		       find_first_zero_bit(&w2, cnt));
+		goto err;
+	}
+
+	npc_cn20k_search_order_set(rvu, arr, cnt);
+
+	kfree(arr);
+	return 0;
+err:
+	kfree(arr);
+	return -EINVAL;
+}
+
+static ssize_t
+npc_subbank_srch_order_write(struct file *file, const char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct npc_priv_t *npc_priv;
+	struct rvu *rvu;
+	char buf[1024];
+	int len;
+
+	npc_priv = npc_priv_get();
+
+	rvu = file->private_data;
+
+	len = simple_write_to_buffer(buf, sizeof(buf), ppos,
+				     user_buf, count);
+	if (npc_subbank_srch_order_parse_n_fill(rvu, buf,
+						npc_priv->num_subbanks)) {
+		npc_subbank_srch_order_dbgfs_usage();
+		return -EFAULT;
+	}
+
+	return len;
+}
+
+static ssize_t
+npc_subbank_srch_order_read(struct file *file, char __user *user_buf,
+			    size_t count, loff_t *ppos)
+{
+	struct npc_priv_t *npc_priv;
+	bool restricted_order;
+	const int *srch_order;
+	char buf[1024];
+	int len = 0;
+
+	npc_priv = npc_priv_get();
+
+	len += snprintf(buf + len, sizeof(buf) - len, "%s",
+			"Usage: echo \"[0]=0,[1]=1,[2]=2,..[31]=31\" > <debugfs>/subbank_srch_order\n");
+
+	len += snprintf(buf + len, sizeof(buf) - len, "%s",
+			"Search order\n");
+
+	srch_order = npc_cn20k_search_order_get(&restricted_order);
+
+	for (int i = 0;  i < npc_priv->num_subbanks; i++)
+		len += snprintf(buf + len, sizeof(buf) - len, "[%d]=%d,",
+				i, srch_order[i]);
+
+	len += snprintf(buf + len - 1, sizeof(buf) - len, "%s", "\n");
+
+	if (restricted_order)
+		len += snprintf(buf + len, sizeof(buf) - len,
+				"Restricted allocation for subbanks %u, %u\n",
+				npc_priv->num_subbanks - 1, 0);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations npc_subbank_srch_order_ops = {
+	.open           = simple_open,
+	.write		= npc_subbank_srch_order_write,
+	.read		= npc_subbank_srch_order_read,
+};
+
+int npc_cn20k_debugfs_init(struct rvu *rvu)
+{
+	struct dentry *npc_dentry;
+
+	npc_dentry = debugfs_create_file("subbank_srch_order", 0644,
+					 rvu->rvu_dbg.npc,
+					 rvu, &npc_subbank_srch_order_ops);
+	if (!npc_dentry)
+		return -EFAULT;
+
+	return 0;
+}
+
+void npc_cn20k_debugfs_deinit(struct rvu *rvu)
+{
+	debugfs_remove_recursive(rvu->rvu_dbg.npc);
+}
 
 void print_nix_cn20k_sq_ctx(struct seq_file *m,
 			    struct nix_cn20k_sq_ctx_s *sq_ctx)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
index a2e3a2cd6edb..0c5f05883666 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
@@ -16,6 +16,9 @@
 #include "struct.h"
 #include "../mbox.h"
 
+int npc_cn20k_debugfs_init(struct rvu *rvu);
+void npc_cn20k_debugfs_deinit(struct rvu *rvu);
+
 void print_nix_cn20k_sq_ctx(struct seq_file *m,
 			    struct nix_cn20k_sq_ctx_s *sq_ctx);
 void print_nix_cn20k_cq_ctx(struct seq_file *m,
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
new file mode 100644
index 000000000000..27b049ac4ae8
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -0,0 +1,1798 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell RVU Admin Function driver
+ *
+ * Copyright (C) 2026 Marvell.
+ *
+ */
+#include <linux/xarray.h>
+#include <linux/bitfield.h>
+
+#include "cn20k/npc.h"
+#include "cn20k/reg.h"
+
+static struct npc_priv_t npc_priv = {
+	.num_banks = MAX_NUM_BANKS,
+};
+
+static const char *npc_kw_name[NPC_MCAM_KEY_MAX] = {
+	[NPC_MCAM_KEY_DYN] = "DYNAMIC",
+	[NPC_MCAM_KEY_X2] = "X2",
+	[NPC_MCAM_KEY_X4] = "X4",
+};
+
+struct npc_priv_t *npc_priv_get(void)
+{
+	return &npc_priv;
+}
+
+static int npc_subbank_idx_2_mcam_idx(struct rvu *rvu, struct npc_subbank *sb,
+				      u16 sub_off, u16 *mcam_idx)
+{
+	int off, bot;
+
+	/* for x4 section, maximum allowed subbank index =
+	 * subsection depth - 1
+	 */
+	if (sb->key_type == NPC_MCAM_KEY_X4 &&
+	    sub_off >= npc_priv.subbank_depth) {
+		dev_err(rvu->dev, "%s:%d bad params\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	/* for x2 section, maximum allowed subbank index =
+	 * 2 * subsection depth - 1
+	 */
+	if (sb->key_type == NPC_MCAM_KEY_X2 &&
+	    sub_off >= npc_priv.subbank_depth * 2) {
+		dev_err(rvu->dev, "%s:%d bad params\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	/* Find subbank offset from respective subbank (w.r.t bank) */
+	off = sub_off & (npc_priv.subbank_depth - 1);
+
+	/* if subsection idx is in bank1, add bank depth,
+	 * which is part of sb->b1b
+	 */
+	bot = sub_off >= npc_priv.subbank_depth ? sb->b1b : sb->b0b;
+
+	*mcam_idx = bot + off;
+	return 0;
+}
+
+static int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
+				      struct npc_subbank **sb,
+				      int *sb_off)
+{
+	int bank_off, sb_id;
+
+	/* mcam_idx should be less than (2 * bank depth) */
+	if (mcam_idx >= npc_priv.bank_depth * 2) {
+		dev_err(rvu->dev, "%s:%d bad params\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	/* find mcam offset per bank */
+	bank_off = mcam_idx & (npc_priv.bank_depth - 1);
+
+	/* Find subbank id */
+	sb_id = bank_off / npc_priv.subbank_depth;
+
+	/* Check if subbank id is more than maximum
+	 * number of subbanks available
+	 */
+	if (sb_id >= npc_priv.num_subbanks) {
+		dev_err(rvu->dev, "%s:%d invalid subbank %d\n",
+			__func__, __LINE__, sb_id);
+		return -EINVAL;
+	}
+
+	*sb = &npc_priv.sb[sb_id];
+
+	/* Subbank offset per bank */
+	*sb_off = bank_off % npc_priv.subbank_depth;
+
+	/* Index in a subbank should add subbank depth
+	 * if it is in bank1
+	 */
+	if (mcam_idx >= npc_priv.bank_depth)
+		*sb_off += npc_priv.subbank_depth;
+
+	return 0;
+}
+
+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:%d Could not find contiguous(%d) entries\n",
+				__func__, __LINE__, count);
+			return -EFAULT;
+		}
+
+		dev_dbg(rvu->dev,
+			"%s:%d sidx=%d eidx=%d t=%d b=%d offset=%d count=%d delta=%d\n",
+			__func__, __LINE__, 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:%d Could not find contiguous(%d) entries in subbbank=%u\n",
+		__func__, __LINE__, 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:%d Error happened to alloc %u, bitmap_weight=%u, sb->idx=%u\n",
+				__func__, __LINE__, 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:%d Could not find non contiguous entries(%u) in subbank(%u) cnt=%d max_alloc=%d\n",
+		__func__, __LINE__, 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:%d Marking set=%d sb_off=%d sb->idx=%d off=%d\n",
+		__func__, __LINE__, 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:%d Error to delete from xa_sb_used array\n",
+			__func__, __LINE__);
+		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:%d Error to add sb(%u) to xa_sb_free array at arr_idx=%d, val=%lu\n",
+			__func__, __LINE__,
+			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)
+
+{
+	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:%d Error to delete from xa_sb_free array\n",
+			__func__, __LINE__);
+		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:%d Error to add to xa_sb_used array\n",
+			__func__, __LINE__);
+
+	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:%d Error to free subbank\n",
+			__func__, __LINE__);
+
+done:
+	return deleted;
+}
+
+static int __maybe_unused
+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:%d Less space, count=%d idx_sz=%d sb_id=%d\n",
+			__func__, __LINE__, 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:%d Wrong ref_enty(%d) or limit(%d)\n",
+			__func__, __LINE__, 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:%d Wrong ref_enty(%d) or limit(%d) for x4\n",
+			__func__, __LINE__, 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:%d request ref and limit should be from same bank\n",
+			__func__, __LINE__);
+		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:%d Wrong ref_enty(%d) or limit(%d) for count(%d)\n",
+			__func__, __LINE__, 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:%d Less number of entries\n",
+				__func__, __LINE__);
+			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:%d subbank key_type mismatch\n",
+			__func__, __LINE__);
+		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:%d no space for entry\n",
+			__func__, __LINE__);
+		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:%d NPC block not implemented\n",
+				__func__, __LINE__);
+			goto err;
+		}
+
+		rc =  __npc_subbank_mark_used(rvu, sb, key_type);
+		if (rc) {
+			dev_err(rvu->dev, "%s:%d Error to mark subbank as used\n",
+				__func__, __LINE__);
+			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:%d Error to find mcam idx for %u\n",
+				__func__, __LINE__, 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:%d Error to mark mcam_idx %u\n",
+				__func__, __LINE__, mcam_idx[i]);
+			rc = -EFAULT;
+			goto err;
+		}
+	}
+
+err:
+	kfree(save);
+	return rc;
+}
+
+static int __maybe_unused
+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 __maybe_unused
+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:%d failed to erase mcam_idx(%u) from xa_idx2pf map\n",
+			__func__, __LINE__, 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:%d failed to erase mcam_idx(%u) from xa_pf2idx_map map\n",
+			__func__, __LINE__, mcam_idx);
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static int __maybe_unused
+npc_add_to_pf_maps(struct rvu *rvu, u16 mcam_idx, int pcifunc)
+{
+	int rc, idx;
+	void *map;
+
+	dev_dbg(rvu->dev,
+		"%s:%d add2maps mcam_idx(%u) to xa_idx2pf map pcifunc=%#x\n",
+		__func__, __LINE__, 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:%d failed to insert mcam_idx(%u) to xa_idx2pf map, existing value=%lu\n",
+			__func__, __LINE__, 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);
+		dev_err(rvu->dev,
+			"%s:%d failed to insert mcam_idx(%u) to xa_pf2idx_map map, earlier value=%lu idx=%u\n",
+			__func__, __LINE__, mcam_idx, xa_to_value(map), idx);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static bool __maybe_unused
+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 __maybe_unused
+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;
+
+	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:%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;
+			}
+			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];
+
+		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;
+}
+
+const int *npc_cn20k_search_order_get(bool *restricted_order)
+{
+	*restricted_order = restrict_valid;
+	return subbank_srch_order;
+}
+
+static void npc_populate_restricted_idxs(int num_subbanks)
+{
+	npc_subbank_restricted_idxs[0] = num_subbanks - 1;
+	npc_subbank_restricted_idxs[1] = 0;
+}
+
+static void npc_create_srch_order(int cnt)
+{
+	int val = 0;
+
+	subbank_srch_order = kcalloc(cnt, sizeof(int),
+				     GFP_KERNEL);
+
+	for (int i = 0; i < cnt; i += 2) {
+		subbank_srch_order[i] = cnt / 2 - val - 1;
+		subbank_srch_order[i + 1] = cnt / 2 + 1 + val;
+		val++;
+	}
+
+	subbank_srch_order[cnt - 1] = cnt / 2;
+}
+
+static void npc_subbank_init(struct rvu *rvu, struct npc_subbank *sb, int idx)
+{
+	mutex_init(&sb->lock);
+
+	sb->b0b = idx * npc_priv.subbank_depth;
+	sb->b0t = sb->b0b + npc_priv.subbank_depth - 1;
+
+	sb->b1b = npc_priv.bank_depth + idx * npc_priv.subbank_depth;
+	sb->b1t = sb->b1b + npc_priv.subbank_depth - 1;
+
+	sb->flags = NPC_SUBBANK_FLAG_FREE;
+	sb->idx = idx;
+	sb->arr_idx = subbank_srch_order[idx];
+
+	dev_dbg(rvu->dev, "%s:%d sb->idx=%u sb->arr_idx=%u\n",
+		__func__, __LINE__, sb->idx, sb->arr_idx);
+
+	/* Keep first and last subbank at end of free array; so that
+	 * it will be used at last
+	 */
+	xa_store(&npc_priv.xa_sb_free, sb->arr_idx,
+		 xa_mk_value(sb->idx), GFP_KERNEL);
+}
+
+static int npc_pcifunc_map_create(struct rvu *rvu)
+{
+	int pf, vf, numvfs;
+	int cnt = 0;
+	u16 pcifunc;
+	u64 cfg;
+
+	for (pf = 0; pf < rvu->hw->total_pfs; pf++) {
+		cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf));
+		numvfs = (cfg >> 12) & 0xFF;
+
+		/* Skip not enabled PFs */
+		if (!(cfg & BIT_ULL(20)))
+			goto chk_vfs;
+
+		/* If Admin function, check on VFs */
+		if (cfg & BIT_ULL(21))
+			goto chk_vfs;
+
+		pcifunc = pf << 9;
+
+		xa_store(&npc_priv.xa_pf_map, (unsigned long)pcifunc,
+			 xa_mk_value(cnt), GFP_KERNEL);
+
+		cnt++;
+
+chk_vfs:
+		for (vf = 0; vf < numvfs; vf++) {
+			pcifunc = (pf << 9) | (vf + 1);
+
+			xa_store(&npc_priv.xa_pf_map, (unsigned long)pcifunc,
+				 xa_mk_value(cnt), GFP_KERNEL);
+			cnt++;
+		}
+	}
+
+	return cnt;
+}
+
+static int npc_priv_init(struct rvu *rvu)
+{
+	struct npc_mcam *mcam = &rvu->hw->mcam;
+	int blkaddr, num_banks, bank_depth;
+	int num_subbanks, subbank_depth;
+	u64 npc_const1, npc_const2 = 0;
+	struct npc_subbank *sb;
+	u64 cfg;
+	int i;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+	if (blkaddr < 0) {
+		dev_err(rvu->dev, "%s:%d NPC block not implemented\n",
+			__func__, __LINE__);
+		return -ENODEV;
+	}
+
+	npc_const1 = rvu_read64(rvu, blkaddr, NPC_AF_CONST1);
+	if (npc_const1 & BIT_ULL(63))
+		npc_const2 = rvu_read64(rvu, blkaddr, NPC_AF_CONST2);
+
+	num_banks = mcam->banks;
+	bank_depth = mcam->banksize;
+
+	num_subbanks = FIELD_GET(GENMASK_ULL(39, 32), npc_const2);
+	npc_priv.num_subbanks = num_subbanks;
+
+	subbank_depth =	bank_depth / num_subbanks;
+
+	npc_priv.bank_depth = bank_depth;
+	npc_priv.subbank_depth = subbank_depth;
+
+	/* Get kex configured key size */
+	cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(0));
+	npc_priv.kw = FIELD_GET(GENMASK_ULL(34, 32), cfg);
+
+	dev_info(rvu->dev,
+		 "banks=%u depth=%u, subbanks=%u depth=%u, key type=%s\n",
+		 num_banks, bank_depth, num_subbanks, subbank_depth,
+		 npc_kw_name[npc_priv.kw]);
+
+	npc_priv.sb = kcalloc(num_subbanks, sizeof(struct npc_subbank),
+			      GFP_KERNEL);
+	if (!npc_priv.sb)
+		return -ENOMEM;
+
+	xa_init_flags(&npc_priv.xa_sb_used, XA_FLAGS_ALLOC);
+	xa_init_flags(&npc_priv.xa_sb_free, XA_FLAGS_ALLOC);
+	xa_init_flags(&npc_priv.xa_idx2pf_map, XA_FLAGS_ALLOC);
+	xa_init_flags(&npc_priv.xa_pf_map, XA_FLAGS_ALLOC);
+
+	npc_create_srch_order(num_subbanks);
+	npc_populate_restricted_idxs(num_subbanks);
+
+	/* Initialize subbanks */
+	for (i = 0, sb = npc_priv.sb; i < num_subbanks; i++, sb++)
+		npc_subbank_init(rvu, sb, i);
+
+	/* Get number of pcifuncs in the system */
+	npc_priv.pf_cnt = npc_pcifunc_map_create(rvu);
+	npc_priv.xa_pf2idx_map = kcalloc(npc_priv.pf_cnt, sizeof(struct xarray),
+					 GFP_KERNEL);
+	if (!npc_priv.xa_pf2idx_map)
+		return -ENOMEM;
+
+	for (i = 0; i < npc_priv.pf_cnt; i++)
+		xa_init_flags(&npc_priv.xa_pf2idx_map[i], XA_FLAGS_ALLOC);
+
+	return 0;
+}
+
+int 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);
+	return 0;
+}
+
+int npc_cn20k_init(struct rvu *rvu)
+{
+	int err;
+
+	err = npc_priv_init(rvu);
+	if (err) {
+		dev_err(rvu->dev, "%s:%d Error to init\n",
+			__func__, __LINE__);
+		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..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
+};
+
+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;
+};
+
+struct rvu;
+
+struct npc_priv_t *npc_priv_get(void);
+int npc_cn20k_init(struct rvu *rvu);
+int 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);
+int npc_cn20k_search_order_set(struct rvu *rvu, int (*arr)[2], int cnt);
+const int *npc_cn20k_search_order_get(bool *restricted_order);
+
+#endif /* NPC_CN20K_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
index affb39803120..098b0247848b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
@@ -77,5 +77,8 @@
 #define RVU_MBOX_VF_INT_ENA_W1S			(0x30)
 #define RVU_MBOX_VF_INT_ENA_W1C			(0x38)
 
+/* NPC registers */
+#define NPC_AF_MCAM_SECTIONX_CFG_EXT(a) (0xf000000ull | (a) << 3)
+
 #define RVU_MBOX_VF_VFAF_TRIGX(a)		(0x2000 | (a) << 3)
 #endif /* RVU_MBOX_REG_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h
index 8a08bebf08c2..779413a383b7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h
@@ -177,10 +177,6 @@ enum nix_scheduler {
 #define NIX_TX_ACTIONOP_MCAST		(0x3ull)
 #define NIX_TX_ACTIONOP_DROP_VIOL	(0x5ull)
 
-#define NPC_MCAM_KEY_X1			0
-#define NPC_MCAM_KEY_X2			1
-#define NPC_MCAM_KEY_X4			2
-
 #define NIX_INTFX_RX(a)			(0x0ull | (a) << 1)
 #define NIX_INTFX_TX(a)			(0x1ull | (a) << 1)
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index a3e273126e4e..73a341980f9e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -52,6 +52,14 @@
 #define MBOX_DIR_PFVF_UP	6  /* PF sends messages to VF */
 #define MBOX_DIR_VFPF_UP	7  /* VF replies to PF */
 
+enum {
+	NPC_MCAM_KEY_X1 = 0,
+	NPC_MCAM_KEY_DYN = NPC_MCAM_KEY_X1,
+	NPC_MCAM_KEY_X2,
+	NPC_MCAM_KEY_X4,
+	NPC_MCAM_KEY_MAX,
+};
+
 enum {
 	TYPE_AFVF,
 	TYPE_AFPF,
@@ -275,6 +283,8 @@ M(NPC_GET_FIELD_HASH_INFO, 0x6013, npc_get_field_hash_info,
 M(NPC_GET_FIELD_STATUS, 0x6014, npc_get_field_status,                     \
 				   npc_get_field_status_req,              \
 				   npc_get_field_status_rsp)              \
+M(NPC_CN20K_MCAM_GET_FREE_COUNT, 0x6015, npc_cn20k_get_free_count,      \
+				 msg_req, npc_cn20k_get_free_count_rsp)	\
 /* NIX mbox IDs (range 0x8000 - 0xFFFF) */				\
 M(NIX_LF_ALLOC,		0x8000, nix_lf_alloc,				\
 				 nix_lf_alloc_req, nix_lf_alloc_rsp)	\
@@ -1797,6 +1807,14 @@ struct npc_mcam_read_entry_rsp {
 	u8 enable;
 };
 
+/* Available entries to use */
+struct npc_cn20k_get_free_count_rsp {
+	struct mbox_msghdr hdr;
+	int free_x2;
+	int free_x4;
+	int free_subbanks;
+};
+
 struct npc_mcam_read_base_rule_rsp {
 	struct mbox_msghdr hdr;
 	struct mcam_entry entry;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
index 15d3cb0b9da6..425d3a43c0b8 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
@@ -3745,6 +3745,9 @@ static void rvu_dbg_npc_init(struct rvu *rvu)
 	debugfs_create_file("rx_miss_act_stats", 0444, rvu->rvu_dbg.npc, rvu,
 			    &rvu_dbg_npc_rx_miss_act_fops);
 
+	if (is_cn20k(rvu->pdev))
+		npc_cn20k_debugfs_init(rvu);
+
 	if (!rvu->hw->cap.npc_exact_match_enabled)
 		return;
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index c7c70429eb6c..6c5fe838717e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -16,6 +16,7 @@
 #include "cgx.h"
 #include "npc_profile.h"
 #include "rvu_npc_hash.h"
+#include "cn20k/npc.h"
 
 #define RSVD_MCAM_ENTRIES_PER_PF	3 /* Broadcast, Promisc and AllMulticast */
 #define RSVD_MCAM_ENTRIES_PER_NIXLF	1 /* Ucast for LFs */
@@ -2159,6 +2160,9 @@ int rvu_npc_init(struct rvu *rvu)
 		npc_load_mkex_profile(rvu, blkaddr, def_pfl_name);
 	}
 
+	if (is_cn20k(rvu->pdev))
+		return npc_cn20k_init(rvu);
+
 	return 0;
 }
 
@@ -2174,6 +2178,9 @@ void rvu_npc_freemem(struct rvu *rvu)
 	else
 		kfree(rvu->kpu_fwdata);
 	mutex_destroy(&mcam->lock);
+
+	if (is_cn20k(rvu->pdev))
+		npc_cn20k_deinit(rvu);
 }
 
 void rvu_npc_get_mcam_entry_alloc_info(struct rvu *rvu, u16 pcifunc,
@@ -3029,7 +3036,6 @@ static int __npc_mcam_alloc_counter(struct rvu *rvu,
 	if (!req->contig && req->count > NPC_MAX_NONCONTIG_COUNTERS)
 		return NPC_MCAM_INVALID_REQ;
 
-
 	/* Check if unused counters are available or not */
 	if (!rvu_rsrc_free_count(&mcam->counters)) {
 		return NPC_MCAM_ALLOC_FAILED;
-- 
2.43.0
Re: [PATCH net-next 01/13] octeontx2-af: npc: cn20k: Index management
Posted by Kalesh Anakkur Purayil 1 day, 14 hours ago
On Mon, Jan 5, 2026 at 8:04 AM Ratheesh Kannoth <rkannoth@marvell.com> wrote:
>
> In CN20K silicon, the MCAM is divided vertically into two banks.
> Each bank has a depth of 8192.
>
> The MCAM is divided horizontally into 32 subbanks, with each subbank
> having a depth of 256.
>
> Each subbank can accommodate either x2 keys or x4 keys. x2 keys are
> 256 bits in size, and x4 keys are 512 bits in size.
>
>     Bank1                   Bank0
>     |-----------------------------|
>     |               |             | subbank 31 { depth 256 }
>     |               |             |
>     |-----------------------------|
>     |               |             | subbank 30
>     |               |             |
>     ------------------------------
>     ...............................
>
>     |-----------------------------|
>     |               |             | subbank 0
>     |               |             |
>     ------------------------------|
>
> This patch implements the following allocation schemes in NPC.
> The allocation API accepts reference (ref), limit, contig, priority,
> and count values. For example, specifying ref=100, limit=200,
> contig=1, priority=LOW, and count=20 will allocate 20 contiguous
> MCAM entries between entries 100 and 200.
>
> 1. Contiguous allocation with ref, limit, and priority.
> 2. Non-contiguous allocation with ref, limit, and priority.
> 3. Non-contiguous allocation without ref.
> 4. Contiguous allocation without ref.
>
> Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
> ---
>  MAINTAINERS                                   |    2 +-
>  .../ethernet/marvell/octeontx2/af/Makefile    |    2 +-
>  .../marvell/octeontx2/af/cn20k/debugfs.c      |  182 ++
>  .../marvell/octeontx2/af/cn20k/debugfs.h      |    3 +
>  .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 1798 +++++++++++++++++
>  .../ethernet/marvell/octeontx2/af/cn20k/npc.h |   65 +
>  .../ethernet/marvell/octeontx2/af/cn20k/reg.h |    3 +
>  .../ethernet/marvell/octeontx2/af/common.h    |    4 -
>  .../net/ethernet/marvell/octeontx2/af/mbox.h  |   18 +
>  .../marvell/octeontx2/af/rvu_debugfs.c        |    3 +
>  .../ethernet/marvell/octeontx2/af/rvu_npc.c   |    8 +-
>  11 files changed, 2081 insertions(+), 7 deletions(-)
>  create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
>  create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 454b8ed119e9..0111506e8fe4 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15304,7 +15304,7 @@ M:      Subbaraya Sundeep <sbhatta@marvell.com>
>  L:     netdev@vger.kernel.org
>  S:     Maintained
>  F:     Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst
> -F:     drivers/net/ethernet/marvell/octeontx2/af/
> +F:     drivers/net/ethernet/marvell/octeontx2/af/*
>
>  MARVELL PEM PMU DRIVER
>  M:     Linu Cherian <lcherian@marvell.com>
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
> index 244de500963e..91b7d6e96a61 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
> @@ -13,4 +13,4 @@ rvu_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \
>                   rvu_cpt.o rvu_devlink.o rpm.o rvu_cn10k.o rvu_switch.o \
>                   rvu_sdp.o rvu_npc_hash.o mcs.o mcs_rvu_if.o mcs_cnf10kb.o \
>                   rvu_rep.o cn20k/mbox_init.o cn20k/nix.o cn20k/debugfs.o \
> -                 cn20k/npa.o
> +                 cn20k/npa.o cn20k/npc.o
> 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);
> +                       goto err;
> +               }
> +
> +               t1[0] = ' ';
> +               t1[strlen(t1) - 1] = ' ';
> +               t1 = strim(t1);
> +
> +               ret = kstrtoint(t1, 10, &idx);
> +               if (ret) {
> +                       pr_err("%s:%d Bad Token %s=%s\n",
> +                              __func__, __LINE__, t1, t2);
> +                       goto err;
> +               }
> +
> +               ret = kstrtoint(t2, 10, &val);
> +               if (ret) {
> +                       pr_err("%s:%d Bad Token %s=%s\n",
> +                              __func__, __LINE__, t1, t2);
> +                       goto err;
> +               }
> +
> +               (*(arr + cnt))[0] = idx;
> +               (*(arr + cnt))[1] = val;
> +
> +               cnt++;
> +       }
> +
> +       if (cnt != num_subbanks) {
> +               pr_err("Could find %u tokens, but exact %u tokens needed\n",
> +                      cnt, num_subbanks);
> +               goto err;
> +       }
> +
> +       for (int i = 0; i < cnt; i++) {
> +               w1 |= BIT_ULL((*(arr + i))[0]);
> +               w2 |= BIT_ULL((*(arr + i))[1]);
> +       }
> +
> +       if (bitmap_weight(&w1, cnt) != cnt) {
> +               pr_err("Missed to fill for [%lu]=\n",
> +                      find_first_zero_bit(&w1, cnt));
> +               goto err;
> +       }
> +
> +       if (bitmap_weight(&w2, cnt) != cnt) {
> +               pr_err("Missed to fill value %lu\n",
> +                      find_first_zero_bit(&w2, cnt));
> +               goto err;
> +       }
> +
> +       npc_cn20k_search_order_set(rvu, arr, cnt);
> +
> +       kfree(arr);
> +       return 0;
> +err:
> +       kfree(arr);
> +       return -EINVAL;
> +}
> +
> +static ssize_t
> +npc_subbank_srch_order_write(struct file *file, const char __user *user_buf,
> +                            size_t count, loff_t *ppos)
> +{
> +       struct npc_priv_t *npc_priv;
> +       struct rvu *rvu;
> +       char buf[1024];
> +       int len;
> +
> +       npc_priv = npc_priv_get();
> +
> +       rvu = file->private_data;
> +
> +       len = simple_write_to_buffer(buf, sizeof(buf), ppos,
> +                                    user_buf, count);
> +       if (npc_subbank_srch_order_parse_n_fill(rvu, buf,
> +                                               npc_priv->num_subbanks)) {
> +               npc_subbank_srch_order_dbgfs_usage();
> +               return -EFAULT;
> +       }
> +
> +       return len;
> +}
> +
> +static ssize_t
> +npc_subbank_srch_order_read(struct file *file, char __user *user_buf,
> +                           size_t count, loff_t *ppos)
> +{
> +       struct npc_priv_t *npc_priv;
> +       bool restricted_order;
> +       const int *srch_order;
> +       char buf[1024];
> +       int len = 0;
> +
> +       npc_priv = npc_priv_get();
> +
> +       len += snprintf(buf + len, sizeof(buf) - len, "%s",
> +                       "Usage: echo \"[0]=0,[1]=1,[2]=2,..[31]=31\" > <debugfs>/subbank_srch_order\n");
> +
> +       len += snprintf(buf + len, sizeof(buf) - len, "%s",
> +                       "Search order\n");
> +
> +       srch_order = npc_cn20k_search_order_get(&restricted_order);
> +
> +       for (int i = 0;  i < npc_priv->num_subbanks; i++)
> +               len += snprintf(buf + len, sizeof(buf) - len, "[%d]=%d,",
> +                               i, srch_order[i]);
> +
> +       len += snprintf(buf + len - 1, sizeof(buf) - len, "%s", "\n");
> +
> +       if (restricted_order)
> +               len += snprintf(buf + len, sizeof(buf) - len,
> +                               "Restricted allocation for subbanks %u, %u\n",
> +                               npc_priv->num_subbanks - 1, 0);
> +
> +       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
> +}
> +
> +static const struct file_operations npc_subbank_srch_order_ops = {
> +       .open           = simple_open,
> +       .write          = npc_subbank_srch_order_write,
> +       .read           = npc_subbank_srch_order_read,
> +};
> +
> +int npc_cn20k_debugfs_init(struct rvu *rvu)
> +{
> +       struct dentry *npc_dentry;
> +
> +       npc_dentry = debugfs_create_file("subbank_srch_order", 0644,
> +                                        rvu->rvu_dbg.npc,
> +                                        rvu, &npc_subbank_srch_order_ops);
> +       if (!npc_dentry)
> +               return -EFAULT;
> +
> +       return 0;
> +}
> +
> +void npc_cn20k_debugfs_deinit(struct rvu *rvu)
> +{
> +       debugfs_remove_recursive(rvu->rvu_dbg.npc);
> +}
>
>  void print_nix_cn20k_sq_ctx(struct seq_file *m,
>                             struct nix_cn20k_sq_ctx_s *sq_ctx)
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
> index a2e3a2cd6edb..0c5f05883666 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
> @@ -16,6 +16,9 @@
>  #include "struct.h"
>  #include "../mbox.h"
>
> +int npc_cn20k_debugfs_init(struct rvu *rvu);
> +void npc_cn20k_debugfs_deinit(struct rvu *rvu);
> +
>  void print_nix_cn20k_sq_ctx(struct seq_file *m,
>                             struct nix_cn20k_sq_ctx_s *sq_ctx);
>  void print_nix_cn20k_cq_ctx(struct seq_file *m,
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
> new file mode 100644
> index 000000000000..27b049ac4ae8
> --- /dev/null
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
> @@ -0,0 +1,1798 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Marvell RVU Admin Function driver
> + *
> + * Copyright (C) 2026 Marvell.
> + *
> + */
> +#include <linux/xarray.h>
> +#include <linux/bitfield.h>
> +
> +#include "cn20k/npc.h"
> +#include "cn20k/reg.h"
> +
> +static struct npc_priv_t npc_priv = {
> +       .num_banks = MAX_NUM_BANKS,
> +};
> +
> +static const char *npc_kw_name[NPC_MCAM_KEY_MAX] = {
> +       [NPC_MCAM_KEY_DYN] = "DYNAMIC",
> +       [NPC_MCAM_KEY_X2] = "X2",
> +       [NPC_MCAM_KEY_X4] = "X4",
> +};
> +
> +struct npc_priv_t *npc_priv_get(void)
> +{
> +       return &npc_priv;
> +}
> +
> +static int npc_subbank_idx_2_mcam_idx(struct rvu *rvu, struct npc_subbank *sb,
> +                                     u16 sub_off, u16 *mcam_idx)
> +{
> +       int off, bot;
> +
> +       /* for x4 section, maximum allowed subbank index =
> +        * subsection depth - 1
> +        */
> +       if (sb->key_type == NPC_MCAM_KEY_X4 &&
> +           sub_off >= npc_priv.subbank_depth) {
> +               dev_err(rvu->dev, "%s:%d bad params\n",
> +                       __func__, __LINE__);
> +               return -EINVAL;
> +       }
> +
> +       /* for x2 section, maximum allowed subbank index =
> +        * 2 * subsection depth - 1
> +        */
> +       if (sb->key_type == NPC_MCAM_KEY_X2 &&
> +           sub_off >= npc_priv.subbank_depth * 2) {
> +               dev_err(rvu->dev, "%s:%d bad params\n",
> +                       __func__, __LINE__);
> +               return -EINVAL;
> +       }
> +
> +       /* Find subbank offset from respective subbank (w.r.t bank) */
> +       off = sub_off & (npc_priv.subbank_depth - 1);
> +
> +       /* if subsection idx is in bank1, add bank depth,
> +        * which is part of sb->b1b
> +        */
> +       bot = sub_off >= npc_priv.subbank_depth ? sb->b1b : sb->b0b;
> +
> +       *mcam_idx = bot + off;
> +       return 0;
> +}
> +
> +static int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
> +                                     struct npc_subbank **sb,
> +                                     int *sb_off)
> +{
> +       int bank_off, sb_id;
> +
> +       /* mcam_idx should be less than (2 * bank depth) */
> +       if (mcam_idx >= npc_priv.bank_depth * 2) {
> +               dev_err(rvu->dev, "%s:%d bad params\n",
> +                       __func__, __LINE__);
> +               return -EINVAL;
> +       }
> +
> +       /* find mcam offset per bank */
> +       bank_off = mcam_idx & (npc_priv.bank_depth - 1);
> +
> +       /* Find subbank id */
> +       sb_id = bank_off / npc_priv.subbank_depth;
> +
> +       /* Check if subbank id is more than maximum
> +        * number of subbanks available
> +        */
> +       if (sb_id >= npc_priv.num_subbanks) {
> +               dev_err(rvu->dev, "%s:%d invalid subbank %d\n",
> +                       __func__, __LINE__, sb_id);
> +               return -EINVAL;
> +       }
> +
> +       *sb = &npc_priv.sb[sb_id];
> +
> +       /* Subbank offset per bank */
> +       *sb_off = bank_off % npc_priv.subbank_depth;
> +
> +       /* Index in a subbank should add subbank depth
> +        * if it is in bank1
> +        */
> +       if (mcam_idx >= npc_priv.bank_depth)
> +               *sb_off += npc_priv.subbank_depth;
> +
> +       return 0;
> +}
> +
> +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:%d Could not find contiguous(%d) entries\n",
> +                               __func__, __LINE__, count);
> +                       return -EFAULT;
> +               }
> +
> +               dev_dbg(rvu->dev,
> +                       "%s:%d sidx=%d eidx=%d t=%d b=%d offset=%d count=%d delta=%d\n",
> +                       __func__, __LINE__, 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:%d Could not find contiguous(%d) entries in subbbank=%u\n",
> +               __func__, __LINE__, 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:%d Error happened to alloc %u, bitmap_weight=%u, sb->idx=%u\n",
> +                               __func__, __LINE__, 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:%d Could not find non contiguous entries(%u) in subbank(%u) cnt=%d max_alloc=%d\n",
> +               __func__, __LINE__, 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:%d Marking set=%d sb_off=%d sb->idx=%d off=%d\n",
> +               __func__, __LINE__, 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:%d Error to delete from xa_sb_used array\n",
> +                       __func__, __LINE__);
> +               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:%d Error to add sb(%u) to xa_sb_free array at arr_idx=%d, val=%lu\n",
> +                       __func__, __LINE__,
> +                       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)
> +
> +{
> +       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:%d Error to delete from xa_sb_free array\n",
> +                       __func__, __LINE__);
> +               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:%d Error to add to xa_sb_used array\n",
> +                       __func__, __LINE__);
> +
> +       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:%d Error to free subbank\n",
> +                       __func__, __LINE__);
> +
> +done:
> +       return deleted;
> +}
> +
> +static int __maybe_unused
> +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:%d Less space, count=%d idx_sz=%d sb_id=%d\n",
> +                       __func__, __LINE__, 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:%d Wrong ref_enty(%d) or limit(%d)\n",
> +                       __func__, __LINE__, 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:%d Wrong ref_enty(%d) or limit(%d) for x4\n",
> +                       __func__, __LINE__, 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:%d request ref and limit should be from same bank\n",
> +                       __func__, __LINE__);
> +               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:%d Wrong ref_enty(%d) or limit(%d) for count(%d)\n",
> +                       __func__, __LINE__, 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:%d Less number of entries\n",
> +                               __func__, __LINE__);
> +                       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:%d subbank key_type mismatch\n",
> +                       __func__, __LINE__);
> +               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:%d no space for entry\n",
> +                       __func__, __LINE__);
> +               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:%d NPC block not implemented\n",
> +                               __func__, __LINE__);
> +                       goto err;
> +               }
> +
> +               rc =  __npc_subbank_mark_used(rvu, sb, key_type);
> +               if (rc) {
> +                       dev_err(rvu->dev, "%s:%d Error to mark subbank as used\n",
> +                               __func__, __LINE__);
> +                       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:%d Error to find mcam idx for %u\n",
> +                               __func__, __LINE__, 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:%d Error to mark mcam_idx %u\n",
> +                               __func__, __LINE__, mcam_idx[i]);
> +                       rc = -EFAULT;
> +                       goto err;
> +               }
> +       }
> +
> +err:
> +       kfree(save);
> +       return rc;
> +}
> +
> +static int __maybe_unused
> +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 __maybe_unused
> +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:%d failed to erase mcam_idx(%u) from xa_idx2pf map\n",
> +                       __func__, __LINE__, 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:%d failed to erase mcam_idx(%u) from xa_pf2idx_map map\n",
> +                       __func__, __LINE__, mcam_idx);
> +               return -EFAULT;
> +       }
> +       return 0;
> +}
> +
> +static int __maybe_unused
> +npc_add_to_pf_maps(struct rvu *rvu, u16 mcam_idx, int pcifunc)
> +{
> +       int rc, idx;
> +       void *map;
> +
> +       dev_dbg(rvu->dev,
> +               "%s:%d add2maps mcam_idx(%u) to xa_idx2pf map pcifunc=%#x\n",
> +               __func__, __LINE__, 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:%d failed to insert mcam_idx(%u) to xa_idx2pf map, existing value=%lu\n",
> +                       __func__, __LINE__, 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);
> +               dev_err(rvu->dev,
> +                       "%s:%d failed to insert mcam_idx(%u) to xa_pf2idx_map map, earlier value=%lu idx=%u\n",
> +                       __func__, __LINE__, mcam_idx, xa_to_value(map), idx);
> +               return -EFAULT;
> +       }
> +
> +       return 0;
> +}
> +
> +static bool __maybe_unused
> +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 __maybe_unused
> +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;
> +
> +       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:%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;
> +                       }
> +                       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;
[Kalesh] consider changing it to a void function as it unconditionally 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;
[Kalesh] follow RCT order
> +       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)
[Kalesh] missing kfree(fslots);
> +               return -ENOMEM;
> +
> +       for (int i = 0; i < cnt; i++, arr++) {
> +               idx = (*arr)[0];
> +               val = (*arr)[1];
> +
> +               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;
> +}
> +
> +const int *npc_cn20k_search_order_get(bool *restricted_order)
> +{
> +       *restricted_order = restrict_valid;
> +       return subbank_srch_order;
> +}
> +
> +static void npc_populate_restricted_idxs(int num_subbanks)
> +{
> +       npc_subbank_restricted_idxs[0] = num_subbanks - 1;
> +       npc_subbank_restricted_idxs[1] = 0;
> +}
> +
> +static void npc_create_srch_order(int cnt)
> +{
> +       int val = 0;
> +
> +       subbank_srch_order = kcalloc(cnt, sizeof(int),
> +                                    GFP_KERNEL);
[Kalesh] missing check for memory allocation failure
> +
> +       for (int i = 0; i < cnt; i += 2) {
> +               subbank_srch_order[i] = cnt / 2 - val - 1;
> +               subbank_srch_order[i + 1] = cnt / 2 + 1 + val;
> +               val++;
> +       }
> +
> +       subbank_srch_order[cnt - 1] = cnt / 2;
> +}
> +
> +static void npc_subbank_init(struct rvu *rvu, struct npc_subbank *sb, int idx)
> +{
> +       mutex_init(&sb->lock);
> +
> +       sb->b0b = idx * npc_priv.subbank_depth;
> +       sb->b0t = sb->b0b + npc_priv.subbank_depth - 1;
> +
> +       sb->b1b = npc_priv.bank_depth + idx * npc_priv.subbank_depth;
> +       sb->b1t = sb->b1b + npc_priv.subbank_depth - 1;
> +
> +       sb->flags = NPC_SUBBANK_FLAG_FREE;
> +       sb->idx = idx;
> +       sb->arr_idx = subbank_srch_order[idx];
> +
> +       dev_dbg(rvu->dev, "%s:%d sb->idx=%u sb->arr_idx=%u\n",
> +               __func__, __LINE__, sb->idx, sb->arr_idx);
> +
> +       /* Keep first and last subbank at end of free array; so that
> +        * it will be used at last
> +        */
> +       xa_store(&npc_priv.xa_sb_free, sb->arr_idx,
> +                xa_mk_value(sb->idx), GFP_KERNEL);
> +}
> +
> +static int npc_pcifunc_map_create(struct rvu *rvu)
> +{
> +       int pf, vf, numvfs;
> +       int cnt = 0;
> +       u16 pcifunc;
[Kalesh]: follow RCT order
> +       u64 cfg;
> +
> +       for (pf = 0; pf < rvu->hw->total_pfs; pf++) {
> +               cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf));
> +               numvfs = (cfg >> 12) & 0xFF;
> +
> +               /* Skip not enabled PFs */
> +               if (!(cfg & BIT_ULL(20)))
> +                       goto chk_vfs;
> +
> +               /* If Admin function, check on VFs */
> +               if (cfg & BIT_ULL(21))
> +                       goto chk_vfs;
> +
> +               pcifunc = pf << 9;
> +
> +               xa_store(&npc_priv.xa_pf_map, (unsigned long)pcifunc,
> +                        xa_mk_value(cnt), GFP_KERNEL);
> +
> +               cnt++;
> +
> +chk_vfs:
> +               for (vf = 0; vf < numvfs; vf++) {
> +                       pcifunc = (pf << 9) | (vf + 1);
> +
> +                       xa_store(&npc_priv.xa_pf_map, (unsigned long)pcifunc,
> +                                xa_mk_value(cnt), GFP_KERNEL);
> +                       cnt++;
> +               }
> +       }
> +
> +       return cnt;
> +}
> +
> +static int npc_priv_init(struct rvu *rvu)
> +{
> +       struct npc_mcam *mcam = &rvu->hw->mcam;
> +       int blkaddr, num_banks, bank_depth;
> +       int num_subbanks, subbank_depth;
> +       u64 npc_const1, npc_const2 = 0;
> +       struct npc_subbank *sb;
> +       u64 cfg;
> +       int i;
> +
> +       blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
> +       if (blkaddr < 0) {
> +               dev_err(rvu->dev, "%s:%d NPC block not implemented\n",
> +                       __func__, __LINE__);
> +               return -ENODEV;
> +       }
> +
> +       npc_const1 = rvu_read64(rvu, blkaddr, NPC_AF_CONST1);
> +       if (npc_const1 & BIT_ULL(63))
> +               npc_const2 = rvu_read64(rvu, blkaddr, NPC_AF_CONST2);
> +
> +       num_banks = mcam->banks;
> +       bank_depth = mcam->banksize;
> +
> +       num_subbanks = FIELD_GET(GENMASK_ULL(39, 32), npc_const2);
> +       npc_priv.num_subbanks = num_subbanks;
> +
> +       subbank_depth = bank_depth / num_subbanks;
> +
> +       npc_priv.bank_depth = bank_depth;
> +       npc_priv.subbank_depth = subbank_depth;
> +
> +       /* Get kex configured key size */
> +       cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(0));
> +       npc_priv.kw = FIELD_GET(GENMASK_ULL(34, 32), cfg);
> +
> +       dev_info(rvu->dev,
> +                "banks=%u depth=%u, subbanks=%u depth=%u, key type=%s\n",
> +                num_banks, bank_depth, num_subbanks, subbank_depth,
> +                npc_kw_name[npc_priv.kw]);
> +
> +       npc_priv.sb = kcalloc(num_subbanks, sizeof(struct npc_subbank),
> +                             GFP_KERNEL);
> +       if (!npc_priv.sb)
> +               return -ENOMEM;
> +
> +       xa_init_flags(&npc_priv.xa_sb_used, XA_FLAGS_ALLOC);
> +       xa_init_flags(&npc_priv.xa_sb_free, XA_FLAGS_ALLOC);
> +       xa_init_flags(&npc_priv.xa_idx2pf_map, XA_FLAGS_ALLOC);
> +       xa_init_flags(&npc_priv.xa_pf_map, XA_FLAGS_ALLOC);
> +
> +       npc_create_srch_order(num_subbanks);
> +       npc_populate_restricted_idxs(num_subbanks);
> +
> +       /* Initialize subbanks */
> +       for (i = 0, sb = npc_priv.sb; i < num_subbanks; i++, sb++)
> +               npc_subbank_init(rvu, sb, i);
> +
> +       /* Get number of pcifuncs in the system */
> +       npc_priv.pf_cnt = npc_pcifunc_map_create(rvu);
> +       npc_priv.xa_pf2idx_map = kcalloc(npc_priv.pf_cnt, sizeof(struct xarray),
> +                                        GFP_KERNEL);
> +       if (!npc_priv.xa_pf2idx_map)
[Kalesh] missing kfree(npc_priv.sb);
> +               return -ENOMEM;
> +
> +       for (i = 0; i < npc_priv.pf_cnt; i++)
> +               xa_init_flags(&npc_priv.xa_pf2idx_map[i], XA_FLAGS_ALLOC);
> +
> +       return 0;
> +}
> +
> +int npc_cn20k_deinit(struct rvu *rvu)
[Kalesh] You can change it to a void function as it unconditionally return 0
> +{
> +       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);
> +       return 0;
> +}
> +
> +int npc_cn20k_init(struct rvu *rvu)
> +{
> +       int err;
> +
> +       err = npc_priv_init(rvu);
> +       if (err) {
> +               dev_err(rvu->dev, "%s:%d Error to init\n",
> +                       __func__, __LINE__);
> +               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..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.
[Kalesh] I think the // comments are prohibited
> +       NPC_SUBBANK_FLAG_FREE = BIT(0), // No slot allocated
> +       NPC_SUBBANK_FLAG_USED = BIT(1), // At least one slot allocated
> +};
> +
> +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;
> +};
> +
> +struct rvu;
> +
> +struct npc_priv_t *npc_priv_get(void);
> +int npc_cn20k_init(struct rvu *rvu);
> +int 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);
> +int npc_cn20k_search_order_set(struct rvu *rvu, int (*arr)[2], int cnt);
> +const int *npc_cn20k_search_order_get(bool *restricted_order);
> +
> +#endif /* NPC_CN20K_H */
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
> index affb39803120..098b0247848b 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
> @@ -77,5 +77,8 @@
>  #define RVU_MBOX_VF_INT_ENA_W1S                        (0x30)
>  #define RVU_MBOX_VF_INT_ENA_W1C                        (0x38)
>
> +/* NPC registers */
> +#define NPC_AF_MCAM_SECTIONX_CFG_EXT(a) (0xf000000ull | (a) << 3)
> +
>  #define RVU_MBOX_VF_VFAF_TRIGX(a)              (0x2000 | (a) << 3)
>  #endif /* RVU_MBOX_REG_H */
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h
> index 8a08bebf08c2..779413a383b7 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h
> @@ -177,10 +177,6 @@ enum nix_scheduler {
>  #define NIX_TX_ACTIONOP_MCAST          (0x3ull)
>  #define NIX_TX_ACTIONOP_DROP_VIOL      (0x5ull)
>
> -#define NPC_MCAM_KEY_X1                        0
> -#define NPC_MCAM_KEY_X2                        1
> -#define NPC_MCAM_KEY_X4                        2
> -
>  #define NIX_INTFX_RX(a)                        (0x0ull | (a) << 1)
>  #define NIX_INTFX_TX(a)                        (0x1ull | (a) << 1)
>
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
> index a3e273126e4e..73a341980f9e 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
> @@ -52,6 +52,14 @@
>  #define MBOX_DIR_PFVF_UP       6  /* PF sends messages to VF */
>  #define MBOX_DIR_VFPF_UP       7  /* VF replies to PF */
>
> +enum {
> +       NPC_MCAM_KEY_X1 = 0,
> +       NPC_MCAM_KEY_DYN = NPC_MCAM_KEY_X1,
> +       NPC_MCAM_KEY_X2,
> +       NPC_MCAM_KEY_X4,
> +       NPC_MCAM_KEY_MAX,
> +};
> +
>  enum {
>         TYPE_AFVF,
>         TYPE_AFPF,
> @@ -275,6 +283,8 @@ M(NPC_GET_FIELD_HASH_INFO, 0x6013, npc_get_field_hash_info,
>  M(NPC_GET_FIELD_STATUS, 0x6014, npc_get_field_status,                     \
>                                    npc_get_field_status_req,              \
>                                    npc_get_field_status_rsp)              \
> +M(NPC_CN20K_MCAM_GET_FREE_COUNT, 0x6015, npc_cn20k_get_free_count,      \
> +                                msg_req, npc_cn20k_get_free_count_rsp) \
>  /* NIX mbox IDs (range 0x8000 - 0xFFFF) */                             \
>  M(NIX_LF_ALLOC,                0x8000, nix_lf_alloc,                           \
>                                  nix_lf_alloc_req, nix_lf_alloc_rsp)    \
> @@ -1797,6 +1807,14 @@ struct npc_mcam_read_entry_rsp {
>         u8 enable;
>  };
>
> +/* Available entries to use */
> +struct npc_cn20k_get_free_count_rsp {
> +       struct mbox_msghdr hdr;
> +       int free_x2;
> +       int free_x4;
> +       int free_subbanks;
> +};
> +
>  struct npc_mcam_read_base_rule_rsp {
>         struct mbox_msghdr hdr;
>         struct mcam_entry entry;
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
> index 15d3cb0b9da6..425d3a43c0b8 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
> @@ -3745,6 +3745,9 @@ static void rvu_dbg_npc_init(struct rvu *rvu)
>         debugfs_create_file("rx_miss_act_stats", 0444, rvu->rvu_dbg.npc, rvu,
>                             &rvu_dbg_npc_rx_miss_act_fops);
>
> +       if (is_cn20k(rvu->pdev))
> +               npc_cn20k_debugfs_init(rvu);
> +
>         if (!rvu->hw->cap.npc_exact_match_enabled)
>                 return;
>
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> index c7c70429eb6c..6c5fe838717e 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> @@ -16,6 +16,7 @@
>  #include "cgx.h"
>  #include "npc_profile.h"
>  #include "rvu_npc_hash.h"
> +#include "cn20k/npc.h"
>
>  #define RSVD_MCAM_ENTRIES_PER_PF       3 /* Broadcast, Promisc and AllMulticast */
>  #define RSVD_MCAM_ENTRIES_PER_NIXLF    1 /* Ucast for LFs */
> @@ -2159,6 +2160,9 @@ int rvu_npc_init(struct rvu *rvu)
>                 npc_load_mkex_profile(rvu, blkaddr, def_pfl_name);
>         }
>
> +       if (is_cn20k(rvu->pdev))
> +               return npc_cn20k_init(rvu);
> +
>         return 0;
>  }
>
> @@ -2174,6 +2178,9 @@ void rvu_npc_freemem(struct rvu *rvu)
>         else
>                 kfree(rvu->kpu_fwdata);
>         mutex_destroy(&mcam->lock);
> +
> +       if (is_cn20k(rvu->pdev))
> +               npc_cn20k_deinit(rvu);
>  }
>
>  void rvu_npc_get_mcam_entry_alloc_info(struct rvu *rvu, u16 pcifunc,
> @@ -3029,7 +3036,6 @@ static int __npc_mcam_alloc_counter(struct rvu *rvu,
>         if (!req->contig && req->count > NPC_MAX_NONCONTIG_COUNTERS)
>                 return NPC_MCAM_INVALID_REQ;
>
> -
[Kalesh] looks unrelated change
>         /* Check if unused counters are available or not */
>         if (!rvu_rsrc_free_count(&mcam->counters)) {
>                 return NPC_MCAM_ALLOC_FAILED;
> --
> 2.43.0
>
>


-- 
Regards,
Kalesh AP
Re: [PATCH net-next 01/13] octeontx2-af: npc: cn20k: Index management
Posted by Ratheesh Kannoth 1 day, 13 hours ago
On 2026-01-06 at 13:45:21, Kalesh Anakkur Purayil (kalesh-anakkur.purayil@broadcom.com) wrote:
> On Mon, Jan 5, 2026 at 8:04 AM Ratheesh Kannoth <rkannoth@marvell.com> wrote:
> >
> > In CN20K silicon, the MCAM is divided vertically into two banks.
> > Each bank has a depth of 8192.
> >
> > The MCAM is divided horizontally into 32 subbanks, with each subbank
> > having a depth of 256.
> >
> > Each subbank can accommodate either x2 keys or x4 keys. x2 keys are
> > 256 bits in size, and x4 keys are 512 bits in size.
> >
> >     Bank1                   Bank0
> >     |-----------------------------|
> >     |               |             | subbank 31 { depth 256 }
> >     |               |             |
> >     |-----------------------------|
> >     |               |             | subbank 30
> >     |               |             |
> >     ------------------------------
> >     ...............................
> >
> >     |-----------------------------|
> >     |               |             | subbank 0
> >     |               |             |
> >     ------------------------------|
> >
> > This patch implements the following allocation schemes in NPC.
> > The allocation API accepts reference (ref), limit, contig, priority,
> > and count values. For example, specifying ref=100, limit=200,
> > contig=1, priority=LOW, and count=20 will allocate 20 contiguous
> > MCAM entries between entries 100 and 200.
> >
> > 1. Contiguous allocation with ref, limit, and priority.
> > 2. Non-contiguous allocation with ref, limit, and priority.
> > 3. Non-contiguous allocation without ref.
> > 4. Contiguous allocation without ref.
> >
> > Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
> > ---
> >  MAINTAINERS                                   |    2 +-
> >  .../ethernet/marvell/octeontx2/af/Makefile    |    2 +-
> >  .../marvell/octeontx2/af/cn20k/debugfs.c      |  182 ++
> >  .../marvell/octeontx2/af/cn20k/debugfs.h      |    3 +
> >  .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 1798 +++++++++++++++++
> >  .../ethernet/marvell/octeontx2/af/cn20k/npc.h |   65 +
> >  .../ethernet/marvell/octeontx2/af/cn20k/reg.h |    3 +
> >  .../ethernet/marvell/octeontx2/af/common.h    |    4 -
> >  .../net/ethernet/marvell/octeontx2/af/mbox.h  |   18 +
> >  .../marvell/octeontx2/af/rvu_debugfs.c        |    3 +
> >  .../ethernet/marvell/octeontx2/af/rvu_npc.c   |    8 +-
> >  11 files changed, 2081 insertions(+), 7 deletions(-)
> >  create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
> >  create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 454b8ed119e9..0111506e8fe4 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -15304,7 +15304,7 @@ M:      Subbaraya Sundeep <sbhatta@marvell.com>
> >  L:     netdev@vger.kernel.org
> >  S:     Maintained
> >  F:     Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst
> > -F:     drivers/net/ethernet/marvell/octeontx2/af/
> > +F:     drivers/net/ethernet/marvell/octeontx2/af/*
> >
> >  MARVELL PEM PMU DRIVER
> >  M:     Linu Cherian <lcherian@marvell.com>
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
> > index 244de500963e..91b7d6e96a61 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile
> > +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
> > @@ -13,4 +13,4 @@ rvu_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \
> >                   rvu_cpt.o rvu_devlink.o rpm.o rvu_cn10k.o rvu_switch.o \
> >                   rvu_sdp.o rvu_npc_hash.o mcs.o mcs_rvu_if.o mcs_cnf10kb.o \
> >                   rvu_rep.o cn20k/mbox_init.o cn20k/nix.o cn20k/debugfs.o \
> > -                 cn20k/npa.o
> > +                 cn20k/npa.o cn20k/npc.o
> > 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);
> > +                       goto err;
> > +               }
> > +
> > +               t1[0] = ' ';
> > +               t1[strlen(t1) - 1] = ' ';
> > +               t1 = strim(t1);
> > +
> > +               ret = kstrtoint(t1, 10, &idx);
> > +               if (ret) {
> > +                       pr_err("%s:%d Bad Token %s=%s\n",
> > +                              __func__, __LINE__, t1, t2);
> > +                       goto err;
> > +               }
> > +
> > +               ret = kstrtoint(t2, 10, &val);
> > +               if (ret) {
> > +                       pr_err("%s:%d Bad Token %s=%s\n",
> > +                              __func__, __LINE__, t1, t2);
> > +                       goto err;
> > +               }
> > +
> > +               (*(arr + cnt))[0] = idx;
> > +               (*(arr + cnt))[1] = val;
> > +
> > +               cnt++;
> > +       }
> > +
> > +       if (cnt != num_subbanks) {
> > +               pr_err("Could find %u tokens, but exact %u tokens needed\n",
> > +                      cnt, num_subbanks);
> > +               goto err;
> > +       }
> > +
> > +       for (int i = 0; i < cnt; i++) {
> > +               w1 |= BIT_ULL((*(arr + i))[0]);
> > +               w2 |= BIT_ULL((*(arr + i))[1]);
> > +       }
> > +
> > +       if (bitmap_weight(&w1, cnt) != cnt) {
> > +               pr_err("Missed to fill for [%lu]=\n",
> > +                      find_first_zero_bit(&w1, cnt));
> > +               goto err;
> > +       }
> > +
> > +       if (bitmap_weight(&w2, cnt) != cnt) {
> > +               pr_err("Missed to fill value %lu\n",
> > +                      find_first_zero_bit(&w2, cnt));
> > +               goto err;
> > +       }
> > +
> > +       npc_cn20k_search_order_set(rvu, arr, cnt);
> > +
> > +       kfree(arr);
> > +       return 0;
> > +err:
> > +       kfree(arr);
> > +       return -EINVAL;
> > +}
> > +
> > +static ssize_t
> > +npc_subbank_srch_order_write(struct file *file, const char __user *user_buf,
> > +                            size_t count, loff_t *ppos)
> > +{
> > +       struct npc_priv_t *npc_priv;
> > +       struct rvu *rvu;
> > +       char buf[1024];
> > +       int len;
> > +
> > +       npc_priv = npc_priv_get();
> > +
> > +       rvu = file->private_data;
> > +
> > +       len = simple_write_to_buffer(buf, sizeof(buf), ppos,
> > +                                    user_buf, count);
> > +       if (npc_subbank_srch_order_parse_n_fill(rvu, buf,
> > +                                               npc_priv->num_subbanks)) {
> > +               npc_subbank_srch_order_dbgfs_usage();
> > +               return -EFAULT;
> > +       }
> > +
> > +       return len;
> > +}
> > +
> > +static ssize_t
> > +npc_subbank_srch_order_read(struct file *file, char __user *user_buf,
> > +                           size_t count, loff_t *ppos)
> > +{
> > +       struct npc_priv_t *npc_priv;
> > +       bool restricted_order;
> > +       const int *srch_order;
> > +       char buf[1024];
> > +       int len = 0;
> > +
> > +       npc_priv = npc_priv_get();
> > +
> > +       len += snprintf(buf + len, sizeof(buf) - len, "%s",
> > +                       "Usage: echo \"[0]=0,[1]=1,[2]=2,..[31]=31\" > <debugfs>/subbank_srch_order\n");
> > +
> > +       len += snprintf(buf + len, sizeof(buf) - len, "%s",
> > +                       "Search order\n");
> > +
> > +       srch_order = npc_cn20k_search_order_get(&restricted_order);
> > +
> > +       for (int i = 0;  i < npc_priv->num_subbanks; i++)
> > +               len += snprintf(buf + len, sizeof(buf) - len, "[%d]=%d,",
> > +                               i, srch_order[i]);
> > +
> > +       len += snprintf(buf + len - 1, sizeof(buf) - len, "%s", "\n");
> > +
> > +       if (restricted_order)
> > +               len += snprintf(buf + len, sizeof(buf) - len,
> > +                               "Restricted allocation for subbanks %u, %u\n",
> > +                               npc_priv->num_subbanks - 1, 0);
> > +
> > +       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
> > +}
> > +
> > +static const struct file_operations npc_subbank_srch_order_ops = {
> > +       .open           = simple_open,
> > +       .write          = npc_subbank_srch_order_write,
> > +       .read           = npc_subbank_srch_order_read,
> > +};
> > +
> > +int npc_cn20k_debugfs_init(struct rvu *rvu)
> > +{
> > +       struct dentry *npc_dentry;
> > +
> > +       npc_dentry = debugfs_create_file("subbank_srch_order", 0644,
> > +                                        rvu->rvu_dbg.npc,
> > +                                        rvu, &npc_subbank_srch_order_ops);
> > +       if (!npc_dentry)
> > +               return -EFAULT;
> > +
> > +       return 0;
> > +}
> > +
> > +void npc_cn20k_debugfs_deinit(struct rvu *rvu)
> > +{
> > +       debugfs_remove_recursive(rvu->rvu_dbg.npc);
> > +}
> >
> >  void print_nix_cn20k_sq_ctx(struct seq_file *m,
> >                             struct nix_cn20k_sq_ctx_s *sq_ctx)
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
> > index a2e3a2cd6edb..0c5f05883666 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
> > +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
> > @@ -16,6 +16,9 @@
> >  #include "struct.h"
> >  #include "../mbox.h"
> >
> > +int npc_cn20k_debugfs_init(struct rvu *rvu);
> > +void npc_cn20k_debugfs_deinit(struct rvu *rvu);
> > +
> >  void print_nix_cn20k_sq_ctx(struct seq_file *m,
> >                             struct nix_cn20k_sq_ctx_s *sq_ctx);
> >  void print_nix_cn20k_cq_ctx(struct seq_file *m,
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
> > new file mode 100644
> > index 000000000000..27b049ac4ae8
> > --- /dev/null
> > +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
> > @@ -0,0 +1,1798 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/* Marvell RVU Admin Function driver
> > + *
> > + * Copyright (C) 2026 Marvell.
> > + *
> > + */
> > +#include <linux/xarray.h>
> > +#include <linux/bitfield.h>
> > +
> > +#include "cn20k/npc.h"
> > +#include "cn20k/reg.h"
> > +
> > +static struct npc_priv_t npc_priv = {
> > +       .num_banks = MAX_NUM_BANKS,
> > +};
> > +
> > +static const char *npc_kw_name[NPC_MCAM_KEY_MAX] = {
> > +       [NPC_MCAM_KEY_DYN] = "DYNAMIC",
> > +       [NPC_MCAM_KEY_X2] = "X2",
> > +       [NPC_MCAM_KEY_X4] = "X4",
> > +};
> > +
> > +struct npc_priv_t *npc_priv_get(void)
> > +{
> > +       return &npc_priv;
> > +}
> > +
> > +static int npc_subbank_idx_2_mcam_idx(struct rvu *rvu, struct npc_subbank *sb,
> > +                                     u16 sub_off, u16 *mcam_idx)
> > +{
> > +       int off, bot;
> > +
> > +       /* for x4 section, maximum allowed subbank index =
> > +        * subsection depth - 1
> > +        */
> > +       if (sb->key_type == NPC_MCAM_KEY_X4 &&
> > +           sub_off >= npc_priv.subbank_depth) {
> > +               dev_err(rvu->dev, "%s:%d bad params\n",
> > +                       __func__, __LINE__);
> > +               return -EINVAL;
> > +       }
> > +
> > +       /* for x2 section, maximum allowed subbank index =
> > +        * 2 * subsection depth - 1
> > +        */
> > +       if (sb->key_type == NPC_MCAM_KEY_X2 &&
> > +           sub_off >= npc_priv.subbank_depth * 2) {
> > +               dev_err(rvu->dev, "%s:%d bad params\n",
> > +                       __func__, __LINE__);
> > +               return -EINVAL;
> > +       }
> > +
> > +       /* Find subbank offset from respective subbank (w.r.t bank) */
> > +       off = sub_off & (npc_priv.subbank_depth - 1);
> > +
> > +       /* if subsection idx is in bank1, add bank depth,
> > +        * which is part of sb->b1b
> > +        */
> > +       bot = sub_off >= npc_priv.subbank_depth ? sb->b1b : sb->b0b;
> > +
> > +       *mcam_idx = bot + off;
> > +       return 0;
> > +}
> > +
> > +static int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
> > +                                     struct npc_subbank **sb,
> > +                                     int *sb_off)
> > +{
> > +       int bank_off, sb_id;
> > +
> > +       /* mcam_idx should be less than (2 * bank depth) */
> > +       if (mcam_idx >= npc_priv.bank_depth * 2) {
> > +               dev_err(rvu->dev, "%s:%d bad params\n",
> > +                       __func__, __LINE__);
> > +               return -EINVAL;
> > +       }
> > +
> > +       /* find mcam offset per bank */
> > +       bank_off = mcam_idx & (npc_priv.bank_depth - 1);
> > +
> > +       /* Find subbank id */
> > +       sb_id = bank_off / npc_priv.subbank_depth;
> > +
> > +       /* Check if subbank id is more than maximum
> > +        * number of subbanks available
> > +        */
> > +       if (sb_id >= npc_priv.num_subbanks) {
> > +               dev_err(rvu->dev, "%s:%d invalid subbank %d\n",
> > +                       __func__, __LINE__, sb_id);
> > +               return -EINVAL;
> > +       }
> > +
> > +       *sb = &npc_priv.sb[sb_id];
> > +
> > +       /* Subbank offset per bank */
> > +       *sb_off = bank_off % npc_priv.subbank_depth;
> > +
> > +       /* Index in a subbank should add subbank depth
> > +        * if it is in bank1
> > +        */
> > +       if (mcam_idx >= npc_priv.bank_depth)
> > +               *sb_off += npc_priv.subbank_depth;
> > +
> > +       return 0;
> > +}
> > +
> > +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:%d Could not find contiguous(%d) entries\n",
> > +                               __func__, __LINE__, count);
> > +                       return -EFAULT;
> > +               }
> > +
> > +               dev_dbg(rvu->dev,
> > +                       "%s:%d sidx=%d eidx=%d t=%d b=%d offset=%d count=%d delta=%d\n",
> > +                       __func__, __LINE__, 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:%d Could not find contiguous(%d) entries in subbbank=%u\n",
> > +               __func__, __LINE__, 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:%d Error happened to alloc %u, bitmap_weight=%u, sb->idx=%u\n",
> > +                               __func__, __LINE__, 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:%d Could not find non contiguous entries(%u) in subbank(%u) cnt=%d max_alloc=%d\n",
> > +               __func__, __LINE__, 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:%d Marking set=%d sb_off=%d sb->idx=%d off=%d\n",
> > +               __func__, __LINE__, 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:%d Error to delete from xa_sb_used array\n",
> > +                       __func__, __LINE__);
> > +               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:%d Error to add sb(%u) to xa_sb_free array at arr_idx=%d, val=%lu\n",
> > +                       __func__, __LINE__,
> > +                       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)
> > +
> > +{
> > +       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:%d Error to delete from xa_sb_free array\n",
> > +                       __func__, __LINE__);
> > +               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:%d Error to add to xa_sb_used array\n",
> > +                       __func__, __LINE__);
> > +
> > +       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:%d Error to free subbank\n",
> > +                       __func__, __LINE__);
> > +
> > +done:
> > +       return deleted;
> > +}
> > +
> > +static int __maybe_unused
> > +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:%d Less space, count=%d idx_sz=%d sb_id=%d\n",
> > +                       __func__, __LINE__, 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:%d Wrong ref_enty(%d) or limit(%d)\n",
> > +                       __func__, __LINE__, 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:%d Wrong ref_enty(%d) or limit(%d) for x4\n",
> > +                       __func__, __LINE__, 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:%d request ref and limit should be from same bank\n",
> > +                       __func__, __LINE__);
> > +               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:%d Wrong ref_enty(%d) or limit(%d) for count(%d)\n",
> > +                       __func__, __LINE__, 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:%d Less number of entries\n",
> > +                               __func__, __LINE__);
> > +                       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:%d subbank key_type mismatch\n",
> > +                       __func__, __LINE__);
> > +               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:%d no space for entry\n",
> > +                       __func__, __LINE__);
> > +               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:%d NPC block not implemented\n",
> > +                               __func__, __LINE__);
> > +                       goto err;
> > +               }
> > +
> > +               rc =  __npc_subbank_mark_used(rvu, sb, key_type);
> > +               if (rc) {
> > +                       dev_err(rvu->dev, "%s:%d Error to mark subbank as used\n",
> > +                               __func__, __LINE__);
> > +                       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:%d Error to find mcam idx for %u\n",
> > +                               __func__, __LINE__, 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:%d Error to mark mcam_idx %u\n",
> > +                               __func__, __LINE__, mcam_idx[i]);
> > +                       rc = -EFAULT;
> > +                       goto err;
> > +               }
> > +       }
> > +
> > +err:
> > +       kfree(save);
> > +       return rc;
> > +}
> > +
> > +static int __maybe_unused
> > +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 __maybe_unused
> > +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:%d failed to erase mcam_idx(%u) from xa_idx2pf map\n",
> > +                       __func__, __LINE__, 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:%d failed to erase mcam_idx(%u) from xa_pf2idx_map map\n",
> > +                       __func__, __LINE__, mcam_idx);
> > +               return -EFAULT;
> > +       }
> > +       return 0;
> > +}
> > +
> > +static int __maybe_unused
> > +npc_add_to_pf_maps(struct rvu *rvu, u16 mcam_idx, int pcifunc)
> > +{
> > +       int rc, idx;
> > +       void *map;
> > +
> > +       dev_dbg(rvu->dev,
> > +               "%s:%d add2maps mcam_idx(%u) to xa_idx2pf map pcifunc=%#x\n",
> > +               __func__, __LINE__, 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:%d failed to insert mcam_idx(%u) to xa_idx2pf map, existing value=%lu\n",
> > +                       __func__, __LINE__, 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);
> > +               dev_err(rvu->dev,
> > +                       "%s:%d failed to insert mcam_idx(%u) to xa_pf2idx_map map, earlier value=%lu idx=%u\n",
> > +                       __func__, __LINE__, mcam_idx, xa_to_value(map), idx);
> > +               return -EFAULT;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static bool __maybe_unused
> > +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 __maybe_unused
> > +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;
> > +
> > +       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:%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;
> > +                       }
> > +                       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;
> [Kalesh] consider changing it to a void function as it unconditionally 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;
> [Kalesh] follow RCT order
This is already in reverse xmas tree.
> > +       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)
> [Kalesh] missing kfree(fslots);
Thanks. AI review already found those and i fixed them. will be part of V2.
https://netdev-ai.bots.linux.dev/ai-review.html?id=ad528672-9dec-4662-97fd-ff401076c201
> > +               return -ENOMEM;
> > +
> > +       for (int i = 0; i < cnt; i++, arr++) {
> > +               idx = (*arr)[0];
> > +               val = (*arr)[1];
> > +
> > +               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;
> > +}
> > +
> > +const int *npc_cn20k_search_order_get(bool *restricted_order)
> > +{
> > +       *restricted_order = restrict_valid;
> > +       return subbank_srch_order;
> > +}
> > +
> > +static void npc_populate_restricted_idxs(int num_subbanks)
> > +{
> > +       npc_subbank_restricted_idxs[0] = num_subbanks - 1;
> > +       npc_subbank_restricted_idxs[1] = 0;
> > +}
> > +
> > +static void npc_create_srch_order(int cnt)
> > +{
> > +       int val = 0;
> > +
> > +       subbank_srch_order = kcalloc(cnt, sizeof(int),
> > +                                    GFP_KERNEL);
> [Kalesh] missing check for memory allocation failure
same as above.
> > +
> > +       for (int i = 0; i < cnt; i += 2) {
> > +               subbank_srch_order[i] = cnt / 2 - val - 1;
> > +               subbank_srch_order[i + 1] = cnt / 2 + 1 + val;
> > +               val++;
> > +       }
> > +
> > +       subbank_srch_order[cnt - 1] = cnt / 2;
> > +}
> > +
> > +static void npc_subbank_init(struct rvu *rvu, struct npc_subbank *sb, int idx)
> > +{
> > +       mutex_init(&sb->lock);
> > +
> > +       sb->b0b = idx * npc_priv.subbank_depth;
> > +       sb->b0t = sb->b0b + npc_priv.subbank_depth - 1;
> > +
> > +       sb->b1b = npc_priv.bank_depth + idx * npc_priv.subbank_depth;
> > +       sb->b1t = sb->b1b + npc_priv.subbank_depth - 1;
> > +
> > +       sb->flags = NPC_SUBBANK_FLAG_FREE;
> > +       sb->idx = idx;
> > +       sb->arr_idx = subbank_srch_order[idx];
> > +
> > +       dev_dbg(rvu->dev, "%s:%d sb->idx=%u sb->arr_idx=%u\n",
> > +               __func__, __LINE__, sb->idx, sb->arr_idx);
> > +
> > +       /* Keep first and last subbank at end of free array; so that
> > +        * it will be used at last
> > +        */
> > +       xa_store(&npc_priv.xa_sb_free, sb->arr_idx,
> > +                xa_mk_value(sb->idx), GFP_KERNEL);
> > +}
> > +
> > +static int npc_pcifunc_map_create(struct rvu *rvu)
> > +{
> > +       int pf, vf, numvfs;
> > +       int cnt = 0;
> > +       u16 pcifunc;
> [Kalesh]: follow RCT order
It is already in reverse xmas tree order. Am i missing anything ?
> > +       u64 cfg;
> > +
> > +       for (pf = 0; pf < rvu->hw->total_pfs; pf++) {
> > +               cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf));
> > +               numvfs = (cfg >> 12) & 0xFF;
> > +
> > +               /* Skip not enabled PFs */
> > +               if (!(cfg & BIT_ULL(20)))
> > +                       goto chk_vfs;
> > +
> > +               /* If Admin function, check on VFs */
> > +               if (cfg & BIT_ULL(21))
> > +                       goto chk_vfs;
> > +
> > +               pcifunc = pf << 9;
> > +
> > +               xa_store(&npc_priv.xa_pf_map, (unsigned long)pcifunc,
> > +                        xa_mk_value(cnt), GFP_KERNEL);
> > +
> > +               cnt++;
> > +
> > +chk_vfs:
> > +               for (vf = 0; vf < numvfs; vf++) {
> > +                       pcifunc = (pf << 9) | (vf + 1);
> > +
> > +                       xa_store(&npc_priv.xa_pf_map, (unsigned long)pcifunc,
> > +                                xa_mk_value(cnt), GFP_KERNEL);
> > +                       cnt++;
> > +               }
> > +       }
> > +
> > +       return cnt;
> > +}
> > +
> > +static int npc_priv_init(struct rvu *rvu)
> > +{
> > +       struct npc_mcam *mcam = &rvu->hw->mcam;
> > +       int blkaddr, num_banks, bank_depth;
> > +       int num_subbanks, subbank_depth;
> > +       u64 npc_const1, npc_const2 = 0;
> > +       struct npc_subbank *sb;
> > +       u64 cfg;
> > +       int i;
> > +
> > +       blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
> > +       if (blkaddr < 0) {
> > +               dev_err(rvu->dev, "%s:%d NPC block not implemented\n",
> > +                       __func__, __LINE__);
> > +               return -ENODEV;
> > +       }
> > +
> > +       npc_const1 = rvu_read64(rvu, blkaddr, NPC_AF_CONST1);
> > +       if (npc_const1 & BIT_ULL(63))
> > +               npc_const2 = rvu_read64(rvu, blkaddr, NPC_AF_CONST2);
> > +
> > +       num_banks = mcam->banks;
> > +       bank_depth = mcam->banksize;
> > +
> > +       num_subbanks = FIELD_GET(GENMASK_ULL(39, 32), npc_const2);
> > +       npc_priv.num_subbanks = num_subbanks;
> > +
> > +       subbank_depth = bank_depth / num_subbanks;
> > +
> > +       npc_priv.bank_depth = bank_depth;
> > +       npc_priv.subbank_depth = subbank_depth;
> > +
> > +       /* Get kex configured key size */
> > +       cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(0));
> > +       npc_priv.kw = FIELD_GET(GENMASK_ULL(34, 32), cfg);
> > +
> > +       dev_info(rvu->dev,
> > +                "banks=%u depth=%u, subbanks=%u depth=%u, key type=%s\n",
> > +                num_banks, bank_depth, num_subbanks, subbank_depth,
> > +                npc_kw_name[npc_priv.kw]);
> > +
> > +       npc_priv.sb = kcalloc(num_subbanks, sizeof(struct npc_subbank),
> > +                             GFP_KERNEL);
> > +       if (!npc_priv.sb)
> > +               return -ENOMEM;
> > +
> > +       xa_init_flags(&npc_priv.xa_sb_used, XA_FLAGS_ALLOC);
> > +       xa_init_flags(&npc_priv.xa_sb_free, XA_FLAGS_ALLOC);
> > +       xa_init_flags(&npc_priv.xa_idx2pf_map, XA_FLAGS_ALLOC);
> > +       xa_init_flags(&npc_priv.xa_pf_map, XA_FLAGS_ALLOC);
> > +
> > +       npc_create_srch_order(num_subbanks);
> > +       npc_populate_restricted_idxs(num_subbanks);
> > +
> > +       /* Initialize subbanks */
> > +       for (i = 0, sb = npc_priv.sb; i < num_subbanks; i++, sb++)
> > +               npc_subbank_init(rvu, sb, i);
> > +
> > +       /* Get number of pcifuncs in the system */
> > +       npc_priv.pf_cnt = npc_pcifunc_map_create(rvu);
> > +       npc_priv.xa_pf2idx_map = kcalloc(npc_priv.pf_cnt, sizeof(struct xarray),
> > +                                        GFP_KERNEL);
> > +       if (!npc_priv.xa_pf2idx_map)
> [Kalesh] missing kfree(npc_priv.sb);
Thanks. AI review already found those and i fixed them. will be part of V2.
https://netdev-ai.bots.linux.dev/ai-review.html?id=ad528672-9dec-4662-97fd-ff401076c201
> > +               return -ENOMEM;
> > +
> > +       for (i = 0; i < npc_priv.pf_cnt; i++)
> > +               xa_init_flags(&npc_priv.xa_pf2idx_map[i], XA_FLAGS_ALLOC);
> > +
> > +       return 0;
> > +}
> > +
> > +int npc_cn20k_deinit(struct rvu *rvu)
> [Kalesh] You can change it to a void function as it unconditionally return 0
ACK.
> > +{
> > +       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);
> > +       return 0;
> > +}
> > +
> > +int npc_cn20k_init(struct rvu *rvu)
> > +{
> > +       int err;
> > +
> > +       err = npc_priv_init(rvu);
> > +       if (err) {
> > +               dev_err(rvu->dev, "%s:%d Error to init\n",
> > +                       __func__, __LINE__);
> > +               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..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.
> [Kalesh] I think the // comments are prohibited
ACK
> > +       NPC_SUBBANK_FLAG_FREE = BIT(0), // No slot allocated
> > +       NPC_SUBBANK_FLAG_USED = BIT(1), // At least one slot allocated
> > +};
> > +
> > +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;
> > +};
> > +
> > +struct rvu;
> > +
> > +struct npc_priv_t *npc_priv_get(void);
> > +int npc_cn20k_init(struct rvu *rvu);
> > +int 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);
> > +int npc_cn20k_search_order_set(struct rvu *rvu, int (*arr)[2], int cnt);
> > +const int *npc_cn20k_search_order_get(bool *restricted_order);
> > +
> > +#endif /* NPC_CN20K_H */
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
> > index affb39803120..098b0247848b 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
> > +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
> > @@ -77,5 +77,8 @@
> >  #define RVU_MBOX_VF_INT_ENA_W1S                        (0x30)
> >  #define RVU_MBOX_VF_INT_ENA_W1C                        (0x38)
> >
> > +/* NPC registers */
> > +#define NPC_AF_MCAM_SECTIONX_CFG_EXT(a) (0xf000000ull | (a) << 3)
> > +
> >  #define RVU_MBOX_VF_VFAF_TRIGX(a)              (0x2000 | (a) << 3)
> >  #endif /* RVU_MBOX_REG_H */
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h
> > index 8a08bebf08c2..779413a383b7 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h
> > +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h
> > @@ -177,10 +177,6 @@ enum nix_scheduler {
> >  #define NIX_TX_ACTIONOP_MCAST          (0x3ull)
> >  #define NIX_TX_ACTIONOP_DROP_VIOL      (0x5ull)
> >
> > -#define NPC_MCAM_KEY_X1                        0
> > -#define NPC_MCAM_KEY_X2                        1
> > -#define NPC_MCAM_KEY_X4                        2
> > -
> >  #define NIX_INTFX_RX(a)                        (0x0ull | (a) << 1)
> >  #define NIX_INTFX_TX(a)                        (0x1ull | (a) << 1)
> >
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
> > index a3e273126e4e..73a341980f9e 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
> > +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
> > @@ -52,6 +52,14 @@
> >  #define MBOX_DIR_PFVF_UP       6  /* PF sends messages to VF */
> >  #define MBOX_DIR_VFPF_UP       7  /* VF replies to PF */
> >
> > +enum {
> > +       NPC_MCAM_KEY_X1 = 0,
> > +       NPC_MCAM_KEY_DYN = NPC_MCAM_KEY_X1,
> > +       NPC_MCAM_KEY_X2,
> > +       NPC_MCAM_KEY_X4,
> > +       NPC_MCAM_KEY_MAX,
> > +};
> > +
> >  enum {
> >         TYPE_AFVF,
> >         TYPE_AFPF,
> > @@ -275,6 +283,8 @@ M(NPC_GET_FIELD_HASH_INFO, 0x6013, npc_get_field_hash_info,
> >  M(NPC_GET_FIELD_STATUS, 0x6014, npc_get_field_status,                     \
> >                                    npc_get_field_status_req,              \
> >                                    npc_get_field_status_rsp)              \
> > +M(NPC_CN20K_MCAM_GET_FREE_COUNT, 0x6015, npc_cn20k_get_free_count,      \
> > +                                msg_req, npc_cn20k_get_free_count_rsp) \
> >  /* NIX mbox IDs (range 0x8000 - 0xFFFF) */                             \
> >  M(NIX_LF_ALLOC,                0x8000, nix_lf_alloc,                           \
> >                                  nix_lf_alloc_req, nix_lf_alloc_rsp)    \
> > @@ -1797,6 +1807,14 @@ struct npc_mcam_read_entry_rsp {
> >         u8 enable;
> >  };
> >
> > +/* Available entries to use */
> > +struct npc_cn20k_get_free_count_rsp {
> > +       struct mbox_msghdr hdr;
> > +       int free_x2;
> > +       int free_x4;
> > +       int free_subbanks;
> > +};
> > +
> >  struct npc_mcam_read_base_rule_rsp {
> >         struct mbox_msghdr hdr;
> >         struct mcam_entry entry;
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
> > index 15d3cb0b9da6..425d3a43c0b8 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
> > +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
> > @@ -3745,6 +3745,9 @@ static void rvu_dbg_npc_init(struct rvu *rvu)
> >         debugfs_create_file("rx_miss_act_stats", 0444, rvu->rvu_dbg.npc, rvu,
> >                             &rvu_dbg_npc_rx_miss_act_fops);
> >
> > +       if (is_cn20k(rvu->pdev))
> > +               npc_cn20k_debugfs_init(rvu);
> > +
> >         if (!rvu->hw->cap.npc_exact_match_enabled)
> >                 return;
> >
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> > index c7c70429eb6c..6c5fe838717e 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> > +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> > @@ -16,6 +16,7 @@
> >  #include "cgx.h"
> >  #include "npc_profile.h"
> >  #include "rvu_npc_hash.h"
> > +#include "cn20k/npc.h"
> >
> >  #define RSVD_MCAM_ENTRIES_PER_PF       3 /* Broadcast, Promisc and AllMulticast */
> >  #define RSVD_MCAM_ENTRIES_PER_NIXLF    1 /* Ucast for LFs */
> > @@ -2159,6 +2160,9 @@ int rvu_npc_init(struct rvu *rvu)
> >                 npc_load_mkex_profile(rvu, blkaddr, def_pfl_name);
> >         }
> >
> > +       if (is_cn20k(rvu->pdev))
> > +               return npc_cn20k_init(rvu);
> > +
> >         return 0;
> >  }
> >
> > @@ -2174,6 +2178,9 @@ void rvu_npc_freemem(struct rvu *rvu)
> >         else
> >                 kfree(rvu->kpu_fwdata);
> >         mutex_destroy(&mcam->lock);
> > +
> > +       if (is_cn20k(rvu->pdev))
> > +               npc_cn20k_deinit(rvu);
> >  }
> >
> >  void rvu_npc_get_mcam_entry_alloc_info(struct rvu *rvu, u16 pcifunc,
> > @@ -3029,7 +3036,6 @@ static int __npc_mcam_alloc_counter(struct rvu *rvu,
> >         if (!req->contig && req->count > NPC_MAX_NONCONTIG_COUNTERS)
> >                 return NPC_MCAM_INVALID_REQ;
> >
> > -
> [Kalesh] looks unrelated change
Yes. This is an extra line got removed from the file. Can i keep this ?

> >         /* Check if unused counters are available or not */
> >         if (!rvu_rsrc_free_count(&mcam->counters)) {
> >                 return NPC_MCAM_ALLOC_FAILED;
> > --
> > 2.43.0
> >
> >
>
>
> --
> Regards,
> Kalesh AP
Re: [PATCH net-next 01/13] octeontx2-af: npc: cn20k: Index management
Posted by Andrew Lunn 2 days, 7 hours ago
> +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");

Isn't checkpatch giving you warnings about pr_err(). It wants you to
use something like netdev_err()? This is a network driver, so you
should have a netdev structure.

       Andrew
Re: [PATCH net-next 01/13] octeontx2-af: npc: cn20k: Index management
Posted by Ratheesh Kannoth 1 day, 19 hours ago
On 2026-01-05 at 20:45:12, Andrew Lunn (andrew@lunn.ch) wrote:
> > +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");
>
> Isn't checkpatch giving you warnings about pr_err(). It wants you to
> use something like netdev_err()? This is a network driver, so you
> should have a netdev structure.
>
>        Andrew
There was no warning reported by checkpatch. NPC is a global TCAM resource.
This debugfs interface sets the order in which the subbanks (there are 32
subbanks in the NPC) are searched for a free slot. Would you prefer that I
create a dummy netdevice and pass it to this function?