Hi, -----Original Message----- From: Xu, Rosen <rosen...@intel.com> Sent: Tuesday, January 12, 2021 18:46 To: Huang, Wei <wei.hu...@intel.com>; dev@dpdk.org; Zhang, Qi Z <qi.z.zh...@intel.com> Cc: sta...@dpdk.org; Zhang, Tianfei <tianfei.zh...@intel.com> Subject: RE: [PATCH v9 1/4] raw/ifpga: add fpga rsu function
Hi, > -----Original Message----- > From: Huang, Wei <wei.hu...@intel.com> > Sent: Tuesday, January 12, 2021 13:18 > 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 v9 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); Why not opae_malloc() or rte_malloc()? [wei] I will change malloc() to opae_malloc() in next patch. > + 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); Why not rte_delay_ms()? [wei] I will change msleep() to rte_delay_ms() in next patch. > + 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