feat(lib/pcie): init pcie device capabilities
Add additional fields in pcie_dev structure that will be later
used by DA testcases.
Find and initialize devices extended capabilities.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I32042393dc023d8ac948aa9f4ea921de22ec0b98
diff --git a/include/lib/pcie/pcie.h b/include/lib/pcie/pcie.h
index 7dd165c..a08cd4a 100644
--- a/include/lib/pcie/pcie.h
+++ b/include/lib/pcie/pcie.h
@@ -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,
diff --git a/lib/pcie/pcie.c b/lib/pcie/pcie.c
index ea187a6..96e1fb9 100644
--- a/lib/pcie/pcie.c
+++ b/lib/pcie/pcie.c
@@ -13,6 +13,7 @@
#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>
@@ -21,8 +22,7 @@
const struct pcie_info_table *g_pcie_info_table;
static pcie_device_bdf_table_t *g_pcie_bdf_table;
-
-static pcie_device_bdf_table_t pcie_bdf_table[PCIE_DEVICE_BDF_TABLE_SZ];
+static pcie_device_bdf_table_t pcie_bdf_table;
static uint32_t g_pcie_index;
static uint32_t g_enumerate;
@@ -252,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.
*/
-static 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);
@@ -266,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;
}
/*
@@ -313,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);
@@ -323,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
@@ -405,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);
}
}
}
@@ -413,72 +525,17 @@
/* 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,
- */
-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;
-}
-
-/*
* @brief This API prints all the PCIe Devices info
* 1. Caller - Validation layer.
* 2. Prerequisite - val_pcie_create_info_table()
@@ -620,7 +677,7 @@
unsigned int num_ecam;
INFO("Creating PCIe info table\n");
- 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);