From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx> Make the ACPI thermal driver use thermal_zone_device_register_with_trips() to register its thermal zones. For this purpose, make it create a trip point table that will be passed to thermal_zone_device_register_with_trips() as an argument. Also use the thermal_zone_update_trip_temp() helper introduced previously to update temperatures of the passive and active trip points after a trip points change notification from the platform firmware. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx> --- v3 -> v4: * Rework to use thermal_zone_update_trip_temp() for updating trip point temperatures. * Rebase on top of the new version of the previous patch. v2 -> v3: * Fix error code path memory leak in acpi_thermal_register_thermal_zone(). * Notice that the critical and hot trips never change after initialization, so don't add struct thermal_trip_ref to any of them. v1 -> v2: * Use thermal_zone_device_lock()/thermal_zone_device_unlock() in acpi_thermal_check_fn() explicitly and call __thermal_zone_device_update() from there without unlocking the thermal zone. * Export __thermal_zone_device_update() to modules (so it can be called by the ACPI thermal code). --- drivers/acpi/thermal.c | 95 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 8 deletions(-) Index: linux-pm/drivers/acpi/thermal.c =================================================================== --- linux-pm.orig/drivers/acpi/thermal.c +++ linux-pm/drivers/acpi/thermal.c @@ -137,6 +137,7 @@ struct acpi_thermal { unsigned long polling_frequency; volatile u8 zombie; struct acpi_thermal_trips trips; + struct thermal_trip *trip_table; struct acpi_handle_list devices; struct thermal_zone_device *thermal_zone; int kelvin_offset; /* in millidegrees */ @@ -190,6 +191,22 @@ static int acpi_thermal_get_polling_freq return 0; } +static int acpi_thermal_temp(struct acpi_thermal *tz, int temp_deci_k) +{ + if (temp_deci_k == THERMAL_TEMP_INVALID) + return THERMAL_TEMP_INVALID; + + return deci_kelvin_to_millicelsius_with_offset(temp_deci_k, + tz->kelvin_offset); +} + +static void acpi_thermal_update_trip_temp(struct acpi_thermal *tz, + void *trip_priv, int temp_deci_k) +{ + thermal_zone_update_trip_temp(tz->thermal_zone, trip_priv, + acpi_thermal_temp(tz, temp_deci_k)); +} + static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) { acpi_status status; @@ -403,7 +420,28 @@ static void __acpi_thermal_trips_update( static void acpi_thermal_adjust_thermal_zone(struct thermal_zone_device *thermal, unsigned long data) { - __acpi_thermal_trips_update(thermal_zone_device_priv(thermal), data); + struct acpi_thermal *tz = thermal_zone_device_priv(thermal); + int i; + + __acpi_thermal_trips_update(tz, data); + + if (tz->trips.passive.valid) + acpi_thermal_update_trip_temp(tz, &tz->trips.passive, + tz->trips.passive.temperature); + else + thermal_zone_update_trip_temp(tz->thermal_zone, + &tz->trips.passive, + THERMAL_TEMP_INVALID); + + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { + if (tz->trips.active[i].valid) + acpi_thermal_update_trip_temp(tz, &tz->trips.active[i], + tz->trips.active[i].temperature); + else + thermal_zone_update_trip_temp(tz->thermal_zone, + &tz->trips.active[i], + THERMAL_TEMP_INVALID); + } } static void acpi_queue_thermal_check(struct acpi_thermal *tz) @@ -768,6 +806,7 @@ static void acpi_thermal_zone_sysfs_remo static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) { + struct thermal_trip *trip; int passive_delay = 0; int trip_count = 0; int result; @@ -788,12 +827,50 @@ static int acpi_thermal_register_thermal for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid; i++) trip_count++; - tz->thermal_zone = thermal_zone_device_register("acpitz", trip_count, 0, - tz, &acpi_thermal_zone_ops, - NULL, passive_delay, - tz->polling_frequency * 100); - if (IS_ERR(tz->thermal_zone)) - return -ENODEV; + trip = kcalloc(trip_count, sizeof(*trip), GFP_KERNEL); + if (!trip) + return -ENOMEM; + + tz->trip_table = trip; + + if (tz->trips.critical.valid) { + trip->type = THERMAL_TRIP_CRITICAL; + trip->temperature = acpi_thermal_temp(tz, tz->trips.critical.temperature); + trip++; + } + + if (tz->trips.hot.valid) { + trip->type = THERMAL_TRIP_HOT; + trip->temperature = acpi_thermal_temp(tz, tz->trips.hot.temperature); + trip++; + } + + if (tz->trips.passive.valid) { + trip->type = THERMAL_TRIP_PASSIVE; + trip->temperature = acpi_thermal_temp(tz, tz->trips.passive.temperature); + trip->priv = &tz->trips.passive; + trip++; + } + + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid; i++) { + trip->type = THERMAL_TRIP_ACTIVE; + trip->temperature = acpi_thermal_temp(tz, tz->trips.active[i].temperature); + trip->priv = &tz->trips.active[i]; + trip++; + } + + tz->thermal_zone = thermal_zone_device_register_with_trips("acpitz", + tz->trip_table, + trip_count, + 0, tz, + &acpi_thermal_zone_ops, + NULL, + passive_delay, + tz->polling_frequency * 100); + if (IS_ERR(tz->thermal_zone)) { + result = PTR_ERR(tz->thermal_zone); + goto free_trip_table; + } result = acpi_thermal_zone_sysfs_add(tz); if (result) @@ -821,6 +898,8 @@ remove_links: acpi_thermal_zone_sysfs_remove(tz); unregister_tzd: thermal_zone_device_unregister(tz->thermal_zone); +free_trip_table: + kfree(tz->trip_table); return result; } @@ -829,6 +908,7 @@ static void acpi_thermal_unregister_ther { acpi_thermal_zone_sysfs_remove(tz); thermal_zone_device_unregister(tz->thermal_zone); + kfree(tz->trip_table); tz->thermal_zone = NULL; acpi_bus_detach_private_data(tz->device->handle); }