1 /* SPDX-License-Identifier: GPL-2.0-only */
2 #ifndef X86_TSC_H
3 #define X86_TSC_H
4 
5 #include <asm/alternative.h>
6 
rdtsc(void)7 static inline uint64_t rdtsc(void)
8 {
9     uint64_t low, high;
10 
11     asm volatile ( "rdtsc" : "=a" (low), "=d" (high) );
12 
13     return (high << 32) | low;
14 }
15 
rdtsc_ordered(void)16 static inline uint64_t rdtsc_ordered(void)
17 {
18     uint64_t low, high, aux;
19 
20     /*
21      * The RDTSC instruction is not serializing.  Make it dispatch serializing
22      * for the purposes here by issuing LFENCE (or MFENCE if necessary) ahead
23      * of it.
24      *
25      * RDTSCP, otoh, "does wait until all previous instructions have executed
26      * and all previous loads are globally visible" (SDM) / "forces all older
27      * instructions to retire before reading the timestamp counter" (APM).
28      */
29     alternative_io_2("lfence; rdtsc",
30                      "mfence; rdtsc", X86_FEATURE_MFENCE_RDTSC,
31                      "rdtscp",        X86_FEATURE_RDTSCP,
32                      ASM_OUTPUT2("=a" (low), "=d" (high), "=c" (aux)),
33                      /* no inputs */);
34 
35     return (high << 32) | low;
36 }
37 
38 #define __write_tsc(val) wrmsrl(MSR_IA32_TSC, val)
39 
40 /*
41  * Reliable TSCs are in lockstep across all CPUs. We should never write to
42  * them.
43  */
44 #define write_tsc(val) ({                                       \
45     ASSERT(!boot_cpu_has(X86_FEATURE_TSC_RELIABLE));            \
46     __write_tsc(val);                                           \
47 })
48 
49 #endif /* X86_TSC_H */
50