get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 43079,
    "url": "http://patches.dpdk.org/api/patches/43079/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20180713170644.9306-4-stephen@networkplumber.org/",
    "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": "<20180713170644.9306-4-stephen@networkplumber.org>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20180713170644.9306-4-stephen@networkplumber.org",
    "date": "2018-07-13T17:06:43",
    "name": "[v12,3/4] net/netvsc: add hyper-v netvsc network device",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "0f407b3297e7a1d65fbed4c39efcdb4e43e259da",
    "submitter": {
        "id": 27,
        "url": "http://patches.dpdk.org/api/people/27/?format=api",
        "name": "Stephen Hemminger",
        "email": "stephen@networkplumber.org"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20180713170644.9306-4-stephen@networkplumber.org/mbox/",
    "series": [
        {
            "id": 577,
            "url": "http://patches.dpdk.org/api/series/577/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=577",
            "date": "2018-07-13T17:06:40",
            "name": "Hyper-V netvsc PMD and VMBus",
            "version": 12,
            "mbox": "http://patches.dpdk.org/series/577/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/43079/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/43079/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id E9D3F2D13;\n\tFri, 13 Jul 2018 19:07:00 +0200 (CEST)",
            "from mail-pg1-f172.google.com (mail-pg1-f172.google.com\n\t[209.85.215.172]) by dpdk.org (Postfix) with ESMTP id BB94A2BE3\n\tfor <dev@dpdk.org>; Fri, 13 Jul 2018 19:06:53 +0200 (CEST)",
            "by mail-pg1-f172.google.com with SMTP id r5-v6so5145523pgv.0\n\tfor <dev@dpdk.org>; Fri, 13 Jul 2018 10:06:53 -0700 (PDT)",
            "from xeon-e3.wavecable.com (204-195-22-127.wavecable.com.\n\t[204.195.22.127]) by smtp.gmail.com with ESMTPSA id\n\tr28-v6sm27960150pfd.37.2018.07.13.10.06.49\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tFri, 13 Jul 2018 10:06:49 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=networkplumber-org.20150623.gappssmtp.com; s=20150623;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references;\n\tbh=mpmFfMrX18A2tRxUEuQ4SjL+s600YssvYMgJkiHzhdA=;\n\tb=n1xdUoj/jU7rUx9h55cD364kAhWadd33/RzrhZitZyRtBJqfM3HZfNs2rI4qpLVtPh\n\tMu17XJtkX2MofadtxosUbNaG4I/FySSTYUSwwFFOyyhd6E0boFiDwbh5g/5byXfxbcPR\n\tm8F1vYGYbW9f9KDYTwJrYhRLbLsgpwkdBC6fHuhZIK55p6WhqTNoUx8J9Jb9m1wnEkPh\n\tZ3n0scAAuQxAv/CMlU6uoLjB58NOWN3tyOE2tVeKtthSctdlNXao/6Lj241G53wyLcm7\n\tDeR4D6hYHqSdMiVXkQb7csNlmwGvU+5foPjUuYGiz5IrVsNB098yl99ycqboCBWpWlX6\n\t9gxg==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=mpmFfMrX18A2tRxUEuQ4SjL+s600YssvYMgJkiHzhdA=;\n\tb=P3Z7w3uQNan1DhVlDvcF92U/3m0/EbPaMH0FugP/K4kaWwx+mPAceTVQrXMzlO1zJg\n\ti1VWXIH68TcuKnqB3zEslQUgsWNCM43WSGTjw1yhZkHbh52hUC9pY156u4bMM4Vcjbak\n\tzkrO6uRhrBT+vvVsoiwPqsnpY0RTWhcLUA/RCOYTg1vTjQ/y2u2DHeOYGo0mcLCtUfuR\n\tL2H6HK1qpHNEu3ESvYRy1HS/0FexjCxt8oOer5zv07zcnFioRO/7X6xRIYe9oGJ7cUtq\n\to6XNN5FattE0FkwlGqCWRI573j5f/uXqqCYY1ZL3jP4R4nzF3Yv117biH8cdS+Whjbhi\n\tImjg==",
        "X-Gm-Message-State": "AOUpUlHRuxeWAt5rhwGMJV2m7izBvSMUcYbSArr+TpqxWTL3ZF9bQBYf\n\t3ZTc9eC80dpfcBk5xZlEzZyVp1LW5Co=",
        "X-Google-Smtp-Source": "AAOMgpdm71VgP7tXmw2dfX5bImS8F2dImSL3dYjQToQ6f5Adybs1rmip4ixATL6RKcxAcP/ZH9f90g==",
        "X-Received": "by 2002:a63:a543:: with SMTP id\n\tr3-v6mr6835207pgu.336.1531501610929; \n\tFri, 13 Jul 2018 10:06:50 -0700 (PDT)",
        "From": "Stephen Hemminger <stephen@networkplumber.org>",
        "To": "dev@dpdk.org",
        "Cc": "Stephen Hemminger <stephen@networkplumber.org>,\n\tHaiyang Zhang <haiyangz@microsoft.com>",
        "Date": "Fri, 13 Jul 2018 10:06:43 -0700",
        "Message-Id": "<20180713170644.9306-4-stephen@networkplumber.org>",
        "X-Mailer": "git-send-email 2.18.0",
        "In-Reply-To": "<20180713170644.9306-1-stephen@networkplumber.org>",
        "References": "<20180713170644.9306-1-stephen@networkplumber.org>",
        "Subject": "[dpdk-dev] [PATCH v12 3/4] net/netvsc: add hyper-v netvsc network\n\tdevice",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<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\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "The driver supports Hyper-V networking directly like\nvirtio for KVM or vmxnet3 for VMware.\n\nThis code is based off of the FreeBSD driver. The file and variable\nnames are kept the same to help with understanding (with most of the\nBSD style warts removed).\n\nThis version supports the latest NetVSP 6.1 version and\nolder versions.\n\nSigned-off-by: Haiyang Zhang <haiyangz@microsoft.com>\nSigned-off-by: Stephen Hemminger <stephen@networkplumber.org>\n---\n MAINTAINERS                                   |    8 +\n config/common_base                            |    8 +\n config/common_linuxapp                        |    3 +\n drivers/net/Makefile                          |    1 +\n drivers/net/meson.build                       |    1 +\n drivers/net/netvsc/Makefile                   |   23 +\n drivers/net/netvsc/hn_ethdev.c                |  760 ++++++++++\n drivers/net/netvsc/hn_logs.h                  |   36 +\n drivers/net/netvsc/hn_nvs.c                   |  546 +++++++\n drivers/net/netvsc/hn_nvs.h                   |  229 +++\n drivers/net/netvsc/hn_rndis.c                 | 1101 ++++++++++++++\n drivers/net/netvsc/hn_rndis.h                 |   32 +\n drivers/net/netvsc/hn_rxtx.c                  | 1329 +++++++++++++++++\n drivers/net/netvsc/hn_var.h                   |  153 ++\n drivers/net/netvsc/meson.build                |    7 +\n drivers/net/netvsc/ndis.h                     |  378 +++++\n drivers/net/netvsc/rndis.h                    |  414 +++++\n drivers/net/netvsc/rte_pmd_netvsc_version.map |    5 +\n mk/rte.app.mk                                 |    1 +\n 19 files changed, 5035 insertions(+)\n create mode 100644 drivers/net/netvsc/Makefile\n create mode 100644 drivers/net/netvsc/hn_ethdev.c\n create mode 100644 drivers/net/netvsc/hn_logs.h\n create mode 100644 drivers/net/netvsc/hn_nvs.c\n create mode 100644 drivers/net/netvsc/hn_nvs.h\n create mode 100644 drivers/net/netvsc/hn_rndis.c\n create mode 100644 drivers/net/netvsc/hn_rndis.h\n create mode 100644 drivers/net/netvsc/hn_rxtx.c\n create mode 100644 drivers/net/netvsc/hn_var.h\n create mode 100644 drivers/net/netvsc/meson.build\n create mode 100644 drivers/net/netvsc/ndis.h\n create mode 100644 drivers/net/netvsc/rndis.h\n create mode 100644 drivers/net/netvsc/rte_pmd_netvsc_version.map",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex b0703063edb9..01c65ca4d1f6 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -606,6 +606,14 @@ F: drivers/net/vdev_netvsc/\n F: doc/guides/nics/vdev_netvsc.rst\n F: doc/guides/nics/features/vdev_netvsc.ini\n \n+Microsoft Hyper-V netvsc - EXPERIMENTAL\n+M: Stephen Hemminger <sthemmin@microsoft.com>\n+M: \"K. Y. Srinivasan\" <kys@microsoft.com>\n+M: Haiyang Zhang <haiyangz@microsoft.com>\n+F: drivers/net/hyperv/\n+F: doc/guides/nics/netvsc.rst\n+F: doc/guides/nics/features/netvsc.ini\n+\n Netcope szedata2\n M: Matej Vido <vido@cesnet.cz>\n F: drivers/net/szedata2/\ndiff --git a/config/common_base b/config/common_base\nindex 304a72c6b7a9..201cdf698f9e 100644\n--- a/config/common_base\n+++ b/config/common_base\n@@ -404,7 +404,15 @@ CONFIG_RTE_LIBRTE_MVPP2_PMD=n\n #\n CONFIG_RTE_LIBRTE_VMBUS=n\n \n+#\n+# Compile native PMD for Hyper-V/Azure\n+#\n+CONFIG_RTE_LIBRTE_NETVSC_PMD=n\n+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_RX=n\n+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_TX=n\n+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_DUMP=n\n \n+#\n # Compile virtual device driver for NetVSC on Hyper-V/Azure\n #\n CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD=n\ndiff --git a/config/common_linuxapp b/config/common_linuxapp\nindex 37e8f6958c20..9c5ea9d899b8 100644\n--- a/config/common_linuxapp\n+++ b/config/common_linuxapp\n@@ -26,6 +26,9 @@ CONFIG_RTE_LIBRTE_POWER=y\n CONFIG_RTE_VIRTIO_USER=y\n CONFIG_RTE_PROC_INFO=y\n \n+CONFIG_RTE_LIBRTE_VMBUS=y\n+CONFIG_RTE_LIBRTE_NETVSC_PMD=y\n+\n # NXP DPAA BUS and drivers\n CONFIG_RTE_LIBRTE_DPAA_BUS=y\n CONFIG_RTE_LIBRTE_DPAA_MEMPOOL=y\ndiff --git a/drivers/net/Makefile b/drivers/net/Makefile\nindex 1ae0eaffbd57..664398de983a 100644\n--- a/drivers/net/Makefile\n+++ b/drivers/net/Makefile\n@@ -33,6 +33,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_LIO_PMD) += liquidio\n DIRS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4\n DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5\n DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2\n+DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc\n DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp\n DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt\n DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null\ndiff --git a/drivers/net/meson.build b/drivers/net/meson.build\nindex d19b195f8b17..9c28ed4da424 100644\n--- a/drivers/net/meson.build\n+++ b/drivers/net/meson.build\n@@ -19,6 +19,7 @@ drivers = ['af_packet',\n \t'kni',\n \t'liquidio',\n \t'mvpp2',\n+\t'netvsc',\n \t'nfp',\n \t'null', 'octeontx', 'pcap', 'ring',\n \t'sfc',\ndiff --git a/drivers/net/netvsc/Makefile b/drivers/net/netvsc/Makefile\nnew file mode 100644\nindex 000000000000..3c713af3c8fc\n--- /dev/null\n+++ b/drivers/net/netvsc/Makefile\n@@ -0,0 +1,23 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+\n+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+LIB = librte_pmd_netvsc.a\n+\n+CFLAGS += -O3 $(WERROR_FLAGS)\n+CFLAGS += -DALLOW_EXPERIMENTAL_API\n+\n+EXPORT_MAP := rte_pmd_netvsc_version.map\n+\n+LIBABIVER := 1\n+\n+SRCS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += hn_ethdev.c\n+SRCS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += hn_rxtx.c\n+SRCS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += hn_rndis.c\n+SRCS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += hn_nvs.c\n+\n+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring\n+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs\n+LDLIBS += -lrte_bus_vmbus\n+\n+include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/drivers/net/netvsc/hn_ethdev.c b/drivers/net/netvsc/hn_ethdev.c\nnew file mode 100644\nindex 000000000000..c9608ac6845d\n--- /dev/null\n+++ b/drivers/net/netvsc/hn_ethdev.c\n@@ -0,0 +1,760 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2016-2018 Microsoft Corporation\n+ * Copyright(c) 2013-2016 Brocade Communications Systems, Inc.\n+ * All rights reserved.\n+ */\n+\n+#include <stdint.h>\n+#include <string.h>\n+#include <stdio.h>\n+#include <errno.h>\n+#include <unistd.h>\n+\n+#include <rte_ethdev.h>\n+#include <rte_memcpy.h>\n+#include <rte_string_fns.h>\n+#include <rte_memzone.h>\n+#include <rte_malloc.h>\n+#include <rte_atomic.h>\n+#include <rte_branch_prediction.h>\n+#include <rte_ether.h>\n+#include <rte_ethdev_driver.h>\n+#include <rte_cycles.h>\n+#include <rte_errno.h>\n+#include <rte_memory.h>\n+#include <rte_atomic.h>\n+#include <rte_eal.h>\n+#include <rte_dev.h>\n+#include <rte_bus_vmbus.h>\n+\n+#include \"hn_logs.h\"\n+#include \"hn_var.h\"\n+#include \"hn_rndis.h\"\n+#include \"hn_nvs.h\"\n+#include \"ndis.h\"\n+\n+#define HN_TX_OFFLOAD_CAPS (DEV_TX_OFFLOAD_IPV4_CKSUM | \\\n+\t\t\t    DEV_TX_OFFLOAD_TCP_CKSUM  | \\\n+\t\t\t    DEV_TX_OFFLOAD_UDP_CKSUM  | \\\n+\t\t\t    DEV_TX_OFFLOAD_TCP_TSO    | \\\n+\t\t\t    DEV_TX_OFFLOAD_MULTI_SEGS | \\\n+\t\t\t    DEV_TX_OFFLOAD_VLAN_INSERT)\n+\n+#define HN_RX_OFFLOAD_CAPS (DEV_RX_OFFLOAD_CHECKSUM | \\\n+\t\t\t    DEV_RX_OFFLOAD_VLAN_STRIP | \\\n+\t\t\t    DEV_RX_OFFLOAD_CRC_STRIP)\n+\n+int hn_logtype_init;\n+int hn_logtype_driver;\n+\n+struct hn_xstats_name_off {\n+\tchar name[RTE_ETH_XSTATS_NAME_SIZE];\n+\tunsigned int offset;\n+};\n+\n+static const struct hn_xstats_name_off hn_stat_strings[] = {\n+\t{ \"good_packets\",           offsetof(struct hn_stats, packets) },\n+\t{ \"good_bytes\",             offsetof(struct hn_stats, bytes) },\n+\t{ \"errors\",                 offsetof(struct hn_stats, errors) },\n+\t{ \"allocation_failed\",      offsetof(struct hn_stats, nomemory) },\n+\t{ \"multicast_packets\",      offsetof(struct hn_stats, multicast) },\n+\t{ \"broadcast_packets\",      offsetof(struct hn_stats, broadcast) },\n+\t{ \"undersize_packets\",      offsetof(struct hn_stats, size_bins[0]) },\n+\t{ \"size_64_packets\",        offsetof(struct hn_stats, size_bins[1]) },\n+\t{ \"size_65_127_packets\",    offsetof(struct hn_stats, size_bins[2]) },\n+\t{ \"size_128_255_packets\",   offsetof(struct hn_stats, size_bins[3]) },\n+\t{ \"size_256_511_packets\",   offsetof(struct hn_stats, size_bins[4]) },\n+\t{ \"size_512_1023_packets\",  offsetof(struct hn_stats, size_bins[5]) },\n+\t{ \"size_1024_1518_packets\", offsetof(struct hn_stats, size_bins[6]) },\n+\t{ \"size_1519_max_packets\",  offsetof(struct hn_stats, size_bins[7]) },\n+};\n+\n+static struct rte_eth_dev *\n+eth_dev_vmbus_allocate(struct rte_vmbus_device *dev, size_t private_data_size)\n+{\n+\tstruct rte_eth_dev *eth_dev;\n+\tconst char *name;\n+\n+\tif (!dev)\n+\t\treturn NULL;\n+\n+\tname = dev->device.name;\n+\n+\tif (rte_eal_process_type() == RTE_PROC_PRIMARY) {\n+\t\teth_dev = rte_eth_dev_allocate(name);\n+\t\tif (!eth_dev) {\n+\t\t\tPMD_DRV_LOG(NOTICE, \"can not allocate rte ethdev\");\n+\t\t\treturn NULL;\n+\t\t}\n+\n+\t\tif (private_data_size) {\n+\t\t\teth_dev->data->dev_private\n+\t\t\t\t= rte_zmalloc_socket(name, private_data_size,\n+\t\t\t\t\t\t     RTE_CACHE_LINE_SIZE, dev->device.numa_node);\n+\t\t\tif (!eth_dev->data->dev_private) {\n+\t\t\t\tPMD_DRV_LOG(NOTICE, \"can not allocate driver data\");\n+\t\t\t\trte_eth_dev_release_port(eth_dev);\n+\t\t\t\treturn NULL;\n+\t\t\t}\n+\t\t}\n+\t} else {\n+\t\teth_dev = rte_eth_dev_attach_secondary(name);\n+\t\tif (!eth_dev) {\n+\t\t\tPMD_DRV_LOG(NOTICE, \"can not attach secondary\");\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n+\teth_dev->device = &dev->device;\n+\teth_dev->intr_handle = &dev->intr_handle;\n+\n+\treturn eth_dev;\n+}\n+\n+static void\n+eth_dev_vmbus_release(struct rte_eth_dev *eth_dev)\n+{\n+\t/* free ether device */\n+\trte_eth_dev_release_port(eth_dev);\n+\n+\tif (rte_eal_process_type() == RTE_PROC_PRIMARY)\n+\t\trte_free(eth_dev->data->dev_private);\n+\n+\teth_dev->data->dev_private = NULL;\n+\n+\t/*\n+\t * Secondary process will check the name to attach.\n+\t * Clear this field to avoid attaching a released ports.\n+\t */\n+\teth_dev->data->name[0] = '\\0';\n+\n+\teth_dev->device = NULL;\n+\teth_dev->intr_handle = NULL;\n+}\n+\n+/* Update link status.\n+ * Note: the DPDK definition of \"wait_to_complete\"\n+ *   means block this call until link is up.\n+ *   which is not worth supporting.\n+ */\n+static int\n+hn_dev_link_update(struct rte_eth_dev *dev,\n+\t\t   __rte_unused int wait_to_complete)\n+{\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\tstruct rte_eth_link link, old;\n+\tint error;\n+\n+\told = dev->data->dev_link;\n+\n+\terror = hn_rndis_get_linkstatus(hv);\n+\tif (error)\n+\t\treturn error;\n+\n+\thn_rndis_get_linkspeed(hv);\n+\n+\tlink = (struct rte_eth_link) {\n+\t\t.link_duplex = ETH_LINK_FULL_DUPLEX,\n+\t\t.link_autoneg = ETH_LINK_SPEED_FIXED,\n+\t\t.link_speed = hv->link_speed / 10000,\n+\t};\n+\n+\tif (hv->link_status == NDIS_MEDIA_STATE_CONNECTED)\n+\t\tlink.link_status = ETH_LINK_UP;\n+\telse\n+\t\tlink.link_status = ETH_LINK_DOWN;\n+\n+\tif (old.link_status == link.link_status)\n+\t\treturn 0;\n+\n+\tPMD_INIT_LOG(DEBUG, \"Port %d is %s\", dev->data->port_id,\n+\t\t     (link.link_status == ETH_LINK_UP) ? \"up\" : \"down\");\n+\n+\treturn rte_eth_linkstatus_set(dev, &link);\n+}\n+\n+static void hn_dev_info_get(struct rte_eth_dev *dev,\n+\t\t\t    struct rte_eth_dev_info *dev_info)\n+{\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\n+\tdev_info->speed_capa = ETH_LINK_SPEED_10G;\n+\tdev_info->min_rx_bufsize = HN_MIN_RX_BUF_SIZE;\n+\tdev_info->max_rx_pktlen  = HN_MAX_XFER_LEN;\n+\tdev_info->max_mac_addrs  = 1;\n+\n+\tdev_info->hash_key_size = NDIS_HASH_KEYSIZE_TOEPLITZ;\n+\tdev_info->flow_type_rss_offloads\n+\t\t= ETH_RSS_IPV4 | ETH_RSS_IPV6 | ETH_RSS_TCP | ETH_RSS_UDP;\n+\n+\tdev_info->max_rx_queues = hv->max_queues;\n+\tdev_info->max_tx_queues = hv->max_queues;\n+\n+\thn_rndis_get_offload(hv, dev_info);\n+}\n+\n+static void\n+hn_dev_promiscuous_enable(struct rte_eth_dev *dev)\n+{\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\n+\thn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_PROMISCUOUS);\n+}\n+\n+static void\n+hn_dev_promiscuous_disable(struct rte_eth_dev *dev)\n+{\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\tuint32_t filter;\n+\n+\tfilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST;\n+\tif (dev->data->all_multicast)\n+\t\tfilter |= NDIS_PACKET_TYPE_ALL_MULTICAST;\n+\thn_rndis_set_rxfilter(hv, filter);\n+}\n+\n+static void\n+hn_dev_allmulticast_enable(struct rte_eth_dev *dev)\n+{\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\n+\thn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_DIRECTED |\n+\t\t\t      NDIS_PACKET_TYPE_ALL_MULTICAST |\n+\t\t\tNDIS_PACKET_TYPE_BROADCAST);\n+}\n+\n+static void\n+hn_dev_allmulticast_disable(struct rte_eth_dev *dev)\n+{\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\n+\thn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_DIRECTED |\n+\t\t\t     NDIS_PACKET_TYPE_BROADCAST);\n+}\n+\n+/* Setup shared rx/tx queue data */\n+static int hn_subchan_configure(struct hn_data *hv,\n+\t\t\t\tuint32_t subchan)\n+{\n+\tstruct vmbus_channel *primary = hn_primary_chan(hv);\n+\tint err;\n+\tunsigned int retry = 0;\n+\n+\tPMD_DRV_LOG(DEBUG,\n+\t\t    \"open %u subchannels\", subchan);\n+\n+\t/* Send create sub channels command */\n+\terr = hn_nvs_alloc_subchans(hv, &subchan);\n+\tif (err)\n+\t\treturn  err;\n+\n+\twhile (subchan > 0) {\n+\t\tstruct vmbus_channel *new_sc;\n+\t\tuint16_t chn_index;\n+\n+\t\terr = rte_vmbus_subchan_open(primary, &new_sc);\n+\t\tif (err == -ENOENT && ++retry < 1000) {\n+\t\t\t/* This can happen if not ready yet */\n+\t\t\trte_delay_ms(10);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (err) {\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t    \"open subchannel failed: %d\", err);\n+\t\t\treturn err;\n+\t\t}\n+\n+\t\tretry = 0;\n+\t\tchn_index = rte_vmbus_sub_channel_index(new_sc);\n+\t\tif (chn_index == 0 || chn_index > hv->max_queues) {\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t    \"Invalid subchannel offermsg channel %u\",\n+\t\t\t\t    chn_index);\n+\t\t\treturn -EIO;\n+\t\t}\n+\n+\t\tPMD_DRV_LOG(DEBUG, \"new sub channel %u\", chn_index);\n+\t\thv->channels[chn_index] = new_sc;\n+\t\t--subchan;\n+\t}\n+\n+\treturn err;\n+}\n+\n+static int hn_dev_configure(struct rte_eth_dev *dev)\n+{\n+\tconst struct rte_eth_conf *dev_conf = &dev->data->dev_conf;\n+\tconst struct rte_eth_rxmode *rxmode = &dev_conf->rxmode;\n+\tconst struct rte_eth_txmode *txmode = &dev_conf->txmode;\n+\n+\tconst struct rte_eth_rss_conf *rss_conf\n+\t\t= &dev_conf->rx_adv_conf.rss_conf;\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\tuint64_t unsupported;\n+\tint err, subchan;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tunsupported = txmode->offloads & ~HN_TX_OFFLOAD_CAPS;\n+\tif (unsupported) {\n+\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t    \"unsupported TX offload: %#\" PRIx64,\n+\t\t\t    unsupported);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tunsupported = rxmode->offloads & ~HN_RX_OFFLOAD_CAPS;\n+\tif (unsupported) {\n+\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t    \"unsupported RX offload: %#\" PRIx64,\n+\t\t\t    rxmode->offloads);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\terr = hn_rndis_conf_offload(hv, txmode->offloads,\n+\t\t\t\t    rxmode->offloads);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t    \"offload configure failed\");\n+\t\treturn err;\n+\t}\n+\n+\thv->num_queues = RTE_MAX(dev->data->nb_rx_queues,\n+\t\t\t\t dev->data->nb_tx_queues);\n+\tsubchan = hv->num_queues - 1;\n+\tif (subchan > 0) {\n+\t\terr = hn_subchan_configure(hv, subchan);\n+\t\tif (err) {\n+\t\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t\t    \"subchannel configuration failed\");\n+\t\t\treturn err;\n+\t\t}\n+\n+\t\terr = hn_rndis_conf_rss(hv, rss_conf);\n+\t\tif (err) {\n+\t\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t\t    \"rss configuration failed\");\n+\t\t\treturn err;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int hn_dev_stats_get(struct rte_eth_dev *dev,\n+\t\t\t    struct rte_eth_stats *stats)\n+{\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < dev->data->nb_tx_queues; i++) {\n+\t\tconst struct hn_tx_queue *txq = dev->data->tx_queues[i];\n+\n+\t\tif (!txq)\n+\t\t\tcontinue;\n+\n+\t\tstats->opackets += txq->stats.packets;\n+\t\tstats->obytes += txq->stats.bytes;\n+\t\tstats->oerrors += txq->stats.errors + txq->stats.nomemory;\n+\n+\t\tif (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {\n+\t\t\tstats->q_opackets[i] = txq->stats.packets;\n+\t\t\tstats->q_obytes[i] = txq->stats.bytes;\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < dev->data->nb_rx_queues; i++) {\n+\t\tconst struct hn_rx_queue *rxq = dev->data->rx_queues[i];\n+\n+\t\tif (!rxq)\n+\t\t\tcontinue;\n+\n+\t\tstats->ipackets += rxq->stats.packets;\n+\t\tstats->ibytes += rxq->stats.bytes;\n+\t\tstats->ierrors += rxq->stats.errors;\n+\t\tstats->imissed += rxq->ring_full;\n+\n+\t\tif (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {\n+\t\t\tstats->q_ipackets[i] = rxq->stats.packets;\n+\t\t\tstats->q_ibytes[i] = rxq->stats.bytes;\n+\t\t}\n+\t}\n+\n+\tstats->rx_nombuf = dev->data->rx_mbuf_alloc_failed;\n+\treturn 0;\n+}\n+\n+static void\n+hn_dev_stats_reset(struct rte_eth_dev *dev)\n+{\n+\tunsigned int i;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tfor (i = 0; i < dev->data->nb_tx_queues; i++) {\n+\t\tstruct hn_tx_queue *txq = dev->data->tx_queues[i];\n+\n+\t\tif (!txq)\n+\t\t\tcontinue;\n+\t\tmemset(&txq->stats, 0, sizeof(struct hn_stats));\n+\t}\n+\n+\tfor (i = 0; i < dev->data->nb_rx_queues; i++) {\n+\t\tstruct hn_rx_queue *rxq = dev->data->rx_queues[i];\n+\n+\t\tif (!rxq)\n+\t\t\tcontinue;\n+\n+\t\tmemset(&rxq->stats, 0, sizeof(struct hn_stats));\n+\t\trxq->ring_full = 0;\n+\t}\n+}\n+\n+static int\n+hn_dev_xstats_get_names(struct rte_eth_dev *dev,\n+\t\t\tstruct rte_eth_xstat_name *xstats_names,\n+\t\t\t__rte_unused unsigned int limit)\n+{\n+\tunsigned int i, t, count = 0;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tif (!xstats_names)\n+\t\treturn dev->data->nb_tx_queues * RTE_DIM(hn_stat_strings)\n+\t\t\t+ dev->data->nb_rx_queues * RTE_DIM(hn_stat_strings);\n+\n+\t/* Note: limit checked in rte_eth_xstats_names() */\n+\tfor (i = 0; i < dev->data->nb_tx_queues; i++) {\n+\t\tconst struct hn_tx_queue *txq = dev->data->tx_queues[i];\n+\n+\t\tif (!txq)\n+\t\t\tcontinue;\n+\n+\t\tfor (t = 0; t < RTE_DIM(hn_stat_strings); t++)\n+\t\t\tsnprintf(xstats_names[count++].name,\n+\t\t\t\t RTE_ETH_XSTATS_NAME_SIZE,\n+\t\t\t\t \"tx_q%u_%s\", i, hn_stat_strings[t].name);\n+\t}\n+\n+\tfor (i = 0; i < dev->data->nb_rx_queues; i++)  {\n+\t\tconst struct hn_rx_queue *rxq = dev->data->rx_queues[i];\n+\n+\t\tif (!rxq)\n+\t\t\tcontinue;\n+\n+\t\tfor (t = 0; t < RTE_DIM(hn_stat_strings); t++)\n+\t\t\tsnprintf(xstats_names[count++].name,\n+\t\t\t\t RTE_ETH_XSTATS_NAME_SIZE,\n+\t\t\t\t \"rx_q%u_%s\", i,\n+\t\t\t\t hn_stat_strings[t].name);\n+\t}\n+\n+\treturn count;\n+}\n+\n+static int\n+hn_dev_xstats_get(struct rte_eth_dev *dev,\n+\t\t  struct rte_eth_xstat *xstats,\n+\t\t  unsigned int n)\n+{\n+\tunsigned int i, t, count = 0;\n+\n+\tconst unsigned int nstats\n+\t\t= dev->data->nb_tx_queues * RTE_DIM(hn_stat_strings)\n+\t\t+ dev->data->nb_rx_queues * RTE_DIM(hn_stat_strings);\n+\tconst char *stats;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tif (n < nstats)\n+\t\treturn nstats;\n+\n+\tfor (i = 0; i < dev->data->nb_tx_queues; i++) {\n+\t\tconst struct hn_tx_queue *txq = dev->data->tx_queues[i];\n+\n+\t\tif (!txq)\n+\t\t\tcontinue;\n+\n+\t\tstats = (const char *)&txq->stats;\n+\t\tfor (t = 0; t < RTE_DIM(hn_stat_strings); t++)\n+\t\t\txstats[count++].value = *(const uint64_t *)\n+\t\t\t\t(stats + hn_stat_strings[t].offset);\n+\t}\n+\n+\tfor (i = 0; i < dev->data->nb_rx_queues; i++) {\n+\t\tconst struct hn_rx_queue *rxq = dev->data->rx_queues[i];\n+\n+\t\tif (!rxq)\n+\t\t\tcontinue;\n+\n+\t\tstats = (const char *)&rxq->stats;\n+\t\tfor (t = 0; t < RTE_DIM(hn_stat_strings); t++)\n+\t\t\txstats[count++].value = *(const uint64_t *)\n+\t\t\t\t(stats + hn_stat_strings[t].offset);\n+\t}\n+\n+\treturn count;\n+}\n+\n+static int\n+hn_dev_start(struct rte_eth_dev *dev)\n+{\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\t/* check if lsc interrupt feature is enabled */\n+\tif (dev->data->dev_conf.intr_conf.lsc) {\n+\t\tPMD_DRV_LOG(ERR, \"link status not supported yet\");\n+\t\treturn -ENOTSUP;\n+\t}\n+\n+\treturn hn_rndis_set_rxfilter(hv,\n+\t\t\t\t     NDIS_PACKET_TYPE_BROADCAST |\n+\t\t\t\t     NDIS_PACKET_TYPE_ALL_MULTICAST |\n+\t\t\t\t     NDIS_PACKET_TYPE_DIRECTED);\n+}\n+\n+static void\n+hn_dev_stop(struct rte_eth_dev *dev)\n+{\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\thn_rndis_set_rxfilter(hv, 0);\n+}\n+\n+static void\n+hn_dev_close(struct rte_eth_dev *dev __rte_unused)\n+{\n+\tPMD_INIT_LOG(DEBUG, \"close\");\n+}\n+\n+static const struct eth_dev_ops hn_eth_dev_ops = {\n+\t.dev_configure\t\t= hn_dev_configure,\n+\t.dev_start\t\t= hn_dev_start,\n+\t.dev_stop\t\t= hn_dev_stop,\n+\t.dev_close\t\t= hn_dev_close,\n+\t.dev_infos_get\t\t= hn_dev_info_get,\n+\t.promiscuous_enable     = hn_dev_promiscuous_enable,\n+\t.promiscuous_disable    = hn_dev_promiscuous_disable,\n+\t.allmulticast_enable    = hn_dev_allmulticast_enable,\n+\t.allmulticast_disable   = hn_dev_allmulticast_disable,\n+\t.tx_queue_setup\t\t= hn_dev_tx_queue_setup,\n+\t.tx_queue_release\t= hn_dev_tx_queue_release,\n+\t.rx_queue_setup\t\t= hn_dev_rx_queue_setup,\n+\t.rx_queue_release\t= hn_dev_rx_queue_release,\n+\t.link_update\t\t= hn_dev_link_update,\n+\t.stats_get\t\t= hn_dev_stats_get,\n+\t.xstats_get\t\t= hn_dev_xstats_get,\n+\t.xstats_get_names\t= hn_dev_xstats_get_names,\n+\t.stats_reset            = hn_dev_stats_reset,\n+\t.xstats_reset\t\t= hn_dev_stats_reset,\n+};\n+\n+/*\n+ * Setup connection between PMD and kernel.\n+ */\n+static int\n+hn_attach(struct hn_data *hv, unsigned int mtu)\n+{\n+\tint error;\n+\n+\t/* Attach NVS */\n+\terror = hn_nvs_attach(hv, mtu);\n+\tif (error)\n+\t\tgoto failed_nvs;\n+\n+\t/* Attach RNDIS */\n+\terror = hn_rndis_attach(hv);\n+\tif (error)\n+\t\tgoto failed_rndis;\n+\n+\t/*\n+\t * NOTE:\n+\t * Under certain conditions on certain versions of Hyper-V,\n+\t * the RNDIS rxfilter is _not_ zero on the hypervisor side\n+\t * after the successful RNDIS initialization.\n+\t */\n+\thn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_NONE);\n+\treturn 0;\n+failed_rndis:\n+\thn_nvs_detach(hv);\n+failed_nvs:\n+\treturn error;\n+}\n+\n+static void\n+hn_detach(struct hn_data *hv)\n+{\n+\thn_nvs_detach(hv);\n+\thn_rndis_detach(hv);\n+}\n+\n+static int\n+eth_hn_dev_init(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct hn_data *hv = eth_dev->data->dev_private;\n+\tstruct rte_device *device = eth_dev->device;\n+\tstruct rte_vmbus_device *vmbus;\n+\tunsigned int rxr_cnt;\n+\tint err, max_chan;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tvmbus = container_of(device, struct rte_vmbus_device, device);\n+\teth_dev->dev_ops = &hn_eth_dev_ops;\n+\teth_dev->tx_pkt_burst = &hn_xmit_pkts;\n+\teth_dev->rx_pkt_burst = &hn_recv_pkts;\n+\n+\t/*\n+\t * for secondary processes, we don't initialize any further as primary\n+\t * has already done this work.\n+\t */\n+\tif (rte_eal_process_type() != RTE_PROC_PRIMARY)\n+\t\treturn 0;\n+\n+\t/* Since Hyper-V only supports one MAC address, just use local data */\n+\teth_dev->data->mac_addrs = &hv->mac_addr;\n+\n+\thv->vmbus = vmbus;\n+\thv->rxbuf_res = &vmbus->resource[HV_RECV_BUF_MAP];\n+\thv->chim_res  = &vmbus->resource[HV_SEND_BUF_MAP];\n+\thv->port_id = eth_dev->data->port_id;\n+\n+\t/* Initialize primary channel input for control operations */\n+\terr = rte_vmbus_chan_open(vmbus, &hv->channels[0]);\n+\tif (err)\n+\t\treturn err;\n+\n+\thv->primary = hn_rx_queue_alloc(hv, 0,\n+\t\t\t\t\teth_dev->device->numa_node);\n+\n+\tif (!hv->primary)\n+\t\treturn -ENOMEM;\n+\n+\terr = hn_attach(hv, ETHER_MTU);\n+\tif  (err)\n+\t\tgoto failed;\n+\n+\terr = hn_tx_pool_init(eth_dev);\n+\tif (err)\n+\t\tgoto failed;\n+\n+\terr = hn_rndis_get_eaddr(hv, hv->mac_addr.addr_bytes);\n+\tif (err)\n+\t\tgoto failed;\n+\n+\tmax_chan = rte_vmbus_max_channels(vmbus);\n+\tPMD_INIT_LOG(DEBUG, \"VMBus max channels %d\", max_chan);\n+\tif (max_chan <= 0)\n+\t\tgoto failed;\n+\n+\tif (hn_rndis_query_rsscaps(hv, &rxr_cnt) != 0)\n+\t\trxr_cnt = 1;\n+\n+\thv->max_queues = RTE_MIN(rxr_cnt, (unsigned int)max_chan);\n+\n+\treturn 0;\n+\n+failed:\n+\tPMD_INIT_LOG(NOTICE, \"device init failed\");\n+\n+\thn_detach(hv);\n+\treturn err;\n+}\n+\n+static int\n+eth_hn_dev_uninit(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct hn_data *hv = eth_dev->data->dev_private;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tif (rte_eal_process_type() != RTE_PROC_PRIMARY)\n+\t\treturn 0;\n+\n+\thn_dev_stop(eth_dev);\n+\thn_dev_close(eth_dev);\n+\n+\teth_dev->dev_ops = NULL;\n+\teth_dev->tx_pkt_burst = NULL;\n+\teth_dev->rx_pkt_burst = NULL;\n+\n+\thn_detach(hv);\n+\trte_vmbus_chan_close(hv->primary->chan);\n+\trte_free(hv->primary);\n+\n+\teth_dev->data->mac_addrs = NULL;\n+\n+\treturn 0;\n+}\n+\n+static int eth_hn_probe(struct rte_vmbus_driver *drv __rte_unused,\n+\t\t\tstruct rte_vmbus_device *dev)\n+{\n+\tstruct rte_eth_dev *eth_dev;\n+\tint ret;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\teth_dev = eth_dev_vmbus_allocate(dev, sizeof(struct hn_data));\n+\tif (!eth_dev)\n+\t\treturn -ENOMEM;\n+\n+\tret = eth_hn_dev_init(eth_dev);\n+\tif (ret)\n+\t\teth_dev_vmbus_release(eth_dev);\n+\telse\n+\t\trte_eth_dev_probing_finish(eth_dev);\n+\n+\treturn ret;\n+}\n+\n+static int eth_hn_remove(struct rte_vmbus_device *dev)\n+{\n+\tstruct rte_eth_dev *eth_dev;\n+\tint ret;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\teth_dev = rte_eth_dev_allocated(dev->device.name);\n+\tif (!eth_dev)\n+\t\treturn -ENODEV;\n+\n+\tret = eth_hn_dev_uninit(eth_dev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\teth_dev_vmbus_release(eth_dev);\n+\treturn 0;\n+}\n+\n+/* Network device GUID */\n+static const rte_uuid_t hn_net_ids[] = {\n+\t/*  f8615163-df3e-46c5-913f-f2d2f965ed0e */\n+\tRTE_UUID_INIT(0xf8615163, 0xdf3e, 0x46c5, 0x913f, 0xf2d2f965ed0eULL),\n+\t{ 0 }\n+};\n+\n+static struct rte_vmbus_driver rte_netvsc_pmd = {\n+\t.id_table = hn_net_ids,\n+\t.probe = eth_hn_probe,\n+\t.remove = eth_hn_remove,\n+};\n+\n+RTE_PMD_REGISTER_VMBUS(net_netvsc, rte_netvsc_pmd);\n+RTE_PMD_REGISTER_KMOD_DEP(net_netvsc, \"* uio_hv_generic\");\n+\n+RTE_INIT(hn_init_log);\n+static void\n+hn_init_log(void)\n+{\n+\thn_logtype_init = rte_log_register(\"pmd.net.netvsc.init\");\n+\tif (hn_logtype_init >= 0)\n+\t\trte_log_set_level(hn_logtype_init, RTE_LOG_NOTICE);\n+\thn_logtype_driver = rte_log_register(\"pmd.net.netvsc.driver\");\n+\tif (hn_logtype_driver >= 0)\n+\t\trte_log_set_level(hn_logtype_driver, RTE_LOG_NOTICE);\n+}\ndiff --git a/drivers/net/netvsc/hn_logs.h b/drivers/net/netvsc/hn_logs.h\nnew file mode 100644\nindex 000000000000..cddadef09c83\n--- /dev/null\n+++ b/drivers/net/netvsc/hn_logs.h\n@@ -0,0 +1,36 @@\n+/* SPDX-License-Identifier: BSD-3-Clause */\n+\n+#ifndef _HN_LOGS_H_\n+#define _HN_LOGS_H_\n+\n+#include <rte_log.h>\n+\n+extern int hn_logtype_init;\n+extern int hn_logtype_driver;\n+\n+#define PMD_INIT_LOG(level, fmt, args...) \\\n+\trte_log(RTE_LOG_ ## level, hn_logtype_init, \"%s(): \" fmt \"\\n\",\\\n+\t\t__func__, ## args)\n+#define PMD_INIT_FUNC_TRACE() PMD_INIT_LOG(DEBUG, \" >>\")\n+\n+#ifdef RTE_LIBRTE_NETVSC_DEBUG_RX\n+#define PMD_RX_LOG(level, fmt, args...) \\\n+\trte_log(RTE_LOG_ ## level, hn_logtype_driver, \\\n+\t\t\"%s() rx: \" fmt \"\\n\", __func__, ## args)\n+#else\n+#define PMD_RX_LOG(level, fmt, args...) do { } while (0)\n+#endif\n+\n+#ifdef RTE_LIBRTE_NETVSC_DEBUG_TX\n+#define PMD_TX_LOG(level, fmt, args...) \\\n+\trte_log(RTE_LOG_ ## level, hn_logtype_driver, \\\n+\t\t\"%s() tx: \" fmt \"\\n\", __func__, ## args)\n+#else\n+#define PMD_TX_LOG(level, fmt, args...) do { } while (0)\n+#endif\n+\n+#define PMD_DRV_LOG(level, fmt, args...) \\\n+\trte_log(RTE_LOG_ ## level, hn_logtype_driver, \"%s(): \" fmt \"\\n\", \\\n+\t\t__func__, ## args)\n+\n+#endif /* _HN_LOGS_H_ */\ndiff --git a/drivers/net/netvsc/hn_nvs.c b/drivers/net/netvsc/hn_nvs.c\nnew file mode 100644\nindex 000000000000..77d3b839fd45\n--- /dev/null\n+++ b/drivers/net/netvsc/hn_nvs.c\n@@ -0,0 +1,546 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2018 Microsoft Corp.\n+ * Copyright (c) 2010-2012 Citrix Inc.\n+ * Copyright (c) 2012 NetApp Inc.\n+ * All rights reserved.\n+ */\n+\n+/*\n+ * Network Virtualization Service.\n+ */\n+\n+\n+#include <stdint.h>\n+#include <string.h>\n+#include <stdio.h>\n+#include <errno.h>\n+#include <unistd.h>\n+\n+#include <rte_ethdev.h>\n+#include <rte_string_fns.h>\n+#include <rte_memzone.h>\n+#include <rte_malloc.h>\n+#include <rte_atomic.h>\n+#include <rte_branch_prediction.h>\n+#include <rte_ether.h>\n+#include <rte_common.h>\n+#include <rte_errno.h>\n+#include <rte_cycles.h>\n+#include <rte_memory.h>\n+#include <rte_eal.h>\n+#include <rte_dev.h>\n+#include <rte_bus_vmbus.h>\n+\n+#include \"hn_logs.h\"\n+#include \"hn_var.h\"\n+#include \"hn_nvs.h\"\n+\n+static const uint32_t hn_nvs_version[] = {\n+\tNVS_VERSION_61,\n+\tNVS_VERSION_6,\n+\tNVS_VERSION_5,\n+\tNVS_VERSION_4,\n+\tNVS_VERSION_2,\n+\tNVS_VERSION_1\n+};\n+\n+static int hn_nvs_req_send(struct hn_data *hv,\n+\t\t\t   void *req, uint32_t reqlen)\n+{\n+\treturn rte_vmbus_chan_send(hn_primary_chan(hv),\n+\t\t\t\t   VMBUS_CHANPKT_TYPE_INBAND,\n+\t\t\t\t   req, reqlen, 0,\n+\t\t\t\t   VMBUS_CHANPKT_FLAG_NONE, NULL);\n+}\n+\n+static int\n+hn_nvs_execute(struct hn_data *hv,\n+\t       void *req, uint32_t reqlen,\n+\t       void *resp, uint32_t resplen,\n+\t       uint32_t type)\n+{\n+\tstruct vmbus_channel *chan = hn_primary_chan(hv);\n+\tchar buffer[NVS_RESPSIZE_MAX];\n+\tconst struct hn_nvs_hdr *hdr;\n+\tuint32_t len;\n+\tint ret;\n+\n+\t/* Send request to ring buffer */\n+\tret = rte_vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND,\n+\t\t\t\t  req, reqlen, 0,\n+\t\t\t\t  VMBUS_CHANPKT_FLAG_RC, NULL);\n+\n+\tif (ret) {\n+\t\tPMD_DRV_LOG(ERR, \"send request failed: %d\", ret);\n+\t\treturn ret;\n+\t}\n+\n+ retry:\n+\tlen = sizeof(buffer);\n+\tret = rte_vmbus_chan_recv(chan, buffer, &len, NULL);\n+\tif (ret == -EAGAIN) {\n+\t\trte_delay_us(HN_CHAN_INTERVAL_US);\n+\t\tgoto retry;\n+\t}\n+\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"recv response failed: %d\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\thdr = (struct hn_nvs_hdr *)buffer;\n+\tif (hdr->type != type) {\n+\t\tPMD_DRV_LOG(ERR, \"unexpected NVS resp %#x, expect %#x\",\n+\t\t\t    hdr->type, type);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (len < resplen) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"invalid NVS resp len %u (expect %u)\",\n+\t\t\t    len, resplen);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmemcpy(resp, buffer, resplen);\n+\n+\t/* All pass! */\n+\treturn 0;\n+}\n+\n+static int\n+hn_nvs_doinit(struct hn_data *hv, uint32_t nvs_ver)\n+{\n+\tstruct hn_nvs_init init;\n+\tstruct hn_nvs_init_resp resp;\n+\tuint32_t status;\n+\tint error;\n+\n+\tmemset(&init, 0, sizeof(init));\n+\tinit.type = NVS_TYPE_INIT;\n+\tinit.ver_min = nvs_ver;\n+\tinit.ver_max = nvs_ver;\n+\n+\terror = hn_nvs_execute(hv, &init, sizeof(init),\n+\t\t\t       &resp, sizeof(resp),\n+\t\t\t       NVS_TYPE_INIT_RESP);\n+\tif (error)\n+\t\treturn error;\n+\n+\tstatus = resp.status;\n+\tif (status != NVS_STATUS_OK) {\n+\t\t/* Not fatal, try other versions */\n+\t\tPMD_INIT_LOG(DEBUG, \"nvs init failed for ver 0x%x\",\n+\t\t\t     nvs_ver);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+hn_nvs_conn_rxbuf(struct hn_data *hv)\n+{\n+\tstruct hn_nvs_rxbuf_conn conn;\n+\tstruct hn_nvs_rxbuf_connresp resp;\n+\tuint32_t status;\n+\tint error;\n+\n+\t/* Kernel has already setup RXBUF on primary channel. */\n+\n+\t/*\n+\t * Connect RXBUF to NVS.\n+\t */\n+\tconn.type = NVS_TYPE_RXBUF_CONN;\n+\tconn.gpadl = hv->rxbuf_res->phys_addr;\n+\tconn.sig = NVS_RXBUF_SIG;\n+\tPMD_DRV_LOG(DEBUG, \"connect rxbuff va=%p gpad=%#\" PRIx64,\n+\t\t    hv->rxbuf_res->addr,\n+\t\t    hv->rxbuf_res->phys_addr);\n+\n+\terror = hn_nvs_execute(hv, &conn, sizeof(conn),\n+\t\t\t       &resp, sizeof(resp),\n+\t\t\t       NVS_TYPE_RXBUF_CONNRESP);\n+\tif (error) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"exec nvs rxbuf conn failed: %d\",\n+\t\t\t    error);\n+\t\treturn error;\n+\t}\n+\n+\tstatus = resp.status;\n+\tif (status != NVS_STATUS_OK) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"nvs rxbuf conn failed: %x\", status);\n+\t\treturn -EIO;\n+\t}\n+\tif (resp.nsect != 1) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"nvs rxbuf response num sections %u != 1\",\n+\t\t\t    resp.nsect);\n+\t\treturn -EIO;\n+\t}\n+\n+\tPMD_DRV_LOG(INFO,\n+\t\t    \"receive buffer size %u count %u\",\n+\t\t    resp.nvs_sect[0].slotsz,\n+\t\t    resp.nvs_sect[0].slotcnt);\n+\thv->rxbuf_section_cnt = resp.nvs_sect[0].slotcnt;\n+\n+\thv->rxbuf_info = rte_calloc(\"HN_RXBUF_INFO\", hv->rxbuf_section_cnt,\n+\t\t\t\t    sizeof(*hv->rxbuf_info), RTE_CACHE_LINE_SIZE);\n+\tif (!hv->rxbuf_info) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"could not allocate rxbuf info\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void\n+hn_nvs_disconn_rxbuf(struct hn_data *hv)\n+{\n+\tstruct hn_nvs_rxbuf_disconn disconn;\n+\tint error;\n+\n+\t/*\n+\t * Disconnect RXBUF from NVS.\n+\t */\n+\tmemset(&disconn, 0, sizeof(disconn));\n+\tdisconn.type = NVS_TYPE_RXBUF_DISCONN;\n+\tdisconn.sig = NVS_RXBUF_SIG;\n+\n+\t/* NOTE: No response. */\n+\terror = hn_nvs_req_send(hv, &disconn, sizeof(disconn));\n+\tif (error) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"send nvs rxbuf disconn failed: %d\",\n+\t\t\t    error);\n+\t}\n+\n+\trte_free(hv->rxbuf_info);\n+\t/*\n+\t * Linger long enough for NVS to disconnect RXBUF.\n+\t */\n+\trte_delay_ms(200);\n+}\n+\n+static void\n+hn_nvs_disconn_chim(struct hn_data *hv)\n+{\n+\tint error;\n+\n+\tif (hv->chim_cnt != 0) {\n+\t\tstruct hn_nvs_chim_disconn disconn;\n+\n+\t\t/* Disconnect chimney sending buffer from NVS. */\n+\t\tmemset(&disconn, 0, sizeof(disconn));\n+\t\tdisconn.type = NVS_TYPE_CHIM_DISCONN;\n+\t\tdisconn.sig = NVS_CHIM_SIG;\n+\n+\t\t/* NOTE: No response. */\n+\t\terror = hn_nvs_req_send(hv, &disconn, sizeof(disconn));\n+\n+\t\tif (error) {\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t    \"send nvs chim disconn failed: %d\", error);\n+\t\t}\n+\n+\t\thv->chim_cnt = 0;\n+\t\t/*\n+\t\t * Linger long enough for NVS to disconnect chimney\n+\t\t * sending buffer.\n+\t\t */\n+\t\trte_delay_ms(200);\n+\t}\n+}\n+\n+static int\n+hn_nvs_conn_chim(struct hn_data *hv)\n+{\n+\tstruct hn_nvs_chim_conn chim;\n+\tstruct hn_nvs_chim_connresp resp;\n+\tuint32_t sectsz;\n+\tunsigned long len = hv->chim_res->len;\n+\tint error;\n+\n+\t/* Connect chimney sending buffer to NVS */\n+\tmemset(&chim, 0, sizeof(chim));\n+\tchim.type = NVS_TYPE_CHIM_CONN;\n+\tchim.gpadl = hv->chim_res->phys_addr;\n+\tchim.sig = NVS_CHIM_SIG;\n+\tPMD_DRV_LOG(DEBUG, \"connect send buf va=%p gpad=%#\" PRIx64,\n+\t\t    hv->chim_res->addr,\n+\t\t    hv->chim_res->phys_addr);\n+\n+\terror = hn_nvs_execute(hv, &chim, sizeof(chim),\n+\t\t\t       &resp, sizeof(resp),\n+\t\t\t       NVS_TYPE_CHIM_CONNRESP);\n+\tif (error) {\n+\t\tPMD_DRV_LOG(ERR, \"exec nvs chim conn failed\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (resp.status != NVS_STATUS_OK) {\n+\t\tPMD_DRV_LOG(ERR, \"nvs chim conn failed: %x\",\n+\t\t\t    resp.status);\n+\t\terror = -EIO;\n+\t\tgoto cleanup;\n+\t}\n+\n+\tsectsz = resp.sectsz;\n+\tif (sectsz == 0 || sectsz & (sizeof(uint32_t) - 1)) {\n+\t\t/* Can't use chimney sending buffer; done! */\n+\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t    \"invalid chimney sending buffer section size: %u\",\n+\t\t\t    sectsz);\n+\t\treturn 0;\n+\t}\n+\n+\thv->chim_szmax = sectsz;\n+\thv->chim_cnt = len / sectsz;\n+\n+\tPMD_DRV_LOG(INFO, \"send buffer %lu section size:%u, count:%u\",\n+\t\t    len, hv->chim_szmax, hv->chim_cnt);\n+\n+\tif (len % hv->chim_szmax != 0) {\n+\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t    \"chimney sending sections are not properly aligned\");\n+\t}\n+\n+\t/* Done! */\n+\treturn 0;\n+\n+cleanup:\n+\thn_nvs_disconn_chim(hv);\n+\treturn error;\n+}\n+\n+/*\n+ * Configure MTU and enable VLAN.\n+ */\n+static int\n+hn_nvs_conf_ndis(struct hn_data *hv, unsigned int mtu)\n+{\n+\tstruct hn_nvs_ndis_conf conf;\n+\tint error;\n+\n+\tmemset(&conf, 0, sizeof(conf));\n+\tconf.type = NVS_TYPE_NDIS_CONF;\n+\tconf.mtu = mtu + ETHER_HDR_LEN;\n+\tconf.caps = NVS_NDIS_CONF_VLAN;\n+\n+\t/* TODO enable SRIOV */\n+\t//if (hv->nvs_ver >= NVS_VERSION_5)\n+\t//\tconf.caps |= NVS_NDIS_CONF_SRIOV;\n+\n+\t/* NOTE: No response. */\n+\terror = hn_nvs_req_send(hv, &conf, sizeof(conf));\n+\tif (error) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"send nvs ndis conf failed: %d\", error);\n+\t\treturn error;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+hn_nvs_init_ndis(struct hn_data *hv)\n+{\n+\tstruct hn_nvs_ndis_init ndis;\n+\tint error;\n+\n+\tmemset(&ndis, 0, sizeof(ndis));\n+\tndis.type = NVS_TYPE_NDIS_INIT;\n+\tndis.ndis_major = NDIS_VERSION_MAJOR(hv->ndis_ver);\n+\tndis.ndis_minor = NDIS_VERSION_MINOR(hv->ndis_ver);\n+\n+\t/* NOTE: No response. */\n+\terror = hn_nvs_req_send(hv, &ndis, sizeof(ndis));\n+\tif (error)\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"send nvs ndis init failed: %d\", error);\n+\n+\treturn error;\n+}\n+\n+static int\n+hn_nvs_init(struct hn_data *hv)\n+{\n+\tunsigned int i;\n+\tint error;\n+\n+\t/*\n+\t * Find the supported NVS version and set NDIS version accordingly.\n+\t */\n+\tfor (i = 0; i < RTE_DIM(hn_nvs_version); ++i) {\n+\t\terror = hn_nvs_doinit(hv, hn_nvs_version[i]);\n+\t\tif (error) {\n+\t\t\tPMD_INIT_LOG(DEBUG, \"version %#x error %d\",\n+\t\t\t\t     hn_nvs_version[i], error);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\thv->nvs_ver = hn_nvs_version[i];\n+\n+\t\t/* Set NDIS version according to NVS version. */\n+\t\thv->ndis_ver = NDIS_VERSION_6_30;\n+\t\tif (hv->nvs_ver <= NVS_VERSION_4)\n+\t\t\thv->ndis_ver = NDIS_VERSION_6_1;\n+\n+\t\tPMD_INIT_LOG(DEBUG,\n+\t\t\t     \"NVS version %#x, NDIS version %u.%u\",\n+\t\t\t     hv->nvs_ver, NDIS_VERSION_MAJOR(hv->ndis_ver),\n+\t\t\t     NDIS_VERSION_MINOR(hv->ndis_ver));\n+\t\treturn 0;\n+\t}\n+\n+\tPMD_DRV_LOG(ERR,\n+\t\t    \"no NVS compatible version available\");\n+\treturn -ENXIO;\n+}\n+\n+int\n+hn_nvs_attach(struct hn_data *hv, unsigned int mtu)\n+{\n+\tint error;\n+\n+\t/*\n+\t * Initialize NVS.\n+\t */\n+\terror = hn_nvs_init(hv);\n+\tif (error)\n+\t\treturn error;\n+\n+\t/** Configure NDIS before initializing it. */\n+\tif (hv->nvs_ver >= NVS_VERSION_2) {\n+\t\terror = hn_nvs_conf_ndis(hv, mtu);\n+\t\tif (error)\n+\t\t\treturn error;\n+\t}\n+\n+\t/*\n+\t * Initialize NDIS.\n+\t */\n+\terror = hn_nvs_init_ndis(hv);\n+\tif (error)\n+\t\treturn error;\n+\n+\t/*\n+\t * Connect RXBUF.\n+\t */\n+\terror = hn_nvs_conn_rxbuf(hv);\n+\tif (error)\n+\t\treturn error;\n+\n+\t/*\n+\t * Connect chimney sending buffer.\n+\t */\n+\terror = hn_nvs_conn_chim(hv);\n+\tif (error) {\n+\t\thn_nvs_disconn_rxbuf(hv);\n+\t\treturn error;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void\n+hn_nvs_detach(struct hn_data *hv __rte_unused)\n+{\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\t/* NOTE: there are no requests to stop the NVS. */\n+\thn_nvs_disconn_rxbuf(hv);\n+\thn_nvs_disconn_chim(hv);\n+}\n+\n+/*\n+ * Ack the consumed RXBUF associated w/ this channel packet,\n+ * so that this RXBUF can be recycled by the hypervisor.\n+ */\n+void\n+hn_nvs_ack_rxbuf(struct vmbus_channel *chan, uint64_t tid)\n+{\n+\tunsigned int retries = 0;\n+\tstruct hn_nvs_rndis_ack ack = {\n+\t\t.type = NVS_TYPE_RNDIS_ACK,\n+\t\t.status = NVS_STATUS_OK,\n+\t};\n+\tint error;\n+\n+\tPMD_RX_LOG(DEBUG, \"ack RX id %\" PRIu64, tid);\n+\n+ again:\n+\terror = rte_vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,\n+\t\t\t\t    &ack, sizeof(ack), tid,\n+\t\t\t\t    VMBUS_CHANPKT_FLAG_NONE, NULL);\n+\n+\tif (error == 0)\n+\t\treturn;\n+\n+\tif (error == -EAGAIN) {\n+\t\t/*\n+\t\t * NOTE:\n+\t\t * This should _not_ happen in real world, since the\n+\t\t * consumption of the TX bufring from the TX path is\n+\t\t * controlled.\n+\t\t */\n+\t\tPMD_RX_LOG(NOTICE, \"RXBUF ack retry\");\n+\t\tif (++retries < 10) {\n+\t\t\trte_delay_ms(1);\n+\t\t\tgoto again;\n+\t\t}\n+\t}\n+\t/* RXBUF leaks! */\n+\tPMD_DRV_LOG(ERR, \"RXBUF ack failed\");\n+}\n+\n+int\n+hn_nvs_alloc_subchans(struct hn_data *hv, uint32_t *nsubch)\n+{\n+\tstruct hn_nvs_subch_req req;\n+\tstruct hn_nvs_subch_resp resp;\n+\tint error;\n+\n+\tmemset(&req, 0, sizeof(req));\n+\treq.type = NVS_TYPE_SUBCH_REQ;\n+\treq.op = NVS_SUBCH_OP_ALLOC;\n+\treq.nsubch = *nsubch;\n+\n+\terror = hn_nvs_execute(hv, &req, sizeof(req),\n+\t\t\t       &resp, sizeof(resp),\n+\t\t\t       NVS_TYPE_SUBCH_RESP);\n+\tif (error)\n+\t\treturn error;\n+\n+\tif (resp.status != NVS_STATUS_OK) {\n+\t\tPMD_INIT_LOG(ERR,\n+\t\t\t     \"nvs subch alloc failed: %#x\",\n+\t\t\t     resp.status);\n+\t\treturn -EIO;\n+\t}\n+\n+\tif (resp.nsubch > *nsubch) {\n+\t\tPMD_INIT_LOG(NOTICE,\n+\t\t\t     \"%u subchans are allocated, requested %u\",\n+\t\t\t     resp.nsubch, *nsubch);\n+\t}\n+\t*nsubch = resp.nsubch;\n+\n+\treturn 0;\n+}\n+\n+void\n+hn_nvs_set_datapath(struct hn_data *hv, uint32_t path)\n+{\n+\tstruct hn_nvs_datapath dp;\n+\n+\tmemset(&dp, 0, sizeof(dp));\n+\tdp.type = NVS_TYPE_SET_DATAPATH;\n+\tdp.active_path = path;\n+\n+\thn_nvs_req_send(hv, &dp, sizeof(dp));\n+}\ndiff --git a/drivers/net/netvsc/hn_nvs.h b/drivers/net/netvsc/hn_nvs.h\nnew file mode 100644\nindex 000000000000..984a9c11c51d\n--- /dev/null\n+++ b/drivers/net/netvsc/hn_nvs.h\n@@ -0,0 +1,229 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2018 Microsoft Corp.\n+ * All rights reserved.\n+ */\n+\n+/*\n+ * The indirection table message is the largest message\n+ * received from host, and that is 112 bytes.\n+ */\n+#define NVS_RESPSIZE_MAX\t256\n+\n+/*\n+ * NDIS protocol version numbers\n+ */\n+#define NDIS_VERSION_6_1\t\t0x00060001\n+#define NDIS_VERSION_6_20\t\t0x00060014\n+#define NDIS_VERSION_6_30\t\t0x0006001e\n+#define NDIS_VERSION_MAJOR(ver)\t(((ver) & 0xffff0000) >> 16)\n+#define NDIS_VERSION_MINOR(ver)\t((ver) & 0xffff)\n+\n+/*\n+ * NVS versions.\n+ */\n+#define NVS_VERSION_1\t\t0x00002\n+#define NVS_VERSION_2\t\t0x30002\n+#define NVS_VERSION_4\t\t0x40000\n+#define NVS_VERSION_5\t\t0x50000\n+#define NVS_VERSION_6\t\t0x60000\n+#define NVS_VERSION_61\t\t0x60001\n+\n+#define NVS_RXBUF_SIG\t\t0xcafe\n+#define NVS_CHIM_SIG\t\t\t0xface\n+\n+#define NVS_CHIM_IDX_INVALID\t\t0xffffffff\n+\n+#define NVS_RNDIS_MTYPE_DATA\t\t0\n+#define NVS_RNDIS_MTYPE_CTRL\t\t1\n+\n+/*\n+ * NVS message transacion status codes.\n+ */\n+#define NVS_STATUS_OK\t\t1\n+#define NVS_STATUS_FAILED\t\t2\n+\n+/*\n+ * NVS request/response message types.\n+ */\n+#define NVS_TYPE_INIT\t\t1\n+#define NVS_TYPE_INIT_RESP\t2\n+\n+#define NVS_TYPE_NDIS_INIT\t100\n+#define NVS_TYPE_RXBUF_CONN\t101\n+#define NVS_TYPE_RXBUF_CONNRESP\t102\n+#define NVS_TYPE_RXBUF_DISCONN\t103\n+#define NVS_TYPE_CHIM_CONN\t104\n+#define NVS_TYPE_CHIM_CONNRESP\t105\n+#define NVS_TYPE_CHIM_DISCONN\t106\n+#define NVS_TYPE_RNDIS\t\t107\n+#define NVS_TYPE_RNDIS_ACK\t108\n+\n+#define NVS_TYPE_NDIS_CONF\t125\n+#define NVS_TYPE_VFASSOC_NOTE\t128\t/* notification */\n+#define NVS_TYPE_SET_DATAPATH\t129\n+#define NVS_TYPE_SUBCH_REQ\t133\n+#define NVS_TYPE_SUBCH_RESP\t133\t/* same as SUBCH_REQ */\n+#define NVS_TYPE_TXTBL_NOTE\t134\t/* notification */\n+\n+\n+/* NVS message common header */\n+struct hn_nvs_hdr {\n+\tuint32_t\ttype;\n+} __rte_packed;\n+\n+struct hn_nvs_init {\n+\tuint32_t\ttype;\t/* NVS_TYPE_INIT */\n+\tuint32_t\tver_min;\n+\tuint32_t\tver_max;\n+\tuint8_t\t\trsvd[28];\n+} __rte_packed;\n+\n+struct hn_nvs_init_resp {\n+\tuint32_t\ttype;\t/* NVS_TYPE_INIT_RESP */\n+\tuint32_t\tver;\t/* deprecated */\n+\tuint32_t\trsvd;\n+\tuint32_t\tstatus;\t/* NVS_STATUS_ */\n+} __rte_packed;\n+\n+/* No response */\n+struct hn_nvs_ndis_conf {\n+\tuint32_t\ttype;\t/* NVS_TYPE_NDIS_CONF */\n+\tuint32_t\tmtu;\n+\tuint32_t\trsvd;\n+\tuint64_t\tcaps;\t/* NVS_NDIS_CONF_ */\n+\tuint8_t\t\trsvd1[20];\n+} __rte_packed;\n+\n+#define NVS_NDIS_CONF_SRIOV\t\t0x0004\n+#define NVS_NDIS_CONF_VLAN\t\t0x0008\n+\n+/* No response */\n+struct hn_nvs_ndis_init {\n+\tuint32_t\ttype;\t/* NVS_TYPE_NDIS_INIT */\n+\tuint32_t\tndis_major;\t/* NDIS_VERSION_MAJOR_ */\n+\tuint32_t\tndis_minor;\t/* NDIS_VERSION_MINOR_ */\n+\tuint8_t\t\trsvd[28];\n+} __rte_packed;\n+\n+#define NVS_DATAPATH_SYNTHETIC\t0\n+#define NVS_DATAPATH_VF\t\t1\n+\n+/* No response */\n+struct hn_nvs_datapath {\n+\tuint32_t\ttype;\t/* NVS_TYPE_SET_DATAPATH */\n+\tuint32_t\tactive_path;/* NVS_DATAPATH_* */\n+\tuint8_t\t\trsvd[32];\n+} __rte_packed;\n+\n+struct hn_nvs_rxbuf_conn {\n+\tuint32_t\ttype;\t/* NVS_TYPE_RXBUF_CONN */\n+\tuint32_t\tgpadl;\t/* RXBUF vmbus GPADL */\n+\tuint16_t\tsig;\t/* NVS_RXBUF_SIG */\n+\tuint8_t\t\trsvd[30];\n+} __rte_packed;\n+\n+struct hn_nvs_rxbuf_sect {\n+\tuint32_t\tstart;\n+\tuint32_t\tslotsz;\n+\tuint32_t\tslotcnt;\n+\tuint32_t\tend;\n+} __rte_packed;\n+\n+struct hn_nvs_rxbuf_connresp {\n+\tuint32_t\ttype;\t/* NVS_TYPE_RXBUF_CONNRESP */\n+\tuint32_t\tstatus;\t/* NVS_STATUS_ */\n+\tuint32_t\tnsect;\t/* # of elem in nvs_sect */\n+\tstruct hn_nvs_rxbuf_sect nvs_sect[1];\n+} __rte_packed;\n+\n+/* No response */\n+struct hn_nvs_rxbuf_disconn {\n+\tuint32_t\ttype;\t/* NVS_TYPE_RXBUF_DISCONN */\n+\tuint16_t\tsig;\t/* NVS_RXBUF_SIG */\n+\tuint8_t\t\trsvd[34];\n+} __rte_packed;\n+\n+struct hn_nvs_chim_conn {\n+\tuint32_t\ttype;\t/* NVS_TYPE_CHIM_CONN */\n+\tuint32_t\tgpadl;\t/* chimney buf vmbus GPADL */\n+\tuint16_t\tsig;\t/* NDIS_NVS_CHIM_SIG */\n+\tuint8_t\t\trsvd[30];\n+} __rte_packed;\n+\n+struct hn_nvs_chim_connresp {\n+\tuint32_t\ttype;\t/* NVS_TYPE_CHIM_CONNRESP */\n+\tuint32_t\tstatus;\t/* NVS_STATUS_ */\n+\tuint32_t\tsectsz;\t/* section size */\n+} __rte_packed;\n+\n+/* No response */\n+struct hn_nvs_chim_disconn {\n+\tuint32_t\ttype;\t/* NVS_TYPE_CHIM_DISCONN */\n+\tuint16_t\tsig;\t/* NVS_CHIM_SIG */\n+\tuint8_t\t\trsvd[34];\n+} __rte_packed;\n+\n+#define NVS_SUBCH_OP_ALLOC\t\t1\n+\n+struct hn_nvs_subch_req {\n+\tuint32_t\ttype;\t/* NVS_TYPE_SUBCH_REQ */\n+\tuint32_t\top;\t/* NVS_SUBCH_OP_ */\n+\tuint32_t\tnsubch;\n+\tuint8_t\t\trsvd[28];\n+} __rte_packed;\n+\n+struct hn_nvs_subch_resp {\n+\tuint32_t\ttype;\t/* NVS_TYPE_SUBCH_RESP */\n+\tuint32_t\tstatus;\t/* NVS_STATUS_ */\n+\tuint32_t\tnsubch;\n+\tuint8_t\t\trsvd[28];\n+} __rte_packed;\n+\n+struct hn_nvs_rndis {\n+\tuint32_t\ttype;\t/* NVS_TYPE_RNDIS */\n+\tuint32_t\trndis_mtype;/* NVS_RNDIS_MTYPE_ */\n+\t/*\n+\t * Chimney sending buffer index and size.\n+\t *\n+\t * NOTE:\n+\t * If nvs_chim_idx is set to NVS_CHIM_IDX_INVALID\n+\t * and nvs_chim_sz is set to 0, then chimney sending\n+\t * buffer is _not_ used by this RNDIS message.\n+\t */\n+\tuint32_t\tchim_idx;\n+\tuint32_t\tchim_sz;\n+\tuint8_t\t\trsvd[24];\n+} __rte_packed;\n+\n+struct hn_nvs_rndis_ack {\n+\tuint32_t\ttype;\t/* NVS_TYPE_RNDIS_ACK */\n+\tuint32_t\tstatus;\t/* NVS_STATUS_ */\n+\tuint8_t\t\trsvd[32];\n+} __rte_packed;\n+\n+\n+int\thn_nvs_attach(struct hn_data *hv, unsigned int mtu);\n+void\thn_nvs_detach(struct hn_data *hv);\n+void\thn_nvs_ack_rxbuf(struct vmbus_channel *chan, uint64_t tid);\n+int\thn_nvs_alloc_subchans(struct hn_data *hv, uint32_t *nsubch);\n+void\thn_nvs_set_datapath(struct hn_data *hv, uint32_t path);\n+\n+static inline int\n+hn_nvs_send(struct vmbus_channel *chan, uint16_t flags,\n+\t    void *nvs_msg, int nvs_msglen, uintptr_t sndc,\n+\t    bool *need_sig)\n+{\n+\treturn rte_vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND,\n+\t\t\t\t   nvs_msg, nvs_msglen, (uint64_t)sndc,\n+\t\t\t\t   flags, need_sig);\n+}\n+\n+static inline int\n+hn_nvs_send_sglist(struct vmbus_channel *chan,\n+\t\t   struct vmbus_gpa sg[], unsigned int sglen,\n+\t\t   void *nvs_msg, int nvs_msglen,\n+\t\t   uintptr_t sndc, bool *need_sig)\n+{\n+\treturn rte_vmbus_chan_send_sglist(chan, sg, sglen, nvs_msg, nvs_msglen,\n+\t\t\t\t\t  (uint64_t)sndc, need_sig);\n+}\ndiff --git a/drivers/net/netvsc/hn_rndis.c b/drivers/net/netvsc/hn_rndis.c\nnew file mode 100644\nindex 000000000000..d47468013689\n--- /dev/null\n+++ b/drivers/net/netvsc/hn_rndis.c\n@@ -0,0 +1,1101 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2009-2018 Microsoft Corp.\n+ * Copyright (c) 2010-2012 Citrix Inc.\n+ * Copyright (c) 2012 NetApp Inc.\n+ * All rights reserved.\n+ */\n+\n+#include <stdint.h>\n+#include <string.h>\n+#include <stdio.h>\n+#include <errno.h>\n+#include <unistd.h>\n+\n+#include <rte_ethdev.h>\n+#include <rte_string_fns.h>\n+#include <rte_memzone.h>\n+#include <rte_malloc.h>\n+#include <rte_atomic.h>\n+#include <rte_branch_prediction.h>\n+#include <rte_ether.h>\n+#include <rte_common.h>\n+#include <rte_errno.h>\n+#include <rte_cycles.h>\n+#include <rte_memory.h>\n+#include <rte_eal.h>\n+#include <rte_dev.h>\n+#include <rte_atomic.h>\n+#include <rte_memory.h>\n+#include <rte_bus_vmbus.h>\n+\n+#include \"hn_logs.h\"\n+#include \"hn_var.h\"\n+#include \"hn_nvs.h\"\n+#include \"hn_rndis.h\"\n+#include \"ndis.h\"\n+\n+#define HN_RNDIS_XFER_SIZE\t\t0x4000\n+\n+#define HN_NDIS_TXCSUM_CAP_IP4\t\t\\\n+\t(NDIS_TXCSUM_CAP_IP4 | NDIS_TXCSUM_CAP_IP4OPT)\n+#define HN_NDIS_TXCSUM_CAP_TCP4\t\t\\\n+\t(NDIS_TXCSUM_CAP_TCP4 | NDIS_TXCSUM_CAP_TCP4OPT)\n+#define HN_NDIS_TXCSUM_CAP_TCP6\t\t\\\n+\t(NDIS_TXCSUM_CAP_TCP6 | NDIS_TXCSUM_CAP_TCP6OPT | \\\n+\t NDIS_TXCSUM_CAP_IP6EXT)\n+#define HN_NDIS_TXCSUM_CAP_UDP6\t\t\\\n+\t(NDIS_TXCSUM_CAP_UDP6 | NDIS_TXCSUM_CAP_IP6EXT)\n+#define HN_NDIS_LSOV2_CAP_IP6\t\t\\\n+\t(NDIS_LSOV2_CAP_IP6EXT | NDIS_LSOV2_CAP_TCP6OPT)\n+\n+/* Get unique request id */\n+static inline uint32_t\n+hn_rndis_rid(struct hn_data *hv)\n+{\n+\tuint32_t rid;\n+\n+\tdo {\n+\t\trid = rte_atomic32_add_return(&hv->rndis_req_id, 1);\n+\t} while (rid == 0);\n+\n+\treturn rid;\n+}\n+\n+static void *hn_rndis_alloc(struct hn_data *hv, size_t size)\n+{\n+\treturn rte_zmalloc_socket(\"RNDIS\", size, PAGE_SIZE,\n+\t\t\t\t hv->vmbus->device.numa_node);\n+}\n+\n+#ifdef RTE_LIBRTE_NETVSC_DEBUG_DUMP\n+void hn_rndis_dump(const void *buf)\n+{\n+\tconst union {\n+\t\tstruct rndis_msghdr hdr;\n+\t\tstruct rndis_packet_msg pkt;\n+\t\tstruct rndis_init_req init_request;\n+\t\tstruct rndis_init_comp init_complete;\n+\t\tstruct rndis_halt_req halt;\n+\t\tstruct rndis_query_req query_request;\n+\t\tstruct rndis_query_comp query_complete;\n+\t\tstruct rndis_set_req set_request;\n+\t\tstruct rndis_set_comp set_complete;\n+\t\tstruct rndis_reset_req reset_request;\n+\t\tstruct rndis_reset_comp reset_complete;\n+\t\tstruct rndis_keepalive_req keepalive_request;\n+\t\tstruct rndis_keepalive_comp keepalive_complete;\n+\t\tstruct rndis_status_msg indicate_status;\n+\t} *rndis_msg = buf;\n+\n+\tswitch (rndis_msg->hdr.type) {\n+\tcase RNDIS_PACKET_MSG: {\n+\t\tconst struct rndis_pktinfo *ppi;\n+\t\tunsigned int ppi_len;\n+\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_MSG_PACKET (len %u, data %u:%u, # oob %u %u:%u, pkt %u:%u)\\n\",\n+\t\t\t    rndis_msg->pkt.len,\n+\t\t\t    rndis_msg->pkt.dataoffset,\n+\t\t\t    rndis_msg->pkt.datalen,\n+\t\t\t    rndis_msg->pkt.oobdataelements,\n+\t\t\t    rndis_msg->pkt.oobdataoffset,\n+\t\t\t    rndis_msg->pkt.oobdatalen,\n+\t\t\t    rndis_msg->pkt.pktinfooffset,\n+\t\t\t    rndis_msg->pkt.pktinfolen);\n+\n+\t\tppi = (const struct rndis_pktinfo *)\n+\t\t\t((const char *)buf\n+\t\t\t + RNDIS_PACKET_MSG_OFFSET_ABS(rndis_msg->pkt.pktinfooffset));\n+\n+\t\tppi_len = rndis_msg->pkt.pktinfolen;\n+\t\twhile (ppi_len > 0) {\n+\t\t\tconst void *ppi_data;\n+\n+\t\t\tppi_data = ppi->data;\n+\n+\t\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t\t\"    PPI (size %u, type %u, offs %u data %#x)\\n\",\n+\t\t\t\tppi->size, ppi->type, ppi->offset,\n+\t\t\t\t*(const uint32_t *)ppi_data);\n+\t\t\tif (ppi->size == 0)\n+\t\t\t\tbreak;\n+\t\t\tppi_len -= ppi->size;\n+\t\t\tppi = (const struct rndis_pktinfo *)\n+\t\t\t\t((const char *)ppi + ppi->size);\n+\t\t}\n+\t\tbreak;\n+\t}\n+\tcase RNDIS_INITIALIZE_MSG:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_MSG_INIT (len %u id %#x, ver %u.%u max xfer %u)\\n\",\n+\t\t\t    rndis_msg->init_request.len,\n+\t\t\t    rndis_msg->init_request.rid,\n+\t\t\t    rndis_msg->init_request.ver_major,\n+\t\t\t    rndis_msg->init_request.ver_minor,\n+\t\t\t    rndis_msg->init_request.max_xfersz);\n+\t\tbreak;\n+\n+\tcase RNDIS_INITIALIZE_CMPLT:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_MSG_INIT_C (len %u, id %#x, status 0x%x, vers %u.%u, \"\n+\t\t\t    \"flags %d, max xfer %u, max pkts %u, aligned %u)\\n\",\n+\t\t\t    rndis_msg->init_complete.len,\n+\t\t\t    rndis_msg->init_complete.rid,\n+\t\t\t    rndis_msg->init_complete.status,\n+\t\t\t    rndis_msg->init_complete.ver_major,\n+\t\t\t    rndis_msg->init_complete.ver_minor,\n+\t\t\t    rndis_msg->init_complete.devflags,\n+\t\t\t    rndis_msg->init_complete.pktmaxsz,\n+\t\t\t    rndis_msg->init_complete.pktmaxcnt,\n+\t\t\t    rndis_msg->init_complete.align);\n+\t\tbreak;\n+\n+\tcase RNDIS_HALT_MSG:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_HALT (len %u id %#x)\\n\",\n+\t\t\t    rndis_msg->halt.len, rndis_msg->halt.rid);\n+\t\tbreak;\n+\n+\tcase RNDIS_QUERY_MSG:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_QUERY (len %u, id %#x, oid %#x, info %u:%u)\\n\",\n+\t\t\t    rndis_msg->query_request.len,\n+\t\t\t    rndis_msg->query_request.rid,\n+\t\t\t    rndis_msg->query_request.oid,\n+\t\t\t    rndis_msg->query_request.infobuflen,\n+\t\t\t    rndis_msg->query_request.infobufoffset);\n+\t\tbreak;\n+\n+\tcase RNDIS_QUERY_CMPLT:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_MSG_QUERY_C (len %u, id %#x, status 0x%x, buf %u:%u)\\n\",\n+\t\t\t    rndis_msg->query_complete.len,\n+\t\t\t    rndis_msg->query_complete.rid,\n+\t\t\t    rndis_msg->query_complete.status,\n+\t\t\t    rndis_msg->query_complete.infobuflen,\n+\t\t\t    rndis_msg->query_complete.infobufoffset);\n+\t\tbreak;\n+\n+\tcase RNDIS_SET_MSG:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_SET (len %u, id %#x, oid %#x, info %u:%u)\\n\",\n+\t\t\t    rndis_msg->set_request.len,\n+\t\t\t    rndis_msg->set_request.rid,\n+\t\t\t    rndis_msg->set_request.oid,\n+\t\t\t    rndis_msg->set_request.infobuflen,\n+\t\t\t    rndis_msg->set_request.infobufoffset);\n+\t\tbreak;\n+\n+\tcase RNDIS_SET_CMPLT:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\\n\",\n+\t\t\t    rndis_msg->set_complete.len,\n+\t\t\t    rndis_msg->set_complete.rid,\n+\t\t\t    rndis_msg->set_complete.status);\n+\t\tbreak;\n+\n+\tcase RNDIS_INDICATE_STATUS_MSG:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_MSG_INDICATE (len %u, status %#x, buf len %u, buf offset %u)\\n\",\n+\t\t\t    rndis_msg->indicate_status.len,\n+\t\t\t    rndis_msg->indicate_status.status,\n+\t\t\t    rndis_msg->indicate_status.stbuflen,\n+\t\t\t    rndis_msg->indicate_status.stbufoffset);\n+\t\tbreak;\n+\n+\tcase RNDIS_RESET_MSG:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_RESET (len %u, id %#x)\\n\",\n+\t\t\t    rndis_msg->reset_request.len,\n+\t\t\t    rndis_msg->reset_request.rid);\n+\t\tbreak;\n+\n+\tcase RNDIS_RESET_CMPLT:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_RESET_C (len %u, status %#x address %#x)\\n\",\n+\t\t\t    rndis_msg->reset_complete.len,\n+\t\t\t    rndis_msg->reset_complete.status,\n+\t\t\t    rndis_msg->reset_complete.adrreset);\n+\t\tbreak;\n+\n+\tcase RNDIS_KEEPALIVE_MSG:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_KEEPALIVE (len %u, id %#x)\\n\",\n+\t\t\t    rndis_msg->keepalive_request.len,\n+\t\t\t    rndis_msg->keepalive_request.rid);\n+\t\tbreak;\n+\n+\tcase RNDIS_KEEPALIVE_CMPLT:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS_KEEPALIVE_C (len %u, id %#x address %#x)\\n\",\n+\t\t\t    rndis_msg->keepalive_complete.len,\n+\t\t\t    rndis_msg->keepalive_complete.rid,\n+\t\t\t    rndis_msg->keepalive_complete.status);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\trte_log(RTE_LOG_DEBUG, hn_logtype_driver,\n+\t\t\t    \"RNDIS type %#x len %u\\n\",\n+\t\t\t    rndis_msg->hdr.type,\n+\t\t\t    rndis_msg->hdr.len);\n+\t\tbreak;\n+\t}\n+}\n+#endif\n+\n+static int hn_nvs_send_rndis_ctrl(struct vmbus_channel *chan,\n+\t\t\t\t  const void *req, uint32_t reqlen)\n+\n+{\n+\tstruct hn_nvs_rndis nvs_rndis = {\n+\t\t.type = NVS_TYPE_RNDIS,\n+\t\t.rndis_mtype = NVS_RNDIS_MTYPE_CTRL,\n+\t\t.chim_idx = NVS_CHIM_IDX_INVALID,\n+\t\t.chim_sz = 0\n+\t};\n+\tstruct vmbus_gpa sg;\n+\trte_iova_t addr;\n+\n+\taddr = rte_malloc_virt2iova(req);\n+\tif (unlikely(addr == RTE_BAD_IOVA)) {\n+\t\tPMD_DRV_LOG(ERR, \"RNDIS send request can not get iova\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (unlikely(reqlen > PAGE_SIZE)) {\n+\t\tPMD_DRV_LOG(ERR, \"RNDIS request %u greater than page size\",\n+\t\t\t    reqlen);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsg.page = addr / PAGE_SIZE;\n+\tsg.ofs  = addr & PAGE_MASK;\n+\tsg.len  = reqlen;\n+\n+\tif (sg.ofs + reqlen >  PAGE_SIZE) {\n+\t\tPMD_DRV_LOG(ERR, \"RNDIS request crosses page bounary\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\thn_rndis_dump(req);\n+\n+\treturn hn_nvs_send_sglist(chan, &sg, 1,\n+\t\t\t\t  &nvs_rndis, sizeof(nvs_rndis), 0U, NULL);\n+}\n+\n+void hn_rndis_link_status(struct hn_data *hv __rte_unused, const void *msg)\n+{\n+\tconst struct rndis_status_msg *indicate = msg;\n+\n+\thn_rndis_dump(msg);\n+\n+\tPMD_DRV_LOG(DEBUG, \"link status %#x\", indicate->status);\n+\n+\tswitch (indicate->status) {\n+\tcase RNDIS_STATUS_LINK_SPEED_CHANGE:\n+\tcase RNDIS_STATUS_NETWORK_CHANGE:\n+\tcase RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:\n+\t\t/* ignore not in DPDK API */\n+\t\tbreak;\n+\n+\tcase RNDIS_STATUS_MEDIA_CONNECT:\n+\tcase RNDIS_STATUS_MEDIA_DISCONNECT:\n+\t\t/* TODO handle as LSC interrupt  */\n+\t\tbreak;\n+\tdefault:\n+\t\tPMD_DRV_LOG(NOTICE, \"unknown RNDIS indication: %#x\",\n+\t\t\t    indicate->status);\n+\t}\n+}\n+\n+/* Callback from hn_process_events when response is visible */\n+void hn_rndis_receive_response(struct hn_data *hv,\n+\t\t\t       const void *data, uint32_t len)\n+{\n+\tconst struct rndis_init_comp *hdr = data;\n+\n+\thn_rndis_dump(data);\n+\n+\tif (len < sizeof(3 * sizeof(uint32_t))) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"missing RNDIS header %u\", len);\n+\t\treturn;\n+\t}\n+\n+\tif (len < hdr->len) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"truncated RNDIS response %u\", len);\n+\t\treturn;\n+\t}\n+\n+\tif  (len > sizeof(hv->rndis_resp)) {\n+\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t    \"RNDIS response exceeds buffer\");\n+\t\tlen = sizeof(hv->rndis_resp);\n+\t}\n+\n+\tif (hdr->rid == 0) {\n+\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t    \"RNDIS response id zero!\");\n+\t}\n+\n+\tmemcpy(hv->rndis_resp, data, len);\n+\n+\t/* make sure response copied before update */\n+\trte_smp_wmb();\n+\n+\tif (rte_atomic32_cmpset(&hv->rndis_pending, hdr->rid, 0) == 0) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"received id %#x pending id %#x\",\n+\t\t\t    hdr->rid, (uint32_t)hv->rndis_pending);\n+\t}\n+}\n+\n+/* Do request/response transaction */\n+static int hn_rndis_exec1(struct hn_data *hv,\n+\t\t\t  const void *req, uint32_t reqlen,\n+\t\t\t  void *comp, uint32_t comp_len)\n+{\n+\tconst struct rndis_halt_req *hdr = req;\n+\tuint32_t rid = hdr->rid;\n+\tstruct vmbus_channel *chan = hn_primary_chan(hv);\n+\tint error;\n+\n+\tif (comp_len > sizeof(hv->rndis_resp)) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"Expected completion size %u exceeds buffer %zu\",\n+\t\t\t    comp_len, sizeof(hv->rndis_resp));\n+\t\treturn -EIO;\n+\t}\n+\n+\tif (comp != NULL &&\n+\t    rte_atomic32_cmpset(&hv->rndis_pending, 0, rid) == 0) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"Request already pending\");\n+\t\treturn -EBUSY;\n+\t}\n+\n+\terror = hn_nvs_send_rndis_ctrl(chan, req, reqlen);\n+\tif (error) {\n+\t\tPMD_DRV_LOG(ERR, \"RNDIS ctrl send failed: %d\", error);\n+\t\treturn error;\n+\t}\n+\n+\tif (comp) {\n+\t\t/* Poll primary channel until response received */\n+\t\twhile (hv->rndis_pending == rid)\n+\t\t\thn_process_events(hv, 0);\n+\n+\t\tmemcpy(comp, hv->rndis_resp, comp_len);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* Do transaction and validate response */\n+static int hn_rndis_execute(struct hn_data *hv, uint32_t rid,\n+\t\t\t    const void *req, uint32_t reqlen,\n+\t\t\t    void *comp, uint32_t comp_len, uint32_t comp_type)\n+{\n+\tconst struct rndis_comp_hdr *hdr = comp;\n+\tint ret;\n+\n+\tmemset(comp, 0, comp_len);\n+\n+\tret = hn_rndis_exec1(hv, req, reqlen, comp, comp_len);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\t/*\n+\t * Check this RNDIS complete message.\n+\t */\n+\tif (unlikely(hdr->type != comp_type)) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"unexpected RNDIS response complete %#x expect %#x\",\n+\t\t\t    hdr->type, comp_type);\n+\n+\t\treturn -ENXIO;\n+\t}\n+\tif (unlikely(hdr->rid != rid)) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"RNDIS comp rid mismatch %#x, expect %#x\",\n+\t\t\t    hdr->rid, rid);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* All pass! */\n+\treturn 0;\n+}\n+\n+static int\n+hn_rndis_query(struct hn_data *hv, uint32_t oid,\n+\t       const void *idata, uint32_t idlen,\n+\t       void *odata, uint32_t odlen)\n+{\n+\tstruct rndis_query_req *req;\n+\tstruct rndis_query_comp *comp;\n+\tuint32_t reqlen, comp_len;\n+\tint error = -EIO;\n+\tunsigned int ofs;\n+\tuint32_t rid;\n+\n+\treqlen = sizeof(*req) + idlen;\n+\treq = hn_rndis_alloc(hv, reqlen);\n+\tif (req == NULL)\n+\t\treturn -ENOMEM;\n+\n+\tcomp_len = sizeof(*comp) + odlen;\n+\tcomp = rte_zmalloc(\"QUERY\", comp_len, PAGE_SIZE);\n+\tif (!comp) {\n+\t\terror = -ENOMEM;\n+\t\tgoto done;\n+\t}\n+\tcomp->status = RNDIS_STATUS_PENDING;\n+\n+\trid = hn_rndis_rid(hv);\n+\n+\treq->type = RNDIS_QUERY_MSG;\n+\treq->len = reqlen;\n+\treq->rid = rid;\n+\treq->oid = oid;\n+\treq->infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;\n+\treq->infobuflen = idlen;\n+\n+\t/* Input data immediately follows RNDIS query. */\n+\tmemcpy(req + 1, idata, idlen);\n+\n+\terror = hn_rndis_execute(hv, rid, req, reqlen,\n+\t\t\t\t comp, comp_len, RNDIS_QUERY_CMPLT);\n+\n+\tif (error)\n+\t\tgoto done;\n+\n+\tif (comp->status != RNDIS_STATUS_SUCCESS) {\n+\t\tPMD_DRV_LOG(ERR, \"RNDIS query 0x%08x failed: status 0x%08x\",\n+\t\t\t    oid, comp->status);\n+\t\terror = -EINVAL;\n+\t\tgoto done;\n+\t}\n+\n+\tif (comp->infobuflen == 0 || comp->infobufoffset == 0) {\n+\t\t/* No output data! */\n+\t\tPMD_DRV_LOG(ERR, \"RNDIS query 0x%08x, no data\", oid);\n+\t\terror = 0;\n+\t\tgoto done;\n+\t}\n+\n+\t/*\n+\t * Check output data length and offset.\n+\t */\n+\t/* ofs is the offset from the beginning of comp. */\n+\tofs = RNDIS_QUERY_COMP_INFOBUFOFFSET_ABS(comp->infobufoffset);\n+\tif (ofs < sizeof(*comp) || ofs + comp->infobuflen > comp_len) {\n+\t\tPMD_DRV_LOG(ERR, \"RNDIS query invalid comp ib off/len, %u/%u\",\n+\t\t\t    comp->infobufoffset, comp->infobuflen);\n+\t\terror = -EINVAL;\n+\t\tgoto done;\n+\t}\n+\n+\t/* Save output data. */\n+\tif (comp->infobuflen < odlen)\n+\t\todlen = comp->infobuflen;\n+\n+\t/* ofs is the offset from the beginning of comp. */\n+\tmemcpy(odata, (const char *)comp + ofs, odlen);\n+\n+\terror = 0;\n+done:\n+\trte_free(comp);\n+\trte_free(req);\n+\treturn error;\n+}\n+\n+static int\n+hn_rndis_halt(struct hn_data *hv)\n+{\n+\tstruct rndis_halt_req *halt;\n+\n+\thalt = hn_rndis_alloc(hv, sizeof(*halt));\n+\tif (halt == NULL)\n+\t\treturn -ENOMEM;\n+\n+\thalt->type = RNDIS_HALT_MSG;\n+\thalt->len = sizeof(*halt);\n+\thalt->rid = hn_rndis_rid(hv);\n+\n+\t/* No RNDIS completion; rely on NVS message send completion */\n+\thn_rndis_exec1(hv, halt, sizeof(*halt), NULL, 0);\n+\n+\trte_free(halt);\n+\n+\tPMD_INIT_LOG(DEBUG, \"RNDIS halt done\");\n+\treturn 0;\n+}\n+\n+static int\n+hn_rndis_query_hwcaps(struct hn_data *hv, struct ndis_offload *caps)\n+{\n+\tstruct ndis_offload in;\n+\tuint32_t caps_len, size;\n+\tint error;\n+\n+\tmemset(caps, 0, sizeof(*caps));\n+\tmemset(&in, 0, sizeof(in));\n+\tin.ndis_hdr.ndis_type = NDIS_OBJTYPE_OFFLOAD;\n+\n+\tif (hv->ndis_ver >= NDIS_VERSION_6_30) {\n+\t\tin.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_3;\n+\t\tsize = NDIS_OFFLOAD_SIZE;\n+\t} else if (hv->ndis_ver >= NDIS_VERSION_6_1) {\n+\t\tin.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_2;\n+\t\tsize = NDIS_OFFLOAD_SIZE_6_1;\n+\t} else {\n+\t\tin.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_1;\n+\t\tsize = NDIS_OFFLOAD_SIZE_6_0;\n+\t}\n+\tin.ndis_hdr.ndis_size = size;\n+\n+\tcaps_len = NDIS_OFFLOAD_SIZE;\n+\terror = hn_rndis_query(hv, OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES,\n+\t\t\t       &in, size, caps, caps_len);\n+\tif (error)\n+\t\treturn error;\n+\n+\t/* Preliminary verification. */\n+\tif (caps->ndis_hdr.ndis_type != NDIS_OBJTYPE_OFFLOAD) {\n+\t\tPMD_DRV_LOG(NOTICE, \"invalid NDIS objtype 0x%02x\",\n+\t\t\t    caps->ndis_hdr.ndis_type);\n+\t\treturn -EINVAL;\n+\t}\n+\tif (caps->ndis_hdr.ndis_rev < NDIS_OFFLOAD_REV_1) {\n+\t\tPMD_DRV_LOG(NOTICE, \"invalid NDIS objrev 0x%02x\",\n+\t\t\t    caps->ndis_hdr.ndis_rev);\n+\t\treturn -EINVAL;\n+\t}\n+\tif (caps->ndis_hdr.ndis_size > caps_len) {\n+\t\tPMD_DRV_LOG(NOTICE, \"invalid NDIS objsize %u, data size %u\",\n+\t\t\t    caps->ndis_hdr.ndis_size, caps_len);\n+\t\treturn -EINVAL;\n+\t} else if (caps->ndis_hdr.ndis_size < NDIS_OFFLOAD_SIZE_6_0) {\n+\t\tPMD_DRV_LOG(NOTICE, \"invalid NDIS objsize %u\",\n+\t\t\t    caps->ndis_hdr.ndis_size);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+hn_rndis_query_rsscaps(struct hn_data *hv,\n+\t\t       unsigned int *rxr_cnt0)\n+{\n+\tstruct ndis_rss_caps in, caps;\n+\tunsigned int indsz, rxr_cnt;\n+\tuint32_t caps_len;\n+\tint error;\n+\n+\t*rxr_cnt0 = 0;\n+\n+\tif (hv->ndis_ver < NDIS_VERSION_6_20) {\n+\t\tPMD_DRV_LOG(DEBUG, \"RSS not supported on this host\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tmemset(&in, 0, sizeof(in));\n+\tin.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;\n+\tin.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;\n+\tin.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;\n+\n+\tcaps_len = NDIS_RSS_CAPS_SIZE;\n+\terror = hn_rndis_query(hv, OID_GEN_RECEIVE_SCALE_CAPABILITIES,\n+\t\t\t       &in, NDIS_RSS_CAPS_SIZE,\n+\t\t\t       &caps, caps_len);\n+\tif (error)\n+\t\treturn error;\n+\n+\tPMD_INIT_LOG(DEBUG, \"RX rings %u indirect %u caps %#x\",\n+\t\t     caps.ndis_nrxr, caps.ndis_nind, caps.ndis_caps);\n+\t/*\n+\t * Preliminary verification.\n+\t */\n+\tif (caps.ndis_hdr.ndis_type != NDIS_OBJTYPE_RSS_CAPS) {\n+\t\tPMD_DRV_LOG(ERR, \"invalid NDIS objtype 0x%02x\",\n+\t\t\t    caps.ndis_hdr.ndis_type);\n+\t\treturn -EINVAL;\n+\t}\n+\tif (caps.ndis_hdr.ndis_rev < NDIS_RSS_CAPS_REV_1) {\n+\t\tPMD_DRV_LOG(ERR, \"invalid NDIS objrev 0x%02x\",\n+\t\t\t    caps.ndis_hdr.ndis_rev);\n+\t\treturn -EINVAL;\n+\t}\n+\tif (caps.ndis_hdr.ndis_size > caps_len) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"invalid NDIS objsize %u, data size %u\",\n+\t\t\t    caps.ndis_hdr.ndis_size, caps_len);\n+\t\treturn -EINVAL;\n+\t} else if (caps.ndis_hdr.ndis_size < NDIS_RSS_CAPS_SIZE_6_0) {\n+\t\tPMD_DRV_LOG(ERR, \"invalid NDIS objsize %u\",\n+\t\t\t    caps.ndis_hdr.ndis_size);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/*\n+\t * Save information for later RSS configuration.\n+\t */\n+\tif (caps.ndis_nrxr == 0) {\n+\t\tPMD_DRV_LOG(ERR, \"0 RX rings!?\");\n+\t\treturn -EINVAL;\n+\t}\n+\trxr_cnt = caps.ndis_nrxr;\n+\n+\tif (caps.ndis_hdr.ndis_size == NDIS_RSS_CAPS_SIZE &&\n+\t    caps.ndis_hdr.ndis_rev >= NDIS_RSS_CAPS_REV_2) {\n+\t\tif (caps.ndis_nind > NDIS_HASH_INDCNT) {\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t    \"too many RSS indirect table entries %u\",\n+\t\t\t\t    caps.ndis_nind);\n+\t\t\treturn -EOPNOTSUPP;\n+\t\t}\n+\t\tif (!rte_is_power_of_2(caps.ndis_nind)) {\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t    \"RSS indirect table size is not power-of-2 %u\",\n+\t\t\t\t    caps.ndis_nind);\n+\t\t}\n+\n+\t\tindsz = caps.ndis_nind;\n+\t} else {\n+\t\tindsz = NDIS_HASH_INDCNT;\n+\t}\n+\n+\tif (indsz < rxr_cnt) {\n+\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t    \"# of RX rings (%d) > RSS indirect table size %d\",\n+\t\t\t    rxr_cnt, indsz);\n+\t\trxr_cnt = indsz;\n+\t}\n+\n+\thv->rss_offloads = 0;\n+\tif (caps.ndis_caps & NDIS_RSS_CAP_IPV4)\n+\t\thv->rss_offloads |= ETH_RSS_IPV4\n+\t\t\t| ETH_RSS_NONFRAG_IPV4_TCP\n+\t\t\t| ETH_RSS_NONFRAG_IPV4_UDP;\n+\tif (caps.ndis_caps & NDIS_RSS_CAP_IPV6)\n+\t\thv->rss_offloads |= ETH_RSS_IPV6\n+\t\t\t| ETH_RSS_NONFRAG_IPV6_TCP;\n+\tif (caps.ndis_caps & NDIS_RSS_CAP_IPV6_EX)\n+\t\thv->rss_offloads |= ETH_RSS_IPV6_EX\n+\t\t\t| ETH_RSS_IPV6_TCP_EX;\n+\n+\t/* Commit! */\n+\t*rxr_cnt0 = rxr_cnt;\n+\n+\treturn 0;\n+}\n+\n+static int\n+hn_rndis_set(struct hn_data *hv, uint32_t oid, const void *data, uint32_t dlen)\n+{\n+\tstruct rndis_set_req *req;\n+\tstruct rndis_set_comp comp;\n+\tuint32_t reqlen, comp_len;\n+\tuint32_t rid;\n+\tint error;\n+\n+\treqlen = sizeof(*req) + dlen;\n+\treq = rte_zmalloc(\"RNDIS_SET\", reqlen, PAGE_SIZE);\n+\tif (!req)\n+\t\treturn -ENOMEM;\n+\n+\trid = hn_rndis_rid(hv);\n+\treq->type = RNDIS_SET_MSG;\n+\treq->len = reqlen;\n+\treq->rid = rid;\n+\treq->oid = oid;\n+\treq->infobuflen = dlen;\n+\treq->infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;\n+\n+\t/* Data immediately follows RNDIS set. */\n+\tmemcpy(req + 1, data, dlen);\n+\n+\tcomp_len = sizeof(comp);\n+\terror = hn_rndis_execute(hv, rid, req, reqlen,\n+\t\t\t\t &comp, comp_len,\n+\t\t\t\t RNDIS_SET_CMPLT);\n+\tif (error) {\n+\t\tPMD_DRV_LOG(ERR, \"exec RNDIS set %#\" PRIx32 \" failed\",\n+\t\t\t    oid);\n+\t\terror = EIO;\n+\t\tgoto done;\n+\t}\n+\n+\tif (comp.status != RNDIS_STATUS_SUCCESS) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"RNDIS set %#\" PRIx32 \" failed: status %#\" PRIx32,\n+\t\t\t    oid, comp.status);\n+\t\terror = EIO;\n+\t\tgoto done;\n+\t}\n+\n+done:\n+\trte_free(req);\n+\treturn error;\n+}\n+\n+int hn_rndis_conf_offload(struct hn_data *hv,\n+\t\t\t  uint64_t tx_offloads, uint64_t rx_offloads)\n+{\n+\tstruct ndis_offload_params params;\n+\tstruct ndis_offload hwcaps;\n+\tint error;\n+\n+\terror = hn_rndis_query_hwcaps(hv, &hwcaps);\n+\tif (error) {\n+\t\tPMD_DRV_LOG(ERR, \"hwcaps query failed: %d\", error);\n+\t\treturn error;\n+\t}\n+\n+\t/* NOTE: 0 means \"no change\" */\n+\tmemset(&params, 0, sizeof(params));\n+\n+\tparams.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;\n+\tif (hv->ndis_ver < NDIS_VERSION_6_30) {\n+\t\tparams.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;\n+\t\tparams.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE_6_1;\n+\t} else {\n+\t\tparams.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;\n+\t\tparams.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE;\n+\t}\n+\n+\tif (tx_offloads & DEV_TX_OFFLOAD_TCP_CKSUM) {\n+\t\tif (hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_TCP4)\n+\t\t\tparams.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TX;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\n+\t\tif (hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_TCP6)\n+\t\t\tparams.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TX;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\t}\n+\n+\tif (rx_offloads & DEV_RX_OFFLOAD_TCP_CKSUM) {\n+\t\tif ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4)\n+\t\t    == NDIS_RXCSUM_CAP_TCP4)\n+\t\t\tparams.ndis_tcp4csum |= NDIS_OFFLOAD_PARAM_RX;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\n+\t\tif ((hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6)\n+\t\t    == NDIS_RXCSUM_CAP_TCP6)\n+\t\t\tparams.ndis_tcp6csum |= NDIS_OFFLOAD_PARAM_RX;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\t}\n+\n+\tif (tx_offloads & DEV_TX_OFFLOAD_UDP_CKSUM) {\n+\t\tif (hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_UDP4)\n+\t\t\tparams.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TX;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\n+\t\tif ((hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_UDP6)\n+\t\t    == NDIS_TXCSUM_CAP_UDP6)\n+\t\t\tparams.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TX;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\t}\n+\n+\tif (rx_offloads & DEV_TX_OFFLOAD_UDP_CKSUM) {\n+\t\tif (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4)\n+\t\t\tparams.ndis_udp4csum |= NDIS_OFFLOAD_PARAM_RX;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\n+\t\tif (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6)\n+\t\t\tparams.ndis_udp6csum |= NDIS_OFFLOAD_PARAM_RX;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\t}\n+\n+\tif (tx_offloads & DEV_TX_OFFLOAD_IPV4_CKSUM) {\n+\t\tif ((hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_IP4)\n+\t\t    == NDIS_TXCSUM_CAP_IP4)\n+\t\t\tparams.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TX;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\t}\n+\tif (rx_offloads & DEV_RX_OFFLOAD_IPV4_CKSUM) {\n+\t\tif (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)\n+\t\t\tparams.ndis_ip4csum |= NDIS_OFFLOAD_PARAM_RX;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\t}\n+\n+\tif (tx_offloads & DEV_TX_OFFLOAD_TCP_TSO) {\n+\t\tif (hwcaps.ndis_lsov2.ndis_ip4_encap & NDIS_OFFLOAD_ENCAP_8023)\n+\t\t\tparams.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\n+\t\tif ((hwcaps.ndis_lsov2.ndis_ip6_opts & HN_NDIS_LSOV2_CAP_IP6)\n+\t\t    == HN_NDIS_LSOV2_CAP_IP6)\n+\t\t\tparams.ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON;\n+\t\telse\n+\t\t\tgoto unsupported;\n+\t}\n+\n+\terror = hn_rndis_set(hv, OID_TCP_OFFLOAD_PARAMETERS, &params,\n+\t\t\t     params.ndis_hdr.ndis_size);\n+\tif (error) {\n+\t\tPMD_DRV_LOG(ERR, \"offload config failed\");\n+\t\treturn error;\n+\t}\n+\n+\treturn 0;\n+ unsupported:\n+\tPMD_DRV_LOG(NOTICE,\n+\t\t    \"offload tx:%\" PRIx64 \" rx:%\" PRIx64 \" not supported by this version\",\n+\t\t    tx_offloads, rx_offloads);\n+\treturn -EINVAL;\n+}\n+\n+int hn_rndis_get_offload(struct hn_data *hv,\n+\t\t\t struct rte_eth_dev_info *dev_info)\n+{\n+\tstruct ndis_offload hwcaps;\n+\tint error;\n+\n+\tmemset(&hwcaps, 0, sizeof(hwcaps));\n+\n+\terror = hn_rndis_query_hwcaps(hv, &hwcaps);\n+\tif (error) {\n+\t\tPMD_DRV_LOG(ERR, \"hwcaps query failed: %d\", error);\n+\t\treturn error;\n+\t}\n+\n+\tdev_info->tx_offload_capa = DEV_TX_OFFLOAD_MULTI_SEGS |\n+\t\t\t\t    DEV_TX_OFFLOAD_VLAN_INSERT;\n+\n+\tif ((hwcaps.ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_IP4)\n+\t    == HN_NDIS_TXCSUM_CAP_IP4)\n+\t\tdev_info->tx_offload_capa |= DEV_TX_OFFLOAD_IPV4_CKSUM;\n+\n+\tif ((hwcaps.ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_TCP4)\n+\t    == HN_NDIS_TXCSUM_CAP_TCP4 &&\n+\t    (hwcaps.ndis_csum.ndis_ip6_txcsum & HN_NDIS_TXCSUM_CAP_TCP6)\n+\t    == HN_NDIS_TXCSUM_CAP_TCP6)\n+\t\tdev_info->tx_offload_capa |= DEV_TX_OFFLOAD_TCP_CKSUM;\n+\n+\tif ((hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_UDP4) &&\n+\t    (hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_UDP6))\n+\t\tdev_info->tx_offload_capa |= DEV_TX_OFFLOAD_UDP_CKSUM;\n+\n+\tif ((hwcaps.ndis_lsov2.ndis_ip4_encap & NDIS_OFFLOAD_ENCAP_8023) &&\n+\t    (hwcaps.ndis_lsov2.ndis_ip6_opts & HN_NDIS_LSOV2_CAP_IP6)\n+\t    == HN_NDIS_LSOV2_CAP_IP6)\n+\t\tdev_info->tx_offload_capa |= DEV_TX_OFFLOAD_TCP_TSO;\n+\n+\tdev_info->rx_offload_capa = DEV_RX_OFFLOAD_VLAN_STRIP |\n+\t\t\t\t    DEV_RX_OFFLOAD_CRC_STRIP;\n+\n+\tif (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)\n+\t\tdev_info->rx_offload_capa |= DEV_RX_OFFLOAD_IPV4_CKSUM;\n+\n+\tif ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4) &&\n+\t    (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6))\n+\t\tdev_info->rx_offload_capa |= DEV_RX_OFFLOAD_TCP_CKSUM;\n+\n+\tif ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4) &&\n+\t    (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6))\n+\t\tdev_info->rx_offload_capa |= DEV_RX_OFFLOAD_UDP_CKSUM;\n+\n+\treturn 0;\n+}\n+\n+int\n+hn_rndis_set_rxfilter(struct hn_data *hv, uint32_t filter)\n+{\n+\tint error;\n+\n+\terror = hn_rndis_set(hv, OID_GEN_CURRENT_PACKET_FILTER,\n+\t\t\t     &filter, sizeof(filter));\n+\tif (error) {\n+\t\tPMD_DRV_LOG(ERR, \"set RX filter %#\" PRIx32 \" failed: %d\",\n+\t\t\t    filter, error);\n+\t} else {\n+\t\tPMD_DRV_LOG(DEBUG, \"set RX filter %#\" PRIx32 \" done\", filter);\n+\t}\n+\n+\treturn error;\n+}\n+\n+/* The default RSS key.\n+ * This value is the same as MLX5 so that flows will be\n+ * received on same path for both VF ans synthetic NIC.\n+ */\n+static const uint8_t rss_default_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {\n+\t0x2c, 0xc6, 0x81, 0xd1,\t0x5b, 0xdb, 0xf4, 0xf7,\n+\t0xfc, 0xa2, 0x83, 0x19,\t0xdb, 0x1a, 0x3e, 0x94,\n+\t0x6b, 0x9e, 0x38, 0xd9,\t0x2c, 0x9c, 0x03, 0xd1,\n+\t0xad, 0x99, 0x44, 0xa7,\t0xd9, 0x56, 0x3d, 0x59,\n+\t0x06, 0x3c, 0x25, 0xf3,\t0xfc, 0x1f, 0xdc, 0x2a,\n+};\n+\n+int hn_rndis_conf_rss(struct hn_data *hv,\n+\t\t      const struct rte_eth_rss_conf *rss_conf)\n+{\n+\tstruct ndis_rssprm_toeplitz rssp;\n+\tstruct ndis_rss_params *prm = &rssp.rss_params;\n+\tconst uint8_t *rss_key = rss_conf->rss_key ? : rss_default_key;\n+\tuint32_t rss_hash;\n+\tunsigned int i;\n+\tint error;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tmemset(&rssp, 0, sizeof(rssp));\n+\n+\tprm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;\n+\tprm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;\n+\tprm->ndis_hdr.ndis_size = sizeof(*prm);\n+\tprm->ndis_flags = 0;\n+\n+\trss_hash = NDIS_HASH_FUNCTION_TOEPLITZ;\n+\tif (rss_conf->rss_hf & ETH_RSS_IPV4)\n+\t\trss_hash |= NDIS_HASH_IPV4;\n+\tif (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_TCP)\n+\t\trss_hash |= NDIS_HASH_TCP_IPV4;\n+\tif (rss_conf->rss_hf & ETH_RSS_IPV6)\n+\t\trss_hash |=  NDIS_HASH_IPV6;\n+\tif (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV6_TCP)\n+\t\trss_hash |= NDIS_HASH_TCP_IPV6;\n+\n+\tprm->ndis_hash = rss_hash;\n+\tprm->ndis_indsize = sizeof(rssp.rss_ind[0]) * NDIS_HASH_INDCNT;\n+\tprm->ndis_indoffset = offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);\n+\tprm->ndis_keysize = NDIS_HASH_KEYSIZE_TOEPLITZ;\n+\tprm->ndis_keyoffset = offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);\n+\n+\tfor (i = 0; i < NDIS_HASH_INDCNT; i++)\n+\t\trssp.rss_ind[i] = i % hv->num_queues;\n+\n+\t/* Set hask key values */\n+\tmemcpy(&rssp.rss_key, rss_key, NDIS_HASH_KEYSIZE_TOEPLITZ);\n+\n+\terror = hn_rndis_set(hv, OID_GEN_RECEIVE_SCALE_PARAMETERS,\n+\t\t\t     &rssp, sizeof(rssp));\n+\tif (error) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"RSS config num queues=%u failed: %d\",\n+\t\t\t    hv->num_queues, error);\n+\t}\n+\treturn error;\n+}\n+\n+static int hn_rndis_init(struct hn_data *hv)\n+{\n+\tstruct rndis_init_req *req;\n+\tstruct rndis_init_comp comp;\n+\tuint32_t comp_len, rid;\n+\tint error;\n+\n+\treq = hn_rndis_alloc(hv, sizeof(*req));\n+\tif (!req) {\n+\t\tPMD_DRV_LOG(ERR, \"no memory for RNDIS init\");\n+\t\treturn -ENXIO;\n+\t}\n+\n+\trid = hn_rndis_rid(hv);\n+\treq->type = RNDIS_INITIALIZE_MSG;\n+\treq->len = sizeof(*req);\n+\treq->rid = rid;\n+\treq->ver_major = RNDIS_VERSION_MAJOR;\n+\treq->ver_minor = RNDIS_VERSION_MINOR;\n+\treq->max_xfersz = HN_RNDIS_XFER_SIZE;\n+\n+\tcomp_len = RNDIS_INIT_COMP_SIZE_MIN;\n+\terror = hn_rndis_execute(hv, rid, req, sizeof(*req),\n+\t\t\t\t &comp, comp_len,\n+\t\t\t\t RNDIS_INITIALIZE_CMPLT);\n+\tif (error)\n+\t\tgoto done;\n+\n+\tif (comp.status != RNDIS_STATUS_SUCCESS) {\n+\t\tPMD_DRV_LOG(ERR, \"RNDIS init failed: status 0x%08x\",\n+\t\t\t    comp.status);\n+\t\terror = -EIO;\n+\t\tgoto done;\n+\t}\n+\n+\thv->rndis_agg_size = comp.pktmaxsz;\n+\thv->rndis_agg_pkts = comp.pktmaxcnt;\n+\thv->rndis_agg_align = 1U << comp.align;\n+\n+\tif (hv->rndis_agg_align < sizeof(uint32_t)) {\n+\t\t/*\n+\t\t * The RNDIS packet message encap assumes that the RNDIS\n+\t\t * packet message is at least 4 bytes aligned.  Fix up the\n+\t\t * alignment here, if the remote side sets the alignment\n+\t\t * too low.\n+\t\t */\n+\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t    \"fixup RNDIS aggpkt align: %u -> %zu\",\n+\t\t\t    hv->rndis_agg_align, sizeof(uint32_t));\n+\t\thv->rndis_agg_align = sizeof(uint32_t);\n+\t}\n+\n+\tPMD_INIT_LOG(INFO,\n+\t\t     \"RNDIS ver %u.%u, aggpkt size %u, aggpkt cnt %u, aggpkt align %u\",\n+\t\t     comp.ver_major, comp.ver_minor,\n+\t\t     hv->rndis_agg_size, hv->rndis_agg_pkts,\n+\t\t     hv->rndis_agg_align);\n+\terror = 0;\n+done:\n+\trte_free(req);\n+\treturn error;\n+}\n+\n+int\n+hn_rndis_get_eaddr(struct hn_data *hv, uint8_t *eaddr)\n+{\n+\tuint32_t eaddr_len;\n+\tint error;\n+\n+\teaddr_len = ETHER_ADDR_LEN;\n+\terror = hn_rndis_query(hv, OID_802_3_PERMANENT_ADDRESS, NULL, 0,\n+\t\t\t       eaddr, eaddr_len);\n+\tif (error)\n+\t\treturn error;\n+\n+\tPMD_DRV_LOG(INFO, \"MAC address %02x:%02x:%02x:%02x:%02x:%02x\",\n+\t\t    eaddr[0], eaddr[1], eaddr[2],\n+\t\t    eaddr[3], eaddr[4], eaddr[5]);\n+\treturn 0;\n+}\n+\n+int\n+hn_rndis_get_linkstatus(struct hn_data *hv)\n+{\n+\treturn hn_rndis_query(hv, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,\n+\t\t\t      &hv->link_status, sizeof(uint32_t));\n+}\n+\n+int\n+hn_rndis_get_linkspeed(struct hn_data *hv)\n+{\n+\treturn hn_rndis_query(hv, OID_GEN_LINK_SPEED, NULL, 0,\n+\t\t\t      &hv->link_speed, sizeof(uint32_t));\n+}\n+\n+int\n+hn_rndis_attach(struct hn_data *hv)\n+{\n+\t/* Initialize RNDIS. */\n+\treturn hn_rndis_init(hv);\n+}\n+\n+void\n+hn_rndis_detach(struct hn_data *hv)\n+{\n+\t/* Halt the RNDIS. */\n+\thn_rndis_halt(hv);\n+}\ndiff --git a/drivers/net/netvsc/hn_rndis.h b/drivers/net/netvsc/hn_rndis.h\nnew file mode 100644\nindex 000000000000..89e2e6ba0fcb\n--- /dev/null\n+++ b/drivers/net/netvsc/hn_rndis.h\n@@ -0,0 +1,32 @@\n+/* SPDX-License-Identifier: BSD-3-Clause */\n+\n+#include \"rndis.h\"\n+\n+struct hn_data;\n+\n+void hn_rndis_receive_response(struct hn_data *hv,\n+\t\t\t      const void *data, uint32_t len);\n+void\thn_rndis_link_status(struct hn_data *hv, const void *data);\n+int\thn_rndis_attach(struct hn_data *hv);\n+void\thn_rndis_detach(struct hn_data *hv);\n+int\thn_rndis_get_eaddr(struct hn_data *hv, uint8_t *eaddr);\n+int\thn_rndis_get_linkstatus(struct hn_data *hv);\n+int\thn_rndis_get_linkspeed(struct hn_data *hv);\n+int\thn_rndis_set_rxfilter(struct hn_data *hv, uint32_t filter);\n+void\thn_rndis_rx_ctrl(struct hn_data *hv, const void *data,\n+\t\t\t int dlen);\n+int\thn_rndis_get_offload(struct hn_data *hv,\n+\t\t\t     struct rte_eth_dev_info *dev_info);\n+int\thn_rndis_conf_offload(struct hn_data *hv,\n+\t\t\t      uint64_t tx_offloads,\n+\t\t\t      uint64_t rx_offloads);\n+int\thn_rndis_query_rsscaps(struct hn_data *hv,\n+\t\t\t       unsigned int *rxr_cnt0);\n+int\thn_rndis_conf_rss(struct hn_data *hv,\n+\t\t\t  const struct rte_eth_rss_conf *rss_conf);\n+\n+#ifdef RTE_LIBRTE_NETVSC_DEBUG_DUMP\n+void hn_rndis_dump(const void *buf);\n+#else\n+#define hn_rndis_dump(buf)\n+#endif\ndiff --git a/drivers/net/netvsc/hn_rxtx.c b/drivers/net/netvsc/hn_rxtx.c\nnew file mode 100644\nindex 000000000000..e174c6d4704e\n--- /dev/null\n+++ b/drivers/net/netvsc/hn_rxtx.c\n@@ -0,0 +1,1329 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2016-2018 Microsoft Corporation\n+ * Copyright(c) 2013-2016 Brocade Communications Systems, Inc.\n+ * All rights reserved.\n+ */\n+\n+#include <stdint.h>\n+#include <string.h>\n+#include <stdio.h>\n+#include <errno.h>\n+#include <unistd.h>\n+#include <strings.h>\n+\n+#include <rte_ethdev.h>\n+#include <rte_memcpy.h>\n+#include <rte_string_fns.h>\n+#include <rte_memzone.h>\n+#include <rte_malloc.h>\n+#include <rte_atomic.h>\n+#include <rte_branch_prediction.h>\n+#include <rte_ether.h>\n+#include <rte_common.h>\n+#include <rte_errno.h>\n+#include <rte_memory.h>\n+#include <rte_eal.h>\n+#include <rte_dev.h>\n+#include <rte_bus_vmbus.h>\n+#include <rte_spinlock.h>\n+\n+#include \"hn_logs.h\"\n+#include \"hn_var.h\"\n+#include \"hn_rndis.h\"\n+#include \"hn_nvs.h\"\n+#include \"ndis.h\"\n+\n+#define HN_NVS_SEND_MSG_SIZE \\\n+\t(sizeof(struct vmbus_chanpkt_hdr) + sizeof(struct hn_nvs_rndis))\n+\n+#define HN_TXD_CACHE_SIZE\t32 /* per cpu tx_descriptor pool cache */\n+#define HN_TXCOPY_THRESHOLD\t512\n+\n+#define HN_RXCOPY_THRESHOLD\t256\n+#define HN_RXQ_EVENT_DEFAULT\t1024\n+\n+struct hn_rxinfo {\n+\tuint32_t\tvlan_info;\n+\tuint32_t\tcsum_info;\n+\tuint32_t\thash_info;\n+\tuint32_t\thash_value;\n+};\n+\n+#define HN_RXINFO_VLAN\t\t\t0x0001\n+#define HN_RXINFO_CSUM\t\t\t0x0002\n+#define HN_RXINFO_HASHINF\t\t0x0004\n+#define HN_RXINFO_HASHVAL\t\t0x0008\n+#define HN_RXINFO_ALL\t\t\t\\\n+\t(HN_RXINFO_VLAN |\t\t\\\n+\t HN_RXINFO_CSUM |\t\t\\\n+\t HN_RXINFO_HASHINF |\t\t\\\n+\t HN_RXINFO_HASHVAL)\n+\n+#define HN_NDIS_VLAN_INFO_INVALID\t0xffffffff\n+#define HN_NDIS_RXCSUM_INFO_INVALID\t0\n+#define HN_NDIS_HASH_INFO_INVALID\t0\n+\n+/*\n+ * Per-transmit book keeping.\n+ * A slot in transmit ring (chim_index) is reserved for each transmit.\n+ *\n+ * There are two types of transmit:\n+ *   - buffered transmit where chimney buffer is used and RNDIS header\n+ *     is in the buffer. mbuf == NULL for this case.\n+ *\n+ *   - direct transmit where RNDIS header is in the in  rndis_pkt\n+ *     mbuf is freed after transmit.\n+ *\n+ * Descriptors come from per-port pool which is used\n+ * to limit number of outstanding requests per device.\n+ */\n+struct hn_txdesc {\n+\tstruct rte_mbuf *m;\n+\n+\tuint16_t\tqueue_id;\n+\tuint16_t\tchim_index;\n+\tuint32_t\tchim_size;\n+\tuint32_t\tdata_size;\n+\tuint32_t\tpackets;\n+\n+\tstruct rndis_packet_msg *rndis_pkt;\n+};\n+\n+#define HN_RNDIS_PKT_LEN\t\t\t\t\\\n+\t(sizeof(struct rndis_packet_msg) +\t\t\\\n+\t RNDIS_PKTINFO_SIZE(NDIS_HASH_VALUE_SIZE) +\t\\\n+\t RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +\t\\\n+\t RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +\t\\\n+\t RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))\n+\n+/* Minimum space required for a packet */\n+#define HN_PKTSIZE_MIN(align) \\\n+\tRTE_ALIGN(ETHER_MIN_LEN + HN_RNDIS_PKT_LEN, align)\n+\n+#define DEFAULT_TX_FREE_THRESH 32U\n+\n+static void\n+hn_update_packet_stats(struct hn_stats *stats, const struct rte_mbuf *m)\n+{\n+\tuint32_t s = m->pkt_len;\n+\tconst struct ether_addr *ea;\n+\n+\tif (s == 64) {\n+\t\tstats->size_bins[1]++;\n+\t} else if (s > 64 && s < 1024) {\n+\t\tuint32_t bin;\n+\n+\t\t/* count zeros, and offset into correct bin */\n+\t\tbin = (sizeof(s) * 8) - __builtin_clz(s) - 5;\n+\t\tstats->size_bins[bin]++;\n+\t} else {\n+\t\tif (s < 64)\n+\t\t\tstats->size_bins[0]++;\n+\t\telse if (s < 1519)\n+\t\t\tstats->size_bins[6]++;\n+\t\telse if (s >= 1519)\n+\t\t\tstats->size_bins[7]++;\n+\t}\n+\n+\tea = rte_pktmbuf_mtod(m, const struct ether_addr *);\n+\tif (is_multicast_ether_addr(ea)) {\n+\t\tif (is_broadcast_ether_addr(ea))\n+\t\t\tstats->broadcast++;\n+\t\telse\n+\t\t\tstats->multicast++;\n+\t}\n+}\n+\n+static inline unsigned int hn_rndis_pktlen(const struct rndis_packet_msg *pkt)\n+{\n+\treturn pkt->pktinfooffset + pkt->pktinfolen;\n+}\n+\n+static inline uint32_t\n+hn_rndis_pktmsg_offset(uint32_t ofs)\n+{\n+\treturn ofs - offsetof(struct rndis_packet_msg, dataoffset);\n+}\n+\n+static void hn_txd_init(struct rte_mempool *mp __rte_unused,\n+\t\t\tvoid *opaque, void *obj, unsigned int idx)\n+{\n+\tstruct hn_txdesc *txd = obj;\n+\tstruct rte_eth_dev *dev = opaque;\n+\tstruct rndis_packet_msg *pkt;\n+\n+\tmemset(txd, 0, sizeof(*txd));\n+\ttxd->chim_index = idx;\n+\n+\tpkt = rte_malloc_socket(\"RNDIS_TX\", HN_RNDIS_PKT_LEN,\n+\t\t\t\trte_align32pow2(HN_RNDIS_PKT_LEN),\n+\t\t\t\tdev->device->numa_node);\n+\tif (!pkt)\n+\t\trte_exit(EXIT_FAILURE, \"can not allocate RNDIS header\");\n+\n+\ttxd->rndis_pkt = pkt;\n+}\n+\n+/*\n+ * Unlike Linux and FreeBSD, this driver uses a mempool\n+ * to limit outstanding transmits and reserve buffers\n+ */\n+int\n+hn_tx_pool_init(struct rte_eth_dev *dev)\n+{\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\tchar name[RTE_MEMPOOL_NAMESIZE];\n+\tstruct rte_mempool *mp;\n+\n+\tsnprintf(name, sizeof(name),\n+\t\t \"hn_txd_%u\", dev->data->port_id);\n+\n+\tPMD_INIT_LOG(DEBUG, \"create a TX send pool %s n=%u size=%zu socket=%d\",\n+\t\t     name, hv->chim_cnt, sizeof(struct hn_txdesc),\n+\t\t     dev->device->numa_node);\n+\n+\tmp = rte_mempool_create(name, hv->chim_cnt, sizeof(struct hn_txdesc),\n+\t\t\t\tHN_TXD_CACHE_SIZE, 0,\n+\t\t\t\tNULL, NULL,\n+\t\t\t\thn_txd_init, dev,\n+\t\t\t\tdev->device->numa_node, 0);\n+\tif (!mp) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t    \"mempool %s create failed: %d\", name, rte_errno);\n+\t\treturn -rte_errno;\n+\t}\n+\n+\thv->tx_pool = mp;\n+\treturn 0;\n+}\n+\n+static void hn_reset_txagg(struct hn_tx_queue *txq)\n+{\n+\ttxq->agg_szleft = txq->agg_szmax;\n+\ttxq->agg_pktleft = txq->agg_pktmax;\n+\ttxq->agg_txd = NULL;\n+\ttxq->agg_prevpkt = NULL;\n+}\n+\n+int\n+hn_dev_tx_queue_setup(struct rte_eth_dev *dev,\n+\t\t      uint16_t queue_idx, uint16_t nb_desc __rte_unused,\n+\t\t      unsigned int socket_id,\n+\t\t      const struct rte_eth_txconf *tx_conf)\n+\n+{\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\tstruct hn_tx_queue *txq;\n+\tuint32_t tx_free_thresh;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\ttxq = rte_zmalloc_socket(\"HN_TXQ\", sizeof(*txq), RTE_CACHE_LINE_SIZE,\n+\t\t\t\t socket_id);\n+\tif (!txq)\n+\t\treturn -ENOMEM;\n+\n+\ttxq->hv = hv;\n+\ttxq->chan = hv->channels[queue_idx];\n+\ttxq->port_id = dev->data->port_id;\n+\ttxq->queue_id = queue_idx;\n+\n+\ttx_free_thresh = tx_conf->tx_free_thresh;\n+\tif (tx_free_thresh == 0)\n+\t\ttx_free_thresh = RTE_MIN(hv->chim_cnt / 4,\n+\t\t\t\t\t DEFAULT_TX_FREE_THRESH);\n+\n+\tif (tx_free_thresh >= hv->chim_cnt - 3)\n+\t\ttx_free_thresh = hv->chim_cnt - 3;\n+\n+\ttxq->free_thresh = tx_free_thresh;\n+\n+\ttxq->agg_szmax  = RTE_MIN(hv->chim_szmax, hv->rndis_agg_size);\n+\ttxq->agg_pktmax = hv->rndis_agg_pkts;\n+\ttxq->agg_align  = hv->rndis_agg_align;\n+\n+\thn_reset_txagg(txq);\n+\n+\tdev->data->tx_queues[queue_idx] = txq;\n+\n+\treturn 0;\n+}\n+\n+void\n+hn_dev_tx_queue_release(void *arg)\n+{\n+\tstruct hn_tx_queue *txq = arg;\n+\tstruct hn_txdesc *txd;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tif (!txq)\n+\t\treturn;\n+\n+\t/* If any pending data is still present just drop it */\n+\ttxd = txq->agg_txd;\n+\tif (txd)\n+\t\trte_mempool_put(txq->hv->tx_pool, txd);\n+\n+\trte_free(txq);\n+}\n+\n+static void\n+hn_nvs_send_completed(struct rte_eth_dev *dev, uint16_t queue_id,\n+\t\t      unsigned long xactid, const struct hn_nvs_rndis_ack *ack)\n+{\n+\tstruct hn_txdesc *txd = (struct hn_txdesc *)xactid;\n+\tstruct hn_tx_queue *txq;\n+\n+\t/* Control packets are sent with xacid == 0 */\n+\tif (!txd)\n+\t\treturn;\n+\n+\ttxq = dev->data->tx_queues[queue_id];\n+\tif (likely(ack->status == NVS_STATUS_OK)) {\n+\t\tPMD_TX_LOG(DEBUG, \"port %u:%u complete tx %u packets %u bytes %u\",\n+\t\t\t   txq->port_id, txq->queue_id, txd->chim_index,\n+\t\t\t   txd->packets, txd->data_size);\n+\t\ttxq->stats.bytes += txd->data_size;\n+\t\ttxq->stats.packets += txd->packets;\n+\t} else {\n+\t\tPMD_TX_LOG(NOTICE, \"port %u:%u complete tx %u failed status %u\",\n+\t\t\t   txq->port_id, txq->queue_id, txd->chim_index, ack->status);\n+\t\t++txq->stats.errors;\n+\t}\n+\n+\trte_pktmbuf_free(txd->m);\n+\n+\trte_mempool_put(txq->hv->tx_pool, txd);\n+}\n+\n+/* Handle transmit completion events */\n+static void\n+hn_nvs_handle_comp(struct rte_eth_dev *dev, uint16_t queue_id,\n+\t\t   const struct vmbus_chanpkt_hdr *pkt,\n+\t\t   const void *data)\n+{\n+\tconst struct hn_nvs_hdr *hdr = data;\n+\n+\tswitch (hdr->type) {\n+\tcase NVS_TYPE_RNDIS_ACK:\n+\t\thn_nvs_send_completed(dev, queue_id, pkt->xactid, data);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tPMD_TX_LOG(NOTICE,\n+\t\t\t   \"unexpected send completion type %u\",\n+\t\t\t   hdr->type);\n+\t}\n+}\n+\n+/* Parse per-packet info (meta data) */\n+static int\n+hn_rndis_rxinfo(const void *info_data, unsigned int info_dlen,\n+\t\tstruct hn_rxinfo *info)\n+{\n+\tconst struct rndis_pktinfo *pi = info_data;\n+\tuint32_t mask = 0;\n+\n+\twhile (info_dlen != 0) {\n+\t\tconst void *data;\n+\t\tuint32_t dlen;\n+\n+\t\tif (unlikely(info_dlen < sizeof(*pi)))\n+\t\t\treturn -EINVAL;\n+\n+\t\tif (unlikely(info_dlen < pi->size))\n+\t\t\treturn -EINVAL;\n+\t\tinfo_dlen -= pi->size;\n+\n+\t\tif (unlikely(pi->size & RNDIS_PKTINFO_SIZE_ALIGNMASK))\n+\t\t\treturn -EINVAL;\n+\t\tif (unlikely(pi->size < pi->offset))\n+\t\t\treturn -EINVAL;\n+\n+\t\tdlen = pi->size - pi->offset;\n+\t\tdata = pi->data;\n+\n+\t\tswitch (pi->type) {\n+\t\tcase NDIS_PKTINFO_TYPE_VLAN:\n+\t\t\tif (unlikely(dlen < NDIS_VLAN_INFO_SIZE))\n+\t\t\t\treturn -EINVAL;\n+\t\t\tinfo->vlan_info = *((const uint32_t *)data);\n+\t\t\tmask |= HN_RXINFO_VLAN;\n+\t\t\tbreak;\n+\n+\t\tcase NDIS_PKTINFO_TYPE_CSUM:\n+\t\t\tif (unlikely(dlen < NDIS_RXCSUM_INFO_SIZE))\n+\t\t\t\treturn -EINVAL;\n+\t\t\tinfo->csum_info = *((const uint32_t *)data);\n+\t\t\tmask |= HN_RXINFO_CSUM;\n+\t\t\tbreak;\n+\n+\t\tcase NDIS_PKTINFO_TYPE_HASHVAL:\n+\t\t\tif (unlikely(dlen < NDIS_HASH_VALUE_SIZE))\n+\t\t\t\treturn -EINVAL;\n+\t\t\tinfo->hash_value = *((const uint32_t *)data);\n+\t\t\tmask |= HN_RXINFO_HASHVAL;\n+\t\t\tbreak;\n+\n+\t\tcase NDIS_PKTINFO_TYPE_HASHINF:\n+\t\t\tif (unlikely(dlen < NDIS_HASH_INFO_SIZE))\n+\t\t\t\treturn -EINVAL;\n+\t\t\tinfo->hash_info = *((const uint32_t *)data);\n+\t\t\tmask |= HN_RXINFO_HASHINF;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tgoto next;\n+\t\t}\n+\n+\t\tif (mask == HN_RXINFO_ALL)\n+\t\t\tbreak; /* All found; done */\n+next:\n+\t\tpi = (const struct rndis_pktinfo *)\n+\t\t    ((const uint8_t *)pi + pi->size);\n+\t}\n+\n+\t/*\n+\t * Final fixup.\n+\t * - If there is no hash value, invalidate the hash info.\n+\t */\n+\tif (!(mask & HN_RXINFO_HASHVAL))\n+\t\tinfo->hash_info = HN_NDIS_HASH_INFO_INVALID;\n+\treturn 0;\n+}\n+\n+/*\n+ * Ack the consumed RXBUF associated w/ this channel packet,\n+ * so that this RXBUF can be recycled by the hypervisor.\n+ */\n+static void hn_rx_buf_release(struct hn_rx_bufinfo *rxb)\n+{\n+\tstruct rte_mbuf_ext_shared_info *shinfo = &rxb->shinfo;\n+\tstruct hn_data *hv = rxb->hv;\n+\n+\tif (rte_mbuf_ext_refcnt_update(shinfo, -1) == 0) {\n+\t\thn_nvs_ack_rxbuf(rxb->chan, rxb->xactid);\n+\t\t--hv->rxbuf_outstanding;\n+\t}\n+}\n+\n+static void hn_rx_buf_free_cb(void *buf __rte_unused, void *opaque)\n+{\n+\thn_rx_buf_release(opaque);\n+}\n+\n+static struct hn_rx_bufinfo *hn_rx_buf_init(const struct hn_rx_queue *rxq,\n+\t\t\t\t\t    const struct vmbus_chanpkt_rxbuf *pkt)\n+{\n+\tstruct hn_rx_bufinfo *rxb;\n+\n+\trxb = rxq->hv->rxbuf_info + pkt->hdr.xactid;\n+\trxb->chan = rxq->chan;\n+\trxb->xactid = pkt->hdr.xactid;\n+\trxb->hv = rxq->hv;\n+\n+\trxb->shinfo.free_cb = hn_rx_buf_free_cb;\n+\trxb->shinfo.fcb_opaque = rxb;\n+\trte_mbuf_ext_refcnt_set(&rxb->shinfo, 1);\n+\treturn rxb;\n+}\n+\n+static void hn_rxpkt(struct hn_rx_queue *rxq, struct hn_rx_bufinfo *rxb,\n+\t\t     uint8_t *data, unsigned int headroom, unsigned int dlen,\n+\t\t     const struct hn_rxinfo *info)\n+{\n+\tstruct hn_data *hv = rxq->hv;\n+\tstruct rte_mbuf *m;\n+\n+\tm = rte_pktmbuf_alloc(rxq->mb_pool);\n+\tif (unlikely(!m)) {\n+\t\tstruct rte_eth_dev *dev\n+\t\t\t= &rte_eth_devices[rxq->port_id];\n+\n+\t\tdev->data->rx_mbuf_alloc_failed++;\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * For large packets, avoid copy if possible but need to keep\n+\t * some space available in receive area for later packets.\n+\t */\n+\tif (dlen >= HN_RXCOPY_THRESHOLD &&\n+\t    hv->rxbuf_outstanding < hv->rxbuf_section_cnt / 2) {\n+\t\tstruct rte_mbuf_ext_shared_info *shinfo;\n+\t\tconst void *rxbuf;\n+\t\trte_iova_t iova;\n+\n+\t\t/*\n+\t\t * Build an external mbuf that points to recveive area.\n+\t\t * Use refcount to handle multiple packets in same\n+\t\t * receive buffer section.\n+\t\t */\n+\t\trxbuf = hv->rxbuf_res->addr;\n+\t\tiova = rte_mem_virt2iova(rxbuf) + RTE_PTR_DIFF(data, rxbuf);\n+\t\tshinfo = &rxb->shinfo;\n+\n+\t\tif (rte_mbuf_ext_refcnt_update(shinfo, 1) == 1)\n+\t\t\t++hv->rxbuf_outstanding;\n+\n+\t\trte_pktmbuf_attach_extbuf(m, data, iova,\n+\t\t\t\t\t  dlen + headroom, shinfo);\n+\t\tm->data_off = headroom;\n+\t} else {\n+\t\t/* Mbuf's in pool must be large enough to hold small packets */\n+\t\tif (unlikely(rte_pktmbuf_tailroom(m) < dlen)) {\n+\t\t\trte_pktmbuf_free_seg(m);\n+\t\t\t++rxq->stats.errors;\n+\t\t\treturn;\n+\t\t}\n+\t\trte_memcpy(rte_pktmbuf_mtod(m, void *),\n+\t\t\t   data + headroom, dlen);\n+\t}\n+\n+\tm->port = rxq->port_id;\n+\tm->pkt_len = dlen;\n+\tm->data_len = dlen;\n+\n+\tif (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {\n+\t\tm->vlan_tci = info->vlan_info;\n+\t\tm->ol_flags |= PKT_RX_VLAN_STRIPPED | PKT_RX_VLAN;\n+\t}\n+\n+\tif (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {\n+\t\tif (info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK)\n+\t\t\tm->ol_flags |= PKT_RX_IP_CKSUM_GOOD;\n+\n+\t\tif (info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK\n+\t\t\t\t       | NDIS_RXCSUM_INFO_TCPCS_OK))\n+\t\t\tm->ol_flags |= PKT_RX_L4_CKSUM_GOOD;\n+\t}\n+\n+\tif (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {\n+\t\tm->ol_flags |= PKT_RX_RSS_HASH;\n+\t\tm->hash.rss = info->hash_value;\n+\t}\n+\n+\tPMD_RX_LOG(DEBUG, \"port %u:%u RX id %\" PRIu64 \" size %u ol_flags %#\" PRIx64,\n+\t\t   rxq->port_id, rxq->queue_id, rxb->xactid,\n+\t\t   m->pkt_len, m->ol_flags);\n+\n+\t++rxq->stats.packets;\n+\trxq->stats.bytes += m->pkt_len;\n+\thn_update_packet_stats(&rxq->stats, m);\n+\n+\tif (unlikely(rte_ring_sp_enqueue(rxq->rx_ring, m) != 0)) {\n+\t\t++rxq->ring_full;\n+\t\trte_pktmbuf_free(m);\n+\t}\n+}\n+\n+static void hn_rndis_rx_data(struct hn_rx_queue *rxq,\n+\t\t\t     struct hn_rx_bufinfo *rxb,\n+\t\t\t     void *data, uint32_t dlen)\n+{\n+\tunsigned int data_off, data_len, pktinfo_off, pktinfo_len;\n+\tconst struct rndis_packet_msg *pkt = data;\n+\tstruct hn_rxinfo info = {\n+\t\t.vlan_info = HN_NDIS_VLAN_INFO_INVALID,\n+\t\t.csum_info = HN_NDIS_RXCSUM_INFO_INVALID,\n+\t\t.hash_info = HN_NDIS_HASH_INFO_INVALID,\n+\t};\n+\tint err;\n+\n+\thn_rndis_dump(pkt);\n+\n+\tif (unlikely(dlen < sizeof(*pkt)))\n+\t\tgoto error;\n+\n+\tif (unlikely(dlen < pkt->len))\n+\t\tgoto error; /* truncated RNDIS from host */\n+\n+\tif (unlikely(pkt->len < pkt->datalen\n+\t\t     + pkt->oobdatalen + pkt->pktinfolen))\n+\t\tgoto error;\n+\n+\tif (unlikely(pkt->datalen == 0))\n+\t\tgoto error;\n+\n+\t/* Check offsets. */\n+\tif (unlikely(pkt->dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN))\n+\t\tgoto error;\n+\n+\tif (likely(pkt->pktinfooffset > 0) &&\n+\t    unlikely(pkt->pktinfooffset < RNDIS_PACKET_MSG_OFFSET_MIN ||\n+\t\t     (pkt->pktinfooffset & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK)))\n+\t\tgoto error;\n+\n+\tdata_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->dataoffset);\n+\tdata_len = pkt->datalen;\n+\tpktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->pktinfooffset);\n+\tpktinfo_len = pkt->pktinfolen;\n+\n+\tif (likely(pktinfo_len > 0)) {\n+\t\terr = hn_rndis_rxinfo((const uint8_t *)pkt + pktinfo_off,\n+\t\t\t\t      pktinfo_len, &info);\n+\t\tif (err)\n+\t\t\tgoto error;\n+\t}\n+\n+\tif (unlikely(data_off + data_len > pkt->len))\n+\t\tgoto error;\n+\n+\tif (unlikely(data_len < ETHER_HDR_LEN))\n+\t\tgoto error;\n+\n+\thn_rxpkt(rxq, rxb, data, data_off, data_len, &info);\n+\treturn;\n+error:\n+\t++rxq->stats.errors;\n+}\n+\n+static void\n+hn_rndis_receive(const struct rte_eth_dev *dev, struct hn_rx_queue *rxq,\n+\t\t struct hn_rx_bufinfo *rxb, void *buf, uint32_t len)\n+{\n+\tconst struct rndis_msghdr *hdr = buf;\n+\n+\tswitch (hdr->type) {\n+\tcase RNDIS_PACKET_MSG:\n+\t\tif (dev->data->dev_started)\n+\t\t\thn_rndis_rx_data(rxq, rxb, buf, len);\n+\t\tbreak;\n+\n+\tcase RNDIS_INDICATE_STATUS_MSG:\n+\t\thn_rndis_link_status(rxq->hv, buf);\n+\t\tbreak;\n+\n+\tcase RNDIS_INITIALIZE_CMPLT:\n+\tcase RNDIS_QUERY_CMPLT:\n+\tcase RNDIS_SET_CMPLT:\n+\t\thn_rndis_receive_response(rxq->hv, buf, len);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t    \"unexpected RNDIS message (type %#x len %u)\",\n+\t\t\t    hdr->type, len);\n+\t\tbreak;\n+\t}\n+}\n+\n+static void\n+hn_nvs_handle_rxbuf(struct rte_eth_dev *dev,\n+\t\t    struct hn_data *hv,\n+\t\t    struct hn_rx_queue *rxq,\n+\t\t    const struct vmbus_chanpkt_hdr *hdr,\n+\t\t    const void *buf)\n+{\n+\tconst struct vmbus_chanpkt_rxbuf *pkt;\n+\tconst struct hn_nvs_hdr *nvs_hdr = buf;\n+\tuint32_t rxbuf_sz = hv->rxbuf_res->len;\n+\tchar *rxbuf = hv->rxbuf_res->addr;\n+\tunsigned int i, hlen, count;\n+\tstruct hn_rx_bufinfo *rxb;\n+\n+\t/* At minimum we need type header */\n+\tif (unlikely(vmbus_chanpkt_datalen(hdr) < sizeof(*nvs_hdr))) {\n+\t\tPMD_RX_LOG(ERR, \"invalid receive nvs RNDIS\");\n+\t\treturn;\n+\t}\n+\n+\t/* Make sure that this is a RNDIS message. */\n+\tif (unlikely(nvs_hdr->type != NVS_TYPE_RNDIS)) {\n+\t\tPMD_RX_LOG(ERR, \"nvs type %u, not RNDIS\",\n+\t\t\t   nvs_hdr->type);\n+\t\treturn;\n+\t}\n+\n+\thlen = vmbus_chanpkt_getlen(hdr->hlen);\n+\tif (unlikely(hlen < sizeof(*pkt))) {\n+\t\tPMD_RX_LOG(ERR, \"invalid rxbuf chanpkt\");\n+\t\treturn;\n+\t}\n+\n+\tpkt = container_of(hdr, const struct vmbus_chanpkt_rxbuf, hdr);\n+\tif (unlikely(pkt->rxbuf_id != NVS_RXBUF_SIG)) {\n+\t\tPMD_RX_LOG(ERR, \"invalid rxbuf_id 0x%08x\",\n+\t\t\t   pkt->rxbuf_id);\n+\t\treturn;\n+\t}\n+\n+\tcount = pkt->rxbuf_cnt;\n+\tif (unlikely(hlen < offsetof(struct vmbus_chanpkt_rxbuf,\n+\t\t\t\t     rxbuf[count]))) {\n+\t\tPMD_RX_LOG(ERR, \"invalid rxbuf_cnt %u\", count);\n+\t\treturn;\n+\t}\n+\n+\tif (pkt->hdr.xactid > hv->rxbuf_section_cnt) {\n+\t\tPMD_RX_LOG(ERR, \"invalid rxbuf section id %\" PRIx64,\n+\t\t\t   pkt->hdr.xactid);\n+\t\treturn;\n+\t}\n+\n+\t/* Setup receive buffer info to allow for callback */\n+\trxb = hn_rx_buf_init(rxq, pkt);\n+\n+\t/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */\n+\tfor (i = 0; i < count; ++i) {\n+\t\tunsigned int ofs, len;\n+\n+\t\tofs = pkt->rxbuf[i].ofs;\n+\t\tlen = pkt->rxbuf[i].len;\n+\n+\t\tif (unlikely(ofs + len > rxbuf_sz)) {\n+\t\t\tPMD_RX_LOG(ERR,\n+\t\t\t\t   \"%uth RNDIS msg overflow ofs %u, len %u\",\n+\t\t\t\t   i, ofs, len);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (unlikely(len == 0)) {\n+\t\t\tPMD_RX_LOG(ERR, \"%uth RNDIS msg len %u\", i, len);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\thn_rndis_receive(dev, rxq, rxb,\n+\t\t\t\t rxbuf + ofs, len);\n+\t}\n+\n+\t/* Send ACK now if external mbuf not used */\n+\thn_rx_buf_release(rxb);\n+}\n+\n+struct hn_rx_queue *hn_rx_queue_alloc(struct hn_data *hv,\n+\t\t\t\t      uint16_t queue_id,\n+\t\t\t\t      unsigned int socket_id)\n+{\n+\tstruct hn_rx_queue *rxq;\n+\n+\trxq = rte_zmalloc_socket(\"HN_RXQ\", sizeof(*rxq),\n+\t\t\t\t RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (rxq) {\n+\t\trxq->hv = hv;\n+\t\trxq->chan = hv->channels[queue_id];\n+\t\trte_spinlock_init(&rxq->ring_lock);\n+\t\trxq->port_id = hv->port_id;\n+\t\trxq->queue_id = queue_id;\n+\n+\t\trxq->event_sz = HN_RXQ_EVENT_DEFAULT;\n+\t\trxq->event_buf = rte_malloc_socket(\"RX_EVENTS\",\n+\t\t\t\t\t\t   rxq->event_sz,\n+\t\t\t\t\t\t   RTE_CACHE_LINE_SIZE,\n+\t\t\t\t\t\t   socket_id);\n+\t\tif (!rxq->event_buf) {\n+\t\t\trte_free(rxq);\n+\t\t\trxq = NULL;\n+\t\t}\n+\t}\n+\treturn rxq;\n+}\n+\n+int\n+hn_dev_rx_queue_setup(struct rte_eth_dev *dev,\n+\t\t      uint16_t queue_idx, uint16_t nb_desc,\n+\t\t      unsigned int socket_id,\n+\t\t      const struct rte_eth_rxconf *rx_conf __rte_unused,\n+\t\t      struct rte_mempool *mp)\n+{\n+\tstruct hn_data *hv = dev->data->dev_private;\n+\tuint32_t qmax = hv->rxbuf_section_cnt;\n+\tchar ring_name[RTE_RING_NAMESIZE];\n+\tstruct hn_rx_queue *rxq;\n+\tunsigned int count;\n+\tsize_t size;\n+\tint err = -ENOMEM;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tif (nb_desc == 0 || nb_desc > qmax)\n+\t\tnb_desc = qmax;\n+\n+\tif (queue_idx == 0) {\n+\t\trxq = hv->primary;\n+\t} else {\n+\t\trxq = hn_rx_queue_alloc(hv, queue_idx, socket_id);\n+\t\tif (!rxq)\n+\t\t\treturn -ENOMEM;\n+\t}\n+\n+\trxq->mb_pool = mp;\n+\n+\tcount = rte_align32pow2(nb_desc);\n+\tsize = sizeof(struct rte_ring) + count * sizeof(void *);\n+\trxq->rx_ring = rte_malloc_socket(\"RX_RING\", size,\n+\t\t\t\t\t RTE_CACHE_LINE_SIZE,\n+\t\t\t\t\t socket_id);\n+\tif (!rxq->rx_ring)\n+\t\tgoto fail;\n+\n+\t/*\n+\t * Staging ring from receive event logic to rx_pkts.\n+\t * rx_pkts assumes caller is handling multi-thread issue.\n+\t * event logic has locking.\n+\t */\n+\tsnprintf(ring_name, sizeof(ring_name),\n+\t\t \"hn_rx_%u_%u\", dev->data->port_id, queue_idx);\n+\terr = rte_ring_init(rxq->rx_ring, ring_name,\n+\t\t\t    count, 0);\n+\tif (err)\n+\t\tgoto fail;\n+\n+\tdev->data->rx_queues[queue_idx] = rxq;\n+\treturn 0;\n+\n+fail:\n+\trte_free(rxq->rx_ring);\n+\trte_free(rxq->event_buf);\n+\trte_free(rxq);\n+\treturn -ENOMEM;\n+}\n+\n+void\n+hn_dev_rx_queue_release(void *arg)\n+{\n+\tstruct hn_rx_queue *rxq = arg;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tif (!rxq)\n+\t\treturn;\n+\n+\trte_free(rxq->rx_ring);\n+\trxq->rx_ring = NULL;\n+\trxq->mb_pool = NULL;\n+\n+\tif (rxq != rxq->hv->primary) {\n+\t\trte_free(rxq->event_buf);\n+\t\trte_free(rxq);\n+\t}\n+}\n+\n+static void\n+hn_nvs_handle_notify(const struct vmbus_chanpkt_hdr *pkthdr,\n+\t\t     const void *data)\n+{\n+\tconst struct hn_nvs_hdr *hdr = data;\n+\n+\tif (unlikely(vmbus_chanpkt_datalen(pkthdr) < sizeof(*hdr))) {\n+\t\tPMD_DRV_LOG(ERR, \"invalid nvs notify\");\n+\t\treturn;\n+\t}\n+\n+\tPMD_DRV_LOG(INFO,\n+\t\t    \"got notify, nvs type %u\", hdr->type);\n+}\n+\n+/*\n+ * Process pending events on the channel.\n+ * Called from both Rx queue poll and Tx cleanup\n+ */\n+void hn_process_events(struct hn_data *hv, uint16_t queue_id)\n+{\n+\tstruct rte_eth_dev *dev = &rte_eth_devices[hv->port_id];\n+\tstruct hn_rx_queue *rxq;\n+\tint ret = 0;\n+\n+\trxq = queue_id == 0 ? hv->primary : dev->data->rx_queues[queue_id];\n+\n+\t/* If no pending data then nothing to do */\n+\tif (rte_vmbus_chan_rx_empty(rxq->chan))\n+\t\treturn;\n+\n+\t/*\n+\t * Since channel is shared between Rx and TX queue need to have a lock\n+\t * since DPDK does not force same CPU to be used for Rx/Tx.\n+\t */\n+\tif (unlikely(!rte_spinlock_trylock(&rxq->ring_lock)))\n+\t\treturn;\n+\n+\tfor (;;) {\n+\t\tconst struct vmbus_chanpkt_hdr *pkt;\n+\t\tuint32_t len = rxq->event_sz;\n+\t\tconst void *data;\n+\n+\t\tret = rte_vmbus_chan_recv_raw(rxq->chan, rxq->event_buf, &len);\n+\t\tif (ret == -EAGAIN)\n+\t\t\tbreak;\t/* ring is empty */\n+\n+\t\tif (ret == -ENOBUFS) {\n+\t\t\t/* expanded buffer needed */\n+\t\t\tlen = rte_align32pow2(len);\n+\t\t\tPMD_DRV_LOG(DEBUG, \"expand event buf to %u\", len);\n+\n+\t\t\trxq->event_buf = rte_realloc(rxq->event_buf,\n+\t\t\t\t\t\t     len, RTE_CACHE_LINE_SIZE);\n+\t\t\tif (rxq->event_buf) {\n+\t\t\t\trxq->event_sz = len;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\trte_exit(EXIT_FAILURE, \"can not expand event buf!\\n\");\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR, \"vmbus ring buffer error: %d\", ret);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tpkt = (const struct vmbus_chanpkt_hdr *)rxq->event_buf;\n+\t\tdata = (char *)rxq->event_buf + vmbus_chanpkt_getlen(pkt->hlen);\n+\n+\t\tswitch (pkt->type) {\n+\t\tcase VMBUS_CHANPKT_TYPE_COMP:\n+\t\t\thn_nvs_handle_comp(dev, queue_id, pkt, data);\n+\t\t\tbreak;\n+\n+\t\tcase VMBUS_CHANPKT_TYPE_RXBUF:\n+\t\t\thn_nvs_handle_rxbuf(dev, hv, rxq, pkt, data);\n+\t\t\tbreak;\n+\n+\t\tcase VMBUS_CHANPKT_TYPE_INBAND:\n+\t\t\thn_nvs_handle_notify(pkt, data);\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tPMD_DRV_LOG(ERR, \"unknown chan pkt %u\", pkt->type);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\trte_spinlock_unlock(&rxq->ring_lock);\n+\n+\tif (unlikely(ret != -EAGAIN))\n+\t\tPMD_DRV_LOG(ERR, \"channel receive failed: %d\", ret);\n+}\n+\n+static void hn_append_to_chim(struct hn_tx_queue *txq,\n+\t\t\t      struct rndis_packet_msg *pkt,\n+\t\t\t      const struct rte_mbuf *m)\n+{\n+\tstruct hn_txdesc *txd = txq->agg_txd;\n+\tuint8_t *buf = (uint8_t *)pkt;\n+\tunsigned int data_offs;\n+\n+\thn_rndis_dump(pkt);\n+\n+\tdata_offs = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->dataoffset);\n+\ttxd->chim_size += pkt->len;\n+\ttxd->data_size += m->pkt_len;\n+\t++txd->packets;\n+\thn_update_packet_stats(&txq->stats, m);\n+\n+\tfor (; m; m = m->next) {\n+\t\tuint16_t len = rte_pktmbuf_data_len(m);\n+\n+\t\trte_memcpy(buf + data_offs,\n+\t\t\t   rte_pktmbuf_mtod(m, const char *), len);\n+\t\tdata_offs += len;\n+\t}\n+}\n+\n+/*\n+ * Send pending aggregated data in chimney buffer (if any).\n+ * Returns error if send was unsuccessful because channel ring buffer\n+ * was full.\n+ */\n+static int hn_flush_txagg(struct hn_tx_queue *txq, bool *need_sig)\n+\n+{\n+\tstruct hn_txdesc *txd = txq->agg_txd;\n+\tstruct hn_nvs_rndis rndis;\n+\tint ret;\n+\n+\tif (!txd)\n+\t\treturn 0;\n+\n+\trndis = (struct hn_nvs_rndis) {\n+\t\t.type = NVS_TYPE_RNDIS,\n+\t\t.rndis_mtype = NVS_RNDIS_MTYPE_DATA,\n+\t\t.chim_idx = txd->chim_index,\n+\t\t.chim_sz = txd->chim_size,\n+\t};\n+\n+\tPMD_TX_LOG(DEBUG, \"port %u:%u tx %u size %u\",\n+\t\t   txq->port_id, txq->queue_id, txd->chim_index, txd->chim_size);\n+\n+\tret = hn_nvs_send(txq->chan, VMBUS_CHANPKT_FLAG_RC,\n+\t\t\t  &rndis, sizeof(rndis), (uintptr_t)txd, need_sig);\n+\n+\tif (likely(ret == 0))\n+\t\thn_reset_txagg(txq);\n+\telse\n+\t\tPMD_TX_LOG(NOTICE, \"port %u:%u send failed: %d\",\n+\t\t\t   txq->port_id, txq->queue_id, ret);\n+\n+\treturn ret;\n+}\n+\n+static struct hn_txdesc *hn_new_txd(struct hn_data *hv,\n+\t\t\t\t    struct hn_tx_queue *txq)\n+{\n+\tstruct hn_txdesc *txd;\n+\n+\tif (rte_mempool_get(hv->tx_pool, (void **)&txd)) {\n+\t\t++txq->stats.nomemory;\n+\t\tPMD_TX_LOG(DEBUG, \"tx pool exhausted!\");\n+\t\treturn NULL;\n+\t}\n+\n+\ttxd->m = NULL;\n+\ttxd->queue_id = txq->queue_id;\n+\ttxd->packets = 0;\n+\ttxd->data_size = 0;\n+\ttxd->chim_size = 0;\n+\n+\treturn txd;\n+}\n+\n+static void *\n+hn_try_txagg(struct hn_data *hv, struct hn_tx_queue *txq, uint32_t pktsize)\n+{\n+\tstruct hn_txdesc *agg_txd = txq->agg_txd;\n+\tstruct rndis_packet_msg *pkt;\n+\tvoid *chim;\n+\n+\tif (agg_txd) {\n+\t\tunsigned int padding, olen;\n+\n+\t\t/*\n+\t\t * Update the previous RNDIS packet's total length,\n+\t\t * it can be increased due to the mandatory alignment\n+\t\t * padding for this RNDIS packet.  And update the\n+\t\t * aggregating txdesc's chimney sending buffer size\n+\t\t * accordingly.\n+\t\t *\n+\t\t * Zero-out the padding, as required by the RNDIS spec.\n+\t\t */\n+\t\tpkt = txq->agg_prevpkt;\n+\t\tolen = pkt->len;\n+\t\tpadding = RTE_ALIGN(olen, txq->agg_align) - olen;\n+\t\tif (padding > 0) {\n+\t\t\tagg_txd->chim_size += padding;\n+\t\t\tpkt->len += padding;\n+\t\t\tmemset((uint8_t *)pkt + olen, 0, padding);\n+\t\t}\n+\n+\t\tchim = (uint8_t *)pkt + pkt->len;\n+\n+\t\ttxq->agg_pktleft--;\n+\t\ttxq->agg_szleft -= pktsize;\n+\t\tif (txq->agg_szleft < HN_PKTSIZE_MIN(txq->agg_align)) {\n+\t\t\t/*\n+\t\t\t * Probably can't aggregate more packets,\n+\t\t\t * flush this aggregating txdesc proactively.\n+\t\t\t */\n+\t\t\ttxq->agg_pktleft = 0;\n+\t\t}\n+\t} else {\n+\t\tagg_txd = hn_new_txd(hv, txq);\n+\t\tif (!agg_txd)\n+\t\t\treturn NULL;\n+\n+\t\tchim = (uint8_t *)hv->chim_res->addr\n+\t\t\t+ agg_txd->chim_index * hv->chim_szmax;\n+\n+\t\ttxq->agg_txd = agg_txd;\n+\t\ttxq->agg_pktleft = txq->agg_pktmax - 1;\n+\t\ttxq->agg_szleft = txq->agg_szmax - pktsize;\n+\t}\n+\ttxq->agg_prevpkt = chim;\n+\n+\treturn chim;\n+}\n+\n+static inline void *\n+hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt,\n+\t\t\tuint32_t pi_dlen, uint32_t pi_type)\n+{\n+\tconst uint32_t pi_size = RNDIS_PKTINFO_SIZE(pi_dlen);\n+\tstruct rndis_pktinfo *pi;\n+\n+\t/*\n+\t * Per-packet-info does not move; it only grows.\n+\t *\n+\t * NOTE:\n+\t * pktinfooffset in this phase counts from the beginning\n+\t * of rndis_packet_msg.\n+\t */\n+\tpi = (struct rndis_pktinfo *)((uint8_t *)pkt + hn_rndis_pktlen(pkt));\n+\n+\tpkt->pktinfolen += pi_size;\n+\n+\tpi->size = pi_size;\n+\tpi->type = pi_type;\n+\tpi->offset = RNDIS_PKTINFO_OFFSET;\n+\n+\treturn pi->data;\n+}\n+\n+/* Put RNDIS header and packet info on packet */\n+static void hn_encap(struct rndis_packet_msg *pkt,\n+\t\t     uint16_t queue_id,\n+\t\t     const struct rte_mbuf *m)\n+{\n+\tunsigned int hlen = m->l2_len + m->l3_len;\n+\tuint32_t *pi_data;\n+\tuint32_t pkt_hlen;\n+\n+\tpkt->type = RNDIS_PACKET_MSG;\n+\tpkt->len = m->pkt_len;\n+\tpkt->dataoffset = 0;\n+\tpkt->datalen = m->pkt_len;\n+\tpkt->oobdataoffset = 0;\n+\tpkt->oobdatalen = 0;\n+\tpkt->oobdataelements = 0;\n+\tpkt->pktinfooffset = sizeof(*pkt);\n+\tpkt->pktinfolen = 0;\n+\tpkt->vchandle = 0;\n+\tpkt->reserved = 0;\n+\n+\t/*\n+\t * Set the hash value for this packet, to the queue_id to cause\n+\t * TX done event for this packet on the right channel.\n+\t */\n+\tpi_data = hn_rndis_pktinfo_append(pkt, NDIS_HASH_VALUE_SIZE,\n+\t\t\t\t\t  NDIS_PKTINFO_TYPE_HASHVAL);\n+\t*pi_data = queue_id;\n+\n+\tif (m->ol_flags & PKT_TX_VLAN_PKT) {\n+\t\tpi_data = hn_rndis_pktinfo_append(pkt, NDIS_VLAN_INFO_SIZE,\n+\t\t\t\t\t\t  NDIS_PKTINFO_TYPE_VLAN);\n+\t\t*pi_data = m->vlan_tci;\n+\t}\n+\n+\tif (m->ol_flags & PKT_TX_TCP_SEG) {\n+\t\tpi_data = hn_rndis_pktinfo_append(pkt, NDIS_LSO2_INFO_SIZE,\n+\t\t\t\t\t\t  NDIS_PKTINFO_TYPE_LSO);\n+\n+\t\tif (m->ol_flags & PKT_TX_IPV6) {\n+\t\t\t*pi_data = NDIS_LSO2_INFO_MAKEIPV6(hlen,\n+\t\t\t\t\t\t\t   m->tso_segsz);\n+\t\t} else {\n+\t\t\t*pi_data = NDIS_LSO2_INFO_MAKEIPV4(hlen,\n+\t\t\t\t\t\t\t   m->tso_segsz);\n+\t\t}\n+\t} else if (m->ol_flags &\n+\t\t   (PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM | PKT_TX_IP_CKSUM)) {\n+\t\tpi_data = hn_rndis_pktinfo_append(pkt, NDIS_TXCSUM_INFO_SIZE,\n+\t\t\t\t\t\t  NDIS_PKTINFO_TYPE_CSUM);\n+\t\t*pi_data = 0;\n+\n+\t\tif (m->ol_flags & PKT_TX_IPV6)\n+\t\t\t*pi_data |= NDIS_TXCSUM_INFO_IPV6;\n+\t\tif (m->ol_flags & PKT_TX_IPV4) {\n+\t\t\t*pi_data |= NDIS_TXCSUM_INFO_IPV4;\n+\n+\t\t\tif (m->ol_flags & PKT_TX_IP_CKSUM)\n+\t\t\t\t*pi_data |= NDIS_TXCSUM_INFO_IPCS;\n+\t\t}\n+\n+\t\tif (m->ol_flags & PKT_TX_TCP_CKSUM)\n+\t\t\t*pi_data |= NDIS_TXCSUM_INFO_MKTCPCS(hlen);\n+\t\telse if (m->ol_flags & PKT_TX_UDP_CKSUM)\n+\t\t\t*pi_data |= NDIS_TXCSUM_INFO_MKUDPCS(hlen);\n+\t}\n+\n+\tpkt_hlen = pkt->pktinfooffset + pkt->pktinfolen;\n+\t/* Fixup RNDIS packet message total length */\n+\tpkt->len += pkt_hlen;\n+\n+\t/* Convert RNDIS packet message offsets */\n+\tpkt->dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);\n+\tpkt->pktinfooffset = hn_rndis_pktmsg_offset(pkt->pktinfooffset);\n+}\n+\n+/* How many scatter gather list elements ar needed */\n+static unsigned int hn_get_slots(const struct rte_mbuf *m)\n+{\n+\tunsigned int slots = 1; /* for RNDIS header */\n+\n+\twhile (m) {\n+\t\tunsigned int size = rte_pktmbuf_data_len(m);\n+\t\tunsigned int offs = rte_mbuf_data_iova(m) & PAGE_MASK;\n+\n+\t\tslots += (offs + size + PAGE_SIZE - 1) / PAGE_SIZE;\n+\t\tm = m->next;\n+\t}\n+\n+\treturn slots;\n+}\n+\n+/* Build scatter gather list from chained mbuf */\n+static unsigned int hn_fill_sg(struct vmbus_gpa *sg,\n+\t\t\t       const struct rte_mbuf *m)\n+{\n+\tunsigned int segs = 0;\n+\n+\twhile (m) {\n+\t\trte_iova_t addr = rte_mbuf_data_iova(m);\n+\t\tunsigned int page = addr / PAGE_SIZE;\n+\t\tunsigned int offset = addr & PAGE_MASK;\n+\t\tunsigned int len = rte_pktmbuf_data_len(m);\n+\n+\t\twhile (len > 0) {\n+\t\t\tunsigned int bytes = RTE_MIN(len, PAGE_SIZE - offset);\n+\n+\t\t\tsg[segs].page = page;\n+\t\t\tsg[segs].ofs = offset;\n+\t\t\tsg[segs].len = bytes;\n+\t\t\tsegs++;\n+\n+\t\t\t++page;\n+\t\t\toffset = 0;\n+\t\t\tlen -= bytes;\n+\t\t}\n+\t\tm = m->next;\n+\t}\n+\n+\treturn segs;\n+}\n+\n+/* Transmit directly from mbuf */\n+static int hn_xmit_sg(struct hn_tx_queue *txq,\n+\t\t      const struct hn_txdesc *txd, const struct rte_mbuf *m,\n+\t\t      bool *need_sig)\n+{\n+\tstruct vmbus_gpa sg[hn_get_slots(m)];\n+\tstruct hn_nvs_rndis nvs_rndis = {\n+\t\t.type = NVS_TYPE_RNDIS,\n+\t\t.rndis_mtype = NVS_RNDIS_MTYPE_DATA,\n+\t\t.chim_sz = txd->chim_size,\n+\t};\n+\trte_iova_t addr;\n+\tunsigned int segs;\n+\n+\t/* attach aggregation data if present */\n+\tif (txd->chim_size > 0)\n+\t\tnvs_rndis.chim_idx = txd->chim_index;\n+\telse\n+\t\tnvs_rndis.chim_idx = NVS_CHIM_IDX_INVALID;\n+\n+\thn_rndis_dump(txd->rndis_pkt);\n+\n+\t/* pass IOVA of rndis header in first segment */\n+\taddr = rte_malloc_virt2iova(txd->rndis_pkt);\n+\tif (unlikely(addr == RTE_BAD_IOVA)) {\n+\t\tPMD_DRV_LOG(ERR, \"RNDIS transmit can not get iova\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsg[0].page = addr / PAGE_SIZE;\n+\tsg[0].ofs = addr & PAGE_MASK;\n+\tsg[0].len = RNDIS_PACKET_MSG_OFFSET_ABS(hn_rndis_pktlen(txd->rndis_pkt));\n+\tsegs = 1;\n+\n+\thn_update_packet_stats(&txq->stats, m);\n+\n+\tsegs += hn_fill_sg(sg + 1, m);\n+\n+\tPMD_TX_LOG(DEBUG, \"port %u:%u tx %u segs %u size %u\",\n+\t\t   txq->port_id, txq->queue_id, txd->chim_index,\n+\t\t   segs, nvs_rndis.chim_sz);\n+\n+\treturn hn_nvs_send_sglist(txq->chan, sg, segs,\n+\t\t\t\t  &nvs_rndis, sizeof(nvs_rndis),\n+\t\t\t\t  (uintptr_t)txd, need_sig);\n+}\n+\n+uint16_t\n+hn_xmit_pkts(void *ptxq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)\n+{\n+\tstruct hn_tx_queue *txq = ptxq;\n+\tstruct hn_data *hv = txq->hv;\n+\tbool need_sig = false;\n+\tuint16_t nb_tx;\n+\tint ret;\n+\n+\tif (unlikely(hv->closed))\n+\t\treturn 0;\n+\n+\tif (rte_mempool_avail_count(hv->tx_pool) <= txq->free_thresh)\n+\t\thn_process_events(hv, txq->queue_id);\n+\n+\tfor (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {\n+\t\tstruct rte_mbuf *m = tx_pkts[nb_tx];\n+\t\tuint32_t pkt_size = m->pkt_len + HN_RNDIS_PKT_LEN;\n+\t\tstruct rndis_packet_msg *pkt;\n+\n+\t\t/* For small packets aggregate them in chimney buffer */\n+\t\tif (m->pkt_len < HN_TXCOPY_THRESHOLD && pkt_size <= txq->agg_szmax) {\n+\t\t\t/* If this packet will not fit, then flush  */\n+\t\t\tif (txq->agg_pktleft == 0 ||\n+\t\t\t    RTE_ALIGN(pkt_size, txq->agg_align) > txq->agg_szleft) {\n+\t\t\t\tif (hn_flush_txagg(txq, &need_sig))\n+\t\t\t\t\tgoto fail;\n+\t\t\t}\n+\n+\t\t\tpkt = hn_try_txagg(hv, txq, pkt_size);\n+\t\t\tif (unlikely(!pkt))\n+\t\t\t\tgoto fail;\n+\n+\t\t\thn_encap(pkt, txq->queue_id, m);\n+\t\t\thn_append_to_chim(txq, pkt, m);\n+\n+\t\t\trte_pktmbuf_free(m);\n+\n+\t\t\t/* if buffer is full, flush */\n+\t\t\tif (txq->agg_pktleft == 0 &&\n+\t\t\t    hn_flush_txagg(txq, &need_sig))\n+\t\t\t\tgoto fail;\n+\t\t} else {\n+\t\t\tstruct hn_txdesc *txd;\n+\n+\t\t\t/* can send chimney data and large packet at once */\n+\t\t\ttxd = txq->agg_txd;\n+\t\t\tif (txd) {\n+\t\t\t\thn_reset_txagg(txq);\n+\t\t\t} else {\n+\t\t\t\ttxd = hn_new_txd(hv, txq);\n+\t\t\t\tif (unlikely(!txd))\n+\t\t\t\t\tgoto fail;\n+\t\t\t}\n+\n+\t\t\tpkt = txd->rndis_pkt;\n+\t\t\ttxd->m = m;\n+\t\t\ttxd->data_size += m->pkt_len;\n+\t\t\t++txd->packets;\n+\n+\t\t\thn_encap(pkt, txq->queue_id, m);\n+\n+\t\t\tret = hn_xmit_sg(txq, txd, m, &need_sig);\n+\t\t\tif (unlikely(ret != 0)) {\n+\t\t\t\tPMD_TX_LOG(NOTICE, \"sg send failed: %d\", ret);\n+\t\t\t\t++txq->stats.errors;\n+\t\t\t\trte_mempool_put(hv->tx_pool, txd);\n+\t\t\t\tgoto fail;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* If partial buffer left, then try and send it.\n+\t * if that fails, then reuse it on next send.\n+\t */\n+\thn_flush_txagg(txq, &need_sig);\n+\n+fail:\n+\tif (need_sig)\n+\t\trte_vmbus_chan_signal_tx(txq->chan);\n+\n+\treturn nb_tx;\n+}\n+\n+uint16_t\n+hn_recv_pkts(void *prxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)\n+{\n+\tstruct hn_rx_queue *rxq = prxq;\n+\tstruct hn_data *hv = rxq->hv;\n+\n+\tif (unlikely(hv->closed))\n+\t\treturn 0;\n+\n+\t/* Get all outstanding receive completions */\n+\thn_process_events(hv, rxq->queue_id);\n+\n+\t/* Get mbufs off staging ring */\n+\treturn rte_ring_sc_dequeue_burst(rxq->rx_ring, (void **)rx_pkts,\n+\t\t\t\t\t nb_pkts, NULL);\n+}\ndiff --git a/drivers/net/netvsc/hn_var.h b/drivers/net/netvsc/hn_var.h\nnew file mode 100644\nindex 000000000000..f0358c58226a\n--- /dev/null\n+++ b/drivers/net/netvsc/hn_var.h\n@@ -0,0 +1,153 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2009-2018 Microsoft Corp.\n+ * Copyright (c) 2016 Brocade Communications Systems, Inc.\n+ * Copyright (c) 2012 NetApp Inc.\n+ * Copyright (c) 2012 Citrix Inc.\n+ * All rights reserved.\n+ */\n+\n+/*\n+ * Tunable ethdev params\n+ */\n+#define HN_MIN_RX_BUF_SIZE\t1024\n+#define HN_MAX_XFER_LEN\t\t2048\n+#define\tHN_MAX_MAC_ADDRS\t1\n+#define HN_MAX_CHANNELS\t\t64\n+\n+/* Claimed to be 12232B */\n+#define HN_MTU_MAX\t\t(9 * 1024)\n+\n+/* Retry interval */\n+#define HN_CHAN_INTERVAL_US\t100\n+\n+/* Buffers need to be aligned */\n+#ifndef PAGE_SIZE\n+#define PAGE_SIZE 4096\n+#endif\n+\n+#ifndef PAGE_MASK\n+#define PAGE_MASK (PAGE_SIZE - 1)\n+#endif\n+\n+struct hn_data;\n+struct hn_txdesc;\n+\n+struct hn_stats {\n+\tuint64_t\tpackets;\n+\tuint64_t\tbytes;\n+\tuint64_t\terrors;\n+\tuint64_t\tnomemory;\n+\tuint64_t\tmulticast;\n+\tuint64_t\tbroadcast;\n+\t/* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */\n+\tuint64_t\tsize_bins[8];\n+};\n+\n+struct hn_tx_queue {\n+\tstruct hn_data  *hv;\n+\tstruct vmbus_channel *chan;\n+\tuint16_t\tport_id;\n+\tuint16_t\tqueue_id;\n+\tuint32_t\tfree_thresh;\n+\n+\t/* Applied packet transmission aggregation limits. */\n+\tuint32_t\tagg_szmax;\n+\tuint32_t\tagg_pktmax;\n+\tuint32_t\tagg_align;\n+\n+\t/* Packet transmission aggregation states */\n+\tstruct hn_txdesc *agg_txd;\n+\tuint32_t\tagg_pktleft;\n+\tuint32_t\tagg_szleft;\n+\tstruct rndis_packet_msg *agg_prevpkt;\n+\n+\tstruct hn_stats stats;\n+};\n+\n+struct hn_rx_queue {\n+\tstruct hn_data  *hv;\n+\tstruct vmbus_channel *chan;\n+\tstruct rte_mempool *mb_pool;\n+\tstruct rte_ring *rx_ring;\n+\tvoid\t*event_buf;\n+\n+\trte_spinlock_t ring_lock;\n+\tuint32_t event_sz;\n+\tuint16_t port_id;\n+\tuint16_t queue_id;\n+\tstruct hn_stats stats;\n+\tuint64_t ring_full;\n+};\n+\n+\n+/* multi-packet data from host */\n+struct hn_rx_bufinfo {\n+\tstruct vmbus_channel *chan;\n+\tstruct hn_data *hv;\n+\tuint64_t\txactid;\n+\tstruct rte_mbuf_ext_shared_info shinfo;\n+} __rte_cache_aligned;\n+\n+struct hn_data {\n+\tstruct rte_vmbus_device *vmbus;\n+\tstruct hn_rx_queue *primary;\n+\tuint16_t\tport_id;\n+\tbool\t\tclosed;\n+\tuint32_t\tlink_status;\n+\tuint32_t\tlink_speed;\n+\n+\tstruct rte_mem_resource *rxbuf_res;\t/* UIO resource for Rx */\n+\tstruct hn_rx_bufinfo *rxbuf_info;\n+\tuint32_t\trxbuf_section_cnt;\t/* # of Rx sections */\n+\tvolatile uint32_t rxbuf_outstanding;\n+\tuint16_t\tmax_queues;\t\t/* Max available queues */\n+\tuint16_t\tnum_queues;\n+\tuint64_t\trss_offloads;\n+\n+\tstruct rte_mem_resource *chim_res;\t/* UIO resource for Tx */\n+\tstruct rte_mempool *tx_pool;\t\t/* Tx descriptors */\n+\tuint32_t\tchim_szmax;\t\t/* Max size per buffer */\n+\tuint32_t\tchim_cnt;\t\t/* Max packets per buffer */\n+\n+\tuint32_t\tnvs_ver;\n+\tuint32_t\tndis_ver;\n+\tuint32_t\trndis_agg_size;\n+\tuint32_t\trndis_agg_pkts;\n+\tuint32_t\trndis_agg_align;\n+\n+\tvolatile uint32_t  rndis_pending;\n+\trte_atomic32_t\trndis_req_id;\n+\tuint8_t\t\trndis_resp[256];\n+\n+\tstruct ether_addr mac_addr;\n+\tstruct vmbus_channel *channels[HN_MAX_CHANNELS];\n+};\n+\n+static inline struct vmbus_channel *\n+hn_primary_chan(const struct hn_data *hv)\n+{\n+\treturn hv->channels[0];\n+}\n+\n+void hn_process_events(struct hn_data *hv, uint16_t queue_id);\n+\n+uint16_t hn_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,\n+\t\t      uint16_t nb_pkts);\n+uint16_t hn_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,\n+\t\t      uint16_t nb_pkts);\n+\n+int\thn_tx_pool_init(struct rte_eth_dev *dev);\n+int\thn_dev_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx,\n+\t\t\t      uint16_t nb_desc, unsigned int socket_id,\n+\t\t\t      const struct rte_eth_txconf *tx_conf);\n+void\thn_dev_tx_queue_release(void *arg);\n+\n+struct hn_rx_queue *hn_rx_queue_alloc(struct hn_data *hv,\n+\t\t\t\t      uint16_t queue_id,\n+\t\t\t\t      unsigned int socket_id);\n+int\thn_dev_rx_queue_setup(struct rte_eth_dev *dev,\n+\t\t\t      uint16_t queue_idx, uint16_t nb_desc,\n+\t\t\t      unsigned int socket_id,\n+\t\t\t      const struct rte_eth_rxconf *rx_conf,\n+\t\t\t      struct rte_mempool *mp);\n+void\thn_dev_rx_queue_release(void *arg);\ndiff --git a/drivers/net/netvsc/meson.build b/drivers/net/netvsc/meson.build\nnew file mode 100644\nindex 000000000000..68fe9b7e6b46\n--- /dev/null\n+++ b/drivers/net/netvsc/meson.build\n@@ -0,0 +1,7 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2018 Microsoft Corporation\n+\n+version = 2\n+sources = files('hn_ethdev.c', 'hn_rxtx.c', 'hn_rndis.c', 'hn_nvs.c')\n+\n+deps += ['bus_vmbus' ]\ndiff --git a/drivers/net/netvsc/ndis.h b/drivers/net/netvsc/ndis.h\nnew file mode 100644\nindex 000000000000..2e7ca99b151f\n--- /dev/null\n+++ b/drivers/net/netvsc/ndis.h\n@@ -0,0 +1,378 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2018 Microsoft Corp.\n+ * All rights reserved.\n+ */\n+\n+#ifndef _NET_NDIS_H_\n+#define _NET_NDIS_H_\n+\n+#define\tNDIS_MEDIA_STATE_CONNECTED\t0\n+#define\tNDIS_MEDIA_STATE_DISCONNECTED\t1\n+\n+#define\tNDIS_NETCHANGE_TYPE_POSSIBLE\t1\n+#define\tNDIS_NETCHANGE_TYPE_DEFINITE\t2\n+#define\tNDIS_NETCHANGE_TYPE_FROMMEDIA\t3\n+\n+#define\tNDIS_OFFLOAD_SET_NOCHG\t\t0\n+#define\tNDIS_OFFLOAD_SET_ON\t\t1\n+#define\tNDIS_OFFLOAD_SET_OFF\t\t2\n+\n+/* a.k.a GRE MAC */\n+#define\tNDIS_ENCAP_TYPE_NVGRE\t\t0x00000001\n+\n+#define\tNDIS_HASH_FUNCTION_MASK\t\t0x000000FF\t/* see hash function */\n+#define\tNDIS_HASH_TYPE_MASK\t\t0x00FFFF00\t/* see hash type */\n+\n+/* hash function */\n+#define\tNDIS_HASH_FUNCTION_TOEPLITZ\t0x00000001\n+\n+/* hash type */\n+#define\tNDIS_HASH_IPV4\t\t\t0x00000100\n+#define\tNDIS_HASH_TCP_IPV4\t\t0x00000200\n+#define\tNDIS_HASH_IPV6\t\t\t0x00000400\n+#define\tNDIS_HASH_IPV6_EX\t\t0x00000800\n+#define\tNDIS_HASH_TCP_IPV6\t\t0x00001000\n+#define\tNDIS_HASH_TCP_IPV6_EX\t\t0x00002000\n+\n+#define\tNDIS_HASH_KEYSIZE_TOEPLITZ\t40\n+#define\tNDIS_HASH_INDCNT\t\t128\n+\n+#define\tNDIS_OBJTYPE_DEFAULT\t\t0x80\n+#define\tNDIS_OBJTYPE_RSS_CAPS\t\t0x88\n+#define\tNDIS_OBJTYPE_RSS_PARAMS\t\t0x89\n+#define\tNDIS_OBJTYPE_OFFLOAD\t\t0xa7\n+\n+struct ndis_object_hdr {\n+\tuint8_t\t\t\tndis_type;\t/* NDIS_OBJTYPE_ */\n+\tuint8_t\t\t\tndis_rev;\t/* type specific */\n+\tuint16_t\t\tndis_size;\t/* incl. this hdr */\n+} __rte_packed;\n+\n+/*\n+ * OID_TCP_OFFLOAD_PARAMETERS\n+ * ndis_type: NDIS_OBJTYPE_DEFAULT\n+ */\n+struct ndis_offload_params {\n+\tstruct ndis_object_hdr\tndis_hdr;\n+\tuint8_t\t\t\tndis_ip4csum;\t/* NDIS_OFFLOAD_PARAM_ */\n+\tuint8_t\t\t\tndis_tcp4csum;\t/* NDIS_OFFLOAD_PARAM_ */\n+\tuint8_t\t\t\tndis_udp4csum;\t/* NDIS_OFFLOAD_PARAM_ */\n+\tuint8_t\t\t\tndis_tcp6csum;\t/* NDIS_OFFLOAD_PARAM_ */\n+\tuint8_t\t\t\tndis_udp6csum;\t/* NDIS_OFFLOAD_PARAM_ */\n+\tuint8_t\t\t\tndis_lsov1;\t/* NDIS_OFFLOAD_PARAM_ */\n+\tuint8_t\t\t\tndis_ipsecv1;\t/* NDIS_OFFLOAD_IPSECV1_ */\n+\tuint8_t\t\t\tndis_lsov2_ip4;\t/* NDIS_OFFLOAD_LSOV2_ */\n+\tuint8_t\t\t\tndis_lsov2_ip6;\t/* NDIS_OFFLOAD_LSOV2_ */\n+\tuint8_t\t\t\tndis_tcp4conn;\t/* 0 */\n+\tuint8_t\t\t\tndis_tcp6conn;\t/* 0 */\n+\tuint32_t\t\tndis_flags;\t/* 0 */\n+\t/* NDIS >= 6.1 */\n+\tuint8_t\t\t\tndis_ipsecv2;\t/* NDIS_OFFLOAD_IPSECV2_ */\n+\tuint8_t\t\t\tndis_ipsecv2_ip4;/* NDIS_OFFLOAD_IPSECV2_ */\n+\t/* NDIS >= 6.30 */\n+\tuint8_t\t\t\tndis_rsc_ip4;\t/* NDIS_OFFLOAD_RSC_ */\n+\tuint8_t\t\t\tndis_rsc_ip6;\t/* NDIS_OFFLOAD_RSC_ */\n+\tuint8_t\t\t\tndis_encap;\t/* NDIS_OFFLOAD_SET_ */\n+\tuint8_t\t\t\tndis_encap_types;/* NDIS_ENCAP_TYPE_ */\n+};\n+\n+#define\tNDIS_OFFLOAD_PARAMS_SIZE\tsizeof(struct ndis_offload_params)\n+#define\tNDIS_OFFLOAD_PARAMS_SIZE_6_1\t\\\n+\toffsetof(struct ndis_offload_params, ndis_rsc_ip4)\n+\n+#define\tNDIS_OFFLOAD_PARAMS_REV_2\t2\t/* NDIS 6.1 */\n+#define\tNDIS_OFFLOAD_PARAMS_REV_3\t3\t/* NDIS 6.30 */\n+\n+#define\tNDIS_OFFLOAD_PARAM_NOCHG\t0\t/* common */\n+#define\tNDIS_OFFLOAD_PARAM_OFF\t\t1\n+#define\tNDIS_OFFLOAD_PARAM_TX\t\t2\n+#define\tNDIS_OFFLOAD_PARAM_RX\t\t3\n+#define\tNDIS_OFFLOAD_PARAM_TXRX\t\t4\n+\n+/* NDIS_OFFLOAD_PARAM_NOCHG */\n+#define\tNDIS_OFFLOAD_LSOV1_OFF\t\t1\n+#define\tNDIS_OFFLOAD_LSOV1_ON\t\t2\n+\n+/* NDIS_OFFLOAD_PARAM_NOCHG */\n+#define\tNDIS_OFFLOAD_IPSECV1_OFF\t1\n+#define\tNDIS_OFFLOAD_IPSECV1_AH\t\t2\n+#define\tNDIS_OFFLOAD_IPSECV1_ESP\t3\n+#define\tNDIS_OFFLOAD_IPSECV1_AH_ESP\t4\n+\n+/* NDIS_OFFLOAD_PARAM_NOCHG */\n+#define\tNDIS_OFFLOAD_LSOV2_OFF\t\t1\n+#define\tNDIS_OFFLOAD_LSOV2_ON\t\t2\n+\n+/* NDIS_OFFLOAD_PARAM_NOCHG */\n+#define\tNDIS_OFFLOAD_IPSECV2_OFF\t1\n+#define\tNDIS_OFFLOAD_IPSECV2_AH\t\t2\n+#define\tNDIS_OFFLOAD_IPSECV2_ESP\t3\n+#define\tNDIS_OFFLOAD_IPSECV2_AH_ESP\t4\n+\n+/* NDIS_OFFLOAD_PARAM_NOCHG */\n+#define\tNDIS_OFFLOAD_RSC_OFF\t\t1\n+#define\tNDIS_OFFLOAD_RSC_ON\t\t2\n+\n+/*\n+ * OID_GEN_RECEIVE_SCALE_CAPABILITIES\n+ * ndis_type: NDIS_OBJTYPE_RSS_CAPS\n+ */\n+struct ndis_rss_caps {\n+\tstruct ndis_object_hdr\t\tndis_hdr;\n+\tuint32_t\t\t\tndis_caps;\t/* NDIS_RSS_CAP_ */\n+\tuint32_t\t\t\tndis_nmsi;\t/* # of MSIs */\n+\tuint32_t\t\t\tndis_nrxr;\t/* # of RX rings */\n+\t/* NDIS >= 6.30 */\n+\tuint16_t\t\t\tndis_nind;\t/* # of indtbl ent. */\n+\tuint16_t\t\t\tndis_pad;\n+} __rte_packed;\n+\n+#define\tNDIS_RSS_CAPS_SIZE\t\t\\\n+\toffsetof(struct ndis_rss_caps, ndis_pad)\n+#define\tNDIS_RSS_CAPS_SIZE_6_0\t\t\\\n+\toffsetof(struct ndis_rss_caps, ndis_nind)\n+\n+#define\tNDIS_RSS_CAPS_REV_1\t\t1\t/* NDIS 6.{0,1,20} */\n+#define\tNDIS_RSS_CAPS_REV_2\t\t2\t/* NDIS 6.30 */\n+\n+#define\tNDIS_RSS_CAP_MSI\t\t0x01000000\n+#define\tNDIS_RSS_CAP_CLASSIFY_ISR\t0x02000000\n+#define\tNDIS_RSS_CAP_CLASSIFY_DPC\t0x04000000\n+#define\tNDIS_RSS_CAP_MSIX\t\t0x08000000\n+#define\tNDIS_RSS_CAP_IPV4\t\t0x00000100\n+#define\tNDIS_RSS_CAP_IPV6\t\t0x00000200\n+#define\tNDIS_RSS_CAP_IPV6_EX\t\t0x00000400\n+#define\tNDIS_RSS_CAP_HASH_TOEPLITZ\tNDIS_HASH_FUNCTION_TOEPLITZ\n+#define\tNDIS_RSS_CAP_HASHFUNC_MASK\tNDIS_HASH_FUNCTION_MASK\n+\n+/*\n+ * OID_GEN_RECEIVE_SCALE_PARAMETERS\n+ * ndis_type: NDIS_OBJTYPE_RSS_PARAMS\n+ */\n+struct ndis_rss_params {\n+\tstruct ndis_object_hdr\t\tndis_hdr;\n+\tuint16_t\t\t\tndis_flags;\t/* NDIS_RSS_FLAG_ */\n+\tuint16_t\t\t\tndis_bcpu;\t/* base cpu 0 */\n+\tuint32_t\t\t\tndis_hash;\t/* NDIS_HASH_ */\n+\tuint16_t\t\t\tndis_indsize;\t/* indirect table */\n+\tuint32_t\t\t\tndis_indoffset;\n+\tuint16_t\t\t\tndis_keysize;\t/* hash key */\n+\tuint32_t\t\t\tndis_keyoffset;\n+\t/* NDIS >= 6.20 */\n+\tuint32_t\t\t\tndis_cpumaskoffset;\n+\tuint32_t\t\t\tndis_cpumaskcnt;\n+\tuint32_t\t\t\tndis_cpumaskentsz;\n+};\n+\n+#define\tNDIS_RSS_PARAMS_SIZE\t\tsizeof(struct ndis_rss_params)\n+#define\tNDIS_RSS_PARAMS_SIZE_6_0\t\\\n+\toffsetof(struct ndis_rss_params, ndis_cpumaskoffset)\n+\n+#define\tNDIS_RSS_PARAMS_REV_1\t\t1\t/* NDIS 6.0 */\n+#define\tNDIS_RSS_PARAMS_REV_2\t\t2\t/* NDIS 6.20 */\n+\n+#define\tNDIS_RSS_FLAG_NONE\t\t0x0000\n+#define\tNDIS_RSS_FLAG_BCPU_UNCHG\t0x0001\n+#define\tNDIS_RSS_FLAG_HASH_UNCHG\t0x0002\n+#define\tNDIS_RSS_FLAG_IND_UNCHG\t\t0x0004\n+#define\tNDIS_RSS_FLAG_KEY_UNCHG\t\t0x0008\n+#define\tNDIS_RSS_FLAG_DISABLE\t\t0x0010\n+\n+/* non-standard convenient struct */\n+struct ndis_rssprm_toeplitz {\n+\tstruct ndis_rss_params\t\trss_params;\n+\t/* Indirect table */\n+\tuint32_t\t\t\trss_ind[NDIS_HASH_INDCNT];\n+\t/* Toeplitz hash key */\n+\tuint8_t\t\t\t\trss_key[NDIS_HASH_KEYSIZE_TOEPLITZ];\n+};\n+\n+#define\tNDIS_RSSPRM_TOEPLITZ_SIZE(nind)\t\\\n+\toffsetof(struct ndis_rssprm_toeplitz, rss_ind[nind])\n+\n+/*\n+ * OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES\n+ * ndis_type: NDIS_OBJTYPE_OFFLOAD\n+ */\n+\n+#define\tNDIS_OFFLOAD_ENCAP_NONE\t\t0x0000\n+#define\tNDIS_OFFLOAD_ENCAP_NULL\t\t0x0001\n+#define\tNDIS_OFFLOAD_ENCAP_8023\t\t0x0002\n+#define\tNDIS_OFFLOAD_ENCAP_8023PQ\t0x0004\n+#define\tNDIS_OFFLOAD_ENCAP_8023PQ_OOB\t0x0008\n+#define\tNDIS_OFFLOAD_ENCAP_RFC1483\t0x0010\n+\n+struct ndis_csum_offload {\n+\tuint32_t\t\t\tndis_ip4_txenc;\t/*NDIS_OFFLOAD_ENCAP_*/\n+\tuint32_t\t\t\tndis_ip4_txcsum;\n+#define\tNDIS_TXCSUM_CAP_IP4OPT\t\t0x001\n+#define\tNDIS_TXCSUM_CAP_TCP4OPT\t\t0x004\n+#define\tNDIS_TXCSUM_CAP_TCP4\t\t0x010\n+#define\tNDIS_TXCSUM_CAP_UDP4\t\t0x040\n+#define\tNDIS_TXCSUM_CAP_IP4\t\t0x100\n+\tuint32_t\t\t\tndis_ip4_rxenc;\t/*NDIS_OFFLOAD_ENCAP_*/\n+\tuint32_t\t\t\tndis_ip4_rxcsum;\n+#define\tNDIS_RXCSUM_CAP_IP4OPT\t\t0x001\n+#define\tNDIS_RXCSUM_CAP_TCP4OPT\t\t0x004\n+#define\tNDIS_RXCSUM_CAP_TCP4\t\t0x010\n+#define\tNDIS_RXCSUM_CAP_UDP4\t\t0x040\n+#define\tNDIS_RXCSUM_CAP_IP4\t\t0x100\n+\tuint32_t\t\t\tndis_ip6_txenc;\t/*NDIS_OFFLOAD_ENCAP_*/\n+\tuint32_t\t\t\tndis_ip6_txcsum;\n+#define\tNDIS_TXCSUM_CAP_IP6EXT\t\t0x001\n+#define\tNDIS_TXCSUM_CAP_TCP6OPT\t\t0x004\n+#define\tNDIS_TXCSUM_CAP_TCP6\t\t0x010\n+#define\tNDIS_TXCSUM_CAP_UDP6\t\t0x040\n+\tuint32_t\t\t\tndis_ip6_rxenc;\t/*NDIS_OFFLOAD_ENCAP_*/\n+\tuint32_t\t\t\tndis_ip6_rxcsum;\n+#define\tNDIS_RXCSUM_CAP_IP6EXT\t\t0x001\n+#define\tNDIS_RXCSUM_CAP_TCP6OPT\t\t0x004\n+#define\tNDIS_RXCSUM_CAP_TCP6\t\t0x010\n+#define\tNDIS_RXCSUM_CAP_UDP6\t\t0x040\n+};\n+\n+struct ndis_lsov1_offload {\n+\tuint32_t\t\t\tndis_encap;\t/*NDIS_OFFLOAD_ENCAP_*/\n+\tuint32_t\t\t\tndis_maxsize;\n+\tuint32_t\t\t\tndis_minsegs;\n+\tuint32_t\t\t\tndis_opts;\n+};\n+\n+struct ndis_ipsecv1_offload {\n+\tuint32_t\t\t\tndis_encap;\t/*NDIS_OFFLOAD_ENCAP_*/\n+\tuint32_t\t\t\tndis_ah_esp;\n+\tuint32_t\t\t\tndis_xport_tun;\n+\tuint32_t\t\t\tndis_ip4_opts;\n+\tuint32_t\t\t\tndis_flags;\n+\tuint32_t\t\t\tndis_ip4_ah;\n+\tuint32_t\t\t\tndis_ip4_esp;\n+};\n+\n+struct ndis_lsov2_offload {\n+\tuint32_t\t\t\tndis_ip4_encap;\t/*NDIS_OFFLOAD_ENCAP_*/\n+\tuint32_t\t\t\tndis_ip4_maxsz;\n+\tuint32_t\t\t\tndis_ip4_minsg;\n+\tuint32_t\t\t\tndis_ip6_encap;\t/*NDIS_OFFLOAD_ENCAP_*/\n+\tuint32_t\t\t\tndis_ip6_maxsz;\n+\tuint32_t\t\t\tndis_ip6_minsg;\n+\tuint32_t\t\t\tndis_ip6_opts;\n+#define\tNDIS_LSOV2_CAP_IP6EXT\t\t0x001\n+#define\tNDIS_LSOV2_CAP_TCP6OPT\t\t0x004\n+};\n+\n+struct ndis_ipsecv2_offload {\n+\tuint32_t\t\t\tndis_encap;\t/*NDIS_OFFLOAD_ENCAP_*/\n+\tuint16_t\t\t\tndis_ip6;\n+\tuint16_t\t\t\tndis_ip4opt;\n+\tuint16_t\t\t\tndis_ip6ext;\n+\tuint16_t\t\t\tndis_ah;\n+\tuint16_t\t\t\tndis_esp;\n+\tuint16_t\t\t\tndis_ah_esp;\n+\tuint16_t\t\t\tndis_xport;\n+\tuint16_t\t\t\tndis_tun;\n+\tuint16_t\t\t\tndis_xport_tun;\n+\tuint16_t\t\t\tndis_lso;\n+\tuint16_t\t\t\tndis_extseq;\n+\tuint32_t\t\t\tndis_udp_esp;\n+\tuint32_t\t\t\tndis_auth;\n+\tuint32_t\t\t\tndis_crypto;\n+\tuint32_t\t\t\tndis_sa_caps;\n+};\n+\n+struct ndis_rsc_offload {\n+\tuint16_t\t\t\tndis_ip4;\n+\tuint16_t\t\t\tndis_ip6;\n+};\n+\n+struct ndis_encap_offload {\n+\tuint32_t\t\t\tndis_flags;\n+\tuint32_t\t\t\tndis_maxhdr;\n+};\n+\n+struct ndis_offload {\n+\tstruct ndis_object_hdr\t\tndis_hdr;\n+\tstruct ndis_csum_offload\tndis_csum;\n+\tstruct ndis_lsov1_offload\tndis_lsov1;\n+\tstruct ndis_ipsecv1_offload\tndis_ipsecv1;\n+\tstruct ndis_lsov2_offload\tndis_lsov2;\n+\tuint32_t\t\t\tndis_flags;\n+\t/* NDIS >= 6.1 */\n+\tstruct ndis_ipsecv2_offload\tndis_ipsecv2;\n+\t/* NDIS >= 6.30 */\n+\tstruct ndis_rsc_offload\t\tndis_rsc;\n+\tstruct ndis_encap_offload\tndis_encap_gre;\n+};\n+\n+#define\tNDIS_OFFLOAD_SIZE\t\tsizeof(struct ndis_offload)\n+#define\tNDIS_OFFLOAD_SIZE_6_0\t\toffsetof(struct ndis_offload, ndis_ipsecv2)\n+#define\tNDIS_OFFLOAD_SIZE_6_1\t\toffsetof(struct ndis_offload, ndis_rsc)\n+\n+#define\tNDIS_OFFLOAD_REV_1\t\t1\t/* NDIS 6.0 */\n+#define\tNDIS_OFFLOAD_REV_2\t\t2\t/* NDIS 6.1 */\n+#define\tNDIS_OFFLOAD_REV_3\t\t3\t/* NDIS 6.30 */\n+\n+/*\n+ * Per-packet-info\n+ */\n+\n+/* VLAN */\n+#define\tNDIS_VLAN_INFO_SIZE\t\tsizeof(uint32_t)\n+#define\tNDIS_VLAN_INFO_PRI_MASK\t\t0x0007\n+#define\tNDIS_VLAN_INFO_CFI_MASK\t\t0x0008\n+#define\tNDIS_VLAN_INFO_ID_MASK\t\t0xfff0\n+#define\tNDIS_VLAN_INFO_MAKE(id, pri, cfi)\t\\\n+\t(((pri) & NDIS_VLAN_INFO_PRI_MASK) |\t\\\n+\t (((cfi) & 0x1) << 3) | (((id) & 0xfff) << 4))\n+#define\tNDIS_VLAN_INFO_ID(inf)\t\t(((inf) & NDIS_VLAN_INFO_ID_MASK) >> 4)\n+#define\tNDIS_VLAN_INFO_CFI(inf)\t\t(((inf) & NDIS_VLAN_INFO_CFI_MASK) >> 3)\n+#define\tNDIS_VLAN_INFO_PRI(inf)\t\t((inf) & NDIS_VLAN_INFO_PRI_MASK)\n+\n+/* Reception checksum */\n+#define\tNDIS_RXCSUM_INFO_SIZE\t\tsizeof(uint32_t)\n+#define\tNDIS_RXCSUM_INFO_TCPCS_FAILED\t0x0001\n+#define\tNDIS_RXCSUM_INFO_UDPCS_FAILED\t0x0002\n+#define\tNDIS_RXCSUM_INFO_IPCS_FAILED\t0x0004\n+#define\tNDIS_RXCSUM_INFO_TCPCS_OK\t0x0008\n+#define\tNDIS_RXCSUM_INFO_UDPCS_OK\t0x0010\n+#define\tNDIS_RXCSUM_INFO_IPCS_OK\t0x0020\n+#define\tNDIS_RXCSUM_INFO_LOOPBACK\t0x0040\n+#define\tNDIS_RXCSUM_INFO_TCPCS_INVAL\t0x0080\n+#define\tNDIS_RXCSUM_INFO_IPCS_INVAL\t0x0100\n+\n+/* LSOv2 */\n+#define\tNDIS_LSO2_INFO_SIZE\t\tsizeof(uint32_t)\n+#define\tNDIS_LSO2_INFO_MSS_MASK\t\t0x000fffff\n+#define\tNDIS_LSO2_INFO_THOFF_MASK\t0x3ff00000\n+#define\tNDIS_LSO2_INFO_ISLSO2\t\t0x40000000\n+#define\tNDIS_LSO2_INFO_ISIPV6\t\t0x80000000\n+\n+#define\tNDIS_LSO2_INFO_MAKE(thoff, mss)\t\t\t\t\\\n+\t((((uint32_t)(mss)) & NDIS_LSO2_INFO_MSS_MASK) |\t\\\n+\t ((((uint32_t)(thoff)) & 0x3ff) << 20) |\t\t\\\n+\t NDIS_LSO2_INFO_ISLSO2)\n+\n+#define\tNDIS_LSO2_INFO_MAKEIPV4(thoff, mss)\t\t\t\\\n+\tNDIS_LSO2_INFO_MAKE((thoff), (mss))\n+\n+#define\tNDIS_LSO2_INFO_MAKEIPV6(thoff, mss)\t\t\t\\\n+\t(NDIS_LSO2_INFO_MAKE((thoff), (mss)) | NDIS_LSO2_INFO_ISIPV6)\n+\n+/* Transmission checksum */\n+#define\tNDIS_TXCSUM_INFO_SIZE\t\tsizeof(uint32_t)\n+#define\tNDIS_TXCSUM_INFO_IPV4\t\t0x00000001\n+#define\tNDIS_TXCSUM_INFO_IPV6\t\t0x00000002\n+#define\tNDIS_TXCSUM_INFO_TCPCS\t\t0x00000004\n+#define\tNDIS_TXCSUM_INFO_UDPCS\t\t0x00000008\n+#define\tNDIS_TXCSUM_INFO_IPCS\t\t0x00000010\n+#define\tNDIS_TXCSUM_INFO_THOFF\t\t0x03ff0000\n+\n+#define\tNDIS_TXCSUM_INFO_MKL4CS(thoff, flag)\t\t\t\\\n+\t((((uint32_t)(thoff)) << 16) | (flag))\n+\n+#define\tNDIS_TXCSUM_INFO_MKTCPCS(thoff)\t\t\t\t\\\n+\tNDIS_TXCSUM_INFO_MKL4CS((thoff), NDIS_TXCSUM_INFO_TCPCS)\n+\n+#define\tNDIS_TXCSUM_INFO_MKUDPCS(thoff)\t\t\t\t\\\n+\tNDIS_TXCSUM_INFO_MKL4CS((thoff), NDIS_TXCSUM_INFO_UDPCS)\n+\n+#endif\t/* !_NET_NDIS_H_ */\ndiff --git a/drivers/net/netvsc/rndis.h b/drivers/net/netvsc/rndis.h\nnew file mode 100644\nindex 000000000000..eac9a99fd8ef\n--- /dev/null\n+++ b/drivers/net/netvsc/rndis.h\n@@ -0,0 +1,414 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2018 Microsoft Corp.\n+ * Copyright (c) 2010 Jonathan Armani <armani@openbsd.org>\n+ * Copyright (c) 2010 Fabien Romano <fabien@openbsd.org>\n+ * Copyright (c) 2010 Michael Knudsen <mk@openbsd.org>\n+ * All rights reserved.\n+ */\n+\n+#ifndef\t_NET_RNDIS_H_\n+#define\t_NET_RNDIS_H_\n+\n+/* Canonical major/minor version as of 22th Aug. 2016. */\n+#define\tRNDIS_VERSION_MAJOR\t\t0x00000001\n+#define\tRNDIS_VERSION_MINOR\t\t0x00000000\n+\n+#define\tRNDIS_STATUS_SUCCESS\t\t0x00000000\n+#define\tRNDIS_STATUS_PENDING\t\t0x00000103\n+\n+#define RNDIS_STATUS_ONLINE\t\t0x40010003\n+#define RNDIS_STATUS_RESET_START\t0x40010004\n+#define RNDIS_STATUS_RESET_END\t\t0x40010005\n+#define RNDIS_STATUS_RING_STATUS\t0x40010006\n+#define RNDIS_STATUS_CLOSED\t\t0x40010007\n+#define RNDIS_STATUS_WAN_LINE_UP\t0x40010008\n+#define RNDIS_STATUS_WAN_LINE_DOWN\t0x40010009\n+#define RNDIS_STATUS_WAN_FRAGMENT\t0x4001000A\n+#define\tRNDIS_STATUS_MEDIA_CONNECT\t0x4001000B\n+#define\tRNDIS_STATUS_MEDIA_DISCONNECT\t0x4001000C\n+#define RNDIS_STATUS_HARDWARE_LINE_UP\t0x4001000D\n+#define RNDIS_STATUS_HARDWARE_LINE_DOWN\t0x4001000E\n+#define RNDIS_STATUS_INTERFACE_UP\t0x4001000F\n+#define RNDIS_STATUS_INTERFACE_DOWN\t0x40010010\n+#define RNDIS_STATUS_MEDIA_BUSY\t\t0x40010011\n+#define\tRNDIS_STATUS_MEDIA_SPECIFIC_INDICATION\t0x40010012\n+#define RNDIS_STATUS_WW_INDICATION\tRDIA_SPECIFIC_INDICATION\n+#define RNDIS_STATUS_LINK_SPEED_CHANGE\t0x40010013\n+#define RNDIS_STATUS_NETWORK_CHANGE\t0x40010018\n+#define\tRNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG 0x40020006\n+\n+#define\tRNDIS_STATUS_FAILURE\t\t0xC0000001\n+#define RNDIS_STATUS_RESOURCES\t\t0xC000009A\n+#define\tRNDIS_STATUS_NOT_SUPPORTED\t0xC00000BB\n+#define RNDIS_STATUS_CLOSING\t\t0xC0010002\n+#define RNDIS_STATUS_BAD_VERSION\t0xC0010004\n+#define RNDIS_STATUS_BAD_CHARACTERISTICS 0xC0010005\n+#define RNDIS_STATUS_ADAPTER_NOT_FOUND\t0xC0010006\n+#define RNDIS_STATUS_OPEN_FAILED\t0xC0010007\n+#define RNDIS_STATUS_DEVICE_FAILED\t0xC0010008\n+#define RNDIS_STATUS_MULTICAST_FULL\t0xC0010009\n+#define RNDIS_STATUS_MULTICAST_EXISTS\t0xC001000A\n+#define RNDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B\n+#define RNDIS_STATUS_REQUEST_ABORTED\t0xC001000C\n+#define RNDIS_STATUS_RESET_IN_PROGRESS\t0xC001000D\n+#define RNDIS_STATUS_CLOSING_INDICATING\t0xC001000E\n+#define RNDIS_STATUS_INVALID_PACKET\t0xC001000F\n+#define RNDIS_STATUS_OPEN_LIST_FULL\t0xC0010010\n+#define RNDIS_STATUS_ADAPTER_NOT_READY\t0xC0010011\n+#define RNDIS_STATUS_ADAPTER_NOT_OPEN\t0xC0010012\n+#define RNDIS_STATUS_NOT_INDICATING\t0xC0010013\n+#define RNDIS_STATUS_INVALID_LENGTH\t0xC0010014\n+#define\tRNDIS_STATUS_INVALID_DATA\t0xC0010015\n+#define RNDIS_STATUS_BUFFER_TOO_SHORT\t0xC0010016\n+#define RNDIS_STATUS_INVALID_OID\t0xC0010017\n+#define RNDIS_STATUS_ADAPTER_REMOVED\t0xC0010018\n+#define RNDIS_STATUS_UNSUPPORTED_MEDIA\t0xC0010019\n+#define RNDIS_STATUS_GROUP_ADDRESS_IN_US 0xC001001A\n+#define RNDIS_STATUS_FILE_NOT_FOUND\t0xC001001B\n+#define RNDIS_STATUS_ERROR_READING_FILE\t0xC001001C\n+#define RNDIS_STATUS_ALREADY_MAPPED\t0xC001001D\n+#define RNDIS_STATUS_RESOURCE_CONFLICT\t0xC001001E\n+#define RNDIS_STATUS_NO_CABLE\t\t0xC001001F\n+\n+#define\tOID_GEN_SUPPORTED_LIST\t\t0x00010101\n+#define\tOID_GEN_HARDWARE_STATUS\t\t0x00010102\n+#define\tOID_GEN_MEDIA_SUPPORTED\t\t0x00010103\n+#define\tOID_GEN_MEDIA_IN_USE\t\t0x00010104\n+#define\tOID_GEN_MAXIMUM_LOOKAHEAD\t0x00010105\n+#define\tOID_GEN_MAXIMUM_FRAME_SIZE\t0x00010106\n+#define\tOID_GEN_LINK_SPEED\t\t0x00010107\n+#define\tOID_GEN_TRANSMIT_BUFFER_SPACE\t0x00010108\n+#define\tOID_GEN_RECEIVE_BUFFER_SPACE\t0x00010109\n+#define\tOID_GEN_TRANSMIT_BLOCK_SIZE\t0x0001010A\n+#define\tOID_GEN_RECEIVE_BLOCK_SIZE\t0x0001010B\n+#define\tOID_GEN_VENDOR_ID\t\t0x0001010C\n+#define\tOID_GEN_VENDOR_DESCRIPTION\t0x0001010D\n+#define\tOID_GEN_CURRENT_PACKET_FILTER\t0x0001010E\n+#define\tOID_GEN_CURRENT_LOOKAHEAD\t0x0001010F\n+#define\tOID_GEN_DRIVER_VERSION\t\t0x00010110\n+#define\tOID_GEN_MAXIMUM_TOTAL_SIZE\t0x00010111\n+#define\tOID_GEN_PROTOCOL_OPTIONS\t0x00010112\n+#define\tOID_GEN_MAC_OPTIONS\t\t0x00010113\n+#define\tOID_GEN_MEDIA_CONNECT_STATUS\t0x00010114\n+#define\tOID_GEN_MAXIMUM_SEND_PACKETS\t0x00010115\n+#define\tOID_GEN_VENDOR_DRIVER_VERSION\t0x00010116\n+#define\tOID_GEN_SUPPORTED_GUIDS\t\t0x00010117\n+#define\tOID_GEN_NETWORK_LAYER_ADDRESSES\t0x00010118\n+#define\tOID_GEN_TRANSPORT_HEADER_OFFSET\t0x00010119\n+#define\tOID_GEN_RECEIVE_SCALE_CAPABILITIES\t0x00010203\n+#define\tOID_GEN_RECEIVE_SCALE_PARAMETERS\t0x00010204\n+#define\tOID_GEN_MACHINE_NAME\t\t0x0001021A\n+#define\tOID_GEN_RNDIS_CONFIG_PARAMETER\t0x0001021B\n+#define\tOID_GEN_VLAN_ID\t\t\t0x0001021C\n+\n+#define\tOID_802_3_PERMANENT_ADDRESS\t0x01010101\n+#define\tOID_802_3_CURRENT_ADDRESS\t0x01010102\n+#define\tOID_802_3_MULTICAST_LIST\t0x01010103\n+#define\tOID_802_3_MAXIMUM_LIST_SIZE\t0x01010104\n+#define\tOID_802_3_MAC_OPTIONS\t\t0x01010105\n+#define\tOID_802_3_RCV_ERROR_ALIGNMENT\t0x01020101\n+#define\tOID_802_3_XMIT_ONE_COLLISION\t0x01020102\n+#define\tOID_802_3_XMIT_MORE_COLLISIONS\t0x01020103\n+#define\tOID_802_3_XMIT_DEFERRED\t\t0x01020201\n+#define\tOID_802_3_XMIT_MAX_COLLISIONS\t0x01020202\n+#define\tOID_802_3_RCV_OVERRUN\t\t0x01020203\n+#define\tOID_802_3_XMIT_UNDERRUN\t\t0x01020204\n+#define\tOID_802_3_XMIT_HEARTBEAT_FAILURE\t0x01020205\n+#define\tOID_802_3_XMIT_TIMES_CRS_LOST\t0x01020206\n+#define\tOID_802_3_XMIT_LATE_COLLISIONS\t0x01020207\n+\n+#define\tOID_TCP_OFFLOAD_PARAMETERS\t0xFC01020C\n+#define\tOID_TCP_OFFLOAD_HARDWARE_CAPABILITIES\t0xFC01020D\n+\n+#define\tRNDIS_MEDIUM_802_3\t\t0x00000000\n+\n+/* Device flags */\n+#define\tRNDIS_DF_CONNECTIONLESS\t\t0x00000001\n+#define\tRNDIS_DF_CONNECTION_ORIENTED\t0x00000002\n+\n+/*\n+ * Common RNDIS message header.\n+ */\n+struct rndis_msghdr {\n+\tuint32_t type;\n+\tuint32_t len;\n+};\n+\n+/*\n+ * RNDIS data message\n+ */\n+#define\tRNDIS_PACKET_MSG\t\t0x00000001\n+\n+struct rndis_packet_msg {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t dataoffset;\n+\tuint32_t datalen;\n+\tuint32_t oobdataoffset;\n+\tuint32_t oobdatalen;\n+\tuint32_t oobdataelements;\n+\tuint32_t pktinfooffset;\n+\tuint32_t pktinfolen;\n+\tuint32_t vchandle;\n+\tuint32_t reserved;\n+};\n+\n+/*\n+ * Minimum value for dataoffset, oobdataoffset, and\n+ * pktinfooffset.\n+ */\n+#define\tRNDIS_PACKET_MSG_OFFSET_MIN\t\t\\\n+\t(sizeof(struct rndis_packet_msg) -\t\\\n+\t offsetof(struct rndis_packet_msg, dataoffset))\n+\n+/* Offset from the beginning of rndis_packet_msg. */\n+#define\tRNDIS_PACKET_MSG_OFFSET_ABS(ofs)\t\\\n+\t((ofs) + offsetof(struct rndis_packet_msg, dataoffset))\n+\n+#define\tRNDIS_PACKET_MSG_OFFSET_ALIGN\t\t4\n+#define\tRNDIS_PACKET_MSG_OFFSET_ALIGNMASK\t\\\n+\t(RNDIS_PACKET_MSG_OFFSET_ALIGN - 1)\n+\n+/* Per-packet-info for RNDIS data message */\n+struct rndis_pktinfo {\n+\tuint32_t size;\n+\tuint32_t type;\t\t/* NDIS_PKTINFO_TYPE_ */\n+\tuint32_t offset;\n+\tuint8_t data[];\n+};\n+\n+#define\tRNDIS_PKTINFO_OFFSET\t\t\\\n+\toffsetof(struct rndis_pktinfo, data[0])\n+#define\tRNDIS_PKTINFO_SIZE_ALIGN\t4\n+#define\tRNDIS_PKTINFO_SIZE_ALIGNMASK\t(RNDIS_PKTINFO_SIZE_ALIGN - 1)\n+\n+#define\tNDIS_PKTINFO_TYPE_CSUM\t\t0\n+#define\tNDIS_PKTINFO_TYPE_IPSEC\t\t1\n+#define\tNDIS_PKTINFO_TYPE_LSO\t\t2\n+#define\tNDIS_PKTINFO_TYPE_CLASSIFY\t3\n+/* reserved 4 */\n+#define\tNDIS_PKTINFO_TYPE_SGLIST\t5\n+#define\tNDIS_PKTINFO_TYPE_VLAN\t\t6\n+#define\tNDIS_PKTINFO_TYPE_ORIG\t\t7\n+#define\tNDIS_PKTINFO_TYPE_PKT_CANCELID\t8\n+#define\tNDIS_PKTINFO_TYPE_ORIG_NBLIST\t9\n+#define\tNDIS_PKTINFO_TYPE_CACHE_NBLIST\t10\n+#define\tNDIS_PKTINFO_TYPE_PKT_PAD\t11\n+\n+/* RNDIS extension */\n+\n+/* Per-packet hash info */\n+#define NDIS_HASH_INFO_SIZE\t\tsizeof(uint32_t)\n+#define NDIS_PKTINFO_TYPE_HASHINF\tNDIS_PKTINFO_TYPE_ORIG_NBLIST\n+/* NDIS_HASH_ */\n+\n+/* Per-packet hash value */\n+#define NDIS_HASH_VALUE_SIZE\t\tsizeof(uint32_t)\n+#define NDIS_PKTINFO_TYPE_HASHVAL\tNDIS_PKTINFO_TYPE_PKT_CANCELID\n+\n+/* Per-packet-info size */\n+#define RNDIS_PKTINFO_SIZE(dlen)\toffsetof(struct rndis_pktinfo, data[dlen])\n+\n+/*\n+ * RNDIS control messages\n+ */\n+\n+/*\n+ * Common header for RNDIS completion messages.\n+ *\n+ * NOTE: It does not apply to RNDIS_RESET_CMPLT.\n+ */\n+struct rndis_comp_hdr {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t rid;\n+\tuint32_t status;\n+};\n+\n+/* Initialize the device. */\n+#define\tRNDIS_INITIALIZE_MSG\t0x00000002\n+#define\tRNDIS_INITIALIZE_CMPLT\t0x80000002\n+\n+struct rndis_init_req {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t rid;\n+\tuint32_t ver_major;\n+\tuint32_t ver_minor;\n+\tuint32_t max_xfersz;\n+};\n+\n+struct rndis_init_comp {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t rid;\n+\tuint32_t status;\n+\tuint32_t ver_major;\n+\tuint32_t ver_minor;\n+\tuint32_t devflags;\n+\tuint32_t medium;\n+\tuint32_t pktmaxcnt;\n+\tuint32_t pktmaxsz;\n+\tuint32_t align;\n+\tuint32_t aflistoffset;\n+\tuint32_t aflistsz;\n+};\n+\n+#define\tRNDIS_INIT_COMP_SIZE_MIN\t\\\n+\toffsetof(struct rndis_init_comp, aflistsz)\n+\n+/* Halt the device.  No response sent. */\n+#define\tRNDIS_HALT_MSG\t\t0x00000003\n+\n+struct rndis_halt_req {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t rid;\n+};\n+\n+/* Send a query object. */\n+#define\tRNDIS_QUERY_MSG\t\t0x00000004\n+#define\tRNDIS_QUERY_CMPLT\t0x80000004\n+\n+struct rndis_query_req {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t rid;\n+\tuint32_t oid;\n+\tuint32_t infobuflen;\n+\tuint32_t infobufoffset;\n+\tuint32_t devicevchdl;\n+};\n+\n+#define\tRNDIS_QUERY_REQ_INFOBUFOFFSET\t\t\\\n+\t(sizeof(struct rndis_query_req) -\t\\\n+\t offsetof(struct rndis_query_req, rid))\n+\n+struct rndis_query_comp {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t rid;\n+\tuint32_t status;\n+\tuint32_t infobuflen;\n+\tuint32_t infobufoffset;\n+};\n+\n+/* infobuf offset from the beginning of rndis_query_comp. */\n+#define\tRNDIS_QUERY_COMP_INFOBUFOFFSET_ABS(ofs)\t\\\n+\t((ofs) + offsetof(struct rndis_query_comp, rid))\n+\n+/* Send a set object request. */\n+#define\tRNDIS_SET_MSG\t\t0x00000005\n+#define\tRNDIS_SET_CMPLT\t\t0x80000005\n+\n+struct rndis_set_req {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t rid;\n+\tuint32_t oid;\n+\tuint32_t infobuflen;\n+\tuint32_t infobufoffset;\n+\tuint32_t devicevchdl;\n+};\n+\n+#define\tRNDIS_SET_REQ_INFOBUFOFFSET\t\t\\\n+\t(sizeof(struct rndis_set_req) -\t\t\\\n+\t offsetof(struct rndis_set_req, rid))\n+\n+struct rndis_set_comp {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t rid;\n+\tuint32_t status;\n+};\n+\n+/*\n+ * Parameter used by OID_GEN_RNDIS_CONFIG_PARAMETER.\n+ */\n+#define\tRNDIS_SET_PARAM_NUMERIC\t0x00000000\n+#define\tRNDIS_SET_PARAM_STRING\t0x00000002\n+\n+struct rndis_set_parameter {\n+\tuint32_t nameoffset;\n+\tuint32_t namelen;\n+\tuint32_t type;\n+\tuint32_t valueoffset;\n+\tuint32_t valuelen;\n+};\n+\n+/* Perform a soft reset on the device. */\n+#define\tRNDIS_RESET_MSG\t\t0x00000006\n+#define\tRNDIS_RESET_CMPLT\t\t0x80000006\n+\n+struct rndis_reset_req {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t rid;\n+};\n+\n+struct rndis_reset_comp {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t status;\n+\tuint32_t adrreset;\n+};\n+\n+/* 802.3 link-state or undefined message error.  Sent by device. */\n+#define\tRNDIS_INDICATE_STATUS_MSG\t0x00000007\n+\n+struct rndis_status_msg {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t status;\n+\tuint32_t stbuflen;\n+\tuint32_t stbufoffset;\n+\t/* rndis_diag_info */\n+};\n+\n+/* stbuf offset from the beginning of rndis_status_msg. */\n+#define\tRNDIS_STBUFOFFSET_ABS(ofs)\t\\\n+\t((ofs) + offsetof(struct rndis_status_msg, status))\n+\n+/*\n+ * Immediately after rndis_status_msg.stbufoffset, if a control\n+ * message is malformatted, or a packet message contains inappropriate\n+ * content.\n+ */\n+struct rndis_diag_info {\n+\tuint32_t diagstatus;\n+\tuint32_t erroffset;\n+};\n+\n+/* Keepalive message.  May be sent by device. */\n+#define\tRNDIS_KEEPALIVE_MSG\t0x00000008\n+#define\tRNDIS_KEEPALIVE_CMPLT\t0x80000008\n+\n+struct rndis_keepalive_req {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t rid;\n+};\n+\n+struct rndis_keepalive_comp {\n+\tuint32_t type;\n+\tuint32_t len;\n+\tuint32_t rid;\n+\tuint32_t status;\n+};\n+\n+/* Packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */\n+#define\tNDIS_PACKET_TYPE_NONE\t\t\t0x00000000\n+#define\tNDIS_PACKET_TYPE_DIRECTED\t\t0x00000001\n+#define\tNDIS_PACKET_TYPE_MULTICAST\t\t0x00000002\n+#define\tNDIS_PACKET_TYPE_ALL_MULTICAST\t\t0x00000004\n+#define\tNDIS_PACKET_TYPE_BROADCAST\t\t0x00000008\n+#define\tNDIS_PACKET_TYPE_SOURCE_ROUTING\t\t0x00000010\n+#define\tNDIS_PACKET_TYPE_PROMISCUOUS\t\t0x00000020\n+#define\tNDIS_PACKET_TYPE_SMT\t\t\t0x00000040\n+#define\tNDIS_PACKET_TYPE_ALL_LOCAL\t\t0x00000080\n+#define\tNDIS_PACKET_TYPE_GROUP\t\t\t0x00001000\n+#define\tNDIS_PACKET_TYPE_ALL_FUNCTIONAL\t\t0x00002000\n+#define\tNDIS_PACKET_TYPE_FUNCTIONAL\t\t0x00004000\n+#define\tNDIS_PACKET_TYPE_MAC_FRAME\t\t0x00008000\n+\n+#endif\t/* !_NET_RNDIS_H_ */\ndiff --git a/drivers/net/netvsc/rte_pmd_netvsc_version.map b/drivers/net/netvsc/rte_pmd_netvsc_version.map\nnew file mode 100644\nindex 000000000000..d534019a6b53\n--- /dev/null\n+++ b/drivers/net/netvsc/rte_pmd_netvsc_version.map\n@@ -0,0 +1,5 @@\n+/* SPDX-License-Identifier: BSD-3-Clause */\n+\n+DPDK_18.08 {\n+\tlocal: *;\n+};\ndiff --git a/mk/rte.app.mk b/mk/rte.app.mk\nindex 6519a9c0e1b1..6f12575eb28d 100644\n--- a/mk/rte.app.mk\n+++ b/mk/rte.app.mk\n@@ -176,6 +176,7 @@ endif # $(CONFIG_RTE_EAL_VFIO)\n endif # $(CONFIG_RTE_LIBRTE_VHOST)\n _LDLIBS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD)    += -lrte_pmd_vmxnet3_uio\n _LDLIBS-$(CONFIG_RTE_LIBRTE_VMBUS)\t    += -lrte_bus_vmbus\n+_LDLIBS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD)\t    += -lrte_pmd_netvsc\n \n ifeq ($(CONFIG_RTE_LIBRTE_BBDEV),y)\n _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_BBDEV_NULL)     += -lrte_pmd_bbdev_null\n",
    "prefixes": [
        "v12",
        "3/4"
    ]
}