]> git.baikalelectronics.ru Git - kernel.git/commit
x86: Derandom delay_tsc for 64 bit
authorThomas Gleixner <tglx@linutronix.de>
Fri, 9 Mar 2012 19:55:10 +0000 (20:55 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 9 Mar 2012 20:43:27 +0000 (12:43 -0800)
commit4ed24bccec7e49482095825ee20247458d093950
treee406279014534fef75e15c5c6b2bc797a0e1488a
parente3b9bfbb62f37e72bebca1f272f5fab9de0171d4
x86: Derandom delay_tsc for 64 bit

Commit 6eb403793cba ("x86: integrate delay functions") converted
delay_tsc() into a random delay generator for 64 bit.  The reason is
that it merged the mostly identical versions of delay_32.c and
delay_64.c.  Though the subtle difference of the result was:

 static void delay_tsc(unsigned long loops)
 {
- unsigned bclock, now;
+ unsigned long bclock, now;

Now the function uses rdtscl() which returns the lower 32bit of the
TSC. On 32bit that's not problematic as unsigned long is 32bit. On 64
bit this fails when the lower 32bit are close to wrap around when
bclock is read, because the following check

       if ((now - bclock) >= loops)
           break;

evaluated to true on 64bit for e.g. bclock = 0xffffffff and now = 0
because the unsigned long (now - bclock) of these values results in
0xffffffff00000001 which is definitely larger than the loops
value. That explains Tvortkos observation:

"Because I am seeing udelay(500) (_occasionally_) being short, and
 that by delaying for some duration between 0us (yep) and 491us."

Make those variables explicitely u32 again, so this works for both 32
and 64 bit.

Reported-by: Tvrtko Ursulin <tvrtko.ursulin@onelan.co.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org # >= 2.6.27
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/x86/lib/delay.c