Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f9274958 authored by Sunil Goutham's avatar Sunil Goutham Committed by David S. Miller
Browse files

octeontx2-af: NPC MCAM entry alloc/free support



This patch adds NPC MCAM entry management and support for
allocating and freeing them via mailbox. Both contiguous and
non-contiguous allocations are supported. Incase of contiguous,
if request cannot be met then max contiguous number of available
entries are allocated.

High or low priority index allocation w.r.t a reference MCAM index
is also supported.

Signed-off-by: default avatarSunil Goutham <sgoutham@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0964fc8f
Loading
Loading
Loading
Loading
+49 −0
Original line number Diff line number Diff line
@@ -149,6 +149,10 @@ M(NPA_HWCTX_DISABLE, 0x403, npa_hwctx_disable, hwctx_disable_req, msg_rsp)\
/* TIM mbox IDs (range 0x800 - 0x9FF) */				\
/* CPT mbox IDs (range 0xA00 - 0xBFF) */				\
/* NPC mbox IDs (range 0x6000 - 0x7FFF) */				\
M(NPC_MCAM_ALLOC_ENTRY,	0x6000, npc_mcam_alloc_entry, npc_mcam_alloc_entry_req,\
				npc_mcam_alloc_entry_rsp)		\
M(NPC_MCAM_FREE_ENTRY,	0x6001, npc_mcam_free_entry,			\
				 npc_mcam_free_entry_req, msg_rsp)	\
/* NIX mbox IDs (range 0x8000 - 0xFFFF) */				\
M(NIX_LF_ALLOC,		0x8000, nix_lf_alloc,				\
				 nix_lf_alloc_req, nix_lf_alloc_rsp)	\
@@ -353,6 +357,8 @@ struct hwctx_disable_req {
	u8 ctype;
};

/* NIX mbox message formats */

/* NIX mailbox error codes
 * Range 401 - 500.
 */
@@ -541,4 +547,47 @@ struct nix_frs_cfg {
	u16	minlen;
};

/* NPC mbox message structs */

#define NPC_MCAM_ENTRY_INVALID	0xFFFF
#define NPC_MCAM_INVALID_MAP	0xFFFF

/* NPC mailbox error codes
 * Range 701 - 800.
 */
enum npc_af_status {
	NPC_MCAM_INVALID_REQ	= -701,
	NPC_MCAM_ALLOC_DENIED	= -702,
	NPC_MCAM_ALLOC_FAILED	= -703,
	NPC_MCAM_PERM_DENIED	= -704,
};

struct npc_mcam_alloc_entry_req {
	struct mbox_msghdr hdr;
#define NPC_MAX_NONCONTIG_ENTRIES	256
	u8  contig;   /* Contiguous entries ? */
#define NPC_MCAM_ANY_PRIO		0
#define NPC_MCAM_LOWER_PRIO		1
#define NPC_MCAM_HIGHER_PRIO		2
	u8  priority; /* Lower or higher w.r.t ref_entry */
	u16 ref_entry;
	u16 count;    /* Number of entries requested */
};

struct npc_mcam_alloc_entry_rsp {
	struct mbox_msghdr hdr;
	u16 entry; /* Entry allocated or start index if contiguous.
		    * Invalid incase of non-contiguous.
		    */
	u16 count; /* Number of entries allocated */
	u16 free_count; /* Number of entries available */
	u16 entry_list[NPC_MAX_NONCONTIG_ENTRIES];
};

struct npc_mcam_free_entry_req {
	struct mbox_msghdr hdr;
	u16 entry; /* Entry index to be freed */
	u8  all;   /* If all entries allocated to this PFVF to be freed */
};

#endif /* MBOX_H */
+18 −1
Original line number Diff line number Diff line
@@ -74,15 +74,25 @@ struct nix_mce_list {
};

struct npc_mcam {
	struct rsrc_bmap counters;
	struct mutex	lock;	/* MCAM entries and counters update lock */
	unsigned long	*bmap;		/* bitmap, 0 => bmap_entries */
	unsigned long	*bmap_reverse;	/* Reverse bitmap, bmap_entries => 0 */
	u16	bmap_entries;	/* Number of unreserved MCAM entries */
	u16	bmap_fcnt;	/* MCAM entries free count */
	u16	*entry2pfvf_map;
	u16	*cntr2pfvf_map;
	u8	keysize;	/* MCAM keysize 112/224/448 bits */
	u8	banks;		/* Number of MCAM banks */
	u8	banks_per_entry;/* Number of keywords in key */
	u16	banksize;	/* Number of MCAM entries in each bank */
	u16	total_entries;	/* Total number of MCAM entries */
	u16     entries;	/* Total minus reserved for NIX LFs */
	u16	nixlf_offset;	/* Offset of nixlf rsvd uncast entries */
	u16	pf_offset;	/* Offset of PF's rsvd bcast, promisc entries */
	u16	lprio_count;
	u16	lprio_start;
	u16	hprio_count;
	u16	hprio_end;
};

