raw/ifpga: add FPGA RSU APIs
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 <wei.huang@intel.com> Acked-by: Tianfei Zhang <tianfei.zhang@intel.com> Acked-by: Rosen Xu <rosen.xu@intel.com>
This commit is contained in:
parent
c45bd78e07
commit
a05bd1b40b
@ -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),
|
||||
|
@ -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 \
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
428
drivers/raw/ifpga/base/ifpga_fme_rsu.c
Normal file
428
drivers/raw/ifpga/base/ifpga_fme_rsu.c
Normal file
@ -0,0 +1,428 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2020 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include "ifpga_sec_mgr.h"
|
||||
|
||||
static struct ifpga_sec_mgr *sec_mgr;
|
||||
|
||||
static void set_rsu_control(struct ifpga_sec_mgr *smgr, uint32_t ctrl)
|
||||
{
|
||||
if (smgr && smgr->rsu_control)
|
||||
*smgr->rsu_control = ctrl;
|
||||
}
|
||||
|
||||
static uint32_t get_rsu_control(struct ifpga_sec_mgr *smgr)
|
||||
{
|
||||
if (smgr && smgr->rsu_control)
|
||||
return *smgr->rsu_control;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_rsu_status(struct ifpga_sec_mgr *smgr, uint32_t status,
|
||||
uint32_t progress)
|
||||
{
|
||||
if (smgr && smgr->rsu_status)
|
||||
*smgr->rsu_status = 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);
|
||||
}
|
@ -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 {
|
||||
|
639
drivers/raw/ifpga/base/ifpga_sec_mgr.c
Normal file
639
drivers/raw/ifpga/base/ifpga_sec_mgr.c
Normal file
@ -0,0 +1,639 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2020 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include "ifpga_sec_mgr.h"
|
||||
|
||||
|
||||
static const char * const rsu_prog[] = {"IDLE", "PREPARING", "SLEEPING",
|
||||
"READY", "AUTHENTICATING", "COPYING", "CANCELLATION", "PROGRAMMING_KEY",
|
||||
"DONE", "PKVL_DONE"};
|
||||
static const char * const rsu_statl[] = {"NORMAL", "TIMEOUT", "AUTH_FAIL",
|
||||
"COPY_FAIL", "FATAL", "PKVL_REJECT", "NON_INCR", "ERASE_FAIL",
|
||||
"WEAROUT"};
|
||||
static const char * const rsu_stath[] = {"NIOS_OK", "USER_OK", "FACTORY_OK",
|
||||
"USER_FAIL", "FACTORY_FAIL", "NIOS_FLASH_ERR", "FPGA_FLASH_ERR"};
|
||||
|
||||
static const char *rsu_progress_name(uint32_t prog)
|
||||
{
|
||||
if (prog > SEC_PROGRESS_PKVL_PROM_DONE)
|
||||
return "UNKNOWN";
|
||||
else
|
||||
return rsu_prog[prog];
|
||||
}
|
||||
|
||||
static const char *rsu_status_name(uint32_t stat)
|
||||
{
|
||||
if (stat >= SEC_STATUS_NIOS_OK) {
|
||||
if (stat > SEC_STATUS_FPGA_FLASH_ERR)
|
||||
return "UNKNOWN";
|
||||
else
|
||||
return rsu_stath[stat-SEC_STATUS_NIOS_OK];
|
||||
} else {
|
||||
if (stat > SEC_STATUS_WEAROUT)
|
||||
return "UNKNOWN";
|
||||
else
|
||||
return rsu_statl[stat];
|
||||
}
|
||||
}
|
||||
|
||||
static bool secure_start_done(uint32_t doorbell)
|
||||
{
|
||||
return (SEC_STATUS_G(doorbell) == SEC_STATUS_ERASE_FAIL ||
|
||||
SEC_STATUS_G(doorbell) == SEC_STATUS_WEAROUT ||
|
||||
(SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_IDLE &&
|
||||
SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_RSU_DONE));
|
||||
}
|
||||
|
||||
static bool secure_prog_ready(uint32_t doorbell)
|
||||
{
|
||||
return (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY);
|
||||
}
|
||||
|
||||
static int poll_timeout(struct intel_max10_device *dev, uint32_t offset,
|
||||
bool (*cond)(uint32_t), uint32_t interval_ms, uint32_t timeout_ms)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
int ret = 0;
|
||||
|
||||
for (;;) {
|
||||
ret = max10_sys_read(dev, offset, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to read max10 register 0x%x [e:%d]\n",
|
||||
offset, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cond(val)) {
|
||||
dev_debug(dev,
|
||||
"Read 0x%08x from max10 register 0x%x "
|
||||
"[poll success]\n", val, offset);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
if (timeout_ms > interval_ms)
|
||||
timeout_ms -= interval_ms;
|
||||
else
|
||||
timeout_ms = 0;
|
||||
if (timeout_ms == 0) {
|
||||
dev_debug(dev,
|
||||
"Read 0x%08x from max10 register 0x%x "
|
||||
"[poll timeout]\n", val, offset);
|
||||
ret = -ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
msleep(interval_ms);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int n3000_secure_update_start(struct intel_max10_device *dev)
|
||||
{
|
||||
uint32_t doorbell = 0;
|
||||
uint32_t prog = 0;
|
||||
uint32_t status = 0;
|
||||
int ret = 0;
|
||||
|
||||
ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to read max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
prog = SEC_PROGRESS_G(doorbell);
|
||||
if ((prog != SEC_PROGRESS_IDLE) && (prog != SEC_PROGRESS_RSU_DONE)) {
|
||||
dev_debug(dev, "Current RSU progress is %s\n",
|
||||
rsu_progress_name(prog));
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = max10_sys_update_bits(dev, MAX10_DOORBELL,
|
||||
RSU_REQUEST | HOST_STATUS, RSU_REQUEST);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to updt max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = poll_timeout(dev, MAX10_DOORBELL, secure_start_done,
|
||||
IFPGA_SEC_START_INTERVAL_MS, IFPGA_SEC_START_TIMEOUT_MS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to poll max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to read max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
status = SEC_STATUS_G(doorbell);
|
||||
if (status == SEC_STATUS_WEAROUT)
|
||||
return -EAGAIN;
|
||||
|
||||
if (status == SEC_STATUS_ERASE_FAIL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int n3000_cancel(struct ifpga_sec_mgr *smgr)
|
||||
{
|
||||
struct intel_max10_device *dev = NULL;
|
||||
uint32_t doorbell = 0;
|
||||
uint32_t prog = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!smgr || !smgr->max10_dev)
|
||||
return -ENODEV;
|
||||
dev = (struct intel_max10_device *)smgr->max10_dev;
|
||||
|
||||
ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to read max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
prog = SEC_PROGRESS_G(doorbell);
|
||||
if (prog == SEC_PROGRESS_IDLE)
|
||||
return 0;
|
||||
if (prog != SEC_PROGRESS_READY)
|
||||
return -EBUSY;
|
||||
|
||||
return max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS,
|
||||
HOST_STATUS_S(HOST_STATUS_ABORT_RSU));
|
||||
}
|
||||
|
||||
static int n3000_prepare(struct ifpga_sec_mgr *smgr)
|
||||
{
|
||||
struct intel_max10_device *dev = NULL;
|
||||
int retry = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!smgr || !smgr->max10_dev)
|
||||
return -ENODEV;
|
||||
dev = (struct intel_max10_device *)smgr->max10_dev;
|
||||
|
||||
ret = n3000_secure_update_start(dev);
|
||||
if (ret == -EBUSY)
|
||||
n3000_cancel(smgr);
|
||||
|
||||
while (ret) {
|
||||
if (++retry > IFPGA_RSU_START_RETRY)
|
||||
break;
|
||||
msleep(1000);
|
||||
ret = n3000_secure_update_start(dev);
|
||||
}
|
||||
if (retry > IFPGA_RSU_START_RETRY) {
|
||||
dev_err(dev, "Failed to start secure flash update\n");
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int n3000_bulk_write(struct intel_max10_device *dev, uint32_t addr,
|
||||
char *buf, uint32_t len)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t n = 0;
|
||||
uint32_t v = 0;
|
||||
uint32_t p = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (len & 0x3) {
|
||||
dev_err(dev,
|
||||
"Length of data block is not 4 bytes aligned [e:%u]\n",
|
||||
len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
n = len >> 2;
|
||||
for (i = 0; i < n; i++) {
|
||||
p = i << 2;
|
||||
v = *(uint32_t *)(buf + p);
|
||||
ret = max10_reg_write(dev, addr + p, v);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to write to staging area 0x%08x [e:%d]\n",
|
||||
addr + p, ret);
|
||||
return ret;
|
||||
}
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int n3000_write_blk(struct ifpga_sec_mgr *smgr, char *buf,
|
||||
uint32_t offset, uint32_t len)
|
||||
{
|
||||
struct intel_max10_device *dev = NULL;
|
||||
uint32_t doorbell = 0;
|
||||
uint32_t prog = 0;
|
||||
uint32_t m = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!smgr || !smgr->max10_dev)
|
||||
return -ENODEV;
|
||||
dev = (struct intel_max10_device *)smgr->max10_dev;
|
||||
|
||||
if (offset + len > dev->staging_area_size) {
|
||||
dev_err(dev,
|
||||
"Write position would be out of staging area [e:%u]\n",
|
||||
dev->staging_area_size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to read max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
prog = SEC_PROGRESS_G(doorbell);
|
||||
if (prog == SEC_PROGRESS_PREPARE)
|
||||
return -EAGAIN;
|
||||
else if (prog != SEC_PROGRESS_READY)
|
||||
return -EBUSY;
|
||||
|
||||
m = len & 0x3;
|
||||
if (m != 0)
|
||||
len += 4 - m; /* make length to 4 bytes align */
|
||||
|
||||
return n3000_bulk_write(dev, dev->staging_area_base + offset, buf, len);
|
||||
}
|
||||
|
||||
static int n3000_write_done(struct ifpga_sec_mgr *smgr)
|
||||
{
|
||||
struct intel_max10_device *dev = NULL;
|
||||
uint32_t doorbell = 0;
|
||||
uint32_t prog = 0;
|
||||
uint32_t status = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!smgr || !smgr->max10_dev)
|
||||
return -ENODEV;
|
||||
dev = (struct intel_max10_device *)smgr->max10_dev;
|
||||
|
||||
ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to read max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
prog = SEC_PROGRESS_G(doorbell);
|
||||
if (prog != SEC_PROGRESS_READY)
|
||||
return -EBUSY;
|
||||
|
||||
ret = max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS,
|
||||
HOST_STATUS_S(HOST_STATUS_WRITE_DONE));
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to update max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = poll_timeout(dev, MAX10_DOORBELL, secure_prog_ready,
|
||||
IFPGA_NIOS_HANDSHAKE_INTERVAL_MS,
|
||||
IFPGA_NIOS_HANDSHAKE_TIMEOUT_MS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to poll max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to read max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
status = SEC_STATUS_G(doorbell);
|
||||
switch (status) {
|
||||
case SEC_STATUS_NORMAL:
|
||||
case SEC_STATUS_NIOS_OK:
|
||||
case SEC_STATUS_USER_OK:
|
||||
case SEC_STATUS_FACTORY_OK:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int n3000_check_complete(struct ifpga_sec_mgr *smgr)
|
||||
{
|
||||
struct intel_max10_device *dev = NULL;
|
||||
uint32_t doorbell = 0;
|
||||
uint32_t status = 0;
|
||||
uint32_t prog = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!smgr || !smgr->max10_dev)
|
||||
return -ENODEV;
|
||||
dev = (struct intel_max10_device *)smgr->max10_dev;
|
||||
|
||||
ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to read max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
status = SEC_STATUS_G(doorbell);
|
||||
switch (status) {
|
||||
case SEC_STATUS_NORMAL:
|
||||
case SEC_STATUS_NIOS_OK:
|
||||
case SEC_STATUS_USER_OK:
|
||||
case SEC_STATUS_FACTORY_OK:
|
||||
case SEC_STATUS_WEAROUT:
|
||||
break;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
prog = SEC_PROGRESS_G(doorbell);
|
||||
switch (prog) {
|
||||
case SEC_PROGRESS_IDLE:
|
||||
case SEC_PROGRESS_RSU_DONE:
|
||||
return 0;
|
||||
case SEC_PROGRESS_AUTHENTICATING:
|
||||
case SEC_PROGRESS_COPYING:
|
||||
case SEC_PROGRESS_UPDATE_CANCEL:
|
||||
case SEC_PROGRESS_PROGRAM_KEY_HASH:
|
||||
return -EAGAIN;
|
||||
case SEC_PROGRESS_PREPARE:
|
||||
case SEC_PROGRESS_READY:
|
||||
return -EBUSY;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int n3000_reload_fpga(struct intel_max10_device *dev, int page)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
dev_info(dev, "Reload FPGA\n");
|
||||
|
||||
if (!dev || ((page != 0) && (page != 1))) {
|
||||
dev_err(dev, "Input parameter of %s is invalid\n", __func__);
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (dev->flags & MAX10_FLAGS_SECURE) {
|
||||
ret = max10_sys_update_bits(dev, FPGA_RECONF_REG,
|
||||
SFPGA_RP_LOAD, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to update max10 reconfig register [e:%d]\n",
|
||||
ret);
|
||||
goto end;
|
||||
}
|
||||
ret = max10_sys_update_bits(dev, FPGA_RECONF_REG,
|
||||
SFPGA_RP_LOAD | SFPGA_RECONF_PAGE,
|
||||
SFPGA_RP_LOAD | SFPGA_PAGE(page));
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to update max10 reconfig register [e:%d]\n",
|
||||
ret);
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
ret = max10_sys_update_bits(dev, RSU_REG, FPGA_RP_LOAD, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to update max10 rsu register [e:%d]\n",
|
||||
ret);
|
||||
goto end;
|
||||
}
|
||||
ret = max10_sys_update_bits(dev, RSU_REG,
|
||||
FPGA_RP_LOAD | FPGA_RECONF_PAGE,
|
||||
FPGA_RP_LOAD | FPGA_PAGE(page));
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to update max10 rsu register [e:%d]\n",
|
||||
ret);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ret = max10_sys_update_bits(dev, FPGA_RECONF_REG, COUNTDOWN_START, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to update max10 reconfig register [e:%d]\n",
|
||||
ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = max10_sys_update_bits(dev, FPGA_RECONF_REG, COUNTDOWN_START,
|
||||
COUNTDOWN_START);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to update max10 reconfig register [e:%d]\n",
|
||||
ret);
|
||||
}
|
||||
end:
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to reload FPGA\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int n3000_reload_bmc(struct intel_max10_device *dev, int page)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
int ret = 0;
|
||||
|
||||
dev_info(dev, "Reload BMC\n");
|
||||
|
||||
if (!dev || ((page != 0) && (page != 1))) {
|
||||
dev_err(dev, "Input parameter of %s is invalid\n", __func__);
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (dev->flags & MAX10_FLAGS_SECURE) {
|
||||
ret = max10_sys_update_bits(dev, MAX10_DOORBELL,
|
||||
CONFIG_SEL | REBOOT_REQ,
|
||||
CONFIG_SEL_S(page) | REBOOT_REQ);
|
||||
} else {
|
||||
val = (page == 0) ? 0x1 : 0x3;
|
||||
ret = max10_reg_write(dev, IFPGA_DUAL_CFG_CTRL1, val);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to write to dual config1 register [e:%d]\n",
|
||||
ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = max10_reg_write(dev, IFPGA_DUAL_CFG_CTRL0, 0x1);
|
||||
if (ret < 0) {
|
||||
if (ret == -EIO) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
dev_err(dev,
|
||||
"Failed to write to dual config0 register [e:%d]\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to reload BMC\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int n3000_reload(struct ifpga_sec_mgr *smgr, int type, int page)
|
||||
{
|
||||
int psel = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!smgr || !smgr->max10_dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (type == IFPGA_BOOT_TYPE_FPGA) {
|
||||
psel = (page == IFPGA_BOOT_PAGE_FACTORY ? 0 : 1);
|
||||
ret = n3000_reload_fpga(smgr->max10_dev, psel);
|
||||
} else if (type == IFPGA_BOOT_TYPE_BMC) {
|
||||
psel = (page == IFPGA_BOOT_PAGE_FACTORY ? 1 : 0);
|
||||
ret = n3000_reload_bmc(smgr->max10_dev, psel);
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint64_t n3000_get_hw_errinfo(struct ifpga_sec_mgr *smgr)
|
||||
{
|
||||
struct intel_max10_device *dev = NULL;
|
||||
uint32_t doorbell = 0;
|
||||
uint32_t stat = 0;
|
||||
uint32_t prog = 0;
|
||||
uint32_t auth_result = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!smgr || !smgr->max10_dev)
|
||||
return -ENODEV;
|
||||
dev = (struct intel_max10_device *)smgr->max10_dev;
|
||||
|
||||
ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read max10 doorbell register [e:%d]\n",
|
||||
ret);
|
||||
return -1;
|
||||
}
|
||||
stat = SEC_STATUS_G(doorbell);
|
||||
prog = SEC_PROGRESS_G(doorbell);
|
||||
dev_debug(dev, "Current RSU status is %s, progress is %s\n",
|
||||
rsu_status_name(stat), rsu_progress_name(prog));
|
||||
|
||||
ret = max10_sys_read(dev, MAX10_AUTH_RESULT, &auth_result);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed to read authenticate result register [e:%d]\n",
|
||||
ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (uint64_t)doorbell << 32 | (uint64_t)auth_result;
|
||||
}
|
||||
|
||||
static const struct ifpga_sec_ops n3000_sec_ops = {
|
||||
.prepare = n3000_prepare,
|
||||
.write_blk = n3000_write_blk,
|
||||
.write_done = n3000_write_done,
|
||||
.check_complete = n3000_check_complete,
|
||||
.reload = n3000_reload,
|
||||
.cancel = n3000_cancel,
|
||||
.cleanup = NULL,
|
||||
.get_hw_errinfo = n3000_get_hw_errinfo,
|
||||
};
|
||||
|
||||
int init_sec_mgr(struct ifpga_fme_hw *fme)
|
||||
{
|
||||
struct ifpga_hw *hw = NULL;
|
||||
opae_share_data *sd = NULL;
|
||||
struct ifpga_sec_mgr *smgr = NULL;
|
||||
|
||||
if (!fme || !fme->max10_dev)
|
||||
return -ENODEV;
|
||||
|
||||
smgr = (struct ifpga_sec_mgr *)malloc(sizeof(*smgr));
|
||||
if (!smgr) {
|
||||
dev_err(NULL, "Failed to allocate memory for security manager\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
fme->sec_mgr = smgr;
|
||||
|
||||
hw = (struct ifpga_hw *)fme->parent;
|
||||
if (hw && hw->adapter && hw->adapter->shm.ptr) {
|
||||
sd = (opae_share_data *)hw->adapter->shm.ptr;
|
||||
smgr->rsu_control = &sd->rsu_ctrl;
|
||||
smgr->rsu_status = &sd->rsu_stat;
|
||||
} else {
|
||||
smgr->rsu_control = NULL;
|
||||
smgr->rsu_status = NULL;
|
||||
}
|
||||
|
||||
if ((hw->pci_data->device_id == IFPGA_N3000_DID) &&
|
||||
(hw->pci_data->vendor_id == IFPGA_N3000_VID)) {
|
||||
smgr->ops = &n3000_sec_ops;
|
||||
smgr->copy_speed = IFPGA_N3000_COPY_SPEED;
|
||||
} else {
|
||||
dev_err(NULL, "No operation for security manager\n");
|
||||
smgr->ops = NULL;
|
||||
}
|
||||
|
||||
smgr->fme = fme;
|
||||
smgr->max10_dev = fme->max10_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void release_sec_mgr(struct ifpga_fme_hw *fme)
|
||||
{
|
||||
struct ifpga_sec_mgr *smgr = NULL;
|
||||
|
||||
if (fme) {
|
||||
smgr = (struct ifpga_sec_mgr *)fme->sec_mgr;
|
||||
if (smgr) {
|
||||
fme->sec_mgr = NULL;
|
||||
free(smgr);
|
||||
}
|
||||
}
|
||||
}
|
93
drivers/raw/ifpga/base/ifpga_sec_mgr.h
Normal file
93
drivers/raw/ifpga/base/ifpga_sec_mgr.h
Normal file
@ -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_ */
|
@ -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',
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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')
|
||||
|
163
drivers/raw/ifpga/rte_pmd_ifpga.c
Normal file
163
drivers/raw/ifpga/rte_pmd_ifpga.c
Normal file
@ -0,0 +1,163 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2021 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <rte_pci.h>
|
||||
#include <rte_bus_pci.h>
|
||||
#include <rte_rawdev.h>
|
||||
#include <rte_rawdev_pmd.h>
|
||||
#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);
|
||||
}
|
132
drivers/raw/ifpga/rte_pmd_ifpga.h
Normal file
132
drivers/raw/ifpga/rte_pmd_ifpga.h
Normal file
@ -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_ */
|
@ -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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user