Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92
mali_device_driver 分为两个部分 : platform_dependent_part 和 common_parts, 参见 mali_kbase_config_rk.c 开头部分的注释.
gpu dvfs核心控制在mali_kbase_dvfs.c中.
s_mali_dvfs_level_table 定义gpu所有可变的freq level以及对应的min utilisation和max utilisation.
static struct mali_dvfs_level_t s_mali_dvfs_level_table[] = {
{100000, 0, 70},
{160000, 50, 65},
{266000, 60, 78},
{350000, 65, 75},
{400000, 70, 75},
{500000, 90, 100},
};
不过它会被dts中的operating-points所覆盖
clk_gpu_dvfs_table: clk_gpu {
operating-points = <
/* KHz uV */
200000 1200000
300000 1200000
400000 1200000
>;
};
gpu dvfs运行时, common parts (metrics system)会周期地(20ms)通知回调 platform_dependent_part 中的函数 kbase_platform_dvfs_event(), 并传入当前的 gpu utilization.
dvfs_callback -> kbase_pm_get_dvfs_action -> kbase_platform_dvfs_event
int kbase_platform_dvfs_event(struct kbase_device *kbdev,
u32 utilisation, /* calculated_utilisation. */
u32 util_gl_share_no_use,
u32 util_cl_share_no_use[2])
{
struct rk_dvfs_t *dvfs = get_rk_dvfs(kbdev);
dvfs->utilisation = utilisation;
if (dvfs->is_enabled) {
/* run 'mali_dvfs_work' in 'mali_dvfs_wq', on cpu0. */
queue_work_on(0, dvfs->mali_dvfs_wq, &(dvfs->mali_dvfs_work));
}
return 1;
}
该 event 被转发到 mali_dvfs_event_proc() 中处理.
static void mali_dvfs_event_proc(struct work_struct *w)
{
int ret = 0;
struct rk_dvfs_t *dvfs = work_to_dvfs(w);
int temp = rockchip_tsadc_get_temp(1, 0);
if (INVALID_TEMP == temp) {
D("got invalid temp, reset to 0.");
temp = 0;
}
dvfs->sum_of_temps += temp;
dvfs->times_of_temp_measures++;
if (dvfs->times_of_temp_measures >= NUM_OF_TEMP_MEASURES_IN_A_SESSION) {
dvfs->temp = dvfs->sum_of_temps
/ NUM_OF_TEMP_MEASURES_IN_A_SESSION;
dvfs->times_of_temp_measures = 0;
dvfs->sum_of_temps = 0;
}
/*-------------------------------------------------------*/
mutex_lock(&(dvfs->dvfs_mutex));
if (is_overheated(dvfs)) {
if (could_jump_down(dvfs)) {
I("to jump down for overheated, temp:%d.",
dvfs->temp);
ret = jump_down_actually(dvfs);
if (ret)
E("fail to jump down, ret:%d.", ret);
} else {
W("overheated! temp:%d, but can't jump down anymore.",
dvfs->temp);
}
dvfs->temp = 0;
goto EXIT;
}
/* If calculated_utilisation asks current_level to jump up,
* and current_level could jump up,
* then .... */
if (dvfs->utilisation > get_util_max_threshold_of_curr_level(dvfs) &&
could_jump_up(dvfs)) {
inc_requests_to_jump_up(dvfs);
if (are_enough_jump_up_requests(dvfs)) {
V("to jump up to highest, util:%d, curr_level:%d.",
dvfs->utilisation,
get_current_level(dvfs));
ret = jump_up_to_highest_actually(dvfs);
if (ret) {
E("fail to jump up, ret:%d.", ret);
goto EXIT;
}
reset_requests_to_jump_up(dvfs);
}
reset_requests_to_jump_down(dvfs);
goto EXIT;
} else if (dvfs->utilisation
< get_util_min_threshold_of_curr_level(dvfs) &&
could_jump_down(dvfs)) {
inc_requests_to_jump_down(dvfs);
if (are_enough_jump_down_requests(dvfs)) {
V("to jump down actually, util:%d, curr_level:%d",
dvfs->utilisation,
get_current_level(dvfs));
jump_down_actually(dvfs);
reset_requests_to_jump_down(dvfs);
}
reset_requests_to_jump_up(dvfs);
goto EXIT;
} else {
reset_requests_to_jump_down(dvfs);
reset_requests_to_jump_up(dvfs);
V("stay in current_level, util:%d, curr_level:%d.",
dvfs->utilisation,
get_current_level(dvfs));
}
EXIT:
mutex_unlock(&(dvfs->dvfs_mutex));
}
a. 如果当前温度过高,那么执行jump_down_actually()下调频率.
b. 如果当前utilization 大于 max_utilization_of_current_dvfs_level, 则直接上跳到最高频率(jump_up_to_highest_actually() ).不过要满足NUM_OF_REQUESTS_TO_PERFORM_ACTUAL_JUMP_UP的次数才上跳.
c. 如果当前utilization 小于max_utilization_of_current_dvfs_level,则一级级下跳(jump_down_actually()).不过要满足NUM_OF_REQUESTS_TO_PERFORM_ACTUAL_JUMP_DOWN的次数才下跳.
如果觉得目前上跳策略太激进, 则可以在 mali_dvfs_event_proc() 进一步修改, 比如每次只上跳一级, 而不是直接到 highest.
原文地址 https://blog.csdn.net/kris_fei/article/details/78059392