From: Linus Walleij <linus.walleij@xxxxxxxxxx> Chanho Min reported that when the boot loader transfers control to the kernel, there may be pending interrupts causing the UART to lock up in an eternal loop trying to pick tokens from the FIFO (since the RX interrupt flag indicates there are tokens) while in practice there are no tokens - in fact there is only a pending IRQ flag. This patch address the issue with a combination of a patch from Russell King that clears and mask all interrupts at probe() and clears any pending error and RX interrupts at port startup time, and a patch from Jong-Sung Kim that clears any RX interrupts (including timeouts) even if if there are zero tokens in the FIFO. This way these pending interrupts should be addressed in two ways and solidify the driver in both probe() and IRQ paths. Cc: stable@xxxxxxxxxx Cc: Shreshtha Kumar Sahu <shreshthakumar.sahu@xxxxxxxxxxxxxx> Reported-by: Chanho Min <chanho0207@xxxxxxxxx> Suggested-by: Russell King <linux@xxxxxxxxxxxxxxxx> Suggested-by: Jong-Sung Kim <neidhard.kim@xxxxxxx> Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx> --- OK Greg requested that we send out this combined approach, can addressees (Chanho especially) please confirm that the patch solves the problem? Tested on U300 and U8500. --- drivers/tty/serial/amba-pl011.c | 17 +++++++++++++---- 1 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 6800f5f..ff3fed0 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -224,6 +224,11 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); } + /* RXIS but RXFE? Just clear the interrupt */ + if(unlikely(fifotaken == 0)) + writew(UART011_RTIS | UART011_RXIS, + uap->port.membase + UART011_ICR); + return fifotaken; } @@ -1381,6 +1386,10 @@ static int pl011_startup(struct uart_port *port) uap->port.uartclk = clk_get_rate(uap->clk); + /* Clear pending error and receive interrupts */ + writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS | + UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR); + /* * Allocate the IRQ */ @@ -1417,10 +1426,6 @@ static int pl011_startup(struct uart_port *port) cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; writew(cr, uap->port.membase + UART011_CR); - /* Clear pending error interrupts */ - writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, - uap->port.membase + UART011_ICR); - /* * initialise the old status of the modem signals */ @@ -1927,6 +1932,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) goto unmap; } + /* Ensure interrupts from this UART are masked and cleared */ + writew(0, uap->port.membase + UART011_IMSC); + writew(0xffff, uap->port.membase + UART011_ICR); + uap->vendor = vendor; uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_tx = vendor->lcrh_tx; -- 1.7.8 -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html