Messages in this thread Patch in this message |  | | Date | Sun, 07 Jan 2001 07:38:42 -0500 | From | Paul Gortmaker <> | Subject | Re: 500 ms offset in i386 Real Time Clock setting |
| |
BJerrick@easystreet.com wrote: > > Neither hwclock nor the /dev/rtc driver takes the following comment from > set_rtc_mmss() in arch/i386/kernel/time.c into account. As a result, using > hwclock --systohc or --adjust always leaves the Hardware Clock 500 ms ahead of > the System Clock:
[...]
> Shouldn't there be some kernel interface that hides this machine-dependency > from user-level code; i.e., that sets time more precisely?
I don't have a problem with the rtc driver delaying 500ms before setting the time since that is in fact a feature of the hardware, and it probably should have done this from the beginning. However I would have a problem with the rtc driver using system time (kernel xtime) to synchronize the start of that delay - the user may want to synchronize the rtc with some external source.
Simple patch (2.4.0) to add the delay follows, along with a $0.02 test prog I used to make sure things behave as desired. (I guess hwclock will still require its own delay for when /dev/rtc isn't present and it goes direct.)
Paul.
--- drivers/char/rtc.c~ Sat Jan 6 05:40:24 2001 +++ drivers/char/rtc.c Sun Jan 7 07:17:39 2001 @@ -40,6 +40,7 @@ * 1.10b Andrew Morton: SMP lock fix * 1.10c Cesar Barros: SMP locking fixes and cleanup * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit + * 1.10e Paul Gortmaker: wait 0.5s before writing time to rtc. */ #define RTC_VERSION "1.10d" @@ -414,6 +415,13 @@ BIN_TO_BCD(mon); BIN_TO_BCD(yrs); } + + /* The second for which the clock is set is only 0.5s long */ + spin_unlock_irq(&rtc_lock); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/2); + set_current_state(TASK_RUNNING); + spin_lock_irq(&rtc_lock); save_control = CMOS_READ(RTC_CONTROL); CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); ----------------------8<-------------------8<----------------------- /* * set RTC when system time ticks over, and then read system time on * ten RTC interrupts. An offset of 500,000 usec (0.5sec) will appear * for rtc drivers that don't schedule_timeout(HZ/2) before setting rtc * time, since the second for which the rtc is set is only 1/2 sec long. * With schedule_timeout(), it will be between (n-1)990,000 and (n)10,000 * (Assumes RTC=UTC; change gmtime() to localtime() if not the case) */ #include <stdio.h> #include <linux/rtc.h> #include <sys/ioctl.h> #include <sys/time.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <time.h>
void main(void)
{ int i, fd, retval; unsigned long data; struct tm *tm;
struct timezone tz = {0,}; struct timeval start, now; fd = open ("/dev/rtc", O_RDONLY);
if (fd == -1) { perror("/dev/rtc"); exit(errno); } printf("ZZZzzz. Waiting for next second...\n"); gettimeofday(&start, &tz); do { gettimeofday(&now, &tz); } while (now.tv_sec == start.tv_sec); tm = gmtime(&start.tv_sec);
retval = ioctl(fd, RTC_SET_TIME, tm); /* need root */ if (retval == -1) { perror("ioctl"); exit(errno); } ioctl(fd, RTC_UIE_ON); printf("10 gettimeofday values (sec, usec) exactly when RTC updates:\n");
gettimeofday(&start, &tz); for (i=0;i<10;i++){ read(fd, &data, sizeof(unsigned long)); /* this blocks */ gettimeofday(&now, &tz); printf("\t%ld\t%ld\n", now.tv_sec-start.tv_sec, now.tv_usec); } }
_________________________________________________________ Do You Yahoo!? Get your free @yahoo.com address at http://mail.yahoo.com - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org Please read the FAQ at http://www.tux.org/lkml/
|  |