aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/hyperv_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource/hyperv_timer.c')
-rw-r--r--drivers/clocksource/hyperv_timer.c45
1 files changed, 16 insertions, 29 deletions
diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c
index ba2c79e6a0ee..2317d4e3daaf 100644
--- a/drivers/clocksource/hyperv_timer.c
+++ b/drivers/clocksource/hyperv_timer.c
@@ -22,6 +22,7 @@
22#include <asm/mshyperv.h> 22#include <asm/mshyperv.h>
23 23
24static struct clock_event_device __percpu *hv_clock_event; 24static struct clock_event_device __percpu *hv_clock_event;
25static u64 hv_sched_clock_offset __ro_after_init;
25 26
26/* 27/*
27 * If false, we're using the old mechanism for stimer0 interrupts 28 * If false, we're using the old mechanism for stimer0 interrupts
@@ -212,19 +213,17 @@ EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup);
212struct clocksource *hyperv_cs; 213struct clocksource *hyperv_cs;
213EXPORT_SYMBOL_GPL(hyperv_cs); 214EXPORT_SYMBOL_GPL(hyperv_cs);
214 215
215#ifdef CONFIG_HYPERV_TSCPAGE 216static struct ms_hyperv_tsc_page tsc_pg __aligned(PAGE_SIZE);
216
217static struct ms_hyperv_tsc_page *tsc_pg;
218 217
219struct ms_hyperv_tsc_page *hv_get_tsc_page(void) 218struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
220{ 219{
221 return tsc_pg; 220 return &tsc_pg;
222} 221}
223EXPORT_SYMBOL_GPL(hv_get_tsc_page); 222EXPORT_SYMBOL_GPL(hv_get_tsc_page);
224 223
225static u64 notrace read_hv_sched_clock_tsc(void) 224static u64 notrace read_hv_clock_tsc(struct clocksource *arg)
226{ 225{
227 u64 current_tick = hv_read_tsc_page(tsc_pg); 226 u64 current_tick = hv_read_tsc_page(&tsc_pg);
228 227
229 if (current_tick == U64_MAX) 228 if (current_tick == U64_MAX)
230 hv_get_time_ref_count(current_tick); 229 hv_get_time_ref_count(current_tick);
@@ -232,9 +231,9 @@ static u64 notrace read_hv_sched_clock_tsc(void)
232 return current_tick; 231 return current_tick;
233} 232}
234 233
235static u64 read_hv_clock_tsc(struct clocksource *arg) 234static u64 read_hv_sched_clock_tsc(void)
236{ 235{
237 return read_hv_sched_clock_tsc(); 236 return read_hv_clock_tsc(NULL) - hv_sched_clock_offset;
238} 237}
239 238
240static struct clocksource hyperv_cs_tsc = { 239static struct clocksource hyperv_cs_tsc = {
@@ -244,9 +243,8 @@ static struct clocksource hyperv_cs_tsc = {
244 .mask = CLOCKSOURCE_MASK(64), 243 .mask = CLOCKSOURCE_MASK(64),
245 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 244 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
246}; 245};
247#endif
248 246
249static u64 notrace read_hv_sched_clock_msr(void) 247static u64 notrace read_hv_clock_msr(struct clocksource *arg)
250{ 248{
251 u64 current_tick; 249 u64 current_tick;
252 /* 250 /*
@@ -258,9 +256,9 @@ static u64 notrace read_hv_sched_clock_msr(void)
258 return current_tick; 256 return current_tick;
259} 257}
260 258
261static u64 read_hv_clock_msr(struct clocksource *arg) 259static u64 read_hv_sched_clock_msr(void)
262{ 260{
263 return read_hv_sched_clock_msr(); 261 return read_hv_clock_msr(NULL) - hv_sched_clock_offset;
264} 262}
265 263
266static struct clocksource hyperv_cs_msr = { 264static struct clocksource hyperv_cs_msr = {
@@ -271,7 +269,6 @@ static struct clocksource hyperv_cs_msr = {
271 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 269 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
272}; 270};
273 271
274#ifdef CONFIG_HYPERV_TSCPAGE
275static bool __init hv_init_tsc_clocksource(void) 272static bool __init hv_init_tsc_clocksource(void)
276{ 273{
277 u64 tsc_msr; 274 u64 tsc_msr;
@@ -280,12 +277,8 @@ static bool __init hv_init_tsc_clocksource(void)
280 if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE)) 277 if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE))
281 return false; 278 return false;
282 279
283 tsc_pg = vmalloc(PAGE_SIZE);
284 if (!tsc_pg)
285 return false;
286
287 hyperv_cs = &hyperv_cs_tsc; 280 hyperv_cs = &hyperv_cs_tsc;
288 phys_addr = page_to_phys(vmalloc_to_page(tsc_pg)); 281 phys_addr = virt_to_phys(&tsc_pg);
289 282
290 /* 283 /*
291 * The Hyper-V TLFS specifies to preserve the value of reserved 284 * The Hyper-V TLFS specifies to preserve the value of reserved
@@ -302,17 +295,11 @@ static bool __init hv_init_tsc_clocksource(void)
302 hv_set_clocksource_vdso(hyperv_cs_tsc); 295 hv_set_clocksource_vdso(hyperv_cs_tsc);
303 clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100); 296 clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
304 297
305 /* sched_clock_register is needed on ARM64 but is a no-op on x86 */ 298 hv_sched_clock_offset = hyperv_cs->read(hyperv_cs);
306 sched_clock_register(read_hv_sched_clock_tsc, 64, HV_CLOCK_HZ); 299 hv_setup_sched_clock(read_hv_sched_clock_tsc);
300
307 return true; 301 return true;
308} 302}
309#else
310static bool __init hv_init_tsc_clocksource(void)
311{
312 return false;
313}
314#endif
315
316 303
317void __init hv_init_clocksource(void) 304void __init hv_init_clocksource(void)
318{ 305{
@@ -333,7 +320,7 @@ void __init hv_init_clocksource(void)
333 hyperv_cs = &hyperv_cs_msr; 320 hyperv_cs = &hyperv_cs_msr;
334 clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100); 321 clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
335 322
336 /* sched_clock_register is needed on ARM64 but is a no-op on x86 */ 323 hv_sched_clock_offset = hyperv_cs->read(hyperv_cs);
337 sched_clock_register(read_hv_sched_clock_msr, 64, HV_CLOCK_HZ); 324 hv_setup_sched_clock(read_hv_sched_clock_msr);
338} 325}
339EXPORT_SYMBOL_GPL(hv_init_clocksource); 326EXPORT_SYMBOL_GPL(hv_init_clocksource);