This introduces another routine cpufreq_notify_post_transition() which can be used to send POSTCHANGE notification for new freq with or without both {PRE|POST}CHANGE notifications for last freq. This is useful at multiple places, specially for sending transition failure notifications.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org ---
V1->V2: - Not required to push it for 3.13 anymore and can go in 3.14. - Rebased over following patchset as there were conflicts in unicore2 driver if following patchset is applied first (which should be the case): https://lkml.org/lkml/2013/10/30/553 (create cpufreq_generic_get() routine)
drivers/cpufreq/cpufreq.c | 14 ++++++++++++++ include/linux/cpufreq.h | 2 ++ 2 files changed, 16 insertions(+)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 5e27def..3b877d4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -338,6 +338,20 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy, } EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
+/* Do post notifications when there are chances that transition has failed */ +void cpufreq_notify_post_transition(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs, int transition_failed) +{ + cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE); + if (!transition_failed) + return; + + swap(freqs->old, freqs->new); + cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE); +} +EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition); +
/********************************************************************* * SYSFS INTERFACE * diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 276e646..b26bfab 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -316,6 +316,8 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
void cpufreq_notify_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, unsigned int state); +void cpufreq_notify_post_transition(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs, int transition_failed);
#else /* CONFIG_CPU_FREQ */ static inline int cpufreq_register_notifier(struct notifier_block *nb,
In the current code, if we fail during a frequency transition we simply send the POSTCHANGE notification with old frequency. This isn't enough.
One of the core user of these notifications is the code responsible for keeping loops_per_jiffy aligned with frequency change. And mostly it is written as:
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { update-loops-per-jiffy... }
So, suppose we are changing to a higher frequency and failed during transition, then following will happen: - CPUFREQ_PRECHANGE notification with freq-new > freq-old - CPUFREQ_POSTCHANGE notification with freq-new == freq-old
The first one will update loops_per_jiffy and second one will do nothing. Even if we send the 2nd notification by exchanging values of freq-new and old, some users of these notifications might get unstable.
This can be fixed by simply calling cpufreq_notify_post_transition() with error code and this routine will take care of sending notifications in correct order.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- drivers/cpufreq/cpufreq.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3b877d4..a7fcb84 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1815,17 +1815,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, 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); - } + if (notify) + cpufreq_notify_post_transition(policy, &freqs, retval); }
out:
In the current code, if we fail during a frequency transition we simply send the POSTCHANGE notification with old frequency. This isn't enough.
One of the core user of these notifications is the code responsible for keeping loops_per_jiffy aligned with frequency change. And mostly it is written as:
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { update-loops-per-jiffy... }
So, suppose we are changing to a higher frequency and failed during transition, then following will happen: - CPUFREQ_PRECHANGE notification with freq-new > freq-old - CPUFREQ_POSTCHANGE notification with freq-new == freq-old
The first one will update loops_per_jiffy and second one will do nothing. Even if we send the 2nd notification by exchanging values of freq-new and old, some users of these notifications might get unstable.
This can be fixed by simply calling cpufreq_notify_post_transition() with error code and this routine will take care of sending notifications in correct order.
Also it fills freqs.old before starting the first notification, this was missing since ever.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- drivers/cpufreq/pcc-cpufreq.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index e2b4f40..1c0f106 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -213,6 +213,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, cpu, target_freq, (pcch_virt_addr + pcc_cpu_data->input_offset));
+ freqs.old = policy->cur; freqs.new = target_freq; cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
@@ -228,25 +229,20 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
status = ioread16(&pcch_hdr->status); + iowrite16(0, &pcch_hdr->status); + + cpufreq_notify_post_transition(policy, &freqs, status != CMD_COMPLETE); + spin_unlock(&pcc_lock); + if (status != CMD_COMPLETE) { pr_debug("target: FAILED for cpu %d, with status: 0x%x\n", cpu, status); - goto cmd_incomplete; + return -EINVAL; } - iowrite16(0, &pcch_hdr->status);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu); - spin_unlock(&pcc_lock);
return 0; - -cmd_incomplete: - freqs.new = freqs.old; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - iowrite16(0, &pcch_hdr->status); - spin_unlock(&pcc_lock); - return -EINVAL; }
static int pcc_get_offset(int cpu)
In the current code, if we fail during a frequency transition we simply send the POSTCHANGE notification with old frequency. This isn't enough.
One of the core user of these notifications is the code responsible for keeping loops_per_jiffy aligned with frequency change. And mostly it is written as:
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { update-loops-per-jiffy... }
So, suppose we are changing to a higher frequency and failed during transition, then following will happen: - CPUFREQ_PRECHANGE notification with freq-new > freq-old - CPUFREQ_POSTCHANGE notification with freq-new == freq-old
The first one will update loops_per_jiffy and second one will do nothing. Even if we send the 2nd notification by exchanging values of freq-new and old, some users of these notifications might get unstable.
This can be fixed by simply calling cpufreq_notify_post_transition() with error code and this routine will take care of sending notifications in correct order.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- drivers/cpufreq/powernow-k8.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 0023c7d..e10b646 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -964,14 +964,9 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, cpufreq_cpu_put(policy);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - res = transition_fid_vid(data, fid, vid); - if (res) - freqs.new = freqs.old; - else - freqs.new = find_khz_freq_from_fid(data->currfid); + cpufreq_notify_post_transition(policy, &freqs, res);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return res; }
In the current code, if we fail during a frequency transition we simply send the POSTCHANGE notification with old frequency. This isn't enough.
One of the core user of these notifications is the code responsible for keeping loops_per_jiffy aligned with frequency change. And mostly it is written as:
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { update-loops-per-jiffy... }
So, suppose we are changing to a higher frequency and failed during transition, then following will happen: - CPUFREQ_PRECHANGE notification with freq-new > freq-old - CPUFREQ_POSTCHANGE notification with freq-new == freq-old
The first one will update loops_per_jiffy and second one will do nothing. Even if we send the 2nd notification by exchanging values of freq-new and old, some users of these notifications might get unstable.
This can be fixed by simply calling cpufreq_notify_post_transition() with error code and this routine will take care of sending notifications in correct order.
Also it returns a proper error message in case frequency transition failed.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- drivers/cpufreq/unicore2-cpufreq.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c index 951152f..99d280d6 100644 --- a/drivers/cpufreq/unicore2-cpufreq.c +++ b/drivers/cpufreq/unicore2-cpufreq.c @@ -38,19 +38,17 @@ static int ucv2_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { - unsigned int cur = policy->cur; struct cpufreq_freqs freqs; + int ret;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - - if (!clk_set_rate(policy->clk, target_freq * 1000)) { - freqs.old = cur; - freqs.new = target_freq; - } + freqs.old = policy->cur; + freqs.new = target_freq;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + ret = clk_set_rate(policy->clk, target_freq * 1000); + cpufreq_notify_post_transition(policy, &freqs, ret);
- return 0; + return ret; }
static int __init ucv2_cpu_init(struct cpufreq_policy *policy)
On Monday, December 02, 2013 11:04:12 AM Viresh Kumar wrote:
This introduces another routine cpufreq_notify_post_transition() which can be used to send POSTCHANGE notification for new freq with or without both {PRE|POST}CHANGE notifications for last freq. This is useful at multiple places, specially for sending transition failure notifications.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org
I've queued this series up for 3.14, but I folded patches [3-5/5] into [2/5] (and needed to rebase the unicore2 changes).
Every time you want to copy-paste the changelog from one patch to another (please don't do that any more) you should rather think about sending a combination of the two as one patch.
Thanks!
V1->V2:
- Not required to push it for 3.13 anymore and can go in 3.14.
- Rebased over following patchset as there were conflicts in unicore2 driver if following patchset is applied first (which should be the case): https://lkml.org/lkml/2013/10/30/553 (create cpufreq_generic_get() routine)
drivers/cpufreq/cpufreq.c | 14 ++++++++++++++ include/linux/cpufreq.h | 2 ++ 2 files changed, 16 insertions(+)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 5e27def..3b877d4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -338,6 +338,20 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy, } EXPORT_SYMBOL_GPL(cpufreq_notify_transition); +/* Do post notifications when there are chances that transition has failed */ +void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, int transition_failed)
+{
- cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE);
- if (!transition_failed)
return;
- swap(freqs->old, freqs->new);
- cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE);
- cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE);
+} +EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition);
/*********************************************************************
SYSFS INTERFACE *
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 276e646..b26bfab 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -316,6 +316,8 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); void cpufreq_notify_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, unsigned int state); +void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, int transition_failed);
#else /* CONFIG_CPU_FREQ */ static inline int cpufreq_register_notifier(struct notifier_block *nb,
linaro-kernel@lists.linaro.org