summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Spang <spang@chromium.org>2013-03-27 19:34:25 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-28 16:04:19 -0700
commit38adbc54cea90e220c9212f961a621b2c6af9ae0 (patch)
treea9f87cf017db71038715f15e277d3a6f687a280d
parentd09a7308e9887a83abfd3176f4416d4142a265dc (diff)
serial: samsung: Avoid waiting forever for TX ready
The no_console_suspend option allows the console to write to the UART during early resume, before the serial port itself is resumed. Such writes hang indefinitely waiting for TX ready. This adds a check to the console putchar function to drop characters instead of hanging if the port hasn't been initialized. That way, we can use no_console_suspend without risk of hanging. Signed-off-by: Michael Spang <spang@chromium.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/samsung.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 78d9c55a9f84..7883f11b8c53 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1367,6 +1367,13 @@ s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
}
+static bool
+s3c24xx_port_configured(unsigned int ucon)
+{
+ /* consider the serial port configured if the tx/rx mode set */
+ return (ucon & 0xf) != 0;
+}
+
#ifdef CONFIG_CONSOLE_POLL
/*
* Console polling routines for writing and reading from the uart while
@@ -1389,6 +1396,11 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,
unsigned char c)
{
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
+ unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
+
+ /* not possible to xmit on unconfigured port */
+ if (!s3c24xx_port_configured(ucon))
+ return;
while (!s3c24xx_serial_console_txrdy(port, ufcon))
cpu_relax();
@@ -1401,6 +1413,12 @@ static void
s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
{
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
+ unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
+
+ /* not possible to xmit on unconfigured port */
+ if (!s3c24xx_port_configured(ucon))
+ return;
+
while (!s3c24xx_serial_console_txrdy(port, ufcon))
barrier();
wr_regb(cons_uart, S3C2410_UTXH, ch);
@@ -1433,9 +1451,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
"registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
port, ulcon, ucon, ubrdiv);
- if ((ucon & 0xf) != 0) {
- /* consider the serial port configured if the tx/rx mode set */
-
+ if (s3c24xx_port_configured(ucon)) {
switch (ulcon & S3C2410_LCON_CSMASK) {
case S3C2410_LCON_CS5:
*bits = 5;