18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_PVCLOCK_H 38c2ecf20Sopenharmony_ci#define _ASM_X86_PVCLOCK_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <asm/clocksource.h> 68c2ecf20Sopenharmony_ci#include <asm/pvclock-abi.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* some helper functions for xen and kvm pv clock sources */ 98c2ecf20Sopenharmony_ciu64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src); 108c2ecf20Sopenharmony_ciu8 pvclock_read_flags(struct pvclock_vcpu_time_info *src); 118c2ecf20Sopenharmony_civoid pvclock_set_flags(u8 flags); 128c2ecf20Sopenharmony_ciunsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src); 138c2ecf20Sopenharmony_civoid pvclock_read_wallclock(struct pvclock_wall_clock *wall, 148c2ecf20Sopenharmony_ci struct pvclock_vcpu_time_info *vcpu, 158c2ecf20Sopenharmony_ci struct timespec64 *ts); 168c2ecf20Sopenharmony_civoid pvclock_resume(void); 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_civoid pvclock_touch_watchdogs(void); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic __always_inline 218c2ecf20Sopenharmony_ciunsigned pvclock_read_begin(const struct pvclock_vcpu_time_info *src) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci unsigned version = src->version & ~1; 248c2ecf20Sopenharmony_ci /* Make sure that the version is read before the data. */ 258c2ecf20Sopenharmony_ci virt_rmb(); 268c2ecf20Sopenharmony_ci return version; 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic __always_inline 308c2ecf20Sopenharmony_cibool pvclock_read_retry(const struct pvclock_vcpu_time_info *src, 318c2ecf20Sopenharmony_ci unsigned version) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci /* Make sure that the version is re-read after the data. */ 348c2ecf20Sopenharmony_ci virt_rmb(); 358c2ecf20Sopenharmony_ci return unlikely(version != src->version); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, 408c2ecf20Sopenharmony_ci * yielding a 64-bit result. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_cistatic inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci u64 product; 458c2ecf20Sopenharmony_ci#ifdef __i386__ 468c2ecf20Sopenharmony_ci u32 tmp1, tmp2; 478c2ecf20Sopenharmony_ci#else 488c2ecf20Sopenharmony_ci ulong tmp; 498c2ecf20Sopenharmony_ci#endif 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (shift < 0) 528c2ecf20Sopenharmony_ci delta >>= -shift; 538c2ecf20Sopenharmony_ci else 548c2ecf20Sopenharmony_ci delta <<= shift; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#ifdef __i386__ 578c2ecf20Sopenharmony_ci __asm__ ( 588c2ecf20Sopenharmony_ci "mul %5 ; " 598c2ecf20Sopenharmony_ci "mov %4,%%eax ; " 608c2ecf20Sopenharmony_ci "mov %%edx,%4 ; " 618c2ecf20Sopenharmony_ci "mul %5 ; " 628c2ecf20Sopenharmony_ci "xor %5,%5 ; " 638c2ecf20Sopenharmony_ci "add %4,%%eax ; " 648c2ecf20Sopenharmony_ci "adc %5,%%edx ; " 658c2ecf20Sopenharmony_ci : "=A" (product), "=r" (tmp1), "=r" (tmp2) 668c2ecf20Sopenharmony_ci : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) ); 678c2ecf20Sopenharmony_ci#elif defined(__x86_64__) 688c2ecf20Sopenharmony_ci __asm__ ( 698c2ecf20Sopenharmony_ci "mulq %[mul_frac] ; shrd $32, %[hi], %[lo]" 708c2ecf20Sopenharmony_ci : [lo]"=a"(product), 718c2ecf20Sopenharmony_ci [hi]"=d"(tmp) 728c2ecf20Sopenharmony_ci : "0"(delta), 738c2ecf20Sopenharmony_ci [mul_frac]"rm"((u64)mul_frac)); 748c2ecf20Sopenharmony_ci#else 758c2ecf20Sopenharmony_ci#error implement me! 768c2ecf20Sopenharmony_ci#endif 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return product; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic __always_inline 828c2ecf20Sopenharmony_ciu64 __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src, u64 tsc) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci u64 delta = tsc - src->tsc_timestamp; 858c2ecf20Sopenharmony_ci u64 offset = pvclock_scale_delta(delta, src->tsc_to_system_mul, 868c2ecf20Sopenharmony_ci src->tsc_shift); 878c2ecf20Sopenharmony_ci return src->system_time + offset; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistruct pvclock_vsyscall_time_info { 918c2ecf20Sopenharmony_ci struct pvclock_vcpu_time_info pvti; 928c2ecf20Sopenharmony_ci} __attribute__((__aligned__(SMP_CACHE_BYTES))); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info) 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT_CLOCK 978c2ecf20Sopenharmony_civoid pvclock_set_pvti_cpu0_va(struct pvclock_vsyscall_time_info *pvti); 988c2ecf20Sopenharmony_cistruct pvclock_vsyscall_time_info *pvclock_get_pvti_cpu0_va(void); 998c2ecf20Sopenharmony_ci#else 1008c2ecf20Sopenharmony_cistatic inline struct pvclock_vsyscall_time_info *pvclock_get_pvti_cpu0_va(void) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci return NULL; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci#endif 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#endif /* _ASM_X86_PVCLOCK_H */ 107