mirror of
https://github.com/torvalds/linux.git
synced 2024-12-02 09:01:34 +00:00
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 revertf967fc8f16
(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:9ee4b83e51
("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>
This commit is contained in:
parent
1db536f95d
commit
f58c252e30
@ -64,10 +64,19 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct uart_port *up = &p->port;
|
||||
int ret;
|
||||
|
||||
if (dma->tx_running)
|
||||
if (dma->tx_running) {
|
||||
if (up->x_char) {
|
||||
dmaengine_pause(dma->txchan);
|
||||
uart_xchar_out(up, UART_TX);
|
||||
dmaengine_resume(dma->txchan);
|
||||
}
|
||||
return 0;
|
||||
} else if (up->x_char) {
|
||||
uart_xchar_out(up, UART_TX);
|
||||
}
|
||||
|
||||
if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
|
||||
/* We have been called from __dma_tx_complete() */
|
||||
|
@ -1822,9 +1822,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
||||
int count;
|
||||
|
||||
if (port->x_char) {
|
||||
serial_out(up, UART_TX, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
uart_xchar_out(port, UART_TX);
|
||||
return;
|
||||
}
|
||||
if (uart_tx_stopped(port)) {
|
||||
|
@ -641,6 +641,20 @@ static void uart_flush_buffer(struct tty_struct *tty)
|
||||
tty_port_tty_wakeup(&state->port);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function performs low-level write of high-priority XON/XOFF
|
||||
* character and accounting for it.
|
||||
*
|
||||
* Requires uart_port to implement .serial_out().
|
||||
*/
|
||||
void uart_xchar_out(struct uart_port *uport, int offset)
|
||||
{
|
||||
serial_port_out(uport, offset, uport->x_char);
|
||||
uport->icount.tx++;
|
||||
uport->x_char = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_xchar_out);
|
||||
|
||||
/*
|
||||
* This function is used to send a high-priority XON/XOFF character to
|
||||
* the device
|
||||
|
@ -458,6 +458,8 @@ extern void uart_handle_cts_change(struct uart_port *uport,
|
||||
extern void uart_insert_char(struct uart_port *port, unsigned int status,
|
||||
unsigned int overrun, unsigned int ch, unsigned int flag);
|
||||
|
||||
void uart_xchar_out(struct uart_port *uport, int offset);
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ_SERIAL
|
||||
#define SYSRQ_TIMEOUT (HZ * 5)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user