Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2235217/?format=api
{ "id": 2235217, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2235217/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20260508034912.4082520-8-rkannoth@marvell.com/", "project": { "id": 46, "url": "http://patchwork.ozlabs.org/api/1.2/projects/46/?format=api", "name": "Intel Wired Ethernet development", "link_name": "intel-wired-lan", "list_id": "intel-wired-lan.osuosl.org", "list_email": "intel-wired-lan@osuosl.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260508034912.4082520-8-rkannoth@marvell.com>", "list_archive_url": null, "date": "2026-05-08T03:49:10", "name": "[v12,net-next,7/9] octeontx2-af: npc: Support for custom KPU profile from filesystem", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "ba2c822c00a707c6484b498957fa77184bb8a3da", "submitter": { "id": 86908, "url": "http://patchwork.ozlabs.org/api/1.2/people/86908/?format=api", "name": "Ratheesh Kannoth", "email": "rkannoth@marvell.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20260508034912.4082520-8-rkannoth@marvell.com/mbox/", "series": [ { "id": 503453, "url": "http://patchwork.ozlabs.org/api/1.2/series/503453/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=503453", "date": "2026-05-08T03:49:12", "name": "octeontx2-af: npc: Enhancements.", "version": 12, "mbox": "http://patchwork.ozlabs.org/series/503453/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2235217/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2235217/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<intel-wired-lan-bounces@osuosl.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=osuosl.org header.i=@osuosl.org header.a=rsa-sha256\n header.s=default header.b=sjyRiodV;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=osuosl.org\n (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org;\n envelope-from=intel-wired-lan-bounces@osuosl.org;\n receiver=patchwork.ozlabs.org)" ], "Received": [ "from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4gC3Dr47jPz1yMp\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 09 May 2026 08:09:16 +1000 (AEST)", "from localhost (localhost [127.0.0.1])\n\tby smtp1.osuosl.org (Postfix) with ESMTP id 37C8584AA5;\n\tFri, 8 May 2026 22:09:15 +0000 (UTC)", "from smtp1.osuosl.org ([127.0.0.1])\n by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id 5Am9a-Ut59lN; Fri, 8 May 2026 22:09:13 +0000 (UTC)", "from lists1.osuosl.org (lists1.osuosl.org [140.211.166.142])\n\tby smtp1.osuosl.org (Postfix) with ESMTP id 41AD684AA8;\n\tFri, 8 May 2026 22:09:13 +0000 (UTC)", "from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136])\n by lists1.osuosl.org (Postfix) with ESMTP id EF758272\n for <intel-wired-lan@lists.osuosl.org>; Fri, 8 May 2026 04:06:59 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n by smtp3.osuosl.org (Postfix) with ESMTP id E0B3161286\n for <intel-wired-lan@lists.osuosl.org>; Fri, 8 May 2026 04:06:59 +0000 (UTC)", "from smtp3.osuosl.org ([127.0.0.1])\n by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id e2rx4JAKUmux for <intel-wired-lan@lists.osuosl.org>;\n Fri, 8 May 2026 04:06:58 +0000 (UTC)", "from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com\n [67.231.148.174])\n by smtp3.osuosl.org (Postfix) with ESMTPS id 58B6961284\n for <intel-wired-lan@lists.osuosl.org>; Fri, 8 May 2026 04:06:58 +0000 (UTC)", "from pps.filterd (m0045849.ppops.net [127.0.0.1])\n by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id\n 647G5Y6g2850587; Thu, 7 May 2026 20:50:49 -0700", "from dc6wp-exch02.marvell.com ([4.21.29.225])\n by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4e0wy29qj3-1\n (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT);\n Thu, 07 May 2026 20:50:49 -0700 (PDT)", "from DC6WP-EXCH02.marvell.com (10.76.176.209) by\n DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server\n (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.2.1544.25; Thu, 7 May 2026 20:50:47 -0700", "from maili.marvell.com (10.69.176.80) by DC6WP-EXCH02.marvell.com\n (10.76.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend\n Transport; Thu, 7 May 2026 20:50:47 -0700", "from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165])\n by maili.marvell.com (Postfix) with ESMTP id 842B83F7041;\n Thu, 7 May 2026 20:50:36 -0700 (PDT)" ], "X-Virus-Scanned": [ "amavis at osuosl.org", "amavis at osuosl.org" ], "X-Comment": "SPF check N/A for local connections - client-ip=140.211.166.142;\n helo=lists1.osuosl.org; envelope-from=intel-wired-lan-bounces@osuosl.org;\n receiver=<UNKNOWN> ", "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 smtp1.osuosl.org 41AD684AA8", "OpenDKIM Filter v2.11.0 smtp3.osuosl.org 58B6961284" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=osuosl.org;\n\ts=default; t=1778278153;\n\tbh=weL5sjMxZ35x6Xc1qHGVeIc8dFhSHKAgb2vFrKEE4tw=;\n\th=From:To:CC:Date:In-Reply-To:References:Subject:List-Id:\n\t List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe:\n\t From;\n\tb=sjyRiodVLN49vVCQEYo+mYSvdOxz/hxuUfXTo+7PtHYwlQxlMLcyoKiFRZwvwNzLw\n\t fjRzoy/QYLI/1CwmcwSVz64/lE7+F+BZjHv2AxslmBGqig4oRZdrDmAJiiV/ZYUkT5\n\t baATGvBZkSMHGvJP+AppsvhPpuNiKHOG9qd2azZ7TsNj01Eer/774Mof7C58CibBZj\n\t lwf54wCFX3Ww0wB5sKmTK8I15jhMA8dV2+BfCDgEfIBpeXVMNTY2Oy63673xKyldaP\n\t n2gYmOm/xX1CUuxuB36J4hjqocPflcRD3oSHv5oeqCe4IP9G2lTakZtThm7vr5WZ61\n\t R1JMrDYtGJLrg==", "Received-SPF": "Pass (mailfrom) identity=mailfrom; client-ip=67.231.148.174;\n helo=mx0b-0016f401.pphosted.com;\n envelope-from=prvs=65883a0750=rkannoth@marvell.com; receiver=<UNKNOWN>", "DMARC-Filter": "OpenDMARC Filter v1.4.2 smtp3.osuosl.org 58B6961284", "From": "Ratheesh Kannoth <rkannoth@marvell.com>", "To": "<intel-wired-lan@lists.osuosl.org>, <linux-kernel@vger.kernel.org>,\n <linux-rdma@vger.kernel.org>, <netdev@vger.kernel.org>,\n <oss-drivers@corigine.com>", "CC": "<akiyano@amazon.com>, <andrew+netdev@lunn.ch>,\n <anthony.l.nguyen@intel.com>, <arkadiusz.kubalewski@intel.com>,\n <brett.creeley@amd.com>, <darinzon@amazon.com>, <davem@davemloft.net>,\n <donald.hunter@gmail.com>, <edumazet@google.com>, <horms@kernel.org>,\n <idosch@nvidia.com>, <ivecera@redhat.com>, <jiri@resnulli.us>,\n <kuba@kernel.org>, <leon@kernel.org>, <mbloch@nvidia.com>,\n <michael.chan@broadcom.com>, <pabeni@redhat.com>,\n <pavan.chebbi@broadcom.com>, <petrm@nvidia.com>,\n <Prathosh.Satish@microchip.com>, <przemyslaw.kitszel@intel.com>,\n <saeedm@nvidia.com>, <sgoutham@marvell.com>, <tariqt@nvidia.com>,\n <vadim.fedorenko@linux.dev>, Ratheesh Kannoth <rkannoth@marvell.com>", "Date": "Fri, 8 May 2026 09:19:10 +0530", "Message-ID": "<20260508034912.4082520-8-rkannoth@marvell.com>", "X-Mailer": "git-send-email 2.43.0", "In-Reply-To": "<20260508034912.4082520-1-rkannoth@marvell.com>", "References": "<20260508034912.4082520-1-rkannoth@marvell.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Content-Type": "text/plain", "X-Proofpoint-ORIG-GUID": "8Yk9S97M0pn7QUdGvmk4d1C1Wr43OgZT", "X-Proofpoint-Spam-Details-Enc": "AW1haW4tMjYwNTA4MDAzNCBTYWx0ZWRfXxiHTsRXr4yUM\n rLe1ToH/6H5/6az8O5M1Z9Nebs0RO34580+gUsYim62UFYLEeteWGc41RcChcgsIIvUeyg3KjZx\n MKBzD5IUm5LljcLchpkGi08WkWNUrXe1fTfubTo2gZ2zJKyLY7PzZQqGnUChauyxTJ/sgQK0vsK\n kMeTLLecFkziKcX4LWrvgvdaKmP0AG052ADEPAT5f7tL4rMizr2HfDD5jBEhfOWibAePObxluKh\n CqnIfvN4Z0wqUjUYrqZVVpEcvtt5S9ba9amcCgj96/YqZDvX8aCz8jgRp7pqTRt/wYcDBHadmke\n XPzWXdaPBnSLZOFx6NirfIWbiYON7uVVeLwf2mZ57GmZ2HIsMTyInBvP5jyFgqpRiThyQ3mYjw0\n /490COXT/lK9tRr5V2MsaSu3lmMmRSN8hnLsK+FuLklRMU7PzBicLgkPL7DK0UC5sNID2Z8DCZR\n +5IDYp2vP4dG/3bf10A==", "X-Proofpoint-GUID": "8Yk9S97M0pn7QUdGvmk4d1C1Wr43OgZT", "X-Authority-Analysis": "v=2.4 cv=WMBPmHsR c=1 sm=1 tr=0 ts=69fd5d99 cx=c_pps\n a=gIfcoYsirJbf48DBMSPrZA==:117 a=gIfcoYsirJbf48DBMSPrZA==:17\n a=NGcC8JguVDcA:10 a=VkNPw1HP01LnGYTKEx00:22 a=l0iWHRpgs5sLHlkKQ1IR:22\n a=EAYMVhzMl8SCOHhVQcBL:22 a=M5GUcnROAAAA:8 a=fPRu-RNDXv4BUTAVjlcA:9\n a=OBjm3rFKGHvpk9ecZwUJ:22", "X-Proofpoint-Virus-Version": "vendor=baseguard\n engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49\n definitions=2026-05-07_02,2026-05-06_01,2025-10-01_01", "X-Mailman-Approved-At": "Fri, 08 May 2026 22:09:04 +0000", "X-Mailman-Original-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=marvell.com; h=\n cc:content-transfer-encoding:content-type:date:from:in-reply-to\n :message-id:mime-version:references:subject:to; s=pfpt0220; bh=w\n eL5sjMxZ35x6Xc1qHGVeIc8dFhSHKAgb2vFrKEE4tw=; b=Kgj1wW5uV6VOe771u\n uRQ+AdIWUBCDQSONo9drqFMHoaVBpKQK5nREfPVdpetU+19hiC7md6qh+04RhN51\n 3na/aqbaUm2ftI0MkeMAd1H18pYpX3HV6R3rM3ThJulNq0QOkNBocZP6n88VlA9m\n ry0O2PnY4lR18xMRm6ypCvOmtS83X5OC7Fs55OcBH93WuJVP+gUUEyRiAivA0AUH\n deKnMCoIxBTTivzWTr2x6K4n3QzITLAgzasukTjHZZbJcuVjY+Q3z32yyG+ftytQ\n pLpPVysei+rrSiBvXbFRNKTMiP27vYzHpGuZAdNiiZwFW6gdboQU+40PvC8YcVUP\n Szo+w==", "X-Mailman-Original-Authentication-Results": [ "smtp3.osuosl.org;\n dmarc=pass (p=none dis=none)\n header.from=marvell.com", "smtp3.osuosl.org;\n dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com\n header.a=rsa-sha256 header.s=pfpt0220 header.b=Kgj1wW5u" ], "Subject": "[Intel-wired-lan] [PATCH v12 net-next 7/9] octeontx2-af: npc:\n Support for custom KPU profile from filesystem", "X-BeenThere": "intel-wired-lan@osuosl.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n <intel-wired-lan.osuosl.org>", "List-Unsubscribe": "<https://lists.osuosl.org/mailman/options/intel-wired-lan>,\n <mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>", "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>", "List-Post": "<mailto:intel-wired-lan@osuosl.org>", "List-Help": "<mailto:intel-wired-lan-request@osuosl.org?subject=help>", "List-Subscribe": "<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>,\n <mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>", "Errors-To": "intel-wired-lan-bounces@osuosl.org", "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>" }, "content": "Flashing updated firmware on deployed devices is cumbersome. Provide a\nmechanism to load a custom KPU (Key Parse Unit) profile directly from\nthe filesystem at module load time.\n\nWhen the rvu_af module is loaded with the kpu_profile parameter, the\nspecified profile is read from /lib/firmware/kpu and programmed into\nthe KPU registers. Add npc_kpu_profile_cam2 for the extended cam format\nused by filesystem-loaded profiles and support ptype/ptype_mask in\nnpc_config_kpucam when profile->from_fs is set.\n\nUsage:\n 1. Copy the KPU profile file to /lib/firmware/kpu.\n 2. Build OCTEONTX2_AF as a module.\n 3. Load: insmod rvu_af.ko kpu_profile=<profile_name>\n\nSigned-off-by: Ratheesh Kannoth <rkannoth@marvell.com>\n---\n .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 57 ++-\n .../net/ethernet/marvell/octeontx2/af/npc.h | 17 +\n .../net/ethernet/marvell/octeontx2/af/rvu.h | 12 +-\n .../ethernet/marvell/octeontx2/af/rvu_npc.c | 456 ++++++++++++++----\n .../ethernet/marvell/octeontx2/af/rvu_npc.h | 17 +\n .../ethernet/marvell/octeontx2/af/rvu_reg.h | 1 +\n 6 files changed, 449 insertions(+), 111 deletions(-)", "diff": "diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c\nindex 6f8f42234b06..67dfbe5ca903 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c\n@@ -521,13 +521,17 @@ npc_program_single_kpm_profile(struct rvu *rvu, int blkaddr,\n \t\t\t int kpm, int start_entry,\n \t\t\t const struct npc_kpu_profile *profile)\n {\n+\tint num_cam_entries, num_action_entries;\n \tint entry, num_entries, max_entries;\n \tu64 idx;\n \n-\tif (profile->cam_entries != profile->action_entries) {\n+\tnum_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile);\n+\tnum_action_entries = npc_get_num_kpu_action_entries(rvu, profile);\n+\n+\tif (num_cam_entries != num_action_entries) {\n \t\tdev_err(rvu->dev,\n \t\t\t\"kpm%d: CAM and action entries [%d != %d] not equal\\n\",\n-\t\t\tkpm, profile->cam_entries, profile->action_entries);\n+\t\t\tkpm, num_cam_entries, num_action_entries);\n \n \t\tWARN(1, \"Fatal error\\n\");\n \t\treturn;\n@@ -536,16 +540,18 @@ npc_program_single_kpm_profile(struct rvu *rvu, int blkaddr,\n \tmax_entries = rvu->hw->npc_kpu_entries / 2;\n \tentry = start_entry;\n \t/* Program CAM match entries for previous kpm extracted data */\n-\tnum_entries = min_t(int, profile->cam_entries, max_entries);\n+\tnum_entries = min_t(int, num_cam_entries, max_entries);\n \tfor (idx = 0; entry < num_entries + start_entry; entry++, idx++)\n-\t\tnpc_config_kpmcam(rvu, blkaddr, &profile->cam[idx],\n+\t\tnpc_config_kpmcam(rvu, blkaddr,\n+\t\t\t\t npc_get_kpu_cam_nth_entry(rvu, profile, idx),\n \t\t\t\t kpm, entry);\n \n \tentry = start_entry;\n \t/* Program this kpm's actions */\n-\tnum_entries = min_t(int, profile->action_entries, max_entries);\n+\tnum_entries = min_t(int, num_action_entries, max_entries);\n \tfor (idx = 0; entry < num_entries + start_entry; entry++, idx++)\n-\t\tnpc_config_kpmaction(rvu, blkaddr, &profile->action[idx],\n+\t\tnpc_config_kpmaction(rvu, blkaddr,\n+\t\t\t\t npc_get_kpu_action_nth_entry(rvu, profile, idx),\n \t\t\t\t kpm, entry, false);\n }\n \n@@ -611,20 +617,23 @@ npc_enable_kpm_entry(struct rvu *rvu, int blkaddr, int kpm, int num_entries)\n static void npc_program_kpm_profile(struct rvu *rvu, int blkaddr, int num_kpms)\n {\n \tconst struct npc_kpu_profile *profile1, *profile2;\n+\tint pfl1_num_cam_entries, pfl2_num_cam_entries;\n \tint idx, total_cam_entries;\n \n \tfor (idx = 0; idx < num_kpms; idx++) {\n \t\tprofile1 = &rvu->kpu.kpu[idx];\n+\t\tpfl1_num_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile1);\n \t\tnpc_program_single_kpm_profile(rvu, blkaddr, idx, 0, profile1);\n \t\tprofile2 = &rvu->kpu.kpu[idx + KPU_OFFSET];\n+\t\tpfl2_num_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile2);\n+\n \t\tnpc_program_single_kpm_profile(rvu, blkaddr, idx,\n-\t\t\t\t\t profile1->cam_entries,\n+\t\t\t\t\t pfl1_num_cam_entries,\n \t\t\t\t\t profile2);\n-\t\ttotal_cam_entries = profile1->cam_entries +\n-\t\t\tprofile2->cam_entries;\n+\t\ttotal_cam_entries = pfl1_num_cam_entries + pfl2_num_cam_entries;\n \t\tnpc_enable_kpm_entry(rvu, blkaddr, idx, total_cam_entries);\n \t\trvu_write64(rvu, blkaddr, NPC_AF_KPMX_PASS2_OFFSET(idx),\n-\t\t\t profile1->cam_entries);\n+\t\t\t pfl1_num_cam_entries);\n \t\t/* Enable the KPUs associated with this KPM */\n \t\trvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx), 0x01);\n \t\trvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx + KPU_OFFSET),\n@@ -634,6 +643,7 @@ static void npc_program_kpm_profile(struct rvu *rvu, int blkaddr, int num_kpms)\n \n void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr)\n {\n+\tstruct npc_kpu_profile_action *act;\n \tstruct rvu_hwinfo *hw = rvu->hw;\n \tint num_pkinds, idx;\n \n@@ -665,9 +675,15 @@ void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr)\n \tnum_pkinds = rvu->kpu.pkinds;\n \tnum_pkinds = min_t(int, hw->npc_pkinds, num_pkinds);\n \n-\tfor (idx = 0; idx < num_pkinds; idx++)\n-\t\tnpc_config_kpmaction(rvu, blkaddr, &rvu->kpu.ikpu[idx],\n+\t/* Cn20k does not support Custom profile from filesystem */\n+\tfor (idx = 0; idx < num_pkinds; idx++) {\n+\t\tact = npc_get_ikpu_nth_entry(rvu, idx);\n+\t\tif (!act)\n+\t\t\tcontinue;\n+\n+\t\tnpc_config_kpmaction(rvu, blkaddr, act,\n \t\t\t\t 0, idx, true);\n+\t}\n \n \t/* Program KPM CAM and Action profiles */\n \tnpc_program_kpm_profile(rvu, blkaddr, hw->npc_kpms);\n@@ -679,7 +695,7 @@ struct npc_priv_t *npc_priv_get(void)\n }\n \n static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,\n-\t\t\t\tstruct npc_mcam_kex_extr *mkex_extr,\n+\t\t\t\tconst struct npc_mcam_kex_extr *mkex_extr,\n \t\t\t\tu8 intf)\n {\n \tu8 num_extr = rvu->hw->npc_kex_extr;\n@@ -708,7 +724,7 @@ static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,\n }\n \n static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,\n-\t\t\t\tstruct npc_mcam_kex_extr *mkex_extr,\n+\t\t\t\tconst struct npc_mcam_kex_extr *mkex_extr,\n \t\t\t\tu8 intf)\n {\n \tu8 num_extr = rvu->hw->npc_kex_extr;\n@@ -737,7 +753,7 @@ static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,\n }\n \n static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,\n-\t\t\t\t struct npc_mcam_kex_extr *mkex_extr)\n+\t\t\t\t const struct npc_mcam_kex_extr *mkex_extr)\n {\n \tstruct rvu_hwinfo *hw = rvu->hw;\n \tu8 intf;\n@@ -1630,8 +1646,8 @@ npc_cn20k_update_action_entries_n_flags(struct rvu *rvu,\n int npc_cn20k_apply_custom_kpu(struct rvu *rvu,\n \t\t\t struct npc_kpu_profile_adapter *profile)\n {\n+\tconst struct npc_cn20k_kpu_profile_fwdata *fw = rvu->kpu_fwdata;\n \tsize_t hdr_sz = sizeof(struct npc_cn20k_kpu_profile_fwdata);\n-\tstruct npc_cn20k_kpu_profile_fwdata *fw = rvu->kpu_fwdata;\n \tstruct npc_kpu_profile_action *action;\n \tstruct npc_kpu_profile_cam *cam;\n \tstruct npc_kpu_fwdata *fw_kpu;\n@@ -1676,8 +1692,15 @@ int npc_cn20k_apply_custom_kpu(struct rvu *rvu,\n \t}\n \n \t/* Verify if profile fits the HW */\n+\tif (fw->kpus > rvu->hw->npc_kpus) {\n+\t\tdev_warn(rvu->dev, \"Not enough KPUs: %d > %d\\n\", fw->kpus,\n+\t\t\t rvu->hw->npc_kpus);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Check if there is enough memory */\n \tif (fw->kpus > profile->kpus) {\n-\t\tdev_warn(rvu->dev, \"Not enough KPUs: %d > %ld\\n\", fw->kpus,\n+\t\tdev_warn(rvu->dev, \"Not enough KPUs: %d > %zu\\n\", fw->kpus,\n \t\t\t profile->kpus);\n \t\treturn -EINVAL;\n \t}\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/npc.h\nindex cefc5d70f3e4..c8c0cb68535c 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h\n+++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h\n@@ -265,6 +265,19 @@ struct npc_kpu_profile_cam {\n \tu16 dp2_mask;\n } __packed;\n \n+struct npc_kpu_profile_cam2 {\n+\tu8 state;\n+\tu8 state_mask;\n+\tu16 dp0;\n+\tu16 dp0_mask;\n+\tu16 dp1;\n+\tu16 dp1_mask;\n+\tu16 dp2;\n+\tu16 dp2_mask;\n+\tu8 ptype;\n+\tu8 ptype_mask;\n+} __packed;\n+\n struct npc_kpu_profile_action {\n \tu8 errlev;\n \tu8 errcode;\n@@ -290,6 +303,10 @@ struct npc_kpu_profile {\n \tint action_entries;\n \tstruct npc_kpu_profile_cam *cam;\n \tstruct npc_kpu_profile_action *action;\n+\tint cam_entries2;\n+\tint action_entries2;\n+\tstruct npc_kpu_profile_action *action2;\n+\tstruct npc_kpu_profile_cam2 *cam2;\n };\n \n /* NPC KPU register formats */\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h\nindex a466181cf908..2a2f2287e0c0 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h\n+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h\n@@ -553,17 +553,19 @@ struct npc_kpu_profile_adapter {\n \tconst char\t\t\t*name;\n \tu64\t\t\t\tversion;\n \tconst struct npc_lt_def_cfg\t*lt_def;\n-\tconst struct npc_kpu_profile_action\t*ikpu; /* array[pkinds] */\n-\tconst struct npc_kpu_profile\t*kpu; /* array[kpus] */\n+\tstruct npc_kpu_profile_action\t*ikpu; /* array[pkinds] */\n+\tstruct npc_kpu_profile_action\t*ikpu2; /* array[pkinds] */\n+\tstruct npc_kpu_profile\t*kpu; /* array[kpus] */\n \tunion npc_mcam_key_prfl {\n-\t\tstruct npc_mcam_kex\t\t*mkex;\n+\t\tconst struct npc_mcam_kex\t\t*mkex;\n \t\t\t\t\t/* used for cn9k and cn10k */\n-\t\tstruct npc_mcam_kex_extr\t*mkex_extr; /* used for cn20k */\n+\t\tconst struct npc_mcam_kex_extr\t*mkex_extr; /* used for cn20k */\n \t} mcam_kex_prfl;\n \tstruct npc_mcam_kex_hash\t*mkex_hash;\n \tbool\t\t\t\tcustom;\n \tsize_t\t\t\t\tpkinds;\n \tsize_t\t\t\t\tkpus;\n+\tbool\t\t\t\tfrom_fs;\n };\n \n #define RVU_SWITCH_LBK_CHAN\t63\n@@ -634,7 +636,7 @@ struct rvu {\n \n \t/* Firmware data */\n \tstruct rvu_fwdata\t*fwdata;\n-\tvoid\t\t\t*kpu_fwdata;\n+\tconst void\t\t*kpu_fwdata;\n \tsize_t\t\t\tkpu_fwdata_sz;\n \tvoid __iomem\t\t*kpu_prfl_addr;\n \ndiff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c\nindex 5fa9e1c7ae9f..a0f97e683145 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c\n@@ -1495,7 +1495,8 @@ void rvu_npc_free_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf)\n }\n \n static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,\n-\t\t\t\tstruct npc_mcam_kex *mkex, u8 intf)\n+\t\t\t\tconst struct npc_mcam_kex *mkex,\n+\t\t\t\tu8 intf)\n {\n \tint lid, lt, ld, fl;\n \n@@ -1524,7 +1525,8 @@ static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,\n }\n \n static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,\n-\t\t\t\tstruct npc_mcam_kex *mkex, u8 intf)\n+\t\t\t\tconst struct npc_mcam_kex *mkex,\n+\t\t\t\tu8 intf)\n {\n \tint lid, lt, ld, fl;\n \n@@ -1553,7 +1555,7 @@ static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,\n }\n \n static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,\n-\t\t\t\t struct npc_mcam_kex *mkex)\n+\t\t\t\t const struct npc_mcam_kex *mkex)\n {\n \tstruct rvu_hwinfo *hw = rvu->hw;\n \tu8 intf;\n@@ -1693,8 +1695,12 @@ static void npc_config_kpucam(struct rvu *rvu, int blkaddr,\n \t\t\t const struct npc_kpu_profile_cam *kpucam,\n \t\t\t int kpu, int entry)\n {\n+\tconst struct npc_kpu_profile_cam2 *kpucam2 = (void *)kpucam;\n+\tstruct npc_kpu_profile_adapter *profile = &rvu->kpu;\n \tstruct npc_kpu_cam cam0 = {0};\n \tstruct npc_kpu_cam cam1 = {0};\n+\tu64 *val = (u64 *)&cam1;\n+\tu64 *mask = (u64 *)&cam0;\n \n \tcam1.state = kpucam->state & kpucam->state_mask;\n \tcam1.dp0_data = kpucam->dp0 & kpucam->dp0_mask;\n@@ -1706,6 +1712,14 @@ static void npc_config_kpucam(struct rvu *rvu, int blkaddr,\n \tcam0.dp1_data = ~kpucam->dp1 & kpucam->dp1_mask;\n \tcam0.dp2_data = ~kpucam->dp2 & kpucam->dp2_mask;\n \n+\tif (profile->from_fs) {\n+\t\tu8 ptype = kpucam2->ptype;\n+\t\tu8 pmask = kpucam2->ptype_mask;\n+\n+\t\t*val |= FIELD_PREP(GENMASK_ULL(57, 56), ptype & pmask);\n+\t\t*mask |= FIELD_PREP(GENMASK_ULL(57, 56), ~ptype & pmask);\n+\t}\n+\n \trvu_write64(rvu, blkaddr,\n \t\t NPC_AF_KPUX_ENTRYX_CAMX(kpu, entry, 0), *(u64 *)&cam0);\n \trvu_write64(rvu, blkaddr,\n@@ -1717,34 +1731,104 @@ u64 npc_enable_mask(int count)\n \treturn (((count) < 64) ? ~(BIT_ULL(count) - 1) : (0x00ULL));\n }\n \n+struct npc_kpu_profile_action *\n+npc_get_ikpu_nth_entry(struct rvu *rvu, int n)\n+{\n+\tstruct npc_kpu_profile_adapter *profile = &rvu->kpu;\n+\n+\tif (profile->from_fs)\n+\t\treturn &profile->ikpu2[n];\n+\n+\treturn &profile->ikpu[n];\n+}\n+\n+int\n+npc_get_num_kpu_cam_entries(struct rvu *rvu,\n+\t\t\t const struct npc_kpu_profile *kpu_pfl)\n+{\n+\tstruct npc_kpu_profile_adapter *profile = &rvu->kpu;\n+\n+\tif (profile->from_fs)\n+\t\treturn kpu_pfl->cam_entries2;\n+\n+\treturn kpu_pfl->cam_entries;\n+}\n+\n+struct npc_kpu_profile_cam *\n+npc_get_kpu_cam_nth_entry(struct rvu *rvu,\n+\t\t\t const struct npc_kpu_profile *kpu_pfl, int n)\n+{\n+\tstruct npc_kpu_profile_adapter *profile = &rvu->kpu;\n+\n+\tif (profile->from_fs)\n+\t\treturn (void *)&kpu_pfl->cam2[n];\n+\n+\treturn (void *)&kpu_pfl->cam[n];\n+}\n+\n+int\n+npc_get_num_kpu_action_entries(struct rvu *rvu,\n+\t\t\t const struct npc_kpu_profile *kpu_pfl)\n+{\n+\tstruct npc_kpu_profile_adapter *profile = &rvu->kpu;\n+\n+\tif (profile->from_fs)\n+\t\treturn kpu_pfl->action_entries2;\n+\n+\treturn kpu_pfl->action_entries;\n+}\n+\n+struct npc_kpu_profile_action *\n+npc_get_kpu_action_nth_entry(struct rvu *rvu,\n+\t\t\t const struct npc_kpu_profile *kpu_pfl,\n+\t\t\t int n)\n+{\n+\tstruct npc_kpu_profile_adapter *profile = &rvu->kpu;\n+\n+\tif (profile->from_fs)\n+\t\treturn (void *)&kpu_pfl->action2[n];\n+\n+\treturn (void *)&kpu_pfl->action[n];\n+}\n+\n static void npc_program_kpu_profile(struct rvu *rvu, int blkaddr, int kpu,\n \t\t\t\t const struct npc_kpu_profile *profile)\n {\n+\tint num_cam_entries, num_action_entries;\n \tint entry, num_entries, max_entries;\n \tu64 entry_mask;\n \n-\tif (profile->cam_entries != profile->action_entries) {\n+\tnum_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile);\n+\tnum_action_entries = npc_get_num_kpu_action_entries(rvu, profile);\n+\n+\tif (num_cam_entries != num_action_entries) {\n \t\tdev_err(rvu->dev,\n \t\t\t\"KPU%d: CAM and action entries [%d != %d] not equal\\n\",\n-\t\t\tkpu, profile->cam_entries, profile->action_entries);\n+\t\t\tkpu, num_cam_entries, num_action_entries);\n \t}\n \n \tmax_entries = rvu->hw->npc_kpu_entries;\n \n+\tWARN(num_cam_entries > max_entries,\n+\t \"KPU%u: err: hw max entries=%u, input entries=%u\\n\",\n+\t kpu, rvu->hw->npc_kpu_entries, num_cam_entries);\n+\n \t/* Program CAM match entries for previous KPU extracted data */\n-\tnum_entries = min_t(int, profile->cam_entries, max_entries);\n+\tnum_entries = min_t(int, num_cam_entries, max_entries);\n \tfor (entry = 0; entry < num_entries; entry++)\n \t\tnpc_config_kpucam(rvu, blkaddr,\n-\t\t\t\t &profile->cam[entry], kpu, entry);\n+\t\t\t\t (void *)npc_get_kpu_cam_nth_entry(rvu, profile, entry),\n+\t\t\t\t kpu, entry);\n \n \t/* Program this KPU's actions */\n-\tnum_entries = min_t(int, profile->action_entries, max_entries);\n+\tnum_entries = min_t(int, num_action_entries, max_entries);\n \tfor (entry = 0; entry < num_entries; entry++)\n-\t\tnpc_config_kpuaction(rvu, blkaddr, &profile->action[entry],\n+\t\tnpc_config_kpuaction(rvu, blkaddr,\n+\t\t\t\t (void *)npc_get_kpu_action_nth_entry(rvu, profile, entry),\n \t\t\t\t kpu, entry, false);\n \n \t/* Enable all programmed entries */\n-\tnum_entries = min_t(int, profile->action_entries, profile->cam_entries);\n+\tnum_entries = min_t(int, num_action_entries, num_cam_entries);\n \tentry_mask = npc_enable_mask(num_entries);\n \t/* Disable first KPU_MAX_CST_ENT entries for built-in profile */\n \tif (!rvu->kpu.custom)\n@@ -1788,26 +1872,168 @@ static void npc_prepare_default_kpu(struct rvu *rvu,\n \tnpc_cn20k_update_action_entries_n_flags(rvu, profile);\n }\n \n-static int npc_apply_custom_kpu(struct rvu *rvu,\n-\t\t\t\tstruct npc_kpu_profile_adapter *profile)\n+static int npc_alloc_kpu_cam2_n_action2(struct rvu *rvu, int kpu_num,\n+\t\t\t\t\tint num_entries)\n+{\n+\tstruct npc_kpu_profile_adapter *adapter = &rvu->kpu;\n+\tstruct npc_kpu_profile *kpu;\n+\n+\tkpu = &adapter->kpu[kpu_num];\n+\n+\tkpu->cam2 = devm_kcalloc(rvu->dev, num_entries,\n+\t\t\t\t sizeof(*kpu->cam2), GFP_KERNEL);\n+\tif (!kpu->cam2)\n+\t\treturn -ENOMEM;\n+\n+\tkpu->action2 = devm_kcalloc(rvu->dev, num_entries,\n+\t\t\t\t sizeof(*kpu->action2), GFP_KERNEL);\n+\tif (!kpu->action2)\n+\t\treturn -ENOMEM;\n+\n+\treturn 0;\n+}\n+\n+static int npc_apply_custom_kpu_from_fw(struct rvu *rvu,\n+\t\t\t\t\tstruct npc_kpu_profile_adapter *profile)\n {\n \tsize_t hdr_sz = sizeof(struct npc_kpu_profile_fwdata), offset = 0;\n+\tconst struct npc_kpu_profile_fwdata *fw;\n \tstruct npc_kpu_profile_action *action;\n-\tstruct npc_kpu_profile_fwdata *fw;\n \tstruct npc_kpu_profile_cam *cam;\n \tstruct npc_kpu_fwdata *fw_kpu;\n-\tint entries;\n-\tu16 kpu, entry;\n+\tint entries, entry, kpu;\n \n-\tif (is_cn20k(rvu->pdev))\n-\t\treturn npc_cn20k_apply_custom_kpu(rvu, profile);\n+\tfw = rvu->kpu_fwdata;\n+\n+\tfor (kpu = 0; kpu < fw->kpus; kpu++) {\n+\t\tif (rvu->kpu_fwdata_sz < hdr_sz + offset) {\n+\t\t\tdev_warn(rvu->dev,\n+\t\t\t\t \"Profile size mismatch on KPU%i parsing\\n\",\n+\t\t\t\t kpu + 1);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tfw_kpu = (struct npc_kpu_fwdata *)(fw->data + offset);\n+\t\tif (fw_kpu->entries > KPU_MAX_CST_ENT)\n+\t\t\tdev_warn(rvu->dev,\n+\t\t\t\t \"Too many custom entries on KPU%d: %d > %d\\n\",\n+\t\t\t\t kpu, fw_kpu->entries, KPU_MAX_CST_ENT);\n+\t\tentries = min_t(int, fw_kpu->entries, KPU_MAX_CST_ENT);\n+\t\tcam = (struct npc_kpu_profile_cam *)fw_kpu->data;\n+\t\toffset += sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam);\n+\t\taction = (struct npc_kpu_profile_action *)(fw->data + offset);\n+\t\toffset += fw_kpu->entries * sizeof(*action);\n+\t\tif (rvu->kpu_fwdata_sz < hdr_sz + offset) {\n+\t\t\tdev_warn(rvu->dev,\n+\t\t\t\t \"Profile size mismatch on KPU%i parsing.\\n\",\n+\t\t\t\t kpu + 1);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tfor (entry = 0; entry < entries; entry++) {\n+\t\t\tprofile->kpu[kpu].cam[entry] = cam[entry];\n+\t\t\tprofile->kpu[kpu].action[entry] = action[entry];\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int npc_apply_custom_kpu_from_fs(struct rvu *rvu,\n+\t\t\t\t\tstruct npc_kpu_profile_adapter *profile)\n+{\n+\tsize_t hdr_sz = sizeof(struct npc_kpu_profile_fwdata), offset = 0;\n+\tconst struct npc_kpu_profile_fwdata *fw;\n+\tstruct npc_kpu_profile_action *action;\n+\tstruct npc_kpu_profile_cam2 *cam2;\n+\tstruct npc_kpu_fwdata *fw_kpu;\n+\tint entries, ret, entry, kpu;\n \n \tfw = rvu->kpu_fwdata;\n \n+\t/* Binary blob contains ikpu actions entries at start of data[0] */\n+\tprofile->ikpu2 = devm_kcalloc(rvu->dev, 1,\n+\t\t\t\t sizeof(ikpu_action_entries),\n+\t\t\t\t GFP_KERNEL);\n+\tif (!profile->ikpu2)\n+\t\treturn -ENOMEM;\n+\n+\taction = (struct npc_kpu_profile_action *)(fw->data + offset);\n+\n+\tif (rvu->kpu_fwdata_sz < hdr_sz + sizeof(ikpu_action_entries))\n+\t\treturn -EINVAL;\n+\n+\t/* The firmware layout does dependent on the internal size of\n+\t * ikpu_action_entries.\n+\t */\n+\tmemcpy((void *)profile->ikpu2, action, sizeof(ikpu_action_entries));\n+\toffset += sizeof(ikpu_action_entries);\n+\n+\tfor (kpu = 0; kpu < fw->kpus; kpu++) {\n+\t\tif (rvu->kpu_fwdata_sz < hdr_sz + offset + sizeof(*fw_kpu)) {\n+\t\t\tdev_warn(rvu->dev,\n+\t\t\t\t \"profile size mismatch on kpu%i parsing\\n\",\n+\t\t\t\t kpu + 1);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tfw_kpu = (struct npc_kpu_fwdata *)(fw->data + offset);\n+\t\tif (fw_kpu->entries <= 0) {\n+\t\t\tdev_warn(rvu->dev,\n+\t\t\t\t \"Invalid kpu entries on KPU%d\\n\", kpu);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tentries = min_t(int, fw_kpu->entries, rvu->hw->npc_kpu_entries);\n+\t\tdev_info(rvu->dev,\n+\t\t\t \"Loading %u entries on KPU%d\\n\", entries, kpu);\n+\n+\t\tcam2 = (struct npc_kpu_profile_cam2 *)fw_kpu->data;\n+\t\toffset += sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam2);\n+\t\taction = (struct npc_kpu_profile_action *)(fw->data + offset);\n+\t\toffset += fw_kpu->entries * sizeof(*action);\n+\t\tif (rvu->kpu_fwdata_sz < hdr_sz + offset) {\n+\t\t\tdev_warn(rvu->dev,\n+\t\t\t\t \"profile size mismatch on kpu%i parsing.\\n\",\n+\t\t\t\t kpu + 1);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tprofile->kpu[kpu].cam_entries2 = entries;\n+\t\tprofile->kpu[kpu].action_entries2 = entries;\n+\t\tret = npc_alloc_kpu_cam2_n_action2(rvu, kpu, entries);\n+\t\tif (ret) {\n+\t\t\tdev_warn(rvu->dev,\n+\t\t\t\t \"profile entry allocation failed for kpu=%d for %d entries\\n\",\n+\t\t\t\t kpu, entries);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tfor (entry = 0; entry < entries; entry++) {\n+\t\t\tprofile->kpu[kpu].cam2[entry] = cam2[entry];\n+\t\t\tprofile->kpu[kpu].action2[entry] = action[entry];\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int npc_apply_custom_kpu(struct rvu *rvu,\n+\t\t\t\tstruct npc_kpu_profile_adapter *profile,\n+\t\t\t\tbool from_fs, int *fw_kpus)\n+{\n+\tsize_t hdr_sz = sizeof(struct npc_kpu_profile_fwdata);\n+\tconst struct npc_kpu_profile_fwdata *fw;\n+\tstruct npc_kpu_profile_fwdata *sfw;\n+\n+\tif (is_cn20k(rvu->pdev))\n+\t\treturn npc_cn20k_apply_custom_kpu(rvu, profile);\n+\n \tif (rvu->kpu_fwdata_sz < hdr_sz) {\n \t\tdev_warn(rvu->dev, \"Invalid KPU profile size\\n\");\n \t\treturn -EINVAL;\n \t}\n+\n+\tfw = rvu->kpu_fwdata;\n \tif (le64_to_cpu(fw->signature) != KPU_SIGN) {\n \t\tdev_warn(rvu->dev, \"Invalid KPU profile signature %llx\\n\",\n \t\t\t fw->signature);\n@@ -1835,42 +2061,38 @@ static int npc_apply_custom_kpu(struct rvu *rvu,\n \t\treturn -EINVAL;\n \t}\n \t/* Verify if profile fits the HW */\n+\tif (fw->kpus > rvu->hw->npc_kpus) {\n+\t\tdev_warn(rvu->dev, \"Not enough KPUs: %d > %d\\n\", fw->kpus,\n+\t\t\t rvu->hw->npc_kpus);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Check if there is enough memory for fw loading.\n+\t * Check if there is enough entries for profile->kpu[] to\n+\t * set cam_entries2 and action_entries2\n+\t */\n \tif (fw->kpus > profile->kpus) {\n-\t\tdev_warn(rvu->dev, \"Not enough KPUs: %d > %ld\\n\", fw->kpus,\n+\t\tdev_warn(rvu->dev, \"Not enough KPUs: %d > %zu\\n\", fw->kpus,\n \t\t\t profile->kpus);\n \t\treturn -EINVAL;\n \t}\n \n+\t*fw_kpus = fw->kpus;\n+\n+\tsfw = devm_kcalloc(rvu->dev, 1, sizeof(*sfw), GFP_KERNEL);\n+\tif (!sfw)\n+\t\treturn -ENOMEM;\n+\n+\tmemcpy(sfw, fw, sizeof(*sfw));\n+\n \tprofile->custom = 1;\n-\tprofile->name = fw->name;\n+\tprofile->name = sfw->name;\n \tprofile->version = le64_to_cpu(fw->version);\n-\tprofile->mcam_kex_prfl.mkex = &fw->mkex;\n-\tprofile->lt_def = &fw->lt_def;\n+\tprofile->mcam_kex_prfl.mkex = &sfw->mkex;\n+\tprofile->lt_def = &sfw->lt_def;\n \n-\tfor (kpu = 0; kpu < fw->kpus; kpu++) {\n-\t\tfw_kpu = (struct npc_kpu_fwdata *)(fw->data + offset);\n-\t\tif (fw_kpu->entries > KPU_MAX_CST_ENT)\n-\t\t\tdev_warn(rvu->dev,\n-\t\t\t\t \"Too many custom entries on KPU%d: %d > %d\\n\",\n-\t\t\t\t kpu, fw_kpu->entries, KPU_MAX_CST_ENT);\n-\t\tentries = min(fw_kpu->entries, KPU_MAX_CST_ENT);\n-\t\tcam = (struct npc_kpu_profile_cam *)fw_kpu->data;\n-\t\toffset += sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam);\n-\t\taction = (struct npc_kpu_profile_action *)(fw->data + offset);\n-\t\toffset += fw_kpu->entries * sizeof(*action);\n-\t\tif (rvu->kpu_fwdata_sz < hdr_sz + offset) {\n-\t\t\tdev_warn(rvu->dev,\n-\t\t\t\t \"Profile size mismatch on KPU%i parsing.\\n\",\n-\t\t\t\t kpu + 1);\n-\t\t\treturn -EINVAL;\n-\t\t}\n-\t\tfor (entry = 0; entry < entries; entry++) {\n-\t\t\tprofile->kpu[kpu].cam[entry] = cam[entry];\n-\t\t\tprofile->kpu[kpu].action[entry] = action[entry];\n-\t\t}\n-\t}\n-\n-\treturn 0;\n+\treturn from_fs ? npc_apply_custom_kpu_from_fs(rvu, profile) :\n+\t\tnpc_apply_custom_kpu_from_fw(rvu, profile);\n }\n \n static int npc_load_kpu_prfl_img(struct rvu *rvu, void __iomem *prfl_addr,\n@@ -1958,45 +2180,19 @@ static int npc_load_kpu_profile_fwdb(struct rvu *rvu, const char *kpu_profile)\n \treturn ret;\n }\n \n-void npc_load_kpu_profile(struct rvu *rvu)\n+static int npc_load_kpu_profile_from_fw(struct rvu *rvu)\n {\n \tstruct npc_kpu_profile_adapter *profile = &rvu->kpu;\n \tconst char *kpu_profile = rvu->kpu_pfl_name;\n-\tconst struct firmware *fw = NULL;\n-\tbool retry_fwdb = false;\n-\n-\t/* If user not specified profile customization */\n-\tif (!strncmp(kpu_profile, def_pfl_name, KPU_NAME_LEN))\n-\t\tgoto revert_to_default;\n-\t/* First prepare default KPU, then we'll customize top entries. */\n-\tnpc_prepare_default_kpu(rvu, profile);\n+\tint fw_kpus = 0;\n \n-\t/* Order of preceedence for load loading NPC profile (high to low)\n-\t * Firmware binary in filesystem.\n-\t * Firmware database method.\n-\t * Default KPU profile.\n-\t */\n-\tif (!request_firmware_direct(&fw, kpu_profile, rvu->dev)) {\n-\t\tdev_info(rvu->dev, \"Loading KPU profile from firmware: %s\\n\",\n-\t\t\t kpu_profile);\n-\t\trvu->kpu_fwdata = kzalloc(fw->size, GFP_KERNEL);\n-\t\tif (rvu->kpu_fwdata) {\n-\t\t\tmemcpy(rvu->kpu_fwdata, fw->data, fw->size);\n-\t\t\trvu->kpu_fwdata_sz = fw->size;\n-\t\t}\n-\t\trelease_firmware(fw);\n-\t\tretry_fwdb = true;\n-\t\tgoto program_kpu;\n-\t}\n-\n-load_image_fwdb:\n \t/* Loading the KPU profile using firmware database */\n \tif (npc_load_kpu_profile_fwdb(rvu, kpu_profile))\n-\t\tgoto revert_to_default;\n+\t\treturn -EFAULT;\n \n-program_kpu:\n \t/* Apply profile customization if firmware was loaded. */\n-\tif (!rvu->kpu_fwdata_sz || npc_apply_custom_kpu(rvu, profile)) {\n+\tif (!rvu->kpu_fwdata_sz ||\n+\t npc_apply_custom_kpu(rvu, profile, false, &fw_kpus)) {\n \t\t/* If image from firmware filesystem fails to load or invalid\n \t\t * retry with firmware database method.\n \t\t */\n@@ -2010,10 +2206,6 @@ void npc_load_kpu_profile(struct rvu *rvu)\n \t\t\t}\n \t\t\trvu->kpu_fwdata = NULL;\n \t\t\trvu->kpu_fwdata_sz = 0;\n-\t\t\tif (retry_fwdb) {\n-\t\t\t\tretry_fwdb = false;\n-\t\t\t\tgoto load_image_fwdb;\n-\t\t\t}\n \t\t}\n \n \t\tdev_warn(rvu->dev,\n@@ -2021,22 +2213,98 @@ void npc_load_kpu_profile(struct rvu *rvu)\n \t\t\t kpu_profile);\n \t\tkfree(rvu->kpu_fwdata);\n \t\trvu->kpu_fwdata = NULL;\n-\t\tgoto revert_to_default;\n+\t\treturn -EFAULT;\n \t}\n \n-\tdev_info(rvu->dev, \"Using custom profile '%s', version %d.%d.%d\\n\",\n+\tdev_info(rvu->dev, \"Using custom profile '%.32s', version %d.%d.%d\\n\",\n \t\t profile->name, NPC_KPU_VER_MAJ(profile->version),\n \t\t NPC_KPU_VER_MIN(profile->version),\n \t\t NPC_KPU_VER_PATCH(profile->version));\n \n-\treturn;\n+\treturn 0;\n+}\n+\n+static int npc_load_kpu_profile_from_fs(struct rvu *rvu)\n+{\n+\tstruct npc_kpu_profile_adapter *profile = &rvu->kpu;\n+\tconst char *kpu_profile = rvu->kpu_pfl_name;\n+\tconst struct firmware *fw = NULL;\n+\tint ret, fw_kpus = 0;\n+\tchar path[512] = \"kpu/\";\n+\n+\tif (strlen(kpu_profile) > sizeof(path) - strlen(\"kpu/\") - 1) {\n+\t\tdev_err(rvu->dev, \"kpu profile name is too big\\n\");\n+\t\treturn -ENOSPC;\n+\t}\n+\n+\tstrcat(path, kpu_profile);\n+\n+\tif (request_firmware_direct(&fw, path, rvu->dev))\n+\t\treturn -ENOENT;\n+\n+\tdev_info(rvu->dev, \"Loading KPU profile from filesystem: %s\\n\",\n+\t\t path);\n+\n+\trvu->kpu_fwdata = fw->data;\n+\trvu->kpu_fwdata_sz = fw->size;\n+\n+\tret = npc_apply_custom_kpu(rvu, profile, true, &fw_kpus);\n+\trelease_firmware(fw);\n+\trvu->kpu_fwdata = NULL;\n+\n+\tif (ret) {\n+\t\trvu->kpu_fwdata_sz = 0;\n+\t\tdev_err(rvu->dev,\n+\t\t\t\"Loading KPU profile from filesystem failed\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\trvu->kpu.kpus = fw_kpus;\n+\tprofile->kpus = fw_kpus;\n+\tprofile->from_fs = true;\n+\treturn 0;\n+}\n+\n+void npc_load_kpu_profile(struct rvu *rvu)\n+{\n+\tstruct npc_kpu_profile_adapter *profile = &rvu->kpu;\n+\tconst char *kpu_profile = rvu->kpu_pfl_name;\n+\n+\tprofile->from_fs = false;\n+\n+\tnpc_prepare_default_kpu(rvu, profile);\n+\n+\t/* If user not specified profile customization */\n+\tif (!strncmp(kpu_profile, def_pfl_name, KPU_NAME_LEN))\n+\t\treturn;\n+\n+\t/* Order of preceedence for load loading NPC profile (high to low)\n+\t * Firmware binary in filesystem.\n+\t * Firmware database method.\n+\t * Default KPU profile.\n+\t */\n+\n+\t/* Filesystem-based KPU loading is not supported on cn20k.\n+\t * npc_prepare_default_kpu() was invoked earlier, but control\n+\t * reached this point because the default profile was not selected.\n+\t * No need to call it again.\n+\t */\n+\tif (!is_cn20k(rvu->pdev)) {\n+\t\tif (!npc_load_kpu_profile_from_fs(rvu))\n+\t\t\treturn;\n+\t}\n+\n+\t/* First prepare default KPU, then we'll customize top entries. */\n+\tnpc_prepare_default_kpu(rvu, profile);\n+\tif (!npc_load_kpu_profile_from_fw(rvu))\n+\t\treturn;\n \n-revert_to_default:\n \tnpc_prepare_default_kpu(rvu, profile);\n }\n \n static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)\n {\n+\tstruct npc_kpu_profile_adapter *profile = &rvu->kpu;\n \tstruct rvu_hwinfo *hw = rvu->hw;\n \tint num_pkinds, num_kpus, idx;\n \n@@ -2060,7 +2328,9 @@ static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)\n \tnum_pkinds = min_t(int, hw->npc_pkinds, num_pkinds);\n \n \tfor (idx = 0; idx < num_pkinds; idx++)\n-\t\tnpc_config_kpuaction(rvu, blkaddr, &rvu->kpu.ikpu[idx], 0, idx, true);\n+\t\tnpc_config_kpuaction(rvu, blkaddr,\n+\t\t\t\t npc_get_ikpu_nth_entry(rvu, idx),\n+\t\t\t\t 0, idx, true);\n \n \t/* Program KPU CAM and Action profiles */\n \tnum_kpus = rvu->kpu.kpus;\n@@ -2068,6 +2338,11 @@ static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)\n \n \tfor (idx = 0; idx < num_kpus; idx++)\n \t\tnpc_program_kpu_profile(rvu, blkaddr, idx, &rvu->kpu.kpu[idx]);\n+\n+\tif (profile->from_fs) {\n+\t\trvu_write64(rvu, blkaddr, NPC_AF_PKINDX_TYPE(54), 0x03);\n+\t\trvu_write64(rvu, blkaddr, NPC_AF_PKINDX_TYPE(58), 0x03);\n+\t}\n }\n \n void npc_mcam_rsrcs_deinit(struct rvu *rvu)\n@@ -2297,18 +2572,21 @@ static void rvu_npc_hw_init(struct rvu *rvu, int blkaddr)\n \n static void rvu_npc_setup_interfaces(struct rvu *rvu, int blkaddr)\n {\n-\tstruct npc_mcam_kex_extr *mkex_extr = rvu->kpu.mcam_kex_prfl.mkex_extr;\n-\tstruct npc_mcam_kex *mkex = rvu->kpu.mcam_kex_prfl.mkex;\n+\tconst struct npc_mcam_kex_extr *mkex_extr;\n \tstruct npc_mcam *mcam = &rvu->hw->mcam;\n \tstruct rvu_hwinfo *hw = rvu->hw;\n+\tconst struct npc_mcam_kex *mkex;\n \tu64 nibble_ena, rx_kex, tx_kex;\n \tu64 *keyx_cfg, reg;\n \tu8 intf;\n \n+\tmkex_extr = rvu->kpu.mcam_kex_prfl.mkex_extr;\n+\tmkex = rvu->kpu.mcam_kex_prfl.mkex;\n+\n \tif (is_cn20k(rvu->pdev)) {\n-\t\tkeyx_cfg = mkex_extr->keyx_cfg;\n+\t\tkeyx_cfg = (u64 *)mkex_extr->keyx_cfg;\n \t} else {\n-\t\tkeyx_cfg = mkex->keyx_cfg;\n+\t\tkeyx_cfg = (u64 *)mkex->keyx_cfg;\n \t\t/* Reserve last counter for MCAM RX miss action which is set to\n \t\t * drop packet. This way we will know how many pkts didn't\n \t\t * match any MCAM entry.\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h\nindex 83c5e32e2afc..662f6693cfe9 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h\n+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h\n@@ -18,4 +18,21 @@ int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr,\n \n void npc_mcam_clear_bit(struct npc_mcam *mcam, u16 index);\n void npc_mcam_set_bit(struct npc_mcam *mcam, u16 index);\n+\n+struct npc_kpu_profile_action *\n+npc_get_ikpu_nth_entry(struct rvu *rvu, int n);\n+\n+int\n+npc_get_num_kpu_cam_entries(struct rvu *rvu,\n+\t\t\t const struct npc_kpu_profile *kpu_pfl);\n+struct npc_kpu_profile_cam *\n+npc_get_kpu_cam_nth_entry(struct rvu *rvu,\n+\t\t\t const struct npc_kpu_profile *kpu_pfl, int n);\n+\n+int\n+npc_get_num_kpu_action_entries(struct rvu *rvu,\n+\t\t\t const struct npc_kpu_profile *kpu_pfl);\n+struct npc_kpu_profile_action *\n+npc_get_kpu_action_nth_entry(struct rvu *rvu,\n+\t\t\t const struct npc_kpu_profile *kpu_pfl, int n);\n #endif /* RVU_NPC_H */\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h\nindex 62cdc714ba57..ab89b8c6e490 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h\n+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h\n@@ -596,6 +596,7 @@\n #define NPC_AF_INTFX_KEX_CFG(a)\t\t(0x01010 | (a) << 8)\n #define NPC_AF_PKINDX_ACTION0(a)\t(0x80000ull | (a) << 6)\n #define NPC_AF_PKINDX_ACTION1(a)\t(0x80008ull | (a) << 6)\n+#define NPC_AF_PKINDX_TYPE(a)\t\t(0x80010ull | (a) << 6)\n #define NPC_AF_PKINDX_CPI_DEFX(a, b)\t(0x80020ull | (a) << 6 | (b) << 3)\n #define NPC_AF_KPUX_ENTRYX_CAMX(a, b, c) \\\n \t\t(0x100000 | (a) << 14 | (b) << 6 | (c) << 3)\n", "prefixes": [ "v12", "net-next", "7/9" ] }