summaryrefslogtreecommitdiffstats
path: root/kernel/time.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
committer <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
commite7c2a72e2680827d6a733931273a93461c0d8d1b (patch)
treec9abeda78ef7504062bb2e816bcf3e3c9d680112 /kernel/time.c
parentec6044459060a8c9ce7f64405c465d141898548c (diff)
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'kernel/time.c')
-rw-r--r--kernel/time.c121
1 files changed, 75 insertions, 46 deletions
diff --git a/kernel/time.c b/kernel/time.c
index 1a25d43ef..0424b2eaa 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -10,39 +10,48 @@
/*
* Modification history kernel/time.c
*
- * 02 Sep 93 Philip Gladstone
+ * 1993-09-02 Philip Gladstone
* Created file with time related functions from sched.c and adjtimex()
- * 08 Oct 93 Torsten Duwe
+ * 1993-10-08 Torsten Duwe
* adjtime interface update and CMOS clock write code
- * 02 Jul 94 Alan Modra
+ * 1994-07-02 Alan Modra
* fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
+ * 1995-03-26 Markus Kuhn
+ * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
+ * precision CMOS clock update
+ *
+ * to do: adjtimex() has to be updated to recent (1994-12-13) revision
+ * of David Mill's kernel clock model. For more information, check
+ * <ftp://louie.udel.edu/pub/ntp/kernel.tar.Z>.
*/
-#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 <asm/segment.h>
#include <asm/io.h>
#include <linux/mc146818rtc.h>
-#define RTC_ALWAYS_BCD 1
-
#include <linux/timex.h>
-/* converts date to days since 1/1/1970
- * assumes year,mon,day in normal date format
- * ie. 1/1/1970 => year=1970, mon=1, day=1
+/* 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,
+ * [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.
+ * -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,
@@ -65,16 +74,16 @@ void time_init(void)
unsigned int year, mon, day, hour, min, sec;
int i;
- /* checking for Update-In-Progress could be done more elegantly
- * (using the "update finished"-interrupt for example), but that
- * would require excessive testing. promise I'll do that when I find
- * the time. - Torsten
+ /* The Linux interpretation of the CMOS clock register contents:
+ * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+ * RTC registers show the second which has precisely just started.
+ * Let's hope other operating systems interpret the RTC the same way.
*/
/* read RTC exactly on falling edge of update flag */
for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
break;
- for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms*/
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
break;
do { /* Isn't this overkill ? UIP above should guarantee consistency */
@@ -98,7 +107,14 @@ void time_init(void)
year += 100;
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_usec = 0;
+printk("Year : %d\n", year);
+printk("Mon : %d\n", mon);
+printk("Day : %d\n", day);
+printk("Hour : %d\n", hour);
+printk("Min : %d\n", min);
+printk("Sec : %d\n", sec);
}
+
/*
* The timezone where the local system is located. Used as a default by some
* programs who obtain this value by using gettimeofday.
@@ -148,25 +164,25 @@ asmlinkage int sys_stime(unsigned long * tptr)
* 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 msecs, but 9.9767 msec. To get around this
+ * 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 1024Hz,
+ * 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 sec. Every time that reached over 1/100
+ * 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 120us or so.
+ * often than every 120 us or so.
*
- * Anyway, this needs more thought.... pjsg (28 Aug 93)
+ * Anyway, this needs more thought.... pjsg (1993-08-28)
*
* If you are really that interested, you should be reading
* comp.protocols.time.ntp!
@@ -198,22 +214,21 @@ static inline unsigned long do_gettimeoffset(void)
/*
* This version of gettimeofday has near microsecond resolution.
*/
-static inline void do_gettimeofday(struct timeval *tv)
+void do_gettimeofday(struct timeval *tv)
{
-#if defined (__i386__) || defined (__mips__)
+ unsigned long flags;
+
+ save_flags(flags);
cli();
*tv = xtime;
+#if defined (__i386__) || defined (__mips__)
tv->tv_usec += do_gettimeoffset();
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
}
- sti();
-#else /* not __i386__ */
- cli();
- *tv = xtime;
- sti();
-#endif /* not __i386__ */
+#endif /* !defined (__i386__) && !defined (__mips__) */
+ restore_flags(flags);
}
asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
@@ -226,21 +241,19 @@ asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
if (error)
return error;
do_gettimeofday(&ktv);
- put_fs_long(ktv.tv_sec, (unsigned long *) &tv->tv_sec);
- put_fs_long(ktv.tv_usec, (unsigned long *) &tv->tv_usec);
+ memcpy_tofs(tv, &ktv, sizeof(ktv));
}
if (tz) {
error = verify_area(VERIFY_WRITE, tz, sizeof *tz);
if (error)
return error;
- put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
- put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
+ memcpy_tofs(tz, &sys_tz, sizeof(sys_tz));
}
return 0;
}
/*
- * Adjust the time obtained from the CMOS to be GMT time instead of
+ * Adjust the time obtained from the CMOS to be UTC time instead of
* local time.
*
* This is ugly, but preferable to the alternatives. Otherwise we
@@ -249,11 +262,11 @@ asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
* hard to make the program warp the clock precisely n hours) or
* compile in the timezone information into the kernel. Bad, bad....
*
- * XXX Currently does not adjust for daylight savings time. May not
- * need to do anything, depending on how smart (dumb?) the BIOS
- * is. Blast it all.... the best thing to do not depend on the CMOS
- * clock at all, but get the time via NTP or timed if you're on a
- * network.... - TYT, 1/1/92
+ * - TYT, 1992-01-01
+ *
+ * The best thing to do is to keep the CMOS clock in universal time (UTC)
+ * as real UNIX machines always do it. This avoids all headaches about
+ * daylight saving times and warping kernel clocks.
*/
inline static void warp_clock(void)
{
@@ -263,12 +276,13 @@ inline static void warp_clock(void)
}
/*
- * The first time we set the timezone, we will warp the clock so that
- * it is ticking GMT time instead of local time. Presumably,
- * if someone is setting the timezone then we are running in an
- * environment where the programs understand about timezones.
- * This should be done at boot time in the /etc/rc script, as
- * soon as possible, so that the clock can be set right. Otherwise,
+ * In case for some reason the CMOS clock has not already been running
+ * in UTC, but in some local time: The first time we set the timezone,
+ * we will warp the clock so that it is ticking UTC time instead of
+ * local time. Presumably, if someone is setting the timezone then we
+ * are running in an environment where the programs understand about
+ * timezones. This should be done at boot time in the /etc/rc script,
+ * as soon as possible, so that the clock can be set right. Otherwise,
* various programs will get confused when the clock gets warped.
*/
asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
@@ -441,6 +455,13 @@ asmlinkage int sys_adjtimex(struct timex *txc_p)
return time_status;
}
+/*
+ * 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
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ */
int set_rtc_mmss(unsigned long nowtime)
{
int retval = 0;
@@ -481,7 +502,15 @@ int set_rtc_mmss(unsigned long nowtime)
else
retval = -1;
- CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
return retval;
}