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>
diff --git a/drivers/serial/Kconfig.ns16550 b/drivers/serial/Kconfig.ns16550
index f00356c..fe8c757 100644
--- a/drivers/serial/Kconfig.ns16550
+++ b/drivers/serial/Kconfig.ns16550
@@ -41,4 +41,22 @@
 	  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 707a0ad..1364102 100644
--- a/drivers/serial/uart_ns16550.c
+++ b/drivers/serial/uart_ns16550.c
@@ -871,6 +871,12 @@
 		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 */