From nobody Mon Feb 9 22:38:35 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1768297092; cv=none; d=zohomail.com; s=zohoarc; b=VD+BWAAHikR7kpJC7ebmqz0MprOu7Hu5UvonOfB+jIo0eIiWr+3UHHg3c9ikrznZZryVrMzAeXhsDVk/BaDrfLzGiw7zJ0ImROpCctJT80KDtTwaz3BBVmwLFfSMQ6nDBKI49Uo+6SWVnks3/Tm2dUzi7lDF/qZ48dE+F4jqWOo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1768297092; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=aiqr9r0qi090TiI98ZmR7YFL4F6SY/8exnQMPCE2VWs=; b=IKGUpQoXS8RHCAT4vIikfSf+/lVONDgI5csUnFreeELJ8TH2oBF9fE3HACmF1cljnZcFBNWtubzs+kZtCGdBuvuw1T6NaZ2xJkHH4VVWr0dvfMkCjcVjdG5Syc8cjtIEV5iIRKpk3/z5bE486ezYj1oBtqe/g0RPcVFl/HMEaKA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1768297092002248.70124393297192; Tue, 13 Jan 2026 01:38:12 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vfaqJ-0008Fc-4F; Tue, 13 Jan 2026 04:37:39 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vfaqG-0007yz-P3 for qemu-devel@nongnu.org; Tue, 13 Jan 2026 04:37:36 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vfaqE-0003M2-KK for qemu-devel@nongnu.org; Tue, 13 Jan 2026 04:37:36 -0500 Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-553-ZTx_7nbBMDSNOIHEfJEUJg-1; Tue, 13 Jan 2026 04:37:30 -0500 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 928431956096; Tue, 13 Jan 2026 09:37:29 +0000 (UTC) Received: from corto.redhat.com (unknown [10.44.32.79]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1E3FC30001A2; Tue, 13 Jan 2026 09:37:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1768297054; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=aiqr9r0qi090TiI98ZmR7YFL4F6SY/8exnQMPCE2VWs=; b=bTGYZ4yfDjIOC097cBeVQ17KiOmpNnX4fO/RYQqMAi8W/t4lGUCxQRi0eS2duVXHJnIx4S DxsfLktNk6bzmyLRXPsipUtbYpnNAN3s97s26l74wLrp9bTlhn5uyyrYHT5gO3kKiacihx 34gacJnfFl91MF9xXv5aXRZYjFKfCHY= X-MC-Unique: ZTx_7nbBMDSNOIHEfJEUJg-1 X-Mimecast-MFC-AGG-ID: ZTx_7nbBMDSNOIHEfJEUJg_1768297049 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: qemu-devel@nongnu.org Cc: Alex Williamson , Yi Liu , Yi Sun , Zhenzhong Duan , Eric Auger , "Michael S. Tsirkin" , =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Subject: [PULL 16/41] intel_iommu_accel: Propagate PASID-based iotlb invalidation to host Date: Tue, 13 Jan 2026 10:36:12 +0100 Message-ID: <20260113093637.1549214-17-clg@redhat.com> In-Reply-To: <20260113093637.1549214-1-clg@redhat.com> References: <20260113093637.1549214-1-clg@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=clg@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1768297093638158500 From: Yi Liu This traps the guest PASID-based iotlb invalidation request and propagate it to host. Intel VT-d 3.0 supports nested translation in PASID granularity. Guest SVA support could be implemented by configuring nested translation on specific pasid. This is also known as dual stage DMA translation. Under such configuration, guest owns the GVA->GPA translation which is configured as first stage page table on host side for a specific pasid, and host owns GPA->HPA translation. As guest owns first stage translation table, piotlb invalidation should be propagated to host since host IOMMU will cache first level page table related mappings during DMA address translation. Signed-off-by: Yi Liu Signed-off-by: Yi Sun Signed-off-by: Zhenzhong Duan Reviewed-by: Eric Auger Reviewed-by: Yi Liu Reviewed-by: Michael S. Tsirkin Link: https://lore.kernel.org/qemu-devel/20260106061304.314546-15-zhenzhong= .duan@intel.com Signed-off-by: C=C3=A9dric Le Goater --- hw/i386/intel_iommu_accel.h | 10 +++++ hw/i386/intel_iommu_internal.h | 6 +++ hw/i386/intel_iommu.c | 11 ++++-- hw/i386/intel_iommu_accel.c | 69 ++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 3 deletions(-) diff --git a/hw/i386/intel_iommu_accel.h b/hw/i386/intel_iommu_accel.h index 30696765af61b8864b3577984c5d9bcd774d4212..6dec8788f18d0196550b3d0047d= c5a5b29ed2c6b 100644 --- a/hw/i386/intel_iommu_accel.h +++ b/hw/i386/intel_iommu_accel.h @@ -17,6 +17,9 @@ bool vtd_check_hiod_accel(IntelIOMMUState *s, VTDHostIOMM= UDevice *vtd_hiod, Error **errp); VTDHostIOMMUDevice *vtd_find_hiod_iommufd(VTDAddressSpace *as); bool vtd_propagate_guest_pasid(VTDAddressSpace *vtd_as, Error **errp); +void vtd_flush_host_piotlb_all_locked(IntelIOMMUState *s, uint16_t domain_= id, + uint32_t pasid, hwaddr addr, + uint64_t npages, bool ih); #else static inline bool vtd_check_hiod_accel(IntelIOMMUState *s, VTDHostIOMMUDevice *vtd_hiod, @@ -37,5 +40,12 @@ static inline bool vtd_propagate_guest_pasid(VTDAddressS= pace *vtd_as, { return true; } + +static inline void vtd_flush_host_piotlb_all_locked(IntelIOMMUState *s, + uint16_t domain_id, + uint32_t pasid, hwaddr= addr, + uint64_t npages, bool = ih) +{ +} #endif #endif diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index e987322e93ab05db2873d550de78abca268ca8c9..a2ca79f925c22928432e4ca7e23= 81c4f535fbdf0 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -622,6 +622,12 @@ typedef struct VTDPASIDCacheInfo { uint32_t pasid; } VTDPASIDCacheInfo; =20 +typedef struct VTDPIOTLBInvInfo { + uint16_t domain_id; + uint32_t pasid; + struct iommu_hwpt_vtd_s1_invalidate *inv_data; +} VTDPIOTLBInvInfo; + /* PASID Table Related Definitions */ #define VTD_PASID_DIR_BASE_ADDR_MASK (~0xfffULL) #define VTD_PASID_TABLE_BASE_ADDR_MASK (~0xfffULL) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index f9b80e3257b4e382fd0eb9f946f6b6691a3d09ab..2889c29102b1c487f760906e403= 8274491da1a44 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2967,6 +2967,8 @@ static void vtd_piotlb_pasid_invalidate(IntelIOMMUSta= te *s, vtd_iommu_lock(s); g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_pasid, &info); + vtd_flush_host_piotlb_all_locked(s, domain_id, pasid, 0, (uint64_t)-1, + false); vtd_iommu_unlock(s); =20 QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) { @@ -2986,7 +2988,8 @@ static void vtd_piotlb_pasid_invalidate(IntelIOMMUSta= te *s, } =20 static void vtd_piotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain= _id, - uint32_t pasid, hwaddr addr, uint8_= t am) + uint32_t pasid, hwaddr addr, uint8_= t am, + bool ih) { VTDIOTLBPageInvInfo info; =20 @@ -2998,6 +3001,7 @@ static void vtd_piotlb_page_invalidate(IntelIOMMUStat= e *s, uint16_t domain_id, vtd_iommu_lock(s); g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page_piotlb, &info); + vtd_flush_host_piotlb_all_locked(s, domain_id, pasid, addr, 1 << am, i= h); vtd_iommu_unlock(s); =20 vtd_iotlb_page_invalidate_notify(s, domain_id, addr, am, pasid); @@ -3029,7 +3033,8 @@ static bool vtd_process_piotlb_desc(IntelIOMMUState *= s, case VTD_INV_DESC_PIOTLB_PSI_IN_PASID: am =3D VTD_INV_DESC_PIOTLB_AM(inv_desc->val[1]); addr =3D (hwaddr) VTD_INV_DESC_PIOTLB_ADDR(inv_desc->val[1]); - vtd_piotlb_page_invalidate(s, domain_id, pasid, addr, am); + vtd_piotlb_page_invalidate(s, domain_id, pasid, addr, am, + VTD_INV_DESC_PIOTLB_IH(inv_desc)); break; =20 default: @@ -5176,7 +5181,7 @@ static int vtd_pri_perform_implicit_invalidation(VTDA= ddressSpace *vtd_as, ret =3D 0; switch (pgtt) { case VTD_SM_PASID_ENTRY_FST: - vtd_piotlb_page_invalidate(s, domain_id, vtd_as->pasid, addr, 0); + vtd_piotlb_page_invalidate(s, domain_id, vtd_as->pasid, addr, 0, f= alse); break; /* Room for other pgtt values */ default: diff --git a/hw/i386/intel_iommu_accel.c b/hw/i386/intel_iommu_accel.c index 69f82e8831f5f834126b9aa1550a6da8f2cc94c5..1f068005d8fa8b2161247e1e238= 6db5a60dbbdc5 100644 --- a/hw/i386/intel_iommu_accel.c +++ b/hw/i386/intel_iommu_accel.c @@ -182,3 +182,72 @@ bool vtd_propagate_guest_pasid(VTDAddressSpace *vtd_as= , Error **errp) =20 return vtd_device_detach_iommufd(vtd_hiod, vtd_as, errp); } + +/* + * This function is a loop function for the s->vtd_address_spaces + * list with VTDPIOTLBInvInfo as execution filter. It propagates + * the piotlb invalidation to host. + */ +static void vtd_flush_host_piotlb_locked(gpointer key, gpointer value, + gpointer user_data) +{ + VTDPIOTLBInvInfo *piotlb_info =3D user_data; + VTDAddressSpace *vtd_as =3D value; + VTDHostIOMMUDevice *vtd_hiod =3D vtd_find_hiod_iommufd(vtd_as); + VTDPASIDCacheEntry *pc_entry =3D &vtd_as->pasid_cache_entry; + uint16_t did; + + if (!vtd_hiod) { + return; + } + + assert(vtd_as->pasid =3D=3D PCI_NO_PASID); + + /* Nothing to do if there is no first stage HWPT attached */ + if (!pc_entry->valid || + !vtd_pe_pgtt_is_fst(&pc_entry->pasid_entry)) { + return; + } + + did =3D VTD_SM_PASID_ENTRY_DID(&pc_entry->pasid_entry); + + if (piotlb_info->domain_id =3D=3D did && piotlb_info->pasid =3D=3D PAS= ID_0) { + HostIOMMUDeviceIOMMUFD *idev =3D + HOST_IOMMU_DEVICE_IOMMUFD(vtd_hiod->hiod); + uint32_t entry_num =3D 1; /* Only implement one request for simpli= city */ + Error *local_err =3D NULL; + struct iommu_hwpt_vtd_s1_invalidate *cache =3D piotlb_info->inv_da= ta; + + if (!iommufd_backend_invalidate_cache(idev->iommufd, vtd_as->fs_hw= pt_id, + IOMMU_HWPT_INVALIDATE_DATA_V= TD_S1, + sizeof(*cache), &entry_num, = cache, + &local_err)) { + /* Something wrong in kernel, but trying to continue */ + error_report_err(local_err); + } + } +} + +void vtd_flush_host_piotlb_all_locked(IntelIOMMUState *s, uint16_t domain_= id, + uint32_t pasid, hwaddr addr, + uint64_t npages, bool ih) +{ + struct iommu_hwpt_vtd_s1_invalidate cache_info =3D { 0 }; + VTDPIOTLBInvInfo piotlb_info; + + cache_info.addr =3D addr; + cache_info.npages =3D npages; + cache_info.flags =3D ih ? IOMMU_VTD_INV_FLAGS_LEAF : 0; + + piotlb_info.domain_id =3D domain_id; + piotlb_info.pasid =3D pasid; + piotlb_info.inv_data =3D &cache_info; + + /* + * Go through each vtd_as instance in s->vtd_address_spaces, find out + * affected host devices which need host piotlb invalidation. Piotlb + * invalidation should check pasid cache per architecture point of vie= w. + */ + g_hash_table_foreach(s->vtd_address_spaces, + vtd_flush_host_piotlb_locked, &piotlb_info); +} --=20 2.52.0