admin管理员组

文章数量:1536371

目录

一、概述

二、源码分析(基于kernel-4.19)

2.1 thermal_init(drivers\thermal\thermal_core.c)

2.2 thermal_register_governors

2.2.1 thermal_register_governor

2.2.2 step_wise(drivers\thermal\step_wise.c)

2.2.3 fair_share(drivers\thermal\fair_share.c)

2.2.4 bang_bang(drivers\thermal\gov_bang_bang.c)

2.2.5 power_allocator(drivers\thermal\power_allocator.c)

2.2.6 user_space

2.3 class_register

2.4 of_parse_thermal_zones


一、概述

        Linux Thermal是linux系统下温度控制相关模块,主要作用是让系统温度保持在安全的范围,为了实现这个目的需要获取温度的设备和控制温度的设备,以及一些温度控制设备的策略。

        获取温度的设备在Thermal框架中被抽象为Thermal Zone Device;

        控制温度的设备在Thermal框架中被抽象为Thermal Cooling Device;

        温控策略在Thermal框架中被抽象为Thermal governors;

        Thermal core,thermal主要的程序,驱动初始化程序,组织并管理上面三个组件,通过sysfs和用户空间交互

        Cooling Device维护一个Cooling等级(state),Cooling Device只根据state进行冷却操作,state的计算由governor完成;thermal_instance结构体描述trip point必须与一个cooling device绑定,一个thermal zone可以有多个cooling设备,同时还提供一个核心函数thermal_zone_device_update作为thermal中断处理和轮询函数,轮询时间会根据不同trip delay调节,发热设备也可以是降温设备,比如CPU、GPU,频率升高时是升温设备,频率降低时是降温设备

        thermal governor,解决温控发生时(throttle),cooling device如何选择cooling state的问题,linux内核提供了多种温控策略:

1.step_wise:根据当前温度,cooling device逐级降频

2.power_allocator:引入PID(比例-积分-微分)控制,根据当前温度,动态给各cooling device分配power,并将power转换为频率,从而达到根据温度限制频率的效果

3.user_space:用户空间控制

4.fair_share:频率挡位比较多的cooling device优先降频

5.bang_bang:两点温度调节,可用于cooling device由风扇的场景

        如果dts中没有指定使用的governor就使用默认策略,默认governor位置(drivers/thermal/Kconfig)

         thermal zone device,创建thermal zone节点和连接thermal sensor,在sys/class/thermal目录下的thermal_zone*,通过dts文件进行配置生成,thermal sensor是温度传感器

二、源码分析(基于kernel-4.19)

2.1 thermal_init(drivers\thermal\thermal_core.c)

static int __init thermal_init(void)
{
	int result;

	mutex_init(&poweroff_lock);//注册互斥锁
	result = thermal_register_governors();//向thermal zone注册thermal_governor
	if (result)
		goto error;

	result = class_register(&thermal_class);//注册class,sys/class/thermal
	if (result)
		goto unregister_governors;

	result = genetlink_init();//注册netlink:用于内核与用户空间进程之间以及不同进程间通信
	if (result)
		goto unregister_class;

	result = of_parse_thermal_zones();//解析dts中的thermal_zone,并注册thermal_zone_device
	if (result)
		goto exit_netlink;

	result = register_pm_notifier(&thermal_pm_nb);//注册notifier机制
	if (result)
		pr_warn("Thermal: Can not register suspend notifier, return %d\n",
			result);

	return 0;

exit_netlink:
	genetlink_exit();
unregister_class:
	class_unregister(&thermal_class);
unregister_governors:
	thermal_unregister_governors();
error:
	ida_destroy(&thermal_tz_ida);
	ida_destroy(&thermal_cdev_ida);
	mutex_destroy(&thermal_list_lock);
	mutex_destroy(&thermal_governor_lock);
	mutex_destroy(&poweroff_lock);
	return result;
}

可以看到代码流程就thermal_register_governors-->class_register-->genetlink_init-->of_parse_thermal_zones-->register_pm_notifier

其中genetlink、notifier大致知道是干啥的就行,不做研究

2.2 thermal_register_governors

static int __init thermal_register_governors(void)//依次注册各governor
{
	int result;

	result = thermal_gov_step_wise_register();
	if (result)
		return result;

	result = thermal_gov_fair_share_register();
	if (result)
		return result;

	result = thermal_gov_bang_bang_register();
	if (result)
		return result;

	result = thermal_gov_user_space_register();
	if (result)
		return result;

	return thermal_gov_power_allocator_register();
}
  1. 走的都是thermal_register_governor,只是传入的参数不同

2.2.1 thermal_register_governor

int thermal_register_governor(struct thermal_governor *governor)
{
	int err;
	const char *name;
	struct thermal_zone_device *pos;

	if (!governor)//指针判空
		return -EINVAL;

	mutex_lock(&thermal_governor_lock);

	err = -EBUSY;
	if (!__find_governor(governor->name)) {//遍历链表查找该governor是否已注册
		bool match_default;

		err = 0;
		list_add(&governor->governor_list, &thermal_governor_list);//没有注册则添加进链表中
		match_default = !strncmp(governor->name,
					 DEFAULT_THERMAL_GOVERNOR,
					 THERMAL_NAME_LENGTH);

		if (!def_governor && match_default)//判断是否与默认策略相同,相同则赋值给def_governor
			def_governor = governor;
	}

	mutex_lock(&thermal_list_lock);

	list_for_each_entry(pos, &thermal_tz_list, node) {//遍历链表
		/*
		 * only thermal zones with specified tz->tzp->governor_name
		 * may run with tz->govenor unset
		 */
		if (pos->governor)//找到注册策略的thermal zone device
			continue;

		name = pos->tzp->governor_name;

		if (!strncasecmp(name, governor->name, THERMAL_NAME_LENGTH)) {
			int ret;

			ret = thermal_set_governor(pos, governor);//切换策略
			if (ret)
				dev_err(&pos->device,
					"Failed to set governor %s for thermal zone %s: %d\n",
					governor->name, pos->type, ret);
		}
	}

	mutex_unlock(&thermal_list_lock);
	mutex_unlock(&thermal_governor_lock);

	return err;
}

下面看具体的各个策略

2.2.2 step_wise(drivers\thermal\step_wise.c)

static int step_wise_throttle(struct thermal_zone_device *tz, int trip)
{
	struct thermal_instance *instance;

	thermal_zone_trip_update(tz, trip);//更新trip、trend和计算cooling_device的等级

	if (tz->forced_passive)//默认触发温度
		thermal_zone_trip_update(tz, THERMAL_TRIPS_NONE);//重新设置trip,这里传入为-1表示啥也不做

	mutex_lock(&tz->lock);

	list_for_each_entry(instance, &tz->thermal_instances, tz_node)//遍历各instances
		thermal_cdev_update(instance->cdev);//更新cooling_device

	mutex_unlock(&tz->lock);

	return 0;
}
static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
{
	int trip_temp;
	enum thermal_trip_type trip_type;
	enum thermal_trend trend;
	struct thermal_instance *instance;
	bool throttle = false;
	int old_target;

	if (trip == THERMAL_TRIPS_NONE) {//没有trip
		trip_temp = tz->forced_passive;//则触发温度为默认值
		trip_type = THERMAL_TRIPS_NONE;//无触发类型
	} else {
		tz->ops->get_trip_temp(tz, trip, &trip_temp);//获取trip温度
		tz->ops->get_trip_type(tz, trip, &trip_type);//获取trip类型
	}

	trend = get_tz_trend(tz, trip);//获取温度的趋势,是用当前温度比较上一次获取的温度
	//这里的趋势共三种上升、下降、稳定

	if (tz->temperature >= trip_temp) {//达到触发温度时
		throttle = true;
		trace_thermal_zone_trip(tz, trip, trip_type);
	}

	dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
				trip, trip_type, trip_temp, trend, throttle);

	mutex_lock(&tz->lock);

	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {//遍历instance链表
		if (instance->trip != trip)//找到与trip对应的instance
			continue;

		old_target = instance->target;
		instance->target = get_target_state(instance, trend, throttle);//获取cooling device的等级
		dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
					old_target, (int)instance->target);

		if (instance->initialized && old_target == instance->target)//instance以及初始化且等级不变则不走下面流程
			continue;//只有等级发生变化才会走下面

		/* Activate a passive thermal instance */
		if (old_target == THERMAL_NO_TARGET &&//上一等级啥也不做则当前等级不为-1
			instance->target != THERMAL_NO_TARGET)
			update_passive_instance(tz, trip_type, 1);//启动温控
		/* Deactivate a passive thermal instance */
		else if (old_target != THERMAL_NO_TARGET &&//上一等级不为空且当前等级为空
			instance->target == THERMAL_NO_TARGET)
			update_passive_instance(tz, trip_type, -1);//不启动温控

		instance->initialized = true;//初始化标志位赋值true,表明已初始化
		mutex_lock(&instance->cdev->lock);
		instance->cdev->updated = false; /* cdev needs update *///更新标志位写为false表示需要更新
		mutex_unlock(&instance->cdev->lock);
	}

	mutex_unlock(&tz->lock);
}
void thermal_cdev_update(struct thermal_cooling_device *cdev)
{
	struct thermal_instance *instance;
	unsigned long target = 0;

	mutex_lock(&cdev->lock);
	/* cooling device is updated*/
	if (cdev->updated) {//判断更新标志位,检查是否需要更新
		mutex_unlock(&cdev->lock);
		return;
	}

	/* Make sure cdev enters the deepest cooling state */
	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {//遍历instances链表
		dev_dbg(&cdev->device, "zone%d->target=%lu\n",
			instance->tz->id, instance->target);
		if (instance->target == THERMAL_NO_TARGET)//非-1才走下面
			continue;
		if (instance->target > target)
			target = instance->target;//更新target
	}

	if (!cdev->ops->set_cur_state(cdev, target))//设置当前等级
		thermal_cooling_device_stats_update(cdev, target);//设置失败则走更新状态

	cdev->updated = true;
	mutex_unlock(&cdev->lock);
	trace_cdev_update(cdev, target);
	dev_dbg(&cdev->device, "set to state %lu\n", target);
}
EXPORT_SYMBOL(thermal_cdev_update);

该策略主要逻辑get_target_state

static unsigned long get_target_state(struct thermal_instance *instance,
				enum thermal_trend trend, bool throttle)
{
	struct thermal_cooling_device *cdev = instance->cdev;
	unsigned long cur_state;
	unsigned long next_target;

	/*
	 * We keep this instance the way it is by default.
	 * Otherwise, we use the current state of the
	 * cdev in use to determine the next_target.
	 */
	cdev->ops->get_cur_state(cdev, &cur_state);//获取当前等级
	next_target = instance->target;
	dev_dbg(&cdev->device, "cur_state=%ld\n", cur_state);

	if (!instance->initialized) {//判断是否初始化
		if (throttle) {//触发温控
			next_target = (cur_state + 1) >= instance->upper ?//当前等级+1是否等级最高等级,是则下一等级为最高等级
			//不是则判断是否低于最低等级,低于则下一等级为最低,否则为当前等级+1,都不满足则啥也不做
					instance->upper :
					((cur_state + 1) < instance->lower ?
					instance->lower : (cur_state + 1));
		} else {
			next_target = THERMAL_NO_TARGET;
		}

		return next_target;
	}

	switch (trend) {//根据温度趋势来判断
	case THERMAL_TREND_RAISING://温度上升时
		if (throttle) {//触发温控
			next_target = cur_state < instance->upper ?//当前等级是否低于最高等级,是则下一等级为当前等级+1,否则为最高等级
				    (cur_state + 1) : instance->upper;
			if (next_target < instance->lower)//上面判断后当前等级还是低于最低等级的话则下一等级为最低等级
				next_target = instance->lower;//这里的等级指的是温控的等级,等级越高说明温控越严重,需要更高等级的限制
		}
		break;
	case THERMAL_TREND_RAISE_FULL://已经是最高温度了
		if (throttle)//触发温控
			next_target = instance->upper;//最高等级
		break;
	case THERMAL_TREND_DROPPING://温度下降时
		if (cur_state <= instance->lower) {//当前等级是否小于最低等级
			if (!throttle)//没触发温控
				next_target = THERMAL_NO_TARGET;//啥也不做
		} else {//不小于最低等级
			if (!throttle) {//触发温控
				next_target = cur_state - 1;//下一等级为当前等级-1
				if (next_target > instance->upper)//上面判断后当前等级大于最高等级则为最高等级
					next_target = instance->upper;
			}
		}
		break;
	case THERMAL_TREND_DROP_FULL://最低温度了
		if (cur_state == instance->lower) {//当前为最低等级
			if (!throttle)//没触发温控
				next_target = THERMAL_NO_TARGET;//啥也不做
		} else//不是最低等级
			next_target = instance->lower;//下一等级为最低等级
		break;
	default:
		break;
	}

