From patchwork Wed May 25 01:51:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Huang X-Patchwork-Id: 111773 X-Patchwork-Delegate: thomas@monjalon.net 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 6B55FA0545; Wed, 25 May 2022 03:44:31 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id C111A42685; Wed, 25 May 2022 03:44:26 +0200 (CEST) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by mails.dpdk.org (Postfix) with ESMTP id 8AA9040E2D; Wed, 25 May 2022 03:44:24 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1653443064; x=1684979064; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=9whPs2PWPcnyrw3UmmYDfF5iPGVTTRnaROLy/uHSVNU=; b=GVnSwkjFggp0N/aiODC9vnF1epBIt8rBQnEFgbgqZ3W0qqiNlhAoYhTS O83Y9LuE/SvTjtfY0a1PPftlh5QjfjXzDgHpg93KfF0TfQ6sslNZsKChk Ki4dVepIsp854OO9XFbx+a+yK6YsZUsxaJsIJVAhecfoUApV85+yLVOEf 0d+Iwgp+TXtz4vnHIiz5WHNP/9mupD4jdqxDv2yAFmPOmg2wsr2FUQ4BC X9f1GAhksJHGsVaW9vWDTgTuuDjpF/vbDNXtPjo1O+2JCUayyCnKUJhbn 7mogVmzyiQKbCZWoXzxOnkla5N60UsA1llc5OsCfPhRtyYn/vWsobku54 g==; X-IronPort-AV: E=McAfee;i="6400,9594,10357"; a="299019359" X-IronPort-AV: E=Sophos;i="5.91,250,1647327600"; d="scan'208";a="299019359" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 May 2022 18:44:23 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.91,250,1647327600"; d="scan'208";a="703705946" Received: from unknown (HELO zj-fpga-amt.sh.intel.com) ([10.238.175.102]) by orsmga004.jf.intel.com with ESMTP; 24 May 2022 18:44:20 -0700 From: Wei Huang To: dev@dpdk.org, thomas@monjalon.net, nipun.gupta@nxp.com, hemant.agrawal@nxp.com Cc: stable@dpdk.org, rosen.xu@intel.com, tianfei.zhang@intel.com, qi.z.zhang@intel.com, Wei Huang Subject: [PATCH v1 1/2] raw/ifpga/base: add pmci driver Date: Tue, 24 May 2022 21:51:22 -0400 Message-Id: <1653443483-30971-2-git-send-email-wei.huang@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1653443483-30971-1-git-send-email-wei.huang@intel.com> References: <1653443483-30971-1-git-send-email-wei.huang@intel.com> X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org PMCI (Platform Management Control Interface) is a new module in FPGA, which is designed to cooperate with BMC chip to fulfill board management functions. This driver provide interfaces to access registers of BMC chip and external flash of FPGA. Signed-off-by: Wei Huang Acked-by: Tianfei Zhang --- drivers/raw/ifpga/base/ifpga_defines.h | 103 ++- drivers/raw/ifpga/base/ifpga_feature_dev.c | 2 + drivers/raw/ifpga/base/ifpga_feature_dev.h | 1 + drivers/raw/ifpga/base/ifpga_fme.c | 265 +++++-- drivers/raw/ifpga/base/ifpga_fme_error.c | 2 + drivers/raw/ifpga/base/ifpga_port_error.c | 2 +- drivers/raw/ifpga/base/ifpga_sec_mgr.c | 9 +- drivers/raw/ifpga/base/ifpga_sec_mgr.h | 9 +- drivers/raw/ifpga/base/opae_hw_api.c | 29 + drivers/raw/ifpga/base/opae_hw_api.h | 1 + drivers/raw/ifpga/base/opae_intel_max10.c | 938 ++++++++++++++++++++--- drivers/raw/ifpga/base/opae_intel_max10.h | 313 +++++++- drivers/raw/ifpga/base/opae_osdep.h | 43 +- drivers/raw/ifpga/base/osdep_rte/osdep_generic.h | 10 + 14 files changed, 1524 insertions(+), 203 deletions(-) diff --git a/drivers/raw/ifpga/base/ifpga_defines.h b/drivers/raw/ifpga/base/ifpga_defines.h index 9a280eb..7c8fa89 100644 --- a/drivers/raw/ifpga/base/ifpga_defines.h +++ b/drivers/raw/ifpga/base/ifpga_defines.h @@ -23,6 +23,7 @@ #define FME_FEATURE_NIOS_SPI "fme_nios_spi" #define FME_FEATURE_I2C_MASTER "fme_i2c_master" #define FME_FEATURE_ETH_GROUP "fme_eth_group" +#define FME_FEATURE_PMCI "fme_pmci" #define PORT_FEATURE_HEADER "port_hdr" #define PORT_FEATURE_UAFU "port_uafu" @@ -91,6 +92,7 @@ enum fpga_id_type { #define FME_FEATURE_ID_NIOS_SPI 0xd #define FME_FEATURE_ID_I2C_MASTER 0xf #define FME_FEATURE_ID_ETH_GROUP 0x10 +#define FME_FEATURE_ID_PMCI 0x12 #define PORT_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER #define PORT_FEATURE_ID_ERROR 0x10 @@ -266,6 +268,24 @@ struct feature_fme_bitstream_id { union { u64 csr; struct { + u8 build_patch:8; + u8 build_minor:8; + u8 build_major:8; + u8 fvl_bypass:1; + u8 mac_lightweight:1; + u8 disagregate:1; + u8 lightweiht:1; + u8 seu:1; + u8 ptp:1; + u8 reserve:2; + u8 interface:4; + u32 afu_revision:12; + u8 patch:4; + u8 minor:4; + u8 major:4; + u8 reserved:4; + } v1; + struct { u32 gitrepo_hash:32; /* GIT repository hash */ /* * HSSI configuration identifier: @@ -274,7 +294,8 @@ struct feature_fme_bitstream_id { * 2 - Ethernet */ u8 hssi_id:4; - u16 rsvd1:12; /* Reserved */ + u8 rsvd1:4; + u8 fim_type:8; /* Bitstream version patch number */ u8 bs_verpatch:4; /* Bitstream version minor number */ @@ -283,7 +304,7 @@ struct feature_fme_bitstream_id { u8 bs_vermajor:4; /* Bitstream version debug number */ u8 bs_verdebug:4; - }; + } v2; }; }; @@ -1670,31 +1691,6 @@ struct bts_header { #define check_support(n) (n == 1 ? "support" : "no") -/* bitstream id definition */ -struct fme_bitstream_id { - union { - u64 id; - struct { - u8 build_patch:8; - u8 build_minor:8; - u8 build_major:8; - u8 fvl_bypass:1; - u8 mac_lightweight:1; - u8 disagregate:1; - u8 lightweiht:1; - u8 seu:1; - u8 ptp:1; - u8 reserve:2; - u8 interface:4; - u32 afu_revision:12; - u8 patch:4; - u8 minor:4; - u8 major:4; - u8 reserved:4; - }; - }; -}; - enum board_interface { VC_8_10G = 0, VC_4_25G = 1, @@ -1703,10 +1699,30 @@ enum board_interface { VC_2_2_25G = 4, }; +enum fim_type { + BASE_ADP = 0, + BASE_FDK, + BASE_X16_ADP, + BASE_X16_FDK, + FIMA_10G_ADP, + FIMA_25G_ADP, + FIMA_100G_ADP, + FIMB_ADP, + FIMC_ADP +}; + +enum hssi_id { + NO_HSSI = 0, + PCIE_RP, + ETHER_NET +}; + enum pac_major { VISTA_CREEK = 0, RUSH_CREEK = 1, DARBY_CREEK = 2, + LIGHTNING_CREEK = 3, + ARROW_CREEK = 5, }; enum pac_minor { @@ -1718,23 +1734,30 @@ enum pac_minor { struct opae_board_info { enum pac_major major; enum pac_minor minor; - enum board_interface type; - - /* PAC features */ - u8 fvl_bypass; - u8 mac_lightweight; - u8 disaggregate; - u8 lightweight; - u8 seu; - u8 ptp; u32 boot_page; u32 max10_version; u32 nios_fw_version; - u32 nums_of_retimer; - u32 ports_per_retimer; - u32 nums_of_fvl; - u32 ports_per_fvl; + + union { + struct { /* N3000 specific */ + enum board_interface type; + u8 fvl_bypass; + u8 mac_lightweight; + u8 disaggregate; + u8 lightweight; + u8 seu; + u8 ptp; + u32 nums_of_retimer; + u32 ports_per_retimer; + u32 nums_of_fvl; + u32 ports_per_fvl; + }; + struct { + enum fim_type n6000_fim_type; + enum hssi_id n6000_hssi_id; + }; + }; }; #pragma pack(pop) diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.c b/drivers/raw/ifpga/base/ifpga_feature_dev.c index dbecc7b..0a00af1 100644 --- a/drivers/raw/ifpga/base/ifpga_feature_dev.c +++ b/drivers/raw/ifpga/base/ifpga_feature_dev.c @@ -227,6 +227,8 @@ int port_clear_error(struct ifpga_port_hw *port) &fme_i2c_master_ops),}, {FEATURE_DRV(FME_FEATURE_ID_ETH_GROUP, FME_FEATURE_ETH_GROUP, &fme_eth_group_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_PMCI, FME_FEATURE_PMCI, + &fme_pmci_ops),}, {0, NULL, NULL}, /* end of arrary */ }; diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.h b/drivers/raw/ifpga/base/ifpga_feature_dev.h index b355d22..a637eb5 100644 --- a/drivers/raw/ifpga/base/ifpga_feature_dev.h +++ b/drivers/raw/ifpga/base/ifpga_feature_dev.h @@ -178,6 +178,7 @@ int do_pr(struct ifpga_hw *hw, u32 port_id, const char *buffer, u32 size, extern struct ifpga_feature_ops fme_i2c_master_ops; extern struct ifpga_feature_ops fme_eth_group_ops; extern struct ifpga_feature_ops fme_nios_spi_master_ops; +extern struct ifpga_feature_ops fme_pmci_ops; int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop); int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop); diff --git a/drivers/raw/ifpga/base/ifpga_fme.c b/drivers/raw/ifpga/base/ifpga_fme.c index 43c7b9c..1b9a922 100644 --- a/drivers/raw/ifpga/base/ifpga_fme.c +++ b/drivers/raw/ifpga/base/ifpga_fme.c @@ -790,19 +790,32 @@ struct ifpga_feature_ops fme_emif_ops = { .uinit = fme_emif_uinit, }; -static const char *board_type_to_string(u32 type) -{ - switch (type) { - case VC_8_10G: - return "VC_8x10G"; - case VC_4_25G: - return "VC_4x25G"; - case VC_2_1_25: - return "VC_2x1x25G"; - case VC_4_25G_2_25G: - return "VC_4x25G+2x25G"; - case VC_2_2_25G: - return "VC_2x2x25G"; +static const char *board_type_to_string(u32 board, u32 type) +{ + if (board == VISTA_CREEK) { + switch (type) { + case VC_8_10G: + return "8x10G"; + case VC_4_25G: + return "4x25G"; + case VC_2_1_25: + return "2x1x25G"; + case VC_4_25G_2_25G: + return "4x25G+2x25G"; + case VC_2_2_25G: + return "2x2x25G"; + break; + } + } else { + switch (type) { + case FIMA_10G_ADP: + return "2x4x10G"; + case FIMA_25G_ADP: + return "2x2x25G"; + case FIMA_100G_ADP: + return "2x100G"; + break; + } } return "unknown"; @@ -817,6 +830,12 @@ static const char *board_major_to_string(u32 major) return "RUSH_CREEK"; case DARBY_CREEK: return "DARBY_CREEK"; + case LIGHTNING_CREEK: + return "LIGHTNING_CREEK"; + case ARROW_CREEK: + return "ARROW_CREEK"; + default: + break; } return "unknown"; @@ -859,35 +878,56 @@ static int board_type_to_info(u32 type, static int fme_get_board_interface(struct ifpga_fme_hw *fme) { - struct fme_bitstream_id id; + struct feature_fme_bitstream_id id; struct ifpga_hw *hw; u32 val; + const char *type = NULL; + int ret; hw = fme->parent; if (!hw) return -ENODEV; - if (fme_hdr_get_bitstream_id(fme, &id.id)) + if (fme_hdr_get_bitstream_id(fme, &id.csr)) return -EINVAL; - fme->board_info.major = id.major; - fme->board_info.minor = id.minor; - fme->board_info.type = id.interface; - fme->board_info.fvl_bypass = id.fvl_bypass; - fme->board_info.mac_lightweight = id.mac_lightweight; - fme->board_info.lightweight = id.lightweiht; - fme->board_info.disaggregate = id.disagregate; - fme->board_info.seu = id.seu; - fme->board_info.ptp = id.ptp; + if (id.v1.major == ARROW_CREEK) { + fme->board_info.major = id.v2.bs_vermajor; + fme->board_info.minor = id.v2.bs_verminor; + fme->board_info.n6000_fim_type = id.v2.fim_type; + fme->board_info.n6000_hssi_id = id.v2.hssi_id; + type = board_type_to_string(fme->board_info.major, + fme->board_info.n6000_fim_type); + } else { + fme->board_info.major = id.v1.major; + fme->board_info.minor = id.v1.minor; + fme->board_info.type = id.v1.interface; + fme->board_info.fvl_bypass = id.v1.fvl_bypass; + fme->board_info.mac_lightweight = id.v1.mac_lightweight; + fme->board_info.lightweight = id.v1.lightweiht; + fme->board_info.disaggregate = id.v1.disagregate; + fme->board_info.seu = id.v1.seu; + fme->board_info.ptp = id.v1.ptp; + type = board_type_to_string(fme->board_info.major, + fme->board_info.type); + } dev_info(fme, "found: PCI dev: %02x:%02x:%x board: %s type: %s\n", hw->pci_data->bus, hw->pci_data->devid, hw->pci_data->function, board_major_to_string(fme->board_info.major), - board_type_to_string(fme->board_info.type)); + type); - dev_info(fme, "support feature:\n" + ret = max10_get_fpga_load_info(fme->max10_dev, &val); + if (ret) + return ret; + fme->board_info.boot_page = val; + + if (fme->board_info.major == VISTA_CREEK) { + dev_info(dev, "FPGA loaded from %s Image\n", + val ? "User" : "Factory"); + dev_info(fme, "support feature:\n" "fvl_bypass:%s\n" "mac_lightweight:%s\n" "lightweight:%s\n" @@ -901,26 +941,29 @@ static int fme_get_board_interface(struct ifpga_fme_hw *fme) check_support(fme->board_info.seu), check_support(fme->board_info.ptp)); + if (board_type_to_info(fme->board_info.type, &fme->board_info)) + return -EINVAL; - if (board_type_to_info(fme->board_info.type, &fme->board_info)) - return -EINVAL; - - dev_info(fme, "get board info: nums_retimers %d ports_per_retimer %d nums_fvl %d ports_per_fvl %d\n", + dev_info(fme, "get board info: nums_retimers %d " + "ports_per_retimer %d nums_fvl %d " + "ports_per_fvl %d\n", fme->board_info.nums_of_retimer, fme->board_info.ports_per_retimer, fme->board_info.nums_of_fvl, fme->board_info.ports_per_fvl); + } else { + dev_info(dev, "FPGA loaded from %s Image\n", + val ? (val == 1 ? "User1" : "User2") : "Factory"); + } - 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; + ret = max10_get_bmc_version(fme->max10_dev, &val); + if (ret) + return ret; fme->board_info.max10_version = val; - if (max10_sys_read(fme->max10_dev, NIOS2_FW_VERSION, &val)) - return -EINVAL; + ret = max10_get_bmcfw_version(fme->max10_dev, &val); + if (ret) + return ret; fme->board_info.nios_fw_version = val; dev_info(fme, "max10 version 0x%x, nios fw version 0x%x\n", @@ -983,11 +1026,25 @@ static int fme_spi_init(struct ifpga_feature *feature) altera_spi_init(spi_master); - max10 = intel_max10_device_probe(spi_master, 0); - if (!max10) { + max10 = opae_zmalloc(sizeof(*max10)); + if (!max10) + goto release_dev; + + max10->spi_master = spi_master; + max10->type = M10_N3000; + + max10->spi_tran_dev = spi_transaction_init(spi_master, 0); + if (!max10->spi_tran_dev) { + dev_err(fme, "%s spi tran init fail\n", __func__); + goto free_max10; + } + + /* init the max10 device */ + ret = intel_max10_device_init(max10); + if (ret) { ret = -ENODEV; dev_err(fme, "max10 init fail\n"); - goto spi_fail; + goto release_spi_tran_dev; } fme->max10_dev = max10; @@ -1002,17 +1059,24 @@ static int fme_spi_init(struct ifpga_feature *feature) max10_fail: intel_max10_device_remove(fme->max10_dev); -spi_fail: +release_spi_tran_dev: + if (max10->spi_tran_dev) + spi_transaction_remove(max10->spi_tran_dev); +free_max10: + opae_free(max10); +release_dev: altera_spi_release(spi_master); - return ret; + return -ENODEV; } static void fme_spi_uinit(struct ifpga_feature *feature) { struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; - if (fme->max10_dev) + if (fme->max10_dev) { intel_max10_device_remove(fme->max10_dev); + opae_free(fme->max10_dev); + } } struct ifpga_feature_ops fme_spi_master_ops = { @@ -1157,27 +1221,37 @@ static int fme_nios_spi_init(struct ifpga_feature *feature) /* 3. init the spi master*/ altera_spi_init(spi_master); + max10 = opae_zmalloc(sizeof(*max10)); + if (!max10) + goto release_dev; + + max10->spi_master = spi_master; + max10->type = M10_N3000; + + max10->spi_tran_dev = spi_transaction_init(spi_master, 0); + if (!max10->spi_tran_dev) { + dev_err(fme, "%s spi tran init fail\n", __func__); + goto free_max10; + } + /* init the max10 device */ - max10 = intel_max10_device_probe(spi_master, 0); - if (!max10) { + ret = intel_max10_device_init(max10); + if (ret) { ret = -ENODEV; dev_err(fme, "max10 init fail\n"); - goto release_dev; + goto release_spi_tran_dev; } fme->max10_dev = max10; - max10->bus = hw->pci_data->bus; - fme_get_board_interface(fme); - mgr->sensor_list = &max10->opae_sensor_list; /* SPI self test */ if (spi_self_checking(max10)) goto spi_fail; - ret = init_sec_mgr(fme); + ret = init_sec_mgr(fme, N3000BMC_SEC); if (ret) { dev_err(fme, "security manager init fail\n"); goto spi_fail; @@ -1187,6 +1261,11 @@ static int fme_nios_spi_init(struct ifpga_feature *feature) spi_fail: intel_max10_device_remove(fme->max10_dev); +release_spi_tran_dev: + if (max10->spi_tran_dev) + spi_transaction_remove(max10->spi_tran_dev); +free_max10: + opae_free(max10); release_dev: altera_spi_release(spi_master); return -ENODEV; @@ -1197,8 +1276,10 @@ 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) + if (fme->max10_dev) { intel_max10_device_remove(fme->max10_dev); + opae_free(fme->max10_dev); + } } struct ifpga_feature_ops fme_nios_spi_master_ops = { @@ -1230,7 +1311,7 @@ static int i2c_mac_rom_test(struct altera_i2c_dev *dev) } if (memcmp(buf, read_buf, strlen(string))) { - dev_err(NULL, "%s test fail!\n", __func__); + dev_info(NULL, "%s test fail!\n", __func__); return -EFAULT; } @@ -1499,3 +1580,81 @@ int fme_mgr_get_sensor_value(struct ifpga_fme_hw *fme, return 0; } + +static int fme_pmci_init(struct ifpga_feature *feature) +{ + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + struct intel_max10_device *max10; + struct ifpga_hw *hw; + struct opae_manager *mgr; + opae_share_data *sd = NULL; + int ret = 0; + + hw = fme->parent; + if (!hw) + return -ENODEV; + + mgr = hw->adapter->mgr; + if (!mgr) + return -ENODEV; + + dev_info(fme, "FME PMCI Init.\n"); + dev_debug(fme, "FME PMCI base addr %p.\n", + feature->addr); + + max10 = opae_zmalloc(sizeof(*max10)); + if (!max10) + return -ENOMEM; + + max10->type = M10_N6000; + max10->mmio = feature->addr; + if (hw->adapter && hw->adapter->shm.ptr) { + sd = (opae_share_data *)hw->adapter->shm.ptr; + max10->bmc_ops.mutex = &sd->spi_mutex; + } else { + max10->bmc_ops.mutex = NULL; + } + + /* init the max10 device */ + ret = intel_max10_device_init(max10); + if (ret) { + dev_err(fme, "max10 init fail\n"); + goto free_max10; + } + + fme->max10_dev = max10; + max10->bus = hw->pci_data->bus; + fme_get_board_interface(fme); + mgr->sensor_list = &max10->opae_sensor_list; + + ret = init_sec_mgr(fme, N6000BMC_SEC); + if (ret) { + dev_err(fme, "security manager init fail\n"); + goto release_max10; + } + + return ret; + +release_max10: + intel_max10_device_remove(max10); +free_max10: + opae_free(max10); + + return ret; +} + +static void fme_pmci_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); + opae_free(fme->max10_dev); + } +} + +struct ifpga_feature_ops fme_pmci_ops = { + .init = fme_pmci_init, + .uinit = fme_pmci_uinit, +}; diff --git a/drivers/raw/ifpga/base/ifpga_fme_error.c b/drivers/raw/ifpga/base/ifpga_fme_error.c index 5905eac..c5bed28 100644 --- a/drivers/raw/ifpga/base/ifpga_fme_error.c +++ b/drivers/raw/ifpga/base/ifpga_fme_error.c @@ -224,6 +224,8 @@ static int fme_global_error_init(struct ifpga_feature *feature) { struct ifpga_fme_hw *fme = feature->parent; + dev_info(NULL, "FME error_module Init.\n"); + fme_error_enable(fme); if (feature->ctx_num) diff --git a/drivers/raw/ifpga/base/ifpga_port_error.c b/drivers/raw/ifpga/base/ifpga_port_error.c index 189f762..6c8a7d7 100644 --- a/drivers/raw/ifpga/base/ifpga_port_error.c +++ b/drivers/raw/ifpga/base/ifpga_port_error.c @@ -88,7 +88,7 @@ static int port_error_init(struct ifpga_feature *feature) { struct ifpga_port_hw *port = feature->parent; - dev_info(NULL, "port error Init.\n"); + dev_info(NULL, "port error_module Init.\n"); spinlock_lock(&port->lock); port_err_mask(port, false); diff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.c b/drivers/raw/ifpga/base/ifpga_sec_mgr.c index 15fb5b6..557c4e3 100644 --- a/drivers/raw/ifpga/base/ifpga_sec_mgr.c +++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.c @@ -227,7 +227,7 @@ static int n3000_bulk_write(struct intel_max10_device *dev, uint32_t addr, for (i = 0; i < n; i++) { p = i << 2; v = *(uint32_t *)(buf + p); - ret = max10_reg_write(dev, addr + p, v); + ret = max10_sys_raw_write(dev, addr + p, v); if (ret < 0) { dev_err(dev, "Failed to write to staging area 0x%08x [e:%d]\n", @@ -490,7 +490,7 @@ static int n3000_reload_bmc(struct intel_max10_device *dev, int page) CONFIG_SEL_S(page) | REBOOT_REQ); } else { val = (page == 0) ? 0x1 : 0x3; - ret = max10_reg_write(dev, IFPGA_DUAL_CFG_CTRL1, val); + ret = max10_sys_raw_write(dev, IFPGA_DUAL_CFG_CTRL1, val); if (ret < 0) { dev_err(dev, "Failed to write to dual config1 register [e:%d]\n", @@ -498,7 +498,7 @@ static int n3000_reload_bmc(struct intel_max10_device *dev, int page) goto end; } - ret = max10_reg_write(dev, IFPGA_DUAL_CFG_CTRL0, 0x1); + ret = max10_sys_raw_write(dev, IFPGA_DUAL_CFG_CTRL0, 0x1); if (ret < 0) { if (ret == -EIO) { ret = 0; @@ -584,7 +584,7 @@ static uint64_t n3000_get_hw_errinfo(struct ifpga_sec_mgr *smgr) .get_hw_errinfo = n3000_get_hw_errinfo, }; -int init_sec_mgr(struct ifpga_fme_hw *fme) +int init_sec_mgr(struct ifpga_fme_hw *fme, enum fpga_sec_type type) { struct ifpga_hw *hw = NULL; opae_share_data *sd = NULL; @@ -621,6 +621,7 @@ int init_sec_mgr(struct ifpga_fme_hw *fme) smgr->fme = fme; smgr->max10_dev = fme->max10_dev; + smgr->type = type; return 0; } diff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.h b/drivers/raw/ifpga/base/ifpga_sec_mgr.h index fbeba56..09cc038 100644 --- a/drivers/raw/ifpga/base/ifpga_sec_mgr.h +++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.h @@ -55,6 +55,12 @@ #define IFPGA_RSU_ERR_WEAROUT -7 #define IFPGA_RSU_ERR_FILE_READ -8 +/* Supported fpga secure manager types */ +enum fpga_sec_type { + N3000BMC_SEC, + N6000BMC_SEC +}; + struct ifpga_sec_mgr; struct ifpga_sec_ops { @@ -80,9 +86,10 @@ struct ifpga_sec_mgr { unsigned int *rsu_control; unsigned int *rsu_status; const struct ifpga_sec_ops *ops; + enum fpga_sec_type type; }; -int init_sec_mgr(struct ifpga_fme_hw *fme); +int init_sec_mgr(struct ifpga_fme_hw *fme, enum fpga_sec_type type); void release_sec_mgr(struct ifpga_fme_hw *fme); int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image, uint64_t *status); diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c index 87256fc..6b78094 100644 --- a/drivers/raw/ifpga/base/opae_hw_api.c +++ b/drivers/raw/ifpga/base/opae_hw_api.c @@ -831,6 +831,35 @@ int opae_manager_get_retimer_status(struct opae_manager *mgr, } /** + * opae_manager_get_sensor_list - get sensor name list + * @mgr: opae_manager of sensors + * @buf: buffer to accommodate name list separated by semicolon + * @size: size of buffer + * + * Return: the pointer of the opae_sensor_info + */ +int +opae_mgr_get_sensor_list(struct opae_manager *mgr, char *buf, size_t size) +{ + struct opae_sensor_info *sensor; + uint32_t offset = 0; + + opae_mgr_for_each_sensor(mgr, sensor) { + if (sensor->name) { + if (buf && (offset < size)) + snprintf(buf + offset, size - offset, "%s;", + sensor->name); + offset += strlen(sensor->name) + 1; + } + } + + if (buf && (offset > 0) && (offset <= size)) + buf[offset-1] = 0; + + return offset; +} + +/** * opae_manager_get_sensor_by_id - get sensor device * @id: the id of the sensor * diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h index fd40e09..8aead4d 100644 --- a/drivers/raw/ifpga/base/opae_hw_api.h +++ b/drivers/raw/ifpga/base/opae_hw_api.h @@ -93,6 +93,7 @@ int opae_manager_flash(struct opae_manager *mgr, int acc_id, const char *buf, u32 size, u64 *status); int opae_manager_get_eth_group_region_info(struct opae_manager *mgr, u8 group_id, struct opae_eth_group_region_info *info); +int opae_mgr_get_sensor_list(struct opae_manager *mgr, char *buf, size_t size); struct opae_sensor_info *opae_mgr_get_sensor_by_name(struct opae_manager *mgr, const char *name); struct opae_sensor_info *opae_mgr_get_sensor_by_id(struct opae_manager *mgr, diff --git a/drivers/raw/ifpga/base/opae_intel_max10.c b/drivers/raw/ifpga/base/opae_intel_max10.c index 9d82fb0..465494a 100644 --- a/drivers/raw/ifpga/base/opae_intel_max10.c +++ b/drivers/raw/ifpga/base/opae_intel_max10.c @@ -4,51 +4,42 @@ #include "opae_intel_max10.h" #include +#include "opae_osdep.h" -int max10_reg_read(struct intel_max10_device *dev, - unsigned int reg, unsigned int *val) +int max10_sys_read(struct intel_max10_device *dev, + unsigned int offset, unsigned int *val) { - if (!dev) + if (!dev || !dev->ops->reg_read) return -ENODEV; - dev_debug(dev, "%s: bus:0x%x, reg:0x%x\n", __func__, dev->bus, reg); - - return spi_transaction_read(dev->spi_tran_dev, - reg, 4, (unsigned char *)val); + return dev->ops->reg_read(dev, dev->csr->base + offset, val); } -int max10_reg_write(struct intel_max10_device *dev, - unsigned int reg, unsigned int val) +int max10_sys_write(struct intel_max10_device *dev, + unsigned int offset, unsigned int val) { - unsigned int tmp = val; - - if (!dev) + if (!dev || !dev->ops->reg_write) return -ENODEV; - dev_debug(dev, "%s: bus:0x%x, reg:0x%x, val:0x%x\n", __func__, - dev->bus, reg, val); - - return spi_transaction_write(dev->spi_tran_dev, - reg, 4, (unsigned char *)&tmp); + return dev->ops->reg_write(dev, dev->csr->base + offset, val); } -int max10_sys_read(struct intel_max10_device *dev, +int max10_sys_raw_read(struct intel_max10_device *dev, unsigned int offset, unsigned int *val) { - if (!dev) + if (!dev || !dev->ops->reg_read) return -ENODEV; - - return max10_reg_read(dev, dev->base + offset, val); + return dev->ops->reg_read(dev, offset, val); } -int max10_sys_write(struct intel_max10_device *dev, +int max10_sys_raw_write(struct intel_max10_device *dev, unsigned int offset, unsigned int val) { - if (!dev) + if (!dev || !dev->ops->reg_write) return -ENODEV; - return max10_reg_write(dev, dev->base + offset, val); + return dev->ops->reg_write(dev, offset, val); } int max10_sys_update_bits(struct intel_max10_device *dev, unsigned int offset, @@ -67,6 +58,402 @@ int max10_sys_update_bits(struct intel_max10_device *dev, unsigned int offset, return max10_sys_write(dev, offset, temp); } +static int n3000_bulk_raw_write(struct intel_max10_device *dev, uint32_t addr, + void *buf, uint32_t len) +{ + uint32_t v = 0; + uint32_t i = 0; + char *p = buf; + int ret = 0; + + len = IFPGA_ALIGN(len, 4); + + for (i = 0; i < len; i += 4) { + v = *(uint32_t *)(p + i); + ret = max10_sys_raw_write(dev, addr + i, v); + if (ret < 0) { + dev_err(dev, + "Failed to write to staging area 0x%08x [e:%d]\n", + addr + i, ret); + return ret; + } + } + + return 0; +} + +static int n3000_bulk_raw_read(struct intel_max10_device *dev, + uint32_t addr, void *buf, uint32_t len) +{ + u32 v, i; + char *p = buf; + int ret; + + len = IFPGA_ALIGN(len, 4); + + for (i = 0; i < len; i += 4) { + ret = max10_sys_raw_read(dev, addr + i, &v); + if (ret < 0) { + dev_err(dev, + "Failed to write to staging area 0x%08x [e:%d]\n", + addr + i, ret); + return ret; + } + *(u32 *)(p + i) = v; + } + + return 0; +} + +static int n3000_flash_read(struct intel_max10_device *dev, + u32 addr, void *buf, u32 size) +{ + if (!dev->raw_blk_ops.read_blk) + return -ENODEV; + + return dev->raw_blk_ops.read_blk(dev, addr, buf, size); +} + +static int n3000_flash_write(struct intel_max10_device *dev, + u32 addr, void *buf, u32 size) +{ + if (!dev->raw_blk_ops.write_blk) + return -ENODEV; + + return dev->raw_blk_ops.write_blk(dev, addr, buf, size); +} + +static u32 +pmci_get_write_space(struct intel_max10_device *dev, u32 size) +{ + u32 count, val; + int ret; + + ret = opae_readl_poll_timeout(dev->mmio + PMCI_FLASH_CTRL, val, + GET_FIELD(PMCI_FLASH_FIFO_SPACE, val) == + PMCI_FIFO_MAX_WORDS, + PMCI_FLASH_INT_US, PMCI_FLASH_TIMEOUT_US); + if (ret == -ETIMEDOUT) + return 0; + + count = GET_FIELD(PMCI_FLASH_FIFO_SPACE, val) * 4; + + return (size > count) ? count : size; +} + +static void pmci_write_fifo(void __iomem *base, char *buf, size_t count) +{ + size_t i; + u32 val; + + for (i = 0; i < count/4 ; i++) { + val = *(u32 *)(buf + i * 4); + writel(val, base); + } +} + +static void pmci_read_fifo(void __iomem *base, char *buf, size_t count) +{ + size_t i; + u32 val; + + for (i = 0; i < count/4; i++) { + val = readl(base); + *(u32 *)(buf + i * 4) = val; + } +} + +static int +__pmci_flash_bulk_write(struct intel_max10_device *dev, u32 addr, + void *buf, u32 size) +{ + UNUSED(addr); + u32 blk_size, n_offset = 0; + + while (size) { + blk_size = pmci_get_write_space(dev, size); + if (blk_size == 0) { + dev_err(pmci->dev, "get FIFO available size fail\n"); + return -EIO; + } + size -= blk_size; + pmci_write_fifo(dev->mmio + PMCI_FLASH_FIFO, (char *)buf + n_offset, + blk_size); + n_offset += blk_size; + } + + return 0; +} + +static int +pmci_flash_bulk_write(struct intel_max10_device *dev, u32 addr, + void *buf, u32 size) +{ + int ret; + + pthread_mutex_lock(dev->bmc_ops.mutex); + + ret = __pmci_flash_bulk_write(dev, addr, buf, size); + + pthread_mutex_unlock(dev->bmc_ops.mutex); + return ret; +} + +static int +pmci_set_flash_host_mux(struct intel_max10_device *dev, bool request) +{ + u32 ctrl; + int ret; + + ret = max10_sys_update_bits(dev, + m10bmc_base(dev) + M10BMC_PMCI_FLASH_CTRL, + FLASH_HOST_REQUEST, + SET_FIELD(FLASH_HOST_REQUEST, request)); + if (ret) + return ret; + + return opae_max10_read_poll_timeout(dev, m10bmc_base(dev) + M10BMC_PMCI_FLASH_CTRL, + ctrl, request ? (get_flash_mux(ctrl) == FLASH_MUX_HOST) : + (get_flash_mux(ctrl) != FLASH_MUX_HOST), + PMCI_FLASH_INT_US, PMCI_FLASH_TIMEOUT_US); +} + +static int +pmci_get_mux(struct intel_max10_device *dev) +{ + pthread_mutex_lock(dev->bmc_ops.mutex); + return pmci_set_flash_host_mux(dev, true); +} + +static int +pmci_put_mux(struct intel_max10_device *dev) +{ + int ret; + + ret = pmci_set_flash_host_mux(dev, false); + pthread_mutex_unlock(dev->bmc_ops.mutex); + return ret; +} + +static int +__pmci_flash_bulk_read(struct intel_max10_device *dev, u32 addr, + void *buf, u32 size) +{ + u32 blk_size, offset = 0, val; + int ret; + + while (size) { + blk_size = min_t(u32, size, PMCI_READ_BLOCK_SIZE); + + opae_writel(addr + offset, dev->mmio + PMCI_FLASH_ADDR); + + opae_writel(SET_FIELD(PMCI_FLASH_READ_COUNT, blk_size / 4) + | PMCI_FLASH_RD_MODE, + dev->mmio + PMCI_FLASH_CTRL); + + ret = opae_readl_poll_timeout((dev->mmio + PMCI_FLASH_CTRL), + val, !(val & PMCI_FLASH_BUSY), + PMCI_FLASH_INT_US, + PMCI_FLASH_TIMEOUT_US); + if (ret) { + dev_err(dev, "%s timed out on reading flash 0x%xn", + __func__, val); + return ret; + } + + pmci_read_fifo(dev->mmio + PMCI_FLASH_FIFO, (char *)buf + offset, + blk_size); + + size -= blk_size; + offset += blk_size; + + opae_writel(0, dev->mmio + PMCI_FLASH_CTRL); + } + + return 0; +} + +static int +pmci_flash_bulk_read(struct intel_max10_device *dev, u32 addr, + void *buf, u32 size) +{ + int ret; + + ret = pmci_get_mux(dev); + if (ret) + return ret; + + ret = __pmci_flash_bulk_read(dev, addr, buf, size); + if (ret) + goto fail; + + return pmci_put_mux(dev); + +fail: + pmci_put_mux(dev); + return ret; +} + +static int pmci_check_flash_address(u32 start, u32 end) +{ + if (start < PMCI_FLASH_START || end > PMCI_FLASH_END) + return -EINVAL; + + return 0; +} + +int opae_read_flash(struct intel_max10_device *dev, u32 addr, + u32 size, void *buf) +{ + int ret; + + if (!dev->bmc_ops.check_flash_range || + !dev->bmc_ops.flash_read) + return -ENODEV; + + if (!buf) + return -EINVAL; + + ret = dev->bmc_ops.check_flash_range(addr, addr + size); + if (ret) + return ret; + + ret = dev->bmc_ops.flash_read(dev, addr, buf, size); + if (ret) + return ret; + + return 0; +} + +static int max10_spi_read(struct intel_max10_device *dev, + unsigned int addr, unsigned int *val) +{ + if (!dev) + return -ENODEV; + + dev_debug(dev, "%s: bus:0x%x, addr:0x%x\n", __func__, dev->bus, addr); + + return spi_transaction_read(dev->spi_tran_dev, + addr, 4, (unsigned char *)val); +} + +static int max10_spi_write(struct intel_max10_device *dev, + unsigned int addr, unsigned int val) +{ + unsigned int tmp = val; + + if (!dev) + return -ENODEV; + + dev_debug(dev, "%s: bus:0x%x, reg:0x%x, val:0x%x\n", __func__, + dev->bus, addr, val); + + return spi_transaction_write(dev->spi_tran_dev, + addr, 4, (unsigned char *)&tmp); +} + +static int indirect_bus_clr_cmd(struct intel_max10_device *dev) +{ + unsigned int cmd; + int ret; + + opae_writel(0, dev->mmio + INDIRECT_CMD_OFF); + + ret = opae_readl_poll_timeout((dev->mmio + INDIRECT_CMD_OFF), cmd, + (!cmd), INDIRECT_INT_US, INDIRECT_TIMEOUT_US); + + if (ret) + dev_err(dev, "%s timed out on clearing cmd 0x%x\n", + __func__, cmd); + + return ret; +} + +static int max10_indirect_reg_read(struct intel_max10_device *dev, + unsigned int addr, unsigned int *val) +{ + unsigned int cmd; + int ret; + + if (!dev) + return -ENODEV; + + pthread_mutex_lock(dev->bmc_ops.mutex); + + cmd = opae_readl(dev->mmio + INDIRECT_CMD_OFF); + if (cmd) + dev_warn(dev, "%s non-zero cmd 0x%x\n", __func__, cmd); + + opae_writel(addr, dev->mmio + INDIRECT_ADDR_OFF); + + opae_writel(INDIRECT_CMD_RD, dev->mmio + INDIRECT_CMD_OFF); + + ret = opae_readl_poll_timeout((dev->mmio + INDIRECT_CMD_OFF), cmd, + (cmd & INDIRECT_CMD_ACK), INDIRECT_INT_US, + INDIRECT_TIMEOUT_US); + + *val = opae_readl(dev->mmio + INDIRECT_RD_OFF); + + if (ret) + dev_err(dev, "%s timed out on reg 0x%x cmd 0x%x\n", + __func__, addr, cmd); + + if (indirect_bus_clr_cmd(dev)) + ret = -ETIME; + + pthread_mutex_unlock(dev->bmc_ops.mutex); + + return ret; +} + +static int max10_indirect_reg_write(struct intel_max10_device *dev, + unsigned int addr, unsigned int val) +{ + unsigned int cmd; + int ret; + + if (!dev) + return -ENODEV; + + pthread_mutex_lock(dev->bmc_ops.mutex); + + cmd = readl(dev->mmio + INDIRECT_CMD_OFF); + + if (cmd) + dev_warn(dev, "%s non-zero cmd 0x%x\n", __func__, cmd); + + opae_writel(val, dev->mmio + INDIRECT_WR_OFF); + + opae_writel(addr, dev->mmio + INDIRECT_ADDR_OFF); + + writel(INDIRECT_CMD_WR, dev->mmio + INDIRECT_CMD_OFF); + + ret = opae_readl_poll_timeout((dev->mmio + INDIRECT_CMD_OFF), cmd, + (cmd & INDIRECT_CMD_ACK), INDIRECT_INT_US, + INDIRECT_TIMEOUT_US); + + if (ret) + dev_err(dev, "%s timed out on reg 0x%x cmd 0x%x\n", + __func__, addr, cmd); + + if (indirect_bus_clr_cmd(dev)) + ret = -ETIME; + + pthread_mutex_unlock(dev->bmc_ops.mutex); + + return ret; +} + +const struct m10bmc_regmap m10bmc_pmci_regmap = { + .reg_write = max10_indirect_reg_write, + .reg_read = max10_indirect_reg_read, +}; + +const struct m10bmc_regmap m10bmc_n3000_regmap = { + .reg_write = max10_spi_write, + .reg_read = max10_spi_read, +}; + static struct max10_compatible_id max10_id_table[] = { {.compatible = MAX10_PAC,}, {.compatible = MAX10_PAC_N3000,}, @@ -122,7 +509,7 @@ static int altera_nor_flash_read(struct intel_max10_device *dev, word_len = len/4; for (i = 0; i < word_len; i++) { - ret = max10_reg_read(dev, offset + i*4, + ret = max10_sys_raw_read(dev, offset + i*4, &value); if (ret) return -EBUSY; @@ -557,15 +944,13 @@ static int check_max10_version(struct intel_max10_device *dev) { unsigned int v; - if (!max10_reg_read(dev, MAX10_SEC_BASE_ADDR + MAX10_BUILD_VER, + if (!max10_sys_raw_read(dev, MAX10_SEC_BASE_ADDR + MAX10_BUILD_VER, &v)) { if (v != 0xffffffff) { dev_info(dev, "secure MAX10 detected\n"); - dev->base = MAX10_SEC_BASE_ADDR; dev->flags |= MAX10_FLAGS_SECURE; } else { dev_info(dev, "non-secure MAX10 detected\n"); - dev->base = MAX10_BASE_ADDR; } return 0; } @@ -648,73 +1033,455 @@ static int max10_staging_area_init(struct intel_max10_device *dev) return 0; } -struct intel_max10_device * -intel_max10_device_probe(struct altera_spi_device *spi, - int chipselect) +int max10_get_fpga_load_info(struct intel_max10_device *dev, unsigned int *val) { - struct intel_max10_device *dev; int ret; - unsigned int val; + unsigned int value; - dev = opae_malloc(sizeof(*dev)); - if (!dev) - return NULL; + /* read FPGA loading information */ + ret = max10_sys_read(dev, dev->csr->fpga_page_info, &value); + if (ret) { + dev_err(dev, "fail to get FPGA loading info\n"); + return ret; + } - TAILQ_INIT(&dev->opae_sensor_list); + if (dev->type == M10_N3000) + *val = value & 0x7; + else if (dev->type == M10_N6000) { + if (!GET_FIELD(PMCI_FPGA_CONFIGED, value)) + return -EINVAL; + *val = GET_FIELD(PMCI_FPGA_BOOT_PAGE, value); + } - dev->spi_master = spi; + return 0; +} - dev->spi_tran_dev = spi_transaction_init(spi, chipselect); - if (!dev->spi_tran_dev) { - dev_err(dev, "%s spi tran init fail\n", __func__); - goto free_dev; - } +int max10_get_bmc_version(struct intel_max10_device *dev, unsigned int *val) +{ + int ret; - /* check the max10 version */ - ret = check_max10_version(dev); - if (ret) { - dev_err(dev, "Failed to find max10 hardware!\n"); - goto free_dev; - } + ret = max10_sys_read(dev, dev->csr->build_version, val); + if (ret) + return ret; - /* load the MAX10 device table */ - ret = init_max10_device_table(dev); - if (ret) { - dev_err(dev, "Init max10 device table fail\n"); - goto free_dev; - } + return 0; +} - /* init max10 devices, like sensor*/ - if (dev->flags & MAX10_FLAGS_SECURE) - ret = max10_secure_hw_init(dev); - else - ret = max10_non_secure_hw_init(dev); - if (ret) { - dev_err(dev, "Failed to init max10 hardware!\n"); - goto free_dtb; +int max10_get_bmcfw_version(struct intel_max10_device *dev, unsigned int *val) +{ + int ret; + + ret = max10_sys_read(dev, dev->csr->fw_version, val); + if (ret) + return ret; + + return 0; +} + +static const struct m10bmc_csr m10bmc_spi_csr = { + .base = MAX10_SEC_BASE_ADDR, + .build_version = MAX10_BUILD_VER, + .fw_version = NIOS2_FW_VERSION, + .fpga_page_info = FPGA_PAGE_INFO, + .doorbell = MAX10_DOORBELL, + .auth_result = MAX10_AUTH_RESULT, +}; + +static const struct m10bmc_csr m10bmc_pmci_csr = { + .base = M10BMC_PMCI_SYS_BASE, + .build_version = M10BMC_PMCI_BUILD_VER, + .fw_version = NIOS2_PMCI_FW_VERSION, + .fpga_page_info = M10BMC_PMCI_FPGA_CONF_STS, + .doorbell = M10BMC_PMCI_DOORBELL, + .auth_result = M10BMC_PMCI_AUTH_RESULT, +}; + +static const struct max10_sensor_raw_data n6010bmc_temp_tbl[] = { + { 0x444, 0x448, 0x44c, 0x0, 0x0, 500, + "FPGA E-TILE Temperature #1" }, + { 0x450, 0x454, 0x458, 0x0, 0x0, 500, + "FPGA E-TILE Temperature #2" }, + { 0x45c, 0x460, 0x464, 0x0, 0x0, 500, + "FPGA E-TILE Temperature #3" }, + { 0x468, 0x46c, 0x470, 0x0, 0x0, 500, + "FPGA E-TILE Temperature #4" }, + { 0x474, 0x478, 0x47c, 0x0, 0x0, 500, + "FPGA P-TILE Temperature" }, + { 0x484, 0x488, 0x48c, 0x0, 0x0, 500, + "FPGA FABRIC Digital Temperature#1" }, + { 0x490, 0x494, 0x498, 0x0, 0x0, 500, + "FPGA FABRIC Digital Temperature#2" }, + { 0x49c, 0x4a0, 0x4a4, 0x0, 0x0, 500, + "FPGA FABRIC Digital Temperature#3" }, + { 0x4a8, 0x4ac, 0x4b0, 0x0, 0x0, 500, + "FPGA FABRIC Digital Temperature#4" }, + { 0x4b4, 0x4b8, 0x4bc, 0x0, 0x0, 500, + "FPGA FABRIC Digital Temperature#5" }, + { 0x4c0, 0x4c4, 0x4c8, 0x0, 0x0, 500, + "FPGA FABRIC Remote Digital Temperature#1" }, + { 0x4cc, 0x4d0, 0x4d4, 0x0, 0x0, 500, + "FPGA FABRIC Remote Digital Temperature#2" }, + { 0x4d8, 0x4dc, 0x4e0, 0x0, 0x0, 500, + "FPGA FABRIC Remote Digital Temperature#3" }, + { 0x4e4, 0x4e8, 0x4ec, 0x0, 0x0, 500, + "FPGA FABRIC Remote Digital Temperature#4" }, + { 0x4f0, 0x4f4, 0x4f8, 0x0, 0x0, 500, + "Board Top Near FPGA Temperature" }, + { 0x4fc, 0x500, 0x504, 0x52c, 0x0, 500, + "Board Bottom Near CVL Temperature" }, + { 0x508, 0x50c, 0x510, 0x52c, 0x0, 500, + "Board Top East Near VRs Temperature" }, + { 0x514, 0x518, 0x51c, 0x52c, 0x0, 500, + "Columbiaville Die Temperature" }, + { 0x520, 0x524, 0x528, 0x52c, 0x0, 500, + "Board Rear Side Temperature" }, + { 0x530, 0x534, 0x538, 0x52c, 0x0, 500, + "Board Front Side Temperature" }, + { 0x53c, 0x540, 0x544, 0x0, 0x0, 500, + "QSFP1 Temperature" }, + { 0x548, 0x54c, 0x550, 0x0, 0x0, 500, + "QSFP2 Temperature" }, + { 0x554, 0x0, 0x0, 0x0, 0x0, 500, + "FPGA Core Voltage Phase 0 VR Temperature" }, + { 0x560, 0x0, 0x0, 0x0, 0x0, 500, + "FPGA Core Voltage Phase 1 VR Temperature" }, + { 0x56c, 0x0, 0x0, 0x0, 0x0, 500, + "FPGA Core Voltage Phase 2 VR Temperature" }, + { 0x578, 0x0, 0x0, 0x0, 0x0, 500, + "FPGA Core Voltage VR Controller Temperature" }, + { 0x584, 0x0, 0x0, 0x0, 0x0, 500, + "FPGA VCCH VR Temperature" }, + { 0x590, 0x0, 0x0, 0x0, 0x0, 500, + "FPGA VCC_1V2 VR Temperature" }, + { 0x59c, 0x0, 0x0, 0x0, 0x0, 500, + "FPGA VCCH, VCC_1V2 VR Controller Temperature" }, + { 0x5a8, 0x0, 0x0, 0x0, 0x0, 500, + "3V3 VR Temperature" }, + { 0x5b4, 0x5b8, 0x5bc, 0x0, 0x0, 500, + "CVL Core Voltage VR Temperature" }, + { 0x5c4, 0x5c8, 0x5cc, 0x5c0, 0x0, 500, + "FPGA P-Tile Temperature [Remote]" }, + { 0x5d0, 0x5d4, 0x5d8, 0x5c0, 0x0, 500, + "FPGA E-Tile Temperature [Remote]" }, + { 0x5dc, 0x5e0, 0x5e4, 0x5c0, 0x0, 500, + "FPGA SDM Temperature [Remote]" }, + { 0x5e8, 0x5ec, 0x5f0, 0x5c0, 0x0, 500, + "FPGA Corner Temperature [Remote]" }, +}; + +static const struct max10_sensor_data n6010bmc_tmp_data = { + .type = SENSOR_TMP_NAME, + .number = ARRAY_SIZE(n6010bmc_temp_tbl), + .table = n6010bmc_temp_tbl, +}; + +static const struct max10_sensor_raw_data n6010bmc_in_tbl[] = { + { 0x5f4, 0x0, 0x0, 0x0, 0x0, 1, + "Inlet 12V PCIe Rail Voltage" }, + { 0x60c, 0x0, 0x0, 0x0, 0x0, 1, + "Inlet 12V Aux Rail Voltage" }, + { 0x624, 0x0, 0x0, 0x0, 0x0, 1, + "Inlet 3V3 PCIe Rail Voltage" }, + { 0x63c, 0x0, 0x0, 0x0, 0x0, 1, + "FPGA Core Voltage Rail Voltage" }, + { 0x644, 0x0, 0x0, 0x0, 0x0, 1, + "FPGA VCCH Rail Voltage" }, + { 0x64c, 0x0, 0x0, 0x0, 0x0, 1, + "FPGA VCC_1V2 Rail Voltage" }, + { 0x654, 0x0, 0x0, 0x0, 0x0, 1, + "FPGA VCCH_GXER_1V1, VCCA_1V8 Voltage" }, + { 0x664, 0x0, 0x0, 0x0, 0x0, 1, + "FPGA VCCIO_1V2 Voltage" }, + { 0x674, 0x0, 0x0, 0x0, 0x0, 1, + "CVL Non Core Rails Inlet Voltage" }, + { 0x684, 0x0, 0x0, 0x0, 0x0, 1, + "MAX10 & Board CLK PWR 3V3 Inlet Voltage" }, + { 0x694, 0x0, 0x0, 0x0, 0x0, 1, + "CVL Core Voltage Rail Voltage" }, + { 0x6ac, 0x0, 0x0, 0x0, 0x0, 1, + "Board 3V3 VR Voltage" }, + { 0x6b4, 0x0, 0x0, 0x0, 0x0, 1, + "QSFP 3V3 Rail Voltage" }, + { 0x6c4, 0x0, 0x0, 0x0, 0x0, 1, + "QSFP (Primary) Supply Rail Voltage" }, + { 0x6c8, 0x0, 0x0, 0x0, 0x0, 1, + "QSFP (Secondary) Supply Rail Voltage" }, + { 0x6cc, 0x0, 0x0, 0x0, 0x0, 1, + "VCCCLK_GXER_2V5 Voltage" }, + { 0x6d0, 0x0, 0x0, 0x0, 0x0, 1, + "AVDDH_1V1_CVL Voltage" }, + { 0x6d4, 0x0, 0x0, 0x0, 0x0, 1, + "VDDH_1V8_CVL Voltage" }, + { 0x6d8, 0x0, 0x0, 0x0, 0x0, 1, + "VCCA_PLL Voltage" }, + { 0x6e0, 0x0, 0x0, 0x0, 0x0, 1, + "VCCRT_GXER_0V9 Voltage" }, + { 0x6e8, 0x0, 0x0, 0x0, 0x0, 1, + "VCCRT_GXEL_0V9 Voltage" }, + { 0x6f0, 0x0, 0x0, 0x0, 0x0, 1, + "VCCH_GXPL_1V8 Voltage" }, + { 0x6f4, 0x0, 0x0, 0x0, 0x0, 1, + "VCCPT_1V8 Voltage" }, + { 0x6fc, 0x0, 0x0, 0x0, 0x0, 1, + "VCC_3V3_M10 Voltage" }, + { 0x700, 0x0, 0x0, 0x0, 0x0, 1, + "VCC_1V8_M10 Voltage" }, + { 0x704, 0x0, 0x0, 0x0, 0x0, 1, + "VCC_1V2_EMIF1_2_3 Voltage" }, + { 0x70c, 0x0, 0x0, 0x0, 0x0, 1, + "VCC_1V2_EMIF4_5 Voltage" }, + { 0x714, 0x0, 0x0, 0x0, 0x0, 1, + "VCCA_1V8 Voltage" }, + { 0x718, 0x0, 0x0, 0x0, 0x0, 1, + "VCCH_GXER_1V1 Voltage" }, + { 0x71c, 0x0, 0x0, 0x0, 0x0, 1, + "AVDD_ETH_0V9_CVL Voltage" }, + { 0x720, 0x0, 0x0, 0x0, 0x0, 1, + "AVDD_PCIE_0V9_CVL Voltage" }, +}; + +static const struct max10_sensor_data n6010bmc_in_data = { + .type = SENSOR_IN_NAME, + .number = ARRAY_SIZE(n6010bmc_in_tbl), + .table = n6010bmc_in_tbl, +}; + +static const struct max10_sensor_raw_data n6010bmc_curr_tbl[] = { + { 0x600, 0x604, 0x608, 0x0, 0x0, 1, + "Inlet 12V PCIe Rail Current" }, + { 0x618, 0x61c, 0x620, 0x0, 0x0, 1, + "Inlet 12V Aux Rail Current" }, + { 0x630, 0x634, 0x638, 0x0, 0x0, 1, + "Inlet 3V3 PCIe Rail Current" }, + { 0x640, 0x0, 0x0, 0x0, 0x0, 1, + "FPGA Core Voltage Rail Current" }, + { 0x648, 0x0, 0x0, 0x0, 0x0, 1, + "FPGA VCCH Rail Current" }, + { 0x650, 0x0, 0x0, 0x0, 0x0, 1, + "FPGA VCC_1V2 Rail Current" }, + { 0x658, 0x65c, 0x660, 0x0, 0x0, 1, + "FPGA VCCH_GXER_1V1, VCCA_1V8 Current" }, + { 0x668, 0x66c, 0x670, 0x0, 0x0, 1, + "FPGA VCCIO_1V2 Current" }, + { 0x678, 0x67c, 0x680, 0x0, 0x0, 1, + "CVL Non Core Rails Inlet Current" }, + { 0x688, 0x68c, 0x680, 0x0, 0x0, 1, + "MAX10 & Board CLK PWR 3V3 Inlet Current" }, + { 0x690, 0x0, 0x0, 0x0, 0x0, 1, + "CVL Core Voltage Rail Current" }, + { 0x6b0, 0x0, 0x0, 0x0, 0x0, 1, + "Board 3V3 VR Current" }, + { 0x6b8, 0x6bc, 0x670, 0x0, 0x0, 1, + "QSFP 3V3 Rail Current" }, +}; + +static const struct max10_sensor_data n6010bmc_curr_data = { + .type = SENSOR_CURR_NAME, + .number = ARRAY_SIZE(n6010bmc_curr_tbl), + .table = n6010bmc_curr_tbl, +}; + +static const struct max10_sensor_raw_data n6010bmc_power_tbl[] = { + { 0x724, 0x0, 0x0, 0x0, 0x0, 1000, "Board Power" }, +}; + +static const struct max10_sensor_data n6010bmc_power_data = { + .type = SENSOR_POWER_NAME, + .number = ARRAY_SIZE(n6010bmc_power_tbl), + .table = n6010bmc_power_tbl, +}; + +static const struct max10_sensor_board_data n6010bmc_sensor_board_data = { + .tables = { + [sensor_temp] = &n6010bmc_tmp_data, + [sensor_in] = &n6010bmc_in_data, + [sensor_curr] = &n6010bmc_curr_data, + [sensor_power] = &n6010bmc_power_data, + }, +}; + +static int get_sensor_data(struct intel_max10_device *dev, + struct opae_sensor_info *sensor, + unsigned int *value, + unsigned int reg, + unsigned int flags) +{ + int ret; + unsigned int data; + + if (!reg) + return 0; + + ret = max10_sys_read(dev, reg, &data); + if (ret) + return ret; + + if (data == SENSOR_INVALID) { + dev_debug(dev, "%s: sensor:%s invalid 0x%x at:%d\n", + __func__, sensor->name, data, reg); + return ret; } - /* read FPGA loading information */ - ret = max10_sys_read(dev, FPGA_PAGE_INFO, &val); - if (ret) { - dev_err(dev, "fail to get FPGA loading info\n"); - goto release_max10_hw; + *value = data * sensor->multiplier; + sensor->flags |= flags; + + return 0; +} + +static int max10_parse_sensor_data(struct intel_max10_device *dev, + const struct max10_sensor_data *sdata) +{ + struct opae_sensor_info *sensor; + const struct max10_sensor_raw_data *raw; + const struct max10_sensor_raw_data *table = + (const struct max10_sensor_raw_data *)sdata->table; + unsigned int i; + static unsigned int sensor_id; + int ret = 0; + + for (i = 0; i < sdata->number; i++) { + raw = &table[i]; + + sensor = opae_zmalloc(sizeof(*sensor)); + if (!sensor) { + ret = -EINVAL; + goto free_sensor; + } + + sensor->type = sdata->type; + sensor->id = sensor_id++; + + if (!raw->reg_input) + continue; + + sensor->value_reg = raw->reg_input; + sensor->multiplier = raw->multiplier; + sensor->name = raw->label; + + ret = get_sensor_data(dev, sensor, + &sensor->high_warn, + raw->reg_high_warn, + OPAE_SENSOR_HIGH_WARN_VALID); + if (ret) + break; + + ret = get_sensor_data(dev, sensor, + &sensor->high_fatal, + raw->reg_high_fatal, + OPAE_SENSOR_HIGH_FATAL_VALID); + if (ret) + break; + + ret = get_sensor_data(dev, sensor, + &sensor->hysteresis, + raw->reg_hyst, + OPAE_SENSOR_HYSTERESIS_VALID); + if (ret) + break; + + ret = get_sensor_data(dev, sensor, + &sensor->low_warn, + raw->reg_low_warn, + OPAE_SENSOR_LOW_WARN_VALID); + if (ret) + break; + + sensor->flags |= OPAE_SENSOR_VALID; + + TAILQ_INSERT_TAIL(&dev->opae_sensor_list, sensor, node); + dev_info(dev, "found valid sensor: %s\n", sensor->name); } - dev_info(dev, "FPGA loaded from %s Image\n", val ? "User" : "Factory"); - return dev; + return ret; -release_max10_hw: +free_sensor: max10_sensor_uinit(dev); -free_dtb: - if (dev->fdt_root) - opae_free(dev->fdt_root); - if (dev->spi_tran_dev) - spi_transaction_remove(dev->spi_tran_dev); -free_dev: - opae_free(dev); + return ret; +} - return NULL; +static int max10_sensor_init_table(struct intel_max10_device *dev, + const struct max10_sensor_board_data *data) +{ + int ret = 0; + unsigned int i; + const struct max10_sensor_data *sdata; + + for (i = 0; i < ARRAY_SIZE(data->tables); i++) { + sdata = data->tables[i]; + if (!sdata) + continue; + ret = max10_parse_sensor_data(dev, sdata); + if (ret) + break; + } + + return ret; +} + +int +intel_max10_device_init(struct intel_max10_device *dev) +{ + int ret = 0; + + TAILQ_INIT(&dev->opae_sensor_list); + + + if (dev->type == M10_N3000) { + dev->ops = &m10bmc_n3000_regmap; + dev->csr = &m10bmc_spi_csr; + + dev->raw_blk_ops.write_blk = n3000_bulk_raw_write; + dev->raw_blk_ops.read_blk = n3000_bulk_raw_read; + dev->bmc_ops.flash_read = n3000_flash_read; + dev->bmc_ops.flash_write = n3000_flash_write; + + /* check the max10 version */ + ret = check_max10_version(dev); + if (ret) { + dev_err(dev, "Failed to find max10 hardware!\n"); + return ret; + } + + /* load the MAX10 device table */ + ret = init_max10_device_table(dev); + if (ret) { + dev_err(dev, "Init max10 device table fail\n"); + return ret; + } + + /* init max10 devices, like sensor*/ + if (dev->flags & MAX10_FLAGS_SECURE) + ret = max10_secure_hw_init(dev); + else + ret = max10_non_secure_hw_init(dev); + if (ret) { + dev_err(dev, "Failed to init max10 hardware!\n"); + opae_free(dev->fdt_root); + return ret; + } + } else if (dev->type == M10_N6000) { + dev->ops = &m10bmc_pmci_regmap; + dev->csr = &m10bmc_pmci_csr; + dev->staging_area_size = MAX_STAGING_AREA_SIZE; + dev->flags |= MAX10_FLAGS_SECURE; + + dev->bmc_ops.flash_read = pmci_flash_bulk_read; + dev->bmc_ops.flash_write = pmci_flash_bulk_write; + dev->bmc_ops.check_flash_range = pmci_check_flash_address; + + ret = max10_sensor_init_table(dev, &n6010bmc_sensor_board_data); + if (ret) + return ret; + + ret = pthread_mutex_init(&dev->bmc_ops.lock, NULL); + if (ret) + return ret; + + if (!dev->bmc_ops.mutex) + dev->bmc_ops.mutex = &dev->bmc_ops.lock; + } + + return ret; } int intel_max10_device_remove(struct intel_max10_device *dev) @@ -722,15 +1489,14 @@ int intel_max10_device_remove(struct intel_max10_device *dev) if (!dev) return 0; - max10_sensor_uinit(dev); + pthread_mutex_destroy(&dev->bmc_ops.lock); - if (dev->spi_tran_dev) - spi_transaction_remove(dev->spi_tran_dev); + if (dev->type == M10_N3000) { + max10_sensor_uinit(dev); - if (dev->fdt_root) - opae_free(dev->fdt_root); - - opae_free(dev); + if (dev->fdt_root) + opae_free(dev->fdt_root); + } return 0; } diff --git a/drivers/raw/ifpga/base/opae_intel_max10.h b/drivers/raw/ifpga/base/opae_intel_max10.h index e761d7e..ead48ea 100644 --- a/drivers/raw/ifpga/base/opae_intel_max10.h +++ b/drivers/raw/ifpga/base/opae_intel_max10.h @@ -7,6 +7,9 @@ #include "opae_osdep.h" #include "opae_spi.h" +#include "ifpga_compat.h" + +struct intel_max10_device; struct max10_compatible_id { char compatible[128]; @@ -29,6 +32,64 @@ struct max10_compatible_id { /** List of opae sensors */ TAILQ_HEAD(opae_sensor_list, opae_sensor_info); +/* Supported MAX10 BMC types */ +enum m10bmc_type { + M10_N3000, + M10_N6000 +}; + +struct regmap_range { + unsigned int min; + unsigned int max; +}; + +struct m10bmc_regmap { + int (*reg_write)(struct intel_max10_device *dev, + unsigned int reg, unsigned int val); + int (*reg_read)(struct intel_max10_device *dev, + unsigned int reg, unsigned int *val); + const struct regmap_range *range; + int num_ranges; +}; + +struct m10bmc_csr { + unsigned int base; + unsigned int build_version; + unsigned int fw_version; + unsigned int fpga_page_info; + unsigned int doorbell; + unsigned int auth_result; +}; + +/** + * struct flash_raw_blk_ops - device specific operations for flash R/W + * @write_blk: write a block of data to flash + * @read_blk: read a block of data from flash + */ +struct flash_raw_blk_ops { + int (*write_blk)(struct intel_max10_device *dev, uint32_t addr, + void *buf, uint32_t size); + int (*read_blk)(struct intel_max10_device *dev, uint32_t addr, + void *buf, uint32_t size); +}; + +/** + * struct m10bmc_ops - device specific operations + * @lock: prevent concurrent flash read/write + * @mutex: prevent concurrent bmc read/write + * @flash_read: read a block of data from flash + * @flash_write: write a block of data to flash + */ +struct m10bmc_ops { + pthread_mutex_t lock; + pthread_mutex_t *mutex; + int (*check_flash_range)(u32 start, u32 end); + int (*flash_read)(struct intel_max10_device *dev, u32 addr, + void *buf, u32 size); + int (*flash_write)(struct intel_max10_device *dev, u32 addr, + void *buf, u32 size); +}; + struct intel_max10_device { unsigned int flags; /*max10 hardware capability*/ struct altera_spi_device *spi_master; @@ -40,6 +101,12 @@ struct intel_max10_device { struct opae_sensor_list opae_sensor_list; u32 staging_area_base; u32 staging_area_size; + enum m10bmc_type type; + const struct m10bmc_regmap *ops; + const struct m10bmc_csr *csr; + struct flash_raw_blk_ops raw_blk_ops; + struct m10bmc_ops bmc_ops; + u8 *mmio; /* mmio address for PMCI */ }; /* retimer speed */ @@ -87,6 +154,7 @@ struct opae_retimer_status { /* System Registers */ #define MAX10_BASE_ADDR 0x300400 #define MAX10_SEC_BASE_ADDR 0x300800 + /* Register offset of system registers */ #define NIOS2_FW_VERSION 0x0 #define MAX10_MACADDR1 0x10 @@ -151,6 +219,32 @@ struct opae_retimer_status { #define SEC_STATUS_NON_INC 0x6 #define SEC_STATUS_ERASE_FAIL 0x7 #define SEC_STATUS_WEAROUT 0x8 +#define SEC_STATUS_PMCI_SS_FAIL 0x9 +#define SEC_STATUS_FLASH_CMD 0xa +#define SEC_STATUS_FACTORY_UNVERITY 0xb +#define SEC_STATUS_FACTORY_ACTIVE 0xc +#define SEC_STATUS_POWER_DOWN 0xd +#define SEC_STATUS_CANCELLATION 0xe +#define SEC_STATUS_HASH 0xf +#define SEC_STATUS_FLASH_ACCESS 0x10 +#define SEC_STATUS_SDM_PR_CERT 0x20 +#define SEC_STATUS_SDM_PR_NIOS_BUSY 0x21 +#define SEC_STATUS_SDM_PR_TIMEOUT 0x22 +#define SEC_STATUS_SDM_PR_FAILED 0x23 +#define SEC_STATUS_SDM_PR_MISMATCH 0x24 +#define SEC_STATUS_SDM_PR_FLUSH 0x25 +#define SEC_STATUS_SDM_SR_CERT 0x30 +#define SEC_STATUS_SDM_SR_NIOS_BUSY 0x31 +#define SEC_STATUS_SDM_SR_TIMEOUT 0x32 +#define SEC_STATUS_SDM_SR_FAILED 0x33 +#define SEC_STATUS_SDM_SR_MISMATCH 0x34 +#define SEC_STATUS_SDM_SR_FLUSH 0x35 +#define SEC_STATUS_SDM_KEY_CERT 0x40 +#define SEC_STATUS_SDM_KEY_NIOS_BUSY 0x41 +#define SEC_STATUS_SDM_KEY_TIMEOUT 0x42 +#define SEC_STATUS_SDM_KEY_FAILED 0x43 +#define SEC_STATUS_SDM_KEY_MISMATCH 0x44 +#define SEC_STATUS_SDM_KEY_FLUSH 0x45 #define SEC_STATUS_NIOS_OK 0x80 #define SEC_STATUS_USER_OK 0x81 #define SEC_STATUS_FACTORY_OK 0x82 @@ -158,9 +252,65 @@ struct opae_retimer_status { #define SEC_STATUS_FACTORY_FAIL 0x84 #define SEC_STATUS_NIOS_FLASH_ERR 0x85 #define SEC_STATUS_FPGA_FLASH_ERR 0x86 +#define SEC_STATUS_MAX SEC_STATUS_FPGA_FLASH_ERR + +/* Authentication status */ +#define SEC_AUTH_G(v) ((v) & 0xff) +#define AUTH_STAT_PASS 0x0 +#define AUTH_STAT_B0_MAGIC 0x1 +#define AUTH_STAT_CONLEN 0x2 +#define AUTH_STAT_CONTYPE 0x3 +#define AUTH_STAT_B1_MAGIC 0x4 +#define AUTH_STAT_ROOT_MAGIC 0x5 +#define AUTH_STAT_CURVE_MAGIC 0x6 +#define AUTH_STAT_PERMISSION 0x7 +#define AUTH_STAT_KEY_ID 0x8 +#define AUTH_STAT_CSK_MAGIC 0x9 +#define AUTH_STAT_CSK_CURVE 0xa +#define AUTH_STAT_CSK_PERMISSION 0xb +#define AUTH_STAT_CSK_ID 0xc +#define AUTH_STAT_CSK_SM 0xd +#define AUTH_STAT_B0_E_MAGIC 0xe +#define AUTH_STAT_B0_E_SIGN 0xf +#define AUTH_STAT_RK_P 0x10 +#define AUTH_STAT_RE_SHA 0x11 +#define AUTH_STAT_CSK_SHA 0x12 +#define AUTH_STAT_B0_SHA 0x13 +#define AUTH_STAT_KEY_INV 0x14 +#define AUTH_STAT_KEY_CAN 0x15 +#define AUTH_STAT_UP_SHA 0x16 +#define AUTH_STAT_CAN_SHA 0x17 +#define AUTH_STAT_HASH 0x18 +#define AUTH_STAT_INV_ID 0x19 +#define AUTH_STAT_KEY_PROG 0x1a +#define AUTH_STAT_INV_BC 0x1b +#define AUTH_STAT_INV_SLOT 0x1c +#define AUTH_STAT_IN_OP 0x1d +#define AUTH_STAT_TIME_OUT 0X1e +#define AUTH_STAT_SHA_TO 0x1f +#define AUTH_STAT_CSK_TO 0x20 +#define AUTH_STAT_B0_TO 0x21 +#define AUTH_STAT_UP_TO 0x22 +#define AUTH_STAT_CAN_TO 0x23 +#define AUTH_STAT_HASH_TO 0x24 +#define AUTH_STAT_AUTH_IDLE 0xfe +#define AUTH_STAT_GA_FAIL 0xff +#define AUTH_STAT_S_ERR 0x8000 +#define AUTH_STAT_S_MN 0x8001 +#define AUTH_STAT_SH_CRC 0x8002 +#define AUTH_STAT_SD_CRC 0x8003 +#define AUTH_STAT_SD_LEN 0x8004 +#define AUTH_STAT_S_ID 0x8005 +#define AUTH_STAT_S_THR 0x8006 +#define AUTH_STAT_S_TO 0x8007 +#define AUTH_STAT_S_EN 0x8008 +#define AUTH_STAT_SF 0x8009 +#define AUTH_STAT_MAX AUTH_STAT_SF + #define CONFIG_SEL BIT(28) #define CONFIG_SEL_S(v) (((v) & 0x1) << 28) #define REBOOT_REQ BIT(29) +#define REBOOT_DISABLED BIT(30) #define MAX10_AUTH_RESULT 0x404 /* PKVL related registers, in system register region */ @@ -185,22 +335,26 @@ struct opae_retimer_status { #define MAX_STAGING_AREA_BASE 0xffffffff #define MAX_STAGING_AREA_SIZE 0x3800000 -int max10_reg_read(struct intel_max10_device *dev, - unsigned int reg, unsigned int *val); -int max10_reg_write(struct intel_max10_device *dev, - unsigned int reg, unsigned int val); +#define m10bmc_base(max10) ((max10)->csr->base) +#define doorbell_reg(max10) ((max10)->csr->doorbell) +#define auth_result_reg(max10) ((max10)->csr->auth_result) + 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_raw_read(struct intel_max10_device *dev, + unsigned int offset, unsigned int *val); +int max10_sys_raw_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); +int max10_get_bmcfw_version(struct intel_max10_device *dev, unsigned int *val); +int max10_get_bmc_version(struct intel_max10_device *dev, unsigned int *val); +int max10_get_fpga_load_info(struct intel_max10_device *dev, unsigned int *val); +int intel_max10_device_init(struct intel_max10_device *dev); int intel_max10_device_remove(struct intel_max10_device *dev); - #define SENSOR_REG_VALUE 0x0 #define SENSOR_REG_HIGH_WARN 0x1 #define SENSOR_REG_HIGH_FATAL 0x2 @@ -254,4 +408,147 @@ struct opae_sensor_info { unsigned int value_reg; }; +#define SENSOR_INVALID 0xdeadbeef + +struct max10_sensor_raw_data { + unsigned int reg_input; + unsigned int reg_high_warn; + unsigned int reg_high_fatal; + unsigned int reg_hyst; + unsigned int reg_low_warn; + unsigned int multiplier; + const char *label; +}; + +struct max10_sensor_data { + const char *type; + unsigned int number; + const struct max10_sensor_raw_data *table; +}; + +enum max10_sensor_types { + sensor_temp, + sensor_in, + sensor_curr, + sensor_power, + sensor_max, +}; + +#define SENSOR_TMP_NAME "Temperature" +#define SENSOR_IN_NAME "Voltage" +#define SENSOR_CURR_NAME "Current" +#define SENSOR_POWER_NAME "Power" + +struct max10_sensor_board_data { + const struct max10_sensor_data *tables[sensor_max]; +}; + +/* indirect access for PMCI */ +#define PMCI_INDIRECT_BASE 0x400 +#define INDIRECT_CMD_OFF (PMCI_INDIRECT_BASE + 0x0) +#define INDIRECT_CMD_RD BIT(0) +#define INDIRECT_CMD_WR BIT(1) +#define INDIRECT_CMD_ACK BIT(2) + +#define INDIRECT_ADDR_OFF (PMCI_INDIRECT_BASE + 0x4) +#define INDIRECT_RD_OFF (PMCI_INDIRECT_BASE + 0x8) +#define INDIRECT_WR_OFF (PMCI_INDIRECT_BASE + 0xc) + +#define INDIRECT_INT_US 1 +#define INDIRECT_TIMEOUT_US 10000 + +#define M10BMC_PMCI_SYS_BASE 0x0 +#define M10BMC_PMCI_SYS_END 0xfff + +#define M10BMC_PMCI_BUILD_VER 0x0 +#define NIOS2_PMCI_FW_VERSION 0x4 + +#define M10BMC_PMCI_PWR_STATE 0xb4 +#define PMCI_PRIMARY_IMAGE_PAGE GENMASK(10, 8) + +#define M10BMC_PMCI_DOORBELL 0x1c0 +#define PMCI_DRBL_REBOOT_DISABLED BIT(1) +#define M10BMC_PMCI_AUTH_RESULT 0x1c4 + +#define M10BMC_PMCI_MAX10_RECONF 0xfc +#define PMCI_MAX10_REBOOT_REQ BIT(0) +#define PMCI_MAX10_REBOOT_PAGE BIT(1) + +#define M10BMC_PMCI_FPGA_RECONF 0xb8 +#define PMCI_FPGA_RECONF_PAGE GENMASK(22, 20) +#define PMCI_FPGA_RP_LOAD BIT(23) + +#define PMCI_FLASH_CTRL 0x40 +#define PMCI_FLASH_WR_MODE BIT(0) +#define PMCI_FLASH_RD_MODE BIT(1) +#define PMCI_FLASH_BUSY BIT(2) +#define PMCI_FLASH_FIFO_SPACE GENMASK(13, 4) +#define PMCI_FLASH_READ_COUNT GENMASK(25, 16) + +#define PMCI_FLASH_INT_US 1 +#define PMCI_FLASH_TIMEOUT_US 10000 + +#define PMCI_FLASH_ADDR 0x44 +#define PMCI_FLASH_FIFO 0x800 +#define PMCI_READ_BLOCK_SIZE 0x800 +#define PMCI_FIFO_MAX_BYTES 0x800 +#define PMCI_FIFO_MAX_WORDS (PMCI_FIFO_MAX_BYTES / 4) + +#define M10BMC_PMCI_FPGA_POC 0xb0 +#define PMCI_FPGA_POC BIT(0) +#define PMCI_NIOS_REQ_CLEAR BIT(1) +#define PMCI_NIOS_STATUS GENMASK(5, 4) +#define NIOS_STATUS_IDLE 0 +#define NIOS_STATUS_SUCCESS 1 +#define NIOS_STATUS_FAIL 2 +#define PMCI_USER_IMAGE_PAGE GENMASK(10, 8) +#define POC_USER_IMAGE_1 1 +#define POC_USER_IMAGE_2 2 +#define PMCI_FACTORY_IMAGE_SEL BIT(31) + +#define M10BMC_PMCI_FPGA_CONF_STS 0xa0 +#define PMCI_FPGA_BOOT_PAGE GENMASK(2, 0) +#define PMCI_FPGA_CONFIGED BIT(3) + +#define M10BMC_PMCI_FLASH_CTRL 0x1d0 +#define FLASH_MUX_SELECTION GENMASK(2, 0) +#define FLASH_MUX_IDLE 0 +#define FLASH_MUX_NIOS 1 +#define FLASH_MUX_HOST 2 +#define FLASH_MUX_PFL 4 +#define get_flash_mux(mux) GET_FIELD(FLASH_MUX_SELECTION, mux) +#define FLASH_NIOS_REQUEST BIT(4) +#define FLASH_HOST_REQUEST BIT(5) + +#define M10BMC_PMCI_SDM_CTRL_STS 0x230 +#define PMCI_SDM_IMG_REQ BIT(0) +#define PMCI_SDM_STAT GENMASK(23, 16) + +#define SDM_STAT_DONE 0x0 +#define SDM_STAT_PROV 0x1 +#define SDM_STAT_BUSY 0x2 +#define SDM_STAT_INV 0x3 +#define SDM_STAT_FAIL 0x4 +#define SDM_STAT_BMC_BUSY 0x5 +#define SDM_STAT_TO 0x6 +#define SDM_STAT_DB 0x7 +#define SDM_STAT_CON_R 0x8 +#define SDM_STAT_CON_E 0x9 +#define SDM_STAT_WAIT 0xa +#define SDM_STAT_RTO 0xb +#define SDM_STAT_SB 0xc +#define SDM_STAT_RE 0xd +#define SDM_STAT_PDD 0xe +#define SDM_STAT_ISC 0xf +#define SDM_STAT_SIC 0x10 +#define SDM_STAT_NO_PROV 0x11 +#define SDM_STAT_CS_MIS 0x12 +#define SDM_STAT_PR_MIS 0x13 +#define SDM_STAT_MAX SDM_STAT_PR_MIS + +#define PMCI_FLASH_START 0x10000 +#define PMCI_FLASH_END 0xC7FFFFF + +int opae_read_flash(struct intel_max10_device *dev, u32 addr, + u32 size, void *buf); #endif diff --git a/drivers/raw/ifpga/base/opae_osdep.h b/drivers/raw/ifpga/base/opae_osdep.h index 18e6a11..033b7e0 100644 --- a/drivers/raw/ifpga/base/opae_osdep.h +++ b/drivers/raw/ifpga/base/opae_osdep.h @@ -79,15 +79,38 @@ struct uuid { #define time_before(a, b) time_after(b, a) #define opae_memset(a, b, c) memset((a), (b), (c)) -#define opae_readq_poll_timeout(addr, val, cond, invl, timeout)\ -({ \ - int wait = 0; \ - for (; wait <= timeout; wait += invl) { \ - (val) = opae_readq(addr); \ - if (cond) \ - break; \ - udelay(invl); \ - } \ - (cond) ? 0 : -ETIMEDOUT; \ +#define readx_poll_timeout(op, val, cond, invl, timeout, args...) \ +({ \ + unsigned long __wait = 0; \ + unsigned long __invl = (invl); \ + unsigned long __timeout = (timeout); \ + for (; __wait <= __timeout; __wait += __invl) { \ + (val) = op(args); \ + if (cond) \ + break; \ + udelay(__invl); \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ }) + +#define opae_readq_poll_timeout(addr, val, cond, invl, timeout) \ + readx_poll_timeout(opae_readq, val, cond, invl, timeout, addr) + +#define opae_readl_poll_timeout(addr, val, cond, invl, timeout) \ + readx_poll_timeout(opae_readl, val, cond, invl, timeout, addr) + +#define opae_readw_poll_timeout(addr, val, cond, invl, timeout) \ + readx_poll_timeout(opae_readw, val, cond, invl, timeout, addr) + +#define opae_readb_poll_timeout(addr, val, cond, invl, timeout) \ + readx_poll_timeout(opae_readb, val, cond, invl, timeout, addr) + +#define opae_max10_read_poll_timeout(dev, addr, value, cond, invl, timeout) \ +({ \ + int __ret, __tmp; \ + __tmp = readx_poll_timeout(max10_sys_read, __ret, __ret || (cond), \ + invl, timeout, (dev), (addr), &(value)); \ + __ret?:__tmp; \ +}) + #endif diff --git a/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h b/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h index 3ff49a8..68499e6 100644 --- a/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h +++ b/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h @@ -39,6 +39,16 @@ #define min(a, b) RTE_MIN(a, b) #define max(a, b) RTE_MAX(a, b) +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1 : __min2; }) + +#define max_t(type, x, y) ({ \ + type __max1 = (x); \ + type __max2 = (y); \ + __max1 > __max2 ? __max1 : __max2; }) + #define spinlock_t rte_spinlock_t #define spinlock_init(x) rte_spinlock_init(x) #define spinlock_lock(x) rte_spinlock_lock(x) From patchwork Wed May 25 01:51:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Huang X-Patchwork-Id: 111774 X-Patchwork-Delegate: thomas@monjalon.net 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 1E8E0A0545; Wed, 25 May 2022 03:44:41 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 2630B427F3; Wed, 25 May 2022 03:44:30 +0200 (CEST) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by mails.dpdk.org (Postfix) with ESMTP id 9836A427F2; Wed, 25 May 2022 03:44:27 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1653443068; x=1684979068; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=sBoOCVHlnMTKe1AUXN0xMcYTzeN11sef4J714UW6Y9E=; b=VG8C+PZbNvW5c3wEo7bt8l5/3XmvzNIhbYyqUIny8mR7eYFkFoznVbuo 8C5b2VcsO7GVloXJChFsVOHr2CZB4MHTcNpFqXLRApqPNcEesl0NwOo9C gqhxWy/lhzHpmHQWfy+ika+Q5T6ifEAtN1ZlJ4eZzZjIDuXxI/BUQ7k8Z ejSLrI3maIBWaBb3ttzxJvJhY+6AtaoWzcC3dEOQYC4wGYkqQcEMsisxx +7XhYXEh1tgJhcUPYY2c/xio9/lYDNjlqK/0FcsyDEFP4zUfJn5yEnjCs X6fHLVO9mNVf3CTO/t4hYeUgsdyV2pS76IlNbf+c/Qbh1ozgjR77+JtCT w==; X-IronPort-AV: E=McAfee;i="6400,9594,10357"; a="299019362" X-IronPort-AV: E=Sophos;i="5.91,250,1647327600"; d="scan'208";a="299019362" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 May 2022 18:44:27 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.91,250,1647327600"; d="scan'208";a="703705957" Received: from unknown (HELO zj-fpga-amt.sh.intel.com) ([10.238.175.102]) by orsmga004.jf.intel.com with ESMTP; 24 May 2022 18:44:24 -0700 From: Wei Huang To: dev@dpdk.org, thomas@monjalon.net, nipun.gupta@nxp.com, hemant.agrawal@nxp.com Cc: stable@dpdk.org, rosen.xu@intel.com, tianfei.zhang@intel.com, qi.z.zhang@intel.com, Wei Huang Subject: [PATCH v1 2/2] raw/ifpga: update secure rsu Date: Tue, 24 May 2022 21:51:23 -0400 Message-Id: <1653443483-30971-3-git-send-email-wei.huang@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1653443483-30971-1-git-send-email-wei.huang@intel.com> References: <1653443483-30971-1-git-send-email-wei.huang@intel.com> X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Update secure RSU (Remote System Update) driver to adapt the changes introduced by OFS. Signed-off-by: Wei Huang Acked-by: Tianfei Zhang --- drivers/raw/ifpga/base/ifpga_api.c | 39 +- drivers/raw/ifpga/base/ifpga_feature_dev.h | 2 + drivers/raw/ifpga/base/ifpga_fme.c | 8 + drivers/raw/ifpga/base/ifpga_fme_rsu.c | 546 ++++++++----- drivers/raw/ifpga/base/ifpga_sec_mgr.c | 1156 ++++++++++++++++++++-------- drivers/raw/ifpga/base/ifpga_sec_mgr.h | 115 ++- drivers/raw/ifpga/base/opae_hw_api.c | 84 +- drivers/raw/ifpga/base/opae_hw_api.h | 14 +- drivers/raw/ifpga/rte_pmd_ifpga.c | 104 ++- drivers/raw/ifpga/rte_pmd_ifpga.h | 117 +++ drivers/raw/ifpga/version.map | 11 + 11 files changed, 1649 insertions(+), 547 deletions(-) diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c index f19cc26..c187f94 100644 --- a/drivers/raw/ifpga/base/ifpga_api.c +++ b/drivers/raw/ifpga/base/ifpga_api.c @@ -261,11 +261,42 @@ static int ifpga_mgr_stop_flash_update(struct opae_manager *mgr, int force) return fpga_stop_flash_update(fme, force); } -static int ifpga_mgr_reload(struct opae_manager *mgr, int type, int page) +static int ifpga_mgr_reload(struct opae_manager *mgr, char *str) { struct ifpga_fme_hw *fme = mgr->data; - return fpga_reload(fme, type, page); + return fpga_reload(fme, str); +} + +static int ifpga_available_images(struct opae_manager *mgr, char *buf, + size_t size) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fpga_available_images(fme, buf, size); +} + +static int ifpga_mgr_set_poc_image(struct opae_manager *mgr, char *str) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fpga_set_poc_image(fme, str); +} + +static int ifpga_mgr_get_poc_images(struct opae_manager *mgr, char *buf, + size_t size) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fpga_get_poc_images(fme, buf, size); +} + +static int ifpga_mgr_read_flash(struct opae_manager *mgr, u32 address, + u32 size, void *buf) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_read_flash(fme, address, size, buf); } struct opae_manager_ops ifpga_mgr_ops = { @@ -277,6 +308,10 @@ struct opae_manager_ops ifpga_mgr_ops = { .update_flash = ifpga_mgr_update_flash, .stop_flash_update = ifpga_mgr_stop_flash_update, .reload = ifpga_mgr_reload, + .available_images = ifpga_available_images, + .get_poc_images = ifpga_mgr_get_poc_images, + .set_poc_image = ifpga_mgr_set_poc_image, + .read_flash = ifpga_mgr_read_flash }; static int ifpga_mgr_read_mac_rom(struct opae_manager *mgr, int offset, diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.h b/drivers/raw/ifpga/base/ifpga_feature_dev.h index a637eb5..7a2f2e5 100644 --- a/drivers/raw/ifpga/base/ifpga_feature_dev.h +++ b/drivers/raw/ifpga/base/ifpga_feature_dev.h @@ -223,4 +223,6 @@ int fme_mgr_get_retimer_status(struct ifpga_fme_hw *fme, int fme_mgr_get_sensor_value(struct ifpga_fme_hw *fme, struct opae_sensor_info *sensor, unsigned int *value); +int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address, + u32 size, void *buf); #endif /* _IFPGA_FEATURE_DEV_H_ */ diff --git a/drivers/raw/ifpga/base/ifpga_fme.c b/drivers/raw/ifpga/base/ifpga_fme.c index 1b9a922..1f54680 100644 --- a/drivers/raw/ifpga/base/ifpga_fme.c +++ b/drivers/raw/ifpga/base/ifpga_fme.c @@ -1658,3 +1658,11 @@ struct ifpga_feature_ops fme_pmci_ops = { .init = fme_pmci_init, .uinit = fme_pmci_uinit, }; + +int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address, + u32 size, void *buf) +{ + struct intel_max10_device *max10 = fme->max10_dev; + + return opae_read_flash(max10, address, size, buf); +} diff --git a/drivers/raw/ifpga/base/ifpga_fme_rsu.c b/drivers/raw/ifpga/base/ifpga_fme_rsu.c index f147aaa..88a19fa 100644 --- a/drivers/raw/ifpga/base/ifpga_fme_rsu.c +++ b/drivers/raw/ifpga/base/ifpga_fme_rsu.c @@ -9,6 +9,28 @@ static struct ifpga_sec_mgr *sec_mgr; +static void lock(struct ifpga_sec_mgr *smgr) +{ + struct ifpga_hw *hw = NULL; + + if (smgr && smgr->fme) { + hw = (struct ifpga_hw *)smgr->fme->parent; + if (hw) + opae_adapter_lock(hw->adapter, -1); + } +} + +static void unlock(struct ifpga_sec_mgr *smgr) +{ + struct ifpga_hw *hw = NULL; + + if (smgr && smgr->fme) { + hw = (struct ifpga_hw *)smgr->fme->parent; + if (hw) + opae_adapter_unlock(hw->adapter); + } +} + static void set_rsu_control(struct ifpga_sec_mgr *smgr, uint32_t ctrl) { if (smgr && smgr->rsu_control) @@ -22,6 +44,16 @@ static uint32_t get_rsu_control(struct ifpga_sec_mgr *smgr) return 0; } +static void cancel_rsu(struct ifpga_sec_mgr *smgr) +{ + uint32_t ctrl = IFPGA_RSU_CANCEL; + + lock(smgr); + ctrl |= get_rsu_control(smgr); + set_rsu_control(smgr, ctrl); + unlock(smgr); +} + static void set_rsu_status(struct ifpga_sec_mgr *smgr, uint32_t status, uint32_t progress) { @@ -40,6 +72,26 @@ static void get_rsu_status(struct ifpga_sec_mgr *smgr, uint32_t *status, } } +static void update_rsu_stat(struct ifpga_sec_mgr *smgr, uint32_t stat) +{ + uint32_t prog = 0; + + lock(smgr); + get_rsu_status(smgr, NULL, &prog); + set_rsu_status(smgr, stat, prog); + unlock(smgr); +} + +static void update_rsu_prog(struct ifpga_sec_mgr *smgr, uint32_t prog) +{ + uint32_t stat = 0; + + lock(smgr); + get_rsu_status(smgr, &stat, NULL); + set_rsu_status(smgr, stat, prog); + unlock(smgr); +} + static void sig_handler(int sig, siginfo_t *info, void *data) { (void)(info); @@ -50,7 +102,7 @@ static void sig_handler(int sig, siginfo_t *info, void *data) if (sec_mgr) { dev_info(sec_mgr, "Interrupt secure flash update" " by keyboard\n"); - set_rsu_control(sec_mgr, IFPGA_RSU_ABORT); + cancel_rsu(sec_mgr); } break; default: @@ -77,149 +129,152 @@ static void log_time(time_t t, const char *msg) printf("%s - %02u:%02u:%02u\n", msg, h, m, s); } -static int start_flash_update(struct ifpga_sec_mgr *smgr) +static enum ifpga_sec_err fpga_sec_dev_prepare(struct ifpga_sec_mgr *smgr) { if (!smgr) - return -ENODEV; + return IFPGA_SEC_ERR_HW_ERROR; - if (!smgr->ops || !smgr->ops->prepare) - return -EINVAL; + if (!smgr->sops || !smgr->sops->prepare) + return IFPGA_SEC_ERR_NO_FUNC; + + return smgr->sops->prepare(smgr); +} + +static int fill_buf(int fd, uint32_t offset, void *buf, uint32_t size) +{ + ssize_t read_size = 0; + + if (lseek(fd, offset, SEEK_SET) < 0) + return -EIO; + + read_size = read(fd, buf, size); + if (read_size < 0) + return -EIO; - return smgr->ops->prepare(smgr); + if ((uint32_t)read_size != size) { + dev_err(smgr, + "Read length %zd is not expected [e:%u]\n", + read_size, size); + return -EIO; + } + + return 0; } -static int write_flash_image(struct ifpga_sec_mgr *smgr, const char *image, - uint32_t offset) +static enum ifpga_sec_err fpga_sec_dev_write(struct ifpga_sec_mgr *smgr) { void *buf = NULL; - int retry = 0; - uint32_t length = 0; - uint32_t to_transfer = 0; - uint32_t one_percent = 0; + int fd = -1; + uint32_t blk_size = 0; + uint32_t offset = 0; uint32_t prog = 0; uint32_t old_prog = -1; - ssize_t read_size = 0; - int fd = -1; - int ret = 0; + enum ifpga_sec_err ret = 0; if (!smgr) - return -ENODEV; + return IFPGA_SEC_ERR_HW_ERROR; - if (!smgr->ops || !smgr->ops->write_blk) - return -EINVAL; + if (!smgr->sops || !smgr->sops->write_blk) + return IFPGA_SEC_ERR_NO_FUNC; + + buf = malloc(IFPGA_RSU_DATA_BLK_SIZE); + if (!buf) { + dev_err(smgr, "Failed to allocate memory for flash update\n"); + return IFPGA_SEC_ERR_NO_MEM; + } + smgr->data = buf; - fd = open(image, O_RDONLY); + fd = open(smgr->filename, O_RDONLY); if (fd < 0) { dev_err(smgr, "Failed to open \'%s\' for RD [e:%s]\n", - image, strerror(errno)); - return -EIO; + smgr->filename, strerror(errno)); + return IFPGA_SEC_ERR_FILE_READ; } - buf = malloc(IFPGA_RSU_DATA_BLK_SIZE); - if (!buf) { - dev_err(smgr, "Failed to allocate memory for flash update\n"); - close(fd); - return -ENOMEM; - } - - length = smgr->rsu_length; - one_percent = length / 100; - do { - to_transfer = (length > IFPGA_RSU_DATA_BLK_SIZE) ? - IFPGA_RSU_DATA_BLK_SIZE : length; - if (lseek(fd, offset, SEEK_SET) < 0) { - dev_err(smgr, "Failed to seek in \'%s\' [e:%s]\n", - image, strerror(errno)); - ret = -EIO; - goto end; - } - read_size = read(fd, buf, to_transfer); - if (read_size < 0) { - dev_err(smgr, "Failed to read from \'%s\' [e:%s]\n", - image, strerror(errno)); - ret = -EIO; - goto end; - } - if ((uint32_t)read_size != to_transfer) { - dev_err(smgr, - "Read length %zd is not expected [e:%u]\n", - read_size, to_transfer); - ret = -EIO; - goto end; + while (smgr->remaining_size) { + if (get_rsu_control(smgr) & IFPGA_RSU_CANCEL) { + ret = IFPGA_SEC_ERR_CANCELED; + break; } - retry = 0; - do { - if (get_rsu_control(smgr) == IFPGA_RSU_ABORT) { - ret = -EAGAIN; - goto end; - } - ret = smgr->ops->write_blk(smgr, buf, offset, - to_transfer); - if (ret == 0) - break; - sleep(1); - } while (++retry <= IFPGA_RSU_WRITE_RETRY); - if (retry > IFPGA_RSU_WRITE_RETRY) { - dev_err(smgr, "Failed to write to staging area 0x%x\n", - offset); - ret = -EAGAIN; - goto end; + blk_size = (smgr->remaining_size > IFPGA_RSU_DATA_BLK_SIZE) ? + IFPGA_RSU_DATA_BLK_SIZE : smgr->remaining_size; + if (fill_buf(fd, offset, buf, blk_size)) { + ret = IFPGA_SEC_ERR_FILE_READ; + break; } - length -= to_transfer; - offset += to_transfer; - prog = offset / one_percent; + ret = smgr->sops->write_blk(smgr, offset, blk_size); + if (ret != IFPGA_SEC_ERR_NONE) + break; + + smgr->remaining_size -= blk_size; + offset += blk_size; + + /* output progress percent */ + prog = offset / smgr->one_percent; if (prog != old_prog) { printf("\r%d%%", prog); fflush(stdout); - set_rsu_status(smgr, IFPGA_RSU_READY, prog); + update_rsu_prog(smgr, prog); old_prog = prog; } - } while (length > 0); - set_rsu_status(smgr, IFPGA_RSU_READY, 100); - printf("\n"); + } + + if (ret == IFPGA_SEC_ERR_NONE) { + update_rsu_prog(smgr, 100); + printf("\r100%%\n"); + } else { + printf("\n"); + } -end: - free(buf); close(fd); + smgr->data = NULL; + free(buf); return ret; } -static int apply_flash_update(struct ifpga_sec_mgr *smgr) +static enum ifpga_sec_err fpga_sec_dev_poll_complete(struct ifpga_sec_mgr *smgr) { - uint32_t one_percent = 0; uint32_t one_percent_time = 0; uint32_t prog = 0; uint32_t old_prog = -1; uint32_t copy_time = 0; - int ret = 0; + int timeout = 2400; /* 2400 seconds */ + enum ifpga_sec_err ret = 0; if (!smgr) - return -ENODEV; + return IFPGA_SEC_ERR_HW_ERROR; - if (!smgr->ops || !smgr->ops->write_done || !smgr->ops->check_complete) - return -EINVAL; + if (!smgr->sops || !smgr->sops->write_done || + !smgr->sops->check_complete) + return IFPGA_SEC_ERR_NO_FUNC; - if (smgr->ops->write_done(smgr) < 0) { + if (smgr->sops->write_done(smgr) != IFPGA_SEC_ERR_NONE) { dev_err(smgr, "Failed to apply flash update\n"); - return -EAGAIN; + return IFPGA_SEC_ERR_HW_ERROR; } - one_percent = (smgr->rsu_length + 99) / 100; + /* calculate time period of one percent */ if (smgr->copy_speed == 0) /* avoid zero divide fault */ smgr->copy_speed = 1; - one_percent_time = (one_percent + smgr->copy_speed - 1) / + one_percent_time = (smgr->one_percent + smgr->copy_speed) / smgr->copy_speed; if (one_percent_time == 0) /* avoid zero divide fault */ one_percent_time = 1; - do { - ret = smgr->ops->check_complete(smgr); - if (ret != -EAGAIN) - break; + while (true) { sleep(1); + ret = smgr->sops->check_complete(smgr); + if (ret != IFPGA_SEC_ERR_BUSY) + break; + if (--timeout < 0) { + ret = IFPGA_SEC_ERR_TIMEOUT; + break; + } + + /* output progress percent */ copy_time += 1; prog = copy_time / one_percent_time; if (prog >= 100) @@ -227,96 +282,90 @@ static int apply_flash_update(struct ifpga_sec_mgr *smgr) if (prog != old_prog) { printf("\r%d%%", prog); fflush(stdout); - set_rsu_status(smgr, IFPGA_RSU_COPYING, prog); + update_rsu_prog(smgr, prog); old_prog = prog; } - } while (true); + } - if (ret < 0) { - printf("\n"); - dev_err(smgr, "Failed to complete secure flash update\n"); - } else { + if (ret == IFPGA_SEC_ERR_NONE) { + update_rsu_prog(smgr, 100); printf("\r100%%\n"); - set_rsu_status(smgr, IFPGA_RSU_COPYING, 100); + } else { + printf("\n"); } return ret; } -static int secure_update_cancel(struct ifpga_sec_mgr *smgr) +static enum ifpga_sec_err fpga_sec_dev_cancel(struct ifpga_sec_mgr *smgr) { if (!smgr) - return -ENODEV; + return IFPGA_SEC_ERR_HW_ERROR; - if (!smgr->ops || !smgr->ops->cancel) - return -EINVAL; + if (!smgr->sops || !smgr->sops->cancel) + return IFPGA_SEC_ERR_NO_FUNC; - return smgr->ops->cancel(smgr); + return smgr->sops->cancel(smgr); } -static int secure_update_status(struct ifpga_sec_mgr *smgr, uint64_t *status) +static void set_error(struct ifpga_sec_mgr *smgr, enum ifpga_sec_err err_code) { - if (!smgr) - return -ENODEV; + uint32_t stat = 0; - if (!smgr->ops || !smgr->ops->get_hw_errinfo) - return -EINVAL; + lock(smgr); + get_rsu_status(smgr, &stat, NULL); + set_rsu_status(smgr, stat, stat); + smgr->err_code = err_code; + unlock(smgr); +} - if (status) - *status = smgr->ops->get_hw_errinfo(smgr); +static int progress_transition(struct ifpga_sec_mgr *smgr, + uint32_t new_progress) +{ + if (get_rsu_control(smgr) & IFPGA_RSU_CANCEL) { + set_error(smgr, IFPGA_SEC_ERR_CANCELED); + smgr->sops->cancel(smgr); + return -ECANCELED; + } + set_rsu_status(smgr, new_progress, 0); return 0; } -int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image, - uint64_t *status) +static void progress_complete(struct ifpga_sec_mgr *smgr) +{ + update_rsu_stat(smgr, IFPGA_RSU_IDLE); +} + +static void fpga_sec_dev_error(struct ifpga_sec_mgr *smgr, + enum ifpga_sec_err err_code) +{ + set_error(smgr, err_code); + if (smgr->sops->get_hw_errinfo) + smgr->hw_errinfo = smgr->sops->get_hw_errinfo(smgr); + if (smgr->sops->cancel) + smgr->sops->cancel(smgr); +} + +static int fpga_sec_mgr_update(struct ifpga_sec_mgr *smgr) { - struct ifpga_hw *hw = NULL; - struct ifpga_sec_mgr *smgr = NULL; - uint32_t rsu_stat = 0; int fd = -1; off_t len = 0; struct sigaction old_sigint_action; struct sigaction sa; time_t start; - int ret = 0; + enum ifpga_sec_err ret = 0; - if (!fme || !image || !status) { - dev_err(fme, "Input parameter of %s is invalid\n", __func__); + if (!smgr) { + dev_err(smgr, "Input parameter of %s is invalid\n", __func__); return -EINVAL; } - hw = (struct ifpga_hw *)fme->parent; - if (!hw) { - dev_err(fme, "Parent of FME not found\n"); - return -ENODEV; - } - - smgr = (struct ifpga_sec_mgr *)fme->sec_mgr; - if (!smgr || !smgr->max10_dev) { - dev_err(smgr, "Security manager not initialized\n"); - return -ENODEV; - } - - opae_adapter_lock(hw->adapter, -1); - get_rsu_status(smgr, &rsu_stat, NULL); - if (rsu_stat != IFPGA_RSU_IDLE) { - opae_adapter_unlock(hw->adapter); - if (rsu_stat == IFPGA_RSU_REBOOT) - dev_info(smgr, "Reboot is in progress\n"); - else - dev_info(smgr, "Update is in progress\n"); - return -EAGAIN; - } - set_rsu_control(smgr, 0); - set_rsu_status(smgr, IFPGA_RSU_PREPARE, 0); - opae_adapter_unlock(hw->adapter); - - fd = open(image, O_RDONLY); + fd = open(smgr->filename, O_RDONLY); if (fd < 0) { dev_err(smgr, "Failed to open \'%s\' for RD [e:%s]\n", - image, strerror(errno)); + smgr->filename, strerror(errno)); return -EIO; } len = lseek(fd, 0, SEEK_END); @@ -325,25 +374,22 @@ int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image, if (len < 0) { dev_err(smgr, "Failed to get file length of \'%s\' [e:%s]\n", - image, strerror(errno)); + smgr->filename, strerror(errno)); return -EIO; } if (len == 0) { - dev_err(smgr, "Length of file \'%s\' is invalid\n", image); - return -EINVAL; - } - smgr->rsu_length = len; - - if (smgr->max10_dev->staging_area_size < smgr->rsu_length) { - dev_err(dev, "Size of staging area is small than image length " - "[%u<%u]\n", smgr->max10_dev->staging_area_size, - smgr->rsu_length); + dev_err(smgr, "Length of file \'%s\' is invalid\n", + smgr->filename); + set_error(smgr, IFPGA_SEC_ERR_INVALID_SIZE); return -EINVAL; } + smgr->remaining_size = len; + smgr->one_percent = smgr->remaining_size / 100; printf("Updating from file \'%s\' with size %u\n", - image, smgr->rsu_length); + smgr->filename, smgr->remaining_size); + /* setup signal handler */ sec_mgr = smgr; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_flags = SA_SIGINFO | SA_RESETHAND; @@ -354,39 +400,106 @@ int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image, " [e:%d]\n", ret); sec_mgr = NULL; } - start = time(NULL); + log_time(time(NULL) - start, "Starting secure flash update"); - ret = start_flash_update(smgr); - if (ret < 0) - goto end; + if (progress_transition(smgr, IFPGA_RSU_PREPARING)) { + ret = smgr->err_code; + goto exit; + } + + ret = fpga_sec_dev_prepare(smgr); + if (ret != IFPGA_SEC_ERR_NONE) { + fpga_sec_dev_error(smgr, ret); + goto exit; + } - set_rsu_status(smgr, IFPGA_RSU_READY, 0); log_time(time(NULL) - start, "Writing to staging area"); - ret = write_flash_image(smgr, image, 0); - if (ret < 0) - goto end; + if (progress_transition(smgr, IFPGA_RSU_WRITING)) { + ret = smgr->err_code; + goto done; + } + + ret = fpga_sec_dev_write(smgr); + if (ret != IFPGA_SEC_ERR_NONE) { + fpga_sec_dev_error(smgr, ret); + goto done; + } - set_rsu_status(smgr, IFPGA_RSU_COPYING, 0); log_time(time(NULL) - start, "Applying secure flash update"); - ret = apply_flash_update(smgr); + if (progress_transition(smgr, IFPGA_RSU_PROGRAMMING)) { + ret = smgr->err_code; + goto done; + } + + ret = fpga_sec_dev_poll_complete(smgr); + if (ret != IFPGA_SEC_ERR_NONE) + fpga_sec_dev_error(smgr, ret); + +done: + if (smgr->sops->cleanup) + smgr->sops->cleanup(smgr); + +exit: + if (ret != IFPGA_SEC_ERR_NONE) + log_time(time(NULL) - start, "Secure flash update ERROR"); + else + log_time(time(NULL) - start, "Secure flash update OK"); -end: if (sec_mgr) { sec_mgr = NULL; if (sigaction(SIGINT, &old_sigint_action, NULL) < 0) dev_err(smgr, "Failed to unregister signal handler\n"); } - secure_update_status(smgr, status); - if (ret < 0) { - log_time(time(NULL) - start, "Secure flash update ERROR"); - if (ret == -EAGAIN) - secure_update_cancel(smgr); - } else { - log_time(time(NULL) - start, "Secure flash update OK"); + progress_complete(smgr); + + dev_info(smgr, "Return %d\n", ret); + return ret == IFPGA_SEC_ERR_NONE ? 0 : -1; +} + +int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image, + uint64_t *status) +{ + struct ifpga_sec_mgr *smgr = NULL; + uint32_t rsu_stat = 0; + int ret = 0; + + if (!fme || !image || !status) { + dev_err(fme, "Input parameter of %s is invalid\n", __func__); + return -EINVAL; + } + + smgr = (struct ifpga_sec_mgr *)fme->sec_mgr; + if (!smgr) { + dev_err(smgr, "Security manager not initialized\n"); + return -ENODEV; + } + if (!smgr->sops) { + dev_err(smgr, "Security manager not support flash update\n"); + return -EOPNOTSUPP; + } + + lock(smgr); + get_rsu_status(smgr, &rsu_stat, NULL); + if (rsu_stat != IFPGA_RSU_IDLE) { + unlock(smgr); + if (rsu_stat == IFPGA_RSU_REBOOT) + dev_info(smgr, "Reboot is in progress\n"); + else + dev_info(smgr, "Update is in progress\n"); + return -EAGAIN; } - set_rsu_status(smgr, IFPGA_RSU_IDLE, 0); + set_rsu_control(smgr, 0); + set_rsu_status(smgr, IFPGA_RSU_PREPARING, 0); + + smgr->filename = image; + smgr->err_code = IFPGA_SEC_ERR_NONE; + smgr->hw_errinfo = 0; + unlock(smgr); + + ret = fpga_sec_mgr_update(smgr); + *status = smgr->hw_errinfo; return ret; } @@ -407,7 +520,7 @@ int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force) get_rsu_status(smgr, &status, NULL); if (status != IFPGA_RSU_IDLE) { dev_info(smgr, "Cancel secure flash update\n"); - set_rsu_control(smgr, IFPGA_RSU_ABORT); + cancel_rsu(smgr); } if (force) { @@ -416,8 +529,8 @@ int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force) get_rsu_status(smgr, &status, NULL); if (status == IFPGA_RSU_IDLE) break; - if (secure_update_cancel(smgr) == 0) - set_rsu_status(smgr, IFPGA_RSU_IDLE, 0); + if (fpga_sec_dev_cancel(smgr) == IFPGA_SEC_ERR_NONE) + update_rsu_stat(smgr, IFPGA_RSU_IDLE); sleep(1); } while (--retry > 0); if (retry <= 0) { @@ -429,9 +542,11 @@ int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force) return ret; } -int fpga_reload(struct ifpga_fme_hw *fme, int type, int page) +int fpga_reload(struct ifpga_fme_hw *fme, char *str) { struct ifpga_sec_mgr *smgr = NULL; + const struct image_load *hndlr = NULL; + int ret = -EOPNOTSUPP; if (!fme) { dev_err(fme, "Input parameter of %s is invalid\n", __func__); @@ -439,8 +554,73 @@ int fpga_reload(struct ifpga_fme_hw *fme, int type, int page) } smgr = (struct ifpga_sec_mgr *)fme->sec_mgr; - if (!smgr || !smgr->ops || !smgr->ops->reload) + if (!smgr) + return -ENODEV; + + if (!smgr->sops || !smgr->sops->image_load) + return -EOPNOTSUPP; + + for (hndlr = smgr->sops->image_load; hndlr->name; hndlr++) { + if (!strcmp(str, hndlr->name)) { + ret = hndlr->load_image(smgr); + break; + } + } + + return ret; +} + +int fpga_available_images(struct ifpga_fme_hw *fme, char *buf, size_t size) +{ + struct ifpga_sec_mgr *smgr = NULL; + const struct image_load *hndlr = NULL; + size_t count = 0; + + if (!fme) { + dev_err(fme, "Input parameter of %s is invalid\n", __func__); return -EINVAL; + } + smgr = (struct ifpga_sec_mgr *)fme->sec_mgr; + + if (!smgr) + return -ENODEV; + + if (!smgr->sops || !smgr->sops->image_load) + return 0; + + if (buf) { + for (hndlr = smgr->sops->image_load; hndlr->name; hndlr++) { + if ((size > count) && + ((size - count) > strlen(hndlr->name))) { + count += snprintf(buf + count, size - count, + "%s ", hndlr->name); + } + } + buf[count - 1] = '\0'; + } else { + for (hndlr = smgr->sops->image_load; hndlr->name; hndlr++) + count += strlen(hndlr->name) + 1; + } + + return count; +} + +int fpga_set_poc_image(struct ifpga_fme_hw *fme, char *buf) +{ + struct ifpga_sec_mgr *smgr = (struct ifpga_sec_mgr *)fme->sec_mgr; + + if (!smgr) + return -ENODEV; + + return pmci_set_poc_image(smgr, buf); +} + +int fpga_get_poc_images(struct ifpga_fme_hw *fme, char *buf, size_t size) +{ + struct ifpga_sec_mgr *smgr = (struct ifpga_sec_mgr *)fme->sec_mgr; + + if (!smgr) + return -ENODEV; - return smgr->ops->reload(smgr, type, page); + return pmci_get_poc_images(smgr, buf, size); } diff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.c b/drivers/raw/ifpga/base/ifpga_sec_mgr.c index 557c4e3..3250da1 100644 --- a/drivers/raw/ifpga/base/ifpga_sec_mgr.c +++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.c @@ -4,9 +4,128 @@ #include #include +#include #include #include "ifpga_sec_mgr.h" +#include "opae_intel_max10.h" +#include "opae_osdep.h" + +static const char * const rsu_stat_string[] = { + [SEC_STATUS_NORMAL] = "Initial normal status", + [SEC_STATUS_TIMEOUT] = "Host timeout", + [SEC_STATUS_AUTH_FAIL] = "Authentication failure", + [SEC_STATUS_COPY_FAIL] = "Image copy failure", + [SEC_STATUS_FATAL] = "Fatal error, Nios boot-up failure", + [SEC_STATUS_PKVL_REJECT] = "pkvl reject", + [SEC_STATUS_NON_INC] = "Staging area non-incremental write fail", + [SEC_STATUS_ERASE_FAIL] = "Staging area erase fail", + [SEC_STATUS_WEAROUT] = "Staging area write wearout", + [SEC_STATUS_PMCI_SS_FAIL] = "PMCI SS Access fail", + [SEC_STATUS_FLASH_CMD] = "Unsupported flash command", + [SEC_STATUS_FACTORY_UNVERITY] = "factory image is unverified", + [SEC_STATUS_FACTORY_ACTIVE] = "current active image is factory", + [SEC_STATUS_POWER_DOWN] = "FPGA/Board powered down", + [SEC_STATUS_CANCELLATION] = "Cancellation not supported", + [SEC_STATUS_HASH] = "Hash Programming not supported", + [SEC_STATUS_FLASH_ACCESS] = "FPGA Flash Access Error", + [SEC_STATUS_SDM_PR_CERT] = "PR: cert not programmed to SDM", + [SEC_STATUS_SDM_PR_NIOS_BUSY] = "PR: Nios Busy waiting for SDM", + [SEC_STATUS_SDM_PR_TIMEOUT] = "PR: SDM Response timed out", + [SEC_STATUS_SDM_PR_FAILED] = "PR Key Hash program failed", + [SEC_STATUS_SDM_PR_MISMATCH] = "PR: SDM Response mismatched", + [SEC_STATUS_SDM_PR_FLUSH] = "PR: SDM Buffer Flushing failed", + [SEC_STATUS_SDM_SR_CERT] = "SR: cert is not programmed to SDM", + [SEC_STATUS_SDM_SR_NIOS_BUSY] = "SR: Nios Busy waiting for SDM", + [SEC_STATUS_SDM_SR_TIMEOUT] = "SR: SDM Response timed out", + [SEC_STATUS_SDM_SR_FAILED] = "SR Key Hash program failed", + [SEC_STATUS_SDM_SR_MISMATCH] = "SR: SDM Response mismatched", + [SEC_STATUS_SDM_SR_FLUSH] = "SR: SDM Buffer Flushing failed", + [SEC_STATUS_SDM_KEY_CERT] = "KEY: cert is not programmed to SDM", + [SEC_STATUS_SDM_KEY_NIOS_BUSY] = "KEY: Nios Busy waiting for SDM", + [SEC_STATUS_SDM_KEY_TIMEOUT] = "KEY: SDM Response timed out", + [SEC_STATUS_SDM_KEY_FAILED] = "KEY: Key Hash program failed", + [SEC_STATUS_SDM_KEY_MISMATCH] = "KEY: SDM Response mismatched", + [SEC_STATUS_SDM_KEY_FLUSH] = "KEY: SDM Buffer Flushing failed", + [SEC_STATUS_USER_FAIL] = "Update Failure", + [SEC_STATUS_FACTORY_FAIL] = "Factory Failure", + [SEC_STATUS_NIOS_FLASH_ERR] = "NIOS Flash Open Error", + [SEC_STATUS_FPGA_FLASH_ERR] = "FPGA Flash Open Error", +}; + +static const char * const auth_stat_string[] = { + [AUTH_STAT_PASS] = "Authenticate Pass", + [AUTH_STAT_B0_MAGIC] = "Block0 Magic value error", + [AUTH_STAT_CONLEN] = "Block0 ConLen error", + [AUTH_STAT_CONTYPE] = "Block0 ConType B[7:0] > 2", + [AUTH_STAT_B1_MAGIC] = "Block1 Magic value error", + [AUTH_STAT_ROOT_MAGIC] = "Root Entry Magic value error", + [AUTH_STAT_CURVE_MAGIC] = "Root Entry Curve Magic value error", + [AUTH_STAT_PERMISSION] = "Root Entry Permission error", + [AUTH_STAT_KEY_ID] = "Root Entry Key ID error", + [AUTH_STAT_CSK_MAGIC] = "CSK Entry Magic value error", + [AUTH_STAT_CSK_CURVE] = "CSK Entry Curve Magic value error", + [AUTH_STAT_CSK_PERMISSION] = "CSK Entry Permission error", + [AUTH_STAT_CSK_ID] = "CSK Entry Key ID error", + [AUTH_STAT_CSK_SM] = "CSK Entry Signature Magic value error", + [AUTH_STAT_B0_E_MAGIC] = "Block0 Entry Magic value error", + [AUTH_STAT_B0_E_SIGN] = "Block0 Entry Signature Magic value error", + [AUTH_STAT_RK_P] = "Root Key Hash not programmed for RSU", + [AUTH_STAT_RE_SHA] = "Root Entry verify SHA failed", + [AUTH_STAT_CSK_SHA] = "CSK Entry verify ECDSA and SHA failed", + [AUTH_STAT_B0_SHA] = "Block0 Entry verify ECDSA and SHA failed", + [AUTH_STAT_KEY_INV] = "KEY ID of authenticate blob is invalid", + [AUTH_STAT_KEY_CAN] = "KEY ID is cancelled", + [AUTH_STAT_UP_SHA] = "Update content SHA verify failed", + [AUTH_STAT_CAN_SHA] = "Cancellation content SHA verify failed", + [AUTH_STAT_HASH] = "HASH Programming content SHA verify failed", + [AUTH_STAT_INV_ID] = "Invalid cancellation ID of cancellation cert", + [AUTH_STAT_KEY_PROG] = "KEY hash programmed for KEY hash programming cert", + [AUTH_STAT_INV_BC] = "Invalid operation of Block0 ConType", + [AUTH_STAT_INV_SLOT] = "Invalid slot in Block0 ConType", + [AUTH_STAT_IN_OP] = "Incompatible operation of Block0 ConType", + [AUTH_STAT_TIME_OUT] = "Flash transfer to staging area timed out", + [AUTH_STAT_SHA_TO] = "Root Entry verify SHA timeout", + [AUTH_STAT_CSK_TO] = "CSK Entry verify ECDSA and SHA timeout", + [AUTH_STAT_B0_TO] = "Block0 Entry verify ECDSA and SHA timeout", + [AUTH_STAT_UP_TO] = "Update content SHA verify timeout", + [AUTH_STAT_CAN_TO] = "Cancellation content SHA verify timeout", + [AUTH_STAT_HASH_TO] = "HASH Programming content SHA verify timeout", + [AUTH_STAT_AUTH_IDLE] = "Authentication engine Idle", + [AUTH_STAT_GA_FAIL] = "Generic Authentication Failure", + [AUTH_STAT_S_ERR] = "Sensor Blob Generic Error", + [AUTH_STAT_S_MN] = "Sensor Blob Magic number error", + [AUTH_STAT_SH_CRC] = "Sensor Blob Header CRC error", + [AUTH_STAT_SD_CRC] = "Sensor Blob Data CRC error", + [AUTH_STAT_SD_LEN] = "Sensor Blob Data Length error", + [AUTH_STAT_S_ID] = "Sensor Blob Sensor ID not supported", + [AUTH_STAT_S_THR] = "Sensor Blob Invalid threshold type", + [AUTH_STAT_S_TO] = "Sensor Blob threshold out of bounds", + [AUTH_STAT_S_EN] = "Sensor Blob exceeds number of sensor count", + [AUTH_STAT_SF] = "only FPGA thermal Sensor Thresholds are allowed", +}; +static const char * const sdm_stat_string[] = { + [SDM_STAT_DONE] = "SR Key Hash program successful", + [SDM_STAT_PROV] = "ignored,SR Hash is already provisioned to SDM", + [SDM_STAT_BUSY] = "Ignored; Configuration Module Busy", + [SDM_STAT_INV] = "Invalid configuration Status from Configuration", + [SDM_STAT_FAIL] = "SDM Flush Buffer failed", + [SDM_STAT_BMC_BUSY] = "BMC Busy waiting for another SDM command response", + [SDM_STAT_TO] = "SDM Response timed out during SDM Provisioning", + [SDM_STAT_DB] = "SDM device busy during SDM Provisioning", + [SDM_STAT_CON_R] = "Config Status retry count exceeded", + [SDM_STAT_CON_E] = "Config status command returned error", + [SDM_STAT_WAIT] = "BMC Busy waiting for another SDM command response", + [SDM_STAT_RTO] = "timed out during PUBKEY_PROGRAM command to SDM", + [SDM_STAT_SB] = "busy during PUBKEY_PROGRAM command to SDM", + [SDM_STAT_RE] = "SR Key Hash program failed with recoverable error", + [SDM_STAT_PDD] = "SR Key Hash program failed permanent device damage", + [SDM_STAT_ISC] = "SR Key program failed by invalid SDM command", + [SDM_STAT_SIC] = "SDM Congiguration failed by Shell Image configured", + [SDM_STAT_NO_PROV] = "SR Key Hash not provisioned to BMC", + [SDM_STAT_CS_MIS] = "failed by SDM CONFIG_STATUS response mismatch", + [SDM_STAT_PR_MIS] = "failed by SDM PUBKEY_PROGRAM Response mismatch", +}; static const char * const rsu_prog[] = {"IDLE", "PREPARING", "SLEEPING", "READY", "AUTHENTICATING", "COPYING", "CANCELLATION", "PROGRAMMING_KEY", @@ -17,6 +136,160 @@ static const char * const rsu_stath[] = {"NIOS_OK", "USER_OK", "FACTORY_OK", "USER_FAIL", "FACTORY_FAIL", "NIOS_FLASH_ERR", "FPGA_FLASH_ERR"}; +static const char * const fpga_image_names[] = { + [FPGA_FACTORY] = "fpga_factory", + [FPGA_USER1] = "fpga_user1", + [FPGA_USER2] = "fpga_user2" +}; + +static enum fpga_image +fpga_image_by_name(char *image_name) +{ + enum fpga_image i; + + for (i = 0; i < FPGA_MAX; i++) + if (!strcmp(image_name, fpga_image_names[i])) + return i; + + return FPGA_MAX; +} + +static int +fpga_images(struct ifpga_sec_mgr *smgr, char *names, enum fpga_image images[]) +{ + u32 image_mask = smgr->poc->avail_image_mask; + enum fpga_image image; + char *image_name; + int i = 0; + + while ((image_name = strsep(&names, "\n"))) { + image = fpga_image_by_name(image_name); + if (image >= FPGA_MAX || !(image_mask & BIT(image))) + return -EINVAL; + + images[i++] = image; + image_mask &= ~BIT(image); + } + + return (i == 0) ? -EINVAL : 0; +} + +int pmci_set_poc_image(struct ifpga_sec_mgr *smgr, char *buf) +{ + enum fpga_image images[FPGA_MAX] = { [0 ... FPGA_MAX - 1] = FPGA_MAX }; + int ret; + + if (!smgr) + return -ENODEV; + + ret = fpga_images(smgr, buf, images); + if (ret) + return -EINVAL; + + return smgr->poc->set_sequence(smgr, images); +} + +int pmci_get_poc_images(struct ifpga_sec_mgr *smgr, char *buf, size_t size) +{ + if (!smgr) + return -ENODEV; + + return smgr->poc->get_sequence(smgr, buf, size); +} + +static int pmci_get_power_on_image(struct ifpga_sec_mgr *smgr, + char *buf, size_t size) +{ + const char *image_names[FPGA_MAX] = { 0 }; + int ret, i = 0; + int j; + u32 poc; + size_t count = 0; + + if (!smgr->max10_dev) + return -ENODEV; + + if (!buf) + return -EINVAL; + + ret = max10_sys_read(smgr->max10_dev, M10BMC_PMCI_FPGA_POC, &poc); + if (ret) + return ret; + + if (poc & PMCI_FACTORY_IMAGE_SEL) + image_names[i++] = fpga_image_names[FPGA_FACTORY]; + + if (GET_FIELD(PMCI_USER_IMAGE_PAGE, poc) == POC_USER_IMAGE_1) { + image_names[i++] = fpga_image_names[FPGA_USER1]; + image_names[i++] = fpga_image_names[FPGA_USER2]; + } else { + image_names[i++] = fpga_image_names[FPGA_USER2]; + image_names[i++] = fpga_image_names[FPGA_USER1]; + } + + if (!(poc & PMCI_FACTORY_IMAGE_SEL)) + image_names[i] = fpga_image_names[FPGA_FACTORY]; + + for (j = 0; j < FPGA_MAX; j++) { + if ((size > count) && + ((size - count) > strlen(image_names[j]))) + count += snprintf(buf + count, size - count, + "%s ", image_names[j]); + } + buf[count - 1] = '\0'; + + return count; +} + +static int +pmci_set_power_on_image(struct ifpga_sec_mgr *smgr, enum fpga_image images[]) +{ + struct intel_max10_device *dev = smgr->max10_dev; + u32 poc_mask = PMCI_FACTORY_IMAGE_SEL; + int ret, first_user = 0; + u32 poc = 0; + + if (!dev) + return -ENODEV; + + if (images[1] == FPGA_FACTORY) + return -EINVAL; + + if (images[0] == FPGA_FACTORY) { + poc = PMCI_FACTORY_IMAGE_SEL; + first_user = 1; + } + + if (images[first_user] == FPGA_USER1 || + images[first_user] == FPGA_USER2) { + poc_mask |= PMCI_USER_IMAGE_PAGE; + if (images[first_user] == FPGA_USER1) + poc |= SET_FIELD(PMCI_USER_IMAGE_PAGE, + POC_USER_IMAGE_1); + else + poc |= SET_FIELD(PMCI_USER_IMAGE_PAGE, + POC_USER_IMAGE_2); + } + + ret = max10_sys_update_bits(dev, + m10bmc_base(dev) + M10BMC_PMCI_FPGA_POC, + poc_mask | PMCI_FPGA_POC, poc | PMCI_FPGA_POC); + if (ret) + return ret; + + ret = opae_max10_read_poll_timeout(dev, + m10bmc_base(dev) + M10BMC_PMCI_FPGA_POC, + poc, + (!(poc & PMCI_FPGA_POC)), + IFPGA_NIOS_HANDSHAKE_INTERVAL_US, + IFPGA_NIOS_HANDSHAKE_TIMEOUT_US); + + if (ret || (GET_FIELD(PMCI_NIOS_STATUS, poc) != NIOS_STATUS_SUCCESS)) + return -EIO; + + return 0; +} + static const char *rsu_progress_name(uint32_t prog) { if (prog > SEC_PROGRESS_PKVL_PROM_DONE) @@ -40,377 +313,527 @@ static const char *rsu_status_name(uint32_t stat) } } -static bool secure_start_done(uint32_t doorbell) +static void print_sdm_status(struct intel_max10_device *dev) { - return (SEC_STATUS_G(doorbell) == SEC_STATUS_ERASE_FAIL || - SEC_STATUS_G(doorbell) == SEC_STATUS_WEAROUT || - (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_IDLE && - SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_RSU_DONE)); + u32 val, sdm_stat; + + const char *sdm_string; + + if (dev->type == M10_N6000) { + if (!max10_sys_read(dev, m10bmc_base(dev) + + M10BMC_PMCI_SDM_CTRL_STS, &val)) + dev_err(dev, "sdm ctrl reg: 0x%08x\n", val); + + sdm_stat = GET_FIELD(val, PMCI_SDM_STAT); + if (sdm_stat > SDM_STAT_MAX) + dev_err(dev, "unknown sdm stat: 0x%08x\n", sdm_stat); + + sdm_string = sdm_stat_string[sdm_stat]; + if (sdm_string) + dev_err(dev, "sdm stat: %s\n", sdm_string); + else + dev_err(dev, "unknown sdm stat\n"); + } } -static bool secure_prog_ready(uint32_t doorbell) +static void print_error_regs(struct intel_max10_device *dev) { - return (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY); + u32 auth_result, doorbell, rsu_stat, auth_stat; + + const char *rsu_string, *auth_string; + + if (!max10_sys_read(dev, doorbell_reg(dev), &doorbell)) + dev_err(dev, "RSU doorbell reg: 0x%08x\n", doorbell); + + if (!max10_sys_read(dev, auth_result_reg(dev), &auth_result)) + dev_err(dev, "RSU auth result reg: 0x%08x\n", auth_result); + + rsu_stat = SEC_STATUS_G(auth_result); + if (rsu_stat > SEC_STATUS_MAX) + dev_err(dev, "unknown rsu stat, error code exceed: 0x%08x\n", rsu_stat); + + rsu_string = rsu_stat_string[rsu_stat]; + if (rsu_string) + dev_err(dev, "rsu stat: %s\n", rsu_string); + else + dev_err(dev, "unknown rsu stat\n"); + + if (rsu_stat == SEC_STATUS_SDM_PR_FAILED || + rsu_stat == SEC_STATUS_SDM_SR_FAILED) + print_sdm_status(dev); + + auth_stat = SEC_AUTH_G(auth_result); + if (auth_stat > AUTH_STAT_MAX) + dev_err(dev, "unknown Authentication status, code exceed: 0x%08x\n", rsu_stat); + + auth_string = auth_stat_string[auth_stat]; + if (auth_string) + dev_err(dev, "auth stat: %s\n", auth_string); + else + dev_err(dev, "unknown auth stat\n"); } -static int poll_timeout(struct intel_max10_device *dev, uint32_t offset, - bool (*cond)(uint32_t), uint32_t interval_ms, uint32_t timeout_ms) +static bool rsu_status_ok(u32 status) { - uint32_t val = 0; - int ret = 0; - - for (;;) { - ret = max10_sys_read(dev, offset, &val); - if (ret < 0) { - dev_err(dev, - "Failed to read max10 register 0x%x [e:%d]\n", - offset, ret); - break; - } + return (status == SEC_STATUS_NORMAL || + status == SEC_STATUS_NIOS_OK || + status == SEC_STATUS_USER_OK || + status == SEC_STATUS_FACTORY_OK); +} - if (cond(val)) { - dev_debug(dev, - "Read 0x%08x from max10 register 0x%x " - "[poll success]\n", val, offset); - ret = 0; - break; - } - if (timeout_ms > interval_ms) - timeout_ms -= interval_ms; - else - timeout_ms = 0; - if (timeout_ms == 0) { - dev_debug(dev, - "Read 0x%08x from max10 register 0x%x " - "[poll timeout]\n", val, offset); - ret = -ETIMEDOUT; - break; - } - msleep(interval_ms); - } +static bool rsu_progress_done(u32 progress) +{ + return (progress == SEC_PROGRESS_IDLE || + progress == SEC_PROGRESS_RSU_DONE); +} - return ret; +static bool rsu_progress_busy(u32 progress) +{ + return (progress == SEC_PROGRESS_AUTHENTICATING || + progress == SEC_PROGRESS_COPYING || + progress == SEC_PROGRESS_UPDATE_CANCEL || + progress == SEC_PROGRESS_PROGRAM_KEY_HASH); } -static int n3000_secure_update_start(struct intel_max10_device *dev) +static enum ifpga_sec_err rsu_check_idle(struct intel_max10_device *dev) { uint32_t doorbell = 0; uint32_t prog = 0; - uint32_t status = 0; int ret = 0; - ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); - if (ret < 0) { + ret = max10_sys_read(dev, doorbell_reg(dev), &doorbell); + if (ret) { dev_err(dev, "Failed to read max10 doorbell register [e:%d]\n", ret); - return ret; + return IFPGA_SEC_ERR_RW_ERROR; } prog = SEC_PROGRESS_G(doorbell); - if ((prog != SEC_PROGRESS_IDLE) && (prog != SEC_PROGRESS_RSU_DONE)) { - dev_debug(dev, "Current RSU progress is %s\n", + if (!rsu_progress_done(prog)) { + dev_info(dev, "Current RSU progress is %s\n", rsu_progress_name(prog)); - return -EBUSY; + return IFPGA_SEC_ERR_BUSY; + } + + return IFPGA_SEC_ERR_NONE; +} + +static bool cond_start_done(uint32_t doorbell, uint32_t progress, + uint32_t status) +{ + if (doorbell & RSU_REQUEST) + return false; + + if (status == SEC_STATUS_ERASE_FAIL || + status == SEC_STATUS_WEAROUT) + return true; + + if (!rsu_progress_done(progress)) + return true; + + return false; +} + +static int +m10bmc_sec_status(struct intel_max10_device *dev, u32 *status) +{ + u32 reg_offset, reg_value; + int ret; + + reg_offset = (dev->type == M10_N6000) ? + auth_result_reg(dev) : doorbell_reg(dev); + + ret = max10_sys_read(dev, reg_offset, ®_value); + if (ret) + return ret; + + *status = SEC_STATUS_G(reg_value); + + return 0; +} + +static int +m10bmc_sec_progress_status(struct intel_max10_device *dev, u32 *doorbell, + u32 *progress, u32 *status) +{ + u32 auth_reg; + int ret; + + ret = max10_sys_read(dev, + doorbell_reg(dev), + doorbell); + if (ret) + return ret; + + *progress = SEC_PROGRESS_G(*doorbell); + + if (dev->type == M10_N6000) { + ret = max10_sys_read(dev, + auth_result_reg(dev), + &auth_reg); + if (ret) + return ret; + *status = SEC_STATUS_G(auth_reg); + } else { + *status = SEC_STATUS_G(*doorbell); } - ret = max10_sys_update_bits(dev, MAX10_DOORBELL, + return 0; +} + +static int rsu_poll_start_done(struct intel_max10_device *dev, u32 *doorbell, + u32 *progress, u32 *status) +{ + unsigned long time = 0; + int ret; + + do { + if (time > IFPGA_NIOS_HANDSHAKE_TIMEOUT_US) + return -ETIMEDOUT; + + ret = m10bmc_sec_progress_status(dev, doorbell, + progress, status); + if (ret) + return ret; + usleep(IFPGA_NIOS_HANDSHAKE_INTERVAL_US); + time += IFPGA_NIOS_HANDSHAKE_INTERVAL_US; + + } while (!cond_start_done(*doorbell, *progress, *status)); + + return 0; +} + +static enum ifpga_sec_err rsu_update_init(struct intel_max10_device *dev) +{ + uint32_t doorbell, progress, status; + int ret = 0; + + ret = max10_sys_update_bits(dev, doorbell_reg(dev), RSU_REQUEST | HOST_STATUS, RSU_REQUEST); - if (ret < 0) { + if (ret) { dev_err(dev, "Failed to updt max10 doorbell register [e:%d]\n", ret); - return ret; + return IFPGA_SEC_ERR_RW_ERROR; } - ret = poll_timeout(dev, MAX10_DOORBELL, secure_start_done, - IFPGA_SEC_START_INTERVAL_MS, IFPGA_SEC_START_TIMEOUT_MS); - if (ret < 0) { + ret = rsu_poll_start_done(dev, &doorbell, &progress, &status); + if (ret == -ETIMEDOUT) { + print_error_regs(dev); + return IFPGA_SEC_ERR_TIMEOUT; + } else if (ret) { dev_err(dev, "Failed to poll max10 doorbell register [e:%d]\n", ret); - return ret; + return IFPGA_SEC_ERR_RW_ERROR; } - ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); - if (ret < 0) { - dev_err(dev, - "Failed to read max10 doorbell register [e:%d]\n", - ret); - return ret; + status = SEC_STATUS_G(doorbell); + if (status == SEC_STATUS_WEAROUT) { + dev_err(dev, "Excessive flash update count detected\n"); + return IFPGA_SEC_ERR_WEAROUT; + } else if (status == SEC_STATUS_ERASE_FAIL) { + print_error_regs(dev); + return IFPGA_SEC_ERR_HW_ERROR; } - status = SEC_STATUS_G(doorbell); - if (status == SEC_STATUS_WEAROUT) - return -EAGAIN; + dev_info(dev, "Current RSU progress is %s\n", + rsu_progress_name(SEC_PROGRESS_G(doorbell))); - if (status == SEC_STATUS_ERASE_FAIL) - return -EIO; + return IFPGA_SEC_ERR_NONE; +} - return 0; +static bool cond_prepare_done(uint32_t doorbell) +{ + return (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_PREPARE); } -static int n3000_cancel(struct ifpga_sec_mgr *smgr) +static enum ifpga_sec_err rsu_prog_ready(struct intel_max10_device *dev) { - struct intel_max10_device *dev = NULL; uint32_t doorbell = 0; uint32_t prog = 0; int ret = 0; - if (!smgr || !smgr->max10_dev) - return -ENODEV; - dev = (struct intel_max10_device *)smgr->max10_dev; - - ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); - if (ret < 0) { + ret = opae_max10_read_poll_timeout(dev, doorbell_reg(dev), + doorbell, cond_prepare_done(doorbell), + IFPGA_RSU_PREP_INTERVAL_US, + IFPGA_RSU_PREP_TIMEOUT_US); + if (ret == -ETIMEDOUT) { + print_error_regs(dev); + return IFPGA_SEC_ERR_TIMEOUT; + } else if (ret) { dev_err(dev, - "Failed to read max10 doorbell register [e:%d]\n", + "Failed to poll max10 prog [e:%d]\n", ret); - return ret; + return IFPGA_SEC_ERR_RW_ERROR; } prog = SEC_PROGRESS_G(doorbell); - if (prog == SEC_PROGRESS_IDLE) - return 0; - if (prog != SEC_PROGRESS_READY) - return -EBUSY; + if (prog == SEC_PROGRESS_PREPARE) { + print_error_regs(dev); + return IFPGA_SEC_ERR_TIMEOUT; + } else if (prog != SEC_PROGRESS_READY) { + return IFPGA_SEC_ERR_HW_ERROR; + } - return max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS, - HOST_STATUS_S(HOST_STATUS_ABORT_RSU)); + dev_info(dev, "Current RSU progress is %s\n", + rsu_progress_name(SEC_PROGRESS_G(doorbell))); + + return IFPGA_SEC_ERR_NONE; } -static int n3000_prepare(struct ifpga_sec_mgr *smgr) +static enum ifpga_sec_err m10bmc_sec_prepare(struct ifpga_sec_mgr *smgr) { struct intel_max10_device *dev = NULL; - int retry = 0; int ret = 0; if (!smgr || !smgr->max10_dev) - return -ENODEV; - dev = (struct intel_max10_device *)smgr->max10_dev; + return IFPGA_SEC_ERR_HW_ERROR; - ret = n3000_secure_update_start(dev); - if (ret == -EBUSY) - n3000_cancel(smgr); + dev = smgr->max10_dev; - while (ret) { - if (++retry > IFPGA_RSU_START_RETRY) - break; - msleep(1000); - ret = n3000_secure_update_start(dev); - } - if (retry > IFPGA_RSU_START_RETRY) { - dev_err(dev, "Failed to start secure flash update\n"); - ret = -EAGAIN; + if (smgr->remaining_size > dev->staging_area_size) { + dev_err(smgr, "Size of staging area is smaller than image " + "length [%u<%u]\n", smgr->max10_dev->staging_area_size, + smgr->remaining_size); + return IFPGA_SEC_ERR_INVALID_SIZE; } - return ret; -} - -static int n3000_bulk_write(struct intel_max10_device *dev, uint32_t addr, - char *buf, uint32_t len) -{ - uint32_t i = 0; - uint32_t n = 0; - uint32_t v = 0; - uint32_t p = 0; - int ret = 0; - - if (len & 0x3) { - dev_err(dev, - "Length of data block is not 4 bytes aligned [e:%u]\n", - len); - return -EINVAL; - } + ret = rsu_check_idle(dev); + if (ret != IFPGA_SEC_ERR_NONE) + return ret; - n = len >> 2; - for (i = 0; i < n; i++) { - p = i << 2; - v = *(uint32_t *)(buf + p); - ret = max10_sys_raw_write(dev, addr + p, v); - if (ret < 0) { - dev_err(dev, - "Failed to write to staging area 0x%08x [e:%d]\n", - addr + p, ret); - return ret; - } - usleep(1); - } + ret = rsu_update_init(dev); + if (ret != IFPGA_SEC_ERR_NONE) + return ret; - return 0; + return rsu_prog_ready(dev); } -static int n3000_write_blk(struct ifpga_sec_mgr *smgr, char *buf, + +static enum ifpga_sec_err m10bmc_sec_write_blk(struct ifpga_sec_mgr *smgr, uint32_t offset, uint32_t len) { struct intel_max10_device *dev = NULL; uint32_t doorbell = 0; - uint32_t prog = 0; - uint32_t m = 0; int ret = 0; if (!smgr || !smgr->max10_dev) - return -ENODEV; - dev = (struct intel_max10_device *)smgr->max10_dev; + return IFPGA_SEC_ERR_HW_ERROR; + + dev = smgr->max10_dev; + if (!dev || !dev->bmc_ops.flash_write) + return IFPGA_SEC_ERR_HW_ERROR; if (offset + len > dev->staging_area_size) { dev_err(dev, "Write position would be out of staging area [e:%u]\n", dev->staging_area_size); - return -ENOMEM; + return IFPGA_SEC_ERR_INVALID_SIZE; } - ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); + ret = max10_sys_read(dev, doorbell_reg(dev), &doorbell); if (ret < 0) { dev_err(dev, "Failed to read max10 doorbell register [e:%d]\n", ret); - return ret; + return IFPGA_SEC_ERR_RW_ERROR; } - prog = SEC_PROGRESS_G(doorbell); - if (prog == SEC_PROGRESS_PREPARE) - return -EAGAIN; - else if (prog != SEC_PROGRESS_READY) - return -EBUSY; + if (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY) + return IFPGA_SEC_ERR_HW_ERROR; - m = len & 0x3; - if (m != 0) - len += 4 - m; /* make length to 4 bytes align */ + ret = dev->bmc_ops.flash_write(dev, dev->staging_area_base + offset, + smgr->data, len); - return n3000_bulk_write(dev, dev->staging_area_base + offset, buf, len); + return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE; } -static int n3000_write_done(struct ifpga_sec_mgr *smgr) +static enum ifpga_sec_err pmci_sec_write_blk(struct ifpga_sec_mgr *smgr, + uint32_t offset, uint32_t len) { - struct intel_max10_device *dev = NULL; + struct intel_max10_device *dev; uint32_t doorbell = 0; - uint32_t prog = 0; - uint32_t status = 0; int ret = 0; + UNUSED(offset); if (!smgr || !smgr->max10_dev) - return -ENODEV; - dev = (struct intel_max10_device *)smgr->max10_dev; + return IFPGA_SEC_ERR_HW_ERROR; - ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); + dev = smgr->max10_dev; + if (!dev || !dev->bmc_ops.flash_write) + return IFPGA_SEC_ERR_HW_ERROR; + + ret = max10_sys_read(dev, doorbell_reg(dev), &doorbell); if (ret < 0) { dev_err(dev, "Failed to read max10 doorbell register [e:%d]\n", ret); - return ret; + return IFPGA_SEC_ERR_RW_ERROR; } - prog = SEC_PROGRESS_G(doorbell); - if (prog != SEC_PROGRESS_READY) - return -EBUSY; + if (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY) + return IFPGA_SEC_ERR_HW_ERROR; + + ret = dev->bmc_ops.flash_write(dev, 0, smgr->data, len); + + return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE; +} - ret = max10_sys_update_bits(dev, MAX10_DOORBELL, HOST_STATUS, +static bool cond_prog_ready(uint32_t doorbell) +{ + return (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY); +} + +static enum ifpga_sec_err m10bmc_sec_write_done(struct ifpga_sec_mgr *smgr) +{ + struct intel_max10_device *dev = NULL; + uint32_t doorbell, status; + int ret = 0; + + if (!smgr || !smgr->max10_dev) + return IFPGA_SEC_ERR_HW_ERROR; + + dev = smgr->max10_dev; + + ret = max10_sys_update_bits(dev, doorbell_reg(dev), HOST_STATUS, HOST_STATUS_S(HOST_STATUS_WRITE_DONE)); if (ret < 0) { dev_err(dev, "Failed to update max10 doorbell register [e:%d]\n", ret); - return ret; + return IFPGA_SEC_ERR_RW_ERROR; } - ret = poll_timeout(dev, MAX10_DOORBELL, secure_prog_ready, - IFPGA_NIOS_HANDSHAKE_INTERVAL_MS, - IFPGA_NIOS_HANDSHAKE_TIMEOUT_MS); - if (ret < 0) { - dev_err(dev, - "Failed to poll max10 doorbell register [e:%d]\n", - ret); - return ret; + ret = opae_max10_read_poll_timeout(dev, doorbell_reg(dev), + doorbell, cond_prog_ready(doorbell), + IFPGA_NIOS_HANDSHAKE_INTERVAL_US, + IFPGA_NIOS_HANDSHAKE_TIMEOUT_US); + if (ret == -ETIMEDOUT) { + print_error_regs(dev); + return IFPGA_SEC_ERR_TIMEOUT; + } else if (ret) { + return IFPGA_SEC_ERR_RW_ERROR; } - ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); - if (ret < 0) { - dev_err(dev, - "Failed to read max10 doorbell register [e:%d]\n", - ret); - return ret; + ret = m10bmc_sec_status(dev, &status); + if (ret) + return IFPGA_SEC_ERR_RW_ERROR; + + if (!rsu_status_ok(status)) { + print_error_regs(dev); + return IFPGA_SEC_ERR_HW_ERROR; } - status = SEC_STATUS_G(doorbell); - switch (status) { - case SEC_STATUS_NORMAL: - case SEC_STATUS_NIOS_OK: - case SEC_STATUS_USER_OK: - case SEC_STATUS_FACTORY_OK: - ret = 0; - break; - default: - ret = -EIO; - break; + return IFPGA_SEC_ERR_NONE; +} + +static enum ifpga_sec_err m10bmc_sec_check_complete(struct ifpga_sec_mgr *smgr) +{ + struct intel_max10_device *dev = NULL; + uint32_t doorbell, status, progress; + + if (!smgr || !smgr->max10_dev) + return IFPGA_SEC_ERR_HW_ERROR; + + dev = smgr->max10_dev; + + if (m10bmc_sec_progress_status(dev, &doorbell, &progress, &status)) { + print_error_regs(dev); + return IFPGA_SEC_ERR_RW_ERROR; } - return ret; + if (!rsu_status_ok(status)) { + print_error_regs(dev); + return IFPGA_SEC_ERR_HW_ERROR; + } + + if (rsu_progress_done(progress)) + return IFPGA_SEC_ERR_NONE; + + if (rsu_progress_busy(progress)) + return IFPGA_SEC_ERR_BUSY; + + return IFPGA_SEC_ERR_HW_ERROR; } -static int n3000_check_complete(struct ifpga_sec_mgr *smgr) +static enum ifpga_sec_err m10bmc_sec_cancel(struct ifpga_sec_mgr *smgr) { struct intel_max10_device *dev = NULL; uint32_t doorbell = 0; - uint32_t status = 0; - uint32_t prog = 0; int ret = 0; if (!smgr || !smgr->max10_dev) - return -ENODEV; - dev = (struct intel_max10_device *)smgr->max10_dev; + return IFPGA_SEC_ERR_HW_ERROR; - ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); + dev = smgr->max10_dev; + + ret = max10_sys_read(dev, doorbell_reg(dev), &doorbell); if (ret < 0) { dev_err(dev, "Failed to read max10 doorbell register [e:%d]\n", ret); - return ret; + return IFPGA_SEC_ERR_RW_ERROR; } - status = SEC_STATUS_G(doorbell); - switch (status) { - case SEC_STATUS_NORMAL: - case SEC_STATUS_NIOS_OK: - case SEC_STATUS_USER_OK: - case SEC_STATUS_FACTORY_OK: - case SEC_STATUS_WEAROUT: - break; - default: - return -EIO; + if (SEC_PROGRESS_G(doorbell) != SEC_PROGRESS_READY) + return IFPGA_SEC_ERR_BUSY; + + ret = max10_sys_update_bits(dev, doorbell_reg(dev), HOST_STATUS, + HOST_STATUS_S(HOST_STATUS_ABORT_RSU)); + + return ret ? IFPGA_SEC_ERR_RW_ERROR : IFPGA_SEC_ERR_NONE; +} + +static uint64_t m10bmc_sec_hw_errinfo(struct ifpga_sec_mgr *smgr) +{ + struct intel_max10_device *dev = NULL; + uint32_t doorbell = IFPGA_HW_ERRINFO_POISON; + uint32_t auth_result = IFPGA_HW_ERRINFO_POISON; + uint32_t stat = 0; + uint32_t prog = 0; + + if (smgr && smgr->max10_dev) { + dev = smgr->max10_dev; + switch (smgr->err_code) { + case IFPGA_SEC_ERR_HW_ERROR: + case IFPGA_SEC_ERR_TIMEOUT: + case IFPGA_SEC_ERR_BUSY: + case IFPGA_SEC_ERR_WEAROUT: + if (max10_sys_read(dev, doorbell_reg(dev), + &doorbell)) + doorbell = IFPGA_HW_ERRINFO_POISON; + if (max10_sys_read(dev, auth_result_reg(dev), + &auth_result)) + auth_result = IFPGA_HW_ERRINFO_POISON; + break; + default: + doorbell = 0; + auth_result = 0; + break; + } } + stat = SEC_STATUS_G(doorbell); prog = SEC_PROGRESS_G(doorbell); - switch (prog) { - case SEC_PROGRESS_IDLE: - case SEC_PROGRESS_RSU_DONE: - return 0; - case SEC_PROGRESS_AUTHENTICATING: - case SEC_PROGRESS_COPYING: - case SEC_PROGRESS_UPDATE_CANCEL: - case SEC_PROGRESS_PROGRAM_KEY_HASH: - return -EAGAIN; - case SEC_PROGRESS_PREPARE: - case SEC_PROGRESS_READY: - return -EBUSY; - default: - return -EIO; - } + dev_info(dev, "Current RSU status is %s, progress is %s\n", + rsu_status_name(stat), rsu_progress_name(prog)); - return 0; + return (uint64_t)doorbell << 32 | (uint64_t)auth_result; } -static int n3000_reload_fpga(struct intel_max10_device *dev, int page) +static int m10bmc_sec_fpga_image_load(struct ifpga_sec_mgr *smgr, int page) { + struct intel_max10_device *dev = NULL; int ret = 0; dev_info(dev, "Reload FPGA\n"); - if (!dev || ((page != 0) && (page != 1))) { - dev_err(dev, "Input parameter of %s is invalid\n", __func__); - ret = -EINVAL; - goto end; - } + if (!smgr || !smgr->max10_dev) + return -ENODEV; + + dev = smgr->max10_dev; if (dev->flags & MAX10_FLAGS_SECURE) { ret = max10_sys_update_bits(dev, FPGA_RECONF_REG, @@ -471,117 +894,210 @@ static int n3000_reload_fpga(struct intel_max10_device *dev, int page) return ret; } -static int n3000_reload_bmc(struct intel_max10_device *dev, int page) +static int m10bmc_sec_bmc_image_load(struct ifpga_sec_mgr *smgr, int page) { - uint32_t val = 0; + struct intel_max10_device *dev = NULL; + uint32_t doorbell = 0; int ret = 0; dev_info(dev, "Reload BMC\n"); - if (!dev || ((page != 0) && (page != 1))) { - dev_err(dev, "Input parameter of %s is invalid\n", __func__); - ret = -EINVAL; - goto end; - } + if (!smgr || !smgr->max10_dev) + return -ENODEV; - if (dev->flags & MAX10_FLAGS_SECURE) { - ret = max10_sys_update_bits(dev, MAX10_DOORBELL, - CONFIG_SEL | REBOOT_REQ, - CONFIG_SEL_S(page) | REBOOT_REQ); - } else { - val = (page == 0) ? 0x1 : 0x3; - ret = max10_sys_raw_write(dev, IFPGA_DUAL_CFG_CTRL1, val); - if (ret < 0) { - dev_err(dev, - "Failed to write to dual config1 register [e:%d]\n", - ret); - goto end; - } + dev = smgr->max10_dev; - ret = max10_sys_raw_write(dev, IFPGA_DUAL_CFG_CTRL0, 0x1); - if (ret < 0) { - if (ret == -EIO) { - ret = 0; - goto end; - } - dev_err(dev, - "Failed to write to dual config0 register [e:%d]\n", + ret = max10_sys_read(dev, doorbell_reg(dev), &doorbell); + if (ret < 0) { + dev_err(dev, "Failed to read max10 doorbell register [e:%d]\n", ret); - } + return ret; } -end: - if (ret < 0) - dev_err(dev, "Failed to reload BMC\n"); + switch (dev->type) { + case N3000BMC_SEC: + if (doorbell & REBOOT_DISABLED) + return -EBUSY; + + ret = max10_sys_update_bits(dev, doorbell_reg(dev), + CONFIG_SEL | REBOOT_REQ, + CONFIG_SEL_S(page) | REBOOT_REQ); + break; + case N6000BMC_SEC: + if (doorbell & PMCI_DRBL_REBOOT_DISABLED) + return -EBUSY; + + ret = max10_sys_update_bits(dev, m10bmc_base(dev) + + M10BMC_PMCI_MAX10_RECONF, + PMCI_MAX10_REBOOT_REQ | PMCI_MAX10_REBOOT_PAGE, + SET_FIELD(PMCI_MAX10_REBOOT_PAGE, page) | + PMCI_MAX10_REBOOT_REQ); + break; + default: + ret = -EINVAL; + break; + } return ret; } -static int n3000_reload(struct ifpga_sec_mgr *smgr, int type, int page) +static int pmci_sec_fpga_image_load(struct ifpga_sec_mgr *smgr, + unsigned int val) { - int psel = 0; - int ret = 0; + struct intel_max10_device *dev; + int ret; if (!smgr || !smgr->max10_dev) return -ENODEV; - if (type == IFPGA_BOOT_TYPE_FPGA) { - psel = (page == IFPGA_BOOT_PAGE_FACTORY ? 0 : 1); - ret = n3000_reload_fpga(smgr->max10_dev, psel); - } else if (type == IFPGA_BOOT_TYPE_BMC) { - psel = (page == IFPGA_BOOT_PAGE_FACTORY ? 1 : 0); - ret = n3000_reload_bmc(smgr->max10_dev, psel); - } else { - ret = -EINVAL; + dev = smgr->max10_dev; + + if (val > 2) { + dev_err(dev, "%s invalid reload val = %d\n", + __func__, val); + return -EINVAL; } - return ret; + ret = max10_sys_update_bits(dev, + M10BMC_PMCI_FPGA_RECONF, + PMCI_FPGA_RP_LOAD, 0); + if (ret) + return ret; + + return max10_sys_update_bits(dev, + M10BMC_PMCI_FPGA_RECONF, + PMCI_FPGA_RECONF_PAGE | PMCI_FPGA_RP_LOAD, + SET_FIELD(PMCI_FPGA_RECONF_PAGE, val) | + PMCI_FPGA_RP_LOAD); } -static uint64_t n3000_get_hw_errinfo(struct ifpga_sec_mgr *smgr) +static int n3000_sec_fpga_image_load_0(struct ifpga_sec_mgr *smgr) { - struct intel_max10_device *dev = NULL; - uint32_t doorbell = 0; - uint32_t stat = 0; - uint32_t prog = 0; - uint32_t auth_result = 0; - int ret = 0; + return m10bmc_sec_fpga_image_load(smgr, 0); +} - if (!smgr || !smgr->max10_dev) - return -ENODEV; - dev = (struct intel_max10_device *)smgr->max10_dev; +static int n3000_sec_fpga_image_load_1(struct ifpga_sec_mgr *smgr) +{ + return m10bmc_sec_fpga_image_load(smgr, 1); +} - ret = max10_sys_read(dev, MAX10_DOORBELL, &doorbell); - if (ret < 0) { - dev_err(dev, "Failed to read max10 doorbell register [e:%d]\n", - ret); - return -1; - } - stat = SEC_STATUS_G(doorbell); - prog = SEC_PROGRESS_G(doorbell); - dev_debug(dev, "Current RSU status is %s, progress is %s\n", - rsu_status_name(stat), rsu_progress_name(prog)); +static int n3000_sec_bmc_image_load_0(struct ifpga_sec_mgr *smgr) +{ + return m10bmc_sec_bmc_image_load(smgr, 0); +} - ret = max10_sys_read(dev, MAX10_AUTH_RESULT, &auth_result); - if (ret < 0) { - dev_err(dev, - "Failed to read authenticate result register [e:%d]\n", - ret); - return -1; - } +static int n3000_sec_bmc_image_load_1(struct ifpga_sec_mgr *smgr) +{ + return m10bmc_sec_bmc_image_load(smgr, 1); +} - return (uint64_t)doorbell << 32 | (uint64_t)auth_result; +static int pmci_sec_bmc_image_load_0(struct ifpga_sec_mgr *smgr) +{ + return m10bmc_sec_bmc_image_load(smgr, 0); +} + +static int pmci_sec_bmc_image_load_1(struct ifpga_sec_mgr *smgr) +{ + return m10bmc_sec_bmc_image_load(smgr, 1); +} + +static int pmci_sec_fpga_image_load_0(struct ifpga_sec_mgr *smgr) +{ + return pmci_sec_fpga_image_load(smgr, 0); +} + +static int pmci_sec_fpga_image_load_1(struct ifpga_sec_mgr *smgr) +{ + return pmci_sec_fpga_image_load(smgr, 1); +} + +static int pmci_sec_fpga_image_load_2(struct ifpga_sec_mgr *smgr) +{ + return pmci_sec_fpga_image_load(smgr, 2); +} + +static int pmci_sec_sdm_image_load(struct ifpga_sec_mgr *smgr) +{ + struct intel_max10_device *dev = smgr->max10_dev; + + return max10_sys_update_bits(dev, + m10bmc_base(dev) + M10BMC_PMCI_SDM_CTRL_STS, + PMCI_SDM_IMG_REQ, PMCI_SDM_IMG_REQ); } -static const struct ifpga_sec_ops n3000_sec_ops = { - .prepare = n3000_prepare, - .write_blk = n3000_write_blk, - .write_done = n3000_write_done, - .check_complete = n3000_check_complete, - .reload = n3000_reload, - .cancel = n3000_cancel, - .cleanup = NULL, - .get_hw_errinfo = n3000_get_hw_errinfo, +static struct image_load n3000_image_load_hndlrs[] = { + { + .name = "fpga_factory", + .load_image = n3000_sec_fpga_image_load_0, + }, + { + .name = "fpga_user", + .load_image = n3000_sec_fpga_image_load_1, + }, + { + .name = "bmc_factory", + .load_image = n3000_sec_bmc_image_load_1, + }, + { + .name = "bmc_user", + .load_image = n3000_sec_bmc_image_load_0, + }, + {} +}; + +static struct image_load pmci_image_load_hndlrs[] = { + { + .name = "bmc_factory", + .load_image = pmci_sec_bmc_image_load_0, + }, + { + .name = "bmc_user", + .load_image = pmci_sec_bmc_image_load_1, + }, + { + .name = "fpga_factory", + .load_image = pmci_sec_fpga_image_load_0, + }, + { + .name = "fpga_user1", + .load_image = pmci_sec_fpga_image_load_1, + }, + { + .name = "fpga_user2", + .load_image = pmci_sec_fpga_image_load_2, + }, + { + .name = "sdm", + .load_image = pmci_sec_sdm_image_load, + }, + {} +}; + +static const struct ifpga_sec_mgr_ops n3000_sec_ops = { + .prepare = m10bmc_sec_prepare, + .write_blk = m10bmc_sec_write_blk, + .write_done = m10bmc_sec_write_done, + .check_complete = m10bmc_sec_check_complete, + .cancel = m10bmc_sec_cancel, + .get_hw_errinfo = m10bmc_sec_hw_errinfo, + .image_load = n3000_image_load_hndlrs, +}; + +static const struct ifpga_sec_mgr_ops pmci_sec_ops = { + .prepare = m10bmc_sec_prepare, + .write_blk = pmci_sec_write_blk, + .write_done = m10bmc_sec_write_done, + .check_complete = m10bmc_sec_check_complete, + .cancel = m10bmc_sec_cancel, + .get_hw_errinfo = m10bmc_sec_hw_errinfo, + .image_load = pmci_image_load_hndlrs, +}; + +static const struct fpga_power_on pmci_power_on_image = { + .avail_image_mask = BIT(FPGA_FACTORY) | + BIT(FPGA_USER1) | BIT(FPGA_USER2), + .set_sequence = pmci_set_power_on_image, + .get_sequence = pmci_get_power_on_image, }; int init_sec_mgr(struct ifpga_fme_hw *fme, enum fpga_sec_type type) @@ -610,19 +1126,25 @@ int init_sec_mgr(struct ifpga_fme_hw *fme, enum fpga_sec_type type) smgr->rsu_status = NULL; } - if (hw && (hw->pci_data->device_id == IFPGA_N3000_DID) && - (hw->pci_data->vendor_id == IFPGA_N3000_VID)) { - smgr->ops = &n3000_sec_ops; - smgr->copy_speed = IFPGA_N3000_COPY_SPEED; - } else { - dev_err(NULL, "No operation for security manager\n"); - smgr->ops = NULL; - } - smgr->fme = fme; smgr->max10_dev = fme->max10_dev; smgr->type = type; + switch (type) { + case N3000BMC_SEC: + smgr->sops = &n3000_sec_ops; + smgr->copy_speed = IFPGA_N3000_COPY_SPEED; + break; + case N6000BMC_SEC: + smgr->sops = &pmci_sec_ops; + smgr->copy_speed = IFPGA_N3000_COPY_SPEED; + smgr->poc = &pmci_power_on_image; + break; + default: + dev_err(NULL, "No operation for security manager\n"); + smgr->sops = NULL; + } + return 0; } diff --git a/drivers/raw/ifpga/base/ifpga_sec_mgr.h b/drivers/raw/ifpga/base/ifpga_sec_mgr.h index 09cc038..0b2e1ac 100644 --- a/drivers/raw/ifpga/base/ifpga_sec_mgr.h +++ b/drivers/raw/ifpga/base/ifpga_sec_mgr.h @@ -25,35 +25,44 @@ #define IFPGA_N3000_COPY_SPEED 42700 /* status */ -#define IFPGA_RSU_IDLE 0 -#define IFPGA_RSU_PREPARE 1 -#define IFPGA_RSU_READY 2 -#define IFPGA_RSU_COPYING 3 -#define IFPGA_RSU_REBOOT 4 +#define IFPGA_RSU_IDLE 0 +#define IFPGA_RSU_PREPARING 1 +#define IFPGA_RSU_WRITING 2 +#define IFPGA_RSU_PROGRAMMING 3 +#define IFPGA_RSU_REBOOT 4 -#define IFPGA_RSU_GET_STAT(v) (((v) >> 16) & 0xffff) -#define IFPGA_RSU_GET_PROG(v) ((v) & 0xffff) -#define IFPGA_RSU_STATUS(s, p) ((((s) << 16) & 0xffff0000) | ((p) & 0xffff)) +#define IFPGA_RSU_GET_STAT(v) (((v) >> 16) & 0xff) +#define IFPGA_RSU_GET_PROG(v) ((v) & 0xff) +#define IFPGA_RSU_STATUS(s, p) ((((s) << 16) & 0xff0000) | ((p) & 0xff)) /* control */ -#define IFPGA_RSU_ABORT 1 +#define IFPGA_RSU_CANCEL 1 + +#define IFPGA_HW_ERRINFO_POISON 0xffffffff #define IFPGA_DUAL_CFG_CTRL0 0x200020 #define IFPGA_DUAL_CFG_CTRL1 0x200024 -#define IFPGA_SEC_START_INTERVAL_MS 100 -#define IFPGA_SEC_START_TIMEOUT_MS 20000 -#define IFPGA_NIOS_HANDSHAKE_INTERVAL_MS 100 -#define IFPGA_NIOS_HANDSHAKE_TIMEOUT_MS 5000 - -#define IFPGA_RSU_ERR_HW_ERROR -1 -#define IFPGA_RSU_ERR_TIMEOUT -2 -#define IFPGA_RSU_ERR_CANCELED -3 -#define IFPGA_RSU_ERR_BUSY -4 -#define IFPGA_RSU_ERR_INVALID_SIZE -5 -#define IFPGA_RSU_ERR_RW_ERROR -6 -#define IFPGA_RSU_ERR_WEAROUT -7 -#define IFPGA_RSU_ERR_FILE_READ -8 +#define IFPGA_NIOS_HANDSHAKE_INTERVAL_US (100 * 1000) +#define IFPGA_NIOS_HANDSHAKE_TIMEOUT_US (5000 * 1000) +/* Wait about 2 minutes to erase flash staging area */ +#define IFPGA_RSU_PREP_INTERVAL_US (100 * 1000) +#define IFPGA_RSU_PREP_TIMEOUT_US (120000 * 1000) + +enum ifpga_sec_err { + IFPGA_SEC_ERR_NONE = 0, + IFPGA_SEC_ERR_HW_ERROR, + IFPGA_SEC_ERR_TIMEOUT, + IFPGA_SEC_ERR_CANCELED, + IFPGA_SEC_ERR_BUSY, + IFPGA_SEC_ERR_INVALID_SIZE, + IFPGA_SEC_ERR_RW_ERROR, + IFPGA_SEC_ERR_WEAROUT, + IFPGA_SEC_ERR_FILE_READ, + IFPGA_SEC_ERR_NO_MEM, + IFPGA_SEC_ERR_NO_FUNC, + IFPGA_SEC_ERR_MAX +}; /* Supported fpga secure manager types */ enum fpga_sec_type { @@ -61,32 +70,57 @@ enum fpga_sec_type { N6000BMC_SEC }; +/* Supported names for power-on images */ +enum fpga_image { + FPGA_FACTORY, + FPGA_USER1, + FPGA_USER2, + FPGA_MAX +}; + struct ifpga_sec_mgr; -struct ifpga_sec_ops { - int (*prepare)(struct ifpga_sec_mgr *smgr); - int (*write_blk)(struct ifpga_sec_mgr *smgr, char *buf, uint32_t offset, - uint32_t size); - int (*write_done)(struct ifpga_sec_mgr *smgr); - int (*check_complete)(struct ifpga_sec_mgr *smgr); - int (*reload)(struct ifpga_sec_mgr *smgr, int type, int page); - int (*cancel)(struct ifpga_sec_mgr *smgr); +struct image_load { + const char *name; + int (*load_image)(struct ifpga_sec_mgr *smgr); +}; + +struct fpga_power_on { + u32 avail_image_mask; + int (*get_sequence)(struct ifpga_sec_mgr *smgr, char *buf, + size_t size); + int (*set_sequence)(struct ifpga_sec_mgr *smgr, + enum fpga_image images[]); +}; + +struct ifpga_sec_mgr_ops { + enum ifpga_sec_err (*prepare)(struct ifpga_sec_mgr *smgr); + enum ifpga_sec_err (*write_blk)(struct ifpga_sec_mgr *smgr, + uint32_t offset, uint32_t size); + enum ifpga_sec_err (*write_done)(struct ifpga_sec_mgr *smgr); + enum ifpga_sec_err (*check_complete)(struct ifpga_sec_mgr *smgr); + enum ifpga_sec_err (*cancel)(struct ifpga_sec_mgr *smgr); void (*cleanup)(struct ifpga_sec_mgr *smgr); u64 (*get_hw_errinfo)(struct ifpga_sec_mgr *smgr); + struct image_load *image_load; /* terminated with { } member */ }; struct ifpga_sec_mgr { struct ifpga_fme_hw *fme; struct intel_max10_device *max10_dev; - unsigned int rsu_length; - /* number of bytes that copied from staging area to working area - * in one second, which is calculated by experiment - */ - unsigned int copy_speed; - unsigned int *rsu_control; unsigned int *rsu_status; - const struct ifpga_sec_ops *ops; + unsigned int *rsu_control; + unsigned int one_percent; /* use to calculate progress value */ + unsigned int copy_speed; /* flash copy speed in bytes/second */ + + const struct ifpga_sec_mgr_ops *sops; + const char *filename; + char *data; /* pointer to update data */ + u32 remaining_size; /* size remaining to transfer */ + enum ifpga_sec_err err_code; + u64 hw_errinfo; /* 64 bits of HW specific error info */ enum fpga_sec_type type; + const struct fpga_power_on *poc; /* power on image configuration */ }; int init_sec_mgr(struct ifpga_fme_hw *fme, enum fpga_sec_type type); @@ -94,7 +128,12 @@ struct ifpga_sec_mgr { int fpga_update_flash(struct ifpga_fme_hw *fme, const char *image, uint64_t *status); int fpga_stop_flash_update(struct ifpga_fme_hw *fme, int force); -int fpga_reload(struct ifpga_fme_hw *fme, int type, int page); +int fpga_reload(struct ifpga_fme_hw *fme, char *str); +int fpga_available_images(struct ifpga_fme_hw *fme, char *buf, size_t size); +int fpga_set_poc_image(struct ifpga_fme_hw *fme, char *buf); +int fpga_get_poc_images(struct ifpga_fme_hw *fme, char *buf, size_t size); +int pmci_set_poc_image(struct ifpga_sec_mgr *smgr, char *buf); +int pmci_get_poc_images(struct ifpga_sec_mgr *smgr, char *buf, size_t size); #endif /* _IFPGA_FME_RSU_H_ */ diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c index 6b78094..ada3d29 100644 --- a/drivers/raw/ifpga/base/opae_hw_api.c +++ b/drivers/raw/ifpga/base/opae_hw_api.c @@ -1055,18 +1055,94 @@ int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force) /** * opae_mgr_reload - reload FPGA. * @mgr: targeted manager - * @type: FPGA type - * @page: reload from which page + * @str: name of reload image type * * Return: 0 on success, otherwise error code. */ -int opae_mgr_reload(struct opae_manager *mgr, int type, int page) +int opae_mgr_reload(struct opae_manager *mgr, char *str) { if (!mgr) return -EINVAL; if (mgr->ops && mgr->ops->reload) - return mgr->ops->reload(mgr, type, page); + return mgr->ops->reload(mgr, str); + + return -ENOENT; +} + +/** + * opae_mgr_available_images - get available load image types. + * @mgr: targeted manager + * @buf: buffer to fill with image type list + * @size: size of the buffer + * + * Return: 0 or positive value on success, otherwise error code. + */ +int opae_mgr_available_images(struct opae_manager *mgr, char *buf, size_t size) +{ + if (!mgr) + return -EINVAL; + + if (mgr->ops && mgr->ops->available_images) + return mgr->ops->available_images(mgr, buf, size); + + return -ENOENT; +} + +/** + * opae_mgr_get_poc_images - get available power_on_images. + * @mgr: targeted manager + * @buf: buffer to fill with image type list + * @size: size of the buffer + * + * Return: 0 or positive value on success, otherwise error code. + */ +int opae_mgr_get_poc_images(struct opae_manager *mgr, char *buf, size_t size) +{ + if (!mgr) + return -EINVAL; + + if (mgr->ops && mgr->ops->get_poc_images) + return mgr->ops->get_poc_images(mgr, buf, size); + + return -ENOENT; +} + +/** + * opae_mgr_set_poc_image - configure the FPGA power_on_image. + * @mgr: targeted manager + * @str: name of power_on_image + * + * Return: 0 on success, otherwise error code. + */ +int opae_mgr_set_poc_image(struct opae_manager *mgr, char *str) +{ + if (!mgr) + return -EINVAL; + + if (mgr->ops && mgr->ops->set_poc_image) + return mgr->ops->set_poc_image(mgr, str); + + return -ENOENT; +} + +/** + * opae_mgr_read_flash - read flash content + * @mgr: targeted manager + * @address: the start address of flash + * @size: the size of flash + * @buf: the read buffer + * + * Return: 0 on success, otherwise error code. + */ +int opae_mgr_read_flash(struct opae_manager *mgr, u32 address, + u32 size, void *buf) +{ + if (!mgr) + return -EINVAL; + + if (mgr->ops && mgr->ops->read_flash) + return mgr->ops->read_flash(mgr, address, size, buf); return -ENOENT; } diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h index 8aead4d..1e31d1e 100644 --- a/drivers/raw/ifpga/base/opae_hw_api.h +++ b/drivers/raw/ifpga/base/opae_hw_api.h @@ -59,7 +59,13 @@ struct opae_manager_ops { int (*update_flash)(struct opae_manager *mgr, const char *image, u64 *status); int (*stop_flash_update)(struct opae_manager *mgr, int force); - int (*reload)(struct opae_manager *mgr, int type, int page); + int (*reload)(struct opae_manager *mgr, char *str); + int (*available_images)(struct opae_manager *mgr, char *buf, + size_t size); + int (*get_poc_images)(struct opae_manager *mgr, char *buf, + size_t size); + int (*set_poc_image)(struct opae_manager *mgr, char *str); + int (*read_flash)(struct opae_manager *mgr, u32 address, u32 size, void *buf); }; /* networking management ops in FME */ @@ -368,5 +374,9 @@ int opae_mgr_get_board_info(struct opae_manager *mgr, int opae_mgr_update_flash(struct opae_manager *mgr, const char *image, uint64_t *status); int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force); -int opae_mgr_reload(struct opae_manager *mgr, int type, int page); +int opae_mgr_reload(struct opae_manager *mgr, char *str); +int opae_mgr_available_images(struct opae_manager *mgr, char *buf, size_t size); +int opae_mgr_set_poc_image(struct opae_manager *mgr, char *str); +int opae_mgr_get_poc_images(struct opae_manager *mgr, char *buf, size_t size); +int opae_mgr_read_flash(struct opae_manager *mgr, u32 address, u32 size, void *buf); #endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.c b/drivers/raw/ifpga/rte_pmd_ifpga.c index 2314643..fda7cae 100644 --- a/drivers/raw/ifpga/rte_pmd_ifpga.c +++ b/drivers/raw/ifpga/rte_pmd_ifpga.c @@ -6,6 +6,7 @@ #include #include #include +#include "base/opae_hw_api.h" #include "rte_pmd_ifpga.h" #include "ifpga_rawdev.h" #include "base/ifpga_api.h" @@ -390,16 +391,104 @@ return 0; } +static int +get_image_load_string(struct opae_adapter *adapter, int type, int page, + char *str, size_t size) +{ + struct opae_adapter_data_pci *pci_data = NULL; + + pci_data = (struct opae_adapter_data_pci *)adapter->data; + if (!pci_data || (pci_data->type != OPAE_FPGA_PCI)) + return -EINVAL; + + if (type == 0) { + if (pci_data->device_id == IFPGA_N3000_ID) { + if (page == 0) + snprintf(str, size, "fpga_factory"); + else + snprintf(str, size, "fpga_user"); + } else if (pci_data->device_id == IFPGA_N6000_ID) { + if (page == 0) + snprintf(str, size, "fpga_factory"); + else if (page == 1) + snprintf(str, size, "fpga_user1"); + else if (page == 2) + snprintf(str, size, "fpga_user2"); + else + snprintf(str, size, "sdm"); + } + } else { + if (page == 0) + snprintf(str, size, "bmc_factory"); + else + snprintf(str, size, "bmc_user"); + } + + return 0; +} + int rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page) { struct opae_adapter *adapter = NULL; + char str[RTE_RAWDEV_NAME_MAX_LEN] = {0}; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + if (get_image_load_string(adapter, type, page, str, sizeof(str))) + return -EINVAL; + + return opae_mgr_reload(adapter->mgr, str); +} + +int +rte_pmd_ifpga_image_load(uint16_t dev_id, char *str) +{ + struct opae_adapter *adapter = NULL; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + return opae_mgr_reload(adapter->mgr, str); +} + +int +rte_pmd_ifpga_get_available_images(uint16_t dev_id, char *buf, size_t size) +{ + struct opae_adapter *adapter = NULL; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + return opae_mgr_available_images(adapter->mgr, buf, size); +} + +int +rte_pmd_ifpga_set_poc_image(uint16_t dev_id, char *str) +{ + struct opae_adapter *adapter = NULL; adapter = get_opae_adapter(dev_id); if (!adapter) return -ENODEV; - return opae_mgr_reload(adapter->mgr, type, page); + return opae_mgr_set_poc_image(adapter->mgr, str); +} + +int +rte_pmd_ifpga_get_poc_images(uint16_t dev_id, char *buf, size_t size) +{ + struct opae_adapter *adapter = NULL; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + return opae_mgr_get_poc_images(adapter->mgr, buf, size); } const struct rte_pci_bus * @@ -422,6 +511,19 @@ return ifpga_rawdev_partial_reconfigure(dev, port, file); } +int +rte_pmd_ifpga_read_flash(uint16_t dev_id, uint32_t address, uint32_t size, + void *buf) +{ + struct opae_adapter *adapter; + + adapter = get_opae_adapter(dev_id); + if (!adapter) + return -ENODEV; + + return opae_mgr_read_flash(adapter->mgr, address, size, buf); +} + void rte_pmd_ifpga_cleanup(void) { diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h b/drivers/raw/ifpga/rte_pmd_ifpga.h index 3fa5d34..2a6a502 100644 --- a/drivers/raw/ifpga/rte_pmd_ifpga.h +++ b/drivers/raw/ifpga/rte_pmd_ifpga.h @@ -21,6 +21,8 @@ #include #define IFPGA_MAX_PORT_NUM 4 +#define IFPGA_N3000_ID 0x0B30 +#define IFPGA_N6000_ID 0xBCCE /** * UUID data structure. @@ -216,6 +218,7 @@ * - (-ENODEV) if dev_id is invalid. * - (-EINVAL) if bad parameter. * - (-EBUSY) if failed to access BMC register. + * - (-EOPNOTSUPP) if the specific image load not supported. */ int rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page); @@ -253,6 +256,120 @@ void rte_pmd_ifpga_cleanup(void); +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Set which image to load for specified Intel FPGA device at power on + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param str + * name of the image to load from flash. + * @return + * - (0) if successful. + * - (-ENODEV) if dev_id is invalid. + * - (-EINVAL) if bad parameter. + * - (-EBUSY) if failed to access BMC register. + * - (-EOPNOTSUPP) if the specific image load not supported. + */ +__rte_experimental +int +rte_pmd_ifpga_set_poc_image(uint16_t dev_id, char *str); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Get available load image supported by specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param buf + * a space separated list of image type name will be filled in this buffer. + * buffer pointer can be NULL. + * @param size + * when buf pointer is not NULL, indicate the size of the buffer. + * @return + * - (0) no available load image type. + * - (>0) string length of the list including the terminating null character. + * - (-ENODEV) if dev_id is invalid. + * - (-EINVAL) if bad parameter. + * - (-EBUSY) if failed to access BMC register. + */ +__rte_experimental +int +rte_pmd_ifpga_get_poc_images(uint16_t dev_id, char *buf, size_t size); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Trigger image load of specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param str + * name of the image to load from flash. + * @return + * - (0) if successful. + * - (-ENODEV) if dev_id is invalid. + * - (-EINVAL) if bad parameter. + * - (-EBUSY) if failed to access BMC register. + * - (-EOPNOTSUPP) if the specific image load not supported. + */ +__rte_experimental +int +rte_pmd_ifpga_image_load(uint16_t dev_id, char *str); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Get available load image supported by specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param buf + * a space separated list of image type name will be filled in this buffer. + * buffer pointer can be NULL. + * @param size + * when buf pointer is not NULL, indicate the size of the buffer. + * @return + * - (0) no available load image type. + * - (>0) string length of the list including the terminating null character. + * - (-ENODEV) if dev_id is invalid. + * - (-EINVAL) if bad parameter. + * - (-EBUSY) if failed to access BMC register. + */ +__rte_experimental +int +rte_pmd_ifpga_get_available_images(uint16_t dev_id, char *buf, size_t size); + +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Read out flash content on specified Intel FPGA device + * + * @param dev_id + * The raw device ID of specified Intel FPGA device. + * @param address + * The start address of the flash. + * @param size + * The size of flash which want to read out. + * @param buf + * The read buffer. + * @return + * - (0) if successful. + * - (-EINVAL) if bad parameter or operation failed. + * - (-ENOMEM) if no available flash memory to access. + */ +__rte_experimental +int +rte_pmd_ifpga_read_flash(uint16_t dev_id, uint32_t address, uint32_t size, + void *buf); + #ifdef __cplusplus } #endif diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map index ff71a45..a201124 100644 --- a/drivers/raw/ifpga/version.map +++ b/drivers/raw/ifpga/version.map @@ -16,3 +16,14 @@ DPDK_22 { local: *; }; + +EXPERIMENTAL { + global: + + # added in 22.07 + rte_pmd_ifpga_image_load; + rte_pmd_ifpga_get_available_images; + rte_pmd_ifpga_set_poc_image; + rte_pmd_ifpga_get_poc_images; + rte_pmd_ifpga_read_flash; +};