diff --git a/kernel/sched/core.c b/kernel/sched/core.c index ee05163f9548fc098cc1e2022da284b0bf42c5f8..5eb068721d206ed1a6e71efe10ed5d20a07227bc 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -73,6 +73,7 @@ #include <linux/init_task.h> #include <linux/binfmts.h> #include <linux/context_tracking.h> +#include <linux/cpufreq.h> #include <asm/switch_to.h> #include <asm/tlb.h> @@ -299,6 +300,11 @@ __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; /* * __task_rq_lock - lock the rq @p resides on. @@ -6929,6 +6935,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); + const_debug unsigned int sysctl_timer_migration = 1; int in_sched_functions(unsigned long addr) @@ -7069,6 +7132,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; INIT_LIST_HEAD(&rq->cfs_tasks); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index a023ea5b4a67b1aea08fea8186a4b8c1e108d719..2cebc49f5e8419d59bdf5a7a130689ee5a231861 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -478,6 +478,8 @@ struct rq { u64 avg_idle; #endif + int cur_freq, max_freq, min_freq; + #ifdef CONFIG_IRQ_TIME_ACCOUNTING u64 prev_irq_time; #endif