summaryrefslogtreecommitdiffstats
path: root/kernel/time/timekeeping.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/time/timekeeping.c')
-rw-r--r--kernel/time/timekeeping.c53
1 files changed, 24 insertions, 29 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index dfdab1c..f4056f6 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -41,6 +41,8 @@ struct timekeeper {
/* Shift conversion between clock shifted nano seconds and
* ntp shifted nano seconds. */
int ntp_error_shift;
+ /* NTP adjusted clock multiplier */
+ u32 mult;
};
struct timekeeper timekeeper;
@@ -66,8 +68,8 @@ static void timekeeper_setup_internals(struct clocksource *clock)
/* Do the ns -> cycle conversion first, using original mult */
tmp = NTP_INTERVAL_LENGTH;
tmp <<= clock->shift;
- tmp += clock->mult_orig/2;
- do_div(tmp, clock->mult_orig);
+ tmp += clock->mult/2;
+ do_div(tmp, clock->mult);
if (tmp == 0)
tmp = 1;
@@ -77,13 +79,20 @@ static void timekeeper_setup_internals(struct clocksource *clock)
/* Go back from cycles -> shifted ns */
timekeeper.xtime_interval = (u64) interval * clock->mult;
timekeeper.raw_interval =
- ((u64) interval * clock->mult_orig) >> clock->shift;
+ ((u64) interval * clock->mult) >> clock->shift;
timekeeper.xtime_nsec = 0;
timekeeper.shift = clock->shift;
timekeeper.ntp_error = 0;
timekeeper.ntp_error_shift = NTP_SCALE_SHIFT - clock->shift;
+
+ /*
+ * The timekeeper keeps its own mult values for the currently
+ * active clocksource. These value will be adjusted via NTP
+ * to counteract clock drifting.
+ */
+ timekeeper.mult = clock->mult;
}
/*
@@ -154,14 +163,15 @@ static void timekeeping_forward_now(void)
cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
clock->cycle_last = cycle_now;
- nsec = clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);
+ nsec = clocksource_cyc2ns(cycle_delta, timekeeper.mult,
+ timekeeper.shift);
/* If arch requires, add in gettimeoffset() */
nsec += arch_gettimeoffset();
timespec_add_ns(&xtime, nsec);
- nsec = clocksource_cyc2ns(cycle_delta, clock->mult_orig, clock->shift);
+ nsec = clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);
timespec_add_ns(&raw_time, nsec);
}
@@ -193,8 +203,8 @@ void getnstimeofday(struct timespec *ts)
cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
/* convert to nanoseconds: */
- nsecs = clocksource_cyc2ns(cycle_delta, clock->mult,
- clock->shift);
+ nsecs = clocksource_cyc2ns(cycle_delta, timekeeper.mult,
+ timekeeper.shift);
/* If arch requires, add in gettimeoffset() */
nsecs += arch_gettimeoffset();
@@ -228,8 +238,8 @@ ktime_t ktime_get(void)
cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
/* convert to nanoseconds: */
- nsecs += clocksource_cyc2ns(cycle_delta, clock->mult,
- clock->shift);
+ nsecs += clocksource_cyc2ns(cycle_delta, timekeeper.mult,
+ timekeeper.shift);
} while (read_seqretry(&xtime_lock, seq));
/*
@@ -271,8 +281,8 @@ void ktime_get_ts(struct timespec *ts)
cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
/* convert to nanoseconds: */
- nsecs = clocksource_cyc2ns(cycle_delta, clock->mult,
- clock->shift);
+ nsecs = clocksource_cyc2ns(cycle_delta, timekeeper.mult,
+ timekeeper.shift);
} while (read_seqretry(&xtime_lock, seq));
@@ -356,22 +366,10 @@ static void change_clocksource(void)
if (new->enable && !new->enable(new))
return;
- /*
- * The frequency may have changed while the clocksource
- * was disabled. If so the code in ->enable() must update
- * the mult value to reflect the new frequency. Make sure
- * mult_orig follows this change.
- */
- new->mult_orig = new->mult;
old = timekeeper.clock;
timekeeper_setup_internals(new);
- /*
- * Save mult_orig in mult so that the value can be restored
- * regardless if ->enable() updates the value of mult or not.
- */
- old->mult = old->mult_orig;
if (old->disable)
old->disable(old);
@@ -461,7 +459,7 @@ void getrawmonotonic(struct timespec *ts)
cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
/* convert to nanoseconds: */
- nsecs = clocksource_cyc2ns(cycle_delta, clock->mult_orig,
+ nsecs = clocksource_cyc2ns(cycle_delta, clock->mult,
clock->shift);
*ts = raw_time;
@@ -521,9 +519,6 @@ void __init timekeeping_init(void)
clock = clocksource_default_clock();
if (clock->enable)
clock->enable(clock);
- /* set mult_orig on enable */
- clock->mult_orig = clock->mult;
-
timekeeper_setup_internals(clock);
xtime.tv_sec = sec;
@@ -697,7 +692,7 @@ static void timekeeping_adjust(s64 offset)
} else
return;
- timekeeper.clock->mult += adj;
+ timekeeper.mult += adj;
timekeeper.xtime_interval += interval;
timekeeper.xtime_nsec -= offset;
timekeeper.ntp_error -= (interval - offset) <<
@@ -789,7 +784,7 @@ void update_wall_time(void)
timekeeper.ntp_error += timekeeper.xtime_nsec <<
timekeeper.ntp_error_shift;
- nsecs = clocksource_cyc2ns(offset, clock->mult, clock->shift);
+ nsecs = clocksource_cyc2ns(offset, timekeeper.mult, timekeeper.shift);
update_xtime_cache(nsecs);
/* check to see if there is a new clocksource to use */
OpenPOWER on IntegriCloud