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 <sultan@kerneltoast.com>
Signed-off-by: Richard Raya <rdxzv.dev@gmail.com>
This commit is contained in:
Sultan Alsawaf 2025-02-05 18:57:32 -08:00 committed by Richard Raya
parent a2d50bb156
commit aaf602d464
6 changed files with 53 additions and 0 deletions

View File

@ -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 <asm-generic/topology.h>
#endif /* _ASM_ARM_TOPOLOGY_H */

View File

@ -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;

View File

@ -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",

View File

@ -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);

View File

@ -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;

View File

@ -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)
{