timer: add initial support for RTC seconds locking
authorAlan Cox <alan@linux.intel.com>
Mon, 22 Dec 2014 12:39:17 +0000 (12:39 +0000)
committerAlan Cox <alan@linux.intel.com>
Mon, 22 Dec 2014 12:39:17 +0000 (12:39 +0000)
We don't try and use the RTC as our actual clock. Many RTCs are not Y2K safe
or have their own interesting sets of problems. We would also have to keep
doing Unix type v RTC time conversion maths.

Instead we treat the RTC seconds as a free running counter and update our
second tick as we see the RTC one shift. This also gives us up to 59 seconds
of 'overrun' which should do for the worst case disk I/O problems.

Kernel/include/kernel.h
Kernel/timer.c

index 3b3e388..11b93f9 100644 (file)
@@ -687,6 +687,7 @@ CODE2 void rdtime(time_t *tloc);
 CODE2 void rdtime32(uint32_t *tloc);
 CODE2 void wrtime(time_t *tloc);
 CODE2 extern void updatetod(void);
+CODE2 extern void inittod(void);
 
 /* provided by architecture or helpers */
 CODE2 void device_init(void);  /* provided by platform */
@@ -700,6 +701,8 @@ CODE2 uint8_t *swapout_prepare_uarea(ptptr p);
 CODE2 uint8_t *swapin_prepare_uarea(ptptr p);
 CODE2 void map_init(void);
 CODE2 void platform_idle(void);
+CODE2 uint8_t rtc_secs(void);
+
 /* Will need a uptr_t eventually */
 extern uint16_t ramtop;             /* Note: ramtop must be in common in some cases */
 CODE2 extern void platform_interrupt(void);
index 4a606f2..88f0724 100644 (file)
@@ -43,9 +43,6 @@ void wrtime(time_t *tloc)
 {
         irqflags_t irq = di();
         memcpy(&tod, tloc, sizeof(tod));
-#ifdef CONFIG_RTC
-       machine_set_clock(tloc);
-#endif
        irqrestore(irq);
 }
 
@@ -61,4 +58,38 @@ void updatetod(void)
         if (!++tod.low)
                ++tod.high;
 }
+#else
+
+static uint8_t rtcsec;
+
+/*
+ *     We use the seconds counter on the RTC as a time counter and lock our
+ *     time progression to it. This avoids doing horrible piles of math to
+ *     use the RTC itself and avoids problems with non Y2K devices.
+ *
+ *     We allow for multi-second leaps. On boxes with many of the directly
+ *     interfaced floppy controllers we can reasonably expect to lose IRQ
+ *     service for annoyingly long times.
+ */
+void updatetod(void)
+{
+       uint8_t rtcnew = rtc_secs();    /* platform function */
+       int8_t slide;
+
+       if (rtcnew == rtcsec)
+               return;
+       slide = rtcnew - rtcsec;        /* Seconds elapsed */
+       if (slide < 0)
+               slide += 60;            /* Seconds wrapped */
+       tod.low += slide;
+       if (tod.low < slide)            /* 32bit wrap ? */
+               tod.high++;
+       rtcsec = rtcnew;
+}
+
+void inittod(void)
+{
+       rtcsec = rtc_secs();
+}
+
 #endif                         /* NO_RTC */