diff options
| -rw-r--r-- | kernel/sched/core.c | 67 | ||||
| -rw-r--r-- | kernel/sched/sched.h | 2 |
2 files changed, 69 insertions, 0 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index e6bc81b37369..9a53673cd810 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -74,6 +74,7 @@ #include <linux/binfmts.h> #include <linux/context_tracking.h> #include <linux/compiler.h> +#include <linux/cpufreq.h> #include <asm/switch_to.h> #include <asm/tlb.h> @@ -286,6 +287,12 @@ __read_mostly int scheduler_running; */ int sysctl_sched_rt_runtime = 950000; +/* + * Maximum possible frequency across all cpus. Task demand and cpu + * capacity (cpu_power) metrics could be scaled in reference to it. + */ +static unsigned int max_possible_freq = 1; + /* cpus with isolated domains */ cpumask_var_t cpu_isolated_map; @@ -7389,6 +7396,63 @@ void __init sched_init_smp(void) } #endif /* CONFIG_SMP */ +static int cpufreq_notifier_policy(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct cpufreq_policy *policy = (struct cpufreq_policy *)data; + int i; + + if (val != CPUFREQ_NOTIFY) + return 0; + + for_each_cpu(i, policy->related_cpus) { + cpu_rq(i)->min_freq = policy->min; + cpu_rq(i)->max_freq = policy->max; + } + + max_possible_freq = max(max_possible_freq, policy->cpuinfo.max_freq); + + return 0; +} + +static int cpufreq_notifier_trans(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct cpufreq_freqs *freq = (struct cpufreq_freqs *)data; + unsigned int cpu = freq->cpu, new_freq = freq->new; + + if (val != CPUFREQ_POSTCHANGE) + return 0; + + cpu_rq(cpu)->cur_freq = new_freq; + + return 0; +} + +static struct notifier_block notifier_policy_block = { + .notifier_call = cpufreq_notifier_policy +}; + +static struct notifier_block notifier_trans_block = { + .notifier_call = cpufreq_notifier_trans +}; + +static int register_sched_callback(void) +{ + int ret; + + ret = cpufreq_register_notifier(¬ifier_policy_block, + CPUFREQ_POLICY_NOTIFIER); + + if (!ret) + ret = cpufreq_register_notifier(¬ifier_trans_block, + CPUFREQ_TRANSITION_NOTIFIER); + + return 0; +} + +core_initcall(register_sched_callback); + int in_sched_functions(unsigned long addr) { return in_lock_functions(addr) || @@ -7526,6 +7590,9 @@ void __init sched_init(void) rq->online = 0; rq->idle_stamp = 0; rq->avg_idle = 2*sysctl_sched_migration_cost; + rq->cur_freq = 0; + rq->max_freq = 0; + rq->min_freq = 0; rq->max_idle_balance_cost = sysctl_sched_migration_cost; rq->cstate = 0; rq->wakeup_latency = 0; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index fffe2623477a..4061d3f9d93d 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -643,6 +643,8 @@ struct rq { u64 max_idle_balance_cost; #endif + int cur_freq, max_freq, min_freq; + #ifdef CONFIG_IRQ_TIME_ACCOUNTING u64 prev_irq_time; #endif |
