From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id D91ADA0559; Fri, 10 Jun 2022 04:17:45 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id E49FC4281E; Fri, 10 Jun 2022 04:17:33 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by mails.dpdk.org (Postfix) with ESMTP id 2B218427F9; Fri, 10 Jun 2022 04:17:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1654827450; x=1686363450; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=bqSLoveGca5wKvJjgOr1WY0e8m51Zm7DeRadoTr9SCM=; b=Ax4SQr2mkiuosVviDHiMiLCIu/kAC2H+UvVOraKLu0dtMyiOIT1JzQ6c lgqVdESz0j+yGRyn7A1/fNVOMMzo4cepF35jYhADxvcE88ykYkiMZIoaI 3eWYJa/Wklx6Zl8KqHE+wFqiFzjyiByc0SpYtNsREze4AfCLyi3EDUSAq n9AVXzfabOBGZvU3wEOsklZqWMbTOt9BkuaQ8/u/fYChDwbSCsLDqzgNl BNh3BDKdY03qaZmYDCAnMGn79DdjpFWTFtt/GrLKVzjeKTrtFPRqEodWW ta31BVP3jFDKOkBIbHNf1zIifpNYupS/9V1olkEz2WtakyOiQFhKPdaQz g==; X-IronPort-AV: E=McAfee;i="6400,9594,10373"; a="260606944" X-IronPort-AV: E=Sophos;i="5.91,288,1647327600"; d="scan'208";a="260606944" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jun 2022 19:17:29 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.91,288,1647327600"; d="scan'208";a="637865822" Received: from unknown (HELO zj-fpga-amt.sh.intel.com) ([10.238.175.102]) by fmsmga008.fm.intel.com with ESMTP; 09 Jun 2022 19:17:26 -0700 From: Wei Huang To: dev@dpdk.org, thomas@monjalon.net, nipun.gupta@nxp.com, hemant.agrawal@nxp.com Cc: stable@dpdk.org, rosen.xu@intel.com, tianfei.zhang@intel.com, qi.z.zhang@intel.com, Wei Huang Subject: [PATCH v2 2/2] raw/ifpga: update secure rsu Date: Thu, 9 Jun 2022 22:25:00 -0400 Message-Id: <1654827900-10023-3-git-send-email-wei.huang@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1654827900-10023-1-git-send-email-wei.huang@intel.com> References: <1653443483-30971-1-git-send-email-wei.huang@intel.com> <1654827900-10023-1-git-send-email-wei.huang@intel.com> X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Update secure RSU (Remote System Update) driver to adapt the changes introduced by OFS. Signed-off-by: Wei Huang --- 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(-) 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 #include +#include #include #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, ®_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 #include #include +#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 #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; +}; -- 1.8.3.1