From aaf602d4647e9d0325c72403150a54639489c35b Mon Sep 17 00:00:00 2001 From: Sultan Alsawaf Date: Wed, 5 Feb 2025 18:57:32 -0800 Subject: [PATCH] arch_topology: Introduce minimum frequency scale The scheduler is unaware of the applied min_freq limit to a CPU, which is useful information when predicting the frequency a CPU will run at for energy efficiency purposes. Export this information via arch_scale_min_freq_capacity() and wire it up for arm64. Change-Id: Icdff7628c095185280e95dd965d497e6f740c871 Signed-off-by: Sultan Alsawaf Signed-off-by: Richard Raya --- arch/arm64/include/asm/topology.h | 6 ++++++ drivers/base/arch_topology.c | 18 ++++++++++++++++++ drivers/cpufreq/cpufreq.c | 3 +++ include/linux/arch_topology.h | 10 ++++++++++ include/linux/cpufreq.h | 8 ++++++++ kernel/sched/sched.h | 8 ++++++++ 6 files changed, 53 insertions(+) diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index b7bd70520a77..0bf1586adce3 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -47,6 +47,12 @@ int pcibus_to_node(struct pci_bus *bus); /* Enable topology flag updates */ #define arch_update_cpu_topology topology_update_cpu_topology +/* Define function to set the minimum frequency scaling factor */ +#define arch_set_min_freq_scale topology_set_min_freq_scale + +/* Define function to get the minimum frequency scaling factor */ +#define arch_scale_min_freq_capacity topology_get_min_freq_scale + #include #endif /* _ASM_ARM_TOPOLOGY_H */ diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 78c741b19397..979c26b0a724 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -106,6 +106,24 @@ void arch_set_max_freq_scale(struct cpumask *cpus, per_cpu(max_freq_scale, cpu) = scale; } +DEFINE_PER_CPU(unsigned long, arch_min_freq_scale); +EXPORT_PER_CPU_SYMBOL_GPL(arch_min_freq_scale); + +void topology_set_min_freq_scale(const struct cpumask *cpus, + unsigned long min_freq, unsigned long max_freq) +{ + unsigned long scale; + int i; + + if (WARN_ON_ONCE(!max_freq)) + return; + + scale = (min_freq * per_cpu(cpu_scale, cpumask_any(cpus))) / max_freq; + + for_each_cpu(i, cpus) + per_cpu(arch_min_freq_scale, i) = scale; +} + static DEFINE_MUTEX(cpu_scale_mutex); DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0e421b895099..5a87940e3c9b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2282,6 +2282,9 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, trace_cpu_frequency_limits(policy->max, policy->min, policy->cpu); + arch_set_min_freq_scale(policy->related_cpus, policy->min, + policy->cpuinfo.max_freq); + policy->cached_target_freq = UINT_MAX; pr_debug("new min and max freqs are %u - %u kHz\n", diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h index 36c3c50eadfe..dd2da0c73aef 100644 --- a/include/linux/arch_topology.h +++ b/include/linux/arch_topology.h @@ -44,6 +44,16 @@ unsigned long topology_get_freq_scale(struct sched_domain *sd, int cpu) return per_cpu(freq_scale, cpu); } +DECLARE_PER_CPU(unsigned long, arch_min_freq_scale); + +static inline unsigned long topology_get_min_freq_scale(int cpu) +{ + return per_cpu(arch_min_freq_scale, cpu); +} + +void topology_set_min_freq_scale(const struct cpumask *cpus, + unsigned long min_freq, unsigned long max_freq); + DECLARE_PER_CPU(unsigned long, max_freq_scale); DECLARE_PER_CPU(unsigned long, max_thermal_scale); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index ced3c6b51e1b..6dfefefcade4 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -923,6 +923,14 @@ extern void arch_set_max_freq_scale(struct cpumask *cpus, unsigned long policy_max_freq); extern void arch_set_max_thermal_scale(struct cpumask *cpus, unsigned long max_thermal_freq); +#ifndef arch_set_min_freq_scale +static __always_inline +void arch_set_min_freq_scale(const struct cpumask *cpus, + unsigned long min_freq, + unsigned long max_freq) +{ +} +#endif /* the following are really really optional */ extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs; extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index c818d6c23d46..4a2d3d907057 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2029,6 +2029,14 @@ unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu) } #endif +#ifndef arch_scale_min_freq_capacity +static __always_inline +unsigned long arch_scale_min_freq_capacity(int cpu) +{ + return 0; +} +#endif + #ifdef CONFIG_SMP static inline unsigned long capacity_of(int cpu) {