diff options
| author | Paul Mackerras <paulus@samba.org> | 2006-03-16 20:01:19 -0500 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2006-03-16 20:01:19 -0500 |
| commit | 23dd64011285010ac291f7dddf6e287bdb43a0ad (patch) | |
| tree | 0e4f4569d38d82f4dceb4150d5ad940e0fd5f24f /arch/powerpc/kernel/time.c | |
| parent | 516450179454de9e689e0a53ed8f34b896e8651c (diff) | |
| parent | 485ff09990416c75ae9593ddc71619939ab9dd51 (diff) | |
Merge ../linux-2.6
Diffstat (limited to 'arch/powerpc/kernel/time.c')
| -rw-r--r-- | arch/powerpc/kernel/time.c | 48 |
1 files changed, 34 insertions, 14 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 4f20a5f15d49..4a27218a086c 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
| @@ -503,9 +503,9 @@ static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, | |||
| 503 | * the two values of tb_update_count match and are even then the | 503 | * the two values of tb_update_count match and are even then the |
| 504 | * tb_to_xs and stamp_xsec values are consistent. If not, then it | 504 | * tb_to_xs and stamp_xsec values are consistent. If not, then it |
| 505 | * loops back and reads them again until this criteria is met. | 505 | * loops back and reads them again until this criteria is met. |
| 506 | * We expect the caller to have done the first increment of | ||
| 507 | * vdso_data->tb_update_count already. | ||
| 506 | */ | 508 | */ |
| 507 | ++(vdso_data->tb_update_count); | ||
| 508 | smp_wmb(); | ||
| 509 | vdso_data->tb_orig_stamp = new_tb_stamp; | 509 | vdso_data->tb_orig_stamp = new_tb_stamp; |
| 510 | vdso_data->stamp_xsec = new_stamp_xsec; | 510 | vdso_data->stamp_xsec = new_stamp_xsec; |
| 511 | vdso_data->tb_to_xs = new_tb_to_xs; | 511 | vdso_data->tb_to_xs = new_tb_to_xs; |
| @@ -530,20 +530,15 @@ static __inline__ void timer_recalc_offset(u64 cur_tb) | |||
| 530 | unsigned long offset; | 530 | unsigned long offset; |
| 531 | u64 new_stamp_xsec; | 531 | u64 new_stamp_xsec; |
| 532 | u64 tlen, t2x; | 532 | u64 tlen, t2x; |
| 533 | u64 tb, xsec_old, xsec_new; | ||
| 534 | struct gettimeofday_vars *varp; | ||
| 533 | 535 | ||
| 534 | if (__USE_RTC()) | 536 | if (__USE_RTC()) |
| 535 | return; | 537 | return; |
| 536 | tlen = current_tick_length(); | 538 | tlen = current_tick_length(); |
| 537 | offset = cur_tb - do_gtod.varp->tb_orig_stamp; | 539 | offset = cur_tb - do_gtod.varp->tb_orig_stamp; |
| 538 | if (tlen == last_tick_len && offset < 0x80000000u) { | 540 | if (tlen == last_tick_len && offset < 0x80000000u) |
| 539 | /* check that we're still in sync; if not, resync */ | 541 | return; |
| 540 | struct timeval tv; | ||
| 541 | __do_gettimeofday(&tv, cur_tb); | ||
| 542 | if (tv.tv_sec <= xtime.tv_sec && | ||
| 543 | (tv.tv_sec < xtime.tv_sec || | ||
| 544 | tv.tv_usec * 1000 <= xtime.tv_nsec)) | ||
| 545 | return; | ||
| 546 | } | ||
| 547 | if (tlen != last_tick_len) { | 542 | if (tlen != last_tick_len) { |
| 548 | t2x = mulhdu(tlen << TICKLEN_SHIFT, ticklen_to_xs); | 543 | t2x = mulhdu(tlen << TICKLEN_SHIFT, ticklen_to_xs); |
| 549 | last_tick_len = tlen; | 544 | last_tick_len = tlen; |
| @@ -552,6 +547,21 @@ static __inline__ void timer_recalc_offset(u64 cur_tb) | |||
| 552 | new_stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC; | 547 | new_stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC; |
| 553 | do_div(new_stamp_xsec, 1000000000); | 548 | do_div(new_stamp_xsec, 1000000000); |
| 554 | new_stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC; | 549 | new_stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC; |
| 550 | |||
| 551 | ++vdso_data->tb_update_count; | ||
| 552 | smp_mb(); | ||
| 553 | |||
| 554 | /* | ||
| 555 | * Make sure time doesn't go backwards for userspace gettimeofday. | ||
| 556 | */ | ||
| 557 | tb = get_tb(); | ||
| 558 | varp = do_gtod.varp; | ||
| 559 | xsec_old = mulhdu(tb - varp->tb_orig_stamp, varp->tb_to_xs) | ||
| 560 | + varp->stamp_xsec; | ||
| 561 | xsec_new = mulhdu(tb - cur_tb, t2x) + new_stamp_xsec; | ||
| 562 | if (xsec_new < xsec_old) | ||
| 563 | new_stamp_xsec += xsec_old - xsec_new; | ||
| 564 | |||
| 555 | update_gtod(cur_tb, new_stamp_xsec, t2x); | 565 | update_gtod(cur_tb, new_stamp_xsec, t2x); |
| 556 | } | 566 | } |
| 557 | 567 | ||
| @@ -800,6 +810,10 @@ int do_settimeofday(struct timespec *tv) | |||
| 800 | } | 810 | } |
| 801 | #endif | 811 | #endif |
| 802 | 812 | ||
| 813 | /* Make userspace gettimeofday spin until we're done. */ | ||
| 814 | ++vdso_data->tb_update_count; | ||
| 815 | smp_mb(); | ||
| 816 | |||
| 803 | /* | 817 | /* |
| 804 | * Subtract off the number of nanoseconds since the | 818 | * Subtract off the number of nanoseconds since the |
| 805 | * beginning of the last tick. | 819 | * beginning of the last tick. |
| @@ -961,10 +975,16 @@ void __init time_init(void) | |||
| 961 | * It is computed as: | 975 | * It is computed as: |
| 962 | * ticklen_to_xs = 2^N / (tb_ticks_per_jiffy * 1e9) | 976 | * ticklen_to_xs = 2^N / (tb_ticks_per_jiffy * 1e9) |
| 963 | * where N = 64 + 20 - TICKLEN_SCALE - TICKLEN_SHIFT | 977 | * where N = 64 + 20 - TICKLEN_SCALE - TICKLEN_SHIFT |
| 964 | * so as to give the result as a 0.64 fixed-point fraction. | 978 | * which turns out to be N = 51 - SHIFT_HZ. |
| 979 | * This gives the result as a 0.64 fixed-point fraction. | ||
| 980 | * That value is reduced by an offset amounting to 1 xsec per | ||
| 981 | * 2^31 timebase ticks to avoid problems with time going backwards | ||
| 982 | * by 1 xsec when we do timer_recalc_offset due to losing the | ||
| 983 | * fractional xsec. That offset is equal to ppc_tb_freq/2^51 | ||
| 984 | * since there are 2^20 xsec in a second. | ||
| 965 | */ | 985 | */ |
| 966 | div128_by_32(1ULL << (64 + 20 - TICKLEN_SCALE - TICKLEN_SHIFT), 0, | 986 | div128_by_32((1ULL << 51) - ppc_tb_freq, 0, |
| 967 | tb_ticks_per_jiffy, &res); | 987 | tb_ticks_per_jiffy << SHIFT_HZ, &res); |
| 968 | div128_by_32(res.result_high, res.result_low, NSEC_PER_SEC, &res); | 988 | div128_by_32(res.result_high, res.result_low, NSEC_PER_SEC, &res); |
| 969 | ticklen_to_xs = res.result_low; | 989 | ticklen_to_xs = res.result_low; |
| 970 | 990 | ||
