Skip to content

Commit

Permalink
cpufreq: move freq change notifications to cpufreq core
Browse files Browse the repository at this point in the history
Most of the drivers do following in their ->target_index() routines:

	struct cpufreq_freqs freqs;
	freqs.old = old freq...
	freqs.new = new freq...

	cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);

	/* Change rate here */

	cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);

This is replicated over all cpufreq drivers today and there doesn't exists a
good enough reason why this shouldn't be moved to cpufreq core instead.

There are few special cases though, like exynos5440, which doesn't do everything
on the call to ->target_index() routine and call some kind of bottom halves for
doing this work, work/tasklet/etc..

They may continue doing notification from their own code as flag:
CPUFREQ_ASYNC_NOTIFICATION is already set for them.

All drivers are also modified in this patch to avoid breaking 'git bisect', as
double notification would happen otherwise.

Acked-by: Hans-Christian Egtvedt <egtvedt@samfundet.no>
Acked-by: Jesper Nilsson <jesper.nilsson@axis.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Russell King <linux@arm.linux.org.uk>
Acked-by: Stephen Warren <swarren@nvidia.com>
Tested-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Reviewed-by: Lan Tianyu <tianyu.lan@intel.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  • Loading branch information
Viresh Kumar authored and Rafael J. Wysocki committed Oct 30, 2013
1 parent 7dbf694 commit d4019f0
Show file tree
Hide file tree
Showing 40 changed files with 198 additions and 624 deletions.
14 changes: 2 additions & 12 deletions drivers/cpufreq/acpi-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,14 +428,10 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
{
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
struct acpi_processor_performance *perf;
struct cpufreq_freqs freqs;
struct drv_cmd cmd;
unsigned int next_perf_state = 0; /* Index into perf table */
int result = 0;

pr_debug("acpi_cpufreq_target %d (%d)\n",
data->freq_table[index].frequency, policy->cpu);

if (unlikely(data == NULL ||
data->acpi_data == NULL || data->freq_table == NULL)) {
return -ENODEV;
Expand Down Expand Up @@ -483,23 +479,17 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
else
cmd.mask = cpumask_of(policy->cpu);

freqs.old = perf->states[perf->state].core_frequency * 1000;
freqs.new = data->freq_table[index].frequency;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);

drv_write(&cmd);

if (acpi_pstate_strict) {
if (!check_freqs(cmd.mask, freqs.new, data)) {
if (!check_freqs(cmd.mask, data->freq_table[index].frequency,
data)) {
pr_debug("acpi_cpufreq_target failed (%d)\n",
policy->cpu);
result = -EAGAIN;
freqs.new = freqs.old;
}
}

cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);

if (!result)
perf->state = next_perf_state;

Expand Down
24 changes: 5 additions & 19 deletions drivers/cpufreq/arm_big_little.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,39 +192,25 @@ bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate)
static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
unsigned int index)
{
struct cpufreq_freqs freqs;
u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster;
int ret = 0;
unsigned int freqs_new;

cur_cluster = cpu_to_cluster(cpu);
new_cluster = actual_cluster = per_cpu(physical_cluster, cpu);

freqs.old = bL_cpufreq_get_rate(cpu);
freqs.new = freq_table[cur_cluster][index].frequency;

pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n",
__func__, cpu, cur_cluster, freqs.old, freqs.new,
freqs.new);
freqs_new = freq_table[cur_cluster][index].frequency;

if (is_bL_switching_enabled()) {
if ((actual_cluster == A15_CLUSTER) &&
(freqs.new < clk_big_min)) {
(freqs_new < clk_big_min)) {
new_cluster = A7_CLUSTER;
} else if ((actual_cluster == A7_CLUSTER) &&
(freqs.new > clk_little_max)) {
(freqs_new > clk_little_max)) {
new_cluster = A15_CLUSTER;
}
}

cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);

ret = bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs.new);
if (ret)
freqs.new = freqs.old;

cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);

return ret;
return bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new);
}

static inline u32 get_table_count(struct cpufreq_frequency_table *table)
Expand Down
22 changes: 9 additions & 13 deletions drivers/cpufreq/at32ap-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,23 @@ static unsigned long loops_per_jiffy_ref;

static int at32_set_target(struct cpufreq_policy *policy, unsigned int index)
{
struct cpufreq_freqs freqs;
unsigned int old_freq, new_freq;

freqs.old = at32_get_speed(0);
freqs.new = freq_table[index].frequency;
old_freq = at32_get_speed(0);
new_freq = freq_table[index].frequency;

if (!ref_freq) {
ref_freq = freqs.old;
ref_freq = old_freq;
loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy;
}

cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (freqs.old < freqs.new)
if (old_freq < new_freq)
boot_cpu_data.loops_per_jiffy = cpufreq_scale(
loops_per_jiffy_ref, ref_freq, freqs.new);
clk_set_rate(cpuclk, freqs.new * 1000);
if (freqs.new < freqs.old)
loops_per_jiffy_ref, ref_freq, new_freq);
clk_set_rate(cpuclk, new_freq * 1000);
if (new_freq < old_freq)
boot_cpu_data.loops_per_jiffy = cpufreq_scale(
loops_per_jiffy_ref, ref_freq, freqs.new);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);

pr_debug("cpufreq: set frequency %u Hz\n", freqs.new * 1000);
loops_per_jiffy_ref, ref_freq, new_freq);

return 0;
}
Expand Down
22 changes: 7 additions & 15 deletions drivers/cpufreq/blackfin-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,27 +132,23 @@ static int bfin_target(struct cpufreq_policy *policy, unsigned int index)
#ifndef CONFIG_BF60x
unsigned int plldiv;
#endif
struct cpufreq_freqs freqs;
static unsigned long lpj_ref;
static unsigned int lpj_ref_freq;
unsigned int old_freq, new_freq;
int ret = 0;

#if defined(CONFIG_CYCLES_CLOCKSOURCE)
cycles_t cycles;
#endif

freqs.old = bfin_getfreq_khz(0);
freqs.new = bfin_freq_table[index].frequency;
old_freq = bfin_getfreq_khz(0);
new_freq = bfin_freq_table[index].frequency;

pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n",
freqs.new, freqs.new, freqs.old);

cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
#ifndef CONFIG_BF60x
plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel;
bfin_write_PLL_DIV(plldiv);
#else
ret = cpu_set_cclk(policy->cpu, freqs.new * 1000);
ret = cpu_set_cclk(policy->cpu, new_freq * 1000);
if (ret != 0) {
WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret);
return ret;
Expand All @@ -168,17 +164,13 @@ static int bfin_target(struct cpufreq_policy *policy, unsigned int index)
#endif
if (!lpj_ref_freq) {
lpj_ref = loops_per_jiffy;
lpj_ref_freq = freqs.old;
lpj_ref_freq = old_freq;
}
if (freqs.new != freqs.old) {
if (new_freq != old_freq) {
loops_per_jiffy = cpufreq_scale(lpj_ref,
lpj_ref_freq, freqs.new);
lpj_ref_freq, new_freq);
}

/* TODO: just test case for cycles clock source, remove later */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);

pr_debug("cpufreq: done\n");
return ret;
}

Expand Down
33 changes: 12 additions & 21 deletions drivers/cpufreq/cpufreq-cpu0.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,27 @@ static unsigned int cpu0_get_speed(unsigned int cpu)

static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
{
struct cpufreq_freqs freqs;
struct dev_pm_opp *opp;
unsigned long volt = 0, volt_old = 0, tol = 0;
unsigned int old_freq, new_freq;
long freq_Hz, freq_exact;
int ret;

freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
if (freq_Hz < 0)
freq_Hz = freq_table[index].frequency * 1000;
freq_exact = freq_Hz;
freqs.new = freq_Hz / 1000;
freqs.old = clk_get_rate(cpu_clk) / 1000;

cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
freq_exact = freq_Hz;
new_freq = freq_Hz / 1000;
old_freq = clk_get_rate(cpu_clk) / 1000;

if (!IS_ERR(cpu_reg)) {
rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
if (IS_ERR(opp)) {
rcu_read_unlock();
pr_err("failed to find OPP for %ld\n", freq_Hz);
freqs.new = freqs.old;
ret = PTR_ERR(opp);
goto post_notify;
return PTR_ERR(opp);
}
volt = dev_pm_opp_get_voltage(opp);
rcu_read_unlock();
Expand All @@ -69,16 +66,15 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
}

pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
freqs.new / 1000, volt ? volt / 1000 : -1);
old_freq / 1000, volt_old ? volt_old / 1000 : -1,
new_freq / 1000, volt ? volt / 1000 : -1);

