From mboxrd@z Thu Jan 1 00:00:00 1970
From: bigeasy@linutronix.de (Sebastian Andrzej Siewior)
Date: Wed, 10 Sep 2014 21:29:58 +0200
Subject: [PATCH 03/16] tty: serial: 8250_core: read only RX if there is
something in the FIFO
In-Reply-To: <1410377411-26656-1-git-send-email-bigeasy@linutronix.de>
References: <1410377411-26656-1-git-send-email-bigeasy@linutronix.de>
Message-ID: <1410377411-26656-4-git-send-email-bigeasy@linutronix.de>
To: linux-arm-kernel@lists.infradead.org
List-Id: linux-arm-kernel.lists.infradead.org
Archived-At:
List-Archive:
List-Post:
The serial8250_do_startup() function unconditionally clears the
interrupts and for that it reads from the RX-FIFO without checking if
there is a byte in the FIFO or not. This works fine on OMAP4+ HW like
AM335x or DRA7.
OMAP3630 ES1.1 (which means probably all OMAP3 and earlier) does not like
this:
|Unhandled fault: external abort on non-linefetch (0x1028) at 0xfb020000
|Internal error: : 1028 [#1] ARM
|Modules linked in:
|CPU: 0 PID: 1 Comm: swapper Not tainted 3.16.0-00022-g7edcb57-dirty #1213
|task: de0572c0 ti: de058000 task.ti: de058000
|PC is at mem32_serial_in+0xc/0x1c
|LR is at serial8250_do_startup+0x220/0x85c
|Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
|Control: 10c5387d Table: 80004019 DAC: 00000015
|[] (mem32_serial_in) from [] (serial8250_do_startup+0x220/0x85c)
|[] (serial8250_do_startup) from [] (omap_8250_startup+0x5c/0xe0)
|[] (omap_8250_startup) from [] (serial8250_startup+0x18/0x2c)
|[] (serial8250_startup) from [] (uart_startup+0x78/0x1d8)
|[] (uart_startup) from [] (uart_open+0xe8/0x114)
|[] (uart_open) from [] (tty_open+0x1a8/0x5a4)
Reviewed-by: Tony Lindgren
Tested-by: Tony Lindgren
Signed-off-by: Sebastian Andrzej Siewior
---
drivers/tty/serial/8250/8250_core.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 3cf5c98013e4..547afde9fdda 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -2088,8 +2088,8 @@ int serial8250_do_startup(struct uart_port *port)
/*
* Clear the interrupt registers.
*/
- serial_port_in(port, UART_LSR);
- serial_port_in(port, UART_RX);
+ if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+ serial_port_in(port, UART_RX);
serial_port_in(port, UART_IIR);
serial_port_in(port, UART_MSR);
@@ -2250,8 +2250,8 @@ int serial8250_do_startup(struct uart_port *port)
* saved flags to avoid getting false values from polling
* routines or the previous session.
*/
- serial_port_in(port, UART_LSR);
- serial_port_in(port, UART_RX);
+ if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+ serial_port_in(port, UART_RX);
serial_port_in(port, UART_IIR);
serial_port_in(port, UART_MSR);
up->lsr_saved_flags = 0;
@@ -2344,7 +2344,8 @@ void serial8250_do_shutdown(struct uart_port *port)
* Read data port to reset things, and then unlink from
* the IRQ chain.
*/
- serial_port_in(port, UART_RX);
+ if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+ serial_port_in(port, UART_RX);
serial8250_rpm_put(up);
del_timer_sync(&up->timer);
--
2.1.0