linux devfreq框架
介绍
devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework for Non-CPU Devices
。
在Linux 里面,CPU调频有cpufreq框架,那么其他模块调频用什么框架呢?比如DDR、DSP、GPU等等,答案是devfreq框架。
这个框架提供了以下功能:
- 提供了一套标准框架,用于任意设备的调频调压功能
- 提供了几个governor。也可以自定义governor并注册
- 提供了工作队列机制,用于周期性进行load monitor,并调整频率
- 在用户层提供了sysfs,类似于cpufreq的功能
软件框架
与cpufreq框架类似,
- 对上:devfreq对上提供sysfs节点,供用户空间配置,包括频率范围、调频周期、调频governor
- 内部:维护devfeq、governord等信息、suspend/resume流程、通知机制、load monitor机制等等
- 对下,devfreq实现了统一的接口,包括devfreq注册、governor注册等
几个重要的概念和模块,
-
governor
与cpufreq类似,调频策略的实现,目前有simple_ondemand、powersave、performance、passive等。还可以自己实现更多的governor,并注册到devfreq core。 -
devfreq driver
驱动开发者为了实现DDR、DSP、GPU等设备实现的具体驱动。主要功能是调整频率、获取频率、选择governor等 -
devfreq event
如果可以调频的设备,拥有一套load monitor的机制,比如使能、去使能、设置事件、获取事件,那么可以使用此框架进行注册和管理。
工作流程
文件
文件 | 作用 | |
---|---|---|
drivers/devfreq/devfreq.c | devfreq core功能,sysfs文件节点、devfreq注册、governor注册公共接口、 | |
include/linux/devfreq.h | ||
drivers/devfreq/devfreq-event.c | devfreq event对硬件负载监控单元功能进行了封装,使能、去使能、获取设置事件等功能 | |
主要数据结构
struct devfreq_dev_profile
struct devfreq_dev_profile {
unsigned long initial_freq;
unsigned int polling_ms;
enum devfreq_timer timer;
bool is_cooling_device;
int (*target)(struct device *dev, unsigned long *freq, u32 flags);
int (*get_dev_status)(struct device *dev,
struct devfreq_dev_status *stat);
int (*get_cur_freq)(struct device *dev, unsigned long *freq);
void (*exit)(struct device *dev);
unsigned long *freq_table;
unsigned int max_state;
};
-
作用
驱动程序需要实现和定义的内容- 初始频率
- 调频周期
- 修改频率函数
- 获取频率函数
-
主要字段说明
字段 | 说明 | |
---|---|---|
initial_freq | 初始频率 | |
timer | 调频使用的定时器timer | |
target | 修改频率函数 | |
get_dev_status | 获取设备状态 | |
get_cur_freq | 通过硬件获取频率,不是软件保存的当前频率值 | |
exit | 可选, 驱动退出时,回调函数 |
struct devfreq
struct devfreq {
struct list_head node;
struct mutex lock;
struct device dev;
struct devfreq_dev_profile *profile;
const struct devfreq_governor *governor;
struct opp_table *opp_table;
struct notifier_block nb;
struct delayed_work work;
unsigned long *freq_table;
unsigned int max_state;
unsigned long previous_freq;
struct devfreq_dev_status last_status;
void *data; /* private data for governors */
struct dev_pm_qos_request user_min_freq_req;
struct dev_pm_qos_request user_max_freq_req;
unsigned long scaling_min_freq;
unsigned long scaling_max_freq;
bool stop_polling;
unsigned long suspend_freq;
unsigned long resume_freq;
atomic_t suspend_count;
/* information for device frequency transitions */
struct devfreq_stats stats;
struct srcu_notifier_head transition_notifier_list;
/* Pointer to the cooling device if used for thermal mitigation */
struct thermal_cooling_device *cdev;
struct notifier_block nb_min;
struct notifier_block nb_max;
};
-
作用
devfreq core维护的各设备的资源集合体。devm_devfreq_add_device
添加调频device后返回此资源体。- 具体设备的调频驱动
- 频率电压表opp
- 调度work
-
重要字段说明
字段 | 说明 | |
---|---|---|
node | devfreq core会把各设备添加个一个大的链表中 | |
profile | 此devfreq绑定的调频驱动 | |
governor | 此devfreq绑定的调频governor | |
opp_table | 此devfreq使用的opp | |
work | 创建周期的work | |
previous_freq | 上一次的频率 | |
user_min_freq_req | 通过sysfs设置的最低频率 | |
user_max_freq_req | 通过sysfs设置的最高频率 | |
scaling_min_freq | 设备支持的最低频率 | |
scaling_max_freq | 设备支持的最高频率 | |
data | governor使用的私有数据,比如simple_ondemand设置的上下阈值。passive需要的parent,获取频率 |
主要函数
devm_devfreq_add_device
参数1:设备指针
参数2:设备驱动实现的调频功能,主要实现部分
参数3:设备驱动选择的governor
参数4:governor使用的私有数据
struct devfreq *devm_devfreq_add_device(struct device *dev,
struct devfreq_dev_profile *profile,
const char *governor_name,
void *data)
devfreq_add_governor
注册新的governor
int devfreq_add_governor(struct devfreq_governor *governor)
调试
用户节点说明 https://github.com/torvalds/linux/blob/master/Documentation/ABI/testing/sysfs-class-devfreq
/sys/class/devfreq/
available_frequencies: 可用的频率列表
available_governors:可用的governor
cur_freq:当前频率
governor: 当前governor
max_freq:最大频率,综合qos(sysfs配置/其他模块请求)、hardware的结果
min_freq :最小频率,综合qos(sysfs配置/其他模块请求)、hardware的结果
polling_interval:governor调度的时间间隔,单位是ms
target_freq:目标频率
trans_stat:状态调整表