当前位置: 首页 > news >正文

linux thermal framework(3)_thermal cooling device

原文:蜗窝科技linux thermal framework(3)_thermal cooling device

1. 介绍

linux使用thermal cooling device来描述一个平台上可以降温的设备。

2. thermal cooling device相关的API以及功能分析

一个thermal cooling device是用struct thermal_cooling_device来表示的

truct thermal_cooling_device {    //1)id,同样的,每个cooling device都有一个id作为区分,这个id也是在注册的时候通过ida分配    int id;    //2)type,用来说明描述的哪一种类型的cooling device,一般这个type会有cpufreq/devfreq等    char *type;    //3)max_state,cooling device会有若干个state,governor通过不断的调整这些state来控制温度    unsigned long max_state;    //4)device,cooling device也是一个抽象出来的设备,因此有一个device数据结构    struct device device;    struct device_node *np;    void *devdata;    void *stats;    //5)ops,这个cooling device的回调函数    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;    ANDROID_KABI_RESERVE(1);};

max_state,这个cooling_device最大state的索引

t hermal_instances, 这个节点和struct thermal_instance有关,我们之前说过,对thermal zone的某一个passive or active类型的trip,会有cooling device的策略介入,那么struct thermal_instance就是作为连接trip和相应的cooling device的,struct thermal_instance的定义如下:

alps/kernel-6.6/drivers/thermal/thermal_core.h

​​​​​​​

/* * This structure is used to describe the behavior of * a certain cooling device on a certain trip point * in a certain thermal zone * thermal_instance 用于描述特定散热设备在特定温控区域(thermal zone) * 的特定触发点(trip point)上的行为表现 */struct thermal_instance {    /* 标识符 */    int id;                         // 实例ID,唯一标识该thermal_instance    char name[THERMAL_NAME_LENGTH]; // 实例名称,用于调试和日志记录    /* 关联设备 */    struct thermal_zone_device *tz; // 所属温控区域设备指针    struct thermal_cooling_device *cdev; // 关联的散热设备指针    const struct thermal_trip *trip;    // 关联的温度触发点指针    /* 状态标志 */    bool initialized;               // 初始化状态标记    /* 散热状态范围控制 */    unsigned long upper;            // 该触发点允许的最高散热状态(冷却等级)    unsigned long lower;            // 该触发点允许的最低散热状态    unsigned long target;           // 当前目标散热状态(期望值)    /* sysfs 接口 */    char attr_name[THERMAL_NAME_LENGTH];         // 属性文件名(通常以trip ID命名)    struct device_attribute attr;                // 设备属性(用于暴露到sysfs)    char weight_attr_name[THERMAL_NAME_LENGTH];  // 权重属性文件名    struct device_attribute weight_attr;         // 权重属性(sysfs可调节参数)    /* 链表管理 */    struct list_head tz_node;        // 温控区域实例链表节点    struct list_head cdev_node;      // 散热设备实例链表节点    /* 权重配置 */    unsigned int weight;             // 该散热设备在当前触发点的权重值(0-100)                                    // 用于多散热设备协同工作时分配散热负载比例    /* 特殊模式 */    bool upper_no_limit;             // 是否禁用散热状态上限(允许最大冷却能力)};

核心功能:

1.实现温控区域(thermal zone)、触发点(trip point)和散热设备(cooling device)的三者关联

2.通过upper/lower/target实现散热状态的闭环控制

关键设计:

1.权重机制(weight):支持多散热设备按比例分配散热任务

2.无上限模式(upper_no_limit):紧急情况下允许散热设备全速运行

我们在下面的章节具体讲一下这个结构体是如何被管理的

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相关的信息:

/kernel/kernel-6.6/arch/arm64/boot/dts/mediatek/mt8195.dtsi​​​​

thermal_zones: thermal-zones {  // 定义所有温控区域(thermal zones)的父节点    cpu0-thermal {  // 定义CPU0温控区域        polling-delay = <1000>;  // 主动轮询间隔(单位:毫秒),当温度超过触发点时使用        polling-delay-passive = <250>;  // 被动轮询间隔(单位:毫秒),用于温度接近触发点时的监控        // 指定该温控区域使用的温度传感器        // &lvts_mcu: 引用之前定义的LVTS传感器节点        // MT8195_MCU_LITTLE_CPU0: 传递给传感器的参数,标识具体监控的CPU核心        thermal-sensors = <&lvts_mcu MT8195_MCU_LITTLE_CPU0>;        // 定义温度触发点(trip points)        trips {            // 警告级触发点(被动冷却)            cpu0_alert: trip-alert {                temperature = <85000>;  // 触发温度(单位:毫摄氏度,即85°C)                hysteresis = <2000>;    // 滞后温度(2°C),避免温度在临界点附近频繁切换状态                type = "passive";       // 触发类型:被动冷却(通过降频等方式降温)            };            // 临界级触发点(紧急处理)            cpu0_crit: trip-crit {                temperature = <100000>;  // 临界温度(100°C)                hysteresis = <2000>;     // 滞后温度(2°C)                type = "critical";       // 触发类型:临界状态(可能触发硬件保护或系统关机)            };        };        // 定义冷却设备映射关系        cooling-maps {            // 映射0:关联触发点和冷却设备            map0 {                trip = <&cpu0_alert>;  // 引用上述定义的警告级触发点                // 指定冷却设备及其操作范围                cooling-device =                     <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,  // CPU0冷却设备,无限制范围                    <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,  // CPU1冷却设备                    <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,  // CPU2冷却设备                    <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; // CPU3冷却设备                    // THERMAL_NO_LIMIT表示不限制最大/最小冷却状态            };        };    };};

cpu0-thermal只有一个cooling-map,即map0,map0对应的trip是类型为passive的trip-alert,他的cooling-device引用了四个cpu,我们看下相同dts中的cpu0的节点描述:​​​​​​

cpus {    /*      * 定义CPU节点的寻址方式:     * - address-cells = 1 表示reg属性用1个u32表示地址     * - size-cells = 0 表示reg属性不包含大小字段     */    #address-cells = <1>;    #size-cells = <0>;    /* CPU0 节点定义 */    cpu0: cpu@0 {        /* 基础属性 */        device_type = "cpu";                     // 设备类型标识        compatible = "arm,cortex-a55";           // 兼容的CPU架构        reg = <0x000>;                          // 物理地址编码(此处为0号CPU)        /* 电源管理 */        enable-method = "psci";                  // 使用ARM PSCI协议启动CPU        performance-domains = <&performance 0>;  // 关联的性能域(用于DVFS调频)        clock-frequency = <1701000000>;          // 标称主频(1.701GHz)        capacity-dmips-mhz = <308>;             // CPU算力指标(DMIPS/MHz)        cpu-idle-states = <&cpu_ret_l &cpu_off_l>; // 支持的休眠状态(retention/off)        /* 缓存配置 */        i-cache-size = <32768>;                 // 指令缓存大小(32KB)        i-cache-line-size = <64>;               // 指令缓存行大小(64B)        i-cache-sets = <128>;                   // 指令缓存组数        d-cache-size = <32768>;                 // 数据缓存大小(32KB)        d-cache-line-size = <64>;               // 数据缓存行大小(64B)        d-cache-sets = <128>;                   // 数据缓存组数        next-level-cache = <&l2_0>;             // 二级缓存引用        /* 温控接口 */        #cooling-cells = <2>;                   // 定义该CPU可作为冷却设备                                                // 参数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 - 将散热设备绑定到温控区域的触发点 * @tz:     目标温控区域设备 * @td:     要绑定的温度触发点描述符 * @cdev:   要绑定的散热设备 * @cool_spec: 散热规格(包含上下限和权重) * * 核心功能: * 1. 建立温控区域(tz)、触发点(trip)和散热设备(cdev)的关联关系 * 2. 创建sysfs控制接口(触发点状态/权重调节) * 3. 初始化散热控制参数(工作范围、权重等) * * 典型调用场景: * - 在温控区域的.bind回调中调用 * - 系统初始化时构建散热拓扑 * * 返回值:0成功,负值表示错误码 */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;    /* 参数校验与默认值处理 */    if (cool_spec->lower == THERMAL_NO_LIMIT)        cool_spec->lower = 0;  // 下限默认为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;    /* 分配thermal_instance内存 */    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;      // 设置散热权重    /* 分配唯一ID并命名 */    result = ida_alloc(&tz->ida, GFP_KERNEL);    if (result < 0)        goto free_mem;    dev->id = result;    sprintf(dev->name, "cdev%d", dev->id);    /* 创建sysfs符号链接(温控区域→散热设备)*/    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来描述

0

一个有两个trip的thermal zone的sysfs目录中trip相关的文件如下:

0

http://www.xdnf.cn/news/1019521.html

相关文章:

  • WEBSOCKET研究
  • 传智健康---十天项目总结
  • 邮科OEM摄像头重塑楼宇安防价值链条
  • 010502管道符_防火墙出入站_不回显带外-渗透命令-基础入门-网络安全
  • 多模态大语言模型arxiv论文略读(120)
  • ArcPy 与 ArcGIS .NET SDK 读取 GDB 要素类坐标系失败?GDAL 外挂方案详解
  • 会计-收入-3-关于特定交易的会计处理
  • Flask应用中处理异步事件(后台线程+事件循环)的方法(2)
  • C# 使用HttpListener时候异常(此平台不支持此操作:System.PlatformNotSupportedException)
  • 论文阅读:arxiv 2025 Not All Tokens Are What You Need In Thinking
  • 一致性hash
  • PG、SprinBoot项目报错,表不存在
  • 代码训练LeetCode(34)文本左右对齐
  • 无人机避障——感知篇(Orin nx采用zed2双目相机进行Vins-Fusion-GPU定位,再通过位姿和深度图建图完成实时感知)
  • .NetCore 8 反射与源生成器(Reflection vs Source Generators)
  • 安装 Ubuntu Desktop 2504
  • Spring Boot自动配置原理与实践
  • 3.图数据Neo4j - CQL的使用
  • 6月13日day52打卡
  • docker-compose部署tidb服务
  • 二叉树的算法
  • 将包含父子关系的扁平列表 List<Demo> 转换成树形结构的 List<DemoVO>,每个节点包含自己的子节点列表
  • 年化收益237%的策略,12年年化是38%,支持配置最小日期,附aitrader_1.5代码发布
  • 爬虫技术栈解析:XPath与BeautifulSoup的深度对比与实践指南
  • WPF数据绑定疑惑解答--(关于控件的Itemsource,Collection绑定)
  • 获取Linux设备系统启动时间和进程启动时间
  • 基于Netty的UDPServer端和Client端解决正向隔离网闸数据透传问题
  • 前端八股文-vue篇
  • 2025-06-13【视频处理】基于视频内容转场进行分割
  • 深度剖析:AI 社媒矩阵营销工具,如何高效获客?