From nobody Sat Feb 7 19:41:08 2026 Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 701632BD035; Mon, 2 Feb 2026 07:46:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018403; cv=none; b=OBkAfXmfk1/TSjvgdE7FnpmRZQ6j48HsoR4hsvmxSc7+Pa+D5hdyHHoFviBTsVVQoHIxJJ5yI74EOiY8sOyKk6ohxqVpZnFKaFbkFjjgmahb9cYVosGDqkUIGspyYFmNIOvl59dXf4B6SIKWygiVUBeF0sEt7GkjmJmotLm77UU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018403; c=relaxed/simple; bh=wRt1WK9EdyqOCWm11ookKZk6qE791TnRzWrTBHaG8CE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=eL/2GNBKfjoUrb4yx3pxrsFT1+O1+JNb6ul1QDoLnIg3sedCWtve08hLywJM5eC6JB9lAlI0iuyCPSsxAKPWm5GsyUnKsQ/Vv7au91SU0DTVNK4e1Y2LAPmKHagds/2NQGi/o6BlWKfecMG/wtVaBRAWjH5GtW5TkedlAH28bWs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=ijh/Hhbz; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="ijh/Hhbz" Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 611N2MJr2646888; Sun, 1 Feb 2026 23:46:18 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=D VwZ39hHbqNHroUp/VOL2leqY7vqQSVIaS2o5IuCdqA=; b=ijh/HhbzkTwNlAcb+ wSln1y9j5BWurCi+3BKZrY5Om6v2fcxFEpj+V/RXqPwGqPq3jZBxom4NYLra/5Ik qGsbFdSOYU/mG4v10h5prSqzpV71V8318Fi6EnenxkD/XbW/KqX7M8MObjoAt8OS YXymo98WiubQ2xOrup41iqBICRv8HwKx5jkLCVEblJc6VeKXGOAJ2dVbV1cKYc+F yliSWOzQIhtqcIAJyCdsi6gCDb+upi6Aw/y/d77eFHIcFkIgpMIXy/wcGlhu84OF jZFMrPx8i2AEpctDybSNRB5KqPET199z8MjHjBl5XxMi4y51e5ai8FTb3oxKtGAt SmRPw== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4c28pe187k-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:18 -0800 (PST) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:46:33 -0800 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:46:33 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id E57245B6948; Sun, 1 Feb 2026 23:46:13 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH net-next v8 01/13] octeontx2-af: npc: cn20k: Index management Date: Mon, 2 Feb 2026 13:15:55 +0530 Message-ID: <20260202074607.2535569-2-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: c5yPp4SzQeH6_NlmMOMOv50-Zc33mUiv X-Authority-Analysis: v=2.4 cv=Y4/1cxeN c=1 sm=1 tr=0 ts=6980564a cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=qNCp7wmcbKduBwIh0tUA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfX1gSXyL4KGtz8 UyhUafwGn0G2h/IUNdmSbHJPHfAMIuuuj+hgYv8D6JSOFA92Fo6N5dalQSqgEUWUoCKzmcHUgSf xvGEkY7PfwD4XMS9bi8UuRV93tg7t/rfzsdUIHaMqFNWOyfD2uSDK3djtAHMoeWtKGgQAWIyVJB 7xTiTLe4PeS2FXgRzk0V5Uo6+a2X0Q/Rt85CmGBS+5iZlP2QTnwJRR8yEJRZdsGJyWuPqerS22T xOF3Agd7cZFk83DRnWaFUWBss3rEHuq0vOYlyE8ptvRzP2QZzp7aZSLChRv4xQiKjZ0B6at+daA TgGpBeoxno6xMSNQF10wpjTGkgOXOz8q2qPZ+24iAE945ubHJa56ZTEV2WAWrvzLsDCA+dlYI1j 1qhHlrk7bbhT7UWlW32MWSjM92onazmFCFnO67Bra5RFd7nouHRKq2f/n1cMmb+VKHZ8bl2T4aR E3/3gN9N1U7922D8H0Q== X-Proofpoint-GUID: c5yPp4SzQeH6_NlmMOMOv50-Zc33mUiv X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" 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=3D100, limit=3D200, contig=3D1, priority=3DLOW, and count=3D20 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 --- .../ethernet/marvell/octeontx2/af/Makefile | 2 +- .../marvell/octeontx2/af/cn20k/debugfs.c | 12 + .../marvell/octeontx2/af/cn20k/debugfs.h | 3 + .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 1754 +++++++++++++++++ .../ethernet/marvell/octeontx2/af/cn20k/npc.h | 110 ++ .../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 +- 10 files changed, 1911 insertions(+), 6 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/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/n= et/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 :=3D 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/dr= ivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c index 498968bf4cf5..0ba123be6643 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c @@ -11,7 +11,19 @@ #include =20 #include "struct.h" +#include "rvu.h" #include "debugfs.h" +#include "cn20k/npc.h" + +int npc_cn20k_debugfs_init(struct rvu *rvu) +{ + return 0; +} + +void npc_cn20k_debugfs_deinit(struct rvu *rvu) +{ + debugfs_remove_recursive(rvu->rvu_dbg.npc); +} =20 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/dr= ivers/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" =20 +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/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.c new file mode 100644 index 000000000000..9b5da2665b54 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c @@ -0,0 +1,1754 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2026 Marvell. + * + */ +#include +#include + +#include "cn20k/npc.h" +#include "cn20k/reg.h" + +static struct npc_priv_t npc_priv =3D { + .num_banks =3D MAX_NUM_BANKS, +}; + +static const char *npc_kw_name[NPC_MCAM_KEY_MAX] =3D { + [NPC_MCAM_KEY_DYN] =3D "DYNAMIC", + [NPC_MCAM_KEY_X2] =3D "X2", + [NPC_MCAM_KEY_X4] =3D "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 =3D + * subsection depth - 1 + */ + if (sb->key_type =3D=3D NPC_MCAM_KEY_X4 && + sub_off >=3D npc_priv.subbank_depth) { + dev_err(rvu->dev, + "%s: Failed to get mcam idx (x4) sb->idx=3D%u sub_off=3D%u", + __func__, sb->idx, sub_off); + return -EINVAL; + } + + /* for x2 section, maximum allowed subbank index =3D + * 2 * subsection depth - 1 + */ + if (sb->key_type =3D=3D NPC_MCAM_KEY_X2 && + sub_off >=3D npc_priv.subbank_depth * 2) { + dev_err(rvu->dev, + "%s: Failed to get mcam idx (x2) sb->idx=3D%u sub_off=3D%u", + __func__, sb->idx, sub_off); + return -EINVAL; + } + + /* Find subbank offset from respective subbank (w.r.t bank) */ + off =3D sub_off & (npc_priv.subbank_depth - 1); + + /* if subsection idx is in bank1, add bank depth, + * which is part of sb->b1b + */ + bot =3D sub_off >=3D npc_priv.subbank_depth ? sb->b1b : sb->b0b; + + *mcam_idx =3D 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 >=3D npc_priv.bank_depth * 2) { + dev_err(rvu->dev, "%s: Invalid mcam idx %u\n", + __func__, mcam_idx); + return -EINVAL; + } + + /* find mcam offset per bank */ + bank_off =3D mcam_idx & (npc_priv.bank_depth - 1); + + /* Find subbank id */ + sb_id =3D bank_off / npc_priv.subbank_depth; + + /* Check if subbank id is more than maximum + * number of subbanks available + */ + if (sb_id >=3D npc_priv.num_subbanks) { + dev_err(rvu->dev, "%s: invalid subbank %d\n", + __func__, sb_id); + return -EINVAL; + } + + *sb =3D &npc_priv.sb[sb_id]; + + /* Subbank offset per bank */ + *sb_off =3D bank_off % npc_priv.subbank_depth; + + /* Index in a subbank should add subbank depth + * if it is in bank1 + */ + if (mcam_idx >=3D npc_priv.bank_depth) + *sb_off +=3D 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 =3D 0; + int cnt =3D 0, sbd; + + sbd =3D npc_priv.subbank_depth; + + if (sidx >=3D npc_priv.bank_depth) + delta =3D sbd; + + switch (prio) { + case NPC_MCAM_LOWER_PRIO: + case NPC_MCAM_ANY_PRIO: + /* Find an area of size 'count' from sidx to eidx */ + offset =3D bitmap_find_next_zero_area(bmap, sbd, sidx - b, + count, 0); + + if (offset >=3D sbd) { + dev_err(rvu->dev, + "%s: Could not find contiguous(%d) entries\n", + __func__, count); + return -EFAULT; + } + + dev_dbg(rvu->dev, + "%s: sidx=3D%d eidx=3D%d t=3D%d b=3D%d offset=3D%d count=3D%d delta=3D%= d\n", + __func__, sidx, eidx, t, b, offset, + count, delta); + + for (cnt =3D 0; cnt < count; cnt++) + save[cnt] =3D offset + cnt + delta; + + break; + + case NPC_MCAM_HIGHER_PRIO: + /* Find an area of 'count' from eidx to sidx */ + for (k =3D eidx - b; cnt < count && k >=3D (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 =3D 0; + continue; + } + + save[cnt++] =3D k + delta; + } + break; + } + + /* Found 'count' number of free slots */ + if (cnt =3D=3D count) + return 0; + + dev_dbg(rvu->dev, + "%s: Could not find contiguous(%d) entries in subbank=3D%u\n", + __func__, count, sb->idx); + return -EFAULT; +} + +static int __npc_subbank_non_contig_alloc(struct rvu *rvu, + struct npc_subbank *sb, + int key_type, int sidx, + int eidx, int prio, + int t, int b, + unsigned long *bmap, + int count, u16 *save, + bool max_alloc, int *alloc_cnt) +{ + unsigned long index; + int cnt =3D 0, delta; + int k, sbd; + + sbd =3D npc_priv.subbank_depth; + delta =3D sidx >=3D 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 =3D find_next_zero_bit(bmap, sbd, sidx - b); + if (index >=3D sbd) { + dev_err(rvu->dev, + "%s: Error happened to alloc %u, bitmap_weight=3D%u, sb->idx=3D%u\n", + __func__, count, + bitmap_weight(bmap, sbd), + sb->idx); + break; + } + + for (k =3D index; cnt < count && k <=3D (eidx - b); k++) { + /* Skip used slots */ + if (test_bit(k, bmap)) + continue; + + save[cnt++] =3D k + delta; + } + break; + + /* Find an area of 'count' from eidx to sidx */ + case NPC_MCAM_HIGHER_PRIO: + for (k =3D eidx - b; cnt < count && k >=3D (sidx - b); k--) { + /* Skip used slots */ + if (test_bit(k, bmap)) + continue; + + save[cnt++] =3D k + delta; + } + break; + } + + /* Update allocated 'cnt' to alloc_cnt */ + *alloc_cnt =3D cnt; + + /* Successfully allocated requested count slots */ + if (cnt =3D=3D count) + return 0; + + /* Allocation successful for cnt < count */ + if (max_alloc && cnt > 0) + return 0; + + dev_dbg(rvu->dev, + "%s: Could not find non contiguous entries(%u) in subbank(%u) cnt=3D%d m= ax_alloc=3D%d\n", + __func__, count, sb->idx, cnt, max_alloc); + + return -EFAULT; +} + +static void __npc_subbank_sboff_2_off(struct rvu *rvu, struct npc_subbank = *sb, + int sb_off, unsigned long **bmap, + int *off) +{ + int sbd; + + sbd =3D npc_priv.subbank_depth; + + *off =3D sb_off & (sbd - 1); + *bmap =3D (sb_off >=3D 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 >=3D subbank.depth, then slots are in + * bank1 + */ + __npc_subbank_sboff_2_off(rvu, sb, sb_off, &bmap, &off); + + dev_dbg(rvu->dev, + "%s: Marking set=3D%d sb_off=3D%d sb->idx=3D%d off=3D%d\n", + __func__, set, sb_off, sb->idx, off); + + if (set) { + /* Slot is already used */ + if (test_bit(off, bmap)) + return false; + + sb->free_cnt--; + set_bit(off, bmap); + return true; + } + + /* Slot is already free */ + if (!test_bit(off, bmap)) + return false; + + sb->free_cnt++; + clear_bit(off, bmap); + return true; +} + +static int __npc_subbank_mark_free(struct rvu *rvu, struct npc_subbank *sb) +{ + int rc, blkaddr; + void *val; + + sb->flags =3D NPC_SUBBANK_FLAG_FREE; + sb->key_type =3D 0; + + bitmap_clear(sb->b0map, 0, npc_priv.subbank_depth); + bitmap_clear(sb->b1map, 0, npc_priv.subbank_depth); + + if (!xa_erase(&npc_priv.xa_sb_used, sb->arr_idx)) { + dev_err(rvu->dev, + "%s: Error to delete from xa_sb_used array\n", + __func__); + return -EFAULT; + } + + rc =3D xa_insert(&npc_priv.xa_sb_free, sb->arr_idx, + xa_mk_value(sb->idx), GFP_KERNEL); + if (rc) { + val =3D xa_load(&npc_priv.xa_sb_free, sb->arr_idx); + dev_err(rvu->dev, + "%s: Error to add sb(%u) to xa_sb_free array at arr_idx=3D%d, val=3D%lu= \n", + __func__, sb->idx, sb->arr_idx, xa_to_value(val)); + } + + blkaddr =3D 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 =3D NPC_SUBBANK_FLAG_USED; + sb->key_type =3D key_type; + if (key_type =3D=3D NPC_MCAM_KEY_X4) + sb->free_cnt =3D npc_priv.subbank_depth; + else + sb->free_cnt =3D 2 * npc_priv.subbank_depth; + + bitmap_clear(sb->b0map, 0, npc_priv.subbank_depth); + bitmap_clear(sb->b1map, 0, npc_priv.subbank_depth); + + if (!xa_erase(&npc_priv.xa_sb_free, sb->arr_idx)) { + dev_err(rvu->dev, + "%s: Error to delete from xa_sb_free array\n", + __func__); + return -EFAULT; + } + + rc =3D xa_insert(&npc_priv.xa_sb_used, sb->arr_idx, + xa_mk_value(sb->idx), GFP_KERNEL); + if (rc) + dev_err(rvu->dev, + "%s: Error to add to xa_sb_used array\n", __func__); + + return rc; +} + +static bool __npc_subbank_free(struct rvu *rvu, struct npc_subbank *sb, + u16 sb_off) +{ + bool deleted =3D false; + unsigned long *bmap; + int rc, off; + + deleted =3D __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 =3D=3D 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 =3D __npc_subbank_mark_free(rvu, sb); + if (rc) + dev_err(rvu->dev, "%s: Error to free subbank\n", __func__); + +done: + return deleted; +} + +static int +npc_subbank_free(struct rvu *rvu, struct npc_subbank *sb, u16 sb_off) +{ + bool deleted; + + mutex_lock(&sb->lock); + deleted =3D __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 =3D false; + unsigned long *bmap; + u16 *save =3D NULL; + int sidx, eidx; + bool diffbank; + int bw, bfree; + int rc =3D 0; + bool ret; + + /* Check if enough space is there to return requested number of + * mcam indexes in case of contiguous allocation + */ + if (!max_alloc && count > idx_sz) { + dev_err(rvu->dev, + "%s: Less space, count=3D%d idx_sz=3D%d sb_id=3D%d\n", + __func__, count, idx_sz, sb->idx); + return -ENOSPC; + } + + /* Allocation on multiple subbank is not supported by this function. + * it means that ref and limit should be on same subbank. + * + * ref and limit values should be validated w.r.t prio as below. + * say ref =3D 100, limit =3D 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 =3D 200, limit =3D 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 =3D=3D NPC_MCAM_LOWER_PRIO && ref > limit) || + (prio =3D=3D NPC_MCAM_HIGHER_PRIO && ref < limit)) { + dev_err(rvu->dev, "%s: Wrong ref_enty(%d) or limit(%d)\n", + __func__, ref, limit); + return -EINVAL; + } + + /* x4 indexes are from 0 to bank size as it combines two x2 banks */ + if (key_type =3D=3D NPC_MCAM_KEY_X4 && + (ref >=3D npc_priv.bank_depth || limit >=3D npc_priv.bank_depth)) { + dev_err(rvu->dev, + "%s: Wrong ref_enty(%d) or limit(%d) for x4\n", + __func__, ref, limit); + return -EINVAL; + } + + /* This function is called either bank0 or bank1 portion of a subbank. + * so ref and limit should be on same bank. + */ + diffbank =3D !!((ref & npc_priv.bank_depth) ^ + (limit & npc_priv.bank_depth)); + if (diffbank) { + dev_err(rvu->dev, + "%s: request ref and limit should be from same bank\n", + __func__); + return -EINVAL; + } + + sidx =3D min_t(int, limit, ref); + eidx =3D max_t(int, limit, ref); + + /* Find total number of slots available; both used and free */ + cnt =3D eidx - sidx + 1; + if (contig && cnt < count) { + dev_err(rvu->dev, + "%s: Wrong ref_enty(%d) or limit(%d) for count(%d)\n", + __func__, ref, limit, count); + return -EINVAL; + } + + /* If subbank is free, check if requested number of indexes is less than + * or equal to mcam entries available in the subbank if contig. + */ + if (sb->flags & NPC_SUBBANK_FLAG_FREE) { + if (contig && count > npc_priv.subbank_depth) { + dev_err(rvu->dev, "%s: Less number of entries\n", + __func__); + goto err; + } + + new_sub_bank =3D 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 !=3D key_type) { + dev_dbg(rvu->dev, "%s: subbank key_type mismatch\n", __func__); + rc =3D -EINVAL; + goto err; + } + +process: + /* if ref or limit >=3D npc_priv.bank_depth, index are in bank1. + * else bank0. + */ + if (ref >=3D npc_priv.bank_depth) { + bmap =3D sb->b1map; + t =3D sb->b1t; + b =3D sb->b1b; + } else { + bmap =3D sb->b0map; + t =3D sb->b0t; + b =3D sb->b0b; + } + + /* Calculate free slots */ + bw =3D bitmap_weight(bmap, npc_priv.subbank_depth); + bfree =3D npc_priv.subbank_depth - bw; + + if (!bfree) { + rc =3D -ENOSPC; + goto err; + } + + /* If request is for contiguous , then max we can allocate is + * equal to subbank_depth + */ + if (contig && bfree < count) { + rc =3D -ENOSPC; + dev_err(rvu->dev, "%s: no space for entry\n", __func__); + goto err; + } + + /* 'save' array stores available indexes temporarily before + * marking it as allocated + */ + save =3D kcalloc(count, sizeof(u16), GFP_KERNEL); + if (!save) { + rc =3D -ENOMEM; + goto err; + } + + if (contig) { + rc =3D __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 =3D count; + + } else { + rc =3D __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 =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) { + dev_err(rvu->dev, + "%s: NPC block not implemented\n", __func__); + rc =3D -EFAULT; + goto err; + } + + rc =3D __npc_subbank_mark_used(rvu, sb, key_type); + if (rc) { + dev_err(rvu->dev, + "%s: Error to mark subbank as used\n", + __func__); + goto err; + } + + /* Configure section type to key_type */ + rvu_write64(rvu, blkaddr, + NPC_AF_MCAM_SECTIONX_CFG_EXT(sb->idx), + key_type); + } + + for (i =3D 0; i < *alloc_cnt; i++) { + rc =3D npc_subbank_idx_2_mcam_idx(rvu, sb, save[i], + &mcam_idx[i]); + if (rc) { + dev_err(rvu->dev, + "%s: Error to find mcam idx for %u\n", + __func__, save[i]); + /* TODO: handle err case gracefully */ + goto err; + } + + /* Mark all slots as used */ + ret =3D __npc_subbank_mark_slot(rvu, sb, save[i], true); + if (!ret) { + dev_err(rvu->dev, "%s: Error to mark mcam_idx %u\n", + __func__, mcam_idx[i]); + rc =3D -EFAULT; + goto err; + } + } + +err: + kfree(save); + return rc; +} + +static int +npc_subbank_alloc(struct rvu *rvu, struct npc_subbank *sb, + int key_type, int ref, int limit, int prio, + bool contig, int count, u16 *mcam_idx, + int idx_sz, bool max_alloc, int *alloc_cnt) +{ + int rc; + + mutex_lock(&sb->lock); + rc =3D __npc_subbank_alloc(rvu, sb, key_type, ref, limit, prio, + contig, count, mcam_idx, idx_sz, + max_alloc, alloc_cnt); + mutex_unlock(&sb->lock); + + return rc; +} + +static int +npc_del_from_pf_maps(struct rvu *rvu, u16 mcam_idx) +{ + int pcifunc, idx; + void *map; + + map =3D xa_erase(&npc_priv.xa_idx2pf_map, mcam_idx); + if (!map) { + dev_err(rvu->dev, + "%s: failed to erase mcam_idx(%u) from xa_idx2pf map\n", + __func__, mcam_idx); + return -EFAULT; + } + + pcifunc =3D xa_to_value(map); + map =3D xa_load(&npc_priv.xa_pf_map, pcifunc); + idx =3D xa_to_value(map); + + map =3D xa_erase(&npc_priv.xa_pf2idx_map[idx], mcam_idx); + if (!map) { + dev_err(rvu->dev, + "%s: failed to erase mcam_idx(%u) from xa_pf2idx_map map\n", + __func__, mcam_idx); + return -EFAULT; + } + return 0; +} + +static int +npc_add_to_pf_maps(struct rvu *rvu, u16 mcam_idx, int pcifunc) +{ + int rc, idx; + void *map; + + dev_dbg(rvu->dev, + "%s: add2maps mcam_idx(%u) to xa_idx2pf map pcifunc=3D%#x\n", + __func__, mcam_idx, pcifunc); + + rc =3D xa_insert(&npc_priv.xa_idx2pf_map, mcam_idx, + xa_mk_value(pcifunc), GFP_KERNEL); + + if (rc) { + map =3D xa_load(&npc_priv.xa_idx2pf_map, mcam_idx); + dev_err(rvu->dev, + "%s: failed to insert mcam_idx(%u) to xa_idx2pf map, existing value=3D%= lu\n", + __func__, mcam_idx, xa_to_value(map)); + return -EFAULT; + } + + map =3D xa_load(&npc_priv.xa_pf_map, pcifunc); + idx =3D xa_to_value(map); + + rc =3D xa_insert(&npc_priv.xa_pf2idx_map[idx], mcam_idx, + xa_mk_value(pcifunc), GFP_KERNEL); + + if (rc) { + map =3D xa_load(&npc_priv.xa_pf2idx_map[idx], mcam_idx); + xa_erase(&npc_priv.xa_idx2pf_map, mcam_idx); + dev_err(rvu->dev, + "%s: failed to insert mcam_idx(%u) to xa_pf2idx_map map, earlier value= =3D%lu idx=3D%u\n", + __func__, mcam_idx, xa_to_value(map), idx); + + return -EFAULT; + } + + return 0; +} + +static bool +npc_subbank_suits(struct npc_subbank *sb, int key_type) +{ + mutex_lock(&sb->lock); + + if (!sb->key_type) { + mutex_unlock(&sb->lock); + return true; + } + + if (sb->key_type =3D=3D 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 =3D false; + + /* ALIGN_DOWN the limit to current subbank boundary bottom index */ + if (*start) { + *start =3D false; + *cur_ref =3D ref; + align =3D SB_ALIGN_DOWN(ref); + if (align < limit) { + *stop =3D true; + *cur_limit =3D limit; + return; + } + *cur_limit =3D align; + return; + } + + *cur_ref =3D *cur_limit - 1; + align =3D *cur_ref - npc_priv.subbank_depth + 1; + if (align <=3D limit) { + *stop =3D true; + *cur_limit =3D limit; + return; + } + + *cur_limit =3D 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 =3D false; + + /* ALIGN_UP the limit to current subbank boundary top index */ + if (*start) { + *start =3D false; + *cur_ref =3D ref; + + /* Find next lower prio subbank's bottom index */ + align =3D SB_ALIGN_UP(ref); + + /* Crosses limit ? */ + if (align - 1 > limit) { + *stop =3D true; + *cur_limit =3D limit; + return; + } + + /* Current subbank's top index */ + *cur_limit =3D align - 1; + return; + } + + *cur_ref =3D *cur_limit + 1; + align =3D *cur_ref + npc_priv.subbank_depth - 1; + + if (align >=3D limit) { + *stop =3D true; + *cur_limit =3D limit; + return; + } + + *cur_limit =3D align; +} + +static int +npc_subbank_iter(struct rvu *rvu, int key_type, + int ref, int limit, int prio, + int *cur_ref, int *cur_limit, + bool *start, bool *stop) +{ + if (prio !=3D 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 =3D=3D NPC_MCAM_KEY_X4) { + if (*cur_ref >=3D npc_priv.bank_depth) + return -EINVAL; + + if (*cur_limit >=3D npc_priv.bank_depth) + return -EINVAL; + } + /* limit and ref should < 2 * bank_depth, for x2 */ + if (*cur_ref >=3D 2 * npc_priv.bank_depth) + return -EINVAL; + + if (*cur_limit >=3D 2 * npc_priv.bank_depth) + return -EINVAL; + + return 0; +} + +static int npc_idx_free(struct rvu *rvu, u16 *mcam_idx, int count, + bool maps_del) +{ + struct npc_subbank *sb; + int idx, i; + bool ret; + int rc; + + /* Check if we can dealloc indexes properly ? */ + for (i =3D 0; i < count; i++) { + rc =3D npc_mcam_idx_2_subbank_idx(rvu, mcam_idx[i], + &sb, &idx); + if (rc) { + dev_err(rvu->dev, + "Failed to free mcam idx=3D%u\n", mcam_idx[i]); + return rc; + } + } + + for (i =3D 0; i < count; i++) { + rc =3D npc_mcam_idx_2_subbank_idx(rvu, mcam_idx[i], + &sb, &idx); + if (rc) + return rc; + + ret =3D npc_subbank_free(rvu, sb, idx); + if (ret) + return -EINVAL; + + if (!maps_del) + continue; + + rc =3D 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 =3D 0; + bool bitset; + + if (prio !=3D NPC_MCAM_HIGHER_PRIO) { + while (ref <=3D limit) { + /* Calculate subbank and subbank index */ + rc =3D 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 =3D SB_ALIGN_UP(ref); + if (contig) { + rc =3D npc_idx_free(rvu, mcam_idx, + cnt, false); + if (rc) + return rc; + cnt =3D 0; + } + continue; + } + + mutex_lock(&sb->lock); + + /* If subbank is free; mark it as used */ + if (sb->flags & NPC_SUBBANK_FLAG_FREE) { + rc =3D __npc_subbank_mark_used(rvu, sb, + key_type); + if (rc) { + mutex_unlock(&sb->lock); + dev_err(rvu->dev, + "%s:Error to add to use array\n", + __func__); + goto err; + } + } + + /* Find correct bmap */ + __npc_subbank_sboff_2_off(rvu, sb, sb_off, &bmap, &off); + + /* if bit is already set, reset 'cnt' */ + bitset =3D test_bit(off, bmap); + if (bitset) { + mutex_unlock(&sb->lock); + if (contig) { + rc =3D npc_idx_free(rvu, mcam_idx, + cnt, false); + if (rc) + return rc; + cnt =3D 0; + } + + ref++; + continue; + } + + set_bit(off, bmap); + sb->free_cnt--; + mcam_idx[cnt++] =3D ref; + mutex_unlock(&sb->lock); + + if (cnt =3D=3D count) + return 0; + ref++; + } + + /* Could not allocate request count slots */ + goto err; + } + while (ref >=3D limit) { + rc =3D npc_mcam_idx_2_subbank_idx(rvu, ref, + &sb, &sb_off); + if (rc) + goto err; + + if (!npc_subbank_suits(sb, key_type)) { + ref =3D SB_ALIGN_DOWN(ref) - 1; + if (contig) { + rc =3D npc_idx_free(rvu, mcam_idx, cnt, false); + if (rc) + return rc; + + cnt =3D 0; + } + continue; + } + + mutex_lock(&sb->lock); + + if (sb->flags & NPC_SUBBANK_FLAG_FREE) { + rc =3D __npc_subbank_mark_used(rvu, sb, key_type); + if (rc) { + mutex_unlock(&sb->lock); + dev_err(rvu->dev, + "%s:Error to add to use array\n", + __func__); + goto err; + } + } + + __npc_subbank_sboff_2_off(rvu, sb, sb_off, &bmap, &off); + bitset =3D test_bit(off, bmap); + if (bitset) { + mutex_unlock(&sb->lock); + if (contig) { + rc =3D npc_idx_free(rvu, mcam_idx, cnt, false); + if (rc) + return rc; + + cnt =3D 0; + } + ref--; + continue; + } + + mcam_idx[cnt++] =3D ref; + sb->free_cnt--; + set_bit(off, bmap); + mutex_unlock(&sb->lock); + + if (cnt =3D=3D count) + return 0; + ref--; + } + +err: + rc =3D npc_idx_free(rvu, mcam_idx, cnt, false); + if (rc) + dev_err(rvu->dev, + "%s: Error happened while freeing cnt=3D%u indexes\n", + __func__, cnt); + + return -ENOSPC; +} + +static int npc_subbank_free_cnt(struct rvu *rvu, struct npc_subbank *sb, + int key_type) +{ + int cnt, spd; + + spd =3D npc_priv.subbank_depth; + mutex_lock(&sb->lock); + + if (sb->flags & NPC_SUBBANK_FLAG_FREE) + cnt =3D key_type =3D=3D NPC_MCAM_KEY_X4 ? spd : 2 * spd; + else + cnt =3D 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 =3D 0, rc; + int alloc_cnt; + + max_alloc =3D !contig; + + start =3D true; + stop =3D false; + + /* Loop until we cross the ref/limit boundary */ + while (!stop) { + rc =3D npc_subbank_iter(rvu, key_type, ref, limit, prio, + &r, &l, &start, &stop); + + dev_dbg(rvu->dev, + "%s: ref=3D%d limit=3D%d r=3D%d l=3D%d start=3D%d stop=3D%d tot=3D%d co= unt=3D%d rc=3D%d\n", + __func__, ref, limit, r, l, + start, stop, tot, count, rc); + + if (rc) + goto err; + + /* Find subbank and subbank index for ref */ + rc =3D npc_mcam_idx_2_subbank_idx(rvu, r, &sb1, + &sb_idx1); + if (rc) + goto err; + + dev_dbg(rvu->dev, + "%s: ref subbank=3D%d off=3D%d\n", + __func__, sb1->idx, sb_idx1); + + /* Skip subbank if it is not available for the keytype */ + if (!npc_subbank_suits(sb1, key_type)) { + dev_dbg(rvu->dev, + "%s: not suitable sb=3D%d key_type=3D%d\n", + __func__, sb1->idx, key_type); + continue; + } + + /* Find subbank and subbank index for limit */ + rc =3D npc_mcam_idx_2_subbank_idx(rvu, l, &sb2, + &sb_idx2); + if (rc) + goto err; + + dev_dbg(rvu->dev, + "%s: limit subbank=3D%d off=3D%d\n", + __func__, sb_idx1, sb_idx2); + + /* subbank of ref and limit should be same */ + if (sb1 !=3D sb2) { + dev_err(rvu->dev, + "%s: l(%d) and r(%d) are not in same subbank\n", + __func__, r, l); + goto err; + } + + if (contig && + npc_subbank_free_cnt(rvu, sb1, key_type) < count) { + dev_dbg(rvu->dev, "%s: less count =3D%d\n", + __func__, + npc_subbank_free_cnt(rvu, sb1, key_type)); + continue; + } + + /* Try in one bank of a subbank */ + alloc_cnt =3D 0; + rc =3D npc_subbank_alloc(rvu, sb1, key_type, + r, l, prio, contig, + count - tot, mcam_idx + tot, + count - tot, max_alloc, + &alloc_cnt); + + tot +=3D alloc_cnt; + + dev_dbg(rvu->dev, "%s: Allocated tot=3D%d alloc_cnt=3D%d\n", + __func__, tot, alloc_cnt); + + if (!rc && count =3D=3D tot) + return 0; + } +err: + dev_dbg(rvu->dev, "%s: Error to allocate\n", + __func__); + + /* non contiguous allocation fails. We need to do clean up */ + if (max_alloc) { + rc =3D npc_idx_free(rvu, mcam_idx, tot, false); + if (rc) + dev_err(rvu->dev, + "%s: failed to free %u indexes\n", + __func__, tot); + } + + return -EFAULT; +} + +/* Minimize allocation from bottom and top subbanks for noref allocations. + * Default allocations are ref based, and will be allocated from top + * subbanks (least priority subbanks). Since default allocation is at very + * early stage of kernel netdev probes, this subbanks will be moved to + * used subbanks list. This will pave a way for noref allocation from these + * used subbanks. Skip allocation for these top and bottom, and try free + * bank next. If none slot is available, come back and search in these + * subbanks. + */ + +static int npc_subbank_restricted_idxs[2]; +static bool restrict_valid =3D true; + +static bool npc_subbank_restrict_usage(struct rvu *rvu, int index) +{ + int i; + + if (!restrict_valid) + return false; + + for (i =3D 0; i < ARRAY_SIZE(npc_subbank_restricted_idxs); i++) { + if (index =3D=3D npc_subbank_restricted_idxs[i]) + return true; + } + + return false; +} + +static int npc_subbank_noref_alloc(struct rvu *rvu, int key_type, bool con= tig, + int count, u16 *mcam_idx) +{ + struct npc_subbank *sb; + unsigned long index; + int tot =3D 0, rc; + bool max_alloc; + int alloc_cnt; + int idx, i; + void *val; + + max_alloc =3D !contig; + + /* Check used subbanks for free slots */ + xa_for_each(&npc_priv.xa_sb_used, index, val) { + idx =3D xa_to_value(val); + + /* Minimize allocation from restricted subbanks + * in noref allocations. + */ + if (npc_subbank_restrict_usage(rvu, idx)) + continue; + + sb =3D &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 =3D 0; + rc =3D 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 +=3D alloc_cnt; + + dev_dbg(rvu->dev, + "%s: Allocated %d from subbank %d, tot=3D%d count=3D%d\n", + __func__, alloc_cnt, sb->idx, tot, count); + + /* Successfully allocated */ + if (!rc && count =3D=3D tot) + return 0; + + /* x4 entries can be allocated from bank 0 only */ + if (key_type =3D=3D NPC_MCAM_KEY_X4) + continue; + + /* try in bank 1 for x2 */ + alloc_cnt =3D 0; + rc =3D 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 +=3D alloc_cnt; + + dev_dbg(rvu->dev, + "%s: Allocated %d from subbank %d, tot=3D%d count=3D%d\n", + __func__, alloc_cnt, sb->idx, tot, count); + + if (!rc && count =3D=3D tot) + return 0; + } + + /* Allocate in free subbanks */ + xa_for_each(&npc_priv.xa_sb_free, index, val) { + idx =3D xa_to_value(val); + sb =3D &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 =3D 0; + rc =3D 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 +=3D alloc_cnt; + + dev_dbg(rvu->dev, + "%s: Allocated %d from subbank %d, tot=3D%d count=3D%d\n", + __func__, alloc_cnt, sb->idx, tot, count); + + /* Successfully allocated */ + if (!rc && count =3D=3D tot) + return 0; + + /* x4 entries can be allocated from bank 0 only */ + if (key_type =3D=3D NPC_MCAM_KEY_X4) + continue; + + /* try in bank 1 for x2 */ + alloc_cnt =3D 0; + rc =3D 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 +=3D alloc_cnt; + + dev_dbg(rvu->dev, + "%s: Allocated %d from subbank %d, tot=3D%d count=3D%d\n", + __func__, alloc_cnt, sb->idx, tot, count); + + if (!rc && count =3D=3D tot) + return 0; + } + + /* Allocate from restricted subbanks */ + for (i =3D 0; restrict_valid && + (i < ARRAY_SIZE(npc_subbank_restricted_idxs)); i++) { + idx =3D npc_subbank_restricted_idxs[i]; + sb =3D &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 =3D 0; + rc =3D 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 +=3D alloc_cnt; + + dev_dbg(rvu->dev, + "%s: Allocated %d from subbank %d, tot=3D%d count=3D%d\n", + __func__, alloc_cnt, sb->idx, tot, count); + + /* Successfully allocated */ + if (!rc && count =3D=3D tot) + return 0; + + /* x4 entries can be allocated from bank 0 only */ + if (key_type =3D=3D NPC_MCAM_KEY_X4) + continue; + + /* try in bank 1 for x2 */ + alloc_cnt =3D 0; + rc =3D 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 +=3D alloc_cnt; + + dev_dbg(rvu->dev, + "%s: Allocated %d from subbank %d, tot=3D%d count=3D%d\n", + __func__, alloc_cnt, sb->idx, tot, count); + + if (!rc && count =3D=3D tot) + return 0; + } + + /* non contiguous allocation fails. We need to do clean up */ + if (max_alloc) + npc_idx_free(rvu, mcam_idx, tot, false); + + dev_dbg(rvu->dev, "%s: non-contig allocation fails\n", + __func__); + + return -EFAULT; +} + +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 =3D npc_priv.bank_depth; + + /* Special case: ref =3D=3D 0 && limit=3D 0 && prio =3D=3D HIGH && count = =3D=3D 1 + * Here user wants to allocate 0th entry + */ + if (!ref && !limit && prio =3D=3D NPC_MCAM_HIGHER_PRIO && + count =3D=3D 1) { + rc =3D npc_subbank_ref_alloc(rvu, key_type, ref, limit, + prio, contig, count, mcam_idx); + + if (rc) + return rc; + goto add2map; + } + + ref_valid =3D !!(limit || ref); + if (!ref_valid) { + if (contig && count > npc_priv.subbank_depth) + goto try_noref_multi_subbank; + + rc =3D npc_subbank_noref_alloc(rvu, key_type, contig, + count, mcam_idx); + if (!rc) + goto add2map; + +try_noref_multi_subbank: + eidx =3D (key_type =3D=3D NPC_MCAM_KEY_X4) ? bd - 1 : 2 * bd - 1; + + if (prio =3D=3D NPC_MCAM_HIGHER_PRIO) + rc =3D npc_multi_subbank_ref_alloc(rvu, key_type, + eidx, 0, + NPC_MCAM_HIGHER_PRIO, + contig, count, + mcam_idx); + else + rc =3D 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 =3D=3D NPC_MCAM_LOWER_PRIO && ref > limit) || + (prio =3D=3D NPC_MCAM_HIGHER_PRIO && ref < limit)) { + dev_err(rvu->dev, "%s: Wrong ref_enty(%d) or limit(%d)\n", + __func__, ref, limit); + return -EINVAL; + } + + if ((key_type =3D=3D NPC_MCAM_KEY_X4 && (ref >=3D bd || limit >=3D bd)) || + (key_type =3D=3D NPC_MCAM_KEY_X2 && + (ref >=3D 2 * bd || limit >=3D 2 * bd))) { + dev_err(rvu->dev, "%s: Wrong ref_enty(%d) or limit(%d)\n", + __func__, ref, limit); + return -EINVAL; + } + + if (contig && count > npc_priv.subbank_depth) + goto try_ref_multi_subbank; + + rc =3D npc_subbank_ref_alloc(rvu, key_type, ref, limit, + prio, contig, count, mcam_idx); + if (!rc) + goto add2map; + +try_ref_multi_subbank: + rc =3D npc_multi_subbank_ref_alloc(rvu, key_type, + ref, limit, prio, + contig, count, mcam_idx); + if (!rc) + goto add2map; + + return rc; + +add2map: + for (i =3D 0; i < count; i++) { + rc =3D 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 =3D 0; + *x4_free =3D 0; + *sb_free =3D 0; + + for (i =3D 0; i < npc_priv.num_subbanks; i++) { + sb =3D &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 =3D=3D NPC_MCAM_KEY_X4) { + (*x4_free) +=3D sb->free_cnt; + goto next; + } + + /* Sumup x2 free counts */ + (*x2_free) +=3D sb->free_cnt; +next: + mutex_unlock(&sb->lock); + } +} + +int +rvu_mbox_handler_npc_cn20k_get_fcnt(struct rvu *rvu, + struct msg_req *req, + struct npc_cn20k_get_fcnt_rsp *rsp) +{ + npc_cn20k_subbank_calc_free(rvu, &rsp->free_x2, + &rsp->free_x4, &rsp->free_subbanks); + return 0; +} + +static int *subbank_srch_order; + +static void npc_populate_restricted_idxs(int num_subbanks) +{ + npc_subbank_restricted_idxs[0] =3D num_subbanks - 1; + npc_subbank_restricted_idxs[1] =3D 0; +} + +static int npc_create_srch_order(int cnt) +{ + int val =3D 0; + + subbank_srch_order =3D kcalloc(cnt, sizeof(int), + GFP_KERNEL); + if (!subbank_srch_order) + return -ENOMEM; + + /* cnt(subbank depth) is always even. There is a check in + * npc_priv_init() to check the same. + */ + for (int i =3D 0; i < cnt; i +=3D 2) { + subbank_srch_order[i] =3D cnt / 2 - val - 1; + subbank_srch_order[i + 1] =3D cnt / 2 + 1 + val; + val++; + } + + subbank_srch_order[cnt - 1] =3D cnt / 2; + return 0; +} + +static void npc_subbank_init(struct rvu *rvu, struct npc_subbank *sb, int = idx) +{ + mutex_init(&sb->lock); + + sb->b0b =3D idx * npc_priv.subbank_depth; + sb->b0t =3D sb->b0b + npc_priv.subbank_depth - 1; + + sb->b1b =3D npc_priv.bank_depth + idx * npc_priv.subbank_depth; + sb->b1t =3D sb->b1b + npc_priv.subbank_depth - 1; + + sb->flags =3D NPC_SUBBANK_FLAG_FREE; + sb->idx =3D idx; + sb->arr_idx =3D subbank_srch_order[idx]; + + dev_dbg(rvu->dev, "%s: sb->idx=3D%u sb->arr_idx=3D%u\n", + __func__, 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 =3D 0; + u16 pcifunc; + u64 cfg; + + for (pf =3D 0; pf < rvu->hw->total_pfs; pf++) { + cfg =3D rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf)); + numvfs =3D (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 =3D pf << 9; + + xa_store(&npc_priv.xa_pf_map, (unsigned long)pcifunc, + xa_mk_value(cnt), GFP_KERNEL); + + cnt++; + +chk_vfs: + for (vf =3D 0; vf < numvfs; vf++) { + pcifunc =3D (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 =3D &rvu->hw->mcam; + int blkaddr, num_banks, bank_depth; + int num_subbanks, subbank_depth; + u64 npc_const1, npc_const2 =3D 0; + struct npc_subbank *sb; + u64 cfg; + int i; + + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) { + dev_err(rvu->dev, "%s: NPC block not implemented\n", + __func__); + return -ENODEV; + } + + npc_const1 =3D rvu_read64(rvu, blkaddr, NPC_AF_CONST1); + if (npc_const1 & BIT_ULL(63)) + npc_const2 =3D rvu_read64(rvu, blkaddr, NPC_AF_CONST2); + + num_banks =3D mcam->banks; + bank_depth =3D mcam->banksize; + + num_subbanks =3D FIELD_GET(GENMASK_ULL(39, 32), npc_const2); + if (!num_subbanks) { + dev_err(rvu->dev, "Number of subbanks is zero\n"); + return -EFAULT; + } + + if (num_subbanks & (num_subbanks - 1)) { + dev_err(rvu->dev, + "subbanks cnt(%u) should be a multiple of 2\n", + num_subbanks); + return -EINVAL; + } + + npc_priv.num_subbanks =3D num_subbanks; + + subbank_depth =3D bank_depth / num_subbanks; + + npc_priv.bank_depth =3D bank_depth; + npc_priv.subbank_depth =3D subbank_depth; + + /* Get kex configured key size */ + cfg =3D rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(0)); + npc_priv.kw =3D FIELD_GET(GENMASK_ULL(34, 32), cfg); + + dev_info(rvu->dev, + "banks=3D%u depth=3D%u, subbanks=3D%u depth=3D%u, key type=3D%s\n", + num_banks, bank_depth, num_subbanks, subbank_depth, + npc_kw_name[npc_priv.kw]); + + npc_priv.sb =3D 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); + + if (npc_create_srch_order(num_subbanks)) + goto fail1; + + npc_populate_restricted_idxs(num_subbanks); + + /* Initialize subbanks */ + for (i =3D 0, sb =3D 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 =3D npc_pcifunc_map_create(rvu); + npc_priv.xa_pf2idx_map =3D kcalloc(npc_priv.pf_cnt, + sizeof(struct xarray), + GFP_KERNEL); + if (!npc_priv.xa_pf2idx_map) + goto fail2; + + for (i =3D 0; i < npc_priv.pf_cnt; i++) + xa_init_flags(&npc_priv.xa_pf2idx_map[i], XA_FLAGS_ALLOC); + + return 0; + +fail2: + kfree(subbank_srch_order); + +fail1: + 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); + kfree(npc_priv.sb); + return -ENOMEM; +} + +void npc_cn20k_deinit(struct rvu *rvu) +{ + int i; + + xa_destroy(&npc_priv.xa_sb_used); + xa_destroy(&npc_priv.xa_sb_free); + xa_destroy(&npc_priv.xa_idx2pf_map); + xa_destroy(&npc_priv.xa_pf_map); + + for (i =3D 0; i < npc_priv.pf_cnt; i++) + xa_destroy(&npc_priv.xa_pf2idx_map[i]); + + kfree(npc_priv.xa_pf2idx_map); + /* No need to destroy mutex lock as it is + * part of subbank structure + */ + kfree(npc_priv.sb); + kfree(subbank_srch_order); +} + +int npc_cn20k_init(struct rvu *rvu) +{ + int err; + + err =3D npc_priv_init(rvu); + if (err) { + dev_err(rvu->dev, "%s: Error to init\n", + __func__); + return err; + } + + npc_priv.init_done =3D true; + + return 0; +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.h new file mode 100644 index 000000000000..26da0a2c717a --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2026 Marvell. + * + */ + +#ifndef NPC_CN20K_H +#define NPC_CN20K_H + +#define MAX_NUM_BANKS 2 +#define MAX_NUM_SUB_BANKS 32 +#define MAX_SUBBANK_DEPTH 256 + +/** + * enum npc_subbank_flag - NPC subbank status + * + * subbank flag indicates whether the subbank is free + * or used. + * + * @NPC_SUBBANK_FLAG_UNINIT: Subbank is not initialized. + * @NPC_SUBBANK_FLAG_FREE: Subbank is free. + * @NPC_SUBBANK_FLAG_USED: Subbank is used. + */ +enum npc_subbank_flag { + NPC_SUBBANK_FLAG_UNINIT, + NPC_SUBBANK_FLAG_FREE =3D BIT(0), + NPC_SUBBANK_FLAG_USED =3D BIT(1), +}; + +/** + * struct npc_subbank - Subbank fields. + * @b0b: Subbanks bottom index for bank0 + * @b1b: Subbanks bottom index for bank1 + * @b0t: Subbanks top index for bank0 + * @b1t: Subbanks top index for bank1 + * @flags: Subbank flags + * @lock: Mutex lock for flags and rsrc mofiication + * @b0map: Bitmap map for bank0 indexes + * @b1map: Bitmap map for bank1 indexes + * @idx: Subbank index + * @arr_idx: Index to the free array or used array + * @free_cnt: Number of free slots in the subbank. + * @key_type: X4 or X2 subbank. + * + * MCAM resource is divided horizontally into mutltiple subbanks and + * Resource allocation from each subbank is managed by this data + * structure. + */ +struct npc_subbank { + u16 b0t, b0b, b1t, b1b; + enum npc_subbank_flag flags; + struct mutex lock; /* Protect subbank resources */ + DECLARE_BITMAP(b0map, MAX_SUBBANK_DEPTH); + DECLARE_BITMAP(b1map, MAX_SUBBANK_DEPTH); + u16 idx; + u16 arr_idx; + u16 free_cnt; + u8 key_type; +}; + +/** + * struct npc_priv_t - NPC private structure. + * @bank_depth: Total entries in each bank. + * @num_banks: Number of banks. + * @num_subbanks: Number of subbanks. + * @subbank_depth: Depth of subbank. + * @kw: Kex configured key type. + * @sb: Subbank array. + * @xa_sb_used: Array of used subbanks. + * @xa_sb_free: Array of free subbanks. + * @xa_pf2idx_map: PF to mcam index map. + * @xa_idx2pf_map: Mcam index to PF map. + * @xa_pf_map: Pcifunc to index map. + * @pf_cnt: Number of PFs.A + * @init_done: Indicates MCAM initialization is done. + * + * This structure is populated during probing time by reading + * HW csr registers. + */ +struct npc_priv_t { + int bank_depth; + const int num_banks; + int num_subbanks; + int subbank_depth; + u8 kw; + struct npc_subbank *sb; + struct xarray xa_sb_used; + struct xarray xa_sb_free; + struct xarray *xa_pf2idx_map; + struct xarray xa_idx2pf_map; + struct xarray xa_pf_map; + int pf_cnt; + bool init_done; +}; + +struct rvu; + +struct npc_priv_t *npc_priv_get(void); +int npc_cn20k_init(struct rvu *rvu); +void npc_cn20k_deinit(struct rvu *rvu); + +void npc_cn20k_subbank_calc_free(struct rvu *rvu, int *x2_free, + int *x4_free, int *sb_free); + +int npc_cn20k_ref_idx_alloc(struct rvu *rvu, int pcifunc, int key_type, + int prio, u16 *mcam_idx, int ref, int limit, + bool contig, int count); +int npc_cn20k_idx_free(struct rvu *rvu, u16 *mcam_idx, int count); +#endif /* NPC_CN20K_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h b/driver= s/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) =20 +/* 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/n= et/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) =20 -#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) =20 diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index a3e273126e4e..1c4b36832788 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 */ =20 +enum { + NPC_MCAM_KEY_X1 =3D 0, + NPC_MCAM_KEY_DYN =3D 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_i= nfo, 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_fcnt, \ + msg_req, npc_cn20k_get_fcnt_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; }; =20 +/* Available entries to use */ +struct npc_cn20k_get_fcnt_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/driv= ers/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); =20 + if (is_cn20k(rvu->pdev)) + npc_cn20k_debugfs_init(rvu); + if (!rvu->hw->cap.npc_exact_match_enabled) return; =20 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" =20 #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); } =20 + if (is_cn20k(rvu->pdev)) + return npc_cn20k_init(rvu); + return 0; } =20 @@ -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); } =20 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; =20 - /* Check if unused counters are available or not */ if (!rvu_rsrc_free_count(&mcam->counters)) { return NPC_MCAM_ALLOC_FAILED; --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0a-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C1A532BEC20; Mon, 2 Feb 2026 07:46:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018406; cv=none; b=TFIjMFRUSj/XPW6f0Szt61pfNUrtYD0SktT8+1dkl0sXs1wtDWTg4155piA5S0wg4L0yqW3qNtfn1JRLaFMP3LHAxBR6bwG+j7jc+m+96d+dPLXo0hWzBSW2AZseNo8ypdtt12LEicvzQjhm8JoyHiXS9RVHyYlJO9TBg4tJuDE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018406; c=relaxed/simple; bh=qL1dqvxi7aq7mNFXqZYwpeFi7QhKyoXyYMNuxFY7eRM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=euBLgeHAERXpflyL98E+ylN0S/AiNTZaELolrX3X3y1UoG+wBP/oOs/DRutIz1HhGGH0wJmXsNrLPikn0Qfgo/FYGn+Rzw58oFH7huo14TL65DE6ldQHsiwsoM+XfpIwJ/B5v0vVh9W+W+RXhLvBWk2hr3zFGEGVvWtbWrBTfcU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=I2LH0whP; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="I2LH0whP" Received: from pps.filterd (m0431384.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6126vHZP905405; Sun, 1 Feb 2026 23:46:22 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=D kIVN0KNXPPSSbh4Kz39s7VAus0SjydqPVdYUK7ceyA=; b=I2LH0whP5zqQsir5I MLX0DNskjIs6Dw8NRwdala53q8Q+3/AQX1IWt+Grw9xtPJfnu5ztJ5LnXd6jAGaU tCJoswxtw3un11Vsgx1ZktrvBE8Mb/BdvDO7vl5FuKtrCbDz0tzAM0JCwQ+BJ6B8 Prkfg1vXuQjTM5Wz9kpHyeY37oKyLGDWoiFYtvy8cP8DFALnLqWF2c+fDQCERZJZ pVlTZ6ts28Eed0ESS0x9e3pluwT5gSvLfw08BZP5wVNbV6Wf+li7vmL3WWkK9HLM 0bri+WoHSmEhZAOXj+gsVv5hdn/WNhD0OWua5D+zxeam13KJkQDrn60p2F4MIJJY q5AxQ== Received: from dc6wp-exch02.marvell.com ([4.21.29.225]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4c2q3q02pe-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:22 -0800 (PST) Received: from DC6WP-EXCH02.marvell.com (10.76.176.209) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:46:47 -0800 Received: from maili.marvell.com (10.69.176.80) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:46:46 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 9C9605B6947; Sun, 1 Feb 2026 23:46:17 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , Suman Ghosh , Ratheesh Kannoth Subject: [PATCH net-next v8 02/13] octeontx2-af: npc: cn20k: KPM profile changes Date: Mon, 2 Feb 2026 13:15:56 +0530 Message-ID: <20260202074607.2535569-3-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authority-Analysis: v=2.4 cv=ZeoQ98VA c=1 sm=1 tr=0 ts=6980564e cx=c_pps a=gIfcoYsirJbf48DBMSPrZA==:117 a=gIfcoYsirJbf48DBMSPrZA==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=6-Y-9hFfzBH4qAAUAIcA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-GUID: JLNTz9I4cgDRxtYf5ngHuzMwxIDbNFgt X-Proofpoint-ORIG-GUID: JLNTz9I4cgDRxtYf5ngHuzMwxIDbNFgt X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfX2dypA+8aFYe9 bsan5U8t6uYyxchARAKPlEJR4uenUDNFLhNtBmCxn4ghpFsUEOCegJ7j2GHj1oOX8EiM8I0VchL aPh8D1bGaGb/LRy5iOrWqK+X7aSaeFeDbO2AtE4mI69eekX33eDHfMcugBE2Z6ZqDIT482cYLT0 ny+M353z+soAgmFuCzCiTNaInmzbyUk9autx/uVX+SoQ/swEg/R+Mi32HLFg4E3ZMwy5bzZ31tC G5xGOjp6JmVFjsEPRJWA6kFolXydRkSaiAQRxwDyWB4cRux+c+2uHyxBMzLLadpuFqvvtoNLEBE iiA28l82S0vkYb1GhwpvGox9UhluZ1yEw2UK1Ppn/oMMHWD8wWSrGAgkvKJVOC+lScX913lbOcS kGlsFobtjNnxBHGBZUGP9Kica8hznUdZuhtuShiQpAXrZQ4FP/Od0nCm4HNsSP1+YcqWEsKpjCw VBQI7o++4+uPQo9AdBw== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" From: Suman Ghosh KPU (Kangaroo Processing Unit) profiles are primarily used to set the required packet pointers that will be used in later stages for key generation. In the new CN20K silicon variant, a new KPM profile is introduced alongside the existing KPU profiles. In CN20K, a total of 16 KPUs are grouped into 8 KPM profiles. As per the current hardware design, each KPM configuration contains a combination of 2 KPUs: KPM0 =3D KPU0 + KPU8 KPM1 =3D KPU1 + KPU9 ... KPM7 =3D KPU7 + KPU15 This configuration enables more efficient use of KPU resources. This patch adds support for the new KPM profile configuration. Signed-off-by: Suman Ghosh Signed-off-by: Ratheesh Kannoth --- .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 221 ++++++++++++++++++ .../ethernet/marvell/octeontx2/af/cn20k/npc.h | 37 +++ .../ethernet/marvell/octeontx2/af/cn20k/reg.h | 17 +- .../net/ethernet/marvell/octeontx2/af/rvu.h | 4 +- .../ethernet/marvell/octeontx2/af/rvu_npc.c | 48 ++-- .../ethernet/marvell/octeontx2/af/rvu_npc.h | 17 ++ 6 files changed, 327 insertions(+), 17 deletions(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.c index 9b5da2665b54..6fa2be006fac 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c @@ -9,6 +9,7 @@ =20 #include "cn20k/npc.h" #include "cn20k/reg.h" +#include "rvu_npc.h" =20 static struct npc_priv_t npc_priv =3D { .num_banks =3D MAX_NUM_BANKS, @@ -20,6 +21,226 @@ static const char *npc_kw_name[NPC_MCAM_KEY_MAX] =3D { [NPC_MCAM_KEY_X4] =3D "X4", }; =20 +static void npc_config_kpmcam(struct rvu *rvu, int blkaddr, + const struct npc_kpu_profile_cam *kpucam, + int kpm, int entry) +{ + struct npc_kpu_cam cam0 =3D {0}; + struct npc_kpu_cam cam1 =3D {0}; + + cam1.state =3D kpucam->state & kpucam->state_mask; + cam1.dp0_data =3D kpucam->dp0 & kpucam->dp0_mask; + cam1.dp1_data =3D kpucam->dp1 & kpucam->dp1_mask; + cam1.dp2_data =3D kpucam->dp2 & kpucam->dp2_mask; + + cam0.state =3D ~kpucam->state & kpucam->state_mask; + cam0.dp0_data =3D ~kpucam->dp0 & kpucam->dp0_mask; + cam0.dp1_data =3D ~kpucam->dp1 & kpucam->dp1_mask; + cam0.dp2_data =3D ~kpucam->dp2 & kpucam->dp2_mask; + + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRYX_CAMX(kpm, entry, 0), *(u64 *)&cam0); + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRYX_CAMX(kpm, entry, 1), *(u64 *)&cam1); +} + +static void +npc_config_kpmaction(struct rvu *rvu, int blkaddr, + const struct npc_kpu_profile_action *kpuaction, + int kpm, int entry, bool pkind) +{ + struct npc_kpm_action0 action0 =3D {0}; + struct npc_kpu_action1 action1 =3D {0}; + u64 reg; + + action1.errlev =3D kpuaction->errlev; + action1.errcode =3D kpuaction->errcode; + action1.dp0_offset =3D kpuaction->dp0_offset; + action1.dp1_offset =3D kpuaction->dp1_offset; + action1.dp2_offset =3D kpuaction->dp2_offset; + + if (pkind) + reg =3D NPC_AF_PKINDX_ACTION1(entry); + else + reg =3D NPC_AF_KPMX_ENTRYX_ACTION1(kpm, entry); + + rvu_write64(rvu, blkaddr, reg, *(u64 *)&action1); + + action0.byp_count =3D kpuaction->bypass_count & 0x7; + action0.capture_ena =3D kpuaction->cap_ena & 1; + action0.parse_done =3D kpuaction->parse_done & 1; + action0.next_state =3D kpuaction->next_state & 0xf; + action0.capture_lid =3D kpuaction->lid & 0x7; + action0.capture_ltype =3D kpuaction->ltype & 0xf; + action0.capture_flags =3D kpuaction->flags & 0xf; + action0.ptr_advance =3D kpuaction->ptr_advance; + action0.var_len_offset =3D kpuaction->offset; + action0.var_len_mask =3D kpuaction->mask; + action0.var_len_right =3D kpuaction->right & 1; + action0.var_len_shift =3D kpuaction->shift & 1; + + if (pkind) + reg =3D NPC_AF_PKINDX_ACTION0(entry); + else + reg =3D NPC_AF_KPMX_ENTRYX_ACTION0(kpm, entry); + + rvu_write64(rvu, blkaddr, reg, *(u64 *)&action0); +} + +static void +npc_program_single_kpm_profile(struct rvu *rvu, int blkaddr, + int kpm, int start_entry, + const struct npc_kpu_profile *profile) +{ + int entry, num_entries, max_entries; + u64 idx; + + if (profile->cam_entries !=3D profile->action_entries) { + dev_err(rvu->dev, + "kpm%d: CAM and action entries [%d !=3D %d] not equal\n", + kpm, profile->cam_entries, profile->action_entries); + } + + max_entries =3D rvu->hw->npc_kpu_entries / 2; + entry =3D start_entry; + /* Program CAM match entries for previous kpm extracted data */ + num_entries =3D min_t(int, profile->cam_entries, max_entries); + for (idx =3D 0; entry < num_entries + start_entry; entry++, idx++) + npc_config_kpmcam(rvu, blkaddr, &profile->cam[idx], + kpm, entry); + + entry =3D start_entry; + /* Program this kpm's actions */ + num_entries =3D min_t(int, profile->action_entries, max_entries); + for (idx =3D 0; entry < num_entries + start_entry; entry++, idx++) + npc_config_kpmaction(rvu, blkaddr, &profile->action[idx], + kpm, entry, false); +} + +static void +npc_enable_kpm_entry(struct rvu *rvu, int blkaddr, int kpm, int num_entrie= s) +{ + u64 entry_mask; + + entry_mask =3D npc_enable_mask(num_entries); + /* Disable first KPU_MAX_CST_ENT entries for built-in profile */ + if (!rvu->kpu.custom) + entry_mask |=3D GENMASK_ULL(KPU_MAX_CST_ENT - 1, 0); + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(kpm, 0), entry_mask); + if (num_entries <=3D 64) { + /* Disable all the entries in W1, W2 and W3 */ + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(kpm, 1), + npc_enable_mask(0)); + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(kpm, 2), + npc_enable_mask(0)); + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(kpm, 3), + npc_enable_mask(0)); + return; + } + + num_entries =3D num_entries - 64; + entry_mask =3D npc_enable_mask(num_entries); + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(kpm, 1), entry_mask); + if (num_entries <=3D 64) { + /* Disable all the entries in W2 and W3 */ + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(kpm, 2), + npc_enable_mask(0)); + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(kpm, 3), + npc_enable_mask(0)); + return; + } + + num_entries =3D num_entries - 64; + entry_mask =3D npc_enable_mask(num_entries); + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(kpm, 2), entry_mask); + if (num_entries <=3D 64) { + /* Disable all the entries in W3 */ + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(kpm, 3), + npc_enable_mask(0)); + return; + } + + num_entries =3D num_entries - 64; + entry_mask =3D npc_enable_mask(num_entries); + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(kpm, 3), entry_mask); +} + +#define KPU_OFFSET 8 +static void npc_program_kpm_profile(struct rvu *rvu, int blkaddr, int num_= kpms) +{ + const struct npc_kpu_profile *profile1, *profile2; + int idx, total_cam_entries; + + for (idx =3D 0; idx < num_kpms; idx++) { + profile1 =3D &rvu->kpu.kpu[idx]; + npc_program_single_kpm_profile(rvu, blkaddr, idx, 0, profile1); + profile2 =3D &rvu->kpu.kpu[idx + KPU_OFFSET]; + npc_program_single_kpm_profile(rvu, blkaddr, idx, + profile1->cam_entries, + profile2); + total_cam_entries =3D profile1->cam_entries + + profile2->cam_entries; + npc_enable_kpm_entry(rvu, blkaddr, idx, total_cam_entries); + rvu_write64(rvu, blkaddr, NPC_AF_KPMX_PASS2_OFFSET(idx), + profile1->cam_entries); + /* Enable the KPUs associated with this KPM */ + rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx), 0x01); + rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx + KPU_OFFSET), + 0x01); + } +} + +void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr) +{ + struct rvu_hwinfo *hw =3D rvu->hw; + int num_pkinds, idx; + + /* Disable all KPMs and their entries */ + for (idx =3D 0; idx < hw->npc_kpms; idx++) { + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(idx, 0), ~0ULL); + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(idx, 1), ~0ULL); + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(idx, 2), ~0ULL); + rvu_write64(rvu, blkaddr, + NPC_AF_KPMX_ENTRY_DISX(idx, 3), ~0ULL); + } + + for (idx =3D 0; idx < hw->npc_kpus; idx++) + rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx), 0x00); + + /* Load and customize KPU profile. */ + npc_load_kpu_profile(rvu); + + /* Configure KPU and KPM mapping for second pass */ + rvu_write64(rvu, blkaddr, NPC_AF_KPM_PASS2_CFG, 0x76543210); + + /* First program IKPU profile i.e PKIND configs. + * Check HW max count to avoid configuring junk or + * writing to unsupported CSR addresses. + */ + num_pkinds =3D rvu->kpu.pkinds; + num_pkinds =3D min_t(int, hw->npc_pkinds, num_pkinds); + + for (idx =3D 0; idx < num_pkinds; idx++) + npc_config_kpmaction(rvu, blkaddr, &rvu->kpu.ikpu[idx], + 0, idx, true); + + /* Program KPM CAM and Action profiles */ + npc_program_kpm_profile(rvu, blkaddr, hw->npc_kpms); +} + struct npc_priv_t *npc_priv_get(void) { return &npc_priv; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.h index 26da0a2c717a..55882a0f37fc 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h @@ -94,6 +94,42 @@ struct npc_priv_t { bool init_done; }; =20 +struct npc_kpm_action0 { +#if defined(__BIG_ENDIAN_BITFIELD) + u64 rsvd_63_57 : 7; + u64 byp_count : 3; + u64 capture_ena : 1; + u64 parse_done : 1; + u64 next_state : 8; + u64 rsvd_43 : 1; + u64 capture_lid : 3; + u64 capture_ltype : 4; + u64 rsvd_32_35 : 4; + u64 capture_flags : 4; + u64 ptr_advance : 8; + u64 var_len_offset : 8; + u64 var_len_mask : 8; + u64 var_len_right : 1; + u64 var_len_shift : 3; +#else + u64 var_len_shift : 3; + u64 var_len_right : 1; + u64 var_len_mask : 8; + u64 var_len_offset : 8; + u64 ptr_advance : 8; + u64 capture_flags : 4; + u64 rsvd_32_35 : 4; + u64 capture_ltype : 4; + u64 capture_lid : 3; + u64 rsvd_43 : 1; + u64 next_state : 8; + u64 parse_done : 1; + u64 capture_ena : 1; + u64 byp_count : 3; + u64 rsvd_63_57 : 7; +#endif +}; + struct rvu; =20 struct npc_priv_t *npc_priv_get(void); @@ -107,4 +143,5 @@ int npc_cn20k_ref_idx_alloc(struct rvu *rvu, int pcifun= c, 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); +void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr); #endif /* NPC_CN20K_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/reg.h index 098b0247848b..073d4b815681 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h @@ -77,8 +77,21 @@ #define RVU_MBOX_VF_INT_ENA_W1S (0x30) #define RVU_MBOX_VF_INT_ENA_W1C (0x38) =20 +#define RVU_MBOX_VF_VFAF_TRIGX(a) (0x2000 | (a) << 3) /* NPC registers */ -#define NPC_AF_MCAM_SECTIONX_CFG_EXT(a) (0xf000000ull | (a) << 3) +#define NPC_AF_INTFX_EXTRACTORX_CFG(a, b) \ + (0x908000ull | (a) << 10 | (b) << 3) +#define NPC_AF_INTFX_EXTRACTORX_LTX_CFG(a, b, c) \ + (0x900000ull | (a) << 13 | (b) << 8 | (c) << 3) +#define NPC_AF_KPMX_ENTRYX_CAMX(a, b, c) \ + (0x100000ull | (a) << 14 | (b) << 6 | (c) << 3) +#define NPC_AF_KPMX_ENTRYX_ACTION0(a, b) \ + (0x100020ull | (a) << 14 | (b) << 6) +#define NPC_AF_KPMX_ENTRYX_ACTION1(a, b) \ + (0x100028ull | (a) << 14 | (b) << 6) +#define NPC_AF_KPMX_ENTRY_DISX(a, b) (0x180000ull | (a) << 6 | (b) << 3) +#define NPC_AF_KPM_PASS2_CFG 0x580 +#define NPC_AF_KPMX_PASS2_OFFSET(a) (0x190000ull | (a) << 3) +#define NPC_AF_MCAM_SECTIONX_CFG_EXT(a) (0xC000000ull | (a) << 3) =20 -#define RVU_MBOX_VF_VFAF_TRIGX(a) (0x2000 | (a) << 3) #endif /* RVU_MBOX_REG_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.h index e85dac2c806d..14ca28ab493a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -447,9 +447,11 @@ struct rvu_hwinfo { u8 sdp_links; u8 cpt_links; /* Number of CPT links */ u8 npc_kpus; /* No of parser units */ + u8 npc_kpms; /* Number of enhanced parser units */ + u8 npc_kex_extr; /* Number of LDATA extractors per KEX */ u8 npc_pkinds; /* No of port kinds */ u8 npc_intfs; /* No of interfaces */ - u8 npc_kpu_entries; /* No of KPU entries */ + u16 npc_kpu_entries; /* No of KPU entries */ u16 npc_counters; /* No of match stats counters */ u32 lbk_bufsize; /* FIFO size supported by LBK */ bool npc_ext_set; /* Extended register set */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.c index 6c5fe838717e..133ae6421de7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -17,6 +17,7 @@ #include "npc_profile.h" #include "rvu_npc_hash.h" #include "cn20k/npc.h" +#include "rvu_npc.h" =20 #define RSVD_MCAM_ENTRIES_PER_PF 3 /* Broadcast, Promisc and AllMulticast = */ #define RSVD_MCAM_ENTRIES_PER_NIXLF 1 /* Ucast for LFs */ @@ -1410,9 +1411,9 @@ static void npc_load_mkex_profile(struct rvu *rvu, in= t blkaddr, iounmap(mkex_prfl_addr); } =20 -static void npc_config_kpuaction(struct rvu *rvu, int blkaddr, - const struct npc_kpu_profile_action *kpuaction, - int kpu, int entry, bool pkind) +void npc_config_kpuaction(struct rvu *rvu, int blkaddr, + const struct npc_kpu_profile_action *kpuaction, + int kpu, int entry, bool pkind) { struct npc_kpu_action0 action0 =3D {0}; struct npc_kpu_action1 action1 =3D {0}; @@ -1475,7 +1476,7 @@ static void npc_config_kpucam(struct rvu *rvu, int bl= kaddr, NPC_AF_KPUX_ENTRYX_CAMX(kpu, entry, 1), *(u64 *)&cam1); } =20 -static inline u64 enable_mask(int count) +u64 npc_enable_mask(int count) { return (((count) < 64) ? ~(BIT_ULL(count) - 1) : (0x00ULL)); } @@ -1508,7 +1509,7 @@ static void npc_program_kpu_profile(struct rvu *rvu, = int blkaddr, int kpu, =20 /* Enable all programmed entries */ num_entries =3D min_t(int, profile->action_entries, profile->cam_entries); - entry_mask =3D enable_mask(num_entries); + entry_mask =3D npc_enable_mask(num_entries); /* Disable first KPU_MAX_CST_ENT entries for built-in profile */ if (!rvu->kpu.custom) entry_mask |=3D GENMASK_ULL(KPU_MAX_CST_ENT - 1, 0); @@ -1517,7 +1518,7 @@ static void npc_program_kpu_profile(struct rvu *rvu, = int blkaddr, int kpu, if (num_entries > 64) { rvu_write64(rvu, blkaddr, NPC_AF_KPUX_ENTRY_DISX(kpu, 1), - enable_mask(num_entries - 64)); + npc_enable_mask(num_entries - 64)); } =20 /* Enable this KPU */ @@ -1705,7 +1706,7 @@ static int npc_load_kpu_profile_fwdb(struct rvu *rvu,= const char *kpu_profile) return ret; } =20 -static void npc_load_kpu_profile(struct rvu *rvu) +void npc_load_kpu_profile(struct rvu *rvu) { struct npc_kpu_profile_adapter *profile =3D &rvu->kpu; const char *kpu_profile =3D rvu->kpu_pfl_name; @@ -1847,12 +1848,19 @@ int npc_mcam_rsrcs_init(struct rvu *rvu, int blkadd= r) mcam->keysize =3D cfg; =20 /* Number of banks combined per MCAM entry */ - if (cfg =3D=3D NPC_MCAM_KEY_X4) - mcam->banks_per_entry =3D 4; - else if (cfg =3D=3D NPC_MCAM_KEY_X2) - mcam->banks_per_entry =3D 2; - else - mcam->banks_per_entry =3D 1; + if (is_cn20k(rvu->pdev)) { + if (cfg =3D=3D NPC_MCAM_KEY_X2) + mcam->banks_per_entry =3D 1; + else + mcam->banks_per_entry =3D 2; + } else { + if (cfg =3D=3D NPC_MCAM_KEY_X4) + mcam->banks_per_entry =3D 4; + else if (cfg =3D=3D NPC_MCAM_KEY_X2) + mcam->banks_per_entry =3D 2; + else + mcam->banks_per_entry =3D 1; + } =20 /* Reserve one MCAM entry for each of the NIX LF to * guarantee space to install default matching DMAC rule. @@ -1982,6 +1990,15 @@ static void rvu_npc_hw_init(struct rvu *rvu, int blk= addr) hw->npc_pkinds =3D (npc_const1 >> 12) & 0xFFULL; hw->npc_kpu_entries =3D npc_const1 & 0xFFFULL; hw->npc_kpus =3D (npc_const >> 8) & 0x1FULL; + /* For Cn20k silicon, check if enhanced parser + * is present, then set the NUM_KPMS =3D NUM_KPUS / 2 and + * number of LDATA extractors per KEX. + */ + if (is_cn20k(rvu->pdev) && (npc_const1 & BIT_ULL(62))) { + hw->npc_kpms =3D hw->npc_kpus / 2; + hw->npc_kex_extr =3D (npc_const1 >> 36) & 0x3FULL; + } + hw->npc_intfs =3D npc_const & 0xFULL; hw->npc_counters =3D (npc_const >> 48) & 0xFFFFULL; =20 @@ -2116,7 +2133,10 @@ int rvu_npc_init(struct rvu *rvu) return -ENOMEM; =20 /* Configure KPU profile */ - npc_parser_profile_init(rvu, blkaddr); + if (is_cn20k(rvu->pdev)) + npc_cn20k_parser_profile_init(rvu, blkaddr); + else + npc_parser_profile_init(rvu, blkaddr); =20 /* Config Outer L2, IPv4's NPC layer info */ rvu_write64(rvu, blkaddr, NPC_AF_PCK_DEF_OL2, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.h new file mode 100644 index 000000000000..80c63618ec47 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2026 Marvell. + * + */ + +#ifndef RVU_NPC_H +#define RVU_NPC_H + +u64 npc_enable_mask(int count); +void npc_load_kpu_profile(struct rvu *rvu); +void npc_config_kpuaction(struct rvu *rvu, int blkaddr, + const struct npc_kpu_profile_action *kpuaction, + int kpu, int entry, bool pkind); + +#endif /* RVU_NPC_H */ --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0a-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 040392BD5AD; Mon, 2 Feb 2026 07:46:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018405; cv=none; b=n6KF/pxkm3AEU/kP8b0DtKA/Drg3fxipnlS9IOqsFqDpydie7ew/CR6py4x0hiCsBcvRYl+O3eNy/JGuG6YzogZ/Nl7v47HzzFS34PmlDt54c0PjY7BT70otI1hzrzTlzLPvZM2TSOhZa455xOf6E0tXEbaL3V8DaBX4DDG2/bU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018405; c=relaxed/simple; bh=PnFXjIZgTwAApsJ28sQRlq3EVdceqABBoC+10cqFAIM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=P7sbVAf4j3euwhIj0qLPNdADcJqcjeQzb3q3Hwu4haqsWAD2TWYoHzD3mG69D5+sg2x6lHcJIktE481n+9bkhjPcbYmsg/qVonoNQCcW/UiKqVsyEiotLOMrFdCkMNhtDtHO05ja3qXgxpMz6crer4H+VpcQvpYRwEP/4blu/LY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=ibP2peUS; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="ibP2peUS" Received: from pps.filterd (m0431384.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6126ux7H904934; Sun, 1 Feb 2026 23:46:25 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=l XifcIBcK++ClBIj96jyORYxy9xlhr59S2kcp8P/G+Q=; b=ibP2peUSDfajcJHBs k91oEN0jgI3hseOGcop1XK7Jw4PeuqddZGUHbkBvIz+tluZWZAxLCDFWLnupGrS9 dT7MhvDlHoIQQfZby4vorRbz9mR/BZ7cPB9WulLJuNj8371WoL4ozyxtVRfeuNQp G7FPIEt/BtK0e+oiIziwfuNDHNlavVdKaRDN4cEgUqh/mHenLA0TpDtHgLaBfYDg xwMDSB7i0DW/7wtzb0Mu0rMCtsvy8kUJOf8lorL3uteDhvAUixm6mvTBP0+qrn0b iRg1e3JlvILljRpZuxuB1cvI4lZUHNzsT+kWylyDWY3P8T5fQyvBaLclvLOYZBW3 E6AaA== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4c2q3q02pg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:25 -0800 (PST) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:46:41 -0800 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:46:41 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 661895B6948; Sun, 1 Feb 2026 23:46:21 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , Suman Ghosh , Ratheesh Kannoth Subject: [PATCH net-next v8 03/13] octeontx2-af: npc: cn20k: Add default profile Date: Mon, 2 Feb 2026 13:15:57 +0530 Message-ID: <20260202074607.2535569-4-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authority-Analysis: v=2.4 cv=ZeoQ98VA c=1 sm=1 tr=0 ts=69805651 cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=NGP3fZmBk5oLfH1lOsUA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-GUID: -viCVMfwd8Cv3z7MjXab-2XnafzPUnyT X-Proofpoint-ORIG-GUID: -viCVMfwd8Cv3z7MjXab-2XnafzPUnyT X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfX/BtGieoXBito G4T2Tw6C7TYhQdMKManF786DypQtBmyg9q/FVTef80QGLl8oqrlhYQL6f4S2qhf1Tu8eI2XUFiT z7AG/wHcMkG03REcSiQF5Y6p0Qf5ryJT6Wyn5cOxqxb/eUyURwaI4gb1ybSDgVEEThGWUa/Noxc n3aO87ycYeGSaKCykyjz4Xzok/JUGHh/nunxqa1Ur9T/LveZxAinhaqSXewQ3X3AR8M46s0LTJn rePQOB1MSjOwj3liOfWA7iv0mQb/XRaEYnw6b+8vSojQ0krDEOnWQTPd7hkxJIlVTli7nWYkGZP Dl1PCO7oA5CwCrG9n42fiK5LtmL7qRT2mDGQjNV15LizSwRkEjb2x2koRG3Gt0uolsZD1H/N6sl vIK/wdlWBF4epIDLR4BlNyzZfsb/vOsKnsd0yHMqMAtDPmzccVLuOR1FUQJQ64eLBM4dn2fBVPL 5aJGQ2VX4acAgPpFRXw== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" From: Suman Ghosh Default mkex profile for cn20k silicon. This commit changes attribute of objects to may_be_unused to avoid compiler warning Signed-off-by: Suman Ghosh Signed-off-by: Ratheesh Kannoth --- .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 176 +++++++++++++++++- .../ethernet/marvell/octeontx2/af/cn20k/npc.h | 18 ++ .../marvell/octeontx2/af/npc_profile.h | 72 +++---- 3 files changed, 229 insertions(+), 37 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.c index 6fa2be006fac..b12d35f7b167 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c @@ -7,9 +7,13 @@ #include #include =20 +#include "rvu.h" +#include "npc.h" +#include "npc_profile.h" +#include "rvu_npc_hash.h" +#include "rvu_npc.h" #include "cn20k/npc.h" #include "cn20k/reg.h" -#include "rvu_npc.h" =20 static struct npc_priv_t npc_priv =3D { .num_banks =3D MAX_NUM_BANKS, @@ -21,6 +25,176 @@ static const char *npc_kw_name[NPC_MCAM_KEY_MAX] =3D { [NPC_MCAM_KEY_X4] =3D "X4", }; =20 +#define KEX_EXTR_CFG(bytesm1, hdr_ofs, ena, key_ofs) \ + (((bytesm1) << 16) | ((hdr_ofs) << 8) | ((ena) << 7) | \ + ((key_ofs) & 0x3F)) + +static struct npc_mcam_kex_extr npc_mkex_extr_default =3D { + .mkex_sign =3D MKEX_SIGN, + .name =3D "default", + .kpu_version =3D NPC_KPU_PROFILE_VER, + .keyx_cfg =3D { + /* nibble: LA..LE (ltype only) + Error code + Channel */ + [NIX_INTF_RX] =3D ((u64)NPC_MCAM_KEY_DYN << 32) | + NPC_PARSE_NIBBLE_INTF_RX | + NPC_PARSE_NIBBLE_ERRCODE, + + /* nibble: LA..LE (ltype only) */ + [NIX_INTF_TX] =3D ((u64)NPC_MCAM_KEY_X2 << 32) | + NPC_PARSE_NIBBLE_INTF_TX, + }, + .intf_extr_lid =3D { + /* Default RX MCAM KEX profile */ + [NIX_INTF_RX] =3D { NPC_LID_LA, NPC_LID_LA, NPC_LID_LB, NPC_LID_LB, + NPC_LID_LC, NPC_LID_LC, NPC_LID_LD }, + [NIX_INTF_TX] =3D { NPC_LID_LA, NPC_LID_LA, NPC_LID_LB, NPC_LID_LB, + NPC_LID_LC, NPC_LID_LD }, + }, + .intf_extr_lt =3D { + /* Default RX MCAM KEX profile */ + [NIX_INTF_RX] =3D { + [0] =3D { + /* Layer A: Ethernet: */ + [NPC_LT_LA_ETHER] =3D + /* DMAC: 6 bytes, KW1[63:15] */ + KEX_EXTR_CFG(0x05, 0x0, 0x1, + NPC_KEXOF_DMAC + 1), + [NPC_LT_LA_CPT_HDR] =3D + /* DMAC: 6 bytes, KW1[63:15] */ + KEX_EXTR_CFG(0x05, 0x0, 0x1, + NPC_KEXOF_DMAC + 1), + }, + [1] =3D { + /* Layer A: Ethernet: */ + [NPC_LT_LA_ETHER] =3D + /* Ethertype: 2 bytes, KW0[63:48] */ + KEX_EXTR_CFG(0x01, 0xc, 0x1, 0x6), + [NPC_LT_LA_CPT_HDR] =3D + /* Ethertype: 2 bytes, KW0[63:48] */ + KEX_EXTR_CFG(0x01, 0xc, 0x1, 0x6), + }, + [2] =3D { + /* Layer B: Single VLAN (CTAG) */ + [NPC_LT_LB_CTAG] =3D + /* CTAG VLAN: 2 bytes, KW1[15:0] */ + KEX_EXTR_CFG(0x01, 0x2, 0x1, 0x8), + /* Layer B: Stacked VLAN (STAG|QinQ) */ + [NPC_LT_LB_STAG_QINQ] =3D + /* Outer VLAN: 2 bytes, KW1[15:0] */ + KEX_EXTR_CFG(0x01, 0x2, 0x1, 0x8), + [NPC_LT_LB_FDSA] =3D + /* SWITCH PORT: 1 byte, KW1[7:0] */ + KEX_EXTR_CFG(0x0, 0x1, 0x1, 0x8), + }, + [3] =3D { + [NPC_LT_LB_CTAG] =3D + /* Ethertype: 2 bytes, KW0[63:48] */ + KEX_EXTR_CFG(0x01, 0x4, 0x1, 0x6), + [NPC_LT_LB_STAG_QINQ] =3D + /* Ethertype: 2 bytes, KW0[63:48] */ + KEX_EXTR_CFG(0x01, 0x8, 0x1, 0x6), + [NPC_LT_LB_FDSA] =3D + /* Ethertype: 2 bytes, KW0[63:48] */ + KEX_EXTR_CFG(0x01, 0x4, 0x1, 0x6), + }, + [4] =3D { + /* Layer C: IPv4 */ + [NPC_LT_LC_IP] =3D + /* SIP+DIP: 8 bytes, KW3[7:0], KW2[63:8] */ + KEX_EXTR_CFG(0x07, 0xc, 0x1, 0x11), + /* Layer C: IPv6 */ + [NPC_LT_LC_IP6] =3D + /* Everything up to SADDR: 8 bytes, KW3[7:0], + * KW2[63:8] + */ + KEX_EXTR_CFG(0x07, 0x0, 0x1, 0x11), + }, + [5] =3D { + [NPC_LT_LC_IP] =3D + /* TOS: 1 byte, KW2[7:0] */ + KEX_EXTR_CFG(0x0, 0x1, 0x1, 0x10), + }, + [6] =3D { + /* Layer D:UDP */ + [NPC_LT_LD_UDP] =3D + /* SPORT+DPORT: 4 bytes, KW3[39:8] */ + KEX_EXTR_CFG(0x3, 0x0, 0x1, 0x19), + /* Layer D:TCP */ + [NPC_LT_LD_TCP] =3D + /* SPORT+DPORT: 4 bytes, KW3[39:8] */ + KEX_EXTR_CFG(0x3, 0x0, 0x1, 0x19), + }, + }, + /* Default TX MCAM KEX profile */ + [NIX_INTF_TX] =3D { + [0] =3D { + /* Layer A: NIX_INST_HDR_S + Ethernet */ + /* NIX appends 8 bytes of NIX_INST_HDR_S at the + * start of each TX packet supplied to NPC. + */ + [NPC_LT_LA_IH_NIX_ETHER] =3D + /* PF_FUNC: 2B , KW0 [47:32] */ + KEX_EXTR_CFG(0x01, 0x0, 0x1, 0x4), + /* Layer A: HiGig2: */ + [NPC_LT_LA_IH_NIX_HIGIG2_ETHER] =3D + /* PF_FUNC: 2B , KW0 [47:32] */ + KEX_EXTR_CFG(0x01, 0x0, 0x1, 0x4), + }, + [1] =3D { + [NPC_LT_LA_IH_NIX_ETHER] =3D + /* SQ_ID 3 bytes, KW1[63:16] */ + KEX_EXTR_CFG(0x02, 0x02, 0x1, 0xa), + [NPC_LT_LA_IH_NIX_HIGIG2_ETHER] =3D + /* VID: 2 bytes, KW1[31:16] */ + KEX_EXTR_CFG(0x01, 0x10, 0x1, 0xa), + }, + [2] =3D { + /* Layer B: Single VLAN (CTAG) */ + [NPC_LT_LB_CTAG] =3D + /* CTAG VLAN[2..3] KW0[63:48] */ + KEX_EXTR_CFG(0x01, 0x2, 0x1, 0x6), + /* Layer B: Stacked VLAN (STAG|QinQ) */ + [NPC_LT_LB_STAG_QINQ] =3D + /* Outer VLAN: 2 bytes, KW0[63:48] */ + KEX_EXTR_CFG(0x01, 0x2, 0x1, 0x6), + }, + [3] =3D { + [NPC_LT_LB_CTAG] =3D + /* CTAG VLAN[2..3] KW1[15:0] */ + KEX_EXTR_CFG(0x01, 0x4, 0x1, 0x8), + [NPC_LT_LB_STAG_QINQ] =3D + /* Outer VLAN: 2 Bytes, KW1[15:0] */ + KEX_EXTR_CFG(0x01, 0x8, 0x1, 0x8), + }, + [4] =3D { + /* Layer C: IPv4 */ + [NPC_LT_LC_IP] =3D + /* SIP+DIP: 8 bytes, KW2[63:0] */ + KEX_EXTR_CFG(0x07, 0xc, 0x1, 0x10), + /* Layer C: IPv6 */ + [NPC_LT_LC_IP6] =3D + /* Everything up to SADDR: 8 bytes, KW2[63:0] */ + KEX_EXTR_CFG(0x07, 0x0, 0x1, 0x10), + }, + [5] =3D { + /* Layer D:UDP */ + [NPC_LT_LD_UDP] =3D + /* SPORT+DPORT: 4 bytes, KW3[31:0] */ + KEX_EXTR_CFG(0x3, 0x0, 0x1, 0x18), + /* Layer D:TCP */ + [NPC_LT_LD_TCP] =3D + /* SPORT+DPORT: 4 bytes, KW3[31:0] */ + KEX_EXTR_CFG(0x3, 0x0, 0x1, 0x18), + }, + }, + }, +}; + +struct npc_mcam_kex_extr *npc_mkex_extr_default_get(void) +{ + return &npc_mkex_extr_default; +} + static void npc_config_kpmcam(struct rvu *rvu, int blkaddr, const struct npc_kpu_profile_cam *kpucam, int kpm, int entry) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.h index 55882a0f37fc..b03922710297 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h @@ -130,6 +130,23 @@ struct npc_kpm_action0 { #endif }; =20 +struct npc_mcam_kex_extr { + /* MKEX Profle Header */ + u64 mkex_sign; /* "mcam-kex-profile" (8 bytes/ASCII characters) */ + u8 name[MKEX_NAME_LEN]; /* MKEX Profile name */ + u64 cpu_model; /* Format as profiled by CPU hardware */ + u64 kpu_version; /* KPU firmware/profile version */ + u64 reserved; /* Reserved for extension */ + + /* MKEX Profle Data */ + u64 keyx_cfg[NPC_MAX_INTF]; /* NPC_AF_INTF(0..1)_KEX_CFG */ +#define NPC_MAX_EXTRACTOR 24 + /* MKEX Extractor data */ + u64 intf_extr_lid[NPC_MAX_INTF][NPC_MAX_EXTRACTOR]; + /* KEX configuration per extractor */ + u64 intf_extr_lt[NPC_MAX_INTF][NPC_MAX_EXTRACTOR][NPC_MAX_LT]; +} __packed; + struct rvu; =20 struct npc_priv_t *npc_priv_get(void); @@ -144,4 +161,5 @@ int npc_cn20k_ref_idx_alloc(struct rvu *rvu, int pcifun= c, int key_type, bool contig, int count); int npc_cn20k_idx_free(struct rvu *rvu, u16 *mcam_idx, int count); void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr); +struct npc_mcam_kex_extr *npc_mkex_extr_default_get(void); #endif /* NPC_CN20K_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h b/driv= ers/net/ethernet/marvell/octeontx2/af/npc_profile.h index 41de72c8607f..561b01fcdbde 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h @@ -489,7 +489,7 @@ enum NPC_ERRLEV_E { 0, 0, 0, 0, \ } =20 -static struct npc_kpu_profile_action ikpu_action_entries[] =3D { +static struct npc_kpu_profile_action ikpu_action_entries[] __maybe_unused = =3D { { NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, 0, 0, @@ -1068,7 +1068,7 @@ static struct npc_kpu_profile_action ikpu_action_entr= ies[] =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu1_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu1_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -1878,7 +1878,7 @@ static struct npc_kpu_profile_cam kpu1_cam_entries[] = =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu2_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu2_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -2823,7 +2823,7 @@ static struct npc_kpu_profile_cam kpu2_cam_entries[] = =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu3_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu3_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -3804,7 +3804,7 @@ static struct npc_kpu_profile_cam kpu3_cam_entries[] = =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu4_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu4_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -4119,7 +4119,7 @@ static struct npc_kpu_profile_cam kpu4_cam_entries[] = =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu5_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu5_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -5172,7 +5172,7 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu6_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu6_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -5901,7 +5901,7 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu7_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu7_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -6252,7 +6252,7 @@ static struct npc_kpu_profile_cam kpu7_cam_entries[] = =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu8_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu8_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -7089,7 +7089,7 @@ static struct npc_kpu_profile_cam kpu8_cam_entries[] = =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu9_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu9_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -7575,7 +7575,7 @@ static struct npc_kpu_profile_cam kpu9_cam_entries[] = =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu10_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu10_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -7746,7 +7746,7 @@ static struct npc_kpu_profile_cam kpu10_cam_entries[]= =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu11_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu11_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -8061,7 +8061,7 @@ static struct npc_kpu_profile_cam kpu11_cam_entries[]= =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu12_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu12_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -8322,7 +8322,7 @@ static struct npc_kpu_profile_cam kpu12_cam_entries[]= =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu13_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu13_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -8340,7 +8340,7 @@ static struct npc_kpu_profile_cam kpu13_cam_entries[]= =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu14_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu14_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -8358,7 +8358,7 @@ static struct npc_kpu_profile_cam kpu14_cam_entries[]= =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu15_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu15_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -8565,7 +8565,7 @@ static struct npc_kpu_profile_cam kpu15_cam_entries[]= =3D { }, }; =20 -static struct npc_kpu_profile_cam kpu16_cam_entries[] =3D { +static struct npc_kpu_profile_cam kpu16_cam_entries[] __maybe_unused =3D { NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, NPC_KPU_NOP_CAM, @@ -8628,7 +8628,7 @@ static struct npc_kpu_profile_cam kpu16_cam_entries[]= =3D { }, }; =20 -static struct npc_kpu_profile_action kpu1_action_entries[] =3D { +static struct npc_kpu_profile_action kpu1_action_entries[] __maybe_unused = =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -9368,7 +9368,7 @@ static struct npc_kpu_profile_action kpu1_action_entr= ies[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu2_action_entries[] =3D { +static struct npc_kpu_profile_action kpu2_action_entries[] __maybe_unused = =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -10209,7 +10209,7 @@ static struct npc_kpu_profile_action kpu2_action_en= tries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu3_action_entries[] =3D { +static struct npc_kpu_profile_action kpu3_action_entries[] __maybe_unused = =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -11082,7 +11082,7 @@ static struct npc_kpu_profile_action kpu3_action_en= tries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu4_action_entries[] =3D { +static struct npc_kpu_profile_action kpu4_action_entries[] __maybe_unused = =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -11363,7 +11363,7 @@ static struct npc_kpu_profile_action kpu4_action_en= tries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu5_action_entries[] =3D { +static struct npc_kpu_profile_action kpu5_action_entries[] __maybe_unused = =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -12300,7 +12300,7 @@ static struct npc_kpu_profile_action kpu5_action_en= tries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu6_action_entries[] =3D { +static struct npc_kpu_profile_action kpu6_action_entries[] __maybe_unused = =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -12949,7 +12949,7 @@ static struct npc_kpu_profile_action kpu6_action_en= tries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu7_action_entries[] =3D { +static struct npc_kpu_profile_action kpu7_action_entries[] __maybe_unused = =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -13262,7 +13262,7 @@ static struct npc_kpu_profile_action kpu7_action_en= tries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu8_action_entries[] =3D { +static struct npc_kpu_profile_action kpu8_action_entries[] __maybe_unused = =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -14007,7 +14007,7 @@ static struct npc_kpu_profile_action kpu8_action_en= tries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu9_action_entries[] =3D { +static struct npc_kpu_profile_action kpu9_action_entries[] __maybe_unused = =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -14440,7 +14440,7 @@ static struct npc_kpu_profile_action kpu9_action_en= tries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu10_action_entries[] =3D { +static struct npc_kpu_profile_action kpu10_action_entries[] __maybe_unused= =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -14593,7 +14593,7 @@ static struct npc_kpu_profile_action kpu10_action_e= ntries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu11_action_entries[] =3D { +static struct npc_kpu_profile_action kpu11_action_entries[] __maybe_unused= =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -14874,7 +14874,7 @@ static struct npc_kpu_profile_action kpu11_action_e= ntries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu12_action_entries[] =3D { +static struct npc_kpu_profile_action kpu12_action_entries[] __maybe_unused= =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -15107,7 +15107,7 @@ static struct npc_kpu_profile_action kpu12_action_e= ntries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu13_action_entries[] =3D { +static struct npc_kpu_profile_action kpu13_action_entries[] __maybe_unused= =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -15124,7 +15124,7 @@ static struct npc_kpu_profile_action kpu13_action_e= ntries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu14_action_entries[] =3D { +static struct npc_kpu_profile_action kpu14_action_entries[] __maybe_unused= =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -15141,7 +15141,7 @@ static struct npc_kpu_profile_action kpu14_action_e= ntries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu15_action_entries[] =3D { +static struct npc_kpu_profile_action kpu15_action_entries[] __maybe_unused= =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -15326,7 +15326,7 @@ static struct npc_kpu_profile_action kpu15_action_e= ntries[] =3D { }, }; =20 -static struct npc_kpu_profile_action kpu16_action_entries[] =3D { +static struct npc_kpu_profile_action kpu16_action_entries[] __maybe_unused= =3D { NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, NPC_KPU_NOP_ACTION, @@ -15383,7 +15383,7 @@ static struct npc_kpu_profile_action kpu16_action_e= ntries[] =3D { }, }; =20 -static struct npc_kpu_profile npc_kpu_profiles[] =3D { +static struct npc_kpu_profile npc_kpu_profiles[] __maybe_unused =3D { { ARRAY_SIZE(kpu1_cam_entries), ARRAY_SIZE(kpu1_action_entries), @@ -15482,7 +15482,7 @@ static struct npc_kpu_profile npc_kpu_profiles[] = =3D { }, }; =20 -static struct npc_lt_def_cfg npc_lt_defaults =3D { +static struct npc_lt_def_cfg npc_lt_defaults __maybe_unused =3D { .rx_ol2 =3D { .lid =3D NPC_LID_LA, .ltype_match =3D NPC_LT_LA_ETHER, @@ -15604,7 +15604,7 @@ static struct npc_lt_def_cfg npc_lt_defaults =3D { }, }; =20 -static struct npc_mcam_kex npc_mkex_default =3D { +static struct npc_mcam_kex npc_mkex_default __maybe_unused =3D { .mkex_sign =3D MKEX_SIGN, .name =3D "default", .kpu_version =3D NPC_KPU_PROFILE_VER, --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 83B4A2BEFFD; Mon, 2 Feb 2026 07:46:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018412; cv=none; b=i1bpdkMK7jvlvUcQgT8EmX/3rksjsRQOyoDauPx8BngSwwzhmhlnCG5jGto6GqteNG0YFAnCjkCqB01P+4XP2I9xlXkMMj6u3axNokU59h462r8FQY3Hw8GtbGb80TzCmFig49wq+U7rcqPGzhCwsN8a5vlCDPAd2Co8sNTyUhU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018412; c=relaxed/simple; bh=NEMlViiL6uUsMCRvO/lCgR0Nn54DkFyqFCDDayauLdY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=XkdW5EBvw/N28e0MPfxOjN3tVLcdt/TCIPyPW2ihxzVRttGl47Vp62qHhDDqU86yU/Lda5M9TSCJ/66EH6QbdbRCzARzbuV5n6PB9MBDGD2ivNjtmgoS3yGCW7wv27fQOZbBUF6LERQ+6DdV0OyG254BgLUD+HLNasW2zo7d5tU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=fKgMaHJ2; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="fKgMaHJ2" Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 611LrR8E2523987; Sun, 1 Feb 2026 23:46:29 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=m jXG8Qz6h6LhgVIT6WcFKNLzASq4/i38E/9zlzfN+kw=; b=fKgMaHJ2csvDjjM2L DhM9PNv0OMXPBuoj5AFrwoMUDNmhmtnvCgfETwbuIomS3ijoQrXPyLn+bvhCC318 FDyOgJdpMT3bg3pbzu2LK4o4fyr5GDumZlg62Yz/ITmtT0jeRRbcNj69oM0WFUb7 DyLdJJsiIkAVHPi5W8ALh5UDhke3gf7VKggsre2rTv4+AmImTl69iytyN+ssLzsd XYRUnPVwtWEapUlwBw0C6X1GVX6RI7kKLlBinuTI5QfgPfZPnCwYM7gTvAN0wPQQ +KVsSDQD9ZN8owAkaIZidkFi8fDqEYckJR0/EN0m/03FGDE93IaoDH9nKeX4Eps7 p11TA== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4c28pe187t-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:29 -0800 (PST) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:46:45 -0800 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:46:45 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 0E7115B6946; Sun, 1 Feb 2026 23:46:24 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , Suman Ghosh , Ratheesh Kannoth Subject: [PATCH net-next v8 04/13] octeontx2-af: npc: cn20k: MKEX profile support Date: Mon, 2 Feb 2026 13:15:58 +0530 Message-ID: <20260202074607.2535569-5-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: pb_4R-I942BTK-YG3cHypCccLRzaSGbj X-Authority-Analysis: v=2.4 cv=Y4/1cxeN c=1 sm=1 tr=0 ts=69805655 cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=4IwJlRh9AewB62vroAYA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfX3y4KK3pwB0Yb LxoiF6ZlkpdKy9sA5fypkmOptkro6rYUOUkjNtjIQhKA54D3qDDGP4WN55FQBc02ZT/CH9nEpZd v3D7VKPN9+f1yCjz/tpwbeHlBGerzzWnRJMyl6DaFAsUmdLZ1Dw5n3y8ZiYNPKypL7BO9dWOVwN D6taC+RfUtlWaJ43+Nc3WhOd5osPFDgg438n15W2JG8eXqS2u5kEaVhUZ3byFhHQk3XR0tICz1/ 0/FdTzCkEjTpS7ianVK6JTBbgrEt5EqmHS1o0hK5yNtKN/kZP3UniiGHxlZ6Ahr43OSNnq+jvUB 3KzqMsLwFsxyDKQKUNROTXp6EBAVaGbvdmC//EFE1N8nbanG+VyUbcD0xzDCkQ/rorx2NoztbyR WeZDbuRlgXKfZTXViX+NDOpYBfTpGiSoQyuofgMMELeipVklVeO8ouehE5in8RIW/m2iIubBMr6 vaAII0ORso3YDtR/Kpw== X-Proofpoint-GUID: pb_4R-I942BTK-YG3cHypCccLRzaSGbj X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" From: Suman Ghosh In new silicon variant cn20k, a new parser profile is introduced. Instead of having two layer-data information per key field type, a new key extractor concept is introduced. As part of this change now a maximum of 24 extractor can be configured per packet parsing profile. For example, LA type(ether) can have 24 unique parsing key, LC type(ip), LD type(tcp/udp) also can have unique 24 parsing key associated. Signed-off-by: Suman Ghosh Signed-off-by: Ratheesh Kannoth --- .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 351 +++++++++++++++++- .../ethernet/marvell/octeontx2/af/cn20k/npc.h | 103 +++++ .../ethernet/marvell/octeontx2/af/cn20k/reg.h | 60 ++- .../net/ethernet/marvell/octeontx2/af/mbox.h | 17 +- .../net/ethernet/marvell/octeontx2/af/npc.h | 1 + .../marvell/octeontx2/af/npc_profile.h | 12 + .../net/ethernet/marvell/octeontx2/af/rvu.h | 6 +- .../ethernet/marvell/octeontx2/af/rvu_npc.c | 73 +++- .../ethernet/marvell/octeontx2/af/rvu_npc.h | 2 + .../marvell/octeontx2/af/rvu_npc_fs.c | 229 ++++++++++-- .../marvell/octeontx2/af/rvu_npc_hash.c | 15 + 11 files changed, 799 insertions(+), 70 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.c index b12d35f7b167..6b66432551db 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c @@ -29,19 +29,21 @@ static const char *npc_kw_name[NPC_MCAM_KEY_MAX] =3D { (((bytesm1) << 16) | ((hdr_ofs) << 8) | ((ena) << 7) | \ ((key_ofs) & 0x3F)) =20 +static const char cn20k_def_pfl_name[] =3D "default"; + static struct npc_mcam_kex_extr npc_mkex_extr_default =3D { - .mkex_sign =3D MKEX_SIGN, + .mkex_sign =3D MKEX_CN20K_SIGN, .name =3D "default", .kpu_version =3D NPC_KPU_PROFILE_VER, .keyx_cfg =3D { /* nibble: LA..LE (ltype only) + Error code + Channel */ [NIX_INTF_RX] =3D ((u64)NPC_MCAM_KEY_DYN << 32) | NPC_PARSE_NIBBLE_INTF_RX | - NPC_PARSE_NIBBLE_ERRCODE, + NPC_CN20K_PARSE_NIBBLE_ERRCODE, =20 /* nibble: LA..LE (ltype only) */ [NIX_INTF_TX] =3D ((u64)NPC_MCAM_KEY_X2 << 32) | - NPC_PARSE_NIBBLE_INTF_TX, + NPC_CN20K_PARSE_NIBBLE_INTF_TX, }, .intf_extr_lid =3D { /* Default RX MCAM KEX profile */ @@ -297,9 +299,9 @@ npc_enable_kpm_entry(struct rvu *rvu, int blkaddr, int = kpm, int num_entries) u64 entry_mask; =20 entry_mask =3D npc_enable_mask(num_entries); - /* Disable first KPU_MAX_CST_ENT entries for built-in profile */ + /* Disable first KPU_CN20K_MAX_CST_ENT entries for built-in profile */ if (!rvu->kpu.custom) - entry_mask |=3D GENMASK_ULL(KPU_MAX_CST_ENT - 1, 0); + entry_mask |=3D GENMASK_ULL(KPU_CN20K_MAX_CST_ENT - 1, 0); rvu_write64(rvu, blkaddr, NPC_AF_KPMX_ENTRY_DISX(kpm, 0), entry_mask); if (num_entries <=3D 64) { @@ -420,6 +422,289 @@ struct npc_priv_t *npc_priv_get(void) return &npc_priv; } =20 +static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr, + struct npc_mcam_kex_extr *mkex_extr, + u8 intf) +{ + u8 num_extr =3D rvu->hw->npc_kex_extr; + int extr, lt; + u64 val; + + if (is_npc_intf_tx(intf)) + return; + + rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf), + mkex_extr->keyx_cfg[NIX_INTF_RX]); + + /* Program EXTRACTOR */ + for (extr =3D 0; extr < num_extr; extr++) + rvu_write64(rvu, blkaddr, + NPC_AF_INTFX_EXTRACTORX_CFG(intf, extr), + mkex_extr->intf_extr_lid[intf][extr]); + + /* Program EXTRACTOR_LTYPE */ + for (extr =3D 0; extr < num_extr; extr++) { + for (lt =3D 0; lt < NPC_MAX_LT; lt++) { + val =3D mkex_extr->intf_extr_lt[intf][extr][lt]; + CN20K_SET_EXTR_LT(intf, extr, lt, val); + } + } +} + +static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr, + struct npc_mcam_kex_extr *mkex_extr, + u8 intf) +{ + u8 num_extr =3D rvu->hw->npc_kex_extr; + int extr, lt; + u64 val; + + if (is_npc_intf_rx(intf)) + return; + + rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf), + mkex_extr->keyx_cfg[NIX_INTF_TX]); + + /* Program EXTRACTOR */ + for (extr =3D 0; extr < num_extr; extr++) + rvu_write64(rvu, blkaddr, + NPC_AF_INTFX_EXTRACTORX_CFG(intf, extr), + mkex_extr->intf_extr_lid[intf][extr]); + + /* Program EXTRACTOR_LTYPE */ + for (extr =3D 0; extr < num_extr; extr++) { + for (lt =3D 0; lt < NPC_MAX_LT; lt++) { + val =3D mkex_extr->intf_extr_lt[intf][extr][lt]; + CN20K_SET_EXTR_LT(intf, extr, lt, val); + } + } +} + +static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr, + struct npc_mcam_kex_extr *mkex_extr) +{ + struct rvu_hwinfo *hw =3D rvu->hw; + u8 intf; + + for (intf =3D 0; intf < hw->npc_intfs; intf++) { + npc_program_mkex_rx(rvu, blkaddr, mkex_extr, intf); + npc_program_mkex_tx(rvu, blkaddr, mkex_extr, intf); + } + + /* Programme mkex hash profile */ + npc_program_mkex_hash(rvu, blkaddr); +} + +void npc_cn20k_load_mkex_profile(struct rvu *rvu, int blkaddr, + const char *mkex_profile) +{ + struct npc_mcam_kex_extr *mcam_kex_extr; + struct device *dev =3D &rvu->pdev->dev; + void __iomem *mkex_prfl_addr =3D NULL; + u64 prfl_sz; + int ret; + + /* If user not selected mkex profile */ + if (rvu->kpu_fwdata_sz || + !strncmp(mkex_profile, cn20k_def_pfl_name, MKEX_NAME_LEN)) + goto program_mkex_extr; + + /* Setting up the mapping for mkex profile image */ + ret =3D npc_fwdb_prfl_img_map(rvu, &mkex_prfl_addr, &prfl_sz); + if (ret < 0) + goto program_mkex_extr; + + mcam_kex_extr =3D (struct npc_mcam_kex_extr __force *)mkex_prfl_addr; + + while (((s64)prfl_sz > 0) && + (mcam_kex_extr->mkex_sign !=3D MKEX_END_SIGN)) { + /* Compare with mkex mod_param name string */ + if (mcam_kex_extr->mkex_sign =3D=3D MKEX_CN20K_SIGN && + !strncmp(mcam_kex_extr->name, mkex_profile, + MKEX_NAME_LEN)) { + rvu->kpu.mcam_kex_prfl.mkex_extr =3D mcam_kex_extr; + goto program_mkex_extr; + } + + mcam_kex_extr++; + prfl_sz -=3D sizeof(struct npc_mcam_kex_extr); + } + dev_warn(dev, "Failed to load requested profile: %s\n", mkex_profile); + +program_mkex_extr: + dev_info(rvu->dev, "Using %s mkex profile\n", + rvu->kpu.mcam_kex_prfl.mkex_extr->name); + /* Program selected mkex profile */ + npc_program_mkex_profile(rvu, blkaddr, + rvu->kpu.mcam_kex_prfl.mkex_extr); + if (mkex_prfl_addr) + iounmap(mkex_prfl_addr); +} + +static u8 npc_map2cn20k_flag(u8 flag) +{ + switch (flag) { + case NPC_F_LC_U_IP_FRAG: + return NPC_CN20K_F_LC_L_IP_FRAG; + + case NPC_F_LC_U_IP6_FRAG: + return NPC_CN20K_F_LC_L_IP6_FRAG; + + case NPC_F_LC_L_6TO4: + return NPC_CN20K_F_LC_L_6TO4; + + case NPC_F_LC_L_MPLS_IN_IP: + return NPC_CN20K_F_LC_U_MPLS_IN_IP; + + case NPC_F_LC_L_IP6_TUN_IP6: + return NPC_CN20K_F_LC_U_IP6_TUN_IP6; + + case NPC_F_LC_L_IP6_MPLS_IN_IP: + return NPC_CN20K_F_LC_U_IP6_MPLS_IN_IP; + + default: + break; + } + + return -1; +} + +void +npc_cn20k_update_action_entries_n_flags(struct rvu *rvu, + struct npc_kpu_profile_adapter *pfl) +{ + struct npc_kpu_profile_action *action; + int entries, ltype; + u8 flags; + + for (int i =3D 0; i < pfl->kpus; i++) { + action =3D pfl->kpu[i].action; + entries =3D pfl->kpu[i].action_entries; + + for (int j =3D 0; j < entries; j++) { + if (action[j].lid !=3D NPC_LID_LC) + continue; + + ltype =3D action[j].ltype; + + if (ltype !=3D NPC_LT_LC_IP && + ltype !=3D NPC_LT_LC_IP6 && + ltype !=3D NPC_LT_LC_IP_OPT && + ltype !=3D NPC_LT_LC_IP6_EXT) + continue; + + flags =3D action[j].flags; + + switch (flags) { + case NPC_F_LC_U_IP_FRAG: + case NPC_F_LC_U_IP6_FRAG: + case NPC_F_LC_L_6TO4: + case NPC_F_LC_L_MPLS_IN_IP: + case NPC_F_LC_L_IP6_TUN_IP6: + case NPC_F_LC_L_IP6_MPLS_IN_IP: + action[j].flags =3D npc_map2cn20k_flag(flags); + break; + default: + break; + } + } + } +} + +int npc_cn20k_apply_custom_kpu(struct rvu *rvu, + struct npc_kpu_profile_adapter *profile) +{ + struct npc_cn20k_kpu_profile_fwdata *fw =3D rvu->kpu_fwdata; + struct npc_kpu_profile_action *action; + struct npc_kpu_profile_cam *cam; + struct npc_kpu_fwdata *fw_kpu; + size_t hdr_sz, offset =3D 0; + u16 kpu, entry; + int entries; + + hdr_sz =3D sizeof(struct npc_cn20k_kpu_profile_fwdata); + + if (rvu->kpu_fwdata_sz < hdr_sz) { + dev_warn(rvu->dev, "Invalid KPU profile size\n"); + return -EINVAL; + } + + if (le64_to_cpu(fw->signature) !=3D KPU_SIGN) { + dev_warn(rvu->dev, "Invalid KPU profile signature %llx\n", + fw->signature); + return -EINVAL; + } + + /* Verify if the using known profile structure */ + if (NPC_KPU_VER_MAJ(profile->version) > + NPC_KPU_VER_MAJ(NPC_KPU_PROFILE_VER)) { + dev_warn(rvu->dev, "Not supported Major version: %d > %d\n", + NPC_KPU_VER_MAJ(profile->version), + NPC_KPU_VER_MAJ(NPC_KPU_PROFILE_VER)); + return -EINVAL; + } + + /* Verify if profile is aligned with the required kernel changes */ + if (NPC_KPU_VER_MIN(profile->version) < + NPC_KPU_VER_MIN(NPC_KPU_PROFILE_VER)) { + dev_warn(rvu->dev, + "Invalid KPU profile version: %d.%d.%d expected version <=3D %d.%d.%d\= n", + NPC_KPU_VER_MAJ(profile->version), + NPC_KPU_VER_MIN(profile->version), + NPC_KPU_VER_PATCH(profile->version), + NPC_KPU_VER_MAJ(NPC_KPU_PROFILE_VER), + NPC_KPU_VER_MIN(NPC_KPU_PROFILE_VER), + NPC_KPU_VER_PATCH(NPC_KPU_PROFILE_VER)); + return -EINVAL; + } + + /* Verify if profile fits the HW */ + if (fw->kpus > profile->kpus) { + dev_warn(rvu->dev, "Not enough KPUs: %d > %ld\n", fw->kpus, + profile->kpus); + return -EINVAL; + } + + profile->mcam_kex_prfl.mkex_extr =3D &fw->mkex; + if (profile->mcam_kex_prfl.mkex_extr->mkex_sign !=3D MKEX_CN20K_SIGN) { + dev_warn(rvu->dev, "Invalid MKEX profile signature:%llx\n", + profile->mcam_kex_prfl.mkex_extr->mkex_sign); + return -EINVAL; + } + + profile->custom =3D 1; + profile->name =3D fw->name; + profile->version =3D le64_to_cpu(fw->version); + profile->lt_def =3D &fw->lt_def; + + for (kpu =3D 0; kpu < fw->kpus; kpu++) { + fw_kpu =3D (struct npc_kpu_fwdata *)(fw->data + offset); + if (fw_kpu->entries > KPU_CN20K_MAX_CST_ENT) + dev_warn(rvu->dev, + "Too many custom entries on KPU%d: %d > %d\n", + kpu, fw_kpu->entries, KPU_CN20K_MAX_CST_ENT); + entries =3D min(fw_kpu->entries, KPU_CN20K_MAX_CST_ENT); + cam =3D (struct npc_kpu_profile_cam *)fw_kpu->data; + offset +=3D sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam); + action =3D (struct npc_kpu_profile_action *)(fw->data + offset); + offset +=3D fw_kpu->entries * sizeof(*action); + if (rvu->kpu_fwdata_sz < hdr_sz + offset) { + dev_warn(rvu->dev, + "Profile size mismatch on KPU%i parsing.\n", + kpu + 1); + return -EINVAL; + } + + for (entry =3D 0; entry < entries; entry++) { + profile->kpu[kpu].cam[entry] =3D cam[entry]; + profile->kpu[kpu].action[entry] =3D action[entry]; + } + } + npc_cn20k_update_action_entries_n_flags(rvu, profile); + + return 0; +} + static int npc_subbank_idx_2_mcam_idx(struct rvu *rvu, struct npc_subbank = *sb, u16 sub_off, u16 *mcam_idx) { @@ -1922,6 +2207,38 @@ rvu_mbox_handler_npc_cn20k_get_fcnt(struct rvu *rvu, return 0; } =20 +int +rvu_mbox_handler_npc_cn20k_get_kex_cfg(struct rvu *rvu, + struct msg_req *req, + struct npc_cn20k_get_kex_cfg_rsp *rsp) +{ + int extr, lt; + + rsp->rx_keyx_cfg =3D CN20K_GET_KEX_CFG(NIX_INTF_RX); + rsp->tx_keyx_cfg =3D CN20K_GET_KEX_CFG(NIX_INTF_TX); + + /* Get EXTRACTOR LID */ + for (extr =3D 0; extr < NPC_MAX_EXTRACTOR; extr++) { + rsp->intf_extr_lid[NIX_INTF_RX][extr] =3D + CN20K_GET_EXTR_LID(NIX_INTF_RX, extr); + rsp->intf_extr_lid[NIX_INTF_TX][extr] =3D + CN20K_GET_EXTR_LID(NIX_INTF_TX, extr); + } + + /* Get EXTRACTOR LTYPE */ + for (extr =3D 0; extr < NPC_MAX_EXTRACTOR; extr++) { + for (lt =3D 0; lt < NPC_MAX_LT; lt++) { + rsp->intf_extr_lt[NIX_INTF_RX][extr][lt] =3D + CN20K_GET_EXTR_LT(NIX_INTF_RX, extr, lt); + rsp->intf_extr_lt[NIX_INTF_TX][extr][lt] =3D + CN20K_GET_EXTR_LT(NIX_INTF_TX, extr, lt); + } + } + + memcpy(rsp->mkex_pfl_name, rvu->mkex_pfl_name, MKEX_NAME_LEN); + return 0; +} + static int *subbank_srch_order; =20 static void npc_populate_restricted_idxs(int num_subbanks) @@ -2132,6 +2449,23 @@ void npc_cn20k_deinit(struct rvu *rvu) kfree(subbank_srch_order); } =20 +static int npc_setup_mcam_section(struct rvu *rvu, int key_type) +{ + int blkaddr, sec; + + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) { + dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__); + return -ENODEV; + } + + for (sec =3D 0; sec < npc_priv.num_subbanks; sec++) + rvu_write64(rvu, blkaddr, + NPC_AF_MCAM_SECTIONX_CFG_EXT(sec), key_type); + + return 0; +} + int npc_cn20k_init(struct rvu *rvu) { int err; @@ -2143,6 +2477,13 @@ int npc_cn20k_init(struct rvu *rvu) return err; } =20 + err =3D npc_setup_mcam_section(rvu, NPC_MCAM_KEY_X2); + if (err) { + dev_err(rvu->dev, "%s: mcam section configuration failure\n", + __func__); + return err; + } + npc_priv.init_done =3D true; =20 return 0; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.h index b03922710297..aadee502bac1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h @@ -8,10 +8,77 @@ #ifndef NPC_CN20K_H #define NPC_CN20K_H =20 +#define MKEX_CN20K_SIGN 0x19bbfdbd160 + #define MAX_NUM_BANKS 2 #define MAX_NUM_SUB_BANKS 32 #define MAX_SUBBANK_DEPTH 256 =20 +/* strtoull of "mkexprof" with base:36 */ +#define MKEX_END_SIGN 0xdeadbeef + +#define NPC_CN20K_BYTESM GENMASK_ULL(18, 16) +#define NPC_CN20K_PARSE_NIBBLE GENMASK_ULL(22, 0) +#define NPC_CN20K_TOTAL_NIBBLE 23 + +#define CN20K_SET_EXTR_LT(intf, extr, ltype, cfg) \ + rvu_write64(rvu, BLKADDR_NPC, \ + NPC_AF_INTFX_EXTRACTORX_LTX_CFG(intf, extr, ltype), cfg) + +#define CN20K_GET_KEX_CFG(intf) \ + rvu_read64(rvu, BLKADDR_NPC, NPC_AF_INTFX_KEX_CFG(intf)) + +#define CN20K_GET_EXTR_LID(intf, extr) \ + rvu_read64(rvu, BLKADDR_NPC, \ + NPC_AF_INTFX_EXTRACTORX_CFG(intf, extr)) + +#define CN20K_SET_EXTR_LT(intf, extr, ltype, cfg) \ + rvu_write64(rvu, BLKADDR_NPC, \ + NPC_AF_INTFX_EXTRACTORX_LTX_CFG(intf, extr, ltype), cfg) + +#define CN20K_GET_EXTR_LT(intf, extr, ltype) \ + rvu_read64(rvu, BLKADDR_NPC, \ + NPC_AF_INTFX_EXTRACTORX_LTX_CFG(intf, extr, ltype)) + +/* NPC_PARSE_KEX_S nibble definitions for each field */ +#define NPC_CN20K_PARSE_NIBBLE_CHAN GENMASK_ULL(2, 0) +#define NPC_CN20K_PARSE_NIBBLE_ERRLEV BIT_ULL(3) +#define NPC_CN20K_PARSE_NIBBLE_ERRCODE GENMASK_ULL(5, 4) +#define NPC_CN20K_PARSE_NIBBLE_L2L3_BCAST BIT_ULL(6) +#define NPC_CN20K_PARSE_NIBBLE_LA_FLAGS BIT_ULL(7) +#define NPC_CN20K_PARSE_NIBBLE_LA_LTYPE BIT_ULL(8) +#define NPC_CN20K_PARSE_NIBBLE_LB_FLAGS BIT_ULL(9) +#define NPC_CN20K_PARSE_NIBBLE_LB_LTYPE BIT_ULL(10) +#define NPC_CN20K_PARSE_NIBBLE_LC_FLAGS BIT_ULL(11) +#define NPC_CN20K_PARSE_NIBBLE_LC_LTYPE BIT_ULL(12) +#define NPC_CN20K_PARSE_NIBBLE_LD_FLAGS BIT_ULL(13) +#define NPC_CN20K_PARSE_NIBBLE_LD_LTYPE BIT_ULL(14) +#define NPC_CN20K_PARSE_NIBBLE_LE_FLAGS BIT_ULL(15) +#define NPC_CN20K_PARSE_NIBBLE_LE_LTYPE BIT_ULL(16) +#define NPC_CN20K_PARSE_NIBBLE_LF_FLAGS BIT_ULL(17) +#define NPC_CN20K_PARSE_NIBBLE_LF_LTYPE BIT_ULL(18) +#define NPC_CN20K_PARSE_NIBBLE_LG_FLAGS BIT_ULL(19) +#define NPC_CN20K_PARSE_NIBBLE_LG_LTYPE BIT_ULL(20) +#define NPC_CN20K_PARSE_NIBBLE_LH_FLAGS BIT_ULL(21) +#define NPC_CN20K_PARSE_NIBBLE_LH_LTYPE BIT_ULL(22) + +/* Rx parse key extract nibble enable */ +#define NPC_CN20K_PARSE_NIBBLE_INTF_RX (NPC_CN20K_PARSE_NIBBLE_CHAN | \ + NPC_CN20K_PARSE_NIBBLE_L2L3_BCAST | \ + NPC_CN20K_PARSE_NIBBLE_LA_LTYPE | \ + NPC_CN20K_PARSE_NIBBLE_LB_LTYPE | \ + NPC_CN20K_PARSE_NIBBLE_LC_FLAGS | \ + NPC_CN20K_PARSE_NIBBLE_LC_LTYPE | \ + NPC_CN20K_PARSE_NIBBLE_LD_LTYPE | \ + NPC_CN20K_PARSE_NIBBLE_LE_LTYPE) + +/* Tx parse key extract nibble enable */ +#define NPC_CN20K_PARSE_NIBBLE_INTF_TX (NPC_CN20K_PARSE_NIBBLE_LA_LTYPE | \ + NPC_CN20K_PARSE_NIBBLE_LB_LTYPE | \ + NPC_CN20K_PARSE_NIBBLE_LC_LTYPE | \ + NPC_CN20K_PARSE_NIBBLE_LD_LTYPE | \ + NPC_CN20K_PARSE_NIBBLE_LE_LTYPE) + /** * enum npc_subbank_flag - NPC subbank status * @@ -147,6 +214,34 @@ struct npc_mcam_kex_extr { u64 intf_extr_lt[NPC_MAX_INTF][NPC_MAX_EXTRACTOR][NPC_MAX_LT]; } __packed; =20 +struct npc_cn20k_kpu_profile_fwdata { +#define KPU_SIGN 0x00666f727075706b +#define KPU_NAME_LEN 32 + /* Maximum number of custom KPU entries supported by + * the built-in profile. + */ +#define KPU_CN20K_MAX_CST_ENT 6 + /* KPU Profle Header */ + __le64 signature; /* "kpuprof\0" (8 bytes/ASCII characters) */ + u8 name[KPU_NAME_LEN]; /* KPU Profile name */ + __le64 version; /* KPU profile version */ + u8 kpus; + u8 reserved[7]; + + /* Default MKEX profile to be used with this KPU profile. May be + * overridden with mkex_profile module parameter. + * Format is same as for the MKEX profile to streamline processing. + */ + struct npc_mcam_kex_extr mkex; + /* LTYPE values for specific HW offloaded protocols. */ + struct npc_lt_def_cfg lt_def; + /* Dynamically sized data: + * Custom KPU CAM and ACTION configuration entries. + * struct npc_kpu_fwdata kpu[kpus]; + */ + u8 data[]; +} __packed; + struct rvu; =20 struct npc_priv_t *npc_priv_get(void); @@ -162,4 +257,12 @@ int npc_cn20k_ref_idx_alloc(struct rvu *rvu, int pcifu= nc, int key_type, int npc_cn20k_idx_free(struct rvu *rvu, u16 *mcam_idx, int count); void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr); struct npc_mcam_kex_extr *npc_mkex_extr_default_get(void); +void npc_cn20k_load_mkex_profile(struct rvu *rvu, int blkaddr, + const char *mkex_profile); +int npc_cn20k_apply_custom_kpu(struct rvu *rvu, + struct npc_kpu_profile_adapter *profile); + +void +npc_cn20k_update_action_entries_n_flags(struct rvu *rvu, + struct npc_kpu_profile_adapter *pfl); #endif /* NPC_CN20K_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/reg.h index 073d4b815681..bf50d999528b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h @@ -80,18 +80,60 @@ #define RVU_MBOX_VF_VFAF_TRIGX(a) (0x2000 | (a) << 3) /* NPC registers */ #define NPC_AF_INTFX_EXTRACTORX_CFG(a, b) \ - (0x908000ull | (a) << 10 | (b) << 3) + (0x20c000ull | (a) << 16 | (b) << 8) #define NPC_AF_INTFX_EXTRACTORX_LTX_CFG(a, b, c) \ - (0x900000ull | (a) << 13 | (b) << 8 | (c) << 3) + (0x204000ull | (a) << 16 | (b) << 8 | (c) << 3) #define NPC_AF_KPMX_ENTRYX_CAMX(a, b, c) \ - (0x100000ull | (a) << 14 | (b) << 6 | (c) << 3) + (0x20000ull | (a) << 12 | (b) << 3 | (c) << 16) #define NPC_AF_KPMX_ENTRYX_ACTION0(a, b) \ - (0x100020ull | (a) << 14 | (b) << 6) + (0x40000ull | (a) << 12 | (b) << 3) #define NPC_AF_KPMX_ENTRYX_ACTION1(a, b) \ - (0x100028ull | (a) << 14 | (b) << 6) -#define NPC_AF_KPMX_ENTRY_DISX(a, b) (0x180000ull | (a) << 6 | (b) << 3) -#define NPC_AF_KPM_PASS2_CFG 0x580 -#define NPC_AF_KPMX_PASS2_OFFSET(a) (0x190000ull | (a) << 3) -#define NPC_AF_MCAM_SECTIONX_CFG_EXT(a) (0xC000000ull | (a) << 3) + (0x50000ull | (a) << 12 | (b) << 3) +#define NPC_AF_KPMX_ENTRY_DISX(a, b) (0x60000ull | (a) << 12 | (b) << 3) +#define NPC_AF_KPM_PASS2_CFG 0x10210 +#define NPC_AF_KPMX_PASS2_OFFSET(a) (0x60040ull | (a) << 12) +#define NPC_AF_MCAM_SECTIONX_CFG_EXT(a) (0xf000000ull | (a) << 3) + +#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(a, b, c) ({ \ + u64 offset; \ + offset =3D (0x8000000ull | (a) << 4 | (b) << 20 | (c) << 3); \ + offset; }) + +#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(a, b, c) ({ \ + u64 offset; \ + offset =3D (0x9000000ull | (a) << 4 | (b) << 20 | (c) << 3); \ + offset; }) + +#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(a, b, c) ({ \ + u64 offset; \ + offset =3D (0x9400000ull | (a) << 4 | (b) << 20 | (c) << 3); \ + offset; }) + +#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(a, b, c) ({ \ + u64 offset; \ + offset =3D (0x9800000ull | (a) << 4 | (b) << 20 | (c) << 3); \ + offset; }) + +#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(a, b, c) ({ \ + u64 offset; \ + offset =3D (0x9c00000ull | (a) << 4 | (b) << 20 | (c) << 3); \ + offset; }) + +#define NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(a, b) ({ \ + u64 offset; \ + offset =3D (0xa000000ull | (a) << 4 | (b) << 20); \ + offset; }) + +#define NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(a, b, c) ({ \ + u64 offset; \ + offset =3D (0xc000000ull | (a) << 4 | (b) << 20 | (c) << 22); \ + offset; }) + +#define NPC_AF_INTFX_MISS_ACTX(a, b) (0xf003000 | (a) << 6 | (b) << 4) + +#define NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(a, b) ({ \ + u64 offset; \ + offset =3D (0xb000000ull | (a) << 4 | (b) << 20); \ + offset; }) =20 #endif /* RVU_MBOX_REG_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index 1c4b36832788..a393bf884fd6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -285,6 +285,8 @@ M(NPC_GET_FIELD_STATUS, 0x6014, npc_get_field_status, = \ npc_get_field_status_rsp) \ M(NPC_CN20K_MCAM_GET_FREE_COUNT, 0x6015, npc_cn20k_get_fcnt, \ msg_req, npc_cn20k_get_fcnt_rsp) \ +M(NPC_CN20K_GET_KEX_CFG, 0x6016, npc_cn20k_get_kex_cfg, \ + msg_req, npc_cn20k_get_kex_cfg_rsp) \ /* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \ M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc, \ nix_lf_alloc_req, nix_lf_alloc_rsp) \ @@ -1559,7 +1561,7 @@ struct npc_mcam_free_entry_req { }; =20 struct mcam_entry { -#define NPC_MAX_KWS_IN_KEY 7 /* Number of keywords in max keywidth */ +#define NPC_MAX_KWS_IN_KEY 8 /* Number of keywords in max keywidth */ u64 kw[NPC_MAX_KWS_IN_KEY]; u64 kw_mask[NPC_MAX_KWS_IN_KEY]; u64 action; @@ -1663,6 +1665,19 @@ struct npc_get_kex_cfg_rsp { u8 mkex_pfl_name[MKEX_NAME_LEN]; }; =20 +struct npc_cn20k_get_kex_cfg_rsp { + struct mbox_msghdr hdr; + u64 rx_keyx_cfg; /* NPC_AF_INTF(0)_KEX_CFG */ + u64 tx_keyx_cfg; /* NPC_AF_INTF(1)_KEX_CFG */ +#define NPC_MAX_EXTRACTOR 24 + /* MKEX Extractor data */ + u64 intf_extr_lid[NPC_MAX_INTF][NPC_MAX_EXTRACTOR]; + /* KEX configuration per extractor */ + u64 intf_extr_lt[NPC_MAX_INTF][NPC_MAX_EXTRACTOR][NPC_MAX_LT]; +#define MKEX_NAME_LEN 128 + u8 mkex_pfl_name[MKEX_NAME_LEN]; +}; + struct ptp_get_cap_rsp { struct mbox_msghdr hdr; #define PTP_CAP_HW_ATOMIC_UPDATE BIT_ULL(0) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/= ethernet/marvell/octeontx2/af/npc.h index 6c3aca6f278d..cb05ec69e0b3 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h @@ -429,6 +429,7 @@ struct nix_rx_action { =20 /* NPC_AF_INTFX_KEX_CFG field masks */ #define NPC_PARSE_NIBBLE GENMASK_ULL(30, 0) +#define NPC_TOTAL_NIBBLE 31 =20 /* NPC_PARSE_KEX_S nibble definitions for each field */ #define NPC_PARSE_NIBBLE_CHAN GENMASK_ULL(2, 0) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h b/driv= ers/net/ethernet/marvell/octeontx2/af/npc_profile.h index 561b01fcdbde..db74f7fdf028 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h @@ -321,6 +321,18 @@ enum npc_kpu_lb_lflag { NPC_F_LB_L_FDSA, }; =20 +enum npc_cn20k_kpu_lc_uflag { + NPC_CN20K_F_LC_U_MPLS_IN_IP =3D 0x20, + NPC_CN20K_F_LC_U_IP6_TUN_IP6 =3D 0x40, + NPC_CN20K_F_LC_U_IP6_MPLS_IN_IP =3D 0x80, +}; + +enum npc_cn20k_kpu_lc_lflag { + NPC_CN20K_F_LC_L_IP_FRAG =3D 2, + NPC_CN20K_F_LC_L_IP6_FRAG, + NPC_CN20K_F_LC_L_6TO4, +}; + enum npc_kpu_lc_uflag { NPC_F_LC_U_UNK_PROTO =3D 0x10, NPC_F_LC_U_IP_FRAG =3D 0x20, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.h index 14ca28ab493a..dd930aa05582 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -554,7 +554,11 @@ struct npc_kpu_profile_adapter { const struct npc_lt_def_cfg *lt_def; const struct npc_kpu_profile_action *ikpu; /* array[pkinds] */ const struct npc_kpu_profile *kpu; /* array[kpus] */ - struct npc_mcam_kex *mkex; + union npc_mcam_key_prfl { + struct npc_mcam_kex *mkex; + /* used for cn9k and cn10k */ + struct npc_mcam_kex_extr *mkex_extr; /* used for cn20k */ + } mcam_kex_prfl; struct npc_mcam_kex_hash *mkex_hash; bool custom; size_t pkinds; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.c index 133ae6421de7..8361d0aa4b6f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -1337,8 +1337,8 @@ static void npc_program_mkex_profile(struct rvu *rvu,= int blkaddr, npc_program_mkex_hash(rvu, blkaddr); } =20 -static int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_= addr, - u64 *size) +int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr, + u64 *size) { u64 prfl_addr, prfl_sz; =20 @@ -1394,7 +1394,7 @@ static void npc_load_mkex_profile(struct rvu *rvu, in= t blkaddr, */ if (!is_rvu_96xx_B0(rvu) || mcam_kex->keyx_cfg[NIX_INTF_RX] =3D=3D mcam_kex->keyx_cfg[NIX_INTF_= TX]) - rvu->kpu.mkex =3D mcam_kex; + rvu->kpu.mcam_kex_prfl.mkex =3D mcam_kex; goto program_mkex; } =20 @@ -1404,9 +1404,10 @@ static void npc_load_mkex_profile(struct rvu *rvu, i= nt blkaddr, dev_warn(dev, "Failed to load requested profile: %s\n", mkex_profile); =20 program_mkex: - dev_info(rvu->dev, "Using %s mkex profile\n", rvu->kpu.mkex->name); + dev_info(rvu->dev, "Using %s mkex profile\n", + rvu->kpu.mcam_kex_prfl.mkex->name); /* Program selected mkex profile */ - npc_program_mkex_profile(rvu, blkaddr, rvu->kpu.mkex); + npc_program_mkex_profile(rvu, blkaddr, rvu->kpu.mcam_kex_prfl.mkex); if (mkex_prfl_addr) iounmap(mkex_prfl_addr); } @@ -1525,7 +1526,8 @@ static void npc_program_kpu_profile(struct rvu *rvu, = int blkaddr, int kpu, rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(kpu), 0x01); } =20 -static int npc_prepare_default_kpu(struct npc_kpu_profile_adapter *profile) +static void npc_prepare_default_kpu(struct rvu *rvu, + struct npc_kpu_profile_adapter *profile) { profile->custom =3D 0; profile->name =3D def_pfl_name; @@ -1535,23 +1537,38 @@ static int npc_prepare_default_kpu(struct npc_kpu_p= rofile_adapter *profile) profile->kpu =3D npc_kpu_profiles; profile->kpus =3D ARRAY_SIZE(npc_kpu_profiles); profile->lt_def =3D &npc_lt_defaults; - profile->mkex =3D &npc_mkex_default; profile->mkex_hash =3D &npc_mkex_hash_default; =20 - return 0; + if (!is_cn20k(rvu->pdev)) { + profile->mcam_kex_prfl.mkex =3D &npc_mkex_default; + return; + } + + profile->mcam_kex_prfl.mkex_extr =3D npc_mkex_extr_default_get(); + ikpu_action_entries[NPC_RX_CPT_HDR_PKIND].offset =3D 6; + ikpu_action_entries[NPC_RX_CPT_HDR_PKIND].mask =3D 0xe0; + ikpu_action_entries[NPC_RX_CPT_HDR_PKIND].shift =3D 0x5; + ikpu_action_entries[NPC_RX_CPT_HDR_PKIND].right =3D 0x1; + + npc_cn20k_update_action_entries_n_flags(rvu, profile); } =20 static int npc_apply_custom_kpu(struct rvu *rvu, struct npc_kpu_profile_adapter *profile) { size_t hdr_sz =3D sizeof(struct npc_kpu_profile_fwdata), offset =3D 0; - struct npc_kpu_profile_fwdata *fw =3D rvu->kpu_fwdata; struct npc_kpu_profile_action *action; + struct npc_kpu_profile_fwdata *fw; struct npc_kpu_profile_cam *cam; struct npc_kpu_fwdata *fw_kpu; int entries; u16 kpu, entry; =20 + if (is_cn20k(rvu->pdev)) + return npc_cn20k_apply_custom_kpu(rvu, profile); + + fw =3D rvu->kpu_fwdata; + if (rvu->kpu_fwdata_sz < hdr_sz) { dev_warn(rvu->dev, "Invalid KPU profile size\n"); return -EINVAL; @@ -1592,7 +1609,7 @@ static int npc_apply_custom_kpu(struct rvu *rvu, profile->custom =3D 1; profile->name =3D fw->name; profile->version =3D le64_to_cpu(fw->version); - profile->mkex =3D &fw->mkex; + profile->mcam_kex_prfl.mkex =3D &fw->mkex; profile->lt_def =3D &fw->lt_def; =20 for (kpu =3D 0; kpu < fw->kpus; kpu++) { @@ -1717,7 +1734,7 @@ void npc_load_kpu_profile(struct rvu *rvu) if (!strncmp(kpu_profile, def_pfl_name, KPU_NAME_LEN)) goto revert_to_default; /* First prepare default KPU, then we'll customize top entries. */ - npc_prepare_default_kpu(profile); + npc_prepare_default_kpu(rvu, profile); =20 /* Order of preceedence for load loading NPC profile (high to low) * Firmware binary in filesystem. @@ -1780,7 +1797,7 @@ void npc_load_kpu_profile(struct rvu *rvu) return; =20 revert_to_default: - npc_prepare_default_kpu(profile); + npc_prepare_default_kpu(rvu, profile); } =20 static void npc_parser_profile_init(struct rvu *rvu, int blkaddr) @@ -2029,12 +2046,21 @@ static void rvu_npc_hw_init(struct rvu *rvu, int bl= kaddr) =20 static void rvu_npc_setup_interfaces(struct rvu *rvu, int blkaddr) { - struct npc_mcam_kex *mkex =3D rvu->kpu.mkex; + struct npc_mcam_kex_extr *mkex_extr =3D rvu->kpu.mcam_kex_prfl.mkex_extr; + struct npc_mcam_kex *mkex =3D rvu->kpu.mcam_kex_prfl.mkex; struct npc_mcam *mcam =3D &rvu->hw->mcam; struct rvu_hwinfo *hw =3D rvu->hw; u64 nibble_ena, rx_kex, tx_kex; + u64 *keyx_cfg; u8 intf; =20 + if (is_cn20k(rvu->pdev)) { + keyx_cfg =3D mkex_extr->keyx_cfg; + goto skip_miss_cntr; + } + + keyx_cfg =3D mkex->keyx_cfg; + /* Reserve last counter for MCAM RX miss action which is set to * drop packet. This way we will know how many pkts didn't match * any MCAM entry. @@ -2042,15 +2068,17 @@ static void rvu_npc_setup_interfaces(struct rvu *rv= u, int blkaddr) mcam->counters.max--; mcam->rx_miss_act_cntr =3D mcam->counters.max; =20 - rx_kex =3D mkex->keyx_cfg[NIX_INTF_RX]; - tx_kex =3D mkex->keyx_cfg[NIX_INTF_TX]; +skip_miss_cntr: + rx_kex =3D keyx_cfg[NIX_INTF_RX]; + tx_kex =3D keyx_cfg[NIX_INTF_TX]; + nibble_ena =3D FIELD_GET(NPC_PARSE_NIBBLE, rx_kex); =20 nibble_ena =3D rvu_npc_get_tx_nibble_cfg(rvu, nibble_ena); if (nibble_ena) { tx_kex &=3D ~NPC_PARSE_NIBBLE; tx_kex |=3D FIELD_PREP(NPC_PARSE_NIBBLE, nibble_ena); - mkex->keyx_cfg[NIX_INTF_TX] =3D tx_kex; + keyx_cfg[NIX_INTF_TX] =3D tx_kex; } =20 /* Configure RX interfaces */ @@ -2062,6 +2090,9 @@ static void rvu_npc_setup_interfaces(struct rvu *rvu,= int blkaddr) rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf), rx_kex); =20 + if (is_cn20k(rvu->pdev)) + continue; + /* If MCAM lookup doesn't result in a match, drop the received * packet. And map this action to a counter to count dropped * packets. @@ -2167,7 +2198,10 @@ int rvu_npc_init(struct rvu *rvu) =20 npc_config_secret_key(rvu, blkaddr); /* Configure MKEX profile */ - npc_load_mkex_profile(rvu, blkaddr, rvu->mkex_pfl_name); + if (is_cn20k(rvu->pdev)) + npc_cn20k_load_mkex_profile(rvu, blkaddr, rvu->mkex_pfl_name); + else + npc_load_mkex_profile(rvu, blkaddr, rvu->mkex_pfl_name); =20 err =3D npc_mcam_rsrcs_init(rvu, blkaddr); if (err) @@ -2177,7 +2211,10 @@ int rvu_npc_init(struct rvu *rvu) if (err) { dev_err(rvu->dev, "Incorrect mkex profile loaded using default mkex\n"); - npc_load_mkex_profile(rvu, blkaddr, def_pfl_name); + if (is_cn20k(rvu->pdev)) + npc_cn20k_load_mkex_profile(rvu, blkaddr, def_pfl_name); + else + npc_load_mkex_profile(rvu, blkaddr, def_pfl_name); } =20 if (is_cn20k(rvu->pdev)) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.h index 80c63618ec47..346e6ada158e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h @@ -13,5 +13,7 @@ void npc_load_kpu_profile(struct rvu *rvu); void npc_config_kpuaction(struct rvu *rvu, int blkaddr, const struct npc_kpu_profile_action *kpuaction, int kpu, int entry, bool pkind); +int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr, + u64 *size); =20 #endif /* RVU_NPC_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drive= rs/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index b56395ac5a74..4817708d0af7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -12,6 +12,8 @@ #include "npc.h" #include "rvu_npc_fs.h" #include "rvu_npc_hash.h" +#include "cn20k/reg.h" +#include "cn20k/npc.h" =20 static const char * const npc_flow_names[] =3D { [NPC_DMAC] =3D "dmac", @@ -81,19 +83,26 @@ const char *npc_get_field_name(u8 hdr) /* Compute keyword masks and figure out the number of keywords a field * spans in the key. */ -static void npc_set_kw_masks(struct npc_mcam *mcam, u8 type, +static void npc_set_kw_masks(struct rvu *rvu, struct npc_mcam *mcam, u8 ty= pe, u8 nr_bits, int start_kwi, int offset, u8 intf) { struct npc_key_field *field =3D &mcam->rx_key_fields[type]; u8 bits_in_kw; int max_kwi; =20 - if (mcam->banks_per_entry =3D=3D 1) - max_kwi =3D 1; /* NPC_MCAM_KEY_X1 */ - else if (mcam->banks_per_entry =3D=3D 2) - max_kwi =3D 3; /* NPC_MCAM_KEY_X2 */ - else - max_kwi =3D 6; /* NPC_MCAM_KEY_X4 */ + if (is_cn20k(rvu->pdev)) { + if (mcam->banks_per_entry =3D=3D 1) + max_kwi =3D 3; /* NPC_MCAM_KEY_X2 */ + else + max_kwi =3D 7; /* NPC_MCAM_KEY_X4 */ + } else { + if (mcam->banks_per_entry =3D=3D 1) + max_kwi =3D 1; /* NPC_MCAM_KEY_X1 */ + else if (mcam->banks_per_entry =3D=3D 2) + max_kwi =3D 3; /* NPC_MCAM_KEY_X2 */ + else + max_kwi =3D 6; /* NPC_MCAM_KEY_X4 */ + } =20 if (is_npc_intf_tx(intf)) field =3D &mcam->tx_key_fields[type]; @@ -155,7 +164,8 @@ static bool npc_is_same(struct npc_key_field *input, sizeof(struct npc_layer_mdata)) =3D=3D 0; } =20 -static void npc_set_layer_mdata(struct npc_mcam *mcam, enum key_fields typ= e, +static void npc_set_layer_mdata(struct rvu *rvu, + struct npc_mcam *mcam, enum key_fields type, u64 cfg, u8 lid, u8 lt, u8 intf) { struct npc_key_field *input =3D &mcam->rx_key_fields[type]; @@ -165,13 +175,17 @@ static void npc_set_layer_mdata(struct npc_mcam *mcam= , enum key_fields type, =20 input->layer_mdata.hdr =3D FIELD_GET(NPC_HDR_OFFSET, cfg); input->layer_mdata.key =3D FIELD_GET(NPC_KEY_OFFSET, cfg); - input->layer_mdata.len =3D FIELD_GET(NPC_BYTESM, cfg) + 1; + if (is_cn20k(rvu->pdev)) + input->layer_mdata.len =3D FIELD_GET(NPC_CN20K_BYTESM, cfg) + 1; + else + input->layer_mdata.len =3D FIELD_GET(NPC_BYTESM, cfg) + 1; input->layer_mdata.ltype =3D lt; input->layer_mdata.lid =3D lid; } =20 static bool npc_check_overlap_fields(struct npc_key_field *input1, - struct npc_key_field *input2) + struct npc_key_field *input2, + int max_kw) { int kwi; =20 @@ -182,7 +196,7 @@ static bool npc_check_overlap_fields(struct npc_key_fie= ld *input1, input1->layer_mdata.ltype !=3D input2->layer_mdata.ltype) return false; =20 - for (kwi =3D 0; kwi < NPC_MAX_KWS_IN_KEY; kwi++) { + for (kwi =3D 0; kwi < max_kw; kwi++) { if (input1->kw_mask[kwi] & input2->kw_mask[kwi]) return true; } @@ -202,6 +216,7 @@ static bool npc_check_overlap(struct rvu *rvu, int blka= ddr, struct npc_key_field *dummy, *input; int start_kwi, offset; u8 nr_bits, lid, lt, ld; + int extr, kws; u64 cfg; =20 dummy =3D &mcam->rx_key_fields[NPC_UNKNOWN]; @@ -212,6 +227,10 @@ static bool npc_check_overlap(struct rvu *rvu, int blk= addr, input =3D &mcam->tx_key_fields[type]; } =20 + if (is_cn20k(rvu->pdev)) + goto skip_cn10k_config; + + kws =3D NPC_MAX_KWS_IN_KEY - 1; for (lid =3D start_lid; lid < NPC_MAX_LID; lid++) { for (lt =3D 0; lt < NPC_MAX_LT; lt++) { for (ld =3D 0; ld < NPC_MAX_LD; ld++) { @@ -221,8 +240,8 @@ static bool npc_check_overlap(struct rvu *rvu, int blka= ddr, if (!FIELD_GET(NPC_LDATA_EN, cfg)) continue; memset(dummy, 0, sizeof(struct npc_key_field)); - npc_set_layer_mdata(mcam, NPC_UNKNOWN, cfg, - lid, lt, intf); + npc_set_layer_mdata(rvu, mcam, NPC_UNKNOWN, + cfg, lid, lt, intf); /* exclude input */ if (npc_is_same(input, dummy)) continue; @@ -230,16 +249,50 @@ static bool npc_check_overlap(struct rvu *rvu, int bl= kaddr, offset =3D (dummy->layer_mdata.key * 8) % 64; nr_bits =3D dummy->layer_mdata.len * 8; /* form KW masks */ - npc_set_kw_masks(mcam, NPC_UNKNOWN, nr_bits, - start_kwi, offset, intf); + npc_set_kw_masks(rvu, mcam, NPC_UNKNOWN, + nr_bits, start_kwi, + offset, intf); /* check any input field bits falls in any * other field bits. */ - if (npc_check_overlap_fields(dummy, input)) + if (npc_check_overlap_fields(dummy, input, + kws)) return true; } } } + return false; + +skip_cn10k_config: + for (extr =3D 0 ; extr < rvu->hw->npc_kex_extr; extr++) { + lid =3D CN20K_GET_EXTR_LID(intf, extr); + if (lid < start_lid) + continue; + for (lt =3D 0; lt < NPC_MAX_LT; lt++) { + cfg =3D CN20K_GET_EXTR_LT(intf, extr, lt); + if (!FIELD_GET(NPC_LDATA_EN, cfg)) + continue; + + memset(dummy, 0, sizeof(struct npc_key_field)); + npc_set_layer_mdata(rvu, mcam, NPC_UNKNOWN, cfg, + lid, lt, intf); + /* exclude input */ + if (npc_is_same(input, dummy)) + continue; + start_kwi =3D dummy->layer_mdata.key / 8; + offset =3D (dummy->layer_mdata.key * 8) % 64; + nr_bits =3D dummy->layer_mdata.len * 8; + /* form KW masks */ + npc_set_kw_masks(rvu, mcam, NPC_UNKNOWN, nr_bits, + start_kwi, offset, intf); + /* check any input field bits falls in any other + * field bits + */ + if (npc_check_overlap_fields(dummy, input, + NPC_MAX_KWS_IN_KEY)) + return true; + } + } =20 return false; } @@ -253,7 +306,8 @@ static bool npc_check_field(struct rvu *rvu, int blkadd= r, enum key_fields type, return true; } =20 -static void npc_scan_exact_result(struct npc_mcam *mcam, u8 bit_number, +static void npc_scan_exact_result(struct rvu *rvu, + struct npc_mcam *mcam, u8 bit_number, u8 key_nibble, u8 intf) { u8 offset =3D (key_nibble * 4) % 64; /* offset within key word */ @@ -269,10 +323,63 @@ static void npc_scan_exact_result(struct npc_mcam *mc= am, u8 bit_number, default: return; } - npc_set_kw_masks(mcam, type, nr_bits, kwi, offset, intf); + npc_set_kw_masks(rvu, mcam, type, nr_bits, kwi, offset, intf); +} + +static void npc_cn20k_scan_parse_result(struct rvu *rvu, struct npc_mcam *= mcam, + u8 bit_number, u8 key_nibble, u8 intf) +{ + u8 offset =3D (key_nibble * 4) % 64; /* offset within key word */ + u8 kwi =3D (key_nibble * 4) / 64; /* which word in key */ + u8 nr_bits =3D 4; /* bits in a nibble */ + u8 type; + + switch (bit_number) { + case 0 ... 2: + type =3D NPC_CHAN; + break; + case 3: + type =3D NPC_ERRLEV; + break; + case 4 ... 5: + type =3D NPC_ERRCODE; + break; + case 6: + type =3D NPC_LXMB; + break; + case 8: + type =3D NPC_LA; + break; + case 10: + type =3D NPC_LB; + break; + case 12: + type =3D NPC_LC; + break; + case 14: + type =3D NPC_LD; + break; + case 16: + type =3D NPC_LE; + break; + case 18: + type =3D NPC_LF; + break; + case 20: + type =3D NPC_LG; + break; + case 22: + type =3D NPC_LH; + break; + default: + return; + } + + npc_set_kw_masks(rvu, mcam, type, nr_bits, kwi, offset, intf); } =20 -static void npc_scan_parse_result(struct npc_mcam *mcam, u8 bit_number, +static void npc_scan_parse_result(struct rvu *rvu, + struct npc_mcam *mcam, u8 bit_number, u8 key_nibble, u8 intf) { u8 offset =3D (key_nibble * 4) % 64; /* offset within key word */ @@ -280,6 +387,12 @@ static void npc_scan_parse_result(struct npc_mcam *mca= m, u8 bit_number, u8 nr_bits =3D 4; /* bits in a nibble */ u8 type; =20 + if (is_cn20k(rvu->pdev)) { + npc_cn20k_scan_parse_result(rvu, mcam, bit_number, + key_nibble, intf); + return; + } + switch (bit_number) { case 0 ... 2: type =3D NPC_CHAN; @@ -322,7 +435,7 @@ static void npc_scan_parse_result(struct npc_mcam *mcam= , u8 bit_number, return; } =20 - npc_set_kw_masks(mcam, type, nr_bits, kwi, offset, intf); + npc_set_kw_masks(rvu, mcam, type, nr_bits, kwi, offset, intf); } =20 static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8= intf) @@ -343,8 +456,13 @@ static void npc_handle_multi_layer_fields(struct rvu *= rvu, int blkaddr, u8 intf) /* Inner VLAN TCI for double tagged frames */ struct npc_key_field *vlan_tag3; u64 *features; + int i, max_kw; u8 start_lid; - int i; + + if (is_cn20k(rvu->pdev)) + max_kw =3D NPC_MAX_KWS_IN_KEY; + else + max_kw =3D NPC_MAX_KWS_IN_KEY - 1; =20 key_fields =3D mcam->rx_key_fields; features =3D &mcam->rx_features; @@ -382,7 +500,7 @@ static void npc_handle_multi_layer_fields(struct rvu *r= vu, int blkaddr, u8 intf) =20 /* if key profile programmed extracts Ethertype from multiple layers */ if (etype_ether->nr_kws && etype_tag1->nr_kws) { - for (i =3D 0; i < NPC_MAX_KWS_IN_KEY; i++) { + for (i =3D 0; i < max_kw; i++) { if (etype_ether->kw_mask[i] !=3D etype_tag1->kw_mask[i]) { dev_err(rvu->dev, "mkex: Etype pos is different for untagged and tagge= d pkts.\n"); goto vlan_tci; @@ -391,7 +509,7 @@ static void npc_handle_multi_layer_fields(struct rvu *r= vu, int blkaddr, u8 intf) key_fields[NPC_ETYPE] =3D *etype_tag1; } if (etype_ether->nr_kws && etype_tag2->nr_kws) { - for (i =3D 0; i < NPC_MAX_KWS_IN_KEY; i++) { + for (i =3D 0; i < max_kw; i++) { if (etype_ether->kw_mask[i] !=3D etype_tag2->kw_mask[i]) { dev_err(rvu->dev, "mkex: Etype pos is different for untagged and doubl= e tagged pkts.\n"); goto vlan_tci; @@ -400,7 +518,7 @@ static void npc_handle_multi_layer_fields(struct rvu *r= vu, int blkaddr, u8 intf) key_fields[NPC_ETYPE] =3D *etype_tag2; } if (etype_tag1->nr_kws && etype_tag2->nr_kws) { - for (i =3D 0; i < NPC_MAX_KWS_IN_KEY; i++) { + for (i =3D 0; i < max_kw; i++) { if (etype_tag1->kw_mask[i] !=3D etype_tag2->kw_mask[i]) { dev_err(rvu->dev, "mkex: Etype pos is different for tagged and double = tagged pkts.\n"); goto vlan_tci; @@ -431,7 +549,7 @@ static void npc_handle_multi_layer_fields(struct rvu *r= vu, int blkaddr, u8 intf) =20 /* if key profile extracts outer vlan tci from multiple layers */ if (vlan_tag1->nr_kws && vlan_tag2->nr_kws) { - for (i =3D 0; i < NPC_MAX_KWS_IN_KEY; i++) { + for (i =3D 0; i < max_kw; i++) { if (vlan_tag1->kw_mask[i] !=3D vlan_tag2->kw_mask[i]) { dev_err(rvu->dev, "mkex: Out vlan tci pos is different for tagged and = double tagged pkts.\n"); goto done; @@ -466,7 +584,11 @@ static void npc_scan_ldata(struct rvu *rvu, int blkadd= r, u8 lid, /* starting KW index and starting bit position */ int start_kwi, offset; =20 - nr_bytes =3D FIELD_GET(NPC_BYTESM, cfg) + 1; + if (is_cn20k(rvu->pdev)) + nr_bytes =3D FIELD_GET(NPC_CN20K_BYTESM, cfg) + 1; + else + nr_bytes =3D FIELD_GET(NPC_BYTESM, cfg) + 1; + hdr =3D FIELD_GET(NPC_HDR_OFFSET, cfg); key =3D FIELD_GET(NPC_KEY_OFFSET, cfg); =20 @@ -489,11 +611,12 @@ do { \ if ((hstart) >=3D hdr && \ ((hstart) + (hlen)) <=3D (hdr + nr_bytes)) { \ bit_offset =3D (hdr + nr_bytes - (hstart) - (hlen)) * 8; \ - npc_set_layer_mdata(mcam, (name), cfg, lid, lt, intf); \ + npc_set_layer_mdata(rvu, mcam, (name), cfg, lid, lt, \ + intf); \ offset +=3D bit_offset; \ start_kwi +=3D offset / 64; \ offset %=3D 64; \ - npc_set_kw_masks(mcam, (name), (hlen) * 8, \ + npc_set_kw_masks(rvu, mcam, (name), (hlen) * 8, \ start_kwi, offset, intf); \ } \ } \ @@ -636,6 +759,7 @@ static int npc_scan_kex(struct rvu *rvu, int blkaddr, u= 8 intf) u8 lid, lt, ld, bitnr; u64 cfg, masked_cfg; u8 key_nibble =3D 0; + int extr; =20 /* Scan and note how parse result is going to be in key. * A bit set in PARSE_NIBBLE_ENA corresponds to a nibble from @@ -643,10 +767,22 @@ static int npc_scan_kex(struct rvu *rvu, int blkaddr,= u8 intf) * will be concatenated in key. */ cfg =3D rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf)); - masked_cfg =3D cfg & NPC_PARSE_NIBBLE; - for_each_set_bit(bitnr, (unsigned long *)&masked_cfg, 31) { - npc_scan_parse_result(mcam, bitnr, key_nibble, intf); - key_nibble++; + if (is_cn20k(rvu->pdev)) { + masked_cfg =3D cfg & NPC_CN20K_PARSE_NIBBLE; + for_each_set_bit(bitnr, (unsigned long *)&masked_cfg, + NPC_CN20K_TOTAL_NIBBLE) { + npc_scan_parse_result(rvu, mcam, bitnr, + key_nibble, intf); + key_nibble++; + } + } else { + masked_cfg =3D cfg & NPC_PARSE_NIBBLE; + for_each_set_bit(bitnr, (unsigned long *)&masked_cfg, + NPC_TOTAL_NIBBLE) { + npc_scan_parse_result(rvu, mcam, bitnr, + key_nibble, intf); + key_nibble++; + } } =20 /* Ignore exact match bits for mcam entries except the first rule @@ -656,10 +792,13 @@ static int npc_scan_kex(struct rvu *rvu, int blkaddr,= u8 intf) masked_cfg =3D cfg & NPC_EXACT_NIBBLE; bitnr =3D NPC_EXACT_NIBBLE_START; for_each_set_bit_from(bitnr, (unsigned long *)&masked_cfg, NPC_EXACT_NIBB= LE_END + 1) { - npc_scan_exact_result(mcam, bitnr, key_nibble, intf); + npc_scan_exact_result(rvu, mcam, bitnr, key_nibble, intf); key_nibble++; } =20 + if (is_cn20k(rvu->pdev)) + goto skip_cn10k_config; + /* Scan and note how layer data is going to be in key */ for (lid =3D 0; lid < NPC_MAX_LID; lid++) { for (lt =3D 0; lt < NPC_MAX_LT; lt++) { @@ -676,6 +815,19 @@ static int npc_scan_kex(struct rvu *rvu, int blkaddr, = u8 intf) } =20 return 0; + +skip_cn10k_config: + for (extr =3D 0 ; extr < rvu->hw->npc_kex_extr; extr++) { + lid =3D CN20K_GET_EXTR_LID(intf, extr); + for (lt =3D 0; lt < NPC_MAX_LT; lt++) { + cfg =3D CN20K_GET_EXTR_LT(intf, extr, lt); + if (!FIELD_GET(NPC_LDATA_EN, cfg)) + continue; + npc_scan_ldata(rvu, blkaddr, lid, lt, cfg, + intf); + } + } + return 0; } =20 static int npc_scan_verify_kex(struct rvu *rvu, int blkaddr) @@ -758,8 +910,8 @@ void npc_update_entry(struct rvu *rvu, enum key_fields = type, struct mcam_entry dummy =3D { {0} }; struct npc_key_field *field; u64 kw1, kw2, kw3; + int i, max_kw; u8 shift; - int i; =20 field =3D &mcam->rx_key_fields[type]; if (is_npc_intf_tx(intf)) @@ -768,7 +920,12 @@ void npc_update_entry(struct rvu *rvu, enum key_fields= type, if (!field->nr_kws) return; =20 - for (i =3D 0; i < NPC_MAX_KWS_IN_KEY; i++) { + if (is_cn20k(rvu->pdev)) + max_kw =3D NPC_MAX_KWS_IN_KEY; + else + max_kw =3D NPC_MAX_KWS_IN_KEY - 1; + + for (i =3D 0; i < max_kw; i++) { if (!field->kw_mask[i]) continue; /* place key value in kw[x] */ @@ -820,7 +977,7 @@ void npc_update_entry(struct rvu *rvu, enum key_fields = type, /* dummy is ready with values and masks for given key * field now clear and update input entry with those */ - for (i =3D 0; i < NPC_MAX_KWS_IN_KEY; i++) { + for (i =3D 0; i < max_kw; i++) { if (!field->kw_mask[i]) continue; entry->kw[i] &=3D ~field->kw_mask[i]; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c b/dri= vers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c index 999f6d93c7fe..5ae046c93a82 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c @@ -125,6 +125,9 @@ static void npc_program_mkex_hash_rx(struct rvu *rvu, i= nt blkaddr, struct npc_mcam_kex_hash *mkex_hash =3D rvu->kpu.mkex_hash; int lid, lt, ld, hash_cnt =3D 0; =20 + if (is_cn20k(rvu->pdev)) + return; + if (is_npc_intf_tx(intf)) return; =20 @@ -165,6 +168,9 @@ static void npc_program_mkex_hash_tx(struct rvu *rvu, i= nt blkaddr, struct npc_mcam_kex_hash *mkex_hash =3D rvu->kpu.mkex_hash; int lid, lt, ld, hash_cnt =3D 0; =20 + if (is_cn20k(rvu->pdev)) + return; + if (is_npc_intf_rx(intf)) return; =20 @@ -224,6 +230,9 @@ void npc_program_mkex_hash(struct rvu *rvu, int blkaddr) struct rvu_hwinfo *hw =3D rvu->hw; u64 cfg; =20 + if (is_cn20k(rvu->pdev)) + return; + /* Check if hardware supports hash extraction */ if (!hwcap->npc_hash_extract) return; @@ -288,6 +297,9 @@ void npc_update_field_hash(struct rvu *rvu, u8 intf, u32 field_hash; u8 hash_idx; =20 + if (is_cn20k(rvu->pdev)) + return; + if (!rvu->hw->cap.npc_hash_extract) { dev_dbg(rvu->dev, "%s: Field hash extract feature is not supported\n", _= _func__); return; @@ -1874,6 +1886,9 @@ int rvu_npc_exact_init(struct rvu *rvu) u64 cfg; bool rc; =20 + if (is_cn20k(rvu->pdev)) + return 0; + /* Read NPC_AF_CONST3 and check for have exact * match functionality is present */ --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5363229E115; Mon, 2 Feb 2026 07:46:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.156.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018403; cv=none; b=fWgLCicwmqemsR0LntccaFylujFNjg1yRPmCfcFKxVnPY6CdZLwf+qvIXn4afJnxXa6xSnkW64hcK4uddvWpXTJNq5cnIgFfckFWveEdbetP+1BMqDH1t6PCSVj1gavIsULkj+mK7KqCaqmGckd1gqSCR/Kdn2tMUs5oUeqgdcs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018403; c=relaxed/simple; bh=ohTX+HuJtE1VQE60oCIqirWax6Z/HYKDf9WX8WZFoL4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Jfz0tINJmMAwGtyM+hxhqUKlvTUVSFzEggdzNFEEqdUSpjFRadbAKAsGC9W3QMrWzedKJR2S5ZopxPxxIJROzGeOvaJaSJAD3r/mY9a7dFHNsYLgEKpBchRVyZzJfFH+EdpWG/aLs5aF5j5Mmaq07lHN40TzSPOe80hKY24vZMY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=LQVRUVB8; arc=none smtp.client-ip=67.231.156.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="LQVRUVB8" Received: from pps.filterd (m0431383.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 611LrHZj3256101; Sun, 1 Feb 2026 23:46:32 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=u 6VsZfs2JpdIq7Lku9aHy5nNbgwqhfMPO60MUUDizGs=; b=LQVRUVB8UQNUZfZK5 fIQdixjn32IzMlUcvwxwl2MgbVxDi7gu1X4kMv02mtL0GNnCYOmn86oqf3WPlhPS 6u6Q+OdEqKlyK0juId7AJT3UY+Sc4DZPp8LJ8A+NA6q4MGR//Y/E34XTKQ1+hkKx ntCLcTNKS4dcP2IzAEKhVUTmuoQp+BDnBvu/PTk4Rsgn9zVu4YMdT8vcngCAU8yN CDD/XwOpjriVFqPkO9ffYh0MrBa2Kh40tmZOv6bynT4BdqZtuKZ85At0yRv3WgXj D91MZ9AHV8U1uF3WwaB3gL7rNaVNPjY2mH+GEqtm7vArO+23HUIdfsfV8X1QAVTn 0rhQw== Received: from dc6wp-exch02.marvell.com ([4.21.29.225]) by mx0b-0016f401.pphosted.com (PPS) with ESMTPS id 4c28mvs7jb-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:32 -0800 (PST) Received: from DC6WP-EXCH02.marvell.com (10.76.176.209) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:46:57 -0800 Received: from maili.marvell.com (10.69.176.80) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:46:57 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id E8C2F5B6946; Sun, 1 Feb 2026 23:46:28 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH net-next v8 05/13] octeontx2-af: npc: cn20k: Allocate default MCAM indexes Date: Mon, 2 Feb 2026 13:15:59 +0530 Message-ID: <20260202074607.2535569-6-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authority-Analysis: v=2.4 cv=MuhfKmae c=1 sm=1 tr=0 ts=69805658 cx=c_pps a=gIfcoYsirJbf48DBMSPrZA==:117 a=gIfcoYsirJbf48DBMSPrZA==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=s374GtA9f-YmEK9EDmoA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-ORIG-GUID: _cmqcE9mYO4nMRXxz1jKTC3XKgEc8Ob2 X-Proofpoint-GUID: _cmqcE9mYO4nMRXxz1jKTC3XKgEc8Ob2 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NSBTYWx0ZWRfX8NS1vnggUyex QLqH2+8OeWaEBfVNBi+jP0VWjGOmT3G1L0Cj5e8bD5dVWHo0d4Eq3pPtgWs7AAZA4ONdNpiInfM stPuCqwyv7BG/NOMv0IeuaLbr0845LvIsjqgRAdXMxg3EJ7Kfvv5TzppVMorIaREFhp475fOlUP f+dPDKrdiQu+maSWLBxxUWkbYlI5IZtO/nBfm4GIJ6S5VaSMGT4SlQ4F5XeURFtmx1VOLYabo8A jtMMaPt59FQcEoyHCFieSA7nOSd9y/xHFL4DtLJY3CmaWV+Cy67XjyK8kVsXizEyXLRXXfpXS/b ty7oLyrJnwBbrC9Vj9twW8r21bqD6Zd3pckRFnExxWHuONYbd880WQ6VyziConv59ml4LCIe6Kl nmIomFs1/UgqSf7MNAxqV2naHXsEKmdk2lsEQeJ+PCEfgKmfNFk24brk4wjBxWRuExV1GRQ28bm XrnnBy2A18HS0aO/dAQ== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" Reserving MCAM entries in the AF driver for installing default MCAM entries is not an efficient allocation method, as it results in significant wastage of entries. This patch allocates MCAM indexes for promiscuous, multicast, broadcast, and unicast traffic in descending order of indexes (from lower to higher priority) when the NIX LF is attached to the PF/VF. Signed-off-by: Ratheesh Kannoth --- .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 361 ++++++++++++++++++ .../ethernet/marvell/octeontx2/af/cn20k/npc.h | 29 ++ .../net/ethernet/marvell/octeontx2/af/mbox.h | 8 +- .../net/ethernet/marvell/octeontx2/af/rvu.c | 32 +- .../net/ethernet/marvell/octeontx2/af/rvu.h | 1 + .../ethernet/marvell/octeontx2/af/rvu_npc.c | 36 +- .../marvell/octeontx2/nic/otx2_flows.c | 2 +- 7 files changed, 447 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.c index 6b66432551db..e8b162cd7bbd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c @@ -25,10 +25,28 @@ static const char *npc_kw_name[NPC_MCAM_KEY_MAX] =3D { [NPC_MCAM_KEY_X4] =3D "X4", }; =20 +static const char *npc_dft_rule_name[NPC_DFT_RULE_MAX_ID] =3D { + [NPC_DFT_RULE_PROMISC_ID] =3D "Promisc", + [NPC_DFT_RULE_MCAST_ID] =3D "Mcast", + [NPC_DFT_RULE_BCAST_ID] =3D "Bcast", + [NPC_DFT_RULE_UCAST_ID] =3D "Ucast", +}; + #define KEX_EXTR_CFG(bytesm1, hdr_ofs, ena, key_ofs) \ (((bytesm1) << 16) | ((hdr_ofs) << 8) | ((ena) << 7) | \ ((key_ofs) & 0x3F)) =20 +#define NPC_DFT_RULE_ID_MK(pcifunc, id) \ + ((pcifunc) | FIELD_PREP(GENMASK_ULL(31, 16), id)) + +#define NPC_DFT_RULE_ID_2_PCIFUNC(rid) \ + FIELD_GET(GENMASK_ULL(15, 0), rid) + +#define NPC_DFT_RULE_ID_2_ID(rid) \ + FIELD_GET(GENMASK_ULL(31, 16), rid) + +#define NPC_DFT_RULE_PRIO 127 + static const char cn20k_def_pfl_name[] =3D "default"; =20 static struct npc_mcam_kex_extr npc_mkex_extr_default =3D { @@ -2332,6 +2350,346 @@ static int npc_pcifunc_map_create(struct rvu *rvu) return cnt; } =20 +int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast, + u16 *mcast, u16 *promisc, u16 *ucast) +{ + u16 *ptr[4] =3D {promisc, mcast, bcast, ucast}; + unsigned long idx; + bool set =3D false; + void *val; + int i, j; + + if (!npc_priv.init_done) + return 0; + + if (is_lbk_vf(rvu, pcifunc)) { + if (!ptr[0]) + return -ENOMEM; + + idx =3D NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_PROMISC_ID); + val =3D xa_load(&npc_priv.xa_pf2dfl_rmap, idx); + if (!val) { + pr_debug("%s: Failed to find %s index for pcifunc=3D%#x\n", + __func__, + npc_dft_rule_name[NPC_DFT_RULE_PROMISC_ID], + pcifunc); + + *ptr[0] =3D USHRT_MAX; + return -ESRCH; + } + + *ptr[0] =3D xa_to_value(val); + return 0; + } + + if (is_vf(pcifunc)) { + if (!ptr[3]) + return -ENOMEM; + + idx =3D NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_UCAST_ID); + val =3D xa_load(&npc_priv.xa_pf2dfl_rmap, idx); + if (!val) { + pr_debug("%s: Failed to find %s index for pcifunc=3D%#x\n", + __func__, + npc_dft_rule_name[NPC_DFT_RULE_UCAST_ID], + pcifunc); + + *ptr[3] =3D USHRT_MAX; + return -ESRCH; + } + + *ptr[3] =3D xa_to_value(val); + return 0; + } + + for (i =3D NPC_DFT_RULE_START_ID, j =3D 0; i < NPC_DFT_RULE_MAX_ID; i++, + j++) { + if (!ptr[j]) + continue; + + idx =3D NPC_DFT_RULE_ID_MK(pcifunc, i); + val =3D xa_load(&npc_priv.xa_pf2dfl_rmap, idx); + if (!val) { + pr_debug("%s: Failed to find %s index for pcifunc=3D%#x\n", + __func__, + npc_dft_rule_name[i], pcifunc); + + *ptr[j] =3D USHRT_MAX; + continue; + } + + *ptr[j] =3D xa_to_value(val); + set =3D true; + } + + return set ? 0 : -ESRCH; +} + +static bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc) +{ + return is_pf_cgxmapped(rvu, rvu_get_pf(rvu->pdev, pcifunc)) || + is_lbk_vf(rvu, pcifunc); +} + +void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc) +{ + struct npc_mcam_free_entry_req free_req =3D { 0 }; + unsigned long index; + struct msg_rsp rsp; + u16 ptr[4]; + int rc, i; + void *map; + + if (!npc_priv.init_done) + return; + + if (!npc_is_cgx_or_lbk(rvu, pcifunc)) { + dev_dbg(rvu->dev, + "%s: dft rule allocation is only for cgx mapped device, pcifunc=3D%#x\n= ", + __func__, pcifunc); + return; + } + + rc =3D npc_cn20k_dft_rules_idx_get(rvu, pcifunc, &ptr[0], &ptr[1], + &ptr[2], &ptr[3]); + if (rc) + return; + + /* LBK */ + if (is_lbk_vf(rvu, pcifunc)) { + index =3D NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_PROMISC_ID); + map =3D xa_erase(&npc_priv.xa_pf2dfl_rmap, index); + if (!map) + dev_dbg(rvu->dev, + "%s: Err from delete %s mcam idx from xarray (pcifunc=3D%#x\n", + __func__, + npc_dft_rule_name[NPC_DFT_RULE_PROMISC_ID], + pcifunc); + + goto free_rules; + } + + /* VF */ + if (is_vf(pcifunc)) { + index =3D NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_UCAST_ID); + map =3D xa_erase(&npc_priv.xa_pf2dfl_rmap, index); + if (!map) + dev_dbg(rvu->dev, + "%s: Err from delete %s mcam idx from xarray (pcifunc=3D%#x\n", + __func__, + npc_dft_rule_name[NPC_DFT_RULE_UCAST_ID], + pcifunc); + + goto free_rules; + } + + /* PF */ + for (i =3D NPC_DFT_RULE_START_ID; i < NPC_DFT_RULE_MAX_ID; i++) { + index =3D NPC_DFT_RULE_ID_MK(pcifunc, i); + map =3D xa_erase(&npc_priv.xa_pf2dfl_rmap, index); + if (!map) + dev_dbg(rvu->dev, + "%s: Err from delete %s mcam idx from xarray (pcifunc=3D%#x\n", + __func__, npc_dft_rule_name[i], + pcifunc); + } + +free_rules: + + free_req.hdr.pcifunc =3D pcifunc; + free_req.all =3D 1; + rc =3D rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp); + if (rc) + dev_err(rvu->dev, + "%s: Error deleting default entries (pcifunc=3D%#x\n", + __func__, pcifunc); +} + +int npc_cn20k_dft_rules_alloc(struct rvu *rvu, u16 pcifunc) +{ + struct npc_mcam_free_entry_req free_req =3D { 0 }; + u16 mcam_idx[4] =3D { 0 }, pf_ucast, pf_pcifunc; + struct npc_mcam_alloc_entry_req req =3D { 0 }; + struct npc_mcam_alloc_entry_rsp rsp =3D { 0 }; + int ret, eidx, i, k, pf, cnt; + struct rvu_pfvf *pfvf; + unsigned long index; + struct msg_rsp free_rsp; + u16 b, m, p, u; + + if (!npc_priv.init_done) + return 0; + + if (!npc_is_cgx_or_lbk(rvu, pcifunc)) { + dev_dbg(rvu->dev, + "%s: dft rule allocation is only for cgx mapped device, pcifunc=3D%#x\n= ", + __func__, pcifunc); + return 0; + } + + /* Check if default rules are already alloced for this pcifunc */ + ret =3D npc_cn20k_dft_rules_idx_get(rvu, pcifunc, &b, &m, &p, &u); + if (!ret) { + dev_err(rvu->dev, + "%s: default rules are already installed (pcifunc=3D%#x)\n", + __func__, pcifunc); + dev_err(rvu->dev, + "%s: bcast(%u) mcast(%u) promisc(%u) ucast(%u)\n", + __func__, b, m, p, u); + return 0; + } + + /* Set ref index as lowest priority index */ + eidx =3D 2 * npc_priv.bank_depth - 1; + + /* Install only UCAST for VF */ + cnt =3D is_vf(pcifunc) ? 1 : ARRAY_SIZE(mcam_idx); + + /* For VF pcifunc, allocate default mcam indexes by taking + * ref as PF's ucast index. + */ + if (is_vf(pcifunc)) { + pf =3D rvu_get_pf(rvu->pdev, pcifunc); + pf_pcifunc =3D pf << RVU_CN20K_PFVF_PF_SHIFT; + + /* Get PF's ucast entry index */ + ret =3D npc_cn20k_dft_rules_idx_get(rvu, pf_pcifunc, NULL, + NULL, NULL, &pf_ucast); + + /* There is no PF rules installed; and VF installation comes + * first. PF may come later. + * TODO: Install PF rules before installing VF rules. + */ + + /* Set PF's ucast as ref entry */ + if (!ret) + eidx =3D pf_ucast; + } + + pfvf =3D rvu_get_pfvf(rvu, pcifunc); + pfvf->hw_prio =3D NPC_DFT_RULE_PRIO; + + req.contig =3D false; + req.ref_prio =3D NPC_MCAM_HIGHER_PRIO; + req.ref_entry =3D eidx; + req.kw_type =3D NPC_MCAM_KEY_X2; + req.count =3D cnt; + req.hdr.pcifunc =3D pcifunc; + + ret =3D rvu_mbox_handler_npc_mcam_alloc_entry(rvu, &req, &rsp); + + /* successfully allocated index */ + if (!ret) { + /* Copy indexes to local array */ + for (i =3D 0; i < cnt; i++) + mcam_idx[i] =3D rsp.entry_list[i]; + + goto chk_sanity; + } + + /* If there is no slots available and request is for PF, + * return error. + */ + if (!is_vf(pcifunc)) { + dev_err(rvu->dev, + "%s: Default index allocation failed for pcifunc=3D%#x\n", + __func__, pcifunc); + return ret; + } + + /* We could not find an index with higher priority index for VF. + * Find rule with lower priority index and set hardware priority + * as NPC_DFT_RULE_PRIO - 1 (higher hw priority) + */ + req.contig =3D false; + req.kw_type =3D NPC_MCAM_KEY_X2; + req.count =3D cnt; + req.hdr.pcifunc =3D pcifunc; + req.ref_prio =3D NPC_MCAM_LOWER_PRIO; + req.ref_entry =3D eidx + 1; + ret =3D rvu_mbox_handler_npc_mcam_alloc_entry(rvu, &req, &rsp); + if (ret) { + dev_err(rvu->dev, + "%s: Default index allocation failed for pcifunc=3D%#x\n", + __func__, pcifunc); + return ret; + } + + /* Copy indexes to local array */ + for (i =3D 0; i < cnt; i++) + mcam_idx[i] =3D rsp.entry_list[i]; + + pfvf->hw_prio =3D NPC_DFT_RULE_PRIO - 1; + +chk_sanity: + /* LBK */ + if (is_lbk_vf(rvu, pcifunc)) { + index =3D NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_PROMISC_ID); + ret =3D xa_insert(&npc_priv.xa_pf2dfl_rmap, index, + xa_mk_value(mcam_idx[0]), GFP_KERNEL); + if (ret) { + dev_err(rvu->dev, + "%s: Err to insert %s mcam idx to xarray pcifunc=3D%#x\n", + __func__, + npc_dft_rule_name[NPC_DFT_RULE_PROMISC_ID], + pcifunc); + goto err; + } + + goto done; + } + + /* VF */ + if (is_vf(pcifunc)) { + index =3D NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_UCAST_ID); + ret =3D xa_insert(&npc_priv.xa_pf2dfl_rmap, index, + xa_mk_value(mcam_idx[0]), GFP_KERNEL); + if (ret) { + dev_err(rvu->dev, + "%s: Err to insert %s mcam idx to xarray pcifunc=3D%#x\n", + __func__, + npc_dft_rule_name[NPC_DFT_RULE_UCAST_ID], + pcifunc); + goto err; + } + + goto done; + } + + /* PF */ + for (i =3D NPC_DFT_RULE_START_ID, k =3D 0; i < NPC_DFT_RULE_MAX_ID && + k < cnt; i++, k++) { + index =3D NPC_DFT_RULE_ID_MK(pcifunc, i); + ret =3D xa_insert(&npc_priv.xa_pf2dfl_rmap, index, + xa_mk_value(mcam_idx[k]), GFP_KERNEL); + if (ret) { + dev_err(rvu->dev, + "%s: Err to insert %s mcam idx to xarray pcifunc=3D%#x\n", + __func__, npc_dft_rule_name[i], + pcifunc); + for (int p =3D NPC_DFT_RULE_START_ID; p < i; p++) { + index =3D NPC_DFT_RULE_ID_MK(pcifunc, p); + xa_erase(&npc_priv.xa_pf2dfl_rmap, index); + } + goto err; + } + } + +done: + return 0; + +err: + free_req.hdr.pcifunc =3D pcifunc; + free_req.all =3D 1; + ret =3D rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &free_rsp); + if (ret) + dev_err(rvu->dev, + "%s: Error deleting default entries (pcifunc=3D%#x\n", + __func__, pcifunc); + + return -EFAULT; +} + static int npc_priv_init(struct rvu *rvu) { struct npc_mcam *mcam =3D &rvu->hw->mcam; @@ -2394,6 +2752,7 @@ static int npc_priv_init(struct rvu *rvu) 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); + xa_init_flags(&npc_priv.xa_pf2dfl_rmap, XA_FLAGS_ALLOC); =20 if (npc_create_srch_order(num_subbanks)) goto fail1; @@ -2425,6 +2784,7 @@ static int npc_priv_init(struct rvu *rvu) xa_destroy(&npc_priv.xa_sb_free); xa_destroy(&npc_priv.xa_idx2pf_map); xa_destroy(&npc_priv.xa_pf_map); + xa_destroy(&npc_priv.xa_pf2dfl_rmap); kfree(npc_priv.sb); return -ENOMEM; } @@ -2437,6 +2797,7 @@ void npc_cn20k_deinit(struct rvu *rvu) xa_destroy(&npc_priv.xa_sb_free); xa_destroy(&npc_priv.xa_idx2pf_map); xa_destroy(&npc_priv.xa_pf_map); + xa_destroy(&npc_priv.xa_pf2dfl_rmap); =20 for (i =3D 0; i < npc_priv.pf_cnt; i++) xa_destroy(&npc_priv.xa_pf2idx_map[i]); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.h index aadee502bac1..8ef9a7510864 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h @@ -95,6 +95,27 @@ enum npc_subbank_flag { NPC_SUBBANK_FLAG_USED =3D BIT(1), }; =20 +/** + * enum npc_dft_rule_id - Default rule type + * + * Mcam default rule type. + * + * @NPC_DFT_RULE_START_ID: Not used + * @NPC_DFT_RULE_PROMISC_ID: promiscuous rule + * @NPC_DFT_RULE_MCAST_ID: multicast rule + * @NPC_DFT_RULE_BCAST_ID: broadcast rule + * @NPC_DFT_RULE_UCAST_ID: unicast rule + * @NPC_DFT_RULE_MAX_ID: Maximum index. + */ +enum npc_dft_rule_id { + NPC_DFT_RULE_START_ID =3D 1, + NPC_DFT_RULE_PROMISC_ID =3D NPC_DFT_RULE_START_ID, + NPC_DFT_RULE_MCAST_ID, + NPC_DFT_RULE_BCAST_ID, + NPC_DFT_RULE_UCAST_ID, + NPC_DFT_RULE_MAX_ID, +}; + /** * struct npc_subbank - Subbank fields. * @b0b: Subbanks bottom index for bank0 @@ -141,6 +162,7 @@ struct npc_subbank { * @xa_pf_map: Pcifunc to index map. * @pf_cnt: Number of PFs.A * @init_done: Indicates MCAM initialization is done. + * @xa_pf2dfl_rmap: PF to default rule index map. * * This structure is populated during probing time by reading * HW csr registers. @@ -157,6 +179,7 @@ struct npc_priv_t { struct xarray *xa_pf2idx_map; struct xarray xa_idx2pf_map; struct xarray xa_pf_map; + struct xarray xa_pf2dfl_rmap; int pf_cnt; bool init_done; }; @@ -265,4 +288,10 @@ int npc_cn20k_apply_custom_kpu(struct rvu *rvu, void npc_cn20k_update_action_entries_n_flags(struct rvu *rvu, struct npc_kpu_profile_adapter *pfl); + +int npc_cn20k_dft_rules_alloc(struct rvu *rvu, u16 pcifunc); +void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc); + +int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast, + u16 *mcast, u16 *promisc, u16 *ucast); #endif /* NPC_CN20K_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index a393bf884fd6..1b7f1103f78f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1539,9 +1539,10 @@ struct npc_mcam_alloc_entry_req { #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 */ + u8 ref_prio; /* Lower or higher w.r.t ref_entry */ u16 ref_entry; u16 count; /* Number of entries requested */ + u8 kw_type; /* entry key type, valid for cn20k */ }; =20 struct npc_mcam_alloc_entry_rsp { @@ -1634,10 +1635,12 @@ struct npc_mcam_alloc_and_write_entry_req { struct mbox_msghdr hdr; struct mcam_entry entry_data; u16 ref_entry; - u8 priority; /* Lower or higher w.r.t ref_entry */ + u8 ref_prio; /* Lower or higher w.r.t ref_entry */ u8 intf; /* Rx or Tx interface */ u8 enable_entry;/* Enable this MCAM entry ? */ u8 alloc_cntr; /* Allocate counter and map ? */ + /* hardware priority, supported for cn20k */ + u8 hw_prio; }; =20 struct npc_mcam_alloc_and_write_entry_rsp { @@ -1790,6 +1793,7 @@ struct npc_install_flow_req { u8 vtag1_op; /* old counter value */ u16 cntr_val; + u8 hw_prio; }; =20 struct npc_install_flow_rsp { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.c index 747fbdf2a908..c8482b1598b9 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -22,6 +22,7 @@ #include "rvu_npc_hash.h" #include "cn20k/reg.h" #include "cn20k/api.h" +#include "cn20k/npc.h" =20 #define DRV_NAME "rvu_af" #define DRV_STRING "Marvell OcteonTX2 RVU Admin Function Driver" @@ -1467,6 +1468,13 @@ static int rvu_detach_rsrcs(struct rvu *rvu, struct = rsrc_detach *detach, else if ((blkid =3D=3D BLKADDR_CPT1) && !detach->cptlfs) continue; } + + if (detach_all || + (detach && (blkid =3D=3D BLKADDR_NIX0 || + blkid =3D=3D BLKADDR_NIX1) && + detach->nixlf)) + npc_cn20k_dft_rules_free(rvu, pcifunc); + rvu_detach_block(rvu, pcifunc, block->type); } =20 @@ -1750,6 +1758,12 @@ int rvu_mbox_handler_attach_resources(struct rvu *rv= u, err =3D rvu_attach_block(rvu, pcifunc, BLKTYPE_NIX, 1, attach); if (err) goto fail2; + + if (is_cn20k(rvu->pdev)) { + err =3D npc_cn20k_dft_rules_alloc(rvu, pcifunc); + if (err) + goto fail3; + } } =20 if (attach->sso) { @@ -1763,7 +1777,7 @@ int rvu_mbox_handler_attach_resources(struct rvu *rvu, err =3D rvu_attach_block(rvu, pcifunc, BLKTYPE_SSO, attach->sso, attach); if (err) - goto fail3; + goto fail4; } =20 if (attach->ssow) { @@ -1772,7 +1786,7 @@ int rvu_mbox_handler_attach_resources(struct rvu *rvu, err =3D rvu_attach_block(rvu, pcifunc, BLKTYPE_SSOW, attach->ssow, attach); if (err) - goto fail4; + goto fail5; } =20 if (attach->timlfs) { @@ -1781,7 +1795,7 @@ int rvu_mbox_handler_attach_resources(struct rvu *rvu, err =3D rvu_attach_block(rvu, pcifunc, BLKTYPE_TIM, attach->timlfs, attach); if (err) - goto fail5; + goto fail6; } =20 if (attach->cptlfs) { @@ -1791,24 +1805,28 @@ int rvu_mbox_handler_attach_resources(struct rvu *r= vu, err =3D rvu_attach_block(rvu, pcifunc, BLKTYPE_CPT, attach->cptlfs, attach); if (err) - goto fail6; + goto fail7; } =20 mutex_unlock(&rvu->rsrc_lock); return 0; =20 -fail6: +fail7: if (attach->timlfs) rvu_detach_block(rvu, pcifunc, BLKTYPE_TIM); =20 -fail5: +fail6: if (attach->ssow) rvu_detach_block(rvu, pcifunc, BLKTYPE_SSOW); =20 -fail4: +fail5: if (attach->sso) rvu_detach_block(rvu, pcifunc, BLKTYPE_SSO); =20 +fail4: + if (is_cn20k(rvu->pdev)) + npc_cn20k_dft_rules_free(rvu, pcifunc); + fail3: if (attach->nixlf) rvu_detach_block(rvu, pcifunc, BLKTYPE_NIX); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.h index dd930aa05582..d2a0f6821cf9 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -308,6 +308,7 @@ struct rvu_pfvf { u64 lmt_map_ent_w1; /* Preseving the word1 of lmtst map table entry*/ unsigned long flags; struct sdp_node_info *sdp_info; + u8 hw_prio; /* Hw priority of default rules */ }; =20 enum rvu_pfvf_flags { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.c index 8361d0aa4b6f..246f3568a795 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -653,6 +653,9 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 p= cifunc, req.match_id =3D action.match_id; req.flow_key_alg =3D action.flow_key_alg; =20 + if (is_cn20k(rvu->pdev)) + req.hw_prio =3D pfvf->hw_prio; + rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp); } =20 @@ -741,6 +744,9 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16= pcifunc, req.match_id =3D action.match_id; req.flow_key_alg =3D flow_key_alg; =20 + if (is_cn20k(rvu->pdev)) + req.hw_prio =3D pfvf->hw_prio; + rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp); } =20 @@ -821,6 +827,9 @@ void rvu_npc_install_bcast_match_entry(struct rvu *rvu,= u16 pcifunc, req.hdr.pcifunc =3D 0; /* AF is requester */ req.vf =3D pcifunc; =20 + if (is_cn20k(rvu->pdev)) + req.hw_prio =3D pfvf->hw_prio; + rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp); } =20 @@ -909,6 +918,9 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, u1= 6 pcifunc, int nixlf, req.match_id =3D action.match_id; req.flow_key_alg =3D flow_key_alg; =20 + if (is_cn20k(rvu->pdev)) + req.hw_prio =3D pfvf->hw_prio; + rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp); } =20 @@ -2484,7 +2496,7 @@ npc_get_mcam_search_range_priority(struct npc_mcam *m= cam, { u16 fcnt; =20 - if (req->priority =3D=3D NPC_MCAM_HIGHER_PRIO) + if (req->ref_prio =3D=3D NPC_MCAM_HIGHER_PRIO) goto hprio; =20 /* For a low priority entry allocation @@ -2584,7 +2596,7 @@ static int npc_mcam_alloc_entries(struct npc_mcam *mc= am, u16 pcifunc, goto lprio_alloc; =20 /* Get the search range for priority allocation request */ - if (req->priority) { + if (req->ref_prio) { npc_get_mcam_search_range_priority(mcam, req, &start, &end, &reverse); goto alloc; @@ -2625,11 +2637,11 @@ static int npc_mcam_alloc_entries(struct npc_mcam *= mcam, u16 pcifunc, * and not in mid zone. */ if (!(pcifunc & RVU_PFVF_FUNC_MASK) && - req->priority =3D=3D NPC_MCAM_HIGHER_PRIO) + req->ref_prio =3D=3D NPC_MCAM_HIGHER_PRIO) end =3D req->ref_entry; =20 if (!(pcifunc & RVU_PFVF_FUNC_MASK) && - req->priority =3D=3D NPC_MCAM_LOWER_PRIO) + req->ref_prio =3D=3D NPC_MCAM_LOWER_PRIO) start =3D req->ref_entry; } =20 @@ -2678,7 +2690,7 @@ static int npc_mcam_alloc_entries(struct npc_mcam *mc= am, u16 pcifunc, /* 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) && + if (!req->ref_prio && rsp->count < req->count && ((end - start) !=3D mcam->bmap_entries)) { reverse =3D true; start =3D 0; @@ -2689,14 +2701,14 @@ static int npc_mcam_alloc_entries(struct npc_mcam *= mcam, u16 pcifunc, /* 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 =3D=3D NPC_MCAM_LOWER_PRIO && + if (req->ref_prio && rsp->count < req->count) { + if (req->ref_prio =3D=3D NPC_MCAM_LOWER_PRIO && (start !=3D (req->ref_entry + 1))) { start =3D req->ref_entry + 1; end =3D mcam->bmap_entries; reverse =3D false; goto alloc; - } else if ((req->priority =3D=3D NPC_MCAM_HIGHER_PRIO) && + } else if ((req->ref_prio =3D=3D NPC_MCAM_HIGHER_PRIO) && ((end - start) !=3D req->ref_entry)) { start =3D 0; end =3D req->ref_entry; @@ -2810,9 +2822,9 @@ int rvu_mbox_handler_npc_mcam_alloc_entry(struct rvu = *rvu, /* 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 =3D=3D NPC_MCAM_HIGHER_PRIO) || - ((req->ref_entry =3D=3D mcam->bmap_entries) && - req->priority =3D=3D NPC_MCAM_LOWER_PRIO)) + if ((!req->ref_entry && req->ref_prio =3D=3D NPC_MCAM_HIGHER_PRIO) || + (req->ref_entry =3D=3D mcam->bmap_entries && + req->ref_prio =3D=3D NPC_MCAM_LOWER_PRIO)) return NPC_MCAM_INVALID_REQ; =20 /* Since list of allocated indices needs to be sent to requester, @@ -3358,7 +3370,7 @@ int rvu_mbox_handler_npc_mcam_alloc_and_write_entry(s= truct rvu *rvu, /* Try to allocate a MCAM entry */ entry_req.hdr.pcifunc =3D req->hdr.pcifunc; entry_req.contig =3D true; - entry_req.priority =3D req->priority; + entry_req.ref_prio =3D req->ref_prio; entry_req.ref_entry =3D req->ref_entry; entry_req.count =3D 1; =20 diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/driv= ers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c index 64c6d9162ef6..052d989f2d9a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c @@ -104,7 +104,7 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 = count) * will be on top of PF. */ if (!is_otx2_vf(pfvf->pcifunc)) { - req->priority =3D NPC_MCAM_HIGHER_PRIO; + req->ref_prio =3D NPC_MCAM_HIGHER_PRIO; req->ref_entry =3D flow_cfg->def_ent[0]; } =20 --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 80EDB2874E9; Mon, 2 Feb 2026 07:46:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018412; cv=none; b=fKTYMJPHpvTNNHV+aVG1odvrP4hhKe7Mc9AxdEZBtuAeA+79/NtSwQsyPDs9d931pxZncWUWuIPHZWE+3uE9/+tJ46GwxNDEljSpK3siZ9cbLcIOJ2TjpolMYP3Dg1xC65dMvsuhULaYqPpj0u2cIEMNRy0JMBP6swG/fJuLo+w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018412; c=relaxed/simple; bh=y+IE3RCg1Qj6yKrseLBFekk1Ke441rZvmLiDs1+riSY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Avtc4HOibL4t8tLvSp/woAarrGR28iPoB4CaBElORQc9q6ApmucArHqIBw8n/9Z47/MEY8EfYZAhDhtT6EU7HqBHvzr2wT9jGVAyZrCch7m4CKJmKPdx3rqCAMawhr9BMGpCGzfMeA4w7Cumi24Doy3XYkMkaZ3aZ3KQUgdCfgQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=lTAe7/oc; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="lTAe7/oc" Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 611LrR8F2523987; Sun, 1 Feb 2026 23:46:36 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=W XxOrdx7fwFs4zvptLrXbLd7BHGWXPdOpTjQ3Cz+E5o=; b=lTAe7/ockqTEq63Lv YolA/5k5b7M1e7VYcE14OiGEUJEB/pkmWdCalfj/j2Ba0JYPNIQ1y95byzySchcl ASCkUhkcPdcJNahWmtCl9hV6/JvGgIxseWne8k3jm/1YP9HuwXOXM/Oq9OVovz9u fv10qQCpmSl9WzOgh+kK9GCnPIoJy1PiStoHJJ8/b3ZtwO1huozbyZbD/hXwhWPW j0U4xQZGVOEI5M5BBvRuQYQymueT6theFAak3y+ehP1ZOoDdEiX5PtOp65XV4pzU VXIHfMC3y19NWzuRO0SL1GwF8Fcy/ubLbSDNDM7olaU97JsoEW8iNzXlE+uQetXO Bz1Ng== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4c28pe1882-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:36 -0800 (PST) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:46:52 -0800 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:46:52 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 575335B6946; Sun, 1 Feb 2026 23:46:32 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , Suman Ghosh , Ratheesh Kannoth Subject: [PATCH net-next v8 06/13] octeontx2-af: npc: cn20k: Use common APIs Date: Mon, 2 Feb 2026 13:16:00 +0530 Message-ID: <20260202074607.2535569-7-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: yKLC3a77BexXCxPXNlJEAy3tjzcNPupn X-Authority-Analysis: v=2.4 cv=Y4/1cxeN c=1 sm=1 tr=0 ts=6980565c cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=YiITfu5hDICovFRBzmQA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfX8kMSfH1gdoRb A2Ys2NlGXT4FmQ2qf9gAQel9ExFzDmVahhNVadKibz7XSazbvzd7yXa/4NR6jdsLe/VFPbyT61R NHUa0O/JVfYGvMroTTDwdpQa9r7ZVvr4FiPKbQyO+Kls8CzBpMbxUKZ5elVVV8SKRbCfyVGMQhu GYXdr9z3HkSsGQyP1FbI7btMWhLaAv+3i1lolL4JZ1j2on8NkazuzfpQZvpzKfFV1ZJOPC/2jYm vD+i7KJgLaYaNahJ3VEbBbuJ//xt5BWyScegGDUh43mISFFnfME3lNPo+h1rhHJ2qu7XSO1CHL0 50PvNcrNrvhuV6aG67kG+ZItZAfxZRYurJue/Wifc0i7kc5XjymS2fWoV0D4HwAuOsdzWtAoiPh LkeD3cyAdjScAT+Jtlv0BbM9p+590LSQNvJNJ3Z7cdWHFkYtcfNkG2Ozm+eDNSxHXoar3fk5pDY lbNWoFWejaz21JYcs5Q== X-Proofpoint-GUID: yKLC3a77BexXCxPXNlJEAy3tjzcNPupn X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" From: Suman Ghosh In cn20k silicon, the register definitions and the algorithms used to read, write, copy, and enable MCAM entries have changed. This patch updates the common APIs to support both cn20k and previous silicon variants. Additionally, cn20k introduces a new algorithm for MCAM index management. The common APIs are updated to invoke the cn20k-specific index management routines for allocating, freeing, and retrieving default MCAM entries. Signed-off-by: Suman Ghosh Signed-off-by: Ratheesh Kannoth --- .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 503 +++++++++++++++++- .../ethernet/marvell/octeontx2/af/cn20k/npc.h | 15 + .../net/ethernet/marvell/octeontx2/af/mbox.h | 3 + .../net/ethernet/marvell/octeontx2/af/rvu.h | 4 +- .../ethernet/marvell/octeontx2/af/rvu_nix.c | 1 - .../ethernet/marvell/octeontx2/af/rvu_npc.c | 347 +++++++++--- .../marvell/octeontx2/af/rvu_npc_fs.c | 11 +- 7 files changed, 792 insertions(+), 92 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.c index e8b162cd7bbd..8f300e421a33 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c @@ -559,6 +559,472 @@ void npc_cn20k_load_mkex_profile(struct rvu *rvu, int= blkaddr, iounmap(mkex_prfl_addr); } =20 +void +npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr, + int index, bool enable) +{ + struct npc_mcam *mcam =3D &rvu->hw->mcam; + int mcam_idx =3D index % mcam->banksize; + int bank =3D index / mcam->banksize; + u64 cfg, hw_prio; + u8 kw_type; + + npc_mcam_idx_2_key_type(rvu, index, &kw_type); + if (kw_type =3D=3D NPC_MCAM_KEY_X2) { + cfg =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, + bank)); + hw_prio =3D cfg & GENMASK_ULL(14, 8); + cfg =3D enable ? 1 : 0; + cfg |=3D hw_prio; + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank), + cfg); + return; + } + + /* For NPC_CN20K_MCAM_KEY_X4 keys, both the banks + * need to be programmed with the same value. + */ + for (bank =3D 0; bank < mcam->banks_per_entry; bank++) { + cfg =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, + bank)); + hw_prio =3D cfg & GENMASK_ULL(14, 8); + cfg =3D enable ? 1 : 0; + cfg |=3D hw_prio; + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank), + cfg); + } +} + +void +npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int bank, int ind= ex) +{ + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index, bank, 1), + 0); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index, bank, 0), + 0); + + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, bank, 1), 0); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, bank, 0), 0); + + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, bank, 1), 0); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, bank, 0), 0); + + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, bank, 1), 0); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, bank, 0), 0); + + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, bank, 1), 0); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, bank, 0), 0); +} + +static void npc_cn20k_get_keyword(struct mcam_entry *entry, int idx, + u64 *cam0, u64 *cam1) +{ + u64 kw_mask; + + /* The two banks of every MCAM entry are used as a single double-wide + * entry that is compared with the search key as follows: + * + * NPC_AF_MCAME()_BANK(0)_CAM(0..1)_W0_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW0] + * NPC_AF_MCAME()_BANK(0)_CAM(0..1)_W1_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW1] + * NPC_AF_MCAME()_BANK(0)_CAM(0..1)_W2_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW2] + * NPC_AF_MCAME()_BANK(0)_CAM(0..1)_W3_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW3] + * NPC_AF_MCAME()_BANK(1)_CAM(0..1)_W0_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW4] + * NPC_AF_MCAME()_BANK(1)_CAM(0..1)_W1_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW5] + * NPC_AF_MCAME()_BANK(1)_CAM(0..1)_W2_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW6] + * NPC_AF_MCAME()_BANK(1)_CAM(0..1)_W3_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW7] + */ + *cam1 =3D entry->kw[idx]; + kw_mask =3D entry->kw_mask[idx]; + *cam1 &=3D kw_mask; + *cam0 =3D ~*cam1 & kw_mask; +} + +/*------------------------------------------------------------------------= -----| + *Kex type | mcam entry | cam1 | cam 0 || <----- output ----> | + *profile | len | (key type) | (key type) || len | type | + *------------------------------------------------------------------------= -----| + *X2 | 256 (X2) | 001b | 110b || X2 | X2 | + *------------------------------------------------------------------------= -----| + *X4 | 256 (X2) | 000b | 000b || X2 | DYNAMIC | + *------------------------------------------------------------------------= -----| + *X4 | 512 (X4) | 010b | 101b || X4 | X4 | + *------------------------------------------------------------------------= -----| + *DYN | 256 (X2) | 000b | 000b || X2 | DYNAMIC | + *------------------------------------------------------------------------= -----| + *DYN | 512 (X4) | 010b | 101b || X4 | X4 | + *------------------------------------------------------------------------= -----| + */ +static void npc_cn20k_config_kw_x2(struct rvu *rvu, struct npc_mcam *mcam, + int blkaddr, int index, u8 intf, + struct mcam_entry *entry, + int bank, u8 kw_type, int kw) +{ + u64 intf_ext =3D 0, intf_ext_mask =3D 0; + u8 tx_intf_mask =3D ~intf & 0x3; + u8 tx_intf =3D intf, kex_type; + u8 kw_type_mask =3D ~kw_type; + u64 cam0, cam1, kex_cfg; + + if (is_npc_intf_tx(intf)) { + /* Last bit must be set and rest don't care + * for TX interfaces + */ + tx_intf_mask =3D 0x1; + tx_intf =3D intf & tx_intf_mask; + tx_intf_mask =3D ~tx_intf & tx_intf_mask; + } + + kex_cfg =3D rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf)); + kex_type =3D (kex_cfg & GENMASK_ULL(34, 32)) >> 32; + if ((kex_type =3D=3D NPC_MCAM_KEY_DYN || kex_type =3D=3D NPC_MCAM_KEY_X4)= && + kw_type =3D=3D NPC_MCAM_KEY_X2) { + kw_type =3D 0; + kw_type_mask =3D 0; + } + + intf_ext =3D ((u64)kw_type << 16) | tx_intf; + intf_ext_mask =3D (((u64)kw_type_mask << 16) & GENMASK_ULL(18, 16)) | + tx_intf_mask; + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index, bank, 1), + intf_ext); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index, bank, 0), + intf_ext_mask); + + /* Set the match key */ + npc_cn20k_get_keyword(entry, kw, &cam0, &cam1); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, bank, 1), + cam1); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, bank, 0), + cam0); + + npc_cn20k_get_keyword(entry, kw + 1, &cam0, &cam1); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, bank, 1), + cam1); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, bank, 0), + cam0); + + npc_cn20k_get_keyword(entry, kw + 2, &cam0, &cam1); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, bank, 1), + cam1); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, bank, 0), + cam0); + + npc_cn20k_get_keyword(entry, kw + 3, &cam0, &cam1); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, bank, 1), + cam1); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, bank, 0), + cam0); +} + +static void npc_cn20k_config_kw_x4(struct rvu *rvu, struct npc_mcam *mcam, + int blkaddr, int index, u8 intf, + struct mcam_entry *entry, u8 kw_type) +{ + int kw =3D 0, bank; + + for (bank =3D 0; bank < mcam->banks_per_entry; bank++, kw =3D kw + 4) + npc_cn20k_config_kw_x2(rvu, mcam, blkaddr, + index, intf, + entry, bank, kw_type, kw); +} + +static void +npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blkaddr, int mcam_idx, + int bank, u8 kw_type, bool enable, u8 hw_prio) +{ + struct npc_mcam *mcam =3D &rvu->hw->mcam; + u64 bank_cfg; + + bank_cfg =3D (u64)hw_prio << 8; + if (enable) + bank_cfg |=3D 0x1; + + if (kw_type =3D=3D NPC_MCAM_KEY_X2) { + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank), + bank_cfg); + return; + } + + /* For NPC_MCAM_KEY_X4 keys, both the banks + * need to be programmed with the same value. + */ + for (bank =3D 0; bank < mcam->banks_per_entry; bank++) { + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank), + bank_cfg); + } +} + +void +npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index, u8 in= tf, + struct mcam_entry *entry, bool enable, u8 hw_prio) +{ + struct npc_mcam *mcam =3D &rvu->hw->mcam; + int mcam_idx =3D index % mcam->banksize; + int bank =3D index / mcam->banksize; + int kw =3D 0; + u8 kw_type; + + /* Disable before mcam entry update */ + npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, false); + + npc_mcam_idx_2_key_type(rvu, index, &kw_type); + /* CAM1 takes the comparison value and + * CAM0 specifies match for a bit in key being '0' or '1' or 'dontcare'. + * CAM1 =3D 0 & CAM0 =3D 1 =3D> match if key =3D 0 + * CAM1 =3D 1 & CAM0 =3D 0 =3D> match if key =3D 1 + * CAM1 =3D 0 & CAM0 =3D 0 =3D> always match i.e dontcare. + */ + if (kw_type =3D=3D NPC_MCAM_KEY_X2) { + /* Clear mcam entry to avoid writes being suppressed by NPC */ + npc_cn20k_clear_mcam_entry(rvu, blkaddr, bank, mcam_idx); + npc_cn20k_config_kw_x2(rvu, mcam, blkaddr, + mcam_idx, intf, entry, + bank, kw_type, kw); + /* Set 'action' */ + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx, + bank, 0), + entry->action); + + /* Set TAG 'action' */ + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx, + bank, 1), + entry->vtag_action); + + goto set_cfg; + } + /* Clear mcam entry to avoid writes being suppressed by NPC */ + npc_cn20k_clear_mcam_entry(rvu, blkaddr, 0, mcam_idx); + npc_cn20k_clear_mcam_entry(rvu, blkaddr, 1, mcam_idx); + + npc_cn20k_config_kw_x4(rvu, mcam, blkaddr, + mcam_idx, intf, entry, kw_type); + for (bank =3D 0; bank < mcam->banks_per_entry; bank++) { + /* Set 'action' */ + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx, + bank, 0), + entry->action); + + /* Set TAG 'action' */ + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx, + bank, 1), + entry->vtag_action); + } + +set_cfg: + /* TODO: */ + /* PF installing VF rule */ + npc_cn20k_set_mcam_bank_cfg(rvu, blkaddr, mcam_idx, bank, + kw_type, enable, hw_prio); +} + +void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 = dest) +{ + struct npc_mcam *mcam =3D &rvu->hw->mcam; + u64 cfg, sreg, dreg, soff, doff; + u8 src_kwtype, dest_kwtype; + int bank, i, sb, db; + int dbank, sbank; + + dbank =3D npc_get_bank(mcam, dest); + sbank =3D npc_get_bank(mcam, src); + npc_mcam_idx_2_key_type(rvu, src, &src_kwtype); + npc_mcam_idx_2_key_type(rvu, dest, &dest_kwtype); + if (src_kwtype !=3D dest_kwtype) + return; + + src &=3D (mcam->banksize - 1); + dest &=3D (mcam->banksize - 1); + + /* Copy INTF's, W0's, W1's, W2's, W3s CAM0 and CAM1 configuration */ + for (bank =3D 0; bank < mcam->banks_per_entry; bank++) { + sb =3D sbank + bank; + sreg =3D NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(src, sb, 0); + db =3D dbank + bank; + dreg =3D NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(dest, db, 0); + for (i =3D 0; i < 10; i++) { + cfg =3D rvu_read64(rvu, blkaddr, sreg + (i * 8)); + rvu_write64(rvu, blkaddr, dreg + (i * 8), cfg); + } + + /* Copy action */ + for (i =3D 0; i < 3; i++) { + soff =3D NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(src, + sb, i); + cfg =3D rvu_read64(rvu, blkaddr, soff); + + doff =3D NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(dest, db, + i); + rvu_write64(rvu, blkaddr, doff, cfg); + } + + /* Copy bank configuration */ + cfg =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(src, sb)); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(dest, db), cfg); + if (src_kwtype =3D=3D NPC_MCAM_KEY_X2) + break; + } +} + +static void npc_cn20k_fill_entryword(struct mcam_entry *entry, int idx, + u64 cam0, u64 cam1) +{ + entry->kw[idx] =3D cam1; + entry->kw_mask[idx] =3D cam1 ^ cam0; +} + +void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index, + struct mcam_entry *entry, u8 *intf, u8 *ena, + u8 *hw_prio) +{ + struct npc_mcam *mcam =3D &rvu->hw->mcam; + u64 cam0, cam1, bank_cfg, cfg; + int kw =3D 0, bank; + u8 kw_type; + + npc_mcam_idx_2_key_type(rvu, index, &kw_type); + + bank =3D npc_get_bank(mcam, index); + index &=3D (mcam->banksize - 1); + + cfg =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index, + bank, 1)) & 3; + *intf =3D cfg; + + bank_cfg =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(index, bank)); + *ena =3D bank_cfg & 0x1; + *hw_prio =3D (bank_cfg & GENMASK_ULL(14, 8)) >> 8; + if (kw_type =3D=3D NPC_MCAM_KEY_X2) { + cam1 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, + bank, + 1)); + cam0 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, + bank, + 0)); + npc_cn20k_fill_entryword(entry, kw, cam0, cam1); + + cam1 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, + bank, + 1)); + cam0 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, + bank, + 0)); + npc_cn20k_fill_entryword(entry, kw + 1, cam0, cam1); + + cam1 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, + bank, + 1)); + cam0 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, + bank, + 0)); + npc_cn20k_fill_entryword(entry, kw + 2, cam0, cam1); + + cam1 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, + bank, + 1)); + cam0 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, + bank, + 0)); + npc_cn20k_fill_entryword(entry, kw + 3, cam0, cam1); + goto read_action; + } + + for (bank =3D 0; bank < mcam->banks_per_entry; bank++, kw =3D kw + 4) { + cam1 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, + bank, + 1)); + cam0 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, + bank, + 0)); + npc_cn20k_fill_entryword(entry, kw, cam0, cam1); + + cam1 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, + bank, + 1)); + cam0 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, + bank, + 0)); + npc_cn20k_fill_entryword(entry, kw + 1, cam0, cam1); + + cam1 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, + bank, + 1)); + cam0 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, + bank, + 0)); + npc_cn20k_fill_entryword(entry, kw + 2, cam0, cam1); + + cam1 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, + bank, + 1)); + cam0 =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, + bank, + 0)); + npc_cn20k_fill_entryword(entry, kw + 3, cam0, cam1); + } + +read_action: + /* 'action' is set to same value for both bank '0' and '1'. + * Hence, reading bank '0' should be enough. + */ + cfg =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 0)); + entry->action =3D cfg; + + cfg =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 1)); + entry->vtag_action =3D cfg; +} + static u8 npc_map2cn20k_flag(u8 flag) { switch (flag) { @@ -632,11 +1098,12 @@ npc_cn20k_update_action_entries_n_flags(struct rvu *= rvu, int npc_cn20k_apply_custom_kpu(struct rvu *rvu, struct npc_kpu_profile_adapter *profile) { + size_t hdr_sz =3D sizeof(struct npc_cn20k_kpu_profile_fwdata); struct npc_cn20k_kpu_profile_fwdata *fw =3D rvu->kpu_fwdata; struct npc_kpu_profile_action *action; struct npc_kpu_profile_cam *cam; struct npc_kpu_fwdata *fw_kpu; - size_t hdr_sz, offset =3D 0; + size_t offset =3D 0; u16 kpu, entry; int entries; =20 @@ -723,6 +1190,40 @@ int npc_cn20k_apply_custom_kpu(struct rvu *rvu, return 0; } =20 +int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type) +{ + struct npc_subbank *sb; + int bank_off, sb_id; + + /* mcam_idx should be less than (2 * bank depth) */ + if (mcam_idx >=3D 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 =3D mcam_idx & (npc_priv.bank_depth - 1); + + /* Find subbank id */ + sb_id =3D bank_off / npc_priv.subbank_depth; + + /* Check if subbank id is more than maximum + * number of subbanks available + */ + if (sb_id >=3D npc_priv.num_subbanks) { + dev_err(rvu->dev, "%s:%d invalid subbank %d\n", + __func__, __LINE__, sb_id); + return -EINVAL; + } + + sb =3D &npc_priv.sb[sb_id]; + + *key_type =3D sb->key_type; + + return 0; +} + static int npc_subbank_idx_2_mcam_idx(struct rvu *rvu, struct npc_subbank = *sb, u16 sub_off, u16 *mcam_idx) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.h index 8ef9a7510864..75c3dce2b0b0 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h @@ -294,4 +294,19 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pci= func); =20 int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast, u16 *mcast, u16 *promisc, u16 *ucast); + +void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index, + u8 intf, struct mcam_entry *entry, + bool enable, u8 hw_prio); +void npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr, + int index, bool enable); +void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, + u16 src, u16 dest); +void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index, + struct mcam_entry *entry, u8 *intf, u8 *ena, + u8 *hw_prio); +void npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, + int bank, int index); +int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type); + #endif /* NPC_CN20K_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index 1b7f1103f78f..8aa684bd83f0 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1577,6 +1577,8 @@ struct npc_mcam_write_entry_req { u8 intf; /* Rx or Tx interface */ u8 enable_entry;/* Enable this MCAM entry ? */ u8 set_cntr; /* Set counter for this entry ? */ + u8 hw_prio; /* hardware priority, valid for cn20k */ + u64 reserved; /* reserved for future use */ }; =20 /* Enable/Disable a given entry */ @@ -1824,6 +1826,7 @@ struct npc_mcam_read_entry_rsp { struct mcam_entry entry_data; u8 intf; u8 enable; + u8 hw_prio; /* valid for cn20k */ }; =20 /* Available entries to use */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.h index d2a0f6821cf9..a53bb5c924ef 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -1124,8 +1124,8 @@ int rvu_cgx_cfg_pause_frm(struct rvu *rvu, u16 pcifun= c, u8 tx_pause, u8 rx_pause void rvu_mac_reset(struct rvu *rvu, u16 pcifunc); u32 rvu_cgx_get_lmac_fifolen(struct rvu *rvu, int cgx, int lmac); void cgx_start_linkup(struct rvu *rvu); -int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, u16 pcifunc, int nixlf, - int type); +int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, + u16 pcifunc, int nixlf, int type); bool is_mcam_entry_enabled(struct rvu *rvu, struct npc_mcam *mcam, int blk= addr, int index); int rvu_npc_init(struct rvu *rvu); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_nix.c index 2f485a930edd..810707d0e1f2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -5283,7 +5283,6 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, = struct msg_req *req, /* Disable the interface if it is in any multicast list */ nix_mcast_update_mce_entry(rvu, pcifunc, 0); =20 - pfvf =3D rvu_get_pfvf(rvu, pcifunc); clear_bit(NIXLF_INITIALIZED, &pfvf->flags); =20 diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.c index 246f3568a795..f8fe93c78dae 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -18,6 +18,7 @@ #include "rvu_npc_hash.h" #include "cn20k/npc.h" #include "rvu_npc.h" +#include "cn20k/reg.h" =20 #define RSVD_MCAM_ENTRIES_PER_PF 3 /* Broadcast, Promisc and AllMulticast = */ #define RSVD_MCAM_ENTRIES_PER_NIXLF 1 /* Ucast for LFs */ @@ -151,10 +152,33 @@ int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, { struct rvu_hwinfo *hw =3D container_of(mcam, struct rvu_hwinfo, mcam); struct rvu *rvu =3D hw->rvu; - int pf =3D rvu_get_pf(rvu->pdev, pcifunc); + u16 bcast, mcast, promisc, ucast; int index; + int rc; + int pf; + + if (is_cn20k(rvu->pdev)) { + rc =3D npc_cn20k_dft_rules_idx_get(rvu, pcifunc, &bcast, &mcast, + &promisc, &ucast); + if (rc) + return -EFAULT; + + switch (type) { + case NIXLF_BCAST_ENTRY: + return bcast; + case NIXLF_ALLMULTI_ENTRY: + return mcast; + case NIXLF_PROMISC_ENTRY: + return promisc; + case NIXLF_UCAST_ENTRY: + return ucast; + default: + return -EINVAL; + } + } =20 /* Check if this is for a PF */ + pf =3D rvu_get_pf(rvu->pdev, pcifunc); if (pf && !(pcifunc & RVU_PFVF_FUNC_MASK)) { /* Reserved entries exclude PF0 */ pf--; @@ -175,7 +199,12 @@ int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, =20 int npc_get_bank(struct npc_mcam *mcam, int index) { + struct rvu_hwinfo *hw =3D container_of(mcam, struct rvu_hwinfo, mcam); int bank =3D index / mcam->banksize; + struct rvu *rvu =3D hw->rvu; + + if (is_cn20k(rvu->pdev)) + return bank; =20 /* 0,1 & 2,3 banks are combined for this keysize */ if (mcam->keysize =3D=3D NPC_MCAM_KEY_X2) @@ -191,7 +220,14 @@ bool is_mcam_entry_enabled(struct rvu *rvu, struct npc= _mcam *mcam, u64 cfg; =20 index &=3D (mcam->banksize - 1); - cfg =3D rvu_read64(rvu, blkaddr, NPC_AF_MCAMEX_BANKX_CFG(index, bank)); + if (is_cn20k(rvu->pdev)) + cfg =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(index, + bank)); + else + cfg =3D rvu_read64(rvu, blkaddr, + NPC_AF_MCAMEX_BANKX_CFG(index, bank)); + return (cfg & 1); } =20 @@ -201,6 +237,13 @@ void npc_enable_mcam_entry(struct rvu *rvu, struct npc= _mcam *mcam, int bank =3D npc_get_bank(mcam, index); int actbank =3D bank; =20 + if (is_cn20k(rvu->pdev)) { + if (index < 0 || index >=3D mcam->banksize * mcam->banks) + return; + + return npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable); + } + index &=3D (mcam->banksize - 1); for (; bank < (actbank + mcam->banks_per_entry); bank++) { rvu_write64(rvu, blkaddr, @@ -369,6 +412,7 @@ static u64 npc_get_default_entry_action(struct rvu *rvu= , struct npc_mcam *mcam, int blkaddr, u16 pf_func) { int bank, nixlf, index; + u64 reg; =20 /* get ucast entry rule entry index */ if (nix_get_nixlf(rvu, pf_func, &nixlf, NULL)) { @@ -383,8 +427,12 @@ static u64 npc_get_default_entry_action(struct rvu *rv= u, struct npc_mcam *mcam, bank =3D npc_get_bank(mcam, index); index &=3D (mcam->banksize - 1); =20 - return rvu_read64(rvu, blkaddr, - NPC_AF_MCAMEX_BANKX_ACTION(index, bank)); + if (is_cn20k(rvu->pdev)) + reg =3D NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 0); + else + reg =3D NPC_AF_MCAMEX_BANKX_ACTION(index, bank); + + return rvu_read64(rvu, blkaddr, reg); } =20 static void npc_fixup_vf_rule(struct rvu *rvu, struct npc_mcam *mcam, @@ -549,6 +597,9 @@ static void npc_copy_mcam_entry(struct rvu *rvu, struct= npc_mcam *mcam, u64 cfg, sreg, dreg; int bank, i; =20 + if (is_cn20k(rvu->pdev)) + return npc_cn20k_copy_mcam_entry(rvu, blkaddr, src, dest); + src &=3D (mcam->banksize - 1); dest &=3D (mcam->banksize - 1); =20 @@ -585,20 +636,31 @@ u64 npc_get_mcam_action(struct rvu *rvu, struct npc_m= cam *mcam, int blkaddr, int index) { int bank =3D npc_get_bank(mcam, index); + u64 reg; =20 index &=3D (mcam->banksize - 1); - return rvu_read64(rvu, blkaddr, - NPC_AF_MCAMEX_BANKX_ACTION(index, bank)); + + if (is_cn20k(rvu->pdev)) + reg =3D NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 0); + else + reg =3D NPC_AF_MCAMEX_BANKX_ACTION(index, bank); + return rvu_read64(rvu, blkaddr, reg); } =20 void npc_set_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, int blkaddr, int index, u64 cfg) { int bank =3D npc_get_bank(mcam, index); + u64 reg; =20 index &=3D (mcam->banksize - 1); - return rvu_write64(rvu, blkaddr, - NPC_AF_MCAMEX_BANKX_ACTION(index, bank), cfg); + + if (is_cn20k(rvu->pdev)) + reg =3D NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 0); + else + reg =3D NPC_AF_MCAMEX_BANKX_ACTION(index, bank); + + return rvu_write64(rvu, blkaddr, reg, cfg); } =20 void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, @@ -954,33 +1016,42 @@ static void npc_update_vf_flow_entry(struct rvu *rvu= , struct npc_mcam *mcam, =20 mutex_lock(&mcam->lock); for (index =3D 0; index < mcam->bmap_entries; index++) { - if (mcam->entry2target_pffunc[index] =3D=3D pcifunc) { - update =3D true; - /* update not needed for the rules added via ntuple filters */ - list_for_each_entry(rule, &mcam->mcam_rules, list) { - if (rule->entry =3D=3D index) - update =3D false; - } - if (!update) - continue; - bank =3D npc_get_bank(mcam, index); - actindex =3D index; - entry =3D index & (mcam->banksize - 1); - - /* read vf flow entry enable status */ - enable =3D is_mcam_entry_enabled(rvu, mcam, blkaddr, - actindex); - /* disable before mcam entry update */ - npc_enable_mcam_entry(rvu, mcam, blkaddr, actindex, - false); - /* update 'action' */ + if (mcam->entry2target_pffunc[index] !=3D pcifunc) + continue; + update =3D true; + /* update not needed for the rules added via ntuple filters */ + list_for_each_entry(rule, &mcam->mcam_rules, list) { + if (rule->entry =3D=3D index) + update =3D false; + } + if (!update) + continue; + bank =3D npc_get_bank(mcam, index); + actindex =3D index; + entry =3D index & (mcam->banksize - 1); + + /* read vf flow entry enable status */ + enable =3D is_mcam_entry_enabled(rvu, mcam, blkaddr, + actindex); + /* disable before mcam entry update */ + npc_enable_mcam_entry(rvu, mcam, blkaddr, actindex, + false); + + /* update 'action' */ + if (is_cn20k(rvu->pdev)) + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(entry, + bank, + 0), + rx_action); + else rvu_write64(rvu, blkaddr, NPC_AF_MCAMEX_BANKX_ACTION(entry, bank), rx_action); - if (enable) - npc_enable_mcam_entry(rvu, mcam, blkaddr, - actindex, true); - } + + if (enable) + npc_enable_mcam_entry(rvu, mcam, blkaddr, + actindex, true); } mutex_unlock(&mcam->lock); } @@ -993,6 +1064,7 @@ static void npc_update_rx_action_with_alg_idx(struct r= vu *rvu, struct nix_rx_act struct npc_mcam *mcam =3D &rvu->hw->mcam; struct rvu_hwinfo *hw =3D rvu->hw; int bank, op_rss; + u64 reg; =20 if (!is_mcam_entry_enabled(rvu, mcam, blkaddr, mcam_index)) return; @@ -1002,15 +1074,19 @@ static void npc_update_rx_action_with_alg_idx(struc= t rvu *rvu, struct nix_rx_act bank =3D npc_get_bank(mcam, mcam_index); mcam_index &=3D (mcam->banksize - 1); =20 + if (is_cn20k(rvu->pdev)) + reg =3D NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_index, + bank, 0); + else + reg =3D NPC_AF_MCAMEX_BANKX_ACTION(mcam_index, bank); + /* If Rx action is MCAST update only RSS algorithm index */ if (!op_rss) { - *(u64 *)&action =3D rvu_read64(rvu, blkaddr, - NPC_AF_MCAMEX_BANKX_ACTION(mcam_index, bank)); + *(u64 *)&action =3D rvu_read64(rvu, blkaddr, reg); =20 action.flow_key_alg =3D alg_idx; } - rvu_write64(rvu, blkaddr, - NPC_AF_MCAMEX_BANKX_ACTION(mcam_index, bank), *(u64 *)&action); + rvu_write64(rvu, blkaddr, reg, *(u64 *)&action); } =20 void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixl= f, @@ -1020,6 +1096,7 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, = u16 pcifunc, int nixlf, struct nix_rx_action action; int blkaddr, index, bank; struct rvu_pfvf *pfvf; + u64 reg; =20 blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) @@ -1042,8 +1119,12 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu,= u16 pcifunc, int nixlf, bank =3D npc_get_bank(mcam, index); index &=3D (mcam->banksize - 1); =20 - *(u64 *)&action =3D rvu_read64(rvu, blkaddr, - NPC_AF_MCAMEX_BANKX_ACTION(index, bank)); + if (is_cn20k(rvu->pdev)) + reg =3D NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 0); + else + reg =3D NPC_AF_MCAMEX_BANKX_ACTION(index, bank); + + *(u64 *)&action =3D rvu_read64(rvu, blkaddr, reg); /* Ignore if no action was set earlier */ if (!*(u64 *)&action) return; @@ -1053,9 +1134,7 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, = u16 pcifunc, int nixlf, action.index =3D group; action.flow_key_alg =3D alg_idx; =20 - rvu_write64(rvu, blkaddr, - NPC_AF_MCAMEX_BANKX_ACTION(index, bank), *(u64 *)&action); - + rvu_write64(rvu, blkaddr, reg, *(u64 *)&action); /* update the VF flow rule action with the VF default entry action */ if (mcam_index < 0) npc_update_vf_flow_entry(rvu, mcam, blkaddr, pcifunc, @@ -1870,46 +1949,56 @@ int npc_mcam_rsrcs_init(struct rvu *rvu, int blkadd= r) int cntr; u64 cfg; =20 - /* Actual number of MCAM entries vary by entry size */ cfg =3D (rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(0)) >> 32) & 0x07; - mcam->total_entries =3D (mcam->banks / BIT_ULL(cfg)) * mcam->banksize; mcam->keysize =3D cfg; =20 /* Number of banks combined per MCAM entry */ if (is_cn20k(rvu->pdev)) { + /* In cn20k, x2 entries is allowed for x4 profile. + * set total_entries as 8192 * 2 and key size as x2. + */ + mcam->total_entries =3D mcam->banks * mcam->banksize; if (cfg =3D=3D NPC_MCAM_KEY_X2) mcam->banks_per_entry =3D 1; else mcam->banks_per_entry =3D 2; + + rsvd =3D 0; } else { + mcam->total_entries =3D (mcam->banks / BIT_ULL(cfg)) * + mcam->banksize; + if (cfg =3D=3D NPC_MCAM_KEY_X4) mcam->banks_per_entry =3D 4; else if (cfg =3D=3D NPC_MCAM_KEY_X2) mcam->banks_per_entry =3D 2; else mcam->banks_per_entry =3D 1; - } =20 - /* Reserve one MCAM entry for each of the NIX LF to - * guarantee space to install default matching DMAC rule. - * Also reserve 2 MCAM entries for each PF for default - * channel based matching or 'bcast & promisc' matching to - * support BCAST and PROMISC modes of operation for PFs. - * PF0 is excluded. - */ - rsvd =3D (nixlf_count * RSVD_MCAM_ENTRIES_PER_NIXLF) + - ((rvu->hw->total_pfs - 1) * RSVD_MCAM_ENTRIES_PER_PF); - if (mcam->total_entries <=3D rsvd) { - dev_warn(rvu->dev, - "Insufficient NPC MCAM size %d for pkt I/O, exiting\n", - mcam->total_entries); - return -ENOMEM; + /* Reserve one MCAM entry for each of the NIX LF to + * guarantee space to install default matching DMAC rule. + * Also reserve 2 MCAM entries for each PF for default + * channel based matching or 'bcast & promisc' matching to + * support BCAST and PROMISC modes of operation for PFs. + * PF0 is excluded. + */ + rsvd =3D (nixlf_count * RSVD_MCAM_ENTRIES_PER_NIXLF) + + ((rvu->hw->total_pfs - 1) * RSVD_MCAM_ENTRIES_PER_PF); + if (mcam->total_entries <=3D rsvd) { + dev_warn(rvu->dev, + "Insufficient NPC MCAM size %d for pkt I/O, exiting\n", + mcam->total_entries); + return -ENOMEM; + } } =20 mcam->bmap_entries =3D mcam->total_entries - rsvd; - mcam->nixlf_offset =3D mcam->bmap_entries; - mcam->pf_offset =3D mcam->nixlf_offset + nixlf_count; + /* cn20k does not need offsets to alloc mcam entries */ + if (!is_cn20k(rvu->pdev)) { + mcam->nixlf_offset =3D mcam->bmap_entries; + mcam->pf_offset =3D mcam->nixlf_offset + nixlf_count; + } =20 /* Allocate bitmaps for managing MCAM entries */ mcam->bmap =3D bitmap_zalloc(mcam->bmap_entries, GFP_KERNEL); @@ -1933,13 +2022,15 @@ int npc_mcam_rsrcs_init(struct rvu *rvu, int blkadd= r) * allocations and another 1/8th at the top for high priority * allocations. */ - mcam->lprio_count =3D mcam->bmap_entries / 8; - if (mcam->lprio_count > BITS_PER_LONG) - mcam->lprio_count =3D round_down(mcam->lprio_count, - BITS_PER_LONG); - mcam->lprio_start =3D mcam->bmap_entries - mcam->lprio_count; - mcam->hprio_count =3D mcam->lprio_count; - mcam->hprio_end =3D mcam->hprio_count; + if (!is_cn20k(rvu->pdev)) { + mcam->lprio_count =3D mcam->bmap_entries / 8; + if (mcam->lprio_count > BITS_PER_LONG) + mcam->lprio_count =3D round_down(mcam->lprio_count, + BITS_PER_LONG); + mcam->lprio_start =3D mcam->bmap_entries - mcam->lprio_count; + mcam->hprio_count =3D mcam->lprio_count; + mcam->hprio_end =3D mcam->hprio_count; + } =20 /* Allocate bitmap for managing MCAM counters and memory * for saving counter to RVU PFFUNC allocation mapping. @@ -2063,24 +2154,21 @@ static void rvu_npc_setup_interfaces(struct rvu *rv= u, int blkaddr) struct npc_mcam *mcam =3D &rvu->hw->mcam; struct rvu_hwinfo *hw =3D rvu->hw; u64 nibble_ena, rx_kex, tx_kex; - u64 *keyx_cfg; + u64 *keyx_cfg, reg; u8 intf; =20 if (is_cn20k(rvu->pdev)) { keyx_cfg =3D mkex_extr->keyx_cfg; - goto skip_miss_cntr; + } else { + keyx_cfg =3D mkex->keyx_cfg; + /* Reserve last counter for MCAM RX miss action which is set to + * drop packet. This way we will know how many pkts didn't + * match any MCAM entry. + */ + mcam->counters.max--; + mcam->rx_miss_act_cntr =3D mcam->counters.max; } =20 - keyx_cfg =3D mkex->keyx_cfg; - - /* Reserve last counter for MCAM RX miss action which is set to - * drop packet. This way we will know how many pkts didn't match - * any MCAM entry. - */ - mcam->counters.max--; - mcam->rx_miss_act_cntr =3D mcam->counters.max; - -skip_miss_cntr: rx_kex =3D keyx_cfg[NIX_INTF_RX]; tx_kex =3D keyx_cfg[NIX_INTF_TX]; =20 @@ -2103,14 +2191,18 @@ static void rvu_npc_setup_interfaces(struct rvu *rv= u, int blkaddr) rx_kex); =20 if (is_cn20k(rvu->pdev)) - continue; + reg =3D NPC_AF_INTFX_MISS_ACTX(intf, 0); + else + reg =3D NPC_AF_INTFX_MISS_ACT(intf); =20 /* If MCAM lookup doesn't result in a match, drop the received * packet. And map this action to a counter to count dropped * packets. */ - rvu_write64(rvu, blkaddr, - NPC_AF_INTFX_MISS_ACT(intf), NIX_RX_ACTIONOP_DROP); + rvu_write64(rvu, blkaddr, reg, NIX_RX_ACTIONOP_DROP); + + if (is_cn20k(rvu->pdev)) + continue; =20 /* NPC_AF_INTFX_MISS_STAT_ACT[14:12] - counter[11:9] * NPC_AF_INTFX_MISS_STAT_ACT[8:0] - counter[8:0] @@ -2130,12 +2222,15 @@ static void rvu_npc_setup_interfaces(struct rvu *rv= u, int blkaddr) rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf), tx_kex); =20 + if (is_cn20k(rvu->pdev)) + reg =3D NPC_AF_INTFX_MISS_ACTX(intf, 0); + else + reg =3D NPC_AF_INTFX_MISS_ACT(intf); + /* Set TX miss action to UCAST_DEFAULT i.e * transmit the packet on NIX LF SQ's default channel. */ - rvu_write64(rvu, blkaddr, - NPC_AF_INTFX_MISS_ACT(intf), - NIX_TX_ACTIONOP_UCAST_DEFAULT); + rvu_write64(rvu, blkaddr, reg, NIX_TX_ACTIONOP_UCAST_DEFAULT); } } =20 @@ -2333,6 +2428,10 @@ static void npc_map_mcam_entry_and_cntr(struct rvu *= rvu, struct npc_mcam *mcam, /* Set mapping and increment counter's refcnt */ mcam->entry2cntr_map[entry] =3D cntr; mcam->cntr_refcnt[cntr]++; + + if (is_cn20k(rvu->pdev)) + return; + /* Enable stats */ rvu_write64(rvu, blkaddr, NPC_AF_MCAMEX_BANKX_STAT_ACT(index, bank), @@ -2390,6 +2489,7 @@ static void npc_mcam_free_all_entries(struct rvu *rvu= , struct npc_mcam *mcam, int blkaddr, u16 pcifunc) { u16 index, cntr; + int rc; =20 /* Scan all MCAM entries and free the ones mapped to 'pcifunc' */ for (index =3D 0; index < mcam->bmap_entries; index++) { @@ -2407,6 +2507,13 @@ static void npc_mcam_free_all_entries(struct rvu *rv= u, struct npc_mcam *mcam, blkaddr, index, cntr); mcam->entry2target_pffunc[index] =3D 0x0; + if (is_cn20k(rvu->pdev)) { + rc =3D npc_cn20k_idx_free(rvu, &index, 1); + if (rc) + dev_err(rvu->dev, + "Failed to free mcam idx=3D%u pcifunc=3D%#x\n", + index, pcifunc); + } } } } @@ -2553,14 +2660,76 @@ 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) { + struct rvu_hwinfo *hw =3D container_of(mcam, struct rvu_hwinfo, mcam); u16 entry_list[NPC_MAX_NONCONTIG_ENTRIES]; u16 fcnt, hp_fcnt, lp_fcnt; + struct rvu *rvu =3D hw->rvu; u16 start, end, index; int entry, next_start; bool reverse =3D false; unsigned long *bmap; + int ret, limit =3D 0; u16 max_contig; =20 + if (!is_cn20k(rvu->pdev)) + goto not_cn20k; + + /* The below table is being followed during allocation, + * + * 1. ref_entry =3D=3D 0 && prio =3D=3D HIGH && count =3D=3D 1 : user wan= ts to + * allocate 0th index + * 2. ref_entry =3D=3D 0 && prio =3D=3D HIGH && count > 1 : Invalid requ= est + * 3. ref_entry =3D=3D 0 && prio =3D=3D LOW && count >=3D 1 : limit =3D 0 + * 4. ref_entry !=3D 0 && prio =3D=3D HIGH && count >=3D 1 : limit =3D 0 + * 5. ref_entry !=3D 0 && prio =3D=3D LOW && count >=3D1 : limit =3D Max + * (X2 2*8192, X4 8192) + */ + if (req->ref_entry && req->ref_prio =3D=3D NPC_MCAM_LOWER_PRIO) { + if (req->kw_type =3D=3D NPC_MCAM_KEY_X2) + limit =3D 2 * mcam->bmap_entries; + else + limit =3D mcam->bmap_entries; + } + + ret =3D npc_cn20k_ref_idx_alloc(rvu, pcifunc, req->kw_type, + req->ref_prio, rsp->entry_list, + req->ref_entry, limit, + req->contig, req->count); + + if (ret) { + rsp->count =3D 0; + return NPC_MCAM_ALLOC_FAILED; + } + + rsp->count =3D req->count; + if (req->contig) + rsp->entry =3D rsp->entry_list[0]; + + /* cn20k, entries allocation algorithm is different. + * This common API updates some bitmap on usage etc, which + * will be used by other functions. So update those for + * cn20k as well. + */ + + mutex_lock(&mcam->lock); + /* Mark the allocated entries as used and set nixlf mapping */ + for (entry =3D 0; entry < rsp->count; entry++) { + index =3D rsp->entry_list[entry]; + npc_mcam_set_bit(mcam, index); + mcam->entry2pfvf_map[index] =3D pcifunc; + mcam->entry2cntr_map[index] =3D NPC_MCAM_INVALID_MAP; + } + + /* cn20k, free count is provided thru different mbox message. + * one counter to indicate free x2 slots and free x4 slots + * does not provide any useful information to the user. + */ + rsp->free_count =3D -1; + mutex_unlock(&mcam->lock); + + return 0; + +not_cn20k: mutex_lock(&mcam->lock); =20 /* Check if there are any free entries */ @@ -2881,6 +3050,14 @@ int rvu_mbox_handler_npc_mcam_free_entry(struct rvu = *rvu, npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr, req->entry, cntr); =20 + if (is_cn20k(rvu->pdev)) { + rc =3D npc_cn20k_idx_free(rvu, &req->entry, 1); + if (rc) + dev_err(rvu->dev, + "Failed to free index=3D%u\n", + req->entry); + } + goto exit; =20 free_all: diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drive= rs/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index 4817708d0af7..508233876fc1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -1761,14 +1761,19 @@ static int npc_update_dmac_value(struct rvu *rvu, i= nt npcblkaddr, struct npc_mcam_write_entry_req write_req =3D { 0 }; struct mcam_entry *entry =3D &write_req.entry_data; struct npc_mcam *mcam =3D &rvu->hw->mcam; + u8 intf, enable, hw_prio; struct msg_rsp rsp; - u8 intf, enable; int err; =20 ether_addr_copy(rule->packet.dmac, pfvf->mac_addr); =20 - npc_read_mcam_entry(rvu, mcam, npcblkaddr, rule->entry, - entry, &intf, &enable); + if (is_cn20k(rvu->pdev)) + npc_cn20k_read_mcam_entry(rvu, npcblkaddr, rule->entry, + entry, &intf, + &enable, &hw_prio); + else + npc_read_mcam_entry(rvu, mcam, npcblkaddr, rule->entry, + entry, &intf, &enable); =20 npc_update_entry(rvu, NPC_DMAC, entry, ether_addr_to_u64(pfvf->mac_addr), 0, --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2F2E02EBDC8; Mon, 2 Feb 2026 07:46:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018413; cv=none; b=nOE6sZBX5qcyt6nS4q3flbFWkNXlqguYI+wze3WPos6pVaAK1qmmksTKLE8uL9vFrVQobIO0XQdTdPGxxIhO8tq4tyRje9lL7798cUquPlqsnYGseRvcZCI5Wp4kGPbCLf17IR/REb0HpimU/5oZs2khd8H+mU+zQSWdpIXGPF4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018413; c=relaxed/simple; bh=3LT9O6wvSVmIpabQ2MCVNj3f1KFa1TYp5hUOAzMpdHg=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=WL0NU7OspVkBpA2FmkbPgMoFpr3gW3BBLS57UakyQguUWYQs9mz0C6vMFpRovnitHONBEOzMMMItIuVEgeFVnStCWJj+CSNPmd/TyUEZ97xH+4HLy3swPYSsGmqCD3B5sD9EFm/D+NKpEZKF87FHOxqvvZF+HbSO2A3lYqsCUYU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=EpK09wBQ; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="EpK09wBQ" Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 611N2MJt2646888; Sun, 1 Feb 2026 23:46:39 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=e USwl5TGlAUA26MOKeK/t/Yr6G1JtNL4UV1Sm3avW74=; b=EpK09wBQR3swGBAM+ nu5HwhGwVmG7jZVZqbymVbPM9mpuM9o5IzWr+H1cHA2M6yODBXvP0Thbki6zQECt n6YX+tQuXb8/Shw5ImlhZtkc5/0VUWPdMQC93BTfKpttuNY2Gf3nT5gtbdQX48qA s1bpqucV3kUWD3b+1njrc+RU3REwKfu6YCe4A6HRaf2HkLLIAQIpMRN94Gaj5A1/ 6g7REX/sERhgSoeSx56wGhX7krt4DfZCUXGKx5Jcj7SpvZlfzyzzMq+cGNsdKQOz Miur5M72YHJyZ/oVX2rDJ24iXy5zzqLhnQ/M408KnF8Aw599gNB3kTg5Zk8hl2hU /SI+g== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4c28pe188r-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:39 -0800 (PST) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:46:55 -0800 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:46:55 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id F2A845B6946; Sun, 1 Feb 2026 23:46:35 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH net-next v8 07/13] octeontx2-af: npc: cn20k: Prepare for new SoC Date: Mon, 2 Feb 2026 13:16:01 +0530 Message-ID: <20260202074607.2535569-8-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: erEzuYL6RfiIq-8Y0Saip4Klm-QYkdGN X-Authority-Analysis: v=2.4 cv=Y4/1cxeN c=1 sm=1 tr=0 ts=6980565f cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=TxAswAKAtbBGRXV0VdsA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfX42P7cbXrEXpP EZIklWTUms1Rw3K9+pxtBYuNaDuH+YyKuaikRoPSMHhQB9XKiWBrKkOGpgYP5KmadrMssp7TenT +jVdf19Xnus9KaQgqeZ8dbjOVPIn+PVGdVyGlyaXIipv1OTco/bJcNY5Uqi2HOSfuL6trHrh4js hVCMz6Ck2KiB65IZWA7h0x+i1NG29ywKRgkYU/YBKhltyh/XaSbuQE+ExaKWUQ6kYKfSbrHg2eS cCUs/A/f0/LwW0/y6PWY19zKORGFk/1RqZP+8e6vCwYwKWVZoOfi/kMGspAmn/f7Ep8vK+QQA52 ySZcZU5AcbQ5fuPsVgY//vPa5EvKULuusKIiS+bLFfcuFtXokIElaMExck1eHJ0SRdDROWmbem0 R70UMa//iUXwZCTN2jExZn+6ulSA0wVLyS92iDaNsVuwxRfSNEZIzkLWMW2H8LxrHT0hYXtfKoh Xzl26cvsCtv35v+DdnQ== X-Proofpoint-GUID: erEzuYL6RfiIq-8Y0Saip4Klm-QYkdGN X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" Current code pass mcam_entry structure to all low level functions. This is not proper: 1) We need to modify all functions to support a new SoC 2) It does not look good to pass soc specific structure to all common functions. This patch adds a mcam meta data structure, which is populated and passed to low level functions. Signed-off-by: Ratheesh Kannoth --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 8 + .../marvell/octeontx2/af/rvu_npc_fs.c | 143 +++++++++++------- .../marvell/octeontx2/af/rvu_npc_fs.h | 2 +- .../marvell/octeontx2/af/rvu_npc_hash.c | 113 +++++++------- .../marvell/octeontx2/af/rvu_npc_hash.h | 2 +- 5 files changed, 155 insertions(+), 113 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index 8aa684bd83f0..a4e79828a84c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1561,6 +1561,14 @@ struct npc_mcam_free_entry_req { u8 all; /* If all entries allocated to this PFVF to be freed */ }; =20 +struct mcam_entry_mdata { + u64 *kw; + u64 *kw_mask; + u64 *action; + u64 *vtag_action; + u8 max_kw; +}; + struct mcam_entry { #define NPC_MAX_KWS_IN_KEY 8 /* Number of keywords in max keywidth */ u64 kw[NPC_MAX_KWS_IN_KEY]; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drive= rs/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index 508233876fc1..d73e447bedca 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -903,11 +903,12 @@ static int npc_check_unsupported_flows(struct rvu *rv= u, u64 features, u8 intf) * dont care. */ void npc_update_entry(struct rvu *rvu, enum key_fields type, - struct mcam_entry *entry, u64 val_lo, + struct mcam_entry_mdata *mdata, u64 val_lo, u64 val_hi, u64 mask_lo, u64 mask_hi, u8 intf) { struct npc_mcam *mcam =3D &rvu->hw->mcam; struct mcam_entry dummy =3D { {0} }; + u64 *kw, *kw_mask, *val, *mask; struct npc_key_field *field; u64 kw1, kw2, kw3; int i, max_kw; @@ -920,10 +921,9 @@ void npc_update_entry(struct rvu *rvu, enum key_fields= type, if (!field->nr_kws) return; =20 - if (is_cn20k(rvu->pdev)) - max_kw =3D NPC_MAX_KWS_IN_KEY; - else - max_kw =3D NPC_MAX_KWS_IN_KEY - 1; + max_kw =3D NPC_MAX_KWS_IN_KEY; + kw =3D dummy.kw; + kw_mask =3D dummy.kw_mask; =20 for (i =3D 0; i < max_kw; i++) { if (!field->kw_mask[i]) @@ -932,10 +932,10 @@ void npc_update_entry(struct rvu *rvu, enum key_field= s type, shift =3D __ffs64(field->kw_mask[i]); /* update entry value */ kw1 =3D (val_lo << shift) & field->kw_mask[i]; - dummy.kw[i] =3D kw1; + kw[i] =3D kw1; /* update entry mask */ kw1 =3D (mask_lo << shift) & field->kw_mask[i]; - dummy.kw_mask[i] =3D kw1; + kw_mask[i] =3D kw1; =20 if (field->nr_kws =3D=3D 1) break; @@ -945,12 +945,12 @@ void npc_update_entry(struct rvu *rvu, enum key_field= s type, kw2 =3D shift ? val_lo >> (64 - shift) : 0; kw2 |=3D (val_hi << shift); kw2 &=3D field->kw_mask[i + 1]; - dummy.kw[i + 1] =3D kw2; + kw[i + 1] =3D kw2; /* update entry mask */ kw2 =3D shift ? mask_lo >> (64 - shift) : 0; kw2 |=3D (mask_hi << shift); kw2 &=3D field->kw_mask[i + 1]; - dummy.kw_mask[i + 1] =3D kw2; + kw_mask[i + 1] =3D kw2; break; } /* place remaining bits of key value in kw[x + 1], kw[x + 2] */ @@ -961,34 +961,40 @@ void npc_update_entry(struct rvu *rvu, enum key_field= s type, kw2 &=3D field->kw_mask[i + 1]; kw3 =3D shift ? val_hi >> (64 - shift) : 0; kw3 &=3D field->kw_mask[i + 2]; - dummy.kw[i + 1] =3D kw2; - dummy.kw[i + 2] =3D kw3; + kw[i + 1] =3D kw2; + kw[i + 2] =3D kw3; /* update entry mask */ kw2 =3D shift ? mask_lo >> (64 - shift) : 0; kw2 |=3D (mask_hi << shift); kw2 &=3D field->kw_mask[i + 1]; kw3 =3D shift ? mask_hi >> (64 - shift) : 0; kw3 &=3D field->kw_mask[i + 2]; - dummy.kw_mask[i + 1] =3D kw2; - dummy.kw_mask[i + 2] =3D kw3; + kw_mask[i + 1] =3D kw2; + kw_mask[i + 2] =3D kw3; break; } } /* dummy is ready with values and masks for given key * field now clear and update input entry with those */ - for (i =3D 0; i < max_kw; i++) { + + val =3D mdata->kw; + mask =3D mdata->kw_mask; + + for (i =3D 0; i < max_kw; i++, val++, mask++) { if (!field->kw_mask[i]) continue; - entry->kw[i] &=3D ~field->kw_mask[i]; - entry->kw_mask[i] &=3D ~field->kw_mask[i]; =20 - entry->kw[i] |=3D dummy.kw[i]; - entry->kw_mask[i] |=3D dummy.kw_mask[i]; + *val &=3D ~field->kw_mask[i]; + *mask &=3D ~field->kw_mask[i]; + + *val |=3D kw[i]; + *mask |=3D kw_mask[i]; } } =20 -static void npc_update_ipv6_flow(struct rvu *rvu, struct mcam_entry *entry, +static void npc_update_ipv6_flow(struct rvu *rvu, + struct mcam_entry_mdata *mdata, u64 features, struct flow_msg *pkt, struct flow_msg *mask, struct rvu_npc_mcam_rule *output, u8 intf) @@ -1014,7 +1020,7 @@ static void npc_update_ipv6_flow(struct rvu *rvu, str= uct mcam_entry *entry, val_hi =3D (u64)src_ip[0] << 32 | src_ip[1]; val_lo =3D (u64)src_ip[2] << 32 | src_ip[3]; =20 - npc_update_entry(rvu, NPC_SIP_IPV6, entry, val_lo, val_hi, + npc_update_entry(rvu, NPC_SIP_IPV6, mdata, val_lo, val_hi, mask_lo, mask_hi, intf); memcpy(opkt->ip6src, pkt->ip6src, sizeof(opkt->ip6src)); memcpy(omask->ip6src, mask->ip6src, sizeof(omask->ip6src)); @@ -1028,14 +1034,15 @@ static void npc_update_ipv6_flow(struct rvu *rvu, s= truct mcam_entry *entry, val_hi =3D (u64)dst_ip[0] << 32 | dst_ip[1]; val_lo =3D (u64)dst_ip[2] << 32 | dst_ip[3]; =20 - npc_update_entry(rvu, NPC_DIP_IPV6, entry, val_lo, val_hi, + npc_update_entry(rvu, NPC_DIP_IPV6, mdata, val_lo, val_hi, mask_lo, mask_hi, intf); memcpy(opkt->ip6dst, pkt->ip6dst, sizeof(opkt->ip6dst)); memcpy(omask->ip6dst, mask->ip6dst, sizeof(omask->ip6dst)); } } =20 -static void npc_update_vlan_features(struct rvu *rvu, struct mcam_entry *e= ntry, +static void npc_update_vlan_features(struct rvu *rvu, + struct mcam_entry_mdata *mdata, u64 features, u8 intf) { bool ctag =3D !!(features & BIT_ULL(NPC_VLAN_ETYPE_CTAG)); @@ -1044,20 +1051,20 @@ static void npc_update_vlan_features(struct rvu *rv= u, struct mcam_entry *entry, =20 /* If only VLAN id is given then always match outer VLAN id */ if (vid && !ctag && !stag) { - npc_update_entry(rvu, NPC_LB, entry, + npc_update_entry(rvu, NPC_LB, mdata, NPC_LT_LB_STAG_QINQ | NPC_LT_LB_CTAG, 0, NPC_LT_LB_STAG_QINQ & NPC_LT_LB_CTAG, 0, intf); return; } if (ctag) - npc_update_entry(rvu, NPC_LB, entry, NPC_LT_LB_CTAG, 0, + npc_update_entry(rvu, NPC_LB, mdata, NPC_LT_LB_CTAG, 0, ~0ULL, 0, intf); if (stag) - npc_update_entry(rvu, NPC_LB, entry, NPC_LT_LB_STAG_QINQ, 0, + npc_update_entry(rvu, NPC_LB, mdata, NPC_LT_LB_STAG_QINQ, 0, ~0ULL, 0, intf); } =20 -static void npc_update_flow(struct rvu *rvu, struct mcam_entry *entry, +static void npc_update_flow(struct rvu *rvu, struct mcam_entry_mdata *mdat= a, u64 features, struct flow_msg *pkt, struct flow_msg *mask, struct rvu_npc_mcam_rule *output, u8 intf, @@ -1075,39 +1082,39 @@ static void npc_update_flow(struct rvu *rvu, struct= mcam_entry *entry, =20 /* For tcp/udp/sctp LTYPE should be present in entry */ if (features & BIT_ULL(NPC_IPPROTO_TCP)) - npc_update_entry(rvu, NPC_LD, entry, NPC_LT_LD_TCP, + npc_update_entry(rvu, NPC_LD, mdata, NPC_LT_LD_TCP, 0, ~0ULL, 0, intf); if (features & BIT_ULL(NPC_IPPROTO_UDP)) - npc_update_entry(rvu, NPC_LD, entry, NPC_LT_LD_UDP, + npc_update_entry(rvu, NPC_LD, mdata, NPC_LT_LD_UDP, 0, ~0ULL, 0, intf); if (features & BIT_ULL(NPC_IPPROTO_SCTP)) - npc_update_entry(rvu, NPC_LD, entry, NPC_LT_LD_SCTP, + npc_update_entry(rvu, NPC_LD, mdata, NPC_LT_LD_SCTP, 0, ~0ULL, 0, intf); if (features & BIT_ULL(NPC_IPPROTO_ICMP)) - npc_update_entry(rvu, NPC_LD, entry, NPC_LT_LD_ICMP, + npc_update_entry(rvu, NPC_LD, mdata, NPC_LT_LD_ICMP, 0, ~0ULL, 0, intf); if (features & BIT_ULL(NPC_IPPROTO_ICMP6)) - npc_update_entry(rvu, NPC_LD, entry, NPC_LT_LD_ICMP6, + npc_update_entry(rvu, NPC_LD, mdata, NPC_LT_LD_ICMP6, 0, ~0ULL, 0, intf); =20 /* For AH, LTYPE should be present in entry */ if (features & BIT_ULL(NPC_IPPROTO_AH)) - npc_update_entry(rvu, NPC_LD, entry, NPC_LT_LD_AH, + npc_update_entry(rvu, NPC_LD, mdata, NPC_LT_LD_AH, 0, ~0ULL, 0, intf); /* For ESP, LTYPE should be present in entry */ if (features & BIT_ULL(NPC_IPPROTO_ESP)) - npc_update_entry(rvu, NPC_LE, entry, NPC_LT_LE_ESP, + npc_update_entry(rvu, NPC_LE, mdata, NPC_LT_LE_ESP, 0, ~0ULL, 0, intf); =20 if (features & BIT_ULL(NPC_LXMB)) { output->lxmb =3D is_broadcast_ether_addr(pkt->dmac) ? 2 : 1; - npc_update_entry(rvu, NPC_LXMB, entry, output->lxmb, 0, + npc_update_entry(rvu, NPC_LXMB, mdata, output->lxmb, 0, output->lxmb, 0, intf); } #define NPC_WRITE_FLOW(field, member, val_lo, val_hi, mask_lo, mask_hi) = \ do { \ if (features & BIT_ULL((field))) { \ - npc_update_entry(rvu, (field), entry, (val_lo), (val_hi), \ + npc_update_entry(rvu, (field), mdata, (val_lo), (val_hi), \ (mask_lo), (mask_hi), intf); \ memcpy(&opkt->member, &pkt->member, sizeof(pkt->member)); \ memcpy(&omask->member, &mask->member, sizeof(mask->member)); \ @@ -1195,10 +1202,10 @@ do { \ =20 NPC_WRITE_FLOW(NPC_IPFRAG_IPV6, next_header, pkt->next_header, 0, mask->next_header, 0); - npc_update_ipv6_flow(rvu, entry, features, pkt, mask, output, intf); - npc_update_vlan_features(rvu, entry, features, intf); + npc_update_ipv6_flow(rvu, mdata, features, pkt, mask, output, intf); + npc_update_vlan_features(rvu, mdata, features, intf); =20 - npc_update_field_hash(rvu, intf, entry, blkaddr, features, + npc_update_field_hash(rvu, intf, mdata, blkaddr, features, pkt, mask, opkt, omask); } =20 @@ -1286,8 +1293,20 @@ static int npc_mcast_update_action_index(struct rvu = *rvu, struct npc_install_flo return 0; } =20 +static void +npc_populate_mcam_mdata(struct rvu *rvu, + struct mcam_entry_mdata *mdata, + struct mcam_entry *entry) +{ + mdata->kw =3D entry->kw; + mdata->kw_mask =3D entry->kw_mask; + mdata->action =3D &entry->action; + mdata->vtag_action =3D &entry->vtag_action; + mdata->max_kw =3D NPC_MAX_KWS_IN_KEY; +} + static int npc_update_rx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf, - struct mcam_entry *entry, + struct mcam_entry_mdata *mdata, struct npc_install_flow_req *req, u16 target, bool pf_set_vfs_mac) { @@ -1298,7 +1317,7 @@ static int npc_update_rx_entry(struct rvu *rvu, struc= t rvu_pfvf *pfvf, if (rswitch->mode =3D=3D DEVLINK_ESWITCH_MODE_SWITCHDEV && pf_set_vfs_mac) req->chan_mask =3D 0x0; /* Do not care channel */ =20 - npc_update_entry(rvu, NPC_CHAN, entry, req->channel, 0, req->chan_mask, + npc_update_entry(rvu, NPC_CHAN, mdata, req->channel, 0, req->chan_mask, 0, NIX_INTF_RX); =20 *(u64 *)&action =3D 0x00; @@ -1330,12 +1349,12 @@ static int npc_update_rx_entry(struct rvu *rvu, str= uct rvu_pfvf *pfvf, action.match_id =3D req->match_id; } =20 - entry->action =3D *(u64 *)&action; + *mdata->action =3D *(u64 *)&action; =20 /* VTAG0 starts at 0th byte of LID_B. * VTAG1 starts at 4th byte of LID_B. */ - entry->vtag_action =3D FIELD_PREP(RX_VTAG0_VALID_BIT, req->vtag0_valid) | + *mdata->vtag_action =3D FIELD_PREP(RX_VTAG0_VALID_BIT, req->vtag0_valid) | FIELD_PREP(RX_VTAG0_TYPE_MASK, req->vtag0_type) | FIELD_PREP(RX_VTAG0_LID_MASK, NPC_LID_LB) | FIELD_PREP(RX_VTAG0_RELPTR_MASK, 0) | @@ -1348,7 +1367,7 @@ static int npc_update_rx_entry(struct rvu *rvu, struc= t rvu_pfvf *pfvf, } =20 static int npc_update_tx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf, - struct mcam_entry *entry, + struct mcam_entry_mdata *mdata, struct npc_install_flow_req *req, u16 target) { struct nix_tx_action action; @@ -1361,7 +1380,7 @@ static int npc_update_tx_entry(struct rvu *rvu, struc= t rvu_pfvf *pfvf, if (is_pffunc_af(req->hdr.pcifunc)) mask =3D 0; =20 - npc_update_entry(rvu, NPC_PF_FUNC, entry, (__force u16)htons(target), + npc_update_entry(rvu, NPC_PF_FUNC, mdata, (__force u16)htons(target), 0, mask, 0, NIX_INTF_TX); =20 *(u64 *)&action =3D 0x00; @@ -1374,12 +1393,12 @@ static int npc_update_tx_entry(struct rvu *rvu, str= uct rvu_pfvf *pfvf, =20 action.match_id =3D req->match_id; =20 - entry->action =3D *(u64 *)&action; + *mdata->action =3D *(u64 *)&action; =20 /* VTAG0 starts at 0th byte of LID_B. * VTAG1 starts at 4th byte of LID_B. */ - entry->vtag_action =3D FIELD_PREP(TX_VTAG0_DEF_MASK, req->vtag0_def) | + *mdata->vtag_action =3D FIELD_PREP(TX_VTAG0_DEF_MASK, req->vtag0_def) | FIELD_PREP(TX_VTAG0_OP_MASK, req->vtag0_op) | FIELD_PREP(TX_VTAG0_LID_MASK, NPC_LID_LA) | FIELD_PREP(TX_VTAG0_RELPTR_MASK, 20) | @@ -1401,6 +1420,7 @@ static int npc_install_flow(struct rvu *rvu, int blka= ddr, u16 target, u64 features, installed_features, missing_features =3D 0; struct npc_mcam_write_entry_req write_req =3D { 0 }; struct npc_mcam *mcam =3D &rvu->hw->mcam; + struct mcam_entry_mdata mdata =3D { }; struct rvu_npc_mcam_rule dummy =3D { 0 }; struct rvu_npc_mcam_rule *rule; u16 owner =3D req->hdr.pcifunc; @@ -1415,15 +1435,19 @@ static int npc_install_flow(struct rvu *rvu, int bl= kaddr, u16 target, entry =3D &write_req.entry_data; entry_index =3D req->entry; =20 - npc_update_flow(rvu, entry, features, &req->packet, &req->mask, &dummy, + npc_populate_mcam_mdata(rvu, &mdata, + &write_req.entry_data); + + npc_update_flow(rvu, &mdata, features, &req->packet, &req->mask, &dummy, req->intf, blkaddr); =20 if (is_npc_intf_rx(req->intf)) { - err =3D npc_update_rx_entry(rvu, pfvf, entry, req, target, pf_set_vfs_ma= c); + err =3D npc_update_rx_entry(rvu, pfvf, &mdata, req, target, + pf_set_vfs_mac); if (err) return err; } else { - err =3D npc_update_tx_entry(rvu, pfvf, entry, req, target); + err =3D npc_update_tx_entry(rvu, pfvf, &mdata, req, target); if (err) return err; } @@ -1443,7 +1467,7 @@ static int npc_install_flow(struct rvu *rvu, int blka= ddr, u16 target, missing_features =3D (def_ucast_rule->features ^ features) & def_ucast_rule->features; if (missing_features) - npc_update_flow(rvu, entry, missing_features, + npc_update_flow(rvu, &mdata, missing_features, &def_ucast_rule->packet, &def_ucast_rule->mask, &dummy, req->intf, @@ -1759,12 +1783,17 @@ static int npc_update_dmac_value(struct rvu *rvu, i= nt npcblkaddr, struct rvu_pfvf *pfvf) { struct npc_mcam_write_entry_req write_req =3D { 0 }; - struct mcam_entry *entry =3D &write_req.entry_data; struct npc_mcam *mcam =3D &rvu->hw->mcam; + struct mcam_entry_mdata mdata =3D { }; + struct mcam_entry *entry; u8 intf, enable, hw_prio; struct msg_rsp rsp; int err; =20 + entry =3D &write_req.entry_data; + + npc_populate_mcam_mdata(rvu, &mdata, entry); + ether_addr_copy(rule->packet.dmac, pfvf->mac_addr); =20 if (is_cn20k(rvu->pdev)) @@ -1775,7 +1804,7 @@ static int npc_update_dmac_value(struct rvu *rvu, int= npcblkaddr, npc_read_mcam_entry(rvu, mcam, npcblkaddr, rule->entry, entry, &intf, &enable); =20 - npc_update_entry(rvu, NPC_DMAC, entry, + npc_update_entry(rvu, NPC_DMAC, &mdata, ether_addr_to_u64(pfvf->mac_addr), 0, 0xffffffffffffull, 0, intf); =20 @@ -1876,6 +1905,7 @@ int npc_install_mcam_drop_rule(struct rvu *rvu, int m= cam_idx, u16 *counter_idx, struct npc_mcam_alloc_counter_rsp cntr_rsp =3D { 0 }; struct npc_mcam_write_entry_req req =3D { 0 }; struct npc_mcam *mcam =3D &rvu->hw->mcam; + struct mcam_entry_mdata mdata =3D { }; struct rvu_npc_mcam_rule *rule; struct msg_rsp rsp; bool enabled; @@ -1931,12 +1961,15 @@ int npc_install_mcam_drop_rule(struct rvu *rvu, int= mcam_idx, u16 *counter_idx, } *counter_idx =3D cntr_rsp.cntr; =20 + npc_populate_mcam_mdata(rvu, &mdata, + &req.entry_data); + /* Fill in fields for this mcam entry */ - npc_update_entry(rvu, NPC_EXACT_RESULT, &req.entry_data, exact_val, 0, + npc_update_entry(rvu, NPC_EXACT_RESULT, &mdata, exact_val, 0, exact_mask, 0, NIX_INTF_RX); - npc_update_entry(rvu, NPC_CHAN, &req.entry_data, chan_val, 0, + npc_update_entry(rvu, NPC_CHAN, &mdata, chan_val, 0, chan_mask, 0, NIX_INTF_RX); - npc_update_entry(rvu, NPC_LXMB, &req.entry_data, bcast_mcast_val, 0, + npc_update_entry(rvu, NPC_LXMB, &mdata, bcast_mcast_val, 0, bcast_mcast_mask, 0, NIX_INTF_RX); =20 req.intf =3D NIX_INTF_RX; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h b/drive= rs/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h index 3f5c9042d10e..442287ee7baa 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h @@ -15,7 +15,7 @@ #define NPC_LDATA_EN BIT_ULL(7) =20 void npc_update_entry(struct rvu *rvu, enum key_fields type, - struct mcam_entry *entry, u64 val_lo, + struct mcam_entry_mdata *mdata, u64 val_lo, u64 val_hi, u64 mask_lo, u64 mask_hi, u8 intf); =20 #endif /* RVU_NPC_FS_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c b/dri= vers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c index 5ae046c93a82..4fba501f4c2b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c @@ -282,7 +282,7 @@ void npc_program_mkex_hash(struct rvu *rvu, int blkaddr) } =20 void npc_update_field_hash(struct rvu *rvu, u8 intf, - struct mcam_entry *entry, + struct mcam_entry_mdata *mdata, int blkaddr, u64 features, struct flow_msg *pkt, @@ -293,9 +293,10 @@ void npc_update_field_hash(struct rvu *rvu, u8 intf, struct npc_mcam_kex_hash *mkex_hash =3D rvu->kpu.mkex_hash; struct npc_get_field_hash_info_req req; struct npc_get_field_hash_info_rsp rsp; + u8 hash_idx, lid, ltype, ltype_mask; u64 ldata[2], cfg; u32 field_hash; - u8 hash_idx; + bool en; =20 if (is_cn20k(rvu->pdev)) return; @@ -310,60 +311,60 @@ void npc_update_field_hash(struct rvu *rvu, u8 intf, =20 for (hash_idx =3D 0; hash_idx < NPC_MAX_HASH; hash_idx++) { cfg =3D rvu_read64(rvu, blkaddr, NPC_AF_INTFX_HASHX_CFG(intf, hash_idx)); - if ((cfg & BIT_ULL(11)) && (cfg & BIT_ULL(12))) { - u8 lid =3D (cfg & GENMASK_ULL(10, 8)) >> 8; - u8 ltype =3D (cfg & GENMASK_ULL(7, 4)) >> 4; - u8 ltype_mask =3D cfg & GENMASK_ULL(3, 0); - - if (mkex_hash->lid_lt_ld_hash_en[intf][lid][ltype][hash_idx]) { - switch (ltype & ltype_mask) { - /* If hash extract enabled is supported for IPv6 then - * 128 bit IPv6 source and destination addressed - * is hashed to 32 bit value. - */ - case NPC_LT_LC_IP6: - /* ld[0] =3D=3D hash_idx[0] =3D=3D Source IPv6 - * ld[1] =3D=3D hash_idx[1] =3D=3D Destination IPv6 - */ - if ((features & BIT_ULL(NPC_SIP_IPV6)) && !hash_idx) { - u32 src_ip[IPV6_WORDS]; - - be32_to_cpu_array(src_ip, pkt->ip6src, IPV6_WORDS); - ldata[1] =3D (u64)src_ip[0] << 32 | src_ip[1]; - ldata[0] =3D (u64)src_ip[2] << 32 | src_ip[3]; - field_hash =3D npc_field_hash_calc(ldata, - rsp, - intf, - hash_idx); - npc_update_entry(rvu, NPC_SIP_IPV6, entry, - field_hash, 0, - GENMASK(31, 0), 0, intf); - memcpy(&opkt->ip6src, &pkt->ip6src, - sizeof(pkt->ip6src)); - memcpy(&omask->ip6src, &mask->ip6src, - sizeof(mask->ip6src)); - } else if ((features & BIT_ULL(NPC_DIP_IPV6)) && hash_idx) { - u32 dst_ip[IPV6_WORDS]; - - be32_to_cpu_array(dst_ip, pkt->ip6dst, IPV6_WORDS); - ldata[1] =3D (u64)dst_ip[0] << 32 | dst_ip[1]; - ldata[0] =3D (u64)dst_ip[2] << 32 | dst_ip[3]; - field_hash =3D npc_field_hash_calc(ldata, - rsp, - intf, - hash_idx); - npc_update_entry(rvu, NPC_DIP_IPV6, entry, - field_hash, 0, - GENMASK(31, 0), 0, intf); - memcpy(&opkt->ip6dst, &pkt->ip6dst, - sizeof(pkt->ip6dst)); - memcpy(&omask->ip6dst, &mask->ip6dst, - sizeof(mask->ip6dst)); - } - - break; - } - } + en =3D !!(cfg & BIT_ULL(11)) && (cfg & BIT_ULL(12)); + if (!en) + continue; + + lid =3D (cfg & GENMASK_ULL(10, 8)) >> 8; + ltype =3D (cfg & GENMASK_ULL(7, 4)) >> 4; + ltype_mask =3D cfg & GENMASK_ULL(3, 0); + + if (!mkex_hash->lid_lt_ld_hash_en[intf][lid][ltype][hash_idx]) + continue; + + /* If hash extract enabled is supported for IPv6 then + * 128 bit IPv6 source and destination addressed + * is hashed to 32 bit value. + */ + if ((ltype & ltype_mask) !=3D NPC_LT_LC_IP6) + continue; + + /* ld[0] =3D=3D hash_idx[0] =3D=3D Source IPv6 + * ld[1] =3D=3D hash_idx[1] =3D=3D Destination IPv6 + */ + if ((features & BIT_ULL(NPC_SIP_IPV6)) && !hash_idx) { + u32 src_ip[IPV6_WORDS]; + + be32_to_cpu_array(src_ip, pkt->ip6src, IPV6_WORDS); + ldata[1] =3D (u64)src_ip[0] << 32 | src_ip[1]; + ldata[0] =3D (u64)src_ip[2] << 32 | src_ip[3]; + field_hash =3D npc_field_hash_calc(ldata, rsp, intf, + hash_idx); + npc_update_entry(rvu, NPC_SIP_IPV6, mdata, field_hash, + 0, GENMASK(31, 0), 0, intf); + memcpy(&opkt->ip6src, &pkt->ip6src, + sizeof(pkt->ip6src)); + memcpy(&omask->ip6src, &mask->ip6src, + sizeof(mask->ip6src)); + continue; + } + + if ((features & BIT_ULL(NPC_DIP_IPV6)) && hash_idx) { + u32 dst_ip[IPV6_WORDS]; + + be32_to_cpu_array(dst_ip, pkt->ip6dst, IPV6_WORDS); + ldata[1] =3D (u64)dst_ip[0] << 32 | dst_ip[1]; + ldata[0] =3D (u64)dst_ip[2] << 32 | dst_ip[3]; + field_hash =3D npc_field_hash_calc(ldata, rsp, intf, + hash_idx); + npc_update_entry(rvu, NPC_DIP_IPV6, mdata, + field_hash, 0, GENMASK(31, 0), + 0, intf); + memcpy(&opkt->ip6dst, &pkt->ip6dst, + sizeof(pkt->ip6dst)); + memcpy(&omask->ip6dst, &mask->ip6dst, + sizeof(mask->ip6dst)); + continue; } } } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.h b/dri= vers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.h index cb25cf478f1f..4cbcae69b6d3 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.h @@ -53,7 +53,7 @@ struct npc_mcam_kex_hash { } __packed; =20 void npc_update_field_hash(struct rvu *rvu, u8 intf, - struct mcam_entry *entry, + struct mcam_entry_mdata *mdata, int blkaddr, u64 features, struct flow_msg *pkt, --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BE91030FF36; Mon, 2 Feb 2026 07:46:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018418; cv=none; b=Mm1xD20GO5iwSsy15j8bDiR73wD08NVtwCh3iE1uEQhc0xIatzzfLtHTrqTVTh1sgfe6j0rvb7e6Er3LRyrTT/8HvAlosw/RYDyHQjroVClfv9m+nUvOzwK7wpL8rwxfCYREt+xvfXDupzWqN2lZmLX7xVLC04g7m6Ab8UZBteQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018418; c=relaxed/simple; bh=nAcGjJYA/Gb0JAxnnetmzIe1nEl4UcPrOlXF873x0Qw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ab3dyicS+V4k2yZNdEs3gnvtkeGIdhCxKHKsfXT7hG8BuX3atG+xdrUfS4Y7PjrhebSVLjt+XIA7l2+030s4hugOonwk8VaLbfKYW7VpjfC8Cmhl6BMUQnbYzAKwDtnnpKyO78dQnj+OD26mKB2TR85i/n104vlE8tsjsRNwWkg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=EJVQAOU1; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="EJVQAOU1" Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 611MNPCP2576737; Sun, 1 Feb 2026 23:46:44 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=+ e9jksNjArueL0NMBH91BmHAVF97f5isX0eUcJXLr+w=; b=EJVQAOU1athM9DGdM n7aEwZcbrqbygYWEzImDKGeTFI/dre3owuHYfjDjq50Hm51OKRCUhKjEGqWWpTyB rw43ZBBhkvk9Bb4pAw+tWnkHv6UC2kXV+QBJ7B9E83DJhs1xN1Pz54oYttgaATSk P6w9ByedVYEHWbeJwlMAnhHfFmmacc/UJ+K6VGB1f8/cCxxCCAMSUTTwHjx9CgXw J2CUHSBWBYtExEexV9HrHPNHeOvfn+tKi4C0Zj9Q3XJnDVQhFwXWzshrW5JJQIYu +bMyh+iQXCSrOUEhVSRXcAasZQlxUei9UKT2FMR+Dx6vi+qEtUJGHnZ4BPSw95E0 uWuEg== Received: from dc6wp-exch02.marvell.com ([4.21.29.225]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4c28pe188t-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:44 -0800 (PST) Received: from DC6WP-EXCH02.marvell.com (10.76.176.209) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:47:08 -0800 Received: from maili.marvell.com (10.69.176.80) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:47:08 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 5E6D45B6946; Sun, 1 Feb 2026 23:46:39 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , Suman Ghosh , Ratheesh Kannoth Subject: [PATCH net-next v8 08/13] octeontx2-af: npc: cn20k: Add new mailboxes for CN20K silicon Date: Mon, 2 Feb 2026 13:16:02 +0530 Message-ID: <20260202074607.2535569-9-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: -LMrOLD3o3eJ7hdfHm_uklzjmYtYpa8N X-Authority-Analysis: v=2.4 cv=Y4/1cxeN c=1 sm=1 tr=0 ts=69805664 cx=c_pps a=gIfcoYsirJbf48DBMSPrZA==:117 a=gIfcoYsirJbf48DBMSPrZA==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=mVer86KWNu4qBHhe280A:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfXz120qdX5JFZr WQ1nLK9NSk9nE3kRRdUhVG36oowh2E1hq6Cz+mLs3pj2SAoL4wclh26mj7U7xFVxNmz/y0Kck4o JcyaBhThn6pU+LusunovEYbreovA7GNnGZE30ZjzVmPYZSTUQ7owWkkwdJztNI6m7ZQ8eN0VHoW zMFmIbL4kohGnJm952JqczYRiLYtyp20yS6v1PkAIcSbA9kRleLCcD8/3vAOdIolcAch6yjtUiG 2Tb8bK7UJdhDHpcaXD3Pj8iH7uf7HScnm8siy9oXu9vVxpOft5nUSQ4awB5+GlQ7Zcp/7O2ttwN 6w4iRWwaxcroDhubteJKtBUEpBK3Tv0unLPN0BjuwvMAsxvqqiKzWik+oni/MaEal0qixAUVUek RfEdbnnmJrBgzKCTMZj6K5lumog6f+vHHdLjtz40WxATdb+qdYceXwQSgLbvPG+pvJvkCzMwrme LsPU2ajTmbow9nUshaA== X-Proofpoint-GUID: -LMrOLD3o3eJ7hdfHm_uklzjmYtYpa8N X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" From: Suman Ghosh Due to new requirements in CN20K, the existing `struct mcam_entry` needed to be updated. Previously, it contained two arrays, `kw` and `kw_mask`, each of size 7 (keyword size). To support CN20K requirements, the size of these arrays has been increased from 7 to 8. However, this change breaks backward compatibility because it alters the structure layout. Therefore, we decided to use separate mailboxes that use the updated `struct mcam_entry`. This patch identifies such mailboxes and adds new ones specifically for CN20K. New mailboxes added: 1. `NPC_CN20K_MCAM_WRITE_ENTRY` 2. `NPC_CN20K_MCAM_ALLOC_AND_WRITE_ENTRY` 3. `NPC_CN20K_MCAM_READ_ENTRY` 4. `NPC_CN20K_MCAM_READ_BASE_RULE` Signed-off-by: Suman Ghosh Signed-off-by: Ratheesh Kannoth --- .../marvell/octeontx2/af/cn20k/mbox_init.c | 17 ++ .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 188 +++++++++++++- .../ethernet/marvell/octeontx2/af/cn20k/npc.h | 7 +- .../ethernet/marvell/octeontx2/af/cn20k/reg.h | 7 + .../net/ethernet/marvell/octeontx2/af/mbox.h | 58 ++++- .../net/ethernet/marvell/octeontx2/af/npc.h | 1 + .../net/ethernet/marvell/octeontx2/af/rvu.c | 62 ++++- .../net/ethernet/marvell/octeontx2/af/rvu.h | 3 +- .../marvell/octeontx2/af/rvu_debugfs.c | 32 ++- .../ethernet/marvell/octeontx2/af/rvu_npc.c | 62 ++++- .../marvell/octeontx2/af/rvu_npc_fs.c | 235 +++++++++++++----- 11 files changed, 571 insertions(+), 101 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/mbox_init.c b/= drivers/net/ethernet/marvell/octeontx2/af/cn20k/mbox_init.c index bd3aab7770dd..71401dec0d77 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/mbox_init.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/mbox_init.c @@ -397,6 +397,12 @@ int rvu_alloc_cint_qint_mem(struct rvu *rvu, struct rv= u_pfvf *pfvf, if (is_rvu_otx2(rvu) || is_cn20k(rvu->pdev)) return 0; =20 + /* sanity check */ + cfg =3D rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_NIXX_CFG(0) | + (RVU_AFPF << 16)); + if (!cfg) + return 0; + ctx_cfg =3D rvu_read64(rvu, blkaddr, NIX_AF_CONST3); /* Alloc memory for CQINT's HW contexts */ cfg =3D rvu_read64(rvu, blkaddr, NIX_AF_CONST2); @@ -420,5 +426,16 @@ int rvu_alloc_cint_qint_mem(struct rvu *rvu, struct rv= u_pfvf *pfvf, rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_BASE(nixlf), (u64)pfvf->nix_qints_ctx->iova); =20 + rvu_write64(rvu, BLKADDR_NIX0, RVU_AF_BAR2_SEL, RVU_AF_BAR2_PFID); + rvu_write64(rvu, BLKADDR_NIX0, + AF_BAR2_ALIASX(0, NIX_GINT_INT_W1S), ALTAF_RDY); + /* wait for ack */ + err =3D rvu_poll_reg(rvu, BLKADDR_NIX0, + AF_BAR2_ALIASX(0, NIX_GINT_INT), ALTAF_RDY, true); + if (err) + rvu->altaf_ready =3D false; + else + rvu->altaf_ready =3D true; + return 0; } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.c index 8f300e421a33..f1d9705fa872 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c @@ -628,9 +628,13 @@ npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkadd= r, int bank, int index) NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, bank, 1), 0); rvu_write64(rvu, blkaddr, NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, bank, 0), 0); + + /* Clear corresponding stats register */ + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(index, bank), 0); } =20 -static void npc_cn20k_get_keyword(struct mcam_entry *entry, int idx, +static void npc_cn20k_get_keyword(struct cn20k_mcam_entry *entry, int idx, u64 *cam0, u64 *cam1) { u64 kw_mask; @@ -670,7 +674,7 @@ static void npc_cn20k_get_keyword(struct mcam_entry *en= try, int idx, */ static void npc_cn20k_config_kw_x2(struct rvu *rvu, struct npc_mcam *mcam, int blkaddr, int index, u8 intf, - struct mcam_entry *entry, + struct cn20k_mcam_entry *entry, int bank, u8 kw_type, int kw) { u64 intf_ext =3D 0, intf_ext_mask =3D 0; @@ -742,7 +746,8 @@ static void npc_cn20k_config_kw_x2(struct rvu *rvu, str= uct npc_mcam *mcam, =20 static void npc_cn20k_config_kw_x4(struct rvu *rvu, struct npc_mcam *mcam, int blkaddr, int index, u8 intf, - struct mcam_entry *entry, u8 kw_type) + struct cn20k_mcam_entry *entry, + u8 kw_type) { int kw =3D 0, bank; =20 @@ -780,9 +785,9 @@ npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blkadd= r, int mcam_idx, } } =20 -void -npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index, u8 in= tf, - struct mcam_entry *entry, bool enable, u8 hw_prio) +void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index, + u8 intf, struct cn20k_mcam_entry *entry, + bool enable, u8 hw_prio) { struct npc_mcam *mcam =3D &rvu->hw->mcam; int mcam_idx =3D index % mcam->banksize; @@ -897,7 +902,7 @@ void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blk= addr, u16 src, u16 dest) } } =20 -static void npc_cn20k_fill_entryword(struct mcam_entry *entry, int idx, +static void npc_cn20k_fill_entryword(struct cn20k_mcam_entry *entry, int i= dx, u64 cam0, u64 cam1) { entry->kw[idx] =3D cam1; @@ -905,8 +910,8 @@ static void npc_cn20k_fill_entryword(struct mcam_entry = *entry, int idx, } =20 void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index, - struct mcam_entry *entry, u8 *intf, u8 *ena, - u8 *hw_prio) + struct cn20k_mcam_entry *entry, + u8 *intf, u8 *ena, u8 *hw_prio) { struct npc_mcam *mcam =3D &rvu->hw->mcam; u64 cam0, cam1, bank_cfg, cfg; @@ -1025,6 +1030,171 @@ void npc_cn20k_read_mcam_entry(struct rvu *rvu, int= blkaddr, u16 index, entry->vtag_action =3D cfg; } =20 +int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struct rvu *rvu, + struct npc_cn20k_mcam_write_entry_req *req, + struct msg_rsp *rsp) +{ + struct rvu_pfvf *pfvf =3D rvu_get_pfvf(rvu, req->hdr.pcifunc); + struct npc_mcam *mcam =3D &rvu->hw->mcam; + u16 pcifunc =3D req->hdr.pcifunc; + int blkaddr, rc; + u8 nix_intf; + + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) + return NPC_MCAM_INVALID_REQ; + + mutex_lock(&mcam->lock); + rc =3D npc_mcam_verify_entry(mcam, pcifunc, req->entry); + if (rc) + goto exit; + + if (!is_npc_interface_valid(rvu, req->intf)) { + rc =3D NPC_MCAM_INVALID_REQ; + goto exit; + } + + if (is_npc_intf_tx(req->intf)) + nix_intf =3D pfvf->nix_tx_intf; + else + nix_intf =3D pfvf->nix_rx_intf; + + /* For AF installed rules, the nix_intf should be set to target NIX */ + if (is_pffunc_af(req->hdr.pcifunc)) + nix_intf =3D req->intf; + + npc_cn20k_config_mcam_entry(rvu, blkaddr, req->entry, nix_intf, + &req->entry_data, req->enable_entry, + req->hw_prio); + + rc =3D 0; +exit: + mutex_unlock(&mcam->lock); + return rc; +} + +int rvu_mbox_handler_npc_cn20k_mcam_read_entry(struct rvu *rvu, + struct npc_mcam_read_entry_req *req, + struct npc_cn20k_mcam_read_entry_rsp *rsp) +{ + struct npc_mcam *mcam =3D &rvu->hw->mcam; + u16 pcifunc =3D req->hdr.pcifunc; + int blkaddr, rc; + + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) + return NPC_MCAM_INVALID_REQ; + + mutex_lock(&mcam->lock); + rc =3D npc_mcam_verify_entry(mcam, pcifunc, req->entry); + if (!rc) + npc_cn20k_read_mcam_entry(rvu, blkaddr, req->entry, + &rsp->entry_data, &rsp->intf, + &rsp->enable, &rsp->hw_prio); + + mutex_unlock(&mcam->lock); + return rc; +} + +int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_entry(struct rvu *rvu, + struct npc_cn20k_mcam_alloc_and_write_entry_req *req, + struct npc_mcam_alloc_and_write_entry_rsp *rsp) +{ + struct rvu_pfvf *pfvf =3D rvu_get_pfvf(rvu, req->hdr.pcifunc); + struct npc_mcam_alloc_entry_req entry_req; + struct npc_mcam_alloc_entry_rsp entry_rsp; + struct npc_mcam *mcam =3D &rvu->hw->mcam; + u16 entry =3D NPC_MCAM_ENTRY_INVALID; + int blkaddr, rc; + u8 nix_intf; + + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) + return NPC_MCAM_INVALID_REQ; + + if (!is_npc_interface_valid(rvu, req->intf)) + return NPC_MCAM_INVALID_REQ; + + /* Try to allocate a MCAM entry */ + entry_req.hdr.pcifunc =3D req->hdr.pcifunc; + entry_req.contig =3D true; + entry_req.ref_prio =3D req->ref_prio; + entry_req.ref_entry =3D req->ref_entry; + entry_req.count =3D 1; + + rc =3D rvu_mbox_handler_npc_mcam_alloc_entry(rvu, + &entry_req, &entry_rsp); + if (rc) + return rc; + + if (!entry_rsp.count) + return NPC_MCAM_ALLOC_FAILED; + + entry =3D entry_rsp.entry; + mutex_lock(&mcam->lock); + + if (is_npc_intf_tx(req->intf)) + nix_intf =3D pfvf->nix_tx_intf; + else + nix_intf =3D pfvf->nix_rx_intf; + + npc_cn20k_config_mcam_entry(rvu, blkaddr, entry, nix_intf, + &req->entry_data, req->enable_entry, + req->hw_prio); + + mutex_unlock(&mcam->lock); + + rsp->entry =3D entry; + return 0; +} + +int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(struct rvu *rvu, + struct msg_req *req, + struct npc_cn20k_mcam_read_base_rule_rsp *rsp) +{ + struct npc_mcam *mcam =3D &rvu->hw->mcam; + int index, blkaddr, nixlf, rc =3D 0; + u16 pcifunc =3D req->hdr.pcifunc; + u8 intf, enable, hw_prio; + struct rvu_pfvf *pfvf; + + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) + return NPC_MCAM_INVALID_REQ; + + /* Return the channel number in case of PF */ + if (!(pcifunc & RVU_PFVF_FUNC_MASK)) { + pfvf =3D rvu_get_pfvf(rvu, pcifunc); + rsp->entry.kw[0] =3D pfvf->rx_chan_base; + rsp->entry.kw_mask[0] =3D 0xFFFULL; + goto out; + } + + /* Find the pkt steering rule installed by PF to this VF */ + mutex_lock(&mcam->lock); + for (index =3D 0; index < mcam->bmap_entries; index++) { + if (mcam->entry2target_pffunc[index] =3D=3D pcifunc) + goto read_entry; + } + + rc =3D nix_get_nixlf(rvu, pcifunc, &nixlf, NULL); + if (rc < 0) { + mutex_unlock(&mcam->lock); + goto out; + } + /* Read the default ucast entry if there is no pkt steering rule */ + index =3D npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf, + NIXLF_UCAST_ENTRY); +read_entry: + /* Read the mcam entry */ + npc_cn20k_read_mcam_entry(rvu, blkaddr, index, + &rsp->entry, &intf, + &enable, &hw_prio); + mutex_unlock(&mcam->lock); +out: + return rc; +} + static u8 npc_map2cn20k_flag(u8 flag) { switch (flag) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.h index 75c3dce2b0b0..13a605f183c6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h @@ -296,15 +296,16 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 = pcifunc, u16 *bcast, u16 *mcast, u16 *promisc, u16 *ucast); =20 void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index, - u8 intf, struct mcam_entry *entry, + u8 intf, + struct cn20k_mcam_entry *entry, bool enable, u8 hw_prio); void npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr, int index, bool enable); void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest); void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index, - struct mcam_entry *entry, u8 *intf, u8 *ena, - u8 *hw_prio); + struct cn20k_mcam_entry *entry, u8 *intf, + u8 *ena, u8 *hw_prio); void npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int bank, int index); int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/reg.h index bf50d999528b..8bfaa507ee50 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h @@ -78,6 +78,13 @@ #define RVU_MBOX_VF_INT_ENA_W1C (0x38) =20 #define RVU_MBOX_VF_VFAF_TRIGX(a) (0x2000 | (a) << 3) + +#define NIX_GINT_INT (0x200) +#define NIX_GINT_INT_W1S (0x208) + +#define ALTAF_FLR BIT_ULL(0) +#define ALTAF_RDY BIT_ULL(1) + /* NPC registers */ #define NPC_AF_INTFX_EXTRACTORX_CFG(a, b) \ (0x20c000ull | (a) << 16 | (b) << 8) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index a4e79828a84c..e004271124df 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -287,6 +287,17 @@ M(NPC_CN20K_MCAM_GET_FREE_COUNT, 0x6015, npc_cn20k_get= _fcnt, \ msg_req, npc_cn20k_get_fcnt_rsp) \ M(NPC_CN20K_GET_KEX_CFG, 0x6016, npc_cn20k_get_kex_cfg, \ msg_req, npc_cn20k_get_kex_cfg_rsp) \ +M(NPC_CN20K_MCAM_WRITE_ENTRY, 0x6017, npc_cn20k_mcam_write_entry, \ + npc_cn20k_mcam_write_entry_req, msg_rsp) \ +M(NPC_CN20K_MCAM_ALLOC_AND_WRITE_ENTRY, 0x6018, \ +npc_cn20k_mcam_alloc_and_write_entry, \ + npc_cn20k_mcam_alloc_and_write_entry_req, \ + npc_mcam_alloc_and_write_entry_rsp) \ +M(NPC_CN20K_MCAM_READ_ENTRY, 0x6019, npc_cn20k_mcam_read_entry, \ + npc_mcam_read_entry_req, \ + npc_cn20k_mcam_read_entry_rsp) \ +M(NPC_CN20K_MCAM_READ_BASE_RULE, 0x601a, npc_cn20k_read_base_steer_rule, = \ + msg_req, npc_cn20k_mcam_read_base_rule_rsp) \ /* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \ M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc, \ nix_lf_alloc_req, nix_lf_alloc_rsp) \ @@ -1570,13 +1581,32 @@ struct mcam_entry_mdata { }; =20 struct mcam_entry { -#define NPC_MAX_KWS_IN_KEY 8 /* Number of keywords in max keywidth */ +#define NPC_MAX_KWS_IN_KEY 7 /* Number of keywords in max keywidth */ u64 kw[NPC_MAX_KWS_IN_KEY]; u64 kw_mask[NPC_MAX_KWS_IN_KEY]; u64 action; u64 vtag_action; }; =20 +struct cn20k_mcam_entry { +#define NPC_CN20K_MAX_KWS_IN_KEY 8 + u64 kw[NPC_CN20K_MAX_KWS_IN_KEY]; + u64 kw_mask[NPC_CN20K_MAX_KWS_IN_KEY]; + u64 action; + u64 vtag_action; +}; + +struct npc_cn20k_mcam_write_entry_req { + struct mbox_msghdr hdr; + struct cn20k_mcam_entry entry_data; + u16 entry; /* MCAM entry to write this match key */ + u16 cntr; /* Counter for this MCAM entry */ + u8 intf; /* Rx or Tx interface */ + u8 enable_entry;/* Enable this MCAM entry ? */ + u8 hw_prio; /* hardware priority, valid for cn20k */ + u64 reserved; /* reserved for future use */ +}; + struct npc_mcam_write_entry_req { struct mbox_msghdr hdr; struct mcam_entry entry_data; @@ -1649,8 +1679,30 @@ struct npc_mcam_alloc_and_write_entry_req { u8 intf; /* Rx or Tx interface */ u8 enable_entry;/* Enable this MCAM entry ? */ u8 alloc_cntr; /* Allocate counter and map ? */ - /* hardware priority, supported for cn20k */ - u8 hw_prio; +}; + +struct npc_cn20k_mcam_alloc_and_write_entry_req { + struct mbox_msghdr hdr; + struct cn20k_mcam_entry entry_data; + u16 ref_entry; + u8 ref_prio; /* Lower or higher w.r.t ref_entry */ + u8 intf; /* Rx or Tx interface */ + u8 enable_entry;/* Enable this MCAM entry ? */ + u8 hw_prio; /* hardware priority, valid for cn20k */ + u16 reserved[4]; /* reserved for future use */ +}; + +struct npc_cn20k_mcam_read_entry_rsp { + struct mbox_msghdr hdr; + struct cn20k_mcam_entry entry_data; + u8 intf; + u8 enable; + u8 hw_prio; /* valid for cn20k */ +}; + +struct npc_cn20k_mcam_read_base_rule_rsp { + struct mbox_msghdr hdr; + struct cn20k_mcam_entry entry; }; =20 struct npc_mcam_alloc_and_write_entry_rsp { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/= ethernet/marvell/octeontx2/af/npc.h index cb05ec69e0b3..cefc5d70f3e4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h @@ -644,6 +644,7 @@ struct rvu_npc_mcam_rule { u16 chan; u16 chan_mask; u8 lxmb; + u8 hw_prio; }; =20 #endif /* NPC_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.c index c8482b1598b9..765daa7709e3 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -600,6 +600,7 @@ static void rvu_check_min_msix_vec(struct rvu *rvu, int= nvecs, int pf, int vf) =20 static int rvu_setup_msix_resources(struct rvu *rvu) { + struct altaf_intr_notify *altaf_intr_data; struct rvu_hwinfo *hw =3D rvu->hw; int pf, vf, numvfs, hwvf, err; int nvecs, offset, max_msix; @@ -706,6 +707,21 @@ static int rvu_setup_msix_resources(struct rvu *rvu) rvu->msix_base_iova =3D iova; rvu->msixtr_base_phy =3D phy_addr; =20 + if (is_rvu_otx2(rvu) || is_cn20k(rvu->pdev)) + return 0; + + altaf_intr_data =3D &rvu->fwdata->altaf_intr_info; + if (altaf_intr_data->gint_paddr) { + iova =3D dma_map_resource(rvu->dev, altaf_intr_data->gint_paddr, + PCI_MSIX_ENTRY_SIZE, + DMA_BIDIRECTIONAL, 0); + + if (dma_mapping_error(rvu->dev, iova)) + return -ENOMEM; + + altaf_intr_data->gint_iova_addr =3D iova; + } + return 0; } =20 @@ -2203,6 +2219,26 @@ int rvu_mbox_handler_ndc_sync_op(struct rvu *rvu, return 0; } =20 +static void rvu_notify_altaf(struct rvu *rvu, u16 pcifunc, u64 op) +{ + int pf, vf; + + if (!rvu->fwdata) + return; + + if (op =3D=3D ALTAF_FLR) { + pf =3D rvu_get_pf(rvu->pdev, pcifunc); + set_bit(pf, rvu->fwdata->altaf_intr_info.flr_pf_bmap); + if (pcifunc & RVU_PFVF_FUNC_MASK) { + vf =3D pcifunc & RVU_PFVF_FUNC_MASK; + set_bit(vf, rvu->fwdata->altaf_intr_info.flr_vf_bmap); + } + } + + rvu_write64(rvu, BLKADDR_NIX0, AF_BAR2_ALIASX(0, NIX_GINT_INT_W1S), op); + usleep_range(5000, 6000); +} + static int rvu_process_mbox_msg(struct otx2_mbox *mbox, int devid, struct mbox_msghdr *req) { @@ -2286,7 +2322,8 @@ static void __rvu_mbox_handler(struct rvu_work *mwork= , int type, bool poll) =20 offset =3D mbox->rx_start + ALIGN(sizeof(*req_hdr), MBOX_MSG_ALIGN); =20 - if (req_hdr->sig && !(is_rvu_otx2(rvu) || is_cn20k(rvu->pdev))) { + if (req_hdr->sig && rvu->altaf_ready && + !(is_rvu_otx2(rvu) || is_cn20k(rvu->pdev))) { req_hdr->opt_msg =3D mw->mbox_wrk[devid].num_msgs; rvu_write64(rvu, BLKADDR_NIX0, RVU_AF_BAR2_SEL, RVU_AF_BAR2_PFID); @@ -2795,6 +2832,16 @@ static void rvu_blklf_teardown(struct rvu *rvu, u16 = pcifunc, u8 blkaddr) block =3D &rvu->hw->block[blkaddr]; num_lfs =3D rvu_get_rsrc_mapcount(rvu_get_pfvf(rvu, pcifunc), block->addr); + + if (block->addr =3D=3D BLKADDR_TIM && rvu->altaf_ready) { + rvu_notify_altaf(rvu, pcifunc, ALTAF_FLR); + return; + } + + if ((block->addr =3D=3D BLKADDR_SSO || block->addr =3D=3D BLKADDR_SSOW) && + rvu->altaf_ready) + return; + if (!num_lfs) return; for (slot =3D 0; slot < num_lfs; slot++) { @@ -3078,7 +3125,7 @@ static int rvu_afvf_msix_vectors_num_ok(struct rvu *r= vu) =20 static int rvu_register_interrupts(struct rvu *rvu) { - int ret, offset, pf_vec_start; + int i, ret, offset, pf_vec_start; =20 rvu->num_vec =3D pci_msix_vec_count(rvu->pdev); =20 @@ -3269,6 +3316,13 @@ static int rvu_register_interrupts(struct rvu *rvu) if (ret) goto fail; =20 + for (i =3D 0; i < rvu->num_vec; i++) { + if (strstr(&rvu->irq_name[i * NAME_SIZE], "Mbox") || + strstr(&rvu->irq_name[i * NAME_SIZE], "FLR")) + irq_set_affinity(pci_irq_vector(rvu->pdev, i), + cpumask_of(0)); + } + return 0; =20 fail: @@ -3297,8 +3351,8 @@ static int rvu_flr_init(struct rvu *rvu) cfg | BIT_ULL(22)); } =20 - rvu->flr_wq =3D alloc_ordered_workqueue("rvu_afpf_flr", - WQ_HIGHPRI | WQ_MEM_RECLAIM); + rvu->flr_wq =3D alloc_workqueue("rvu_afpf_flr", + WQ_HIGHPRI | WQ_MEM_RECLAIM, 0); if (!rvu->flr_wq) return -ENOMEM; =20 diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.h index a53bb5c924ef..f811d6b5c545 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -197,7 +197,7 @@ struct npc_key_field { /* Masks where all set bits indicate position * of a field in the key */ - u64 kw_mask[NPC_MAX_KWS_IN_KEY]; + u64 kw_mask[NPC_CN20K_MAX_KWS_IN_KEY]; /* Number of words in the key a field spans. If a field is * of 16 bytes and key offset is 4 then the field will use * 4 bytes in KW0, 8 bytes in KW1 and 4 bytes in KW2 and @@ -1191,4 +1191,5 @@ int rvu_rep_pf_init(struct rvu *rvu); int rvu_rep_install_mcam_rules(struct rvu *rvu); void rvu_rep_update_rules(struct rvu *rvu, u16 pcifunc, bool ena); int rvu_rep_notify_pfvf_state(struct rvu *rvu, u16 pcifunc, bool enable); +int npc_mcam_verify_entry(struct npc_mcam *mcam, u16 pcifunc, int entry); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/driv= ers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index 425d3a43c0b8..620724dad093 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -21,6 +21,7 @@ #include "rvu_npc_hash.h" #include "mcs.h" =20 +#include "cn20k/reg.h" #include "cn20k/debugfs.h" =20 #define DEBUGFS_DIR_NAME "octeontx2" @@ -3506,11 +3507,11 @@ static int rvu_dbg_npc_mcam_show_rules(struct seq_f= ile *s, void *unused) struct rvu_npc_mcam_rule *iter; struct rvu *rvu =3D s->private; struct npc_mcam *mcam; - int pf, vf =3D -1; + int pf, vf =3D -1, bank; + u16 target, index; bool enabled; + u64 hits, off; int blkaddr; - u16 target; - u64 hits; =20 blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) @@ -3554,6 +3555,15 @@ static int rvu_dbg_npc_mcam_show_rules(struct seq_fi= le *s, void *unused) =20 enabled =3D is_mcam_entry_enabled(rvu, mcam, blkaddr, iter->entry); seq_printf(s, "\tenabled: %s\n", enabled ? "yes" : "no"); + if (is_cn20k(rvu->pdev)) { + seq_printf(s, "\tpriority: %u\n", iter->hw_prio); + index =3D iter->entry & (mcam->banksize - 1); + bank =3D npc_get_bank(mcam, iter->entry); + off =3D NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(index, bank); + hits =3D rvu_read64(rvu, blkaddr, off); + seq_printf(s, "\thits: %lld\n", hits); + continue; + } =20 if (!iter->has_cntr) continue; @@ -3698,9 +3708,9 @@ static int rvu_dbg_npc_exact_drop_cnt(struct seq_file= *s, void *unused) struct npc_exact_table *table; struct rvu *rvu =3D s->private; struct npc_key_field *field; + u64 cfg, cam1, off; u16 chan, pcifunc; int blkaddr, i; - u64 cfg, cam1; char *str; =20 blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); @@ -3721,11 +3731,17 @@ static int rvu_dbg_npc_exact_drop_cnt(struct seq_fi= le *s, void *unused) chan =3D field->kw_mask[0] & cam1; =20 str =3D (cfg & 1) ? "enabled" : "disabled"; + if (is_cn20k(rvu->pdev)) { + off =3D NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(i, 0); + seq_printf(s, "0x%x\t%d\t\t%llu\t0x%x\t%s\n", pcifunc, + i, rvu_read64(rvu, blkaddr, off), chan, str); + } else { + off =3D NPC_AF_MATCH_STATX(table->counter_idx[i]); + seq_printf(s, "0x%x\t%d\t\t%llu\t0x%x\t%s\n", pcifunc, + i, rvu_read64(rvu, blkaddr, off), + chan, str); + } =20 - seq_printf(s, "0x%x\t%d\t\t%llu\t0x%x\t%s\n", pcifunc, i, - rvu_read64(rvu, blkaddr, - NPC_AF_MATCH_STATX(table->counter_idx[i])), - chan, str); } =20 return 0; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.c index f8fe93c78dae..08f1c5e38ed9 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -2385,8 +2385,8 @@ void rvu_npc_get_mcam_counter_alloc_info(struct rvu *= rvu, u16 pcifunc, } } =20 -static int npc_mcam_verify_entry(struct npc_mcam *mcam, - u16 pcifunc, int entry) +int npc_mcam_verify_entry(struct npc_mcam *mcam, + u16 pcifunc, int entry) { /* verify AF installed entries */ if (is_pffunc_af(pcifunc)) @@ -2931,6 +2931,10 @@ int npc_config_cntr_default_entries(struct rvu *rvu,= bool enable) struct rvu_npc_mcam_rule *rule; int blkaddr; =20 + /* Counter is set for each rule by default */ + if (is_cn20k(rvu->pdev)) + return -EINVAL; + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) return -EINVAL; @@ -3111,7 +3115,7 @@ int rvu_mbox_handler_npc_mcam_write_entry(struct rvu = *rvu, if (rc) goto exit; =20 - if (req->set_cntr && + if (!is_cn20k(rvu->pdev) && req->set_cntr && npc_mcam_verify_counter(mcam, pcifunc, req->cntr)) { rc =3D NPC_MCAM_INVALID_REQ; goto exit; @@ -3326,6 +3330,10 @@ int rvu_mbox_handler_npc_mcam_alloc_counter(struct r= vu *rvu, struct npc_mcam *mcam =3D &rvu->hw->mcam; int err; =20 + /* Counter is not supported for CN20K */ + if (is_cn20k(rvu->pdev)) + return NPC_MCAM_INVALID_REQ; + mutex_lock(&mcam->lock); =20 err =3D __npc_mcam_alloc_counter(rvu, req, rsp); @@ -3380,6 +3388,10 @@ int rvu_mbox_handler_npc_mcam_free_counter(struct rv= u *rvu, struct npc_mcam *mcam =3D &rvu->hw->mcam; int err; =20 + /* Counter is not supported for CN20K */ + if (is_cn20k(rvu->pdev)) + return NPC_MCAM_INVALID_REQ; + mutex_lock(&mcam->lock); =20 err =3D __npc_mcam_free_counter(rvu, req, rsp); @@ -3438,6 +3450,10 @@ int rvu_mbox_handler_npc_mcam_unmap_counter(struct r= vu *rvu, u16 index, entry =3D 0; int blkaddr, rc; =20 + /* Counter is not supported for CN20K */ + if (is_cn20k(rvu->pdev)) + return NPC_MCAM_INVALID_REQ; + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) return NPC_MCAM_INVALID_REQ; @@ -3482,12 +3498,20 @@ int rvu_mbox_handler_npc_mcam_clear_counter(struct = rvu *rvu, struct npc_mcam_oper_counter_req *req, struct msg_rsp *rsp) { struct npc_mcam *mcam =3D &rvu->hw->mcam; - int blkaddr, err; + int blkaddr, err, index, bank; =20 blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) return NPC_MCAM_INVALID_REQ; =20 + if (is_cn20k(rvu->pdev)) { + index =3D req->cntr & (mcam->banksize - 1); + bank =3D npc_get_bank(mcam, req->cntr); + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(index, bank), 0); + return 0; + } + mutex_lock(&mcam->lock); err =3D npc_mcam_verify_counter(mcam, req->hdr.pcifunc, req->cntr); mutex_unlock(&mcam->lock); @@ -3504,12 +3528,23 @@ int rvu_mbox_handler_npc_mcam_counter_stats(struct = rvu *rvu, struct npc_mcam_oper_counter_rsp *rsp) { struct npc_mcam *mcam =3D &rvu->hw->mcam; - int blkaddr, err; + int blkaddr, err, index, bank; + u64 regval; =20 blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) return NPC_MCAM_INVALID_REQ; =20 + if (is_cn20k(rvu->pdev)) { + index =3D req->cntr & (mcam->banksize - 1); + bank =3D npc_get_bank(mcam, req->cntr); + regval =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(index, + bank)); + rsp->stat =3D regval; + return 0; + } + mutex_lock(&mcam->lock); err =3D npc_mcam_verify_counter(mcam, req->hdr.pcifunc, req->cntr); mutex_unlock(&mcam->lock); @@ -3804,13 +3839,24 @@ int rvu_mbox_handler_npc_mcam_entry_stats(struct rv= u *rvu, if (blkaddr < 0) return NPC_MCAM_INVALID_REQ; =20 - mutex_lock(&mcam->lock); - index =3D req->entry & (mcam->banksize - 1); bank =3D npc_get_bank(mcam, req->entry); =20 + mutex_lock(&mcam->lock); + + if (is_cn20k(rvu->pdev)) { + regval =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(index, + bank)); + rsp->stat_ena =3D 1; + rsp->stat =3D regval; + mutex_unlock(&mcam->lock); + return 0; + } + /* read MCAM entry STAT_ACT register */ - regval =3D rvu_read64(rvu, blkaddr, NPC_AF_MCAMEX_BANKX_STAT_ACT(index, b= ank)); + regval =3D rvu_read64(rvu, blkaddr, NPC_AF_MCAMEX_BANKX_STAT_ACT(index, + bank)); =20 if (!(regval & rvu->hw->npc_stat_ena)) { rsp->stat_ena =3D 0; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drive= rs/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index d73e447bedca..584be2892ba7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -227,10 +227,11 @@ static bool npc_check_overlap(struct rvu *rvu, int bl= kaddr, input =3D &mcam->tx_key_fields[type]; } =20 + kws =3D NPC_MAX_KWS_IN_KEY; + if (is_cn20k(rvu->pdev)) goto skip_cn10k_config; =20 - kws =3D NPC_MAX_KWS_IN_KEY - 1; for (lid =3D start_lid; lid < NPC_MAX_LID; lid++) { for (lt =3D 0; lt < NPC_MAX_LT; lt++) { for (ld =3D 0; ld < NPC_MAX_LD; ld++) { @@ -255,8 +256,7 @@ static bool npc_check_overlap(struct rvu *rvu, int blka= ddr, /* check any input field bits falls in any * other field bits. */ - if (npc_check_overlap_fields(dummy, input, - kws)) + if (npc_check_overlap_fields(dummy, input, kws)) return true; } } @@ -289,7 +289,7 @@ static bool npc_check_overlap(struct rvu *rvu, int blka= ddr, * field bits */ if (npc_check_overlap_fields(dummy, input, - NPC_MAX_KWS_IN_KEY)) + NPC_CN20K_MAX_KWS_IN_KEY)) return true; } } @@ -460,9 +460,9 @@ static void npc_handle_multi_layer_fields(struct rvu *r= vu, int blkaddr, u8 intf) u8 start_lid; =20 if (is_cn20k(rvu->pdev)) - max_kw =3D NPC_MAX_KWS_IN_KEY; + max_kw =3D NPC_CN20K_MAX_KWS_IN_KEY; else - max_kw =3D NPC_MAX_KWS_IN_KEY - 1; + max_kw =3D NPC_MAX_KWS_IN_KEY; =20 key_fields =3D mcam->rx_key_fields; features =3D &mcam->rx_features; @@ -906,6 +906,7 @@ void npc_update_entry(struct rvu *rvu, enum key_fields = type, struct mcam_entry_mdata *mdata, u64 val_lo, u64 val_hi, u64 mask_lo, u64 mask_hi, u8 intf) { + struct cn20k_mcam_entry cn20k_dummy =3D { {0} }; struct npc_mcam *mcam =3D &rvu->hw->mcam; struct mcam_entry dummy =3D { {0} }; u64 *kw, *kw_mask, *val, *mask; @@ -921,9 +922,15 @@ void npc_update_entry(struct rvu *rvu, enum key_fields= type, if (!field->nr_kws) return; =20 - max_kw =3D NPC_MAX_KWS_IN_KEY; - kw =3D dummy.kw; - kw_mask =3D dummy.kw_mask; + if (is_cn20k(rvu->pdev)) { + max_kw =3D NPC_CN20K_MAX_KWS_IN_KEY; + kw =3D cn20k_dummy.kw; + kw_mask =3D cn20k_dummy.kw_mask; + } else { + max_kw =3D NPC_MAX_KWS_IN_KEY; + kw =3D dummy.kw; + kw_mask =3D dummy.kw_mask; + } =20 for (i =3D 0; i < max_kw; i++) { if (!field->kw_mask[i]) @@ -1247,6 +1254,10 @@ static void rvu_mcam_remove_counter_from_rule(struct= rvu *rvu, u16 pcifunc, { struct npc_mcam *mcam =3D &rvu->hw->mcam; =20 + /* There is no counter allotted for cn20k */ + if (is_cn20k(rvu->pdev)) + return; + mutex_lock(&mcam->lock); =20 __rvu_mcam_remove_counter_from_rule(rvu, pcifunc, rule); @@ -1296,8 +1307,17 @@ static int npc_mcast_update_action_index(struct rvu = *rvu, struct npc_install_flo static void npc_populate_mcam_mdata(struct rvu *rvu, struct mcam_entry_mdata *mdata, + struct cn20k_mcam_entry *cn20k_entry, struct mcam_entry *entry) { + if (is_cn20k(rvu->pdev)) { + mdata->kw =3D cn20k_entry->kw; + mdata->kw_mask =3D cn20k_entry->kw_mask; + mdata->action =3D &cn20k_entry->action; + mdata->vtag_action =3D &cn20k_entry->vtag_action; + mdata->max_kw =3D NPC_CN20K_MAX_KWS_IN_KEY; + return; + } mdata->kw =3D entry->kw; mdata->kw_mask =3D entry->kw_mask; mdata->action =3D &entry->action; @@ -1417,9 +1437,11 @@ static int npc_install_flow(struct rvu *rvu, int blk= addr, u16 target, bool pf_set_vfs_mac) { struct rvu_npc_mcam_rule *def_ucast_rule =3D pfvf->def_ucast_rule; + struct npc_cn20k_mcam_write_entry_req cn20k_wreq =3D { 0 }; u64 features, installed_features, missing_features =3D 0; struct npc_mcam_write_entry_req write_req =3D { 0 }; struct npc_mcam *mcam =3D &rvu->hw->mcam; + struct cn20k_mcam_entry *cn20k_entry; struct mcam_entry_mdata mdata =3D { }; struct rvu_npc_mcam_rule dummy =3D { 0 }; struct rvu_npc_mcam_rule *rule; @@ -1432,11 +1454,12 @@ static int npc_install_flow(struct rvu *rvu, int bl= kaddr, u16 target, =20 installed_features =3D req->features; features =3D req->features; - entry =3D &write_req.entry_data; entry_index =3D req->entry; =20 - npc_populate_mcam_mdata(rvu, &mdata, - &write_req.entry_data); + cn20k_entry =3D &cn20k_wreq.entry_data; + entry =3D &write_req.entry_data; + + npc_populate_mcam_mdata(rvu, &mdata, cn20k_entry, entry); =20 npc_update_flow(rvu, &mdata, features, &req->packet, &req->mask, &dummy, req->intf, blkaddr); @@ -1484,51 +1507,90 @@ static int npc_install_flow(struct rvu *rvu, int bl= kaddr, u16 target, new =3D true; } =20 - /* allocate new counter if rule has no counter */ - if (!req->default_rule && req->set_cntr && !rule->has_cntr) - rvu_mcam_add_counter_to_rule(rvu, owner, rule, rsp); - - /* if user wants to delete an existing counter for a rule then - * free the counter - */ - if (!req->set_cntr && rule->has_cntr) - rvu_mcam_remove_counter_from_rule(rvu, owner, rule); + if (!is_cn20k(rvu->pdev)) { + write_req.hdr.pcifunc =3D owner; + + /* allocate new counter if rule has no counter */ + if (!req->default_rule && req->set_cntr && !rule->has_cntr) + rvu_mcam_add_counter_to_rule(rvu, owner, rule, rsp); + + /* if user wants to delete an existing counter for a rule then + * free the counter + */ + if (!req->set_cntr && rule->has_cntr) + rvu_mcam_remove_counter_from_rule(rvu, owner, rule); + + /* AF owns the default rules so change the owner just to relax + * the checks in rvu_mbox_handler_npc_mcam_write_entry + */ + if (req->default_rule) + write_req.hdr.pcifunc =3D 0; + + write_req.entry =3D entry_index; + write_req.intf =3D req->intf; + write_req.enable_entry =3D (u8)enable; + /* if counter is available then clear and use it */ + if (req->set_cntr && rule->has_cntr) { + rvu_write64(rvu, blkaddr, + NPC_AF_MATCH_STATX(rule->cntr), + req->cntr_val); + write_req.set_cntr =3D 1; + write_req.cntr =3D rule->cntr; + } + goto update_rule; + } =20 - write_req.hdr.pcifunc =3D owner; + cn20k_wreq.hdr.pcifunc =3D owner; =20 - /* AF owns the default rules so change the owner just to relax - * the checks in rvu_mbox_handler_npc_mcam_write_entry - */ if (req->default_rule) - write_req.hdr.pcifunc =3D 0; + cn20k_wreq.hdr.pcifunc =3D 0; =20 - write_req.entry =3D entry_index; - write_req.intf =3D req->intf; - write_req.enable_entry =3D (u8)enable; - /* if counter is available then clear and use it */ - if (req->set_cntr && rule->has_cntr) { - rvu_write64(rvu, blkaddr, NPC_AF_MATCH_STATX(rule->cntr), req->cntr_val); - write_req.set_cntr =3D 1; - write_req.cntr =3D rule->cntr; - } + cn20k_wreq.entry =3D entry_index; + cn20k_wreq.intf =3D req->intf; + cn20k_wreq.enable_entry =3D (u8)enable; + cn20k_wreq.hw_prio =3D req->hw_prio; + +update_rule: =20 /* update rule */ memcpy(&rule->packet, &dummy.packet, sizeof(rule->packet)); memcpy(&rule->mask, &dummy.mask, sizeof(rule->mask)); rule->entry =3D entry_index; - memcpy(&rule->rx_action, &entry->action, sizeof(struct nix_rx_action)); - if (is_npc_intf_tx(req->intf)) - memcpy(&rule->tx_action, &entry->action, - sizeof(struct nix_tx_action)); - rule->vtag_action =3D entry->vtag_action; + if (is_cn20k(rvu->pdev)) { + memcpy(&rule->rx_action, &cn20k_entry->action, + sizeof(struct nix_rx_action)); + if (is_npc_intf_tx(req->intf)) + memcpy(&rule->tx_action, &cn20k_entry->action, + sizeof(struct nix_tx_action)); + rule->vtag_action =3D cn20k_entry->vtag_action; + } else { + memcpy(&rule->rx_action, &entry->action, + sizeof(struct nix_rx_action)); + if (is_npc_intf_tx(req->intf)) + memcpy(&rule->tx_action, &entry->action, + sizeof(struct nix_tx_action)); + rule->vtag_action =3D entry->vtag_action; + } + rule->features =3D installed_features; rule->default_rule =3D req->default_rule; rule->owner =3D owner; rule->enable =3D enable; - rule->chan_mask =3D write_req.entry_data.kw_mask[0] & NPC_KEX_CHAN_MASK; - rule->chan =3D write_req.entry_data.kw[0] & NPC_KEX_CHAN_MASK; + + if (is_cn20k(rvu->pdev)) { + rule->chan_mask =3D cn20k_wreq.entry_data.kw_mask[0] & + NPC_KEX_CHAN_MASK; + rule->chan =3D cn20k_wreq.entry_data.kw[0] & + NPC_KEX_CHAN_MASK; + } else { + rule->chan_mask =3D write_req.entry_data.kw_mask[0] & + NPC_KEX_CHAN_MASK; + rule->chan =3D write_req.entry_data.kw[0] & NPC_KEX_CHAN_MASK; + } + rule->chan &=3D rule->chan_mask; rule->lxmb =3D dummy.lxmb; + rule->hw_prio =3D req->hw_prio; if (is_npc_intf_tx(req->intf)) rule->intf =3D pfvf->nix_tx_intf; else @@ -1540,8 +1602,14 @@ static int npc_install_flow(struct rvu *rvu, int blk= addr, u16 target, pfvf->def_ucast_rule =3D rule; =20 /* write to mcam entry registers */ - err =3D rvu_mbox_handler_npc_mcam_write_entry(rvu, &write_req, - &write_rsp); + if (is_cn20k(rvu->pdev)) + err =3D rvu_mbox_handler_npc_cn20k_mcam_write_entry(rvu, + &cn20k_wreq, + &write_rsp); + else + err =3D rvu_mbox_handler_npc_mcam_write_entry(rvu, &write_req, + &write_rsp); + if (err) { rvu_mcam_remove_counter_from_rule(rvu, owner, rule); if (new) { @@ -1782,23 +1850,25 @@ static int npc_update_dmac_value(struct rvu *rvu, i= nt npcblkaddr, struct rvu_npc_mcam_rule *rule, struct rvu_pfvf *pfvf) { + struct npc_cn20k_mcam_write_entry_req cn20k_wreq =3D { 0 }; struct npc_mcam_write_entry_req write_req =3D { 0 }; - struct npc_mcam *mcam =3D &rvu->hw->mcam; struct mcam_entry_mdata mdata =3D { }; + struct npc_mcam *mcam =3D &rvu->hw->mcam; + struct cn20k_mcam_entry *cn20k_entry; struct mcam_entry *entry; u8 intf, enable, hw_prio; struct msg_rsp rsp; int err; =20 + cn20k_entry =3D &cn20k_wreq.entry_data; entry =3D &write_req.entry_data; - - npc_populate_mcam_mdata(rvu, &mdata, entry); + npc_populate_mcam_mdata(rvu, &mdata, cn20k_entry, entry); =20 ether_addr_copy(rule->packet.dmac, pfvf->mac_addr); =20 if (is_cn20k(rvu->pdev)) npc_cn20k_read_mcam_entry(rvu, npcblkaddr, rule->entry, - entry, &intf, + cn20k_entry, &intf, &enable, &hw_prio); else npc_read_mcam_entry(rvu, mcam, npcblkaddr, rule->entry, @@ -1808,12 +1878,21 @@ static int npc_update_dmac_value(struct rvu *rvu, i= nt npcblkaddr, ether_addr_to_u64(pfvf->mac_addr), 0, 0xffffffffffffull, 0, intf); =20 - write_req.hdr.pcifunc =3D rule->owner; - write_req.entry =3D rule->entry; - write_req.intf =3D pfvf->nix_rx_intf; - mutex_unlock(&mcam->lock); - err =3D rvu_mbox_handler_npc_mcam_write_entry(rvu, &write_req, &rsp); + if (is_cn20k(rvu->pdev)) { + cn20k_wreq.hdr.pcifunc =3D rule->owner; + cn20k_wreq.entry =3D rule->entry; + cn20k_wreq.intf =3D pfvf->nix_rx_intf; + err =3D rvu_mbox_handler_npc_cn20k_mcam_write_entry(rvu, + &cn20k_wreq, + &rsp); + } else { + write_req.hdr.pcifunc =3D rule->owner; + write_req.entry =3D rule->entry; + write_req.intf =3D pfvf->nix_rx_intf; + err =3D rvu_mbox_handler_npc_mcam_write_entry(rvu, &write_req, + &rsp); + } mutex_lock(&mcam->lock); =20 return err; @@ -1901,6 +1980,7 @@ int npc_install_mcam_drop_rule(struct rvu *rvu, int m= cam_idx, u16 *counter_idx, u64 chan_val, u64 chan_mask, u64 exact_val, u64 exact_mask, u64 bcast_mcast_val, u64 bcast_mcast_mask) { + struct npc_cn20k_mcam_write_entry_req cn20k_req =3D { 0 }; struct npc_mcam_alloc_counter_req cntr_req =3D { 0 }; struct npc_mcam_alloc_counter_rsp cntr_rsp =3D { 0 }; struct npc_mcam_write_entry_req req =3D { 0 }; @@ -1949,19 +2029,24 @@ int npc_install_mcam_drop_rule(struct rvu *rvu, int= mcam_idx, u16 *counter_idx, /* Reserve slot 0 */ npc_mcam_rsrcs_reserve(rvu, blkaddr, mcam_idx); =20 - /* Allocate counter for this single drop on non hit rule */ - cntr_req.hdr.pcifunc =3D 0; /* AF request */ - cntr_req.contig =3D true; - cntr_req.count =3D 1; - err =3D rvu_mbox_handler_npc_mcam_alloc_counter(rvu, &cntr_req, &cntr_rsp= ); - if (err) { - dev_err(rvu->dev, "%s: Err to allocate cntr for drop rule (err=3D%d)\n", - __func__, err); - return -EFAULT; + if (!is_cn20k(rvu->pdev)) { + /* Allocate counter for this single drop on non hit rule */ + cntr_req.hdr.pcifunc =3D 0; /* AF request */ + cntr_req.contig =3D true; + cntr_req.count =3D 1; + err =3D rvu_mbox_handler_npc_mcam_alloc_counter(rvu, &cntr_req, + &cntr_rsp); + if (err) { + dev_err(rvu->dev, + "%s: Err to allocate cntr for drop rule (err=3D%d)\n", + __func__, err); + return -EFAULT; + } + *counter_idx =3D cntr_rsp.cntr; } - *counter_idx =3D cntr_rsp.cntr; =20 npc_populate_mcam_mdata(rvu, &mdata, + &cn20k_req.entry_data, &req.entry_data); =20 /* Fill in fields for this mcam entry */ @@ -1972,6 +2057,23 @@ int npc_install_mcam_drop_rule(struct rvu *rvu, int = mcam_idx, u16 *counter_idx, npc_update_entry(rvu, NPC_LXMB, &mdata, bcast_mcast_val, 0, bcast_mcast_mask, 0, NIX_INTF_RX); =20 + if (is_cn20k(rvu->pdev)) { + cn20k_req.intf =3D NIX_INTF_RX; + cn20k_req.entry =3D mcam_idx; + + err =3D rvu_mbox_handler_npc_cn20k_mcam_write_entry(rvu, + &cn20k_req, + &rsp); + if (err) { + dev_err(rvu->dev, + "%s: Installation of single drop on non hit rule at %d failed\n", + __func__, mcam_idx); + return err; + } + + goto enable_entry; + } + req.intf =3D NIX_INTF_RX; req.set_cntr =3D true; req.cntr =3D cntr_rsp.cntr; @@ -1979,14 +2081,17 @@ int npc_install_mcam_drop_rule(struct rvu *rvu, int= mcam_idx, u16 *counter_idx, =20 err =3D rvu_mbox_handler_npc_mcam_write_entry(rvu, &req, &rsp); if (err) { - dev_err(rvu->dev, "%s: Installation of single drop on non hit rule at %d= failed\n", + dev_err(rvu->dev, + "%s: Installation of single drop on non hit rule at %d failed\n", __func__, mcam_idx); return err; } =20 - dev_err(rvu->dev, "%s: Installed single drop on non hit rule at %d, cntr= =3D%d\n", + dev_err(rvu->dev, + "%s: Installed single drop on non hit rule at %d, cntr=3D%d\n", __func__, mcam_idx, req.cntr); =20 +enable_entry: /* disable entry at Bank 0, index 0 */ npc_enable_mcam_entry(rvu, mcam, blkaddr, mcam_idx, false); =20 --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E59A62BEC20; Mon, 2 Feb 2026 07:46:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018420; cv=none; b=smRlKuF+6z80UqS6xV9WQWvfdWX87X5lUyWBkfT1MZ2KNs6exvFR2OV634/ykd0QtcwVVbA+Jdf88H9AYnzmoH5AvKFKsbP7vHSDiD35bB/bapEisXwePk3p0EKLMK0rVq24C5djnOFmg2SKd2+F5fYYSlmvebedGipbEQwxvpU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018420; c=relaxed/simple; bh=rawm3BEBuAUnWzyEMG9/7ySDALRgi62PMprCYBGJk7g=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=twQjb8u0XQ/CwwI4W4xRfWEgc7m5O+/7qKyJlZEjr2K5kiLrmZpHpOcfbz+UFk29Rnyay/ARE9rFQl7UE1OmneMZu900KQS5GGAFNyVqlTdJrYEZbYKICe5WGvJfTJ/NjuZ45de3T38gBai4PfU073dygX9hBP/88wg95+wC7xY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=bBPjpUay; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="bBPjpUay" Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 611MNPCQ2576737; Sun, 1 Feb 2026 23:46:47 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=A CURKnOc5GdAEPD0nrOuXTHdeLa3yYjMtuPpJTGobfE=; b=bBPjpUayPvajaQnSy xRwyrFKtjgpHT2pINEgZovTBA2F1VdSUbG10hnosYJMTy6p9d3pxCyha63JJ/Xhl 8fIwOw9EXDMfhxM8tvMnL/lwXEiDV1xdK27rUNkugjHkoMYUgegaP3AuS3/Y7P3i eUgzjcULkvjttwSxWkc0TYyz0v7LY5hb/gI7nQ/KjqUDkbLoqL2c5BXsojx+UFP8 yh2cmSoYGQfe0f0/cM3vqV74lJzHI6W19XeRN3XtlBzjCCSIU6hJ6JWGq+p0UiYA uUyBDINfGtdEyz40b/OdCfgG01jjC6TuW3hYWOMJHiyU70f+5kpyyVTcp7TXa2eU CPPrw== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4c28pe1890-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:46 -0800 (PST) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:47:02 -0800 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:47:02 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 122125B6947; Sun, 1 Feb 2026 23:46:42 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH net-next v8 09/13] octeontx2-af: npc: cn20k: virtual index support Date: Mon, 2 Feb 2026 13:16:03 +0530 Message-ID: <20260202074607.2535569-10-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: 1cxLjxHSTkdtDMsNU2QL2z3hK9V0aDQn X-Authority-Analysis: v=2.4 cv=Y4/1cxeN c=1 sm=1 tr=0 ts=69805666 cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=wI1F4VKOs4pjml9ngxsA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfXz+cfjVLR0x74 Vf3S/W7zoCxArJcPJNpdFfMMdx7EmBAlGD2XHE8V7N0lm4Zr0ojfZ+mKQS1Dwfm3Z0OkUYThGpr 0X7Xl7VnsRuQ7LrBOjw3EMh4txEUPTobDdGMnum8anhB1NB38FRphK2NNvFoJRUakLwcnKOHPTx kpHxtWjwZpoUPFpQ1yYbmYbyyUyqdmiC2jdFk/8Zv8+Rt0CEGx0pzCUICd7O7TT3Zh4iW101X26 C1Q0j8s2SVWjKXy4TMoem1cQjz8tyrghUVm6iZ3C5JSZhO5XFBu3knijoKrIwNJ3f8vNTEqY4+B Z8MZGYWmbR5UVmHScfsvg9W4eKULFrgd/dsiEqT3OfF4FzzOXCwnaWGLcZd5tISgU6vfVcXfWb4 JOlAjcTQQhwRktsVZkoqncl2pXO6s+hGZGutoWHKlB76u3J/1d2NM3LM+eLfYmY+rLpElcqcr66 tGnHc+wJ4ypjt/OlL8Q== X-Proofpoint-GUID: 1cxLjxHSTkdtDMsNU2QL2z3hK9V0aDQn X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" This patch adds support for virtual MCAM index allocation and improves CN20K MCAM defragmentation handling. A new field is introduced in the non-ref, non-contiguous MCAM allocation mailbox request to indicate that virtual indexes should be returned instead of physical ones. Virtual indexes allow the hardware to move mapped MCAM entries internally, enabling defragmentation and preventing scattered allocations across subbanks. The patch also enhances defragmentation by treating non-ref, non-contiguous allocations as ideal candidates for packing sparsely used regions, which can free up subbanks for potential x2 or x4 configuration. All such allocations are tracked and always returned as virtual indexes so they remain stable even when entries are moved during defrag. During defragmentation, MCAM entries may shift between subbanks, but their virtual indexes remain unchanged. Additionally, this update fixes an issue where entry statistics were not being restored correctly after defragmentation. Signed-off-by: Ratheesh Kannoth --- .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 831 +++++++++++++++++- .../ethernet/marvell/octeontx2/af/cn20k/npc.h | 30 +- .../net/ethernet/marvell/octeontx2/af/mbox.h | 5 + .../marvell/octeontx2/af/rvu_devlink.c | 90 +- .../ethernet/marvell/octeontx2/af/rvu_npc.c | 26 +- .../ethernet/marvell/octeontx2/af/rvu_npc.h | 2 + .../marvell/octeontx2/af/rvu_npc_fs.c | 6 + 7 files changed, 966 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.c index f1d9705fa872..7306414d1cf2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c @@ -215,6 +215,231 @@ struct npc_mcam_kex_extr *npc_mkex_extr_default_get(v= oid) return &npc_mkex_extr_default; } =20 +static u16 npc_idx2vidx(u16 idx) +{ + unsigned long index; + void *map; + u16 vidx; + int val; + + vidx =3D idx; + index =3D idx; + + map =3D xa_load(&npc_priv.xa_idx2vidx_map, index); + if (!map) + goto done; + + val =3D xa_to_value(map); + if (val =3D=3D -1) + goto done; + + vidx =3D val; + +done: + return vidx; +} + +static bool npc_is_vidx(u16 vidx) +{ + return vidx >=3D npc_priv.bank_depth * 2; +} + +static u16 npc_vidx2idx(u16 vidx) +{ + unsigned long index; + void *map; + int val; + u16 idx; + + idx =3D vidx; + index =3D vidx; + + map =3D xa_load(&npc_priv.xa_vidx2idx_map, index); + if (!map) + goto done; + + val =3D xa_to_value(map); + if (val =3D=3D -1) + goto done; + + idx =3D val; + +done: + return idx; +} + +u16 npc_cn20k_vidx2idx(u16 idx) +{ + if (!npc_priv.init_done) + return idx; + + if (!npc_is_vidx(idx)) + return idx; + + return npc_vidx2idx(idx); +} + +u16 npc_cn20k_idx2vidx(u16 idx) +{ + if (!npc_priv.init_done) + return idx; + + if (npc_is_vidx(idx)) + return idx; + + return npc_idx2vidx(idx); +} + +static int npc_vidx_maps_del_entry(struct rvu *rvu, u16 vidx, u16 *old_mid= x) +{ + u16 mcam_idx; + void *map; + + if (!npc_is_vidx(vidx)) { + dev_err(rvu->dev, + "%s: vidx(%u) does not map to proper mcam idx\n", + __func__, vidx); + return -ESRCH; + } + + mcam_idx =3D npc_vidx2idx(vidx); + + map =3D xa_erase(&npc_priv.xa_vidx2idx_map, vidx); + if (!map) { + dev_err(rvu->dev, + "%s: vidx(%u) does not map to proper mcam idx\n", + __func__, vidx); + return -ESRCH; + } + + map =3D xa_erase(&npc_priv.xa_idx2vidx_map, mcam_idx); + if (!map) { + dev_err(rvu->dev, + "%s: mcam idx(%u) is not valid\n", + __func__, vidx); + return -ESRCH; + } + + if (old_midx) + *old_midx =3D mcam_idx; + + return 0; +} + +static int npc_vidx_maps_modify(struct rvu *rvu, u16 vidx, u16 new_midx) +{ + u16 old_midx; + void *map; + int rc; + + if (!npc_is_vidx(vidx)) { + dev_err(rvu->dev, + "%s: vidx(%u) does not map to proper mcam idx\n", + __func__, vidx); + return -ESRCH; + } + + map =3D xa_erase(&npc_priv.xa_vidx2idx_map, vidx); + if (!map) { + dev_err(rvu->dev, + "%s: vidx(%u) could not be deleted from vidx2idx map\n", + __func__, vidx); + return -ESRCH; + } + + old_midx =3D xa_to_value(map); + + rc =3D xa_insert(&npc_priv.xa_vidx2idx_map, vidx, + xa_mk_value(new_midx), GFP_KERNEL); + if (rc) { + dev_err(rvu->dev, + "%s: vidx(%u) cannot be added to vidx2idx map\n", + __func__, vidx); + goto fail1; + } + + map =3D xa_erase(&npc_priv.xa_idx2vidx_map, old_midx); + if (!map) { + dev_err(rvu->dev, + "%s: old_midx(%u, vidx(%u)) cannot be added to idx2vidx map\n", + __func__, old_midx, vidx); + rc =3D -ESRCH; + goto fail2; + } + + rc =3D xa_insert(&npc_priv.xa_idx2vidx_map, new_midx, + xa_mk_value(vidx), GFP_KERNEL); + if (rc) { + dev_err(rvu->dev, + "%s: new_midx(%u, vidx(%u)) cannot be added to idx2vidx map\n", + __func__, new_midx, vidx); + goto fail3; + } + + return 0; + +fail3: + if (xa_insert(&npc_priv.xa_idx2vidx_map, old_midx, + xa_mk_value(vidx), GFP_KERNEL)) + dev_err(rvu->dev, + "%s: Error to roll back idx2vidx old_midx=3D%u vidx=3D%u\n", + __func__, old_midx, vidx); +fail2: + if (xa_erase(&npc_priv.xa_vidx2idx_map, vidx)) + dev_err(rvu->dev, + "%s: Failed to roll back vidx2idx vidx=3D%u\n", + __func__, vidx); + +fail1: + if (xa_insert(&npc_priv.xa_vidx2idx_map, vidx, + xa_mk_value(old_midx), GFP_KERNEL)) + dev_err(rvu->dev, + "%s: Faled to roll back vidx2idx to old_midx=3D%u, vidx=3D%u\n", + __func__, old_midx, vidx); + + return rc; +} + +static int npc_vidx_maps_add_entry(struct rvu *rvu, u16 mcam_idx, int pcif= unc, + u16 *vidx) +{ + int rc, max, min; + u32 id; + + /* Virtual index start from maximum mcam index + 1 */ + max =3D npc_priv.bank_depth * 2 * 2 - 1; + min =3D npc_priv.bank_depth * 2; + + rc =3D xa_alloc(&npc_priv.xa_vidx2idx_map, &id, + xa_mk_value(mcam_idx), + XA_LIMIT(min, max), GFP_KERNEL); + if (rc) { + dev_err(rvu->dev, + "%s: Failed to add to vidx2idx map (%u)\n", + __func__, mcam_idx); + goto fail1; + } + + rc =3D xa_insert(&npc_priv.xa_idx2vidx_map, mcam_idx, + xa_mk_value(id), GFP_KERNEL); + if (rc) { + dev_err(rvu->dev, + "%s: Failed to add to idx2vidx map (%u)\n", + __func__, mcam_idx); + goto fail2; + } + + if (vidx) + *vidx =3D id; + + return 0; + +fail2: + xa_erase(&npc_priv.xa_vidx2idx_map, id); +fail1: + return rc; +} + static void npc_config_kpmcam(struct rvu *rvu, int blkaddr, const struct npc_kpu_profile_cam *kpucam, int kpm, int entry) @@ -1040,6 +1265,8 @@ int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struc= t rvu *rvu, int blkaddr, rc; u8 nix_intf; =20 + req->entry =3D npc_cn20k_vidx2idx(req->entry); + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) return NPC_MCAM_INVALID_REQ; @@ -1081,6 +1308,8 @@ int rvu_mbox_handler_npc_cn20k_mcam_read_entry(struct= rvu *rvu, u16 pcifunc =3D req->hdr.pcifunc; int blkaddr, rc; =20 + req->entry =3D npc_cn20k_vidx2idx(req->entry); + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) return NPC_MCAM_INVALID_REQ; @@ -1121,6 +1350,7 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_e= ntry(struct rvu *rvu, entry_req.ref_prio =3D req->ref_prio; entry_req.ref_entry =3D req->ref_entry; entry_req.count =3D 1; + entry_req.virt =3D req->virt; =20 rc =3D rvu_mbox_handler_npc_mcam_alloc_entry(rvu, &entry_req, &entry_rsp); @@ -1130,7 +1360,7 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_e= ntry(struct rvu *rvu, if (!entry_rsp.count) return NPC_MCAM_ALLOC_FAILED; =20 - entry =3D entry_rsp.entry; + entry =3D npc_cn20k_vidx2idx(entry_rsp.entry); mutex_lock(&mcam->lock); =20 if (is_npc_intf_tx(req->intf)) @@ -1144,7 +1374,7 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_e= ntry(struct rvu *rvu, =20 mutex_unlock(&mcam->lock); =20 - rsp->entry =3D entry; + rsp->entry =3D entry_rsp.entry; return 0; } =20 @@ -1367,8 +1597,8 @@ int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam= _idx, u8 *key_type) =20 /* mcam_idx should be less than (2 * bank depth) */ if (mcam_idx >=3D npc_priv.bank_depth * 2) { - dev_err(rvu->dev, "%s:%d bad params\n", - __func__, __LINE__); + dev_err(rvu->dev, "%s: bad params\n", + __func__); return -EINVAL; } =20 @@ -1382,8 +1612,8 @@ int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam= _idx, u8 *key_type) * number of subbanks available */ if (sb_id >=3D npc_priv.num_subbanks) { - dev_err(rvu->dev, "%s:%d invalid subbank %d\n", - __func__, __LINE__, sb_id); + dev_err(rvu->dev, "%s: invalid subbank %d\n", + __func__, sb_id); return -EINVAL; } =20 @@ -2214,14 +2444,15 @@ static int npc_idx_free(struct rvu *rvu, u16 *mcam_= idx, int count, bool maps_del) { struct npc_subbank *sb; - int idx, i; + u16 vidx, midx; + int sb_off, i; bool ret; int rc; =20 /* Check if we can dealloc indexes properly ? */ for (i =3D 0; i < count; i++) { rc =3D npc_mcam_idx_2_subbank_idx(rvu, mcam_idx[i], - &sb, &idx); + &sb, &sb_off); if (rc) { dev_err(rvu->dev, "Failed to free mcam idx=3D%u\n", mcam_idx[i]); @@ -2230,19 +2461,50 @@ static int npc_idx_free(struct rvu *rvu, u16 *mcam_= idx, int count, } =20 for (i =3D 0; i < count; i++) { - rc =3D npc_mcam_idx_2_subbank_idx(rvu, mcam_idx[i], - &sb, &idx); - if (rc) + if (npc_is_vidx(mcam_idx[i])) { + vidx =3D mcam_idx[i]; + midx =3D npc_vidx2idx(vidx); + } else { + midx =3D mcam_idx[i]; + vidx =3D npc_idx2vidx(midx); + } + + if (midx >=3D npc_priv.bank_depth * npc_priv.num_banks) { + dev_err(rvu->dev, + "%s: Invalid mcam_idx=3D%u cannot be deleted\n", + __func__, mcam_idx[i]); + return -EINVAL; + } + + rc =3D npc_mcam_idx_2_subbank_idx(rvu, midx, + &sb, &sb_off); + if (rc) { + dev_err(rvu->dev, + "%s: Failed to find subbank info for vidx=3D%u\n", + __func__, vidx); return rc; + } =20 - ret =3D npc_subbank_free(rvu, sb, idx); - if (ret) + ret =3D npc_subbank_free(rvu, sb, sb_off); + if (ret) { + dev_err(rvu->dev, + "%s: Failed to find subbank info for vidx=3D%u\n", + __func__, vidx); return -EINVAL; + } =20 if (!maps_del) continue; =20 - rc =3D npc_del_from_pf_maps(rvu, mcam_idx[i]); + rc =3D npc_del_from_pf_maps(rvu, midx); + if (rc) + return rc; + + /* If there is no vidx mapping; continue */ + if (vidx =3D=3D midx) + continue; + + rc =3D npc_vidx_maps_del_entry(rvu, vidx, NULL); if (rc) return rc; } @@ -2758,10 +3020,12 @@ int npc_cn20k_idx_free(struct rvu *rvu, u16 *mcam_i= dx, int count) =20 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) + bool contig, int count, bool virt) { + bool defrag_candidate =3D false; int i, eidx, rc, bd; bool ref_valid; + u16 vidx; =20 bd =3D npc_priv.bank_depth; =20 @@ -2779,6 +3043,7 @@ int npc_cn20k_ref_idx_alloc(struct rvu *rvu, int pcif= unc, int key_type, } =20 ref_valid =3D !!(limit || ref); + defrag_candidate =3D !ref_valid && !contig && virt; if (!ref_valid) { if (contig && count > npc_priv.subbank_depth) goto try_noref_multi_subbank; @@ -2847,6 +3112,16 @@ int npc_cn20k_ref_idx_alloc(struct rvu *rvu, int pci= func, int key_type, rc =3D npc_add_to_pf_maps(rvu, mcam_idx[i], pcifunc); if (rc) return rc; + + if (!defrag_candidate) + continue; + + rc =3D npc_vidx_maps_add_entry(rvu, mcam_idx[i], pcifunc, &vidx); + if (rc) + return rc; + + /* Return vidx to caller */ + mcam_idx[i] =3D vidx; } =20 return 0; @@ -3021,6 +3296,523 @@ static int npc_pcifunc_map_create(struct rvu *rvu) return cnt; } =20 +struct npc_defrag_node { + u8 idx; + u8 key_type; + bool valid; + bool refs; + u16 free_cnt; + u16 vidx_cnt; + u16 *vidx; + struct list_head list; +}; + +static bool npc_defrag_skip_restricted_sb(int sb_id) +{ + int i; + + if (!restrict_valid) + return false; + + for (i =3D 0; i < ARRAY_SIZE(npc_subbank_restricted_idxs); i++) + if (sb_id =3D=3D npc_subbank_restricted_idxs[i]) + return true; + return false; +} + +/* Find subbank with minimum number of virtual indexes */ +static struct npc_defrag_node *npc_subbank_min_vidx(struct list_head *lh) +{ + struct npc_defrag_node *node, *tnode =3D NULL; + int min =3D INT_MAX; + + list_for_each_entry(node, lh, list) { + if (!node->valid) + continue; + + /* if subbank has ref allocated mcam indexes, that subbank + * is not a good candidate to move out indexes. + */ + if (node->refs) + continue; + + if (min > node->vidx_cnt) { + min =3D node->vidx_cnt; + tnode =3D node; + } + } + + return tnode; +} + +/* Find subbank with maximum number of free spaces */ +static struct npc_defrag_node *npc_subbank_max_free(struct list_head *lh) +{ + struct npc_defrag_node *node, *tnode =3D NULL; + int max =3D INT_MIN; + + list_for_each_entry(node, lh, list) { + if (!node->valid) + continue; + + if (max < node->free_cnt) { + max =3D node->free_cnt; + tnode =3D node; + } + } + + return tnode; +} + +static int npc_defrag_alloc_free_slots(struct rvu *rvu, + struct npc_defrag_node *f, + int cnt, u16 *save) +{ + int alloc_cnt1, alloc_cnt2; + struct npc_subbank *sb; + int rc, sb_off, i; + bool deleted; + + sb =3D &npc_priv.sb[f->idx]; + + alloc_cnt1 =3D 0; + alloc_cnt2 =3D 0; + + rc =3D __npc_subbank_alloc(rvu, sb, + NPC_MCAM_KEY_X2, sb->b0b, + sb->b0t, + NPC_MCAM_LOWER_PRIO, + false, cnt, save, cnt, true, + &alloc_cnt1); + if (alloc_cnt1 < cnt) { + rc =3D __npc_subbank_alloc(rvu, sb, + NPC_MCAM_KEY_X2, sb->b1b, + sb->b1t, + NPC_MCAM_LOWER_PRIO, + false, cnt - alloc_cnt1, + save + alloc_cnt1, + cnt - alloc_cnt1, + true, &alloc_cnt2); + } + + if (alloc_cnt1 + alloc_cnt2 !=3D cnt) { + dev_err(rvu->dev, + "%s: Failed to alloc cnt=3D%u alloc_cnt1=3D%u alloc_cnt2=3D%u\n", + __func__, cnt, alloc_cnt1, alloc_cnt2); + goto fail_free_alloc; + } + return 0; + +fail_free_alloc: + for (i =3D 0; i < alloc_cnt1 + alloc_cnt2; i++) { + rc =3D npc_mcam_idx_2_subbank_idx(rvu, save[i], + &sb, &sb_off); + if (rc) { + dev_err(rvu->dev, + "%s: Error to find subbank for mcam idx=3D%u\n", + __func__, save[i]); + break; + } + + deleted =3D __npc_subbank_free(rvu, sb, sb_off); + if (!deleted) { + dev_err(rvu->dev, + "%s: Error to free mcam idx=3D%u\n", + __func__, save[i]); + break; + } + } + + return rc; +} + +static int npc_defrag_add_2_show_list(struct rvu *rvu, u16 old_midx, + u16 new_midx, u16 vidx) +{ + struct npc_defrag_show_node *node; + + node =3D kcalloc(1, sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + + node->old_midx =3D old_midx; + node->new_midx =3D new_midx; + node->vidx =3D vidx; + INIT_LIST_HEAD(&node->list); + + mutex_lock(&npc_priv.lock); + list_add_tail(&node->list, &npc_priv.defrag_lh); + mutex_unlock(&npc_priv.lock); + + return 0; +} + +static +int npc_defrag_move_vdx_to_free(struct rvu *rvu, + struct npc_defrag_node *f, + struct npc_defrag_node *v, + int cnt, u16 *save) +{ + struct npc_mcam *mcam =3D &rvu->hw->mcam; + int i, vidx_cnt, rc, sb_off; + u16 new_midx, old_midx, vidx; + struct npc_subbank *sb; + bool deleted; + u16 pcifunc; + int blkaddr; + void *map; + u8 bank; + u16 midx; + u64 stats; + + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + + vidx_cnt =3D v->vidx_cnt; + for (i =3D 0; i < cnt; i++) { + vidx =3D v->vidx[vidx_cnt - i - 1]; + old_midx =3D npc_vidx2idx(vidx); + new_midx =3D save[cnt - i - 1]; + + dev_dbg(rvu->dev, + "%s: Moving %u ---> %u (vidx=3D%u)\n", + __func__, + old_midx, new_midx, vidx); + + rc =3D npc_defrag_add_2_show_list(rvu, old_midx, new_midx, vidx); + if (rc) + dev_err(rvu->dev, + "%s: Error happened to add to show list vidx=3D%u\n", + __func__, vidx); + + /* Modify vidx to point to new mcam idx */ + rc =3D npc_vidx_maps_modify(rvu, vidx, new_midx); + if (rc) + return rc; + + midx =3D old_midx % mcam->banksize; + bank =3D old_midx / mcam->banksize; + stats =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(midx, + bank)); + + npc_cn20k_enable_mcam_entry(rvu, blkaddr, old_midx, false); + npc_cn20k_copy_mcam_entry(rvu, blkaddr, old_midx, new_midx); + npc_cn20k_enable_mcam_entry(rvu, blkaddr, new_midx, true); + + midx =3D new_midx % mcam->banksize; + bank =3D new_midx / mcam->banksize; + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(midx, bank), + stats); + + /* Free the old mcam idx */ + rc =3D npc_mcam_idx_2_subbank_idx(rvu, old_midx, + &sb, &sb_off); + if (rc) { + dev_err(rvu->dev, + "%s: Unable to calculate subbank off for mcamidx=3D%u\n", + __func__, old_midx); + return rc; + } + + deleted =3D __npc_subbank_free(rvu, sb, sb_off); + if (!deleted) { + dev_err(rvu->dev, + "%s: Failed to free mcamidx=3D%u sb=3D%u sb_off=3D%u\n", + __func__, old_midx, sb->idx, sb_off); + return -EFAULT; + } + + /* save pcifunc */ + map =3D xa_load(&npc_priv.xa_idx2pf_map, old_midx); + pcifunc =3D xa_to_value(map); + + /* delete from pf maps */ + rc =3D npc_del_from_pf_maps(rvu, old_midx); + if (rc) { + dev_err(rvu->dev, + "%s: Failed to delete pf maps for mcamidx=3D%u\n", + __func__, old_midx); + return rc; + } + + /* add new mcam_idx to pf map */ + rc =3D npc_add_to_pf_maps(rvu, new_midx, pcifunc); + if (rc) { + dev_err(rvu->dev, + "%s: Failed to add pf maps for mcamidx=3D%u\n", + __func__, new_midx); + return rc; + } + + /* Remove from mcam maps */ + mcam->entry2pfvf_map[old_midx] =3D NPC_MCAM_INVALID_MAP; + mcam->entry2cntr_map[old_midx] =3D NPC_MCAM_INVALID_MAP; + npc_mcam_clear_bit(mcam, old_midx); + + mcam->entry2pfvf_map[new_midx] =3D pcifunc; + mcam->entry2cntr_map[new_midx] =3D new_midx; + npc_mcam_set_bit(mcam, new_midx); + + /* Mark as invalid */ + v->vidx[vidx_cnt - i - 1] =3D -1; + save[cnt - i - 1] =3D -1; + + f->free_cnt--; + v->vidx_cnt--; + } + + return 0; +} + +static int npc_defrag_process(struct rvu *rvu, struct list_head *lh) +{ + struct npc_defrag_node *v =3D NULL; + struct npc_defrag_node *f =3D NULL; + int rc =3D 0, cnt; + u16 *save; + + while (1) { + /* Find subbank with minimum vidx */ + if (!v) { + v =3D npc_subbank_min_vidx(lh); + if (!v) + break; + } + + /* Find subbank with maximum free slots */ + if (!f) { + f =3D npc_subbank_max_free(lh); + if (!f) + break; + } + + if (!v->vidx_cnt) { + list_del_init(&v->list); + v =3D NULL; + continue; + } + + if (!f->free_cnt) { + list_del_init(&f->list); + f =3D NULL; + continue; + } + + /* If both subbanks are same, choose vidx and + * search for free list again + */ + if (f =3D=3D v) { + list_del_init(&f->list); + f =3D NULL; + continue; + } + + /* Calculate minimum free slots needs to be allocated */ + cnt =3D f->free_cnt > v->vidx_cnt ? v->vidx_cnt : + f->free_cnt; + + dev_dbg(rvu->dev, + "%s: cnt=3D%u free_cnt=3D%u(sb=3D%u) vidx_cnt=3D%u(sb=3D%u)\n", + __func__, cnt, f->free_cnt, f->idx, + v->vidx_cnt, v->idx); + + /* Allocate an array to store newly allocated + * free slots (mcam indexes) + */ + save =3D kcalloc(cnt, sizeof(*save), GFP_KERNEL); + if (!save) { + rc =3D -ENOMEM; + goto err; + } + + /* Alloc free slots for existing vidx */ + rc =3D npc_defrag_alloc_free_slots(rvu, f, cnt, save); + if (rc) { + kfree(save); + goto err; + } + + /* Move vidx to free slots; update pf_map and vidx maps, + * and free existing vidx mcam slots + */ + rc =3D npc_defrag_move_vdx_to_free(rvu, f, v, cnt, save); + if (rc) { + kfree(save); + goto err; + } + + kfree(save); + + if (!f->free_cnt) { + list_del_init(&f->list); + f =3D NULL; + } + + if (!v->vidx_cnt) { + list_del_init(&v->list); + v =3D NULL; + } + } + +err: + /* Whole defragmentation process is done within locks. if there + * is an error, it would be hard to roll back as index remove/add + * can fail again if it failed before. This would mean that there + * is bug in the index management algorithm. + * Return from here than rolling back. + */ + return rc; +} + +static void npc_defrag_list_clear(void) +{ + struct npc_defrag_show_node *node, *next; + + mutex_lock(&npc_priv.lock); + list_for_each_entry_safe(node, next, &npc_priv.defrag_lh, list) { + list_del_init(&node->list); + kfree(node); + } + + mutex_unlock(&npc_priv.lock); +} + +static void npc_lock_all_subbank(void) +{ + int i; + + for (i =3D 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 =3D npc_priv.num_subbanks - 1; i >=3D 0; i--) + mutex_unlock(&npc_priv.sb[i].lock); +} + +/* Only non-ref non-contigous mcam indexes + * are picked for defrag process + */ +int npc_cn20k_defrag(struct rvu *rvu) +{ + struct npc_mcam *mcam =3D &rvu->hw->mcam; + struct npc_defrag_node *node, *tnode; + struct list_head x4lh, x2lh, *lh; + int rc =3D 0, i, sb_off, tot; + struct npc_subbank *sb; + unsigned long index; + void *map; + u16 midx; + + /* Free previous show list */ + npc_defrag_list_clear(); + + INIT_LIST_HEAD(&x4lh); + INIT_LIST_HEAD(&x2lh); + + node =3D kcalloc(npc_priv.num_subbanks, sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + + /* Lock mcam */ + mutex_lock(&mcam->lock); + npc_lock_all_subbank(); + + /* Fill in node with subbank properties */ + for (i =3D 0; i < npc_priv.num_subbanks; i++) { + sb =3D &npc_priv.sb[i]; + + node[i].idx =3D i; + node[i].key_type =3D sb->key_type; + node[i].free_cnt =3D sb->free_cnt; + node[i].vidx =3D kcalloc(npc_priv.subbank_depth * 2, + sizeof(*node[i].vidx), + GFP_KERNEL); + if (!node[i].vidx) { + rc =3D -ENOMEM; + goto free_vidx; + } + + /* If subbank is empty, dont include it in defrag + * process + */ + if (sb->flags & NPC_SUBBANK_FLAG_FREE) { + node[i].valid =3D false; + continue; + } + + if (npc_defrag_skip_restricted_sb(i)) { + node[i].valid =3D false; + continue; + } + + node[i].valid =3D true; + INIT_LIST_HEAD(&node[i].list); + + /* Add node to x2 or x4 list */ + lh =3D sb->key_type =3D=3D NPC_MCAM_KEY_X2 ? &x2lh : &x4lh; + list_add_tail(&node[i].list, lh); + } + + /* Filling vidx[] array with all vidx in that subbank */ + xa_for_each_start(&npc_priv.xa_vidx2idx_map, index, map, + npc_priv.bank_depth * 2) { + midx =3D xa_to_value(map); + rc =3D npc_mcam_idx_2_subbank_idx(rvu, midx, + &sb, &sb_off); + if (rc) { + dev_err(rvu->dev, + "%s: Error to get mcam_idx for vidx=3D%lu\n", + __func__, index); + goto free_vidx; + } + + tnode =3D &node[sb->idx]; + tnode->vidx[tnode->vidx_cnt] =3D index; + tnode->vidx_cnt++; + } + + /* Mark all subbank which has ref allocation */ + for (i =3D 0; i < npc_priv.num_subbanks; i++) { + tnode =3D &node[i]; + + if (!tnode->valid) + continue; + + tot =3D (tnode->key_type =3D=3D NPC_MCAM_KEY_X2) ? + npc_priv.subbank_depth * 2 : npc_priv.subbank_depth; + + if (node[i].vidx_cnt !=3D tot - tnode->free_cnt) + tnode->refs =3D true; + } + + rc =3D npc_defrag_process(rvu, &x2lh); + if (rc) + goto free_vidx; + + rc =3D npc_defrag_process(rvu, &x4lh); + if (rc) + goto free_vidx; + +free_vidx: + npc_unlock_all_subbank(); + mutex_unlock(&mcam->lock); + for (i =3D 0; i < npc_priv.num_subbanks; i++) + kfree(node[i].vidx); + kfree(node); + return rc; +} + +int rvu_mbox_handler_npc_defrag(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) +{ + return npc_cn20k_defrag(rvu); +} + int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast, u16 *mcast, u16 *promisc, u16 *ucast) { @@ -3424,6 +4216,8 @@ static int npc_priv_init(struct rvu *rvu) xa_init_flags(&npc_priv.xa_idx2pf_map, XA_FLAGS_ALLOC); xa_init_flags(&npc_priv.xa_pf_map, XA_FLAGS_ALLOC); xa_init_flags(&npc_priv.xa_pf2dfl_rmap, XA_FLAGS_ALLOC); + xa_init_flags(&npc_priv.xa_idx2vidx_map, XA_FLAGS_ALLOC); + xa_init_flags(&npc_priv.xa_vidx2idx_map, XA_FLAGS_ALLOC); =20 if (npc_create_srch_order(num_subbanks)) goto fail1; @@ -3445,6 +4239,9 @@ static int npc_priv_init(struct rvu *rvu) for (i =3D 0; i < npc_priv.pf_cnt; i++) xa_init_flags(&npc_priv.xa_pf2idx_map[i], XA_FLAGS_ALLOC); =20 + INIT_LIST_HEAD(&npc_priv.defrag_lh); + mutex_init(&npc_priv.lock); + return 0; =20 fail2: @@ -3456,6 +4253,8 @@ static int npc_priv_init(struct rvu *rvu) xa_destroy(&npc_priv.xa_idx2pf_map); xa_destroy(&npc_priv.xa_pf_map); xa_destroy(&npc_priv.xa_pf2dfl_rmap); + xa_destroy(&npc_priv.xa_idx2vidx_map); + xa_destroy(&npc_priv.xa_vidx2idx_map); kfree(npc_priv.sb); return -ENOMEM; } @@ -3469,6 +4268,8 @@ void npc_cn20k_deinit(struct rvu *rvu) xa_destroy(&npc_priv.xa_idx2pf_map); xa_destroy(&npc_priv.xa_pf_map); xa_destroy(&npc_priv.xa_pf2dfl_rmap); + xa_destroy(&npc_priv.xa_idx2vidx_map); + xa_destroy(&npc_priv.xa_vidx2idx_map); =20 for (i =3D 0; i < npc_priv.pf_cnt; i++) xa_destroy(&npc_priv.xa_pf2idx_map[i]); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.h index 13a605f183c6..178051b2535a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h @@ -147,6 +147,23 @@ struct npc_subbank { u8 key_type; }; =20 +/** + * struct npc_defrag_show_node - Defragmentation show node + * @old_midx: Old mcam index. + * @new_midx: New mcam index. + * @vidx: Virtual index + * @list: Linked list of these nodes + * + * This structure holds information on last defragmentation + * executed on mcam resource. + */ +struct npc_defrag_show_node { + u16 old_midx; + u16 new_midx; + u16 vidx; + struct list_head list; +}; + /** * struct npc_priv_t - NPC private structure. * @bank_depth: Total entries in each bank. @@ -163,6 +180,10 @@ struct npc_subbank { * @pf_cnt: Number of PFs.A * @init_done: Indicates MCAM initialization is done. * @xa_pf2dfl_rmap: PF to default rule index map. + * @xa_idx2vidx_map: Mcam index to virtual index map. + * @xa_vidx2idx_map: virtual index to mcam index map. + * @defrag_lh: Defrag list head. + * @lock: Lock for defrag list * * This structure is populated during probing time by reading * HW csr registers. @@ -180,6 +201,10 @@ struct npc_priv_t { struct xarray xa_idx2pf_map; struct xarray xa_pf_map; struct xarray xa_pf2dfl_rmap; + struct xarray xa_idx2vidx_map; + struct xarray xa_vidx2idx_map; + struct list_head defrag_lh; + struct mutex lock; /* protect defrag nodes */ int pf_cnt; bool init_done; }; @@ -276,7 +301,7 @@ void npc_cn20k_subbank_calc_free(struct rvu *rvu, int *= x2_free, =20 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); + bool contig, int count, bool virt); int npc_cn20k_idx_free(struct rvu *rvu, u16 *mcam_idx, int count); void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr); struct npc_mcam_kex_extr *npc_mkex_extr_default_get(void); @@ -309,5 +334,8 @@ void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blk= addr, u16 index, void npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int bank, int index); int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type); +u16 npc_cn20k_vidx2idx(u16 index); +u16 npc_cn20k_idx2vidx(u16 idx); +int npc_cn20k_defrag(struct rvu *rvu); =20 #endif /* NPC_CN20K_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index e004271124df..1638bf4e15fd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -298,6 +298,9 @@ M(NPC_CN20K_MCAM_READ_ENTRY, 0x6019, npc_cn20k_mcam_rea= d_entry, \ npc_cn20k_mcam_read_entry_rsp) \ M(NPC_CN20K_MCAM_READ_BASE_RULE, 0x601a, npc_cn20k_read_base_steer_rule, = \ msg_req, npc_cn20k_mcam_read_base_rule_rsp) \ +M(NPC_MCAM_DEFRAG, 0x601b, npc_defrag, \ + msg_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) \ @@ -1554,6 +1557,7 @@ struct npc_mcam_alloc_entry_req { u16 ref_entry; u16 count; /* Number of entries requested */ u8 kw_type; /* entry key type, valid for cn20k */ + u8 virt; /* Request virtual index */ }; =20 struct npc_mcam_alloc_entry_rsp { @@ -1689,6 +1693,7 @@ struct npc_cn20k_mcam_alloc_and_write_entry_req { u8 intf; /* Rx or Tx interface */ u8 enable_entry;/* Enable this MCAM entry ? */ u8 hw_prio; /* hardware priority, valid for cn20k */ + u8 virt; /* Allocate virtual index */ u16 reserved[4]; /* reserved for future use */ }; =20 diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/driv= ers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c index 0f9953eaf1b0..45d6fefa4e43 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c @@ -11,6 +11,7 @@ #include "rvu_reg.h" #include "rvu_struct.h" #include "rvu_npc_hash.h" +#include "cn20k/npc.h" =20 #define DRV_NAME "octeontx2-af" =20 @@ -1256,9 +1257,66 @@ enum rvu_af_dl_param_id { RVU_AF_DEVLINK_PARAM_ID_NPC_MCAM_ZONE_PERCENT, RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE, RVU_AF_DEVLINK_PARAM_ID_NPC_DEF_RULE_CNTR_ENABLE, + RVU_AF_DEVLINK_PARAM_ID_NPC_DEFRAG, RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF, }; =20 +static int rvu_af_npc_defrag_feature_get(struct devlink *devlink, u32 id, + struct devlink_param_gset_ctx *ctx, + struct netlink_ext_ack *extack) +{ + struct rvu_devlink *rvu_dl =3D devlink_priv(devlink); + struct rvu *rvu =3D rvu_dl->rvu; + bool enabled; + + enabled =3D is_cn20k(rvu->pdev); + + snprintf(ctx->val.vstr, sizeof(ctx->val.vstr), "%s", + enabled ? "enabled" : "disabled"); + + return 0; +} + +static int rvu_af_npc_defrag(struct devlink *devlink, u32 id, + struct devlink_param_gset_ctx *ctx, + struct netlink_ext_ack *extack) +{ + struct rvu_devlink *rvu_dl =3D devlink_priv(devlink); + struct rvu *rvu =3D rvu_dl->rvu; + + npc_cn20k_defrag(rvu); + + return 0; +} + +static int rvu_af_npc_defrag_feature_validate(struct devlink *devlink, u32= id, + union devlink_param_value val, + struct netlink_ext_ack *extack) +{ + struct rvu_devlink *rvu_dl =3D devlink_priv(devlink); + struct rvu *rvu =3D rvu_dl->rvu; + u64 enable; + + if (kstrtoull(val.vstr, 10, &enable)) { + NL_SET_ERR_MSG_MOD(extack, + "Only 1 value is supported"); + return -EINVAL; + } + + if (enable !=3D 1) { + NL_SET_ERR_MSG_MOD(extack, + "Only initiating defrag is supported"); + return -EINVAL; + } + + if (is_cn20k(rvu->pdev)) + return 0; + + NL_SET_ERR_MSG_MOD(extack, + "Can defrag NPC only in cn20k silicon"); + return -EFAULT; +} + static int rvu_af_npc_exact_feature_get(struct devlink *devlink, u32 id, struct devlink_param_gset_ctx *ctx, struct netlink_ext_ack *extack) @@ -1561,6 +1619,15 @@ static const struct devlink_ops rvu_devlink_ops =3D { .eswitch_mode_set =3D rvu_devlink_eswitch_mode_set, }; =20 +static const struct devlink_param rvu_af_dl_param_defrag[] =3D { + DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_DEFRAG, + "npc_defrag", DEVLINK_PARAM_TYPE_STRING, + BIT(DEVLINK_PARAM_CMODE_RUNTIME), + rvu_af_npc_defrag_feature_get, + rvu_af_npc_defrag, + rvu_af_npc_defrag_feature_validate), +}; + int rvu_register_dl(struct rvu *rvu) { struct rvu_devlink *rvu_dl; @@ -1593,6 +1660,17 @@ int rvu_register_dl(struct rvu *rvu) goto err_dl_health; } =20 + if (is_cn20k(rvu->pdev)) { + err =3D devlink_params_register(dl, rvu_af_dl_param_defrag, + ARRAY_SIZE(rvu_af_dl_param_defrag)); + if (err) { + dev_err(rvu->dev, + "devlink defrag params register failed with error %d", + err); + goto err_dl_defrag; + } + } + /* Register exact match devlink only for CN10K-B */ if (!rvu_npc_exact_has_match_table(rvu)) goto done; @@ -1601,7 +1679,8 @@ int rvu_register_dl(struct rvu *rvu) ARRAY_SIZE(rvu_af_dl_param_exact_match)); if (err) { dev_err(rvu->dev, - "devlink exact match params register failed with error %d", err); + "devlink exact match params register failed with error %d", + err); goto err_dl_exact_match; } =20 @@ -1610,6 +1689,11 @@ int rvu_register_dl(struct rvu *rvu) return 0; =20 err_dl_exact_match: + if (is_cn20k(rvu->pdev)) + devlink_params_unregister(dl, rvu_af_dl_param_defrag, + ARRAY_SIZE(rvu_af_dl_param_defrag)); + +err_dl_defrag: devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_para= ms)); =20 err_dl_health: @@ -1627,6 +1711,10 @@ void rvu_unregister_dl(struct rvu *rvu) =20 devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_para= ms)); =20 + if (is_cn20k(rvu->pdev)) + devlink_params_unregister(dl, rvu_af_dl_param_defrag, + ARRAY_SIZE(rvu_af_dl_param_defrag)); + /* Unregister exact match devlink only for CN10K-B */ if (rvu_npc_exact_has_match_table(rvu)) devlink_params_unregister(dl, rvu_af_dl_param_exact_match, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.c index 08f1c5e38ed9..1c50fd150bd3 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -2448,6 +2448,10 @@ static void npc_unmap_mcam_entry_and_cntr(struct rvu= *rvu, /* Remove mapping and reduce counter's refcnt */ mcam->entry2cntr_map[entry] =3D NPC_MCAM_INVALID_MAP; mcam->cntr_refcnt[cntr]--; + + if (is_cn20k(rvu->pdev)) + return; + /* Disable stats */ rvu_write64(rvu, blkaddr, NPC_AF_MCAMEX_BANKX_STAT_ACT(index, bank), 0x00); @@ -2457,7 +2461,7 @@ static void npc_unmap_mcam_entry_and_cntr(struct rvu = *rvu, * reverse bitmap too. Should be called with * 'mcam->lock' held. */ -static void npc_mcam_set_bit(struct npc_mcam *mcam, u16 index) +void npc_mcam_set_bit(struct npc_mcam *mcam, u16 index) { u16 entry, rentry; =20 @@ -2473,7 +2477,7 @@ static void npc_mcam_set_bit(struct npc_mcam *mcam, u= 16 index) * reverse bitmap too. Should be called with * 'mcam->lock' held. */ -static void npc_mcam_clear_bit(struct npc_mcam *mcam, u16 index) +void npc_mcam_clear_bit(struct npc_mcam *mcam, u16 index) { u16 entry, rentry; =20 @@ -2694,7 +2698,7 @@ static int npc_mcam_alloc_entries(struct npc_mcam *mc= am, u16 pcifunc, ret =3D npc_cn20k_ref_idx_alloc(rvu, pcifunc, req->kw_type, req->ref_prio, rsp->entry_list, req->ref_entry, limit, - req->contig, req->count); + req->contig, req->count, !!req->virt); =20 if (ret) { rsp->count =3D 0; @@ -2714,7 +2718,7 @@ static int npc_mcam_alloc_entries(struct npc_mcam *mc= am, u16 pcifunc, mutex_lock(&mcam->lock); /* Mark the allocated entries as used and set nixlf mapping */ for (entry =3D 0; entry < rsp->count; entry++) { - index =3D rsp->entry_list[entry]; + index =3D npc_cn20k_vidx2idx(rsp->entry_list[entry]); npc_mcam_set_bit(mcam, index); mcam->entry2pfvf_map[index] =3D pcifunc; mcam->entry2cntr_map[index] =3D NPC_MCAM_INVALID_MAP; @@ -3026,6 +3030,8 @@ int rvu_mbox_handler_npc_mcam_free_entry(struct rvu *= rvu, int blkaddr, rc =3D 0; u16 cntr; =20 + req->entry =3D npc_cn20k_vidx2idx(req->entry); + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) return NPC_MCAM_INVALID_REQ; @@ -3156,6 +3162,8 @@ int rvu_mbox_handler_npc_mcam_ena_entry(struct rvu *r= vu, u16 pcifunc =3D req->hdr.pcifunc; int blkaddr, rc; =20 + req->entry =3D npc_cn20k_vidx2idx(req->entry); + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) return NPC_MCAM_INVALID_REQ; @@ -3179,6 +3187,8 @@ int rvu_mbox_handler_npc_mcam_dis_entry(struct rvu *r= vu, u16 pcifunc =3D req->hdr.pcifunc; int blkaddr, rc; =20 + req->entry =3D npc_cn20k_vidx2idx(req->entry); + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) return NPC_MCAM_INVALID_REQ; @@ -3213,8 +3223,8 @@ int rvu_mbox_handler_npc_mcam_shift_entry(struct rvu = *rvu, =20 mutex_lock(&mcam->lock); for (index =3D 0; index < req->shift_count; index++) { - old_entry =3D req->curr_entry[index]; - new_entry =3D req->new_entry[index]; + old_entry =3D npc_cn20k_vidx2idx(req->curr_entry[index]); + new_entry =3D npc_cn20k_vidx2idx(req->new_entry[index]); =20 /* Check if both old and new entries are valid and * does belong to this PFFUNC or not. @@ -3256,7 +3266,7 @@ int rvu_mbox_handler_npc_mcam_shift_entry(struct rvu = *rvu, /* If shift has failed then report the failed index */ if (index !=3D req->shift_count) { rc =3D NPC_MCAM_PERM_DENIED; - rsp->failed_entry_idx =3D index; + rsp->failed_entry_idx =3D npc_cn20k_idx2vidx(index); } =20 mutex_unlock(&mcam->lock); @@ -3839,6 +3849,8 @@ int rvu_mbox_handler_npc_mcam_entry_stats(struct rvu = *rvu, if (blkaddr < 0) return NPC_MCAM_INVALID_REQ; =20 + req->entry =3D npc_cn20k_vidx2idx(req->entry); + index =3D req->entry & (mcam->banksize - 1); bank =3D npc_get_bank(mcam, req->entry); =20 diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.h index 346e6ada158e..83c5e32e2afc 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h @@ -16,4 +16,6 @@ void npc_config_kpuaction(struct rvu *rvu, int blkaddr, int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr, u64 *size); =20 +void npc_mcam_clear_bit(struct npc_mcam *mcam, u16 index); +void npc_mcam_set_bit(struct npc_mcam *mcam, u16 index); #endif /* RVU_NPC_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drive= rs/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index 584be2892ba7..bff190ba95e2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -1655,6 +1655,8 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu, bool enable =3D true; u16 target; =20 + req->entry =3D npc_cn20k_vidx2idx(req->entry); + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) { dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__); @@ -1808,6 +1810,10 @@ int rvu_mbox_handler_npc_delete_flow(struct rvu *rvu, struct list_head del_list; int blkaddr; =20 + req->entry =3D npc_cn20k_vidx2idx(req->entry); + req->start =3D npc_cn20k_vidx2idx(req->start); + req->end =3D npc_cn20k_vidx2idx(req->end); + INIT_LIST_HEAD(&del_list); =20 mutex_lock(&mcam->lock); --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D02F3126C2; Mon, 2 Feb 2026 07:46:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018423; cv=none; b=gJ1BYTtqieJupGeQ61r04pHsbhf7rvfddCyzdtqb6nNVYfj4MoNf0TRkcOPPXnvl+PUT224L8fNAxk8NDVWFScS69cLnW3IWQz1hKyOyfqt55loupDzfr8b1qhyMyHmNuKIKhmhNcRYYB1UqkcStoYCetfxtryuSO6DAnYwdGGg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018423; c=relaxed/simple; bh=z95Av594Dl7LvOIs9XcWuVVasE+xxRO6i+7G6DqQn+k=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=g/HriVTGXdZ/aSFxkKSqOBoGXDd8WwG7L1d0XHurgH4VpXLxyDqJ7ttdmTVEpAR9FOaDLOIPhuCEhZeEmAwIKmFcF1FGf3CXk2s2uqghu2ouAJ9daxp2uzDi9CT7jY95/7sh2VUF5sbP5FNP2wuCgLlTG1bUk7ebeZu13gO9mVo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=gRzIkAt6; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="gRzIkAt6" Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 611NTtHL2695784; Sun, 1 Feb 2026 23:46:50 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=b tUW9sg29XfKehOpnsiUbYXIuifCrNSY9P7xsZZJYng=; b=gRzIkAt6ku4SNYMOL b1W8ois58GIB0qQyPcqfXVtg2ezsss9Qg6bzdIqtC1c7YZfR07dlUCKTTvtb1UgG SC6uXBq41cd/qedZKL/EhDSkkSu8kQyKn6VDx8mBiWHQqVcQD7Yi2t+7aToZfRTq Y+0rPISaIf+umKteqwc/d6zEtHak7VAb+FkqBClXCDOLIUvKArUQMqYB2S3m1pzC nzWCCcsUNiuwvYYQGDvHMjGQ66Zk6sUBI6XLi9udpdK9On/cNFS9ieTYSHSpU3n9 3zDPgPuR6FY8O832qfDSPsQxESbS/pVARwmiifZKMDi4bw5OVOkSJBBFH2fDU0bH 53SUg== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4c28pe1892-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:50 -0800 (PST) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:47:06 -0800 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:47:06 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 7268D5B6947; Sun, 1 Feb 2026 23:46:46 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH net-next v8 10/13] octeontx2-af: npc: cn20k: Allocate MCAM entry for flow installation Date: Mon, 2 Feb 2026 13:16:04 +0530 Message-ID: <20260202074607.2535569-11-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: DIYUFtjrNsRSxTRh7BPIXgAmXdJU58ox X-Authority-Analysis: v=2.4 cv=Y4/1cxeN c=1 sm=1 tr=0 ts=6980566a cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=R86mbzlVWIuRp1_vrRQA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfX7QZGydd7Y4tk YExayU6Tmeo+M8jMyBSX0PsMK+Dk1h831tw2KEaXTV14bdSUXj/PyWKOw8eVaPxQnMkTW1esOph oW8Tp61bGmhEHrtjIHSHLBcMRpAmh7WF5pBsZ2ONrMLFU+spUN4vw1xJshEfhnjvhFQ1urgdglw TfFEaXalLl2I0feuEbzr5bVKOixEI9mM7yZIP/r7tviNMvGt60hLFNDShA9R83JH9Q9Wl0ohwsH uaN1YjVlEOq2yIat+RlkgbHyXHSQqfZXRxr3oWfH1uYtk/wffKTMDdS622XK6fGwS4sz9RQV68Q k1j9IDXdqI8TuH8Ju/7IoXonj12VQxerI6f7ulp1/IzabFWR3Qeinja/mK4Ha1yPVP7CnhpDOxI PGYyWyDymDFgz3XfgprRqxUifIixbd3xEcN2ZYL+GZwf9mibnnn1bCKq0k3ZeQKqsTAO/g6gQ6N pZ9ud12tPUflDgSKxXQ== X-Proofpoint-GUID: DIYUFtjrNsRSxTRh7BPIXgAmXdJU58ox X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" In CN20K, the PF/VF driver is unaware of the NPC MCAM entry type (x2/x4) required for a particular TC rule when the user installs rules through the TC command. This forces the PF/VF driver to first query the AF driver for the rule size, then allocate an entry, and finally install the flow. This sequence requires three mailbox request/response exchanges from the PF. To speed up the installation, the `install_flow` mailbox request message is extended with additional fields that allow the AF driver to determine the required NPC MCAM entry type, allocate the MCAM entry, and complete the flow installation in a single step. Signed-off-by: Ratheesh Kannoth --- .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 184 ++++++++++-- .../ethernet/marvell/octeontx2/af/cn20k/npc.h | 5 +- .../net/ethernet/marvell/octeontx2/af/mbox.h | 48 ++++ .../ethernet/marvell/octeontx2/af/rvu_npc.c | 4 + .../marvell/octeontx2/af/rvu_npc_fs.c | 137 ++++++++- .../marvell/octeontx2/af/rvu_npc_fs.h | 12 + .../marvell/octeontx2/nic/otx2_flows.c | 265 +++++++++++++++++- 7 files changed, 598 insertions(+), 57 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.c index 7306414d1cf2..237e6f606fc1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c @@ -14,6 +14,7 @@ #include "rvu_npc.h" #include "cn20k/npc.h" #include "cn20k/reg.h" +#include "rvu_npc_fs.h" =20 static struct npc_priv_t npc_priv =3D { .num_banks =3D MAX_NUM_BANKS, @@ -799,7 +800,7 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkadd= r, cfg =3D rvu_read64(rvu, blkaddr, NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank)); - hw_prio =3D cfg & GENMASK_ULL(14, 8); + hw_prio =3D cfg & GENMASK_ULL(30, 24); cfg =3D enable ? 1 : 0; cfg |=3D hw_prio; rvu_write64(rvu, blkaddr, @@ -815,7 +816,7 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkadd= r, cfg =3D rvu_read64(rvu, blkaddr, NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank)); - hw_prio =3D cfg & GENMASK_ULL(14, 8); + hw_prio =3D cfg & GENMASK_ULL(30, 24); cfg =3D enable ? 1 : 0; cfg |=3D hw_prio; rvu_write64(rvu, blkaddr, @@ -882,25 +883,33 @@ static void npc_cn20k_get_keyword(struct cn20k_mcam_e= ntry *entry, int idx, *cam0 =3D ~*cam1 & kw_mask; } =20 -/*------------------------------------------------------------------------= -----| - *Kex type | mcam entry | cam1 | cam 0 || <----- output ----> | - *profile | len | (key type) | (key type) || len | type | - *------------------------------------------------------------------------= -----| - *X2 | 256 (X2) | 001b | 110b || X2 | X2 | - *------------------------------------------------------------------------= -----| - *X4 | 256 (X2) | 000b | 000b || X2 | DYNAMIC | - *------------------------------------------------------------------------= -----| - *X4 | 512 (X4) | 010b | 101b || X4 | X4 | - *------------------------------------------------------------------------= -----| - *DYN | 256 (X2) | 000b | 000b || X2 | DYNAMIC | - *------------------------------------------------------------------------= -----| - *DYN | 512 (X4) | 010b | 101b || X4 | X4 | - *------------------------------------------------------------------------= -----| +/*------------------------------------------------------------------------- + *Kex type| mcam | cam1 |cam0 | req_kwtype||<----- output > | + * in | | | | || | | + * profile| len | | | ||len | type | + *------------------------------------------------------------------------- + *X2 | 256 (X2) | 001b |110b | 0 ||X2 | X2 | + *------------------------------------------------------------------------| + *X4 | 256 (X2) | 000b |000b | 0 ||X2 | DYN | + *------------------------------------------------------------------------| + *X4 | 512 (X4) | 010b |101b | 0 ||X4 | X4 | + *------------------------------------------------------------------------| + *DYN | 256 (X2) | 000b |000b | 0 ||X2 | DYN | + *------------------------------------------------------------------------| + *DYN | 512 (X4) | 010b |101b | 0 ||X4 | X4 | + *------------------------------------------------------------------------| + *X4 | 256 (X2) | 000b |000b | X2 ||DYN | DYN | + *------------------------------------------------------------------------| + *DYNC | 256 (X2) | 000b |000b | X2 ||DYN | DYN | + *------------------------------------------------------------------------| + * X2 | 512 (X4) | xxxb |xxxb | X4 ||INVAL | INVAL | + *------------------------------------------------------------------------| */ static void npc_cn20k_config_kw_x2(struct rvu *rvu, struct npc_mcam *mcam, int blkaddr, int index, u8 intf, struct cn20k_mcam_entry *entry, - int bank, u8 kw_type, int kw) + int bank, u8 kw_type, int kw, + u8 req_kw_type) { u64 intf_ext =3D 0, intf_ext_mask =3D 0; u8 tx_intf_mask =3D ~intf & 0x3; @@ -925,6 +934,15 @@ static void npc_cn20k_config_kw_x2(struct rvu *rvu, st= ruct npc_mcam *mcam, kw_type_mask =3D 0; } =20 + /* Say, we need to write x2 keyword in an x4 subbank. + * req_kw_type will be x2, and kw_type will be x4. + * So in the case ignore kw bits in mcam. + */ + if (kw_type =3D=3D NPC_MCAM_KEY_X4 && req_kw_type =3D=3D NPC_MCAM_KEY_X2)= { + kw_type =3D 0; + kw_type_mask =3D 0; + } + intf_ext =3D ((u64)kw_type << 16) | tx_intf; intf_ext_mask =3D (((u64)kw_type_mask << 16) & GENMASK_ULL(18, 16)) | tx_intf_mask; @@ -972,14 +990,15 @@ static void npc_cn20k_config_kw_x2(struct rvu *rvu, s= truct npc_mcam *mcam, static void npc_cn20k_config_kw_x4(struct rvu *rvu, struct npc_mcam *mcam, int blkaddr, int index, u8 intf, struct cn20k_mcam_entry *entry, - u8 kw_type) + u8 kw_type, u8 req_kw_type) { int kw =3D 0, bank; =20 for (bank =3D 0; bank < mcam->banks_per_entry; bank++, kw =3D kw + 4) npc_cn20k_config_kw_x2(rvu, mcam, blkaddr, index, intf, - entry, bank, kw_type, kw); + entry, bank, kw_type, + kw, req_kw_type); } =20 static void @@ -989,7 +1008,7 @@ npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blkad= dr, int mcam_idx, struct npc_mcam *mcam =3D &rvu->hw->mcam; u64 bank_cfg; =20 - bank_cfg =3D (u64)hw_prio << 8; + bank_cfg =3D (u64)hw_prio << 24; if (enable) bank_cfg |=3D 0x1; =20 @@ -1012,7 +1031,7 @@ npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blka= ddr, int mcam_idx, =20 void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index, u8 intf, struct cn20k_mcam_entry *entry, - bool enable, u8 hw_prio) + bool enable, u8 hw_prio, u8 req_kw_type) { struct npc_mcam *mcam =3D &rvu->hw->mcam; int mcam_idx =3D index % mcam->banksize; @@ -1035,27 +1054,34 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, i= nt blkaddr, int index, npc_cn20k_clear_mcam_entry(rvu, blkaddr, bank, mcam_idx); npc_cn20k_config_kw_x2(rvu, mcam, blkaddr, mcam_idx, intf, entry, - bank, kw_type, kw); + bank, kw_type, kw, req_kw_type); /* Set 'action' */ rvu_write64(rvu, blkaddr, NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx, bank, 0), entry->action); =20 + /* Set 'action2' for inline receive */ + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx, + bank, 2), + entry->action2); + /* Set TAG 'action' */ rvu_write64(rvu, blkaddr, NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx, bank, 1), entry->vtag_action); - goto set_cfg; } + /* Clear mcam entry to avoid writes being suppressed by NPC */ npc_cn20k_clear_mcam_entry(rvu, blkaddr, 0, mcam_idx); npc_cn20k_clear_mcam_entry(rvu, blkaddr, 1, mcam_idx); =20 npc_cn20k_config_kw_x4(rvu, mcam, blkaddr, - mcam_idx, intf, entry, kw_type); + mcam_idx, intf, entry, + kw_type, req_kw_type); for (bank =3D 0; bank < mcam->banks_per_entry; bank++) { /* Set 'action' */ rvu_write64(rvu, blkaddr, @@ -1068,6 +1094,12 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, in= t blkaddr, int index, NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx, bank, 1), entry->vtag_action); + + /* Set 'action2' for inline receive */ + rvu_write64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx, + bank, 2), + entry->action2); } =20 set_cfg: @@ -1156,7 +1188,7 @@ void npc_cn20k_read_mcam_entry(struct rvu *rvu, int b= lkaddr, u16 index, bank_cfg =3D rvu_read64(rvu, blkaddr, NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(index, bank)); *ena =3D bank_cfg & 0x1; - *hw_prio =3D (bank_cfg & GENMASK_ULL(14, 8)) >> 8; + *hw_prio =3D (bank_cfg & GENMASK_ULL(30, 24)) >> 24; if (kw_type =3D=3D NPC_MCAM_KEY_X2) { cam1 =3D rvu_read64(rvu, blkaddr, NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, @@ -1292,7 +1324,7 @@ int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struc= t rvu *rvu, =20 npc_cn20k_config_mcam_entry(rvu, blkaddr, req->entry, nix_intf, &req->entry_data, req->enable_entry, - req->hw_prio); + req->hw_prio, req->req_kw_type); =20 rc =3D 0; exit: @@ -1370,7 +1402,7 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_e= ntry(struct rvu *rvu, =20 npc_cn20k_config_mcam_entry(rvu, blkaddr, entry, nix_intf, &req->entry_data, req->enable_entry, - req->hw_prio); + req->hw_prio, req->req_kw_type); =20 mutex_unlock(&mcam->lock); =20 @@ -1378,6 +1410,14 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_= entry(struct rvu *rvu, return 0; } =20 +static int rvu_npc_get_base_steer_rule_type(struct rvu *rvu, u16 pcifunc) +{ + if (is_lbk_vf(rvu, pcifunc)) + return NIXLF_PROMISC_ENTRY; + + return NIXLF_UCAST_ENTRY; +} + int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(struct rvu *rvu, struct msg_req *req, struct npc_cn20k_mcam_read_base_rule_rsp *rsp) @@ -1387,6 +1427,7 @@ int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(s= truct rvu *rvu, u16 pcifunc =3D req->hdr.pcifunc; u8 intf, enable, hw_prio; struct rvu_pfvf *pfvf; + int rl_type; =20 blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) @@ -1412,9 +1453,11 @@ int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(= struct rvu *rvu, mutex_unlock(&mcam->lock); goto out; } + + rl_type =3D rvu_npc_get_base_steer_rule_type(rvu, pcifunc); + /* Read the default ucast entry if there is no pkt steering rule */ - index =3D npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf, - NIXLF_UCAST_ENTRY); + index =3D npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf, rl_type); read_entry: /* Read the mcam entry */ npc_cn20k_read_mcam_entry(rvu, blkaddr, index, @@ -3888,6 +3931,89 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16= pcifunc, u16 *bcast, return set ? 0 : -ESRCH; } =20 +int rvu_mbox_handler_npc_get_pfl_info(struct rvu *rvu, struct msg_req *req, + struct npc_get_pfl_info_rsp *rsp) +{ + if (!is_cn20k(rvu->pdev)) { + dev_err(rvu->dev, "Mbox support is only for cn20k\n"); + return -EOPNOTSUPP; + } + + rsp->kw_type =3D npc_priv.kw; + rsp->x4_slots =3D npc_priv.bank_depth; + return 0; +} + +int rvu_mbox_handler_npc_get_num_kws(struct rvu *rvu, + struct npc_get_num_kws_req *req, + struct npc_get_num_kws_rsp *rsp) +{ + struct rvu_npc_mcam_rule dummy =3D { 0 }; + struct cn20k_mcam_entry cn20k_entry =3D { 0 }; + struct mcam_entry_mdata mdata =3D { }; + struct mcam_entry entry =3D { 0 }; + struct npc_install_flow_req *fl; + int i, cnt =3D 0, blkaddr; + + if (!is_cn20k(rvu->pdev)) { + dev_err(rvu->dev, "Mbox support is only for cn20k\n"); + return -EOPNOTSUPP; + } + + fl =3D &req->fl; + + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) { + dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__); + return NPC_MCAM_INVALID_REQ; + } + + npc_populate_mcam_mdata(rvu, &mdata, &cn20k_entry, &entry); + + npc_update_flow(rvu, &mdata, fl->features, &fl->packet, + &fl->mask, &dummy, fl->intf, blkaddr); + + /* Find the most significant word valid. Traverse from + * MSB to LSB, check if cam0 or cam1 is set + */ + for (i =3D NPC_CN20K_MAX_KWS_IN_KEY - 1; i >=3D 0; i--) { + if (cn20k_entry.kw[i] || cn20k_entry.kw_mask[i]) { + cnt =3D i + 1; + break; + } + } + + rsp->kws =3D cnt; + + return 0; +} + +int rvu_mbox_handler_npc_get_dft_rl_idxs(struct rvu *rvu, struct msg_req *= req, + struct npc_get_dft_rl_idxs_rsp *rsp) +{ + u16 bcast, mcast, promisc, ucast; + u16 pcifunc; + int rc; + + if (!is_cn20k(rvu->pdev)) { + dev_err(rvu->dev, "Mbox support is only for cn20k\n"); + return -EOPNOTSUPP; + } + + pcifunc =3D req->hdr.pcifunc; + + rc =3D npc_cn20k_dft_rules_idx_get(rvu, pcifunc, &bcast, &mcast, + &promisc, &ucast); + if (rc) + return rc; + + rsp->bcast =3D bcast; + rsp->mcast =3D mcast; + rsp->promisc =3D promisc; + rsp->ucast =3D ucast; + return 0; +} + static bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc) { return is_pf_cgxmapped(rvu, rvu_get_pf(rvu->pdev, pcifunc)) || diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.h index 178051b2535a..12a76aaa5317 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h @@ -321,9 +321,8 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pc= ifunc, u16 *bcast, u16 *mcast, u16 *promisc, u16 *ucast); =20 void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index, - u8 intf, - struct cn20k_mcam_entry *entry, - bool enable, u8 hw_prio); + u8 intf, struct cn20k_mcam_entry *entry, + bool enable, u8 hw_prio, u8 req_kw_type); void npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr, int index, bool enable); void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index 1638bf4e15fd..79cb1c752c2b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -301,6 +301,15 @@ M(NPC_CN20K_MCAM_READ_BASE_RULE, 0x601a, npc_cn20k_rea= d_base_steer_rule, \ M(NPC_MCAM_DEFRAG, 0x601b, npc_defrag, \ msg_req, \ msg_rsp) \ +M(NPC_MCAM_GET_NUM_KWS, 0x601c, npc_get_num_kws, \ + npc_get_num_kws_req, \ + npc_get_num_kws_rsp) \ +M(NPC_MCAM_GET_DFT_RL_IDXS, 0x601d, npc_get_dft_rl_idxs, \ + msg_req, \ + npc_get_dft_rl_idxs_rsp)\ +M(NPC_MCAM_GET_NPC_PFL_INFO, 0x601e, npc_get_pfl_info, \ + msg_req, \ + npc_get_pfl_info_rsp) \ /* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \ M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc, \ nix_lf_alloc_req, nix_lf_alloc_rsp) \ @@ -1598,6 +1607,7 @@ struct cn20k_mcam_entry { u64 kw_mask[NPC_CN20K_MAX_KWS_IN_KEY]; u64 action; u64 vtag_action; + u64 action2; }; =20 struct npc_cn20k_mcam_write_entry_req { @@ -1608,6 +1618,7 @@ struct npc_cn20k_mcam_write_entry_req { u8 intf; /* Rx or Tx interface */ u8 enable_entry;/* Enable this MCAM entry ? */ u8 hw_prio; /* hardware priority, valid for cn20k */ + u8 req_kw_type; /* Type of kw which should be written */ u64 reserved; /* reserved for future use */ }; =20 @@ -1694,6 +1705,7 @@ struct npc_cn20k_mcam_alloc_and_write_entry_req { u8 enable_entry;/* Enable this MCAM entry ? */ u8 hw_prio; /* hardware priority, valid for cn20k */ u8 virt; /* Allocate virtual index */ + u8 req_kw_type; /* Key type to be written */ u16 reserved[4]; /* reserved for future use */ }; =20 @@ -1861,11 +1873,47 @@ struct npc_install_flow_req { /* old counter value */ u16 cntr_val; u8 hw_prio; + u8 req_kw_type; /* Key type to be written */ + u8 alloc_entry; /* only for cn20k */ + u16 ref_prio; + u16 ref_entry; }; =20 struct npc_install_flow_rsp { struct mbox_msghdr hdr; int counter; /* negative if no counter else counter number */ + u16 entry; + u8 kw_type; +}; + +struct npc_get_num_kws_req { + struct mbox_msghdr hdr; + struct npc_install_flow_req fl; + u32 rsvd[4]; +}; + +struct npc_get_num_kws_rsp { + struct mbox_msghdr hdr; + int kws; + u32 rsvd[4]; +}; + +struct npc_get_dft_rl_idxs_rsp { + struct mbox_msghdr hdr; + u16 bcast; + u16 mcast; + u16 promisc; + u16 ucast; + u16 vf_ucast; + u16 rsvd[7]; +}; + +struct npc_get_pfl_info_rsp { + struct mbox_msghdr hdr; + u16 x4_slots; + u8 kw_type; + u8 rsvd1[3]; + u32 rsvd2[4]; }; =20 struct npc_delete_flow_req { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.c index 1c50fd150bd3..ca1c4b3178e6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -2678,6 +2678,10 @@ static int npc_mcam_alloc_entries(struct npc_mcam *m= cam, u16 pcifunc, if (!is_cn20k(rvu->pdev)) goto not_cn20k; =20 + /* Only x2 or x4 key types are accepted */ + if (req->kw_type !=3D NPC_MCAM_KEY_X2 && req->kw_type !=3D NPC_MCAM_KEY_X= 4) + return NPC_MCAM_INVALID_REQ; + /* The below table is being followed during allocation, * * 1. ref_entry =3D=3D 0 && prio =3D=3D HIGH && count =3D=3D 1 : user wan= ts to diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drive= rs/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index bff190ba95e2..b9572de1d175 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -1071,11 +1071,11 @@ static void npc_update_vlan_features(struct rvu *rv= u, ~0ULL, 0, intf); } =20 -static void npc_update_flow(struct rvu *rvu, struct mcam_entry_mdata *mdat= a, - u64 features, struct flow_msg *pkt, - struct flow_msg *mask, - struct rvu_npc_mcam_rule *output, u8 intf, - int blkaddr) +void npc_update_flow(struct rvu *rvu, struct mcam_entry_mdata *mdata, + u64 features, struct flow_msg *pkt, + struct flow_msg *mask, + struct rvu_npc_mcam_rule *output, u8 intf, + int blkaddr) { u64 dmac_mask =3D ether_addr_to_u64(mask->dmac); u64 smac_mask =3D ether_addr_to_u64(mask->smac); @@ -1304,7 +1304,7 @@ static int npc_mcast_update_action_index(struct rvu *= rvu, struct npc_install_flo return 0; } =20 -static void +void npc_populate_mcam_mdata(struct rvu *rvu, struct mcam_entry_mdata *mdata, struct cn20k_mcam_entry *cn20k_entry, @@ -1549,6 +1549,7 @@ static int npc_install_flow(struct rvu *rvu, int blka= ddr, u16 target, cn20k_wreq.intf =3D req->intf; cn20k_wreq.enable_entry =3D (u8)enable; cn20k_wreq.hw_prio =3D req->hw_prio; + cn20k_wreq.req_kw_type =3D req->req_kw_type; =20 update_rule: =20 @@ -1642,6 +1643,79 @@ static int npc_install_flow(struct rvu *rvu, int blk= addr, u16 target, return 0; } =20 +static int +rvu_npc_free_entry_for_flow_install(struct rvu *rvu, u16 pcifunc, + bool free_entry, int mcam_idx) +{ + struct npc_mcam_free_entry_req free_req; + struct msg_rsp rsp; + int rc; + + if (!free_entry) + return 0; + + free_req.hdr.pcifunc =3D pcifunc; + free_req.entry =3D mcam_idx; + rc =3D rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp); + return rc; +} + +static int +rvu_npc_alloc_entry_for_flow_install(struct rvu *rvu, + struct npc_install_flow_req *fl_req, + u16 *mcam_idx, u8 *kw_type, + bool *allocated) +{ + struct npc_mcam_alloc_entry_req entry_req; + struct npc_mcam_alloc_entry_rsp entry_rsp; + struct npc_get_num_kws_req kws_req; + struct npc_get_num_kws_rsp kws_rsp; + int off, kw_bits, rc; + u8 *src, *dst; + + if (!is_cn20k(rvu->pdev)) { + *kw_type =3D -1; + return 0; + } + + if (!fl_req->alloc_entry) { + *kw_type =3D -1; + return 0; + } + + off =3D offsetof(struct npc_install_flow_req, packet); + dst =3D (u8 *)&kws_req.fl + off; + src =3D (u8 *)fl_req + off; + memcpy(dst, src, sizeof(struct npc_install_flow_req) - off); + rc =3D rvu_mbox_handler_npc_get_num_kws(rvu, &kws_req, &kws_rsp); + if (rc) + return rc; + + kw_bits =3D kws_rsp.kws * 64; + + *kw_type =3D NPC_MCAM_KEY_X2; + if (kw_bits > 256) + *kw_type =3D NPC_MCAM_KEY_X4; + + memset(&entry_req, 0, sizeof(entry_req)); + memset(&entry_rsp, 0, sizeof(entry_rsp)); + + entry_req.hdr.pcifunc =3D fl_req->hdr.pcifunc; + entry_req.ref_prio =3D fl_req->ref_prio; + entry_req.ref_entry =3D fl_req->ref_entry; + entry_req.kw_type =3D *kw_type; + entry_req.count =3D 1; + rc =3D rvu_mbox_handler_npc_mcam_alloc_entry(rvu, + &entry_req, + &entry_rsp); + if (rc) + return rc; + + *mcam_idx =3D entry_rsp.entry_list[0]; + *allocated =3D true; + return 0; +} + int rvu_mbox_handler_npc_install_flow(struct rvu *rvu, struct npc_install_flow_req *req, struct npc_install_flow_rsp *rsp) @@ -1652,11 +1726,11 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *r= vu, int blkaddr, nixlf, err; struct rvu_pfvf *pfvf; bool pf_set_vfs_mac =3D false; + bool allocated =3D false; bool enable =3D true; + u8 kw_type; u16 target; =20 - req->entry =3D npc_cn20k_vidx2idx(req->entry); - blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) { dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__); @@ -1666,6 +1740,17 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rv= u, if (!is_npc_interface_valid(rvu, req->intf)) return NPC_FLOW_INTF_INVALID; =20 + err =3D rvu_npc_alloc_entry_for_flow_install(rvu, req, &req->entry, + &kw_type, &allocated); + if (err) { + dev_err(rvu->dev, + "%s: Error to alloc mcam entry for pcifunc=3D%#x\n", + __func__, req->hdr.pcifunc); + return err; + } + + req->entry =3D npc_cn20k_vidx2idx(req->entry); + /* If DMAC is not extracted in MKEX, rules installed by AF * can rely on L2MB bit set by hardware protocol checker for * broadcast and multicast addresses. @@ -1679,6 +1764,10 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rv= u, dev_warn(rvu->dev, "%s: mkex profile does not support ucast flow\n", __func__); + rvu_npc_free_entry_for_flow_install(rvu, + req->hdr.pcifunc, + allocated, + req->entry); return NPC_FLOW_NOT_SUPPORTED; } =20 @@ -1686,6 +1775,10 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rv= u, dev_warn(rvu->dev, "%s: mkex profile does not support bcast/mcast flow", __func__); + rvu_npc_free_entry_for_flow_install(rvu, + req->hdr.pcifunc, + allocated, + req->entry); return NPC_FLOW_NOT_SUPPORTED; } =20 @@ -1695,8 +1788,11 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rv= u, } =20 process_flow: - if (from_vf && req->default_rule) + if (from_vf && req->default_rule) { + rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc, + allocated, req->entry); return NPC_FLOW_VF_PERM_DENIED; + } =20 /* Each PF/VF info is maintained in struct rvu_pfvf. * rvu_pfvf for the target PF/VF needs to be retrieved @@ -1724,8 +1820,11 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rv= u, req->chan_mask =3D 0xFFF; =20 err =3D npc_check_unsupported_flows(rvu, req->features, req->intf); - if (err) + if (err) { + rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc, + allocated, req->entry); return NPC_FLOW_NOT_SUPPORTED; + } =20 pfvf =3D rvu_get_pfvf(rvu, target); =20 @@ -1744,8 +1843,11 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rv= u, =20 /* Proceed if NIXLF is attached or not for TX rules */ err =3D nix_get_nixlf(rvu, target, &nixlf, NULL); - if (err && is_npc_intf_rx(req->intf) && !pf_set_vfs_mac) + if (err && is_npc_intf_rx(req->intf) && !pf_set_vfs_mac) { + rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc, + allocated, req->entry); return NPC_FLOW_NO_NIXLF; + } =20 /* don't enable rule when nixlf not attached or initialized */ if (!(is_nixlf_attached(rvu, target) && @@ -1760,20 +1862,31 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *r= vu, enable =3D true; =20 /* Do not allow requests from uninitialized VFs */ - if (from_vf && !enable) + if (from_vf && !enable) { + rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc, + allocated, req->entry); return NPC_FLOW_VF_NOT_INIT; + } =20 /* PF sets VF mac & VF NIXLF is not attached, update the mac addr */ if (pf_set_vfs_mac && !enable) { ether_addr_copy(pfvf->default_mac, req->packet.dmac); ether_addr_copy(pfvf->mac_addr, req->packet.dmac); set_bit(PF_SET_VF_MAC, &pfvf->flags); + rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc, + allocated, req->entry); return 0; } =20 mutex_lock(&rswitch->switch_lock); err =3D npc_install_flow(rvu, blkaddr, target, nixlf, pfvf, req, rsp, enable, pf_set_vfs_mac); + if (err) + rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc, + allocated, req->entry); + + rsp->kw_type =3D kw_type; + rsp->entry =3D req->entry; mutex_unlock(&rswitch->switch_lock); =20 return err; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h b/drive= rs/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h index 442287ee7baa..d3ba86c23959 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h @@ -18,4 +18,16 @@ void npc_update_entry(struct rvu *rvu, enum key_fields t= ype, struct mcam_entry_mdata *mdata, u64 val_lo, u64 val_hi, u64 mask_lo, u64 mask_hi, u8 intf); =20 +void npc_update_flow(struct rvu *rvu, struct mcam_entry_mdata *mdata, + u64 features, struct flow_msg *pkt, + struct flow_msg *mask, + struct rvu_npc_mcam_rule *output, u8 intf, + int blkaddr); + +void +npc_populate_mcam_mdata(struct rvu *rvu, + struct mcam_entry_mdata *mdata, + struct cn20k_mcam_entry *cn20k_entry, + struct mcam_entry *entry); + #endif /* RVU_NPC_FS_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/driv= ers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c index 052d989f2d9a..23372f30dcc2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c @@ -37,6 +37,98 @@ static void otx2_clear_ntuple_flow_info(struct otx2_nic = *pfvf, struct otx2_flow_ flow_cfg->max_flows =3D 0; } =20 +static int otx2_mcam_pfl_info_get(struct otx2_nic *pfvf, bool *is_x2, + u16 *x4_slots) +{ + struct npc_get_pfl_info_rsp *rsp; + struct msg_req *req; + static struct { + bool is_set; + bool is_x2; + u16 x4_slots; + } pfl_info; + + /* Avoid sending mboxes for constant information + * like x4_slots + */ + if (pfl_info.is_set) { + *is_x2 =3D pfl_info.is_x2; + *x4_slots =3D pfl_info.x4_slots; + return 0; + } + + mutex_lock(&pfvf->mbox.lock); + + req =3D otx2_mbox_alloc_msg_npc_get_pfl_info(&pfvf->mbox); + if (!req) { + mutex_unlock(&pfvf->mbox.lock); + return -ENOMEM; + } + + /* Send message to AF */ + if (otx2_sync_mbox_msg(&pfvf->mbox)) { + mutex_unlock(&pfvf->mbox.lock); + return -EFAULT; + } + + rsp =3D (struct npc_get_pfl_info_rsp *)otx2_mbox_get_rsp + (&pfvf->mbox.mbox, 0, &req->hdr); + + if (IS_ERR(rsp)) { + mutex_unlock(&pfvf->mbox.lock); + return -EFAULT; + } + + *is_x2 =3D (rsp->kw_type =3D=3D NPC_MCAM_KEY_X2); + if (*is_x2) + *x4_slots =3D 0; + else + *x4_slots =3D rsp->x4_slots; + + pfl_info.is_x2 =3D *is_x2; + pfl_info.x4_slots =3D *x4_slots; + pfl_info.is_set =3D true; + + mutex_unlock(&pfvf->mbox.lock); + return 0; +} + +static int otx2_get_dft_rl_idx(struct otx2_nic *pfvf, u16 *mcam_idx) +{ + struct npc_get_dft_rl_idxs_rsp *rsp; + struct msg_req *req; + + mutex_lock(&pfvf->mbox.lock); + + req =3D otx2_mbox_alloc_msg_npc_get_dft_rl_idxs(&pfvf->mbox); + if (!req) { + mutex_unlock(&pfvf->mbox.lock); + return -ENOMEM; + } + + /* Send message to AF */ + if (otx2_sync_mbox_msg(&pfvf->mbox)) { + mutex_unlock(&pfvf->mbox.lock); + return -EINVAL; + } + + rsp =3D (struct npc_get_dft_rl_idxs_rsp *)otx2_mbox_get_rsp + (&pfvf->mbox.mbox, 0, &req->hdr); + + if (IS_ERR(rsp)) { + mutex_unlock(&pfvf->mbox.lock); + return -EFAULT; + } + + if (is_otx2_lbkvf(pfvf->pdev)) + *mcam_idx =3D rsp->promisc; + else + *mcam_idx =3D rsp->ucast; + + mutex_unlock(&pfvf->mbox.lock); + return 0; +} + static int otx2_free_ntuple_mcam_entries(struct otx2_nic *pfvf) { struct otx2_flow_config *flow_cfg =3D pfvf->flow_cfg; @@ -69,7 +161,10 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 = count) struct otx2_flow_config *flow_cfg =3D pfvf->flow_cfg; struct npc_mcam_alloc_entry_req *req; struct npc_mcam_alloc_entry_rsp *rsp; - int ent, allocated =3D 0; + u16 dft_idx =3D 0, x4_slots =3D 0; + int ent, allocated =3D 0, ref; + bool is_x2 =3D false; + int rc; =20 /* Free current ones and allocate new ones with requested count */ otx2_free_ntuple_mcam_entries(pfvf); @@ -86,6 +181,22 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 = count) return -ENOMEM; } =20 + if (is_cn20k(pfvf->pdev)) { + rc =3D otx2_mcam_pfl_info_get(pfvf, &is_x2, &x4_slots); + if (rc) { + netdev_err(pfvf->netdev, "Error to retrieve profile info\n"); + return rc; + } + + rc =3D otx2_get_dft_rl_idx(pfvf, &dft_idx); + if (rc) { + netdev_err(pfvf->netdev, + "Error to retrieve ucast mcam idx for pcifunc %#x\n", + pfvf->pcifunc); + return -EFAULT; + } + } + mutex_lock(&pfvf->mbox.lock); =20 /* In a single request a max of NPC_MAX_NONCONTIG_ENTRIES MCAM entries @@ -96,18 +207,31 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16= count) if (!req) goto exit; =20 + req->kw_type =3D is_x2 ? NPC_MCAM_KEY_X2 : NPC_MCAM_KEY_X4; req->contig =3D false; req->count =3D (count - allocated) > NPC_MAX_NONCONTIG_ENTRIES ? NPC_MAX_NONCONTIG_ENTRIES : count - allocated; =20 + ref =3D 0; + + if (is_cn20k(pfvf->pdev)) { + req->ref_prio =3D NPC_MCAM_HIGHER_PRIO; + ref =3D dft_idx; + } + /* Allocate higher priority entries for PFs, so that VF's entries * will be on top of PF. */ if (!is_otx2_vf(pfvf->pcifunc)) { req->ref_prio =3D NPC_MCAM_HIGHER_PRIO; - req->ref_entry =3D flow_cfg->def_ent[0]; + ref =3D flow_cfg->def_ent[0]; } =20 + if (is_cn20k(pfvf->pdev)) + ref =3D is_x2 ? ref : ref & (x4_slots - 1); + + req->ref_entry =3D ref; + /* Send message to AF */ if (otx2_sync_mbox_msg(&pfvf->mbox)) goto exit; @@ -163,8 +287,24 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf) struct npc_get_field_status_rsp *frsp; struct npc_mcam_alloc_entry_req *req; struct npc_mcam_alloc_entry_rsp *rsp; - int vf_vlan_max_flows; - int ent, count; + int vf_vlan_max_flows, count; + int rc, ref, prio, ent; + u16 dft_idx; + + ref =3D 0; + prio =3D 0; + if (is_cn20k(pfvf->pdev)) { + rc =3D otx2_get_dft_rl_idx(pfvf, &dft_idx); + if (rc) { + netdev_err(pfvf->netdev, + "Error to retrieve ucast mcam idx for pcifunc %#x\n", + pfvf->pcifunc); + return -EFAULT; + } + + ref =3D dft_idx; + prio =3D NPC_MCAM_HIGHER_PRIO; + } =20 vf_vlan_max_flows =3D pfvf->total_vfs * OTX2_PER_VF_VLAN_FLOWS; count =3D flow_cfg->ucast_flt_cnt + @@ -183,8 +323,11 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf) return -ENOMEM; } =20 + req->kw_type =3D NPC_MCAM_KEY_X2; req->contig =3D false; req->count =3D count; + req->ref_prio =3D prio; + req->ref_entry =3D ref; =20 /* Send message to AF */ if (otx2_sync_mbox_msg(&pfvf->mbox)) { @@ -819,7 +962,7 @@ static int otx2_prepare_ipv6_flow(struct ethtool_rx_flo= w_spec *fsp, } =20 static int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp, - struct npc_install_flow_req *req) + struct npc_install_flow_req *req) { struct ethhdr *eth_mask =3D &fsp->m_u.ether_spec; struct ethhdr *eth_hdr =3D &fsp->h_u.ether_spec; @@ -945,6 +1088,58 @@ static int otx2_prepare_flow_request(struct ethtool_r= x_flow_spec *fsp, return 0; } =20 +static int otx2_get_kw_type(struct otx2_nic *pfvf, + struct npc_install_flow_req *fl_req, + u8 *kw_type) +{ + struct npc_get_num_kws_req *req; + struct npc_get_num_kws_rsp *rsp; + u8 *src, *dst; + int off, err; + int kw_bits; + + off =3D offsetof(struct npc_install_flow_req, packet); + + mutex_lock(&pfvf->mbox.lock); + + req =3D otx2_mbox_alloc_msg_npc_get_num_kws(&pfvf->mbox); + if (!req) { + mutex_unlock(&pfvf->mbox.lock); + return -EINVAL; + } + + dst =3D (u8 *)&req->fl + off; + src =3D (u8 *)fl_req + off; + + memcpy(dst, src, sizeof(struct npc_install_flow_req) - off); + + err =3D otx2_sync_mbox_msg(&pfvf->mbox); + if (err) { + mutex_unlock(&pfvf->mbox.lock); + netdev_err(pfvf->netdev, + "Error to get default number of keywords\n"); + return err; + } + + rsp =3D (struct npc_get_num_kws_rsp *)otx2_mbox_get_rsp + (&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + mutex_unlock(&pfvf->mbox.lock); + return -EFAULT; + } + + kw_bits =3D rsp->kws * 64; + + if (kw_bits <=3D 256) + *kw_type =3D NPC_MCAM_KEY_X2; + else + *kw_type =3D NPC_MCAM_KEY_X4; + + mutex_unlock(&pfvf->mbox.lock); + + return 0; +} + static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf, struct ethtool_rx_flow_spec *fsp) { @@ -973,12 +1168,41 @@ static int otx2_is_flow_rule_dmacfilter(struct otx2_= nic *pfvf, =20 static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow) { + struct otx2_flow_config *flow_cfg =3D pfvf->flow_cfg; + struct npc_install_flow_req *req, treq =3D { 0 }; u64 ring_cookie =3D flow->flow_spec.ring_cookie; #ifdef CONFIG_DCB int vlan_prio, qidx, pfc_rule =3D 0; #endif - struct npc_install_flow_req *req; - int err, vf =3D 0; + int err, vf =3D 0, off, sz; + bool modify =3D false; + u8 kw_type =3D 0; + u8 *src, *dst; + u16 x4_slots; + bool is_x2; + + if (is_cn20k(pfvf->pdev)) { + err =3D otx2_mcam_pfl_info_get(pfvf, &is_x2, &x4_slots); + if (err) { + netdev_err(pfvf->netdev, + "Error to retrieve ucast mcam idx for pcifunc %#x\n", + pfvf->pcifunc); + return -EFAULT; + } + + if (!is_x2) { + err =3D otx2_prepare_flow_request(&flow->flow_spec, + &treq); + if (err) + return err; + + err =3D otx2_get_kw_type(pfvf, &treq, &kw_type); + if (err) + return err; + + modify =3D true; + } + } =20 mutex_lock(&pfvf->mbox.lock); req =3D otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox); @@ -987,14 +1211,29 @@ static int otx2_add_flow_msg(struct otx2_nic *pfvf, = struct otx2_flow *flow) return -ENOMEM; } =20 - err =3D otx2_prepare_flow_request(&flow->flow_spec, req); - if (err) { - /* free the allocated msg above */ - otx2_mbox_reset(&pfvf->mbox.mbox, 0); - mutex_unlock(&pfvf->mbox.lock); - return err; + if (modify) { + off =3D offsetof(struct npc_install_flow_req, packet); + sz =3D sizeof(struct npc_install_flow_req) - off; + dst =3D (u8 *)req + off; + src =3D (u8 *)&treq + off; + + memcpy(dst, src, sz); + req->req_kw_type =3D kw_type; + } else { + err =3D otx2_prepare_flow_request(&flow->flow_spec, req); + if (err) { + /* free the allocated msg above */ + otx2_mbox_reset(&pfvf->mbox.mbox, 0); + mutex_unlock(&pfvf->mbox.lock); + return err; + } } =20 + netdev_dbg(pfvf->netdev, + "flow entry (%u) installed at loc:%u kw_type=3D%u\n", + flow_cfg->flow_ent[flow->location], + flow->location, kw_type); + req->entry =3D flow->entry; req->intf =3D NIX_INTF_RX; req->set_cntr =3D 1; --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0a-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 42F713148DA; Mon, 2 Feb 2026 07:47:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018425; cv=none; b=Ly8rfaE+LhyyLKJpfx67eGQ36YBPDQZiytzaqSTM1tfe7cQ2oe2V1KlGvgqpv0BTi6/3bmCKqPiUKHWyeVxL6q+mzYzpXwnpkEisPLX2y51xhBZQJX8s6U6ktqdLDsDlL8/a8LtatI+5zxApygXNlPGt1ZBLcAPVnbPb1f6VBj4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018425; c=relaxed/simple; bh=VHNtpmuh8XH5jeD685TNp8wk10ejYKeojasNB0EnFBo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=X/T7jE17+Q8rj1BFZqazgF0iwlbaH4FPrSXxZ4O2h75UkY5SNMG1MhlSWqtqMSBM9qgVNPZuHivLnaQ9yg3NBTOrT5sz/mAOnsg1RUXaLXc1YRjpPvcco65Z4h9NnZhZfQhZu1d6w6Z04GKTbm4LGRfIbiWMipt8+LXEuH4CiJo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=Ku/92T/h; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="Ku/92T/h" Received: from pps.filterd (m0431384.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6126uv4M904760; Sun, 1 Feb 2026 23:46:54 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=L afK2jpOJgU5N80FJqpvJkl7iG4z/pqepp0xNAlbddM=; b=Ku/92T/hRZorKA56f i2Pw1D7MFitBA1Xcy6B3gALfA28/KApe0n5YlRrS8wH3ZPJ65F+MLRsMI+LLnC6D 9UqPqQqAgHF2UlJ0z/NoA4HJTa3r2+poUQtSVnIdVB/rQhccVbpAdPVF5DwXbZ2y iEXASBQHWRUF+3K2EbCZE4yIfGw8iw3gecYUe2f0rJ7yv79cFr5xJbp06YAfzGWB Ra5+576pD9mUDVoK6grRIk9JJAJo/P4/5E9M4wSYf8yESGSGM96vAe2Pvha+Ttlr VgoW5Yvcyu2YSyF3JsK5OVr8MWB0OhI7gsRTQIpFQ8QkFH6uzSLNHuPtDLFVSVl4 Z6dig== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4c2q3q02q5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:53 -0800 (PST) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:47:09 -0800 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:47:09 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id D4A735B6946; Sun, 1 Feb 2026 23:46:49 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , "Subbaraya Sundeep" , Ratheesh Kannoth Subject: [PATCH net-next v8 11/13] octeontx2-pf: cn20k: Add TC rules support Date: Mon, 2 Feb 2026 13:16:05 +0530 Message-ID: <20260202074607.2535569-12-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authority-Analysis: v=2.4 cv=ZeoQ98VA c=1 sm=1 tr=0 ts=6980566d cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=DpXxuF1KUPOfmLfLDTAA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-GUID: 4_5cmyRpbcBIDsaIGSUHwAFWe5ZI7KFu X-Proofpoint-ORIG-GUID: 4_5cmyRpbcBIDsaIGSUHwAFWe5ZI7KFu X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfXxDa+dbKCvIOb fUpijQBdEEnIkmlrWcqdQX3TDNBwH+kIni5BY93Ps4WlaVXsG68BY2UnWSLaNU+OnNG3xBcLdzT NbjbJmWuPtqwAjEJgqLcWwkZ1g8PgNU2JuEpyuPiXClJRRlwoGjx2U0YH0GSYTGvHGvw6x/ehAx egUGlFIbflGn1TpVilGdiyZKWfpwx78fWow2SKNSiLRBg7TMo8L5jpnr7+JpRJlgZT1ZSu4SHaT Wp3BUX/m3T62AIILq6+FD+JJ37JQ1pcw89AFCmmtbiel07kngqZLLKFKBTL3ac9zEDT9Icroeth GzGyzK50RjndcNXTrj1ucfQCvnU5hCQxTZ9qLzbjlh696bRXeTgki598STCD9888Ga4/DHyIW2X GcKc0P1fQ/ba6KEaLVDxONebLTuuekLGcoFRUz1uwpXFqU/6vcmtaP+iNoqYMiIbQuDzLwYUeFH q+bHNE/laDTr6kE+Dhw== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" From: Subbaraya Sundeep Unlike previous silicons, MCAM entries required for TC rules in CN20K are allocated dynamically. The key size can also be dynamic, i.e., X2 or X4. Based on the size of the TC rule match criteria, the AF driver allocates an X2 or X4 rule. This patch implements the required changes for CN20K TC by requesting an MCAM entry from the AF driver on the fly when the user installs a rule. Based on the TC rule priority added or deleted by the user, the PF driver shifts MCAM entries accordingly. If there is a mix of X2 and X4 rules and the user tries to install a rule in the middle of existing rules, the PF driver detects this and rejects the rule since X2 and X4 rules cannot be shifted in hardware. Signed-off-by: Subbaraya Sundeep Signed-off-by: Ratheesh Kannoth --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 5 + .../ethernet/marvell/octeontx2/nic/cn20k.c | 261 ++++++++++++++++++ .../ethernet/marvell/octeontx2/nic/cn20k.h | 14 + .../marvell/octeontx2/nic/otx2_common.h | 35 +++ .../ethernet/marvell/octeontx2/nic/otx2_tc.c | 79 +++--- 5 files changed, 356 insertions(+), 38 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index 79cb1c752c2b..2d9f6cb4820f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1875,6 +1875,11 @@ struct npc_install_flow_req { u8 hw_prio; u8 req_kw_type; /* Key type to be written */ u8 alloc_entry; /* only for cn20k */ +/* For now use any priority, once AF driver is changed to + * allocate least priority entry instead of mid zone then make + * NPC_MCAM_LEAST_PRIO as 3 + */ +#define NPC_MCAM_LEAST_PRIO NPC_MCAM_ANY_PRIO u16 ref_prio; u16 ref_entry; }; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.c b/drivers/n= et/ethernet/marvell/octeontx2/nic/cn20k.c index a60f8cf53feb..43aa62e05dbb 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.c @@ -251,6 +251,267 @@ static u8 cn20k_aura_bpid_idx(struct otx2_nic *pfvf, = int aura_id) #endif } =20 +static int cn20k_tc_get_entry_index(struct otx2_flow_config *flow_cfg, + struct otx2_tc_flow *node) +{ + struct otx2_tc_flow *tmp; + int index =3D 0; + + list_for_each_entry(tmp, &flow_cfg->flow_list_tc, list) { + if (tmp =3D=3D node) + return index; + + index++; + } + + return 0; +} + +int cn20k_tc_free_mcam_entry(struct otx2_nic *nic, u16 entry) +{ + struct npc_mcam_free_entry_req *req; + int err; + + mutex_lock(&nic->mbox.lock); + req =3D otx2_mbox_alloc_msg_npc_mcam_free_entry(&nic->mbox); + if (!req) { + mutex_unlock(&nic->mbox.lock); + return -ENOMEM; + } + + req->entry =3D entry; + /* Send message to AF to free MCAM entries */ + err =3D otx2_sync_mbox_msg(&nic->mbox); + if (err) { + mutex_unlock(&nic->mbox.lock); + return err; + } + + mutex_unlock(&nic->mbox.lock); + + return 0; +} + +static bool cn20k_tc_check_entry_shiftable(struct otx2_nic *nic, + struct otx2_flow_config *flow_cfg, + struct otx2_tc_flow *node, int index, + bool error) +{ + struct otx2_tc_flow *first, *tmp, *n; + u32 prio =3D 0; + int i =3D 0; + u8 type; + + first =3D list_first_entry(&flow_cfg->flow_list_tc, struct otx2_tc_flow, + list); + type =3D first->kw_type; + + /* Check all the nodes from start to given index (including index) has + * same type i.e, either X2 or X4 + */ + list_for_each_entry_safe(tmp, n, &flow_cfg->flow_list_tc, list) { + if (i > index) + break; + + if (type !=3D tmp->kw_type) { + /* List has both X2 and X4 entries so entries cannot be + * shifted to save MCAM space. + */ + if (error) + dev_err(nic->dev, "Rule %d cannot be shifted to %d\n", + tmp->prio, prio); + return false; + } + + type =3D tmp->kw_type; + prio =3D tmp->prio; + i++; + } + + return true; +} + +void cn20k_tc_update_mcam_table_del_req(struct otx2_nic *nic, + struct otx2_flow_config *flow_cfg, + struct otx2_tc_flow *node) +{ + struct otx2_tc_flow *first, *tmp, *n; + int i =3D 0, index; + u16 cntr_val =3D 0; + u16 entry; + + index =3D cn20k_tc_get_entry_index(flow_cfg, node); + first =3D list_first_entry(&flow_cfg->flow_list_tc, struct otx2_tc_flow, + list); + entry =3D first->entry; + + /* If entries cannot be shifted then delete given entry + * and free it to AF too. + */ + if (!cn20k_tc_check_entry_shiftable(nic, flow_cfg, node, + index, false)) { + list_del(&node->list); + entry =3D node->entry; + goto free_mcam_entry; + } + + /* Find and delete the entry from the list and re-install + * all the entries from beginning to the index of the + * deleted entry to higher mcam indexes. + */ + list_for_each_entry_safe(tmp, n, &flow_cfg->flow_list_tc, list) { + if (node =3D=3D tmp) { + list_del(&tmp->list); + break; + } + + otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val); + tmp->entry =3D (list_next_entry(tmp, list))->entry; + tmp->req.entry =3D tmp->entry; + tmp->req.cntr_val =3D cntr_val; + } + + list_for_each_entry_safe(tmp, n, &flow_cfg->flow_list_tc, list) { + if (i =3D=3D index) + break; + + otx2_add_mcam_flow_entry(nic, &tmp->req); + i++; + } + +free_mcam_entry: + if (cn20k_tc_free_mcam_entry(nic, entry)) + netdev_err(nic->netdev, "Freeing entry %d to AF failed\n", + entry); +} + +int cn20k_tc_update_mcam_table_add_req(struct otx2_nic *nic, + struct otx2_flow_config *flow_cfg, + struct otx2_tc_flow *node) +{ + struct otx2_tc_flow *tmp; + u16 cntr_val =3D 0; + int list_idx, i; + int entry, prev; + + /* Find the index of the entry(list_idx) whose priority + * is greater than the new entry and re-install all + * the entries from beginning to list_idx to higher + * mcam indexes. + */ + list_idx =3D otx2_tc_add_to_flow_list(flow_cfg, node); + entry =3D node->entry; + if (!cn20k_tc_check_entry_shiftable(nic, flow_cfg, node, + list_idx, true)) + /* Due to mix of X2 and X4, entries cannot be shifted. + * In this case free the entry allocated for this rule. + */ + return -EINVAL; + + for (i =3D 0; i < list_idx; i++) { + tmp =3D otx2_tc_get_entry_by_index(flow_cfg, i); + if (!tmp) + return -ENOMEM; + + otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val); + prev =3D tmp->entry; + tmp->entry =3D entry; + tmp->req.entry =3D tmp->entry; + tmp->req.cntr_val =3D cntr_val; + otx2_add_mcam_flow_entry(nic, &tmp->req); + entry =3D prev; + } + + return entry; +} + +#define MAX_TC_HW_PRIORITY 125 +#define MAX_TC_VF_PRIORITY 126 +#define MAX_TC_PF_PRIORITY 127 + +static int __cn20k_tc_alloc_entry(struct otx2_nic *nic, + struct npc_install_flow_req *flow_req, + u16 *entry, u8 *type, + u32 tc_priority, bool hw_priority) +{ + struct otx2_flow_config *flow_cfg =3D nic->flow_cfg; + struct npc_install_flow_req *req; + struct npc_install_flow_rsp *rsp; + struct otx2_tc_flow *tmp; + int ret =3D 0; + + req =3D otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox); + if (!req) + return -ENOMEM; + + memcpy(&flow_req->hdr, &req->hdr, sizeof(struct mbox_msghdr)); + memcpy(req, flow_req, sizeof(struct npc_install_flow_req)); + req->alloc_entry =3D 1; + + /* Allocate very least priority for first rule */ + if (hw_priority || list_empty(&flow_cfg->flow_list_tc)) { + req->ref_prio =3D NPC_MCAM_LEAST_PRIO; + } else { + req->ref_prio =3D NPC_MCAM_HIGHER_PRIO; + tmp =3D list_first_entry(&flow_cfg->flow_list_tc, + struct otx2_tc_flow, list); + req->ref_entry =3D tmp->entry; + } + + ret =3D otx2_sync_mbox_msg(&nic->mbox); + if (ret) + return ret; + + rsp =3D (struct npc_install_flow_rsp *)otx2_mbox_get_rsp(&nic->mbox.mbox, + 0, &req->hdr); + if (IS_ERR(rsp)) + return -EFAULT; + + if (entry) + *entry =3D rsp->entry; + if (type) + *type =3D rsp->kw_type; + + return ret; +} + +int cn20k_tc_alloc_entry(struct otx2_nic *nic, + struct flow_cls_offload *tc_flow_cmd, + struct otx2_tc_flow *new_node, + struct npc_install_flow_req *flow_req) +{ + bool hw_priority =3D false; + u16 entry_from_af; + u8 entry_type; + int ret; + + if (is_otx2_vf(nic->pcifunc)) + flow_req->hw_prio =3D MAX_TC_VF_PRIORITY; + else + flow_req->hw_prio =3D MAX_TC_PF_PRIORITY; + + if (new_node->prio <=3D MAX_TC_HW_PRIORITY) { + flow_req->hw_prio =3D new_node->prio; + hw_priority =3D true; + } + + mutex_lock(&nic->mbox.lock); + + ret =3D __cn20k_tc_alloc_entry(nic, flow_req, &entry_from_af, &entry_type, + new_node->prio, hw_priority); + if (ret) { + mutex_unlock(&nic->mbox.lock); + return ret; + } + + new_node->kw_type =3D entry_type; + new_node->entry =3D entry_from_af; + + mutex_unlock(&nic->mbox.lock); + + return 0; +} + static int cn20k_aura_aq_init(struct otx2_nic *pfvf, int aura_id, int pool_id, int numptrs) { diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.h b/drivers/n= et/ethernet/marvell/octeontx2/nic/cn20k.h index 832adaf8c57f..b5e527f6d7eb 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.h @@ -10,8 +10,22 @@ =20 #include "otx2_common.h" =20 +struct otx2_flow_config; +struct otx2_tc_flow; + void cn20k_init(struct otx2_nic *pfvf); int cn20k_register_pfvf_mbox_intr(struct otx2_nic *pf, int numvfs); void cn20k_disable_pfvf_mbox_intr(struct otx2_nic *pf, int numvfs); void cn20k_enable_pfvf_mbox_intr(struct otx2_nic *pf, int numvfs); +void cn20k_tc_update_mcam_table_del_req(struct otx2_nic *nic, + struct otx2_flow_config *flow_cfg, + struct otx2_tc_flow *node); +int cn20k_tc_update_mcam_table_add_req(struct otx2_nic *nic, + struct otx2_flow_config *flow_cfg, + struct otx2_tc_flow *node); +int cn20k_tc_alloc_entry(struct otx2_nic *nic, + struct flow_cls_offload *tc_flow_cmd, + struct otx2_tc_flow *new_node, + struct npc_install_flow_req *dummy); +int cn20k_tc_free_mcam_entry(struct otx2_nic *nic, u16 entry); #endif /* CN20K_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/dri= vers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index 8cdfc36d79d2..e5287e317834 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -366,6 +366,31 @@ struct otx2_flow_config { u16 ntuple_cnt; }; =20 +struct otx2_tc_flow_stats { + u64 bytes; + u64 pkts; + u64 used; +}; + +struct otx2_tc_flow { + struct list_head list; + unsigned long cookie; + struct rcu_head rcu; + struct otx2_tc_flow_stats stats; + spinlock_t lock; /* lock for stats */ + u16 rq; + u16 entry; + u16 leaf_profile; + bool is_act_police; + u32 prio; + struct npc_install_flow_req req; + u64 rate; + u32 burst; + u32 mcast_grp_idx; + bool is_pps; + u8 kw_type; /* X2/X4 */ +}; + struct dev_hw_ops { int (*sq_aq_init)(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura); @@ -1216,4 +1241,14 @@ void otx2_dma_unmap_skb_frags(struct otx2_nic *pfvf,= struct sg_list *sg); int otx2_read_free_sqe(struct otx2_nic *pfvf, u16 qidx); void otx2_queue_vf_work(struct mbox *mw, struct workqueue_struct *mbox_wq, int first, int mdevs, u64 intr); +int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry, + u16 *cntr_val); +int otx2_add_mcam_flow_entry(struct otx2_nic *nic, + struct npc_install_flow_req *req); +int otx2_tc_add_to_flow_list(struct otx2_flow_config *flow_cfg, + struct otx2_tc_flow *node); + +struct otx2_tc_flow * +otx2_tc_get_entry_by_index(struct otx2_flow_config *flow_cfg, + int index); #endif /* OTX2_COMMON_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers= /net/ethernet/marvell/octeontx2/nic/otx2_tc.c index 26a08d2cfbb1..700b8e0f7481 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c @@ -31,30 +31,6 @@ =20 #define MCAST_INVALID_GRP (-1U) =20 -struct otx2_tc_flow_stats { - u64 bytes; - u64 pkts; - u64 used; -}; - -struct otx2_tc_flow { - struct list_head list; - unsigned long cookie; - struct rcu_head rcu; - struct otx2_tc_flow_stats stats; - spinlock_t lock; /* lock for stats */ - u16 rq; - u16 entry; - u16 leaf_profile; - bool is_act_police; - u32 prio; - struct npc_install_flow_req req; - u32 mcast_grp_idx; - u64 rate; - u32 burst; - bool is_pps; -}; - static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst, u32 *burst_exp, u32 *burst_mantissa) { @@ -971,8 +947,9 @@ static void otx2_destroy_tc_flow_list(struct otx2_nic *= pfvf) } } =20 -static struct otx2_tc_flow *otx2_tc_get_entry_by_cookie(struct otx2_flow_c= onfig *flow_cfg, - unsigned long cookie) +static struct otx2_tc_flow * +otx2_tc_get_entry_by_cookie(struct otx2_flow_config *flow_cfg, + unsigned long cookie) { struct otx2_tc_flow *tmp; =20 @@ -984,8 +961,8 @@ static struct otx2_tc_flow *otx2_tc_get_entry_by_cookie= (struct otx2_flow_config return NULL; } =20 -static struct otx2_tc_flow *otx2_tc_get_entry_by_index(struct otx2_flow_co= nfig *flow_cfg, - int index) +struct otx2_tc_flow * +otx2_tc_get_entry_by_index(struct otx2_flow_config *flow_cfg, int index) { struct otx2_tc_flow *tmp; int i =3D 0; @@ -1014,8 +991,8 @@ static void otx2_tc_del_from_flow_list(struct otx2_flo= w_config *flow_cfg, } } =20 -static int otx2_tc_add_to_flow_list(struct otx2_flow_config *flow_cfg, - struct otx2_tc_flow *node) +int otx2_tc_add_to_flow_list(struct otx2_flow_config *flow_cfg, + struct otx2_tc_flow *node) { struct list_head *pos, *n; struct otx2_tc_flow *tmp; @@ -1038,7 +1015,8 @@ static int otx2_tc_add_to_flow_list(struct otx2_flow_= config *flow_cfg, return index; } =20 -static int otx2_add_mcam_flow_entry(struct otx2_nic *nic, struct npc_insta= ll_flow_req *req) +int otx2_add_mcam_flow_entry(struct otx2_nic *nic, + struct npc_install_flow_req *req) { struct npc_install_flow_req *tmp_req; int err; @@ -1064,7 +1042,7 @@ static int otx2_add_mcam_flow_entry(struct otx2_nic *= nic, struct npc_install_flo return 0; } =20 -static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry, u16 *= cntr_val) +int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry, u16 *cntr_va= l) { struct npc_delete_flow_rsp *rsp; struct npc_delete_flow_req *req; @@ -1114,6 +1092,11 @@ static int otx2_tc_update_mcam_table_del_req(struct = otx2_nic *nic, int i =3D 0, index =3D 0; u16 cntr_val =3D 0; =20 + if (is_cn20k(nic->pdev)) { + cn20k_tc_update_mcam_table_del_req(nic, flow_cfg, node); + return 0; + } + /* Find and delete the entry from the list and re-install * all the entries from beginning to the index of the * deleted entry to higher mcam indexes. @@ -1153,6 +1136,9 @@ static int otx2_tc_update_mcam_table_add_req(struct o= tx2_nic *nic, int list_idx, i; u16 cntr_val =3D 0; =20 + if (is_cn20k(nic->pdev)) + return cn20k_tc_update_mcam_table_add_req(nic, flow_cfg, node); + /* Find the index of the entry(list_idx) whose priority * is greater than the new entry and re-install all * the entries from beginning to list_idx to higher @@ -1172,7 +1158,7 @@ static int otx2_tc_update_mcam_table_add_req(struct o= tx2_nic *nic, mcam_idx++; } =20 - return mcam_idx; + return flow_cfg->flow_ent[mcam_idx]; } =20 static int otx2_tc_update_mcam_table(struct otx2_nic *nic, @@ -1238,7 +1224,6 @@ static int otx2_tc_del_flow(struct otx2_nic *nic, mutex_unlock(&nic->mbox.lock); } =20 - free_mcam_flow: otx2_del_mcam_flow_entry(nic, flow_node->entry, NULL); otx2_tc_update_mcam_table(nic, flow_cfg, flow_node, false); @@ -1254,7 +1239,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic, struct otx2_flow_config *flow_cfg =3D nic->flow_cfg; struct otx2_tc_flow *new_node, *old_node; struct npc_install_flow_req *req, dummy; - int rc, err, mcam_idx; + int rc, err, entry; =20 if (!(nic->flags & OTX2_FLAG_TC_FLOWER_SUPPORT)) return -ENOMEM; @@ -1264,7 +1249,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic, return -EINVAL; } =20 - if (flow_cfg->nr_flows =3D=3D flow_cfg->max_flows) { + if (!is_cn20k(nic->pdev) && flow_cfg->nr_flows =3D=3D flow_cfg->max_flows= ) { NL_SET_ERR_MSG_MOD(extack, "Free MCAM entry not available to add the flow"); return -ENOMEM; @@ -1292,7 +1277,23 @@ static int otx2_tc_add_flow(struct otx2_nic *nic, if (old_node) otx2_tc_del_flow(nic, tc_flow_cmd); =20 - mcam_idx =3D otx2_tc_update_mcam_table(nic, flow_cfg, new_node, true); + if (is_cn20k(nic->pdev)) { + rc =3D cn20k_tc_alloc_entry(nic, tc_flow_cmd, new_node, &dummy); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, + "MCAM rule allocation failed"); + kfree_rcu(new_node, rcu); + return rc; + } + } + + entry =3D otx2_tc_update_mcam_table(nic, flow_cfg, new_node, true); + if (entry < 0) { + NL_SET_ERR_MSG_MOD(extack, "Adding rule failed"); + rc =3D entry; + goto free_leaf; + } + mutex_lock(&nic->mbox.lock); req =3D otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox); if (!req) { @@ -1304,7 +1305,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic, memcpy(&dummy.hdr, &req->hdr, sizeof(struct mbox_msghdr)); memcpy(req, &dummy, sizeof(struct npc_install_flow_req)); req->channel =3D nic->hw.rx_chan_base; - req->entry =3D flow_cfg->flow_ent[mcam_idx]; + req->entry =3D (u16)entry; req->intf =3D NIX_INTF_RX; req->vf =3D nic->pcifunc; req->set_cntr =3D 1; @@ -1325,6 +1326,8 @@ static int otx2_tc_add_flow(struct otx2_nic *nic, return 0; =20 free_leaf: + if (is_cn20k(nic->pdev)) + cn20k_tc_free_mcam_entry(nic, new_node->entry); otx2_tc_del_from_flow_list(flow_cfg, new_node); if (new_node->is_act_police) { mutex_lock(&nic->mbox.lock); --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 680E92C11DD; Mon, 2 Feb 2026 07:47:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.156.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018428; cv=none; b=Vq94KvoqlX/0TwvLLpPGaVm9QuG5ppyJ+5x2rIN4IRpqyvF+IorLY/cMl01cwpoRRAsSwbrdSUFB+TmUk16JG1VCDl5SUdGPnFj2n6u4lZnHyYyaKWIFeCej5JwkYgPBdXtr2+NTCVtWch2yV6l8DWxEO0FZftlEBRHXmPYharM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018428; c=relaxed/simple; bh=H2t4dNUqFkQg4jWXQ0+JQdLkKsTN4x3SADKE7x2bj2c=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MLgSVFoXrjWIbu67AvLZ+JkvRrKDdWtiPiSbQs8kxl1UbRuvprbzdzjRRb1jUcULg+Fqqg5yDGZTIO3A1yNx8b8WNsAQDZ7LvU6WzGna/WGyK6h/ZLUYKl6bIocY0lGF8wtgr2J0upmdy+gNw7MKts+0PbuwuE08W2ITLJm4q/E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=QbdYqobN; arc=none smtp.client-ip=67.231.156.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="QbdYqobN" Received: from pps.filterd (m0431383.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 611NhMFg3444759; Sun, 1 Feb 2026 23:46:57 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=d sFdzb4xZ3RkWS2AUpghp1Zp9yrWbTiGOhJAI1bd7Bg=; b=QbdYqobNA5a9E6NSb wNhyY5F7i9XMnpNggxKRVrNxx/fs8k5GLzazW/3zCj9tqj6gsw2Z81K0vSSBoI4R hfy9HBr/BesfjU6uysYdCPpx9tQocjx0yhcqswVN/QvaN5VpWEATAqOyYFNu7AUM 6ihOneBV800CYs4cBwDFwx05+54sUHW241oK3nbpV0tqtqerv6v2R7tmDa2NpRql ju99uUmMnOTHV85yR2Hq/dkH8ymwnFJoI9VIIbqTDu7kYNMSLUpQxvvmg8gStI1Y VhQ0JeBHdDGGYneTr8Kce5hFuwjVMoBcnnd/ZLyPExXivxhNt2s3EN/LTRqf+23U H9XCg== Received: from dc6wp-exch02.marvell.com ([4.21.29.225]) by mx0b-0016f401.pphosted.com (PPS) with ESMTPS id 4c28mvs7jx-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:46:57 -0800 (PST) Received: from DC6WP-EXCH02.marvell.com (10.76.176.209) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:47:22 -0800 Received: from maili.marvell.com (10.69.176.80) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:47:22 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 7E59F5B6946; Sun, 1 Feb 2026 23:46:53 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH net-next v8 12/13] octeontx2-af: npc: cn20k: add debugfs support Date: Mon, 2 Feb 2026 13:16:06 +0530 Message-ID: <20260202074607.2535569-13-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authority-Analysis: v=2.4 cv=MuhfKmae c=1 sm=1 tr=0 ts=69805671 cx=c_pps a=gIfcoYsirJbf48DBMSPrZA==:117 a=gIfcoYsirJbf48DBMSPrZA==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=VlSHqinqd2IHOLuXnyEA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-ORIG-GUID: v71fMpV79tHhgAFgy8390AvU88ykR1Z3 X-Proofpoint-GUID: v71fMpV79tHhgAFgy8390AvU88ykR1Z3 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfX6hXmeRgQ7eJD 39FuV0yXYrQelrlxv76L5jgCBVSOy1mfjZEO7FYNGkwFQzj5yQink3vgjwmtECzhP6aZa+FYySw pnjPXRtbc04MCZK//SqhkbrsLlIvYIcquM2hXbvT/BUem3lsiUPn3KPlLWilPHQG1PjvRnmyci0 Gubygbugrvscunv1o3yFFxHWV9hGq8cmdPHEspGYZocnJnGRONel8C5IIiHFSpTPAxjy3WtTH+D cYyeRTNMD17Eh8J8WfkcJe7XgvtZtHXP8iKDc1s+UGgvRVaYtmJbpjNU2eIFDYBiKmu24R8PRwX iwL+prj1Y/Sh9GKubfdz8K6vUAoLNjygGmCmwxh6szplVZIYlbFyoRDZngIqW0XwOU7KJPGJNgw Y2f7vU7LtkZH46oaRE/q5XWWF+ajl7LRr2ibxNAVkrgtYj545vnTdsI93tcm8AI92mt+3464oY2 UUCtH+Xal/stS9yAOMA== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" CN20K silicon divides the NPC MCAM into banks and subbanks, with each subbank configurable for x2 or x4 key widths. This patch adds debugfs entries to expose subbank usage details and their configured key type. A debugfs entry is also added to display the default MCAM indexes allocated for each pcifunc. Additionally, debugfs support is introduced to show the mapping between virtual indexes and real MCAM indexes, and vice versa. Signed-off-by: Ratheesh Kannoth --- .../marvell/octeontx2/af/cn20k/debugfs.c | 261 ++++++++++++++++++ .../marvell/octeontx2/af/rvu_debugfs.c | 41 ++- 2 files changed, 292 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c b/dr= ivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c index 0ba123be6643..3debf2fae1a4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c @@ -15,8 +15,269 @@ #include "debugfs.h" #include "cn20k/npc.h" =20 +static int npc_mcam_layout_show(struct seq_file *s, void *unused) +{ + int i, j, sbd, idx0, idx1, vidx0, vidx1; + struct npc_priv_t *npc_priv; + char buf0[32], buf1[32]; + struct npc_subbank *sb; + unsigned int bw0, bw1; + bool v0, v1; + int pf1, pf2; + bool e0, e1; + void *map; + + npc_priv =3D s->private; + + sbd =3D npc_priv->subbank_depth; + + for (i =3D npc_priv->num_subbanks - 1; i >=3D 0; i--) { + sb =3D &npc_priv->sb[i]; + mutex_lock(&sb->lock); + + if (sb->flags & NPC_SUBBANK_FLAG_FREE) + goto next; + + bw0 =3D bitmap_weight(sb->b0map, npc_priv->subbank_depth); + if (sb->key_type =3D=3D NPC_MCAM_KEY_X4) { + seq_printf(s, "\n\nsubbank:%u, x4, free=3D%u, used=3D%u\n", + sb->idx, sb->free_cnt, bw0); + + for (j =3D sbd - 1; j >=3D 0; j--) { + if (!test_bit(j, sb->b0map)) + continue; + + idx0 =3D sb->b0b + j; + map =3D xa_load(&npc_priv->xa_idx2pf_map, idx0); + pf1 =3D xa_to_value(map); + + map =3D xa_load(&npc_priv->xa_idx2vidx_map, idx0); + if (map) { + vidx0 =3D xa_to_value(map); + snprintf(buf0, sizeof(buf0), + "v:%u", vidx0); + } + + seq_printf(s, "\t%u(%#x) %s\n", idx0, pf1, + map ? buf0 : " "); + } + goto next; + } + + bw1 =3D bitmap_weight(sb->b1map, npc_priv->subbank_depth); + seq_printf(s, "\n\nsubbank:%u, x2, free=3D%u, used=3D%u\n", + sb->idx, sb->free_cnt, bw0 + bw1); + seq_printf(s, "bank1(%u)\t\tbank0(%u)\n", bw1, bw0); + + for (j =3D sbd - 1; j >=3D 0; j--) { + e0 =3D test_bit(j, sb->b0map); + e1 =3D test_bit(j, sb->b1map); + + if (!e1 && !e0) + continue; + + if (e1 && e0) { + idx0 =3D sb->b0b + j; + map =3D xa_load(&npc_priv->xa_idx2pf_map, idx0); + pf1 =3D xa_to_value(map); + + map =3D xa_load(&npc_priv->xa_idx2vidx_map, idx0); + v0 =3D !!map; + if (v0) { + vidx0 =3D xa_to_value(map); + snprintf(buf0, sizeof(buf0), "v:%05u", + vidx0); + } + + idx1 =3D sb->b1b + j; + map =3D xa_load(&npc_priv->xa_idx2pf_map, idx1); + pf2 =3D xa_to_value(map); + + map =3D xa_load(&npc_priv->xa_idx2vidx_map, idx1); + v1 =3D !!map; + if (v1) { + vidx1 =3D xa_to_value(map); + snprintf(buf1, sizeof(buf1), "v:%05u", + vidx1); + } + + seq_printf(s, "%05u(%#x) %s\t\t%05u(%#x) %s\n", + idx1, pf2, v1 ? buf1 : " ", + idx0, pf1, v0 ? buf0 : " "); + + continue; + } + + if (e0) { + idx0 =3D sb->b0b + j; + map =3D xa_load(&npc_priv->xa_idx2pf_map, idx0); + pf1 =3D xa_to_value(map); + + map =3D xa_load(&npc_priv->xa_idx2vidx_map, idx0); + if (map) { + vidx0 =3D xa_to_value(map); + snprintf(buf0, sizeof(buf0), "v:%05u", + vidx0); + } + + seq_printf(s, "\t\t \t\t%05u(%#x) %s\n", idx0, + pf1, map ? buf0 : " "); + continue; + } + + idx1 =3D sb->b1b + j; + map =3D xa_load(&npc_priv->xa_idx2pf_map, idx1); + pf1 =3D xa_to_value(map); + map =3D xa_load(&npc_priv->xa_idx2vidx_map, idx1); + if (map) { + vidx1 =3D xa_to_value(map); + snprintf(buf1, sizeof(buf1), "v:%05u", vidx1); + } + + seq_printf(s, "%05u(%#x) %s\n", idx1, pf1, + map ? buf1 : " "); + } +next: + mutex_unlock(&sb->lock); + } + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(npc_mcam_layout); + +static int npc_mcam_default_show(struct seq_file *s, void *unused) +{ + struct npc_priv_t *npc_priv; + unsigned long index; + u16 ptr[4], pcifunc; + struct rvu *rvu; + int rc, i; + void *map; + + npc_priv =3D npc_priv_get(); + rvu =3D s->private; + + seq_puts(s, "\npcifunc\tBcast\tmcast\tpromisc\tucast\n"); + + xa_for_each(&npc_priv->xa_pf_map, index, map) { + pcifunc =3D index; + + for (i =3D 0; i < ARRAY_SIZE(ptr); i++) + ptr[i] =3D USHRT_MAX; + + rc =3D npc_cn20k_dft_rules_idx_get(rvu, pcifunc, &ptr[0], + &ptr[1], &ptr[2], &ptr[3]); + if (rc) + continue; + + seq_printf(s, "%#x\t", pcifunc); + for (i =3D 0; i < ARRAY_SIZE(ptr); i++) { + if (ptr[i] !=3D USHRT_MAX) + seq_printf(s, "%u\t", ptr[i]); + else + seq_puts(s, "\t"); + } + seq_puts(s, "\n"); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(npc_mcam_default); + +static int npc_vidx2idx_map_show(struct seq_file *s, void *unused) +{ + struct npc_priv_t *npc_priv; + unsigned long index, start; + struct xarray *xa; + void *map; + + npc_priv =3D s->private; + start =3D npc_priv->bank_depth * 2; + xa =3D &npc_priv->xa_vidx2idx_map; + + seq_puts(s, "\nvidx\tmcam_idx\n"); + + xa_for_each_start(xa, index, map, start) + seq_printf(s, "%lu\t%lu\n", index, xa_to_value(map)); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(npc_vidx2idx_map); + +static int npc_idx2vidx_map_show(struct seq_file *s, void *unused) +{ + struct npc_priv_t *npc_priv; + unsigned long index; + struct xarray *xa; + void *map; + + npc_priv =3D s->private; + xa =3D &npc_priv->xa_idx2vidx_map; + + seq_puts(s, "\nmidx\tvidx\n"); + + xa_for_each(xa, index, map) + seq_printf(s, "%lu\t%lu\n", index, xa_to_value(map)); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(npc_idx2vidx_map); + +static int npc_defrag_show(struct seq_file *s, void *unused) +{ + struct npc_defrag_show_node *node; + struct npc_priv_t *npc_priv; + u16 sbd, bdm; + + npc_priv =3D s->private; + bdm =3D npc_priv->bank_depth - 1; + sbd =3D npc_priv->subbank_depth; + + seq_puts(s, "\nold(sb) -> new(sb)\t\tvidx\n"); + + mutex_lock(&npc_priv->lock); + list_for_each_entry(node, &npc_priv->defrag_lh, list) + seq_printf(s, "%u(%u)\t%u(%u)\t%u\n", node->old_midx, + (node->old_midx & bdm) / sbd, + node->new_midx, + (node->new_midx & bdm) / sbd, + node->vidx); + mutex_unlock(&npc_priv->lock); + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(npc_defrag); + int npc_cn20k_debugfs_init(struct rvu *rvu) { + struct npc_priv_t *npc_priv =3D npc_priv_get(); + struct dentry *npc_dentry; + + npc_dentry =3D debugfs_create_file("mcam_layout", 0444, rvu->rvu_dbg.npc, + npc_priv, &npc_mcam_layout_fops); + + if (!npc_dentry) + return -EFAULT; + + npc_dentry =3D debugfs_create_file("mcam_default", 0444, rvu->rvu_dbg.npc, + rvu, &npc_mcam_default_fops); + + if (!npc_dentry) + return -EFAULT; + + npc_dentry =3D debugfs_create_file("vidx2idx", 0444, rvu->rvu_dbg.npc, + npc_priv, &npc_vidx2idx_map_fops); + if (!npc_dentry) + return -EFAULT; + + npc_dentry =3D debugfs_create_file("idx2vidx", 0444, rvu->rvu_dbg.npc, + npc_priv, &npc_idx2vidx_map_fops); + if (!npc_dentry) + return -EFAULT; + + npc_dentry =3D debugfs_create_file("defrag", 0444, rvu->rvu_dbg.npc, + npc_priv, &npc_defrag_fops); + if (!npc_dentry) + return -EFAULT; + return 0; } =20 diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/driv= ers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index 620724dad093..413f9fa40b33 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -23,6 +23,7 @@ =20 #include "cn20k/reg.h" #include "cn20k/debugfs.h" +#include "cn20k/npc.h" =20 #define DEBUGFS_DIR_NAME "octeontx2" =20 @@ -3197,7 +3198,9 @@ static void rvu_print_npc_mcam_info(struct seq_file *= s, static int rvu_dbg_npc_mcam_info_display(struct seq_file *filp, void *unsu= ed) { struct rvu *rvu =3D filp->private; + int x4_free, x2_free, sb_free; int pf, vf, numvfs, blkaddr; + struct npc_priv_t *npc_priv; struct npc_mcam *mcam; u16 pcifunc, counters; u64 cfg; @@ -3211,16 +3214,34 @@ static int rvu_dbg_npc_mcam_info_display(struct seq= _file *filp, void *unsued) =20 seq_puts(filp, "\nNPC MCAM info:\n"); /* MCAM keywidth on receive and transmit sides */ - cfg =3D rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_RX)); - cfg =3D (cfg >> 32) & 0x07; - seq_printf(filp, "\t\t RX keywidth \t: %s\n", (cfg =3D=3D NPC_MCAM_KEY_X1= ) ? - "112bits" : ((cfg =3D=3D NPC_MCAM_KEY_X2) ? - "224bits" : "448bits")); - cfg =3D rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_TX)); - cfg =3D (cfg >> 32) & 0x07; - seq_printf(filp, "\t\t TX keywidth \t: %s\n", (cfg =3D=3D NPC_MCAM_KEY_X1= ) ? - "112bits" : ((cfg =3D=3D NPC_MCAM_KEY_X2) ? - "224bits" : "448bits")); + if (is_cn20k(rvu->pdev)) { + npc_priv =3D npc_priv_get(); + seq_printf(filp, "\t\t RX keywidth \t: %s\n", + (npc_priv->kw =3D=3D NPC_MCAM_KEY_X1) ? + "256bits" : "512bits"); + + npc_cn20k_subbank_calc_free(rvu, &x2_free, &x4_free, &sb_free); + seq_printf(filp, "\t\t free x4 slots\t: %d\n", x4_free); + + seq_printf(filp, "\t\t free x2 slots\t: %d\n", x2_free); + + seq_printf(filp, "\t\t free subbanks\t: %d\n", sb_free); + } else { + cfg =3D rvu_read64(rvu, blkaddr, + NPC_AF_INTFX_KEX_CFG(NIX_INTF_RX)); + cfg =3D (cfg >> 32) & 0x07; + seq_printf(filp, "\t\t RX keywidth \t: %s\n", + (cfg =3D=3D NPC_MCAM_KEY_X1) ? + "112bits" : ((cfg =3D=3D NPC_MCAM_KEY_X2) ? + "224bits" : "448bits")); + cfg =3D rvu_read64(rvu, blkaddr, + NPC_AF_INTFX_KEX_CFG(NIX_INTF_TX)); + cfg =3D (cfg >> 32) & 0x07; + seq_printf(filp, "\t\t TX keywidth \t: %s\n", + (cfg =3D=3D NPC_MCAM_KEY_X1) ? + "112bits" : ((cfg =3D=3D NPC_MCAM_KEY_X2) ? + "224bits" : "448bits")); + } =20 mutex_lock(&mcam->lock); /* MCAM entries */ --=20 2.43.0 From nobody Sat Feb 7 19:41:08 2026 Received: from mx0a-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE75330C37C; Mon, 2 Feb 2026 07:47:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018431; cv=none; b=OB/HW4EZUj97qane5+W9xVSs1lCfg/3KnLypB/r48XH8rfuU82HSGktJVVdcGk+qDWV2IHfJ8KvyeRea9EFLW7eBTFKEZxG29V8JVHJ4wLPP7YMKyOKz0obJnx5AB007LdtxVzqPHurCRM77NMk+53ar/yXRYA1L/ceFmw92sow= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770018431; c=relaxed/simple; bh=387M639IklX61YE7fdg8NJfnNKGD7nmL/PHCDI9px2E=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=eaSgEAoa6xqjsJ7KWqmGfc+qy4ItKNi0vNCL0BdcnhNuaygnv/tFJUgP5yVKa6rzqICngdpzQ7FQ38691oh2gtD3yhQc7c8LEZsV37pKhCEBjtG/dW7IDVhzn4n1yN2ag6/UN6Hw4RHZMNKbgvoVxIeukU0foBEoyAhqMTXSzbQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=bO6Of88l; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="bO6Of88l" Received: from pps.filterd (m0431384.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6126upce904509; Sun, 1 Feb 2026 23:47:00 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=+ D/1pLH2bBhS8I26inJbyhb+DEwehHlL9LxFVCuWNjc=; b=bO6Of88ln2rGqQBKF 4CKDqUJO87tmQxRmNgLDO1b8tQeRUEmeOOPVG7l7PeThcYBGrO7gvbT/RCMV8dgO OaryqmL3Hu0UdvPDGomlEXVETzs27WbBuZX4Y/6144tsk3rLCDIHy3p8fR80KlGC luj+bbTlL0T/vte+RunReRq4dKwWOIf8+3ryIoi4ESmcOWJJ+0tU1xHo2nIwysJ7 AF+hyslr9DNd1pXqYLVTl5Owa43d6SmTlhkIX/lCzsW+2AOM/esM8oIyTEj6xxkw D1+6MFhYmyF/3PJKn5f6mL+Y/giWG60ahHwsJQLOfHB7/YnihnBSEnUAgS+umoks i0/rw== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4c2q3q02qe-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 23:47:00 -0800 (PST) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Sun, 1 Feb 2026 23:47:16 -0800 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Sun, 1 Feb 2026 23:47:16 -0800 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id DA8255B6946; Sun, 1 Feb 2026 23:46:56 -0800 (PST) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH net-next v8 13/13] octeontx2-af: npc: Use common structures Date: Mon, 2 Feb 2026 13:16:07 +0530 Message-ID: <20260202074607.2535569-14-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260202074607.2535569-1-rkannoth@marvell.com> References: <20260202074607.2535569-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authority-Analysis: v=2.4 cv=ZeoQ98VA c=1 sm=1 tr=0 ts=69805674 cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=M5GUcnROAAAA:8 a=bNx57pydN-Y4TXDtlhsA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-GUID: v3aYI7r7eqm1Z1dzlXtETMpAhYPs0Gty X-Proofpoint-ORIG-GUID: v3aYI7r7eqm1Z1dzlXtETMpAhYPs0Gty X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAyMDA2NiBTYWx0ZWRfX6HDTLEQ5Su5m 8ZW+wEmR1rxfmN6tLcUMtwGzuxXA4NKdsvDDgNxKNnfzw79yGwPySI1eYYjwV8RD8HqRjP2TjDB fWW8aTLqrjMSUBNu1oQtU+yoGjBIoSj22Ua9B1r9ITgUFLxQhtEwgbbAQxjW5vujCkPAQ5kRXr3 NW+sZvmq2iW0n91rkXGzsvHtQWGHcnVgIndK7mDjp1tXCQzn+s/xXLO1YwCUSpTTAsiYIRBqVMs c0sG26/sDr2QHhNzUtyVtQTfOlSGClsdRarg91okAD7P5IyIaxpaSQoUDKZLa2v2WzNAenxnond j2dGRa6dPIw7FXgunCyIAhYi2ildDNrJn5+vCcJnDQEvlGo2u6dk1vVOFlToxig5iNxS12oMrfO D2QOz1QQVzJj9biDjS72365qzcGwOHwvFTVD5N7NDv+iodg0gmGMY1MI+dpMIc24T0vpLLm6lOC cl4w3fsGXPzMDfHn9Fw== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-02_02,2026-01-30_04,2025-10-01_01 Content-Type: text/plain; charset="utf-8" CN20K and legacy silicon differ in the size of key words used in NPC MCAM. However, SoC-specific structures are not required for low-level functions. Remove the SoC-specific structures and rename the macros to improve readability. Signed-off-by: Ratheesh Kannoth --- .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 11 ++++--- .../net/ethernet/marvell/octeontx2/af/mbox.h | 16 ++++++---- .../net/ethernet/marvell/octeontx2/af/rvu.h | 2 +- .../marvell/octeontx2/af/rvu_npc_fs.c | 31 ++++++++----------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/driver= s/net/ethernet/marvell/octeontx2/af/cn20k/npc.c index 237e6f606fc1..b9354d35cc44 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c @@ -3948,10 +3948,10 @@ int rvu_mbox_handler_npc_get_num_kws(struct rvu *rv= u, struct npc_get_num_kws_req *req, struct npc_get_num_kws_rsp *rsp) { + u64 kw_mask[NPC_KWS_IN_KEY_SZ_MAX] =3D { 0 }; + u64 kw[NPC_KWS_IN_KEY_SZ_MAX] =3D { 0 }; struct rvu_npc_mcam_rule dummy =3D { 0 }; - struct cn20k_mcam_entry cn20k_entry =3D { 0 }; struct mcam_entry_mdata mdata =3D { }; - struct mcam_entry entry =3D { 0 }; struct npc_install_flow_req *fl; int i, cnt =3D 0, blkaddr; =20 @@ -3968,7 +3968,8 @@ int rvu_mbox_handler_npc_get_num_kws(struct rvu *rvu, return NPC_MCAM_INVALID_REQ; } =20 - npc_populate_mcam_mdata(rvu, &mdata, &cn20k_entry, &entry); + mdata.kw =3D kw; + mdata.kw_mask =3D kw_mask; =20 npc_update_flow(rvu, &mdata, fl->features, &fl->packet, &fl->mask, &dummy, fl->intf, blkaddr); @@ -3976,8 +3977,8 @@ int rvu_mbox_handler_npc_get_num_kws(struct rvu *rvu, /* Find the most significant word valid. Traverse from * MSB to LSB, check if cam0 or cam1 is set */ - for (i =3D NPC_CN20K_MAX_KWS_IN_KEY - 1; i >=3D 0; i--) { - if (cn20k_entry.kw[i] || cn20k_entry.kw_mask[i]) { + for (i =3D NPC_KWS_IN_KEY_SZ_MAX - 1; i >=3D 0; i--) { + if (kw[i] || kw_mask[i]) { cnt =3D i + 1; break; } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index 2d9f6cb4820f..dc42c81c0942 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1593,18 +1593,22 @@ struct mcam_entry_mdata { u8 max_kw; }; =20 +enum npc_kws_in_key_sz { + NPC_KWS_IN_KEY_SZ_7 =3D 7, + NPC_KWS_IN_KEY_SZ_8 =3D 8, + NPC_KWS_IN_KEY_SZ_MAX, +}; + struct mcam_entry { -#define NPC_MAX_KWS_IN_KEY 7 /* Number of keywords in max keywidth */ - u64 kw[NPC_MAX_KWS_IN_KEY]; - u64 kw_mask[NPC_MAX_KWS_IN_KEY]; + u64 kw[NPC_KWS_IN_KEY_SZ_7]; + u64 kw_mask[NPC_KWS_IN_KEY_SZ_7]; u64 action; u64 vtag_action; }; =20 struct cn20k_mcam_entry { -#define NPC_CN20K_MAX_KWS_IN_KEY 8 - u64 kw[NPC_CN20K_MAX_KWS_IN_KEY]; - u64 kw_mask[NPC_CN20K_MAX_KWS_IN_KEY]; + u64 kw[NPC_KWS_IN_KEY_SZ_8]; + u64 kw_mask[NPC_KWS_IN_KEY_SZ_8]; u64 action; u64 vtag_action; u64 action2; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.h index f811d6b5c545..a466181cf908 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -197,7 +197,7 @@ struct npc_key_field { /* Masks where all set bits indicate position * of a field in the key */ - u64 kw_mask[NPC_CN20K_MAX_KWS_IN_KEY]; + u64 kw_mask[NPC_KWS_IN_KEY_SZ_MAX]; /* Number of words in the key a field spans. If a field is * of 16 bytes and key offset is 4 then the field will use * 4 bytes in KW0, 8 bytes in KW1 and 4 bytes in KW2 and diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drive= rs/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index b9572de1d175..ecaf196bdd2c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -227,7 +227,7 @@ static bool npc_check_overlap(struct rvu *rvu, int blka= ddr, input =3D &mcam->tx_key_fields[type]; } =20 - kws =3D NPC_MAX_KWS_IN_KEY; + kws =3D NPC_KWS_IN_KEY_SZ_7; =20 if (is_cn20k(rvu->pdev)) goto skip_cn10k_config; @@ -289,7 +289,7 @@ static bool npc_check_overlap(struct rvu *rvu, int blka= ddr, * field bits */ if (npc_check_overlap_fields(dummy, input, - NPC_CN20K_MAX_KWS_IN_KEY)) + NPC_KWS_IN_KEY_SZ_8)) return true; } } @@ -460,9 +460,9 @@ static void npc_handle_multi_layer_fields(struct rvu *r= vu, int blkaddr, u8 intf) u8 start_lid; =20 if (is_cn20k(rvu->pdev)) - max_kw =3D NPC_CN20K_MAX_KWS_IN_KEY; + max_kw =3D NPC_KWS_IN_KEY_SZ_8; else - max_kw =3D NPC_MAX_KWS_IN_KEY; + max_kw =3D NPC_KWS_IN_KEY_SZ_7; =20 key_fields =3D mcam->rx_key_fields; features =3D &mcam->rx_features; @@ -906,12 +906,12 @@ void npc_update_entry(struct rvu *rvu, enum key_field= s type, struct mcam_entry_mdata *mdata, u64 val_lo, u64 val_hi, u64 mask_lo, u64 mask_hi, u8 intf) { - struct cn20k_mcam_entry cn20k_dummy =3D { {0} }; + u64 kw_mask[NPC_KWS_IN_KEY_SZ_MAX] =3D { 0 }; + u64 kw[NPC_KWS_IN_KEY_SZ_MAX] =3D { 0 }; struct npc_mcam *mcam =3D &rvu->hw->mcam; - struct mcam_entry dummy =3D { {0} }; - u64 *kw, *kw_mask, *val, *mask; struct npc_key_field *field; u64 kw1, kw2, kw3; + u64 *val, *mask; int i, max_kw; u8 shift; =20 @@ -922,15 +922,10 @@ void npc_update_entry(struct rvu *rvu, enum key_field= s type, if (!field->nr_kws) return; =20 - if (is_cn20k(rvu->pdev)) { - max_kw =3D NPC_CN20K_MAX_KWS_IN_KEY; - kw =3D cn20k_dummy.kw; - kw_mask =3D cn20k_dummy.kw_mask; - } else { - max_kw =3D NPC_MAX_KWS_IN_KEY; - kw =3D dummy.kw; - kw_mask =3D dummy.kw_mask; - } + if (is_cn20k(rvu->pdev)) + max_kw =3D NPC_KWS_IN_KEY_SZ_8; + else + max_kw =3D NPC_KWS_IN_KEY_SZ_7; =20 for (i =3D 0; i < max_kw; i++) { if (!field->kw_mask[i]) @@ -1315,14 +1310,14 @@ npc_populate_mcam_mdata(struct rvu *rvu, mdata->kw_mask =3D cn20k_entry->kw_mask; mdata->action =3D &cn20k_entry->action; mdata->vtag_action =3D &cn20k_entry->vtag_action; - mdata->max_kw =3D NPC_CN20K_MAX_KWS_IN_KEY; + mdata->max_kw =3D NPC_KWS_IN_KEY_SZ_8; return; } mdata->kw =3D entry->kw; mdata->kw_mask =3D entry->kw_mask; mdata->action =3D &entry->action; mdata->vtag_action =3D &entry->vtag_action; - mdata->max_kw =3D NPC_MAX_KWS_IN_KEY; + mdata->max_kw =3D NPC_KWS_IN_KEY_SZ_7; } =20 static int npc_update_rx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf, --=20 2.43.0