mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 12:52:29 -04:00
hwrng: omap - Fix probe error path cleanup
omap_rng_probe() enables runtime PM before acquiring and enabling the functional clocks. Several later error paths returned or unwound without undoing all state acquired so far. If pm_runtime_resume_and_get() failed, the driver returned through the generic ioremap error label and left runtime PM enabled. If either clock lookup returned -EPROBE_DEFER, the function returned directly and skipped the runtime PM cleanup; the register clock defer path could also leave the already enabled functional clock prepared. Route these failures through the existing unwind labels so each path only undoes resources that were acquired successfully. Keep the resume failure path limited to pm_runtime_disable(), and use the later labels only after the runtime PM usage count or clocks have been acquired. This issue was identified during our ongoing static-analysis research while reviewing kernel code. Fixes:61dc0a446e("hwrng: omap - Fix assumption that runtime_get_sync will always succeed") Fixes:43ec540e6f("hwrng: omap - move clock related code to omap_rng_probe()") Fixes:b166be0044("hwrng: omap - Fix clock resource by adding a register clock") Co-developed-by: Ijae Kim <ae878000@gmail.com> Signed-off-by: Ijae Kim <ae878000@gmail.com> Signed-off-by: Myeonghun Pak <mhun512@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
committed by
Herbert Xu
parent
ba08897441
commit
f8c24e6899
@@ -455,32 +455,40 @@ static int omap_rng_probe(struct platform_device *pdev)
|
||||
ret = pm_runtime_resume_and_get(&pdev->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to runtime_get device: %d\n", ret);
|
||||
goto err_ioremap;
|
||||
goto err_pm_disable;
|
||||
}
|
||||
|
||||
priv->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (PTR_ERR(priv->clk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
if (PTR_ERR(priv->clk) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err_pm_put;
|
||||
}
|
||||
if (!IS_ERR(priv->clk)) {
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to enable the clk: %d\n", ret);
|
||||
goto err_register;
|
||||
goto err_pm_put;
|
||||
}
|
||||
} else {
|
||||
priv->clk = NULL;
|
||||
}
|
||||
|
||||
priv->clk_reg = devm_clk_get(&pdev->dev, "reg");
|
||||
if (PTR_ERR(priv->clk_reg) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
if (PTR_ERR(priv->clk_reg) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err_clk;
|
||||
}
|
||||
if (!IS_ERR(priv->clk_reg)) {
|
||||
ret = clk_prepare_enable(priv->clk_reg);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to enable the register clk: %d\n",
|
||||
ret);
|
||||
goto err_register;
|
||||
goto err_clk;
|
||||
}
|
||||
} else {
|
||||
priv->clk_reg = NULL;
|
||||
}
|
||||
|
||||
ret = (dev->of_node) ? of_get_omap_rng_device_details(priv, pdev) :
|
||||
@@ -498,12 +506,14 @@ static int omap_rng_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
err_register:
|
||||
clk_disable_unprepare(priv->clk_reg);
|
||||
err_clk:
|
||||
clk_disable_unprepare(priv->clk);
|
||||
err_pm_put:
|
||||
priv->base = NULL;
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
err_pm_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
clk_disable_unprepare(priv->clk_reg);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
err_ioremap:
|
||||
dev_err(dev, "initialization failed.\n");
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user