thermal的cpu cool device

来源:互联网 发布:vue.js 动态添加class 编辑:程序博客网 时间:2024/05/05 14:56
在drivers/thermal/lmx_thermal.c 中的imx_thermal_probe中有注册cpu cool devicedata->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_registerstatic 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_maskif (!alloc_cpumask_var(&temp_mask, GFP_KERNEL))return ERR_PTR(-ENOMEM);//将要进行降温控制的cpu和所有在线的cpu相与,结果还是要控制的cpucpumask_and(temp_mask, clip_cpus, cpu_online_mask);//得到cpu 调频的几种governer。调频的governer分别是cpufreq_performance/cpufreq_powersave/cpufreq_userspace/cpufreq_ondemand/cpufreq_conservativepolicy = 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_opsif (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__);elsepr_debug("%s: freq:%u KHz\n", __func__, freq);}snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", cpufreq_dev->id);//注册cool deivcecool_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;}

原创粉丝点击