diff options
author | Finn Thain <fthain@telegraphics.com.au> | 2018-04-22 21:02:57 -0400 |
---|---|---|
committer | Geert Uytterhoeven <geert@linux-m68k.org> | 2018-05-22 04:31:50 -0400 |
commit | b65769fc013edb7c2e5fdcd91ea6124ad76168f5 (patch) | |
tree | b6ad02cfbf7a81d1a4f339d0873fabb71b8b549e | |
parent | 4eee57d68b8b2e6e0a6960c0bacf93448e4ae214 (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.c | 4 | ||||
-rw-r--r-- | arch/m68k/apollo/config.c | 8 | ||||
-rw-r--r-- | arch/m68k/kernel/time.c | 14 | ||||
-rw-r--r-- | arch/m68k/mvme147/config.c | 4 | ||||
-rw-r--r-- | arch/m68k/mvme16x/config.c | 4 | ||||
-rw-r--r-- | arch/m68k/sun3/intersil.c | 8 | ||||
-rw-r--r-- | arch/m68k/sun3x/time.c | 8 |
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) | |||
74 | void read_persistent_clock(struct timespec *ts) | 74 | void 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); |