Skip to content

Commit

Permalink
dmaengine: fsl-edma: disable clks on all error paths
Browse files Browse the repository at this point in the history
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: Andreas Platschek <andreas.platschek@opentech.at>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
  • Loading branch information
Andreas Platschek authored and Vinod Koul committed Dec 15, 2017
1 parent eb94369 commit 2610acf
Showing 1 changed file with 14 additions and 14 deletions.
28 changes: 14 additions & 14 deletions drivers/dma/fsl-edma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

for (i = 0; i < DMAMUX_NR; i++)
for (i = 0; i < nr_clocks; i++)
clk_disable_unprepare(fsl_edma->muxclk[i]);
}

Expand Down Expand Up @@ -904,25 +904,25 @@ static int fsl_edma_probe(struct platform_device *pdev)

res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
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]);
}

sprintf(clkname, "dmamux%d", i);
fsl_edma->muxclk[i] = devm_clk_get(&pdev->dev, clkname);
if (IS_ERR(fsl_edma->muxclk[i])) {
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]);
}

ret = clk_prepare_enable(fsl_edma->muxclk[i]);
if (ret) {
/* disable only clks which were enabled on error */
for (; i >= 0; i--)
clk_disable_unprepare(fsl_edma->muxclk[i]);

dev_err(&pdev->dev, "DMAMUX clk block failed.\n");
return ret;
}
if (ret)
/* on error: disable all previously enabled clks */
fsl_disable_clocks(fsl_edma, i);

}

Expand Down Expand Up @@ -976,7 +976,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"Can't register Freescale eDMA engine. (%d)\n", ret);
fsl_disable_clocks(fsl_edma);
fsl_disable_clocks(fsl_edma, DMAMUX_NR);
return ret;
}

Expand All @@ -985,7 +985,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"Can't register Freescale eDMA of_dma. (%d)\n", ret);
dma_async_device_unregister(&fsl_edma->dma_dev);
fsl_disable_clocks(fsl_edma);
fsl_disable_clocks(fsl_edma, DMAMUX_NR);
return ret;
}

Expand Down Expand Up @@ -1015,7 +1015,7 @@ static int fsl_edma_remove(struct platform_device *pdev)
fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
of_dma_controller_free(np);
dma_async_device_unregister(&fsl_edma->dma_dev);
fsl_disable_clocks(fsl_edma);
fsl_disable_clocks(fsl_edma, DMAMUX_NR);

return 0;
}
Expand Down

0 comments on commit 2610acf

Please sign in to comment.