]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
dmaengine: dw-axi-dmac: fix PM for system sleep and channel alloc
authorTze Yee Ng <tze.yee.ng@altera.com>
Mon, 25 May 2026 07:10:22 +0000 (00:10 -0700)
committerVinod Koul <vkoul@kernel.org>
Thu, 11 Jun 2026 05:28:42 +0000 (10:58 +0530)
The driver only had runtime PM callbacks. If a channel stayed allocated
across system suspend/resume, the runtime usage count could remain
non-zero while hardware state (DMAC_CFG, clocks) was lost, and
axi_dma_runtime_resume() would not run to restore it.

Add system-sleep PM ops that use pm_runtime_force_suspend() and
pm_runtime_force_resume() so suspend/resume reuses the existing
axi_dma_suspend() and axi_dma_resume() paths.

Replace pm_runtime_get() with pm_runtime_resume_and_get() in
dma_chan_alloc_chan_resources() so clocks are enabled before a client
can immediately submit a transfer and touch MMIO.

Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
Link: https://patch.msgid.link/18bf778a3a1cc2f377ef8eb0d1508d8ac6371896.1779688569.git.tze.yee.ng@altera.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c

index f7a50f470461c60c2e3b30e6df46aaa01d58e5ae..bcefaff03b5c66a1b749d158761b60d7e5368ca9 100644 (file)
@@ -516,11 +516,17 @@ static void dw_axi_dma_synchronize(struct dma_chan *dchan)
 static int dma_chan_alloc_chan_resources(struct dma_chan *dchan)
 {
        struct axi_dma_chan *chan = dchan_to_axi_dma_chan(dchan);
+       int ret;
+
+       ret = pm_runtime_resume_and_get(chan->chip->dev);
+       if (ret < 0)
+               return ret;
 
        /* ASSERT: channel is idle */
        if (axi_chan_is_hw_enable(chan)) {
                dev_err(chan2dev(chan), "%s is non-idle!\n",
                        axi_chan_name(chan));
+               pm_runtime_put(chan->chip->dev);
                return -EBUSY;
        }
 
@@ -531,12 +537,11 @@ static int dma_chan_alloc_chan_resources(struct dma_chan *dchan)
                                          64, 0);
        if (!chan->desc_pool) {
                dev_err(chan2dev(chan), "No memory for descriptors\n");
+               pm_runtime_put(chan->chip->dev);
                return -ENOMEM;
        }
        dev_vdbg(dchan2dev(dchan), "%s: allocating\n", axi_chan_name(chan));
 
-       pm_runtime_get(chan->chip->dev);
-
        return 0;
 }
 
@@ -1663,6 +1668,8 @@ static void dw_remove(struct platform_device *pdev)
 }
 
 static const struct dev_pm_ops dw_axi_dma_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
        SET_RUNTIME_PM_OPS(axi_dma_runtime_suspend, axi_dma_runtime_resume, NULL)
 };