Skip to content

Commit 63ed4e0

Browse files
kattisrinivasangregkh
authored andcommitted
Drivers: hv: vmbus: Consolidate all Hyper-V specific clocksource code
As part of the effort to separate out architecture specific code, consolidate all Hyper-V specific clocksource code to an architecture specific code. Signed-off-by: K. Y. Srinivasan <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 669c256 commit 63ed4e0

File tree

5 files changed

+117
-126
lines changed

5 files changed

+117
-126
lines changed

arch/x86/hyperv/hv_init.c

+105
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,87 @@
2424
#include <linux/version.h>
2525
#include <linux/vmalloc.h>
2626
#include <linux/mm.h>
27+
#include <linux/clockchips.h>
28+
29+
30+
#ifdef CONFIG_X86_64
31+
32+
static struct ms_hyperv_tsc_page *tsc_pg;
33+
34+
static u64 read_hv_clock_tsc(struct clocksource *arg)
35+
{
36+
u64 current_tick;
37+
38+
if (tsc_pg->tsc_sequence != 0) {
39+
/*
40+
* Use the tsc page to compute the value.
41+
*/
42+
43+
while (1) {
44+
u64 tmp;
45+
u32 sequence = tsc_pg->tsc_sequence;
46+
u64 cur_tsc;
47+
u64 scale = tsc_pg->tsc_scale;
48+
s64 offset = tsc_pg->tsc_offset;
49+
50+
rdtscll(cur_tsc);
51+
/* current_tick = ((cur_tsc *scale) >> 64) + offset */
52+
asm("mulq %3"
53+
: "=d" (current_tick), "=a" (tmp)
54+
: "a" (cur_tsc), "r" (scale));
55+
56+
current_tick += offset;
57+
if (tsc_pg->tsc_sequence == sequence)
58+
return current_tick;
59+
60+
if (tsc_pg->tsc_sequence != 0)
61+
continue;
62+
/*
63+
* Fallback using MSR method.
64+
*/
65+
break;
66+
}
67+
}
68+
rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
69+
return current_tick;
70+
}
71+
72+
static struct clocksource hyperv_cs_tsc = {
73+
.name = "hyperv_clocksource_tsc_page",
74+
.rating = 400,
75+
.read = read_hv_clock_tsc,
76+
.mask = CLOCKSOURCE_MASK(64),
77+
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
78+
};
79+
#endif
80+
81+
static u64 read_hv_clock_msr(struct clocksource *arg)
82+
{
83+
u64 current_tick;
84+
/*
85+
* Read the partition counter to get the current tick count. This count
86+
* is set to 0 when the partition is created and is incremented in
87+
* 100 nanosecond units.
88+
*/
89+
rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
90+
return current_tick;
91+
}
92+
93+
static struct clocksource hyperv_cs_msr = {
94+
.name = "hyperv_clocksource_msr",
95+
.rating = 400,
96+
.read = read_hv_clock_msr,
97+
.mask = CLOCKSOURCE_MASK(64),
98+
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
99+
};
27100

28101
static void *hypercall_pg;
29102
/*
30103
* This function is to be invoked early in the boot sequence after the
31104
* hypervisor has been detected.
32105
*
33106
* 1. Setup the hypercall page.
107+
* 2. Register Hyper-V specific clocksource.
34108
*/
35109
void hyperv_init(void)
36110
{
@@ -58,6 +132,37 @@ void hyperv_init(void)
58132
hypercall_msr.enable = 1;
59133
hypercall_msr.guest_physical_address = vmalloc_to_pfn(hypercall_pg);
60134
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
135+
136+
/*
137+
* Register Hyper-V specific clocksource.
138+
*/
139+
#ifdef CONFIG_X86_64
140+
if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
141+
union hv_x64_msr_hypercall_contents tsc_msr;
142+
143+
tsc_pg = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
144+
if (!tsc_pg) {
145+
clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
146+
return;
147+
}
148+
149+
rdmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
150+
151+
tsc_msr.enable = 1;
152+
tsc_msr.guest_physical_address = vmalloc_to_pfn(tsc_pg);
153+
154+
wrmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
155+
clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
156+
return;
157+
}
158+
#endif
159+
/*
160+
* For 32 bit guests just use the MSR based mechanism for reading
161+
* the partition counter.
162+
*/
163+
164+
if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
165+
clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
61166
}
62167

63168
/*

arch/x86/include/asm/mshyperv.h

+12
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ union hv_x64_msr_hypercall_contents {
2525
};
2626
};
2727

28+
/*
29+
* TSC page layout.
30+
*/
31+
32+
struct ms_hyperv_tsc_page {
33+
volatile u32 tsc_sequence;
34+
u32 reserved1;
35+
volatile u64 tsc_scale;
36+
volatile s64 tsc_offset;
37+
u64 reserved2[509];
38+
};
39+
2840
/*
2941
* The guest OS needs to register the guest ID with the hypervisor.
3042
* The guest ID is a 64 bit entity and the structure of this ID is

arch/x86/kernel/cpu/mshyperv.c

-23
Original file line numberDiff line numberDiff line change
@@ -133,26 +133,6 @@ static uint32_t __init ms_hyperv_platform(void)
133133
return 0;
134134
}
135135

136-
static u64 read_hv_clock(struct clocksource *arg)
137-
{
138-
u64 current_tick;
139-
/*
140-
* Read the partition counter to get the current tick count. This count
141-
* is set to 0 when the partition is created and is incremented in
142-
* 100 nanosecond units.
143-
*/
144-
rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
145-
return current_tick;
146-
}
147-
148-
static struct clocksource hyperv_cs = {
149-
.name = "hyperv_clocksource",
150-
.rating = 400, /* use this when running on Hyperv*/
151-
.read = read_hv_clock,
152-
.mask = CLOCKSOURCE_MASK(64),
153-
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
154-
};
155-
156136
static unsigned char hv_get_nmi_reason(void)
157137
{
158138
return 0;
@@ -208,9 +188,6 @@ static void __init ms_hyperv_init_platform(void)
208188
"hv_nmi_unknown");
209189
#endif
210190

