mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-08 05:43:28 -04:00
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal management updates from Zhang Rui:
"Specifics:
- enhance Thermal Framework with several new capabilities:
* use power estimates
* compute weights with relative integers instead of percentages
* allow governors to have private data in thermal zones
* export thermal zone parameters through sysfs
Thanks to the ARM thermal team (Javi, Punit, KP).
- introduce a new thermal governor: power allocator. First in kernel
closed loop PI(D) controller for thermal control. Thanks to ARM
thermal team.
- enhance OF thermal to allow thermal zones to have sustainable power
HW specification. Thanks to Punit.
- introduce thermal driver for Intel Quark SoC x1000platform. Thanks
to Ong, Boon Leong.
- introduce QPNP PMIC temperature alarm driver. Thanks to Ivan T. I.
- introduce thermal driver for Hisilicon hi6220. Thanks to
kongxinwei.
- enhance Exynos thermal driver to handle Exynos5433 TMU. Thanks to
Chanwoo C.
- TI thermal driver now has a better implementation for EOCZ bit.
From Pavel M.
- add id for Skylake processors in int340x processor thermal driver.
- a couple of small fixes and cleanups."
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (36 commits)
thermal: hisilicon: add new hisilicon thermal sensor driver
dt-bindings: Document the hi6220 thermal sensor bindings
thermal: of-thermal: add support for reading coefficients property
thermal: support slope and offset coefficients
thermal: power_allocator: round the division when divvying up power
thermal: exynos: Add the support for Exynos5433 TMU
thermal: cpu_cooling: Fix power calculation when CPUs are offline
thermal: cpu_cooling: Remove cpu_dev update on policy CPU update
thermal: export thermal_zone_parameters to sysfs
thermal: cpu_cooling: Check memory allocation of power_table
ti-soc-thermal: request temperature periodically if hw can't do that itself
ti-soc-thermal: implement eocz bit to make driver useful on omap3
cleanup ti-soc-thermal
thermal: remove stale THERMAL_POWER_ACTOR select
thermal: Default OF created trip points to writable
thermal: core: Add Kconfig option to enable writable trips
thermal: x86_pkg_temp: drop const for thermal_zone_parameters
of: thermal: Introduce sustainable power for a thermal zone
thermal: add trace events to the power allocator governor
thermal: introduce the Power Allocator governor
...
This commit is contained in:
@@ -28,6 +28,9 @@
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
typedef int (*get_static_t)(cpumask_t *cpumask, int interval,
|
||||
unsigned long voltage, u32 *power);
|
||||
|
||||
#ifdef CONFIG_CPU_THERMAL
|
||||
/**
|
||||
* cpufreq_cooling_register - function to create cpufreq cooling device.
|
||||
@@ -36,6 +39,10 @@
|
||||
struct thermal_cooling_device *
|
||||
cpufreq_cooling_register(const struct cpumask *clip_cpus);
|
||||
|
||||
struct thermal_cooling_device *
|
||||
cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
|
||||
u32 capacitance, get_static_t plat_static_func);
|
||||
|
||||
/**
|
||||
* of_cpufreq_cooling_register - create cpufreq cooling device based on DT.
|
||||
* @np: a valid struct device_node to the cooling device device tree node.
|
||||
@@ -45,6 +52,12 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus);
|
||||
struct thermal_cooling_device *
|
||||
of_cpufreq_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus);
|
||||
|
||||
struct thermal_cooling_device *
|
||||
of_cpufreq_power_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus,
|
||||
u32 capacitance,
|
||||
get_static_t plat_static_func);
|
||||
#else
|
||||
static inline struct thermal_cooling_device *
|
||||
of_cpufreq_cooling_register(struct device_node *np,
|
||||
@@ -52,6 +65,15 @@ of_cpufreq_cooling_register(struct device_node *np,
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline struct thermal_cooling_device *
|
||||
of_cpufreq_power_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus,
|
||||
u32 capacitance,
|
||||
get_static_t plat_static_func)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -67,12 +89,29 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
static inline struct thermal_cooling_device *
|
||||
cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
|
||||
u32 capacitance, get_static_t plat_static_func)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct thermal_cooling_device *
|
||||
of_cpufreq_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline struct thermal_cooling_device *
|
||||
of_cpufreq_power_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus,
|
||||
u32 capacitance,
|
||||
get_static_t plat_static_func)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline
|
||||
void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
/* No upper/lower limit requirement */
|
||||
#define THERMAL_NO_LIMIT ((u32)~0)
|
||||
|
||||
/* Default weight of a bound cooling device */
|
||||
#define THERMAL_WEIGHT_DEFAULT 0
|
||||
|
||||
/* Unit conversion macros */
|
||||
#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \
|
||||
((long)t-2732+5)/10 : ((long)t-2732-5)/10)
|
||||
@@ -56,10 +59,13 @@
|
||||
#define DEFAULT_THERMAL_GOVERNOR "fair_share"
|
||||
#elif defined(CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE)
|
||||
#define DEFAULT_THERMAL_GOVERNOR "user_space"
|
||||
#elif defined(CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR)
|
||||
#define DEFAULT_THERMAL_GOVERNOR "power_allocator"
|
||||
#endif
|
||||
|
||||
struct thermal_zone_device;
|
||||
struct thermal_cooling_device;
|
||||
struct thermal_instance;
|
||||
|
||||
enum thermal_device_mode {
|
||||
THERMAL_DEVICE_DISABLED = 0,
|
||||
@@ -113,6 +119,12 @@ struct thermal_cooling_device_ops {
|
||||
int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
|
||||
int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
|
||||
int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
|
||||
int (*get_requested_power)(struct thermal_cooling_device *,
|
||||
struct thermal_zone_device *, u32 *);
|
||||
int (*state2power)(struct thermal_cooling_device *,
|
||||
struct thermal_zone_device *, unsigned long, u32 *);
|
||||
int (*power2state)(struct thermal_cooling_device *,
|
||||
struct thermal_zone_device *, u32, unsigned long *);
|
||||
};
|
||||
|
||||
struct thermal_cooling_device {
|
||||
@@ -144,8 +156,7 @@ struct thermal_attr {
|
||||
* @devdata: private pointer for device private data
|
||||
* @trips: number of trip points the thermal zone supports
|
||||
* @passive_delay: number of milliseconds to wait between polls when
|
||||
* performing passive cooling. Currenty only used by the
|
||||
* step-wise governor
|
||||
* performing passive cooling.
|
||||
* @polling_delay: number of milliseconds to wait between polls when
|
||||
* checking whether trip points have been crossed (0 for
|
||||
* interrupt driven systems)
|
||||
@@ -155,13 +166,13 @@ struct thermal_attr {
|
||||
* @last_temperature: previous temperature read
|
||||
* @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION
|
||||
* @passive: 1 if you've crossed a passive trip point, 0 otherwise.
|
||||
* Currenty only used by the step-wise governor.
|
||||
* @forced_passive: If > 0, temperature at which to switch on all ACPI
|
||||
* processor cooling devices. Currently only used by the
|
||||
* step-wise governor.
|
||||
* @ops: operations this &thermal_zone_device supports
|
||||
* @tzp: thermal zone parameters
|
||||
* @governor: pointer to the governor for this thermal zone
|
||||
* @governor_data: private pointer for governor data
|
||||
* @thermal_instances: list of &struct thermal_instance of this thermal zone
|
||||
* @idr: &struct idr to generate unique id for this zone's cooling
|
||||
* devices
|
||||
@@ -186,8 +197,9 @@ struct thermal_zone_device {
|
||||
int passive;
|
||||
unsigned int forced_passive;
|
||||
struct thermal_zone_device_ops *ops;
|
||||
const struct thermal_zone_params *tzp;
|
||||
struct thermal_zone_params *tzp;
|
||||
struct thermal_governor *governor;
|
||||
void *governor_data;
|
||||
struct list_head thermal_instances;
|
||||
struct idr idr;
|
||||
struct mutex lock;
|
||||
@@ -198,12 +210,19 @@ struct thermal_zone_device {
|
||||
/**
|
||||
* struct thermal_governor - structure that holds thermal governor information
|
||||
* @name: name of the governor
|
||||
* @bind_to_tz: callback called when binding to a thermal zone. If it
|
||||
* returns 0, the governor is bound to the thermal zone,
|
||||
* otherwise it fails.
|
||||
* @unbind_from_tz: callback called when a governor is unbound from a
|
||||
* thermal zone.
|
||||
* @throttle: callback called for every trip point even if temperature is
|
||||
* below the trip point temperature
|
||||
* @governor_list: node in thermal_governor_list (in thermal_core.c)
|
||||
*/
|
||||
struct thermal_governor {
|
||||
char name[THERMAL_NAME_LENGTH];
|
||||
int (*bind_to_tz)(struct thermal_zone_device *tz);
|
||||
void (*unbind_from_tz)(struct thermal_zone_device *tz);
|
||||
int (*throttle)(struct thermal_zone_device *tz, int trip);
|
||||
struct list_head governor_list;
|
||||
};
|
||||
@@ -214,9 +233,12 @@ struct thermal_bind_params {
|
||||
|
||||
/*
|
||||
* This is a measure of 'how effectively these devices can
|
||||
* cool 'this' thermal zone. The shall be determined by platform
|
||||
* characterization. This is on a 'percentage' scale.
|
||||
* See Documentation/thermal/sysfs-api.txt for more information.
|
||||
* cool 'this' thermal zone. It shall be determined by
|
||||
* platform characterization. This value is relative to the
|
||||
* rest of the weights so a cooling device whose weight is
|
||||
* double that of another cooling device is twice as
|
||||
* effective. See Documentation/thermal/sysfs-api.txt for more
|
||||
* information.
|
||||
*/
|
||||
int weight;
|
||||
|
||||
@@ -253,6 +275,44 @@ struct thermal_zone_params {
|
||||
|
||||
int num_tbps; /* Number of tbp entries */
|
||||
struct thermal_bind_params *tbp;
|
||||
|
||||
/*
|
||||
* Sustainable power (heat) that this thermal zone can dissipate in
|
||||
* mW
|
||||
*/
|
||||
u32 sustainable_power;
|
||||
|
||||
/*
|
||||
* Proportional parameter of the PID controller when
|
||||
* overshooting (i.e., when temperature is below the target)
|
||||
*/
|
||||
s32 k_po;
|
||||
|
||||
/*
|
||||
* Proportional parameter of the PID controller when
|
||||
* undershooting
|
||||
*/
|
||||
s32 k_pu;
|
||||
|
||||
/* Integral parameter of the PID controller */
|
||||
s32 k_i;
|
||||
|
||||
/* Derivative parameter of the PID controller */
|
||||
s32 k_d;
|
||||
|
||||
/* threshold below which the error is no longer accumulated */
|
||||
s32 integral_cutoff;
|
||||
|
||||
/*
|
||||
* @slope: slope of a linear temperature adjustment curve.
|
||||
* Used by thermal zone drivers.
|
||||
*/
|
||||
int slope;
|
||||
/*
|
||||
* @offset: offset of a linear temperature adjustment curve.
|
||||
* Used by thermal zone drivers (default 0).
|
||||
*/
|
||||
int offset;
|
||||
};
|
||||
|
||||
struct thermal_genl_event {
|
||||
@@ -316,14 +376,25 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_THERMAL)
|
||||
static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
return cdev->ops->get_requested_power && cdev->ops->state2power &&
|
||||
cdev->ops->power2state;
|
||||
}
|
||||
|
||||
int power_actor_get_max_power(struct thermal_cooling_device *,
|
||||
struct thermal_zone_device *tz, u32 *max_power);
|
||||
int power_actor_set_power(struct thermal_cooling_device *,
|
||||
struct thermal_instance *, u32);
|
||||
struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
|
||||
void *, struct thermal_zone_device_ops *,
|
||||
const struct thermal_zone_params *, int, int);
|
||||
struct thermal_zone_params *, int, int);
|
||||
void thermal_zone_device_unregister(struct thermal_zone_device *);
|
||||
|
||||
int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
|
||||
struct thermal_cooling_device *,
|
||||
unsigned long, unsigned long);
|
||||
unsigned long, unsigned long,
|
||||
unsigned int);
|
||||
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
|
||||
struct thermal_cooling_device *);
|
||||
void thermal_zone_device_update(struct thermal_zone_device *);
|
||||
@@ -343,6 +414,14 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
|
||||
void thermal_cdev_update(struct thermal_cooling_device *);
|
||||
void thermal_notify_framework(struct thermal_zone_device *, int);
|
||||
#else
|
||||
static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
|
||||
{ return false; }
|
||||
static inline int power_actor_get_max_power(struct thermal_cooling_device *cdev,
|
||||
struct thermal_zone_device *tz, u32 *max_power)
|
||||
{ return 0; }
|
||||
static inline int power_actor_set_power(struct thermal_cooling_device *cdev,
|
||||
struct thermal_instance *tz, u32 power)
|
||||
{ return 0; }
|
||||
static inline struct thermal_zone_device *thermal_zone_device_register(
|
||||
const char *type, int trips, int mask, void *devdata,
|
||||
struct thermal_zone_device_ops *ops,
|
||||
|
||||
@@ -77,6 +77,64 @@ TRACE_EVENT(thermal_zone_trip,
|
||||
__entry->trip_type)
|
||||
);
|
||||
|
||||
TRACE_EVENT(thermal_power_cpu_get_power,
|
||||
TP_PROTO(const struct cpumask *cpus, unsigned long freq, u32 *load,
|
||||
size_t load_len, u32 dynamic_power, u32 static_power),
|
||||
|
||||
TP_ARGS(cpus, freq, load, load_len, dynamic_power, static_power),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__bitmask(cpumask, num_possible_cpus())
|
||||
__field(unsigned long, freq )
|
||||
__dynamic_array(u32, load, load_len)
|
||||
__field(size_t, load_len )
|
||||
__field(u32, dynamic_power )
|
||||
__field(u32, static_power )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_bitmask(cpumask, cpumask_bits(cpus),
|
||||
num_possible_cpus());
|
||||
__entry->freq = freq;
|
||||
memcpy(__get_dynamic_array(load), load,
|
||||
load_len * sizeof(*load));
|
||||
__entry->load_len = load_len;
|
||||
__entry->dynamic_power = dynamic_power;
|
||||
__entry->static_power = static_power;
|
||||
),
|
||||
|
||||
TP_printk("cpus=%s freq=%lu load={%s} dynamic_power=%d static_power=%d",
|
||||
__get_bitmask(cpumask), __entry->freq,
|
||||
__print_array(__get_dynamic_array(load), __entry->load_len, 4),
|
||||
__entry->dynamic_power, __entry->static_power)
|
||||
);
|
||||
|
||||
TRACE_EVENT(thermal_power_cpu_limit,
|
||||
TP_PROTO(const struct cpumask *cpus, unsigned int freq,
|
||||
unsigned long cdev_state, u32 power),
|
||||
|
||||
TP_ARGS(cpus, freq, cdev_state, power),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__bitmask(cpumask, num_possible_cpus())
|
||||
__field(unsigned int, freq )
|
||||
__field(unsigned long, cdev_state)
|
||||
__field(u32, power )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_bitmask(cpumask, cpumask_bits(cpus),
|
||||
num_possible_cpus());
|
||||
__entry->freq = freq;
|
||||
__entry->cdev_state = cdev_state;
|
||||
__entry->power = power;
|
||||
),
|
||||
|
||||
TP_printk("cpus=%s freq=%u cdev_state=%lu power=%u",
|
||||
__get_bitmask(cpumask), __entry->freq, __entry->cdev_state,
|
||||
__entry->power)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_THERMAL_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
||||
87
include/trace/events/thermal_power_allocator.h
Normal file
87
include/trace/events/thermal_power_allocator.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM thermal_power_allocator
|
||||
|
||||
#if !defined(_TRACE_THERMAL_POWER_ALLOCATOR_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _TRACE_THERMAL_POWER_ALLOCATOR_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
TRACE_EVENT(thermal_power_allocator,
|
||||
TP_PROTO(struct thermal_zone_device *tz, u32 *req_power,
|
||||
u32 total_req_power, u32 *granted_power,
|
||||
u32 total_granted_power, size_t num_actors,
|
||||
u32 power_range, u32 max_allocatable_power,
|
||||
unsigned long current_temp, s32 delta_temp),
|
||||
TP_ARGS(tz, req_power, total_req_power, granted_power,
|
||||
total_granted_power, num_actors, power_range,
|
||||
max_allocatable_power, current_temp, delta_temp),
|
||||
TP_STRUCT__entry(
|
||||
__field(int, tz_id )
|
||||
__dynamic_array(u32, req_power, num_actors )
|
||||
__field(u32, total_req_power )
|
||||
__dynamic_array(u32, granted_power, num_actors)
|
||||
__field(u32, total_granted_power )
|
||||
__field(size_t, num_actors )
|
||||
__field(u32, power_range )
|
||||
__field(u32, max_allocatable_power )
|
||||
__field(unsigned long, current_temp )
|
||||
__field(s32, delta_temp )
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->tz_id = tz->id;
|
||||
memcpy(__get_dynamic_array(req_power), req_power,
|
||||
num_actors * sizeof(*req_power));
|
||||
__entry->total_req_power = total_req_power;
|
||||
memcpy(__get_dynamic_array(granted_power), granted_power,
|
||||
num_actors * sizeof(*granted_power));
|
||||
__entry->total_granted_power = total_granted_power;
|
||||
__entry->num_actors = num_actors;
|
||||
__entry->power_range = power_range;
|
||||
__entry->max_allocatable_power = max_allocatable_power;
|
||||
__entry->current_temp = current_temp;
|
||||
__entry->delta_temp = delta_temp;
|
||||
),
|
||||
|
||||
TP_printk("thermal_zone_id=%d req_power={%s} total_req_power=%u granted_power={%s} total_granted_power=%u power_range=%u max_allocatable_power=%u current_temperature=%lu delta_temperature=%d",
|
||||
__entry->tz_id,
|
||||
__print_array(__get_dynamic_array(req_power),
|
||||
__entry->num_actors, 4),
|
||||
__entry->total_req_power,
|
||||
__print_array(__get_dynamic_array(granted_power),
|
||||
__entry->num_actors, 4),
|
||||
__entry->total_granted_power, __entry->power_range,
|
||||
__entry->max_allocatable_power, __entry->current_temp,
|
||||
__entry->delta_temp)
|
||||
);
|
||||
|
||||
TRACE_EVENT(thermal_power_allocator_pid,
|
||||
TP_PROTO(struct thermal_zone_device *tz, s32 err, s32 err_integral,
|
||||
s64 p, s64 i, s64 d, s32 output),
|
||||
TP_ARGS(tz, err, err_integral, p, i, d, output),
|
||||
TP_STRUCT__entry(
|
||||
__field(int, tz_id )
|
||||
__field(s32, err )
|
||||
__field(s32, err_integral)
|
||||
__field(s64, p )
|
||||
__field(s64, i )
|
||||
__field(s64, d )
|
||||
__field(s32, output )
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->tz_id = tz->id;
|
||||
__entry->err = err;
|
||||
__entry->err_integral = err_integral;
|
||||
__entry->p = p;
|
||||
__entry->i = i;
|
||||
__entry->d = d;
|
||||
__entry->output = output;
|
||||
),
|
||||
|
||||
TP_printk("thermal_zone_id=%d err=%d err_integral=%d p=%lld i=%lld d=%lld output=%d",
|
||||
__entry->tz_id, __entry->err, __entry->err_integral,
|
||||
__entry->p, __entry->i, __entry->d, __entry->output)
|
||||
);
|
||||
#endif /* _TRACE_THERMAL_POWER_ALLOCATOR_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
||||
Reference in New Issue
Block a user