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 | 60 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-)
diff --git a/kernel/sched/power.c b/kernel/sched/power.c index 22d5758b89ef..d2ba44befaae 100644 --- a/kernel/sched/power.c +++ b/kernel/sched/power.c @@ -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 @@ static int sched_power_gov_bind(struct thermal_zone_device *tz) 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;