From nobody Mon Feb 9 20:34:20 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=none (zoho.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail(p=none dis=none) header.from=citrix.com ARC-Seal: i=1; a=rsa-sha256; t=1573660872; cv=none; d=zoho.com; s=zohoarc; b=lQYTnk3E7CaPNH8/Q1AHC6CU8VzTGXSsk26vbjCzRJYkAhMExQbUFVSc+QlWFOxFIu0B+1tksi2xOk9iWrAZi9LdSFYVMT2QDs1rKsRgGvIJMry1kiJv4b4/t+XuKO0sItQAOye/ckHE5G83iVx571QftwUCjYZ5wUx5/NUjTYo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1573660872; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=OBI/MVjPtADOpr/zBLV7dYEHwwaQcTeSBLqakJXK8Ss=; b=QQ5g9hAHK1t8aPuWvQVnKH4OcZEE2O0cFeWlmEjXCClXt9J9OQ6s3kOPLwssP1qW9Yhwic8aHDiNFMxDmHCEb5BKXaXKJKsC37wozDgRoVc9IZZbmIYjoDThg0xrRrMD7koQ0myvD59LLYEXuUzluaiQ0UTJzNcu7qj7M7NgCK0= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=none (zoho.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1573660872651663.262239564763; Wed, 13 Nov 2019 08:01:12 -0800 (PST) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1iUv3u-0000eH-5I; Wed, 13 Nov 2019 16:00:06 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1iUv3t-0000Th-8r for xen-devel@lists.xenproject.org; Wed, 13 Nov 2019 16:00:05 +0000 Received: from esa4.hc3370-68.iphmx.com (unknown [216.71.155.144]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id a72de23c-062e-11ea-a237-12813bfff9fa; Wed, 13 Nov 2019 16:00:03 +0000 (UTC) X-Inumbo-ID: a72de23c-062e-11ea-a237-12813bfff9fa DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=citrix.com; s=securemail; t=1573660803; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=X1oDbAmauwWtuFAWXlOr5DGa14RPLRDRHRqxVKGG0ms=; b=BoIres4U4JLaM2rP9m7RFajzjboOEYCjvL+m9CmIOcK7hnXgFCDZpFqh NS8/7sceW3qxkYgd51ClBusOQhaJItjEdT00oKnsAkj57YB/mfi4mT4/o 70EUu3s9axVRKD3qZhB2qmBPXJ0RdY6qiYc9vr/Hdxa+jf5K3t5xjSWSZ Y=; Authentication-Results: esa4.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none; spf=None smtp.pra=roger.pau@citrix.com; spf=Pass smtp.mailfrom=roger.pau@citrix.com; spf=None smtp.helo=postmaster@mail.citrix.com Received-SPF: none (zoho.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Received-SPF: None (esa4.hc3370-68.iphmx.com: no sender authenticity information available from domain of roger.pau@citrix.com) identity=pra; client-ip=162.221.158.21; receiver=esa4.hc3370-68.iphmx.com; envelope-from="roger.pau@citrix.com"; x-sender="roger.pau@citrix.com"; x-conformance=sidf_compatible Received-SPF: Pass (esa4.hc3370-68.iphmx.com: domain of roger.pau@citrix.com designates 162.221.158.21 as permitted sender) identity=mailfrom; client-ip=162.221.158.21; receiver=esa4.hc3370-68.iphmx.com; envelope-from="roger.pau@citrix.com"; x-sender="roger.pau@citrix.com"; x-conformance=sidf_compatible; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:209.167.231.154 ip4:178.63.86.133 ip4:195.66.111.40/30 ip4:85.115.9.32/28 ip4:199.102.83.4 ip4:192.28.146.160 ip4:192.28.146.107 ip4:216.52.6.88 ip4:216.52.6.188 ip4:162.221.158.21 ip4:162.221.156.83 ip4:168.245.78.127 ~all" Received-SPF: None (esa4.hc3370-68.iphmx.com: no sender authenticity information available from domain of postmaster@mail.citrix.com) identity=helo; client-ip=162.221.158.21; receiver=esa4.hc3370-68.iphmx.com; envelope-from="roger.pau@citrix.com"; x-sender="postmaster@mail.citrix.com"; x-conformance=sidf_compatible IronPort-SDR: Z2R8kXFlY7xamkobaWVrB6yuC6+F0jWe072S3VWtlWoUEuVZn4N0DWZlBeVncTWSTF8Crf46XR IEap50omgzJ1ce8Vnb5jMCWEz87Prh2tV4ZgbiCeY/UWwr0D2NjNl/fcWz+hE01f8uJmK2k8Vf K1VOGLUElFH3qYznXl9/g1Wcq3p4XNKD/NeKe3N3mqPiabC4VYhG/jo/5Rk+O470Ztj/ukKAHw m7PU4/rtK0HISvPH7wCPn3jrVyxutoMaOU8H9TmD7IaXRhO/8JrUl9HNLs51YDsZDioDAxTN8l WrQ= X-SBRS: 2.7 X-MesageID: 8804583 X-Ironport-Server: esa4.hc3370-68.iphmx.com X-Remote-IP: 162.221.158.21 X-Policy: $RELAYED X-IronPort-AV: E=Sophos;i="5.68,300,1569297600"; d="scan'208";a="8804583" From: Roger Pau Monne To: Date: Wed, 13 Nov 2019 16:59:39 +0100 Message-ID: <20191113155940.81837-3-roger.pau@citrix.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191113155940.81837-1-roger.pau@citrix.com> References: <20191113155940.81837-1-roger.pau@citrix.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH for-4.13 v4 2/3] x86/passthrough: fix migration of MSI when using posted interrupts X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Juergen Gross , Wei Liu , Andrew Cooper , Joe Jin , Jan Beulich , Roger Pau Monne Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) When using posted interrupts and the guest migrates MSI from vCPUs Xen needs to flush any pending PIRR vectors on the previous vCPU, or else those vectors could get wrongly injected at a later point when the MSI fields are already updated. The usage of a fixed vCPU in lowest priority mode when using VT-d posted interrupts is also removed, and as a result VT-d posted interrupts are not used together with lowest priority mode and multiple destinations. That forces vlapic_lowest_prio to be called in order to select the destination vCPU during interrupt dispatch. Note that PIRR is synced to IRR both in pt_irq_destroy_bind and pt_irq_create_bind when the interrupt delivery data is being updated. Reported-by: Joe Jin Signed-off-by: Roger Pau Monn=C3=A9 Tested-by: Joe Jin --- Cc: Joe Jin Cc: Juergen Gross --- Changes since v3: - In multi-destination mode make sure all destination vCPUs have PIR synced to IRR by using a bitmap. - Drop the bogus selection of a fixed vCPU when using lowest priority mode. Changes since v2: - Also sync PIRR with IRR when using CPU posted interrupts. - Force the selection of a specific vCPU when using posted interrupts for multi-dest. - Change vmsi_deliver_pirq to honor dest_vcpu_id. Changes since v1: - Store the vcpu id also in multi-dest mode if the interrupt is bound to a vcpu for posted delivery. - s/#if/#ifdef/. --- xen/arch/x86/hvm/hvm.c | 31 ++++++++ xen/arch/x86/hvm/vlapic.c | 19 +++++ xen/arch/x86/hvm/vmsi.c | 23 ------ xen/drivers/passthrough/io.c | 118 ++++++++++++++----------------- xen/include/asm-x86/hvm/hvm.h | 5 +- xen/include/asm-x86/hvm/vlapic.h | 3 + 6 files changed, 110 insertions(+), 89 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 06a7b40107..0e3379fa6f 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -5266,6 +5267,36 @@ void hvm_set_segment_register(struct vcpu *v, enum x= 86_segment seg, alternative_vcall(hvm_funcs.set_segment_register, v, seg, reg); } =20 +int hvm_intr_get_dests(struct domain *d, uint8_t dest, uint8_t dest_mode, + uint8_t delivery_mode, unsigned long *vcpus) +{ + struct vcpu *v; + + switch ( delivery_mode ) + { + case dest_LowestPrio: + /* + * Get all the possible destinations, but note that lowest priority + * mode is only going to inject the interrupt to the vCPU running = at + * the least privilege level. + * + * Fallthrough + */ + case dest_Fixed: + for_each_vcpu ( d, v ) + if ( vlapic_match_dest(vcpu_vlapic(v), NULL, 0, dest, dest_mod= e) ) + __set_bit(v->vcpu_id, vcpus); + break; + + default: + gprintk(XENLOG_WARNING, "unsupported interrupt delivery mode %u\n", + delivery_mode); + return -EINVAL; + } + + return 0; +} + /* * Local variables: * mode: C diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 9466258d6f..9d9c6d391a 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -112,6 +112,25 @@ static void sync_pir_to_irr(struct vcpu *v) alternative_vcall(hvm_funcs.sync_pir_to_irr, v); } =20 +void domain_sync_vlapic_pir(struct domain *d, unsigned long *vcpus) +{ + unsigned int id; + + if ( !bitmap_weight(vcpus, d->max_vcpus) ) + return; + + for ( id =3D find_first_bit(vcpus, d->max_vcpus); + id < d->max_vcpus; + id =3D find_next_bit(vcpus, d->max_vcpus, id + 1) ) + { + if ( d->vcpu[id] !=3D current ) + vcpu_pause(d->vcpu[id]); + sync_pir_to_irr(d->vcpu[id]); + if ( d->vcpu[id] !=3D current ) + vcpu_unpause(d->vcpu[id]); + } +} + static int vlapic_find_highest_irr(struct vlapic *vlapic) { sync_pir_to_irr(vlapic_vcpu(vlapic)); diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c index 6597d9f719..66891d7d20 100644 --- a/xen/arch/x86/hvm/vmsi.c +++ b/xen/arch/x86/hvm/vmsi.c @@ -121,29 +121,6 @@ void vmsi_deliver_pirq(struct domain *d, const struct = hvm_pirq_dpci *pirq_dpci) vmsi_deliver(d, vector, dest, dest_mode, delivery_mode, trig_mode); } =20 -/* Return value, -1 : multi-dests, non-negative value: dest_vcpu_id */ -int hvm_girq_dest_2_vcpu_id(struct domain *d, uint8_t dest, uint8_t dest_m= ode) -{ - int dest_vcpu_id =3D -1, w =3D 0; - struct vcpu *v; - =20 - if ( d->max_vcpus =3D=3D 1 ) - return 0; -=20 - for_each_vcpu ( d, v ) - { - if ( vlapic_match_dest(vcpu_vlapic(v), NULL, 0, dest, dest_mode) )=20 - { - w++; - dest_vcpu_id =3D v->vcpu_id; - } - } - if ( w > 1 ) - return -1; - - return dest_vcpu_id; -} - /* MSI-X mask bit hypervisor interception */ struct msixtbl_entry { diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index b292e79382..5289e89bc1 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -219,62 +219,6 @@ void free_hvm_irq_dpci(struct hvm_irq_dpci *dpci) xfree(dpci); } =20 -/* - * This routine handles lowest-priority interrupts using vector-hashing - * mechanism. As an example, modern Intel CPUs use this method to handle - * lowest-priority interrupts. - * - * Here is the details about the vector-hashing mechanism: - * 1. For lowest-priority interrupts, store all the possible destination - * vCPUs in an array. - * 2. Use "gvec % max number of destination vCPUs" to find the right - * destination vCPU in the array for the lowest-priority interrupt. - */ -static struct vcpu *vector_hashing_dest(const struct domain *d, - uint32_t dest_id, - bool dest_mode, - uint8_t gvec) - -{ - unsigned long *dest_vcpu_bitmap; - unsigned int dest_vcpus =3D 0; - struct vcpu *v, *dest =3D NULL; - unsigned int i; - - dest_vcpu_bitmap =3D xzalloc_array(unsigned long, - BITS_TO_LONGS(d->max_vcpus)); - if ( !dest_vcpu_bitmap ) - return NULL; - - for_each_vcpu ( d, v ) - { - if ( !vlapic_match_dest(vcpu_vlapic(v), NULL, APIC_DEST_NOSHORT, - dest_id, dest_mode) ) - continue; - - __set_bit(v->vcpu_id, dest_vcpu_bitmap); - dest_vcpus++; - } - - if ( dest_vcpus !=3D 0 ) - { - unsigned int mod =3D gvec % dest_vcpus; - unsigned int idx =3D 0; - - for ( i =3D 0; i <=3D mod; i++ ) - { - idx =3D find_next_bit(dest_vcpu_bitmap, d->max_vcpus, idx) + 1; - BUG_ON(idx > d->max_vcpus); - } - - dest =3D d->vcpu[idx - 1]; - } - - xfree(dest_vcpu_bitmap); - - return dest; -} - int pt_irq_create_bind( struct domain *d, const struct xen_domctl_bind_pt_irq *pt_irq_bind) { @@ -345,6 +289,8 @@ int pt_irq_create_bind( const struct vcpu *vcpu; uint32_t gflags =3D pt_irq_bind->u.msi.gflags & ~XEN_DOMCTL_VMSI_X86_UNMASKED; + DECLARE_BITMAP(dest_vcpus, MAX_VIRT_CPUS) =3D { }; + DECLARE_BITMAP(prev_vcpus, MAX_VIRT_CPUS) =3D { }; =20 if ( !(pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) ) { @@ -411,6 +357,24 @@ int pt_irq_create_bind( =20 pirq_dpci->gmsi.gvec =3D pt_irq_bind->u.msi.gvec; pirq_dpci->gmsi.gflags =3D gflags; + if ( pirq_dpci->gmsi.dest_vcpu_id !=3D -1 ) + __set_bit(pirq_dpci->gmsi.dest_vcpu_id, prev_vcpus); + else + { + /* + * If previous configuration has multiple possible + * destinations record them in order to sync the PIR t= o IRR + * afterwards. + */ + dest =3D MASK_EXTR(pirq_dpci->gmsi.gflags, + XEN_DOMCTL_VMSI_X86_DEST_ID_MASK); + dest_mode =3D pirq_dpci->gmsi.gflags & + XEN_DOMCTL_VMSI_X86_DM_MASK; + delivery_mode =3D MASK_EXTR(pirq_dpci->gmsi.gflags, + XEN_DOMCTL_VMSI_X86_DELIV_MA= SK); + hvm_intr_get_dests(d, dest, dest_mode, delivery_mode, + prev_vcpus); + } } } /* Calculate dest_vcpu_id for MSI-type pirq migration. */ @@ -420,20 +384,16 @@ int pt_irq_create_bind( delivery_mode =3D MASK_EXTR(pirq_dpci->gmsi.gflags, XEN_DOMCTL_VMSI_X86_DELIV_MASK); =20 - dest_vcpu_id =3D hvm_girq_dest_2_vcpu_id(d, dest, dest_mode); + hvm_intr_get_dests(d, dest, dest_mode, delivery_mode, dest_vcpus); + dest_vcpu_id =3D bitmap_weight(dest_vcpus, d->max_vcpus) !=3D 1 ? + -1 : find_first_bit(dest_vcpus, d->max_vcpus); pirq_dpci->gmsi.dest_vcpu_id =3D dest_vcpu_id; spin_unlock(&d->event_lock); =20 pirq_dpci->gmsi.posted =3D false; vcpu =3D (dest_vcpu_id >=3D 0) ? d->vcpu[dest_vcpu_id] : NULL; - if ( iommu_intpost ) - { - if ( delivery_mode =3D=3D dest_LowestPrio ) - vcpu =3D vector_hashing_dest(d, dest, dest_mode, - pirq_dpci->gmsi.gvec); - if ( vcpu ) - pirq_dpci->gmsi.posted =3D true; - } + if ( vcpu && iommu_intpost ) + pirq_dpci->gmsi.posted =3D true; if ( vcpu && is_iommu_enabled(d) ) hvm_migrate_pirq(pirq_dpci, vcpu); =20 @@ -442,6 +402,9 @@ int pt_irq_create_bind( pi_update_irte(vcpu ? &vcpu->arch.hvm.vmx.pi_desc : NULL, info, pirq_dpci->gmsi.gvec); =20 + if ( hvm_funcs.deliver_posted_intr ) + domain_sync_vlapic_pir(d, prev_vcpus); + if ( pt_irq_bind->u.msi.gflags & XEN_DOMCTL_VMSI_X86_UNMASKED ) { unsigned long flags; @@ -731,6 +694,31 @@ int pt_irq_destroy_bind( else if ( pirq_dpci && pirq_dpci->gmsi.posted ) pi_update_irte(NULL, pirq, 0); =20 + if ( hvm_funcs.deliver_posted_intr ) + { + DECLARE_BITMAP(vcpus, MAX_VIRT_CPUS) =3D { }; + + if ( pirq_dpci->gmsi.dest_vcpu_id !=3D -1 ) + __set_bit(pirq_dpci->gmsi.dest_vcpu_id, vcpus); + else + { + /* + * If previous configuration has multiple possible + * destinations record them in order to sync the PIR to IRR. + */ + uint8_t dest =3D MASK_EXTR(pirq_dpci->gmsi.gflags, + XEN_DOMCTL_VMSI_X86_DEST_ID_MASK); + uint8_t dest_mode =3D pirq_dpci->gmsi.gflags & + XEN_DOMCTL_VMSI_X86_DM_MASK; + uint8_t delivery_mode =3D MASK_EXTR(pirq_dpci->gmsi.gflags, + XEN_DOMCTL_VMSI_X86_DELIV_MA= SK); + + hvm_intr_get_dests(d, dest, dest_mode, delivery_mode, vcpus); + } + + domain_sync_vlapic_pir(d, vcpus); + } + if ( pirq_dpci && (pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) && list_empty(&pirq_dpci->digl_list) ) { diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index f86af09898..899665fed8 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -266,7 +266,6 @@ int vmsi_deliver( uint8_t delivery_mode, uint8_t trig_mode); struct hvm_pirq_dpci; void vmsi_deliver_pirq(struct domain *d, const struct hvm_pirq_dpci *); -int hvm_girq_dest_2_vcpu_id(struct domain *d, uint8_t dest, uint8_t dest_m= ode); =20 enum hvm_intblk hvm_interrupt_blocked(struct vcpu *v, struct hvm_intack intack); @@ -336,6 +335,10 @@ unsigned long hvm_cr4_guest_valid_bits(const struct do= main *d, bool restore); bool hvm_flush_vcpu_tlb(bool (*flush_vcpu)(void *ctxt, struct vcpu *v), void *ctxt); =20 +/* Get all the possible destination vCPUs of an interrupt. */ +int hvm_intr_get_dests(struct domain *d, uint8_t dest, uint8_t dest_mode, + uint8_t delivery_mode, unsigned long *vcpus); + #ifdef CONFIG_HVM =20 #define hvm_get_guest_tsc(v) hvm_get_guest_tsc_fixed(v, 0) diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vla= pic.h index dde66b4f0f..2bc2ebadf0 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -150,4 +150,7 @@ bool_t vlapic_match_dest( const struct vlapic *target, const struct vlapic *source, int short_hand, uint32_t dest, bool_t dest_mode); =20 +/* Sync the PIR to IRR of all vlapics in the vcpus bitmap. */ +void domain_sync_vlapic_pir(struct domain *d, unsigned long *vcpus); + #endif /* __ASM_X86_HVM_VLAPIC_H__ */ --=20 2.24.0 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xenproject.org https://lists.xenproject.org/mailman/listinfo/xen-devel