diff mbox series

[SRU,F/raspi] rtc: class: support hctosys from modular RTC drivers

Message ID 20210503154545.152714-1-juergh@canonical.com
State New
Headers show
Series [SRU,F/raspi] rtc: class: support hctosys from modular RTC drivers | expand

Commit Message

Juerg Haefliger May 3, 2021, 3:45 p.m. UTC
From: Steve Muckle <smuckle@google.com>

BugLink: https://bugs.launchpad.net/bugs/1926911

Due to distribution constraints it may not be possible to statically
compile the required RTC driver into the kernel.

Expand RTC_HCTOSYS support to cover all RTC devices (statically compiled
or not) by checking at the end of RTC device registration whether the
time should be synced.

Signed-off-by: Steve Muckle <smuckle@google.com>
Link: https://lore.kernel.org/r/20191106194625.116692-1-smuckle@google.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
(cherry picked from commit f9b2a4d6a5f18e0aaf715206a056565c56889d9f)
Signed-off-by: Juerg Haefliger <juergh@canonical.com>
---
 drivers/rtc/Kconfig   |  3 --
 drivers/rtc/Makefile  |  1 -
 drivers/rtc/class.c   | 61 ++++++++++++++++++++++++++++++++++++++
 drivers/rtc/hctosys.c | 69 -------------------------------------------
 4 files changed, 61 insertions(+), 73 deletions(-)
 delete mode 100644 drivers/rtc/hctosys.c

Comments

Krzysztof Kozlowski May 4, 2021, 11:22 a.m. UTC | #1
On 03/05/2021 11:45, Juerg Haefliger wrote:
> From: Steve Muckle <smuckle@google.com>
> 
> BugLink: https://bugs.launchpad.net/bugs/1926911
> 
> Due to distribution constraints it may not be possible to statically
> compile the required RTC driver into the kernel.
> 
> Expand RTC_HCTOSYS support to cover all RTC devices (statically compiled
> or not) by checking at the end of RTC device registration whether the
> time should be synced.
> 
> Signed-off-by: Steve Muckle <smuckle@google.com>
> Link: https://lore.kernel.org/r/20191106194625.116692-1-smuckle@google.com
> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> (cherry picked from commit f9b2a4d6a5f18e0aaf715206a056565c56889d9f)
> Signed-off-by: Juerg Haefliger <juergh@canonical.com>
> ---
>  drivers/rtc/Kconfig   |  3 --
>  drivers/rtc/Makefile  |  1 -
>  drivers/rtc/class.c   | 61 ++++++++++++++++++++++++++++++++++++++
>  drivers/rtc/hctosys.c | 69 -------------------------------------------
>  4 files changed, 61 insertions(+), 73 deletions(-)
>  delete mode 100644 drivers/rtc/hctosys.c
> 

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>


