[v1,2/2] raw/ifpga: update secure rsu

Message ID 1653443483-30971-3-git-send-email-wei.huang@intel.com (mailing list archive)
State New
Delegated to: Thomas Monjalon
Headers
Series Update rsu implementation |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation warning apply issues

Commit Message

Wei Huang May 25, 2022, 1:51 a.m. UTC
  Update secure RSU (Remote System Update) driver to adapt the changes
introduced by OFS.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
---
 drivers/raw/ifpga/base/ifpga_api.c         |   39 +-
 drivers/raw/ifpga/base/ifpga_feature_dev.h |    2 +
 drivers/raw/ifpga/base/ifpga_fme.c         |    8 +
 drivers/raw/ifpga/base/ifpga_fme_rsu.c     |  546 ++++++++-----
 drivers/raw/ifpga/base/ifpga_sec_mgr.c     | 1156 ++++++++++++++++++++--------
 drivers/raw/ifpga/base/ifpga_sec_mgr.h     |  115 ++-
 drivers/raw/ifpga/base/opae_hw_api.c       |   84 +-
 drivers/raw/ifpga/base/opae_hw_api.h       |   14 +-
 drivers/raw/ifpga/rte_pmd_ifpga.c          |  104 ++-
 drivers/raw/ifpga/rte_pmd_ifpga.h          |  117 +++
 drivers/raw/ifpga/version.map              |   11 +
 11 files changed, 1649 insertions(+), 547 deletions(-)
  

Patch

diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c
index f19cc26..c187f94 100644
--- a/drivers/raw/ifpga/base/ifpga_api.c
+++ b/drivers/raw/ifpga/base/ifpga_api.c
@@ -261,11 +261,42 @@  static int ifpga_mgr_stop_flash_update(struct opae_manager *mgr, int force)
 	return fpga_stop_flash_update(fme, force);
 }
 
-static int ifpga_mgr_reload(struct opae_manager *mgr, int type, int page)
+static int ifpga_mgr_reload(struct opae_manager *mgr, char *str)
 {
 	struct ifpga_fme_hw *fme = mgr->data;
 
-	return fpga_reload(fme, type, page);
+	return fpga_reload(fme, str);
+}
+
+static int ifpga_available_images(struct opae_manager *mgr, char *buf,
+	size_t size)
+{
+	struct ifpga_fme_hw *fme = mgr->data;
+
+	return fpga_available_images(fme, buf, size);
+}
+
+static int ifpga_mgr_set_poc_image(struct opae_manager *mgr, char *str)
+{
+	struct ifpga_fme_hw *fme = mgr->data;
+
+	return fpga_set_poc_image(fme, str);
+}
+
+static int ifpga_mgr_get_poc_images(struct opae_manager *mgr, char *buf,
+	size_t size)
+{
+	struct ifpga_fme_hw *fme = mgr->data;
+
+	return fpga_get_poc_images(fme, buf, size);
+}
+
+static int ifpga_mgr_read_flash(struct opae_manager *mgr, u32 address,
+		u32 size, void *buf)
+{
+	struct ifpga_fme_hw *fme = mgr->data;
+
+	return fme_mgr_read_flash(fme, address, size, buf);
 }
 
 struct opae_manager_ops ifpga_mgr_ops = {
@@ -277,6 +308,10 @@  struct opae_manager_ops ifpga_mgr_ops = {
 	.update_flash = ifpga_mgr_update_flash,
 	.stop_flash_update = ifpga_mgr_stop_flash_update,
 	.reload = ifpga_mgr_reload,
+	.available_images = ifpga_available_images,
+	.get_poc_images = ifpga_mgr_get_poc_images,
+	.set_poc_image = ifpga_mgr_set_poc_image,
+	.read_flash = ifpga_mgr_read_flash
 };
 
 static int ifpga_mgr_read_mac_rom(struct opae_manager *mgr, int offset,
diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.h b/drivers/raw/ifpga/base/ifpga_feature_dev.h
index a637eb5..7a2f2e5 100644
--- a/drivers/raw/ifpga/base/ifpga_feature_dev.h
+++ b/drivers/raw/ifpga/base/ifpga_feature_dev.h
@@ -223,4 +223,6 @@  int fme_mgr_get_retimer_status(struct ifpga_fme_hw *fme,
 int fme_mgr_get_sensor_value(struct ifpga_fme_hw *fme,
 		struct opae_sensor_info *sensor,
 		unsigned int *value);
+int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address,
+		u32 size, void *buf);
 #endif /* _IFPGA_FEATURE_DEV_H_ */
diff --git a/drivers/raw/ifpga/base/ifpga_fme.c b/drivers/raw/ifpga/base/ifpga_fme.c
index 1b9a922..1f54680 100644
--- a/drivers/raw/ifpga/base/ifpga_fme.c
+++ b/drivers/raw/ifpga/base/ifpga_fme.c
@@ -1658,3 +1658,11 @@  struct ifpga_feature_ops fme_pmci_ops = {
 	.init = fme_pmci_init,
 	.uinit = fme_pmci_uinit,
 };
+
+int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address,
+		u32 size, void *buf)
+{
+	struct intel_max10_device *max10 = fme->max10_dev;
+
+	return opae_read_flash(max10, address, size, buf);
+}
diff --git a/drivers/raw/ifpga/base/ifpga_fme_rsu.c b/drivers/raw/ifpga/base/ifpga_fme_rsu.c
index f147aaa..88a19fa 100644
--- a/drivers/raw/ifpga/base/ifpga_fme_rsu.c
+++ b/drivers/raw/ifpga/base/ifpga_fme_rsu.c
@@ -9,6 +9,28 @@ 
 
 static struct ifpga_sec_mgr *sec_mgr;
 
+static void lock(struct ifpga_sec_mgr *smgr)
+{
+	struct ifpga_hw *hw = NULL;
+
+	if (smgr && smgr->fme) {
+		hw = (struct ifpga_hw *)smgr->fme->parent;
+		if (hw)
+			opae_adapter_lock(hw->adapter, -1);
+	}
+}
+
+static void unlock(struct ifpga_sec_mgr *smgr)
+{
+	struct ifpga_hw *hw = NULL;
+
+	if (smgr && smgr->fme) {
+		hw = (struct ifpga_hw *)smgr->fme->parent;
+		if (hw)
+			opae_adapter_unlock(hw->adapter);
+	}
+}
+
 static void set_rsu_control(struct ifpga_sec_mgr *smgr, uint32_t ctrl)
 {
 	if (smgr && smgr->rsu_control)
@@ -22,6 +44,16 @@  static uint32_t get_rsu_control(struct ifpga_sec_mgr *smgr)
 	return 0;
 }
 
+static void cancel_rsu(struct ifpga_sec_mgr *smgr)
+{
+	uint32_t ctrl = IFPGA_RSU_CANCEL;
+
+	lock(smgr);
+	ctrl |= get_rsu_control(smgr);
+	set_rsu_control(smgr, ctrl);
+	unlock(smgr);
+}
+
 static void set_rsu_status(struct ifpga_sec_mgr *smgr, uint32_t status,
 	uint32_t progress)
 {
@@ -40,6 +72,26 @@  static void get_rsu_status(struct ifpga_sec_mgr *smgr, uint32_t *status,
 	}
 }
 
+static void update_rsu_stat(struct ifpga_sec_mgr *smgr, uint32_t stat)
+{
+	uint32_t prog = 0;
+
+	lock(smgr);
+	get_rsu_status(smgr, NULL, &prog);
+	set_rsu_status(smgr, stat, prog);
+	unlock(smgr);
+}
+
+static void update_rsu_prog(struct ifpga_sec_mgr *smgr, uint32_t prog)
+{
+	uint32_t stat = 0;
+
+	lock(smgr);
+	get_rsu_status(smgr, &stat, NULL);
+	set_rsu_status(smgr, stat, prog);
+	unlock(smgr);
+}
+
 static void sig_handler(int sig, siginfo_t *info, void *data)
 {
 	(void)(info);
@@ -50,7 +102,7 @@  static void sig_handler(int sig, siginfo_t *info, void *data)
 		if (sec_mgr) {
 			dev_info(sec_mgr, "Interrupt secure flash update"
 				" by keyboard\n");
-			set_rsu_control(sec_mgr, IFPGA_RSU_ABORT);
+			cancel_rsu(sec_mgr);
 		}
 		break;
 	default:
@@ -77,149 +129,152 @@  static void log_time(time_t t, const char *msg)
 	printf("%s - %02u:%02u:%02u\n", msg, h, m, s);
 }
 
-static int start_flash_update(struct ifpga_sec_mgr *smgr)
+static enum ifpga_sec_err fpga_sec_dev_prepare(struct ifpga_sec_mgr *smgr)
 {
 	if (!smgr)
-		return -ENODEV;
+		return IFPGA_SEC_ERR_HW_ERROR;
 
-	if (!smgr->ops || !smgr->ops->prepare)
-		return -EINVAL;
+	if (!smgr->sops || !smgr->sops->prepare)
+		return IFPGA_SEC_ERR_NO_FUNC;
+
+	return smgr->sops->prepare(smgr);
+}
+
+static int fill_buf(int fd, uint32_t offset, void *buf, uint32_t size)
+{
+	ssize_t read_size = 0;
+
+	if (lseek(fd, offset, SEEK_SET) < 0)
+		return -EIO;
+
+	read_size = read(fd, buf, size);
+	if (read_size < 0)
+		return -EIO;
 
-	return smgr->ops->prepare(smgr);
+	if ((uint32_t)read_size != size) {
+		dev_err(smgr,
+			"Read length %zd is not expected [e:%u]\n",
+			read_size, size);
+		return -EIO;
+	}
+
+	return 0;
 }
 
-static int write_flash_image(struct ifpga_sec_mgr *smgr, const char *image,
-	uint32_t offset)
+static enum ifpga_sec_err fpga_sec_dev_write(struct ifpga_sec_mgr *smgr)
 {
 	void *buf = NULL;
-	int retry = 0;
-	uint32_t length = 0;
-	uint32_t to_transfer = 0;
-	uint32_t one_percent = 0;
+	int fd = -1;
+	uint32_t blk_size = 0;
+	uint32_t offset = 0;
 	uint32_t prog = 0;
 	uint32_t old_prog = -1;
-	ssize_t read_size = 0;
-	int fd = -1;
-	int ret = 0;
+	enum ifpga_sec_err ret = 0;
 
 	if (!smgr)
-		return -ENODEV;
+		return IFPGA_SEC_ERR_HW_ERROR;
 
-	if (!smgr->ops || !smgr->ops->write_blk)
-		return -EINVAL;
+	if (!smgr->sops || !smgr->sops->write_blk)
+		return IFPGA_SEC_ERR_NO_FUNC;
+
+	buf = malloc(IFPGA_RSU_DATA_BLK_SIZE);
+	if (!buf) {
+		dev_err(smgr, "Failed to allocate memory for flash update\n");
+		return IFPGA_SEC_ERR_NO_MEM;
+	}
+	smgr->data = buf;
 
-	fd = open(image, O_RDONLY);
+	fd = open(smgr->filename, O_RDONLY);
 	if (fd < 0) {
 		dev_err(smgr,
 			"Failed to open \'%s\' for RD [e:%s]\n",
-			image, strerror(errno));
-		return -EIO;
+			smgr->filename, strerror(errno));
+		return IFPGA_SEC_ERR_FILE_READ;
 	}
 
-	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;
-		if (lseek(fd, offset, SEEK_SET) < 0) {
-			dev_err(smgr, "Failed to seek in \'%s\' [e:%s]\n",
-				image, strerror(errno));
-			ret = -EIO;
-			goto end;
-		}
-		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;
+	while (smgr->remaining_size) {
+		if (get_rsu_control(smgr) & IFPGA_RSU_CANCEL) {
+			ret = IFPGA_SEC_ERR_CANCELED;
+			break;
 		}
 
-		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;
+		blk_size = (smgr->remaining_size > IFPGA_RSU_DATA_BLK_SIZE) ?
+			IFPGA_RSU_DATA_BLK_SIZE : smgr->remaining_size;
+		if (fill_buf(fd, offset, buf, blk_size)) {
+			ret = IFPGA_SEC_ERR_FILE_READ;
+			break;
 		}
 
-		length -= to_transfer;
-		offset += to_transfer;
-		prog = offset / one_percent;
+		ret = smgr->sops->write_blk(smgr, offset, blk_size);
+		if (ret != IFPGA_SEC_ERR_NONE)
+			break;
+
+		smgr->remaining_size -= blk_size;
+		offset += blk_size;
+
+		/* output progress percent */
+		prog = offset / smgr->one_percent;
 		if (prog != old_prog) {
 			printf("\r%d%%", prog);
 			fflush(stdout);
-			set_rsu_status(smgr, IFPGA_RSU_READY, prog);
+			update_rsu_prog(smgr, prog);
 			old_prog = prog;
 		}
-	} while (length > 0);
-	set_rsu_status(smgr, IFPGA_RSU_READY, 100);
-	printf("\n");
+	}
+
+	if (ret == IFPGA_SEC_ERR_NONE) {
+		update_rsu_prog(smgr, 100);
+		printf("\r100%%\n");
+	} else {
+		printf("\n");
+	}
 
