diff options
author | Chanho Min <chanho0207@gmail.com> | 2012-02-19 20:24:40 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-02-24 16:50:47 -0500 |
commit | 6dc01aa65306fe46b7ba38db51fad4ed81c23d00 (patch) | |
tree | cad255d51a09c900062d9dbd2db07432dc4b5b19 /drivers/tty/serial | |
parent | b26469a8b139fba11d9336c1c117fafccfa9c7d5 (diff) |
amba-pl011/dma: Add check for the residue in DMA callback
In DMA-operated uart, I found that rx data can be taken by the UART
interrupts during the DMA irq handler. pl011_int is occurred just
before it goes inside spin_lock_irq. When it returns to the callback,
DMA buffer already has been flushed. Then, pl011_dma_rx_chars gets
invalid data. So I add check for the residue as the patch bellow.
Signed-off-by: Chanho Min <chanho.min@lge.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 6800f5f26241..cc3ea066c43a 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c | |||
@@ -827,7 +827,12 @@ static void pl011_dma_rx_callback(void *data) | |||
827 | { | 827 | { |
828 | struct uart_amba_port *uap = data; | 828 | struct uart_amba_port *uap = data; |
829 | struct pl011_dmarx_data *dmarx = &uap->dmarx; | 829 | struct pl011_dmarx_data *dmarx = &uap->dmarx; |
830 | struct dma_chan *rxchan = dmarx->chan; | ||
830 | bool lastbuf = dmarx->use_buf_b; | 831 | bool lastbuf = dmarx->use_buf_b; |
832 | struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ? | ||
833 | &dmarx->sgbuf_b : &dmarx->sgbuf_a; | ||
834 | size_t pending; | ||
835 | struct dma_tx_state state; | ||
831 | int ret; | 836 | int ret; |
832 | 837 | ||
833 | /* | 838 | /* |
@@ -838,11 +843,21 @@ static void pl011_dma_rx_callback(void *data) | |||
838 | * we immediately trigger the next DMA job. | 843 | * we immediately trigger the next DMA job. |
839 | */ | 844 | */ |
840 | spin_lock_irq(&uap->port.lock); | 845 | spin_lock_irq(&uap->port.lock); |
846 | /* | ||
847 | * Rx data can be taken by the UART interrupts during | ||
848 | * the DMA irq handler. So we check the residue here. | ||
849 | */ | ||
850 | rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state); | ||
851 | pending = sgbuf->sg.length - state.residue; | ||
852 | BUG_ON(pending > PL011_DMA_BUFFER_SIZE); | ||
853 | /* Then we terminate the transfer - we now know our residue */ | ||
854 | dmaengine_terminate_all(rxchan); | ||
855 | |||
841 | uap->dmarx.running = false; | 856 | uap->dmarx.running = false; |
842 | dmarx->use_buf_b = !lastbuf; | 857 | dmarx->use_buf_b = !lastbuf; |
843 | ret = pl011_dma_rx_trigger_dma(uap); | 858 | ret = pl011_dma_rx_trigger_dma(uap); |
844 | 859 | ||
845 | pl011_dma_rx_chars(uap, PL011_DMA_BUFFER_SIZE, lastbuf, false); | 860 | pl011_dma_rx_chars(uap, pending, lastbuf, false); |
846 | spin_unlock_irq(&uap->port.lock); | 861 | spin_unlock_irq(&uap->port.lock); |
847 | /* | 862 | /* |
848 | * Do this check after we picked the DMA chars so we don't | 863 | * Do this check after we picked the DMA chars so we don't |