From patchwork Wed Mar 3 02:34:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Huang X-Patchwork-Id: 88401 X-Patchwork-Delegate: qi.z.zhang@intel.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8B6ECA0566; Wed, 3 Mar 2021 03:34:36 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 3DE53160715; Wed, 3 Mar 2021 03:34:32 +0100 (CET) Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by mails.dpdk.org (Postfix) with ESMTP id 75AE1160703; Wed, 3 Mar 2021 03:34:29 +0100 (CET) IronPort-SDR: j97CHtOqa9A/ZJQa0gOSQx6m6GPQXDWSreujYcNqaw52SY+jq8boontRs3d/ZnDltkmR1s5yBq NPCf6BVTxHww== X-IronPort-AV: E=McAfee;i="6000,8403,9911"; a="186416567" X-IronPort-AV: E=Sophos;i="5.81,218,1610438400"; d="scan'208";a="186416567" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 18:34:29 -0800 IronPort-SDR: n0UL6fGdVNHl8W5/m1Du4jcoHzc4CvwcKaJhBmiLGOBUSsOxoUBSmB6anPBeRcp9Zpj9i9lEr/ bH9lGEjBfaqg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,218,1610438400"; d="scan'208";a="435051384" Received: from unknown (HELO sh_lab5_1.sh.intel.com) ([10.238.175.190]) by FMSMGA003.fm.intel.com with ESMTP; 02 Mar 2021 18:34:26 -0800 From: Wei Huang To: dev@dpdk.org, rosen.xu@intel.com, qi.z.zhang@intel.com Cc: stable@dpdk.org, tianfei.zhang@intel.com, ferruh.yigit@intel.com, Wei Huang Date: Tue, 2 Mar 2021 21:34:29 -0500 Message-Id: <1614738871-8329-2-git-send-email-wei.huang@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1614738871-8329-1-git-send-email-wei.huang@intel.com> References: <1614738871-8329-1-git-send-email-wei.huang@intel.com> Subject: [dpdk-dev] [PATCH v16 1/3] raw/ifpga: add fpga rsu APIs 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 Sender: "dev" RSU (Remote System Update) depends on secure manager which may be different on various implementations, so a new secure manager device is implemented for adapting such difference. There are five APIs added: 1. rte_pmd_ifpga_get_dev_id() get raw device ID of ifpga device from PCI address like 'Domain:Bus:Dev.Func'. 2. rte_pmd_ifpga_update_flash() update flash with specific image file. 3. rte_pmd_ifpga_stop_update() abort flash update process. 4. rte_pmd_ifpga_reboot_try() check current ifpga status and change it to reboot status if it is idle. 5. rte_pmd_ifpga_reload() trigger full reconfiguration of ifpga device. Signed-off-by: Wei Huang Acked-by: Tianfei Zhang Acked-by: Rosen Xu --- v2: fix coding style issue in ifpga_fme_rsu.c and ifpga_sec_mgr.c --- v3: fix compilation issues in ifpga_fme_rsu.c --- v4: fix compilation issues in opae_intel_max10.c --- v5: implement APIs in rte_pmd_ifpga.c --- doc/api/doxy-api-index.md | 3 +- doc/api/doxy-api.conf.in | 1 + drivers/raw/ifpga/base/ifpga_api.c | 26 + drivers/raw/ifpga/base/ifpga_fme.c | 8 + drivers/raw/ifpga/base/ifpga_fme_rsu.c | 428 +++++++++++++++ drivers/raw/ifpga/base/ifpga_hw.h | 1 + drivers/raw/ifpga/base/ifpga_sec_mgr.c | 639 ++++++++++++++++++++++ drivers/raw/ifpga/base/ifpga_sec_mgr.h | 93 ++++ drivers/raw/ifpga/base/meson.build | 2 + drivers/raw/ifpga/base/opae_hw_api.c | 59 ++ drivers/raw/ifpga/base/opae_hw_api.h | 10 + drivers/raw/ifpga/base/opae_intel_max10.c | 48 ++ drivers/raw/ifpga/base/opae_intel_max10.h | 44 ++ drivers/raw/ifpga/meson.build | 4 +- drivers/raw/ifpga/rte_pmd_ifpga.c | 163 ++++++ drivers/raw/ifpga/rte_pmd_ifpga.h | 132 +++++ drivers/raw/ifpga/version.map | 11 + 17 files changed, 1670 insertions(+), 2 deletions(-) create mode 100644 drivers/raw/ifpga/base/ifpga_fme_rsu.c create mode 100644 drivers/raw/ifpga/base/ifpga_sec_mgr.c create mode 100644 drivers/raw/ifpga/base/ifpga_sec_mgr.h create mode 100644 drivers/raw/ifpga/rte_pmd_ifpga.c create mode 100644 drivers/raw/ifpga/rte_pmd_ifpga.h diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index 748514e243..8a48af1042 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -56,7 +56,8 @@ The public API headers are grouped by topics: [dpaa2_qdma] (@ref rte_pmd_dpaa2_qdma.h), [crypto_scheduler] (@ref rte_cryptodev_scheduler.h), [dlb] (@ref rte_pmd_dlb.h), - [dlb2] (@ref rte_pmd_dlb2.h) + [dlb2] (@ref rte_pmd_dlb2.h), + [ifpga] (@ref rte_pmd_ifpga.h) - **memory**: [memseg] (@ref rte_memory.h), diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in index 5c883b613b..5eb31508fd 100644 --- a/doc/api/doxy-api.conf.in +++ b/doc/api/doxy-api.conf.in @@ -23,6 +23,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \ @TOPDIR@/drivers/net/softnic \ @TOPDIR@/drivers/raw/dpaa2_cmdif \ @TOPDIR@/drivers/raw/dpaa2_qdma \ + @TOPDIR@/drivers/raw/ifpga \ @TOPDIR@/drivers/raw/ioat \ @TOPDIR@/lib/librte_eal/include \ @TOPDIR@/lib/librte_eal/include/generic \ diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c index 1ff57fa188..1aedf150bc 100644 --- a/drivers/raw/ifpga/base/ifpga_api.c +++ b/drivers/raw/ifpga/base/ifpga_api.c @@ -5,6 +5,7 @@ #include "ifpga_api.h" #include "ifpga_enumerate.h" #include "ifpga_feature_dev.h" +#include "ifpga_sec_mgr.h" #include "opae_hw_api.h" @@ -228,11 +229,36 @@ static int ifpga_mgr_get_board_info(struct opae_manager *mgr, return 0; } +static int ifpga_mgr_update_flash(struct opae_manager *mgr, const char *image, + u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fpga_update_flash(fme, image, status); +} + +static int ifpga_mgr_stop_flash_update(struct opae_manager *mgr, int force) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fpga_stop_flash_update(fme, force); +} + +static int ifpga_mgr_reload(struct opae_manager *mgr, int type, int page) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fpga_reload(fme, type, page); +} + struct opae_manager_ops ifpga_mgr_ops = { .flash = ifpga_mgr_flash, .get_eth_group_region_info = ifpga_mgr_get_eth_group_region_info, .get_sensor_value = ifpga_mgr_get_sensor_value, .get_board_info = ifpga_mgr_get_board_info, + .update_flash = ifpga_mgr_update_flash, + .stop_flash_update = ifpga_mgr_stop_flash_update, + .reload = ifpga_mgr_reload, }; static int ifpga_mgr_read_mac_rom(struct opae_manager *mgr, int offset, diff --git a/drivers/raw/ifpga/base/ifpga_fme.c b/drivers/raw/ifpga/base/ifpga_fme.c index f29ff3159b..34fd9a818e 100644 --- a/drivers/raw/ifpga/base/ifpga_fme.c +++ b/drivers/raw/ifpga/base/ifpga_fme.c @@ -7,6 +7,7 @@ #include "opae_intel_max10.h" #include "opae_i2c.h" #include "opae_at24_eeprom.h" +#include "ifpga_sec_mgr.h" #define PWR_THRESHOLD_MAX 0x7F @@ -1152,6 +1153,12 @@ static int fme_nios_spi_init(struct ifpga_feature *feature) if (spi_self_checking(max10)) goto spi_fail; + ret = init_sec_mgr(fme); + if (ret) { + dev_err(fme, "security manager init fail\n"); + goto spi_fail; + } + return ret; spi_fail: @@ -1165,6 +1172,7 @@ static void fme_nios_spi_uinit(struct ifpga_feature *feature) { struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + release_sec_mgr(fme); if (fme->max10_dev) intel_max10_device_remove(fme->max10_dev); } diff --git a/drivers/raw/ifpga/base/ifpga_fme_rsu.c b/drivers/raw/ifpga/base/ifpga_fme_rsu.c new file mode 100644 index 0000000000..28198abd78 --- /dev/null +++ b/drivers/raw/ifpga/base/ifpga_fme_rsu.c @@ -0,0 +1,428 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#include +#include +#include +#include "ifpga_sec_mgr.h" + +static struct ifpga_sec_mgr *sec_mgr; + +static void set_rsu_control(struct ifpga_sec_mgr *smgr, uint32_t ctrl) +{ + if (smgr && smgr->rsu_control) + *smgr->rsu_control = ctrl; +} + +static uint32_t get_rsu_control(struct ifpga_sec_mgr *smgr) +{ + if (smgr && smgr->rsu_control) + return *smgr->rsu_control; + return 0; +} + +static void set_rsu_status(struct ifpga_sec_mgr *smgr, uint32_t status, + uint32_t progress) +{ + if (smgr && smgr->rsu_status) + *smgr->rsu_status = IFPGA_RSU_STATUS(status, progress); +} + +static void get_rsu_status(struct ifpga_sec_mgr *smgr, uint32_t *status, + uint32_t *progress) +{ + if (smgr && smgr->rsu_status) { + if (status) + *status = IFPGA_RSU_GET_STAT(*smgr->rsu_status); + if (progress) + *progress = IFPGA_RSU_GET_PROG(*smgr->rsu_status); + } +} + +static void sig_handler(int sig, siginfo_t *info, void *data) +{ + (void)(info); + (void)(data); + + switch (sig) { + case SIGINT: + if (sec_mgr) { + dev_info(sec_mgr, "Interrupt secure flash update" + " by keyboard\n"); + set_rsu_control(sec_mgr, IFPGA_RSU_ABORT); + } + break; + default: + break; + } +} + +static void log_time(time_t t, const char *msg) +{ + uint32_t h = 0; + uint32_t m = 0; + uint32_t s = 0; + + if (t < 60) { + s = (uint32_t)t; + } else if (t < 3600) { + s = (uint32_t)(t % 60); + m = (uint32_t)(t / 60); + } else { + s = (uint32_t)(t % 60); + m = (uint32_t)((t % 3600) / 60); + h = (uint32_t)(t / 3600); + } + printf("%s - %02u:%02u:%02u\n", msg, h, m, s); +} + +static int start_flash_update(struct ifpga_sec_mgr *smgr) +{ + if (!smgr) + return -ENODEV; + + if (!smgr->ops || !smgr->ops->prepare) + return -EINVAL; + + return smgr->ops->prepare(smgr); +} + +static int write_flash_image(struct ifpga_sec_mgr *smgr, const char *image, + uint32_t offset) +{ + void *buf = NULL; + int retry = 0; + uint32_t length = 0; + uint32_t to_transfer = 0; + uint32_t one_percent = 0; + uint32_t prog = 0; + uint32_t old_prog = -1; + ssize_t read_size = 0; + int fd = -1; + int ret = 0; + + if (!smgr) + return -ENODEV; + + if (!smgr->ops || !smgr->ops->write_blk) + return -EINVAL; + + fd = open(image, O_RDONLY); + if (fd < 0) { + dev_err(smgr, + "Failed to open \'%s\' for RD [e:%s]\n", + image, strerror(errno)); + return -EIO; + } + + buf = malloc(IFPGA_RSU_DATA_BLK_SIZE); + if (!buf) { + dev_err(smgr, "Failed to allocate memory for flash update\n"); + close(fd); + return -ENOMEM; + } + + length = smgr->rsu_length; + one_percent = length / 100; + do { + to_transfer = (length > IFPGA_RSU_DATA_BLK_SIZE) ? + IFPGA_RSU_DATA_BLK_SIZE : length; + lseek(fd, offset, SEEK_SET); + read_size = read(fd, buf, to_transfer); + if (read_size < 0) { + dev_err(smgr, "Failed to read from \'%s\' [e:%s]\n", + image, strerror(errno)); + ret = -EIO; + goto end; + } + if ((uint32_t)read_size != to_transfer) { + dev_err(smgr, + "Read length %zd is not expected [e:%u]\n", + read_size, to_transfer); + ret = -EIO; + goto end; + } + + retry = 0; + do { + if (get_rsu_control(smgr) == IFPGA_RSU_ABORT) { + ret = -EAGAIN; + goto end; + } + ret = smgr->ops->write_blk(smgr, buf, offset, + to_transfer); + if (ret == 0) + break; + sleep(1); + } while (++retry <= IFPGA_RSU_WRITE_RETRY); + if (retry > IFPGA_RSU_WRITE_RETRY) { + dev_err(smgr, "Failed to write to staging area 0x%x\n", + offset); + ret = -EAGAIN; + goto end; + } + + length -= to_transfer; + offset += to_transfer; + prog = offset / one_percent; + if (prog != old_prog) { + printf("\r%d%%", prog); + fflush(stdout); + set_rsu_status(smgr, IFPGA_RSU_READY, prog); + old_prog = prog; + } + } while (length > 0); + set_rsu_status(smgr, IFPGA_RSU_READY, 100); + printf("\n"); + +end: + free(buf); + close(fd); + return ret; +} + +static int apply_flash_update(struct ifpga_sec_mgr *smgr) +{ + uint32_t one_percent = 0; + uint32_t one_percent_time = 0; + uint32_t prog = 0; + uint32_t old_prog = -1; + uint32_t copy_time = 0; + int ret = 0; + + if (!smgr) + return -ENODEV; + + if (!smgr->ops || !smgr->ops->write_done || !smgr->ops->check_complete) + return -EINVAL; + + if (smgr->ops->write_done(smgr) < 0) { + dev_err(smgr, "Failed to apply flash update\n"); + return -EAGAIN; + } + + one_percent = (smgr->rsu_length + 99) / 100; + if (smgr->copy_speed == 0) /* avoid zero divide fault */ + smgr->copy_speed = 1; + one_percent_time = (one_percent + smgr->copy_speed - 1) / + smgr->copy_speed; + if (one_percent_time == 0) /* avoid zero divide fault */ + one_percent_time = 1; + + do { + ret = smgr->ops->check_complete(smgr); + if (ret != -EAGAIN) + break; + sleep(1); + copy_time += 1; + prog = copy_time / one_percent_time; + if (prog >= 100) + prog = 99; + if (prog != old_prog) { + printf("\r%d%%", prog); + fflush(stdout); + set_rsu_status(smgr, IFPGA_RSU_COPYING, prog); + old_prog = prog; + } + } while (true); + + if (ret < 0) { + printf("\n"); + dev_err(smgr, "Failed to complete secure flash update\n"); + } else { + printf("\r100%%\n"); + set_rsu_status(smgr, IFPGA_RSU_COPYING, 100); + } + + return ret; +} + +static int secure_update_cancel(struct ifpga_sec_mgr *smgr) +{ + if (!smgr) + return -ENODEV; + + if (!smgr->ops || !smgr->ops->cancel) + return -EINVAL; + + return smgr->ops->cancel(smgr); +} + +static int secure_update_status(struct ifpga_sec_mgr *smgr, uint64_t *status) +{ + if (!smgr) + return -ENODEV; + + if (!smgr->ops || !smgr->ops->get_hw_errinfo) + return -EINVAL; + + if (status) + *status = smgr->ops->get_hw_errinfo(smgr); + + return 0; +} + +int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image, + uint64_t *status) +{ + struct ifpga_hw *hw = NULL; + struct ifpga_sec_mgr *smgr = NULL; + uint32_t rsu_stat = 0; + int fd = -1; + struct sigaction old_sigint_action; + struct sigaction sa; + time_t start; + int ret = 0; + + if (!fme || !image || !status) { + dev_err(fme, "Input parameter of %s is invalid\n", __func__); + return -EINVAL; + } + + hw = (struct ifpga_hw *)fme->parent; + if (!hw) { + dev_err(fme, "Parent of FME not found\n"); + return -ENODEV; + } + + smgr = (struct ifpga_sec_mgr *)fme->sec_mgr; + if (!smgr || !smgr->max10_dev) { + dev_err(smgr, "Security manager not initialized\n"); + return -ENODEV; + } + + opae_adapter_lock(hw->adapter, -1); + get_rsu_status(smgr, &rsu_stat, NULL); + if (rsu_stat != IFPGA_RSU_IDLE) { + opae_adapter_unlock(hw->adapter); + if (rsu_stat == IFPGA_RSU_REBOOT) + dev_info(smgr, "Reboot is in progress\n"); + else + dev_info(smgr, "Update is in progress\n"); + return -EAGAIN; + } + set_rsu_control(smgr, 0); + set_rsu_status(smgr, IFPGA_RSU_PREPARE, 0); + opae_adapter_unlock(hw->adapter); + + fd = open(image, O_RDONLY); + if (fd < 0) { + dev_err(smgr, + "Failed to open \'%s\' for RD [e:%s]\n", + image, strerror(errno)); + return -EIO; + } + smgr->rsu_length = lseek(fd, 0, SEEK_END); + close(fd); + + if (smgr->max10_dev->staging_area_size < smgr->rsu_length) { + dev_err(dev, "Size of staging area is small than image length " + "[%u<%u]\n", smgr->max10_dev->staging_area_size, + smgr->rsu_length); + return -EINVAL; + } + + printf("Updating from file \'%s\' with size %u\n", + image, smgr->rsu_length); + + sec_mgr = smgr; + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_flags = SA_SIGINFO | SA_RESETHAND; + sa.sa_sigaction = sig_handler; + ret = sigaction(SIGINT, &sa, &old_sigint_action); + if (ret < 0) { + dev_warn(dev, "Failed to register signal handler" + " [e:%d]\n", ret); + sec_mgr = NULL; + } + + start = time(NULL); + log_time(time(NULL) - start, "Starting secure flash update"); + ret = start_flash_update(smgr); + if (ret < 0) + goto end; + + set_rsu_status(smgr, IFPGA_RSU_READY, 0); + log_time(time(NULL) - start, "Writing to staging area"); + ret = write_flash_image(smgr, image, 0); + if (ret < 0) + goto end; + + set_rsu_status(smgr, IFPGA_RSU_COPYING, 0); + log_time(time(NULL) - start, "Applying secure flash update"); + ret = apply_flash_update(smgr); + +end: + if (sec_mgr) { + sec_mgr = NULL; + if (sigaction(SIGINT, &old_sigint_action, NULL) < 0) + dev_err(smgr, "Failed to unregister signal handler\n"); + } + + secure_update_status(smgr, status); + if (ret < 0) { + log_time(time(NULL) - start, "Secure flash update ERROR"); + if (ret == -EAGAIN) + secure_update_cancel(smgr); + } else { + log_time(time(NULL) - start, "Secure flash update OK"); + } + set_rsu_status(smgr, IFPGA_RSU_IDLE, 0); + + return ret; +} + +int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force) +{ + struct ifpga_sec_mgr *smgr = NULL; + uint32_t status = 0; + int retry = IFPGA_RSU_CANCEL_RETRY; + int ret = 0; + + if (!fme) { + dev_err(fme, "Input parameter of %s is invalid\n", __func__); + return -EINVAL; + } + smgr = (struct ifpga_sec_mgr *)fme->sec_mgr; + + get_rsu_status(smgr, &status, NULL); + if (status != IFPGA_RSU_IDLE) { + dev_info(smgr, "Cancel secure flash update\n"); + set_rsu_control(smgr, IFPGA_RSU_ABORT); + } + + if (force) { + sleep(2); + do { + get_rsu_status(smgr, &status, NULL); + if (status == IFPGA_RSU_IDLE) + break; + if (secure_update_cancel(smgr) == 0) + set_rsu_status(smgr, IFPGA_RSU_IDLE, 0); + sleep(1); + } while (--retry > 0); + if (retry <= 0) { + dev_err(smgr, "Failed to stop flash update\n"); + ret = -EAGAIN; + } + } + + return ret; +} + +int fpga_reload(struct ifpga_fme_hw *fme, int type, int page) +{ + struct ifpga_sec_mgr *smgr = NULL; + + if (!fme) { + dev_err(fme, "Input parameter of %s is invalid\n", __func__); + return -EINVAL; + } + smgr = (struct ifpga_sec_mgr *)fme->sec_mgr; + + if (!smgr || !smgr->ops || !smgr->ops->reload) + return -EINVAL; + + return smgr->ops->reload(smgr, type, page); +} diff --git a/drivers/raw/ifpga/base/ifpga_hw.h b/drivers/raw/ifpga/base/ifpga_hw.h index 7c3307fe77..ed5edc6016 100644 --- a/drivers/raw/ifpga/base/ifpga_hw.h +++ b/drivers/raw/ifpga/base/ifpga_hw.h @@ -91,6 +91,7 @@ struct ifpga_fme_hw { struct opae_board_info board_info; int nums_eth_dev; unsigned int nums_acc_region; + void *sec_mgr; }; enum ifpga_port_state { diff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.c b/drivers/raw/ifpga/base/ifpga_sec_mgr.c new file mode 100644 index 0000000000..4cf1db3049 --- /dev/null +++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.c @@ -0,0 +1,639 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#include +#include +#include +#include "ifpga_sec_mgr.h" + + +static const char * const rsu_prog[] = {"IDLE", "PREPARING", "SLEEPING", + "READY", "AUTHENTICATING", "COPYING", "CANCELLATION", "PROGRAMMING_KEY", + "DONE", "PKVL_DONE"}; +static const char * const rsu_statl[] = {"NORMAL", "TIMEOUT", "AUTH_FAIL", + "COPY_FAIL", "FATAL", "PKVL_REJECT", "NON_INCR", "ERASE_FAIL", + "WEAROUT"}; +static const char * const rsu_stath[] = {"NIOS_OK", "USER_OK", "FACTORY_OK", + "USER_FAIL", "FACTORY_FAIL", "NIOS_FLASH_ERR", "FPGA_FLASH_ERR"}; + +static const char *rsu_progress_name(uint32_t prog) +{ + if (prog > SEC_PROGRESS_PKVL_PROM_DONE) + return "UNKNOWN"; + else + return rsu_prog[prog]; +} + +static const char *rsu_status_name(uint32_t stat) +{ + if (stat >= SEC_STATUS_NIOS_OK) { + if (stat > SEC_STATUS_FPGA_FLASH_ERR) + return "UNKNOWN"; + else + return rsu_stath[stat-SEC_STATUS_NIOS_OK]; + } else { + if (stat > SEC_STATUS_WEAROUT) + return "UNKNOWN"; + else + return rsu_statl[stat]; + } +} + +static bool secure_start_done(uint32_t doorbell) +{ + return (SEC_STATUS_G(doorbell) == SEC_STATUS_ERASE_FAIL || + SEC_STATUS_G(doorbell) == SEC_STATUS_WEAROUT || + (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_IDLE && + SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_RSU_DONE)); +} + +static bool secure_prog_ready(uint32_t doorbell) +{ + return (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY); +} + +static int poll_timeout(struct intel_max10_device *dev, uint32_t offset, + bool (*cond)(uint32_t), uint32_t interval_ms, uint32_t timeout_ms) +{ + uint32_t val = 0; + int ret = 0; + + for (;;) { + ret = max10_sys_read(dev, offset, &val); + if (ret < 0) { + dev_err(dev, + "Failed to read max10 register 0x%x [e:%d]\n", + offset, ret); + break; + } + + if (cond(val)) { + dev_debug(dev, + "Read 0x%08x from max10 register 0x%x " + "[poll success]\n", val, offset); + ret = 0; + break; + } + if (timeout_ms > interval_ms) + timeout_ms -= interval_ms; + else + timeout_ms = 0; + if (timeout_ms == 0) { + dev_debug(dev, + "Read 0x%08x from max10 register 0x%x " + "[poll timeout]\n", val, offset); + ret = -ETIMEDOUT; + break; + } + msleep(interval_ms); + } + + return ret; +} + +static int n3000_secure_update_start(struct intel_max10_device *dev) +{ + uint32_t doorbell = 0; + uint32_t prog = 0; + uint32_t status = 0; + int ret = 0; + + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); + if (ret < 0) { + dev_err(dev, + "Failed to read max10 doorbell register [e:%d]\n", + ret); + return ret; + } + + prog = SEC_PROGRESS_G(doorbell); + if ((prog != SEC_PROGRESS_IDLE) && (prog != SEC_PROGRESS_RSU_DONE)) { + dev_debug(dev, "Current RSU progress is %s\n", + rsu_progress_name(prog)); + return -EBUSY; + } + + ret = max10_sys_update_bits(dev, MAX10_DOORBELL, + RSU_REQUEST | HOST_STATUS, RSU_REQUEST); + if (ret < 0) { + dev_err(dev, + "Failed to updt max10 doorbell register [e:%d]\n", + ret); + return ret; + } + + ret = poll_timeout(dev, MAX10_DOORBELL, secure_start_done, + IFPGA_SEC_START_INTERVAL_MS, IFPGA_SEC_START_TIMEOUT_MS); + if (ret < 0) { + dev_err(dev, + "Failed to poll max10 doorbell register [e:%d]\n", + ret); + return ret; + } + + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); + if (ret < 0) { + dev_err(dev, + "Failed to read max10 doorbell register [e:%d]\n", + ret); + return ret; + } + + status = SEC_STATUS_G(doorbell); + if (status == SEC_STATUS_WEAROUT) + return -EAGAIN; + + if (status == SEC_STATUS_ERASE_FAIL) + return -EIO; + + return 0; +} + +static int n3000_cancel(struct ifpga_sec_mgr *smgr) +{ + struct intel_max10_device *dev = NULL; + uint32_t doorbell = 0; + uint32_t prog = 0; + int ret = 0; + + if (!smgr || !smgr->max10_dev) + return -ENODEV; + dev = (struct intel_max10_device *)smgr->max10_dev; + + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); + if (ret < 0) { + dev_err(dev, + "Failed to read max10 doorbell register [e:%d]\n", + ret); + return ret; + } + + prog = SEC_PROGRESS_G(doorbell); + if (prog == SEC_PROGRESS_IDLE) + return 0; + if (prog != SEC_PROGRESS_READY) + return -EBUSY; + + return max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS, + HOST_STATUS_S(HOST_STATUS_ABORT_RSU)); +} + +static int n3000_prepare(struct ifpga_sec_mgr *smgr) +{ + struct intel_max10_device *dev = NULL; + int retry = 0; + int ret = 0; + + if (!smgr || !smgr->max10_dev) + return -ENODEV; + dev = (struct intel_max10_device *)smgr->max10_dev; + + ret = n3000_secure_update_start(dev); + if (ret == -EBUSY) + n3000_cancel(smgr); + + while (ret) { + if (++retry > IFPGA_RSU_START_RETRY) + break; + msleep(1000); + ret = n3000_secure_update_start(dev); + } + if (retry > IFPGA_RSU_START_RETRY) { + dev_err(dev, "Failed to start secure flash update\n"); + ret = -EAGAIN; + } + + return ret; +} + +static int n3000_bulk_write(struct intel_max10_device *dev, uint32_t addr, + char *buf, uint32_t len) +{ + uint32_t i = 0; + uint32_t n = 0; + uint32_t v = 0; + uint32_t p = 0; + int ret = 0; + + if (len & 0x3) { + dev_err(dev, + "Length of data block is not 4 bytes aligned [e:%u]\n", + len); + return -EINVAL; + } + + n = len >> 2; + for (i = 0; i < n; i++) { + p = i << 2; + v = *(uint32_t *)(buf + p); + ret = max10_reg_write(dev, addr + p, v); + if (ret < 0) { + dev_err(dev, + "Failed to write to staging area 0x%08x [e:%d]\n", + addr + p, ret); + return ret; + } + usleep(1); + } + + return 0; +} + +static int n3000_write_blk(struct ifpga_sec_mgr *smgr, char *buf, + uint32_t offset, uint32_t len) +{ + struct intel_max10_device *dev = NULL; + uint32_t doorbell = 0; + uint32_t prog = 0; + uint32_t m = 0; + int ret = 0; + + if (!smgr || !smgr->max10_dev) + return -ENODEV; + dev = (struct intel_max10_device *)smgr->max10_dev; + + if (offset + len > dev->staging_area_size) { + dev_err(dev, + "Write position would be out of staging area [e:%u]\n", + dev->staging_area_size); + return -ENOMEM; + } + + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); + if (ret < 0) { + dev_err(dev, + "Failed to read max10 doorbell register [e:%d]\n", + ret); + return ret; + } + + prog = SEC_PROGRESS_G(doorbell); + if (prog == SEC_PROGRESS_PREPARE) + return -EAGAIN; + else if (prog != SEC_PROGRESS_READY) + return -EBUSY; + + m = len & 0x3; + if (m != 0) + len += 4 - m; /* make length to 4 bytes align */ + + return n3000_bulk_write(dev, dev->staging_area_base + offset, buf, len); +} + +static int n3000_write_done(struct ifpga_sec_mgr *smgr) +{ + struct intel_max10_device *dev = NULL; + uint32_t doorbell = 0; + uint32_t prog = 0; + uint32_t status = 0; + int ret = 0; + + if (!smgr || !smgr->max10_dev) + return -ENODEV; + dev = (struct intel_max10_device *)smgr->max10_dev; + + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); + if (ret < 0) { + dev_err(dev, + "Failed to read max10 doorbell register [e:%d]\n", + ret); + return ret; + } + + prog = SEC_PROGRESS_G(doorbell); + if (prog != SEC_PROGRESS_READY) + return -EBUSY; + + ret = max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS, + HOST_STATUS_S(HOST_STATUS_WRITE_DONE)); + if (ret < 0) { + dev_err(dev, + "Failed to update max10 doorbell register [e:%d]\n", + ret); + return ret; + } + + ret = poll_timeout(dev, MAX10_DOORBELL, secure_prog_ready, + IFPGA_NIOS_HANDSHAKE_INTERVAL_MS, + IFPGA_NIOS_HANDSHAKE_TIMEOUT_MS); + if (ret < 0) { + dev_err(dev, + "Failed to poll max10 doorbell register [e:%d]\n", + ret); + return ret; + } + + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); + if (ret < 0) { + dev_err(dev, + "Failed to read max10 doorbell register [e:%d]\n", + ret); + return ret; + } + + status = SEC_STATUS_G(doorbell); + switch (status) { + case SEC_STATUS_NORMAL: + case SEC_STATUS_NIOS_OK: + case SEC_STATUS_USER_OK: + case SEC_STATUS_FACTORY_OK: + ret = 0; + break; + default: + ret = -EIO; + break; + } + + return ret; +} + +static int n3000_check_complete(struct ifpga_sec_mgr *smgr) +{ + struct intel_max10_device *dev = NULL; + uint32_t doorbell = 0; + uint32_t status = 0; + uint32_t prog = 0; + int ret = 0; + + if (!smgr || !smgr->max10_dev) + return -ENODEV; + dev = (struct intel_max10_device *)smgr->max10_dev; + + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); + if (ret < 0) { + dev_err(dev, + "Failed to read max10 doorbell register [e:%d]\n", + ret); + return ret; + } + + status = SEC_STATUS_G(doorbell); + switch (status) { + case SEC_STATUS_NORMAL: + case SEC_STATUS_NIOS_OK: + case SEC_STATUS_USER_OK: + case SEC_STATUS_FACTORY_OK: + case SEC_STATUS_WEAROUT: + break; + default: + return -EIO; + } + + prog = SEC_PROGRESS_G(doorbell); + switch (prog) { + case SEC_PROGRESS_IDLE: + case SEC_PROGRESS_RSU_DONE: + return 0; + case SEC_PROGRESS_AUTHENTICATING: + case SEC_PROGRESS_COPYING: + case SEC_PROGRESS_UPDATE_CANCEL: + case SEC_PROGRESS_PROGRAM_KEY_HASH: + return -EAGAIN; + case SEC_PROGRESS_PREPARE: + case SEC_PROGRESS_READY: + return -EBUSY; + default: + return -EIO; + } + + return 0; +} + +static int n3000_reload_fpga(struct intel_max10_device *dev, int page) +{ + int ret = 0; + + dev_info(dev, "Reload FPGA\n"); + + if (!dev || ((page != 0) && (page != 1))) { + dev_err(dev, "Input parameter of %s is invalid\n", __func__); + ret = -EINVAL; + goto end; + } + + if (dev->flags & MAX10_FLAGS_SECURE) { + ret = max10_sys_update_bits(dev, FPGA_RECONF_REG, + SFPGA_RP_LOAD, 0); + if (ret < 0) { + dev_err(dev, + "Failed to update max10 reconfig register [e:%d]\n", + ret); + goto end; + } + ret = max10_sys_update_bits(dev, FPGA_RECONF_REG, + SFPGA_RP_LOAD | SFPGA_RECONF_PAGE, + SFPGA_RP_LOAD | SFPGA_PAGE(page)); + if (ret < 0) { + dev_err(dev, + "Failed to update max10 reconfig register [e:%d]\n", + ret); + goto end; + } + } else { + ret = max10_sys_update_bits(dev, RSU_REG, FPGA_RP_LOAD, 0); + if (ret < 0) { + dev_err(dev, + "Failed to update max10 rsu register [e:%d]\n", + ret); + goto end; + } + ret = max10_sys_update_bits(dev, RSU_REG, + FPGA_RP_LOAD | FPGA_RECONF_PAGE, + FPGA_RP_LOAD | FPGA_PAGE(page)); + if (ret < 0) { + dev_err(dev, + "Failed to update max10 rsu register [e:%d]\n", + ret); + goto end; + } + } + + ret = max10_sys_update_bits(dev, FPGA_RECONF_REG, COUNTDOWN_START, 0); + if (ret < 0) { + dev_err(dev, + "Failed to update max10 reconfig register [e:%d]\n", + ret); + goto end; + } + + ret = max10_sys_update_bits(dev, FPGA_RECONF_REG, COUNTDOWN_START, + COUNTDOWN_START); + if (ret < 0) { + dev_err(dev, + "Failed to update max10 reconfig register [e:%d]\n", + ret); + } +end: + if (ret < 0) + dev_err(dev, "Failed to reload FPGA\n"); + + return ret; +} + +static int n3000_reload_bmc(struct intel_max10_device *dev, int page) +{ + uint32_t val = 0; + int ret = 0; + + dev_info(dev, "Reload BMC\n"); + + if (!dev || ((page != 0) && (page != 1))) { + dev_err(dev, "Input parameter of %s is invalid\n", __func__); + ret = -EINVAL; + goto end; + } + + if (dev->flags & MAX10_FLAGS_SECURE) { + ret = max10_sys_update_bits(dev, MAX10_DOORBELL, + CONFIG_SEL | REBOOT_REQ, + CONFIG_SEL_S(page) | REBOOT_REQ); + } else { + val = (page == 0) ? 0x1 : 0x3; + ret = max10_reg_write(dev, IFPGA_DUAL_CFG_CTRL1, val); + if (ret < 0) { + dev_err(dev, + "Failed to write to dual config1 register [e:%d]\n", + ret); + goto end; + } + + ret = max10_reg_write(dev, IFPGA_DUAL_CFG_CTRL0, 0x1); + if (ret < 0) { + if (ret == -EIO) { + ret = 0; + goto end; + } + dev_err(dev, + "Failed to write to dual config0 register [e:%d]\n", + ret); + } + } + +end: + if (ret < 0) + dev_err(dev, "Failed to reload BMC\n"); + + return ret; +} + +static int n3000_reload(struct ifpga_sec_mgr *smgr, int type, int page) +{ + int psel = 0; + int ret = 0; + + if (!smgr || !smgr->max10_dev) + return -ENODEV; + + if (type == IFPGA_BOOT_TYPE_FPGA) { + psel = (page == IFPGA_BOOT_PAGE_FACTORY ? 0 : 1); + ret = n3000_reload_fpga(smgr->max10_dev, psel); + } else if (type == IFPGA_BOOT_TYPE_BMC) { + psel = (page == IFPGA_BOOT_PAGE_FACTORY ? 1 : 0); + ret = n3000_reload_bmc(smgr->max10_dev, psel); + } else { + ret = -EINVAL; + } + + return ret; +} + +static uint64_t n3000_get_hw_errinfo(struct ifpga_sec_mgr *smgr) +{ + struct intel_max10_device *dev = NULL; + uint32_t doorbell = 0; + uint32_t stat = 0; + uint32_t prog = 0; + uint32_t auth_result = 0; + int ret = 0; + + if (!smgr || !smgr->max10_dev) + return -ENODEV; + dev = (struct intel_max10_device *)smgr->max10_dev; + + ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); + if (ret < 0) { + dev_err(dev, "Failed to read max10 doorbell register [e:%d]\n", + ret); + return -1; + } + stat = SEC_STATUS_G(doorbell); + prog = SEC_PROGRESS_G(doorbell); + dev_debug(dev, "Current RSU status is %s, progress is %s\n", + rsu_status_name(stat), rsu_progress_name(prog)); + + ret = max10_sys_read(dev, MAX10_AUTH_RESULT, &auth_result); + if (ret < 0) { + dev_err(dev, + "Failed to read authenticate result register [e:%d]\n", + ret); + return -1; + } + + return (uint64_t)doorbell << 32 | (uint64_t)auth_result; +} + +static const struct ifpga_sec_ops n3000_sec_ops = { + .prepare = n3000_prepare, + .write_blk = n3000_write_blk, + .write_done = n3000_write_done, + .check_complete = n3000_check_complete, + .reload = n3000_reload, + .cancel = n3000_cancel, + .cleanup = NULL, + .get_hw_errinfo = n3000_get_hw_errinfo, +}; + +int init_sec_mgr(struct ifpga_fme_hw *fme) +{ + struct ifpga_hw *hw = NULL; + opae_share_data *sd = NULL; + struct ifpga_sec_mgr *smgr = NULL; + + if (!fme || !fme->max10_dev) + return -ENODEV; + + smgr = (struct ifpga_sec_mgr *)malloc(sizeof(*smgr)); + if (!smgr) { + dev_err(NULL, "Failed to allocate memory for security manager\n"); + return -ENOMEM; + } + fme->sec_mgr = smgr; + + hw = (struct ifpga_hw *)fme->parent; + if (hw && hw->adapter && hw->adapter->shm.ptr) { + sd = (opae_share_data *)hw->adapter->shm.ptr; + smgr->rsu_control = &sd->rsu_ctrl; + smgr->rsu_status = &sd->rsu_stat; + } else { + smgr->rsu_control = NULL; + smgr->rsu_status = NULL; + } + + if ((hw->pci_data->device_id == IFPGA_N3000_DID) && + (hw->pci_data->vendor_id == IFPGA_N3000_VID)) { + smgr->ops = &n3000_sec_ops; + smgr->copy_speed = IFPGA_N3000_COPY_SPEED; + } else { + dev_err(NULL, "No operation for security manager\n"); + smgr->ops = NULL; + } + + smgr->fme = fme; + smgr->max10_dev = fme->max10_dev; + + return 0; +} + +void release_sec_mgr(struct ifpga_fme_hw *fme) +{ + struct ifpga_sec_mgr *smgr = NULL; + + if (fme) { + smgr = (struct ifpga_sec_mgr *)fme->sec_mgr; + if (smgr) { + fme->sec_mgr = NULL; + free(smgr); + } + } +} diff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.h b/drivers/raw/ifpga/base/ifpga_sec_mgr.h new file mode 100644 index 0000000000..fbeba561f4 --- /dev/null +++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#ifndef _IFPGA_FME_RSU_H_ +#define _IFPGA_FME_RSU_H_ + + +#include "ifpga_hw.h" + +#define IFPGA_N3000_VID 0x8086 +#define IFPGA_N3000_DID 0x0b30 + +#define IFPGA_BOOT_TYPE_FPGA 0 +#define IFPGA_BOOT_TYPE_BMC 1 + +#define IFPGA_BOOT_PAGE_FACTORY 0 +#define IFPGA_BOOT_PAGE_USER 1 + +#define IFPGA_RSU_DATA_BLK_SIZE 32768 +#define IFPGA_RSU_START_RETRY 120 +#define IFPGA_RSU_WRITE_RETRY 10 +#define IFPGA_RSU_CANCEL_RETRY 30 + +#define IFPGA_N3000_COPY_SPEED 42700 + +/* status */ +#define IFPGA_RSU_IDLE 0 +#define IFPGA_RSU_PREPARE 1 +#define IFPGA_RSU_READY 2 +#define IFPGA_RSU_COPYING 3 +#define IFPGA_RSU_REBOOT 4 + +#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)) + +/* control */ +#define IFPGA_RSU_ABORT 1 + +#define IFPGA_DUAL_CFG_CTRL0 0x200020 +#define IFPGA_DUAL_CFG_CTRL1 0x200024 + +#define IFPGA_SEC_START_INTERVAL_MS 100 +#define IFPGA_SEC_START_TIMEOUT_MS 20000 +#define IFPGA_NIOS_HANDSHAKE_INTERVAL_MS 100 +#define IFPGA_NIOS_HANDSHAKE_TIMEOUT_MS 5000 + +#define IFPGA_RSU_ERR_HW_ERROR -1 +#define IFPGA_RSU_ERR_TIMEOUT -2 +#define IFPGA_RSU_ERR_CANCELED -3 +#define IFPGA_RSU_ERR_BUSY -4 +#define IFPGA_RSU_ERR_INVALID_SIZE -5 +#define IFPGA_RSU_ERR_RW_ERROR -6 +#define IFPGA_RSU_ERR_WEAROUT -7 +#define IFPGA_RSU_ERR_FILE_READ -8 + +struct ifpga_sec_mgr; + +struct ifpga_sec_ops { + int (*prepare)(struct ifpga_sec_mgr *smgr); + int (*write_blk)(struct ifpga_sec_mgr *smgr, char *buf, uint32_t offset, + uint32_t size); + int (*write_done)(struct ifpga_sec_mgr *smgr); + int (*check_complete)(struct ifpga_sec_mgr *smgr); + int (*reload)(struct ifpga_sec_mgr *smgr, int type, int page); + int (*cancel)(struct ifpga_sec_mgr *smgr); + void (*cleanup)(struct ifpga_sec_mgr *smgr); + u64 (*get_hw_errinfo)(struct ifpga_sec_mgr *smgr); +}; + +struct ifpga_sec_mgr { + struct ifpga_fme_hw *fme; + struct intel_max10_device *max10_dev; + unsigned int rsu_length; + /* number of bytes that copied from staging area to working area + * in one second, which is calculated by experiment + */ + unsigned int copy_speed; + unsigned int *rsu_control; + unsigned int *rsu_status; + const struct ifpga_sec_ops *ops; +}; + +int init_sec_mgr(struct ifpga_fme_hw *fme); +void release_sec_mgr(struct ifpga_fme_hw *fme); +int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image, + uint64_t *status); +int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force); +int fpga_reload(struct ifpga_fme_hw *fme, int type, int page); + + +#endif /* _IFPGA_FME_RSU_H_ */ diff --git a/drivers/raw/ifpga/base/meson.build b/drivers/raw/ifpga/base/meson.build index da2d6e33ca..3549afafa1 100644 --- a/drivers/raw/ifpga/base/meson.build +++ b/drivers/raw/ifpga/base/meson.build @@ -12,6 +12,8 @@ sources = [ 'ifpga_port.c', 'ifpga_port_error.c', 'ifpga_fme_pr.c', + 'ifpga_fme_rsu.c', + 'ifpga_sec_mgr.c', 'opae_hw_api.c', 'opae_ifpga_hw_api.c', 'opae_debug.c', diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c index d5cd5fe608..86ad88f720 100644 --- a/drivers/raw/ifpga/base/opae_hw_api.c +++ b/drivers/raw/ifpga/base/opae_hw_api.c @@ -470,6 +470,8 @@ static void opae_adapter_shm_init(struct opae_adapter *adapter) opae_mutex_init(&sd->i2c_mutex); sd->ref_cnt = 0; sd->dtb_size = SHM_BLK_SIZE; + sd->rsu_ctrl = 0; + sd->rsu_stat = 0; } static void *opae_adapter_shm_alloc(struct opae_adapter *adapter) @@ -964,3 +966,60 @@ opae_mgr_get_board_info(struct opae_manager *mgr, return -ENOENT; } + +/** + * opae_mgr_update_flash - update image in flash. + * @mgr: targeted manager + * @image: name of image file + * @status: status of update + * + * Return: 0 on success, otherwise error code. + */ +int opae_mgr_update_flash(struct opae_manager *mgr, const char *image, + uint64_t *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr->ops && mgr->ops->update_flash) + return mgr->ops->update_flash(mgr, image, status); + + return -ENOENT; +} + +/** + * opae_stop_flash_update - stop flash update. + * @mgr: targeted manager + * @force: make sure the update process is stopped + * + * Return: 0 on success, otherwise error code. + */ +int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force) +{ + if (!mgr) + return -EINVAL; + + if (mgr->ops && mgr->ops->stop_flash_update) + return mgr->ops->stop_flash_update(mgr, force); + + return -ENOENT; +} + +/** + * opae_mgr_reload - reload FPGA. + * @mgr: targeted manager + * @type: FPGA type + * @page: reload from which page + * + * Return: 0 on success, otherwise error code. + */ +int opae_mgr_reload(struct opae_manager *mgr, int type, int page) +{ + if (!mgr) + return -EINVAL; + + if (mgr->ops && mgr->ops->reload) + return mgr->ops->reload(mgr, type, page); + + return -ENOENT; +} diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h index e99ee4564c..91d26d9b5b 100644 --- a/drivers/raw/ifpga/base/opae_hw_api.h +++ b/drivers/raw/ifpga/base/opae_hw_api.h @@ -55,6 +55,10 @@ struct opae_manager_ops { unsigned int *value); int (*get_board_info)(struct opae_manager *mgr, struct opae_board_info **info); + int (*update_flash)(struct opae_manager *mgr, const char *image, + u64 *status); + int (*stop_flash_update)(struct opae_manager *mgr, int force); + int (*reload)(struct opae_manager *mgr, int type, int page); }; /* networking management ops in FME */ @@ -276,6 +280,8 @@ typedef struct { pthread_mutex_t i2c_mutex; u32 ref_cnt; /* reference count of shared memory */ u32 dtb_size; /* actual length of DTB data in byte */ + u32 rsu_ctrl; /* used to control rsu */ + u32 rsu_stat; /* used to report status for rsu */ }; }; u8 dtb[SHM_BLK_SIZE]; /* DTB data */ @@ -354,4 +360,8 @@ int opae_manager_eth_group_read_reg(struct opae_manager *mgr, u8 group_id, u8 type, u8 index, u16 addr, u32 *data); int opae_mgr_get_board_info(struct opae_manager *mgr, struct opae_board_info **info); +int opae_mgr_update_flash(struct opae_manager *mgr, const char *image, + uint64_t *status); +int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force); +int opae_mgr_reload(struct opae_manager *mgr, int type, int page); #endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga/base/opae_intel_max10.c b/drivers/raw/ifpga/base/opae_intel_max10.c index 1a526ea549..443e248fb3 100644 --- a/drivers/raw/ifpga/base/opae_intel_max10.c +++ b/drivers/raw/ifpga/base/opae_intel_max10.c @@ -51,6 +51,22 @@ int max10_sys_write(struct intel_max10_device *dev, return max10_reg_write(dev, dev->base + offset, val); } +int max10_sys_update_bits(struct intel_max10_device *dev, unsigned int offset, + unsigned int msk, unsigned int val) +{ + int ret = 0; + unsigned int temp = 0; + + ret = max10_sys_read(dev, offset, &temp); + if (ret < 0) + return ret; + + temp &= ~msk; + temp |= val & msk; + + return max10_sys_write(dev, offset, temp); +} + static struct max10_compatible_id max10_id_table[] = { {.compatible = MAX10_PAC,}, {.compatible = MAX10_PAC_N3000,}, @@ -557,6 +573,36 @@ static int check_max10_version(struct intel_max10_device *dev) return -ENODEV; } +static int max10_staging_area_init(struct intel_max10_device *dev) +{ + char *fdt_root = dev->fdt_root; + int ret, offset = 0; + u64 start, size; + + if (!fdt_root) { + dev_debug(dev, + "skip staging area init as not find Device Tree\n"); + return -ENODEV; + } + + dev->staging_area_size = 0; + + fdt_for_each_subnode(offset, fdt_root, 0) { + if (fdt_node_check_compatible(fdt_root, offset, + "ifpga-sec-mgr,staging-area")) + continue; + + ret = fdt_get_reg(fdt_root, offset, 0, &start, &size); + if (!ret) { + dev->staging_area_base = start; + dev->staging_area_size = size; + } + return ret; + } + + return -ENODEV; +} + static int max10_secure_hw_init(struct intel_max10_device *dev) { @@ -581,6 +627,8 @@ max10_secure_hw_init(struct intel_max10_device *dev) max10_sensor_init(dev, sysmgr_offset); + max10_staging_area_init(dev); + return 0; } diff --git a/drivers/raw/ifpga/base/opae_intel_max10.h b/drivers/raw/ifpga/base/opae_intel_max10.h index 123cdc48b9..670683f017 100644 --- a/drivers/raw/ifpga/base/opae_intel_max10.h +++ b/drivers/raw/ifpga/base/opae_intel_max10.h @@ -38,6 +38,8 @@ struct intel_max10_device { unsigned int base; /* max10 base address */ u16 bus; struct opae_sensor_list opae_sensor_list; + u32 staging_area_base; + u32 staging_area_size; }; /* retimer speed */ @@ -98,6 +100,7 @@ struct opae_retimer_status { #define MAX10_MAC_COUNT GENMASK(23, 16) #define RSU_REG 0x2c #define FPGA_RECONF_PAGE GENMASK(2, 0) +#define FPGA_PAGE(p) ((p) & 0x1) #define FPGA_RP_LOAD BIT(3) #define NIOS2_PRERESET BIT(4) #define NIOS2_HANG BIT(5) @@ -106,6 +109,9 @@ struct opae_retimer_status { #define NIOS2_I2C2_POLL_STOP BIT(13) #define PKVL_EEPROM_LOAD BIT(31) #define FPGA_RECONF_REG 0x30 +#define SFPGA_RECONF_PAGE GENMASK(22, 20) +#define SFPGA_PAGE(p) (((p) & 0x1) << 20) +#define SFPGA_RP_LOAD BIT(23) #define MAX10_TEST_REG 0x3c #define COUNTDOWN_START BIT(18) #define MAX10_BUILD_VER 0x68 @@ -118,8 +124,44 @@ struct opae_retimer_status { #define MAX10_DOORBELL 0x400 #define RSU_REQUEST BIT(0) #define SEC_PROGRESS GENMASK(7, 4) +#define SEC_PROGRESS_G(v) (((v) >> 4) & 0xf) +#define SEC_PROGRESS_IDLE 0x0 +#define SEC_PROGRESS_PREPARE 0x1 +#define SEC_PROGRESS_SLEEP 0x2 +#define SEC_PROGRESS_READY 0x3 +#define SEC_PROGRESS_AUTHENTICATING 0x4 +#define SEC_PROGRESS_COPYING 0x5 +#define SEC_PROGRESS_UPDATE_CANCEL 0x6 +#define SEC_PROGRESS_PROGRAM_KEY_HASH 0x7 +#define SEC_PROGRESS_RSU_DONE 0x8 +#define SEC_PROGRESS_PKVL_PROM_DONE 0x9 #define HOST_STATUS GENMASK(11, 8) +#define HOST_STATUS_S(v) (((v) << 8) & 0xf00) +#define HOST_STATUS_IDLE 0x0 +#define HOST_STATUS_WRITE_DONE 0x1 +#define HOST_STATUS_ABORT_RSU 0x2 #define SEC_STATUS GENMASK(23, 16) +#define SEC_STATUS_G(v) (((v) >> 16) & 0xff) +#define SEC_STATUS_NORMAL 0x0 +#define SEC_STATUS_TIMEOUT 0x1 +#define SEC_STATUS_AUTH_FAIL 0x2 +#define SEC_STATUS_COPY_FAIL 0x3 +#define SEC_STATUS_FATAL 0x4 +#define SEC_STATUS_PKVL_REJECT 0x5 +#define SEC_STATUS_NON_INC 0x6 +#define SEC_STATUS_ERASE_FAIL 0x7 +#define SEC_STATUS_WEAROUT 0x8 +#define SEC_STATUS_NIOS_OK 0x80 +#define SEC_STATUS_USER_OK 0x81 +#define SEC_STATUS_FACTORY_OK 0x82 +#define SEC_STATUS_USER_FAIL 0x83 +#define SEC_STATUS_FACTORY_FAIL 0x84 +#define SEC_STATUS_NIOS_FLASH_ERR 0x85 +#define SEC_STATUS_FPGA_FLASH_ERR 0x86 +#define CONFIG_SEL BIT(28) +#define CONFIG_SEL_S(v) (((v) & 0x1) << 28) +#define REBOOT_REQ BIT(29) +#define MAX10_AUTH_RESULT 0x404 /* PKVL related registers, in system register region */ #define PKVL_POLLING_CTRL 0x80 @@ -149,6 +191,8 @@ int max10_sys_read(struct intel_max10_device *dev, unsigned int offset, unsigned int *val); int max10_sys_write(struct intel_max10_device *dev, unsigned int offset, unsigned int val); +int max10_sys_update_bits(struct intel_max10_device *dev, + unsigned int offset, unsigned int msk, unsigned int val); struct intel_max10_device * intel_max10_device_probe(struct altera_spi_device *spi, int chipselect); diff --git a/drivers/raw/ifpga/meson.build b/drivers/raw/ifpga/meson.build index 027ff80562..60ea59ae28 100644 --- a/drivers/raw/ifpga/meson.build +++ b/drivers/raw/ifpga/meson.build @@ -13,8 +13,10 @@ objs = [base_objs] deps += ['ethdev', 'rawdev', 'pci', 'bus_pci', 'kvargs', 'bus_vdev', 'bus_ifpga', 'net', 'net_i40e', 'net_ipn3ke'] -sources = files('ifpga_rawdev.c') +sources = files('ifpga_rawdev.c', 'rte_pmd_ifpga.c') includes += include_directories('base') includes += include_directories('../../net/ipn3ke') includes += include_directories('../../net/i40e') + +headers = files('rte_pmd_ifpga.h') diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.c b/drivers/raw/ifpga/rte_pmd_ifpga.c new file mode 100644 index 0000000000..af6f175e98 --- /dev/null +++ b/drivers/raw/ifpga/rte_pmd_ifpga.c @@ -0,0 +1,163 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Intel Corporation + */ + +#include +#include +#include +#include +#include "rte_pmd_ifpga.h" +#include "ifpga_rawdev.h" +#include "base/ifpga_sec_mgr.h" + + +int +rte_pmd_ifpga_get_dev_id(const char *pci_addr, uint16_t *dev_id) +{ + struct rte_pci_addr addr; + struct rte_rawdev *rdev = NULL; + char rdev_name[RTE_RAWDEV_NAME_MAX_LEN] = {0}; + + if (!pci_addr || !dev_id) { + IFPGA_RAWDEV_PMD_ERR("Input parameter is invalid."); + return -EINVAL; + } + + if (strnlen(pci_addr, PCI_PRI_STR_SIZE) == PCI_PRI_STR_SIZE) { + IFPGA_RAWDEV_PMD_ERR("PCI address is too long."); + return -EINVAL; + } + + if (rte_pci_addr_parse(pci_addr, &addr)) { + IFPGA_RAWDEV_PMD_ERR("PCI address %s is invalid.", pci_addr); + return -EINVAL; + } + + snprintf(rdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%02x:%02x.%x", + addr.bus, addr.devid, addr.function); + rdev = rte_rawdev_pmd_get_named_dev(rdev_name); + if (!rdev) { + IFPGA_RAWDEV_PMD_DEBUG("%s is not probed by ifpga driver.", + pci_addr); + return -ENODEV; + } + *dev_id = rdev->dev_id; + + return 0; +} + +static struct rte_rawdev * +get_rte_rawdev(uint16_t dev_id) +{ + struct rte_rawdev *dev = NULL; + + if (dev_id >= RTE_RAWDEV_MAX_DEVS) + return NULL; + + dev = &rte_rawdevs[dev_id]; + if (dev->attached == RTE_RAWDEV_ATTACHED) + return dev; + + return NULL; +} + +static struct opae_adapter * +get_opae_adapter(uint16_t dev_id) +{ + struct rte_rawdev *dev = NULL; + struct opae_adapter *adapter = NULL; + + dev = get_rte_rawdev(dev_id); + if (!dev) { + IFPGA_RAWDEV_PMD_ERR("Device ID %u is invalid.", dev_id); + return NULL; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) { + IFPGA_RAWDEV_PMD_ERR("Adapter is not registered."); + return NULL; + } + + return adapter; +} + +static opae_share_data * +get_share_data(struct opae_adapter *adapter) +{ + opae_share_data *sd = NULL; + + if (!adapter) + return NULL; + + sd = (opae_share_data *)adapter->shm.ptr; + if (!sd) { + IFPGA_RAWDEV_PMD_ERR("Share data is not initialized."); + return NULL; + } + + return sd; +} + +int +rte_pmd_ifpga_update_flash(uint16_t dev_id, const char *image, + uint64_t *status) +{ + struct opae_adapter *adapter = NULL; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + return opae_mgr_update_flash(adapter->mgr, image, status); +} + +int +rte_pmd_ifpga_stop_update(uint16_t dev_id, int force) +{ + struct opae_adapter *adapter = NULL; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + return opae_mgr_stop_flash_update(adapter->mgr, force); +} + +int +rte_pmd_ifpga_reboot_try(uint16_t dev_id) +{ + struct opae_adapter *adapter = NULL; + opae_share_data *sd = NULL; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + sd = get_share_data(adapter); + if (!sd) + return -ENOMEM; + + opae_adapter_lock(adapter, -1); + if (IFPGA_RSU_GET_STAT(sd->rsu_stat) != IFPGA_RSU_IDLE) { + opae_adapter_unlock(adapter); + IFPGA_RAWDEV_PMD_WARN("Update or reboot is in progress."); + return -EBUSY; + } + sd->rsu_stat = IFPGA_RSU_STATUS(IFPGA_RSU_REBOOT, 0); + opae_adapter_unlock(adapter); + + return 0; +} + +int +rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page) +{ + struct opae_adapter *adapter = NULL; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + return opae_mgr_reload(adapter->mgr, type, page); +} diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h b/drivers/raw/ifpga/rte_pmd_ifpga.h new file mode 100644 index 0000000000..023a011116 --- /dev/null +++ b/drivers/raw/ifpga/rte_pmd_ifpga.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Intel Corporation + */ + +#ifndef _RTE_PMD_IFPGA_H_ +#define _RTE_PMD_IFPGA_H_ + +/** + * @file rte_pmd_ifpga.h + * + * ifpga PMD specific functions. + * + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Get raw device ID from PCI address string like 'Domain:Bus:Dev.Func' + * + * @param pci_addr + * The PCI address of specified Intel FPGA device. + * @param dev_id + * The buffer to output device ID. + * @return + * - (0) if successful. + * - (-EINVAL) if bad parameter. + * - (-ENODEV) if FPGA is not probed by ifpga driver. + */ +__rte_experimental +int +rte_pmd_ifpga_get_dev_id(const char *pci_addr, uint16_t *dev_id); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Update image flash of specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param image + * The image file name string. + * @param status + * The detailed update status for debug. + * @return + * - (0) if successful. + * - (-ENODEV) if dev_id is invalid. + * - (-EINVAL) if bad parameter or staging area is not initialized. + * - (-EBUSY) if FPGA is updating or rebooting. + * - (-EIO) if failed to open image file. + */ +__rte_experimental +int +rte_pmd_ifpga_update_flash(uint16_t dev_id, const char *image, + uint64_t *status); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Stop flash update of specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param force + * Abort the update process by writing register if set non-zero. + * @return + * - (0) if successful. + * - (-ENODEV) if dev_id is invalid. + * - (-EINVAL) if bad parameter. + * - (-EAGAIN) if failed with force. + */ +__rte_experimental +int +rte_pmd_ifpga_stop_update(uint16_t dev_id, int force); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Check current Intel FPGA status and change it to reboot status if it is idle + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @return + * - (0) if FPGA is ready to reboot. + * - (-ENODEV) if dev_id is invalid. + * - (-ENOMEM) if share data is not initialized. + * - (-EBUSY) if FPGA is updating or rebooting. + */ +__rte_experimental +int +rte_pmd_ifpga_reboot_try(uint16_t dev_id); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Trigger full reconfiguration of specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param type + * Select reconfiguration type. + * 0 - reconfigure FPGA only. + * 1 - reboot the whole card including FPGA. + * @param page + * Select image from which flash partition. + * 0 - factory partition. + * 1 - user partition. + * @return + * - (0) if successful. + * - (-ENODEV) if dev_id is invalid. + * - (-EINVAL) if bad parameter. + * - (-EBUSY) if failed to access BMC register. + */ +__rte_experimental +int +rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_PMD_IFPGA_H_ */ diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map index 4a76d1d52d..16584f7fe4 100644 --- a/drivers/raw/ifpga/version.map +++ b/drivers/raw/ifpga/version.map @@ -1,3 +1,14 @@ DPDK_21 { local: *; }; + +EXPERIMENTAL { + global: + + # added in 21.05 + rte_pmd_ifpga_get_dev_id; + rte_pmd_ifpga_update_flash; + rte_pmd_ifpga_stop_update; + rte_pmd_ifpga_reboot_try; + rte_pmd_ifpga_reload; +}; From patchwork Wed Mar 3 02:34:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Huang X-Patchwork-Id: 88402 X-Patchwork-Delegate: qi.z.zhang@intel.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 014DBA0566; Wed, 3 Mar 2021 03:34:49 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 2C76D160727; Wed, 3 Mar 2021 03:34:34 +0100 (CET) Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by mails.dpdk.org (Postfix) with ESMTP id 5B9B0160703; Wed, 3 Mar 2021 03:34:31 +0100 (CET) IronPort-SDR: kZ7zckD6pBsdj6ZDUGTAYV5vT+dtrpuQoHUwhn/aMSdkoS3PWq22LC7bzSNGZMjKONknGRVfHF u57jUxeXCw4Q== X-IronPort-AV: E=McAfee;i="6000,8403,9911"; a="186416570" X-IronPort-AV: E=Sophos;i="5.81,218,1610438400"; d="scan'208";a="186416570" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 18:34:31 -0800 IronPort-SDR: 5jvGkjwiQcwE8tRXFt10xrHBui6f9SUvc13Z33g6ALbalvBDTvd7ML8w4UrI22x+VXHqZVn15z v60Sa28gFIPw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,218,1610438400"; d="scan'208";a="435051396" Received: from unknown (HELO sh_lab5_1.sh.intel.com) ([10.238.175.190]) by FMSMGA003.fm.intel.com with ESMTP; 02 Mar 2021 18:34:29 -0800 From: Wei Huang To: dev@dpdk.org, rosen.xu@intel.com, qi.z.zhang@intel.com Cc: stable@dpdk.org, tianfei.zhang@intel.com, ferruh.yigit@intel.com, Wei Huang Date: Tue, 2 Mar 2021 21:34:30 -0500 Message-Id: <1614738871-8329-3-git-send-email-wei.huang@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1614738871-8329-1-git-send-email-wei.huang@intel.com> References: <1614738871-8329-1-git-send-email-wei.huang@intel.com> Subject: [dpdk-dev] [PATCH v16 2/3] raw/ifpga: add APIs to get fpga information 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 Sender: "dev" There are some information data can be got from FPGA, they are implemented in below APIs: 1. rte_pmd_ifpga_get_property() get properties of FPGA (include BMC). 2. rte_pmd_ifpga_get_phy_info() get information of PHY connect to FPGA. 3. rte_pmd_ifpga_get_rsu_status() get status of rsu process. Signed-off-by: Wei Huang Acked-by: Tianfei Zhang Acked-by: Rosen Xu --- v2: implement APIs in rte_pmd_ifpga.c --- drivers/raw/ifpga/base/ifpga_api.c | 8 + drivers/raw/ifpga/base/ifpga_defines.h | 1 + drivers/raw/ifpga/base/ifpga_feature_dev.c | 21 ++ drivers/raw/ifpga/base/ifpga_feature_dev.h | 1 + drivers/raw/ifpga/base/ifpga_fme.c | 28 ++- drivers/raw/ifpga/base/opae_hw_api.c | 18 ++ drivers/raw/ifpga/base/opae_hw_api.h | 2 + drivers/raw/ifpga/base/opae_ifpga_hw_api.h | 1 + drivers/raw/ifpga/rte_pmd_ifpga.c | 221 +++++++++++++++++++++ drivers/raw/ifpga/rte_pmd_ifpga.h | 110 ++++++++++ drivers/raw/ifpga/version.map | 3 + 11 files changed, 412 insertions(+), 2 deletions(-) diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c index 1aedf150bc..4610ef101e 100644 --- a/drivers/raw/ifpga/base/ifpga_api.c +++ b/drivers/raw/ifpga/base/ifpga_api.c @@ -229,6 +229,13 @@ static int ifpga_mgr_get_board_info(struct opae_manager *mgr, return 0; } +static int ifpga_mgr_get_uuid(struct opae_manager *mgr, struct uuid *uuid) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fpga_get_pr_uuid(fme, uuid); +} + static int ifpga_mgr_update_flash(struct opae_manager *mgr, const char *image, u64 *status) { @@ -256,6 +263,7 @@ struct opae_manager_ops ifpga_mgr_ops = { .get_eth_group_region_info = ifpga_mgr_get_eth_group_region_info, .get_sensor_value = ifpga_mgr_get_sensor_value, .get_board_info = ifpga_mgr_get_board_info, + .get_uuid = ifpga_mgr_get_uuid, .update_flash = ifpga_mgr_update_flash, .stop_flash_update = ifpga_mgr_stop_flash_update, .reload = ifpga_mgr_reload, diff --git a/drivers/raw/ifpga/base/ifpga_defines.h b/drivers/raw/ifpga/base/ifpga_defines.h index 9f0147d1ed..dca1518a83 100644 --- a/drivers/raw/ifpga/base/ifpga_defines.h +++ b/drivers/raw/ifpga/base/ifpga_defines.h @@ -1727,6 +1727,7 @@ struct opae_board_info { u8 seu; u8 ptp; + u32 boot_page; u32 max10_version; u32 nios_fw_version; u32 nums_of_retimer; diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.c b/drivers/raw/ifpga/base/ifpga_feature_dev.c index 0f852a75ad..08135137ad 100644 --- a/drivers/raw/ifpga/base/ifpga_feature_dev.c +++ b/drivers/raw/ifpga/base/ifpga_feature_dev.c @@ -87,6 +87,27 @@ int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) return 0; } +int fpga_get_pr_uuid(struct ifpga_fme_hw *fme, struct uuid *uuid) +{ + struct feature_fme_pr *fme_pr; + u64 guidl, guidh; + + if (!fme || !uuid) + return -EINVAL; + + fme_pr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_PR_MGMT); + + spinlock_lock(&fme->lock); + guidl = readq(&fme_pr->fme_pr_intfc_id_l); + guidh = readq(&fme_pr->fme_pr_intfc_id_h); + spinlock_unlock(&fme->lock); + + opae_memcpy(uuid->b, &guidl, sizeof(u64)); + opae_memcpy(uuid->b + 8, &guidh, sizeof(u64)); + + return 0; +} + /* Mask / Unmask Port Errors by the Error Mask register. */ void port_err_mask(struct ifpga_port_hw *port, bool mask) { diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.h b/drivers/raw/ifpga/base/ifpga_feature_dev.h index 2b1309b44a..b355d22b0e 100644 --- a/drivers/raw/ifpga/base/ifpga_feature_dev.h +++ b/drivers/raw/ifpga/base/ifpga_feature_dev.h @@ -103,6 +103,7 @@ is_port_feature_present(struct ifpga_port_hw *port, int index) } int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); +int fpga_get_pr_uuid(struct ifpga_fme_hw *fme, struct uuid *uuid); int __fpga_port_disable(struct ifpga_port_hw *port); void __fpga_port_enable(struct ifpga_port_hw *port); diff --git a/drivers/raw/ifpga/base/ifpga_fme.c b/drivers/raw/ifpga/base/ifpga_fme.c index 34fd9a818e..43c7b9c3dc 100644 --- a/drivers/raw/ifpga/base/ifpga_fme.c +++ b/drivers/raw/ifpga/base/ifpga_fme.c @@ -101,6 +101,24 @@ static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) return 0; } +static int fme_hdr_get_port_type(struct ifpga_fme_hw *fme, u64 *port_type) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_port pt; + u32 port = (u32)((*port_type >> 32) & 0xffffffff); + + pt.csr = readq(&fme_hdr->port[port]); + if (!pt.port_implemented) + return -ENODEV; + if (pt.afu_access_control) + *port_type |= 0x1; + else + *port_type &= ~0x1; + + return 0; +} + static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) { struct feature_fme_header *fme_hdr @@ -179,6 +197,8 @@ fme_hdr_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) return fme_hdr_get_bitstream_id(fme, &prop->data); case FME_HDR_PROP_BITSTREAM_METADATA: return fme_hdr_get_bitstream_metadata(fme, &prop->data); + case FME_HDR_PROP_PORT_TYPE: + return fme_hdr_get_port_type(fme, &prop->data); } return -ENOENT; @@ -891,13 +911,17 @@ static int fme_get_board_interface(struct ifpga_fme_hw *fme) fme->board_info.nums_of_fvl, fme->board_info.ports_per_fvl); + if (max10_sys_read(fme->max10_dev, FPGA_PAGE_INFO, &val)) + return -EINVAL; + fme->board_info.boot_page = val & 0x7; + if (max10_sys_read(fme->max10_dev, MAX10_BUILD_VER, &val)) return -EINVAL; - fme->board_info.max10_version = val & 0xffffff; + fme->board_info.max10_version = val; if (max10_sys_read(fme->max10_dev, NIOS2_FW_VERSION, &val)) return -EINVAL; - fme->board_info.nios_fw_version = val & 0xffffff; + fme->board_info.nios_fw_version = val; dev_info(fme, "max10 version 0x%x, nios fw version 0x%x\n", fme->board_info.max10_version, diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c index 86ad88f720..11c9887c7f 100644 --- a/drivers/raw/ifpga/base/opae_hw_api.c +++ b/drivers/raw/ifpga/base/opae_hw_api.c @@ -967,6 +967,24 @@ opae_mgr_get_board_info(struct opae_manager *mgr, return -ENOENT; } +/** + * opae_mgr_get_uuid - get manager's UUID. + * @mgr: targeted manager + * @uuid: a pointer to UUID + * + * Return: 0 on success, otherwise error code. + */ +int opae_mgr_get_uuid(struct opae_manager *mgr, struct uuid *uuid) +{ + if (!mgr || !uuid) + return -EINVAL; + + if (mgr->ops && mgr->ops->get_uuid) + return mgr->ops->get_uuid(mgr, uuid); + + return -ENOENT; +} + /** * opae_mgr_update_flash - update image in flash. * @mgr: targeted manager diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h index 91d26d9b5b..7e04b56471 100644 --- a/drivers/raw/ifpga/base/opae_hw_api.h +++ b/drivers/raw/ifpga/base/opae_hw_api.h @@ -55,6 +55,7 @@ struct opae_manager_ops { unsigned int *value); int (*get_board_info)(struct opae_manager *mgr, struct opae_board_info **info); + int (*get_uuid)(struct opae_manager *mgr, struct uuid *uuid); int (*update_flash)(struct opae_manager *mgr, const char *image, u64 *status); int (*stop_flash_update)(struct opae_manager *mgr, int force); @@ -360,6 +361,7 @@ int opae_manager_eth_group_read_reg(struct opae_manager *mgr, u8 group_id, u8 type, u8 index, u16 addr, u32 *data); int opae_mgr_get_board_info(struct opae_manager *mgr, struct opae_board_info **info); +int opae_mgr_get_uuid(struct opae_manager *mgr, struct uuid *uuid); 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); diff --git a/drivers/raw/ifpga/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga/base/opae_ifpga_hw_api.h index bab33862ee..ffdbebf704 100644 --- a/drivers/raw/ifpga/base/opae_ifpga_hw_api.h +++ b/drivers/raw/ifpga/base/opae_ifpga_hw_api.h @@ -61,6 +61,7 @@ struct feature_prop { #define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ #define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ #define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ +#define FME_HDR_PROP_PORT_TYPE 0x8 /* RDWR */ /* FME error reporting feature's properties */ /* FME error reporting properties format */ diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.c b/drivers/raw/ifpga/rte_pmd_ifpga.c index af6f175e98..8e04e22d5f 100644 --- a/drivers/raw/ifpga/rte_pmd_ifpga.c +++ b/drivers/raw/ifpga/rte_pmd_ifpga.c @@ -8,6 +8,7 @@ #include #include "rte_pmd_ifpga.h" #include "ifpga_rawdev.h" +#include "base/ifpga_api.h" #include "base/ifpga_sec_mgr.h" @@ -99,6 +100,226 @@ get_share_data(struct opae_adapter *adapter) return sd; } +int +rte_pmd_ifpga_get_rsu_status(uint16_t dev_id, uint32_t *stat, uint32_t *prog) +{ + struct opae_adapter *adapter = NULL; + opae_share_data *sd = NULL; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + sd = get_share_data(adapter); + if (!sd) + return -ENOMEM; + + if (stat) + *stat = IFPGA_RSU_GET_STAT(sd->rsu_stat); + if (prog) + *prog = IFPGA_RSU_GET_PROG(sd->rsu_stat); + + return 0; +} + +static int +ifpga_is_rebooting(struct opae_adapter *adapter) +{ + opae_share_data *sd = NULL; + + sd = get_share_data(adapter); + if (!sd) + return 1; + + if (IFPGA_RSU_GET_STAT(sd->rsu_stat) == IFPGA_RSU_REBOOT) { + IFPGA_RAWDEV_PMD_WARN("Reboot is in progress."); + return 1; + } + + return 0; +} + +static int +get_common_property(struct opae_adapter *adapter, + rte_pmd_ifpga_common_prop *prop) +{ + struct ifpga_fme_hw *fme = NULL; + struct opae_board_info *info = NULL; + struct feature_prop fp; + struct uuid pr_id; + int ret = 0; + + if (!adapter || !prop) + return -EINVAL; + + if (!adapter->mgr || !adapter->mgr->data) { + IFPGA_RAWDEV_PMD_ERR("Manager is not registered."); + return -ENODEV; + } + + fme = adapter->mgr->data; + fp.feature_id = FME_FEATURE_ID_HEADER; + fp.prop_id = FME_HDR_PROP_PORTS_NUM; + ret = ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, &fp); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("Failed to get port number."); + return ret; + } + prop->num_ports = fp.data; + + fp.prop_id = FME_HDR_PROP_BITSTREAM_ID; + ret = ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, &fp); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("Failed to get bitstream ID."); + return ret; + } + prop->bitstream_id = fp.data; + + fp.prop_id = FME_HDR_PROP_BITSTREAM_METADATA; + ret = ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, &fp); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("Failed to get bitstream metadata."); + return ret; + } + prop->bitstream_metadata = fp.data; + + ret = opae_mgr_get_uuid(adapter->mgr, &pr_id); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("Failed to get PR ID."); + return ret; + } + memcpy(prop->pr_id.b, pr_id.b, sizeof(rte_pmd_ifpga_uuid)); + + ret = opae_mgr_get_board_info(adapter->mgr, &info); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("Failed to get board info."); + return ret; + } + prop->boot_page = info->boot_page; + prop->bmc_version = info->max10_version; + prop->bmc_nios_version = info->nios_fw_version; + + return 0; +} + +static int +get_port_property(struct opae_adapter *adapter, uint16_t port, + rte_pmd_ifpga_port_prop *prop) +{ + struct ifpga_fme_hw *fme = NULL; + struct feature_prop fp; + struct opae_accelerator *acc = NULL; + struct uuid afu_id; + int ret = 0; + + if (!adapter || !prop) + return -EINVAL; + + if (!adapter->mgr || !adapter->mgr->data) { + IFPGA_RAWDEV_PMD_ERR("Manager is not registered."); + return -ENODEV; + } + + fme = adapter->mgr->data; + fp.feature_id = FME_FEATURE_ID_HEADER; + fp.prop_id = FME_HDR_PROP_PORT_TYPE; + fp.data = port; + fp.data <<= 32; + ret = ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, &fp); + if (ret) + return ret; + prop->type = fp.data & 0xffffffff; + + if (prop->type == 0) { + acc = opae_adapter_get_acc(adapter, port); + ret = opae_acc_get_uuid(acc, &afu_id); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("Failed to get port%u AFU ID.", + port); + return ret; + } + memcpy(prop->afu_id.b, afu_id.b, sizeof(rte_pmd_ifpga_uuid)); + } + + return 0; +} + +int +rte_pmd_ifpga_get_property(uint16_t dev_id, rte_pmd_ifpga_prop *prop) +{ + struct opae_adapter *adapter = NULL; + uint32_t i = 0; + int ret = 0; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + opae_adapter_lock(adapter, -1); + if (ifpga_is_rebooting(adapter)) { + ret = -EBUSY; + goto unlock_dev; + } + + ret = get_common_property(adapter, &prop->common); + if (ret) { + ret = -EIO; + goto unlock_dev; + } + + for (i = 0; i < prop->common.num_ports; i++) { + ret = get_port_property(adapter, i, &prop->port[i]); + if (ret) { + ret = -EIO; + break; + } + } + +unlock_dev: + opae_adapter_unlock(adapter); + return ret; +} + +int +rte_pmd_ifpga_get_phy_info(uint16_t dev_id, rte_pmd_ifpga_phy_info *info) +{ + struct opae_adapter *adapter = NULL; + struct opae_retimer_info rtm_info; + struct opae_retimer_status rtm_status; + int ret = 0; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + opae_adapter_lock(adapter, -1); + if (ifpga_is_rebooting(adapter)) { + ret = -EBUSY; + goto unlock_dev; + } + + ret = opae_manager_get_retimer_info(adapter->mgr, &rtm_info); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("Failed to get retimer info."); + ret = -EIO; + goto unlock_dev; + } + info->num_retimers = rtm_info.nums_retimer; + + ret = opae_manager_get_retimer_status(adapter->mgr, &rtm_status); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("Failed to get retimer status."); + ret = -EIO; + goto unlock_dev; + } + info->link_speed = rtm_status.speed; + info->link_status = rtm_status.line_link_bitmap; + +unlock_dev: + opae_adapter_unlock(adapter); + return ret; +} + int rte_pmd_ifpga_update_flash(uint16_t dev_id, const char *image, uint64_t *status) diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h b/drivers/raw/ifpga/rte_pmd_ifpga.h index 023a011116..633f6e9d1b 100644 --- a/drivers/raw/ifpga/rte_pmd_ifpga.h +++ b/drivers/raw/ifpga/rte_pmd_ifpga.h @@ -18,6 +18,55 @@ extern "C" { #endif +#include + +#define IFPGA_MAX_PORT_NUM 4 + +/** + * UUID data structure. + */ +typedef struct { + uint8_t b[16]; +} rte_pmd_ifpga_uuid; + +/** + * FME property data structure. + */ +typedef struct { + uint32_t num_ports; + uint32_t boot_page; + uint64_t bitstream_id; + uint64_t bitstream_metadata; + rte_pmd_ifpga_uuid pr_id; + uint32_t bmc_version; + uint32_t bmc_nios_version; +} rte_pmd_ifpga_common_prop; + +/** + * port property data structure. + */ +typedef struct { + rte_pmd_ifpga_uuid afu_id; + uint32_t type; /* AFU memory access control type */ +} rte_pmd_ifpga_port_prop; + +/** + * FPGA property data structure. + */ +typedef struct { + rte_pmd_ifpga_common_prop common; + rte_pmd_ifpga_port_prop port[IFPGA_MAX_PORT_NUM]; +} rte_pmd_ifpga_prop; + +/** + * PHY information data structure. + */ +typedef struct { + uint32_t num_retimers; + uint32_t link_speed; + uint32_t link_status; +} rte_pmd_ifpga_phy_info; + /** * @warning * @b EXPERIMENTAL: this API may change, or be removed, without prior notice @@ -37,6 +86,67 @@ __rte_experimental int rte_pmd_ifpga_get_dev_id(const char *pci_addr, uint16_t *dev_id); +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Get current RSU status of the specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param stat + * The buffer to output RSU status. + * @param prog + * The buffer to output RSU progress. + * @return + * - (0) if successful. + * - (-ENODEV) if dev_id is invalid. + * - (-ENOMEM) if share data is not initialized. + */ +__rte_experimental +int +rte_pmd_ifpga_get_rsu_status(uint16_t dev_id, uint32_t *stat, uint32_t *prog); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Get FPGA property of specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param prop + * The data pointer of FPGA property buffer. + * @return + * - (0) if successful. + * - (-ENODEV) if dev_id is invalid. + * - (-EBUSY) if FPGA is rebooting. + * - (-EIO) if failed to access hardware. + */ +__rte_experimental +int +rte_pmd_ifpga_get_property(uint16_t dev_id, rte_pmd_ifpga_prop *prop); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Get PHY information of specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param info + * The data pointer of PHY information buffer. + * @return + * - (0) if successful. + * - (-ENODEV) if dev_id is invalid. + * - (-EBUSY) if FPGA is rebooting. + * - (-EIO) if failed to access hardware. + */ +__rte_experimental +int +rte_pmd_ifpga_get_phy_info(uint16_t dev_id, rte_pmd_ifpga_phy_info *info); + /** * @warning * @b EXPERIMENTAL: this API may change, or be removed, without prior notice diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map index 16584f7fe4..ca6f7f5810 100644 --- a/drivers/raw/ifpga/version.map +++ b/drivers/raw/ifpga/version.map @@ -7,6 +7,9 @@ EXPERIMENTAL { # added in 21.05 rte_pmd_ifpga_get_dev_id; + rte_pmd_ifpga_get_rsu_status; + rte_pmd_ifpga_get_property; + rte_pmd_ifpga_get_phy_info; rte_pmd_ifpga_update_flash; rte_pmd_ifpga_stop_update; rte_pmd_ifpga_reboot_try; From patchwork Wed Mar 3 02:34:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Huang X-Patchwork-Id: 88403 X-Patchwork-Delegate: qi.z.zhang@intel.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id B8675A0566; Wed, 3 Mar 2021 03:34:57 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id A4A04160731; Wed, 3 Mar 2021 03:34:35 +0100 (CET) Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by mails.dpdk.org (Postfix) with ESMTP id 4E0C4160719; Wed, 3 Mar 2021 03:34:33 +0100 (CET) IronPort-SDR: KsbZT/1h0lXssSUn063eOa9ol1DZcpwKWeSMloDMOuO+M2iTOuS9UGYzV6AVH7clKbD+TURKxF XVH/mrBvs1iw== X-IronPort-AV: E=McAfee;i="6000,8403,9911"; a="186416577" X-IronPort-AV: E=Sophos;i="5.81,218,1610438400"; d="scan'208";a="186416577" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 18:34:32 -0800 IronPort-SDR: SuwjBtwEnZaLxEVMDDm9qVEEKFa3fS2mCRmFjzXOa6zZlCmLRIhUOCE2raQ6B3L5v1axx2zi2H ZiCAkUdauRnA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,218,1610438400"; d="scan'208";a="435051402" Received: from unknown (HELO sh_lab5_1.sh.intel.com) ([10.238.175.190]) by FMSMGA003.fm.intel.com with ESMTP; 02 Mar 2021 18:34:31 -0800 From: Wei Huang To: dev@dpdk.org, rosen.xu@intel.com, qi.z.zhang@intel.com Cc: stable@dpdk.org, tianfei.zhang@intel.com, ferruh.yigit@intel.com, Wei Huang Date: Tue, 2 Mar 2021 21:34:31 -0500 Message-Id: <1614738871-8329-4-git-send-email-wei.huang@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1614738871-8329-1-git-send-email-wei.huang@intel.com> References: <1614738871-8329-1-git-send-email-wei.huang@intel.com> Subject: [dpdk-dev] [PATCH v16 3/3] raw/ifpga: add miscellaneous APIs 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 Sender: "dev" Below miscellaneous APIs are used to implement OPAE application. 1. rte_pmd_ifpga_get_pci_bus() get PCI bus ifpga driver registered. 2. rte_pmd_ifpga_partial_reconfigure() do partial reconfiguration. 3. rte_pmd_ifpga_cleanup() free software resources allocated by driver. 4. rte_pmd_ifpga_set_rsu_status() set status of rsu process. Signed-off-by: Wei Huang Acked-by: Tianfei Zhang Acked-by: Rosen Xu --- v2: implement APIs in rte_pmd_ifpga.c --- drivers/raw/ifpga/ifpga_rawdev.c | 30 ++++++++++++++ drivers/raw/ifpga/ifpga_rawdev.h | 7 +++- drivers/raw/ifpga/rte_pmd_ifpga.c | 45 +++++++++++++++++++++ drivers/raw/ifpga/rte_pmd_ifpga.h | 66 +++++++++++++++++++++++++++++++ drivers/raw/ifpga/version.map | 4 ++ 5 files changed, 151 insertions(+), 1 deletion(-) diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c index 27129b133e..05d79bfcc2 100644 --- a/drivers/raw/ifpga/ifpga_rawdev.c +++ b/drivers/raw/ifpga/ifpga_rawdev.c @@ -1737,3 +1737,33 @@ RTE_PMD_REGISTER_PARAM_STRING(ifpga_rawdev_cfg, "ifpga= " "port= " "afu_bts="); + +struct rte_pci_bus *ifpga_get_pci_bus(void) +{ + return rte_ifpga_rawdev_pmd.bus; +} + +int ifpga_rawdev_partial_reconfigure(struct rte_rawdev *dev, int port, + const char *file) +{ + if (!dev) { + IFPGA_RAWDEV_PMD_ERR("Input parameter is invalid"); + return -EINVAL; + } + + return rte_fpga_do_pr(dev, port, file); +} + +void ifpga_rawdev_cleanup(void) +{ + struct ifpga_rawdev *dev; + unsigned int i; + + for (i = 0; i < IFPGA_RAWDEV_NUM; i++) { + dev = &ifpga_rawdevices[i]; + if (dev->rawdev) { + rte_rawdev_pmd_release(dev->rawdev); + dev->rawdev = NULL; + } + } +} diff --git a/drivers/raw/ifpga/ifpga_rawdev.h b/drivers/raw/ifpga/ifpga_rawdev.h index 7754beb02b..9bbe9a4278 100644 --- a/drivers/raw/ifpga/ifpga_rawdev.h +++ b/drivers/raw/ifpga/ifpga_rawdev.h @@ -43,7 +43,7 @@ enum ifpga_rawdev_device_state { static inline struct opae_adapter * ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) { - return rawdev->dev_private; + return (struct opae_adapter *)rawdev->dev_private; } #define IFPGA_RAWDEV_MSIX_IRQ_NUM 7 @@ -76,4 +76,9 @@ int ifpga_unregister_msix_irq(enum ifpga_irq_type type, int vec_start, rte_intr_callback_fn handler, void *arg); +struct rte_pci_bus *ifpga_get_pci_bus(void); +int ifpga_rawdev_partial_reconfigure(struct rte_rawdev *dev, int port, + const char *file); +void ifpga_rawdev_cleanup(void); + #endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.c b/drivers/raw/ifpga/rte_pmd_ifpga.c index 8e04e22d5f..6e23a2581a 100644 --- a/drivers/raw/ifpga/rte_pmd_ifpga.c +++ b/drivers/raw/ifpga/rte_pmd_ifpga.c @@ -122,6 +122,25 @@ rte_pmd_ifpga_get_rsu_status(uint16_t dev_id, uint32_t *stat, uint32_t *prog) return 0; } +int +rte_pmd_ifpga_set_rsu_status(uint16_t dev_id, uint32_t stat, uint32_t prog) +{ + struct opae_adapter *adapter = NULL; + opae_share_data *sd = NULL; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + sd = get_share_data(adapter); + if (!sd) + return -ENOMEM; + + sd->rsu_stat = IFPGA_RSU_STATUS(stat, prog); + + return 0; +} + static int ifpga_is_rebooting(struct opae_adapter *adapter) { @@ -382,3 +401,29 @@ rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page) return opae_mgr_reload(adapter->mgr, type, page); } + +const struct rte_pci_bus * +rte_pmd_ifpga_get_pci_bus(void) +{ + return ifpga_get_pci_bus(); +} + +int +rte_pmd_ifpga_partial_reconfigure(uint16_t dev_id, int port, const char *file) +{ + struct rte_rawdev *dev = NULL; + + dev = get_rte_rawdev(dev_id); + if (!dev) { + IFPGA_RAWDEV_PMD_ERR("Device ID %u is invalid.", dev_id); + return -EINVAL; + } + + return ifpga_rawdev_partial_reconfigure(dev, port, file); +} + +void +rte_pmd_ifpga_cleanup(void) +{ + ifpga_rawdev_cleanup(); +} diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h b/drivers/raw/ifpga/rte_pmd_ifpga.h index 633f6e9d1b..47d66ba655 100644 --- a/drivers/raw/ifpga/rte_pmd_ifpga.h +++ b/drivers/raw/ifpga/rte_pmd_ifpga.h @@ -107,6 +107,27 @@ __rte_experimental int rte_pmd_ifpga_get_rsu_status(uint16_t dev_id, uint32_t *stat, uint32_t *prog); +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Set current RSU status of the specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param stat + * The RSU status value to set. + * @param prog + * The RSU progress value to set. + * @return + * - (0) if successful. + * - (-ENODEV) if dev_id is invalid. + * - (-ENOMEM) if share data is not initialized. + */ +__rte_experimental +int +rte_pmd_ifpga_set_rsu_status(uint16_t dev_id, uint32_t stat, uint32_t prog); + /** * @warning * @b EXPERIMENTAL: this API may change, or be removed, without prior notice @@ -235,6 +256,51 @@ __rte_experimental int rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page); +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Get PCI bus the Intel FPGA driver register to + * + * @return + * - (valid pointer) if successful. + * - (NULL) if the Intel FPGA driver is not registered to any PCI bus. + */ +__rte_experimental +const struct rte_pci_bus * +rte_pmd_ifpga_get_pci_bus(void); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Perform PR (partial reconfiguration) on specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param port + * The port index of the partial reconfiguration area. + * @param file + * The GBS (Green BitStream) image file name string. + * @return + * - (0) if successful. + * - (-EINVAL) if bad parameter or operation failed. + * - (-ENOMEM) if failed to allocate memory. + */ +__rte_experimental +int +rte_pmd_ifpga_partial_reconfigure(uint16_t dev_id, int port, const char *file); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Free software resources allocated by Intel FPGA PMD + */ +__rte_experimental +void +rte_pmd_ifpga_cleanup(void); + #ifdef __cplusplus } #endif diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map index ca6f7f5810..995c419a9b 100644 --- a/drivers/raw/ifpga/version.map +++ b/drivers/raw/ifpga/version.map @@ -8,10 +8,14 @@ EXPERIMENTAL { # added in 21.05 rte_pmd_ifpga_get_dev_id; rte_pmd_ifpga_get_rsu_status; + rte_pmd_ifpga_set_rsu_status; rte_pmd_ifpga_get_property; rte_pmd_ifpga_get_phy_info; rte_pmd_ifpga_update_flash; rte_pmd_ifpga_stop_update; rte_pmd_ifpga_reboot_try; rte_pmd_ifpga_reload; + rte_pmd_ifpga_get_pci_bus; + rte_pmd_ifpga_partial_reconfigure; + rte_pmd_ifpga_cleanup; };