Best regards,
Krzysztof
Colin Ian King May 4, 2021, 11:30 a.m. UTC | #2
On 03/05/2021 16:45, Juerg Haefliger wrote:
> From: Steve Muckle <smuckle@google.com>
> 
> BugLink: https://bugs.launchpad.net/bugs/1926911
> 
> Due to distribution constraints it may not be possible to statically
> compile the required RTC driver into the kernel.
> 
> Expand RTC_HCTOSYS support to cover all RTC devices (statically compiled
> or not) by checking at the end of RTC device registration whether the
> time should be synced.
> 
> Signed-off-by: Steve Muckle <smuckle@google.com>
> Link: https://lore.kernel.org/r/20191106194625.116692-1-smuckle@google.com
> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> (cherry picked from commit f9b2a4d6a5f18e0aaf715206a056565c56889d9f)
> Signed-off-by: Juerg Haefliger <juergh@canonical.com>
> ---
>  drivers/rtc/Kconfig   |  3 --
>  drivers/rtc/Makefile  |  1 -
>  drivers/rtc/class.c   | 61 ++++++++++++++++++++++++++++++++++++++
>  drivers/rtc/hctosys.c | 69 -------------------------------------------
>  4 files changed, 61 insertions(+), 73 deletions(-)
>  delete mode 100644 drivers/rtc/hctosys.c
> 
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 778cb0e63055..d9daa6ec45ff 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -41,9 +41,6 @@ config RTC_HCTOSYS_DEVICE
>  	  device should record time in UTC, since the kernel won't do
>  	  timezone correction.
>  
> -	  The driver for this RTC device must be loaded before late_initcall
> -	  functions run, so it must usually be statically linked.
> -
>  	  This clock should be battery-backed, so that it reads the correct
>  	  time when the system boots from a power-off state. Otherwise, your
>  	  system will need an external clock source (like an NTP server).
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index a20943eafaab..9918b0429383 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -6,7 +6,6 @@
>  ccflags-$(CONFIG_RTC_DEBUG)	:= -DDEBUG
>  
>  obj-$(CONFIG_RTC_LIB)		+= lib.o
> -obj-$(CONFIG_RTC_HCTOSYS)	+= hctosys.o
>  obj-$(CONFIG_RTC_SYSTOHC)	+= systohc.o
>  obj-$(CONFIG_RTC_CLASS)		+= rtc-core.o
>  obj-$(CONFIG_RTC_MC146818_LIB)	+= rtc-mc146818-lib.o
> diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
> index 9458e6d6686a..8793b2b8cf9d 100644
> --- a/drivers/rtc/class.c
> +++ b/drivers/rtc/class.c
> @@ -34,6 +34,62 @@ static void rtc_device_release(struct device *dev)
>  #ifdef CONFIG_RTC_HCTOSYS_DEVICE
>  /* Result of the last RTC to system clock attempt. */
>  int rtc_hctosys_ret = -ENODEV;
> +
> +/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
> + * whether it stores the most close value or the value with partial
> + * seconds truncated. However, it is important that we use it to store
> + * the truncated value. This is because otherwise it is necessary,
> + * in an rtc sync function, to read both xtime.tv_sec and
> + * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
> + * of >32bits is not possible. So storing the most close value would
> + * slow down the sync API. So here we have the truncated value and
> + * the best guess is to add 0.5s.
> + */
> +
> +static int rtc_hctosys(void)
> +{
> +	int err = -ENODEV;
> +	struct rtc_time tm;
> +	struct timespec64 tv64 = {
> +		.tv_nsec = NSEC_PER_SEC >> 1,
> +	};
> +	struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
> +
> +	if (!rtc) {
> +		pr_info("unable to open rtc device (%s)\n",
> +			CONFIG_RTC_HCTOSYS_DEVICE);
> +		goto err_open;
> +	}
> +
> +	err = rtc_read_time(rtc, &tm);
> +	if (err) {
> +		dev_err(rtc->dev.parent,
> +			"hctosys: unable to read the hardware clock\n");
> +		goto err_read;
> +	}
> +
> +	tv64.tv_sec = rtc_tm_to_time64(&tm);
> +
> +#if BITS_PER_LONG == 32
> +	if (tv64.tv_sec > INT_MAX) {
> +		err = -ERANGE;
> +		goto err_read;
> +	}
> +#endif
> +
> +	err = do_settimeofday64(&tv64);
> +
> +	dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n",
> +		 &tm, (long long)tv64.tv_sec);
> +
> +err_read:
> +	rtc_class_close(rtc);
> +
> +err_open:
> +	rtc_hctosys_ret = err;
> +
> +	return err;
> +}
>  #endif
>  
>  #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
> @@ -375,6 +431,11 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
>  	dev_info(rtc->dev.parent, "registered as %s\n",
>  		 dev_name(&rtc->dev));
>  
> +#ifdef CONFIG_RTC_HCTOSYS_DEVICE
> +	if (!strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE))
> +		rtc_hctosys();
> +#endif
> +
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(__rtc_register_device);
> diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
> deleted file mode 100644
> index a74d0d890600..000000000000
> --- a/drivers/rtc/hctosys.c
> +++ /dev/null
> @@ -1,69 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -/*
> - * RTC subsystem, initialize system time on startup
> - *
> - * Copyright (C) 2005 Tower Technologies
> - * Author: Alessandro Zummo <a.zummo@towertech.it>
> - */
> -
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/rtc.h>
> -
> -/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
> - * whether it stores the most close value or the value with partial
> - * seconds truncated. However, it is important that we use it to store
> - * the truncated value. This is because otherwise it is necessary,
> - * in an rtc sync function, to read both xtime.tv_sec and
> - * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
> - * of >32bits is not possible. So storing the most close value would
> - * slow down the sync API. So here we have the truncated value and
> - * the best guess is to add 0.5s.
> - */
> -
> -static int __init rtc_hctosys(void)
> -{
> -	int err = -ENODEV;
> -	struct rtc_time tm;
> -	struct timespec64 tv64 = {
> -		.tv_nsec = NSEC_PER_SEC >> 1,
> -	};
> -	struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
> -
> -	if (!rtc) {
> -		pr_info("unable to open rtc device (%s)\n",
> -			CONFIG_RTC_HCTOSYS_DEVICE);
> -		goto err_open;
> -	}
> -
> -	err = rtc_read_time(rtc, &tm);
> -	if (err) {
> -		dev_err(rtc->dev.parent,
> -			"hctosys: unable to read the hardware clock\n");
> -		goto err_read;
> -	}
> -
> -	tv64.tv_sec = rtc_tm_to_time64(&tm);
> -
> -#if BITS_PER_LONG == 32
> -	if (tv64.tv_sec > INT_MAX) {
> -		err = -ERANGE;
> -		goto err_read;
> -	}
> -#endif
> -
> -	err = do_settimeofday64(&tv64);
> -
> -	dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n",
> -		 &tm, (long long)tv64.tv_sec);
> -
> -err_read:
> -	rtc_class_close(rtc);
> -
> -err_open:
> -	rtc_hctosys_ret = err;
> -
> -	return err;
> -}
> -
> -late_initcall(rtc_hctosys);
> 
Yep, LGTM

Acked-by: Colin Ian King <colin.king@canonical.com>
Dimitri John Ledkov May 4, 2021, 5:22 p.m. UTC | #3
Hi,

This will introduce a regression in certain configurations as
mentioned on https://github.com/systemd/systemd/issues/17737

I had a tentative patch to kernel to only advance time in rtc_hctosys
only if it is newer than the one returned by ktime_get_real_ts64.

However that went nowhere.

If this is cherry picked, imho we must change config
CONFIG_RTC_HCTOSYS or at least set it to something sane because
currently on raspi it is set to CONFIG_RTC_HCTOSYS_DEVICE="rtc0" which
always points at the non-battery backed RTC from the SOC.

Does above make any sense?


