aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Genoud <richard.genoud@gmail.com>2016-12-06 07:05:33 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-01-19 14:18:03 -0500
commit2d789bd1fc24788116ee0711208ef439a8db7ba5 (patch)
tree987b9d77998ec11eb42bea5ddfae9681a45872b5
parent199c89fd32b2a127f12d5614a701e275f7f5a10f (diff)
tty/serial: atmel: RS485 half duplex w/DMA: enable RX after TX is done
commit b389f173aaa1204d6dc1f299082a162eb0491545 upstream. When using RS485 in half duplex, RX should be enabled when TX is finished, and stopped when TX starts. Before commit 0058f0871efe7b01c6 ("tty/serial: atmel: fix RS485 half duplex with DMA"), RX was not disabled in atmel_start_tx() if the DMA was used. So, collisions could happened. But disabling RX in atmel_start_tx() uncovered another bug: RX was enabled again in the wrong place (in atmel_tx_dma) instead of being enabled when TX is finished (in atmel_complete_tx_dma), so the transmission simply stopped. This bug was not triggered before commit 0058f0871efe7b01c6 ("tty/serial: atmel: fix RS485 half duplex with DMA") because RX was never disabled before. Moving atmel_start_rx() in atmel_complete_tx_dma() corrects the problem. Reported-by: Gil Weber <webergil@gmail.com> Fixes: 0058f0871efe7b01c6 Tested-by: Gil Weber <webergil@gmail.com> Signed-off-by: Richard Genoud <richard.genoud@gmail.com> Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/atmel_serial.c11
1 files changed, 5 insertions, 6 deletions
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 168b10cad47b..11c0117af80b 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -798,6 +798,11 @@ static void atmel_complete_tx_dma(void *arg)
798 */ 798 */
799 if (!uart_circ_empty(xmit)) 799 if (!uart_circ_empty(xmit))
800 atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); 800 atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
801 else if ((port->rs485.flags & SER_RS485_ENABLED) &&
802 !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
803 /* DMA done, stop TX, start RX for RS485 */
804 atmel_start_rx(port);
805 }
801 806
802 spin_unlock_irqrestore(&port->lock, flags); 807 spin_unlock_irqrestore(&port->lock, flags);
803} 808}
@@ -900,12 +905,6 @@ static void atmel_tx_dma(struct uart_port *port)
900 desc->callback = atmel_complete_tx_dma; 905 desc->callback = atmel_complete_tx_dma;
901 desc->callback_param = atmel_port; 906 desc->callback_param = atmel_port;
902 atmel_port->cookie_tx = dmaengine_submit(desc); 907 atmel_port->cookie_tx = dmaengine_submit(desc);
903
904 } else {
905 if (port->rs485.flags & SER_RS485_ENABLED) {
906 /* DMA done, stop TX, start RX for RS485 */
907 atmel_start_rx(port);
908 }
909 } 908 }
910 909
911 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 910 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)