From patchwork Tue Apr 11 14:11:15 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ladi Prosek X-Patchwork-Id: 9675447 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 1D903600CB for ; Tue, 11 Apr 2017 14:11:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1161028583 for ; Tue, 11 Apr 2017 14:11:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 035E028587; Tue, 11 Apr 2017 14:11:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8370A28583 for ; Tue, 11 Apr 2017 14:11:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752845AbdDKOLZ (ORCPT ); Tue, 11 Apr 2017 10:11:25 -0400 Received: from mx1.redhat.com ([209.132.183.28]:50056 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753072AbdDKOLV (ORCPT ); Tue, 11 Apr 2017 10:11:21 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CF93D8048D for ; Tue, 11 Apr 2017 14:11:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com CF93D8048D Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=lprosek@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com CF93D8048D Received: from dhcp-1-107.brq.redhat.com (dhcp-1-114.brq.redhat.com [10.34.1.114]) by smtp.corp.redhat.com (Postfix) with ESMTP id 563917B550; Tue, 11 Apr 2017 14:11:18 +0000 (UTC) From: Ladi Prosek To: kvm@vger.kernel.org Cc: rkrcmar@redhat.com Subject: [PATCH] KVM: x86: implement IOAPIC_REG_EOI for directed EOI support Date: Tue, 11 Apr 2017 16:11:15 +0200 Message-Id: <20170411141115.4314-1-lprosek@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Tue, 11 Apr 2017 14:11:21 +0000 (UTC) Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP If the guest takes advantage of the directed EOI feature by setting APIC_SPIV_DIRECTED_EOI, it is expected to signal EOI by writing to the EOI register of the respective IOAPIC. From Intel's x2APIC Specification: "following the EOI to the local x2APIC unit for a level triggered interrupt, perform a directed EOI to the IOxAPIC generating the interrupt by writing to its EOI register." Commit fc61b800f950 ("KVM: Add Directed EOI support to APIC emulation") inhibited EOI on LAPIC EOI register write but didn't add the IOAPIC part. IOAPIC_REG_EOI writes were handled only on IA64 and the code was later removed with the rest of IA64 support. The bug has gone undetected for a long time because Linux writes to IOAPIC_REG_EOI only if the IOAPIC version is >=0x20. Windows doesn't seem to perform such a check. This commit re-adds IOAPIC_REG_EOI and implements it in terms of __kvm_ioapic_update_eoi. Fixes: fc61b800f950 ("KVM: Add Directed EOI support to APIC emulation") Signed-off-by: Ladi Prosek --- arch/x86/kvm/ioapic.c | 46 ++++++++++++++++++++++++++++------------------ arch/x86/kvm/ioapic.h | 1 + 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index 289270a..8df1c6c 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -415,14 +415,15 @@ static void kvm_ioapic_eoi_inject_work(struct work_struct *work) #define IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT 10000 static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, - struct kvm_ioapic *ioapic, int vector, int trigger_mode) + struct kvm_ioapic *ioapic, int vector, int trigger_mode, + bool directed) { struct dest_map *dest_map = &ioapic->rtc_status.dest_map; struct kvm_lapic *apic = vcpu->arch.apic; int i; /* RTC special handling */ - if (test_bit(vcpu->vcpu_id, dest_map->map) && + if (!directed && test_bit(vcpu->vcpu_id, dest_map->map) && vector == dest_map->vectors[vcpu->vcpu_id]) rtc_irq_eoi(ioapic, vcpu); @@ -432,21 +433,23 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, if (ent->fields.vector != vector) continue; - /* - * We are dropping lock while calling ack notifiers because ack - * notifier callbacks for assigned devices call into IOAPIC - * recursively. Since remote_irr is cleared only after call - * to notifiers if the same vector will be delivered while lock - * is dropped it will be put into irr and will be delivered - * after ack notifier returns. - */ - spin_unlock(&ioapic->lock); - kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i); - spin_lock(&ioapic->lock); - - if (trigger_mode != IOAPIC_LEVEL_TRIG || - kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) - continue; + if (!directed) { + /* + * We are dropping lock while calling ack notifiers because ack + * notifier callbacks for assigned devices call into IOAPIC + * recursively. Since remote_irr is cleared only after call + * to notifiers if the same vector will be delivered while lock + * is dropped it will be put into irr and will be delivered + * after ack notifier returns. + */ + spin_unlock(&ioapic->lock); + kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i); + spin_lock(&ioapic->lock); + + if (trigger_mode != IOAPIC_LEVEL_TRIG || + kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) + continue; + } ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); ent->fields.remote_irr = 0; @@ -478,7 +481,7 @@ void kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector, int trigger_mode) struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic; spin_lock(&ioapic->lock); - __kvm_ioapic_update_eoi(vcpu, ioapic, vector, trigger_mode); + __kvm_ioapic_update_eoi(vcpu, ioapic, vector, trigger_mode, false); spin_unlock(&ioapic->lock); } @@ -540,6 +543,7 @@ static int ioapic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this, gpa_t addr, int len, const void *val) { struct kvm_ioapic *ioapic = to_ioapic(this); + struct kvm_lapic *apic = vcpu->arch.apic; u32 data; if (!ioapic_in_range(ioapic, addr)) return -EOPNOTSUPP; @@ -575,6 +579,12 @@ static int ioapic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this, ioapic_write_indirect(ioapic, data); break; + case IOAPIC_REG_EOI: + if (kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) + __kvm_ioapic_update_eoi(vcpu, ioapic, data, + IOAPIC_LEVEL_TRIG, true); + break; + default: break; } diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h index 1cc6e54..251b61b 100644 --- a/arch/x86/kvm/ioapic.h +++ b/arch/x86/kvm/ioapic.h @@ -20,6 +20,7 @@ struct kvm_vcpu; /* Direct registers. */ #define IOAPIC_REG_SELECT 0x00 #define IOAPIC_REG_WINDOW 0x10 +#define IOAPIC_REG_EOI 0x40 /* Indirect registers. */ #define IOAPIC_REG_APIC_ID 0x00 /* x86 IOAPIC only */