linux thermal framework(3)_thermal cooling device
作者:huowj 发布于:2025-4-14 10:33 分类:电源管理子系统
1. 介绍
linux使用thermal cooling device来描述一个平台上可以降温的设备。
2. thermal cooling device相关的API以及功能分析
2.1 struct thermal_cooling_device
一个thermal cooling device是用struct thermal_cooling_device来表示的
struct thermal_cooling_device { int id; const char *type; unsigned long max_state; struct device device; struct device_node *np; void *devdata; void *stats; const struct thermal_cooling_device_ops *ops; bool updated; /* true if the cooling device does not need update */ struct mutex lock; /* protect thermal_instances list */ struct list_head thermal_instances; struct list_head node; #ifdef CONFIG_THERMAL_DEBUGFS struct thermal_debugfs *debugfs; #endif };
max_state,这个cooling_device最大state的索引
thermal_instances, 这个节点和struct thermal_instance有关,我们之前说过,对thermal zone的某一个passive or active类型的trip,会有cooling device的策略介入,那么struct thermal_instance就是作为连接trip和相应的cooling device的,struct thermal_instance的定义如下:
/* * This structure is used to describe the behavior of * a certain cooling device on a certain trip point * in a certain thermal zone */ struct thermal_instance { int id; char name[THERMAL_NAME_LENGTH]; struct thermal_cooling_device *cdev; const struct thermal_trip *trip; bool initialized; unsigned long upper; /* Highest cooling state for this trip point */ unsigned long lower; /* Lowest cooling state for this trip point */ unsigned long target; /* expected cooling state */ char attr_name[THERMAL_NAME_LENGTH]; struct device_attribute attr; char weight_attr_name[THERMAL_NAME_LENGTH]; struct device_attribute weight_attr; struct list_head trip_node; /* node in trip->thermal_instances */ struct list_head cdev_node; /* node in cdev->thermal_instances */ unsigned int weight; /* The weight of the cooling device */ bool upper_no_limit; };
1)注释:thermal_instance是用来描述一个cooling deivce在某一个thermal zone的一个trip上的行为
2)id, 这个thermal instance的编号
3)name, 这个thermal instance的名字
4)cdev,和这个thermal instance相关的cooling device
5)trip, 和这个thermal instance相关的trip
6)initialized, 是否初始化
7)upper/lower/targe, 这个trip对应的最高/最低/期望state
8)attr/attr_name, 属性一般为trip id
9)weight/weight_attr/weight_attr_name, weight是这个cooling_device在这个trip所占的比重
我们在下面的章节具体讲一下这个结构体是如何被管理的
2.2 thermal_cooling_device的注册
和thermal zone一样,cooling device也不是一个实际存在的物理设备,是由linux抽象出来表示一类可降温的设备,这些设备可以有cpufreq(通过限制cpu频率来降低cpu温度)、devfreq(通过限制设备频率来降低设备温度)、cpuidle(通过进入低功耗模式的idle来降低cpu温度),同样的,cooling device也是通过cpufreq/devfreq/cpuidle这些设备注册的时候,向thermal core注册的。我们以cpufreq为例来描述详细的注册过程。
和thermal zone一样,我们也通过dts中一个实际的例子来描述cooling device注册,这里再次使用mt8195.dtsi中的cpu作为例子,以下是cpu0的thermal_zone节点,只保留了cooling-map相关的信息:
thermal_zones: thermal-zones { cpu0-thermal { ... trips { cpu0_alert: trip-alert { temperature = <85000>; hysteresis = <2000>; type = "passive"; }; cpu0_crit: trip-crit { temperature = <100000>; hysteresis = <2000>; type = "critical"; }; }; cooling-maps { map0 { trip = <&cpu0_alert>; cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; ... other thermal zones }
cpu0-thermal只有一个cooling-map,即map0,map0对应的trip是类型为passive的trip-alert,他的cooling-device引用了四个cpu,我们看下相同dts中的cpu0的节点描述:
cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x000>; enable-method = "psci"; performance-domains = <&performance 0>; clock-frequency = <1701000000>; capacity-dmips-mhz = <308>; cpu-idle-states = <&cpu_ret_l &cpu_off_l>; i-cache-size = <32768>; i-cache-line-size = <64>; i-cache-sets = <128>; d-cache-size = <32768>; d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; #cooling-cells = <2>; };
cpu0使用cooling-cells来描述使用几个u32来引用这个cooling device。
cpu的cooling device是在cpufreq policy初始化的时候通过调用of_cpufreq_cooling_register向thermal core注册的,这个函数会判断dts中是否有cooling-cells节点,如果存在的话,会调用__cpufreq_cooling_register
/** * thermal_bind_cdev_to_trip - bind a cooling device to a thermal zone * @tz: pointer to struct thermal_zone_device * @td: descriptor of the trip point to bind @cdev to * @cdev: pointer to struct thermal_cooling_device * @cool_spec: cooling specification for the trip point and @cdev * * This interface function bind a thermal cooling device to the certain trip * point of a thermal zone device. * This function is usually called in the thermal zone device .bind callback. * * Return: 0 on success, the proper error value otherwise. */ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz, struct thermal_trip_desc *td, struct thermal_cooling_device *cdev, struct cooling_spec *cool_spec) { struct thermal_instance *dev; bool upper_no_limit; int result; /* lower default 0, upper default max_state */ if (cool_spec->lower == THERMAL_NO_LIMIT) cool_spec->lower = 0; if (cool_spec->upper == THERMAL_NO_LIMIT) { cool_spec->upper = cdev->max_state; upper_no_limit = true; } else { upper_no_limit = false; } if (cool_spec->lower > cool_spec->upper || cool_spec->upper > cdev->max_state) return -EINVAL; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; dev->cdev = cdev; dev->trip = &td->trip; dev->upper = cool_spec->upper; dev->upper_no_limit = upper_no_limit; dev->lower = cool_spec->lower; dev->target = THERMAL_NO_TARGET; dev->weight = cool_spec->weight; result = ida_alloc(&tz->ida, GFP_KERNEL); if (result < 0) goto free_mem; dev->id = result; sprintf(dev->name, "cdev%d", dev->id); result = sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name); if (result) goto release_ida; snprintf(dev->attr_name, sizeof(dev->attr_name), "cdev%d_trip_point", dev->id); sysfs_attr_init(&dev->attr.attr); dev->attr.attr.name = dev->attr_name; dev->attr.attr.mode = 0444; dev->attr.show = trip_point_show; result = device_create_file(&tz->device, &dev->attr); if (result) goto remove_symbol_link; snprintf(dev->weight_attr_name, sizeof(dev->weight_attr_name), "cdev%d_weight", dev->id); sysfs_attr_init(&dev->weight_attr.attr); dev->weight_attr.attr.name = dev->weight_attr_name; dev->weight_attr.attr.mode = S_IWUSR | S_IRUGO; dev->weight_attr.show = weight_show; dev->weight_attr.store = weight_store; result = device_create_file(&tz->device, &dev->weight_attr); if (result) goto remove_trip_file; result = thermal_instance_add(dev, cdev, td); if (result) goto remove_weight_file; thermal_governor_update_tz(tz, THERMAL_TZ_BIND_CDEV); return 0; remove_weight_file: device_remove_file(&tz->device, &dev->weight_attr); remove_trip_file: device_remove_file(&tz->device, &dev->attr); remove_symbol_link: sysfs_remove_link(&tz->device.kobj, dev->name); release_ida: ida_free(&tz->ida, dev->id); free_mem: kfree(dev); return result; }
1)注释:这个接口将一个cooling device和一个thermal zone的某个固定的trip进行绑定
2)初始化一个thermal_instance,通过向它属于的thermal zone申请一个id,这个instance就叫做cdev+id,并在这个thermal zone的目录下面创建一个软连接,名字就是instance的名字,指向对应的cooling_device目录
3)初始化这个instance的attr和weight_attr,分别叫做cdev+id_trip_point和cdev+id_weight,并在这个thermal zone的目录下创建对应的文件
4)最后将这个instance分别加入thermal trip desc和cooling device的相应链表中
至此,thermal zone,trip,cooling device之间的关如下图,一个thermal zone包含若干个trip,thermal zone用数组来管理它的trip,一个trip可以对应若干个cooling device,一个cooling device也可以map若干个不同thermal zone的trip,trip和cooling device的对应关系通过thermal instance来描述
一个有两个trip的thermal zone的sysfs目录中trip相关的文件如下:
/sys/class/thermal/thermal_zone0 # ls -al
cdev0 -> ../cooling_device0
cdev0_trip_point
cdev0_weight
cdev1 -> ../cooling_device1
cdev1_trip_point
cdev1_weight

