This patch add an interface which allows to change the weight of a CPU cooling device. It changes the allocated power in every thermal zone were this device is pinned.
The wieght varies from 0 to 1024 (0.0 to 1.0) and is multipiled by requested power in IPA thermal governor. With this patch it is possible to tune the algorithm which calculates and grants power for thermal actors, so some CPUs get higher freqencies as their operating limits.
Signed-off-by: Lukasz Luba l.luba@partner.samsung.com --- drivers/thermal/cpu_cooling.c | 19 +++++++++++ drivers/thermal/thermal_core.c | 59 ++++++++++++++++++++++++++++++++++ include/linux/cpu_cooling.h | 11 +++++++ include/linux/thermal.h | 3 ++ 4 files changed, 92 insertions(+)
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index dfd23245f778..0360cdd0826b 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -736,6 +736,25 @@ cpufreq_cooling_register(struct cpufreq_policy *policy) } EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
+bool cpufreq_cooling_test_related_cpu(struct thermal_cooling_device *cdev, + int cpu) +{ + struct cpufreq_cooling_device *cpufreq_cdev; + struct cpufreq_policy *policy; + + if (cdev && cdev->devdata) { + cpufreq_cdev = cdev->devdata; + if (cpufreq_cdev->policy) { + policy = cpufreq_cdev->policy; + if (cpumask_test_cpu(cpu, policy->related_cpus)) + return true; + } + } + + return false; +} +EXPORT_SYMBOL_GPL(cpufreq_cooling_test_related_cpu); + /** * of_cpufreq_cooling_register - function to create cpufreq cooling device. * @policy: cpufreq policy diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 6ab982309e6a..2fc143ac8552 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -9,6 +9,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/cpu_cooling.h> #include <linux/module.h> #include <linux/device.h> #include <linux/err.h> @@ -779,6 +780,64 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, } EXPORT_SYMBOL_GPL(thermal_zone_bind_cooling_device);
+static void +thermal_update_weight(struct thermal_instance *instance, unsigned long weight) +{ + instance->weight = weight; +} + +static bool thermal_cdev_in_tz(struct thermal_cooling_device *cdev, + struct thermal_zone_device *tz) +{ + struct thermal_instance *pos; + + list_for_each_entry(pos, &tz->thermal_instances, tz_node) + if (pos->cdev == cdev) + return true; + + return false; +} + +int thermal_cpu_cdev_set_weight(int cpu, unsigned long weight) +{ + struct thermal_cooling_device *cdev; + struct thermal_instance *instance; + struct thermal_zone_device *tz; + + mutex_lock(&thermal_list_lock); + list_for_each_entry(cdev, &thermal_cdev_list, node) { + if (cpufreq_cooling_test_related_cpu(cdev, cpu)) + goto update; + } + + mutex_unlock(&thermal_list_lock); + return -ENODEV; + +update: + mutex_unlock(&thermal_list_lock); + + mutex_lock(&cdev->lock); + list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) + thermal_update_weight(instance, weight); + mutex_unlock(&cdev->lock); + + /* Update thermal zones which are pinned to this cooling device. + * It will trigger recalculation of the states. + */ + mutex_lock(&thermal_list_lock); + list_for_each_entry(tz, &thermal_tz_list, node) { + if (thermal_cdev_in_tz(cdev, tz)) + thermal_zone_device_update(tz, + THERMAL_EVENT_UNSPECIFIED); + + } + mutex_unlock(&thermal_list_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(thermal_cpu_cdev_set_weight); + + /** * thermal_zone_unbind_cooling_device() - unbind a cooling device from a * thermal zone. diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h index de0dafb9399d..c875cde35879 100644 --- a/include/linux/cpu_cooling.h +++ b/include/linux/cpu_cooling.h @@ -44,6 +44,10 @@ cpufreq_cooling_register(struct cpufreq_policy *policy); */ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
+ +bool cpufreq_cooling_test_related_cpu(struct thermal_cooling_device *cdev, + int cpu); + #else /* !CONFIG_CPU_THERMAL */ static inline struct thermal_cooling_device * cpufreq_cooling_register(struct cpufreq_policy *policy) @@ -56,6 +60,13 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) { return; } + +static inline +bool cpufreq_cooling_test_related_cpu(struct thermal_cooling_device *cdev, + int cpu) +{ + return false; +} #endif /* CONFIG_CPU_THERMAL */
#if defined(CONFIG_THERMAL_OF) && defined(CONFIG_CPU_THERMAL) diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 5f4705f46c2f..baef42ccb3a5 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -458,6 +458,7 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *, struct thermal_cooling_device *, int); void thermal_cdev_update(struct thermal_cooling_device *); void thermal_notify_framework(struct thermal_zone_device *, int); +int thermal_cpu_cdev_set_weight(int cpu, unsigned long weight); #else static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev) { return false; } @@ -529,6 +530,8 @@ static inline void thermal_cdev_update(struct thermal_cooling_device *cdev) static inline void thermal_notify_framework(struct thermal_zone_device *tz, int trip) { } +static inline +int thermal_cpu_cdev_set_weight(int cpu, unsigned long weight) {} #endif /* CONFIG_THERMAL */
#if defined(CONFIG_NET) && IS_ENABLED(CONFIG_THERMAL)