Skip to contentSkip to conversation

Add persistent clock support

RFC PATCH In review Baolin Wang 2 participants 16 messages May 14, 2018 – May 16, 2018

Subsystems (8)
lore
Share & tools
lore
#0 lore raw

cover Add persistent clock support

Hi,

We will meet below issues when compensating the suspend time for the timekeeping.

1. We have too many different ways of dealing with persistent timekeeping across architectures, so it is hard for one driver to compatable with different architectures.

2. On some platforms (such as Spreadtrum platform), we registered the high resolution timer as one clocksource to update the OS time, but the high resolution timer will be stopped in suspend state. So we use another one always-on timer (but low resolution) to calculate the suspend time to compensate the OS time. Though we can register the always-on timer as one clocksource, we need re-calculate the mult/shift with one larger conversion range to calculate the suspend time and need update the clock in case of running over the always-on timer.

More duplicate code will be added if other platforms meet this case.

3. Now we have 3 sources that could be used to compensate the OS time:
Nonstop clocksource during suspend, persistent clock and rtc device, which is complicated. Another hand is that the nonstop clocksource can risk wrapping if the suspend time is too long, so we need one mechanism to wake up the system before the nonstop clocksource wrapping.

According to above issues, we can introduce one common persistent clock framework to compatable with different architectures, in future we will remove the persistent clock implementation for each architecture. Also this framework will implement common code to help drivers to register easily. Moreover if we converted all SUSPEND_NONSTOP clocksource to register to be one persistent clock, we can remove the SUSPEND_NONSTOP clocksource accounting in timekeeping, which means we can only compensate the OS time from persistent clock and RTC.

Will be appreciated for any comments. Thank you all.

Arnd posted some comments as below last time, but we did not get a general consensus, so I post them again.

Arnd said:

"I was planning to discuss this with Daniel and John during Linaro Connect, but that didn't happen, so I'd like to bring up the bigger picture here again.

Today, we have a number of subsystem-type interfaces that deal with time keeping in the wider sense (I might be missing some):
- clock source
- clock event
- sched clock
- real time clock
- ptp clock
- persistent clock

The first five have separate registration interfaces and may all refer to different hardware blocks, or (more commonly) have some overlap in the hardware. The fifth one is generalized by your series, without it it's really architecture specific (as the other ones were one one point).

Are we happy with that structure in the long run? One of my earlier comments on this series was that I thought it should be combined with the clocksource registration, but upon talking to Baolin about it more, I realized that this just follows the same structure that we have for the others.

In theory, we could have a more abstract way of registering a clock hardware that interfaces with any combination of the six subsystems I mentioned above, with a superset of the subsystem specific structures and a set of flags that indicate what a particular device is usable for.

Combining all six might be a bit too much (in particular rtc, though it clearly overlaps the persistent-clk case), but what your general ideas on where we should be heading? Is it worth reworking the core kernel portion of the subsystems to simplify the individual drivers?"

Baolin Wang (10):
time: Add persistent clock support
clocksource: sprd: Add one persistent timer for Spreadtrum platform
arm: omap: Convert 32K counter to use persistent clock
clocksource: tegra20_timer: Remove register_persistent_clock() API
arm: time: Remove the persistent clock support for ARM
clocksource: arm_arch_timer: Register the persistent clock
clocksource: timer-ti-32k: Register the persistent clock
clocksource: time-pistachio: Register the persistent clock
x86: tsc: Register the persistent clock
time: timekeeping: Remove time compensating from nonstop clocksources

 arch/arm/include/asm/mach/time.h     |    4 -
 arch/arm/kernel/time.c               |   36 -------
 arch/arm/plat-omap/Kconfig           |    1 +
 arch/arm/plat-omap/counter_32k.c     |   44 ++-------
 arch/x86/Kconfig                     |    1 +
 arch/x86/kernel/tsc.c                |   16 +++
 drivers/clocksource/Kconfig          |    4 +
 drivers/clocksource/arm_arch_timer.c |   10 ++
 drivers/clocksource/tegra20_timer.c  |   12 ++-
 drivers/clocksource/time-pistachio.c |    3 +
 drivers/clocksource/timer-sprd.c     |   80 +++++++++++++++
 drivers/clocksource/timer-ti-32k.c   |    4 +
 include/linux/persistent_clock.h     |   21 ++++
 kernel/time/Kconfig                  |    4 +
 kernel/time/Makefile                 |    1 +
 kernel/time/persistent_clock.c       |  180 ++++++++++++++++++++++++++++++++++
 kernel/time/timekeeping.c            |   19 +---
 17 files changed, 345 insertions(+), 95 deletions(-)
 create mode 100644 include/linux/persistent_clock.h
 create mode 100644 kernel/time/persistent_clock.c
Signature · 1 line
1.7.9.5
#1 lore raw

RFC PATCH 1/10 time: Add persistent clock support

On our Spreadtrum SC9860 platform, we registered the high resolution ARM generic timer as one clocksource to update the OS time, but the ARM generic timer will be stopped in suspend state. So we use one 64bit always-on timer (but low resolution) of Spreadtrum to calculate the suspend time to compensate the OS time. Though we can register the always-on timer as one clocksource, we need re-calculate the mult/shift with one larger conversion range to calculate the suspend time.

But now we have too many different ways of dealing with persistent timekeeping across architectures, and there will be many duplicate code if we register one timer to be one persistent clock. Thus it will be more helpful if we add one common framework for timer drivers to be registered as one persistent clock and implement the common read_persistent_clock64() to compensate the OS time.

Moreover we can register the clocksource with CLOCK_SOURCE_SUSPEND_NONSTOP to be one persistent clock, then we can simplify the suspend/resume accounting by removing CLOCK_SOURCE_SUSPEND_NONSTOP timing. After that we can only compensate the OS time by persistent clock or RTC.

---
 include/linux/persistent_clock.h |   21 +++++
 kernel/time/Kconfig              |    4 +
 kernel/time/Makefile             |    1 +
 kernel/time/persistent_clock.c   |  180 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 206 insertions(+)
 create mode 100644 include/linux/persistent_clock.h
 create mode 100644 kernel/time/persistent_clock.c
include/linux/persistent_clock.h new file +21 -0
new file mode 100644
index 0000000..4917980
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef __PERSISTENT_CLOCK_H__
+#define __PERSISTENT_CLOCK_H__
+
+#ifdef CONFIG_PERSISTENT_CLOCK
+extern int __init persistent_clock_init_and_register(u64 (*read)(void),
+						     u64 mask, u32 freq,
+						     u64 maxsec);
+extern void __init persistent_clock_cleanup(void);
+#else
+static inline int persistent_clock_init_and_register(u64 (*read)(void),
+						     u64 mask, u32 freq,
+						     u64 maxsec)
+{
+	return 0;
+}
+
+static inline void persistent_clock_cleanup(void) { }
+#endif
+
+#endif
kernel/time/Kconfig +4 -0
index 78eabc4..7188600 100644
@@ -47,6 +47,10 @@ config GENERIC_CLOCKEVENTS_MIN_ADJUST
 config GENERIC_CMOS_UPDATE
 	bool
 
+# Persistent clock support
+config PERSISTENT_CLOCK
+	bool
+
 if GENERIC_CLOCKEVENTS
 menu "Timers subsystem"
 
kernel/time/Makefile +1 -0
index f1e46f3..f6d368f 100644
@@ -18,3 +18,4 @@ obj-$(CONFIG_GENERIC_SCHED_CLOCK)		+= sched_clock.o
 obj-$(CONFIG_TICK_ONESHOT)			+= tick-oneshot.o tick-sched.o
 obj-$(CONFIG_DEBUG_FS)				+= timekeeping_debug.o
 obj-$(CONFIG_TEST_UDELAY)			+= test_udelay.o
+obj-$(CONFIG_PERSISTENT_CLOCK)			+= persistent_clock.o
kernel/time/persistent_clock.c new file +180 -0

180 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#2 lore raw

RFC PATCH 2/10 clocksource: sprd: Add one persistent timer for Spreadtrum platform

