@@ -100,11 +100,11 @@ static void sugov_fast_switch(struct cpufreq_policy *policy,
}
static void sugov_update_commit(struct sugov_policy *sg_policy, u64 time,
- unsigned int next_freq)
+ int cpu, bool remote, unsigned int next_freq)
{
struct cpufreq_policy *policy = sg_policy->policy;
- if (policy->fast_switch_enabled) {
+ if (policy->fast_switch_enabled && !remote) {
if (sg_policy->next_freq == next_freq) {
trace_cpu_frequency(policy->cur, policy->cpu);
return;
@@ -116,7 +116,7 @@ static void sugov_update_commit(struct sugov_policy *sg_policy, u64 time,
sg_policy->next_freq = next_freq;
sg_policy->last_freq_update_time = time;
sg_policy->work_in_progress = true;
- irq_work_queue(&sg_policy->irq_work);
+ irq_work_queue_on(&sg_policy->irq_work, cpu);
}
}
@@ -206,6 +206,20 @@ static void sugov_update_single(struct update_util_data *hook, u64 time,
struct cpufreq_policy *policy = sg_policy->policy;
unsigned long util, max;
unsigned int next_f;
+ int cpu, this_cpu = smp_processor_id();
+ bool remote;
+
+ if (policy->dvfs_possible_from_any_cpu) {
+ /*
+ * Avoid sending IPI to 'hook->cpu' if this CPU can change
+ * frequency on its behalf.
+ */
+ remote = false;
+ cpu = this_cpu;
+ } else {
+ cpu = hook->cpu;
+ remote = this_cpu != hook->cpu;
+ }
sugov_set_iowait_boost(sg_cpu, time, flags);
sg_cpu->last_update = time;
@@ -220,7 +234,7 @@ static void sugov_update_single(struct update_util_data *hook, u64 time,
sugov_iowait_boost(sg_cpu, &util, &max);
next_f = get_next_freq(sg_policy, util, max);
}
- sugov_update_commit(sg_policy, time, next_f);
+ sugov_update_commit(sg_policy, time, cpu, remote, next_f);
}
static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu)
@@ -269,8 +283,24 @@ static void sugov_update_shared(struct update_util_data *hook, u64 time,
{
struct sugov_cpu *sg_cpu = container_of(hook, struct sugov_cpu, update_util);
struct sugov_policy *sg_policy = sg_cpu->sg_policy;
+ struct cpufreq_policy *policy = sg_policy->policy;
unsigned long util, max;
unsigned int next_f;
+ int cpu, this_cpu = smp_processor_id();
+ bool remote;
+
+ if (policy->dvfs_possible_from_any_cpu ||
+ cpumask_test_cpu(this_cpu, policy->cpus)) {
+ /*
+ * Avoid sending IPI to 'hook->cpu' if this CPU can change
+ * frequency on its behalf.
+ */
+ remote = false;
+ cpu = this_cpu;
+ } else {
+ cpu = hook->cpu;
+ remote = this_cpu != hook->cpu;
+ }
sugov_get_util(&util, &max, hook->cpu);
@@ -289,7 +319,7 @@ static void sugov_update_shared(struct update_util_data *hook, u64 time,
else
next_f = sugov_next_freq_shared(sg_cpu);
- sugov_update_commit(sg_policy, time, next_f);
+ sugov_update_commit(sg_policy, time, cpu, remote, next_f);
}
raw_spin_unlock(&sg_policy->update_lock);