From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53324) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Zriuw-0006AA-KM for qemu-devel@nongnu.org; Thu, 29 Oct 2015 04:50:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Zrius-0004sU-Gl for qemu-devel@nongnu.org; Thu, 29 Oct 2015 04:50:42 -0400 Received: from relay.parallels.com ([195.214.232.42]:50207) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Zriur-0004sH-Qm for qemu-devel@nongnu.org; Thu, 29 Oct 2015 04:50:38 -0400 References: <1444979273-6587-9-git-send-email-den@openvz.org> <1445530171-20688-1-git-send-email-asmetanin@virtuozzo.com> <563108D9.7000708@redhat.com> From: Andrey Smetanin Message-ID: <5631DDC5.1000800@virtuozzo.com> Date: Thu, 29 Oct 2015 11:50:13 +0300 MIME-Version: 1.0 In-Reply-To: <563108D9.7000708@redhat.com> Content-Type: text/plain; charset="windows-1252"; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH v3 8/9] kvm/x86: Hyper-V synthetic interrupt controller Reply-To: asmetanin@virtuozzo.com List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Paolo Bonzini , kvm@vger.kernel.org Cc: Gleb Natapov , qemu-devel@nongnu.org, Roman Kagan , "Denis V. Lunev" , Vitaly Kuznetsov , "K. Y. Srinivasan" On 10/28/2015 08:41 PM, Paolo Bonzini wrote: > Hi Andrey, > > just one question. Is kvm_arch_set_irq actually needed? I think > everything should work fine without it. Can you check? If so, I can > remove it myself and revert the patch that introduced the hook. > Hi Paolo, I have checked that Hyper-V SynIC unit test and some hand-made tests with Windows guest(with enabled SynIC) works fine without kvm_arch_set_irq. It will be nice to remove this function. Thanks > Paolo > > On 22/10/2015 18:09, Andrey Smetanin wrote: >> SynIC (synthetic interrupt controller) is a lapic extension, >> which is controlled via MSRs and maintains for each vCPU >> - 16 synthetic interrupt "lines" (SINT's); each can be configured to >> trigger a specific interrupt vector optionally with auto-EOI >> semantics >> - a message page in the guest memory with 16 256-byte per-SINT message >> slots >> - an event flag page in the guest memory with 16 2048-bit per-SINT >> event flag areas >> >> The host triggers a SINT whenever it delivers a new message to the >> corresponding slot or flips an event flag bit in the corresponding area. >> The guest informs the host that it can try delivering a message by >> explicitly asserting EOI in lapic or writing to End-Of-Message (EOM) >> MSR. >> >> The userspace (qemu) triggers interrupts and receives EOM notifications >> via irqfd with resampler; for that, a GSI is allocated for each >> configured SINT, and irq_routing api is extended to support GSI-SINT >> mapping. >> >> Signed-off-by: Andrey Smetanin >> Reviewed-by: Roman Kagan >> Signed-off-by: Denis V. Lunev >> CC: Vitaly Kuznetsov >> CC: "K. Y. Srinivasan" >> CC: Gleb Natapov >> CC: Paolo Bonzini >> CC: Roman Kagan >> >> Changes v3: >> * added KVM_CAP_HYPERV_SYNIC and KVM_IRQ_ROUTING_HV_SINT notes into >> docs >> >> Changes v2: >> * do not use posted interrupts for Hyper-V SynIC AutoEOI vectors >> * add Hyper-V SynIC vectors into EOI exit bitmap >> * Hyper-V SyniIC SINT msr write logic simplified >> --- >> Documentation/virtual/kvm/api.txt | 14 ++ >> arch/x86/include/asm/kvm_host.h | 14 ++ >> arch/x86/kvm/hyperv.c | 297 ++++++++++++++++++++++++++++++++++++++ >> arch/x86/kvm/hyperv.h | 21 +++ >> arch/x86/kvm/irq_comm.c | 34 +++++ >> arch/x86/kvm/lapic.c | 18 ++- >> arch/x86/kvm/lapic.h | 5 + >> arch/x86/kvm/x86.c | 12 +- >> include/linux/kvm_host.h | 6 + >> include/uapi/linux/kvm.h | 8 + >> 10 files changed, 421 insertions(+), 8 deletions(-) >> >> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt >> index 092ee9f..8710418 100644 >> --- a/Documentation/virtual/kvm/api.txt >> +++ b/Documentation/virtual/kvm/api.txt >> @@ -1451,6 +1451,7 @@ struct kvm_irq_routing_entry { >> struct kvm_irq_routing_irqchip irqchip; >> struct kvm_irq_routing_msi msi; >> struct kvm_irq_routing_s390_adapter adapter; >> + struct kvm_irq_routing_hv_sint hv_sint; >> __u32 pad[8]; >> } u; >> }; >> @@ -1459,6 +1460,7 @@ struct kvm_irq_routing_entry { >> #define KVM_IRQ_ROUTING_IRQCHIP 1 >> #define KVM_IRQ_ROUTING_MSI 2 >> #define KVM_IRQ_ROUTING_S390_ADAPTER 3 >> +#define KVM_IRQ_ROUTING_HV_SINT 4 >> >> No flags are specified so far, the corresponding field must be set to zero. >> >> @@ -1482,6 +1484,10 @@ struct kvm_irq_routing_s390_adapter { >> __u32 adapter_id; >> }; >> >> +struct kvm_irq_routing_hv_sint { >> + __u32 vcpu; >> + __u32 sint; >> +}; >> >> 4.53 KVM_ASSIGN_SET_MSIX_NR (deprecated) >> >> @@ -3685,3 +3691,11 @@ available, means that that the kernel has an implementation of the >> H_RANDOM hypercall backed by a hardware random-number generator. >> If present, the kernel H_RANDOM handler can be enabled for guest use >> with the KVM_CAP_PPC_ENABLE_HCALL capability. >> + >> +8.2 KVM_CAP_HYPERV_SYNIC >> + >> +Architectures: x86 >> +This capability, if KVM_CHECK_EXTENSION indicates that it is >> +available, means that that the kernel has an implementation of the >> +Hyper-V Synthetic interrupt controller(SynIC). SynIC is used to >> +support Windows Hyper-V based guest paravirt drivers(VMBus). >> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h >> index 3c6327d..8434f88 100644 >> --- a/arch/x86/include/asm/kvm_host.h >> +++ b/arch/x86/include/asm/kvm_host.h >> @@ -25,6 +25,7 @@ >> #include >> #include >> #include >> +#include >> >> #include >> #include >> @@ -374,10 +375,23 @@ struct kvm_mtrr { >> struct list_head head; >> }; >> >> +/* Hyper-V synthetic interrupt controller (SynIC)*/ >> +struct kvm_vcpu_hv_synic { >> + u64 version; >> + u64 control; >> + u64 msg_page; >> + u64 evt_page; >> + atomic64_t sint[HV_SYNIC_SINT_COUNT]; >> + atomic_t sint_to_gsi[HV_SYNIC_SINT_COUNT]; >> + DECLARE_BITMAP(auto_eoi_bitmap, 256); >> + DECLARE_BITMAP(vec_bitmap, 256); >> +}; >> + >> /* Hyper-V per vcpu emulation context */ >> struct kvm_vcpu_hv { >> u64 hv_vapic; >> s64 runtime_offset; >> + struct kvm_vcpu_hv_synic synic; >> }; >> >> struct kvm_vcpu_arch { >> diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c >> index 62cf8c9..8ff71f3 100644 >> --- a/arch/x86/kvm/hyperv.c >> +++ b/arch/x86/kvm/hyperv.c >> @@ -23,13 +23,296 @@ >> >> #include "x86.h" >> #include "lapic.h" >> +#include "ioapic.h" >> #include "hyperv.h" >> >> #include >> +#include >> #include >> >> #include "trace.h" >> >> +static inline u64 synic_read_sint(struct kvm_vcpu_hv_synic *synic, int sint) >> +{ >> + return atomic64_read(&synic->sint[sint]); >> +} >> + >> +static inline int synic_get_sint_vector(u64 sint_value) >> +{ >> + if (sint_value & HV_SYNIC_SINT_MASKED) >> + return -1; >> + return sint_value & HV_SYNIC_SINT_VECTOR_MASK; >> +} >> + >> +static bool synic_has_vector_connected(struct kvm_vcpu_hv_synic *synic, >> + int vector) >> +{ >> + int i; >> + >> + for (i = 0; i < ARRAY_SIZE(synic->sint); i++) { >> + if (synic_get_sint_vector(synic_read_sint(synic, i)) == vector) >> + return true; >> + } >> + return false; >> +} >> + >> +static bool synic_has_vector_auto_eoi(struct kvm_vcpu_hv_synic *synic, >> + int vector) >> +{ >> + int i; >> + u64 sint_value; >> + >> + for (i = 0; i < ARRAY_SIZE(synic->sint); i++) { >> + sint_value = synic_read_sint(synic, i); >> + if (synic_get_sint_vector(sint_value) == vector && >> + sint_value & HV_SYNIC_SINT_AUTO_EOI) >> + return true; >> + } >> + return false; >> +} >> + >> +static int synic_set_sint(struct kvm_vcpu_hv_synic *synic, int sint, u64 data) >> +{ >> + int vector; >> + >> + vector = data & HV_SYNIC_SINT_VECTOR_MASK; >> + if (vector < 16) >> + return 1; >> + /* >> + * Guest may configure multiple SINTs to use the same vector, so >> + * we maintain a bitmap of vectors handled by synic, and a >> + * bitmap of vectors with auto-eoi behavior. The bitmaps are >> + * updated here, and atomically queried on fast paths. >> + */ >> + >> + atomic64_set(&synic->sint[sint], data); >> + >> + if (synic_has_vector_connected(synic, vector)) >> + __set_bit(vector, synic->vec_bitmap); >> + else >> + __clear_bit(vector, synic->vec_bitmap); >> + >> + if (synic_has_vector_auto_eoi(synic, vector)) >> + __set_bit(vector, synic->auto_eoi_bitmap); >> + else >> + __clear_bit(vector, synic->auto_eoi_bitmap); >> + >> + /* Load SynIC vectors into EOI exit bitmap */ >> + kvm_make_request(KVM_REQ_SCAN_IOAPIC, synic_to_vcpu(synic)); >> + return 0; >> +} >> + >> +static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vcpu_id) >> +{ >> + struct kvm_vcpu *vcpu; >> + >> + if (vcpu_id >= atomic_read(&kvm->online_vcpus)) >> + return NULL; >> + vcpu = kvm_get_vcpu(kvm, vcpu_id); >> + if (!vcpu) >> + return NULL; >> + >> + return vcpu_to_synic(vcpu); >> +} >> + >> +static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint) >> +{ >> + struct kvm *kvm = vcpu->kvm; >> + int gsi, idx; >> + >> + vcpu_debug(vcpu, "Hyper-V SynIC acked sint %d\n", sint); >> + >> + idx = srcu_read_lock(&kvm->irq_srcu); >> + gsi = atomic_read(&vcpu_to_synic(vcpu)->sint_to_gsi[sint]); >> + if (gsi != -1) >> + kvm_notify_acked_gsi(kvm, gsi); >> + srcu_read_unlock(&kvm->irq_srcu, idx); >> +} >> + >> +static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, >> + u32 msr, u64 data, bool host) >> +{ >> + struct kvm_vcpu *vcpu = synic_to_vcpu(synic); >> + int ret; >> + >> + vcpu_debug(vcpu, "Hyper-V SynIC set msr 0x%x 0x%llx host %d\n", >> + msr, data, host); >> + ret = 0; >> + switch (msr) { >> + case HV_X64_MSR_SCONTROL: >> + synic->control = data; >> + break; >> + case HV_X64_MSR_SVERSION: >> + if (!host) { >> + ret = 1; >> + break; >> + } >> + synic->version = data; >> + break; >> + case HV_X64_MSR_SIEFP: >> + if (data & HV_SYNIC_SIEFP_ENABLE) >> + if (kvm_clear_guest(vcpu->kvm, >> + data & PAGE_MASK, PAGE_SIZE)) { >> + ret = 1; >> + break; >> + } >> + synic->evt_page = data; >> + break; >> + case HV_X64_MSR_SIMP: >> + if (data & HV_SYNIC_SIMP_ENABLE) >> + if (kvm_clear_guest(vcpu->kvm, >> + data & PAGE_MASK, PAGE_SIZE)) { >> + ret = 1; >> + break; >> + } >> + synic->msg_page = data; >> + break; >> + case HV_X64_MSR_EOM: { >> + int i; >> + >> + for (i = 0; i < ARRAY_SIZE(synic->sint); i++) >> + kvm_hv_notify_acked_sint(vcpu, i); >> + break; >> + } >> + case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: >> + ret = synic_set_sint(synic, msr - HV_X64_MSR_SINT0, data); >> + break; >> + default: >> + ret = 1; >> + break; >> + } >> + return ret; >> +} >> + >> +static int synic_get_msr(struct kvm_vcpu_hv_synic *synic, u32 msr, u64 *pdata) >> +{ >> + int ret; >> + >> + ret = 0; >> + switch (msr) { >> + case HV_X64_MSR_SCONTROL: >> + *pdata = synic->control; >> + break; >> + case HV_X64_MSR_SVERSION: >> + *pdata = synic->version; >> + break; >> + case HV_X64_MSR_SIEFP: >> + *pdata = synic->evt_page; >> + break; >> + case HV_X64_MSR_SIMP: >> + *pdata = synic->msg_page; >> + break; >> + case HV_X64_MSR_EOM: >> + *pdata = 0; >> + break; >> + case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: >> + *pdata = atomic64_read(&synic->sint[msr - HV_X64_MSR_SINT0]); >> + break; >> + default: >> + ret = 1; >> + break; >> + } >> + return ret; >> +} >> + >> +int synic_set_irq(struct kvm_vcpu_hv_synic *synic, u32 sint) >> +{ >> + struct kvm_vcpu *vcpu = synic_to_vcpu(synic); >> + struct kvm_lapic_irq irq; >> + int ret, vector; >> + >> + if (sint >= ARRAY_SIZE(synic->sint)) >> + return -EINVAL; >> + >> + vector = synic_get_sint_vector(synic_read_sint(synic, sint)); >> + if (vector < 0) >> + return -ENOENT; >> + >> + memset(&irq, 0, sizeof(irq)); >> + irq.dest_id = kvm_apic_id(vcpu->arch.apic); >> + irq.dest_mode = APIC_DEST_PHYSICAL; >> + irq.delivery_mode = APIC_DM_FIXED; >> + irq.vector = vector; >> + irq.level = 1; >> + >> + ret = kvm_irq_delivery_to_apic(vcpu->kvm, NULL, &irq, NULL); >> + vcpu_debug(vcpu, "Hyper-V SynIC set irq ret %d\n", ret); >> + return ret; >> +} >> + >> +int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint) >> +{ >> + struct kvm_vcpu_hv_synic *synic; >> + >> + synic = synic_get(kvm, vcpu_id); >> + if (!synic) >> + return -EINVAL; >> + >> + return synic_set_irq(synic, sint); >> +} >> + >> +void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector) >> +{ >> + struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); >> + int i; >> + >> + vcpu_debug(vcpu, "Hyper-V SynIC send eoi vec %d\n", vector); >> + >> + for (i = 0; i < ARRAY_SIZE(synic->sint); i++) >> + if (synic_get_sint_vector(synic_read_sint(synic, i)) == vector) >> + kvm_hv_notify_acked_sint(vcpu, i); >> +} >> + >> +static int kvm_hv_set_sint_gsi(struct kvm *kvm, u32 vcpu_id, u32 sint, int gsi) >> +{ >> + struct kvm_vcpu_hv_synic *synic; >> + >> + synic = synic_get(kvm, vcpu_id); >> + if (!synic) >> + return -EINVAL; >> + >> + if (sint >= ARRAY_SIZE(synic->sint_to_gsi)) >> + return -EINVAL; >> + >> + atomic_set(&synic->sint_to_gsi[sint], gsi); >> + return 0; >> +} >> + >> +void kvm_hv_irq_routing_update(struct kvm *kvm) >> +{ >> + struct kvm_irq_routing_table *irq_rt; >> + struct kvm_kernel_irq_routing_entry *e; >> + u32 gsi; >> + >> + irq_rt = srcu_dereference_check(kvm->irq_routing, &kvm->irq_srcu, >> + lockdep_is_held(&kvm->irq_lock)); >> + >> + for (gsi = 0; gsi < irq_rt->nr_rt_entries; gsi++) { >> + hlist_for_each_entry(e, &irq_rt->map[gsi], link) { >> + if (e->type == KVM_IRQ_ROUTING_HV_SINT) >> + kvm_hv_set_sint_gsi(kvm, e->hv_sint.vcpu, >> + e->hv_sint.sint, gsi); >> + } >> + } >> +} >> + >> +static void synic_init(struct kvm_vcpu_hv_synic *synic) >> +{ >> + int i; >> + >> + memset(synic, 0, sizeof(*synic)); >> + synic->version = HV_SYNIC_VERSION_1; >> + for (i = 0; i < ARRAY_SIZE(synic->sint); i++) { >> + atomic64_set(&synic->sint[i], HV_SYNIC_SINT_MASKED); >> + atomic_set(&synic->sint_to_gsi[i], -1); >> + } >> +} >> + >> +void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu) >> +{ >> + synic_init(vcpu_to_synic(vcpu)); >> +} >> + >> static bool kvm_hv_msr_partition_wide(u32 msr) >> { >> bool r = false; >> @@ -226,6 +509,13 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) >> return 1; >> hv->runtime_offset = data - current_task_runtime_100ns(); >> break; >> + case HV_X64_MSR_SCONTROL: >> + case HV_X64_MSR_SVERSION: >> + case HV_X64_MSR_SIEFP: >> + case HV_X64_MSR_SIMP: >> + case HV_X64_MSR_EOM: >> + case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: >> + return synic_set_msr(vcpu_to_synic(vcpu), msr, data, host); >> default: >> vcpu_unimpl(vcpu, "Hyper-V uhandled wrmsr: 0x%x data 0x%llx\n", >> msr, data); >> @@ -304,6 +594,13 @@ static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) >> case HV_X64_MSR_VP_RUNTIME: >> data = current_task_runtime_100ns() + hv->runtime_offset; >> break; >> + case HV_X64_MSR_SCONTROL: >> + case HV_X64_MSR_SVERSION: >> + case HV_X64_MSR_SIEFP: >> + case HV_X64_MSR_SIMP: >> + case HV_X64_MSR_EOM: >> + case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: >> + return synic_get_msr(vcpu_to_synic(vcpu), msr, pdata); >> default: >> vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr); >> return 1; >> diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h >> index c7bce55..8668612 100644 >> --- a/arch/x86/kvm/hyperv.h >> +++ b/arch/x86/kvm/hyperv.h >> @@ -29,4 +29,25 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); >> bool kvm_hv_hypercall_enabled(struct kvm *kvm); >> int kvm_hv_hypercall(struct kvm_vcpu *vcpu); >> >> +int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint); >> +void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector); >> + >> +static inline struct kvm_vcpu_hv_synic *vcpu_to_synic(struct kvm_vcpu *vcpu) >> +{ >> + return &vcpu->arch.hyperv.synic; >> +} >> + >> +static inline struct kvm_vcpu *synic_to_vcpu(struct kvm_vcpu_hv_synic *synic) >> +{ >> + struct kvm_vcpu_hv *hv; >> + struct kvm_vcpu_arch *arch; >> + >> + hv = container_of(synic, struct kvm_vcpu_hv, synic); >> + arch = container_of(hv, struct kvm_vcpu_arch, hyperv); >> + return container_of(arch, struct kvm_vcpu, arch); >> +} >> +void kvm_hv_irq_routing_update(struct kvm *kvm); >> + >> +void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu); >> + >> #endif >> diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c >> index fe91f72..5e195b9 100644 >> --- a/arch/x86/kvm/irq_comm.c >> +++ b/arch/x86/kvm/irq_comm.c >> @@ -33,6 +33,8 @@ >> >> #include "lapic.h" >> >> +#include "hyperv.h" >> + >> static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e, >> struct kvm *kvm, int irq_source_id, int level, >> bool line_status) >> @@ -251,6 +253,16 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin, >> srcu_read_unlock(&kvm->irq_srcu, idx); >> } >> >> +static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e, >> + struct kvm *kvm, int irq_source_id, int level, >> + bool line_status) >> +{ >> + if (!level) >> + return -1; >> + >> + return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint); >> +} >> + >> int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e, >> const struct kvm_irq_routing_entry *ue) >> { >> @@ -289,6 +301,11 @@ int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e, >> e->msi.address_hi = ue->u.msi.address_hi; >> e->msi.data = ue->u.msi.data; >> break; >> + case KVM_IRQ_ROUTING_HV_SINT: >> + e->set = kvm_hv_set_sint; >> + e->hv_sint.vcpu = ue->u.hv_sint.vcpu; >> + e->hv_sint.sint = ue->u.hv_sint.sint; >> + break; >> default: >> goto out; >> } >> @@ -405,3 +422,20 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, >> } >> srcu_read_unlock(&kvm->irq_srcu, idx); >> } >> + >> +int kvm_arch_set_irq(struct kvm_kernel_irq_routing_entry *irq, struct kvm *kvm, >> + int irq_source_id, int level, bool line_status) >> +{ >> + switch (irq->type) { >> + case KVM_IRQ_ROUTING_HV_SINT: >> + return kvm_hv_set_sint(irq, kvm, irq_source_id, level, >> + line_status); >> + default: >> + return -EWOULDBLOCK; >> + } >> +} >> + >> +void kvm_arch_irq_routing_update(struct kvm *kvm) >> +{ >> + kvm_hv_irq_routing_update(kvm); >> +} >> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c >> index dc03a01..3132478 100644 >> --- a/arch/x86/kvm/lapic.c >> +++ b/arch/x86/kvm/lapic.c >> @@ -41,6 +41,7 @@ >> #include "trace.h" >> #include "x86.h" >> #include "cpuid.h" >> +#include "hyperv.h" >> >> #ifndef CONFIG_X86_64 >> #define mod_64(x, y) ((x) - (y) * div64_u64(x, y)) >> @@ -128,11 +129,6 @@ static inline int apic_enabled(struct kvm_lapic *apic) >> (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \ >> APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER) >> >> -static inline int kvm_apic_id(struct kvm_lapic *apic) >> -{ >> - return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; >> -} >> - >> /* The logical map is definitely wrong if we have multiple >> * modes at the same time. (Physical map is always right.) >> */ >> @@ -850,7 +846,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, >> apic_clear_vector(vector, apic->regs + APIC_TMR); >> } >> >> - if (kvm_x86_ops->deliver_posted_interrupt) >> + if (kvm_x86_ops->deliver_posted_interrupt && >> + !test_bit(vector, vcpu_to_synic(vcpu)->auto_eoi_bitmap)) >> kvm_x86_ops->deliver_posted_interrupt(vcpu, vector); >> else { >> apic_set_irr(vector, apic); >> @@ -972,6 +969,9 @@ static int apic_set_eoi(struct kvm_lapic *apic) >> apic_clear_isr(vector, apic); >> apic_update_ppr(apic); >> >> + if (test_bit(vector, vcpu_to_synic(apic->vcpu)->vec_bitmap)) >> + kvm_hv_synic_send_eoi(apic->vcpu, vector); >> + >> kvm_ioapic_send_eoi(apic, vector); >> kvm_make_request(KVM_REQ_EVENT, apic->vcpu); >> return vector; >> @@ -1881,6 +1881,12 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) >> apic_set_isr(vector, apic); >> apic_update_ppr(apic); >> apic_clear_irr(vector, apic); >> + >> + if (test_bit(vector, vcpu_to_synic(vcpu)->auto_eoi_bitmap)) { >> + apic_clear_isr(vector, apic); >> + apic_update_ppr(apic); >> + } >> + >> return vector; >> } >> >> diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h >> index fde8e35d..6c64090 100644 >> --- a/arch/x86/kvm/lapic.h >> +++ b/arch/x86/kvm/lapic.h >> @@ -164,6 +164,11 @@ static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu) >> return kvm_vcpu_has_lapic(vcpu) && test_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events); >> } >> >> +static inline int kvm_apic_id(struct kvm_lapic *apic) >> +{ >> + return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; >> +} >> + >> bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector); >> >> void wait_lapic_expire(struct kvm_vcpu *vcpu); >> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c >> index fb6cfbf..b853b2df 100644 >> --- a/arch/x86/kvm/x86.c >> +++ b/arch/x86/kvm/x86.c >> @@ -959,6 +959,7 @@ static u32 emulated_msrs[] = { >> HV_X64_MSR_RESET, >> HV_X64_MSR_VP_INDEX, >> HV_X64_MSR_VP_RUNTIME, >> + HV_X64_MSR_SCONTROL, >> HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME, >> MSR_KVM_PV_EOI_EN, >> >> @@ -2441,6 +2442,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) >> case KVM_CAP_HYPERV: >> case KVM_CAP_HYPERV_VAPIC: >> case KVM_CAP_HYPERV_SPIN: >> + case KVM_CAP_HYPERV_SYNIC: >> case KVM_CAP_PCI_SEGMENT: >> case KVM_CAP_DEBUGREGS: >> case KVM_CAP_X86_ROBUST_SINGLESTEP: >> @@ -6195,6 +6197,8 @@ static void process_smi(struct kvm_vcpu *vcpu) >> >> static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu) >> { >> + u64 eoi_exit_bitmap[4]; >> + >> if (!kvm_apic_hw_enabled(vcpu->arch.apic)) >> return; >> >> @@ -6205,8 +6209,10 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu) >> else >> kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors); >> >> - kvm_x86_ops->load_eoi_exitmap(vcpu, >> - (u64 *)vcpu->arch.ioapic_handled_vectors); >> + bitmap_or((ulong *)eoi_exit_bitmap, vcpu->arch.ioapic_handled_vectors, >> + vcpu_to_synic(vcpu)->vec_bitmap, 256); >> + >> + kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap); >> } >> >> static void kvm_vcpu_flush_tlb(struct kvm_vcpu *vcpu) >> @@ -7456,6 +7462,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) >> >> vcpu->arch.pending_external_vector = -1; >> >> + kvm_hv_vcpu_init(vcpu); >> + >> return 0; >> >> fail_free_mce_banks: >> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h >> index c742e79..43b0141 100644 >> --- a/include/linux/kvm_host.h >> +++ b/include/linux/kvm_host.h >> @@ -318,6 +318,11 @@ struct kvm_s390_adapter_int { >> u32 adapter_id; >> }; >> >> +struct kvm_hv_sint { >> + u32 vcpu; >> + u32 sint; >> +}; >> + >> struct kvm_kernel_irq_routing_entry { >> u32 gsi; >> u32 type; >> @@ -331,6 +336,7 @@ struct kvm_kernel_irq_routing_entry { >> } irqchip; >> struct msi_msg msi; >> struct kvm_s390_adapter_int adapter; >> + struct kvm_hv_sint hv_sint; >> }; >> struct hlist_node link; >> }; >> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h >> index 03f3618..27ce460 100644 >> --- a/include/uapi/linux/kvm.h >> +++ b/include/uapi/linux/kvm.h >> @@ -831,6 +831,7 @@ struct kvm_ppc_smmu_info { >> #define KVM_CAP_GUEST_DEBUG_HW_WPS 120 >> #define KVM_CAP_SPLIT_IRQCHIP 121 >> #define KVM_CAP_IOEVENTFD_ANY_LENGTH 122 >> +#define KVM_CAP_HYPERV_SYNIC 123 >> >> #ifdef KVM_CAP_IRQ_ROUTING >> >> @@ -854,10 +855,16 @@ struct kvm_irq_routing_s390_adapter { >> __u32 adapter_id; >> }; >> >> +struct kvm_irq_routing_hv_sint { >> + __u32 vcpu; >> + __u32 sint; >> +}; >> + >> /* gsi routing entry types */ >> #define KVM_IRQ_ROUTING_IRQCHIP 1 >> #define KVM_IRQ_ROUTING_MSI 2 >> #define KVM_IRQ_ROUTING_S390_ADAPTER 3 >> +#define KVM_IRQ_ROUTING_HV_SINT 4 >> >> struct kvm_irq_routing_entry { >> __u32 gsi; >> @@ -868,6 +875,7 @@ struct kvm_irq_routing_entry { >> struct kvm_irq_routing_irqchip irqchip; >> struct kvm_irq_routing_msi msi; >> struct kvm_irq_routing_s390_adapter adapter; >> + struct kvm_irq_routing_hv_sint hv_sint; >> __u32 pad[8]; >> } u; >> }; >>