aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/arc_uart.c
diff options
context:
space:
mode:
authorVineet Gupta <Vineet.Gupta1@synopsys.com>2013-08-01 21:49:19 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-02 11:54:12 +0800
commit5284eba7b37dfeffe75bfdf81a13e9efebe0480a (patch)
tree488245e42b7e58d5e813cfd3de6f56c04c53c8a1 /drivers/tty/serial/arc_uart.c
parenttty: Only hangup once (diff)
downloadlinux-dev-5284eba7b37dfeffe75bfdf81a13e9efebe0480a.tar.xz
linux-dev-5284eba7b37dfeffe75bfdf81a13e9efebe0480a.zip
serial/arc-uart: Handle Rx Error Interrupts w/o any data
Currently, Rx error handling only triggers if there is some Rx data. Fix that by checking for error - before the data handling. Reported-by: Mischa Jonker <mjonker@synopsys.com> Tested-by: Mischa Jonker <mjonker@synopsys.com> Signed-off-by: Vineet Gupta <vgupta@synopsys.com> Cc: Jiri Slaby <jslaby@suse.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/arc_uart.c')
-rw-r--r--drivers/tty/serial/arc_uart.c26
1 files changed, 16 insertions, 10 deletions
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 2f195f0d7a11..e296c892df61 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -209,9 +209,9 @@ static void arc_serial_start_tx(struct uart_port *port)
arc_serial_tx_chars(uart);
}
-static void arc_serial_rx_chars(struct arc_uart_port *uart)
+static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status)
{
- unsigned int status, ch, flg = 0;
+ unsigned int ch, flg = 0;
/*
* UART has 4 deep RX-FIFO. Driver's recongnition of this fact
@@ -222,11 +222,11 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart)
* before RX-EMPTY=0, implies some sort of buffering going on in the
* controller, which is indeed the Rx-FIFO.
*/
- while (!((status = UART_GET_STATUS(uart)) & RXEMPTY)) {
-
- ch = UART_GET_DATA(uart);
- uart->port.icount.rx++;
-
+ do {
+ /*
+ * This could be an Rx Intr for err (no data),
+ * so check err and clear that Intr first
+ */
if (unlikely(status & (RXOERR | RXFERR))) {
if (status & RXOERR) {
uart->port.icount.overrun++;
@@ -242,6 +242,12 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart)
} else
flg = TTY_NORMAL;
+ if (status & RXEMPTY)
+ continue;
+
+ ch = UART_GET_DATA(uart);
+ uart->port.icount.rx++;
+
if (unlikely(uart_handle_sysrq_char(&uart->port, ch)))
goto done;
@@ -249,7 +255,7 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart)
done:
tty_flip_buffer_push(&uart->port.state->port);
- }
+ } while (!((status = UART_GET_STATUS(uart)) & RXEMPTY));
}
/*
@@ -292,11 +298,11 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id)
* notifications from the UART Controller.
* To demultiplex between the two, we check the relevant bits
*/
- if ((status & RXIENB) && !(status & RXEMPTY)) {
+ if (status & RXIENB) {
/* already in ISR, no need of xx_irqsave */
spin_lock(&uart->port.lock);
- arc_serial_rx_chars(uart);
+ arc_serial_rx_chars(uart, status);
spin_unlock(&uart->port.lock);
}