On Mon, May 3, 2021 at 4:46 PM Juerg Haefliger
<juerg.haefliger@canonical.com> wrote:
>
> From: Steve Muckle <smuckle@google.com>
>
> BugLink: https://bugs.launchpad.net/bugs/1926911
>
> Due to distribution constraints it may not be possible to statically
> compile the required RTC driver into the kernel.
>
> Expand RTC_HCTOSYS support to cover all RTC devices (statically compiled
> or not) by checking at the end of RTC device registration whether the
> time should be synced.
>
> Signed-off-by: Steve Muckle <smuckle@google.com>
> Link: https://lore.kernel.org/r/20191106194625.116692-1-smuckle@google.com
> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> (cherry picked from commit f9b2a4d6a5f18e0aaf715206a056565c56889d9f)
> Signed-off-by: Juerg Haefliger <juergh@canonical.com>
> ---
>  drivers/rtc/Kconfig   |  3 --
>  drivers/rtc/Makefile  |  1 -
>  drivers/rtc/class.c   | 61 ++++++++++++++++++++++++++++++++++++++
>  drivers/rtc/hctosys.c | 69 -------------------------------------------
>  4 files changed, 61 insertions(+), 73 deletions(-)
>  delete mode 100644 drivers/rtc/hctosys.c
>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 778cb0e63055..d9daa6ec45ff 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -41,9 +41,6 @@ config RTC_HCTOSYS_DEVICE
>           device should record time in UTC, since the kernel won't do
>           timezone correction.
>
> -         The driver for this RTC device must be loaded before late_initcall
> -         functions run, so it must usually be statically linked.
> -
>           This clock should be battery-backed, so that it reads the correct
>           time when the system boots from a power-off state. Otherwise, your
>           system will need an external clock source (like an NTP server).
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index a20943eafaab..9918b0429383 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -6,7 +6,6 @@
>  ccflags-$(CONFIG_RTC_DEBUG)    := -DDEBUG
>
>  obj-$(CONFIG_RTC_LIB)          += lib.o
> -obj-$(CONFIG_RTC_HCTOSYS)      += hctosys.o
>  obj-$(CONFIG_RTC_SYSTOHC)      += systohc.o
>  obj-$(CONFIG_RTC_CLASS)                += rtc-core.o
>  obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o
> diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
> index 9458e6d6686a..8793b2b8cf9d 100644
> --- a/drivers/rtc/class.c
> +++ b/drivers/rtc/class.c
> @@ -34,6 +34,62 @@ static void rtc_device_release(struct device *dev)
>  #ifdef CONFIG_RTC_HCTOSYS_DEVICE
>  /* Result of the last RTC to system clock attempt. */
>  int rtc_hctosys_ret = -ENODEV;
> +
> +/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
> + * whether it stores the most close value or the value with partial
> + * seconds truncated. However, it is important that we use it to store
> + * the truncated value. This is because otherwise it is necessary,
> + * in an rtc sync function, to read both xtime.tv_sec and
> + * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
> + * of >32bits is not possible. So storing the most close value would
> + * slow down the sync API. So here we have the truncated value and
> + * the best guess is to add 0.5s.
> + */
> +
> +static int rtc_hctosys(void)
> +{
> +       int err = -ENODEV;
> +       struct rtc_time tm;
> +       struct timespec64 tv64 = {
> +               .tv_nsec = NSEC_PER_SEC >> 1,
> +       };
> +       struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
> +
> +       if (!rtc) {
> +               pr_info("unable to open rtc device (%s)\n",
> +                       CONFIG_RTC_HCTOSYS_DEVICE);
> +               goto err_open;
> +       }
> +
> +       err = rtc_read_time(rtc, &tm);
> +       if (err) {
> +               dev_err(rtc->dev.parent,
> +                       "hctosys: unable to read the hardware clock\n");
> +               goto err_read;
> +       }
> +
> +       tv64.tv_sec = rtc_tm_to_time64(&tm);
> +
> +#if BITS_PER_LONG == 32
> +       if (tv64.tv_sec > INT_MAX) {
> +               err = -ERANGE;
> +               goto err_read;
> +       }
> +#endif
> +
> +       err = do_settimeofday64(&tv64);
> +
> +       dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n",
> +                &tm, (long long)tv64.tv_sec);
> +
> +err_read:
> +       rtc_class_close(rtc);
> +
> +err_open:
> +       rtc_hctosys_ret = err;
> +
> +       return err;
> +}
>  #endif
>
>  #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
> @@ -375,6 +431,11 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
>         dev_info(rtc->dev.parent, "registered as %s\n",
>                  dev_name(&rtc->dev));
>
> +#ifdef CONFIG_RTC_HCTOSYS_DEVICE
> +       if (!strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE))
> +               rtc_hctosys();
> +#endif
> +
>         return 0;
>  }
>  EXPORT_SYMBOL_GPL(__rtc_register_device);
> diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
> deleted file mode 100644
> index a74d0d890600..000000000000
> --- a/drivers/rtc/hctosys.c
> +++ /dev/null
> @@ -1,69 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -/*
> - * RTC subsystem, initialize system time on startup
> - *
> - * Copyright (C) 2005 Tower Technologies
> - * Author: Alessandro Zummo <a.zummo@towertech.it>
> - */
> -
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/rtc.h>
> -
> -/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
> - * whether it stores the most close value or the value with partial
> - * seconds truncated. However, it is important that we use it to store
> - * the truncated value. This is because otherwise it is necessary,
> - * in an rtc sync function, to read both xtime.tv_sec and
> - * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
> - * of >32bits is not possible. So storing the most close value would
> - * slow down the sync API. So here we have the truncated value and
> - * the best guess is to add 0.5s.
> - */
> -
> -static int __init rtc_hctosys(void)
> -{
> -       int err = -ENODEV;
> -       struct rtc_time tm;
> -       struct timespec64 tv64 = {
> -               .tv_nsec = NSEC_PER_SEC >> 1,
> -       };
> -       struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
> -
> -       if (!rtc) {
> -               pr_info("unable to open rtc device (%s)\n",
> -                       CONFIG_RTC_HCTOSYS_DEVICE);
> -               goto err_open;
> -       }
> -
> -       err = rtc_read_time(rtc, &tm);
> -       if (err) {
> -               dev_err(rtc->dev.parent,
> -                       "hctosys: unable to read the hardware clock\n");
> -               goto err_read;
> -       }
> -
> -       tv64.tv_sec = rtc_tm_to_time64(&tm);
> -
> -#if BITS_PER_LONG == 32
> -       if (tv64.tv_sec > INT_MAX) {
> -               err = -ERANGE;
> -               goto err_read;
> -       }
> -#endif
> -
> -       err = do_settimeofday64(&tv64);
> -
> -       dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n",
> -                &tm, (long long)tv64.tv_sec);
> -
> -err_read:
> -       rtc_class_close(rtc);
> -
> -err_open:
> -       rtc_hctosys_ret = err;
> -
> -       return err;
> -}
> -
> -late_initcall(rtc_hctosys);
> --
> 2.27.0
>
>
> --
> kernel-team mailing list
> kernel-team@lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team
Dimitri John Ledkov May 4, 2021, 5:23 p.m. UTC | #4
See previous discussion about this attached as emails.

