2018-05-08 01:52:29 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2016-11-08 13:09:00 +08:00
|
|
|
/*
|
|
|
|
* thermal.c - sysfs interface of thermal devices
|
|
|
|
*
|
|
|
|
* Copyright (C) 2016 Eduardo Valentin <edubezval@gmail.com>
|
|
|
|
*
|
|
|
|
* Highly based on original thermal_core.c
|
|
|
|
* Copyright (C) 2008 Intel Corp
|
|
|
|
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
|
|
|
|
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
|
|
|
|
#include <linux/sysfs.h>
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/string.h>
|
2018-04-02 18:56:25 +08:00
|
|
|
#include <linux/jiffies.h>
|
2016-11-08 13:09:00 +08:00
|
|
|
|
|
|
|
#include "thermal_core.h"
|
|
|
|
|
|
|
|
/* sys I/F for thermal zone */
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
type_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
|
|
|
|
|
|
|
return sprintf(buf, "%s\n", tz->type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
temp_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
|
|
|
int temperature, ret;
|
|
|
|
|
|
|
|
ret = thermal_zone_get_temp(tz, &temperature);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return sprintf(buf, "%d\n", temperature);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
mode_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
2022-08-05 23:38:34 +08:00
|
|
|
int enabled;
|
|
|
|
|
|
|
|
mutex_lock(&tz->lock);
|
|
|
|
enabled = thermal_zone_device_is_enabled(tz);
|
|
|
|
mutex_unlock(&tz->lock);
|
2016-11-08 13:09:00 +08:00
|
|
|
|
thermal: Use mode helpers in drivers
Use thermal_zone_device_{en|dis}able() and thermal_zone_device_is_enabled().
Consequently, all set_mode() implementations in drivers:
- can stop modifying tzd's "mode" member,
- shall stop taking tzd's lock, as it is taken in the helpers
- shall stop calling thermal_zone_device_update() as it is called in the
helpers
- can assume they are called when the mode truly changes, so checks to
verify that can be dropped
Not providing set_mode() by a driver no longer prevents the core from
being able to set tzd's mode, so the relevant check in mode_store() is
removed.
Other comments:
- acpi/thermal.c: tz->thermal_zone->mode will be updated only after we
return from set_mode(), so use function parameter in thermal_set_mode()
instead, no need to call acpi_thermal_check() in set_mode()
- thermal/imx_thermal.c: regmap writes and mode assignment are done in
thermal_zone_device_{en|dis}able() and set_mode() callback
- thermal/intel/intel_quark_dts_thermal.c: soc_dts_{en|dis}able() are a
part of set_mode() callback, so they don't need to modify tzd->mode, and
don't need to fall back to the opposite mode if unsuccessful, as the return
value will be propagated to thermal_zone_device_{en|dis}able() and
ultimately tzd's member will not be changed in thermal_zone_device_set_mode().
- thermal/of-thermal.c: no need to set zone->mode to DISABLED in
of_parse_thermal_zones() as a tzd is kzalloc'ed so mode is DISABLED anyway
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
[for acerhdf]
Acked-by: Peter Kaestle <peter@piie.net>
Reviewed-by: Amit Kucheria <amit.kucheria@linaro.org>
Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20200629122925.21729-8-andrzej.p@collabora.com
2020-06-29 20:29:21 +08:00
|
|
|
return sprintf(buf, "%s\n", enabled ? "enabled" : "disabled");
|
2016-11-08 13:09:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
mode_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
|
|
|
int result;
|
|
|
|
|
|
|
|
if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
|
thermal: Use mode helpers in drivers
Use thermal_zone_device_{en|dis}able() and thermal_zone_device_is_enabled().
Consequently, all set_mode() implementations in drivers:
- can stop modifying tzd's "mode" member,
- shall stop taking tzd's lock, as it is taken in the helpers
- shall stop calling thermal_zone_device_update() as it is called in the
helpers
- can assume they are called when the mode truly changes, so checks to
verify that can be dropped
Not providing set_mode() by a driver no longer prevents the core from
being able to set tzd's mode, so the relevant check in mode_store() is
removed.
Other comments:
- acpi/thermal.c: tz->thermal_zone->mode will be updated only after we
return from set_mode(), so use function parameter in thermal_set_mode()
instead, no need to call acpi_thermal_check() in set_mode()
- thermal/imx_thermal.c: regmap writes and mode assignment are done in
thermal_zone_device_{en|dis}able() and set_mode() callback
- thermal/intel/intel_quark_dts_thermal.c: soc_dts_{en|dis}able() are a
part of set_mode() callback, so they don't need to modify tzd->mode, and
don't need to fall back to the opposite mode if unsuccessful, as the return
value will be propagated to thermal_zone_device_{en|dis}able() and
ultimately tzd's member will not be changed in thermal_zone_device_set_mode().
- thermal/of-thermal.c: no need to set zone->mode to DISABLED in
of_parse_thermal_zones() as a tzd is kzalloc'ed so mode is DISABLED anyway
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
[for acerhdf]
Acked-by: Peter Kaestle <peter@piie.net>
Reviewed-by: Amit Kucheria <amit.kucheria@linaro.org>
Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20200629122925.21729-8-andrzej.p@collabora.com
2020-06-29 20:29:21 +08:00
|
|
|
result = thermal_zone_device_enable(tz);
|
2016-11-08 13:09:00 +08:00
|
|
|
else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
|
thermal: Use mode helpers in drivers
Use thermal_zone_device_{en|dis}able() and thermal_zone_device_is_enabled().
Consequently, all set_mode() implementations in drivers:
- can stop modifying tzd's "mode" member,
- shall stop taking tzd's lock, as it is taken in the helpers
- shall stop calling thermal_zone_device_update() as it is called in the
helpers
- can assume they are called when the mode truly changes, so checks to
verify that can be dropped
Not providing set_mode() by a driver no longer prevents the core from
being able to set tzd's mode, so the relevant check in mode_store() is
removed.
Other comments:
- acpi/thermal.c: tz->thermal_zone->mode will be updated only after we
return from set_mode(), so use function parameter in thermal_set_mode()
instead, no need to call acpi_thermal_check() in set_mode()
- thermal/imx_thermal.c: regmap writes and mode assignment are done in
thermal_zone_device_{en|dis}able() and set_mode() callback
- thermal/intel/intel_quark_dts_thermal.c: soc_dts_{en|dis}able() are a
part of set_mode() callback, so they don't need to modify tzd->mode, and
don't need to fall back to the opposite mode if unsuccessful, as the return
value will be propagated to thermal_zone_device_{en|dis}able() and
ultimately tzd's member will not be changed in thermal_zone_device_set_mode().
- thermal/of-thermal.c: no need to set zone->mode to DISABLED in
of_parse_thermal_zones() as a tzd is kzalloc'ed so mode is DISABLED anyway
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
[for acerhdf]
Acked-by: Peter Kaestle <peter@piie.net>
Reviewed-by: Amit Kucheria <amit.kucheria@linaro.org>
Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20200629122925.21729-8-andrzej.p@collabora.com
2020-06-29 20:29:21 +08:00
|
|
|
result = thermal_zone_device_disable(tz);
|
2016-11-08 13:09:00 +08:00
|
|
|
else
|
|
|
|
result = -EINVAL;
|
|
|
|
|
|
|
|
if (result)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
trip_point_type_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
struct thermal_trip trip;
|
|
|
|
int trip_id, result;
|
2016-11-08 13:09:00 +08:00
|
|
|
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
if (sscanf(attr->attr.name, "trip_point_%d_type", &trip_id) != 1)
|
2016-11-08 13:09:00 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2022-11-10 23:24:58 +08:00
|
|
|
mutex_lock(&tz->lock);
|
|
|
|
|
|
|
|
if (device_is_registered(dev))
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
result = __thermal_zone_get_trip(tz, trip_id, &trip);
|
2022-11-10 23:24:58 +08:00
|
|
|
else
|
|
|
|
result = -ENODEV;
|
|
|
|
|
|
|
|
mutex_unlock(&tz->lock);
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
|
2016-11-08 13:09:00 +08:00
|
|
|
if (result)
|
|
|
|
return result;
|
|
|
|
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
switch (trip.type) {
|
2016-11-08 13:09:00 +08:00
|
|
|
case THERMAL_TRIP_CRITICAL:
|
|
|
|
return sprintf(buf, "critical\n");
|
|
|
|
case THERMAL_TRIP_HOT:
|
|
|
|
return sprintf(buf, "hot\n");
|
|
|
|
case THERMAL_TRIP_PASSIVE:
|
|
|
|
return sprintf(buf, "passive\n");
|
|
|
|
case THERMAL_TRIP_ACTIVE:
|
|
|
|
return sprintf(buf, "active\n");
|
|
|
|
default:
|
|
|
|
return sprintf(buf, "unknown\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
trip_point_temp_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
struct thermal_trip trip;
|
|
|
|
int trip_id, ret;
|
2016-11-08 13:09:00 +08:00
|
|
|
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip_id) != 1)
|
2016-11-08 13:09:00 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2022-11-10 23:24:58 +08:00
|
|
|
mutex_lock(&tz->lock);
|
|
|
|
|
|
|
|
if (!device_is_registered(dev)) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
ret = __thermal_zone_get_trip(tz, trip_id, &trip);
|
2020-07-06 18:55:38 +08:00
|
|
|
if (ret)
|
2022-11-10 23:24:58 +08:00
|
|
|
goto unlock;
|
2020-07-06 18:55:38 +08:00
|
|
|
|
2022-10-03 17:25:36 +08:00
|
|
|
ret = kstrtoint(buf, 10, &trip.temperature);
|
|
|
|
if (ret)
|
|
|
|
goto unlock;
|
2022-11-10 23:24:58 +08:00
|
|
|
|
2022-10-03 17:25:36 +08:00
|
|
|
ret = thermal_zone_set_trip(tz, trip_id, &trip);
|
2022-11-10 23:24:58 +08:00
|
|
|
unlock:
|
|
|
|
mutex_unlock(&tz->lock);
|
2022-10-03 17:25:36 +08:00
|
|
|
|
|
|
|
return ret ? ret : count;
|
2016-11-08 13:09:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
trip_point_temp_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
struct thermal_trip trip;
|
|
|
|
int trip_id, ret;
|
2016-11-08 13:09:00 +08:00
|
|
|
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip_id) != 1)
|
2016-11-08 13:09:00 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2022-11-10 23:24:58 +08:00
|
|
|
mutex_lock(&tz->lock);
|
|
|
|
|
|
|
|
if (device_is_registered(dev))
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
ret = __thermal_zone_get_trip(tz, trip_id, &trip);
|
2022-11-10 23:24:58 +08:00
|
|
|
else
|
|
|
|
ret = -ENODEV;
|
|
|
|
|
|
|
|
mutex_unlock(&tz->lock);
|
2016-11-08 13:09:00 +08:00
|
|
|
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
return sprintf(buf, "%d\n", trip.temperature);
|
2016-11-08 13:09:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
2022-10-03 17:25:36 +08:00
|
|
|
struct thermal_trip trip;
|
|
|
|
int trip_id, ret;
|
2016-11-08 13:09:00 +08:00
|
|
|
|
2022-10-03 17:25:36 +08:00
|
|
|
if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1)
|
2016-11-08 13:09:00 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2022-10-03 17:25:36 +08:00
|
|
|
if (kstrtoint(buf, 10, &trip.hysteresis))
|
2016-11-08 13:09:00 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2022-11-10 23:24:58 +08:00
|
|
|
mutex_lock(&tz->lock);
|
|
|
|
|
|
|
|
if (!device_is_registered(dev)) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
2022-10-03 17:25:36 +08:00
|
|
|
ret = __thermal_zone_get_trip(tz, trip_id, &trip);
|
|
|
|
if (ret)
|
|
|
|
goto unlock;
|
|
|
|
|
|
|
|
ret = thermal_zone_set_trip(tz, trip_id, &trip);
|
2022-11-10 23:24:58 +08:00
|
|
|
unlock:
|
|
|
|
mutex_unlock(&tz->lock);
|
2016-11-08 13:09:00 +08:00
|
|
|
|
|
|
|
return ret ? ret : count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
struct thermal_trip trip;
|
|
|
|
int trip_id, ret;
|
2016-11-08 13:09:00 +08:00
|
|
|
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1)
|
2016-11-08 13:09:00 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2022-11-10 23:24:58 +08:00
|
|
|
mutex_lock(&tz->lock);
|
|
|
|
|
|
|
|
if (device_is_registered(dev))
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
ret = __thermal_zone_get_trip(tz, trip_id, &trip);
|
2022-11-10 23:24:58 +08:00
|
|
|
else
|
|
|
|
ret = -ENODEV;
|
|
|
|
|
|
|
|
mutex_unlock(&tz->lock);
|
2016-11-08 13:09:00 +08:00
|
|
|
|
thermal/core: Add a generic thermal_zone_get_trip() function
The thermal_zone_device_ops structure defines a set of ops family,
get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is
returning a property of a trip point.
The result is the code is calling the ops everywhere to get a trip
point which is supposed to be defined in the backend driver. It is a
non-sense as a thermal trip can be generic and used by the backend
driver to declare its trip points.
Part of the thermal framework has been changed and all the OF thermal
drivers are using the same definition for the trip point and use a
thermal zone registration variant to pass those trip points which are
part of the thermal zone device structure.
Consequently, we can use a generic function to get the trip points
when they are stored in the thermal zone device structure.
This approach can be generalized to all the drivers and we can get rid
of the ops->get_trip_*. That will result to a much more simpler code
and make possible to rework how the thermal trip are handled in the
thermal core framework as discussed previously.
This change adds a function thermal_zone_get_trip() where we get the
thermal trip point structure which contains all the properties (type,
temp, hyst) instead of doing multiple calls to ops->get_trip_*.
That opens the door for trip point extension with more attributes. For
instance, replacing the trip points disabled bitmask with a 'disabled'
field in the structure.
Here we replace all the calls to ops->get_trip_* in the thermal core
code with a call to the thermal_zone_get_trip() function.
The thermal zone ops defines a callback to retrieve the critical
temperature. As the trip handling is being reworked, all the trip
points will be the same whatever the driver and consequently finding
the critical trip temperature will be just a loop to search for a
critical trip point type.
Provide such a generic function, so we encapsulate the ops
get_crit_temp() which can be removed when all the backend drivers are
using the generic trip points handling.
While at it, add the thermal_zone_get_num_trips() to encapsulate the
code more and reduce the grip with the thermal framework internals.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Zhang Rui <rui.zhang@intel.com>
Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org
2022-10-03 17:25:34 +08:00
|
|
|
return ret ? ret : sprintf(buf, "%d\n", trip.hysteresis);
|
2016-11-08 13:09:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
policy_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
|
|
|
char name[THERMAL_NAME_LENGTH];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
snprintf(name, sizeof(name), "%s", buf);
|
|
|
|
|
|
|
|
ret = thermal_zone_device_set_policy(tz, name);
|
|
|
|
if (!ret)
|
|
|
|
ret = count;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
|
|
|
|
|
|
|
return sprintf(buf, "%s\n", tz->governor->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
available_policies_show(struct device *dev, struct device_attribute *devattr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
return thermal_build_list_of_policies(buf);
|
|
|
|
}
|
|
|
|
|
2016-11-08 13:09:18 +08:00
|
|
|
#if (IS_ENABLED(CONFIG_THERMAL_EMULATION))
|
2016-11-08 13:09:00 +08:00
|
|
|
static ssize_t
|
|
|
|
emul_temp_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
|
|
|
int ret = 0;
|
|
|
|
int temperature;
|
|
|
|
|
|
|
|
if (kstrtoint(buf, 10, &temperature))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2022-11-10 23:24:58 +08:00
|
|
|
mutex_lock(&tz->lock);
|
|
|
|
|
|
|
|
if (!device_is_registered(dev)) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tz->ops->set_emul_temp)
|
2016-11-08 13:09:00 +08:00
|
|
|
tz->emul_temperature = temperature;
|
2022-11-10 23:24:58 +08:00
|
|
|
else
|
2016-11-08 13:09:00 +08:00
|
|
|
ret = tz->ops->set_emul_temp(tz, temperature);
|
|
|
|
|
|
|
|
if (!ret)
|
2022-11-10 23:24:58 +08:00
|
|
|
__thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
mutex_unlock(&tz->lock);
|
2016-11-08 13:09:00 +08:00
|
|
|
|
|
|
|
return ret ? ret : count;
|
|
|
|
}
|
2017-12-20 02:15:09 +08:00
|
|
|
static DEVICE_ATTR_WO(emul_temp);
|
2016-11-08 13:09:18 +08:00
|
|
|
#endif
|
2016-11-08 13:09:00 +08:00
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
sustainable_power_show(struct device *dev, struct device_attribute *devattr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
|
|
|
|
|
|
|
if (tz->tzp)
|
|
|
|
return sprintf(buf, "%u\n", tz->tzp->sustainable_power);
|
|
|
|
else
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
sustainable_power_store(struct device *dev, struct device_attribute *devattr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev);
|
|
|
|
u32 sustainable_power;
|
|
|
|
|
|
|
|
if (!tz->tzp)
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
if (kstrtou32(buf, 10, &sustainable_power))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
tz->tzp->sustainable_power = sustainable_power;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define create_s32_tzp_attr(name) \
|
|
|
|
static ssize_t \
|
|
|
|
name##_show(struct device *dev, struct device_attribute *devattr, \
|
|
|
|
char *buf) \
|
|
|
|
{ \
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev); \
|
|
|
|
\
|
|
|
|
if (tz->tzp) \
|
|
|
|
return sprintf(buf, "%d\n", tz->tzp->name); \
|
|
|
|
else \
|
|
|
|
return -EIO; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static ssize_t \
|
|
|
|
name##_store(struct device *dev, struct device_attribute *devattr, \
|
|
|
|
const char *buf, size_t count) \
|
|
|
|
{ \
|
|
|
|
struct thermal_zone_device *tz = to_thermal_zone(dev); \
|
|
|
|
s32 value; \
|
|
|
|
\
|
|
|
|
if (!tz->tzp) \
|
|
|
|
return -EIO; \
|
|
|
|
\
|
|
|
|
if (kstrtos32(buf, 10, &value)) \
|
|
|
|
return -EINVAL; \
|
|
|
|
\
|
|
|
|
tz->tzp->name = value; \
|
|
|
|
\
|
|
|
|
return count; \
|
|
|
|
} \
|
2018-04-03 17:49:04 +08:00
|
|
|
static DEVICE_ATTR_RW(name)
|
2016-11-08 13:09:00 +08:00
|
|
|
|
|
|
|
create_s32_tzp_attr(k_po);
|
|
|
|
create_s32_tzp_attr(k_pu);
|
|
|
|
create_s32_tzp_attr(k_i);
|
|
|
|
create_s32_tzp_attr(k_d);
|
|
|
|
create_s32_tzp_attr(integral_cutoff);
|
|
|
|
create_s32_tzp_attr(slope);
|
|
|
|
create_s32_tzp_attr(offset);
|
|
|
|
#undef create_s32_tzp_attr
|
|
|
|
|
|
|
|
/*
|
|
|
|
* These are thermal zone device attributes that will always be present.
|
|
|
|
* All the attributes created for tzp (create_s32_tzp_attr) also are always
|
|
|
|
* present on the sysfs interface.
|
|
|
|
*/
|
2017-12-20 02:15:08 +08:00
|
|
|
static DEVICE_ATTR_RO(type);
|
|
|
|
static DEVICE_ATTR_RO(temp);
|
2017-12-20 02:15:07 +08:00
|
|
|
static DEVICE_ATTR_RW(policy);
|
2017-12-20 02:15:08 +08:00
|
|
|
static DEVICE_ATTR_RO(available_policies);
|
2017-12-20 02:15:07 +08:00
|
|
|
static DEVICE_ATTR_RW(sustainable_power);
|
2016-11-08 13:09:00 +08:00
|
|
|
|
|
|
|
/* These thermal zone device attributes are created based on conditions */
|
2017-12-20 02:15:07 +08:00
|
|
|
static DEVICE_ATTR_RW(mode);
|
2016-11-08 13:09:00 +08:00
|
|
|
|
|
|
|
/* These attributes are unconditionally added to a thermal zone */
|
|
|
|
static struct attribute *thermal_zone_dev_attrs[] = {
|
|
|
|
&dev_attr_type.attr,
|
|
|
|
&dev_attr_temp.attr,
|
|
|
|
#if (IS_ENABLED(CONFIG_THERMAL_EMULATION))
|
|
|
|
&dev_attr_emul_temp.attr,
|
|
|
|
#endif
|
|
|
|
&dev_attr_policy.attr,
|
|
|
|
&dev_attr_available_policies.attr,
|
|
|
|
&dev_attr_sustainable_power.attr,
|
|
|
|
&dev_attr_k_po.attr,
|
|
|
|
&dev_attr_k_pu.attr,
|
|
|
|
&dev_attr_k_i.attr,
|
|
|
|
&dev_attr_k_d.attr,
|
|
|
|
&dev_attr_integral_cutoff.attr,
|
|
|
|
&dev_attr_slope.attr,
|
|
|
|
&dev_attr_offset.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2020-11-29 07:43:42 +08:00
|
|
|
static const struct attribute_group thermal_zone_attribute_group = {
|
2016-11-08 13:09:00 +08:00
|
|
|
.attrs = thermal_zone_dev_attrs,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct attribute *thermal_zone_mode_attrs[] = {
|
|
|
|
&dev_attr_mode.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2020-11-29 07:43:42 +08:00
|
|
|
static const struct attribute_group thermal_zone_mode_attribute_group = {
|
2016-11-08 13:09:00 +08:00
|
|
|
.attrs = thermal_zone_mode_attrs,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct attribute_group *thermal_zone_attribute_groups[] = {
|
|
|
|
&thermal_zone_attribute_group,
|
|
|
|
&thermal_zone_mode_attribute_group,
|
|
|
|
/* This is not NULL terminated as we create the group dynamically */
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* create_trip_attrs() - create attributes for trip points
|
|
|
|
* @tz: the thermal zone device
|
|
|
|
* @mask: Writeable trip point bitmap.
|
|
|
|
*
|
|
|
|
* helper function to instantiate sysfs entries for every trip
|
|
|
|
* point and its properties of a struct thermal_zone_device.
|
|
|
|
*
|
|
|
|
* Return: 0 on success, the proper error value otherwise.
|
|
|
|
*/
|
|
|
|
static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
|
|
|
|
{
|
|
|
|
struct attribute **attrs;
|
|
|
|
int indx;
|
|
|
|
|
|
|
|
/* This function works only for zones with at least one trip */
|
2022-07-23 04:00:04 +08:00
|
|
|
if (tz->num_trips <= 0)
|
2016-11-08 13:09:00 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2022-07-23 04:00:04 +08:00
|
|
|
tz->trip_type_attrs = kcalloc(tz->num_trips, sizeof(*tz->trip_type_attrs),
|
2016-11-08 13:09:26 +08:00
|
|
|
GFP_KERNEL);
|
2016-11-08 13:09:00 +08:00
|
|
|
if (!tz->trip_type_attrs)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2022-07-23 04:00:04 +08:00
|
|
|
tz->trip_temp_attrs = kcalloc(tz->num_trips, sizeof(*tz->trip_temp_attrs),
|
2016-11-08 13:09:26 +08:00
|
|
|
GFP_KERNEL);
|
2016-11-08 13:09:00 +08:00
|
|
|
if (!tz->trip_temp_attrs) {
|
|
|
|
kfree(tz->trip_type_attrs);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2022-10-03 17:25:35 +08:00
|
|
|
tz->trip_hyst_attrs = kcalloc(tz->num_trips,
|
|
|
|
sizeof(*tz->trip_hyst_attrs),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!tz->trip_hyst_attrs) {
|
|
|
|
kfree(tz->trip_type_attrs);
|
|
|
|
kfree(tz->trip_temp_attrs);
|
|
|
|
return -ENOMEM;
|
2016-11-08 13:09:00 +08:00
|
|
|
}
|
|
|
|
|
2022-07-23 04:00:04 +08:00
|
|
|
attrs = kcalloc(tz->num_trips * 3 + 1, sizeof(*attrs), GFP_KERNEL);
|
2016-11-08 13:09:00 +08:00
|
|
|
if (!attrs) {
|
|
|
|
kfree(tz->trip_type_attrs);
|
|
|
|
kfree(tz->trip_temp_attrs);
|
2022-10-03 17:25:35 +08:00
|
|
|
kfree(tz->trip_hyst_attrs);
|
2016-11-08 13:09:00 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2022-07-23 04:00:04 +08:00
|
|
|
for (indx = 0; indx < tz->num_trips; indx++) {
|
2016-11-08 13:09:00 +08:00
|
|
|
/* create trip type attribute */
|
|
|
|
snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
|
|
|
|
"trip_point_%d_type", indx);
|
|
|
|
|
|
|
|
sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
|
|
|
|
tz->trip_type_attrs[indx].attr.attr.name =
|
|
|
|
tz->trip_type_attrs[indx].name;
|
|
|
|
tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
|
|
|
|
tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
|
|
|
|
attrs[indx] = &tz->trip_type_attrs[indx].attr.attr;
|
|
|
|
|
|
|
|
/* create trip temp attribute */
|
|
|
|
snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
|
|
|
|
"trip_point_%d_temp", indx);
|
|
|
|
|
|
|
|
sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
|
|
|
|
tz->trip_temp_attrs[indx].attr.attr.name =
|
|
|
|
tz->trip_temp_attrs[indx].name;
|
|
|
|
tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
|
|
|
|
tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
|
|
|
|
if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS) &&
|
|
|
|
mask & (1 << indx)) {
|
|
|
|
tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
|
|
|
|
tz->trip_temp_attrs[indx].attr.store =
|
|
|
|
trip_point_temp_store;
|
|
|
|
}
|
2022-07-23 04:00:04 +08:00
|
|
|
attrs[indx + tz->num_trips] = &tz->trip_temp_attrs[indx].attr.attr;
|
2016-11-08 13:09:00 +08:00
|
|
|
|
|
|
|
snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
|
|
|
|
"trip_point_%d_hyst", indx);
|
|
|
|
|
|
|
|
sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
|
|
|
|
tz->trip_hyst_attrs[indx].attr.attr.name =
|
|
|
|
tz->trip_hyst_attrs[indx].name;
|
|
|
|
tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
|
|
|
|
tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
|
|
|
|
if (tz->ops->set_trip_hyst) {
|
|
|
|
tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
|
|
|
|
tz->trip_hyst_attrs[indx].attr.store =
|
|
|
|
trip_point_hyst_store;
|
|
|
|
}
|
2022-07-23 04:00:04 +08:00
|
|
|
attrs[indx + tz->num_trips * 2] =
|
2016-11-08 13:09:00 +08:00
|
|
|
&tz->trip_hyst_attrs[indx].attr.attr;
|
|
|
|
}
|
2022-07-23 04:00:04 +08:00
|
|
|
attrs[tz->num_trips * 3] = NULL;
|
2016-11-08 13:09:00 +08:00
|
|
|
|
|
|
|
tz->trips_attribute_group.attrs = attrs;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-08-08 22:39:52 +08:00
|
|
|
/**
|
|
|
|
* destroy_trip_attrs() - destroy attributes for trip points
|
|
|
|
* @tz: the thermal zone device
|
|
|
|
*
|
|
|
|
* helper function to free resources allocated by create_trip_attrs()
|
|
|
|
*/
|
|
|
|
static void destroy_trip_attrs(struct thermal_zone_device *tz)
|
|
|
|
{
|
|
|
|
if (!tz)
|
|
|
|
return;
|
|
|
|
|
|
|
|
kfree(tz->trip_type_attrs);
|
|
|
|
kfree(tz->trip_temp_attrs);
|
2022-10-03 17:25:35 +08:00
|
|
|
kfree(tz->trip_hyst_attrs);
|
2017-08-08 22:39:52 +08:00
|
|
|
kfree(tz->trips_attribute_group.attrs);
|
|
|
|
}
|
|
|
|
|
2016-11-08 13:09:00 +08:00
|
|
|
int thermal_zone_create_device_groups(struct thermal_zone_device *tz,
|
|
|
|
int mask)
|
|
|
|
{
|
|
|
|
const struct attribute_group **groups;
|
|
|
|
int i, size, result;
|
|
|
|
|
|
|
|
/* we need one extra for trips and the NULL to terminate the array */
|
|
|
|
size = ARRAY_SIZE(thermal_zone_attribute_groups) + 2;
|
|
|
|
/* This also takes care of API requirement to be NULL terminated */
|
|
|
|
groups = kcalloc(size, sizeof(*groups), GFP_KERNEL);
|
|
|
|
if (!groups)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
for (i = 0; i < size - 2; i++)
|
|
|
|
groups[i] = thermal_zone_attribute_groups[i];
|
|
|
|
|
2022-07-23 04:00:04 +08:00
|
|
|
if (tz->num_trips) {
|
2016-11-08 13:09:00 +08:00
|
|
|
result = create_trip_attrs(tz, mask);
|
|
|
|
if (result) {
|
|
|
|
kfree(groups);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
groups[size - 2] = &tz->trips_attribute_group;
|
|
|
|
}
|
|
|
|
|
|
|
|
tz->device.groups = groups;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2016-11-08 13:09:02 +08:00
|
|
|
|
2017-08-08 22:39:52 +08:00
|
|
|
void thermal_zone_destroy_device_groups(struct thermal_zone_device *tz)
|
|
|
|
{
|
|
|
|
if (!tz)
|
|
|
|
return;
|
|
|
|
|
2022-07-23 04:00:04 +08:00
|
|
|
if (tz->num_trips)
|
2017-08-08 22:39:52 +08:00
|
|
|
destroy_trip_attrs(tz);
|
|
|
|
|
|
|
|
kfree(tz->device.groups);
|
|
|
|
}
|
|
|
|
|
2016-11-08 13:09:02 +08:00
|
|
|
/* sys I/F for cooling device */
|
|
|
|
static ssize_t
|
2018-04-03 17:49:03 +08:00
|
|
|
cdev_type_show(struct device *dev, struct device_attribute *attr, char *buf)
|
2016-11-08 13:09:02 +08:00
|
|
|
{
|
|
|
|
struct thermal_cooling_device *cdev = to_cooling_device(dev);
|
|
|
|
|
|
|
|
return sprintf(buf, "%s\n", cdev->type);
|
|
|
|
}
|
|
|
|
|
2018-04-03 17:49:03 +08:00
|
|
|
static ssize_t max_state_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2016-11-08 13:09:02 +08:00
|
|
|
{
|
|
|
|
struct thermal_cooling_device *cdev = to_cooling_device(dev);
|
|
|
|
|
2022-10-17 18:03:01 +08:00
|
|
|
return sprintf(buf, "%ld\n", cdev->max_state);
|
2016-11-08 13:09:02 +08:00
|
|
|
}
|
|
|
|
|
2018-04-03 17:49:03 +08:00
|
|
|
static ssize_t cur_state_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2016-11-08 13:09:02 +08:00
|
|
|
{
|
|
|
|
struct thermal_cooling_device *cdev = to_cooling_device(dev);
|
|
|
|
unsigned long state;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = cdev->ops->get_cur_state(cdev, &state);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
return sprintf(buf, "%ld\n", state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
2018-04-03 17:49:03 +08:00
|
|
|
cur_state_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
2016-11-08 13:09:02 +08:00
|
|
|
{
|
|
|
|
struct thermal_cooling_device *cdev = to_cooling_device(dev);
|
|
|
|
unsigned long state;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
if (sscanf(buf, "%ld\n", &state) != 1)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if ((long)state < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2022-10-17 18:03:01 +08:00
|
|
|
/* Requested state should be less than max_state + 1 */
|
|
|
|
if (state > cdev->max_state)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-11-28 06:43:11 +08:00
|
|
|
mutex_lock(&cdev->lock);
|
|
|
|
|
2016-11-08 13:09:02 +08:00
|
|
|
result = cdev->ops->set_cur_state(cdev, state);
|
2018-11-28 06:43:11 +08:00
|
|
|
if (!result)
|
|
|
|
thermal_cooling_device_stats_update(cdev, state);
|
|
|
|
|
|
|
|
mutex_unlock(&cdev->lock);
|
|
|
|
return result ? result : count;
|
2016-11-08 13:09:02 +08:00
|
|
|
}
|
|
|
|
|
2018-04-03 17:49:03 +08:00
|
|
|
static struct device_attribute
|
|
|
|
dev_attr_cdev_type = __ATTR(type, 0444, cdev_type_show, NULL);
|
2018-04-03 17:49:04 +08:00
|
|
|
static DEVICE_ATTR_RO(max_state);
|
|
|
|
static DEVICE_ATTR_RW(cur_state);
|
2016-11-08 13:09:02 +08:00
|
|
|
|
|
|
|
static struct attribute *cooling_device_attrs[] = {
|
|
|
|
&dev_attr_cdev_type.attr,
|
|
|
|
&dev_attr_max_state.attr,
|
|
|
|
&dev_attr_cur_state.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct attribute_group cooling_device_attr_group = {
|
|
|
|
.attrs = cooling_device_attrs,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct attribute_group *cooling_device_attr_groups[] = {
|
|
|
|
&cooling_device_attr_group,
|
2018-04-02 18:56:25 +08:00
|
|
|
NULL, /* Space allocated for cooling_device_stats_attr_group */
|
2016-11-08 13:09:02 +08:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
#ifdef CONFIG_THERMAL_STATISTICS
|
|
|
|
struct cooling_dev_stats {
|
|
|
|
spinlock_t lock;
|
|
|
|
unsigned int total_trans;
|
|
|
|
unsigned long state;
|
|
|
|
ktime_t last_time;
|
|
|
|
ktime_t *time_in_state;
|
|
|
|
unsigned int *trans_table;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void update_time_in_state(struct cooling_dev_stats *stats)
|
|
|
|
{
|
|
|
|
ktime_t now = ktime_get(), delta;
|
|
|
|
|
|
|
|
delta = ktime_sub(now, stats->last_time);
|
|
|
|
stats->time_in_state[stats->state] =
|
|
|
|
ktime_add(stats->time_in_state[stats->state], delta);
|
|
|
|
stats->last_time = now;
|
|
|
|
}
|
|
|
|
|
|
|
|
void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
|
|
|
|
unsigned long new_state)
|
|
|
|
{
|
|
|
|
struct cooling_dev_stats *stats = cdev->stats;
|
|
|
|
|
2023-03-18 01:01:26 +08:00
|
|
|
lockdep_assert_held(&cdev->lock);
|
|
|
|
|
2020-12-08 02:53:01 +08:00
|
|
|
if (!stats)
|
|
|
|
return;
|
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
spin_lock(&stats->lock);
|
|
|
|
|
|
|
|
if (stats->state == new_state)
|
|
|
|
goto unlock;
|
|
|
|
|
|
|
|
update_time_in_state(stats);
|
2022-10-17 18:03:02 +08:00
|
|
|
stats->trans_table[stats->state * (cdev->max_state + 1) + new_state]++;
|
2018-04-02 18:56:25 +08:00
|
|
|
stats->state = new_state;
|
|
|
|
stats->total_trans++;
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
spin_unlock(&stats->lock);
|
|
|
|
}
|
|
|
|
|
2018-04-03 17:49:03 +08:00
|
|
|
static ssize_t total_trans_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2018-04-02 18:56:25 +08:00
|
|
|
{
|
|
|
|
struct thermal_cooling_device *cdev = to_cooling_device(dev);
|
2023-03-18 01:01:26 +08:00
|
|
|
struct cooling_dev_stats *stats;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
mutex_lock(&cdev->lock);
|
|
|
|
|
|
|
|
stats = cdev->stats;
|
|
|
|
if (!stats)
|
|
|
|
goto unlock;
|
2018-04-02 18:56:25 +08:00
|
|
|
|
|
|
|
spin_lock(&stats->lock);
|
|
|
|
ret = sprintf(buf, "%u\n", stats->total_trans);
|
|
|
|
spin_unlock(&stats->lock);
|
|
|
|
|
2023-03-18 01:01:26 +08:00
|
|
|
unlock:
|
|
|
|
mutex_unlock(&cdev->lock);
|
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
2018-04-03 17:49:03 +08:00
|
|
|
time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2018-04-02 18:56:25 +08:00
|
|
|
{
|
|
|
|
struct thermal_cooling_device *cdev = to_cooling_device(dev);
|
2023-03-18 01:01:26 +08:00
|
|
|
struct cooling_dev_stats *stats;
|
2018-04-02 18:56:25 +08:00
|
|
|
ssize_t len = 0;
|
|
|
|
int i;
|
|
|
|
|
2023-03-18 01:01:26 +08:00
|
|
|
mutex_lock(&cdev->lock);
|
|
|
|
|
|
|
|
stats = cdev->stats;
|
|
|
|
if (!stats)
|
|
|
|
goto unlock;
|
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
spin_lock(&stats->lock);
|
2023-03-18 01:01:26 +08:00
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
update_time_in_state(stats);
|
|
|
|
|
2022-10-17 18:03:02 +08:00
|
|
|
for (i = 0; i <= cdev->max_state; i++) {
|
2018-04-02 18:56:25 +08:00
|
|
|
len += sprintf(buf + len, "state%u\t%llu\n", i,
|
|
|
|
ktime_to_ms(stats->time_in_state[i]));
|
|
|
|
}
|
|
|
|
spin_unlock(&stats->lock);
|
|
|
|
|
2023-03-18 01:01:26 +08:00
|
|
|
unlock:
|
|
|
|
mutex_unlock(&cdev->lock);
|
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
2018-04-03 17:49:03 +08:00
|
|
|
reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
|
|
|
|
size_t count)
|
2018-04-02 18:56:25 +08:00
|
|
|
{
|
|
|
|
struct thermal_cooling_device *cdev = to_cooling_device(dev);
|
2023-03-18 01:01:26 +08:00
|
|
|
struct cooling_dev_stats *stats;
|
|
|
|
int i, states;
|
|
|
|
|
|
|
|
mutex_lock(&cdev->lock);
|
|
|
|
|
|
|
|
stats = cdev->stats;
|
|
|
|
if (!stats)
|
|
|
|
goto unlock;
|
|
|
|
|
|
|
|
states = cdev->max_state + 1;
|
2018-04-02 18:56:25 +08:00
|
|
|
|
|
|
|
spin_lock(&stats->lock);
|
|
|
|
|
|
|
|
stats->total_trans = 0;
|
|
|
|
stats->last_time = ktime_get();
|
|
|
|
memset(stats->trans_table, 0,
|
|
|
|
states * states * sizeof(*stats->trans_table));
|
|
|
|
|
2022-10-17 18:03:02 +08:00
|
|
|
for (i = 0; i < states; i++)
|
2018-04-02 18:56:25 +08:00
|
|
|
stats->time_in_state[i] = ktime_set(0, 0);
|
|
|
|
|
|
|
|
spin_unlock(&stats->lock);
|
|
|
|
|
2023-03-18 01:01:26 +08:00
|
|
|
unlock:
|
|
|
|
mutex_unlock(&cdev->lock);
|
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2018-04-03 17:49:03 +08:00
|
|
|
static ssize_t trans_table_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2018-04-02 18:56:25 +08:00
|
|
|
{
|
|
|
|
struct thermal_cooling_device *cdev = to_cooling_device(dev);
|
2023-03-18 01:01:26 +08:00
|
|
|
struct cooling_dev_stats *stats;
|
2018-04-02 18:56:25 +08:00
|
|
|
ssize_t len = 0;
|
|
|
|
int i, j;
|
|
|
|
|
2023-03-18 01:01:26 +08:00
|
|
|
mutex_lock(&cdev->lock);
|
|
|
|
|
|
|
|
stats = cdev->stats;
|
|
|
|
if (!stats) {
|
|
|
|
len = -ENODATA;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
|
|
|
|
len += snprintf(buf + len, PAGE_SIZE - len, " : ");
|
2022-10-17 18:03:02 +08:00
|
|
|
for (i = 0; i <= cdev->max_state; i++) {
|
2018-04-02 18:56:25 +08:00
|
|
|
if (len >= PAGE_SIZE)
|
|
|
|
break;
|
|
|
|
len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i);
|
|
|
|
}
|
2023-03-18 01:01:26 +08:00
|
|
|
if (len >= PAGE_SIZE) {
|
|
|
|
len = PAGE_SIZE;
|
|
|
|
goto unlock;
|
|
|
|
}
|
2018-04-02 18:56:25 +08:00
|
|
|
|
|
|
|
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
|
|
|
|
|
2022-10-17 18:03:02 +08:00
|
|
|
for (i = 0; i <= cdev->max_state; i++) {
|
2018-04-02 18:56:25 +08:00
|
|
|
if (len >= PAGE_SIZE)
|
|
|
|
break;
|
|
|
|
|
|
|
|
len += snprintf(buf + len, PAGE_SIZE - len, "state%2u:", i);
|
|
|
|
|
2022-10-17 18:03:02 +08:00
|
|
|
for (j = 0; j <= cdev->max_state; j++) {
|
2018-04-02 18:56:25 +08:00
|
|
|
if (len >= PAGE_SIZE)
|
|
|
|
break;
|
|
|
|
len += snprintf(buf + len, PAGE_SIZE - len, "%8u ",
|
2022-10-17 18:03:02 +08:00
|
|
|
stats->trans_table[i * (cdev->max_state + 1) + j]);
|
2018-04-02 18:56:25 +08:00
|
|
|
}
|
|
|
|
if (len >= PAGE_SIZE)
|
|
|
|
break;
|
|
|
|
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len >= PAGE_SIZE) {
|
|
|
|
pr_warn_once("Thermal transition table exceeds PAGE_SIZE. Disabling\n");
|
2023-03-18 01:01:26 +08:00
|
|
|
len = -EFBIG;
|
2018-04-02 18:56:25 +08:00
|
|
|
}
|
2023-03-18 01:01:26 +08:00
|
|
|
|
|
|
|
unlock:
|
|
|
|
mutex_unlock(&cdev->lock);
|
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2018-04-03 17:49:04 +08:00
|
|
|
static DEVICE_ATTR_RO(total_trans);
|
|
|
|
static DEVICE_ATTR_RO(time_in_state_ms);
|
|
|
|
static DEVICE_ATTR_WO(reset);
|
|
|
|
static DEVICE_ATTR_RO(trans_table);
|
2018-04-02 18:56:25 +08:00
|
|
|
|
|
|
|
static struct attribute *cooling_device_stats_attrs[] = {
|
|
|
|
&dev_attr_total_trans.attr,
|
|
|
|
&dev_attr_time_in_state_ms.attr,
|
|
|
|
&dev_attr_reset.attr,
|
|
|
|
&dev_attr_trans_table.attr,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct attribute_group cooling_device_stats_attr_group = {
|
|
|
|
.attrs = cooling_device_stats_attrs,
|
|
|
|
.name = "stats"
|
|
|
|
};
|
|
|
|
|
|
|
|
static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
|
|
|
|
{
|
2022-07-29 23:39:07 +08:00
|
|
|
const struct attribute_group *stats_attr_group = NULL;
|
2018-04-02 18:56:25 +08:00
|
|
|
struct cooling_dev_stats *stats;
|
2022-10-17 18:03:02 +08:00
|
|
|
/* Total number of states is highest state + 1 */
|
|
|
|
unsigned long states = cdev->max_state + 1;
|
2018-04-02 18:56:25 +08:00
|
|
|
int var;
|
|
|
|
|
2023-03-18 01:01:26 +08:00
|
|
|
lockdep_assert_held(&cdev->lock);
|
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
var = sizeof(*stats);
|
|
|
|
var += sizeof(*stats->time_in_state) * states;
|
|
|
|
var += sizeof(*stats->trans_table) * states * states;
|
|
|
|
|
|
|
|
stats = kzalloc(var, GFP_KERNEL);
|
|
|
|
if (!stats)
|
2022-07-29 23:39:07 +08:00
|
|
|
goto out;
|
2018-04-02 18:56:25 +08:00
|
|
|
|
|
|
|
stats->time_in_state = (ktime_t *)(stats + 1);
|
|
|
|
stats->trans_table = (unsigned int *)(stats->time_in_state + states);
|
|
|
|
cdev->stats = stats;
|
|
|
|
stats->last_time = ktime_get();
|
|
|
|
|
|
|
|
spin_lock_init(&stats->lock);
|
|
|
|
|
2022-07-29 23:39:07 +08:00
|
|
|
stats_attr_group = &cooling_device_stats_attr_group;
|
|
|
|
|
|
|
|
out:
|
2018-04-02 18:56:25 +08:00
|
|
|
/* Fill the empty slot left in cooling_device_attr_groups */
|
|
|
|
var = ARRAY_SIZE(cooling_device_attr_groups) - 2;
|
2022-07-29 23:39:07 +08:00
|
|
|
cooling_device_attr_groups[var] = stats_attr_group;
|
2018-04-02 18:56:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev)
|
|
|
|
{
|
2023-03-18 01:01:26 +08:00
|
|
|
lockdep_assert_held(&cdev->lock);
|
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
kfree(cdev->stats);
|
|
|
|
cdev->stats = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
cooling_device_stats_setup(struct thermal_cooling_device *cdev) {}
|
|
|
|
static inline void
|
|
|
|
cooling_device_stats_destroy(struct thermal_cooling_device *cdev) {}
|
|
|
|
|
|
|
|
#endif /* CONFIG_THERMAL_STATISTICS */
|
|
|
|
|
2016-11-08 13:09:02 +08:00
|
|
|
void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *cdev)
|
|
|
|
{
|
2018-04-02 18:56:25 +08:00
|
|
|
cooling_device_stats_setup(cdev);
|
2016-11-08 13:09:02 +08:00
|
|
|
cdev->device.groups = cooling_device_attr_groups;
|
|
|
|
}
|
|
|
|
|
2018-04-02 18:56:25 +08:00
|
|
|
void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev)
|
|
|
|
{
|
|
|
|
cooling_device_stats_destroy(cdev);
|
|
|
|
}
|
|
|
|
|
2023-03-18 01:01:26 +08:00
|
|
|
void thermal_cooling_device_stats_reinit(struct thermal_cooling_device *cdev)
|
|
|
|
{
|
|
|
|
cooling_device_stats_destroy(cdev);
|
|
|
|
cooling_device_stats_setup(cdev);
|
|
|
|
}
|
|
|
|
|
2016-11-08 13:09:02 +08:00
|
|
|
/* these helper will be used only at the time of bindig */
|
|
|
|
ssize_t
|
2018-04-03 17:49:03 +08:00
|
|
|
trip_point_show(struct device *dev, struct device_attribute *attr, char *buf)
|
2016-11-08 13:09:02 +08:00
|
|
|
{
|
|
|
|
struct thermal_instance *instance;
|
|
|
|
|
|
|
|
instance =
|
|
|
|
container_of(attr, struct thermal_instance, attr);
|
|
|
|
|
2020-12-15 07:38:06 +08:00
|
|
|
return sprintf(buf, "%d\n", instance->trip);
|
2016-11-08 13:09:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t
|
2018-04-03 17:49:03 +08:00
|
|
|
weight_show(struct device *dev, struct device_attribute *attr, char *buf)
|
2016-11-08 13:09:02 +08:00
|
|
|
{
|
|
|
|
struct thermal_instance *instance;
|
|
|
|
|
|
|
|
instance = container_of(attr, struct thermal_instance, weight_attr);
|
|
|
|
|
|
|
|
return sprintf(buf, "%d\n", instance->weight);
|
|
|
|
}
|
|
|
|
|
2018-04-03 17:49:03 +08:00
|
|
|
ssize_t weight_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
2016-11-08 13:09:02 +08:00
|
|
|
{
|
|
|
|
struct thermal_instance *instance;
|
|
|
|
int ret, weight;
|
|
|
|
|
|
|
|
ret = kstrtoint(buf, 0, &weight);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
instance = container_of(attr, struct thermal_instance, weight_attr);
|
|
|
|
instance->weight = weight;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|