In reply to Baolin Wang

On Spreadtrum SC9860 platform, we need one persistent timer to calculate the suspend time to compensate the OS time.

This patch registers one Spreadtrum AON timer as persistent timer, which runs at 32bit and periodic mode.

---
 drivers/clocksource/Kconfig      |    1 +
 drivers/clocksource/timer-sprd.c |   80 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+)
drivers/clocksource/Kconfig +1 -0
index 8e8a097..d7dddcc 100644
@@ -453,6 +453,7 @@ config SPRD_TIMER
 	bool "Spreadtrum timer driver" if COMPILE_TEST
 	depends on HAS_IOMEM
 	select TIMER_OF
+	select PERSISTENT_CLOCK
 	help
 	  Enables support for the Spreadtrum timer driver.
 
drivers/clocksource/timer-sprd.c +80 -0

91 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#3 lore raw

RFC PATCH 3/10 arm: omap: Convert 32K counter to use persistent clock

In reply to Baolin Wang

We have introduced the persistent clock framework to support the OS time compensating from persistent clock, so this patch converts the 32k counter to use persistent clock framework to save lots of duplicate code.

---
 arch/arm/plat-omap/Kconfig       |    1 +
 arch/arm/plat-omap/counter_32k.c |   44 ++++++--------------------------------
 2 files changed, 8 insertions(+), 37 deletions(-)
arch/arm/plat-omap/Kconfig +1 -0
index afc1a1d..0e4e385 100644
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 config ARCH_OMAP
+	select PERSISTENT_CLOCK
 	bool
 
 if ARCH_OMAP
arch/arm/plat-omap/counter_32k.c +7 -37

68 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#4 lore raw

RFC PATCH 4/10 clocksource: tegra20_timer: Remove register_persistent_clock() API

In reply to Baolin Wang

We will convert all drivers to use persistent clock framework to compensate the suspend time for OS time, instead of using the register_persistent_clock() API in ARM architecture.

So this patch removes the register_persistent_clock() and implement its function to read persistent clock.

---
 drivers/clocksource/tegra20_timer.c |   12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
drivers/clocksource/tegra20_timer.c +9 -3
index c337a81..97a34cb 100644
@@ -124,7 +124,7 @@ static u64 tegra_rtc_read_ms(void)
 }
 
 /*
- * tegra_read_persistent_clock64 -  Return time from a persistent clock.
+ * read_persistent_clock64 -  Return time from a persistent clock.
  *
  * Reads the time from a source which isn't disabled during PM, the
  * 32k sync timer.  Convert the cycles elapsed since last read into
@@ -133,10 +133,16 @@ static u64 tegra_rtc_read_ms(void)
  * tegra_rtc driver could be executing to avoid race conditions
  * on the RTC shadow register
  */
-static void tegra_read_persistent_clock64(struct timespec64 *ts)
+void read_persistent_clock64(struct timespec64 *ts)
 {
 	u64 delta;
 
+	if (!rtc_base) {
+		ts->tv_sec = 0;
+		ts->tv_nsec = 0;
+		return;
+	}
+
 	last_persistent_ms = persistent_ms;
 	persistent_ms = tegra_rtc_read_ms();
 	delta = persistent_ms - last_persistent_ms;
@@ -259,6 +265,6 @@ static int __init tegra20_init_rtc(struct device_node *np)
 	else
 		clk_prepare_enable(clk);
 
-	return register_persistent_clock(NULL, tegra_read_persistent_clock64);
+	return 0;
 }
 TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc);
Signature · 1 line
1.7.9.5
#5 lore raw

RFC PATCH 5/10 arm: time: Remove the persistent clock support for ARM

In reply to Baolin Wang

We have converted all drivers to use common persistent clock framework to compensate the suspend time, so we can remove the persistent clock, which only supports the ARM architecture.

Moreover there are no drivers will register read_boot_clock64(), so remove it too.

---
 arch/arm/include/asm/mach/time.h |    4 ----
 arch/arm/kernel/time.c           |   36 ------------------------------------
 2 files changed, 40 deletions(-)
