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

Linux电源管理(五),发热管理(thermal),温度控制

更多linux系统电源管理相关的内容请看:Linux电源管理、功耗管理 和 发热管理 (CPUFreq、CPUIdle、RPM、thermal、睡眠 和 唤醒)-CSDN博客

本文主要基于linux-5.4.18版本的内核代码进行分析。 

1 简介

1.1 硬件知识

CPU等芯片在工作时会产生大量热量,导致硬件温度升高,而每个芯片都有自己的工作温度区间(例如FT-2000四核处理器的工作温度如下图所示)。当芯片的温度不在这个区间内时,芯片将无法正常工作。

                 《FT-2000/4 系列处理器数据手册》1 简介

为了控制硬件温度,硬件上有两类降温设备(Cooling device):

  • 主动降温(Active Cooling)设备,一般是风扇;
  • 被动降温(Passive Cooling)设备,一般是发热的芯片本身,通过降低频率或者电压来减少热量的产生。

1.2 温度控制的方案

                《Advanced Configuration and Power Interface (ACPI) Specification》3.10 Thermal Management Concepts

如上图所示,很多硬件设计中,CPU的温度传感器和风扇是直接受EC (Embedded Controller)控制的,所以出现了两种温度控制的方案:

  • 第一种、完全由EC来控制硬件温度,linux系统不干预;
  • 第二种、Linux系统通过EC来控制硬件温度

本文主要分析第二种方案

2 thermal_zone_device

2.1 简介

可以获取温度的设备抽象为thermal_zone_device, 如Temperature Sensor等。
                《SoC底层软件低功耗系统设计与实现》 9.1.2 模块功能详解

2.2 数据结构

2.2.1 struct thermal_zone_device

//include/linux/thermal.h
struct thermal_zone_device {int temperature;                 //current temperature. int last_temperature;            //previous temperature readint prev_low_trip;               //上⼀次温控的低温触发点int prev_high_trip;              //上⼀次温控的⾼温触发点struct thermal_zone_device_ops *ops;struct thermal_zone_params *tzp;struct thermal_governor *governor;struct delayed_work poll_queue;......
};

register和unregister

struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,void *, struct thermal_zone_device_ops *,struct thermal_zone_params *, int, int);void thermal_zone_device_unregister(struct thermal_zone_device *);

2.2.2 struct thermal_zone_device_ops

//include/linux/thermal.h
struct thermal_zone_device_ops {int (*bind) (struct thermal_zone_device *,struct thermal_cooling_device *);int (*unbind) (struct thermal_zone_device *,struct thermal_cooling_device *);int (*get_temp) (struct thermal_zone_device *, int *);int (*set_trips) (struct thermal_zone_device *, int, int);int (*get_mode) (struct thermal_zone_device *,enum thermal_device_mode *);int (*set_mode) (struct thermal_zone_device *,enum thermal_device_mode);int (*get_trip_type) (struct thermal_zone_device *, int,enum thermal_trip_type *);int (*get_trip_temp) (struct thermal_zone_device *, int, int *);int (*set_trip_temp) (struct thermal_zone_device *, int, int);int (*get_trip_hyst) (struct thermal_zone_device *, int, int *);int (*set_trip_hyst) (struct thermal_zone_device *, int, int);int (*get_crit_temp) (struct thermal_zone_device *, int *);int (*set_emul_temp) (struct thermal_zone_device *, int);int (*get_trend) (struct thermal_zone_device *, int,enum thermal_trend *); int (*notify) (struct thermal_zone_device *, int,enum thermal_trip_type);
};

2.3 温度状态 和 温度阈值(trip point)

2.3.1 简介

软件上有四个温度阈值,分别是active、passive、hot和critical。

当实际温度超过active温度阈值时,应该执行主动降温操作;
当实际温度超过pssive温度阈值时,应该执行被动降温操作;
当实际温度超过hot温度阈值时,在支持ACPI的设备上应该执行S4(挂起到硬盘)操作;
当实际温度超过critical温度阈值时,应该执行关机操作。

当实际温度超过某个阈值后,具体执行什么操作请看下面的 “4 绑定zone_device的trip points和cooling_device” 小节

2.3.2 数据结构

//include/linux/thermal.h
/*** struct thermal_trip - representation of a point in temperature domain* @np: pointer to struct device_node that this trip point was created from* @temperature: temperature value in miliCelsius* @hysteresis: relative hysteresis in miliCelsius* @type: trip point type*/struct thermal_trip {struct device_node *np;int temperature;int hysteresis;enum thermal_trip_type type;
};
//include/linux/thermal.h
enum thermal_trip_type {THERMAL_TRIP_ACTIVE = 0,THERMAL_TRIP_PASSIVE,THERMAL_TRIP_HOT,THERMAL_TRIP_CRITICAL,
};

