Message ID | 1344577046-14847-2-git-send-email-shawn.guo@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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 >
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 --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