summaryrefslogtreecommitdiffstats
path: root/meta-eas/recipes-kernel/linux/linux-renesas/0027-arm64-parse-cpu-capacity-dmips-mhz-from-DT.patch
diff options
context:
space:
mode:
authorFrode Isaksen <fisaksen@baylibre.com>2017-12-19 11:15:35 +0000
committerJan-Simon Moeller <jsmoeller@linuxfoundation.org>2018-02-07 11:47:29 +0000
commitc4a6287185179732dfc1e903c195ff90c19f1065 (patch)
treed35f5010dbd952e40f5c178322026445b55757c1 /meta-eas/recipes-kernel/linux/linux-renesas/0027-arm64-parse-cpu-capacity-dmips-mhz-from-DT.patch
parent109dea1d5c5a38807b098b588584636ae636a302 (diff)
This layer provides Energy Aware Scheduling (EAS) patcheseel_5.1.0eel_5.0.3eel_5.0.2eel/5.1.0eel/5.0.3eel/5.0.25.1.05.0.35.0.2eel
For the moment only for Renesas R-Car Gen3 SoC's. Can be expanded for other SoC's by setting the machine feature biglittle and provide the relevant EAS patches. Bug-AGL: SPEC-813 Change-Id: I2b5e69c515c33e57be19b30466fe208d7b8ac1a5 Signed-off-by: Frode Isaksen <fisaksen@baylibre.com>
Diffstat (limited to 'meta-eas/recipes-kernel/linux/linux-renesas/0027-arm64-parse-cpu-capacity-dmips-mhz-from-DT.patch')
-rw-r--r--meta-eas/recipes-kernel/linux/linux-renesas/0027-arm64-parse-cpu-capacity-dmips-mhz-from-DT.patch212
1 files changed, 212 insertions, 0 deletions
diff --git a/meta-eas/recipes-kernel/linux/linux-renesas/0027-arm64-parse-cpu-capacity-dmips-mhz-from-DT.patch b/meta-eas/recipes-kernel/linux/linux-renesas/0027-arm64-parse-cpu-capacity-dmips-mhz-from-DT.patch
new file mode 100644
index 0000000..0b35caf
--- /dev/null
+++ b/meta-eas/recipes-kernel/linux/linux-renesas/0027-arm64-parse-cpu-capacity-dmips-mhz-from-DT.patch
@@ -0,0 +1,212 @@
+From f7b42d6b9a5d61382b11dfa52484bd86f41fc32e Mon Sep 17 00:00:00 2001
+From: Juri Lelli <juri.lelli@arm.com>
+Date: Thu, 19 Nov 2015 16:18:38 +0000
+Subject: [PATCH 27/92] arm64: parse cpu capacity-dmips-mhz from DT
+
+With the introduction of cpu capacity-dmips-mhz bindings, CPU capacities
+can now be calculated from values extracted from DT and information
+coming from cpufreq. Add parsing of DT information at boot time, and
+complement it with cpufreq information. Also, store such information
+using per CPU variables, as we do for arm.
+
+Caveat: the information provided by this patch will start to be used in
+the future. We need to #define arch_scale_cpu_capacity to something
+provided in arch, so that scheduler's default implementation (which gets
+used if arch_scale_cpu_capacity is not defined) is overwritten.
+
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Will Deacon <will.deacon@arm.com>
+Cc: Mark Brown <broonie@kernel.org>
+Cc: Sudeep Holla <sudeep.holla@arm.com>
+Signed-off-by: Juri Lelli <juri.lelli@arm.com>
+---
+ arch/arm64/kernel/topology.c | 149 ++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 148 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
+index 694f6de..c1277c19 100644
+--- a/arch/arm64/kernel/topology.c
++++ b/arch/arm64/kernel/topology.c
+@@ -19,10 +19,152 @@
+ #include <linux/nodemask.h>
+ #include <linux/of.h>
+ #include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/cpufreq.h>
+
+ #include <asm/cputype.h>
+ #include <asm/topology.h>
+
++static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
++
++unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
++{
++ return per_cpu(cpu_scale, cpu);
++}
++
++static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
++{
++ per_cpu(cpu_scale, cpu) = capacity;
++}
++
++static u32 capacity_scale;
++static u32 *raw_capacity;
++static bool cap_parsing_failed;
++
++static void __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
++{
++ int ret;
++ u32 cpu_capacity;
++
++ if (cap_parsing_failed)
++ return;
++
++ ret = of_property_read_u32(cpu_node,
++ "capacity-dmips-mhz",
++ &cpu_capacity);
++ if (!ret) {
++ if (!raw_capacity) {
++ raw_capacity = kcalloc(num_possible_cpus(),
++ sizeof(*raw_capacity),
++ GFP_KERNEL);
++ if (!raw_capacity) {
++ pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
++ cap_parsing_failed = true;
++ return;
++ }
++ }
++ capacity_scale = max(cpu_capacity, capacity_scale);
++ raw_capacity[cpu] = cpu_capacity;
++ pr_debug("cpu_capacity: %s cpu_capacity=%u (raw)\n",
++ cpu_node->full_name, raw_capacity[cpu]);
++ } else {
++ if (raw_capacity) {
++ pr_err("cpu_capacity: missing %s raw capacity\n",
++ cpu_node->full_name);
++ pr_err("cpu_capacity: partial information: fallback to 1024 for all CPUs\n");
++ }
++ cap_parsing_failed = true;
++ kfree(raw_capacity);
++ }
++}
++
++static void normalize_cpu_capacity(void)
++{
++ u64 capacity;
++ int cpu;
++
++ if (!raw_capacity || cap_parsing_failed)
++ return;
++
++ pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale);
++ for_each_possible_cpu(cpu) {
++ pr_debug("cpu_capacity: cpu=%d raw_capacity=%u\n",
++ cpu, raw_capacity[cpu]);
++ capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
++ / capacity_scale;
++ set_capacity_scale(cpu, capacity);
++ pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
++ cpu, arch_scale_cpu_capacity(NULL, cpu));
++ }
++}
++
++#ifdef CONFIG_CPU_FREQ
++static cpumask_var_t cpus_to_visit;
++static bool cap_parsing_done;
++
++static int
++init_cpu_capacity_callback(struct notifier_block *nb,
++ unsigned long val,
++ void *data)
++{
++ struct cpufreq_policy *policy = data;
++ int cpu;
++
++ if (cap_parsing_failed || cap_parsing_done)
++ return 0;
++
++ 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));
++ cpumask_andnot(cpus_to_visit,
++ cpus_to_visit,
++ policy->related_cpus);
++ for_each_cpu(cpu, policy->related_cpus) {
++ raw_capacity[cpu] = arch_scale_cpu_capacity(NULL, cpu) *
++ policy->cpuinfo.max_freq / 1000UL;
++ capacity_scale = max(raw_capacity[cpu], capacity_scale);
++ }
++ if (cpumask_empty(cpus_to_visit)) {
++ normalize_cpu_capacity();
++ kfree(raw_capacity);
++ pr_debug("cpu_capacity: parsing done\n");
++ cap_parsing_done = true;
++ }
++ }
++ return 0;
++}
++
++static struct notifier_block init_cpu_capacity_notifier = {
++ .notifier_call = init_cpu_capacity_callback,
++};
++
++static int __init register_cpufreq_notifier(void)
++{
++ if (cap_parsing_failed)
++ return -EINVAL;
++
++ 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);
++}
++core_initcall(register_cpufreq_notifier);
++#else
++static int __init free_raw_capacity(void)
++{
++ kfree(raw_capacity);
++
++ return 0;
++}
++core_initcall(free_raw_capacity);
++#endif
++
+ static int __init get_cpu_for_node(struct device_node *node)
+ {
+ struct device_node *cpu_node;
+@@ -34,6 +176,7 @@ static int __init get_cpu_for_node(struct device_node *node)
+
+ for_each_possible_cpu(cpu) {
+ if (of_get_cpu_node(cpu, NULL) == cpu_node) {
++ parse_cpu_capacity(cpu_node, cpu);
+ of_node_put(cpu_node);
+ return cpu;
+ }
+@@ -178,13 +321,17 @@ static int __init parse_dt_topology(void)
+ * cluster with restricted subnodes.
+ */
+ map = of_get_child_by_name(cn, "cpu-map");
+- if (!map)
++ if (!map) {
++ cap_parsing_failed = true;
+ goto out;
++ }
+
+ ret = parse_cluster(map, 0);
+ if (ret != 0)
+ goto out_map;
+
++ normalize_cpu_capacity();
++
+ /*
+ * Check that all cores are in the topology; the SMP code will
+ * only mark cores described in the DT as possible.
+--
+1.9.1
+