ANDROID: implement max frequency capping
Implements the Max Frequency Capping Engine (MFCE) getter function topology_get_max_freq_scale() to provide the scheduler with a maximum frequency scaling correction factor for more accurate cpu capacity handling by being able to deal with max frequency capping. This scaling factor describes the influence of running a cpu with a current maximum frequency (policy) lower than the maximum possible frequency (cpuinfo). The factor is: policy_max_freq(cpu) << SCHED_CAPACITY_SHIFT / cpuinfo_max_freq(cpu) It also implements the MFCE setter function arch_set_max_freq_scale() which is called from cpufreq_set_policy(). Signed-off-by: Ionela Voinescu <ionela.voinescu@arm.com> Signed-off-by: Dietmar Eggemann <dietmar.eggemann@arm.com> [Trivial cherry-pick issue in cpufreq.c] Signed-off-by: Quentin Perret <quentin.perret@arm.com> Change-Id: I59e52861ee260755ab0518fe1f7183a2e4e3d0fc
This commit is contained in:
committed by
Quentin Perret
parent
6c401bf9b0
commit
c4ed8aa44d
@@ -18,6 +18,8 @@
|
|||||||
#include <linux/cpuset.h>
|
#include <linux/cpuset.h>
|
||||||
|
|
||||||
DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
|
DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
|
||||||
|
DEFINE_PER_CPU(unsigned long, max_cpu_freq);
|
||||||
|
DEFINE_PER_CPU(unsigned long, max_freq_scale) = SCHED_CAPACITY_SCALE;
|
||||||
|
|
||||||
void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
|
void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
|
||||||
unsigned long max_freq)
|
unsigned long max_freq)
|
||||||
@@ -27,8 +29,29 @@ void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
|
|||||||
|
|
||||||
scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq;
|
scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq;
|
||||||
|
|
||||||
for_each_cpu(i, cpus)
|
for_each_cpu(i, cpus) {
|
||||||
per_cpu(freq_scale, i) = scale;
|
per_cpu(freq_scale, i) = scale;
|
||||||
|
per_cpu(max_cpu_freq, i) = max_freq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void arch_set_max_freq_scale(struct cpumask *cpus,
|
||||||
|
unsigned long policy_max_freq)
|
||||||
|
{
|
||||||
|
unsigned long scale, max_freq;
|
||||||
|
int cpu = cpumask_first(cpus);
|
||||||
|
|
||||||
|
if (cpu > nr_cpu_ids)
|
||||||
|
return;
|
||||||
|
|
||||||
|
max_freq = per_cpu(max_cpu_freq, cpu);
|
||||||
|
if (!max_freq)
|
||||||
|
return;
|
||||||
|
|
||||||
|
scale = (policy_max_freq << SCHED_CAPACITY_SHIFT) / max_freq;
|
||||||
|
|
||||||
|
for_each_cpu(cpu, cpus)
|
||||||
|
per_cpu(max_freq_scale, cpu) = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEFINE_MUTEX(cpu_scale_mutex);
|
static DEFINE_MUTEX(cpu_scale_mutex);
|
||||||
|
|||||||
@@ -159,6 +159,12 @@ __weak void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(arch_set_freq_scale);
|
EXPORT_SYMBOL_GPL(arch_set_freq_scale);
|
||||||
|
|
||||||
|
__weak void arch_set_max_freq_scale(struct cpumask *cpus,
|
||||||
|
unsigned long policy_max_freq)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(arch_set_max_freq_scale);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a generic cpufreq init() routine which can be used by cpufreq
|
* This is a generic cpufreq init() routine which can be used by cpufreq
|
||||||
* drivers of SMP systems. It will do following:
|
* drivers of SMP systems. It will do following:
|
||||||
@@ -2244,6 +2250,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
|||||||
policy->max = new_policy->max;
|
policy->max = new_policy->max;
|
||||||
trace_cpu_frequency_limits(policy);
|
trace_cpu_frequency_limits(policy);
|
||||||
|
|
||||||
|
arch_set_max_freq_scale(policy->cpus, policy->max);
|
||||||
|
|
||||||
policy->cached_target_freq = UINT_MAX;
|
policy->cached_target_freq = UINT_MAX;
|
||||||
|
|
||||||
pr_debug("new min and max freqs are %u - %u kHz\n",
|
pr_debug("new min and max freqs are %u - %u kHz\n",
|
||||||
|
|||||||
@@ -33,4 +33,12 @@ unsigned long topology_get_freq_scale(int cpu)
|
|||||||
return per_cpu(freq_scale, cpu);
|
return per_cpu(freq_scale, cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECLARE_PER_CPU(unsigned long, max_freq_scale);
|
||||||
|
|
||||||
|
static inline
|
||||||
|
unsigned long topology_get_max_freq_scale(struct sched_domain *sd, int cpu)
|
||||||
|
{
|
||||||
|
return per_cpu(max_freq_scale, cpu);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _LINUX_ARCH_TOPOLOGY_H_ */
|
#endif /* _LINUX_ARCH_TOPOLOGY_H_ */
|
||||||
|
|||||||
@@ -955,6 +955,8 @@ extern unsigned int arch_freq_get_on_cpu(int cpu);
|
|||||||
|
|
||||||
extern void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
|
extern void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
|
||||||
unsigned long max_freq);
|
unsigned long max_freq);
|
||||||
|
extern void arch_set_max_freq_scale(struct cpumask *cpus,
|
||||||
|
unsigned long policy_max_freq);
|
||||||
|
|
||||||
/* the following are really really optional */
|
/* the following are really really optional */
|
||||||
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
|
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
|
||||||
|
|||||||
Reference in New Issue
Block a user