2.3.3 通过设备树指定trip points

        trips {cpu_alert0: cpu-alert0 {temperature = <90000>; /* millicelsius */hysteresis = <2000>; /* millicelsius */type = "active";};  cpu_alert1: cpu-alert1 {temperature = <100000>; /* millicelsius */hysteresis = <2000>; /* millicelsius */type = "passive";};  cpu_crit: cpu-crit {temperature = <125000>; /* millicelsius */hysteresis = <2000>; /* millicelsius */type = "critical";};  };

上面的设备树信息说明

The trip node is a node to describe a point in the temperature domain in which the system takes an action. This node describes just the point, not the action.

Required properties:
- temperature:      An integer indicating the trip temperature level,
  Type: signed      in millicelsius.
  Size: one cell

- hysteresis:       A low hysteresis value on temperature property (above).
  Type: unsigned    This is a relative value, in millicelsius.
  Size: one cell

- type:         a string containing the trip type. Expected values are:
    "active":   A trip point to enable active cooling
    "passive":  A trip point to enable passive cooling
    "hot":      A trip point to notify emergency
    "critical": Hardware not reliable.

                Documentation/devicetree/bindings/thermal/thermal.txt

2.3.4 通过ACPI Source Language (ASL)来指定trip points

Thermal Objects

<1> _ACx (Active Cooling)

This optional object, if present under a thermal zone, returns the temperature trip point at which OSPM must start or
stop Active cooling, where x is a value between 0 and 9 that designates multiple active cooling levels of the thermal
zone.

<2> _PSV (Passive)

This optional object, if present under a thermal zone, evaluates to the temperature at which OSPM must activate
passive cooling policy.

<3> _CRT (Critical Temperature)

This object, when defined under a thermal zone, returns the critical temperature at which OSPM must shutdown the
system.

<4> _HOT (Hot Temperature)

This optional object, when defined under a thermal zone, returns the critical temperature at which OSPM may choose
to transition the system into the S4 sleeping state.

                《Advanced Configuration and Power Interface (ACPI) Specification》11.4 Thermal Objects

示例

ThermalZone (TZ0) {Method(_PSV) { Return(_C2K(70)) }   /* passive cooling temp */Method(_HOT) { Return(_C2K(85)) }   /* hot temp */Method(_CRT) { Return(_C2K(95)) }   /* critical temp */......
} /* ThermalZone(TZ0) */

2.3.5 查看trip points信息

/sys/class/thermal/thermal_zoneX/trip_point_0_type
/sys/class/thermal/thermal_zoneX/trip_point_0_temp
/sys/class/thermal/thermal_zoneX/trip_point_0_hyst

示例

# cat /sys/class/thermal/thermal_zone4/trip_point_0_type 
critical
# cat /sys/class/thermal/thermal_zone4/trip_point_0_temp
110050
# cat /sys/class/thermal/thermal_zone4/trip_point_0_hyst 
0

2.4 查看或者设置 thermal_zone_device信息

/sys/class/thermal/thermal_zoneX/

3 cooling_device

3.1 简介

可以控制温度的设备抽象为thermal_cooling_device, 如⻛扇、CPU、DDR、GPU等。

                《SoC底层软件低功耗系统设计与实现》 9.1.2 模块功能详解

主动(active)降温设备 和 被动(passive)降温设备 

Cooling devices are nodes providing control on power dissipation. There are essentially two ways to provide control on power dissipation. First is by means of regulating device performance, which is known as passive cooling. A typical passive cooling is a CPU that has dynamic voltage and  frequency scaling (DVFS), and uses lower frequencies as cooling states. Second is by means of activating devices in order to remove the dissipated heat, which is known as active cooling, e.g. regulating fan speeds. In both cases, cooling devices shall have a way to determine the state of cooling in which the device is.
                Documentation/devicetree/bindings/thermal/thermal.txt

Active cooling devices typically consume power and produce some amount of noise when enabled. These devices
attempt to cool a thermal zone through the removal of heat rather than limiting the performance of a device to address
an adverse thermal condition.
                《Advanced Configuration and Power Interface (ACPI) Specification》11.1.4 Active Cooling

Passive cooling controls are able to cool a thermal zone without creating noise and without consuming additional
power (actually saving power), but do so by decreasing the performance of the devices in the zone .
                《Advanced Configuration and Power Interface (ACPI) Specification》11.1.5 Passive Cooling

3.2 数据结构

3.2.1 struct thermal_cooling_device;

//include/linux/thermal.h
struct thermal_cooling_device {int id; char type[THERMAL_NAME_LENGTH];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;
};

3.2.2 struct thermal_cooling_device_ops;

//include/linux/thermal.h
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 *);
};

3.3 states

3.3.1 简介

冷却设备(cooling device)维护一个冷却(cooling)等级,即状态(state),一般状态越高,系统的冷却需求越高,所采取的冷却措施也可能更激进。冷却设备根据不同等级的冷却需求进行冷却行为。冷却设备只根据state进行冷却操作,是实施者,而state的计算由thermal governor完成。

                《SoC底层软件低功耗系统设计与实现》 9.1.2 模块功能详解

Any cooling device has a range of cooling states (i.e. different levels of heat dissipation). For example a fan's cooling states correspond to the different fan speeds possible. Cooling states are referred to by single unsigned integers, where larger numbers mean greater heat dissipation. The precise set of cooling states associated with a device should be defined in a particular device's binding.
                Documentation/devicetree/bindings/thermal/thermal.txt

3.3.2 设置cooling device的states

3.3.2.1 通过设备树指定PWM风扇的states (cooling-levels)
//arch/arm/boot/dts/exynos5410-odroidxu.dtsfan0: pwm-fan {compatible = "pwm-fan";pwms = <&pwm 0 20972 0>;#cooling-cells = <2>;cooling-levels = <0 130 170 230>;};

cooling-levels      :  PWM duty cycle values in a range from 0 to 255 which correspond to thermal cooling states 
                Documentation/devicetree/bindings/hwmon/pwm-fan.txt 

3.3.2.2 通过设备树指定CPU的states (operating-points)
//Documentation/devicetree/bindings/thermal/thermal.txt
cpus {/* * Here is an example of describing a cooling device for a DVFS* capable CPU. The CPU node describes its four OPPs.* The cooling states possible are 0..3, and they are* used as OPP indexes. The minimum cooling state is 0, which means* all four OPPs can be available to the system. The maximum* cooling state is 3, which means only the lowest OPPs (198MHz@0.85V)* can be available in the system.*/cpu0: cpu@0 {...operating-points = <                                                /* kHz    uV */                                                 970000  1200000                                                 792000  1100000                                                 396000  950000198000  850000>;#cooling-cells = <2>; /* min followed by max */};...     
};
3.3.3.3 通过ACPI Source Language (ASL)指定风扇的states (转速)

根据下面的 “7.2.2 控制风扇的转速(fan_set_cur_state)” 章节信息,使用ACPI 1.0规范时,风扇对应的cooling device只有2种states,即打开(D0) 和 关闭(D3);使用ACPI 4.0规范时,可以通过“_FPS (Fan Performance States)”来指定多个states。

3.3.3.4 通过ACPI Source Language (ASL)指定CPU的states

_TSS (Throttling Supported States)

This optional object indicates to OSPM the number of supported processor throttling states that a platform supports.

 

                《Advanced Configuration and Power Interface (ACPI) Specification》
                                8.4.5.2 _TSS (Throttling Supported States) 

ASL示例

Scope(\_SB) {Device(CPU0) {Name(_HID, "ACPI0007")Name(_UID, 0)......// Throttling Supported States// The values shown are for exemplary purposes onlyName(_TSS, Package() {// Read: freq percentage, power, latency, control, statusPackage() {0x64, 1000, 0x0, 0x7, 0x0}, // Throttle off (100%)Package() {0x58, 800, 0x0, 0xF, 0x0}, // 87.5%Package() {0x4B, 600, 0x0, 0xE, 0x0}, // 75%Package() {0x3F, 400, 0x0, 0xD, 0x0} // 62.5%})......}......
}

                《Advanced Configuration and Power Interface (ACPI) Specification》
                                11.7.3 Example: Thermal Zone with Multiple Devices 

对应的驱动初始化流程请看“7.3.2” 小节

3.3.3 查看cooling device的states信息

/sys/class/thermal/cooling_device0/cur_state
/sys/class/thermal/cooling_device0/max_state

3.4 查看cooling_device信息

/sys/class/thermal/cooling_deviceX

4 绑定zone_device的trip points和cooling_device

4.1 简介

thermal_zone_device_register()函数在注册thermal_zone_device时,会调用bind_tz()函数,bind_tz()会遍历已经注册的cooling device,然后执行cooling device和当前注册的thermal_zone_device绑定工作。

thermal_cooling_device_register()函数在注册thermal_cooling_device时,会调用bind_cdev()函数,bind_tz()会遍历已经注册的zone device,然后执行zone device和当前注册的thermal_cooling_device绑定工作。

bind_tz() 和 bind_cdev()最终都会执行struct thermal_zone_device_ops中的bind()函数 和 struct thermal_bind_params中的match()函数来完成具体工作,所以需要实现bind() 或者 match()函数才能完成绑定工作。

最终的绑定工作通过thermal_zone_bind_cooling_device()函数实现,绑定关系通过struct thermal_instance记录。

4.2 数据结构 

/** 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_zone_device *tz;struct thermal_cooling_device *cdev;int 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 tz_node; /* node in tz->thermal_instances */struct list_head cdev_node; /* node in cdev->thermal_instances */unsigned int weight; /* The weight of the cooling device */
};

4.3 绑定函数

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.

int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, int trip,struct thermal_cooling_device *cdev,unsigned long upper, unsigned long lower,unsigned int weight);

4.4 指定thermal zone device的每个trip point和 cooling device之间的绑定关系

4.4.1 设备树

        trips {cpu_alert0: cpu-alert0 {            //trip pointtemperature = <90000>; /* millicelsius */hysteresis = <2000>; /* millicelsius */type = "active";};......cooling-maps {map0 {trip = <&cpu_alert0>;cooling-device = <&fan0 THERMAL_NO_LIMIT 4>; };......

4.4.2 ACPI

_ACx (Active Cooling)
_ALx (Active List)

_PSV (Passive)
_PSL (Passive List)

                《Advanced Configuration and Power Interface (ACPI) Specification》
                                11.4 Thermal Objects

4.5 查看绑定关系

# ls /sys/class/thermal/thermal_zone7/cdev* -l
lrwxrwxrwx 1 root root    0 5月  11 18:51 /sys/class/thermal/thermal_zone7/cdev0 -> ../cooling_device9
-r--r--r-- 1 root root 4096 5月  11 18:51 /sys/class/thermal/thermal_zone7/cdev0_trip_point
-rw-r--r-- 1 root root 4096 5月  11 18:51 /sys/class/thermal/thermal_zone7/cdev0_weight
lrwxrwxrwx 1 root root    0 5月  11 18:51 /sys/class/thermal/thermal_zone7/cdev1 -> ../cooling_device10
-r--r--r-- 1 root root 4096 5月  11 18:51 /sys/class/thermal/thermal_zone7/cdev1_trip_point
-rw-r--r-- 1 root root 4096 5月  11 18:51 /sys/class/thermal/thermal_zone7/cdev1_weight
# cat /sys/class/thermal/thermal_zone7/cdev0_trip_point 
2
# cat /sys/class/thermal/thermal_zone7/cdev1_trip_point 
1
# cat /sys/class/thermal/thermal_zone7/trip_point_2_temp 
80000
# cat /sys/class/thermal/thermal_zone7/trip_point_1_temp 
60000

上面的信息显示thermal_zone7的1号trip point (60摄氏度)和cooling_device10绑定在一起。2号trip point (80摄氏度)和cooling_device9绑定在一起

5 governors

5.1 简介

温控策略抽象为thermal_governor, ⽐如step_wise、bang_bang等。

                《SoC底层软件低功耗系统设计与实现》 9.1.2 模块功能详解

5.2 现有的governors

5.2.1 step_wise

/** If the temperature is higher than a trip point,*    a. if the trend is THERMAL_TREND_RAISING, use higher cooling*       state for this trip point*    b. if the trend is THERMAL_TREND_DROPPING, do nothing*    c. if the trend is THERMAL_TREND_RAISE_FULL, use upper limit*       for this trip point*    d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit*       for this trip point* If the temperature is lower than a trip point,*    a. if the trend is THERMAL_TREND_RAISING, do nothing*    b. if the trend is THERMAL_TREND_DROPPING, use lower cooling*       state for this trip point, if the cooling state already*       equals lower limit, deactivate the thermal instance*    c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing*    d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit,*       if the cooling state already equals lower limit,*       deactivate the thermal instance*/

                drivers/thermal/step_wise.c

5.2.2 power_allocator

5.2.3 bang_bang

 * Regulation Logic: a two point regulation, deliver cooling state depending* on the previous state shown in this diagram:**                Fan:   OFF    ON**                              |*                              |*          trip_temp:    +---->+*                        |     |        ^*                        |     |        |*                        |     |   Temperature* (trip_temp - hyst):    +<----+*                        |*                        |*                        |**   * If the fan is not running and temperature exceeds trip_temp, the fan*     gets turned on.*   * In case the fan is running, temperature must fall below*     (trip_temp - hyst) so that the fan gets turned off again.*

                drivers/thermal/gov_bang_bang.c 

5.2.4 user_space

Notifies user space about thermal events

                drivers/thermal/user_space.c

5.2.5 fair_share

 * Throttling Logic: This uses three parameters to calculate the new* throttle state of the cooling devices associated with the given zone.** Parameters used for Throttling:* P1. max_state: Maximum throttle state exposed by the cooling device.* P2. percentage[i]/100:*  How 'effective' the 'i'th device is, in cooling the given zone.* P3. cur_trip_level/max_no_of_trips:*  This describes the extent to which the devices should be throttled.*  We do not want to throttle too much when we trip a lower temperature,*  whereas the throttling is at full swing if we trip critical levels.*  (Heavily assumes the trip points are in ascending order)* new_state of cooling device = P3 * P2 * P1

                drivers/thermal/fair_share.c

5.3 查看和设置governor

/sys/class/thermal/thermal_zoneX/available_policies

/sys/class/thermal/thermal_zoneX/policy

6 核心代码流程

6.1 简介

内核代码中会循环读取温度数据,如果温度超过某个trip point温度,就会启动和这个trip point绑定的cooling device开始降温工作。

6.2 代码流程

轮训工作通过工作项实现

thermal_zone_device_register();-> INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);

 工作项处理函数thermal_zone_device_check()的流程如下:

                《SoC底层软件低功耗系统设计与实现》9.1.6 关于critical事件和非critical事件的处理流程

monitor_thermal_zone()函数会重新添加工作项,以此来达到循环执行的效果 (循环的间隔时间通过struct thermal_zone_device中的passive_delay变量和polling_delay变量控制)。

monitor_thermal_zone();-> thermal_zone_device_set_polling();-> mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, <时间>);

tz->governor->throttle()会执行governors的控温逻辑,选择cooling device的states,然后调用cdev->ops->set_cur_state();

以step_wise(governor)为例

step_wise_throttle();-> thermal_zone_trip_update(tz, trip);-> trend = get_tz_trend(tz, trip);-> instance->target = get_target_state(instance, trend, throttle);-> thermal_cdev_update();-> cdev->ops->set_cur_state();

关键函数get_target_state()的注释如下:

//drivers/thermal/step_wise.c
/** If the temperature is higher than a trip point,*    a. if the trend is THERMAL_TREND_RAISING, use higher cooling*       state for this trip point*    b. if the trend is THERMAL_TREND_DROPPING, do nothing*    c. if the trend is THERMAL_TREND_RAISE_FULL, use upper limit*       for this trip point*    d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit*       for this trip point* If the temperature is lower than a trip point,*    a. if the trend is THERMAL_TREND_RAISING, do nothing*    b. if the trend is THERMAL_TREND_DROPPING, use lower cooling*       state for this trip point, if the cooling state already*       equals lower limit, deactivate the thermal instance*    c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing*    d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit,*       if the cooling state already equals lower limit,*       deactivate the thermal instance*/
static unsigned long get_target_state(struct thermal_instance *instance,enum thermal_trend trend, bool throttle)
{......
}

7 基于ACPI的温控驱动分析

7.1 thermal_zone_device

7.1.1 数据结构

7.1.1.1 struct acpi_driver acpi_thermal_driver;
//include/acpi/acpi_drivers.h
#define ACPI_THERMAL_HID        "LNXTHERM"//drivers/acpi/thermal.c
static const struct acpi_device_id  thermal_device_ids[] = {{ACPI_THERMAL_HID, 0},{"", 0},
};
MODULE_DEVICE_TABLE(acpi, thermal_device_ids);static struct acpi_driver acpi_thermal_driver = {.name = "thermal",.class = ACPI_THERMAL_CLASS,.ids = thermal_device_ids,.ops = {.add = acpi_thermal_add,.remove = acpi_thermal_remove,.notify = acpi_thermal_notify,},   .drv.pm = &acpi_thermal_pm,
};
 7.1.1.2 struct thermal_zone_device_ops acpi_thermal_zone_ops;
//drivers/acpi/thermal.c
static struct thermal_zone_device_ops acpi_thermal_zone_ops = {.bind = acpi_thermal_bind_cooling_device,.unbind = acpi_thermal_unbind_cooling_device,.get_temp = thermal_get_temp,.get_mode = thermal_get_mode,.set_mode = thermal_set_mode,.get_trip_type = thermal_get_trip_type,.get_trip_temp = thermal_get_trip_temp,.get_crit_temp = thermal_get_crit_temp,.get_trend = thermal_get_trend,.notify = thermal_notify,
};

7.1.2 ACPI中的 Thermal Objects

                《Advanced Configuration and Power Interface (ACPI) Specification》11.4 Thermal Objects

7.1.3 驱动初始化大致流程

acpi_thermal_add();-> acpi_thermal_get_info(tz);-> acpi_thermal_get_trip_points(tz);    /* Get trip points [_CRT, _PSV, etc.] (required) */-> acpi_thermal_trips_update();-> acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, &tmp);-> tz->trips.critical.temperature = tmp;-> acpi_evaluate_integer(tz->device->handle, "_HOT", NULL, &tmp);-> tz->trips.hot.temperature = tmp;-> acpi_evaluate_integer(tz->device->handle, "_PSV", NULL, &tmp);-> tz->trips.passive.temperature = tmp;-> acpi_thermal_get_temperature(tz);    /* Get temperature [_TMP] (required) */-> acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp);-> tz->temperature = tmp;-> acpi_thermal_set_cooling_mode();    /* Set the cooling mode [_SCP] to active cooling (default) */-> acpi_thermal_register_thermal_zone();-> thermal_zone_device_register("acpitz", trips, 0, tz, &acpi_thermal_zone_ops,  ...);-> sysfs_create_link(&tz->device->dev.kobj, &tz->thermal_zone->device.kobj, "thermal_zone");-> sysfs_create_link(&tz->thermal_zone->device.kobj, &tz->device->dev.kobj, "device");

7.1.4 ACPI Source Language (ASL)示例 

