summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2018-04-22 21:02:57 -0400
committerGeert Uytterhoeven <geert@linux-m68k.org>2018-05-22 04:31:50 -0400
commitb65769fc013edb7c2e5fdcd91ea6124ad76168f5 (patch)
treeb6ad02cfbf7a81d1a4f339d0873fabb71b8b549e
parent4eee57d68b8b2e6e0a6960c0bacf93448e4ae214 (diff)
m68k: Fix off-by-one calendar month
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>
-rw-r--r--arch/m68k/68000/timers.c4
-rw-r--r--arch/m68k/apollo/config.c8
-rw-r--r--arch/m68k/kernel/time.c14
-rw-r--r--arch/m68k/mvme147/config.c4
-rw-r--r--arch/m68k/mvme16x/config.c4
-rw-r--r--arch/m68k/sun3/intersil.c8
-rw-r--r--arch/m68k/sun3x/time.c8
7 files changed, 31 insertions, 19 deletions
diff --git a/arch/m68k/68000/timers.c b/arch/m68k/68000/timers.c
index 252455bce144..71ddb4c98726 100644
--- a/arch/m68k/68000/timers.c
+++ b/arch/m68k/68000/timers.c
@@ -125,7 +125,9 @@ int m68328_hwclk(int set, struct rtc_time *t)
125{ 125{
126 if (!set) { 126 if (!set) {
127 long now = RTCTIME; 127 long now = RTCTIME;
128 t->tm_year = t->tm_mon = t->tm_mday = 1; 128 t->tm_year = 1;
129 t->tm_mon = 0;
130 t->tm_mday = 1;
129 t->tm_hour = (now >> 24) % 24; 131 t->tm_hour = (now >> 24) % 24;
130 t->tm_min = (now >> 16) % 60; 132 t->tm_min = (now >> 16) % 60;
131 t->tm_sec = now % 60; 133 t->tm_sec = now % 60;
diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
index 0d27706f14d4..b2a6bc63f8cd 100644
--- a/arch/m68k/apollo/config.c
+++ b/arch/m68k/apollo/config.c
@@ -221,8 +221,10 @@ int dn_dummy_hwclk(int op, struct rtc_time *t) {
221 t->tm_hour=rtc->hours; 221 t->tm_hour=rtc->hours;
222 t->tm_mday=rtc->day_of_month; 222 t->tm_mday=rtc->day_of_month;
223 t->tm_wday=rtc->day_of_week; 223 t->tm_wday=rtc->day_of_week;
224 t->tm_mon=rtc->month; 224 t->tm_mon = rtc->month - 1;
225 t->tm_year=rtc->year; 225 t->tm_year=rtc->year;
226 if (t->tm_year < 70)
227 t->tm_year += 100;
226 } else { 228 } else {
227 rtc->second=t->tm_sec; 229 rtc->second=t->tm_sec;
228 rtc->minute=t->tm_min; 230 rtc->minute=t->tm_min;
@@ -230,8 +232,8 @@ int dn_dummy_hwclk(int op, struct rtc_time *t) {
230 rtc->day_of_month=t->tm_mday; 232 rtc->day_of_month=t->tm_mday;
231 if(t->tm_wday!=-1) 233 if(t->tm_wday!=-1)
232 rtc->day_of_week=t->tm_wday; 234 rtc->day_of_week=t->tm_wday;
233 rtc->month=t->tm_mon; 235 rtc->month = t->tm_mon + 1;
234 rtc->year=t->tm_year; 236 rtc->year = t->tm_year % 100;
235 } 237 }
236 238
237 return 0; 239 return 0;
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 97dd4e26f234..6b4389a6e8ea 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -74,17 +74,17 @@ static irqreturn_t timer_interrupt(int irq, void *dummy)
74void read_persistent_clock(struct timespec *ts) 74void read_persistent_clock(struct timespec *ts)
75{ 75{
76 struct rtc_time time; 76 struct rtc_time time;
77
77 ts->tv_sec = 0; 78 ts->tv_sec = 0;
78 ts->tv_nsec = 0; 79 ts->tv_nsec = 0;
79 80
80 if (mach_hwclk) { 81 if (!mach_hwclk)
81 mach_hwclk(0, &time); 82 return;
83
84 mach_hwclk(0, &time);
82 85
83 if ((time.tm_year += 1900) < 1970) 86 ts->tv_sec = mktime(time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
84 time.tm_year += 100; 87 time.tm_hour, time.tm_min, time.tm_sec);
85 ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
86 time.tm_hour, time.tm_min, time.tm_sec);
87 }
88} 88}
89 89
90#if defined(CONFIG_ARCH_USES_GETTIMEOFFSET) && IS_ENABLED(CONFIG_RTC_DRV_GENERIC) 90#if defined(CONFIG_ARCH_USES_GETTIMEOFFSET) && IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index 8778612d1f31..f8a710fd84cd 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -153,12 +153,14 @@ int mvme147_hwclk(int op, struct rtc_time *t)
153 if (!op) { 153 if (!op) {
154 m147_rtc->ctrl = RTC_READ; 154 m147_rtc->ctrl = RTC_READ;
155 t->tm_year = bcd2int (m147_rtc->bcd_year); 155 t->tm_year = bcd2int (m147_rtc->bcd_year);
156 t->tm_mon = bcd2int (m147_rtc->bcd_mth); 156 t->tm_mon = bcd2int(m147_rtc->bcd_mth) - 1;
157 t->tm_mday = bcd2int (m147_rtc->bcd_dom); 157 t->tm_mday = bcd2int (m147_rtc->bcd_dom);
158 t->tm_hour = bcd2int (m147_rtc->bcd_hr); 158 t->tm_hour = bcd2int (m147_rtc->bcd_hr);
159 t->tm_min = bcd2int (m147_rtc->bcd_min); 159 t->tm_min = bcd2int (m147_rtc->bcd_min);
160 t->tm_sec = bcd2int (m147_rtc->bcd_sec); 160 t->tm_sec = bcd2int (m147_rtc->bcd_sec);
161 m147_rtc->ctrl = 0; 161 m147_rtc->ctrl = 0;
162 if (t->tm_year < 70)
163 t->tm_year += 100;
162 } 164 }
163 return 0; 165 return 0;
164} 166}
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index 6fa06d4d16bf..4ffd9ef98de4 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -400,12 +400,14 @@ int mvme16x_hwclk(int op, struct rtc_time *t)
400 if (!op) { 400 if (!op) {
401 rtc->ctrl = RTC_READ; 401 rtc->ctrl = RTC_READ;
402 t->tm_year = bcd2int (rtc->bcd_year); 402 t->tm_year = bcd2int (rtc->bcd_year);
403 t->tm_mon = bcd2int (rtc->bcd_mth); 403 t->tm_mon = bcd2int(rtc->bcd_mth) - 1;
404 t->tm_mday = bcd2int (rtc->bcd_dom); 404 t->tm_mday = bcd2int (rtc->bcd_dom);
405 t->tm_hour = bcd2int (rtc->bcd_hr); 405 t->tm_hour = bcd2int (rtc->bcd_hr);
406 t->tm_min = bcd2int (rtc->bcd_min); 406 t->tm_min = bcd2int (rtc->bcd_min);
407 t->tm_sec = bcd2int (rtc->bcd_sec); 407 t->tm_sec = bcd2int (rtc->bcd_sec);
408 rtc->ctrl = 0; 408 rtc->ctrl = 0;
409 if (t->tm_year < 70)
410 t->tm_year += 100;
409 } 411 }
410 return 0; 412 return 0;
411} 413}
diff --git a/arch/m68k/sun3/intersil.c b/arch/m68k/sun3/intersil.c
index 2cd0bcbe6f30..d911070af02a 100644
--- a/arch/m68k/sun3/intersil.c
+++ b/arch/m68k/sun3/intersil.c
@@ -48,9 +48,9 @@ int sun3_hwclk(int set, struct rtc_time *t)
48 todintersil->hour = t->tm_hour; 48 todintersil->hour = t->tm_hour;
49 todintersil->minute = t->tm_min; 49 todintersil->minute = t->tm_min;
50 todintersil->second = t->tm_sec; 50 todintersil->second = t->tm_sec;
51 todintersil->month = t->tm_mon; 51 todintersil->month = t->tm_mon + 1;
52 todintersil->day = t->tm_mday; 52 todintersil->day = t->tm_mday;
53 todintersil->year = t->tm_year - 68; 53 todintersil->year = (t->tm_year - 68) % 100;
54 todintersil->weekday = t->tm_wday; 54 todintersil->weekday = t->tm_wday;
55 } else { 55 } else {
56 /* read clock */ 56 /* read clock */
@@ -58,10 +58,12 @@ int sun3_hwclk(int set, struct rtc_time *t)
58 t->tm_hour = todintersil->hour; 58 t->tm_hour = todintersil->hour;
59 t->tm_min = todintersil->minute; 59 t->tm_min = todintersil->minute;
60 t->tm_sec = todintersil->second; 60 t->tm_sec = todintersil->second;
61 t->tm_mon = todintersil->month; 61 t->tm_mon = todintersil->month - 1;
62 t->tm_mday = todintersil->day; 62 t->tm_mday = todintersil->day;
63 t->tm_year = todintersil->year + 68; 63 t->tm_year = todintersil->year + 68;
64 t->tm_wday = todintersil->weekday; 64 t->tm_wday = todintersil->weekday;
65 if (t->tm_year < 70)
66 t->tm_year += 100;
65 } 67 }
66 68
67 intersil_clock->cmd_reg = START_VAL; 69 intersil_clock->cmd_reg = START_VAL;
diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
index 7a2c53d9f779..047e2bcee3d7 100644
--- a/arch/m68k/sun3x/time.c
+++ b/arch/m68k/sun3x/time.c
@@ -52,8 +52,8 @@ int sun3x_hwclk(int set, struct rtc_time *t)
52 h->hour = bin2bcd(t->tm_hour); 52 h->hour = bin2bcd(t->tm_hour);
53 h->wday = bin2bcd(t->tm_wday); 53 h->wday = bin2bcd(t->tm_wday);
54 h->mday = bin2bcd(t->tm_mday); 54 h->mday = bin2bcd(t->tm_mday);
55 h->month = bin2bcd(t->tm_mon); 55 h->month = bin2bcd(t->tm_mon + 1);
56 h->year = bin2bcd(t->tm_year); 56 h->year = bin2bcd(t->tm_year % 100);
57 h->csr &= ~C_WRITE; 57 h->csr &= ~C_WRITE;
58 } else { 58 } else {
59 h->csr |= C_READ; 59 h->csr |= C_READ;
@@ -62,9 +62,11 @@ int sun3x_hwclk(int set, struct rtc_time *t)
62 t->tm_hour = bcd2bin(h->hour); 62 t->tm_hour = bcd2bin(h->hour);
63 t->tm_wday = bcd2bin(h->wday); 63 t->tm_wday = bcd2bin(h->wday);
64 t->tm_mday = bcd2bin(h->mday); 64 t->tm_mday = bcd2bin(h->mday);
65 t->tm_mon = bcd2bin(h->month); 65 t->tm_mon = bcd2bin(h->month) - 1;
66 t->tm_year = bcd2bin(h->year); 66 t->tm_year = bcd2bin(h->year);
67 h->csr &= ~C_READ; 67 h->csr &= ~C_READ;
68 if (t->tm_year < 70)
69 t->tm_year += 100;
68 } 70 }
69 71
70 local_irq_restore(flags); 72 local_irq_restore(flags);