	return next_target;
}

从上面源码可以看出step_wise是根据当前的温度来逐步提高或下降等级

2.2.3 fair_share(drivers\thermal\fair_share.c)

static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
{
	struct thermal_instance *instance;
	int total_weight = 0;
	int total_instance = 0;
	int cur_trip_level = get_trip_level(tz);//获取当前的trip等级

	mutex_lock(&tz->lock);

	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
		if (instance->trip != trip)//遍历链表找到不同trip的instance
			continue;

		total_weight += instance->weight;//统计instance的weight即权重
		total_instance++;//统计总的instance
	}

	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
		int percentage;
		struct thermal_cooling_device *cdev = instance->cdev;

		if (instance->trip != trip)
			continue;

		if (!total_weight)//总权重无效
			percentage = 100 / total_instance;//得到百分比
		else//总权重有效
			percentage = (instance->weight * 100) / total_weight;//则百分比由权重计算出,与权重相关

		instance->target = get_target_state(tz, cdev, percentage,
						    cur_trip_level);//计算目标等级,与百分比相关,即正常情况下与权重相关

		mutex_lock(&instance->cdev->lock);
		instance->cdev->updated = false;
		mutex_unlock(&instance->cdev->lock);
		thermal_cdev_update(cdev);
	}

	mutex_unlock(&tz->lock);
	return 0;
}

static struct thermal_governor thermal_gov_fair_share = {
	.name		= "fair_share",
	.throttle	= fair_share_throttle,
};

int thermal_gov_fair_share_register(void)
{
	return thermal_register_governor(&thermal_gov_fair_share);
}
static int get_trip_level(struct thermal_zone_device *tz)
{
	int count = 0;
	int trip_temp;
	enum thermal_trip_type trip_type;

	if (tz->trips == 0 || !tz->ops->get_trip_temp)//未实现get_trip_temp获取trips为0
		return 0;

	for (count = 0; count < tz->trips; count++) {//遍历trips
		tz->ops->get_trip_temp(tz, count, &trip_temp);//获取触发温度
		if (tz->temperature < trip_temp)
			break;
	}

	/*
	 * count > 0 only if temperature is greater than first trip
	 * point, in which case, trip_point = count - 1
	 */
	if (count > 0) {
		tz->ops->get_trip_type(tz, count - 1, &trip_type);//获取触发类型
		trace_thermal_zone_trip(tz, count - 1, trip_type);
	}

	return count;
}

static long get_target_state(struct thermal_zone_device *tz,
		struct thermal_cooling_device *cdev, int percentage, int level)
{
	unsigned long max_state;

	cdev->ops->get_max_state(cdev, &max_state);//得到最大等级

	return (long)(percentage * level * max_state) / (100 * tz->trips);//
}

fair_share为频率挡位较多的cooling device优先降频,频率挡位较多即trip多则权重就高,计算出的等级就高

2.2.4 bang_bang(drivers\thermal\gov_bang_bang.c)

static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
{
	int trip_temp, trip_hyst;
	struct thermal_instance *instance;

	tz->ops->get_trip_temp(tz, trip, &trip_temp);//获取目标温度

	if (!tz->ops->get_trip_hyst) {//如果没有实现get_trip_hyst
		pr_warn_once("Undefined get_trip_hyst for thermal zone %s - "
				"running with default hysteresis zero\n", tz->type);
		trip_hyst = 0;
	} else
		tz->ops->get_trip_hyst(tz, trip, &trip_hyst);//获取目标滞后

	dev_dbg(&tz->device, "Trip%d[temp=%d]:temp=%d:hyst=%d\n",
				trip, trip_temp, tz->temperature,
				trip_hyst);

	mutex_lock(&tz->lock);

	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
		if (instance->trip != trip)//遍历instance找到对应trip
			continue;

		/* in case fan is in initial state, switch the fan off */
		if (instance->target == THERMAL_NO_TARGET)//啥也不做
			instance->target = 0;//则为0

		/* in case fan is neither on nor off set the fan to active */
		if (instance->target != 0 && instance->target != 1) {//bang_bang只有0和1两种状态,0为关闭1为打开,如果非0非1
			pr_warn("Thermal instance %s controlled by bang-bang has unexpected state: %ld\n",
					instance->name, instance->target);
			instance->target = 1;//则为1
		}

		/*
		 * enable fan when temperature exceeds trip_temp and disable
		 * the fan in case it falls below trip_temp minus hysteresis
		 */
		if (instance->target == 0 && tz->temperature >= trip_temp)//没打开风扇且达到触发温度
			instance->target = 1;//则打开风扇
		else if (instance->target == 1 &&//打开风扇且温度小于触发温度减去滞后温度
				tz->temperature <= trip_temp - trip_hyst)
			instance->target = 0;//关闭风扇

		dev_dbg(&instance->cdev->device, "target=%d\n",
					(int)instance->target);

		mutex_lock(&instance->cdev->lock);
		instance->cdev->updated = false; /* cdev needs update */
		mutex_unlock(&instance->cdev->lock);
	}

	mutex_unlock(&tz->lock);
}


static int bang_bang_control(struct thermal_zone_device *tz, int trip)//风扇策略
{
	struct thermal_instance *instance;

	thermal_zone_trip_update(tz, trip);//先更新trip

	mutex_lock(&tz->lock);

	list_for_each_entry(instance, &tz->thermal_instances, tz_node)
		thermal_cdev_update(instance->cdev);//再更新cdev即cooling device

	mutex_unlock(&tz->lock);

	return 0;
}

static struct thermal_governor thermal_gov_bang_bang = {
	.name		= "bang_bang",
	.throttle	= bang_bang_control,
};

int thermal_gov_bang_bang_register(void)
{
	return thermal_register_governor(&thermal_gov_bang_bang);
}

bang_bang两点温度调节或风扇策略,如同风扇一样只有打开和关闭两个状态

2.2.5 power_allocator(drivers\thermal\power_allocator.c)

static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
{
	int ret;
	int switch_on_temp, control_temp;
	struct power_allocator_params *params = tz->governor_data;

	/*
	 * We get called for every trip point but we only need to do
	 * our calculations once
	 */
	if (trip != params->trip_max_desired_temperature)
		return 0;

	ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,
				     &switch_on_temp);//获取trip温度,作为switch_on触发温度,超过此温度governor就会打开
	if (!ret && (tz->temperature < switch_on_temp)) {
		tz->passive = 0;
		reset_pid_controller(params);//将PID控制器的累积误差、上一次的迭代错误写为0
		allow_maximum_power(tz);//分配最大可用功耗
		return 0;
	}

	tz->passive = 1;//passive为1表示温度已经达到了被动触发点,其他情况为0

	ret = tz->ops->get_trip_temp(tz, params->trip_max_desired_temperature,
				&control_temp);//获取trip温度,作为目标温度
	if (ret) {
		dev_warn(&tz->device,
			 "Failed to get the maximum desired temperature: %d\n",
			 ret);
		return ret;
	}

	return allocate_power(tz, control_temp);//主要的算法逻辑
}

static struct thermal_governor thermal_gov_power_allocator = {
	.name		= "power_allocator",
	.bind_to_tz	= power_allocator_bind,
	.unbind_from_tz	= power_allocator_unbind,
	.throttle	= power_allocator_throttle,
};

int thermal_gov_power_allocator_register(void)
{
	return thermal_register_governor(&thermal_gov_power_allocator);
}

void thermal_gov_power_allocator_unregister(void)
{
	thermal_unregister_governor(&thermal_gov_power_allocator);
static int allocate_power(struct thermal_zone_device *tz,
			  int control_temp)//IPA主要算法逻辑
{
	struct thermal_instance *instance;
	struct power_allocator_params *params = tz->governor_data;
	u32 *req_power, *max_power, *granted_power, *extra_actor_power;
	u32 *weighted_req_power;
	u32 total_req_power, max_allocatable_power, total_weighted_req_power;
	u32 total_granted_power, power_range;
	int i, num_actors, total_weight, ret = 0;
	int trip_max_desired_temperature = params->trip_max_desired_temperature;//最后被动触发温度

	mutex_lock(&tz->lock);

	num_actors = 0;
	total_weight = 0;
	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {//遍历所有instance
		if ((instance->trip == trip_max_desired_temperature) &&
		    cdev_is_power_actor(instance->cdev)) {//用功耗对cdev进行调整
			num_actors++;
			total_weight += instance->weight;//统计所有满足条件的actors数量、weight总数
		}
	}

	if (!num_actors) {
		ret = -ENODEV;
		goto unlock;
	}

	/*
	 * We need to allocate five arrays of the same size:
	 * req_power, max_power, granted_power, extra_actor_power and
	 * weighted_req_power.  They are going to be needed until this
	 * function returns.  Allocate them all in one go to simplify
	 * the allocation and deallocation logic.
	 */
	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*max_power));//BUILD_BUG_ON(condition)为真则编译报错
	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*granted_power));//此处为保证这4个参数大小一致
	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*extra_actor_power));
	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*weighted_req_power));
	req_power = kcalloc(num_actors * 5, sizeof(*req_power), GFP_KERNEL);//为5个num_actors各申请sizeof(*req_power)大小的内存
	if (!req_power) {
		ret = -ENOMEM;
		goto unlock;
	}

	max_power = &req_power[num_actors];//获取max_power地址
	granted_power = &req_power[2 * num_actors];//获取granted_power地址
	extra_actor_power = &req_power[3 * num_actors];//获取extra_actor_power地址
	weighted_req_power = &req_power[4 * num_actors];//获取weighted_req_power地址

	i = 0;
	total_weighted_req_power = 0;
	total_req_power = 0;
	max_allocatable_power = 0;

	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {//遍历所有instance(cooling devices)
		int weight;
		struct thermal_cooling_device *cdev = instance->cdev;

		if (instance->trip != trip_max_desired_temperature)//找到与最后被动触发相同温度的instance
			continue;

		if (!cdev_is_power_actor(cdev))//用功耗对cdev进行调整
			continue;

		if (cdev->ops->get_requested_power(cdev, tz, &req_power[i]))//获取需要的功耗保存在max_power里
			continue;

		if (!total_weight)
			weight = 1 << FRAC_BITS;//如果获取的weight总数为0,则weight为20
		else
			weight = instance->weight;//否则将当前instance的weight赋值给weight

		weighted_req_power[i] = frac_to_int(weight * req_power[i]);//获取cooling device的权重功耗(weight*max_power) >> 10

		if (power_actor_get_max_power(cdev, tz, &max_power[i]))//获取cdev可用消耗的最大功耗
			continue;

		total_req_power += req_power[i];//统计上面获取需要的功耗,即总的cooling device需要的功耗
		max_allocatable_power += max_power[i];//统计上面获取的可用最大功耗,即总的最大可分配功耗
		total_weighted_req_power += weighted_req_power[i];//统计上面获取的(weight*max_power) >> 10,即总的cooling device的权重功耗

		i++;
	}

	power_range = pid_controller(tz, control_temp, max_allocatable_power);//PID控制算法,power_range是当前温度下可支配的最大功耗

	divvy_up_power(weighted_req_power, max_power, num_actors,//公摊计算出当前温度下每个cooling device的最终的total_granted_power
		       total_weighted_req_power, power_range, granted_power,//total_granted_power=granted_power+extra_actor_power
		       extra_actor_power);

	total_granted_power = 0;
	i = 0;
	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {//遍历cooling device
		if (instance->trip != trip_max_desired_temperature)
			continue;

		if (!cdev_is_power_actor(instance->cdev))
			continue;

		power_actor_set_power(instance->cdev, instance,
				      granted_power[i]);//给cooling device设置granted_power
		total_granted_power += granted_power[i];//统计total_granted_power

		i++;
	}

	trace_thermal_power_allocator(tz, req_power, total_req_power,
				      granted_power, total_granted_power,
				      num_actors, power_range,
				      max_allocatable_power, tz->temperature,
				      control_temp - tz->temperature);

	kfree(req_power);
unlock:
	mutex_unlock(&tz->lock);

	return ret;
}
static int allocate_power(struct thermal_zone_device *tz,
			  int control_temp)//IPA主要算法逻辑
{
	struct thermal_instance *instance;
	struct power_allocator_params *params = tz->governor_data;
	u32 *req_power, *max_power, *granted_power, *extra_actor_power;
	u32 *weighted_req_power;
	u32 total_req_power, max_allocatable_power, total_weighted_req_power;
	u32 total_granted_power, power_range;
	int i, num_actors, total_weight, ret = 0;
	int trip_max_desired_temperature = params->trip_max_desired_temperature;//最后被动触发温度

	mutex_lock(&tz->lock);

	num_actors = 0;
	total_weight = 0;
	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {//遍历所有instance
		if ((instance->trip == trip_max_desired_temperature) &&
		    cdev_is_power_actor(instance->cdev)) {//用功耗对cdev进行调整
			num_actors++;
			total_weight += instance->weight;//统计所有满足条件的actors数量、weight总数
		}
	}

	if (!num_actors) {
		ret = -ENODEV;
		goto unlock;
	}

	/*
	 * We need to allocate five arrays of the same size:
	 * req_power, max_power, granted_power, extra_actor_power and
	 * weighted_req_power.  They are going to be needed until this
	 * function returns.  Allocate them all in one go to simplify
	 * the allocation and deallocation logic.
	 */
	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*max_power));//BUILD_BUG_ON(condition)为真则编译报错
	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*granted_power));//此处为保证这4个参数大小一致
	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*extra_actor_power));
	BUILD_BUG_ON(sizeof(*req_power) != sizeof(*weighted_req_power));
	req_power = kcalloc(num_actors * 5, sizeof(*req_power), GFP_KERNEL);//为5个num_actors各申请sizeof(*req_power)大小的内存
	if (!req_power) {
		ret = -ENOMEM;
		goto unlock;
	}

	max_power = &req_power[num_actors];//获取max_power地址
	granted_power = &req_power[2 * num_actors];//获取granted_power地址
	extra_actor_power = &req_power[3 * num_actors];//获取extra_actor_power地址
	weighted_req_power = &req_power[4 * num_actors];//获取weighted_req_power地址

	i = 0;
	total_weighted_req_power = 0;
	total_req_power = 0;
	max_allocatable_power = 0;

	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {//遍历所有instance(cooling devices)
		int weight;
		struct thermal_cooling_device *cdev = instance->cdev;

		if (instance->trip != trip_max_desired_temperature)//找到与最后被动触发相同温度的instance
			continue;

		if (!cdev_is_power_actor(cdev))//用功耗对cdev进行调整
			continue;

		if (cdev->ops->get_requested_power(cdev, tz, &req_power[i]))//获取需要的功耗保存在max_power里
			continue;

		if (!total_weight)
			weight = 1 << FRAC_BITS;//如果获取的weight总数为0,则weight为1 << 10
		else
			weight = instance->weight;//否则将当前instance的weight赋值给weight

		weighted_req_power[i] = frac_to_int(weight * req_power[i]);//获取cooling device的权重功耗(weight*max_power) >> 10

		if (power_actor_get_max_power(cdev, tz, &max_power[i]))//获取cdev可用消耗的最大功耗
			continue;

		total_req_power += req_power[i];//统计上面获取需要的功耗,即总的cooling device需要的功耗
		max_allocatable_power += max_power[i];//统计上面获取的可用最大功耗,即总的最大可分配功耗
		total_weighted_req_power += weighted_req_power[i];//统计上面获取的(weight*max_power) >> 10,即总的cooling device的权重功耗

		i++;
	}

	power_range = pid_controller(tz, control_temp, max_allocatable_power);//PID控制算法,power_range是当前温度下可支配的最大功耗

	divvy_up_power(weighted_req_power, max_power, num_actors,//公摊计算出当前温度下每个cooling device的最终的total_granted_power
		       total_weighted_req_power, power_range, granted_power,//total_granted_power=granted_power+extra_actor_power
		       extra_actor_power);

	total_granted_power = 0;
	i = 0;
	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {//遍历cooling device
		if (instance->trip != trip_max_desired_temperature)
			continue;

		if (!cdev_is_power_actor(instance->cdev))
			continue;

		power_actor_set_power(instance->cdev, instance,
				      granted_power[i]);//给cooling device设置granted_power
		total_granted_power += granted_power[i];//统计total_granted_power

		i++;
	}

	trace_thermal_power_allocator(tz, req_power, total_req_power,
				      granted_power, total_granted_power,
				      num_actors, power_range,
				      max_allocatable_power, tz->temperature,
				      control_temp - tz->temperature);

	kfree(req_power);
unlock:
	mutex_unlock(&tz->lock);

	return ret;
}
static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors,
			   u32 total_req_power, u32 power_range,
			   u32 *granted_power, u32 *extra_actor_power)//公摊计算出当前温度下cooling device最终total_granted_power
{
	u32 extra_power, capped_extra_power;
	int i;

	/*
	 * Prevent division by 0 if none of the actors request power.
	 */
	if (!total_req_power)//防止为0
		total_req_power = 1;

	capped_extra_power = 0;
	extra_power = 0;
	for (i = 0; i < num_actors; i++) {//遍历数组
		u64 req_range = (u64)req_power[i] * power_range;

		granted_power[i] = DIV_ROUND_CLOSEST_ULL(req_range,
							 total_req_power);//公式:四舍五入power_range * (weighted_req_power[i] / total_weighted_req_power)

		if (granted_power[i] > max_power[i]) {//分配的功耗不能大于最大功耗
			extra_power += granted_power[i] - max_power[i];//累加分配过多的功耗
			granted_power[i] = max_power[i];
		}

		extra_actor_power[i] = max_power[i] - granted_power[i];
		capped_extra_power += extra_actor_power[i];//记录每个申请者分配过多的功耗
	}

	if (!extra_power)//如果没有分配过多的功耗说明此时分配ok
		return;//否则return

	/*
	 * Re-divvy the reclaimed extra among actors based on
	 * how far they are from the max
	 */
	extra_power = min(extra_power, capped_extra_power);//重新分配额外功耗
	if (capped_extra_power > 0)
		for (i = 0; i < num_actors; i++)
			granted_power[i] += (extra_actor_power[i] *
					extra_power) / capped_extra_power;
}

此策略会获取switch_on温度作为此governor开关的判断,获取target温度,作为目标温度,策略的目的就是让温度维持在目标温度;首先得到此温度下能分配的最大功耗,计算每个cooling device的weight权重

通过PID相加得到可分配的功耗,按照每个cooling device的权重分配