On Tue, May 4, 2021 at 6:22 PM Dimitri John Ledkov
<dimitri.ledkov@canonical.com> wrote:
>
> Hi,
>
> This will introduce a regression in certain configurations as
> mentioned on https://github.com/systemd/systemd/issues/17737
>
> I had a tentative patch to kernel to only advance time in rtc_hctosys
> only if it is newer than the one returned by ktime_get_real_ts64.
>
> However that went nowhere.
>
> If this is cherry picked, imho we must change config
> CONFIG_RTC_HCTOSYS or at least set it to something sane because
> currently on raspi it is set to CONFIG_RTC_HCTOSYS_DEVICE="rtc0" which
> always points at the non-battery backed RTC from the SOC.
>
> Does above make any sense?
>
>
> On Mon, May 3, 2021 at 4:46 PM Juerg Haefliger
> <juerg.haefliger@canonical.com> wrote:
> >
> > From: Steve Muckle <smuckle@google.com>
> >
> > BugLink: https://bugs.launchpad.net/bugs/1926911
> >
> > Due to distribution constraints it may not be possible to statically
> > compile the required RTC driver into the kernel.
> >
> > Expand RTC_HCTOSYS support to cover all RTC devices (statically compiled
> > or not) by checking at the end of RTC device registration whether the
> > time should be synced.
> >
> > Signed-off-by: Steve Muckle <smuckle@google.com>
> > Link: https://lore.kernel.org/r/20191106194625.116692-1-smuckle@google.com
> > Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> > (cherry picked from commit f9b2a4d6a5f18e0aaf715206a056565c56889d9f)
> > Signed-off-by: Juerg Haefliger <juergh@canonical.com>
> > ---
> >  drivers/rtc/Kconfig   |  3 --
> >  drivers/rtc/Makefile  |  1 -
> >  drivers/rtc/class.c   | 61 ++++++++++++++++++++++++++++++++++++++
> >  drivers/rtc/hctosys.c | 69 -------------------------------------------
> >  4 files changed, 61 insertions(+), 73 deletions(-)
> >  delete mode 100644 drivers/rtc/hctosys.c
> >
> > diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> > index 778cb0e63055..d9daa6ec45ff 100644
> > --- a/drivers/rtc/Kconfig
> > +++ b/drivers/rtc/Kconfig
> > @@ -41,9 +41,6 @@ config RTC_HCTOSYS_DEVICE
> >           device should record time in UTC, since the kernel won't do
> >           timezone correction.
> >
> > -         The driver for this RTC device must be loaded before late_initcall
> > -         functions run, so it must usually be statically linked.
> > -
> >           This clock should be battery-backed, so that it reads the correct
> >           time when the system boots from a power-off state. Otherwise, your
> >           system will need an external clock source (like an NTP server).
> > diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> > index a20943eafaab..9918b0429383 100644
> > --- a/drivers/rtc/Makefile
> > +++ b/drivers/rtc/Makefile
> > @@ -6,7 +6,6 @@
> >  ccflags-$(CONFIG_RTC_DEBUG)    := -DDEBUG
> >
> >  obj-$(CONFIG_RTC_LIB)          += lib.o
> > -obj-$(CONFIG_RTC_HCTOSYS)      += hctosys.o
> >  obj-$(CONFIG_RTC_SYSTOHC)      += systohc.o
> >  obj-$(CONFIG_RTC_CLASS)                += rtc-core.o
> >  obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o
> > diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
> > index 9458e6d6686a..8793b2b8cf9d 100644
> > --- a/drivers/rtc/class.c
> > +++ b/drivers/rtc/class.c
> > @@ -34,6 +34,62 @@ static void rtc_device_release(struct device *dev)
> >  #ifdef CONFIG_RTC_HCTOSYS_DEVICE
> >  /* Result of the last RTC to system clock attempt. */
> >  int rtc_hctosys_ret = -ENODEV;
> > +
> > +/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
> > + * whether it stores the most close value or the value with partial
> > + * seconds truncated. However, it is important that we use it to store
> > + * the truncated value. This is because otherwise it is necessary,
> > + * in an rtc sync function, to read both xtime.tv_sec and
> > + * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
> > + * of >32bits is not possible. So storing the most close value would
> > + * slow down the sync API. So here we have the truncated value and
> > + * the best guess is to add 0.5s.
> > + */
> > +
> > +static int rtc_hctosys(void)
> > +{
> > +       int err = -ENODEV;
> > +       struct rtc_time tm;
> > +       struct timespec64 tv64 = {
> > +               .tv_nsec = NSEC_PER_SEC >> 1,
> > +       };
> > +       struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
> > +
> > +       if (!rtc) {
> > +               pr_info("unable to open rtc device (%s)\n",
> > +                       CONFIG_RTC_HCTOSYS_DEVICE);
> > +               goto err_open;
> > +       }
> > +
> > +       err = rtc_read_time(rtc, &tm);
> > +       if (err) {
> > +               dev_err(rtc->dev.parent,
> > +                       "hctosys: unable to read the hardware clock\n");
> > +               goto err_read;
> > +       }
> > +
> > +       tv64.tv_sec = rtc_tm_to_time64(&tm);
> > +
> > +#if BITS_PER_LONG == 32
> > +       if (tv64.tv_sec > INT_MAX) {
> > +               err = -ERANGE;
> > +               goto err_read;
> > +       }
> > +#endif
> > +
> > +       err = do_settimeofday64(&tv64);
> > +
> > +       dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n",
> > +                &tm, (long long)tv64.tv_sec);
> > +
> > +err_read:
> > +       rtc_class_close(rtc);
> > +
> > +err_open:
> > +       rtc_hctosys_ret = err;
> > +
> > +       return err;
> > +}
> >  #endif
> >
> >  #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
> > @@ -375,6 +431,11 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
> >         dev_info(rtc->dev.parent, "registered as %s\n",
> >                  dev_name(&rtc->dev));
> >
> > +#ifdef CONFIG_RTC_HCTOSYS_DEVICE
> > +       if (!strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE))
> > +               rtc_hctosys();
> > +#endif
> > +
> >         return 0;
> >  }
> >  EXPORT_SYMBOL_GPL(__rtc_register_device);
> > diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
> > deleted file mode 100644
> > index a74d0d890600..000000000000
> > --- a/drivers/rtc/hctosys.c
> > +++ /dev/null
> > @@ -1,69 +0,0 @@
> > -// SPDX-License-Identifier: GPL-2.0
> > -/*
> > - * RTC subsystem, initialize system time on startup
> > - *
> > - * Copyright (C) 2005 Tower Technologies
> > - * Author: Alessandro Zummo <a.zummo@towertech.it>
> > - */
> > -
> > -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > -
> > -#include <linux/rtc.h>
> > -
> > -/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
> > - * whether it stores the most close value or the value with partial
> > - * seconds truncated. However, it is important that we use it to store
> > - * the truncated value. This is because otherwise it is necessary,
> > - * in an rtc sync function, to read both xtime.tv_sec and
> > - * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
> > - * of >32bits is not possible. So storing the most close value would
> > - * slow down the sync API. So here we have the truncated value and
> > - * the best guess is to add 0.5s.
> > - */
> > -
> > -static int __init rtc_hctosys(void)
> > -{
> > -       int err = -ENODEV;
> > -       struct rtc_time tm;
> > -       struct timespec64 tv64 = {
> > -               .tv_nsec = NSEC_PER_SEC >> 1,
> > -       };
> > -       struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
> > -
> > -       if (!rtc) {
> > -               pr_info("unable to open rtc device (%s)\n",
> > -                       CONFIG_RTC_HCTOSYS_DEVICE);
> > -               goto err_open;
> > -       }
> > -
> > -       err = rtc_read_time(rtc, &tm);
> > -       if (err) {
> > -               dev_err(rtc->dev.parent,
> > -                       "hctosys: unable to read the hardware clock\n");
> > -               goto err_read;
> > -       }
> > -
> > -       tv64.tv_sec = rtc_tm_to_time64(&tm);
> > -
> > -#if BITS_PER_LONG == 32
> > -       if (tv64.tv_sec > INT_MAX) {
> > -               err = -ERANGE;
> > -               goto err_read;
> > -       }
> > -#endif
> > -
> > -       err = do_settimeofday64(&tv64);
> > -
> > -       dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n",
> > -                &tm, (long long)tv64.tv_sec);
> > -
> > -err_read:
> > -       rtc_class_close(rtc);
> > -
> > -err_open:
> > -       rtc_hctosys_ret = err;
> > -
> > -       return err;
> > -}
> > -
> > -late_initcall(rtc_hctosys);
> > --
> > 2.27.0
> >
> >
> > --
> > kernel-team mailing list
> > kernel-team@lists.ubuntu.com
> > https://lists.ubuntu.com/mailman/listinfo/kernel-team
>
>
>
> --
> Regards,
>
> Dimitri.
Krzysztof Kozlowski May 4, 2021, 5:39 p.m. UTC | #5
On 04/05/2021 13:22, Dimitri John Ledkov wrote:
> Hi,
> 
> This will introduce a regression in certain configurations as
> mentioned on https://github.com/systemd/systemd/issues/17737
> 
> I had a tentative patch to kernel to only advance time in rtc_hctosys
> only if it is newer than the one returned by ktime_get_real_ts64.

