Commit 2610acf4 authored by Andreas Platschek's avatar Andreas Platschek Committed by Vinod Koul

dmaengine: fsl-edma: disable clks on all error paths

Previously enabled clks are only disabled if clk_prepare_enable() fails.
However, there are other error paths were the previously enabled
clocks are not disabled.

To fix the problem, fsl_disable_clocks() now takes the number of clocks
that shall be disabled + unprepared. For existing calls were all clocks
were already successfully prepared + enabled, DMAMUX_NR is passed to
disable + unprepare all clocks.

In error paths were only some clocks were successfully prepared +
enabled the loop counter is passed, in order to disable + unprepare
all successfully prepared + enabled clocks.

Found by Linux Driver Verification project (linuxtesting.org).
Signed-off-by: default avatarAndreas Platschek <andreas.platschek@opentech.at>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
parent eb943696
...@@ -863,11 +863,11 @@ static void fsl_edma_irq_exit( ...@@ -863,11 +863,11 @@ static void fsl_edma_irq_exit(
} }
} }
static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma) static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma, int nr_clocks)
{ {
int i; int i;
for (i = 0; i < DMAMUX_NR; i++) for (i = 0; i < nr_clocks; i++)
clk_disable_unprepare(fsl_edma->muxclk[i]); clk_disable_unprepare(fsl_edma->muxclk[i]);
} }
...@@ -904,25 +904,25 @@ static int fsl_edma_probe(struct platform_device *pdev) ...@@ -904,25 +904,25 @@ static int fsl_edma_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i); res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
fsl_edma->muxbase[i] = devm_ioremap_resource(&pdev->dev, res); fsl_edma->muxbase[i] = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(fsl_edma->muxbase[i])) if (IS_ERR(fsl_edma->muxbase[i])) {
/* on error: disable all previously enabled clks */
fsl_disable_clocks(fsl_edma, i);
return PTR_ERR(fsl_edma->muxbase[i]); return PTR_ERR(fsl_edma->muxbase[i]);
}
sprintf(clkname, "dmamux%d", i); sprintf(clkname, "dmamux%d", i);
fsl_edma->muxclk[i] = devm_clk_get(&pdev->dev, clkname); fsl_edma->muxclk[i] = devm_clk_get(&pdev->dev, clkname);
if (IS_ERR(fsl_edma->muxclk[i])) { if (IS_ERR(fsl_edma->muxclk[i])) {
dev_err(&pdev->dev, "Missing DMAMUX block clock.\n"); dev_err(&pdev->dev, "Missing DMAMUX block clock.\n");
/* on error: disable all previously enabled clks */
fsl_disable_clocks(fsl_edma, i);
return PTR_ERR(fsl_edma->muxclk[i]); return PTR_ERR(fsl_edma->muxclk[i]);
} }
ret = clk_prepare_enable(fsl_edma->muxclk[i]); ret = clk_prepare_enable(fsl_edma->muxclk[i]);
if (ret) { if (ret)
/* disable only clks which were enabled on error */ /* on error: disable all previously enabled clks */
for (; i >= 0; i--) fsl_disable_clocks(fsl_edma, i);
clk_disable_unprepare(fsl_edma->muxclk[i]);
dev_err(&pdev->dev, "DMAMUX clk block failed.\n");
return ret;
}
} }
...@@ -976,7 +976,7 @@ static int fsl_edma_probe(struct platform_device *pdev) ...@@ -976,7 +976,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
if (ret) { if (ret) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Can't register Freescale eDMA engine. (%d)\n", ret); "Can't register Freescale eDMA engine. (%d)\n", ret);
fsl_disable_clocks(fsl_edma); fsl_disable_clocks(fsl_edma, DMAMUX_NR);
return ret; return ret;
} }
...@@ -985,7 +985,7 @@ static int fsl_edma_probe(struct platform_device *pdev) ...@@ -985,7 +985,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Can't register Freescale eDMA of_dma. (%d)\n", ret); "Can't register Freescale eDMA of_dma. (%d)\n", ret);
dma_async_device_unregister(&fsl_edma->dma_dev); dma_async_device_unregister(&fsl_edma->dma_dev);
fsl_disable_clocks(fsl_edma); fsl_disable_clocks(fsl_edma, DMAMUX_NR);
return ret; return ret;
} }
...@@ -1015,7 +1015,7 @@ static int fsl_edma_remove(struct platform_device *pdev) ...@@ -1015,7 +1015,7 @@ static int fsl_edma_remove(struct platform_device *pdev)
fsl_edma_cleanup_vchan(&fsl_edma->dma_dev); fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
of_dma_controller_free(np); of_dma_controller_free(np);
dma_async_device_unregister(&fsl_edma->dma_dev); dma_async_device_unregister(&fsl_edma->dma_dev);
fsl_disable_clocks(fsl_edma); fsl_disable_clocks(fsl_edma, DMAMUX_NR);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment