]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
m68k: Fix off-by-one calendar month
authorFinn Thain <fthain@telegraphics.com.au>
Mon, 23 Apr 2018 01:02:57 +0000 (11:02 +1000)
committerGeert Uytterhoeven <geert@linux-m68k.org>
Tue, 22 May 2018 08:31:50 +0000 (10:31 +0200)
This fixes a bug in read_persistent_clock() which causes the system
clock to lag the Real Time Clock by one month. The problem was noticed
on a Mac, but theoretically it must also affect Atari, BVME6000 and Q40.

The tm_mon value in the struct rtc_time passed to mach_hwclk() is
zero-based, and atari_mste_hwclk(), atari_tt_hwclk(), bvme6000_hwclk(),
mac_hwclk() and q40_hwclk() all make this adjustment. Unfortunately,
dn_dummy_hwclk(), mvme147_hwclk(), mvme16x_hwclk(), sun3_hwclk() and
sun3x_hwclk() fail to decrement tm_mon.  Also m68328_hwclk() assumes
a one-based tm_mon.

Bring these platforms into line and fix read_persistent_clock() so it
works correctly on all m68k platforms.

The datasheets for the RTC devices found on the affected platforms
all confirm that the year is stored as a value in the range 0-99 and
the month is stored as a value in the range 1-12. Please refer to the
datasheets for MC146818 (Apollo), DS1643 (MVME), ICM7170 (Sun 3)
and M48T02 (Sun 3x).

Reported-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
arch/m68k/68000/timers.c
arch/m68k/apollo/config.c
arch/m68k/kernel/time.c
arch/m68k/mvme147/config.c
arch/m68k/mvme16x/config.c
arch/m68k/sun3/intersil.c
arch/m68k/sun3x/time.c

index 252455bce1446b5c3734b054b27afaa85733c9ef..71ddb4c98726b1f43f19f060e41af92707fbde58 100644 (file)
@@ -125,7 +125,9 @@ int m68328_hwclk(int set, struct rtc_time *t)
 {
        if (!set) {
                long now = RTCTIME;
-               t->tm_year = t->tm_mon = t->tm_mday = 1;
+               t->tm_year = 1;
+               t->tm_mon = 0;
+               t->tm_mday = 1;
                t->tm_hour = (now >> 24) % 24;
                t->tm_min = (now >> 16) % 60;
                t->tm_sec = now % 60;
index 0d27706f14d4c01967e051b2c6221cd049435883..b2a6bc63f8cd1aab4806113812bf4c3987bbd8f8 100644 (file)
@@ -221,8 +221,10 @@ int dn_dummy_hwclk(int op, struct rtc_time *t) {
     t->tm_hour=rtc->hours;
     t->tm_mday=rtc->day_of_month;
     t->tm_wday=rtc->day_of_week;
-    t->tm_mon=rtc->month;
+    t->tm_mon = rtc->month - 1;
     t->tm_year=rtc->year;
+    if (t->tm_year < 70)
+       t->tm_year += 100;
   } else {
     rtc->second=t->tm_sec;
     rtc->minute=t->tm_min;
@@ -230,8 +232,8 @@ int dn_dummy_hwclk(int op, struct rtc_time *t) {
     rtc->day_of_month=t->tm_mday;
     if(t->tm_wday!=-1)
       rtc->day_of_week=t->tm_wday;
-    rtc->month=t->tm_mon;
-    rtc->year=t->tm_year;
+    rtc->month = t->tm_mon + 1;
+    rtc->year = t->tm_year % 100;
   }
 
   return 0;
index 97dd4e26f23413e51eecd9876851c3c0f8828281..6b4389a6e8ea4440da5c1b6cbafb748db753edbb 100644 (file)
@@ -74,17 +74,17 @@ static irqreturn_t timer_interrupt(int irq, void *dummy)
 void read_persistent_clock(struct timespec *ts)
 {
        struct rtc_time time;
+
        ts->tv_sec = 0;
        ts->tv_nsec = 0;
 
-       if (mach_hwclk) {
-               mach_hwclk(0, &time);
+       if (!mach_hwclk)
+               return;
+
+       mach_hwclk(0, &time);
 
-               if ((time.tm_year += 1900) < 1970)
-                       time.tm_year += 100;
-               ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
-                                     time.tm_hour, time.tm_min, time.tm_sec);
-       }
+       ts->tv_sec = mktime(time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
+                           time.tm_hour, time.tm_min, time.tm_sec);
 }
 
 #if defined(CONFIG_ARCH_USES_GETTIMEOFFSET) && IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
index 8778612d1f312d5c2c7e588a8b8828adce68eca6..f8a710fd84cd68aea7467653890f1cd14dd45cf4 100644 (file)
@@ -153,12 +153,14 @@ int mvme147_hwclk(int op, struct rtc_time *t)
        if (!op) {
                m147_rtc->ctrl = RTC_READ;
                t->tm_year = bcd2int (m147_rtc->bcd_year);
-               t->tm_mon  = bcd2int (m147_rtc->bcd_mth);
+               t->tm_mon  = bcd2int(m147_rtc->bcd_mth) - 1;
                t->tm_mday = bcd2int (m147_rtc->bcd_dom);
                t->tm_hour = bcd2int (m147_rtc->bcd_hr);
                t->tm_min  = bcd2int (m147_rtc->bcd_min);
                t->tm_sec  = bcd2int (m147_rtc->bcd_sec);
                m147_rtc->ctrl = 0;
+               if (t->tm_year < 70)
+                       t->tm_year += 100;
        }
        return 0;
 }
index 6fa06d4d16bf08d41a56c705dd5699485b0e3516..4ffd9ef98de4db20cb6b151132f53b75e64e84d5 100644 (file)
@@ -400,12 +400,14 @@ int mvme16x_hwclk(int op, struct rtc_time *t)
        if (!op) {
                rtc->ctrl = RTC_READ;
                t->tm_year = bcd2int (rtc->bcd_year);
-               t->tm_mon  = bcd2int (rtc->bcd_mth);
+               t->tm_mon  = bcd2int(rtc->bcd_mth) - 1;
                t->tm_mday = bcd2int (rtc->bcd_dom);
                t->tm_hour = bcd2int (rtc->bcd_hr);
                t->tm_min  = bcd2int (rtc->bcd_min);
                t->tm_sec  = bcd2int (rtc->bcd_sec);
                rtc->ctrl = 0;
+               if (t->tm_year < 70)
+                       t->tm_year += 100;
        }
        return 0;
 }
index 2cd0bcbe6f307909f8b83af0d00b51e0f6bb51a5..d911070af02a5d238d4ea28010cf488fe6b80f02 100644 (file)
@@ -48,9 +48,9 @@ int sun3_hwclk(int set, struct rtc_time *t)
                todintersil->hour = t->tm_hour;
                todintersil->minute = t->tm_min;
                todintersil->second = t->tm_sec;
-               todintersil->month = t->tm_mon;
+               todintersil->month = t->tm_mon + 1;
                todintersil->day = t->tm_mday;
-               todintersil->year = t->tm_year - 68;
+               todintersil->year = (t->tm_year - 68) % 100;
                todintersil->weekday = t->tm_wday;
        } else {
                /* read clock */
@@ -58,10 +58,12 @@ int sun3_hwclk(int set, struct rtc_time *t)
                t->tm_hour = todintersil->hour;
                t->tm_min = todintersil->minute;
                t->tm_sec = todintersil->second;
-               t->tm_mon = todintersil->month;
+               t->tm_mon = todintersil->month - 1;
                t->tm_mday = todintersil->day;
                t->tm_year = todintersil->year + 68;
                t->tm_wday = todintersil->weekday;
+               if (t->tm_year < 70)
+                       t->tm_year += 100;
        }
 
        intersil_clock->cmd_reg = START_VAL;
index 7a2c53d9f779aff6beb908eedab1a28130ad992d..047e2bcee3d7a5710b42e561b0c1a9cc03d3a97e 100644 (file)
@@ -52,8 +52,8 @@ int sun3x_hwclk(int set, struct rtc_time *t)
                h->hour = bin2bcd(t->tm_hour);
                h->wday = bin2bcd(t->tm_wday);
                h->mday = bin2bcd(t->tm_mday);
-               h->month = bin2bcd(t->tm_mon);
-               h->year = bin2bcd(t->tm_year);
+               h->month = bin2bcd(t->tm_mon + 1);
+               h->year = bin2bcd(t->tm_year % 100);
                h->csr &= ~C_WRITE;
        } else {
                h->csr |= C_READ;
@@ -62,9 +62,11 @@ int sun3x_hwclk(int set, struct rtc_time *t)
                t->tm_hour = bcd2bin(h->hour);
                t->tm_wday = bcd2bin(h->wday);
                t->tm_mday = bcd2bin(h->mday);
-               t->tm_mon = bcd2bin(h->month);
+               t->tm_mon = bcd2bin(h->month) - 1;
                t->tm_year = bcd2bin(h->year);
                h->csr &= ~C_READ;
+               if (t->tm_year < 70)
+                       t->tm_year += 100;
        }
 
        local_irq_restore(flags);