serial: clps711x: Check for valid TTY in RX-interrupt
authorAlexander Shiyan <shc_work@mail.ru>
Sun, 14 Oct 2012 07:05:30 +0000 (11:05 +0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 24 Oct 2012 18:39:48 +0000 (11:39 -0700)
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/clps711x.c

index 73505c1edc7d6e5c86762bba5bca18603bfa8510..6039ebe349c040a2276a07d47fb57b4a742b2b27 100644 (file)
@@ -55,8 +55,6 @@
 #define TX_IRQ(port)           ((port)->line ? IRQ_UTXINT2 : IRQ_UTXINT1)
 #define RX_IRQ(port)           ((port)->line ? IRQ_URXINT2 : IRQ_URXINT1)
 
-#define UART_ANY_ERR           (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
-
 struct clps711x_port {
        struct uart_driver      uart;
        struct clk              *uart_clk;
@@ -99,54 +97,55 @@ static void clps711xuart_enable_ms(struct uart_port *port)
 static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
 {
        struct uart_port *port = dev_id;
-       struct tty_struct *tty = port->state->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
        unsigned int status, ch, flg;
 
-       status = clps_readl(SYSFLG(port));
-       while (!(status & SYSFLG_URXFE)) {
-               ch = clps_readl(UARTDR(port));
+       if (!tty)
+               return IRQ_HANDLED;
 
-               port->icount.rx++;
+       for (;;) {
+               status = clps_readl(SYSFLG(port));
+               if (status & SYSFLG_URXFE)
+                       break;
 
+               ch = clps_readw(UARTDR(port));
+               status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR);
+               ch &= 0xff;
+
+               port->icount.rx++;
                flg = TTY_NORMAL;
 
-               /*
-                * Note that the error handling code is
-                * out of the main execution path
-                */
-               if (unlikely(ch & UART_ANY_ERR)) {
-                       if (ch & UARTDR_PARERR)
+               if (unlikely(status)) {
+                       if (status & UARTDR_PARERR)
                                port->icount.parity++;
-                       else if (ch & UARTDR_FRMERR)
+                       else if (status & UARTDR_FRMERR)
                                port->icount.frame++;
-                       if (ch & UARTDR_OVERR)
+                       else if (status & UARTDR_OVERR)
                                port->icount.overrun++;
 
-                       ch &= port->read_status_mask;
+                       status &= port->read_status_mask;
 
-                       if (ch & UARTDR_PARERR)
+                       if (status & UARTDR_PARERR)
                                flg = TTY_PARITY;
-                       else if (ch & UARTDR_FRMERR)
+                       else if (status & UARTDR_FRMERR)
                                flg = TTY_FRAME;
-
-#ifdef SUPPORT_SYSRQ
-                       port->sysrq = 0;
-#endif
+                       else if (status & UARTDR_OVERR)
+                               flg = TTY_OVERRUN;
                }
 
                if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
+                       continue;
 
-               /*
-                * CHECK: does overrun affect the current character?
-                * ASSUMPTION: it does not.
-                */
-               uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
+               if (status & port->ignore_status_mask)
+                       continue;
 
-       ignore_char:
-               status = clps_readl(SYSFLG(port));
+               uart_insert_char(port, status, UARTDR_OVERR, ch, flg);
        }
+
        tty_flip_buffer_push(tty);
+
+       tty_kref_put(tty);
+
        return IRQ_HANDLED;
 }