From e91d863d1aaeda0349aed42dfbd75c98e042a2c9 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 13 Mar 2015 12:38:51 +0100 Subject: serial: samsung: Clear operation mode on UART shutdown Exynos serial ports operate either in a DMA-based or interrupt-based modes. In DMA-based mode, the UART generates a transfer data request and a Transmission (Tx) interrupt in interrupt-based mode. The Tx IRQ is only unmasked in interrupt-based mode and it was done in s3c24xx_serial_start_tx(). Commit ba019a3e2ad5 ("serial: samsung: remove redundant interrupt enabling") removed the IRQ enable on that function since it is enabled when the mode is set in enable_tx_pio(). The problem is that enable_tx_pio() is only called if the port mode has not been set before but the mode was not cleared on .shutdown(). So if the UART was shutdown and then started up again, the mode set will remain and the Tx IRQ won't be unmasked. This caused a hang on at least Exynos5250, Exynos5420 and Exynos5800 when the system is rebooted or powered off. Fixes: ba019a3e2ad5 ("serial: samsung: remove redundant interrupt enabling") Signed-off-by: Javier Martinez Canillas Reviewed-by: Sylwester Nawrocki Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index af821a908720..cf08876922f1 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -963,6 +963,7 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) free_irq(ourport->tx_irq, ourport); tx_enabled(port) = 0; ourport->tx_claimed = 0; + ourport->tx_mode = 0; } if (ourport->rx_claimed) { -- cgit v1.2.3 From 4e8f245937091b2c9eebf3d4909c9ceda4f0a78e Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 13 Mar 2015 14:51:50 +0100 Subject: tty: serial: fsl_lpuart: specify transmit FIFO size Specify transmit FIFO size which might be different depending on LPUART instance. This makes sure uart_wait_until_sent in serial core getting called, which in turn waits and checks if the FIFO is really empty on shutdown by using the tx_empty callback. Without the call of this callback, the last several characters might not yet be transmitted when closing the serial port. This can be reproduced by simply using echo and redirect the output to a ttyLP device. Signed-off-by: Stefan Agner Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index b1893f3f88f1..7ec911000ec2 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1076,6 +1076,8 @@ static int lpuart_startup(struct uart_port *port) sport->txfifo_size = 0x1 << (((temp >> UARTPFIFO_TXSIZE_OFF) & UARTPFIFO_FIFOSIZE_MASK) + 1); + sport->port.fifosize = sport->txfifo_size; + sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) & UARTPFIFO_FIFOSIZE_MASK) + 1); -- cgit v1.2.3 From 8e4934c6d6c659e22b1b746af4196683e77ce6ca Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 13 Mar 2015 14:51:51 +0100 Subject: tty: serial: fsl_lpuart: clear receive flag on FIFO flush When the receiver was enabled during startup, a character could have been in the FIFO when the UART get initially used. The driver configures the (receive) watermark level, and flushes the FIFO. However, the receive flag (RDRF) could still be set at that stage (as mentioned in the register description of UARTx_RWFIFO). This leads to an interrupt which won't be handled properly in interrupt mode: The receive interrupt function lpuart_rxint checks the FIFO count, which is 0 at that point (due to the flush during initialization). The problem does not manifest when using DMA to receive characters. Fix this situation by explicitly read the status register, which leads to clearing of the RDRF flag. Due to the flush just after the status flag read, a explicit data read is not to required. Signed-off-by: Stefan Agner Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 7ec911000ec2..3ad1458bfeb0 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -921,6 +921,9 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE, sport->port.membase + UARTPFIFO); + /* explicitly clear RDRF */ + readb(sport->port.membase + UARTSR1); + /* flush Tx and Rx FIFO */ writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH, sport->port.membase + UARTCFIFO); -- cgit v1.2.3