Skip to contentSkip to conversation

Xen wallclock on arm and arm64

PATCH Superseded Stefano Stabellini 6 participants 24 messages Nov 5, 2015 – Nov 9, 2015

Subsystems (4)

v1 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

cover Xen wallclock on arm and arm64

Hi all,

this series introduces PV wallclock time support on arm and arm64.

Stefano Stabellini (3):
xen/arm: introduce xen_read_wallclock
xen/arm: introduce HYPERVISOR_dom0_op on arm and arm64 xen/arm: set the system time in Xen via the XENPF_settime hypercall

 arch/arm/Kconfig                     |    1 +
 arch/arm/include/asm/xen/hypercall.h |    2 +
 arch/arm/xen/enlighten.c             |   82 ++++++++++++++++++++++++++++++++++
 arch/arm/xen/hypercall.S             |    1 +
 arch/arm64/xen/hypercall.S           |    1 +
 5 files changed, 87 insertions(+)

Cheers,

Stefano

#1 lore raw

PATCH 1/3 xen/arm: introduce xen_read_wallclock

Read the wallclock from the shared info page at boot time.

---
 arch/arm/Kconfig         |    1 +
 arch/arm/xen/enlighten.c |   31 +++++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)
arch/arm/Kconfig +1 -0
index 60be104..a9de420 100644
@@ -1852,6 +1852,7 @@ config XEN
 	depends on CPU_V7 && !CPU_V6
 	depends on !GENERIC_ATOMIC64
 	depends on MMU
+	depends on HAVE_ARM_ARCH_TIMER
 	select ARCH_DMA_ADDR_T_64BIT
 	select ARM_PSCI
 	select SWIOTLB_XEN
arch/arm/xen/enlighten.c +31 -0
index 15621b1..f07383d 100644
@@ -28,6 +28,8 @@
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
 #include <linux/console.h>
+#include <linux/timekeeping.h>
+#include <clocksource/arm_arch_timer.h>
 
 #include <linux/mm.h>
 
@@ -95,6 +97,32 @@ static unsigned long long xen_stolen_accounting(int cpu)
 	return state.time[RUNSTATE_runnable] + state.time[RUNSTATE_offline];
 }
 
+static void xen_read_wallclock(struct timespec *ts)
+{
+	u32 version;
+	u64 delta;
+	struct timespec now;
+	struct shared_info *s = HYPERVISOR_shared_info;
+	struct pvclock_wall_clock *wall_clock = &(s->wc);
+
+	/* get wallclock at system boot */
+	do {
+		version = wall_clock->version;
+		rmb();		/* fetch version before time */
+		now.tv_sec  = wall_clock->sec;
+		now.tv_nsec = wall_clock->nsec;
+		rmb();		/* fetch time before checking version */
+	} while ((wall_clock->version & 1) || (version != wall_clock->version));
+
+	delta = arch_timer_read_counter();	/* time since system boot */
+	delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;
+
+	now.tv_nsec = do_div(delta, NSEC_PER_SEC);
+	now.tv_sec = delta;
+
+	set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
+}
+
 static void xen_percpu_init(void)
 {
 	struct vcpu_register_vcpu_info info;
@@ -218,6 +246,7 @@ static int __init xen_guest_init(void)
 	struct shared_info *shared_info_page = NULL;
 	struct resource res;
 	phys_addr_t grant_frames;
+	struct timespec ts;
 
 	if (!xen_domain())
 		return 0;
@@ -291,6 +320,8 @@ static int __init xen_guest_init(void)
 
 	pv_time_ops.steal_clock = xen_stolen_accounting;
 	static_key_slow_inc(&paravirt_steal_enabled);
+	xen_read_wallclock(&ts);
+	do_settimeofday(&ts);
 
 	return 0;
 }
Signature · 1 line
1.7.10.4
#2 lore raw

PATCH 1/3 xen/arm: introduce xen_read_wallclock

Quoted 3 lines · On Thursday 05 November 2015 17:09:43 Stefano Stabellini wrote:

Read the wallclock from the shared info page at boot time.

Please use the appropriate timespec64 based functions here, we are in the process of converting all callers of struct timespec.

arch/arm/xen/enlighten.c static unsigned long long xen_stolen_accounting(int cpu) · line 106

Quoted 8 lines

---

arch/arm/xen/enlighten.c +7 -0
+static void xen_read_wallclock(struct timespec *ts)
+{
+	u32 version;
+	u64 delta;
+	struct timespec now;
+	struct shared_info *s = HYPERVISOR_shared_info;
+	struct pvclock_wall_clock *wall_clock = &(s->wc);

pvclock_wall_clock has a 'u32 sec', so that suffers from a potential overflow. We should try to avoid introducing that on ARM, and instead have a 64-bit seconds based version, or alternatively a 64-bit nanoseconds version (with no extra seconds) that is also sufficient.

Quoted 10 lines
arch/arm/xen/enlighten.c +1 -0
 	struct vcpu_register_vcpu_info info;
@@ -218,6 +246,7 @@ static int __init xen_guest_init(void)
 	struct shared_info *shared_info_page = NULL;
 	struct resource res;
 	phys_addr_t grant_frames;
+	struct timespec ts;
 
 	if (!xen_domain())
 		return 0;

arch/arm/xen/enlighten.c static int __init xen_guest_init(void) · line 325

Quoted 6 lines
arch/arm/xen/enlighten.c +2 -0
@@ -291,6 +320,8 @@ static int __init xen_guest_init(void)
 
 	pv_time_ops.steal_clock = xen_stolen_accounting;
 	static_key_slow_inc(&paravirt_steal_enabled);
+	xen_read_wallclock(&ts);
+	do_settimeofday(&ts);
 

Once you can get a 64-bit time, call do_settimeofday64() here.

Arnd

#3 lore raw

PATCH 1/3 xen/arm: introduce xen_read_wallclock

Quoted 7 lines · Arnd Bergmann
Quoted 3 lines · On Thursday 05 November 2015 17:09:43 Stefano Stabellini wrote:

Read the wallclock from the shared info page at boot time.

Please use the appropriate timespec64 based functions here, we are in the process of converting all callers of struct timespec.

OK, I can do that

Quoted 6 lines
Quoted 6 lines

---

arch/arm/xen/enlighten.c +5 -0
+static void xen_read_wallclock(struct timespec *ts)
+{
+	u32 version;
+	u64 delta;
+	struct timespec now;
Quoted 8 lines

arch/arm/xen/enlighten.c static unsigned long long xen_stolen_accounting(int cpu) · line 106

Quoted 2 lines
arch/arm/xen/enlighten.c +2 -0
+	struct shared_info *s = HYPERVISOR_shared_info;
+	struct pvclock_wall_clock *wall_clock = &(s->wc);

pvclock_wall_clock has a 'u32 sec', so that suffers from a potential overflow. We should try to avoid introducing that on ARM, and instead have a 64-bit seconds based version, or alternatively a 64-bit nanoseconds version (with no extra seconds) that is also sufficient.

Unfortunately this a preexisting ABI which is common with other existing architectures (see arch/x86/kernel/pvclock.c:pvclock_read_wallclock). I cannot just change it.

Quoted 11 lines
Quoted 11 lines
arch/arm/xen/enlighten.c +1 -0
 	struct vcpu_register_vcpu_info info;
@@ -218,6 +246,7 @@ static int __init xen_guest_init(void)
 	struct shared_info *shared_info_page = NULL;
 	struct resource res;
 	phys_addr_t grant_frames;
+	struct timespec ts;
 
 	if (!xen_domain())
 		return 0;
@@ -291,6 +320,8 @@ static int __init xen_guest_init(void)
 
Quoted 8 lines

arch/arm/xen/enlighten.c static int __init xen_guest_init(void) · line 325

Quoted 5 lines
arch/arm/xen/enlighten.c +2 -0
 	pv_time_ops.steal_clock = xen_stolen_accounting;
 	static_key_slow_inc(&paravirt_steal_enabled);
+	xen_read_wallclock(&ts);
+	do_settimeofday(&ts);
 

Once you can get a 64-bit time, call do_settimeofday64() here.

OK

#4 lore raw

PATCH 1/3 xen/arm: introduce xen_read_wallclock

Quoted 15 lines · On Friday 06 November 2015 15:09:53 Stefano Stabellini wrote:
Quoted 6 lines
Quoted 6 lines

---

arch/arm/xen/enlighten.c +5 -0
+static void xen_read_wallclock(struct timespec *ts)
+{
+   u32 version;
+   u64 delta;
+   struct timespec now;
Quoted 8 lines

arch/arm/xen/enlighten.c static unsigned long long xen_stolen_accounting(int cpu) · line 106

Quoted 2 lines
arch/arm/xen/enlighten.c +2 -0
+   struct shared_info *s = HYPERVISOR_shared_info;
+   struct pvclock_wall_clock *wall_clock = &(s->wc);

pvclock_wall_clock has a 'u32 sec', so that suffers from a potential overflow. We should try to avoid introducing that on ARM, and instead have a 64-bit seconds based version, or alternatively a 64-bit nanoseconds version (with no extra seconds) that is also sufficient.

Quoted 3 lines

Unfortunately this a preexisting ABI which is common with other existing architectures (see arch/x86/kernel/pvclock.c:pvclock_read_wallclock). I cannot just change it.

Maybe we need a "struct pvclock_wall_clock_v2"?

In theory, 'u32 sec' takes us all the way until 2106, which is significantly longer away than the signed overflow in 2038, but it would still be nice to not introduce this limitation on ARM in the first place.

I'm not quite sure about how the split between pvclock_wall_clock and the delta works. Normally I'd expect that pvclock_wall_clock is the wallclock time as it was at boot, while delta is the number of expired nanoseconds since boot. However it is unclear why the latter has a longer range (539 years starting at boot, rather than 126 years starting in 1970).

Arnd

#5 lore raw

PATCH 1/3 xen/arm: introduce xen_read_wallclock

Quoted 25 lines · Arnd Bergmann
Quoted 15 lines
Quoted 6 lines
Quoted 6 lines

---

arch/arm/xen/enlighten.c +5 -0
+static void xen_read_wallclock(struct timespec *ts)
+{
+   u32 version;
+   u64 delta;
+   struct timespec now;
Quoted 8 lines

arch/arm/xen/enlighten.c static unsigned long long xen_stolen_accounting(int cpu) · line 106

Quoted 2 lines
arch/arm/xen/enlighten.c +2 -0
+   struct shared_info *s = HYPERVISOR_shared_info;
+   struct pvclock_wall_clock *wall_clock = &(s->wc);

pvclock_wall_clock has a 'u32 sec', so that suffers from a potential overflow. We should try to avoid introducing that on ARM, and instead have a 64-bit seconds based version, or alternatively a 64-bit nanoseconds version (with no extra seconds) that is also sufficient.

Quoted 3 lines

Unfortunately this a preexisting ABI which is common with other existing architectures (see arch/x86/kernel/pvclock.c:pvclock_read_wallclock). I cannot just change it.

Maybe we need a "struct pvclock_wall_clock_v2"?

In theory, 'u32 sec' takes us all the way until 2106, which is significantly longer away than the signed overflow in 2038, but it would still be nice to not introduce this limitation on ARM in the first place.

Quoted 5 lines

I'm not quite sure about how the split between pvclock_wall_clock and the delta works. Normally I'd expect that pvclock_wall_clock is the wallclock time as it was at boot, while delta is the number of expired nanoseconds since boot. However it is unclear why the latter has a longer range (539 years starting at boot, rather than 126 years starting in 1970).

Actually we already have a sec overflow field in struct shared_info on the hypervisor side, called wc_sec_hi. I just need to make use of it in Linux. See:

http://xenbits.xen.org/gitweb/?p=xen.git;a=blob_plain;f=xen/include/public/xen.h;hb=HEAD

Thanks for raising my attention to the problem,

Stefano

#6 lore raw

PATCH 1/3 xen/arm: introduce xen_read_wallclock

Quoted 7 lines · On Monday 09 November 2015 13:53:30 Stefano Stabellini wrote:
Quoted 5 lines · Arnd Bergmann

I'm not quite sure about how the split between pvclock_wall_clock and the delta works. Normally I'd expect that pvclock_wall_clock is the wallclock time as it was at boot, while delta is the number of expired nanoseconds since boot. However it is unclear why the latter has a longer range (539 years starting at boot, rather than 126 years starting in 1970).

Quoted 7 lines

Actually we already have a sec overflow field in struct shared_info on the hypervisor side, called wc_sec_hi. I just need to make use of it in Linux. See:

http://xenbits.xen.org/gitweb/?p=xen.git;a=blob_plain;f=xen/include/public/xen.h;hb=HEAD

Thanks for raising my attention to the problem,

Sounds good for Xen on ARM. This same interface is also used on KVM, right? Does the extension also work there?

Arnd

#7 lore raw

PATCH 1/3 xen/arm: introduce xen_read_wallclock

Quoted 12 lines · Arnd Bergmann
Quoted 11 lines · On Monday 09 November 2015 13:53:30 Stefano Stabellini wrote:
Quoted 5 lines · Arnd Bergmann

I'm not quite sure about how the split between pvclock_wall_clock and the delta works. Normally I'd expect that pvclock_wall_clock is the wallclock time as it was at boot, while delta is the number of expired nanoseconds since boot. However it is unclear why the latter has a longer range (539 years starting at boot, rather than 126 years starting in 1970).

Actually we already have a sec overflow field in struct shared_info on the hypervisor side, called wc_sec_hi. I just need to make use of it in Linux. See:

Quoted 6 lines
Quoted 3 lines

http://xenbits.xen.org/gitweb/?p=xen.git;a=blob_plain;f=xen/include/public/xen.h;hb=HEAD

Thanks for raising my attention to the problem,

Sounds good for Xen on ARM. This same interface is also used on KVM, right? Does the extension also work there?

It doesn't look like it (see arch/x86/kvm/x86.c:kvm_write_wall_clock).

#8 lore raw

PATCH 1/3 xen/arm: introduce xen_read_wallclock

Quoted 13 lines · On Monday 09 November 2015 17:14:24 Stefano Stabellini wrote:
Quoted 12 lines · Arnd Bergmann
Quoted 11 lines · On Monday 09 November 2015 13:53:30 Stefano Stabellini wrote:
Quoted 5 lines · Arnd Bergmann

I'm not quite sure about how the split between pvclock_wall_clock and the delta works. Normally I'd expect that pvclock_wall_clock is the wallclock time as it was at boot, while delta is the number of expired nanoseconds since boot. However it is unclear why the latter has a longer range (539 years starting at boot, rather than 126 years starting in 1970).

Actually we already have a sec overflow field in struct shared_info on the hypervisor side, called wc_sec_hi. I just need to make use of it in Linux. See:

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

http://xenbits.xen.org/gitweb/?p=xen.git;a=blob_plain;f=xen/include/public/xen.h;hb=HEAD

Thanks for raising my attention to the problem,

Sounds good for Xen on ARM. This same interface is also used on KVM, right? Does the extension also work there?

It doesn't look like it (see arch/x86/kvm/x86.c:kvm_write_wall_clock).

(adding Christoffer and Marc)

That kvm_set_msr_common() function appears to be very x86 specific though, and I'm not sure what the ARM equivalent would be.

How does KVM get/set the system time today on ARM and ARM64? Is this going to be done through a PSCI call based on pvclock_wall_clock in the future?

Arnd

reviewer
#9 lore raw

PATCH 1/3 xen/arm: introduce xen_read_wallclock

In reply to Stefano Stabellini

arch/arm/xen/enlighten.c static unsigned long long xen_stolen_accounting(int cpu) · line 118

Quoted 2 lines
arch/arm/xen/enlighten.c +2 -0
+	delta = arch_timer_read_counter();	/* time since system boot */
+	delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;

The arch counter value is not a number of nanoseconds (unless CNTFRQ reads as 1000000), so this doesn't look right; the units don't match.

Thanks,
Mark.

#10 lore raw

PATCH 1/3 xen/arm: introduce xen_read_wallclock

Quoted 5 lines · Mark Rutland

arch/arm/xen/enlighten.c static unsigned long long xen_stolen_accounting(int cpu) · line 118

Quoted 2 lines
arch/arm/xen/enlighten.c +2 -0
+	delta = arch_timer_read_counter();	/* time since system boot */
+	delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;

The arch counter value is not a number of nanoseconds (unless CNTFRQ reads as 1000000), so this doesn't look right; the units don't match.

That was a bad mistake. Thanks for catching it!

#11 lore raw

PATCH 2/3 xen/arm: introduce HYPERVISOR_dom0_op on arm and arm64

In reply to Stefano Stabellini
---
 arch/arm/include/asm/xen/hypercall.h |    2 ++
 arch/arm/xen/enlighten.c             |    1 +
 arch/arm/xen/hypercall.S             |    1 +
 arch/arm64/xen/hypercall.S           |    1 +
 4 files changed, 5 insertions(+)
arch/arm/include/asm/xen/hypercall.h +2 -0
index 712b50e..7a8ee15 100644
@@ -35,6 +35,7 @@
 
 #include <xen/interface/xen.h>
 #include <xen/interface/sched.h>
+#include <xen/interface/platform.h>
 
 long privcmd_call(unsigned call, unsigned long a1,
 		unsigned long a2, unsigned long a3,
@@ -49,6 +50,7 @@ int HYPERVISOR_memory_op(unsigned int cmd, void *arg);
 int HYPERVISOR_physdev_op(int cmd, void *arg);
 int HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args);
 int HYPERVISOR_tmem_op(void *arg);
+int HYPERVISOR_dom0_op(void *arg);
 int HYPERVISOR_multicall(struct multicall_entry *calls, uint32_t nr);
 
 static inline int
arch/arm/xen/enlighten.c +1 -0
index f07383d..b6aea9c 100644
@@ -359,5 +359,6 @@ EXPORT_SYMBOL_GPL(HYPERVISOR_memory_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_physdev_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_vcpu_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_tmem_op);
+EXPORT_SYMBOL_GPL(HYPERVISOR_dom0_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_multicall);
 EXPORT_SYMBOL_GPL(privcmd_call);
arch/arm/xen/hypercall.S +1 -0
index 10fd99c..89db58f 100644
@@ -89,6 +89,7 @@ HYPERCALL2(memory_op);
 HYPERCALL2(physdev_op);
 HYPERCALL3(vcpu_op);
 HYPERCALL1(tmem_op);
+HYPERCALL1(dom0_op);
 HYPERCALL2(multicall);
 
 ENTRY(privcmd_call)
arch/arm64/xen/hypercall.S +1 -0
index 8bbe940..3840b1a 100644
@@ -80,6 +80,7 @@ HYPERCALL2(memory_op);
 HYPERCALL2(physdev_op);
 HYPERCALL3(vcpu_op);
 HYPERCALL1(tmem_op);
+HYPERCALL1(dom0_op);
 HYPERCALL2(multicall);
 
 ENTRY(privcmd_call)
Signature · 1 line
1.7.10.4
#12 lore raw

PATCH 2/3 xen/arm: introduce HYPERVISOR_dom0_op on arm and arm64

arch/arm/xen/hypercall.S HYPERCALL2(memory_op); · line 92

Quoted 8 lines
Quoted 1 line
Quoted 1 line · On 05.11.15 at 18:09, <[email protected]> wrote:
arch/arm/xen/hypercall.S +1 -0
@@ -89,6 +89,7 @@ HYPERCALL2(memory_op);
 HYPERCALL2(physdev_op);
 HYPERCALL3(vcpu_op);
 HYPERCALL1(tmem_op);
+HYPERCALL1(dom0_op);

Assuming this somehow tries to mirror x86 naming - time to rename it there? I don't see why you'd want to introduce a dom0_op when it has been renamed to platform_op many years ago - see public/dom0_ops.h.

Jan

#13 lore raw

PATCH 2/3 xen/arm: introduce HYPERVISOR_dom0_op on arm and arm64

Quoted 13 lines · Jan Beulich

arch/arm/xen/hypercall.S HYPERCALL2(memory_op); · line 92

Quoted 8 lines
Quoted 1 line
Quoted 1 line · On 05.11.15 at 18:09, <[email protected]> wrote:
arch/arm/xen/hypercall.S +1 -0
@@ -89,6 +89,7 @@ HYPERCALL2(memory_op);
 HYPERCALL2(physdev_op);
 HYPERCALL3(vcpu_op);
 HYPERCALL1(tmem_op);
+HYPERCALL1(dom0_op);

Assuming this somehow tries to mirror x86 naming - time to rename it there? I don't see why you'd want to introduce a dom0_op when it has been renamed to platform_op many years ago - see public/dom0_ops.h.

In Linux it was never renamed. I could do that now as a precursor to this.

#14 lore raw

Re: [PATCH 2/3] xen/arm: introduce HYPERVISOR_dom0_op on arm and arm64

In reply to Jan Beulich
Quoted 13 lines · Jan Beulich

arch/arm/xen/hypercall.S HYPERCALL2(memory_op); · line 92

Quoted 8 lines
Quoted 1 line
Quoted 1 line · On 05.11.15 at 18:09, <[email protected]> wrote:
arch/arm/xen/hypercall.S +1 -0
@@ -89,6 +89,7 @@ HYPERCALL2(memory_op);
 HYPERCALL2(physdev_op);
 HYPERCALL3(vcpu_op);
 HYPERCALL1(tmem_op);
+HYPERCALL1(dom0_op);

Assuming this somehow tries to mirror x86 naming - time to rename it there? I don't see why you'd want to introduce a dom0_op when it has been renamed to platform_op many years ago - see public/dom0_ops.h.

In Linux it was never renamed. I could do that now as a precursor to this.

#15 lore raw

PATCH 3/3 xen/arm: set the system time in Xen via the XENPF_settime hypercall

In reply to Stefano Stabellini

If Linux is running as dom0, call XENPF_settime to update the system time in Xen on pvclock_gtod notifications.

---
 arch/arm/xen/enlighten.c |   52 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)
arch/arm/xen/enlighten.c +51 -1
index b6aea9c..0176db0 100644
@@ -28,6 +28,7 @@
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
 #include <linux/console.h>
+#include <linux/pvclock_gtod.h>
 #include <linux/timekeeping.h>
 #include <clocksource/arm_arch_timer.h>
 
@@ -123,6 +124,50 @@ static void xen_read_wallclock(struct timespec *ts)
 	set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
 }
 
+static int xen_pvclock_gtod_notify(struct notifier_block *nb,
+				   unsigned long was_set, void *priv)
+{
+	/* Protected by the calling core code serialization */
+	static struct timespec next_sync;
+
+	struct xen_platform_op op;
+	struct timespec now;
+
+	now = __current_kernel_time();
+
+	/*
+	 * We only take the expensive HV call when the clock was set
+	 * or when the 11 minutes RTC synchronization time elapsed.
+	 */
+	if (!was_set && timespec_compare(&now, &next_sync) < 0)
+		return NOTIFY_OK;
+
+	op.interface_version = XENPF_INTERFACE_VERSION;
+	op.cmd = XENPF_settime;
+	op.u.settime.secs = now.tv_sec;
+	op.u.settime.nsecs = now.tv_nsec;
+	op.u.settime.system_time = arch_timer_read_counter();
+	printk("GTOD: Setting to %ld.%ld@%lld\n",
+	       (long)op.u.settime.secs,
+	       (long)op.u.settime.nsecs,
+	       (long long)op.u.settime.system_time);
+	(void)HYPERVISOR_dom0_op(&op);
+
+	/*
+	 * Move the next drift compensation time 11 minutes
+	 * ahead. That's emulating the sync_cmos_clock() update for
+	 * the hardware RTC.
+	 */
+	next_sync = now;
+	next_sync.tv_sec += 11 * 60;
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block xen_pvclock_gtod_notifier = {
+	.notifier_call = xen_pvclock_gtod_notify,
+};
+
 static void xen_percpu_init(void)
 {
 	struct vcpu_register_vcpu_info info;
@@ -321,7 +366,12 @@ static int __init xen_guest_init(void)
 	pv_time_ops.steal_clock = xen_stolen_accounting;
 	static_key_slow_inc(&paravirt_steal_enabled);
 	xen_read_wallclock(&ts);
-	do_settimeofday(&ts);
+	if (xen_initial_domain())
+		pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier);
+	else {
+		xen_read_wallclock(&ts);
+		do_settimeofday(&ts);
+	}
 
 	return 0;
 }
Signature · 1 line
1.7.10.4
#16 lore raw

PATCH 3/3 xen/arm: set the system time in Xen via the XENPF_settime hypercall

Quoted 2 lines · Stefano Stabellini

If Linux is running as dom0, call XENPF_settime to update the system time in Xen on pvclock_gtod notifications.

Isn't this a cut-and-paste from x86? Can you make it common?

David

#17 lore raw

PATCH 3/3 xen/arm: set the system time in Xen via the XENPF_settime hypercall

Quoted 5 lines · David Vrabel
Quoted 2 lines · Stefano Stabellini

If Linux is running as dom0, call XENPF_settime to update the system time in Xen on pvclock_gtod notifications.

Isn't this a cut-and-paste from x86? Can you make it common?

Not exactly, for the way system_time is set.

#18 lore raw

PATCH 3/3 xen/arm: set the system time in Xen via the XENPF_settime hypercall

In reply to Stefano Stabellini
Quoted 23 lines · On Thursday 05 November 2015 17:09:45 Stefano Stabellini wrote:

If Linux is running as dom0, call XENPF_settime to update the system time in Xen on pvclock_gtod notifications.

---
 arch/arm/xen/enlighten.c |   52 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)
arch/arm/xen/enlighten.c +1 -0
index b6aea9c..0176db0 100644
@@ -28,6 +28,7 @@
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
 #include <linux/console.h>
+#include <linux/pvclock_gtod.h>
 #include <linux/timekeeping.h>
 #include <clocksource/arm_arch_timer.h>
 
@@ -123,6 +124,50 @@ static void xen_read_wallclock(struct timespec *ts)
 	set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);