-end:
-	free(buf);
 	close(fd);
+	smgr->data = NULL;
+	free(buf);
 	return ret;
 }
 
-static int apply_flash_update(struct ifpga_sec_mgr *smgr)
+static enum ifpga_sec_err fpga_sec_dev_poll_complete(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;
+	int timeout = 2400;   /* 2400 seconds */
+	enum ifpga_sec_err ret = 0;
 
 	if (!smgr)
-		return -ENODEV;
+		return IFPGA_SEC_ERR_HW_ERROR;
 
-	if (!smgr->ops || !smgr->ops->write_done || !smgr->ops->check_complete)
-		return -EINVAL;
+	if (!smgr->sops || !smgr->sops->write_done ||
+		!smgr->sops->check_complete)
+		return IFPGA_SEC_ERR_NO_FUNC;
 
-	if (smgr->ops->write_done(smgr) < 0) {
+	if (smgr->sops->write_done(smgr) != IFPGA_SEC_ERR_NONE) {
 		dev_err(smgr, "Failed to apply flash update\n");
-		return -EAGAIN;
+		return IFPGA_SEC_ERR_HW_ERROR;
 	}
 
-	one_percent = (smgr->rsu_length + 99) / 100;
+	/* calculate time period of one percent */
 	if (smgr->copy_speed == 0)   /* avoid zero divide fault */
 		smgr->copy_speed = 1;
-	one_percent_time = (one_percent + smgr->copy_speed - 1) /
+	one_percent_time = (smgr->one_percent + smgr->copy_speed) /
 		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;
+	while (true) {
 		sleep(1);
+		ret = smgr->sops->check_complete(smgr);
+		if (ret != IFPGA_SEC_ERR_BUSY)
+			break;
+		if (--timeout < 0) {
+			ret = IFPGA_SEC_ERR_TIMEOUT;
+			break;
+		}
+
+		/* output progress percent */
 		copy_time += 1;
 		prog = copy_time / one_percent_time;
 		if (prog >= 100)
@@ -227,96 +282,90 @@  static int apply_flash_update(struct ifpga_sec_mgr *smgr)
 		if (prog != old_prog) {
 			printf("\r%d%%", prog);
 			fflush(stdout);
-			set_rsu_status(smgr, IFPGA_RSU_COPYING, prog);
+			update_rsu_prog(smgr, prog);
 			old_prog = prog;
 		}
-	} while (true);
+	}
 
-	if (ret < 0) {
-		printf("\n");
-		dev_err(smgr, "Failed to complete secure flash update\n");
-	} else {
+	if (ret == IFPGA_SEC_ERR_NONE) {
+		update_rsu_prog(smgr, 100);
 		printf("\r100%%\n");
-		set_rsu_status(smgr, IFPGA_RSU_COPYING, 100);
+	} else {
+		printf("\n");
 	}
 
 	return ret;
 }
 
-static int secure_update_cancel(struct ifpga_sec_mgr *smgr)
+static enum ifpga_sec_err fpga_sec_dev_cancel(struct ifpga_sec_mgr *smgr)
 {
 	if (!smgr)
-		return -ENODEV;
+		return IFPGA_SEC_ERR_HW_ERROR;
 
-	if (!smgr->ops || !smgr->ops->cancel)
-		return -EINVAL;
+	if (!smgr->sops || !smgr->sops->cancel)
+		return IFPGA_SEC_ERR_NO_FUNC;
 
-	return smgr->ops->cancel(smgr);
+	return smgr->sops->cancel(smgr);
 }
 
-static int secure_update_status(struct ifpga_sec_mgr *smgr, uint64_t *status)
+static void set_error(struct ifpga_sec_mgr *smgr, enum ifpga_sec_err err_code)
 {
-	if (!smgr)
-		return -ENODEV;
+	uint32_t stat = 0;
 
-	if (!smgr->ops || !smgr->ops->get_hw_errinfo)
-		return -EINVAL;
+	lock(smgr);
+	get_rsu_status(smgr, &stat, NULL);
+	set_rsu_status(smgr, stat, stat);
+	smgr->err_code = err_code;
+	unlock(smgr);
+}
 
-	if (status)
-		*status = smgr->ops->get_hw_errinfo(smgr);
+static int progress_transition(struct ifpga_sec_mgr *smgr,
+	uint32_t new_progress)
+{
+	if (get_rsu_control(smgr) & IFPGA_RSU_CANCEL) {
+		set_error(smgr, IFPGA_SEC_ERR_CANCELED);
+		smgr->sops->cancel(smgr);
+		return -ECANCELED;
+	}
 
+	set_rsu_status(smgr, new_progress, 0);
 	return 0;
 }
 
-int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image,
-	uint64_t *status)
+static void progress_complete(struct ifpga_sec_mgr *smgr)
+{
+	update_rsu_stat(smgr, IFPGA_RSU_IDLE);
+}
+
+static void fpga_sec_dev_error(struct ifpga_sec_mgr *smgr,
+	enum ifpga_sec_err err_code)
+{
+	set_error(smgr, err_code);
+	if (smgr->sops->get_hw_errinfo)
+		smgr->hw_errinfo = smgr->sops->get_hw_errinfo(smgr);
+	if (smgr->sops->cancel)
+		smgr->sops->cancel(smgr);
+}
+
+static int fpga_sec_mgr_update(struct ifpga_sec_mgr *smgr)
 {
-	struct ifpga_hw *hw = NULL;
-	struct ifpga_sec_mgr *smgr = NULL;
-	uint32_t rsu_stat = 0;
 	int fd = -1;
 	off_t len = 0;
 	struct sigaction old_sigint_action;
 	struct sigaction sa;
 	time_t start;
-	int ret = 0;
+	enum ifpga_sec_err ret = 0;
 
-	if (!fme || !image || !status) {
-		dev_err(fme, "Input parameter of %s is invalid\n", __func__);
+	if (!smgr) {
+		dev_err(smgr, "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);
+	fd = open(smgr->filename, O_RDONLY);
 	if (fd < 0) {
 		dev_err(smgr,
 			"Failed to open \'%s\' for RD [e:%s]\n",
-			image, strerror(errno));
+			smgr->filename, strerror(errno));
 		return -EIO;
 	}
 	len = lseek(fd, 0, SEEK_END);
@@ -325,25 +374,22 @@  int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image,
 	if (len < 0) {
 		dev_err(smgr,
 			"Failed to get file length of \'%s\' [e:%s]\n",
-			image, strerror(errno));
+			smgr->filename, strerror(errno));
 		return -EIO;
 	}
 	if (len == 0) {
-		dev_err(smgr, "Length of file \'%s\' is invalid\n", image);
-		return -EINVAL;
-	}
-	smgr->rsu_length = len;
-
-	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);
+		dev_err(smgr, "Length of file \'%s\' is invalid\n",
+			smgr->filename);
+		set_error(smgr, IFPGA_SEC_ERR_INVALID_SIZE);
 		return -EINVAL;
 	}
+	smgr->remaining_size = len;
+	smgr->one_percent = smgr->remaining_size / 100;
 
 	printf("Updating from file \'%s\' with size %u\n",
-		image, smgr->rsu_length);
+		smgr->filename, smgr->remaining_size);
 
+	/* setup signal handler */
 	sec_mgr = smgr;
 	memset(&sa, 0, sizeof(struct sigaction));
 	sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
@@ -354,39 +400,106 @@  int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image,
 			" [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;
+	if (progress_transition(smgr, IFPGA_RSU_PREPARING)) {
+		ret = smgr->err_code;
+		goto exit;
+	}
+
+	ret = fpga_sec_dev_prepare(smgr);
+	if (ret != IFPGA_SEC_ERR_NONE) {
+		fpga_sec_dev_error(smgr, ret);
+		goto exit;
+	}
 
-	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;
+	if (progress_transition(smgr, IFPGA_RSU_WRITING)) {
+		ret = smgr->err_code;
+		goto done;
+	}
+
+	ret = fpga_sec_dev_write(smgr);
+	if (ret != IFPGA_SEC_ERR_NONE) {
+		fpga_sec_dev_error(smgr, ret);
+		goto done;
+	}
 
-	set_rsu_status(smgr, IFPGA_RSU_COPYING, 0);
 	log_time(time(NULL) - start, "Applying secure flash update");
-	ret = apply_flash_update(smgr);
+	if (progress_transition(smgr, IFPGA_RSU_PROGRAMMING)) {
+		ret = smgr->err_code;
+		goto done;
+	}
+
+	ret = fpga_sec_dev_poll_complete(smgr);
+	if (ret != IFPGA_SEC_ERR_NONE)
+		fpga_sec_dev_error(smgr, ret);
+
+done:
+	if (smgr->sops->cleanup)
+		smgr->sops->cleanup(smgr);
+
+exit:
+	if (ret != IFPGA_SEC_ERR_NONE)
+		log_time(time(NULL) - start, "Secure flash update ERROR");
+	else
+		log_time(time(NULL) - start, "Secure flash update OK");
 
-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");
+	progress_complete(smgr);
+
+	dev_info(smgr, "Return %d\n", ret);
+	return ret == IFPGA_SEC_ERR_NONE ? 0 : -1;
+}
+
+int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image,
+	uint64_t *status)
+{
+	struct ifpga_sec_mgr *smgr = NULL;
+	uint32_t rsu_stat = 0;
+	int ret = 0;
+
+	if (!fme || !image || !status) {
+		dev_err(fme, "Input parameter of %s is invalid\n", __func__);
+		return -EINVAL;
+	}
+
+	smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;
+	if (!smgr) {
+		dev_err(smgr, "Security manager not initialized\n");
+		return -ENODEV;
+	}
+	if (!smgr->sops) {
+		dev_err(smgr, "Security manager not support flash update\n");
+		return -EOPNOTSUPP;
+	}
+
+	lock(smgr);
+	get_rsu_status(smgr, &rsu_stat, NULL);
+	if (rsu_stat != IFPGA_RSU_IDLE) {
+		unlock(smgr);
+		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_status(smgr, IFPGA_RSU_IDLE, 0);
+	set_rsu_control(smgr, 0);
+	set_rsu_status(smgr, IFPGA_RSU_PREPARING, 0);
+
+	smgr->filename = image;
+	smgr->err_code = IFPGA_SEC_ERR_NONE;
+	smgr->hw_errinfo = 0;
+	unlock(smgr);
+
+	ret = fpga_sec_mgr_update(smgr);
+	*status = smgr->hw_errinfo;
 
 	return ret;
 }
@@ -407,7 +520,7 @@  int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force)
 	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);
