Commit Graph

5 Commits

Author SHA1 Message Date
Duy Truong
04e554807c Update copyright to The Linux Foundation
Change-Id: Ibead64ce2e901dede2ddd1b86088b88f2350ce92
Signed-off-by: Duy Truong <dtruong@codeaurora.org>
2013-03-15 17:07:39 -07:00
Jeff Ohlstein
89120a6cbe arm: delay: annotate delay constant as unsigned long
Currently the __udelay function causes the following compiler warning
when HZ is set to 1000:

arch/arm/lib/delay.c: In function __udelay:
arch/arm/lib/delay.c:88: warning: integer overflow in expression

The overflow does not occur if the constant is unsigned.

Change-Id: I45fcbad2944c88f6ec49f45816032efff12d9e1b
Signed-off-by: Jeff Ohlstein <johlstei@codeaurora.org>
(cherry picked from commit ed5a151ce513dff8d021be33899d5c6d7c6633e1)
2013-02-20 01:32:29 -08:00
Stephen Boyd
567ad90009 arm: Implement a timer based __delay() loop
udelay() can be incorrect on SMP machines that scale their CPU
frequencies independently of one another (as pointed out here
http://article.gmane.org/gmane.linux.kernel/977567). The delay
loop can either be too fast or too slow depending on which CPU the
loops_per_jiffy counter is calibrated on and which CPU the delay
loop is running on. udelay() can also be incorrect if the
CPU frequency switches during the __delay() loop, causing the loop
to either terminate too early, or too late.

We'd rather not fix udelay() by forcing it to run on one CPU or
take the penalty of a rather large loops_per_jiffy being used in
udelay() when the CPU is actually running slower. Instead we
solve the problem by making __delay() into a timer based loop
which should be unaffected by CPU frequency scaling. Therefore,
implement a timer based __delay() loop which can be used in place
of the current register based __delay() if a machine so chooses.

The kernel is already prepared for a timer based approach
(evident by the read_current_timer() function). If an arch
implements read_current_timer(), calibrate_delay() will use a
timer based function, calibrate_delay_direct(), to calculate
loops_per_jiffy (in which case loops_per_jiffy should really be
renamed to timer_ticks_per_jiffy). Since the loops_per_jiffy will
be based on timer ticks, __delay() should be implemented as a
loop around read_current_timer().

Doing this makes the expensive loops_per_jiffy calculation go
away (saving ~150ms on boot time on my machine) and fixes
udelay() by making it safe in the face of independently scaling
CPUs. The only prerequisite is that read_current_timer() is
monotonically increasing across calls (and doesn't overflow
within ~2000us).

There is a downside to this approach though. BogoMIPS is no
longer "accurate" in that it reflects the BogoMIPS of the timer
and not the CPU. On most SoC's the timer isn't running anywhere
near as fast as the CPU so BogoMIPS will be ridiculously low (my
timer runs at 4.8 MHz and thus my BogoMIPS is 9.6 compared to my
CPU's 800). This shouldn't be too much of a concern though since
BogoMIPS are bogus anyway (hence the name).

This loop is pretty much a copy of AVR's version made more generic.

Change-Id: I1a80718d93a4821ea55bde99ff0f9cd1c19990ae
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Reviewed-by: Saravana Kannan <skannan@codeaurora.org>
(cherry picked from commit 976eafa8b18252876e15f861944acf693b07ce7e)
2013-02-20 01:32:28 -08:00
Stephen Boyd
2eb58c9c0f arm: Allow machines to override __delay()
Some machines want to implement their own __delay() routine based
on fixed timers. Expose functionality to set the __delay()
routine at runtime. This should allow two machines with different
__delay() routines to happily co-exist within the same kernel
with minimal overhead.

Russell expressed concern that using a timer based __delay()
would cause problems where an iomapped device isn't mapped in
before a delay call was made (see
http://article.gmane.org/gmane.linux.ports.arm.kernel/78543 for
more info). We can sidestep that issue with this approach since
the __delay() routine _should_ only be pointed to a timer based
delay once the timer has been properly mapped. Up until that
point __delay() and udelay() will use delay_loop() which is
always safe to call.

This patch is inspired by x86's delay.c

Change-Id: I1ed80eef1eed6d6df881f93f4515de778ad60f67
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Reviewed-by: Saravana Kannan <skannan@codeaurora.org>
(cherry picked from commit bc0ef8ab167272890f1aab62928b04a9aeb87ce9)
2013-02-20 01:32:28 -08:00
Stephen Boyd
e89a2fd996 arm: Translate delay.S into (mostly) C
In the next patch we're going to allow machines to override the
__delay() implementation at runtime so they can implement a timer
based __delay() routine. It's easier to do this using C, so lets
write udelay and friends in C.

We lose the #if 0 code, which according to Russell is used "to
make the delay loop more stable and predictable on older CPUs"
(see http://article.gmane.org/gmane.linux.kernel/888867 for more
info). We shouldn't be too worried though, since the next patch
adds functionality to allow a machine to set the __delay() loop
themselves, therefore allowing machines to resurrect the
commented out code if they need it.

bloat-o-meter shows an increase of 12 bytes. Further inspection
of the assembly shows GCC copying the loops_per_jiffy pointer and
the magic HZ value to the ends of __const_udelay() and _delay()
thus contributing an extra 4 and 8 bytes of data to each
function. These two values weren't taken into account in the
delay.S version since they weren't part of the function in nm's
eyes. This means we only really gained an extra 4 bytes due to
GCC's decision to duplicate the loops_per_jiffy pointer in
__const_udelay.

 $ scripts/bloat-o-meter vmlinux.orig vmlinux.new
 add/remove: 0/0 grow/shrink: 2/0 up/down: 12/0 (12)
 function                                     old     new   delta
 __udelay                                      48      56      +8
 __const_udelay                                40      44      +4

Change-Id: Ibfaab52d0f5e09471571be082232db04726d5532
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Reviewed-by: Saravana Kannan <skannan@codeaurora.org>
(cherry picked from commit 8d5868d8205d10a0a8e423f53e9cc9bb3e9d1a34)

Conflicts:

	arch/arm/kernel/armksyms.c
	arch/arm/lib/delay.S
2013-02-20 01:32:27 -08:00