arch/arm/xen/enlighten.c static void xen_read_wallclock(struct timespec *ts) · line 134

Quoted 10 lines
arch/arm/xen/enlighten.c +8 -0
 }
 
+static int xen_pvclock_gtod_notify(struct notifier_block *nb,
+				   unsigned long was_set, void *priv)
+{
+	/* Protected by the calling core code serialization */
+	static struct timespec next_sync;
+
+	struct xen_platform_op op;
+	struct timespec now;

Again, use timespec64

arch/arm/xen/enlighten.c static void xen_read_wallclock(struct timespec *ts) · line 136

Quoted 1 line
arch/arm/xen/enlighten.c +1 -0
+	now = __current_kernel_time();

We don't have __current_kernel_time64() yet, but it is trivial to add, just follow the example of current_kernel_time()/current_kernel_time64() and convert the existing __current_kernel_time() function into a static inline wrapper for the new __current_kernel_time64().

Quoted 7 lines
arch/arm/xen/enlighten.c +7 -0
+	/*
+	 * We only take the expensive HV call when the clock was set
+	 * or when the 11 minutes RTC synchronization time elapsed.
+	 */
+	if (!was_set && timespec_compare(&now, &next_sync) < 0)
+		return NOTIFY_OK;
+

arch/arm/xen/enlighten.c static void xen_read_wallclock(struct timespec *ts) · line 154

Quoted 10 lines
arch/arm/xen/enlighten.c +10 -0
+	op.interface_version = XENPF_INTERFACE_VERSION;
+	op.cmd = XENPF_settime;
+	op.u.settime.secs = now.tv_sec;
+	op.u.settime.nsecs = now.tv_nsec;
+	op.u.settime.system_time = arch_timer_read_counter();
+	printk("GTOD: Setting to %ld.%ld at %lld\n",
+	       (long)op.u.settime.secs,
+	       (long)op.u.settime.nsecs,
+	       (long long)op.u.settime.system_time);
+	(void)HYPERVISOR_dom0_op(&op);

I guess we will also need a XENPF_settime64 interface, but at least we can get away with implementing only that one on ARM, while x86 will have to support both the 32-bit and 64-bit based variant.

Arnd

#19 lore raw

PATCH 3/3 xen/arm: set the system time in Xen via the XENPF_settime hypercall

Quoted 26 lines · Arnd Bergmann
Quoted 25 lines · On Thursday 05 November 2015 17:09:45 Stefano Stabellini wrote:

If Linux is running as dom0, call XENPF_settime to update the system time in Xen on pvclock_gtod notifications.

---
 arch/arm/xen/enlighten.c |   52 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)
