162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _ASM_X86_PVCLOCK_H 362306a36Sopenharmony_ci#define _ASM_X86_PVCLOCK_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <asm/barrier.h> 662306a36Sopenharmony_ci#include <asm/pvclock-abi.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* some helper functions for xen and kvm pv clock sources */ 962306a36Sopenharmony_ciu64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src); 1062306a36Sopenharmony_ciu8 pvclock_read_flags(struct pvclock_vcpu_time_info *src); 1162306a36Sopenharmony_civoid pvclock_set_flags(u8 flags); 1262306a36Sopenharmony_ciunsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src); 1362306a36Sopenharmony_civoid pvclock_resume(void); 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_civoid pvclock_touch_watchdogs(void); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic __always_inline 1862306a36Sopenharmony_ciunsigned pvclock_read_begin(const struct pvclock_vcpu_time_info *src) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci unsigned version = src->version & ~1; 2162306a36Sopenharmony_ci /* Make sure that the version is read before the data. */ 2262306a36Sopenharmony_ci rmb(); 2362306a36Sopenharmony_ci return version; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic __always_inline 2762306a36Sopenharmony_cibool pvclock_read_retry(const struct pvclock_vcpu_time_info *src, 2862306a36Sopenharmony_ci unsigned version) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci /* Make sure that the version is re-read after the data. */ 3162306a36Sopenharmony_ci rmb(); 3262306a36Sopenharmony_ci return version != src->version; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, 3762306a36Sopenharmony_ci * yielding a 64-bit result. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_cistatic inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci u64 product; 4262306a36Sopenharmony_ci#ifdef __i386__ 4362306a36Sopenharmony_ci u32 tmp1, tmp2; 4462306a36Sopenharmony_ci#else 4562306a36Sopenharmony_ci unsigned long tmp; 4662306a36Sopenharmony_ci#endif 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (shift < 0) 4962306a36Sopenharmony_ci delta >>= -shift; 5062306a36Sopenharmony_ci else 5162306a36Sopenharmony_ci delta <<= shift; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#ifdef __i386__ 5462306a36Sopenharmony_ci __asm__ ( 5562306a36Sopenharmony_ci "mul %5 ; " 5662306a36Sopenharmony_ci "mov %4,%%eax ; " 5762306a36Sopenharmony_ci "mov %%edx,%4 ; " 5862306a36Sopenharmony_ci "mul %5 ; " 5962306a36Sopenharmony_ci "xor %5,%5 ; " 6062306a36Sopenharmony_ci "add %4,%%eax ; " 6162306a36Sopenharmony_ci "adc %5,%%edx ; " 6262306a36Sopenharmony_ci : "=A" (product), "=r" (tmp1), "=r" (tmp2) 6362306a36Sopenharmony_ci : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) ); 6462306a36Sopenharmony_ci#elif defined(__x86_64__) 6562306a36Sopenharmony_ci __asm__ ( 6662306a36Sopenharmony_ci "mulq %[mul_frac] ; shrd $32, %[hi], %[lo]" 6762306a36Sopenharmony_ci : [lo]"=a"(product), 6862306a36Sopenharmony_ci [hi]"=d"(tmp) 6962306a36Sopenharmony_ci : "0"(delta), 7062306a36Sopenharmony_ci [mul_frac]"rm"((u64)mul_frac)); 7162306a36Sopenharmony_ci#else 7262306a36Sopenharmony_ci#error implement me! 7362306a36Sopenharmony_ci#endif 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return product; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic __always_inline 7962306a36Sopenharmony_ciu64 __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src, u64 tsc) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci u64 delta = tsc - src->tsc_timestamp; 8262306a36Sopenharmony_ci u64 offset = pvclock_scale_delta(delta, src->tsc_to_system_mul, 8362306a36Sopenharmony_ci src->tsc_shift); 8462306a36Sopenharmony_ci return src->system_time + offset; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistruct pvclock_vsyscall_time_info { 8862306a36Sopenharmony_ci struct pvclock_vcpu_time_info pvti; 8962306a36Sopenharmony_ci} __attribute__((__aligned__(64))); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#ifdef CONFIG_PARAVIRT_CLOCK 9462306a36Sopenharmony_civoid pvclock_set_pvti_cpu0_va(struct pvclock_vsyscall_time_info *pvti); 9562306a36Sopenharmony_cistruct pvclock_vsyscall_time_info *pvclock_get_pvti_cpu0_va(void); 9662306a36Sopenharmony_ci#else 9762306a36Sopenharmony_cistatic inline struct pvclock_vsyscall_time_info *pvclock_get_pvti_cpu0_va(void) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci return NULL; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci#endif 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#endif /* _ASM_X86_PVCLOCK_H */ 104