All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3] intel_iommu: Keep PASID cache consistent with PT fast path
@ 2026-11-12  8:15 Zhenzhong Duan
  2026-11-12 12:06 ` Yi Liu
  2026-11-13  8:37 ` Clement Mathieu--Drif
  0 siblings, 2 replies; 3+ messages in thread
From: Zhenzhong Duan @ 2026-11-12  8:15 UTC (permalink / raw)
  To: qemu-devel
  Cc: clement.mathieu--drif, mst, jasowangio, yi.l.liu, Zhenzhong Duan

With caching mode disabled, a guest can install a scalable-mode
pass-through PASID entry without issuing a PASID-cache invalidation. The
first DMA enables the PT fast path, but leaves QEMU's PASID cache invalid.

When the guest tears down that entry to switch back to a DMA domain, the
invalidation handler sees both a non-present guest entry and an invalid
cached entry and returns without re-enabling the IOMMU memory region.
Subsequent DMA therefore continues to bypass translation.

The issue can be reproduced with an emulated device in scalable mode
with caching-mode=off:

1. Unbind the guest device driver and change the group's type to
   identity through /sys/kernel/iommu_groups/<group>/type.
2. Rebind the driver and issue a DMA write.
3. Unbind the driver, change the group's type back to DMA-FQ, and
   rebind the driver.
4. Issue another DMA write using an IOVA mapped to a different GPA.

The second write incorrectly bypasses translation instead of reaching
the mapped GPA.

Save the PASID entry when enabling the scalable-mode PT fast path so
teardown invalidation can restore the IOMMU address space. Return after
handling a non-present entry, and refresh the cached entry when a present
entry changes, pass vtd_as to vtd_try_enable_pt_fast_path() instead of
pick it from PASID 0.

Opportunistically clarify the invalidation modes in the fast-path comment
and merge trace event vtd_translate_pt and vtd_pt_enable_fast_path into
vtd_fast_path_translate_pt.

Fixes: c9cf33075a4c ("intel_iommu: Fix DMA failure when guest switches IOMMU domain")
Reported-by: Clement Mathieu--Drif <clement.mathieu--drif@bull.com>
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Tested-by: Clement Mathieu--Drif <clement.mathieu--drif@bull.com>
---
v3:
- introduce a new helper vtd_try_enable_pt_fast_path (Clement)
v2:
- move "VTDPASIDCacheEntry *pc_entry" in the branch it is used (Clement)

 hw/i386/intel_iommu.c | 62 ++++++++++++++++++++++++-------------------
 hw/i386/trace-events  |  3 +--
 2 files changed, 35 insertions(+), 30 deletions(-)

diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index b7da5d086d..a5ff89a11a 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -1649,7 +1649,7 @@ static int vtd_address_space_sync(VTDAddressSpace *vtd_as)
  * or second stage translation, it depends on PGTT setting.
  */
 static bool vtd_dev_pt_enabled(IntelIOMMUState *s, VTDContextEntry *ce,
-                               uint32_t pasid)
+                               uint32_t pasid, VTDPASIDEntry *pasid_entry)
 {
     VTDPASIDEntry pe;
     int ret;
@@ -1663,6 +1663,11 @@ static bool vtd_dev_pt_enabled(IntelIOMMUState *s, VTDContextEntry *ce,
              */
             return false;
         }
+
+        if (pasid_entry) {
+            *pasid_entry = pe;
+        }
+
         return vtd_pe_pgtt_is_pt(&pe);
     }
 
@@ -1689,7 +1694,7 @@ static bool vtd_as_pt_enabled(VTDAddressSpace *as)
         return false;
     }
 
-    return vtd_dev_pt_enabled(s, &ce, as->pasid);
+    return vtd_dev_pt_enabled(s, &ce, as->pasid, NULL);
 }
 
 /* Return whether the device is using IOMMU translation. */
