ARM: 7653/2: do not scale loops_per_jiffy when using a constant delay clock
Will Deacon
will.deacon at arm.com
Tue Mar 19 14:16:16 EDT 2013
On Thu, Mar 07, 2013 at 06:37:30AM +0000, Nicolas Pitre wrote:
> On Thu, 7 Mar 2013, Will Deacon wrote:
>
> > On the topic of this patch: I still think that we should revert it and
> > require cpufreq drivers to pass CPUFREQ_CONST_LOOPS in their flags (I guess
> > the cpu0 platform data may need extending to take some flags).
>
> I must disagree. The constness here is a property of the timer source
> used to implement one of the udelay() providers. Constness has no
> relation with cpufreq which may or may not impact a given udelay
> implementation.
>
> > Longer term, we might want to assess the binding between timer-based
> > delays and loops_per_jiffy, but that's an entirely new problem.
>
> Actually I do think that the lpj should always be scaled regardless, as
> this has meaning only for a CPU loop. This is even more important if
> there is the possibility for switching between different
> implementations. The local timer based udelay implementation should
> simply never factor in lpj into its delay evaluation.
>
> So the current patch is a stop gap to fix the problem today. When
> something better is proposed we can remove this fix.
Ok, how about a simple change like the one below?
Will
--->8
diff --git a/arch/arm/include/asm/delay.h b/arch/arm/include/asm/delay.h
index 720799f..06777b9 100644
--- a/arch/arm/include/asm/delay.h
+++ b/arch/arm/include/asm/delay.h
@@ -24,7 +24,7 @@ extern struct arm_delay_ops {
void (*delay)(unsigned long);
void (*const_udelay)(unsigned long);
void (*udelay)(unsigned long);
- bool const_clock;
+ unsigned long lpj;
} arm_delay_ops;
#define __delay(n) arm_delay_ops.delay(n)
diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c
index 6b93f6a..0d90ed8 100644
--- a/arch/arm/lib/delay.c
+++ b/arch/arm/lib/delay.c
@@ -58,7 +58,7 @@ static void __timer_delay(unsigned long cycles)
static void __timer_const_udelay(unsigned long xloops)
{
unsigned long long loops = xloops;
- loops *= loops_per_jiffy;
+ loops *= arm_delay_ops.lpj;
__timer_delay(loops >> UDELAY_SHIFT);
}
@@ -73,11 +73,13 @@ void __init register_current_timer_delay(const struct delay_timer *timer)
pr_info("Switching to timer-based delay loop\n");
delay_timer = timer;
lpj_fine = timer->freq / HZ;
- loops_per_jiffy = lpj_fine;
+
+ /* cpufreq may scale loops_per_jiffy, so keep a private copy */
+ arm_delay_ops.lpj = lpj_fine;
arm_delay_ops.delay = __timer_delay;
arm_delay_ops.const_udelay = __timer_const_udelay;
arm_delay_ops.udelay = __timer_udelay;
- arm_delay_ops.const_clock = true;
+
delay_calibrated = true;
} else {
pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
More information about the linux-arm-kernel
mailing list