diff options
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/timekeeping.c | 53 |
1 files changed, 24 insertions, 29 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index dfdab1cefe1e..f4056f6c2632 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -41,6 +41,8 @@ struct timekeeper { | |||
41 | /* Shift conversion between clock shifted nano seconds and | 41 | /* Shift conversion between clock shifted nano seconds and |
42 | * ntp shifted nano seconds. */ | 42 | * ntp shifted nano seconds. */ |
43 | int ntp_error_shift; | 43 | int ntp_error_shift; |
44 | /* NTP adjusted clock multiplier */ | ||
45 | u32 mult; | ||
44 | }; | 46 | }; |
45 | 47 | ||
46 | struct timekeeper timekeeper; | 48 | struct timekeeper timekeeper; |
@@ -66,8 +68,8 @@ static void timekeeper_setup_internals(struct clocksource *clock) | |||
66 | /* Do the ns -> cycle conversion first, using original mult */ | 68 | /* Do the ns -> cycle conversion first, using original mult */ |
67 | tmp = NTP_INTERVAL_LENGTH; | 69 | tmp = NTP_INTERVAL_LENGTH; |
68 | tmp <<= clock->shift; | 70 | tmp <<= clock->shift; |
69 | tmp += clock->mult_orig/2; | 71 | tmp += clock->mult/2; |
70 | do_div(tmp, clock->mult_orig); | 72 | do_div(tmp, clock->mult); |
71 | if (tmp == 0) | 73 | if (tmp == 0) |
72 | tmp = 1; | 74 | tmp = 1; |
73 | 75 | ||
@@ -77,13 +79,20 @@ static void timekeeper_setup_internals(struct clocksource *clock) | |||
77 | /* Go back from cycles -> shifted ns */ | 79 | /* Go back from cycles -> shifted ns */ |
78 | timekeeper.xtime_interval = (u64) interval * clock->mult; | 80 | timekeeper.xtime_interval = (u64) interval * clock->mult; |
79 | timekeeper.raw_interval = | 81 | timekeeper.raw_interval = |
80 | ((u64) interval * clock->mult_orig) >> clock->shift; | 82 | ((u64) interval * clock->mult) >> clock->shift; |
81 | 83 | ||
82 | timekeeper.xtime_nsec = 0; | 84 | timekeeper.xtime_nsec = 0; |
83 | timekeeper.shift = clock->shift; | 85 | timekeeper.shift = clock->shift; |
84 | 86 | ||
85 | timekeeper.ntp_error = 0; | 87 | timekeeper.ntp_error = 0; |
86 | timekeeper.ntp_error_shift = NTP_SCALE_SHIFT - clock->shift; | 88 | timekeeper.ntp_error_shift = NTP_SCALE_SHIFT - clock->shift; |
89 | |||
90 | /* | ||
91 | * The timekeeper keeps its own mult values for the currently | ||
92 | * active clocksource. These value will be adjusted via NTP | ||
93 | * to counteract clock drifting. | ||
94 | */ | ||
95 | timekeeper.mult = clock->mult; | ||
87 | } | 96 | } |
88 | 97 | ||
89 | /* | 98 | /* |
@@ -154,14 +163,15 @@ static void timekeeping_forward_now(void) | |||
154 | cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; | 163 | cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; |
155 | clock->cycle_last = cycle_now; | 164 | clock->cycle_last = cycle_now; |
156 | 165 | ||
157 | nsec = clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift); | 166 | nsec = clocksource_cyc2ns(cycle_delta, timekeeper.mult, |
167 | timekeeper.shift); | ||
158 | 168 | ||
159 | /* If arch requires, add in gettimeoffset() */ | 169 | /* If arch requires, add in gettimeoffset() */ |
160 | nsec += arch_gettimeoffset(); | 170 | nsec += arch_gettimeoffset(); |
161 | 171 | ||
162 | timespec_add_ns(&xtime, nsec); | 172 | timespec_add_ns(&xtime, nsec); |
163 | 173 | ||
164 | nsec = clocksource_cyc2ns(cycle_delta, clock->mult_orig, clock->shift); | 174 | nsec = clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift); |
165 | timespec_add_ns(&raw_time, nsec); | 175 | timespec_add_ns(&raw_time, nsec); |
166 | } | 176 | } |
167 | 177 | ||
@@ -193,8 +203,8 @@ void getnstimeofday(struct timespec *ts) | |||
193 | cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; | 203 | cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; |
194 | 204 | ||
195 | /* convert to nanoseconds: */ | 205 | /* convert to nanoseconds: */ |
196 | nsecs = clocksource_cyc2ns(cycle_delta, clock->mult, | 206 | nsecs = clocksource_cyc2ns(cycle_delta, timekeeper.mult, |
197 | clock->shift); | 207 | timekeeper.shift); |
198 | 208 | ||
199 | /* If arch requires, add in gettimeoffset() */ | 209 | /* If arch requires, add in gettimeoffset() */ |
200 | nsecs += arch_gettimeoffset(); | 210 | nsecs += arch_gettimeoffset(); |
@@ -228,8 +238,8 @@ ktime_t ktime_get(void) | |||
228 | cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; | 238 | cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; |
229 | 239 | ||
230 | /* convert to nanoseconds: */ | 240 | /* convert to nanoseconds: */ |
231 | nsecs += clocksource_cyc2ns(cycle_delta, clock->mult, | 241 | nsecs += clocksource_cyc2ns(cycle_delta, timekeeper.mult, |
232 | clock->shift); | 242 | timekeeper.shift); |
233 | 243 | ||
234 | } while (read_seqretry(&xtime_lock, seq)); | 244 | } while (read_seqretry(&xtime_lock, seq)); |
235 | /* | 245 | /* |
@@ -271,8 +281,8 @@ void ktime_get_ts(struct timespec *ts) | |||
271 | cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; | 281 | cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; |
272 | 282 | ||
273 | /* convert to nanoseconds: */ | 283 | /* convert to nanoseconds: */ |
274 | nsecs = clocksource_cyc2ns(cycle_delta, clock->mult, | 284 | nsecs = clocksource_cyc2ns(cycle_delta, timekeeper.mult, |
275 | clock->shift); | 285 | timekeeper.shift); |
276 | 286 | ||
277 | } while (read_seqretry(&xtime_lock, seq)); | 287 | } while (read_seqretry(&xtime_lock, seq)); |
278 | 288 | ||
@@ -356,22 +366,10 @@ static void change_clocksource(void) | |||
356 | 366 | ||
357 | if (new->enable && !new->enable(new)) | 367 | if (new->enable && !new->enable(new)) |
358 | return; | 368 | return; |
359 | /* | ||
360 | * The frequency may have changed while the clocksource | ||
361 | * was disabled. If so the code in ->enable() must update | ||
362 | * the mult value to reflect the new frequency. Make sure | ||
363 | * mult_orig follows this change. | ||
364 | */ | ||
365 | new->mult_orig = new->mult; | ||
366 | 369 | ||
367 | old = timekeeper.clock; | 370 | old = timekeeper.clock; |
368 | timekeeper_setup_internals(new); | 371 | timekeeper_setup_internals(new); |
369 | 372 | ||
370 | /* | ||
371 | * Save mult_orig in mult so that the value can be restored | ||
372 | * regardless if ->enable() updates the value of mult or not. | ||
373 | */ | ||
374 | old->mult = old->mult_orig; | ||
375 | if (old->disable) | 373 | if (old->disable) |
376 | old->disable(old); | 374 | old->disable(old); |
377 | 375 | ||
@@ -461,7 +459,7 @@ void getrawmonotonic(struct timespec *ts) | |||
461 | cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; | 459 | cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; |
462 | 460 | ||
463 | /* convert to nanoseconds: */ | 461 | /* convert to nanoseconds: */ |
464 | nsecs = clocksource_cyc2ns(cycle_delta, clock->mult_orig, | 462 | nsecs = clocksource_cyc2ns(cycle_delta, clock->mult, |
465 | clock->shift); | 463 | clock->shift); |
466 | 464 | ||
467 | *ts = raw_time; | 465 | *ts = raw_time; |
@@ -521,9 +519,6 @@ void __init timekeeping_init(void) | |||
521 | clock = clocksource_default_clock(); | 519 | clock = clocksource_default_clock(); |
522 | if (clock->enable) | 520 | if (clock->enable) |
523 | clock->enable(clock); | 521 | clock->enable(clock); |
524 | /* set mult_orig on enable */ | ||
525 | clock->mult_orig = clock->mult; | ||
526 | |||
527 | timekeeper_setup_internals(clock); | 522 | timekeeper_setup_internals(clock); |
528 | 523 | ||
529 | xtime.tv_sec = sec; | 524 | xtime.tv_sec = sec; |
@@ -697,7 +692,7 @@ static void timekeeping_adjust(s64 offset) | |||
697 | } else | 692 | } else |
698 | return; | 693 | return; |
699 | 694 | ||
700 | timekeeper.clock->mult += adj; | 695 | timekeeper.mult += adj; |
701 | timekeeper.xtime_interval += interval; | 696 | timekeeper.xtime_interval += interval; |
702 | timekeeper.xtime_nsec -= offset; | 697 | timekeeper.xtime_nsec -= offset; |
703 | timekeeper.ntp_error -= (interval - offset) << | 698 | timekeeper.ntp_error -= (interval - offset) << |
@@ -789,7 +784,7 @@ void update_wall_time(void) | |||
789 | timekeeper.ntp_error += timekeeper.xtime_nsec << | 784 | timekeeper.ntp_error += timekeeper.xtime_nsec << |
790 | timekeeper.ntp_error_shift; | 785 | timekeeper.ntp_error_shift; |
791 | 786 | ||
792 | nsecs = clocksource_cyc2ns(offset, clock->mult, clock->shift); | 787 | nsecs = clocksource_cyc2ns(offset, timekeeper.mult, timekeeper.shift); |
793 | update_xtime_cache(nsecs); | 788 | update_xtime_cache(nsecs); |
794 | 789 | ||
795 | /* check to see if there is a new clocksource to use */ | 790 | /* check to see if there is a new clocksource to use */ |