P: p = mul_frac(err < 0 ? tz->tzp->k_po : tz->tzp->k_pu, err);//control_temp大于目标温度使用k_pu,否则使用k_po

//k_po = int_to_frac(sustainable_power / (control_temp - switch_on,k_pu = int_to_frac(2*sustainable_power / (control_temp - switch_on)

I: i = mul_frac(tz->tzp->k_i, params->err_integral);//计算积分项     ,公式:K_i*err_integral(差值的累加),默认:K_i = int_to_frac(10 / 1000)

D: d = mul_frac(tz->tzp->k_d, err - params->prev_err);//计算微分项,公式:K_d*(err - prev_err) / passive_delay,默认:K_d = 0

然后判断分配的功耗与可分配的最大功耗之前是否有差异,如果大于可分配的最大功耗就统计多出来的部分,再按照权重进行分配一次,所以每个cooling device可分配到的功耗就为

Pgranted_i + Pextra_granted_i,这个策略保证在目标温度下能极可能分配多的功耗,保证了性能和温升的需求

2.2.6 user_space

static int notify_user_space(struct thermal_zone_device *tz, int trip)
{
	char *thermal_prop[5];
	int i;

	mutex_lock(&tz->lock);//上锁
	thermal_prop[0] = kasprintf(GFP_KERNEL, "NAME=%s", tz->type);
	thermal_prop[1] = kasprintf(GFP_KERNEL, "TEMP=%d", tz->temperature);
	thermal_prop[2] = kasprintf(GFP_KERNEL, "TRIP=%d", trip);
	thermal_prop[3] = kasprintf(GFP_KERNEL, "EVENT=%d", tz->notify_event);
	thermal_prop[4] = NULL;
	kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, thermal_prop);//将上述参数发送出去
	for (i = 0; i < 4; ++i)
		kfree(thermal_prop[i]);//释放指针
	mutex_unlock(&tz->lock);//解锁
	return 0;
}

static struct thermal_governor thermal_gov_user_space = {
	.name		= "user_space",
	.throttle	= notify_user_space,
};

int thermal_gov_user_space_register(void)
{
	return thermal_register_governor(&thermal_gov_user_space);
}

user_space策略主要是将温控相关参数传给用户空间,由用户空间指定对应策略

2.3 class_register

调用的是__class_register

#define class_register(class)			\
({						\
	static struct lock_class_key __key;	\
	__class_register(class, &__key);	\
})
int __class_register(struct class *cls, struct lock_class_key *key)//cls指向"thermal"
{
	struct subsys_private *cp;
	int error;

	pr_debug("device class '%s': registering\n", cls->name);

	cp = kzalloc(sizeof(*cp), GFP_KERNEL);//申请内存
	if (!cp)//内存申请失败
		return -ENOMEM;
	klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);//初始化klist
	INIT_LIST_HEAD(&cp->interfaces);//初始化interfaces链表
	kset_init(&cp->glue_dirs);//初始化kset数据结构
	__mutex_init(&cp->mutex, "subsys mutex", key);//初始化互斥体
	error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);//给内核对象kobject设置名字,相当于在/sys/class目录下创建一个名称为cls->name的文件夹
	if (error) {
		kfree(cp);
		return error;
	}

	/* set the default /sys/dev directory for devices of this class */
	if (!cls->dev_kobj)
		cls->dev_kobj = sysfs_dev_char_kobj;//默认sys/dev路径

#if defined(CONFIG_BLOCK)
	/* let the block class directory show up in the root of sysfs */
	if (!sysfs_deprecated || cls != &block_class)
		cp->subsys.kobj.kset = class_kset;
#else
	cp->subsys.kobj.kset = class_kset;
#endif
	cp->subsys.kobj.ktype = &class_ktype;
	cp->class = cls;
	cls->p = cp;

	error = kset_register(&cp->subsys);//初始化并添加一个kset
	if (error) {
		kfree(cp);
		return error;
	}
	error = class_add_groups(class_get(cls), cls->class_groups);//给定目录kobject,创建对应属性组
	class_put(cls);//递减kobj内核对象的引用计数 当为0的时候调用在kobject_init()中传入的kobj_type{}结构中包含的kobj释放函数
	if (error) {
		kobject_del(&cp->subsys.kobj);//取消链接object
		kfree_const(cp->subsys.kobj.name);//释放内存
		kfree(cp);//释放指针
	}
	return error;
}
EXPORT_SYMBOL_GPL(__class_register);
int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
{//在C中,当无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表
	va_list vargs;
	int retval;

	va_start(vargs, fmt);//Va_start相关宏获取省略号指定的参数
	retval = kobject_set_name_vargs(kobj, fmt, vargs);
	va_end(vargs);//释放指针

	return retval;
}
EXPORT_SYMBOL(kobject_set_name);

2.4 of_parse_thermal_zones

int __init of_parse_thermal_zones(void)//解析dtsi中&thermal_zones并注册thermal_zone_device
{
	struct device_node *np, *child;
	struct __thermal_zone *tz;
	struct thermal_zone_device_ops *ops;

	np = of_find_node_by_name(NULL, "thermal-zones");//通过名称thermal-zones查找节点
	//thermal_zones下每一个子节点都是一个thermal,在/sys/class/thermal下对应一个thermal_zoneX目录,ntc的也在里面
	if (!np) {
		pr_debug("unable to find thermal zones\n");
		return 0; /* Run successfully on systems without thermal DT */ //即便dts里没有thermal-zones结点也允许thermal core跑起来
	}

	for_each_available_child_of_node(np, child) {//遍历所有子节点
		struct thermal_zone_device *zone;
		struct thermal_zone_params *tzp;
		int i, mask = 0;
		u32 prop;

		tz = thermal_of_build_thermal_zone(child);//创建一个thermal zone节点
		if (IS_ERR(tz)) {
			pr_err("failed to build thermal zone %s: %ld\n",
			       child->name,
			       PTR_ERR(tz));
			continue;
		}

		ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL);//新申请一段内存,将of_thermal_ops内容复制到新申请的内存中
		if (!ops)
			goto exit_free;

		tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);//申请内存
		if (!tzp) {
			kfree(ops);
			goto exit_free;
		}

		/* No hwmon because there might be hwmon drivers registering */
		tzp->no_hwmon = true;//不创建hwmon

		if (!of_property_read_u32(child, "sustainable-power", &prop))//解析sustainable-power字段
			tzp->sustainable_power = prop;//读出来写到sustainable_power中

		for (i = 0; i < tz->ntrips; i++)
			mask |= 1 << i;

		/* these two are left for temperature drivers to use */
		tzp->slope = tz->slope;//温度调整曲线的斜率
		tzp->offset = tz->offset;//温度调整曲线的偏移量

		zone = thermal_zone_device_register(child->name, tz->ntrips,//向thermal_core注册thermal_zone_devices并绑定cool device
						    mask, tz,
						    ops, tzp,
						    tz->passive_delay,
						    tz->polling_delay);
		if (IS_ERR(zone)) {
			pr_err("Failed to build %s zone %ld\n", child->name,
			       PTR_ERR(zone));
			kfree(tzp);
			kfree(ops);
			of_thermal_free_zone(tz);
			/* attempting to build remaining zones still */
		}
	}
	of_node_put(np);

	return 0;

