get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 99818,
    "url": "https://patches.dpdk.org/api/patches/99818/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20210927134231.11177-2-srikanth.k@oneconvergence.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20210927134231.11177-2-srikanth.k@oneconvergence.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210927134231.11177-2-srikanth.k@oneconvergence.com",
    "date": "2021-09-27T13:42:21",
    "name": "[01/11] bus/vmbus: stub for FreeBSD support",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "61e0c7c6beee97e095e899d8803e49e09b1b916f",
    "submitter": {
        "id": 2368,
        "url": "https://patches.dpdk.org/api/people/2368/?format=api",
        "name": "Srikanth Kaka",
        "email": "srikanth.k@oneconvergence.com"
    },
    "delegate": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20210927134231.11177-2-srikanth.k@oneconvergence.com/mbox/",
    "series": [
        {
            "id": 19194,
            "url": "https://patches.dpdk.org/api/series/19194/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=19194",
            "date": "2021-09-27T13:42:20",
            "name": "add FreeBSD support to VMBUS & NetVSC PMDs",
            "version": 1,
            "mbox": "https://patches.dpdk.org/series/19194/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/99818/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/99818/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 5F00FA0C46;\n\tMon, 27 Sep 2021 17:00:34 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 840D841185;\n\tMon, 27 Sep 2021 16:58:31 +0200 (CEST)",
            "from mail-pj1-f44.google.com (mail-pj1-f44.google.com\n [209.85.216.44]) by mails.dpdk.org (Postfix) with ESMTP id 712DC40E3C\n for <dev@dpdk.org>; Mon, 27 Sep 2021 15:43:02 +0200 (CEST)",
            "by mail-pj1-f44.google.com with SMTP id\n lb1-20020a17090b4a4100b001993f863df2so13732714pjb.5\n for <dev@dpdk.org>; Mon, 27 Sep 2021 06:43:02 -0700 (PDT)",
            "from srikanth-ThinkPad-T450.domain.name ([223.178.22.200])\n by smtp.gmail.com with ESMTPSA id b3sm16960665pfo.23.2021.09.27.06.42.59\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Mon, 27 Sep 2021 06:43:01 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=oneconvergence.com; s=google;\n h=from:to:cc:subject:date:message-id:in-reply-to:references\n :mime-version:content-transfer-encoding;\n bh=yz6aDe4LWap9zJh7cnQk/JAzxo2TaQL4wy5utc+mxFE=;\n b=KbyrxbU/7GxGWU6TYLeeLFpLTPXOF2woy3RrLdwYg64lehHS/rTtv70QK9jaYdV+ys\n NHLDa8GP9aurgfnmjd3tk3lpVGFMZkdLh2HF2mstmtNVnAQH+rgCxbds6G5q1Yg0p9pC\n Oq2SiEm6lfpJjylK0He8h+nU9Ds1arjGj7vp0=",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20210112;\n h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n :references:mime-version:content-transfer-encoding;\n bh=yz6aDe4LWap9zJh7cnQk/JAzxo2TaQL4wy5utc+mxFE=;\n b=pYg51TBH7m2JvAn159XidoN/tY8TFGoxskPw2qrwjhWxd1m4spx8kIT6xmrPau08WU\n g3KpUs0hNs7mPIb8NlRhPWD7pmXDxnpwrQ4YXzrDcHHn1yF+DTRPNkNOxvUV+l9IMQs1\n bzwwBHBDMBF89Buqnvrjhkxo8/MuWib6a7LAkSZFldBznp3k1WQPXzSdpFxbS6WNjDfY\n qtYvuznL9/VD3QsThI5PIe30Yj/r4Sund+yZ7FBuPKj32kpN+RL/wyJFPV6V3BKWmIfm\n E1VWz/5KKSUdWUaPf3EB7NrkYzy+AYh4Ap4QRgAy0sdIdOBHkt3uOL0Tvap0BwmiA27/\n sbsQ==",
        "X-Gm-Message-State": "AOAM5330VkGNMRSFLJ2GL5pgSc/9TXb3e34yAFT4hCtN3f3/8GTWi3Et\n HEuZ4W60ZoNkdL2Ep6FX7b2m/g==",
        "X-Google-Smtp-Source": "\n ABdhPJzPCJo1TUsBeSxP3AYy/2bpuXThqzucs6OyGRimqdb1IhBixYBwFNZZ1FDS/E07vPIqFCy4eg==",
        "X-Received": "by 2002:a17:90b:3b4c:: with SMTP id\n ot12mr20033623pjb.67.1632750181468;\n Mon, 27 Sep 2021 06:43:01 -0700 (PDT)",
        "From": "Srikanth Kaka <srikanth.k@oneconvergence.com>",
        "To": "Stephen Hemminger <sthemmin@microsoft.com>, Long Li <longli@microsoft.com>",
        "Cc": "dev@dpdk.org, Vag Singh <vag.singh@oneconvergence.com>,\n Anand Thulasiram <avelu@juniper.net>,\n Srikanth Kaka <srikanth.k@oneconvergence.com>",
        "Date": "Mon, 27 Sep 2021 19:12:21 +0530",
        "Message-Id": "<20210927134231.11177-2-srikanth.k@oneconvergence.com>",
        "X-Mailer": "git-send-email 2.30.2",
        "In-Reply-To": "<20210927134231.11177-1-srikanth.k@oneconvergence.com>",
        "References": "<20210927134231.11177-1-srikanth.k@oneconvergence.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-Mailman-Approved-At": "Mon, 27 Sep 2021 16:58:07 +0200",
        "Subject": "[dpdk-dev] [PATCH 01/11] bus/vmbus: stub for FreeBSD support",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "These files are a copy of their Linux equivalents.\nThey will be ported to FreeBSD.\n\nSigned-off-by: Srikanth Kaka <srikanth.k@oneconvergence.com>\nSigned-off-by: Vag Singh <vag.singh@oneconvergence.com>\nSigned-off-by: Anand Thulasiram <avelu@juniper.net>\n---\n drivers/bus/vmbus/freebsd/vmbus_bus.c | 376 +++++++++++++++++++++\n drivers/bus/vmbus/freebsd/vmbus_uio.c | 453 ++++++++++++++++++++++++++\n 2 files changed, 829 insertions(+)\n create mode 100644 drivers/bus/vmbus/freebsd/vmbus_bus.c\n create mode 100644 drivers/bus/vmbus/freebsd/vmbus_uio.c",
    "diff": "diff --git a/drivers/bus/vmbus/freebsd/vmbus_bus.c b/drivers/bus/vmbus/freebsd/vmbus_bus.c\nnew file mode 100644\nindex 0000000000..3c924eee14\n--- /dev/null\n+++ b/drivers/bus/vmbus/freebsd/vmbus_bus.c\n@@ -0,0 +1,376 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2018, Microsoft Corporation.\n+ * All Rights Reserved.\n+ */\n+\n+#include <string.h>\n+#include <unistd.h>\n+#include <dirent.h>\n+#include <fcntl.h>\n+#include <sys/mman.h>\n+#include <sys/stat.h>\n+\n+#include <rte_eal.h>\n+#include <rte_uuid.h>\n+#include <rte_tailq.h>\n+#include <rte_log.h>\n+#include <rte_devargs.h>\n+#include <rte_memory.h>\n+#include <rte_malloc.h>\n+#include <rte_bus_vmbus.h>\n+\n+#include \"eal_filesystem.h\"\n+#include \"private.h\"\n+\n+/** Pathname of VMBUS devices directory. */\n+#define SYSFS_VMBUS_DEVICES \"/sys/bus/vmbus/devices\"\n+\n+/*\n+ * GUID associated with network devices\n+ * {f8615163-df3e-46c5-913f-f2d2f965ed0e}\n+ */\n+static const rte_uuid_t vmbus_nic_uuid = {\n+\t0xf8, 0x61, 0x51, 0x63,\n+\t0xdf, 0x3e,\n+\t0x46, 0xc5,\n+\t0x91, 0x3f,\n+\t0xf2, 0xd2, 0xf9, 0x65, 0xed, 0xe\n+};\n+\n+extern struct rte_vmbus_bus rte_vmbus_bus;\n+\n+/* Read sysfs file to get UUID */\n+static int\n+parse_sysfs_uuid(const char *filename, rte_uuid_t uu)\n+{\n+\tchar buf[BUFSIZ];\n+\tchar *cp, *in = buf;\n+\tFILE *f;\n+\n+\tf = fopen(filename, \"r\");\n+\tif (f == NULL) {\n+\t\tVMBUS_LOG(ERR, \"cannot open sysfs value %s: %s\",\n+\t\t\t  filename, strerror(errno));\n+\t\treturn -1;\n+\t}\n+\n+\tif (fgets(buf, sizeof(buf), f) == NULL) {\n+\t\tVMBUS_LOG(ERR, \"cannot read sysfs value %s\",\n+\t\t\t\tfilename);\n+\t\tfclose(f);\n+\t\treturn -1;\n+\t}\n+\tfclose(f);\n+\n+\tcp = strchr(buf, '\\n');\n+\tif (cp)\n+\t\t*cp = '\\0';\n+\n+\t/* strip { } notation */\n+\tif (buf[0] == '{') {\n+\t\tin = buf + 1;\n+\t\tcp = strchr(in, '}');\n+\t\tif (cp)\n+\t\t\t*cp = '\\0';\n+\t}\n+\n+\tif (rte_uuid_parse(in, uu) < 0) {\n+\t\tVMBUS_LOG(ERR, \"%s %s not a valid UUID\",\n+\t\t\tfilename, buf);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+get_sysfs_string(const char *filename, char *buf, size_t buflen)\n+{\n+\tchar *cp;\n+\tFILE *f;\n+\n+\tf = fopen(filename, \"r\");\n+\tif (f == NULL) {\n+\t\tVMBUS_LOG(ERR, \"cannot open sysfs value %s:%s\",\n+\t\t\t  filename, strerror(errno));\n+\t\treturn -1;\n+\t}\n+\n+\tif (fgets(buf, buflen, f) == NULL) {\n+\t\tVMBUS_LOG(ERR, \"cannot read sysfs value %s\",\n+\t\t\t\tfilename);\n+\t\tfclose(f);\n+\t\treturn -1;\n+\t}\n+\tfclose(f);\n+\n+\t/* remove trailing newline */\n+\tcp = memchr(buf, '\\n', buflen);\n+\tif (cp)\n+\t\t*cp = '\\0';\n+\n+\treturn 0;\n+}\n+\n+static int\n+vmbus_get_uio_dev(const struct rte_vmbus_device *dev,\n+\t\t  char *dstbuf, size_t buflen)\n+{\n+\tchar dirname[PATH_MAX];\n+\tunsigned int uio_num;\n+\tstruct dirent *e;\n+\tDIR *dir;\n+\n+\t/* Assume recent kernel where uio is in uio/uioX */\n+\tsnprintf(dirname, sizeof(dirname),\n+\t\t SYSFS_VMBUS_DEVICES \"/%s/uio\", dev->device.name);\n+\n+\tdir = opendir(dirname);\n+\tif (dir == NULL)\n+\t\treturn -1; /* Not a UIO device */\n+\n+\t/* take the first file starting with \"uio\" */\n+\twhile ((e = readdir(dir)) != NULL) {\n+\t\tconst int prefix_len = 3;\n+\t\tchar *endptr;\n+\n+\t\tif (strncmp(e->d_name, \"uio\", prefix_len) != 0)\n+\t\t\tcontinue;\n+\n+\t\t/* try uio%d */\n+\t\terrno = 0;\n+\t\tuio_num = strtoull(e->d_name + prefix_len, &endptr, 10);\n+\t\tif (errno == 0 && endptr != (e->d_name + prefix_len)) {\n+\t\t\tsnprintf(dstbuf, buflen, \"%s/uio%u\", dirname, uio_num);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tclosedir(dir);\n+\n+\tif (e == NULL)\n+\t\treturn -1;\n+\n+\treturn uio_num;\n+}\n+\n+/* Check map names with kernel names */\n+static const char *map_names[VMBUS_MAX_RESOURCE] = {\n+\t[HV_TXRX_RING_MAP] = \"txrx_rings\",\n+\t[HV_INT_PAGE_MAP]  = \"int_page\",\n+\t[HV_MON_PAGE_MAP]  = \"monitor_page\",\n+\t[HV_RECV_BUF_MAP]  = \"recv:\",\n+\t[HV_SEND_BUF_MAP]  = \"send:\",\n+};\n+\n+\n+/* map the resources of a vmbus device in virtual memory */\n+int\n+rte_vmbus_map_device(struct rte_vmbus_device *dev)\n+{\n+\tchar uioname[PATH_MAX], filename[PATH_MAX];\n+\tchar dirname[PATH_MAX], mapname[64];\n+\tint i;\n+\n+\tdev->uio_num = vmbus_get_uio_dev(dev, uioname, sizeof(uioname));\n+\tif (dev->uio_num < 0) {\n+\t\tVMBUS_LOG(DEBUG, \"Not managed by UIO driver, skipped\");\n+\t\treturn 1;\n+\t}\n+\n+\t/* Extract resource value */\n+\tfor (i = 0; i < VMBUS_MAX_RESOURCE; i++) {\n+\t\tstruct rte_mem_resource *res = &dev->resource[i];\n+\t\tunsigned long len, gpad = 0;\n+\t\tchar *cp;\n+\n+\t\tsnprintf(dirname, sizeof(dirname),\n+\t\t\t \"%s/maps/map%d\", uioname, i);\n+\n+\t\tsnprintf(filename, sizeof(filename),\n+\t\t\t \"%s/name\", dirname);\n+\n+\t\tif (get_sysfs_string(filename, mapname, sizeof(mapname)) < 0) {\n+\t\t\tVMBUS_LOG(ERR, \"could not read %s\", filename);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (strncmp(map_names[i], mapname, strlen(map_names[i])) != 0) {\n+\t\t\tVMBUS_LOG(ERR,\n+\t\t\t\t\"unexpected resource %s (expected %s)\",\n+\t\t\t\tmapname, map_names[i]);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tsnprintf(filename, sizeof(filename),\n+\t\t\t \"%s/size\", dirname);\n+\t\tif (eal_parse_sysfs_value(filename, &len) < 0) {\n+\t\t\tVMBUS_LOG(ERR,\n+\t\t\t\t\"could not read %s\", filename);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tres->len = len;\n+\n+\t\t/* both send and receive buffers have gpad in name */\n+\t\tcp = memchr(mapname, ':', sizeof(mapname));\n+\t\tif (cp)\n+\t\t\tgpad = strtoul(cp+1, NULL, 0);\n+\n+\t\t/* put the GPAD value in physical address */\n+\t\tres->phys_addr = gpad;\n+\t}\n+\n+\treturn vmbus_uio_map_resource(dev);\n+}\n+\n+void\n+rte_vmbus_unmap_device(struct rte_vmbus_device *dev)\n+{\n+\tvmbus_uio_unmap_resource(dev);\n+}\n+\n+/* Scan one vmbus sysfs entry, and fill the devices list from it. */\n+static int\n+vmbus_scan_one(const char *name)\n+{\n+\tstruct rte_vmbus_device *dev, *dev2;\n+\tchar filename[PATH_MAX];\n+\tchar dirname[PATH_MAX];\n+\tunsigned long tmp;\n+\n+\tdev = calloc(1, sizeof(*dev));\n+\tif (dev == NULL)\n+\t\treturn -1;\n+\n+\tdev->device.bus = &rte_vmbus_bus.bus;\n+\tdev->device.name = strdup(name);\n+\tif (!dev->device.name)\n+\t\tgoto error;\n+\n+\t/* sysfs base directory\n+\t *   /sys/bus/vmbus/devices/7a08391f-f5a0-4ac0-9802-d13fd964f8df\n+\t * or on older kernel\n+\t *   /sys/bus/vmbus/devices/vmbus_1\n+\t */\n+\tsnprintf(dirname, sizeof(dirname), \"%s/%s\",\n+\t\t SYSFS_VMBUS_DEVICES, name);\n+\n+\t/* get device class  */\n+\tsnprintf(filename, sizeof(filename), \"%s/class_id\", dirname);\n+\tif (parse_sysfs_uuid(filename, dev->class_id) < 0)\n+\t\tgoto error;\n+\n+\t/* skip non-network devices */\n+\tif (rte_uuid_compare(dev->class_id, vmbus_nic_uuid) != 0) {\n+\t\tfree(dev);\n+\t\treturn 0;\n+\t}\n+\n+\t/* get device id */\n+\tsnprintf(filename, sizeof(filename), \"%s/device_id\", dirname);\n+\tif (parse_sysfs_uuid(filename, dev->device_id) < 0)\n+\t\tgoto error;\n+\n+\t/* get relid */\n+\tsnprintf(filename, sizeof(filename), \"%s/id\", dirname);\n+\tif (eal_parse_sysfs_value(filename, &tmp) < 0)\n+\t\tgoto error;\n+\tdev->relid = tmp;\n+\n+\t/* get monitor id */\n+\tsnprintf(filename, sizeof(filename), \"%s/monitor_id\", dirname);\n+\tif (eal_parse_sysfs_value(filename, &tmp) < 0)\n+\t\tgoto error;\n+\tdev->monitor_id = tmp;\n+\n+\t/* get numa node (if present) */\n+\tsnprintf(filename, sizeof(filename), \"%s/numa_node\",\n+\t\t dirname);\n+\n+\tif (access(filename, R_OK) == 0) {\n+\t\tif (eal_parse_sysfs_value(filename, &tmp) < 0)\n+\t\t\tgoto error;\n+\t\tdev->device.numa_node = tmp;\n+\t} else {\n+\t\t/* if no NUMA support, set default to 0 */\n+\t\tdev->device.numa_node = SOCKET_ID_ANY;\n+\t}\n+\n+\tdev->device.devargs = vmbus_devargs_lookup(dev);\n+\n+\t/* device is valid, add in list (sorted) */\n+\tVMBUS_LOG(DEBUG, \"Adding vmbus device %s\", name);\n+\n+\tTAILQ_FOREACH(dev2, &rte_vmbus_bus.device_list, next) {\n+\t\tint ret;\n+\n+\t\tret = rte_uuid_compare(dev->device_id, dev2->device_id);\n+\t\tif (ret > 0)\n+\t\t\tcontinue;\n+\n+\t\tif (ret < 0) {\n+\t\t\tvmbus_insert_device(dev2, dev);\n+\t\t} else { /* already registered */\n+\t\t\tVMBUS_LOG(NOTICE,\n+\t\t\t\t\"%s already registered\", name);\n+\t\t\tfree(dev);\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\n+\tvmbus_add_device(dev);\n+\treturn 0;\n+error:\n+\tVMBUS_LOG(DEBUG, \"failed\");\n+\n+\tfree(dev);\n+\treturn -1;\n+}\n+\n+/*\n+ * Scan the content of the vmbus, and the devices in the devices list\n+ */\n+int\n+rte_vmbus_scan(void)\n+{\n+\tstruct dirent *e;\n+\tDIR *dir;\n+\n+\tdir = opendir(SYSFS_VMBUS_DEVICES);\n+\tif (dir == NULL) {\n+\t\tif (errno == ENOENT)\n+\t\t\treturn 0;\n+\n+\t\tVMBUS_LOG(ERR, \"opendir %s failed: %s\",\n+\t\t\t  SYSFS_VMBUS_DEVICES, strerror(errno));\n+\t\treturn -1;\n+\t}\n+\n+\twhile ((e = readdir(dir)) != NULL) {\n+\t\tif (e->d_name[0] == '.')\n+\t\t\tcontinue;\n+\n+\t\tif (vmbus_scan_one(e->d_name) < 0)\n+\t\t\tgoto error;\n+\t}\n+\tclosedir(dir);\n+\treturn 0;\n+\n+error:\n+\tclosedir(dir);\n+\treturn -1;\n+}\n+\n+void rte_vmbus_irq_mask(struct rte_vmbus_device *device)\n+{\n+\tvmbus_uio_irq_control(device, 1);\n+}\n+\n+void rte_vmbus_irq_unmask(struct rte_vmbus_device *device)\n+{\n+\tvmbus_uio_irq_control(device, 0);\n+}\n+\n+int rte_vmbus_irq_read(struct rte_vmbus_device *device)\n+{\n+\treturn vmbus_uio_irq_read(device);\n+}\ndiff --git a/drivers/bus/vmbus/freebsd/vmbus_uio.c b/drivers/bus/vmbus/freebsd/vmbus_uio.c\nnew file mode 100644\nindex 0000000000..b52ca5bf1d\n--- /dev/null\n+++ b/drivers/bus/vmbus/freebsd/vmbus_uio.c\n@@ -0,0 +1,453 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2018, Microsoft Corporation.\n+ * All Rights Reserved.\n+ */\n+\n+#include <string.h>\n+#include <unistd.h>\n+#include <fcntl.h>\n+#include <dirent.h>\n+#include <inttypes.h>\n+#include <sys/stat.h>\n+#include <sys/mman.h>\n+\n+#include <rte_log.h>\n+#include <rte_bus.h>\n+#include <rte_memory.h>\n+#include <rte_common.h>\n+#include <rte_malloc.h>\n+#include <rte_bus_vmbus.h>\n+#include <rte_string_fns.h>\n+\n+#include \"private.h\"\n+\n+/** Pathname of VMBUS devices directory. */\n+#define SYSFS_VMBUS_DEVICES \"/sys/bus/vmbus/devices\"\n+\n+static void *vmbus_map_addr;\n+\n+/* Control interrupts */\n+void vmbus_uio_irq_control(struct rte_vmbus_device *dev, int32_t onoff)\n+{\n+\tif (write(dev->intr_handle.fd, &onoff, sizeof(onoff)) < 0) {\n+\t\tVMBUS_LOG(ERR, \"cannot write to %d:%s\",\n+\t\t\tdev->intr_handle.fd, strerror(errno));\n+\t}\n+}\n+\n+int vmbus_uio_irq_read(struct rte_vmbus_device *dev)\n+{\n+\tint32_t count;\n+\tint cc;\n+\n+\tcc = read(dev->intr_handle.fd, &count, sizeof(count));\n+\tif (cc < (int)sizeof(count)) {\n+\t\tif (cc < 0) {\n+\t\t\tVMBUS_LOG(ERR, \"IRQ read failed %s\",\n+\t\t\t\t  strerror(errno));\n+\t\t\treturn -errno;\n+\t\t}\n+\t\tVMBUS_LOG(ERR, \"can't read IRQ count\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn count;\n+}\n+\n+void\n+vmbus_uio_free_resource(struct rte_vmbus_device *dev,\n+\t\tstruct mapped_vmbus_resource *uio_res)\n+{\n+\trte_free(uio_res);\n+\n+\tif (dev->intr_handle.uio_cfg_fd >= 0) {\n+\t\tclose(dev->intr_handle.uio_cfg_fd);\n+\t\tdev->intr_handle.uio_cfg_fd = -1;\n+\t}\n+\n+\tif (dev->intr_handle.fd >= 0) {\n+\t\tclose(dev->intr_handle.fd);\n+\t\tdev->intr_handle.fd = -1;\n+\t\tdev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;\n+\t}\n+}\n+\n+int\n+vmbus_uio_alloc_resource(struct rte_vmbus_device *dev,\n+\t\t\t struct mapped_vmbus_resource **uio_res)\n+{\n+\tchar devname[PATH_MAX]; /* contains the /dev/uioX */\n+\n+\t/* save fd if in primary process */\n+\tsnprintf(devname, sizeof(devname), \"/dev/uio%u\", dev->uio_num);\n+\tdev->intr_handle.fd = open(devname, O_RDWR);\n+\tif (dev->intr_handle.fd < 0) {\n+\t\tVMBUS_LOG(ERR, \"Cannot open %s: %s\",\n+\t\t\tdevname, strerror(errno));\n+\t\tgoto error;\n+\t}\n+\tdev->intr_handle.type = RTE_INTR_HANDLE_UIO_INTX;\n+\n+\t/* allocate the mapping details for secondary processes*/\n+\t*uio_res = rte_zmalloc(\"UIO_RES\", sizeof(**uio_res), 0);\n+\tif (*uio_res == NULL) {\n+\t\tVMBUS_LOG(ERR, \"cannot store uio mmap details\");\n+\t\tgoto error;\n+\t}\n+\n+\tstrlcpy((*uio_res)->path, devname, PATH_MAX);\n+\trte_uuid_copy((*uio_res)->id, dev->device_id);\n+\n+\treturn 0;\n+\n+error:\n+\tvmbus_uio_free_resource(dev, *uio_res);\n+\treturn -1;\n+}\n+\n+static int\n+find_max_end_va(const struct rte_memseg_list *msl, void *arg)\n+{\n+\tsize_t sz = msl->memseg_arr.len * msl->page_sz;\n+\tvoid *end_va = RTE_PTR_ADD(msl->base_va, sz);\n+\tvoid **max_va = arg;\n+\n+\tif (*max_va < end_va)\n+\t\t*max_va = end_va;\n+\treturn 0;\n+}\n+\n+/*\n+ * TODO: this should be part of memseg api.\n+ *       code is duplicated from PCI.\n+ */\n+static void *\n+vmbus_find_max_end_va(void)\n+{\n+\tvoid *va = NULL;\n+\n+\trte_memseg_list_walk(find_max_end_va, &va);\n+\treturn va;\n+}\n+\n+int\n+vmbus_uio_map_resource_by_index(struct rte_vmbus_device *dev, int idx,\n+\t\t\t\tstruct mapped_vmbus_resource *uio_res,\n+\t\t\t\tint flags)\n+{\n+\tsize_t size = dev->resource[idx].len;\n+\tstruct vmbus_map *maps = uio_res->maps;\n+\tvoid *mapaddr;\n+\toff_t offset;\n+\tint fd;\n+\n+\t/* devname for mmap  */\n+\tfd = open(uio_res->path, O_RDWR);\n+\tif (fd < 0) {\n+\t\tVMBUS_LOG(ERR, \"Cannot open %s: %s\",\n+\t\t\t  uio_res->path, strerror(errno));\n+\t\treturn -1;\n+\t}\n+\n+\t/* try mapping somewhere close to the end of hugepages */\n+\tif (vmbus_map_addr == NULL)\n+\t\tvmbus_map_addr = vmbus_find_max_end_va();\n+\n+\t/* offset is special in uio it indicates which resource */\n+\toffset = idx * rte_mem_page_size();\n+\n+\tmapaddr = vmbus_map_resource(vmbus_map_addr, fd, offset, size, flags);\n+\tclose(fd);\n+\n+\tif (mapaddr == MAP_FAILED)\n+\t\treturn -1;\n+\n+\tdev->resource[idx].addr = mapaddr;\n+\tvmbus_map_addr = RTE_PTR_ADD(mapaddr, size);\n+\n+\t/* Record result of successful mapping for use by secondary */\n+\tmaps[idx].addr = mapaddr;\n+\tmaps[idx].size = size;\n+\n+\treturn 0;\n+}\n+\n+static int vmbus_uio_map_primary(struct vmbus_channel *chan,\n+\t\t\t\t void **ring_buf, uint32_t *ring_size)\n+{\n+\tstruct mapped_vmbus_resource *uio_res;\n+\n+\tuio_res = vmbus_uio_find_resource(chan->device);\n+\tif (!uio_res) {\n+\t\tVMBUS_LOG(ERR, \"can not find resources!\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tif (uio_res->nb_maps < VMBUS_MAX_RESOURCE) {\n+\t\tVMBUS_LOG(ERR, \"VMBUS: only %u resources found!\",\n+\t\t\t  uio_res->nb_maps);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t*ring_size = uio_res->maps[HV_TXRX_RING_MAP].size / 2;\n+\t*ring_buf  = uio_res->maps[HV_TXRX_RING_MAP].addr;\n+\treturn 0;\n+}\n+\n+static int vmbus_uio_map_subchan(const struct rte_vmbus_device *dev,\n+\t\t\t\t const struct vmbus_channel *chan,\n+\t\t\t\t void **ring_buf, uint32_t *ring_size)\n+{\n+\tchar ring_path[PATH_MAX];\n+\tsize_t file_size;\n+\tstruct stat sb;\n+\tvoid *mapaddr;\n+\tint fd;\n+\n+\tsnprintf(ring_path, sizeof(ring_path),\n+\t\t \"%s/%s/channels/%u/ring\",\n+\t\t SYSFS_VMBUS_DEVICES, dev->device.name,\n+\t\t chan->relid);\n+\n+\tfd = open(ring_path, O_RDWR);\n+\tif (fd < 0) {\n+\t\tVMBUS_LOG(ERR, \"Cannot open %s: %s\",\n+\t\t\t  ring_path, strerror(errno));\n+\t\treturn -errno;\n+\t}\n+\n+\tif (fstat(fd, &sb) < 0) {\n+\t\tVMBUS_LOG(ERR, \"Cannot state %s: %s\",\n+\t\t\t  ring_path, strerror(errno));\n+\t\tclose(fd);\n+\t\treturn -errno;\n+\t}\n+\tfile_size = sb.st_size;\n+\n+\tif (file_size == 0 || (file_size & (rte_mem_page_size() - 1))) {\n+\t\tVMBUS_LOG(ERR, \"incorrect size %s: %zu\",\n+\t\t\t  ring_path, file_size);\n+\n+\t\tclose(fd);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmapaddr = vmbus_map_resource(vmbus_map_addr, fd,\n+\t\t\t\t     0, file_size, 0);\n+\tclose(fd);\n+\n+\tif (mapaddr == MAP_FAILED)\n+\t\treturn -EIO;\n+\n+\t*ring_size = file_size / 2;\n+\t*ring_buf = mapaddr;\n+\n+\tvmbus_map_addr = RTE_PTR_ADD(mapaddr, file_size);\n+\treturn 0;\n+}\n+\n+int\n+vmbus_uio_map_secondary_subchan(const struct rte_vmbus_device *dev,\n+\t\t\t\tconst struct vmbus_channel *chan)\n+{\n+\tconst struct vmbus_br *br = &chan->txbr;\n+\tchar ring_path[PATH_MAX];\n+\tvoid *mapaddr, *ring_buf;\n+\tuint32_t ring_size;\n+\tint fd;\n+\n+\tsnprintf(ring_path, sizeof(ring_path),\n+\t\t \"%s/%s/channels/%u/ring\",\n+\t\t SYSFS_VMBUS_DEVICES, dev->device.name,\n+\t\t chan->relid);\n+\n+\tring_buf = br->vbr;\n+\tring_size = br->dsize + sizeof(struct vmbus_bufring);\n+\tVMBUS_LOG(INFO, \"secondary ring_buf %p size %u\",\n+\t\t  ring_buf, ring_size);\n+\n+\tfd = open(ring_path, O_RDWR);\n+\tif (fd < 0) {\n+\t\tVMBUS_LOG(ERR, \"Cannot open %s: %s\",\n+\t\t\t  ring_path, strerror(errno));\n+\t\treturn -errno;\n+\t}\n+\n+\tmapaddr = vmbus_map_resource(ring_buf, fd, 0, 2 * ring_size, 0);\n+\tclose(fd);\n+\n+\tif (mapaddr == ring_buf)\n+\t\treturn 0;\n+\n+\tif (mapaddr == MAP_FAILED)\n+\t\tVMBUS_LOG(ERR,\n+\t\t\t  \"mmap subchan %u in secondary failed\", chan->relid);\n+\telse {\n+\t\tVMBUS_LOG(ERR,\n+\t\t\t  \"mmap subchan %u in secondary address mismatch\",\n+\t\t\t  chan->relid);\n+\t\tvmbus_unmap_resource(mapaddr, 2 * ring_size);\n+\t}\n+\treturn -1;\n+}\n+\n+int vmbus_uio_map_rings(struct vmbus_channel *chan)\n+{\n+\tconst struct rte_vmbus_device *dev = chan->device;\n+\tuint32_t ring_size;\n+\tvoid *ring_buf;\n+\tint ret;\n+\n+\t/* Primary channel */\n+\tif (chan->subchannel_id == 0)\n+\t\tret = vmbus_uio_map_primary(chan, &ring_buf, &ring_size);\n+\telse\n+\t\tret = vmbus_uio_map_subchan(dev, chan, &ring_buf, &ring_size);\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tvmbus_br_setup(&chan->txbr, ring_buf, ring_size);\n+\tvmbus_br_setup(&chan->rxbr, (char *)ring_buf + ring_size, ring_size);\n+\treturn 0;\n+}\n+\n+static int vmbus_uio_sysfs_read(const char *dir, const char *name,\n+\t\t\t\tunsigned long *val, unsigned long max_range)\n+{\n+\tchar path[PATH_MAX];\n+\tFILE *f;\n+\tint ret;\n+\n+\tsnprintf(path, sizeof(path), \"%s/%s\", dir, name);\n+\tf = fopen(path, \"r\");\n+\tif (!f) {\n+\t\tVMBUS_LOG(ERR, \"can't open %s:%s\",\n+\t\t\t  path, strerror(errno));\n+\t\treturn -errno;\n+\t}\n+\n+\tif (fscanf(f, \"%lu\", val) != 1)\n+\t\tret = -EIO;\n+\telse if (*val > max_range)\n+\t\tret = -ERANGE;\n+\telse\n+\t\tret = 0;\n+\tfclose(f);\n+\n+\treturn ret;\n+}\n+\n+static bool vmbus_uio_ring_present(const struct rte_vmbus_device *dev,\n+\t\t\t\t   uint32_t relid)\n+{\n+\tchar ring_path[PATH_MAX];\n+\n+\t/* Check if kernel has subchannel sysfs files */\n+\tsnprintf(ring_path, sizeof(ring_path),\n+\t\t \"%s/%s/channels/%u/ring\",\n+\t\t SYSFS_VMBUS_DEVICES, dev->device.name, relid);\n+\n+\treturn access(ring_path, R_OK|W_OK) == 0;\n+}\n+\n+bool vmbus_uio_subchannels_supported(const struct rte_vmbus_device *dev,\n+\t\t\t\t     const struct vmbus_channel *chan)\n+{\n+\treturn vmbus_uio_ring_present(dev, chan->relid);\n+}\n+\n+static bool vmbus_isnew_subchannel(struct vmbus_channel *primary,\n+\t\t\t\t   unsigned long id)\n+{\n+\tconst struct vmbus_channel *c;\n+\n+\tSTAILQ_FOREACH(c, &primary->subchannel_list, next) {\n+\t\tif (c->relid == id)\n+\t\t\treturn false;\n+\t}\n+\treturn true;\n+}\n+\n+int vmbus_uio_get_subchan(struct vmbus_channel *primary,\n+\t\t\t  struct vmbus_channel **subchan)\n+{\n+\tconst struct rte_vmbus_device *dev = primary->device;\n+\tchar chan_path[PATH_MAX], subchan_path[PATH_MAX];\n+\tstruct dirent *ent;\n+\tDIR *chan_dir;\n+\tint err;\n+\n+\tsnprintf(chan_path, sizeof(chan_path),\n+\t\t \"%s/%s/channels\",\n+\t\t SYSFS_VMBUS_DEVICES, dev->device.name);\n+\n+\tchan_dir = opendir(chan_path);\n+\tif (!chan_dir) {\n+\t\tVMBUS_LOG(ERR, \"cannot open %s: %s\",\n+\t\t\t  chan_path, strerror(errno));\n+\t\treturn -errno;\n+\t}\n+\n+\twhile ((ent = readdir(chan_dir))) {\n+\t\tunsigned long relid, subid, monid;\n+\t\tchar *endp;\n+\n+\t\tif (ent->d_name[0] == '.')\n+\t\t\tcontinue;\n+\n+\t\terrno = 0;\n+\t\trelid = strtoul(ent->d_name, &endp, 0);\n+\t\tif (*endp || errno != 0 || relid > UINT16_MAX) {\n+\t\t\tVMBUS_LOG(NOTICE, \"not a valid channel relid: %s\",\n+\t\t\t\t  ent->d_name);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (!vmbus_isnew_subchannel(primary, relid)) {\n+\t\t\tVMBUS_LOG(DEBUG, \"skip already found channel: %lu\",\n+\t\t\t\t  relid);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (!vmbus_uio_ring_present(dev, relid)) {\n+\t\t\tVMBUS_LOG(DEBUG, \"ring mmap not found (yet) for: %lu\",\n+\t\t\t\t  relid);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tsnprintf(subchan_path, sizeof(subchan_path), \"%s/%lu\",\n+\t\t\t chan_path, relid);\n+\t\terr = vmbus_uio_sysfs_read(subchan_path, \"subchannel_id\",\n+\t\t\t\t\t   &subid, UINT16_MAX);\n+\t\tif (err) {\n+\t\t\tVMBUS_LOG(NOTICE, \"no subchannel_id in %s:%s\",\n+\t\t\t\t  subchan_path, strerror(-err));\n+\t\t\tgoto fail;\n+\t\t}\n+\n+\t\tif (subid == 0)\n+\t\t\tcontinue;\t/* skip primary channel */\n+\n+\t\terr = vmbus_uio_sysfs_read(subchan_path, \"monitor_id\",\n+\t\t\t\t\t   &monid, UINT8_MAX);\n+\t\tif (err) {\n+\t\t\tVMBUS_LOG(NOTICE, \"no monitor_id in %s:%s\",\n+\t\t\t\t  subchan_path, strerror(-err));\n+\t\t\tgoto fail;\n+\t\t}\n+\n+\t\terr = vmbus_chan_create(dev, relid, subid, monid, subchan);\n+\t\tif (err) {\n+\t\t\tVMBUS_LOG(ERR, \"subchannel setup failed\");\n+\t\t\tgoto fail;\n+\t\t}\n+\t\tbreak;\n+\t}\n+\tclosedir(chan_dir);\n+\n+\treturn (ent == NULL) ? -ENOENT : 0;\n+fail:\n+\tclosedir(chan_dir);\n+\treturn err;\n+}\n",
    "prefixes": [
        "01/11"
    ]
}