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 */