]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
dmaengine: tegra: Return correct DMA status when paused
authorAkhil R <akhilrajeev@nvidia.com>
Thu, 12 Dec 2024 12:44:12 +0000 (18:14 +0530)
committerVinod Koul <vkoul@kernel.org>
Tue, 24 Dec 2024 10:19:30 +0000 (15:49 +0530)
Currently, the driver does not return the correct DMA status when a DMA
pause is issued by the client drivers. This causes GPCDMA users to
assume that DMA is still running, while in reality, the DMA is paused.

Return DMA_PAUSED for tx_status() if the channel is paused in the middle
of a transfer.

Fixes: ee17028009d4 ("dmaengine: tegra: Add tegra gpcdma driver")
Cc: stable@vger.kernel.org
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
Link: https://lore.kernel.org/r/20241212124412.5650-1-kkartik@nvidia.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/tegra186-gpc-dma.c

index cacf3757adc2e2ee1735e53e19c97281201582af..4d6fe0efa76e4b4270958e5cfeecdc7d5c762414 100644 (file)
@@ -231,6 +231,7 @@ struct tegra_dma_channel {
        bool config_init;
        char name[30];
        enum dma_transfer_direction sid_dir;
+       enum dma_status status;
        int id;
        int irq;
        int slave_id;
@@ -393,6 +394,8 @@ static int tegra_dma_pause(struct tegra_dma_channel *tdc)
                tegra_dma_dump_chan_regs(tdc);
        }
 
+       tdc->status = DMA_PAUSED;
+
        return ret;
 }
 
@@ -419,6 +422,8 @@ static void tegra_dma_resume(struct tegra_dma_channel *tdc)
        val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE);
        val &= ~TEGRA_GPCDMA_CHAN_CSRE_PAUSE;
        tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSRE, val);
+
+       tdc->status = DMA_IN_PROGRESS;
 }
 
 static int tegra_dma_device_resume(struct dma_chan *dc)
@@ -544,6 +549,7 @@ static void tegra_dma_xfer_complete(struct tegra_dma_channel *tdc)
 
        tegra_dma_sid_free(tdc);
        tdc->dma_desc = NULL;
+       tdc->status = DMA_COMPLETE;
 }
 
 static void tegra_dma_chan_decode_error(struct tegra_dma_channel *tdc,
@@ -716,6 +722,7 @@ static int tegra_dma_terminate_all(struct dma_chan *dc)
                tdc->dma_desc = NULL;
        }
 
+       tdc->status = DMA_COMPLETE;
        tegra_dma_sid_free(tdc);
        vchan_get_all_descriptors(&tdc->vc, &head);
        spin_unlock_irqrestore(&tdc->vc.lock, flags);
@@ -769,6 +776,9 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
        if (ret == DMA_COMPLETE)
                return ret;
 
+       if (tdc->status == DMA_PAUSED)
+               ret = DMA_PAUSED;
+
        spin_lock_irqsave(&tdc->vc.lock, flags);
        vd = vchan_find_desc(&tdc->vc, cookie);
        if (vd) {