+		cancel_rsu(smgr);
 	}
 
 	if (force) {
@@ -416,8 +529,8 @@  int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force)
 			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);
+			if (fpga_sec_dev_cancel(smgr) == IFPGA_SEC_ERR_NONE)
+				update_rsu_stat(smgr, IFPGA_RSU_IDLE);
 			sleep(1);
 		} while (--retry > 0);
 		if (retry <= 0) {
@@ -429,9 +542,11 @@  int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force)
 	return ret;
 }
 
-int fpga_reload(struct ifpga_fme_hw *fme, int type, int page)
+int fpga_reload(struct ifpga_fme_hw *fme, char *str)
 {
 	struct ifpga_sec_mgr *smgr = NULL;
+	const struct image_load *hndlr = NULL;
+	int ret = -EOPNOTSUPP;
 
 	if (!fme) {
 		dev_err(fme, "Input parameter of %s is invalid\n", __func__);
@@ -439,8 +554,73 @@  int fpga_reload(struct ifpga_fme_hw *fme, int type, int page)
 	}
 	smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;
 
-	if (!smgr || !smgr->ops || !smgr->ops->reload)
+	if (!smgr)
+		return -ENODEV;
+
+	if (!smgr->sops || !smgr->sops->image_load)
+		return -EOPNOTSUPP;
+
+	for (hndlr = smgr->sops->image_load; hndlr->name; hndlr++) {
+		if (!strcmp(str, hndlr->name)) {
+			ret = hndlr->load_image(smgr);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+int fpga_available_images(struct ifpga_fme_hw *fme, char *buf, size_t size)
+{
+	struct ifpga_sec_mgr *smgr = NULL;
+	const struct image_load *hndlr = NULL;
+	size_t count = 0;
+
+	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)
+		return -ENODEV;
+
+	if (!smgr->sops || !smgr->sops->image_load)
+		return 0;
+
+	if (buf) {
+		for (hndlr = smgr->sops->image_load; hndlr->name; hndlr++) {
+			if ((size > count) &&
+				((size - count) > strlen(hndlr->name))) {
+				count += snprintf(buf + count, size - count,
+					"%s ", hndlr->name);
+			}
+		}
+		buf[count - 1] = '\0';
+	} else {
+		for (hndlr = smgr->sops->image_load; hndlr->name; hndlr++)
+			count += strlen(hndlr->name) + 1;
+	}
+
+	return count;
+}
+
+int fpga_set_poc_image(struct ifpga_fme_hw *fme, char *buf)
+{
+	struct ifpga_sec_mgr *smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;
+
+	if (!smgr)
+		return -ENODEV;
+
+	return pmci_set_poc_image(smgr, buf);
+}
+
+int fpga_get_poc_images(struct ifpga_fme_hw *fme, char *buf, size_t size)
+{
+	struct ifpga_sec_mgr *smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;
+
+	if (!smgr)
+		return -ENODEV;
 
-	return smgr->ops->reload(smgr, type, page);
+	return pmci_get_poc_images(smgr, buf, size);
 }
diff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.c b/drivers/raw/ifpga/base/ifpga_sec_mgr.c
index 557c4e3..3250da1 100644
--- a/drivers/raw/ifpga/base/ifpga_sec_mgr.c
+++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.c
@@ -4,9 +4,128 @@ 
 
 #include <fcntl.h>
 #include <signal.h>
+#include <stdint.h>
 #include <unistd.h>
 #include "ifpga_sec_mgr.h"
+#include "opae_intel_max10.h"
+#include "opae_osdep.h"
+
+static const char * const rsu_stat_string[] = {
+	[SEC_STATUS_NORMAL] = "Initial normal status",
+	[SEC_STATUS_TIMEOUT] = "Host timeout",
+	[SEC_STATUS_AUTH_FAIL] = "Authentication failure",
+	[SEC_STATUS_COPY_FAIL] = "Image copy failure",
+	[SEC_STATUS_FATAL] = "Fatal error, Nios boot-up failure",
+	[SEC_STATUS_PKVL_REJECT] = "pkvl reject",
+	[SEC_STATUS_NON_INC] = "Staging area non-incremental write fail",
+	[SEC_STATUS_ERASE_FAIL] = "Staging area erase fail",
+	[SEC_STATUS_WEAROUT] = "Staging area write wearout",
+	[SEC_STATUS_PMCI_SS_FAIL] = "PMCI SS Access fail",
+	[SEC_STATUS_FLASH_CMD] = "Unsupported flash command",
+	[SEC_STATUS_FACTORY_UNVERITY] = "factory image is unverified",
+	[SEC_STATUS_FACTORY_ACTIVE] = "current active image is factory",
+	[SEC_STATUS_POWER_DOWN] = "FPGA/Board powered down",
+	[SEC_STATUS_CANCELLATION] = "Cancellation not supported",
+	[SEC_STATUS_HASH] = "Hash Programming not supported",
+	[SEC_STATUS_FLASH_ACCESS] = "FPGA Flash Access Error",
+	[SEC_STATUS_SDM_PR_CERT] = "PR: cert not programmed to SDM",
+	[SEC_STATUS_SDM_PR_NIOS_BUSY] = "PR: Nios Busy waiting for SDM",
+	[SEC_STATUS_SDM_PR_TIMEOUT] = "PR: SDM Response timed out",
+	[SEC_STATUS_SDM_PR_FAILED] = "PR Key Hash program failed",
+	[SEC_STATUS_SDM_PR_MISMATCH] = "PR: SDM Response mismatched",
+	[SEC_STATUS_SDM_PR_FLUSH] = "PR: SDM Buffer Flushing failed",
+	[SEC_STATUS_SDM_SR_CERT] = "SR: cert is not programmed to SDM",
+	[SEC_STATUS_SDM_SR_NIOS_BUSY] = "SR: Nios Busy waiting for SDM",
+	[SEC_STATUS_SDM_SR_TIMEOUT] = "SR: SDM Response timed out",
+	[SEC_STATUS_SDM_SR_FAILED] = "SR Key Hash program failed",
+	[SEC_STATUS_SDM_SR_MISMATCH] = "SR: SDM Response mismatched",
+	[SEC_STATUS_SDM_SR_FLUSH] = "SR: SDM Buffer Flushing failed",
+	[SEC_STATUS_SDM_KEY_CERT] = "KEY: cert is not programmed to SDM",
+	[SEC_STATUS_SDM_KEY_NIOS_BUSY] = "KEY: Nios Busy waiting for SDM",
+	[SEC_STATUS_SDM_KEY_TIMEOUT] = "KEY: SDM Response timed out",
+	[SEC_STATUS_SDM_KEY_FAILED] = "KEY: Key Hash program failed",
+	[SEC_STATUS_SDM_KEY_MISMATCH] = "KEY: SDM Response mismatched",
+	[SEC_STATUS_SDM_KEY_FLUSH] = "KEY: SDM Buffer Flushing failed",
+	[SEC_STATUS_USER_FAIL] = "Update Failure",
+	[SEC_STATUS_FACTORY_FAIL] = "Factory Failure",
+	[SEC_STATUS_NIOS_FLASH_ERR] = "NIOS Flash Open Error",
+	[SEC_STATUS_FPGA_FLASH_ERR] = "FPGA Flash Open Error",
+};
+
+static const char * const auth_stat_string[] = {
+	[AUTH_STAT_PASS] = "Authenticate Pass",
+	[AUTH_STAT_B0_MAGIC] = "Block0 Magic value error",
+	[AUTH_STAT_CONLEN] = "Block0 ConLen error",
+	[AUTH_STAT_CONTYPE] = "Block0 ConType B[7:0] > 2",
+	[AUTH_STAT_B1_MAGIC] = "Block1 Magic value error",
+	[AUTH_STAT_ROOT_MAGIC] = "Root Entry Magic value error",
+	[AUTH_STAT_CURVE_MAGIC] = "Root Entry Curve Magic value error",
+	[AUTH_STAT_PERMISSION] = "Root Entry Permission error",
+	[AUTH_STAT_KEY_ID] = "Root Entry Key ID error",
+	[AUTH_STAT_CSK_MAGIC] = "CSK Entry Magic value error",
+	[AUTH_STAT_CSK_CURVE] = "CSK Entry Curve Magic value error",
+	[AUTH_STAT_CSK_PERMISSION] = "CSK Entry Permission error",
+	[AUTH_STAT_CSK_ID] = "CSK Entry Key ID error",
+	[AUTH_STAT_CSK_SM] = "CSK Entry Signature Magic value error",
+	[AUTH_STAT_B0_E_MAGIC] = "Block0 Entry Magic value error",
+	[AUTH_STAT_B0_E_SIGN] = "Block0 Entry Signature Magic value error",
+	[AUTH_STAT_RK_P] = "Root Key Hash not programmed for RSU",
+	[AUTH_STAT_RE_SHA] = "Root Entry verify SHA failed",
+	[AUTH_STAT_CSK_SHA] = "CSK Entry verify ECDSA and SHA failed",
+	[AUTH_STAT_B0_SHA] = "Block0 Entry verify ECDSA and SHA failed",
+	[AUTH_STAT_KEY_INV] = "KEY ID of authenticate blob is invalid",
+	[AUTH_STAT_KEY_CAN] = "KEY ID is cancelled",
+	[AUTH_STAT_UP_SHA] = "Update content SHA verify failed",
+	[AUTH_STAT_CAN_SHA] = "Cancellation content SHA verify failed",
+	[AUTH_STAT_HASH] = "HASH Programming content SHA verify failed",
+	[AUTH_STAT_INV_ID] = "Invalid cancellation ID of cancellation cert",
+	[AUTH_STAT_KEY_PROG] = "KEY hash programmed for KEY hash programming cert",
+	[AUTH_STAT_INV_BC] = "Invalid operation of Block0 ConType",
+	[AUTH_STAT_INV_SLOT] = "Invalid slot in Block0 ConType",
+	[AUTH_STAT_IN_OP] = "Incompatible operation of Block0 ConType",
+	[AUTH_STAT_TIME_OUT] = "Flash transfer to staging area timed out",
+	[AUTH_STAT_SHA_TO] = "Root Entry verify SHA timeout",
+	[AUTH_STAT_CSK_TO] = "CSK Entry verify ECDSA and SHA timeout",
+	[AUTH_STAT_B0_TO] = "Block0 Entry verify ECDSA and SHA timeout",
+	[AUTH_STAT_UP_TO] = "Update content SHA verify timeout",
+	[AUTH_STAT_CAN_TO] = "Cancellation content SHA verify timeout",
+	[AUTH_STAT_HASH_TO] = "HASH Programming content SHA verify timeout",
+	[AUTH_STAT_AUTH_IDLE] = "Authentication engine Idle",
+	[AUTH_STAT_GA_FAIL] = "Generic Authentication Failure",
+	[AUTH_STAT_S_ERR] = "Sensor Blob Generic Error",
+	[AUTH_STAT_S_MN] = "Sensor Blob Magic number error",
+	[AUTH_STAT_SH_CRC] = "Sensor Blob Header CRC error",
+	[AUTH_STAT_SD_CRC] = "Sensor Blob Data CRC error",
+	[AUTH_STAT_SD_LEN] = "Sensor Blob Data Length error",
+	[AUTH_STAT_S_ID] = "Sensor Blob Sensor ID not supported",
+	[AUTH_STAT_S_THR] = "Sensor Blob Invalid threshold type",
+	[AUTH_STAT_S_TO] = "Sensor Blob threshold out of bounds",
+	[AUTH_STAT_S_EN] = "Sensor Blob exceeds number of sensor count",
+	[AUTH_STAT_SF] = "only FPGA thermal Sensor Thresholds are allowed",
+};
 
+static const char * const sdm_stat_string[] = {
+	[SDM_STAT_DONE] = "SR Key Hash program successful",
+	[SDM_STAT_PROV] = "ignored,SR Hash is already provisioned to SDM",
+	[SDM_STAT_BUSY] = "Ignored; Configuration Module Busy",
+	[SDM_STAT_INV] = "Invalid configuration Status from Configuration",
+	[SDM_STAT_FAIL] = "SDM Flush Buffer failed",
+	[SDM_STAT_BMC_BUSY] = "BMC Busy waiting for another SDM command response",
+	[SDM_STAT_TO] = "SDM Response timed out during SDM Provisioning",
+	[SDM_STAT_DB] = "SDM device busy during SDM Provisioning",
+	[SDM_STAT_CON_R] = "Config Status retry count exceeded",
+	[SDM_STAT_CON_E] = "Config status command returned error",
+	[SDM_STAT_WAIT] = "BMC Busy waiting for another SDM command response",
+	[SDM_STAT_RTO] = "timed out during PUBKEY_PROGRAM command to SDM",
+	[SDM_STAT_SB] = "busy during PUBKEY_PROGRAM command to SDM",
+	[SDM_STAT_RE] = "SR Key Hash program failed with recoverable error",
+	[SDM_STAT_PDD] = "SR Key Hash program failed permanent device damage",
+	[SDM_STAT_ISC] = "SR Key program failed by invalid SDM command",
+	[SDM_STAT_SIC] = "SDM Congiguration failed by Shell Image configured",
+	[SDM_STAT_NO_PROV] = "SR Key Hash not provisioned to BMC",
+	[SDM_STAT_CS_MIS] = "failed by SDM CONFIG_STATUS response mismatch",
+	[SDM_STAT_PR_MIS] = "failed by SDM PUBKEY_PROGRAM Response mismatch",
+};
 
 static const char * const rsu_prog[] = {"IDLE", "PREPARING", "SLEEPING",
 	"READY", "AUTHENTICATING", "COPYING", "CANCELLATION", "PROGRAMMING_KEY",
@@ -17,6 +136,160 @@ 
 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 * const fpga_image_names[] = {
+	[FPGA_FACTORY] = "fpga_factory",
+	[FPGA_USER1] = "fpga_user1",
+	[FPGA_USER2] = "fpga_user2"
+};
+
+static enum fpga_image
+fpga_image_by_name(char *image_name)
+{
+	enum fpga_image i;
+
+	for (i = 0; i < FPGA_MAX; i++)
+		if (!strcmp(image_name, fpga_image_names[i]))
+			return i;
+
+	return FPGA_MAX;
+}
+
+static int
+fpga_images(struct ifpga_sec_mgr *smgr, char *names, enum fpga_image images[])
+{
+	u32 image_mask = smgr->poc->avail_image_mask;
+	enum fpga_image image;
+	char *image_name;
+	int i = 0;
+
+	while ((image_name = strsep(&names, "\n"))) {
+		image = fpga_image_by_name(image_name);
+		if (image >= FPGA_MAX || !(image_mask & BIT(image)))
+			return -EINVAL;
+
+		images[i++] = image;
+		image_mask &= ~BIT(image);
+	}
+
+	return (i == 0) ? -EINVAL : 0;
+}
+
+int pmci_set_poc_image(struct ifpga_sec_mgr *smgr, char *buf)
+{
+	enum fpga_image images[FPGA_MAX] = { [0 ... FPGA_MAX - 1] = FPGA_MAX };
+	int ret;
+
+	if (!smgr)
+		return -ENODEV;
+
+	ret = fpga_images(smgr, buf, images);
+	if (ret)
+		return -EINVAL;
+
+	return smgr->poc->set_sequence(smgr, images);
+}
+
+int pmci_get_poc_images(struct ifpga_sec_mgr *smgr, char *buf, size_t size)
+{
+	if (!smgr)
+		return -ENODEV;
+
+	return smgr->poc->get_sequence(smgr, buf, size);
+}
+
+static int pmci_get_power_on_image(struct ifpga_sec_mgr *smgr,
+		char *buf, size_t size)
+{
+	const char *image_names[FPGA_MAX] = { 0 };
+	int ret, i = 0;
+	int j;
+	u32 poc;
+	size_t count = 0;
+
+	if (!smgr->max10_dev)
+		return -ENODEV;
+
+	if (!buf)
+		return -EINVAL;
+
+	ret = max10_sys_read(smgr->max10_dev, M10BMC_PMCI_FPGA_POC, &poc);
+	if (ret)
+		return ret;
+
+	if (poc & PMCI_FACTORY_IMAGE_SEL)
+		image_names[i++] = fpga_image_names[FPGA_FACTORY];
+
+	if (GET_FIELD(PMCI_USER_IMAGE_PAGE, poc) == POC_USER_IMAGE_1) {
+		image_names[i++] = fpga_image_names[FPGA_USER1];
+		image_names[i++] = fpga_image_names[FPGA_USER2];
+	} else {
+		image_names[i++] = fpga_image_names[FPGA_USER2];
+		image_names[i++] = fpga_image_names[FPGA_USER1];
+	}
+
+	if (!(poc & PMCI_FACTORY_IMAGE_SEL))
+		image_names[i] = fpga_image_names[FPGA_FACTORY];
+
+	for (j = 0; j < FPGA_MAX; j++) {
+		if ((size > count) &&
+				((size - count) > strlen(image_names[j])))
+			count += snprintf(buf + count, size - count,
+					"%s ", image_names[j]);
+	}
+	buf[count - 1] = '\0';
+
+	return count;
+}
+
+static int
+pmci_set_power_on_image(struct ifpga_sec_mgr *smgr, enum fpga_image images[])
+{
+	struct intel_max10_device *dev = smgr->max10_dev;
+	u32 poc_mask = PMCI_FACTORY_IMAGE_SEL;
+	int ret, first_user = 0;
+	u32 poc = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	if (images[1] == FPGA_FACTORY)
+		return -EINVAL;
+
+	if (images[0] == FPGA_FACTORY) {
+		poc = PMCI_FACTORY_IMAGE_SEL;
+		first_user = 1;
+	}
+
+	if (images[first_user] == FPGA_USER1 ||
+			images[first_user] == FPGA_USER2) {
+		poc_mask |= PMCI_USER_IMAGE_PAGE;
+		if (images[first_user] == FPGA_USER1)
+			poc |= SET_FIELD(PMCI_USER_IMAGE_PAGE,
+					POC_USER_IMAGE_1);
+		else
+			poc |= SET_FIELD(PMCI_USER_IMAGE_PAGE,
+					POC_USER_IMAGE_2);
+	}
+
+	ret = max10_sys_update_bits(dev,
+			m10bmc_base(dev) + M10BMC_PMCI_FPGA_POC,
+			poc_mask | PMCI_FPGA_POC, poc | PMCI_FPGA_POC);
+	if (ret)
+		return ret;
+
+	ret = opae_max10_read_poll_timeout(dev,
+			m10bmc_base(dev) + M10BMC_PMCI_FPGA_POC,
+			poc,
+			(!(poc & PMCI_FPGA_POC)),
+			IFPGA_NIOS_HANDSHAKE_INTERVAL_US,
+			IFPGA_NIOS_HANDSHAKE_TIMEOUT_US);
+
+	if (ret || (GET_FIELD(PMCI_NIOS_STATUS, poc) != NIOS_STATUS_SUCCESS))
+		return -EIO;
+
+	return 0;
+}
+
 static const char *rsu_progress_name(uint32_t prog)
 {
 	if (prog > SEC_PROGRESS_PKVL_PROM_DONE)
@@ -40,377 +313,527 @@  static const char *rsu_status_name(uint32_t stat)
 	}
 }
 
-static bool secure_start_done(uint32_t doorbell)
+static void print_sdm_status(struct intel_max10_device *dev)
 {
-	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));
+	u32 val, sdm_stat;
+
+	const char *sdm_string;
+
+	if (dev->type == M10_N6000) {
+		if (!max10_sys_read(dev, m10bmc_base(dev) +
+					M10BMC_PMCI_SDM_CTRL_STS, &val))
+			dev_err(dev, "sdm ctrl reg: 0x%08x\n", val);
+
+		sdm_stat = GET_FIELD(val, PMCI_SDM_STAT);
+		if (sdm_stat > SDM_STAT_MAX)
+			dev_err(dev, "unknown sdm stat: 0x%08x\n", sdm_stat);
+
+		sdm_string = sdm_stat_string[sdm_stat];
+		if (sdm_string)
+			dev_err(dev, "sdm stat: %s\n", sdm_string);
+		else
+			dev_err(dev, "unknown sdm stat\n");
+	}
 }
 
