diff options
author | Frode Isaksen <fisaksen@baylibre.com> | 2017-12-19 11:15:35 +0000 |
---|---|---|
committer | Jan-Simon Moeller <jsmoeller@linuxfoundation.org> | 2018-02-07 11:47:29 +0000 |
commit | c4a6287185179732dfc1e903c195ff90c19f1065 (patch) | |
tree | d35f5010dbd952e40f5c178322026445b55757c1 /meta-eas/recipes-kernel/linux/linux-renesas/0027-arm64-parse-cpu-capacity-dmips-mhz-from-DT.patch | |
parent | 109dea1d5c5a38807b098b588584636ae636a302 (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.patch | 212 |
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 + |