Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+14 −14
Original line number Diff line number Diff line
@@ -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]);
}

@@ -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);

	}

@@ -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;
	}

@@ -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;
	}

@@ -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;
}