From 38e8059ce9326a82e6768f9160b1a54812ec3de7 Mon Sep 17 00:00:00 2001 From: Yuan Liu Date: Wed, 17 Apr 2019 10:30:14 +0800 Subject: [PATCH] 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 Acked-by: Yu Wang --- devicemodel/hw/uart_core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/devicemodel/hw/uart_core.c b/devicemodel/hw/uart_core.c index f545c4fc0..002e3c90a 100644 --- a/devicemodel/hw/uart_core.c +++ b/devicemodel/hw/uart_core.c @@ -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;