Message ID | 20200508132943.9826-9-Sergey.Semin@baikalelectronics.ru (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | spi: dw: Add generic DW DMA controller support | expand |
On Fri, May 08, 2020 at 04:29:33PM +0300, Serge Semin wrote: > If DMAC register is left uncleared any further DMAless transfers > may cause the DMAC hardware handshaking interface getting activated. > So the next DMA-based Rx/Tx transaction will be started right > after the dma_async_issue_pending() method is invoked even if no > DMATDLR/DMARDLR conditions are met. This at the same time may cause > the Tx/Rx FIFO buffers underrun/overrun. In order to fix this we > must clear DMAC register after a current DMA-based transaction is > finished. This also looks like a bugfix so should be pulled forwards to the start of the series if possible.
On Fri, May 08, 2020 at 06:31:34PM +0100, Mark Brown wrote: > On Fri, May 08, 2020 at 04:29:33PM +0300, Serge Semin wrote: > > If DMAC register is left uncleared any further DMAless transfers > > may cause the DMAC hardware handshaking interface getting activated. > > So the next DMA-based Rx/Tx transaction will be started right > > after the dma_async_issue_pending() method is invoked even if no > > DMATDLR/DMARDLR conditions are met. This at the same time may cause > > the Tx/Rx FIFO buffers underrun/overrun. In order to fix this we > > must clear DMAC register after a current DMA-based transaction is > > finished. > > This also looks like a bugfix so should be pulled forwards to the start > of the series if possible. Ok. -Sergey
diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c index 7f0e4d888125..7a6769386932 100644 --- a/drivers/spi/spi-dw-dma.c +++ b/drivers/spi/spi-dw-dma.c @@ -156,6 +156,8 @@ static void dw_spi_dma_tx_done(void *arg) clear_bit(TX_BUSY, &dws->dma_chan_busy); if (test_bit(RX_BUSY, &dws->dma_chan_busy)) return; + + dw_writel(dws, DW_SPI_DMACR, 0); spi_finalize_current_transfer(dws->master); } @@ -226,6 +228,8 @@ static void dw_spi_dma_rx_done(void *arg) clear_bit(RX_BUSY, &dws->dma_chan_busy); if (test_bit(TX_BUSY, &dws->dma_chan_busy)) return; + + dw_writel(dws, DW_SPI_DMACR, 0); spi_finalize_current_transfer(dws->master); } @@ -318,6 +322,8 @@ static void dw_spi_dma_stop(struct dw_spi *dws) dmaengine_terminate_sync(dws->rxchan); clear_bit(RX_BUSY, &dws->dma_chan_busy); } + + dw_writel(dws, DW_SPI_DMACR, 0); } static const struct dw_spi_dma_ops dw_spi_pci_dma_ops = {