From e92e4035e09ae1c8e02f92e3d6b7ffa68a9957ca Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Tue, 23 Feb 2016 13:08:31 -0700 Subject: [PATCH] ANDROID: GKI: drivers: cpu_cooling: allow platform freq mitigation Allow platform drivers to register with CPU cooling with their frequency mitigation functions. This allows the platform drivers to provide the callbacks to get the current ceil limit and to set the floor and ceil limits for the cpu. Change-Id: I47960b002bf1bce1cd588de2892de46793a95562 Signed-off-by: Lina Iyer (cherry picked from commit 986fde1710c194bede83bf62eb542e6f05af3886) Signed-off-by: Mark Salyzyn Bug: 154153737 --- drivers/thermal/cpu_cooling.c | 56 ++++++++++++++++++++++++++++++++--- include/linux/cpu_cooling.h | 17 +++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 438f62129b5b..06339a0b470b 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -91,6 +92,7 @@ struct cpufreq_cooling_device { struct cpufreq_policy *policy; struct list_head node; struct time_in_idle *idle_time; + struct cpu_cooling_ops *plat_ops; }; static DEFINE_IDA(cpufreq_ida); @@ -342,7 +344,16 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, cpufreq_cdev->cpufreq_state = state; cpufreq_cdev->clipped_freq = clip_freq; - cpufreq_update_policy(cpufreq_cdev->policy->cpu); + /* Check if the device has a platform mitigation function that + * can handle the CPU freq mitigation, if not, notify cpufreq + * framework. + */ + if (cpufreq_cdev->plat_ops && + cpufreq_cdev->plat_ops->ceil_limit) + cpufreq_cdev->plat_ops->ceil_limit(cpufreq_cdev->policy->cpu, + clip_freq); + else + cpufreq_update_policy(cpufreq_cdev->policy->cpu); return 0; } @@ -524,6 +535,9 @@ static struct notifier_block thermal_cpufreq_notifier_block = { * @policy: cpufreq policy * Normally this should be same as cpufreq policy->related_cpus. * @try_model: true if a power model should be used + * @plat_mitig_func: function that does the mitigation by changing the + * frequencies (Optional). By default, cpufreq framweork will + * be notified of the new limits. * * This interface function registers the cpufreq cooling device with the name * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq @@ -535,7 +549,8 @@ static struct notifier_block thermal_cpufreq_notifier_block = { */ static struct thermal_cooling_device * __cpufreq_cooling_register(struct device_node *np, - struct cpufreq_policy *policy, bool try_model) + struct cpufreq_policy *policy, bool try_model, + struct cpu_cooling_ops *plat_ops) { struct thermal_cooling_device *cdev; struct cpufreq_cooling_device *cpufreq_cdev; @@ -589,6 +604,8 @@ __cpufreq_cooling_register(struct device_node *np, #endif cooling_ops = &cpufreq_cooling_ops; + cpufreq_cdev->plat_ops = plat_ops; + ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL); if (ret < 0) { cdev = ERR_PTR(ret); @@ -642,7 +659,7 @@ free_cdev: struct thermal_cooling_device * cpufreq_cooling_register(struct cpufreq_policy *policy) { - return __cpufreq_cooling_register(NULL, policy, false); + return __cpufreq_cooling_register(NULL, policy, false, NULL); } EXPORT_SYMBOL_GPL(cpufreq_cooling_register); @@ -678,7 +695,7 @@ of_cpufreq_cooling_register(struct cpufreq_policy *policy) } if (of_find_property(np, "#cooling-cells", NULL)) { - cdev = __cpufreq_cooling_register(np, policy, true); + cdev = __cpufreq_cooling_register(np, policy, true, NULL); if (IS_ERR(cdev)) { pr_err("cpu_cooling: cpu%d is not running as cooling device: %ld\n", policy->cpu, PTR_ERR(cdev)); @@ -691,6 +708,37 @@ of_cpufreq_cooling_register(struct cpufreq_policy *policy) } EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register); +/** + * cpufreq_platform_cooling_register() - create cpufreq cooling device with + * additional platform specific mitigation function. + * + * @clip_cpus: cpumask of cpus where the frequency constraints will happen + * @plat_ops: the platform mitigation functions that will be called insted of + * cpufreq, if provided. + * + * Return: a valid struct thermal_cooling_device pointer on success, + * on failure, it returns a corresponding ERR_PTR(). + */ +struct thermal_cooling_device * +cpufreq_platform_cooling_register(struct cpufreq_policy *policy, + struct cpu_cooling_ops *plat_ops) +{ + struct device_node *cpu_node; + struct thermal_cooling_device *cdev = NULL; + + cpu_node = of_cpu_device_node_get(policy->cpu); + if (!cpu_node) { + pr_err("No cpu node\n"); + return ERR_PTR(-EINVAL); + } + cdev = __cpufreq_cooling_register(cpu_node, policy, false, + plat_ops); + + of_node_put(cpu_node); + return cdev; +} +EXPORT_SYMBOL(cpufreq_platform_cooling_register); + /** * cpufreq_cooling_unregister - function to remove cpufreq cooling device. * @cdev: thermal cooling device pointer. diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h index de0dafb9399d..e2bf9373f987 100644 --- a/include/linux/cpu_cooling.h +++ b/include/linux/cpu_cooling.h @@ -30,6 +30,12 @@ struct cpufreq_policy; +typedef int (*plat_mitig_t)(int cpu, u32 clip_freq); + +struct cpu_cooling_ops { + plat_mitig_t ceil_limit, floor_limit; +}; + #ifdef CONFIG_CPU_THERMAL /** * cpufreq_cooling_register - function to create cpufreq cooling device. @@ -38,6 +44,10 @@ struct cpufreq_policy; struct thermal_cooling_device * cpufreq_cooling_register(struct cpufreq_policy *policy); +struct thermal_cooling_device * +cpufreq_platform_cooling_register(struct cpufreq_policy *policy, + struct cpu_cooling_ops *ops); + /** * cpufreq_cooling_unregister - function to remove cpufreq cooling device. * @cdev: thermal cooling device pointer. @@ -51,6 +61,13 @@ cpufreq_cooling_register(struct cpufreq_policy *policy) return ERR_PTR(-ENOSYS); } +static inline struct thermal_cooling_device * +cpufreq_platform_cooling_register(struct cpufreq_policy *policy, + struct cpu_cooling_ops *ops) +{ + return NULL; +} + static inline void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) {