diff options
Diffstat (limited to 'arch/x86/kernel/pvclock.c')
| -rw-r--r-- | arch/x86/kernel/pvclock.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c index f7fdd56bc0ab..f5bc40e1697e 100644 --- a/arch/x86/kernel/pvclock.c +++ b/arch/x86/kernel/pvclock.c | |||
| @@ -118,11 +118,14 @@ unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src) | |||
| 118 | return pv_tsc_khz; | 118 | return pv_tsc_khz; |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | static atomic64_t last_value = ATOMIC64_INIT(0); | ||
| 122 | |||
| 121 | cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) | 123 | cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) |
| 122 | { | 124 | { |
| 123 | struct pvclock_shadow_time shadow; | 125 | struct pvclock_shadow_time shadow; |
| 124 | unsigned version; | 126 | unsigned version; |
| 125 | cycle_t ret, offset; | 127 | cycle_t ret, offset; |
| 128 | u64 last; | ||
| 126 | 129 | ||
| 127 | do { | 130 | do { |
| 128 | version = pvclock_get_time_values(&shadow, src); | 131 | version = pvclock_get_time_values(&shadow, src); |
| @@ -132,6 +135,27 @@ cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) | |||
| 132 | barrier(); | 135 | barrier(); |
| 133 | } while (version != src->version); | 136 | } while (version != src->version); |
| 134 | 137 | ||
| 138 | /* | ||
| 139 | * Assumption here is that last_value, a global accumulator, always goes | ||
| 140 | * forward. If we are less than that, we should not be much smaller. | ||
| 141 | * We assume there is an error marging we're inside, and then the correction | ||
| 142 | * does not sacrifice accuracy. | ||
| 143 | * | ||
| 144 | * For reads: global may have changed between test and return, | ||
| 145 | * but this means someone else updated poked the clock at a later time. | ||
| 146 | * We just need to make sure we are not seeing a backwards event. | ||
| 147 | * | ||
| 148 | * For updates: last_value = ret is not enough, since two vcpus could be | ||
| 149 | * updating at the same time, and one of them could be slightly behind, | ||
| 150 | * making the assumption that last_value always go forward fail to hold. | ||
| 151 | */ | ||
| 152 | last = atomic64_read(&last_value); | ||
| 153 | do { | ||
| 154 | if (ret < last) | ||
| 155 | return last; | ||
| 156 | last = atomic64_cmpxchg(&last_value, last, ret); | ||
| 157 | } while (unlikely(last != ret)); | ||
| 158 | |||
| 135 | return ret; | 159 | return ret; |
| 136 | } | 160 | } |
| 137 | 161 | ||
