summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/sched/core.c67
-rw-r--r--kernel/sched/sched.h2
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(&notifier_policy_block,
+ CPUFREQ_POLICY_NOTIFIER);
+
+ if (!ret)
+ ret = cpufreq_register_notifier(&notifier_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