.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* KVM paravirtual clock driver. A clocksource implementation |
---|
2 | 3 | Copyright (C) 2008 Glauber de Oliveira Costa, Red Hat Inc. |
---|
3 | | - |
---|
4 | | - This program is free software; you can redistribute it and/or modify |
---|
5 | | - it under the terms of the GNU General Public License as published by |
---|
6 | | - the Free Software Foundation; either version 2 of the License, or |
---|
7 | | - (at your option) any later version. |
---|
8 | | - |
---|
9 | | - This program is distributed in the hope that it will be useful, |
---|
10 | | - but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
12 | | - GNU General Public License for more details. |
---|
13 | | - |
---|
14 | | - You should have received a copy of the GNU General Public License |
---|
15 | | - along with this program; if not, write to the Free Software |
---|
16 | | - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
---|
17 | 4 | */ |
---|
18 | 5 | |
---|
19 | 6 | #include <linux/clocksource.h> |
---|
.. | .. |
---|
33 | 20 | #include <asm/hypervisor.h> |
---|
34 | 21 | #include <asm/mem_encrypt.h> |
---|
35 | 22 | #include <asm/x86_init.h> |
---|
36 | | -#include <asm/reboot.h> |
---|
37 | 23 | #include <asm/kvmclock.h> |
---|
38 | 24 | |
---|
39 | 25 | static int kvmclock __initdata = 1; |
---|
.. | .. |
---|
111 | 97 | if (!stable) |
---|
112 | 98 | clear_sched_clock_stable(); |
---|
113 | 99 | kvm_sched_clock_offset = kvm_clock_read(); |
---|
114 | | - pv_time_ops.sched_clock = kvm_sched_clock_read; |
---|
| 100 | + pv_ops.time.sched_clock = kvm_sched_clock_read; |
---|
115 | 101 | |
---|
116 | 102 | pr_info("kvm-clock: using sched offset of %llu cycles", |
---|
117 | 103 | kvm_sched_clock_offset); |
---|
.. | .. |
---|
163 | 149 | return ret; |
---|
164 | 150 | } |
---|
165 | 151 | |
---|
| 152 | +static int kvm_cs_enable(struct clocksource *cs) |
---|
| 153 | +{ |
---|
| 154 | + vclocks_set_used(VDSO_CLOCKMODE_PVCLOCK); |
---|
| 155 | + return 0; |
---|
| 156 | +} |
---|
| 157 | + |
---|
166 | 158 | struct clocksource kvm_clock = { |
---|
167 | 159 | .name = "kvm-clock", |
---|
168 | 160 | .read = kvm_clock_get_cycles, |
---|
169 | 161 | .rating = 400, |
---|
170 | 162 | .mask = CLOCKSOURCE_MASK(64), |
---|
171 | 163 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
---|
| 164 | + .enable = kvm_cs_enable, |
---|
172 | 165 | }; |
---|
173 | 166 | EXPORT_SYMBOL_GPL(kvm_clock); |
---|
174 | 167 | |
---|
.. | .. |
---|
201 | 194 | } |
---|
202 | 195 | #endif |
---|
203 | 196 | |
---|
204 | | -/* |
---|
205 | | - * After the clock is registered, the host will keep writing to the |
---|
206 | | - * registered memory location. If the guest happens to shutdown, this memory |
---|
207 | | - * won't be valid. In cases like kexec, in which you install a new kernel, this |
---|
208 | | - * means a random memory location will be kept being written. So before any |
---|
209 | | - * kind of shutdown from our side, we unregister the clock by writing anything |
---|
210 | | - * that does not have the 'enable' bit set in the msr |
---|
211 | | - */ |
---|
212 | | -#ifdef CONFIG_KEXEC_CORE |
---|
213 | | -static void kvm_crash_shutdown(struct pt_regs *regs) |
---|
| 197 | +void kvmclock_disable(void) |
---|
214 | 198 | { |
---|
215 | 199 | native_write_msr(msr_kvm_system_time, 0, 0); |
---|
216 | | - kvm_disable_steal_time(); |
---|
217 | | - native_machine_crash_shutdown(regs); |
---|
218 | | -} |
---|
219 | | -#endif |
---|
220 | | - |
---|
221 | | -static void kvm_shutdown(void) |
---|
222 | | -{ |
---|
223 | | - native_write_msr(msr_kvm_system_time, 0, 0); |
---|
224 | | - kvm_disable_steal_time(); |
---|
225 | | - native_machine_shutdown(); |
---|
226 | 200 | } |
---|
227 | 201 | |
---|
228 | 202 | static void __init kvmclock_init_mem(void) |
---|
.. | .. |
---|
266 | 240 | |
---|
267 | 241 | static int __init kvm_setup_vsyscall_timeinfo(void) |
---|
268 | 242 | { |
---|
269 | | -#ifdef CONFIG_X86_64 |
---|
270 | | - u8 flags; |
---|
271 | | - |
---|
272 | | - if (!per_cpu(hv_clock_per_cpu, 0) || !kvmclock_vsyscall) |
---|
273 | | - return 0; |
---|
274 | | - |
---|
275 | | - flags = pvclock_read_flags(&hv_clock_boot[0].pvti); |
---|
276 | | - if (!(flags & PVCLOCK_TSC_STABLE_BIT)) |
---|
277 | | - return 0; |
---|
278 | | - |
---|
279 | | - kvm_clock.archdata.vclock_mode = VCLOCK_PVCLOCK; |
---|
280 | | -#endif |
---|
281 | | - |
---|
282 | 243 | kvmclock_init_mem(); |
---|
| 244 | + |
---|
| 245 | +#ifdef CONFIG_X86_64 |
---|
| 246 | + if (per_cpu(hv_clock_per_cpu, 0) && kvmclock_vsyscall) { |
---|
| 247 | + u8 flags; |
---|
| 248 | + |
---|
| 249 | + flags = pvclock_read_flags(&hv_clock_boot[0].pvti); |
---|
| 250 | + if (!(flags & PVCLOCK_TSC_STABLE_BIT)) |
---|
| 251 | + return 0; |
---|
| 252 | + |
---|
| 253 | + kvm_clock.vdso_clock_mode = VDSO_CLOCKMODE_PVCLOCK; |
---|
| 254 | + } |
---|
| 255 | +#endif |
---|
283 | 256 | |
---|
284 | 257 | return 0; |
---|
285 | 258 | } |
---|
.. | .. |
---|
350 | 323 | #endif |
---|
351 | 324 | x86_platform.save_sched_clock_state = kvm_save_sched_clock_state; |
---|
352 | 325 | x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state; |
---|
353 | | - machine_ops.shutdown = kvm_shutdown; |
---|
354 | | -#ifdef CONFIG_KEXEC_CORE |
---|
355 | | - machine_ops.crash_shutdown = kvm_crash_shutdown; |
---|
356 | | -#endif |
---|
357 | 326 | kvm_get_preset_lpj(); |
---|
| 327 | + |
---|
| 328 | + /* |
---|
| 329 | + * X86_FEATURE_NONSTOP_TSC is TSC runs at constant rate |
---|
| 330 | + * with P/T states and does not stop in deep C-states. |
---|
| 331 | + * |
---|
| 332 | + * Invariant TSC exposed by host means kvmclock is not necessary: |
---|
| 333 | + * can use TSC as clocksource. |
---|
| 334 | + * |
---|
| 335 | + */ |
---|
| 336 | + if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && |
---|
| 337 | + boot_cpu_has(X86_FEATURE_NONSTOP_TSC) && |
---|
| 338 | + !check_tsc_unstable()) |
---|
| 339 | + kvm_clock.rating = 299; |
---|
| 340 | + |
---|
358 | 341 | clocksource_register_hz(&kvm_clock, NSEC_PER_SEC); |
---|
359 | 342 | pv_info.name = "KVM"; |
---|
360 | 343 | } |
---|