arch/arm/xen/enlighten.c +1 -0
index b6aea9c..0176db0 100644
@@ -28,6 +28,7 @@
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
 #include <linux/console.h>
+#include <linux/pvclock_gtod.h>
 #include <linux/timekeeping.h>
 #include <clocksource/arm_arch_timer.h>
 
@@ -123,6 +124,50 @@ static void xen_read_wallclock(struct timespec *ts)
 	set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
 }
 
Quoted 10 lines

arch/arm/xen/enlighten.c static void xen_read_wallclock(struct timespec *ts) · line 134

Quoted 8 lines
arch/arm/xen/enlighten.c +8 -0
+static int xen_pvclock_gtod_notify(struct notifier_block *nb,
+				   unsigned long was_set, void *priv)
+{
+	/* Protected by the calling core code serialization */
+	static struct timespec next_sync;
+
+	struct xen_platform_op op;
+	struct timespec now;

Again, use timespec64

OK

Quoted 7 lines

arch/arm/xen/enlighten.c static void xen_read_wallclock(struct timespec *ts) · line 136

Quoted 1 line
arch/arm/xen/enlighten.c +1 -0
+	now = __current_kernel_time();

We don't have __current_kernel_time64() yet, but it is trivial to add, just follow the example of current_kernel_time()/current_kernel_time64() and convert the existing __current_kernel_time() function into a static inline wrapper for the new __current_kernel_time64().

All right. I guess something like:

struct timespec64 __current_kernel_time64(void)

{
	struct timekeeper *tk = &tk_core.timekeeper;

	return tk_xtime(tk);
}
Quoted 14 lines
Quoted 14 lines
arch/arm/xen/enlighten.c +14 -0
+	/*
+	 * We only take the expensive HV call when the clock was set
+	 * or when the 11 minutes RTC synchronization time elapsed.
+	 */
+	if (!was_set && timespec_compare(&now, &next_sync) < 0)
+		return NOTIFY_OK;
+
+	op.interface_version = XENPF_INTERFACE_VERSION;
+	op.cmd = XENPF_settime;
+	op.u.settime.secs = now.tv_sec;
+	op.u.settime.nsecs = now.tv_nsec;
+	op.u.settime.system_time = arch_timer_read_counter();
+	printk("GTOD: Setting to %ld.%ld at %lld\n",
+	       (long)op.u.settime.secs,
Quoted 8 lines

arch/arm/xen/enlighten.c static void xen_read_wallclock(struct timespec *ts) · line 154

Quoted 3 lines
arch/arm/xen/enlighten.c +3 -0
+	       (long)op.u.settime.nsecs,
+	       (long long)op.u.settime.system_time);
+	(void)HYPERVISOR_dom0_op(&op);

I guess we will also need a XENPF_settime64 interface, but at least we can get away with implementing only that one on ARM, while x86 will have to support both the 32-bit and 64-bit based variant.

We already have XENPF_settime64, I'll just use it instead.

#20 lore raw

PATCH 3/3 xen/arm: set the system time in Xen via the XENPF_settime hypercall

Quoted 10 lines · On Monday 09 November 2015 14:10:22 Stefano Stabellini wrote:
Quoted 8 lines · Arnd Bergmann

arch/arm/xen/enlighten.c static void xen_read_wallclock(struct timespec *ts) · line 136

Quoted 1 line · On Thursday 05 November 2015 17:09:45 Stefano Stabellini wrote:
arch/arm/xen/enlighten.c +1 -0
+	now = __current_kernel_time();

We don't have __current_kernel_time64() yet, but it is trivial to add, just follow the example of current_kernel_time()/current_kernel_time64() and convert the existing __current_kernel_time() function into a static inline wrapper for the new __current_kernel_time64().

Quoted 8 lines

All right. I guess something like:

struct timespec64 __current_kernel_time64(void)

{
	struct timekeeper *tk = &tk_core.timekeeper;

	return tk_xtime(tk);
}

Yes, exactly.

Just to make sure that this is actually the correct interface that you want to call:

__current_kernel_time{,64}() is the fastest interface we have to get an approximation of the current time, while ignoring all of the locking.

Is is possible that you instead want ktime_get_real_ts64(), which gives you the time as precise as the kernel knows it, but uses locking?

Quoted 23 lines
Quoted 14 lines
Quoted 14 lines
arch/arm/xen/enlighten.c +14 -0
+	/*
+	 * We only take the expensive HV call when the clock was set
+	 * or when the 11 minutes RTC synchronization time elapsed.
+	 */
+	if (!was_set && timespec_compare(&now, &next_sync) < 0)
+		return NOTIFY_OK;
+
+	op.interface_version = XENPF_INTERFACE_VERSION;
+	op.cmd = XENPF_settime;
+	op.u.settime.secs = now.tv_sec;
+	op.u.settime.nsecs = now.tv_nsec;
+	op.u.settime.system_time = arch_timer_read_counter();
+	printk("GTOD: Setting to %ld.%ld at %lld\n",
+	       (long)op.u.settime.secs,
Quoted 8 lines

arch/arm/xen/enlighten.c static void xen_read_wallclock(struct timespec *ts) · line 154

Quoted 3 lines
arch/arm/xen/enlighten.c +3 -0
+	       (long)op.u.settime.nsecs,
+	       (long long)op.u.settime.system_time);
+	(void)HYPERVISOR_dom0_op(&op);

I guess we will also need a XENPF_settime64 interface, but at least we can get away with implementing only that one on ARM, while x86 will have to support both the 32-bit and 64-bit based variant.

Quoted 1 line

We already have XENPF_settime64, I'll just use it instead.

Ok, great! Then we just need to find a volunteer who can do the same thing on x86, with the fallback to XENPF_settime that they need for older hosts.

Arnd

#21 lore raw

PATCH 3/3 xen/arm: set the system time in Xen via the XENPF_settime hypercall

Quoted 25 lines · Arnd Bergmann
Quoted 10 lines · On Monday 09 November 2015 14:10:22 Stefano Stabellini wrote:
Quoted 8 lines · Arnd Bergmann

arch/arm/xen/enlighten.c static void xen_read_wallclock(struct timespec *ts) · line 136

Quoted 1 line · On Thursday 05 November 2015 17:09:45 Stefano Stabellini wrote:
arch/arm/xen/enlighten.c +1 -0
+	now = __current_kernel_time();

We don't have __current_kernel_time64() yet, but it is trivial to add, just follow the example of current_kernel_time()/current_kernel_time64() and convert the existing __current_kernel_time() function into a static inline wrapper for the new __current_kernel_time64().

Quoted 8 lines

All right. I guess something like:

struct timespec64 __current_kernel_time64(void)

{
	struct timekeeper *tk = &tk_core.timekeeper;

	return tk_xtime(tk);
}

Yes, exactly.

Just to make sure that this is actually the correct interface that you want to call:

Quoted 7 lines

__current_kernel_time{,64}() is the fastest interface we have to get an approximation of the current time, while ignoring all of the locking.

Is is possible that you instead want ktime_get_real_ts64(), which gives you the time as precise as the kernel knows it, but uses locking?

I am not 100% sure. Can I call ktime_get_real_ts64 from a pvclock_gtod notifier_call function?

#22 lore raw

PATCH 3/3 xen/arm: set the system time in Xen via the XENPF_settime hypercall

Quoted 30 lines · Stefano Stabellini
Quoted 29 lines · Arnd Bergmann
Quoted 10 lines · On Monday 09 November 2015 14:10:22 Stefano Stabellini wrote:
Quoted 8 lines · Arnd Bergmann

arch/arm/xen/enlighten.c static void xen_read_wallclock(struct timespec *ts) · line 136

Quoted 1 line · On Thursday 05 November 2015 17:09:45 Stefano Stabellini wrote:
arch/arm/xen/enlighten.c +1 -0
+	now = __current_kernel_time();

We don't have __current_kernel_time64() yet, but it is trivial to add, just follow the example of current_kernel_time()/current_kernel_time64() and convert the existing __current_kernel_time() function into a static inline wrapper for the new __current_kernel_time64().

Quoted 8 lines

All right. I guess something like:

struct timespec64 __current_kernel_time64(void)

{
	struct timekeeper *tk = &tk_core.timekeeper;

	return tk_xtime(tk);
}

Yes, exactly.

Just to make sure that this is actually the correct interface that you want to call:

__current_kernel_time{,64}() is the fastest interface we have to get an approximation of the current time, while ignoring all of the locking.

Quoted 6 lines
Quoted 3 lines

Is is possible that you instead want ktime_get_real_ts64(), which gives you the time as precise as the kernel knows it, but uses locking?

I am not 100% sure. Can I call ktime_get_real_ts64 from a pvclock_gtod notifier_call function?

It doesn't look like it: we would be getting the tk_core seqcount twice.

#23 lore raw

PATCH 3/3 xen/arm: set the system time in Xen via the XENPF_settime hypercall

Quoted 11 lines · On Monday 09 November 2015 17:42:50 Stefano Stabellini wrote:
Quoted 10 lines · Stefano Stabellini
Quoted 9 lines · Arnd Bergmann

On Monday 09 November 2015 14:10:22 Stefano Stabellini wrote:

Just to make sure that this is actually the correct interface that you want to call:

__current_kernel_time{,64}() is the fastest interface we have to get an approximation of the current time, while ignoring all of the locking.

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

Is is possible that you instead want ktime_get_real_ts64(), which gives you the time as precise as the kernel knows it, but uses locking?

I am not 100% sure. Can I call ktime_get_real_ts64 from a pvclock_gtod notifier_call function?

It doesn't look like it: we would be getting the tk_core seqcount twice.

Ok, I see. I'm still unsure what this is all good for, but at least this call appears to be safe.

Arnd