Commit 9b96fbac authored by Linus Walleij's avatar Linus Walleij Committed by Greg Kroah-Hartman

serial: PL011: clear pending interrupts

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 two
patches suggested by Russell King that clears and mask
all interrupts at probe() and clears any pending error
and RX interrupts at port startup time.

We suspect the spurious interrupts are a side-effect of
switching the UART from FIFO to non-FIFO mode.

Cc: Shreshtha Kumar Sahu <shreshthakumar.sahu@stericsson.com>
Reported-by: default avatarChanho Min <chanho0207@gmail.com>
Suggested-by: default avatarRussell King <linux@arm.linux.org.uk>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Reviewed-by: default avatarJong-Sung Kim <neidhard.kim@lge.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 60f4b002
...@@ -1396,6 +1396,10 @@ static int pl011_startup(struct uart_port *port) ...@@ -1396,6 +1396,10 @@ static int pl011_startup(struct uart_port *port)
uap->port.uartclk = clk_get_rate(uap->clk); 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 * Allocate the IRQ
*/ */
...@@ -1432,10 +1436,6 @@ static int pl011_startup(struct uart_port *port) ...@@ -1432,10 +1436,6 @@ static int pl011_startup(struct uart_port *port)
cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
writew(cr, uap->port.membase + UART011_CR); 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 * initialise the old status of the modem signals
*/ */
...@@ -1450,6 +1450,9 @@ static int pl011_startup(struct uart_port *port) ...@@ -1450,6 +1450,9 @@ static int pl011_startup(struct uart_port *port)
* as well. * as well.
*/ */
spin_lock_irq(&uap->port.lock); spin_lock_irq(&uap->port.lock);
/* Clear out any spuriously appearing RX interrupts */
writew(UART011_RTIS | UART011_RXIS,
uap->port.membase + UART011_ICR);
uap->im = UART011_RTIM; uap->im = UART011_RTIM;
if (!pl011_dma_rx_running(uap)) if (!pl011_dma_rx_running(uap))
uap->im |= UART011_RXIM; uap->im |= UART011_RXIM;
...@@ -1942,6 +1945,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) ...@@ -1942,6 +1945,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
goto unmap; 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->vendor = vendor;
uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_rx = vendor->lcrh_rx;
uap->lcrh_tx = vendor->lcrh_tx; uap->lcrh_tx = vendor->lcrh_tx;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment