From: Srinivas Pandruvada srinivas.pandruvada@linux.intel.com
commit 6757a7abe47bcb12cb2d45661067e182424b0ee3 upstream.
Trip temperatures are read using ACPI methods and stored in the memory during zone initializtion and when the firmware sends a notification for change. This trip temperature is returned when the thermal core calls via callback get_trip_temp().
But it is possible that while updating the memory copy of the trips when the firmware sends a notification for change, thermal core is reading the trip temperature via the callback get_trip_temp(). This may return invalid trip temperature.
To address this add a mutex to protect the invalid temperature reads in the callback get_trip_temp() and int340x_thermal_read_trips().
Fixes: 5fbf7f27fa3d ("Thermal/int340x: Add common thermal zone handler") Signed-off-by: Srinivas Pandruvada srinivas.pandruvada@linux.intel.com Cc: 5.0+ stable@vger.kernel.org # 5.0+ Signed-off-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c | 18 +++++++++-- drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h | 1 2 files changed, 16 insertions(+), 3 deletions(-)
--- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c @@ -43,11 +43,13 @@ static int int340x_thermal_get_trip_temp int trip, int *temp) { struct int34x_thermal_zone *d = zone->devdata; - int i; + int i, ret = 0;
if (d->override_ops && d->override_ops->get_trip_temp) return d->override_ops->get_trip_temp(zone, trip, temp);
+ mutex_lock(&d->trip_mutex); + if (trip < d->aux_trip_nr) *temp = d->aux_trips[trip]; else if (trip == d->crt_trip_id) @@ -65,10 +67,12 @@ static int int340x_thermal_get_trip_temp } } if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) - return -EINVAL; + ret = -EINVAL; }
- return 0; + mutex_unlock(&d->trip_mutex); + + return ret; }
static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, @@ -173,6 +177,8 @@ int int340x_thermal_read_trips(struct in int trip_cnt = int34x_zone->aux_trip_nr; int i;
+ mutex_lock(&int34x_zone->trip_mutex); + int34x_zone->crt_trip_id = -1; if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_CRT", &int34x_zone->crt_temp)) @@ -200,6 +206,8 @@ int int340x_thermal_read_trips(struct in int34x_zone->act_trips[i].valid = true; }
+ mutex_unlock(&int34x_zone->trip_mutex); + return trip_cnt; } EXPORT_SYMBOL_GPL(int340x_thermal_read_trips); @@ -223,6 +231,8 @@ struct int34x_thermal_zone *int340x_ther if (!int34x_thermal_zone) return ERR_PTR(-ENOMEM);
+ mutex_init(&int34x_thermal_zone->trip_mutex); + int34x_thermal_zone->adev = adev; int34x_thermal_zone->override_ops = override_ops;
@@ -269,6 +279,7 @@ err_thermal_zone: acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); kfree(int34x_thermal_zone->aux_trips); err_trip_alloc: + mutex_destroy(&int34x_thermal_zone->trip_mutex); kfree(int34x_thermal_zone); return ERR_PTR(ret); } @@ -280,6 +291,7 @@ void int340x_thermal_zone_remove(struct thermal_zone_device_unregister(int34x_thermal_zone->zone); acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); kfree(int34x_thermal_zone->aux_trips); + mutex_destroy(&int34x_thermal_zone->trip_mutex); kfree(int34x_thermal_zone); } EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h @@ -32,6 +32,7 @@ struct int34x_thermal_zone { struct thermal_zone_device_ops *override_ops; void *priv_data; struct acpi_lpat_conversion_table *lpat_table; + struct mutex trip_mutex; };
struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *,