diff options
| author | Vineet Gupta <Vineet.Gupta1@synopsys.com> | 2013-08-02 00:49:19 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-08-01 23:54:12 -0400 |
| commit | 5284eba7b37dfeffe75bfdf81a13e9efebe0480a (patch) | |
| tree | 488245e42b7e58d5e813cfd3de6f56c04c53c8a1 | |
| parent | cb50e5235b8ae5aa0fe422eaaa8e444024c5bd98 (diff) | |
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>
| -rw-r--r-- | drivers/tty/serial/arc_uart.c | 26 |
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) | |||
| 209 | arc_serial_tx_chars(uart); | 209 | arc_serial_tx_chars(uart); |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | static void arc_serial_rx_chars(struct arc_uart_port *uart) | 212 | static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status) |
| 213 | { | 213 | { |
| 214 | unsigned int status, ch, flg = 0; | 214 | unsigned int ch, flg = 0; |
| 215 | 215 | ||
| 216 | /* | 216 | /* |
| 217 | * UART has 4 deep RX-FIFO. Driver's recongnition of this fact | 217 | * 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) | |||
| 222 | * before RX-EMPTY=0, implies some sort of buffering going on in the | 222 | * before RX-EMPTY=0, implies some sort of buffering going on in the |
| 223 | * controller, which is indeed the Rx-FIFO. | 223 | * controller, which is indeed the Rx-FIFO. |
| 224 | */ | 224 | */ |
| 225 | while (!((status = UART_GET_STATUS(uart)) & RXEMPTY)) { | 225 | do { |
| 226 | 226 | /* | |
| 227 | ch = UART_GET_DATA(uart); | 227 | * This could be an Rx Intr for err (no data), |
| 228 | uart->port.icount.rx++; | 228 | * so check err and clear that Intr first |
| 229 | 229 | */ | |
| 230 | if (unlikely(status & (RXOERR | RXFERR))) { | 230 | if (unlikely(status & (RXOERR | RXFERR))) { |
| 231 | if (status & RXOERR) { | 231 | if (status & RXOERR) { |
| 232 | uart->port.icount.overrun++; | 232 | uart->port.icount.overrun++; |
| @@ -242,6 +242,12 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart) | |||
| 242 | } else | 242 | } else |
| 243 | flg = TTY_NORMAL; | 243 | flg = TTY_NORMAL; |
| 244 | 244 | ||
| 245 | if (status & RXEMPTY) | ||
| 246 | continue; | ||
| 247 | |||
| 248 | ch = UART_GET_DATA(uart); | ||
| 249 | uart->port.icount.rx++; | ||
| 250 | |||
| 245 | if (unlikely(uart_handle_sysrq_char(&uart->port, ch))) | 251 | if (unlikely(uart_handle_sysrq_char(&uart->port, ch))) |
| 246 | goto done; | 252 | goto done; |
| 247 | 253 | ||
| @@ -249,7 +255,7 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart) | |||
| 249 | 255 | ||
| 250 | done: | 256 | done: |
| 251 | tty_flip_buffer_push(&uart->port.state->port); | 257 | tty_flip_buffer_push(&uart->port.state->port); |
| 252 | } | 258 | } while (!((status = UART_GET_STATUS(uart)) & RXEMPTY)); |
| 253 | } | 259 | } |
| 254 | 260 | ||
| 255 | /* | 261 | /* |
| @@ -292,11 +298,11 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id) | |||
| 292 | * notifications from the UART Controller. | 298 | * notifications from the UART Controller. |
| 293 | * To demultiplex between the two, we check the relevant bits | 299 | * To demultiplex between the two, we check the relevant bits |
| 294 | */ | 300 | */ |
| 295 | if ((status & RXIENB) && !(status & RXEMPTY)) { | 301 | if (status & RXIENB) { |
| 296 | 302 | ||
| 297 | /* already in ISR, no need of xx_irqsave */ | 303 | /* already in ISR, no need of xx_irqsave */ |
| 298 | spin_lock(&uart->port.lock); | 304 | spin_lock(&uart->port.lock); |
| 299 | arc_serial_rx_chars(uart); | 305 | arc_serial_rx_chars(uart, status); |
| 300 | spin_unlock(&uart->port.lock); | 306 | spin_unlock(&uart->port.lock); |
| 301 | } | 307 | } |
| 302 | 308 | ||
