lkml.org 
[lkml]   [2017]   [Mar]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.16 210/370] tty/serial: atmel: RS485 half duplex w/DMA: enable RX after TX is done
    3.16.42-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Richard Genoud <richard.genoud@gmail.com>

    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>
    [bwh: Backported to 3.16:
    - s/port->rs485/atmel_port->rs485/
    - Adjust context]
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    ---
    drivers/tty/serial/atmel_serial.c | 11 +++++------
    1 file changed, 5 insertions(+), 6 deletions(-)

    --- a/drivers/tty/serial/atmel_serial.c
    +++ b/drivers/tty/serial/atmel_serial.c
    @@ -734,6 +734,11 @@ static void atmel_complete_tx_dma(void *
    /* Do we really need this? */
    if (!uart_circ_empty(xmit))
    tasklet_schedule(&atmel_port->tasklet);
    + else if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
    + !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) {
    + /* DMA done, stop TX, start RX for RS485 */
    + atmel_start_rx(port);
    + }

    spin_unlock_irqrestore(&port->lock, flags);
    }
    @@ -806,12 +811,6 @@ static void atmel_tx_dma(struct uart_por
    desc->callback = atmel_complete_tx_dma;
    desc->callback_param = atmel_port;
    atmel_port->cookie_tx = dmaengine_submit(desc);
    -
    - } else {
    - if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
    - /* DMA done, stop TX, start RX for RS485 */
    - atmel_start_rx(port);
    - }
    }

    if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
    \
     
     \ /
      Last update: 2017-03-10 14:54    [W:4.450 / U:0.072 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site