ThermalZone (TZ0) {Method(_TMP) { Return (\_SB.PCI0.ISA0.EC0.TMP )} // get current tempName(_PSL, Package() {\_SB.CPU0, \\_SB.CPU1}) // passive cooling devicesName(_AL0, Package() {\_SB.PCI0.ISA0.EC0.FN1}) // active coolingMethod(_AC0) { Return (\_SB.PCI0.ISA0.EC0.AC0) } // fan temp (high)Method(_AC1) { Return (\_SB.PCI0.ISA0.EC0.AC1) } // fan temp (low)Method(_PSV) { Return (\_SB.PCI0.ISA0.EC0.PSV) } // passive cooling tempMethod(_HOT) { Return (\_SB.PCI0.ISA0.EC0.HOT) } // get critical S4 tempMethod(_CRT) { Return (\_SB.PCI0.ISA0.EC0.CRT) } // get crit. tempName(_TC1, 4) // bogus example constantName(_TC2, 3) // bogus example constantMethod(_SCP, 1) { Store (Arg0, \\_SB.PCI0.ISA0.EC0.MODE) } // set cooling modeName(_TSP, 150) // passive sampling = 15 sec
} // end of TZ0

                《Advanced Configuration and Power Interface (ACPI) Specification》 
                                11.7.3 Example: Thermal Zone with Multiple Devices

7.2 cooling_device: Fan

7.2.1 数据结构

7.2.1.1 struct platform_driver acpi_fan_driver;
//drivers/acpi/fan.c
static const struct acpi_device_id fan_device_ids[] = {{"PNP0C0B", 0},{"INT3404", 0},{"", 0},
};
MODULE_DEVICE_TABLE(acpi, fan_device_ids);static struct platform_driver acpi_fan_driver = {.probe = acpi_fan_probe,.remove = acpi_fan_remove,.driver = {.name = "acpi-fan",.acpi_match_table = fan_device_ids,.pm = FAN_PM_OPS_PTR,},
};
7.2.1.2 struct thermal_cooling_device_ops fan_cooling_ops;
//drivers/acpi/fan.c
static const struct thermal_cooling_device_ops fan_cooling_ops = {.get_max_state = fan_get_max_state,.get_cur_state = fan_get_cur_state,.set_cur_state = fan_set_cur_state,
};

7.2.2 控制风扇的转速(fan_set_cur_state)

7.2.2.1 简介 

在ACPI规范中Device Power States有四种

                 《Advanced Configuration and Power Interface (ACPI) Specification》 A.2 Device Power States

7.2.2.2 控制固定转速的风扇

对于固定转速的风扇,控制起来很方便,进入D0状态就是打开风扇,进入D3状态就是关闭风扇。

