aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/clocksource.h97
-rw-r--r--kernel/timer.c47
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 */
189static 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 */
240static 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 */
177int register_clocksource(struct clocksource*); 274int register_clocksource(struct clocksource*);
178void reselect_clocksource(void); 275void 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) */
597long time_precision = 1; /* clock precision (us) */ 597long time_precision = 1; /* clock precision (us) */
598long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */ 598long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */
599long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */ 599long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */
600static long time_phase; /* phase offset (scaled us) */
601long time_freq = (((NSEC_PER_SEC + HZ/2) % HZ - HZ/2) << SHIFT_USEC) / NSEC_PER_USEC; 600long 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)*/
603static long time_adj; /* tick adjust (scaled 1 / HZ) */ 602static 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()" */
750static void update_wall_time_one_tick(void) 749static 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 */
873static void update_wall_time(void) 859static 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/*