Merge branch 'x86-hyperv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/hyperv changes from Ingo Molnar: "The biggest change is support for Windows 8's improved hypervisor interrupt model on the Linux Hyper-V guest subsystem code side. Smallish fixes otherwise." * 'x86-hyperv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86, hyperv: HYPERV depends on X86_LOCAL_APIC X86: Handle Hyper-V vmbus interrupts as special hypervisor interrupts X86: Add a check to catch Xen emulation of Hyper-V x86: Hyper-V: register clocksource only if its advertised
This commit is contained in:
commit
29d5052329
@ -109,8 +109,8 @@
|
|||||||
|
|
||||||
#define UV_BAU_MESSAGE 0xf5
|
#define UV_BAU_MESSAGE 0xf5
|
||||||
|
|
||||||
/* Xen vector callback to receive events in a HVM domain */
|
/* Vector on which hypervisor callbacks will be delivered */
|
||||||
#define XEN_HVM_EVTCHN_CALLBACK 0xf3
|
#define HYPERVISOR_CALLBACK_VECTOR 0xf3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local APIC timer IRQ vector is on a different priority level,
|
* Local APIC timer IRQ vector is on a different priority level,
|
||||||
|
@ -11,4 +11,8 @@ struct ms_hyperv_info {
|
|||||||
|
|
||||||
extern struct ms_hyperv_info ms_hyperv;
|
extern struct ms_hyperv_info ms_hyperv;
|
||||||
|
|
||||||
|
void hyperv_callback_vector(void);
|
||||||
|
void hyperv_vector_handler(struct pt_regs *regs);
|
||||||
|
void hv_register_vmbus_handler(int irq, irq_handler_t handler);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,10 +14,15 @@
|
|||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
#include <linux/clocksource.h>
|
#include <linux/clocksource.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/hardirq.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/hypervisor.h>
|
#include <asm/hypervisor.h>
|
||||||
#include <asm/hyperv.h>
|
#include <asm/hyperv.h>
|
||||||
#include <asm/mshyperv.h>
|
#include <asm/mshyperv.h>
|
||||||
|
#include <asm/desc.h>
|
||||||
|
#include <asm/idle.h>
|
||||||
|
#include <asm/irq_regs.h>
|
||||||
|
|
||||||
struct ms_hyperv_info ms_hyperv;
|
struct ms_hyperv_info ms_hyperv;
|
||||||
EXPORT_SYMBOL_GPL(ms_hyperv);
|
EXPORT_SYMBOL_GPL(ms_hyperv);
|
||||||
@ -30,6 +35,13 @@ static bool __init ms_hyperv_platform(void)
|
|||||||
if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
|
if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Xen emulates Hyper-V to support enlightened Windows.
|
||||||
|
* Check to see first if we are on a Xen Hypervisor.
|
||||||
|
*/
|
||||||
|
if (xen_cpuid_base())
|
||||||
|
return false;
|
||||||
|
|
||||||
cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
|
cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
|
||||||
&eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
|
&eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
|
||||||
|
|
||||||
@ -68,7 +80,14 @@ static void __init ms_hyperv_init_platform(void)
|
|||||||
printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n",
|
printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n",
|
||||||
ms_hyperv.features, ms_hyperv.hints);
|
ms_hyperv.features, ms_hyperv.hints);
|
||||||
|
|
||||||
clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
|
if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
|
||||||
|
clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
|
||||||
|
#if IS_ENABLED(CONFIG_HYPERV)
|
||||||
|
/*
|
||||||
|
* Setup the IDT for hypervisor callback.
|
||||||
|
*/
|
||||||
|
alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
|
const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
|
||||||
@ -77,3 +96,36 @@ const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
|
|||||||
.init_platform = ms_hyperv_init_platform,
|
.init_platform = ms_hyperv_init_platform,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL(x86_hyper_ms_hyperv);
|
EXPORT_SYMBOL(x86_hyper_ms_hyperv);
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_HYPERV)
|
||||||
|
static int vmbus_irq = -1;
|
||||||
|
static irq_handler_t vmbus_isr;
|
||||||
|
|
||||||
|
void hv_register_vmbus_handler(int irq, irq_handler_t handler)
|
||||||
|
{
|
||||||
|
vmbus_irq = irq;
|
||||||
|
vmbus_isr = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hyperv_vector_handler(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||||
|
struct irq_desc *desc;
|
||||||
|
|
||||||
|
irq_enter();
|
||||||
|
exit_idle();
|
||||||
|
|
||||||
|
desc = irq_to_desc(vmbus_irq);
|
||||||
|
|
||||||
|
if (desc)
|
||||||
|
generic_handle_irq_desc(vmbus_irq, desc);
|
||||||
|
|
||||||
|
irq_exit();
|
||||||
|
set_irq_regs(old_regs);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void hv_register_vmbus_handler(int irq, irq_handler_t handler)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
EXPORT_SYMBOL_GPL(hv_register_vmbus_handler);
|
||||||
|
@ -1091,11 +1091,18 @@ ENTRY(xen_failsafe_callback)
|
|||||||
_ASM_EXTABLE(4b,9b)
|
_ASM_EXTABLE(4b,9b)
|
||||||
ENDPROC(xen_failsafe_callback)
|
ENDPROC(xen_failsafe_callback)
|
||||||
|
|
||||||
BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK,
|
BUILD_INTERRUPT3(xen_hvm_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
|
||||||
xen_evtchn_do_upcall)
|
xen_evtchn_do_upcall)
|
||||||
|
|
||||||
#endif /* CONFIG_XEN */
|
#endif /* CONFIG_XEN */
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_HYPERV)
|
||||||
|
|
||||||
|
BUILD_INTERRUPT3(hyperv_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
|
||||||
|
hyperv_vector_handler)
|
||||||
|
|
||||||
|
#endif /* CONFIG_HYPERV */
|
||||||
|
|
||||||
#ifdef CONFIG_FUNCTION_TRACER
|
#ifdef CONFIG_FUNCTION_TRACER
|
||||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||||
|
|
||||||
|
@ -1454,11 +1454,16 @@ ENTRY(xen_failsafe_callback)
|
|||||||
CFI_ENDPROC
|
CFI_ENDPROC
|
||||||
END(xen_failsafe_callback)
|
END(xen_failsafe_callback)
|
||||||
|
|
||||||
apicinterrupt XEN_HVM_EVTCHN_CALLBACK \
|
apicinterrupt HYPERVISOR_CALLBACK_VECTOR \
|
||||||
xen_hvm_callback_vector xen_evtchn_do_upcall
|
xen_hvm_callback_vector xen_evtchn_do_upcall
|
||||||
|
|
||||||
#endif /* CONFIG_XEN */
|
#endif /* CONFIG_XEN */
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_HYPERV)
|
||||||
|
apicinterrupt HYPERVISOR_CALLBACK_VECTOR \
|
||||||
|
hyperv_callback_vector hyperv_vector_handler
|
||||||
|
#endif /* CONFIG_HYPERV */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some functions should be protected against kprobes
|
* Some functions should be protected against kprobes
|
||||||
*/
|
*/
|
||||||
|
@ -2,7 +2,7 @@ menu "Microsoft Hyper-V guest support"
|
|||||||
|
|
||||||
config HYPERV
|
config HYPERV
|
||||||
tristate "Microsoft Hyper-V client drivers"
|
tristate "Microsoft Hyper-V client drivers"
|
||||||
depends on X86 && ACPI && PCI
|
depends on X86 && ACPI && PCI && X86_LOCAL_APIC
|
||||||
help
|
help
|
||||||
Select this option to run Linux as a Hyper-V client operating
|
Select this option to run Linux as a Hyper-V client operating
|
||||||
system.
|
system.
|
||||||
|
@ -1787,7 +1787,7 @@ void xen_callback_vector(void)
|
|||||||
int rc;
|
int rc;
|
||||||
uint64_t callback_via;
|
uint64_t callback_via;
|
||||||
if (xen_have_vector_callback) {
|
if (xen_have_vector_callback) {
|
||||||
callback_via = HVM_CALLBACK_VECTOR(XEN_HVM_EVTCHN_CALLBACK);
|
callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR);
|
||||||
rc = xen_set_callback_via(callback_via);
|
rc = xen_set_callback_via(callback_via);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_ERR "Request for Xen HVM callback vector"
|
printk(KERN_ERR "Request for Xen HVM callback vector"
|
||||||
@ -1798,8 +1798,9 @@ void xen_callback_vector(void)
|
|||||||
printk(KERN_INFO "Xen HVM callback vector for event delivery is "
|
printk(KERN_INFO "Xen HVM callback vector for event delivery is "
|
||||||
"enabled\n");
|
"enabled\n");
|
||||||
/* in the restore case the vector has already been allocated */
|
/* in the restore case the vector has already been allocated */
|
||||||
if (!test_bit(XEN_HVM_EVTCHN_CALLBACK, used_vectors))
|
if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors))
|
||||||
alloc_intr_gate(XEN_HVM_EVTCHN_CALLBACK, xen_hvm_callback_vector);
|
alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
|
||||||
|
xen_hvm_callback_vector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
Loading…
Reference in New Issue
Block a user