arch/arm/include/asm/mach/time.h +0 -4
index 0f79e4d..3cbcafc 100644
@@ -12,8 +12,4 @@
 
 extern void timer_tick(void);
 
-typedef void (*clock_access_fn)(struct timespec64 *);
-extern int register_persistent_clock(clock_access_fn read_boot,
-				     clock_access_fn read_persistent);
-
 #endif
arch/arm/kernel/time.c +0 -36
index cf2701c..713905c 100644
@@ -76,42 +76,6 @@ void timer_tick(void)
 }
 #endif
 
-static void dummy_clock_access(struct timespec64 *ts)
-{
-	ts->tv_sec = 0;
-	ts->tv_nsec = 0;
-}
-
-static clock_access_fn __read_persistent_clock = dummy_clock_access;
-static clock_access_fn __read_boot_clock = dummy_clock_access;
-
-void read_persistent_clock64(struct timespec64 *ts)
-{
-	__read_persistent_clock(ts);
-}
-
-void read_boot_clock64(struct timespec64 *ts)
-{
-	__read_boot_clock(ts);
-}
-
-int __init register_persistent_clock(clock_access_fn read_boot,
-				     clock_access_fn read_persistent)
-{
-	/* Only allow the clockaccess functions to be registered once */
-	if (__read_persistent_clock == dummy_clock_access &&
-	    __read_boot_clock == dummy_clock_access) {
-		if (read_boot)
-			__read_boot_clock = read_boot;
-		if (read_persistent)
-			__read_persistent_clock = read_persistent;
-
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
 void __init time_init(void)
 {
 	if (machine_desc->init_time) {
Signature · 1 line
1.7.9.5
#6 lore raw

RFC PATCH 6/10 clocksource: arm_arch_timer: Register the persistent clock

In reply to Baolin Wang

Register the persistent clock to compensate the suspend time for OS time, if the ARM counter clocksource will not be stopped in suspend state.

---
 drivers/clocksource/Kconfig          |    1 +
 drivers/clocksource/arm_arch_timer.c |   10 ++++++++++
 2 files changed, 11 insertions(+)
drivers/clocksource/Kconfig +1 -0
index d7dddcc..884719c 100644
@@ -308,6 +308,7 @@ config ARC_TIMERS_64BIT
 
 config ARM_ARCH_TIMER
 	bool
+	select PERSISTENT_CLOCK
 	select TIMER_OF if OF
 	select TIMER_ACPI if ACPI
 
drivers/clocksource/arm_arch_timer.c +10 -0
index 57cb2f0..671be63 100644
@@ -32,6 +32,7 @@
 #include <asm/virt.h>
 
 #include <clocksource/arm_arch_timer.h>
+#include <linux/persistent_clock.h>
 
 #undef pr_fmt
 #define pr_fmt(fmt) "arch_timer: " fmt
@@ -950,6 +951,15 @@ 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);
+
+	/*
+	 * Register the persistent clock if the clocksource will not be stopped
+	 * in suspend state.
+	 */
+	if (!arch_counter_suspend_stop)
+		persistent_clock_init_and_register(arch_timer_read_counter,
+						   CLOCKSOURCE_MASK(56),
+						   arch_timer_rate, 0);
 }
 
 static void arch_timer_stop(struct clock_event_device *clk)
Signature · 1 line
1.7.9.5
#7 lore raw

RFC PATCH 7/10 clocksource: timer-ti-32k: Register the persistent clock

In reply to Baolin Wang

Since the 32K counter is always available, then we can register the persistent clock to compensate the suspend time for the OS time.

---
 drivers/clocksource/Kconfig        |    1 +
 drivers/clocksource/timer-ti-32k.c |    4 ++++
 2 files changed, 5 insertions(+)
drivers/clocksource/Kconfig +1 -0
index 884719c..ed19757 100644
@@ -262,6 +262,7 @@ config CLKSRC_TI_32K
 	bool "Texas Instruments 32.768 Hz Clocksource" if COMPILE_TEST
 	depends on GENERIC_SCHED_CLOCK
 	select TIMER_OF if OF
+	select PERSISTENT_CLOCK
 	help
 	  This option enables support for Texas Instruments 32.768 Hz clocksource
 	  available on many OMAP-like platforms.
drivers/clocksource/timer-ti-32k.c +4 -0
index 880a861..353ff9d 100644
@@ -41,6 +41,7 @@
 #include <linux/clocksource.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/persistent_clock.h>
 
 /*
  * 32KHz clocksource ... always available, on pretty most chips except
@@ -120,6 +121,9 @@ static int __init ti_32k_timer_init(struct device_node *np)
 	}
 
 	sched_clock_register(omap_32k_read_sched_clock, 32, 32768);
+	persistent_clock_init_and_register(omap_32k_read_sched_clock,
+					   CLOCKSOURCE_MASK(32), 32768, 0);
+
 	pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n");
 
 	return 0;
Signature · 1 line
1.7.9.5
#8 lore raw

RFC PATCH 8/10 clocksource: time-pistachio: Register the persistent clock

In reply to Baolin Wang

Since the timer on pistachio platform is always available, we can register it as one persistent clock to compensate the suspend time for the OS time.

---
 drivers/clocksource/Kconfig          |    1 +
 drivers/clocksource/time-pistachio.c |    3 +++
 2 files changed, 4 insertions(+)
drivers/clocksource/Kconfig +1 -0
index ed19757..b45be75 100644
@@ -255,6 +255,7 @@ config CLKSRC_PISTACHIO
 	bool "Clocksource for Pistachio SoC" if COMPILE_TEST
 	depends on HAS_IOMEM
 	select TIMER_OF
+	select PERSISTENT_CLOCK
 	help
 	  Enables the clocksource for the Pistachio SoC.
 
drivers/clocksource/time-pistachio.c +3 -0
index a2dd85d..5c3eb71 100644
@@ -20,6 +20,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/persistent_clock.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/sched_clock.h>
@@ -212,6 +213,8 @@ static int __init pistachio_clksrc_of_init(struct device_node *node)
 
 	raw_spin_lock_init(&pcs_gpt.lock);
 	sched_clock_register(pistachio_read_sched_clock, 32, rate);
+	persistent_clock_init_and_register(pistachio_read_sched_clock,
+					   CLOCKSOURCE_MASK(32), rate, 0);
 	return clocksource_register_hz(&pcs_gpt.cs, rate);
 }
 TIMER_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer",
Signature · 1 line
1.7.9.5
#9 lore raw

RFC PATCH 9/10 x86: tsc: Register the persistent clock

In reply to Baolin Wang

Register the tsc as one persistent clock to compensate the suspend time if the tsc clocksource is always available.

---
 arch/x86/Kconfig      |    1 +
 arch/x86/kernel/tsc.c |   16 ++++++++++++++++
 2 files changed, 17 insertions(+)
arch/x86/Kconfig +1 -0
index c07f492..667e3a7 100644
@@ -195,6 +195,7 @@ config X86
 	select USER_STACKTRACE_SUPPORT
 	select VIRT_TO_BUS
 	select X86_FEATURE_NAMES		if PROC_FS
+	select PERSISTENT_CLOCK
 
 config INSTRUCTION_DECODER
 	def_bool y
arch/x86/kernel/tsc.c +16 -0
index 74392d9..dd8d7c3 100644
@@ -11,6 +11,7 @@
 #include <linux/delay.h>
 #include <linux/clocksource.h>
 #include <linux/percpu.h>
+#include <linux/persistent_clock.h>
 #include <linux/timex.h>
 #include <linux/static_key.h>
 
@@ -1032,6 +1033,11 @@ static u64 read_tsc(struct clocksource *cs)
 	return (u64)rdtsc_ordered();
 }
 
+static u64 notrace tsc_read_persistent_clock(void)
+{
+	return (u64)rdtsc_ordered();
+}
+
 static void tsc_cs_mark_unstable(struct clocksource *cs)
 {
 	if (tsc_unstable)
@@ -1300,6 +1306,11 @@ static void tsc_refine_calibration_work(struct work_struct *work)
 	if (boot_cpu_has(X86_FEATURE_ART))
 		art_related_clocksource = &clocksource_tsc;
 	clocksource_register_khz(&clocksource_tsc, tsc_khz);
+
+	if (clocksource_tsc.flags & CLOCK_SOURCE_SUSPEND_NONSTOP)
+		persistent_clock_init_and_register(tsc_read_persistent_clock,
+						   CLOCKSOURCE_MASK(64),
+						   tsc_khz, 0);
 unreg:
 	clocksource_unregister(&clocksource_tsc_early);
 }
@@ -1327,6 +1338,11 @@ static int __init init_tsc_clocksource(void)
 		if (boot_cpu_has(X86_FEATURE_ART))
 			art_related_clocksource = &clocksource_tsc;
 		clocksource_register_khz(&clocksource_tsc, tsc_khz);
+
+		if (clocksource_tsc.flags & CLOCK_SOURCE_SUSPEND_NONSTOP)
+			persistent_clock_init_and_register(tsc_read_persistent_clock,
+							   CLOCKSOURCE_MASK(64),
+							   tsc_khz, 0);
 unreg:
 		clocksource_unregister(&clocksource_tsc_early);
 		return 0;
Signature · 1 line
1.7.9.5
#10 lore raw

RFC PATCH 10/10 time: timekeeping: Remove time compensating from nonstop clocksources

In reply to Baolin Wang

Since we have converted all nonstop clocksources to use persistent clock, thus we can simplify the time compensating by removing the nonstop clocksources. Now we can compensate the suspend time for the OS time from the persistent clock or rtc device.

---
 kernel/time/timekeeping.c |   19 ++++---------------
 1 file changed, 4 insertions(+), 15 deletions(-)
kernel/time/timekeeping.c +4 -15
index 49cbcee..48d2a80 100644
@@ -1666,7 +1666,6 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta)
 void timekeeping_resume(void)
 {
 	struct timekeeper *tk = &tk_core.timekeeper;
-	struct clocksource *clock = tk->tkr_mono.clock;
 	unsigned long flags;
 	struct timespec64 ts_new, ts_delta;
 	u64 cycle_now;
@@ -1682,27 +1681,17 @@ void timekeeping_resume(void)
 
 	/*
 	 * After system resumes, we need to calculate the suspended time and
-	 * compensate it for the OS time. There are 3 sources that could be
-	 * used: Nonstop clocksource during suspend, persistent clock and rtc
-	 * device.
+	 * compensate it for the OS time. There are 2 sources that could be
+	 * used: persistent clock and rtc device.
 	 *
 	 * One specific platform may have 1 or 2 or all of them, and the
 	 * preference will be:
-	 *	suspend-nonstop clocksource -> persistent clock -> rtc
+	 *	persistent clock -> rtc
 	 * The less preferred source will only be tried if there is no better
 	 * usable source. The rtc part is handled separately in rtc core code.
 	 */
 	cycle_now = tk_clock_read(&tk->tkr_mono);
-	if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) &&
-		cycle_now > tk->tkr_mono.cycle_last) {
-		u64 nsec, cyc_delta;
-
-		cyc_delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last,
-					      tk->tkr_mono.mask);
-		nsec = mul_u64_u32_shr(cyc_delta, clock->mult, clock->shift);
-		ts_delta = ns_to_timespec64(nsec);
-		sleeptime_injected = true;
-	} else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) {
+	if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) {
 		ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time);
 		sleeptime_injected = true;
 	}
Signature · 1 line
1.7.9.5
#11 lore raw
In reply to Baolin Wang
Quoted 8 lines · Baolin Wang

Hi,

We will meet below issues when compensating the suspend time for the timekeeping.

1. We have too many different ways of dealing with persistent timekeeping across architectures, so it is hard for one driver to compatable with different architectures.

Quoted 8 lines

2. On some platforms (such as Spreadtrum platform), we registered the high resolution timer as one clocksource to update the OS time, but the high resolution timer will be stopped in suspend state. So we use another one always-on timer (but low resolution) to calculate the suspend time to compensate the OS time. Though we can register the always-on timer as one clocksource, we need re-calculate the mult/shift with one larger conversion range to calculate the suspend time and need update the clock in case of running over the always-on timer.

First, can you elaborate what you mean by 'suspend state' ? On which power domain the clocksource belongs to?

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#12 lore raw

Hi Daniel,

Quoted 18 lines · Daniel Lezcano
Quoted 8 lines · Baolin Wang

Hi,

We will meet below issues when compensating the suspend time for the timekeeping.

1. We have too many different ways of dealing with persistent timekeeping across architectures, so it is hard for one driver to compatable with different architectures.

Quoted 8 lines

2. On some platforms (such as Spreadtrum platform), we registered the high resolution timer as one clocksource to update the OS time, but the high resolution timer will be stopped in suspend state. So we use another one always-on timer (but low resolution) to calculate the suspend time to compensate the OS time. Though we can register the always-on timer as one clocksource, we need re-calculate the mult/shift with one larger conversion range to calculate the suspend time and need update the clock in case of running over the always-on timer.

