Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65632179 authored by Stefan Agner's avatar Stefan Agner Committed by Greg Kroah-Hartman
Browse files

tty: serial: fsl_lpuart: fix framing error handling when using DMA



When using DMA framing error get cleared properly. However, due
to the additional read from the data register, an underflow in
the receive FIFO buffer occurs (the FIFO pointer gets out of
sync).

Clear the FIFO in case an underflow has occurred. Also disable the
receiver during this operation and when reading the data register to
minimize potential interference.

Signed-off-by: default avatarStefan Agner <stefan.agner@toradex.com>
Acked-by: default avatarMax Krummenacher <max.krummenacher@toradex.com>
Signed-off-by: default avatarAndrey Smirnov <andrew.smirnov@gmail.com>
Cc: Stefan Agner <stefan@agner.ch>
Cc: Bhuvanchandra DV <bhuvanchandra.dv@toradex.com>
Cc: Chris Healy <cphealy@gmail.com>
Cc: Cory Tusar <cory.tusar@zii.aero>
Cc: Lucas Stach <l.stach@pengutronix.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: linux-imx@nxp.com
Cc: linux-serial@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Link: https://lore.kernel.org/r/20190729195226.8862-2-andrew.smirnov@gmail.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b777b5de
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -983,6 +983,13 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
		unsigned char sr = readb(sport->port.membase + UARTSR1);

		if (sr & (UARTSR1_PE | UARTSR1_FE)) {
			unsigned char cr2;

			/* Disable receiver during this operation... */
			cr2 = readb(sport->port.membase + UARTCR2);
			cr2 &= ~UARTCR2_RE;
			writeb(cr2, sport->port.membase + UARTCR2);

			/* Read DR to clear the error flags */
			readb(sport->port.membase + UARTDR);

@@ -990,6 +997,25 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
				sport->port.icount.parity++;
			else if (sr & UARTSR1_FE)
				sport->port.icount.frame++;
			/*
			 * At this point parity/framing error is
			 * cleared However, since the DMA already read
			 * the data register and we had to read it
			 * again after reading the status register to
			 * properly clear the flags, the FIFO actually
			 * underflowed... This requires a clearing of
			 * the FIFO...
			 */
			if (readb(sport->port.membase + UARTSFIFO) &
			    UARTSFIFO_RXUF) {
				writeb(UARTSFIFO_RXUF,
				       sport->port.membase + UARTSFIFO);
				writeb(UARTCFIFO_RXFLUSH,
				       sport->port.membase + UARTCFIFO);
			}

			cr2 |= UARTCR2_RE;
			writeb(cr2, sport->port.membase + UARTCR2);
		}
	}