get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 126759,
    "url": "http://patches.dpdk.org/api/patches/126759/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20230508111812.2655-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": "<20230508111812.2655-2-nipun.gupta@amd.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20230508111812.2655-2-nipun.gupta@amd.com",
    "date": "2023-05-08T11:18:09",
    "name": "[v4,1/4] bus/cdx: introduce cdx bus",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "f27ac8ce2e2690933479dd8c91db95e158d87d79",
    "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/20230508111812.2655-2-nipun.gupta@amd.com/mbox/",
    "series": [
        {
            "id": 27954,
            "url": "http://patches.dpdk.org/api/series/27954/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=27954",
            "date": "2023-05-08T11:18:08",
            "name": "Support AMD CDX bus, for FPGA based CDX devices. The CDX",
            "version": 4,
            "mbox": "http://patches.dpdk.org/series/27954/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/126759/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/126759/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 D473B42A94;\n\tMon,  8 May 2023 13:18:44 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id C6295427E9;\n\tMon,  8 May 2023 13:18:44 +0200 (CEST)",
            "from NAM10-BN7-obe.outbound.protection.outlook.com\n (mail-bn7nam10on2086.outbound.protection.outlook.com [40.107.92.86])\n by mails.dpdk.org (Postfix) with ESMTP id 2842D40685\n for <dev@dpdk.org>; Mon,  8 May 2023 13:18:43 +0200 (CEST)",
            "from BN9PR03CA0493.namprd03.prod.outlook.com (2603:10b6:408:130::18)\n by DM4PR12MB5200.namprd12.prod.outlook.com (2603:10b6:5:397::11) with\n Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6363.32; Mon, 8 May\n 2023 11:18:40 +0000",
            "from BN8NAM11FT111.eop-nam11.prod.protection.outlook.com\n (2603:10b6:408:130:cafe::cc) by BN9PR03CA0493.outlook.office365.com\n (2603:10b6:408:130::18) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6363.32 via Frontend\n Transport; Mon, 8 May 2023 11:18:40 +0000",
            "from SATLEXMB03.amd.com (165.204.84.17) by\n BN8NAM11FT111.mail.protection.outlook.com (10.13.177.54) with Microsoft SMTP\n Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id\n 15.20.6363.32 via Frontend Transport; Mon, 8 May 2023 11:18:39 +0000",
            "from SATLEXMB03.amd.com (10.181.40.144) by SATLEXMB03.amd.com\n (10.181.40.144) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.34; Mon, 8 May\n 2023 06:18:38 -0500",
            "from xhdipdslab41.xilinx.com (10.180.168.240) by SATLEXMB03.amd.com\n (10.181.40.144) with Microsoft SMTP Server id 15.1.2375.34 via\n Frontend Transport; Mon, 8 May 2023 06:18:36 -0500"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=SyooAEIZO/y0if7kpt1cMeuHKos0IHEQnpX8VRFIraSZqE29U3vCWHSGvPzRm0DiLFlSn8Am7631PnyHGOR4ilEImCnL7xR7lgYvRL2hH8WZ74WhBQ/Mw/UZ+uP6KXGkskiN8TOc/DCCmn/+w+cY0OrRImgUjPEaUKLlhPXQ52Vef8/WCkUh2hs5rtPU7NpJLaXEfgMCyyRlROFjku56S5vvkp7EGCLUNt/HGoFq4JtTj823Z988ncSXYkLQo/gOXI2pLrilNJ0PSmiIzcX5RNCW2ytl7p9/1aFJgzDrWTocTE0ggKaiheg8ijnjdSDsNzjxVl8gPGAKrQjUMHkHfw==",
        "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=L5+/Dw9JmGl2N71BWsPV7+xNWeRZsLKNkII51JIrTrg=;\n b=RP+jfnivHduH4Ld6rzS1K/bgLpdnTRfW+zSX4bq1i2RecKHyJwzU04PlRsl1ZOoQH191A4Glkky15RZdgnY6gLbu5QtJzy/8rPjLBEr0bTEjI+TYVJa2wPfGOiOFyDKuoVr+gHM+NKOYlDdPhrahOMCjI72u70M9Pszt3d73NhJ5E2B3fhEU6hnWIAqryX8XTy9qpg4L+W+zqFICnHCs78G6a9AdBC2ZDO+xMQYfqFYLMAO1CcNdChwEoSIewC3UDlOV/0brgvM05PBUPAQsUbrQ59GLsQKyDJDYGlA8hsKE1Y8ApMid2bT9D02N/bfbVz1Xe2hZxYQietiMly8X0Q==",
        "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=L5+/Dw9JmGl2N71BWsPV7+xNWeRZsLKNkII51JIrTrg=;\n b=PDAqiYVQC+dMsN5lWgo4fuyb9acH243MUKr9X1GLcgO1QKw9Q/AIvstgmY8f9Nx5ybZX4UTRW/bFB9AweXUf2W8FW55WOCssF/DD4aQRH5bauI6nv619iSQhI/ULAMdQQagHejDt1NfpWeuPtz5YwiTHN+KKoQUw79Rd395Dip4=",
        "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=SATLEXMB03.amd.com; pr=C",
        "From": "Nipun Gupta <nipun.gupta@amd.com>",
        "To": "<dev@dpdk.org>, <thomas@monjalon.net>, <david.marchand@redhat.com>",
        "CC": "<ferruh.yigit@amd.com>, <harpreet.anand@amd.com>,\n <nikhil.agarwal@amd.com>, Nipun Gupta <nipun.gupta@amd.com>",
        "Subject": "[PATCH v4 1/4] bus/cdx: introduce cdx bus",
        "Date": "Mon, 8 May 2023 16:48:09 +0530",
        "Message-ID": "<20230508111812.2655-2-nipun.gupta@amd.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20230508111812.2655-1-nipun.gupta@amd.com>",
        "References": "<20230124140746.594066-1-nipun.gupta@amd.com>\n <20230508111812.2655-1-nipun.gupta@amd.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-EOPAttributedMessage": "0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "BN8NAM11FT111:EE_|DM4PR12MB5200:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "b9a9b8ed-fdd5-470d-845c-08db4fb5f9ab",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n hnJ8foZ4i8prvmgUFfZIalHMPwV/Q6WRVub2q69mp2kpDVxMr9zI38C9qo8DKpfMYPxI3uU9nf7nN5BEqtwbJDPl0Fgm6Vb8JBWS7BLLm++JKUeuNVpj5NVoQ3hJH8Xb3I8qfmyBCIeonMEWAztkkvH3jGy8bNUQxJdz7Fnt4X6AY7FcBUlReJwF8w0KHEh/MGcDyKEDoTgf7KMgEuaR0SaOQhvPjfaW7ggYqZyK7BZeqTr54V7xgqyj4pJHgGFGt7XNoSlmkCHIjPDCMo3Jo80dMPGdq3+WQXo6TyRU90zeDnVNWtM7fVZ3iQAG6fgJG6UxSG1Rpwza8rwvXRIGfLd2oE9RelEOXGEYk8Lc/s4ypWCna7prfTcz2lwaWGQkJ/eAXBTX9xtnRO6t0y6cQ+NCLC7BDRggo6hzn66iwZQQM4ZndX1xtP3vC7DAyJtWEHL5w3egoR22RtBnpyam7MtipTGAFPAIjZ/Wx/GYYmUgH1SnjwS/lZ6FTBL6fKmxJChMyZ/nyorD/e7fgBXfae7DTHKh/R5Mb1wragXmMj5lAh3YjguZ3Mlt2vZszNJ0lh1x+3Vi7whzG8NWMsQmFGZk1Ki24bQw9d0+qw9FvlzX5Hsx2pV2/+E0WJRwfT6M7QYZDxxEugyv7zBH7bKrUFEmHh1oVivCgbhCIOC1Nug/wEpPKpkE/WvZJWT656ZHkbuBAaw1XxMXWyYcA8z2hawNcXf3iRAdYyrPMbnOrJc=",
        "X-Forefront-Antispam-Report": "CIP:165.204.84.17; CTRY:US; LANG:en; SCL:1; SRV:;\n IPV:CAL; SFV:NSPM; H:SATLEXMB03.amd.com; PTR:InfoDomainNonexistent; CAT:NONE;\n SFS:(13230028)(4636009)(346002)(376002)(396003)(136003)(39860400002)(451199021)(36840700001)(46966006)(40470700004)(36860700001)(426003)(336012)(83380400001)(47076005)(478600001)(6666004)(110136005)(54906003)(2616005)(1076003)(26005)(186003)(44832011)(30864003)(2906002)(36756003)(40460700003)(356005)(70206006)(82310400005)(4326008)(82740400003)(41300700001)(81166007)(70586007)(8936002)(40480700001)(8676002)(86362001)(316002)(5660300002)(36900700001);\n DIR:OUT; SFP:1101;",
        "X-OriginatorOrg": "amd.com",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "08 May 2023 11:18:39.9186 (UTC)",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n b9a9b8ed-fdd5-470d-845c-08db4fb5f9ab",
        "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=[SATLEXMB03.amd.com]",
        "X-MS-Exchange-CrossTenant-AuthSource": "\n BN8NAM11FT111.eop-nam11.prod.protection.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Anonymous",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "HybridOnPrem",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DM4PR12MB5200",
        "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": "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>\n---\n MAINTAINERS                            |   5 +\n doc/guides/rel_notes/release_23_07.rst |   6 +\n drivers/bus/cdx/bus_cdx_driver.h       | 201 ++++++++++\n drivers/bus/cdx/cdx.c                  | 520 +++++++++++++++++++++++++\n drivers/bus/cdx/cdx_logs.h             |  37 ++\n drivers/bus/cdx/cdx_vfio.c             | 437 +++++++++++++++++++++\n drivers/bus/cdx/meson.build            |  13 +\n drivers/bus/cdx/private.h              |  49 +++\n drivers/bus/cdx/version.map            |  11 +\n drivers/bus/meson.build                |   1 +\n 10 files changed, 1280 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 8df23e5099..1f9b6af9b9 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+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..a5f581dc3d 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 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..7edcb019eb\n--- /dev/null\n+++ b/drivers/bus/cdx/bus_cdx_driver.h\n@@ -0,0 +1,201 @@\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+ *\n+ * CDX bus interface\n+ */\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <limits.h>\n+#include <errno.h>\n+#include <stdint.h>\n+#include <inttypes.h>\n+\n+#include <bus_driver.h>\n+#include <dev_driver.h>\n+#include <rte_debug.h>\n+#include <rte_interrupts.h>\n+#include <rte_dev.h>\n+#include <rte_bus.h>\n+\n+/* Forward declarations */\n+struct rte_cdx_device;\n+struct rte_cdx_driver;\n+\n+#define CDX_MAX_RESOURCE 4\n+\n+/** List of CDX devices */\n+RTE_TAILQ_HEAD(rte_cdx_device_list, rte_cdx_device);\n+/** List of CDX drivers */\n+RTE_TAILQ_HEAD(rte_cdx_driver_list, rte_cdx_driver);\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+/** 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+\tstruct rte_cdx_id id;\t\t\t/**< CDX ID. */\n+\tstruct rte_mem_resource mem_resource[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+ * Structure describing the CDX bus\n+ */\n+struct rte_cdx_bus {\n+\tstruct rte_bus bus;\t\t\t/**< Inherit the generic class */\n+\tstruct rte_cdx_device_list device_list;\t/**< List of CDX devices */\n+\tstruct rte_cdx_driver_list driver_list;\t/**< List of CDX drivers */\n+};\n+\n+/**\n+ * Get Pathname of CDX devices directory.\n+ *\n+ * @return\n+ *   sysfs path for CDX devices.\n+ */\n+__rte_internal\n+const char *rte_cdx_get_sysfs_path(void);\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, negative on error and positive if no driver\n+ *   is found for the device.\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..d479daa315\n--- /dev/null\n+++ b/drivers/bus/cdx/cdx.c\n@@ -0,0 +1,520 @@\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 CDX architecture:\n+ *\n+ *          +--------------------------------------+\n+ *          |   DPDK                               |\n+ *          |                    DPDK CDX drivers  |\n+ *          |                             |        |\n+ *          |                      DPDK CDX bus    |\n+ *          |                             |        |\n+ *          +-----------------------------|--------+\n+ *                                        |\n+ *          +-----------------------------|--------+\n+ *          |    Application CPUs (APU)   |        |\n+ *          |                             |        |\n+ *          |                     VFIO CDX driver  |\n+ *          |     Linux OS                |        |\n+ *          |                      Linux 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+#include <string.h>\n+#include <dirent.h>\n+\n+#include <rte_log.h>\n+#include <rte_bus.h>\n+#include <rte_eal_paging.h>\n+#include <rte_errno.h>\n+#include <rte_devargs.h>\n+#include <rte_malloc.h>\n+#include <rte_memcpy.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 SYSFS_CDX_DEVICES \"/sys/bus/cdx/devices\"\n+#define CDX_BUS_NAME\tcdx\n+#define CDX_DEV_PREFIX\t\"cdx-\"\n+\n+/**\n+ * @file\n+ * CDX probing using Linux sysfs.\n+ */\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+\tchar *name = NULL;\n+\tint ret;\n+\n+\tdev = calloc(1, sizeof(*dev));\n+\tif (!dev)\n+\t\treturn -ENOMEM;\n+\n+\tname = calloc(1, RTE_DEV_NAME_MAX_LEN);\n+\tif (!name) {\n+\t\tret = -ENOMEM;\n+\t\tgoto err;\n+\t}\n+\n+\tdev->device.bus = &rte_cdx_bus.bus;\n+\tmemcpy(name, dev_name, RTE_DEV_NAME_MAX_LEN);\n+\tdev->device.name = 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+\tif (name)\n+\t\tfree(name);\n+\tif (dev)\n+\t\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_get_sysfs_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_get_sysfs_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+const char *\n+rte_cdx_get_sysfs_path(void)\n+{\n+\treturn SYSFS_CDX_DEVICES;\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 int\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->device.name;\n+\tbool already_probed;\n+\tint ret;\n+\n+\tif ((dr == NULL) || (dev == NULL))\n+\t\treturn -EINVAL;\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->device.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+\tif (dev == NULL)\n+\t\treturn -EINVAL;\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->device.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..e5e23d8b94\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 are 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..ae11f589b3\n--- /dev/null\n+++ b/drivers/bus/cdx/cdx_vfio.c\n@@ -0,0 +1,437 @@\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 <string.h>\n+#include <fcntl.h>\n+#include <sys/eventfd.h>\n+#include <sys/socket.h>\n+#include <sys/ioctl.h>\n+#include <sys/mman.h>\n+#include <stdbool.h>\n+\n+#include <rte_log.h>\n+#include <rte_eal_paging.h>\n+#include <rte_malloc.h>\n+#include <rte_vfio.h>\n+#include <rte_eal.h>\n+#include <rte_bus.h>\n+#include <rte_spinlock.h>\n+#include <rte_tailq.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+/**\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[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_rte_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_get_sysfs_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_rte_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_get_sysfs_path(),\n+\t\t\t\tdev_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_get_sysfs_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_get_sysfs_path(),\n+\t\t\t\tcdx_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..c4ca76dc1b\n--- /dev/null\n+++ b/drivers/bus/cdx/private.h\n@@ -0,0 +1,49 @@\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 <stdbool.h>\n+#include <stdio.h>\n+\n+#include \"bus_cdx_driver.h\"\n+\n+extern struct rte_cdx_bus rte_cdx_bus;\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..957fcab978\n--- /dev/null\n+++ b/drivers/bus/cdx/version.map\n@@ -0,0 +1,11 @@\n+INTERNAL {\n+\tglobal:\n+\n+\trte_cdx_get_sysfs_path;\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": [
        "v4",
        "1/4"
    ]
}