diff options
Diffstat (limited to 'include/linux/clocksource.h')
| -rw-r--r-- | include/linux/clocksource.h | 113 |
1 files changed, 9 insertions, 104 deletions
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 4bc94282c364..d852024ed095 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h | |||
| @@ -46,8 +46,8 @@ typedef u64 cycle_t; | |||
| 46 | * @shift: cycle to nanosecond divisor (power of two) | 46 | * @shift: cycle to nanosecond divisor (power of two) |
| 47 | * @update_callback: called when safe to alter clocksource values | 47 | * @update_callback: called when safe to alter clocksource values |
| 48 | * @is_continuous: defines if clocksource is free-running. | 48 | * @is_continuous: defines if clocksource is free-running. |
| 49 | * @interval_cycles: Used internally by timekeeping core, please ignore. | 49 | * @cycle_interval: Used internally by timekeeping core, please ignore. |
| 50 | * @interval_snsecs: Used internally by timekeeping core, please ignore. | 50 | * @xtime_interval: Used internally by timekeeping core, please ignore. |
| 51 | */ | 51 | */ |
| 52 | struct clocksource { | 52 | struct clocksource { |
| 53 | char *name; | 53 | char *name; |
| @@ -61,8 +61,9 @@ struct clocksource { | |||
| 61 | int is_continuous; | 61 | int is_continuous; |
| 62 | 62 | ||
| 63 | /* timekeeping specific data, ignore */ | 63 | /* timekeeping specific data, ignore */ |
| 64 | cycle_t interval_cycles; | 64 | cycle_t cycle_last, cycle_interval; |
| 65 | u64 interval_snsecs; | 65 | u64 xtime_nsec, xtime_interval; |
| 66 | s64 error; | ||
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| 68 | /* simplify initialization of mask field */ | 69 | /* simplify initialization of mask field */ |
| @@ -168,107 +169,11 @@ static inline void clocksource_calculate_interval(struct clocksource *c, | |||
| 168 | tmp += c->mult/2; | 169 | tmp += c->mult/2; |
| 169 | do_div(tmp, c->mult); | 170 | do_div(tmp, c->mult); |
| 170 | 171 | ||
| 171 | c->interval_cycles = (cycle_t)tmp; | 172 | c->cycle_interval = (cycle_t)tmp; |
| 172 | if(c->interval_cycles == 0) | 173 | if (c->cycle_interval == 0) |
| 173 | c->interval_cycles = 1; | 174 | c->cycle_interval = 1; |
| 174 | 175 | ||
| 175 | c->interval_snsecs = (u64)c->interval_cycles * c->mult; | 176 | c->xtime_interval = (u64)c->cycle_interval * c->mult; |
| 176 | } | ||
| 177 | |||
| 178 | |||
| 179 | /** | ||
| 180 | * error_aproximation - calculates an error adjustment for a given error | ||
| 181 | * | ||
| 182 | * @error: Error value (unsigned) | ||
| 183 | * @unit: Adjustment unit | ||
| 184 | * | ||
| 185 | * For a given error value, this function takes the adjustment unit | ||
| 186 | * and uses binary approximation to return a power of two adjustment value. | ||
| 187 | * | ||
| 188 | * This function is only for use by the the make_ntp_adj() function | ||
| 189 | * and you must hold a write on the xtime_lock when calling. | ||
| 190 | */ | ||
| 191 | static inline int error_aproximation(u64 error, u64 unit) | ||
| 192 | { | ||
| 193 | static int saved_adj = 0; | ||
| 194 | u64 adjusted_unit = unit << saved_adj; | ||
| 195 | |||
| 196 | if (error > (adjusted_unit * 2)) { | ||
| 197 | /* large error, so increment the adjustment factor */ | ||
| 198 | saved_adj++; | ||
| 199 | } else if (error > adjusted_unit) { | ||
| 200 | /* just right, don't touch it */ | ||
| 201 | } else if (saved_adj) { | ||
| 202 | /* small error, so drop the adjustment factor */ | ||
| 203 | saved_adj--; | ||
| 204 | return 0; | ||
| 205 | } | ||
| 206 | |||
| 207 | return saved_adj; | ||
| 208 | } | ||
| 209 | |||
| 210 | |||
| 211 | /** | ||
| 212 | * make_ntp_adj - Adjusts the specified clocksource for a given error | ||
| 213 | * | ||
| 214 | * @clock: Pointer to clock to be adjusted | ||
| 215 | * @cycles_delta: Current unacounted cycle delta | ||
| 216 | * @error: Pointer to current error value | ||
| 217 | * | ||
| 218 | * Returns clock shifted nanosecond adjustment to be applied against | ||
| 219 | * the accumulated time value (ie: xtime). | ||
| 220 | * | ||
| 221 | * If the error value is large enough, this function calulates the | ||
| 222 | * (power of two) adjustment value, and adjusts the clock's mult and | ||
| 223 | * interval_snsecs values accordingly. | ||
| 224 | * | ||
| 225 | * However, since there may be some unaccumulated cycles, to avoid | ||
| 226 | * time inconsistencies we must adjust the accumulation value | ||
| 227 | * accordingly. | ||
| 228 | * | ||
| 229 | * This is not very intuitive, so the following proof should help: | ||
| 230 | * The basic timeofday algorithm: base + cycle * mult | ||
| 231 | * Thus: | ||
| 232 | * new_base + cycle * new_mult = old_base + cycle * old_mult | ||
| 233 | * new_base = old_base + cycle * old_mult - cycle * new_mult | ||
| 234 | * new_base = old_base + cycle * (old_mult - new_mult) | ||
| 235 | * new_base - old_base = cycle * (old_mult - new_mult) | ||
| 236 | * base_delta = cycle * (old_mult - new_mult) | ||
| 237 | * base_delta = cycle * (mult_delta) | ||
| 238 | * | ||
| 239 | * Where mult_delta is the adjustment value made to mult | ||
| 240 | * | ||
| 241 | */ | ||
| 242 | static inline s64 make_ntp_adj(struct clocksource *clock, | ||
| 243 | cycles_t cycles_delta, s64* error) | ||
| 244 | { | ||
| 245 | s64 ret = 0; | ||
| 246 | if (*error > ((s64)clock->interval_cycles+1)/2) { | ||
| 247 | /* calculate adjustment value */ | ||
| 248 | int adjustment = error_aproximation(*error, | ||
| 249 | clock->interval_cycles); | ||
| 250 | /* adjust clock */ | ||
| 251 | clock->mult += 1 << adjustment; | ||
| 252 | clock->interval_snsecs += clock->interval_cycles << adjustment; | ||
| 253 | |||
| 254 | /* adjust the base and error for the adjustment */ | ||
| 255 | ret = -(cycles_delta << adjustment); | ||
| 256 | *error -= clock->interval_cycles << adjustment; | ||
| 257 | /* XXX adj error for cycle_delta offset? */ | ||
| 258 | } else if ((-(*error)) > ((s64)clock->interval_cycles+1)/2) { | ||
| 259 | /* calculate adjustment value */ | ||
| 260 | int adjustment = error_aproximation(-(*error), | ||
| 261 | clock->interval_cycles); | ||
| 262 | /* adjust clock */ | ||
| 263 | clock->mult -= 1 << adjustment; | ||
| 264 | clock->interval_snsecs -= clock->interval_cycles << adjustment; | ||
| 265 | |||
| 266 | /* adjust the base and error for the adjustment */ | ||
| 267 | ret = cycles_delta << adjustment; | ||
| 268 | *error += clock->interval_cycles << adjustment; | ||
| 269 | /* XXX adj error for cycle_delta offset? */ | ||
| 270 | } | ||
| 271 | return ret; | ||
| 272 | } | 177 | } |
| 273 | 178 | ||
| 274 | 179 | ||
