To prevent triggering PSLVERR, it is necessary to check whether the
UART_LSR_DR bit of UART_LSR is set before reading UART_RX.
Ensure atomicity of UART_LSR and UART_RX, put serial8250_discard_data()
under port->lock.
Signed-off-by: Yunhui Cui <cuiyunhui@xxxxxxxxxxxxx>
---
drivers/tty/serial/8250/8250.h | 15 +++++++++++
drivers/tty/serial/8250/8250_port.c | 42 ++++++++++++++---------------
2 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index b861585ca02a..5a106cf88207 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -162,6 +162,21 @@ static inline u16 serial_lsr_in(struct uart_8250_port *up)
return lsr;
}
+/*
+ * To avoid PSLVERR, check UART_LSR_DR in UART_LSR before
+ * reading UART_RX.
+ */
+static inline unsigned int serial8250_discard_data(struct uart_8250_port *up)
+{
+ u16 lsr;
+
+ lsr = serial_in(up, UART_LSR);
+ if (lsr & UART_LSR_DR)
+ return serial_in(up, UART_RX);
+...
+ return 0;
+}
+
/*
* For the 16C950
*/
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index a913135d5217..802ac50357c0 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -2137,25 +2136,21 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
static int serial8250_get_poll_char(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- int status;
+ int status = NO_POLL_CHAR;
u16 lsr;
serial8250_rpm_get(up);
+ uart_port_lock_irqsave(port, &flags);
lsr = serial_port_in(port, UART_LSR);
-
- if (!(lsr & UART_LSR_DR)) {
- status = NO_POLL_CHAR;
- goto out;
- }
-
- status = serial_port_in(port, UART_RX);
+ if ((lsr & UART_LSR_DR))
+ status = serial_port_in(port, UART_RX);
+ uart_port_unlock_irqrestore(port, flags);