From b5fecc5ff8bdf349d57776f14c493c8d42012a99 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 16 Mar 2021 09:01:28 +0100 Subject: [PATCH] drivers/pcie: Add a function for dynamic PCIe IRQ connection The is meant to fix a chicken & egg issue with MSI interrupt remapping. Currently, drivers first connect the irq (by-passing any possible MSI remapping), so the IRQ ends-up being remapped at the IOAPIC level which is not what we want. So adding a dedicated function to properly handle this case. This is valid only for runtime dynamic IRQ connection obviously. Signed-off-by: Tomasz Bursztyka --- drivers/pcie/host/pcie.c | 29 +++++++++++++++++++++++++++++ include/drivers/pcie/pcie.h | 18 ++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index 8626e127bc0..f6fb38142ef 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -252,6 +252,35 @@ unsigned int pcie_get_irq(pcie_bdf_t bdf) return PCIE_CONF_INTR_IRQ(data); } +bool pcie_connect_dynamic_irq(pcie_bdf_t bdf, + unsigned int irq, + unsigned int priority, + void (*routine)(const void *parameter), + const void *parameter, + uint32_t flags) +{ +#if defined(CONFIG_PCIE_MSI) && defined(CONFIG_PCIE_MSI_MULTI_VECTOR) + if (pcie_is_msi(bdf)) { + msi_vector_t vector; + + if ((pcie_msi_vectors_allocate(bdf, priority, + &vector, 1) == 0) || + !pcie_msi_vector_connect(bdf, &vector, + routine, parameter, flags)) { + return false; + } + } else +#endif /* CONFIG_PCIE_MSI && CONFIG_PCIE_MSI_MULTI_VECTOR */ + { + if (irq_connect_dynamic(irq, priority, routine, + parameter, flags) < 0) { + return false; + } + } + + return true; +} + void pcie_irq_enable(pcie_bdf_t bdf, unsigned int irq) { #if CONFIG_PCIE_MSI diff --git a/include/drivers/pcie/pcie.h b/include/drivers/pcie/pcie.h index 785e31ab0b8..76c1afc94ff 100644 --- a/include/drivers/pcie/pcie.h +++ b/include/drivers/pcie/pcie.h @@ -181,6 +181,24 @@ extern uint32_t pcie_get_cap(pcie_bdf_t bdf, uint32_t cap_id); */ extern uint32_t pcie_get_ext_cap(pcie_bdf_t bdf, uint32_t cap_id); +/** + * @brief Dynamically connect a PCIe endpoint IRQ to an ISR handler + * + * @param bdf the PCI endpoint to examine + * @param irq the IRQ to connect (see pcie_alloc_irq()) + * @param priority priority of the IRQ + * @param routine the ISR handler to connect to the IRQ + * @param parameter the parameter to provide to the handler + * @param flags IRQ connection flags + * @return true if connected, false otherwise + */ +extern bool pcie_connect_dynamic_irq(pcie_bdf_t bdf, + unsigned int irq, + unsigned int priority, + void (*routine)(const void *parameter), + const void *parameter, + uint32_t flags); + /* * Configuration word 13 contains the head of the capabilities list. */