Quoted 1 line

First, can you elaborate what you mean by 'suspend state' ? On which power

What I mean is the high resolution timer will be stopped when the system goes into suspend state.

Quoted 1 line

domain the clocksource belongs to?

On Spreadtrum platform, It belongs to one power domain named "APCPU_TOP", that will be power down when the system goes into suspend state.

Signature · 2 lines
Baolin.wang
Best Regards
#13 lore raw
Quoted 23 lines · Baolin Wang

Hi Daniel,

Quoted 18 lines · Daniel Lezcano
Quoted 8 lines · Baolin Wang

Hi,

We will meet below issues when compensating the suspend time for the timekeeping.

1. We have too many different ways of dealing with persistent timekeeping across architectures, so it is hard for one driver to compatable with different architectures.

Quoted 8 lines

2. On some platforms (such as Spreadtrum platform), we registered the high resolution timer as one clocksource to update the OS time, but the high resolution timer will be stopped in suspend state. So we use another one always-on timer (but low resolution) to calculate the suspend time to compensate the OS time. Though we can register the always-on timer as one clocksource, we need re-calculate the mult/shift with one larger conversion range to calculate the suspend time and need update the clock in case of running over the always-on timer.

Quoted 1 line

First, can you elaborate what you mean by 'suspend state' ? On which power

