Commit 2abfa876 authored by Rickard Andersson's avatar Rickard Andersson Committed by Rafael J. Wysocki

cpufreq: handle SW coordinated CPUs

This patch fixes a bug that occurred when we had load on a secondary CPU
and the primary CPU was sleeping. Only one sampling timer was spawned
and it was spawned as a deferred timer on the primary CPU, so when a
secondary CPU had a change in load this was not detected by the cpufreq
governor (both ondemand and conservative).

This patch make sure that deferred timers are run on all CPUs in the
case of software controlled CPUs that run on the same frequency.
Signed-off-by: default avatarRickard Andersson <rickard.andersson@stericsson.com>
Signed-off-by: default avatarFabio Baltieri <fabio.baltieri@linaro.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 88b62b91
...@@ -122,7 +122,8 @@ static void cs_dbs_timer(struct work_struct *work) ...@@ -122,7 +122,8 @@ static void cs_dbs_timer(struct work_struct *work)
dbs_check_cpu(&cs_dbs_data, cpu); dbs_check_cpu(&cs_dbs_data, cpu);
schedule_delayed_work_on(cpu, &dbs_info->cdbs.work, delay); schedule_delayed_work_on(smp_processor_id(), &dbs_info->cdbs.work,
delay);
mutex_unlock(&dbs_info->cdbs.timer_mutex); mutex_unlock(&dbs_info->cdbs.timer_mutex);
} }
......
...@@ -161,13 +161,23 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) ...@@ -161,13 +161,23 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
} }
EXPORT_SYMBOL_GPL(dbs_check_cpu); EXPORT_SYMBOL_GPL(dbs_check_cpu);
bool dbs_sw_coordinated_cpus(struct cpu_dbs_common_info *cdbs)
{
struct cpufreq_policy *policy = cdbs->cur_policy;
return cpumask_weight(policy->cpus) > 1;
}
EXPORT_SYMBOL_GPL(dbs_sw_coordinated_cpus);
static inline void dbs_timer_init(struct dbs_data *dbs_data, static inline void dbs_timer_init(struct dbs_data *dbs_data,
struct cpu_dbs_common_info *cdbs, unsigned int sampling_rate) struct cpu_dbs_common_info *cdbs,
unsigned int sampling_rate,
int cpu)
{ {
int delay = delay_for_sampling_rate(sampling_rate); int delay = delay_for_sampling_rate(sampling_rate);
struct cpu_dbs_common_info *cdbs_local = dbs_data->get_cpu_cdbs(cpu);
INIT_DEFERRABLE_WORK(&cdbs->work, dbs_data->gov_dbs_timer); schedule_delayed_work_on(cpu, &cdbs_local->work, delay);
schedule_delayed_work_on(cdbs->cpu, &cdbs->work, delay);
} }
static inline void dbs_timer_exit(struct cpu_dbs_common_info *cdbs) static inline void dbs_timer_exit(struct cpu_dbs_common_info *cdbs)
...@@ -217,6 +227,10 @@ int cpufreq_governor_dbs(struct dbs_data *dbs_data, ...@@ -217,6 +227,10 @@ int cpufreq_governor_dbs(struct dbs_data *dbs_data,
if (ignore_nice) if (ignore_nice)
j_cdbs->prev_cpu_nice = j_cdbs->prev_cpu_nice =
kcpustat_cpu(j).cpustat[CPUTIME_NICE]; kcpustat_cpu(j).cpustat[CPUTIME_NICE];
mutex_init(&j_cdbs->timer_mutex);
INIT_DEFERRABLE_WORK(&j_cdbs->work,
dbs_data->gov_dbs_timer);
} }
/* /*
...@@ -275,15 +289,33 @@ int cpufreq_governor_dbs(struct dbs_data *dbs_data, ...@@ -275,15 +289,33 @@ int cpufreq_governor_dbs(struct dbs_data *dbs_data,
} }
mutex_unlock(&dbs_data->mutex); mutex_unlock(&dbs_data->mutex);
mutex_init(&cpu_cdbs->timer_mutex); if (dbs_sw_coordinated_cpus(cpu_cdbs)) {
dbs_timer_init(dbs_data, cpu_cdbs, *sampling_rate); for_each_cpu(j, policy->cpus) {
struct cpu_dbs_common_info *j_cdbs;
j_cdbs = dbs_data->get_cpu_cdbs(j);
dbs_timer_init(dbs_data, j_cdbs,
*sampling_rate, j);
}
} else {
dbs_timer_init(dbs_data, cpu_cdbs, *sampling_rate, cpu);
}
break; break;
case CPUFREQ_GOV_STOP: case CPUFREQ_GOV_STOP:
if (dbs_data->governor == GOV_CONSERVATIVE) if (dbs_data->governor == GOV_CONSERVATIVE)
cs_dbs_info->enable = 0; cs_dbs_info->enable = 0;
if (dbs_sw_coordinated_cpus(cpu_cdbs)) {
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_common_info *j_cdbs;
j_cdbs = dbs_data->get_cpu_cdbs(j);
dbs_timer_exit(j_cdbs);
}
} else {
dbs_timer_exit(cpu_cdbs); dbs_timer_exit(cpu_cdbs);
}
mutex_lock(&dbs_data->mutex); mutex_lock(&dbs_data->mutex);
mutex_destroy(&cpu_cdbs->timer_mutex); mutex_destroy(&cpu_cdbs->timer_mutex);
......
...@@ -171,6 +171,7 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate) ...@@ -171,6 +171,7 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate)
u64 get_cpu_idle_time(unsigned int cpu, u64 *wall); u64 get_cpu_idle_time(unsigned int cpu, u64 *wall);
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
bool dbs_sw_coordinated_cpus(struct cpu_dbs_common_info *cdbs);
int cpufreq_governor_dbs(struct dbs_data *dbs_data, int cpufreq_governor_dbs(struct dbs_data *dbs_data,
struct cpufreq_policy *policy, unsigned int event); struct cpufreq_policy *policy, unsigned int event);
#endif /* _CPUFREQ_GOVERNER_H */ #endif /* _CPUFREQ_GOVERNER_H */
...@@ -243,7 +243,8 @@ static void od_dbs_timer(struct work_struct *work) ...@@ -243,7 +243,8 @@ static void od_dbs_timer(struct work_struct *work)
} }
} }
schedule_delayed_work_on(cpu, &dbs_info->cdbs.work, delay); schedule_delayed_work_on(smp_processor_id(), &dbs_info->cdbs.work,
delay);
mutex_unlock(&dbs_info->cdbs.timer_mutex); mutex_unlock(&dbs_info->cdbs.timer_mutex);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment