Merge changes from topics "multi_pdev", "pcie_enum"
* changes:
feat(realm_host_mgmt): support multiple devices in DA test
refactor(lib/pcie): rename macro CHECK_DA_SUPPORT_IN_RMI
feat(lib/pcie): init pcie device capabilities
feat(lib/pcie): add dvsec helpers
fix(lib/pcie): import pcie enumeration helpers from rmm-acs
diff --git a/include/lib/pcie/pcie.h b/include/lib/pcie/pcie.h
index d7188a0..a08cd4a 100644
--- a/include/lib/pcie/pcie.h
+++ b/include/lib/pcie/pcie.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,7 @@
#ifndef PCIE_H
#define PCIE_H
+#include <stdbool.h>
#include <cdefs.h>
#include <stdint.h>
#include <utils_def.h>
@@ -14,6 +15,8 @@
/* platforms need to ensure that number of entries is less that this value */
#define MAX_PCIE_INFO_ENTRIES 5
+#define PCIE_DEVICES_MAX 128
+
typedef struct {
unsigned long ecam_base; /* ECAM base address */
unsigned int segment_num; /* Segment number of this ECAM */
@@ -26,14 +29,39 @@
pcie_info_block_t block[MAX_PCIE_INFO_ENTRIES];
};
-typedef struct {
- uint32_t bdf;
- uint32_t rp_bdf;
-} pcie_device_attr_t;
+/* Flags for PCIe device capability */
+#define PCIE_DEV_CFLAG_DOE (U(1) << 0)
+#define PCIE_DEV_CFLAG_IDE (U(1) << 1)
+#define PCIE_DEV_CFLAG_DVSEC_RMEDA (U(1) << 3)
-typedef struct __packed {
+#define pcie_dev_has_doe(_d) (((_d)->cflags & PCIE_DEV_CFLAG_DOE) != 0U)
+#define pcie_dev_has_ide(_d) (((_d)->cflags & PCIE_DEV_CFLAG_IDE) != 0U)
+#define pcie_dev_has_dvsec_rmeda(_d) \
+ (((_d)->cflags & PCIE_DEV_CFLAG_DVSEC_RMEDA) != 0U)
+
+struct pcie_dev {
+ uint32_t bdf;
+
+ /* Pointer to rootport device if this is a endpoint */
+ struct pcie_dev *rp_dev;
+
+ /* PCIe capabilities flags */
+ uint32_t cflags;
+
+ uint32_t doe_cap_base;
+ uint32_t ide_cap_base;
+ uint32_t dvsec_rmeda_cap_base;
+
+ /* Device port type */
+ uint32_t dp_type;
+
+ unsigned long ecam_base;
+};
+typedef struct pcie_dev pcie_dev_t;
+
+typedef struct {
uint32_t num_entries;
- pcie_device_attr_t device[]; /* in the format of Segment/Bus/Dev/Func */
+ pcie_dev_t device[PCIE_DEVICES_MAX];
} pcie_device_bdf_table_t;
/* Address initialisation structure */
@@ -71,9 +99,6 @@
#define PCIE_CAP_NOT_FOUND 0x10000010 /* The specified capability was not found */
#define PCIE_UNKNOWN_RESPONSE 0xFFFFFFFF /* Function not found or UR response from completer */
-/* Allows storage of 2048 valid BDFs */
-#define PCIE_DEVICE_BDF_TABLE_SZ 8192
-
typedef enum {
HEADER = 0,
PCIE_CAP = 1,
@@ -100,7 +125,7 @@
#define CC_BASE_SHIFT 24
void pcie_init(void);
-void pcie_create_info_table(void);
+
pcie_device_bdf_table_t *pcie_get_bdf_table(void);
uint32_t pcie_find_capability(uint32_t bdf, uint32_t cid_type, uint32_t cid,
uint32_t *cid_offset);
diff --git a/include/lib/pcie/pcie_doe.h b/include/lib/pcie/pcie_doe.h
index 777309a..2d9016d 100644
--- a/include/lib/pcie/pcie_doe.h
+++ b/include/lib/pcie/pcie_doe.h
@@ -91,23 +91,6 @@
uint8_t next_index;
} pcie_doe_disc_resp_t;
-/* Skip test if DA is not supported in RMI features */
-#define CHECK_DA_SUPPORT_IN_RMI(_reg0) \
- do { \
- SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP(); \
- /* Get feature register0 */ \
- if (host_rmi_features(0UL, &_reg0) != REALM_SUCCESS) { \
- ERROR("Failed to get RMI feat_reg0\n"); \
- return TEST_RESULT_FAIL; \
- } \
- \
- /* DA not supported in RMI features? */ \
- if ((_reg0 & RMI_FEATURE_REGISTER_0_DA_EN) == 0UL) { \
- WARN("DA not in RMI features, skipping\n"); \
- return TEST_RESULT_SKIPPED; \
- } \
- } while (false)
-
#define SKIP_TEST_IF_DOE_NOT_SUPPORTED(_bdf, _doe_cap_base) \
do { \
/* Test PCIe DOE only for RME */ \
diff --git a/include/lib/pcie/pcie_dvsec_rmeda.h b/include/lib/pcie/pcie_dvsec_rmeda.h
new file mode 100644
index 0000000..b693f2a
--- /dev/null
+++ b/include/lib/pcie/pcie_dvsec_rmeda.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PCIE_DVSEC_RME_DA_H
+#define PCIE_DVSEC_RME_DA_H
+
+/* PCI RootPort Extended Capability RMEDA registers offset */
+
+/*
+ * Extended Capability Header
+ * DVSEC Headers
+ * RME-DA Control registers
+ */
+#define PCIE_ECAP_ECH_OFFSET U(0)
+#define PCIE_ECAP_DVSEC_HDR1_OFFSET U(4)
+#define PCIE_ECAP_DVSEC_HDR2_OFFSET U(8)
+#define PCIE_ECAP_DVSEC_RME_DA_CTL_REG1_OFFSET U(12)
+#define PCIE_ECAP_DVSEC_RME_DA_CTL_REG2_OFFSET U(16)
+
+/* RME-DA DVSEC Header1 */
+#define DVSEC_HDR1_VENDOR_ID_SHIFT U(0)
+#define DVSEC_HDR1_VENDOR_ID_WIDTH U(16)
+#define DVSEC_HDR1_REVISION_SHIFT U(16)
+#define DVSEC_HDR1_REVISION_WIDTH U(4)
+#define DVSEC_HDR1_LENGTH_SHIFT U(20)
+#define DVSEC_HDR1_LENGTH_WIDTH U(12)
+
+/* RME-DA DVSEC Header1 - Values */
+#define DVSEC_VENDOR_ID_ARM U(0x13b5)
+#define DVSEC_REVISION_0 U(0x0)
+
+/* RME-DA DVSEC Header2 */
+#define DVSEC_HDR2_DVSEC_ID_SHIFT U(0)
+#define DVSEC_HDR2_DVSEC_ID_WIDTH U(16)
+
+/* RME-DA DVSEC Header2 - Values */
+#define DVSEC_ID_RME_DA U(0xFF01)
+
+/* RME-DA Control register 1 */
+#define DVSEC_RMEDA_CTL_REG1_TDISP_EN_SHIFT U(0)
+#define DVSEC_RMEDA_CTL_REG1_TDISP_EN_WIDTH U(1)
+
+/* RME-DA Control register 1 - Values */
+#define RME_DA_TDISP_DISABLE U(0)
+#define RME_DA_TDISP_ENABLE U(1)
+
+/* RME-DA Control register 2. 32 IDE Selective Stream Lock bits */
+#define DVSEC_RME_DA_CTL_REG2_SEL_STR_LOCK_SHIFT U(0)
+#define DVSEC_RME_DA_CTL_REG2_SEL_STR_LOCK_WIDTH U(32)
+
+uint32_t pcie_find_rmeda_capability(uint32_t bdf, uint32_t *cid_offset);
+
+#endif /* PCIE_DVSEC_RME_DA_H */
diff --git a/include/lib/pcie/pcie_spec.h b/include/lib/pcie/pcie_spec.h
index 31fd98b..cd851ee 100644
--- a/include/lib/pcie/pcie_spec.h
+++ b/include/lib/pcie/pcie_spec.h
@@ -87,6 +87,14 @@
#define PCIE_ECAP_CIDR_MASK 0xffff
#define PCIE_ECAP_NCPR_MASK 0xfff
+/* PCIe Extended Capability Header */
+#define PCIE_ECH_ID_SHIFT U(0)
+#define PCIE_ECH_ID_WIDTH U(16)
+#define PCIE_ECH_CAP_VER_SHIFT U(16)
+#define PCIE_ECH_CAP_VER_WIDTH U(4)
+#define PCIE_ECH_NEXT_CAP_OFFSET_SHIFT U(20)
+#define PCIE_ECH_NEXT_CAP_OFFSET_WIDTH U(12)
+
#define PCIE_CAP_START 0x40
#define PCIE_CAP_END 0xFC
#define PCIE_ECAP_START 0x100
@@ -107,6 +115,8 @@
#define ECID_PASID 0x001B
#define ECID_DPC 0x001D
#define ECID_DVSEC 0x0023
+#define ECID_DOE 0x002E
+#define ECID_IDE 0x0030
/* PCI Express capability struct offsets */
#define CIDR_OFFSET 0x0
diff --git a/include/plat/common/plat_pcie_enum.h b/include/plat/common/plat_pcie_enum.h
new file mode 100644
index 0000000..667fe05
--- /dev/null
+++ b/include/plat/common/plat_pcie_enum.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2025, Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_PCIE_ENUM_H__
+#define __PLAT_PCIE_ENUM_H__
+
+#include <stdio.h>
+#include <stdint.h>
+
+/* Header Offset and Type */
+#define HEADER_OFFSET 0xC
+#define TYPE0_HEADER 0
+#define TYPE1_HEADER 1
+
+#define TYPE01_RIDR 0x8
+
+#define DEVICE_ID_OFFSET 16
+
+/* Initial BUS definitions */
+#define PRI_BUS 0
+#define SEC_BUS 1
+#define BUS_NUM_REG_OFFSET 0x18
+
+/* BAR offset */
+#define BAR0_OFFSET 0x10
+#define TYPE1_BAR_MAX_OFF 0x14
+#define TYPE0_BAR_MAX_OFF 0x24
+
+#define BAR_NON_PRE_MEM 0
+#define BAR_PRE_MEM 0x1
+
+#define MEM_BASE32_LIM_MASK 0xFFF00000
+#define MEM_BASE64_LIM_MASK 0xFFFFFFFFFFF00000
+#define NON_PRE_FET_OFFSET 0x20
+#define PRE_FET_OFFSET 0x24
+#define BAR_INCREMENT 0x100000
+
+#define PRI_BUS_CLEAR_MASK 0xFFFFFF00
+
+#define TYPE0_MAX_BARS 6
+#define TYPE1_MAX_BARS 2
+
+/* BAR register masks */
+#define BAR_MIT_MASK 0x1
+#define BAR_MDT_MASK 0x3
+#define BAR_MT_MASK 0x1
+#define BAR_BASE_MASK 0xfffffff
+
+/* BAR register shifts */
+#define BAR_MIT_SHIFT 0
+#define BAR_MDT_SHIFT 1
+#define BAR_MT_SHIFT 3
+#define BAR_BASE_SHIFT 4
+
+/* TYPE 0/1 Cmn Cfg reg offsets and mask*/
+#define TYPE01_CPR 0x34
+#define TYPE01_CPR_MASK 0xff
+#define COMMAND_REG_OFFSET 0x04
+#define REG_ACC_DATA 0x7
+
+#define BAR_MASK 0xFFFFFFF0
+
+#define PCIE_HEADER_TYPE(header_value) ((header_value >> 16) & 0x3)
+#define BUS_NUM_REG_CFG(sub_bus, sec_bus, pri_bus) (sub_bus << 16 | sec_bus << 8 | bus)
+
+#define BAR_REG(bar_reg_value) ((bar_reg_value >> 2) & 0x1)
+#define BAR_MEM(bar_reg_value) ((bar_reg_value & 0xF) >> 3)
+#define REG_MASK_SHIFT(bar_value) ((bar_value & MEM_BASE32_LIM_MASK) >> 16)
+
+#endif /* __PLAT_PCIE_ENUM_H__ */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index e5032fa..077ccb3 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -208,6 +208,11 @@
*/
const struct pcie_info_table *plat_pcie_get_info_table(void);
+/* Retrieve platform PCIe bar config values */
+int plat_pcie_get_bar_config(uint64_t *bar64_val, uint64_t *rp_bar64_val,
+ uint32_t *bar32np_val, uint32_t *bar32p_val,
+ uint32_t *rp_bar32_val);
+
/*
* This function provides an address that is recognized as invalid for use
* as an entry point in the CPU_ON and CPU_SUSPEND calls on this platform.
diff --git a/include/runtime_services/host_realm_managment/host_da_helper.h b/include/runtime_services/host_realm_managment/host_da_helper.h
index 0f6bf6a..f650bef 100644
--- a/include/runtime_services/host_realm_managment/host_da_helper.h
+++ b/include/runtime_services/host_realm_managment/host_da_helper.h
@@ -8,10 +8,37 @@
#define HOST_DA_HELPER_H
#include <host_realm_rmi.h>
+#include <pcie.h>
+
+/*
+ * Skip DA test if any of the below check is true
+ * RMM is TRP
+ * FEAT_RME not supported
+ * DA is not supported in RMI features
+ */
+#define SKIP_DA_TEST_IF_PREREQS_NOT_MET(_reg0) \
+ do { \
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP(); \
+ \
+ /* Get feature register0 */ \
+ if (host_rmi_features(0UL, &_reg0) != REALM_SUCCESS) { \
+ ERROR("Failed to get RMI feat_reg0\n"); \
+ return TEST_RESULT_FAIL; \
+ } \
+ \
+ /* DA not supported in RMI features? */ \
+ if ((_reg0 & RMI_FEATURE_REGISTER_0_DA_EN) == 0UL) { \
+ WARN("DA not in RMI features, skipping\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (false)
/* SPDM_MAX_CERTIFICATE_CHAIN_SIZE is 64KB */
#define HOST_PDEV_CERT_LEN_MAX (64 * 1024)
+/* todo: This macro can come from platform layer */
+#define HOST_PDEV_MAX 32
+
/*
* Measurement max supported is 4KB.
* todo: This will be increased if device supports returning more measurements
@@ -45,9 +72,11 @@
size_t public_key_metadata_len;
unsigned char public_key_sig_algo;
- /* PCIe details: bdf, DOE, Stream id, IO range */
- uint32_t bdf;
- uint32_t doe_cap_base;
+ /* Is this device connected to TSM */
+ bool is_connected_to_tsm;
+
+ /* The PCIe device for this host_pdev */
+ pcie_dev_t *dev;
};
struct host_vdev {
@@ -82,16 +111,18 @@
size_t ifc_report_len;
};
+void host_pdevs_init(void);
+bool is_host_pdev_independently_attested(struct host_pdev *h_pdev);
int host_create_realm_with_feat_da(struct realm *realm);
int host_pdev_create(struct host_pdev *h_pdev);
int host_pdev_reclaim(struct host_pdev *h_pdev);
int host_pdev_setup(struct host_pdev *h_pdev);
int host_pdev_transition(struct host_pdev *h_pdev, unsigned char to_state);
-int host_assign_vdev_to_realm(struct realm *realm, struct host_pdev *h_pdev,
- struct host_vdev *h_vdev);
-int host_unassign_vdev_from_realm(struct realm *realm, struct host_pdev *h_pdev,
- struct host_vdev *h_vdev);
+int host_assign_vdev_to_realm(struct realm *realm, struct host_vdev *h_vdev,
+ unsigned long tdi_id, void *pdev_ptr);
+int host_unassign_vdev_from_realm(struct realm *realm, struct host_vdev *h_vdev);
+
u_register_t host_dev_mem_map(struct realm *realm, u_register_t dev_pa,
long map_level, u_register_t *dev_ipa);
diff --git a/include/runtime_services/host_realm_managment/host_realm_rmi.h b/include/runtime_services/host_realm_managment/host_realm_rmi.h
index 18e47a1..05570fd 100644
--- a/include/runtime_services/host_realm_managment/host_realm_rmi.h
+++ b/include/runtime_services/host_realm_managment/host_realm_rmi.h
@@ -1234,7 +1234,7 @@
/* Bits16: Segment ID */
SET_MEMBER_RMI(unsigned short segment_id, 0x10, 0x18);
/* Address: ECAM base address of the PCIe configuration space */
- SET_MEMBER_RMI(unsigned short ecam_addr, 0x18, 0x20);
+ SET_MEMBER_RMI(unsigned long ecam_addr, 0x18, 0x20);
/* Bits16: Root Port identifier */
SET_MEMBER_RMI(unsigned short root_id, 0x20, 0x28);
/* UInt64: Certificate identifier */
diff --git a/lib/pcie/pcie.c b/lib/pcie/pcie.c
index 8de2825..96e1fb9 100644
--- a/lib/pcie/pcie.c
+++ b/lib/pcie/pcie.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,17 +13,36 @@
#include <pcie.h>
#include <pcie_doe.h>
#include <pcie_spec.h>
+#include <pcie_dvsec_rmeda.h>
#include <platform.h>
+#include <plat_pcie_enum.h>
#include <tftf_lib.h>
#define PCIE_DEBUG VERBOSE
const struct pcie_info_table *g_pcie_info_table;
-pcie_device_bdf_table_t *g_pcie_bdf_table;
+static pcie_device_bdf_table_t *g_pcie_bdf_table;
+static pcie_device_bdf_table_t pcie_bdf_table;
-pcie_device_bdf_table_t pcie_bdf_table[PCIE_DEVICE_BDF_TABLE_SZ];
+static uint32_t g_pcie_index;
+static uint32_t g_enumerate;
-uintptr_t pcie_cfg_addr(uint32_t bdf)
+/* 64-bit address initialisation */
+static uint64_t g_bar64_p_start;
+static uint64_t g_rp_bar64_value;
+static uint64_t g_bar64_p_max;
+static uint32_t g_64_bus, g_bar64_size;
+
+/* 32-bit address initialisation */
+static uint32_t g_bar32_np_start;
+static uint32_t g_bar32_p_start;
+static uint32_t g_rp_bar32_value;
+static uint32_t g_bar32_np_max;
+static uint32_t g_bar32_p_max;
+static uint32_t g_np_bar_size, g_p_bar_size;
+static uint32_t g_np_bus, g_p_bus;
+
+static uintptr_t pcie_cfg_addr(uint32_t bdf)
{
uint32_t bus = PCIE_EXTRACT_BDF_BUS(bdf);
uint32_t dev = PCIE_EXTRACT_BDF_DEV(bdf);
@@ -102,7 +121,7 @@
* @param bdf - Function's Segment/Bus/Dev/Func in PCIE_CREATE_BDF format
* @return false If not a Host Bridge, true If it's a Host Bridge.
*/
-bool pcie_is_host_bridge(uint32_t bdf)
+static bool pcie_is_host_bridge(uint32_t bdf)
{
uint32_t reg_value = pcie_read_cfg(bdf, TYPE01_RIDR);
@@ -168,7 +187,7 @@
* @param bdf
* @return true if bdf is valid else false
*/
-bool pcie_check_device_valid(uint32_t bdf)
+static bool pcie_check_device_valid(uint32_t bdf)
{
(void) bdf;
/*
@@ -185,7 +204,7 @@
* @return Returns TRUE if the Function is on-chip peripheral, FALSE if it is
* not an on-chip peripheral
*/
-bool pcie_is_onchip_peripheral(uint32_t bdf)
+static bool pcie_is_onchip_peripheral(uint32_t bdf)
{
(void)bdf;
return false;
@@ -200,7 +219,7 @@
* (1 << 0b1100) for iEP_EP, (1 << 0b1011) for iEP_RP,
* (1 << PCIECR[7:4]) for any other device type.
*/
-uint32_t pcie_device_port_type(uint32_t bdf)
+static uint32_t pcie_device_port_type(uint32_t bdf)
{
uint32_t pciecs_base, reg_value, dp_type;
@@ -233,13 +252,13 @@
* @brief Returns BDF of the upstream Root Port of a pcie device function.
*
* @param bdf - Function's Segment/Bus/Dev/Func in PCIE_CREATE_BDF format
- * @param usrp_bdf - Upstream Rootport bdf in PCIE_CREATE_BDF format
- * @return 0 for success, 1 for failure.
+ * @return pcie_dev for success, NULL for failure.
*/
-uint32_t pcie_get_rootport(uint32_t bdf, uint32_t *rp_bdf)
+static pcie_dev_t *pcie_get_rootport(uint32_t bdf)
{
uint32_t seg_num, sec_bus, sub_bus;
uint32_t reg_value, dp_type, index = 0;
+ uint32_t rp_bdf;
dp_type = pcie_device_port_type(bdf);
@@ -247,43 +266,43 @@
/* If the device is RP or iEP_RP, set its rootport value to same */
if ((dp_type == RP) || (dp_type == iEP_RP)) {
- *rp_bdf = bdf;
- return 0;
+ return NULL;
}
/* If the device is RCiEP and RCEC, set RP as 0xff */
if ((dp_type == RCiEP) || (dp_type == RCEC)) {
- *rp_bdf = 0xffffffff;
- return 1;
+ return NULL;
}
assert(g_pcie_bdf_table != NULL);
while (index < g_pcie_bdf_table->num_entries) {
- *rp_bdf = g_pcie_bdf_table->device[index++].bdf;
+ rp_bdf = g_pcie_bdf_table->device[index].bdf;
/*
* Extract Secondary and Subordinate Bus numbers of the
* upstream Root port and check if the input function's
* bus number falls within that range.
*/
- reg_value = pcie_read_cfg(*rp_bdf, TYPE1_PBN);
- seg_num = PCIE_EXTRACT_BDF_SEG(*rp_bdf);
+ reg_value = pcie_read_cfg(rp_bdf, TYPE1_PBN);
+ seg_num = PCIE_EXTRACT_BDF_SEG(rp_bdf);
sec_bus = ((reg_value >> SECBN_SHIFT) & SECBN_MASK);
sub_bus = ((reg_value >> SUBBN_SHIFT) & SUBBN_MASK);
- dp_type = pcie_device_port_type(*rp_bdf);
+ dp_type = pcie_device_port_type(rp_bdf);
if (((dp_type == RP) || (dp_type == iEP_RP)) &&
- (sec_bus <= PCIE_EXTRACT_BDF_BUS(bdf)) &&
- (sub_bus >= PCIE_EXTRACT_BDF_BUS(bdf)) &&
- (seg_num == PCIE_EXTRACT_BDF_SEG(bdf)))
- return 0;
+ (sec_bus <= PCIE_EXTRACT_BDF_BUS(bdf)) &&
+ (sub_bus >= PCIE_EXTRACT_BDF_BUS(bdf)) &&
+ (seg_num == PCIE_EXTRACT_BDF_SEG(bdf))) {
+ return &g_pcie_bdf_table->device[index];
}
- /* Return failure */
- ERROR("PCIe Hierarchy fail: RP of bdf 0x%x not found\n", bdf);
- *rp_bdf = 0;
- return 1;
+ index++;
+ }
+
+ /* Return failure */
+ ERROR("PCIe Hierarchy fail: RP of bdf 0x%x not found\n", bdf);
+ return NULL;
}
/*
@@ -294,8 +313,9 @@
*/
static uint32_t pcie_populate_device_rootport(void)
{
- uint32_t bdf, rp_bdf;
+ uint32_t bdf;
pcie_device_bdf_table_t *bdf_tbl_ptr = g_pcie_bdf_table;
+ pcie_dev_t *rp_dev;
assert(bdf_tbl_ptr != NULL);
@@ -304,16 +324,125 @@
bdf = bdf_tbl_ptr->device[tbl_index].bdf;
/* Checks if the BDF has RootPort */
- pcie_get_rootport(bdf, &rp_bdf);
+ rp_dev = pcie_get_rootport(bdf);
- bdf_tbl_ptr->device[tbl_index].rp_bdf = rp_bdf;
- PCIE_DEBUG("Dev bdf: 0x%x RP bdf: 0x%x\n", bdf, rp_bdf);
+ bdf_tbl_ptr->device[tbl_index].rp_dev = rp_dev;
+
+ if (rp_dev != NULL) {
+ INFO("Dev bdf: 0x%x RP bdf: 0x%x\n", bdf,
+ rp_dev->bdf);
+ } else {
+ INFO("Dev bdf: 0x%x RP bdf: none\n", bdf);
+ }
}
return 0;
}
/*
+ * @brief Returns the header type of the input pcie device function
+ *
+ * @param bdf - Segment/Bus/Dev/Func in the format of PCIE_CREATE_BDF
+ * @return TYPE0_HEADER for functions with Type 0 config space header,
+ * TYPE1_HEADER for functions with Type 1 config space header,
+ */
+static uint32_t pcie_function_header_type(uint32_t bdf)
+{
+ /* Read four bytes of config space starting from cache line size register */
+ uint32_t reg_value = pcie_read_cfg(bdf, TYPE01_CLSR);
+
+ /* Extract header type register value */
+ reg_value = ((reg_value >> TYPE01_HTR_SHIFT) & TYPE01_HTR_MASK);
+
+ /* Header layout bits within header type register indicate the header type */
+ return ((reg_value >> HTR_HL_SHIFT) & HTR_HL_MASK);
+}
+
+/*
+ * @brief Returns the ECAM address of the input PCIe function
+ *
+ * @param bdf - Segment/Bus/Dev/Func in PCIE_CREATE_BDF format
+ * @return ECAM address if success, else NULL address
+ */
+static uintptr_t pcie_get_ecam_base(uint32_t bdf)
+{
+ uint8_t ecam_index = 0, sec_bus = 0, sub_bus;
+ uint16_t seg_num = (uint16_t)PCIE_EXTRACT_BDF_SEG(bdf);
+ uint32_t reg_value;
+ uintptr_t ecam_base = 0;
+
+ assert(g_pcie_info_table != NULL);
+
+ while (ecam_index < g_pcie_info_table->num_entries) {
+ /* Derive ECAM specific information */
+ const pcie_info_block_t *block = &g_pcie_info_table->block[ecam_index];
+
+ if (seg_num == block->segment_num) {
+ if (pcie_function_header_type(bdf) == TYPE0_HEADER) {
+ /* Return ecam_base if Type0 Header */
+ ecam_base = block->ecam_base;
+ break;
+ }
+
+ /* Check for Secondary/Subordinate bus if Type1 Header */
+ reg_value = pcie_read_cfg(bdf, TYPE1_PBN);
+ sec_bus = ((reg_value >> SECBN_SHIFT) & SECBN_MASK);
+ sub_bus = ((reg_value >> SUBBN_SHIFT) & SUBBN_MASK);
+
+ if ((sec_bus >= block->start_bus_num) &&
+ (sub_bus <= block->end_bus_num)) {
+ ecam_base = block->ecam_base;
+ break;
+ }
+ }
+ ecam_index++;
+ }
+
+ return ecam_base;
+}
+
+static void pcie_devices_init_fields(void)
+{
+ pcie_device_bdf_table_t *bdf_tbl_ptr = g_pcie_bdf_table;
+ pcie_dev_t *pcie_dev;
+ uint32_t status;
+ uint32_t base;
+ uint32_t bdf;
+
+ assert(bdf_tbl_ptr != NULL);
+
+ for (uint32_t i = 0; i < bdf_tbl_ptr->num_entries; i++) {
+ pcie_dev = &bdf_tbl_ptr->device[i];
+ bdf = pcie_dev->bdf;
+
+ pcie_dev->dp_type = pcie_device_port_type(bdf);
+ pcie_dev->ecam_base = pcie_get_ecam_base(bdf);
+
+ /* Has DOE? */
+ status = pcie_find_capability(bdf, PCIE_ECAP, ECID_DOE, &base);
+ if (status == PCIE_SUCCESS) {
+ pcie_dev->cflags |= PCIE_DEV_CFLAG_DOE;
+ pcie_dev->doe_cap_base = base;
+ }
+
+ /* Has IDE? */
+ status = pcie_find_capability(bdf, PCIE_ECAP, ECID_IDE, &base);
+ if (status == PCIE_SUCCESS) {
+ pcie_dev->cflags |= PCIE_DEV_CFLAG_IDE;
+ pcie_dev->ide_cap_base = base;
+ }
+
+ if (pcie_dev->dp_type == RP) {
+ status = pcie_find_rmeda_capability(bdf, &base);
+ if (status == PCIE_SUCCESS) {
+ pcie_dev->cflags |= PCIE_DEV_CFLAG_DVSEC_RMEDA;
+ pcie_dev->dvsec_rmeda_cap_base = base;
+ }
+ }
+ }
+}
+
+/*
* @brief Returns the BDF Table pointer
*
* @param None
@@ -334,7 +463,7 @@
*
* @return None
*/
-void pcie_create_device_bdf_table(void)
+static void pcie_create_device_bdf_table(void)
{
uint32_t seg_num, start_bus, end_bus;
uint32_t bus_index, dev_index, func_index, ecam_index;
@@ -386,6 +515,8 @@
g_pcie_bdf_table->device[
g_pcie_bdf_table->num_entries++].bdf = bdf;
+
+ assert(g_pcie_bdf_table->num_entries < PCIE_DEVICES_MAX);
}
}
}
@@ -394,79 +525,24 @@
/* Sanity Check : Confirm all EP (normal, integrated) have a rootport */
pcie_populate_device_rootport();
+
+ /*
+ * Once devices are enumerated and rootports are assigned, initialize
+ * the rest of pcie_dev fields
+ */
+ pcie_devices_init_fields();
+
INFO("Number of BDFs found : %u\n", g_pcie_bdf_table->num_entries);
}
/*
- * @brief Returns the header type of the input pcie device function
- *
- * @param bdf - Segment/Bus/Dev/Func in the format of PCIE_CREATE_BDF
- * @return TYPE0_HEADER for functions with Type 0 config space header,
- * TYPE1_HEADER for functions with Type 1 config space header,
- */
-uint32_t pcie_function_header_type(uint32_t bdf)
-{
- /* Read four bytes of config space starting from cache line size register */
- uint32_t reg_value = pcie_read_cfg(bdf, TYPE01_CLSR);
-
- /* Extract header type register value */
- reg_value = ((reg_value >> TYPE01_HTR_SHIFT) & TYPE01_HTR_MASK);
-
- /* Header layout bits within header type register indicate the header type */
- return ((reg_value >> HTR_HL_SHIFT) & HTR_HL_MASK);
-}
-
-/*
- * @brief Returns the ECAM address of the input PCIe function
- *
- * @param bdf - Segment/Bus/Dev/Func in PCIE_CREATE_BDF format
- * @return ECAM address if success, else NULL address
- */
-uintptr_t pcie_get_ecam_base(uint32_t bdf)
-{
- uint8_t ecam_index = 0, sec_bus = 0, sub_bus;
- uint16_t seg_num = (uint16_t)PCIE_EXTRACT_BDF_SEG(bdf);
- uint32_t reg_value;
- uintptr_t ecam_base = 0;
-
- assert(g_pcie_info_table != NULL);
-
- while (ecam_index < g_pcie_info_table->num_entries) {
- /* Derive ECAM specific information */
- const pcie_info_block_t *block = &g_pcie_info_table->block[ecam_index];
-
- if (seg_num == block->segment_num) {
- if (pcie_function_header_type(bdf) == TYPE0_HEADER) {
- /* Return ecam_base if Type0 Header */
- ecam_base = block->ecam_base;
- break;
- }
-
- /* Check for Secondary/Subordinate bus if Type1 Header */
- reg_value = pcie_read_cfg(bdf, TYPE1_PBN);
- sec_bus = ((reg_value >> SECBN_SHIFT) & SECBN_MASK);
- sub_bus = ((reg_value >> SUBBN_SHIFT) & SUBBN_MASK);
-
- if ((sec_bus >= block->start_bus_num) &&
- (sub_bus <= block->end_bus_num)) {
- ecam_base = block->ecam_base;
- break;
- }
- }
- ecam_index++;
- }
-
- return ecam_base;
-}
-
-/*
* @brief This API prints all the PCIe Devices info
* 1. Caller - Validation layer.
* 2. Prerequisite - val_pcie_create_info_table()
* @param None
* @return None
*/
-void pcie_print_device_info(void)
+static void pcie_print_device_info(void)
{
uint32_t bdf, dp_type;
uint32_t tbl_index = 0;
@@ -596,19 +672,12 @@
* @param void
* @return void
*/
-void pcie_create_info_table(void)
+static void pcie_create_info_table(void)
{
unsigned int num_ecam;
INFO("Creating PCIe info table\n");
-
- g_pcie_info_table = plat_pcie_get_info_table();
- if (g_pcie_info_table == NULL) {
- ERROR("PCIe info not returned by platform\n");
- panic();
- }
-
- g_pcie_bdf_table = pcie_bdf_table;
+ g_pcie_bdf_table = &pcie_bdf_table;
num_ecam = g_pcie_info_table->num_entries;
INFO("Number of ECAM regions : %u\n", num_ecam);
@@ -620,12 +689,611 @@
pcie_print_device_info();
}
+static void pal_pci_cfg_write(uint32_t bus, uint32_t dev, uint32_t func,
+ uint32_t offset, uint32_t data)
+{
+ pcie_write_cfg(PCIE_CREATE_BDF(0, bus, dev, func), offset, data);
+}
+
+static void pal_pci_cfg_read(uint32_t bus, uint32_t dev, uint32_t func,
+ uint32_t offset, uint32_t *value)
+{
+ *value = pcie_read_cfg(PCIE_CREATE_BDF(0, bus, dev, func), offset);
+}
+
+/*
+ * This API programs the Memory Base and Memeory limit register of the Bus,
+ * Device and Function of Type1 Header
+ */
+static void get_resource_base_32(uint32_t bus, uint32_t dev, uint32_t func,
+ uint32_t bar32_p_base, uint32_t bar32_np_base,
+ uint32_t bar32_p_limit, uint32_t bar32_np_limit)
+{
+ uint32_t mem_bar_np;
+ uint32_t mem_bar_p;
+
+ /* Update the 32 bit NP-BAR start address for the next iteration */
+ if (bar32_np_base != g_bar32_np_start) {
+ if ((g_bar32_np_start << 12) != 0) {
+ g_bar32_np_start = (g_bar32_np_start &
+ MEM_BASE32_LIM_MASK) + BAR_INCREMENT;
+ }
+
+ if (bar32_np_limit == g_bar32_np_start) {
+ bar32_np_limit = bar32_np_limit - BAR_INCREMENT;
+ }
+
+ pal_pci_cfg_read(bus, dev, func, NON_PRE_FET_OFFSET,
+ &mem_bar_np);
+ mem_bar_np = ((bar32_np_limit & MEM_BASE32_LIM_MASK) |
+ mem_bar_np);
+ pal_pci_cfg_write(bus, dev, func, NON_PRE_FET_OFFSET,
+ mem_bar_np);
+ }
+
+ /* Update the 32 bit P-BAR start address for the next iteration */
+ if (bar32_p_base != g_bar32_p_start) {
+ if ((g_bar32_p_start << 12) != 0) {
+ g_bar32_p_start = (g_bar32_p_start &
+ MEM_BASE32_LIM_MASK) + BAR_INCREMENT;
+ }
+
+ if (bar32_p_limit == g_bar32_p_start) {
+ bar32_p_limit = bar32_p_limit - BAR_INCREMENT;
+ }
+
+ pal_pci_cfg_read(bus, dev, func, PRE_FET_OFFSET, &mem_bar_p);
+ mem_bar_p = ((bar32_p_limit & MEM_BASE32_LIM_MASK) | mem_bar_p);
+ pal_pci_cfg_write(bus, dev, func, PRE_FET_OFFSET, mem_bar_p);
+ }
+}
+
+/*
+ * This API programs the Memory Base and Memeory limit register of the Bus,
+ * Device and Function of Type1 Header
+ */
+static void get_resource_base_64(uint32_t bus, uint32_t dev, uint32_t func,
+ uint64_t bar64_p_base, uint64_t g_bar64_p_max)
+{
+ uint32_t bar64_p_lower32_base = (uint32_t)bar64_p_base;
+ uint32_t bar64_p_upper32_base = (uint32_t)(bar64_p_base >> 32);
+ uint32_t bar64_p_lower32_limit = (uint32_t)g_bar64_p_max;
+ uint32_t bar64_p_upper32_limit = (uint32_t)(g_bar64_p_max >> 32);
+
+ /* Obtain the memory base and memory limit */
+ bar64_p_lower32_base = REG_MASK_SHIFT(bar64_p_lower32_base);
+ bar64_p_lower32_limit = REG_MASK_SHIFT(bar64_p_lower32_limit);
+ uint32_t mem_bar_p = ((bar64_p_lower32_limit << 16) |
+ bar64_p_lower32_base);
+
+ /* Configure Memory base and Memory limit register */
+ if ((bar64_p_base != g_bar64_p_max) && (g_bar64_p_start <=
+ g_bar64_p_max)) {
+ if ((g_bar64_p_start << 12) != 0) {
+ g_bar64_p_start = (g_bar64_p_start &
+ MEM_BASE64_LIM_MASK) + BAR_INCREMENT;
+ }
+
+ if (bar64_p_lower32_limit == g_bar64_p_start) {
+ bar64_p_lower32_limit = bar64_p_lower32_limit -
+ BAR_INCREMENT;
+ }
+
+ g_bar64_p_start = (g_bar64_p_start & MEM_BASE64_LIM_MASK) +
+ BAR_INCREMENT;
+
+ pal_pci_cfg_write(bus, dev, func, PRE_FET_OFFSET, mem_bar_p);
+ pal_pci_cfg_write(bus, dev, func, PRE_FET_OFFSET + 4,
+ bar64_p_upper32_base);
+ pal_pci_cfg_write(bus, dev, func, PRE_FET_OFFSET + 8,
+ bar64_p_upper32_limit);
+ }
+}
+
+static void pcie_rp_program_bar(uint32_t bus, uint32_t dev, uint32_t func)
+{
+ uint64_t bar_size, bar_upper_bits;
+ uint32_t offset = BAR0_OFFSET;
+ uint32_t bar_reg_value, bar_lower_bits;
+
+ while (offset <= TYPE1_BAR_MAX_OFF) {
+ pal_pci_cfg_read(bus, dev, func, offset, &bar_reg_value);
+
+ if (BAR_REG(bar_reg_value) == BAR_64_BIT) {
+ /*
+ * BAR supports 64-bit address therefore, write all 1's
+ * to BARn and BARn+1 and identify the size requested
+ */
+ pal_pci_cfg_write(bus, dev, func, offset, 0xFFFFFFF0);
+ pal_pci_cfg_write(bus, dev, func, offset + 4,
+ 0xFFFFFFFF);
+ pal_pci_cfg_read(bus, dev, func, offset,
+ &bar_lower_bits);
+ bar_size = bar_lower_bits & BAR_MASK;
+
+ pal_pci_cfg_read(bus, dev, func, offset + 4,
+ &bar_reg_value);
+ bar_upper_bits = bar_reg_value;
+ bar_size = bar_size | (bar_upper_bits << 32);
+
+ bar_size = ~bar_size + 1;
+
+ /*
+ * If BAR size is 0, then BAR not implemented, move to
+ * next BAR
+ */
+ if (bar_size == 0) {
+ offset = offset + 8;
+ continue;
+ }
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ (uint32_t)g_rp_bar64_value);
+ pal_pci_cfg_write(bus, dev, func, offset + 4,
+ (uint32_t)(g_rp_bar64_value >> 32));
+ offset = offset + 8;
+ } else {
+ /*
+ * BAR supports 32-bit address. Write all 1's to BARn
+ * and identify the size requested
+ */
+ pal_pci_cfg_write(bus, dev, func, offset, 0xFFFFFFF0);
+ pal_pci_cfg_read(bus, dev, func, offset,
+ &bar_lower_bits);
+ bar_reg_value = bar_lower_bits & BAR_MASK;
+ bar_size = ~bar_reg_value + 1;
+
+ /*
+ * If BAR size is 0, then BAR not implemented, move to
+ * next BAR
+ */
+ if (bar_size == 0) {
+ offset = offset + 4;
+ continue;
+ }
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ g_rp_bar32_value);
+ g_rp_bar32_value = g_rp_bar32_value + (uint32_t)bar_size;
+ offset = offset + 4;
+ }
+ }
+}
+
+/*
+ * This API programs all the BAR register in PCIe config space pointed by Bus,
+ * Device and Function for an End Point PCIe device
+ */
+static void pcie_program_bar_reg(uint32_t bus, uint32_t dev, uint32_t func)
+{
+ uint64_t bar_size, bar_upper_bits;
+ uint32_t bar_reg_value, bar_lower_bits;
+ uint32_t offset = BAR0_OFFSET;
+ uint32_t np_bar_size = 0;
+ uint32_t p_bar_size = 0, p_bar64_size = 0;
+
+ while (offset <= TYPE0_BAR_MAX_OFF) {
+ pal_pci_cfg_read(bus, dev, func, offset, &bar_reg_value);
+
+ if (BAR_MEM(bar_reg_value) == BAR_PRE_MEM) {
+ if (BAR_REG(bar_reg_value) == BAR_64_BIT) {
+ /*
+ * BAR supports 64-bit address therefore,
+ * write all 1's to BARn and BARn+1 and identify
+ * the size requested
+ */
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ 0xFFFFFFF0);
+ pal_pci_cfg_write(bus, dev, func, offset + 4,
+ 0xFFFFFFFF);
+ pal_pci_cfg_read(bus, dev, func, offset,
+ &bar_lower_bits);
+ bar_size = bar_lower_bits & BAR_MASK;
+
+ pal_pci_cfg_read(bus, dev, func, offset + 4,
+ &bar_reg_value);
+ bar_upper_bits = bar_reg_value;
+ bar_size = bar_size | (bar_upper_bits << 32);
+
+ bar_size = ~bar_size + 1;
+
+ /*
+ * If BAR size is 0, then BAR not implemented,
+ * move to next BAR
+ */
+ if (bar_size == 0) {
+ offset = offset + 8;
+ continue;
+ }
+
+ /*
+ * If p_bar64_size = 0 and bus number is same as
+ * bus of previous bus number, then check if the
+ * current PCIe Device BAR size is greater than
+ * the previous BAR size, if yes then add current
+ * BAR size to the updated start address else
+ * add the previous BAR size to the updated
+ * start address
+ */
+ if ((p_bar64_size == 0) && ((g_64_bus == bus))) {
+ if (g_bar64_size < bar_size) {
+ g_bar64_p_start =
+ g_bar64_p_start +
+ bar_size;
+ } else {
+ g_bar64_p_start =
+ g_bar64_p_start +
+ g_bar64_size;
+ }
+ } else if ((g_bar64_size < bar_size) &&
+ (p_bar64_size != 0)) {
+ g_bar64_p_start = g_bar64_p_start +
+ bar_size;
+ } else {
+ g_bar64_p_start = g_bar64_p_start +
+ p_bar64_size;
+ }
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ (uint32_t)g_bar64_p_start);
+ pal_pci_cfg_write(bus, dev, func, offset + 4,
+ (uint32_t)(g_bar64_p_start >>
+ 32));
+
+ p_bar64_size = (uint32_t)bar_size;
+ g_bar64_size = (uint32_t)bar_size;
+ g_64_bus = bus;
+ offset = offset + 8;
+ } else {
+ /*
+ * BAR supports 32-bit address. Write all 1's
+ * to BARn and identify the size requested
+ */
+ pal_pci_cfg_write(bus, dev, func, offset,
+ 0xFFFFFFF0);
+ pal_pci_cfg_read(bus, dev, func, offset,
+ &bar_lower_bits);
+ bar_reg_value = bar_lower_bits & BAR_MASK;
+ bar_size = ~bar_reg_value + 1;
+
+ /*
+ * If BAR size is 0, then BAR not implemented,
+ * move to next BAR
+ */
+ if (bar_size == 0) {
+ offset = offset + 4;
+ continue;
+ }
+
+ /*
+ * If p_bar_size = 0 and bus number is same as
+ * bus of previous bus number, then check if the
+ * current PCIe Device BAR size is greater than
+ * the previous BAR size, if yes then add
+ * current BAR size to the updated start
+ * address else add the previous BAR size to the
+ * updated start address
+ */
+ if ((p_bar_size == 0) && ((g_p_bus == bus))) {
+ if (g_p_bar_size < bar_size) {
+ g_bar32_p_start =
+ g_bar32_p_start +
+ (uint32_t)bar_size;
+ } else {
+ g_bar32_p_start =
+ g_bar32_p_start +
+ g_p_bar_size;
+ }
+ } else if ((g_p_bar_size < bar_size) &&
+ (p_bar_size != 0)) {
+ g_bar32_p_start = g_bar32_p_start +
+ (uint32_t)bar_size;
+ } else {
+ g_bar32_p_start = g_bar32_p_start +
+ p_bar_size;
+ }
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ g_bar32_p_start);
+ p_bar_size = (uint32_t)bar_size;
+ g_p_bar_size = (uint32_t)bar_size;
+ g_p_bus = bus;
+
+ offset = offset + 4;
+ }
+ } else {
+ /*
+ * BAR supports 32-bit address. Write all 1's to BARn
+ * and identify the size requested
+ */
+ pal_pci_cfg_write(bus, dev, func, offset, 0xFFFFFFF0);
+ pal_pci_cfg_read(bus, dev, func, offset,
+ &bar_lower_bits);
+ bar_reg_value = bar_lower_bits & BAR_MASK;
+ bar_size = ~bar_reg_value + 1;
+
+ /*
+ * If BAR size is 0, then BAR not implemented, move to
+ * next BAR
+ */
+ if (bar_size == 0) {
+ if (BAR_REG(bar_lower_bits) == BAR_64_BIT) {
+ offset = offset + 8;
+ }
+
+ if (BAR_REG(bar_lower_bits) == BAR_32_BIT) {
+ offset = offset + 4;
+ }
+
+ continue;
+ }
+
+ /*
+ * If np_bar_size = 0 and bus number is same as bus of
+ * previous bus number, then check if the current PCIe
+ * Device BAR size is greater than the previous BAR
+ * size, if yes then add current BAR size to the
+ * updated start address else add the previous BAR size
+ * to the updated start address
+ */
+ if ((np_bar_size == 0) && ((g_np_bus == bus))) {
+ if (g_np_bar_size < bar_size) {
+ g_bar32_np_start = g_bar32_np_start +
+ (uint32_t)bar_size;
+ } else {
+ g_bar32_np_start = g_bar32_np_start +
+ g_np_bar_size;
+ }
+ } else if ((g_np_bar_size < bar_size) &&
+ (np_bar_size != 0)) {
+ g_bar32_np_start = g_bar32_np_start +
+ (uint32_t)bar_size;
+ } else {
+ g_bar32_np_start = g_bar32_np_start +
+ np_bar_size;
+ }
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ g_bar32_np_start);
+ np_bar_size = (uint32_t)bar_size;
+ g_np_bar_size = (uint32_t)bar_size;
+ g_np_bus = bus;
+
+ pal_pci_cfg_read(bus, dev, func, offset, &bar_reg_value);
+ if (BAR_REG(bar_reg_value) == BAR_64_BIT) {
+ pal_pci_cfg_write(bus, dev, func,
+ offset + 4, 0);
+ offset = offset + 8;
+ }
+
+ if (BAR_REG(bar_reg_value) == BAR_32_BIT) {
+ offset = offset + 4;
+ }
+ }
+
+ g_bar32_p_max = g_bar32_p_start;
+ g_bar32_np_max = g_bar32_np_start;
+ g_bar64_p_max = g_bar64_p_start;
+ }
+}
+
+/*
+ * This API performs the PCIe bus enumeration
+ *
+ * bus,sec_bus - Bus(8-bits), secondary bus (8-bits)
+ * sub_bus - Subordinate bus
+ */
+static uint32_t pcie_enumerate_device(uint32_t bus, uint32_t sec_bus)
+{
+ uint32_t vendor_id = 0;
+ uint32_t header_value;
+ uint32_t sub_bus = bus;
+ uint32_t dev;
+ uint32_t func;
+ uint32_t class_code;
+ uint32_t com_reg_value;
+ uint32_t bar32_p_limit;
+ uint32_t bar32_np_limit;
+ uint32_t bar32_p_base = g_bar32_p_start;
+ uint32_t bar32_np_base = g_bar32_np_start;
+ uint64_t bar64_p_base = g_bar64_p_start;
+
+ if (bus == ((g_pcie_info_table->block[g_pcie_index].end_bus_num) + 1)) {
+ return sub_bus;
+ }
+
+ for (dev = 0; dev < PCIE_MAX_DEV; dev++) {
+ for (func = 0; func < PCIE_MAX_FUNC; func++) {
+ pal_pci_cfg_read(bus, dev, func, 0, &vendor_id);
+
+ if ((vendor_id == 0x0) || (vendor_id == 0xFFFFFFFF)) {
+ continue;
+ }
+
+ /* Skip Hostbridge configuration */
+ pal_pci_cfg_read(bus, dev, func, TYPE01_RIDR,
+ &class_code);
+
+ if ((((class_code >> CC_BASE_SHIFT) & CC_BASE_MASK) ==
+ HB_BASE_CLASS) &&
+ (((class_code >> CC_SUB_SHIFT) & CC_SUB_MASK)) ==
+ HB_SUB_CLASS) {
+ continue;
+ }
+
+ pal_pci_cfg_read(bus, dev, func, HEADER_OFFSET,
+ &header_value);
+ if (PCIE_HEADER_TYPE(header_value) == TYPE1_HEADER) {
+ /*
+ * Enable memory access, Bus master enable and
+ * I/O access
+ */
+ pal_pci_cfg_read(bus, dev, func,
+ COMMAND_REG_OFFSET,
+ &com_reg_value);
+
+ pal_pci_cfg_write(bus, dev, func,
+ COMMAND_REG_OFFSET,
+ (com_reg_value |
+ REG_ACC_DATA));
+
+ pal_pci_cfg_write(bus, dev, func,
+ BUS_NUM_REG_OFFSET,
+ BUS_NUM_REG_CFG(0xFF, sec_bus,
+ bus));
+
+ pal_pci_cfg_write(bus, dev, func,
+ NON_PRE_FET_OFFSET,
+ ((g_bar32_np_start >> 16) &
+ 0xFFF0));
+
+ pal_pci_cfg_write(bus, dev, func,
+ PRE_FET_OFFSET,
+ ((g_bar32_p_start >> 16) &
+ 0xFFF0));
+
+ sub_bus = pcie_enumerate_device(sec_bus,
+ (sec_bus + 1));
+ pal_pci_cfg_write(bus, dev, func,
+ BUS_NUM_REG_OFFSET,
+ BUS_NUM_REG_CFG(sub_bus,
+ sec_bus, bus));
+ sec_bus = sub_bus + 1;
+
+ /*
+ * Obtain the start memory base address & the
+ * final memory base address of 32 bit BAR
+ */
+ bar32_p_limit = g_bar32_p_max;
+ bar32_np_limit = g_bar32_np_max;
+
+ get_resource_base_32(bus, dev, func,
+ bar32_p_base,
+ bar32_np_base,
+ bar32_p_limit,
+ bar32_np_limit);
+
+ /*
+ * Obtain the start memory base address & the
+ * final memory base address of 64 bit BAR
+ */
+ get_resource_base_64(bus, dev, func,
+ bar64_p_base,
+ g_bar64_p_max);
+
+ /* Update the BAR values of Type 1 Devices */
+ pcie_rp_program_bar(bus, dev, func);
+
+ /* Update the base and limit values */
+ bar32_p_base = g_bar32_p_start;
+ bar32_np_base = g_bar32_np_start;
+ bar64_p_base = g_bar64_p_start;
+ }
+
+ if (PCIE_HEADER_TYPE(header_value) == TYPE0_HEADER) {
+ pcie_program_bar_reg(bus, dev, func);
+ sub_bus = sec_bus - 1;
+ }
+ }
+ }
+
+ return sub_bus;
+}
+
+/*
+ * This API clears the primary bus number configured in the Type1 Header.
+ * Note: This is done to make sure the hardware is compatible
+ * with Linux enumeration.
+ */
+static void pcie_clear_pri_bus(void)
+{
+ uint32_t bus;
+ uint32_t dev;
+ uint32_t func;
+ uint32_t bus_value;
+ uint32_t header_value;
+ uint32_t vendor_id;
+
+ for (bus = 0; bus <= g_pcie_info_table->block[g_pcie_index].end_bus_num;
+ bus++) {
+ for (dev = 0; dev < PCIE_MAX_DEV; dev++) {
+ for (func = 0; func < PCIE_MAX_FUNC; func++) {
+ pal_pci_cfg_read(bus, dev, func, 0, &vendor_id);
+
+ if ((vendor_id == 0x0) ||
+ (vendor_id == 0xFFFFFFFF)) {
+ continue;
+ }
+
+ pal_pci_cfg_read(bus, dev, func, HEADER_OFFSET,
+ &header_value);
+ if (PCIE_HEADER_TYPE(header_value) ==
+ TYPE1_HEADER) {
+ pal_pci_cfg_read(bus, dev, func,
+ BUS_NUM_REG_OFFSET,
+ &bus_value);
+
+ bus_value = bus_value &
+ PRI_BUS_CLEAR_MASK;
+
+ pal_pci_cfg_write(bus, dev, func,
+ BUS_NUM_REG_OFFSET,
+ bus_value);
+ }
+ }
+ }
+ }
+}
+
+static void pcie_enumerate_devices(void)
+{
+ uint32_t pri_bus, sec_bus;
+ int rc;
+
+ g_pcie_info_table = plat_pcie_get_info_table();
+ if (g_pcie_info_table == NULL) {
+ ERROR("PCIe info not returned by platform\n");
+ panic();
+ }
+
+ if (g_pcie_info_table->num_entries == 0) {
+ INFO("Skipping Enumeration\n");
+ return;
+ }
+
+ /* Get platform specific bar config parameters */
+ rc = plat_pcie_get_bar_config(&g_bar64_p_start, &g_rp_bar64_value,
+ &g_bar32_np_start, &g_bar32_p_start,
+ &g_rp_bar32_value);
+ if (rc != 0) {
+ ERROR("PCIe bar config parameters not returned by platform\n");
+ panic();
+ }
+
+ INFO("Starting Enumeration\n");
+ while (g_pcie_index < g_pcie_info_table->num_entries) {
+ pri_bus = g_pcie_info_table->block[g_pcie_index].start_bus_num;
+
+ sec_bus = pri_bus + 1;
+
+ pcie_enumerate_device(pri_bus, sec_bus);
+ pcie_clear_pri_bus();
+
+ g_pcie_index++;
+ }
+ g_enumerate = 0;
+ g_pcie_index = 0;
+}
+
void pcie_init(void)
{
static bool is_init;
/* Create PCIe table and enumeration */
if (!is_init) {
+ pcie_enumerate_devices();
+
pcie_create_info_table();
is_init = true;
}
diff --git a/lib/pcie/pcie_doe.c b/lib/pcie/pcie_doe.c
index bd8e53a..e1d6449 100644
--- a/lib/pcie/pcie_doe.c
+++ b/lib/pcie/pcie_doe.c
@@ -13,6 +13,7 @@
#include <debug.h>
#include <pcie.h>
+#include <pcie_spec.h>
#include <pcie_doe.h>
#include <tftf_lib.h>
@@ -241,10 +242,12 @@
return rc;
}
+/* TODO: add an iterator interface to get next eligible device */
int pcie_find_doe_device(uint32_t *bdf_ptr, uint32_t *cap_base_ptr)
{
pcie_device_bdf_table_t *bdf_table_ptr = pcie_get_bdf_table();
uint32_t num_bdf = bdf_table_ptr->num_entries;
+ pcie_dev_t *dev;
INFO("PCI BDF table entries: %u\n", num_bdf);
@@ -257,15 +260,13 @@
INFO("PCI BDF table 0x%lx\n", (uintptr_t)bdf_table_ptr);
while (num_bdf-- != 0) {
- uint32_t bdf = bdf_table_ptr->device[num_bdf].bdf;
- uint32_t status, doe_cap_base;
+ dev = &bdf_table_ptr->device[num_bdf];
- /* Check for DOE capability */
- status = pcie_find_capability(bdf, PCIE_ECAP, DOE_CAP_ID, &doe_cap_base);
- if (status == PCIE_SUCCESS) {
- INFO("PCIe DOE capability: bdf 0x%x cap_base 0x%x\n", bdf, doe_cap_base);
- *bdf_ptr = bdf;
- *cap_base_ptr = doe_cap_base;
+ if ((dev->dp_type == EP) && (pcie_dev_has_doe(dev))) {
+ INFO("PCIe DOE capability: bdf 0x%x cap_base 0x%x\n",
+ dev->bdf, dev->doe_cap_base);
+ *bdf_ptr = dev->bdf;
+ *cap_base_ptr = dev->doe_cap_base;
return 0;
}
}
diff --git a/lib/pcie/pcie_dvsec_rmeda.c b/lib/pcie/pcie_dvsec_rmeda.c
new file mode 100644
index 0000000..c1da99a
--- /dev/null
+++ b/lib/pcie/pcie_dvsec_rmeda.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common_def.h>
+#include <errno.h>
+#include <stddef.h>
+#include <debug.h>
+#include <mmio.h>
+#include <pcie.h>
+#include <pcie_spec.h>
+#include <pcie_dvsec_rmeda.h>
+#include <platform.h>
+#include <tftf_lib.h>
+
+/*
+ * Check if the DVSEC header matches RME Sys Arch spec
+ *
+ * DVSEC_REVISION must be 0
+ * DVSEC_VENDOR_ID must be Arm
+ * DVSEC_ID must be RME_DA
+ */
+static bool is_dvsec_arm_rmeda(uint32_t rp_bdf, uint32_t dvsec_base)
+{
+ uint32_t hdr1 = 0U;
+ uint32_t hdr2 = 0U;
+
+ hdr1 = pcie_read_cfg(rp_bdf, dvsec_base + PCIE_ECAP_DVSEC_HDR1_OFFSET);
+ hdr2 = pcie_read_cfg(rp_bdf, dvsec_base + PCIE_ECAP_DVSEC_HDR2_OFFSET);
+
+ if ((EXTRACT(DVSEC_HDR1_VENDOR_ID, hdr1) == DVSEC_VENDOR_ID_ARM) &&
+ (EXTRACT(DVSEC_HDR1_REVISION, hdr1) == DVSEC_REVISION_0) &&
+ (EXTRACT(DVSEC_HDR2_DVSEC_ID, hdr2) == DVSEC_ID_RME_DA)) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Traverse all DVSEC extended capability and return the first RMEDA DVSEC if the
+ * header, revision are expected as mentioned in RME System Architecture.
+ */
+uint32_t pcie_find_rmeda_capability(uint32_t rp_bdf, uint32_t *cid_offset)
+{
+ uint32_t ech;
+ unsigned int dvsec_offset;
+ uint16_t next_cap_offset;
+
+ dvsec_offset = PCIE_ECAP_START;
+ do {
+ assert((dvsec_offset + sizeof(ech)) < SZ_4K);
+
+ ech = pcie_read_cfg(rp_bdf, dvsec_offset);
+
+ /* Check for PCIE_ECH_CAP_VER_1 as well? */
+ if ((EXTRACT(PCIE_ECH_ID, ech) == ECID_DVSEC) &&
+ is_dvsec_arm_rmeda(rp_bdf, dvsec_offset)) {
+ *cid_offset = dvsec_offset;
+ return PCIE_SUCCESS;
+ }
+
+ next_cap_offset = EXTRACT(PCIE_ECH_NEXT_CAP_OFFSET, ech);
+ dvsec_offset += next_cap_offset;
+ } while ((next_cap_offset != 0U) && (dvsec_offset < PCIE_ECAP_END));
+
+ return PCIE_CAP_NOT_FOUND;
+}
diff --git a/plat/arm/fvp/fvp_pcie.c b/plat/arm/fvp/fvp_pcie.c
index 38bdf39..4bba516 100644
--- a/plat/arm/fvp/fvp_pcie.c
+++ b/plat/arm/fvp/fvp_pcie.c
@@ -27,6 +27,28 @@
return &fvp_pcie_cfg;
}
+/* Retrieve platform PCIe bar config values */
+int plat_pcie_get_bar_config(uint64_t *bar64_val, uint64_t *rp_bar64_val,
+ uint32_t *bar32np_val, uint32_t *bar32p_val,
+ uint32_t *rp_bar32_val)
+{
+#ifdef __aarch64__
+ assert((bar64_val != NULL) && (rp_bar64_val != NULL) &&
+ (bar32np_val != NULL) && (bar32p_val != NULL) &&
+ (rp_bar32_val != NULL));
+
+ *bar64_val = PLATFORM_OVERRIDE_PCIE_BAR64_VALUE;
+ *rp_bar64_val = PLATFORM_OVERRIDE_RP_BAR64_VALUE;
+
+ *bar32np_val = PLATFORM_OVERRIDE_PCIE_BAR32NP_VALUE;
+ *bar32p_val = PLATFORM_OVERRIDE_PCIE_BAR32P_VALUE;
+ *rp_bar32_val = PLATOFRM_OVERRIDE_RP_BAR32_VALUE;
+
+ return 0;
+#endif
+ return -1;
+}
+
/*
* Retrieve platform PCIe memory region (Base Platform RevC only)
*/
diff --git a/plat/arm/fvp/include/platform_pcie.h b/plat/arm/fvp/include/platform_pcie.h
index 4b3a0e9..4a2817e 100644
--- a/plat/arm/fvp/include/platform_pcie.h
+++ b/plat/arm/fvp/include/platform_pcie.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,4 +19,11 @@
#define PLATFORM_PCIE_START_BUS_NUM_0 0x0
#define PLATFORM_PCIE_END_BUS_NUM_0 0xFF
+/* PCIe BAR config parameters*/
+#define PLATFORM_OVERRIDE_PCIE_BAR64_VALUE 0x4000100000
+#define PLATFORM_OVERRIDE_RP_BAR64_VALUE 0x4000000000
+#define PLATFORM_OVERRIDE_PCIE_BAR32NP_VALUE 0x50000000
+#define PLATFORM_OVERRIDE_PCIE_BAR32P_VALUE 0x50600000
+#define PLATOFRM_OVERRIDE_RP_BAR32_VALUE 0x50850000
+
#endif /* PLATFORM_PCIE_H */
diff --git a/plat/common/plat_common.c b/plat/common/plat_common.c
index c06ad13..f8524cf 100644
--- a/plat/common/plat_common.c
+++ b/plat/common/plat_common.c
@@ -1,3 +1,4 @@
+
/*
* Copyright (c) 2018-2025, Arm Limited. All rights reserved.
*
@@ -25,6 +26,7 @@
#pragma weak tftf_plat_reset
#pragma weak plat_get_prot_regions
#pragma weak plat_pcie_get_info_table
+#pragma weak plat_pcie_get_bar_config
#pragma weak plat_get_invalid_addr
#pragma weak plat_get_dev_region
@@ -157,6 +159,13 @@
return NULL;
}
+int plat_pcie_get_bar_config(uint64_t *bar64_val, uint64_t *rp_bar64_val,
+ uint32_t *bar32np_val, uint32_t *bar32p_val,
+ uint32_t *rp_bar32_val)
+{
+ return -1;
+}
+
uintptr_t plat_get_invalid_addr(void)
{
return (uintptr_t)0x0;
diff --git a/realm/realm_da.c b/realm/realm_da.c
index c442b21..a0e812c 100644
--- a/realm/realm_da.c
+++ b/realm/realm_da.c
@@ -62,6 +62,11 @@
return false;
}
+ realm_printf("======================================\n");
+ realm_printf("Realm: Lock -> Accept -> Unlock device: (bdf: 0x%x)\n",
+ rdev->id);
+ realm_printf("======================================\n");
+
rsi_rc = realm_rsi_rdev_get_state(rdev);
if (rsi_rc != RSI_SUCCESS) {
return false;
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_da_helper.c b/tftf/tests/runtime_services/host_realm_managment/host_da_helper.c
index 8bcf370..c9a82c2 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_da_helper.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_da_helper.c
@@ -6,16 +6,17 @@
*/
#include <stdint.h>
-
#include <arch_features.h>
#include <debug.h>
#include <heap/page_alloc.h>
#include <host_da_helper.h>
#include <host_realm_helper.h>
#include <host_realm_mem_layout.h>
+#include <pcie_spec.h>
#include <pcie_doe.h>
-extern struct host_pdev gbl_host_pdev;
+extern int gbl_host_pdev_count;
+extern struct host_pdev gbl_host_pdevs[32];
extern struct host_vdev gbl_host_vdev;
static const char * const pdev_state_str[] = {
@@ -28,7 +29,7 @@
"RMI_PDEV_STATE_ERROR"
};
-struct host_vdev *find_host_vdev_from_id(unsigned long vdev_id)
+static struct host_vdev *find_host_vdev_from_id(unsigned long vdev_id)
{
struct host_vdev *h_vdev = &gbl_host_vdev;
@@ -39,18 +40,23 @@
return NULL;
}
-struct host_pdev *find_host_pdev_from_pdev_ptr(unsigned long pdev_ptr)
+static struct host_pdev *find_host_pdev_from_pdev_ptr(unsigned long pdev_ptr)
{
- struct host_pdev *h_pdev = &gbl_host_pdev;
+ uint32_t i;
+ struct host_pdev *h_pdev;
- if (h_pdev->pdev == (void *)pdev_ptr) {
- return h_pdev;
+ for (i = 0; i < gbl_host_pdev_count; i++) {
+ h_pdev = &gbl_host_pdevs[i];
+
+ if (h_pdev->pdev == (void *)pdev_ptr) {
+ return h_pdev;
+ }
}
return NULL;
}
-struct host_vdev *find_host_vdev_from_vdev_ptr(unsigned long vdev_ptr)
+static struct host_vdev *find_host_vdev_from_vdev_ptr(unsigned long vdev_ptr)
{
struct host_vdev *h_vdev = &gbl_host_vdev;
@@ -122,9 +128,11 @@
pdev_params->flags = h_pdev->pdev_flags;
pdev_params->cert_id = h_pdev->cert_slot_id;
- pdev_params->pdev_id = h_pdev->bdf;
+ pdev_params->pdev_id = h_pdev->dev->bdf;
pdev_params->num_aux = h_pdev->pdev_aux_num;
pdev_params->hash_algo = h_pdev->pdev_hash_algo;
+ pdev_params->root_id = h_pdev->dev->rp_dev->bdf;
+ pdev_params->ecam_addr = h_pdev->dev->ecam_base;
for (i = 0; i < h_pdev->pdev_aux_num; i++) {
pdev_params->aux[i] = (uintptr_t)h_pdev->pdev_aux[i];
}
@@ -340,7 +348,8 @@
}
resp_len = 0UL;
- rc = pcie_doe_communicate(doe_header, h_pdev->bdf, h_pdev->doe_cap_base,
+ rc = pcie_doe_communicate(doe_header, h_pdev->dev->bdf,
+ h_pdev->dev->doe_cap_base,
(void *)dcomm_enter->req_addr,
dcomm_exit->req_len,
(void *)dcomm_enter->resp_addr, &resp_len);
@@ -493,7 +502,10 @@
u_register_t ret, count;
int i;
- memset(h_pdev, 0, sizeof(struct host_pdev));
+ /* RCiEP devices not supported by RMM */
+ if (h_pdev->dev->dp_type == RCiEP) {
+ return -1;
+ }
/* Allocate granule for PDEV and delegate */
h_pdev->pdev = page_alloc(PAGE_SIZE);
@@ -512,10 +524,20 @@
* Off chip PCIe device - set flags as non coherent device protected by
* end to end IDE, with SPDM.
*/
- h_pdev->pdev_flags = (INPLACE(RMI_PDEV_FLAGS_SPDM, RMI_PDEV_SPDM_TRUE) |
- INPLACE(RMI_PDEV_FLAGS_IDE, RMI_PDEV_IDE_TRUE) |
- INPLACE(RMI_PDEV_FLAGS_COHERENT,
- RMI_PDEV_COHERENT_FALSE));
+ h_pdev->pdev_flags = 0;
+
+ /* Set IDE based on device capability */
+ if (pcie_dev_has_ide(h_pdev->dev)) {
+ h_pdev->pdev_flags |= INPLACE(RMI_PDEV_FLAGS_IDE,
+ RMI_PDEV_IDE_TRUE);
+ }
+
+ /* Supports SPDM */
+ h_pdev->pdev_flags |= INPLACE(RMI_PDEV_FLAGS_SPDM, RMI_PDEV_SPDM_TRUE);
+
+ /* Not a coherent device */
+ h_pdev->pdev_flags |= INPLACE(RMI_PDEV_FLAGS_COHERENT,
+ RMI_PDEV_COHERENT_FALSE);
/* Get num of aux granules required for this PDEV */
ret = host_rmi_pdev_aux_count(h_pdev->pdev_flags, &count);
@@ -606,7 +628,6 @@
return -1;
}
-
/*
* Stop PDEV and ternimate secure session and call PDEV destroy
*/
@@ -642,10 +663,13 @@
ERROR("Aux granule undelegate failed 0x%lx\n", ret);
result = -1;
}
+
+ h_pdev->pdev_aux[i] = NULL;
}
/* Undelegate PDEV granule */
ret = host_rmi_granule_undelegate((u_register_t)h_pdev->pdev);
+ h_pdev->pdev = NULL;
if (ret != RMI_SUCCESS) {
ERROR("PDEV undelegate failed 0x%lx\n", ret);
result = -1;
@@ -683,7 +707,8 @@
* response buffer, VDEV AUX granules and memory required to device
* measurements, interface report.
*/
-static int host_vdev_setup(struct host_pdev *h_pdev, struct host_vdev *h_vdev)
+static int host_vdev_setup(struct host_vdev *h_vdev, unsigned long tdi_id,
+ void *pdev_ptr)
{
u_register_t ret;
@@ -694,9 +719,9 @@
* the VMM view of vdev_id and Realm view of device_id must match.
*/
h_vdev->vdev_id = 0UL;
- h_vdev->tdi_id = h_pdev->bdf;
+ h_vdev->tdi_id = tdi_id;
h_vdev->flags = 0UL;
- h_vdev->pdev_ptr = h_pdev->pdev;
+ h_vdev->pdev_ptr = pdev_ptr;
/* Allocate granule for VDEV and delegate */
h_vdev->vdev_ptr = (void *)page_alloc(PAGE_SIZE);
@@ -751,15 +776,14 @@
return -1;
}
-int host_assign_vdev_to_realm(struct realm *realm,
- struct host_pdev *h_pdev,
- struct host_vdev *h_vdev)
+int host_assign_vdev_to_realm(struct realm *realm, struct host_vdev *h_vdev,
+ unsigned long tdi_id, void *pdev_ptr)
{
struct rmi_vdev_params *vdev_params;
u_register_t ret;
int rc;
- rc = host_vdev_setup(h_pdev, h_vdev);
+ rc = host_vdev_setup(h_vdev, tdi_id, pdev_ptr);
if (rc != 0) {
return rc;
}
@@ -778,12 +802,12 @@
* This is TDI id, this must be same as PDEV ID for assigning the whole
* device.
*/
- vdev_params->tdi_id = h_pdev->bdf;
+ vdev_params->tdi_id = tdi_id;
vdev_params->flags = h_vdev->flags;
vdev_params->num_aux = 0UL;
- ret = host_rmi_vdev_create(realm->rd, (u_register_t)h_pdev->pdev,
+ ret = host_rmi_vdev_create(realm->rd, (u_register_t)pdev_ptr,
(u_register_t)h_vdev->vdev_ptr,
(u_register_t)vdev_params);
if (ret != RMI_SUCCESS) {
@@ -794,10 +818,9 @@
return 0;
}
-int host_unassign_vdev_from_realm(struct realm *realm,
- struct host_pdev *h_pdev,
- struct host_vdev *h_vdev)
+int host_unassign_vdev_from_realm(struct realm *realm, struct host_vdev *h_vdev)
{
+ struct host_pdev *h_pdev;
u_register_t ret, state;
int rc;
@@ -818,6 +841,9 @@
return -1;
}
+ h_pdev = find_host_pdev_from_pdev_ptr((unsigned long)h_vdev->pdev_ptr);
+ assert(h_pdev);
+
/* Do VDEV communicate to move VDEV from STOPPING to STOPPED state */
rc = host_dev_communicate(h_pdev, h_vdev, RMI_VDEV_STATE_STOPPED);
if (rc != 0) {
@@ -825,14 +851,15 @@
return rc;
}
- ret = host_rmi_vdev_destroy(realm->rd, (u_register_t)h_pdev->pdev,
- (u_register_t)h_vdev->vdev_ptr);
+ ret = host_rmi_vdev_destroy(realm->rd,
+ (u_register_t)h_vdev->pdev_ptr,
+ (u_register_t)h_vdev->vdev_ptr);
if (ret != RMI_SUCCESS) {
ERROR("VDEV destroy failed\n");
return -1;
}
- ret = host_rmi_granule_undelegate((u_register_t)(u_register_t)h_vdev->vdev_ptr);
+ ret = host_rmi_granule_undelegate((u_register_t)h_vdev->vdev_ptr);
if (ret != RMI_SUCCESS) {
ERROR("VDEV undelegate failed\n");
return -1;
@@ -921,3 +948,83 @@
*dev_ipa = map_addr;
return REALM_SUCCESS;
}
+
+bool is_host_pdev_independently_attested(struct host_pdev *h_pdev)
+{
+ assert(h_pdev);
+ assert(h_pdev->dev);
+
+ if ((pcie_dev_has_doe(h_pdev->dev)) &&
+ (pcie_dev_has_ide(h_pdev->dev)) &&
+ (h_pdev->dev->rp_dev != NULL) &&
+ (pcie_dev_has_ide(h_pdev->dev->rp_dev)) &&
+ (pcie_dev_has_dvsec_rmeda(h_pdev->dev->rp_dev))) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Find all PCIe off-chip devices that confimrs to TEE-IO standards
+ * Devices that supports DOE, IDE, TDISP with RootPort that supports
+ * RME DA are initlized in host_pdevs[]
+ */
+void host_pdevs_init(void)
+{
+ static bool gbl_host_pdevs_init_done;
+ pcie_device_bdf_table_t *bdf_table;
+ pcie_dev_t *dev;
+ uint32_t i;
+ uint32_t cnt = 0;
+
+ if (gbl_host_pdevs_init_done) {
+ return;
+ }
+
+ /* When called for the first time this does PCIe enumeration */
+ pcie_init();
+
+ INFO("Initializing host_pdevs\n");
+ bdf_table = pcie_get_bdf_table();
+ if ((bdf_table == NULL) || (bdf_table->num_entries == 0)) {
+ goto out_init;
+ }
+
+ for (i = 0; i < bdf_table->num_entries; i++) {
+ dev = &bdf_table->device[i];
+
+ if ((dev->dp_type != EP) && (dev->dp_type != RCiEP)) {
+ continue;
+ }
+
+ if ((dev->dp_type == EP) && (dev->rp_dev == NULL)) {
+ INFO("No RP found for Device %x:%x.%x\n",
+ PCIE_EXTRACT_BDF_BUS(dev->bdf),
+ PCIE_EXTRACT_BDF_DEV(dev->bdf),
+ PCIE_EXTRACT_BDF_FUNC(dev->bdf));
+ continue;
+ }
+
+ /*
+ * Skip VF in multi function device as it can't be treated as
+ * PDEV
+ */
+ if (PCIE_EXTRACT_BDF_FUNC(dev->bdf) != 0) {
+ continue;
+ }
+
+ /* Initialize host_pdev */
+ gbl_host_pdevs[cnt].dev = dev;
+ cnt++;
+
+ if (cnt == HOST_PDEV_MAX) {
+ WARN("Max host_pdev count reached.\n");
+ break;
+ }
+ }
+
+out_init:
+ gbl_host_pdevs_init_done = true;
+ gbl_host_pdev_count = cnt;
+}
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_rmi_da_flow.c b/tftf/tests/runtime_services/host_realm_managment/host_rmi_da_flow.c
index f110e10..5b41e55 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_rmi_da_flow.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_rmi_da_flow.c
@@ -20,9 +20,34 @@
#include <spdm.h>
#include <test_helpers.h>
-struct host_pdev gbl_host_pdev;
+int gbl_host_pdev_count;
+struct host_pdev gbl_host_pdevs[HOST_PDEV_MAX];
struct host_vdev gbl_host_vdev;
+static test_result_t tsm_disconnect_device(struct host_pdev *h_pdev)
+{
+ int rc;
+
+ assert(h_pdev->is_connected_to_tsm);
+
+ INFO("===========================================\n");
+ INFO("Host: TSM disconnect device: (0x%x) %x:%x.%x\n",
+ h_pdev->dev->bdf,
+ PCIE_EXTRACT_BDF_BUS(h_pdev->dev->bdf),
+ PCIE_EXTRACT_BDF_DEV(h_pdev->dev->bdf),
+ PCIE_EXTRACT_BDF_FUNC(h_pdev->dev->bdf));
+ INFO("===========================================\n");
+
+ rc = host_pdev_reclaim(h_pdev);
+ if (rc != 0) {
+ return TEST_RESULT_FAIL;
+ }
+
+ h_pdev->is_connected_to_tsm = false;
+
+ return TEST_RESULT_SUCCESS;
+}
+
/*
* This invokes various RMI calls related to PDEV, VDEV management that does
* PDEV create/communicate/set_key/abort/stop/destroy and assigns the device
@@ -31,58 +56,27 @@
* 1. Create a Realm with DA feature enabled
* 2. Find a known PCIe endpoint and connect with TSM to get_cert and establish
* secure session
- * 3. Assign the PCIe endpoint (a PF) to the Realm
- * 4. Call Realm to do DA related RSI calls
- * 5. Unassign the PCIe endpoint from the Realm
- * 6. Delete the Realm
- * 7. Reclaim the PCIe TDI from TSM
*/
-test_result_t host_invoke_rmi_da_flow(void)
+static test_result_t tsm_connect_device(struct host_pdev *h_pdev)
{
- u_register_t rmi_feat_reg0;
- uint32_t pdev_bdf, doe_cap_base;
- struct host_pdev *h_pdev;
- struct host_vdev *h_vdev;
- uint8_t public_key_algo;
int rc;
- bool realm_rc;
- struct realm realm;
- test_result_t result = TEST_RESULT_FAIL;
+ uint8_t public_key_algo;
- CHECK_DA_SUPPORT_IN_RMI(rmi_feat_reg0);
- SKIP_TEST_IF_DOE_NOT_SUPPORTED(pdev_bdf, doe_cap_base);
-
- INFO("DA on bdf: 0x%x, doe_cap_base: 0x%x\n", pdev_bdf, doe_cap_base);
-
- /*
- * Create a Realm with DA feature enabled
- *
- * todo: creating this after host_pdev_setup causes Realm create to
- * fail.
- */
- rc = host_create_realm_with_feat_da(&realm);
- if (rc != 0) {
- INFO("Realm create with feat_da failed\n");
- return TEST_RESULT_FAIL;
- }
-
- INFO("Realm created with feat_da enabled\n");
-
- h_pdev = &gbl_host_pdev;
- h_vdev = &gbl_host_vdev;
+ INFO("======================================\n");
+ INFO("Host: TSM connect device: (0x%x) %x:%x.%x\n",
+ h_pdev->dev->bdf,
+ PCIE_EXTRACT_BDF_BUS(h_pdev->dev->bdf),
+ PCIE_EXTRACT_BDF_DEV(h_pdev->dev->bdf),
+ PCIE_EXTRACT_BDF_FUNC(h_pdev->dev->bdf));
+ INFO("======================================\n");
/* Allocate granules. Skip DA ABIs if host_pdev_setup fails */
rc = host_pdev_setup(h_pdev);
if (rc == -1) {
- INFO("host_pdev_setup failed.\n");
- (void)host_destroy_realm(&realm);
+ ERROR("host_pdev_setup failed.\n");
return TEST_RESULT_FAIL;
}
- /* todo: move to tdi_pdev_setup */
- h_pdev->bdf = pdev_bdf;
- h_pdev->doe_cap_base = doe_cap_base;
-
/* Call rmi_pdev_create to transition PDEV to STATE_NEW */
rc = host_pdev_transition(h_pdev, RMI_PDEV_STATE_NEW);
if (rc != 0) {
@@ -123,71 +117,223 @@
/* Call rmi_pdev_set_key transition PDEV to HAS_KEY */
rc = host_pdev_transition(h_pdev, RMI_PDEV_STATE_HAS_KEY);
if (rc != 0) {
- INFO("PDEV transition: PDEV_NEEDS_KEY -> PDEV_HAS_KEY failed\n");
+ ERROR("PDEV transition: PDEV_NEEDS_KEY -> PDEV_HAS_KEY failed\n");
goto err_pdev_reclaim;
}
/* Call rmi_pdev_comminucate to transition PDEV to READY state */
rc = host_pdev_transition(h_pdev, RMI_PDEV_STATE_READY);
if (rc != 0) {
- INFO("PDEV transition: PDEV_HAS_KEY -> PDEV_READY failed\n");
+ ERROR("PDEV transition: PDEV_HAS_KEY -> PDEV_READY failed\n");
goto err_pdev_reclaim;
}
-
- /*
- * 3 Assign VDEV (the PCIe endpoint) from the Realm
- */
- rc = host_assign_vdev_to_realm(&realm, h_pdev, h_vdev);
- if (rc != 0) {
- INFO("VDEV assign to realm failed\n");
- /* TF-RMM has support till here. Change error code temporarily */
- result = TEST_RESULT_SUCCESS;
- goto err_pdev_reclaim;
- }
-
- /*
- * 4 Call Realm to do DA related RSI calls
- */
- realm_rc = host_enter_realm_execute(&realm, REALM_DA_RSI_CALLS,
- RMI_EXIT_HOST_CALL, 0U);
- if (!realm_rc) {
- INFO("Realm DA_RSI_CALLS failed\n");
- goto err_pdev_reclaim;
- }
-
- /*
- * 5 Unassign VDEV (the PCIe endpoint) from the Realm
- */
- rc = host_unassign_vdev_from_realm(&realm, h_pdev, h_vdev);
- if (rc != 0) {
- INFO("VDEV unassign to realm failed\n");
- goto err_pdev_reclaim;
- }
-
- /*
- * 6 Destroy the Realm
- */
- if (!host_destroy_realm(&realm)) {
- INFO("Realm destroy failed\n");
- (void)host_pdev_reclaim(h_pdev);
- return TEST_RESULT_FAIL;
- }
-
- /*
- * 7 Reclaim PDEV (the PCIe TDI) from TSM
- */
- rc = host_pdev_reclaim(h_pdev);
- if (rc != 0) {
- INFO("Reclaim PDEV from TSM failed\n");
- return TEST_RESULT_FAIL;
- }
+ h_pdev->is_connected_to_tsm = true;
return TEST_RESULT_SUCCESS;
err_pdev_reclaim:
- (void)host_destroy_realm(&realm);
(void)host_pdev_reclaim(h_pdev);
+
+ return TEST_RESULT_FAIL;
+}
+
+/* Iterate thorough all host_pdevs and try to connect to TSM */
+static test_result_t tsm_connect_devices(void)
+{
+ uint32_t i;
+ int count = 0;
+ struct host_pdev *h_pdev;
+ test_result_t result = TEST_RESULT_SKIPPED;
+
+ for (i = 0; i < gbl_host_pdev_count; i++) {
+ h_pdev = &gbl_host_pdevs[i];
+
+ if (!is_host_pdev_independently_attested(h_pdev)) {
+ continue;
+ }
+
+ result = tsm_connect_device(h_pdev);
+ if (result != TEST_RESULT_SUCCESS) {
+ ERROR("tsm_connect_device: 0x%x failed\n",
+ h_pdev->dev->bdf);
+ break;
+ }
+
+ count++;
+ }
+
+ if (count != 0U) {
+ INFO("%d devices connected to TSM\n", count);
+ } else {
+ INFO("No device connected to TSM\n");
+ }
+
+ return result;
+}
+
+/* Iterate thorough all connected host_pdevs and disconnect from TSM */
+static test_result_t tsm_disconnect_devices(void)
+{
+ uint32_t i;
+ struct host_pdev *h_pdev;
+ test_result_t rc;
+ bool return_error = false;
+
+ for (i = 0; i < gbl_host_pdev_count; i++) {
+ h_pdev = &gbl_host_pdevs[i];
+
+ if (h_pdev->is_connected_to_tsm) {
+ rc = tsm_disconnect_device(h_pdev);
+ if (rc != TEST_RESULT_SUCCESS) {
+ /* Set error, continue with other devices */
+ return_error = true;
+ }
+ }
+ }
+
+ if (return_error) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+static test_result_t realm_assign_unassign_device(struct realm *realm_ptr,
+ struct host_vdev *h_vdev,
+ unsigned long tdi_id,
+ void *pdev_ptr)
+{
+ int rc;
+ bool realm_rc;
+
+ /* Assign VDEV */
+ INFO("======================================\n");
+ INFO("Host: Assign device: (0x%x) %x:%x.%x to Realm \n",
+ (uint32_t)tdi_id,
+ PCIE_EXTRACT_BDF_BUS((uint32_t)tdi_id),
+ PCIE_EXTRACT_BDF_DEV((uint32_t)tdi_id),
+ PCIE_EXTRACT_BDF_FUNC((uint32_t)tdi_id));
+ INFO("======================================\n");
+
+ rc = host_assign_vdev_to_realm(realm_ptr, h_vdev, tdi_id, pdev_ptr);
+ if (rc != 0) {
+ ERROR("VDEV assign to realm failed\n");
+ /* TF-RMM has support till here. Change error code temporarily */
+ return TEST_RESULT_SUCCESS;
+ /* return TEST_RESULT_FAIL */
+ }
+
+ /* Enter Realm. Lock -> Accept -> Unlock the assigned device */
+ realm_rc = host_enter_realm_execute(realm_ptr, REALM_DA_RSI_CALLS,
+ RMI_EXIT_HOST_CALL, 0U);
+
+ /* Unassign VDEV */
+ INFO("======================================\n");
+ INFO("Host: Unassign device: (0x%x) %x:%x.%x from Realm \n",
+ (uint32_t)tdi_id,
+ PCIE_EXTRACT_BDF_BUS((uint32_t)tdi_id),
+ PCIE_EXTRACT_BDF_DEV((uint32_t)tdi_id),
+ PCIE_EXTRACT_BDF_FUNC((uint32_t)tdi_id));
+ INFO("======================================\n");
+
+ rc = host_unassign_vdev_from_realm(realm_ptr, h_vdev);
+ if (rc != 0) {
+ ERROR("VDEV unassign to realm failed\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!realm_rc) {
+ ERROR("Realm DA_RSI_CALLS failed\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+static test_result_t
+realm_assign_unassign_devices(struct realm *realm_ptr)
+{
+ uint32_t i;
+ test_result_t rc;
+ struct host_pdev *h_pdev;
+ struct host_vdev *h_vdev;
+
+ for (i = 0; i < gbl_host_pdev_count; i++) {
+ h_pdev = &gbl_host_pdevs[i];
+
+ if (h_pdev->is_connected_to_tsm) {
+ h_vdev = &gbl_host_vdev;
+
+ rc = realm_assign_unassign_device(realm_ptr, h_vdev,
+ h_pdev->dev->bdf,
+ h_pdev->pdev);
+ if (rc != TEST_RESULT_SUCCESS) {
+ break;
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * Iterate thorugh all host_pdevs and do
+ * TSM connect
+ * TSM disconnect
+ */
+test_result_t host_da_workflow_on_all_offchip_devices(void)
+{
+ int rc;
+ struct realm realm;
+ test_result_t result;
+ bool return_error = false;
+ u_register_t rmi_feat_reg0;
+
+ SKIP_DA_TEST_IF_PREREQS_NOT_MET(rmi_feat_reg0);
+ host_pdevs_init();
+
+ /*
+ * Create a Realm with DA feature enabled
+ *
+ * todo: creating this after host_pdev_setup causes Realm create to
+ * fail.
+ */
+ rc = host_create_realm_with_feat_da(&realm);
+ if (rc != 0) {
+ ERROR("Realm create with feat_da failed\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Connect all devices with TSM */
+ result = tsm_connect_devices();
+ if (result == TEST_RESULT_SKIPPED) {
+ goto out_rm_realm;
+ } else if (result != TEST_RESULT_SUCCESS) {
+ return_error = true;
+ }
+
+ /* Assign all TSM connected devices to a Realm */
+ result = realm_assign_unassign_devices(&realm);
+ if (result != TEST_RESULT_SUCCESS) {
+ return_error = true;
+ }
+
+ result = tsm_disconnect_devices();
+ if (result != TEST_RESULT_SUCCESS) {
+ return_error = true;
+ }
+
+out_rm_realm:
+ /* Destroy the Realm */
+ if (!host_destroy_realm(&realm)) {
+ return_error = true;
+ }
+
+ if (return_error) {
+ result = TEST_RESULT_FAIL;
+ }
+
return result;
}
@@ -205,6 +351,8 @@
return TEST_RESULT_SKIPPED;
}
+ host_pdevs_init();
+
/* Initialize Host NS heap memory */
ret = page_pool_init((u_register_t)PAGE_POOL_BASE,
(u_register_t)PAGE_POOL_MAX_SIZE);
@@ -213,7 +361,7 @@
return TEST_RESULT_FAIL;
}
- h_pdev = &gbl_host_pdev;
+ h_pdev = &gbl_host_pdevs[0];
/*
* Call rmi_pdev_create with invalid pdev, expect an error
diff --git a/tftf/tests/runtime_services/host_realm_managment/rmi_dev_delegate_tests.c b/tftf/tests/runtime_services/host_realm_managment/rmi_dev_delegate_tests.c
index 554029c..ae81946 100644
--- a/tftf/tests/runtime_services/host_realm_managment/rmi_dev_delegate_tests.c
+++ b/tftf/tests/runtime_services/host_realm_managment/rmi_dev_delegate_tests.c
@@ -8,10 +8,10 @@
#include <arch_features.h>
#include <common_def.h>
+#include <host_da_helper.h>
#include <host_realm_helper.h>
#include <host_realm_mem_layout.h>
#include <host_shared_data.h>
-#include <pcie_doe.h>
#include <plat_topology.h>
#include <platform.h>
#include <power_management.h>
@@ -90,7 +90,7 @@
u_register_t rmi_feat_reg0;
unsigned int num_reg = 0U;
- CHECK_DA_SUPPORT_IN_RMI(rmi_feat_reg0);
+ SKIP_DA_TEST_IF_PREREQS_NOT_MET(rmi_feat_reg0);
host_rmi_init_cmp_result();
@@ -147,7 +147,7 @@
u_register_t rmi_feat_reg0, lead_mpid;
unsigned int num_reg = 0U;
- CHECK_DA_SUPPORT_IN_RMI(rmi_feat_reg0);
+ SKIP_DA_TEST_IF_PREREQS_NOT_MET(rmi_feat_reg0);
lead_mpid = read_mpidr_el1() & MPID_MASK;
@@ -275,7 +275,7 @@
u_register_t rmi_feat_reg0;
unsigned int num_reg = 0U;
- CHECK_DA_SUPPORT_IN_RMI(rmi_feat_reg0);
+ SKIP_DA_TEST_IF_PREREQS_NOT_MET(rmi_feat_reg0);
host_rmi_init_cmp_result();
diff --git a/tftf/tests/runtime_services/host_realm_managment/rmi_dev_mem_map_tests.c b/tftf/tests/runtime_services/host_realm_managment/rmi_dev_mem_map_tests.c
index f55a1c9..1a28d4f 100644
--- a/tftf/tests/runtime_services/host_realm_managment/rmi_dev_mem_map_tests.c
+++ b/tftf/tests/runtime_services/host_realm_managment/rmi_dev_mem_map_tests.c
@@ -12,7 +12,6 @@
#include <host_realm_helper.h>
#include <host_realm_mem_layout.h>
#include <host_shared_data.h>
-#include <pcie_doe.h>
#include <plat_topology.h>
#include <platform.h>
#include <test_helpers.h>
@@ -77,7 +76,7 @@
unsigned int num[NUM_INFO_TESTS];
unsigned int num_reg, offset, i, j;
- CHECK_DA_SUPPORT_IN_RMI(rmi_features);
+ SKIP_DA_TEST_IF_PREREQS_NOT_MET(rmi_features);
/* Initialise memory test structures */
diff --git a/tftf/tests/tests-realm-payload.mk b/tftf/tests/tests-realm-payload.mk
index add6a7f..5859d31 100644
--- a/tftf/tests/tests-realm-payload.mk
+++ b/tftf/tests/tests-realm-payload.mk
@@ -62,6 +62,7 @@
$(addprefix lib/pcie/, \
pcie.c \
pcie_doe.c \
+ pcie_dvsec_rmeda.c \
)
ifeq (${ENABLE_REALM_PAYLOAD_TESTS},1)
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 064f988..c9dc0cb 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -173,8 +173,8 @@
<!-- Test cases related to Dev Mem Map and Unmap -->
<testcase name="Realm payload Dev Mem Map and Unmap"
function="host_realm_dev_mem_map_unmap" />
- <!-- Invoke RMI calls related to DA PDEV/VDEV management -->
- <testcase name="Invoke RMI DA ABIs "
- function="host_invoke_rmi_da_flow" />
+ <!-- Invoke DA workflow on PCIe off-chip device -->
+ <testcase name="DA workflow on all PCIe off-chip devices"
+ function="host_da_workflow_on_all_offchip_devices" />
</testsuite>
</testsuites>