diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1995-11-14 08:00:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1995-11-14 08:00:00 +0000 |
commit | e7c2a72e2680827d6a733931273a93461c0d8d1b (patch) | |
tree | c9abeda78ef7504062bb2e816bcf3e3c9d680112 /kernel/time.c | |
parent | ec6044459060a8c9ce7f64405c465d141898548c (diff) |
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'kernel/time.c')
-rw-r--r-- | kernel/time.c | 121 |
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; } |