get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 128267,
    "url": "http://patches.dpdk.org/api/patches/128267/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20230607042425.30714-2-nipun.gupta@amd.com/",
    "project": {
        "id": 1,
        "url": "http://patches.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": "<20230607042425.30714-2-nipun.gupta@amd.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20230607042425.30714-2-nipun.gupta@amd.com",
    "date": "2023-06-07T04:24:22",
    "name": "[v8,1/4] bus/cdx: introduce AMD CDX bus",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "101a95fbd668e466bca7c17874e56e2ad175d111",
    "submitter": {
        "id": 2928,
        "url": "http://patches.dpdk.org/api/people/2928/?format=api",
        "name": "Gupta, Nipun",
        "email": "nipun.gupta@amd.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20230607042425.30714-2-nipun.gupta@amd.com/mbox/",
    "series": [
        {
            "id": 28384,
            "url": "http://patches.dpdk.org/api/series/28384/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=28384",
            "date": "2023-06-07T04:24:21",
            "name": "Support AMD CDX bus",
            "version": 8,
            "mbox": "http://patches.dpdk.org/series/28384/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/128267/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/128267/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 B0E3242C46;\n\tWed,  7 Jun 2023 06:24:48 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 9B312427F5;\n\tWed,  7 Jun 2023 06:24:48 +0200 (CEST)",
            "from NAM10-DM6-obe.outbound.protection.outlook.com\n (mail-dm6nam10on2072.outbound.protection.outlook.com [40.107.93.72])\n by mails.dpdk.org (Postfix) with ESMTP id A2DE840A84\n for <dev@dpdk.org>; Wed,  7 Jun 2023 06:24:47 +0200 (CEST)",
            "from CYXPR02CA0006.namprd02.prod.outlook.com (2603:10b6:930:cf::10)\n by DS7PR12MB8323.namprd12.prod.outlook.com (2603:10b6:8:da::7) with\n Microsoft\n SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.20.6477.19; Wed, 7 Jun 2023 04:24:44 +0000",
            "from CY4PEPF0000E9D2.namprd03.prod.outlook.com\n (2603:10b6:930:cf:cafe::90) by CYXPR02CA0006.outlook.office365.com\n (2603:10b6:930:cf::10) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6455.34 via Frontend\n Transport; Wed, 7 Jun 2023 04:24:44 +0000",
            "from SATLEXMB04.amd.com (165.204.84.17) by\n CY4PEPF0000E9D2.mail.protection.outlook.com (10.167.241.145) with Microsoft\n SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id\n 15.20.6477.13 via Frontend Transport; Wed, 7 Jun 2023 04:24:44 +0000",
            "from SATLEXMB06.amd.com (10.181.40.147) by SATLEXMB04.amd.com\n (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.34; Tue, 6 Jun\n 2023 23:24:43 -0500",
            "from SATLEXMB04.amd.com (10.181.40.145) by SATLEXMB06.amd.com\n (10.181.40.147) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.34; Tue, 6 Jun\n 2023 23:24:43 -0500",
            "from xhdipdslab41.xilinx.com (10.180.168.240) by SATLEXMB04.amd.com\n (10.181.40.145) with Microsoft SMTP Server id 15.1.2375.34 via\n Frontend Transport; Tue, 6 Jun 2023 23:24:40 -0500"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=lLjeNUacFt9k52JmhCa2EtJS5lW7zNPDCrtrGEfCeafpe3w6xhgBPx7fCiBPLYdklujKzXKyhpg1Y5esoVvebJSjnUQCARm6gniYm99eu4VT89Cl7qZ7+4bfi+Uf6alx1GTWOhIRHm9FcOWDjzPx5J3Gzo+IlJEwA7cJxfPPk6UxHGUyoa3mDx4LkEKYay/9BilLk0TTiPALKwJLLbIrKvj01m6dL4lVkVyhzr6TlEXKSY9r5NDnQl2KYURWPQ1vSFVKmTdOOrkefjPF/pbn4QKPco2HC7SVINxvvZq6dIiijB9GEdagTTEtA/uPF3Xp6qEE53U/tiTm54KULDxDiw==",
        "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=+r1cakJoQg81VGMOOKf5U/hIJb6yqlyu6PaLUWp1Cz8=;\n b=IfHuR64OSNpK04h+IjtA2U5xRJkMDYSSDuvT0aindxv9w8DR/gfpN76SU1oKOVmQq/ANlVrUym7WJ+ekvmvQ/mVSOka2tG43U/rl16CvVNiDLrlqMfLE/NE5wH2vm+SCCuCJK+nHo3VhLrHi+G9v9F0MY7DZpOkpFEW73Gt2SfkyL85ossc7p4rAG+m1Ft+bqZFR1ML+dSXBb4NN23Zclrfm232KaaVlWgexyp/Btn6qNshwSC0jVVfccjYg62sc5Q75paf/IxALNNUT9YC31a3eceDlwj6+kqP4ltwE0/81YMRbD04qg8dhbdpmEk9e+RsYlvycx74xM+REx0RoZg==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass (sender ip is\n 165.204.84.17) smtp.rcpttodomain=dpdk.org smtp.mailfrom=amd.com; dmarc=pass\n (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com;\n dkim=none (message not signed); arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=+r1cakJoQg81VGMOOKf5U/hIJb6yqlyu6PaLUWp1Cz8=;\n b=aVfV+wrAkrSJmawgijDUXwKUsgHAXYnYRR9OUsh/bgjqMEQ4KEHSW/fmPDhWS6/EayZdf+kVia7QjIrzHAN6/T5jVJWrzgYTsckbx4PU8H9LMWU0xFJldmd8rXh83/fNcor2w26gCyy8MpBBfbfXENzZFB+ZC67KGIDMrHX56WU=",
        "X-MS-Exchange-Authentication-Results": "spf=pass (sender IP is 165.204.84.17)\n smtp.mailfrom=amd.com; dkim=none (message not signed)\n header.d=none;dmarc=pass action=none header.from=amd.com;",
        "Received-SPF": "Pass (protection.outlook.com: domain of amd.com designates\n 165.204.84.17 as permitted sender) receiver=protection.outlook.com;\n client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C",
        "From": "Nipun Gupta <nipun.gupta@amd.com>",
        "To": "<dev@dpdk.org>, <thomas@monjalon.net>, <david.marchand@redhat.com>,\n <hkalra@marvell.com>, <anatoly.burakov@intel.com>,\n <stephen@networkplumber.org>",
        "CC": "<ferruh.yigit@amd.com>, <harpreet.anand@amd.com>,\n <nikhil.agarwal@amd.com>, Nipun Gupta <nipun.gupta@amd.com>",
        "Subject": "[PATCH v8 1/4] bus/cdx: introduce AMD CDX bus",
        "Date": "Wed, 7 Jun 2023 09:54:22 +0530",
        "Message-ID": "<20230607042425.30714-2-nipun.gupta@amd.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20230607042425.30714-1-nipun.gupta@amd.com>",
        "References": "<20230124140746.594066-1-nipun.gupta@amd.com>\n <20230607042425.30714-1-nipun.gupta@amd.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-EOPAttributedMessage": "0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "CY4PEPF0000E9D2:EE_|DS7PR12MB8323:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "247ebd84-1799-4af6-529b-08db670f1ee3",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n cYjbBJYMjhisSFEiclg6DRv4/IlGgCPwpy1S1vXSliFlct7Ri91e/Ip/6J5SxCCa8qWFkSUzHN4tEOo5UntnVpWRJKBcDAujUrTMWyHBo2jSk5/diT2s3nmhH6UPWTXH+cQrul1fUHk+XtElC1fXewMsGeRIlYK92I56WG8vt9PSt6kg3JuMS8ZneSy1rcWqjgQzjWcBDjjrrpLtqZn/RHL98Z30Dsg+gcUiy3iyxmYaar2cf5N6ro77yBuBTamXWxqO0XMWrvbrPMhk2gkuqpvxu36mZmlOktuIKMKp0UZ/9d2Q2j1sEw3zZmRtnBkoQEliyp5XaWEwB+A8cYAwUH9oCh1SnpxQev5umXv/O2zZEYQwuJNA7AgDwR17SIU5iYxyoXA81fLw7LNa1nV23oYeN2WB9ZS302U50PsFX9BH8UIhoJpspicuHOe2mAWibGXCpUalQ9bk7vRkHXDUSvnk4rfmGfRHCfcbjwBQ5KEcdaoa5a83Zqh4wsQr87ZqEG9taVwIuJoeGIZvgULOSOB/AmAV5XezT3Hdux7vDU/qVmbaaMf9bnubr3CtPJ7hXcouwndgKU/ZRVH76s6wnpFGyKVGk7nuY+M9GZTZ1LkMhROm23GgHVvvCrJ+dd56ucL++w7PBu7+4Ww3zhCZmX6hz+F/GD+pcl0nk3mSkS9jaelIWhR2aNtL8gNOc8+/qT7wVO8duWg6rjEFpLLMvhN2sfq4fkgY2h1jPPQigoe5PdsSytk8q4jkEgpvSEElWTMWVWuU4d+zbC62QnbVwA==",
        "X-Forefront-Antispam-Report": "CIP:165.204.84.17; CTRY:US; LANG:en; SCL:1; SRV:;\n IPV:CAL; SFV:NSPM; H:SATLEXMB04.amd.com; PTR:InfoDomainNonexistent; CAT:NONE;\n SFS:(13230028)(4636009)(376002)(346002)(396003)(39860400002)(136003)(451199021)(46966006)(36840700001)(40470700004)(36756003)(478600001)(5660300002)(110136005)(40460700003)(54906003)(6666004)(8936002)(8676002)(316002)(4326008)(70206006)(70586007)(41300700001)(44832011)(2906002)(30864003)(81166007)(40480700001)(356005)(82740400003)(1076003)(26005)(86362001)(186003)(47076005)(2616005)(36860700001)(83380400001)(336012)(426003)(82310400005)(36900700001);\n DIR:OUT; SFP:1101;",
        "X-OriginatorOrg": "amd.com",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "07 Jun 2023 04:24:44.2348 (UTC)",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 247ebd84-1799-4af6-529b-08db670f1ee3",
        "X-MS-Exchange-CrossTenant-Id": "3dd8961f-e488-4e60-8e11-a82d994e183d",
        "X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp": "\n TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d; Ip=[165.204.84.17];\n Helo=[SATLEXMB04.amd.com]",
        "X-MS-Exchange-CrossTenant-AuthSource": "\n CY4PEPF0000E9D2.namprd03.prod.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Anonymous",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "HybridOnPrem",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DS7PR12MB8323",
        "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": "AMD CDX bus supports multiple type of devices, which can be\nexposed to user-space via vfio-cdx.\n\nvfio-cdx provides the MMIO IO_MEMORY regions as well as the\nDMA interface for the device (IOMMU).\n\nThis support aims to enable the DPDK to support the cdx\ndevices in user-space using VFIO interface.\n\nSigned-off-by: Nipun Gupta <nipun.gupta@amd.com>\nAcked-by: Ferruh Yigit <ferruh.yigit@amd.com>\n---\n MAINTAINERS                            |   5 +\n doc/guides/rel_notes/release_23_07.rst |   6 +\n drivers/bus/cdx/bus_cdx_driver.h       | 166 ++++++++\n drivers/bus/cdx/cdx.c                  | 503 +++++++++++++++++++++++++\n drivers/bus/cdx/cdx_logs.h             |  37 ++\n drivers/bus/cdx/cdx_vfio.c             | 426 +++++++++++++++++++++\n drivers/bus/cdx/meson.build            |  13 +\n drivers/bus/cdx/private.h              |  53 +++\n drivers/bus/cdx/version.map            |  10 +\n drivers/bus/meson.build                |   1 +\n 10 files changed, 1220 insertions(+)\n create mode 100644 drivers/bus/cdx/bus_cdx_driver.h\n create mode 100644 drivers/bus/cdx/cdx.c\n create mode 100644 drivers/bus/cdx/cdx_logs.h\n create mode 100644 drivers/bus/cdx/cdx_vfio.c\n create mode 100644 drivers/bus/cdx/meson.build\n create mode 100644 drivers/bus/cdx/private.h\n create mode 100644 drivers/bus/cdx/version.map",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex a5219926ab..c4b2b3565b 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -569,6 +569,11 @@ M: Parav Pandit <parav@nvidia.com>\n M: Xueming Li <xuemingl@nvidia.com>\n F: drivers/bus/auxiliary/\n \n+AMD CDX bus driver\n+M: Nipun Gupta <nipun.gupta@amd.com>\n+M: Nikhil Agarwal <nikhil.agarwal@amd.com>\n+F: drivers/bus/cdx/\n+\n Intel FPGA bus\n M: Rosen Xu <rosen.xu@intel.com>\n F: drivers/bus/ifpga/\ndiff --git a/doc/guides/rel_notes/release_23_07.rst b/doc/guides/rel_notes/release_23_07.rst\nindex a9b1293689..7c6bb2b894 100644\n--- a/doc/guides/rel_notes/release_23_07.rst\n+++ b/doc/guides/rel_notes/release_23_07.rst\n@@ -55,6 +55,12 @@ New Features\n      Also, make sure to start the actual text at the margin.\n      =======================================================\n \n+* **Added AMD CDX bus support.**\n+\n+  CDX bus driver has been added to support AMD CDX bus, which operates\n+  on FPGA based CDX devices. The CDX devices are memory mapped on system\n+  bus for embedded CPUs.\n+\n \n Removed Items\n -------------\ndiff --git a/drivers/bus/cdx/bus_cdx_driver.h b/drivers/bus/cdx/bus_cdx_driver.h\nnew file mode 100644\nindex 0000000000..9a2be6481a\n--- /dev/null\n+++ b/drivers/bus/cdx/bus_cdx_driver.h\n@@ -0,0 +1,166 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.\n+ */\n+\n+#ifndef BUS_CDX_DRIVER_H\n+#define BUS_CDX_DRIVER_H\n+\n+/**\n+ * @file\n+ * AMD CDX bus interface\n+ */\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+#include <stdlib.h>\n+#include <inttypes.h>\n+\n+#include <bus_driver.h>\n+#include <dev_driver.h>\n+#include <rte_interrupts.h>\n+\n+/* Forward declarations */\n+struct rte_cdx_device;\n+struct rte_cdx_driver;\n+struct rte_cdx_bus;\n+\n+#define RTE_CDX_BUS_DEVICES_PATH \"/sys/bus/cdx/devices\"\n+\n+#define RTE_CDX_MAX_RESOURCE 4\n+\n+/** Any CDX device identifier (vendor, device). */\n+#define RTE_CDX_ANY_ID (0xffff)\n+\n+#define RTE_PMD_REGISTER_CDX_TABLE(name, table) \\\n+static const char DRV_EXP_TAG(name, cdx_tbl_export)[] __rte_used = \\\n+RTE_STR(table)\n+\n+/**\n+ * A structure describing an ID for a CDX driver. Each driver provides a\n+ * table of these IDs for each device that it supports.\n+ */\n+struct rte_cdx_id {\n+\tuint16_t vendor_id;\t\t\t/**< Vendor ID. */\n+\tuint16_t device_id;\t\t\t/**< Device ID. */\n+};\n+\n+/**\n+ * A structure describing a CDX device.\n+ */\n+struct rte_cdx_device {\n+\tRTE_TAILQ_ENTRY(rte_cdx_device) next;\t/**< Next probed CDX device. */\n+\tstruct rte_device device;\t\t/**< Inherit core device */\n+\tchar name[RTE_DEV_NAME_MAX_LEN];\t/**< Device name */\n+\tstruct rte_cdx_id id;\t\t\t/**< CDX ID. */\n+\tstruct rte_mem_resource mem_resource[RTE_CDX_MAX_RESOURCE];\n+\t\t\t\t\t\t/**< CDX Memory Resource */\n+};\n+\n+/**\n+ * @internal\n+ * Helper macro for drivers that need to convert to struct rte_cdx_device.\n+ */\n+#define RTE_DEV_TO_CDX_DEV(ptr) \\\n+\tcontainer_of(ptr, struct rte_cdx_device, device)\n+\n+#define RTE_DEV_TO_CDX_DEV_CONST(ptr) \\\n+\tcontainer_of(ptr, const struct rte_cdx_device, device)\n+\n+#define RTE_ETH_DEV_TO_CDX_DEV(eth_dev)\tRTE_DEV_TO_CDX_DEV((eth_dev)->device)\n+\n+#ifdef __cplusplus\n+/** C++ macro used to help building up tables of device IDs. */\n+#define RTE_CDX_DEVICE(vend, dev)\t\\\n+\t(vend),\t\t\t\t\\\n+\t(dev)\n+#else\n+/** Macro used to help building up tables of device IDs. */\n+#define RTE_CDX_DEVICE(vend, dev)\t\\\n+\t.vendor_id = (vend),\t\t\\\n+\t.device_id = (dev)\n+#endif\n+\n+/**\n+ * Initialisation function for the driver called during CDX probing.\n+ */\n+typedef int (rte_cdx_probe_t)(struct rte_cdx_driver *, struct rte_cdx_device *);\n+\n+/**\n+ * Uninitialisation function for the driver called during hotplugging.\n+ */\n+typedef int (rte_cdx_remove_t)(struct rte_cdx_device *);\n+\n+/**\n+ * A structure describing a CDX driver.\n+ */\n+struct rte_cdx_driver {\n+\tRTE_TAILQ_ENTRY(rte_cdx_driver) next;\t/**< Next in list. */\n+\tstruct rte_driver driver;\t\t/**< Inherit core driver. */\n+\tstruct rte_cdx_bus *bus;\t\t/**< CDX bus reference. */\n+\trte_cdx_probe_t *probe;\t\t\t/**< Device probe function. */\n+\trte_cdx_remove_t *remove;\t\t/**< Device remove function. */\n+\tconst struct rte_cdx_id *id_table;\t/**< ID table, NULL terminated. */\n+\tuint32_t drv_flags;\t\t\t/**< Flags RTE_CDX_DRV_*. */\n+};\n+\n+/**\n+ * Map the CDX device resources in user space virtual memory address.\n+ *\n+ * @param dev\n+ *   A pointer to a rte_cdx_device structure describing the device\n+ *   to use.\n+ *\n+ * @return\n+ *   0 on success, <0 on error.\n+ */\n+__rte_internal\n+int rte_cdx_map_device(struct rte_cdx_device *dev);\n+\n+/**\n+ * Unmap this device.\n+ *\n+ * @param dev\n+ *   A pointer to a rte_cdx_device structure describing the device\n+ *   to use.\n+ */\n+__rte_internal\n+void rte_cdx_unmap_device(struct rte_cdx_device *dev);\n+\n+/**\n+ * Register a CDX driver.\n+ *\n+ * @param driver\n+ *   A pointer to a rte_cdx_driver structure describing the driver\n+ *   to be registered.\n+ */\n+__rte_internal\n+void rte_cdx_register(struct rte_cdx_driver *driver);\n+\n+/**\n+ * Helper for CDX device registration from driver (eth, crypto, raw) instance.\n+ */\n+#define RTE_PMD_REGISTER_CDX(nm, cdx_drv) \\\n+\tRTE_INIT(cdxinitfn_ ##nm) \\\n+\t{\\\n+\t\t(cdx_drv).driver.name = RTE_STR(nm);\\\n+\t\trte_cdx_register(&cdx_drv); \\\n+\t} \\\n+\tRTE_PMD_EXPORT_NAME(nm, __COUNTER__)\n+\n+/**\n+ * Unregister a CDX driver.\n+ *\n+ * @param driver\n+ *   A pointer to a rte_cdx_driver structure describing the driver\n+ *   to be unregistered.\n+ */\n+__rte_internal\n+void rte_cdx_unregister(struct rte_cdx_driver *driver);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* BUS_CDX_DRIVER_H */\ndiff --git a/drivers/bus/cdx/cdx.c b/drivers/bus/cdx/cdx.c\nnew file mode 100644\nindex 0000000000..38515e7fda\n--- /dev/null\n+++ b/drivers/bus/cdx/cdx.c\n@@ -0,0 +1,503 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.\n+ */\n+\n+/*\n+ * Architecture Overview\n+ * =====================\n+ * CDX is a Hardware Architecture designed for AMD FPGA devices. It\n+ * consists of sophisticated mechanism for interaction between FPGA,\n+ * Firmware and the APUs (Application CPUs).\n+ *\n+ * Firmware resides on RPU (Realtime CPUs) which interacts with\n+ * the FPGA program manager and the APUs. The RPU provides memory-mapped\n+ * interface (RPU if) which is used to communicate with APUs.\n+ *\n+ * The diagram below shows an overview of the AMD CDX architecture:\n+ *\n+ *          +--------------------------------------+\n+ *          |   DPDK                               |\n+ *          |                    DPDK CDX drivers  |\n+ *          |                             |        |\n+ *          |                    DPDK AMD CDX bus  |\n+ *          |                             |        |\n+ *          +-----------------------------|--------+\n+ *                                        |\n+ *          +-----------------------------|--------+\n+ *          |    Application CPUs (APU)   |        |\n+ *          |                             |        |\n+ *          |                     VFIO CDX driver  |\n+ *          |     Linux OS                |        |\n+ *          |                    Linux AMD CDX bus |\n+ *          |                             |        |\n+ *          +-----------------------------|--------+\n+ *                                        |\n+ *                                        |\n+ *          +------------------------| RPU if |----+\n+ *          |                             |        |\n+ *          |                             V        |\n+ *          |          Realtime CPUs (RPU)         |\n+ *          |                                      |\n+ *          +--------------------------------------+\n+ *                                |\n+ *          +---------------------|----------------+\n+ *          |  FPGA               |                |\n+ *          |      +-----------------------+       |\n+ *          |      |           |           |       |\n+ *          | +-------+    +-------+   +-------+   |\n+ *          | | dev 1 |    | dev 2 |   | dev 3 |   |\n+ *          | +-------+    +-------+   +-------+   |\n+ *          +--------------------------------------+\n+ *\n+ * The RPU firmware extracts the device information from the loaded FPGA\n+ * image and implements a mechanism that allows the APU drivers to\n+ * enumerate such devices (device personality and resource details) via\n+ * a dedicated communication channel.\n+ *\n+ * VFIO CDX driver provides the CDX device resources like MMIO and interrupts\n+ * to map to user-space. DPDK CDX bus uses sysfs interface and the vfio-cdx\n+ * driver to discover and initialize the CDX devices for user-space\n+ * applications.\n+ */\n+\n+/**\n+ * @file\n+ * CDX probing using Linux sysfs.\n+ */\n+\n+#include <string.h>\n+#include <dirent.h>\n+\n+#include <rte_eal_paging.h>\n+#include <rte_errno.h>\n+#include <rte_devargs.h>\n+#include <rte_malloc.h>\n+#include <rte_vfio.h>\n+\n+#include <eal_filesystem.h>\n+\n+#include \"bus_cdx_driver.h\"\n+#include \"cdx_logs.h\"\n+#include \"private.h\"\n+\n+#define CDX_BUS_NAME\tcdx\n+#define CDX_DEV_PREFIX\t\"cdx-\"\n+\n+/* CDX Bus iterators */\n+#define FOREACH_DEVICE_ON_CDXBUS(p)\t\\\n+\t\tRTE_TAILQ_FOREACH(p, &rte_cdx_bus.device_list, next)\n+\n+#define FOREACH_DRIVER_ON_CDXBUS(p)\t\\\n+\t\tRTE_TAILQ_FOREACH(p, &rte_cdx_bus.driver_list, next)\n+\n+struct rte_cdx_bus rte_cdx_bus;\n+\n+/* Add a device to CDX bus */\n+static void\n+cdx_add_device(struct rte_cdx_device *cdx_dev)\n+{\n+\tTAILQ_INSERT_TAIL(&rte_cdx_bus.device_list, cdx_dev, next);\n+}\n+\n+static int\n+cdx_get_kernel_driver_by_path(const char *filename, char *driver_name,\n+\t\tsize_t len)\n+{\n+\tint count;\n+\tchar path[PATH_MAX];\n+\tchar *name;\n+\n+\tif (!filename || !driver_name)\n+\t\treturn -1;\n+\n+\tcount = readlink(filename, path, PATH_MAX);\n+\tif (count >= PATH_MAX)\n+\t\treturn -1;\n+\n+\t/* For device does not have a driver */\n+\tif (count < 0)\n+\t\treturn 1;\n+\n+\tpath[count] = '\\0';\n+\n+\tname = strrchr(path, '/');\n+\tif (name) {\n+\t\tstrlcpy(driver_name, name + 1, len);\n+\t\treturn 0;\n+\t}\n+\n+\treturn -1;\n+}\n+\n+int rte_cdx_map_device(struct rte_cdx_device *dev)\n+{\n+\treturn cdx_vfio_map_resource(dev);\n+}\n+\n+void rte_cdx_unmap_device(struct rte_cdx_device *dev)\n+{\n+\tcdx_vfio_unmap_resource(dev);\n+}\n+\n+static struct rte_devargs *\n+cdx_devargs_lookup(const char *dev_name)\n+{\n+\tstruct rte_devargs *devargs;\n+\n+\tRTE_EAL_DEVARGS_FOREACH(\"cdx\", devargs) {\n+\t\tif (strcmp(devargs->name, dev_name) == 0)\n+\t\t\treturn devargs;\n+\t}\n+\treturn NULL;\n+}\n+\n+static bool\n+cdx_ignore_device(const char *dev_name)\n+{\n+\tstruct rte_devargs *devargs = cdx_devargs_lookup(dev_name);\n+\n+\tswitch (rte_cdx_bus.bus.conf.scan_mode) {\n+\tcase RTE_BUS_SCAN_ALLOWLIST:\n+\t\tif (devargs && devargs->policy == RTE_DEV_ALLOWED)\n+\t\t\treturn false;\n+\t\tbreak;\n+\tcase RTE_BUS_SCAN_UNDEFINED:\n+\tcase RTE_BUS_SCAN_BLOCKLIST:\n+\t\tif (devargs == NULL || devargs->policy != RTE_DEV_BLOCKED)\n+\t\t\treturn false;\n+\t\tbreak;\n+\t}\n+\treturn true;\n+}\n+\n+/*\n+ * Scan one cdx sysfs entry, and fill the devices list from it.\n+ * It checks if the CDX device is bound to vfio-cdx driver. In case\n+ * the device is vfio bound, it reads the vendor and device id and\n+ * stores it for device-driver matching.\n+ */\n+static int\n+cdx_scan_one(const char *dirname, const char *dev_name)\n+{\n+\tchar filename[PATH_MAX];\n+\tstruct rte_cdx_device *dev = NULL;\n+\tchar driver[PATH_MAX];\n+\tunsigned long tmp;\n+\tint ret;\n+\n+\tdev = calloc(1, sizeof(*dev));\n+\tif (!dev)\n+\t\treturn -ENOMEM;\n+\n+\tdev->device.bus = &rte_cdx_bus.bus;\n+\tmemcpy(dev->name, dev_name, RTE_DEV_NAME_MAX_LEN);\n+\tdev->device.name = dev->name;\n+\n+\t/* parse driver */\n+\tsnprintf(filename, sizeof(filename), \"%s/driver\", dirname);\n+\tret = cdx_get_kernel_driver_by_path(filename, driver, sizeof(driver));\n+\tif (ret < 0) {\n+\t\tCDX_BUS_ERR(\"Fail to get kernel driver\");\n+\t\tret = -1;\n+\t\tgoto err;\n+\t}\n+\n+\t/*\n+\t * Check if device is bound to 'vfio-cdx' driver, so that user-space\n+\t * can gracefully access the device.\n+\t */\n+\tif (ret || strcmp(driver, \"vfio-cdx\")) {\n+\t\tret = 0;\n+\t\tgoto err;\n+\t}\n+\n+\t/* get vendor id */\n+\tsnprintf(filename, sizeof(filename), \"%s/vendor\", dirname);\n+\tif (eal_parse_sysfs_value(filename, &tmp) < 0) {\n+\t\tret = -1;\n+\t\tgoto err;\n+\t}\n+\tdev->id.vendor_id = (uint16_t)tmp;\n+\n+\t/* get device id */\n+\tsnprintf(filename, sizeof(filename), \"%s/device\", dirname);\n+\tif (eal_parse_sysfs_value(filename, &tmp) < 0) {\n+\t\tfree(dev);\n+\t\treturn -1;\n+\t}\n+\tdev->id.device_id = (uint16_t)tmp;\n+\n+\tcdx_add_device(dev);\n+\n+\treturn 0;\n+\n+err:\n+\tfree(dev);\n+\treturn ret;\n+}\n+\n+/*\n+ * Scan the content of the CDX bus, and the devices in the devices\n+ * list.\n+ */\n+static int\n+cdx_scan(void)\n+{\n+\tstruct dirent *e;\n+\tDIR *dir;\n+\tchar dirname[PATH_MAX];\n+\n+\tdir = opendir(RTE_CDX_BUS_DEVICES_PATH);\n+\tif (dir == NULL) {\n+\t\tCDX_BUS_ERR(\"%s(): opendir failed: %s\", __func__,\n+\t\t\tstrerror(errno));\n+\t\treturn -1;\n+\t}\n+\n+\twhile ((e = readdir(dir)) != NULL) {\n+\t\tif (e->d_name[0] == '.')\n+\t\t\tcontinue;\n+\n+\t\tif (cdx_ignore_device(e->d_name))\n+\t\t\tcontinue;\n+\n+\t\tsnprintf(dirname, sizeof(dirname), \"%s/%s\",\n+\t\t\t\tRTE_CDX_BUS_DEVICES_PATH, e->d_name);\n+\n+\t\tif (cdx_scan_one(dirname, e->d_name) < 0)\n+\t\t\tgoto error;\n+\t}\n+\tclosedir(dir);\n+\treturn 0;\n+\n+error:\n+\tclosedir(dir);\n+\treturn -1;\n+}\n+\n+/* map a particular resource from a file */\n+void *\n+cdx_map_resource(void *requested_addr, int fd, uint64_t offset, size_t size,\n+\t\tint additional_flags)\n+{\n+\tvoid *mapaddr;\n+\n+\t/* Map the cdx MMIO memory resource of device */\n+\tmapaddr = rte_mem_map(requested_addr, size,\n+\t\tRTE_PROT_READ | RTE_PROT_WRITE,\n+\t\tRTE_MAP_SHARED | additional_flags, fd, offset);\n+\tif (mapaddr == NULL) {\n+\t\tCDX_BUS_ERR(\"%s(): cannot map resource(%d, %p, 0x%zx, 0x%\"PRIx64\"): %s (%p)\",\n+\t\t\t__func__, fd, requested_addr, size, offset,\n+\t\t\trte_strerror(rte_errno), mapaddr);\n+\t}\n+\tCDX_BUS_DEBUG(\"CDX MMIO memory mapped at %p\", mapaddr);\n+\n+\treturn mapaddr;\n+}\n+\n+/* unmap a particular resource */\n+void\n+cdx_unmap_resource(void *requested_addr, size_t size)\n+{\n+\tif (requested_addr == NULL)\n+\t\treturn;\n+\n+\t/* Unmap the CDX memory resource of device */\n+\tif (rte_mem_unmap(requested_addr, size)) {\n+\t\tCDX_BUS_ERR(\"%s(): cannot mem unmap(%p, %#zx): %s\", __func__,\n+\t\t\trequested_addr, size, rte_strerror(rte_errno));\n+\t}\n+\tCDX_BUS_DEBUG(\"CDX memory unmapped at %p\", requested_addr);\n+}\n+/*\n+ * Match the CDX Driver and Device using device id and vendor id.\n+ */\n+static bool\n+cdx_match(const struct rte_cdx_driver *cdx_drv,\n+\t\tconst struct rte_cdx_device *cdx_dev)\n+{\n+\tconst struct rte_cdx_id *id_table;\n+\n+\tfor (id_table = cdx_drv->id_table; id_table->vendor_id != 0;\n+\t     id_table++) {\n+\t\t/* check if device's identifiers match the driver's ones */\n+\t\tif (id_table->vendor_id != cdx_dev->id.vendor_id &&\n+\t\t\t\tid_table->vendor_id != RTE_CDX_ANY_ID)\n+\t\t\tcontinue;\n+\t\tif (id_table->device_id != cdx_dev->id.device_id &&\n+\t\t\t\tid_table->device_id != RTE_CDX_ANY_ID)\n+\t\t\tcontinue;\n+\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * If vendor id and device id match, call the probe() function of the\n+ * driver.\n+ */\n+static int\n+cdx_probe_one_driver(struct rte_cdx_driver *dr,\n+\t\tstruct rte_cdx_device *dev)\n+{\n+\tconst char *dev_name = dev->name;\n+\tbool already_probed;\n+\tint ret;\n+\n+\t/* The device is not blocked; Check if driver supports it */\n+\tif (!cdx_match(dr, dev))\n+\t\t/* Match of device and driver failed */\n+\t\treturn 1;\n+\n+\talready_probed = rte_dev_is_probed(&dev->device);\n+\tif (already_probed) {\n+\t\tCDX_BUS_INFO(\"Device %s is already probed\", dev_name);\n+\t\treturn -EEXIST;\n+\t}\n+\n+\tCDX_BUS_DEBUG(\"  probe device %s using driver: %s\", dev_name,\n+\t\tdr->driver.name);\n+\n+\tret = cdx_vfio_map_resource(dev);\n+\tif (ret != 0) {\n+\t\tCDX_BUS_ERR(\"CDX map device failed: %d\", ret);\n+\t\tgoto error_map_device;\n+\t}\n+\n+\t/* call the driver probe() function */\n+\tret = dr->probe(dr, dev);\n+\tif (ret) {\n+\t\tCDX_BUS_ERR(\"Probe CDX driver: %s device: %s failed: %d\",\n+\t\t\tdr->driver.name, dev_name, ret);\n+\t\tgoto error_probe;\n+\t} else {\n+\t\tdev->device.driver = &dr->driver;\n+\t}\n+\n+\treturn ret;\n+\n+error_probe:\n+\tcdx_vfio_unmap_resource(dev);\n+error_map_device:\n+\treturn ret;\n+}\n+\n+/*\n+ * If vendor/device ID match, call the probe() function of all\n+ * registered driver for the given device. Return < 0 if initialization\n+ * failed, return 1 if no driver is found for this device.\n+ */\n+static int\n+cdx_probe_all_drivers(struct rte_cdx_device *dev)\n+{\n+\tstruct rte_cdx_driver *dr = NULL;\n+\tint rc = 0;\n+\n+\tFOREACH_DRIVER_ON_CDXBUS(dr) {\n+\t\trc = cdx_probe_one_driver(dr, dev);\n+\t\tif (rc < 0)\n+\t\t\t/* negative value is an error */\n+\t\t\treturn rc;\n+\t\tif (rc > 0)\n+\t\t\t/* positive value means driver doesn't support it */\n+\t\t\tcontinue;\n+\t\treturn 0;\n+\t}\n+\treturn 1;\n+}\n+\n+/*\n+ * Scan the content of the CDX bus, and call the probe() function for\n+ * all registered drivers that have a matching entry in its id_table\n+ * for discovered devices.\n+ */\n+static int\n+cdx_probe(void)\n+{\n+\tstruct rte_cdx_device *dev = NULL;\n+\tsize_t probed = 0, failed = 0;\n+\tint ret = 0;\n+\n+\tFOREACH_DEVICE_ON_CDXBUS(dev) {\n+\t\tprobed++;\n+\n+\t\tret = cdx_probe_all_drivers(dev);\n+\t\tif (ret < 0) {\n+\t\t\tCDX_BUS_ERR(\"Requested device %s cannot be used\",\n+\t\t\t\tdev->name);\n+\t\t\trte_errno = errno;\n+\t\t\tfailed++;\n+\t\t\tret = 0;\n+\t\t}\n+\t}\n+\n+\treturn (probed && probed == failed) ? -1 : 0;\n+}\n+\n+static int\n+cdx_parse(const char *name, void *addr)\n+{\n+\tconst char **out = addr;\n+\tint ret;\n+\n+\tret = strncmp(name, CDX_DEV_PREFIX, strlen(CDX_DEV_PREFIX));\n+\n+\tif (ret == 0 && addr)\n+\t\t*out = name;\n+\n+\treturn ret;\n+}\n+\n+/* register a driver */\n+void\n+rte_cdx_register(struct rte_cdx_driver *driver)\n+{\n+\tTAILQ_INSERT_TAIL(&rte_cdx_bus.driver_list, driver, next);\n+\tdriver->bus = &rte_cdx_bus;\n+}\n+\n+/* unregister a driver */\n+void\n+rte_cdx_unregister(struct rte_cdx_driver *driver)\n+{\n+\tTAILQ_REMOVE(&rte_cdx_bus.driver_list, driver, next);\n+\tdriver->bus = NULL;\n+}\n+\n+static struct rte_device *\n+cdx_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,\n+\t\tconst void *data)\n+{\n+\tconst struct rte_cdx_device *cdx_start;\n+\tstruct rte_cdx_device *cdx_dev;\n+\n+\tif (start != NULL) {\n+\t\tcdx_start = RTE_DEV_TO_CDX_DEV_CONST(start);\n+\t\tcdx_dev = TAILQ_NEXT(cdx_start, next);\n+\t} else {\n+\t\tcdx_dev = TAILQ_FIRST(&rte_cdx_bus.device_list);\n+\t}\n+\twhile (cdx_dev != NULL) {\n+\t\tif (cmp(&cdx_dev->device, data) == 0)\n+\t\t\treturn &cdx_dev->device;\n+\t\tcdx_dev = TAILQ_NEXT(cdx_dev, next);\n+\t}\n+\treturn NULL;\n+}\n+\n+struct rte_cdx_bus rte_cdx_bus = {\n+\t.bus = {\n+\t\t.scan = cdx_scan,\n+\t\t.probe = cdx_probe,\n+\t\t.find_device = cdx_find_device,\n+\t\t.parse = cdx_parse,\n+\t},\n+\t.device_list = TAILQ_HEAD_INITIALIZER(rte_cdx_bus.device_list),\n+\t.driver_list = TAILQ_HEAD_INITIALIZER(rte_cdx_bus.driver_list),\n+};\n+\n+RTE_REGISTER_BUS(cdx, rte_cdx_bus.bus);\n+RTE_LOG_REGISTER_DEFAULT(cdx_logtype_bus, NOTICE);\ndiff --git a/drivers/bus/cdx/cdx_logs.h b/drivers/bus/cdx/cdx_logs.h\nnew file mode 100644\nindex 0000000000..a1046ce544\n--- /dev/null\n+++ b/drivers/bus/cdx/cdx_logs.h\n@@ -0,0 +1,37 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.\n+ */\n+\n+#ifndef CDX_LOGS_H\n+#define CDX_LOGS_H\n+\n+extern int cdx_logtype_bus;\n+\n+#define CDX_BUS_LOG(level, fmt, args...) \\\n+\trte_log(RTE_LOG_ ## level, cdx_logtype_bus, \"cdx: \" fmt \"\\n\", \\\n+\t\t##args)\n+\n+/* Debug logs with Function names */\n+#define CDX_BUS_DEBUG(fmt, args...) \\\n+\trte_log(RTE_LOG_DEBUG, cdx_logtype_bus, \"cdx: %s(): \" fmt \"\\n\", \\\n+\t\t__func__, ##args)\n+\n+#define CDX_BUS_INFO(fmt, args...) \\\n+\tCDX_BUS_LOG(INFO, fmt, ## args)\n+#define CDX_BUS_ERR(fmt, args...) \\\n+\tCDX_BUS_LOG(ERR, fmt, ## args)\n+#define CDX_BUS_WARN(fmt, args...) \\\n+\tCDX_BUS_LOG(WARNING, fmt, ## args)\n+\n+/* DP Logs, toggled out at compile time if level lower than current level */\n+#define CDX_BUS_DP_LOG(level, fmt, args...) \\\n+\tRTE_LOG_DP(level, PMD, fmt, ## args)\n+\n+#define CDX_BUS_DP_DEBUG(fmt, args...) \\\n+\tCDX_BUS_DP_LOG(DEBUG, fmt, ## args)\n+#define CDX_BUS_DP_INFO(fmt, args...) \\\n+\tCDX_BUS_DP_LOG(INFO, fmt, ## args)\n+#define CDX_BUS_DP_WARN(fmt, args...) \\\n+\tCDX_BUS_DP_LOG(WARNING, fmt, ## args)\n+\n+#endif /* CDX_LOGS_H */\ndiff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c\nnew file mode 100644\nindex 0000000000..86290f0450\n--- /dev/null\n+++ b/drivers/bus/cdx/cdx_vfio.c\n@@ -0,0 +1,426 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.\n+ */\n+\n+/**\n+ * @file\n+ * CDX probing using Linux VFIO.\n+ *\n+ * This code tries to determine if the CDX device is bound to VFIO driver,\n+ * and initialize it (map MMIO regions, set up interrupts) if that's the case.\n+ *\n+ */\n+\n+#include <fcntl.h>\n+#include <unistd.h>\n+#include <sys/eventfd.h>\n+#include <sys/socket.h>\n+#include <sys/ioctl.h>\n+#include <sys/mman.h>\n+#include <rte_eal_paging.h>\n+#include <rte_malloc.h>\n+#include <rte_vfio.h>\n+\n+#include \"bus_cdx_driver.h\"\n+#include \"cdx_logs.h\"\n+#include \"private.h\"\n+\n+/**\n+ * A structure describing a CDX mapping.\n+ */\n+struct cdx_map {\n+\tvoid *addr;\n+\tchar *path;\n+\tuint64_t offset;\n+\tuint64_t size;\n+};\n+\n+/**\n+ * A structure describing a mapped CDX resource.\n+ * For multi-process we need to reproduce all CDX mappings in secondary\n+ * processes, so save them in a tailq.\n+ */\n+struct mapped_cdx_resource {\n+\tTAILQ_ENTRY(mapped_cdx_resource) next;\n+\tchar name[RTE_DEV_NAME_MAX_LEN];      /**< CDX device name */\n+\tchar path[PATH_MAX];\n+\tint nb_maps;\n+\tstruct cdx_map maps[RTE_CDX_MAX_RESOURCE];\n+};\n+\n+/** mapped cdx device list */\n+TAILQ_HEAD(mapped_cdx_res_list, mapped_cdx_resource);\n+\n+static struct rte_tailq_elem cdx_vfio_tailq = {\n+\t.name = \"VFIO_CDX_RESOURCE_LIST\",\n+};\n+EAL_REGISTER_TAILQ(cdx_vfio_tailq)\n+\n+static struct mapped_cdx_resource *\n+cdx_vfio_find_and_unmap_resource(struct mapped_cdx_res_list *vfio_res_list,\n+\t\tstruct rte_cdx_device *dev)\n+{\n+\tstruct mapped_cdx_resource *vfio_res = NULL;\n+\tconst char *dev_name = dev->device.name;\n+\tstruct cdx_map *maps;\n+\tint i;\n+\n+\t/* Get vfio_res */\n+\tTAILQ_FOREACH(vfio_res, vfio_res_list, next) {\n+\t\tif (strcmp(vfio_res->name, dev_name))\n+\t\t\tcontinue;\n+\t\tbreak;\n+\t}\n+\n+\tif  (vfio_res == NULL)\n+\t\treturn vfio_res;\n+\n+\tCDX_BUS_INFO(\"Releasing CDX mapped resource for %s\", dev_name);\n+\n+\tmaps = vfio_res->maps;\n+\tfor (i = 0; i < vfio_res->nb_maps; i++) {\n+\t\tif (maps[i].addr) {\n+\t\t\tCDX_BUS_DEBUG(\"Calling cdx_unmap_resource for %s at %p\",\n+\t\t\t\tdev_name, maps[i].addr);\n+\t\t\tcdx_unmap_resource(maps[i].addr, maps[i].size);\n+\t\t}\n+\t}\n+\n+\treturn vfio_res;\n+}\n+\n+static int\n+cdx_vfio_unmap_resource_primary(struct rte_cdx_device *dev)\n+{\n+\tchar cdx_addr[PATH_MAX] = {0};\n+\tstruct mapped_cdx_resource *vfio_res = NULL;\n+\tstruct mapped_cdx_res_list *vfio_res_list;\n+\n+\tvfio_res_list =\n+\t\tRTE_TAILQ_CAST(cdx_vfio_tailq.head, mapped_cdx_res_list);\n+\tvfio_res = cdx_vfio_find_and_unmap_resource(vfio_res_list, dev);\n+\n+\t/* if we haven't found our tailq entry, something's wrong */\n+\tif (vfio_res == NULL) {\n+\t\tCDX_BUS_ERR(\"%s cannot find TAILQ entry for cdx device!\",\n+\t\t\tcdx_addr);\n+\t\treturn -1;\n+\t}\n+\n+\tTAILQ_REMOVE(vfio_res_list, vfio_res, next);\n+\trte_free(vfio_res);\n+\treturn 0;\n+}\n+\n+static int\n+cdx_vfio_unmap_resource_secondary(struct rte_cdx_device *dev)\n+{\n+\tstruct mapped_cdx_resource *vfio_res = NULL;\n+\tstruct mapped_cdx_res_list *vfio_res_list;\n+\n+\tvfio_res_list =\n+\t\tRTE_TAILQ_CAST(cdx_vfio_tailq.head, mapped_cdx_res_list);\n+\tvfio_res = cdx_vfio_find_and_unmap_resource(vfio_res_list, dev);\n+\n+\t/* if we haven't found our tailq entry, something's wrong */\n+\tif (vfio_res == NULL) {\n+\t\tCDX_BUS_ERR(\"%s cannot find TAILQ entry for CDX device!\",\n+\t\t\tdev->device.name);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+cdx_vfio_unmap_resource(struct rte_cdx_device *dev)\n+{\n+\tif (rte_eal_process_type() == RTE_PROC_PRIMARY)\n+\t\treturn cdx_vfio_unmap_resource_primary(dev);\n+\telse\n+\t\treturn cdx_vfio_unmap_resource_secondary(dev);\n+}\n+\n+static int\n+cdx_vfio_setup_device(int vfio_dev_fd)\n+{\n+\t/*\n+\t * Reset the device. If the device is not capable of resetting,\n+\t * then it updates errno as EINVAL.\n+\t */\n+\tif (ioctl(vfio_dev_fd, VFIO_DEVICE_RESET) && errno != EINVAL) {\n+\t\tCDX_BUS_ERR(\"Unable to reset device! Error: %d (%s)\", errno,\n+\t\t\tstrerror(errno));\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+cdx_vfio_mmap_resource(int vfio_dev_fd, struct mapped_cdx_resource *vfio_res,\n+\t\tint index, int additional_flags)\n+{\n+\tstruct cdx_map *map = &vfio_res->maps[index];\n+\tvoid *vaddr;\n+\n+\tif (map->size == 0) {\n+\t\tCDX_BUS_DEBUG(\"map size is 0, skip region %d\", index);\n+\t\treturn 0;\n+\t}\n+\n+\t/* reserve the address using an inaccessible mapping */\n+\tvaddr = mmap(map->addr, map->size, 0, MAP_PRIVATE |\n+\t\t     MAP_ANONYMOUS | additional_flags, -1, 0);\n+\tif (vaddr != MAP_FAILED) {\n+\t\tvoid *map_addr = NULL;\n+\n+\t\tif (map->size) {\n+\t\t\t/* actual map of first part */\n+\t\t\tmap_addr = cdx_map_resource(vaddr, vfio_dev_fd,\n+\t\t\t\t\t\t    map->offset, map->size,\n+\t\t\t\t\t\t    RTE_MAP_FORCE_ADDRESS);\n+\t\t}\n+\n+\t\tif (map_addr == NULL) {\n+\t\t\tmunmap(vaddr, map->size);\n+\t\t\tvaddr = MAP_FAILED;\n+\t\t\tCDX_BUS_ERR(\"Failed to map cdx MMIO region %d\", index);\n+\t\t\treturn -1;\n+\t\t}\n+\t} else {\n+\t\tCDX_BUS_ERR(\"Failed to create inaccessible mapping for MMIO region %d\",\n+\t\t\tindex);\n+\t\treturn -1;\n+\t}\n+\n+\tmap->addr = vaddr;\n+\treturn 0;\n+}\n+\n+/*\n+ * region info may contain capability headers, so we need to keep reallocating\n+ * the memory until we match allocated memory size with argsz.\n+ */\n+static int\n+cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,\n+\t\tint region)\n+{\n+\tstruct vfio_region_info *ri;\n+\tsize_t argsz = sizeof(*ri);\n+\tint ret;\n+\n+\tri = malloc(sizeof(*ri));\n+\tif (ri == NULL) {\n+\t\tCDX_BUS_ERR(\"Cannot allocate memory for VFIO region info\");\n+\t\treturn -1;\n+\t}\n+again:\n+\tmemset(ri, 0, argsz);\n+\tri->argsz = argsz;\n+\tri->index = region;\n+\n+\tret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, ri);\n+\tif (ret < 0) {\n+\t\tfree(ri);\n+\t\treturn ret;\n+\t}\n+\tif (ri->argsz != argsz) {\n+\t\tstruct vfio_region_info *tmp;\n+\n+\t\targsz = ri->argsz;\n+\t\ttmp = realloc(ri, argsz);\n+\n+\t\tif (tmp == NULL) {\n+\t\t\t/* realloc failed but the ri is still there */\n+\t\t\tfree(ri);\n+\t\t\tCDX_BUS_ERR(\"Cannot reallocate memory for VFIO region info\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\tri = tmp;\n+\t\tgoto again;\n+\t}\n+\t*info = ri;\n+\n+\treturn 0;\n+}\n+\n+static int\n+find_max_end_va(const struct rte_memseg_list *msl, void *arg)\n+{\n+\tsize_t sz = msl->len;\n+\tvoid *end_va = RTE_PTR_ADD(msl->base_va, sz);\n+\tvoid **max_va = arg;\n+\n+\tif (*max_va < end_va)\n+\t\t*max_va = end_va;\n+\treturn 0;\n+}\n+\n+static void *\n+cdx_find_max_end_va(void)\n+{\n+\tvoid *va = NULL;\n+\n+\trte_memseg_list_walk(find_max_end_va, &va);\n+\treturn va;\n+}\n+\n+static int\n+cdx_vfio_map_resource_primary(struct rte_cdx_device *dev)\n+{\n+\tstruct vfio_device_info device_info = { .argsz = sizeof(device_info) };\n+\tchar cdx_addr[PATH_MAX] = {0};\n+\tstatic void *cdx_map_addr;\n+\tstruct mapped_cdx_resource *vfio_res = NULL;\n+\tstruct mapped_cdx_res_list *vfio_res_list =\n+\t\tRTE_TAILQ_CAST(cdx_vfio_tailq.head, mapped_cdx_res_list);\n+\tconst char *dev_name = dev->device.name;\n+\tstruct cdx_map *maps;\n+\tint vfio_dev_fd, i, ret;\n+\n+\tret = rte_vfio_setup_device(RTE_CDX_BUS_DEVICES_PATH, dev_name,\n+\t\t\t\t    &vfio_dev_fd, &device_info);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* allocate vfio_res and get region info */\n+\tvfio_res = rte_zmalloc(\"VFIO_RES\", sizeof(*vfio_res), 0);\n+\tif (vfio_res == NULL) {\n+\t\tCDX_BUS_ERR(\"Cannot store VFIO mmap details\");\n+\t\tgoto err_vfio_dev_fd;\n+\t}\n+\tmemcpy(vfio_res->name, dev_name, RTE_DEV_NAME_MAX_LEN);\n+\n+\t/* get number of registers */\n+\tvfio_res->nb_maps = device_info.num_regions;\n+\n+\t/* map memory regions */\n+\tmaps = vfio_res->maps;\n+\n+\tfor (i = 0; i < vfio_res->nb_maps; i++) {\n+\t\tstruct vfio_region_info *reg = NULL;\n+\t\tvoid *vaddr;\n+\n+\t\tret = cdx_vfio_get_region_info(vfio_dev_fd, &reg, i);\n+\t\tif (ret < 0) {\n+\t\t\tCDX_BUS_ERR(\"%s cannot get device region info error %i (%s)\",\n+\t\t\t\tdev_name, errno, strerror(errno));\n+\t\t\tgoto err_vfio_res;\n+\t\t}\n+\n+\t\t/* skip non-mmappable regions */\n+\t\tif ((reg->flags & VFIO_REGION_INFO_FLAG_MMAP) == 0) {\n+\t\t\tfree(reg);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* try mapping somewhere close to the end of hugepages */\n+\t\tif (cdx_map_addr == NULL)\n+\t\t\tcdx_map_addr = cdx_find_max_end_va();\n+\n+\t\tvaddr = cdx_map_addr;\n+\t\tcdx_map_addr = RTE_PTR_ADD(vaddr, (size_t)reg->size);\n+\n+\t\tcdx_map_addr = RTE_PTR_ALIGN(cdx_map_addr,\n+\t\t\t\t\t     sysconf(_SC_PAGE_SIZE));\n+\n+\t\tmaps[i].addr = vaddr;\n+\t\tmaps[i].offset = reg->offset;\n+\t\tmaps[i].size = reg->size;\n+\t\tmaps[i].path = NULL; /* vfio doesn't have per-resource paths */\n+\n+\t\tret = cdx_vfio_mmap_resource(vfio_dev_fd, vfio_res, i, 0);\n+\t\tif (ret < 0) {\n+\t\t\tCDX_BUS_ERR(\"%s mapping region %i failed: %s\",\n+\t\t\t\tcdx_addr, i, strerror(errno));\n+\t\t\tfree(reg);\n+\t\t\tgoto err_vfio_res;\n+\t\t}\n+\n+\t\tdev->mem_resource[i].addr = maps[i].addr;\n+\t\tdev->mem_resource[i].len = maps[i].size;\n+\n+\t\tfree(reg);\n+\t}\n+\n+\tif (cdx_vfio_setup_device(vfio_dev_fd) < 0) {\n+\t\tCDX_BUS_ERR(\"%s setup device failed\", dev_name);\n+\t\tgoto err_vfio_res;\n+\t}\n+\n+\tTAILQ_INSERT_TAIL(vfio_res_list, vfio_res, next);\n+\n+\treturn 0;\n+err_vfio_res:\n+\tcdx_vfio_find_and_unmap_resource(vfio_res_list, dev);\n+\trte_free(vfio_res);\n+err_vfio_dev_fd:\n+\trte_vfio_release_device(RTE_CDX_BUS_DEVICES_PATH, dev_name, vfio_dev_fd);\n+\treturn -1;\n+}\n+\n+static int\n+cdx_vfio_map_resource_secondary(struct rte_cdx_device *dev)\n+{\n+\tstruct vfio_device_info device_info = { .argsz = sizeof(device_info) };\n+\tchar cdx_addr[PATH_MAX] = {0};\n+\tint vfio_dev_fd;\n+\tint i, ret;\n+\tstruct mapped_cdx_resource *vfio_res = NULL;\n+\tstruct mapped_cdx_res_list *vfio_res_list =\n+\t\tRTE_TAILQ_CAST(cdx_vfio_tailq.head, mapped_cdx_res_list);\n+\tconst char *dev_name = dev->device.name;\n+\tstruct cdx_map *maps;\n+\n+\t/* if we're in a secondary process, just find our tailq entry */\n+\tTAILQ_FOREACH(vfio_res, vfio_res_list, next) {\n+\t\tif (strcmp(vfio_res->name, dev_name))\n+\t\t\tcontinue;\n+\t\tbreak;\n+\t}\n+\t/* if we haven't found our tailq entry, something's wrong */\n+\tif (vfio_res == NULL) {\n+\t\tCDX_BUS_ERR(\"%s cannot find TAILQ entry for cdx device!\",\n+\t\t\tdev_name);\n+\t\treturn -1;\n+\t}\n+\n+\tret = rte_vfio_setup_device(RTE_CDX_BUS_DEVICES_PATH, dev_name,\n+\t\t\t\t\t&vfio_dev_fd, &device_info);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* map MMIO regions */\n+\tmaps = vfio_res->maps;\n+\n+\tfor (i = 0; i < vfio_res->nb_maps; i++) {\n+\t\tret = cdx_vfio_mmap_resource(vfio_dev_fd, vfio_res, i, MAP_FIXED);\n+\t\tif (ret < 0) {\n+\t\t\tCDX_BUS_ERR(\"%s mapping MMIO region %i failed: %s\",\n+\t\t\t\tdev_name, i, strerror(errno));\n+\t\t\tgoto err_vfio_dev_fd;\n+\t\t}\n+\n+\t\tdev->mem_resource[i].addr = maps[i].addr;\n+\t\tdev->mem_resource[i].len = maps[i].size;\n+\t}\n+\n+\treturn 0;\n+err_vfio_dev_fd:\n+\trte_vfio_release_device(RTE_CDX_BUS_DEVICES_PATH, cdx_addr, vfio_dev_fd);\n+\treturn -1;\n+}\n+\n+/*\n+ * map the CDX resources of a CDX device in virtual memory (VFIO version).\n+ * primary and secondary processes follow almost exactly the same path\n+ */\n+int\n+cdx_vfio_map_resource(struct rte_cdx_device *dev)\n+{\n+\tif (rte_eal_process_type() == RTE_PROC_PRIMARY)\n+\t\treturn cdx_vfio_map_resource_primary(dev);\n+\telse\n+\t\treturn cdx_vfio_map_resource_secondary(dev);\n+}\ndiff --git a/drivers/bus/cdx/meson.build b/drivers/bus/cdx/meson.build\nnew file mode 100644\nindex 0000000000..f2ca104d34\n--- /dev/null\n+++ b/drivers/bus/cdx/meson.build\n@@ -0,0 +1,13 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright (C) 2022-2023, Advanced Micro Devices, Inc.\n+\n+if not is_linux\n+    build = false\n+    reason = 'only supported on Linux'\n+endif\n+\n+driver_sdk_headers = files('bus_cdx_driver.h')\n+sources = files(\n+        'cdx.c',\n+        'cdx_vfio.c',\n+)\ndiff --git a/drivers/bus/cdx/private.h b/drivers/bus/cdx/private.h\nnew file mode 100644\nindex 0000000000..81987d0cfe\n--- /dev/null\n+++ b/drivers/bus/cdx/private.h\n@@ -0,0 +1,53 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.\n+ */\n+\n+#ifndef CDX_PRIVATE_H\n+#define CDX_PRIVATE_H\n+\n+#include \"bus_cdx_driver.h\"\n+\n+/**\n+ * Structure describing the CDX bus.\n+ */\n+struct rte_cdx_bus {\n+\tstruct rte_bus bus;\t\t\t\t/**< Inherit the generic class */\n+\tRTE_TAILQ_HEAD(, rte_cdx_device) device_list;\t/**< List of CDX devices */\n+\tRTE_TAILQ_HEAD(, rte_cdx_driver) driver_list;\t/**< List of CDX drivers */\n+};\n+\n+/**\n+ * Map a particular resource from a file.\n+ *\n+ * @param requested_addr\n+ *      The starting address for the new mapping range.\n+ * @param fd\n+ *      The file descriptor.\n+ * @param offset\n+ *      The offset for the mapping range.\n+ * @param size\n+ *      The size for the mapping range.\n+ * @param additional_flags\n+ *      The additional rte_mem_map() flags for the mapping range.\n+ * @return\n+ *   - On success, the function returns a pointer to the mapped area.\n+ *   - On error, NULL is returned.\n+ */\n+void *cdx_map_resource(void *requested_addr, int fd, uint64_t offset,\n+\t\tsize_t size, int additional_flags);\n+\n+/**\n+ * Unmap a particular resource.\n+ *\n+ * @param requested_addr\n+ *      The address for the unmapping range.\n+ * @param size\n+ *      The size for the unmapping range.\n+ */\n+void cdx_unmap_resource(void *requested_addr, size_t size);\n+\n+/* map/unmap VFIO resource */\n+int cdx_vfio_map_resource(struct rte_cdx_device *dev);\n+int cdx_vfio_unmap_resource(struct rte_cdx_device *dev);\n+\n+#endif /* CDX_PRIVATE_H */\ndiff --git a/drivers/bus/cdx/version.map b/drivers/bus/cdx/version.map\nnew file mode 100644\nindex 0000000000..360460da18\n--- /dev/null\n+++ b/drivers/bus/cdx/version.map\n@@ -0,0 +1,10 @@\n+INTERNAL {\n+\tglobal:\n+\n+\trte_cdx_map_device;\n+\trte_cdx_register;\n+\trte_cdx_unmap_device;\n+\trte_cdx_unregister;\n+\n+\tlocal: *;\n+};\ndiff --git a/drivers/bus/meson.build b/drivers/bus/meson.build\nindex 6d2520c543..a78b4283bf 100644\n--- a/drivers/bus/meson.build\n+++ b/drivers/bus/meson.build\n@@ -3,6 +3,7 @@\n \n drivers = [\n         'auxiliary',\n+        'cdx',\n         'dpaa',\n         'fslmc',\n         'ifpga',\n",
    "prefixes": [
        "v8",
        "1/4"
    ]
}