Quoted 8 lines

What I mean is the high resolution timer will be stopped when the system goes into suspend state.

Quoted 1 line

domain the clocksource belongs to?

On Spreadtrum platform, It belongs to one power domain named "APCPU_TOP", that will be power down when the system goes into suspend state.

Sorry, I made a mistake here. Our high resolution timer is on one always-on power domain, but it's clock will be shut down when the system goes into suspend.

Signature · 2 lines
Baolin.wang
Best Regards
#14 lore raw
In reply to Baolin Wang
Quoted 34 lines · Baolin Wang

Hi,

We will meet below issues when compensating the suspend time for the timekeeping.

1. We have too many different ways of dealing with persistent timekeeping across architectures, so it is hard for one driver to compatable with different architectures.

2. On some platforms (such as Spreadtrum platform), we registered the high resolution timer as one clocksource to update the OS time, but the high resolution timer will be stopped in suspend state. So we use another one always-on timer (but low resolution) to calculate the suspend time to compensate the OS time. Though we can register the always-on timer as one clocksource, we need re-calculate the mult/shift with one larger conversion range to calculate the suspend time and need update the clock in case of running over the always-on timer.

More duplicate code will be added if other platforms meet this case.

3. Now we have 3 sources that could be used to compensate the OS time:
Nonstop clocksource during suspend, persistent clock and rtc device, which is complicated. Another hand is that the nonstop clocksource can risk wrapping if the suspend time is too long, so we need one mechanism to wake up the system before the nonstop clocksource wrapping.

