Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1634884 > unrolled thread

[PATCH v2] Added "Preserve Boot Time Support"

Started byBogdan Mirea <Bogdan-Stefan_mirea@mentor.com>
First post2017-05-03 13:10 +0200
Last post2017-05-04 13:00 +0200
Articles 3 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v2] Added "Preserve Boot Time Support" Bogdan Mirea <Bogdan-Stefan_mirea@mentor.com> - 2017-05-03 13:10 +0200
    Re: [PATCH v2] Added "Preserve Boot Time Support" Oleksij Rempel <ore@pengutronix.de> - 2017-05-04 11:30 +0200
      RE: [PATCH v2] Added "Preserve Boot Time Support" "Mirea, Bogdan-Stefan" <Bogdan-Stefan_Mirea@mentor.com> - 2017-05-04 13:00 +0200

#1634884 — [PATCH v2] Added "Preserve Boot Time Support"

FromBogdan Mirea <Bogdan-Stefan_mirea@mentor.com>
Date2017-05-03 13:10 +0200
Subject[PATCH v2] Added "Preserve Boot Time Support"
Message-ID<tD0kp-4uV-13@gated-at.bofh.it>
This option enables Boot Time Preservation between Bootloader and
Linux Kernel. It is based on the idea that the Bootloader (or any
other early firmware) will start the HW Timer and Linux Kernel will
count the time starting with the cycles elapsed since timer start.

The sched_clock part is preserving boottime for kmsg which should be in
sync with system uptime. The system uptime part is driver specific and I
updated the arm_arch_timer with an arch_timer_setsystime() function
which will call do_settimeofday64() with the values read from arch timer
counter.

This way both kmsg and uptime will be in sync, otherwise incosistencies
will appear between the two.

Signed-off-by: Bogdan Mirea <Bogdan-Stefan_mirea@mentor.com>
---
 drivers/clocksource/arm_arch_timer.c | 26 ++++++++++++++++++++++++++
 kernel/time/Kconfig                  |  8 ++++++++
 kernel/time/sched_clock.c            |  6 ++++++
 3 files changed, 40 insertions(+)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 5152b38..7f9bf2a 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -475,6 +475,28 @@ struct timecounter *arch_timer_get_timecounter(void)
 	return &timecounter;
 }
 
+#ifdef CONFIG_BOOT_TIME_PRESERVE
+/*
+ * Set the real system time(including the time spent in bootloader)
+ * based on the timer counter.
+ */
+void arch_timer_setsystime(void)
+{
+	static struct timespec64 boot_ts;
+	static cycles_t cycles;
+	unsigned long long nsecs;
+
+	cycles = arch_timer_read_counter() ? arch_timer_read_counter() : 0;
+
+	nsecs = clocksource_cyc2ns(cycles, clocksource_counter.mult,
+				   clocksource_counter.shift);
+	timespec64_add_ns(&boot_ts, nsecs);
+
+	if (do_settimeofday64(&boot_ts))
+		pr_warn("arch_timer: unable to set systime\n");
+}
+#endif /* CONFIG_BOOT_TIME_PRESERVE */
+
 static void __init arch_counter_register(unsigned type)
 {
 	u64 start_count;
@@ -504,6 +526,10 @@ static void __init arch_counter_register(unsigned type)
 
 	/* 56 bits minimum, so we assume worst case rollover */
 	sched_clock_register(arch_timer_read_counter, 56, arch_timer_rate);
+#ifdef CONFIG_BOOT_TIME_PRESERVE
+	/* Set systime */
+	arch_timer_setsystime();
+#endif /* CONFIG_BOOT_TIME_PRESERVE */
 }
 
 static void arch_timer_stop(struct clock_event_device *clk)
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index 4008d9f..7d70232 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -193,5 +193,13 @@ config HIGH_RES_TIMERS
 	  hardware is not capable then this option only increases
 	  the size of the kernel image.
 
+config BOOT_TIME_PRESERVE
+	bool "Preserve Boot Time Support"
+	help
+	  This option enables Boot Time Preservation between Bootloader and
+	  Linux Kernel. It is based on the idea that the Bootloader (or any
+	  other early firmware) will start the HW Timer and Linux Kernel will
+	  count the time starting with the cycles elapsed since timer start.
+
 endmenu
 endif
diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c
index a26036d..1d6e35a 100644
--- a/kernel/time/sched_clock.c
+++ b/kernel/time/sched_clock.c
@@ -193,7 +193,13 @@ sched_clock_register(u64 (*read)(void), int bits, unsigned long rate)
 	/* Update epoch for new counter and update 'epoch_ns' from old counter*/
 	new_epoch = read();
 	cyc = cd.actual_read_sched_clock();
+
+#ifdef CONFIG_BOOT_TIME_PRESERVE
+	ns = rd.epoch_ns + cyc_to_ns((new_epoch - rd.epoch_cyc) & new_mask, new_mult, new_shift);
+#else
 	ns = rd.epoch_ns + cyc_to_ns((cyc - rd.epoch_cyc) & rd.sched_clock_mask, rd.mult, rd.shift);