@@ -1701,8 +1706,8 @@ static bool vtd_switch_address_space(VTDAddressSpace *as)
     assert(as);
 
     s = as->iommu_state;
-    use_iommu = s->dmar_enabled && !vtd_as_pt_enabled(as);
     pt = s->dmar_enabled && vtd_as_pt_enabled(as);
+    use_iommu = s->dmar_enabled && !pt;
 
     /*
      * When guest enables scalable mode and sets up first stage page table,
@@ -1887,23 +1892,34 @@ VTDAddressSpace *vtd_get_as_by_sid(IntelIOMMUState *s, uint16_t sid)
     return vtd_get_as_by_sid_and_pasid(s, sid, IOMMU_NO_PASID);
 }
 
-static void vtd_pt_enable_fast_path(IntelIOMMUState *s, uint16_t source_id)
+static bool vtd_try_enable_pt_fast_path(IntelIOMMUState *s,
+                                        VTDAddressSpace *vtd_as,
+                                        VTDContextEntry *ce, uint32_t pasid)
 {
-    VTDAddressSpace *vtd_as;
-    bool success = false;
+    VTDPASIDEntry pe;
 
-    vtd_as = vtd_get_as_by_sid(s, source_id);
-    if (!vtd_as) {
-        goto out;
+    if (!vtd_dev_pt_enabled(s, ce, pasid, &pe)) {
+        return false;
     }
 
-    if (vtd_switch_address_space(vtd_as) == false) {
-        /* We switched off IOMMU region successfully. */
-        success = true;
+    /*
+     * When this happens, it means firstly caching-mode is not
+     * enabled, and this is the first passthrough translation for
+     * the device. Let's enable the fast path for passthrough.
+     *
+     * When passthrough is disabled again for the device, we can
+     * capture it via context-cache invalidation in legacy mode or
+     * PASID-cache invalidation in scalable mode, then the IOMMU
+     * region can be swapped back.
+     */
+    if (!vtd_switch_address_space(vtd_as) && s->root_scalable) {
+        VTDPASIDCacheEntry *pc_entry = &vtd_as->pasid_cache_entry;
+
+        pc_entry->pasid_entry = pe;
+        pc_entry->valid = true;
     }
 
-out:
-    trace_vtd_pt_enable_fast_path(source_id, success);
+    return true;
 }
 
 /*
@@ -2167,23 +2183,12 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
      * We don't need to translate for pass-through context entries.
      * Also, let's ignore IOTLB caching as well for PT devices.
      */
