diff options
author | Muhammad Hamza Farooq <mfarooq@visteon.com> | 2015-09-18 13:08:32 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-10-04 18:36:10 +0200 |
commit | e7327c09def48ccfd204025726f11b57a19a9c24 (patch) | |
tree | eddd5d76fd117cbe60f27f25558b907547150a3c /drivers/tty/serial/sh-sci.c | |
parent | serial: sh-sci: Do not terminate DMA engine when race condition occurs (diff) | |
download | linux-e7327c09def48ccfd204025726f11b57a19a9c24.tar.xz linux-e7327c09def48ccfd204025726f11b57a19a9c24.zip |
serial: sh-sci: Pause DMA engine and get DMA status again
Occasionally, DMA transaction completes _after_ DMA engine is stopped.
Verify if the transaction has not finished before forcing the engine to
stop and push the data
Signed-off-by: Muhammad Hamza Farooq <mfarooq@visteon.com>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
-rw-r--r-- | drivers/tty/serial/sh-sci.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 9406fe227bc7..b1d1ce1986e6 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1277,6 +1277,7 @@ static bool filter(struct dma_chan *chan, void *slave) static void rx_timer_fn(unsigned long arg) { struct sci_port *s = (struct sci_port *)arg; + struct dma_chan *chan = s->chan_rx; struct uart_port *port = &s->port; struct dma_tx_state state; enum dma_status status; @@ -1305,6 +1306,21 @@ static void rx_timer_fn(unsigned long arg) return; } + dmaengine_pause(chan); + + /* + * sometimes DMA transfer doesn't stop even if it is stopped and + * data keeps on coming until transaction is complete so check + * for DMA_COMPLETE again + * Let packet complete handler take care of the packet + */ + status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); + if (status == DMA_COMPLETE) { + spin_unlock_irqrestore(&port->lock, flags); + dev_dbg(port->dev, "Transaction complete after DMA engine was stopped"); + return; + } + /* Handle incomplete DMA receive */ dmaengine_terminate_all(s->chan_rx); read = sg_dma_len(&s->sg_rx[active]) - state.residue; |