According to above issues, we can introduce one common persistent clock framework to compatable with different architectures, in future we will remove the persistent clock implementation for each architecture. Also this framework will implement common code to help drivers to register easily. Moreover if we converted all SUSPEND_NONSTOP clocksource to register to be one persistent clock, we can remove the SUSPEND_NONSTOP clocksource accounting in timekeeping, which means we can only compensate the OS time from persistent clock and RTC.

Quoted 1 line

Will be appreciated for any comments. Thank you all.

Why do we need another API ?

Why not remove the present persistent API and rely on the SUSPEND_NONSTOP flag to do the right action at suspend and resume?

We register different clocksources, the rating does the selection.

When entering 'suspend', we check against the SUSPEND_NONSTOP flag and switch to the first clocksource with the best rating and the flag set. When resuming, we switch back to the highest rating.

Having a clocksource out of the always-on domain must be notified with a trace in the log because this is not a normal situation.

Signature · 5 lines
 <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
#15 lore raw

HI Daniel,

Quoted 39 lines · Daniel Lezcano
Quoted 34 lines · Baolin Wang

Hi,

We will meet below issues when compensating the suspend time for the timekeeping.

1. We have too many different ways of dealing with persistent timekeeping across architectures, so it is hard for one driver to compatable with different architectures.

2. On some platforms (such as Spreadtrum platform), we registered the high resolution timer as one clocksource to update the OS time, but the high resolution timer will be stopped in suspend state. So we use another one always-on timer (but low resolution) to calculate the suspend time to compensate the OS time. Though we can register the always-on timer as one clocksource, we need re-calculate the mult/shift with one larger conversion range to calculate the suspend time and need update the clock in case of running over the always-on timer.

More duplicate code will be added if other platforms meet this case.

3. Now we have 3 sources that could be used to compensate the OS time:
Nonstop clocksource during suspend, persistent clock and rtc device, which is complicated. Another hand is that the nonstop clocksource can risk wrapping if the suspend time is too long, so we need one mechanism to wake up the system before the nonstop clocksource wrapping.

According to above issues, we can introduce one common persistent clock framework to compatable with different architectures, in future we will remove the persistent clock implementation for each architecture. Also this framework will implement common code to help drivers to register easily. Moreover if we converted all SUSPEND_NONSTOP clocksource to register to be one persistent clock, we can remove the SUSPEND_NONSTOP clocksource accounting in timekeeping, which means we can only compensate the OS time from persistent clock and RTC.

Quoted 1 line

Will be appreciated for any comments. Thank you all.

Why do we need another API ?

Quoted 8 lines

Why not remove the present persistent API and rely on the SUSPEND_NONSTOP flag to do the right action at suspend and resume?

We register different clocksources, the rating does the selection.

When entering 'suspend', we check against the SUSPEND_NONSTOP flag and switch to the first clocksource with the best rating and the flag set. When resuming, we switch back to the highest rating.

I agree with John's view he posted before, he said:

"For context, these abstractions have grown out of the need for using different hardware components for all of these. It was quite common for x86 hardware to use the acpi_pm for clocksource, lapic/PIT for clockevent, tsc for sched_clock and CMOS RTC for persistent clock. While some of these could be backed by the same hardware, it wasn't common. However, hardware with less restrictions have allowed in some cases for these to be more unified, but I'm not sure if its particularly common.

Another part of the reason that we don't combine the above abstractions, even when they are backed by the same hardware, is because some of the fields used for freq conversion (mult/shift) have different needs for the different types of accounting.

For instance, with a clocksource, we are very focused on avoiding error to keep timekeeing accurate, thus we want to use as large a shift (and thus mult) as possible (and do our shifting as late as possible in our accounting). However, that then shrinks the amount of time that can be accumulated in one go w/o causing an overflow.

Where as with sched_clock, we don't worry as much as about accuracy, so we can use smaller shifts (and thus mults), and thus can go for longer periods of time between accumulating without worrying.

Similarly for the persistent clock case we don't need need to worry as much about accuracy, so we can can use smaller shifts, but we are not in as much of a hot patch, so we can also"

Signature · 2 lines
Baolin.wang
Best Regards