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