211-
if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
212-
clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
213-
214191
#ifdef CONFIG_X86_IO_APIC
215192
no_timer_check = 1;
216193
#endif

drivers/hv/hv.c

-95
Original file line numberDiff line numberDiff line change
@@ -87,56 +87,6 @@ static int query_hypervisor_info(void)
8787
return max_leaf;
8888
}
8989

90-
#ifdef CONFIG_X86_64
91-
static u64 read_hv_clock_tsc(struct clocksource *arg)
92-
{
93-
u64 current_tick;
94-
struct ms_hyperv_tsc_page *tsc_pg = hv_context.tsc_page;
95-
96-
if (tsc_pg->tsc_sequence != 0) {
97-
/*
98-
* Use the tsc page to compute the value.
99-
*/
100-
101-
while (1) {
102-
u64 tmp;
103-
u32 sequence = tsc_pg->tsc_sequence;
104-
u64 cur_tsc;
105-
u64 scale = tsc_pg->tsc_scale;
106-
s64 offset = tsc_pg->tsc_offset;
107-
108-
rdtscll(cur_tsc);
109-
/* current_tick = ((cur_tsc *scale) >> 64) + offset */
110-
asm("mulq %3"
111-
: "=d" (current_tick), "=a" (tmp)
112-
: "a" (cur_tsc), "r" (scale));
113-
114-
current_tick += offset;
115-
if (tsc_pg->tsc_sequence == sequence)
116-
return current_tick;
117-
118-
if (tsc_pg->tsc_sequence != 0)
119-
continue;
120-
/*
121-
* Fallback using MSR method.
122-
*/
123-
break;
124-
}
125-
}
126-
rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
127-
return current_tick;
128-
}
129-
130-
static struct clocksource hyperv_cs_tsc = {
131-
.name = "hyperv_clocksource_tsc_page",
132-
.rating = 425,
133-
.read = read_hv_clock_tsc,
134-
.mask = CLOCKSOURCE_MASK(64),
135-
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
136-
};
137-
#endif
138-
139-
14090
/*
14191
* hv_init - Main initialization routine.
14292
*
@@ -171,29 +121,7 @@ int hv_init(void)
171121
if (!hypercall_msr.enable)
172122
return -ENOTSUPP;
173123

174-
#ifdef CONFIG_X86_64
175-
if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
176-
union hv_x64_msr_hypercall_contents tsc_msr;
177-
void *va_tsc;
178-
179-
va_tsc = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
180-
if (!va_tsc)
181-
goto cleanup;
182-
hv_context.tsc_page = va_tsc;
183-
184-
rdmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
185-
186-
tsc_msr.enable = 1;
187-
tsc_msr.guest_physical_address = vmalloc_to_pfn(va_tsc);
188-
189-
wrmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
190-
clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
191-
}
192-
#endif
193124
return 0;
194-
195-
cleanup:
196-
return -ENOTSUPP;
197125
}
198126

199127
/*
@@ -204,29 +132,6 @@ int hv_init(void)
204132
void hv_cleanup(bool crash)
205133
{
206134

207-
#ifdef CONFIG_X86_64
208-
union hv_x64_msr_hypercall_contents hypercall_msr;
209-
/*
210-
* Cleanup the TSC page based CS.
211-
*/
212-
if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
213-
/*
214-
* Crash can happen in an interrupt context and unregistering
215-
* a clocksource is impossible and redundant in this case.
216-
*/
217-
if (!oops_in_progress) {
218-
clocksource_change_rating(&hyperv_cs_tsc, 10);
219-
clocksource_unregister(&hyperv_cs_tsc);
220-
}
221-
222-
hypercall_msr.as_uint64 = 0;
223-
wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
224-
if (!crash) {
225-
vfree(hv_context.tsc_page);
226-
hv_context.tsc_page = NULL;
227-
}
228-
}
229-
#endif
230135
}
231136

232137
/*

drivers/hv/hyperv_vmbus.h

-8
Original file line numberDiff line numberDiff line change
@@ -416,14 +416,6 @@ struct hv_context {
416416

417417
extern struct hv_context hv_context;
418418

419-
struct ms_hyperv_tsc_page {
420-
volatile u32 tsc_sequence;
421-
u32 reserved1;
422-
volatile u64 tsc_scale;
423-
volatile s64 tsc_offset;
424-
u64 reserved2[509];
425-
};
426-
427419
struct hv_ring_buffer_debug_info {
428420
u32 current_interrupt_mask;
429421
u32 current_read_index;

0 commit comments

Comments
 (0)