Commit b65769fc authored by Finn Thain's avatar Finn Thain Committed by Geert Uytterhoeven
Browse files

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: default avatarStan Johnson <userm57@yahoo.com>
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Reviewed-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
parent 4eee57d6
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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;
+5 −3
Original line number Diff line number Diff line
@@ -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;
+7 −7
Original line number Diff line number Diff line
@@ -74,18 +74,18 @@ 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) {
	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,
	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)
static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
+3 −1
Original line number Diff line number Diff line
@@ -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;
}
+3 −1
Original line number Diff line number Diff line
@@ -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;
}
Loading