From ef0d955758e549f39d97b07089dedc4bdd05bc0e Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 27 Sep 2021 11:04:55 -0700 Subject: [PATCH] uart: ns16550: add workaround to re-enable interrupts in ISR In some configurations (e.g. edge interrupt triggers), an interruptible event occurs during ISR and the host interrupt controller does not see the new event due to IIR is constantly asserting interrupts. For example, the callback handles RX and then TX. If another character comes in before end of TX processing (TX interrupt still asserts while raising RX interrupt), the host interrupt controller may not see this new event. So if needed, the IER is being toggled to re-assert interrupts at the end of ISR to nudge the host interrupt controller to fire the ISR again. Signed-off-by: Daniel Leung --- drivers/serial/Kconfig.ns16550 | 18 ++++++++++++++++++ drivers/serial/uart_ns16550.c | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/drivers/serial/Kconfig.ns16550 b/drivers/serial/Kconfig.ns16550 index f00356c60f2..fe8c7578d18 100644 --- a/drivers/serial/Kconfig.ns16550 +++ b/drivers/serial/Kconfig.ns16550 @@ -41,4 +41,22 @@ config UART_NS16550_ACCESS_WORD_ONLY 16550 (DesignWare UART) only allows word access, byte access will raise exception. +menu "NS16550 Workarounds" + +config UART_NS16550_WA_ISR_REENABLE_INTERRUPT + bool "Re-enable interrupts by toggling IER at end of ISR" + depends on UART_INTERRUPT_DRIVEN + help + In some configurations (e.g. edge interrupt triggers), + an interruptible event occurs during ISR and the host interrupt + controller does not see the new event due to IIR is constantly + asserting interrupts. For example, the callback handles RX and + then TX. If another character comes in before end of TX processing + (TX interrupt still asserts while raising RX interrupt), the host + interrupt controller may not see this new event. So if needed, + the IER is being toggled to re-assert interrupts at the end of ISR + to nudge the host interrupt controller to fire the ISR again. + +endmenu + endif # UART_NS16550 diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index 707a0adbf20..1364102be6e 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -871,6 +871,12 @@ static void uart_ns16550_isr(const struct device *dev) dev_data->cb(dev, dev_data->cb_data); } +#ifdef CONFIG_UART_NS16550_WA_ISR_REENABLE_INTERRUPT + uint8_t cached_ier = INBYTE(IER(dev)); + + OUTBYTE(IER(dev), 0U); + OUTBYTE(IER(dev), cached_ier); +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */