diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/clocksource.h | 97 |
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 | */ | ||
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); |