diff mbox series

[2/3,v2] m68k: mac: use time64_t in RTC handling

Message ID 20180619140229.3615110-2-arnd@arndb.de
State New
Headers show
Series [1/3,v2] powerpc: mac: fix rtc read/write functions | expand

Commit Message

Arnd Bergmann June 19, 2018, 2:02 p.m. UTC
The real-time clock on m68k (and powerpc) mac systems uses an unsigned
32-bit value starting in 1904, which overflows in 2040, about two years
later than everyone else, but this gets wrapped around in the Linux
code in 2038 already because of the deprecated usage of time_t and/or
long in the conversion.

Getting rid of the deprecated interfaces makes it work until 2040 as
documented, and it could be easily extended by reinterpreting
the resulting time64_t as a positive number. For the moment, I'm
adding a WARN_ON() that triggers if we encounter a time before 1970
or after 2040 (the two are indistinguishable).

This brings it in line with the corresponding code that we have on
powerpc macintosh.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

---
v2: Fix varargs passing bug pointed out by Andreas Schwab
    Fix a typo that caused a build regression
---
 arch/m68k/mac/misc.c | 62 +++++++++++++++++++++++++++++++++-------------------
 1 file changed, 39 insertions(+), 23 deletions(-)

-- 
2.9.0

Comments

Finn Thain June 22, 2018, 5:26 a.m. UTC | #1
On Tue, 19 Jun 2018, Arnd Bergmann wrote:

> The real-time clock on m68k (and powerpc) mac systems uses an unsigned 

> 32-bit value starting in 1904, which overflows in 2040, about two years 

> later than everyone else, but this gets wrapped around in the Linux code 

> in 2038 already because of the deprecated usage of time_t and/or long in 

> the conversion.

> 

> Getting rid of the deprecated interfaces makes it work until 2040 as 

> documented, and it could be easily extended by reinterpreting the 

> resulting time64_t as a positive number. For the moment, I'm adding a 

> WARN_ON() that triggers if we encounter a time before 1970 or after 2040 

> (the two are indistinguishable).

> 


I really don't like the WARN_ON(), but I'd prefer to address that in a 
separate patch rather than impede the progress of this patch (or of this 
series, since 3/3 seems to be unrelated).

BTW, have you considered using the same wrap-around test (i.e. YY < 70) 
that we use for the year register in the other RTC chips?

> This brings it in line with the corresponding code that we have on 

> powerpc macintosh.

> 


Your recent patches to the Mac RTC routines (which are duplicated under 
arch/m68k and arch/powerpc) conflict with my recent patch that 
deduplicates the same code. So I will rebase and resubmit after someone 
merges these fixes.

Apparently the PowerMac routines work now, which is sufficient testing for 
me; the PowerMac routines will get tested on m68k Macs when that code gets 
deduplicated again.

BTW, Joshua tells me that he is not doing code review. We should probably 
drop the "M68K ON APPLE MACINTOSH" entry from the MAINTAINERS file, like 
the Amiga and Atari ports...

-- 

> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

> ---

> v2: Fix varargs passing bug pointed out by Andreas Schwab

>     Fix a typo that caused a build regression

> ---

>  arch/m68k/mac/misc.c | 62 +++++++++++++++++++++++++++++++++-------------------

>  1 file changed, 39 insertions(+), 23 deletions(-)

> 

> diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c

> index c68054361615..0a2572a6bfe5 100644

> --- a/arch/m68k/mac/misc.c

> +++ b/arch/m68k/mac/misc.c

> @@ -26,33 +26,39 @@

>  

>  #include <asm/machdep.h>

>  

> -/* Offset between Unix time (1970-based) and Mac time (1904-based) */

> +/* Offset between Unix time (1970-based) and Mac time (1904-based). Cuda and PMU

> + * times wrap in 2040. If we need to handle later times, the read_time functions

> + * need to be changed to interpret wrapped times as post-2040. */

>  

>  #define RTC_OFFSET 2082844800

>  

>  static void (*rom_reset)(void);

>  

>  #ifdef CONFIG_ADB_CUDA

> -static long cuda_read_time(void)

> +static time64_t cuda_read_time(void)

>  {

>  	struct adb_request req;

> -	long time;

> +	time64_t time;

>  

>  	if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)

>  		return 0;

>  	while (!req.complete)

>  		cuda_poll();

>  

> -	time = (req.reply[3] << 24) | (req.reply[4] << 16) |

> -	       (req.reply[5] << 8) | req.reply[6];

> +	time = (u32)((req.reply[3] << 24) | (req.reply[4] << 16) |

> +		     (req.reply[5] << 8) | req.reply[6]);

> +

> +	/* it's either after year 2040, or the RTC has gone backwards */

> +	WARN_ON(time < RTC_OFFSET);

> +

>  	return time - RTC_OFFSET;

>  }

>  

> -static void cuda_write_time(long data)

> +static void cuda_write_time(time64_t time)

>  {

>  	struct adb_request req;

> +	u32 data = lower_32_bits(time + RTC_OFFSET);

>  

> -	data += RTC_OFFSET;

>  	if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,

>  			 (data >> 24) & 0xFF, (data >> 16) & 0xFF,

>  			 (data >> 8) & 0xFF, data & 0xFF) < 0)

> @@ -86,26 +92,30 @@ static void cuda_write_pram(int offset, __u8 data)

>  #endif /* CONFIG_ADB_CUDA */

>  

>  #ifdef CONFIG_ADB_PMU68K

> -static long pmu_read_time(void)

> +static time64_t pmu_read_time(void)

>  {

>  	struct adb_request req;

> -	long time;

> +	time64_t time;

>  

>  	if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)

>  		return 0;

>  	while (!req.complete)

>  		pmu_poll();

>  

> -	time = (req.reply[1] << 24) | (req.reply[2] << 16) |

> -	       (req.reply[3] << 8) | req.reply[4];

> +	time = (u32)((req.reply[1] << 24) | (req.reply[2] << 16) |

> +		     (req.reply[3] << 8) | req.reply[4]);

> +

> +	/* it's either after year 2040, or the RTC has gone backwards */

> +	WARN_ON(time < RTC_OFFSET);

> +

>  	return time - RTC_OFFSET;

>  }

>  

> -static void pmu_write_time(long data)

> +static void pmu_write_time(time64_t time)

>  {

>  	struct adb_request req;

> +	u32 data = lower_32_bits(time + RTC_OFFSET);

>  

> -	data += RTC_OFFSET;

>  	if (pmu_request(&req, NULL, 5, PMU_SET_RTC,

>  			(data >> 24) & 0xFF, (data >> 16) & 0xFF,

>  			(data >> 8) & 0xFF, data & 0xFF) < 0)

> @@ -269,8 +279,12 @@ static long via_read_time(void)

>  		via_pram_command(0x89, &result.cdata[1]);

>  		via_pram_command(0x8D, &result.cdata[0]);

>  

> -		if (result.idata == last_result.idata)

> +		if (result.idata == last_result.idata) {

> +			if (result.idata < RTC_OFFSET)

> +				result.idata += 0x100000000ull;

> +

>  			return result.idata - RTC_OFFSET;

> +		}

>  

>  		if (++count > 10)

>  			break;

> @@ -291,11 +305,11 @@ static long via_read_time(void)

>   * is basically any machine with Mac II-style ADB.

>   */

>  

> -static void via_write_time(long time)

> +static void via_write_time(time64_t time)

>  {

>  	union {

>  		__u8 cdata[4];

> -		long idata;

> +		__u32 idata;

>  	} data;

>  	__u8 temp;

>  

> @@ -585,12 +599,15 @@ void mac_reset(void)

>   * This function translates seconds since 1970 into a proper date.

>   *

>   * Algorithm cribbed from glibc2.1, __offtime().

> + *

> + * This is roughly same as rtc_time64_to_tm(), which we should probably

> + * use here, but it's only available when CONFIG_RTC_LIB is enabled.

>   */

>  #define SECS_PER_MINUTE (60)

>  #define SECS_PER_HOUR  (SECS_PER_MINUTE * 60)

>  #define SECS_PER_DAY   (SECS_PER_HOUR * 24)

>  

> -static void unmktime(unsigned long time, long offset,

> +static void unmktime(time64_t time, long offset,

>  		     int *yearp, int *monp, int *dayp,

>  		     int *hourp, int *minp, int *secp)

>  {

> @@ -602,11 +619,10 @@ static void unmktime(unsigned long time, long offset,

>  		/* Leap years.  */

>  		{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }

>  	};

> -	long int days, rem, y, wday, yday;

> +	int days, rem, y, wday, yday;

>  	const unsigned short int *ip;

>  

> -	days = time / SECS_PER_DAY;

> -	rem = time % SECS_PER_DAY;

> +	days = div_u64_rem(time, SECS_PER_DAY, &rem);

>  	rem += offset;

>  	while (rem < 0) {

>  		rem += SECS_PER_DAY;

> @@ -657,7 +673,7 @@ static void unmktime(unsigned long time, long offset,

>  

>  int mac_hwclk(int op, struct rtc_time *t)

>  {

> -	unsigned long now;

> +	time64_t now;

>  

>  	if (!op) { /* read */

>  		switch (macintosh_config->adb_type) {

> @@ -693,8 +709,8 @@ int mac_hwclk(int op, struct rtc_time *t)

>  		         __func__, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,

>  		         t->tm_hour, t->tm_min, t->tm_sec);

>  

> -		now = mktime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,

> -			     t->tm_hour, t->tm_min, t->tm_sec);

> +		now = mktime64(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,

> +			       t->tm_hour, t->tm_min, t->tm_sec);

>  

>  		switch (macintosh_config->adb_type) {

>  		case MAC_ADB_IOP:

>
Arnd Bergmann June 22, 2018, 8:54 a.m. UTC | #2
On Fri, Jun 22, 2018 at 7:26 AM, Finn Thain <fthain@telegraphics.com.au> wrote:
> On Tue, 19 Jun 2018, Arnd Bergmann wrote:

>

>> The real-time clock on m68k (and powerpc) mac systems uses an unsigned

>> 32-bit value starting in 1904, which overflows in 2040, about two years

>> later than everyone else, but this gets wrapped around in the Linux code

>> in 2038 already because of the deprecated usage of time_t and/or long in

>> the conversion.

>>

>> Getting rid of the deprecated interfaces makes it work until 2040 as

>> documented, and it could be easily extended by reinterpreting the

>> resulting time64_t as a positive number. For the moment, I'm adding a

>> WARN_ON() that triggers if we encounter a time before 1970 or after 2040

>> (the two are indistinguishable).

>>

>

> I really don't like the WARN_ON(), but I'd prefer to address that in a

> separate patch rather than impede the progress of this patch (or of this

> series, since 3/3 seems to be unrelated).

>

> BTW, have you considered using the same wrap-around test (i.e. YY < 70)

> that we use for the year register in the other RTC chips?


That wrap-around test would have the same effect as the my original
version (aside from the two bugs I now fixed), doing rougly

-        return time - RTC_OFFSET;
+        return (u32)(time - RTC_OFFSET);

or some other variation of that will give us an RTC that supports all dates
between 1970 and 2106. I don't think anyone so far had a strong
preference here, so I went with what Mathieu suggested and kept the
original Mac behavior, but added the WARN_ON().

>> This brings it in line with the corresponding code that we have on

>> powerpc macintosh.

>>

>

> Your recent patches to the Mac RTC routines (which are duplicated under

> arch/m68k and arch/powerpc) conflict with my recent patch that

> deduplicates the same code. So I will rebase and resubmit after someone

> merges these fixes.

>

> Apparently the PowerMac routines work now, which is sufficient testing for

> me; the PowerMac routines will get tested on m68k Macs when that code gets

> deduplicated again.


Sorry about introducing that conflict, and thanks for bearing with me on the
rebase. One thing to watch out for (if you haven't noticed already) is that the
powerpc version now depends on rtc_time64_to_tm/rtc_tm_to_time64 which
are only available if CONFIG_RTC_LIB is enabled but simplifies the code a
bit. I did not want to introduce that as a global dependency on m68k which
is rather limited on code size already, but it probably doesn't hurt to require
RTC_LIB on m68k-mac.

        Arnd
Geert Uytterhoeven July 8, 2018, 10:49 a.m. UTC | #3
Hi Arnd, Finn,

On Fri, Jun 22, 2018 at 10:55 AM Arnd Bergmann <arnd@arndb.de> wrote:
> On Fri, Jun 22, 2018 at 7:26 AM, Finn Thain <fthain@telegraphics.com.au> wrote:

> > On Tue, 19 Jun 2018, Arnd Bergmann wrote:

> >

> >> The real-time clock on m68k (and powerpc) mac systems uses an unsigned

> >> 32-bit value starting in 1904, which overflows in 2040, about two years

> >> later than everyone else, but this gets wrapped around in the Linux code

> >> in 2038 already because of the deprecated usage of time_t and/or long in

> >> the conversion.

> >>

> >> Getting rid of the deprecated interfaces makes it work until 2040 as

> >> documented, and it could be easily extended by reinterpreting the

> >> resulting time64_t as a positive number. For the moment, I'm adding a

> >> WARN_ON() that triggers if we encounter a time before 1970 or after 2040

> >> (the two are indistinguishable).

> >>

> >

> > I really don't like the WARN_ON(), but I'd prefer to address that in a

> > separate patch rather than impede the progress of this patch (or of this

> > series, since 3/3 seems to be unrelated).

> >

> > BTW, have you considered using the same wrap-around test (i.e. YY < 70)

> > that we use for the year register in the other RTC chips?

>

> That wrap-around test would have the same effect as the my original

> version (aside from the two bugs I now fixed), doing rougly

>

> -        return time - RTC_OFFSET;

> +        return (u32)(time - RTC_OFFSET);

>

> or some other variation of that will give us an RTC that supports all dates

> between 1970 and 2106. I don't think anyone so far had a strong

> preference here, so I went with what Mathieu suggested and kept the

> original Mac behavior, but added the WARN_ON().


So, is this safe to apply?
Especially in light of the warnings seen by Meelis with the PPC version.

Thanks!


Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Finn Thain July 8, 2018, 11:45 a.m. UTC | #4
On Sun, 8 Jul 2018, Geert Uytterhoeven wrote:

> On Fri, Jun 22, 2018 at 10:55 AM Arnd Bergmann <arnd@arndb.de> wrote:


> > I don't think anyone so far had a strong preference here, so I went 

> > with what Mathieu suggested and kept the original Mac behavior, but 

> > added the WARN_ON().

> 

> So, is this safe to apply?

> Especially in light of the warnings seen by Meelis with the PPC version.

> 


You mean, "can we apply this and avoid warning splats?"

Meelis's result says, "no".

I forget what date the RTC gets set to when the PMU/Cuda is reset but I 
suspect that timezone arithmetic in either MacOS or Linux could cause it 
to end up in 1969.

So I'd prefer to see the WARN_ON() removed.

--
Geert Uytterhoeven July 18, 2018, 11:36 a.m. UTC | #5
On Tue, Jun 19, 2018 at 4:04 PM Arnd Bergmann <arnd@arndb.de> wrote:
> The real-time clock on m68k (and powerpc) mac systems uses an unsigned

> 32-bit value starting in 1904, which overflows in 2040, about two years

> later than everyone else, but this gets wrapped around in the Linux

> code in 2038 already because of the deprecated usage of time_t and/or

> long in the conversion.

>

> Getting rid of the deprecated interfaces makes it work until 2040 as

> documented, and it could be easily extended by reinterpreting

> the resulting time64_t as a positive number. For the moment, I'm

> adding a WARN_ON() that triggers if we encounter a time before 1970

> or after 2040 (the two are indistinguishable).

>

> This brings it in line with the corresponding code that we have on

> powerpc macintosh.

>

> Signed-off-by: Arnd Bergmann <arnd@arndb.de>


Thanks for your patch!

Applied and queued for v4.19, with the WARN_ON() dropped.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Finn Thain July 18, 2018, 12:02 p.m. UTC | #6
On Wed, 18 Jul 2018, Geert Uytterhoeven wrote:

> 

> Thanks for your patch!

> 

> Applied and queued for v4.19, with the WARN_ON() dropped.

> 


The patch you've committed to your for-v4.19 branch has this hunk:

@@ -269,8 +275,12 @@ static long via_read_time(void)
                via_pram_command(0x89, &result.cdata[1]);
                via_pram_command(0x8D, &result.cdata[0]);
 
-               if (result.idata == last_result.idata)
+               if (result.idata == last_result.idata) {
+                       if (result.idata < RTC_OFFSET)
+                               result.idata += 0x100000000ull;
+
                        return result.idata - RTC_OFFSET;
+               }
 
                if (++count > 10)
                        break;

That looks bogus to me, since result.idata is a long.

Also, the following hunk seems a bit pointless (?)

@@ -291,11 +301,11 @@ static long via_read_time(void)
  * is basically any machine with Mac II-style ADB.
  */
 
-static void via_write_time(long time)
+static void via_write_time(time64_t time)
 {
        union {
                __u8 cdata[4];
-               long idata;
+               __u32 idata;
        } data;
        __u8 temp;
 

But if data.idata needs to be changed to __u32 here, why not change the 
same struct member in via_read_time() also?

--
Arnd Bergmann July 18, 2018, 12:20 p.m. UTC | #7
On Wed, Jul 18, 2018 at 2:02 PM, Finn Thain <fthain@telegraphics.com.au> wrote:
> On Wed, 18 Jul 2018, Geert Uytterhoeven wrote:

>

>>

>> Thanks for your patch!

>>

>> Applied and queued for v4.19, with the WARN_ON() dropped.

>>

>

> The patch you've committed to your for-v4.19 branch has this hunk:

>

> @@ -269,8 +275,12 @@ static long via_read_time(void)

>                 via_pram_command(0x89, &result.cdata[1]);

>                 via_pram_command(0x8D, &result.cdata[0]);

>

> -               if (result.idata == last_result.idata)

> +               if (result.idata == last_result.idata) {

> +                       if (result.idata < RTC_OFFSET)

> +                               result.idata += 0x100000000ull;

> +

>                         return result.idata - RTC_OFFSET;

> +               }

>

>                 if (++count > 10)

>                         break;

>

> That looks bogus to me, since result.idata is a long.




> Also, the following hunk seems a bit pointless (?)

>

> @@ -291,11 +301,11 @@ static long via_read_time(void)

>   * is basically any machine with Mac II-style ADB.

>   */

>

> -static void via_write_time(long time)

> +static void via_write_time(time64_t time)

>  {

>         union {

>                 __u8 cdata[4];

> -               long idata;

> +               __u32 idata;

>         } data;

>         __u8 temp;

>

>

> But if data.idata needs to be changed to __u32 here, why not change the

> same struct member in via_read_time() also?


Hmm, apparently I forgot to update via_read_time(), that one
is indeed bogus and now inconsistent with the other functions.

The change in via_write_time() seems at least consistent wtih
what we do elsewhere, and using __u32 makes this code
more portable. (yes, I realize that 64-bit powermac doesn't
use the VIA RTC, but it feels better to write code portably
anyway).

I'd suggest we do it like below to make it consistent with the
rest again, using the 1904..2040 range of dates and no warning
for invalid dates.

If you agree, I'll send that as a proper patch.

       Arnd

diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index bf8df47a6d09..8335509969f1 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -255,12 +255,13 @@ static void via_write_pram(int offset, __u8 data)
  * is basically any machine with Mac II-style ADB.
  */

-static long via_read_time(void)
+static time64_t via_read_time(void)
 {
        union {
                __u8 cdata[4];
-               long idata;
+               __u32 idata;
        } result, last_result;
+       time64_t ret;
        int count = 1;

        via_pram_command(0x81, &last_result.cdata[3]);
@@ -279,12 +280,8 @@ static long via_read_time(void)
                via_pram_command(0x89, &result.cdata[1]);
                via_pram_command(0x8D, &result.cdata[0]);

-               if (result.idata == last_result.idata) {
-                       if (result.idata < RTC_OFFSET)
-                               result.idata += 0x100000000ull;
-
-                       return result.idata - RTC_OFFSET;
-               }
+               if (result.idata == last_result.idata)
+                       return (time64_t(result.idata) - RTC_OFFSET);

                if (++count > 10)
                        break;
Finn Thain July 18, 2018, 1:49 p.m. UTC | #8
On Wed, 18 Jul 2018, Arnd Bergmann wrote:

> Hmm, apparently I forgot to update via_read_time(), that one

> is indeed bogus and now inconsistent with the other functions.

> 

> The change in via_write_time() seems at least consistent wtih what we do 

> elsewhere, and using __u32 makes this code more portable. (yes, I 

> realize that 64-bit powermac doesn't use the VIA RTC, but it feels 

> better to write code portably anyway).

> 


As for portability, I think you just contradicted yourself. But I take 
your point about consistency. So I won't object to adopting __u32.

> I'd suggest we do it like below to make it consistent with the

> rest again, using the 1904..2040 range of dates and no warning

> for invalid dates.

> 

> If you agree, I'll send that as a proper patch.

> 


Geert may instead wish to fixup or revert the patch he has committed 
already...

>        Arnd

> 

> diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c

> index bf8df47a6d09..8335509969f1 100644

> --- a/arch/m68k/mac/misc.c

> +++ b/arch/m68k/mac/misc.c

> @@ -255,12 +255,13 @@ static void via_write_pram(int offset, __u8 data)

>   * is basically any machine with Mac II-style ADB.

>   */

> 

> -static long via_read_time(void)

> +static time64_t via_read_time(void)

>  {

>         union {

>                 __u8 cdata[4];

> -               long idata;

> +               __u32 idata;

>         } result, last_result;

> +       time64_t ret;


ret isn't used.

>         int count = 1;

> 

>         via_pram_command(0x81, &last_result.cdata[3]);

> @@ -279,12 +280,8 @@ static long via_read_time(void)

>                 via_pram_command(0x89, &result.cdata[1]);

>                 via_pram_command(0x8D, &result.cdata[0]);

> 

> -               if (result.idata == last_result.idata) {

> -                       if (result.idata < RTC_OFFSET)

> -                               result.idata += 0x100000000ull;

> -

> -                       return result.idata - RTC_OFFSET;

> -               }

> +               if (result.idata == last_result.idata)

> +                       return (time64_t(result.idata) - RTC_OFFSET);

> 


Did you mean to write,

			return (time64_t)result.idata - RTC_OFFSET;

?

--
Arnd Bergmann July 18, 2018, 2:26 p.m. UTC | #9
On Wed, Jul 18, 2018 at 3:49 PM, Finn Thain <fthain@telegraphics.com.au> wrote:
> On Wed, 18 Jul 2018, Arnd Bergmann wrote:


>>

>> -static long via_read_time(void)

>> +static time64_t via_read_time(void)

>>  {

>>         union {

>>                 __u8 cdata[4];

>> -               long idata;

>> +               __u32 idata;

>>         } result, last_result;

>> +       time64_t ret;

>

> ret isn't used.

>

>>         int count = 1;

>>

>>         via_pram_command(0x81, &last_result.cdata[3]);

>> @@ -279,12 +280,8 @@ static long via_read_time(void)

>>                 via_pram_command(0x89, &result.cdata[1]);

>>                 via_pram_command(0x8D, &result.cdata[0]);

>>

>> -               if (result.idata == last_result.idata) {

>> -                       if (result.idata < RTC_OFFSET)

>> -                               result.idata += 0x100000000ull;

>> -

>> -                       return result.idata - RTC_OFFSET;

>> -               }

>> +               if (result.idata == last_result.idata)

>> +                       return (time64_t(result.idata) - RTC_OFFSET);

>>

>

> Did you mean to write,

>

>                         return (time64_t)result.idata - RTC_OFFSET;

>

> ?


Right, I should have at least tried to build it again.

      Arnd
Finn Thain July 22, 2018, 11:56 a.m. UTC | #10
On Wed, 18 Jul 2018, I wrote:

> On Wed, 18 Jul 2018, Arnd Bergmann wrote:

> 

> > I'd suggest we do it like below to make it consistent with the rest 

> > again, using the 1904..2040 range of dates and no warning for invalid 

> > dates.

> > 

> > If you agree, I'll send that as a proper patch.

> > 

> 

> Geert may instead wish to fixup or revert the patch he has committed 

> already...


Geert, how do you want to handle this?

Do you want a fixup patch or a v3 patch with the WARN_ON and the other two 
issues addressed?

I'm willing to send either one if Arnd is okay with that. I'd really like 
to resolve this before the merge window opens, since my PMU patch series 
is affected.

--
Geert Uytterhoeven July 23, 2018, 8:08 a.m. UTC | #11
Hi Finn,

On Sun, Jul 22, 2018 at 1:56 PM Finn Thain <fthain@telegraphics.com.au> wrote:
> On Wed, 18 Jul 2018, I wrote:

> > On Wed, 18 Jul 2018, Arnd Bergmann wrote:

> > > I'd suggest we do it like below to make it consistent with the rest

> > > again, using the 1904..2040 range of dates and no warning for invalid

> > > dates.

> > >

> > > If you agree, I'll send that as a proper patch.

> >

> > Geert may instead wish to fixup or revert the patch he has committed

> > already...

>

> Geert, how do you want to handle this?

>

> Do you want a fixup patch or a v3 patch with the WARN_ON and the other two

> issues addressed?


Please send a fixup patch, for the m68k/master branch, which is non-rebasing.
I'll fold it into the original commit on the m68k/for-next branch.

> I'm willing to send either one if Arnd is okay with that. I'd really like

> to resolve this before the merge window opens, since my PMU patch series

> is affected.


+1. If it's not resolved (a few days) before the merge window opens, I may have
to revert the patch instead.

Thanks!

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
diff mbox series

Patch

diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index c68054361615..0a2572a6bfe5 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -26,33 +26,39 @@ 
 
 #include <asm/machdep.h>
 
-/* Offset between Unix time (1970-based) and Mac time (1904-based) */
+/* Offset between Unix time (1970-based) and Mac time (1904-based). Cuda and PMU
+ * times wrap in 2040. If we need to handle later times, the read_time functions
+ * need to be changed to interpret wrapped times as post-2040. */
 
 #define RTC_OFFSET 2082844800
 
 static void (*rom_reset)(void);
 
 #ifdef CONFIG_ADB_CUDA
-static long cuda_read_time(void)
+static time64_t cuda_read_time(void)
 {
 	struct adb_request req;
-	long time;
+	time64_t time;
 
 	if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
 		return 0;
 	while (!req.complete)
 		cuda_poll();
 
-	time = (req.reply[3] << 24) | (req.reply[4] << 16) |
-	       (req.reply[5] << 8) | req.reply[6];
+	time = (u32)((req.reply[3] << 24) | (req.reply[4] << 16) |
+		     (req.reply[5] << 8) | req.reply[6]);
+
+	/* it's either after year 2040, or the RTC has gone backwards */
+	WARN_ON(time < RTC_OFFSET);
+
 	return time - RTC_OFFSET;
 }
 
-static void cuda_write_time(long data)
+static void cuda_write_time(time64_t time)
 {
 	struct adb_request req;
+	u32 data = lower_32_bits(time + RTC_OFFSET);
 
-	data += RTC_OFFSET;
 	if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
 			 (data >> 24) & 0xFF, (data >> 16) & 0xFF,
 			 (data >> 8) & 0xFF, data & 0xFF) < 0)
@@ -86,26 +92,30 @@  static void cuda_write_pram(int offset, __u8 data)
 #endif /* CONFIG_ADB_CUDA */
 
 #ifdef CONFIG_ADB_PMU68K
-static long pmu_read_time(void)
+static time64_t pmu_read_time(void)
 {
 	struct adb_request req;
-	long time;
+	time64_t time;
 
 	if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
 		return 0;
 	while (!req.complete)
 		pmu_poll();
 
-	time = (req.reply[1] << 24) | (req.reply[2] << 16) |
-	       (req.reply[3] << 8) | req.reply[4];
+	time = (u32)((req.reply[1] << 24) | (req.reply[2] << 16) |
+		     (req.reply[3] << 8) | req.reply[4]);
+
+	/* it's either after year 2040, or the RTC has gone backwards */
+	WARN_ON(time < RTC_OFFSET);
+
 	return time - RTC_OFFSET;
 }
 
-static void pmu_write_time(long data)
+static void pmu_write_time(time64_t time)
 {
 	struct adb_request req;
+	u32 data = lower_32_bits(time + RTC_OFFSET);
 
-	data += RTC_OFFSET;
 	if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
 			(data >> 24) & 0xFF, (data >> 16) & 0xFF,
 			(data >> 8) & 0xFF, data & 0xFF) < 0)
@@ -269,8 +279,12 @@  static long via_read_time(void)
 		via_pram_command(0x89, &result.cdata[1]);
 		via_pram_command(0x8D, &result.cdata[0]);
 
-		if (result.idata == last_result.idata)
+		if (result.idata == last_result.idata) {
+			if (result.idata < RTC_OFFSET)
+				result.idata += 0x100000000ull;
+
 			return result.idata - RTC_OFFSET;
+		}
 
 		if (++count > 10)
 			break;
@@ -291,11 +305,11 @@  static long via_read_time(void)
  * is basically any machine with Mac II-style ADB.
  */
 
-static void via_write_time(long time)
+static void via_write_time(time64_t time)
 {
 	union {
 		__u8 cdata[4];
-		long idata;
+		__u32 idata;
 	} data;
 	__u8 temp;
 
@@ -585,12 +599,15 @@  void mac_reset(void)
  * This function translates seconds since 1970 into a proper date.
  *
  * Algorithm cribbed from glibc2.1, __offtime().
+ *
+ * This is roughly same as rtc_time64_to_tm(), which we should probably
+ * use here, but it's only available when CONFIG_RTC_LIB is enabled.
  */
 #define SECS_PER_MINUTE (60)
 #define SECS_PER_HOUR  (SECS_PER_MINUTE * 60)
 #define SECS_PER_DAY   (SECS_PER_HOUR * 24)
 
-static void unmktime(unsigned long time, long offset,
+static void unmktime(time64_t time, long offset,
 		     int *yearp, int *monp, int *dayp,
 		     int *hourp, int *minp, int *secp)
 {
@@ -602,11 +619,10 @@  static void unmktime(unsigned long time, long offset,
 		/* Leap years.  */
 		{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
 	};
-	long int days, rem, y, wday, yday;
+	int days, rem, y, wday, yday;
 	const unsigned short int *ip;
 
-	days = time / SECS_PER_DAY;
-	rem = time % SECS_PER_DAY;
+	days = div_u64_rem(time, SECS_PER_DAY, &rem);
 	rem += offset;
 	while (rem < 0) {
 		rem += SECS_PER_DAY;
@@ -657,7 +673,7 @@  static void unmktime(unsigned long time, long offset,
 
 int mac_hwclk(int op, struct rtc_time *t)
 {
-	unsigned long now;
+	time64_t now;
 
 	if (!op) { /* read */
 		switch (macintosh_config->adb_type) {
@@ -693,8 +709,8 @@  int mac_hwclk(int op, struct rtc_time *t)
 		         __func__, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
 		         t->tm_hour, t->tm_min, t->tm_sec);
 
-		now = mktime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
-			     t->tm_hour, t->tm_min, t->tm_sec);
+		now = mktime64(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
+			       t->tm_hour, t->tm_min, t->tm_sec);
 
 		switch (macintosh_config->adb_type) {
 		case MAC_ADB_IOP: