aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/linux/clocksource.h97
1 files changed, 97 insertions, 0 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);