get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 85966,
    "url": "http://patches.dpdk.org/api/patches/85966/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1609812336-29506-4-git-send-email-wei.huang@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1609812336-29506-4-git-send-email-wei.huang@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1609812336-29506-4-git-send-email-wei.huang@intel.com",
    "date": "2021-01-05T02:05:35",
    "name": "[v6,3/4] raw/ifpga: add opae API for Cyborg",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "28488fdf4d17d651185102fab3eb4e5cf327c04e",
    "submitter": {
        "id": 2033,
        "url": "http://patches.dpdk.org/api/people/2033/?format=api",
        "name": "Wei Huang",
        "email": "wei.huang@intel.com"
    },
    "delegate": {
        "id": 1540,
        "url": "http://patches.dpdk.org/api/users/1540/?format=api",
        "username": "qzhan15",
        "first_name": "Qi",
        "last_name": "Zhang",
        "email": "qi.z.zhang@intel.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1609812336-29506-4-git-send-email-wei.huang@intel.com/mbox/",
    "series": [
        {
            "id": 14528,
            "url": "http://patches.dpdk.org/api/series/14528/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=14528",
            "date": "2021-01-05T02:05:32",
            "name": "raw/ifpga: add extra OPAE APIs",
            "version": 6,
            "mbox": "http://patches.dpdk.org/series/14528/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/85966/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/85966/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 (xvm-189-124.dc0.ghst.net [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 67378A09FF;\n\tTue,  5 Jan 2021 03:06:03 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 9319C160799;\n\tTue,  5 Jan 2021 03:05:35 +0100 (CET)",
            "from mga05.intel.com (mga05.intel.com [192.55.52.43])\n by mails.dpdk.org (Postfix) with ESMTP id C5CFA16078A;\n Tue,  5 Jan 2021 03:05:32 +0100 (CET)",
            "from orsmga003.jf.intel.com ([10.7.209.27])\n by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 04 Jan 2021 18:05:32 -0800",
            "from unknown (HELO sh_lab5_1.sh.intel.com) ([10.238.175.190])\n by orsmga003.jf.intel.com with ESMTP; 04 Jan 2021 18:05:30 -0800"
        ],
        "IronPort-SDR": [
            "\n faUGkcuxAy5MXiQ1Rzn3TGSiWFuEMNp5u1MFmJXVO4kUFULKWQMHQzF3ridtoK/Kdl5w+Zx86i\n oHebZr/h0Acg==",
            "\n /n94Gmo+zAnA5v0gx4M29hDseRKwJosoyz2VgExt0PnaE13G0CQzZnasO3fIcQcYlfdi8AC/t8\n fEOIFXW05OIg=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6000,8403,9854\"; a=\"261800723\"",
            "E=Sophos;i=\"5.78,475,1599548400\"; d=\"scan'208\";a=\"261800723\"",
            "E=Sophos;i=\"5.78,475,1599548400\"; d=\"scan'208\";a=\"346099980\""
        ],
        "X-ExtLoop1": "1",
        "From": "Wei Huang <wei.huang@intel.com>",
        "To": "dev@dpdk.org,\n\trosen.xu@intel.com,\n\tqi.z.zhang@intel.com",
        "Cc": "stable@dpdk.org, tianfei.zhang@intel.com, Wei Huang <wei.huang@intel.com>",
        "Date": "Mon,  4 Jan 2021 21:05:35 -0500",
        "Message-Id": "<1609812336-29506-4-git-send-email-wei.huang@intel.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1609812336-29506-1-git-send-email-wei.huang@intel.com>",
        "References": "<1609812336-29506-1-git-send-email-wei.huang@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v6 3/4] raw/ifpga: add opae API for Cyborg",
        "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": "Cyborg is part of OpenStack, it needs some OPAE type APIs to manage\nPACs (Programmable Acceleration Card) with Intel FPGA. Below major\nfunctions are added to meets Cyborg requirements.\n1. opae_init_eal() set up EAL environment.\n2. opae_cleanup_eal() clean up EAL environment.\n3. opae_enumerate() searches PAC with specific FPGA.\n4. opae_get_property() gets properties of FPGA.\n5. opae_partial_reconfigure() perform partial configuration on FPGA.\n6. opae_get_image_info() gets information of image file.\n7. opae_update_flash() updates FPGA flash with specific image file.\n8. opae_cancel_flash_update() cancel process of FPGA flash update.\n9. opae_probe_device() manually probe specific FPGA with ifpga driver.\n10. opae_remove_device() manually remove specific FPGA from ifpga driver.\n11. opae_bind_driver() binds specific FPGA with specified kernel driver.\n12. opae_unbind_driver() unbinds specific FPGA from kernel driver.\n13. opae_reboot_device() reboots specific FPGA (do reconfiguration).\n\nSigned-off-by: Wei Huang <wei.huang@intel.com>\n---\nv2: fix typo in commit log and ifpga_opae_api.h\n---\nv3: fix coding style issue in ifpga_opae_api.c\n---\nv4: enclose macro PCI_EXT_CAP_ID in parentheses\n---\nv5: fix icc compiler build error\n---\n drivers/raw/ifpga/ifpga_opae_api.c | 1801 ++++++++++++++++++++++++++++\n drivers/raw/ifpga/ifpga_opae_api.h |  245 ++++\n drivers/raw/ifpga/ifpga_rawdev.c   |  152 ++-\n drivers/raw/ifpga/ifpga_rawdev.h   |   15 +\n drivers/raw/ifpga/meson.build      |    4 +-\n 5 files changed, 2210 insertions(+), 7 deletions(-)\n create mode 100644 drivers/raw/ifpga/ifpga_opae_api.c\n create mode 100644 drivers/raw/ifpga/ifpga_opae_api.h",
    "diff": "diff --git a/drivers/raw/ifpga/ifpga_opae_api.c b/drivers/raw/ifpga/ifpga_opae_api.c\nnew file mode 100644\nindex 000000000..67866371d\n--- /dev/null\n+++ b/drivers/raw/ifpga/ifpga_opae_api.c\n@@ -0,0 +1,1801 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2020 Intel Corporation\n+ */\n+\n+#include <stdlib.h>\n+#include <string.h>\n+#include <dirent.h>\n+#include <fcntl.h>\n+#include <glob.h>\n+#include <unistd.h>\n+#include <sys/stat.h>\n+#include <rte_eal.h>\n+#include <rte_bus_pci.h>\n+#include <rte_rawdev_pmd.h>\n+#include \"base/opae_hw_api.h\"\n+#include \"base/ifpga_sec_mgr.h\"\n+#include \"ifpga_rawdev.h\"\n+#include \"ifpga_opae_api.h\"\n+\n+\n+int opae_log_level;\n+FILE *opae_log_file;\n+\n+static opae_api_version api_ver = {21, 2, 0};\n+static int eal_inited;\n+static uint32_t dev_aer[2] = {0};\n+\n+static const char * const log_level_name[] = {\"CRITICAL\", \"ERROR\",\n+\t\"WARNING\", \"INFORMATION\", \"DEBUG\"};\n+static const char * const proc_type_name[] = {\"NON-DPDK\", \"PRIMARY\",\n+\t\"SECONDARY\"};\n+static const char * const platform_name[] = {\"Vista Creek\", \"Rush Creek\",\n+\t\"Darby Creek\", \"Lightning Creek\"};\n+static const char * const release_name[] = {\"Pre-Alpha\", \"Alpha\", \"Beta\", \"PV\"};\n+static const char * const interface_type[] = {\"8x10G\", \"4x25G\", \"2x1x25G\",\n+\t\"4x25G+2x25G\", \"2x2x25G\", \"2x1x25Gx2FVL\", \"1x2x25G\"};\n+static const char * const kdrv[] = {OPAE_KDRV_UNKNOWN, OPAE_KDRV_IGB_UIO,\n+\tOPAE_KDRV_VFIO_PCI, OPAE_KDRV_UIO_PCI};\n+\n+RTE_INIT(init_api_env)\n+{\n+\teal_inited = 0;\n+\topae_log_level = OPAE_LOG_ERR;\n+\topae_log_file = NULL;\n+\tifpga_rawdev_logtype = 0;\n+\n+\topae_log_info(\"API environment is initialized\\n\");\n+}\n+\n+RTE_FINI(clean_api_env)\n+{\n+\tif (opae_log_file) {\n+\t\tfclose(opae_log_file);\n+\t\topae_log_file = NULL;\n+\t}\n+\topae_log_info(\"API environment is cleaned\\n\");\n+}\n+\n+void opae_get_api_version(opae_api_version *version)\n+{\n+\tif (version)\n+\t\tmemcpy(version, &api_ver, sizeof(opae_api_version));\n+\topae_log_info(\"API version is %u.%u.%u\\n\",\n+\t\tapi_ver.major, api_ver.minor, api_ver.micro);\n+}\n+\n+int opae_set_log_level(int level)\n+{\n+\tif ((level >= OPAE_LOG_API) && (level <= OPAE_LOG_DEBUG))\n+\t\topae_log_level = level;\n+\topae_log_api(\"Current log level is %s\\n\",\n+\t\tlog_level_name[opae_log_level]);\n+\treturn opae_log_level;\n+}\n+\n+int opae_set_log_file(char *path, int clean)\n+{\n+\tFILE *f = NULL;\n+\ttime_t start;\n+\tstruct tm *lt = NULL;\n+\n+\tif (path) {\n+\t\tif (clean)\n+\t\t\tf = fopen(path, \"w+\");\n+\t\telse\n+\t\t\tf = fopen(path, \"a+\");\n+\n+\t\tif (f) {\n+\t\t\tif (opae_log_file) {\n+\t\t\t\tfclose(opae_log_file);\n+\t\t\t\topae_log_file = NULL;\n+\t\t\t}\n+\t\t\ttime(&start);\n+\t\t\tlt = localtime(&start);\n+\t\t\tif (lt)\n+\t\t\t\tfprintf(f, \"================%d-%02d-%02d \"\n+\t\t\t\t\t\"%02d:%02d:%02d================\\n\",\n+\t\t\t\t\t1900 + lt->tm_year, 1 + lt->tm_mon,\n+\t\t\t\t\tlt->tm_mday,\n+\t\t\t\t\tlt->tm_hour, lt->tm_min, lt->tm_sec);\n+\t\t\tfflush(f);\n+\t\t\topae_log_file = f;\n+\t\t} else {\n+\t\t\topae_log_err(\"failed to open log file \\'%s\\'\\n\", path);\n+\t\t\treturn -1;\n+\t\t}\n+\t} else {\n+\t\tif (opae_log_file) {\n+\t\t\tfclose(opae_log_file);\n+\t\t\topae_log_file = NULL;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int opae_get_image_info(const char *image, opae_img_info *info)\n+{\n+\tint fd = -1;\n+\toff_t file_size = 0;\n+\topae_img_hdr hdr;\n+\tssize_t read_size = 0;\n+\tint ret = 0;\n+\n+\tif (!image || !info) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tfd = open(image, O_RDONLY);\n+\tif (fd < 0) {\n+\t\topae_log_err(\"Failed to open \\'%s\\' for RD [e:%s]\\n\",\n+\t\t\timage, strerror(errno));\n+\t\treturn -EIO;\n+\t}\n+\n+\tfile_size = lseek(fd, 0, SEEK_END);\n+\topae_log_dbg(\"Size of \\'%s\\' is %lu\\n\", image, file_size);\n+\tif (file_size < (OPAE_IMG_HDR_SIZE + OPAE_IMG_PL_MIN_SIZE)) {\n+\t\topae_log_err(\"Size of \\'%s\\' is less than expected [e:%u]\\n\",\n+\t\t\timage, OPAE_IMG_HDR_SIZE + OPAE_IMG_PL_MIN_SIZE);\n+\t\tret = -EINVAL;\n+\t\tgoto close_fd;\n+\t}\n+\n+\t/* read image header */\n+\tlseek(fd, 0, SEEK_SET);\n+\tread_size = read(fd, (void *)&hdr, sizeof(opae_img_hdr));\n+\tif (read_size < 0) {\n+\t\topae_log_err(\"Failed to read from \\'%s\\' [e:%s]\\n\",\n+\t\t\timage, strerror(errno));\n+\t\tret = -EIO;\n+\t\tgoto close_fd;\n+\t}\n+\tif ((size_t)read_size != sizeof(opae_img_hdr)) {\n+\t\topae_log_err(\"Read length %zd is not expected [e:%zu]\\n\",\n+\t\t\tread_size, sizeof(opae_img_hdr));\n+\t\tret = -EIO;\n+\t\tgoto close_fd;\n+\t}\n+\n+\tinfo->total_len = file_size;\n+\t/* check signed image header */\n+\tif (hdr.magic == OPAE_IMG_BLK0_MAGIC) {\n+\t\tinfo->type = OPAE_IMG_TYPE(hdr.payload_type);\n+\t\tinfo->subtype = OPAE_IMG_SUBTYPE(hdr.payload_type);\n+\t\tinfo->payload_offset = OPAE_IMG_HDR_SIZE;\n+\t\tinfo->payload_len = hdr.payload_len;\n+\t} else {\n+\t\topae_log_err(\"Image \\'%s\\' can not be recognized\\n\", image);\n+\t\tret = -EINVAL;\n+\t}\n+close_fd:\n+\tclose(fd);\n+\treturn ret;\n+}\n+\n+static int write_file(char *path, char *buf, int size)\n+{\n+\tint fd = -1;\n+\tssize_t n = 0;\n+\n+\tif (!path || !buf || (size <= 0))\n+\t\treturn -EINVAL;\n+\n+\tfd = open(path, O_WRONLY);\n+\tif (fd < 0) {\n+\t\topae_log_err(\"Failed to open \\'%s\\' for WR [e:%s]\\n\",\n+\t\t\tpath, strerror(errno));\n+\t\treturn -EIO;\n+\t}\n+\topae_log_dbg(\"Write \\\"%s\\\" to \\'%s\\'\\n\", buf, path);\n+\tn = write(fd, buf, size);\n+\tif (n < size)  {\n+\t\topae_log_err(\"Failed to write to \\'%s\\' [e:%s]\\n\",\n+\t\t\tpath, strerror(errno));\n+\t\tclose(fd);\n+\t\treturn -EIO;\n+\t}\n+\tclose(fd);\n+\n+\treturn 0;\n+}\n+\n+static int read_file(char *path, char *buf, int size)\n+{\n+\tint fd = -1;\n+\tssize_t n = 0;\n+\n+\tif (!path || !buf || (size <= 0))\n+\t\treturn -EINVAL;\n+\n+\tfd = open(path, O_RDONLY);\n+\tif (fd < 0) {\n+\t\topae_log_err(\"Failed to open \\'%s\\' for RD [e:%s]\\n\",\n+\t\t\tpath, strerror(errno));\n+\t\treturn -EIO;\n+\t}\n+\tn = read(fd, buf, size);\n+\tif (n < 0)  {\n+\t\topae_log_err(\"Failed to read from \\'%s\\' [e:%s]\\n\",\n+\t\t\tpath, strerror(errno));\n+\t\tclose(fd);\n+\t\treturn -EIO;\n+\t}\n+\tclose(fd);\n+\n+\tif (n > 0)\n+\t\tbuf[n-1] = 0;\n+\n+\topae_log_dbg(\"Read \\\"%s\\\" from \\'%s\\'\\n\", buf, path);\n+\treturn 0;\n+}\n+\n+int opae_get_proc_type(void)\n+{\n+\tint type = -1;\n+\n+\tif (eal_inited) {\n+\t\tif (rte_eal_process_type() == RTE_PROC_PRIMARY)\n+\t\t\ttype = 0;\n+\t\telse\n+\t\t\ttype = 1;\n+\t}\n+\topae_log_info(\"Current process type is %s\\n\", proc_type_name[type+1]);\n+\n+\treturn type;\n+}\n+\n+static bool check_eal(int inited)\n+{\n+\tif (!eal_inited) {\n+\t\tif (inited) {\n+\t\t\topae_log_warn(\"EAL is not initialized\\n\");\n+\t\t\treturn 0;\n+\t\t}\n+\t} else {\n+\t\tif (!inited) {\n+\t\t\topae_log_warn(\"EAL is already initialized\\n\");\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\treturn 1;\n+}\n+\n+int opae_init_eal(int argc, char **argv)\n+{\n+\tint ret = 0;\n+\n+\tif (!check_eal(0))\n+\t\treturn ret;\n+\n+\tret = rte_eal_init(argc, argv);\n+\tif (ret < 0) {\n+\t\tif (rte_errno == EALREADY) {\n+\t\t\teal_inited = 1;\n+\t\t\treturn 0;\n+\t\t}\n+\t\topae_log_err(\"Cannot initialize EAL [e:%d]\\n\", ret);\n+\t\tif (rte_eal_cleanup())\n+\t\t\topae_log_warn(\"EAL could not release all resources\\n\");\n+\t} else {\n+\t\teal_inited = 1;\n+\t\topae_log_info(\"Initialize EAL done\\n\");\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int opae_cleanup_eal(void)\n+{\n+\tint ret = 0;\n+\n+\tif (!check_eal(1))\n+\t\treturn -EPERM;\n+\n+\tifpga_rawdev_cleanup();\n+\n+\tret = rte_eal_cleanup();\n+\tif (ret)\n+\t\topae_log_err(\"Failed to cleanup EAL [e:%d]\\n\", ret);\n+\n+\treturn ret;\n+}\n+\n+static int compare_pci_id(opae_pci_id *id, opae_pci_id *expected_id)\n+{\n+\tif ((expected_id->class_id != BIT_SET_32) &&\n+\t\t(expected_id->class_id != id->class_id))\n+\t\treturn -1;\n+\tif ((expected_id->vendor_id != BIT_SET_16) &&\n+\t\t(expected_id->vendor_id != id->vendor_id))\n+\t\treturn -1;\n+\tif ((expected_id->device_id != BIT_SET_16) &&\n+\t\t(expected_id->device_id != id->device_id))\n+\t\treturn -1;\n+\tif ((expected_id->subsystem_vendor_id != BIT_SET_16) &&\n+\t\t(expected_id->subsystem_vendor_id != id->subsystem_vendor_id))\n+\t\treturn -1;\n+\tif ((expected_id->subsystem_device_id != BIT_SET_16) &&\n+\t\t(expected_id->subsystem_device_id != id->subsystem_device_id))\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n+static int parse_sysfs_value(char *node, uint32_t *val)\n+{\n+\tchar buf[16];\n+\tchar *end = NULL;\n+\tint ret = 0;\n+\n+\tret = read_file(node, buf, sizeof(buf));\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\t*val = (uint32_t)strtoul(buf, &end, 0);\n+\treturn 0;\n+}\n+\n+static int get_pci_id(const char *dev_path, opae_pci_id *id)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tuint32_t tmp;\n+\n+\tif (!dev_path || !id)\n+\t\treturn -EINVAL;\n+\n+\tsnprintf(path, sizeof(path), \"%s/vendor\", dev_path);\n+\tif (parse_sysfs_value(path, &tmp) < 0)\n+\t\treturn -ENODEV;\n+\tid->vendor_id = (uint16_t)tmp;\n+\n+\tsnprintf(path, sizeof(path), \"%s/device\", dev_path);\n+\tif (parse_sysfs_value(path, &tmp) < 0)\n+\t\treturn -ENODEV;\n+\tid->device_id = (uint16_t)tmp;\n+\n+\tsnprintf(path, sizeof(path), \"%s/subsystem_vendor\", dev_path);\n+\tif (parse_sysfs_value(path, &tmp) < 0)\n+\t\treturn -ENODEV;\n+\tid->subsystem_vendor_id = (uint16_t)tmp;\n+\n+\tsnprintf(path, sizeof(path), \"%s/subsystem_device\", dev_path);\n+\tif (parse_sysfs_value(path, &tmp) < 0)\n+\t\treturn -ENODEV;\n+\tid->subsystem_device_id = (uint16_t)tmp;\n+\n+\tsnprintf(path, sizeof(path), \"%s/class\", dev_path);\n+\tif (parse_sysfs_value(path, &tmp) < 0)\n+\t\treturn -ENODEV;\n+\tid->class_id = (uint32_t)tmp & RTE_CLASS_ANY_ID;\n+\n+\treturn 0;\n+}\n+\n+static int extract_path(char *in, int ridx, char *out, uint32_t size)\n+{\n+\tchar src[PATH_MAX] = {0};\n+\tchar *p = NULL;\n+\tint ret = 0;\n+\n+\tif (!in || (strlen(in) > PATH_MAX) || (ridx < 0) || !out)\n+\t\treturn -EINVAL;\n+\n+\tstrncpy(src, in, sizeof(src));\n+\t*out = 0;\n+\n+\twhile (1) {\n+\t\tp = strrchr(src, '/');\n+\t\tif (p) {\n+\t\t\t*p++ = 0;\n+\t\t\tif (*p) {\n+\t\t\t\tif (ridx-- <= 0) {\n+\t\t\t\t\tif (size > strlen(p)) {\n+\t\t\t\t\t\tstrncpy(out, p, size);\n+\t\t\t\t\t\tret = strlen(p);\n+\t\t\t\t\t}\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t} else {\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int opae_enumerate(opae_pci_id *filter, pcidev_id list, int size)\n+{\n+\tDIR *dir = NULL;\n+\tstruct dirent *dirent = NULL;\n+\tchar path[PATH_MAX] = {0};\n+\topae_pci_id id;\n+\tint n = 0;\n+\n+\tif (!filter || (size < 0) || (!list && (size > 0))) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tdir = opendir(rte_pci_get_sysfs_path());\n+\tif (!dir) {\n+\t\topae_log_err(\"Failed to open \\'%s\\'\\n\",\n+\t\t\trte_pci_get_sysfs_path());\n+\t\treturn -EINVAL;\n+\t}\n+\twhile ((dirent = readdir(dir))) {\n+\t\tif (!strcmp(dirent->d_name, \".\"))\n+\t\t\tcontinue;\n+\t\tif (!strcmp(dirent->d_name, \"..\"))\n+\t\t\tcontinue;\n+\n+\t\tsnprintf(path, PATH_MAX, \"%s/%s\", rte_pci_get_sysfs_path(),\n+\t\t\tdirent->d_name);\n+\t\tif (get_pci_id(path, &id) < 0)\n+\t\t\tcontinue;\n+\t\tif (compare_pci_id(&id, filter) < 0)\n+\t\t\tcontinue;\n+\n+\t\tif (n++ < size) {\n+\t\t\tsnprintf(list->bdf, sizeof(list->bdf), \"%s\",\n+\t\t\t\tdirent->d_name);\n+\t\t\tlist++;\n+\t\t}\n+\t}\n+\tclosedir(dir);\n+\n+\treturn n;\n+}\n+\n+static int get_driver(pcidev_id id, char *drv_name, uint32_t size)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tchar link[PATH_MAX] = {0};\n+\tint ret = 0;\n+\n+\tif (!id || !drv_name) {\n+\t\tret = -EINVAL;\n+\t\tgoto end;\n+\t}\n+\tsize--;   /* reserve one byte for the end of string */\n+\n+\tsnprintf(path, PATH_MAX, \"%s/%s/driver\",\n+\t\trte_pci_get_sysfs_path(), id->bdf);\n+\tret = readlink(path, link, PATH_MAX);\n+\tif (ret >= PATH_MAX) {\n+\t\topae_log_err(\"Link path too long [%d]\\n\", ret);\n+\t\tret = -ENAMETOOLONG;\n+\t\tgoto end;\n+\t}\n+\tif (ret > 0) {\n+\t\tret = extract_path(link, 0, drv_name, size);\n+\t} else {\n+\t\t*drv_name = 0;\n+\t\topae_log_info(\"No link path for \\'%s\\'\\n\", path);\n+\t\tret = 0;\n+\t}\n+\n+end:\n+\tif (ret < 0)\n+\t\topae_log_err(\"Failed to get driver of %s\\n\", id->bdf);\n+\n+\treturn ret;\n+}\n+\n+static int get_pci_addr(const char *bdf, opae_pci_addr *addr)\n+{\n+\tunsigned int domain = 0;\n+\tunsigned int bus = 0;\n+\tunsigned int devid = 0;\n+\tunsigned int function = 0;\n+\tint ret = 0;\n+\n+\tif (!bdf || !addr)\n+\t\treturn -EINVAL;\n+\n+\tret = sscanf(bdf, \"%04x:%02x:%02x.%d\",\n+\t\t&domain, &bus, &devid, &function);\n+\tif (ret == 4) {\n+\t\taddr->domain = (uint32_t)domain;\n+\t\taddr->bus = (uint8_t)bus;\n+\t\taddr->devid = (uint8_t)devid;\n+\t\taddr->function = (uint8_t)function;\n+\t\treturn 0;\n+\t}\n+\n+\treturn -EINVAL;\n+}\n+\n+static struct rte_rawdev *get_rte_rawdev(pcidev_id id, int log)\n+{\n+\topae_pci_addr addr;\n+\tstruct rte_rawdev *rdev = NULL;\n+\tchar rdev_name[OPAE_NAME_SIZE] = {0};\n+\n+\tif (!id)\n+\t\treturn NULL;\n+\n+\tif (get_pci_addr(id->bdf, &addr) < 0)\n+\t\treturn NULL;\n+\n+\tsnprintf(rdev_name, OPAE_NAME_SIZE, \"IFPGA:%02x:%02x.%x\",\n+\t\taddr.bus, addr.devid, addr.function);\n+\trdev = rte_rawdev_pmd_get_named_dev(rdev_name);\n+\tif (log && !rdev)\n+\t\topae_log_warn(\"%s is not probed\\n\", id->bdf);\n+\n+\treturn rdev;\n+}\n+\n+static struct rte_pci_device *get_rte_pcidev(pcidev_id id, int log)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\tstruct rte_pci_bus *pci_bus = NULL;\n+\tstruct rte_pci_device *pci_dev = NULL;\n+\n+\tif (!id)\n+\t\treturn NULL;\n+\n+\tpci_bus = ifpga_get_pci_bus();\n+\tif (pci_bus) {\n+\t\tTAILQ_FOREACH(pci_dev, &pci_bus->device_list, next) {\n+\t\t\tif (!strcmp(id->bdf, pci_dev->name))\n+\t\t\t\treturn pci_dev;\n+\t\t}\n+\t} else {\n+\t\trdev = get_rte_rawdev(id, 0);\n+\t\tif (rdev && rdev->device) {\n+\t\t\tpci_dev = RTE_DEV_TO_PCI(rdev->device);\n+\t\t\treturn pci_dev;\n+\t\t}\n+\t}\n+\n+\tif (log)\n+\t\topae_log_err(\"No rte_pci_device for %s\\n\", id->bdf);\n+\n+\treturn NULL;\n+}\n+\n+static int lock(pcidev_id id)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\tint ret = 0;\n+\n+\trdev = get_rte_rawdev(id, 0);\n+\tif (rdev)\n+\t\tret = ifpga_rawdev_lock(rdev);\n+\n+\treturn ret;\n+}\n+\n+static int unlock(pcidev_id id)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\tint ret = 0;\n+\n+\trdev = get_rte_rawdev(id, 0);\n+\tif (rdev)\n+\t\tret = ifpga_rawdev_unlock(rdev);\n+\n+\treturn ret;\n+}\n+\n+int opae_load_rsu_status(pcidev_id id, uint32_t *status, uint32_t *progress)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\tuint32_t value = 0;\n+\n+\tif (!check_eal(1))\n+\t\treturn -EPERM;\n+\n+\trdev = get_rte_rawdev(id, 1);\n+\tif (rdev)\n+\t\tvalue = ifpga_rawdev_get_rsu_stat(rdev);\n+\telse\n+\t\treturn -ENODEV;\n+\n+\tif (status)\n+\t\t*status = (value >> 16) & 0xffff;\n+\tif (progress)\n+\t\t*progress = value & 0xffff;\n+\n+\treturn 0;\n+}\n+\n+int opae_store_rsu_status(pcidev_id id, uint32_t status, uint32_t progress)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\tuint32_t value = 0;\n+\n+\tif (!check_eal(1))\n+\t\treturn -EPERM;\n+\n+\trdev = get_rte_rawdev(id, 1);\n+\tif (rdev) {\n+\t\tvalue = ((status << 16) & 0xffff0000) | (progress & 0xffff);\n+\t\tifpga_rawdev_set_rsu_stat(rdev, value);\n+\t} else {\n+\t\treturn -ENODEV;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int get_pci_property(pcidev_id id, opae_pci_property *prop)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tint ret = 0;\n+\n+\tif (!id || !prop)\n+\t\treturn -EINVAL;\n+\n+\tsnprintf(path, PATH_MAX, \"%s/%s\", rte_pci_get_sysfs_path(), id->bdf);\n+\n+\tret = get_pci_id(path, &prop->id);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tret = get_pci_addr(id->bdf, &prop->addr);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tsnprintf(prop->pci_addr, OPAE_NAME_SIZE, \"%s\", id->bdf);\n+\tget_driver(id, prop->drv_name, sizeof(prop->drv_name));\n+\n+\treturn 0;\n+}\n+\n+static int get_fme_property(pcidev_id id, opae_fme_property *prop)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\tifpga_fme_property fme_prop;\n+\topae_bitstream_id bbs_id;\n+\tint ret = 0;\n+\n+\tif (!prop)\n+\t\treturn -EINVAL;\n+\n+\trdev = get_rte_rawdev(id, 1);\n+\tif (!rdev)\n+\t\treturn -ENODEV;\n+\n+\tret = ifpga_rawdev_get_fme_property(rdev, &fme_prop);\n+\tif (!ret) {\n+\t\tprop->boot_page = fme_prop.boot_page;\n+\t\tprop->num_ports = fme_prop.num_ports;\n+\t\tprop->bitstream_id = fme_prop.bitstream_id;\n+\t\tprop->bitstream_metadata = fme_prop.bitstream_metadata;\n+\t\tmemcpy(prop->pr_id.b, fme_prop.pr_id.b, sizeof(opae_uuid));\n+\n+\t\tbbs_id.id = prop->bitstream_id;\n+\t\tif (bbs_id.major < sizeof(platform_name) / sizeof(char *)) {\n+\t\t\tsnprintf(prop->platform_name,\n+\t\t\t\tsizeof(prop->platform_name), \"%s\",\n+\t\t\t\tplatform_name[bbs_id.major]);\n+\t\t} else {\n+\t\t\tsnprintf(prop->platform_name,\n+\t\t\t\tsizeof(prop->platform_name), \"unknown\");\n+\t\t}\n+\n+\t\tsnprintf(prop->dcp_version, sizeof(prop->dcp_version),\n+\t\t\t\"DCP 1.%u\", bbs_id.minor);\n+\n+\t\tif (bbs_id.patch < sizeof(release_name)/sizeof(char *)) {\n+\t\t\tsnprintf(prop->release_name, sizeof(prop->release_name),\n+\t\t\t\t\"%s\", release_name[bbs_id.patch]);\n+\t\t} else {\n+\t\t\tsnprintf(prop->release_name, sizeof(prop->release_name),\n+\t\t\t\t\"unknown\");\n+\t\t}\n+\n+\t\tif (bbs_id.major == 0) {  /* Vista Creek */\n+\t\t\tif (bbs_id.interface <\n+\t\t\t\tsizeof(interface_type) / sizeof(char *)) {\n+\t\t\t\tsnprintf(prop->interface_type,\n+\t\t\t\t\tsizeof(prop->interface_type), \"%s\",\n+\t\t\t\t\tinterface_type[bbs_id.interface]);\n+\t\t\t} else {\n+\t\t\t\tsnprintf(prop->interface_type,\n+\t\t\t\t\tsizeof(prop->interface_type), \"unknown\");\n+\t\t\t}\n+\t\t} else {\n+\t\t\tsnprintf(prop->interface_type,\n+\t\t\t\tsizeof(prop->interface_type), \"unknown\");\n+\t\t}\n+\n+\t\tsnprintf(prop->build_version, sizeof(prop->build_version),\n+\t\t\t\"%u.%u.%u\", bbs_id.build_major, bbs_id.build_minor,\n+\t\t\tbbs_id.build_patch);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int get_port_property(pcidev_id id, uint32_t port,\n+\topae_port_property *prop)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\tifpga_port_property port_prop;\n+\tint ret = 0;\n+\n+\tif (!prop || (port >= OPAE_MAX_PORT_NUM))\n+\t\treturn -EINVAL;\n+\n+\trdev = get_rte_rawdev(id, 1);\n+\tif (!rdev)\n+\t\treturn -ENODEV;\n+\n+\tret = ifpga_rawdev_get_port_property(rdev, port, &port_prop);\n+\tif (!ret) {\n+\t\tmemcpy(prop->afu_id.b, port_prop.afu_id.b, sizeof(opae_uuid));\n+\t\tprop->type = port_prop.type;\n+\t\tprop->index = port;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int get_bmc_property(pcidev_id id, opae_bmc_property *prop)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\tifpga_bmc_property bmc_prop;\n+\topae_bmc_version ver;\n+\tint ret = 0;\n+\n+\tif (!prop)\n+\t\treturn -EINVAL;\n+\n+\trdev = get_rte_rawdev(id, 1);\n+\tif (!rdev)\n+\t\treturn -ENODEV;\n+\n+\tret = ifpga_rawdev_get_bmc_property(rdev, &bmc_prop);\n+\tif (!ret) {\n+\t\tver.version = bmc_prop.bmc_version;\n+\t\tsnprintf(prop->bmc_version, sizeof(prop->bmc_version), \"%c.%u.%u.%u\",\n+\t\t\tver.board, ver.major, ver.minor, ver.micro);\n+\n+\t\tver.version = bmc_prop.fw_version;\n+\t\tsnprintf(prop->fw_version, sizeof(prop->fw_version), \"%c.%u.%u.%u\",\n+\t\t\tver.board, ver.major, ver.minor, ver.micro);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int opae_get_property(pcidev_id id, opae_fpga_property *prop, int type)\n+{\n+\tuint32_t status = 0;\n+\tuint32_t i = 0;\n+\tint ret = 0;\n+\n+\tif (!prop) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (type == 0)\n+\t\ttype = OPAE_PROP_ALL;\n+\n+\tmemset(prop, 0, sizeof(opae_fpga_property));\n+\n+\t/* PCI properties */\n+\tif (type & OPAE_PROP_PCI) {\n+\t\tret = get_pci_property(id, &prop->pci);\n+\t\tif (ret < 0) {\n+\t\t\topae_log_err(\"Failed to get PCI property\\n\");\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\tif (type == OPAE_PROP_PCI)\n+\t\treturn 0;\n+\n+\tif (!check_eal(1))\n+\t\treturn -EPERM;\n+\n+\tif (!get_rte_rawdev(id, 1))\n+\t\treturn -ENODEV;\n+\n+\tlock(id);\n+\topae_load_rsu_status(id, &status, NULL);\n+\tif (status == IFPGA_RSU_REBOOT) {\n+\t\topae_log_warn(\"Reboot is in progress\\n\");\n+\t\tret = -EAGAIN;\n+\t\tgoto unlock_dev;\n+\t}\n+\n+\t/* FME properties */\n+\tif (type & (OPAE_PROP_FME | OPAE_PROP_PORT)) {\n+\t\tret = get_fme_property(id, &prop->fme);\n+\t\tif (ret) {\n+\t\t\topae_log_err(\"Failed to get FME property\\n\");\n+\t\t\tgoto unlock_dev;\n+\t\t}\n+\t}\n+\n+\t/* PORT properties */\n+\tif (type & OPAE_PROP_PORT) {\n+\t\tfor (i = 0; i < prop->fme.num_ports; i++) {\n+\t\t\tret = get_port_property(id, i, &prop->port[i]);\n+\t\t\tif (ret) {\n+\t\t\t\topae_log_err(\"Failed to get port property\\n\");\n+\t\t\t\tgoto unlock_dev;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* BMC properties */\n+\tif (type & OPAE_PROP_BMC) {\n+\t\tret = get_bmc_property(id, &prop->bmc);\n+\t\tif (ret) {\n+\t\t\topae_log_err(\"Failed to get BMC property\\n\");\n+\t\t\tgoto unlock_dev;\n+\t\t}\n+\t}\n+\n+unlock_dev:\n+\tunlock(id);\n+\treturn ret;\n+}\n+\n+int opae_get_phy_info(pcidev_id id, opae_phy_info *info)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\tifpga_phy_info phy_info;\n+\tint ret = 0;\n+\n+\tif (!info)\n+\t\treturn -EINVAL;\n+\n+\trdev = get_rte_rawdev(id, 1);\n+\tif (!rdev)\n+\t\treturn -ENODEV;\n+\n+\tret = ifpga_rawdev_get_phy_info(rdev, &phy_info);\n+\tif (!ret) {\n+\t\tinfo->num_retimers = phy_info.num_retimers;\n+\t\tinfo->link_speed = phy_info.link_speed;\n+\t\tinfo->link_status = phy_info.link_status;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int update_driver(pcidev_id id, char *drv_name)\n+{\n+\tstruct rte_pci_device *pci_dev = NULL;\n+\tchar name[OPAE_NAME_SIZE] = {0};\n+\tint ret = 0;\n+\n+\tif (!id)\n+\t\treturn -EINVAL;\n+\n+\tif (drv_name) {\n+\t\tif (strlen(drv_name) >= OPAE_NAME_SIZE) {\n+\t\t\topae_log_err(\"Driver name \\'%s\\' too long\\n\",\n+\t\t\t\tdrv_name);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tstrncpy(name, drv_name, sizeof(name));\n+\t} else {\n+\t\tret = get_driver(id, name, sizeof(name));\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\t}\n+\n+\tpci_dev = get_rte_pcidev(id, 0);\n+\tif (pci_dev) {\n+\t\tif (strlen(name) == 0) {\n+\t\t\tpci_dev->kdrv = RTE_PCI_KDRV_NONE;\n+\t\t} else {\n+\t\t\tif (!strcmp(name, OPAE_KDRV_VFIO_PCI))\n+\t\t\t\tpci_dev->kdrv = RTE_PCI_KDRV_VFIO;\n+\t\t\telse if (!strcmp(name, OPAE_KDRV_IGB_UIO))\n+\t\t\t\tpci_dev->kdrv = RTE_PCI_KDRV_IGB_UIO;\n+\t\t\telse if (!strcmp(name, OPAE_KDRV_UIO_PCI))\n+\t\t\t\tpci_dev->kdrv = RTE_PCI_KDRV_UIO_GENERIC;\n+\t\t\telse\n+\t\t\t\tpci_dev->kdrv = RTE_PCI_KDRV_UNKNOWN;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int opae_unbind_driver(pcidev_id id)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tchar drv_name[OPAE_NAME_SIZE] = {0};\n+\tchar null[] = {0};\n+\tint ret = 0;\n+\n+\tif (get_rte_rawdev(id, 0)) {\n+\t\topae_log_err(\"%s is probed, remove it first\\n\", id->bdf);\n+\t\treturn -EBUSY;\n+\t}\n+\n+\tret = get_driver(id, drv_name, sizeof(drv_name));\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (strlen(drv_name) > 0) {\n+\t\tsnprintf(path, PATH_MAX, \"/sys/bus/pci/drivers/%s/unbind\",\n+\t\t\tdrv_name);\n+\t\tret = write_file(path, id->bdf, strlen(id->bdf) + 1);\n+\t\tif (ret == 0)\n+\t\t\tret = update_driver(id, null);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int check_driver(const char *drv_name)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tstruct stat buf;\n+\n+\tif (!drv_name)\n+\t\treturn -EINVAL;\n+\n+\tif (strlen(drv_name) > 0) {\n+\t\tsnprintf(path, PATH_MAX, \"/sys/bus/pci/drivers/%s\", drv_name);\n+\t\tif ((stat(path, &buf) < 0) || ((buf.st_mode & S_IFDIR) == 0)) {\n+\t\t\topae_log_warn(\"Driver %s is not installed\\n\",\n+\t\t\t\tdrv_name);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int opae_bind_driver(pcidev_id id, char *drv_name)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tchar name[OPAE_NAME_SIZE] = {0};\n+\tchar null[] = {0};\n+\tint ret = 0;\n+\n+\tret = check_driver(drv_name);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tret = get_driver(id, name, sizeof(name));\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (!strcmp(drv_name, name))   /* driver not change */\n+\t\treturn 0;\n+\n+\tret = opae_unbind_driver(id);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (strlen(drv_name) > 0) {\n+\t\t/* bind driver */\n+\t\tsnprintf(path, PATH_MAX, \"%s/%s/driver_override\",\n+\t\t\trte_pci_get_sysfs_path(), id->bdf);\n+\t\tret = write_file(path, drv_name, strlen(drv_name) + 1);\n+\t\tif (ret < 0)\n+\t\t\tgoto update_drv;\n+\n+\t\tsnprintf(path, PATH_MAX, \"/sys/bus/pci/drivers/%s/bind\",\n+\t\t\tdrv_name);\n+\t\tret = write_file(path, id->bdf, strlen(id->bdf) + 1);\n+\t\tif (ret < 0)\n+\t\t\tgoto update_drv;\n+\n+\t\tsnprintf(path, PATH_MAX, \"%s/%s/driver_override\",\n+\t\t\trte_pci_get_sysfs_path(), id->bdf);\n+\t\tret = write_file(path, null, 1);\n+\t\tif (ret < 0)\n+\t\t\tgoto update_drv;\n+\t}\n+\n+update_drv:\n+\tret = update_driver(id, NULL);\n+\tif (ret < 0)\n+\t\topae_log_err(\"Failed to update driver information of %s\\n\",\n+\t\t\tid->bdf);\n+\n+\treturn 0;\n+}\n+\n+int opae_probe_device(pcidev_id id)\n+{\n+\tstruct rte_pci_bus *pci_bus = NULL;\n+\tstruct rte_pci_device *pci_dev = NULL;\n+\n+\tif (!id) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!check_eal(1))\n+\t\treturn -EPERM;\n+\n+\t/* make sure device is added in rte_pci_bus devices list */\n+\tpci_bus = ifpga_get_pci_bus();\n+\tif (pci_bus && pci_bus->bus.scan)\n+\t\tpci_bus->bus.scan();\n+\n+\tpci_dev = get_rte_pcidev(id, 1);\n+\tif (!pci_dev)\n+\t\treturn -ENODEV;\n+\n+\tif (pci_dev->kdrv != RTE_PCI_KDRV_VFIO) {\n+\t\topae_log_err(\"vfio-pci driver is not bound to %s\\n\", id->bdf);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!pci_bus || !pci_bus->bus.plug)\n+\t\treturn -ENODEV;\n+\n+\treturn pci_bus->bus.plug(&pci_dev->device);\n+}\n+\n+int opae_remove_device(pcidev_id id)\n+{\n+\tstruct rte_pci_device *pci_dev = NULL;\n+\tstruct rte_pci_driver *pci_drv = NULL;\n+\tint ret = 0;\n+\n+\tif (!check_eal(1))\n+\t\treturn -EPERM;\n+\n+\tpci_dev = get_rte_pcidev(id, 0);\n+\tif (pci_dev && pci_dev->driver) {\n+\t\tpci_drv = pci_dev->driver;\n+\t\tret = pci_drv->remove(pci_dev);\n+\t\tif (ret < 0) {\n+\t\t\topae_log_err(\"Failed to remove %s [e:%d]\\n\",\n+\t\t\t\tid->bdf, ret);\n+\t\t\treturn ret;\n+\t\t}\n+\t\tpci_dev->driver = NULL;\n+\t\tpci_dev->device.driver = NULL;\n+\t\tif (pci_drv->drv_flags & RTE_PCI_DRV_NEED_MAPPING)\n+\t\t\trte_pci_unmap_device(pci_dev);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int is_pac(pcidev_id id)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\topae_pci_id pci_id;\n+\n+\tif (!id)\n+\t\treturn 0;\n+\n+\tsnprintf(path, PATH_MAX, \"%s/%s\", rte_pci_get_sysfs_path(), id->bdf);\n+\tif (get_pci_id(path, &pci_id) < 0)\n+\t\treturn 0;\n+\n+\tif ((pci_id.vendor_id == 0x8086) && (pci_id.device_id == 0x0b30))\n+\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+int opae_get_parent(pcidev_id id, pcidev_id parent)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tchar link[PATH_MAX] = {0};\n+\tint ret = 0;\n+\n+\tif (!id || !parent) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\tret = -EINVAL;\n+\t\tgoto end;\n+\t}\n+\n+\tsnprintf(path, PATH_MAX, \"%s/%s\", rte_pci_get_sysfs_path(), id->bdf);\n+\tret = readlink(path, link, PATH_MAX);\n+\tif (ret >= PATH_MAX) {\n+\t\topae_log_err(\"Length of link path exceeds %u\\n\", PATH_MAX);\n+\t\tret = -ENAMETOOLONG;\n+\t\tgoto end;\n+\t}\n+\n+\tif (ret > 0) {\n+\t\tret = extract_path(link, 1, parent->bdf, sizeof(parent->bdf));\n+\t\tif (!strncmp(parent->bdf, \"pci\", 3)) {\n+\t\t\tparent->bdf[0] = 0;\n+\t\t\tret = -ENODEV;\n+\t\t}\n+\t} else {\n+\t\tparent->bdf[0] = 0;\n+\t\tif (ret == 0)\n+\t\t\topae_log_err(\"Length of link path is 0\\n\");\n+\t\telse\n+\t\t\topae_log_err(\"No link path for \\'%s\\'\\n\", path);\n+\t}\n+end:\n+\tif (ret <= 0)\n+\t\topae_log_err(\"%s has no parent\\n\", id->bdf);\n+\n+\treturn ret;\n+}\n+\n+int opae_get_child(pcidev_id id, pcidev_id child, int size)\n+{\n+\tglob_t pglob = {.gl_pathc = 0, .gl_pathv = NULL};\n+\tchar path[PATH_MAX] = {0};\n+\tint i, count = 0;\n+\tint len = 0;\n+\tint ret = 0;\n+\n+\tif (!id || (size < 0)) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsnprintf(path, PATH_MAX, \"%s/%s/*:*:*.?\", rte_pci_get_sysfs_path(),\n+\t\tid->bdf);\n+\tret = glob(path, 0, NULL, &pglob);\n+\tif (ret == 0) {\n+\t\tif (child && (size > 0)) {\n+\t\t\tfor (i = 0; i < (int)pglob.gl_pathc; i++) {\n+\t\t\t\tlen = extract_path(pglob.gl_pathv[i], 0,\n+\t\t\t\t\tchild->bdf, sizeof(child->bdf));\n+\t\t\t\tif (len <= 0) {\n+\t\t\t\t\tchild->bdf[0] = 0;\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\t\t\t\tif (++count >= size)\n+\t\t\t\t\tbreak;\n+\t\t\t\tchild++;\n+\t\t\t}\n+\t\t} else {\n+\t\t\tcount = (int)pglob.gl_pathc;\n+\t\t}\n+\t\tglobfree(&pglob);\n+\t} else {\n+\t\tif (pglob.gl_pathv)\n+\t\t\tglobfree(&pglob);\n+\t}\n+\n+\treturn count;\n+}\n+\n+int opae_get_pf1(pcidev_id id, pcidev_id peer, int size)\n+{\n+\topae_pci_device parent;\n+\topae_pci_device child[4];\n+\tint n = 0;\n+\tint ret = 0;\n+\n+\tif (!id) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!is_pac(id)) {\n+\t\topae_log_info(\"%s has no peer function\\n\", id->bdf);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tret = opae_get_parent(id, &parent);\n+\tif (ret < 0)\n+\t\treturn -ENODEV;\n+\tret = opae_get_parent(&parent, &parent);\n+\tif (ret < 0)\n+\t\treturn -ENODEV;\n+\n+\tn = opae_get_child(&parent, child,\n+\t\tsizeof(child) / sizeof(opae_pci_device));\n+\t/* there should have four downstream ports of PCI switch on board */\n+\tif (n == 4) {\n+\t\tn = opae_get_child(&child[3], peer, size);\n+\t} else {\n+\t\tpeer->bdf[0] = 0;\n+\t\topae_log_dbg(\"%s has %d child(s)\\n\", parent.bdf, n);\n+\t\tn = 0;\n+\t}\n+\n+\treturn n;\n+}\n+\n+void opae_check_pcidev_list(void)\n+{\n+\tint i = 0;\n+\tunsigned int k = 0;\n+\tstruct rte_pci_bus *pci_bus = NULL;\n+\tstruct rte_pci_device *pci_dev = NULL;\n+\n+\tif (!check_eal(1))\n+\t\treturn;\n+\n+\tpci_bus = ifpga_get_pci_bus();\n+\tif (!pci_bus)\n+\t\treturn;\n+\n+\tprintf(\" ID     NAME       SEG BUS DEV FUNC  VID  DID   KDRV\\n\");\n+\tTAILQ_FOREACH(pci_dev, &pci_bus->device_list, next) {\n+\t\tk = pci_dev->kdrv;\n+\t\tprintf(\"%3d %s  %04x  %02x  %02x %2d   %04x %04x   %s\\n\",\n+\t\t\ti, pci_dev->name, pci_dev->addr.domain,\n+\t\t\tpci_dev->addr.bus, pci_dev->addr.devid,\n+\t\t\tpci_dev->addr.function, pci_dev->id.vendor_id,\n+\t\t\tpci_dev->id.device_id,\n+\t\t\tk > RTE_PCI_KDRV_UIO_GENERIC ? \"\" : kdrv[k]);\n+\t\ti++;\n+\t}\n+}\n+\n+int opae_update_flash(pcidev_id id, const char *image, uint64_t *status)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\topae_img_info info;\n+\tint ret = 0;\n+\n+\tret = opae_get_image_info(image, &info);\n+\tif (ret < 0) {\n+\t\topae_log_err(\"Failed to get image information [e:%d]\\n\", ret);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif ((info.type != OPAE_IMG_TYPE_BBS) &&\n+\t\t(info.type != OPAE_IMG_TYPE_BMC)) {\n+\t\topae_log_err(\"Image is not supported [t:%u]\\n\", info.type);\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tif (!check_eal(1))\n+\t\treturn -EPERM;\n+\n+\trdev = get_rte_rawdev(id, 1);\n+\tif (!rdev)\n+\t\treturn -ENODEV;\n+\n+\treturn ifpga_rawdev_update_flash(rdev, image, status);\n+}\n+\n+int opae_cancel_flash_update(pcidev_id id, int force)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\n+\tif (!check_eal(1))\n+\t\treturn -EPERM;\n+\n+\trdev = get_rte_rawdev(id, 1);\n+\tif (!rdev)\n+\t\treturn -ENODEV;\n+\n+\treturn ifpga_rawdev_stop_flash_update(rdev, force);\n+}\n+\n+#define PCI_EXT_CAP_ID_ERR\t\t0x01\t/* Advanced Error Reporting */\n+#define PCI_CFG_SPACE_SIZE\t\t256\n+#define PCI_CFG_SPACE_EXP_SIZE\t4096\n+#define PCI_EXT_CAP_ID(hdr)\t\t((int)((hdr) & 0x0000ffff))\n+#define PCI_EXT_CAP_NEXT(hdr)\t(((hdr) >> 20) & 0xffc)\n+\n+static int find_pci_ecap(int fd, int cap)\n+{\n+\tuint32_t header = 0;\n+\tint ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;\n+\tint pos = PCI_CFG_SPACE_SIZE;  /* start of extension capability area */\n+\tint ret = 0;\n+\n+\tret = pread(fd, &header, sizeof(header), pos);\n+\tif (ret < 0) {\n+\t\topae_log_err(\"Failed to read from PCI configuration space [e:%s]\\n\",\n+\t\t\tstrerror(errno));\n+\t\treturn ret;\n+\t}\n+\topae_log_dbg(\"Read 0x%08x from PCI configuration space 0x%x\\n\",\n+\t\theader, pos);\n+\n+\tif (header == 0) {\n+\t\topae_log_err(\"Capability is empty\\n\");\n+\t\treturn 0;\n+\t}\n+\n+\twhile (ttl-- > 0) {\n+\t\tif ((PCI_EXT_CAP_ID(header) == cap) && (pos != 0))\n+\t\t\treturn pos;\n+\n+\t\tpos = PCI_EXT_CAP_NEXT(header);\n+\t\tif (pos < PCI_CFG_SPACE_SIZE) {\n+\t\t\topae_log_err(\"Position of capability is invalid\"\n+\t\t\t\t\t\t \"[e:%d]\\n\", pos);\n+\t\t\tbreak;\n+\t\t}\n+\t\tret = pread(fd, &header, sizeof(header), pos);\n+\t\tif (ret < 0) {\n+\t\t\topae_log_err(\"Failed to read from PCI config space [e:%s]\\n\",\n+\t\t\t\tstrerror(errno));\n+\t\t\treturn ret;\n+\t\t}\n+\t\topae_log_dbg(\"Read 0x%08x from PCI configuration space 0x%x\\n\",\n+\t\t\theader, pos);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int set_aer(pcidev_id id, uint32_t v1, uint32_t v2, int record)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tuint32_t val = 0;\n+\tint fd = -1;\n+\tint pos = 0;\n+\tint ret = 0;\n+\n+\tif (!id)\n+\t\treturn -EINVAL;\n+\n+\tsnprintf(path, PATH_MAX, \"%s/%s/config\",\n+\t\trte_pci_get_sysfs_path(), id->bdf);\n+\tfd = open(path, O_RDWR);\n+\tif (fd < 0) {\n+\t\topae_log_err(\"Failed to open \\'%s\\' for RDWR [e:%s]\\n\",\n+\t\t\tpath, strerror(errno));\n+\t\treturn -EIO;\n+\t}\n+\n+\tpos = find_pci_ecap(fd, PCI_EXT_CAP_ID_ERR);\n+\tif (pos <= 0) {\n+\t\topae_log_warn(\"AER capability is not present\\n\");\n+\t\tret = -ENXIO;\n+\t\tgoto close_fd;\n+\t}\n+\n+\tif (record) {\n+\t\tret = pread(fd, &val, sizeof(val), pos + 0x08);\n+\t\tif (ret < 0) {\n+\t\t\topae_log_err(\"Failed to read from PCI config space [e:%s]\\n\",\n+\t\t\t\tstrerror(errno));\n+\t\t\tgoto close_fd;\n+\t\t}\n+\t\topae_log_dbg(\"Read 0x%08x from PCI configuration space 0x%x\\n\",\n+\t\t\tval, pos + 0x08);\n+\t\tdev_aer[0] = val;\n+\n+\t\tret = pread(fd, &val, sizeof(val), pos + 0x14);\n+\t\tif (ret < 0) {\n+\t\t\topae_log_err(\"Failed to read from PCI config space [e:%s]\\n\",\n+\t\t\t\tstrerror(errno));\n+\t\t\tgoto close_fd;\n+\t\t}\n+\t\topae_log_dbg(\"Read 0x%08x from PCI configuration space 0x%x\\n\",\n+\t\t\tval, pos + 0x14);\n+\t\tdev_aer[1] = val;\n+\t}\n+\n+\topae_log_dbg(\"Write 0x%08x to PCI configuration space 0x%x\\n\",\n+\t\tv1, pos + 0x08);\n+\tret = pwrite(fd, &v1, sizeof(v1), pos + 0x08);\n+\tif (ret < 0) {\n+\t\topae_log_err(\"Failed to write to PCI config space 0x%x [e:%s]\\n\",\n+\t\t\tpos + 0x08, strerror(errno));\n+\t\tgoto close_fd;\n+\t}\n+\n+\topae_log_dbg(\"Write 0x%08x to PCI configuration space 0x%x\\n\",\n+\t\tv2, pos + 0x14);\n+\tret = pwrite(fd, &v2, sizeof(v2), pos + 0x14);\n+\tif (ret < 0) {\n+\t\topae_log_err(\"Failed to write to PCI config space 0x%x [e:%s]\\n\",\n+\t\t\tpos + 0x14, strerror(errno));\n+\t}\n+\n+close_fd:\n+\tclose(fd);\n+\treturn ret < 0 ? ret : 0;\n+}\n+\n+static int enable_aer(pcidev_id id)\n+{\n+\tif (!id) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\topae_log_info(\"Enable AER of %s\\n\", id->bdf);\n+\n+\treturn set_aer(id, dev_aer[0], dev_aer[1], 0);\n+}\n+\n+static int disable_aer(pcidev_id id)\n+{\n+\tif (!id) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\topae_log_info(\"Disable AER of %s\\n\", id->bdf);\n+\n+\treturn set_aer(id, 0xffffffff, 0xffffffff, 1);\n+}\n+\n+static int reload(pcidev_id id, int type, int page)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\tint ret = 0;\n+\n+\trdev = get_rte_rawdev(id, 1);\n+\tif (rdev)\n+\t\tret = ifpga_rawdev_reload(rdev, type, page);\n+\telse\n+\t\tret = -ENODEV;\n+\n+\treturn ret;\n+}\n+\n+static int remove_tree(pcidev_id id)\n+{\n+\tint i, n = 0;\n+\tpcidev_id child;\n+\tint ret = 0;\n+\n+\tif (!id) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tn = opae_get_child(id, NULL, 0);\n+\tif (n > 0) {\n+\t\tchild = (pcidev_id)rte_zmalloc(NULL,\n+\t\t\tsizeof(opae_pci_device) * n, 0);\n+\t\tif (!child) {\n+\t\t\topae_log_err(\"Failed to malloc for children of %s\\n\",\n+\t\t\t\tid->bdf);\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto end;\n+\t\t}\n+\n+\t\topae_get_child(id, child, n);\n+\t\tfor (i = 0; i < n; i++)\n+\t\t\tremove_tree(&child[i]);\n+\t\topae_free(child);\n+\t}\n+\n+end:\n+\topae_remove_device(id);\n+\treturn ret;\n+}\n+\n+static int remove_device(pcidev_id id)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tchar one[] = {'1', 0};\n+\tint ret = 0;\n+\n+\tif (!id) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\topae_log_info(\"Remove %s from system\\n\", id->bdf);\n+\n+\tsnprintf(path, PATH_MAX, \"%s/%s/remove\",\n+\t\trte_pci_get_sysfs_path(), id->bdf);\n+\tret = write_file(path, one, strlen(one));\n+\tif (ret < 0) {\n+\t\topae_log_err(\"Failed to remove %s from system\\n\", id->bdf);\n+\t\treturn ret;\n+\t}\n+\n+\tremove_tree(id);\n+\n+\treturn 0;\n+}\n+\n+static int scan_device(pcidev_id parent, pcidev_id id)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tchar bus[8] = {0};\n+\tchar one[] = {'1', 0};\n+\tchar pwr[16] = {0};\n+\tchar pwr_on[] = {'o', 'n', 0};\n+\tint pwr_on_failed = 0;\n+\tint ret = 0;\n+\n+\tif (!parent) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\topae_log_info(\"Rescan devices under %s\\n\", parent->bdf);\n+\n+\tif (id) {   /* scan specified bus under parent device */\n+\t\tsnprintf(path, PATH_MAX, \"%s/%s/power/control\",\n+\t\t\trte_pci_get_sysfs_path(), parent->bdf);\n+\t\tret = read_file(path, pwr, sizeof(pwr));\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\n+\t\tif (strcmp(pwr, \"on\")) {\n+\t\t\tret = write_file(path, pwr_on, strlen(pwr_on));\n+\t\t\tif (ret < 0)\n+\t\t\t\tpwr_on_failed = 1;\n+\t\t\telse\n+\t\t\t\tsleep(1);\n+\t\t}\n+\n+\t\tsnprintf(bus, sizeof(bus), \"%s\", id->bdf);\n+\t\tsnprintf(path, PATH_MAX, \"%s/%s/pci_bus/%s/rescan\",\n+\t\t\trte_pci_get_sysfs_path(), parent->bdf, bus);\n+\t\tret = write_file(path, one, strlen(one));\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\n+\t\tif (pwr_on_failed) {   /* workaround for power on failed */\n+\t\t\tret = write_file(path, one, strlen(one));\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t}\n+\n+\t\tif (strcmp(pwr, \"on\")) {\n+\t\t\tsnprintf(path, PATH_MAX, \"%s/%s/power/control\",\n+\t\t\t\trte_pci_get_sysfs_path(), parent->bdf);\n+\t\t\tret = write_file(path, pwr, strlen(pwr));\n+\t\t}\n+\t} else {   /* scan all buses under parent device */\n+\t\tsnprintf(path, PATH_MAX, \"%s/%s/rescan\",\n+\t\t\trte_pci_get_sysfs_path(), parent->bdf);\n+\t\tret = write_file(path, one, strlen(one));\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int opae_reboot_device(pcidev_id id, int type, int page)\n+{\n+\topae_pci_device fpga;    /* FPGA after reboot */\n+\topae_pci_device parent;\n+\topae_pci_device peer[2];   /* physical function 1 of FPGA */\n+\topae_pci_device peer_parent;\n+\topae_pci_device ups;   /* upstream port device */\n+\topae_pci_device root;  /* port connected to PAC */\n+\tpcidev_id peer_primary = NULL;\n+\tuint32_t rsu_stat = 0;\n+\tchar drv_name[OPAE_NAME_SIZE] = {0};\n+\tint n = 0;\n+\tint i = 0;\n+\tint ret = 0;\n+\n+\tif (!id) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!is_pac(id)) {\n+\t\topae_log_err(\"%s can not be rebooted\\n\", id->bdf);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tret = opae_get_parent(id, &parent);\n+\tif (ret < 0)\n+\t\treturn -ENODEV;\n+\tret = opae_get_parent(&parent, &ups);\n+\tif (ret < 0)\n+\t\treturn -ENODEV;\n+\tret = opae_get_parent(&ups, &root);\n+\tif (ret < 0)\n+\t\treturn -ENODEV;\n+\n+\tn = opae_get_pf1(id, peer, sizeof(peer) / sizeof(opae_pci_device));\n+\tif (n <= 0) {\n+\t\topae_log_err(\"PF1 of %s is not found\\n\", id->bdf);\n+\t} else {\n+\t\tpeer_primary = &peer[0];\n+\t\tret = opae_get_parent(peer_primary, &peer_parent);\n+\t\tif (ret < 0)\n+\t\t\treturn -ENODEV;\n+\t}\n+\n+\tget_driver(id, drv_name, sizeof(drv_name));  /* save original driver */\n+\n+\tif (!check_eal(1))\n+\t\treturn -EPERM;\n+\n+\tif (!get_rte_rawdev(id, 1))\n+\t\treturn -ENODEV;\n+\n+\tlock(id);\n+\topae_load_rsu_status(id, &rsu_stat, NULL);\n+\tif (rsu_stat != IFPGA_RSU_IDLE) {\n+\t\tunlock(id);\n+\t\tif (rsu_stat == IFPGA_RSU_REBOOT)\n+\t\t\topae_log_warn(\"Reboot is in progress\\n\");\n+\t\telse\n+\t\t\topae_log_warn(\"Flash is in progress\\n\");\n+\t\treturn -EAGAIN;\n+\t}\n+\topae_store_rsu_status(id, IFPGA_RSU_REBOOT, 0);\n+\tunlock(id);\n+\n+\tif (type == IFPGA_BOOT_TYPE_FPGA) {\n+\t\t/* disable AER */\n+\t\tret = disable_aer(&parent);\n+\t\tif (ret < 0) {\n+\t\t\topae_log_err(\"Failed to disable AER of %s\\n\",\n+\t\t\t\tparent.bdf);\n+\t\t\tgoto reboot_end;\n+\t\t}\n+\t\tret = disable_aer(&peer_parent);\n+\t\tif (ret < 0) {\n+\t\t\topae_log_err(\"Failed to disable AER of %s\\n\",\n+\t\t\t\tpeer_parent.bdf);\n+\t\t\tgoto reboot_end;\n+\t\t}\n+\t\topae_store_rsu_status(id, IFPGA_RSU_REBOOT, 1);\n+\n+\t\t/* trigger reconfiguration */\n+\t\tret = reload(id, type, page);\n+\t\topae_store_rsu_status(id, IFPGA_RSU_REBOOT, 2);\n+\t\tif (ret == 0) {\n+\t\t\tret = remove_device(id);\n+\t\t\tfor (i = 0; i < n; i++)\n+\t\t\t\tret += remove_device(&peer[i]);\n+\t\t\tif (ret == 0) {\n+\t\t\t\topae_log_info(\"Wait 10 seconds for FPGA reloading\\n\");\n+\t\t\t\tsleep(10);\n+\t\t\t\tret = scan_device(&parent, id);\n+\t\t\t\tif (ret < 0)\n+\t\t\t\t\topae_log_err(\"Failed to rescan %s\\n\",\n+\t\t\t\t\t\tid->bdf);\n+\t\t\t\tif (peer_primary) {\n+\t\t\t\t\tret = scan_device(&peer_parent,\n+\t\t\t\t\t\tpeer_primary);\n+\t\t\t\t\tif (ret < 0) {\n+\t\t\t\t\t\topae_log_err(\"Failed to rescan %s\\n\",\n+\t\t\t\t\t\t\tpeer_primary->bdf);\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* restore AER */\n+\t\tif (enable_aer(&parent) < 0) {\n+\t\t\topae_log_err(\"Failed to enable AER of %s\\n\",\n+\t\t\t\tparent.bdf);\n+\t\t}\n+\t\tif (enable_aer(&peer_parent) < 0) {\n+\t\t\topae_log_err(\"Failed to enable AER of %s\\n\",\n+\t\t\t\tpeer_parent.bdf);\n+\t\t}\n+\t} else if (type == IFPGA_BOOT_TYPE_BMC) {\n+\t\t/* disable AER */\n+\t\tret = disable_aer(&root);\n+\t\tif (ret < 0) {\n+\t\t\topae_log_err(\"Failed to disable AER of %s\\n\", root.bdf);\n+\t\t\tgoto reboot_end;\n+\t\t}\n+\t\topae_store_rsu_status(id, IFPGA_RSU_REBOOT, 1);\n+\n+\t\t/* trigger reconfiguration */\n+\t\tret = reload(id, type, page);\n+\t\topae_store_rsu_status(id, IFPGA_RSU_REBOOT, 2);\n+\t\tif (ret == 0) {\n+\t\t\tret += remove_device(&ups);\n+\t\t\tif (ret == 0) {\n+\t\t\t\topae_log_info(\"Wait 10 seconds for BMC reloading\\n\");\n+\t\t\t\tsleep(10);\n+\t\t\t\tret = scan_device(&root, &ups);\n+\t\t\t\tif (ret < 0)\n+\t\t\t\t\topae_log_err(\"Failed to rescan %s\\n\",\n+\t\t\t\t\t\tups.bdf);\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* restore AER */\n+\t\tif (enable_aer(&root) < 0)\n+\t\t\topae_log_err(\"Failed to enable AER of %s\\n\", root.bdf);\n+\t} else {\n+\t\topae_log_err(\"Type of reboot is not supported [t:%d]\\n\", type);\n+\t\tret = -EINVAL;\n+\t\tgoto reboot_end;\n+\t}\n+\n+\t/* update id if bdf changed after reboot */\n+\tif (opae_get_child(&parent, &fpga, 1) == 1) {\n+\t\tif (strcmp(id->bdf, fpga.bdf))\n+\t\t\tid = &fpga;\n+\t}\n+\n+\tret = opae_bind_driver(id, drv_name);\n+\tif (ret < 0)\n+\t\topae_log_err(\"Failed to bind original driver of %s\\n\", id->bdf);\n+\n+\tret = opae_probe_device(id);\n+\tif (ret < 0)\n+\t\topae_log_err(\"Failed to probe %s [e:%d]\\n\", id->bdf, ret);\n+\n+reboot_end:\n+\topae_store_rsu_status(id, IFPGA_RSU_IDLE, 0);\n+\treturn ret;\n+}\n+\n+int opae_partial_reconfigure(pcidev_id id, int port, const char *gbs)\n+{\n+\tstruct rte_rawdev *rdev = NULL;\n+\n+\tif (!id || !gbs) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!check_eal(1))\n+\t\treturn -EPERM;\n+\n+\trdev = get_rte_rawdev(id, 1);\n+\tif (!rdev)\n+\t\treturn -ENODEV;\n+\n+\treturn ifpga_rawdev_partial_reconfigure(rdev, port, gbs);\n+}\n+\n+int opae_read_pci_cfg(pcidev_id id, uint32_t address, uint32_t *value)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tint fd = -1;\n+\tint ret = 0;\n+\n+\tif (!id || !value) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsnprintf(path, PATH_MAX, \"%s/%s/config\", rte_pci_get_sysfs_path(),\n+\t\tid->bdf);\n+\tfd = open(path, O_RDONLY);\n+\tif (fd < 0) {\n+\t\topae_log_dbg(\"Failed to open \\'%s\\' for RDONLY [e:%s]\\n\",\n+\t\t\tpath, strerror(errno));\n+\t\treturn -EIO;\n+\t}\n+\n+\tret = pread(fd, value, 4, address);\n+\tif (ret < 0) {\n+\t\topae_log_err(\"Failed to read from PCI device %s [e:%s]\\n\",\n+\t\t\tid->bdf, strerror(errno));\n+\t\tclose(fd);\n+\t\treturn ret;\n+\t}\n+\n+\topae_log_dbg(\"CONFIG+0x%08x -> 0x%08x\\n\", address, *value);\n+\tclose(fd);\n+\treturn 0;\n+}\n+\n+int opae_write_pci_cfg(pcidev_id id, uint32_t address, uint32_t value)\n+{\n+\tchar path[PATH_MAX] = {0};\n+\tint fd = -1;\n+\tint ret = 0;\n+\n+\tif (!id) {\n+\t\topae_log_err(\"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsnprintf(path, PATH_MAX, \"%s/%s/config\", rte_pci_get_sysfs_path(),\n+\t\tid->bdf);\n+\tfd = open(path, O_WRONLY);\n+\tif (fd < 0) {\n+\t\topae_log_dbg(\"Failed to open \\'%s\\' for WRONLY [e:%s]\\n\",\n+\t\t\tpath, strerror(errno));\n+\t\treturn -EIO;\n+\t}\n+\n+\tret = pwrite(fd, &value, 4, address);\n+\tif (ret < 0) {\n+\t\topae_log_err(\"Failed to write to PCI device %s [e:%s]\\n\",\n+\t\t\tid->bdf, strerror(errno));\n+\t\tclose(fd);\n+\t\treturn ret;\n+\t}\n+\n+\topae_log_dbg(\"CONFIG+0x%08x <- 0x%08x\\n\", address, value);\n+\tclose(fd);\n+\treturn 0;\n+}\ndiff --git a/drivers/raw/ifpga/ifpga_opae_api.h b/drivers/raw/ifpga/ifpga_opae_api.h\nnew file mode 100644\nindex 000000000..d4ce64280\n--- /dev/null\n+++ b/drivers/raw/ifpga/ifpga_opae_api.h\n@@ -0,0 +1,245 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2020 Intel Corporation\n+ */\n+\n+#ifndef _OPAE_API_H\n+#define _OPAE_API_H\n+\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+#include <stdint.h>\n+\n+extern int opae_log_level;\n+extern FILE *opae_log_file;\n+\n+#define OPAE_LOG_API      0  /**< Critical conditions.              */\n+#define OPAE_LOG_ERR      1  /**< Error conditions.                 */\n+#define OPAE_LOG_WARN     2  /**< Warning conditions.               */\n+#define OPAE_LOG_INFO     3  /**< Informational.                    */\n+#define OPAE_LOG_DEBUG    4  /**< Debug-level messages.             */\n+\n+#define opae_log(type, fmt, args...)             \\\n+do {                                             \\\n+\tif (opae_log_level >= OPAE_LOG_##type) {     \\\n+\t\tprintf(fmt, ##args);                     \\\n+\t\tif (opae_log_file) {                     \\\n+\t\t\tfprintf(opae_log_file, fmt, ##args); \\\n+\t\t\tfflush(opae_log_file);               \\\n+\t\t}                                        \\\n+\t}                                            \\\n+} while (0)\n+\n+#define opae_log_api(fmt, args...)  opae_log(API, \"OPAE-API: \"fmt, ##args)\n+#define opae_log_err(fmt, args...)  opae_log(ERR, \"OPAE-ERR: \"fmt, ##args)\n+#define opae_log_dbg(fmt, args...)  opae_log(DEBUG, \"OPAE-DBG: \"fmt, ##args)\n+#define opae_log_warn(fmt, args...) opae_log(WARN, \"OPAE-WARN: \"fmt, ##args)\n+#define opae_log_info(fmt, args...) opae_log(INFO, \"OPAE-INFO: \"fmt, ##args)\n+\n+#define EAL_INIT_FUNCTION    \"init\"\n+#define EAL_DEFAULT_OPTIONS  \"--proc-type auto\"\n+\n+#define OPAE_KDRV_UNKNOWN           \"unknown\"\n+#define OPAE_KDRV_VFIO_PCI          \"vfio-pci\"\n+#define OPAE_KDRV_IGB_UIO           \"igb_uio\"\n+#define OPAE_KDRV_UIO_PCI           \"uio_pci_generic\"\n+#define OPAE_KDRV_INTEL_FPGA_PCI    \"intel-fpga-pci\"\n+\n+typedef struct {\n+\tuint32_t major;\n+\tuint32_t minor;\n+\tuint32_t micro;\n+} opae_api_version;\n+\n+#define OPAE_NAME_SIZE  32\n+\n+typedef struct {\n+\tchar bdf[OPAE_NAME_SIZE];   /* segment:bus:device.function */\n+} opae_pci_device;\n+\n+typedef opae_pci_device *pcidev_id;\n+\n+typedef struct {\n+\tuint32_t class_id;            /**< Class ID or RTE_CLASS_ANY_ID. */\n+\tuint16_t vendor_id;           /**< Vendor ID or PCI_ANY_ID. */\n+\tuint16_t device_id;           /**< Device ID or PCI_ANY_ID. */\n+\tuint16_t subsystem_vendor_id; /**< Subsystem vendor ID or PCI_ANY_ID. */\n+\tuint16_t subsystem_device_id; /**< Subsystem device ID or PCI_ANY_ID. */\n+} opae_pci_id;\n+\n+typedef struct {\n+\tuint32_t domain;              /**< Device domain */\n+\tuint8_t bus;                  /**< Device bus */\n+\tuint8_t devid;                /**< Device ID */\n+\tuint8_t function;             /**< Device function. */\n+} opae_pci_addr;\n+\n+typedef struct {\n+\tchar pci_addr[OPAE_NAME_SIZE];  /* segment:bus:device.function */\n+\tchar drv_name[OPAE_NAME_SIZE];  /* vfio-pci, intel-fpga-pci, etc. */\n+\topae_pci_id id;\n+\topae_pci_addr addr;\n+} opae_pci_property;\n+\n+#define BIT_SET_8   0xFF\n+#define BIT_SET_16  0xFFFF\n+#define BIT_SET_32  0xFFFFFFFF\n+\n+typedef struct {\n+\tuint8_t b[16];\n+} opae_uuid;\n+\n+typedef struct {\n+\tuint32_t boot_page;\n+\tuint32_t num_ports;\n+\tuint64_t bitstream_id;\n+\tuint64_t bitstream_metadata;\n+\topae_uuid pr_id;\n+\tchar platform_name[OPAE_NAME_SIZE];\n+\tchar dcp_version[OPAE_NAME_SIZE];\n+\tchar release_name[OPAE_NAME_SIZE];\n+\tchar interface_type[OPAE_NAME_SIZE];\n+\tchar build_version[OPAE_NAME_SIZE];\n+} opae_fme_property;\n+\n+typedef struct {\n+\topae_uuid afu_id;\n+\tuint32_t type;   /* AFU memory access control type */\n+\tuint32_t index;  /* PORT index */\n+} opae_port_property;\n+\n+typedef struct {\n+\tchar bmc_version[OPAE_NAME_SIZE];\n+\tchar fw_version[OPAE_NAME_SIZE];\n+} opae_bmc_property;\n+\n+typedef struct {\n+\tuint32_t num_retimers;\n+\tuint32_t link_speed;\n+\tuint32_t link_status;  /* each bit corresponding to one link status */\n+} opae_phy_info;\n+\n+typedef struct {\n+\tunion {\n+\t\tuint64_t id;\n+\t\tstruct {\n+\t\t\tuint8_t build_patch;\n+\t\t\tuint8_t build_minor;\n+\t\t\tuint8_t build_major;\n+\t\t\tuint8_t fvl_bypass:1;\n+\t\t\tuint8_t mac_lightweight:1;\n+\t\t\tuint8_t disagregate:1;\n+\t\t\tuint8_t lightweiht:1;\n+\t\t\tuint8_t seu:1;\n+\t\t\tuint8_t ptp:1;\n+\t\t\tuint8_t reserve:2;\n+\t\t\tuint16_t interface:4;\n+\t\t\tuint16_t afu_revision:12;\n+\t\t\tuint16_t patch:4;\n+\t\t\tuint16_t minor:4;\n+\t\t\tuint16_t major:4;\n+\t\t\tuint16_t reserved:4;\n+\t\t};\n+\t};\n+} opae_bitstream_id;\n+\n+typedef struct {\n+\tunion {\n+\t\tuint32_t version;\n+\t\tstruct {\n+\t\t\tuint8_t micro;\n+\t\t\tuint8_t minor;\n+\t\t\tuint8_t major;\n+\t\t\tuint8_t board;\n+\t\t};\n+\t};\n+} opae_bmc_version;\n+\n+#define OPAE_MAX_PORT_NUM   4\n+\n+#define OPAE_PROP_PCI   0x01\n+#define OPAE_PROP_FME   0x02\n+#define OPAE_PROP_PORT  0x04\n+#define OPAE_PROP_BMC   0x08\n+#define OPAE_PROP_ALL   \\\n+\t(OPAE_PROP_PCI | OPAE_PROP_FME | OPAE_PROP_PORT | OPAE_PROP_BMC)\n+\n+typedef struct {\n+\topae_pci_property pci;\n+\topae_fme_property fme;\n+\topae_port_property port[OPAE_MAX_PORT_NUM];\n+\topae_bmc_property bmc;\n+} opae_fpga_property;\n+\n+typedef struct {\n+\tuint64_t guid_h;\n+\tuint64_t guid_l;\n+\tuint32_t metadata_len;\n+} gbs_header;\n+\n+#define OPAE_IMG_TYPE_BBS       0\n+#define OPAE_IMG_TYPE_BMC       1\n+#define OPAE_IMG_TYPE_GBS       2\n+#define OPAE_IMG_TYPE(t)        ((t) & 0xff)\n+\n+#define OPAE_IMG_SUBTYPE_UPDATE             0\n+#define OPAE_IMG_SUBTYPE_CANCELLATION       1\n+#define OPAE_IMG_SUBTYPE_ROOT_KEY_HASH_256  2\n+#define OPAE_IMG_SUBTYPE_ROOT_KEY_HASH_384  3\n+#define OPAE_IMG_SUBTYPE(t)     (((t) >> 8) & 0xff)\n+\n+#define OPAE_IMG_BLK0_SIZE      128\n+#define OPAE_IMG_BLK0_MAGIC     0xb6eafd19\n+#define OPAE_IMG_BLK1_SIZE      896\n+#define OPAE_IMG_HDR_SIZE   (OPAE_IMG_BLK0_SIZE + OPAE_IMG_BLK1_SIZE)\n+#define OPAE_IMG_PL_MIN_SIZE    128\n+\n+typedef struct {\n+\tuint32_t magic;\n+\tuint32_t payload_len;\n+\tuint32_t payload_type;\n+} opae_img_hdr;\n+\n+typedef struct {\n+\tint type;\n+\tint subtype;\n+\tuint32_t total_len;\n+\tuint32_t payload_offset;\n+\tuint32_t payload_len;\n+} opae_img_info;\n+\n+void opae_get_api_version(opae_api_version *version);\n+void opae_check_pcidev_list(void);\n+int opae_set_log_level(int level);\n+int opae_set_log_file(char *path, int clean);\n+int opae_get_proc_type(void);\n+int opae_get_parent(pcidev_id id, pcidev_id parent);\n+int opae_get_child(pcidev_id id, pcidev_id child, int size);\n+int opae_get_pf1(pcidev_id id, pcidev_id peer, int size);\n+int opae_init_eal(int argc, char **argv);\n+int opae_cleanup_eal(void);\n+int opae_enumerate(opae_pci_id *filter, pcidev_id list, int size);\n+int opae_probe_device(pcidev_id id);\n+int opae_remove_device(pcidev_id id);\n+int opae_unbind_driver(pcidev_id id);\n+int opae_bind_driver(pcidev_id id, char *drv_name);\n+int opae_get_property(pcidev_id id, opae_fpga_property *prop, int type);\n+int opae_get_phy_info(pcidev_id id, opae_phy_info *info);\n+int opae_partial_reconfigure(pcidev_id id, int port, const char *gbs);\n+int opae_get_image_info(const char *image, opae_img_info *info);\n+int opae_cancel_flash_update(pcidev_id id, int force);\n+int opae_update_flash(pcidev_id id, const char *image, uint64_t *status);\n+int opae_reboot_device(pcidev_id id, int type, int page);\n+int opae_store_rsu_status(pcidev_id id, uint32_t status, uint32_t progress);\n+int opae_load_rsu_status(pcidev_id id, uint32_t *status, uint32_t *progress);\n+int opae_read_pci_cfg(pcidev_id id, uint32_t address, uint32_t *value);\n+int opae_write_pci_cfg(pcidev_id id, uint32_t address, uint32_t value);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+\n+#endif  /* _OPAE_API_H */\ndiff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c\nindex 8dd566e44..64ed9903e 100644\n--- a/drivers/raw/ifpga/ifpga_rawdev.c\n+++ b/drivers/raw/ifpga/ifpga_rawdev.c\n@@ -1738,6 +1738,79 @@ RTE_PMD_REGISTER_PARAM_STRING(ifpga_rawdev_cfg,\n \t\"port=<int> \"\n \t\"afu_bts=<path>\");\n \n+struct rte_pci_bus *ifpga_get_pci_bus(void)\n+{\n+\treturn rte_ifpga_rawdev_pmd.bus;\n+}\n+\n+int ifpga_rawdev_lock(struct rte_rawdev *dev)\n+{\n+\tif (!dev) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"rawdev is invalid\");\n+\t\treturn -EINVAL;\n+\t}\n+\treturn opae_adapter_lock(ifpga_rawdev_get_priv(dev), -1);\n+}\n+\n+int ifpga_rawdev_unlock(struct rte_rawdev *dev)\n+{\n+\tif (!dev) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"rawdev is invalid\");\n+\t\treturn -EINVAL;\n+\t}\n+\treturn opae_adapter_unlock(ifpga_rawdev_get_priv(dev));\n+}\n+\n+uint32_t ifpga_rawdev_get_rsu_stat(struct rte_rawdev *dev)\n+{\n+\tstruct opae_adapter *adapter = NULL;\n+\topae_share_data *sd = NULL;\n+\n+\tif (!dev) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"rawdev is invalid\");\n+\t\treturn 0;\n+\t}\n+\n+\tadapter = ifpga_rawdev_get_priv(dev);\n+\tif (!adapter) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"adapter is invalid\");\n+\t\treturn 0;\n+\t}\n+\n+\tsd = (opae_share_data *)adapter->shm.ptr;\n+\tif (!sd) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"shared memory is invalid\");\n+\t\treturn 0;\n+\t}\n+\n+\treturn sd->rsu_stat;\n+}\n+\n+void ifpga_rawdev_set_rsu_stat(struct rte_rawdev *dev, uint32_t value)\n+{\n+\tstruct opae_adapter *adapter = NULL;\n+\topae_share_data *sd = NULL;\n+\n+\tif (!dev) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"rawdev is invalid\");\n+\t\treturn;\n+\t}\n+\n+\tadapter = ifpga_rawdev_get_priv(dev);\n+\tif (!adapter) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"adapter is invalid\");\n+\t\treturn;\n+\t}\n+\n+\tsd = (opae_share_data *)adapter->shm.ptr;\n+\tif (!sd) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"shared memory is invalid\");\n+\t\treturn;\n+\t}\n+\n+\tsd->rsu_stat = value;\n+}\n+\n int ifpga_rawdev_get_fme_property(struct rte_rawdev *dev,\n \tifpga_fme_property *prop)\n {\n@@ -1748,8 +1821,8 @@ int ifpga_rawdev_get_fme_property(struct rte_rawdev *dev,\n \tstruct uuid pr_id;\n \tint ret = 0;\n \n-\tif (!dev) {\n-\t\tIFPGA_RAWDEV_PMD_ERR(\"rawdev is invalid\");\n+\tif (!dev || !prop) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"Input parameter is invalid\");\n \t\treturn -EINVAL;\n \t}\n \n@@ -1820,8 +1893,8 @@ int ifpga_rawdev_get_port_property(struct rte_rawdev *dev, uint32_t port,\n \tstruct uuid afu_id;\n \tint ret = 0;\n \n-\tif (!dev) {\n-\t\tIFPGA_RAWDEV_PMD_ERR(\"rawdev is invalid\");\n+\tif (!dev || !prop) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"Input parameter is invalid\");\n \t\treturn -EINVAL;\n \t}\n \n@@ -1867,8 +1940,8 @@ int ifpga_rawdev_get_bmc_property(struct rte_rawdev *dev,\n \tstruct opae_board_info *info = NULL;\n \tint ret = 0;\n \n-\tif (!dev) {\n-\t\tIFPGA_RAWDEV_PMD_ERR(\"rawdev is invalid\");\n+\tif (!dev || !prop) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"Input parameter is invalid\");\n \t\treturn -EINVAL;\n \t}\n \n@@ -1895,6 +1968,48 @@ int ifpga_rawdev_get_bmc_property(struct rte_rawdev *dev,\n \treturn 0;\n }\n \n+int ifpga_rawdev_get_phy_info(struct rte_rawdev *dev, ifpga_phy_info *info)\n+{\n+\tstruct opae_adapter *adapter = NULL;\n+\tstruct opae_retimer_info rtm_info;\n+\tstruct opae_retimer_status rtm_status;\n+\tint ret = 0;\n+\n+\tif (!dev || !info) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"Input parameter is invalid\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tadapter = ifpga_rawdev_get_priv(dev);\n+\tif (!adapter) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"adapter is invalid\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tif (!adapter->mgr) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"manager is invalid\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tret = opae_manager_get_retimer_info(adapter->mgr, &rtm_info);\n+\tif (ret) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"Failed to get retimer info\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = opae_manager_get_retimer_status(adapter->mgr, &rtm_status);\n+\tif (ret) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"Failed to get retimer status\");\n+\t\treturn ret;\n+\t}\n+\n+\tinfo->num_retimers = rtm_info.nums_retimer;\n+\tinfo->link_speed = rtm_status.speed;\n+\tinfo->link_status = rtm_status.line_link_bitmap;\n+\n+\treturn 0;\n+}\n+\n int ifpga_rawdev_update_flash(struct rte_rawdev *dev, const char *image,\n \tuint64_t *status)\n {\n@@ -1949,3 +2064,28 @@ int ifpga_rawdev_reload(struct rte_rawdev *dev, int type, int page)\n \n \treturn opae_mgr_reload(adapter->mgr, type, page);\n }\n+\n+int ifpga_rawdev_partial_reconfigure(struct rte_rawdev *dev, int port,\n+\tconst char *file)\n+{\n+\tif (!dev) {\n+\t\tIFPGA_RAWDEV_PMD_ERR(\"rawdev is invalid\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn rte_fpga_do_pr(dev, port, file);\n+}\n+\n+void ifpga_rawdev_cleanup(void)\n+{\n+\tstruct ifpga_rawdev *dev;\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < IFPGA_RAWDEV_NUM; i++) {\n+\t\tdev = &ifpga_rawdevices[i];\n+\t\tif (dev->rawdev) {\n+\t\t\trte_rawdev_pmd_release(dev->rawdev);\n+\t\t\tdev->rawdev = NULL;\n+\t\t}\n+\t}\n+}\ndiff --git a/drivers/raw/ifpga/ifpga_rawdev.h b/drivers/raw/ifpga/ifpga_rawdev.h\nindex d4be7913d..185e79071 100644\n--- a/drivers/raw/ifpga/ifpga_rawdev.h\n+++ b/drivers/raw/ifpga/ifpga_rawdev.h\n@@ -89,6 +89,12 @@ typedef struct {\n \tuint32_t fw_version;\n } ifpga_bmc_property;\n \n+typedef struct {\n+\tuint32_t num_retimers;\n+\tuint32_t link_speed;\n+\tuint32_t link_status;\n+} ifpga_phy_info;\n+\n int\n ifpga_register_msix_irq(struct rte_rawdev *dev, int port_id,\n \t\tenum ifpga_irq_type type, int vec_start, int count,\n@@ -98,15 +104,24 @@ int\n ifpga_unregister_msix_irq(enum ifpga_irq_type type,\n \t\tint vec_start, rte_intr_callback_fn handler, void *arg);\n \n+struct rte_pci_bus *ifpga_get_pci_bus(void);\n+int ifpga_rawdev_lock(struct rte_rawdev *dev);\n+int ifpga_rawdev_unlock(struct rte_rawdev *dev);\n+uint32_t ifpga_rawdev_get_rsu_stat(struct rte_rawdev *dev);\n+void ifpga_rawdev_set_rsu_stat(struct rte_rawdev *dev, uint32_t value);\n int ifpga_rawdev_get_fme_property(struct rte_rawdev *dev,\n \tifpga_fme_property *prop);\n int ifpga_rawdev_get_port_property(struct rte_rawdev *dev, uint32_t port,\n \tifpga_port_property *prop);\n int ifpga_rawdev_get_bmc_property(struct rte_rawdev *dev,\n \tifpga_bmc_property *prop);\n+int ifpga_rawdev_get_phy_info(struct rte_rawdev *dev, ifpga_phy_info *info);\n int ifpga_rawdev_update_flash(struct rte_rawdev *dev, const char *image,\n \tuint64_t *status);\n int ifpga_rawdev_stop_flash_update(struct rte_rawdev *dev, int force);\n int ifpga_rawdev_reload(struct rte_rawdev *dev, int type, int page);\n+int ifpga_rawdev_partial_reconfigure(struct rte_rawdev *dev, int port,\n+\tconst char *file);\n+void ifpga_rawdev_cleanup(void);\n \n #endif /* _IFPGA_RAWDEV_H_ */\ndiff --git a/drivers/raw/ifpga/meson.build b/drivers/raw/ifpga/meson.build\nindex 027ff8056..417480f19 100644\n--- a/drivers/raw/ifpga/meson.build\n+++ b/drivers/raw/ifpga/meson.build\n@@ -13,8 +13,10 @@ objs = [base_objs]\n deps += ['ethdev', 'rawdev', 'pci', 'bus_pci', 'kvargs',\n \t'bus_vdev', 'bus_ifpga', 'net', 'net_i40e', 'net_ipn3ke']\n \n-sources = files('ifpga_rawdev.c')\n+sources = files('ifpga_rawdev.c', 'ifpga_opae_api.c')\n \n includes += include_directories('base')\n includes += include_directories('../../net/ipn3ke')\n includes += include_directories('../../net/i40e')\n+\n+install_headers('ifpga_opae_api.h')\n",
    "prefixes": [
        "v6",
        "3/4"
    ]
}