aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/time.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-10-30 06:55:52 -0500
committerPaul Mackerras <paulus@samba.org>2005-10-30 06:55:52 -0500
commit5f6b5b973a125de0dbe236ce659a495787c81ff0 (patch)
tree49286d23fff0b829e2c93831925eadceeeb6cd7a /arch/powerpc/kernel/time.c
parenteb66ce6333742e32825f0294310ff53e284fa828 (diff)
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 <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/time.c')
-rw-r--r--arch/powerpc/kernel/time.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 9f264c2f02c3..ed5c38fb146c 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -518,7 +518,7 @@ int do_settimeofday(struct timespec *tv)
518 long wtm_nsec, new_nsec = tv->tv_nsec; 518 long wtm_nsec, new_nsec = tv->tv_nsec;
519 unsigned long flags; 519 unsigned long flags;
520 long int tb_delta; 520 long int tb_delta;
521 u64 new_xsec; 521 u64 new_xsec, tb_delta_xs;
522 522
523 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) 523 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
524 return -EINVAL; 524 return -EINVAL;
@@ -541,8 +541,7 @@ int do_settimeofday(struct timespec *tv)
541#endif 541#endif
542 tb_delta = tb_ticks_since(tb_last_stamp); 542 tb_delta = tb_ticks_since(tb_last_stamp);
543 tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; 543 tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
544 544 tb_delta_xs = mulhdu(tb_delta, do_gtod.varp->tb_to_xs);
545 new_nsec -= 1000 * mulhwu(tb_to_us, tb_delta);
546 545
547 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec); 546 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec);
548 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec); 547 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec);
@@ -557,9 +556,12 @@ int do_settimeofday(struct timespec *tv)
557 556
558 ntp_clear(); 557 ntp_clear();
559 558
560 new_xsec = (u64)new_nsec * XSEC_PER_SEC; 559 new_xsec = 0;
561 do_div(new_xsec, NSEC_PER_SEC); 560 if (new_nsec != 0) {
562 new_xsec += (u64)new_sec * XSEC_PER_SEC; 561 new_xsec = (u64)new_nsec * XSEC_PER_SEC;
562 do_div(new_xsec, NSEC_PER_SEC);
563 }
564 new_xsec += (u64)new_sec * XSEC_PER_SEC - tb_delta_xs;
563 update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs); 565 update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs);
564 566
565#ifdef CONFIG_PPC64 567#ifdef CONFIG_PPC64