| From foo@baz Mon Apr 9 17:09:24 CEST 2018 |
| From: Geert Uytterhoeven <geert+renesas@glider.be> |
| Date: Tue, 25 Apr 2017 20:15:35 +0200 |
| Subject: serial: sh-sci: Fix race condition causing garbage during shutdown |
| |
| From: Geert Uytterhoeven <geert+renesas@glider.be> |
| |
| |
| [ Upstream commit 1cf4a7efdc71cab84c42cfea7200608711ea954f ] |
| |
| If DMA is enabled and used, a burst of old data may be seen on the |
| serial console during "poweroff" or "reboot". uart_flush_buffer() |
| clears the circular buffer, but sci_port.tx_dma_len is not reset. |
| This leads to a circular buffer overflow, dumping (UART_XMIT_SIZE - |
| sci_port.tx_dma_len) bytes. |
| |
| To fix this, add a .flush_buffer() callback that resets |
| sci_port.tx_dma_len. |
| |
| Inspired by commit 31ca2c63fdc0aee7 ("tty/serial: atmel: fix race |
| condition (TX+DMA)"). |
| |
| Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/tty/serial/sh-sci.c | 16 ++++++++++++++-- |
| 1 file changed, 14 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/tty/serial/sh-sci.c |
| +++ b/drivers/tty/serial/sh-sci.c |
| @@ -1545,7 +1545,16 @@ static void sci_free_dma(struct uart_por |
| if (s->chan_rx) |
| sci_rx_dma_release(s, false); |
| } |
| -#else |
| + |
| +static void sci_flush_buffer(struct uart_port *port) |
| +{ |
| + /* |
| + * In uart_flush_buffer(), the xmit circular buffer has just been |
| + * cleared, so we have to reset tx_dma_len accordingly. |
| + */ |
| + to_sci_port(port)->tx_dma_len = 0; |
| +} |
| +#else /* !CONFIG_SERIAL_SH_SCI_DMA */ |
| static inline void sci_request_dma(struct uart_port *port) |
| { |
| } |
| @@ -1553,7 +1562,9 @@ static inline void sci_request_dma(struc |
| static inline void sci_free_dma(struct uart_port *port) |
| { |
| } |
| -#endif |
| + |
| +#define sci_flush_buffer NULL |
| +#endif /* !CONFIG_SERIAL_SH_SCI_DMA */ |
| |
| static irqreturn_t sci_rx_interrupt(int irq, void *ptr) |
| { |
| @@ -2551,6 +2562,7 @@ static const struct uart_ops sci_uart_op |
| .break_ctl = sci_break_ctl, |
| .startup = sci_startup, |
| .shutdown = sci_shutdown, |
| + .flush_buffer = sci_flush_buffer, |
| .set_termios = sci_set_termios, |
| .pm = sci_pm, |
| .type = sci_type, |