Merge branch 'thermal-core'
Merge thermal control core changes for 6.3-rc1: - Clean up thermal device unregistration code (Viresh Kumar). - Fix and clean up thermal control core initialization error code paths (Daniel Lezcano). - Relocate the trip points handling code into a separate file (Daniel Lezcano). - Make the thermal core fail registration of thermal zones and cooling devices if the thermal class has not been registered (Rafael Wysocki). - Make the core thermal control code use sysfs_emit_at() instead of scnprintf() where applicable (ye xingchen). * thermal-core: thermal: core: Use sysfs_emit_at() instead of scnprintf() thermal: Fail object registration if thermal class is not registered thermal/core: Move the thermal trip code to a dedicated file thermal/core: Remove unneeded ida_destroy() thermal/core: Fix unregistering netlink at thermal init time thermal: core: Use device_unregister() instead of device_del/put() thermal: core: Move cdev cleanup to thermal_release()
This commit is contained in:
Коммит
c3bd6d539f
|
@ -4,8 +4,8 @@
|
|||
#
|
||||
|
||||
obj-$(CONFIG_THERMAL) += thermal_sys.o
|
||||
thermal_sys-y += thermal_core.o thermal_sysfs.o \
|
||||
thermal_helpers.o
|
||||
thermal_sys-y += thermal_core.o thermal_sysfs.o
|
||||
thermal_sys-y += thermal_trip.o thermal_helpers.o
|
||||
|
||||
# netlink interface to manage the thermal framework
|
||||
thermal_sys-$(CONFIG_THERMAL_NETLINK) += thermal_netlink.o
|
||||
|
|
|
@ -229,10 +229,9 @@ int thermal_build_list_of_policies(char *buf)
|
|||
mutex_lock(&thermal_governor_lock);
|
||||
|
||||
list_for_each_entry(pos, &thermal_governor_list, governor_list) {
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count, "%s ",
|
||||
pos->name);
|
||||
count += sysfs_emit_at(buf, count, "%s ", pos->name);
|
||||
}
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
|
||||
count += sysfs_emit_at(buf, count, "\n");
|
||||
|
||||
mutex_unlock(&thermal_governor_lock);
|
||||
|
||||
|
@ -770,14 +769,14 @@ static void thermal_release(struct device *dev)
|
|||
} else if (!strncmp(dev_name(dev), "cooling_device",
|
||||
sizeof("cooling_device") - 1)) {
|
||||
cdev = to_cooling_device(dev);
|
||||
thermal_cooling_device_destroy_sysfs(cdev);
|
||||
kfree(cdev->type);
|
||||
ida_free(&thermal_cdev_ida, cdev->id);
|
||||
kfree(cdev);
|
||||
}
|
||||
}
|
||||
|
||||
static struct class thermal_class = {
|
||||
.name = "thermal",
|
||||
.dev_release = thermal_release,
|
||||
};
|
||||
static struct class *thermal_class;
|
||||
|
||||
static inline
|
||||
void print_bind_err_msg(struct thermal_zone_device *tz,
|
||||
|
@ -880,6 +879,9 @@ __thermal_cooling_device_register(struct device_node *np,
|
|||
!ops->set_cur_state)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!thermal_class)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
|
||||
if (!cdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
@ -901,27 +903,25 @@ __thermal_cooling_device_register(struct device_node *np,
|
|||
cdev->np = np;
|
||||
cdev->ops = ops;
|
||||
cdev->updated = false;
|
||||
cdev->device.class = &thermal_class;
|
||||
cdev->device.class = thermal_class;
|
||||
cdev->devdata = devdata;
|
||||
|
||||
ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
|
||||
if (ret) {
|
||||
kfree(cdev->type);
|
||||
goto out_ida_remove;
|
||||
}
|
||||
if (ret)
|
||||
goto out_cdev_type;
|
||||
|
||||
thermal_cooling_device_setup_sysfs(cdev);
|
||||
|
||||
ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
|
||||
if (ret) {
|
||||
kfree(cdev->type);
|
||||
thermal_cooling_device_destroy_sysfs(cdev);
|
||||
goto out_ida_remove;
|
||||
}
|
||||
if (ret)
|
||||
goto out_cooling_dev;
|
||||
|
||||
ret = device_register(&cdev->device);
|
||||
if (ret)
|
||||
goto out_kfree_type;
|
||||
if (ret) {
|
||||
/* thermal_release() handles rest of the cleanup */
|
||||
put_device(&cdev->device);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/* Add 'this' new cdev to the global cdev list */
|
||||
mutex_lock(&thermal_list_lock);
|
||||
|
@ -940,13 +940,10 @@ __thermal_cooling_device_register(struct device_node *np,
|
|||
|
||||
return cdev;
|
||||
|
||||
out_kfree_type:
|
||||
out_cooling_dev:
|
||||
thermal_cooling_device_destroy_sysfs(cdev);
|
||||
out_cdev_type:
|
||||
kfree(cdev->type);
|
||||
put_device(&cdev->device);
|
||||
|
||||
/* thermal_release() takes care of the rest */
|
||||
cdev = NULL;
|
||||
out_ida_remove:
|
||||
ida_free(&thermal_cdev_ida, id);
|
||||
out_kfree_cdev:
|
||||
|
@ -1107,11 +1104,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
|
|||
|
||||
mutex_unlock(&thermal_list_lock);
|
||||
|
||||
ida_free(&thermal_cdev_ida, cdev->id);
|
||||
device_del(&cdev->device);
|
||||
thermal_cooling_device_destroy_sysfs(cdev);
|
||||
kfree(cdev->type);
|
||||
put_device(&cdev->device);
|
||||
device_unregister(&cdev->device);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
|
||||
|
||||
|
@ -1162,12 +1155,6 @@ static void thermal_set_delay_jiffies(unsigned long *delay_jiffies, int delay_ms
|
|||
*delay_jiffies = round_jiffies(*delay_jiffies);
|
||||
}
|
||||
|
||||
int thermal_zone_get_num_trips(struct thermal_zone_device *tz)
|
||||
{
|
||||
return tz->num_trips;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips);
|
||||
|
||||
int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
int i, ret = -EINVAL;
|
||||
|
@ -1194,87 +1181,6 @@ int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_get_crit_temp);
|
||||
|
||||
int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id,
|
||||
struct thermal_trip *trip)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!tz || trip_id < 0 || trip_id >= tz->num_trips || !trip)
|
||||
return -EINVAL;
|
||||
|
||||
if (tz->trips) {
|
||||
*trip = tz->trips[trip_id];
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tz->ops->get_trip_hyst) {
|
||||
ret = tz->ops->get_trip_hyst(tz, trip_id, &trip->hysteresis);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
trip->hysteresis = 0;
|
||||
}
|
||||
|
||||
ret = tz->ops->get_trip_temp(tz, trip_id, &trip->temperature);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return tz->ops->get_trip_type(tz, trip_id, &trip->type);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__thermal_zone_get_trip);
|
||||
|
||||
int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id,
|
||||
struct thermal_trip *trip)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
ret = __thermal_zone_get_trip(tz, trip_id, trip);
|
||||
mutex_unlock(&tz->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_get_trip);
|
||||
|
||||
int thermal_zone_set_trip(struct thermal_zone_device *tz, int trip_id,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
struct thermal_trip t;
|
||||
int ret;
|
||||
|
||||
if (!tz->ops->set_trip_temp && !tz->ops->set_trip_hyst && !tz->trips)
|
||||
return -EINVAL;
|
||||
|
||||
ret = __thermal_zone_get_trip(tz, trip_id, &t);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (t.type != trip->type)
|
||||
return -EINVAL;
|
||||
|
||||
if (t.temperature != trip->temperature && tz->ops->set_trip_temp) {
|
||||
ret = tz->ops->set_trip_temp(tz, trip_id, trip->temperature);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (t.hysteresis != trip->hysteresis && tz->ops->set_trip_hyst) {
|
||||
ret = tz->ops->set_trip_hyst(tz, trip_id, trip->hysteresis);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tz->trips && (t.temperature != trip->temperature || t.hysteresis != trip->hysteresis))
|
||||
tz->trips[trip_id] = *trip;
|
||||
|
||||
thermal_notify_tz_trip_change(tz->id, trip_id, trip->type,
|
||||
trip->temperature, trip->hysteresis);
|
||||
|
||||
__thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* thermal_zone_device_register_with_trips() - register a new thermal zone device
|
||||
* @type: the thermal zone device type
|
||||
|
@ -1349,6 +1255,9 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
|
|||
if (num_trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp) && !trips)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!thermal_class)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
tz = kzalloc(sizeof(*tz), GFP_KERNEL);
|
||||
if (!tz)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
@ -1370,7 +1279,7 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
|
|||
|
||||
tz->ops = ops;
|
||||
tz->tzp = tzp;
|
||||
tz->device.class = &thermal_class;
|
||||
tz->device.class = thermal_class;
|
||||
tz->devdata = devdata;
|
||||
tz->trips = trips;
|
||||
tz->num_trips = num_trips;
|
||||
|
@ -1613,11 +1522,23 @@ static int __init thermal_init(void)
|
|||
|
||||
result = thermal_register_governors();
|
||||
if (result)
|
||||
goto error;
|
||||
goto unregister_netlink;
|
||||
|
||||
result = class_register(&thermal_class);
|
||||
if (result)
|
||||
thermal_class = kzalloc(sizeof(*thermal_class), GFP_KERNEL);
|
||||
if (!thermal_class) {
|
||||
result = -ENOMEM;
|
||||
goto unregister_governors;
|
||||
}
|
||||
|
||||
thermal_class->name = "thermal";
|
||||
thermal_class->dev_release = thermal_release;
|
||||
|
||||
result = class_register(thermal_class);
|
||||
if (result) {
|
||||
kfree(thermal_class);
|
||||
thermal_class = NULL;
|
||||
goto unregister_governors;
|
||||
}
|
||||
|
||||
result = register_pm_notifier(&thermal_pm_nb);
|
||||
if (result)
|
||||
|
@ -1628,9 +1549,9 @@ static int __init thermal_init(void)
|
|||
|
||||
unregister_governors:
|
||||
thermal_unregister_governors();
|
||||
unregister_netlink:
|
||||
thermal_netlink_exit();
|
||||
error:
|
||||
ida_destroy(&thermal_tz_ida);
|
||||
ida_destroy(&thermal_cdev_ida);
|
||||
mutex_destroy(&thermal_list_lock);
|
||||
mutex_destroy(&thermal_governor_lock);
|
||||
return result;
|
||||
|
|
|
@ -52,6 +52,10 @@ int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *,
|
|||
int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *),
|
||||
void *thermal_governor);
|
||||
|
||||
int __for_each_thermal_trip(struct thermal_zone_device *,
|
||||
int (*cb)(struct thermal_trip *, void *),
|
||||
void *);
|
||||
|
||||
struct thermal_zone_device *thermal_zone_get_by_id(int id);
|
||||
|
||||
struct thermal_attr {
|
||||
|
|
|
@ -146,68 +146,6 @@ unlock:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
|
||||
|
||||
/**
|
||||
* __thermal_zone_set_trips - Computes the next trip points for the driver
|
||||
* @tz: a pointer to a thermal zone device structure
|
||||
*
|
||||
* The function computes the next temperature boundaries by browsing
|
||||
* the trip points. The result is the closer low and high trip points
|
||||
* to the current temperature. These values are passed to the backend
|
||||
* driver to let it set its own notification mechanism (usually an
|
||||
* interrupt).
|
||||
*
|
||||
* This function must be called with tz->lock held. Both tz and tz->ops
|
||||
* must be valid pointers.
|
||||
*
|
||||
* It does not return a value
|
||||
*/
|
||||
void __thermal_zone_set_trips(struct thermal_zone_device *tz)
|
||||
{
|
||||
struct thermal_trip trip;
|
||||
int low = -INT_MAX, high = INT_MAX;
|
||||
int i, ret;
|
||||
|
||||
lockdep_assert_held(&tz->lock);
|
||||
|
||||
if (!tz->ops->set_trips)
|
||||
return;
|
||||
|
||||
for (i = 0; i < tz->num_trips; i++) {
|
||||
int trip_low;
|
||||
|
||||
ret = __thermal_zone_get_trip(tz, i , &trip);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
trip_low = trip.temperature - trip.hysteresis;
|
||||
|
||||
if (trip_low < tz->temperature && trip_low > low)
|
||||
low = trip_low;
|
||||
|
||||
if (trip.temperature > tz->temperature &&
|
||||
trip.temperature < high)
|
||||
high = trip.temperature;
|
||||
}
|
||||
|
||||
/* No need to change trip points */
|
||||
if (tz->prev_low_trip == low && tz->prev_high_trip == high)
|
||||
return;
|
||||
|
||||
tz->prev_low_trip = low;
|
||||
tz->prev_high_trip = high;
|
||||
|
||||
dev_dbg(&tz->device,
|
||||
"new temperature boundaries: %d < x < %d\n", low, high);
|
||||
|
||||
/*
|
||||
* Set a temperature window. When this window is left the driver
|
||||
* must inform the thermal core via thermal_zone_device_update.
|
||||
*/
|
||||
ret = tz->ops->set_trips(tz, low, high);
|
||||
if (ret)
|
||||
dev_err(&tz->device, "Failed to set trips: %d\n", ret);
|
||||
}
|
||||
|
||||
static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev,
|
||||
int target)
|
||||
{
|
||||
|
|
|
@ -699,3 +699,8 @@ int __init thermal_netlink_init(void)
|
|||
{
|
||||
return genl_register_family(&thermal_gnl_family);
|
||||
}
|
||||
|
||||
void __init thermal_netlink_exit(void)
|
||||
{
|
||||
genl_unregister_family(&thermal_gnl_family);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ struct thermal_genl_cpu_caps {
|
|||
/* Netlink notification function */
|
||||
#ifdef CONFIG_THERMAL_NETLINK
|
||||
int __init thermal_netlink_init(void);
|
||||
void __init thermal_netlink_exit(void);
|
||||
int thermal_notify_tz_create(int tz_id, const char *name);
|
||||
int thermal_notify_tz_delete(int tz_id);
|
||||
int thermal_notify_tz_enable(int tz_id);
|
||||
|
@ -115,4 +116,6 @@ static inline int thermal_genl_cpu_capability_event(int count, struct thermal_ge
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void __init thermal_netlink_exit(void) {}
|
||||
|
||||
#endif /* CONFIG_THERMAL_NETLINK */
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2008 Intel Corp
|
||||
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
|
||||
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
|
||||
* Copyright 2022 Linaro Limited
|
||||
*
|
||||
* Thermal trips handling
|
||||
*/
|
||||
#include "thermal_core.h"
|
||||
|
||||
int __for_each_thermal_trip(struct thermal_zone_device *tz,
|
||||
int (*cb)(struct thermal_trip *, void *),
|
||||
void *data)
|
||||
{
|
||||
int i, ret;
|
||||
struct thermal_trip trip;
|
||||
|
||||
lockdep_assert_held(&tz->lock);
|
||||
|
||||
for (i = 0; i < tz->num_trips; i++) {
|
||||
|
||||
ret = __thermal_zone_get_trip(tz, i, &trip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cb(&trip, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thermal_zone_get_num_trips(struct thermal_zone_device *tz)
|
||||
{
|
||||
return tz->num_trips;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips);
|
||||
|
||||
/**
|
||||
* __thermal_zone_set_trips - Computes the next trip points for the driver
|
||||
* @tz: a pointer to a thermal zone device structure
|
||||
*
|
||||
* The function computes the next temperature boundaries by browsing
|
||||
* the trip points. The result is the closer low and high trip points
|
||||
* to the current temperature. These values are passed to the backend
|
||||
* driver to let it set its own notification mechanism (usually an
|
||||
* interrupt).
|
||||
*
|
||||
* This function must be called with tz->lock held. Both tz and tz->ops
|
||||
* must be valid pointers.
|
||||
*
|
||||
* It does not return a value
|
||||
*/
|
||||
void __thermal_zone_set_trips(struct thermal_zone_device *tz)
|
||||
{
|
||||
struct thermal_trip trip;
|
||||
int low = -INT_MAX, high = INT_MAX;
|
||||
int i, ret;
|
||||
|
||||
lockdep_assert_held(&tz->lock);
|
||||
|
||||
if (!tz->ops->set_trips)
|
||||
return;
|
||||
|
||||
for (i = 0; i < tz->num_trips; i++) {
|
||||
int trip_low;
|
||||
|
||||
ret = __thermal_zone_get_trip(tz, i , &trip);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
trip_low = trip.temperature - trip.hysteresis;
|
||||
|
||||
if (trip_low < tz->temperature && trip_low > low)
|
||||
low = trip_low;
|
||||
|
||||
if (trip.temperature > tz->temperature &&
|
||||
trip.temperature < high)
|
||||
high = trip.temperature;
|
||||
}
|
||||
|
||||
/* No need to change trip points */
|
||||
if (tz->prev_low_trip == low && tz->prev_high_trip == high)
|
||||
return;
|
||||
|
||||
tz->prev_low_trip = low;
|
||||
tz->prev_high_trip = high;
|
||||
|
||||
dev_dbg(&tz->device,
|
||||
"new temperature boundaries: %d < x < %d\n", low, high);
|
||||
|
||||
/*
|
||||
* Set a temperature window. When this window is left the driver
|
||||
* must inform the thermal core via thermal_zone_device_update.
|
||||
*/
|
||||
ret = tz->ops->set_trips(tz, low, high);
|
||||
if (ret)
|
||||
dev_err(&tz->device, "Failed to set trips: %d\n", ret);
|
||||
}
|
||||
|
||||
int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id,
|
||||
struct thermal_trip *trip)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!tz || trip_id < 0 || trip_id >= tz->num_trips || !trip)
|
||||
return -EINVAL;
|
||||
|
||||
if (tz->trips) {
|
||||
*trip = tz->trips[trip_id];
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tz->ops->get_trip_hyst) {
|
||||
ret = tz->ops->get_trip_hyst(tz, trip_id, &trip->hysteresis);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
trip->hysteresis = 0;
|
||||
}
|
||||
|
||||
ret = tz->ops->get_trip_temp(tz, trip_id, &trip->temperature);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return tz->ops->get_trip_type(tz, trip_id, &trip->type);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__thermal_zone_get_trip);
|
||||
|
||||
int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id,
|
||||
struct thermal_trip *trip)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
ret = __thermal_zone_get_trip(tz, trip_id, trip);
|
||||
mutex_unlock(&tz->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_get_trip);
|
||||
|
||||
int thermal_zone_set_trip(struct thermal_zone_device *tz, int trip_id,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
struct thermal_trip t;
|
||||
int ret;
|
||||
|
||||
if (!tz->ops->set_trip_temp && !tz->ops->set_trip_hyst && !tz->trips)
|
||||
return -EINVAL;
|
||||
|
||||
ret = __thermal_zone_get_trip(tz, trip_id, &t);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (t.type != trip->type)
|
||||
return -EINVAL;
|
||||
|
||||
if (t.temperature != trip->temperature && tz->ops->set_trip_temp) {
|
||||
ret = tz->ops->set_trip_temp(tz, trip_id, trip->temperature);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (t.hysteresis != trip->hysteresis && tz->ops->set_trip_hyst) {
|
||||
ret = tz->ops->set_trip_hyst(tz, trip_id, trip->hysteresis);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tz->trips && (t.temperature != trip->temperature || t.hysteresis != trip->hysteresis))
|
||||
tz->trips[trip_id] = *trip;
|
||||
|
||||
thermal_notify_tz_trip_change(tz->id, trip_id, trip->type,
|
||||
trip->temperature, trip->hysteresis);
|
||||
|
||||
__thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
|
||||
|
||||
return 0;
|
||||
}
|
Загрузка…
Ссылка в новой задаче