-static bool secure_prog_ready(uint32_t doorbell)
+static void print_error_regs(struct intel_max10_device *dev)
 {
-	return (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY);
+	u32 auth_result, doorbell, rsu_stat, auth_stat;
+
+	const char *rsu_string, *auth_string;
+
+	if (!max10_sys_read(dev, doorbell_reg(dev), &doorbell))
+		dev_err(dev, "RSU doorbell reg: 0x%08x\n", doorbell);
+
+	if (!max10_sys_read(dev, auth_result_reg(dev), &auth_result))
+		dev_err(dev, "RSU auth result reg: 0x%08x\n", auth_result);
+
+	rsu_stat = SEC_STATUS_G(auth_result);
+	if (rsu_stat > SEC_STATUS_MAX)
+		dev_err(dev, "unknown rsu stat, error code exceed: 0x%08x\n", rsu_stat);
+
+	rsu_string = rsu_stat_string[rsu_stat];
+	if (rsu_string)
+		dev_err(dev, "rsu stat: %s\n", rsu_string);
+	else
+		dev_err(dev, "unknown rsu stat\n");
+
+	if (rsu_stat == SEC_STATUS_SDM_PR_FAILED ||
+			rsu_stat == SEC_STATUS_SDM_SR_FAILED)
+		print_sdm_status(dev);
+
+	auth_stat = SEC_AUTH_G(auth_result);
+	if (auth_stat > AUTH_STAT_MAX)
+		dev_err(dev, "unknown Authentication status, code exceed: 0x%08x\n", rsu_stat);
+
+	auth_string = auth_stat_string[auth_stat];
+	if (auth_string)
+		dev_err(dev, "auth stat: %s\n", auth_string);
+	else
+		dev_err(dev, "unknown auth stat\n");
 }
 
