diff options
author | Tony Breeds <tony@bakeyournoodle.com> | 2007-09-21 17:35:52 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-10-02 21:48:42 -0400 |
commit | 4a4cfe3836916e12282ceb5c4bdd799dc71af567 (patch) | |
tree | f5454326fa67be9db72c399b3703733e62a062fc /arch/powerpc/kernel/time.c | |
parent | aa3be5f32db137bc4404f32a24b36fb47d48d260 (diff) |
[POWERPC] Implement generic time of day clocksource for powerpc
Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/time.c')
-rw-r--r-- | arch/powerpc/kernel/time.c | 270 |
1 files changed, 98 insertions, 172 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index b94e4dffba19..e71a0d8c597a 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -65,17 +65,44 @@ | |||
65 | #include <asm/div64.h> | 65 | #include <asm/div64.h> |
66 | #include <asm/smp.h> | 66 | #include <asm/smp.h> |
67 | #include <asm/vdso_datapage.h> | 67 | #include <asm/vdso_datapage.h> |
68 | #ifdef CONFIG_PPC64 | ||
69 | #include <asm/firmware.h> | 68 | #include <asm/firmware.h> |
70 | #endif | ||
71 | #ifdef CONFIG_PPC_ISERIES | 69 | #ifdef CONFIG_PPC_ISERIES |
72 | #include <asm/iseries/it_lp_queue.h> | 70 | #include <asm/iseries/it_lp_queue.h> |
73 | #include <asm/iseries/hv_call_xm.h> | 71 | #include <asm/iseries/hv_call_xm.h> |
74 | #endif | 72 | #endif |
75 | 73 | ||
74 | /* powerpc clocksource/clockevent code */ | ||
75 | |||
76 | #include <linux/clocksource.h> | ||
77 | |||
78 | static cycle_t rtc_read(void); | ||
79 | static struct clocksource clocksource_rtc = { | ||
80 | .name = "rtc", | ||
81 | .rating = 400, | ||
82 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
83 | .mask = CLOCKSOURCE_MASK(64), | ||
84 | .shift = 22, | ||
85 | .mult = 0, /* To be filled in */ | ||
86 | .read = rtc_read, | ||
87 | }; | ||
88 | |||
89 | static cycle_t timebase_read(void); | ||
90 | static struct clocksource clocksource_timebase = { | ||
91 | .name = "timebase", | ||
92 | .rating = 400, | ||
93 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
94 | .mask = CLOCKSOURCE_MASK(64), | ||
95 | .shift = 22, | ||
96 | .mult = 0, /* To be filled in */ | ||
97 | .read = timebase_read, | ||
98 | }; | ||
99 | |||
76 | #ifdef CONFIG_PPC_ISERIES | 100 | #ifdef CONFIG_PPC_ISERIES |
77 | static unsigned long __initdata iSeries_recal_titan; | 101 | static unsigned long __initdata iSeries_recal_titan; |
78 | static signed long __initdata iSeries_recal_tb; | 102 | static signed long __initdata iSeries_recal_tb; |
103 | |||
104 | /* Forward declaration is only needed for iSereis compiles */ | ||
105 | void __init clocksource_init(void); | ||
79 | #endif | 106 | #endif |
80 | 107 | ||
81 | #define XSEC_PER_SEC (1024*1024) | 108 | #define XSEC_PER_SEC (1024*1024) |
@@ -343,65 +370,6 @@ void udelay(unsigned long usecs) | |||
343 | } | 370 | } |
344 | EXPORT_SYMBOL(udelay); | 371 | EXPORT_SYMBOL(udelay); |
345 | 372 | ||
346 | /* | ||
347 | * This version of gettimeofday has microsecond resolution. | ||
348 | */ | ||
349 | static inline void __do_gettimeofday(struct timeval *tv) | ||
350 | { | ||
351 | unsigned long sec, usec; | ||
352 | u64 tb_ticks, xsec; | ||
353 | struct gettimeofday_vars *temp_varp; | ||
354 | u64 temp_tb_to_xs, temp_stamp_xsec; | ||
355 | |||
356 | /* | ||
357 | * These calculations are faster (gets rid of divides) | ||
358 | * if done in units of 1/2^20 rather than microseconds. | ||
359 | * The conversion to microseconds at the end is done | ||
360 | * without a divide (and in fact, without a multiply) | ||
361 | */ | ||
362 | temp_varp = do_gtod.varp; | ||
363 | |||
364 | /* Sampling the time base must be done after loading | ||
365 | * do_gtod.varp in order to avoid racing with update_gtod. | ||
366 | */ | ||
367 | data_barrier(temp_varp); | ||
368 | tb_ticks = get_tb() - temp_varp->tb_orig_stamp; | ||
369 | temp_tb_to_xs = temp_varp->tb_to_xs; | ||
370 | temp_stamp_xsec = temp_varp->stamp_xsec; | ||
371 | xsec = temp_stamp_xsec + mulhdu(tb_ticks, temp_tb_to_xs); | ||
372 | sec = xsec / XSEC_PER_SEC; | ||
373 | usec = (unsigned long)xsec & (XSEC_PER_SEC - 1); | ||
374 | usec = SCALE_XSEC(usec, 1000000); | ||
375 | |||
376 | tv->tv_sec = sec; | ||
377 | tv->tv_usec = usec; | ||
378 | } | ||
379 | |||
380 | void do_gettimeofday(struct timeval *tv) | ||
381 | { | ||
382 | if (__USE_RTC()) { | ||
383 | /* do this the old way */ | ||
384 | unsigned long flags, seq; | ||
385 | unsigned int sec, nsec, usec; | ||
386 | |||
387 | do { | ||
388 | seq = read_seqbegin_irqsave(&xtime_lock, flags); | ||
389 | sec = xtime.tv_sec; | ||
390 | nsec = xtime.tv_nsec + tb_ticks_since(tb_last_jiffy); | ||
391 | } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); | ||
392 | usec = nsec / 1000; | ||
393 | while (usec >= 1000000) { | ||
394 | usec -= 1000000; | ||
395 | ++sec; | ||
396 | } | ||
397 | tv->tv_sec = sec; | ||
398 | tv->tv_usec = usec; | ||
399 | return; | ||
400 | } | ||
401 | __do_gettimeofday(tv); | ||
402 | } | ||
403 | |||
404 | EXPORT_SYMBOL(do_gettimeofday); | ||
405 | 373 | ||
406 | /* | 374 | /* |
407 | * There are two copies of tb_to_xs and stamp_xsec so that no | 375 | * There are two copies of tb_to_xs and stamp_xsec so that no |
@@ -447,56 +415,6 @@ static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, | |||
447 | ++(vdso_data->tb_update_count); | 415 | ++(vdso_data->tb_update_count); |
448 | } | 416 | } |
449 | 417 | ||
450 | /* | ||
451 | * When the timebase - tb_orig_stamp gets too big, we do a manipulation | ||
452 | * between tb_orig_stamp and stamp_xsec. The goal here is to keep the | ||
453 | * difference tb - tb_orig_stamp small enough to always fit inside a | ||
454 | * 32 bits number. This is a requirement of our fast 32 bits userland | ||
455 | * implementation in the vdso. If we "miss" a call to this function | ||
456 | * (interrupt latency, CPU locked in a spinlock, ...) and we end up | ||
457 | * with a too big difference, then the vdso will fallback to calling | ||
458 | * the syscall | ||
459 | */ | ||
460 | static __inline__ void timer_recalc_offset(u64 cur_tb) | ||
461 | { | ||
462 | unsigned long offset; | ||
463 | u64 new_stamp_xsec; | ||
464 | u64 tlen, t2x; | ||
465 | u64 tb, xsec_old, xsec_new; | ||
466 | struct gettimeofday_vars *varp; | ||
467 | |||
468 | if (__USE_RTC()) | ||
469 | return; | ||
470 | tlen = current_tick_length(); | ||
471 | offset = cur_tb - do_gtod.varp->tb_orig_stamp; | ||
472 | if (tlen == last_tick_len && offset < 0x80000000u) | ||
473 | return; | ||
474 | if (tlen != last_tick_len) { | ||
475 | t2x = mulhdu(tlen << TICKLEN_SHIFT, ticklen_to_xs); | ||
476 | last_tick_len = tlen; | ||
477 | } else | ||
478 | t2x = do_gtod.varp->tb_to_xs; | ||
479 | new_stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC; | ||
480 | do_div(new_stamp_xsec, 1000000000); | ||
481 | new_stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC; | ||
482 | |||
483 | ++vdso_data->tb_update_count; | ||
484 | smp_mb(); | ||
485 | |||
486 | /* | ||
487 | * Make sure time doesn't go backwards for userspace gettimeofday. | ||
488 | */ | ||
489 | tb = get_tb(); | ||
490 | varp = do_gtod.varp; | ||
491 | xsec_old = mulhdu(tb - varp->tb_orig_stamp, varp->tb_to_xs) | ||
492 | + varp->stamp_xsec; | ||
493 | xsec_new = mulhdu(tb - cur_tb, t2x) + new_stamp_xsec; | ||
494 | if (xsec_new < xsec_old) | ||
495 | new_stamp_xsec += xsec_old - xsec_new; | ||
496 | |||
497 | update_gtod(cur_tb, new_stamp_xsec, t2x); | ||
498 | } | ||
499 | |||
500 | #ifdef CONFIG_SMP | 418 | #ifdef CONFIG_SMP |
501 | unsigned long profile_pc(struct pt_regs *regs) | 419 | unsigned long profile_pc(struct pt_regs *regs) |
502 | { | 420 | { |
@@ -568,6 +486,8 @@ static int __init iSeries_tb_recal(void) | |||
568 | iSeries_recal_titan = titan; | 486 | iSeries_recal_titan = titan; |
569 | iSeries_recal_tb = tb; | 487 | iSeries_recal_tb = tb; |
570 | 488 | ||
489 | /* Called here as now we know accurate values for the timebase */ | ||
490 | clocksource_init(); | ||
571 | return 0; | 491 | return 0; |
572 | } | 492 | } |
573 | late_initcall(iSeries_tb_recal); | 493 | late_initcall(iSeries_tb_recal); |
@@ -650,7 +570,6 @@ void timer_interrupt(struct pt_regs * regs) | |||
650 | if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) { | 570 | if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) { |
651 | tb_last_jiffy = tb_next_jiffy; | 571 | tb_last_jiffy = tb_next_jiffy; |
652 | do_timer(1); | 572 | do_timer(1); |
653 | timer_recalc_offset(tb_last_jiffy); | ||
654 | } | 573 | } |
655 | write_sequnlock(&xtime_lock); | 574 | write_sequnlock(&xtime_lock); |
656 | } | 575 | } |
@@ -722,66 +641,6 @@ unsigned long long sched_clock(void) | |||
722 | return mulhdu(get_tb() - boot_tb, tb_to_ns_scale) << tb_to_ns_shift; | 641 | return mulhdu(get_tb() - boot_tb, tb_to_ns_scale) << tb_to_ns_shift; |
723 | } | 642 | } |
724 | 643 | ||
725 | int do_settimeofday(struct timespec *tv) | ||
726 | { | ||
727 | time_t wtm_sec, new_sec = tv->tv_sec; | ||
728 | long wtm_nsec, new_nsec = tv->tv_nsec; | ||
729 | unsigned long flags; | ||
730 | u64 new_xsec; | ||
731 | unsigned long tb_delta; | ||
732 | |||
733 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | ||
734 | return -EINVAL; | ||
735 | |||
736 | write_seqlock_irqsave(&xtime_lock, flags); | ||
737 | |||
738 | /* | ||
739 | * Updating the RTC is not the job of this code. If the time is | ||
740 | * stepped under NTP, the RTC will be updated after STA_UNSYNC | ||
741 | * is cleared. Tools like clock/hwclock either copy the RTC | ||
742 | * to the system time, in which case there is no point in writing | ||
743 | * to the RTC again, or write to the RTC but then they don't call | ||
744 | * settimeofday to perform this operation. | ||
745 | */ | ||
746 | |||
747 | /* Make userspace gettimeofday spin until we're done. */ | ||
748 | ++vdso_data->tb_update_count; | ||
749 | smp_mb(); | ||
750 | |||
751 | /* | ||
752 | * Subtract off the number of nanoseconds since the | ||
753 | * beginning of the last tick. | ||
754 | */ | ||
755 | tb_delta = tb_ticks_since(tb_last_jiffy); | ||
756 | tb_delta = mulhdu(tb_delta, do_gtod.varp->tb_to_xs); /* in xsec */ | ||
757 | new_nsec -= SCALE_XSEC(tb_delta, 1000000000); | ||
758 | |||
759 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec); | ||
760 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec); | ||
761 | |||
762 | set_normalized_timespec(&xtime, new_sec, new_nsec); | ||
763 | set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); | ||
764 | |||
765 | ntp_clear(); | ||
766 | |||
767 | new_xsec = xtime.tv_nsec; | ||
768 | if (new_xsec != 0) { | ||
769 | new_xsec *= XSEC_PER_SEC; | ||
770 | do_div(new_xsec, NSEC_PER_SEC); | ||
771 | } | ||
772 | new_xsec += (u64)xtime.tv_sec * XSEC_PER_SEC; | ||
773 | update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs); | ||
774 | |||
775 | vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; | ||
776 | vdso_data->tz_dsttime = sys_tz.tz_dsttime; | ||
777 | |||
778 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
779 | clock_was_set(); | ||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | EXPORT_SYMBOL(do_settimeofday); | ||
784 | |||
785 | static int __init get_freq(char *name, int cells, unsigned long *val) | 644 | static int __init get_freq(char *name, int cells, unsigned long *val) |
786 | { | 645 | { |
787 | struct device_node *cpu; | 646 | struct device_node *cpu; |
@@ -873,6 +732,69 @@ unsigned long read_persistent_clock(void) | |||
873 | tm.tm_hour, tm.tm_min, tm.tm_sec); | 732 | tm.tm_hour, tm.tm_min, tm.tm_sec); |
874 | } | 733 | } |
875 | 734 | ||
735 | /* clocksource code */ | ||
736 | static cycle_t rtc_read(void) | ||
737 | { | ||
738 | return (cycle_t)get_rtc(); | ||
739 | } | ||
740 | |||
741 | static cycle_t timebase_read(void) | ||
742 | { | ||
743 | return (cycle_t)get_tb(); | ||
744 | } | ||
745 | |||
746 | void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) | ||
747 | { | ||
748 | u64 t2x, stamp_xsec; | ||
749 | |||
750 | if (clock != &clocksource_timebase) | ||
751 | return; | ||
752 | |||
753 | /* Make userspace gettimeofday spin until we're done. */ | ||
754 | ++vdso_data->tb_update_count; | ||
755 | smp_mb(); | ||
756 | |||
757 | /* XXX this assumes clock->shift == 22 */ | ||
758 | /* 4611686018 ~= 2^(20+64-22) / 1e9 */ | ||
759 | t2x = (u64) clock->mult * 4611686018ULL; | ||
760 | stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC; | ||
761 | do_div(stamp_xsec, 1000000000); | ||
762 | stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC; | ||
763 | update_gtod(clock->cycle_last, stamp_xsec, t2x); | ||
764 | } | ||
765 | |||
766 | void update_vsyscall_tz(void) | ||
767 | { | ||
768 | /* Make userspace gettimeofday spin until we're done. */ | ||
769 | ++vdso_data->tb_update_count; | ||
770 | smp_mb(); | ||
771 | vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; | ||
772 | vdso_data->tz_dsttime = sys_tz.tz_dsttime; | ||
773 | smp_mb(); | ||
774 | ++vdso_data->tb_update_count; | ||
775 | } | ||
776 | |||
777 | void __init clocksource_init(void) | ||
778 | { | ||
779 | struct clocksource *clock; | ||
780 | |||
781 | if (__USE_RTC()) | ||
782 | clock = &clocksource_rtc; | ||
783 | else | ||
784 | clock = &clocksource_timebase; | ||
785 | |||
786 | clock->mult = clocksource_hz2mult(tb_ticks_per_sec, clock->shift); | ||
787 | |||
788 | if (clocksource_register(clock)) { | ||
789 | printk(KERN_ERR "clocksource: %s is already registered\n", | ||
790 | clock->name); | ||
791 | return; | ||
792 | } | ||
793 | |||
794 | printk(KERN_INFO "clocksource: %s mult[%x] shift[%d] registered\n", | ||
795 | clock->name, clock->mult, clock->shift); | ||
796 | } | ||
797 | |||
876 | /* This function is only called on the boot processor */ | 798 | /* This function is only called on the boot processor */ |
877 | void __init time_init(void) | 799 | void __init time_init(void) |
878 | { | 800 | { |
@@ -982,6 +904,10 @@ void __init time_init(void) | |||
982 | 904 | ||
983 | write_sequnlock_irqrestore(&xtime_lock, flags); | 905 | write_sequnlock_irqrestore(&xtime_lock, flags); |
984 | 906 | ||
907 | /* Register the clocksource, if we're not running on iSeries */ | ||
908 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
909 | clocksource_init(); | ||
910 | |||
985 | /* Not exact, but the timer interrupt takes care of this */ | 911 | /* Not exact, but the timer interrupt takes care of this */ |
986 | set_dec(tb_ticks_per_jiffy); | 912 | set_dec(tb_ticks_per_jiffy); |
987 | } | 913 | } |