summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTze Yee Ng <tze.yee.ng@altera.com>2026-05-25 10:10:22 +0300
committerVinod Koul <vkoul@kernel.org>2026-06-11 08:28:42 +0300
commitdf0c2dc68770cf43f15df40b184df030b850ea05 (patch)
tree3262cb5a9a9a556a6814000108ab8ec4aefa8682
parentdc6d681e1571c89cd38145926fb2513d70a633e1 (diff)
downloadlinux-df0c2dc68770cf43f15df40b184df030b850ea05.tar.xz
dmaengine: dw-axi-dmac: fix PM for system sleep and channel alloc
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>
-rw-r--r--drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index f7a50f470461..bcefaff03b5c 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -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)
};