forked from Minki/linux
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>
This commit is contained in:
parent
4eee57d68b
commit
b65769fc01
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
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);
|
||||
}
|
||||
mach_hwclk(0, &time);
|
||||
|
||||
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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user