Add proper reset control handling to the AXI DMA driver to ensure
reliable initialization and power management. The driver now manages
resets during probe, remove, and system suspend/resume operations.
The implementation stores reset control in the chip structure and adds
reset assert/deassert calls at the appropriate points: resets are
deasserted during probe after clock acquisition, asserted during remove
and error cleanup, and properly managed during suspend/resume cycles.
Additionally, proper error handling is implemented for reset control
operations to ensure robust behavior.
This ensures the controller is properly reset during power transitions
and prevents potential issues with incomplete initialization.
Signed-off-by: Artem Shimko <a.shimko.dev@gmail.com>
---
.../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 50 +++++++++++++------
drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 1 +
2 files changed, 35 insertions(+), 16 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 8b7cf3baf5d3..a3e93b658c21 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -1316,11 +1316,16 @@ static int dma_chan_resume(struct dma_chan *dchan)
static int axi_dma_suspend(struct device *dev)
{
+ int ret;
struct axi_dma_chip *chip = dev_get_drvdata(dev);
axi_dma_irq_disable(chip);
axi_dma_disable(chip);
+ ret = reset_control_assert(chip->resets);
+ if (ret)
+ dev_warn(dev, "Failed to assert resets, but continuing suspend\n");
+
clk_disable_unprepare(chip->core_clk);
clk_disable_unprepare(chip->cfgr_clk);
@@ -1340,6 +1345,10 @@ static int axi_dma_resume(struct device *dev)
if (ret < 0)
return ret;
+ ret = reset_control_deassert(chip->resets);
+ if (ret)
+ return ret;
+
axi_dma_enable(chip);
axi_dma_irq_enable(chip);
@@ -1455,7 +1464,6 @@ static int dw_probe(struct platform_device *pdev)
struct axi_dma_chip *chip;
struct dw_axi_dma *dw;
struct dw_axi_dma_hcfg *hdata;
- struct reset_control *resets;
unsigned int flags;
u32 i;
int ret;
@@ -1487,16 +1495,6 @@ static int dw_probe(struct platform_device *pdev)
return PTR_ERR(chip->apb_regs);
}
- if (flags & AXI_DMA_FLAG_HAS_RESETS) {
- resets = devm_reset_control_array_get_exclusive(&pdev->dev);
- if (IS_ERR(resets))
- return PTR_ERR(resets);
-
- ret = reset_control_deassert(resets);
- if (ret)
- return ret;
- }
-
chip->dw->hdata->use_cfg2 = !!(flags & AXI_DMA_FLAG_USE_CFG2);
chip->core_clk = devm_clk_get(chip->dev, "core-clk");
@@ -1507,18 +1505,28 @@ static int dw_probe(struct platform_device *pdev)
if (IS_ERR(chip->cfgr_clk))
return PTR_ERR(chip->cfgr_clk);
+ chip->resets = devm_reset_control_array_get_optional_exclusive(&pdev->dev);
+ if (IS_ERR(chip->resets))
+ return PTR_ERR(chip->resets);
+
+ ret = reset_control_deassert(chip->resets);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to deassert resets\n");
+
ret = parse_device_properties(chip);
if (ret)
- return ret;
+ goto err_exit;
dw->chan = devm_kcalloc(chip->dev, hdata->nr_channels,
sizeof(*dw->chan), GFP_KERNEL);
- if (!dw->chan)
- return -ENOMEM;
+ if (!dw->chan) {
+ ret = -ENOMEM;
+ goto err_exit;
+ }
ret = axi_req_irqs(pdev, chip);
if (ret)
- return ret;
+ goto err_exit;
INIT_LIST_HEAD(&dw->dma.channels);
for (i = 0; i < hdata->nr_channels; i++) {
@@ -1605,20 +1613,30 @@ static int dw_probe(struct platform_device *pdev)
err_pm_disable:
pm_runtime_disable(chip->dev);
+err_exit:
+ reset_control_assert(chip->resets);
return ret;
}
static void dw_remove(struct platform_device *pdev)
{
+ int ret;
struct axi_dma_chip *chip = platform_get_drvdata(pdev);
struct dw_axi_dma *dw = chip->dw;
struct axi_dma_chan *chan, *_chan;
u32 i;
- /* Enable clk before accessing to registers */
+ /*
+ * The peripheral must be clocked and out of reset
+ * before its registers can be accessed.
+ */
clk_prepare_enable(chip->cfgr_clk);
clk_prepare_enable(chip->core_clk);
+ ret = reset_control_deassert(chip->resets);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to deassert resets\n");
+
axi_dma_irq_disable(chip);
for (i = 0; i < dw->hdata->nr_channels; i++) {
axi_chan_disable(&chip->dw->chan[i]);
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
index b842e6a8d90d..c74affb9f344 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
@@ -71,6 +71,7 @@ struct axi_dma_chip {
struct clk *core_clk;
struct clk *cfgr_clk;
struct dw_axi_dma *dw;
+ struct reset_control *resets;
};
/* LLI == Linked List Item */
--
2.43.0
Hi Artem,
kernel test robot noticed the following build warnings:
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Artem-Shimko/dmaengine-dw-axi-dmac-simplify-PM-functions-and-use-modern-macros/20251017-183103
base: https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git next
patch link: https://lore.kernel.org/r/20251017102950.206443-3-a.shimko.dev%40gmail.com
patch subject: [PATCH v4 2/2] dmaengine: dw-axi-dmac: add reset control support
config: loongarch-randconfig-r072-20251019 (https://download.01.org/0day-ci/archive/20251022/202510221508.PY6fB9CB-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 15.1.0
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202510221508.PY6fB9CB-lkp@intel.com/
New smatch warnings:
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:1355 axi_dma_resume() warn: 'chip->core_clk' from clk_prepare_enable() not released on lines: 1350.
Old smatch warnings:
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:1237 dma_chan_pause() warn: inconsistent indenting
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:1284 axi_chan_resume() warn: inconsistent indenting
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:1355 axi_dma_resume() warn: 'chip->cfgr_clk' from clk_prepare_enable() not released on lines: 1346,1350.
vim +1355 drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
45fdf99125b2bf7 Artem Shimko 2025-10-17 1335 static int axi_dma_resume(struct device *dev)
I guess kbuild bot thinks these are new warnings because the function
was renamed. In the past we've just ignored clk_prepare_enable() warnings.
Perhaps that's the correct thing to do in a resume function.
The indenting in dma_chan_pause() and axi_chan_resume() could be cleaned up.
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1336 {
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1337 int ret;
45fdf99125b2bf7 Artem Shimko 2025-10-17 1338 struct axi_dma_chip *chip = dev_get_drvdata(dev);
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1339
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1340 ret = clk_prepare_enable(chip->cfgr_clk);
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1341 if (ret < 0)
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1342 return ret;
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1343
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1344 ret = clk_prepare_enable(chip->core_clk);
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1345 if (ret < 0)
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1346 return ret;
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1347
9c360f02c387f93 Artem Shimko 2025-10-17 1348 ret = reset_control_deassert(chip->resets);
9c360f02c387f93 Artem Shimko 2025-10-17 1349 if (ret)
9c360f02c387f93 Artem Shimko 2025-10-17 1350 return ret;
9c360f02c387f93 Artem Shimko 2025-10-17 1351
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1352 axi_dma_enable(chip);
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1353 axi_dma_irq_enable(chip);
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1354
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 @1355 return 0;
1fe20f1b84548bb Eugeniy Paltsev 2018-03-06 1356 }
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.