+#endif /* CONFIG_BOOT_TIME_PRESERVE */
+
 	cd.actual_read_sched_clock = read;
 
 	rd.read_sched_clock	= read;
-- 
1.9.1

[toc] | [next] | [standalone]


#1635567

FromOleksij Rempel <ore@pengutronix.de>
Date2017-05-04 11:30 +0200
Message-ID<tDlfb-1wD-13@gated-at.bofh.it>
In reply to#1634884
Hi Bogdan,

are there any example what and how bootloader should do to provide 
correct values?

On 05/03/2017 12:59 PM, Bogdan Mirea wrote:
> This option enables Boot Time Preservation between Bootloader and
> Linux Kernel. It is based on the idea that the Bootloader (or any
> other early firmware) will start the HW Timer and Linux Kernel will
> count the time starting with the cycles elapsed since timer start.
>
> The sched_clock part is preserving boottime for kmsg which should be in
> sync with system uptime. The system uptime part is driver specific and I
> updated the arm_arch_timer with an arch_timer_setsystime() function
> which will call do_settimeofday64() with the values read from arch timer
> counter.
>
> This way both kmsg and uptime will be in sync, otherwise incosistencies
> will appear between the two.
>
> Signed-off-by: Bogdan Mirea <Bogdan-Stefan_mirea@mentor.com>
> ---
>  drivers/clocksource/arm_arch_timer.c | 26 ++++++++++++++++++++++++++
>  kernel/time/Kconfig                  |  8 ++++++++
>  kernel/time/sched_clock.c            |  6 ++++++
>  3 files changed, 40 insertions(+)
>
> diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
> index 5152b38..7f9bf2a 100644
> --- a/drivers/clocksource/arm_arch_timer.c
> +++ b/drivers/clocksource/arm_arch_timer.c
> @@ -475,6 +475,28 @@ struct timecounter *arch_timer_get_timecounter(void)
>  	return &timecounter;
>  }
>
> +#ifdef CONFIG_BOOT_TIME_PRESERVE
> +/*
> + * Set the real system time(including the time spent in bootloader)
> + * based on the timer counter.
> + */
> +void arch_timer_setsystime(void)
> +{
> +	static struct timespec64 boot_ts;
> +	static cycles_t cycles;
> +	unsigned long long nsecs;
> +
> +	cycles = arch_timer_read_counter() ? arch_timer_read_counter() : 0;
> +
> +	nsecs = clocksource_cyc2ns(cycles, clocksource_counter.mult,
> +				   clocksource_counter.shift);
> +	timespec64_add_ns(&boot_ts, nsecs);
> +
> +	if (do_settimeofday64(&boot_ts))
> +		pr_warn("arch_timer: unable to set systime\n");
> +}
> +#endif /* CONFIG_BOOT_TIME_PRESERVE */
> +
>  static void __init arch_counter_register(unsigned type)
>  {
>  	u64 start_count;
> @@ -504,6 +526,10 @@ static void __init arch_counter_register(unsigned type)
>
>  	/* 56 bits minimum, so we assume worst case rollover */
>  	sched_clock_register(arch_timer_read_counter, 56, arch_timer_rate);
> +#ifdef CONFIG_BOOT_TIME_PRESERVE
> +	/* Set systime */
> +	arch_timer_setsystime();
> +#endif /* CONFIG_BOOT_TIME_PRESERVE */
>  }
>
>  static void arch_timer_stop(struct clock_event_device *clk)
> diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
> index 4008d9f..7d70232 100644
> --- a/kernel/time/Kconfig
> +++ b/kernel/time/Kconfig
> @@ -193,5 +193,13 @@ config HIGH_RES_TIMERS
>  	  hardware is not capable then this option only increases
>  	  the size of the kernel image.
>
> +config BOOT_TIME_PRESERVE
> +	bool "Preserve Boot Time Support"
> +	help
> +	  This option enables Boot Time Preservation between Bootloader and
> +	  Linux Kernel. It is based on the idea that the Bootloader (or any
> +	  other early firmware) will start the HW Timer and Linux Kernel will
> +	  count the time starting with the cycles elapsed since timer start.
> +
>  endmenu
>  endif
> diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c
> index a26036d..1d6e35a 100644
> --- a/kernel/time/sched_clock.c
> +++ b/kernel/time/sched_clock.c
> @@ -193,7 +193,13 @@ sched_clock_register(u64 (*read)(void), int bits, unsigned long rate)
>  	/* Update epoch for new counter and update 'epoch_ns' from old counter*/
>  	new_epoch = read();
>  	cyc = cd.actual_read_sched_clock();
> +
> +#ifdef CONFIG_BOOT_TIME_PRESERVE
> +	ns = rd.epoch_ns + cyc_to_ns((new_epoch - rd.epoch_cyc) & new_mask, new_mult, new_shift);
> +#else
>  	ns = rd.epoch_ns + cyc_to_ns((cyc - rd.epoch_cyc) & rd.sched_clock_mask, rd.mult, rd.shift);
> +#endif /* CONFIG_BOOT_TIME_PRESERVE */
> +
>  	cd.actual_read_sched_clock = read;
>
>  	rd.read_sched_clock	= read;
>

