From 869c5d2e54967a8dde25359708353df8d50ebfae Mon Sep 17 00:00:00 2001 From: "Charles E. Youse" Date: Thu, 2 May 2019 14:22:00 -0700 Subject: [PATCH] drivers/uart_ns16550: enable auto IRQ detection for PCI(e) endpoints If a UART is configured with IRQ == PCIE_IRQ_DETECT, then use the pcie_wired_irq() to determine the IRQ at runtime, and install the handler using the dynamic interrupt mechanism. Signed-off-by: Charles E. Youse --- drivers/serial/uart_ns16550_port_x.h | 45 +++++++++++++++++++++++----- include/dt-bindings/pcie/pcie.h | 9 ++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/drivers/serial/uart_ns16550_port_x.h b/drivers/serial/uart_ns16550_port_x.h index 7a3311feb3d..782b4786fc6 100644 --- a/drivers/serial/uart_ns16550_port_x.h +++ b/drivers/serial/uart_ns16550_port_x.h @@ -50,20 +50,51 @@ static void irq_config_func_@NUM@(struct device *dev) { ARG_UNUSED(dev); +#if DT_UART_NS16550_PORT_@NUM@_PCIE +#if DT_UART_NS16550_PORT_@NUM@_IRQ == PCIE_IRQ_DETECT + + /* PCI(e) with auto IRQ detection */ + + BUILD_ASSERT_MSG(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), + "NS16550 PCI auto-IRQ needs CONFIG_DYNAMIC_INTERRUPTS"); + + unsigned int irq; + + irq = pcie_wired_irq(DT_UART_NS16550_PORT_@NUM@_BASE_ADDR); + if (irq == PCIE_CONF_INTR_IRQ_NONE) return; + + irq_connect_dynamic(irq, + DT_UART_NS16550_PORT_@NUM@_IRQ_PRI, + uart_ns16550_isr, + DEVICE_GET(uart_ns16550_@NUM@), + DT_UART_NS16550_PORT_@NUM@_IRQ_FLAGS); + + pcie_irq_enable(DT_UART_NS16550_PORT_@NUM@_BASE_ADDR, irq); + +#else + + /* PCI(e) with fixed or MSI IRQ */ + IRQ_CONNECT(DT_UART_NS16550_PORT_@NUM@_IRQ, DT_UART_NS16550_PORT_@NUM@_IRQ_PRI, uart_ns16550_isr, DEVICE_GET(uart_ns16550_@NUM@), DT_UART_NS16550_PORT_@NUM@_IRQ_FLAGS); -#ifdef UART_NS16550_PCIE_ENABLED - if (DEV_CFG(dev)->pcie) { - pcie_irq_enable(DT_UART_NS16550_PORT_@NUM@_BASE_ADDR, - DT_UART_NS16550_PORT_@NUM@_IRQ); - } else { - irq_enable(DT_UART_NS16550_PORT_@NUM@_IRQ); - } + pcie_irq_enable(DT_UART_NS16550_PORT_@NUM@_BASE_ADDR, + DT_UART_NS16550_PORT_@NUM@_IRQ); + +#endif #else + + /* not PCI(e) */ + + IRQ_CONNECT(DT_UART_NS16550_PORT_@NUM@_IRQ, + DT_UART_NS16550_PORT_@NUM@_IRQ_PRI, + uart_ns16550_isr, DEVICE_GET(uart_ns16550_@NUM@), + DT_UART_NS16550_PORT_@NUM@_IRQ_FLAGS); + irq_enable(DT_UART_NS16550_PORT_@NUM@_IRQ); + #endif } #endif diff --git a/include/dt-bindings/pcie/pcie.h b/include/dt-bindings/pcie/pcie.h index 0930469f749..323da9e505a 100644 --- a/include/dt-bindings/pcie/pcie.h +++ b/include/dt-bindings/pcie/pcie.h @@ -7,6 +7,15 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PCIE_PCIE_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_PCIE_PCIE_H_ +/* + * Set the device's IRQ (in devicetree, or whatever) to PCIE_IRQ_DETECT + * if the device doesn't support MSI and we don't/can't know the wired IRQ + * allocated by the firmware ahead of time. Use of this functionality will + * generally also require CONFIG_DYNAMIC_INTERRUPTS. + */ + +#define PCIE_IRQ_DETECT 0xFFFFFFFU + /* * We represent a PCI device ID as [31:16] device ID, [15:0] vendor ID. Not * coincidentally, this is same representation used in PCI configuration space.