/* scaling up? scale voltage before frequency */
if (!IS_ERR(cpu_reg) && freqs.new > freqs.old) {
if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
if (ret) {
pr_err("failed to scale voltage up: %d\n", ret);
freqs.new = freqs.old;
goto post_notify;
return ret;
}
}

Expand All @@ -87,23 +83,18 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
pr_err("failed to set clock rate: %d\n", ret);
if (!IS_ERR(cpu_reg))
regulator_set_voltage_tol(cpu_reg, volt_old, tol);
freqs.new = freqs.old;
goto post_notify;
return ret;
}

/* scaling down? scale voltage after frequency */
if (!IS_ERR(cpu_reg) && freqs.new < freqs.old) {
if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
if (ret) {
pr_err("failed to scale voltage down: %d\n", ret);
clk_set_rate(cpu_clk, freqs.old * 1000);
freqs.new = freqs.old;
clk_set_rate(cpu_clk, old_freq * 1000);
}
}

post_notify:
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);

return ret;
}

Expand Down
40 changes: 37 additions & 3 deletions drivers/cpufreq/cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1669,6 +1669,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
retval = cpufreq_driver->target(policy, target_freq, relation);
else if (cpufreq_driver->target_index) {
struct cpufreq_frequency_table *freq_table;
struct cpufreq_freqs freqs;
bool notify;
int index;

freq_table = cpufreq_frequency_get_table(policy->cpu);
Expand All @@ -1684,10 +1686,42 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
goto out;
}

if (freq_table[index].frequency == policy->cur)
if (freq_table[index].frequency == policy->cur) {
retval = 0;
else
retval = cpufreq_driver->target_index(policy, index);
goto out;
}

notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);

if (notify) {
freqs.old = policy->cur;
freqs.new = freq_table[index].frequency;
freqs.flags = 0;

pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
__func__, policy->cpu, freqs.old,
freqs.new);

cpufreq_notify_transition(policy, &freqs,
CPUFREQ_PRECHANGE);
}

retval = cpufreq_driver->target_index(policy, index);
if (retval)
pr_err("%s: Failed to change cpu frequency: %d\n",
__func__, retval);

if (notify) {
/*
* Notify with old freq in case we failed to change
* frequency
*/
if (retval)
freqs.new = freqs.old;

cpufreq_notify_transition(policy, &freqs,
CPUFREQ_POSTCHANGE);
}
}

out:
Expand Down
8 changes: 0 additions & 8 deletions drivers/cpufreq/cris-artpec3-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,9 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)

static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)
{
struct cpufreq_freqs freqs;
reg_clkgen_rw_clk_ctrl clk_ctrl;
clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);

freqs.old = cris_freq_get_cpu_frequency(policy->cpu);
freqs.new = cris_freq_table[state].frequency;

cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);

local_irq_disable();

/* Even though we may be SMP they will share the same clock
Expand All @@ -50,8 +44,6 @@ static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)

local_irq_enable();

cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);

return 0;
}

Expand Down
8 changes: 0 additions & 8 deletions drivers/cpufreq/cris-etraxfs-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,9 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)

static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)
{
struct cpufreq_freqs freqs;
reg_config_rw_clk_ctrl clk_ctrl;
clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);

freqs.old = cris_freq_get_cpu_frequency(policy->cpu);
freqs.new = cris_freq_table[state].frequency;

cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);

local_irq_disable();

/* Even though we may be SMP they will share the same clock
Expand All @@ -50,8 +44,6 @@ static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)

local_irq_enable();

cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);

return 0;
}

Expand Down
Loading

0 comments on commit d4019f0

Please sign in to comment.