get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 115666,
    "url": "https://patches.dpdk.org/api/patches/115666/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1661899911-13086-2-git-send-email-longli@linuxonhyperv.com/",
    "project": {
        "id": 1,
        "url": "https://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": "<1661899911-13086-2-git-send-email-longli@linuxonhyperv.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1661899911-13086-2-git-send-email-longli@linuxonhyperv.com",
    "date": "2022-08-30T22:51:34",
    "name": "[v6,01/18] net/mana: add basic driver, build environment and doc",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "bf9509898daa9f5f2e25e9ac1f5b9b859c69fa11",
    "submitter": {
        "id": 1784,
        "url": "https://patches.dpdk.org/api/people/1784/?format=api",
        "name": "Long Li",
        "email": "longli@linuxonhyperv.com"
    },
    "delegate": {
        "id": 319,
        "url": "https://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1661899911-13086-2-git-send-email-longli@linuxonhyperv.com/mbox/",
    "series": [
        {
            "id": 24471,
            "url": "https://patches.dpdk.org/api/series/24471/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=24471",
            "date": "2022-08-30T22:51:33",
            "name": "Introduce Microsoft Azure Network Adatper (MANA) PMD",
            "version": 6,
            "mbox": "https://patches.dpdk.org/series/24471/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/115666/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/115666/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 1AF29A00C5;\n\tWed, 31 Aug 2022 00:52:03 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 364CC4114B;\n\tWed, 31 Aug 2022 00:51:57 +0200 (CEST)",
            "from linux.microsoft.com (linux.microsoft.com [13.77.154.182])\n by mails.dpdk.org (Postfix) with ESMTP id 31345400D4\n for <dev@dpdk.org>; Wed, 31 Aug 2022 00:51:55 +0200 (CEST)",
            "by linux.microsoft.com (Postfix, from userid 1004)\n id 827AE2045E24; Tue, 30 Aug 2022 15:51:54 -0700 (PDT)"
        ],
        "DKIM-Filter": "OpenDKIM Filter v2.11.0 linux.microsoft.com 827AE2045E24",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxonhyperv.com;\n s=default; t=1661899914;\n bh=u75gqy8/Ko+13yReIyUpCvQSK05wZS0fp5NDz/bbzTo=;\n h=From:To:Cc:Subject:Date:In-Reply-To:References:Reply-To:From;\n b=FfWzX10Bz3tw/DIqFB53D3ozpJDiGOyhUsxXpd35biXi3Bjxl59PGjL4AtoZBuYIs\n JNDRNMWVkOb/GJS813hMF9Ftee3N3WX82URKSICQ60oaZylguD3hT4Ov9otx6yx/qS\n /ptZX3NsjwI2Cr6/E9IJGOQuuzHuNi4ZQjfVDnRk=",
        "From": "longli@linuxonhyperv.com",
        "To": "Ferruh Yigit <ferruh.yigit@xilinx.com>",
        "Cc": "dev@dpdk.org, Ajay Sharma <sharmaajay@microsoft.com>,\n Stephen Hemminger <sthemmin@microsoft.com>, Long Li <longli@microsoft.com>",
        "Subject": "[Patch v6 01/18] net/mana: add basic driver,\n build environment and doc",
        "Date": "Tue, 30 Aug 2022 15:51:34 -0700",
        "Message-Id": "<1661899911-13086-2-git-send-email-longli@linuxonhyperv.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1661899911-13086-1-git-send-email-longli@linuxonhyperv.com>",
        "References": "<1661899911-13086-1-git-send-email-longli@linuxonhyperv.com>",
        "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>",
        "Reply-To": "longli@microsoft.com",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "From: Long Li <longli@microsoft.com>\n\nMANA is a PCI device. It uses IB verbs to access hardware through the\nkernel RDMA layer. This patch introduces build environment and basic\ndevice probe functions.\n\nSigned-off-by: Long Li <longli@microsoft.com>\n---\nChange log:\nv2:\nFix typos.\nMake the driver build only on x86-64 and Linux.\nRemove unused header files.\nChange port definition to uint16_t or uint8_t (for IB).\nUse getline() in place of fgets() to read and truncate a line.\nv3:\nAdd meson build check for required functions from RDMA direct verb header file\nv4:\nRemove extra \"\\n\" in logging code.\nUse \"r\" in place of \"rb\" in fopen() to read text files.\n\n MAINTAINERS                       |   6 +\n doc/guides/nics/features/mana.ini |  10 +\n doc/guides/nics/index.rst         |   1 +\n doc/guides/nics/mana.rst          |  66 +++\n drivers/net/mana/mana.c           | 704 ++++++++++++++++++++++++++++++\n drivers/net/mana/mana.h           | 210 +++++++++\n drivers/net/mana/meson.build      |  44 ++\n drivers/net/mana/mp.c             | 235 ++++++++++\n drivers/net/mana/version.map      |   3 +\n drivers/net/meson.build           |   1 +\n 10 files changed, 1280 insertions(+)\n create mode 100644 doc/guides/nics/features/mana.ini\n create mode 100644 doc/guides/nics/mana.rst\n create mode 100644 drivers/net/mana/mana.c\n create mode 100644 drivers/net/mana/mana.h\n create mode 100644 drivers/net/mana/meson.build\n create mode 100644 drivers/net/mana/mp.c\n create mode 100644 drivers/net/mana/version.map",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 18d9edaf88..b8bda48a33 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -837,6 +837,12 @@ F: buildtools/options-ibverbs-static.sh\n F: doc/guides/nics/mlx5.rst\n F: doc/guides/nics/features/mlx5.ini\n \n+Microsoft mana\n+M: Long Li <longli@microsoft.com>\n+F: drivers/net/mana\n+F: doc/guides/nics/mana.rst\n+F: doc/guides/nics/features/mana.ini\n+\n Microsoft vdev_netvsc - EXPERIMENTAL\n M: Matan Azrad <matan@nvidia.com>\n F: drivers/net/vdev_netvsc/\ndiff --git a/doc/guides/nics/features/mana.ini b/doc/guides/nics/features/mana.ini\nnew file mode 100644\nindex 0000000000..b92a27374c\n--- /dev/null\n+++ b/doc/guides/nics/features/mana.ini\n@@ -0,0 +1,10 @@\n+;\n+; Supported features of the 'mana' network poll mode driver.\n+;\n+; Refer to default.ini for the full list of available PMD features.\n+;\n+[Features]\n+Linux                = Y\n+Multiprocess aware   = Y\n+Usage doc            = Y\n+x86-64               = Y\ndiff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst\nindex 1c94caccea..2725d1d9f0 100644\n--- a/doc/guides/nics/index.rst\n+++ b/doc/guides/nics/index.rst\n@@ -41,6 +41,7 @@ Network Interface Controller Drivers\n     intel_vf\n     kni\n     liquidio\n+    mana\n     memif\n     mlx4\n     mlx5\ndiff --git a/doc/guides/nics/mana.rst b/doc/guides/nics/mana.rst\nnew file mode 100644\nindex 0000000000..40e18fe810\n--- /dev/null\n+++ b/doc/guides/nics/mana.rst\n@@ -0,0 +1,66 @@\n+..  SPDX-License-Identifier: BSD-3-Clause\n+    Copyright 2022 Microsoft Corporation\n+\n+MANA poll mode driver library\n+=============================\n+\n+The MANA poll mode driver library (**librte_net_mana**) implements support\n+for Microsoft Azure Network Adapter VF in SR-IOV context.\n+\n+Features\n+--------\n+\n+Features of the MANA Ethdev PMD are:\n+\n+Prerequisites\n+-------------\n+\n+This driver relies on external libraries and kernel drivers for resources\n+allocations and initialization. The following dependencies are not part of\n+DPDK and must be installed separately:\n+\n+- **libibverbs** (provided by rdma-core package)\n+\n+  User space verbs framework used by librte_net_mana. This library provides\n+  a generic interface between the kernel and low-level user space drivers\n+  such as libmana.\n+\n+  It allows slow and privileged operations (context initialization, hardware\n+  resources allocations) to be managed by the kernel and fast operations to\n+  never leave user space.\n+\n+- **libmana** (provided by rdma-core package)\n+\n+  Low-level user space driver library for Microsoft Azure Network Adapter\n+  devices, it is automatically loaded by libibverbs.\n+\n+- **Kernel modules**\n+\n+  They provide the kernel-side verbs API and low level device drivers that\n+  manage actual hardware initialization and resources sharing with user\n+  space processes.\n+\n+  Unlike most other PMDs, these modules must remain loaded and bound to\n+  their devices:\n+\n+  - mana: Ethernet device driver that provides kernel network interfaces.\n+  - mana_ib: InifiniBand device driver.\n+  - ib_uverbs: user space driver for verbs (entry point for libibverbs).\n+\n+Driver compilation and testing\n+------------------------------\n+\n+Refer to the document :ref:`compiling and testing a PMD for a NIC <pmd_build_and_test>`\n+for details.\n+\n+Netvsc PMD arguments\n+--------------------\n+\n+The user can specify below argument in devargs.\n+\n+#.  ``mac``:\n+\n+    Specify the MAC address for this device. If it is set, the driver\n+    probes and loads the NIC with a matching mac address. If it is not\n+    set, the driver probes on all the NICs on the PCI device. The default\n+    value is not set, meaning all the NICs will be probed and loaded.\ndiff --git a/drivers/net/mana/mana.c b/drivers/net/mana/mana.c\nnew file mode 100644\nindex 0000000000..cb59eb6882\n--- /dev/null\n+++ b/drivers/net/mana/mana.c\n@@ -0,0 +1,704 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2022 Microsoft Corporation\n+ */\n+\n+#include <unistd.h>\n+#include <dirent.h>\n+#include <fcntl.h>\n+#include <sys/mman.h>\n+\n+#include <ethdev_driver.h>\n+#include <ethdev_pci.h>\n+#include <rte_kvargs.h>\n+#include <rte_eal_paging.h>\n+\n+#include <infiniband/verbs.h>\n+#include <infiniband/manadv.h>\n+\n+#include <assert.h>\n+\n+#include \"mana.h\"\n+\n+/* Shared memory between primary/secondary processes, per driver */\n+struct mana_shared_data *mana_shared_data;\n+const struct rte_memzone *mana_shared_mz;\n+static const char *MZ_MANA_SHARED_DATA = \"mana_shared_data\";\n+\n+struct mana_shared_data mana_local_data;\n+\n+/* Spinlock for mana_shared_data */\n+static rte_spinlock_t mana_shared_data_lock = RTE_SPINLOCK_INITIALIZER;\n+\n+/* Allocate a buffer on the stack and fill it with a printf format string. */\n+#define MKSTR(name, ...) \\\n+\tint mkstr_size_##name = snprintf(NULL, 0, \"\" __VA_ARGS__); \\\n+\tchar name[mkstr_size_##name + 1]; \\\n+\t\\\n+\tmemset(name, 0, mkstr_size_##name + 1); \\\n+\tsnprintf(name, sizeof(name), \"\" __VA_ARGS__)\n+\n+int mana_logtype_driver;\n+int mana_logtype_init;\n+\n+const struct eth_dev_ops mana_dev_ops = {\n+};\n+\n+const struct eth_dev_ops mana_dev_sec_ops = {\n+};\n+\n+uint16_t\n+mana_rx_burst_removed(void *dpdk_rxq __rte_unused,\n+\t\t      struct rte_mbuf **pkts __rte_unused,\n+\t\t      uint16_t pkts_n __rte_unused)\n+{\n+\trte_mb();\n+\treturn 0;\n+}\n+\n+uint16_t\n+mana_tx_burst_removed(void *dpdk_rxq __rte_unused,\n+\t\t      struct rte_mbuf **pkts __rte_unused,\n+\t\t      uint16_t pkts_n __rte_unused)\n+{\n+\trte_mb();\n+\treturn 0;\n+}\n+\n+static const char *mana_init_args[] = {\n+\t\"mac\",\n+\tNULL,\n+};\n+\n+/* Support of parsing up to 8 mac address from EAL command line */\n+#define MAX_NUM_ADDRESS 8\n+struct mana_conf {\n+\tstruct rte_ether_addr mac_array[MAX_NUM_ADDRESS];\n+\tunsigned int index;\n+};\n+\n+static int mana_arg_parse_callback(const char *key, const char *val,\n+\t\t\t\t   void *private)\n+{\n+\tstruct mana_conf *conf = (struct mana_conf *)private;\n+\tint ret;\n+\n+\tDRV_LOG(INFO, \"key=%s value=%s index=%d\", key, val, conf->index);\n+\n+\tif (conf->index >= MAX_NUM_ADDRESS) {\n+\t\tDRV_LOG(ERR, \"Exceeding max MAC address\");\n+\t\treturn 1;\n+\t}\n+\n+\tret = rte_ether_unformat_addr(val, &conf->mac_array[conf->index]);\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"Invalid MAC address %s\", val);\n+\t\treturn ret;\n+\t}\n+\n+\tconf->index++;\n+\n+\treturn 0;\n+}\n+\n+static int mana_parse_args(struct rte_devargs *devargs, struct mana_conf *conf)\n+{\n+\tstruct rte_kvargs *kvlist;\n+\tunsigned int arg_count;\n+\tint ret = 0;\n+\n+\tkvlist = rte_kvargs_parse(devargs->args, mana_init_args);\n+\tif (!kvlist) {\n+\t\tDRV_LOG(ERR, \"failed to parse kvargs args=%s\", devargs->args);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\targ_count = rte_kvargs_count(kvlist, mana_init_args[0]);\n+\tif (arg_count > MAX_NUM_ADDRESS) {\n+\t\tret = -EINVAL;\n+\t\tgoto free_kvlist;\n+\t}\n+\tret = rte_kvargs_process(kvlist, mana_init_args[0],\n+\t\t\t\t mana_arg_parse_callback, conf);\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"error parsing args\");\n+\t\tgoto free_kvlist;\n+\t}\n+\n+free_kvlist:\n+\trte_kvargs_free(kvlist);\n+\treturn ret;\n+}\n+\n+static int get_port_mac(struct ibv_device *device, unsigned int port,\n+\t\t\tstruct rte_ether_addr *addr)\n+{\n+\tFILE *file;\n+\tint ret = 0;\n+\tDIR *dir;\n+\tstruct dirent *dent;\n+\tunsigned int dev_port;\n+\tchar mac[20];\n+\n+\tMKSTR(path, \"%s/device/net\", device->ibdev_path);\n+\n+\tdir = opendir(path);\n+\tif (!dir)\n+\t\treturn -ENOENT;\n+\n+\twhile ((dent = readdir(dir))) {\n+\t\tchar *name = dent->d_name;\n+\n+\t\tMKSTR(filepath, \"%s/%s/dev_port\", path, name);\n+\n+\t\t/* Ignore . and .. */\n+\t\tif ((name[0] == '.') &&\n+\t\t    ((name[1] == '\\0') ||\n+\t\t     ((name[1] == '.') && (name[2] == '\\0'))))\n+\t\t\tcontinue;\n+\n+\t\tfile = fopen(filepath, \"r\");\n+\t\tif (!file)\n+\t\t\tcontinue;\n+\n+\t\tret = fscanf(file, \"%u\", &dev_port);\n+\t\tfclose(file);\n+\n+\t\tif (ret != 1)\n+\t\t\tcontinue;\n+\n+\t\t/* Ethernet ports start at 0, IB port start at 1 */\n+\t\tif (dev_port == port - 1) {\n+\t\t\tMKSTR(filepath, \"%s/%s/address\", path, name);\n+\n+\t\t\tfile = fopen(filepath, \"r\");\n+\t\t\tif (!file)\n+\t\t\t\tcontinue;\n+\n+\t\t\tret = fscanf(file, \"%s\", mac);\n+\t\t\tfclose(file);\n+\n+\t\t\tif (ret < 0)\n+\t\t\t\tbreak;\n+\n+\t\t\tret = rte_ether_unformat_addr(mac, addr);\n+\t\t\tif (ret)\n+\t\t\t\tDRV_LOG(ERR, \"unrecognized mac addr %s\", mac);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tclosedir(dir);\n+\treturn ret;\n+}\n+\n+static int mana_ibv_device_to_pci_addr(const struct ibv_device *device,\n+\t\t\t\t       struct rte_pci_addr *pci_addr)\n+{\n+\tFILE *file;\n+\tchar *line = NULL;\n+\tsize_t len = 0;\n+\n+\tMKSTR(path, \"%s/device/uevent\", device->ibdev_path);\n+\n+\tfile = fopen(path, \"r\");\n+\tif (!file)\n+\t\treturn -errno;\n+\n+\twhile (getline(&line, &len, file) != -1) {\n+\t\t/* Extract information. */\n+\t\tif (sscanf(line,\n+\t\t\t   \"PCI_SLOT_NAME=\"\n+\t\t\t   \"%\" SCNx32 \":%\" SCNx8 \":%\" SCNx8 \".%\" SCNx8 \"\\n\",\n+\t\t\t   &pci_addr->domain,\n+\t\t\t   &pci_addr->bus,\n+\t\t\t   &pci_addr->devid,\n+\t\t\t   &pci_addr->function) == 4) {\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tfree(line);\n+\tfclose(file);\n+\treturn 0;\n+}\n+\n+static int mana_proc_priv_init(struct rte_eth_dev *dev)\n+{\n+\tstruct mana_process_priv *priv;\n+\n+\tpriv = rte_zmalloc_socket(\"mana_proc_priv\",\n+\t\t\t\t  sizeof(struct mana_process_priv),\n+\t\t\t\t  RTE_CACHE_LINE_SIZE,\n+\t\t\t\t  dev->device->numa_node);\n+\tif (!priv)\n+\t\treturn -ENOMEM;\n+\n+\tdev->process_private = priv;\n+\treturn 0;\n+}\n+\n+static int mana_map_doorbell_secondary(struct rte_eth_dev *eth_dev, int fd)\n+{\n+\tstruct mana_process_priv *priv = eth_dev->process_private;\n+\n+\tvoid *addr;\n+\n+\taddr = mmap(NULL, rte_mem_page_size(), PROT_WRITE, MAP_SHARED, fd, 0);\n+\tif (addr == MAP_FAILED) {\n+\t\tDRV_LOG(ERR, \"Failed to map secondary doorbell port %u\",\n+\t\t\teth_dev->data->port_id);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tDRV_LOG(INFO, \"Secondary doorbell mapped to %p\", addr);\n+\n+\tpriv->db_page = addr;\n+\n+\treturn 0;\n+}\n+\n+/* Initialize shared data for the driver (all devices) */\n+static int mana_init_shared_data(void)\n+{\n+\tint ret =  0;\n+\tconst struct rte_memzone *secondary_mz;\n+\n+\trte_spinlock_lock(&mana_shared_data_lock);\n+\n+\t/* Skip if shared data is already initialized */\n+\tif (mana_shared_data)\n+\t\tgoto exit;\n+\n+\tif (rte_eal_process_type() == RTE_PROC_PRIMARY) {\n+\t\tmana_shared_mz = rte_memzone_reserve(MZ_MANA_SHARED_DATA,\n+\t\t\t\t\t\t     sizeof(*mana_shared_data),\n+\t\t\t\t\t\t     SOCKET_ID_ANY, 0);\n+\t\tif (!mana_shared_mz) {\n+\t\t\tDRV_LOG(ERR, \"Cannot allocate mana shared data\");\n+\t\t\tret = -rte_errno;\n+\t\t\tgoto exit;\n+\t\t}\n+\n+\t\tmana_shared_data = mana_shared_mz->addr;\n+\t\tmemset(mana_shared_data, 0, sizeof(*mana_shared_data));\n+\t\trte_spinlock_init(&mana_shared_data->lock);\n+\t} else {\n+\t\tsecondary_mz = rte_memzone_lookup(MZ_MANA_SHARED_DATA);\n+\t\tif (!secondary_mz) {\n+\t\t\tDRV_LOG(ERR, \"Cannot attach mana shared data\");\n+\t\t\tret = -rte_errno;\n+\t\t\tgoto exit;\n+\t\t}\n+\n+\t\tmana_shared_data = secondary_mz->addr;\n+\t\tmemset(&mana_local_data, 0, sizeof(mana_local_data));\n+\t}\n+\n+exit:\n+\trte_spinlock_unlock(&mana_shared_data_lock);\n+\n+\treturn ret;\n+}\n+\n+static int mana_init_once(void)\n+{\n+\tint ret;\n+\n+\tret = mana_init_shared_data();\n+\tif (ret)\n+\t\treturn ret;\n+\n+\trte_spinlock_lock(&mana_shared_data->lock);\n+\n+\tswitch (rte_eal_process_type()) {\n+\tcase RTE_PROC_PRIMARY:\n+\t\tif (mana_shared_data->init_done)\n+\t\t\tbreak;\n+\n+\t\tret = mana_mp_init_primary();\n+\t\tif (ret)\n+\t\t\tbreak;\n+\t\tDRV_LOG(ERR, \"MP INIT PRIMARY\");\n+\n+\t\tmana_shared_data->init_done = 1;\n+\t\tbreak;\n+\n+\tcase RTE_PROC_SECONDARY:\n+\n+\t\tif (mana_local_data.init_done)\n+\t\t\tbreak;\n+\n+\t\tret = mana_mp_init_secondary();\n+\t\tif (ret)\n+\t\t\tbreak;\n+\n+\t\tDRV_LOG(ERR, \"MP INIT SECONDARY\");\n+\n+\t\tmana_local_data.init_done = 1;\n+\t\tbreak;\n+\n+\tdefault:\n+\t\t/* Impossible, internal error */\n+\t\tret = -EPROTO;\n+\t\tbreak;\n+\t}\n+\n+\trte_spinlock_unlock(&mana_shared_data->lock);\n+\n+\treturn ret;\n+}\n+\n+static int mana_pci_probe_mac(struct rte_pci_driver *pci_drv __rte_unused,\n+\t\t\t      struct rte_pci_device *pci_dev,\n+\t\t\t      struct rte_ether_addr *mac_addr)\n+{\n+\tstruct ibv_device **ibv_list;\n+\tint ibv_idx;\n+\tstruct ibv_context *ctx;\n+\tstruct ibv_device_attr_ex dev_attr;\n+\tint num_devices;\n+\tint ret = 0;\n+\tuint8_t port;\n+\tstruct mana_priv *priv = NULL;\n+\tstruct rte_eth_dev *eth_dev = NULL;\n+\tbool found_port;\n+\n+\tibv_list = ibv_get_device_list(&num_devices);\n+\tfor (ibv_idx = 0; ibv_idx < num_devices; ibv_idx++) {\n+\t\tstruct ibv_device *ibdev = ibv_list[ibv_idx];\n+\t\tstruct rte_pci_addr pci_addr;\n+\n+\t\tDRV_LOG(INFO, \"Probe device name %s dev_name %s ibdev_path %s\",\n+\t\t\tibdev->name, ibdev->dev_name, ibdev->ibdev_path);\n+\n+\t\tif (mana_ibv_device_to_pci_addr(ibdev, &pci_addr))\n+\t\t\tcontinue;\n+\n+\t\t/* Ignore if this IB device is not this PCI device */\n+\t\tif (pci_dev->addr.domain != pci_addr.domain ||\n+\t\t    pci_dev->addr.bus != pci_addr.bus ||\n+\t\t    pci_dev->addr.devid != pci_addr.devid ||\n+\t\t    pci_dev->addr.function != pci_addr.function)\n+\t\t\tcontinue;\n+\n+\t\tctx = ibv_open_device(ibdev);\n+\t\tif (!ctx) {\n+\t\t\tDRV_LOG(ERR, \"Failed to open IB device %s\",\n+\t\t\t\tibdev->name);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tret = ibv_query_device_ex(ctx, NULL, &dev_attr);\n+\t\tDRV_LOG(INFO, \"dev_attr.orig_attr.phys_port_cnt %u\",\n+\t\t\tdev_attr.orig_attr.phys_port_cnt);\n+\t\tfound_port = false;\n+\n+\t\tfor (port = 1; port <= dev_attr.orig_attr.phys_port_cnt;\n+\t\t     port++) {\n+\t\t\tstruct ibv_parent_domain_init_attr attr = {};\n+\t\t\tstruct rte_ether_addr addr;\n+\t\t\tchar address[64];\n+\t\t\tchar name[RTE_ETH_NAME_MAX_LEN];\n+\n+\t\t\tret = get_port_mac(ibdev, port, &addr);\n+\t\t\tif (ret)\n+\t\t\t\tcontinue;\n+\n+\t\t\tif (mac_addr && !rte_is_same_ether_addr(&addr, mac_addr))\n+\t\t\t\tcontinue;\n+\n+\t\t\trte_ether_format_addr(address, sizeof(address), &addr);\n+\t\t\tDRV_LOG(INFO, \"device located port %u address %s\",\n+\t\t\t\tport, address);\n+\t\t\tfound_port = true;\n+\n+\t\t\tpriv = rte_zmalloc_socket(NULL, sizeof(*priv),\n+\t\t\t\t\t\t  RTE_CACHE_LINE_SIZE,\n+\t\t\t\t\t\t  SOCKET_ID_ANY);\n+\t\t\tif (!priv) {\n+\t\t\t\tret = -ENOMEM;\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\n+\t\t\tsnprintf(name, sizeof(name), \"%s_port%d\",\n+\t\t\t\t pci_dev->device.name, port);\n+\n+\t\t\tif (rte_eal_process_type() == RTE_PROC_SECONDARY) {\n+\t\t\t\tint fd;\n+\n+\t\t\t\teth_dev = rte_eth_dev_attach_secondary(name);\n+\t\t\t\tif (!eth_dev) {\n+\t\t\t\t\tDRV_LOG(ERR, \"Can't attach to dev %s\",\n+\t\t\t\t\t\tname);\n+\t\t\t\t\tret = -ENOMEM;\n+\t\t\t\t\tgoto failed;\n+\t\t\t\t}\n+\n+\t\t\t\teth_dev->device = &pci_dev->device;\n+\t\t\t\teth_dev->dev_ops = &mana_dev_sec_ops;\n+\t\t\t\tret = mana_proc_priv_init(eth_dev);\n+\t\t\t\tif (ret)\n+\t\t\t\t\tgoto failed;\n+\t\t\t\tpriv->process_priv = eth_dev->process_private;\n+\n+\t\t\t\t/* Get the IB FD from the primary process */\n+\t\t\t\tfd = mana_mp_req_verbs_cmd_fd(eth_dev);\n+\t\t\t\tif (fd < 0) {\n+\t\t\t\t\tDRV_LOG(ERR, \"Failed to get FD %d\", fd);\n+\t\t\t\t\tret = -ENODEV;\n+\t\t\t\t\tgoto failed;\n+\t\t\t\t}\n+\n+\t\t\t\tret = mana_map_doorbell_secondary(eth_dev, fd);\n+\t\t\t\tif (ret) {\n+\t\t\t\t\tDRV_LOG(ERR, \"Failed secondary map %d\",\n+\t\t\t\t\t\tfd);\n+\t\t\t\t\tgoto failed;\n+\t\t\t\t}\n+\n+\t\t\t\t/* fd is no not used after mapping doorbell */\n+\t\t\t\tclose(fd);\n+\n+\t\t\t\trte_spinlock_lock(&mana_shared_data->lock);\n+\t\t\t\tmana_shared_data->secondary_cnt++;\n+\t\t\t\tmana_local_data.secondary_cnt++;\n+\t\t\t\trte_spinlock_unlock(&mana_shared_data->lock);\n+\n+\t\t\t\trte_eth_copy_pci_info(eth_dev, pci_dev);\n+\t\t\t\trte_eth_dev_probing_finish(eth_dev);\n+\n+\t\t\t\t/* Impossible to have more than one port\n+\t\t\t\t * matching a MAC address\n+\t\t\t\t */\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\teth_dev = rte_eth_dev_allocate(name);\n+\t\t\tif (!eth_dev) {\n+\t\t\t\tret = -ENOMEM;\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\n+\t\t\teth_dev->data->mac_addrs =\n+\t\t\t\trte_calloc(\"mana_mac\", 1,\n+\t\t\t\t\t   sizeof(struct rte_ether_addr), 0);\n+\t\t\tif (!eth_dev->data->mac_addrs) {\n+\t\t\t\tret = -ENOMEM;\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\n+\t\t\trte_ether_addr_copy(&addr, eth_dev->data->mac_addrs);\n+\n+\t\t\tpriv->ib_pd = ibv_alloc_pd(ctx);\n+\t\t\tif (!priv->ib_pd) {\n+\t\t\t\tDRV_LOG(ERR, \"ibv_alloc_pd failed port %d\", port);\n+\t\t\t\tret = -ENOMEM;\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\n+\t\t\t/* Create a parent domain with the port number */\n+\t\t\tattr.pd = priv->ib_pd;\n+\t\t\tattr.comp_mask = IBV_PARENT_DOMAIN_INIT_ATTR_PD_CONTEXT;\n+\t\t\tattr.pd_context = (void *)(uint64_t)port;\n+\t\t\tpriv->ib_parent_pd = ibv_alloc_parent_domain(ctx, &attr);\n+\t\t\tif (!priv->ib_parent_pd) {\n+\t\t\t\tDRV_LOG(ERR,\n+\t\t\t\t\t\"ibv_alloc_parent_domain failed port %d\",\n+\t\t\t\t\tport);\n+\t\t\t\tret = -ENOMEM;\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\n+\t\t\tpriv->ib_ctx = ctx;\n+\t\t\tpriv->port_id = eth_dev->data->port_id;\n+\t\t\tpriv->dev_port = port;\n+\t\t\teth_dev->data->dev_private = priv;\n+\t\t\tpriv->dev_data = eth_dev->data;\n+\n+\t\t\tpriv->max_rx_queues = dev_attr.orig_attr.max_qp;\n+\t\t\tpriv->max_tx_queues = dev_attr.orig_attr.max_qp;\n+\n+\t\t\tpriv->max_rx_desc =\n+\t\t\t\tRTE_MIN(dev_attr.orig_attr.max_qp_wr,\n+\t\t\t\t\tdev_attr.orig_attr.max_cqe);\n+\t\t\tpriv->max_tx_desc =\n+\t\t\t\tRTE_MIN(dev_attr.orig_attr.max_qp_wr,\n+\t\t\t\t\tdev_attr.orig_attr.max_cqe);\n+\n+\t\t\tpriv->max_send_sge = dev_attr.orig_attr.max_sge;\n+\t\t\tpriv->max_recv_sge = dev_attr.orig_attr.max_sge;\n+\n+\t\t\tpriv->max_mr = dev_attr.orig_attr.max_mr;\n+\t\t\tpriv->max_mr_size = dev_attr.orig_attr.max_mr_size;\n+\n+\t\t\tDRV_LOG(INFO, \"dev %s max queues %d desc %d sge %d\",\n+\t\t\t\tname, priv->max_rx_queues, priv->max_rx_desc,\n+\t\t\t\tpriv->max_send_sge);\n+\n+\t\t\trte_spinlock_lock(&mana_shared_data->lock);\n+\t\t\tmana_shared_data->primary_cnt++;\n+\t\t\trte_spinlock_unlock(&mana_shared_data->lock);\n+\n+\t\t\teth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_RMV;\n+\n+\t\t\teth_dev->device = &pci_dev->device;\n+\t\t\teth_dev->data->dev_flags |=\n+\t\t\t\tRTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;\n+\n+\t\t\tDRV_LOG(INFO, \"device %s at port %u\",\n+\t\t\t\tname, eth_dev->data->port_id);\n+\n+\t\t\teth_dev->rx_pkt_burst = mana_rx_burst_removed;\n+\t\t\teth_dev->tx_pkt_burst = mana_tx_burst_removed;\n+\t\t\teth_dev->dev_ops = &mana_dev_ops;\n+\n+\t\t\trte_eth_copy_pci_info(eth_dev, pci_dev);\n+\t\t\trte_eth_dev_probing_finish(eth_dev);\n+\t\t}\n+\n+\t\t/* Secondary process doesn't need an ibv_ctx. It maps the\n+\t\t * doorbell pages using the IB cmd_fd passed from the primary\n+\t\t * process and send messages to primary process for memory\n+\t\t * registartions.\n+\t\t */\n+\t\tif (!found_port || rte_eal_process_type() == RTE_PROC_SECONDARY)\n+\t\t\tibv_close_device(ctx);\n+\t}\n+\n+\tibv_free_device_list(ibv_list);\n+\treturn 0;\n+\n+failed:\n+\t/* Free the resource for the port failed */\n+\tif (priv) {\n+\t\tif (priv->ib_parent_pd)\n+\t\t\tibv_dealloc_pd(priv->ib_parent_pd);\n+\n+\t\tif (priv->ib_pd)\n+\t\t\tibv_dealloc_pd(priv->ib_pd);\n+\t}\n+\n+\tif (eth_dev)\n+\t\trte_eth_dev_release_port(eth_dev);\n+\n+\trte_free(priv);\n+\n+\tibv_close_device(ctx);\n+\tibv_free_device_list(ibv_list);\n+\n+\treturn ret;\n+}\n+\n+static int mana_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n+\t\t\t  struct rte_pci_device *pci_dev)\n+{\n+\tstruct rte_devargs *args = pci_dev->device.devargs;\n+\tstruct mana_conf conf = {};\n+\tunsigned int i;\n+\tint ret;\n+\n+\tif (args && args->args) {\n+\t\tret = mana_parse_args(args, &conf);\n+\t\tif (ret) {\n+\t\t\tDRV_LOG(ERR, \"failed to parse parameters args = %s\",\n+\t\t\t\targs->args);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\tret = mana_init_once();\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"Failed to init PMD global data %d\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/* If there are no driver parameters, probe on all ports */\n+\tif (!conf.index)\n+\t\treturn mana_pci_probe_mac(pci_drv, pci_dev, NULL);\n+\n+\tfor (i = 0; i < conf.index; i++) {\n+\t\tret = mana_pci_probe_mac(pci_drv, pci_dev, &conf.mac_array[i]);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int mana_dev_uninit(struct rte_eth_dev *dev)\n+{\n+\tRTE_SET_USED(dev);\n+\treturn 0;\n+}\n+\n+static int mana_pci_remove(struct rte_pci_device *pci_dev)\n+{\n+\tif (rte_eal_process_type() == RTE_PROC_PRIMARY) {\n+\t\trte_spinlock_lock(&mana_shared_data_lock);\n+\n+\t\trte_spinlock_lock(&mana_shared_data->lock);\n+\n+\t\tRTE_VERIFY(mana_shared_data->primary_cnt > 0);\n+\t\tmana_shared_data->primary_cnt--;\n+\t\tif (!mana_shared_data->primary_cnt) {\n+\t\t\tDRV_LOG(DEBUG, \"mp uninit primary\");\n+\t\t\tmana_mp_uninit_primary();\n+\t\t}\n+\n+\t\trte_spinlock_unlock(&mana_shared_data->lock);\n+\n+\t\t/* Also free the shared memory if this is the last */\n+\t\tif (!mana_shared_data->primary_cnt) {\n+\t\t\tDRV_LOG(DEBUG, \"free shared memezone data\");\n+\t\t\trte_memzone_free(mana_shared_mz);\n+\t\t}\n+\n+\t\trte_spinlock_unlock(&mana_shared_data_lock);\n+\t} else {\n+\t\trte_spinlock_lock(&mana_shared_data_lock);\n+\n+\t\trte_spinlock_lock(&mana_shared_data->lock);\n+\t\tRTE_VERIFY(mana_shared_data->secondary_cnt > 0);\n+\t\tmana_shared_data->secondary_cnt--;\n+\t\trte_spinlock_unlock(&mana_shared_data->lock);\n+\n+\t\tRTE_VERIFY(mana_local_data.secondary_cnt > 0);\n+\t\tmana_local_data.secondary_cnt--;\n+\t\tif (!mana_local_data.secondary_cnt) {\n+\t\t\tDRV_LOG(DEBUG, \"mp uninit secondary\");\n+\t\t\tmana_mp_uninit_secondary();\n+\t\t}\n+\n+\t\trte_spinlock_unlock(&mana_shared_data_lock);\n+\t}\n+\n+\treturn rte_eth_dev_pci_generic_remove(pci_dev, mana_dev_uninit);\n+}\n+\n+static const struct rte_pci_id mana_pci_id_map[] = {\n+\t{\n+\t\tRTE_PCI_DEVICE(PCI_VENDOR_ID_MICROSOFT,\n+\t\t\t       PCI_DEVICE_ID_MICROSOFT_MANA)\n+\t},\n+};\n+\n+static struct rte_pci_driver mana_pci_driver = {\n+\t.driver = {\n+\t\t.name = \"mana_pci\",\n+\t},\n+\t.id_table = mana_pci_id_map,\n+\t.probe = mana_pci_probe,\n+\t.remove = mana_pci_remove,\n+\t.drv_flags = RTE_PCI_DRV_INTR_RMV,\n+};\n+\n+RTE_INIT(rte_mana_pmd_init)\n+{\n+\trte_pci_register(&mana_pci_driver);\n+}\n+\n+RTE_PMD_EXPORT_NAME(net_mana, __COUNTER__);\n+RTE_PMD_REGISTER_PCI_TABLE(net_mana, mana_pci_id_map);\n+RTE_PMD_REGISTER_KMOD_DEP(net_mana, \"* ib_uverbs & mana_ib\");\n+RTE_LOG_REGISTER_SUFFIX(mana_logtype_init, init, NOTICE);\n+RTE_LOG_REGISTER_SUFFIX(mana_logtype_driver, driver, NOTICE);\ndiff --git a/drivers/net/mana/mana.h b/drivers/net/mana/mana.h\nnew file mode 100644\nindex 0000000000..e30c030b4e\n--- /dev/null\n+++ b/drivers/net/mana/mana.h\n@@ -0,0 +1,210 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2022 Microsoft Corporation\n+ */\n+\n+#ifndef __MANA_H__\n+#define __MANA_H__\n+\n+enum {\n+\tPCI_VENDOR_ID_MICROSOFT = 0x1414,\n+};\n+\n+enum {\n+\tPCI_DEVICE_ID_MICROSOFT_MANA = 0x00ba,\n+};\n+\n+/* Shared data between primary/secondary processes */\n+struct mana_shared_data {\n+\trte_spinlock_t lock;\n+\tint init_done;\n+\tunsigned int primary_cnt;\n+\tunsigned int secondary_cnt;\n+};\n+\n+#define MIN_RX_BUF_SIZE\t1024\n+#define MAX_FRAME_SIZE\tRTE_ETHER_MAX_LEN\n+#define BNIC_MAX_MAC_ADDR 1\n+\n+#define BNIC_DEV_RX_OFFLOAD_SUPPORT ( \\\n+\t\tDEV_RX_OFFLOAD_CHECKSUM | \\\n+\t\tDEV_RX_OFFLOAD_RSS_HASH)\n+\n+#define BNIC_DEV_TX_OFFLOAD_SUPPORT ( \\\n+\t\tRTE_ETH_TX_OFFLOAD_MULTI_SEGS | \\\n+\t\tRTE_ETH_TX_OFFLOAD_IPV4_CKSUM | \\\n+\t\tRTE_ETH_TX_OFFLOAD_TCP_CKSUM | \\\n+\t\tRTE_ETH_TX_OFFLOAD_UDP_CKSUM | \\\n+\t\tRTE_ETH_TX_OFFLOAD_TCP_TSO)\n+\n+#define INDIRECTION_TABLE_NUM_ELEMENTS 64\n+#define TOEPLITZ_HASH_KEY_SIZE_IN_BYTES 40\n+#define BNIC_ETH_RSS_SUPPORT ( \\\n+\tETH_RSS_IPV4 |\t     \\\n+\tETH_RSS_NONFRAG_IPV4_TCP | \\\n+\tETH_RSS_NONFRAG_IPV4_UDP | \\\n+\tETH_RSS_IPV6 |\t     \\\n+\tETH_RSS_NONFRAG_IPV6_TCP | \\\n+\tETH_RSS_NONFRAG_IPV6_UDP)\n+\n+#define MIN_BUFFERS_PER_QUEUE\t\t64\n+#define MAX_RECEIVE_BUFFERS_PER_QUEUE\t256\n+#define MAX_SEND_BUFFERS_PER_QUEUE\t256\n+\n+struct mana_process_priv {\n+\tvoid *db_page;\n+};\n+\n+struct mana_priv {\n+\tstruct rte_eth_dev_data *dev_data;\n+\tstruct mana_process_priv *process_priv;\n+\tint num_queues;\n+\n+\t/* DPDK port */\n+\tuint16_t port_id;\n+\n+\t/* IB device port */\n+\tuint8_t dev_port;\n+\n+\tstruct ibv_context *ib_ctx;\n+\tstruct ibv_pd *ib_pd;\n+\tstruct ibv_pd *ib_parent_pd;\n+\tstruct ibv_rwq_ind_table *ind_table;\n+\tuint8_t ind_table_key[40];\n+\tstruct ibv_qp *rwq_qp;\n+\tvoid *db_page;\n+\tint max_rx_queues;\n+\tint max_tx_queues;\n+\tint max_rx_desc;\n+\tint max_tx_desc;\n+\tint max_send_sge;\n+\tint max_recv_sge;\n+\tint max_mr;\n+\tuint64_t max_mr_size;\n+};\n+\n+struct mana_txq_desc {\n+\tstruct rte_mbuf *pkt;\n+\tuint32_t wqe_size_in_bu;\n+};\n+\n+struct mana_rxq_desc {\n+\tstruct rte_mbuf *pkt;\n+\tuint32_t wqe_size_in_bu;\n+};\n+\n+struct mana_gdma_queue {\n+\tvoid *buffer;\n+\tuint32_t count;\t/* in entries */\n+\tuint32_t size;\t/* in bytes */\n+\tuint32_t id;\n+\tuint32_t head;\n+\tuint32_t tail;\n+};\n+\n+struct mana_stats {\n+\tuint64_t packets;\n+\tuint64_t bytes;\n+\tuint64_t errors;\n+\tuint64_t nombuf;\n+};\n+\n+#define MANA_MR_BTREE_PER_QUEUE_N\t64\n+struct mana_txq {\n+\tstruct mana_priv *priv;\n+\tuint32_t num_desc;\n+\tstruct ibv_cq *cq;\n+\tstruct ibv_qp *qp;\n+\n+\tstruct mana_gdma_queue gdma_sq;\n+\tstruct mana_gdma_queue gdma_cq;\n+\n+\tuint32_t tx_vp_offset;\n+\n+\t/* For storing pending requests */\n+\tstruct mana_txq_desc *desc_ring;\n+\n+\t/* desc_ring_head is where we put pending requests to ring,\n+\t * completion pull off desc_ring_tail\n+\t */\n+\tuint32_t desc_ring_head, desc_ring_tail;\n+\n+\tstruct mana_stats stats;\n+\tunsigned int socket;\n+};\n+\n+struct mana_rxq {\n+\tstruct mana_priv *priv;\n+\tuint32_t num_desc;\n+\tstruct rte_mempool *mp;\n+\tstruct ibv_cq *cq;\n+\tstruct ibv_wq *wq;\n+\n+\t/* For storing pending requests */\n+\tstruct mana_rxq_desc *desc_ring;\n+\n+\t/* desc_ring_head is where we put pending requests to ring,\n+\t * completion pull off desc_ring_tail\n+\t */\n+\tuint32_t desc_ring_head, desc_ring_tail;\n+\n+\tstruct mana_gdma_queue gdma_rq;\n+\tstruct mana_gdma_queue gdma_cq;\n+\n+\tstruct mana_stats stats;\n+\n+\tunsigned int socket;\n+};\n+\n+extern int mana_logtype_driver;\n+extern int mana_logtype_init;\n+\n+#define DRV_LOG(level, fmt, args...) \\\n+\trte_log(RTE_LOG_ ## level, mana_logtype_driver, \"%s(): \" fmt \"\\n\", \\\n+\t\t__func__, ## args)\n+\n+#define PMD_INIT_LOG(level, fmt, args...) \\\n+\trte_log(RTE_LOG_ ## level, mana_logtype_init, \"%s(): \" fmt \"\\n\",\\\n+\t\t__func__, ## args)\n+\n+#define PMD_INIT_FUNC_TRACE() PMD_INIT_LOG(DEBUG, \" >>\")\n+\n+const uint32_t *mana_supported_ptypes(struct rte_eth_dev *dev);\n+\n+uint16_t mana_rx_burst_removed(void *dpdk_rxq, struct rte_mbuf **pkts,\n+\t\t\t       uint16_t pkts_n);\n+\n+uint16_t mana_tx_burst_removed(void *dpdk_rxq, struct rte_mbuf **pkts,\n+\t\t\t       uint16_t pkts_n);\n+\n+/** Request timeout for IPC. */\n+#define MANA_MP_REQ_TIMEOUT_SEC 5\n+\n+/* Request types for IPC. */\n+enum mana_mp_req_type {\n+\tMANA_MP_REQ_VERBS_CMD_FD = 1,\n+\tMANA_MP_REQ_CREATE_MR,\n+\tMANA_MP_REQ_START_RXTX,\n+\tMANA_MP_REQ_STOP_RXTX,\n+};\n+\n+/* Pameters for IPC. */\n+struct mana_mp_param {\n+\tenum mana_mp_req_type type;\n+\tint port_id;\n+\tint result;\n+\n+\t/* MANA_MP_REQ_CREATE_MR */\n+\tuintptr_t addr;\n+\tuint32_t len;\n+};\n+\n+#define MANA_MP_NAME\t\"net_mana_mp\"\n+int mana_mp_init_primary(void);\n+int mana_mp_init_secondary(void);\n+void mana_mp_uninit_primary(void);\n+void mana_mp_uninit_secondary(void);\n+int mana_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev);\n+\n+void mana_mp_req_on_rxtx(struct rte_eth_dev *dev, enum mana_mp_req_type type);\n+\n+#endif\ndiff --git a/drivers/net/mana/meson.build b/drivers/net/mana/meson.build\nnew file mode 100644\nindex 0000000000..81c4118f53\n--- /dev/null\n+++ b/drivers/net/mana/meson.build\n@@ -0,0 +1,44 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2022 Microsoft Corporation\n+\n+if not is_linux or not dpdk_conf.has('RTE_ARCH_X86_64')\n+    build = false\n+    reason = 'mana is supported on Linux X86_64'\n+    subdir_done()\n+endif\n+\n+deps += ['pci', 'bus_pci', 'net', 'eal', 'kvargs']\n+\n+sources += files(\n+\t'mana.c',\n+\t'mp.c',\n+)\n+\n+libnames = ['ibverbs', 'mana' ]\n+foreach libname:libnames\n+    lib = cc.find_library(libname, required:false)\n+    if lib.found()\n+        ext_deps += lib\n+    else\n+        build = false\n+        reason = 'missing dependency, \"' + libname + '\"'\n+        subdir_done()\n+    endif\n+endforeach\n+\n+required_symbols = [\n+    ['infiniband/manadv.h', 'manadv_set_context_attr'],\n+    ['infiniband/manadv.h', 'manadv_init_obj'],\n+    ['infiniband/manadv.h', 'MANADV_CTX_ATTR_BUF_ALLOCATORS'],\n+    ['infiniband/manadv.h', 'MANADV_OBJ_QP'],\n+    ['infiniband/manadv.h', 'MANADV_OBJ_CQ'],\n+    ['infiniband/manadv.h', 'MANADV_OBJ_RWQ'],\n+]\n+\n+foreach arg:required_symbols\n+    if not cc.has_header_symbol(arg[0], arg[1])\n+        build = false\n+        reason = 'missing symbol \"' + arg[1] + '\" in \"' + arg[0] + '\"'\n+        subdir_done()\n+    endif\n+endforeach\ndiff --git a/drivers/net/mana/mp.c b/drivers/net/mana/mp.c\nnew file mode 100644\nindex 0000000000..d7580e8a28\n--- /dev/null\n+++ b/drivers/net/mana/mp.c\n@@ -0,0 +1,235 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2022 Microsoft Corporation\n+ */\n+\n+#include <rte_malloc.h>\n+#include <ethdev_driver.h>\n+#include <rte_log.h>\n+\n+#include <infiniband/verbs.h>\n+\n+#include \"mana.h\"\n+\n+extern struct mana_shared_data *mana_shared_data;\n+\n+static void mp_init_msg(struct rte_mp_msg *msg, enum mana_mp_req_type type,\n+\t\t\tint port_id)\n+{\n+\tstruct mana_mp_param *param;\n+\n+\tstrlcpy(msg->name, MANA_MP_NAME, sizeof(msg->name));\n+\tmsg->len_param = sizeof(*param);\n+\n+\tparam = (struct mana_mp_param *)msg->param;\n+\tparam->type = type;\n+\tparam->port_id = port_id;\n+}\n+\n+static int mana_mp_primary_handle(const struct rte_mp_msg *mp_msg,\n+\t\t\t\t  const void *peer)\n+{\n+\tstruct rte_eth_dev *dev;\n+\tconst struct mana_mp_param *param =\n+\t\t(const struct mana_mp_param *)mp_msg->param;\n+\tstruct rte_mp_msg mp_res = { 0 };\n+\tstruct mana_mp_param *res = (struct mana_mp_param *)mp_res.param;\n+\tint ret;\n+\tstruct mana_priv *priv;\n+\n+\tif (!rte_eth_dev_is_valid_port(param->port_id)) {\n+\t\tDRV_LOG(ERR, \"MP handle port ID %u invalid\", param->port_id);\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tdev = &rte_eth_devices[param->port_id];\n+\tpriv = dev->data->dev_private;\n+\n+\tmp_init_msg(&mp_res, param->type, param->port_id);\n+\n+\tswitch (param->type) {\n+\tcase MANA_MP_REQ_VERBS_CMD_FD:\n+\t\tmp_res.num_fds = 1;\n+\t\tmp_res.fds[0] = priv->ib_ctx->cmd_fd;\n+\t\tres->result = 0;\n+\t\tret = rte_mp_reply(&mp_res, peer);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tDRV_LOG(ERR, \"Port %u unknown primary MP type %u\",\n+\t\t\tparam->port_id, param->type);\n+\t\tret = -EINVAL;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int mana_mp_secondary_handle(const struct rte_mp_msg *mp_msg,\n+\t\t\t\t    const void *peer)\n+{\n+\tstruct rte_mp_msg mp_res = { 0 };\n+\tstruct mana_mp_param *res = (struct mana_mp_param *)mp_res.param;\n+\tconst struct mana_mp_param *param =\n+\t\t(const struct mana_mp_param *)mp_msg->param;\n+\tstruct rte_eth_dev *dev;\n+\tint ret;\n+\n+\tif (!rte_eth_dev_is_valid_port(param->port_id)) {\n+\t\tDRV_LOG(ERR, \"MP handle port ID %u invalid\", param->port_id);\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tdev = &rte_eth_devices[param->port_id];\n+\n+\tmp_init_msg(&mp_res, param->type, param->port_id);\n+\n+\tswitch (param->type) {\n+\tcase MANA_MP_REQ_START_RXTX:\n+\t\tDRV_LOG(INFO, \"Port %u starting datapath\", dev->data->port_id);\n+\n+\t\trte_mb();\n+\n+\t\tres->result = 0;\n+\t\tret = rte_mp_reply(&mp_res, peer);\n+\t\tbreak;\n+\n+\tcase MANA_MP_REQ_STOP_RXTX:\n+\t\tDRV_LOG(INFO, \"Port %u stopping datapath\", dev->data->port_id);\n+\n+\t\tdev->tx_pkt_burst = mana_tx_burst_removed;\n+\t\tdev->rx_pkt_burst = mana_rx_burst_removed;\n+\n+\t\trte_mb();\n+\n+\t\tres->result = 0;\n+\t\tret = rte_mp_reply(&mp_res, peer);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tDRV_LOG(ERR, \"Port %u unknown secondary MP type %u\",\n+\t\t\tparam->port_id, param->type);\n+\t\tret = -EINVAL;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int mana_mp_init_primary(void)\n+{\n+\tint ret;\n+\n+\tret = rte_mp_action_register(MANA_MP_NAME, mana_mp_primary_handle);\n+\tif (ret && rte_errno != ENOTSUP) {\n+\t\tDRV_LOG(ERR, \"Failed to register primary handler %d %d\",\n+\t\t\tret, rte_errno);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void mana_mp_uninit_primary(void)\n+{\n+\trte_mp_action_unregister(MANA_MP_NAME);\n+}\n+\n+int mana_mp_init_secondary(void)\n+{\n+\treturn rte_mp_action_register(MANA_MP_NAME, mana_mp_secondary_handle);\n+}\n+\n+void mana_mp_uninit_secondary(void)\n+{\n+\trte_mp_action_unregister(MANA_MP_NAME);\n+}\n+\n+int mana_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev)\n+{\n+\tstruct rte_mp_msg mp_req = { 0 };\n+\tstruct rte_mp_msg *mp_res;\n+\tstruct rte_mp_reply mp_rep;\n+\tstruct mana_mp_param *res;\n+\tstruct timespec ts = {.tv_sec = MANA_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};\n+\tint ret;\n+\n+\tmp_init_msg(&mp_req, MANA_MP_REQ_VERBS_CMD_FD, dev->data->port_id);\n+\n+\tret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"port %u request to primary process failed\",\n+\t\t\tdev->data->port_id);\n+\t\treturn ret;\n+\t}\n+\n+\tif (mp_rep.nb_received != 1) {\n+\t\tDRV_LOG(ERR, \"primary replied %u messages\", mp_rep.nb_received);\n+\t\tret = -EPROTO;\n+\t\tgoto exit;\n+\t}\n+\n+\tmp_res = &mp_rep.msgs[0];\n+\tres = (struct mana_mp_param *)mp_res->param;\n+\tif (res->result) {\n+\t\tDRV_LOG(ERR, \"failed to get CMD FD, port %u\",\n+\t\t\tdev->data->port_id);\n+\t\tret = res->result;\n+\t\tgoto exit;\n+\t}\n+\n+\tif (mp_res->num_fds != 1) {\n+\t\tDRV_LOG(ERR, \"got FDs %d unexpected\", mp_res->num_fds);\n+\t\tret = -EPROTO;\n+\t\tgoto exit;\n+\t}\n+\n+\tret = mp_res->fds[0];\n+\tDRV_LOG(ERR, \"port %u command FD from primary is %d\",\n+\t\tdev->data->port_id, ret);\n+exit:\n+\tfree(mp_rep.msgs);\n+\treturn ret;\n+}\n+\n+void mana_mp_req_on_rxtx(struct rte_eth_dev *dev, enum mana_mp_req_type type)\n+{\n+\tstruct rte_mp_msg mp_req = { 0 };\n+\tstruct rte_mp_msg *mp_res;\n+\tstruct rte_mp_reply mp_rep;\n+\tstruct mana_mp_param *res;\n+\tstruct timespec ts = {.tv_sec = MANA_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};\n+\tint i, ret;\n+\n+\tif (type != MANA_MP_REQ_START_RXTX && type != MANA_MP_REQ_STOP_RXTX) {\n+\t\tDRV_LOG(ERR, \"port %u unknown request (req_type %d)\",\n+\t\t\tdev->data->port_id, type);\n+\t\treturn;\n+\t}\n+\n+\tif (!mana_shared_data->secondary_cnt)\n+\t\treturn;\n+\n+\tmp_init_msg(&mp_req, type, dev->data->port_id);\n+\n+\tret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);\n+\tif (ret) {\n+\t\tif (rte_errno != ENOTSUP)\n+\t\t\tDRV_LOG(ERR, \"port %u failed to request Rx/Tx (%d)\",\n+\t\t\t\tdev->data->port_id, type);\n+\t\tgoto exit;\n+\t}\n+\tif (mp_rep.nb_sent != mp_rep.nb_received) {\n+\t\tDRV_LOG(ERR, \"port %u not all secondaries responded (%d)\",\n+\t\t\tdev->data->port_id, type);\n+\t\tgoto exit;\n+\t}\n+\tfor (i = 0; i < mp_rep.nb_received; i++) {\n+\t\tmp_res = &mp_rep.msgs[i];\n+\t\tres = (struct mana_mp_param *)mp_res->param;\n+\t\tif (res->result) {\n+\t\t\tDRV_LOG(ERR, \"port %u request failed on secondary %d\",\n+\t\t\t\tdev->data->port_id, i);\n+\t\t\tgoto exit;\n+\t\t}\n+\t}\n+exit:\n+\tfree(mp_rep.msgs);\n+}\ndiff --git a/drivers/net/mana/version.map b/drivers/net/mana/version.map\nnew file mode 100644\nindex 0000000000..c2e0723b4c\n--- /dev/null\n+++ b/drivers/net/mana/version.map\n@@ -0,0 +1,3 @@\n+DPDK_22 {\n+\tlocal: *;\n+};\ndiff --git a/drivers/net/meson.build b/drivers/net/meson.build\nindex 2355d1cde8..0b111a6ebb 100644\n--- a/drivers/net/meson.build\n+++ b/drivers/net/meson.build\n@@ -34,6 +34,7 @@ drivers = [\n         'ixgbe',\n         'kni',\n         'liquidio',\n+        'mana',\n         'memif',\n         'mlx4',\n         'mlx5',\n",
    "prefixes": [
        "v6",
        "01/18"
    ]
}