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 <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2021-09-27 11:04:55 -07:00 committed by Christopher Friedt
parent cf3dabedaf
commit ef0d955758
2 changed files with 24 additions and 0 deletions

View file

@ -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

View file

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