exit_free:
	of_node_put(child);
	of_node_put(np);
	of_thermal_free_zone(tz);

	/* no memory available, so free what we have built */
	of_thermal_destroy_zones();

	return -ENOMEM;
}
struct device_node *of_find_node_by_name(struct device_node *from,
	const char *name)
{
	struct device_node *np;
	unsigned long flags;

	raw_spin_lock_irqsave(&devtree_lock, flags);//上锁
	for_each_of_allnodes_from(from, np)
		if (np->name && (of_node_cmp(np->name, name) == 0)//按name查找节点
		    && of_node_get(np))//增加节点的引用计数
			break;
	of_node_put(from);//减少节点的引用计数
	raw_spin_unlock_irqrestore(&devtree_lock, flags);//解锁
	return np;
}
EXPORT_SYMBOL(of_find_node_by_name);
static struct __thermal_zone
__init *thermal_of_build_thermal_zone(struct device_node *np)//创建一个thermal_zone节点
{
	struct device_node *child = NULL, *gchild;
	struct __thermal_zone *tz;
	int ret, i;
	u32 prop, coef[2];

	if (!np) {
		pr_err("no thermal zone np\n");
		return ERR_PTR(-EINVAL);
	}

	tz = kzalloc(sizeof(*tz), GFP_KERNEL);//申请内存
	if (!tz)
		return ERR_PTR(-ENOMEM);

	ret = of_property_read_u32(np, "polling-delay-passive", &prop);//解析polling-delay-passive,超过阀值轮询时间
	//读取np结点中的propname属性的值,并将读取到的u32类型的值保存在out_value指向的内存中,函数的返回值表示读取到的u32类型的数据的个数
	if (ret < 0) {
		pr_err("missing polling-delay-passive property\n");
		goto free_tz;
	}
	tz->passive_delay = prop;

	ret = of_property_read_u32(np, "polling-delay", &prop);//解析polling-delay,未超过阀值轮询时间
	if (ret < 0) {
		pr_err("missing polling-delay property\n");
		goto free_tz;
	}
	tz->polling_delay = prop;

	/*
	 * REVIST: for now, the thermal framework supports only
	 * one sensor per thermal zone. Thus, we are considering
	 * only the first two values as slope and offset.
	 */
	ret = of_property_read_u32_array(np, "coefficients", coef, 2);//读取属性中u32类型的数组数据,解析coefficients
	if (ret == 0) {
		tz->slope = coef[0];//slope斜率
		tz->offset = coef[1];//offset偏移量
	} else {
		tz->slope = 1;
		tz->offset = 0;
	}

	/* trips */
	child = of_get_child_by_name(np, "trips");//查找trips字段

	/* No trips provided */
	if (!child)
		goto finish;

	tz->ntrips = of_get_child_count(child);//获取子节点数量
	if (tz->ntrips == 0) /* must have at least one child */
		goto finish;

	tz->trips = kcalloc(tz->ntrips, sizeof(*tz->trips), GFP_KERNEL);//申请内存
	if (!tz->trips) {
		ret = -ENOMEM;
		goto free_tz;
	}

	i = 0;
	for_each_child_of_node(child, gchild) {
		ret = thermal_of_populate_trip(gchild, &tz->trips[i++]);//遍历解析trip字段下面的字段
		if (ret)
			goto free_trips;
	}

	of_node_put(child);//减少节点计数

	/* cooling-maps */
	child = of_get_child_by_name(np, "cooling-maps");//查找cooling-maps字段

	/* cooling-maps not provided */
	if (!child)
		goto finish;

	tz->num_tbps = of_get_child_count(child);
	if (tz->num_tbps == 0)
		goto finish;

	tz->tbps = kcalloc(tz->num_tbps, sizeof(*tz->tbps), GFP_KERNEL);
	if (!tz->tbps) {
		ret = -ENOMEM;
		goto free_trips;
	}

	i = 0;
	for_each_child_of_node(child, gchild) {//遍历解析cooling-maps下面字段,绑定cooling device
		ret = thermal_of_populate_bind_params(gchild, &tz->tbps[i++],
						      tz->trips, tz->ntrips);
		if (ret)
			goto free_tbps;
	}

finish:
	of_node_put(child);
	tz->mode = THERMAL_DEVICE_DISABLED;

	return tz;

free_tbps:
	for (i = i - 1; i >= 0; i--)
		of_node_put(tz->tbps[i].cooling_device);
	kfree(tz->tbps);
free_trips:
	for (i = 0; i < tz->ntrips; i++)
		of_node_put(tz->trips[i].np);
	kfree(tz->trips);
	of_node_put(gchild);
free_tz:
	kfree(tz);
	of_node_put(child);

	return ERR_PTR(ret);
}
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)//注册一个thermal_zone_device
{
	struct thermal_zone_device *tz;
	enum thermal_trip_type trip_type;
	int trip_temp;
	int result;
	int count;
	struct thermal_governor *governor;

	if (!type || strlen(type) == 0)
		return ERR_PTR(-EINVAL);

	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
		return ERR_PTR(-EINVAL);

	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
		return ERR_PTR(-EINVAL);

	if (!ops)
		return ERR_PTR(-EINVAL);

	if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp))
		return ERR_PTR(-EINVAL);

	tz = kzalloc(sizeof(*tz), GFP_KERNEL);
	if (!tz)
		return ERR_PTR(-ENOMEM);

	
	INIT_LIST_HEAD(&tz->thermal_instances);//初始化一个链表thermal_instances
	ida_init(&tz->ida);//初始化冷却设备唯一ID
	mutex_init(&tz->lock);//初始化互斥锁
	
	result = ida_simple_get(&thermal_tz_ida, 0, 0, GFP_KERNEL);//自动分配id
	if (result < 0)
		goto free_tz;

	tz->id = result;
	strlcpy(tz->type, type, sizeof(tz->type));
	tz->ops = ops;
	tz->tzp = tzp;
	tz->device.class = &thermal_class;
	tz->devdata = devdata;
	tz->trips = trips;
	tz->passive_delay = passive_delay;
	tz->polling_delay = polling_delay;

	/* sys I/F */
	/* Add nodes that are always present via .groups */
	result = thermal_zone_create_device_groups(tz, mask);//添加节点
	if (result)
		goto remove_id;

	/* A new thermal zone needs to be updated anyway. */
	atomic_set(&tz->need_update, 1);//设置原子变量的值

	dev_set_name(&tz->device, "thermal_zone%d", tz->id);//设置thermal_zone节点名称
	result = device_register(&tz->device);//注册设备
	if (result)
		goto remove_device_groups;

	for (count = 0; count < trips; count++) {
		if (tz->ops->get_trip_type(tz, count, &trip_type))//获取trip类型
			set_bit(count, &tz->trips_disabled);
		if (tz->ops->get_trip_temp(tz, count, &trip_temp))//获取trip温度
			set_bit(count, &tz->trips_disabled);//将tz->trips_disabled第count位设置为1
		/* Check for bogus trip points */
		if (trip_temp == 0)
			set_bit(count, &tz->trips_disabled);
	}

	/* Update 'this' zone's governor information */
	mutex_lock(&thermal_governor_lock);
	
	if (tz->tzp)
		governor = __find_governor(tz->tzp->governor_name);//thermal_zone设置governor,否则默认governor
	else
		governor = def_governor;

	result = thermal_set_governor(tz, governor);//切换新的governor
	if (result) {
		mutex_unlock(&thermal_governor_lock);
		goto unregister;
	}

	mutex_unlock(&thermal_governor_lock);

	if (!tz->tzp || !tz->tzp->no_hwmon) {
		result = thermal_add_hwmon_sysfs(tz);//判断是否需要添加hwmon,如是则添加上
		if (result)
			goto unregister;
	}

	mutex_lock(&thermal_list_lock);
	list_add_tail(&tz->node, &thermal_tz_list);//将thermal zone加入到thermal_tz_list
	mutex_unlock(&thermal_list_lock);
	/* Bind cooling devices for this zone */
	bind_tz(tz);//将thermal_cdev_list上的cooling设备绑定到thermal_zone_device上

	INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);//初始化work quene下半部分,处理中断需要响应的操作,定时去调用thermal_zone_device_update
	//设置polling_delay值为轮询周期
	thermal_zone_device_reset(tz);//对thermal zone的温度等复位
	/* Update the new thermal zone and mark it as already updated. */
	if (atomic_cmpxchg(&tz->need_update, 1, 0))
		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);

	return tz;

