Skip to content

Commit 9328626

Browse files
vittyvkKAGA-KOKO
authored andcommitted
x86/hyperv: Reenlightenment notifications support
Hyper-V supports Live Migration notification. This is supposed to be used in conjunction with TSC emulation: when a VM is migrated to a host with different TSC frequency for some short period the host emulates the accesses to TSC and sends an interrupt to notify about the event. When the guest is done updating everything it can disable TSC emulation and everything will start working fast again. These notifications weren't required until now as Hyper-V guests are not supposed to use TSC as a clocksource: in Linux the TSC is even marked as unstable on boot. Guests normally use 'tsc page' clocksource and host updates its values on migrations automatically. Things change when with nested virtualization: even when the PV clocksources (kvm-clock or tsc page) are passed through to the nested guests the TSC frequency and frequency changes need to be know.. Hyper-V Top Level Functional Specification (as of v5.0b) wrongly specifies EAX:BIT(12) of CPUID:0x40000009 as the feature identification bit. The right one to check is EAX:BIT(13) of CPUID:0x40000003. I was assured that the fix in on the way. Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Cc: Stephen Hemminger <sthemmin@microsoft.com> Cc: kvm@vger.kernel.org Cc: Radim Krčmář <rkrcmar@redhat.com> Cc: Haiyang Zhang <haiyangz@microsoft.com> Cc: "Michael Kelley (EOSG)" <Michael.H.Kelley@microsoft.com> Cc: Roman Kagan <rkagan@virtuozzo.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: devel@linuxdriverproject.org Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: "K. Y. Srinivasan" <kys@microsoft.com> Cc: Cathy Avery <cavery@redhat.com> Cc: Mohammed Gamal <mmorsy@redhat.com> Link: https://lkml.kernel.org/r/20180124132337.30138-4-vkuznets@redhat.com
1 parent e2768ea commit 9328626

File tree

7 files changed

+143
-1
lines changed

7 files changed

+143
-1
lines changed

arch/x86/entry/entry_32.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,9 @@ BUILD_INTERRUPT3(xen_hvm_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
895895
BUILD_INTERRUPT3(hyperv_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
896896
hyperv_vector_handler)
897897

898+
BUILD_INTERRUPT3(hyperv_reenlightenment_vector, HYPERV_REENLIGHTENMENT_VECTOR,
899+
hyperv_reenlightenment_intr)
900+
898901
#endif /* CONFIG_HYPERV */
899902

900903
ENTRY(page_fault)

arch/x86/entry/entry_64.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,9 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \
12451245
#if IS_ENABLED(CONFIG_HYPERV)
12461246
apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \
12471247
hyperv_callback_vector hyperv_vector_handler
1248+
1249+
apicinterrupt3 HYPERV_REENLIGHTENMENT_VECTOR \
1250+
hyperv_reenlightenment_vector hyperv_reenlightenment_intr
12481251
#endif /* CONFIG_HYPERV */
12491252

12501253
idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK

arch/x86/hyperv/hv_init.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919

2020
#include <linux/types.h>
21+
#include <asm/apic.h>
22+
#include <asm/desc.h>
2123
#include <asm/hypervisor.h>
2224
#include <asm/hyperv.h>
2325
#include <asm/mshyperv.h>
@@ -102,6 +104,93 @@ static int hv_cpu_init(unsigned int cpu)
102104
return 0;
103105
}
104106