功能
最新评论
- wangjing
写得太好了 - wangjing
写得太好了! - DRAM
圖面都沒辦法顯示出來好像掛點了。 - Simbr
bus至少是不是还有个subsystem? - troy
@testtest:只要ldrex-modify-strex... - gh
Linux 内核在 sparse 内存模型基础上实现了vme...
文章分类
随机文章
文章存档
- 2025年4月(5)
- 2024年2月(1)
- 2023年5月(1)
- 2022年10月(1)
- 2022年8月(1)
- 2022年6月(1)
- 2022年5月(1)
- 2022年4月(2)
- 2022年2月(2)
- 2021年12月(1)
- 2021年11月(5)
- 2021年7月(1)
- 2021年6月(1)
- 2021年5月(3)
- 2020年3月(3)
- 2020年2月(2)
- 2020年1月(3)
- 2019年12月(3)
- 2019年5月(4)
- 2019年3月(1)
- 2019年1月(3)
- 2018年12月(2)
- 2018年11月(1)
- 2018年10月(2)
- 2018年8月(1)
- 2018年6月(1)
- 2018年5月(1)
- 2018年4月(7)
- 2018年2月(4)
- 2018年1月(5)
- 2017年12月(2)
- 2017年11月(2)
- 2017年10月(1)
- 2017年9月(5)
- 2017年8月(4)
- 2017年7月(4)
- 2017年6月(3)
- 2017年5月(3)
- 2017年4月(1)
- 2017年3月(8)
- 2017年2月(6)
- 2017年1月(5)
- 2016年12月(6)
- 2016年11月(11)
- 2016年10月(9)
- 2016年9月(6)
- 2016年8月(9)
- 2016年7月(5)
- 2016年6月(8)
- 2016年5月(8)
- 2016年4月(7)
- 2016年3月(5)
- 2016年2月(5)
- 2016年1月(6)
- 2015年12月(6)
- 2015年11月(9)
- 2015年10月(9)
- 2015年9月(4)
- 2015年8月(3)
- 2015年7月(7)
- 2015年6月(3)
- 2015年5月(6)
- 2015年4月(9)
- 2015年3月(9)
- 2015年2月(6)
- 2015年1月(6)
- 2014年12月(17)
- 2014年11月(8)
- 2014年10月(9)
- 2014年9月(7)
- 2014年8月(12)
- 2014年7月(6)
- 2014年6月(6)
- 2014年5月(9)
- 2014年4月(9)
- 2014年3月(7)
- 2014年2月(3)
- 2014年1月(4)
发表评论: