sched/power: add thermal governor cooling devices and zones
authorLukasz Luba <l.luba@partner.samsung.com>
Tue, 6 Nov 2018 16:47:54 +0000 (17:47 +0100)
committerLukasz Luba <l.luba@partner.samsung.com>
Fri, 17 May 2019 07:15:44 +0000 (09:15 +0200)
The patch populated cooling devices for clusters and CPUs.

Signed-off-by: Lukasz Luba <l.luba@partner.samsung.com>
kernel/sched/power.c
kernel/sched/power.h

index 1976e5db8efcf6c1a5a2ef063362f606444f947e..22d5758b89ef30669e39cff3c8ddb8d92d3d957c 100644 (file)
@@ -5,6 +5,7 @@
  *  Copyright (C) 2018 Samsung
  */
 
+#define pr_fmt(fmt) "SCHED_POWER: " fmt
 
 #include <linux/sched.h>
 #include <linux/thermal.h>
@@ -480,6 +481,28 @@ fs_initcall(sched_power_init);
 
 /////////////////thermal governor////////////////////////
 
+struct _thermal_zone {
+       struct thermal_zone_device *tz;
+       bool single_cooling_dev;
+       struct list_head node;
+};
+
+struct _cooling_dev {
+       struct thermal_cooling_device *cdev;
+       struct list_head node;
+       int max_single_state; /* max state (0-highest) which means freqency */
+       int min_sum_single_idle; /* minimum sum of idle calculated for 'single'
+                                   zone. Other zones should not go bellow this
+                                   value for the same 'state' (frequency) */
+       bool cpu_dev;
+       unsigned long int cpus[0];
+};
+
+static LIST_HEAD(tz_list);
+static LIST_HEAD(cdev_list);
+static DEFINE_MUTEX(tz_list_lock);
+static DEFINE_MUTEX(cdev_list_lock);
+
 static int cdev_get_min_power(struct thermal_cooling_device *cdev,
                              u64 *min_power)
 {
@@ -521,22 +544,157 @@ static int controller_prepare_coefficents(struct thermal_zone_device *tz,
        return 0;
 }
 
+static struct _thermal_zone *find_zone(struct thermal_zone_device *tz)
+{
+       struct _thermal_zone *zone;
+
+       mutex_lock(&tz_list_lock);
+       list_for_each_entry(zone, &tz_list, node) {
+               if (zone->tz == tz) {
+                       mutex_unlock(&tz_list_lock);
+                       return zone;
+               }
+       }
+       mutex_unlock(&tz_list_lock);
+
+       return NULL;
+}
+static int inject_more_idle(struct _thermal_zone *zone)
+{
+
+       return 0;
+}
+
+static int throttle_single_cdev(struct _thermal_zone *zone)
+{
+
+
+       return 0;
+}
+
 static int sched_power_gov_throttle(struct thermal_zone_device *tz, int trip)
 {
+       struct thermal_cooling_device *cdev;
+       struct thermal_instance *inst;
+       u32 dev_power;
+       struct _thermal_zone *zone;
+       int ret;
+
+       zone = find_zone(tz);
+       if (!zone)
+               return -EINVAL;
+
+       if (zone->single_cooling_dev) {
+               /* ret = calc_power_budget(tz); */
+               ret = inject_more_idle(zone);
+               if (ret) {
+                       throttle_single_cdev(zone);
+                       power_actor_set_power(cdev, inst, dev_power);
+               }
+       } else {
+
+       }
+
 
        return 0;
 }
 
+static inline bool is_cpufreq_cooling(struct thermal_cooling_device *cdev)
+{
+       const char dev_name[] = "thermal-cpufreq-";
+
+       return strncmp(dev_name, cdev->type, strlen(dev_name)) ?
+               false : true;
+}
+
+static void cleanup_percpu_cooling_dev(struct _cooling_dev *cooling)
+{
+       int i;
+       struct cpumask *cpumask;
+       struct cpu_power *cpower;
+
+       cpumask = to_cpumask(cooling->cpus);
+       for_each_cpu(i, cpumask) {
+               cpower = (&per_cpu(cpu_power, i));
+               raw_spin_lock(&cpower->update_lock);
+               cpower->cooling = NULL;
+               raw_spin_unlock(&cpower->update_lock);
+       }
+       kfree(cooling);
+}
+
 static int sched_power_gov_bind(struct thermal_zone_device *tz)
 {
        struct thermal_instance *inst;
+       struct _thermal_zone *zone;
+       struct _cooling_dev *cooling, *prev_cooling;
+       struct thermal_cooling_device *cdev;
+       int i = 0;
+       int cpu;
+       int cpus_size;
+       struct cpumask *cpumask;
+       struct cpu_power *cpower;
+
+       zone = kzalloc(sizeof(*zone), GFP_KERNEL);
+       if (!zone)
+               return -ENOMEM;
 
+       mutex_lock(&cdev_list_lock);
        list_for_each_entry(inst, &tz->thermal_instances, tz_node) {
+               cdev = inst->cdev;
+               if (is_cpufreq_cooling(cdev))
+                       cpus_size = cpumask_size();
+               else
+                       cpus_size = 0;
+
+               cooling = kzalloc(sizeof(*cooling) + cpus_size, GFP_KERNEL);
+               if (!cooling)
+                       goto cleanup;
+
+               cooling->cpu_dev = !!cpus_size;
+               cooling->cdev = cdev;
+               if (cooling->cpu_dev) {
+                       cpumask = to_cpumask(cooling->cpus);
+
+                       cpufreq_cooling_copy_cpumask(cdev, cpumask);
+
+                       for_each_cpu(cpu, cpumask) {
+                               cpower = (&per_cpu(cpu_power, cpu));
+                               raw_spin_lock(&cpower->update_lock);
+                               cpower->cooling = cooling;
+                               raw_spin_unlock(&cpower->update_lock);
+                       }
+               }
+               list_add(&cooling->node, &cdev_list);
 
+               pr_info("registred new cooling device for CPUs\n"); 
 
+               prev_cooling = cooling;
+               i++;
        }
+       mutex_unlock(&cdev_list_lock);
+
+       zone->single_cooling_dev = (i == 1 ? true : false);
+       zone->tz = tz;
+
+       mutex_lock(&tz_list_lock);
+       list_add(&zone->node, &tz_list);
+       mutex_unlock(&tz_list_lock);
 
        return 0;
+
+cleanup:
+       list_for_each_entry_reverse(cooling, &prev_cooling->node, node) {
+               if (i-- == 0)
+                       break;
+               list_del(&prev_cooling->node);
+               cleanup_percpu_cooling_dev(prev_cooling);
+               prev_cooling = cooling;
+       }
+       mutex_unlock(&cdev_list_lock);
+       kfree(zone);
+
+       return -ENOMEM;
 }
 
 static void sched_power_gov_unbind(struct thermal_zone_device *tz)
index 8ce1409ea538a507d4ac9283b73c1298caa1bf02..da969b9bc30fb1993d4f1466a16609437a661a69 100644 (file)
@@ -9,6 +9,7 @@
 #define __SCHED_POWER_H__
 
 #include <linux/idle_inject.h>
+#include <linux/cpu_cooling.h>
 
 #include "sched.h"
 
@@ -38,6 +39,8 @@ struct power_request {
        int flags
 };
 
+struct _cooling_dev;
+
 struct cpu_power {
        struct update_sched_power update_power;
        unsigned int max_capacity;
@@ -51,6 +54,7 @@ struct cpu_power {
        struct sched_power *sched_power;
        struct power_request req;
        bool operating;
+       struct _cooling_dev *cooling;
        /* lock shared with thermal framework and/or cpufreq */
        raw_spinlock_t update_lock;
        struct idle_inject_device *ii_dev;