[PATCH 08/12] Serial: sc26xx - avoid endless loop with IRQs masked.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If hardware is in wierd state it is possible to lock the
system while waiting for the TX flush to complete.

Signed-off-by: Martin Fuzzey <mfuzzey@xxxxxxxxx>

---

 drivers/serial/sc26xx.c |   27 ++++++++++++++++++++++-----
 1 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c
index 69b7ae7..bc466ac 100644
--- a/drivers/serial/sc26xx.c
+++ b/drivers/serial/sc26xx.c
@@ -72,6 +72,7 @@ struct uart_sc26xx_port {
 #define SR_FRAME    (1 << 6)
 #define SR_PARITY   (1 << 5)
 #define SR_OVERRUN  (1 << 4)
+#define SR_TXEMT    (1 << 3)
 #define SR_TXRDY    (1 << 2)
 #define SR_RXRDY    (1 << 0)
 
@@ -396,6 +397,22 @@ static void sc26xx_shutdown(struct uart_port *port)
 	WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
 }
 
+static int wait_tx_empty(struct uart_port *port)
+{
+	int i;
+	u8 sr;
+	u8 bits = SR_TXEMT | SR_TXRDY;
+
+	for (i = 0; i < 10000; i++) {
+		sr = READ_SC_PORT(port, SR);
+		if  ((sr & bits) == bits)
+			return 0;
+		udelay(2);
+	}
+	dev_warn(port->dev, "Timed out waiting for TX Empty sr=%02X\n", sr);
+	return -1;
+}
+
 /* port->lock is not held.  */
 static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
 			      struct ktermios *old)
@@ -407,8 +424,8 @@ static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
 
 	spin_lock_irqsave(&port->lock, flags);
 
-	while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
-		udelay(2);
+	if (wait_tx_empty(port))
+		goto out;
 
 	WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
 
@@ -501,11 +518,11 @@ static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
 	write_cmd_port(port, CR_RES_TX);
 
 	WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
-	while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
-		udelay(2);
+	if (wait_tx_empty(port))
+		goto out;
 
 	uart_update_timeout(port, cflag, baud);
-
+out:
 	spin_unlock_irqrestore(&port->lock, flags);
 }
 

--
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

[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux