dm: uart_core: fix uart dm cause interrupt storm issue

For Linux kernel, the UART driver will disable IER.THRE. But for Windows, it
will keep IER.THRE turn on then cause interrupt storm.

From pc16550d UART spec, INTR PIN description:

"Interrupt. This pin goes high whenever any one of the following interrupt types
has an active high condition and is enabled through the IER Receiver Error Flag;
Received Data Available timeout (FIFO Mode only); Transmitter Holding Register
Empty; and MODEM Status. The INTR signal is reset low upon the appropriate
interrupt service or a Master Reset operation."

And Interrupt Reset Control of Transmitter Holding Register Empty Interrupt
description:

"Reading the IIR Register (if source of interrupt) or Writing into
the Transmitter Holding Register"

The datasheet hasn't describe very clear if the THRE interrupt will be
re-generate after "Reading the IIR Register". We assume it will not do
that, so the THRE interrupt only generate when THR turn to empty.

This patch follows above assumption to resolve the interrupt storm cause WaaG
boot failed issue.

Tracked-On: #2713
Signed-off-by: Yuan Liu <yuan1.liu@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Yuan Liu 2019-04-17 10:30:14 +08:00 committed by wenlingz
parent 7553d1cd26
commit 38e8059ce9
1 changed files with 4 additions and 5 deletions

View File

@ -434,6 +434,9 @@ uart_write(struct uart_vdev *uart, int offset, uint8_t value)
uart->thre_int_pending = true;
break;
case REG_IER:
if (((uart->ier & IER_ETXRDY) == 0) &&
((value & IER_ETXRDY) != 0))
uart->thre_int_pending = true;
/*
* Apply mask so that bits 4-7 are 0
* Also enables bits 0-3 only if they're 1
@ -553,12 +556,8 @@ uart_read(struct uart_vdev *uart, int offset)
/*
* Reading the IIR register clears the THRE INT.
*/
if (intr_reason == IIR_TXRDY) {
if (intr_reason == IIR_TXRDY)
uart->thre_int_pending = false;
uart_toggle_intr(uart);
}
/* THRE INT is re-generated since the THR register is always empty in here */
uart->thre_int_pending = true;
iir |= intr_reason;