get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/137655/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 137655,
    "url": "http://patchwork.dpdk.org/api/patches/137655/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20240301084244.190484-2-chaoyong.he@corigine.com/",
    "project": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20240301084244.190484-2-chaoyong.he@corigine.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20240301084244.190484-2-chaoyong.he@corigine.com",
    "date": "2024-03-01T08:42:42",
    "name": "[v2,1/3] net/nfp: add the elf module",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "e476bf800846e2b628d98ac15c9b84d29c1266de",
    "submitter": {
        "id": 2554,
        "url": "http://patchwork.dpdk.org/api/people/2554/?format=api",
        "name": "Chaoyong He",
        "email": "chaoyong.he@corigine.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patchwork.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/20240301084244.190484-2-chaoyong.he@corigine.com/mbox/",
    "series": [
        {
            "id": 31323,
            "url": "http://patchwork.dpdk.org/api/series/31323/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=31323",
            "date": "2024-03-01T08:42:41",
            "name": "reload the firmware as needed",
            "version": 2,
            "mbox": "http://patchwork.dpdk.org/series/31323/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/137655/comments/",
    "check": "warning",
    "checks": "http://patchwork.dpdk.org/api/patches/137655/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id F201443BC0;\n\tFri,  1 Mar 2024 09:43:15 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 0561643320;\n\tFri,  1 Mar 2024 09:43:10 +0100 (CET)",
            "from NAM11-CO1-obe.outbound.protection.outlook.com\n (mail-co1nam11on2134.outbound.protection.outlook.com [40.107.220.134])\n by mails.dpdk.org (Postfix) with ESMTP id 71568400D5\n for <dev@dpdk.org>; Fri,  1 Mar 2024 09:43:07 +0100 (CET)",
            "from SJ0PR13MB5545.namprd13.prod.outlook.com (2603:10b6:a03:424::5)\n by MW3PR13MB4153.namprd13.prod.outlook.com (2603:10b6:303:5c::8) with\n Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7316.41; Fri, 1 Mar\n 2024 08:43:05 +0000",
            "from SJ0PR13MB5545.namprd13.prod.outlook.com\n ([fe80::ec12:7411:559a:850e]) by SJ0PR13MB5545.namprd13.prod.outlook.com\n ([fe80::ec12:7411:559a:850e%4]) with mapi id 15.20.7316.039; Fri, 1 Mar 2024\n 08:43:05 +0000"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=eTqQM+Gk+ZY966iWCFuu8jRNWsGCSEuYXdkHHwkQQ4HoqraKBExTkQeJkosq596XD6et/CMybn71YpybuqFCn9m/Ulizr10TaGTfeR5ZV+r6fY9fMcikB6oK/wyQkuHuqCaxvuWos6Fh8Bqkc2Myr9qf8goOWX6df8hAp1QtZrBZhf4mbYmNgoad/GSg9anN0aMufJUOkOG+rCEslZX1jAnVoUGg7QbdxSZ2m6VQOexVmtZMlD/M1CbPlI/fvbraNsh5tVP8VDyVVukLsr54ZrJ501vaGa54DOiisRiLLhEiJatCH54F+H/MPkEujRpX7087sJ9ZLZH8Q21s3gjc5Q==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector9901;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n bh=JJVWxYvpEmsKXer3gmq/e7+MiPU/4lmmC3fd/RDyqVA=;\n b=Zy0qglsAMJlWazB9rrpSZyAp3Xtd7YMj/O5TbUJG1SlOrHXkgLqp3XjRJ1J/Lf6alTP56In8IILVMTjEg21/HkzuRv7w2i4I5c+vZPAl2cxiJZvgodkiR+3Cl9FFFMbEYrFubm0OlURUZ6YVm3bCK42Gnm+uNLZc5pbaRPG/GKZ01xqC8un1S2eDzXoPCCudJ0hhYvFS15bC1pHJ1kfyhIPFBJNp3kEKGy0Fh2sueJeclqooKxKXDK/euxt6mss8XHTwIkQ9i8W/W1EkwxCrIy6v3ttGoE6BLgkWMVn5cTntNsocuvpT8bQQhX15azB7QSCGIGeJ8U7VzSJR3PMc7g==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass\n smtp.mailfrom=corigine.com; dmarc=pass action=none header.from=corigine.com;\n dkim=pass header.d=corigine.com; arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=corigine.onmicrosoft.com; s=selector2-corigine-onmicrosoft-com;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=JJVWxYvpEmsKXer3gmq/e7+MiPU/4lmmC3fd/RDyqVA=;\n b=ODFQXnH50GsaMukigkcxHQ+sQO9qcGLDrqF9AJjalCEa1QCWInQrrsuznv4t8IS2ntfO3TnIVtshWo4jGyardYnSOk7noHLKX2UFg8vEPJashvGl0+cYs7rIxBI2l2PMXJ/PJP6J1XaALHJ2WSohPGdI8Hj6Pu1WlzP79/8jjXg=",
        "Authentication-Results": "dkim=none (message not signed)\n header.d=none;dmarc=none action=none header.from=corigine.com;",
        "From": "Chaoyong He <chaoyong.he@corigine.com>",
        "To": "dev@dpdk.org",
        "Cc": "oss-drivers@corigine.com, Peng Zhang <peng.zhang@corigine.com>,\n Chaoyong He <chaoyong.he@corigine.com>, Long Wu <long.wu@corigine.com>",
        "Subject": "[PATCH v2 1/3] net/nfp: add the elf module",
        "Date": "Fri,  1 Mar 2024 16:42:42 +0800",
        "Message-Id": "<20240301084244.190484-2-chaoyong.he@corigine.com>",
        "X-Mailer": "git-send-email 2.39.1",
        "In-Reply-To": "<20240301084244.190484-1-chaoyong.he@corigine.com>",
        "References": "<20240227111551.3773862-1-chaoyong.he@corigine.com>\n <20240301084244.190484-1-chaoyong.he@corigine.com>",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-ClientProxiedBy": "SJ0PR03CA0206.namprd03.prod.outlook.com\n (2603:10b6:a03:2ef::31) To SJ0PR13MB5545.namprd13.prod.outlook.com\n (2603:10b6:a03:424::5)",
        "MIME-Version": "1.0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "SJ0PR13MB5545:EE_|MW3PR13MB4153:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "37549033-bbfc-4be8-a805-08dc39cb9caa",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n 5/0GBNt/L9+osPtsZi27n2QeR0gVgj6dhbsQp1LtCCZYp9KRD8AkYbxCm0iS2yu3BWbAulNlGHRd12BEMQmFvRX3nWGykAdZ0z0zcSuxo+sS51gQlmW8dy/PbyCi9GdrRShKdfkrthpQAtzpplS3JLoUo+i10ZW6qgTBPwwaLexvGQY0Owzn+stLw8guXXRwvYUf8fPBexoaYwIwy9szvuyvq7PQyYo+5mkkOrf6I3RC41dPnRwQoMun1cWdQEC02pPbFwnO1cSSaHkKUjJGvhf2F+VWdTOkVz0fvzLcKO2l/jNYED+dhBPscph0MpCietcFJHhAQ989crLuVkty57HSrv/O1Qh4Jj/Y2YWQxYUhX6dXc4RocL5Pyc1YkCXvw4TzxZrkRlSl3iMD2miHT3x9qOLO6gRXP92G4EJ09wgXDgqyHOpOtTKdsFQtqAwBiT/7MGYZH+yNt2s2YNWvz9/EaRZy+iGrlftvUHtwUevVkHU+u73KDXFiXU7SWVjzKL5SlIG7ZUvcBWGFsKH2KUMqyT36UviUZYZEIBPb1/tMHaJw+sD+p+1GuzKCmQwdl5uty8/nVy728U/iLOFBrqLYK7bZ99mtS19RnLr7XjOD5DWQCN/16xPUndNbgbbLYwzM7J++DMUkRydvxQNEZmtrsdLZJFctJOQkkUb9S1BkxCjVcTNcIBoxiIvitlOJtSuRLpgvCExnputs0+RxuA==",
        "X-Forefront-Antispam-Report": "CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;\n IPV:NLI; SFV:NSPM; H:SJ0PR13MB5545.namprd13.prod.outlook.com; PTR:; CAT:NONE;\n SFS:(13230031)(38350700005); DIR:OUT; SFP:1102;",
        "X-MS-Exchange-AntiSpam-MessageData-ChunkCount": "1",
        "X-MS-Exchange-AntiSpam-MessageData-0": "\n sR0wrXNx1QsWjsTIm8Cc7+excQzUv93KXL9HLct8mOmSSx+uIJILnWLG0QDi5pbzv57LwJzFxEASdJfmJq2l/cllVInat5dAQ7KJ812hy8u1XTrH/YSwYOM2zp1cvaLKwQ1ZarRPo4kX+ledLxZMrYjciFJS5z13nj+R//zOIEoHQTjXgWIst5CbDATIEnXWPueLy3DmjU+zM79Maton8U8Tyari4PvmkmiQY8auEFyt26yCdExHZt1tQ9zD8LGq8rRwSmCwU1YkHQPXCVI0K2c53RtRNBwhObOWa4zk6czE4+g91BqYAY1jF103N9EJRfRWi/BU+vqxERWyYMeuUdOZ4i8AHDNEZQBWjz59vDPkN+lQVMGWAoiMfbz5sSB8UnBXJ1WAgwskLCyuiZBFy+NiL/P0fpocj4Y/8UVY2MB1nJr6aFSWrqXBzHZDti2j0uOAFMYbZbDueSBZjekM0idY3DbFVAWzGfp4dOuNpWGiqd5tmyp1bKU45Hu3/EtTnNWpQJVXN16I5fajjpJq+hrdDsZk5eHb+0R6+lwOaV/VCvm1ZeWdC91OOO47iZ9mbYWVFAAe8IOu24GMfieRHsn9BKvG/Zw0fGBwWuQtKAt/VJcfyZf9tkvNZQPzEFpXRf5Qgmy+nWnBE/kMsvBxc9ZiJfncJpcGMv7LZKgEBETGwxsEYGH/kUG8HyLKZmPyljh5IX/g9TQKaSPgkVyiPeQ7wWWp8Oqq6udPcc5eHw2Z0f9UNDmcZKOAlbXAmyYxArmh5VRsbGpUFGvZRVgJ+K1VXCex1i9q6q8OdzBxvm99s3IEbUES7/EZTv3ZCoBfz/gzA0Ml/PkdcKDJ4Sf+zG7xkLaHwy3kWYjadFz/dSlTaBk617emoE9HbRysVdUQtezlyhGp/GFu3PTr8o0CWGJyAIHJyhZoF4GGNc5rrPTPZWj4+R38SGDigNK06ODBkvYe/Pkh0loPucKofY2VdHRQIvqr0VZjXCekgYhhV0D2bAt3Z5L1HRSYB2nMvxgT0/cDSdNjJmAUaiLNWBUK1tk2MSfivsmcuL1vEHhd4lyXI/F3Mvnn8GMVMbEKeyEmcjkQ9pdTg34M4DnxRpzIoc1hQuNMXz1iolrVLIhqtuDTb3zD3VBNfjvjPo4xSqC3XWPw05szWty+u1Pcuqbpc60Fn0ip3m4xNKDFdXa3L53+RjFaO1T2GqoqULTqb7THECm3Gw+VW/dWFpvOMW4G7wkJEtWnQ92DdDuheZ0Yxvfecqyid6V5NTaooqsQDFK2mTcAQfWOJo/EnjyZAusv2RZPPqNtcxdbEwVb76S6VUAjkqCeLYyFegJn5tcHIkJrDx5LG+pOcHbe5ahyH9+5ppP/0P08RrypTF+y66M8zt5zq7KUx5+UQyf62RMZ5SewnLKT/JC83RMetvCDXtNGQtKNp5gCRifPrbexb7HRL51rwRZbIRSqUYlYggXjnkHqiE28eHp7wTa4B/3rvUqzNwtTCH97QbvP2xGHxhiwLEVlsi8JYyhowzNQZDknHT5TBm9rwniNYt6jwbLDFP5W19gl8zI7UdIVD3M4p5G1SAD/cf87+RHihjrnFlUV4IWzfbhilv7UqAqbBG2+Gotb9A==",
        "X-OriginatorOrg": "corigine.com",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 37549033-bbfc-4be8-a805-08dc39cb9caa",
        "X-MS-Exchange-CrossTenant-AuthSource": "SJ0PR13MB5545.namprd13.prod.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Internal",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "01 Mar 2024 08:43:05.6026 (UTC)",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted",
        "X-MS-Exchange-CrossTenant-Id": "fe128f2c-073b-4c20-818e-7246a585940c",
        "X-MS-Exchange-CrossTenant-MailboxType": "HOSTED",
        "X-MS-Exchange-CrossTenant-UserPrincipalName": "\n z4icKF1xqaiBl979hEF+UOSiTwOW4eA/DbR+fpDvEmAtDsHemGwwH3iJQjnx+hQ4Y/Gt7rHsVbeF5ajZvc0749qkAig+2G6sRPao9GwUmEU=",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "MW3PR13MB4153",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "From: Peng Zhang <peng.zhang@corigine.com>\n\nAdd the 'nfp_elf' module, which can get new MIP(Microcode Information Page)\ninformation from the firmware ELF file.\n\nSigned-off-by: Peng Zhang <peng.zhang@corigine.com>\nReviewed-by: Chaoyong He <chaoyong.he@corigine.com>\nReviewed-by: Long Wu <long.wu@corigine.com>\n---\n drivers/net/nfp/meson.build       |    1 +\n drivers/net/nfp/nfpcore/nfp_elf.c | 1079 +++++++++++++++++++++++++++++\n drivers/net/nfp/nfpcore/nfp_elf.h |   13 +\n drivers/net/nfp/nfpcore/nfp_mip.c |   30 +-\n drivers/net/nfp/nfpcore/nfp_mip.h |   70 +-\n 5 files changed, 1168 insertions(+), 25 deletions(-)\n create mode 100644 drivers/net/nfp/nfpcore/nfp_elf.c\n create mode 100644 drivers/net/nfp/nfpcore/nfp_elf.h",
    "diff": "diff --git a/drivers/net/nfp/meson.build b/drivers/net/nfp/meson.build\nindex e376fd328f..959ca01844 100644\n--- a/drivers/net/nfp/meson.build\n+++ b/drivers/net/nfp/meson.build\n@@ -18,6 +18,7 @@ sources = files(\n         'nfdk/nfp_nfdk_dp.c',\n         'nfpcore/nfp_cppcore.c',\n         'nfpcore/nfp_crc.c',\n+        'nfpcore/nfp_elf.c',\n         'nfpcore/nfp_hwinfo.c',\n         'nfpcore/nfp_mip.c',\n         'nfpcore/nfp_mutex.c',\ndiff --git a/drivers/net/nfp/nfpcore/nfp_elf.c b/drivers/net/nfp/nfpcore/nfp_elf.c\nnew file mode 100644\nindex 0000000000..fbd350589b\n--- /dev/null\n+++ b/drivers/net/nfp/nfpcore/nfp_elf.c\n@@ -0,0 +1,1079 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2023 Corigine, Inc.\n+ * All rights reserved.\n+ */\n+\n+#include \"nfp_elf.h\"\n+\n+#include <malloc.h>\n+#include <stdbool.h>\n+#include <ethdev_pci.h>\n+\n+#include <nfp_platform.h>\n+#include <rte_common.h>\n+#include <eal_firmware.h>\n+\n+#include \"nfp_logs.h\"\n+#include \"nfp_mip.h\"\n+\n+/*\n+ * NFP Chip Families.\n+ *\n+ * These are not enums, because they need to be microcode compatible.\n+ * They are also not maskable.\n+ *\n+ * Note: The NFP-4xxx family is handled as NFP-6xxx in most software\n+ * components.\n+ */\n+#define NFP_CHIP_FAMILY_NFP3800 0x3800\n+#define NFP_CHIP_FAMILY_NFP6000 0x6000\n+\n+/* Standard ELF */\n+#define NFP_ELF_EI_NIDENT     16\n+#define NFP_ELF_EI_MAG0       0\n+#define NFP_ELF_EI_MAG1       1\n+#define NFP_ELF_EI_MAG2       2\n+#define NFP_ELF_EI_MAG3       3\n+#define NFP_ELF_EI_CLASS      4\n+#define NFP_ELF_EI_DATA       5\n+#define NFP_ELF_EI_VERSION    6\n+#define NFP_ELF_EI_PAD        7\n+#define NFP_ELF_ELFMAG0       0x7f\n+#define NFP_ELF_ELFMAG1       'E'\n+#define NFP_ELF_ELFMAG2       'L'\n+#define NFP_ELF_ELFMAG3       'F'\n+#define NFP_ELF_ELFCLASSNONE  0\n+#define NFP_ELF_ELFCLASS32    1\n+#define NFP_ELF_ELFCLASS64    2\n+#define NFP_ELF_ELFDATANONE   0\n+#define NFP_ELF_ELFDATA2LSB   1\n+#define NFP_ELF_ELFDATA2MSB   2\n+\n+#define NFP_ELF_ET_NONE       0\n+#define NFP_ELF_ET_REL        1\n+#define NFP_ELF_ET_EXEC       2\n+#define NFP_ELF_ET_DYN        3\n+#define NFP_ELF_ET_CORE       4\n+#define NFP_ELF_ET_LOPROC     0xFF00\n+#define NFP_ELF_ET_HIPROC     0xFFFF\n+#define NFP_ELF_ET_NFP_PARTIAL_REL   (NFP_ELF_ET_LOPROC + NFP_ELF_ET_REL)\n+#define NFP_ELF_ET_NFP_PARTIAL_EXEC  (NFP_ELF_ET_LOPROC + NFP_ELF_ET_EXEC)\n+\n+#define NFP_ELF_EM_NFP        250\n+#define NFP_ELF_EM_NFP6000    0x6000\n+\n+#define NFP_ELF_SHT_NULL      0\n+#define NFP_ELF_SHT_PROGBITS  1\n+#define NFP_ELF_SHT_SYMTAB    2\n+#define NFP_ELF_SHT_STRTAB    3\n+#define NFP_ELF_SHT_RELA      4\n+#define NFP_ELF_SHT_HASH      5\n+#define NFP_ELF_SHT_DYNAMIC   6\n+#define NFP_ELF_SHT_NOTE      7\n+#define NFP_ELF_SHT_NOBITS    8\n+#define NFP_ELF_SHT_REL       9\n+#define NFP_ELF_SHT_SHLIB     10\n+#define NFP_ELF_SHT_DYNSYM    11\n+#define NFP_ELF_SHT_LOPROC    0x70000000\n+#define NFP_ELF_SHT_HIPROC    0x7fffffff\n+#define NFP_ELF_SHT_LOUSER    0x80000000\n+#define NFP_ELF_SHT_HIUSER    0x8fffffff\n+\n+#define NFP_ELF_EV_NONE       0\n+#define NFP_ELF_EV_CURRENT    1\n+\n+#define NFP_ELF_SHN_UNDEF     0\n+\n+/* EM_NFP ELF flags */\n+\n+/*\n+ * Valid values for FAMILY are:\n+ * 0x6000 - NFP-6xxx/NFP-4xxx\n+ * 0x3800 - NFP-38xx\n+ */\n+#define NFP_ELF_EF_NFP_FAMILY_MASK        0xFFFF\n+#define NFP_ELF_EF_NFP_FAMILY_LSB         8\n+\n+#define NFP_ELF_SHT_NFP_MECONFIG          (NFP_ELF_SHT_LOPROC + 1)\n+#define NFP_ELF_SHT_NFP_INITREG           (NFP_ELF_SHT_LOPROC + 2)\n+#define NFP_ELF_SHT_UOF_DEBUG             (NFP_ELF_SHT_LOUSER)\n+\n+/* NFP target revision note type */\n+#define NFP_ELT_NOTE_NAME_NFP             \"NFP\\0\"\n+#define NFP_ELT_NOTE_NAME_NFP_SZ          4\n+#define NFP_ELT_NOTE_NAME_NFP_USER        \"NFP_USR\\0\"\n+#define NFP_ELT_NOTE_NAME_NFP_USER_SZ     8\n+#define NFP_ELF_NT_NFP_BUILD_INFO         0x100\n+#define NFP_ELF_NT_NFP_REVS               0x101\n+#define NFP_ELF_NT_NFP_MIP_LOCATION       0x102\n+#define NFP_ELF_NT_NFP_USER               0xf0000000\n+\n+\n+/* Standard ELF structures */\n+struct nfp_elf_elf64_ehdr {\n+\tuint8_t e_ident[NFP_ELF_EI_NIDENT];\n+\trte_le16_t e_type;\n+\trte_le16_t e_machine;\n+\trte_le32_t e_version;\n+\trte_le64_t e_entry;\n+\trte_le64_t e_phoff;\n+\trte_le64_t e_shoff;\n+\trte_le32_t e_flags;\n+\trte_le16_t e_ehsize;\n+\trte_le16_t e_phentsize;\n+\trte_le16_t e_phnum;\n+\trte_le16_t e_shentsize;\n+\trte_le16_t e_shnum;\n+\trte_le16_t e_shstrndx;\n+};\n+\n+struct nfp_elf_elf64_shdr {\n+\trte_le32_t sh_name;\n+\trte_le32_t sh_type;\n+\trte_le64_t sh_flags;\n+\trte_le64_t sh_addr;\n+\trte_le64_t sh_offset;\n+\trte_le64_t sh_size;\n+\trte_le32_t sh_link;\n+\trte_le32_t sh_info;\n+\trte_le64_t sh_addralign;\n+\trte_le64_t sh_entsize;\n+};\n+\n+struct nfp_elf_elf64_sym {\n+\trte_le32_t st_name;\n+\tuint8_t st_info;\n+\tuint8_t st_other;\n+\trte_le16_t st_shndx;\n+\trte_le64_t st_value;\n+\trte_le64_t st_size;\n+};\n+\n+struct nfp_elf_elf64_rel {\n+\trte_le64_t r_offset;\n+\trte_le64_t r_info;\n+};\n+\n+struct nfp_elf_elf64_nhdr {\n+\trte_le32_t n_namesz;\n+\trte_le32_t n_descsz;\n+\trte_le32_t n_type;\n+};\n+\n+/* NFP specific structures */\n+struct nfp_elf_elf_meconfig {\n+\trte_le32_t ctx_enables;\n+\trte_le32_t entry;\n+\trte_le32_t misc_control;\n+\trte_le32_t reserved;\n+};\n+\n+struct nfp_elf_elf_initregentry {\n+\trte_le32_t w0;\n+\trte_le32_t cpp_offset_lo;\n+\trte_le32_t val;\n+\trte_le32_t mask;\n+};\n+\n+/* NFP NFFW ELF struct and API */\n+struct nfp_elf_user_note {\n+\tconst char *name;\n+\tuint32_t data_sz;\n+\tvoid *data;\n+};\n+\n+/*\n+ * nfp_elf_fw_mip contains firmware related fields from the MIP as well as the\n+ * MIP location in the NFFW file. All fields are only valid if shndx > 0.\n+ *\n+ * This struct will only be available if the firmware contains a .note section\n+ * with a note of type NFP_ELF_NT_NFP_MIP_LOCATION.\n+ */\n+struct nfp_elf_fw_mip {\n+\tsize_t shndx;\n+\tuint64_t sh_offset;\n+\trte_le32_t mip_ver;      /**< Version of the format of the MIP itself */\n+\n+\trte_le32_t fw_version;\n+\trte_le32_t fw_buildnum;\n+\trte_le32_t fw_buildtime;\n+\tchar fw_name[20];        /**< At most 16 chars, 17 ensures '\\0', round up */\n+\tconst char *fw_typeid;   /**< NULL if none set */\n+};\n+\n+/*\n+ * It is preferred to access this struct via the nfp_elf functions\n+ * rather than directly.\n+ */\n+struct nfp_elf {\n+\tstruct nfp_elf_elf64_ehdr *ehdr;\n+\tstruct nfp_elf_elf64_shdr *shdrs;\n+\tsize_t shdrs_cnt;\n+\tvoid **shdrs_data;\n+\n+\t/** True if section data has been endian swapped */\n+\tuint8_t *shdrs_host_endian;\n+\n+\tsize_t shdr_idx_symtab;\n+\n+\tstruct nfp_elf_elf64_sym *syms;\n+\tsize_t syms_cnt;\n+\n+\tchar *shstrtab;\n+\tsize_t shstrtab_sz;\n+\n+\tchar *symstrtab;\n+\tsize_t symstrtab_sz;\n+\n+\tstruct nfp_elf_elf_meconfig *meconfs;\n+\tsize_t meconfs_cnt;\n+\n+\t/* ==== .note data start ==== */\n+\n+\t/**\n+\t * Following data derived from SHT_NOTE sections for read-only usage.\n+\t * These fields are not used in nfp_elf_to_buf()\n+\t */\n+\tint rev_min; /**< -1 if file did not specify */\n+\tint rev_max; /**< -1 if file did not specify */\n+\n+\t/**\n+\t * If mip_shndx == 0 and mip_sh_off == 0, the .note stated there is no MIP.\n+\t * If mip_shndx == 0 and mip_sh_off == UINT64_MAX, there was no .note and\n+\t * a MIP _may_ still be found in the first 256KiB of DRAM/EMEM data.\n+\t */\n+\tsize_t mip_shndx; /**< Section in which MIP resides, 0 if no MIP */\n+\tuint64_t mip_sh_off; /**< Offset within section (not address) */\n+\n+\tstruct nfp_elf_fw_mip fw_mip;\n+\tconst char *fw_info_strtab;\n+\tsize_t fw_info_strtab_sz;\n+\n+\t/* ==== .note.user data start ==== */\n+\tsize_t user_note_cnt;\n+\tstruct nfp_elf_user_note *user_notes;\n+\n+\tvoid *dbgdata;\n+\n+\tint family;\n+\n+\t/**\n+\t * For const entry points in the API, we allocate and keep a buffer\n+\t * and for mutable entry points we assume the buffer remains valid\n+\t * and we just set pointers to it.\n+\t */\n+\tvoid *_buf;\n+\tsize_t _bufsz;\n+};\n+\n+static void\n+nfp_elf_free(struct nfp_elf *ectx)\n+{\n+\tif (ectx == NULL)\n+\t\treturn;\n+\n+\tfree(ectx->shdrs);\n+\tfree(ectx->shdrs_data);\n+\tfree(ectx->shdrs_host_endian);\n+\tif (ectx->_bufsz != 0)\n+\t\tfree(ectx->_buf);\n+\n+\tfree(ectx);\n+}\n+\n+static size_t\n+nfp_elf_get_sec_ent_cnt(struct nfp_elf *ectx,\n+\t\tsize_t idx)\n+{\n+\tuint64_t sh_size = rte_le_to_cpu_64(ectx->shdrs[idx].sh_size);\n+\tuint64_t sh_entsize = rte_le_to_cpu_64(ectx->shdrs[idx].sh_entsize);\n+\n+\tif (sh_entsize != 0)\n+\t\treturn sh_size / sh_entsize;\n+\n+\treturn 0;\n+}\n+\n+static bool\n+nfp_elf_check_sh_size(uint64_t sh_size)\n+{\n+\tif (sh_size == 0 || sh_size > UINT32_MAX)\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n+static const char *\n+nfp_elf_fwinfo_next(struct nfp_elf *ectx,\n+\t\tconst char *key_val)\n+{\n+\tsize_t s_len;\n+\tconst char *strtab = ectx->fw_info_strtab;\n+\tssize_t tab_sz = (ssize_t)ectx->fw_info_strtab_sz;\n+\n+\tif (key_val == NULL)\n+\t\treturn strtab;\n+\n+\ts_len = strlen(key_val);\n+\tif (key_val < strtab || ((key_val + s_len + 1) >= (strtab + tab_sz - 1)))\n+\t\treturn NULL;\n+\n+\tkey_val += s_len + 1;\n+\n+\treturn key_val;\n+}\n+\n+static const char *\n+nfp_elf_fwinfo_lookup(struct nfp_elf *ectx,\n+\t\tconst char *key)\n+{\n+\tsize_t s_len;\n+\tconst char *s;\n+\tsize_t key_len = strlen(key);\n+\tconst char *strtab = ectx->fw_info_strtab;\n+\tssize_t tab_sz = (ssize_t)ectx->fw_info_strtab_sz;\n+\n+\tif (strtab == NULL)\n+\t\treturn NULL;\n+\n+\tfor (s = strtab, s_len = strlen(s) + 1;\n+\t\t\t(s[0] != '\\0') && (tab_sz > 0);\n+\t\t\ts_len = strlen(s) + 1, tab_sz -= s_len, s += s_len) {\n+\t\tif ((strncmp(s, key, key_len) == 0) && (s[key_len] == '='))\n+\t\t\treturn &s[key_len + 1];\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static bool\n+nfp_elf_arch_is_thornham(struct nfp_elf *ectx)\n+{\n+\tif (ectx == NULL)\n+\t\treturn false;\n+\n+\tif (ectx->family == NFP_CHIP_FAMILY_NFP6000 || ectx->family == NFP_CHIP_FAMILY_NFP3800)\n+\t\treturn true;\n+\n+\treturn false;\n+}\n+\n+static int\n+nfp_elf_parse_sht_rel(struct nfp_elf_elf64_shdr *sec,\n+\t\tstruct nfp_elf *ectx,\n+\t\tsize_t idx,\n+\t\tuint8_t *buf8)\n+{\n+\tuint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);\n+\tuint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);\n+\tuint64_t sh_entsize = rte_le_to_cpu_64(sec->sh_entsize);\n+\n+\tif (sh_entsize != sizeof(struct nfp_elf_elf64_rel)) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid ELF section header, index %zu.\", idx);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!nfp_elf_check_sh_size(sh_size)) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid ELF section header, index %zu.\", idx);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tectx->shdrs_data[idx] = buf8 + sh_offset;\n+\tectx->shdrs_host_endian[idx] = 1;\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_elf_parse_note_name_nfp(struct nfp_elf *ectx,\n+\t\tsize_t idx,\n+\t\tuint32_t ndescsz,\n+\t\tuint32_t ntype,\n+\t\tconst char *nname,\n+\t\trte_le32_t *descword)\n+{\n+\tif (strncmp(nname, NFP_ELT_NOTE_NAME_NFP, NFP_ELT_NOTE_NAME_NFP_SZ) == 0) {\n+\t\tswitch (ntype) {\n+\t\tcase NFP_ELF_NT_NFP_REVS:\n+\t\t\tif (ndescsz != 8) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Invalid ELF NOTE descsz in section %zu.\", idx);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\n+\t\t\tectx->rev_min = (int)rte_le_to_cpu_32(descword[0]);\n+\t\t\tectx->rev_max = (int)rte_le_to_cpu_32(descword[1]);\n+\t\t\tbreak;\n+\t\tcase NFP_ELF_NT_NFP_MIP_LOCATION:\n+\t\t\tif (ndescsz != 12) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Invalid ELF NOTE descsz in section %zu.\", idx);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\n+\t\t\tectx->mip_shndx = rte_le_to_cpu_32(descword[0]);\n+\t\t\tif (ectx->mip_shndx == 0) {\n+\t\t\t\tectx->mip_sh_off = 0;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tif (ectx->mip_shndx >= ectx->shdrs_cnt) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Invalid ELF NOTE shndx in section %zu.\", idx);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\n+\t\t\tectx->mip_sh_off = rte_le_to_cpu_32(descword[1]) |\n+\t\t\t\t\t(uint64_t)rte_le_to_cpu_32(descword[2]) << 32;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t} else if (strncmp(nname, NFP_ELT_NOTE_NAME_NFP_USER,\n+\t\t\tNFP_ELT_NOTE_NAME_NFP_USER_SZ) == 0 && ntype == NFP_ELF_NT_NFP_USER) {\n+\t\tectx->user_note_cnt++;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_elf_parse_sht_note(struct nfp_elf_elf64_shdr *sec,\n+\t\tstruct nfp_elf *ectx,\n+\t\tsize_t idx,\n+\t\tuint8_t *buf8)\n+{\n+\tint err;\n+\tsize_t nsz;\n+\tuint8_t *desc;\n+\tuint32_t ntype;\n+\tuint32_t nnamesz;\n+\tuint32_t ndescsz;\n+\tconst char *nname;\n+\tuint8_t *shdrs_data;\n+\trte_le32_t *descword;\n+\tstruct nfp_elf_elf64_nhdr *nhdr;\n+\tstruct nfp_elf_user_note *unote;\n+\tuint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);\n+\tuint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);\n+\n+\tif (!nfp_elf_check_sh_size(sh_size)) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid ELF section header, index %zu.\", idx);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tshdrs_data = buf8 + sh_offset;\n+\tectx->shdrs_data[idx] = shdrs_data;\n+\tectx->shdrs_host_endian[idx] = 0;\n+\n+\t/* Extract notes that we recognise */\n+\tnhdr = (struct nfp_elf_elf64_nhdr *)shdrs_data;\n+\n+\twhile ((uint8_t *)nhdr < (shdrs_data + sh_size)) {\n+\t\tnnamesz  = rte_le_to_cpu_32(nhdr->n_namesz);\n+\t\tndescsz  = rte_le_to_cpu_32(nhdr->n_descsz);\n+\t\tntype    = rte_le_to_cpu_32(nhdr->n_type);\n+\t\tnname    = (const char *)((uint8_t *)nhdr + sizeof(*nhdr));\n+\t\tdescword = (rte_le32_t *)((uint8_t *)nhdr + sizeof(*nhdr) +\n+\t\t\t\t((nnamesz + UINT32_C(3)) & ~UINT32_C(3)));\n+\n+\t\terr = nfp_elf_parse_note_name_nfp(ectx, idx, ndescsz, ntype, nname, descword);\n+\t\tif (err != 0)\n+\t\t\treturn err;\n+\n+\t\tnhdr = (struct nfp_elf_elf64_nhdr *)((uint8_t *)descword +\n+\t\t\t\t((ndescsz + UINT32_C(3)) & ~UINT32_C(3)));\n+\t}\n+\n+\tif (ectx->user_note_cnt == 0)\n+\t\treturn 0;\n+\n+\tectx->user_notes = calloc(ectx->user_note_cnt, sizeof(*ectx->user_notes));\n+\tif (ectx->user_notes == NULL) {\n+\t\tPMD_DRV_LOG(ERR, \"Out of memory.\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tnhdr = (struct nfp_elf_elf64_nhdr *)shdrs_data;\n+\tunote = ectx->user_notes;\n+\twhile ((uint8_t *)nhdr < (shdrs_data + sh_size)) {\n+\t\tnnamesz = rte_le_to_cpu_32(nhdr->n_namesz);\n+\t\tndescsz = rte_le_to_cpu_32(nhdr->n_descsz);\n+\t\tntype   = rte_le_to_cpu_32(nhdr->n_type);\n+\t\tnname   = (const char *)((uint8_t *)nhdr + sizeof(*nhdr));\n+\t\tdesc    = (uint8_t *)nhdr + sizeof(*nhdr) +\n+\t\t\t\t((nnamesz + UINT32_C(3)) & ~UINT32_C(3));\n+\n+\t\tif (strncmp(nname, NFP_ELT_NOTE_NAME_NFP_USER,\n+\t\t\t\tNFP_ELT_NOTE_NAME_NFP_USER_SZ) != 0)\n+\t\t\tcontinue;\n+\n+\t\tif (ntype != NFP_ELF_NT_NFP_USER)\n+\t\t\tcontinue;\n+\n+\t\tunote->name = (const char *)desc;\n+\t\tnsz = strlen(unote->name) + 1;\n+\t\tif (nsz % 4 != 0)\n+\t\t\tnsz = ((nsz / 4) + 1) * 4;\n+\t\tif (nsz > ndescsz) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Invalid ELF USER NOTE descsz in section %zu.\", idx);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tunote->data_sz = ndescsz - (uint32_t)nsz;\n+\t\tif (unote->data_sz != 0)\n+\t\t\tunote->data = desc + nsz;\n+\t\tunote++;\n+\n+\t\tnhdr = (struct nfp_elf_elf64_nhdr *)\n+\t\t\t\t(desc + ((ndescsz + UINT32_C(3)) & ~UINT32_C(3)));\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_elf_parse_sht_meconfig(struct nfp_elf_elf64_shdr *sec,\n+\t\tstruct nfp_elf *ectx,\n+\t\tsize_t idx,\n+\t\tuint8_t *buf8)\n+{\n+\tsize_t ent_cnt;\n+\tuint8_t *shdrs_data;\n+\tuint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);\n+\tuint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);\n+\n+\tif (!nfp_elf_check_sh_size(sh_size)) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid ELF section header, index %zu.\", idx);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tshdrs_data = buf8 + sh_offset;\n+\tent_cnt = nfp_elf_get_sec_ent_cnt(ectx, idx);\n+\tectx->shdrs_data[idx] = shdrs_data;\n+\tectx->meconfs = (struct nfp_elf_elf_meconfig *)shdrs_data;\n+\tectx->meconfs_cnt = ent_cnt;\n+\tectx->shdrs_host_endian[idx] = 1;\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_elf_parse_sht_initreg(struct nfp_elf_elf64_shdr *sec,\n+\t\tstruct nfp_elf *ectx,\n+\t\tsize_t idx,\n+\t\tuint8_t *buf8)\n+{\n+\tuint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);\n+\tuint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);\n+\tuint64_t sh_entsize = rte_le_to_cpu_64(sec->sh_entsize);\n+\n+\tif (!nfp_elf_arch_is_thornham(ectx)) {\n+\t\tPMD_DRV_LOG(ERR, \"Section not supported for target arch.\");\n+\t\treturn -ENOTSUP;\n+\t}\n+\n+\tif (sh_entsize != sizeof(struct nfp_elf_elf_initregentry) ||\n+\t\t\t!nfp_elf_check_sh_size(sh_size)) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid ELF section header, index %zu.\", idx);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tectx->shdrs_data[idx] = buf8 + sh_offset;\n+\tectx->shdrs_host_endian[idx] = 1;\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_elf_parse_sht_symtab(struct nfp_elf_elf64_shdr *sec,\n+\t\tstruct nfp_elf *ectx,\n+\t\tsize_t idx,\n+\t\tuint8_t *buf8)\n+{\n+\tuint64_t sh_size = rte_le_to_cpu_64(sec->sh_size);\n+\tuint64_t sh_offset = rte_le_to_cpu_64(sec->sh_offset);\n+\tuint64_t sh_entsize = rte_le_to_cpu_64(sec->sh_entsize);\n+\n+\tif (sh_entsize != sizeof(struct nfp_elf_elf64_sym) ||\n+\t\t\t!nfp_elf_check_sh_size(sh_size)) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid ELF section header, index %zu.\", idx);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tectx->shdrs_data[idx] = buf8 + sh_offset;\n+\tectx->shdrs_host_endian[ectx->shdr_idx_symtab] = 1;\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_elf_populate_fw_mip(struct nfp_elf *ectx,\n+\t\tuint8_t *buf8)\n+{\n+\tuint8_t *pu8;\n+\tconst char *nx;\n+\tuint64_t sh_size;\n+\tuint64_t sh_offset;\n+\tuint32_t first_entry;\n+\tconst struct nfp_mip *mip;\n+\tstruct nfp_elf_elf64_shdr *sec;\n+\tconst struct nfp_mip_entry *ent;\n+\tconst struct nfp_mip_fwinfo_entry *fwinfo;\n+\n+\tsec = &ectx->shdrs[ectx->mip_shndx];\n+\tsh_size = rte_le_to_cpu_64(sec->sh_size);\n+\tsh_offset = rte_le_to_cpu_64(sec->sh_offset);\n+\tpu8 = buf8 + sh_offset + ectx->mip_sh_off;\n+\tmip = (const struct nfp_mip *)pu8;\n+\tfirst_entry = rte_le_to_cpu_32(mip->first_entry);\n+\n+\tif (mip->signature != NFP_MIP_SIGNATURE) {\n+\t\tPMD_DRV_LOG(ERR, \"Incorrect MIP signature %#08x\",\n+\t\t\t\trte_le_to_cpu_32(mip->signature));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tectx->fw_mip.shndx = ectx->mip_shndx;\n+\tectx->fw_mip.sh_offset = ectx->mip_sh_off;\n+\tectx->fw_mip.mip_ver = mip->mip_version;\n+\n+\tif (ectx->fw_mip.mip_ver != NFP_MIP_VERSION) {\n+\t\tPMD_DRV_LOG(ERR, \"MIP note pointer does not point to recognised version.\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tectx->fw_mip.fw_version   = mip->version;\n+\tectx->fw_mip.fw_buildnum  = mip->buildnum;\n+\tectx->fw_mip.fw_buildtime = mip->buildtime;\n+\tstrncpy(ectx->fw_mip.fw_name, mip->name, 16);\n+\n+\t/*\n+\t * If there is a FWINFO v1 entry, it will be first and\n+\t * right after the MIP itself, so in the same section.\n+\t */\n+\tif (ectx->mip_sh_off + first_entry + sizeof(*ent) < sh_size) {\n+\t\tpu8 += first_entry;\n+\t\tent = (const struct nfp_mip_entry *)pu8;\n+\t\tif (ent->type == NFP_MIP_TYPE_FWINFO && ent->version == 1) {\n+\t\t\tpu8 += sizeof(*ent);\n+\t\t\tfwinfo = (const struct nfp_mip_fwinfo_entry *)pu8;\n+\t\t\tif (fwinfo->kv_len != 0) {\n+\t\t\t\tectx->fw_info_strtab_sz = fwinfo->kv_len;\n+\t\t\t\tectx->fw_info_strtab = fwinfo->key_value_strs;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tectx->fw_mip.fw_typeid = nfp_elf_fwinfo_lookup(ectx, \"TypeId\");\n+\n+\t/*\n+\t * TypeId will be the last reserved key-value pair, so skip\n+\t * to the first entry after it for the user values.\n+\t */\n+\tif (ectx->fw_mip.fw_typeid == NULL)\n+\t\treturn 0;\n+\n+\tnx = nfp_elf_fwinfo_next(ectx, ectx->fw_mip.fw_typeid);\n+\tif (nx == NULL)\n+\t\tectx->fw_info_strtab_sz = 0;\n+\telse\n+\t\tectx->fw_info_strtab_sz -= (nx - ectx->fw_info_strtab);\n+\tectx->fw_info_strtab = nx;\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_elf_read_file_headers(struct nfp_elf *ectx,\n+\t\tvoid *buf)\n+{\n+\tuint16_t e_type;\n+\tuint32_t e_flags;\n+\tuint32_t e_version;\n+\tuint16_t e_machine;\n+\n+\tectx->ehdr = buf;\n+\te_type = rte_le_to_cpu_16(ectx->ehdr->e_type);\n+\te_flags = rte_le_to_cpu_32(ectx->ehdr->e_flags);\n+\te_version = rte_le_to_cpu_32(ectx->ehdr->e_version);\n+\te_machine = rte_le_to_cpu_16(ectx->ehdr->e_machine);\n+\n+\tswitch (e_machine) {\n+\tcase NFP_ELF_EM_NFP:\n+\t\tectx->family = (e_flags >> NFP_ELF_EF_NFP_FAMILY_LSB)\n+\t\t\t\t& NFP_ELF_EF_NFP_FAMILY_MASK;\n+\t\tbreak;\n+\tcase NFP_ELF_EM_NFP6000:\n+\t\tectx->family = NFP_CHIP_FAMILY_NFP6000;\n+\t\tbreak;\n+\tdefault:\n+\t\tPMD_DRV_LOG(ERR, \"Invalid ELF machine type.\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif ((e_type != NFP_ELF_ET_EXEC && e_type != NFP_ELF_ET_REL &&\n+\t\t\te_type != NFP_ELF_ET_NFP_PARTIAL_EXEC &&\n+\t\t\te_type != NFP_ELF_ET_NFP_PARTIAL_REL) ||\n+\t\t\te_version != NFP_ELF_EV_CURRENT ||\n+\t\t\tectx->ehdr->e_ehsize != sizeof(struct nfp_elf_elf64_ehdr) ||\n+\t\t\tectx->ehdr->e_shentsize != sizeof(struct nfp_elf_elf64_shdr)) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid ELF file header.\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ectx->ehdr->e_shoff < ectx->ehdr->e_ehsize) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid ELF header content.\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ectx->ehdr->e_shstrndx >= ectx->ehdr->e_shnum) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid ELF header content.\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_elf_read_section_headers(struct nfp_elf *ectx,\n+\t\tuint8_t *buf8,\n+\t\tsize_t buf_len)\n+{\n+\tsize_t idx;\n+\tint err = 0;\n+\tuint8_t *pu8;\n+\tuint64_t sh_size;\n+\tuint64_t sh_offset;\n+\tuint64_t sh_entsize;\n+\tstruct nfp_elf_elf64_shdr *sec;\n+\tuint64_t e_shoff = rte_le_to_cpu_16(ectx->ehdr->e_shoff);\n+\tuint16_t e_shnum = rte_le_to_cpu_16(ectx->ehdr->e_shnum);\n+\n+\tif (buf_len < e_shoff + ((size_t)e_shnum * sizeof(*sec))) {\n+\t\tPMD_DRV_LOG(ERR, \"ELF data too short.\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tpu8 = buf8 + e_shoff;\n+\n+\tif (e_shnum == 0) {\n+\t\tectx->shdrs = NULL;\n+\t\tectx->shdrs_data = NULL;\n+\t\tectx->shdrs_host_endian = NULL;\n+\t\tectx->shdrs_cnt = 0;\n+\t\treturn 0;\n+\t}\n+\n+\tectx->shdrs = calloc(e_shnum, sizeof(*ectx->shdrs));\n+\tif (ectx->shdrs == NULL) {\n+\t\tPMD_DRV_LOG(ERR, \"Out of memory.\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tectx->shdrs_data = calloc(e_shnum, sizeof(void *));\n+\tif (ectx->shdrs_data == NULL) {\n+\t\tPMD_DRV_LOG(ERR, \"Out of memory.\");\n+\t\terr = -ENOMEM;\n+\t\tgoto free_shdrs;\n+\t}\n+\n+\tectx->shdrs_host_endian = calloc(e_shnum, sizeof(ectx->shdrs_host_endian[0]));\n+\tif (ectx->shdrs_host_endian == NULL) {\n+\t\tPMD_DRV_LOG(ERR, \"Out of memory.\");\n+\t\terr = -ENOMEM;\n+\t\tgoto free_shdrs_data;\n+\t}\n+\n+\tmemcpy(ectx->shdrs, pu8, e_shnum * sizeof(*ectx->shdrs));\n+\tectx->shdrs_cnt = e_shnum;\n+\n+\tfor (idx = 0, sec = ectx->shdrs; idx < ectx->shdrs_cnt; idx++, sec++) {\n+\t\tsh_size = rte_le_to_cpu_64(sec->sh_size);\n+\t\tsh_offset = rte_le_to_cpu_64(sec->sh_offset);\n+\t\tsh_entsize = rte_le_to_cpu_64(sec->sh_entsize);\n+\n+\t\tif (sh_entsize != 0 && (sh_size % sh_entsize != 0)) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Invalid ELF section header, index %zu.\", idx);\n+\t\t\terr = -EINVAL;\n+\t\t\tgoto free_shdrs_host_endian;\n+\t\t}\n+\n+\t\tswitch (rte_le_to_cpu_32(sec->sh_type)) {\n+\t\tcase NFP_ELF_SHT_REL:\n+\t\t\terr = nfp_elf_parse_sht_rel(sec, ectx, idx, buf8);\n+\t\t\tif (err != 0) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Failed to parse sht rel.\");\n+\t\t\t\tgoto free_shdrs_host_endian;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase NFP_ELF_SHT_NOTE:\n+\t\t\terr = nfp_elf_parse_sht_note(sec, ectx, idx, buf8);\n+\t\t\tif (err != 0) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Failed to parse sht note.\");\n+\t\t\t\tgoto free_shdrs_host_endian;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase NFP_ELF_SHT_NFP_MECONFIG:\n+\t\t\terr = nfp_elf_parse_sht_meconfig(sec, ectx, idx, buf8);\n+\t\t\tif (err != 0) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Failed to parse sht meconfig.\");\n+\t\t\t\tgoto free_shdrs_host_endian;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase NFP_ELF_SHT_NFP_INITREG:\n+\t\t\terr = nfp_elf_parse_sht_initreg(sec, ectx, idx, buf8);\n+\t\t\tif (err != 0) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Failed to parse sht initregp.\");\n+\t\t\t\tgoto free_shdrs_host_endian;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase NFP_ELF_SHT_SYMTAB:\n+\t\t\terr = nfp_elf_parse_sht_symtab(sec, ectx, idx, buf8);\n+\t\t\tif (err != 0) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Failed to parse sht symtab.\");\n+\t\t\t\tgoto free_shdrs_host_endian;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase NFP_ELF_SHT_NOBITS:\n+\t\tcase NFP_ELF_SHT_NULL:\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tif (sh_offset > 0 && sh_size <= 0)\n+\t\t\t\tbreak;\n+\n+\t\t\t/*\n+\t\t\t * Limit sections to 4GiB, because they won't need to be this large\n+\t\t\t * and this ensures we can handle the file on 32-bit hosts without\n+\t\t\t * unexpected problems.\n+\t\t\t */\n+\t\t\tif (sh_size > UINT32_MAX) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Invalid ELF section header, index %zu.\", idx);\n+\t\t\t\terr = -EINVAL;\n+\t\t\t\tgoto free_shdrs_host_endian;\n+\t\t\t}\n+\n+\t\t\tpu8 = buf8 + sh_offset;\n+\t\t\tectx->shdrs_data[idx] = pu8;\n+\t\t\tectx->shdrs_host_endian[idx] = 0;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+\n+free_shdrs_host_endian:\n+\tfree(ectx->shdrs_host_endian);\n+free_shdrs_data:\n+\tfree(ectx->shdrs_data);\n+free_shdrs:\n+\tfree(ectx->shdrs);\n+\n+\treturn err;\n+}\n+\n+static int\n+nfp_elf_read_shstrtab(struct nfp_elf *ectx)\n+{\n+\tstruct nfp_elf_elf64_shdr *sec;\n+\tuint16_t e_shstrndx = rte_le_to_cpu_16(ectx->ehdr->e_shstrndx);\n+\n+\tif (ectx->ehdr->e_shnum <= ectx->ehdr->e_shstrndx) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid Index.\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsec = &ectx->shdrs[e_shstrndx];\n+\tif (sec == NULL || rte_le_to_cpu_32(sec->sh_type) != NFP_ELF_SHT_STRTAB) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid ELF shstrtab.\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tectx->shstrtab = ectx->shdrs_data[e_shstrndx];\n+\tectx->shstrtab_sz = rte_le_to_cpu_64(sec->sh_size);\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_elf_read_first_symtab(struct nfp_elf *ectx)\n+{\n+\tsize_t idx;\n+\tuint32_t sh_type;\n+\tuint64_t sh_size;\n+\tstruct nfp_elf_elf64_shdr *sec;\n+\n+\tfor (idx = 0, sec = ectx->shdrs; idx < ectx->shdrs_cnt; idx++, sec++) {\n+\t\tif (sec != NULL) {\n+\t\t\tsh_type = rte_le_to_cpu_32(sec->sh_type);\n+\t\t\tif (sh_type == NFP_ELF_SHT_SYMTAB)\n+\t\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tsh_size = rte_le_to_cpu_64(sec->sh_size);\n+\n+\tif (idx < ectx->shdrs_cnt && sh_type == NFP_ELF_SHT_SYMTAB) {\n+\t\tectx->shdr_idx_symtab = idx;\n+\t\tectx->syms = ectx->shdrs_data[idx];\n+\t\tectx->syms_cnt = nfp_elf_get_sec_ent_cnt(ectx, idx);\n+\n+\t\t/* Load symtab's strtab */\n+\t\tidx = rte_le_to_cpu_32(sec->sh_link);\n+\n+\t\tif (idx == NFP_ELF_SHN_UNDEF || idx >= ectx->shdrs_cnt) {\n+\t\t\tPMD_DRV_LOG(ERR, \"ELF symtab has no strtab.\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tsec = &ectx->shdrs[idx];\n+\t\tsh_type = rte_le_to_cpu_32(sec->sh_type);\n+\t\tif (sh_type != NFP_ELF_SHT_STRTAB) {\n+\t\t\tPMD_DRV_LOG(ERR, \"ELF symtab has no strtab.\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tif (!nfp_elf_check_sh_size(sh_size)) {\n+\t\t\tPMD_DRV_LOG(ERR, \"ELF symtab has invalid strtab.\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tectx->symstrtab = ectx->shdrs_data[idx];\n+\t\tectx->symstrtab_sz = sh_size;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_elf_is_valid_file(uint8_t *buf8)\n+{\n+\tif (buf8[NFP_ELF_EI_MAG0] != NFP_ELF_ELFMAG0 ||\n+\t\t\tbuf8[NFP_ELF_EI_MAG1] != NFP_ELF_ELFMAG1 ||\n+\t\t\tbuf8[NFP_ELF_EI_MAG2] != NFP_ELF_ELFMAG2 ||\n+\t\t\tbuf8[NFP_ELF_EI_MAG3] != NFP_ELF_ELFMAG3 ||\n+\t\t\tbuf8[NFP_ELF_EI_VERSION] != NFP_ELF_EV_CURRENT ||\n+\t\t\tbuf8[NFP_ELF_EI_DATA] != NFP_ELF_ELFDATA2LSB)\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_elf_is_valid_class(uint8_t *buf8)\n+{\n+\tif (buf8[NFP_ELF_EI_CLASS] != NFP_ELF_ELFCLASS64)\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n+static struct nfp_elf *\n+nfp_elf_mutable_buf(void *buf,\n+\t\tsize_t buf_len)\n+{\n+\tint err = 0;\n+\tuint8_t *buf8 = buf;\n+\tstruct nfp_elf *ectx;\n+\n+\tif (buf == NULL) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid parameters.\");\n+\t\treturn NULL;\n+\t}\n+\n+\tif (buf_len < sizeof(struct nfp_elf_elf64_ehdr)) {\n+\t\tPMD_DRV_LOG(ERR, \"ELF data too short.\");\n+\t\treturn NULL;\n+\t}\n+\n+\tectx = calloc(1, sizeof(struct nfp_elf));\n+\tif (ectx == NULL) {\n+\t\tPMD_DRV_LOG(ERR, \"Out of memory.\");\n+\t\treturn NULL;\n+\t}\n+\n+\tectx->rev_min = -1;\n+\tectx->rev_max = -1;\n+\tectx->mip_sh_off = UINT64_MAX;\n+\n+\terr = nfp_elf_is_valid_file(buf8);\n+\tif (err != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Not a valid ELF file.\");\n+\t\tgoto elf_free;\n+\t}\n+\n+\terr = nfp_elf_is_valid_class(buf8);\n+\tif (err != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Unknown ELF class.\");\n+\t\tgoto elf_free;\n+\t}\n+\n+\terr = nfp_elf_read_file_headers(ectx, buf);\n+\tif (err != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to read file headers.\");\n+\t\tgoto elf_free;\n+\t}\n+\n+\terr = nfp_elf_read_section_headers(ectx, buf8, buf_len);\n+\tif (err != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to read section headers.\");\n+\t\tgoto elf_free;\n+\t}\n+\n+\terr = nfp_elf_read_shstrtab(ectx);\n+\tif (err != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to read shstrtab.\");\n+\t\tgoto elf_free;\n+\t}\n+\n+\t/* Read first symtab if any, assuming it's the primary or only one */\n+\terr = nfp_elf_read_first_symtab(ectx);\n+\tif (err != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to read first symtab.\");\n+\t\tgoto elf_free;\n+\t}\n+\n+\t/* Populate the fw_mip struct if we have a .note for it */\n+\tif (ectx->mip_shndx != 0) {\n+\t\terr = nfp_elf_populate_fw_mip(ectx, buf8);\n+\t\tif (err != 0) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Failed to populate the fw mip.\");\n+\t\t\tgoto elf_free;\n+\t\t}\n+\t}\n+\n+\tectx->_buf = buf;\n+\tectx->_bufsz = 0;\n+\n+\treturn ectx;\n+\n+elf_free:\n+\tnfp_elf_free(ectx);\n+\n+\treturn NULL;\n+}\n+\n+int\n+nfp_elf_get_fw_version(uint32_t *fw_version,\n+\t\tchar *fw_name)\n+{\n+\tvoid *fw_buf;\n+\tsize_t fsize;\n+\tstruct nfp_elf *elf;\n+\n+\tif (rte_firmware_read(fw_name, &fw_buf, &fsize) != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"firmware %s not found!\", fw_name);\n+\t\treturn -ENOENT;\n+\t}\n+\n+\telf = nfp_elf_mutable_buf(fw_buf, fsize);\n+\tif (elf == NULL) {\n+\t\tPMD_DRV_LOG(ERR, \"Parse nffw file failed.\");\n+\t\tfree(fw_buf);\n+\t\treturn -EIO;\n+\t}\n+\n+\t*fw_version = rte_le_to_cpu_32(elf->fw_mip.fw_version);\n+\n+\tnfp_elf_free(elf);\n+\tfree(fw_buf);\n+\treturn 0;\n+}\n+\ndiff --git a/drivers/net/nfp/nfpcore/nfp_elf.h b/drivers/net/nfp/nfpcore/nfp_elf.h\nnew file mode 100644\nindex 0000000000..4081af6f01\n--- /dev/null\n+++ b/drivers/net/nfp/nfpcore/nfp_elf.h\n@@ -0,0 +1,13 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2023 Corigine, Inc.\n+ * All rights reserved.\n+ */\n+\n+#ifndef __NFP_ELF_H__\n+#define __NFP_ELF_H__\n+\n+#include <stdint.h>\n+\n+int nfp_elf_get_fw_version(uint32_t *fw_version, char *fw_name);\n+\n+#endif /* __NFP_ELF_H__ */\ndiff --git a/drivers/net/nfp/nfpcore/nfp_mip.c b/drivers/net/nfp/nfpcore/nfp_mip.c\nindex d5ada3687a..98d1d19047 100644\n--- a/drivers/net/nfp/nfpcore/nfp_mip.c\n+++ b/drivers/net/nfp/nfpcore/nfp_mip.c\n@@ -10,30 +10,6 @@\n #include \"nfp_logs.h\"\n #include \"nfp_nffw.h\"\n \n-#define NFP_MIP_SIGNATURE        rte_cpu_to_le_32(0x0050494d)  /* \"MIP\\0\" */\n-#define NFP_MIP_VERSION          rte_cpu_to_le_32(1)\n-#define NFP_MIP_MAX_OFFSET       (256 * 1024)\n-\n-struct nfp_mip {\n-\tuint32_t signature;\n-\tuint32_t mip_version;\n-\tuint32_t mip_size;\n-\tuint32_t first_entry;\n-\n-\tuint32_t version;\n-\tuint32_t buildnum;\n-\tuint32_t buildtime;\n-\tuint32_t loadtime;\n-\n-\tuint32_t symtab_addr;\n-\tuint32_t symtab_size;\n-\tuint32_t strtab_addr;\n-\tuint32_t strtab_size;\n-\n-\tchar name[16];\n-\tchar toolchain[32];\n-};\n-\n /* Read memory and check if it could be a valid MIP */\n static int\n nfp_mip_try_read(struct nfp_cpp *cpp,\n@@ -134,6 +110,12 @@ nfp_mip_name(const struct nfp_mip *mip)\n \treturn mip->name;\n }\n \n+uint32_t\n+nfp_mip_fw_version(const struct nfp_mip *mip)\n+{\n+\treturn rte_le_to_cpu_32(mip->version);\n+}\n+\n /**\n  * Get the address and size of the MIP symbol table.\n  *\ndiff --git a/drivers/net/nfp/nfpcore/nfp_mip.h b/drivers/net/nfp/nfpcore/nfp_mip.h\nindex dbd9af31ed..411fe413d7 100644\n--- a/drivers/net/nfp/nfpcore/nfp_mip.h\n+++ b/drivers/net/nfp/nfpcore/nfp_mip.h\n@@ -8,12 +8,80 @@\n \n #include \"nfp_cpp.h\"\n \n-struct nfp_mip;\n+/* \"MIP\\0\" */\n+#define NFP_MIP_SIGNATURE        rte_cpu_to_le_32(0x0050494d)\n+#define NFP_MIP_VERSION          rte_cpu_to_le_32(1)\n+\n+/* nfp_mip_entry_type */\n+#define NFP_MIP_TYPE_FWINFO      0x70000002\n+\n+/* Each packed struct field is stored as Little Endian */\n+struct nfp_mip {\n+\trte_le32_t signature;\n+\trte_le32_t mip_version;\n+\n+\trte_le32_t mip_size;\n+\trte_le32_t first_entry;\n+\n+\trte_le32_t version;\n+\trte_le32_t buildnum;\n+\trte_le32_t buildtime;\n+\trte_le32_t loadtime;\n+\n+\trte_le32_t symtab_addr;\n+\trte_le32_t symtab_size;\n+\trte_le32_t strtab_addr;\n+\trte_le32_t strtab_size;\n+\n+\tchar name[16];\n+\tchar toolchain[32];\n+};\n+\n+struct nfp_mip_entry {\n+\tuint32_t type;\n+\tuint32_t version;\n+\tuint32_t offset_next;\n+};\n+\n+/*\n+ * A key-value pair has no imposed limit, but it is recommended that\n+ * consumers only allocate enough memory for keys they plan to process and\n+ * skip over unused keys or ignore values that are longer than expected.\n+ *\n+ * For MIPv1, this will be preceded by struct nfp_mip_entry.\n+ * The entry size will be the size of key_value_strs, round to the next\n+ * 4-byte multiple. If entry size is 0, then there are no key-value strings\n+ * and it will not contain an empty string.\n+ *\n+ * The following keys are reserved and possibly set by the linker. The\n+ * convention is to start linker-set keys with a capital letter. Reserved\n+ * entries will be placed first in key_value_strs, user entries will be\n+ * placed next and be sorted alphabetically.\n+ * TypeId - Present if a user specified fw_typeid when linking.\n+ *\n+ * The following keys are reserved, but not used. Their values are in the\n+ * root MIP struct.\n+ */\n+struct nfp_mip_fwinfo_entry {\n+\t/** The byte size of @p key_value_strs. */\n+\tuint32_t kv_len;\n+\n+\t/** The number of key-value pairs in the following string. */\n+\tuint32_t num;\n+\n+\t/**\n+\t * A series of NUL terminated strings, terminated by an extra\n+\t * NUL which is also the last byte of the entry, so an iterator\n+\t * can either check on size or when key[0] == '\\0'.\n+\t */\n+\tchar key_value_strs[];\n+};\n \n struct nfp_mip *nfp_mip_open(struct nfp_cpp *cpp);\n void nfp_mip_close(struct nfp_mip *mip);\n \n const char *nfp_mip_name(const struct nfp_mip *mip);\n+uint32_t nfp_mip_fw_version(const struct nfp_mip *mip);\n void nfp_mip_symtab(const struct nfp_mip *mip, uint32_t *addr, uint32_t *size);\n void nfp_mip_strtab(const struct nfp_mip *mip, uint32_t *addr, uint32_t *size);\n \n",
    "prefixes": [
        "v2",
        "1/3"
    ]
}