thermal: add interface for changing 'weight' of cpu cooling
authorLukasz Luba <l.luba@partner.samsung.com>
Tue, 23 Oct 2018 14:09:46 +0000 (16:09 +0200)
committerLukasz Luba <l.luba@partner.samsung.com>
Fri, 17 May 2019 07:15:33 +0000 (09:15 +0200)
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
drivers/thermal/thermal_core.c
include/linux/cpu_cooling.h
include/linux/thermal.h

index dfd23245f778a3193903d582e015bd27a7f50ad3..0360cdd0826bb92ac57ff65eeada81ebcac6ab1a 100644 (file)
@@ -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
index 6ab982309e6a04cd3c933850d34aabaaf3dd60e4..2fc143ac85526fe8f536dfb63249759d298ef6df 100644 (file)
@@ -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 @@ free_mem:
 }
 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.
index de0dafb9399dc0fb8022d364a3eedebca964138d..c875cde35879e02a7106f2dab87da52352925b85 100644 (file)
@@ -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)
index 5f4705f46c2f9ab8aae927304443807de8e27f4d..baef42ccb3a5f4eddb47fef516b6dabad00b5006 100644 (file)
@@ -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)