That's the mainline commit, so change for it (e.g. do not set the system
clock for modules) should go via upstream.

> However that went nowhere.
> 
> If this is cherry picked, imho we must change config
> CONFIG_RTC_HCTOSYS or at least set it to something sane because
> currently on raspi it is set to CONFIG_RTC_HCTOSYS_DEVICE="rtc0" which
> always points at the non-battery backed RTC from the SOC.

RPi does not have a RTC, so whoever adds it via overlay, probably
chooses one with a battery. Otherwise there is no much point of having
RTC...

Best regards,
Krzysztof
Dimitri John Ledkov May 4, 2021, 5:42 p.m. UTC | #6
On Tue, May 4, 2021 at 6:39 PM Krzysztof Kozlowski
<krzysztof.kozlowski@canonical.com> wrote:
>
> On 04/05/2021 13:22, Dimitri John Ledkov wrote:
> > Hi,
> >
> > This will introduce a regression in certain configurations as
> > mentioned on https://github.com/systemd/systemd/issues/17737
> >
> > I had a tentative patch to kernel to only advance time in rtc_hctosys
> > only if it is newer than the one returned by ktime_get_real_ts64.
>
> That's the mainline commit, so change for it (e.g. do not set the system
> clock for modules) should go via upstream.
>
> > However that went nowhere.
> >
> > If this is cherry picked, imho we must change config
> > CONFIG_RTC_HCTOSYS or at least set it to something sane because
> > currently on raspi it is set to CONFIG_RTC_HCTOSYS_DEVICE="rtc0" which
> > always points at the non-battery backed RTC from the SOC.
>
> RPi does not have a RTC, so whoever adds it via overlay, probably
> chooses one with a battery. Otherwise there is no much point of having
> RTC...

