Some thermal drivers support trip point interrupts. These IRQs are triggered when the defined temperature threshold value is reached. This information is enough to say what is the temperature. Therefore, create a new API, which allows to provide temperature value as an argument and avoid reading the temperature again by in the framework function. This would also avoid scenario when the temperature which is later read via update_temperature() is different than the one which triggered the IRQ. This issue has been reported on some mainline boards. It should also improve performance in such scenario, since there is no call to __thermal_zone_get_temp() in the code path (which might be heavy, when temperature sensor is connected via slow interface). Signed-off-by: Lukasz Luba <lukasz.luba@xxxxxxx> --- Hi all, This is a RFC with proposal to skip reading temperature using get_temp() callback when calling thermal_zone_device_update() from thermal driver IRQ hanlder. There was a discussion [1] that reading temperature after the IRQ might give different value than that IRQ trip threshold was programmed. Therefore, this proposal aims to solve the situation and feed temperature to the thermal fwk as an argument. Regards, Lukasz [1] https://lore.kernel.org/lkml/20231113130435.500353-1-m.majewski2@xxxxxxxxxxx/ drivers/thermal/thermal_core.c | 29 ++++++++++++++++++++++++----- drivers/thermal/thermal_core.h | 3 ++- drivers/thermal/thermal_sysfs.c | 6 ++++-- drivers/thermal/thermal_trip.c | 2 +- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 62979c5401c3..9f25c62bd3cd 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -417,10 +417,16 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, handle_non_critical_trips(tz, trip); } -static void update_temperature(struct thermal_zone_device *tz) +static void update_temperature(struct thermal_zone_device *tz, bool read_temp, + int known_temp) { int temp, ret; + if (!read_temp) { + temp = known_temp; + goto set_temperature; + } + ret = __thermal_zone_get_temp(tz, &temp); if (ret) { if (ret != -EAGAIN) @@ -430,6 +436,7 @@ static void update_temperature(struct thermal_zone_device *tz) return; } +set_temperature: tz->last_temperature = tz->temperature; tz->temperature = temp; @@ -449,7 +456,8 @@ static void thermal_zone_device_init(struct thermal_zone_device *tz) } void __thermal_zone_device_update(struct thermal_zone_device *tz, - enum thermal_notify_event event) + enum thermal_notify_event event, + bool read_temp, int temp) { struct thermal_trip *trip; @@ -459,7 +467,7 @@ void __thermal_zone_device_update(struct thermal_zone_device *tz, if (!thermal_zone_device_is_enabled(tz)) return; - update_temperature(tz); + update_temperature(tz, read_temp, temp); __thermal_zone_set_trips(tz); @@ -491,7 +499,7 @@ static int thermal_zone_device_set_mode(struct thermal_zone_device *tz, if (!ret) tz->mode = mode; - __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED, true, 0); mutex_unlock(&tz->lock); @@ -532,11 +540,22 @@ void thermal_zone_device_update(struct thermal_zone_device *tz, { mutex_lock(&tz->lock); if (thermal_zone_is_present(tz)) - __thermal_zone_device_update(tz, event); + __thermal_zone_device_update(tz, event, true, 0); mutex_unlock(&tz->lock); } EXPORT_SYMBOL_GPL(thermal_zone_device_update); +void thermal_zone_device_update_with_temp(struct thermal_zone_device *tz, + enum thermal_notify_event event, + int temp) +{ + mutex_lock(&tz->lock); + if (thermal_zone_is_present(tz)) + __thermal_zone_device_update(tz, event, false, temp); + mutex_unlock(&tz->lock); +} +EXPORT_SYMBOL_GPL(thermal_zone_device_update_with_temp); + static void thermal_zone_device_check(struct work_struct *work) { struct thermal_zone_device *tz = container_of(work, struct diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index e6a2b6f97be8..2d73847fcfea 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -113,7 +113,8 @@ void thermal_unregister_governor(struct thermal_governor *); int thermal_zone_device_set_policy(struct thermal_zone_device *, char *); int thermal_build_list_of_policies(char *buf); void __thermal_zone_device_update(struct thermal_zone_device *tz, - enum thermal_notify_event event); + enum thermal_notify_event event, + bool read_temp, int temp); void thermal_zone_device_critical_reboot(struct thermal_zone_device *tz); void thermal_governor_update_tz(struct thermal_zone_device *tz, enum thermal_notify_event reason); diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index 5abf6d136c24..9062545f314e 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -131,7 +131,8 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, thermal_zone_set_trip_temp(tz, trip, temp); - __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED); + __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED, + true, 0); } unlock: @@ -256,7 +257,8 @@ emul_temp_store(struct device *dev, struct device_attribute *attr, ret = tz->ops->set_emul_temp(tz, temperature); if (!ret) - __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED, + true, 0); mutex_unlock(&tz->lock); diff --git a/drivers/thermal/thermal_trip.c b/drivers/thermal/thermal_trip.c index a1ad345c0741..77dc433e6e1c 100644 --- a/drivers/thermal/thermal_trip.c +++ b/drivers/thermal/thermal_trip.c @@ -158,7 +158,7 @@ void thermal_zone_trip_updated(struct thermal_zone_device *tz, thermal_notify_tz_trip_change(tz->id, thermal_zone_trip_id(tz, trip), trip->type, trip->temperature, trip->hysteresis); - __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED); + __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED, true, 0); } void thermal_zone_set_trip_temp(struct thermal_zone_device *tz, -- 2.25.1