From 98222f8f2204746681a58bb50efd77f1b6fb5d68 Mon Sep 17 00:00:00 2001 From: Hyeonseong Gil Date: Mon, 11 Jul 2016 15:54:19 +0900 Subject: [PATCH] [COMMON] thermal: cpu_cooling: add static power table If cpu_cooling is registered for power_allocator governor, build static power table with coefficient from ECT and look up it in accordance with temperature and voltage. Resolved migration conflicts from kernel 4.9 to 4.14. - rename cpufreq_device -> cpufreq_cdev - allowed_cpus -> policy->related_cpus Change-Id: I516c9f5796cda6b4e64c9448a6565086443369a8 Signed-off-by: Hyeonseong Gil --- drivers/thermal/cpu_cooling.c | 142 ++++++++++++++++++++++++++++++++-- include/linux/cpu_cooling.h | 5 ++ 2 files changed, 139 insertions(+), 8 deletions(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index dc35593a0d5b..49ceb0394f2e 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -35,6 +35,8 @@ #include #include +#include +#include /* * Cooling state <-> CPUFreq frequency @@ -231,6 +233,130 @@ static int update_freq_table(struct cpufreq_cooling_device *cpufreq_cdev, return 0; } +static int build_static_power_table(struct cpufreq_cooling_device *cpufreq_cdev) +{ + int i, j; + int ids = cal_asv_get_ids_info(0); + int asv_group = cal_asv_get_grp(0, 0); + void *gen_block; + struct ect_gen_param_table *volt_temp_param, *asv_param; + + gen_block = ect_get_block("GEN"); + if (gen_block == NULL) { + pr_err("%s: Failed to get gen block from ECT\n", __func__); + return -EINVAL; + } + + volt_temp_param = ect_gen_param_get_table(gen_block, "DTM_MNGS_VOLT_TEMP"); + asv_param = ect_gen_param_get_table(gen_block, "DTM_MNGS_ASV"); + + if (volt_temp_param && asv_param) { + cpufreq_cdev->leakage_volt_size = volt_temp_param->num_of_row - 1; + cpufreq_cdev->leakage_temp_size = volt_temp_param->num_of_col - 1; + + cpufreq_cdev->leakage_coeff = kzalloc(sizeof(int) * + volt_temp_param->num_of_row * + volt_temp_param->num_of_col, + GFP_KERNEL); + if (!cpufreq_cdev->leakage_coeff) + goto err_mem; + + cpufreq_cdev->asv_coeff = kzalloc(sizeof(int) * + asv_param->num_of_row * + asv_param->num_of_col, + GFP_KERNEL); + if (!cpufreq_cdev->asv_coeff) + goto free_leakage_coeff; + + cpufreq_cdev->leakage_table = kzalloc(sizeof(int) * + volt_temp_param->num_of_row * + volt_temp_param->num_of_col, + GFP_KERNEL); + if (!cpufreq_cdev->leakage_table) + goto free_asv_coeff; + + memcpy(cpufreq_cdev->leakage_coeff, volt_temp_param->parameter, + sizeof(int) * volt_temp_param->num_of_row * volt_temp_param->num_of_col); + memcpy(cpufreq_cdev->asv_coeff, asv_param->parameter, + sizeof(int) * asv_param->num_of_row * asv_param->num_of_col); + memcpy(cpufreq_cdev->leakage_table, volt_temp_param->parameter, + sizeof(int) * volt_temp_param->num_of_row * volt_temp_param->num_of_col); + } else { + pr_err("%s: Failed to get param table from ECT\n", __func__); + return -EINVAL; + } + + for (i = 1; i <= cpufreq_cdev->leakage_volt_size; i++) { + long asv_coeff = (long)cpufreq_cdev->asv_coeff[3 * i + 0] * asv_group * asv_group + + (long)cpufreq_cdev->asv_coeff[3 * i + 1] * asv_group + + (long)cpufreq_cdev->asv_coeff[3 * i + 2]; + asv_coeff = asv_coeff / 100; + + for (j = 1; j <= cpufreq_cdev->leakage_temp_size; j++) { + long leakage_coeff = (long)cpufreq_cdev->leakage_coeff[i * (cpufreq_cdev->leakage_temp_size + 1) + j]; + leakage_coeff = ids * leakage_coeff * asv_coeff; + leakage_coeff = leakage_coeff / 100000; + cpufreq_cdev->leakage_table[i * (cpufreq_cdev->leakage_temp_size + 1) + j] = (int)leakage_coeff; + } + } + + return 0; + +free_asv_coeff: + kfree(cpufreq_cdev->asv_coeff); +free_leakage_coeff: + kfree(cpufreq_cdev->leakage_coeff); +err_mem: + return -ENOMEM; +} + +static int lookup_static_power(struct cpufreq_cooling_device *cpufreq_cdev, + unsigned long voltage, int temperature, u32 *power) +{ + int volt_index = 0, temp_index = 0; + int num_cpus; + int max_cpus; + struct cpufreq_policy *policy = cpufreq_cdev->policy; + struct cpumask *cpumask = policy->related_cpus; + cpumask_t tempmask; + + cpumask_and(&tempmask, cpumask, cpu_online_mask); + max_cpus = cpumask_weight(cpumask); + num_cpus = cpumask_weight(&tempmask); + voltage = voltage / 1000; + temperature = temperature / 1000; + + for (volt_index = 0; volt_index <= cpufreq_cdev->leakage_volt_size; volt_index++) { + if (voltage < cpufreq_cdev->leakage_table[volt_index * (cpufreq_cdev->leakage_temp_size + 1)]) { + volt_index = volt_index - 1; + break; + } + } + + if (volt_index == 0) + volt_index = 1; + + if (volt_index > cpufreq_cdev->leakage_volt_size) + volt_index = cpufreq_cdev->leakage_volt_size; + + for (temp_index = 0; temp_index <= cpufreq_cdev->leakage_temp_size; temp_index++) { + if (temperature < cpufreq_cdev->leakage_table[temp_index]) { + temp_index = temp_index - 1; + break; + } + } + + if (temp_index == 0) + temp_index = 1; + + if (temp_index > cpufreq_cdev->leakage_temp_size) + temp_index = cpufreq_cdev->leakage_temp_size; + + *power = (unsigned int)cpufreq_cdev->leakage_table[volt_index * (cpufreq_cdev->leakage_temp_size + 1) + temp_index] * num_cpus / max_cpus; + + return 0; +} + static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev, u32 freq) { @@ -314,10 +440,7 @@ static int get_static_power(struct cpufreq_cooling_device *cpufreq_cdev, unsigned long freq_hz = freq * 1000; struct device *dev; - if (!cpufreq_cdev->plat_get_static_power) { - *power = 0; - return 0; - } + *power = 0; dev = get_cpu_device(policy->cpu); WARN_ON(!dev); @@ -338,8 +461,7 @@ static int get_static_power(struct cpufreq_cooling_device *cpufreq_cdev, return -EINVAL; } - return cpufreq_cdev->plat_get_static_power(cpumask, tz->passive_delay, - voltage, power); + return lookup_static_power(cpufreq_cdev, voltage, tz->temperature, power); } /** @@ -757,14 +879,18 @@ __cpufreq_cooling_register(struct device_node *np, } if (capacitance) { - cpufreq_cdev->plat_get_static_power = plat_static_func; - ret = update_freq_table(cpufreq_cdev, capacitance); if (ret) { cdev = ERR_PTR(ret); goto remove_ida; } + ret = build_static_power_table(cpufreq_cdev); + if (ret) { + cdev = ERR_PTR(ret); + goto remove_ida; + } + cooling_ops = &cpufreq_power_cooling_ops; } else { cooling_ops = &cpufreq_cooling_ops; diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h index b23da6f0e0b3..505602017fc9 100644 --- a/include/linux/cpu_cooling.h +++ b/include/linux/cpu_cooling.h @@ -67,6 +67,11 @@ struct cpufreq_cooling_device { struct list_head node; struct time_in_idle *idle_time; get_static_t plat_get_static_power; + int *leakage_table; + int *leakage_coeff; + int *asv_coeff; + unsigned int leakage_volt_size; + unsigned int leakage_temp_size; }; #ifdef CONFIG_CPU_THERMAL -- 2.20.1