-    if (vtd_dev_pt_enabled(s, &ce, pasid)) {
+    if (vtd_try_enable_pt_fast_path(s, vtd_as, &ce, pasid)) {
         entry->iova = addr & VTD_PAGE_MASK_4K;
         entry->translated_addr = entry->iova;
         entry->addr_mask = ~VTD_PAGE_MASK_4K;
         entry->perm = IOMMU_RW;
-        trace_vtd_translate_pt(source_id, entry->iova);
-
-        /*
-         * When this happens, it means firstly caching-mode is not
-         * enabled, and this is the first passthrough translation for
-         * the device. Let's enable the fast path for passthrough.
-         *
-         * When passthrough is disabled again for the device, we can
-         * capture it via the context entry invalidation, then the
-         * IOMMU region can be swapped back.
-         */
-        vtd_pt_enable_fast_path(s, source_id);
+        trace_vtd_fast_path_translate_pt(source_id, entry->iova);
         vtd_iommu_unlock(s);
         return true;
     }
@@ -3133,6 +3138,7 @@ static void vtd_pasid_cache_sync_locked(gpointer key, gpointer value,
             vtd_address_space_unmap(vtd_as, n);
         }
         vtd_switch_address_space(vtd_as);
+        return;
     }
 
     /*
@@ -3158,11 +3164,11 @@ static void vtd_pasid_cache_sync_locked(gpointer key, gpointer value,
     }
 
     if (!pc_entry->valid) {
-        pc_entry->pasid_entry = pe;
         pc_entry->valid = true;
     } else if (!vtd_pasid_entry_compare(&pe, &pc_entry->pasid_entry)) {
         return;
     }
+    pc_entry->pasid_entry = pe;
 
     vtd_switch_address_space(vtd_as);
     vtd_address_space_sync(vtd_as);
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index 7bf4cddd38..3337a7e19c 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -47,8 +47,7 @@ vtd_page_walk_skip_read(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"P
 vtd_page_walk_skip_reserve(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to rsrv set"
 vtd_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)"
 vtd_as_unmap_whole(uint8_t bus, uint8_t slot, uint8_t fn, uint64_t iova, uint64_t size) "Device %02x:%02x.%x start 0x%"PRIx64" size 0x%"PRIx64
-vtd_translate_pt(uint16_t sid, uint64_t addr) "source id 0x%"PRIx16", iova 0x%"PRIx64
-vtd_pt_enable_fast_path(uint16_t sid, bool success) "sid 0x%"PRIx16" %d"
+vtd_fast_path_translate_pt(uint16_t sid, uint64_t addr) "source id 0x%"PRIx16", iova 0x%"PRIx64
 vtd_irq_generate(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64
 vtd_reg_read(uint64_t addr, uint64_t size) "addr 0x%"PRIx64" size 0x%"PRIx64
 vtd_reg_write(uint64_t addr, uint64_t size, uint64_t val) "addr 0x%"PRIx64" size 0x%"PRIx64" value 0x%"PRIx64
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v3] intel_iommu: Keep PASID cache consistent with PT fast path
  2026-11-12  8:15 [PATCH v3] intel_iommu: Keep PASID cache consistent with PT fast path Zhenzhong Duan
@ 2026-11-12 12:06 ` Yi Liu
  2026-11-13  8:37 ` Clement Mathieu--Drif
  1 sibling, 0 replies; 3+ messages in thread
From: Yi Liu @ 2026-11-12 12:06 UTC (permalink / raw)
  To: Zhenzhong Duan, qemu-devel; +Cc: clement.mathieu--drif, mst, jasowangio

On 11/12/26 16:15, Zhenzhong Duan wrote:
> With caching mode disabled, a guest can install a scalable-mode
> pass-through PASID entry without issuing a PASID-cache invalidation. The
> first DMA enables the PT fast path, but leaves QEMU's PASID cache invalid.
> 
> When the guest tears down that entry to switch back to a DMA domain, the
> invalidation handler sees both a non-present guest entry and an invalid
> cached entry and returns without re-enabling the IOMMU memory region.
> Subsequent DMA therefore continues to bypass translation.
> 
> The issue can be reproduced with an emulated device in scalable mode
> with caching-mode=off:
> 
> 1. Unbind the guest device driver and change the group's type to
>     identity through /sys/kernel/iommu_groups/<group>/type.
> 2. Rebind the driver and issue a DMA write.
> 3. Unbind the driver, change the group's type back to DMA-FQ, and
>     rebind the driver.
> 4. Issue another DMA write using an IOVA mapped to a different GPA.
> 
> The second write incorrectly bypasses translation instead of reaching
> the mapped GPA.
> 
> Save the PASID entry when enabling the scalable-mode PT fast path so
> teardown invalidation can restore the IOMMU address space. Return after
> handling a non-present entry, and refresh the cached entry when a present
> entry changes, pass vtd_as to vtd_try_enable_pt_fast_path() instead of
> pick it from PASID 0.
> 
> Opportunistically clarify the invalidation modes in the fast-path comment
> and merge trace event vtd_translate_pt and vtd_pt_enable_fast_path into
> vtd_fast_path_translate_pt.
> 
> Fixes: c9cf33075a4c ("intel_iommu: Fix DMA failure when guest switches IOMMU domain")
> Reported-by: Clement Mathieu--Drif <clement.mathieu--drif@bull.com>
> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
> Tested-by: Clement Mathieu--Drif <clement.mathieu--drif@bull.com>
> ---
> v3:
> - introduce a new helper vtd_try_enable_pt_fast_path (Clement)
> v2:
> - move "VTDPASIDCacheEntry *pc_entry" in the branch it is used (Clement)

LGTM.

Reviewed-by: Yi Liu <yi.l.liu@intel.com>

>   hw/i386/intel_iommu.c | 62 ++++++++++++++++++++++++-------------------
>   hw/i386/trace-events  |  3 +--
>   2 files changed, 35 insertions(+), 30 deletions(-)
> 
> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
> index b7da5d086d..a5ff89a11a 100644
> --- a/hw/i386/intel_iommu.c
> +++ b/hw/i386/intel_iommu.c
> @@ -1649,7 +1649,7 @@ static int vtd_address_space_sync(VTDAddressSpace *vtd_as)
>    * or second stage translation, it depends on PGTT setting.
>    */
>   static bool vtd_dev_pt_enabled(IntelIOMMUState *s, VTDContextEntry *ce,
> -                               uint32_t pasid)
> +                               uint32_t pasid, VTDPASIDEntry *pasid_entry)
>   {
>       VTDPASIDEntry pe;
>       int ret;
> @@ -1663,6 +1663,11 @@ static bool vtd_dev_pt_enabled(IntelIOMMUState *s, VTDContextEntry *ce,
>                */
>               return false;
>           }
> +
> +        if (pasid_entry) {
> +            *pasid_entry = pe;
> +        }
> +
>           return vtd_pe_pgtt_is_pt(&pe);
>       }
>   
> @@ -1689,7 +1694,7 @@ static bool vtd_as_pt_enabled(VTDAddressSpace *as)
>           return false;
>       }
>   
> -    return vtd_dev_pt_enabled(s, &ce, as->pasid);
> +    return vtd_dev_pt_enabled(s, &ce, as->pasid, NULL);
>   }
>   
>   /* Return whether the device is using IOMMU translation. */
> @@ -1701,8 +1706,8 @@ static bool vtd_switch_address_space(VTDAddressSpace *as)
>       assert(as);
>   
>       s = as->iommu_state;
> -    use_iommu = s->dmar_enabled && !vtd_as_pt_enabled(as);
>       pt = s->dmar_enabled && vtd_as_pt_enabled(as);
> +    use_iommu = s->dmar_enabled && !pt;
>   
>       /*
>        * When guest enables scalable mode and sets up first stage page table,
> @@ -1887,23 +1892,34 @@ VTDAddressSpace *vtd_get_as_by_sid(IntelIOMMUState *s, uint16_t sid)
>       return vtd_get_as_by_sid_and_pasid(s, sid, IOMMU_NO_PASID);
>   }
>   
> -static void vtd_pt_enable_fast_path(IntelIOMMUState *s, uint16_t source_id)
> +static bool vtd_try_enable_pt_fast_path(IntelIOMMUState *s,
> +                                        VTDAddressSpace *vtd_as,
> +                                        VTDContextEntry *ce, uint32_t pasid)
>   {
> -    VTDAddressSpace *vtd_as;
> -    bool success = false;
> +    VTDPASIDEntry pe;
>   
> -    vtd_as = vtd_get_as_by_sid(s, source_id);
> -    if (!vtd_as) {
> -        goto out;
> +    if (!vtd_dev_pt_enabled(s, ce, pasid, &pe)) {
> +        return false;
>       }
>   
> -    if (vtd_switch_address_space(vtd_as) == false) {
> -        /* We switched off IOMMU region successfully. */
> -        success = true;
> +    /*
> +     * When this happens, it means firstly caching-mode is not
> +     * enabled, and this is the first passthrough translation for
> +     * the device. Let's enable the fast path for passthrough.
> +     *
> +     * When passthrough is disabled again for the device, we can
> +     * capture it via context-cache invalidation in legacy mode or
> +     * PASID-cache invalidation in scalable mode, then the IOMMU
> +     * region can be swapped back.
> +     */
> +    if (!vtd_switch_address_space(vtd_as) && s->root_scalable) {
> +        VTDPASIDCacheEntry *pc_entry = &vtd_as->pasid_cache_entry;
> +
> +        pc_entry->pasid_entry = pe;
> +        pc_entry->valid = true;
>       }
>   
> -out:
> -    trace_vtd_pt_enable_fast_path(source_id, success);
> +    return true;
>   }
>   
>   /*
> @@ -2167,23 +2183,12 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
>        * We don't need to translate for pass-through context entries.
>        * Also, let's ignore IOTLB caching as well for PT devices.
>        */
> -    if (vtd_dev_pt_enabled(s, &ce, pasid)) {
> +    if (vtd_try_enable_pt_fast_path(s, vtd_as, &ce, pasid)) {
>           entry->iova = addr & VTD_PAGE_MASK_4K;
>           entry->translated_addr = entry->iova;
>           entry->addr_mask = ~VTD_PAGE_MASK_4K;
>           entry->perm = IOMMU_RW;
> -        trace_vtd_translate_pt(source_id, entry->iova);
> -
> -        /*
> -         * When this happens, it means firstly caching-mode is not
> -         * enabled, and this is the first passthrough translation for
> -         * the device. Let's enable the fast path for passthrough.
> -         *
> -         * When passthrough is disabled again for the device, we can
> -         * capture it via the context entry invalidation, then the
> -         * IOMMU region can be swapped back.
> -         */
> -        vtd_pt_enable_fast_path(s, source_id);
> +        trace_vtd_fast_path_translate_pt(source_id, entry->iova);
>           vtd_iommu_unlock(s);
>           return true;
>       }
> @@ -3133,6 +3138,7 @@ static void vtd_pasid_cache_sync_locked(gpointer key, gpointer value,
>               vtd_address_space_unmap(vtd_as, n);
>           }
>           vtd_switch_address_space(vtd_as);
> +        return;
>       }
>   
>       /*
> @@ -3158,11 +3164,11 @@ static void vtd_pasid_cache_sync_locked(gpointer key, gpointer value,
>       }
>   
>       if (!pc_entry->valid) {
> -        pc_entry->pasid_entry = pe;
>           pc_entry->valid = true;
>       } else if (!vtd_pasid_entry_compare(&pe, &pc_entry->pasid_entry)) {
>           return;
>       }
> +    pc_entry->pasid_entry = pe;
>   
>       vtd_switch_address_space(vtd_as);
>       vtd_address_space_sync(vtd_as);
> diff --git a/hw/i386/trace-events b/hw/i386/trace-events
> index 7bf4cddd38..3337a7e19c 100644
> --- a/hw/i386/trace-events
> +++ b/hw/i386/trace-events
> @@ -47,8 +47,7 @@ vtd_page_walk_skip_read(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"P
>   vtd_page_walk_skip_reserve(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to rsrv set"
>   vtd_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)"
>   vtd_as_unmap_whole(uint8_t bus, uint8_t slot, uint8_t fn, uint64_t iova, uint64_t size) "Device %02x:%02x.%x start 0x%"PRIx64" size 0x%"PRIx64
> -vtd_translate_pt(uint16_t sid, uint64_t addr) "source id 0x%"PRIx16", iova 0x%"PRIx64
> -vtd_pt_enable_fast_path(uint16_t sid, bool success) "sid 0x%"PRIx16" %d"
> +vtd_fast_path_translate_pt(uint16_t sid, uint64_t addr) "source id 0x%"PRIx16", iova 0x%"PRIx64
>   vtd_irq_generate(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64
>   vtd_reg_read(uint64_t addr, uint64_t size) "addr 0x%"PRIx64" size 0x%"PRIx64
>   vtd_reg_write(uint64_t addr, uint64_t size, uint64_t val) "addr 0x%"PRIx64" size 0x%"PRIx64" value 0x%"PRIx64



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v3] intel_iommu: Keep PASID cache consistent with PT fast path
  2026-11-12  8:15 [PATCH v3] intel_iommu: Keep PASID cache consistent with PT fast path Zhenzhong Duan
  2026-11-12 12:06 ` Yi Liu
@ 2026-11-13  8:37 ` Clement Mathieu--Drif
  1 sibling, 0 replies; 3+ messages in thread
From: Clement Mathieu--Drif @ 2026-11-13  8:37 UTC (permalink / raw)
  To: Zhenzhong Duan, qemu-devel; +Cc: mst, jasowangio, yi.l.liu

Hi Zhenzhong,

Sending this from another address because of microsoft's outage.

Reviewed-by: Clement Mathieu--Drif <clement.mathieu--drif@bull.com>

Thanks

On Thu, 2026-11-12 at 16:15 +0800, Zhenzhong Duan wrote:
> Caution: External email. Do not open attachments or click links, unless this email comes from a known sender and you know the content is safe.
> 
> 
> With caching mode disabled, a guest can install a scalable-mode  
> pass-through PASID entry without issuing a PASID-cache invalidation. The  
> first DMA enables the PT fast path, but leaves QEMU's PASID cache invalid.
> 
> When the guest tears down that entry to switch back to a DMA domain, the  
> invalidation handler sees both a non-present guest entry and an invalid  
> cached entry and returns without re-enabling the IOMMU memory region.  
> Subsequent DMA therefore continues to bypass translation.
> 
> The issue can be reproduced with an emulated device in scalable mode  
> with caching-mode=off:
> 
> 1. Unbind the guest device driver and change the group's type to  
>    identity through /sys/kernel/iommu_groups/<group>/type.  
> 2. Rebind the driver and issue a DMA write.  
> 3. Unbind the driver, change the group's type back to DMA-FQ, and  
>    rebind the driver.  
> 4. Issue another DMA write using an IOVA mapped to a different GPA.
> 
> The second write incorrectly bypasses translation instead of reaching  
> the mapped GPA.
> 
> Save the PASID entry when enabling the scalable-mode PT fast path so  
> teardown invalidation can restore the IOMMU address space. Return after  
> handling a non-present entry, and refresh the cached entry when a present  
> entry changes, pass vtd_as to vtd_try_enable_pt_fast_path() instead of  
> pick it from PASID 0.
> 
> Opportunistically clarify the invalidation modes in the fast-path comment  
> and merge trace event vtd_translate_pt and vtd_pt_enable_fast_path into  
> vtd_fast_path_translate_pt.
> 
> Fixes: c9cf33075a4c ("intel_iommu: Fix DMA failure when guest switches IOMMU domain")  
> Reported-by: Clement Mathieu--Drif <[clement.mathieu--drif@bull.com](mailto:clement.mathieu--drif@bull.com)>  
> Signed-off-by: Zhenzhong Duan <[zhenzhong.duan@intel.com](mailto:zhenzhong.duan@intel.com)>  
> Tested-by: Clement Mathieu--Drif <[clement.mathieu--drif@bull.com](mailto:clement.mathieu--drif@bull.com)>  
> ---  
> v3:  
> - introduce a new helper vtd_try_enable_pt_fast_path (Clement)  
> v2:  
> - move "VTDPASIDCacheEntry *pc_entry" in the branch it is used (Clement)
> 
>  hw/i386/intel_iommu.c | 62 ++++++++++++++++++++++++-------------------  
>  hw/i386/trace-events  |  3 +--  
>  2 files changed, 35 insertions(+), 30 deletions(-)
> 
> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c  
> index b7da5d086d..a5ff89a11a 100644  
> --- a/hw/i386/intel_iommu.c  
> +++ b/hw/i386/intel_iommu.c  
> @@ -1649,7 +1649,7 @@ static int vtd_address_space_sync(VTDAddressSpace *vtd_as)  
>   * or second stage translation, it depends on PGTT setting.  
>   */  
>  static bool vtd_dev_pt_enabled(IntelIOMMUState *s, VTDContextEntry *ce,  
> -                               uint32_t pasid)  
> +                               uint32_t pasid, VTDPASIDEntry *pasid_entry)  
>  {  
>      VTDPASIDEntry pe;  
>      int ret;  
> @@ -1663,6 +1663,11 @@ static bool vtd_dev_pt_enabled(IntelIOMMUState *s, VTDContextEntry *ce,  
>               */  
>              return false;  
>          }  
> +  
> +        if (pasid_entry) {  
> +            *pasid_entry = pe;  
> +        }  
> +  
>          return vtd_pe_pgtt_is_pt(&pe);  
>      }
> 
> @@ -1689,7 +1694,7 @@ static bool vtd_as_pt_enabled(VTDAddressSpace *as)  
>          return false;  
>      }
> 
> -    return vtd_dev_pt_enabled(s, &ce, as->pasid);  
> +    return vtd_dev_pt_enabled(s, &ce, as->pasid, NULL);  
>  }
> 
>  /* Return whether the device is using IOMMU translation. */  
> @@ -1701,8 +1706,8 @@ static bool vtd_switch_address_space(VTDAddressSpace *as)  
>      assert(as);
> 
>      s = as->iommu_state;  
> -    use_iommu = s->dmar_enabled && !vtd_as_pt_enabled(as);  
>      pt = s->dmar_enabled && vtd_as_pt_enabled(as);  
> +    use_iommu = s->dmar_enabled && !pt;
> 
>      /*  
>       * When guest enables scalable mode and sets up first stage page table,  
> @@ -1887,23 +1892,34 @@ VTDAddressSpace *vtd_get_as_by_sid(IntelIOMMUState *s, uint16_t sid)  
>      return vtd_get_as_by_sid_and_pasid(s, sid, IOMMU_NO_PASID);  
>  }
> 
> -static void vtd_pt_enable_fast_path(IntelIOMMUState *s, uint16_t source_id)  
> +static bool vtd_try_enable_pt_fast_path(IntelIOMMUState *s,  
> +                                        VTDAddressSpace *vtd_as,  
> +                                        VTDContextEntry *ce, uint32_t pasid)  
>  {  
> -    VTDAddressSpace *vtd_as;  
> -    bool success = false;  
> +    VTDPASIDEntry pe;
> 
> -    vtd_as = vtd_get_as_by_sid(s, source_id);  
> -    if (!vtd_as) {  
> -        goto out;  
> +    if (!vtd_dev_pt_enabled(s, ce, pasid, &pe)) {  
> +        return false;  
>      }
> 
> -    if (vtd_switch_address_space(vtd_as) == false) {  
> -        /* We switched off IOMMU region successfully. */  
> -        success = true;  
> +    /*  
> +     * When this happens, it means firstly caching-mode is not  
> +     * enabled, and this is the first passthrough translation for  
> +     * the device. Let's enable the fast path for passthrough.  
> +     *  
> +     * When passthrough is disabled again for the device, we can  
> +     * capture it via context-cache invalidation in legacy mode or  
> +     * PASID-cache invalidation in scalable mode, then the IOMMU  
> +     * region can be swapped back.  
> +     */  
> +    if (!vtd_switch_address_space(vtd_as) && s->root_scalable) {  
> +        VTDPASIDCacheEntry *pc_entry = &vtd_as->pasid_cache_entry;  
> +  
> +        pc_entry->pasid_entry = pe;  
> +        pc_entry->valid = true;  
>      }
> 
> -out:  
> -    trace_vtd_pt_enable_fast_path(source_id, success);  
> +    return true;  
>  }
> 
>  /*  
> @@ -2167,23 +2183,12 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,  
>       * We don't need to translate for pass-through context entries.  
>       * Also, let's ignore IOTLB caching as well for PT devices.  
>       */  
> -    if (vtd_dev_pt_enabled(s, &ce, pasid)) {  
> +    if (vtd_try_enable_pt_fast_path(s, vtd_as, &ce, pasid)) {  
>          entry->iova = addr & VTD_PAGE_MASK_4K;  
>          entry->translated_addr = entry->iova;  
>          entry->addr_mask = ~VTD_PAGE_MASK_4K;  
>          entry->perm = IOMMU_RW;  
> -        trace_vtd_translate_pt(source_id, entry->iova);  
> -  
> -        /*  
> -         * When this happens, it means firstly caching-mode is not  
> -         * enabled, and this is the first passthrough translation for  
> -         * the device. Let's enable the fast path for passthrough.  
> -         *  
> -         * When passthrough is disabled again for the device, we can  
> -         * capture it via the context entry invalidation, then the  
> -         * IOMMU region can be swapped back.  
> -         */  
> -        vtd_pt_enable_fast_path(s, source_id);  
> +        trace_vtd_fast_path_translate_pt(source_id, entry->iova);  
>          vtd_iommu_unlock(s);  
>          return true;  
>      }  
> @@ -3133,6 +3138,7 @@ static void vtd_pasid_cache_sync_locked(gpointer key, gpointer value,  
>              vtd_address_space_unmap(vtd_as, n);  
>          }  
>          vtd_switch_address_space(vtd_as);  
> +        return;  
>      }
> 
>      /*  
> @@ -3158,11 +3164,11 @@ static void vtd_pasid_cache_sync_locked(gpointer key, gpointer value,  
>      }
> 
>      if (!pc_entry->valid) {  
> -        pc_entry->pasid_entry = pe;  
>          pc_entry->valid = true;  
>      } else if (!vtd_pasid_entry_compare(&pe, &pc_entry->pasid_entry)) {  
>          return;  
>      }  
> +    pc_entry->pasid_entry = pe;
> 
>      vtd_switch_address_space(vtd_as);  
>      vtd_address_space_sync(vtd_as);  
> diff --git a/hw/i386/trace-events b/hw/i386/trace-events  
> index 7bf4cddd38..3337a7e19c 100644  
> --- a/hw/i386/trace-events  
> +++ b/hw/i386/trace-events  
> @@ -47,8 +47,7 @@ vtd_page_walk_skip_read(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"P  
>  vtd_page_walk_skip_reserve(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to rsrv set"  
>  vtd_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)"  
>  vtd_as_unmap_whole(uint8_t bus, uint8_t slot, uint8_t fn, uint64_t iova, uint64_t size) "Device %02x:%02x.%x start 0x%"PRIx64" size 0x%"PRIx64  
> -vtd_translate_pt(uint16_t sid, uint64_t addr) "source id 0x%"PRIx16", iova 0x%"PRIx64  
> -vtd_pt_enable_fast_path(uint16_t sid, bool success) "sid 0x%"PRIx16" %d"  
> +vtd_fast_path_translate_pt(uint16_t sid, uint64_t addr) "source id 0x%"PRIx16", iova 0x%"PRIx64  
>  vtd_irq_generate(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64  
>  vtd_reg_read(uint64_t addr, uint64_t size) "addr 0x%"PRIx64" size 0x%"PRIx64  
>  vtd_reg_write(uint64_t addr, uint64_t size, uint64_t val) "addr 0x%"PRIx64" size 0x%"PRIx64" value 0x%"PRIx64  
> --  
> 2.52.0
> 


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-11-13  8:37 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-12  8:15 [PATCH v3] intel_iommu: Keep PASID cache consistent with PT fast path Zhenzhong Duan
2026-11-12 12:06 ` Yi Liu
2026-11-13  8:37 ` Clement Mathieu--Drif

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.