基础知识
1.thermal 的框架
使用场景:
当cpu 温度过高时,适当的进行降频,从而控制稳定cpu 温度。
代码分析:
从Makefile 开始
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for sensor chip drivers.
#
obj-$(CONFIG_THERMAL) += thermal_sys.o
thermal_sys-y += thermal_core.o thermal_sysfs.o \
thermal_helpers.o # 核心代码
# interface to/from other layers providing sensors
thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o
thermal_sys-$(CONFIG_THERMAL_OF) += of-thermal.o # dts 解析
# governors
thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o # governors 也是五种
thermal_sys-$(CONFIG_THERMAL_GOV_BANG_BANG) += gov_bang_bang.o
thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o
thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o
thermal_sys-$(CONFIG_THERMAL_GOV_POWER_ALLOCATOR) += power_allocator.o
# cpufreq cooling
thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o # cooling device
# clock cooling
thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o
# devfreq cooling
thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
# platform thermal drivers
obj-$(CONFIG_SUN8I_THS) += sun8i_ths.o # 平台相关代码,提供读取温度的接口
1.thermal 的初始化
static int __init thermal_init(void)
{
int result;
mutex_init(&poweroff_lock);
result = thermal_register_governors(); // 1.注册五种governors
result = class_register(&thermal_class); // 2.注册 /sys/class/thermal
result = of_parse_thermal_zones(); // 3.解析dts 的"thermal-zones"节点,并注册
// thermal_zone_device
result = register_pm_notifier(&thermal_pm_nb); // 4.notifier
}
fs_initcall(thermal_init);
其中最重要的是 of_parse_thermal_zones
先看看 相关dts:
thermal-zones {
cpu_thermal: cpu_thermal {
polling-delay-passive = <330>;
polling-delay = <1000>;
thermal-sensors = <&ths 0>;
trips {
cpu_warm: cpu_warm {
temperature = <65000>;
hysteresis = <2000>;
type = "passive";
};
cpu_hot: cpu_hot {
temperature = <75000>;
hysteresis = <2000>;
type = "passive";
};
cpu_very_hot: cpu_very_hot {
temperature = <90000>;
hysteresis = <2000>;
type = "passive";
};
cpu_crit: cpu_crit {
temperature = <105000>;
hysteresis = <2000>;
type = "critical";
};
};
cooling-maps {
cpu_warm_limit_cpu {
trip = <&cpu_warm>;
cooling-device = <&cpu0 THERMAL_NO_LIMIT 1>;
};
cpu_hot_limit_cpu {
trip = <&cpu_hot>;
cooling-device = <&cpu0 2 3>;
};
cpu_very_hot_limit_cpu {
trip = <&cpu_very_hot>;
cooling-device = <&cpu0 5 THERMAL_NO_LIMIT>;
};
};
};
};
int __init of_parse_thermal_zones(void)
{
np = of_find_node_by_name(NULL, "thermal-zones"); // 查找 "thermal-zones"
for_each_available_child_of_node(np, child) { // 遍历子节点
tz = thermal_of_build_thermal_zone(child); // 解析关键词,填充tz 数据结构
ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL);
if (!ops)
goto exit_free;
tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
zone = thermal_zone_device_register(child->name, tz->ntrips,
mask, tz,
ops, tzp,
tz->passive_delay,
tz->polling_delay); // 注册一个 thermal_zone_device
}
}
struct thermal_zone_device *
thermal_zone_device_register(const char *type, int trips, int mask,
void *devdata, struct thermal_zone_device_ops *ops,
struct thermal_zone_params *tzp, int passive_delay,
int polling_delay)
{
dev_set_name(&tz->device, "thermal_zone%d", tz->id);
result = device_register(&tz->device); // 注册设备
result = thermal_set_governor(tz, governor); // set governor
list_add_tail(&tz->node, &thermal_tz_list);
/* Bind cooling devices for this zone */
bind_tz(tz); // 将thermal_cdev_list 中的所有cooling devices 与之绑定
INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check); // 初始化工作队列
if (atomic_cmpxchg(&tz->need_update, 1, 0))
thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
}
cpufreq cooling device 的注册,位于 cpufreq_driver -> reay 阶段,
static void cpufreq_ready(struct cpufreq_policy *policy)
{
if (of_find_property(np, "#cooling-cells", NULL)) { // 包含#cooling-cells 属性的
priv->cdev = of_cpufreq_power_cooling_register(np,
policy, power_coefficient, NULL); // register
}
}
else {
cooling_ops = &cpufreq_cooling_ops;
}
cdev = thermal_of_cooling_device_register(np, dev_name, cpufreq_cdev,
cooling_ops);
list_add(&cdev->node, &thermal_cdev_list); // 就是添加到 thermal_cdev_list 中
需要关心的是 cpufreq_cooling_ops
static struct thermal_cooling_device_ops cpufreq_cooling_ops = {
.get_max_state = cpufreq_get_max_state,
.get_cur_state = cpufreq_get_cur_state,
.set_cur_state = cpufreq_set_cur_state,
};
.set_cur_state 被 thermal governor 调用
static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
clip_freq = cpufreq_cdev->freq_table[state].frequency; //根据state 设置新的频率
cpufreq_cdev->cpufreq_state = state;
cpufreq_cdev->clipped_freq = clip_freq; //
cpufreq_update_policy(cpufreq_cdev->policy->cpu);
return 0;
}
时序图: