SPECS/linux/06-pv-ops-boot_clock.patch
e7547e1f
 From b2ce2307e8547e420fcce9fbad46119814f7f810 Mon Sep 17 00:00:00 2001
 From: Alexey Makhalov <amakhalov@vmware.com>
 Date: Tue, 9 May 2017 12:39:57 -0700
 Subject: [PATCH] x86/vmware: pv-ops boot_clock
 
 ---
  arch/x86/include/asm/paravirt.h       |  5 +++++
  arch/x86/include/asm/paravirt_types.h |  5 +++++
  arch/x86/kernel/cpu/vmware.c          | 24 +++++++++++++++++++++++-
  arch/x86/kernel/head_64.S             |  8 ++++++++
  arch/x86/kernel/paravirt.c            |  7 +++++++
  arch/x86/kernel/setup.c               |  9 +++++++++
  6 files changed, 57 insertions(+), 1 deletion(-)
 
fc081194
 diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
e7547e1f
 index ce932812f142..3d4ba2a999cb 100644
fc081194
 --- a/arch/x86/include/asm/paravirt.h
 +++ b/arch/x86/include/asm/paravirt.h
 @@ -193,6 +193,11 @@ static inline u64 paravirt_steal_clock(int cpu)
  	return PVOP_CALL1(u64, pv_time_ops.steal_clock, cpu);
  }
  
 +static inline void paravirt_read_boot_clock64(struct timespec64 *ts)
 +{
 +	PVOP_VCALL1(pv_time_ops.read_boot_clock64, ts);
 +}
 +
  static inline unsigned long long paravirt_read_pmc(int counter)
  {
  	return PVOP_CALL1(u64, pv_cpu_ops.read_pmc, counter);
 diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
e7547e1f
 index 0f400c0e4979..5f09979f612d 100644
fc081194
 --- a/arch/x86/include/asm/paravirt_types.h
 +++ b/arch/x86/include/asm/paravirt_types.h
 @@ -51,6 +51,10 @@ struct mm_struct;
  struct desc_struct;
  struct task_struct;
  struct cpumask;
 +#if __BITS_PER_LONG == 64
 +# define timespec64 timespec
 +#endif
 +struct timespec64;
  
  /*
   * Wrapper type for pointers to code which uses the non-standard
 @@ -96,6 +100,7 @@ struct pv_lazy_ops {
  struct pv_time_ops {
  	unsigned long long (*sched_clock)(void);
  	unsigned long long (*steal_clock)(int cpu);
 +	void (*read_boot_clock64)(struct timespec64 *ts);
  };
  
  struct pv_cpu_ops {
 diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
e7547e1f
 index 987ac571d16c..0e1fc6e17efc 100644
fc081194
 --- a/arch/x86/kernel/cpu/vmware.c
 +++ b/arch/x86/kernel/cpu/vmware.c
 @@ -124,6 +124,7 @@ static struct kmsg_dumper kmsg_dumper = {
  #ifdef CONFIG_PARAVIRT
  static struct cyc2ns_data vmware_cyc2ns __ro_after_init;
  static int vmw_sched_clock __initdata = 1;
 +uint64_t __initdata tsc_at_head;
  
  static __init int setup_vmw_sched_clock(char *s)
  {
 @@ -145,7 +146,7 @@ static unsigned long long vmware_sched_clock(void)
  static void __init vmware_cyc2ns_setup(void)
  {
  	struct cyc2ns_data *d = &vmware_cyc2ns;
 -	unsigned long long tsc_now = rdtsc();
 +	unsigned long long tsc_now = tsc_at_head;
  
  	clocks_calc_mult_shift(&d->cyc2ns_mul, &d->cyc2ns_shift,
  			       vmware_tsc_khz, NSEC_PER_MSEC, 0);
 @@ -175,6 +176,26 @@ struct clocksource * __init clocksource_default_clock(void)
  	return &clocksource_vmware;
  }
  
 +/* Function to read the exact time the system has been started. It will be
 +   used as zero time for monotonic clock */
 +static void vmware_read_boot_clock64(struct timespec64 *ts)
 +{
 +	struct timespec64 now;
 +	u64 delta_nsec;
 +	u32 rem;
 +
 +	read_persistent_clock64(&now);
 +	delta_nsec = mul_u64_u32_shr(rdtsc(), vmware_cyc2ns.cyc2ns_mul,
 +			     vmware_cyc2ns.cyc2ns_shift);
 +	delta_nsec -= vmware_cyc2ns.cyc2ns_offset;
 +	ts->tv_sec = now.tv_sec - div_s64_rem(delta_nsec, NSEC_PER_SEC, &rem);
 +	ts->tv_nsec = now.tv_nsec - rem;
 +	while (unlikely(ts->tv_nsec < 0)) {
 +		ts->tv_sec--;
 +		ts->tv_nsec += NSEC_PER_SEC;
 +	}
 +}
 +
  static uint64_t vmware_steal_clock(int cpu)
  {
  	struct vmware_steal_time *steal;
 @@ -311,6 +332,7 @@ static void __init vmware_paravirt_ops_setup(void)
  #endif
  	}
  	clocksource_register_khz(&clocksource_vmware, vmware_tsc_khz);
 +	pv_time_ops.read_boot_clock64 = vmware_read_boot_clock64;
  }
  #else
  #define vmware_paravirt_ops_setup() do {} while (0)
 diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
e7547e1f
 index b4421cc191b0..f7b8017fa90a 100644
fc081194
 --- a/arch/x86/kernel/head_64.S
 +++ b/arch/x86/kernel/head_64.S
 @@ -184,6 +184,14 @@ ENTRY(secondary_startup_64)
  	 * after the boot processor executes this code.
  	 */
  
 +	/*
 +	 * Read a TSC value first
 +	 */
 +	rdtsc
 +	shl	$0x20, %rdx
 +	or	%rax, %rdx
 +	mov	%rdx, tsc_at_head(%rip)
 +
  	/* Sanitize CPU configuration */
  	call verify_cpu
  
 diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
e7547e1f
 index bbf3d5933eaa..10bbdb3e6651 100644
fc081194
 --- a/arch/x86/kernel/paravirt.c
 +++ b/arch/x86/kernel/paravirt.c
 @@ -203,6 +203,12 @@ static u64 native_steal_clock(int cpu)
  	return 0;
  }
  
 +static void native_read_boot_clock64(struct timespec64 *ts)
 +{
 +	ts->tv_sec = 0;
 +	ts->tv_nsec = 0;
 +}
 +
  /* These are in entry.S */
  extern void native_iret(void);
  extern void native_usergs_sysret64(void);
 @@ -310,6 +316,7 @@ struct pv_init_ops pv_init_ops = {
  struct pv_time_ops pv_time_ops = {
  	.sched_clock = native_sched_clock,
  	.steal_clock = native_steal_clock,
 +	.read_boot_clock64 = native_read_boot_clock64,
  };
  
  __visible struct pv_irq_ops pv_irq_ops = {
 diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
e7547e1f
 index 9c337b0e8ba7..67a42e58b118 100644
fc081194
 --- a/arch/x86/kernel/setup.c
 +++ b/arch/x86/kernel/setup.c
 @@ -1302,3 +1302,12 @@ void arch_show_smap(struct seq_file *m, struct vm_area_struct *vma)
  
  	seq_printf(m, "ProtectionKey:  %8u\n", vma_pkey(vma));
  }
 +
 +/* We need to define a real function for read_boot_clock64, to override the
 +   weak default version */
 +#ifdef CONFIG_PARAVIRT
 +void read_boot_clock64(struct timespec64 *ts)
 +{
 +	paravirt_read_boot_clock64(ts);
 +}
 +#endif
e7547e1f
 -- 
 2.11.0