-static int poll_timeout(struct intel_max10_device *dev, uint32_t offset,
-	bool (*cond)(uint32_t), uint32_t interval_ms, uint32_t timeout_ms)
+static bool rsu_status_ok(u32 status)
 {
-	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;
-		}
+	return (status == SEC_STATUS_NORMAL ||
+		status == SEC_STATUS_NIOS_OK ||
+		status == SEC_STATUS_USER_OK ||
+		status == SEC_STATUS_FACTORY_OK);
+}
 
-		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);
-	}
+static bool rsu_progress_done(u32 progress)
+{
+	return (progress == SEC_PROGRESS_IDLE ||
+		progress == SEC_PROGRESS_RSU_DONE);
+}
 
-	return ret;
+static bool rsu_progress_busy(u32 progress)
+{
+	return (progress == SEC_PROGRESS_AUTHENTICATING ||
+		progress == SEC_PROGRESS_COPYING ||
+		progress == SEC_PROGRESS_UPDATE_CANCEL ||
+		progress == SEC_PROGRESS_PROGRAM_KEY_HASH);
 }
 
-static int n3000_secure_update_start(struct intel_max10_device *dev)
+static enum ifpga_sec_err rsu_check_idle(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) {
+	ret = max10_sys_read(dev, doorbell_reg(dev), &doorbell);
+	if (ret) {
 		dev_err(dev,
 			"Failed to read max10 doorbell register [e:%d]\n",
 			ret);
-		return ret;
+		return IFPGA_SEC_ERR_RW_ERROR;
 	}
 
 	prog = SEC_PROGRESS_G(doorbell);
-	if ((prog != SEC_PROGRESS_IDLE) && (prog != SEC_PROGRESS_RSU_DONE)) {
-		dev_debug(dev, "Current RSU progress is %s\n",
+	if (!rsu_progress_done(prog)) {
+		dev_info(dev, "Current RSU progress is %s\n",
 			rsu_progress_name(prog));
-		return -EBUSY;
+		return IFPGA_SEC_ERR_BUSY;
+	}
+
+	return IFPGA_SEC_ERR_NONE;
+}
+
+static bool cond_start_done(uint32_t doorbell, uint32_t progress,
+		uint32_t status)
+{
+	if (doorbell & RSU_REQUEST)
+		return false;
+
+	if (status == SEC_STATUS_ERASE_FAIL ||
+		status == SEC_STATUS_WEAROUT)
+		return true;
+
+	if (!rsu_progress_done(progress))
+		return true;
+
+	return false;
+}
+
+static int
+m10bmc_sec_status(struct intel_max10_device *dev, u32 *status)
+{
+	u32 reg_offset, reg_value;
+	int ret;
+
+	reg_offset = (dev->type == M10_N6000) ?
+		auth_result_reg(dev) : doorbell_reg(dev);
+
+	ret = max10_sys_read(dev, reg_offset, &reg_value);
+	if (ret)
+		return ret;
+
+	*status = SEC_STATUS_G(reg_value);
+
+	return 0;
+}
+
+static int
+m10bmc_sec_progress_status(struct intel_max10_device *dev, u32 *doorbell,
+			   u32 *progress, u32 *status)
+{
+	u32 auth_reg;
+	int ret;
+
+	ret = max10_sys_read(dev,
+			      doorbell_reg(dev),
+			      doorbell);
+	if (ret)
+		return ret;
+
+	*progress = SEC_PROGRESS_G(*doorbell);
+
+	if (dev->type == M10_N6000) {
+		ret = max10_sys_read(dev,
+				      auth_result_reg(dev),
+				      &auth_reg);
+		if (ret)
+			return ret;
+		*status = SEC_STATUS_G(auth_reg);
+	} else {
+		*status = SEC_STATUS_G(*doorbell);
 	}
 
-	ret = max10_sys_update_bits(dev, MAX10_DOORBELL,
+	return 0;
+}
+
+static int rsu_poll_start_done(struct intel_max10_device *dev, u32 *doorbell,
+			       u32 *progress, u32 *status)
+{
+	unsigned long time = 0;
+	int ret;
+
+	do {
+		if (time > IFPGA_NIOS_HANDSHAKE_TIMEOUT_US)
+			return -ETIMEDOUT;
+
+		ret = m10bmc_sec_progress_status(dev, doorbell,
+				progress, status);
+		if (ret)
+			return ret;
+		usleep(IFPGA_NIOS_HANDSHAKE_INTERVAL_US);
+		time += IFPGA_NIOS_HANDSHAKE_INTERVAL_US;
+
+	} while (!cond_start_done(*doorbell, *progress, *status));
+
+	return 0;
+}
+
+static enum ifpga_sec_err rsu_update_init(struct intel_max10_device *dev)
+{
+	uint32_t doorbell, progress, status;
+	int ret = 0;
+
+	ret = max10_sys_update_bits(dev, doorbell_reg(dev),
 		RSU_REQUEST | HOST_STATUS, RSU_REQUEST);
-	if (ret < 0) {
+	if (ret) {
 		dev_err(dev,
 			"Failed to updt max10 doorbell register [e:%d]\n",
 			ret);
-		return ret;
+		return IFPGA_SEC_ERR_RW_ERROR;
 	}
 
-	ret = poll_timeout(dev, MAX10_DOORBELL, secure_start_done,
-		IFPGA_SEC_START_INTERVAL_MS, IFPGA_SEC_START_TIMEOUT_MS);
-	if (ret < 0) {
+	ret = rsu_poll_start_done(dev, &doorbell, &progress, &status);
+	if (ret == -ETIMEDOUT) {
+		print_error_regs(dev);
+		return IFPGA_SEC_ERR_TIMEOUT;
+	} else if (ret) {
 		dev_err(dev,
 			"Failed to poll max10 doorbell register [e:%d]\n",
 			ret);
-		return ret;
+		return IFPGA_SEC_ERR_RW_ERROR;
 	}
 
-	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) {
+		dev_err(dev, "Excessive flash update count detected\n");
+		return IFPGA_SEC_ERR_WEAROUT;
+	} else if (status == SEC_STATUS_ERASE_FAIL) {
+		print_error_regs(dev);
+		return IFPGA_SEC_ERR_HW_ERROR;
 	}
 
-	status = SEC_STATUS_G(doorbell);
-	if (status == SEC_STATUS_WEAROUT)
-		return -EAGAIN;
+	dev_info(dev, "Current RSU progress is %s\n",
+			rsu_progress_name(SEC_PROGRESS_G(doorbell)));
 
-	if (status == SEC_STATUS_ERASE_FAIL)
-		return -EIO;
+	return IFPGA_SEC_ERR_NONE;
+}
 
-	return 0;
+static bool cond_prepare_done(uint32_t doorbell)
+{
+	return (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_PREPARE);
 }
 
-static int n3000_cancel(struct ifpga_sec_mgr *smgr)
+static enum ifpga_sec_err rsu_prog_ready(struct intel_max10_device *dev)
 {
-	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) {
+	ret = opae_max10_read_poll_timeout(dev, doorbell_reg(dev),
+			doorbell, cond_prepare_done(doorbell),
+			IFPGA_RSU_PREP_INTERVAL_US,
+			IFPGA_RSU_PREP_TIMEOUT_US);
+	if (ret == -ETIMEDOUT) {
+		print_error_regs(dev);
+		return IFPGA_SEC_ERR_TIMEOUT;
+	} else if (ret) {
 		dev_err(dev,
-			"Failed to read max10 doorbell register [e:%d]\n",
+			"Failed to poll max10 prog [e:%d]\n",
 			ret);
-		return ret;
+		return IFPGA_SEC_ERR_RW_ERROR;
 	}
 
 	prog = SEC_PROGRESS_G(doorbell);
-	if (prog == SEC_PROGRESS_IDLE)
-		return 0;
-	if (prog != SEC_PROGRESS_READY)
-		return -EBUSY;
+	if (prog == SEC_PROGRESS_PREPARE) {
+		print_error_regs(dev);
+		return IFPGA_SEC_ERR_TIMEOUT;
+	} else if (prog != SEC_PROGRESS_READY) {
+		return IFPGA_SEC_ERR_HW_ERROR;
+	}
 
-	return max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS,
-		HOST_STATUS_S(HOST_STATUS_ABORT_RSU));
+	dev_info(dev, "Current RSU progress is %s\n",
+			rsu_progress_name(SEC_PROGRESS_G(doorbell)));
+
+	return IFPGA_SEC_ERR_NONE;
 }
 
-static int n3000_prepare(struct ifpga_sec_mgr *smgr)
+static enum ifpga_sec_err m10bmc_sec_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;
+		return IFPGA_SEC_ERR_HW_ERROR;
 
-	ret = n3000_secure_update_start(dev);
-	if (ret == -EBUSY)
-		n3000_cancel(smgr);
+	dev = smgr->max10_dev;
 
-	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;
+	if (smgr->remaining_size > dev->staging_area_size) {
+		dev_err(smgr, "Size of staging area is smaller than image "
+			"length [%u<%u]\n", smgr->max10_dev->staging_area_size,
+			smgr->remaining_size);
+		return IFPGA_SEC_ERR_INVALID_SIZE;
 	}
 
-	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;
-	}
+	ret = rsu_check_idle(dev);
+	if (ret != IFPGA_SEC_ERR_NONE)
+		return ret;
 
-	n = len >> 2;
-	for (i = 0; i < n; i++) {
-		p = i << 2;
-		v = *(uint32_t *)(buf + p);
-		ret = max10_sys_raw_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);
-	}
+	ret = rsu_update_init(dev);
+	if (ret != IFPGA_SEC_ERR_NONE)
+		return ret;
 
-	return 0;
+	return rsu_prog_ready(dev);
 }
 
-static int n3000_write_blk(struct ifpga_sec_mgr *smgr, char *buf,
+
+static enum ifpga_sec_err m10bmc_sec_write_blk(struct ifpga_sec_mgr *smgr,
 	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;
+		return IFPGA_SEC_ERR_HW_ERROR;
+
+	dev = smgr->max10_dev;
+	if (!dev || !dev->bmc_ops.flash_write)
+		return IFPGA_SEC_ERR_HW_ERROR;
 
 	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;
+		return IFPGA_SEC_ERR_INVALID_SIZE;
 	}
 
-	ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
+	ret = max10_sys_read(dev, doorbell_reg(dev), &doorbell);
 	if (ret < 0) {
 		dev_err(dev,
 			"Failed to read max10 doorbell register [e:%d]\n",
 			ret);
-		return ret;
+		return IFPGA_SEC_ERR_RW_ERROR;
 	}
 
-	prog = SEC_PROGRESS_G(doorbell);
-	if (prog == SEC_PROGRESS_PREPARE)
-		return -EAGAIN;
-	else if (prog != SEC_PROGRESS_READY)
-		return -EBUSY;
+	if (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY)
+		return IFPGA_SEC_ERR_HW_ERROR;
 
-	m = len & 0x3;
-	if (m != 0)
-		len += 4 - m;   /* make length to 4 bytes align */
+	ret = dev->bmc_ops.flash_write(dev, dev->staging_area_base + offset,
+			smgr->data, len);
 
-	return n3000_bulk_write(dev, dev->staging_area_base + offset, buf, len);
+	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
 }
 
