diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index acb73288759..62022a6b89c 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -71,6 +71,31 @@ uint32_t pcie_get_cap(pcie_bdf_t bdf, uint32_t cap_id) return reg; } +uint32_t pcie_get_ext_cap(pcie_bdf_t bdf, uint32_t cap_id) +{ + unsigned int reg = PCIE_CONF_EXT_CAPPTR; /* Start at end of the PCI configuration space */ + uint32_t data; + + while (reg) { + data = pcie_conf_read(bdf, reg); + if (!data || data == 0xffffffff) { + return 0; + } + + if (PCIE_CONF_EXT_CAP_ID(data) == cap_id) { + break; + } + + reg = PCIE_CONF_EXT_CAP_NEXT(data) >> 2; + + if (reg < PCIE_CONF_EXT_CAPPTR) { + return 0; + } + } + + return reg; +} + bool pcie_get_mbar(pcie_bdf_t bdf, unsigned int bar_index, struct pcie_mbar *mbar) diff --git a/include/drivers/pcie/pcie.h b/include/drivers/pcie/pcie.h index 327702af6f0..0a9e0bd6223 100644 --- a/include/drivers/pcie/pcie.h +++ b/include/drivers/pcie/pcie.h @@ -167,6 +167,15 @@ extern void pcie_irq_enable(pcie_bdf_t bdf, unsigned int irq); */ extern uint32_t pcie_get_cap(pcie_bdf_t bdf, uint32_t cap_id); +/** + * @brief Find an Extended PCI(e) capability in an endpoint's configuration space. + * + * @param bdf the PCI endpoint to examine + * @param cap_id the capability ID of interest + * @return the index of the configuration word, or 0 if no capability. + */ +extern uint32_t pcie_get_ext_cap(pcie_bdf_t bdf, uint32_t cap_id); + /* * Configuration word 13 contains the head of the capabilities list. */ @@ -182,6 +191,21 @@ extern uint32_t pcie_get_cap(pcie_bdf_t bdf, uint32_t cap_id); #define PCIE_CONF_CAP_ID(w) ((w) & 0xFFU) #define PCIE_CONF_CAP_NEXT(w) (((w) >> 10) & 0x3FU) +/* + * The extended PCI Express capabilies lies at the end of the PCI configuration space + */ + +#define PCIE_CONF_EXT_CAPPTR 64U + +/* + * The first word of every capability contains an extended capability identifier, + * and a link to the next capability (or 0) in the extended configuration space. + */ + +#define PCIE_CONF_EXT_CAP_ID(w) ((w) & 0xFFFFU) +#define PCIE_CONF_EXT_CAP_VER(w) (((w) >> 16) & 0xFU) +#define PCIE_CONF_EXT_CAP_NEXT(w) (((w) >> 20) & 0xFFFU) + /* * Configuration word 0 aligns directly with pcie_id_t. */