Upon adjustments of the monotonic clock's frequencies from the timekeeping core, the clockevents devices' ->mult_adjusted should be changed accordingly, too.
Introduce clockevents_adjust_all_freqs() which traverses all registered clockevent devices and recalculates their ->mult_adjusted based on the monotonic clock's current frequency. Call clockevents_adjust_all_freqs() from timekeeping_apply_adjustment(). Signed-off-by: Nicolai Stange <[email protected]> --- kernel/time/clockevents.c | 25 +++++++++++++++++++++++++ kernel/time/tick-internal.h | 1 + kernel/time/timekeeping.c | 3 +++ 3 files changed, 29 insertions(+) diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index ee7cd40..8f58565 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -561,6 +561,31 @@ void __clockevents_adjust_freq(struct clock_event_device *dev) dev->shift)); } +void clockevents_adjust_all_freqs(u32 mult_cs_mono, u32 mult_cs_raw) +{ + u32 last_mult_raw = 0, last_mult_adjusted = 0; + u32 mult_raw; + unsigned long flags; + struct clock_event_device *dev; + + raw_spin_lock_irqsave(&clockevents_lock, flags); + list_for_each_entry(dev, &clockevent_devices, list) { + if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT)) + continue; + + mult_raw = dev->mult; + if (mult_raw != last_mult_raw) { + last_mult_raw = mult_raw; + last_mult_adjusted = + __clockevents_calc_adjust_freq(mult_raw, + mult_cs_mono, + mult_cs_raw); + } + dev->mult_adjusted = last_mult_adjusted; + } + raw_spin_unlock_irqrestore(&clockevents_lock, flags); +} + int __clockevents_update_freq(struct clock_event_device *dev, u32 freq) { clockevents_config(dev, freq); diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index 0b29d23..9162671 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h @@ -56,6 +56,7 @@ extern int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, bool force); extern void clockevents_handle_noop(struct clock_event_device *dev); extern int __clockevents_update_freq(struct clock_event_device *dev, u32 freq); +extern void clockevents_adjust_all_freqs(u32 mult_cs_mono, u32 mult_cs_raw); extern void timekeeping_get_mono_mult(u32 *mult_cs_mono, u32 *mult_cs_raw); extern ssize_t sysfs_get_uname(const char *buf, char *dst, size_t cnt); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 6eac5b5..8d378b9 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1845,6 +1845,9 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk, tk->xtime_interval += interval; tk->tkr_mono.xtime_nsec -= offset; tk->ntp_error -= (interval - offset) << tk->ntp_error_shift; + + clockevents_adjust_all_freqs(tk->tkr_mono.mult, + tk->tkr_mono.clock->mult); } /* -- 2.9.2

