CINXE.COM
LKML: john stultz: [PATCH 2/11] Time: Reduced NTP Rework (part 2)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>LKML: john stultz: [PATCH 2/11] Time: Reduced NTP Rework (part 2)</title><link href="/css/message.css" rel="stylesheet" type="text/css" /><link href="/css/wrap.css" rel="alternate stylesheet" type="text/css" title="wrap" /><link href="/css/nowrap.css" rel="stylesheet" type="text/css" title="nowrap" /><link href="/favicon.ico" rel="shortcut icon" /><script src="/js/simple-calendar.js" type="text/javascript"></script><script src="/js/styleswitcher.js" type="text/javascript"></script><link rel="alternate" type="application/rss+xml" title="lkml.org : last 100 messages" href="/rss.php" /><link rel="alternate" type="application/rss+xml" title="lkml.org : last messages by john stultz" href="/groupie.php?aid=1263" /><!--Matomo--><script> var _paq = window._paq = window._paq || []; /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(["setDoNotTrack", true]); _paq.push(["disableCookies"]); _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { var u="//m.lkml.org/"; _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script><!--End Matomo Code--></head><body onload="es.jasper.simpleCalendar.init();" itemscope="itemscope" itemtype="http://schema.org/BlogPosting"><table border="0" cellpadding="0" cellspacing="0"><tr><td width="180" align="center"><a href="/"><img style="border:0;width:135px;height:32px" src="/images/toprowlk.gif" alt="lkml.org" /></a></td><td width="32">聽</td><td class="nb"><div><a class="nb" href="/lkml"> [lkml]</a> 聽 <a class="nb" href="/lkml/2005"> [2005]</a> 聽 <a class="nb" href="/lkml/2005/12"> [Dec]</a> 聽 <a class="nb" href="/lkml/2005/12/15"> [15]</a> 聽 <a class="nb" href="/lkml/last100"> [last100]</a> 聽 <a href="/rss.php"><img src="/images/rss-or.gif" border="0" alt="RSS Feed" /></a></div><div>Views: <a href="#" class="nowrap" onclick="setActiveStyleSheet('wrap');return false;">[wrap]</a><a href="#" class="wrap" onclick="setActiveStyleSheet('nowrap');return false;">[no wrap]</a> 聽 <a class="nb" href="/lkml/mheaders/2005/12/15/406" onclick="this.href='/lkml/headers'+'/2005/12/15/406';">[headers]</a>聽 <a href="/lkml/bounce/2005/12/15/406">[forward]</a>聽 </div></td><td width="32">聽</td></tr><tr><td valign="top"><div class="es-jasper-simpleCalendar" baseurl="/lkml/"></div><div class="threadlist">Messages in this thread</div><ul class="threadlist"><li class="root"><a href="/lkml/2005/12/15/405">First message in thread</a></li><li><a href="/lkml/2005/12/15/405">john stultz</a><ul><li><a href="/lkml/2005/12/15/404">john stultz</a></li><li class="origin"><a href="">john stultz</a></li><li><a href="/lkml/2005/12/15/407">john stultz</a><ul><li><a href="/lkml/2006/1/3/509">Andrew Morton</a><ul><li><a href="/lkml/2006/1/4/72">john stultz</a><ul><li><a href="/lkml/2006/1/4/76">Andrew Morton</a></li></ul></li></ul></li></ul></li><li><a href="/lkml/2005/12/15/408">john stultz</a></li><li><a href="/lkml/2005/12/15/409">john stultz</a></li><li><a href="/lkml/2005/12/15/410">john stultz</a></li><li><a href="/lkml/2005/12/15/411">john stultz</a></li><li><a href="/lkml/2005/12/15/412">john stultz</a></li><li><a href="/lkml/2005/12/15/413">john stultz</a></li><li><a href="/lkml/2005/12/15/414">john stultz</a></li><li><a href="/lkml/2005/12/15/415">john stultz</a></li></ul></li></ul><div class="threadlist">Patch in this message</div><ul class="threadlist"><li><a href="/lkml/diff/2005/12/15/406/1">Get diff 1</a></li></ul></td><td width="32" rowspan="2" class="c" valign="top"><img src="/images/icornerl.gif" width="32" height="32" alt="/" /></td><td class="c" rowspan="2" valign="top" style="padding-top: 1em"><table><tr><td><table><tr><td class="lp">Date</td><td class="rp" itemprop="datePublished">Thu, 15 Dec 2005 18:07:13 -0700</td></tr><tr><td class="lp">From</td><td class="rp" itemprop="author">john stultz <></td></tr><tr><td class="lp">Subject</td><td class="rp" itemprop="name">[PATCH 2/11] Time: Reduced NTP Rework (part 2)</td></tr></table></td><td></td></tr></table><pre itemprop="articleBody">Andrew, All,<br /> Here is the second of two patches which try to minimize my ntp <br />rework patches.<br /><br />This patch further changes the interrupt time NTP code, breaking out <br />the leapsecond processing and introduces an accessor to a shifted ppm <br />adjustment value. For correctness, I've also introduced a new lock, the <br />ntp_lock, which protects the NTP state machine when accessing it from <br />my timekeeping code (which does not use the xtime_lock).<br /><br />Again, this patch should not affect the existing behavior, but just <br />separate the logical functionality so it can be re-used by my timeofday <br />patches.<br /><br />Andrew, please consider for inclusion into your tree.<br /><br />thanks<br />-john<br /><br />Signed-off-by: John Stultz <johnstul@us.ibm.com><br /><br /> include/linux/timex.h | 23 +++++++<br /> kernel/time.c | 8 +-<br /> kernel/timer.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++--<br /> 3 files changed, 165 insertions(+), 10 deletions(-)<br /><br />linux-2.6.15-rc5_timeofday-ntp-part2_B14.patch<br />============================================<br />diff --git a/include/linux/timex.h b/include/linux/timex.h<br />index 04a4a8c..e35c683 100644<br />--- a/include/linux/timex.h<br />+++ b/include/linux/timex.h<br />@@ -260,6 +260,8 @@ extern long pps_calcnt; /* calibration <br /> extern long pps_errcnt; /* calibration errors */<br /> extern long pps_stbcnt; /* stability limit exceeded */<br /> <br />+extern seqlock_t ntp_lock;<br />+<br /> /**<br /> * ntp_clear - Clears the NTP state variables<br /> *<br />@@ -267,21 +269,40 @@ extern long pps_stbcnt; /* stability li<br /> */<br /> static inline void ntp_clear(void)<br /> {<br />+ unsigned long flags;<br />+<br />+ write_seqlock_irqsave(&ntp_lock, flags);<br /> time_adjust = 0; /* stop active adjtime() */<br /> time_status |= STA_UNSYNC;<br /> time_maxerror = NTP_PHASE_LIMIT;<br /> time_esterror = NTP_PHASE_LIMIT;<br />+ write_sequnlock_irqrestore(&ntp_lock, flags);<br /> }<br /> <br /> /**<br /> * ntp_synced - Returns 1 if the NTP status is not UNSYNC<br />- *<br /> */<br /> static inline int ntp_synced(void)<br /> {<br /> return !(time_status & STA_UNSYNC);<br /> }<br /> <br />+/**<br />+ * ntp_get_ppm_adjustment - Returns Shifted PPM adjustment<br />+ */<br />+extern long ntp_get_ppm_adjustment(void);<br />+<br />+/**<br />+ * ntp_advance - Advances the NTP state machine by interval_ns<br />+ */<br />+extern void ntp_advance(unsigned long interval_ns);<br />+<br />+/**<br />+ * ntp_leapsecond - NTP leapsecond processing code.<br />+ */<br />+extern int ntp_leapsecond(struct timespec now);<br />+<br />+<br /> /* Required to safely shift negative values */<br /> #define shift_right(x, s) ({ \<br /> __typeof__(x) __x = (x); \<br />diff --git a/kernel/time.c b/kernel/time.c<br />index cf5a458..6529064 100644<br />--- a/kernel/time.c<br />+++ b/kernel/time.c<br />@@ -258,6 +258,8 @@ int do_adjtimex(struct timex *txc)<br /> return -EINVAL;<br /> <br /> write_seqlock_irq(&xtime_lock);<br />+ write_seqlock(&ntp_lock);<br />+<br /> result = time_state; /* mostly `TIME_OK' */<br /> <br /> /* Save for later - semantics of adjtime is to return old value */<br />@@ -395,6 +397,7 @@ leave: if ((time_status & (STA_UNSYNC|ST<br /> txc->calcnt = pps_calcnt;<br /> txc->errcnt = pps_errcnt;<br /> txc->stbcnt = pps_stbcnt;<br />+ write_sequnlock(&ntp_lock);<br /> write_sequnlock_irq(&xtime_lock);<br /> do_gettimeofday(&txc->time);<br /> notify_arch_cmos_timer();<br />@@ -512,10 +515,7 @@ int do_settimeofday (struct timespec *tv<br /> set_normalized_timespec(&xtime, sec, nsec);<br /> set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);<br /> <br />- time_adjust = 0; /* stop active adjtime() */<br />- time_status |= STA_UNSYNC;<br />- time_maxerror = NTP_PHASE_LIMIT;<br />- time_esterror = NTP_PHASE_LIMIT;<br />+ ntp_clear();<br /> time_interpolator_reset();<br /> }<br /> write_sequnlock_irq(&xtime_lock);<br />diff --git a/kernel/timer.c b/kernel/timer.c<br />index 2a0a549..a543d54 100644<br />--- a/kernel/timer.c<br />+++ b/kernel/timer.c<br />@@ -582,7 +582,6 @@ long time_tolerance = MAXFREQ; /* frequ<br /> long time_precision = 1; /* clock precision (us) */<br /> long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */<br /> long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */<br />-static long time_phase; /* phase offset (scaled us) */<br /> long time_freq = (((NSEC_PER_SEC + HZ/2) % HZ - HZ/2) << SHIFT_USEC) / NSEC_PER_USEC;<br /> /* frequency offset (scaled ppm)*/<br /> static long time_adj; /* tick adjust (scaled 1 / HZ) */<br />@@ -591,8 +590,91 @@ long time_adjust;<br /> long time_next_adjust;<br /> long time_adjust_step; /* per tick time_adjust step */<br /> <br />+long total_sppm; /* shifted ppm sum of all adjustments */<br />+long offset_adj_ppm;<br />+long tick_adj_ppm;<br />+long singleshot_adj_ppm;<br />+<br />+#define MAX_SINGLESHOT_ADJ 500 /* (ppm) */<br />+#define SEC_PER_DAY 86400<br />+#define END_OF_DAY(x) ((x) + SEC_PER_DAY - ((x) % SEC_PER_DAY) - 1)<br />+<br />+/* NTP lock, protects NTP state machine */<br />+seqlock_t ntp_lock = SEQLOCK_UNLOCKED;<br />+<br />+/**<br />+ * ntp_leapsecond - NTP leapsecond processing code.<br />+ * now: the current time<br />+ *<br />+ * Returns the number of seconds (-1, 0, or 1) that<br />+ * should be added to the current time to properly<br />+ * adjust for leapseconds.<br />+ */<br />+int ntp_leapsecond(struct timespec now)<br />+{<br />+ /*<br />+ * Leap second processing. If in leap-insert state at<br />+ * the end of the day, the system clock is set back one<br />+ * second; if in leap-delete state, the system clock is<br />+ * set ahead one second.<br />+ */<br />+ static time_t leaptime = 0;<br />+<br />+ unsigned long flags;<br />+ int ret = 0;<br />+<br />+ write_seqlock_irqsave(&ntp_lock, flags);<br />+<br />+ switch (time_state) {<br />+<br />+ case TIME_OK:<br />+ if (time_status & STA_INS) {<br />+ time_state = TIME_INS;<br />+ leaptime = END_OF_DAY(now.tv_sec);<br />+ } else if (time_status & STA_DEL) {<br />+ time_state = TIME_DEL;<br />+ leaptime = END_OF_DAY(now.tv_sec);<br />+ }<br />+ break;<br />+<br />+ case TIME_INS:<br />+ /* Once we are at (or past) leaptime, insert the second */<br />+ if (now.tv_sec >= leaptime) {<br />+ time_state = TIME_OOP;<br />+ printk(KERN_NOTICE "Clock: inserting leap second 23:59:60 UTC\n");<br />+ ret = -1;<br />+ }<br />+ break;<br />+<br />+ case TIME_DEL:<br />+ /* Once we are at (or past) leaptime, delete the second */<br />+ if (now.tv_sec >= leaptime) {<br />+ time_state = TIME_WAIT;<br />+ printk(KERN_NOTICE "Clock: deleting leap second 23:59:59 UTC\n");<br />+ ret = 1;<br />+ }<br />+ break;<br />+<br />+ case TIME_OOP:<br />+ /* Wait for the end of the leap second */<br />+ if (now.tv_sec > (leaptime + 1))<br />+ time_state = TIME_WAIT;<br />+ time_state = TIME_WAIT;<br />+ break;<br />+<br />+ case TIME_WAIT:<br />+ if (!(time_status & (STA_INS | STA_DEL)))<br />+ time_state = TIME_OK;<br />+ break;<br />+ }<br />+<br />+ write_sequnlock_irqrestore(&ntp_lock, flags);<br />+<br />+ return ret;<br />+}<br />+<br /> /*<br />- * this routine handles the overflow of the microsecond field<br />+ * this routine handles the overflow of the nanosecond field<br /> *<br /> * The tricky bits of code to handle the accurate clock support<br /> * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.<br />@@ -663,6 +745,13 @@ static void second_overflow(void)<br /> time_state = TIME_OK;<br /> }<br /> <br />+ /* Bump the maxerror field */<br />+ time_maxerror += time_tolerance >> SHIFT_USEC;<br />+ if ( time_maxerror > NTP_PHASE_LIMIT ) {<br />+ time_maxerror = NTP_PHASE_LIMIT;<br />+ time_status |= STA_UNSYNC;<br />+ }<br />+<br /> /*<br /> * Compute the phase adjustment for the next second. In PLL mode, the<br /> * offset is reduced by a fixed factor times the time constant. In FLL<br />@@ -678,6 +767,13 @@ static void second_overflow(void)<br /> time_offset -= ltemp;<br /> time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);<br /> <br />+ offset_adj_ppm = shift_right(ltemp, SHIFT_UPDATE); /* ppm */<br />+<br />+ /* first calculate usec/user_tick offset: */<br />+ tick_adj_ppm = ((USEC_PER_SEC + USER_HZ/2)/USER_HZ) - tick_usec;<br />+ /* multiply by user_hz to get usec/sec => ppm: */<br />+ tick_adj_ppm *= USER_HZ;<br />+<br /> /*<br /> * Compute the frequency estimate and additional phase adjustment due<br /> * to frequency error for the next second. When the PPS signal is<br />@@ -718,15 +814,25 @@ static void second_overflow(void)<br /> }<br /> <br /> /**<br />+ * ntp_get_ppm_adjustment - return shifted PPM adjustment<br />+ */<br />+long ntp_get_ppm_adjustment(void)<br />+{<br />+ return total_sppm;<br />+}<br />+<br />+/**<br /> * ntp_advance - increments the NTP state machine<br /> * @interval_ns: interval, in nanoseconds<br />- *<br />- * Must be holding the xtime writelock when calling.<br /> */<br />-static void ntp_advance(unsigned long interval_ns)<br />+void ntp_advance(unsigned long interval_ns)<br /> {<br /> static unsigned long interval_sum;<br /> <br />+ unsigned long flags;<br />+<br />+ write_seqlock_irqsave(&ntp_lock, flags);<br />+<br /> /* increment the interval sum: */<br /> interval_sum += interval_ns;<br /> <br />@@ -753,6 +859,8 @@ static void ntp_advance(unsigned long in<br /> }<br /> interval_ns -= tick_nsec;<br /> }<br />+ /* usec/tick => ppm: */<br />+ singleshot_adj_ppm = time_adjust_step*(1000000/HZ);<br /> <br /> /* Changes by adjtime() do not take effect till next tick. */<br /> if (time_next_adjust != 0) {<br />@@ -764,6 +872,14 @@ static void ntp_advance(unsigned long in<br /> interval_sum -= NSEC_PER_SEC;<br /> second_overflow();<br /> }<br />+<br />+ /* calculate the total continuous ppm adjustment: */<br />+ total_sppm = time_freq; /* already shifted by SHIFT_USEC */<br />+ total_sppm += offset_adj_ppm << SHIFT_USEC;<br />+ total_sppm += tick_adj_ppm << SHIFT_USEC;<br />+ total_sppm += singleshot_adj_ppm << SHIFT_USEC;<br />+<br />+ write_sequnlock_irqrestore(&ntp_lock, flags);<br /> }<br /> <br /> /**<br />@@ -773,6 +889,8 @@ static void ntp_advance(unsigned long in<br /> */<br /> static inline long phase_advance(void)<br /> {<br />+ static long time_phase; /* phase offset (scaled us) */<br />+<br /> long delta = 0;<br /> <br /> time_phase += time_adj;<br />@@ -791,12 +909,28 @@ static inline long phase_advance(void)<br /> */<br /> static inline void xtime_advance(long delta_nsec)<br /> {<br />+ int leapsecond;<br />+<br /> xtime.tv_nsec += delta_nsec;<br /> if (likely(xtime.tv_nsec < NSEC_PER_SEC))<br /> return;<br /> <br /> xtime.tv_nsec -= NSEC_PER_SEC;<br /> xtime.tv_sec++;<br />+<br />+ /* process leapsecond: */<br />+ leapsecond = ntp_leapsecond(xtime);<br />+ if (likely(!leapsecond))<br />+ return;<br />+<br />+ xtime.tv_sec += leapsecond;<br />+ wall_to_monotonic.tv_sec -= leapsecond;<br />+ /*<br />+ * Use of time interpolator for a gradual<br />+ * change of time:<br />+ */<br />+ time_interpolator_update(leapsecond*NSEC_PER_SEC);<br />+ clock_was_set();<br /> }<br /> <br /> /*<br />-<br />To unsubscribe from this list: send the line "unsubscribe linux-kernel" in<br />the body of a message to majordomo@vger.kernel.org<br />More majordomo info at <a href="http://vger.kernel.org/majordomo-info.html">http://vger.kernel.org/majordomo-info.html</a><br />Please read the FAQ at <a href="http://www.tux.org/lkml/">http://www.tux.org/lkml/</a><br /></pre></td><td width="32" rowspan="2" class="c" valign="top"><img src="/images/icornerr.gif" width="32" height="32" alt="\" /></td></tr><tr><td align="right" valign="bottom"> 聽 </td></tr><tr><td align="right" valign="bottom">聽</td><td class="c" valign="bottom" style="padding-bottom: 0px"><img src="/images/bcornerl.gif" width="32" height="32" alt="\" /></td><td class="c">聽</td><td class="c" valign="bottom" style="padding-bottom: 0px"><img src="/images/bcornerr.gif" width="32" height="32" alt="/" /></td></tr><tr><td align="right" valign="top" colspan="2"> 聽 </td><td class="lm">Last update: 2005-12-16 02:12 聽聽 [from the cache]<br />漏2003-2020 <a href="http://blog.jasper.es/"><span itemprop="editor">Jasper Spaans</span></a>|hosted at <a href="https://www.digitalocean.com/?refcode=9a8e99d24cf9">Digital Ocean</a> and my Meterkast|<a href="http://blog.jasper.es/categories.html#lkml-ref">Read the blog</a></td><td>聽</td></tr></table><script language="javascript" src="/js/styleswitcher.js" type="text/javascript"></script></body></html>