: Differences between tags 'r2_4_29' and 'PPS_2_1_5'
: Using module 'Kernel' in CVS repository '/root/LinuxCVS'
: This patch was created automatically at Mon Jan 24 21:13:40 CET 2005
: ($Id: make-CVS-diff,v 2.3 2002/08/19 21:24:36 windl Exp $)
Index: linux/CREDITS
diff -u linux/CREDITS:1.1.1.19 linux/CREDITS:1.1.1.19.2.1
--- linux/CREDITS:1.1.1.19	Sat Jan 22 22:01:56 2005
+++ linux/CREDITS	Mon Jan 24 21:02:57 2005
@@ -3311,7 +3311,10 @@
 N: Ulrich Windl
 E: Ulrich.Windl@rz.uni-regensburg.de
 P: 1024/E843660D CF D7 43 A1 5A 49 14 25  7C 04 A0 6E 4C 3A AC 6D
-D: Supports NTP on Linux.  Added PPS code.  Fixed bugs in adjtimex().
+D: Supports NTP on Linux.  Implemented PPS API (RFC 2783).
+D: Extended and updated kernel time routines to match the demands of NTP.
+D: Added support for nanosecond time resolution (time "mega patch").
+D: Several fixes for adjtimex().  Added /proc/sys/kernel/time directory.
 S: Alte Regensburger Str. 11a
 S: 93149 Nittenau
 S: Germany
Index: linux/Makefile
diff -u linux/Makefile:1.1.1.19 linux/Makefile:1.1.1.19.2.1
--- linux/Makefile:1.1.1.19	Sat Jan 22 22:01:56 2005
+++ linux/Makefile	Mon Jan 24 21:02:57 2005
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 29
-EXTRAVERSION =
+EXTRAVERSION = -NANO
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
Index: linux/Documentation/Configure.help
diff -u linux/Documentation/Configure.help:1.1.1.19 linux/Documentation/Configure.help:1.1.1.19.2.1
--- linux/Documentation/Configure.help:1.1.1.19	Sat Jan 22 22:03:21 2005
+++ linux/Documentation/Configure.help	Mon Jan 24 21:03:09 2005
@@ -4859,6 +4859,28 @@
 
   If unsure, say N.
 
+NTP kernel support
+CONFIG_NTP
+  Say N here if you are sure you do not use the NTP kernel code and you
+  want to minimize the kernel size or system overhead.  Otherwise say Y.
+
+NTP PPS support
+CONFIG_NTP_PPS
+  Saying Y enables extra code that can calibrate your system clock relative
+  to some external precision pulse-per-second (PPS).  This simply provides
+  an additional kernel routine that still needs to be used by some driver
+  (e.g. the serial driver can take time stamps for pulses on carrier detect).
+  Normally you would say N here.
+
+NTP PPS support on serial port
+CONFIG_NTP_PPS_SERIAL
+  Saying Y here will provide the PPS API (RFC 2783) for the serial driver.
+  The PPS API enables application programs to capture precision time stamps,
+  optionally calibrating the software clock.  This feature is optional, and
+  it keeps the port available for normal operation.  Usually you don't need
+  this.  See http://www.ntp.org/ntpfaq/NTP-s-config.htm#S-CONFIG-ADV-PPS for
+  details.
+
 VGA text console
 CONFIG_VGA_CONSOLE
   Saying Y here will allow you to use Linux in text mode through a
Index: linux/Documentation/ioctl-number.txt
diff -u linux/Documentation/ioctl-number.txt:1.1.1.7 linux/Documentation/ioctl-number.txt:1.1.1.7.2.1
--- linux/Documentation/ioctl-number.txt:1.1.1.7	Sat Jan 22 21:54:13 2005
+++ linux/Documentation/ioctl-number.txt	Mon Jan 24 21:03:12 2005
@@ -72,7 +72,7 @@
 		linux/blkpg.h
 0x20	all	drivers/cdrom/cm206.h
 0x22	all	scsi/sg.h
-'1'	00-1F	<linux/timepps.h>	PPS kit from Ulrich Windl
+'1'	00-1F	linux/timepps.h		PPSkit (PPS API) from Ulrich Windl
 					<ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
 '6'	00-10	<asm-i386/processor.h>	Intel IA32 microcode update driver
 					<mailto:tigran@veritas.com>
Index: linux/Documentation/kernel-time.txt
diff -u /dev/null linux/Documentation/kernel-time.txt:1.2.8.1
--- /dev/null	Mon Jan 24 21:14:03 2005
+++ linux/Documentation/kernel-time.txt	Mon Jan 24 21:03:12 2005
@@ -0,0 +1,359 @@
+Kernel Time Overview
+====================
+
+This document gives a short overview about the code that handles time
+in the Linux kernel in order to make it understandable what all the
+NTP stuff is about. The description concentrates on the user's view of
+kernel time.
+
+1. Hardware
+===========
+
+The kernel uses the timer (programmable periodic interrupt at rate
+``HZ'') to increment the kernel clock. The kernel clock consists of
+two counters.  The first one (``tv_sec'') counts the seconds since
+1970-01-01, while the second one (``tv_nsec'') manages the fraction of
+the current second in nanoseconds.  During boot the first value is
+derived from the time found in the CMOS clock (also known as ``real
+time clock'') which only has a resolution of one second.
+
+During each interrupt a specific amount (the "time_tick",
+1000000000/HZ) of nanoseconds is added to the fractional second.  If
+a second overflow occurs, it is handled accordingly.  Normally the new
+kernel time is not written back to the CMOS clock, but it can be done.
+
+If an application program asks for the current time, it is possible to
+get an estimate of the elapsed time since the last timer interrupt, by
+extrapolating the time.  This is what  ``do_nanotime()'' is for.
+
+On the Intel 386 architecture the registers in the timer chip can be
+read to get a resolution of less than a microsecond.
+
+On a Pentium the CPU's cycle counter can be used to estimate the time
+since the last timer interrupt by scaling the cycles elapsed during
+two successive timer interrupts. The resolution for fast CPUs is
+significantly higher than for the timer's counter register (close to
+or even below one microsecond).  Furthermore it can be read much
+faster than the hardware registers of the timer chip.  Unfortunately
+modern motherboards may vary the CPU frequency to avoid overheating
+the processor or to save power (APM features).
+
+Other architectures have similar fast timing facilities, more or less
+reliable.
+
+These are the components that determine the "resolution" of the kernel
+clock.  Also the "stability" (reliability or predictability) and
+precision (the error accumulated during reading the time) is
+determined by the hardware.
+
+2. Software
+===========
+
+While the hardware is responsible for the resolution and precision of
+the clock, the software is responsible for calibrating the clock and
+programming the hardware. Linux uses an extended algorithm to manage
+system time.  That algorithm is basically the NTP kernel clock model
+described in RFC 1589, RFC 1305 and related papers.  The current
+implementation is referred to as ``nanokernel'', because it keeps time
+in nanoseconds.
+
+As most clocks are not very precise or stable, it is necessary to
+correct the kernel clock from time to time. Traditionally it is
+possible to overwrite the current kernel counters to make the time
+"step" (stime, settimeofday, clock_settime). Also it's possible to
+initiate a more gradual change in time by specifying the amount of
+time that is to be changed. This is called "slewing" the clock
+(adjtime).
+
+When slewing the clock, the value of "time_tick" is modified by a
+small amount, called "tickadj" (50000/HZ, µs per interrupt). That
+way the clock seems to be running faster or slower for some time
+(until the desired correction has been applied), and then continues to
+run at nominal speed. Obviously "tickadj" does not only affect the
+speed in which an adjustment is made, but also the resolution of the
+adjustment.  Usually there is no adjustment below "tickadj". One
+reason against using the smallest possible value for tickadj is that
+the correction must be more than the clock's intrinsic error (Besides
+that fact that a correction can take very long). Otherwise you'll
+never be able to keep up with the error.
+
+2.1 NTP extensions
+==================
+
+Independent on which of the above two methods is used, the process has
+to be repeated again and again to keep the deviation of the software
+clock within a small interval. When you know the percentage of your
+clock error (e.g. 15 seconds to fast within 24 hours), you can also
+pass a correction value to the kernel, asking for automatic
+correction of the frequency error.
+
+Such a correction value can be expressed in PPM (parts per million,
+0.0001%) of the clock's "frequency". Additionally the enhanced clock
+model can be told to learn from periodic adjustments to the time
+offset, such that the virtual frequency of the kernel clock is
+modified (you can't tune the hardware).  Alternatively the frequency
+can be set directly. As these corrections are limited by ``tickadj''
+(max <= HZ*tickadj), it's sometimes necessary to change the value of
+``time_tick'' (if you want to keep tickadj small).
+
+Unfortunately specifying the frequency alone is not sufficient to make
+a stable clock, because the frequency varies over time. These
+variations in frequency are usually influenced by the environmental
+temperature and are commonly named "drift". When the clock algorithm
+learns from periodic adjustments, it also gets an estimate for the
+drift. Thus at each timer interrupt a small "tolerance" (uncertainty)
+is added to the clock's error. If the initial error is set when
+synchronizing, the kernel maintains an estimate of the current maximum
+error.
+
+The idea is to "synchronize" the kernel clock to a reference clock and
+let it run free for a while, until the estimated error is too big to
+be tolerated (Here a few milliseconds is considered "big" already, and
+typical update intervals are between one minute and one hour).
+
+To make the automatic correction work, the basic algorithm is modified
+in a way that can deal with fractions of nanoseconds, and time_tick is
+temporarily modified to yield a value that results in an error of less
+than one nanosecond per timer interrupt.
+
+Besides that regulation and error propagating machinery, the kernel
+clock also handles insertion and deletion of leap seconds (if it is
+told to do so).
+
+Managing a precise and stable kernel time requires periodic updates to
+the clock offset and estimated error (tolerance) of the kernel clock.
+Depending on the clock's stability there is an optimal update
+frequency, derived from the so-called Allan variance.  The xntpd
+daemon is a program to do that (see http://www.eecis.udel.edu/~ntp),
+but there's also a way to calibrate the kernel clock by external
+hardware.  One of these methods is called the PPS (Pulse Per Second)
+code.
+
+2.1.1 PPS calibration
+=====================
+
+PPS calibration works very similar to time calibration, but only on a
+smaller scale.  The code assumes the clock initially is closer than
+0.5 seconds to some reference time.  As the PPS can only calibrate the
+frequency and the offset relative to the second, the absolute time
+(epoch) must be set by other means.
+
+Basically the code automatically compares the current clock offset for
+each second with a high precision external pulse (e.g. derived from a
+GPS receiver, allowing a maximum relative error of 500PPM) and learns
+whether the clock frequency is too slow or fast. The code can be told
+to adjust only the time offset, or to adjust the frequency of the
+kernel.  The precision achievable with PPS synchronization is
+significantly higher than with usual adjustments.  With a Celeron-500
+system with little load it is possible to get the clock as close as a
+few hundred nanoseconds relative to the PPS on average.
+
+PPS API
+-------
+
+There's a new RFC (2783) on how to implement a common programming
+interface for the PPS stuff.  Linux includes an example implementation
+for the serial port.  You can capture changes of the carrier detect
+status line.  These events can be used to calibrate the system clock
+if the pulses are stable enough.  See <linux/timepps.h>.
+
+2.2 The new Linux implementation
+================================
+
+In the Linux implementation the CMOS clock is updated periodically
+(every 11 minutes) from the kernel time when the clock is synchronized
+(flag STA_UNSYNC is cleared). The flag STA_UNSYNC will automatically
+be set, once the maximum error is above a fixed limit
+(NTP_PHASE_LIMIT, currently about 2s).  Unfortunately the maximum
+error increases with a worst-case estimate (in reality the increase of
+the error depends mostly on the frequency change of the system
+clock(s).  A busy system board gets warmer, and the frequency of the
+clock decreases).
+
+Linux uses one function, adjtimex, to implement the functions for
+classical adjtime() and the new ntp_gettime() and ntp_adjtime()
+functions.  In order to achieve that, the function uses one rather big
+"struct kernel_timex" (Currently just named ``timex'' to confuse
+people) that contains a "modes" field and several state variables.  By
+setting individual bits in the "modes" field the specific function of
+the adjtimex system call is selected while the remaining fields of the
+structure are written or read as needed.
+
+struct kernel_timex {
+	unsigned int modes;	/* clock mode bits (wo) */
+	long	offset;		/* time offset (ns/us) (rw) */
+	long	freq;		/* frequency offset (scaled PPM) (rw) */
+	long	maxerror;	/* maximum error (us) (rw) */
+	long	esterror;	/* estimated error (us) (rw) */
+	int	status;		/* clock status bits (rw) */
+	long	constant;	/* poll interval (log2 s) (rw) */
+	long	precision;	/* clock precision (ns/us) (ro) */
+	long	tolerance;	/* clock frequency tolerance (scaled
+				 * PPM) (ro) */
+	/*----BEGIN Linux extensions (part 1) */
+	/* Depending on whether ``NANO'' is defined when including
+	 * this file, the same memory location can be accessed under
+	 * two different names.  ``STA_NANO'' at runtime should
+	 * correspond with ``NANO'' at compilation time.
+	 */
+#ifdef NANO
+	struct timespec time;	/* current time (ns) (ro) */
+#else
+	struct timeval time;	/* current time (us) (ro) */
+#endif /* NANO */
+	long	time_tick;	/* time increment per tick (?) (rw) */
+	/*----END Linux extensions (part 1) */
+	/*
+	 * The following read-only structure members are implemented
+	 * only if the PPS signal discipline is configured in the
+	 * kernel. They are included in all configurations to insure
+	 * portability.
+	 */
+	long	ppsfreq;	/* PPS frequency (scaled PPM) (ro) */
+	long	jitter;		/* PPS jitter (ns/us) (ro) */
+	int	shift;		/* interval duration (s) (shift) (ro) */
+	long	stabil;		/* PPS stability (scaled PPM) (ro) */
+	long	jitcnt;		/* jitter limit exceeded (ro) */
+	long	calcnt;		/* calibration intervals (ro) */
+	long	errcnt;		/* calibration errors (ro) */
+	long	stbcnt;		/* stability limit exceeded (ro) */
+	/*----BEGIN Linux extensions (part 2) */
+	/* first we reserve some space, then we add our new stuff */
+	/* Yes, it's ugly, but it's binary compatible */
+	int  :32; int  :32; int  :32; int  :32;
+	int tickadj;		/* tickadj (us) (rw) -- extension by UW */
+	int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+	/*----END Linux extensions (part 2) */
+};
+
+The official ntp_gettime() function only returns these data:
+
+struct ntptimeval {
+	struct timeval	time;	/* current time (ro) */
+	long maxerror;		/* maximum error (us) (ro) */
+	long esterror;		/* estimated error (us) (ro) */
+};
+
+The official ntp_adjtime() function contains these data (note the lack
+of `time'!):
+
+struct timex {
+	unsigned int modes;	/* mode selector */
+	long offset;		/* time offset (usec) */
+	long freq;		/* frequency offset (scaled ppm) */
+	long maxerror;		/* maximum error (usec) */
+	long esterror;		/* estimated error (usec) */
+	int status;		/* clock command/status */
+	long constant;		/* pll time constant */
+	long precision;		/* clock precision (usec) (read only) */
+	long tolerance;		/* clock frequency tolerance (ppm)
+				 * (read only)
+				 */
+
+	long ppsfreq;           /* pps frequency (scaled ppm) (ro) */
+	long jitter;            /* pps jitter (us) (ro) */
+	int shift;              /* interval duration (s) (shift) (ro) */
+	long stabil;            /* pps stability (scaled ppm) (ro) */
+	long jitcnt;            /* jitter limit exceeded (ro) */
+	long calcnt;            /* calibration intervals (ro) */
+	long errcnt;            /* calibration errors (ro) */
+	long stbcnt;            /* stability limit exceeded (ro) */
+};
+
+The symbolic names of the bits used to select the NTP compatible
+operating modes all start with "MOD_"; extensions start with "ADJ_".
+The specific status of the kernel clock (`status') is also expressed
+by a set of bits, all starting with "STA_".
+
+Thus the classical function "adjtime" can be implemented as follows
+(please note that "struct timeval" is reduced to a single "long",
+causing severe restrictions):
+
+/* This is a simple-minded implementation! */
+inline	int adjtime (const struct timeval *delta, struct timeval *olddelta)
+{
+	struct timex	tntx;
+	int		result;
+	if (delta) {
+		struct timeval tmp;
+
+		/* We enforce some arbitrary (2000s) limit here. */
+		tmp.tv_sec = delta->tv_sec + delta->tv_usec / 1000000L;
+		tmp.tv_usec = delta->tv_usec % 1000000L;
+		if (tmp.tv_sec > 2000 || tmp.tv_sec < -2000) {
+			return -1;
+		}
+		tntx.offset = tmp.tv_usec + tmp.tv_sec * 1000000L;
+		tntx.modes = ADJ_ADJTIME;
+	}
+	else
+		tntx.modes = 0;
+	result = __adjtimex (&tntx);
+	if (result >= 0 && olddelta) {
+		if (tntx.offset < 0) {
+			olddelta->tv_usec = -(-tntx.offset % 1000000);
+			olddelta->tv_sec  = -(-tntx.offset / 1000000);
+		} else {
+			olddelta->tv_usec = tntx.offset % 1000000;
+			olddelta->tv_sec  = tntx.offset / 1000000;
+		}
+	}
+	return result;
+}
+
+The "ntp_gettime" and "ntp_adjtime" functions can be implemented as
+follows:
+
+int ntp_gettime(struct ntptimeval *tptr)
+{
+	struct kernel_timex tx;
+	int result;
+
+	tx.modes = 0;
+	result = adjtimex(&tx);
+	tptr->time = tx.time;
+	tptr->maxerror = tx.maxerror;
+	tptr->esterror = tx.esterror;
+	return(result);
+}
+
+inline	int adjtime (const struct timeval *delta, struct timeval *olddelta)
+{
+	struct timex	tntx;
+	int		result;
+	if (delta) {
+		struct timeval tmp;
+
+		/* We enforce some arbitrary (2000s) limit here. */
+		tmp.tv_sec = delta->tv_sec + delta->tv_usec / 1000000L;
+		tmp.tv_usec = delta->tv_usec % 1000000L;
+		if (tmp.tv_sec > 2000 || tmp.tv_sec < -2000) {
+			return -1;
+		}
+		tntx.offset = tmp.tv_usec + tmp.tv_sec * 1000000L;
+		tntx.modes = ADJ_ADJTIME;
+	}
+	else
+		tntx.modes = 0;
+	result = __adjtimex (&tntx);
+	if (result >= 0 && olddelta) {
+		if (tntx.offset < 0) {
+			olddelta->tv_usec = -(-tntx.offset % 1000000);
+			olddelta->tv_sec  = -(-tntx.offset / 1000000);
+		} else {
+			olddelta->tv_usec = tntx.offset % 1000000;
+			olddelta->tv_sec  = tntx.offset / 1000000;
+		}
+	}
+	return result;
+}
+
+2.3 Problems
+============
+
+The kernel's ``struct timex'' is an equivalent superset of NTP's timex
+structure.
+
+Ulrich Windl
+2003-03-21
Index: linux/Documentation/magic-number.txt
diff -u linux/Documentation/magic-number.txt:1.1.1.2 linux/Documentation/magic-number.txt:1.1.1.2.18.1
--- linux/Documentation/magic-number.txt:1.1.1.2	Sun Mar 11 14:52:29 2001
+++ linux/Documentation/magic-number.txt	Mon Jan 24 21:03:12 2005
@@ -54,6 +54,7 @@
 PTY_MAGIC	      0x5001	  (none at the moment)
 					            drivers/char/pty.c
 PPP_MAGIC             0x5002      ppp               include/linux/if_ppp.h
+PPSCLOCK_MAGIC	      0x5003	  pps		    include/linux/timepps.h
 SERIAL_MAGIC          0x5301      async_struct      include/linux/serial.h
 SSTATE_MAGIC          0x5302      serial_state      include/linux/serial.h
 SLIP_MAGIC            0x5302      slip              drivers/net/slip.h
Index: linux/Documentation/sysctl/kernel.txt
diff -u linux/Documentation/sysctl/kernel.txt:1.1.1.2 linux/Documentation/sysctl/kernel.txt:1.1.1.2.12.1
--- linux/Documentation/sysctl/kernel.txt:1.1.1.2	Thu Dec 13 19:48:49 2001
+++ linux/Documentation/sysctl/kernel.txt	Mon Jan 24 21:03:17 2005
@@ -40,6 +40,7 @@
 - sg-big-buff                 [ generic SCSI device (sg) ]
 - shmmax                      [ sysv ipc ]
 - tainted
+- time			      [ directory ]
 - version
 - zero-paged                  [ PPC only ]
 
@@ -221,6 +222,37 @@
 
 ==============================================================
 
+time:
+
+time/Hz (r/o):
+	Intended to reveal the value of HZ to user programs.
+
+time/pps (r/o):
+	(experimental) Used to reveal the internals of ``struct pps''
+
+time/rtc_runs_localtime (r/w):
+	Set to ``1'' if RTC is set to local time
+
+time/rtc_update (r/w):
+	Amount of seconds after which the RTC is updated from system time
+	if ``STA_UNSYNC'' in ``time_status'' is cleared.  When setting the
+	system time directly, it will be updated the next second.
+	Setting ``rtc_update'' to a value <= 0, the RTC is not updated.
+
+time/tickadj (r/w):
+	Amount of nanoseconds that will be used to adjust a wrong clock
+	gradually (using ``adjtime()'').
+
+time/time_tick (r/w):
+	Amount of nanoseconds to add every timer interrupt.
+
+time/timezone (r/w):
+	Two values describing the time zone offset west of GMT in minutes,
+	and whether daylight saving time is active (required to convert
+	kernel time to local time).
+
+==============================================================
+
 tainted: 
 
 Non-zero if the kernel has been tainted.  Numeric values, which
Index: linux/arch/alpha/config.in
diff -u linux/arch/alpha/config.in:1.1.1.12 linux/arch/alpha/config.in:1.1.1.12.2.1
--- linux/arch/alpha/config.in:1.1.1.12	Sat Jan 22 21:52:43 2005
+++ linux/arch/alpha/config.in	Mon Jan 24 21:03:21 2005
@@ -221,6 +221,13 @@
 	define_bool CONFIG_ALPHA_EV6 y
 	define_bool CONFIG_ALPHA_EV67 y
 fi
+bool 'NTP kernel support' CONFIG_NTP
+if [ "$CONFIG_NTP" != "n" ]; then
+  bool '   NTP PPS support' CONFIG_NTP_PPS
+  if [ "$CONFIG_NTP_PPS" != "n" ]; then
+    bool '   Debug NTP PPS support' CONFIG_NTP_PPS_DEBUG
+  fi
+fi
 
 if [ "$CONFIG_ALPHA_JENSEN" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
 	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
Index: linux/arch/alpha/defconfig
diff -u linux/arch/alpha/defconfig:1.1.1.7 linux/arch/alpha/defconfig:1.1.1.7.2.1
--- linux/arch/alpha/defconfig:1.1.1.7	Sat Jan 22 21:52:43 2005
+++ linux/arch/alpha/defconfig	Mon Jan 24 21:03:21 2005
@@ -74,6 +74,10 @@
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_BINFMT_EM86 is not set
+CONFIG_NTP=y
+# CONFIG_NTP_PPS is not set
+# CONFIG_NTP_PPS_DEBUG is not set
+# CONFIG_NTP_PPS_SERIAL is not set
 
 #
 # Parallel port support
Index: linux/arch/alpha/kernel/osf_sys.c
diff -u linux/arch/alpha/kernel/osf_sys.c:1.1.1.9 linux/arch/alpha/kernel/osf_sys.c:1.1.1.9.4.1
--- linux/arch/alpha/kernel/osf_sys.c:1.1.1.9	Fri Aug 15 22:25:15 2003
+++ linux/arch/alpha/kernel/osf_sys.c	Mon Jan 24 21:03:26 2005
@@ -1293,17 +1293,20 @@
 
 	/* copy relevant bits of struct timex. */
 	if (copy_from_user(&txc, txc_p, offsetof(struct timex32, time)) ||
-	    copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) - 
+	    copy_from_user(&txc.time_tick, &txc_p->tick, sizeof(struct timex32) - 
 			   offsetof(struct timex32, time)))
 	  return -EFAULT;
 
+	txc.time_tick *= 1000;
+	/* NOTE[UW]: time_tick is nanoseconds */
 	ret = do_adjtimex(&txc);	
 	if (ret < 0)
 	  return ret;
+	txc.time_tick /= 1000;
 	
 	/* copy back to timex32 */
 	if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) ||
-	    (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) - 
+	    (copy_to_user(&txc_p->tick, &txc.time_tick, sizeof(struct timex32) - 
 			  offsetof(struct timex32, tick))) ||
 	    (put_tv32(&txc_p->time, &txc.time)))
 	  return -EFAULT;
Index: linux/arch/alpha/kernel/time.c
diff -u linux/arch/alpha/kernel/time.c:1.1.1.7 linux/arch/alpha/kernel/time.c:1.1.1.7.4.1
--- linux/arch/alpha/kernel/time.c:1.1.1.7	Fri Aug 15 22:25:16 2003
+++ linux/arch/alpha/kernel/time.c	Mon Jan 24 21:03:26 2005
@@ -18,16 +18,35 @@
  *      fixed tick loss calculation in timer_interrupt
  *      (round system clock to nearest tick instead of truncating)
  *      fixed algorithm in time_init for getting time from CMOS clock
+ * 1999-03-10	Ulrich Windl
+ *	Updated for nanosecond resolution and general cleanup
  * 1999-04-16	Thorsten Kranzkowski (dl8bcu@gmx.net)
  *	fixed algorithm in do_gettimeofday() for calculating the precise time
  *	from processor cycle counter (now taking lost_ticks into account)
+ * 1999-04-29	Ulrich Windl
+ *	Merged recent changes.
+ * 1999-12-10	Ulrich Windl
+ *	Implement new logic with ``rtc_update_slave''.
+ *	Use new ``update_rtc()'' (untested).
+ * 2000-03-16	Ulrich Windl, John Sager
+ *	Fixed compilation.
+ * 2000-04-16	Ulrich Windl
+ *	Don't take ``lost_ticks'' into account here. It's done in
+ *	``kernel/time.c'' now..
  * 2000-08-13	Jan-Benedict Glaw <jbglaw@lug-owl.de>
  * 	Fixed time_init to be aware of epoches != 1900. This prevents
  * 	booting up in 2048 for me;) Code is stolen from rtc.c.
+ * 2000-12-03	Ulrich Windl
+ *	Re-merged code from 2.2.17.
+ * 2000-12-09	Ulrich Windl
+ *	Remove traditional code for microseconds as the nanoseconds seem
+ *	stable.
+ * 2001-03-28	Ulrich Windl
+ *	Another cross-merge to fix compilation problems.
  */
 #include <linux/config.h>
 #include <linux/errno.h>
-#include <linux/sched.h>
+#include <linux/time.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
@@ -49,12 +68,11 @@
 #include "irq_impl.h"
 
 extern rwlock_t xtime_lock;
-extern unsigned long wall_jiffies;	/* kernel/timer.c */
-
-static int set_rtc_mmss(unsigned long);
 
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 
+static void update_rtc(void);
+
 /*
  * Shift amount by which scaled_ticks_per_cycle is scaled.  Shifting
  * by 48 gives us 16 bits for HZ while keeping the accuracy good even
@@ -86,6 +104,30 @@
 
 
 /*
+ * Use the cycle counter to estimate an displacement from the last time
+ * tick.  Unfortunately the Alpha designers made only the low 32-bits of
+ * the cycle counter active, so we overflow on 8.2 seconds on a 500MHz
+ * part.  So we can't do the "find absolute time in terms of cycles" thing
+ * that the other ports do.
+ */
+/* nanoseconds since last timer interrupt */
+static inline unsigned long do_exact_nanotime(void)
+{
+	unsigned long delta_usec;
+
+#ifdef CONFIG_SMP
+	delta_usec = (jiffies - wall_jiffies) * (1000000 / HZ);
+#else
+	delta_usec = rpcc() - state.last_time;
+	delta_usec = (delta_usec * state.scaled_ticks_per_cycle 
+		      + state.partial_tick
+		      + ((jiffies - wall_jiffies) << FIX_SHIFT)) * 15625;
+	delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
+#endif
+	return delta_usec * 1000;
+}
+
+/*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
@@ -121,18 +163,18 @@
 	}
 
 	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
+	 * If we have a change of the software clock to be committed to the
+	 * CMOS clock, then do it. Update_rtc() has to be called as close as
+	 * possible to 500 ms before the new second starts.
 	 */
-	if ((time_status & STA_UNSYNC) == 0
-	    && xtime.tv_sec > state.last_rtc_update + 660
-	    && xtime.tv_usec >= 500000 - ((unsigned) tick) / 2
-	    && xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
-		int tmp = set_rtc_mmss(xtime.tv_sec);
-		state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0);
+	if (rtc_update_slave &&
+	    xtime.tv_sec >= state.last_rtc_update + rtc_update_slave &&
+	    xtime.tv_nsec >= 500000000 - ((unsigned long) time_tick) / 2 &&
+	    xtime.tv_nsec <= 500000000 + ((unsigned long) time_tick) / 2) {
+		update_rtc();
+		state.last_rtc_update = xtime.tv_sec;
+		rtc_update_slave = 0;
 	}
-
 	write_unlock(&xtime_lock);
 }
 
@@ -141,6 +183,8 @@
 {
 	unsigned char x;
 
+	do_nanotime = do_exact_nanotime;
+
 	/* Reset periodic interrupt frequency.  */
 	x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f;
 	/* Test includes known working values on various platforms
@@ -365,7 +409,7 @@
 		year += 100;
 
 	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_usec = 0;
+	xtime.tv_nsec = 0;
 
 	if (HZ > (1<<16)) {
 		extern void __you_loose (void);
@@ -378,110 +422,14 @@
 	state.last_rtc_update = 0;
 	state.partial_tick = 0L;
 
+	timevar_init();
+
 	/* Startup the timer source. */
 	alpha_mv.init_rtc();
 }
 
 /*
- * Use the cycle counter to estimate an displacement from the last time
- * tick.  Unfortunately the Alpha designers made only the low 32-bits of
- * the cycle counter active, so we overflow on 8.2 seconds on a 500MHz
- * part.  So we can't do the "find absolute time in terms of cycles" thing
- * that the other ports do.
- */
-void
-do_gettimeofday(struct timeval *tv)
-{
-	unsigned long sec, usec, lost, flags;
-	unsigned long delta_cycles, delta_usec, partial_tick;
-
-	read_lock_irqsave(&xtime_lock, flags);
-
-	delta_cycles = rpcc() - state.last_time;
-	sec = xtime.tv_sec;
-	usec = xtime.tv_usec;
-	partial_tick = state.partial_tick;
-	lost = jiffies - wall_jiffies;
-
-	read_unlock_irqrestore(&xtime_lock, flags);
-
-#ifdef CONFIG_SMP
-	/* Until and unless we figure out how to get cpu cycle counters
-	   in sync and keep them there, we can't use the rpcc tricks.  */
-	delta_usec = lost * (1000000 / HZ);
-#else
-	/*
-	 * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks)
-	 *	= cycles * (s_t_p_c) * 1e6 / (2**48 * ticks)
-	 *	= cycles * (s_t_p_c) * 15625 / (2**42 * ticks)
-	 *
-	 * which, given a 600MHz cycle and a 1024Hz tick, has a
-	 * dynamic range of about 1.7e17, which is less than the
-	 * 1.8e19 in an unsigned long, so we are safe from overflow.
-	 *
-	 * Round, but with .5 up always, since .5 to even is harder
-	 * with no clear gain.
-	 */
-
-	delta_usec = (delta_cycles * state.scaled_ticks_per_cycle 
-		      + partial_tick
-		      + (lost << FIX_SHIFT)) * 15625;
-	delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
-#endif
-
-	usec += delta_usec;
-	if (usec >= 1000000) {
-		sec += 1;
-		usec -= 1000000;
-	}
-
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
-}
-
-void
-do_settimeofday(struct timeval *tv)
-{
-	unsigned long delta_usec;
-	long sec, usec;
-	
-	write_lock_irq(&xtime_lock);
-
-	/* The offset that is added into time in do_gettimeofday above
-	   must be subtracted out here to keep a coherent view of the
-	   time.  Without this, a full-tick error is possible.  */
-
-#ifdef CONFIG_SMP
-	delta_usec = (jiffies - wall_jiffies) * (1000000 / HZ);
-#else
-	delta_usec = rpcc() - state.last_time;
-	delta_usec = (delta_usec * state.scaled_ticks_per_cycle 
-		      + state.partial_tick
-		      + ((jiffies - wall_jiffies) << FIX_SHIFT)) * 15625;
-	delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
-#endif
-
-	sec = tv->tv_sec;
-	usec = tv->tv_usec;
-	usec -= delta_usec;
-	if (usec < 0) {
-		usec += 1000000;
-		sec -= 1;
-	}
-
-	xtime.tv_sec = sec;
-	xtime.tv_usec = usec;
-	time_adjust = 0;		/* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
-
-	write_unlock_irq(&xtime_lock);
-}
-
-
-/*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * In order to set the CMOS clock precisely, update_rtc has to be
  * called 500 ms after the second nowtime has started, because when
  * nowtime is written into the registers of the CMOS clock, it will
  * jump to the next second precisely 500 ms later. Check the Motorola
@@ -490,15 +438,11 @@
  * BUG: This routine does not handle hour overflow properly; it just
  *      sets the minutes. Usually you won't notice until after reboot!
  */
-
-extern int abs(int);
-
-static int
-set_rtc_mmss(unsigned long nowtime)
+static void
+update_rtc(void)
 {
-	int retval = 0;
-	int real_seconds, real_minutes, cmos_minutes;
 	unsigned char save_control, save_freq_select;
+	int ss, mi, hh, dd, mo, yy;
 
 	/* irq are locally disabled here */
 	spin_lock(&rtc_lock);
@@ -510,37 +454,29 @@
 	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
 	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
 
-	cmos_minutes = CMOS_READ(RTC_MINUTES);
-	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-		BCD_TO_BIN(cmos_minutes);
-
-	/*
-	 * since we're only adjusting minutes and seconds,
-	 * don't interfere with hour overflow. This avoids
-	 * messing with unknown time zones but requires your
-	 * RTC not to be off by more than 15 minutes
-	 */
-	real_seconds = nowtime % 60;
-	real_minutes = nowtime / 60;
-	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) {
-		/* correct for half hour time zone */
-		real_minutes += 30;
-	}
-	real_minutes %= 60;
-
-	if (abs(real_minutes - cmos_minutes) < 30) {
-		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-			BIN_TO_BCD(real_seconds);
-			BIN_TO_BCD(real_minutes);
-		}
-		CMOS_WRITE(real_seconds,RTC_SECONDS);
-		CMOS_WRITE(real_minutes,RTC_MINUTES);
-	} else {
-		printk(KERN_WARNING
-		       "set_rtc_mmss: can't update from %d to %d\n",
-		       cmos_minutes, real_minutes);
- 		retval = -1;
-	}
+	ktime_to_rtc(xtime.tv_sec, &ss, &dd);
+	hh = ss >> 16;
+	mi = (ss >> 8) & 0xff;
+	ss &= 0xff;
+	yy = (dd >> 16) % 100;
+	mo = (dd >> 8) & 0xff;
+	dd &= 0xff;
+	printk(KERN_DEBUG "update_rtc: %02d-%02d-%02d %02d:%02d:%02d\n",
+	       yy, mo, dd, hh, mi, ss);
+	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(ss);
+		BIN_TO_BCD(mi);
+		BIN_TO_BCD(hh);
+		BIN_TO_BCD(dd);
+		BIN_TO_BCD(mo);
+		BIN_TO_BCD(yy);
+	}
+	CMOS_WRITE(ss, RTC_SECONDS);
+	CMOS_WRITE(mi, RTC_MINUTES);
+	CMOS_WRITE(hh, RTC_HOURS);
+	CMOS_WRITE(dd, RTC_DAY_OF_MONTH);
+	CMOS_WRITE(mo, RTC_MONTH);
+	CMOS_WRITE(yy, RTC_YEAR);
 
 	/* The following flags have to be released exactly in this order,
 	 * otherwise the DS12887 (popular MC146818A clone with integrated
@@ -552,6 +488,12 @@
 	CMOS_WRITE(save_control, RTC_CONTROL);
 	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
 	spin_unlock(&rtc_lock);
+}
 
-	return retval;
+/* Fine-tune the tick interpolation for a total frequency error
+ * `freq' / 1000 PPM.
+ */
+void update_nanoscale(long freq)
+{
+	/* not implemented -- this is just a prototype [UW] */
 }
Index: linux/arch/arm/config.in
diff -u linux/arch/arm/config.in:1.1.1.10 linux/arch/arm/config.in:1.1.1.10.2.1
--- linux/arch/arm/config.in:1.1.1.10	Sat Jan 22 21:52:45 2005
+++ linux/arch/arm/config.in	Mon Jan 24 21:03:30 2005
@@ -178,6 +178,13 @@
 if [ "$CONFIG_ARCH_GUIDEA07" = "y" ]; then
    define_bool CONFIG_ARCH_CDB89712 y
 fi
+bool 'NTP kernel support' CONFIG_NTP
+if [ "$CONFIG_NTP" != "n" ]; then
+  bool '   NTP PPS support' CONFIG_NTP_PPS
+  if [ "$CONFIG_NTP_PPS" != "n" ]; then
+    bool '   Debug NTP PPS support' CONFIG_NTP_PPS_DEBUG
+  fi
+fi
 
 endmenu
 
Index: linux/arch/arm/defconfig
diff -u linux/arch/arm/defconfig:1.1.1.3 linux/arch/arm/defconfig:1.1.1.3.2.1
--- linux/arch/arm/defconfig:1.1.1.3	Sat Jan 22 21:52:45 2005
+++ linux/arch/arm/defconfig	Mon Jan 24 21:03:30 2005
@@ -88,6 +88,10 @@
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 # CONFIG_ARTHUR is not set
+CONFIG_NTP=y
+# CONFIG_NTP_PPS is not set
+# CONFIG_NTP_PPS_DEBUG is not set
+# CONFIG_NTP_PPS_SERIAL is not set
 CONFIG_CMDLINE="root=1f04 mem=32M"
 CONFIG_LEDS=y
 CONFIG_LEDS_TIMER=y
Index: linux/arch/arm/kernel/time.c
diff -u linux/arch/arm/kernel/time.c:1.1.1.5 linux/arch/arm/kernel/time.c:1.1.1.5.2.1
--- linux/arch/arm/kernel/time.c:1.1.1.5	Sat Jan 22 21:39:59 2005
+++ linux/arch/arm/kernel/time.c	Mon Jan 24 21:03:34 2005
@@ -15,6 +15,11 @@
  *              fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
  *  1998-12-20  Updated NTP code according to technical memorandum Jan '96
  *              "A Kernel Model for Precision Timekeeping" by Dave Mills
+ * 1999-03-10	Ulrich Windl
+ *	Updated for nanosecond resolution (untested)
+ * 2000-12-09	Ulrich Windl
+ *	Remove traditional code for microseconds as the nanoseconds seem
+ *	stable.
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -103,12 +108,14 @@
 	if (time_status & STA_UNSYNC || set_rtc == NULL)
 		return;
 
+	/* [UW] the new update logic should be merged from
+	   arch/i386/kernel/time.c */
 	if (next_rtc_update &&
 	    time_before(xtime.tv_sec, next_rtc_update))
 		return;
 
-	if (xtime.tv_usec < 50000 - (tick >> 1) &&
-	    xtime.tv_usec >= 50000 + (tick >> 1))
+	if (xtime.tv_nsec < 50000000 - (time_tick >> 1) &&
+	    xtime.tv_nsec >= 50000000 + (time_tick >> 1))
 		return;
 
 	if (set_rtc())
@@ -149,58 +156,6 @@
 #define do_leds()
 #endif
 
-void do_gettimeofday(struct timeval *tv)
-{
-	unsigned long flags;
-	unsigned long usec, sec;
-
-	read_lock_irqsave(&xtime_lock, flags);
-	usec = gettimeoffset();
-	{
-		unsigned long lost = jiffies - wall_jiffies;
-
-		if (lost)
-			usec += lost * USECS_PER_JIFFY;
-	}
-	sec = xtime.tv_sec;
-	usec += xtime.tv_usec;
-	read_unlock_irqrestore(&xtime_lock, flags);
-
-	/* usec may have gone up a lot: be safe */
-	while (usec >= 1000000) {
-		usec -= 1000000;
-		sec++;
-	}
-
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
-}
-
-void do_settimeofday(struct timeval *tv)
-{
-	write_lock_irq(&xtime_lock);
-	/* This is revolting. We need to set the xtime.tv_usec
-	 * correctly. However, the value in this location is
-	 * is value at the last tick.
-	 * Discover what correction gettimeofday
-	 * would have done, and then undo it!
-	 */
-	tv->tv_usec -= gettimeoffset();
-	tv->tv_usec -= (jiffies - wall_jiffies) * USECS_PER_JIFFY;
-
-	while (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
-	}
-
-	xtime = *tv;
-	time_adjust = 0;		/* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
-	write_unlock_irq(&xtime_lock);
-}
-
 static struct irqaction timer_irq = {
 	.name	= "timer",
 	.flags	= SA_INTERRUPT,
@@ -211,6 +166,17 @@
  */
 #include <asm/arch/time.h>
 
+/* nanoseconds since last timer interrupt */
+static inline unsigned long do_exact_nanotime(void)
+{
+	return gettimeoffset() * 1000;
+}
+
+static unsigned long do_gettimeoffset(void)
+{
+	return gettimeoffset ();
+}
+
 /*
  * This must cause the timer to start ticking.
  * It doesn't have to set the current time though
@@ -219,8 +185,18 @@
  */
 void __init time_init(void)
 {
-	xtime.tv_usec = 0;
+	do_nanotime = do_exact_nanotime;
+	xtime.tv_nsec = 0;
 	xtime.tv_sec  = 0;
 
+	timevar_init();		/* architecture independent initialization */
 	setup_timer();
 }
+
+/* Fine-tune the tick interpolation for a total frequency error
+ * `freq' / 1000 PPM.
+ */
+void update_nanoscale(long freq)
+{
+	/* not implemented -- this is just a prototype [UW] */
+}
Index: linux/arch/cris/kernel/time.c
diff -u linux/arch/cris/kernel/time.c:1.1.1.9 linux/arch/cris/kernel/time.c:1.1.1.9.2.1
--- linux/arch/cris/kernel/time.c:1.1.1.9	Sat Jan 22 21:52:55 2005
+++ linux/arch/cris/kernel/time.c	Mon Jan 24 21:03:40 2005
@@ -658,3 +658,11 @@
 		IO_STATE(R_VECT_MASK_SET, nmi, set);
 #endif
 }
+
+/* Fine-tune the tick interpolation for a total frequency error
+ * `freq' / 1000 PPM.
+ */
+void update_nanoscale(long freq)
+{
+	/* not implemented -- this is just a prototype [UW] */
+}
Index: linux/arch/i386/config.in
diff -u linux/arch/i386/config.in:1.1.1.15 linux/arch/i386/config.in:1.1.1.15.2.1
--- linux/arch/i386/config.in:1.1.1.15	Sat Jan 22 21:52:56 2005
+++ linux/arch/i386/config.in	Mon Jan 24 21:03:43 2005
@@ -221,6 +221,13 @@
 if [ "$CONFIG_HIGHMEM" = "y" ]; then
    bool 'HIGHMEM I/O support' CONFIG_HIGHIO
 fi
+bool 'NTP kernel support' CONFIG_NTP
+if [ "$CONFIG_NTP" != "n" ]; then
+  bool '   NTP PPS support' CONFIG_NTP_PPS
+  if [ "$CONFIG_NTP_PPS" != "n" ]; then
+    bool '   Debug NTP PPS support' CONFIG_NTP_PPS_DEBUG
+  fi
+fi
 
 bool 'Math emulation' CONFIG_MATH_EMULATION
 bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
Index: linux/arch/i386/defconfig
diff -u linux/arch/i386/defconfig:1.1.1.17 linux/arch/i386/defconfig:1.1.1.17.2.1
--- linux/arch/i386/defconfig:1.1.1.17	Sat Jan 22 22:02:08 2005
+++ linux/arch/i386/defconfig	Mon Jan 24 21:03:43 2005
@@ -119,6 +119,10 @@
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=y
 # CONFIG_OOM_KILLER is not set
+CONFIG_NTP=y
+# CONFIG_NTP_PPS is not set
+# CONFIG_NTP_PPS_DEBUG is not set
+# CONFIG_NTP_PPS_SERIAL is not set
 CONFIG_PM=y
 # CONFIG_APM is not set
 
Index: linux/arch/i386/kernel/apm.c
diff -u linux/arch/i386/kernel/apm.c:1.1.1.13 linux/arch/i386/kernel/apm.c:1.1.1.13.2.1
--- linux/arch/i386/kernel/apm.c:1.1.1.13	Sat Jan 22 21:40:07 2005
+++ linux/arch/i386/kernel/apm.c	Mon Jan 24 21:03:48 2005
@@ -308,9 +308,9 @@
 #undef INIT_TIMER_AFTER_SUSPEND
 
 #ifdef INIT_TIMER_AFTER_SUSPEND
-#include <linux/timex.h>
-#include <asm/io.h>
+#include <linux/time.h>
 #include <linux/delay.h>
+#include <asm/io.h>
 #endif
 
 /*
@@ -386,13 +386,6 @@
 static int			ignore_normal_resume;
 static int			bounce_interval = DEFAULT_BOUNCE_INTERVAL;
 
-#ifdef CONFIG_APM_RTC_IS_GMT
-#	define	clock_cmos_diff	0
-#	define	got_clock_diff	1
-#else
-static long			clock_cmos_diff;
-static int			got_clock_diff;
-#endif
 static int			debug;
 static int			smp = 0;
 static int			apm_disabled = -1;
@@ -1188,29 +1181,10 @@
 {
 	unsigned long	flags;
 
-	if (got_clock_diff) {	/* Must know time zone in order to set clock */
-		save_flags(flags);
-		cli();
-		CURRENT_TIME = get_cmos_time() + clock_cmos_diff;
-		restore_flags(flags);
-	}
-}
-
-static void get_time_diff(void)
-{
-#ifndef CONFIG_APM_RTC_IS_GMT
-	unsigned long	flags;
-
-	/*
-	 * Estimate time zone so that set_time can update the clock
-	 */
 	save_flags(flags);
-	clock_cmos_diff = -get_cmos_time();
 	cli();
-	clock_cmos_diff += CURRENT_TIME;
-	got_clock_diff = 1;
+	CURRENT_TIME = get_cmos_time();
 	restore_flags(flags);
-#endif
 }
 
 static void reinit_timer(void)
@@ -1248,7 +1222,11 @@
 		}
 		printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n");
 	}
+#ifndef CONFIG_NTP
 	get_time_diff();
+#else
+	printk(KERN_WARNING "apm: get_time_diff() not called\n");	
+#endif
 	__cli();
 	err = set_system_power_state(APM_STATE_SUSPEND);
 	reinit_timer();
@@ -1276,7 +1254,11 @@
 	int	err;
 
 	/* If needed, notify drivers here */
+#ifndef CONFIG_NTP
 	get_time_diff();
+#else
+	printk(KERN_WARNING "apm: get_time_diff() not called\n");	
+#endif
 	err = set_system_power_state(APM_STATE_STANDBY);
 	if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
 		apm_error("standby", err);
Index: linux/arch/i386/kernel/i386_ksyms.c
diff -u linux/arch/i386/kernel/i386_ksyms.c:1.1.1.14 linux/arch/i386/kernel/i386_ksyms.c:1.1.1.14.2.1
--- linux/arch/i386/kernel/i386_ksyms.c:1.1.1.14	Sat Jan 22 21:52:56 2005
+++ linux/arch/i386/kernel/i386_ksyms.c	Mon Jan 24 21:03:48 2005
@@ -32,6 +32,7 @@
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern spinlock_t rtc_lock;
+extern spinlock_t i8253_lock;
 
 #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
 extern void machine_real_restart(unsigned char *, int);
@@ -167,6 +168,7 @@
 EXPORT_SYMBOL(get_wchan);
 
 EXPORT_SYMBOL(rtc_lock);
+EXPORT_SYMBOL(i8253_lock);
 
 #undef memcpy
 #undef memset
Index: linux/arch/i386/kernel/i8259.c
diff -u linux/arch/i386/kernel/i8259.c:1.1.1.5 linux/arch/i386/kernel/i8259.c:1.1.1.5.2.1
--- linux/arch/i386/kernel/i8259.c:1.1.1.5	Sat Jan 22 21:52:56 2005
+++ linux/arch/i386/kernel/i8259.c	Mon Jan 24 21:03:48 2005
@@ -5,7 +5,7 @@
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/smp_lock.h>
Index: linux/arch/i386/kernel/irq.c
diff -u linux/arch/i386/kernel/irq.c:1.1.1.8 linux/arch/i386/kernel/irq.c:1.1.1.8.2.1
--- linux/arch/i386/kernel/irq.c:1.1.1.8	Sat Jan 22 21:40:07 2005
+++ linux/arch/i386/kernel/irq.c	Mon Jan 24 21:03:48 2005
@@ -24,7 +24,7 @@
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/smp_lock.h>
Index: linux/arch/i386/kernel/setup.c
diff -u linux/arch/i386/kernel/setup.c:1.1.1.17 linux/arch/i386/kernel/setup.c:1.1.1.17.2.1
--- linux/arch/i386/kernel/setup.c:1.1.1.17	Sat Jan 22 21:52:57 2005
+++ linux/arch/i386/kernel/setup.c	Mon Jan 24 21:03:49 2005
@@ -111,6 +111,7 @@
 #include <asm/mtrr.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/timex.h>	/* cpu_khz */
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/cobalt.h>
Index: linux/arch/i386/kernel/smpboot.c
diff -u linux/arch/i386/kernel/smpboot.c:1.1.1.13 linux/arch/i386/kernel/smpboot.c:1.1.1.13.2.1
--- linux/arch/i386/kernel/smpboot.c:1.1.1.13	Sat Jan 22 21:52:57 2005
+++ linux/arch/i386/kernel/smpboot.c	Mon Jan 24 21:03:49 2005
@@ -43,6 +43,7 @@
 
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h>
+#include <asm/timex.h>	/* cpu_khz */
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
 #include <asm/smpboot.h>
@@ -126,9 +127,11 @@
  * The bootstrap kernel entry code has set these up. Save them for
  * a given CPU
  */
-
 void __init smp_store_cpu_info(int id)
 {
+#ifdef CONFIG_X86_TSC
+	extern unsigned long calibrate_tsc(void);
+#endif
 	struct cpuinfo_x86 *c = cpu_data + id;
 
 	*c = boot_cpu_data;
@@ -148,6 +151,28 @@
 		 * Remember we have B step Pentia with bugs
 		 */
 		smp_b_stepping = 1;
+
+#ifdef CONFIG_X86_TSC
+	/*
+	 * Calibrate all additional CPUs (id != 0) and report CPU clock
+	 * in kHz (just like in time_init()).
+	 */
+	if (id != 0) {
+		exact_nanotime_quotient = calibrate_tsc();
+
+		if (exact_nanotime_quotient != 0) {
+			unsigned long eax, edx, kHz;
+
+			edx = 1000000 >> 4; eax = 0;
+			__asm__("divl %2"
+				:"=a" (kHz), "=d" (edx)
+				:"r" (exact_nanotime_quotient),
+				"0" (eax), "1" (edx));
+			printk("CPU#%d: Detected %ld kHz processor.\n",
+			       id, kHz);
+		}
+	}
+#endif
 }
 
 /*
@@ -187,8 +212,6 @@
 
 #define NR_LOOPS 5
 
-extern unsigned long fast_gettimeoffset_quotient;
-
 /*
  * accurate 64-bit/32-bit division, expanded to 32-bit divisions and 64-bit
  * multiplication. Not terribly optimized but we need it at boot time only
@@ -223,12 +246,19 @@
 	unsigned long long t0;
 	unsigned long long sum, avg;
 	long long delta;
-	unsigned long one_usec;
+	unsigned long quarter_usec, edx;
 	int buggy = 0;
 
 	printk("checking TSC synchronization across CPUs: ");
 
-	one_usec = ((1<<30)/fast_gettimeoffset_quotient)*(1<<2);
+	/* convert 250ns to CPU cycles:
+	 * cycles = (250 * 2^28) / exact_nanotime_quotient
+	 * cycles = (15*2^32 + 2684354560) / exact_nanotime_quotient
+	 */
+	__asm__("divl %2"
+		:"=a" (quarter_usec), "=d" (edx)
+		:"r" (exact_nanotime_quotient),
+		 "0" (2684354560U), "1" (15));
 
 	atomic_set(&tsc_start_flag, 1);
 	wmb();
@@ -284,22 +314,23 @@
 		if (delta < 0)
 			delta = -delta;
 		/*
-		 * We report bigger than 2 microseconds clock differences.
+		 * We report bigger than 0.5 microseconds clock differences.
 		 */
-		if (delta > 2*one_usec) {
+		if (delta > 2 * quarter_usec) {
 			long realdelta;
 			if (!buggy) {
 				buggy = 1;
 				printk("\n");
 			}
-			realdelta = div64(delta, one_usec);
+			realdelta = div64(delta, quarter_usec);
 			if (tsc_values[i] < avg)
 				realdelta = -realdelta;
 
-			printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n",
-				i, realdelta);
+			printk(KERN_WARNING
+			       "BIOS BUG: CPU#%d improperly initialized\n", i);
+			printk(KERN_INFO "TSC skew is %ld ns! FIXED.\n",
+			       realdelta * 250);
 		}
-
 		sum += delta;
 	}
 	if (!buggy)
@@ -332,7 +363,6 @@
 #undef NR_LOOPS
 
 extern void calibrate_delay(void);
-
 static atomic_t init_deasserted;
 
 void __init smp_callin(void)
Index: linux/arch/i386/kernel/time.c
diff -u linux/arch/i386/kernel/time.c:1.1.1.9 linux/arch/i386/kernel/time.c:1.1.1.9.2.1
--- linux/arch/i386/kernel/time.c:1.1.1.9	Sat Jan 22 21:52:57 2005
+++ linux/arch/i386/kernel/time.c	Mon Jan 24 21:03:49 2005
@@ -11,13 +11,13 @@
  *      fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
  *      precision CMOS clock update
  * 1996-05-03    Ingo Molnar
- *      fixed time warps in do_[slow|fast]_gettimeoffset()
+ *      fixed time warps in do_[poor|exact]_microtime()
  * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
  *		"A Kernel Model for Precision Timekeeping" by Dave Mills
  * 1998-09-05    (Various)
- *	More robust do_fast_gettimeoffset() algorithm implemented
+ *	More robust do_exact_microtime() algorithm implemented
  *	(works with APM, Cyrix 6x86MX and Centaur C6),
- *	monotonic gettimeofday() with fast_get_timeoffset(),
+ *	monotonic gettimeofday() with exact_microtime(),
  *	drift-proof precision TSC calibration on boot
  *	(C. Scott Ananian <cananian@alumni.princeton.edu>, Andrew D.
  *	Balsa <andrebalsa@altern.org>, Philip Gladstone <philip@raptor.com>;
@@ -28,6 +28,54 @@
  * 1998-12-24 Copyright (C) 1998  Andrea Arcangeli
  *	Fixed a xtime SMP race (we need the xtime_lock rw spinlock to
  *	serialize accesses to xtime/lost_ticks).
+ * 1999-04-24	Ulrich Windl
+ *	Modifications for nanosecond resolution. Several cleanups, including
+ *	renaming.  Fixed bug for ``CONFIG_X86_TSC'' with bad CPU
+ *	implementation.  ``calibrate_tsc()'' calibrates for nanoseconds now.
+ *	Made ``mktime()'' architecture independent.  Fixed time offset
+ *	computations (estimations).
+ * 1999-05-22	Ulrich Windl
+ *	Bug fix: The value of ``lost_ticks'' may change while the time offset
+ *	is computed, causing time jumps in both directions (Seen on a i386).
+ * 1999-10-14	Ulrich Windl
+ *	Bug fix: The code using the timer chip could return bad time due to
+ *	overflows.  Reduce resolution even more.
+ * 1999-12-10	Ulrich Windl
+ *	Implement new logic with ``rtc_update_slave''.  Do a complete update
+ *	of the CMOS date and time registers (``update_rtc'' replaces
+ *	``set_rtc_mmss'').  Use new ``rtc_to_ktime()'' and ``ktime_to_rtc()''
+ *	to get the timezone right.
+ * 2000-03-31	Ulrich Windl
+ *	Print time read from CMOS clock.  Require ``HZ == 100''.  Improve
+ *	speed and precision when converting timer count to nanoseconds.
+ * 2000-04-16	Ulrich Windl
+ *	``do_nanotime'' does not include ``lost_ticks''.
+ * 2000-09-04	Ulrich Windl
+ *	Improved accuracy and valid range of ``nanodelay_at_last_interrupt''
+ *	as well as ``do_poor_nanotime()''.  Fixed conversion from TSC to
+ *	nanoseconds.
+ * 2000-12-09	Ulrich Windl
+ *	Remove traditional code for microseconds as the nanoseconds seem
+ *	stable.
+ * 2001-01-09	Ulrich Windl
+ *	Improved accuracy and arithmetic of ``cpu_khz''. Improved accuracy of
+ *	``nanodelay_at_last_interrupt'', ``do_poor_nanotime()'' (fixed stupid
+ *	bug, too).
+ * 2001-03-15	Ulrich Windl
+ *	Fix for SMP: ``exact_nanotime_quotient'' is no longer static.
+ * 2001-04-16	Ulrich Windl
+ *	Removed unneeded code from ``update_rtc''.
+ * 2001-05-10	Ulrich Windl
+ *	Added scaled tick interpolation for TSC and i8259 to avoid jumps near
+ *	the end of a tick (``scaled_nano_quotient'', ``update_nanoscale()'').
+ * 2002-09-25	Ulrich Windl
+ *	Fixed some compilation problems when ``CONFIG_X86_TSC'' is not
+ *	defined.
+ * 2003-04-06	Ulrich Windl
+ *	Fixed assembler constraints that allowed illegal register allocation.
+ *	Use macros calls instead of writing explicit inline assember.
+ * 2003-08-14	Ulrich Windl
+ *	Merged nanosecond timing into new code base.
  */
 
 #include <linux/errno.h>
@@ -43,6 +91,7 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 
+#include <asm/timex.h>
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/irq.h>
@@ -53,7 +102,6 @@
 #include <asm/processor.h>
 
 #include <linux/mc146818rtc.h>
-#include <linux/timex.h>
 #include <linux/config.h>
 
 #include <asm/fixmap.h>
@@ -67,26 +115,64 @@
 
 unsigned long cpu_khz;	/* Detected as we calibrate the TSC */
 
-/* Number of usecs that the last interrupt was delayed */
-static int delay_at_last_interrupt;
+#ifndef NANOSECOND
+#define NANOSECOND 1000000000
+#endif
+
+/* multiply (a) * (rm1), and divide 64 bit result by (rm2).
+ * quotient will be in (a), remainder in (d).
+*/
+#define	mul_div(a, d, rm1, rm2) \
+	__asm__("mull %3\n\t" \
+		"divl %4" \
+		:"=&a" (a), "=&d" (d) \
+		:"%0" (a), "rm" (rm1), "rm" (rm2) \
+		:"cc")
+
+/* multiply (a) * (rm) with 64 bit result in (d),(a) */
+#define	mul64(a, d, rm) \
+	__asm__("mull %2" \
+		:"+a" (a), "=d" (d) \
+		:"rm" (rm) \
+		:"cc")
+
+#if HZ == 100
+/* One count of the timer register is worth 1/CLOCK_TICK_RATE
+ * (1000000000/1193180ns == 838.09651519ns). The register is reloaded
+ * with LATCH (11932). This accumulates within one tick to
+ * 10000168ns, giving an error of about 167.6ns per tick.  Using a factor
+ * of 838ns per timer count would result in 984ns error per tick.
+ * Scaling the exact factor by 2^(32-10) gives 3515231566,
+ * resulting in an overall error of 167.6ns per tick. That is less than
+ * the intrinsic error, so it must be OK.
+ */
+#define	EXACT_i8253_FACTOR	3515231566UL
+#else
+#error HZ != 100 not implemented
+#endif
+unsigned long scaled_i8253_factor = EXACT_i8253_FACTOR;
+
+#ifdef CONFIG_X86_TSC
+static int use_tsc = 0;
+
+/* Number of nanoseconds that the last interrupt was delayed */
+static long nanodelay_at_last_interrupt;
 
 static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
 
-/* Cached *multiplier* to convert TSC counts to microseconds.
+/* Cached *multiplier* to convert TSC counts to nanoseconds.
  * (see the equation below).
- * Equal to 2^32 * (1 / (clocks per usec) ).
+ * Equal to 2^28 * (1 / (clocks per nsec) ).
  * Initialized in time_init.
  */
-unsigned long fast_gettimeoffset_quotient;
+unsigned long exact_nanotime_quotient = 0;
+unsigned long scaled_nano_quotient = 0;
 
-extern rwlock_t xtime_lock;
-extern unsigned long wall_jiffies;
-
-spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
-
-static inline unsigned long do_fast_gettimeoffset(void)
+/* nanoseconds since last timer interrupt (using the CPU cycle-counter) */
+static inline unsigned long do_exact_nanotime(void)
 {
-	register unsigned long eax, edx;
+	register unsigned long eax asm("ax");
+	register unsigned long edx asm("dx");
 
 	/* Read the Time Stamp Counter */
 
@@ -96,9 +182,10 @@
 	eax -= last_tsc_low;	/* tsc_low delta */
 
 	/*
-         * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
-         *             = (tsc_low delta) * (usecs_per_clock)
-         *             = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
+	 * Time offset = (tsc_low delta << 4) * scaled_nano_quotient
+	 *             = (tsc_low delta << 4) * (nsecs_per_clock)
+	 *             = (tsc_low delta << 4) * (nsecs_per_jiffy /
+	 *				    clocks_per_jiffy)
 	 *
 	 * Using a mull instead of a divl saves up to 31 clock cycles
 	 * in the critical path.
@@ -106,58 +193,31 @@
 
 	__asm__("mull %2"
 		:"=a" (eax), "=d" (edx)
-		:"rm" (fast_gettimeoffset_quotient),
-		 "0" (eax));
+		:"%rm" (scaled_nano_quotient), "0" (eax << 4)
+		:"cc");
 
-	/* our adjusted time offset in microseconds */
-	return delay_at_last_interrupt + edx;
+	/* our adjusted time offset in nanoseconds */
+	return nanodelay_at_last_interrupt + edx;
 }
+#endif
 
-#define TICK_SIZE tick
+extern rwlock_t xtime_lock;
 
-spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 
-EXPORT_SYMBOL(i8253_lock);
+spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
 
 extern spinlock_t i8259A_lock;
 
-#ifndef CONFIG_X86_TSC
-
+/* return nanoseconds since last timer interrupt (using the timer
+ * chip's registers plus some helper variable to detect overflows)
+ */
 /* This function must be called with interrupts disabled 
  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
- * 
- * However, the pc-audio speaker driver changes the divisor so that
- * it gets interrupted rather more often - it loads 64 into the
- * counter rather than 11932! This has an adverse impact on
- * do_gettimeoffset() -- it stops working! What is also not
- * good is that the interval that our timer function gets called
- * is no longer 10.0002 ms, but 9.9767 ms. To get around this
- * would require using a different timing source. Maybe someone
- * could use the RTC - I know that this can interrupt at frequencies
- * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
- * it so that at startup, the timer code in sched.c would select
- * using either the RTC or the 8253 timer. The decision would be
- * based on whether there was any other device around that needed
- * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
- * and then do some jiggery to have a version of do_timer that 
- * advanced the clock by 1/1024 s. Every time that reached over 1/100
- * of a second, then do all the old code. If the time was kept correct
- * then do_gettimeoffset could just return 0 - there is no low order
- * divider that can be accessed.
- *
- * Ideally, you would be able to use the RTC for the speaker driver,
- * but it appears that the speaker driver really needs interrupt more
- * often than every 120 us or so.
- *
- * Anyway, this needs more thought....		pjsg (1993-08-28)
- * 
- * If you are really that interested, you should be reading
- * comp.protocols.time.ntp!
  */
-
-static unsigned long do_slow_gettimeoffset(void)
+static unsigned long do_poor_nanotime(void)
 {
-	int count;
+	unsigned long count;
 
 	static int count_p = LATCH;    /* for the first call after boot */
 	static unsigned long jiffies_p = 0;
@@ -173,13 +233,11 @@
 	outb_p(0x00, 0x43);	/* latch the count ASAP */
 
 	count = inb_p(0x40);	/* read the latched count */
-
 	/*
 	 * We do this guaranteed double memory access instead of a _p 
 	 * postfix in the previous port access. Wheee, hackady hack
 	 */
  	jiffies_t = jiffies;
-
 	count |= inb_p(0x40) << 8;
 	
         /* VIA686a test code... reset the latch if count > max + 1 */
@@ -202,7 +260,6 @@
 	 */
 
 /* you can safely undefine this if you don't have the Neptune chipset */
-
 #define BUGGY_NEPTUN_TIMER
 
 	if( jiffies_t == jiffies_p ) {
@@ -226,7 +283,10 @@
 				 * well, that's why we call them lost, don't we? :)
 				 * [hmm, on the Pentium and Alpha we can ... sort of]
 				 */
+#if 0 /* Should it be treated? [UW] */
 				count -= LATCH;
+				/* "count -= LATCH" would overflow below */
+#endif
 			} else {
 #ifdef BUGGY_NEPTUN_TIMER
 				/*
@@ -238,25 +298,32 @@
 				 */
 
 				count -= 256;
+				/* OK, won't overflow nanosecond computing */
 #else
-				printk("do_slow_gettimeoffset(): hardware timer problem?\n");
+				printk("do_poor_nanotime(): hardware timer problem?\n");
 #endif
 			}
 		}
-	} else
-		jiffies_p = jiffies_t;
-
+	}
+	jiffies_p = jiffies_t;
 	count_p = count;
 
-	count = ((LATCH-1) - count) * TICK_SIZE;
-	count = (count + LATCH/2) / LATCH;
+	/* The timer register moves from `LATCH' to zero while one
+	 * `time_tick' elapses.  We define zero as the maximum offset.
+	 * If servicing the interrupt is delayed for too long, the
+	 * cycle starts again.  That's why we need an indication for
+	 * `lost' (delayed) interrupt servicing.
+	 */
 
-	return count;
+	count = (LATCH-1) - count;
+	/* variable is being misused */
+	mul64(count, jiffies_t, scaled_i8253_factor);
+	/* As we take the higher 32 bits of the result, the result is
+	 * too large by a factor of 2^22.
+	 */
+	return (jiffies_t << 10) + (count >> 22);
 }
 
-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
-
-
 /* IBM Summit (EXA) Cyclone Timer code*/
 #ifdef CONFIG_X86_SUMMIT
 
@@ -303,6 +370,7 @@
                
 	count = ((LATCH-1) - count) * TICK_SIZE;
 	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+	delay_at_last_interrupt *= 1000;	/* quick-and-dirty fix by UW */
 }
 
 static unsigned long do_gettimeoffset_cyclone(void)
@@ -320,7 +388,7 @@
 
 	/* convert cyclone ticks to microseconds */	
 	/* XXX slow, can we speed this up? */
-	offset = offset/(CYCLONE_TIMER_FREQ/1000000);
+	offset = offset/(CYCLONE_TIMER_FREQ/1000);	/* fix by UW */
 
 	/* our adjusted time offset in microseconds */
 	return delay_at_last_interrupt + offset;
@@ -416,12 +484,6 @@
 }
 #endif /* CONFIG_X86_SUMMIT */
 
-#else
-
-#define do_gettimeoffset()	do_fast_gettimeoffset()
-
-#endif
-
 /* No-cyclone stubs */
 #ifndef CONFIG_X86_SUMMIT
 int __init cyclone_setup(char *str) 
@@ -436,74 +498,54 @@
 void __cyclone_delay(unsigned long loops) {}
 #endif /* CONFIG_X86_SUMMIT */
 
-/*
- * This version of gettimeofday has microsecond resolution
- * and better than microsecond precision on fast x86 machines with TSC.
- */
-void do_gettimeofday(struct timeval *tv)
+/* update ``scaled_nano_quotient'' and ``scaled_i8253_factor'' */
+void update_nanoscale(long freq)
 {
-	unsigned long flags;
-	unsigned long usec, sec;
-
-	read_lock_irqsave(&xtime_lock, flags);
-	usec = do_gettimeoffset();
-	{
-		unsigned long lost = jiffies - wall_jiffies;
-		if (lost)
-			usec += lost * (1000000 / HZ);
-	}
-	sec = xtime.tv_sec;
-	usec += xtime.tv_usec;
-	read_unlock_irqrestore(&xtime_lock, flags);
-
-	while (usec >= 1000000) {
-		usec -= 1000000;
-		sec++;
-	}
-
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
-}
-
-void do_settimeofday(struct timeval *tv)
-{
-	write_lock_irq(&xtime_lock);
-	/*
-	 * This is revolting. We need to set "xtime" correctly. However, the
-	 * value in this location is the value at the most recent update of
-	 * wall time.  Discover what correction gettimeofday() would have
-	 * made, and then undo it!
-	 */
-	tv->tv_usec -= do_gettimeoffset();
-	tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
-
-	while (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
-	}
-
-	xtime = *tv;
-	time_adjust = 0;		/* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
-	write_unlock_irq(&xtime_lock);
+	register unsigned long	eax, edx;
+#if 0	/* XXX debugging leftover */
+	printk(KERN_DEBUG "update_nanoscale(): freq = %lu\n", freq);
+#endif
+	if ( freq < -2000000 || freq > 2000000 )
+		return;	/* enforce limit to avoid overflow in division */
+	/* `freq' is 1000*PPM, so the multiplier is ``freq / 1000000000'' */
+#ifdef CONFIG_X86_TSC
+	eax = freq >= 0 ? freq : -freq;
+	mul_div(eax, edx, exact_nanotime_quotient, NANOSECOND);
+	if ( freq >= 0 )
+		scaled_nano_quotient = (long) exact_nanotime_quotient + eax;
+	else
+		scaled_nano_quotient = (long) exact_nanotime_quotient - eax;
+#if 0	/* XXX debugging leftover */
+	printk(KERN_DEBUG "(TSC CPU#%d): q(%lu)%+ldPPM = s(%lu)\n",
+	       smp_processor_id(), exact_nanotime_quotient, freq,
+	       scaled_nano_quotient);
+#endif
+#endif /* CONFIG_X86_TSC */
+	eax = freq >= 0 ? freq : -freq;
+	mul_div(eax, edx, EXACT_i8253_FACTOR, NANOSECOND);
+	if ( freq >= 0 )
+		scaled_i8253_factor = (long) EXACT_i8253_FACTOR + eax;
+	else
+		scaled_i8253_factor = (long) EXACT_i8253_FACTOR - eax;
+#if 0	/* XXX debugging leftover */
+	printk(KERN_DEBUG "(i8253): q(%lu)%+ldPPM = s(%lu)\n",
+	       EXACT_i8253_FACTOR, freq, scaled_i8253_factor);
+#endif
 }
 
 /*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be
- * called 500 ms after the second nowtime has started, because when
- * nowtime is written into the registers of the CMOS clock, it will
+ * In order to set the CMOS clock precisely, update_rtc has to be
+ * called 500 ms after the current second has started, because when
+ * the time is written into the registers of the CMOS clock, it will
  * jump to the next second precisely 500 ms later. Check the Motorola
  * MC146818A or Dallas DS12887 data sheet for details.
  *
  * BUG: This routine does not handle hour overflow properly; it just
  *      sets the minutes. Usually you'll only notice that after reboot!
  */
-static int set_rtc_mmss(unsigned long nowtime)
+static void update_rtc(void)
 {
-	int retval = 0;
-	int real_seconds, real_minutes, cmos_minutes;
+	int ss, mi, hh, dd, mo, yy;
 	unsigned char save_control, save_freq_select;
 
 	/* gets recalled with irq locally disabled */
@@ -514,35 +556,30 @@
 	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
 	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
 
-	cmos_minutes = CMOS_READ(RTC_MINUTES);
-	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-		BCD_TO_BIN(cmos_minutes);
-
-	/*
-	 * since we're only adjusting minutes and seconds,
-	 * don't interfere with hour overflow. This avoids
-	 * messing with unknown time zones but requires your
-	 * RTC not to be off by more than 15 minutes
-	 */
-	real_seconds = nowtime % 60;
-	real_minutes = nowtime / 60;
-	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
-		real_minutes += 30;		/* correct for half hour time zone */
-	real_minutes %= 60;
-
-	if (abs(real_minutes - cmos_minutes) < 30) {
-		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-			BIN_TO_BCD(real_seconds);
-			BIN_TO_BCD(real_minutes);
-		}
-		CMOS_WRITE(real_seconds,RTC_SECONDS);
-		CMOS_WRITE(real_minutes,RTC_MINUTES);
-	} else {
-		printk(KERN_WARNING
-		       "set_rtc_mmss: can't update from %d to %d\n",
-		       cmos_minutes, real_minutes);
-		retval = -1;
-	}
+	ktime_to_rtc(xtime.tv_sec, &ss, &dd);
+	hh = ss >> 16;
+	mi = (ss >> 8) & 0xff;
+	ss &= 0xff;
+	yy = (dd >> 16) % 100;
+	mo = (dd >> 8) & 0xff;
+	dd &= 0xff;
+	printk(KERN_DEBUG "update_rtc: %02d-%02d-%02d %02d:%02d:%02d\n",
+	       yy, mo, dd, hh, mi, ss);
+
+	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(ss);
+		BIN_TO_BCD(mi);
+		BIN_TO_BCD(hh);
+		BIN_TO_BCD(dd);
+		BIN_TO_BCD(mo);
+		BIN_TO_BCD(yy);
+  	}
+	CMOS_WRITE(ss, RTC_SECONDS);
+	CMOS_WRITE(mi, RTC_MINUTES);
+	CMOS_WRITE(hh, RTC_HOURS);
+	CMOS_WRITE(dd, RTC_DAY_OF_MONTH);
+	CMOS_WRITE(mo, RTC_MONTH);
+	CMOS_WRITE(yy, RTC_YEAR);
 
 	/* The following flags have to be released exactly in this order,
 	 * otherwise the DS12887 (popular MC146818A clone with integrated
@@ -554,8 +591,6 @@
 	CMOS_WRITE(save_control, RTC_CONTROL);
 	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
 	spin_unlock(&rtc_lock);
-
-	return retval;
 }
 
 /* last time the cmos clock got updated */
@@ -604,18 +639,17 @@
 #endif
 
 	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
-	 */
-	if ((time_status & STA_UNSYNC) == 0 &&
-	    xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
-	    xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
-		if (set_rtc_mmss(xtime.tv_sec) == 0)
-			last_rtc_update = xtime.tv_sec;
-		else
-			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	 * If we have a change of the software clock to be committed to the
+	 * CMOS clock, then do it. Update_rtc() has to be called as close as
+	 * possible to 500 ms before the new second starts.
+	 */
+	if (rtc_update_slave &&
+	    xtime.tv_sec >= last_rtc_update + rtc_update_slave &&
+	    xtime.tv_nsec >= NANOSECOND / 2 - ((unsigned long) time_tick) / 2 &&
+	    xtime.tv_nsec <= NANOSECOND / 2 + ((unsigned long) time_tick) / 2) {
+		update_rtc();
+		last_rtc_update = xtime.tv_sec;
+		rtc_update_slave = 0;
 	}
 	    
 #ifdef CONFIG_MCA
@@ -635,8 +669,6 @@
 #endif
 }
 
-static int use_tsc;
-
 /*
  * This is the same as the above, except we _also_ save the current
  * Time Stamp Counter value at the time of the timer interrupt, so that
@@ -644,8 +676,6 @@
  */
 static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	int count;
-
 	/*
 	 * Here we are in the timer irq handler. We just have irqs locally
 	 * disabled but we don't know if the timer_bh is running on the other
@@ -657,7 +687,14 @@
 
 	if(use_cyclone)
 		mark_timeoffset_cyclone();
+#ifdef CONFIG_X86_TSC
 	else if (use_tsc) {
+		long count;
+		unsigned long eax, edx;
+#ifdef CONFIG_SMP
+		unsigned long delta_nsec_high, delta_nsec_low;
+		int cpu;
+#endif
 		/*
 		 * It is important that these two operations happen almost at
 		 * the same time. We do the RDTSC stuff first, since it's
@@ -671,13 +708,12 @@
 		 */
 	
 		/* read Pentium cycle counter */
-
 		rdtscl(last_tsc_low);
 
 		spin_lock(&i8253_lock);
 		outb_p(0x00, 0x43);     /* latch the count ASAP */
 
-		count = inb_p(0x40);    /* read the latched count */
+		count = inb_p(0x40);	/* read the latched count */
 		count |= inb(0x40) << 8;
 
 		/* Any unpaired read will cause the above to swap MSB/LSB
@@ -702,11 +738,16 @@
 		if (count == LATCH) {
 			count--;
 		}
+		eax = (LATCH-1) - count;
+		mul64(eax, edx, scaled_i8253_factor);
 
-		count = ((LATCH-1) - count) * TICK_SIZE;
-		delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+		/* As we take the higher 32 bits of the result, the
+		 * result is too large by a factor of 2^22.
+		 */
+		nanodelay_at_last_interrupt = (edx << 10) + (eax >> 22);
 	}
 
+#endif /* CONFIG_X86_TSC */
 	do_timer_interrupt(irq, NULL, regs);
 
 	write_unlock(&xtime_lock);
@@ -740,25 +781,29 @@
 		mon = CMOS_READ(RTC_MONTH);
 		year = CMOS_READ(RTC_YEAR);
 	} while (sec != CMOS_READ(RTC_SECONDS));
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-	  {
-	    BCD_TO_BIN(sec);
-	    BCD_TO_BIN(min);
-	    BCD_TO_BIN(hour);
-	    BCD_TO_BIN(day);
-	    BCD_TO_BIN(mon);
-	    BCD_TO_BIN(year);
-	  }
 	spin_unlock(&rtc_lock);
-	if ((year += 1900) < 1970)
-		year += 100;
-	return mktime(year, mon, day, hour, min, sec);
+  	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+	{
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
+	if ((year += 1900) < 1970)	/* Fix for year 2000 rollover */
+		year += 100;		/* Doesn't the CMOS have a century? */
+	printk(KERN_INFO "get_cmos_time: %d-%02d-%02d %02d:%02d:%02d\n",
+	       year, mon, day, hour, min, sec);
+	return rtc_to_ktime(year, mon, day, hour, min, sec);
 }
 
 static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
 
+#ifdef CONFIG_X86_TSC
 /* ------ Calibrate the TSC ------- 
- * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
+ * Return 2^28 * (1 / (TSC clocks per nsec)) for exact time differences using
+ * ``rdtsc''.
  * Too much 64-bit arithmetic here to do this cleanly in C, and for
  * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
  * output busy loop as low as possible. We avoid reading the CTC registers
@@ -767,11 +812,16 @@
  */
 
 #define CALIBRATE_LATCH	(5 * LATCH)
-#define CALIBRATE_TIME	(5 * 1000020/HZ)
+#define CALIBRATE_TIME	((5 * 1000020/HZ * 1000) >> 4)
+/* allow 1GHz / 16 = 62.5MHz CPUs */
 
+#ifdef CONFIG_SMP
+unsigned long __init calibrate_tsc(void)
+#else
 static unsigned long __init calibrate_tsc(void)
+#endif
 {
-       /* Set the Gate high, disable speaker */
+	/* Set the Gate high, disable speaker */
 	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
 
 	/*
@@ -810,6 +860,8 @@
 			:"g" (startlow), "g" (starthigh),
 			 "0" (endlow), "1" (endhigh));
 
+		printk(KERN_DEBUG "calibrate_tsc(): %dns = %lu:%lu\n",
+		       CALIBRATE_TIME << 4, endhigh, endlow);
 		/* Error: ECPUTOOFAST */
 		if (endhigh)
 			goto bad_ctc;
@@ -818,10 +870,14 @@
 		if (endlow <= CALIBRATE_TIME)
 			goto bad_ctc;
 
+		/* CALIBRATE_TIME * 2^32 / endlow */
 		__asm__("divl %2"
 			:"=a" (endlow), "=d" (endhigh)
-			:"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
+			:"rm" (endlow), "0" (0), "1" (CALIBRATE_TIME)
+			:"cc");
 
+		printk(KERN_DEBUG "calibrate_tsc(): 16 * (%lu:%lu)\n",
+		       endhigh, endlow);
 		return endlow;
 	}
 
@@ -833,13 +889,15 @@
 bad_ctc:
 	return 0;
 }
+#endif
 
 void __init time_init(void)
 {
 	extern int x86_udelay_tsc;
 	
+	do_nanotime = do_poor_nanotime;
 	xtime.tv_sec = get_cmos_time();
-	xtime.tv_usec = 0;
+	xtime.tv_nsec = 0;
 
 /*
  * If we have APM enabled or the CPU clock speed is variable
@@ -855,6 +913,8 @@
  * to disk; this won't break the kernel, though, 'cuz we're
  * smart.  See arch/i386/kernel/apm.c.
  */
+
+#ifdef CONFIG_X86_TSC
  	/*
  	 *	Firstly we have to do a CPU check for chips with
  	 * 	a potentially buggy TSC. At this point we haven't run
@@ -872,9 +932,13 @@
 		init_cyclone_clock();
 		
 	if (cpu_has_tsc) {
-		unsigned long tsc_quotient = calibrate_tsc();
-		if (tsc_quotient) {
-			fast_gettimeoffset_quotient = tsc_quotient;
+		exact_nanotime_quotient = calibrate_tsc();
+		scaled_nano_quotient = exact_nanotime_quotient;
+		/* exact_nanotime_quotient is 2^28 * number of ns/TSC */
+		if (exact_nanotime_quotient != 0)
+		{
+			unsigned long eax, edx;
+
 			/* XXX: This is messy
 			 * However, we want to allow for the cyclone timer 
 			 * to work w/ or w/o the TSCs being avaliable
@@ -886,26 +950,26 @@
 				 *	and just enable this for the next intel chips ?
 			 	 */
 				use_tsc = 1;
+				/* Now it's safe to use these routines */
+				do_nanotime = do_exact_nanotime;
 				x86_udelay_tsc = 1;
-#ifndef do_gettimeoffset
-				do_gettimeoffset = do_fast_gettimeoffset;
-#endif
 			}
-			/* report CPU clock rate in Hz.
-			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
-			 * clock/second. Our precision is about 100 ppm.
+			/* report CPU clock rate in kHz. The formula is
+			 * ((10^6 >> 4) * 2^32) / (2^32 * 1 / (clocks/ns)) =
+			 * clock/millisecond. Our precision is about 100 ppm.
 			 */
-			{	unsigned long eax=0, edx=1000;
-				__asm__("divl %2"
-		       		:"=a" (cpu_khz), "=d" (edx)
-        	       		:"r" (tsc_quotient),
-	                	"0" (eax), "1" (edx));
-				printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000);
-			}
+			edx = 1000000 >> 4, eax = 0;
+			__asm__("divl %2"
+				:"=a" (cpu_khz), "=d" (edx)
+				:"rm" (exact_nanotime_quotient),
+				"0" (eax), "1" (edx)
+				:"cc");
+			printk("Detected %ld kHz processor.\n", cpu_khz);
 		}
 	}
 
-
+#endif /* CONFIG_X86_TSC */
+	timevar_init();		/* architecture independent initialization */
 #ifdef CONFIG_VISWS
 	printk("Starting Cobalt Timer system clock\n");
 
Index: linux/arch/i386/kernel/visws_apic.c
diff -u linux/arch/i386/kernel/visws_apic.c:1.1.1.2 linux/arch/i386/kernel/visws_apic.c:1.1.1.2.18.1
--- linux/arch/i386/kernel/visws_apic.c:1.1.1.2	Sun Mar 11 14:51:22 2001
+++ linux/arch/i386/kernel/visws_apic.c	Mon Jan 24 21:03:49 2005
@@ -16,10 +16,9 @@
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
-#include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/smp.h>
Index: linux/arch/ia64/dig/setup.c
diff -u linux/arch/ia64/dig/setup.c:1.1.1.5 linux/arch/ia64/dig/setup.c:1.1.1.5.2.1
--- linux/arch/ia64/dig/setup.c:1.1.1.5	Sat Jan 22 21:40:11 2005
+++ linux/arch/ia64/dig/setup.c	Mon Jan 24 21:03:52 2005
@@ -17,7 +17,7 @@
 #include <linux/string.h>
 #include <linux/tty.h>
 #include <linux/console.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/sched.h>
 
 #include <asm/io.h>
Index: linux/arch/ia64/ia32/sys_ia32.c
diff -u linux/arch/ia64/ia32/sys_ia32.c:1.1.1.13 linux/arch/ia64/ia32/sys_ia32.c:1.1.1.13.2.1
--- linux/arch/ia64/ia32/sys_ia32.c:1.1.1.13	Sat Jan 22 22:02:12 2005
+++ linux/arch/ia64/ia32/sys_ia32.c	Mon Jan 24 21:03:56 2005
@@ -748,6 +748,7 @@
 struct timeval32
 {
     int tv_sec, tv_usec;
+	/*[UW] Attention: Actually ``tv_usec'' is nanoseconds sometimes! */
 };
 
 struct itimerval32
@@ -4537,12 +4538,15 @@
 	u32 modes;
 	s32 offset, freq, maxerror, esterror;
 	s32 status, constant, precision, tolerance;
-	struct timeval32 time;
-	s32 tick;
+	struct timespec32 time;		/* ``NTP_NANO'' is defined */
+	s32 time_tick;
 	s32 ppsfreq, jitter, shift, stabil;
 	s32 jitcnt, calcnt, errcnt, stbcnt;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
+	/*[UW]Sorry , the layout is a mess, but it's for historical reasons */
+	s32 tai;
+	s32  :32; s32  :32; s32  :32;
+	int	tickadj;
+	s32  :32; s32  :32; s32  :32;
 	s32  :32; s32  :32; s32  :32; s32  :32;
 };
 
@@ -4566,8 +4570,8 @@
 	   __get_user(txc.precision, &utp->precision) ||
 	   __get_user(txc.tolerance, &utp->tolerance) ||
 	   __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __get_user(txc.tick, &utp->tick) ||
+	   __get_user(txc.time.tv_nsec, &utp->time.tv_nsec) ||
+	   __get_user(txc.time_tick, &utp->time_tick) ||
 	   __get_user(txc.ppsfreq, &utp->ppsfreq) ||
 	   __get_user(txc.jitter, &utp->jitter) ||
 	   __get_user(txc.shift, &utp->shift) ||
@@ -4575,7 +4579,9 @@
 	   __get_user(txc.jitcnt, &utp->jitcnt) ||
 	   __get_user(txc.calcnt, &utp->calcnt) ||
 	   __get_user(txc.errcnt, &utp->errcnt) ||
-	   __get_user(txc.stbcnt, &utp->stbcnt))
+	   __get_user(txc.stbcnt, &utp->stbcnt) ||
+	   __get_user(txc.stbcnt, &utp->tai) ||
+	   __get_user(txc.stbcnt, &utp->tickadj))
 		return -EFAULT;
 
 	ret = do_adjtimex(&txc);
@@ -4590,8 +4596,8 @@
 	   __put_user(txc.precision, &utp->precision) ||
 	   __put_user(txc.tolerance, &utp->tolerance) ||
 	   __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __put_user(txc.tick, &utp->tick) ||
+	   __put_user(txc.time.tv_nsec, &utp->time.tv_nsec) ||
+	   __put_user(txc.tick, &utp->time_tick) ||
 	   __put_user(txc.ppsfreq, &utp->ppsfreq) ||
 	   __put_user(txc.jitter, &utp->jitter) ||
 	   __put_user(txc.shift, &utp->shift) ||
@@ -4599,7 +4605,9 @@
 	   __put_user(txc.jitcnt, &utp->jitcnt) ||
 	   __put_user(txc.calcnt, &utp->calcnt) ||
 	   __put_user(txc.errcnt, &utp->errcnt) ||
-	   __put_user(txc.stbcnt, &utp->stbcnt))
+	   __put_user(txc.stbcnt, &utp->stbcnt) ||
+	   __put_user(txc.stbcnt, &utp->tai) ||
+	   __put_user(txc.stbcnt, &utp->tickadj))
 		ret = -EFAULT;
 
 	return ret;
Index: linux/arch/ia64/kernel/irq.c
diff -u linux/arch/ia64/kernel/irq.c:1.1.1.11 linux/arch/ia64/kernel/irq.c:1.1.1.11.2.1
--- linux/arch/ia64/kernel/irq.c:1.1.1.11	Sat Jan 22 21:40:12 2005
+++ linux/arch/ia64/kernel/irq.c	Mon Jan 24 21:03:59 2005
@@ -24,7 +24,7 @@
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/smp_lock.h>
Index: linux/arch/ia64/kernel/time.c
diff -u linux/arch/ia64/kernel/time.c:1.1.1.9 linux/arch/ia64/kernel/time.c:1.1.1.9.2.1
--- linux/arch/ia64/kernel/time.c:1.1.1.9	Sat Jan 22 21:53:03 2005
+++ linux/arch/ia64/kernel/time.c	Mon Jan 24 21:03:59 2005
@@ -294,3 +294,11 @@
 	efi_gettimeofday((struct timeval *) &xtime);
 	ia64_init_itm();
 }
+
+/* Fine-tune the tick interpolation for a total frequency error
+ * `freq' / 1000 PPM.
+ */
+void update_nanoscale(long freq)
+{
+	/* not implemented -- this is just a prototype [UW] */
+}
Index: linux/arch/m68k/config.in
diff -u linux/arch/m68k/config.in:1.1.1.8 linux/arch/m68k/config.in:1.1.1.8.2.1
--- linux/arch/m68k/config.in:1.1.1.8	Sat Jan 22 21:53:07 2005
+++ linux/arch/m68k/config.in	Mon Jan 24 21:04:03 2005
@@ -146,6 +146,13 @@
       bool '    IEEE 1284 transfer modes' CONFIG_PARPORT_1284
    fi
 fi
+bool 'NTP kernel support' CONFIG_NTP
+if [ "$CONFIG_NTP" != "n" ]; then
+  bool '   NTP PPS support' CONFIG_NTP_PPS
+  if [ "$CONFIG_NTP_PPS" != "n" ]; then
+    bool '   Debug NTP PPS support' CONFIG_NTP_PPS_DEBUG
+  fi
+fi
 
 if [ "$CONFIG_Q40" = "y" -o "$CONFIG_AMIGA_PCMCIA" = "y" \
       -o "$CONFIG_GG2" = "y" ]; then
Index: linux/arch/m68k/defconfig
diff -u linux/arch/m68k/defconfig:1.1.1.3 linux/arch/m68k/defconfig:1.1.1.3.2.1
--- linux/arch/m68k/defconfig:1.1.1.3	Sat Jan 22 21:53:07 2005
+++ linux/arch/m68k/defconfig	Mon Jan 24 21:04:03 2005
@@ -47,6 +47,10 @@
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
+CONFIG_NTP=y
+# CONFIG_NTP_PPS is not set
+# CONFIG_NTP_PPS_DEBUG is not set
+# CONFIG_NTP_PPS_SERIAL is not set
 CONFIG_ZORRO=y
 # CONFIG_AMIGA_PCMCIA is not set
 # CONFIG_HEARTBEAT is not set
Index: linux/arch/m68k/kernel/time.c
diff -u linux/arch/m68k/kernel/time.c:1.1.1.3 linux/arch/m68k/kernel/time.c:1.1.1.3.4.1
--- linux/arch/m68k/kernel/time.c:1.1.1.3	Fri Aug 15 22:25:34 2003
+++ linux/arch/m68k/kernel/time.c	Mon Jan 24 21:04:08 2005
@@ -6,13 +6,20 @@
  * This file contains the m68k-specific time handling details.
  * Most of the stuff is located in the machine specific files.
  *
- * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
- *		"A Kernel Model for Precision Timekeeping" by Dave Mills
+ * 1999-05-22	Ulrich Windl
+ *	Updated for nanosecond resolution (untested)
+ * 1999-12-10	Ulrich Windl
+ *	Implement new logic with ``rtc_update_slave''.  Use ``rtc_update()'',
+ *	replacing ``set_rtc_mmss()'' (untested).
+ * 2000-12-09	Ulrich Windl
+ *	Remove traditional code for microseconds as the nanoseconds seem
+ *	stable.
  */
 
 #include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/errno.h>
-#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/timex.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
@@ -21,14 +28,11 @@
 #include <asm/machdep.h>
 #include <asm/io.h>
 
-#include <linux/timex.h>
-
-
-static inline int set_rtc_mmss(unsigned long nowtime)
+static inline void update_rtc(void)
 {
-  if (mach_set_clock_mmss)
-    return mach_set_clock_mmss (nowtime);
-  return -1;
+	if (mach_set_clock_mmss)
+		return mach_set_clock_mmss (xtime.tv_sec);
+	return -1;
 }
 
 static inline void do_profile (unsigned long pc)
@@ -85,6 +89,12 @@
 #endif /* CONFIG_HEARTBEAT */
 }
 
+/* nanoseconds since last timer interrupt */
+static inline unsigned long do_exact_nanotime(void)
+{
+	return do_exact_microtime() * 1000;
+}
+
 void time_init(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
@@ -92,65 +102,21 @@
 	extern void arch_gettod(int *year, int *mon, int *day, int *hour,
 				int *min, int *sec);
 
+	do_nanotime = do_exact_nanotime;
 	arch_gettod (&year, &mon, &day, &hour, &min, &sec);
 
 	if ((year += 1900) < 1970)
 		year += 100;
 	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_usec = 0;
+	xtime.tv_nsec = 0;
 
 	mach_sched_init(timer_interrupt);
 }
 
-extern rwlock_t xtime_lock;
-
-/*
- * This version of gettimeofday has near microsecond resolution.
+/* Fine-tune the tick interpolation for a total frequency error
+ * `freq' / 1000 PPM.
  */
-void do_gettimeofday(struct timeval *tv)
-{
-	extern unsigned long wall_jiffies;
-	unsigned long flags;
-	unsigned long usec, sec, lost;
-
-	read_lock_irqsave(&xtime_lock, flags);
-	usec = mach_gettimeoffset();
-	lost = jiffies - wall_jiffies;
-	if (lost)
-		usec += lost * (1000000/HZ);
-	sec = xtime.tv_sec;
-	usec += xtime.tv_usec;
-	read_unlock_irqrestore(&xtime_lock, flags);
-
-	while (usec >= 1000000) {
-		usec -= 1000000;
-		sec++;
-	}
-
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
-}
-
-void do_settimeofday(struct timeval *tv)
+void update_nanoscale(long freq)
 {
-	write_lock_irq(&xtime_lock);
-	/* This is revolting. We need to set the xtime.tv_usec
-	 * correctly. However, the value in this location is
-	 * is value at the last tick.
-	 * Discover what correction gettimeofday
-	 * would have done, and then undo it!
-	 */
-	tv->tv_usec -= mach_gettimeoffset();
-
-	while (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
-	}
-
-	xtime = *tv;
-	time_adjust = 0;		/* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
-	write_unlock_irq(&xtime_lock);
+	/* not implemented -- this is just a prototype [UW] */
 }
Index: linux/arch/mips/config-shared.in
diff -u linux/arch/mips/config-shared.in:1.1.1.5 linux/arch/mips/config-shared.in:1.1.1.5.2.1
--- linux/arch/mips/config-shared.in:1.1.1.5	Sat Jan 22 22:02:25 2005
+++ linux/arch/mips/config-shared.in	Mon Jan 24 21:04:11 2005
@@ -971,6 +971,14 @@
 
 #source drivers/misc/Config.in
 
+bool 'NTP kernel support' CONFIG_NTP
+if [ "$CONFIG_NTP" != "n" ]; then
+  bool '   NTP PPS support' CONFIG_NTP_PPS
+  if [ "$CONFIG_NTP_PPS" != "n" ]; then
+    bool '   Debug NTP PPS support' CONFIG_NTP_PPS_DEBUG
+  fi
+fi
+
 source fs/Config.in
 
 source drivers/media/Config.in
Index: linux/arch/mips/defconfig
diff -u linux/arch/mips/defconfig:1.1.1.9 linux/arch/mips/defconfig:1.1.1.9.2.1
--- linux/arch/mips/defconfig:1.1.1.9	Sat Jan 22 22:02:25 2005
+++ linux/arch/mips/defconfig	Mon Jan 24 21:04:11 2005
@@ -150,6 +150,10 @@
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_OOM_KILLER is not set
 # CONFIG_CMDLINE_BOOL is not set
+CONFIG_NTP=y
+# CONFIG_NTP_PPS is not set
+# CONFIG_NTP_PPS_DEBUG is not set
+# CONFIG_NTP_PPS_SERIAL is not set
 
 #
 # Memory Technology Devices (MTD)
Index: linux/arch/mips/baget/irq.c
diff -u linux/arch/mips/baget/irq.c:1.1.1.6 linux/arch/mips/baget/irq.c:1.1.1.6.2.1
--- linux/arch/mips/baget/irq.c:1.1.1.6	Sat Jan 22 21:40:27 2005
+++ linux/arch/mips/baget/irq.c	Mon Jan 24 21:04:14 2005
@@ -13,7 +13,7 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/delay.h>
Index: linux/arch/mips/baget/time.c
diff -u linux/arch/mips/baget/time.c:1.1.1.3 linux/arch/mips/baget/time.c:1.1.1.3.2.1
--- linux/arch/mips/baget/time.c:1.1.1.3	Sat Jan 22 21:40:27 2005
+++ linux/arch/mips/baget/time.c	Mon Jan 24 21:04:14 2005
@@ -12,7 +12,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/spinlock.h>
 
 #include <asm/bootinfo.h>
Index: linux/arch/mips/kernel/setup.c
diff -u linux/arch/mips/kernel/setup.c:1.1.1.9 linux/arch/mips/kernel/setup.c:1.1.1.9.2.1
--- linux/arch/mips/kernel/setup.c:1.1.1.9	Sat Jan 22 22:02:34 2005
+++ linux/arch/mips/kernel/setup.c	Mon Jan 24 21:04:18 2005
@@ -29,7 +29,6 @@
 #include <linux/bootmem.h>
 #include <linux/blk.h>
 #include <linux/ide.h>
-#include <linux/timex.h>
 
 #include <asm/asm.h>
 #include <asm/bootinfo.h>
Index: linux/arch/mips/kernel/sysirix.c
diff -u linux/arch/mips/kernel/sysirix.c:1.1.1.9 linux/arch/mips/kernel/sysirix.c:1.1.1.9.2.1
--- linux/arch/mips/kernel/sysirix.c:1.1.1.9	Sat Jan 22 22:02:34 2005
+++ linux/arch/mips/kernel/sysirix.c	Mon Jan 24 21:04:18 2005
@@ -13,7 +13,7 @@
 #include <linux/slab.h>
 #include <linux/swap.h>
 #include <linux/errno.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/times.h>
 #include <linux/elf.h>
 #include <linux/msg.h>
@@ -618,19 +618,7 @@
 
 asmlinkage int irix_stime(int value)
 {
-	if (!capable(CAP_SYS_TIME))
-		return -EPERM;
-
-	write_lock_irq(&xtime_lock);
-	xtime.tv_sec = value;
-	xtime.tv_usec = 0;
-	time_adjust = 0;			/* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
-	write_unlock_irq(&xtime_lock);
-
-	return 0;
+	return sys_stime(&value);
 }
 
 extern int do_setitimer(int which, struct itimerval *value,
@@ -1050,10 +1038,7 @@
 
 asmlinkage int irix_gettimeofday(struct timeval *tv)
 {
-	int retval;
-
-	retval = copy_to_user(tv, &xtime, sizeof(*tv)) ? -EFAULT : 0;
-	return retval;
+	return sys_gettimeofday(tv, NULL);
 }
 
 #define IRIX_MAP_AUTOGROW 0x40
Index: linux/arch/mips/kernel/time.c
diff -u linux/arch/mips/kernel/time.c:1.1.1.8 linux/arch/mips/kernel/time.c:1.1.1.8.2.1
--- linux/arch/mips/kernel/time.c:1.1.1.8	Sat Jan 22 22:02:34 2005
+++ linux/arch/mips/kernel/time.c	Mon Jan 24 21:04:18 2005
@@ -10,12 +10,19 @@
  * under  the terms of  the GNU General  Public License as published by the
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
+ * 1999-04-07	Ulrich Windl
+ *	Updated for nanosecond resolution (untested)
+ * 1999-12-10	Ulrich Windl
+ *	Implement new logic with ``rtc_update_slave''.
+ *	Use new ``update_rtc'' (untested).
+ * 2000-12-09	Ulrich Windl
+ *	Remove traditional code for microseconds as the nanoseconds seem
+ *	stable.
  */
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/time.h>
 #include <linux/timex.h>
@@ -45,7 +52,6 @@
  * forward reference
  */
 extern rwlock_t xtime_lock;
-extern volatile unsigned long wall_jiffies;
 
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 
@@ -151,62 +157,6 @@
 unsigned int (*mips_hpt_read)(void);
 void (*mips_hpt_init)(unsigned int);
 
-
-/*
- * timeofday services, for syscalls.
- */
-void do_gettimeofday(struct timeval *tv)
-{
-	unsigned long flags, lost;
-
-	read_lock_irqsave(&xtime_lock, flags);
-
-	*tv = xtime;
-	tv->tv_usec += do_gettimeoffset();
-	/*
-	 * xtime is atomically updated in timer_bh.  jiffies - wall_jiffies
-	 * is nonzero if the timer bottom half hasn't executed yet.
-	 */
-	lost = jiffies - wall_jiffies;
-	if (lost)
-		tv->tv_usec += lost * USECS_PER_JIFFY;
-
-	read_unlock_irqrestore(&xtime_lock, flags);
-
-	while (tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
-	}
-}
-
-void do_settimeofday(struct timeval *tv)
-{
-	write_lock_irq(&xtime_lock);
-
-	/*
-	 * This is revolting.  We need to set "xtime" correctly.  However,
-	 * the value in this location is the value at the most recent update
-	 * of wall time.  Discover what correction gettimeofday() would have
-	 * made, and then undo it!
-	 */
-	tv->tv_usec -= do_gettimeoffset();
-	tv->tv_usec -= (jiffies - wall_jiffies) * USECS_PER_JIFFY;
-
-	while (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
-	}
-
-	xtime = *tv;
-	time_adjust = 0;			/* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
-
-	write_unlock_irq(&xtime_lock);
-}
-
-
 /*
  * Gettimeoffset routines.  These routines returns the time duration
  * since last timer interrupt in usecs.
@@ -356,6 +306,7 @@
 		: "r" (count), "r" (quotient)
 		: "lo", GCC_REG_ACCUM);
 
+#ifdef CONFIG_NTP
 	/*
 	 * Due to possible jiffies inconsistencies, we need to check
 	 * the result so that we'll get a timer that is monotonic.
Index: linux/arch/mips/sni/setup.c
diff -u linux/arch/mips/sni/setup.c:1.1.1.4 linux/arch/mips/sni/setup.c:1.1.1.4.2.1
--- linux/arch/mips/sni/setup.c:1.1.1.4	Sat Jan 22 21:40:39 2005
+++ linux/arch/mips/sni/setup.c	Mon Jan 24 21:04:22 2005
@@ -14,7 +14,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/pci.h>
 #include <linux/mc146818rtc.h>
 #include <linux/console.h>
Index: linux/arch/mips64/kernel/smp.c
diff -u linux/arch/mips64/kernel/smp.c:1.1.1.10 linux/arch/mips64/kernel/smp.c:1.1.1.10.2.1
--- linux/arch/mips64/kernel/smp.c:1.1.1.10	Sat Jan 22 22:02:43 2005
+++ linux/arch/mips64/kernel/smp.c	Mon Jan 24 21:04:25 2005
@@ -27,7 +27,6 @@
 #include <linux/threads.h>
 #include <linux/module.h>
 #include <linux/time.h>
-#include <linux/timex.h>
 #include <linux/sched.h>
 
 #include <asm/atomic.h>
Index: linux/arch/ppc/config.in
diff -u linux/arch/ppc/config.in:1.1.1.13 linux/arch/ppc/config.in:1.1.1.13.2.1
--- linux/arch/ppc/config.in:1.1.1.13	Sat Jan 22 21:53:37 2005
+++ linux/arch/ppc/config.in	Mon Jan 24 21:04:28 2005
@@ -121,6 +121,13 @@
  	define_bool CONFIG_TQM8xxL y
   fi
 fi
+bool 'NTP kernel support' CONFIG_NTP
+if [ "$CONFIG_NTP" != "n" ]; then
+  bool '   NTP PPS support' CONFIG_NTP_PPS
+  if [ "$CONFIG_NTP_PPS" != "n" ]; then
+    bool '   Debug NTP PPS support' CONFIG_NTP_PPS_DEBUG
+  fi
+fi
 
 if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ]; then
   choice 'Machine Type'		\
Index: linux/arch/ppc/defconfig
diff -u linux/arch/ppc/defconfig:1.1.1.12 linux/arch/ppc/defconfig:1.1.1.12.2.1
--- linux/arch/ppc/defconfig:1.1.1.12	Sat Jan 22 22:02:48 2005
+++ linux/arch/ppc/defconfig	Mon Jan 24 21:04:28 2005
@@ -655,6 +655,10 @@
 CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_NTP=y
+# CONFIG_NTP_PPS is not set
+# CONFIG_NTP_PPS_DEBUG is not set
+# CONFIG_NTP_PPS_SERIAL is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
 
Index: linux/arch/ppc/amiga/time.c
diff -u linux/arch/ppc/amiga/time.c:1.1.1.4 linux/arch/ppc/amiga/time.c:1.1.1.4.4.1
--- linux/arch/ppc/amiga/time.c:1.1.1.4	Fri Aug 15 22:25:48 2003
+++ linux/arch/ppc/amiga/time.c	Mon Jan 24 21:04:32 2005
@@ -8,8 +8,7 @@
 
 #include <asm/machdep.h>
 #include <asm/io.h>
-
-#include <linux/timex.h>
+#include <asm/timex.h>
 
 unsigned long m68k_get_rtc_time(void)
 {
Index: linux/arch/ppc/kernel/irq.c
diff -u linux/arch/ppc/kernel/irq.c:1.1.1.11 linux/arch/ppc/kernel/irq.c:1.1.1.11.2.1
--- linux/arch/ppc/kernel/irq.c:1.1.1.11	Sat Jan 22 21:40:50 2005
+++ linux/arch/ppc/kernel/irq.c	Mon Jan 24 21:04:35 2005
@@ -35,7 +35,7 @@
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/slab.h>
Index: linux/arch/ppc/kernel/time.c
diff -u linux/arch/ppc/kernel/time.c:1.1.1.11 linux/arch/ppc/kernel/time.c:1.1.1.11.2.1
--- linux/arch/ppc/kernel/time.c:1.1.1.11	Sat Jan 22 21:40:52 2005
+++ linux/arch/ppc/kernel/time.c	Mon Jan 24 21:04:35 2005
@@ -38,20 +38,23 @@
  * Since it is not possible to get a nice 100 Hz clock out of this, without
  * creating a software PLL, I have set HZ to 128.  -- Dan
  *
- * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
- *             "A Kernel Model for Precision Timekeeping" by Dave Mills
+ * 1999-05-22	Ulrich Windl
+ *	Updated for nanoseconds and general cleanup (untested)
+ * 1999-12-10	Ulrich Windl
+ *	Implement new logic with ``rtc_update_slave''.
+ * 2000-12-09	Ulrich Windl
+ *	Remove traditional code for microseconds as the nanoseconds seem
+ *	stable.
  */
 
 #include <linux/config.h>
 #include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
 #include <linux/time.h>
@@ -183,15 +186,15 @@
 		 * We should have an rtc call that only sets the minutes and
 		 * seconds like on Intel to avoid problems with non UTC clocks.
 		 */
-		if ( ppc_md.set_rtc_time && (time_status & STA_UNSYNC) == 0 &&
-		     xtime.tv_sec - last_rtc_update >= 659 &&
-		     abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ &&
-		     jiffies - wall_jiffies == 1) {
-		  	if (ppc_md.set_rtc_time(xtime.tv_sec+1 + time_offset) == 0)
-				last_rtc_update = xtime.tv_sec+1;
-			else
-				/* Try again one minute later */
-				last_rtc_update += 60;
+		if (rtc_update_slave && ppc_md.set_rtc_time &&
+		    xtime.tv_sec >= last_rtc_update + rtc_update_slave)
+		{
+			if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) {
+				last_rtc_update = xtime.tv_sec;
+				rtc_update_slave = 0;
+			}
+			else	/* pause for 1 minute */
+				rtc_update_slave += 60;
 		}
 		write_unlock(&xtime_lock);
 	}
@@ -211,83 +214,13 @@
 	return 1; /* lets ret_from_int know we can do checks */
 }
 
-/*
- * This version of gettimeofday has microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
-	unsigned long flags;
-	unsigned delta, lost_ticks, usec, sec;
-
-	read_lock_irqsave(&xtime_lock, flags);
-	sec = xtime.tv_sec;
-	usec = xtime.tv_usec;
-	delta = tb_ticks_since(tb_last_stamp);
-#ifdef CONFIG_SMP
-	/* As long as timebases are not in sync, gettimeofday can only
-	 * have jiffy resolution on SMP.
-	 */
-	if (!smp_tb_synchronized)
-		delta = 0;
-#endif /* CONFIG_SMP */
-	lost_ticks = jiffies - wall_jiffies;
-	read_unlock_irqrestore(&xtime_lock, flags);
-
-	usec += mulhwu(tb_to_us, tb_ticks_per_jiffy * lost_ticks + delta);
-	while (usec >= 1000000) {
-	  	sec++;
-		usec -= 1000000;
-	}
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
-}
-
-void do_settimeofday(struct timeval *tv)
+/* nanoseconds since last timer interrupt */
+static inline unsigned long do_exact_nanotime(void)
 {
-	unsigned long flags;
-	int tb_delta, new_usec, new_sec;
-
-	write_lock_irqsave(&xtime_lock, flags);
-	/* Updating the RTC is not the job of this code. If the time is
-	 * stepped under NTP, the RTC will be update after STA_UNSYNC
-	 * is cleared. Tool like clock/hwclock either copy the RTC
-	 * to the system time, in which case there is no point in writing
-	 * to the RTC again, or write to the RTC but then they don't call
-	 * settimeofday to perform this operation. Note also that
-	 * we don't touch the decrementer since:
-	 * a) it would lose timer interrupt synchronization on SMP
-	 * (if it is working one day)
-	 * b) it could make one jiffy spuriously shorter or longer
-	 * which would introduce another source of uncertainty potentially
-	 * harmful to relatively short timers.
-	 */
-
-	/* This works perfectly on SMP only if the tb are in sync but
-	 * guarantees an error < 1 jiffy even if they are off by eons,
-	 * still reasonable when gettimeofday resolution is 1 jiffy.
-	 */
-	tb_delta = tb_ticks_since(last_jiffy_stamp(smp_processor_id()));
-	tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
-	new_sec = tv->tv_sec;
-	new_usec = tv->tv_usec - mulhwu(tb_to_us, tb_delta);
-	while (new_usec <0) {
-		new_sec--;
-		new_usec += 1000000;
-	}
-	xtime.tv_usec = new_usec;
-	xtime.tv_sec = new_sec;
-
-	/* In case of a large backwards jump in time with NTP, we want the
-	 * clock to be updated as soon as the PLL is again in lock.
-	 */
-	last_rtc_update = new_sec - 658;
-
-	time_adjust = 0;                /* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_state = TIME_ERROR;        /* p. 24, (a) */
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
-	write_unlock_irqrestore(&xtime_lock, flags);
+	return (decrementer_count - get_dec())
+	    * count_period_num / count_period_den * 1000;
+	/* please verify! - UW */
+	/* set_dec(frac_tick * count_period_den / count_period_num); */
 }
 
 /* This function is only called on the boot processor */
@@ -296,6 +229,7 @@
 	time_t sec, old_sec;
 	unsigned old_stamp, stamp, elapsed;
 
+	do_nanotime = do_exact_nanotime;
         if (ppc_md.time_init != NULL)
                 time_offset = ppc_md.time_init();
 
@@ -331,7 +265,8 @@
 		if (sec == old_sec)
 			printk("Warning: real time clock seems stuck!\n");
 		xtime.tv_sec = sec;
-		xtime.tv_usec = 0;
+		xtime.tv_nsec = 0;
+		timevar_init();
 		/* No update now, we just read the time from the RTC ! */
 		last_rtc_update = xtime.tv_sec;
 	}
@@ -426,3 +361,10 @@
 	return mlt;
 }
 
+/* Fine-tune the tick interpolation for a total frequency error
+ * `freq' / 1000 PPM.
+ */
+void update_nanoscale(long freq)
+{
+	/* not implemented -- this is just a prototype [UW] */
+}
Index: linux/arch/s390/config.in
diff -u linux/arch/s390/config.in:1.1.1.10 linux/arch/s390/config.in:1.1.1.10.2.1
--- linux/arch/s390/config.in:1.1.1.10	Sat Jan 22 21:53:50 2005
+++ linux/arch/s390/config.in	Mon Jan 24 21:04:38 2005
@@ -64,6 +64,17 @@
 bool 'VM shared kernel support' CONFIG_SHARED_KERNEL
 endmenu
 
+mainmenu_option next_comment
+comment 'Time configuration'
+bool 'NTP kernel support' CONFIG_NTP
+if [ "$CONFIG_NTP" != "n" ]; then
+  bool '   NTP PPS support' CONFIG_NTP_PPS
+  if [ "$CONFIG_NTP_PPS" != "n" ]; then
+    bool '   Debug NTP PPS support' CONFIG_NTP_PPS_DEBUG
+  fi
+fi
+endmenu
+
 source drivers/s390/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
Index: linux/arch/s390/defconfig
diff -u linux/arch/s390/defconfig:1.1.1.11 linux/arch/s390/defconfig:1.1.1.11.2.1
--- linux/arch/s390/defconfig:1.1.1.11	Sat Jan 22 22:03:00 2005
+++ linux/arch/s390/defconfig	Mon Jan 24 21:04:38 2005
@@ -52,6 +52,14 @@
 # CONFIG_SHARED_KERNEL is not set
 
 #
+# Time configuration
+#
+CONFIG_NTP=y
+# CONFIG_NTP_PPS is not set
+# CONFIG_NTP_PPS_DEBUG is not set
+# CONFIG_NTP_PPS_SERIAL is not set
+
+#
 # Block device drivers
 #
 CONFIG_BLK_DEV_LOOP=y
Index: linux/arch/s390/kernel/time.c
diff -u linux/arch/s390/kernel/time.c:1.1.1.9 linux/arch/s390/kernel/time.c:1.1.1.9.2.1
--- linux/arch/s390/kernel/time.c:1.1.1.9	Sat Jan 22 21:53:51 2005
+++ linux/arch/s390/kernel/time.c	Mon Jan 24 21:04:41 2005
@@ -9,10 +9,14 @@
  *
  *  Derived from "arch/i386/kernel/time.c"
  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ * 2000-01-23	Ulrich Windl
+ *	Merged changes for PPSkit-0.9.1 from i386 architecture [untested].
+ * 2000-12-09	Ulrich Windl
+ *	Remove traditional code for microseconds as the nanoseconds seem
+ *	stable.
  */
 
 #include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
@@ -28,7 +32,6 @@
 #include <asm/delay.h>
 #include <asm/s390_ext.h>
 
-#include <linux/timex.h>
 #include <linux/config.h>
 
 #include <asm/irq.h>
@@ -49,10 +52,11 @@
 static u64 init_timer_cc;
 static u64 xtime_cc;
 
-extern rwlock_t xtime_lock;
-extern unsigned long wall_jiffies;
-
-void tod_to_timeval(__u64 todval, struct timeval *xtime)
+#ifndef NANOSECOND
+#define NANOSECOND 1000000000
+#endif
+  
+void tod_to_timespec(__u64 todval, struct timespec *xtime)
 {
         const int high_bit = 0x80000000L;
         const int c_f4240 = 0xf4240L;
@@ -84,9 +88,11 @@
 		      : "=m" (*xtime) : "m" (todval),
 		        "m" (c_7a120), "m" (high_bit), "m" (c_f4240)
 		      : "cc", "memory", "2", "3", "4" );
+	xtime->tv_nsec *= 1000;	/* UW: sorry, I can't do S390 assembler */
 }
 
-static inline unsigned long do_gettimeoffset(void) 
+/* nanoseconds since last timer interrupt */
+unsigned long do_nanotime(void) 
 {
 	__u64 now;
 
@@ -94,54 +100,7 @@
         now = (now - init_timer_cc) >> 12;
 	/* We require the offset from the latest update of xtime */
 	now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
-	return (unsigned long) now;
-}
-
-/*
- * This version of gettimeofday has microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
-	unsigned long flags;
-	unsigned long usec, sec;
-
-	read_lock_irqsave(&xtime_lock, flags);
-	sec = xtime.tv_sec;
-	usec = xtime.tv_usec + do_gettimeoffset();
-	read_unlock_irqrestore(&xtime_lock, flags);
-
-	while (usec >= 1000000) {
-		usec -= 1000000;
-		sec++;
-	}
-
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
-}
-
-void do_settimeofday(struct timeval *tv)
-{
-
-	write_lock_irq(&xtime_lock);
-	/* This is revolting. We need to set the xtime.tv_usec
-	 * correctly. However, the value in this location is
-	 * is value at the last tick.
-	 * Discover what correction gettimeofday
-	 * would have done, and then undo it!
-	 */
-	tv->tv_usec -= do_gettimeoffset();
-
-	while (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
-	}
-
-	xtime = *tv;
-	time_adjust = 0;		/* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
-	write_unlock_irq(&xtime_lock);
+	return (unsigned long) now * 1000;
 }
 
 static inline __u32 div64_32(__u64 dividend, __u32 divisor)
@@ -263,7 +222,8 @@
 	xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
         set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
                       (0x3c26700LL*1000000*4096);
-        tod_to_timeval(set_time_cc, &xtime);
+        tod_to_timespec(set_time_cc, &xtime);
+	timevar_init();
 
         /* request the 0x1004 external interrupt */
         if (register_early_external_interrupt(0x1004, NULL,
@@ -273,3 +233,11 @@
         /* init CPU timer */
         init_cpu_timer();
 }
+
+/* Fine-tune the tick interpolation for a total frequency error
+ * `freq' / 1000 PPM.
+ */
+void update_nanoscale(long freq)
+{
+	/* not implemented -- this is just a prototype [UW] */
+}
Index: linux/arch/s390x/kernel/time.c
diff -u linux/arch/s390x/kernel/time.c:1.1.1.8 linux/arch/s390x/kernel/time.c:1.1.1.8.2.1
--- linux/arch/s390x/kernel/time.c:1.1.1.8	Sat Jan 22 21:53:52 2005
+++ linux/arch/s390x/kernel/time.c	Mon Jan 24 21:04:44 2005
@@ -238,3 +238,11 @@
         /* init CPU timer */
         init_cpu_timer();
 }
+
+/* Fine-tune the tick interpolation for a total frequency error
+ * `freq' / 1000 PPM.
+ */
+void update_nanoscale(long freq)
+{
+	/* not implemented -- this is just a prototype [UW] */
+}
Index: linux/arch/sh/kernel/irq.c
diff -u linux/arch/sh/kernel/irq.c:1.1.1.6 linux/arch/sh/kernel/irq.c:1.1.1.6.2.1
--- linux/arch/sh/kernel/irq.c:1.1.1.6	Sat Jan 22 21:41:03 2005
+++ linux/arch/sh/kernel/irq.c	Mon Jan 24 21:04:47 2005
@@ -21,7 +21,7 @@
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/smp.h>
Index: linux/arch/sh/kernel/time.c
diff -u linux/arch/sh/kernel/time.c:1.1.1.5 linux/arch/sh/kernel/time.c:1.1.1.5.2.1
--- linux/arch/sh/kernel/time.c:1.1.1.5	Sat Jan 22 21:41:04 2005
+++ linux/arch/sh/kernel/time.c	Mon Jan 24 21:04:47 2005
@@ -34,7 +34,7 @@
 #include <asm/kgdb.h>
 #endif
 
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/irq.h>
 
 #define TMU_TOCR_INIT	0x00	/* Don't output RTC clock */
@@ -154,52 +154,12 @@
 
 void do_gettimeofday(struct timeval *tv)
 {
-	unsigned long flags;
-	unsigned long usec, sec;
-
-	read_lock_irqsave(&xtime_lock, flags);
-	usec = do_gettimeoffset();
-	{
-		unsigned long lost = jiffies - wall_jiffies;
-		if (lost)
-			usec += lost * (1000000 / HZ);
-	}
-	sec = xtime.tv_sec;
-	usec += xtime.tv_usec;
-	read_unlock_irqrestore(&xtime_lock, flags);
-
-	while (usec >= 1000000) {
-		usec -= 1000000;
-		sec++;
-	}
-
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
+	sys_gettimeofday(tv, NULL);
 }
 
 void do_settimeofday(struct timeval *tv)
 {
-	write_lock_irq(&xtime_lock);
-	/*
-	 * This is revolting. We need to set "xtime" correctly. However, the
-	 * value in this location is the value at the most recent update of
-	 * wall time.  Discover what correction gettimeofday() would have
-	 * made, and then undo it!
-	 */
-	tv->tv_usec -= do_gettimeoffset();
-	tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
-
-	while (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
-	}
-
-	xtime = *tv;
-	time_adjust = 0;		/* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
-	write_unlock_irq(&xtime_lock);
+	sys_settimeofday(tv, NULL);
 }
 
 /* last time the RTC clock got updated */
@@ -241,20 +201,18 @@
 	if (sh_mv.mv_heartbeat != NULL) 
 		sh_mv.mv_heartbeat();
 #endif
-
 	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
+	 * If we have a change of the software clock to be committed to the
+	 * CMOS clock, then do it. Update_rtc() has to be called as close as
+	 * possible to 500 ms before the new second starts.
 	 */
-	if ((time_status & STA_UNSYNC) == 0 &&
-	    xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
-	    xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
-		if (sh_mv.mv_rtc_settimeofday(&xtime) == 0)
-			last_rtc_update = xtime.tv_sec;
-		else
-			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	if (rtc_update_slave &&
+	    xtime.tv_sec >= last_rtc_update + rtc_update_slave &&
+	    xtime.tv_nsec >= NANOSECOND / 2 - ((unsigned long) time_tick) / 2 &&
+	    xtime.tv_nsec <= NANOSECOND / 2 + ((unsigned long) time_tick) / 2) {
+		update_rtc();
+		last_rtc_update = xtime.tv_sec;
+		rtc_update_slave = 0;
 	}
 }
 
@@ -573,3 +531,11 @@
 #endif
 
 }
+
+/* Fine-tune the tick interpolation for a total frequency error
+ * `freq' / 1000 PPM.
+ */
+void update_nanoscale(long freq)
+{
+	/* not implemented -- this is just a prototype [UW] */
+}
Index: linux/arch/sparc/config.in
diff -u linux/arch/sparc/config.in:1.1.1.10 linux/arch/sparc/config.in:1.1.1.10.2.1
--- linux/arch/sparc/config.in:1.1.1.10	Sat Jan 22 21:53:56 2005
+++ linux/arch/sparc/config.in	Mon Jan 24 21:04:51 2005
@@ -93,6 +93,13 @@
    source drivers/sbus/char/Config.in
    source drivers/sbus/audio/Config.in
 fi
+bool 'NTP kernel support' CONFIG_NTP
+if [ "$CONFIG_NTP" != "n" ]; then
+  bool '   NTP PPS support' CONFIG_NTP_PPS
+  if [ "$CONFIG_NTP_PPS" != "n" ]; then
+    bool '   Debug NTP PPS support' CONFIG_NTP_PPS_DEBUG
+  fi
+fi
 
 mainmenu_option next_comment
 comment 'Block devices'
Index: linux/arch/sparc/defconfig
diff -u linux/arch/sparc/defconfig:1.1.1.10 linux/arch/sparc/defconfig:1.1.1.10.2.1
--- linux/arch/sparc/defconfig:1.1.1.10	Sat Jan 22 21:53:56 2005
+++ linux/arch/sparc/defconfig	Mon Jan 24 21:04:51 2005
@@ -54,6 +54,10 @@
 CONFIG_BINFMT_MISC=m
 CONFIG_SUNOS_EMUL=y
 # CONFIG_OOM_KILLER is not set
+CONFIG_NTP=y
+# CONFIG_NTP_PPS is not set
+# CONFIG_NTP_PPS_DEBUG is not set
+# CONFIG_NTP_PPS_SERIAL is not set
 
 #
 # Parallel port support
Index: linux/arch/sparc/kernel/pcic.c
diff -u linux/arch/sparc/kernel/pcic.c:1.1.1.7 linux/arch/sparc/kernel/pcic.c:1.1.1.7.6.1
--- linux/arch/sparc/kernel/pcic.c:1.1.1.7	Sun Feb 23 18:38:30 2003
+++ linux/arch/sparc/kernel/pcic.c	Mon Jan 24 21:04:56 2005
@@ -24,7 +24,7 @@
 
 #include <linux/ctype.h>
 #include <linux/pci.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/interrupt.h>
 
 #include <asm/irq.h>
@@ -828,20 +828,10 @@
 	}       
 }
 
+/* is this needed at all? */
 static void pci_do_settimeofday(struct timeval *tv)
 {
-	cli();
-	tv->tv_usec -= do_gettimeoffset();
-	if(tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
-	}
-	xtime = *tv;
-	time_adjust = 0;		/* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
-	sti();
+	do_settimeofday(tv);
 }
 
 #if 0
Index: linux/arch/sparc/kernel/tick14.c
diff -u linux/arch/sparc/kernel/tick14.c:1.1.1.1 linux/arch/sparc/kernel/tick14.c:1.1.1.1.26.1
--- linux/arch/sparc/kernel/tick14.c:1.1.1.1	Thu Apr 24 04:01:16 1997
+++ linux/arch/sparc/kernel/tick14.c	Mon Jan 24 21:04:56 2005
@@ -15,11 +15,12 @@
 #include <linux/param.h>
 #include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 
 #include <asm/oplib.h>
 #include <asm/segment.h>
 #include <asm/timer.h>
+#include <asm/timex.h>
 #include <asm/mostek.h>
 #include <asm/system.h>
 #include <asm/irq.h>
Index: linux/arch/sparc/kernel/time.c
diff -u linux/arch/sparc/kernel/time.c:1.1.1.6 linux/arch/sparc/kernel/time.c:1.1.1.6.4.1
--- linux/arch/sparc/kernel/time.c:1.1.1.6	Fri Aug 15 22:26:04 2003
+++ linux/arch/sparc/kernel/time.c	Mon Jan 24 21:04:56 2005
@@ -12,18 +12,20 @@
  *
  * This file handles the Sparc specific time handling details.
  *
- * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
- *		"A Kernel Model for Precision Timekeeping" by Dave Mills
+ * 1999-03-10	Ulrich Windl
+ *	Updated for nanokernel resolution (untested)
+ * 1999-12-10	Ulrich Windl
+ *	Implement new logic with ``rtc_update_slave''.
+ *	Use new ``update_rtc()'' (untested).
  */
 #include <linux/config.h>
 #include <linux/errno.h>
-#include <linux/sched.h>
+#include <linux/time.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
@@ -41,13 +43,11 @@
 #include <asm/page.h>
 #include <asm/pcic.h>
 
-extern rwlock_t xtime_lock;
-
 enum sparc_clock_type sp_clock_typ;
 spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED;
 unsigned long mstk48t02_regs = 0UL;
 static struct mostek48t08 *mstk48t08_regs = 0;
-static int set_rtc_mmss(unsigned long);
+static void update_rtc(void);
 static void sbus_do_settimeofday(struct timeval *tv);
 
 #ifdef CONFIG_SUN4
@@ -138,14 +138,13 @@
 	do_timer(regs);
 
 	/* Determine when to update the Mostek clock. */
-	if ((time_status & STA_UNSYNC) == 0 &&
-	    xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
-	    xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
-	  if (set_rtc_mmss(xtime.tv_sec) == 0)
-	    last_rtc_update = xtime.tv_sec;
-	  else
-	    last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	if (rtc_update_slave &&
+	    xtime.tv_sec >= last_rtc_update + rtc_update_slave &&
+	    xtime.tv_nsec >= 500000000 - ((unsigned long) time_tick) / 2 &&
+	    xtime.tv_nsec <= 500000000 + ((unsigned long) time_tick) / 2) {
+		update_rtc();
+		last_rtc_update = xtime.tv_sec;
+		rtc_update_slave = 0;
 	}
 	write_unlock(&xtime_lock);
 }
@@ -371,6 +370,9 @@
 	struct intersil *iregs;
 #endif
 
+	do_microtime = do_exact_microtime;
+	do_nanotime = do_exact_nanotime;
+	timevar_init();		/* architecture independent initialization */
 	BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
 	btfixup();
 
@@ -398,7 +400,7 @@
 	mon = MSTK_REG_MONTH(mregs);
 	year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
 	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_usec = 0;
+	xtime.tv_nsec = 0;
 	mregs->creg &= ~MSTK_CREG_READ;
 	spin_unlock_irq(&mostek_lock);
 #ifdef CONFIG_SUN4
@@ -429,7 +431,7 @@
 		intersil_start(iregs);
 
 		xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-		xtime.tv_usec = 0;
+		xtime.tv_nsec = 0;
 		printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec);
 	}
 #endif
@@ -465,78 +467,25 @@
 	return offset + count;
 }
 
-/* This need not obtain the xtime_lock as it is coded in
- * an implicitly SMP safe way already.
- */
-void do_gettimeofday(struct timeval *tv)
+/* microseconds since last timer interrupt */
+static inline unsigned long do_exact_microtime(void)
 {
-	/* Load doubles must be used on xtime so that what we get
-	 * is guarenteed to be atomic, this is why we can run this
-	 * with interrupts on full blast.  Don't touch this... -DaveM
-	 */
-	__asm__ __volatile__(
-	"sethi	%hi(master_l10_counter), %o1\n\t"
-	"ld	[%o1 + %lo(master_l10_counter)], %g3\n\t"
-	"sethi	%hi(xtime), %g2\n"
-	"1:\n\t"
-	"ldd	[%g2 + %lo(xtime)], %o4\n\t"
-	"ld	[%g3], %o1\n\t"
-	"ldd	[%g2 + %lo(xtime)], %o2\n\t"
-	"xor	%o4, %o2, %o2\n\t"
-	"xor	%o5, %o3, %o3\n\t"
-	"orcc	%o2, %o3, %g0\n\t"
-	"bne	1b\n\t"
-	" cmp	%o1, 0\n\t"
-	"bge	1f\n\t"
-	" srl	%o1, 0xa, %o1\n\t"
-	"sethi	%hi(tick), %o3\n\t"
-	"ld	[%o3 + %lo(tick)], %o3\n\t"
-	"sethi	%hi(0x1fffff), %o2\n\t"
-	"or	%o2, %lo(0x1fffff), %o2\n\t"
-	"add	%o5, %o3, %o5\n\t"
-	"and	%o1, %o2, %o1\n"
-	"1:\n\t"
-	"add	%o5, %o1, %o5\n\t"
-	"sethi	%hi(1000000), %o2\n\t"
-	"or	%o2, %lo(1000000), %o2\n\t"
-	"cmp	%o5, %o2\n\t"
-	"bl,a	1f\n\t"
-	" st	%o4, [%o0 + 0x0]\n\t"
-	"add	%o4, 0x1, %o4\n\t"
-	"sub	%o5, %o2, %o5\n\t"
-	"st	%o4, [%o0 + 0x0]\n"
-	"1:\n\t"
-	"st	%o5, [%o0 + 0x4]\n");
-}
-
-void do_settimeofday(struct timeval *tv)
-{
-	write_lock_irq(&xtime_lock);
-	bus_do_settimeofday(tv);
-	write_unlock_irq(&xtime_lock);
-}
-
-static void sbus_do_settimeofday(struct timeval *tv)
-{
-	tv->tv_usec -= do_gettimeoffset();
-	if(tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
-	}
-	xtime = *tv;
-	time_adjust = 0;		/* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
+	return do_gettimeoffset();
+}
+
+/* nanoseconds since last timer interrupt */
+static inline unsigned long do_exact_nanotime(void)
+{
+	return do_exact_microtime() * 1000;
 }
 
 /*
- * BUG: This routine does not handle hour overflow properly; it just
- *      sets the minutes. Usually you won't notice until after reboot!
+ * Update the RTC from kernel time
  */
-static int set_rtc_mmss(unsigned long nowtime)
+static void update_rtc(void)
 {
-	int real_seconds, real_minutes, mostek_minutes;
+	int ss, mi, hh, dd, mo, yy;
+	unsigned char save_control, save_freq_select;
 	struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
 	unsigned long flags;
 #ifdef CONFIG_SUN4
@@ -547,32 +496,30 @@
 	/* Not having a register set can lead to trouble. */
 	if (!regs) {
 #ifdef CONFIG_SUN4
-		if(!iregs)
-		return -1;
+		if (!iregs)
+			return -1;
 	 	else {
 			temp = iregs->clk.int_csec;
 
-			mostek_minutes = iregs->clk.int_min;
-
-			real_seconds = nowtime % 60;
-			real_minutes = nowtime / 60;
-			if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
-				real_minutes += 30;	/* correct for half hour time zone */
-			real_minutes %= 60;
-
-			if (abs(real_minutes - mostek_minutes) < 30) {
-				intersil_stop(iregs);
-				iregs->clk.int_sec=real_seconds;
-				iregs->clk.int_min=real_minutes;
-				intersil_start(iregs);
-			} else {
-				printk(KERN_WARNING
-			       "set_rtc_mmss: can't update from %d to %d\n",
-				       mostek_minutes, real_minutes);
-				return -1;
-			}
-			
-			return 0;
+			ktime_to_rtc(xtime.tv_sec, &ss, &dd);
+			hh = ss >> 16;
+			mi = (ss >> 8) & 0xff;
+			ss &= 0xff;
+			yy = (dd >> 16) % 100;
+			mo = (dd >> 8) & 0xff;
+			dd &= 0xff;
+			printk(KERN_DEBUG
+			       "update_rtc: %d-%02d-%02d %02d:%02d:%02d\n",
+			       yy, mo, dd, hh, mi, ss);
+
+			intersil_stop(iregs);
+			iregs->clk.int_sec = ss;
+			iregs->clk.int_min = mi;
+			iregs->clk.int_hour = hh;
+			iregs->clk.int_dom = dd;
+			iregs->clk.int_month = mo;
+			iregs->clk.int_year = yy;
+			intersil_start(iregs);
 		}
 #endif
 	}
@@ -607,3 +554,11 @@
 		return -1;
 	}
 }
+
+/* Fine-tune the tick interpolation for a total frequency error
+ * `freq' / 1000 PPM.
+ */
+void update_nanoscale(long freq)
+{
+	/* not implemented -- this is just a prototype [UW] */
+}
Index: linux/arch/sparc64/config.in
diff -u linux/arch/sparc64/config.in:1.1.1.13 linux/arch/sparc64/config.in:1.1.1.13.2.1
--- linux/arch/sparc64/config.in:1.1.1.13	Sat Jan 22 21:53:58 2005
+++ linux/arch/sparc64/config.in	Mon Jan 24 21:04:59 2005
@@ -125,6 +125,13 @@
 if [ "$CONFIG_NET" = "y" ]; then
    source net/Config.in
 fi
+bool 'NTP kernel support' CONFIG_NTP
+if [ "$CONFIG_NTP" != "n" ]; then
+  bool '   NTP PPS support' CONFIG_NTP_PPS
+  if [ "$CONFIG_NTP_PPS" != "n" ]; then
+    bool '   Debug NTP PPS support' CONFIG_NTP_PPS_DEBUG
+  fi
+fi
 
 mainmenu_option next_comment
 comment 'ATA/IDE/MFM/RLL support'
Index: linux/arch/sparc64/defconfig
diff -u linux/arch/sparc64/defconfig:1.1.1.16 linux/arch/sparc64/defconfig:1.1.1.16.2.1
--- linux/arch/sparc64/defconfig:1.1.1.16	Sat Jan 22 22:03:09 2005
+++ linux/arch/sparc64/defconfig	Mon Jan 24 21:04:59 2005
@@ -74,6 +74,10 @@
 # CONFIG_SUNOS_EMUL is not set
 CONFIG_SOLARIS_EMUL=m
 # CONFIG_OOM_KILLER is not set
+CONFIG_NTP=y
+# CONFIG_NTP_PPS is not set
+# CONFIG_NTP_PPS_DEBUG is not set
+# CONFIG_NTP_PPS_SERIAL is not set
 
 #
 # Parallel port support
Index: linux/arch/sparc64/kernel/sys_sparc32.c
diff -u linux/arch/sparc64/kernel/sys_sparc32.c:1.1.1.15 linux/arch/sparc64/kernel/sys_sparc32.c:1.1.1.15.2.1
--- linux/arch/sparc64/kernel/sys_sparc32.c:1.1.1.15	Sat Jan 22 22:03:11 2005
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Mon Jan 24 21:05:03 2005
@@ -19,7 +19,7 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/utsname.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/sem.h>
Index: linux/arch/sparc64/kernel/time.c
diff -u linux/arch/sparc64/kernel/time.c:1.1.1.12 linux/arch/sparc64/kernel/time.c:1.1.1.12.2.1
--- linux/arch/sparc64/kernel/time.c:1.1.1.12	Sat Jan 22 21:54:01 2005
+++ linux/arch/sparc64/kernel/time.c	Mon Jan 24 21:05:03 2005
@@ -7,17 +7,24 @@
  * Based largely on code which is:
  *
  * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ * 1999-03-10	Ulrich Windl
+ *	Updated for nanokernel resolution (untested)
+ * 1999-12-10	Ulrich Windl
+ *	Implement new logic with ``rtc_update_slave''.
+ *	Use new ``rtc_update()'' (untested).
+ * 2000-12-09	Ulrich Windl
+ *	Remove traditional code for microseconds as the nanoseconds seem
+ *	stable.
  */
 
 #include <linux/config.h>
 #include <linux/errno.h>
-#include <linux/sched.h>
+#include <linux/time.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/mc146818rtc.h>
@@ -50,7 +57,7 @@
 static unsigned long mstk48t08_regs = 0UL;
 static unsigned long mstk48t59_regs = 0UL;
 
-static int set_rtc_mmss(unsigned long);
+static void update_rtc(void);
 
 struct sparc64_tick_ops *tick_ops;
 
@@ -414,15 +421,13 @@
 	static long last_rtc_update;
 
 	/* Determine when to update the Mostek clock. */
-	if ((time_status & STA_UNSYNC) == 0 &&
-	    xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
-	    xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
-		if (set_rtc_mmss(xtime.tv_sec) == 0)
-			last_rtc_update = xtime.tv_sec;
-		else
-			last_rtc_update = xtime.tv_sec - 600;
-			/* do it again in 60 s */
+	if (rtc_update_slave &&
+	    xtime.tv_sec >= last_rtc_update + rtc_update_slave &&
+	    xtime.tv_nsec >= 500000000 - ((unsigned long) tick) / 2 &&
+	    xtime.tv_nsec <= 500000000 + ((unsigned long) tick) / 2) {
+		update_rtc();
+		last_rtc_update = xtime.tv_sec;
+		rtc_update_slave = 0;
 	}
 }
 
@@ -684,7 +689,7 @@
 	}
 
 	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_usec = 0;
+	xtime.tv_nsec = 0;
 
 	if (mregs) {
 		tmp = mostek_read(mregs + MOSTEK_CREG);
@@ -976,11 +981,19 @@
 	return clock;
 }
 
+/* nanoseconds since last timer interrupt */
+static inline unsigned long do_exact_nanotime(void)
+{
+	return do_gettimeoffset() * 1000;	/* please fix it! -- UW */
+}
+
 /* The quotient formula is taken from the IA64 port. */
 void __init time_init(void)
 {
 	unsigned long clock = sparc64_init_timers(timer_interrupt);
 
+	do_nanotime = do_exact_nanotime;
+	timevar_init();		/* architecture independent initialization */
 	timer_ticks_per_usec_quotient =
 		(((1000000UL << 30) +
 		  (clock / 2)) / clock);
@@ -996,29 +1009,6 @@
 	return (ticks * timer_ticks_per_usec_quotient) >> 30UL;
 }
 
-void do_settimeofday(struct timeval *tv)
-{
-	if (this_is_starfire)
-		return;
-
-	write_lock_irq(&xtime_lock);
-
-	tv->tv_usec -= do_gettimeoffset();
-	tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
-
-	while (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
-	}
-
-	xtime = *tv;
-	time_adjust = 0;		/* stop active adjtime() */
-	time_status |= STA_UNSYNC;
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_esterror = NTP_PHASE_LIMIT;
-
-	write_unlock_irq(&xtime_lock);
-}
 
 void do_gettimeofday(struct timeval *tv)
 {
@@ -1045,9 +1035,9 @@
 	tv->tv_usec = usec;
 }
 
-static int set_rtc_mmss(unsigned long nowtime)
+static void update_rtc(void)
 {
-	int real_seconds, real_minutes, chip_minutes;
+	int ss, mi, hh, dd, mo, yy;
 	unsigned long mregs = mstk48t02_regs;
 #ifdef CONFIG_PCI
 	unsigned long dregs = ds1287_regs;
@@ -1062,95 +1052,35 @@
 	 * Also starfire doesn't have a tod clock.
 	 */
 	if (!mregs && !dregs) 
-		return -1;
+		return;
 
+	ktime_to_rtc(xtime.tv_sec, &ss, &dd);
+	hh = ss >> 16;
+	mi = (ss >> 8) & 0xff;
+	ss &= 0xff;
+	yy = (dd >> 16) % 100;
+	mo = (dd >> 8) & 0xff;
+	dd &= 0xff;
+	printk(KERN_DEBUG "update_rtc: %d-%02d-%02d %02d:%02d:%02d\n",
+	       yy, mo, dd, hh, mi, ss);
 	if (mregs) {
 		spin_lock_irqsave(&mostek_lock, flags);
-
-		/* Read the current RTC minutes. */
-		tmp = mostek_read(mregs + MOSTEK_CREG);
-		tmp |= MSTK_CREG_READ;
-		mostek_write(mregs + MOSTEK_CREG, tmp);
-
-		chip_minutes = MSTK_REG_MIN(mregs);
-
-		tmp = mostek_read(mregs + MOSTEK_CREG);
-		tmp &= ~MSTK_CREG_READ;
-		mostek_write(mregs + MOSTEK_CREG, tmp);
-
-		/*
-		 * since we're only adjusting minutes and seconds,
-		 * don't interfere with hour overflow. This avoids
-		 * messing with unknown time zones but requires your
-		 * RTC not to be off by more than 15 minutes
-		 */
-		real_seconds = nowtime % 60;
-		real_minutes = nowtime / 60;
-		if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
-			real_minutes += 30;	/* correct for half hour time zone */
-		real_minutes %= 60;
-
-		if (abs(real_minutes - chip_minutes) < 30) {
-			tmp = mostek_read(mregs + MOSTEK_CREG);
-			tmp |= MSTK_CREG_WRITE;
-			mostek_write(mregs + MOSTEK_CREG, tmp);
-
-			MSTK_SET_REG_SEC(mregs,real_seconds);
-			MSTK_SET_REG_MIN(mregs,real_minutes);
-
-			tmp = mostek_read(mregs + MOSTEK_CREG);
-			tmp &= ~MSTK_CREG_WRITE;
-			mostek_write(mregs + MOSTEK_CREG, tmp);
-
-			spin_unlock_irqrestore(&mostek_lock, flags);
-
-			return 0;
-		} else {
-			spin_unlock_irqrestore(&mostek_lock, flags);
-
-			return -1;
-		}
-	} else {
-		int retval = 0;
-		unsigned char save_control, save_freq_select;
-
-		/* Stolen from arch/i386/kernel/time.c, see there for
-		 * credits and descriptive comments.
-		 */
-		spin_lock_irqsave(&rtc_lock, flags);
-		save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
-		CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-
-		save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
-		CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-		chip_minutes = CMOS_READ(RTC_MINUTES);
-		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-			BCD_TO_BIN(chip_minutes);
-		real_seconds = nowtime % 60;
-		real_minutes = nowtime / 60;
-		if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
-			real_minutes += 30;
-		real_minutes %= 60;
-
-		if (abs(real_minutes - chip_minutes) < 30) {
-			if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-				BIN_TO_BCD(real_seconds);
-				BIN_TO_BCD(real_minutes);
-			}
-			CMOS_WRITE(real_seconds,RTC_SECONDS);
-			CMOS_WRITE(real_minutes,RTC_MINUTES);
-		} else {
-			printk(KERN_WARNING
-			       "set_rtc_mmss: can't update from %d to %d\n",
-			       chip_minutes, real_minutes);
-			retval = -1;
-		}
-
-		CMOS_WRITE(save_control, RTC_CONTROL);
-		CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-		spin_unlock_irqrestore(&rtc_lock, flags);
-
-		return retval;
+		regs->creg |= MSTK_CREG_WRITE;
+		MSTK_SET_REG_SEC(regs, ss);
+		MSTK_SET_REG_MIN(regs, mi);
+		MSTK_SET_REG_HOUR(regs, hh);
+		MSTK_SET_REG_DOM(regs, dd);
+		MSTK_SET_REG_MONTH(regs, mo);
+		MSTK_SET_REG_YEAR(regs, yy);
+		regs->creg &= ~MSTK_CREG_WRITE;
+		spin_unlock_irqrestore(&mostek_lock, flags);
 	}
 }
+
+/* Fine-tune the tick interpolation for a total frequency error
+ * `freq' / 1000 PPM.
+ */
+void update_nanoscale(long freq)
+{
+	/* not implemented -- this is just a prototype [UW] */
+}
Index: linux/arch/sparc64/solaris/misc.c
diff -u linux/arch/sparc64/solaris/misc.c:1.1.1.6 linux/arch/sparc64/solaris/misc.c:1.1.1.6.6.1
--- linux/arch/sparc64/solaris/misc.c:1.1.1.6	Sun Feb 23 18:38:35 2003
+++ linux/arch/sparc64/solaris/misc.c	Mon Jan 24 21:05:07 2005
@@ -14,7 +14,7 @@
 #include <linux/smp.h>
 #include <linux/mman.h>
 #include <linux/file.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 
 #include <asm/uaccess.h>
 #include <asm/string.h>
Index: linux/drivers/acorn/char/i2c.c
diff -u linux/drivers/acorn/char/i2c.c:1.1.1.4 linux/drivers/acorn/char/i2c.c:1.1.1.4.2.1
--- linux/drivers/acorn/char/i2c.c:1.1.1.4	Sat Jan 22 21:54:31 2005
+++ linux/drivers/acorn/char/i2c.c	Mon Jan 24 21:05:11 2005
@@ -132,7 +132,7 @@
 	if (rtc_command(RTC_GETDATETIME, &old_rtctm))
 		return 0;
 
-	new_rtctm.cs    = xtime.tv_usec / 10000;
+	new_rtctm.cs    = xtime.tv_nsec / 10000000;
 	new_rtctm.secs  = nowtime % 60;	nowtime /= 60;
 	new_rtctm.mins  = nowtime % 60;	nowtime /= 60;
 	new_rtctm.hours = nowtime % 24;
@@ -284,7 +284,7 @@
 		rtc_client = client;
 		get_rtc_time(&rtctm, &year);
 
-		xtime.tv_usec = rtctm.cs * 10000;
+		xtime.tv_nsec = rtctm.cs * 10000000;
 		xtime.tv_sec  = mktime(year, rtctm.mon, rtctm.mday,
 				       rtctm.hours, rtctm.mins, rtctm.secs);
 		set_rtc = k_set_rtc_time;
Index: linux/drivers/atm/ambassador.c
diff -u linux/drivers/atm/ambassador.c:1.1.1.6 linux/drivers/atm/ambassador.c:1.1.1.6.2.1
--- linux/drivers/atm/ambassador.c:1.1.1.6	Sat Jan 22 21:41:37 2005
+++ linux/drivers/atm/ambassador.c	Mon Jan 24 21:05:19 2005
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/time.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -515,7 +516,7 @@
 	  
 	  // VC layer stats
 	  atomic_inc(&atm_vcc->stats->rx);
-	  skb->stamp = xtime;
+	  do_gettimeofday(&skb->stamp);
 	  // end of our responsability
 	  atm_vcc->push (atm_vcc, skb);
 	  return;
Index: linux/drivers/atm/atmtcp.c
diff -u linux/drivers/atm/atmtcp.c:1.1.1.6 linux/drivers/atm/atmtcp.c:1.1.1.6.2.1
--- linux/drivers/atm/atmtcp.c:1.1.1.6	Sat Jan 22 21:54:33 2005
+++ linux/drivers/atm/atmtcp.c	Mon Jan 24 21:05:19 2005
@@ -8,6 +8,7 @@
 #include <linux/atmdev.h>
 #include <linux/atm_tcp.h>
 #include <linux/bitops.h>
+#include <linux/time.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
 
@@ -299,7 +300,7 @@
 		result = -ENOBUFS;
 		goto done;
 	}
-	new_skb->stamp = xtime;
+	do_gettimeofday(&new_skb->stamp);
 	memcpy(skb_put(new_skb,skb->len),skb->data,skb->len);
 	out_vcc->push(out_vcc,new_skb);
 	atomic_inc(&vcc->stats->tx);
Index: linux/drivers/atm/eni.c
diff -u linux/drivers/atm/eni.c:1.1.1.7 linux/drivers/atm/eni.c:1.1.1.7.2.1
--- linux/drivers/atm/eni.c:1.1.1.7	Sat Jan 22 21:54:33 2005
+++ linux/drivers/atm/eni.c	Mon Jan 24 21:05:19 2005
@@ -14,7 +14,6 @@
 #include <linux/sonet.h>
 #include <linux/skbuff.h>
 #include <linux/time.h>
-#include <linux/sched.h> /* for xtime */
 #include <linux/delay.h>
 #include <linux/uio.h>
 #include <linux/init.h>
@@ -703,7 +702,7 @@
 			DPRINTK("Grr, servicing VCC %ld twice\n",vci);
 			continue;
 		}
-		ENI_VCC(vcc)->timestamp = xtime;
+		do_gettimeofday(&ENI_VCC(vcc)->timestamp);
 		ENI_VCC(vcc)->next = NULL;
 		if (vcc->qos.rxtp.traffic_class == ATM_CBR) {
 			if (eni_dev->fast)
Index: linux/drivers/atm/fore200e.c
diff -u linux/drivers/atm/fore200e.c:1.1.1.9 linux/drivers/atm/fore200e.c:1.1.1.9.2.1
--- linux/drivers/atm/fore200e.c:1.1.1.9	Sat Jan 22 21:54:33 2005
+++ linux/drivers/atm/fore200e.c	Mon Jan 24 21:05:19 2005
@@ -1206,7 +1206,7 @@
 	return -ENOMEM;
     } 
 
-    skb->stamp = xtime;
+    do_gettimeofday(&skb->stamp);
     
 #ifdef FORE200E_52BYTE_AAL0_SDU
     if (cell_header) {
Index: linux/drivers/atm/horizon.c
diff -u linux/drivers/atm/horizon.c:1.1.1.6 linux/drivers/atm/horizon.c:1.1.1.6.2.1
--- linux/drivers/atm/horizon.c:1.1.1.6	Sat Jan 22 21:54:33 2005
+++ linux/drivers/atm/horizon.c	Mon Jan 24 21:05:19 2005
@@ -1049,7 +1049,7 @@
 	  struct atm_vcc * vcc = ATM_SKB(skb)->vcc;
 	  // VC layer stats
 	  atomic_inc(&vcc->stats->rx);
-	  skb->stamp = xtime;
+	  do_gettimeofday(&skb->stamp);
 	  // end of our responsability
 	  vcc->push (vcc, skb);
 	}
Index: linux/drivers/atm/iphase.c
diff -u linux/drivers/atm/iphase.c:1.1.1.10 linux/drivers/atm/iphase.c:1.1.1.10.2.1
--- linux/drivers/atm/iphase.c:1.1.1.10	Sat Jan 22 21:54:34 2005
+++ linux/drivers/atm/iphase.c	Mon Jan 24 21:05:19 2005
@@ -54,7 +54,6 @@
 #include <linux/sonet.h>  
 #include <linux/skbuff.h>  
 #include <linux/time.h>  
-#include <linux/sched.h> /* for xtime */  
 #include <linux/delay.h>  
 #include <linux/uio.h>  
 #include <linux/init.h>  
Index: linux/drivers/atm/nicstar.c
diff -u linux/drivers/atm/nicstar.c:1.1.1.9 linux/drivers/atm/nicstar.c:1.1.1.9.2.1
--- linux/drivers/atm/nicstar.c:1.1.1.9	Sat Jan 22 21:54:34 2005
+++ linux/drivers/atm/nicstar.c	Mon Jan 24 21:05:20 2005
@@ -2191,7 +2191,7 @@
          memcpy(sb->tail, cell, ATM_CELL_PAYLOAD);
          skb_put(sb, ATM_CELL_PAYLOAD);
          ATM_SKB(sb)->vcc = vcc;
-         sb->stamp = xtime;
+         do_gettimeofday(&sb->stamp);
          vcc->push(vcc, sb);
          atomic_inc(&vcc->stats->rx);
          cell += ATM_CELL_PAYLOAD;
@@ -2323,7 +2323,7 @@
             skb->destructor = ns_sb_destructor;
 #endif /* NS_USE_DESTRUCTORS */
             ATM_SKB(skb)->vcc = vcc;
-            skb->stamp = xtime;
+            do_gettimeofday(&skb->stamp);
             vcc->push(vcc, skb);
             atomic_inc(&vcc->stats->rx);
          }
@@ -2351,7 +2351,7 @@
                sb->destructor = ns_sb_destructor;
 #endif /* NS_USE_DESTRUCTORS */
                ATM_SKB(sb)->vcc = vcc;
-               sb->stamp = xtime;
+               do_gettimeofday(&sb->stamp);
                vcc->push(vcc, sb);
                atomic_inc(&vcc->stats->rx);
             }
@@ -2378,7 +2378,7 @@
                memcpy(skb->data, sb->data, NS_SMBUFSIZE);
                skb_put(skb, len - NS_SMBUFSIZE);
                ATM_SKB(skb)->vcc = vcc;
-               skb->stamp = xtime;
+               do_gettimeofday(&skb->stamp);
                vcc->push(vcc, skb);
                atomic_inc(&vcc->stats->rx);
             }
@@ -2485,7 +2485,7 @@
 #ifdef NS_USE_DESTRUCTORS
             hb->destructor = ns_hb_destructor;
 #endif /* NS_USE_DESTRUCTORS */
-            hb->stamp = xtime;
+            do_gettimeofday(&hb->stamp);
             vcc->push(vcc, hb);
             atomic_inc(&vcc->stats->rx);
          }
Index: linux/drivers/atm/zatm.c
diff -u linux/drivers/atm/zatm.c:1.1.1.5 linux/drivers/atm/zatm.c:1.1.1.5.2.1
--- linux/drivers/atm/zatm.c:1.1.1.5	Sat Jan 22 21:54:35 2005
+++ linux/drivers/atm/zatm.c	Mon Jan 24 21:05:20 2005
@@ -584,7 +584,7 @@
 #ifdef CONFIG_ATM_ZATM_EXACT_TS
 		skb->stamp = exact_time(zatm_dev,here[1]);
 #else
-		skb->stamp = xtime;
+		do_gettimeofday(&skb->stamp);
 #endif
 #if 0
 printk("[-3..0] 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",((unsigned *) skb->data)[-3],
Index: linux/drivers/char/Config.in
diff -u linux/drivers/char/Config.in:1.1.1.15 linux/drivers/char/Config.in:1.1.1.15.2.1
--- linux/drivers/char/Config.in:1.1.1.15	Sat Jan 22 21:54:39 2005
+++ linux/drivers/char/Config.in	Mon Jan 24 21:05:26 2005
@@ -25,6 +25,13 @@
       tristate '   Dual serial port support' CONFIG_DUALSP_SERIAL
    fi
 fi
+if [ "$CONFIG_SERIAL" != "n" ]; then
+   if [ "$CONFIG_NTP" = "y" -a "$CONFIG_NTP_PPS" = "y" ]; then
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 bool '   NTP PPS support on serial port' CONFIG_NTP_PPS_SERIAL
+      fi
+   fi
+fi
 dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL
 if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
    bool '  Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
Index: linux/drivers/char/n_tty.c
diff -u linux/drivers/char/n_tty.c:1.1.1.7 linux/drivers/char/n_tty.c:1.1.1.7.2.1
--- linux/drivers/char/n_tty.c:1.1.1.7	Sat Jan 22 22:03:52 2005
+++ linux/drivers/char/n_tty.c	Mon Jan 24 21:05:26 2005
@@ -1498,3 +1498,28 @@
 	n_tty_write_wakeup	/* write_wakeup */
 };
 
+#ifdef	CONFIG_NTP_PPS
+	/* OK, I found this too late: That hack is most likely wrong, but
+	 * it should be better than the previous versions. XXX FIXME!
+	 * (Any help appreciated -- U. Windl)
+	 */
+struct tty_ldisc tty_ldisc_N_PPSCLOCK = {
+	TTY_LDISC_MAGIC,	/* magic */
+	"n_PPSclock",		/* name */
+	0,			/* num */
+	0,			/* flags */
+	n_tty_open,		/* open */
+	n_tty_close,		/* close */
+	n_tty_flush_buffer,	/* flush_buffer */
+	n_tty_chars_in_buffer,	/* chars_in_buffer */
+	read_chan,		/* read */
+	write_chan,		/* write */
+	n_tty_ioctl,		/* ioctl */
+	n_tty_set_termios,	/* set_termios */
+	normal_poll,		/* poll */
+	NULL,			/* hangup */
+	n_tty_receive_buf,	/* receive_buf */
+	n_tty_receive_room,	/* receive_room */
+	n_tty_write_wakeup	/* write_wakeup */
+};
+#endif
Index: linux/drivers/char/serial.c
diff -u linux/drivers/char/serial.c:1.1.1.17 linux/drivers/char/serial.c:1.1.1.17.2.1
--- linux/drivers/char/serial.c:1.1.1.17	Sat Jan 22 22:03:55 2005
+++ linux/drivers/char/serial.c	Mon Jan 24 21:05:27 2005
@@ -39,6 +39,9 @@
  *
  *  8/99: Generalized PCI support added.  Theodore Ts'o
  * 
+ *  12/99: Additions for NTP PPS pulse on CD by Ulrich Windl (with
+ *	  contributions by H. P. Anvin).  Revised PPS API (1999-08-17)
+ *
  *  3/00: Rid circular buffer of redundant xmit_cnt.  Fix a
  *	  few races on freeing buffers too.
  *	  Alan Modra <alan@linuxcare.com>
@@ -57,6 +60,11 @@
  * 10/00: add in optional software flow control for serial console.
  *	  Kanoj Sarcar <kanoj@sgi.com>  (Modified by Theodore Ts'o)
  *
+ * 12/00: Updated PPS API for Linux 2.4.0
+ *	  Ulrich Windl
+ * 04/01: Updated to support different devices for PPS API's ``kernel
+ *	  consumer''
+ *	  Ulrich Windl
  * 02/02: Fix for AMD Elan bug in transmit irq routine, by
  *        Christer Weinigel <wingel@hog.ctrl-c.liu.se>,
  *        Robert Schwebel <robert@schwebel.de>,
@@ -64,7 +72,7 @@
  *        Theodore Ts'o <tytso@mit.edu>
  */
 
-static char *serial_version = "5.05c";
+static char *serial_version = "5.05c+";
 static char *serial_revdate = "2001-07-08";
 
 /*
@@ -141,6 +149,7 @@
 #undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 #undef SERIAL_DEBUG_PCI
 #undef SERIAL_DEBUG_AUTOCONF
+#undef SERIAL_DEBUG_NTP_PPS
 
 /* Sanity checks */
 
@@ -236,6 +245,13 @@
 #include <asm/irq.h>
 #include <asm/bitops.h>
 
+#ifdef	CONFIG_NTP_PPS_SERIAL
+#include <linux/time.h> 	/* struct timeval, do_gettimeofday(),
+				   hardpps() */
+#include <linux/timepps.h>	/* PPS API */
+#include <linux/slab.h>		/* kmalloc(), kfree() */
+#endif
+
 #if defined(CONFIG_MAC_SERIAL)
 #define SERIAL_DEV_OFFSET	((_machine == _MACH_prep || _machine == _MACH_chrp) ? 0 : 2)
 #else
@@ -735,6 +751,98 @@
 	}
 }
 
+#ifdef	CONFIG_NTP_PPS_SERIAL
+#define NANOSECOND	1000000000
+
+/* update PPS info from the event time stamp stored in etime and ecount. */
+static inline void pps_update_event(struct async_struct *info,
+				    int modem_status)
+{
+	struct tty_struct const	*const tty	= info->tty;
+	struct pps	*pp;
+	int mode;
+
+	if ((pp = (struct pps *) tty->disc_data) == NULL
+	    || pp->magic != PPSCLOCK_MAGIC) {
+#ifdef SERIAL_DEBUG_NTP_PPS
+		printk(KERN_ERR
+		       "pps_update_event(): illegal disc_data for info %p\n",
+		       info);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+		return;
+	}
+	mode = pp->state.parm.mode;
+	if ((mode & (PPS_ECHOASSERT|PPS_ECHOCLEAR)) != 0) {
+		/* echo event via cleared RTS bit */
+		info->MCR |= UART_MCR_RTS;		/* signal no event */
+		if (((modem_status & UART_MSR_DCD) != 0) ==
+		    ((mode & PPS_ECHOASSERT) != 0))
+			info->MCR &= ~UART_MCR_RTS;	/* signal event */
+		serial_out(info, UART_MCR, info->MCR);
+	}
+	if ((modem_status & UART_MSR_DCD) != 0)	{
+		struct timespec ts;
+		ts = pp->state.etime;
+		pp->state.info.current_mode = mode;
+		if ((mode & PPS_OFFSETASSERT) != 0) {
+			ts.tv_nsec += pp->state.parm.assert_offset.tv_nsec;
+			if (ts.tv_nsec >= NANOSECOND) {
+				ts.tv_nsec -= NANOSECOND;
+				++ts.tv_sec;
+			} else if (ts.tv_nsec < 0) {
+				ts.tv_nsec += NANOSECOND;
+				--ts.tv_sec;
+			}
+		}
+		if ((pps_kc_hardpps_mode & PPS_CAPTUREASSERT) != 0 &&
+		    pps_kc_hardpps_dev == (void *) tty)
+			hardpps(&ts, pp->state.ecount);
+		if ((mode & PPS_CAPTUREASSERT) != 0) {
+			pp->state.info.assert_timestamp = ts;
+			++pp->state.info.assert_sequence;
+			if (waitqueue_active(&pp->state.ewait))
+				wake_up_interruptible(&pp->state.ewait);
+		}
+#ifdef SERIAL_DEBUG_NTP_PPS
+		printk(KERN_DEBUG
+		       "ASSERT event #%lu for %p at %lu.%09ld (%9ld)\n",
+		       pp->state.info.assert_sequence, pp, ts.tv_sec,
+		       ts.tv_nsec, pp->state.ecount);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+	} else {
+		struct timespec ts;
+		ts = pp->state.etime;
+		pp->state.info.current_mode = mode;
+		if ((mode & PPS_OFFSETCLEAR) != 0) {
+			ts.tv_nsec += pp->state.parm.clear_offset.tv_nsec;
+			if (ts.tv_nsec >= NANOSECOND) {
+				ts.tv_nsec -= NANOSECOND;
+				++ts.tv_sec;
+			} else if (ts.tv_nsec < 0) {
+				ts.tv_nsec += NANOSECOND;
+				--ts.tv_sec;
+			}
+		}
+		if ((pps_kc_hardpps_mode & PPS_CAPTURECLEAR) != 0 &&
+		    pps_kc_hardpps_dev == (void *) tty)
+			hardpps(&ts, pp->state.ecount);
+		if ((mode & PPS_CAPTURECLEAR) != 0) {
+			pp->state.info.clear_timestamp = ts;
+			++pp->state.info.clear_sequence;
+			if (waitqueue_active(&pp->state.ewait))
+				wake_up_interruptible(&pp->state.ewait);
+		}
+#ifdef SERIAL_DEBUG_NTP_PPS
+		printk(KERN_DEBUG
+		       "CLEAR event #%lu for %p at %lu.%09ld (%9ld)\n",
+		       pp->state.info.clear_sequence, pp, ts.tv_sec,
+		       ts.tv_nsec, pp->state.ecount);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+	}
+#undef NANOSECOND
+}
+#endif
+
 static _INLINE_ void check_modem_status(struct async_struct *info)
 {
 	int	status;
@@ -750,12 +858,14 @@
 		if (status & UART_MSR_DDSR)
 			icount->dsr++;
 		if (status & UART_MSR_DDCD) {
+#ifdef CONFIG_NTP_PPS_SERIAL
+			struct pps *pp = (struct pps *) info->tty->disc_data;
+				
+			if (pp != NULL && pp->magic == PPSCLOCK_MAGIC) {
+				pps_update_event(info, status);
+			}
+#endif /* CONFIG_NTP_PPS_SERIAL */
 			icount->dcd++;
-#ifdef CONFIG_HARD_PPS
-			if ((info->flags & ASYNC_HARDPPS_CD) &&
-			    (status & UART_MSR_DCD))
-				hardpps();
-#endif
 		}
 		if (status & UART_MSR_DCTS)
 			icount->cts++;
@@ -842,6 +952,24 @@
 #ifdef SERIAL_DEBUG_INTR
 		printk("IIR = %x...", serial_in(info, UART_IIR));
 #endif
+#ifdef CONFIG_NTP_PPS_SERIAL
+		{	/* store timestamp in case it is wanted later */
+			struct pps *pp = (struct pps *) info->tty->disc_data;
+				
+			if (pp != NULL && pp->magic == PPSCLOCK_MAGIC) {
+				pp->state.ecount =
+				do_clock_gettime(CLOCK_REALTIME,
+						 &pp->state.etime);
+#ifdef SERIAL_DEBUG_NTP_PPS
+				printk(KERN_DEBUG
+				       "rs_interrupt: time %ld:%ld(%ld)\n",
+				       pp->state.etime.tv_sec,
+				       pp->state.etime.tv_nsec,
+				       pp->state.ecount);
+#endif
+			}
+		}
+#endif /* CONFIG_NTP_PPS_SERIAL */
 		end_mark = 0;
 
 		info->last_active = jiffies;
@@ -910,6 +1038,23 @@
 	if (!info || !info->tty)
 		return;
 
+#ifdef CONFIG_NTP_PPS_SERIAL
+	{	/* store timestamp in case it is wanted later */
+		struct pps *pp = (struct pps *) info->tty->disc_data;
+
+		if (pp != NULL && pp->magic == PPSCLOCK_MAGIC) {
+			pp->state.ecount = do_clock_gettime(CLOCK_REALTIME,
+							    &pp->state.etime);
+#ifdef SERIAL_DEBUG_NTP_PPS
+				printk(KERN_DEBUG
+				       "rs_interrupt_single: time %ld:%ld(%ld)\n",
+				       pp->state.etime.tv_sec,
+				       pp->state.etime.tv_nsec,
+				       pp->state.ecount);
+#endif
+		}
+	}
+#endif /* CONFIG_NTP_PPS_SERIAL */
 #ifdef CONFIG_SERIAL_MULTIPORT	
 	multi = &rs_multiport[irq];
 	if (multi->port_monitor)
@@ -989,6 +1134,24 @@
 		if (!info->tty ||
 		    (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
 			goto next;
+#ifdef CONFIG_NTP_PPS_SERIAL
+		{	/* store timestamp in case it is wanted later */
+			struct pps *pp = (struct pps *) info->tty->disc_data;
+				
+			if (pp != NULL && pp->magic == PPSCLOCK_MAGIC) {
+				pp->state.ecount =
+					do_clock_gettime(CLOCK_REALTIME,
+							 &pp->state.etime);
+#ifdef SERIAL_DEBUG_NTP_PPS
+				printk(KERN_DEBUG
+				       "rs_interrupt_multi: time %ld:%ld(%ld)\n",
+				       pp->state.etime.tv_sec,
+				       pp->state.etime.tv_nsec,
+				       pp->state.ecount);
+#endif
+			}
+		}
+#endif /* CONFIG_NTP_PPS_SERIAL */
 
 		info->last_active = jiffies;
 
@@ -1642,6 +1805,9 @@
 	unsigned cflag, cval, fcr = 0;
 	int	bits;
 	unsigned long	flags;
+#ifdef CONFIG_NTP_PPS_SERIAL
+	struct pps	*pps;
+#endif
 
 	if (!info->tty || !info->tty->termios)
 		return;
@@ -1756,8 +1922,6 @@
 	
 	/* CTS flow control flag and modem status interrupts */
 	info->IER &= ~UART_IER_MSI;
-	if (info->flags & ASYNC_HARDPPS_CD)
-		info->IER |= UART_IER_MSI;
 	if (cflag & CRTSCTS) {
 		info->flags |= ASYNC_CTS_FLOW;
 		info->IER |= UART_IER_MSI;
@@ -1769,6 +1933,12 @@
 		info->flags |= ASYNC_CHECK_CD;
 		info->IER |= UART_IER_MSI;
 	}
+#ifdef CONFIG_NTP_PPS_SERIAL
+	if ((pps = info->tty->disc_data) != 0 &&
+	    pps->magic == PPSCLOCK_MAGIC &&
+	    (pps->state.parm.mode & ~PPS_TSFMT_TSPEC) != 0)
+		info->IER |= UART_IER_MSI;	/* enable interrupts */
+#endif
 	serial_out(info, UART_IER, info->IER);
 
 	/*
@@ -2548,6 +2718,34 @@
 }
 #endif
 
+#ifdef	CONFIG_NTP_PPS_SERIAL
+/* Return allowed mode bits for given pps struct, file's mode, and user.
+ * Bits set in `*obligatory' must be set.  Returned bits may be set.
+ */
+static int pps_allowed_mode(const struct tty_struct *tty, mode_t fmode,
+			    int *obligatory)
+{
+	const struct pps	*pps = (const struct pps *) tty->disc_data;
+	int 			cap = pps->state.cap;
+
+	cap &= ~PPS_CANWAIT;				/* always RO */
+	*obligatory = PPS_TSFMT_TSPEC;		/* only supported format */
+	if ((fmode & FMODE_WRITE) == 0) {	/* read-only mode */
+		cap = *obligatory = pps->state.parm.mode;
+	} else if (!capable(CAP_SYS_TIME)) {	/* may not manipulate time */
+		int	fixed_bits;
+		int	active_flags = pps->state.parm.mode;
+
+		if (pps_kc_hardpps_dev == tty) {
+			fixed_bits = PPS_OFFSETASSERT|PPS_OFFSETCLEAR;
+			fixed_bits &= active_flags;
+			*obligatory |= fixed_bits;
+		}
+	}
+	return cap;
+}
+#endif
+
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
 {
@@ -2555,6 +2753,9 @@
 	struct async_icount cprev, cnow;	/* kernel counter temps */
 	struct serial_icounter_struct icount;
 	unsigned long flags;
+#ifdef	CONFIG_NTP_PPS_SERIAL
+	int error = 0;
+#endif
 #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
 	int retval, tmp;
 #endif
@@ -2707,6 +2908,379 @@
 			/* "setserial -W" is called in Debian boot */
 			printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
 			return 0;
+#ifdef	CONFIG_NTP_PPS_SERIAL
+#ifdef SERIAL_DEBUG_NTP_PPS
+#define RESTORE_FLAGS_AND_RETURN	\
+	do { \
+		printk(KERN_DEBUG "ioctl() returns %d\n", error);\
+		restore_flags(flags); return error;\
+	} while (0);
+#else
+#define RESTORE_FLAGS_AND_RETURN	\
+	do { restore_flags(flags); return error; } while (0);
+#endif
+
+		case PPS_IOC_CREATE:
+		{
+			/* initialize the tty data struct */
+			struct pps *pps;
+
+			save_flags(flags); cli();
+			pps = (struct pps *) tty->disc_data;
+#ifdef SERIAL_DEBUG_NTP_PPS
+			printk(KERN_DEBUG
+			       "PPS_IOC_CREATE: tty/count/data = %p/%d/%p\n",
+			       tty, tty->count, pps);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+			if (pps != NULL) {
+#ifdef SERIAL_DEBUG_NTP_PPS
+				printk(KERN_DEBUG
+				       "PPS_IOC_CREATE: magic = 0x%x\n",
+				       pps->magic);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+				/* share the handle if valid, otherwise fail */
+				if (pps->magic != PPSCLOCK_MAGIC)
+					error = -EBADF;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			if ((file->f_mode & FMODE_WRITE) == 0) {
+				error = -EBADF;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			if ((pps = (struct pps *) kmalloc(sizeof(struct pps),
+							  GFP_KERNEL)) == NULL)
+			{
+				printk(KERN_ERR
+				       "PPS_IOC_CREATE: kmalloc failed\n");
+				error = -ENOMEM;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			/* clear all parameters */
+			memset(pps, 0, sizeof(struct pps));
+			pps->magic = PPSCLOCK_MAGIC;
+			pps->state.parm.api_version = PPS_API_VERS_1;
+			pps->state.parm.mode = PPS_TSFMT_TSPEC;
+			pps->state.cap = (PPS_CAPTUREASSERT|
+					  PPS_CAPTURECLEAR|
+					  PPS_OFFSETASSERT|
+					  PPS_OFFSETCLEAR|
+					  PPS_ECHOASSERT|
+					  PPS_ECHOCLEAR|
+					  PPS_CANWAIT|
+					  PPS_TSFMT_TSPEC);
+			init_waitqueue_head(&pps->state.ewait);
+			tty->disc_data = (char *) pps;
+			tty->termios->c_line = N_PPSCLOCK;
+#ifdef SERIAL_DEBUG_NTP_PPS
+			printk(KERN_DEBUG
+			       "PPS_IOC_CREATE: new pps at %p, magic 0x%0x\n",
+			       pps, pps->magic);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+			error = 0;
+			RESTORE_FLAGS_AND_RETURN;
+		}
+
+		case PPS_IOC_DESTROY:
+		{
+			/* draft 03 says the settings are unaffected. */
+			struct pps *pps;
+
+			save_flags(flags); cli();
+			if ((file->f_mode & FMODE_WRITE) == 0) {
+				error = -EBADF;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			pps = (struct pps *) tty->disc_data;
+#ifdef SERIAL_DEBUG_NTP_PPS
+			printk(KERN_DEBUG
+			       "PPS_IOC_DESTROY: tty/count/data = %p/%d/%p\n",
+			       tty, tty->count, pps);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+			if (pps == NULL || pps->magic != PPSCLOCK_MAGIC) {
+				error = -EOPNOTSUPP;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			if (waitqueue_active(&pps->state.ewait)) {
+#ifdef SERIAL_DEBUG_NTP_PPS
+				printk(KERN_DEBUG
+				       "PPS_IOC_DESTROY: wait queue busy\n");
+#endif /* SERIAL_DEBUG_NTP_PPS */
+				error = -EBUSY;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			error = 0;
+			RESTORE_FLAGS_AND_RETURN;
+		}
+
+		case PPS_IOC_FETCH:
+		{
+			struct pps *pps = (struct pps *) tty->disc_data;
+			struct pps_fetch_args parms;
+			long timeout;
+
+			save_flags(flags); cli();
+#ifdef SERIAL_DEBUG_NTP_PPS
+			printk(KERN_DEBUG
+			       "PPS_IOC_FETCH: tty/count/pps = %p/%d/%p\n",
+			       tty, tty->count, pps);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+			if (pps == NULL || pps->magic != PPSCLOCK_MAGIC) {
+				error = -EOPNOTSUPP;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			if (copy_from_user(&parms,
+					   (struct pps_fetch_args *) arg,
+					   sizeof(struct pps_fetch_args))
+			    != 0) {
+				error = -EFAULT;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			if (parms.tsformat != PPS_TSFMT_TSPEC) {
+				error = -EINVAL;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			timeout = HZ * parms.timeout.tv_sec;
+			timeout += parms.timeout.tv_nsec / (1000000000 / HZ);
+			if (timeout != 0) {
+				restore_flags(flags);
+				if (parms.timeout.tv_sec == -1)
+					interruptible_sleep_on(&pps->state.ewait);
+				else {
+					timeout = interruptible_sleep_on_timeout(
+						&pps->state.ewait,
+						timeout);
+					if (timeout <= 0) {
+						error = -ETIMEDOUT;
+						return error;
+						/* flags already restored */
+					}
+				}
+				save_flags(flags); cli();
+				pps = (struct pps *) tty->disc_data;
+				if (pps == NULL || pps->magic != PPSCLOCK_MAGIC)
+				{
+#ifdef SERIAL_DEBUG_NTP_PPS
+					printk(KERN_DEBUG "PPS_IOC_FETCH: "
+					       "tty %p lacks pps\n",
+					       tty);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+					error = -EOPNOTSUPP;
+					RESTORE_FLAGS_AND_RETURN;
+				}
+				if (signal_pending(current)) {
+					error = -EINTR;
+					RESTORE_FLAGS_AND_RETURN;
+				}
+			}
+			parms.pps_info_buf = pps->state.info;
+			if (copy_to_user((struct pps_fetch_args *) arg,
+					 &parms,
+					 sizeof(struct pps_fetch_args)) != 0)
+				error = -EFAULT;
+			RESTORE_FLAGS_AND_RETURN;
+		}
+
+		case PPS_IOC_SETPARMS:
+		{
+			struct pps *pps = (struct pps *) tty->disc_data;
+			struct pps_params parms;
+			int may_bits, must_bits;
+
+			save_flags(flags); cli();
+			if ((file->f_mode & FMODE_WRITE) == 0) {
+				error = -EBADF;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+#ifdef SERIAL_DEBUG_NTP_PPS
+			printk(KERN_DEBUG
+			       "PPS_IOC_SETPARAMS: tty/pps = %p/%p\n",
+			       tty, pps);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+			if (pps == NULL || pps->magic != PPSCLOCK_MAGIC) {
+				error = -EOPNOTSUPP;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			if (copy_from_user(&parms,
+					   (struct pps_params *) arg,
+					   sizeof(struct pps_params)) != 0) {
+				error = -EFAULT;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+#ifdef SERIAL_DEBUG_NTP_PPS
+			printk(KERN_DEBUG "PPS_IOC_SETPARAMS: "
+			       "vers/mode(cap) = %#x/%#x(%#x)\n",
+			       parms.api_version, parms.mode, pps->state.cap);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+			if (parms.api_version != PPS_API_VERS_1) {
+				error = -EINVAL;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			if ((parms.mode & ~pps->state.cap) != 0 ) {
+				error = -EINVAL;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			if ((parms.mode &
+			     (PPS_TSFMT_TSPEC|PPS_TSFMT_NTPFP)) == 0 ) {
+				/* section 3.3 of RFC 2783 interpreted */
+				parms.mode |= PPS_TSFMT_TSPEC;
+			}
+			may_bits = pps_allowed_mode(tty, file->f_mode,
+						    &must_bits);
+			if ((parms.mode & must_bits) != must_bits ||
+			    (parms.mode & ~may_bits) != 0) {
+				error = -EPERM;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			if (capable(CAP_SYS_TIME)) {
+				/* allow setting offsets */
+				pps->state.parm = parms;
+			} else {
+				pps_params_t	*ppspp = &pps->state.parm;
+
+				ppspp->api_version = parms.api_version;
+				ppspp->mode = parms.mode;
+				/* not offsets! */
+			}
+			if (parms.mode & (PPS_CAPTUREASSERT|PPS_CAPTURECLEAR)) {
+				/* enable interrupts */
+				info->IER |= UART_IER_MSI;
+				info->flags |= ASYNC_LOW_LATENCY;
+				if (info->flags & ASYNC_INITIALIZED) {
+					serial_out(info, UART_IER, info->IER);
+#ifdef SERIAL_DEBUG_NTP_PPS
+					printk(KERN_DEBUG
+					       "PPS_IOC_SETPARAMS: IER:%02x\n",
+					       info->IER);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+				}
+			}
+			RESTORE_FLAGS_AND_RETURN;
+		}
+
+		case PPS_IOC_GETPARMS:
+		{
+			const struct pps *pps = (struct pps *) tty->disc_data;
+
+			save_flags(flags); cli();
+#ifdef SERIAL_DEBUG_NTP_PPS
+			printk(KERN_DEBUG
+			       "PPS_IOC_GETPARAMS: tty/pps = %p/%p\n",
+			       tty, pps);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+			if (pps == NULL || pps->magic != PPSCLOCK_MAGIC) {
+				error = -EOPNOTSUPP;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			if (copy_to_user((pps_params_t *) arg,
+					 &(pps->state.parm),
+					 sizeof(struct pps_params)) != 0) {
+				error = -EFAULT;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+		}
+
+		case PPS_IOC_GETCAP:
+		{
+			const struct pps *pps = (struct pps *) tty->disc_data;
+			int may_bits, must_bits;
+
+			save_flags(flags); cli();
+#ifdef SERIAL_DEBUG_NTP_PPS
+			printk(KERN_DEBUG
+			       "PPS_IOC_GETCAP: tty/pps = %p/%p\n", tty, pps);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+			if (pps == NULL || pps->magic != PPSCLOCK_MAGIC) {
+				error = -EOPNOTSUPP;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			may_bits = pps_allowed_mode(tty, file->f_mode,
+						    &must_bits);
+			if (copy_to_user((int *) arg, &may_bits,
+					 sizeof(int)) != 0)
+				error = -EFAULT;
+			RESTORE_FLAGS_AND_RETURN;
+		}
+
+		case PPS_IOC_KC_BIND:
+		{
+			struct pps *pps = (struct pps *) tty->disc_data;
+			struct pps_bind_args parms;
+
+			save_flags(flags); cli();
+			if ((file->f_mode & FMODE_WRITE) == 0) {
+				error = -EBADF;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+#ifdef SERIAL_DEBUG_NTP_PPS
+			printk(KERN_DEBUG
+			       "PPS_IOC_KC_BIND: tty/pps = %p/%p\n", tty, pps);
+			printk(KERN_DEBUG
+			       "PPS_IOC_KC_BIND: current dev/mode = %p/0x%x\n",
+			       pps_kc_hardpps_dev, pps_kc_hardpps_mode);
+			
+#endif /* SERIAL_DEBUG_NTP_PPS */
+			if (pps == NULL || pps->magic != PPSCLOCK_MAGIC)
+			{
+				error = -EOPNOTSUPP;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			if (copy_from_user(&parms,
+					   (struct pps_bind_args *) arg,
+					   sizeof(struct pps_bind_args)) != 0)
+			{
+				error = -EFAULT;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			/* generic parameter validation */
+			if (parms.tsformat != PPS_TSFMT_TSPEC ||
+			    (parms.edge & ~PPS_CAPTUREBOTH) != 0 ||
+#if 0
+			    parms.consumer < PPS_KC_HARDPPS ||
+			    parms.consumer > PPS_KC_HARDPPS_FLL ||
+#endif
+			    parms.consumer != PPS_KC_HARDPPS) {
+				error = -EINVAL;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			/* permission check */
+			if (!capable(CAP_SYS_TIME)) {
+				error = -EPERM;
+				RESTORE_FLAGS_AND_RETURN;
+			}
+			/* detailed parameter check */
+			if (parms.edge == 0) {
+				if (pps_kc_hardpps_dev == NULL ||
+				    pps_kc_hardpps_dev == (void *) tty) {
+					pps_kc_hardpps_mode = parms.edge;
+					pps_kc_hardpps_dev = NULL;
+#ifdef SERIAL_DEBUG_NTP_PPS
+					printk(KERN_DEBUG "PPS_IOC_KC_BIND: "
+					       "unbound kernel consumer\n");
+#endif /* SERIAL_DEBUG_NTP_PPS */
+				} else {	/* another consumer bound */
+					error = -EINVAL;
+					RESTORE_FLAGS_AND_RETURN;
+				}
+			} else {
+				if (pps_kc_hardpps_dev == (void *) tty ||
+				    pps_kc_hardpps_dev == NULL) {
+					pps_kc_hardpps_mode = parms.edge;
+					pps_kc_hardpps_dev = tty;
+#ifdef SERIAL_DEBUG_NTP_PPS
+					printk(KERN_DEBUG "PPS_IOC_KC_BIND: "
+					       "new kernel consumer: dev=%p, "
+					       "edge=0x%x\n",
+					       pps_kc_hardpps_dev,
+					       pps_kc_hardpps_mode);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+				} else {
+					error = -EINVAL;
+					RESTORE_FLAGS_AND_RETURN;
+				}
+			}
+			RESTORE_FLAGS_AND_RETURN;
+		}
+#endif /* CONFIG_NTP_PPS_SERIAL */
 
 		default:
 			return -ENOIOCTLCMD;
@@ -2859,6 +3433,32 @@
 		 */
 		rs_wait_until_sent(tty, info->timeout);
 	}
+#ifdef CONFIG_NTP_PPS_SERIAL
+	if (info->tty->disc_data != NULL
+	    && ((struct pps *)(info->tty->disc_data))->magic == PPSCLOCK_MAGIC)
+	{
+		struct pps *tmp = (struct pps *) info->tty->disc_data;
+		if (waitqueue_active(&tmp->state.ewait))
+			wake_up_interruptible(&tmp->state.ewait);
+		info->tty->termios->c_line = N_TTY;
+		info->tty->disc_data = NULL;
+		tmp->magic = 0;
+		kfree(tmp);
+		if (pps_kc_hardpps_dev == (void *) info->tty) {
+			pps_kc_hardpps_mode = 0;
+			pps_kc_hardpps_dev = NULL;
+#ifdef SERIAL_DEBUG_NTP_PPS
+			printk(KERN_DEBUG
+			       "rs_close(): unbound kernel consumer dev %p\n",
+			       info->tty);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+		}
+#ifdef SERIAL_DEBUG_NTP_PPS
+		printk(KERN_DEBUG "rs_close(): removed pps %p from tty %p\n",
+		       tmp, tty);
+#endif /* SERIAL_DEBUG_NTP_PPS */
+	}
+#endif /* CONFIG_NTP_PPS_SERIAL */
 	shutdown(info);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
@@ -3263,6 +3863,9 @@
 {
 	struct async_struct *info = state->info, scr_info;
 	char	stat_buf[30], control, status;
+#ifdef SERIAL_DEBUG_NTP_PPS
+	char	ier;
+#endif
 	int	ret;
 	unsigned long flags;
 
@@ -3297,6 +3900,9 @@
 	save_flags(flags); cli();
 	status = serial_in(info, UART_MSR);
 	control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR);
+#ifdef SERIAL_DEBUG_NTP_PPS
+	ier = serial_in(info, UART_IER);
+#endif
 	restore_flags(flags); 
 
 	stat_buf[0] = 0;
@@ -3334,6 +3940,9 @@
 	if (state->icount.overrun)
 		ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
 
+#ifdef SERIAL_DEBUG_NTP_PPS
+	ret += sprintf(buf+ret, " IER:%02x", (unsigned) ier);
+#endif
 	/*
 	 * Last thing is the RS-232 status lines
 	 */
@@ -3413,6 +4022,10 @@
        " SERIAL_ACPI"
 #define SERIAL_OPT
 #endif
+#ifdef CONFIG_NTP_PPS_SERIAL
+	       " PPS_API(RFC-2783)"
+#define SERIAL_OPT
+#endif
 #ifdef SERIAL_OPT
        " enabled\n";
 #else
@@ -5660,7 +6273,8 @@
 	state = &rs_table[i];
 	if (rs_table[i].count) {
 		restore_flags(flags);
-		printk("Couldn't configure serial #%d (port=%ld,irq=%d): "
+		printk(KERN_ERR
+		       "Couldn't configure serial #%d (port=%ld,irq=%d): "
 		       "device already open\n", i, port, req->irq);
 		return -1;
 	}
@@ -5682,7 +6296,7 @@
 	autoconfig(state);
 	if (state->type == PORT_UNKNOWN) {
 		restore_flags(flags);
-		printk("register_serial(): autoconfig failed\n");
+		printk(KERN_ERR "register_serial(): autoconfig failed\n");
 		return -1;
 	}
 	restore_flags(flags);
@@ -5743,10 +6357,12 @@
 	save_flags(flags); cli();
         remove_bh(SERIAL_BH);
 	if ((e1 = tty_unregister_driver(&serial_driver)))
-		printk("serial: failed to unregister serial driver (%d)\n",
+		printk(KERN_WARNING
+		       "serial: failed to unregister serial driver (%d)\n",
 		       e1);
 	if ((e2 = tty_unregister_driver(&callout_driver)))
-		printk("serial: failed to unregister callout driver (%d)\n", 
+		printk(KERN_WARNING
+		       "serial: failed to unregister callout driver (%d)\n", 
 		       e2);
 	restore_flags(flags);
 
Index: linux/drivers/char/tty_io.c
diff -u linux/drivers/char/tty_io.c:1.1.1.17 linux/drivers/char/tty_io.c:1.1.1.17.2.1
--- linux/drivers/char/tty_io.c:1.1.1.17	Sat Jan 22 22:03:57 2005
+++ linux/drivers/char/tty_io.c	Mon Jan 24 21:05:27 2005
@@ -2626,7 +2626,6 @@
 	return 0;
 }
 
-
 /*
  * Initialize the console device. This is called *early*, so
  * we can't necessarily depend on lots of kernel help here.
@@ -2638,6 +2637,9 @@
 	/* Setup the default TTY line discipline. */
 	memset(tty_ldiscs, 0, NR_LDISCS*sizeof(struct tty_ldisc));
 	(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
+#ifdef	CONFIG_NTP_PPS
+	(void) tty_register_ldisc(N_PPSCLOCK, &tty_ldisc_N_PPSCLOCK);
+#endif
 
 	/*
 	 * Set up the standard termios.  Individual tty drivers may 
Index: linux/drivers/char/ftape/lowlevel/ftape-calibr.c
diff -u linux/drivers/char/ftape/lowlevel/ftape-calibr.c:1.1.1.3 linux/drivers/char/ftape/lowlevel/ftape-calibr.c:1.1.1.3.6.1
--- linux/drivers/char/ftape/lowlevel/ftape-calibr.c:1.1.1.3	Sun Feb 23 18:39:11 2003
+++ linux/drivers/char/ftape/lowlevel/ftape-calibr.c	Mon Jan 24 21:05:32 2005
@@ -26,7 +26,7 @@
 
 #include <linux/config.h>
 #include <linux/errno.h>
-#include <linux/sched.h>
+#include <linux/time.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #if defined(__alpha__)
@@ -35,7 +35,7 @@
 # include <asm/msr.h>
 # include <asm/timex.h>
 #elif defined(__i386__) 
-# include <linux/timex.h>
+# include <asm/timex.h>
 #endif
 #include <linux/ftape.h>
 #include "../lowlevel/ftape-tracing.h"
Index: linux/drivers/sbus/char/sunkbd.c
diff -u linux/drivers/sbus/char/sunkbd.c:1.1.1.5 linux/drivers/sbus/char/sunkbd.c:1.1.1.5.8.1
--- linux/drivers/sbus/char/sunkbd.c:1.1.1.5	Sun Aug 18 22:10:34 2002
+++ linux/drivers/sbus/char/sunkbd.c	Mon Jan 24 21:05:35 2005
@@ -1296,7 +1296,7 @@
 	if (next != kbd_tail){
 		kbd_queue [kbd_head].id = scan & KBD_KEYMASK;
 		kbd_queue [kbd_head].value=scan & KBD_UP ? VKEY_UP : VKEY_DOWN;
-		kbd_queue [kbd_head].time = xtime;
+		do_gettimeofday(&kbd_queue [kbd_head].time);
 		kbd_head = next;
 	}
 	spin_unlock_irqrestore(&kbd_queue_lock, flags);
Index: linux/drivers/sbus/char/sunmouse.c
diff -u linux/drivers/sbus/char/sunmouse.c:1.1.1.2 linux/drivers/sbus/char/sunmouse.c:1.1.1.2.20.1
--- linux/drivers/sbus/char/sunmouse.c:1.1.1.2	Fri Feb  2 20:10:41 2001
+++ linux/drivers/sbus/char/sunmouse.c	Mon Jan 24 21:05:35 2005
@@ -360,20 +360,20 @@
 			ev.id = MS_MIDDLE;
 			ev.value = bstate & BUTTON_MIDDLE;
 		}
-		ev.time = xtime;
+		do_gettimeofday(&ev.time);
 		ev.value = ev.value ? VKEY_DOWN : VKEY_UP;
 		pushed += push_event (&ev);
 	}
 	if (sunmouse.delta_x) {
 		ev.id = LOC_X_DELTA;
-		ev.time = xtime;
+		do_gettimeofday(&ev.time);
 		ev.value = sunmouse.delta_x;
 		pushed += push_event (&ev);
 		sunmouse.delta_x = 0;
 	}
 	if (sunmouse.delta_y) {
 		ev.id = LOC_Y_DELTA;
-		ev.time = xtime;
+		do_gettimeofday(&ev.time);
 		ev.value = sunmouse.delta_y;
 		pushed += push_event (&ev);
 	}
Index: linux/fs/affs/file.c
diff -u linux/fs/affs/file.c:1.1.1.8 linux/fs/affs/file.c:1.1.1.8.10.1
--- linux/fs/affs/file.c:1.1.1.8	Fri Mar  8 21:04:00 2002
+++ linux/fs/affs/file.c	Mon Jan 24 21:05:41 2005
@@ -15,7 +15,7 @@
 #include <asm/div64.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <linux/sched.h>
+#include <linux/time.h>
 #include <linux/affs_fs.h>
 #include <linux/fcntl.h>
 #include <linux/kernel.h>
Index: linux/fs/isofs/util.c
diff -u linux/fs/isofs/util.c:1.1.1.4 linux/fs/isofs/util.c:1.1.1.4.12.1
--- linux/fs/isofs/util.c:1.1.1.4	Thu Dec 13 19:50:37 2001
+++ linux/fs/isofs/util.c	Mon Jan 24 21:05:44 2005
@@ -2,7 +2,6 @@
  *  linux/fs/isofs/util.c
  */
 
-#include <linux/time.h>
 #include <linux/iso_fs.h>
 
 /* 
Index: linux/fs/udf/udfdecl.h
diff -u linux/fs/udf/udfdecl.h:1.1.1.5 linux/fs/udf/udfdecl.h:1.1.1.5.8.1
--- linux/fs/udf/udfdecl.h:1.1.1.5	Sun Aug 18 22:11:32 2002
+++ linux/fs/udf/udfdecl.h	Mon Jan 24 21:05:49 2005
@@ -31,7 +31,7 @@
 #define UDF_NAME_LEN		255
 #define UDF_PATH_LEN		1023
 
-#define CURRENT_UTIME	(xtime.tv_usec)
+#define CURRENT_UTIME	(xtime.tv_nsec / 1000)
 
 #define udf_file_entry_alloc_offset(inode)\
 	((UDF_I_EXTENDED_FE(inode) ?\
Index: linux/include/asm-alpha/termios.h
diff -u linux/include/asm-alpha/termios.h:1.1.1.3 linux/include/asm-alpha/termios.h:1.1.1.3.14.1
--- linux/include/asm-alpha/termios.h:1.1.1.3	Sat Jul 28 22:52:25 2001
+++ linux/include/asm-alpha/termios.h	Mon Jan 24 21:05:52 2005
@@ -83,6 +83,7 @@
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14
 #define N_HCI		15  /* Bluetooth HCI UART */
+#define	N_PPSCLOCK	16	/* pulse-per-second detection */
 
 #ifdef __KERNEL__
 /*	eof=^D		eol=\0		eol2=\0		erase=del
Index: linux/include/asm-alpha/timex.h
diff -u linux/include/asm-alpha/timex.h:1.1.1.3 linux/include/asm-alpha/timex.h:1.1.1.3.4.1
--- linux/include/asm-alpha/timex.h:1.1.1.3	Fri Aug 15 22:28:37 2003
+++ linux/include/asm-alpha/timex.h	Mon Jan 24 21:05:52 2005
@@ -8,6 +8,9 @@
 
 #define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
 
+/* LATCH is used in the interval timer and ftape setup. */
+#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
+
 /*
  * Standard way to access the cycle counter.
  * Currently only used on SMP for scheduling.
Index: linux/include/asm-arm/termios.h
diff -u linux/include/asm-arm/termios.h:1.1.1.3 linux/include/asm-arm/termios.h:1.1.1.3.14.1
--- linux/include/asm-arm/termios.h:1.1.1.3	Sat Jul 28 22:52:27 2001
+++ linux/include/asm-arm/termios.h	Mon Jan 24 21:05:57 2005
@@ -66,6 +66,7 @@
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14
 #define N_HCI		15  /* Bluetooth HCI UART */
+#define	N_PPSCLOCK	16	/* pulse-per-second detection */
 
 #ifdef __KERNEL__
 
Index: linux/include/asm-i386/termios.h
diff -u linux/include/asm-i386/termios.h:1.1.1.4 linux/include/asm-i386/termios.h:1.1.1.4.6.1
--- linux/include/asm-i386/termios.h:1.1.1.4	Sun Feb 23 18:41:13 2003
+++ linux/include/asm-i386/termios.h	Mon Jan 24 21:06:01 2005
@@ -58,6 +58,7 @@
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14	/* synchronous PPP */
 #define N_HCI		15  /* Bluetooth HCI UART */
+#define	N_PPSCLOCK	16	/* pulse-per-second detection */
 
 #ifdef __KERNEL__
 
Index: linux/include/asm-i386/timex.h
diff -u linux/include/asm-i386/timex.h:1.1.1.4 linux/include/asm-i386/timex.h:1.1.1.4.6.1
--- linux/include/asm-i386/timex.h:1.1.1.4	Sun Feb 23 18:41:13 2003
+++ linux/include/asm-i386/timex.h	Mon Jan 24 21:06:01 2005
@@ -16,6 +16,10 @@
 #endif
 
 #define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
+
+/* LATCH is used in the interval timer and ftape setup. */
+#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
+
 #define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
 		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
@@ -50,6 +54,11 @@
 #endif
 }
 
+/* The following two items are set if TSC is configured and operational: */
+extern	unsigned long cpu_khz;		/* CPU frequency in kHz */
+extern	unsigned long exact_nanotime_quotient;
+					/* 2^28 * (1 / (clocks per nsec) */
+
 extern unsigned long cpu_khz;
 
 #define vxtime_lock()		do {} while (0)
Index: linux/include/asm-m68k/machdep.h
diff -u linux/include/asm-m68k/machdep.h:1.1.1.4 linux/include/asm-m68k/machdep.h:1.1.1.4.4.1
--- linux/include/asm-m68k/machdep.h:1.1.1.4	Fri Aug 15 22:28:52 2003
+++ linux/include/asm-m68k/machdep.h	Mon Jan 24 21:06:05 2005
@@ -3,7 +3,7 @@
 
 struct pt_regs;
 struct kbd_repeat;
-struct mktime;
+/*struct mktime; -- conflicts with function of same name --UW */
 struct rtc_time;
 struct rtc_pll_info;
 struct gendisk;
Index: linux/include/asm-m68k/termios.h
diff -u linux/include/asm-m68k/termios.h:1.1.1.4 linux/include/asm-m68k/termios.h:1.1.1.4.6.1
--- linux/include/asm-m68k/termios.h:1.1.1.4	Sun Feb 23 18:41:20 2003
+++ linux/include/asm-m68k/termios.h	Mon Jan 24 21:06:05 2005
@@ -68,6 +68,7 @@
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14
 #define N_HCI		15  /* Bluetooth HCI UART */
+#define	N_PPSCLOCK	16	/* pulse-per-second detection */
 
 #ifdef __KERNEL__
 
Index: linux/include/asm-m68k/timex.h
diff -u linux/include/asm-m68k/timex.h:1.1.1.2 linux/include/asm-m68k/timex.h:1.1.1.2.6.1
--- linux/include/asm-m68k/timex.h:1.1.1.2	Sun Feb 23 18:41:20 2003
+++ linux/include/asm-m68k/timex.h	Mon Jan 24 21:06:05 2005
@@ -12,6 +12,9 @@
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
 		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
 
+/* LATCH is used in the interval timer and ftape setup. */
+#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
+
 typedef unsigned long cycles_t;
 
 static inline cycles_t get_cycles(void)
Index: linux/include/asm-mips/termios.h
diff -u linux/include/asm-mips/termios.h:1.1.1.5 linux/include/asm-mips/termios.h:1.1.1.5.6.1
--- linux/include/asm-mips/termios.h:1.1.1.5	Sun Feb 23 18:41:21 2003
+++ linux/include/asm-mips/termios.h	Mon Jan 24 21:06:10 2005
@@ -103,6 +103,7 @@
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14	/* synchronous PPP */
 #define N_HCI		15	/* Bluetooth HCI UART */
+#define	N_PPSCLOCK	16	/* pulse-per-second detection */
 
 #ifdef __KERNEL__
 
Index: linux/include/asm-mips/timex.h
diff -u linux/include/asm-mips/timex.h:1.1.1.4 linux/include/asm-mips/timex.h:1.1.1.4.2.1
--- linux/include/asm-mips/timex.h:1.1.1.4	Sat Jan 22 21:44:55 2005
+++ linux/include/asm-mips/timex.h	Mon Jan 24 21:06:10 2005
@@ -12,6 +12,9 @@
 
 #include <asm/mipsregs.h>
 
+/* LATCH is used in the interval timer and ftape setup. */
+#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
+
 /*
  * Standard way to access the cycle counter.
  * Currently only used on SMP for scheduling.
Index: linux/include/asm-mips64/timex.h
diff -u linux/include/asm-mips64/timex.h:1.1.1.4 linux/include/asm-mips64/timex.h:1.1.1.4.2.1
--- linux/include/asm-mips64/timex.h:1.1.1.4	Sat Jan 22 21:45:02 2005
+++ linux/include/asm-mips64/timex.h	Mon Jan 24 21:06:12 2005
@@ -12,6 +12,9 @@
 
 #include <asm/mipsregs.h>
 
+/* LATCH is used in the interval timer and ftape setup. */
+#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
+
 /*
  * Standard way to access the cycle counter.
  * Currently only used on SMP for scheduling.
Index: linux/include/asm-ppc/termios.h
diff -u linux/include/asm-ppc/termios.h:1.1.1.7 linux/include/asm-ppc/termios.h:1.1.1.7.2.1
--- linux/include/asm-ppc/termios.h:1.1.1.7	Sat Jan 22 21:45:09 2005
+++ linux/include/asm-ppc/termios.h	Mon Jan 24 21:06:15 2005
@@ -192,6 +192,7 @@
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14
 #define N_HCI		15  /* Bluetooth HCI UART */
+#define	N_PPSCLOCK	16	/* pulse-per-second detection */
 
 #ifdef __KERNEL__
 
Index: linux/include/asm-ppc/timex.h
diff -u linux/include/asm-ppc/timex.h:1.1.1.5 linux/include/asm-ppc/timex.h:1.1.1.5.4.1
--- linux/include/asm-ppc/timex.h:1.1.1.5	Fri Aug 15 22:29:02 2003
+++ linux/include/asm-ppc/timex.h	Mon Jan 24 21:06:15 2005
@@ -16,6 +16,9 @@
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
 		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
 
+/* LATCH is used in the interval timer and ftape setup. */
+#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
+
 typedef unsigned long cycles_t;
 
 /*
Index: linux/include/asm-s390/timex.h
diff -u linux/include/asm-s390/timex.h:1.1.1.4 linux/include/asm-s390/timex.h:1.1.1.4.6.1
--- linux/include/asm-s390/timex.h:1.1.1.4	Sun Feb 23 18:41:35 2003
+++ linux/include/asm-s390/timex.h	Mon Jan 24 21:06:19 2005
@@ -17,6 +17,9 @@
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
 		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
 
+/* LATCH is used in the interval timer and ftape setup. */
+#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
+
 typedef unsigned long long cycles_t;
 
 extern cycles_t cacheflush_time;
Index: linux/include/asm-sparc/termios.h
diff -u linux/include/asm-sparc/termios.h:1.1.1.3 linux/include/asm-sparc/termios.h:1.1.1.3.14.1
--- linux/include/asm-sparc/termios.h:1.1.1.3	Sat Jul 28 22:53:32 2001
+++ linux/include/asm-sparc/termios.h	Mon Jan 24 21:06:22 2005
@@ -71,6 +71,7 @@
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14	/* synchronous PPP */
 #define N_HCI		15  /* Bluetooth HCI UART */
+#define	N_PPSCLOCK	16	/* pulse-per-second detection */
 
 #ifdef __KERNEL__
 
Index: linux/include/asm-sparc/timex.h
diff -u linux/include/asm-sparc/timex.h:1.1.1.2 linux/include/asm-sparc/timex.h:1.1.1.2.6.1
--- linux/include/asm-sparc/timex.h:1.1.1.2	Sun Feb 23 18:41:38 2003
+++ linux/include/asm-sparc/timex.h	Mon Jan 24 21:06:22 2005
@@ -12,6 +12,9 @@
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
 		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
 
+/* LATCH is used in the interval timer and ftape setup. */
+#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
+
 /* XXX Maybe do something better at some point... -DaveM */
 typedef unsigned long cycles_t;
 extern cycles_t cacheflush_time;
Index: linux/include/asm-sparc64/termios.h
diff -u linux/include/asm-sparc64/termios.h:1.1.1.3 linux/include/asm-sparc64/termios.h:1.1.1.3.14.1
--- linux/include/asm-sparc64/termios.h:1.1.1.3	Sat Jul 28 22:53:36 2001
+++ linux/include/asm-sparc64/termios.h	Mon Jan 24 21:06:25 2005
@@ -71,6 +71,7 @@
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14	/* synchronous PPP */
 #define N_HCI		15  /* Bluetooth HCI UART */
+#define	N_PPSCLOCK	16	/* pulse-per-second detection */
 
 #ifdef __KERNEL__
 
Index: linux/include/asm-sparc64/timex.h
diff -u linux/include/asm-sparc64/timex.h:1.1.1.5 linux/include/asm-sparc64/timex.h:1.1.1.5.4.1
--- linux/include/asm-sparc64/timex.h:1.1.1.5	Fri Aug 15 22:29:09 2003
+++ linux/include/asm-sparc64/timex.h	Mon Jan 24 21:06:25 2005
@@ -14,6 +14,9 @@
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
 		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
 
+/* LATCH is used in the interval timer and ftape setup. */
+#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
+
 /* Getting on the cycle counter on sparc64. */
 typedef unsigned long cycles_t;
 #define get_cycles()	tick_ops->get_tick()
Index: linux/include/linux/sched.h
diff -u linux/include/linux/sched.h:1.1.1.17 linux/include/linux/sched.h:1.1.1.17.2.1
--- linux/include/linux/sched.h:1.1.1.17	Sat Jan 22 22:07:59 2005
+++ linux/include/linux/sched.h	Mon Jan 24 21:06:31 2005
@@ -1,6 +1,10 @@
 #ifndef _LINUX_SCHED_H
 #define _LINUX_SCHED_H
 
+/* 1999-02-02	Ulrich Windl
+ *	Moved time related stuff to <linux/time.h>
+ */
+
 #include <asm/param.h>	/* for HZ */
 
 extern unsigned long event;
@@ -11,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/times.h>
-#include <linux/timex.h>
 #include <linux/rbtree.h>
 
 #include <asm/system.h>
@@ -77,7 +80,6 @@
 extern int last_pid;
 
 #include <linux/fs.h>
-#include <linux/time.h>
 #include <linux/param.h>
 #include <linux/resource.h>
 #ifdef __KERNEL__
@@ -583,15 +585,12 @@
 extern unsigned long volatile jiffies;
 extern unsigned long itimer_ticks;
 extern unsigned long itimer_next;
-extern struct timeval xtime;
 extern void do_timer(struct pt_regs *);
 
 extern unsigned int * prof_buffer;
 extern unsigned long prof_len;
 extern unsigned long prof_shift;
 
-#define CURRENT_TIME (xtime.tv_sec)
-
 extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, int nr));
 extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr));
 extern void FASTCALL(sleep_on(wait_queue_head_t *q));
Index: linux/include/linux/serial.h
diff -u linux/include/linux/serial.h:1.1.1.6 linux/include/linux/serial.h:1.1.1.6.8.1
--- linux/include/linux/serial.h:1.1.1.6	Sun Aug 18 22:12:08 2002
+++ linux/include/linux/serial.h	Mon Jan 24 21:06:32 2005
@@ -112,8 +112,6 @@
 #define ASYNC_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
 #define ASYNC_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
 
-#define ASYNC_HARDPPS_CD	0x0800	/* Call hardpps when CD goes high  */
-
 #define ASYNC_SPD_SHI	0x1000	/* Use 230400 instead of 38400 bps */
 #define ASYNC_SPD_WARP	0x1010	/* Use 460800 instead of 38400 bps */
 
@@ -124,7 +122,7 @@
 
 #define ASYNC_AUTOPROBE	 0x8000 /* Port was autoprobed by PCI or PNP code */
 
-#define ASYNC_FLAGS	0x7FFF	/* Possible legal async flags */
+#define ASYNC_FLAGS	0x77FF	/* Possible legal async flags */
 #define ASYNC_USR_MASK	0x3430	/* Legal flags that non-privileged
 				 * users can set or reset */
 
Index: linux/include/linux/sysctl.h
diff -u linux/include/linux/sysctl.h:1.1.1.12 linux/include/linux/sysctl.h:1.1.1.12.2.1
--- linux/include/linux/sysctl.h:1.1.1.12	Sat Jan 22 22:08:00 2005
+++ linux/include/linux/sysctl.h	Mon Jan 24 21:06:32 2005
@@ -124,6 +124,7 @@
 	KERN_CORE_USES_PID=52,		/* int: use core or core.%pid */
 	KERN_TAINTED=53,	/* int: various kernel tainted flags */
 	KERN_CADPID=54,		/* int: PID of the process to notify on CAD */
+	KERN_TIME=55,		/* directory: time */
  	KERN_CORE_PATTERN=56,	/* string: pattern for core-files */
 	KERN_PPC_L3CR=57,       /* l3cr register on PPC */
 	KERN_EXCEPTION_TRACE=58, /* boolean: exception trace */
@@ -131,6 +132,17 @@
 	KERN_SPARC_SCONS_PWROFF=64, /* int: serial console power-off halt */
 };
 
+/* KERN_TIME names: */
+enum
+{
+	KERN_TIME_TIMEZONE=1,		/* struct: timezone */
+	KERN_TIME_RTC_UPDATE=2,		/* int: rtc_update */
+	KERN_TIME_RTC_RUNS_LOCALTIME=3,	/* int: rtc_runs_localtime */
+	KERN_TIME_TIME_TICK=4,		/* int: time_tick */
+	KERN_TIME_TICKADJ=5,		/* int: tickadj */
+	KERN_TIME_HZ=6,			/* int: HZ */
+	KERN_TIME_PPS_VAR=99,		/* struct pps_var: pps */
+};
 
 /* CTL_VM names: */
 enum
Index: linux/include/linux/time.h
diff -u linux/include/linux/time.h:1.1.1.2 linux/include/linux/time.h:1.1.1.2.10.1
--- linux/include/linux/time.h:1.1.1.2	Fri Mar  8 21:04:44 2002
+++ linux/include/linux/time.h	Mon Jan 24 21:06:32 2005
@@ -1,8 +1,26 @@
 #ifndef _LINUX_TIME_H
 #define _LINUX_TIME_H
 
+/* 1999-02-02	Ulrich Windl
+ *	Added time related stuff from <linux/sched.h>
+ * 1999-03-10	Ulrich Windl
+ *	Complete rewrite for nanosecond resolution:  Add public
+ *	``do_nanotime'' and ``do_microtime'' function to get time offset.
+ *	Add functions from POSIX.4 (clock_{gettime,settime,getres}).
+ *	Added ``mktime()''.
+ * 1999-12-04	Ulrich Windl
+ *	Added declaration for ``rtc_update'', ``ktime_to_rtc'', and
+ *	``rtc_to_ktime''.
+ * 2000-03-31	Ulrich Windl
+ *	Make ``do_clock_gettime()'' return the offset since last update of
+ *	``xtime''.
+ * 2000-12-09	Ulrich Windl
+ *	Remove ``(*do_microtime)(void)'' as the nanoseconds seem stable.
+ */
+#include <asm/timex.h>
 #include <asm/param.h>
 #include <linux/types.h>
+#include <linux/spinlock.h>
 
 #ifndef _STRUCT_TIMESPEC
 #define _STRUCT_TIMESPEC
@@ -10,10 +28,32 @@
 	time_t	tv_sec;		/* seconds */
 	long	tv_nsec;	/* nanoseconds */
 };
+#define	CLOCK_REALTIME	0	/* currently a dummy */
+typedef int	clockid_t;	/* POSIX.4, currently dummy */
 #endif /* _STRUCT_TIMESPEC */
 
 #ifdef __KERNEL__
 
+/* elapsed timer interrupts since last processing */
+extern volatile unsigned long wall_jiffies;
+
+/* Warning: SHIFT_HZ should no longer be used; it's obsolete now! [UW] */
+#if HZ >= 24 && HZ < 48
+# define SHIFT_HZ	5
+#elif HZ >= 48 && HZ < 96
+# define SHIFT_HZ	6
+#elif HZ >= 96 && HZ < 192
+# define SHIFT_HZ	7
+#elif HZ >= 192 && HZ < 384
+# define SHIFT_HZ	8
+#elif HZ >= 384 && HZ < 768
+# define SHIFT_HZ	9
+#elif HZ >= 768 && HZ < 1536
+# define SHIFT_HZ	10
+#else
+# error You lose.
+#endif
+
 /*
  * Change timeval to jiffies, trying to avoid the
  * most obvious overflows..
@@ -48,40 +88,6 @@
 	value->tv_sec = jiffies / HZ;
 }
 
-
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
- * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
- * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
- *
- * [For the Julian calendar (which was used in Russia before 1917,
- * Britain & colonies before 1752, anywhere else before 1582,
- * and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
- *
- * This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
- */
-static inline unsigned long
-mktime (unsigned int year, unsigned int mon,
-	unsigned int day, unsigned int hour,
-	unsigned int min, unsigned int sec)
-{
-	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
-		mon += 12;		/* Puts Feb last since it has leap day */
-		year -= 1;
-	}
-
-	return (((
-		(unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
-			year*365 - 719499
-	    )*24 + hour /* now have hours */
-	  )*60 + min /* now have minutes */
-	)*60 + sec; /* finally seconds */
-}
-
 #endif /* __KERNEL__ */
 
 
@@ -98,8 +104,46 @@
 #define NFDBITS			__NFDBITS
 
 #ifdef __KERNEL__
-extern void do_gettimeofday(struct timeval *tv);
-extern void do_settimeofday(struct timeval *tv);
+/* The current time */
+extern	volatile struct timespec xtime;
+#define CURRENT_TIME (xtime.tv_sec)
+
+/*
+ * This spinlock protect us from races in SMP while playing with xtime. -arca
+ */
+extern rwlock_t xtime_lock;
+
+/* kernel time variables */
+extern long time_tick;				/* time increment (ns) */
+extern int rtc_update_slave;			/* see kernel/time.c */
+
+/* Gregorian date & time as UNIX time */
+extern unsigned long mktime(unsigned int year, unsigned int mon,
+			    unsigned int day, unsigned int hour,
+			    unsigned int min, unsigned int sec);
+/* kernel time as Gregorian components to update RTC, see kernel/time.c */
+extern void ktime_to_rtc(time_t t, int *hhmmss, int *yyyymmdd);
+/* RTC time as kernel time (uses mktime). */
+time_t rtc_to_ktime(unsigned int year, unsigned int mon,
+		    unsigned int day, unsigned int hour,
+		    unsigned int min, unsigned int sec);
+
+extern void update_wall_time(unsigned long ticks);
+/* nanoseconds since last timer interrupt (hook) */
+extern unsigned long (*do_nanotime)(void);
+
+/* compensate a systematic clockerror of `freq' / 1000 PPM */
+extern	void update_nanoscale(long freq);
+
+extern void do_gettimeofday(struct timeval *tvp);
+extern void do_settimeofday(const struct timeval *tvp);
+extern unsigned long do_clock_gettime(clockid_t sysclock, struct timespec *tsp);
+extern void do_clock_settime(clockid_t sysclock, const struct timespec *tsp);
+extern void do_clock_getres(clockid_t sysclock, struct timespec *tsp);
+#ifdef CONFIG_NTP_PPS	/* handle PPS pulse */
+extern void hardpps(const struct timespec *p_ts, long nsec);
+#endif
+extern void timevar_init(void);		/* initialize kernel time variables */
 #endif
 
 #define FD_SETSIZE		__FD_SETSIZE
Index: linux/include/linux/timepps.h
diff -u /dev/null linux/include/linux/timepps.h:1.2.8.1
--- /dev/null	Mon Jan 24 21:14:18 2005
+++ linux/include/linux/timepps.h	Mon Jan 24 21:06:32 2005
@@ -0,0 +1,230 @@
+/* Interface to the PPS API described in RFC 2783 (March 2000)
+ *
+ * Copyright (c) 1999, 2001 by Ulrich Windl,
+ * 	based on code by Reg Clemens <reg@dwf.com>
+ *		based on code by Poul-Henning Kamp <phk@FreeBSD.org>
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ---------------------------------------------------------------------------- */
+
+#ifndef _SYS_TIMEPPS_H_
+#define _SYS_TIMEPPS_H_
+
+/* Implementation note: the logical states ``assert'' and ``clear''
+ * are implemented in terms of the UART register, i.e. ``assert''
+ * means the bit is set.
+ */
+
+/*---- 3.2 New data structures ----*/
+#define PPS_API_VERS_1	1		/* draft-05, dated 1999-08 */
+
+typedef int pps_handle_t;	 	/* represents a PPS source */
+
+typedef unsigned long pps_seq_t;	/* sequence number */
+
+typedef struct ntp_fp {
+	unsigned int	integral;
+	unsigned int	fractional;
+} ntp_fp_t;				/* NTP-compatible time stamp */
+
+typedef union pps_timeu {
+	struct timespec	tspec;
+	ntp_fp_t	ntpfp;
+	unsigned long	longpad[3];
+} pps_timeu_t;		/* generic data type to represent time stamps */
+
+typedef struct pps_info {
+	pps_seq_t	assert_sequence;	/* seq. num. of assert event */
+	pps_seq_t	clear_sequence;		/* seq. num. of clear event */
+	pps_timeu_t	assert_tu;		/* time of assert event */
+	pps_timeu_t	clear_tu;		/* time of clear event */
+	int		current_mode;		/* current mode bits */
+} pps_info_t;
+
+#define assert_timestamp        assert_tu.tspec
+#define clear_timestamp         clear_tu.tspec
+
+#define assert_timestamp_ntpfp  assert_tu.ntpfp
+#define clear_timestamp_ntpfp   clear_tu.ntpfp
+
+typedef struct pps_params {
+	int		api_version;	/* API version # */
+	int		mode;		/* mode bits */
+	pps_timeu_t assert_off_tu;	/* offset compensation for assert */
+	pps_timeu_t clear_off_tu;	/* offset compensation for clear */
+} pps_params_t;
+
+#define assert_offset   assert_off_tu.tspec
+#define clear_offset    clear_off_tu.tspec
+
+#define assert_offset_ntpfp     assert_off_tu.ntpfp
+#define clear_offset_ntpfp      clear_off_tu.ntpfp
+
+/*---- 3.3 Mode bit definitions ----*/
+/*-- Device/implementation parameters --*/
+#define PPS_CAPTUREASSERT	0x01	/* capture assert events */
+#define PPS_CAPTURECLEAR	0x02	/* capture clear events */
+#define PPS_CAPTUREBOTH		0x03	/* capture assert and clear events */
+
+#define PPS_OFFSETASSERT	0x10	/* apply compensation for assert ev. */
+#define PPS_OFFSETCLEAR		0x20	/* apply compensation for clear ev. */
+
+#define PPS_CANWAIT		0x100	/* Can we wait for an event? */
+#define PPS_CANPOLL		0x200	/* "This bit is reserved for
+                                           future use." */
+
+/*-- Kernel actions --*/
+#define PPS_ECHOASSERT		0x40	/* feed back assert event to output */
+#define PPS_ECHOCLEAR		0x80	/* feed back clear event to output */
+
+/*-- Timestamp formats --*/
+#define PPS_TSFMT_TSPEC		0x1000	/* select timespec format */
+#define PPS_TSFMT_NTPFP		0x2000	/* select NTP format */
+
+/*---- 3.4.4 New functions: disciplining the kernel timebase ----*/
+/*-- Kernel consumers --*/
+#define PPS_KC_HARDPPS		0	/* hardpps() (or equivalent) */
+#define PPS_KC_HARDPPS_PLL	1	/* hardpps() constrained to
+					   use a phase-locked loop */
+#define PPS_KC_HARDPPS_FLL	2	/* hardpps() constrained to
+					   use a frequency-locked loop */
+
+/*------ Here begins the implementation-specific part! ------*/
+struct pps_fetch_args {
+	int		tsformat;
+	struct timespec	timeout;
+	pps_info_t	pps_info_buf;
+};
+
+struct pps_bind_args {
+	int		tsformat;	/* format of time stamps */
+	int		edge;		/* selected event type */
+	int		consumer;	/* selected kernel consumer */
+};
+
+/* check Documentation/ioctl-number.txt! */
+#define PPS_IOC_CREATE		_IO('1', 1)
+#define PPS_IOC_DESTROY		_IO('1', 2)
+#define PPS_IOC_SETPARMS	_IOW('1', 3, pps_params_t)
+#define PPS_IOC_GETPARMS	_IOR('1', 4, pps_params_t)
+#define PPS_IOC_GETCAP		_IOR('1', 5, int)
+#define PPS_IOC_FETCH		_IOWR('1', 6, struct pps_fetch_args)
+#define PPS_IOC_KC_BIND		_IOW('1', 7, struct pps_bind_args)
+
+#ifdef __KERNEL__
+
+#include <linux/ioctl.h>
+
+#define PPSCLOCK_MAGIC 0x5003	/* check Documentation/magic-number.txt! */
+
+struct pps_state {
+	pps_params_t	parm;		/* PPS parameters */
+	pps_info_t	info;		/* PPS information */
+	int		cap;		/* PPS capabilities */
+	long		ecount;		/* interpolation offset of event */
+	struct timespec	etime;		/* kernel time of event */
+	wait_queue_head_t ewait;	/* wait queue for event */
+};
+
+struct pps {
+	int     magic;			/* magic number */
+	struct  pps_state       state;	/* data */
+};
+
+/* state variables to bind kernel consumer */
+/* PPS API (RFC 2783): current source and mode for ``kernel consumer'' */
+extern	void	*pps_kc_hardpps_dev;	/* some unique pointer to device */
+extern	int	pps_kc_hardpps_mode;	/* mode bits for kernel consumer */
+
+#else /* !KERNEL */
+
+#include	<sys/ioctl.h>
+
+/*---- 3.4 Functions ----*/
+
+/* create PPS handle from file descriptor */
+static __inline int time_pps_create(int filedes, pps_handle_t *handle)
+{
+	int error;
+
+	error = ioctl(filedes, PPS_IOC_CREATE, 0);
+	if (error < 0) {
+		*handle = -1;
+		return (-1);
+	}
+	*handle = filedes;
+	return (0);
+}
+
+/* release PPS handle */
+static __inline int time_pps_destroy(pps_handle_t handle)
+{
+	return (ioctl(handle, PPS_IOC_DESTROY, 0));
+}
+
+/* set parameters for handle */
+static __inline int time_pps_setparams(pps_handle_t handle,
+				       const pps_params_t *ppsparams)
+{
+	if (ppsparams->api_version != PPS_API_VERS_1) {
+		/* This is ugly, but there was no reasonable consensus
+                   in the API working group.  I require
+                   ``api_version'' to be set!
+		*/
+		((pps_params_t *) ppsparams)->api_version = PPS_API_VERS_1;
+	}
+
+	return (ioctl(handle, PPS_IOC_SETPARMS, ppsparams));
+}
+
+/* get parameters for handle */
+static __inline int time_pps_getparams(pps_handle_t handle,
+				       pps_params_t *ppsparams)
+{
+	return (ioctl(handle, PPS_IOC_GETPARMS, ppsparams));
+}
+
+/* get capabilities for handle */
+static __inline int time_pps_getcap(pps_handle_t handle, int *mode)
+{
+	return (ioctl(handle, PPS_IOC_GETCAP, mode));
+}
+
+/* current event for handle */
+static __inline int time_pps_fetch(pps_handle_t handle, const int tsformat,
+				   pps_info_t *ppsinfobuf,
+				   const struct timespec *timeout)
+{
+	int error;
+	struct pps_fetch_args arg;
+
+	arg.tsformat = tsformat;
+	if (timeout)
+		arg.timeout = *timeout;
+	else	/* wait forever */
+		arg.timeout.tv_sec = arg.timeout.tv_nsec = -1;
+	error = ioctl(handle, PPS_IOC_FETCH, &arg);
+	*ppsinfobuf = arg.pps_info_buf;
+	return (error);
+}
+
+/* specify kernel consumer */
+static __inline int time_pps_kcbind(pps_handle_t handle,
+				    const int kernel_consumer,
+				    const int edge, const int tsformat)
+{
+	int error;
+	struct pps_bind_args arg;
+
+	arg.tsformat = tsformat;
+	arg.edge = edge;
+	arg.consumer = kernel_consumer;
+	error = ioctl(handle, PPS_IOC_KC_BIND, &arg);
+	return(error);
+}
+
+#endif /* !KERNEL */
+#endif /* _SYS_TIMEPPS_H_ */
Index: linux/include/linux/timex.h
diff -u linux/include/linux/timex.h:1.1.1.2 linux/include/linux/timex.h:1.1.1.2.14.1
--- linux/include/linux/timex.h:1.1.1.2	Sat Jul 28 22:53:54 2001
+++ linux/include/linux/timex.h	Mon Jan 24 21:06:32 2005
@@ -1,28 +1,54 @@
-/*****************************************************************************
- *                                                                           *
- * Copyright (c) David L. Mills 1993                                         *
- *                                                                           *
- * Permission to use, copy, modify, and distribute this software and its     *
- * documentation for any purpose and without fee is hereby granted, provided *
- * that the above copyright notice appears in all copies and that both the   *
- * copyright notice and this permission notice appear in supporting          *
- * documentation, and that the name University of Delaware not be used in    *
- * advertising or publicity pertaining to distribution of the software       *
- * without specific, written prior permission.  The University of Delaware   *
- * makes no representations about the suitability this software for any      *
- * purpose.  It is provided "as is" without express or implied warranty.     *
- *                                                                           *
- *****************************************************************************/
+/***********************************************************************
+ *								       *
+ * Copyright (c) David L. Mills 1993-2000			       *
+ *								       *
+ * Permission to use, copy, modify, and distribute this software and   *
+ * its documentation for any purpose and without fee is hereby	       *
+ * granted, provided that the above copyright notice appears in all    *
+ * copies and that both the copyright notice and this permission       *
+ * notice appear in supporting documentation, and that the name        *
+ * University of Delaware not be used in advertising or publicity      *
+ * pertaining to distribution of the software without specific,	       *
+ * written prior permission. The University of Delaware makes no       *
+ * representations about the suitability this software for any	       *
+ * purpose. It is provided "as is" without express or implied	       *
+ * warranty.							       *
+ *								       *
+ **********************************************************************/
 
 /*
  * Modification history timex.h
  *
- * 29 Dec 97	Russell King
+ *---- BEGIN Linux specific changes (latest on top)
+ * 2000-10-14	Ulrich Windl
+ *	Add declaration for ``adjtimex()''.
+ * 1999-11-11	Ulrich Windl
+ *	Updated for ``nanokernel-19990829'': Introduced ``NTP_API'',
+ *	``MOD_PPSMAX''.  Dropped ``MOD_PLL'' and ``MOD_FLL''.  The old ``NANO''
+ *	is named ``NTP_NANO'' now.  ``NTP_PHASE_LIMIT'' is nanoseconds now.
+ * 1999-02-26	Ulrich Windl
+ *	Updated file for new ``nanokernel'' preferred for NTPv4.  Tried to
+ *	keep very close to Dave Mills' code.  Changed `tick' to `time_tick'
+ *	(ns now).  Adjusted several other definitions.
+ * 1999-01-24	Ulrich Windl
+ *	Activated new field ``tickadj''
+ * 1997-08-30	Ulrich Windl
+ *	Added new constant NTP_PHASE_LIMIT
+ * 1997-12-29	Russell King
  *	Moved CLOCK_TICK_RATE, CLOCK_TICK_FACTOR and FINETUNE to asm/timex.h
  *	for ARM machines
+ * 1995-08-13	Torsten Duwe
+ *	kernel PLL updated to 1994-12-13 specs (RFC-1589)
+ * 1993-10-07	Torsten Duwe
+ *	Derived linux/timex.h
+ *---- END Linux specific changes
+ *
+ * 16 Aug 00	David L. Mills
+ *	API Version 4. Added MOD_TAI and tai member of ntptimeval
+ *	structure.
  *
- *  9 Jan 97    Adrian Sun
- *      Shifted LATCH define to allow access to alpha machines.
+ * 17 Nov 98	David L. Mills
+ *	Revised for nanosecond kernel and user interface.
  *
  * 26 Sep 94	David L. Mills
  *	Added defines for hybrid phase/frequency-lock loop.
@@ -40,175 +66,103 @@
  *	interval.
  *
  * 17 Sep 93    David L. Mills
- *      Created file $NTP/include/sys/timex.h
- * 07 Oct 93    Torsten Duwe
- *      Derived linux/timex.h
- * 1995-08-13    Torsten Duwe
- *      kernel PLL updated to 1994-12-13 specs (rfc-1589)
- * 1997-08-30    Ulrich Windl
- *      Added new constant NTP_PHASE_LIMIT
+ *      Created file
  */
-#ifndef _LINUX_TIMEX_H
-#define _LINUX_TIMEX_H
-
-#include <asm/param.h>
-
 /*
- * The following defines establish the engineering parameters of the PLL
- * model. The HZ variable establishes the timer interrupt frequency, 100 Hz
- * for the SunOS kernel, 256 Hz for the Ultrix kernel and 1024 Hz for the
- * OSF/1 kernel. The SHIFT_HZ define expresses the same value as the
- * nearest power of two in order to avoid hardware multiply operations.
- */
-#if HZ >= 12 && HZ < 24
-# define SHIFT_HZ	4
-#elif HZ >= 24 && HZ < 48
-# define SHIFT_HZ	5
-#elif HZ >= 48 && HZ < 96
-# define SHIFT_HZ	6
-#elif HZ >= 96 && HZ < 192
-# define SHIFT_HZ	7
-#elif HZ >= 192 && HZ < 384
-# define SHIFT_HZ	8
-#elif HZ >= 384 && HZ < 768
-# define SHIFT_HZ	9
-#elif HZ >= 768 && HZ < 1536
-# define SHIFT_HZ	10
-#else
-# error You lose.
-#endif
-
-/*
- * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen
- * for a slightly underdamped convergence characteristic. SHIFT_KH
- * establishes the damping of the FLL and is chosen by wisdom and black
- * art.
- *
- * MAXTC establishes the maximum time constant of the PLL. With the
- * SHIFT_KG and SHIFT_KF values given and a time constant range from
- * zero to MAXTC, the PLL will converge in 15 minutes to 16 hours,
- * respectively.
- */
-#define SHIFT_KG 6		/* phase factor (shift) */
-#define SHIFT_KF 16		/* PLL frequency factor (shift) */
-#define SHIFT_KH 2		/* FLL frequency factor (shift) */
-#define MAXTC 6			/* maximum time constant (shift) */
-
-/*
- * The SHIFT_SCALE define establishes the decimal point of the time_phase
- * variable which serves as an extension to the low-order bits of the
- * system clock variable. The SHIFT_UPDATE define establishes the decimal
- * point of the time_offset variable which represents the current offset
- * with respect to standard time. The FINEUSEC define represents 1 usec in
- * scaled units.
- *
- * SHIFT_USEC defines the scaling (shift) of the time_freq and
- * time_tolerance variables, which represent the current frequency
- * offset and maximum frequency tolerance.
- *
- * FINEUSEC is 1 us in SHIFT_UPDATE units of the time_phase variable.
- */
-#define SHIFT_SCALE 22		/* phase scale (shift) */
-#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */
-#define SHIFT_USEC 16		/* frequency offset scale (shift) */
-#define FINEUSEC (1L << SHIFT_SCALE) /* 1 us in phase units */
-
-#define MAXPHASE 512000L        /* max phase error (us) */
-#define MAXFREQ (512L << SHIFT_USEC)  /* max frequency error (ppm) */
-#define MAXTIME (200L << PPS_AVG) /* max PPS error (jitter) (200 us) */
-#define MINSEC 16L              /* min interval between updates (s) */
-#define MAXSEC 1200L            /* max interval between updates (s) */
-#define	NTP_PHASE_LIMIT	(MAXPHASE << 5)	/* beyond max. dispersion */
-
-/*
- * The following defines are used only if a pulse-per-second (PPS)
- * signal is available and connected via a modem control lead, such as
- * produced by the optional ppsclock feature incorporated in the Sun
- * asynch driver. They establish the design parameters of the frequency-
- * lock loop used to discipline the CPU clock oscillator to the PPS
- * signal.
- *
- * PPS_AVG is the averaging factor for the frequency loop, as well as
- * the time and frequency dispersion.
- *
- * PPS_SHIFT and PPS_SHIFTMAX specify the minimum and maximum
- * calibration intervals, respectively, in seconds as a power of two.
- *
- * PPS_VALID is the maximum interval before the PPS signal is considered
- * invalid and protocol updates used directly instead.
- *
- * MAXGLITCH is the maximum interval before a time offset of more than
- * MAXTIME is believed.
- */
-#define PPS_AVG 2		/* pps averaging constant (shift) */
-#define PPS_SHIFT 2		/* min interval duration (s) (shift) */
-#define PPS_SHIFTMAX 8		/* max interval duration (s) (shift) */
-#define PPS_VALID 120		/* pps signal watchdog max (s) */
-#define MAXGLITCH 30		/* pps signal glitch max (s) */
-
-/*
- * Pick up the architecture specific timex specifications
+ * This header file defines the Network Time Protocol (NTP) interfaces
+ * for user and daemon application programs. These are implemented using
+ * defined syscalls and data structures and require specific kernel
+ * support.
+ *
+ * The original precision time kernels developed from 1993 have an
+ * ultimate resolution of one microsecond; however, the most recent
+ * kernels have an ultimate resolution of one nanosecond. In these
+ * kernels, a ntp_adjtime() syscalls can be used to determine which
+ * resolution is in use and to select either one at any time. The
+ * resolution selected affects the scaling of certain fields in the
+ * ntp_gettime() and ntp_adjtime() syscalls, as described below.
+ *
+ * NAME
+ *	ntp_gettime - NTP user application interface
+ *
+ * SYNOPSIS
+ *	#include <sys/timex.h>
+ *
+ *	int ntp_gettime(struct ntptimeval *tptr);
+ *
+ * DESCRIPTION
+ *	The time returned by ntp_gettime() is in a timeval structure,
+ *	but may be in either microsecond (seconds and microseconds) or
+ *	nanosecond (seconds and nanoseconds) format. The particular
+ *	format in use is determined by the STA_NANO bit of the status
+ *	word returned by the ntp_adjtime() syscall.
+ *
+ * NAME
+ *	ntp_adjtime - NTP daemon application interface
+ *
+ * SYNOPSIS
+ *	#include <sys/timex.h>
+ *
+ *	int ntp_adjtime(struct timex *tptr);
+ *
+ * DESCRIPTION
+ *	Certain fields of the timex structure are interpreted in either
+ *	microseconds or nanoseconds according to the state of the
+ *	STA_NANO bit in the status word. See the description below for
+ *	further information.
  */
-#include <asm/timex.h>
-
-/* LATCH is used in the interval timer and ftape setup. */
-#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
-
-/*
- * syscall interface - used (mainly by NTP daemon)
- * to discipline kernel clock oscillator
- */
-struct timex {
-	unsigned int modes;	/* mode selector */
-	long offset;		/* time offset (usec) */
-	long freq;		/* frequency offset (scaled ppm) */
-	long maxerror;		/* maximum error (usec) */
-	long esterror;		/* estimated error (usec) */
-	int status;		/* clock command/status */
-	long constant;		/* pll time constant */
-	long precision;		/* clock precision (usec) (read only) */
-	long tolerance;		/* clock frequency tolerance (ppm)
-				 * (read only)
-				 */
-	struct timeval time;	/* (read only) */
-	long tick;		/* (modified) usecs between clock ticks */
-
-	long ppsfreq;           /* pps frequency (scaled ppm) (ro) */
-	long jitter;            /* pps jitter (us) (ro) */
-	int shift;              /* interval duration (s) (shift) (ro) */
-	long stabil;            /* pps stability (scaled ppm) (ro) */
-	long jitcnt;            /* jitter limit exceeded (ro) */
-	long calcnt;            /* calibration intervals (ro) */
-	long errcnt;            /* calibration errors (ro) */
-	long stbcnt;            /* stability limit exceeded (ro) */
-
-	int  :32; int  :32; int  :32; int  :32;
-	int  :32; int  :32; int  :32; int  :32;
-	int  :32; int  :32; int  :32; int  :32;
-};
+#ifndef _LINUX_TIMEX_H
+#define _LINUX_TIMEX_H
 
+#define	NTP_API		4	/* NTP API version */
 /*
- * Mode codes (timex.mode)
- */
-#define ADJ_OFFSET		0x0001	/* time offset */
-#define ADJ_FREQUENCY		0x0002	/* frequency offset */
-#define ADJ_MAXERROR		0x0004	/* maximum time error */
-#define ADJ_ESTERROR		0x0008	/* estimated time error */
-#define ADJ_STATUS		0x0010	/* clock status */
-#define ADJ_TIMECONST		0x0020	/* pll time constant */
-#define ADJ_TICK		0x4000	/* tick value */
-#define ADJ_OFFSET_SINGLESHOT	0x8001	/* old-fashioned adjtime */
-
-/* xntp 3.4 compatibility names */
-#define MOD_OFFSET	ADJ_OFFSET
-#define MOD_FREQUENCY	ADJ_FREQUENCY
-#define MOD_MAXERROR	ADJ_MAXERROR
-#define MOD_ESTERROR	ADJ_ESTERROR
-#define MOD_STATUS	ADJ_STATUS
-#define MOD_TIMECONST	ADJ_TIMECONST
-#define MOD_CLKB	ADJ_TICK
-#define MOD_CLKA	ADJ_OFFSET_SINGLESHOT /* 0x8000 in original */
-
+ * The following defines establish the performance envelope of the
+ * kernel discipline loop. Phase or frequency errors greater than
+ * NAXPHASE or MAXFREQ are clamped to these maxima. For update intervals
+ * less than MINSEC, the loop always operates in PLL mode; while, for
+ * update intervals greater than MAXSEC, the loop always operates in FLL
+ * mode. Between these two limits the operating mode is selected by the
+ * STA_FLL bit in the status word.
+ */
+#define MAXPHASE	500000000L /* max phase error (ns) */
+#define MAXFREQ		500000L	/* max freq error (ns/s) */
+#define MINSEC		256	/* min FLL update interval (s) */
+#define MAXSEC		2048	/* max PLL update interval (s) */
+#define NANOSECOND	1000000000L /* nanoseconds in one second */
+#define SCALE_PPM	(65536 / 1000) /* crude ns/s to scaled PPM */
+#define MAXTC		10	/* max time constant */
+
+/*
+ * The following defines and structures define the user interface for
+ * the ntp_gettime() and ntp_adjtime() syscalls.
+ *
+ * Control mode codes (timex.modes)
+ */
+#define MOD_OFFSET	0x0001	/* set time offset */
+#define MOD_FREQUENCY	0x0002	/* set frequency offset */
+#define MOD_MAXERROR	0x0004	/* set maximum time error */
+#define MOD_ESTERROR	0x0008	/* set estimated time error */
+#define MOD_STATUS	0x0010	/* set clock status bits */
+#define MOD_TIMECONST	0x0020	/* set PLL time constant */
+#define MOD_PPSMAX	0x0040	/* set PPS maximum averaging interval */
+#define MOD_TAI		0x0080	/* set TAI offset */
+#define	MOD_MICRO	0x1000	/* select microsecond resolution */
+#define	MOD_NANO	0x2000	/* select nanosecond resolution */
+#define MOD_CLKB	0x4000	/* select clock B */
+#define MOD_CLKA	0x8000	/* select clock A */
+
+/*
+ * Here are the additional bits for adjtimex().  They all start with
+ * ``ADJ_''.  Some of these bits were different in the old adjtimex(), thus
+ * not all old binaries will work!!!
+ * We've learned the lesson and allocate bits from the other end now!
+ * As the `ADJ_OFFSET_SINGLESHOT' is the candidate that will most likely
+ * cause trouble, take the chance and replace that ugly name with
+ * `ADJ_ADJTIME'.
+ */
+#define ADJ_ADJTIME	0x80000000	/* plain old adjtime() */
+#define ADJ_TIMETICK	0x40000000	/* set new value for  `time_tick' */
+#define ADJ_TICKADJ	0x20000000	/* set new value for `tickadj' */
 
 /*
  * Status codes (timex.status)
@@ -216,7 +170,7 @@
 #define STA_PLL		0x0001	/* enable PLL updates (rw) */
 #define STA_PPSFREQ	0x0002	/* enable PPS freq discipline (rw) */
 #define STA_PPSTIME	0x0004	/* enable PPS time discipline (rw) */
-#define STA_FLL		0x0008	/* select frequency-lock mode (rw) */
+#define STA_FLL		0x0008	/* enable FLL mode (rw) */
 
 #define STA_INS		0x0010	/* insert leap (rw) */
 #define STA_DEL		0x0020	/* delete leap (rw) */
@@ -229,62 +183,173 @@
 #define STA_PPSERROR	0x0800	/* PPS signal calibration error (ro) */
 
 #define STA_CLOCKERR	0x1000	/* clock hardware fault (ro) */
+#define STA_NANO	0x2000	/* resolution (0 = us, 1 = ns) (ro) */
+#define STA_MODE	0x4000	/* mode (0 = PLL, 1 = FLL) (ro) */
+#define STA_CLK		0x8000	/* clock source (0 = A, 1 = B) (ro) */
 
 #define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \
-    STA_PPSERROR | STA_CLOCKERR) /* read-only bits */
+    STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK)
 
 /*
  * Clock states (time_state)
  */
-#define TIME_OK		0	/* clock synchronized, no leap second */
-#define TIME_INS	1	/* insert leap second */
-#define TIME_DEL	2	/* delete leap second */
+#define TIME_OK		0	/* no leap second warning */
+#define TIME_INS	1	/* insert leap second warning */
+#define TIME_DEL	2	/* delete leap second warning */
 #define TIME_OOP	3	/* leap second in progress */
 #define TIME_WAIT	4	/* leap second has occurred */
-#define TIME_ERROR	5	/* clock not synchronized */
-#define TIME_BAD	TIME_ERROR /* bw compat */
+#define TIME_ERROR	5	/* error (see status word) */
+
+/*
+ * NTP user interface (ntp_gettime()) - used to read kernel clock values
+ *
+ * Note: The time member is in microseconds if STA_NANO is zero and
+ * nanoseconds if not.  Depending on whether ``NANO'' is defined when
+ * including this file, the same memory location can be accessed under two
+ * different names.  ``STA_NANO'' at runtime should correspond with ``NANO''
+ * at compilation time.
+ */
+struct ntptimeval {
+#ifdef NTP_NANO
+	struct timespec time;	/* current time (ns) (ro) */
+#else
+	struct timeval time;	/* current time (us) (ro) */
+#endif /* NTP_NANO */
+	long maxerror;		/* maximum error (us) (ro) */
+	long esterror;		/* estimated error (us) (ro) */
+	long tai;		/* TAI offset */
+};
 
+/*
+ * NTP daemon interface (ntp_adjtime()) - used to discipline CPU clock
+ * oscillator and determine status.
+ *
+ * Note: The offset, precision and jitter members are in microseconds if
+ * STA_NANO is zero and nanoseconds if not.
+ */
+/*
+ * In Linux ntp_gettime(), ntp_adjtime(), and adjtime() use a common
+ * ``struct timex'' that is a superset of Dave Mills' structure.
+ */
+struct timex {
+	unsigned int modes;	/* clock mode bits (wo) */
+	long	offset;		/* time offset (ns/us) (rw) */
+	long	freq;		/* frequency offset (scaled PPM) (rw) */
+	long	maxerror;	/* maximum error (us) (rw) */
+	long	esterror;	/* estimated error (us) (rw) */
+	int	status;		/* clock status bits (rw) */
+	long	constant;	/* poll interval (log2 s) (rw) */
+	long	precision;	/* clock precision (ns/us) (ro) */
+	long	tolerance;	/* clock frequency tolerance (scaled
+				 * PPM) (ro) */
+	/*----BEGIN Linux extensions (part 1) */
+	/* Depending on whether ``NTP_NANO'' is defined when including
+	 * this file, the same memory location can be accessed under
+	 * two different names.  ``STA_NANO'' at runtime should
+	 * correspond with ``NTP_NANO'' at compilation time.
+	 */
+#ifdef NTP_NANO
+	struct timespec time;	/* current time (ns) (ro) */
+#else
+	struct timeval time;	/* current time (us) (ro) */
+#endif /* NTP_NANO */
+	long	time_tick;	/* time increment per tick (?) (rw) */
+	/*----END Linux extensions (part 1) */
+	/*
+	 * The following read-only structure members are implemented
+	 * only if the PPS signal discipline is configured in the
+	 * kernel. They are included in all configurations to insure
+	 * portability.
+	 */
+	long	ppsfreq;	/* PPS frequency (scaled PPM) (ro) */
+	long	jitter;		/* PPS jitter (ns/us) (ro) */
+	int	shift;		/* interval duration (s) (shift) (ro) */
+	long	stabil;		/* PPS stability (scaled PPM) (ro) */
+	long	jitcnt;		/* jitter limit exceeded (ro) */
+	long	calcnt;		/* calibration intervals (ro) */
+	long	errcnt;		/* calibration errors (ro) */
+	long	stbcnt;		/* stability limit exceeded (ro) */
+	/*----BEGIN Linux extensions (part 2) */
+	/* first we reserve some space, then we add our new stuff */
+	/* Yes, it's ugly, but it's binary compatible */
+	long	tai;		/* TAI offset */
+	int  :32; int  :32; int  :32;
+	int	tickadj;	/* tickadj (us) (rw) -- extension by UW */
+	int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+	/*----END Linux extensions (part 2) */
+};
+
+extern int adjtimex(struct timex *txc);	/* Linux-specific, try to avoid! */
+
+#if 0 /* This will break some libraries */
+#define	LINUX_PROVIDES_NTP_INTERFACE	/* but give the guys a chance */
+#define	ntp_adjtime	adjtimex	/* that one is easy */
+
+inline	int ntp_gettime(struct ntptimeval *ntv)
+{
+	struct timex	tntx;
+	int		result;
+	tntx.modes = 0;
+	result = __adjtimex (&tntx);
+	ntv->time = tntx.time;
+	ntv->maxerror = tntx.maxerror;
+	ntv->esterror = tntx.esterror;
+	return(result);
+}
+
+/* Adjust the current time of day by the amount in DELTA.  If OLDDELTA
+ * is not NULL, it is filled in with the amount of time adjustment
+ * remaining to be done from the last `adjtime' call.  This call is
+ * restricted to the super-user.
+ */
+/* This is a simple-minded implementation! */
+inline	int adjtime (const struct timeval *delta, struct timeval *olddelta)
+{
+	struct timex	tntx;
+	int		result;
+	if (delta) {
+		struct timeval tmp;
+
+		/* We enforce some arbitrary (2000s) limit here. */
+		tmp.tv_sec = delta->tv_sec + delta->tv_usec / 1000000L;
+		tmp.tv_usec = delta->tv_usec % 1000000L;
+		if (tmp.tv_sec > 2000 || tmp.tv_sec < -2000) {
+			return -1;
+		}
+		tntx.offset = tmp.tv_usec + tmp.tv_sec * 1000000L;
+		tntx.modes = ADJ_ADJTIME;
+	}
+	else
+		tntx.modes = 0;
+	result = __adjtimex (&tntx);
+	if (result >= 0 && olddelta) {
+		if (tntx.offset < 0) {
+			olddelta->tv_usec = -(-tntx.offset % 1000000);
+			olddelta->tv_sec  = -(-tntx.offset / 1000000);
+		} else {
+			olddelta->tv_usec = tntx.offset % 1000000;
+			olddelta->tv_sec  = tntx.offset / 1000000;
+		}
+	}
+	return result;
+}
+#endif
 #ifdef __KERNEL__
 /*
- * kernel variables
- * Note: maximum error = NTP synch distance = dispersion + delay / 2;
- * estimated error = NTP dispersion.
- */
-extern long tick;                      /* timer interrupt period */
-extern int tickadj;			/* amount of adjustment per tick */
-
-/*
- * phase-lock loop variables
- */
-extern int time_state;		/* clock status */
-extern int time_status;		/* clock synchronization status bits */
-extern long time_offset;	/* time adjustment (us) */
-extern long time_constant;	/* pll time constant */
-extern long time_tolerance;	/* frequency tolerance (ppm) */
-extern long time_precision;	/* clock precision (us) */
-extern long time_maxerror;	/* maximum error */
-extern long time_esterror;	/* estimated error */
-
-extern long time_phase;		/* phase offset (scaled us) */
-extern long time_freq;		/* frequency offset (scaled ppm) */
-extern long time_adj;		/* tick adjust (scaled 1 / HZ) */
-extern long time_reftime;	/* time at last adjustment (s) */
-
-extern long time_adjust;	/* The amount of adjtime left */
-
-/* interface variables pps->timer interrupt */
-extern long pps_offset;		/* pps time offset (us) */
-extern long pps_jitter;		/* time dispersion (jitter) (us) */
-extern long pps_freq;		/* frequency offset (scaled ppm) */
-extern long pps_stabil;		/* frequency dispersion (scaled ppm) */
-extern long pps_valid;		/* pps signal watchdog counter */
-
-/* interface variables pps->adjtimex */
-extern int pps_shift;		/* interval duration (s) (shift) */
-extern long pps_jitcnt;		/* jitter limit exceeded */
-extern long pps_calcnt;		/* calibration intervals */
-extern long pps_errcnt;		/* calibration errors */
-extern long pps_stbcnt;		/* stability limit exceeded */
+ * Pick up the architecture specific timex specifications
+ */
+#include <asm/timex.h>
+
+/* This limit (ns) will set the clock to `unsynchronized' */
+#define	NTP_PHASE_LIMIT	(MAXPHASE << 2)
+
+#ifdef CONFIG_NTP
+extern int time_state;				/* clock state */
+extern int time_status;				/* clock status bits */
+extern long time_maxerror;			/* maximum error (us) */
+extern long time_esterror;			/* estimated error (us) */
+#endif
 
 #endif /* KERNEL */
 
Index: linux/include/linux/tty.h
diff -u linux/include/linux/tty.h:1.1.1.8 linux/include/linux/tty.h:1.1.1.8.2.1
--- linux/include/linux/tty.h:1.1.1.8	Sat Jan 22 22:08:01 2005
+++ linux/include/linux/tty.h	Mon Jan 24 21:06:32 2005
@@ -412,6 +412,9 @@
 
 /* n_tty.c */
 extern struct tty_ldisc tty_ldisc_N_TTY;
+#ifdef CONFIG_NTP_PPS
+extern struct tty_ldisc tty_ldisc_N_PPSCLOCK;
+#endif
 
 /* tty_ioctl.c */
 extern int n_tty_ioctl(struct tty_struct * tty, struct file * file,
Index: linux/kernel/ksyms.c
diff -u linux/kernel/ksyms.c:1.1.1.18 linux/kernel/ksyms.c:1.1.1.18.2.1
--- linux/kernel/ksyms.c:1.1.1.18	Sat Jan 22 21:59:13 2005
+++ linux/kernel/ksyms.c	Mon Jan 24 21:06:40 2005
@@ -23,6 +23,10 @@
 #include <linux/serial.h>
 #include <linux/locks.h>
 #include <linux/delay.h>
+#include <linux/time.h>
+#ifdef CONFIG_NTP_PPS
+#include <linux/timepps.h>
+#endif
 #include <linux/random.h>
 #include <linux/reboot.h>
 #include <linux/pagemap.h>
@@ -475,9 +479,17 @@
 EXPORT_SYMBOL(yield);
 EXPORT_SYMBOL(__cond_resched);
 EXPORT_SYMBOL(jiffies);
+/* kernel time */
 EXPORT_SYMBOL(xtime);
+EXPORT_SYMBOL(do_nanotime);
 EXPORT_SYMBOL(do_gettimeofday);
 EXPORT_SYMBOL(do_settimeofday);
+EXPORT_SYMBOL(do_clock_gettime);
+#ifdef	CONFIG_NTP_PPS
+EXPORT_SYMBOL(pps_kc_hardpps_dev);
+EXPORT_SYMBOL(pps_kc_hardpps_mode);
+EXPORT_SYMBOL(hardpps);
+#endif
 
 #if !defined(__ia64__)
 EXPORT_SYMBOL(loops_per_jiffy);
Index: linux/kernel/l_fp.h
diff -u /dev/null linux/kernel/l_fp.h:1.2.8.1
--- /dev/null	Mon Jan 24 21:14:19 2005
+++ linux/kernel/l_fp.h	Mon Jan 24 21:06:40 2005
@@ -0,0 +1,205 @@
+/***********************************************************************
+ *								       *
+ * Copyright (c) David L. Mills 1993-1998			       *
+ *								       *
+ * Permission to use, copy, modify, and distribute this software and   *
+ * its documentation for any purpose and without fee is hereby	       *
+ * granted, provided that the above copyright notice appears in all    *
+ * copies and that both the copyright notice and this permission       *
+ * notice appear in supporting documentation, and that the name	       *
+ * University of Delaware not be used in advertising or publicity      *
+ * pertaining to distribution of the software without specific,	       *
+ * written prior permission. The University of Delaware makes no       *
+ * representations about the suitability this software for any	       *
+ * purpose. It is provided "as is" without express or implied	       *
+ * warranty.							       *
+ *								       *
+ **********************************************************************/
+/*
+ * Modification history time_ops.h
+ *
+ * 23 Oct 98    David L. Mills
+ *      Created file
+ *
+ * This file contains macro sets for 64-bit arithmetic and logic
+ * operations in both 32-bit and 64-bit architectures. They are designed
+ * to use the same source code in either architecture, with all
+ * differences confined to this file. Macros adapted from the NTP
+ * distribution ntp_fp.h, original author Dennis Ferguson.
+ */
+#if !defined(NTP_L64)
+
+/*
+ * Double precision macros for 32-bit machines
+ *
+ * A 64-bit fixed-point value is represented in 32-bit architectures as
+ * two 32-bit words in the following format:
+ *
+ *    0		    1		   2		   3
+ *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |s|			Integral Part			     |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |			       Fractional Part			     |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+typedef long int32;
+typedef unsigned long u_int32;
+typedef struct {			/* basic type in two formats */
+	union {
+		u_int32 Xl_ui;
+		int32 Xl_i;
+	} Ul_i;
+	union {
+		u_int32 Xl_uf;
+		int32 Xl_f;
+	} Ul_f;
+} l_fp;
+
+#define l_ui	Ul_i.Xl_ui		/* unsigned integral part */
+#define l_i	Ul_i.Xl_i		/* signed integral part */
+#define l_uf	Ul_f.Xl_uf		/* unsigned fractional part */
+#define l_f	Ul_f.Xl_f		/* signed fractional part */
+
+#define M_ADD(r_i, r_f, a_i, a_f)	/* r += a */ \
+	do { \
+		register u_int32 lo_tmp; \
+		register u_int32 hi_tmp; \
+		\
+		lo_tmp = ((r_f) & 0xffff) + ((a_f) & 0xffff); \
+		hi_tmp = (((r_f) >> 16) & 0xffff) + (((a_f) >> 16) & \
+		    0xffff); \
+		if (lo_tmp & 0x10000) \
+			 hi_tmp++; \
+		(r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \
+		\
+		(r_i) += (a_i); \
+		if (hi_tmp & 0x10000) \
+			 (r_i)++; \
+	} while (0)
+
+#define M_SUB(r_i, r_f, a_i, a_f)	/* r -= a */ \
+	do { \
+		register u_int32 lo_tmp; \
+		register u_int32 hi_tmp; \
+		\
+		if ((a_f) == 0) { \
+			 (r_i) -= (a_i); \
+		} else { \
+			lo_tmp = ((r_f) & 0xffff) + ((-((int32)(a_f))) \
+			    & 0xffff); \
+			hi_tmp = (((r_f) >> 16) & 0xffff) \
+			    + (((-((int32)(a_f))) >> 16) & 0xffff); \
+			if (lo_tmp & 0x10000) \
+				 hi_tmp++; \
+			(r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & \
+			    0xffff); \
+			(r_i) += ~(a_i); \
+			if (hi_tmp & 0x10000) \
+				 (r_i)++; \
+		 } \
+	} while (0)
+
+#define M_NEG(v_i, v_f)  /* v = -v */ \
+	do { \
+		 if ((v_f) == 0) \
+			 (v_i) = -((int32)(v_i)); \
+		 else { \
+			 (v_f) = -((int32)(v_f)); \
+			 (v_i) = ~(v_i); \
+		 } \
+	} while (0)
+
+#define M_RSHIFT(v_i, v_f, n)		/* v >>= n */ \
+	do { \
+		if ((v_i) < 0) { \
+			M_NEG((v_i), (v_f)); \
+			if ((n) < 32) { \
+				(v_f) = ((v_f) >> (n)) | ((v_i) << \
+				    (32 - (n))); \
+				(v_i) = (v_i) >> (n); \
+			} else { \
+				(v_f) = (v_i) >> ((n) - 32); \
+				(v_i) = 0; \
+			} \
+			M_NEG((v_i), (v_f)); \
+		} else { \
+			if ((n) < 32) { \
+				(v_f) = ((v_f) >> (n)) | ((v_i) << \
+				    (32 - (n))); \
+				(v_i) = (v_i) >> (n); \
+			} else { \
+				(v_f) = (v_i) >> ((n) - 32); \
+				(v_i) = 0; \
+			} \
+		 } \
+	} while (0)
+
+#define M_MPY(v_i, v_f, m)		/* v *= m */ \
+	do { \
+		register u_int32 a, b, c, d; \
+		if ((v_i) < 0) { \
+			M_NEG((v_i), (v_f)); \
+			d = ((v_f) & 0xffff) * (m); \
+			c = ((v_f) >> 16) * (m) + (d >> 16); \
+			b = ((v_i) & 0xffff) * (m) + (c >> 16); \
+			a = ((v_i) >> 16) * (m) + (b >> 16); \
+			(v_i) = (a << 16) + (b & 0xffff); \
+			(v_f) = (c << 16) + (d & 0xffff); \
+			M_NEG((v_i), (v_f)); \
+		} else { \
+			d = ((v_f) & 0xffff) * (m); \
+			c = ((v_f) >> 16) * (m) + (d >> 16); \
+			b = ((v_i) & 0xffff) * (m) + (c >> 16); \
+			a = ((v_i) >> 16) * (m) + (b >> 16); \
+			(v_i) = (a << 16) + (b & 0xffff); \
+			(v_f) = (c << 16) + (d & 0xffff); \
+		} \
+	} while (0)
+/*
+ * Operations - u,v are 64 bits; a,n are 32 bits.
+ */
+#define L_ADD(v, u)	M_ADD((v).l_i, (v).l_uf, (u).l_i, (u).l_uf)
+#define L_SUB(v, u)	M_SUB((v).l_i, (v).l_uf, (u).l_i, (u).l_uf)
+#define L_ADDHI(v, a)	M_ADD((v).l_i, (v).l_uf, (a), 0)
+#define L_NEG(v)	M_NEG((v).l_i, (v).l_uf)
+#define L_RSHIFT(v, n)	M_RSHIFT((v).l_i, (v).l_uf, n)
+#define L_MPY(v, a)	M_MPY((v).l_i, (v).l_uf, a)
+#define L_CLR(v)	((v).l_i = (v).l_uf = 0)
+#define L_ISNEG(v)	((v).l_ui < 0)
+#define L_LINT(v, a)			/* load integral part */ \
+	do { \
+		 (v).l_i = (a); \
+		 (v).l_uf = 0; \
+	} while (0)
+#define L_GINT(v)	((v).l_i)	/* get integral part */
+
+#else /* NTP_L64 */
+
+/*
+ * Single-precision macros for 64-bit machines
+ *
+ * A 64-bit fixed-point value is represented in 62-bit architectures as
+ * a single 64-bit word, with the implied decimal point to the left of
+ * bit 32.
+ */
+typedef long long l_fp;
+#define L_ADD(v, u)	((v) += (u))
+#define L_SUB(v, u)	((v) -= (u))
+#define L_ADDHI(v, a)	((v) += (long long)(a) << 32)
+#define L_NEG(v)	((v) = -(v))
+#define L_RSHIFT(v, n) \
+	do { \
+		if ((v) < 0) \
+			(v) = -(-(v) >> (n)); \
+		else \
+			(v) = (v) >> (n); \
+	} while (0)
+#define L_MPY(v, a)	((v) *= (a))
+#define L_CLR(v)	((v) = 0)
+#define L_ISNEG(v)	((v) < 0)
+#define L_LINT(v, a)	((v) = (long long)(a) << 32)
+#define L_GINT(v)	((long) ((v) < 0 ? -(-(v) >> 32) : (v) >> 32))
+
+#endif /* NTP_L64 */
Index: linux/kernel/sysctl.c
diff -u linux/kernel/sysctl.c:1.1.1.15 linux/kernel/sysctl.c:1.1.1.15.2.1
--- linux/kernel/sysctl.c:1.1.1.15	Sat Jan 22 22:08:12 2005
+++ linux/kernel/sysctl.c	Mon Jan 24 21:06:40 2005
@@ -14,6 +14,7 @@
  * Added proc_doulongvec_minmax, 09/08/99, Carlos H. Bauer.
  * Changed linked lists to use list.h instead of lists.h, 02/24/00, Bill
  *  Wendling.
+ * Added `time' subdirectory, 11/09/99, Ulrich Windl
  * The list_for_each() macro wasn't appropriate for the sysctl loop.
  *  Removed it and replaced it with older style, 03/23/00, Bill Wendling
  */
@@ -118,6 +119,7 @@
 	{ root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
 
 static ctl_table kern_table[];
+extern ctl_table kern_time_table[];
 static ctl_table vm_table[];
 #ifdef CONFIG_NET
 extern ctl_table net_table[];
@@ -274,6 +276,7 @@
 	{KERN_S390_USER_DEBUG_LOGGING,"userprocess_debug",
 	 &sysctl_userprocess_debug,sizeof(int),0644,NULL,&proc_dointvec},
 #endif
+	{KERN_TIME, "time", NULL, 0, 0555, kern_time_table},
 #ifdef __x86_64__
 	{KERN_EXCEPTION_TRACE,"exception-trace",
 	 &exception_trace,sizeof(int),0644,NULL,&proc_dointvec},
Index: linux/kernel/time.c
diff -u linux/kernel/time.c:1.1.1.5 linux/kernel/time.c:1.1.1.5.6.1
--- linux/kernel/time.c:1.1.1.5	Sun Feb 23 18:41:52 2003
+++ linux/kernel/time.c	Mon Jan 24 21:06:40 2005
@@ -7,28 +7,193 @@
  *  time related system calls: time, stime, gettimeofday, settimeofday,
  *			       adjtime
  */
+/* The following notice is for legal reasons, and it applies to some parts
+ * of the code:
+ */
+/***********************************************************************
+ *								       *
+ * Copyright (c) David L. Mills 1993-2000			       *
+ *								       *
+ * Permission to use, copy, modify, and distribute this software and   *
+ * its documentation for any purpose and without fee is hereby	       *
+ * granted, provided that the above copyright notice appears in all    *
+ * copies and that both the copyright notice and this permission       *
+ * notice appear in supporting documentation, and that the name	       *
+ * University of Delaware not be used in advertising or publicity      *
+ * pertaining to distribution of the software without specific,	       *
+ * written prior permission. The University of Delaware makes no       *
+ * representations about the suitability this software for any	       *
+ * purpose. It is provided "as is" without express or implied	       *
+ * warranty.							       *
+ *								       *
+ **********************************************************************/
+
 /*
  * Modification history kernel/time.c
  * 
- * 1993-09-02    Philip Gladstone
- *      Created file with time related functions from sched.c and adjtimex() 
- * 1993-10-08    Torsten Duwe
- *      adjtime interface update and CMOS clock write code
- * 1995-08-13    Torsten Duwe
- *      kernel PLL updated to 1994-12-13 specs (rfc-1589)
- * 1999-01-16    Ulrich Windl
+ * 1993-09-02	Philip Gladstone
+ *	Created file with time related functions from sched.c and adjtimex() 
+ * 1993-10-08	Torsten Duwe
+ *	adjtime interface update and CMOS clock write code
+ * 1995-08-13	Torsten Duwe
+ *	kernel PLL updated to 1994-12-13 specs (RFC-1589)
+ * 1997-09-10	Ulrich Windl
+ *	Updated NTP code according to technical memorandum Jan '96
+ *	"A Kernel Model for Precision Timekeeping" by Dave Mills
+ * 1998-12-24	Andrea Arcangeli, Copyright (C) 1998
+ *	Fixed a xtime SMP race (we need the xtime_lock rw spinlock to
+ *	serialize accesses to xtime/lost_ticks).
+ * 1999-01-16	Ulrich Windl
  *	Introduced error checking for many cases in adjtimex().
  *	Updated NTP code according to technical memorandum Jan '96
  *	"A Kernel Model for Precision Timekeeping" by Dave Mills
  *	Allow time_constant larger than MAXTC(6) for NTP v4 (MAXTC == 10)
  *	(Even though the technical memorandum forbids it)
+ * 1999-01-24	Ulrich Windl
+ *	Added code to support ADJ_TICKADJ in adjtimex(). Added support for
+ *	PPS signal.
+ * 1999-01-31	Ulrich Windl
+ *	Split NTP PPS support into different levels: NTP, NTP with PPS,
+ *	NTP with PPS and serial carrier detect.  Moved time stuff from
+ *	sched.c to the place where it really belongs.
+ * 1999-05-10	Ulrich Windl
+ *	Merged in changes for new NTP clock model (`nanokernel').  Added new
+ *	do_clock_{get,set}time (see POSIX.4).  Added do_clock_getres
+ *	(see POSIX.4).  Made heavy changes to the clock model and related
+ *	variables.  Added mktime().  Fixes for the `nanokernel'.  Enforce
+ *	monotonous time.  Increased speed of adjtime() to 50ms/s.
+ * 1999-05-22	Ulrich Windl
+ *	Added dynamic tolerance estimate to ``hardpps()''.  Also be more
+ *	conservative when getting late pulses.  Optimized for fixed value
+ *	of ``hz'' (namely ``HZ'').  Fixed problem for ``MOD_CONSTANT'' in
+ *	``adjtimex()''.
+ * 1999-08-15	Ulrich Windl
+ *	Added clamping of illegal values in adjtimex() to avoid failures like
+ *	that of the Ariane-5 (ntpd does not care much about errors from
+ *	syscalls).
+ * 1999-09-17	Andrea Arcangeli <andrea@suse.de>
+ *	Fixed adjtimex/settimeofday/stime SMP races.
+ * 1999-09-27	Ulrich Windl
+ *	Make message about ``update_wall_time: ticks is 2'' conditional.
+ *	Optimize ``tick_update'' away.  Call ``second_overflow'' without delay
+ *	if multiple ticks are pending.  This may reduce nano jitter a bit.
+ *	Added dynamic spike threshold for PPS jitter detection from the latest
+ *	nanokernel (1999-08-29).  Also catch another condition for a bad pulse.
+ * 1999-10-07	Ulrich Windl
+ *	Make sure that MOD_OFFSET and ADJ_ADJTIME are not used at the same time
+ *	(to avoid ns/us confusion).
+ * 1999-11-03	Ulrich Windl
+ *	Updated clock model according to ``nanokernel-19990829'': The new
+ *	``hardpps()'' will adjust the offset and frequency quicker than the
+ *	previous version.  New ``MOD_PPSMAX'' implemented.  Changed/added some
+ *	spinlocks according to standard tree.  Enforce ``MOD_PPSMAX''.
+ * 1999-11-14	Ulrich Windl
+ *	Added sysctl for time variables.  Moved ``time_tick'' out from #ifdef.
+ *	Deleted variable ``time_tolerance''; dynamic estimate is only used for
+ *	maxerror.  Promote internal ``time_maxerror'' and ``time_esterror''
+ *	to nanoseconds.  Added new ``rtc_update'' variable to prevent automatic
+ *	updates of the CMOS clock.  Fixed some debug messages.
+ * 1999-12-04	Ulrich Windl
+ *	Corrected logic for ``rtc_update'' (was inverted).  Added new function
+ *	``ktime_to_rtc'' and ``rtc_to_ktime'' to convert between kernel time
+ *	and RTC time, depending on the timezone of the RTC (local or UTC).
+ *	The new functions obsolete ``warp_clock()''.
+ * 2000-01-05	Ulrich Windl, Harald Koenig
+ *	Fixed Y2K bug in ``ktime_to_rtc()''.
+ * 2000-01-19	Ulrich Windl
+ *	Fixed problem when ``CONFIG_NTP_PPS'' is not defined.
+ * 2000-03-29	Ulrich Windl
+ *	Fixed incorrect start condition after bad pulse in ``hardpps()''.
+ *	Fixed problem where ``NANOSECOND % HZ != 0'' (notably DEC Alpha).
+ *	``time_tick'' is no longer used when ``CONFIG_NTP'' is defined!
+ * 2000-03-31	Ulrich Windl
+ *	Changed ``do_clock_gettime()'' to return the time offset.
+ * 2000-04-16	Ulrich Windl
+ *	New ``do_nanotime()'' does not include ``lost_ticks''.
+ * 2000-04-24	Ulrich Windl
+ *	Modified condition for ``STA_PPSWANDER'' in ``hardpps()'' to use
+ *	dynamic threshold.  Converted ``tickadj'' to nanoseconds (external
+ *	interface is still using microseconds).
+ * 2000-05-01	Ulrich Windl
+ *	Undo change from 1999-04-21 (Stop ``adjtime()'' if precision
+ *	adjustments are being made).  The logic prevented ``adjtime()'' from
+ *	working when ``STA_PLL'' was set.
+ * 2000-05-16	Ulrich Windl
+ *	Revised sysctl() interface to provide range checks.  Made ``time_tick''
+ *	and ``tickadj'' writable.
+ * 2000-09-23	Ulrich Windl
+ *	Updated clock model according to ``nanokernel-20000921'' (NTP API v4):
+ *	Added support for TAI (International Atomic Time) offset.  Offsets for
+ *	``STA_PPSTIME'' are applied directly now, improving error statistics.
+ *	Fixed detection of early pulses in ``hardpps()''.
+ * 2000-12-09	Ulrich Windl
+ *	Remove use of routines dealing with microseconds explicitly.
+ * 2001-03-11	Ulrich Windl
+ *	Added spinlock for ``hardpps()'' to protect time variables.  Fixed
+ *	logic to detect negative time warps. Updated clock model according to
+ *	``nanokernel-20001025'': ``PPS_FAVGDEF'' changed form 7 to 8. Clearing
+ *	``STA_PLL'' will reset ``time_status''. Explicitly clear ``time_tai''.
+ *	Finally found and fixed the time bug introduced to Linux-2.4
+ *	(``wall_jiffies'' are not what I had thought).
+ * 2001-04-17	Ulrich Windl
+ *	Added state variables for PPS API's ``kernel consumer'' to support
+ *	different devices.
+ * 2001-05-10	Ulrich Windl
+ *	Use new ``update_nanoscale()'' when ``time_freq'' or ``time_tick''
+ *	changes.
+ * 2001-05-14	Ulrich Windl
+ *	Use ``pps.stabil'' when updating ``pps.frange'' for possibly more
+ *	accurate result.
+ * 2001-12-03	Ulrich Windl
+ *	Fix compilation for ``#ifndef CONFIG_NTP''.
+ * 2001-12-29	Ulrich Windl
+ *	Avoid returning of non-normalized time due to rounding of microseconds.
+ * 2002-10-17	Ulrich Windl, Petr Sumbera
+ *	Avoid overflow into sign for ``MOD_OFFSET'' when converting
+ *	microseconds to nanoseconds.  Added new sysctl value ``KERN_TIME_HZ''
+ *	(``Hz'') for ``HZ''.
+ * 2003-02-04	Ulrich Windl
+ *	Added missing permission check for ``sys_clock_settime()''.  Added
+ *	strategy routine to implement proper permission checks for sysctl.
+ * 2003-03-21	Ulrich Windl
+ *	Fixed bug: adjtimex() was accepting microseconds as nanoseconds,
+ *	returning nanoseconds as microseconds.  Indicate broken adjtime()
+ *	implementation with limited range.  Changed ``tickadj'' back to
+ *	microseconds (which is the granularity of adjtime() anyway).
  */
 
+#include <linux/config.h>
+#define	NTP_NANO	/* we want to see nanoseconds in <linux/timex.h> */
 #include <linux/mm.h>
+#include <linux/time.h>
 #include <linux/timex.h>
+#ifdef CONFIG_NTP_PPS
+#include <linux/timepps.h>
+#endif
+#include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/sysctl.h>
+
+#define NTP_L64	/* GNU C has `long long' with 64 bit */
+#include "l_fp.h"
 
 #include <asm/uaccess.h>
+#if defined(CONFIG_NTP_PPS_DEBUG) && defined(CONFIG_X86_TSC)
+#include <asm/msr.h>
+#endif
+
+/* The current time */
+volatile struct timespec xtime __attribute__ ((aligned (16)));
+
+/* The xtime_lock is not only serializing the xtime read/writes but it's also
+   serializing all accesses to the global NTP variables.
+   NOTE NOTE: We really need a spinlock here as the global irq locking
+   only protect us against the timer irq and not against other time-related
+   syscall running under us. */
+/*
+ * This spinlock protect us from races in SMP while playing with xtime. -arca
+ */
+rwlock_t xtime_lock = RW_LOCK_UNLOCKED;
 
 /* 
  * The timezone where the local system is located.  Used as a default by some
@@ -36,9 +201,478 @@
  */
 struct timezone sys_tz;
 
-/* The xtime_lock is not only serializing the xtime read/writes but it's also
-   serializing all accesses to the global NTP variables now. */
-extern rwlock_t xtime_lock;
+
+/* kernel time variables */
+static long time_adjust = 0;	/* remaining adjustment for adjtime() */
+
+long time_tick;			/* nanoseconds per tick (ns) */
+static	long tickadj;	/* number of microseconds to adjust time_tick */
+
+/* [extension by UW]: If ``rtc_update'' is positive then update the RTC as
+ * before, but using the value as interval between updates.
+ * ``rtc_update_slave'' will contain the value of ``rtc_update'' if the RTC
+ * clock should be updated.  Once updated, the value will be reset to zero.
+ */
+static	int rtc_update;
+int rtc_update_slave;
+
+/* [extension by UW]: If ``rtc_runs_localtime'' is non-zero, believe
+ * that the RTC uses local time.
+ */
+static	int rtc_runs_localtime = 0;
+
+#define hz HZ			/* (fixed) timer interrupt frequency */
+
+#ifdef CONFIG_NTP
+#define	ADJ_SERVED_MODE_BITS	(MOD_OFFSET|MOD_FREQUENCY|MOD_MAXERROR| \
+				 MOD_ESTERROR|MOD_STATUS|MOD_TIMECONST| \
+				 MOD_PPSMAX|MOD_TAI|MOD_MICRO|MOD_NANO| \
+				 MOD_CLKB|MOD_CLKA| \
+				 ADJ_TICKADJ|ADJ_TIMETICK|ADJ_ADJTIME)
+/*
+ * Generic NTP kernel interface
+ *
+ * These routines constitute the Network Time Protocol (NTP) interfaces
+ * for user and daemon application programs. The ntp_gettime() routine
+ * provides the time, maximum error (synch distance) and estimated error
+ * (dispersion) to client user application programs. The ntp_adjtime()
+ * routine is used by the NTP daemon to adjust the system clock to an
+ * externally derived time. The time offset and related variables set by
+ * this routine are used by other routines in this module to adjust the
+ * phase and frequency of the clock discipline loop which controls the
+ * system clock.
+ *
+ * When the kernel time is reckoned directly in nanoseconds (NTP_NANO
+ * defined), the time at each tick interrupt is derived directly from
+ * the kernel time variable. When the kernel time is reckoned in
+ * microseconds, (NTP_NANO undefined), the time is derived from the kernel
+ * time variable together with a variable representing the leftover
+ * nanoseconds at the last tick interrupt. In either case, the current
+ * nanosecond time is reckoned from these values plus an interpolated
+ * value derived by the clock routines in another architecture-specific
+ * module. The interpolation can use either a dedicated counter or a
+ * processor cycle counter (PCC) implemented in some architectures.
+ *
+ * Note that all routines must run with exclusive access to the time
+ * variables.
+ */
+/*
+ * Phase/frequency-lock loop (PLL/FLL) definitions
+ *
+ * The nanosecond clock discipline uses two variable types, time
+ * variables and frequency variables. Both types are represented as 64-
+ * bit fixed-point quantities with the decimal point between two 32-bit
+ * halves. On a 32-bit machine, each half is represented as a single
+ * word and mathematical operations are done using multiple-precision
+ * arithmetic. On a 64-bit machine, ordinary computer arithmetic is
+ * used.
+ *
+ * A time variable is a signed 64-bit fixed-point number in ns and
+ * fraction. It represents the remaining time offset to be amortized
+ * over succeeding tick interrupts. The maximum time offset is about
+ * 0.5 s and the resolution is about 2.3e-10 ns.
+ *
+ *			1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |s s s|			 ns				   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |			    fraction				   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * A frequency variable is a signed 64-bit fixed-point number in ns/s
+ * and fraction. It represents the ns and fraction to be added to the
+ * kernel time variable at each second. The maximum frequency offset is
+ * about +-500000 ns/s and the resolution is about 2.3e-10 ns/s.
+ *
+ *			1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |s s s s s s s s s s s s s|	          ns/s			   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |			    fraction				   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+/*
+ * The following variables establish the state of the PLL/FLL and the
+ * residual time and frequency offset of the local clock.
+ */
+#define SHIFT_PLL	4	/* PLL loop gain (shift) */
+#define SHIFT_FLL	2	/* FLL loop gain (shift) */
+
+int time_state;			/* clock state */
+/* bit STA_UNSYNC prevents a periodic update of the CMOS clock */
+int time_status;		/* clock status bits */
+long time_constant;		/* poll interval (shift) (s) */
+long time_tai;			/* TAI offset (s) */
+long time_monitor;		/* last time offset scaled (ns) */
+long time_precision = 1;	/* clock precision (ns) */
+long time_maxerror;		/* maximum error (ns) -- [extension by UW] */
+long time_esterror;		/* estimated error (ns) -- [extension by UW] */
+long time_reftime;		/* time at last adjustment (s) */
+l_fp time_offset;		/* time offset (ns) */
+l_fp time_freq;			/* frequency offset (ns/s) */
+l_fp time_adj;			/* tick adjust (ns/s) */
+l_fp time_phase;		/* time phase (ns) */
+
+#ifdef CONFIG_NTP_PPS
+/*
+ * The following variables are used when a pulse-per-second (PPS) signal
+ * is available and connected via a modem control lead. They establish
+ * the engineering parameters of the clock discipline loop when
+ * controlled by the PPS signal.
+ */
+#define PPS_FAVG	2	/* min freq avg interval (s) (shift) */
+#define PPS_FAVGDEF	8	/* default freq avg interval (s) (shift) */
+#define PPS_FAVGMAX	15	/* max freq avg interval (s) (shift) */
+#define PPS_PAVG	4	/* phase avg interval (s) (shift) */
+#define PPS_VALID	120	/* PPS signal watchdog max (s) */
+#define PPS_MAXWANDER	100000	/* max PPS wander (ns/s) */
+#define PPS_POPCORN	2	/* popcorn spike threshold (shift) */
+
+struct pps_var {
+	struct timespec tf[3];	/* phase median filter */
+	l_fp freq;		/* scaled frequency offset (ns/s) */
+	long lastfreq;		/* last scaled freq offset (ns/s) */
+	long fcount;		/* frequency accumulator */
+	long jitter;		/* nominal jitter (ns) */
+	long stabil;		/* nominal stability (scaled ns/s) */
+	long lastsec;		/* time of last calibration (s) */
+	int valid;		/* signal watchdog counter */
+	int shift;		/* interval duration (s) (shift) */
+	int shiftmax;		/* max interval duration (s) (shift) */
+	int intcnt;		/* interval counter */
+
+/*
+ * PPS signal quality monitors
+ */
+	long calcnt;		/* calibration intervals */
+	long jitcnt;		/* jitter limit exceeded */
+	long stbcnt;		/* stability limit exceeded */
+	long errcnt;		/* calibration errors */
+
+/* dynamic tolerance adjustment */
+	long fmin, fmax;	/* PPS frequency minimum and maximum */
+	long frange;		/* frequency range */
+};
+
+static struct pps_var pps;
+
+/* PPS API (RFC 2783): current source and mode for ``kernel consumer'' */
+void	*pps_kc_hardpps_dev = NULL;	/* some unique pointer to device */
+int	pps_kc_hardpps_mode;		/* mode bits for kernel consumer */
+#endif /* CONFIG_NTP_PPS */
+/*
+ * End of phase/frequency-lock loop (PLL/FLL) definitions
+ */
+#else	/* !CONFIG_NTP */
+#define	ADJ_SERVED_MODE_BITS	(ADJ_TICKADJ|ADJ_TIMETICK|ADJ_ADJTIME)
+#endif
+
+/* Define entries for `time' subdirectory. */
+static /* const */ int	sysctl_tz_min	= -12 * 60;
+static /* const */ int	sysctl_tz_max	=  12 * 60;
+static /* const */ int	sysctl_zero	= 0;
+static /* const */ int	sysctl_one	= 1;
+static /* const */ int	sysctl_no_max	= 1 << 30;
+static /* const */ int	sysctl_tick_min	= 9 * (NANOSECOND/10/hz);
+static /* const */ int	sysctl_tick_max	= 11 * (NANOSECOND/10/hz);
+static /* const */ int	sysctl_tickadj_max = (NANOSECOND/1000/hz) / 4;
+static /* const */ int	sysctl_hz = HZ;
+
+/* strategy routine for sysctl() */
+static int time_strategy(ctl_table *table, int *name, int nlen,
+			 void *oldval, size_t *oldlenp,
+			 void *newval, size_t newlen, void **context)
+{
+	if (!capable(CAP_SYS_TIME)) {
+		return -EPERM;
+	}
+	return 0;		/* do automatic checking */
+}
+
+ctl_table kern_time_table[] = {
+	/* Warning: ``sys_tz.tz_dsttime'' isn't checked properly */
+	{KERN_TIME_TIMEZONE, "timezone", &sys_tz, sizeof(sys_tz),
+	 0644, NULL, &proc_dointvec_minmax, &time_strategy, NULL,
+	 &sysctl_tz_min, &sysctl_tz_max},
+	{KERN_TIME_RTC_RUNS_LOCALTIME, "rtc_runs_localtime",
+	 &rtc_runs_localtime, sizeof(rtc_runs_localtime),
+	 0644, NULL, &proc_dointvec_minmax, &time_strategy, NULL,
+	 &sysctl_zero, &sysctl_one},
+	{KERN_TIME_RTC_UPDATE, "rtc_update", &rtc_update, sizeof(rtc_update),
+	 0644, NULL, &proc_dointvec_minmax, &time_strategy, NULL,
+	 &sysctl_zero, &sysctl_no_max},
+	{KERN_TIME_TIME_TICK, "time_tick", &time_tick, sizeof(time_tick),
+	 0644, NULL, &proc_dointvec_minmax, &time_strategy, NULL,
+	 &sysctl_tick_min, &sysctl_tick_max},
+	{KERN_TIME_TICKADJ, "tickadj", &tickadj, sizeof(tickadj),
+	 0644, NULL, &proc_dointvec_minmax, &time_strategy, NULL,
+	 &sysctl_one, &sysctl_tickadj_max},
+	{KERN_TIME_HZ, "Hz", &sysctl_hz, sizeof(sysctl_hz),
+	 0444, NULL, &proc_dointvec},
+#ifdef CONFIG_NTP
+#ifdef CONFIG_NTP_PPS
+	/* this entry is for debugging (experimental) */
+	{KERN_TIME_PPS_VAR, "pps", &pps, sizeof(pps),
+	 0444, NULL, &proc_dointvec},
+#endif
+#endif
+	{0}
+};
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+unsigned long
+mktime (unsigned int year, unsigned int mon,
+	unsigned int day, unsigned int hour,
+	unsigned int min, unsigned int sec)
+{
+	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
+		mon += 12;		/* Puts Feb last since it has leap day */
+		year -= 1;
+	}
+
+	return (((
+		(unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
+			year*365 - 719499
+	    )*24 + hour /* now have hours */
+	  )*60 + min /* now have minutes */
+	)*60 + sec; /* finally seconds */
+}
+
+/* Convert Gregorian calendar information from RTC to kernel time
+ * (uses mktime).
+ */
+time_t rtc_to_ktime(unsigned int year, unsigned int mon,
+		     unsigned int day, unsigned int hour,
+		     unsigned int min, unsigned int sec)
+{
+	time_t result = mktime(year, mon, day, hour, min, sec);
+	if (rtc_runs_localtime) {		/* apply effective timezone */
+		result += sys_tz.tz_minuteswest * 60;
+		if (sys_tz.tz_dsttime)
+			result -= 3600;
+	}
+	return result;
+}
+
+/* Build time and date components from system time, intended to set the RTC
+ * (based on code found in fs/fat/misc.c):
+ * ``*hhmmss = seconds + (minutes << 8) + (hour << 16)''
+ * ``*yyyymmdd = mday + (month << 8) + (year << 16)''
+ */
+void ktime_to_rtc(time_t t, int *hhmmss, int *yyyymmdd)
+{
+	/* Table to map days in year to months (non leap-years, zero-based) */
+	static int dmt[] = {
+		0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0,0,0,0
+	/*    Jan Feb Mar Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec */
+	};
+	int day, year, nl_day, month;
+	if (rtc_runs_localtime) {		/* apply effective timezone */
+		t -= sys_tz.tz_minuteswest * 60;
+		if (sys_tz.tz_dsttime)
+			t += 3600;
+	}
+	*hhmmss = (t % 60) + (((t / 60) % 60) << 8) + (((t / 3600) % 24) << 16);
+	day = t / 86400;		/* days since epoch (1970) */
+	year = day / 365;		/* non-leap years since epoch */
+	/* correct for leap years in epoch: 1972 (2) was the first */
+	if ((year + 1) / 4 + 365 * year > day)
+		year--;
+	/* reduce to day in current year */
+	day -= (year + 1) / 4 + 365 * year;
+	/* map March, 1st to Feburary, 29nd for leap years */
+	if (day == 59 && ((year + 2) & 3) == 0) {
+		nl_day = day;
+		month = 2;
+	} else {			/* determine month and day of month */
+		nl_day = ((year + 2) & 3) || day < 59 ? day : day - 1;
+		for (month = 0; month < 12; month++)
+			if (dmt[month] > nl_day)
+				break;
+	}
+	*yyyymmdd = nl_day - dmt[month - 1] + 1 + (month << 8) + ((year + 1970) << 16);
+}
+
+/*
+ * Advance to a new second, and possibly update time adjustments.
+ *
+ * The tricky bits of code to handle the accurate clock support
+ * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
+ * They were originally developed for SUN and DEC kernels.
+ * All the kudos should go to Dave for this stuff.
+ *
+ */
+static inline void second_overflow(void)
+{
+#ifdef CONFIG_NTP
+	l_fp ftemp;		/* 32/64-bit temporary */
+
+	/* Bump the maxerror field */
+#ifdef CONFIG_NTP_PPS
+	time_maxerror += pps.frange;
+#else
+	time_maxerror += MAXFREQ;
+#endif
+	if (time_maxerror > NTP_PHASE_LIMIT) {
+		time_maxerror = NTP_PHASE_LIMIT;
+		time_status |= STA_UNSYNC;
+	}
+	if (rtc_update > 0 && (time_status & STA_UNSYNC) == 0)
+		rtc_update_slave = rtc_update;
+
+	/*
+	 * Leap second processing. If in leap-insert state at
+	 * the end of the day, the system clock is set back one
+	 * second; if in leap-delete state, the system clock is
+	 * set ahead one second. The nano_time() routine or
+	 * external clock driver will insure that reported time
+	 * is always monotonic.
+	 */
+	switch (time_state) {
+
+	case TIME_OK:	/* no leap second */
+		if (time_status & STA_INS)
+			time_state = TIME_INS;
+		else if (time_status & STA_DEL)
+			time_state = TIME_DEL;
+		break;
+
+	case TIME_INS:	/* Insert second 23:59:60 following second 23:59:59. */
+		if (!(time_status & STA_INS))
+			time_state = TIME_OK;
+		else if (xtime.tv_sec % 86400 == 0) {
+			xtime.tv_sec--;
+			time_state = TIME_OOP;
+			printk(KERN_NOTICE
+			       "TIME_INS: inserting second 23:59:60 UTC\n");
+		}
+		break;
+
+	case TIME_DEL:	/* Skip second 23:59:59. */
+		if (!(time_status & STA_DEL))
+			time_state = TIME_OK;
+		else if ((xtime.tv_sec + 1) % 86400 == 0) {
+			xtime.tv_sec++;
+			time_tai--;
+			time_state = TIME_WAIT;
+			printk(KERN_NOTICE
+			       "TIME_DEL: skipping second 23:59:59 UTC\n");
+		}
+		break;
+
+	case TIME_OOP:	/* leap second insert in progress */
+		time_tai++;
+		time_state = TIME_WAIT;
+		break;
+
+	case TIME_WAIT:	/* Wait for status bits to clear. */
+		if (!(time_status & (STA_INS | STA_DEL)))
+			time_state = TIME_OK;
+	}
+
+	/*
+	 * Compute the total time adjustment for the next second
+	 * in ns. The offset is reduced by a factor depending on
+	 * whether the PPS signal is operating. Note that the
+	 * value is in effect scaled by the clock frequency,
+	 * since the adjustment is added at each tick interrupt.
+	 */
+	ftemp = time_offset;
+#ifdef CONFIG_NTP_PPS
+	if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL)
+		L_RSHIFT(ftemp, pps.shift);
+	else
+#endif
+		L_RSHIFT(ftemp, SHIFT_PLL + time_constant);
+	time_adj = ftemp;
+	L_SUB(time_offset, ftemp);
+	L_ADD(time_adj, time_freq);
+	L_ADDHI(time_adj, NANOSECOND);
+#ifdef	CONFIG_NTP_PPS
+	if (pps.valid > 0)
+		pps.valid--;
+	else
+		time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
+				 STA_PPSWANDER | STA_PPSERROR);
+#endif
+#endif /* CONFIG_NTP */
+}
+
+/* in the NTP reference this is called "hardclock()" */
+inline static void update_wall_time_one_tick(void)
+{
+	long ltemp, time_update = time_adjust;
+
+	if (time_update != 0) {
+		/* We are doing an adjtime() thing.
+		 * Clamp time_update within bounds (-tickadj .. tickadj).
+		 */
+		if (time_update > tickadj)
+			time_update = tickadj;
+		else if (time_update < -tickadj)
+			time_update = -tickadj;
+	     
+		/* Update remaining adjustment */
+		time_adjust -= time_update;
+		time_update *= 1000;	/* convert to nanoseconds */
+	}
+#ifdef CONFIG_NTP
+	/*
+	 * Update the nanosecond and microsecond clocks. If the phase
+	 * increment exceeds the tick period, update the clock phase.
+	 */
+	L_ADD(time_phase, time_adj);
+	ltemp = L_GINT(time_phase) / hz;
+	time_update += ltemp;
+	L_ADDHI(time_phase, -ltemp * hz);
+#else
+	time_update += time_tick;
+#endif
+	xtime.tv_nsec += time_update;
+}
+
+/*
+ * Using a loop looks inefficient, but "ticks" is
+ * usually just one (we shouldn't be losing ticks,
+ * we're doing this this way mainly for interrupt
+ * latency reasons, not because we think we'll
+ * have lots of lost timer ticks
+ */
+void update_wall_time(unsigned long ticks)
+{
+#ifdef CONFIG_NTP_PPS_DEBUG
+	if (ticks > 1)
+		printk(KERN_INFO "update_wall_time: ticks is %lu\n", ticks);
+#endif
+	do {
+		ticks--;
+		update_wall_time_one_tick();
+		if (xtime.tv_nsec >= NANOSECOND) {
+			xtime.tv_nsec -= NANOSECOND;
+			xtime.tv_sec++;
+			second_overflow();
+		}
+	} while (ticks);
+}
+
+/* these pointers are set up during init! */
+unsigned long (*do_nanotime)(void);
 
 #if !defined(__alpha__) && !defined(__ia64__)
 
@@ -71,7 +705,7 @@
  * architectures that need it).
  */
  
-asmlinkage long sys_stime(int * tptr)
+asmlinkage int sys_stime(int * tptr)
 {
 	int value;
 
@@ -82,18 +716,134 @@
 	write_lock_irq(&xtime_lock);
 	vxtime_lock();
 	xtime.tv_sec = value;
-	xtime.tv_usec = 0;
+	xtime.tv_nsec = 0;
 	vxtime_unlock();
 	time_adjust = 0;	/* stop active adjtime() */
+	if (rtc_update > 0)
+		rtc_update_slave = 1;	/* update the RTC clock next second */
+#ifdef CONFIG_NTP
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
+#endif
 	write_unlock_irq(&xtime_lock);
 	return 0;
 }
 
 #endif
 
+/* Get the time with theoretical nanosecond resolution */
+inline unsigned long do_clock_gettime(clockid_t sysclock, struct timespec *tsp)
+{
+	unsigned long flags;
+	unsigned long nsec, sec;
+	unsigned long result;
+	static struct timespec last;
+
+	read_lock_irqsave(&xtime_lock, flags);
+	result = do_nanotime();
+	sec = xtime.tv_sec;
+	nsec = xtime.tv_nsec + result;
+	nsec += (jiffies - wall_jiffies) * time_tick;
+	while (nsec >= NANOSECOND) {
+		nsec -= NANOSECOND;
+		sec++;
+	}
+	/* tick adjustments and interrupt delays could make the time
+         * go backwards for very short intervals.  Avoid that.
+	 */
+	if (nsec <= last.tv_nsec && sec == last.tv_sec)
+	{
+#if 1		/* [UW]: maybe remove this once debugged */
+		static	int	complaints = 100;
+
+		if (complaints > 0) {
+			--complaints;
+			printk(KERN_WARNING
+			       "do_clock_gettime: negative time warp on "
+			       "CPU#%d: %ldns (%ld,%ld)\n",
+			       smp_processor_id(), nsec - last.tv_nsec,
+			       jiffies - wall_jiffies, result);
+			if (complaints == 0)
+				printk(KERN_INFO
+				       "(won't complain any more)\n");
+		}
+#endif
+		if ((nsec = last.tv_nsec + 1) >= NANOSECOND) {
+			nsec -= NANOSECOND;
+			sec++;
+		}
+	}
+	last.tv_sec = sec;
+	last.tv_nsec = nsec;
+	read_unlock_irqrestore(&xtime_lock, flags);
+
+#ifdef CONFIG_NTP_PPS_DEBUG
+#ifdef CONFIG_SMP	/*[UW] put CPU# into time (very ugly) */
+#if NR_CPUS > 32
+#error "NR_CPUS > 32; code has to be updated"
+#endif  
+	nsec &= ~31;
+	nsec |= smp_processor_id();
+#endif	/* CONFIG_SMP */
+#endif	/* CONFIG_NTP_PPS_DEBUG */
+	tsp->tv_sec = sec;
+	tsp->tv_nsec = nsec;
+	return result;
+}
+
+/*
+ * This version of gettimeofday has better than microsecond resolution
+ * on fast x86 machines with TSC.
+ */
+void inline do_gettimeofday(struct timeval *tvp)
+{
+	struct timespec now;
+
+	do_clock_gettime(CLOCK_REALTIME, &now);
+	tvp->tv_sec = now.tv_sec;
+	tvp->tv_usec = now.tv_nsec / 1000;
+}
+
+/* Set the time with theoretical nanosecond resolution */
+void do_clock_settime(clockid_t sysclock, const struct timespec *tsp)
+{
+	unsigned long flags;
+	struct timespec new_ts = *tsp;
+
+	write_lock_irqsave(&xtime_lock, flags);
+	/* The value in xtime is the time at the last tick. As the current
+	 * time offset will be added when reading the time, subtract it first.
+	 * Finally think of normalizing the time again.
+	 */
+	new_ts.tv_nsec -= do_nanotime();
+	new_ts.tv_nsec -= (jiffies - wall_jiffies) * time_tick;
+
+	while (new_ts.tv_nsec < 0) {
+		new_ts.tv_nsec += NANOSECOND;
+		new_ts.tv_sec--;
+	}
+
+	xtime = new_ts;
+	time_adjust = 0;		/* stop active adjtime() */
+	if (rtc_update > 0)
+		rtc_update_slave = 1;	/* update the RTC clock next second */
+#ifdef CONFIG_NTP
+	time_status |= STA_UNSYNC;
+	time_maxerror = NTP_PHASE_LIMIT;
+	time_esterror = NTP_PHASE_LIMIT;
+#endif
+	write_unlock_irqrestore(&xtime_lock, flags);
+}
+
+void do_settimeofday(const struct timeval *tvp)
+{
+	struct timespec now;
+	now.tv_sec = tvp->tv_sec;
+	now.tv_nsec = tvp->tv_usec * 1000;
+	do_clock_settime(CLOCK_REALTIME, &now);
+}
+
 asmlinkage long sys_gettimeofday(struct timeval *tv, struct timezone *tz)
 {
 	if (tv) {
@@ -109,6 +859,54 @@
 	return 0;
 }
 
+/* get the time with nanosecond resolution */
+asmlinkage int sys_clock_gettime(clockid_t sysclock, struct timespec *tsp)
+{
+	/* only one clock (CLOCK_REALTIME) is implemented */
+	if (tsp) {
+		struct timespec kts;
+		do_clock_gettime(sysclock, &kts);
+		if (copy_to_user(tsp, &kts, sizeof(kts)))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+/* Get clock resolution down to one nanosecond theoretically */
+void do_clock_getres(clockid_t sysclock, struct timespec *tsp)
+{
+	struct timespec ts;
+	int retry_limit;		/* implement emergency break */
+
+	/* We do a quick and dirty algorithm: Just get a non-zero time
+         * difference (with possibly some retries for fast CPUs or
+         * poor resolution)...
+	 */
+	ts.tv_sec = 0;
+	retry_limit = 1000;
+	do {
+		struct timespec	ts1, ts2;
+		do_clock_gettime(sysclock, &ts1);
+		do_clock_gettime(sysclock, &ts2);
+		ts.tv_nsec = ts2.tv_nsec - ts1.tv_nsec;
+		ts.tv_sec = ts2.tv_sec - ts1.tv_sec;
+	} while ( --retry_limit > 0 && (ts.tv_sec != 0 || ts.tv_nsec == 0) );
+	*tsp = ts;
+}
+
+/* get the time resolution down to one nanosecond */
+asmlinkage int sys_clock_getres(clockid_t sysclock, struct timespec *tsp)
+{
+	/* only one clock (CLOCK_REALTIME) is implemented */
+	if (tsp) {
+		struct timespec kts;
+		do_clock_getres(sysclock, &kts);
+		if (copy_to_user(tsp, &kts, sizeof(kts)))
+			return -EFAULT;
+	}
+	return 0;
+}
+
 /*
  * Adjust the time obtained from the CMOS to be UTC time instead of
  * local time.
@@ -188,210 +986,766 @@
 	return do_sys_settimeofday(tv ? &new_tv : NULL, tz ? &new_tz : NULL);
 }
 
-long pps_offset;		/* pps time offset (us) */
-long pps_jitter = MAXTIME;	/* time dispersion (jitter) (us) */
+asmlinkage int sys_clock_settime(clockid_t sysclock,
+				 const struct timespec *tsp)
+{
+	struct timespec	new_ts;
 
-long pps_freq;			/* frequency offset (scaled ppm) */
-long pps_stabil = MAXFREQ;	/* frequency dispersion (scaled ppm) */
+	if (!capable(CAP_SYS_TIME))
+		return -EPERM;
+	if (tsp) {
+		if (copy_from_user(&new_ts, tsp, sizeof(*tsp)))
+			return -EFAULT;
+	}
+	do_clock_settime(sysclock, tsp);
+	return 0;
+}
 
-long pps_valid = PPS_VALID;	/* pps signal watchdog counter */
+#ifdef	CONFIG_NTP_PPS
+/*
+ * hardpps() - discipline CPU clock oscillator to external PPS signal
+ *
+ * This routine is called at each PPS interrupt in order to discipline
+ * the CPU clock oscillator to the PPS signal. There are two independent
+ * first-order feedback loops, one for the phase, the other for the
+ * frequency. The phase loop measures and grooms the PPS phase offset
+ * and leaves it in a handy spot for the seconds overflow routine. The
+ * frequency loop averages successive PPS phase differences and
+ * calculates the PPS frequency offset, which is also processed by the
+ * seconds overflow routine. The code requires the caller to capture the
+ * time and architecture-dependent hardware counter values in
+ * nanoseconds at the on-time PPS signal transition.
+ *
+ * Note that, on some Unix systems this routine runs at an interrupt
+ * priority level higher than the timer interrupt routine second_overflow().
+ * Therefore, the variables used are distinct from the second_overflow()
+ * variables, except for the actual time and frequency variables, which
+ * are determined by this routine and updated atomically.
+ */
+void hardpps(const struct timespec *p_ts, long nsec)
+{
+	static	long pps_lastcount;	/* last counter offset */
+	unsigned long flags;
+	long u_sec, u_nsec, v_nsec;	/* multi-purpose temps */
+	l_fp ftemp;
+	int fr_upd;			/* update frequency range? */
+#ifdef CONFIG_NTP_PPS_DEBUG
+#ifdef CONFIG_X86_TSC
+	struct {
+		unsigned long low;
+		/* unsigned long high; */
+	} start_cc, end_cc;
+	static long cc_min = 10000000L;
+	static long cc_max = 0L;
+	unsigned long cc;
+
+	/* read Pentium cycle counter */
+	rdtscl(start_cc.low);
+#endif
+#endif
+	write_lock_irqsave(&xtime_lock, flags);
+	/*
+	 * The signal is first processed by a range gate and frequency
+	 * discriminator. The range gate rejects noise spikes outside
+	 * the range +-500 us. The frequency discriminator rejects input
+	 * signals with apparent frequency outside the range 1 +-500
+	 * PPM. If two hits occur in the same second, we ignore the
+	 * later hit; if not and a hit occurs outside the range gate,
+	 * keep the later hit for later comparison, but do not process
+	 * it.
+	 */
+#if 0
+	time_tick = (NANOSECOND + hz/2) / hz;	/* UW: really necessary? */
+#endif
+	time_status |= STA_PPSJITTER;
+	time_status &= ~(STA_PPSWANDER | STA_PPSERROR);
+	u_sec = p_ts->tv_sec;
+	u_nsec = p_ts->tv_nsec;		/* relative position around second */
+	if (u_nsec >= (NANOSECOND >> 1)) {
+		u_nsec -= NANOSECOND;
+		u_sec++;
+	}
+	/* compute relative offset to last position */
+	v_nsec = u_nsec - pps.tf[0].tv_nsec;
+	if (u_sec == pps.tf[0].tv_sec && v_nsec < NANOSECOND - MAXFREQ) {
+#ifdef CONFIG_NTP_PPS_DEBUG
+		printk(KERN_INFO
+		       "hardpps(%ld.%08ld): early pulse, delta = %ld ns\n",
+		       p_ts->tv_sec % 10, p_ts->tv_nsec, v_nsec);
+#endif
+		goto done;			/* ignore early pulse */
+	}
+	pps.tf[2] = pps.tf[1];
+	pps.tf[1] = pps.tf[0];
+	pps.tf[0].tv_sec = u_sec;
+	pps.tf[0].tv_nsec = u_nsec;
+
+	/*
+	 * Compute the difference between the current and previous
+	 * counter values. If the difference exceeds 0.5 s, assume it
+	 * has wrapped around, so correct 1.0 s. If the result exceeds
+	 * the tick interval, the sample point has crossed a tick
+	 * boundary during the last second, so correct the tick. Very
+	 * intricate.
+	 */
+	u_nsec = nsec - pps_lastcount;
+	pps_lastcount = nsec;
+	if (u_nsec > (time_tick >> 1))
+		u_nsec -= time_tick;
+	else if (u_nsec < -(time_tick >> 1))
+		u_nsec += time_tick;
+	pps.fcount += u_nsec;
+	if (v_nsec > MAXFREQ || v_nsec < -MAXFREQ) {
+#ifdef CONFIG_NTP_PPS_DEBUG
+		printk(KERN_INFO "hardpps: bad pulse, delta = %ld ns\n",
+		       v_nsec);
+		printk(KERN_DEBUG
+		       "hardpps: last=%ld:%09ld, this=%ld:%09ld (%ld nsec)\n",
+		       pps.tf[1].tv_sec % 10, pps.tf[1].tv_nsec,
+		       pps.tf[0].tv_sec % 10, pps.tf[0].tv_nsec, u_nsec);
+#endif
+		/* Not in reference implementation: The pulse is already in
+		 * the filter stages, therefore we can't simply ignore it.
+		 * Instead we discard the current data and restart the
+		 * calibration interval.  Don't increment jitcnt.
+		 */
+		pps.lastsec = pps.tf[0].tv_sec;
+		pps.fcount = 0;
+		if (--pps.intcnt <= -4) {
+			pps.intcnt = -4;
+			if (pps.shift > PPS_FAVG) {
+				pps.shift--;
+				pps.intcnt = 0;
+			}
+		}
+		goto done;
+	}
+	pps.valid = PPS_VALID;
+	time_status |= STA_PPSSIGNAL;
+	time_status &= ~STA_PPSJITTER;
+
+	/*
+	 * A three-stage median filter is used to help denoise the PPS
+	 * time. The median sample becomes the time offset estimate; the
+	 * difference between the other two samples becomes the time
+	 * dispersion (jitter) estimate.
+	 */
+	if (pps.tf[0].tv_nsec > pps.tf[1].tv_nsec) {
+		if (pps.tf[1].tv_nsec > pps.tf[2].tv_nsec) {
+			v_nsec = pps.tf[1].tv_nsec;	/* 0 1 2 */
+			u_nsec = pps.tf[0].tv_nsec - pps.tf[2].tv_nsec;
+		} else if (pps.tf[2].tv_nsec > pps.tf[0].tv_nsec) {
+			v_nsec = pps.tf[0].tv_nsec;	/* 2 0 1 */
+			u_nsec = pps.tf[2].tv_nsec - pps.tf[1].tv_nsec;
+		} else {
+			v_nsec = pps.tf[2].tv_nsec;	/* 0 2 1 */
+			u_nsec = pps.tf[0].tv_nsec - pps.tf[1].tv_nsec;
+		}
+	} else {
+		if (pps.tf[1].tv_nsec < pps.tf[2].tv_nsec) {
+			v_nsec = pps.tf[1].tv_nsec;	/* 2 1 0 */
+			u_nsec = pps.tf[2].tv_nsec - pps.tf[0].tv_nsec;
+		} else  if (pps.tf[2].tv_nsec < pps.tf[0].tv_nsec) {
+			v_nsec = pps.tf[0].tv_nsec;	/* 1 0 2 */
+			u_nsec = pps.tf[1].tv_nsec - pps.tf[2].tv_nsec;
+		} else {
+			v_nsec = pps.tf[2].tv_nsec;	/* 1 2 0 */
+			u_nsec = pps.tf[1].tv_nsec - pps.tf[0].tv_nsec;
+		}
+	}
+
+	/*
+	 * Nominal jitter is due to PPS signal noise and interrupt
+	 * latency. If it exceeds the popcorn threshold, the sample is
+	 * discarded. otherwise, if so enabled, the time offset is
+	 * updated. We can tolerate a modest loss of data here without
+	 * much degrading time accuracy.
+	 */
+	if (u_nsec > (pps.jitter << PPS_POPCORN)) {
+#ifdef CONFIG_NTP_PPS_DEBUG
+		printk(KERN_INFO
+		       "hardpps: PPSJITTER: jitter=%ld, limit=%ld\n",
+		       u_nsec, (pps.jitter << PPS_POPCORN));
+#endif
+		time_status |= STA_PPSJITTER;
+		pps.jitcnt++;
+	} else if (time_status & STA_PPSTIME) {
+		time_monitor = -v_nsec;
+		L_LINT(time_offset, time_monitor);
+		time_adjust = 0;	/* cancel running adjtime() */
+#ifdef CONFIG_NTP_PPS_DEBUG
+		printk(KERN_DEBUG
+		       "hardpps: PPSTIME monitor=%ld, jitter=%ld\n",
+		       time_monitor, pps.jitter);
+#endif
+	}
+	pps.jitter += (u_nsec - pps.jitter) >> PPS_FAVG;
+	u_sec = pps.tf[0].tv_sec - pps.lastsec;
+	/* (The first pulse after a pause will always end a calibration
+	 * interval.  The workaround is probably not worth the extra cycles.)
+	 */
+	if (u_sec < (1 << pps.shift))
+		goto done;
+	/*
+	 * At the end of the calibration interval the difference between
+	 * the first and last counter values becomes the scaled
+	 * frequency. It will later be divided by the length of the
+	 * interval to determine the frequency update. If the frequency
+	 * exceeds a sanity threshold, or if the actual calibration
+	 * interval is not equal to the expected length, the data are
+	 * discarded. We can tolerate a modest loss of data here without
+	 * degrading frequency accuracy.
+	 */
+	pps.calcnt++;
+	v_nsec = -pps.fcount;
+	pps.lastsec = pps.tf[0].tv_sec;
+	pps.fcount = 0;
+	u_nsec = MAXFREQ << pps.shift;
+	if (v_nsec > u_nsec || v_nsec < -u_nsec || u_sec != (1 << pps.shift)) {
+#ifdef CONFIG_NTP_PPS_DEBUG
+		printk(KERN_NOTICE
+		       "hardpps: PPSERROR limit=%ld, fcount=%ld, len=%ld\n",
+		       u_nsec, v_nsec, u_sec);
+#endif
+		time_status |= STA_PPSERROR;
+		pps.errcnt++;
+		/* not in reference implementation */
+		if (--pps.intcnt <= -4) {
+			pps.intcnt = -4;
+			if (pps.shift > PPS_FAVG) {
+				pps.shift--;
+				pps.intcnt = 0;
+			}
+		}
+		goto done;
+	}
+
+	/*
+	 * Here the raw frequency offset and wander (stability) is
+	 * calculated. If the wander is less than the wander threshold
+	 * for four consecutive averaging intervals, the interval is
+	 * doubled; if it is greater than the threshold for four
+	 * consecutive intervals, the interval is halved. The scaled
+	 * frequency offset is converted to frequency offset. The
+	 * stability metric is calculated as the average of recent
+	 * frequency changes, but is used only for performance
+	 * monitoring.
+	 */
+	L_LINT(ftemp, v_nsec);
+	L_RSHIFT(ftemp, pps.shift);
+	L_SUB(ftemp, pps.freq);
+	u_nsec = L_GINT(ftemp);
+	fr_upd = 0;
+#ifdef CONFIG_NTP_PPS_DEBUG
+	printk(KERN_INFO "hardpps: new frequency %ld >> %d == %ld\n",
+	       v_nsec, pps.shift, v_nsec >> pps.shift);
+#endif
+	/* Not in reference implementation: Use dynamic limit (i.e. stability)
+	 * for maximum wander. Approximate SCALE_PPM (65536 / 1000) by 64.
+	 */
+	v_nsec = (pps.stabil >> 6) << PPS_POPCORN;
+	if (v_nsec == 0 || v_nsec > PPS_MAXWANDER)
+		v_nsec = PPS_MAXWANDER;
+#ifdef CONFIG_NTP_PPS_DEBUG
+	printk(KERN_DEBUG "hardpps: frequency change=%ld (limit %ld)\n",
+	       u_nsec, v_nsec);
+#endif
+	if (u_nsec > v_nsec || u_nsec < -v_nsec) {
+#ifdef CONFIG_NTP_PPS_DEBUG
+		printk(KERN_NOTICE
+		       "hardpps: PPSWANDER: change=%ld, limit=%ld, shift=%d\n",
+		       u_nsec, v_nsec, pps.shift);
+#endif
+		L_LINT(ftemp, u_nsec > 0 ? v_nsec : -v_nsec);
+		time_status |= STA_PPSWANDER;
+		pps.stbcnt++;
+		if (--pps.intcnt <= -4) {
+			pps.intcnt = -4;
+			if (pps.shift > PPS_FAVG) {
+				pps.shift--;
+				pps.intcnt = 0;
+			}
+		}
+	} else {	/* good sample */
+		/* Update frequency error estimate in rather stable
+                   situations.
+		*/
+		if (pps.shift > PPS_FAVG + 1)
+			fr_upd = 1;
+		if (++pps.intcnt >= 4) {
+			pps.intcnt = 4;
+			if (pps.shift < pps.shiftmax) {
+				pps.shift++;
+				pps.intcnt = 0;
+			}
+		}
+	}
+	if (u_nsec < 0)
+		u_nsec = -u_nsec;
+	pps.stabil += (u_nsec * SCALE_PPM - pps.stabil) >> PPS_FAVG;
+
+	/*
+	 * The PPS frequency is recalculated and clamped to the maximum
+	 * MAXFREQ. If enabled, the system clock frequency is updated as
+	 * well.
+	 */
+	L_ADD(pps.freq, ftemp);
+	u_nsec = L_GINT(pps.freq);
+	if (u_nsec > MAXFREQ)
+		L_LINT(pps.freq, MAXFREQ);
+	else if (u_nsec < -MAXFREQ)
+		L_LINT(pps.freq, -MAXFREQ);
+	else if (fr_upd) {
+		/* pps.frange is the maximum difference of the
+		   observed frequency values including (in-)stability.
+		   Otherwise it's a pessimistic worst-case estimate.
+		*/
+		if (u_nsec - (pps.stabil >> 7) < pps.fmin)
+			pps.fmin = u_nsec - (pps.stabil >> 7);
+		if (u_nsec + (pps.stabil >> 7)> pps.fmax)
+			pps.fmax = u_nsec + (pps.stabil >> 7);
+		pps.frange = pps.fmax - pps.fmin;
+		if (pps.frange > MAXFREQ) {
+			printk(KERN_WARNING
+			       "hardpps: pps.frange %ld exceeded MAXFREQ\n",
+			       pps.frange);
+#ifdef CONFIG_NTP_PPS_DEBUG
+			printk(KERN_INFO "hardpps: frange=%ld (%ld:%ld)\n",
+			       pps.frange, pps.fmin, pps.fmax);
+#endif
+			/* force recalculation on next update */
+			pps.fmin = MAXFREQ;
+			pps.fmax = -MAXFREQ;
+			pps.frange = MAXFREQ;
+		}
+	}
+#ifdef CONFIG_NTP_PPS_DEBUG
+	printk(KERN_INFO "hardpps: new pps.freq=%ld (add %ld)\n",
+	       L_GINT(pps.freq), L_GINT(ftemp));
+#endif
+	if ((time_status & STA_PPSFREQ) != 0 &&
+	    (time_status & STA_FREQHOLD) == 0)
+	{
+		time_freq = pps.freq;
+		update_nanoscale(time_tick * hz - NANOSECOND +
+				 L_GINT(time_freq));
+	}
+done:
+	write_unlock_irqrestore(&xtime_lock, flags);
+#ifdef CONFIG_NTP_PPS_DEBUG
+#ifdef CONFIG_X86_TSC
+	/* read Pentium cycle counter */
+	rdtscl(end_cc.low);
+	cc = end_cc.low - start_cc.low;
+	if (cc > cc_max) {
+		cc_max = cc;
+		printk(KERN_DEBUG "hardpps: new max CC = %lu\n", cc_max);
+	}
+	if (cc < cc_min) {
+		cc_min = cc;
+		printk(KERN_DEBUG "hardpps: new min CC = %lu\n", cc_min);
+	}
+#endif
+#endif
+}
+#endif	/* CONFIG_NTP_PPS */
 
-int pps_shift = PPS_SHIFT;	/* interval duration (s) (shift) */
+#ifdef CONFIG_NTP
+/*
+ * hardupdate() - local clock update
+ *
+ * This routine is called by adjtimex() to update the local clock
+ * phase and frequency. The implementation is of an adaptive-parameter,
+ * hybrid phase/frequency-lock loop (PLL/FLL). The routine computes new
+ * time and frequency offset estimates for each call. If the kernel PPS
+ * discipline code is configured (CONFIG_NTP_PPS), the PPS signal itself
+ * determines the new time offset, instead of the calling argument.
+ * Presumably, calls to ntp_adjtime() occur only when the caller
+ * believes the local clock is valid within some bound (+-128 ms with
+ * NTP). If the caller's time is far different than the PPS time, an
+ * argument will ensue, and it's not clear who will lose.
+ *
+ * For uncompensated quartz crystal oscillators and nominal update
+ * intervals less than 256 s, operation should be in phase-lock mode,
+ * where the loop is disciplined to phase. For update intervals greater
+ * than 1024 s, operation should be in frequency-lock mode, where the
+ * loop is disciplined to frequency. Between 256 s and 1024 s, the mode
+ * is selected by the STA_MODE status bit.
+ */
+static inline void hardupdate(long offset)
+{
+	long mtemp;
+	l_fp ftemp;
 
-long pps_jitcnt;		/* jitter limit exceeded */
-long pps_calcnt;		/* calibration intervals */
-long pps_errcnt;		/* calibration errors */
-long pps_stbcnt;		/* stability limit exceeded */
+	/*
+	 * Select how the phase is to be controlled and from which
+	 * source. If the PPS signal is present and enabled to
+	 * discipline the time, the PPS offset is used; otherwise, the
+	 * argument offset is used.
+	 */
+	if (!(time_status & STA_PLL))
+		return;
+	if (!(time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL)) {
+		if (offset > MAXPHASE)
+			time_monitor = MAXPHASE;
+		else if (offset < -MAXPHASE)
+			time_monitor = -MAXPHASE;
+		else
+			time_monitor = offset;
+		L_LINT(time_offset, time_monitor);
+	}
 
-/* hook for a loadable hardpps kernel module */
-void (*hardpps_ptr)(struct timeval *);
+	/*
+	 * Select how the frequency is to be controlled and in which
+	 * mode (PLL or FLL). If the PPS signal is present and enabled
+	 * to discipline the frequency, the PPS frequency is used;
+	 * otherwise, the argument offset is used to compute it.
+	 */
+	if (time_status & STA_PPSFREQ && time_status & STA_PPSSIGNAL) {
+		time_reftime = xtime.tv_sec;
+		return;
+	}
+	if (time_status & STA_FREQHOLD || time_reftime == 0)
+		time_reftime = xtime.tv_sec;
+	mtemp = xtime.tv_sec - time_reftime;
+	L_LINT(ftemp, time_monitor);
+	L_RSHIFT(ftemp, (SHIFT_PLL + 2 + time_constant) << 1);
+	L_MPY(ftemp, mtemp);
+	L_ADD(time_freq, ftemp);
+	time_status &= ~STA_MODE;
+	if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) {
+		L_LINT(ftemp, (time_monitor << 4) / mtemp);
+		L_RSHIFT(ftemp, SHIFT_FLL + 4);
+		L_ADD(time_freq, ftemp);
+		time_status |= STA_MODE;
+	}
+	time_reftime = xtime.tv_sec;
+	if (L_GINT(time_freq) > MAXFREQ)
+		L_LINT(time_freq, MAXFREQ);
+	else if (L_GINT(time_freq) < -MAXFREQ)
+		L_LINT(time_freq, -MAXFREQ);
+	update_nanoscale(time_tick * hz - NANOSECOND + L_GINT(time_freq));
+}
+#endif /* CONFIG_NTP */
 
 /* adjtimex mainly allows reading (and writing, if superuser) of
- * kernel time-keeping variables. used by xntpd.
+ * kernel time-keeping variables. used by NTP.
  */
 int do_adjtimex(struct timex *txc)
 {
-        long ltemp, mtemp, save_adjust;
+	long save_adjust;
 	int result;
 
+#if 1	/* complain about not configured mode bits */
+	if (txc->modes & ~ADJ_SERVED_MODE_BITS)
+	{
+		static int complain = 5;
+		if (complain) {
+			--complain;
+			printk(KERN_NOTICE
+			       "adjtimex: %s used unsupported ADJ bits 0x%x\n",
+			       current->comm,
+			       txc->modes & ~ADJ_SERVED_MODE_BITS);
+		}
+	}
+#endif
 	/* In order to modify anything, you gotta be super-user! */
 	if (txc->modes && !capable(CAP_SYS_TIME))
 		return -EPERM;
 		
 	/* Now we validate the data before disabling interrupts */
 
-	if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
-	  /* singleshot must not be used with any other mode bits */
-		if (txc->modes != ADJ_OFFSET_SINGLESHOT)
-			return -EINVAL;
-
-	if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET))
-	  /* adjustment Offset limited to +- .512 seconds */
-		if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE )
-			return -EINVAL;	
-
-	/* if the quartz is off by more than 10% something is VERY wrong ! */
-	if (txc->modes & ADJ_TICK)
-		if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ)
-			return -EINVAL;
+#if 1	/* Map old method to new one; this will vanish soon */
+#define	OLD_ADJTIME	(MOD_OFFSET|MOD_CLKA)
+	if ((txc->modes & OLD_ADJTIME) == OLD_ADJTIME) {
+		static int complain = 5;
+		txc->modes ^= OLD_ADJTIME;
+		txc->modes |= ADJ_ADJTIME;
+		if (complain) {
+			--complain;
+			printk(KERN_WARNING
+			       "adjtime: %s used obsolete ADJ_OFFSET_SINGLESHOT\n",
+			       current->comm);
+		}
+	}
+#undef	OLD_ADJTIME
+#if 1	/* Establish extra warnings for older applications */
+#define	OLD_ADJTICK	(MOD_CLKB)
+	if ((txc->modes & OLD_ADJTICK) == OLD_ADJTICK) {
+		static int complain = 5;
+		if (complain) {
+			--complain;
+			printk(KERN_NOTICE
+			       "adjtimex: %s may be using obsolete ADJ_TICK\n",
+			       current->comm);
+		}
+	}
+#undef	OLD_ADJTICK
+#define	OLD_ADJTICKADJ	(MOD_NANO)
+	if ((txc->modes & OLD_ADJTICKADJ) == OLD_ADJTICKADJ) {
+		static int complain = 5;
+		if (complain) {
+			--complain;
+			printk(KERN_NOTICE
+			       "adjtimex: %s could be using obsolete ADJ_TICKADJ\n",
+			       current->comm);
+		}
+	}
+#undef	OLD_ADJTICKADJ
+#endif
+#endif
+	if ((txc->modes & MOD_OFFSET) != 0 &&
+	    (txc->modes & ADJ_ADJTIME) != 0) {
+		/* ntp_adjtime() and adjtime() are mutually exclusive! */
+		return -EINVAL;
+	}
 
 	write_lock_irq(&xtime_lock);
-	result = time_state;	/* mostly `TIME_OK' */
 
-	/* Save for later - semantics of adjtime is to return old value */
-	save_adjust = time_adjust;
+#ifdef CONFIG_NTP
+	result = time_state;	/* mostly `TIME_OK' */
+#else
+	result = 0;
+#endif
 
-#if 0	/* STA_CLOCKERR is never set yet */
+#if defined(CONFIG_NTP) && 0	/* STA_CLOCKERR is never set yet */
 	time_status &= ~STA_CLOCKERR;		/* reset STA_CLOCKERR */
 #endif
 	/* If there are input parameters, then process them */
 	if (txc->modes)
 	{
-	    if (txc->modes & ADJ_STATUS)	/* only set allowed bits */
-		time_status =  (txc->status & ~STA_RONLY) |
-			      (time_status & STA_RONLY);
-
-	    if (txc->modes & ADJ_FREQUENCY) {	/* p. 22 */
-		if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) {
-		    result = -EINVAL;
-		    goto leave;
-		}
-		time_freq = txc->freq - pps_freq;
-	    }
-
-	    if (txc->modes & ADJ_MAXERROR) {
-		if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) {
-		    result = -EINVAL;
-		    goto leave;
-		}
-		time_maxerror = txc->maxerror;
-	    }
-
-	    if (txc->modes & ADJ_ESTERROR) {
-		if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) {
-		    result = -EINVAL;
-		    goto leave;
-		}
-		time_esterror = txc->esterror;
-	    }
-
-	    if (txc->modes & ADJ_TIMECONST) {	/* p. 24 */
-		if (txc->constant < 0) {	/* NTP v4 uses values > 6 */
-		    result = -EINVAL;
-		    goto leave;
-		}
-		time_constant = txc->constant;
-	    }
-
-	    if (txc->modes & ADJ_OFFSET) {	/* values checked earlier */
-		if (txc->modes == ADJ_OFFSET_SINGLESHOT) {
-		    /* adjtime() is independent from ntp_adjtime() */
-		    time_adjust = txc->offset;
-		}
-		else if ( time_status & (STA_PLL | STA_PPSTIME) ) {
-		    ltemp = (time_status & (STA_PPSTIME | STA_PPSSIGNAL)) ==
-		            (STA_PPSTIME | STA_PPSSIGNAL) ?
-		            pps_offset : txc->offset;
-
-		    /*
-		     * Scale the phase adjustment and
-		     * clamp to the operating range.
-		     */
-		    if (ltemp > MAXPHASE)
-		        time_offset = MAXPHASE << SHIFT_UPDATE;
-		    else if (ltemp < -MAXPHASE)
-			time_offset = -(MAXPHASE << SHIFT_UPDATE);
-		    else
-		        time_offset = ltemp << SHIFT_UPDATE;
-
-		    /*
-		     * Select whether the frequency is to be controlled
-		     * and in which mode (PLL or FLL). Clamp to the operating
-		     * range. Ugly multiply/divide should be replaced someday.
-		     */
-
-		    if (time_status & STA_FREQHOLD || time_reftime == 0)
-		        time_reftime = xtime.tv_sec;
-		    mtemp = xtime.tv_sec - time_reftime;
-		    time_reftime = xtime.tv_sec;
-		    if (time_status & STA_FLL) {
-		        if (mtemp >= MINSEC) {
-			    ltemp = (time_offset / mtemp) << (SHIFT_USEC -
-							      SHIFT_UPDATE);
-			    if (ltemp < 0)
-			        time_freq -= -ltemp >> SHIFT_KH;
-			    else
-			        time_freq += ltemp >> SHIFT_KH;
-			} else /* calibration interval too short (p. 12) */
-				result = TIME_ERROR;
-		    } else {	/* PLL mode */
-		        if (mtemp < MAXSEC) {
-			    ltemp *= mtemp;
-			    if (ltemp < 0)
-			        time_freq -= -ltemp >> (time_constant +
-							time_constant +
-							SHIFT_KF - SHIFT_USEC);
-			    else
-			        time_freq += ltemp >> (time_constant +
-						       time_constant +
-						       SHIFT_KF - SHIFT_USEC);
-			} else /* calibration interval too long (p. 12) */
-				result = TIME_ERROR;
-		    }
-		    if (time_freq > time_tolerance)
-		        time_freq = time_tolerance;
-		    else if (time_freq < -time_tolerance)
-		        time_freq = -time_tolerance;
-		} /* STA_PLL || STA_PPSTIME */
-	    } /* txc->modes & ADJ_OFFSET */
-	    if (txc->modes & ADJ_TICK) {
-		/* if the quartz is off by more than 10% something is
-		   VERY wrong ! */
-		if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ) {
-		    result = -EINVAL;
-		    goto leave;
+#ifdef CONFIG_NTP
+		if (txc->modes & MOD_STATUS) {  /* only modify allowed bits */
+			if ((time_status & STA_PLL) != 0 &&
+			    (txc->status & STA_PLL) == 0) {
+				/* If the STA_PLL bit in the status word is
+				 * cleared, the state and status words are
+				 * reset to the initial values.
+				 */
+				time_state = TIME_OK;
+				time_status = STA_UNSYNC;
+#ifdef CONFIG_NTP_PPS
+				/* the PPS calibration interval may end
+				   surprisingly early */
+				pps.shift = PPS_FAVG;
+				pps.intcnt = 0;
+#endif
+			}
+			time_status =  (txc->status & ~STA_RONLY) |
+				(time_status & STA_RONLY);
+		}
+
+		if (txc->modes & MOD_FREQUENCY) {	/* p. 22 */
+			long freq;		/* frequency ns/s) */
+			freq = txc->freq / SCALE_PPM;
+			if (freq > MAXFREQ) {
+				result = -EINVAL;
+				freq = MAXFREQ;
+			} else if (freq < -MAXFREQ) {
+				result = -EINVAL;
+				freq = -MAXFREQ;
+			}
+			L_LINT(time_freq, freq);
+			update_nanoscale(time_tick * hz - NANOSECOND +
+					 L_GINT(time_freq));
+#ifdef CONFIG_NTP_PPS
+			pps.freq = time_freq;
+#endif
+		}
+
+		if (txc->modes & MOD_MAXERROR) {
+			txc->maxerror *= 1000;	/* convert to ns */
+			if (txc->maxerror < 0
+			    || txc->maxerror >= NTP_PHASE_LIMIT) {
+				result = -EINVAL;
+				txc->maxerror = NTP_PHASE_LIMIT;
+			}
+			time_maxerror = txc->maxerror;
+		}
+
+		if (txc->modes & MOD_ESTERROR) {
+			txc->esterror *= 1000;
+			if (txc->esterror < 0
+			    || txc->esterror >= NTP_PHASE_LIMIT) {
+				result = -EINVAL;
+				txc->esterror = NTP_PHASE_LIMIT;
+			}
+			time_esterror = txc->esterror;
+		}
+
+		/* Note that the timex.constant structure member has a
+		 * dual purpose to set the time constant and to set
+		 * the TAI offset.
+		 */
+		if (txc->modes & MOD_TIMECONST) {	/* p. 24 */
+			if (txc->constant < 0) {
+				result = -EINVAL;
+				txc->constant = 0;
+			} else if (txc->constant > MAXTC) {
+				result = -EINVAL;
+				txc->constant = MAXTC;
+			}
+			time_constant = txc->constant;
+		}
+		if (txc->modes & MOD_TAI) {
+			if (txc->constant > 0)
+				time_tai = txc->constant;
+			else
+				result = -EINVAL;
+		}
+#ifdef CONFIG_NTP_PPS
+		if (txc->modes & MOD_PPSMAX) {
+			if (txc->shift < PPS_FAVG) {
+				pps.shiftmax = PPS_FAVG;
+				result = -EINVAL;
+			} else if (txc->shift > PPS_FAVGMAX) {
+				pps.shiftmax = PPS_FAVGMAX;
+				result = -EINVAL;
+			} else
+				pps.shiftmax = txc->shift;
+			if (pps.shift > pps.shiftmax) {	/* enforce limit */
+				pps.shift = pps.shiftmax;
+			}
+		}
+#endif
+		if (txc->modes & MOD_NANO)
+			time_status |= STA_NANO;
+		if (txc->modes & MOD_MICRO)
+			time_status &= ~STA_NANO;
+		if (txc->modes & MOD_CLKB)
+			time_status |= STA_CLK;
+		if (txc->modes & MOD_CLKA)
+			time_status &= ~STA_CLK;
+		if (txc->modes & MOD_OFFSET) {
+			if ((time_status & STA_NANO) == 0) {
+				/* need nanoseconds, but avoid sign overflow */
+				if (txc->offset > MAXPHASE / 1000)
+					txc->offset = MAXPHASE;
+				else if (txc->offset < -MAXPHASE / 1000)
+					txc->offset = -MAXPHASE;
+				else
+					txc->offset *= 1000;
+			}
+			/* offset will be clamped silently in hardupdate() */
+			hardupdate(txc->offset);
+		}
+#endif /* CONFIG_NTP */
+		if (txc->modes == ADJ_ADJTIME) {
+			/*
+			 * The emulation of adjtime() is actually broken,
+			 * because only one ``long'' is available to represent
+			 * a ``struct timeval''.
+			 */
+			/* Save current adjustment to be retuned */
+			save_adjust = time_adjust;
+			time_adjust = txc->offset;
+			if (txc->offset < -30000000 || txc->offset > 30000000)
+				printk(KERN_WARNING
+				       "adjtime() fails with large offsets\n");
+		}
+		if (txc->modes & ADJ_TIMETICK) {
+#ifdef CONFIG_NTP
+			if ((time_status & STA_NANO) == 0)
+				txc->time_tick *= 1000;
+#endif
+			/* if the quartz is off by more than 10% something is
+			   VERY wrong ! */
+			if (txc->time_tick <  9 * (NANOSECOND/10/hz) ||
+			    txc->time_tick > 11 * (NANOSECOND/10/hz)) {
+				result = -EINVAL;
+				goto leave;
+			}
+			time_tick = txc->time_tick;
+#ifdef CONFIG_NTP
+			update_nanoscale(time_tick * hz - NANOSECOND +
+					 L_GINT(time_freq));
+#endif
+		}
+		if (txc->modes & ADJ_TICKADJ) {
+			/* Traditional UN*Xes seem to allow about ``tick/10'',
+			   but we will allow up to ``time_tick/4'' (scaled).
+			   Larger values might cause trouble!
+			*/
+			if (txc->tickadj <= 0 ||
+			    txc->tickadj > time_tick / 4) {
+				result = -EINVAL;
+				goto leave;
+			}
+			tickadj = txc->tickadj;
 		}
-		tick = txc->tick;
-	    }
 	} /* txc->modes */
-leave:	if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
+leave:
+	if (txc->modes & ADJ_ADJTIME)
+		txc->offset = save_adjust;
+#ifdef CONFIG_NTP
+	else {
+		if (time_status & STA_NANO)
+			txc->offset = time_monitor;
+		else
+			txc->offset = time_monitor / 1000;
+	}
+	txc->freq	   = L_GINT(time_freq) * SCALE_PPM;
+	txc->maxerror	   = time_maxerror / 1000;
+	txc->esterror	   = time_esterror / 1000;
+	txc->tai	   = time_tai;
+	txc->status	   = time_status;
+	txc->constant	   = time_constant;
+	if (time_status & STA_NANO) {
+		txc->precision = time_precision ? : 1;
+		txc->time_tick = time_tick;
+	} else {
+		txc->time.tv_nsec += 500;	/* make microseconds */
+		txc->time.tv_nsec /= 1000;
+		txc->precision = ((time_precision + 500) / 1000) ? : 1;
+		txc->time_tick = (time_tick + 500) / 1000;
+	}
+	txc->tolerance = MAXFREQ * SCALE_PPM;
+#else
+	txc->time_tick	   = time_tick;
+#endif
+#ifdef CONFIG_NTP_PPS
+	txc->ppsfreq	   = L_GINT(pps.freq) * SCALE_PPM;
+	if (time_status & STA_NANO)
+		txc->jitter = pps.jitter;
+	else
+		txc->jitter = pps.jitter / 1000;
+	txc->shift	   = pps.shift;
+	txc->stabil	   = pps.stabil;
+	txc->jitcnt	   = pps.jitcnt;
+	txc->calcnt	   = pps.calcnt;
+	txc->errcnt	   = pps.errcnt;
+	txc->stbcnt	   = pps.stbcnt;
+#endif
+	txc->tickadj	   = tickadj;	/* extension by UW */
+
+#ifdef CONFIG_NTP
+	if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
+	    /* clock not synchronized (hardware or software error) */
+#ifdef CONFIG_NTP_PPS
 	    || ((time_status & (STA_PPSFREQ|STA_PPSTIME)) != 0
 		&& (time_status & STA_PPSSIGNAL) == 0)
-	    /* p. 24, (b) */
+	    /* PPS signal lost when either PPS time or PPS frequency
+	     * synchronization requested
+	     */
 	    || ((time_status & (STA_PPSTIME|STA_PPSJITTER))
 		== (STA_PPSTIME|STA_PPSJITTER))
-	    /* p. 24, (c) */
+	    /* PPS jitter exceeded when PPS time synchronization requested */
 	    || ((time_status & STA_PPSFREQ) != 0
-		&& (time_status & (STA_PPSWANDER|STA_PPSERROR)) != 0))
-	    /* p. 24, (d) */
+		&& (time_status & (STA_PPSWANDER|STA_PPSERROR)) != 0)
+	    /* PPS wander exceeded or calibration error when PPS frequency
+	     * synchronization requested
+	     */
+#endif
+	   )
 		result = TIME_ERROR;
+#endif
 	
-	if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
-	    txc->offset	   = save_adjust;
-	else {
-	    if (time_offset < 0)
-		txc->offset = -(-time_offset >> SHIFT_UPDATE);
-	    else
-		txc->offset = time_offset >> SHIFT_UPDATE;
-	}
-	txc->freq	   = time_freq + pps_freq;
-	txc->maxerror	   = time_maxerror;
-	txc->esterror	   = time_esterror;
-	txc->status	   = time_status;
-	txc->constant	   = time_constant;
-	txc->precision	   = time_precision;
-	txc->tolerance	   = time_tolerance;
-	txc->tick	   = tick;
-	txc->ppsfreq	   = pps_freq;
-	txc->jitter	   = pps_jitter >> PPS_AVG;
-	txc->shift	   = pps_shift;
-	txc->stabil	   = pps_stabil;
-	txc->jitcnt	   = pps_jitcnt;
-	txc->calcnt	   = pps_calcnt;
-	txc->errcnt	   = pps_errcnt;
-	txc->stbcnt	   = pps_stbcnt;
 	write_unlock_irq(&xtime_lock);
-	do_gettimeofday(&txc->time);
+	do_clock_gettime(CLOCK_REALTIME, &txc->time);
+#ifdef CONFIG_NTP
+	if ((time_status & STA_NANO) == 0)
+		txc->time.tv_nsec /= 1000;
+#endif
 	return(result);
 }
 
@@ -409,3 +1763,60 @@
 	ret = do_adjtimex(&txc);
 	return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
 }
+
+/*
+ * timevar_init() - initialize variables and structures
+ * (needed before first time interrupt is processed)
+ *
+ * This routine must be called after the kernel variables hz and tick
+ * are set or changed and before the next tick interrupt. In this
+ * particular implementation, these values are assumed set elsewhere in
+ * the kernel. The design allows the clock frequency and tick interval
+ * to be changed while the system is running. So, this routine should
+ * probably be integrated with the code that does that.
+ */
+void timevar_init(void)
+{
+	struct timespec ts;
+
+	/*
+	 * The following variable must be initialized any time the
+	 * kernel variable hz is changed.
+	 */
+	time_tick = (NANOSECOND + hz/2) / hz;
+	/* Speed of adjtime() is 50ms/s; may not be <= 0 */
+	tickadj = 50000/hz ? : 1;
+	time_adjust = 0;
+	rtc_update = 660;			/* update every 11 minutes */
+
+	/*
+	 * The following variables are initialized only at startup. Only
+	 * those structures not cleared by the compiler need to be
+	 * initialized, and these only in the simulator. In the actual
+	 * kernel, any nonzero values here will quickly evaporate.
+	 */
+#ifdef CONFIG_NTP
+	time_state = TIME_OK;
+	time_status = STA_UNSYNC;
+	time_tai = 0;
+	time_maxerror = time_esterror = NTP_PHASE_LIMIT;
+	L_CLR(time_offset);
+	L_CLR(time_freq);
+	L_LINT(time_adj, NANOSECOND);		/* preset for first second */
+	L_CLR(time_phase);
+	do_clock_getres(CLOCK_REALTIME, &ts);
+	time_precision = ts.tv_nsec;
+#ifdef CONFIG_NTP_PPS
+	pps.shift = PPS_FAVG;
+	pps.shiftmax = PPS_FAVGDEF;
+	pps.tf[0].tv_sec = pps.tf[0].tv_nsec = 0;
+	pps.tf[1].tv_sec = pps.tf[1].tv_nsec = 0;
+	pps.tf[2].tv_sec = pps.tf[2].tv_nsec = 0;
+	pps.fcount = 0;
+	L_CLR(pps.freq);
+	pps.fmin = MAXFREQ;
+	pps.fmax = -MAXFREQ;
+	pps.frange = MAXFREQ;
+#endif
+#endif
+}
Index: linux/kernel/timer.c
diff -u linux/kernel/timer.c:1.1.1.6 linux/kernel/timer.c:1.1.1.6.6.1
--- linux/kernel/timer.c:1.1.1.6	Sun Feb 23 18:41:52 2003
+++ linux/kernel/timer.c	Mon Jan 24 21:06:40 2005
@@ -17,7 +17,7 @@
 
 #include <linux/config.h>
 #include <linux/mm.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
@@ -25,42 +25,9 @@
 
 #include <asm/uaccess.h>
 
-/*
- * Timekeeping variables
- */
-
-long tick = (1000000 + HZ/2) / HZ;	/* timer interrupt period */
-
-/* The current time */
-struct timeval xtime __attribute__ ((aligned (16)));
-
-/* Don't completely fail for HZ > 500.  */
-int tickadj = 500/HZ ? : 1;		/* microsecs */
-
 DECLARE_TASK_QUEUE(tq_timer);
 DECLARE_TASK_QUEUE(tq_immediate);
 
-/*
- * phase-lock loop variables
- */
-/* TIME_ERROR prevents overwriting the CMOS clock */
-int time_state = TIME_OK;		/* clock synchronization status	*/
-int time_status = STA_UNSYNC;		/* clock status bits		*/
-long time_offset;			/* time adjustment (us)		*/
-long time_constant = 2;			/* pll time constant		*/
-long time_tolerance = MAXFREQ;		/* frequency tolerance (ppm)	*/
-long time_precision = 1;		/* clock precision (us)		*/
-long time_maxerror = NTP_PHASE_LIMIT;	/* maximum error (us)		*/
-long time_esterror = NTP_PHASE_LIMIT;	/* estimated error (us)		*/
-long time_phase;			/* phase offset (scaled us)	*/
-long time_freq = ((1000000 + HZ/2) % HZ - HZ/2) << SHIFT_USEC;
-					/* frequency offset (scaled ppm)*/
-long time_adj;				/* tick adjust (scaled 1 / HZ)	*/
-long time_reftime;			/* time at last adjustment (s)	*/
-
-long time_adjust;
-long time_adjust_step;
-
 unsigned long event;
 
 extern int do_setitimer(int, struct itimerval *, struct itimerval *);
@@ -351,189 +318,6 @@
 	run_task_queue(&tq_immediate);
 }
 
-/*
- * this routine handles the overflow of the microsecond field
- *
- * The tricky bits of code to handle the accurate clock support
- * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
- * They were originally developed for SUN and DEC kernels.
- * All the kudos should go to Dave for this stuff.
- *
- */
-static void second_overflow(void)
-{
-    long ltemp;
-
-    /* Bump the maxerror field */
-    time_maxerror += time_tolerance >> SHIFT_USEC;
-    if ( time_maxerror > NTP_PHASE_LIMIT ) {
-	time_maxerror = NTP_PHASE_LIMIT;
-	time_status |= STA_UNSYNC;
-    }
-
-    /*
-     * Leap second processing. If in leap-insert state at
-     * the end of the day, the system clock is set back one
-     * second; if in leap-delete state, the system clock is
-     * set ahead one second. The microtime() routine or
-     * external clock driver will insure that reported time
-     * is always monotonic. The ugly divides should be
-     * replaced.
-     */
-    switch (time_state) {
-
-    case TIME_OK:
-	if (time_status & STA_INS)
-	    time_state = TIME_INS;
-	else if (time_status & STA_DEL)
-	    time_state = TIME_DEL;
-	break;
-
-    case TIME_INS:
-	if (xtime.tv_sec % 86400 == 0) {
-	    xtime.tv_sec--;
-	    time_state = TIME_OOP;
-	    printk(KERN_NOTICE "Clock: inserting leap second 23:59:60 UTC\n");
-	}
-	break;
-
-    case TIME_DEL:
-	if ((xtime.tv_sec + 1) % 86400 == 0) {
-	    xtime.tv_sec++;
-	    time_state = TIME_WAIT;
-	    printk(KERN_NOTICE "Clock: deleting leap second 23:59:59 UTC\n");
-	}
-	break;
-
-    case TIME_OOP:
-	time_state = TIME_WAIT;
-	break;
-
-    case TIME_WAIT:
-	if (!(time_status & (STA_INS | STA_DEL)))
-	    time_state = TIME_OK;
-    }
-
-    /*
-     * Compute the phase adjustment for the next second. In
-     * PLL mode, the offset is reduced by a fixed factor
-     * times the time constant. In FLL mode the offset is
-     * used directly. In either mode, the maximum phase
-     * adjustment for each second is clamped so as to spread
-     * the adjustment over not more than the number of
-     * seconds between updates.
-     */
-    if (time_offset < 0) {
-	ltemp = -time_offset;
-	if (!(time_status & STA_FLL))
-	    ltemp >>= SHIFT_KG + time_constant;
-	if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE)
-	    ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE;
-	time_offset += ltemp;
-	time_adj = -ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
-    } else {
-	ltemp = time_offset;
-	if (!(time_status & STA_FLL))
-	    ltemp >>= SHIFT_KG + time_constant;
-	if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE)
-	    ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE;
-	time_offset -= ltemp;
-	time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
-    }
-
-    /*
-     * Compute the frequency estimate and additional phase
-     * adjustment due to frequency error for the next
-     * second. When the PPS signal is engaged, gnaw on the
-     * watchdog counter and update the frequency computed by
-     * the pll and the PPS signal.
-     */
-    pps_valid++;
-    if (pps_valid == PPS_VALID) {	/* PPS signal lost */
-	pps_jitter = MAXTIME;
-	pps_stabil = MAXFREQ;
-	time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
-			 STA_PPSWANDER | STA_PPSERROR);
-    }
-    ltemp = time_freq + pps_freq;
-    if (ltemp < 0)
-	time_adj -= -ltemp >>
-	    (SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE);
-    else
-	time_adj += ltemp >>
-	    (SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE);
-
-#if HZ == 100
-    /* Compensate for (HZ==100) != (1 << SHIFT_HZ).
-     * Add 25% and 3.125% to get 128.125; => only 0.125% error (p. 14)
-     */
-    if (time_adj < 0)
-	time_adj -= (-time_adj >> 2) + (-time_adj >> 5);
-    else
-	time_adj += (time_adj >> 2) + (time_adj >> 5);
-#endif
-}
-
-/* in the NTP reference this is called "hardclock()" */
-static void update_wall_time_one_tick(void)
-{
-	if ( (time_adjust_step = time_adjust) != 0 ) {
-	    /* We are doing an adjtime thing. 
-	     *
-	     * Prepare time_adjust_step to be within bounds.
-	     * Note that a positive time_adjust means we want the clock
-	     * to run faster.
-	     *
-	     * Limit the amount of the step to be in the range
-	     * -tickadj .. +tickadj
-	     */
-	     if (time_adjust > tickadj)
-		time_adjust_step = tickadj;
-	     else if (time_adjust < -tickadj)
-		time_adjust_step = -tickadj;
-	     
-	    /* Reduce by this step the amount of time left  */
-	    time_adjust -= time_adjust_step;
-	}
-	xtime.tv_usec += tick + time_adjust_step;
-	/*
-	 * Advance the phase, once it gets to one microsecond, then
-	 * advance the tick more.
-	 */
-	time_phase += time_adj;
-	if (time_phase <= -FINEUSEC) {
-		long ltemp = -time_phase >> SHIFT_SCALE;
-		time_phase += ltemp << SHIFT_SCALE;
-		xtime.tv_usec -= ltemp;
-	}
-	else if (time_phase >= FINEUSEC) {
-		long ltemp = time_phase >> SHIFT_SCALE;
-		time_phase -= ltemp << SHIFT_SCALE;
-		xtime.tv_usec += ltemp;
-	}
-}
-
-/*
- * Using a loop looks inefficient, but "ticks" is
- * usually just one (we shouldn't be losing ticks,
- * we're doing this this way mainly for interrupt
- * latency reasons, not because we think we'll
- * have lots of lost timer ticks
- */
-static void update_wall_time(unsigned long ticks)
-{
-	do {
-		ticks--;
-		update_wall_time_one_tick();
-	} while (ticks);
-
-	if (xtime.tv_usec >= 1000000) {
-	    xtime.tv_usec -= 1000000;
-	    xtime.tv_sec++;
-	    second_overflow();
-	}
-}
-
 static inline void do_process_times(struct task_struct *p,
 	unsigned long user, unsigned long system)
 {
@@ -661,12 +445,7 @@
 }
 
 /* jiffies at the most recent update of wall time */
-unsigned long wall_jiffies;
-
-/*
- * This spinlock protect us from races in SMP while playing with xtime. -arca
- */
-rwlock_t xtime_lock = RW_LOCK_UNLOCKED;
+volatile unsigned long wall_jiffies;
 
 static inline void update_times(void)
 {
Index: linux/mm/oom_kill.c
diff -u linux/mm/oom_kill.c:1.1.1.9 linux/mm/oom_kill.c:1.1.1.9.2.1
--- linux/mm/oom_kill.c:1.1.1.9	Sat Jan 22 21:59:17 2005
+++ linux/mm/oom_kill.c	Mon Jan 24 21:06:45 2005
@@ -19,7 +19,7 @@
 #include <linux/sched.h>
 #include <linux/swap.h>
 #include <linux/swapctl.h>
-#include <linux/timex.h>
+#include <linux/time.h>
 
 /* #define DEBUG */
 
Index: linux/net/khttpd/structure.h
diff -u linux/net/khttpd/structure.h:1.1.1.1 linux/net/khttpd/structure.h:1.1.1.1.26.1
--- linux/net/khttpd/structure.h:1.1.1.1	Thu Feb 10 04:47:20 2000
+++ linux/net/khttpd/structure.h	Mon Jan 24 21:06:51 2005
@@ -1,7 +1,7 @@
 #ifndef _INCLUDE_GUARD_STRUCTURE_H_
 #define _INCLUDE_GUARD_STRUCTURE_H_
 
-#include <linux/time.h>
+#include <linux/types.h>
 #include <linux/wait.h>
 
 
Index: linux/net/sunrpc/svcauth_des.c
diff -u linux/net/sunrpc/svcauth_des.c:1.1.1.1 linux/net/sunrpc/svcauth_des.c:1.1.1.1.26.1
--- linux/net/sunrpc/svcauth_des.c:1.1.1.1	Mon Apr  7 20:35:33 1997
+++ linux/net/sunrpc/svcauth_des.c	Mon Jan 24 21:06:54 2005
@@ -7,7 +7,7 @@
  */
 
 #include <linux/types.h>
-#include <linux/sched.h>
+#include <linux/time.h>
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/svcauth.h>
@@ -175,7 +175,7 @@
 #endif
 	}
 
-	now = xtime;
+	do_gettimeofday(&now);	/* now = xtime; need for speed? -- UW */
 	now.tv_secs -= data->dc_window;
 	if (now.tv_secs < cryptbuf[0] ||
 	    (now.tv_secs == cryptbuf[0] && now.tv_usec < cryptbuf[1]))
