|
@@ -34,6 +34,14 @@
|
|
#define TK_MIRROR (1 << 1)
|
|
#define TK_MIRROR (1 << 1)
|
|
#define TK_CLOCK_WAS_SET (1 << 2)
|
|
#define TK_CLOCK_WAS_SET (1 << 2)
|
|
|
|
|
|
|
|
+enum timekeeping_adv_mode {
|
|
|
|
+ /* Update timekeeper when a tick has passed */
|
|
|
|
+ TK_ADV_TICK,
|
|
|
|
+
|
|
|
|
+ /* Update timekeeper on a direct frequency change */
|
|
|
|
+ TK_ADV_FREQ
|
|
|
|
+};
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* The most important data for readout fits into a single 64 byte
|
|
* The most important data for readout fits into a single 64 byte
|
|
* cache line.
|
|
* cache line.
|
|
@@ -2021,11 +2029,11 @@ static u64 logarithmic_accumulation(struct timekeeper *tk, u64 offset,
|
|
return offset;
|
|
return offset;
|
|
}
|
|
}
|
|
|
|
|
|
-/**
|
|
|
|
- * update_wall_time - Uses the current clocksource to increment the wall time
|
|
|
|
- *
|
|
|
|
|
|
+/*
|
|
|
|
+ * timekeeping_advance - Updates the timekeeper to the current time and
|
|
|
|
+ * current NTP tick length
|
|
*/
|
|
*/
|
|
-void update_wall_time(void)
|
|
|
|
|
|
+static void timekeeping_advance(enum timekeeping_adv_mode mode)
|
|
{
|
|
{
|
|
struct timekeeper *real_tk = &tk_core.timekeeper;
|
|
struct timekeeper *real_tk = &tk_core.timekeeper;
|
|
struct timekeeper *tk = &shadow_timekeeper;
|
|
struct timekeeper *tk = &shadow_timekeeper;
|
|
@@ -2042,14 +2050,17 @@ void update_wall_time(void)
|
|
|
|
|
|
#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
|
|
#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
|
|
offset = real_tk->cycle_interval;
|
|
offset = real_tk->cycle_interval;
|
|
|
|
+
|
|
|
|
+ if (mode != TK_ADV_TICK)
|
|
|
|
+ goto out;
|
|
#else
|
|
#else
|
|
offset = clocksource_delta(tk_clock_read(&tk->tkr_mono),
|
|
offset = clocksource_delta(tk_clock_read(&tk->tkr_mono),
|
|
tk->tkr_mono.cycle_last, tk->tkr_mono.mask);
|
|
tk->tkr_mono.cycle_last, tk->tkr_mono.mask);
|
|
-#endif
|
|
|
|
|
|
|
|
/* Check if there's really nothing to do */
|
|
/* Check if there's really nothing to do */
|
|
- if (offset < real_tk->cycle_interval)
|
|
|
|
|
|
+ if (offset < real_tk->cycle_interval && mode == TK_ADV_TICK)
|
|
goto out;
|
|
goto out;
|
|
|
|
+#endif
|
|
|
|
|
|
/* Do some additional sanity checking */
|
|
/* Do some additional sanity checking */
|
|
timekeeping_check_update(tk, offset);
|
|
timekeeping_check_update(tk, offset);
|
|
@@ -2105,6 +2116,15 @@ out:
|
|
clock_was_set_delayed();
|
|
clock_was_set_delayed();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * update_wall_time - Uses the current clocksource to increment the wall time
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+void update_wall_time(void)
|
|
|
|
+{
|
|
|
|
+ timekeeping_advance(TK_ADV_TICK);
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* getboottime64 - Return the real time of system boot.
|
|
* getboottime64 - Return the real time of system boot.
|
|
* @ts: pointer to the timespec64 to be set
|
|
* @ts: pointer to the timespec64 to be set
|
|
@@ -2327,6 +2347,10 @@ int do_adjtimex(struct timex *txc)
|
|
write_seqcount_end(&tk_core.seq);
|
|
write_seqcount_end(&tk_core.seq);
|
|
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
|
|
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
|
|
|
|
|
|
|
|
+ /* Update the multiplier immediately if frequency was set directly */
|
|
|
|
+ if (txc->modes & (ADJ_FREQUENCY | ADJ_TICK))
|
|
|
|
+ timekeeping_advance(TK_ADV_FREQ);
|
|
|
|
+
|
|
if (tai != orig_tai)
|
|
if (tai != orig_tai)
|
|
clock_was_set();
|
|
clock_was_set();
|
|
|
|
|