-static int n3000_write_done(struct ifpga_sec_mgr *smgr)
+static enum ifpga_sec_err pmci_sec_write_blk(struct ifpga_sec_mgr *smgr,
+	uint32_t offset, uint32_t len)
 {
-	struct intel_max10_device *dev = NULL;
+	struct intel_max10_device *dev;
 	uint32_t doorbell = 0;
-	uint32_t prog = 0;
-	uint32_t status = 0;
 	int ret = 0;
+	UNUSED(offset);
 
 	if (!smgr || !smgr->max10_dev)
-		return -ENODEV;
-	dev = (struct intel_max10_device *)smgr->max10_dev;
+		return IFPGA_SEC_ERR_HW_ERROR;
 
-	ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
+	dev = smgr->max10_dev;
+	if (!dev || !dev->bmc_ops.flash_write)
+		return IFPGA_SEC_ERR_HW_ERROR;
+
+	ret = max10_sys_read(dev, doorbell_reg(dev), &doorbell);
 	if (ret < 0) {
 		dev_err(dev,
 			"Failed to read max10 doorbell register [e:%d]\n",
 			ret);
-		return ret;
+		return IFPGA_SEC_ERR_RW_ERROR;
 	}
 
-	prog = SEC_PROGRESS_G(doorbell);
-	if (prog != SEC_PROGRESS_READY)
-		return -EBUSY;
+	if (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY)
+		return IFPGA_SEC_ERR_HW_ERROR;
+
+	ret = dev->bmc_ops.flash_write(dev, 0, smgr->data, len);
+
+	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
+}
 
-	ret = max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS,
+static bool cond_prog_ready(uint32_t doorbell)
+{
+	return (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY);
+}
+
+static enum ifpga_sec_err m10bmc_sec_write_done(struct ifpga_sec_mgr *smgr)
+{
+	struct intel_max10_device *dev = NULL;
+	uint32_t doorbell, status;
+	int ret = 0;
+
+	if (!smgr || !smgr->max10_dev)
+		return IFPGA_SEC_ERR_HW_ERROR;
+
+	dev = smgr->max10_dev;
+
+	ret = max10_sys_update_bits(dev, doorbell_reg(dev), 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;
+		return IFPGA_SEC_ERR_RW_ERROR;
 	}
 
-	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 = opae_max10_read_poll_timeout(dev, doorbell_reg(dev),
+			doorbell, cond_prog_ready(doorbell),
+			IFPGA_NIOS_HANDSHAKE_INTERVAL_US,
+			IFPGA_NIOS_HANDSHAKE_TIMEOUT_US);
+	if (ret == -ETIMEDOUT) {
+		print_error_regs(dev);
+		return IFPGA_SEC_ERR_TIMEOUT;
+	} else if (ret) {
+		return IFPGA_SEC_ERR_RW_ERROR;
 	}
 
-	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;
+	ret = m10bmc_sec_status(dev, &status);
+	if (ret)
+		return IFPGA_SEC_ERR_RW_ERROR;
+
+	if (!rsu_status_ok(status)) {
+		print_error_regs(dev);
+		return IFPGA_SEC_ERR_HW_ERROR;
 	}
 
-	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 IFPGA_SEC_ERR_NONE;
+}
+
+static enum ifpga_sec_err m10bmc_sec_check_complete(struct ifpga_sec_mgr *smgr)
+{
+	struct intel_max10_device *dev = NULL;
+	uint32_t doorbell, status, progress;
+
+	if (!smgr || !smgr->max10_dev)
+		return IFPGA_SEC_ERR_HW_ERROR;
+
+	dev = smgr->max10_dev;
+
+	if (m10bmc_sec_progress_status(dev, &doorbell, &progress, &status)) {
+		print_error_regs(dev);
+		return IFPGA_SEC_ERR_RW_ERROR;
 	}
 
-	return ret;
+	if (!rsu_status_ok(status)) {
+		print_error_regs(dev);
+		return IFPGA_SEC_ERR_HW_ERROR;
+	}
+
+	if (rsu_progress_done(progress))
+		return IFPGA_SEC_ERR_NONE;
+
+	if (rsu_progress_busy(progress))
+		return IFPGA_SEC_ERR_BUSY;
+
+	return IFPGA_SEC_ERR_HW_ERROR;
 }
 
-static int n3000_check_complete(struct ifpga_sec_mgr *smgr)
+static enum ifpga_sec_err m10bmc_sec_cancel(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;
+		return IFPGA_SEC_ERR_HW_ERROR;
 
-	ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
+	dev = smgr->max10_dev;
+
+	ret = max10_sys_read(dev, doorbell_reg(dev), &doorbell);
 	if (ret < 0) {
 		dev_err(dev,
 			"Failed to read max10 doorbell register [e:%d]\n",
 			ret);
-		return ret;
+		return IFPGA_SEC_ERR_RW_ERROR;
 	}
 
-	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;
+	if (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY)
+		return IFPGA_SEC_ERR_BUSY;
+
+	ret = max10_sys_update_bits(dev, doorbell_reg(dev), HOST_STATUS,
+		HOST_STATUS_S(HOST_STATUS_ABORT_RSU));
+
+	return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE;
+}
+
+static uint64_t m10bmc_sec_hw_errinfo(struct ifpga_sec_mgr *smgr)
+{
+	struct intel_max10_device *dev = NULL;
+	uint32_t doorbell = IFPGA_HW_ERRINFO_POISON;
+	uint32_t auth_result = IFPGA_HW_ERRINFO_POISON;
+	uint32_t stat = 0;
+	uint32_t prog = 0;
+
+	if (smgr && smgr->max10_dev) {
+		dev = smgr->max10_dev;
+		switch (smgr->err_code) {
+		case IFPGA_SEC_ERR_HW_ERROR:
+		case IFPGA_SEC_ERR_TIMEOUT:
+		case IFPGA_SEC_ERR_BUSY:
+		case IFPGA_SEC_ERR_WEAROUT:
+			if (max10_sys_read(dev, doorbell_reg(dev),
+					&doorbell))
+				doorbell = IFPGA_HW_ERRINFO_POISON;
+			if (max10_sys_read(dev, auth_result_reg(dev),
+					&auth_result))
+				auth_result = IFPGA_HW_ERRINFO_POISON;
+			break;
+		default:
+			doorbell = 0;
+			auth_result = 0;
+			break;
+		}
 	}
 
+	stat = SEC_STATUS_G(doorbell);
 	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;
-	}
+	dev_info(dev, "Current RSU status is %s, progress is %s\n",
+		rsu_status_name(stat), rsu_progress_name(prog));
 
-	return 0;
+	return (uint64_t)doorbell << 32 | (uint64_t)auth_result;
 }
 
-static int n3000_reload_fpga(struct intel_max10_device *dev, int page)
+static int m10bmc_sec_fpga_image_load(struct ifpga_sec_mgr *smgr, int page)
 {
+	struct intel_max10_device *dev = NULL;
 	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 (!smgr || !smgr->max10_dev)
+		return -ENODEV;
+
+	dev = smgr->max10_dev;
 
 	if (dev->flags & MAX10_FLAGS_SECURE) {
 		ret = max10_sys_update_bits(dev, FPGA_RECONF_REG,
@@ -471,117 +894,210 @@  static int n3000_reload_fpga(struct intel_max10_device *dev, int page)
 	return ret;
 }
 
-static int n3000_reload_bmc(struct intel_max10_device *dev, int page)
+static int m10bmc_sec_bmc_image_load(struct ifpga_sec_mgr *smgr, int page)
 {
-	uint32_t val = 0;
+	struct intel_max10_device *dev = NULL;
+	uint32_t doorbell = 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 (!smgr || !smgr->max10_dev)
+		return -ENODEV;
 
-	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_sys_raw_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;
-		}
+	dev = smgr->max10_dev;
 
-		ret = max10_sys_raw_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 = max10_sys_read(dev, doorbell_reg(dev), &doorbell);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read max10 doorbell register [e:%d]\n",
 				ret);
-		}
+		return ret;
 	}
 
-end:
-	if (ret < 0)
-		dev_err(dev, "Failed to reload BMC\n");
+	switch (dev->type) {
+	case N3000BMC_SEC:
+		if (doorbell & REBOOT_DISABLED)
+			return -EBUSY;
+
+		ret = max10_sys_update_bits(dev, doorbell_reg(dev),
+			CONFIG_SEL | REBOOT_REQ,
+			CONFIG_SEL_S(page) | REBOOT_REQ);
+		break;
+	case N6000BMC_SEC:
+		if (doorbell & PMCI_DRBL_REBOOT_DISABLED)
+			return -EBUSY;
+
+		ret = max10_sys_update_bits(dev, m10bmc_base(dev) +
+				M10BMC_PMCI_MAX10_RECONF,
+				PMCI_MAX10_REBOOT_REQ | PMCI_MAX10_REBOOT_PAGE,
+				SET_FIELD(PMCI_MAX10_REBOOT_PAGE, page) |
+				PMCI_MAX10_REBOOT_REQ);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
 
 	return ret;
 }
 
-static int n3000_reload(struct ifpga_sec_mgr *smgr, int type, int page)
+static int pmci_sec_fpga_image_load(struct ifpga_sec_mgr *smgr,
+				    unsigned int val)
 {
-	int psel = 0;
-	int ret = 0;
+	struct intel_max10_device *dev;
+	int ret;
 
 	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;
+	dev = smgr->max10_dev;
+
+	if (val > 2) {
+		dev_err(dev, "%s invalid reload val = %d\n",
+			__func__, val);
+		return -EINVAL;
 	}
 
-	return ret;
+	ret = max10_sys_update_bits(dev,
+				 M10BMC_PMCI_FPGA_RECONF,
+				 PMCI_FPGA_RP_LOAD, 0);
+	if (ret)
+		return ret;
+
+	return max10_sys_update_bits(dev,
+				  M10BMC_PMCI_FPGA_RECONF,
+				  PMCI_FPGA_RECONF_PAGE | PMCI_FPGA_RP_LOAD,
+				  SET_FIELD(PMCI_FPGA_RECONF_PAGE, val) |
+				  PMCI_FPGA_RP_LOAD);
 }
 
-static uint64_t n3000_get_hw_errinfo(struct ifpga_sec_mgr *smgr)
+static int n3000_sec_fpga_image_load_0(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;
+	return m10bmc_sec_fpga_image_load(smgr, 0);
+}
 
-	if (!smgr || !smgr->max10_dev)
-		return -ENODEV;
-	dev = (struct intel_max10_device *)smgr->max10_dev;
+static int n3000_sec_fpga_image_load_1(struct ifpga_sec_mgr *smgr)
+{
+	return m10bmc_sec_fpga_image_load(smgr, 1);
+}
 
-	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));
+static int n3000_sec_bmc_image_load_0(struct ifpga_sec_mgr *smgr)
+{
+	return m10bmc_sec_bmc_image_load(smgr, 0);
+}
 
-	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;
-	}
+static int n3000_sec_bmc_image_load_1(struct ifpga_sec_mgr *smgr)
+{
+	return m10bmc_sec_bmc_image_load(smgr, 1);
+}
 
-	return (uint64_t)doorbell << 32 | (uint64_t)auth_result;
+static int pmci_sec_bmc_image_load_0(struct ifpga_sec_mgr *smgr)
+{
+	return m10bmc_sec_bmc_image_load(smgr, 0);
+}
+
+static int pmci_sec_bmc_image_load_1(struct ifpga_sec_mgr *smgr)
+{
+	return m10bmc_sec_bmc_image_load(smgr, 1);
+}
+
+static int pmci_sec_fpga_image_load_0(struct ifpga_sec_mgr *smgr)
+{
+	return pmci_sec_fpga_image_load(smgr, 0);
+}
+
+static int pmci_sec_fpga_image_load_1(struct ifpga_sec_mgr *smgr)
+{
+	return pmci_sec_fpga_image_load(smgr, 1);
+}
+
+static int pmci_sec_fpga_image_load_2(struct ifpga_sec_mgr *smgr)
+{
+	return pmci_sec_fpga_image_load(smgr, 2);
+}
+
+static int pmci_sec_sdm_image_load(struct ifpga_sec_mgr *smgr)
+{
+	struct intel_max10_device *dev = smgr->max10_dev;
+
+	return max10_sys_update_bits(dev,
+			m10bmc_base(dev) + M10BMC_PMCI_SDM_CTRL_STS,
+			PMCI_SDM_IMG_REQ, PMCI_SDM_IMG_REQ);
 }
 
