diff mbox series

[v9,1/4] raw/ifpga: add fpga rsu function

Message ID 1610428684-20708-2-git-send-email-wei.huang@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Qi Zhang
Headers show
Series raw/ifpga: add extra OPAE APIs | expand

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Huang, Wei Jan. 12, 2021, 5:18 a.m. UTC
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.huang@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

Comments

Xu, Rosen Jan. 12, 2021, 10:46 a.m. UTC | #1
Hi,

> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Tuesday, January 12, 2021 13:18
> To: dev@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Qi Z
> <qi.z.zhang@intel.com>
> Cc: stable@dpdk.org; Zhang, Tianfei <tianfei.zhang@intel.com>; Huang, Wei
> <wei.huang@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.huang@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()?

> +	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()?

> +		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
Huang, Wei Jan. 18, 2021, 2:27 a.m. UTC | #2
Hi,

-----Original Message-----
From: Xu, Rosen <rosen.xu@intel.com> 
Sent: Tuesday, January 12, 2021 18:46
To: Huang, Wei <wei.huang@intel.com>; dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>
Cc: stable@dpdk.org; Zhang, Tianfei <tianfei.zhang@intel.com>
Subject: RE: [PATCH v9 1/4] raw/ifpga: add fpga rsu function

Hi,

> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Tuesday, January 12, 2021 13:18
> To: dev@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Qi Z 
> <qi.z.zhang@intel.com>
> Cc: stable@dpdk.org; Zhang, Tianfei <tianfei.zhang@intel.com>; Huang, 
> Wei <wei.huang@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.huang@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
Huang, Wei Jan. 18, 2021, 5:44 a.m. UTC | #3
Hi,

-----Original Message-----
From: Xu, Rosen <rosen.xu@intel.com> 
Sent: Tuesday, January 12, 2021 18:46
To: Huang, Wei <wei.huang@intel.com>; dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>
Cc: stable@dpdk.org; Zhang, Tianfei <tianfei.zhang@intel.com>
Subject: RE: [PATCH v9 1/4] raw/ifpga: add fpga rsu function

Hi,

> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Tuesday, January 12, 2021 13:18
> To: dev@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Qi Z 
> <qi.z.zhang@intel.com>
> Cc: stable@dpdk.org; Zhang, Tianfei <tianfei.zhang@intel.com>; Huang, 
> Wei <wei.huang@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.huang@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] malloc() is defined in ifpga_compat.h as "#define malloc(size) opae_malloc(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);

Why not rte_delay_ms()?
[Wei] msleep() is defined in opae_osdep.h as "#define msleep(x) opae_udelay(1000 * (x))" and
Opae_udelay() is defined as rte_delay_us() in osdep_generic.h.

> +		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
diff mbox series

Patch

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_ */