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 in case of failures. This is useful at multiple places, specially for sending transition failure notifications.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org ---
Hi Rafael,
Please see if you want to take it for 3.13 or 14, as this fixes bugs which are partly introduced in 3.13..
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 606224a..a862aa9 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -324,6 +324,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 ee5fe9d..57e48db 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -314,6 +314,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 a862aa9..557bb49 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1764,17 +1764,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 | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c index 653ae29..3e79dae 100644 --- a/drivers/cpufreq/unicore2-cpufreq.c +++ b/drivers/cpufreq/unicore2-cpufreq.c @@ -49,17 +49,16 @@ static int ucv2_target(struct cpufreq_policy *policy, unsigned int cur = ucv2_getspeed(0); struct cpufreq_freqs freqs; struct clk *mclk = clk_get(NULL, "MAIN_CLK"); + int ret;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - - if (!clk_set_rate(mclk, target_freq * 1000)) { - freqs.old = cur; - freqs.new = target_freq; - } + freqs.old = cur; + freqs.new = target_freq;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + ret = clk_set_rate(mclk, 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 Saturday, November 30, 2013 09:26:19 PM 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 in case of failures. This is useful at multiple places, specially for sending transition failure notifications.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org
Hi Rafael,
Please see if you want to take it for 3.13 or 14, as this fixes bugs which are partly introduced in 3.13..
Which ones?
Rafael
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 606224a..a862aa9 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -324,6 +324,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 ee5fe9d..57e48db 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -314,6 +314,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,
On 1 December 2013 01:50, Rafael J. Wysocki rjw@rjwysocki.net wrote:
On Saturday, November 30, 2013 09:26:19 PM 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 in case of failures. This is useful at multiple places, specially for sending transition failure notifications.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org
Hi Rafael,
Please see if you want to take it for 3.13 or 14, as this fixes bugs which are partly introduced in 3.13..
Which ones?
Patch:
commit d4019f0a92ab802f385cc9c8ad3ab7b5449712cb Author: Viresh Kumar viresh.kumar@linaro.org Date: Wed Aug 14 19:38:24 2013 +0530
cpufreq: move freq change notifications to cpufreq core
adds:
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c + 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); + }
And I thought it might go in 3.13, but surely it doesn't fix any obvious kernel crashes. It only fixes stuff when target_index() fails.
linaro-kernel@lists.linaro.org