-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,
+static struct image_load n3000_image_load_hndlrs[] = {
+	{
+		.name = "fpga_factory",
+		.load_image = n3000_sec_fpga_image_load_0,
+	},
+	{
+		.name = "fpga_user",
+		.load_image = n3000_sec_fpga_image_load_1,
+	},
+	{
+		.name = "bmc_factory",
+		.load_image = n3000_sec_bmc_image_load_1,
+	},
+	{
+		.name = "bmc_user",
+		.load_image = n3000_sec_bmc_image_load_0,
+	},
+	{}
+};
+
+static struct image_load pmci_image_load_hndlrs[] = {
+	{
+		.name = "bmc_factory",
+		.load_image = pmci_sec_bmc_image_load_0,
+	},
+	{
+		.name = "bmc_user",
+		.load_image = pmci_sec_bmc_image_load_1,
+	},
+	{
+		.name = "fpga_factory",
+		.load_image = pmci_sec_fpga_image_load_0,
+	},
+	{
+		.name = "fpga_user1",
+		.load_image = pmci_sec_fpga_image_load_1,
+	},
+	{
+		.name = "fpga_user2",
+		.load_image = pmci_sec_fpga_image_load_2,
+	},
+	{
+		.name = "sdm",
+		.load_image = pmci_sec_sdm_image_load,
+	},
+	{}
+};
+
+static const struct ifpga_sec_mgr_ops n3000_sec_ops = {
+	.prepare = m10bmc_sec_prepare,
+	.write_blk = m10bmc_sec_write_blk,
+	.write_done = m10bmc_sec_write_done,
+	.check_complete = m10bmc_sec_check_complete,
+	.cancel = m10bmc_sec_cancel,
+	.get_hw_errinfo = m10bmc_sec_hw_errinfo,
+	.image_load = n3000_image_load_hndlrs,
+};
+
+static const struct ifpga_sec_mgr_ops pmci_sec_ops = {
+	.prepare = m10bmc_sec_prepare,
+	.write_blk = pmci_sec_write_blk,
+	.write_done = m10bmc_sec_write_done,
+	.check_complete = m10bmc_sec_check_complete,
+	.cancel = m10bmc_sec_cancel,
+	.get_hw_errinfo = m10bmc_sec_hw_errinfo,
+	.image_load = pmci_image_load_hndlrs,
+};
+
+static const struct fpga_power_on pmci_power_on_image = {
+	.avail_image_mask = BIT(FPGA_FACTORY) |
+		BIT(FPGA_USER1) | BIT(FPGA_USER2),
+	.set_sequence = pmci_set_power_on_image,
+	.get_sequence = pmci_get_power_on_image,
 };
 
 int init_sec_mgr(struct ifpga_fme_hw *fme, enum fpga_sec_type type)
@@ -610,19 +1126,25 @@  int init_sec_mgr(struct ifpga_fme_hw *fme, enum fpga_sec_type type)
 		smgr->rsu_status = NULL;
 	}
 
-	if (hw && (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;
 	smgr->type = type;
 
+	switch (type) {
+	case N3000BMC_SEC:
+		smgr->sops = &n3000_sec_ops;
+		smgr->copy_speed = IFPGA_N3000_COPY_SPEED;
+		break;
+	case N6000BMC_SEC:
+		smgr->sops = &pmci_sec_ops;
+		smgr->copy_speed = IFPGA_N3000_COPY_SPEED;
+		smgr->poc = &pmci_power_on_image;
+		break;
+	default:
+		dev_err(NULL, "No operation for security manager\n");
+		smgr->sops = NULL;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.h b/drivers/raw/ifpga/base/ifpga_sec_mgr.h
index 09cc038..0b2e1ac 100644
--- a/drivers/raw/ifpga/base/ifpga_sec_mgr.h
+++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.h
@@ -25,35 +25,44 @@ 
 #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
+#define IFPGA_RSU_IDLE         0
+#define IFPGA_RSU_PREPARING    1
+#define IFPGA_RSU_WRITING      2
+#define IFPGA_RSU_PROGRAMMING  3
+#define IFPGA_RSU_REBOOT       4
 
-#define IFPGA_RSU_GET_STAT(v)  (((v) >> 16) & 0xffff)
-#define IFPGA_RSU_GET_PROG(v)  ((v) & 0xffff)
-#define IFPGA_RSU_STATUS(s, p) ((((s) << 16) & 0xffff0000) | ((p) & 0xffff))
+#define IFPGA_RSU_GET_STAT(v)  (((v) >> 16) & 0xff)
+#define IFPGA_RSU_GET_PROG(v)  ((v) & 0xff)
+#define IFPGA_RSU_STATUS(s, p) ((((s) << 16) & 0xff0000) | ((p) & 0xff))
 
 /* control */
-#define IFPGA_RSU_ABORT      1
+#define IFPGA_RSU_CANCEL         1
+
+#define IFPGA_HW_ERRINFO_POISON  0xffffffff
 
 #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
+#define IFPGA_NIOS_HANDSHAKE_INTERVAL_US  (100 * 1000)
+#define IFPGA_NIOS_HANDSHAKE_TIMEOUT_US   (5000 * 1000)
+/* Wait about 2 minutes to erase flash staging area */
+#define IFPGA_RSU_PREP_INTERVAL_US        (100 * 1000)
+#define IFPGA_RSU_PREP_TIMEOUT_US         (120000 * 1000)
+
+enum ifpga_sec_err {
+	IFPGA_SEC_ERR_NONE = 0,
+	IFPGA_SEC_ERR_HW_ERROR,
+	IFPGA_SEC_ERR_TIMEOUT,
+	IFPGA_SEC_ERR_CANCELED,
+	IFPGA_SEC_ERR_BUSY,
+	IFPGA_SEC_ERR_INVALID_SIZE,
+	IFPGA_SEC_ERR_RW_ERROR,
+	IFPGA_SEC_ERR_WEAROUT,
+	IFPGA_SEC_ERR_FILE_READ,
+	IFPGA_SEC_ERR_NO_MEM,
+	IFPGA_SEC_ERR_NO_FUNC,
+	IFPGA_SEC_ERR_MAX
+};
 
 /* Supported fpga secure manager types */
 enum fpga_sec_type {
@@ -61,32 +70,57 @@  enum fpga_sec_type {
 	N6000BMC_SEC
 };
 
+/* Supported names for power-on images */
+enum fpga_image {
+	FPGA_FACTORY,
+	FPGA_USER1,
+	FPGA_USER2,
+	FPGA_MAX
+};
+
 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);
+struct image_load {
+	const char *name;
+	int (*load_image)(struct ifpga_sec_mgr *smgr);
+};
+
+struct fpga_power_on {
+	u32 avail_image_mask;
+	int (*get_sequence)(struct ifpga_sec_mgr *smgr, char *buf,
+			size_t size);
+	int (*set_sequence)(struct ifpga_sec_mgr *smgr,
+			enum fpga_image images[]);
+};
+
+struct ifpga_sec_mgr_ops {
+	enum ifpga_sec_err (*prepare)(struct ifpga_sec_mgr *smgr);
+	enum ifpga_sec_err (*write_blk)(struct ifpga_sec_mgr *smgr,
+		uint32_t offset, uint32_t size);
+	enum ifpga_sec_err (*write_done)(struct ifpga_sec_mgr *smgr);
+	enum ifpga_sec_err (*check_complete)(struct ifpga_sec_mgr *smgr);
+	enum ifpga_sec_err (*cancel)(struct ifpga_sec_mgr *smgr);
 	void (*cleanup)(struct ifpga_sec_mgr *smgr);
 	u64 (*get_hw_errinfo)(struct ifpga_sec_mgr *smgr);
+	struct image_load *image_load;  /* terminated with { } member */
 };
 
 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;
+	unsigned int *rsu_control;
+	unsigned int one_percent;  /* use to calculate progress value */
+	unsigned int copy_speed;  /* flash copy speed in bytes/second */
+
+	const struct ifpga_sec_mgr_ops *sops;
+	const char *filename;
+	char *data;		/* pointer to update data */
+	u32 remaining_size;		/* size remaining to transfer */
+	enum ifpga_sec_err err_code;
+	u64 hw_errinfo;  /* 64 bits of HW specific error info */
 	enum fpga_sec_type type;
+	const struct fpga_power_on *poc; /* power on image configuration */
 };
 
 int init_sec_mgr(struct ifpga_fme_hw *fme, enum fpga_sec_type type);
@@ -94,7 +128,12 @@  struct ifpga_sec_mgr {
 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);
+int fpga_reload(struct ifpga_fme_hw *fme, char *str);
+int fpga_available_images(struct ifpga_fme_hw *fme, char *buf, size_t size);
+int fpga_set_poc_image(struct ifpga_fme_hw *fme, char *buf);
+int fpga_get_poc_images(struct ifpga_fme_hw *fme, char *buf, size_t size);
 
+int pmci_set_poc_image(struct ifpga_sec_mgr *smgr, char *buf);
+int pmci_get_poc_images(struct ifpga_sec_mgr *smgr, char *buf, size_t size);
 
 #endif /* _IFPGA_FME_RSU_H_ */
diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c
index 6b78094..ada3d29 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.c
+++ b/drivers/raw/ifpga/base/opae_hw_api.c
@@ -1055,18 +1055,94 @@  int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force)
 /**
  * opae_mgr_reload -  reload FPGA.
  * @mgr: targeted manager
- * @type: FPGA type
- * @page: reload from which page
+ * @str: name of reload image type
  *
  * Return: 0 on success, otherwise error code.
  */
-int opae_mgr_reload(struct opae_manager *mgr, int type, int page)
+int opae_mgr_reload(struct opae_manager *mgr, char *str)
 {
 	if (!mgr)
 		return -EINVAL;
 
 	if (mgr->ops && mgr->ops->reload)
-		return mgr->ops->reload(mgr, type, page);
+		return mgr->ops->reload(mgr, str);
+
+	return -ENOENT;
+}
+
+/**
+ * opae_mgr_available_images -  get available load image types.
+ * @mgr: targeted manager
+ * @buf: buffer to fill with image type list
+ * @size: size of the buffer
+ *
+ * Return: 0 or positive value on success, otherwise error code.
+ */
+int opae_mgr_available_images(struct opae_manager *mgr, char *buf, size_t size)
+{
+	if (!mgr)
+		return -EINVAL;
+
+	if (mgr->ops && mgr->ops->available_images)
+		return mgr->ops->available_images(mgr, buf, size);
+
+	return -ENOENT;
+}
+
+/**
+ * opae_mgr_get_poc_images -  get available power_on_images.
+ * @mgr: targeted manager
+ * @buf: buffer to fill with image type list
+ * @size: size of the buffer
+ *
+ * Return: 0 or positive value on success, otherwise error code.
+ */
+int opae_mgr_get_poc_images(struct opae_manager *mgr, char *buf, size_t size)
+{
+	if (!mgr)
+		return -EINVAL;
+
+	if (mgr->ops && mgr->ops->get_poc_images)
+		return mgr->ops->get_poc_images(mgr, buf, size);
+
+	return -ENOENT;
+}
+
+/**
+ * opae_mgr_set_poc_image -  configure the FPGA power_on_image.
+ * @mgr: targeted manager
+ * @str: name of power_on_image
+ *
+ * Return: 0 on success, otherwise error code.
+ */
+int opae_mgr_set_poc_image(struct opae_manager *mgr, char *str)
+{
+	if (!mgr)
+		return -EINVAL;
+
+	if (mgr->ops && mgr->ops->set_poc_image)
+		return mgr->ops->set_poc_image(mgr, str);
+
+	return -ENOENT;
+}
+
+/**
+ * opae_mgr_read_flash -  read flash content
+ * @mgr: targeted manager
+ * @address: the start address of flash
+ * @size: the size of flash
+ * @buf: the read buffer
+ *
+ * Return: 0 on success, otherwise error code.
+ */
+int opae_mgr_read_flash(struct opae_manager *mgr, u32 address,
+		u32 size, void *buf)
+{
+	if (!mgr)
+		return -EINVAL;
+
+	if (mgr->ops && mgr->ops->read_flash)
+		return mgr->ops->read_flash(mgr, address, size, buf);
 
 	return -ENOENT;
 }
diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h
index 8aead4d..1e31d1e 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.h
+++ b/drivers/raw/ifpga/base/opae_hw_api.h
@@ -59,7 +59,13 @@  struct opae_manager_ops {
 	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);
+	int (*reload)(struct opae_manager *mgr, char *str);
+	int (*available_images)(struct opae_manager *mgr, char *buf,
+			size_t size);
+	int (*get_poc_images)(struct opae_manager *mgr, char *buf,
+			size_t size);
+	int (*set_poc_image)(struct opae_manager *mgr, char *str);
+	int (*read_flash)(struct opae_manager *mgr, u32 address, u32 size, void *buf);
 };
 
 /* networking management ops in FME */
@@ -368,5 +374,9 @@  int opae_mgr_get_board_info(struct opae_manager *mgr,
 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);
+int opae_mgr_reload(struct opae_manager *mgr, char *str);
+int opae_mgr_available_images(struct opae_manager *mgr, char *buf, size_t size);
+int opae_mgr_set_poc_image(struct opae_manager *mgr, char *str);
+int opae_mgr_get_poc_images(struct opae_manager *mgr, char *buf, size_t size);
+int opae_mgr_read_flash(struct opae_manager *mgr, u32 address, u32 size, void *buf);
 #endif /* _OPAE_HW_API_H_*/
diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.c b/drivers/raw/ifpga/rte_pmd_ifpga.c
index 2314643..fda7cae 100644
--- a/drivers/raw/ifpga/rte_pmd_ifpga.c
+++ b/drivers/raw/ifpga/rte_pmd_ifpga.c
@@ -6,6 +6,7 @@ 
 #include <rte_bus_pci.h>
 #include <rte_rawdev.h>
 #include <rte_rawdev_pmd.h>
+#include "base/opae_hw_api.h"
 #include "rte_pmd_ifpga.h"
 #include "ifpga_rawdev.h"
 #include "base/ifpga_api.h"
@@ -390,16 +391,104 @@ 
 	return 0;
 }
 
+static int
+get_image_load_string(struct opae_adapter *adapter, int type, int page,
+	char *str, size_t size)
+{
+	struct opae_adapter_data_pci *pci_data = NULL;
+
+	pci_data = (struct opae_adapter_data_pci *)adapter->data;
+	if (!pci_data || (pci_data->type != OPAE_FPGA_PCI))
+		return -EINVAL;
+
+	if (type == 0) {
+		if (pci_data->device_id == IFPGA_N3000_ID) {
+			if (page == 0)
+				snprintf(str, size, "fpga_factory");
+			else
+				snprintf(str, size, "fpga_user");
+		} else if (pci_data->device_id == IFPGA_N6000_ID) {
+			if (page == 0)
+				snprintf(str, size, "fpga_factory");
+			else if (page == 1)
+				snprintf(str, size, "fpga_user1");
+			else if (page == 2)
+				snprintf(str, size, "fpga_user2");
+			else
+				snprintf(str, size, "sdm");
+		}
+	} else {
+		if (page == 0)
+			snprintf(str, size, "bmc_factory");
+		else
+			snprintf(str, size, "bmc_user");
+	}
+
+	return 0;
+}
+
 int
 rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page)
 {
 	struct opae_adapter *adapter = NULL;
+	char str[RTE_RAWDEV_NAME_MAX_LEN] = {0};
+
+	adapter = get_opae_adapter(dev_id);
+	if (!adapter)
+		return -ENODEV;
+
+	if (get_image_load_string(adapter, type, page, str, sizeof(str)))
+		return -EINVAL;
+
+	return opae_mgr_reload(adapter->mgr, str);
+}
+
+int
+rte_pmd_ifpga_image_load(uint16_t dev_id, char *str)
+{
+	struct opae_adapter *adapter = NULL;
+
+	adapter = get_opae_adapter(dev_id);
+	if (!adapter)
+		return -ENODEV;
+
+	return opae_mgr_reload(adapter->mgr, str);
+}
+
+int
+rte_pmd_ifpga_get_available_images(uint16_t dev_id, char *buf, size_t size)
+{
+	struct opae_adapter *adapter = NULL;
+
+	adapter = get_opae_adapter(dev_id);
+	if (!adapter)
+		return -ENODEV;
+
+	return opae_mgr_available_images(adapter->mgr, buf, size);
+}
+
+int
+rte_pmd_ifpga_set_poc_image(uint16_t dev_id, char *str)
+{
+	struct opae_adapter *adapter = NULL;
 
 	adapter = get_opae_adapter(dev_id);
 	if (!adapter)
 		return -ENODEV;
 
-	return opae_mgr_reload(adapter->mgr, type, page);
+	return opae_mgr_set_poc_image(adapter->mgr, str);
+}
+
+int
+rte_pmd_ifpga_get_poc_images(uint16_t dev_id, char *buf, size_t size)
+{
+	struct opae_adapter *adapter = NULL;
+
+	adapter = get_opae_adapter(dev_id);
+	if (!adapter)
+		return -ENODEV;
+
+	return opae_mgr_get_poc_images(adapter->mgr, buf, size);
 }
 
 const struct rte_pci_bus *
@@ -422,6 +511,19 @@ 
 	return ifpga_rawdev_partial_reconfigure(dev, port, file);
 }
 
+int
+rte_pmd_ifpga_read_flash(uint16_t dev_id, uint32_t address, uint32_t size,
+		void *buf)
+{
+	struct opae_adapter *adapter;
+
+	adapter = get_opae_adapter(dev_id);
+	if (!adapter)
+		return -ENODEV;
+
+	return opae_mgr_read_flash(adapter->mgr, address, size, buf);
+}
+
 void
 rte_pmd_ifpga_cleanup(void)
 {
diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h b/drivers/raw/ifpga/rte_pmd_ifpga.h
index 3fa5d34..2a6a502 100644
--- a/drivers/raw/ifpga/rte_pmd_ifpga.h
+++ b/drivers/raw/ifpga/rte_pmd_ifpga.h
@@ -21,6 +21,8 @@ 
 #include <stdint.h>
 
 #define IFPGA_MAX_PORT_NUM   4
+#define IFPGA_N3000_ID    0x0B30
+#define IFPGA_N6000_ID    0xBCCE
 
 /**
  * UUID data structure.
@@ -216,6 +218,7 @@ 
  *   - (-ENODEV) if dev_id is invalid.
  *   - (-EINVAL) if bad parameter.
  *   - (-EBUSY) if failed to access BMC register.
+ *   - (-EOPNOTSUPP) if the specific image load not supported.
  */
 int
 rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page);
@@ -253,6 +256,120 @@ 
 void
 rte_pmd_ifpga_cleanup(void);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Set which image to load for specified Intel FPGA device at power on
+ *
+ * @param dev_id
+ *    The raw device ID of specified Intel FPGA device.
+ * @param str
+ *    name of the image to load from flash.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENODEV) if dev_id is invalid.
+ *   - (-EINVAL) if bad parameter.
+ *   - (-EBUSY) if failed to access BMC register.
+ *   - (-EOPNOTSUPP) if the specific image load not supported.
+ */
+__rte_experimental
+int
+rte_pmd_ifpga_set_poc_image(uint16_t dev_id, char *str);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get available load image supported by specified Intel FPGA device
+ *
+ * @param dev_id
+ *    The raw device ID of specified Intel FPGA device.
+ * @param buf
+ *    a space separated list of image type name will be filled in this buffer.
+ *    buffer pointer can be NULL.
+ * @param size
+ *    when buf pointer is not NULL, indicate the size of the buffer.
+ * @return
+ *   - (0) no available load image type.
+ *   - (>0) string length of the list including the terminating null character.
+ *   - (-ENODEV) if dev_id is invalid.
+ *   - (-EINVAL) if bad parameter.
+ *   - (-EBUSY) if failed to access BMC register.
+ */
+__rte_experimental
+int
+rte_pmd_ifpga_get_poc_images(uint16_t dev_id, char *buf, size_t size);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Trigger image load of specified Intel FPGA device
+ *
+ * @param dev_id
+ *    The raw device ID of specified Intel FPGA device.
+ * @param str
+ *    name of the image to load from flash.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENODEV) if dev_id is invalid.
+ *   - (-EINVAL) if bad parameter.
+ *   - (-EBUSY) if failed to access BMC register.
+ *   - (-EOPNOTSUPP) if the specific image load not supported.
+ */
+__rte_experimental
+int
+rte_pmd_ifpga_image_load(uint16_t dev_id, char *str);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get available load image supported by specified Intel FPGA device
+ *
+ * @param dev_id
+ *    The raw device ID of specified Intel FPGA device.
+ * @param buf
+ *    a space separated list of image type name will be filled in this buffer.
+ *    buffer pointer can be NULL.
+ * @param size
+ *    when buf pointer is not NULL, indicate the size of the buffer.
+ * @return
+ *   - (0) no available load image type.
+ *   - (>0) string length of the list including the terminating null character.
+ *   - (-ENODEV) if dev_id is invalid.
+ *   - (-EINVAL) if bad parameter.
+ *   - (-EBUSY) if failed to access BMC register.
+ */
+__rte_experimental
+int
+rte_pmd_ifpga_get_available_images(uint16_t dev_id, char *buf, size_t size);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Read out flash content on specified Intel FPGA device
+ *
+ * @param dev_id
+ *   The raw device ID of specified Intel FPGA device.
+ * @param address
+ *   The start address of the flash.
+ * @param size
+ *   The size of flash which want to read out.
+ * @param buf
+ *   The read buffer.
+ * @return
+ *   - (0) if successful.
+ *   - (-EINVAL) if bad parameter or operation failed.
+ *   - (-ENOMEM) if no available flash memory to access.
+ */
+__rte_experimental
+int
+rte_pmd_ifpga_read_flash(uint16_t dev_id, uint32_t address, uint32_t size,
+	void *buf);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map
index ff71a45..a201124 100644
--- a/drivers/raw/ifpga/version.map
+++ b/drivers/raw/ifpga/version.map
@@ -16,3 +16,14 @@  DPDK_22 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	# added in 22.07
+	rte_pmd_ifpga_image_load;
+	rte_pmd_ifpga_get_available_images;
+	rte_pmd_ifpga_set_poc_image;
+	rte_pmd_ifpga_get_poc_images;
+	rte_pmd_ifpga_read_flash;
+};