1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _ASM_X86_PVCLOCK_H 3 #define _ASM_X86_PVCLOCK_H 4 5 #include <asm/barrier.h> 6 #include <asm/pvclock-abi.h> 7 8 /* some helper functions for xen and kvm pv clock sources */ 9 u64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src); 10 u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src); 11 void pvclock_set_flags(u8 flags); 12 unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src); 13 void pvclock_resume(void); 14 15 void pvclock_touch_watchdogs(void); 16 17 static __always_inline 18 unsigned pvclock_read_begin(const struct pvclock_vcpu_time_info *src) 19 { 20 unsigned version = src->version & ~1; 21 /* Make sure that the version is read before the data. */ 22 rmb(); 23 return version; 24 } 25 26 static __always_inline 27 bool pvclock_read_retry(const struct pvclock_vcpu_time_info *src, 28 unsigned version) 29 { 30 /* Make sure that the version is re-read after the data. */ 31 rmb(); 32 return version != src->version; 33 } 34 35 /* 36 * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, 37 * yielding a 64-bit result. 38 */ 39 static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift) 40 { 41 u64 product; 42 #ifdef __i386__ 43 u32 tmp1, tmp2; 44 #else 45 unsigned long tmp; 46 #endif 47 48 if (shift < 0) 49 delta >>= -shift; 50 else 51 delta <<= shift; 52 53 #ifdef __i386__ 54 __asm__ ( 55 "mul %5 ; " 56 "mov %4,%%eax ; " 57 "mov %%edx,%4 ; " 58 "mul %5 ; " 59 "xor %5,%5 ; " 60 "add %4,%%eax ; " 61 "adc %5,%%edx ; " 62 : "=A" (product), "=r" (tmp1), "=r" (tmp2) 63 : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) ); 64 #elif defined(__x86_64__) 65 __asm__ ( 66 "mulq %[mul_frac] ; shrd $32, %[hi], %[lo]" 67 : [lo]"=a"(product), 68 [hi]"=d"(tmp) 69 : "0"(delta), 70 [mul_frac]"rm"((u64)mul_frac)); 71 #else 72 #error implement me! 73 #endif 74 75 return product; 76 } 77 78 static __always_inline 79 u64 __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src, u64 tsc) 80 { 81 u64 delta = tsc - src->tsc_timestamp; 82 u64 offset = pvclock_scale_delta(delta, src->tsc_to_system_mul, 83 src->tsc_shift); 84 return src->system_time + offset; 85 } 86 87 struct pvclock_vsyscall_time_info { 88 struct pvclock_vcpu_time_info pvti; 89 } __attribute__((__aligned__(64))); 90 91 #define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info) 92 93 #ifdef CONFIG_PARAVIRT_CLOCK 94 void pvclock_set_pvti_cpu0_va(struct pvclock_vsyscall_time_info *pvti); 95 struct pvclock_vsyscall_time_info *pvclock_get_pvti_cpu0_va(void); 96 #else 97 static inline struct pvclock_vsyscall_time_info *pvclock_get_pvti_cpu0_va(void) 98 { 99 return NULL; 100 } 101 #endif 102 103 #endif /* _ASM_X86_PVCLOCK_H */ 104