lkml.org 
[lkml]   [2016]   [Sep]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC v6 23/23] timekeeping: inform clockevents about freq adjustments
    Date
    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, if the CLOCK_EVT_FEAT_NO_ADJUST flag is not set,
    recalculates their ->mult_adjusted based on the monotonic clock's current
    frequency.

    Call clockevents_adjust_all_freqs() from timekeeping_freqadjust().

    Note that it might look like as if timekeeping_apply_adjustment() was the
    more natural candidate to trigger the clockevent devices' frequency updates
    from: it's the single place where the mono clock's ->mult is changed.
    However, timekeeping_apply_adjustment() is also invoked for the
    on-off-controlled adjustments made to the mono clock's ->mult from
    timekeeping_adjust(). These adjustments are very small in magnitude and,
    more importantly, exhibit some oscillatory behaviour once the NTP error
    becomes small. We don't want the clockevent devices' ->mult values to
    follow these oscillations because they're negligible and because the
    process of updating them would periodically destroy what
    clockevents_increase_min_delta() might have built up.

    Signed-off-by: Nicolai Stange <nicstange@gmail.com>
    ---
    kernel/time/clockevents.c | 33 +++++++++++++++++++++++++++++++++
    kernel/time/tick-internal.h | 5 +++++
    kernel/time/timekeeping.c | 2 ++
    3 files changed, 40 insertions(+)

    diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
    index b121932..e009add 100644
    --- a/kernel/time/clockevents.c
    +++ b/kernel/time/clockevents.c
    @@ -626,6 +626,39 @@ void __clockevents_adjust_freq(struct clock_event_device *dev)
    mult_cs_raw);
    }

    +void clockevents_adjust_all_freqs(u32 mult_cs_mono, u32 mult_cs_raw)
    +{
    + u32 last_mult_raw = 0, last_shift = 0, last_mult_adjusted = 0;
    + u32 mult_raw, shift;
    + 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) ||
    + (dev->features & CLOCK_EVT_FEAT_NO_ADJUST))
    + continue;
    +
    + /*
    + * The cached last_mult_adjusted is only valid if
    + * shift == last_shift. Otherwise, it could exceed
    + * what is allowed by ->max_delta_ns.
    + */
    + mult_raw = dev->mult;
    + shift = dev->shift;
    + if (mult_raw != last_mult_raw || shift != last_shift) {
    + last_mult_raw = mult_raw;
    + last_shift = shift;
    + 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..2d97c42 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);

    @@ -95,6 +96,10 @@ static inline void tick_set_periodic_handler(struct clock_event_device *dev, int
    #else /* !GENERIC_CLOCKEVENTS: */
    static inline void tick_suspend(void) { }
    static inline void tick_resume(void) { }
    +
    +static inline void clockevents_adjust_all_freqs(u32 mult_cs_mono,
    + u32 mult_cs_raw)
    +{}
    #endif /* !GENERIC_CLOCKEVENTS */

    /* Oneshot related functions */
    diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
    index 7ddca9e..f55926b 100644
    --- a/kernel/time/timekeeping.c
    +++ b/kernel/time/timekeeping.c
    @@ -1910,6 +1910,8 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,

    /* scale the corrections */
    timekeeping_apply_adjustment(tk, offset, negative, adj_scale);
    + clockevents_adjust_all_freqs(tk->tkr_mono.mult,
    + tk->tkr_mono.clock->mult);
    }

    /*
    --
    2.9.3
    \
     
     \ /
      Last update: 2016-09-17 09:59    [W:2.113 / U:0.088 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site