unregister:
	ida_simple_remove(&thermal_tz_ida, tz->id);
	device_unregister(&tz->device);
	return ERR_PTR(result);

remove_device_groups:
	thermal_zone_destroy_device_groups(tz);
remove_id:
	ida_simple_remove(&thermal_tz_ida, tz->id);
free_tz:
	kfree(tz);
	return ERR_PTR(result);
}
EXPORT_SYMBOL_GPL(thermal_zone_device_register);

从上面代码中可以看出解析dts就是匹配对应字段,然后复制给结构体对应成员

下面给出dts配置中字段的含义

thermal dts配置说明
thermal_zones: thermal-zones {//一个节点对应一个thermal zone,并包含温控策略相关参数
	soc_thermal: soc-thermal {
		polling-delay-passive = <20>;//温度高于trip-point-0指定的值即发生温控时的轮询周期,每隔20ms获取一次温度
		polling-delay = <1000>;//温度低于trip-point-0指定的值即未发生温控时的轮询周期,每隔1000ms获取一次温度
		sustainable-power = <1000>;//温度等于trip-point-1指定的值时,系统分配给cooling device的能量
		thermal-sensors = <&tsadc 0>;//当前thermal zone通过tsadc0获取温度,使用的是tsadc的通道0
 
		trips {//trips包含不同温度阈值,不同的温控策略,配置不一定相同
			threshold: trip-point-0 {
				temperature = <70000>;//超过70摄氏度,温控策略开始工作
				hysteresis = <2000>;//温度低于70-2=68度时,温控停止工作
				type = "passive";//表示超过该温度值时,使用polling-delay-passive
			};
 
			target: trip-point-1 {//温控目标温度,期望通过降频使得芯片不超过该值
				temperature = <85000>;//期望通过降频使得芯片不超过85摄氏度
				hysteresis = <2000>;//
				type = "passive";//表示超过该温度值时,使用polling-delay-passive
			};

			soc_crit: soc-crit {//过温保护阈值,如果降频后温度仍然上升,那么超过该值后,让系统重启
				temperature = <115000>;//超过115摄氏度重启
				hysteresis = <2000>;
				type = "critical";//表示超过该温度值时,重启
			};
		};
 
		cooling-maps {//cooling device配置节点,每个子节点代表一个cooling device
			map0 {
				trip = <&target>;//表示在target trip下,该cooling device才起作用,对于power allocater策略必须填target
				cooling-device = <&cpu_l0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;//对应的真正执行冷却操作的设备及最大/最小状态,THERMAL_NO_LIMIT不起作用
				contribution = <4096>;//计算功耗时乘以4096/1024倍,用于调整降频顺序和尺度
			};
 
			map1 {
				trip = <&target>;
				cooling-device = <&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
				contribution = <1024>;
			};
 
			map2 {
				trip = <&target>;
				cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
				contribution = <4096>;
			};
		};
	};
 
	gpu_thermal: gpu-thermal {//一个节点对应一个thermal zone,并包含温控策略相关参数,当前thermal zone只用于获取温度
		polling-delay-passive = <100>; /* milliseconds */
		polling-delay = <1000>; /* milliseconds */
		thermal-sensors = <&tsadc 1>;
	};
};

参考:万字长文 | Thermal框架源码剖析

Linux Thermal机制源码分析之Thermal zone_linux thermal zone_不捡风筝的玖伍贰柒的博客-CSDN博客

本文标签: LinuxThermal