Paul Menzel (paulepanter@users.sourceforge.net) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3219
-gerrit
commit 0aa640b9220fd51e6b48d39ee9d6a08bde5c8bb2 Author: Paul Menzel paulepanter@users.sourceforge.net Date: Wed May 8 16:24:38 2013 +0200
Intel 5000: udelay.c: Work around 32-bit overflow
Port the following commit over to the Intel 5000.
commit 8bacc40fc7bd07365c2992b260ddbd45cd6e4518 Author: Nico Huber nico.huber@secunet.com Date: Thu Jul 19 16:16:59 2012 +0200
Fix udelay() implementation for i945 romstage
Reviewed-on: http://review.coreboot.org/1254
Change-Id: I5c113bb0b2fed7b93feb3dcb1b5d962e1442963a Signed-off-by: Paul Menzel paulepanter@users.sourceforge.net --- src/northbridge/intel/i5000/udelay.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/src/northbridge/intel/i5000/udelay.c b/src/northbridge/intel/i5000/udelay.c index ce4c7b3..699e0d4 100644 --- a/src/northbridge/intel/i5000/udelay.c +++ b/src/northbridge/intel/i5000/udelay.c @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2007-2008 coresystems GmbH + * 2012 secunet Security Networks AG * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +24,17 @@ #include <cpu/x86/msr.h> #include <cpu/intel/speedstep.h>
+/* Simple 32- to 64-bit multiplication. Uses 16-bit words to avoid overflow. */ +static inline void multiply_to_tsc(tsc_t * const tsc, const u32 a, const u32 b) +{ + tsc->lo = (a & 0xffff) * (b & 0xffff); + tsc->hi = ((tsc->lo >> 16) + + ((a & 0xffff) * (b >> 16)) + + ((b & 0xffff) * (a >> 16))); + tsc->lo = ((tsc->hi & 0xffff) << 16) | (tsc->lo & 0xffff); + tsc->hi = ((a >> 16) * (b >> 16)) + (tsc->hi >> 16); +} + /** * Intel Core(tm) cpus always run the TSC at the maximum possible CPU clock */ @@ -34,7 +46,6 @@ void udelay(u32 us) msr_t msr; u32 fsb = 0, divisor; u32 d; /* ticks per us */ - u32 dn = 0x1000000 / 2; /* how many us before we need to use hi */
msr = rdmsr(MSR_FSB_FREQ); switch (msr.lo & 0x07) { @@ -64,10 +75,9 @@ void udelay(u32 us) msr = rdmsr(0x198); divisor = (msr.hi >> 8) & 0x1f;
- d = fsb * divisor; + d = (fsb * divisor) / 4; /* CPU clock is always a quarter. */
- tscd.hi = us / dn; - tscd.lo = (us - tscd.hi * dn) * d; + multiply_to_tsc(&tscd, us, d);
tsc1 = rdtsc(); dword = tsc1.lo + tscd.lo; @@ -81,5 +91,6 @@ void udelay(u32 us)
do { tsc = rdtsc(); - } while ((tsc.hi < tsc1.hi) || ((tsc.hi == tsc1.hi) && (tsc.lo < tsc1.lo))); + } while ((tsc.hi < tsc1.hi) + || ((tsc.hi == tsc1.hi) && (tsc.lo < tsc1.lo))); }