Add basic support for handling cluster weight reqest.
Signed-off-by: Lukasz Luba l.luba@partner.samsung.com --- kernel/sched/power.c | 134 ++++++++++++++++++++++++++++--------------- kernel/sched/power.h | 36 ++++++++++++ 2 files changed, 123 insertions(+), 47 deletions(-)
diff --git a/kernel/sched/power.c b/kernel/sched/power.c index 8bd8502681e3..6c72a9bee8ac 100644 --- a/kernel/sched/power.c +++ b/kernel/sched/power.c @@ -22,6 +22,11 @@ static DEFINE_PER_CPU(struct cpu_power, cpu_power); DEFINE_PER_CPU(struct update_sched_power *, update_cpu_power);
+static LIST_HEAD(tz_list); +static LIST_HEAD(cdev_list); +static DEFINE_MUTEX(tz_list_lock); +static DEFINE_MUTEX(cdev_list_lock); + static struct sched_power sched_power;
void sched_power_set_update_func(int cpu, struct update_sched_power *update, @@ -176,7 +181,7 @@ static u64 cluster_power_budget(struct cpumask *cpus) }
static int -sched_power_reweight_cluster(int cpu, struct cpumask *cpus, unsigned int capacity, +sched_power_reweight_cpu(int cpu, struct cpumask *cpus, unsigned int capacity, unsigned int period, int flags) { /* int ret, i; */ @@ -210,6 +215,43 @@ sched_power_reweight_cluster(int cpu, struct cpumask *cpus, unsigned int capacit return 0; }
+static int sched_power_reweight_cluster(int cpu, struct cpumask *cpus, + int weight, int flags) +{ + struct _thermal_zone *zone, *system_zone = NULL; + struct _cooling_dev *cooling; + struct _cooling_instance *inst, *cluster_inst = NULL; + struct cpumask *cpumask; + + mutex_lock(&tz_list_lock); + list_for_each_entry(zone, &tz_list, node) { + if (zone->single_cooling_dev) + continue; + list_for_each_entry(inst, &zone->cooling_list, node) { + cpumask = to_cpumask(inst->cooling->cpus); + + if (cpumask_test_cpu(cpu, cpumask)) { + system_zone = zone; + cluster_inst = inst; + break; + } + } + } + mutex_unlock(&tz_list_lock); + + if (system_zone) { + mutex_lock(&system_zone->lock); + cluster_inst->weight = weight; + mutex_unlock(&system_zone->lock); + thermal_notify_framework(system_zone->tz, + system_zone->trip_ctrl_alg.desired_id); + } else { + return -ENODEV; + } + + return 0; +} + static int sched_power_cpu_capacity_request(int cpu, unsigned int capacity, unsigned int period, int flags) { @@ -222,16 +264,38 @@ static int sched_power_cpu_capacity_request(int cpu, unsigned int capacity, cpower = (&per_cpu(cpu_power, cpu));
//for cluster OR system wise - ret = sched_power_reweight_cluster(cpu, cpower->cluster_mask, capacity, + ret = sched_power_reweight_cpu(cpu, cpower->cluster_mask, capacity, period, flags);
return ret; }
+static int sched_power_handle_request(struct power_request *req) +{ + int ret; + struct cpu_power *cpower; + + cpower = (&per_cpu(cpu_power, req->cpu)); + + switch (req->flags) { + case SCHED_POWER_CPU_WEIGHT: + break; + case SCHED_POWER_CLUSTER_WEIGHT: + ret = sched_power_reweight_cluster(req->cpu, + cpower->cluster_mask, + req->weight, req->flags); + break; + default: + return; + } + + return 0; +} + static void sched_power_work(struct kthread_work *work) { struct sched_power *sp = container_of(work, struct sched_power, work); - int i; + int i, ret; struct cpu_power *cpower = NULL; struct power_request req; unsigned int w; @@ -240,15 +304,21 @@ static void sched_power_work(struct kthread_work *work) for_each_online_cpu(i) { cpower = (&per_cpu(cpu_power, i)); raw_spin_lock(&cpower->update_lock); - w = cpower->weight; + if (!cpower->req.time) { + raw_spin_unlock(&cpower->update_lock); + continue; + } req = cpower->req; - cpower->req.time = sched_clock(); + w = cpower->weight; + cpower->req.time = 0; cpower->weight = req.weight; raw_spin_unlock(&cpower->update_lock);
pr_info("cpower req poped\n"); - thermal_cpu_cdev_set_weight(req.cpu, req.weight); - need_update = true; + /* thermal_cpu_cdev_set_weight(req.cpu, req.weight); */ + ret = sched_power_handle_request(&req); + if (!ret) + need_update = true; }
if (need_update) @@ -470,46 +540,7 @@ fs_initcall(sched_power_init);
/////////////////thermal governor////////////////////////
-struct trip_ctrl_alg { - int switch_on_id; - int switch_on_temp; - int desired_id; - int desired_temp; - int k_p; - int k_i; - s64 integral; -}; - -struct _thermal_zone { - struct thermal_zone_device *tz; - bool single_cooling_dev; - int num_cooling; - struct list_head node; - struct list_head cooling_list; - struct trip_ctrl_alg trip_ctrl_alg; -}; - -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]; -}; - -struct _cooling_instance { - struct list_head node; - struct _cooling_dev *cooling; - u32 weight; -};
-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) @@ -669,14 +700,22 @@ static int share_power_budget(struct _thermal_zone *zone, u32 power_budget) if (!power) return -ENOMEM;
- /* estimate cooling dev's power and total power */ + /* The calculation two-loops split is needed due to taking + zone->lock only for protecting 'weights'. */ list_for_each_entry(inst, &zone->cooling_list, node) { get_requested_power(inst, zone, &power[i]); + i++; + }
+ mutex_lock(&zone->lock); + /* estimate cooling dev's power and total power */ + i = 0; + list_for_each_entry(inst, &zone->cooling_list, node) { power[i] = (inst->weight * power[i]) >> 10; sum_power += power[i]; i++; } + mutex_unlock(&zone->lock);
if (sum_power <= 0) goto cleanup; @@ -856,6 +895,7 @@ static int sched_power_gov_bind(struct thermal_zone_device *tz) return -ENOMEM;
INIT_LIST_HEAD(&zone->cooling_list); + mutex_init(&zone->lock);
mutex_lock(&cdev_list_lock); list_for_each_entry(inst, &tz->thermal_instances, tz_node) { diff --git a/kernel/sched/power.h b/kernel/sched/power.h index 340b3924ecd7..c7e92295cab1 100644 --- a/kernel/sched/power.h +++ b/kernel/sched/power.h @@ -66,5 +66,41 @@ struct cpu_power { struct cpumask *cluster_mask; };
+struct trip_ctrl_alg { + int switch_on_id; + int switch_on_temp; + int desired_id; + int desired_temp; + int k_p; + int k_i; + s64 integral; +}; + +struct _thermal_zone { + struct thermal_zone_device *tz; + bool single_cooling_dev; + int num_cooling; + struct list_head node; + struct list_head cooling_list; + struct trip_ctrl_alg trip_ctrl_alg; + struct mutex lock; +}; + +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]; +}; + +struct _cooling_instance { + struct list_head node; + struct _cooling_dev *cooling; + u32 weight; +};
#endif