On Thu, 9 Jan 2025 at 18:34, Daniel Lezcano <daniel.lezcano@xxxxxxxxxx> wrote: > > > Ulf, > > can you have a look at this particular patch please ? > > Perhaps this scenario already happened in the past and there is an > alternative to fix it instead of this proposed change I think the patch makes sense. If there is a PM domain that is attached to the device that is managing the clocks for the thermal zone, the detach procedure certainly needs to be well controlled/synchronized. > > > On 03/01/2025 17:38, Claudiu wrote: > > From: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> > > > > On the Renesas RZ/G3S (and other Renesas SoCs, e.g., RZ/G2{L, LC, UL}), > > clocks are managed through PM domains. These PM domains, registered on > > behalf of the clock controller driver, are configured with > > GENPD_FLAG_PM_CLK. In most of the Renesas drivers used by RZ SoCs, the > > clocks are enabled/disabled using runtime PM APIs. > > > > During probe, devices are attached to the PM domain controlling their > > clocks. Similarly, during removal, devices are detached from the PM domain. > > > > The detachment call stack is as follows: > > > > device_driver_detach() -> > > device_release_driver_internal() -> > > __device_release_driver() -> > > device_remove() -> > > platform_remove() -> > > dev_pm_domain_detach() > > > > In the upcoming Renesas RZ/G3S thermal driver, the > > struct thermal_zone_device_ops::change_mode API is implemented to > > start/stop the thermal sensor unit. Register settings are updated within > > the change_mode API. > > > > In case devres helpers are used for thermal zone register/unregister the > > struct thermal_zone_device_ops::change_mode API is invoked when the > > driver is unbound. The identified call stack is as follows: > > > > device_driver_detach() -> > > device_release_driver_internal() -> > > device_unbind_cleanup() -> > > devres_release_all() -> > > devm_thermal_of_zone_release() -> > > thermal_zone_device_disable() -> > > thermal_zone_device_set_mode() -> > > rzg3s_thermal_change_mode() > > > > The device_unbind_cleanup() function is called after the thermal device is > > detached from the PM domain (via dev_pm_domain_detach()). > > > > The rzg3s_thermal_change_mode() implementation calls > > pm_runtime_resume_and_get()/pm_runtime_put_autosuspend() before/after > > accessing the registers. However, during the unbind scenario, the > > devm_thermal_of_zone_release() is invoked after dev_pm_domain_detach(). > > Consequently, the clocks are not enabled, as the device is removed from > > the PM domain at this time, leading to an Asynchronous SError Interrupt. > > The system cannot be used after this. > > > > Add thermal_of_zone_register()/thermal_of_zone_unregister(). These will > > be used in the upcomming RZ/G3S thermal driver. > > > > Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> Reviewed-by: Ulf Hansson <ulf.hansson@xxxxxxxxxx> Kind regards Uffe > > --- > > drivers/thermal/thermal_of.c | 8 +++++--- > > include/linux/thermal.h | 14 ++++++++++++++ > > 2 files changed, 19 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c > > index fab11b98ca49..8fc35d20db60 100644 > > --- a/drivers/thermal/thermal_of.c > > +++ b/drivers/thermal/thermal_of.c > > @@ -329,11 +329,12 @@ static bool thermal_of_should_bind(struct thermal_zone_device *tz, > > * > > * @tz: a pointer to the thermal zone structure > > */ > > -static void thermal_of_zone_unregister(struct thermal_zone_device *tz) > > +void thermal_of_zone_unregister(struct thermal_zone_device *tz) > > { > > thermal_zone_device_disable(tz); > > thermal_zone_device_unregister(tz); > > } > > +EXPORT_SYMBOL_GPL(thermal_of_zone_unregister); > > > > /** > > * thermal_of_zone_register - Register a thermal zone with device node > > @@ -355,8 +356,8 @@ static void thermal_of_zone_unregister(struct thermal_zone_device *tz) > > * - ENOMEM: if one structure can not be allocated > > * - Other negative errors are returned by the underlying called functions > > */ > > -static struct thermal_zone_device *thermal_of_zone_register(struct device_node *sensor, int id, void *data, > > - const struct thermal_zone_device_ops *ops) > > +struct thermal_zone_device *thermal_of_zone_register(struct device_node *sensor, int id, void *data, > > + const struct thermal_zone_device_ops *ops) > > { > > struct thermal_zone_device_ops of_ops = *ops; > > struct thermal_zone_device *tz; > > @@ -429,6 +430,7 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node * > > > > return ERR_PTR(ret); > > } > > +EXPORT_SYMBOL_GPL(thermal_of_zone_register); > > > > static void devm_thermal_of_zone_release(struct device *dev, void *res) > > { > > diff --git a/include/linux/thermal.h b/include/linux/thermal.h > > index 69f9bedd0ee8..adbb4092a064 100644 > > --- a/include/linux/thermal.h > > +++ b/include/linux/thermal.h > > @@ -195,13 +195,23 @@ struct thermal_zone_params { > > > > /* Function declarations */ > > #ifdef CONFIG_THERMAL_OF > > +struct thermal_zone_device *thermal_of_zone_register(struct device_node *sensor, int id, void *data, > > + const struct thermal_zone_device_ops *ops); > > struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, int id, void *data, > > const struct thermal_zone_device_ops *ops); > > > > +void thermal_of_zone_unregister(struct thermal_zone_device *tz); > > void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_device *tz); > > > > #else > > > > +static inline > > +struct thermal_zone_device *thermal_of_zone_register(struct device_node *sensor, int id, void *data, > > + const struct thermal_zone_device_ops *ops) > > +{ > > + return ERR_PTR(-ENOTSUPP); > > +} > > + > > static inline > > struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, int id, void *data, > > const struct thermal_zone_device_ops *ops) > > @@ -209,6 +219,10 @@ struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, in > > return ERR_PTR(-ENOTSUPP); > > } > > > > +static inline void thermal_of_zone_unregister(struct thermal_zone_device *tz) > > +{ > > +} > > + > > static inline void devm_thermal_of_zone_unregister(struct device *dev, > > struct thermal_zone_device *tz) > > { > > > -- > <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs > > Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | > <http://twitter.com/#!/linaroorg> Twitter | > <http://www.linaro.org/linaro-blog/> Blog