fan_set_cur_state();-> fan_set_state();
static int fan_set_state(struct acpi_device *device, unsigned long state)
{if (state != 0 && state != 1)return -EINVAL;return acpi_device_set_power(device,state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
}
7.2.2.3 ACPI 1.0版本下控制可调转速的风扇

ACPI 1.0 defined a simple fan device that is assumed to be in operation when it is in the D0 state. Thermal zones reference fan device(s) as being responsible primarily for cooling within that zone.Notice that multiple fan devices can be present for any one thermal zone. They might be actual different fans, or they might be used to implement one fan of multiple speeds (for example, by turning both “fans” on the one fan will run full speed).

                《Advanced Configuration and Power Interface (ACPI) Specification》11.3 Fan Device

示例

// Following is a single fan with two speeds. This is represented
// by creating two logical fan devices. When FN2 is turned on then
// the fan is at a low speed. When FN1 and FN2 are both on then
// the fan is at high speed.
//
// Create FAN device object FN1
Device (FN1) {// Device ID for the FANName(_HID, EISAID("PNP0C0B"))Name(_UID, 0)Name(_PR0, Package(){FN10, FN11})
}
// Create FAN device object FN2
Device (FN2) {// Device ID for the FANName(_HID, EISAID("PNP0C0B"))Name(_UID, 1)Name(_PR0, Package(){FN10})
}

                《Advanced Configuration and Power Interface (ACPI) Specification》11.7.2 Example: Multiple-Speed Fans 

7.2.2.4 ACPI 4.0版本下控制可调转速的风扇

ACPI 4.0添加了4个Fan Objects来描述风扇信息,其中“_FPS (Fan Performance States)”可以描述一个风扇支持的多个转速信息。

Package {Revision,        // Integer - Current revision is: 0FanPState[0],    // Package......FanPState[n]     // Package
}

Each FanPState sub-Package contains the elements described below: 

Package ()            // Fan P-State
{Control,          // Integer DWORDTripPoint,        // Integer DWORDSpeed,            // Integer DWORDNoiseLevel,       // Integer DWORDPower             // Integer DWORD
}

                《Advanced Configuration and Power Interface (ACPI) Specification》11.3.1 Fan Objects 

 驱动流程

fan_set_cur_state();-> fan_set_state_acpi4();

7.2.3 驱动初始化大致流程

acpi_fan_probe(); -> acpi_fan_get_fps();          //get _FPS (Fan Performance States)-> acpi_evaluate_object(device->handle, "_FPS", NULL, &buffer);-> fan->fps_count = obj->package.count - 1;-> thermal_cooling_device_register(name, device, &fan_cooling_ops);

7.2.4 ACPI Source Language (ASL)示例 

请看上面的“7.2.2.3”小节 

7.3 cooling_device: Processor

7.3.1 数据结构

//drivers/acpi/processor_thermal.c
static const struct acpi_device_id processor_device_ids[] = {{ACPI_PROCESSOR_OBJECT_HID, 0},      //ACPI_PROCESSOR_OBJECT_HID   "LNXCPU"{ACPI_PROCESSOR_DEVICE_HID, 0},      //ACPI_PROCESSOR_DEVICE_HID   "ACPI0007"{"", 0},
};
MODULE_DEVICE_TABLE(acpi, processor_device_ids);static struct device_driver acpi_processor_driver = {.name = "processor",.bus = &cpu_subsys,.acpi_match_table = processor_device_ids,.probe = acpi_processor_start,.remove = acpi_processor_stop,
};
const struct thermal_cooling_device_ops processor_cooling_ops = { .get_max_state = processor_get_max_state,.get_cur_state = processor_get_cur_state,.set_cur_state = processor_set_cur_state,
};

7.3.2 初始化流程

acpi_processor_driver_init(void);       //module_init(acpi_processor_driver_init);-> driver_register(&acpi_processor_driver);-> acpi_processor_start();-> __acpi_processor_start();-> acpi_pss_perf_init();-> acpi_processor_get_throttling_info();-> acpi_processor_get_throttling_states();-> acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer);-> pr->throttling.state_count = tss->package.count;-> thermal_cooling_device_register("Processor", device, &processor_cooling_ops);

7.3.3 ACPI Source Language (ASL)示例 

Scope(\_SB) {Device(CPU0) {Name(_HID, "ACPI0007")Name(_UID, 0)//// Load additional objects if 3.0 Thermal model support is available//Method(_INI, 0) {If (\_OSI("3.0 Thermal Model")) {LoadTable("OEM1", "PmRef", "Cpu0", "\\_SB.CPU0") // 3.0 Thermal Model}}// For brevity, most processor objects have been excluded// from this example (such as \_PSS, \_CST, \_PCT, \_PPC, etc.)// Processor Throttle Control objectName(_PTC, ResourceTemplate() {Register(SystemIO, 32, 0, 0x120) // Processor ControlRegister(SystemIO, 32, 0, 0x120) // Processor Status})// Throttling Supported States// The values shown are for exemplary purposes onlyName(_TSS, Package() {// Read: freq percentage, power, latency, control, statusPackage() {0x64, 1000, 0x0, 0x7, 0x0}, // Throttle off (100%)Package() {0x58, 800, 0x0, 0xF, 0x0}, // 87.5%Package() {0x4B, 600, 0x0, 0xE, 0x0}, // 75%Package() {0x3F, 400, 0x0, 0xD, 0x0} // 62.5%})// Throttling Present Capabilities// The values shown are for exemplary purposes onlyMethod(_TPC) {If(\_SB.AC) {Return(0) // All throttle states available} Else {Return(2) // Throttle states >= 2 are available}   }   } // end of CPU0 scope......
}

                《Advanced Configuration and Power Interface (ACPI) Specification》 
                                11.7.3 Example: Thermal Zone with Multiple Devices

8 通过设备树(DTS)指定硬件信息的温控驱动分析

8.1 thermal_zone_device

8.1.1 数据结构

//drivers/thermal/of-thermal.c
static struct thermal_zone_device_ops of_thermal_ops = {.get_mode = of_thermal_get_mode,.set_mode = of_thermal_set_mode,.get_trip_type = of_thermal_get_trip_type,.get_trip_temp = of_thermal_get_trip_temp,.set_trip_temp = of_thermal_set_trip_temp,.get_trip_hyst = of_thermal_get_trip_hyst,.set_trip_hyst = of_thermal_set_trip_hyst,.get_crit_temp = of_thermal_get_crit_temp,.bind = of_thermal_bind,.unbind = of_thermal_unbind,
};

8.1.2 初始化流程

thermal_init();       //fs_initcall(thermal_init);-> of_parse_thermal_zones();-> of_find_node_by_name(NULL, "thermal-zones");-> thermal_of_build_thermal_zone();-> of_property_read_u32(np, "polling-delay-passive", &prop);-> of_property_read_u32(np, "polling-delay", &prop);-> of_property_read_u32_array(np, "coefficients", coef, 2);-> child = of_get_child_by_name(np, "trips");-> thermal_of_populate_trip();-> of_property_read_u32(np, "temperature", &prop);   //获取trip point温度值-> of_property_read_u32(np, "hysteresis", &prop);-> thermal_of_get_trip_type();-> of_property_read_string(np, "type", &t);      //获取trip point类型(active、passive、hot和critical)-> child = of_get_child_by_name(np, "cooling-maps");-> thermal_of_populate_bind_params();-> of_property_read_u32(np, "contribution", &prop);-> of_count_phandle_with_args(np, "cooling-device", "#cooling-cells");-> of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells", i, &cooling_spec);-> __tcbp[i].cooling_device = cooling_spec.np;-> __tcbp[i].min = cooling_spec.args[0];        //minimum cooling state-> __tcbp[i].max = cooling_spec.args[1];        //maximum cooling state-> __tbp->tcbp = __tcbp;-> thermal_zone_device_register();

温度传感器的初始化

thermal_zone_of_sensor_register();-> np = of_find_node_by_name(NULL, "thermal-zones");-> of_parse_phandle_with_args(child, "thermal-sensors", "#thermal-sensor-cells", 0, &sensor_specs);-> thermal_zone_of_add_sensor();-> tz->ops = ops;-> tzd->ops->get_temp = of_thermal_get_temp;-> tzd->ops->get_trend = of_thermal_get_trend;

8.1.3 设备树示例

thermal-zones {cpu_thermal: cpu-thermal {polling-delay-passive = <250>; /* milliseconds */polling-delay = <1000>; /* milliseconds */thermal-sensors = <&bandgap0>;trips {cpu_alert0: cpu-alert0 {temperature = <90000>; /* millicelsius */hysteresis = <2000>; /* millicelsius */type = "active";};  cpu_alert1: cpu-alert1 {temperature = <100000>; /* millicelsius */hysteresis = <2000>; /* millicelsius */type = "passive";};  cpu_crit: cpu-crit {temperature = <125000>; /* millicelsius */hysteresis = <2000>; /* millicelsius */type = "critical";};  };  cooling-maps {map0 {trip = <&cpu_alert0>;cooling-device = <&fan0 THERMAL_NO_LIMIT 4>; };  map1 {trip = <&cpu_alert1>;cooling-device = <&fan0 5 THERMAL_NO_LIMIT>, <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;};  };  };  
};

                Documentation/devicetree/bindings/thermal/thermal.txt 

8.2 cooling_device: pwm-fan

8.2.1 数据结构

//drivers/hwmon/pwm-fan.c
static const struct thermal_cooling_device_ops pwm_fan_cooling_ops = {.get_max_state = pwm_fan_get_max_state,.get_cur_state = pwm_fan_get_cur_state,.set_cur_state = pwm_fan_set_cur_state,
};

8.2.2 初始化

pwm_fan_probe();-> pwm_fan_of_get_cooling_data();-> of_property_read_u32_array(np, "cooling-levels", ctx->pwm_fan_cooling_levels, num);     //获取cooling device支持的state-> devm_thermal_of_cooling_device_register(..., "pwm-fan", ctx, &pwm_fan_cooling_ops);

8.2.3 设备树示例

请看“3.3.2.1” 小节

8.3 cooling_device: thermal-cpufreq

8.3.1 数据结构

//drivers/thermal/cpu_cooling.c
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,
};

 8.3.2 初始化流程

cpufreq_online();-> of_cpufreq_cooling_register();-> __cpufreq_cooling_register();-> freq_qos_add_request();-> thermal_of_cooling_device_register();

8.3.3 设备树示例

请看 “3.3.2.2” 小节

9 调试

9.1 /sys/kernel/debug/tracing/events/thermal

9.2 /sys/kernel/debug/tracing/events/thermal_power_allocator/

9.3 tmon

tomon工具可以显示下面的信息:

  • 实时显示Thermal Zone(温度传感器)获取的温度
  • Thermal Zone的trip points
  • Cooling device的states信息(current state和 max state)
  • Cooling device 和 Thermal zone的绑定关系

⼯具源码:<kernel_src>/tools/thermal/tmon

执行命令“ ./tools/thermal/tmon/tmon” 后会显示下面的界面

相关文章:

  • C 语 言 - - - 简 易 通 讯 录
  • Python 字符串
  • 【Linux 系统调试】syslog:Linux 系统日志工具详解
  • c++STL-vector的模拟实现
  • 开关电源滤波器讲解
  • 鲁滨逊归结原理详解:期末考点+解题指南
  • c++刷题便捷函数(类似于stoi的小函数)
  • 解锁性能密码:Linux 环境下 Oracle 大页配置全攻略​
  • 基于大模型的甲状腺结节诊疗全流程预测与方案研究报告
  • 基于STM32、HAL库的RN7302电能计量芯片驱动程序设计
  • Docke容器下JAVA系统时间与Linux服务器时间不一致问题解决办法
  • latex控制表格宽度,不要超出页面
  • java 中 pojo 的详细讲解
  • 国外付费AI软件充值教程
  • 图中点的层次:BFS与邻接表的完美结合
  • Linux复习笔记(三) 网络服务配置(web)
  • python标准库--itertools - 迭代器工具在算法比赛的应用
  • DVWA靶场保姆级通关教程--08SQL盲注(上)
  • Linux常用命令(持续完善)
  • 深入解读tcpdump:原理、数据结构与操作手册
  • 全国汽车以旧换新补贴申请量突破1000万份
  • 网信部门曝光网络谣言典型案例,“AI预测彩票号码百分百中奖”等在列
  • 上海国际电影节特设“今日亚洲”单元
  • 听企业聊感受,《外企聊营商》5月13日起推出
  • 全国重点网络媒体和网络达人走进沧州,探寻“文武双全”的多重魅力
  • 巴基斯坦称成功拦截印度导弹,空军所有资产安全