[toc] | [prev] | [next] | [standalone]


#1635640

From"Mirea, Bogdan-Stefan" <Bogdan-Stefan_Mirea@mentor.com>
Date2017-05-04 13:00 +0200
Message-ID<tDmEi-2js-23@gated-at.bofh.it>
In reply to#1635567
Hi Oleksij,

On Thursday, May 04, 2017 12:27 PM, Oleksij Rempel wrote:
> Hi Bogdan,
>
> are there any example what and how bootloader should do to provide
> correct values?

I will give you an example with a real behavior on Renesas RCAR Gen3
Salvator-x:

We have an ARM64 SOC with the following boot stages:
ARM Trusted Firmware BL2 -> ARM Trusted Firmware BL31 -> U-Boot -> Linux

[First]
On ARM Trusted Firmware BL31 "programs the CNTFRQ_EL0 register with the
clock frequency of the system counter, which is provided by the
platform"(Aarch64 Bl31 documentation [1]). And after this step the timer
is up and running so every timer cycle is counted in the CCNT register.

[Step A]
After this step BL31 will load and start execution of U-Boot(BL33). In
U-Boot we will spend for example 4 seconds and then load and start
execution of Linux Kernel.

[Step B]
Linux Kernel starts and after kernel timer is initiallized the
sched_clock_register will be called.

[Step C]
Testing with "$: uptime > /dev/kmsg"



Test 1: Testing with default kernel (no patch added)
Log will be:
[Step A]
[    0.165573]
[    0.167127] U-Boot 2015.04 (Apr 06 2017 - 12:28:41)
...
[    4.364556]
[    4.366065] Starting kernel ...

[Step B]
...
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff
max_cycles: 0x1ec02923e, max_idle_ns: 440795202125 ns
[    0.000003] sched_clock: 56 bits at 8MHz, resolution 120ns, wraps
every 2199023255496ns
[    0.000214] Console: colour dummy device 80x25
[    0.000594] console [tty0] enabled
...
[Step C]
$ uptime  > /dev/kmsg
[   9.148458]  00:00:09 up 0 min,  load average: 0.00, 0.00, 0.00

There is no inconsistency between kmsg and uptime, but from [Step B] we
observe that the time spent before kernel start is not added.



Test 2: Testing only with preserve boot time "kernel/time/sched_clock" 
modifications:
Log will be:
[Step A]
[    0.164567]
[    0.166122] U-Boot 2015.04 (Apr 06 2017 - 12:28:41)
...
[    4.357793]
[    4.359301] Starting kernel ...

[Step B]
...
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff
max_cycles: 0x1ec02923e, max_idle_ns: 440795202125 ns
[    4.641512] sched_clock: 56 bits at 8MHz, resolution 120ns, wraps
every 2199023255496ns
[    4.641724] Console: colour dummy device 80x25
[    4.642105] console [tty0] enabled
...

[Step C]
uptime  > /dev/kmsg
[   13.933217]  00:00:09 up 0 min,  load average: 0.00, 0.00, 0.00

We can see that the preserve boottime changes in
"kernel/time/sched_clock" updates the kmsg time [Step B], but there is
an inconsistency between kmsg time and uptime since uptime is not
updated accordingly to the timer's CCNT value [Step C]. The uptime
starts from 0, and dt~=4sec inconsistency between kmsg and uptime is
observable.



Test 3: Testing with the full preserve boot time support with
"kernel/time/sched_clock" and "drivers/clocksource/arm_arch_timer":
Log will be:
[Step A]
[    0.164564]
[    0.166119] U-Boot 2015.04 (Apr 06 2017 - 12:28:41)
...
[    4.357751]
[    4.359259] Starting kernel ...
[Step B]
...
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff
max_cycles: 0x1ec02923e, max_idle_ns: 440795202125 ns
[    4.638667] sched_clock: 56 bits at 8MHz, resolution 120ns, wraps
every 2199023255496ns
[    4.638884] Console: colour dummy device 80x25
[    4.639265] console [tty0] enabled
...

[Step C]
$ uptime > /dev/kmsg
[   17.728591]  00:00:17 up 0 min,  load average: 0.00, 0.00, 0.00

We can observe that the patch updates kmsg time with the time spent
before kernel starts [Step B]("kernel/time/sched_clock") and also
updates kernel uptime("drivers/clocksource/arm_arch_timer") in [Step C]
no inconsistency being present between kmsg and uptime.


Best Regards,
Bogdan
[1]
https://github.com/ARM-software/arm-trusted-firmware/blob/master/docs/firmware-design.md

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web