Skip to content

Commit f58c252

Browse files
ij-intelgregkh
authored andcommitted
serial: 8250: fix XOFF/XON sending when DMA is used
When 8250 UART is using DMA, x_char (XON/XOFF) is never sent to the wire. After this change, x_char is injected correctly. Create uart_xchar_out() helper for sending the x_char out and accounting related to it. It seems that almost every driver does these same steps with x_char. Except for 8250, however, almost all currently lack .serial_out so they cannot immediately take advantage of this new helper. The downside of this patch is that it might reintroduce the problems some devices faced with mixed DMA/non-DMA transfer which caused revert f967fc8 (Revert "serial: 8250_dma: don't bother DMA with small transfers"). However, the impact should be limited to cases with XON/XOFF (that didn't work with DMA capable devices to begin with so this problem is not very likely to cause a major issue, if any at all). Fixes: 9ee4b83 ("serial: 8250: Add support for dmaengine") Reported-by: Gilles Buloz <gilles.buloz@kontron.com> Tested-by: Gilles Buloz <gilles.buloz@kontron.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Link: https://lore.kernel.org/r/20220314091432.4288-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 1db536f commit f58c252

File tree

4 files changed

+27
-4
lines changed

4 files changed

+27
-4
lines changed

drivers/tty/serial/8250/8250_dma.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,19 @@ int serial8250_tx_dma(struct uart_8250_port *p)
6464
struct uart_8250_dma *dma = p->dma;
6565
struct circ_buf *xmit = &p->port.state->xmit;
6666
struct dma_async_tx_descriptor *desc;
67+
struct uart_port *up = &p->port;
6768
int ret;
6869

69-
if (dma->tx_running)
70+
if (dma->tx_running) {
71+
if (up->x_char) {
72+
dmaengine_pause(dma->txchan);
73+
uart_xchar_out(up, UART_TX);
74+
dmaengine_resume(dma->txchan);
75+
}
7076
return 0;
77+
} else if (up->x_char) {
78+
uart_xchar_out(up, UART_TX);
79+
}
7180

7281
if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
7382
/* We have been called from __dma_tx_complete() */

drivers/tty/serial/8250/8250_port.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,9 +1822,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
18221822
int count;
18231823

18241824
if (port->x_char) {
1825-
serial_out(up, UART_TX, port->x_char);
1826-
port->icount.tx++;
1827-
port->x_char = 0;
1825+
uart_xchar_out(port, UART_TX);
18281826
return;
18291827
}
18301828
if (uart_tx_stopped(port)) {

drivers/tty/serial/serial_core.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,20 @@ static void uart_flush_buffer(struct tty_struct *tty)
641641
tty_port_tty_wakeup(&state->port);
642642
}
643643

644+
/*
645+
* This function performs low-level write of high-priority XON/XOFF
646+
* character and accounting for it.
647+
*
648+
* Requires uart_port to implement .serial_out().
649+
*/
650+
void uart_xchar_out(struct uart_port *uport, int offset)
651+
{
652+
serial_port_out(uport, offset, uport->x_char);
653+
uport->icount.tx++;
654+
uport->x_char = 0;
655+
}
656+
EXPORT_SYMBOL_GPL(uart_xchar_out);
657+
644658
/*
645659
* This function is used to send a high-priority XON/XOFF character to
646660
* the device

include/linux/serial_core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,8 @@ extern void uart_handle_cts_change(struct uart_port *uport,
458458
extern void uart_insert_char(struct uart_port *port, unsigned int status,
459459
unsigned int overrun, unsigned int ch, unsigned int flag);
460460

461+
void uart_xchar_out(struct uart_port *uport, int offset);
462+
461463
#ifdef CONFIG_MAGIC_SYSRQ_SERIAL
462464
#define SYSRQ_TIMEOUT (HZ * 5)
463465

0 commit comments

Comments
 (0)