1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/percpu.h>
15#include <linux/cpumask.h>
16#include <linux/clockchips.h>
17#include <linux/clocksource.h>
18#include <linux/sched_clock.h>
19#include <linux/mm.h>
20#include <linux/cpuhotplug.h>
21#include <clocksource/hyperv_timer.h>
22#include <asm/hyperv-tlfs.h>
23#include <asm/mshyperv.h>
24
25static struct clock_event_device __percpu *hv_clock_event;
26static u64 hv_sched_clock_offset __ro_after_init;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44static bool direct_mode_enabled;
45
46static int stimer0_irq;
47static int stimer0_vector;
48static int stimer0_message_sint;
49
50
51
52
53
54
55void hv_stimer0_isr(void)
56{
57 struct clock_event_device *ce;
58
59 ce = this_cpu_ptr(hv_clock_event);
60 ce->event_handler(ce);
61}
62EXPORT_SYMBOL_GPL(hv_stimer0_isr);
63
64static int hv_ce_set_next_event(unsigned long delta,
65 struct clock_event_device *evt)
66{
67 u64 current_tick;
68
69 current_tick = hv_read_reference_counter();
70 current_tick += delta;
71 hv_init_timer(0, current_tick);
72 return 0;
73}
74
75static int hv_ce_shutdown(struct clock_event_device *evt)
76{
77 hv_init_timer(0, 0);
78 hv_init_timer_config(0, 0);
79 if (direct_mode_enabled)
80 hv_disable_stimer0_percpu_irq(stimer0_irq);
81
82 return 0;
83}
84
85static int hv_ce_set_oneshot(struct clock_event_device *evt)
86{
87 union hv_stimer_config timer_cfg;
88
89 timer_cfg.as_uint64 = 0;
90 timer_cfg.enable = 1;
91 timer_cfg.auto_enable = 1;
92 if (direct_mode_enabled) {
93
94
95
96
97 timer_cfg.direct_mode = 1;
98 timer_cfg.apic_vector = stimer0_vector;
99 hv_enable_stimer0_percpu_irq(stimer0_irq);
100 } else {
101
102
103
104
105 timer_cfg.direct_mode = 0;
106 timer_cfg.sintx = stimer0_message_sint;
107 }
108 hv_init_timer_config(0, timer_cfg.as_uint64);
109 return 0;
110}
111
112
113
114
115static int hv_stimer_init(unsigned int cpu)
116{
117 struct clock_event_device *ce;
118
119 if (!hv_clock_event)
120 return 0;
121
122 ce = per_cpu_ptr(hv_clock_event, cpu);
123 ce->name = "Hyper-V clockevent";
124 ce->features = CLOCK_EVT_FEAT_ONESHOT;
125 ce->cpumask = cpumask_of(cpu);
126 ce->rating = 1000;
127 ce->set_state_shutdown = hv_ce_shutdown;
128 ce->set_state_oneshot = hv_ce_set_oneshot;
129 ce->set_next_event = hv_ce_set_next_event;
130
131 clockevents_config_and_register(ce,
132 HV_CLOCK_HZ,
133 HV_MIN_DELTA_TICKS,
134 HV_MAX_MAX_DELTA_TICKS);
135 return 0;
136}
137
138
139
140
141int hv_stimer_cleanup(unsigned int cpu)
142{
143 struct clock_event_device *ce;
144
145 if (!hv_clock_event)
146 return 0;
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162 ce = per_cpu_ptr(hv_clock_event, cpu);
163 if (direct_mode_enabled)
164 hv_ce_shutdown(ce);
165 else
166 clockevents_unbind_device(ce, cpu);
167
168 return 0;
169}
170EXPORT_SYMBOL_GPL(hv_stimer_cleanup);
171
172
173int hv_stimer_alloc(void)
174{
175 int ret = 0;
176
177
178
179
180
181
182 if (!(ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE))
183 return -EINVAL;
184
185 hv_clock_event = alloc_percpu(struct clock_event_device);
186 if (!hv_clock_event)
187 return -ENOMEM;
188
189 direct_mode_enabled = ms_hyperv.misc_features &
190 HV_STIMER_DIRECT_MODE_AVAILABLE;
191 if (direct_mode_enabled) {
192 ret = hv_setup_stimer0_irq(&stimer0_irq, &stimer0_vector,
193 hv_stimer0_isr);
194 if (ret)
195 goto free_percpu;
196
197
198
199
200
201
202 ret = cpuhp_setup_state(CPUHP_AP_HYPERV_TIMER_STARTING,
203 "clockevents/hyperv/stimer:starting",
204 hv_stimer_init, hv_stimer_cleanup);
205 if (ret < 0)
206 goto free_stimer0_irq;
207 }
208 return ret;
209
210free_stimer0_irq:
211 hv_remove_stimer0_irq(stimer0_irq);
212 stimer0_irq = 0;
213free_percpu:
214 free_percpu(hv_clock_event);
215 hv_clock_event = NULL;
216 return ret;
217}
218EXPORT_SYMBOL_GPL(hv_stimer_alloc);
219
220
221
222
223
224
225
226void hv_stimer_legacy_init(unsigned int cpu, int sint)
227{
228 if (direct_mode_enabled)
229 return;
230
231
232
233
234
235
236
237
238 stimer0_message_sint = sint;
239 (void)hv_stimer_init(cpu);
240}
241EXPORT_SYMBOL_GPL(hv_stimer_legacy_init);
242
243
244
245
246
247
248
249void hv_stimer_legacy_cleanup(unsigned int cpu)
250{
251 if (direct_mode_enabled)
252 return;
253 (void)hv_stimer_cleanup(cpu);
254}
255EXPORT_SYMBOL_GPL(hv_stimer_legacy_cleanup);
256
257
258
259void hv_stimer_free(void)
260{
261 if (!hv_clock_event)
262 return;
263
264 if (direct_mode_enabled) {
265 cpuhp_remove_state(CPUHP_AP_HYPERV_TIMER_STARTING);
266 hv_remove_stimer0_irq(stimer0_irq);
267 stimer0_irq = 0;
268 }
269 free_percpu(hv_clock_event);
270 hv_clock_event = NULL;
271}
272EXPORT_SYMBOL_GPL(hv_stimer_free);
273
274
275
276
277
278void hv_stimer_global_cleanup(void)
279{
280 int cpu;
281
282
283
284
285
286 for_each_present_cpu(cpu) {
287 hv_stimer_legacy_cleanup(cpu);
288 }
289
290
291
292
293
294
295 hv_stimer_free();
296}
297EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup);
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315u64 (*hv_read_reference_counter)(void);
316EXPORT_SYMBOL_GPL(hv_read_reference_counter);
317
318static union {
319 struct ms_hyperv_tsc_page page;
320 u8 reserved[PAGE_SIZE];
321} tsc_pg __aligned(PAGE_SIZE);
322
323struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
324{
325 return &tsc_pg.page;
326}
327EXPORT_SYMBOL_GPL(hv_get_tsc_page);
328
329static u64 notrace read_hv_clock_tsc(void)
330{
331 u64 current_tick = hv_read_tsc_page(hv_get_tsc_page());
332
333 if (current_tick == U64_MAX)
334 hv_get_time_ref_count(current_tick);
335
336 return current_tick;
337}
338
339static u64 notrace read_hv_clock_tsc_cs(struct clocksource *arg)
340{
341 return read_hv_clock_tsc();
342}
343
344static u64 read_hv_sched_clock_tsc(void)
345{
346 return (read_hv_clock_tsc() - hv_sched_clock_offset) *
347 (NSEC_PER_SEC / HV_CLOCK_HZ);
348}
349
350static void suspend_hv_clock_tsc(struct clocksource *arg)
351{
352 u64 tsc_msr;
353
354
355 hv_get_reference_tsc(tsc_msr);
356 tsc_msr &= ~BIT_ULL(0);
357 hv_set_reference_tsc(tsc_msr);
358}
359
360
361static void resume_hv_clock_tsc(struct clocksource *arg)
362{
363 phys_addr_t phys_addr = virt_to_phys(&tsc_pg);
364 u64 tsc_msr;
365
366
367 hv_get_reference_tsc(tsc_msr);
368 tsc_msr &= GENMASK_ULL(11, 0);
369 tsc_msr |= BIT_ULL(0) | (u64)phys_addr;
370 hv_set_reference_tsc(tsc_msr);
371}
372
373static int hv_cs_enable(struct clocksource *cs)
374{
375 hv_enable_vdso_clocksource();
376 return 0;
377}
378
379static struct clocksource hyperv_cs_tsc = {
380 .name = "hyperv_clocksource_tsc_page",
381 .rating = 250,
382 .read = read_hv_clock_tsc_cs,
383 .mask = CLOCKSOURCE_MASK(64),
384 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
385 .suspend= suspend_hv_clock_tsc,
386 .resume = resume_hv_clock_tsc,
387 .enable = hv_cs_enable,
388};
389
390static u64 notrace read_hv_clock_msr(void)
391{
392 u64 current_tick;
393
394
395
396
397
398 hv_get_time_ref_count(current_tick);
399 return current_tick;
400}
401
402static u64 notrace read_hv_clock_msr_cs(struct clocksource *arg)
403{
404 return read_hv_clock_msr();
405}
406
407static u64 read_hv_sched_clock_msr(void)
408{
409 return (read_hv_clock_msr() - hv_sched_clock_offset) *
410 (NSEC_PER_SEC / HV_CLOCK_HZ);
411}
412
413static struct clocksource hyperv_cs_msr = {
414 .name = "hyperv_clocksource_msr",
415 .rating = 250,
416 .read = read_hv_clock_msr_cs,
417 .mask = CLOCKSOURCE_MASK(64),
418 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
419};
420
421static bool __init hv_init_tsc_clocksource(void)
422{
423 u64 tsc_msr;
424 phys_addr_t phys_addr;
425
426 if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE))
427 return false;
428
429 hv_read_reference_counter = read_hv_clock_tsc;
430 phys_addr = virt_to_phys(hv_get_tsc_page());
431
432
433
434
435
436
437
438
439 hv_get_reference_tsc(tsc_msr);
440 tsc_msr &= GENMASK_ULL(11, 0);
441 tsc_msr = tsc_msr | 0x1 | (u64)phys_addr;
442 hv_set_reference_tsc(tsc_msr);
443
444 hv_set_clocksource_vdso(hyperv_cs_tsc);
445 clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
446
447 hv_sched_clock_offset = hv_read_reference_counter();
448 hv_setup_sched_clock(read_hv_sched_clock_tsc);
449
450 return true;
451}
452
453void __init hv_init_clocksource(void)
454{
455
456
457
458
459
460
461
462
463 if (hv_init_tsc_clocksource())
464 return;
465
466 if (!(ms_hyperv.features & HV_MSR_TIME_REF_COUNT_AVAILABLE))
467 return;
468
469 hv_read_reference_counter = read_hv_clock_msr;
470 clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
471
472 hv_sched_clock_offset = hv_read_reference_counter();
473 hv_setup_sched_clock(read_hv_sched_clock_msr);
474}
475EXPORT_SYMBOL_GPL(hv_init_clocksource);
476