mirror of
https://github.com/torvalds/linux.git
synced 2024-12-01 16:41:39 +00:00
hwrng: stm32 - repair clock handling
The clock management in this driver does not seem to be correct. The struct hwrng .init callback enables the clock, but there is no matching .cleanup callback to disable the clock. The clock get disabled as some later point by runtime PM suspend callback. Furthermore, both runtime PM and sleep suspend callbacks access registers first and disable clock which are used for register access second. If the IP is already in RPM suspend and the system enters sleep state, the sleep callback will attempt to access registers while the register clock are already disabled. This bug has been fixed once before already in commit9bae54942b
("hwrng: stm32 - fix pm_suspend issue"), and regressed in commitff4e46104f
("hwrng: stm32 - rework power management sequences") . Fix this slightly differently, disable register clock at the end of .init callback, this way the IP is disabled after .init. On every access to the IP, which really is only stm32_rng_read(), do pm_runtime_get_sync() which is already done in stm32_rng_read() to bring the IP from RPM suspend, and pm_runtime_mark_last_busy()/pm_runtime_put_sync_autosuspend() to put it back into RPM suspend. Change sleep suspend/resume callbacks to enable and disable register clock around register access, as those cannot use the RPM suspend/resume callbacks due to slightly different initialization in those sleep callbacks. This way, the register access should always be performed with clock surely enabled. Fixes:ff4e46104f
("hwrng: stm32 - rework power management sequences") Signed-off-by: Marek Vasut <marex@denx.de> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
da62ed5c01
commit
c819d7b836
@ -363,6 +363,8 @@ static int stm32_rng_init(struct hwrng *rng)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -387,6 +389,11 @@ static int __maybe_unused stm32_rng_runtime_suspend(struct device *dev)
|
||||
static int __maybe_unused stm32_rng_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32_rng_private *priv = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(priv->clk);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (priv->data->has_cond_reset) {
|
||||
priv->pm_conf.nscr = readl_relaxed(priv->base + RNG_NSCR);
|
||||
@ -468,6 +475,8 @@ static int __maybe_unused stm32_rng_resume(struct device *dev)
|
||||
writel_relaxed(reg, priv->base + RNG_CR);
|
||||
}
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user