From: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> Restart devices (e.g., watchdog) may be part of a software-controlled power domain. In the case of watchdog devices, if they implement the struct watchdog::restart() API, this is called though: kernel_restart() -> machine_restart() -> do_kernel_restart() -> atomic_notifier_call_chain() -> watchdog_restart_notifier() The watchdog_restart_notifier() is called with local interrupts disabled and SMP disabled (machine_restart() calls local_irq_disable() and smp_send_stop() before calling do_kernel_restart()). If the restart device (e.g., watchdog) is part of a software-controlled power domain and this domain is off at the moment of restart, we need to power it on before configuring the watchdog device. Add the dev_pm_genpd_resume_restart_dev() function to power on a restart device in these scenarios. Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> --- drivers/pmdomain/core.c | 18 ++++++++++++++++++ include/linux/pm_domain.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c index 83d978743659..d05bd72f6cfe 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -1540,6 +1540,24 @@ void dev_pm_genpd_resume(struct device *dev) } EXPORT_SYMBOL_GPL(dev_pm_genpd_resume); +/** + * dev_pm_genpd_resume_restart_dev - Try to synchronously resume the genpd for + * a reset device + * @dev: The reset device that is attached to the genpd, which needs to be + * resumed. + * + * This routine should tipicaly be called for a restart device (e.g. watchdog) + * that needs to be resumed during system restart phase. + */ +void dev_pm_genpd_resume_restart_dev(struct device *dev) +{ + if (system_state != SYSTEM_RESTART) + return; + + dev_pm_genpd_resume(dev); +} +EXPORT_SYMBOL_GPL(dev_pm_genpd_resume_restart_dev); + #else /* !CONFIG_PM_SLEEP */ #define genpd_prepare NULL diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 71e4f0fb8867..9f8ecfa0bf3c 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -347,9 +347,11 @@ static inline void dev_pm_genpd_synced_poweroff(struct device *dev) #ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP void dev_pm_genpd_suspend(struct device *dev); void dev_pm_genpd_resume(struct device *dev); +void dev_pm_genpd_resume_restart_dev(struct device *dev); #else static inline void dev_pm_genpd_suspend(struct device *dev) {} static inline void dev_pm_genpd_resume(struct device *dev) {} +static inline void dev_pm_genpd_resume_restart_dev(struct device *dev) {} #endif /* OF PM domain providers */ -- 2.39.2