1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/kernel.h>
19#include <linux/percpu.h>
20#include <linux/notifier.h>
21#include <linux/sched.h>
22#include <linux/gfp.h>
23#include <linux/bootmem.h>
24#include <linux/nmi.h>
25
26#include <asm/fixmap.h>
27#include <asm/pvclock.h>
28
29static u8 valid_flags __read_mostly = 0;
30
31void pvclock_set_flags(u8 flags)
32{
33 valid_flags = flags;
34}
35
36unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src)
37{
38 u64 pv_tsc_khz = 1000000ULL << 32;
39
40 do_div(pv_tsc_khz, src->tsc_to_system_mul);
41 if (src->tsc_shift < 0)
42 pv_tsc_khz <<= -src->tsc_shift;
43 else
44 pv_tsc_khz >>= src->tsc_shift;
45 return pv_tsc_khz;
46}
47
48void pvclock_touch_watchdogs(void)
49{
50 touch_softlockup_watchdog_sync();
51 clocksource_touch_watchdog();
52 rcu_cpu_stall_reset();
53 reset_hung_task_detector();
54}
55
56static atomic64_t last_value = ATOMIC64_INIT(0);
57
58void pvclock_resume(void)
59{
60 atomic64_set(&last_value, 0);
61}
62
63u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src)
64{
65 unsigned version;
66 u8 flags;
67
68 do {
69 version = pvclock_read_begin(src);
70 flags = src->flags;
71 } while (pvclock_read_retry(src, version));
72
73 return flags & valid_flags;
74}
75
76u64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
77{
78 unsigned version;
79 u64 ret;
80 u64 last;
81 u8 flags;
82
83 do {
84 version = pvclock_read_begin(src);
85 ret = __pvclock_read_cycles(src, rdtsc_ordered());
86 flags = src->flags;
87 } while (pvclock_read_retry(src, version));
88
89 if (unlikely((flags & PVCLOCK_GUEST_STOPPED) != 0)) {
90 src->flags &= ~PVCLOCK_GUEST_STOPPED;
91 pvclock_touch_watchdogs();
92 }
93
94 if ((valid_flags & PVCLOCK_TSC_STABLE_BIT) &&
95 (flags & PVCLOCK_TSC_STABLE_BIT))
96 return ret;
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 last = atomic64_read(&last_value);
113 do {
114 if (ret < last)
115 return last;
116 last = atomic64_cmpxchg(&last_value, last, ret);
117 } while (unlikely(last != ret));
118
119 return ret;
120}
121
122void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
123 struct pvclock_vcpu_time_info *vcpu_time,
124 struct timespec *ts)
125{
126 u32 version;
127 u64 delta;
128 struct timespec now;
129
130
131 do {
132 version = wall_clock->version;
133 rmb();
134 now.tv_sec = wall_clock->sec;
135 now.tv_nsec = wall_clock->nsec;
136 rmb();
137 } while ((wall_clock->version & 1) || (version != wall_clock->version));
138
139 delta = pvclock_clocksource_read(vcpu_time);
140 delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;
141
142 now.tv_nsec = do_div(delta, NSEC_PER_SEC);
143 now.tv_sec = delta;
144
145 set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
146}
147