107+
static void (*hv_reenlightenment_cb)(void);
108+
109+
static void hv_reenlightenment_notify(struct work_struct *dummy)
110+
{
111+
struct hv_tsc_emulation_status emu_status;
112+
113+
rdmsrl(HV_X64_MSR_TSC_EMULATION_STATUS, *(u64 *)&emu_status);
114+
115+
/* Don't issue the callback if TSC accesses are not emulated */
116+
if (hv_reenlightenment_cb && emu_status.inprogress)
117+
hv_reenlightenment_cb();
118+
}
119+
static DECLARE_DELAYED_WORK(hv_reenlightenment_work, hv_reenlightenment_notify);
120+
121+
void hyperv_stop_tsc_emulation(void)
122+
{
123+
u64 freq;
124+
struct hv_tsc_emulation_status emu_status;
125+
126+
rdmsrl(HV_X64_MSR_TSC_EMULATION_STATUS, *(u64 *)&emu_status);
127+
emu_status.inprogress = 0;
128+
wrmsrl(HV_X64_MSR_TSC_EMULATION_STATUS, *(u64 *)&emu_status);
129+
130+
rdmsrl(HV_X64_MSR_TSC_FREQUENCY, freq);
131+
tsc_khz = div64_u64(freq, 1000);
132+
}
133+
EXPORT_SYMBOL_GPL(hyperv_stop_tsc_emulation);
134+
135+
static inline bool hv_reenlightenment_available(void)
136+
{
137+
/*
138+
* Check for required features and priviliges to make TSC frequency
139+
* change notifications work.
140+
*/
141+
return ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
142+
ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE &&
143+
ms_hyperv.features & HV_X64_ACCESS_REENLIGHTENMENT;
144+
}
145+
146+
__visible void __irq_entry hyperv_reenlightenment_intr(struct pt_regs *regs)
147+
{
148+
entering_ack_irq();
149+
150+
schedule_delayed_work(&hv_reenlightenment_work, HZ/10);
151+
152+
exiting_irq();
153+
}
154+
155+
void set_hv_tscchange_cb(void (*cb)(void))
156+
{
157+
struct hv_reenlightenment_control re_ctrl = {
158+
.vector = HYPERV_REENLIGHTENMENT_VECTOR,
159+
.enabled = 1,
160+
.target_vp = hv_vp_index[smp_processor_id()]
161+
};
162+
struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1};
163+
164+
if (!hv_reenlightenment_available()) {
165+
pr_warn("Hyper-V: reenlightenment support is unavailable\n");
166+
return;
167+
}
168+
169+
hv_reenlightenment_cb = cb;
170+
171+
/* Make sure callback is registered before we write to MSRs */
172+
wmb();
173+
174+
wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl));
175+
wrmsrl(HV_X64_MSR_TSC_EMULATION_CONTROL, *((u64 *)&emu_ctrl));
176+
}
177+
EXPORT_SYMBOL_GPL(set_hv_tscchange_cb);
178+
179+
void clear_hv_tscchange_cb(void)
180+
{
181+
struct hv_reenlightenment_control re_ctrl;
182+
183+
if (!hv_reenlightenment_available())
184+
return;
185+
186+
rdmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *(u64 *)&re_ctrl);
187+
re_ctrl.enabled = 0;
188+
wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *(u64 *)&re_ctrl);
189+
190+
hv_reenlightenment_cb = NULL;
191+
}
192+
EXPORT_SYMBOL_GPL(clear_hv_tscchange_cb);
193+
105194
/*
106195
* This function is to be invoked early in the boot sequence after the
107196
* hypervisor has been detected.

arch/x86/include/asm/irq_vectors.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,12 @@
103103
#endif
104104

105105
#define MANAGED_IRQ_SHUTDOWN_VECTOR 0xef
106-
#define LOCAL_TIMER_VECTOR 0xee
106+
107+
#if IS_ENABLED(CONFIG_HYPERV)
108+
#define HYPERV_REENLIGHTENMENT_VECTOR 0xee
109+
#endif
110+
111+
#define LOCAL_TIMER_VECTOR 0xed
107112

108113
#define NR_VECTORS 256
109114

arch/x86/include/asm/mshyperv.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
160160
#define hv_set_synint_state(int_num, val) wrmsrl(int_num, val)
161161

162162
void hyperv_callback_vector(void);
163+
void hyperv_reenlightenment_vector(void);
163164
#ifdef CONFIG_TRACING
164165
#define trace_hyperv_callback_vector hyperv_callback_vector
165166
#endif
@@ -316,11 +317,19 @@ void hyper_alloc_mmu(void);
316317
void hyperv_report_panic(struct pt_regs *regs, long err);
317318
bool hv_is_hypercall_page_setup(void);
318319
void hyperv_cleanup(void);
320+
321+
void hyperv_reenlightenment_intr(struct pt_regs *regs);
322+
void set_hv_tscchange_cb(void (*cb)(void));
323+
void clear_hv_tscchange_cb(void);
324+
void hyperv_stop_tsc_emulation(void);
319325
#else /* CONFIG_HYPERV */
320326
static inline void hyperv_init(void) {}
321327
static inline bool hv_is_hypercall_page_setup(void) { return false; }
322328
static inline void hyperv_cleanup(void) {}
323329
static inline void hyperv_setup_mmu_ops(void) {}
330+
static inline void set_hv_tscchange_cb(void (*cb)(void)) {}
331+
static inline void clear_hv_tscchange_cb(void) {}
332+
static inline void hyperv_stop_tsc_emulation(void) {};
324333
#endif /* CONFIG_HYPERV */
325334

326335
#ifdef CONFIG_HYPERV_TSCPAGE

arch/x86/include/uapi/asm/hyperv.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
*/
4141
#define HV_X64_ACCESS_FREQUENCY_MSRS (1 << 11)
4242

43+
/* AccessReenlightenmentControls privilege */
44+
#define HV_X64_ACCESS_REENLIGHTENMENT BIT(13)
45+
4346
/*
4447
* Basic SynIC MSRs (HV_X64_MSR_SCONTROL through HV_X64_MSR_EOM
4548
* and HV_X64_MSR_SINT0 through HV_X64_MSR_SINT15) available
@@ -234,6 +237,30 @@
234237
#define HV_X64_MSR_CRASH_PARAMS \
235238
(1 + (HV_X64_MSR_CRASH_P4 - HV_X64_MSR_CRASH_P0))
236239

240+
/* TSC emulation after migration */
241+
#define HV_X64_MSR_REENLIGHTENMENT_CONTROL 0x40000106
242+
243+
struct hv_reenlightenment_control {
244+
u64 vector:8;
245+
u64 reserved1:8;
246+
u64 enabled:1;
247+
u64 reserved2:15;
248+
u64 target_vp:32;
249+
};
250+
251+
#define HV_X64_MSR_TSC_EMULATION_CONTROL 0x40000107
252+
#define HV_X64_MSR_TSC_EMULATION_STATUS 0x40000108
253+
254+
struct hv_tsc_emulation_control {
255+
u64 enabled:1;
256+
u64 reserved:63;
257+
};
258+
259+
struct hv_tsc_emulation_status {
260+
u64 inprogress:1;
261+
u64 reserved:63;
262+
};
263+
237264
#define HV_X64_MSR_HYPERCALL_ENABLE 0x00000001
238265
#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT 12
239266
#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_MASK \

arch/x86/kernel/cpu/mshyperv.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@ static void __init ms_hyperv_init_platform(void)
251251
hyperv_setup_mmu_ops();
252252
/* Setup the IDT for hypervisor callback */
253253
alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
254+
255+
/* Setup the IDT for reenlightenment notifications */
256+
if (ms_hyperv.features & HV_X64_ACCESS_REENLIGHTENMENT)
257+
alloc_intr_gate(HYPERV_REENLIGHTENMENT_VECTOR,
258+
hyperv_reenlightenment_vector);
259+
254260
#endif
255261
}
256262

0 commit comments

Comments
 (0)