aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/lib.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-06-24 10:57:00 +0100
committerKeir Fraser <keir.fraser@citrix.com>2009-06-24 10:57:00 +0100
commitc764820ae6c300900aecc04dab691b14f4152f13 (patch)
treeb105569caa7337be0fcb2db2b3d3acca66378455 /xen/common/lib.c
parent448dac02973ea594c7d5a9ba31da3b6e3ae1ef2d (diff)
downloadxen-c764820ae6c300900aecc04dab691b14f4152f13.tar.gz
xen-c764820ae6c300900aecc04dab691b14f4152f13.tar.bz2
xen-c764820ae6c300900aecc04dab691b14f4152f13.zip
Move muldiv64 out and make it as a public function.
muldiv64 is used to caculate u64*u32/u32, and we will use it for TSC scaling. Signed-off-by: Xiantao Zhang <xiantao.zhang@intel.com> Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/common/lib.c')
-rw-r--r--xen/common/lib.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/xen/common/lib.c b/xen/common/lib.c
index 2f1a005ca4..579512a4c5 100644
--- a/xen/common/lib.c
+++ b/xen/common/lib.c
@@ -401,6 +401,35 @@ s64 __moddi3(s64 a, s64 b)
#endif /* BITS_PER_LONG == 32 */
+/* Compute with 96 bit intermediate result: (a*b)/c */
+uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
+{
+#ifdef __x86_64__
+ asm ( "mul %%rdx; div %%rcx" : "=a" (a) : "0" (a), "d" (b), "c" (c) );
+ return a;
+#else
+ union {
+ uint64_t ll;
+ struct {
+#ifdef WORDS_BIGENDIAN
+ uint32_t high, low;
+#else
+ uint32_t low, high;
+#endif
+ } l;
+ } u, res;
+ uint64_t rl, rh;
+
+ u.ll = a;
+ rl = (uint64_t)u.l.low * (uint64_t)b;
+ rh = (uint64_t)u.l.high * (uint64_t)b;
+ rh += (rl >> 32);
+ res.l.high = rh / c;
+ res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
+ return res.ll;
+#endif
+}
+
unsigned long long parse_size_and_unit(const char *s, const char **ps)
{
unsigned long long ret;