get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 111774,
    "url": "https://patches.dpdk.org/api/patches/111774/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1653443483-30971-3-git-send-email-wei.huang@intel.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": "<1653443483-30971-3-git-send-email-wei.huang@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1653443483-30971-3-git-send-email-wei.huang@intel.com",
    "date": "2022-05-25T01:51:23",
    "name": "[v1,2/2] raw/ifpga: update secure rsu",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "fd89c9171ca9e5c2bd7484db8faf8a48bb1ba4ab",
    "submitter": {
        "id": 2033,
        "url": "https://patches.dpdk.org/api/people/2033/?format=api",
        "name": "Wei Huang",
        "email": "wei.huang@intel.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/1653443483-30971-3-git-send-email-wei.huang@intel.com/mbox/",
    "series": [
        {
            "id": 23136,
            "url": "https://patches.dpdk.org/api/series/23136/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=23136",
            "date": "2022-05-25T01:51:21",
            "name": "Update rsu implementation",
            "version": 1,
            "mbox": "https://patches.dpdk.org/series/23136/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/111774/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/111774/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 1E8E0A0545;\n\tWed, 25 May 2022 03:44:41 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 2630B427F3;\n\tWed, 25 May 2022 03:44:30 +0200 (CEST)",
            "from mga01.intel.com (mga01.intel.com [192.55.52.88])\n by mails.dpdk.org (Postfix) with ESMTP id 9836A427F2;\n Wed, 25 May 2022 03:44:27 +0200 (CEST)",
            "from orsmga004.jf.intel.com ([10.7.209.38])\n by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 24 May 2022 18:44:27 -0700",
            "from unknown (HELO zj-fpga-amt.sh.intel.com) ([10.238.175.102])\n by orsmga004.jf.intel.com with ESMTP; 24 May 2022 18:44:24 -0700"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1653443068; x=1684979068;\n h=from:to:cc:subject:date:message-id:in-reply-to: references;\n bh=sBoOCVHlnMTKe1AUXN0xMcYTzeN11sef4J714UW6Y9E=;\n b=VG8C+PZbNvW5c3wEo7bt8l5/3XmvzNIhbYyqUIny8mR7eYFkFoznVbuo\n 8C5b2VcsO7GVloXJChFsVOHr2CZB4MHTcNpFqXLRApqPNcEesl0NwOo9C\n gqhxWy/lhzHpmHQWfy+ika+Q5T6ifEAtN1ZlJ4eZzZjIDuXxI/BUQ7k8Z\n ejSLrI3maIBWaBb3ttzxJvJhY+6AtaoWzcC3dEOQYC4wGYkqQcEMsisxx\n +7XhYXEh1tgJhcUPYY2c/xio9/lYDNjlqK/0FcsyDEFP4zUfJn5yEnjCs\n X6fHLVO9mNVf3CTO/t4hYeUgsdyV2pS76IlNbf+c/Qbh1ozgjR77+JtCT w==;",
        "X-IronPort-AV": [
            "E=McAfee;i=\"6400,9594,10357\"; a=\"299019362\"",
            "E=Sophos;i=\"5.91,250,1647327600\"; d=\"scan'208\";a=\"299019362\"",
            "E=Sophos;i=\"5.91,250,1647327600\"; d=\"scan'208\";a=\"703705957\""
        ],
        "X-ExtLoop1": "1",
        "From": "Wei Huang <wei.huang@intel.com>",
        "To": "dev@dpdk.org, thomas@monjalon.net, nipun.gupta@nxp.com,\n hemant.agrawal@nxp.com",
        "Cc": "stable@dpdk.org, rosen.xu@intel.com, tianfei.zhang@intel.com,\n qi.z.zhang@intel.com, Wei Huang <wei.huang@intel.com>",
        "Subject": "[PATCH v1 2/2] raw/ifpga: update secure rsu",
        "Date": "Tue, 24 May 2022 21:51:23 -0400",
        "Message-Id": "<1653443483-30971-3-git-send-email-wei.huang@intel.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1653443483-30971-1-git-send-email-wei.huang@intel.com>",
        "References": "<1653443483-30971-1-git-send-email-wei.huang@intel.com>",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "Update secure RSU (Remote System Update) driver to adapt the changes\nintroduced by OFS.\n\nSigned-off-by: Wei Huang <wei.huang@intel.com>\nAcked-by: Tianfei Zhang <tianfei.zhang@intel.com>\n---\n drivers/raw/ifpga/base/ifpga_api.c         |   39 +-\n drivers/raw/ifpga/base/ifpga_feature_dev.h |    2 +\n drivers/raw/ifpga/base/ifpga_fme.c         |    8 +\n drivers/raw/ifpga/base/ifpga_fme_rsu.c     |  546 ++++++++-----\n drivers/raw/ifpga/base/ifpga_sec_mgr.c     | 1156 ++++++++++++++++++++--------\n drivers/raw/ifpga/base/ifpga_sec_mgr.h     |  115 ++-\n drivers/raw/ifpga/base/opae_hw_api.c       |   84 +-\n drivers/raw/ifpga/base/opae_hw_api.h       |   14 +-\n drivers/raw/ifpga/rte_pmd_ifpga.c          |  104 ++-\n drivers/raw/ifpga/rte_pmd_ifpga.h          |  117 +++\n drivers/raw/ifpga/version.map              |   11 +\n 11 files changed, 1649 insertions(+), 547 deletions(-)",
    "diff": "diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c\nindex f19cc26..c187f94 100644\n--- a/drivers/raw/ifpga/base/ifpga_api.c\n+++ b/drivers/raw/ifpga/base/ifpga_api.c\n@@ -261,11 +261,42 @@ static int ifpga_mgr_stop_flash_update(struct opae_manager *mgr, int force)\n \treturn fpga_stop_flash_update(fme, force);\n }\n \n-static int ifpga_mgr_reload(struct opae_manager *mgr, int type, int page)\n+static int ifpga_mgr_reload(struct opae_manager *mgr, char *str)\n {\n \tstruct ifpga_fme_hw *fme = mgr->data;\n \n-\treturn fpga_reload(fme, type, page);\n+\treturn fpga_reload(fme, str);\n+}\n+\n+static int ifpga_available_images(struct opae_manager *mgr, char *buf,\n+\tsize_t size)\n+{\n+\tstruct ifpga_fme_hw *fme = mgr->data;\n+\n+\treturn fpga_available_images(fme, buf, size);\n+}\n+\n+static int ifpga_mgr_set_poc_image(struct opae_manager *mgr, char *str)\n+{\n+\tstruct ifpga_fme_hw *fme = mgr->data;\n+\n+\treturn fpga_set_poc_image(fme, str);\n+}\n+\n+static int ifpga_mgr_get_poc_images(struct opae_manager *mgr, char *buf,\n+\tsize_t size)\n+{\n+\tstruct ifpga_fme_hw *fme = mgr->data;\n+\n+\treturn fpga_get_poc_images(fme, buf, size);\n+}\n+\n+static int ifpga_mgr_read_flash(struct opae_manager *mgr, u32 address,\n+\t\tu32 size, void *buf)\n+{\n+\tstruct ifpga_fme_hw *fme = mgr->data;\n+\n+\treturn fme_mgr_read_flash(fme, address, size, buf);\n }\n \n struct opae_manager_ops ifpga_mgr_ops = {\n@@ -277,6 +308,10 @@ struct opae_manager_ops ifpga_mgr_ops = {\n \t.update_flash = ifpga_mgr_update_flash,\n \t.stop_flash_update = ifpga_mgr_stop_flash_update,\n \t.reload = ifpga_mgr_reload,\n+\t.available_images = ifpga_available_images,\n+\t.get_poc_images = ifpga_mgr_get_poc_images,\n+\t.set_poc_image = ifpga_mgr_set_poc_image,\n+\t.read_flash = ifpga_mgr_read_flash\n };\n \n static int ifpga_mgr_read_mac_rom(struct opae_manager *mgr, int offset,\ndiff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.h b/drivers/raw/ifpga/base/ifpga_feature_dev.h\nindex a637eb5..7a2f2e5 100644\n--- a/drivers/raw/ifpga/base/ifpga_feature_dev.h\n+++ b/drivers/raw/ifpga/base/ifpga_feature_dev.h\n@@ -223,4 +223,6 @@ int fme_mgr_get_retimer_status(struct ifpga_fme_hw *fme,\n int fme_mgr_get_sensor_value(struct ifpga_fme_hw *fme,\n \t\tstruct opae_sensor_info *sensor,\n \t\tunsigned int *value);\n+int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address,\n+\t\tu32 size, void *buf);\n #endif /* _IFPGA_FEATURE_DEV_H_ */\ndiff --git a/drivers/raw/ifpga/base/ifpga_fme.c b/drivers/raw/ifpga/base/ifpga_fme.c\nindex 1b9a922..1f54680 100644\n--- a/drivers/raw/ifpga/base/ifpga_fme.c\n+++ b/drivers/raw/ifpga/base/ifpga_fme.c\n@@ -1658,3 +1658,11 @@ struct ifpga_feature_ops fme_pmci_ops = {\n \t.init = fme_pmci_init,\n \t.uinit = fme_pmci_uinit,\n };\n+\n+int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address,\n+\t\tu32 size, void *buf)\n+{\n+\tstruct intel_max10_device *max10 = fme->max10_dev;\n+\n+\treturn opae_read_flash(max10, address, size, buf);\n+}\ndiff --git a/drivers/raw/ifpga/base/ifpga_fme_rsu.c b/drivers/raw/ifpga/base/ifpga_fme_rsu.c\nindex f147aaa..88a19fa 100644\n--- a/drivers/raw/ifpga/base/ifpga_fme_rsu.c\n+++ b/drivers/raw/ifpga/base/ifpga_fme_rsu.c\n@@ -9,6 +9,28 @@\n \n static struct ifpga_sec_mgr *sec_mgr;\n \n+static void lock(struct ifpga_sec_mgr *smgr)\n+{\n+\tstruct ifpga_hw *hw = NULL;\n+\n+\tif (smgr && smgr->fme) {\n+\t\thw = (struct ifpga_hw *)smgr->fme->parent;\n+\t\tif (hw)\n+\t\t\topae_adapter_lock(hw->adapter, -1);\n+\t}\n+}\n+\n+static void unlock(struct ifpga_sec_mgr *smgr)\n+{\n+\tstruct ifpga_hw *hw = NULL;\n+\n+\tif (smgr && smgr->fme) {\n+\t\thw = (struct ifpga_hw *)smgr->fme->parent;\n+\t\tif (hw)\n+\t\t\topae_adapter_unlock(hw->adapter);\n+\t}\n+}\n+\n static void set_rsu_control(struct ifpga_sec_mgr *smgr, uint32_t ctrl)\n {\n \tif (smgr && smgr->rsu_control)\n@@ -22,6 +44,16 @@ static uint32_t get_rsu_control(struct ifpga_sec_mgr *smgr)\n \treturn 0;\n }\n \n+static void cancel_rsu(struct ifpga_sec_mgr *smgr)\n+{\n+\tuint32_t ctrl = IFPGA_RSU_CANCEL;\n+\n+\tlock(smgr);\n+\tctrl |= get_rsu_control(smgr);\n+\tset_rsu_control(smgr, ctrl);\n+\tunlock(smgr);\n+}\n+\n static void set_rsu_status(struct ifpga_sec_mgr *smgr, uint32_t status,\n \tuint32_t progress)\n {\n@@ -40,6 +72,26 @@ static void get_rsu_status(struct ifpga_sec_mgr *smgr, uint32_t *status,\n \t}\n }\n \n+static void update_rsu_stat(struct ifpga_sec_mgr *smgr, uint32_t stat)\n+{\n+\tuint32_t prog = 0;\n+\n+\tlock(smgr);\n+\tget_rsu_status(smgr, NULL, &prog);\n+\tset_rsu_status(smgr, stat, prog);\n+\tunlock(smgr);\n+}\n+\n+static void update_rsu_prog(struct ifpga_sec_mgr *smgr, uint32_t prog)\n+{\n+\tuint32_t stat = 0;\n+\n+\tlock(smgr);\n+\tget_rsu_status(smgr, &stat, NULL);\n+\tset_rsu_status(smgr, stat, prog);\n+\tunlock(smgr);\n+}\n+\n static void sig_handler(int sig, siginfo_t *info, void *data)\n {\n \t(void)(info);\n@@ -50,7 +102,7 @@ static void sig_handler(int sig, siginfo_t *info, void *data)\n \t\tif (sec_mgr) {\n \t\t\tdev_info(sec_mgr, \"Interrupt secure flash update\"\n \t\t\t\t\" by keyboard\\n\");\n-\t\t\tset_rsu_control(sec_mgr, IFPGA_RSU_ABORT);\n+\t\t\tcancel_rsu(sec_mgr);\n \t\t}\n \t\tbreak;\n \tdefault:\n@@ -77,149 +129,152 @@ static void log_time(time_t t, const char *msg)\n \tprintf(\"%s - %02u:%02u:%02u\\n\", msg, h, m, s);\n }\n \n-static int start_flash_update(struct ifpga_sec_mgr *smgr)\n+static enum ifpga_sec_err fpga_sec_dev_prepare(struct ifpga_sec_mgr *smgr)\n {\n \tif (!smgr)\n-\t\treturn -ENODEV;\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \n-\tif (!smgr->ops || !smgr->ops->prepare)\n-\t\treturn -EINVAL;\n+\tif (!smgr->sops || !smgr->sops->prepare)\n+\t\treturn IFPGA_SEC_ERR_NO_FUNC;\n+\n+\treturn smgr->sops->prepare(smgr);\n+}\n+\n+static int fill_buf(int fd, uint32_t offset, void *buf, uint32_t size)\n+{\n+\tssize_t read_size = 0;\n+\n+\tif (lseek(fd, offset, SEEK_SET) < 0)\n+\t\treturn -EIO;\n+\n+\tread_size = read(fd, buf, size);\n+\tif (read_size < 0)\n+\t\treturn -EIO;\n \n-\treturn smgr->ops->prepare(smgr);\n+\tif ((uint32_t)read_size != size) {\n+\t\tdev_err(smgr,\n+\t\t\t\"Read length %zd is not expected [e:%u]\\n\",\n+\t\t\tread_size, size);\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n }\n \n-static int write_flash_image(struct ifpga_sec_mgr *smgr, const char *image,\n-\tuint32_t offset)\n+static enum ifpga_sec_err fpga_sec_dev_write(struct ifpga_sec_mgr *smgr)\n {\n \tvoid *buf = NULL;\n-\tint retry = 0;\n-\tuint32_t length = 0;\n-\tuint32_t to_transfer = 0;\n-\tuint32_t one_percent = 0;\n+\tint fd = -1;\n+\tuint32_t blk_size = 0;\n+\tuint32_t offset = 0;\n \tuint32_t prog = 0;\n \tuint32_t old_prog = -1;\n-\tssize_t read_size = 0;\n-\tint fd = -1;\n-\tint ret = 0;\n+\tenum ifpga_sec_err ret = 0;\n \n \tif (!smgr)\n-\t\treturn -ENODEV;\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \n-\tif (!smgr->ops || !smgr->ops->write_blk)\n-\t\treturn -EINVAL;\n+\tif (!smgr->sops || !smgr->sops->write_blk)\n+\t\treturn IFPGA_SEC_ERR_NO_FUNC;\n+\n+\tbuf = malloc(IFPGA_RSU_DATA_BLK_SIZE);\n+\tif (!buf) {\n+\t\tdev_err(smgr, \"Failed to allocate memory for flash update\\n\");\n+\t\treturn IFPGA_SEC_ERR_NO_MEM;\n+\t}\n+\tsmgr->data = buf;\n \n-\tfd = open(image, O_RDONLY);\n+\tfd = open(smgr->filename, O_RDONLY);\n \tif (fd < 0) {\n \t\tdev_err(smgr,\n \t\t\t\"Failed to open \\'%s\\' for RD [e:%s]\\n\",\n-\t\t\timage, strerror(errno));\n-\t\treturn -EIO;\n+\t\t\tsmgr->filename, strerror(errno));\n+\t\treturn IFPGA_SEC_ERR_FILE_READ;\n \t}\n \n-\tbuf = malloc(IFPGA_RSU_DATA_BLK_SIZE);\n-\tif (!buf) {\n-\t\tdev_err(smgr, \"Failed to allocate memory for flash update\\n\");\n-\t\tclose(fd);\n-\t\treturn -ENOMEM;\n-\t}\n-\n-\tlength = smgr->rsu_length;\n-\tone_percent = length / 100;\n-\tdo {\n-\t\tto_transfer = (length > IFPGA_RSU_DATA_BLK_SIZE) ?\n-\t\t\tIFPGA_RSU_DATA_BLK_SIZE : length;\n-\t\tif (lseek(fd, offset, SEEK_SET) < 0) {\n-\t\t\tdev_err(smgr, \"Failed to seek in \\'%s\\' [e:%s]\\n\",\n-\t\t\t\timage, strerror(errno));\n-\t\t\tret = -EIO;\n-\t\t\tgoto end;\n-\t\t}\n-\t\tread_size = read(fd, buf, to_transfer);\n-\t\tif (read_size < 0) {\n-\t\t\tdev_err(smgr, \"Failed to read from \\'%s\\' [e:%s]\\n\",\n-\t\t\t\timage, strerror(errno));\n-\t\t\tret = -EIO;\n-\t\t\tgoto end;\n-\t\t}\n-\t\tif ((uint32_t)read_size != to_transfer) {\n-\t\t\tdev_err(smgr,\n-\t\t\t\t\"Read length %zd is not expected [e:%u]\\n\",\n-\t\t\t\tread_size, to_transfer);\n-\t\t\tret = -EIO;\n-\t\t\tgoto end;\n+\twhile (smgr->remaining_size) {\n+\t\tif (get_rsu_control(smgr) & IFPGA_RSU_CANCEL) {\n+\t\t\tret = IFPGA_SEC_ERR_CANCELED;\n+\t\t\tbreak;\n \t\t}\n \n-\t\tretry = 0;\n-\t\tdo {\n-\t\t\tif (get_rsu_control(smgr) == IFPGA_RSU_ABORT) {\n-\t\t\t\tret = -EAGAIN;\n-\t\t\t\tgoto end;\n-\t\t\t}\n-\t\t\tret = smgr->ops->write_blk(smgr, buf, offset,\n-\t\t\t\tto_transfer);\n-\t\t\tif (ret == 0)\n-\t\t\t\tbreak;\n-\t\t\tsleep(1);\n-\t\t} while (++retry <= IFPGA_RSU_WRITE_RETRY);\n-\t\tif (retry > IFPGA_RSU_WRITE_RETRY) {\n-\t\t\tdev_err(smgr, \"Failed to write to staging area 0x%x\\n\",\n-\t\t\t\toffset);\n-\t\t\tret = -EAGAIN;\n-\t\t\tgoto end;\n+\t\tblk_size = (smgr->remaining_size > IFPGA_RSU_DATA_BLK_SIZE) ?\n+\t\t\tIFPGA_RSU_DATA_BLK_SIZE : smgr->remaining_size;\n+\t\tif (fill_buf(fd, offset, buf, blk_size)) {\n+\t\t\tret = IFPGA_SEC_ERR_FILE_READ;\n+\t\t\tbreak;\n \t\t}\n \n-\t\tlength -= to_transfer;\n-\t\toffset += to_transfer;\n-\t\tprog = offset / one_percent;\n+\t\tret = smgr->sops->write_blk(smgr, offset, blk_size);\n+\t\tif (ret != IFPGA_SEC_ERR_NONE)\n+\t\t\tbreak;\n+\n+\t\tsmgr->remaining_size -= blk_size;\n+\t\toffset += blk_size;\n+\n+\t\t/* output progress percent */\n+\t\tprog = offset / smgr->one_percent;\n \t\tif (prog != old_prog) {\n \t\t\tprintf(\"\\r%d%%\", prog);\n \t\t\tfflush(stdout);\n-\t\t\tset_rsu_status(smgr, IFPGA_RSU_READY, prog);\n+\t\t\tupdate_rsu_prog(smgr, prog);\n \t\t\told_prog = prog;\n \t\t}\n-\t} while (length > 0);\n-\tset_rsu_status(smgr, IFPGA_RSU_READY, 100);\n-\tprintf(\"\\n\");\n+\t}\n+\n+\tif (ret == IFPGA_SEC_ERR_NONE) {\n+\t\tupdate_rsu_prog(smgr, 100);\n+\t\tprintf(\"\\r100%%\\n\");\n+\t} else {\n+\t\tprintf(\"\\n\");\n+\t}\n \n-end:\n-\tfree(buf);\n \tclose(fd);\n+\tsmgr->data = NULL;\n+\tfree(buf);\n \treturn ret;\n }\n \n-static int apply_flash_update(struct ifpga_sec_mgr *smgr)\n+static enum ifpga_sec_err fpga_sec_dev_poll_complete(struct ifpga_sec_mgr *smgr)\n {\n-\tuint32_t one_percent = 0;\n \tuint32_t one_percent_time = 0;\n \tuint32_t prog = 0;\n \tuint32_t old_prog = -1;\n \tuint32_t copy_time = 0;\n-\tint ret = 0;\n+\tint timeout = 2400;   /* 2400 seconds */\n+\tenum ifpga_sec_err ret = 0;\n \n \tif (!smgr)\n-\t\treturn -ENODEV;\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \n-\tif (!smgr->ops || !smgr->ops->write_done || !smgr->ops->check_complete)\n-\t\treturn -EINVAL;\n+\tif (!smgr->sops || !smgr->sops->write_done ||\n+\t\t!smgr->sops->check_complete)\n+\t\treturn IFPGA_SEC_ERR_NO_FUNC;\n \n-\tif (smgr->ops->write_done(smgr) < 0) {\n+\tif (smgr->sops->write_done(smgr) != IFPGA_SEC_ERR_NONE) {\n \t\tdev_err(smgr, \"Failed to apply flash update\\n\");\n-\t\treturn -EAGAIN;\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \t}\n \n-\tone_percent = (smgr->rsu_length + 99) / 100;\n+\t/* calculate time period of one percent */\n \tif (smgr->copy_speed == 0)   /* avoid zero divide fault */\n \t\tsmgr->copy_speed = 1;\n-\tone_percent_time = (one_percent + smgr->copy_speed - 1) /\n+\tone_percent_time = (smgr->one_percent + smgr->copy_speed) /\n \t\tsmgr->copy_speed;\n \tif (one_percent_time == 0)   /* avoid zero divide fault */\n \t\tone_percent_time = 1;\n \n-\tdo {\n-\t\tret = smgr->ops->check_complete(smgr);\n-\t\tif (ret != -EAGAIN)\n-\t\t\tbreak;\n+\twhile (true) {\n \t\tsleep(1);\n+\t\tret = smgr->sops->check_complete(smgr);\n+\t\tif (ret != IFPGA_SEC_ERR_BUSY)\n+\t\t\tbreak;\n+\t\tif (--timeout < 0) {\n+\t\t\tret = IFPGA_SEC_ERR_TIMEOUT;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* output progress percent */\n \t\tcopy_time += 1;\n \t\tprog = copy_time / one_percent_time;\n \t\tif (prog >= 100)\n@@ -227,96 +282,90 @@ static int apply_flash_update(struct ifpga_sec_mgr *smgr)\n \t\tif (prog != old_prog) {\n \t\t\tprintf(\"\\r%d%%\", prog);\n \t\t\tfflush(stdout);\n-\t\t\tset_rsu_status(smgr, IFPGA_RSU_COPYING, prog);\n+\t\t\tupdate_rsu_prog(smgr, prog);\n \t\t\told_prog = prog;\n \t\t}\n-\t} while (true);\n+\t}\n \n-\tif (ret < 0) {\n-\t\tprintf(\"\\n\");\n-\t\tdev_err(smgr, \"Failed to complete secure flash update\\n\");\n-\t} else {\n+\tif (ret == IFPGA_SEC_ERR_NONE) {\n+\t\tupdate_rsu_prog(smgr, 100);\n \t\tprintf(\"\\r100%%\\n\");\n-\t\tset_rsu_status(smgr, IFPGA_RSU_COPYING, 100);\n+\t} else {\n+\t\tprintf(\"\\n\");\n \t}\n \n \treturn ret;\n }\n \n-static int secure_update_cancel(struct ifpga_sec_mgr *smgr)\n+static enum ifpga_sec_err fpga_sec_dev_cancel(struct ifpga_sec_mgr *smgr)\n {\n \tif (!smgr)\n-\t\treturn -ENODEV;\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \n-\tif (!smgr->ops || !smgr->ops->cancel)\n-\t\treturn -EINVAL;\n+\tif (!smgr->sops || !smgr->sops->cancel)\n+\t\treturn IFPGA_SEC_ERR_NO_FUNC;\n \n-\treturn smgr->ops->cancel(smgr);\n+\treturn smgr->sops->cancel(smgr);\n }\n \n-static int secure_update_status(struct ifpga_sec_mgr *smgr, uint64_t *status)\n+static void set_error(struct ifpga_sec_mgr *smgr, enum ifpga_sec_err err_code)\n {\n-\tif (!smgr)\n-\t\treturn -ENODEV;\n+\tuint32_t stat = 0;\n \n-\tif (!smgr->ops || !smgr->ops->get_hw_errinfo)\n-\t\treturn -EINVAL;\n+\tlock(smgr);\n+\tget_rsu_status(smgr, &stat, NULL);\n+\tset_rsu_status(smgr, stat, stat);\n+\tsmgr->err_code = err_code;\n+\tunlock(smgr);\n+}\n \n-\tif (status)\n-\t\t*status = smgr->ops->get_hw_errinfo(smgr);\n+static int progress_transition(struct ifpga_sec_mgr *smgr,\n+\tuint32_t new_progress)\n+{\n+\tif (get_rsu_control(smgr) & IFPGA_RSU_CANCEL) {\n+\t\tset_error(smgr, IFPGA_SEC_ERR_CANCELED);\n+\t\tsmgr->sops->cancel(smgr);\n+\t\treturn -ECANCELED;\n+\t}\n \n+\tset_rsu_status(smgr, new_progress, 0);\n \treturn 0;\n }\n \n-int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image,\n-\tuint64_t *status)\n+static void progress_complete(struct ifpga_sec_mgr *smgr)\n+{\n+\tupdate_rsu_stat(smgr, IFPGA_RSU_IDLE);\n+}\n+\n+static void fpga_sec_dev_error(struct ifpga_sec_mgr *smgr,\n+\tenum ifpga_sec_err err_code)\n+{\n+\tset_error(smgr, err_code);\n+\tif (smgr->sops->get_hw_errinfo)\n+\t\tsmgr->hw_errinfo = smgr->sops->get_hw_errinfo(smgr);\n+\tif (smgr->sops->cancel)\n+\t\tsmgr->sops->cancel(smgr);\n+}\n+\n+static int fpga_sec_mgr_update(struct ifpga_sec_mgr *smgr)\n {\n-\tstruct ifpga_hw *hw = NULL;\n-\tstruct ifpga_sec_mgr *smgr = NULL;\n-\tuint32_t rsu_stat = 0;\n \tint fd = -1;\n \toff_t len = 0;\n \tstruct sigaction old_sigint_action;\n \tstruct sigaction sa;\n \ttime_t start;\n-\tint ret = 0;\n+\tenum ifpga_sec_err ret = 0;\n \n-\tif (!fme || !image || !status) {\n-\t\tdev_err(fme, \"Input parameter of %s is invalid\\n\", __func__);\n+\tif (!smgr) {\n+\t\tdev_err(smgr, \"Input parameter of %s is invalid\\n\", __func__);\n \t\treturn -EINVAL;\n \t}\n \n-\thw = (struct ifpga_hw *)fme->parent;\n-\tif (!hw) {\n-\t\tdev_err(fme, \"Parent of FME not found\\n\");\n-\t\treturn -ENODEV;\n-\t}\n-\n-\tsmgr = (struct ifpga_sec_mgr *)fme->sec_mgr;\n-\tif (!smgr || !smgr->max10_dev) {\n-\t\tdev_err(smgr, \"Security manager not initialized\\n\");\n-\t\treturn -ENODEV;\n-\t}\n-\n-\topae_adapter_lock(hw->adapter, -1);\n-\tget_rsu_status(smgr, &rsu_stat, NULL);\n-\tif (rsu_stat != IFPGA_RSU_IDLE) {\n-\t\topae_adapter_unlock(hw->adapter);\n-\t\tif (rsu_stat == IFPGA_RSU_REBOOT)\n-\t\t\tdev_info(smgr, \"Reboot is in progress\\n\");\n-\t\telse\n-\t\t\tdev_info(smgr, \"Update is in progress\\n\");\n-\t\treturn -EAGAIN;\n-\t}\n-\tset_rsu_control(smgr, 0);\n-\tset_rsu_status(smgr, IFPGA_RSU_PREPARE, 0);\n-\topae_adapter_unlock(hw->adapter);\n-\n-\tfd = open(image, O_RDONLY);\n+\tfd = open(smgr->filename, O_RDONLY);\n \tif (fd < 0) {\n \t\tdev_err(smgr,\n \t\t\t\"Failed to open \\'%s\\' for RD [e:%s]\\n\",\n-\t\t\timage, strerror(errno));\n+\t\t\tsmgr->filename, strerror(errno));\n \t\treturn -EIO;\n \t}\n \tlen = lseek(fd, 0, SEEK_END);\n@@ -325,25 +374,22 @@ int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image,\n \tif (len < 0) {\n \t\tdev_err(smgr,\n \t\t\t\"Failed to get file length of \\'%s\\' [e:%s]\\n\",\n-\t\t\timage, strerror(errno));\n+\t\t\tsmgr->filename, strerror(errno));\n \t\treturn -EIO;\n \t}\n \tif (len == 0) {\n-\t\tdev_err(smgr, \"Length of file \\'%s\\' is invalid\\n\", image);\n-\t\treturn -EINVAL;\n-\t}\n-\tsmgr->rsu_length = len;\n-\n-\tif (smgr->max10_dev->staging_area_size < smgr->rsu_length) {\n-\t\tdev_err(dev, \"Size of staging area is small than image length \"\n-\t\t\t\"[%u<%u]\\n\", smgr->max10_dev->staging_area_size,\n-\t\t\tsmgr->rsu_length);\n+\t\tdev_err(smgr, \"Length of file \\'%s\\' is invalid\\n\",\n+\t\t\tsmgr->filename);\n+\t\tset_error(smgr, IFPGA_SEC_ERR_INVALID_SIZE);\n \t\treturn -EINVAL;\n \t}\n+\tsmgr->remaining_size = len;\n+\tsmgr->one_percent = smgr->remaining_size / 100;\n \n \tprintf(\"Updating from file \\'%s\\' with size %u\\n\",\n-\t\timage, smgr->rsu_length);\n+\t\tsmgr->filename, smgr->remaining_size);\n \n+\t/* setup signal handler */\n \tsec_mgr = smgr;\n \tmemset(&sa, 0, sizeof(struct sigaction));\n \tsa.sa_flags = SA_SIGINFO | SA_RESETHAND;\n@@ -354,39 +400,106 @@ int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image,\n \t\t\t\" [e:%d]\\n\", ret);\n \t\tsec_mgr = NULL;\n \t}\n-\n \tstart = time(NULL);\n+\n \tlog_time(time(NULL) - start, \"Starting secure flash update\");\n-\tret = start_flash_update(smgr);\n-\tif (ret < 0)\n-\t\tgoto end;\n+\tif (progress_transition(smgr, IFPGA_RSU_PREPARING)) {\n+\t\tret = smgr->err_code;\n+\t\tgoto exit;\n+\t}\n+\n+\tret = fpga_sec_dev_prepare(smgr);\n+\tif (ret != IFPGA_SEC_ERR_NONE) {\n+\t\tfpga_sec_dev_error(smgr, ret);\n+\t\tgoto exit;\n+\t}\n \n-\tset_rsu_status(smgr, IFPGA_RSU_READY, 0);\n \tlog_time(time(NULL) - start, \"Writing to staging area\");\n-\tret = write_flash_image(smgr, image, 0);\n-\tif (ret < 0)\n-\t\tgoto end;\n+\tif (progress_transition(smgr, IFPGA_RSU_WRITING)) {\n+\t\tret = smgr->err_code;\n+\t\tgoto done;\n+\t}\n+\n+\tret = fpga_sec_dev_write(smgr);\n+\tif (ret != IFPGA_SEC_ERR_NONE) {\n+\t\tfpga_sec_dev_error(smgr, ret);\n+\t\tgoto done;\n+\t}\n \n-\tset_rsu_status(smgr, IFPGA_RSU_COPYING, 0);\n \tlog_time(time(NULL) - start, \"Applying secure flash update\");\n-\tret = apply_flash_update(smgr);\n+\tif (progress_transition(smgr, IFPGA_RSU_PROGRAMMING)) {\n+\t\tret = smgr->err_code;\n+\t\tgoto done;\n+\t}\n+\n+\tret = fpga_sec_dev_poll_complete(smgr);\n+\tif (ret != IFPGA_SEC_ERR_NONE)\n+\t\tfpga_sec_dev_error(smgr, ret);\n+\n+done:\n+\tif (smgr->sops->cleanup)\n+\t\tsmgr->sops->cleanup(smgr);\n+\n+exit:\n+\tif (ret != IFPGA_SEC_ERR_NONE)\n+\t\tlog_time(time(NULL) - start, \"Secure flash update ERROR\");\n+\telse\n+\t\tlog_time(time(NULL) - start, \"Secure flash update OK\");\n \n-end:\n \tif (sec_mgr) {\n \t\tsec_mgr = NULL;\n \t\tif (sigaction(SIGINT, &old_sigint_action, NULL) < 0)\n \t\t\tdev_err(smgr, \"Failed to unregister signal handler\\n\");\n \t}\n \n-\tsecure_update_status(smgr, status);\n-\tif (ret < 0) {\n-\t\tlog_time(time(NULL) - start, \"Secure flash update ERROR\");\n-\t\tif (ret == -EAGAIN)\n-\t\t\tsecure_update_cancel(smgr);\n-\t} else {\n-\t\tlog_time(time(NULL) - start, \"Secure flash update OK\");\n+\tprogress_complete(smgr);\n+\n+\tdev_info(smgr, \"Return %d\\n\", ret);\n+\treturn ret == IFPGA_SEC_ERR_NONE ? 0 : -1;\n+}\n+\n+int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image,\n+\tuint64_t *status)\n+{\n+\tstruct ifpga_sec_mgr *smgr = NULL;\n+\tuint32_t rsu_stat = 0;\n+\tint ret = 0;\n+\n+\tif (!fme || !image || !status) {\n+\t\tdev_err(fme, \"Input parameter of %s is invalid\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsmgr = (struct ifpga_sec_mgr *)fme->sec_mgr;\n+\tif (!smgr) {\n+\t\tdev_err(smgr, \"Security manager not initialized\\n\");\n+\t\treturn -ENODEV;\n+\t}\n+\tif (!smgr->sops) {\n+\t\tdev_err(smgr, \"Security manager not support flash update\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tlock(smgr);\n+\tget_rsu_status(smgr, &rsu_stat, NULL);\n+\tif (rsu_stat != IFPGA_RSU_IDLE) {\n+\t\tunlock(smgr);\n+\t\tif (rsu_stat == IFPGA_RSU_REBOOT)\n+\t\t\tdev_info(smgr, \"Reboot is in progress\\n\");\n+\t\telse\n+\t\t\tdev_info(smgr, \"Update is in progress\\n\");\n+\t\treturn -EAGAIN;\n \t}\n-\tset_rsu_status(smgr, IFPGA_RSU_IDLE, 0);\n+\tset_rsu_control(smgr, 0);\n+\tset_rsu_status(smgr, IFPGA_RSU_PREPARING, 0);\n+\n+\tsmgr->filename = image;\n+\tsmgr->err_code = IFPGA_SEC_ERR_NONE;\n+\tsmgr->hw_errinfo = 0;\n+\tunlock(smgr);\n+\n+\tret = fpga_sec_mgr_update(smgr);\n+\t*status = smgr->hw_errinfo;\n \n \treturn ret;\n }\n@@ -407,7 +520,7 @@ int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force)\n \tget_rsu_status(smgr, &status, NULL);\n \tif (status != IFPGA_RSU_IDLE) {\n \t\tdev_info(smgr, \"Cancel secure flash update\\n\");\n-\t\tset_rsu_control(smgr, IFPGA_RSU_ABORT);\n+\t\tcancel_rsu(smgr);\n \t}\n \n \tif (force) {\n@@ -416,8 +529,8 @@ int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force)\n \t\t\tget_rsu_status(smgr, &status, NULL);\n \t\t\tif (status == IFPGA_RSU_IDLE)\n \t\t\t\tbreak;\n-\t\t\tif (secure_update_cancel(smgr) == 0)\n-\t\t\t\tset_rsu_status(smgr, IFPGA_RSU_IDLE, 0);\n+\t\t\tif (fpga_sec_dev_cancel(smgr) == IFPGA_SEC_ERR_NONE)\n+\t\t\t\tupdate_rsu_stat(smgr, IFPGA_RSU_IDLE);\n \t\t\tsleep(1);\n \t\t} while (--retry > 0);\n \t\tif (retry <= 0) {\n@@ -429,9 +542,11 @@ int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force)\n \treturn ret;\n }\n \n-int fpga_reload(struct ifpga_fme_hw *fme, int type, int page)\n+int fpga_reload(struct ifpga_fme_hw *fme, char *str)\n {\n \tstruct ifpga_sec_mgr *smgr = NULL;\n+\tconst struct image_load *hndlr = NULL;\n+\tint ret = -EOPNOTSUPP;\n \n \tif (!fme) {\n \t\tdev_err(fme, \"Input parameter of %s is invalid\\n\", __func__);\n@@ -439,8 +554,73 @@ int fpga_reload(struct ifpga_fme_hw *fme, int type, int page)\n \t}\n \tsmgr = (struct ifpga_sec_mgr *)fme->sec_mgr;\n \n-\tif (!smgr || !smgr->ops || !smgr->ops->reload)\n+\tif (!smgr)\n+\t\treturn -ENODEV;\n+\n+\tif (!smgr->sops || !smgr->sops->image_load)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tfor (hndlr = smgr->sops->image_load; hndlr->name; hndlr++) {\n+\t\tif (!strcmp(str, hndlr->name)) {\n+\t\t\tret = hndlr->load_image(smgr);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int fpga_available_images(struct ifpga_fme_hw *fme, char *buf, size_t size)\n+{\n+\tstruct ifpga_sec_mgr *smgr = NULL;\n+\tconst struct image_load *hndlr = NULL;\n+\tsize_t count = 0;\n+\n+\tif (!fme) {\n+\t\tdev_err(fme, \"Input parameter of %s is invalid\\n\", __func__);\n \t\treturn -EINVAL;\n+\t}\n+\tsmgr = (struct ifpga_sec_mgr *)fme->sec_mgr;\n+\n+\tif (!smgr)\n+\t\treturn -ENODEV;\n+\n+\tif (!smgr->sops || !smgr->sops->image_load)\n+\t\treturn 0;\n+\n+\tif (buf) {\n+\t\tfor (hndlr = smgr->sops->image_load; hndlr->name; hndlr++) {\n+\t\t\tif ((size > count) &&\n+\t\t\t\t((size - count) > strlen(hndlr->name))) {\n+\t\t\t\tcount += snprintf(buf + count, size - count,\n+\t\t\t\t\t\"%s \", hndlr->name);\n+\t\t\t}\n+\t\t}\n+\t\tbuf[count - 1] = '\\0';\n+\t} else {\n+\t\tfor (hndlr = smgr->sops->image_load; hndlr->name; hndlr++)\n+\t\t\tcount += strlen(hndlr->name) + 1;\n+\t}\n+\n+\treturn count;\n+}\n+\n+int fpga_set_poc_image(struct ifpga_fme_hw *fme, char *buf)\n+{\n+\tstruct ifpga_sec_mgr *smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;\n+\n+\tif (!smgr)\n+\t\treturn -ENODEV;\n+\n+\treturn pmci_set_poc_image(smgr, buf);\n+}\n+\n+int fpga_get_poc_images(struct ifpga_fme_hw *fme, char *buf, size_t size)\n+{\n+\tstruct ifpga_sec_mgr *smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;\n+\n+\tif (!smgr)\n+\t\treturn -ENODEV;\n \n-\treturn smgr->ops->reload(smgr, type, page);\n+\treturn pmci_get_poc_images(smgr, buf, size);\n }\ndiff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.c b/drivers/raw/ifpga/base/ifpga_sec_mgr.c\nindex 557c4e3..3250da1 100644\n--- a/drivers/raw/ifpga/base/ifpga_sec_mgr.c\n+++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.c\n@@ -4,9 +4,128 @@\n \n #include <fcntl.h>\n #include <signal.h>\n+#include <stdint.h>\n #include <unistd.h>\n #include \"ifpga_sec_mgr.h\"\n+#include \"opae_intel_max10.h\"\n+#include \"opae_osdep.h\"\n+\n+static const char * const rsu_stat_string[] = {\n+\t[SEC_STATUS_NORMAL] = \"Initial normal status\",\n+\t[SEC_STATUS_TIMEOUT] = \"Host timeout\",\n+\t[SEC_STATUS_AUTH_FAIL] = \"Authentication failure\",\n+\t[SEC_STATUS_COPY_FAIL] = \"Image copy failure\",\n+\t[SEC_STATUS_FATAL] = \"Fatal error, Nios boot-up failure\",\n+\t[SEC_STATUS_PKVL_REJECT] = \"pkvl reject\",\n+\t[SEC_STATUS_NON_INC] = \"Staging area non-incremental write fail\",\n+\t[SEC_STATUS_ERASE_FAIL] = \"Staging area erase fail\",\n+\t[SEC_STATUS_WEAROUT] = \"Staging area write wearout\",\n+\t[SEC_STATUS_PMCI_SS_FAIL] = \"PMCI SS Access fail\",\n+\t[SEC_STATUS_FLASH_CMD] = \"Unsupported flash command\",\n+\t[SEC_STATUS_FACTORY_UNVERITY] = \"factory image is unverified\",\n+\t[SEC_STATUS_FACTORY_ACTIVE] = \"current active image is factory\",\n+\t[SEC_STATUS_POWER_DOWN] = \"FPGA/Board powered down\",\n+\t[SEC_STATUS_CANCELLATION] = \"Cancellation not supported\",\n+\t[SEC_STATUS_HASH] = \"Hash Programming not supported\",\n+\t[SEC_STATUS_FLASH_ACCESS] = \"FPGA Flash Access Error\",\n+\t[SEC_STATUS_SDM_PR_CERT] = \"PR: cert not programmed to SDM\",\n+\t[SEC_STATUS_SDM_PR_NIOS_BUSY] = \"PR: Nios Busy waiting for SDM\",\n+\t[SEC_STATUS_SDM_PR_TIMEOUT] = \"PR: SDM Response timed out\",\n+\t[SEC_STATUS_SDM_PR_FAILED] = \"PR Key Hash program failed\",\n+\t[SEC_STATUS_SDM_PR_MISMATCH] = \"PR: SDM Response mismatched\",\n+\t[SEC_STATUS_SDM_PR_FLUSH] = \"PR: SDM Buffer Flushing failed\",\n+\t[SEC_STATUS_SDM_SR_CERT] = \"SR: cert is not programmed to SDM\",\n+\t[SEC_STATUS_SDM_SR_NIOS_BUSY] = \"SR: Nios Busy waiting for SDM\",\n+\t[SEC_STATUS_SDM_SR_TIMEOUT] = \"SR: SDM Response timed out\",\n+\t[SEC_STATUS_SDM_SR_FAILED] = \"SR Key Hash program failed\",\n+\t[SEC_STATUS_SDM_SR_MISMATCH] = \"SR: SDM Response mismatched\",\n+\t[SEC_STATUS_SDM_SR_FLUSH] = \"SR: SDM Buffer Flushing failed\",\n+\t[SEC_STATUS_SDM_KEY_CERT] = \"KEY: cert is not programmed to SDM\",\n+\t[SEC_STATUS_SDM_KEY_NIOS_BUSY] = \"KEY: Nios Busy waiting for SDM\",\n+\t[SEC_STATUS_SDM_KEY_TIMEOUT] = \"KEY: SDM Response timed out\",\n+\t[SEC_STATUS_SDM_KEY_FAILED] = \"KEY: Key Hash program failed\",\n+\t[SEC_STATUS_SDM_KEY_MISMATCH] = \"KEY: SDM Response mismatched\",\n+\t[SEC_STATUS_SDM_KEY_FLUSH] = \"KEY: SDM Buffer Flushing failed\",\n+\t[SEC_STATUS_USER_FAIL] = \"Update Failure\",\n+\t[SEC_STATUS_FACTORY_FAIL] = \"Factory Failure\",\n+\t[SEC_STATUS_NIOS_FLASH_ERR] = \"NIOS Flash Open Error\",\n+\t[SEC_STATUS_FPGA_FLASH_ERR] = \"FPGA Flash Open Error\",\n+};\n+\n+static const char * const auth_stat_string[] = {\n+\t[AUTH_STAT_PASS] = \"Authenticate Pass\",\n+\t[AUTH_STAT_B0_MAGIC] = \"Block0 Magic value error\",\n+\t[AUTH_STAT_CONLEN] = \"Block0 ConLen error\",\n+\t[AUTH_STAT_CONTYPE] = \"Block0 ConType B[7:0] > 2\",\n+\t[AUTH_STAT_B1_MAGIC] = \"Block1 Magic value error\",\n+\t[AUTH_STAT_ROOT_MAGIC] = \"Root Entry Magic value error\",\n+\t[AUTH_STAT_CURVE_MAGIC] = \"Root Entry Curve Magic value error\",\n+\t[AUTH_STAT_PERMISSION] = \"Root Entry Permission error\",\n+\t[AUTH_STAT_KEY_ID] = \"Root Entry Key ID error\",\n+\t[AUTH_STAT_CSK_MAGIC] = \"CSK Entry Magic value error\",\n+\t[AUTH_STAT_CSK_CURVE] = \"CSK Entry Curve Magic value error\",\n+\t[AUTH_STAT_CSK_PERMISSION] = \"CSK Entry Permission error\",\n+\t[AUTH_STAT_CSK_ID] = \"CSK Entry Key ID error\",\n+\t[AUTH_STAT_CSK_SM] = \"CSK Entry Signature Magic value error\",\n+\t[AUTH_STAT_B0_E_MAGIC] = \"Block0 Entry Magic value error\",\n+\t[AUTH_STAT_B0_E_SIGN] = \"Block0 Entry Signature Magic value error\",\n+\t[AUTH_STAT_RK_P] = \"Root Key Hash not programmed for RSU\",\n+\t[AUTH_STAT_RE_SHA] = \"Root Entry verify SHA failed\",\n+\t[AUTH_STAT_CSK_SHA] = \"CSK Entry verify ECDSA and SHA failed\",\n+\t[AUTH_STAT_B0_SHA] = \"Block0 Entry verify ECDSA and SHA failed\",\n+\t[AUTH_STAT_KEY_INV] = \"KEY ID of authenticate blob is invalid\",\n+\t[AUTH_STAT_KEY_CAN] = \"KEY ID is cancelled\",\n+\t[AUTH_STAT_UP_SHA] = \"Update content SHA verify failed\",\n+\t[AUTH_STAT_CAN_SHA] = \"Cancellation content SHA verify failed\",\n+\t[AUTH_STAT_HASH] = \"HASH Programming content SHA verify failed\",\n+\t[AUTH_STAT_INV_ID] = \"Invalid cancellation ID of cancellation cert\",\n+\t[AUTH_STAT_KEY_PROG] = \"KEY hash programmed for KEY hash programming cert\",\n+\t[AUTH_STAT_INV_BC] = \"Invalid operation of Block0 ConType\",\n+\t[AUTH_STAT_INV_SLOT] = \"Invalid slot in Block0 ConType\",\n+\t[AUTH_STAT_IN_OP] = \"Incompatible operation of Block0 ConType\",\n+\t[AUTH_STAT_TIME_OUT] = \"Flash transfer to staging area timed out\",\n+\t[AUTH_STAT_SHA_TO] = \"Root Entry verify SHA timeout\",\n+\t[AUTH_STAT_CSK_TO] = \"CSK Entry verify ECDSA and SHA timeout\",\n+\t[AUTH_STAT_B0_TO] = \"Block0 Entry verify ECDSA and SHA timeout\",\n+\t[AUTH_STAT_UP_TO] = \"Update content SHA verify timeout\",\n+\t[AUTH_STAT_CAN_TO] = \"Cancellation content SHA verify timeout\",\n+\t[AUTH_STAT_HASH_TO] = \"HASH Programming content SHA verify timeout\",\n+\t[AUTH_STAT_AUTH_IDLE] = \"Authentication engine Idle\",\n+\t[AUTH_STAT_GA_FAIL] = \"Generic Authentication Failure\",\n+\t[AUTH_STAT_S_ERR] = \"Sensor Blob Generic Error\",\n+\t[AUTH_STAT_S_MN] = \"Sensor Blob Magic number error\",\n+\t[AUTH_STAT_SH_CRC] = \"Sensor Blob Header CRC error\",\n+\t[AUTH_STAT_SD_CRC] = \"Sensor Blob Data CRC error\",\n+\t[AUTH_STAT_SD_LEN] = \"Sensor Blob Data Length error\",\n+\t[AUTH_STAT_S_ID] = \"Sensor Blob Sensor ID not supported\",\n+\t[AUTH_STAT_S_THR] = \"Sensor Blob Invalid threshold type\",\n+\t[AUTH_STAT_S_TO] = \"Sensor Blob threshold out of bounds\",\n+\t[AUTH_STAT_S_EN] = \"Sensor Blob exceeds number of sensor count\",\n+\t[AUTH_STAT_SF] = \"only FPGA thermal Sensor Thresholds are allowed\",\n+};\n \n+static const char * const sdm_stat_string[] = {\n+\t[SDM_STAT_DONE] = \"SR Key Hash program successful\",\n+\t[SDM_STAT_PROV] = \"ignored,SR Hash is already provisioned to SDM\",\n+\t[SDM_STAT_BUSY] = \"Ignored; Configuration Module Busy\",\n+\t[SDM_STAT_INV] = \"Invalid configuration Status from Configuration\",\n+\t[SDM_STAT_FAIL] = \"SDM Flush Buffer failed\",\n+\t[SDM_STAT_BMC_BUSY] = \"BMC Busy waiting for another SDM command response\",\n+\t[SDM_STAT_TO] = \"SDM Response timed out during SDM Provisioning\",\n+\t[SDM_STAT_DB] = \"SDM device busy during SDM Provisioning\",\n+\t[SDM_STAT_CON_R] = \"Config Status retry count exceeded\",\n+\t[SDM_STAT_CON_E] = \"Config status command returned error\",\n+\t[SDM_STAT_WAIT] = \"BMC Busy waiting for another SDM command response\",\n+\t[SDM_STAT_RTO] = \"timed out during PUBKEY_PROGRAM command to SDM\",\n+\t[SDM_STAT_SB] = \"busy during PUBKEY_PROGRAM command to SDM\",\n+\t[SDM_STAT_RE] = \"SR Key Hash program failed with recoverable error\",\n+\t[SDM_STAT_PDD] = \"SR Key Hash program failed permanent device damage\",\n+\t[SDM_STAT_ISC] = \"SR Key program failed by invalid SDM command\",\n+\t[SDM_STAT_SIC] = \"SDM Congiguration failed by Shell Image configured\",\n+\t[SDM_STAT_NO_PROV] = \"SR Key Hash not provisioned to BMC\",\n+\t[SDM_STAT_CS_MIS] = \"failed by SDM CONFIG_STATUS response mismatch\",\n+\t[SDM_STAT_PR_MIS] = \"failed by SDM PUBKEY_PROGRAM Response mismatch\",\n+};\n \n static const char * const rsu_prog[] = {\"IDLE\", \"PREPARING\", \"SLEEPING\",\n \t\"READY\", \"AUTHENTICATING\", \"COPYING\", \"CANCELLATION\", \"PROGRAMMING_KEY\",\n@@ -17,6 +136,160 @@\n static const char * const rsu_stath[] = {\"NIOS_OK\", \"USER_OK\", \"FACTORY_OK\",\n \t\"USER_FAIL\", \"FACTORY_FAIL\", \"NIOS_FLASH_ERR\", \"FPGA_FLASH_ERR\"};\n \n+static const char * const fpga_image_names[] = {\n+\t[FPGA_FACTORY] = \"fpga_factory\",\n+\t[FPGA_USER1] = \"fpga_user1\",\n+\t[FPGA_USER2] = \"fpga_user2\"\n+};\n+\n+static enum fpga_image\n+fpga_image_by_name(char *image_name)\n+{\n+\tenum fpga_image i;\n+\n+\tfor (i = 0; i < FPGA_MAX; i++)\n+\t\tif (!strcmp(image_name, fpga_image_names[i]))\n+\t\t\treturn i;\n+\n+\treturn FPGA_MAX;\n+}\n+\n+static int\n+fpga_images(struct ifpga_sec_mgr *smgr, char *names, enum fpga_image images[])\n+{\n+\tu32 image_mask = smgr->poc->avail_image_mask;\n+\tenum fpga_image image;\n+\tchar *image_name;\n+\tint i = 0;\n+\n+\twhile ((image_name = strsep(&names, \"\\n\"))) {\n+\t\timage = fpga_image_by_name(image_name);\n+\t\tif (image >= FPGA_MAX || !(image_mask & BIT(image)))\n+\t\t\treturn -EINVAL;\n+\n+\t\timages[i++] = image;\n+\t\timage_mask &= ~BIT(image);\n+\t}\n+\n+\treturn (i == 0) ? -EINVAL : 0;\n+}\n+\n+int pmci_set_poc_image(struct ifpga_sec_mgr *smgr, char *buf)\n+{\n+\tenum fpga_image images[FPGA_MAX] = { [0 ... FPGA_MAX - 1] = FPGA_MAX };\n+\tint ret;\n+\n+\tif (!smgr)\n+\t\treturn -ENODEV;\n+\n+\tret = fpga_images(smgr, buf, images);\n+\tif (ret)\n+\t\treturn -EINVAL;\n+\n+\treturn smgr->poc->set_sequence(smgr, images);\n+}\n+\n+int pmci_get_poc_images(struct ifpga_sec_mgr *smgr, char *buf, size_t size)\n+{\n+\tif (!smgr)\n+\t\treturn -ENODEV;\n+\n+\treturn smgr->poc->get_sequence(smgr, buf, size);\n+}\n+\n+static int pmci_get_power_on_image(struct ifpga_sec_mgr *smgr,\n+\t\tchar *buf, size_t size)\n+{\n+\tconst char *image_names[FPGA_MAX] = { 0 };\n+\tint ret, i = 0;\n+\tint j;\n+\tu32 poc;\n+\tsize_t count = 0;\n+\n+\tif (!smgr->max10_dev)\n+\t\treturn -ENODEV;\n+\n+\tif (!buf)\n+\t\treturn -EINVAL;\n+\n+\tret = max10_sys_read(smgr->max10_dev, M10BMC_PMCI_FPGA_POC, &poc);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (poc & PMCI_FACTORY_IMAGE_SEL)\n+\t\timage_names[i++] = fpga_image_names[FPGA_FACTORY];\n+\n+\tif (GET_FIELD(PMCI_USER_IMAGE_PAGE, poc) == POC_USER_IMAGE_1) {\n+\t\timage_names[i++] = fpga_image_names[FPGA_USER1];\n+\t\timage_names[i++] = fpga_image_names[FPGA_USER2];\n+\t} else {\n+\t\timage_names[i++] = fpga_image_names[FPGA_USER2];\n+\t\timage_names[i++] = fpga_image_names[FPGA_USER1];\n+\t}\n+\n+\tif (!(poc & PMCI_FACTORY_IMAGE_SEL))\n+\t\timage_names[i] = fpga_image_names[FPGA_FACTORY];\n+\n+\tfor (j = 0; j < FPGA_MAX; j++) {\n+\t\tif ((size > count) &&\n+\t\t\t\t((size - count) > strlen(image_names[j])))\n+\t\t\tcount += snprintf(buf + count, size - count,\n+\t\t\t\t\t\"%s \", image_names[j]);\n+\t}\n+\tbuf[count - 1] = '\\0';\n+\n+\treturn count;\n+}\n+\n+static int\n+pmci_set_power_on_image(struct ifpga_sec_mgr *smgr, enum fpga_image images[])\n+{\n+\tstruct intel_max10_device *dev = smgr->max10_dev;\n+\tu32 poc_mask = PMCI_FACTORY_IMAGE_SEL;\n+\tint ret, first_user = 0;\n+\tu32 poc = 0;\n+\n+\tif (!dev)\n+\t\treturn -ENODEV;\n+\n+\tif (images[1] == FPGA_FACTORY)\n+\t\treturn -EINVAL;\n+\n+\tif (images[0] == FPGA_FACTORY) {\n+\t\tpoc = PMCI_FACTORY_IMAGE_SEL;\n+\t\tfirst_user = 1;\n+\t}\n+\n+\tif (images[first_user] == FPGA_USER1 ||\n+\t\t\timages[first_user] == FPGA_USER2) {\n+\t\tpoc_mask |= PMCI_USER_IMAGE_PAGE;\n+\t\tif (images[first_user] == FPGA_USER1)\n+\t\t\tpoc |= SET_FIELD(PMCI_USER_IMAGE_PAGE,\n+\t\t\t\t\tPOC_USER_IMAGE_1);\n+\t\telse\n+\t\t\tpoc |= SET_FIELD(PMCI_USER_IMAGE_PAGE,\n+\t\t\t\t\tPOC_USER_IMAGE_2);\n+\t}\n+\n+\tret = max10_sys_update_bits(dev,\n+\t\t\tm10bmc_base(dev) + M10BMC_PMCI_FPGA_POC,\n+\t\t\tpoc_mask | PMCI_FPGA_POC, poc | PMCI_FPGA_POC);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = opae_max10_read_poll_timeout(dev,\n+\t\t\tm10bmc_base(dev) + M10BMC_PMCI_FPGA_POC,\n+\t\t\tpoc,\n+\t\t\t(!(poc & PMCI_FPGA_POC)),\n+\t\t\tIFPGA_NIOS_HANDSHAKE_INTERVAL_US,\n+\t\t\tIFPGA_NIOS_HANDSHAKE_TIMEOUT_US);\n+\n+\tif (ret || (GET_FIELD(PMCI_NIOS_STATUS, poc) != NIOS_STATUS_SUCCESS))\n+\t\treturn -EIO;\n+\n+\treturn 0;\n+}\n+\n static const char *rsu_progress_name(uint32_t prog)\n {\n \tif (prog > SEC_PROGRESS_PKVL_PROM_DONE)\n@@ -40,377 +313,527 @@ static const char *rsu_status_name(uint32_t stat)\n \t}\n }\n \n-static bool secure_start_done(uint32_t doorbell)\n+static void print_sdm_status(struct intel_max10_device *dev)\n {\n-\treturn (SEC_STATUS_G(doorbell) == SEC_STATUS_ERASE_FAIL ||\n-\t\tSEC_STATUS_G(doorbell) == SEC_STATUS_WEAROUT ||\n-\t\t(SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_IDLE &&\n-\t\tSEC_PROGRESS_G(doorbell) != SEC_PROGRESS_RSU_DONE));\n+\tu32 val, sdm_stat;\n+\n+\tconst char *sdm_string;\n+\n+\tif (dev->type == M10_N6000) {\n+\t\tif (!max10_sys_read(dev, m10bmc_base(dev) +\n+\t\t\t\t\tM10BMC_PMCI_SDM_CTRL_STS, &val))\n+\t\t\tdev_err(dev, \"sdm ctrl reg: 0x%08x\\n\", val);\n+\n+\t\tsdm_stat = GET_FIELD(val, PMCI_SDM_STAT);\n+\t\tif (sdm_stat > SDM_STAT_MAX)\n+\t\t\tdev_err(dev, \"unknown sdm stat: 0x%08x\\n\", sdm_stat);\n+\n+\t\tsdm_string = sdm_stat_string[sdm_stat];\n+\t\tif (sdm_string)\n+\t\t\tdev_err(dev, \"sdm stat: %s\\n\", sdm_string);\n+\t\telse\n+\t\t\tdev_err(dev, \"unknown sdm stat\\n\");\n+\t}\n }\n \n-static bool secure_prog_ready(uint32_t doorbell)\n+static void print_error_regs(struct intel_max10_device *dev)\n {\n-\treturn (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY);\n+\tu32 auth_result, doorbell, rsu_stat, auth_stat;\n+\n+\tconst char *rsu_string, *auth_string;\n+\n+\tif (!max10_sys_read(dev, doorbell_reg(dev), &doorbell))\n+\t\tdev_err(dev, \"RSU doorbell reg: 0x%08x\\n\", doorbell);\n+\n+\tif (!max10_sys_read(dev, auth_result_reg(dev), &auth_result))\n+\t\tdev_err(dev, \"RSU auth result reg: 0x%08x\\n\", auth_result);\n+\n+\trsu_stat = SEC_STATUS_G(auth_result);\n+\tif (rsu_stat > SEC_STATUS_MAX)\n+\t\tdev_err(dev, \"unknown rsu stat, error code exceed: 0x%08x\\n\", rsu_stat);\n+\n+\trsu_string = rsu_stat_string[rsu_stat];\n+\tif (rsu_string)\n+\t\tdev_err(dev, \"rsu stat: %s\\n\", rsu_string);\n+\telse\n+\t\tdev_err(dev, \"unknown rsu stat\\n\");\n+\n+\tif (rsu_stat == SEC_STATUS_SDM_PR_FAILED ||\n+\t\t\trsu_stat == SEC_STATUS_SDM_SR_FAILED)\n+\t\tprint_sdm_status(dev);\n+\n+\tauth_stat = SEC_AUTH_G(auth_result);\n+\tif (auth_stat > AUTH_STAT_MAX)\n+\t\tdev_err(dev, \"unknown Authentication status, code exceed: 0x%08x\\n\", rsu_stat);\n+\n+\tauth_string = auth_stat_string[auth_stat];\n+\tif (auth_string)\n+\t\tdev_err(dev, \"auth stat: %s\\n\", auth_string);\n+\telse\n+\t\tdev_err(dev, \"unknown auth stat\\n\");\n }\n \n-static int poll_timeout(struct intel_max10_device *dev, uint32_t offset,\n-\tbool (*cond)(uint32_t), uint32_t interval_ms, uint32_t timeout_ms)\n+static bool rsu_status_ok(u32 status)\n {\n-\tuint32_t val = 0;\n-\tint ret = 0;\n-\n-\tfor (;;) {\n-\t\tret = max10_sys_read(dev, offset, &val);\n-\t\tif (ret < 0) {\n-\t\t\tdev_err(dev,\n-\t\t\t\t\"Failed to read max10 register 0x%x [e:%d]\\n\",\n-\t\t\t\toffset, ret);\n-\t\t\tbreak;\n-\t\t}\n+\treturn (status == SEC_STATUS_NORMAL ||\n+\t\tstatus == SEC_STATUS_NIOS_OK ||\n+\t\tstatus == SEC_STATUS_USER_OK ||\n+\t\tstatus == SEC_STATUS_FACTORY_OK);\n+}\n \n-\t\tif (cond(val)) {\n-\t\t\tdev_debug(dev,\n-\t\t\t\t\"Read 0x%08x from max10 register 0x%x \"\n-\t\t\t\t\"[poll success]\\n\", val, offset);\n-\t\t\tret = 0;\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (timeout_ms > interval_ms)\n-\t\t\ttimeout_ms -= interval_ms;\n-\t\telse\n-\t\t\ttimeout_ms = 0;\n-\t\tif (timeout_ms == 0) {\n-\t\t\tdev_debug(dev,\n-\t\t\t\t\"Read 0x%08x from max10 register 0x%x \"\n-\t\t\t\t\"[poll timeout]\\n\", val, offset);\n-\t\t\tret = -ETIMEDOUT;\n-\t\t\tbreak;\n-\t\t}\n-\t\tmsleep(interval_ms);\n-\t}\n+static bool rsu_progress_done(u32 progress)\n+{\n+\treturn (progress == SEC_PROGRESS_IDLE ||\n+\t\tprogress == SEC_PROGRESS_RSU_DONE);\n+}\n \n-\treturn ret;\n+static bool rsu_progress_busy(u32 progress)\n+{\n+\treturn (progress == SEC_PROGRESS_AUTHENTICATING ||\n+\t\tprogress == SEC_PROGRESS_COPYING ||\n+\t\tprogress == SEC_PROGRESS_UPDATE_CANCEL ||\n+\t\tprogress == SEC_PROGRESS_PROGRAM_KEY_HASH);\n }\n \n-static int n3000_secure_update_start(struct intel_max10_device *dev)\n+static enum ifpga_sec_err rsu_check_idle(struct intel_max10_device *dev)\n {\n \tuint32_t doorbell = 0;\n \tuint32_t prog = 0;\n-\tuint32_t status = 0;\n \tint ret = 0;\n \n-\tret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);\n-\tif (ret < 0) {\n+\tret = max10_sys_read(dev, doorbell_reg(dev), &doorbell);\n+\tif (ret) {\n \t\tdev_err(dev,\n \t\t\t\"Failed to read max10 doorbell register [e:%d]\\n\",\n \t\t\tret);\n-\t\treturn ret;\n+\t\treturn IFPGA_SEC_ERR_RW_ERROR;\n \t}\n \n \tprog = SEC_PROGRESS_G(doorbell);\n-\tif ((prog != SEC_PROGRESS_IDLE) && (prog != SEC_PROGRESS_RSU_DONE)) {\n-\t\tdev_debug(dev, \"Current RSU progress is %s\\n\",\n+\tif (!rsu_progress_done(prog)) {\n+\t\tdev_info(dev, \"Current RSU progress is %s\\n\",\n \t\t\trsu_progress_name(prog));\n-\t\treturn -EBUSY;\n+\t\treturn IFPGA_SEC_ERR_BUSY;\n+\t}\n+\n+\treturn IFPGA_SEC_ERR_NONE;\n+}\n+\n+static bool cond_start_done(uint32_t doorbell, uint32_t progress,\n+\t\tuint32_t status)\n+{\n+\tif (doorbell & RSU_REQUEST)\n+\t\treturn false;\n+\n+\tif (status == SEC_STATUS_ERASE_FAIL ||\n+\t\tstatus == SEC_STATUS_WEAROUT)\n+\t\treturn true;\n+\n+\tif (!rsu_progress_done(progress))\n+\t\treturn true;\n+\n+\treturn false;\n+}\n+\n+static int\n+m10bmc_sec_status(struct intel_max10_device *dev, u32 *status)\n+{\n+\tu32 reg_offset, reg_value;\n+\tint ret;\n+\n+\treg_offset = (dev->type == M10_N6000) ?\n+\t\tauth_result_reg(dev) : doorbell_reg(dev);\n+\n+\tret = max10_sys_read(dev, reg_offset, &reg_value);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t*status = SEC_STATUS_G(reg_value);\n+\n+\treturn 0;\n+}\n+\n+static int\n+m10bmc_sec_progress_status(struct intel_max10_device *dev, u32 *doorbell,\n+\t\t\t   u32 *progress, u32 *status)\n+{\n+\tu32 auth_reg;\n+\tint ret;\n+\n+\tret = max10_sys_read(dev,\n+\t\t\t      doorbell_reg(dev),\n+\t\t\t      doorbell);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t*progress = SEC_PROGRESS_G(*doorbell);\n+\n+\tif (dev->type == M10_N6000) {\n+\t\tret = max10_sys_read(dev,\n+\t\t\t\t      auth_result_reg(dev),\n+\t\t\t\t      &auth_reg);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t\t*status = SEC_STATUS_G(auth_reg);\n+\t} else {\n+\t\t*status = SEC_STATUS_G(*doorbell);\n \t}\n \n-\tret = max10_sys_update_bits(dev, MAX10_DOORBELL,\n+\treturn 0;\n+}\n+\n+static int rsu_poll_start_done(struct intel_max10_device *dev, u32 *doorbell,\n+\t\t\t       u32 *progress, u32 *status)\n+{\n+\tunsigned long time = 0;\n+\tint ret;\n+\n+\tdo {\n+\t\tif (time > IFPGA_NIOS_HANDSHAKE_TIMEOUT_US)\n+\t\t\treturn -ETIMEDOUT;\n+\n+\t\tret = m10bmc_sec_progress_status(dev, doorbell,\n+\t\t\t\tprogress, status);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t\tusleep(IFPGA_NIOS_HANDSHAKE_INTERVAL_US);\n+\t\ttime += IFPGA_NIOS_HANDSHAKE_INTERVAL_US;\n+\n+\t} while (!cond_start_done(*doorbell, *progress, *status));\n+\n+\treturn 0;\n+}\n+\n+static enum ifpga_sec_err rsu_update_init(struct intel_max10_device *dev)\n+{\n+\tuint32_t doorbell, progress, status;\n+\tint ret = 0;\n+\n+\tret = max10_sys_update_bits(dev, doorbell_reg(dev),\n \t\tRSU_REQUEST | HOST_STATUS, RSU_REQUEST);\n-\tif (ret < 0) {\n+\tif (ret) {\n \t\tdev_err(dev,\n \t\t\t\"Failed to updt max10 doorbell register [e:%d]\\n\",\n \t\t\tret);\n-\t\treturn ret;\n+\t\treturn IFPGA_SEC_ERR_RW_ERROR;\n \t}\n \n-\tret = poll_timeout(dev, MAX10_DOORBELL, secure_start_done,\n-\t\tIFPGA_SEC_START_INTERVAL_MS, IFPGA_SEC_START_TIMEOUT_MS);\n-\tif (ret < 0) {\n+\tret = rsu_poll_start_done(dev, &doorbell, &progress, &status);\n+\tif (ret == -ETIMEDOUT) {\n+\t\tprint_error_regs(dev);\n+\t\treturn IFPGA_SEC_ERR_TIMEOUT;\n+\t} else if (ret) {\n \t\tdev_err(dev,\n \t\t\t\"Failed to poll max10 doorbell register [e:%d]\\n\",\n \t\t\tret);\n-\t\treturn ret;\n+\t\treturn IFPGA_SEC_ERR_RW_ERROR;\n \t}\n \n-\tret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);\n-\tif (ret < 0) {\n-\t\tdev_err(dev,\n-\t\t\t\"Failed to read max10 doorbell register [e:%d]\\n\",\n-\t\t\tret);\n-\t\treturn ret;\n+\tstatus = SEC_STATUS_G(doorbell);\n+\tif (status == SEC_STATUS_WEAROUT) {\n+\t\tdev_err(dev, \"Excessive flash update count detected\\n\");\n+\t\treturn IFPGA_SEC_ERR_WEAROUT;\n+\t} else if (status == SEC_STATUS_ERASE_FAIL) {\n+\t\tprint_error_regs(dev);\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \t}\n \n-\tstatus = SEC_STATUS_G(doorbell);\n-\tif (status == SEC_STATUS_WEAROUT)\n-\t\treturn -EAGAIN;\n+\tdev_info(dev, \"Current RSU progress is %s\\n\",\n+\t\t\trsu_progress_name(SEC_PROGRESS_G(doorbell)));\n \n-\tif (status == SEC_STATUS_ERASE_FAIL)\n-\t\treturn -EIO;\n+\treturn IFPGA_SEC_ERR_NONE;\n+}\n \n-\treturn 0;\n+static bool cond_prepare_done(uint32_t doorbell)\n+{\n+\treturn (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_PREPARE);\n }\n \n-static int n3000_cancel(struct ifpga_sec_mgr *smgr)\n+static enum ifpga_sec_err rsu_prog_ready(struct intel_max10_device *dev)\n {\n-\tstruct intel_max10_device *dev = NULL;\n \tuint32_t doorbell = 0;\n \tuint32_t prog = 0;\n \tint ret = 0;\n \n-\tif (!smgr || !smgr->max10_dev)\n-\t\treturn -ENODEV;\n-\tdev = (struct intel_max10_device *)smgr->max10_dev;\n-\n-\tret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);\n-\tif (ret < 0) {\n+\tret = opae_max10_read_poll_timeout(dev, doorbell_reg(dev),\n+\t\t\tdoorbell, cond_prepare_done(doorbell),\n+\t\t\tIFPGA_RSU_PREP_INTERVAL_US,\n+\t\t\tIFPGA_RSU_PREP_TIMEOUT_US);\n+\tif (ret == -ETIMEDOUT) {\n+\t\tprint_error_regs(dev);\n+\t\treturn IFPGA_SEC_ERR_TIMEOUT;\n+\t} else if (ret) {\n \t\tdev_err(dev,\n-\t\t\t\"Failed to read max10 doorbell register [e:%d]\\n\",\n+\t\t\t\"Failed to poll max10 prog [e:%d]\\n\",\n \t\t\tret);\n-\t\treturn ret;\n+\t\treturn IFPGA_SEC_ERR_RW_ERROR;\n \t}\n \n \tprog = SEC_PROGRESS_G(doorbell);\n-\tif (prog == SEC_PROGRESS_IDLE)\n-\t\treturn 0;\n-\tif (prog != SEC_PROGRESS_READY)\n-\t\treturn -EBUSY;\n+\tif (prog == SEC_PROGRESS_PREPARE) {\n+\t\tprint_error_regs(dev);\n+\t\treturn IFPGA_SEC_ERR_TIMEOUT;\n+\t} else if (prog != SEC_PROGRESS_READY) {\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n+\t}\n \n-\treturn max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS,\n-\t\tHOST_STATUS_S(HOST_STATUS_ABORT_RSU));\n+\tdev_info(dev, \"Current RSU progress is %s\\n\",\n+\t\t\trsu_progress_name(SEC_PROGRESS_G(doorbell)));\n+\n+\treturn IFPGA_SEC_ERR_NONE;\n }\n \n-static int n3000_prepare(struct ifpga_sec_mgr *smgr)\n+static enum ifpga_sec_err m10bmc_sec_prepare(struct ifpga_sec_mgr *smgr)\n {\n \tstruct intel_max10_device *dev = NULL;\n-\tint retry = 0;\n \tint ret = 0;\n \n \tif (!smgr || !smgr->max10_dev)\n-\t\treturn -ENODEV;\n-\tdev = (struct intel_max10_device *)smgr->max10_dev;\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \n-\tret = n3000_secure_update_start(dev);\n-\tif (ret == -EBUSY)\n-\t\tn3000_cancel(smgr);\n+\tdev = smgr->max10_dev;\n \n-\twhile (ret) {\n-\t\tif (++retry > IFPGA_RSU_START_RETRY)\n-\t\t\tbreak;\n-\t\tmsleep(1000);\n-\t\tret = n3000_secure_update_start(dev);\n-\t}\n-\tif (retry > IFPGA_RSU_START_RETRY) {\n-\t\tdev_err(dev, \"Failed to start secure flash update\\n\");\n-\t\tret = -EAGAIN;\n+\tif (smgr->remaining_size > dev->staging_area_size) {\n+\t\tdev_err(smgr, \"Size of staging area is smaller than image \"\n+\t\t\t\"length [%u<%u]\\n\", smgr->max10_dev->staging_area_size,\n+\t\t\tsmgr->remaining_size);\n+\t\treturn IFPGA_SEC_ERR_INVALID_SIZE;\n \t}\n \n-\treturn ret;\n-}\n-\n-static int n3000_bulk_write(struct intel_max10_device *dev, uint32_t addr,\n-\tchar *buf, uint32_t len)\n-{\n-\tuint32_t i = 0;\n-\tuint32_t n = 0;\n-\tuint32_t v = 0;\n-\tuint32_t p = 0;\n-\tint ret = 0;\n-\n-\tif (len & 0x3) {\n-\t\tdev_err(dev,\n-\t\t\t\"Length of data block is not 4 bytes aligned [e:%u]\\n\",\n-\t\t\tlen);\n-\t\treturn -EINVAL;\n-\t}\n+\tret = rsu_check_idle(dev);\n+\tif (ret != IFPGA_SEC_ERR_NONE)\n+\t\treturn ret;\n \n-\tn = len >> 2;\n-\tfor (i = 0; i < n; i++) {\n-\t\tp = i << 2;\n-\t\tv = *(uint32_t *)(buf + p);\n-\t\tret = max10_sys_raw_write(dev, addr + p, v);\n-\t\tif (ret < 0) {\n-\t\t\tdev_err(dev,\n-\t\t\t\t\"Failed to write to staging area 0x%08x [e:%d]\\n\",\n-\t\t\t\taddr + p, ret);\n-\t\t\treturn ret;\n-\t\t}\n-\t\tusleep(1);\n-\t}\n+\tret = rsu_update_init(dev);\n+\tif (ret != IFPGA_SEC_ERR_NONE)\n+\t\treturn ret;\n \n-\treturn 0;\n+\treturn rsu_prog_ready(dev);\n }\n \n-static int n3000_write_blk(struct ifpga_sec_mgr *smgr, char *buf,\n+\n+static enum ifpga_sec_err m10bmc_sec_write_blk(struct ifpga_sec_mgr *smgr,\n \tuint32_t offset, uint32_t len)\n {\n \tstruct intel_max10_device *dev = NULL;\n \tuint32_t doorbell = 0;\n-\tuint32_t prog = 0;\n-\tuint32_t m = 0;\n \tint ret = 0;\n \n \tif (!smgr || !smgr->max10_dev)\n-\t\treturn -ENODEV;\n-\tdev = (struct intel_max10_device *)smgr->max10_dev;\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n+\n+\tdev = smgr->max10_dev;\n+\tif (!dev || !dev->bmc_ops.flash_write)\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \n \tif (offset + len > dev->staging_area_size) {\n \t\tdev_err(dev,\n \t\t\t\"Write position would be out of staging area [e:%u]\\n\",\n \t\t\tdev->staging_area_size);\n-\t\treturn -ENOMEM;\n+\t\treturn IFPGA_SEC_ERR_INVALID_SIZE;\n \t}\n \n-\tret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);\n+\tret = max10_sys_read(dev, doorbell_reg(dev), &doorbell);\n \tif (ret < 0) {\n \t\tdev_err(dev,\n \t\t\t\"Failed to read max10 doorbell register [e:%d]\\n\",\n \t\t\tret);\n-\t\treturn ret;\n+\t\treturn IFPGA_SEC_ERR_RW_ERROR;\n \t}\n \n-\tprog = SEC_PROGRESS_G(doorbell);\n-\tif (prog == SEC_PROGRESS_PREPARE)\n-\t\treturn -EAGAIN;\n-\telse if (prog != SEC_PROGRESS_READY)\n-\t\treturn -EBUSY;\n+\tif (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY)\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \n-\tm = len & 0x3;\n-\tif (m != 0)\n-\t\tlen += 4 - m;   /* make length to 4 bytes align */\n+\tret = dev->bmc_ops.flash_write(dev, dev->staging_area_base + offset,\n+\t\t\tsmgr->data, len);\n \n-\treturn n3000_bulk_write(dev, dev->staging_area_base + offset, buf, len);\n+\treturn ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;\n }\n \n-static int n3000_write_done(struct ifpga_sec_mgr *smgr)\n+static enum ifpga_sec_err pmci_sec_write_blk(struct ifpga_sec_mgr *smgr,\n+\tuint32_t offset, uint32_t len)\n {\n-\tstruct intel_max10_device *dev = NULL;\n+\tstruct intel_max10_device *dev;\n \tuint32_t doorbell = 0;\n-\tuint32_t prog = 0;\n-\tuint32_t status = 0;\n \tint ret = 0;\n+\tUNUSED(offset);\n \n \tif (!smgr || !smgr->max10_dev)\n-\t\treturn -ENODEV;\n-\tdev = (struct intel_max10_device *)smgr->max10_dev;\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \n-\tret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);\n+\tdev = smgr->max10_dev;\n+\tif (!dev || !dev->bmc_ops.flash_write)\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n+\n+\tret = max10_sys_read(dev, doorbell_reg(dev), &doorbell);\n \tif (ret < 0) {\n \t\tdev_err(dev,\n \t\t\t\"Failed to read max10 doorbell register [e:%d]\\n\",\n \t\t\tret);\n-\t\treturn ret;\n+\t\treturn IFPGA_SEC_ERR_RW_ERROR;\n \t}\n \n-\tprog = SEC_PROGRESS_G(doorbell);\n-\tif (prog != SEC_PROGRESS_READY)\n-\t\treturn -EBUSY;\n+\tif (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY)\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n+\n+\tret = dev->bmc_ops.flash_write(dev, 0, smgr->data, len);\n+\n+\treturn ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;\n+}\n \n-\tret = max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS,\n+static bool cond_prog_ready(uint32_t doorbell)\n+{\n+\treturn (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY);\n+}\n+\n+static enum ifpga_sec_err m10bmc_sec_write_done(struct ifpga_sec_mgr *smgr)\n+{\n+\tstruct intel_max10_device *dev = NULL;\n+\tuint32_t doorbell, status;\n+\tint ret = 0;\n+\n+\tif (!smgr || !smgr->max10_dev)\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n+\n+\tdev = smgr->max10_dev;\n+\n+\tret = max10_sys_update_bits(dev, doorbell_reg(dev), HOST_STATUS,\n \t\tHOST_STATUS_S(HOST_STATUS_WRITE_DONE));\n \tif (ret < 0) {\n \t\tdev_err(dev,\n \t\t\t\"Failed to update max10 doorbell register [e:%d]\\n\",\n \t\t\tret);\n-\t\treturn ret;\n+\t\treturn IFPGA_SEC_ERR_RW_ERROR;\n \t}\n \n-\tret = poll_timeout(dev, MAX10_DOORBELL, secure_prog_ready,\n-\t\tIFPGA_NIOS_HANDSHAKE_INTERVAL_MS,\n-\t\tIFPGA_NIOS_HANDSHAKE_TIMEOUT_MS);\n-\tif (ret < 0) {\n-\t\tdev_err(dev,\n-\t\t\t\"Failed to poll max10 doorbell register [e:%d]\\n\",\n-\t\t\tret);\n-\t\treturn ret;\n+\tret = opae_max10_read_poll_timeout(dev, doorbell_reg(dev),\n+\t\t\tdoorbell, cond_prog_ready(doorbell),\n+\t\t\tIFPGA_NIOS_HANDSHAKE_INTERVAL_US,\n+\t\t\tIFPGA_NIOS_HANDSHAKE_TIMEOUT_US);\n+\tif (ret == -ETIMEDOUT) {\n+\t\tprint_error_regs(dev);\n+\t\treturn IFPGA_SEC_ERR_TIMEOUT;\n+\t} else if (ret) {\n+\t\treturn IFPGA_SEC_ERR_RW_ERROR;\n \t}\n \n-\tret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);\n-\tif (ret < 0) {\n-\t\tdev_err(dev,\n-\t\t\t\"Failed to read max10 doorbell register [e:%d]\\n\",\n-\t\t\tret);\n-\t\treturn ret;\n+\tret = m10bmc_sec_status(dev, &status);\n+\tif (ret)\n+\t\treturn IFPGA_SEC_ERR_RW_ERROR;\n+\n+\tif (!rsu_status_ok(status)) {\n+\t\tprint_error_regs(dev);\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \t}\n \n-\tstatus = SEC_STATUS_G(doorbell);\n-\tswitch (status) {\n-\tcase SEC_STATUS_NORMAL:\n-\tcase SEC_STATUS_NIOS_OK:\n-\tcase SEC_STATUS_USER_OK:\n-\tcase SEC_STATUS_FACTORY_OK:\n-\t\tret = 0;\n-\t\tbreak;\n-\tdefault:\n-\t\tret = -EIO;\n-\t\tbreak;\n+\treturn IFPGA_SEC_ERR_NONE;\n+}\n+\n+static enum ifpga_sec_err m10bmc_sec_check_complete(struct ifpga_sec_mgr *smgr)\n+{\n+\tstruct intel_max10_device *dev = NULL;\n+\tuint32_t doorbell, status, progress;\n+\n+\tif (!smgr || !smgr->max10_dev)\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n+\n+\tdev = smgr->max10_dev;\n+\n+\tif (m10bmc_sec_progress_status(dev, &doorbell, &progress, &status)) {\n+\t\tprint_error_regs(dev);\n+\t\treturn IFPGA_SEC_ERR_RW_ERROR;\n \t}\n \n-\treturn ret;\n+\tif (!rsu_status_ok(status)) {\n+\t\tprint_error_regs(dev);\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n+\t}\n+\n+\tif (rsu_progress_done(progress))\n+\t\treturn IFPGA_SEC_ERR_NONE;\n+\n+\tif (rsu_progress_busy(progress))\n+\t\treturn IFPGA_SEC_ERR_BUSY;\n+\n+\treturn IFPGA_SEC_ERR_HW_ERROR;\n }\n \n-static int n3000_check_complete(struct ifpga_sec_mgr *smgr)\n+static enum ifpga_sec_err m10bmc_sec_cancel(struct ifpga_sec_mgr *smgr)\n {\n \tstruct intel_max10_device *dev = NULL;\n \tuint32_t doorbell = 0;\n-\tuint32_t status = 0;\n-\tuint32_t prog = 0;\n \tint ret = 0;\n \n \tif (!smgr || !smgr->max10_dev)\n-\t\treturn -ENODEV;\n-\tdev = (struct intel_max10_device *)smgr->max10_dev;\n+\t\treturn IFPGA_SEC_ERR_HW_ERROR;\n \n-\tret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);\n+\tdev = smgr->max10_dev;\n+\n+\tret = max10_sys_read(dev, doorbell_reg(dev), &doorbell);\n \tif (ret < 0) {\n \t\tdev_err(dev,\n \t\t\t\"Failed to read max10 doorbell register [e:%d]\\n\",\n \t\t\tret);\n-\t\treturn ret;\n+\t\treturn IFPGA_SEC_ERR_RW_ERROR;\n \t}\n \n-\tstatus = SEC_STATUS_G(doorbell);\n-\tswitch (status) {\n-\tcase SEC_STATUS_NORMAL:\n-\tcase SEC_STATUS_NIOS_OK:\n-\tcase SEC_STATUS_USER_OK:\n-\tcase SEC_STATUS_FACTORY_OK:\n-\tcase SEC_STATUS_WEAROUT:\n-\t\tbreak;\n-\tdefault:\n-\t\treturn -EIO;\n+\tif (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY)\n+\t\treturn IFPGA_SEC_ERR_BUSY;\n+\n+\tret = max10_sys_update_bits(dev, doorbell_reg(dev), HOST_STATUS,\n+\t\tHOST_STATUS_S(HOST_STATUS_ABORT_RSU));\n+\n+\treturn ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;\n+}\n+\n+static uint64_t m10bmc_sec_hw_errinfo(struct ifpga_sec_mgr *smgr)\n+{\n+\tstruct intel_max10_device *dev = NULL;\n+\tuint32_t doorbell = IFPGA_HW_ERRINFO_POISON;\n+\tuint32_t auth_result = IFPGA_HW_ERRINFO_POISON;\n+\tuint32_t stat = 0;\n+\tuint32_t prog = 0;\n+\n+\tif (smgr && smgr->max10_dev) {\n+\t\tdev = smgr->max10_dev;\n+\t\tswitch (smgr->err_code) {\n+\t\tcase IFPGA_SEC_ERR_HW_ERROR:\n+\t\tcase IFPGA_SEC_ERR_TIMEOUT:\n+\t\tcase IFPGA_SEC_ERR_BUSY:\n+\t\tcase IFPGA_SEC_ERR_WEAROUT:\n+\t\t\tif (max10_sys_read(dev, doorbell_reg(dev),\n+\t\t\t\t\t&doorbell))\n+\t\t\t\tdoorbell = IFPGA_HW_ERRINFO_POISON;\n+\t\t\tif (max10_sys_read(dev, auth_result_reg(dev),\n+\t\t\t\t\t&auth_result))\n+\t\t\t\tauth_result = IFPGA_HW_ERRINFO_POISON;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tdoorbell = 0;\n+\t\t\tauth_result = 0;\n+\t\t\tbreak;\n+\t\t}\n \t}\n \n+\tstat = SEC_STATUS_G(doorbell);\n \tprog = SEC_PROGRESS_G(doorbell);\n-\tswitch (prog) {\n-\tcase SEC_PROGRESS_IDLE:\n-\tcase SEC_PROGRESS_RSU_DONE:\n-\t\treturn 0;\n-\tcase SEC_PROGRESS_AUTHENTICATING:\n-\tcase SEC_PROGRESS_COPYING:\n-\tcase SEC_PROGRESS_UPDATE_CANCEL:\n-\tcase SEC_PROGRESS_PROGRAM_KEY_HASH:\n-\t\treturn -EAGAIN;\n-\tcase SEC_PROGRESS_PREPARE:\n-\tcase SEC_PROGRESS_READY:\n-\t\treturn -EBUSY;\n-\tdefault:\n-\t\treturn -EIO;\n-\t}\n+\tdev_info(dev, \"Current RSU status is %s, progress is %s\\n\",\n+\t\trsu_status_name(stat), rsu_progress_name(prog));\n \n-\treturn 0;\n+\treturn (uint64_t)doorbell << 32 | (uint64_t)auth_result;\n }\n \n-static int n3000_reload_fpga(struct intel_max10_device *dev, int page)\n+static int m10bmc_sec_fpga_image_load(struct ifpga_sec_mgr *smgr, int page)\n {\n+\tstruct intel_max10_device *dev = NULL;\n \tint ret = 0;\n \n \tdev_info(dev, \"Reload FPGA\\n\");\n \n-\tif (!dev || ((page != 0) && (page != 1))) {\n-\t\tdev_err(dev, \"Input parameter of %s is invalid\\n\", __func__);\n-\t\tret = -EINVAL;\n-\t\tgoto end;\n-\t}\n+\tif (!smgr || !smgr->max10_dev)\n+\t\treturn -ENODEV;\n+\n+\tdev = smgr->max10_dev;\n \n \tif (dev->flags & MAX10_FLAGS_SECURE) {\n \t\tret = max10_sys_update_bits(dev, FPGA_RECONF_REG,\n@@ -471,117 +894,210 @@ static int n3000_reload_fpga(struct intel_max10_device *dev, int page)\n \treturn ret;\n }\n \n-static int n3000_reload_bmc(struct intel_max10_device *dev, int page)\n+static int m10bmc_sec_bmc_image_load(struct ifpga_sec_mgr *smgr, int page)\n {\n-\tuint32_t val = 0;\n+\tstruct intel_max10_device *dev = NULL;\n+\tuint32_t doorbell = 0;\n \tint ret = 0;\n \n \tdev_info(dev, \"Reload BMC\\n\");\n \n-\tif (!dev || ((page != 0) && (page != 1))) {\n-\t\tdev_err(dev, \"Input parameter of %s is invalid\\n\", __func__);\n-\t\tret = -EINVAL;\n-\t\tgoto end;\n-\t}\n+\tif (!smgr || !smgr->max10_dev)\n+\t\treturn -ENODEV;\n \n-\tif (dev->flags & MAX10_FLAGS_SECURE) {\n-\t\tret = max10_sys_update_bits(dev, MAX10_DOORBELL,\n-\t\t\tCONFIG_SEL | REBOOT_REQ,\n-\t\t\tCONFIG_SEL_S(page) | REBOOT_REQ);\n-\t} else {\n-\t\tval = (page == 0) ? 0x1 : 0x3;\n-\t\tret = max10_sys_raw_write(dev, IFPGA_DUAL_CFG_CTRL1, val);\n-\t\tif (ret < 0) {\n-\t\t\tdev_err(dev,\n-\t\t\t\t\"Failed to write to dual config1 register [e:%d]\\n\",\n-\t\t\t\tret);\n-\t\t\tgoto end;\n-\t\t}\n+\tdev = smgr->max10_dev;\n \n-\t\tret = max10_sys_raw_write(dev, IFPGA_DUAL_CFG_CTRL0, 0x1);\n-\t\tif (ret < 0) {\n-\t\t\tif (ret == -EIO) {\n-\t\t\t\tret = 0;\n-\t\t\t\tgoto end;\n-\t\t\t}\n-\t\t\tdev_err(dev,\n-\t\t\t\t\"Failed to write to dual config0 register [e:%d]\\n\",\n+\tret = max10_sys_read(dev, doorbell_reg(dev), &doorbell);\n+\tif (ret < 0) {\n+\t\tdev_err(dev, \"Failed to read max10 doorbell register [e:%d]\\n\",\n \t\t\t\tret);\n-\t\t}\n+\t\treturn ret;\n \t}\n \n-end:\n-\tif (ret < 0)\n-\t\tdev_err(dev, \"Failed to reload BMC\\n\");\n+\tswitch (dev->type) {\n+\tcase N3000BMC_SEC:\n+\t\tif (doorbell & REBOOT_DISABLED)\n+\t\t\treturn -EBUSY;\n+\n+\t\tret = max10_sys_update_bits(dev, doorbell_reg(dev),\n+\t\t\tCONFIG_SEL | REBOOT_REQ,\n+\t\t\tCONFIG_SEL_S(page) | REBOOT_REQ);\n+\t\tbreak;\n+\tcase N6000BMC_SEC:\n+\t\tif (doorbell & PMCI_DRBL_REBOOT_DISABLED)\n+\t\t\treturn -EBUSY;\n+\n+\t\tret = max10_sys_update_bits(dev, m10bmc_base(dev) +\n+\t\t\t\tM10BMC_PMCI_MAX10_RECONF,\n+\t\t\t\tPMCI_MAX10_REBOOT_REQ | PMCI_MAX10_REBOOT_PAGE,\n+\t\t\t\tSET_FIELD(PMCI_MAX10_REBOOT_PAGE, page) |\n+\t\t\t\tPMCI_MAX10_REBOOT_REQ);\n+\t\tbreak;\n+\tdefault:\n+\t\tret = -EINVAL;\n+\t\tbreak;\n+\t}\n \n \treturn ret;\n }\n \n-static int n3000_reload(struct ifpga_sec_mgr *smgr, int type, int page)\n+static int pmci_sec_fpga_image_load(struct ifpga_sec_mgr *smgr,\n+\t\t\t\t    unsigned int val)\n {\n-\tint psel = 0;\n-\tint ret = 0;\n+\tstruct intel_max10_device *dev;\n+\tint ret;\n \n \tif (!smgr || !smgr->max10_dev)\n \t\treturn -ENODEV;\n \n-\tif (type == IFPGA_BOOT_TYPE_FPGA) {\n-\t\tpsel = (page == IFPGA_BOOT_PAGE_FACTORY ? 0 : 1);\n-\t\tret = n3000_reload_fpga(smgr->max10_dev, psel);\n-\t} else if (type == IFPGA_BOOT_TYPE_BMC) {\n-\t\tpsel = (page == IFPGA_BOOT_PAGE_FACTORY ? 1 : 0);\n-\t\tret = n3000_reload_bmc(smgr->max10_dev, psel);\n-\t} else {\n-\t\tret = -EINVAL;\n+\tdev = smgr->max10_dev;\n+\n+\tif (val > 2) {\n+\t\tdev_err(dev, \"%s invalid reload val = %d\\n\",\n+\t\t\t__func__, val);\n+\t\treturn -EINVAL;\n \t}\n \n-\treturn ret;\n+\tret = max10_sys_update_bits(dev,\n+\t\t\t\t M10BMC_PMCI_FPGA_RECONF,\n+\t\t\t\t PMCI_FPGA_RP_LOAD, 0);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn max10_sys_update_bits(dev,\n+\t\t\t\t  M10BMC_PMCI_FPGA_RECONF,\n+\t\t\t\t  PMCI_FPGA_RECONF_PAGE | PMCI_FPGA_RP_LOAD,\n+\t\t\t\t  SET_FIELD(PMCI_FPGA_RECONF_PAGE, val) |\n+\t\t\t\t  PMCI_FPGA_RP_LOAD);\n }\n \n-static uint64_t n3000_get_hw_errinfo(struct ifpga_sec_mgr *smgr)\n+static int n3000_sec_fpga_image_load_0(struct ifpga_sec_mgr *smgr)\n {\n-\tstruct intel_max10_device *dev = NULL;\n-\tuint32_t doorbell = 0;\n-\tuint32_t stat = 0;\n-\tuint32_t prog = 0;\n-\tuint32_t auth_result = 0;\n-\tint ret = 0;\n+\treturn m10bmc_sec_fpga_image_load(smgr, 0);\n+}\n \n-\tif (!smgr || !smgr->max10_dev)\n-\t\treturn -ENODEV;\n-\tdev = (struct intel_max10_device *)smgr->max10_dev;\n+static int n3000_sec_fpga_image_load_1(struct ifpga_sec_mgr *smgr)\n+{\n+\treturn m10bmc_sec_fpga_image_load(smgr, 1);\n+}\n \n-\tret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);\n-\tif (ret < 0) {\n-\t\tdev_err(dev, \"Failed to read max10 doorbell register [e:%d]\\n\",\n-\t\t\tret);\n-\t\treturn -1;\n-\t}\n-\tstat = SEC_STATUS_G(doorbell);\n-\tprog = SEC_PROGRESS_G(doorbell);\n-\tdev_debug(dev, \"Current RSU status is %s, progress is %s\\n\",\n-\t\trsu_status_name(stat), rsu_progress_name(prog));\n+static int n3000_sec_bmc_image_load_0(struct ifpga_sec_mgr *smgr)\n+{\n+\treturn m10bmc_sec_bmc_image_load(smgr, 0);\n+}\n \n-\tret = max10_sys_read(dev, MAX10_AUTH_RESULT, &auth_result);\n-\tif (ret < 0) {\n-\t\tdev_err(dev,\n-\t\t\t\"Failed to read authenticate result register [e:%d]\\n\",\n-\t\t\tret);\n-\t\treturn -1;\n-\t}\n+static int n3000_sec_bmc_image_load_1(struct ifpga_sec_mgr *smgr)\n+{\n+\treturn m10bmc_sec_bmc_image_load(smgr, 1);\n+}\n \n-\treturn (uint64_t)doorbell << 32 | (uint64_t)auth_result;\n+static int pmci_sec_bmc_image_load_0(struct ifpga_sec_mgr *smgr)\n+{\n+\treturn m10bmc_sec_bmc_image_load(smgr, 0);\n+}\n+\n+static int pmci_sec_bmc_image_load_1(struct ifpga_sec_mgr *smgr)\n+{\n+\treturn m10bmc_sec_bmc_image_load(smgr, 1);\n+}\n+\n+static int pmci_sec_fpga_image_load_0(struct ifpga_sec_mgr *smgr)\n+{\n+\treturn pmci_sec_fpga_image_load(smgr, 0);\n+}\n+\n+static int pmci_sec_fpga_image_load_1(struct ifpga_sec_mgr *smgr)\n+{\n+\treturn pmci_sec_fpga_image_load(smgr, 1);\n+}\n+\n+static int pmci_sec_fpga_image_load_2(struct ifpga_sec_mgr *smgr)\n+{\n+\treturn pmci_sec_fpga_image_load(smgr, 2);\n+}\n+\n+static int pmci_sec_sdm_image_load(struct ifpga_sec_mgr *smgr)\n+{\n+\tstruct intel_max10_device *dev = smgr->max10_dev;\n+\n+\treturn max10_sys_update_bits(dev,\n+\t\t\tm10bmc_base(dev) + M10BMC_PMCI_SDM_CTRL_STS,\n+\t\t\tPMCI_SDM_IMG_REQ, PMCI_SDM_IMG_REQ);\n }\n \n-static const struct ifpga_sec_ops n3000_sec_ops = {\n-\t.prepare = n3000_prepare,\n-\t.write_blk = n3000_write_blk,\n-\t.write_done = n3000_write_done,\n-\t.check_complete = n3000_check_complete,\n-\t.reload = n3000_reload,\n-\t.cancel = n3000_cancel,\n-\t.cleanup = NULL,\n-\t.get_hw_errinfo = n3000_get_hw_errinfo,\n+static struct image_load n3000_image_load_hndlrs[] = {\n+\t{\n+\t\t.name = \"fpga_factory\",\n+\t\t.load_image = n3000_sec_fpga_image_load_0,\n+\t},\n+\t{\n+\t\t.name = \"fpga_user\",\n+\t\t.load_image = n3000_sec_fpga_image_load_1,\n+\t},\n+\t{\n+\t\t.name = \"bmc_factory\",\n+\t\t.load_image = n3000_sec_bmc_image_load_1,\n+\t},\n+\t{\n+\t\t.name = \"bmc_user\",\n+\t\t.load_image = n3000_sec_bmc_image_load_0,\n+\t},\n+\t{}\n+};\n+\n+static struct image_load pmci_image_load_hndlrs[] = {\n+\t{\n+\t\t.name = \"bmc_factory\",\n+\t\t.load_image = pmci_sec_bmc_image_load_0,\n+\t},\n+\t{\n+\t\t.name = \"bmc_user\",\n+\t\t.load_image = pmci_sec_bmc_image_load_1,\n+\t},\n+\t{\n+\t\t.name = \"fpga_factory\",\n+\t\t.load_image = pmci_sec_fpga_image_load_0,\n+\t},\n+\t{\n+\t\t.name = \"fpga_user1\",\n+\t\t.load_image = pmci_sec_fpga_image_load_1,\n+\t},\n+\t{\n+\t\t.name = \"fpga_user2\",\n+\t\t.load_image = pmci_sec_fpga_image_load_2,\n+\t},\n+\t{\n+\t\t.name = \"sdm\",\n+\t\t.load_image = pmci_sec_sdm_image_load,\n+\t},\n+\t{}\n+};\n+\n+static const struct ifpga_sec_mgr_ops n3000_sec_ops = {\n+\t.prepare = m10bmc_sec_prepare,\n+\t.write_blk = m10bmc_sec_write_blk,\n+\t.write_done = m10bmc_sec_write_done,\n+\t.check_complete = m10bmc_sec_check_complete,\n+\t.cancel = m10bmc_sec_cancel,\n+\t.get_hw_errinfo = m10bmc_sec_hw_errinfo,\n+\t.image_load = n3000_image_load_hndlrs,\n+};\n+\n+static const struct ifpga_sec_mgr_ops pmci_sec_ops = {\n+\t.prepare = m10bmc_sec_prepare,\n+\t.write_blk = pmci_sec_write_blk,\n+\t.write_done = m10bmc_sec_write_done,\n+\t.check_complete = m10bmc_sec_check_complete,\n+\t.cancel = m10bmc_sec_cancel,\n+\t.get_hw_errinfo = m10bmc_sec_hw_errinfo,\n+\t.image_load = pmci_image_load_hndlrs,\n+};\n+\n+static const struct fpga_power_on pmci_power_on_image = {\n+\t.avail_image_mask = BIT(FPGA_FACTORY) |\n+\t\tBIT(FPGA_USER1) | BIT(FPGA_USER2),\n+\t.set_sequence = pmci_set_power_on_image,\n+\t.get_sequence = pmci_get_power_on_image,\n };\n \n int init_sec_mgr(struct ifpga_fme_hw *fme, enum fpga_sec_type type)\n@@ -610,19 +1126,25 @@ int init_sec_mgr(struct ifpga_fme_hw *fme, enum fpga_sec_type type)\n \t\tsmgr->rsu_status = NULL;\n \t}\n \n-\tif (hw && (hw->pci_data->device_id == IFPGA_N3000_DID) &&\n-\t\t(hw->pci_data->vendor_id == IFPGA_N3000_VID)) {\n-\t\tsmgr->ops = &n3000_sec_ops;\n-\t\tsmgr->copy_speed = IFPGA_N3000_COPY_SPEED;\n-\t} else {\n-\t\tdev_err(NULL, \"No operation for security manager\\n\");\n-\t\tsmgr->ops = NULL;\n-\t}\n-\n \tsmgr->fme = fme;\n \tsmgr->max10_dev = fme->max10_dev;\n \tsmgr->type = type;\n \n+\tswitch (type) {\n+\tcase N3000BMC_SEC:\n+\t\tsmgr->sops = &n3000_sec_ops;\n+\t\tsmgr->copy_speed = IFPGA_N3000_COPY_SPEED;\n+\t\tbreak;\n+\tcase N6000BMC_SEC:\n+\t\tsmgr->sops = &pmci_sec_ops;\n+\t\tsmgr->copy_speed = IFPGA_N3000_COPY_SPEED;\n+\t\tsmgr->poc = &pmci_power_on_image;\n+\t\tbreak;\n+\tdefault:\n+\t\tdev_err(NULL, \"No operation for security manager\\n\");\n+\t\tsmgr->sops = NULL;\n+\t}\n+\n \treturn 0;\n }\n \ndiff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.h b/drivers/raw/ifpga/base/ifpga_sec_mgr.h\nindex 09cc038..0b2e1ac 100644\n--- a/drivers/raw/ifpga/base/ifpga_sec_mgr.h\n+++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.h\n@@ -25,35 +25,44 @@\n #define IFPGA_N3000_COPY_SPEED   42700\n \n /* status */\n-#define IFPGA_RSU_IDLE       0\n-#define IFPGA_RSU_PREPARE    1\n-#define IFPGA_RSU_READY      2\n-#define IFPGA_RSU_COPYING    3\n-#define IFPGA_RSU_REBOOT     4\n+#define IFPGA_RSU_IDLE         0\n+#define IFPGA_RSU_PREPARING    1\n+#define IFPGA_RSU_WRITING      2\n+#define IFPGA_RSU_PROGRAMMING  3\n+#define IFPGA_RSU_REBOOT       4\n \n-#define IFPGA_RSU_GET_STAT(v)  (((v) >> 16) & 0xffff)\n-#define IFPGA_RSU_GET_PROG(v)  ((v) & 0xffff)\n-#define IFPGA_RSU_STATUS(s, p) ((((s) << 16) & 0xffff0000) | ((p) & 0xffff))\n+#define IFPGA_RSU_GET_STAT(v)  (((v) >> 16) & 0xff)\n+#define IFPGA_RSU_GET_PROG(v)  ((v) & 0xff)\n+#define IFPGA_RSU_STATUS(s, p) ((((s) << 16) & 0xff0000) | ((p) & 0xff))\n \n /* control */\n-#define IFPGA_RSU_ABORT      1\n+#define IFPGA_RSU_CANCEL         1\n+\n+#define IFPGA_HW_ERRINFO_POISON  0xffffffff\n \n #define IFPGA_DUAL_CFG_CTRL0     0x200020\n #define IFPGA_DUAL_CFG_CTRL1     0x200024\n \n-#define IFPGA_SEC_START_INTERVAL_MS       100\n-#define IFPGA_SEC_START_TIMEOUT_MS        20000\n-#define IFPGA_NIOS_HANDSHAKE_INTERVAL_MS  100\n-#define IFPGA_NIOS_HANDSHAKE_TIMEOUT_MS   5000\n-\n-#define IFPGA_RSU_ERR_HW_ERROR\t\t-1\n-#define IFPGA_RSU_ERR_TIMEOUT\t\t-2\n-#define IFPGA_RSU_ERR_CANCELED\t\t-3\n-#define IFPGA_RSU_ERR_BUSY\t\t\t-4\n-#define IFPGA_RSU_ERR_INVALID_SIZE\t-5\n-#define IFPGA_RSU_ERR_RW_ERROR\t\t-6\n-#define IFPGA_RSU_ERR_WEAROUT\t\t-7\n-#define IFPGA_RSU_ERR_FILE_READ\t\t-8\n+#define IFPGA_NIOS_HANDSHAKE_INTERVAL_US  (100 * 1000)\n+#define IFPGA_NIOS_HANDSHAKE_TIMEOUT_US   (5000 * 1000)\n+/* Wait about 2 minutes to erase flash staging area */\n+#define IFPGA_RSU_PREP_INTERVAL_US        (100 * 1000)\n+#define IFPGA_RSU_PREP_TIMEOUT_US         (120000 * 1000)\n+\n+enum ifpga_sec_err {\n+\tIFPGA_SEC_ERR_NONE = 0,\n+\tIFPGA_SEC_ERR_HW_ERROR,\n+\tIFPGA_SEC_ERR_TIMEOUT,\n+\tIFPGA_SEC_ERR_CANCELED,\n+\tIFPGA_SEC_ERR_BUSY,\n+\tIFPGA_SEC_ERR_INVALID_SIZE,\n+\tIFPGA_SEC_ERR_RW_ERROR,\n+\tIFPGA_SEC_ERR_WEAROUT,\n+\tIFPGA_SEC_ERR_FILE_READ,\n+\tIFPGA_SEC_ERR_NO_MEM,\n+\tIFPGA_SEC_ERR_NO_FUNC,\n+\tIFPGA_SEC_ERR_MAX\n+};\n \n /* Supported fpga secure manager types */\n enum fpga_sec_type {\n@@ -61,32 +70,57 @@ enum fpga_sec_type {\n \tN6000BMC_SEC\n };\n \n+/* Supported names for power-on images */\n+enum fpga_image {\n+\tFPGA_FACTORY,\n+\tFPGA_USER1,\n+\tFPGA_USER2,\n+\tFPGA_MAX\n+};\n+\n struct ifpga_sec_mgr;\n \n-struct ifpga_sec_ops {\n-\tint (*prepare)(struct ifpga_sec_mgr *smgr);\n-\tint (*write_blk)(struct ifpga_sec_mgr *smgr, char *buf, uint32_t offset,\n-\t\tuint32_t size);\n-\tint (*write_done)(struct ifpga_sec_mgr *smgr);\n-\tint (*check_complete)(struct ifpga_sec_mgr *smgr);\n-\tint (*reload)(struct ifpga_sec_mgr *smgr, int type, int page);\n-\tint (*cancel)(struct ifpga_sec_mgr *smgr);\n+struct image_load {\n+\tconst char *name;\n+\tint (*load_image)(struct ifpga_sec_mgr *smgr);\n+};\n+\n+struct fpga_power_on {\n+\tu32 avail_image_mask;\n+\tint (*get_sequence)(struct ifpga_sec_mgr *smgr, char *buf,\n+\t\t\tsize_t size);\n+\tint (*set_sequence)(struct ifpga_sec_mgr *smgr,\n+\t\t\tenum fpga_image images[]);\n+};\n+\n+struct ifpga_sec_mgr_ops {\n+\tenum ifpga_sec_err (*prepare)(struct ifpga_sec_mgr *smgr);\n+\tenum ifpga_sec_err (*write_blk)(struct ifpga_sec_mgr *smgr,\n+\t\tuint32_t offset, uint32_t size);\n+\tenum ifpga_sec_err (*write_done)(struct ifpga_sec_mgr *smgr);\n+\tenum ifpga_sec_err (*check_complete)(struct ifpga_sec_mgr *smgr);\n+\tenum ifpga_sec_err (*cancel)(struct ifpga_sec_mgr *smgr);\n \tvoid (*cleanup)(struct ifpga_sec_mgr *smgr);\n \tu64 (*get_hw_errinfo)(struct ifpga_sec_mgr *smgr);\n+\tstruct image_load *image_load;  /* terminated with { } member */\n };\n \n struct ifpga_sec_mgr {\n \tstruct ifpga_fme_hw *fme;\n \tstruct intel_max10_device *max10_dev;\n-\tunsigned int rsu_length;\n-\t/* number of bytes that copied from staging area to working area\n-\t * in one second, which is calculated by experiment\n-\t */\n-\tunsigned int copy_speed;\n-\tunsigned int *rsu_control;\n \tunsigned int *rsu_status;\n-\tconst struct ifpga_sec_ops *ops;\n+\tunsigned int *rsu_control;\n+\tunsigned int one_percent;  /* use to calculate progress value */\n+\tunsigned int copy_speed;  /* flash copy speed in bytes/second */\n+\n+\tconst struct ifpga_sec_mgr_ops *sops;\n+\tconst char *filename;\n+\tchar *data;\t\t/* pointer to update data */\n+\tu32 remaining_size;\t\t/* size remaining to transfer */\n+\tenum ifpga_sec_err err_code;\n+\tu64 hw_errinfo;  /* 64 bits of HW specific error info */\n \tenum fpga_sec_type type;\n+\tconst struct fpga_power_on *poc; /* power on image configuration */\n };\n \n int init_sec_mgr(struct ifpga_fme_hw *fme, enum fpga_sec_type type);\n@@ -94,7 +128,12 @@ struct ifpga_sec_mgr {\n int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image,\n \tuint64_t *status);\n int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force);\n-int fpga_reload(struct ifpga_fme_hw *fme, int type, int page);\n+int fpga_reload(struct ifpga_fme_hw *fme, char *str);\n+int fpga_available_images(struct ifpga_fme_hw *fme, char *buf, size_t size);\n+int fpga_set_poc_image(struct ifpga_fme_hw *fme, char *buf);\n+int fpga_get_poc_images(struct ifpga_fme_hw *fme, char *buf, size_t size);\n \n+int pmci_set_poc_image(struct ifpga_sec_mgr *smgr, char *buf);\n+int pmci_get_poc_images(struct ifpga_sec_mgr *smgr, char *buf, size_t size);\n \n #endif /* _IFPGA_FME_RSU_H_ */\ndiff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c\nindex 6b78094..ada3d29 100644\n--- a/drivers/raw/ifpga/base/opae_hw_api.c\n+++ b/drivers/raw/ifpga/base/opae_hw_api.c\n@@ -1055,18 +1055,94 @@ int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force)\n /**\n  * opae_mgr_reload -  reload FPGA.\n  * @mgr: targeted manager\n- * @type: FPGA type\n- * @page: reload from which page\n+ * @str: name of reload image type\n  *\n  * Return: 0 on success, otherwise error code.\n  */\n-int opae_mgr_reload(struct opae_manager *mgr, int type, int page)\n+int opae_mgr_reload(struct opae_manager *mgr, char *str)\n {\n \tif (!mgr)\n \t\treturn -EINVAL;\n \n \tif (mgr->ops && mgr->ops->reload)\n-\t\treturn mgr->ops->reload(mgr, type, page);\n+\t\treturn mgr->ops->reload(mgr, str);\n+\n+\treturn -ENOENT;\n+}\n+\n+/**\n+ * opae_mgr_available_images -  get available load image types.\n+ * @mgr: targeted manager\n+ * @buf: buffer to fill with image type list\n+ * @size: size of the buffer\n+ *\n+ * Return: 0 or positive value on success, otherwise error code.\n+ */\n+int opae_mgr_available_images(struct opae_manager *mgr, char *buf, size_t size)\n+{\n+\tif (!mgr)\n+\t\treturn -EINVAL;\n+\n+\tif (mgr->ops && mgr->ops->available_images)\n+\t\treturn mgr->ops->available_images(mgr, buf, size);\n+\n+\treturn -ENOENT;\n+}\n+\n+/**\n+ * opae_mgr_get_poc_images -  get available power_on_images.\n+ * @mgr: targeted manager\n+ * @buf: buffer to fill with image type list\n+ * @size: size of the buffer\n+ *\n+ * Return: 0 or positive value on success, otherwise error code.\n+ */\n+int opae_mgr_get_poc_images(struct opae_manager *mgr, char *buf, size_t size)\n+{\n+\tif (!mgr)\n+\t\treturn -EINVAL;\n+\n+\tif (mgr->ops && mgr->ops->get_poc_images)\n+\t\treturn mgr->ops->get_poc_images(mgr, buf, size);\n+\n+\treturn -ENOENT;\n+}\n+\n+/**\n+ * opae_mgr_set_poc_image -  configure the FPGA power_on_image.\n+ * @mgr: targeted manager\n+ * @str: name of power_on_image\n+ *\n+ * Return: 0 on success, otherwise error code.\n+ */\n+int opae_mgr_set_poc_image(struct opae_manager *mgr, char *str)\n+{\n+\tif (!mgr)\n+\t\treturn -EINVAL;\n+\n+\tif (mgr->ops && mgr->ops->set_poc_image)\n+\t\treturn mgr->ops->set_poc_image(mgr, str);\n+\n+\treturn -ENOENT;\n+}\n+\n+/**\n+ * opae_mgr_read_flash -  read flash content\n+ * @mgr: targeted manager\n+ * @address: the start address of flash\n+ * @size: the size of flash\n+ * @buf: the read buffer\n+ *\n+ * Return: 0 on success, otherwise error code.\n+ */\n+int opae_mgr_read_flash(struct opae_manager *mgr, u32 address,\n+\t\tu32 size, void *buf)\n+{\n+\tif (!mgr)\n+\t\treturn -EINVAL;\n+\n+\tif (mgr->ops && mgr->ops->read_flash)\n+\t\treturn mgr->ops->read_flash(mgr, address, size, buf);\n \n \treturn -ENOENT;\n }\ndiff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h\nindex 8aead4d..1e31d1e 100644\n--- a/drivers/raw/ifpga/base/opae_hw_api.h\n+++ b/drivers/raw/ifpga/base/opae_hw_api.h\n@@ -59,7 +59,13 @@ struct opae_manager_ops {\n \tint (*update_flash)(struct opae_manager *mgr, const char *image,\n \t\t\tu64 *status);\n \tint (*stop_flash_update)(struct opae_manager *mgr, int force);\n-\tint (*reload)(struct opae_manager *mgr, int type, int page);\n+\tint (*reload)(struct opae_manager *mgr, char *str);\n+\tint (*available_images)(struct opae_manager *mgr, char *buf,\n+\t\t\tsize_t size);\n+\tint (*get_poc_images)(struct opae_manager *mgr, char *buf,\n+\t\t\tsize_t size);\n+\tint (*set_poc_image)(struct opae_manager *mgr, char *str);\n+\tint (*read_flash)(struct opae_manager *mgr, u32 address, u32 size, void *buf);\n };\n \n /* networking management ops in FME */\n@@ -368,5 +374,9 @@ int opae_mgr_get_board_info(struct opae_manager *mgr,\n int opae_mgr_update_flash(struct opae_manager *mgr, const char *image,\n \t\tuint64_t *status);\n int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force);\n-int opae_mgr_reload(struct opae_manager *mgr, int type, int page);\n+int opae_mgr_reload(struct opae_manager *mgr, char *str);\n+int opae_mgr_available_images(struct opae_manager *mgr, char *buf, size_t size);\n+int opae_mgr_set_poc_image(struct opae_manager *mgr, char *str);\n+int opae_mgr_get_poc_images(struct opae_manager *mgr, char *buf, size_t size);\n+int opae_mgr_read_flash(struct opae_manager *mgr, u32 address, u32 size, void *buf);\n #endif /* _OPAE_HW_API_H_*/\ndiff --git a/drivers/raw/ifpga/rte_pmd_ifpga.c b/drivers/raw/ifpga/rte_pmd_ifpga.c\nindex 2314643..fda7cae 100644\n--- a/drivers/raw/ifpga/rte_pmd_ifpga.c\n+++ b/drivers/raw/ifpga/rte_pmd_ifpga.c\n@@ -6,6 +6,7 @@\n #include <rte_bus_pci.h>\n #include <rte_rawdev.h>\n #include <rte_rawdev_pmd.h>\n+#include \"base/opae_hw_api.h\"\n #include \"rte_pmd_ifpga.h\"\n #include \"ifpga_rawdev.h\"\n #include \"base/ifpga_api.h\"\n@@ -390,16 +391,104 @@\n \treturn 0;\n }\n \n+static int\n+get_image_load_string(struct opae_adapter *adapter, int type, int page,\n+\tchar *str, size_t size)\n+{\n+\tstruct opae_adapter_data_pci *pci_data = NULL;\n+\n+\tpci_data = (struct opae_adapter_data_pci *)adapter->data;\n+\tif (!pci_data || (pci_data->type != OPAE_FPGA_PCI))\n+\t\treturn -EINVAL;\n+\n+\tif (type == 0) {\n+\t\tif (pci_data->device_id == IFPGA_N3000_ID) {\n+\t\t\tif (page == 0)\n+\t\t\t\tsnprintf(str, size, \"fpga_factory\");\n+\t\t\telse\n+\t\t\t\tsnprintf(str, size, \"fpga_user\");\n+\t\t} else if (pci_data->device_id == IFPGA_N6000_ID) {\n+\t\t\tif (page == 0)\n+\t\t\t\tsnprintf(str, size, \"fpga_factory\");\n+\t\t\telse if (page == 1)\n+\t\t\t\tsnprintf(str, size, \"fpga_user1\");\n+\t\t\telse if (page == 2)\n+\t\t\t\tsnprintf(str, size, \"fpga_user2\");\n+\t\t\telse\n+\t\t\t\tsnprintf(str, size, \"sdm\");\n+\t\t}\n+\t} else {\n+\t\tif (page == 0)\n+\t\t\tsnprintf(str, size, \"bmc_factory\");\n+\t\telse\n+\t\t\tsnprintf(str, size, \"bmc_user\");\n+\t}\n+\n+\treturn 0;\n+}\n+\n int\n rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page)\n {\n \tstruct opae_adapter *adapter = NULL;\n+\tchar str[RTE_RAWDEV_NAME_MAX_LEN] = {0};\n+\n+\tadapter = get_opae_adapter(dev_id);\n+\tif (!adapter)\n+\t\treturn -ENODEV;\n+\n+\tif (get_image_load_string(adapter, type, page, str, sizeof(str)))\n+\t\treturn -EINVAL;\n+\n+\treturn opae_mgr_reload(adapter->mgr, str);\n+}\n+\n+int\n+rte_pmd_ifpga_image_load(uint16_t dev_id, char *str)\n+{\n+\tstruct opae_adapter *adapter = NULL;\n+\n+\tadapter = get_opae_adapter(dev_id);\n+\tif (!adapter)\n+\t\treturn -ENODEV;\n+\n+\treturn opae_mgr_reload(adapter->mgr, str);\n+}\n+\n+int\n+rte_pmd_ifpga_get_available_images(uint16_t dev_id, char *buf, size_t size)\n+{\n+\tstruct opae_adapter *adapter = NULL;\n+\n+\tadapter = get_opae_adapter(dev_id);\n+\tif (!adapter)\n+\t\treturn -ENODEV;\n+\n+\treturn opae_mgr_available_images(adapter->mgr, buf, size);\n+}\n+\n+int\n+rte_pmd_ifpga_set_poc_image(uint16_t dev_id, char *str)\n+{\n+\tstruct opae_adapter *adapter = NULL;\n \n \tadapter = get_opae_adapter(dev_id);\n \tif (!adapter)\n \t\treturn -ENODEV;\n \n-\treturn opae_mgr_reload(adapter->mgr, type, page);\n+\treturn opae_mgr_set_poc_image(adapter->mgr, str);\n+}\n+\n+int\n+rte_pmd_ifpga_get_poc_images(uint16_t dev_id, char *buf, size_t size)\n+{\n+\tstruct opae_adapter *adapter = NULL;\n+\n+\tadapter = get_opae_adapter(dev_id);\n+\tif (!adapter)\n+\t\treturn -ENODEV;\n+\n+\treturn opae_mgr_get_poc_images(adapter->mgr, buf, size);\n }\n \n const struct rte_pci_bus *\n@@ -422,6 +511,19 @@\n \treturn ifpga_rawdev_partial_reconfigure(dev, port, file);\n }\n \n+int\n+rte_pmd_ifpga_read_flash(uint16_t dev_id, uint32_t address, uint32_t size,\n+\t\tvoid *buf)\n+{\n+\tstruct opae_adapter *adapter;\n+\n+\tadapter = get_opae_adapter(dev_id);\n+\tif (!adapter)\n+\t\treturn -ENODEV;\n+\n+\treturn opae_mgr_read_flash(adapter->mgr, address, size, buf);\n+}\n+\n void\n rte_pmd_ifpga_cleanup(void)\n {\ndiff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h b/drivers/raw/ifpga/rte_pmd_ifpga.h\nindex 3fa5d34..2a6a502 100644\n--- a/drivers/raw/ifpga/rte_pmd_ifpga.h\n+++ b/drivers/raw/ifpga/rte_pmd_ifpga.h\n@@ -21,6 +21,8 @@\n #include <stdint.h>\n \n #define IFPGA_MAX_PORT_NUM   4\n+#define IFPGA_N3000_ID    0x0B30\n+#define IFPGA_N6000_ID    0xBCCE\n \n /**\n  * UUID data structure.\n@@ -216,6 +218,7 @@\n  *   - (-ENODEV) if dev_id is invalid.\n  *   - (-EINVAL) if bad parameter.\n  *   - (-EBUSY) if failed to access BMC register.\n+ *   - (-EOPNOTSUPP) if the specific image load not supported.\n  */\n int\n rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page);\n@@ -253,6 +256,120 @@\n void\n rte_pmd_ifpga_cleanup(void);\n \n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice\n+ *\n+ * Set which image to load for specified Intel FPGA device at power on\n+ *\n+ * @param dev_id\n+ *    The raw device ID of specified Intel FPGA device.\n+ * @param str\n+ *    name of the image to load from flash.\n+ * @return\n+ *   - (0) if successful.\n+ *   - (-ENODEV) if dev_id is invalid.\n+ *   - (-EINVAL) if bad parameter.\n+ *   - (-EBUSY) if failed to access BMC register.\n+ *   - (-EOPNOTSUPP) if the specific image load not supported.\n+ */\n+__rte_experimental\n+int\n+rte_pmd_ifpga_set_poc_image(uint16_t dev_id, char *str);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice\n+ *\n+ * Get available load image supported by specified Intel FPGA device\n+ *\n+ * @param dev_id\n+ *    The raw device ID of specified Intel FPGA device.\n+ * @param buf\n+ *    a space separated list of image type name will be filled in this buffer.\n+ *    buffer pointer can be NULL.\n+ * @param size\n+ *    when buf pointer is not NULL, indicate the size of the buffer.\n+ * @return\n+ *   - (0) no available load image type.\n+ *   - (>0) string length of the list including the terminating null character.\n+ *   - (-ENODEV) if dev_id is invalid.\n+ *   - (-EINVAL) if bad parameter.\n+ *   - (-EBUSY) if failed to access BMC register.\n+ */\n+__rte_experimental\n+int\n+rte_pmd_ifpga_get_poc_images(uint16_t dev_id, char *buf, size_t size);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice\n+ *\n+ * Trigger image load of specified Intel FPGA device\n+ *\n+ * @param dev_id\n+ *    The raw device ID of specified Intel FPGA device.\n+ * @param str\n+ *    name of the image to load from flash.\n+ * @return\n+ *   - (0) if successful.\n+ *   - (-ENODEV) if dev_id is invalid.\n+ *   - (-EINVAL) if bad parameter.\n+ *   - (-EBUSY) if failed to access BMC register.\n+ *   - (-EOPNOTSUPP) if the specific image load not supported.\n+ */\n+__rte_experimental\n+int\n+rte_pmd_ifpga_image_load(uint16_t dev_id, char *str);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice\n+ *\n+ * Get available load image supported by specified Intel FPGA device\n+ *\n+ * @param dev_id\n+ *    The raw device ID of specified Intel FPGA device.\n+ * @param buf\n+ *    a space separated list of image type name will be filled in this buffer.\n+ *    buffer pointer can be NULL.\n+ * @param size\n+ *    when buf pointer is not NULL, indicate the size of the buffer.\n+ * @return\n+ *   - (0) no available load image type.\n+ *   - (>0) string length of the list including the terminating null character.\n+ *   - (-ENODEV) if dev_id is invalid.\n+ *   - (-EINVAL) if bad parameter.\n+ *   - (-EBUSY) if failed to access BMC register.\n+ */\n+__rte_experimental\n+int\n+rte_pmd_ifpga_get_available_images(uint16_t dev_id, char *buf, size_t size);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice\n+ *\n+ * Read out flash content on specified Intel FPGA device\n+ *\n+ * @param dev_id\n+ *   The raw device ID of specified Intel FPGA device.\n+ * @param address\n+ *   The start address of the flash.\n+ * @param size\n+ *   The size of flash which want to read out.\n+ * @param buf\n+ *   The read buffer.\n+ * @return\n+ *   - (0) if successful.\n+ *   - (-EINVAL) if bad parameter or operation failed.\n+ *   - (-ENOMEM) if no available flash memory to access.\n+ */\n+__rte_experimental\n+int\n+rte_pmd_ifpga_read_flash(uint16_t dev_id, uint32_t address, uint32_t size,\n+\tvoid *buf);\n+\n #ifdef __cplusplus\n }\n #endif\ndiff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map\nindex ff71a45..a201124 100644\n--- a/drivers/raw/ifpga/version.map\n+++ b/drivers/raw/ifpga/version.map\n@@ -16,3 +16,14 @@ DPDK_22 {\n \n \tlocal: *;\n };\n+\n+EXPERIMENTAL {\n+\tglobal:\n+\n+\t# added in 22.07\n+\trte_pmd_ifpga_image_load;\n+\trte_pmd_ifpga_get_available_images;\n+\trte_pmd_ifpga_set_poc_image;\n+\trte_pmd_ifpga_get_poc_images;\n+\trte_pmd_ifpga_read_flash;\n+};\n",
    "prefixes": [
        "v1",
        "2/2"
    ]
}