diff options
Diffstat (limited to 'meta-eas/recipes-kernel/linux/linux-renesas/0036-arm-Frequency-invariant-load-tracking-support.patch')
-rw-r--r-- | meta-eas/recipes-kernel/linux/linux-renesas/0036-arm-Frequency-invariant-load-tracking-support.patch | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/meta-eas/recipes-kernel/linux/linux-renesas/0036-arm-Frequency-invariant-load-tracking-support.patch b/meta-eas/recipes-kernel/linux/linux-renesas/0036-arm-Frequency-invariant-load-tracking-support.patch new file mode 100644 index 0000000..5c8419e --- /dev/null +++ b/meta-eas/recipes-kernel/linux/linux-renesas/0036-arm-Frequency-invariant-load-tracking-support.patch @@ -0,0 +1,134 @@ +From f2b29716bba30b235f4c3a4292bb0ca0465e0031 Mon Sep 17 00:00:00 2001 +From: Dietmar Eggemann <dietmar.eggemann@arm.com> +Date: Wed, 16 Nov 2016 19:46:35 +0000 +Subject: [PATCH 36/92] arm: Frequency-invariant load-tracking support + +Implements arch-specific function scale_freq_capacity() which provides +the following frequency scaling factor: + + current_freq(cpu) << SCHED_CAPACITY_SHIFT / max_supported_freq(cpu) + +The debug output in init_cpu_capacity_callback() has been changed to be +able to distinguish whether cpu capacity and max frequency or only max +frequency has been parsed. The latter case happens on systems where there +is no or broken cpu capacity binding (cpu node property +capacity-dmips-mhz) information. + +One possible consumer of this is the Per-Entity Load Tracking (PELT) +mechanism of the scheduler's CFS class. + +The actual wiring up to the scheduler isn't provided by this patch. + +Cc: Russell King <linux@arm.linux.org.uk> +Signed-off-by: Dietmar Eggemann <dietmar.eggemann@arm.com> +(cherry picked from commit fd3bdcb6e9f895ba22de4295e29de4f4e1ed3e77) +Signed-off-by: Gaku Inami <gaku.inami.xw@bp.renesas.com> +--- + arch/arm/kernel/topology.c | 57 +++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 51 insertions(+), 6 deletions(-) + +diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c +index b030d01..e521b07 100644 +--- a/arch/arm/kernel/topology.c ++++ b/arch/arm/kernel/topology.c +@@ -219,6 +219,8 @@ static void normalize_cpu_capacity(void) + static bool cap_parsing_done; + static void parsing_done_workfn(struct work_struct *work); + static DECLARE_WORK(parsing_done_work, parsing_done_workfn); ++static DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE; ++static DEFINE_PER_CPU(unsigned long, max_freq); + + static int + init_cpu_capacity_callback(struct notifier_block *nb, +@@ -233,13 +235,14 @@ static void normalize_cpu_capacity(void) + + switch (val) { + case CPUFREQ_NOTIFY: +- pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] (to_visit=%*pbl)\n", +- cpumask_pr_args(policy->related_cpus), +- cpumask_pr_args(cpus_to_visit)); ++ pr_debug("cpu_capacity: calling %s for CPUs [%*pbl] (to_visit=%*pbl)\n", ++ __func__, cpumask_pr_args(policy->related_cpus), ++ cpumask_pr_args(cpus_to_visit)); + cpumask_andnot(cpus_to_visit, + cpus_to_visit, + policy->related_cpus); + for_each_cpu(cpu, policy->related_cpus) { ++ per_cpu(max_freq, cpu) = policy->cpuinfo.max_freq; + if (cap_parsing_failed) + continue; + raw_capacity[cpu] = arch_scale_cpu_capacity(NULL, cpu) * +@@ -250,8 +253,10 @@ static void normalize_cpu_capacity(void) + if (!cap_parsing_failed) { + normalize_cpu_capacity(); + kfree(raw_capacity); ++ pr_debug("cpu_capacity: parsing done"); ++ } else { ++ pr_debug("cpu_capacity: max frequency parsing done"); + } +- pr_debug("cpu_capacity: parsing done"); + cap_parsing_done = true; + schedule_work(&parsing_done_work); + } +@@ -263,16 +268,56 @@ static void normalize_cpu_capacity(void) + .notifier_call = init_cpu_capacity_callback, + }; + ++unsigned long scale_freq_capacity(struct sched_domain *sd, int cpu) ++{ ++ return per_cpu(freq_scale, cpu); ++} ++ ++static void set_freq_scale(unsigned int cpu, unsigned long freq) ++{ ++ unsigned long max = per_cpu(max_freq, cpu); ++ ++ if (!max) ++ return; ++ ++ per_cpu(freq_scale, cpu) = (freq << SCHED_CAPACITY_SHIFT) / max; ++} ++ ++static int ++set_freq_scale_callback(struct notifier_block *nb, ++ unsigned long val, ++ void *data) ++{ ++ struct cpufreq_freqs *freq = data; ++ ++ switch (val) { ++ case CPUFREQ_PRECHANGE: ++ set_freq_scale(freq->cpu, freq->new); ++ } ++ return 0; ++} ++ ++static struct notifier_block set_freq_scale_notifier = { ++ .notifier_call = set_freq_scale_callback, ++}; + static int __init register_cpufreq_notifier(void) + { ++ int ret; ++ + if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) { + pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n"); + return -ENOMEM; + } + cpumask_copy(cpus_to_visit, cpu_possible_mask); + +- return cpufreq_register_notifier(&init_cpu_capacity_notifier, +- CPUFREQ_POLICY_NOTIFIER); ++ ret = cpufreq_register_notifier(&init_cpu_capacity_notifier, ++ CPUFREQ_POLICY_NOTIFIER); ++ ++ if (ret) ++ return ret; ++ ++ return cpufreq_register_notifier(&set_freq_scale_notifier, ++ CPUFREQ_TRANSITION_NOTIFIER); + } + core_initcall(register_cpufreq_notifier); + +-- +1.9.1 + |