diff mbox

[v3,1/3] ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp

Message ID 1344577046-14847-2-git-send-email-shawn.guo@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Shawn Guo Aug. 10, 2012, 5:37 a.m. UTC
From: Richard Zhao <richard.zhao@linaro.org>

If CONFIG_SMP, cpufreq skips loops_per_jiffy update, because different
arch has different per-cpu loops_per_jiffy definition.

Signed-off-by: Richard Zhao <richard.zhao@linaro.org>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/kernel/smp.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 54 insertions(+), 0 deletions(-)

Comments

Rafael Wysocki Sept. 4, 2012, 11:27 p.m. UTC | #1
On Friday, August 10, 2012, Shawn Guo wrote:
> From: Richard Zhao <richard.zhao@linaro.org>
> 
> If CONFIG_SMP, cpufreq skips loops_per_jiffy update, because different
> arch has different per-cpu loops_per_jiffy definition.
> 
> Signed-off-by: Richard Zhao <richard.zhao@linaro.org>
> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
> Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>

Applied to the linux-next branch of the linux-pm.git tree as v3.7 material.

Thanks,
Rafael


> ---
>  arch/arm/kernel/smp.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 54 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
> index ebd8ad2..8e03567 100644
> --- a/arch/arm/kernel/smp.c
> +++ b/arch/arm/kernel/smp.c
> @@ -25,6 +25,7 @@
>  #include <linux/percpu.h>
>  #include <linux/clockchips.h>
>  #include <linux/completion.h>
> +#include <linux/cpufreq.h>
>  
>  #include <linux/atomic.h>
>  #include <asm/cacheflush.h>
> @@ -584,3 +585,56 @@ int setup_profiling_timer(unsigned int multiplier)
>  {
>  	return -EINVAL;
>  }
> +
> +#ifdef CONFIG_CPU_FREQ
> +
> +static DEFINE_PER_CPU(unsigned long, l_p_j_ref);
> +static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq);
> +static unsigned long global_l_p_j_ref;
> +static unsigned long global_l_p_j_ref_freq;
> +
> +static int cpufreq_callback(struct notifier_block *nb,
> +					unsigned long val, void *data)
> +{
> +	struct cpufreq_freqs *freq = data;
> +	int cpu = freq->cpu;
> +
> +	if (freq->flags & CPUFREQ_CONST_LOOPS)
> +		return NOTIFY_OK;
> +
> +	if (!per_cpu(l_p_j_ref, cpu)) {
> +		per_cpu(l_p_j_ref, cpu) =
> +			per_cpu(cpu_data, cpu).loops_per_jiffy;
> +		per_cpu(l_p_j_ref_freq, cpu) = freq->old;
> +		if (!global_l_p_j_ref) {
> +			global_l_p_j_ref = loops_per_jiffy;
> +			global_l_p_j_ref_freq = freq->old;
> +		}
> +	}
> +
> +	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
> +	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
> +	    (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
> +		loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
> +						global_l_p_j_ref_freq,
> +						freq->new);
> +		per_cpu(cpu_data, cpu).loops_per_jiffy =
> +			cpufreq_scale(per_cpu(l_p_j_ref, cpu),
> +					per_cpu(l_p_j_ref_freq, cpu),
> +					freq->new);
> +	}
> +	return NOTIFY_OK;
> +}
> +
> +static struct notifier_block cpufreq_notifier = {
> +	.notifier_call  = cpufreq_callback,
> +};
> +
> +static int __init register_cpufreq_notifier(void)
> +{
> +	return cpufreq_register_notifier(&cpufreq_notifier,
> +						CPUFREQ_TRANSITION_NOTIFIER);
> +}
> +core_initcall(register_cpufreq_notifier);
> +
> +#endif
>
Stephen Warren Sept. 6, 2012, 10:35 p.m. UTC | #2
On 08/09/2012 11:37 PM, Shawn Guo wrote:
> From: Richard Zhao <richard.zhao@linaro.org>
> 
> If CONFIG_SMP, cpufreq skips loops_per_jiffy update, because different
> arch has different per-cpu loops_per_jiffy definition.
> 
> Signed-off-by: Richard Zhao <richard.zhao@linaro.org>
> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
> Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>

I believe this patch is causing issues initializing PCI-Express on Tegra.

In next-20120906, I cold-booted 10 times. 3 times, PCIe initialized OK,
and 7 times, the driver timed out in arch/arm/mach-tegra/pcie.c function
tegra_pcie_check_link(). With this patch reverted, another 10 cold boot
attempts all succeeded just fine. Similarly, the regression appeared in
next-20120905, and I isolated it to arch/arm/kernel/, and this is the
only patch in that directory between next-20120904 and next-20120905.

Do you have any idea what the problem might be?

Looking at the timestamps in dmesg in the failing case, the driver is
waiting the expected (per pcie.c driver code) 1.2 seconds before giving
up on the port, although I suppose if the kernel's idea of real-time is
off, then the dmesg log timestamps might be off too.
diff mbox

Patch

diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index ebd8ad2..8e03567 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -25,6 +25,7 @@ 
 #include <linux/percpu.h>
 #include <linux/clockchips.h>
 #include <linux/completion.h>
+#include <linux/cpufreq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -584,3 +585,56 @@  int setup_profiling_timer(unsigned int multiplier)
 {
 	return -EINVAL;
 }
+
+#ifdef CONFIG_CPU_FREQ
+
+static DEFINE_PER_CPU(unsigned long, l_p_j_ref);
+static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq);
+static unsigned long global_l_p_j_ref;
+static unsigned long global_l_p_j_ref_freq;
+
+static int cpufreq_callback(struct notifier_block *nb,
+					unsigned long val, void *data)
+{
+	struct cpufreq_freqs *freq = data;
+	int cpu = freq->cpu;
+
+	if (freq->flags & CPUFREQ_CONST_LOOPS)
+		return NOTIFY_OK;
+
+	if (!per_cpu(l_p_j_ref, cpu)) {
+		per_cpu(l_p_j_ref, cpu) =
+			per_cpu(cpu_data, cpu).loops_per_jiffy;
+		per_cpu(l_p_j_ref_freq, cpu) = freq->old;
+		if (!global_l_p_j_ref) {
+			global_l_p_j_ref = loops_per_jiffy;
+			global_l_p_j_ref_freq = freq->old;
+		}
+	}
+
+	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
+	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
+	    (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+		loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
+						global_l_p_j_ref_freq,
+						freq->new);
+		per_cpu(cpu_data, cpu).loops_per_jiffy =
+			cpufreq_scale(per_cpu(l_p_j_ref, cpu),
+					per_cpu(l_p_j_ref_freq, cpu),
+					freq->new);
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cpufreq_notifier = {
+	.notifier_call  = cpufreq_callback,
+};
+
+static int __init register_cpufreq_notifier(void)
+{
+	return cpufreq_register_notifier(&cpufreq_notifier,
+						CPUFREQ_TRANSITION_NOTIFIER);
+}
+core_initcall(register_cpufreq_notifier);
+
+#endif