That. I just don't know which RTC are available as rpi-hats and which
dtb overlay they use and which rtc name they end up with.

If the properly working & battery backed RTC is added via overlay dtb
and it ends up having rtc0 name, everything is fine. I just don't know
if the overlays remove all other rtc nodes and like take over the rtc0
name.

@juerg do rpi RTCs with batteries end up having rtc0 kernel name? or
do they end up with something else? Also we must include them into the
initrd as modules for UC20 cause otherwise it would be odd if the
clock jumps after pivot to root & after NTP got network time.
Krzysztof Kozlowski May 4, 2021, 5:46 p.m. UTC | #7
On 04/05/2021 13:42, Dimitri John Ledkov wrote:
>>>
>>> If this is cherry picked, imho we must change config
>>> CONFIG_RTC_HCTOSYS or at least set it to something sane because
>>> currently on raspi it is set to CONFIG_RTC_HCTOSYS_DEVICE="rtc0" which
>>> always points at the non-battery backed RTC from the SOC.
>>
>> RPi does not have a RTC, so whoever adds it via overlay, probably
>> chooses one with a battery. Otherwise there is no much point of having
>> RTC...
> 
> That. I just don't know which RTC are available as rpi-hats and which
> dtb overlay they use and which rtc name they end up with.
> 
> If the properly working & battery backed RTC is added via overlay dtb
> and it ends up having rtc0 name, everything is fine. I just don't know
> if the overlays remove all other rtc nodes and like take over the rtc0
> name.

The first RTC registered will always have rtc0. Regardless of its
properties (e.g. with or without battery).

Best regards,
Krzysztof
Juerg Haefliger May 5, 2021, 7:10 a.m. UTC | #8
On Tue, 4 May 2021 18:42:41 +0100
Dimitri John Ledkov <dimitri.ledkov@canonical.com> wrote:

> On Tue, May 4, 2021 at 6:39 PM Krzysztof Kozlowski
> <krzysztof.kozlowski@canonical.com> wrote:
> >
> > On 04/05/2021 13:22, Dimitri John Ledkov wrote:  
> > > Hi,
> > >
> > > This will introduce a regression in certain configurations as
> > > mentioned on https://github.com/systemd/systemd/issues/17737
> > >
> > > I had a tentative patch to kernel to only advance time in rtc_hctosys
> > > only if it is newer than the one returned by ktime_get_real_ts64.  
> >
> > That's the mainline commit, so change for it (e.g. do not set the system
> > clock for modules) should go via upstream.
> >  
> > > However that went nowhere.
> > >
> > > If this is cherry picked, imho we must change config
> > > CONFIG_RTC_HCTOSYS or at least set it to something sane because
> > > currently on raspi it is set to CONFIG_RTC_HCTOSYS_DEVICE="rtc0" which
> > > always points at the non-battery backed RTC from the SOC.  
> >
> > RPi does not have a RTC, so whoever adds it via overlay, probably
> > chooses one with a battery. Otherwise there is no much point of having
> > RTC...  
> 
> That. I just don't know which RTC are available as rpi-hats and which
> dtb overlay they use and which rtc name they end up with.

The first to load will get rtc0 and that's what the kernel will use ('rtc0' is
set as a CONFIG option).


> If the properly working & battery backed RTC is added via overlay dtb
> and it ends up having rtc0 name, everything is fine. I just don't know
> if the overlays remove all other rtc nodes and like take over the rtc0
> name.

You can have multiple RTCs. If someone chooses to do that (why?) then whichever
is probed first ends up being rtc0. I don't think we need to handle the case of
multiple RTCs and try to determine which one to use.


> @juerg do rpi RTCs with batteries end up having rtc0 kernel name?

The first to load. I don't believe the driver knows if an RTC is battery backed
or not.


> or
> do they end up with something else? Also we must include them into the
> initrd as modules for UC20 cause otherwise it would be odd if the
> clock jumps after pivot to root & after NTP got network time.

Yes. But the same is true for server, isn't it? Adding the module is a separate
step and not under the kernels control. The question is if we should/need to
include all RTCs currently supported by the Pi or just add them as needed.

....Juerg
Tim Gardner May 7, 2021, 7:29 p.m. UTC | #9
Applied to focal:raspi/master-next. Thanks.

 From the ensuing discussion, I gather that there are no more RTC config 
changes required ?

-rtg

On 5/3/21 9:45 AM, Juerg Haefliger wrote:
> From: Steve Muckle <smuckle@google.com>
> 
> BugLink: https://bugs.launchpad.net/bugs/1926911
> 
> Due to distribution constraints it may not be possible to statically
> compile the required RTC driver into the kernel.
> 
> Expand RTC_HCTOSYS support to cover all RTC devices (statically compiled
> or not) by checking at the end of RTC device registration whether the
> time should be synced.
> 
> Signed-off-by: Steve Muckle <smuckle@google.com>
> Link: https://lore.kernel.org/r/20191106194625.116692-1-smuckle@google.com
> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> (cherry picked from commit f9b2a4d6a5f18e0aaf715206a056565c56889d9f)
> Signed-off-by: Juerg Haefliger <juergh@canonical.com>
> ---
>   drivers/rtc/Kconfig   |  3 --
>   drivers/rtc/Makefile  |  1 -
>   drivers/rtc/class.c   | 61 ++++++++++++++++++++++++++++++++++++++
>   drivers/rtc/hctosys.c | 69 -------------------------------------------
>   4 files changed, 61 insertions(+), 73 deletions(-)
>   delete mode 100644 drivers/rtc/hctosys.c
> 
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 778cb0e63055..d9daa6ec45ff 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -41,9 +41,6 @@ config RTC_HCTOSYS_DEVICE
>   	  device should record time in UTC, since the kernel won't do
>   	  timezone correction.
>   
> -	  The driver for this RTC device must be loaded before late_initcall
> -	  functions run, so it must usually be statically linked.
> -
>   	  This clock should be battery-backed, so that it reads the correct
>   	  time when the system boots from a power-off state. Otherwise, your
>   	  system will need an external clock source (like an NTP server).
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index a20943eafaab..9918b0429383 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -6,7 +6,6 @@
>   ccflags-$(CONFIG_RTC_DEBUG)	:= -DDEBUG
>   
>   obj-$(CONFIG_RTC_LIB)		+= lib.o
> -obj-$(CONFIG_RTC_HCTOSYS)	+= hctosys.o
>   obj-$(CONFIG_RTC_SYSTOHC)	+= systohc.o
>   obj-$(CONFIG_RTC_CLASS)		+= rtc-core.o
>   obj-$(CONFIG_RTC_MC146818_LIB)	+= rtc-mc146818-lib.o
> diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
> index 9458e6d6686a..8793b2b8cf9d 100644
> --- a/drivers/rtc/class.c
> +++ b/drivers/rtc/class.c
> @@ -34,6 +34,62 @@ static void rtc_device_release(struct device *dev)
>   #ifdef CONFIG_RTC_HCTOSYS_DEVICE
>   /* Result of the last RTC to system clock attempt. */
>   int rtc_hctosys_ret = -ENODEV;
> +
> +/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
> + * whether it stores the most close value or the value with partial
> + * seconds truncated. However, it is important that we use it to store
> + * the truncated value. This is because otherwise it is necessary,
> + * in an rtc sync function, to read both xtime.tv_sec and
> + * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
> + * of >32bits is not possible. So storing the most close value would
> + * slow down the sync API. So here we have the truncated value and
> + * the best guess is to add 0.5s.
> + */
> +
> +static int rtc_hctosys(void)
> +{
> +	int err = -ENODEV;
> +	struct rtc_time tm;
> +	struct timespec64 tv64 = {
> +		.tv_nsec = NSEC_PER_SEC >> 1,
> +	};
> +	struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
> +
> +	if (!rtc) {
> +		pr_info("unable to open rtc device (%s)\n",
> +			CONFIG_RTC_HCTOSYS_DEVICE);
> +		goto err_open;
> +	}
> +
> +	err = rtc_read_time(rtc, &tm);
> +	if (err) {
> +		dev_err(rtc->dev.parent,
> +			"hctosys: unable to read the hardware clock\n");
> +		goto err_read;
> +	}
> +
> +	tv64.tv_sec = rtc_tm_to_time64(&tm);
> +
> +#if BITS_PER_LONG == 32
> +	if (tv64.tv_sec > INT_MAX) {
> +		err = -ERANGE;
> +		goto err_read;
> +	}
> +#endif
> +
> +	err = do_settimeofday64(&tv64);
> +
> +	dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n",
> +		 &tm, (long long)tv64.tv_sec);
> +
> +err_read:
> +	rtc_class_close(rtc);
> +
> +err_open:
> +	rtc_hctosys_ret = err;
> +
> +	return err;
> +}
>   #endif
>   
>   #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
> @@ -375,6 +431,11 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
>   	dev_info(rtc->dev.parent, "registered as %s\n",
>   		 dev_name(&rtc->dev));
>   
> +#ifdef CONFIG_RTC_HCTOSYS_DEVICE
> +	if (!strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE))
> +		rtc_hctosys();
> +#endif
> +
>   	return 0;
>   }
>   EXPORT_SYMBOL_GPL(__rtc_register_device);
> diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
> deleted file mode 100644
> index a74d0d890600..000000000000
> --- a/drivers/rtc/hctosys.c
> +++ /dev/null
> @@ -1,69 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -/*
> - * RTC subsystem, initialize system time on startup
> - *
> - * Copyright (C) 2005 Tower Technologies
> - * Author: Alessandro Zummo <a.zummo@towertech.it>
> - */
> -
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/rtc.h>
> -
> -/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
> - * whether it stores the most close value or the value with partial
> - * seconds truncated. However, it is important that we use it to store
> - * the truncated value. This is because otherwise it is necessary,
> - * in an rtc sync function, to read both xtime.tv_sec and
> - * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
> - * of >32bits is not possible. So storing the most close value would
> - * slow down the sync API. So here we have the truncated value and
> - * the best guess is to add 0.5s.
> - */
> -
> -static int __init rtc_hctosys(void)
> -{
> -	int err = -ENODEV;
> -	struct rtc_time tm;
> -	struct timespec64 tv64 = {
> -		.tv_nsec = NSEC_PER_SEC >> 1,
> -	};
> -	struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
> -
> -	if (!rtc) {
> -		pr_info("unable to open rtc device (%s)\n",
> -			CONFIG_RTC_HCTOSYS_DEVICE);
> -		goto err_open;
> -	}
> -
> -	err = rtc_read_time(rtc, &tm);
> -	if (err) {
> -		dev_err(rtc->dev.parent,
> -			"hctosys: unable to read the hardware clock\n");
> -		goto err_read;
> -	}
> -
> -	tv64.tv_sec = rtc_tm_to_time64(&tm);
> -
> -#if BITS_PER_LONG == 32
> -	if (tv64.tv_sec > INT_MAX) {
> -		err = -ERANGE;
> -		goto err_read;
> -	}
> -#endif
> -
> -	err = do_settimeofday64(&tv64);
> -
> -	dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n",
> -		 &tm, (long long)tv64.tv_sec);
> -
> -err_read:
> -	rtc_class_close(rtc);
> -
> -err_open:
> -	rtc_hctosys_ret = err;
> -
> -	return err;
> -}
> -
> -late_initcall(rtc_hctosys);
>
diff mbox series

Patch

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 778cb0e63055..d9daa6ec45ff 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -41,9 +41,6 @@  config RTC_HCTOSYS_DEVICE
 	  device should record time in UTC, since the kernel won't do
 	  timezone correction.
 
-	  The driver for this RTC device must be loaded before late_initcall
-	  functions run, so it must usually be statically linked.
-
 	  This clock should be battery-backed, so that it reads the correct
 	  time when the system boots from a power-off state. Otherwise, your
 	  system will need an external clock source (like an NTP server).
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index a20943eafaab..9918b0429383 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -6,7 +6,6 @@ 
 ccflags-$(CONFIG_RTC_DEBUG)	:= -DDEBUG
 
 obj-$(CONFIG_RTC_LIB)		+= lib.o
-obj-$(CONFIG_RTC_HCTOSYS)	+= hctosys.o
 obj-$(CONFIG_RTC_SYSTOHC)	+= systohc.o
 obj-$(CONFIG_RTC_CLASS)		+= rtc-core.o
 obj-$(CONFIG_RTC_MC146818_LIB)	+= rtc-mc146818-lib.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 9458e6d6686a..8793b2b8cf9d 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -34,6 +34,62 @@  static void rtc_device_release(struct device *dev)
 #ifdef CONFIG_RTC_HCTOSYS_DEVICE
 /* Result of the last RTC to system clock attempt. */
 int rtc_hctosys_ret = -ENODEV;
+
+/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
+ * whether it stores the most close value or the value with partial
+ * seconds truncated. However, it is important that we use it to store
+ * the truncated value. This is because otherwise it is necessary,
+ * in an rtc sync function, to read both xtime.tv_sec and
+ * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
+ * of >32bits is not possible. So storing the most close value would
+ * slow down the sync API. So here we have the truncated value and
+ * the best guess is to add 0.5s.
+ */
+
+static int rtc_hctosys(void)
+{
+	int err = -ENODEV;
+	struct rtc_time tm;
+	struct timespec64 tv64 = {
+		.tv_nsec = NSEC_PER_SEC >> 1,
+	};
+	struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+
+	if (!rtc) {
+		pr_info("unable to open rtc device (%s)\n",
+			CONFIG_RTC_HCTOSYS_DEVICE);
+		goto err_open;
+	}
+
+	err = rtc_read_time(rtc, &tm);
+	if (err) {
+		dev_err(rtc->dev.parent,
+			"hctosys: unable to read the hardware clock\n");
+		goto err_read;
+	}
+
+	tv64.tv_sec = rtc_tm_to_time64(&tm);
+
+#if BITS_PER_LONG == 32
+	if (tv64.tv_sec > INT_MAX) {
+		err = -ERANGE;
+		goto err_read;
+	}
+#endif
+
+	err = do_settimeofday64(&tv64);
+
+	dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n",
+		 &tm, (long long)tv64.tv_sec);
+
+err_read:
+	rtc_class_close(rtc);
+
+err_open:
+	rtc_hctosys_ret = err;
+
+	return err;
+}
 #endif
 
 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
@@ -375,6 +431,11 @@  int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
 	dev_info(rtc->dev.parent, "registered as %s\n",
 		 dev_name(&rtc->dev));
 
+#ifdef CONFIG_RTC_HCTOSYS_DEVICE
+	if (!strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE))
+		rtc_hctosys();
+#endif
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(__rtc_register_device);
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
deleted file mode 100644
index a74d0d890600..000000000000
--- a/drivers/rtc/hctosys.c
+++ /dev/null
@@ -1,69 +0,0 @@ 
-// SPDX-License-Identifier: GPL-2.0
-/*
- * RTC subsystem, initialize system time on startup
- *
- * Copyright (C) 2005 Tower Technologies
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/rtc.h>
-
-/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
- * whether it stores the most close value or the value with partial
- * seconds truncated. However, it is important that we use it to store
- * the truncated value. This is because otherwise it is necessary,
- * in an rtc sync function, to read both xtime.tv_sec and
- * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
- * of >32bits is not possible. So storing the most close value would
- * slow down the sync API. So here we have the truncated value and
- * the best guess is to add 0.5s.
- */
-
-static int __init rtc_hctosys(void)
-{
-	int err = -ENODEV;
-	struct rtc_time tm;
-	struct timespec64 tv64 = {
-		.tv_nsec = NSEC_PER_SEC >> 1,
-	};
-	struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
-
-	if (!rtc) {
-		pr_info("unable to open rtc device (%s)\n",
-			CONFIG_RTC_HCTOSYS_DEVICE);
-		goto err_open;
-	}
-
-	err = rtc_read_time(rtc, &tm);
-	if (err) {
-		dev_err(rtc->dev.parent,
-			"hctosys: unable to read the hardware clock\n");
-		goto err_read;
-	}
-
-	tv64.tv_sec = rtc_tm_to_time64(&tm);
-
-#if BITS_PER_LONG == 32
-	if (tv64.tv_sec > INT_MAX) {
-		err = -ERANGE;
-		goto err_read;
-	}
-#endif
-
-	err = do_settimeofday64(&tv64);
-
-	dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n",
-		 &tm, (long long)tv64.tv_sec);
-
-err_read:
-	rtc_class_close(rtc);
-
-err_open:
-	rtc_hctosys_ret = err;
-
-	return err;
-}
-
-late_initcall(rtc_hctosys);