This driver uses mktime() and rtc_time_to_tm() to convert between time values. This works fine on 64-bit kernels over the whole supported range, and the vr41xx chip is a 64-bit MIPS implementation, but it is inconsistent because it doesn't do the same thing on 32-bit kernels that overflow in 2106 or 2038.
Changing it to use mktime64/rtc_time64_to_tm() should have no visible impact on vr41xx but gets us closer to removing the 32-bit interfaces.
Signed-off-by: Arnd Bergmann arnd@arndb.de --- drivers/rtc/rtc-vr41xx.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 7ce22967fd16..480cffe8d321 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -88,7 +88,7 @@ static unsigned int alarm_enabled; static int aie_irq; static int pie_irq;
-static inline unsigned long read_elapsed_second(void) +static inline time64_t read_elapsed_second(void) {
unsigned long first_low, first_mid, first_high; @@ -105,10 +105,10 @@ static inline unsigned long read_elapsed_second(void) } while (first_low != second_low || first_mid != second_mid || first_high != second_high);
- return (first_high << 17) | (first_mid << 1) | (first_low >> 15); + return ((u64)first_high << 17) | (first_mid << 1) | (first_low >> 15); }
-static inline void write_elapsed_second(unsigned long sec) +static inline void write_elapsed_second(time64_t sec) { spin_lock_irq(&rtc_lock);
@@ -121,22 +121,22 @@ static inline void write_elapsed_second(unsigned long sec)
static int vr41xx_rtc_read_time(struct device *dev, struct rtc_time *time) { - unsigned long epoch_sec, elapsed_sec; + time64_t epoch_sec, elapsed_sec;
- epoch_sec = mktime(epoch, 1, 1, 0, 0, 0); + epoch_sec = mktime64(epoch, 1, 1, 0, 0, 0); elapsed_sec = read_elapsed_second();
- rtc_time_to_tm(epoch_sec + elapsed_sec, time); + rtc_time64_to_tm(epoch_sec + elapsed_sec, time);
return 0; }
static int vr41xx_rtc_set_time(struct device *dev, struct rtc_time *time) { - unsigned long epoch_sec, current_sec; + time64_t epoch_sec, current_sec;
- epoch_sec = mktime(epoch, 1, 1, 0, 0, 0); - current_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, + epoch_sec = mktime64(epoch, 1, 1, 0, 0, 0); + current_sec = mktime64(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec);
write_elapsed_second(current_sec - epoch_sec); @@ -165,11 +165,11 @@ static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) { - unsigned long alarm_sec; + time64_t alarm_sec; struct rtc_time *time = &wkalrm->time;
- alarm_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, - time->tm_hour, time->tm_min, time->tm_sec); + alarm_sec = mktime64(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, + time->tm_hour, time->tm_min, time->tm_sec);
spin_lock_irq(&rtc_lock);
The loongson1 platform is 32-bit, so storing a time value in 32 bits suffers from limited range. In this case it is likely to be correct until 2106, but it's better to avoid the limitation and just use the time64_t based mktime64() and rtc_time64_to_tm() interfaces.
The hardware uses a 32-bit year number, and time64_t can cover that entire range.
Signed-off-by: Arnd Bergmann arnd@arndb.de --- drivers/rtc/rtc-ls1x.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c index 045af1135e48..de86f9fabc11 100644 --- a/drivers/rtc/rtc-ls1x.c +++ b/drivers/rtc/rtc-ls1x.c @@ -87,16 +87,17 @@
static int ls1x_rtc_read_time(struct device *dev, struct rtc_time *rtm) { - unsigned long v, t; + unsigned long v; + time64_t t;
v = readl(SYS_TOYREAD0); t = readl(SYS_TOYREAD1);
memset(rtm, 0, sizeof(struct rtc_time)); - t = mktime((t & LS1X_YEAR_MASK), ls1x_get_month(v), + t = mktime64((t & LS1X_YEAR_MASK), ls1x_get_month(v), ls1x_get_day(v), ls1x_get_hour(v), ls1x_get_min(v), ls1x_get_sec(v)); - rtc_time_to_tm(t, rtm); + rtc_time64_to_tm(t, rtm);
return 0; }
The tps6586x use a 64-bit 'epoch_start' value, but then computes that value using an 'mktime()', which has a smaller range and overflows in 2106 at the latest. As both the hardware and the subsystem interface support wider than 32-bit ranges for rtc times here, let's change all the operations on 'seconds' to time64_t.
Signed-off-by: Arnd Bergmann arnd@arndb.de --- drivers/rtc/rtc-tps6586x.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index d7785ae0a2b4..46a19adf9a96 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -58,7 +58,7 @@ struct tps6586x_rtc { struct rtc_device *rtc; int irq; bool irq_en; - unsigned long long epoch_start; + time64_t epoch_start; };
static inline struct device *to_tps6586x_dev(struct device *dev) @@ -71,7 +71,7 @@ static int tps6586x_rtc_read_time(struct device *dev, struct rtc_time *tm) struct tps6586x_rtc *rtc = dev_get_drvdata(dev); struct device *tps_dev = to_tps6586x_dev(dev); unsigned long long ticks = 0; - unsigned long seconds; + time64_t seconds; u8 buff[6]; int ret; int i; @@ -98,11 +98,11 @@ static int tps6586x_rtc_set_time(struct device *dev, struct rtc_time *tm) struct tps6586x_rtc *rtc = dev_get_drvdata(dev); struct device *tps_dev = to_tps6586x_dev(dev); unsigned long long ticks; - unsigned long seconds; + time64_t seconds; u8 buff[5]; int ret;
- rtc_tm_to_time(tm, &seconds); + seconds = rtc_tm_to_time64(tm); if (seconds < rtc->epoch_start) { dev_err(dev, "requested time unsupported\n"); return -EINVAL; @@ -157,7 +157,7 @@ static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct tps6586x_rtc *rtc = dev_get_drvdata(dev); struct device *tps_dev = to_tps6586x_dev(dev); - unsigned long seconds; + time64_t seconds; unsigned long ticks; unsigned long rtc_current_time; unsigned long long rticks = 0; @@ -166,7 +166,7 @@ static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) int ret; int i;
- rtc_tm_to_time(&alrm->time, &seconds); + seconds = rtc_tm_to_time64(&alrm->time);
if (alrm->enabled && (seconds < rtc->epoch_start)) { dev_err(dev, "can't set alarm to requested time\n"); @@ -213,7 +213,7 @@ static int tps6586x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct tps6586x_rtc *rtc = dev_get_drvdata(dev); struct device *tps_dev = to_tps6586x_dev(dev); unsigned long ticks; - unsigned long seconds; + time64_t seconds; u8 buff[3]; int ret;
@@ -227,7 +227,7 @@ static int tps6586x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) seconds = ticks >> 10; seconds += rtc->epoch_start;
- rtc_time_to_tm(seconds, &alrm->time); + rtc_time64_to_tm(seconds, &alrm->time); return 0; }
@@ -261,7 +261,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) rtc->irq = platform_get_irq(pdev, 0);
/* Set epoch start as 00:00:00:01:01:2009 */ - rtc->epoch_start = mktime(2009, 1, 1, 0, 0, 0); + rtc->epoch_start = mktime64(2009, 1, 1, 0, 0, 0);
/* 1 kHz tick mode, enable tick counting */ ret = tps6586x_update(tps_dev, RTC_CTRL,
Hi,
On 20/04/2018 18:14:24+0200, Arnd Bergmann wrote:
This driver uses mktime() and rtc_time_to_tm() to convert between time values. This works fine on 64-bit kernels over the whole supported range, and the vr41xx chip is a 64-bit MIPS implementation, but it is inconsistent because it doesn't do the same thing on 32-bit kernels that overflow in 2106 or 2038.
Changing it to use mktime64/rtc_time64_to_tm() should have no visible impact on vr41xx but gets us closer to removing the 32-bit interfaces.
Signed-off-by: Arnd Bergmann arnd@arndb.de
drivers/rtc/rtc-vr41xx.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
I've applied the series a while ago. It should be noted that mktime64 will fail on 32bit platforms in year 21000 or so but I pretty sure it is not worth fixing. My understanding is that the kernel will fail in April 2262 anyway as ktime_t will overflow.
Note that I will be following up with multiple series adding proper rtc HW range, removing set_mmss and rtc_time_to_tm/rtc_tm_to_time64.
On Wed, May 16, 2018 at 9:55 AM, Alexandre Belloni alexandre.belloni@bootlin.com wrote:
Hi,
On 20/04/2018 18:14:24+0200, Arnd Bergmann wrote:
This driver uses mktime() and rtc_time_to_tm() to convert between time values. This works fine on 64-bit kernels over the whole supported range, and the vr41xx chip is a 64-bit MIPS implementation, but it is inconsistent because it doesn't do the same thing on 32-bit kernels that overflow in 2106 or 2038.
Changing it to use mktime64/rtc_time64_to_tm() should have no visible impact on vr41xx but gets us closer to removing the 32-bit interfaces.
Signed-off-by: Arnd Bergmann arnd@arndb.de
drivers/rtc/rtc-vr41xx.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
I've applied the series a while ago.
Thanks! We should be able to remove mktime() in the near future then, along with some other interfaces from linux/time32.h and linux/timekeeping32.h.
It should be noted that mktime64 will fail on 32bit platforms in year 21000 or so but I pretty sure it is not worth fixing. My understanding is that the kernel will fail in April 2262 anyway as ktime_t will overflow.
Right.
Note that I will be following up with multiple series adding proper rtc HW range, removing set_mmss and rtc_time_to_tm/rtc_tm_to_time64.
Ok, looking forward to those patches!
Arnd