在drivers/thermal/lmx_thermal.c 中的imx_thermal_probe中有注册cpu cool device
data->cdev = cpufreq_cooling_register(cpu_present_mask);
if (IS_ERR(data->cdev)) {
ret = PTR_ERR(data->cdev);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"failed to register cpufreq cooling device: %d\n",
ret);
return ret;
}
cpufreq_cooling_register->__cpufreq_cooling_register
static struct thermal_cooling_device *
__cpufreq_cooling_register(struct device_node *np,
const struct cpumask *clip_cpus, u32 capacitance,
get_static_t plat_static_func)
{
struct cpufreq_policy *policy;
struct thermal_cooling_device *cool_dev;
struct cpufreq_cooling_device *cpufreq_dev;
char dev_name[THERMAL_NAME_LENGTH];
struct cpufreq_frequency_table *pos, *table;
cpumask_var_t temp_mask;
unsigned int freq, i, num_cpus;
int ret;
struct thermal_cooling_device_ops *cooling_ops;
bool first;
//通过alloc_cpumask_var 申请一段空间,用来保存cpu_mask
if (!alloc_cpumask_var(&temp_mask, GFP_KERNEL))
return ERR_PTR(-ENOMEM);
//将要进行降温控制的cpu和所有在线的cpu相与,结果还是要控制的cpu
cpumask_and(temp_mask, clip_cpus, cpu_online_mask);
//得到cpu 调频的几种governer。调频的governer分别是cpufreq_performance/cpufreq_powersave/cpufreq_userspace/cpufreq_ondemand/cpufreq_conservative
policy = cpufreq_cpu_get(cpumask_first(temp_mask));
if (!policy) {
pr_debug("%s: CPUFreq policy not found\n", __func__);
cool_dev = ERR_PTR(-EPROBE_DEFER);
goto free_cpumask;
}
//得到调频的governer后就可以得到这可以调整的频率,毕竟调频governer就是调整cpu 频率的,所以肯定保存有cpu的频率
table = policy->freq_table;
if (!table) {
pr_debug("%s: CPUFreq table not found\n", __func__);
cool_dev = ERR_PTR(-ENODEV);
goto put_policy;
}
cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL);
if (!cpufreq_dev) {
cool_dev = ERR_PTR(-ENOMEM);
goto put_policy;
}
//使用cpumask_weight计算clip_cpus里面有几个bit为1,从而得到有几个cpu可以降温
num_cpus = cpumask_weight(clip_cpus);
cpufreq_dev->time_in_idle = kcalloc(num_cpus,
sizeof(*cpufreq_dev->time_in_idle),
GFP_KERNEL);
if (!cpufreq_dev->time_in_idle) {
cool_dev = ERR_PTR(-ENOMEM);
goto free_cdev;
}
cpufreq_dev->time_in_idle_timestamp =
kcalloc(num_cpus, sizeof(*cpufreq_dev->time_in_idle_timestamp),
GFP_KERNEL);
if (!cpufreq_dev->time_in_idle_timestamp) {
cool_dev = ERR_PTR(-ENOMEM);
goto free_time_in_idle;
}
//找到总共有几个频率可以调整
/* Find max levels */
cpufreq_for_each_valid_entry(pos, table)
cpufreq_dev->max_level++;
cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) *
cpufreq_dev->max_level, GFP_KERNEL);
if (!cpufreq_dev->freq_table) {
cool_dev = ERR_PTR(-ENOMEM);
goto free_time_in_idle_timestamp;
}
/* max_level is an index, not a counter */
cpufreq_dev->max_level--;
cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus);
//通过目前flow,这里的电流capacitance 为0,所以cpu cool device调整使用的ops就是cpufreq_cooling_ops
if (capacitance) {
cpufreq_dev->plat_get_static_power = plat_static_func;
ret = build_dyn_power_table(cpufreq_dev, capacitance);
if (ret) {
cool_dev = ERR_PTR(ret);
goto free_table;
}
cooling_ops = &cpufreq_power_cooling_ops;
} else {
cooling_ops = &cpufreq_cooling_ops;
}
ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL);
if (ret < 0) {
cool_dev = ERR_PTR(ret);
goto free_power_table;
}
cpufreq_dev->id = ret;
//将频率按从打到小排序保存在freq_table
/* Fill freq-table in descending order of frequencies */
for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) {
freq = find_next_max(table, freq);
cpufreq_dev->freq_table[i] = freq;
/* Warn for duplicate entries */
if (!freq)
pr_warn("%s: table has duplicate entries\n", __func__);
else
pr_debug("%s: freq:%u KHz\n", __func__, freq);
}
snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
cpufreq_dev->id);
//注册cool deivce
cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev,
cooling_ops);
if (IS_ERR(cool_dev))
goto remove_ida;
cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0];
cpufreq_dev->cool_dev = cool_dev;
mutex_lock(&cooling_list_lock);
/* Register the notifier for first cpufreq cooling device */
first = list_empty(&cpufreq_dev_list);
list_add(&cpufreq_dev->node, &cpufreq_dev_list);
mutex_unlock(&cooling_list_lock);
if (first)
cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
CPUFREQ_POLICY_NOTIFIER);
}
前面的分析我们知道对cool device来所调节是通过thermal_cooling_device_ops来进行,本例中的thermal_cooling_device_ops为
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,
};
最终在governer中通过set_cur_state来调节
static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus);
unsigned int clip_freq;
/* Request state should be less than max_level */
if (WARN_ON(state > cpufreq_device->max_level))
return -EINVAL;
/* Check if the old cooling action is same as new cooling action */
if (cpufreq_device->cpufreq_state == state)
return 0;
//从freq_table中得到需要调整的频率
clip_freq = cpufreq_device->freq_table[state];
cpufreq_device->cpufreq_state = state;
cpufreq_device->clipped_freq = clip_freq;
//通过cpu调频的框架来将更新cpu的频率
cpufreq_update_policy(cpu);
return 0;
}
thermal的cpu cool device
最新推荐文章于 2023-03-21 11:44:09 发布