diff options
-rw-r--r-- | include/linux/clocksource.h | 97 | ||||
-rw-r--r-- | kernel/timer.c | 47 |
2 files changed, 125 insertions, 19 deletions
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index c4187cda0ee4..c4739c4e3039 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h | |||
@@ -173,6 +173,103 @@ static inline void calculate_clocksource_interval(struct clocksource *c, | |||
173 | c->interval_snsecs = (u64)c->interval_cycles * c->mult; | 173 | c->interval_snsecs = (u64)c->interval_cycles * c->mult; |
174 | } | 174 | } |
175 | 175 | ||
176 | |||
177 | /** | ||
178 | * error_aproximation - calculates an error adjustment for a given error | ||
179 | * | ||
180 | * @error: Error value (unsigned) | ||
181 | * @unit: Adjustment unit | ||
182 | * | ||
183 | * For a given error value, this function takes the adjustment unit | ||
184 | * and uses binary approximation to return a power of two adjustment value. | ||
185 | * | ||
186 | * This function is only for use by the the make_ntp_adj() function | ||
187 | * and you must hold a write on the xtime_lock when calling. | ||
188 | */ | ||
189 | static inline int error_aproximation(u64 error, u64 unit) | ||
190 | { | ||
191 | static int saved_adj = 0; | ||
192 | u64 adjusted_unit = unit << saved_adj; | ||
193 | |||
194 | if (error > (adjusted_unit * 2)) { | ||
195 | /* large error, so increment the adjustment factor */ | ||
196 | saved_adj++; | ||
197 | } else if (error > adjusted_unit) { | ||
198 | /* just right, don't touch it */ | ||
199 | } else if (saved_adj) { | ||
200 | /* small error, so drop the adjustment factor */ | ||
201 | saved_adj--; | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | return saved_adj; | ||
206 | } | ||
207 | |||
208 | |||
209 | /** | ||
210 | * make_ntp_adj - Adjusts the specified clocksource for a given error | ||
211 | * | ||
212 | * @clock: Pointer to clock to be adjusted | ||
213 | * @cycles_delta: Current unacounted cycle delta | ||
214 | * @error: Pointer to current error value | ||
215 | * | ||
216 | * Returns clock shifted nanosecond adjustment to be applied against | ||
217 | * the accumulated time value (ie: xtime). | ||
218 | * | ||
219 | * If the error value is large enough, this function calulates the | ||
220 | * (power of two) adjustment value, and adjusts the clock's mult and | ||
221 | * interval_snsecs values accordingly. | ||
222 | * | ||
223 | * However, since there may be some unaccumulated cycles, to avoid | ||
224 | * time inconsistencies we must adjust the accumulation value | ||
225 | * accordingly. | ||
226 | * | ||
227 | * This is not very intuitive, so the following proof should help: | ||
228 | * The basic timeofday algorithm: base + cycle * mult | ||
229 | * Thus: | ||
230 | * new_base + cycle * new_mult = old_base + cycle * old_mult | ||
231 | * new_base = old_base + cycle * old_mult - cycle * new_mult | ||
232 | * new_base = old_base + cycle * (old_mult - new_mult) | ||
233 | * new_base - old_base = cycle * (old_mult - new_mult) | ||
234 | * base_delta = cycle * (old_mult - new_mult) | ||
235 | * base_delta = cycle * (mult_delta) | ||
236 | * | ||
237 | * Where mult_delta is the adjustment value made to mult | ||
238 | * | ||
239 | */ | ||
240 | static inline s64 make_ntp_adj(struct clocksource *clock, | ||
241 | cycles_t cycles_delta, s64* error) | ||
242 | { | ||
243 | s64 ret = 0; | ||
244 | if (*error > ((s64)clock->interval_cycles+1)/2) { | ||
245 | /* calculate adjustment value */ | ||
246 | int adjustment = error_aproximation(*error, | ||
247 | clock->interval_cycles); | ||
248 | /* adjust clock */ | ||
249 | clock->mult += 1 << adjustment; | ||
250 | clock->interval_snsecs += clock->interval_cycles << adjustment; | ||
251 | |||
252 | /* adjust the base and error for the adjustment */ | ||
253 | ret = -(cycles_delta << adjustment); | ||
254 | *error -= clock->interval_cycles << adjustment; | ||
255 | /* XXX adj error for cycle_delta offset? */ | ||
256 | } else if ((-(*error)) > ((s64)clock->interval_cycles+1)/2) { | ||
257 | /* calculate adjustment value */ | ||
258 | int adjustment = error_aproximation(-(*error), | ||
259 | clock->interval_cycles); | ||
260 | /* adjust clock */ | ||
261 | clock->mult -= 1 << adjustment; | ||
262 | clock->interval_snsecs -= clock->interval_cycles << adjustment; | ||
263 | |||
264 | /* adjust the base and error for the adjustment */ | ||
265 | ret = cycles_delta << adjustment; | ||
266 | *error += clock->interval_cycles << adjustment; | ||
267 | /* XXX adj error for cycle_delta offset? */ | ||
268 | } | ||
269 | return ret; | ||
270 | } | ||
271 | |||
272 | |||
176 | /* used to install a new clocksource */ | 273 | /* used to install a new clocksource */ |
177 | int register_clocksource(struct clocksource*); | 274 | int register_clocksource(struct clocksource*); |
178 | void reselect_clocksource(void); | 275 | void reselect_clocksource(void); |
diff --git a/kernel/timer.c b/kernel/timer.c index 623f9ea198d8..6811436a031d 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -597,7 +597,6 @@ long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */ | |||
597 | long time_precision = 1; /* clock precision (us) */ | 597 | long time_precision = 1; /* clock precision (us) */ |
598 | long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */ | 598 | long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */ |
599 | long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */ | 599 | long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */ |
600 | static long time_phase; /* phase offset (scaled us) */ | ||
601 | long time_freq = (((NSEC_PER_SEC + HZ/2) % HZ - HZ/2) << SHIFT_USEC) / NSEC_PER_USEC; | 600 | long time_freq = (((NSEC_PER_SEC + HZ/2) % HZ - HZ/2) << SHIFT_USEC) / NSEC_PER_USEC; |
602 | /* frequency offset (scaled ppm)*/ | 601 | /* frequency offset (scaled ppm)*/ |
603 | static long time_adj; /* tick adjust (scaled 1 / HZ) */ | 602 | static long time_adj; /* tick adjust (scaled 1 / HZ) */ |
@@ -747,27 +746,14 @@ static long adjtime_adjustment(void) | |||
747 | } | 746 | } |
748 | 747 | ||
749 | /* in the NTP reference this is called "hardclock()" */ | 748 | /* in the NTP reference this is called "hardclock()" */ |
750 | static void update_wall_time_one_tick(void) | 749 | static void update_ntp_one_tick(void) |
751 | { | 750 | { |
752 | long time_adjust_step, delta_nsec; | 751 | long time_adjust_step; |
753 | 752 | ||
754 | time_adjust_step = adjtime_adjustment(); | 753 | time_adjust_step = adjtime_adjustment(); |
755 | if (time_adjust_step) | 754 | if (time_adjust_step) |
756 | /* Reduce by this step the amount of time left */ | 755 | /* Reduce by this step the amount of time left */ |
757 | time_adjust -= time_adjust_step; | 756 | time_adjust -= time_adjust_step; |
758 | delta_nsec = tick_nsec + time_adjust_step * 1000; | ||
759 | /* | ||
760 | * Advance the phase, once it gets to one microsecond, then | ||
761 | * advance the tick more. | ||
762 | */ | ||
763 | time_phase += time_adj; | ||
764 | if ((time_phase >= FINENSEC) || (time_phase <= -FINENSEC)) { | ||
765 | long ltemp = shift_right(time_phase, (SHIFT_SCALE - 10)); | ||
766 | time_phase -= ltemp << (SHIFT_SCALE - 10); | ||
767 | delta_nsec += ltemp; | ||
768 | } | ||
769 | xtime.tv_nsec += delta_nsec; | ||
770 | time_interpolator_update(delta_nsec); | ||
771 | 757 | ||
772 | /* Changes by adjtime() do not take effect till next tick. */ | 758 | /* Changes by adjtime() do not take effect till next tick. */ |
773 | if (time_next_adjust != 0) { | 759 | if (time_next_adjust != 0) { |
@@ -872,8 +858,13 @@ device_initcall(timekeeping_init_device); | |||
872 | */ | 858 | */ |
873 | static void update_wall_time(void) | 859 | static void update_wall_time(void) |
874 | { | 860 | { |
861 | static s64 remainder_snsecs, error; | ||
862 | s64 snsecs_per_sec; | ||
875 | cycle_t now, offset; | 863 | cycle_t now, offset; |
876 | 864 | ||
865 | snsecs_per_sec = (s64)NSEC_PER_SEC << clock->shift; | ||
866 | remainder_snsecs += (s64)xtime.tv_nsec << clock->shift; | ||
867 | |||
877 | now = read_clocksource(clock); | 868 | now = read_clocksource(clock); |
878 | offset = (now - last_clock_cycle)&clock->mask; | 869 | offset = (now - last_clock_cycle)&clock->mask; |
879 | 870 | ||
@@ -881,17 +872,35 @@ static void update_wall_time(void) | |||
881 | * case of lost or late ticks, it will accumulate correctly. | 872 | * case of lost or late ticks, it will accumulate correctly. |
882 | */ | 873 | */ |
883 | while (offset > clock->interval_cycles) { | 874 | while (offset > clock->interval_cycles) { |
875 | /* get the ntp interval in clock shifted nanoseconds */ | ||
876 | s64 ntp_snsecs = current_tick_length(clock->shift); | ||
877 | |||
884 | /* accumulate one interval */ | 878 | /* accumulate one interval */ |
879 | remainder_snsecs += clock->interval_snsecs; | ||
885 | last_clock_cycle += clock->interval_cycles; | 880 | last_clock_cycle += clock->interval_cycles; |
886 | offset -= clock->interval_cycles; | 881 | offset -= clock->interval_cycles; |
887 | 882 | ||
888 | update_wall_time_one_tick(); | 883 | /* interpolator bits */ |
889 | if (xtime.tv_nsec >= 1000000000) { | 884 | time_interpolator_update(clock->interval_snsecs |
890 | xtime.tv_nsec -= 1000000000; | 885 | >> clock->shift); |
886 | /* increment the NTP state machine */ | ||
887 | update_ntp_one_tick(); | ||
888 | |||
889 | /* accumulate error between NTP and clock interval */ | ||
890 | error += (ntp_snsecs - (s64)clock->interval_snsecs); | ||
891 | |||
892 | /* correct the clock when NTP error is too big */ | ||
893 | remainder_snsecs += make_ntp_adj(clock, offset, &error); | ||
894 | |||
895 | if (remainder_snsecs >= snsecs_per_sec) { | ||
896 | remainder_snsecs -= snsecs_per_sec; | ||
891 | xtime.tv_sec++; | 897 | xtime.tv_sec++; |
892 | second_overflow(); | 898 | second_overflow(); |
893 | } | 899 | } |
894 | } | 900 | } |
901 | /* store full nanoseconds into xtime */ | ||
902 | xtime.tv_nsec = remainder_snsecs >> clock->shift; | ||
903 | remainder_snsecs -= (s64)xtime.tv_nsec << clock->shift; | ||
895 | } | 904 | } |
896 | 905 | ||
897 | /* | 906 | /* |