{"id":2230876,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2230876/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20260430071315.354333-8-zhenzhong.duan@intel.com/","project":{"id":14,"url":"http://patchwork.ozlabs.org/api/1.1/projects/14/?format=json","name":"QEMU Development","link_name":"qemu-devel","list_id":"qemu-devel.nongnu.org","list_email":"qemu-devel@nongnu.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260430071315.354333-8-zhenzhong.duan@intel.com>","date":"2026-04-30T07:13:03","name":"[v4,07/15] intel_iommu: Simplify PASID matching logic in invalidation handlers","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"90500a68fd03e0d24060a4387950b4eaba33757c","submitter":{"id":81636,"url":"http://patchwork.ozlabs.org/api/1.1/people/81636/?format=json","name":"Duan, Zhenzhong","email":"zhenzhong.duan@intel.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20260430071315.354333-8-zhenzhong.duan@intel.com/mbox/","series":[{"id":502222,"url":"http://patchwork.ozlabs.org/api/1.1/series/502222/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/list/?series=502222","date":"2026-04-30T07:12:57","name":"intel_iommu: Enable PASID support for passthrough device","version":4,"mbox":"http://patchwork.ozlabs.org/series/502222/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2230876/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2230876/checks/","tags":{},"headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256\n header.s=Intel header.b=NyXEqB7l;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists1p.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g5lnX6CZ9z1yHZ\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 30 Apr 2026 17:15:44 +1000 (AEST)","from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists1p.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wILbX-0005ak-Cs; Thu, 30 Apr 2026 03:14:35 -0400","from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <zhenzhong.duan@intel.com>)\n id 1wILay-00059u-Nf\n for qemu-devel@nongnu.org; Thu, 30 Apr 2026 03:14:03 -0400","from mgamail.intel.com ([192.198.163.13])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <zhenzhong.duan@intel.com>)\n id 1wILaw-0008OM-Mp\n for qemu-devel@nongnu.org; Thu, 30 Apr 2026 03:14:00 -0400","from orviesa007.jf.intel.com ([10.64.159.147])\n by fmvoesa107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 30 Apr 2026 00:13:57 -0700","from unknown (HELO gnr-sp-2s-612.sh.intel.com) ([10.112.230.229])\n by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 30 Apr 2026 00:13:55 -0700"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1777533238; x=1809069238;\n h=from:to:cc:subject:date:message-id:in-reply-to:\n references:mime-version:content-transfer-encoding;\n bh=nciqrJEDnL7LE44597jZpQmfa0vZJA1BvaEkRrNFzf4=;\n b=NyXEqB7ljixtquka4Wb+SEXbGMQMG9Z3PoR++btLaZzy0koX+vFHoMEA\n ryGcXX5bqGx9dQHds4mAR8AUwkmojWNSVxucIM3CMhg6zZ35C405aKy6X\n 4op1TZRKuAfFF59elTTK2WG1mDMUvhA055gZSD4893gqQ9jEniFyMm7Mu\n xxjxtkkKUI6zM9kXxBVsTMeUabjQY4Q1wJks28EExCruEc8ebjKgX59zd\n 0AFRerOva3yS1A7mO6W9Z9iPGdXJXcAvtzyRDWlLhNNn15HkH2m48S9mb\n iIKn4F5Uv23ZLWhaqJ0+Ij7TTJXfhxC7VRD4EsPu1q0Y2Aw3nBIDAtAEx Q==;","X-CSE-ConnectionGUID":["fjhF0UFySnCF89Wq0foKXA==","yFTsqa4XS7O2G/t7WVvkPw=="],"X-CSE-MsgGUID":["/u8dQdzFSduPU5DcJnQTPw==","6Qkxt9EOTDSKmt7fnZOXhA=="],"X-IronPort-AV":["E=McAfee;i=\"6800,10657,11771\"; a=\"81051622\"","E=Sophos;i=\"6.23,207,1770624000\"; d=\"scan'208\";a=\"81051622\"","E=Sophos;i=\"6.23,207,1770624000\"; d=\"scan'208\";a=\"234771526\""],"X-ExtLoop1":"1","From":"Zhenzhong Duan <zhenzhong.duan@intel.com>","To":"qemu-devel@nongnu.org","Cc":"alex@shazbot.org, clg@redhat.com, eric.auger@redhat.com, mst@redhat.com,\n jasowang@redhat.com, jgg@nvidia.com, nicolinc@nvidia.com,\n skolothumtho@nvidia.com, joao.m.martins@oracle.com,\n clement.mathieu--drif@bull.com, kevin.tian@intel.com, yi.l.liu@intel.com,\n xudong.hao@intel.com, Zhenzhong Duan <zhenzhong.duan@intel.com>","Subject":"[PATCH v4 07/15] intel_iommu: Simplify PASID matching logic in\n invalidation handlers","Date":"Thu, 30 Apr 2026 03:13:03 -0400","Message-ID":"<20260430071315.354333-8-zhenzhong.duan@intel.com>","X-Mailer":"git-send-email 2.47.3","In-Reply-To":"<20260430071315.354333-1-zhenzhong.duan@intel.com>","References":"<20260430071315.354333-1-zhenzhong.duan@intel.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Received-SPF":"pass client-ip=192.198.163.13;\n envelope-from=zhenzhong.duan@intel.com; helo=mgamail.intel.com","X-Spam_score_int":"-43","X-Spam_score":"-4.4","X-Spam_bar":"----","X-Spam_report":"(-4.4 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001,\n DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001,\n 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 <qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<https://lists.nongnu.org/archive/html/qemu-devel>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"},"content":"Refactor PASID matching in IOTLB/PIOTLB invalidation handlers by\nintroducing a helper function to convert VT-d PASID to PCI PASID,\neliminating complex conditions.\n\nSuggested-by: Clement Mathieu--Drif <clement.mathieu--drif@bull.com>\nSigned-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>\n---\n hw/i386/intel_iommu.c | 132 +++++++++++++++++++++++++-----------------\n 1 file changed, 80 insertions(+), 52 deletions(-)","diff":"diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c\nindex 6715cc4383..74642d8123 100644\n--- a/hw/i386/intel_iommu.c\n+++ b/hw/i386/intel_iommu.c\n@@ -92,6 +92,34 @@ static void vtd_pasid_cache_reset_locked(IntelIOMMUState *s)\n     }\n }\n \n+/*\n+ * Converts VT-d PASID to PCI PASID representation\n+ *\n+ * This function handles the semantic difference between how Intel VT-d IOMMU\n+ * and the PCI subsystem represent \"no PASID\" scenarios:\n+ *\n+ * Requests-without-PASID:\n+ *   - PCI subsystem: Uses PCI_NO_PASID (-1) to indicate no PASID present\n+ *   - VT-d IOMMU:    Uses PASID_0 (0) to index the PASID table for translation\n+ *\n+ * Requests-with-PASID:\n+ *   - Both subsystems use identical PASID values (1-0xFFFFF)\n+ *\n+ * Since PCI PASID values are cached in vtd_as->pasid, this conversion is\n+ * required when mapping from VT-d PASID space back to the corresponding\n+ * vtd_as (address space) structure.\n+ *\n+ * @pasid: VT-d PASID value to convert\n+ * @return: Corresponding PCI PASID value\n+ */\n+static uint32_t vtd_pasid_to_pci_pasid(uint32_t pasid)\n+{\n+    if (pasid == PASID_0) {\n+        pasid = PCI_NO_PASID;\n+    }\n+    return pasid;\n+}\n+\n static void vtd_define_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val,\n                             uint64_t wmask, uint64_t w1cmask)\n {\n@@ -2487,9 +2515,10 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)\n }\n \n /*\n- * There is no pasid field in iotlb invalidation descriptor, so PCI_NO_PASID\n+ * There is no pasid field in iotlb invalidation descriptor, so PASID_0\n  * is passed as parameter. Piotlb invalidation supports pasid, pasid in its\n- * descriptor is passed which should not be PCI_NO_PASID.\n+ * descriptor is passed. In both cases, pasid is converted to PCI pasid\n+ * before checking with vtd_as->pasid.\n  */\n static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,\n                                              uint16_t domain_id, hwaddr addr,\n@@ -2500,51 +2529,45 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,\n     int ret;\n     hwaddr size = (1 << am) * VTD_PAGE_SIZE;\n \n+    pasid = vtd_pasid_to_pci_pasid(pasid);\n+\n     QLIST_FOREACH(vtd_as, &(s->vtd_as_with_notifiers), next) {\n         ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),\n                                        vtd_as->devfn, &ce);\n-        if (!ret && domain_id == vtd_get_domain_id(s, &ce, vtd_as->pasid)) {\n+        if (ret || vtd_as->pasid != pasid ||\n+            domain_id != vtd_get_domain_id(s, &ce, vtd_as->pasid)) {\n+            continue;\n+        }\n+\n+        if (vtd_as_has_map_notifier(vtd_as)) {\n             /*\n-             * In legacy mode, vtd_as->pasid == pasid is always true.\n-             * In scalable mode, for vtd address space backing a PCI\n-             * device without pasid, needs to compare pasid with\n-             * PASID_0 of this device.\n+             * When first stage translation is off, as long as we have MAP\n+             * notifications registered in any of our IOMMU notifiers,\n+             * we need to sync the shadow page table. Otherwise VFIO\n+             * device attaches to nested page table instead of shadow\n+             * page table, so no need to sync.\n              */\n-            if (!(vtd_as->pasid == pasid ||\n-                  (vtd_as->pasid == PCI_NO_PASID && pasid == PASID_0))) {\n-                continue;\n-            }\n-\n-            if (vtd_as_has_map_notifier(vtd_as)) {\n-                /*\n-                 * When first stage translation is off, as long as we have MAP\n-                 * notifications registered in any of our IOMMU notifiers,\n-                 * we need to sync the shadow page table. Otherwise VFIO\n-                 * device attaches to nested page table instead of shadow\n-                 * page table, so no need to sync.\n-                 */\n-                if (!s->fsts || !s->root_scalable) {\n-                    vtd_sync_shadow_page_table_range(vtd_as, &ce, addr, size);\n-                }\n-            } else {\n-                /*\n-                 * For UNMAP-only notifiers, we don't need to walk the\n-                 * page tables.  We just deliver the PSI down to\n-                 * invalidate caches.\n-                 */\n-                const IOMMUTLBEvent event = {\n-                    .type = IOMMU_NOTIFIER_UNMAP,\n-                    .entry = {\n-                        .target_as = &address_space_memory,\n-                        .iova = addr,\n-                        .translated_addr = 0,\n-                        .addr_mask = size - 1,\n-                        .perm = IOMMU_NONE,\n-                        .pasid = vtd_as->pasid,\n-                    },\n-                };\n-                memory_region_notify_iommu(&vtd_as->iommu, 0, event);\n+            if (!s->fsts || !s->root_scalable) {\n+                vtd_sync_shadow_page_table_range(vtd_as, &ce, addr, size);\n             }\n+        } else {\n+            /*\n+             * For UNMAP-only notifiers, we don't need to walk the\n+             * page tables.  We just deliver the PSI down to\n+             * invalidate caches.\n+             */\n+            const IOMMUTLBEvent event = {\n+                .type = IOMMU_NOTIFIER_UNMAP,\n+                .entry = {\n+                    .target_as = &address_space_memory,\n+                    .iova = addr,\n+                    .translated_addr = 0,\n+                    .addr_mask = size - 1,\n+                    .perm = IOMMU_NONE,\n+                    .pasid = vtd_as->pasid,\n+                },\n+            };\n+            memory_region_notify_iommu(&vtd_as->iommu, 0, event);\n         }\n     }\n }\n@@ -2563,7 +2586,7 @@ static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id,\n     vtd_iommu_lock(s);\n     g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page, &info);\n     vtd_iommu_unlock(s);\n-    vtd_iotlb_page_invalidate_notify(s, domain_id, addr, am, PCI_NO_PASID);\n+    vtd_iotlb_page_invalidate_notify(s, domain_id, addr, am, PASID_0);\n }\n \n /* Flush IOTLB\n@@ -3001,12 +3024,17 @@ static gboolean vtd_hash_remove_by_pasid(gpointer key, gpointer value,\n             (entry->pasid == info->pasid));\n }\n \n+/*\n+ * Piotlb invalidation supports pasid, pasid in its descriptor is passed and\n+ * is converted to PCI pasid before checking with vtd_as->pasid.\n+ */\n static void vtd_piotlb_pasid_invalidate(IntelIOMMUState *s,\n                                         uint16_t domain_id, uint32_t pasid)\n {\n     VTDIOTLBPageInvInfo info;\n     VTDAddressSpace *vtd_as;\n     VTDContextEntry ce;\n+    int ret;\n \n     info.domain_id = domain_id;\n     info.pasid = pasid;\n@@ -3018,18 +3046,18 @@ static void vtd_piotlb_pasid_invalidate(IntelIOMMUState *s,\n                                      false);\n     vtd_iommu_unlock(s);\n \n+    pasid = vtd_pasid_to_pci_pasid(pasid);\n+\n     QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) {\n-        if (!vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),\n-                                      vtd_as->devfn, &ce) &&\n-            domain_id == vtd_get_domain_id(s, &ce, vtd_as->pasid)) {\n-            if ((vtd_as->pasid != PCI_NO_PASID || pasid != PASID_0) &&\n-                vtd_as->pasid != pasid) {\n-                continue;\n-            }\n+        ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),\n+                                       vtd_as->devfn, &ce);\n+        if (ret || vtd_as->pasid != pasid ||\n+            domain_id != vtd_get_domain_id(s, &ce, vtd_as->pasid)) {\n+            continue;\n+        }\n \n-            if (!s->fsts || !vtd_as_has_map_notifier(vtd_as)) {\n-                vtd_address_space_sync(vtd_as);\n-            }\n+        if (!s->fsts || !vtd_as_has_map_notifier(vtd_as)) {\n+            vtd_address_space_sync(vtd_as);\n         }\n     }\n }\n","prefixes":["v4","07/15"]}