/* Structure for per RVU func info ie PF/VF */
@@ -315,6 +325,7 @@ int rvu_mbox_handler_npa_lf_free(struct rvu *rvu, struct msg_req *req,
				 struct msg_rsp *rsp);

/* NIX APIs */
bool is_nixlf_attached(struct rvu *rvu, u16 pcifunc);
int rvu_nix_init(struct rvu *rvu);
void rvu_nix_freemem(struct rvu *rvu);
int rvu_get_nixlf_count(struct rvu *rvu);
@@ -369,4 +380,10 @@ void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf);
void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
				    int group, int alg_idx, int mcam_index);
int rvu_mbox_handler_npc_mcam_alloc_entry(struct rvu *rvu,
					  struct npc_mcam_alloc_entry_req *req,
					  struct npc_mcam_alloc_entry_rsp *rsp);
int rvu_mbox_handler_npc_mcam_free_entry(struct rvu *rvu,
					 struct npc_mcam_free_entry_req *req,
					 struct msg_rsp *rsp);
#endif /* RVU_H */
+11 −0
Original line number Diff line number Diff line
@@ -55,6 +55,17 @@ struct mce {
	u16			pcifunc;
};

bool is_nixlf_attached(struct rvu *rvu, u16 pcifunc)
{
	struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
	int blkaddr;

	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
	if (!pfvf->nixlf || blkaddr < 0)
		return false;
	return true;
}

