From 5f6b5b973a125de0dbe236ce659a495787c81ff0 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 30 Oct 2005 22:55:52 +1100 Subject: [PATCH] powerpc: Fix time setting bug on 32-bit This fixes a bug where settimeofday would set the wrong parameters in do_gtod, resulting in gettimeofday returning a value about 4 hours after the correct time. The bug was that we divided a negative 64-bit value with do_div, which treated it as unsigned and gave us a result that was approximately 1.8e10 too large (since the divisor was 1e9). Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/time.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 9f264c2f02..ed5c38fb14 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -518,7 +518,7 @@ int do_settimeofday(struct timespec *tv) long wtm_nsec, new_nsec = tv->tv_nsec; unsigned long flags; long int tb_delta; - u64 new_xsec; + u64 new_xsec, tb_delta_xs; if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) return -EINVAL; @@ -541,8 +541,7 @@ int do_settimeofday(struct timespec *tv) #endif tb_delta = tb_ticks_since(tb_last_stamp); tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; - - new_nsec -= 1000 * mulhwu(tb_to_us, tb_delta); + tb_delta_xs = mulhdu(tb_delta, do_gtod.varp->tb_to_xs); wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec); wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec); @@ -557,9 +556,12 @@ int do_settimeofday(struct timespec *tv) ntp_clear(); - new_xsec = (u64)new_nsec * XSEC_PER_SEC; - do_div(new_xsec, NSEC_PER_SEC); - new_xsec += (u64)new_sec * XSEC_PER_SEC; + new_xsec = 0; + if (new_nsec != 0) { + new_xsec = (u64)new_nsec * XSEC_PER_SEC; + do_div(new_xsec, NSEC_PER_SEC); + } + new_xsec += (u64)new_sec * XSEC_PER_SEC - tb_delta_xs; update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs); #ifdef CONFIG_PPC64 -- 2.39.5