目录
Linux devfreq 简介
现在的 Soc
由众多的子模块构成,比如CNN
,DSP
,ISP
,CPU
等,在不同的场景下,并非所有的模块都要保持最高的性能,因此,SoC
设计的时候会划分一些电压域,这些电压域内的模块,可以根据具体需要调整电压和频率,从而达到既能实现功能,又能降低功耗的目的
不过频率电压并不是随意搭配的,一般情况下,高频对应着高压,低频对应着低压,这是由于晶体管的电器特性决定的
Linux
内核用 OPP(Operation Performance Point)
对这些设备支持的频率和电压进行描述和管理,CPU
的 DVFS
也就是 cpufreq
也是基于 OPP
实现的,但是仅仅支持 CPU
设备的调频和调压,这里主要介绍的是设备的 DVFS
,也是基于 OPP
实现的,Linux
内核实现了一个 devfreq framework
用于实现和管理 device
的 dvfs
,用于支持非CPU
设备的调频,调压,并且设备可以匹配自己的 governor
策略
devFreq framework
规范了设备调频调压的过程,也标准化了用户空间的控制接口,通过设备的需求,利用 governor
策略控制频率,进而根据 opp table
选择对应的电压
核心数据结构
devfreq_dev_profile 结构体
devfreq_dev_profile
结构体, 是OPP device
注册到 devfreq framework
的数据结构,主要包含 OPP
设备的频率信息和相关的回调函数,是 devfreq framework
和 OPP device
的交互接口,将 OPP device driver
对 devfreq
的使用,简化为对 devfreq profile
结构体的填充
// drivers/devfreq/devfreq.c
// include/linux/devfreq.h
struct devfreq_dev_profile {
// devfreq 注册的初始化频率
unsigned long initial_freq;
// governor polling 的时间间隔,单位 ms
unsigned int polling_ms;
// devfreq framework用于设定 OPP device frequency的回调函数
int (*target)(struct device *dev, unsigned long *freq, u32 flags);
// devfreq framework 用于获取 OPP device 负载状态的回调函数
int (*get_dev_status)(struct device *dev, struct devfreq_dev_status *stat);
// devfreq framework 用于获取当前频率的回调函数
int (*get_cur_freq)(struct device *dev, unsigned long *freq);
// 当 devfreq 设备从 devfreq framework 移除的时候调用
// 调用时机是 error 或者 devfreq_remove_device() call
void (*exit)(struct device *dev);
unsigned long *freq_table;
unsigned int max_state;
};
devfreq_governor 结构体
devfreq_governor
是 governor
注册到devfreq framework
的数据结构,主要包含 governor
的相关属性和具体的函数实现,是devfreq framework
和 governor
的交互接口
struct devfreq_governor {
// 将 devfreq_governor 作为链表节点进行管理
struct list_head node;
// governor name
const char name[DEVFREQ_NAME_LEN];
// 是否可以切换为其他 governor 1:不能切换
const unsigned int immutable;
// governor 注册到 devfreq framework 的算法实现函数,返回调整后的频率
int (*get_target_freq)(struct