int rvu_get_nixlf_count(struct rvu *rvu)
{
	struct rvu_block *block;
+510 −4
Original line number Diff line number Diff line
@@ -26,6 +26,9 @@

#define NPC_PARSE_RESULT_DMAC_OFFSET	8

static void npc_mcam_free_all_entries(struct rvu *rvu, struct npc_mcam *mcam,
				      int blkaddr, u16 pcifunc);

struct mcam_entry {
#define NPC_MAX_KWS_IN_KEY	7 /* Number of keywords in max keywidth */
	u64	kw[NPC_MAX_KWS_IN_KEY];
@@ -466,6 +469,13 @@ void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
	if (blkaddr < 0)
		return;

	mutex_lock(&mcam->lock);

	/* Disable and free all MCAM entries mapped to this 'pcifunc' */
	npc_mcam_free_all_entries(rvu, mcam, blkaddr, pcifunc);

	mutex_unlock(&mcam->lock);

	/* Disable ucast MCAM match entry of this PF/VF */
	index = npc_get_nixlf_mcam_index(mcam, pcifunc,
					 nixlf, NIXLF_UCAST_ENTRY);
@@ -690,13 +700,14 @@ static int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)
{
	int nixlf_count = rvu_get_nixlf_count(rvu);
	struct npc_mcam *mcam = &rvu->hw->mcam;
	int rsvd;
	int rsvd, err;
	u64 cfg;

	/* Get HW limits */
	cfg = rvu_read64(rvu, blkaddr, NPC_AF_CONST);
	mcam->banks = (cfg >> 44) & 0xF;
	mcam->banksize = (cfg >> 28) & 0xFFFF;
	mcam->counters.max = (cfg >> 48) & 0xFFFF;

	/* Actual number of MCAM entries vary by entry size */
	cfg = (rvu_read64(rvu, blkaddr,
@@ -728,20 +739,69 @@ static int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)
		return -ENOMEM;
	}

	mcam->entries = mcam->total_entries - rsvd;
	mcam->nixlf_offset = mcam->entries;
	mcam->bmap_entries = mcam->total_entries - rsvd;
	mcam->nixlf_offset = mcam->bmap_entries;
	mcam->pf_offset = mcam->nixlf_offset + nixlf_count;

	/* Allocate bitmaps for managing MCAM entries */
	mcam->bmap = devm_kcalloc(rvu->dev, BITS_TO_LONGS(mcam->bmap_entries),
				  sizeof(long), GFP_KERNEL);
	if (!mcam->bmap)
		return -ENOMEM;

	mcam->bmap_reverse = devm_kcalloc(rvu->dev,
					  BITS_TO_LONGS(mcam->bmap_entries),
					  sizeof(long), GFP_KERNEL);
	if (!mcam->bmap_reverse)
		return -ENOMEM;

	mcam->bmap_fcnt = mcam->bmap_entries;

	/* Alloc memory for saving entry to RVU PFFUNC allocation mapping */
	mcam->entry2pfvf_map = devm_kcalloc(rvu->dev, mcam->bmap_entries,
					    sizeof(u16), GFP_KERNEL);
	if (!mcam->entry2pfvf_map)
		return -ENOMEM;

	/* Reserve 1/8th of MCAM entries at the bottom for low priority
	 * allocations and another 1/8th at the top for high priority
	 * allocations.
	 */
	mcam->lprio_count = mcam->bmap_entries / 8;
	if (mcam->lprio_count > BITS_PER_LONG)
		mcam->lprio_count = round_down(mcam->lprio_count,
					       BITS_PER_LONG);
	mcam->lprio_start = mcam->bmap_entries - mcam->lprio_count;
	mcam->hprio_count = mcam->lprio_count;
	mcam->hprio_end = mcam->hprio_count;

	/* Allocate bitmap for managing MCAM counters and memory
	 * for saving counter to RVU PFFUNC allocation mapping.
	 */
	err = rvu_alloc_bitmap(&mcam->counters);
	if (err)
		return err;

	mcam->cntr2pfvf_map = devm_kcalloc(rvu->dev, mcam->counters.max,
					   sizeof(u16), GFP_KERNEL);
	if (!mcam->cntr2pfvf_map)
		goto free_mem;

	mutex_init(&mcam->lock);

	return 0;

free_mem:
	kfree(mcam->counters.bmap);
	return -ENOMEM;
}

int rvu_npc_init(struct rvu *rvu)
{
	struct npc_pkind *pkind = &rvu->hw->pkind;
	u64 keyz = NPC_MCAM_KEY_X2;
	int blkaddr, err;
	int blkaddr, entry, bank, err;
	u64 cfg;

	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
	if (blkaddr < 0) {
@@ -749,6 +809,14 @@ int rvu_npc_init(struct rvu *rvu)
		return -ENODEV;
	}

	/* First disable all MCAM entries, to stop traffic towards NIXLFs */
	cfg = rvu_read64(rvu, blkaddr, NPC_AF_CONST);
	for (bank = 0; bank < ((cfg >> 44) & 0xF); bank++) {
		for (entry = 0; entry < ((cfg >> 28) & 0xFFFF); entry++)
			rvu_write64(rvu, blkaddr,
				    NPC_AF_MCAMEX_BANKX_CFG(entry, bank), 0);
	}

	/* Allocate resource bimap for pkind*/
	pkind->rsrc.max = (rvu_read64(rvu, blkaddr,
				      NPC_AF_CONST1) >> 12) & 0xFF;
@@ -814,5 +882,443 @@ void rvu_npc_freemem(struct rvu *rvu)
	struct npc_mcam *mcam = &rvu->hw->mcam;

	kfree(pkind->rsrc.bmap);
	kfree(mcam->counters.bmap);
	mutex_destroy(&mcam->lock);
}

static int npc_mcam_verify_entry(struct npc_mcam *mcam,
				 u16 pcifunc, int entry)
{
	/* Verify if entry is valid and if it is indeed
	 * allocated to the requesting PFFUNC.
	 */
	if (entry >= mcam->bmap_entries)
		return NPC_MCAM_INVALID_REQ;

	if (pcifunc != mcam->entry2pfvf_map[entry])
		return NPC_MCAM_PERM_DENIED;

	return 0;
}

/* Sets MCAM entry in bitmap as used. Update
 * reverse bitmap too. Should be called with
 * 'mcam->lock' held.
 */
static void npc_mcam_set_bit(struct npc_mcam *mcam, u16 index)
{
	u16 entry, rentry;

	entry = index;
	rentry = mcam->bmap_entries - index - 1;

	__set_bit(entry, mcam->bmap);
	__set_bit(rentry, mcam->bmap_reverse);
	mcam->bmap_fcnt--;
}

/* Sets MCAM entry in bitmap as free. Update
 * reverse bitmap too. Should be called with
 * 'mcam->lock' held.
 */
static void npc_mcam_clear_bit(struct npc_mcam *mcam, u16 index)
{
	u16 entry, rentry;

	entry = index;
	rentry = mcam->bmap_entries - index - 1;

	__clear_bit(entry, mcam->bmap);
	__clear_bit(rentry, mcam->bmap_reverse);
	mcam->bmap_fcnt++;
}

static void npc_mcam_free_all_entries(struct rvu *rvu, struct npc_mcam *mcam,
				      int blkaddr, u16 pcifunc)
{
	u16 index;

	/* Scan all MCAM entries and free the ones mapped to 'pcifunc' */
	for (index = 0; index < mcam->bmap_entries; index++) {
		if (mcam->entry2pfvf_map[index] == pcifunc) {
			mcam->entry2pfvf_map[index] = NPC_MCAM_INVALID_MAP;
			/* Free the entry in bitmap */
			npc_mcam_clear_bit(mcam, index);
			/* Disable the entry */
			npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
		}
	}
}

/* Find area of contiguous free entries of size 'nr'.
 * If not found return max contiguous free entries available.
 */
static u16 npc_mcam_find_zero_area(unsigned long *map, u16 size, u16 start,
				   u16 nr, u16 *max_area)
{
	u16 max_area_start = 0;
	u16 index, next, end;

	*max_area = 0;

again:
	index = find_next_zero_bit(map, size, start);
	if (index >= size)
		return max_area_start;

	end = ((index + nr) >= size) ? size : index + nr;
	next = find_next_bit(map, end, index);
	if (*max_area < (next - index)) {
		*max_area = next - index;
		max_area_start = index;
	}

	if (next < end) {
		start = next + 1;
		goto again;
	}

	return max_area_start;
}

/* Find number of free MCAM entries available
 * within range i.e in between 'start' and 'end'.
 */
static u16 npc_mcam_get_free_count(unsigned long *map, u16 start, u16 end)
{
	u16 index, next;
	u16 fcnt = 0;

again:
	if (start >= end)
		return fcnt;

	index = find_next_zero_bit(map, end, start);
	if (index >= end)
		return fcnt;

	next = find_next_bit(map, end, index);
	if (next <= end) {
		fcnt += next - index;
		start = next + 1;
		goto again;
	}

	fcnt += end - index;
	return fcnt;
}

static void
npc_get_mcam_search_range_priority(struct npc_mcam *mcam,
				   struct npc_mcam_alloc_entry_req *req,
				   u16 *start, u16 *end, bool *reverse)
{
	u16 fcnt;

	if (req->priority == NPC_MCAM_HIGHER_PRIO)
		goto hprio;

	/* For a low priority entry allocation
	 * - If reference entry is not in hprio zone then
	 *      search range: ref_entry to end.
	 * - If reference entry is in hprio zone and if
	 *   request can be accomodated in non-hprio zone then
	 *      search range: 'start of middle zone' to 'end'
	 * - else search in reverse, so that less number of hprio
	 *   zone entries are allocated.
	 */

	*reverse = false;
	*start = req->ref_entry + 1;
	*end = mcam->bmap_entries;

	if (req->ref_entry >= mcam->hprio_end)
		return;

	fcnt = npc_mcam_get_free_count(mcam->bmap,
				       mcam->hprio_end, mcam->bmap_entries);
	if (fcnt > req->count)
		*start = mcam->hprio_end;
	else
		*reverse = true;
	return;

hprio:
	/* For a high priority entry allocation, search is always
	 * in reverse to preserve hprio zone entries.
	 * - If reference entry is not in lprio zone then
	 *      search range: 0 to ref_entry.
	 * - If reference entry is in lprio zone and if
	 *   request can be accomodated in middle zone then
	 *      search range: 'hprio_end' to 'lprio_start'
	 */

	*reverse = true;
	*start = 0;
	*end = req->ref_entry;

	if (req->ref_entry <= mcam->lprio_start)
		return;

	fcnt = npc_mcam_get_free_count(mcam->bmap,
				       mcam->hprio_end, mcam->lprio_start);
	if (fcnt < req->count)
		return;
	*start = mcam->hprio_end;
	*end = mcam->lprio_start;
}

static int npc_mcam_alloc_entries(struct npc_mcam *mcam, u16 pcifunc,
				  struct npc_mcam_alloc_entry_req *req,
				  struct npc_mcam_alloc_entry_rsp *rsp)
{
	u16 entry_list[NPC_MAX_NONCONTIG_ENTRIES];
	u16 fcnt, hp_fcnt, lp_fcnt;
	u16 start, end, index;
	int entry, next_start;
	bool reverse = false;
	unsigned long *bmap;
	u16 max_contig;

	mutex_lock(&mcam->lock);

	/* Check if there are any free entries */
	if (!mcam->bmap_fcnt) {
		mutex_unlock(&mcam->lock);
		return NPC_MCAM_ALLOC_FAILED;
	}

	/* MCAM entries are divided into high priority, middle and
	 * low priority zones. Idea is to not allocate top and lower
	 * most entries as much as possible, this is to increase
	 * probability of honouring priority allocation requests.
	 *
	 * Two bitmaps are used for mcam entry management,
	 * mcam->bmap for forward search i.e '0 to mcam->bmap_entries'.
	 * mcam->bmap_reverse for reverse search i.e 'mcam->bmap_entries to 0'.
	 *
	 * Reverse bitmap is used to allocate entries
	 * - when a higher priority entry is requested
	 * - when available free entries are less.
	 * Lower priority ones out of avaialble free entries are always
	 * chosen when 'high vs low' question arises.
	 */

	/* Get the search range for priority allocation request */
	if (req->priority) {
		npc_get_mcam_search_range_priority(mcam, req,
						   &start, &end, &reverse);
		goto alloc;
	}

	/* Find out the search range for non-priority allocation request
	 *
	 * Get MCAM free entry count in middle zone.
	 */
	lp_fcnt = npc_mcam_get_free_count(mcam->bmap,
					  mcam->lprio_start,
					  mcam->bmap_entries);
	hp_fcnt = npc_mcam_get_free_count(mcam->bmap, 0, mcam->hprio_end);
	fcnt = mcam->bmap_fcnt - lp_fcnt - hp_fcnt;

	/* Check if request can be accomodated in the middle zone */
	if (fcnt > req->count) {
		start = mcam->hprio_end;
		end = mcam->lprio_start;
	} else if ((fcnt + (hp_fcnt / 2) + (lp_fcnt / 2)) > req->count) {
		/* Expand search zone from half of hprio zone to
		 * half of lprio zone.
		 */
		start = mcam->hprio_end / 2;
		end = mcam->bmap_entries - (mcam->lprio_count / 2);
		reverse = true;
	} else {
		/* Not enough free entries, search all entries in reverse,
		 * so that low priority ones will get used up.
		 */
		reverse = true;
		start = 0;
		end = mcam->bmap_entries;
	}

alloc:
	if (reverse) {
		bmap = mcam->bmap_reverse;
		start = mcam->bmap_entries - start;
		end = mcam->bmap_entries - end;
		index = start;
		start = end;
		end = index;
	} else {
		bmap = mcam->bmap;
	}

	if (req->contig) {
		/* Allocate requested number of contiguous entries, if
		 * unsuccessful find max contiguous entries available.
		 */
		index = npc_mcam_find_zero_area(bmap, end, start,
						req->count, &max_contig);
		rsp->count = max_contig;
		if (reverse)
			rsp->entry = mcam->bmap_entries - index - max_contig;
		else
			rsp->entry = index;
	} else {
		/* Allocate requested number of non-contiguous entries,
		 * if unsuccessful allocate as many as possible.
		 */
		rsp->count = 0;
		next_start = start;
		for (entry = 0; entry < req->count; entry++) {
			index = find_next_zero_bit(bmap, end, next_start);
			if (index >= end)
				break;

			next_start = start + (index - start) + 1;

			/* Save the entry's index */
			if (reverse)
				index = mcam->bmap_entries - index - 1;
			entry_list[entry] = index;
			rsp->count++;
		}
	}

	/* If allocating requested no of entries is unsucessful,
	 * expand the search range to full bitmap length and retry.
	 */
	if (!req->priority && (rsp->count < req->count) &&
	    ((end - start) != mcam->bmap_entries)) {
		reverse = true;
		start = 0;
		end = mcam->bmap_entries;
		goto alloc;
	}

	/* For priority entry allocation requests, if allocation is
	 * failed then expand search to max possible range and retry.
	 */
	if (req->priority && rsp->count < req->count) {
		if (req->priority == NPC_MCAM_LOWER_PRIO &&
		    (start != (req->ref_entry + 1))) {
			start = req->ref_entry + 1;
			end = mcam->bmap_entries;
			reverse = false;
			goto alloc;
		} else if ((req->priority == NPC_MCAM_HIGHER_PRIO) &&
			   ((end - start) != req->ref_entry)) {
			start = 0;
			end = req->ref_entry;
			reverse = true;
			goto alloc;
		}
	}

	/* Copy MCAM entry indices into mbox response entry_list.
	 * Requester always expects indices in ascending order, so
	 * so reverse the list if reverse bitmap is used for allocation.
	 */
	if (!req->contig && rsp->count) {
		index = 0;
		for (entry = rsp->count - 1; entry >= 0; entry--) {
			if (reverse)
				rsp->entry_list[index++] = entry_list[entry];
			else
				rsp->entry_list[entry] = entry_list[entry];
		}
	}

	/* Mark the allocated entries as used and set nixlf mapping */
	for (entry = 0; entry < rsp->count; entry++) {
		index = req->contig ?
			(rsp->entry + entry) : rsp->entry_list[entry];
		npc_mcam_set_bit(mcam, index);
		mcam->entry2pfvf_map[index] = pcifunc;
	}

	/* Update available free count in mbox response */
	rsp->free_count = mcam->bmap_fcnt;

	mutex_unlock(&mcam->lock);
	return 0;
}

int rvu_mbox_handler_npc_mcam_alloc_entry(struct rvu *rvu,
					  struct npc_mcam_alloc_entry_req *req,
					  struct npc_mcam_alloc_entry_rsp *rsp)
{
	struct npc_mcam *mcam = &rvu->hw->mcam;
	u16 pcifunc = req->hdr.pcifunc;
	int blkaddr;

	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
	if (blkaddr < 0)
		return NPC_MCAM_INVALID_REQ;

	rsp->entry = NPC_MCAM_ENTRY_INVALID;
	rsp->free_count = 0;

	/* Check if ref_entry is within range */
	if (req->priority && req->ref_entry >= mcam->bmap_entries)
		return NPC_MCAM_INVALID_REQ;

	/* ref_entry can't be '0' if requested priority is high.
	 * Can't be last entry if requested priority is low.
	 */
	if ((!req->ref_entry && req->priority == NPC_MCAM_HIGHER_PRIO) ||
	    ((req->ref_entry == (mcam->bmap_entries - 1)) &&
	     req->priority == NPC_MCAM_LOWER_PRIO))
		return NPC_MCAM_INVALID_REQ;

	/* Since list of allocated indices needs to be sent to requester,
	 * max number of non-contiguous entries per mbox msg is limited.
	 */
	if (!req->contig && req->count > NPC_MAX_NONCONTIG_ENTRIES)
		return NPC_MCAM_INVALID_REQ;

	/* Alloc request from PFFUNC with no NIXLF attached should be denied */
	if (!is_nixlf_attached(rvu, pcifunc))
		return NPC_MCAM_ALLOC_DENIED;

	return npc_mcam_alloc_entries(mcam, pcifunc, req, rsp);
}

int rvu_mbox_handler_npc_mcam_free_entry(struct rvu *rvu,
					 struct npc_mcam_free_entry_req *req,
					 struct msg_rsp *rsp)
{
	struct npc_mcam *mcam = &rvu->hw->mcam;
	u16 pcifunc = req->hdr.pcifunc;
	int blkaddr, rc = 0;

	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
	if (blkaddr < 0)
		return NPC_MCAM_INVALID_REQ;

	/* Free request from PFFUNC with no NIXLF attached, ignore */
	if (!is_nixlf_attached(rvu, pcifunc))
		return NPC_MCAM_INVALID_REQ;

	mutex_lock(&mcam->lock);

	if (req->all)
		goto free_all;

	rc = npc_mcam_verify_entry(mcam, pcifunc, req->entry);
	if (rc)
		goto exit;

	mcam->entry2pfvf_map[req->entry] = 0;
	npc_mcam_clear_bit(mcam, req->entry);
	npc_enable_mcam_entry(rvu, mcam, blkaddr, req->entry, false);

	goto exit;

free_all:
	/* Free up all entries allocated to requesting PFFUNC */
	npc_mcam_free_all_entries(rvu, mcam, blkaddr, pcifunc);
exit:
	mutex_unlock(&mcam->lock);
	return rc;
}