> -----Original Message-----
> From: Huang, Wei <wei.hu...@intel.com>
> Sent: 2021年1月5日 15:09
> To: dev@dpdk.org; Xu, Rosen <rosen...@intel.com>; Zhang, Qi Z
> <qi.z.zh...@intel.com>
> Cc: sta...@dpdk.org; Zhang, Tianfei <tianfei.zh...@intel.com>; Huang, Wei
> <wei.hu...@intel.com>
> Subject: [PATCH v7 1/4] raw/ifpga: add fpga rsu function
>
> RSU (Remote System Update) depends on secure manager which may be
> different on various implementations, so a new secure manager device is
> implemented for adapting such difference.
> There are three major functions added:
> 1. ifpga_rawdev_update_flash() updates flash with specific image file.
> 2. ifpga_rawdev_stop_flash_update() aborts flash update process.
> 3. ifpga_rawdev_reload() reloads FPGA from updated flash.
>
> Signed-off-by: Wei Huang <wei.hu...@intel.com>
> ---
> v2: fix coding style issue in ifpga_fme_rsu.c and ifpga_sec_mgr.c
> ---
> v3: fix compilation issues in ifpga_fme_rsu.c
> ---
> v4: fix compilation issues in opae_intel_max10.c
> ---
> drivers/raw/ifpga/base/ifpga_api.c | 26 +
> drivers/raw/ifpga/base/ifpga_fme.c | 8 +
> drivers/raw/ifpga/base/ifpga_fme_rsu.c | 435 +++++++++++++++
> drivers/raw/ifpga/base/ifpga_hw.h | 1 +
> drivers/raw/ifpga/base/ifpga_sec_mgr.c | 639
> ++++++++++++++++++++++
> drivers/raw/ifpga/base/ifpga_sec_mgr.h | 89 +++
> drivers/raw/ifpga/base/meson.build | 2 +
> drivers/raw/ifpga/base/opae_hw_api.c | 59 ++
> drivers/raw/ifpga/base/opae_hw_api.h | 11 +
> drivers/raw/ifpga/base/opae_intel_max10.c | 48 ++
> drivers/raw/ifpga/base/opae_intel_max10.h | 44 ++
> drivers/raw/ifpga/ifpga_rawdev.c | 55 ++
> drivers/raw/ifpga/ifpga_rawdev.h | 7 +-
> 13 files changed, 1423 insertions(+), 1 deletion(-) create mode 100644
> drivers/raw/ifpga/base/ifpga_fme_rsu.c
> create mode 100644 drivers/raw/ifpga/base/ifpga_sec_mgr.c
> create mode 100644 drivers/raw/ifpga/base/ifpga_sec_mgr.h
>
> diff --git a/drivers/raw/ifpga/base/ifpga_api.c
> b/drivers/raw/ifpga/base/ifpga_api.c
> index 1ff57fa18..1aedf150b 100644
> --- a/drivers/raw/ifpga/base/ifpga_api.c
> +++ b/drivers/raw/ifpga/base/ifpga_api.c
> @@ -5,6 +5,7 @@
> #include "ifpga_api.h"
> #include "ifpga_enumerate.h"
> #include "ifpga_feature_dev.h"
> +#include "ifpga_sec_mgr.h"
>
> #include "opae_hw_api.h"
>
> @@ -228,11 +229,36 @@ static int ifpga_mgr_get_board_info(struct
> opae_manager *mgr,
> return 0;
> }
>
> +static int ifpga_mgr_update_flash(struct opae_manager *mgr, const char
> *image,
> + u64 *status)
> +{
> + struct ifpga_fme_hw *fme = mgr->data;
> +
> + return fpga_update_flash(fme, image, status); }
> +
> +static int ifpga_mgr_stop_flash_update(struct opae_manager *mgr, int
> +force) {
> + struct ifpga_fme_hw *fme = mgr->data;
> +
> + return fpga_stop_flash_update(fme, force); }
> +
> +static int ifpga_mgr_reload(struct opae_manager *mgr, int type, int
> +page) {
> + struct ifpga_fme_hw *fme = mgr->data;
> +
> + return fpga_reload(fme, type, page);
> +}
> +
> struct opae_manager_ops ifpga_mgr_ops = {
> .flash = ifpga_mgr_flash,
> .get_eth_group_region_info = ifpga_mgr_get_eth_group_region_info,
> .get_sensor_value = ifpga_mgr_get_sensor_value,
> .get_board_info = ifpga_mgr_get_board_info,
> + .update_flash = ifpga_mgr_update_flash,
> + .stop_flash_update = ifpga_mgr_stop_flash_update,
> + .reload = ifpga_mgr_reload,
> };
>
> static int ifpga_mgr_read_mac_rom(struct opae_manager *mgr, int offset,
> diff --git a/drivers/raw/ifpga/base/ifpga_fme.c
> b/drivers/raw/ifpga/base/ifpga_fme.c
> index f29ff3159..34fd9a818 100644
> --- a/drivers/raw/ifpga/base/ifpga_fme.c
> +++ b/drivers/raw/ifpga/base/ifpga_fme.c
> @@ -7,6 +7,7 @@
> #include "opae_intel_max10.h"
> #include "opae_i2c.h"
> #include "opae_at24_eeprom.h"
> +#include "ifpga_sec_mgr.h"
>
> #define PWR_THRESHOLD_MAX 0x7F
>
> @@ -1152,6 +1153,12 @@ static int fme_nios_spi_init(struct ifpga_feature
> *feature)
> if (spi_self_checking(max10))
> goto spi_fail;
>
> + ret = init_sec_mgr(fme);
> + if (ret) {
> + dev_err(fme, "security manager init fail\n");
> + goto spi_fail;
> + }
> +
> return ret;
>
> spi_fail:
> @@ -1165,6 +1172,7 @@ static void fme_nios_spi_uinit(struct ifpga_feature
> *feature) {
> struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent;
>
> + release_sec_mgr(fme);
> if (fme->max10_dev)
> intel_max10_device_remove(fme->max10_dev);
> }
> diff --git a/drivers/raw/ifpga/base/ifpga_fme_rsu.c
> b/drivers/raw/ifpga/base/ifpga_fme_rsu.c
> new file mode 100644
> index 000000000..fad1ac416
> --- /dev/null
> +++ b/drivers/raw/ifpga/base/ifpga_fme_rsu.c
> @@ -0,0 +1,435 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2020 Intel Corporation
> + */
> +
> +#include <fcntl.h>
> +#include <signal.h>
> +#include <unistd.h>
> +#include "ifpga_sec_mgr.h"
> +
> +static struct ifpga_sec_mgr *sec_mgr;
> +
> +static void set_rsu_control(struct ifpga_sec_mgr *smgr, uint32_t ctrl)
> +{
> + if (smgr && smgr->rsu_control)
> + *smgr->rsu_control = ctrl;
> +}
> +
> +static uint32_t get_rsu_control(struct ifpga_sec_mgr *smgr) {
> + if (smgr && smgr->rsu_control)
> + return *smgr->rsu_control;
> + return 0;
> +}
> +
> +static void set_rsu_status(struct ifpga_sec_mgr *smgr, uint32_t status,
> + uint32_t progress)
> +{
> + if (smgr && smgr->rsu_status)
> + *smgr->rsu_status = ((status << 16) & 0xffff0000) |
> + (progress & 0xffff);
> +}
> +
> +static void get_rsu_status(struct ifpga_sec_mgr *smgr, uint32_t *status,
> + uint32_t *progress)
> +{
> + if (smgr && smgr->rsu_status) {
> + if (status)
> + *status = (*smgr->rsu_status >> 16) & 0xffff;
> + if (progress)
> + *progress = *smgr->rsu_status & 0xffff;
> + }
> + if (smgr && smgr->rsu_status) {
> + if (status)
> + *status = (*smgr->rsu_status >> 16) & 0xffff;
> + if (progress)
> + *progress = *smgr->rsu_status & 0xffff;
> + }
> +}
> +
> +static void sig_handler(int sig, siginfo_t *info, void *data) {
> + (void)(info);
> + (void)(data);
> +
> + switch (sig) {
> + case SIGINT:
> + if (sec_mgr) {
> + dev_info(sec_mgr, "Interrupt secure flash update"
> + " by keyboard\n");
> + set_rsu_control(sec_mgr, IFPGA_RSU_ABORT);
> + }
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static void log_time(time_t t, const char *msg) {
> + uint32_t h = 0;
> + uint32_t m = 0;
> + uint32_t s = 0;
> +
> + if (t < 60) {
> + s = (uint32_t)t;
> + } else if (t < 3600) {
> + s = (uint32_t)(t % 60);
> + m = (uint32_t)(t / 60);
> + } else {
> + s = (uint32_t)(t % 60);
> + m = (uint32_t)((t % 3600) / 60);
> + h = (uint32_t)(t / 3600);
> + }
> + printf("%s - %02u:%02u:%02u\n", msg, h, m, s); }
> +
> +static int start_flash_update(struct ifpga_sec_mgr *smgr) {
> + if (!smgr)
> + return -ENODEV;
> +
> + if (!smgr->ops || !smgr->ops->prepare)
> + return -EINVAL;
> +
> + return smgr->ops->prepare(smgr);
> +}
> +
> +static int write_flash_image(struct ifpga_sec_mgr *smgr, const char *image,
> + uint32_t offset)
> +{
> + void *buf = NULL;
> + int retry = 0;
> + uint32_t length = 0;
> + uint32_t to_transfer = 0;
> + uint32_t one_percent = 0;
> + uint32_t prog = 0;
> + uint32_t old_prog = -1;
> + ssize_t read_size = 0;
> + int fd = -1;
> + int ret = 0;
> +
> + if (!smgr)
> + return -ENODEV;
> +
> + if (!smgr->ops || !smgr->ops->write_blk)
> + return -EINVAL;
> +
> + fd = open(image, O_RDONLY);
> + if (fd < 0) {
> + dev_err(smgr,
> + "Failed to open \'%s\' for RD [e:%s]\n",
> + image, strerror(errno));
> + return -EIO;
> + }
> +
> + buf = malloc(IFPGA_RSU_DATA_BLK_SIZE);
> + if (!buf) {
> + dev_err(smgr, "Failed to allocate memory for flash update\n");
> + close(fd);
> + return -ENOMEM;
> + }
> +
> + length = smgr->rsu_length;
> + one_percent = length / 100;
> + do {
> + to_transfer = (length > IFPGA_RSU_DATA_BLK_SIZE) ?
> + IFPGA_RSU_DATA_BLK_SIZE : length;
> + lseek(fd, offset, SEEK_SET);
> + read_size = read(fd, buf, to_transfer);
> + if (read_size < 0) {
> + dev_err(smgr, "Failed to read from \'%s\' [e:%s]\n",
> + image, strerror(errno));
> + ret = -EIO;
> + goto end;
> + }
> + if ((uint32_t)read_size != to_transfer) {
> + dev_err(smgr,
> + "Read length %zd is not expected [e:%u]\n",
> + read_size, to_transfer);
> + ret = -EIO;
> + goto end;
> + }
> +
> + retry = 0;
> + do {
> + if (get_rsu_control(smgr) == IFPGA_RSU_ABORT) {
> + ret = -EAGAIN;
> + goto end;
> + }
> + ret = smgr->ops->write_blk(smgr, buf, offset,
> + to_transfer);
> + if (ret == 0)
> + break;
> + sleep(1);
> + } while (++retry <= IFPGA_RSU_WRITE_RETRY);
> + if (retry > IFPGA_RSU_WRITE_RETRY) {
> + dev_err(smgr, "Failed to write to staging area 0x%x\n",
> + offset);
> + ret = -EAGAIN;
> + goto end;
> + }
> +
> + length -= to_transfer;
> + offset += to_transfer;
> + prog = offset / one_percent;
> + if (prog != old_prog) {
> + printf("\r%d%%", prog);
> + fflush(stdout);
> + set_rsu_status(smgr, IFPGA_RSU_READY, prog);
> + old_prog = prog;
> + }
> + } while (length > 0);
> + set_rsu_status(smgr, IFPGA_RSU_READY, 100);
> + printf("\n");
> +
> +end:
> + free(buf);
> + close(fd);
> + return ret;
> +}
> +
> +static int apply_flash_update(struct ifpga_sec_mgr *smgr) {
> + uint32_t one_percent = 0;
> + uint32_t one_percent_time = 0;
> + uint32_t prog = 0;
> + uint32_t old_prog = -1;
> + uint32_t copy_time = 0;
> + int ret = 0;
> +
> + if (!smgr)
> + return -ENODEV;
> +
> + if (!smgr->ops || !smgr->ops->write_done
> || !smgr->ops->check_complete)
> + return -EINVAL;
> +
> + if (smgr->ops->write_done(smgr) < 0) {
> + dev_err(smgr, "Failed to apply flash update\n");
> + return -EAGAIN;
> + }
> +
> + one_percent = (smgr->rsu_length + 99) / 100;
> + if (smgr->copy_speed == 0) /* avoid zero divide fault */
> + smgr->copy_speed = 1;
> + one_percent_time = (one_percent + smgr->copy_speed - 1) /
> + smgr->copy_speed;
> + if (one_percent_time == 0) /* avoid zero divide fault */
> + one_percent_time = 1;
> +
> + do {
> + ret = smgr->ops->check_complete(smgr);
> + if (ret != -EAGAIN)
> + break;
> + sleep(1);
> + copy_time += 1;
> + prog = copy_time / one_percent_time;
> + if (prog >= 100)
> + prog = 99;
> + if (prog != old_prog) {
> + printf("\r%d%%", prog);
> + fflush(stdout);
> + set_rsu_status(smgr, IFPGA_RSU_COPYING, prog);
> + old_prog = prog;
> + }
> + } while (true);
> +
> + if (ret < 0) {
> + printf("\n");
> + dev_err(smgr, "Failed to complete secure flash update\n");
> + } else {
> + printf("\r100%%\n");
> + set_rsu_status(smgr, IFPGA_RSU_COPYING, 100);
> + }
> +
> + return ret;
> +}
> +
> +static int secure_update_cancel(struct ifpga_sec_mgr *smgr) {
> + if (!smgr)
> + return -ENODEV;
> +
> + if (!smgr->ops || !smgr->ops->cancel)
> + return -EINVAL;
> +
> + return smgr->ops->cancel(smgr);
> +}
> +
> +static int secure_update_status(struct ifpga_sec_mgr *smgr, uint64_t
> +*status) {
> + if (!smgr)
> + return -ENODEV;
> +
> + if (!smgr->ops || !smgr->ops->get_hw_errinfo)
> + return -EINVAL;
> +
> + if (status)
> + *status = smgr->ops->get_hw_errinfo(smgr);
> +
> + return 0;
> +}
> +
> +int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image,
> + uint64_t *status)
> +{
> + struct ifpga_hw *hw = NULL;
> + struct ifpga_sec_mgr *smgr = NULL;
> + uint32_t rsu_stat = 0;
> + int fd = -1;
> + struct sigaction old_sigint_action;
> + struct sigaction sa;
> + time_t start;
> + int ret = 0;
> +
> + if (!fme || !image || !status) {
> + dev_err(fme, "Input parameter of %s is invalid\n", __func__);
> + return -EINVAL;
> + }
> +
> + hw = (struct ifpga_hw *)fme->parent;
> + if (!hw) {
> + dev_err(fme, "Parent of FME not found\n");
> + return -ENODEV;
> + }
> +
> + smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;
> + if (!smgr || !smgr->max10_dev) {
> + dev_err(smgr, "Security manager not initialized\n");
> + return -ENODEV;
> + }
> +
> + opae_adapter_lock(hw->adapter, -1);
> + get_rsu_status(smgr, &rsu_stat, NULL);
> + if (rsu_stat != IFPGA_RSU_IDLE) {
> + opae_adapter_unlock(hw->adapter);
> + if (rsu_stat == IFPGA_RSU_REBOOT)
> + dev_info(smgr, "Reboot is in progress\n");
> + else
> + dev_info(smgr, "Update is in progress\n");
> + return -EAGAIN;
> + }
> + set_rsu_control(smgr, 0);
> + set_rsu_status(smgr, IFPGA_RSU_PREPARE, 0);
> + opae_adapter_unlock(hw->adapter);
> +
> + fd = open(image, O_RDONLY);
> + if (fd < 0) {
> + dev_err(smgr,
> + "Failed to open \'%s\' for RD [e:%s]\n",
> + image, strerror(errno));
> + return -EIO;
> + }
> + smgr->rsu_length = lseek(fd, 0, SEEK_END);
> + close(fd);
> +
> + if (smgr->max10_dev->staging_area_size < smgr->rsu_length) {
> + dev_err(dev, "Size of staging area is small than image length "
> + "[%u<%u]\n", smgr->max10_dev->staging_area_size,
> + smgr->rsu_length);
> + return -EINVAL;
> + }
> +
> + printf("Updating from file \'%s\' with size %u\n",
> + image, smgr->rsu_length);
> +
> + sec_mgr = smgr;
> + memset(&sa, 0, sizeof(struct sigaction));
> + sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
> + sa.sa_sigaction = sig_handler;
> + ret = sigaction(SIGINT, &sa, &old_sigint_action);
> + if (ret < 0) {
> + dev_warn(dev, "Failed to register signal handler"
> + " [e:%d]\n", ret);
> + sec_mgr = NULL;
> + }
> +
> + start = time(NULL);
> + log_time(time(NULL) - start, "Starting secure flash update");
> + ret = start_flash_update(smgr);
> + if (ret < 0)
> + goto end;
> +
> + set_rsu_status(smgr, IFPGA_RSU_READY, 0);
> + log_time(time(NULL) - start, "Writing to staging area");
> + ret = write_flash_image(smgr, image, 0);
> + if (ret < 0)
> + goto end;
> +
> + set_rsu_status(smgr, IFPGA_RSU_COPYING, 0);
> + log_time(time(NULL) - start, "Applying secure flash update");
> + ret = apply_flash_update(smgr);
> +
> +end:
> + if (sec_mgr) {
> + sec_mgr = NULL;
> + if (sigaction(SIGINT, &old_sigint_action, NULL) < 0)
> + dev_err(smgr, "Failed to unregister signal handler\n");
> + }
> +
> + secure_update_status(smgr, status);
> + if (ret < 0) {
> + log_time(time(NULL) - start, "Secure flash update ERROR");
> + if (ret == -EAGAIN)
> + secure_update_cancel(smgr);
> + } else {
> + log_time(time(NULL) - start, "Secure flash update OK");
> + }
> + set_rsu_status(smgr, IFPGA_RSU_IDLE, 0);
> +
> + return ret;
> +}
> +
> +int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force) {
> + struct ifpga_sec_mgr *smgr = NULL;
> + uint32_t status = 0;
> + int retry = IFPGA_RSU_CANCEL_RETRY;
> + int ret = 0;
> +
> + if (!fme) {
> + dev_err(fme, "Input parameter of %s is invalid\n", __func__);
> + return -EINVAL;
> + }
> + smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;
> +
> + get_rsu_status(smgr, &status, NULL);
> + if (status != IFPGA_RSU_IDLE) {
> + dev_info(smgr, "Cancel secure flash update\n");
> + set_rsu_control(smgr, IFPGA_RSU_ABORT);
> + }
> +
> + if (force) {
> + sleep(2);
> + do {
> + get_rsu_status(smgr, &status, NULL);
> + if (status == IFPGA_RSU_IDLE)
> + break;
> + if (secure_update_cancel(smgr) == 0)
> + set_rsu_status(smgr, IFPGA_RSU_IDLE, 0);
> + sleep(1);
> + } while (--retry > 0);
> + if (retry <= 0) {
> + dev_err(smgr, "Failed to stop flash update\n");
> + ret = -EAGAIN;
> + }
> + }
> +
> + return ret;
> +}
> +
> +int fpga_reload(struct ifpga_fme_hw *fme, int type, int page) {
> + struct ifpga_sec_mgr *smgr = NULL;
> +
> + if (!fme) {
> + dev_err(fme, "Input parameter of %s is invalid\n", __func__);
> + return -EINVAL;
> + }
> + smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;
> +
> + if (!smgr || !smgr->ops || !smgr->ops->reload)
> + return -EINVAL;
> +
> + return smgr->ops->reload(smgr, type, page); }
> diff --git a/drivers/raw/ifpga/base/ifpga_hw.h
> b/drivers/raw/ifpga/base/ifpga_hw.h
> index 7c3307fe7..ed5edc601 100644
> --- a/drivers/raw/ifpga/base/ifpga_hw.h
> +++ b/drivers/raw/ifpga/base/ifpga_hw.h
> @@ -91,6 +91,7 @@ struct ifpga_fme_hw {
> struct opae_board_info board_info;
> int nums_eth_dev;
> unsigned int nums_acc_region;
> + void *sec_mgr;
> };
>
> enum ifpga_port_state {
> diff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.c
> b/drivers/raw/ifpga/base/ifpga_sec_mgr.c
> new file mode 100644
> index 000000000..4cf1db304
> --- /dev/null
> +++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.c
> @@ -0,0 +1,639 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2020 Intel Corporation
> + */
> +
> +#include <fcntl.h>
> +#include <signal.h>
> +#include <unistd.h>
> +#include "ifpga_sec_mgr.h"
> +
> +
> +static const char * const rsu_prog[] = {"IDLE", "PREPARING", "SLEEPING",
> + "READY", "AUTHENTICATING", "COPYING", "CANCELLATION",
> "PROGRAMMING_KEY",
> + "DONE", "PKVL_DONE"};
> +static const char * const rsu_statl[] = {"NORMAL", "TIMEOUT",
> "AUTH_FAIL",
> + "COPY_FAIL", "FATAL", "PKVL_REJECT", "NON_INCR", "ERASE_FAIL",
> + "WEAROUT"};
> +static const char * const rsu_stath[] = {"NIOS_OK", "USER_OK",
> "FACTORY_OK",
> + "USER_FAIL", "FACTORY_FAIL", "NIOS_FLASH_ERR",
> "FPGA_FLASH_ERR"};
> +
> +static const char *rsu_progress_name(uint32_t prog) {
> + if (prog > SEC_PROGRESS_PKVL_PROM_DONE)
> + return "UNKNOWN";
> + else
> + return rsu_prog[prog];
> +}
> +
> +static const char *rsu_status_name(uint32_t stat) {
> + if (stat >= SEC_STATUS_NIOS_OK) {
> + if (stat > SEC_STATUS_FPGA_FLASH_ERR)
> + return "UNKNOWN";
> + else
> + return rsu_stath[stat-SEC_STATUS_NIOS_OK];
> + } else {
> + if (stat > SEC_STATUS_WEAROUT)
> + return "UNKNOWN";
> + else
> + return rsu_statl[stat];
> + }
> +}
> +
> +static bool secure_start_done(uint32_t doorbell) {
> + return (SEC_STATUS_G(doorbell) == SEC_STATUS_ERASE_FAIL ||
> + SEC_STATUS_G(doorbell) == SEC_STATUS_WEAROUT ||
> + (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_IDLE &&
> + SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_RSU_DONE)); }
> +
> +static bool secure_prog_ready(uint32_t doorbell) {
> + return (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY); }
> +
> +static int poll_timeout(struct intel_max10_device *dev, uint32_t offset,
> + bool (*cond)(uint32_t), uint32_t interval_ms, uint32_t timeout_ms) {
> + uint32_t val = 0;
> + int ret = 0;
> +
> + for (;;) {
> + ret = max10_sys_read(dev, offset, &val);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to read max10 register 0x%x [e:%d]\n",
> + offset, ret);
> + break;
> + }
> +
> + if (cond(val)) {
> + dev_debug(dev,
> + "Read 0x%08x from max10 register 0x%x "
> + "[poll success]\n", val, offset);
> + ret = 0;
> + break;
> + }
> + if (timeout_ms > interval_ms)
> + timeout_ms -= interval_ms;
> + else
> + timeout_ms = 0;
> + if (timeout_ms == 0) {
> + dev_debug(dev,
> + "Read 0x%08x from max10 register 0x%x "
> + "[poll timeout]\n", val, offset);
> + ret = -ETIMEDOUT;
> + break;
> + }
> + msleep(interval_ms);
> + }
> +
> + return ret;
> +}
> +
> +static int n3000_secure_update_start(struct intel_max10_device *dev) {
> + uint32_t doorbell = 0;
> + uint32_t prog = 0;
> + uint32_t status = 0;
> + int ret = 0;
> +
> + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to read max10 doorbell register [e:%d]\n",
> + ret);
> + return ret;
> + }
> +
> + prog = SEC_PROGRESS_G(doorbell);
> + if ((prog != SEC_PROGRESS_IDLE) && (prog !=
> SEC_PROGRESS_RSU_DONE)) {
> + dev_debug(dev, "Current RSU progress is %s\n",
> + rsu_progress_name(prog));
> + return -EBUSY;
> + }
> +
> + ret = max10_sys_update_bits(dev, MAX10_DOORBELL,
> + RSU_REQUEST | HOST_STATUS, RSU_REQUEST);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to updt max10 doorbell register [e:%d]\n",
> + ret);
> + return ret;
> + }
> +
> + ret = poll_timeout(dev, MAX10_DOORBELL, secure_start_done,
> + IFPGA_SEC_START_INTERVAL_MS,
> IFPGA_SEC_START_TIMEOUT_MS);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to poll max10 doorbell register [e:%d]\n",
> + ret);
> + return ret;
> + }
> +
> + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to read max10 doorbell register [e:%d]\n",
> + ret);
> + return ret;
> + }
> +
> + status = SEC_STATUS_G(doorbell);
> + if (status == SEC_STATUS_WEAROUT)
> + return -EAGAIN;
> +
> + if (status == SEC_STATUS_ERASE_FAIL)
> + return -EIO;
> +
> + return 0;
> +}
> +
> +static int n3000_cancel(struct ifpga_sec_mgr *smgr) {
> + struct intel_max10_device *dev = NULL;
> + uint32_t doorbell = 0;
> + uint32_t prog = 0;
> + int ret = 0;
> +
> + if (!smgr || !smgr->max10_dev)
> + return -ENODEV;
> + dev = (struct intel_max10_device *)smgr->max10_dev;
> +
> + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to read max10 doorbell register [e:%d]\n",
> + ret);
> + return ret;
> + }
> +
> + prog = SEC_PROGRESS_G(doorbell);
> + if (prog == SEC_PROGRESS_IDLE)
> + return 0;
> + if (prog != SEC_PROGRESS_READY)
> + return -EBUSY;
> +
> + return max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS,
> + HOST_STATUS_S(HOST_STATUS_ABORT_RSU));
> +}
> +
> +static int n3000_prepare(struct ifpga_sec_mgr *smgr) {
> + struct intel_max10_device *dev = NULL;
> + int retry = 0;
> + int ret = 0;
> +
> + if (!smgr || !smgr->max10_dev)
> + return -ENODEV;
> + dev = (struct intel_max10_device *)smgr->max10_dev;
> +
> + ret = n3000_secure_update_start(dev);
> + if (ret == -EBUSY)
> + n3000_cancel(smgr);
> +
> + while (ret) {
> + if (++retry > IFPGA_RSU_START_RETRY)
> + break;
> + msleep(1000);
> + ret = n3000_secure_update_start(dev);
> + }
> + if (retry > IFPGA_RSU_START_RETRY) {
> + dev_err(dev, "Failed to start secure flash update\n");
> + ret = -EAGAIN;
> + }
> +
> + return ret;
> +}
> +
> +static int n3000_bulk_write(struct intel_max10_device *dev, uint32_t addr,
> + char *buf, uint32_t len)
> +{
> + uint32_t i = 0;
> + uint32_t n = 0;
> + uint32_t v = 0;
> + uint32_t p = 0;
> + int ret = 0;
> +
> + if (len & 0x3) {
> + dev_err(dev,
> + "Length of data block is not 4 bytes aligned [e:%u]\n",
> + len);
> + return -EINVAL;
> + }
> +
> + n = len >> 2;
> + for (i = 0; i < n; i++) {
> + p = i << 2;
> + v = *(uint32_t *)(buf + p);
> + ret = max10_reg_write(dev, addr + p, v);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to write to staging area 0x%08x
> [e:%d]\n",
> + addr + p, ret);
> + return ret;
> + }
> + usleep(1);
> + }
> +
> + return 0;
> +}
> +
> +static int n3000_write_blk(struct ifpga_sec_mgr *smgr, char *buf,
> + uint32_t offset, uint32_t len)
> +{
> + struct intel_max10_device *dev = NULL;
> + uint32_t doorbell = 0;
> + uint32_t prog = 0;
> + uint32_t m = 0;
> + int ret = 0;
> +
> + if (!smgr || !smgr->max10_dev)
> + return -ENODEV;
> + dev = (struct intel_max10_device *)smgr->max10_dev;
> +
> + if (offset + len > dev->staging_area_size) {
> + dev_err(dev,
> + "Write position would be out of staging area [e:%u]\n",
> + dev->staging_area_size);
> + return -ENOMEM;
> + }
> +
> + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to read max10 doorbell register [e:%d]\n",
> + ret);
> + return ret;
> + }
> +
> + prog = SEC_PROGRESS_G(doorbell);
> + if (prog == SEC_PROGRESS_PREPARE)
> + return -EAGAIN;
> + else if (prog != SEC_PROGRESS_READY)
> + return -EBUSY;
> +
> + m = len & 0x3;
> + if (m != 0)
> + len += 4 - m; /* make length to 4 bytes align */
> +
> + return n3000_bulk_write(dev, dev->staging_area_base + offset, buf,
> +len); }
> +
> +static int n3000_write_done(struct ifpga_sec_mgr *smgr) {
> + struct intel_max10_device *dev = NULL;
> + uint32_t doorbell = 0;
> + uint32_t prog = 0;
> + uint32_t status = 0;
> + int ret = 0;
> +
> + if (!smgr || !smgr->max10_dev)
> + return -ENODEV;
> + dev = (struct intel_max10_device *)smgr->max10_dev;
> +
> + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to read max10 doorbell register [e:%d]\n",
> + ret);
> + return ret;
> + }
> +
> + prog = SEC_PROGRESS_G(doorbell);
> + if (prog != SEC_PROGRESS_READY)
> + return -EBUSY;
> +
> + ret = max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS,
> + HOST_STATUS_S(HOST_STATUS_WRITE_DONE));
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to update max10 doorbell register [e:%d]\n",
> + ret);
> + return ret;
> + }
> +
> + ret = poll_timeout(dev, MAX10_DOORBELL, secure_prog_ready,
> + IFPGA_NIOS_HANDSHAKE_INTERVAL_MS,
> + IFPGA_NIOS_HANDSHAKE_TIMEOUT_MS);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to poll max10 doorbell register [e:%d]\n",
> + ret);
> + return ret;
> + }
> +
> + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to read max10 doorbell register [e:%d]\n",
> + ret);
> + return ret;
> + }
> +
> + status = SEC_STATUS_G(doorbell);
> + switch (status) {
> + case SEC_STATUS_NORMAL:
> + case SEC_STATUS_NIOS_OK:
> + case SEC_STATUS_USER_OK:
> + case SEC_STATUS_FACTORY_OK:
> + ret = 0;
> + break;
> + default:
> + ret = -EIO;
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static int n3000_check_complete(struct ifpga_sec_mgr *smgr) {
> + struct intel_max10_device *dev = NULL;
> + uint32_t doorbell = 0;
> + uint32_t status = 0;
> + uint32_t prog = 0;
> + int ret = 0;
> +
> + if (!smgr || !smgr->max10_dev)
> + return -ENODEV;
> + dev = (struct intel_max10_device *)smgr->max10_dev;
> +
> + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to read max10 doorbell register [e:%d]\n",
> + ret);
> + return ret;
> + }
> +
> + status = SEC_STATUS_G(doorbell);
> + switch (status) {
> + case SEC_STATUS_NORMAL:
> + case SEC_STATUS_NIOS_OK:
> + case SEC_STATUS_USER_OK:
> + case SEC_STATUS_FACTORY_OK:
> + case SEC_STATUS_WEAROUT:
> + break;
> + default:
> + return -EIO;
> + }
> +
> + prog = SEC_PROGRESS_G(doorbell);
> + switch (prog) {
> + case SEC_PROGRESS_IDLE:
> + case SEC_PROGRESS_RSU_DONE:
> + return 0;
> + case SEC_PROGRESS_AUTHENTICATING:
> + case SEC_PROGRESS_COPYING:
> + case SEC_PROGRESS_UPDATE_CANCEL:
> + case SEC_PROGRESS_PROGRAM_KEY_HASH:
> + return -EAGAIN;
> + case SEC_PROGRESS_PREPARE:
> + case SEC_PROGRESS_READY:
> + return -EBUSY;
> + default:
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +static int n3000_reload_fpga(struct intel_max10_device *dev, int page)
> +{
> + int ret = 0;
> +
> + dev_info(dev, "Reload FPGA\n");
> +
> + if (!dev || ((page != 0) && (page != 1))) {
> + dev_err(dev, "Input parameter of %s is invalid\n", __func__);
> + ret = -EINVAL;
> + goto end;
> + }
> +
> + if (dev->flags & MAX10_FLAGS_SECURE) {
> + ret = max10_sys_update_bits(dev, FPGA_RECONF_REG,
> + SFPGA_RP_LOAD, 0);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to update max10 reconfig register
> [e:%d]\n",
> + ret);
> + goto end;
> + }
> + ret = max10_sys_update_bits(dev, FPGA_RECONF_REG,
> + SFPGA_RP_LOAD | SFPGA_RECONF_PAGE,
> + SFPGA_RP_LOAD | SFPGA_PAGE(page));
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to update max10 reconfig register
> [e:%d]\n",
> + ret);
> + goto end;
> + }
> + } else {
> + ret = max10_sys_update_bits(dev, RSU_REG, FPGA_RP_LOAD, 0);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to update max10 rsu register [e:%d]\n",
> + ret);
> + goto end;
> + }
> + ret = max10_sys_update_bits(dev, RSU_REG,
> + FPGA_RP_LOAD | FPGA_RECONF_PAGE,
> + FPGA_RP_LOAD | FPGA_PAGE(page));
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to update max10 rsu register [e:%d]\n",
> + ret);
> + goto end;
> + }
> + }
> +
> + ret = max10_sys_update_bits(dev, FPGA_RECONF_REG,
> COUNTDOWN_START, 0);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to update max10 reconfig register [e:%d]\n",
> + ret);
> + goto end;
> + }
> +
> + ret = max10_sys_update_bits(dev, FPGA_RECONF_REG,
> COUNTDOWN_START,
> + COUNTDOWN_START);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to update max10 reconfig register [e:%d]\n",
> + ret);
> + }
> +end:
> + if (ret < 0)
> + dev_err(dev, "Failed to reload FPGA\n");
> +
> + return ret;
> +}
> +
> +static int n3000_reload_bmc(struct intel_max10_device *dev, int page) {
> + uint32_t val = 0;
> + int ret = 0;
> +
> + dev_info(dev, "Reload BMC\n");
> +
> + if (!dev || ((page != 0) && (page != 1))) {
> + dev_err(dev, "Input parameter of %s is invalid\n", __func__);
> + ret = -EINVAL;
> + goto end;
> + }
> +
> + if (dev->flags & MAX10_FLAGS_SECURE) {
> + ret = max10_sys_update_bits(dev, MAX10_DOORBELL,
> + CONFIG_SEL | REBOOT_REQ,
> + CONFIG_SEL_S(page) | REBOOT_REQ);
> + } else {
> + val = (page == 0) ? 0x1 : 0x3;
> + ret = max10_reg_write(dev, IFPGA_DUAL_CFG_CTRL1, val);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to write to dual config1 register
> [e:%d]\n",
> + ret);
> + goto end;
> + }
> +
> + ret = max10_reg_write(dev, IFPGA_DUAL_CFG_CTRL0, 0x1);
> + if (ret < 0) {
> + if (ret == -EIO) {
> + ret = 0;
> + goto end;
> + }
> + dev_err(dev,
> + "Failed to write to dual config0 register
> [e:%d]\n",
> + ret);
> + }
> + }
> +
> +end:
> + if (ret < 0)
> + dev_err(dev, "Failed to reload BMC\n");
> +
> + return ret;
> +}
> +
> +static int n3000_reload(struct ifpga_sec_mgr *smgr, int type, int page)
> +{
> + int psel = 0;
> + int ret = 0;
> +
> + if (!smgr || !smgr->max10_dev)
> + return -ENODEV;
> +
> + if (type == IFPGA_BOOT_TYPE_FPGA) {
> + psel = (page == IFPGA_BOOT_PAGE_FACTORY ? 0 : 1);
> + ret = n3000_reload_fpga(smgr->max10_dev, psel);
> + } else if (type == IFPGA_BOOT_TYPE_BMC) {
> + psel = (page == IFPGA_BOOT_PAGE_FACTORY ? 1 : 0);
> + ret = n3000_reload_bmc(smgr->max10_dev, psel);
> + } else {
> + ret = -EINVAL;
> + }
> +
> + return ret;
> +}
> +
> +static uint64_t n3000_get_hw_errinfo(struct ifpga_sec_mgr *smgr) {
> + struct intel_max10_device *dev = NULL;
> + uint32_t doorbell = 0;
> + uint32_t stat = 0;
> + uint32_t prog = 0;
> + uint32_t auth_result = 0;
> + int ret = 0;
> +
> + if (!smgr || !smgr->max10_dev)
> + return -ENODEV;
> + dev = (struct intel_max10_device *)smgr->max10_dev;
> +
> + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
> + if (ret < 0) {
> + dev_err(dev, "Failed to read max10 doorbell register [e:%d]\n",
> + ret);
> + return -1;
> + }
> + stat = SEC_STATUS_G(doorbell);
> + prog = SEC_PROGRESS_G(doorbell);
> + dev_debug(dev, "Current RSU status is %s, progress is %s\n",
> + rsu_status_name(stat), rsu_progress_name(prog));
> +
> + ret = max10_sys_read(dev, MAX10_AUTH_RESULT, &auth_result);
> + if (ret < 0) {
> + dev_err(dev,
> + "Failed to read authenticate result register [e:%d]\n",
> + ret);
> + return -1;
> + }
> +
> + return (uint64_t)doorbell << 32 | (uint64_t)auth_result; }
> +
> +static const struct ifpga_sec_ops n3000_sec_ops = {
> + .prepare = n3000_prepare,
> + .write_blk = n3000_write_blk,
> + .write_done = n3000_write_done,
> + .check_complete = n3000_check_complete,
> + .reload = n3000_reload,
> + .cancel = n3000_cancel,
> + .cleanup = NULL,
> + .get_hw_errinfo = n3000_get_hw_errinfo, };
> +
> +int init_sec_mgr(struct ifpga_fme_hw *fme) {
> + struct ifpga_hw *hw = NULL;
> + opae_share_data *sd = NULL;
> + struct ifpga_sec_mgr *smgr = NULL;
> +
> + if (!fme || !fme->max10_dev)
> + return -ENODEV;
> +
> + smgr = (struct ifpga_sec_mgr *)malloc(sizeof(*smgr));
> + if (!smgr) {
> + dev_err(NULL, "Failed to allocate memory for security
> manager\n");
> + return -ENOMEM;
> + }
> + fme->sec_mgr = smgr;
> +
> + hw = (struct ifpga_hw *)fme->parent;
> + if (hw && hw->adapter && hw->adapter->shm.ptr) {
> + sd = (opae_share_data *)hw->adapter->shm.ptr;
> + smgr->rsu_control = &sd->rsu_ctrl;
> + smgr->rsu_status = &sd->rsu_stat;
> + } else {
> + smgr->rsu_control = NULL;
> + smgr->rsu_status = NULL;
> + }
> +
> + if ((hw->pci_data->device_id == IFPGA_N3000_DID) &&
> + (hw->pci_data->vendor_id == IFPGA_N3000_VID)) {
> + smgr->ops = &n3000_sec_ops;
> + smgr->copy_speed = IFPGA_N3000_COPY_SPEED;
> + } else {
> + dev_err(NULL, "No operation for security manager\n");
> + smgr->ops = NULL;
> + }
> +
> + smgr->fme = fme;
> + smgr->max10_dev = fme->max10_dev;
> +
> + return 0;
> +}
> +
> +void release_sec_mgr(struct ifpga_fme_hw *fme) {
> + struct ifpga_sec_mgr *smgr = NULL;
> +
> + if (fme) {
> + smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;
> + if (smgr) {
> + fme->sec_mgr = NULL;
> + free(smgr);
> + }
> + }
> +}
> diff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.h
> b/drivers/raw/ifpga/base/ifpga_sec_mgr.h
> new file mode 100644
> index 000000000..17f38ca68
> --- /dev/null
> +++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.h
> @@ -0,0 +1,89 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2020 Intel Corporation
> + */
> +
> +#ifndef _IFPGA_FME_RSU_H_
> +#define _IFPGA_FME_RSU_H_
> +
> +
> +#include "ifpga_hw.h"
> +
> +#define IFPGA_N3000_VID 0x8086
> +#define IFPGA_N3000_DID 0x0b30
> +
> +#define IFPGA_BOOT_TYPE_FPGA 0
> +#define IFPGA_BOOT_TYPE_BMC 1
> +
> +#define IFPGA_BOOT_PAGE_FACTORY 0
> +#define IFPGA_BOOT_PAGE_USER 1
> +
> +#define IFPGA_RSU_DATA_BLK_SIZE 32768
> +#define IFPGA_RSU_START_RETRY 120
> +#define IFPGA_RSU_WRITE_RETRY 10
> +#define IFPGA_RSU_CANCEL_RETRY 30
> +
> +#define IFPGA_N3000_COPY_SPEED 42700
> +
> +/* status */
> +#define IFPGA_RSU_IDLE 0
> +#define IFPGA_RSU_PREPARE 1
> +#define IFPGA_RSU_READY 2
> +#define IFPGA_RSU_COPYING 3
> +#define IFPGA_RSU_REBOOT 4
> +
> +/* control */
> +#define IFPGA_RSU_ABORT 1
> +
> +#define IFPGA_DUAL_CFG_CTRL0 0x200020
> +#define IFPGA_DUAL_CFG_CTRL1 0x200024
> +
> +#define IFPGA_SEC_START_INTERVAL_MS 100
> +#define IFPGA_SEC_START_TIMEOUT_MS 20000
> +#define IFPGA_NIOS_HANDSHAKE_INTERVAL_MS 100
> +#define IFPGA_NIOS_HANDSHAKE_TIMEOUT_MS 5000
> +
> +#define IFPGA_RSU_ERR_HW_ERROR -1
> +#define IFPGA_RSU_ERR_TIMEOUT -2
> +#define IFPGA_RSU_ERR_CANCELED -3
> +#define IFPGA_RSU_ERR_BUSY -4
> +#define IFPGA_RSU_ERR_INVALID_SIZE -5
> +#define IFPGA_RSU_ERR_RW_ERROR -6
> +#define IFPGA_RSU_ERR_WEAROUT -7
> +#define IFPGA_RSU_ERR_FILE_READ -8
> +
> +struct ifpga_sec_mgr;
> +
> +struct ifpga_sec_ops {
> + int (*prepare)(struct ifpga_sec_mgr *smgr);
> + int (*write_blk)(struct ifpga_sec_mgr *smgr, char *buf, uint32_t offset,
> + uint32_t size);
> + int (*write_done)(struct ifpga_sec_mgr *smgr);
> + int (*check_complete)(struct ifpga_sec_mgr *smgr);
> + int (*reload)(struct ifpga_sec_mgr *smgr, int type, int page);
> + int (*cancel)(struct ifpga_sec_mgr *smgr);
> + void (*cleanup)(struct ifpga_sec_mgr *smgr);
> + u64 (*get_hw_errinfo)(struct ifpga_sec_mgr *smgr); };
> +
> +struct ifpga_sec_mgr {
> + struct ifpga_fme_hw *fme;
> + struct intel_max10_device *max10_dev;
> + unsigned int rsu_length;
> + /* number of bytes that copied from staging area to working area
> + * in one second, which is calculated by experiment
> + */
> + unsigned int copy_speed;
> + unsigned int *rsu_control;
> + unsigned int *rsu_status;
> + const struct ifpga_sec_ops *ops;
> +};
> +
> +int init_sec_mgr(struct ifpga_fme_hw *fme); void release_sec_mgr(struct
> +ifpga_fme_hw *fme); int fpga_update_flash(struct ifpga_fme_hw *fme,
> +const char *image,
> + uint64_t *status);
> +int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force); int
> +fpga_reload(struct ifpga_fme_hw *fme, int type, int page);
> +
> +
> +#endif /* _IFPGA_FME_RSU_H_ */
> diff --git a/drivers/raw/ifpga/base/meson.build
> b/drivers/raw/ifpga/base/meson.build
> index da2d6e33c..3549afafa 100644
> --- a/drivers/raw/ifpga/base/meson.build
> +++ b/drivers/raw/ifpga/base/meson.build
> @@ -12,6 +12,8 @@ sources = [
> 'ifpga_port.c',
> 'ifpga_port_error.c',
> 'ifpga_fme_pr.c',
> + 'ifpga_fme_rsu.c',
> + 'ifpga_sec_mgr.c',
> 'opae_hw_api.c',
> 'opae_ifpga_hw_api.c',
> 'opae_debug.c',
> diff --git a/drivers/raw/ifpga/base/opae_hw_api.c
> b/drivers/raw/ifpga/base/opae_hw_api.c
> index d5cd5fe60..86ad88f72 100644
> --- a/drivers/raw/ifpga/base/opae_hw_api.c
> +++ b/drivers/raw/ifpga/base/opae_hw_api.c
> @@ -470,6 +470,8 @@ static void opae_adapter_shm_init(struct
> opae_adapter *adapter)
> opae_mutex_init(&sd->i2c_mutex);
> sd->ref_cnt = 0;
> sd->dtb_size = SHM_BLK_SIZE;
> + sd->rsu_ctrl = 0;
> + sd->rsu_stat = 0;
> }
>
> static void *opae_adapter_shm_alloc(struct opae_adapter *adapter) @@
> -964,3 +966,60 @@ opae_mgr_get_board_info(struct opae_manager *mgr,
>
> return -ENOENT;
> }
> +
> +/**
> + * opae_mgr_update_flash - update image in flash.
> + * @mgr: targeted manager
> + * @image: name of image file
> + * @status: status of update
> + *
> + * Return: 0 on success, otherwise error code.
> + */
> +int opae_mgr_update_flash(struct opae_manager *mgr, const char *image,
> + uint64_t *status)
> +{
> + if (!mgr)
> + return -EINVAL;
> +
> + if (mgr->ops && mgr->ops->update_flash)
> + return mgr->ops->update_flash(mgr, image, status);
> +
> + return -ENOENT;
> +}
> +
> +/**
> + * opae_stop_flash_update - stop flash update.
> + * @mgr: targeted manager
> + * @force: make sure the update process is stopped
> + *
> + * Return: 0 on success, otherwise error code.
> + */
> +int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force) {
> + if (!mgr)
> + return -EINVAL;
> +
> + if (mgr->ops && mgr->ops->stop_flash_update)
> + return mgr->ops->stop_flash_update(mgr, force);
> +
> + return -ENOENT;
> +}
> +
> +/**
> + * opae_mgr_reload - reload FPGA.
> + * @mgr: targeted manager
> + * @type: FPGA type
> + * @page: reload from which page
> + *
> + * Return: 0 on success, otherwise error code.
> + */
> +int opae_mgr_reload(struct opae_manager *mgr, int type, int page) {
> + if (!mgr)
> + return -EINVAL;
> +
> + if (mgr->ops && mgr->ops->reload)
> + return mgr->ops->reload(mgr, type, page);
> +
> + return -ENOENT;
> +}
> diff --git a/drivers/raw/ifpga/base/opae_hw_api.h
> b/drivers/raw/ifpga/base/opae_hw_api.h
> index e99ee4564..c819dc3d2 100644
> --- a/drivers/raw/ifpga/base/opae_hw_api.h
> +++ b/drivers/raw/ifpga/base/opae_hw_api.h
> @@ -55,6 +55,10 @@ struct opae_manager_ops {
> unsigned int *value);
> int (*get_board_info)(struct opae_manager *mgr,
> struct opae_board_info **info);
> + int (*update_flash)(struct opae_manager *mgr, const char *image,
> + u64 *status);
> + int (*stop_flash_update)(struct opae_manager *mgr, int force);
> + int (*reload)(struct opae_manager *mgr, int type, int page);
> };
>
> /* networking management ops in FME */
> @@ -276,6 +280,8 @@ typedef struct {
> pthread_mutex_t i2c_mutex;
> u32 ref_cnt; /* reference count of shared memory */
> u32 dtb_size; /* actual length of DTB data in byte */
> + u32 rsu_ctrl; /* used to control rsu */
> + u32 rsu_stat; /* used to report status for rsu */
> };
> };
> u8 dtb[SHM_BLK_SIZE]; /* DTB data */
> @@ -354,4 +360,9 @@ int opae_manager_eth_group_read_reg(struct
> opae_manager *mgr, u8 group_id,
> u8 type, u8 index, u16 addr, u32 *data); int
> opae_mgr_get_board_info(struct opae_manager *mgr,
> struct opae_board_info **info);
> +int opae_mgr_update_flash(struct opae_manager *mgr, const char *image,
> + uint64_t *status);
> +int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force);
> +int opae_mgr_reload(struct opae_manager *mgr, int type, int page);
> +
> #endif /* _OPAE_HW_API_H_*/
> diff --git a/drivers/raw/ifpga/base/opae_intel_max10.c
> b/drivers/raw/ifpga/base/opae_intel_max10.c
> index 1a526ea54..443e248fb 100644
> --- a/drivers/raw/ifpga/base/opae_intel_max10.c
> +++ b/drivers/raw/ifpga/base/opae_intel_max10.c
> @@ -51,6 +51,22 @@ int max10_sys_write(struct intel_max10_device *dev,
> return max10_reg_write(dev, dev->base + offset, val); }
>
> +int max10_sys_update_bits(struct intel_max10_device *dev, unsigned int
> offset,
> + unsigned int msk, unsigned int val) {
> + int ret = 0;
> + unsigned int temp = 0;
> +
> + ret = max10_sys_read(dev, offset, &temp);
> + if (ret < 0)
> + return ret;
> +
> + temp &= ~msk;
> + temp |= val & msk;
> +
> + return max10_sys_write(dev, offset, temp); }
> +
> static struct max10_compatible_id max10_id_table[] = {
> {.compatible = MAX10_PAC,},
> {.compatible = MAX10_PAC_N3000,},
> @@ -557,6 +573,36 @@ static int check_max10_version(struct
> intel_max10_device *dev)
> return -ENODEV;
> }
>
> +static int max10_staging_area_init(struct intel_max10_device *dev) {
> + char *fdt_root = dev->fdt_root;
> + int ret, offset = 0;
> + u64 start, size;
> +
> + if (!fdt_root) {
> + dev_debug(dev,
> + "skip staging area init as not find Device Tree\n");
> + return -ENODEV;
> + }
> +
> + dev->staging_area_size = 0;
> +
> + fdt_for_each_subnode(offset, fdt_root, 0) {
> + if (fdt_node_check_compatible(fdt_root, offset,
> + "ifpga-sec-mgr,staging-area"))
> + continue;
> +
> + ret = fdt_get_reg(fdt_root, offset, 0, &start, &size);
> + if (!ret) {
> + dev->staging_area_base = start;
> + dev->staging_area_size = size;
> + }
> + return ret;
> + }
> +
> + return -ENODEV;
> +}
> +
> static int
> max10_secure_hw_init(struct intel_max10_device *dev) { @@ -581,6
> +627,8 @@ max10_secure_hw_init(struct intel_max10_device *dev)
>
> max10_sensor_init(dev, sysmgr_offset);
>
> + max10_staging_area_init(dev);
> +
> return 0;
> }
>
> diff --git a/drivers/raw/ifpga/base/opae_intel_max10.h
> b/drivers/raw/ifpga/base/opae_intel_max10.h
> index 123cdc48b..670683f01 100644
> --- a/drivers/raw/ifpga/base/opae_intel_max10.h
> +++ b/drivers/raw/ifpga/base/opae_intel_max10.h
> @@ -38,6 +38,8 @@ struct intel_max10_device {
> unsigned int base; /* max10 base address */
> u16 bus;
> struct opae_sensor_list opae_sensor_list;
> + u32 staging_area_base;
> + u32 staging_area_size;
> };
>
> /* retimer speed */
> @@ -98,6 +100,7 @@ struct opae_retimer_status {
> #define MAX10_MAC_COUNT GENMASK(23, 16)
> #define RSU_REG 0x2c
> #define FPGA_RECONF_PAGE GENMASK(2, 0)
> +#define FPGA_PAGE(p) ((p) & 0x1)
> #define FPGA_RP_LOAD BIT(3)
> #define NIOS2_PRERESET BIT(4)
> #define NIOS2_HANG BIT(5)
> @@ -106,6 +109,9 @@ struct opae_retimer_status {
> #define NIOS2_I2C2_POLL_STOP BIT(13)
> #define PKVL_EEPROM_LOAD BIT(31)
> #define FPGA_RECONF_REG 0x30
> +#define SFPGA_RECONF_PAGE GENMASK(22, 20)
> +#define SFPGA_PAGE(p) (((p) & 0x1) << 20)
> +#define SFPGA_RP_LOAD BIT(23)
> #define MAX10_TEST_REG 0x3c
> #define COUNTDOWN_START BIT(18)
> #define MAX10_BUILD_VER 0x68
> @@ -118,8 +124,44 @@ struct opae_retimer_status {
> #define MAX10_DOORBELL 0x400
> #define RSU_REQUEST BIT(0)
> #define SEC_PROGRESS GENMASK(7, 4)
> +#define SEC_PROGRESS_G(v) (((v) >> 4) & 0xf)
> +#define SEC_PROGRESS_IDLE 0x0
> +#define SEC_PROGRESS_PREPARE 0x1
> +#define SEC_PROGRESS_SLEEP 0x2
> +#define SEC_PROGRESS_READY 0x3
> +#define SEC_PROGRESS_AUTHENTICATING 0x4
> +#define SEC_PROGRESS_COPYING 0x5
> +#define SEC_PROGRESS_UPDATE_CANCEL 0x6
> +#define SEC_PROGRESS_PROGRAM_KEY_HASH 0x7
> +#define SEC_PROGRESS_RSU_DONE 0x8
> +#define SEC_PROGRESS_PKVL_PROM_DONE 0x9
> #define HOST_STATUS GENMASK(11, 8)
> +#define HOST_STATUS_S(v) (((v) << 8) & 0xf00)
> +#define HOST_STATUS_IDLE 0x0
> +#define HOST_STATUS_WRITE_DONE 0x1
> +#define HOST_STATUS_ABORT_RSU 0x2
> #define SEC_STATUS GENMASK(23, 16)
> +#define SEC_STATUS_G(v) (((v) >> 16) & 0xff)
> +#define SEC_STATUS_NORMAL 0x0
> +#define SEC_STATUS_TIMEOUT 0x1
> +#define SEC_STATUS_AUTH_FAIL 0x2
> +#define SEC_STATUS_COPY_FAIL 0x3
> +#define SEC_STATUS_FATAL 0x4
> +#define SEC_STATUS_PKVL_REJECT 0x5
> +#define SEC_STATUS_NON_INC 0x6
> +#define SEC_STATUS_ERASE_FAIL 0x7
> +#define SEC_STATUS_WEAROUT 0x8
> +#define SEC_STATUS_NIOS_OK 0x80
> +#define SEC_STATUS_USER_OK 0x81
> +#define SEC_STATUS_FACTORY_OK 0x82
> +#define SEC_STATUS_USER_FAIL 0x83
> +#define SEC_STATUS_FACTORY_FAIL 0x84
> +#define SEC_STATUS_NIOS_FLASH_ERR 0x85
> +#define SEC_STATUS_FPGA_FLASH_ERR 0x86
> +#define CONFIG_SEL BIT(28)
> +#define CONFIG_SEL_S(v) (((v) & 0x1) << 28)
> +#define REBOOT_REQ BIT(29)
> +#define MAX10_AUTH_RESULT 0x404
>
> /* PKVL related registers, in system register region */
> #define PKVL_POLLING_CTRL 0x80
> @@ -149,6 +191,8 @@ int max10_sys_read(struct intel_max10_device *dev,
> unsigned int offset, unsigned int *val); int max10_sys_write(struct
> intel_max10_device *dev,
> unsigned int offset, unsigned int val);
> +int max10_sys_update_bits(struct intel_max10_device *dev,
> + unsigned int offset, unsigned int msk, unsigned int val);
> struct intel_max10_device *
> intel_max10_device_probe(struct altera_spi_device *spi,
> int chipselect);
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index 27129b133..660ea2051 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -1737,3 +1737,58 @@
> RTE_PMD_REGISTER_PARAM_STRING(ifpga_rawdev_cfg,
> "ifpga=<string> "
> "port=<int> "
> "afu_bts=<path>");
> +
> +int ifpga_rawdev_update_flash(struct rte_rawdev *dev, const char *image,
> + uint64_t *status)
> +{
> + struct opae_adapter *adapter = NULL;
> +
> + if (!dev) {
> + IFPGA_RAWDEV_PMD_ERR("rawdev is invalid");
> + return -EINVAL;
> + }
> +
> + adapter = ifpga_rawdev_get_priv(dev);
> + if (!adapter) {
> + IFPGA_RAWDEV_PMD_ERR("adapter is invalid");
> + return -ENODEV;
> + }
> +
> + return opae_mgr_update_flash(adapter->mgr, image, status); }
> +
> +int ifpga_rawdev_stop_flash_update(struct rte_rawdev *dev, int force) {
> + struct opae_adapter *adapter = NULL;
> +
> + if (!dev) {
> + IFPGA_RAWDEV_PMD_ERR("rawdev is invalid");
> + return -EINVAL;
> + }
> +
> + adapter = ifpga_rawdev_get_priv(dev);
> + if (!adapter) {
> + IFPGA_RAWDEV_PMD_ERR("adapter is invalid");
> + return -ENODEV;
> + }
> +
> + return opae_mgr_stop_flash_update(adapter->mgr, force); }
> +
> +int ifpga_rawdev_reload(struct rte_rawdev *dev, int type, int page) {
> + struct opae_adapter *adapter = NULL;
> +
> + if (!dev) {
> + IFPGA_RAWDEV_PMD_ERR("rawdev is invalid");
> + return -EINVAL;
> + }
> +
> + adapter = ifpga_rawdev_get_priv(dev);
> + if (!adapter) {
> + IFPGA_RAWDEV_PMD_ERR("adapter is invalid");
> + return -ENODEV;
> + }
> +
> + return opae_mgr_reload(adapter->mgr, type, page); }
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.h
> b/drivers/raw/ifpga/ifpga_rawdev.h
> index 7754beb02..bf74a5eb3 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.h
> +++ b/drivers/raw/ifpga/ifpga_rawdev.h
> @@ -43,7 +43,7 @@ enum ifpga_rawdev_device_state { static inline struct
> opae_adapter * ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev)
> {
> - return rawdev->dev_private;
> + return (struct opae_adapter *)rawdev->dev_private;
> }
>
> #define IFPGA_RAWDEV_MSIX_IRQ_NUM 7
> @@ -76,4 +76,9 @@ int
> ifpga_unregister_msix_irq(enum ifpga_irq_type type,
> int vec_start, rte_intr_callback_fn handler, void *arg);
>
> +int ifpga_rawdev_update_flash(struct rte_rawdev *dev, const char *image,
> + uint64_t *status);
> +int ifpga_rawdev_stop_flash_update(struct rte_rawdev *dev, int force);
> +int ifpga_rawdev_reload(struct rte_rawdev *dev, int type, int page);
> +
> #endif /* _IFPGA_RAWDEV_H_ */
> --
> 2.29.2
It looks good for me.
Acked-by: Tianfei zhang <tianfei.zh...@intel.com>