]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
serial: 8250: Add UART_BUG_TXRACE workaround for Aspeed VUART
authorAndrew Jeffery <andrew@aj.id.au>
Thu, 20 May 2021 02:13:33 +0000 (11:43 +0930)
committerStefan Bader <stefan.bader@canonical.com>
Wed, 30 Jun 2021 06:27:12 +0000 (08:27 +0200)
BugLink: https://bugs.launchpad.net/bugs/1931896
commit df8f2be2fd0b44b2cb6077068f52e05f0ac40897 upstream.

Aspeed Virtual UARTs directly bridge e.g. the system console UART on the
LPC bus to the UART interface on the BMC's internal APB. As such there's
no RS-232 signalling involved - the UART interfaces on each bus are
directly connected as the producers and consumers of the one set of
FIFOs.

The APB in the AST2600 generally runs at 100MHz while the LPC bus peaks
at 33MHz. The difference in clock speeds exposes a race in the VUART
design where a Tx data burst on the APB interface can result in a byte
lost on the LPC interface. The symptom is LSR[DR] remains clear on the
LPC interface despite data being present in its Rx FIFO, while LSR[THRE]
remains clear on the APB interface as the host has not consumed the data
the BMC has transmitted. In this state, the UART has stalled and no
further data can be transmitted without manual intervention (e.g.
resetting the FIFOs, resulting in loss of data).

The recommended work-around is to insert a read cycle on the APB
interface between writes to THR.

Cc: ChiaWei Wang <chiawei_wang@aspeedtech.com>
Tested-by: ChiaWei Wang <chiawei_wang@aspeedtech.com>
Reviewed-by: Jiri Slaby <jirislaby@kernel.org>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Cc: stable <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20210520021334.497341-2-andrew@aj.id.au
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Kelsey Skunberg <kelsey.skunberg@canonical.com>
drivers/tty/serial/8250/8250.h
drivers/tty/serial/8250/8250_aspeed_vuart.c
drivers/tty/serial/8250/8250_port.c

index 52bb21205bb682555ba6f22ce89b2ef388f0cc79..34aa2714f3c932e36b30710d282775014124e76f 100644 (file)
@@ -88,6 +88,7 @@ struct serial8250_config {
 #define UART_BUG_NOMSR (1 << 2)        /* UART has buggy MSR status bits (Au1x00) */
 #define UART_BUG_THRE  (1 << 3)        /* UART has buggy THRE reassertion */
 #define UART_BUG_PARITY        (1 << 4)        /* UART mishandles parity if FIFO enabled */
+#define UART_BUG_TXRACE        (1 << 5)        /* UART Tx fails to set remote DR */
 
 
 #ifdef CONFIG_SERIAL_8250_SHARE_IRQ
index c33e02cbde9303110a094f8d63523197e22f9d5d..ec0d1da71a203174b7291af4292f4c5d21937ccc 100644 (file)
@@ -403,6 +403,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
        port.port.status = UPSTAT_SYNC_FIFO;
        port.port.dev = &pdev->dev;
        port.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
+       port.bugs |= UART_BUG_TXRACE;
 
        rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
        if (rc < 0)
index b0af13074cd36d877ee7f1177af8cbc1ff07eab6..6e141429c98085daacc3da8ddc317e4153018935 100644 (file)
@@ -1815,6 +1815,18 @@ void serial8250_tx_chars(struct uart_8250_port *up)
        count = up->tx_loadsz;
        do {
                serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               if (up->bugs & UART_BUG_TXRACE) {
+                       /*
+                        * The Aspeed BMC virtual UARTs have a bug where data
+                        * may get stuck in the BMC's Tx FIFO from bursts of
+                        * writes on the APB interface.
+                        *
+                        * Delay back-to-back writes by a read cycle to avoid
+                        * stalling the VUART. Read a register that won't have
+                        * side-effects and discard the result.
+                        */
+                       serial_in(up, UART_SCR);
+               }
                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                port->icount.tx++;
                if (uart_circ_empty(xmit))