sched/power: register only the real cooling device not instances
authorLukasz Luba <l.luba@partner.samsung.com>
Wed, 7 Nov 2018 19:41:27 +0000 (20:41 +0100)
committerLukasz Luba <l.luba@partner.samsung.com>
Fri, 17 May 2019 07:15:45 +0000 (09:15 +0200)
Check if the instance is not pointing to the already known
cooling device. Skip registration of instances, take into account
only real cooling devices.

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

index 22d5758b89ef30669e39cff3c8ddb8d92d3d957c..d2ba44befaae7db19911e152d18dce5f28beba15 100644 (file)
@@ -485,6 +485,7 @@ struct _thermal_zone {
        struct thermal_zone_device *tz;
        bool single_cooling_dev;
        struct list_head node;
+       struct list_head cooling_list;
 };
 
 struct _cooling_dev {
@@ -498,6 +499,11 @@ struct _cooling_dev {
        unsigned long int cpus[0];
 };
 
+struct _cooling_instance {
+       struct list_head node;
+       struct _cooling_dev *cooling;
+};
+
 static LIST_HEAD(tz_list);
 static LIST_HEAD(cdev_list);
 static DEFINE_MUTEX(tz_list_lock);
@@ -623,11 +629,37 @@ static void cleanup_percpu_cooling_dev(struct _cooling_dev *cooling)
        kfree(cooling);
 }
 
+/* called with 'cdev_list_lock' taken */
+static struct _cooling_dev
+*find_registered_cooling_dev(struct thermal_cooling_device *cdev)
+{
+       struct _cooling_dev *cooling;
+
+       list_for_each_entry(cooling, &cdev_list, node)
+               if (cdev == cooling->cdev)
+                       return cooling;
+
+       return NULL;
+}
+
+static bool cdev_in_instance_list(struct _thermal_zone *zone,
+                                 struct thermal_cooling_device *cdev)
+{
+       struct _cooling_instance *inst;
+
+       list_for_each_entry(inst, &zone->cooling_list, node)
+               if (cdev == inst->cooling->cdev)
+                       return true;
+
+       return false;
+}
+
 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 _cooling_instance *_inst, *tmp;
        struct thermal_cooling_device *cdev;
        int i = 0;
        int cpu;
@@ -639,9 +671,19 @@ static int sched_power_gov_bind(struct thermal_zone_device *tz)
        if (!zone)
                return -ENOMEM;
 
+       INIT_LIST_HEAD(&zone->cooling_list);
+
        mutex_lock(&cdev_list_lock);
        list_for_each_entry(inst, &tz->thermal_instances, tz_node) {
                cdev = inst->cdev;
+
+               if (cdev_in_instance_list(zone, cdev))
+                       continue;
+
+               cooling = find_registered_cooling_dev(cdev);
+               if (cooling)
+                       goto handle_cooling_instance;
+
                if (is_cpufreq_cooling(cdev))
                        cpus_size = cpumask_size();
                else
@@ -666,11 +708,20 @@ static int sched_power_gov_bind(struct thermal_zone_device *tz)
                        }
                }
                list_add(&cooling->node, &cdev_list);
-
-               pr_info("registred new cooling device for CPUs\n"); 
+               pr_info("created new CPU cooling device\n");
 
                prev_cooling = cooling;
                i++;
+
+handle_cooling_instance:
+               _inst = kmalloc(sizeof(*_inst), GFP_KERNEL);
+               if (!_inst)
+                       goto cleanup;
+
+               _inst->cooling = cooling;
+               list_add(&_inst->node, &zone->cooling_list);
+
+               pr_info("pinned cooling device into zone\n");
        }
        mutex_unlock(&cdev_list_lock);
 
@@ -692,6 +743,11 @@ cleanup:
                prev_cooling = cooling;
        }
        mutex_unlock(&cdev_list_lock);
+
+       list_for_each_entry_safe(_inst, tmp,  &zone->cooling_list, node) {
+               list_del(&_inst->node);
+               kfree(_inst);
+       }
        kfree(zone);
 
        return -ENOMEM;