Move the cpu capacity bits out of arch/arm/ and into the CPUfreq driver. Not all ARM devices will use CPUfreq and it is unsafe to assume as such in topology.c.
Instead, use the new capacity_ops introduced into CFS. If this code is generic enough then it could be factored and shared via a header to make it easier for other CPUfreq drivers to take advantage of it. Signed-off-by: Mike Turquette <mturque...@linaro.org> --- This approach simply builds on top of Morten's series. I am not sure that the per-cpu method is the best way to go in the future. And if so I imagine that the CPUfreq core could provide everything except for the cpu_eff part. In general I think that the overlap between CPUfreq drivers and arch/arm/kernel/topology.c is something that needs to addresssed soon, as both pieces of code are re-inventing parts of each other. arch/arm/include/asm/topology.h | 2 ++ arch/arm/kernel/topology.c | 42 ++------------------------------- drivers/cpufreq/arm_big_little.c | 51 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h index 2fe85ff..3951232 100644 --- a/arch/arm/include/asm/topology.h +++ b/arch/arm/include/asm/topology.h @@ -14,6 +14,8 @@ struct cputopo_arm { }; extern struct cputopo_arm cpu_topology[NR_CPUS]; +extern unsigned long max_raw_capacity; +DECLARE_PER_CPU(unsigned long, cpu_raw_capacity); #define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id) #define topology_core_id(cpu) (cpu_topology[cpu].core_id) diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index 5f049ec..a2c9b5f 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -79,8 +79,8 @@ static unsigned long *__cpu_capacity; static unsigned long middle_capacity = 1; -static unsigned long max_raw_capacity = 1; -static DEFINE_PER_CPU(unsigned long, cpu_raw_capacity); +unsigned long max_raw_capacity = 1; +DEFINE_PER_CPU(unsigned long, cpu_raw_capacity); /* * Iterate all CPUs' descriptor in DT and compute the efficiency @@ -175,44 +175,6 @@ static void update_cpu_capacity(unsigned int cpu) cpu, arch_scale_freq_capacity(NULL, cpu)); } -/* - * Scheduler load-tracking scale-invariance - * - * Provides the scheduler with a scale-invariance correction factor that - * compensates for frequency scaling and micro-architecture differences between - * cpus. - */ - -static DEFINE_PER_CPU(atomic_long_t, cpu_curr_freq); -static DEFINE_PER_CPU(atomic_long_t, cpu_max_freq); - -/* cpufreq callback function setting current cpu frequency */ -void arch_scale_set_curr_freq(int cpu, unsigned long freq) -{ - atomic_long_set(&per_cpu(cpu_curr_freq, cpu), freq); -} - -/* cpufreq callback function setting max cpu frequency */ -void arch_scale_set_max_freq(int cpu, unsigned long freq) -{ - atomic_long_set(&per_cpu(cpu_max_freq, cpu), freq); -} - -unsigned long arch_scale_load_capacity(int cpu) -{ - unsigned long curr = atomic_long_read(&per_cpu(cpu_curr_freq, cpu)); - unsigned long max = atomic_long_read(&per_cpu(cpu_max_freq, cpu)); - unsigned long ret; - - if (!max || !per_cpu(cpu_raw_capacity, cpu)) - return SCHED_CAPACITY_SCALE; - - ret = (curr * SCHED_CAPACITY_SCALE) / max; - ret = (ret * per_cpu(cpu_raw_capacity, cpu)) / max_raw_capacity; - - return ret; -} - #else static inline void parse_dt_topology(void) {} static inline void update_cpu_capacity(unsigned int cpuid) {} diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index a46c223..5baffbd 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -31,7 +31,10 @@ #include <linux/slab.h> #include <linux/topology.h> #include <linux/types.h> +#include <linux/sched.h> +#include <linux/rcupdate.h> #include <asm/bL_switcher.h> +#include <asm/topology.h> #include "arm_big_little.h" @@ -533,9 +536,52 @@ static struct notifier_block bL_switcher_notifier = { .notifier_call = bL_cpufreq_switcher_notifier, }; +/* + * Scheduler load-tracking scale-invariance + * + * Provides the scheduler with a scale-invariance correction factor that + * compensates for frequency scaling and micro-architecture differences between + * cpus. + */ + +static DEFINE_PER_CPU(atomic_long_t, cpu_curr_freq); +static DEFINE_PER_CPU(atomic_long_t, cpu_max_freq); + +/* cpufreq callback function setting current cpu frequency */ +void arch_scale_set_curr_freq(int cpu, unsigned long freq) +{ + atomic_long_set(&per_cpu(cpu_curr_freq, cpu), freq); +} + +/* cpufreq callback function setting max cpu frequency */ +void arch_scale_set_max_freq(int cpu, unsigned long freq) +{ + atomic_long_set(&per_cpu(cpu_max_freq, cpu), freq); +} + +/* + * scale_load_capacity returns the current capacity for a given cpu, adjusted + * for micro-architectural differences and taking into accout cpu frequency + */ +unsigned long scale_load_capacity(int cpu) +{ + unsigned long curr = atomic_long_read(&per_cpu(cpu_curr_freq, cpu)); + unsigned long max = atomic_long_read(&per_cpu(cpu_max_freq, cpu)); + unsigned long ret; + + if (!max || !per_cpu(cpu_raw_capacity, cpu)) + return SCHED_CAPACITY_SCALE; + + ret = (curr * SCHED_CAPACITY_SCALE) / max; + ret = (ret * per_cpu(cpu_raw_capacity, cpu)) / max_raw_capacity; + + return ret; +} + int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) { int ret, i; + unsigned long flags; if (arm_bL_ops) { pr_debug("%s: Already registered: %s, exiting\n", __func__, @@ -550,6 +596,11 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) arm_bL_ops = ops; + spin_lock_irqsave(&cfs_capacity_ops.lock, flags); + cfs_capacity_ops.get_capacity = scale_load_capacity; + spin_unlock_irqrestore(&cfs_capacity_ops.lock, flags); + synchronize_rcu(); + ret = bL_switcher_get_enabled(); set_switching_enabled(ret); -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/