提交 18665414 编写于 作者: U Uwe Kleine-König 提交者: Greg Kroah-Hartman

serial: imx: Fix handling of TC irq in combination with DMA

When using RS485 half duplex the Transmitter Complete irq is needed to
determine the moment when the transmitter can be disabled. When using
DMA this irq must only be enabled when DMA has completed to transfer all
data. Otherwise the CPU might busily trigger this irq which is not
properly handled and so the also pending irq for the DMA transfer cannot
trigger.
Signed-off-by: NUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 81ca8e82
...@@ -575,6 +575,11 @@ static void dma_tx_callback(void *data) ...@@ -575,6 +575,11 @@ static void dma_tx_callback(void *data)
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
imx_dma_tx(sport); imx_dma_tx(sport);
else if (sport->port.rs485.flags & SER_RS485_ENABLED) {
u32 ucr4 = imx_uart_readl(sport, UCR4);
ucr4 |= UCR4_TCEN;
imx_uart_writel(sport, ucr4, UCR4);
}
spin_unlock_irqrestore(&sport->port.lock, flags); spin_unlock_irqrestore(&sport->port.lock, flags);
} }
...@@ -587,12 +592,16 @@ static void imx_dma_tx(struct imx_port *sport) ...@@ -587,12 +592,16 @@ static void imx_dma_tx(struct imx_port *sport)
struct dma_async_tx_descriptor *desc; struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = sport->dma_chan_tx; struct dma_chan *chan = sport->dma_chan_tx;
struct device *dev = sport->port.dev; struct device *dev = sport->port.dev;
u32 ucr1; u32 ucr1, ucr4;
int ret; int ret;
if (sport->dma_is_txing) if (sport->dma_is_txing)
return; return;
ucr4 = imx_uart_readl(sport, UCR4);
ucr4 &= ~UCR4_TCEN;
imx_uart_writel(sport, ucr4, UCR4);
sport->tx_bytes = uart_circ_chars_pending(xmit); sport->tx_bytes = uart_circ_chars_pending(xmit);
if (xmit->tail < xmit->head) { if (xmit->tail < xmit->head) {
...@@ -643,7 +652,7 @@ static void imx_start_tx(struct uart_port *port) ...@@ -643,7 +652,7 @@ static void imx_start_tx(struct uart_port *port)
u32 ucr1; u32 ucr1;
if (port->rs485.flags & SER_RS485_ENABLED) { if (port->rs485.flags & SER_RS485_ENABLED) {
u32 ucr2, ucr4; u32 ucr2;
ucr2 = imx_uart_readl(sport, UCR2); ucr2 = imx_uart_readl(sport, UCR2);
if (port->rs485.flags & SER_RS485_RTS_ON_SEND) if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
...@@ -655,10 +664,15 @@ static void imx_start_tx(struct uart_port *port) ...@@ -655,10 +664,15 @@ static void imx_start_tx(struct uart_port *port)
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
imx_stop_rx(port); imx_stop_rx(port);
/* enable transmitter and shifter empty irq */ /*
ucr4 = imx_uart_readl(sport, UCR4); * Enable transmitter and shifter empty irq only if DMA is off.
ucr4 |= UCR4_TCEN; * In the DMA case this is done in the tx-callback.
imx_uart_writel(sport, ucr4, UCR4); */
if (!sport->dma_is_enabled) {
u32 ucr4 = imx_uart_readl(sport, UCR4);
ucr4 |= UCR4_TCEN;
imx_uart_writel(sport, ucr4, UCR4);
}
} }
if (!sport->dma_is_enabled) { if (!sport->dma_is_enabled) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册