diff options
Diffstat (limited to 'arch/powerpc/kernel/time.c')
-rw-r--r-- | arch/powerpc/kernel/time.c | 105 |
1 files changed, 30 insertions, 75 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 522bb1dfc353..567dd7c3ac2a 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -86,8 +86,6 @@ static struct clocksource clocksource_rtc = { | |||
86 | .rating = 400, | 86 | .rating = 400, |
87 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 87 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
88 | .mask = CLOCKSOURCE_MASK(64), | 88 | .mask = CLOCKSOURCE_MASK(64), |
89 | .shift = 22, | ||
90 | .mult = 0, /* To be filled in */ | ||
91 | .read = rtc_read, | 89 | .read = rtc_read, |
92 | }; | 90 | }; |
93 | 91 | ||
@@ -97,8 +95,6 @@ static struct clocksource clocksource_timebase = { | |||
97 | .rating = 400, | 95 | .rating = 400, |
98 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 96 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
99 | .mask = CLOCKSOURCE_MASK(64), | 97 | .mask = CLOCKSOURCE_MASK(64), |
100 | .shift = 22, | ||
101 | .mult = 0, /* To be filled in */ | ||
102 | .read = timebase_read, | 98 | .read = timebase_read, |
103 | }; | 99 | }; |
104 | 100 | ||
@@ -110,22 +106,16 @@ static void decrementer_set_mode(enum clock_event_mode mode, | |||
110 | struct clock_event_device *dev); | 106 | struct clock_event_device *dev); |
111 | 107 | ||
112 | static struct clock_event_device decrementer_clockevent = { | 108 | static struct clock_event_device decrementer_clockevent = { |
113 | .name = "decrementer", | 109 | .name = "decrementer", |
114 | .rating = 200, | 110 | .rating = 200, |
115 | .shift = 0, /* To be filled in */ | 111 | .irq = 0, |
116 | .mult = 0, /* To be filled in */ | 112 | .set_next_event = decrementer_set_next_event, |
117 | .irq = 0, | 113 | .set_mode = decrementer_set_mode, |
118 | .set_next_event = decrementer_set_next_event, | 114 | .features = CLOCK_EVT_FEAT_ONESHOT, |
119 | .set_mode = decrementer_set_mode, | ||
120 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
121 | }; | 115 | }; |
122 | 116 | ||
123 | struct decrementer_clock { | 117 | DEFINE_PER_CPU(u64, decrementers_next_tb); |
124 | struct clock_event_device event; | 118 | static DEFINE_PER_CPU(struct clock_event_device, decrementers); |
125 | u64 next_tb; | ||
126 | }; | ||
127 | |||
128 | static DEFINE_PER_CPU(struct decrementer_clock, decrementers); | ||
129 | 119 | ||
130 | #ifdef CONFIG_PPC_ISERIES | 120 | #ifdef CONFIG_PPC_ISERIES |
131 | static unsigned long __initdata iSeries_recal_titan; | 121 | static unsigned long __initdata iSeries_recal_titan; |
@@ -168,13 +158,13 @@ EXPORT_SYMBOL_GPL(ppc_tb_freq); | |||
168 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 158 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
169 | /* | 159 | /* |
170 | * Factors for converting from cputime_t (timebase ticks) to | 160 | * Factors for converting from cputime_t (timebase ticks) to |
171 | * jiffies, milliseconds, seconds, and clock_t (1/USER_HZ seconds). | 161 | * jiffies, microseconds, seconds, and clock_t (1/USER_HZ seconds). |
172 | * These are all stored as 0.64 fixed-point binary fractions. | 162 | * These are all stored as 0.64 fixed-point binary fractions. |
173 | */ | 163 | */ |
174 | u64 __cputime_jiffies_factor; | 164 | u64 __cputime_jiffies_factor; |
175 | EXPORT_SYMBOL(__cputime_jiffies_factor); | 165 | EXPORT_SYMBOL(__cputime_jiffies_factor); |
176 | u64 __cputime_msec_factor; | 166 | u64 __cputime_usec_factor; |
177 | EXPORT_SYMBOL(__cputime_msec_factor); | 167 | EXPORT_SYMBOL(__cputime_usec_factor); |
178 | u64 __cputime_sec_factor; | 168 | u64 __cputime_sec_factor; |
179 | EXPORT_SYMBOL(__cputime_sec_factor); | 169 | EXPORT_SYMBOL(__cputime_sec_factor); |
180 | u64 __cputime_clockt_factor; | 170 | u64 __cputime_clockt_factor; |
@@ -192,8 +182,8 @@ static void calc_cputime_factors(void) | |||
192 | 182 | ||
193 | div128_by_32(HZ, 0, tb_ticks_per_sec, &res); | 183 | div128_by_32(HZ, 0, tb_ticks_per_sec, &res); |
194 | __cputime_jiffies_factor = res.result_low; | 184 | __cputime_jiffies_factor = res.result_low; |
195 | div128_by_32(1000, 0, tb_ticks_per_sec, &res); | 185 | div128_by_32(1000000, 0, tb_ticks_per_sec, &res); |
196 | __cputime_msec_factor = res.result_low; | 186 | __cputime_usec_factor = res.result_low; |
197 | div128_by_32(1, 0, tb_ticks_per_sec, &res); | 187 | div128_by_32(1, 0, tb_ticks_per_sec, &res); |
198 | __cputime_sec_factor = res.result_low; | 188 | __cputime_sec_factor = res.result_low; |
199 | div128_by_32(USER_HZ, 0, tb_ticks_per_sec, &res); | 189 | div128_by_32(USER_HZ, 0, tb_ticks_per_sec, &res); |
@@ -441,7 +431,7 @@ EXPORT_SYMBOL(profile_pc); | |||
441 | /* | 431 | /* |
442 | * This function recalibrates the timebase based on the 49-bit time-of-day | 432 | * This function recalibrates the timebase based on the 49-bit time-of-day |
443 | * value in the Titan chip. The Titan is much more accurate than the value | 433 | * value in the Titan chip. The Titan is much more accurate than the value |
444 | * returned by the service processor for the timebase frequency. | 434 | * returned by the service processor for the timebase frequency. |
445 | */ | 435 | */ |
446 | 436 | ||
447 | static int __init iSeries_tb_recal(void) | 437 | static int __init iSeries_tb_recal(void) |
@@ -576,9 +566,8 @@ void arch_irq_work_raise(void) | |||
576 | void timer_interrupt(struct pt_regs * regs) | 566 | void timer_interrupt(struct pt_regs * regs) |
577 | { | 567 | { |
578 | struct pt_regs *old_regs; | 568 | struct pt_regs *old_regs; |
579 | struct decrementer_clock *decrementer = &__get_cpu_var(decrementers); | 569 | u64 *next_tb = &__get_cpu_var(decrementers_next_tb); |
580 | struct clock_event_device *evt = &decrementer->event; | 570 | struct clock_event_device *evt = &__get_cpu_var(decrementers); |
581 | u64 now; | ||
582 | 571 | ||
583 | /* Ensure a positive value is written to the decrementer, or else | 572 | /* Ensure a positive value is written to the decrementer, or else |
584 | * some CPUs will continue to take decrementer exceptions. | 573 | * some CPUs will continue to take decrementer exceptions. |
@@ -613,16 +602,9 @@ void timer_interrupt(struct pt_regs * regs) | |||
613 | get_lppaca()->int_dword.fields.decr_int = 0; | 602 | get_lppaca()->int_dword.fields.decr_int = 0; |
614 | #endif | 603 | #endif |
615 | 604 | ||
616 | now = get_tb_or_rtc(); | 605 | *next_tb = ~(u64)0; |
617 | if (now >= decrementer->next_tb) { | 606 | if (evt->event_handler) |
618 | decrementer->next_tb = ~(u64)0; | 607 | evt->event_handler(evt); |
619 | if (evt->event_handler) | ||
620 | evt->event_handler(evt); | ||
621 | } else { | ||
622 | now = decrementer->next_tb - now; | ||
623 | if (now <= DECREMENTER_MAX) | ||
624 | set_dec((int)now); | ||
625 | } | ||
626 | 608 | ||
627 | #ifdef CONFIG_PPC_ISERIES | 609 | #ifdef CONFIG_PPC_ISERIES |
628 | if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending()) | 610 | if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending()) |
@@ -650,9 +632,9 @@ static void generic_suspend_disable_irqs(void) | |||
650 | * with suspending. | 632 | * with suspending. |
651 | */ | 633 | */ |
652 | 634 | ||
653 | set_dec(0x7fffffff); | 635 | set_dec(DECREMENTER_MAX); |
654 | local_irq_disable(); | 636 | local_irq_disable(); |
655 | set_dec(0x7fffffff); | 637 | set_dec(DECREMENTER_MAX); |
656 | } | 638 | } |
657 | 639 | ||
658 | static void generic_suspend_enable_irqs(void) | 640 | static void generic_suspend_enable_irqs(void) |
@@ -824,9 +806,8 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, | |||
824 | ++vdso_data->tb_update_count; | 806 | ++vdso_data->tb_update_count; |
825 | smp_mb(); | 807 | smp_mb(); |
826 | 808 | ||
827 | /* XXX this assumes clock->shift == 22 */ | 809 | /* 19342813113834067 ~= 2^(20+64) / 1e9 */ |
828 | /* 4611686018 ~= 2^(20+64-22) / 1e9 */ | 810 | new_tb_to_xs = (u64) mult * (19342813113834067ULL >> clock->shift); |
829 | new_tb_to_xs = (u64) mult * 4611686018ULL; | ||
830 | new_stamp_xsec = (u64) wall_time->tv_nsec * XSEC_PER_SEC; | 811 | new_stamp_xsec = (u64) wall_time->tv_nsec * XSEC_PER_SEC; |
831 | do_div(new_stamp_xsec, 1000000000); | 812 | do_div(new_stamp_xsec, 1000000000); |
832 | new_stamp_xsec += (u64) wall_time->tv_sec * XSEC_PER_SEC; | 813 | new_stamp_xsec += (u64) wall_time->tv_sec * XSEC_PER_SEC; |
@@ -877,9 +858,7 @@ static void __init clocksource_init(void) | |||
877 | else | 858 | else |
878 | clock = &clocksource_timebase; | 859 | clock = &clocksource_timebase; |
879 | 860 | ||
880 | clock->mult = clocksource_hz2mult(tb_ticks_per_sec, clock->shift); | 861 | if (clocksource_register_hz(clock, tb_ticks_per_sec)) { |
881 | |||
882 | if (clocksource_register(clock)) { | ||
883 | printk(KERN_ERR "clocksource: %s is already registered\n", | 862 | printk(KERN_ERR "clocksource: %s is already registered\n", |
884 | clock->name); | 863 | clock->name); |
885 | return; | 864 | return; |
@@ -892,7 +871,7 @@ static void __init clocksource_init(void) | |||
892 | static int decrementer_set_next_event(unsigned long evt, | 871 | static int decrementer_set_next_event(unsigned long evt, |
893 | struct clock_event_device *dev) | 872 | struct clock_event_device *dev) |
894 | { | 873 | { |
895 | __get_cpu_var(decrementers).next_tb = get_tb_or_rtc() + evt; | 874 | __get_cpu_var(decrementers_next_tb) = get_tb_or_rtc() + evt; |
896 | set_dec(evt); | 875 | set_dec(evt); |
897 | return 0; | 876 | return 0; |
898 | } | 877 | } |
@@ -904,34 +883,9 @@ static void decrementer_set_mode(enum clock_event_mode mode, | |||
904 | decrementer_set_next_event(DECREMENTER_MAX, dev); | 883 | decrementer_set_next_event(DECREMENTER_MAX, dev); |
905 | } | 884 | } |
906 | 885 | ||
907 | static inline uint64_t div_sc64(unsigned long ticks, unsigned long nsec, | ||
908 | int shift) | ||
909 | { | ||
910 | uint64_t tmp = ((uint64_t)ticks) << shift; | ||
911 | |||
912 | do_div(tmp, nsec); | ||
913 | return tmp; | ||
914 | } | ||
915 | |||
916 | static void __init setup_clockevent_multiplier(unsigned long hz) | ||
917 | { | ||
918 | u64 mult, shift = 32; | ||
919 | |||
920 | while (1) { | ||
921 | mult = div_sc64(hz, NSEC_PER_SEC, shift); | ||
922 | if (mult && (mult >> 32UL) == 0UL) | ||
923 | break; | ||
924 | |||
925 | shift--; | ||
926 | } | ||
927 | |||
928 | decrementer_clockevent.shift = shift; | ||
929 | decrementer_clockevent.mult = mult; | ||
930 | } | ||
931 | |||
932 | static void register_decrementer_clockevent(int cpu) | 886 | static void register_decrementer_clockevent(int cpu) |
933 | { | 887 | { |
934 | struct clock_event_device *dec = &per_cpu(decrementers, cpu).event; | 888 | struct clock_event_device *dec = &per_cpu(decrementers, cpu); |
935 | 889 | ||
936 | *dec = decrementer_clockevent; | 890 | *dec = decrementer_clockevent; |
937 | dec->cpumask = cpumask_of(cpu); | 891 | dec->cpumask = cpumask_of(cpu); |
@@ -946,7 +900,8 @@ static void __init init_decrementer_clockevent(void) | |||
946 | { | 900 | { |
947 | int cpu = smp_processor_id(); | 901 | int cpu = smp_processor_id(); |
948 | 902 | ||
949 | setup_clockevent_multiplier(ppc_tb_freq); | 903 | clockevents_calc_mult_shift(&decrementer_clockevent, ppc_tb_freq, 4); |
904 | |||
950 | decrementer_clockevent.max_delta_ns = | 905 | decrementer_clockevent.max_delta_ns = |
951 | clockevent_delta2ns(DECREMENTER_MAX, &decrementer_clockevent); | 906 | clockevent_delta2ns(DECREMENTER_MAX, &decrementer_clockevent); |
952 | decrementer_clockevent.min_delta_ns = | 907 | decrementer_clockevent.min_delta_ns = |
@@ -1014,10 +969,10 @@ void __init time_init(void) | |||
1014 | boot_tb = get_tb_or_rtc(); | 969 | boot_tb = get_tb_or_rtc(); |
1015 | 970 | ||
1016 | /* If platform provided a timezone (pmac), we correct the time */ | 971 | /* If platform provided a timezone (pmac), we correct the time */ |
1017 | if (timezone_offset) { | 972 | if (timezone_offset) { |
1018 | sys_tz.tz_minuteswest = -timezone_offset / 60; | 973 | sys_tz.tz_minuteswest = -timezone_offset / 60; |
1019 | sys_tz.tz_dsttime = 0; | 974 | sys_tz.tz_dsttime = 0; |
1020 | } | 975 | } |
1021 | 976 | ||
1022 | vdso_data->tb_update_count = 0; | 977 | vdso_data->tb_update_count = 0; |
1023 | vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; | 978 | vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; |