@samitouri / QOSamiQemu / commits / 659275f846

hw/vfio/iommufd: Control dirty tracking for nesting parent HWPT

QEMU smmuv3 accel does not support live migration yet, so dirty tracking for the nesting parent HWPT is not useful. Also, nested vIOMMU use cases can break on some platforms. For example, SMMUv3 with HTTU may advertise dirty tracking capability, but the kernel supports it only for stage-1. Requesting dirty tracking for a nesting parent HWPT (stage-2) can fail. Add a vIOMMU flag to explicitly request dirty tracking for the nesting parent HWPT. For nested cases, dirty tracking is enabled only when requested by the vIOMMU. Non-nested cases and Intel vIOMMU keep the existing behavior. Fixes: fc6dafb98cec ("hw/arm/smmuv3: Implement get_viommu_cap() callback") Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com> Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com> Link: https://lore.kernel.org/qemu-devel/20260401084133.56266-1-skolothumtho@nvidia.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Shameer Kolothum committed Apr 1, 2026 at 09:41 UTC 659275f84694e7b06d67d877137905d371a3fde4
5 files changed +28 -4
hw/i386/intel_iommu.c
+5 -2
@@ -4825,9 +4825,12 @@ static void vtd_dev_unset_iommu_device(PCIBus *bus, void *opaque, int devfn)
4825 static uint64_t vtd_get_viommu_flags(void *opaque)
4826 {
4827 IntelIOMMUState *s = opaque;
4828 - uint64_t flags;
4828 + uint64_t flags = 0;
4829
4830 - flags = s->fsts ? VIOMMU_FLAG_WANT_NESTING_PARENT : 0;
4830 + if (s->fsts) {
4831 + flags = VIOMMU_FLAG_WANT_NESTING_PARENT |
4832 + VIOMMU_FLAG_WANT_NESTING_DIRTY_TRACKING;
4833 + }
4834
4835 return flags;
4836 }
hw/vfio/device.c
+11
@@ -522,6 +522,17 @@ void vfio_device_unprepare(VFIODevice *vbasedev)
522 vbasedev->bcontainer = NULL;
523 }
524
525 +bool vfio_device_get_viommu_flags_want_nesting_dirty(VFIODevice *vbasedev)
526 +{
527 + VFIOPCIDevice *vdev = vfio_pci_from_vfio_device(vbasedev);
528 +
529 + if (vdev) {
530 + return !!(pci_device_get_viommu_flags(PCI_DEVICE(vdev)) &
531 + VIOMMU_FLAG_WANT_NESTING_DIRTY_TRACKING);
532 + }
533 + return false;
534 +}
535 +
536 bool vfio_device_get_viommu_flags_want_nesting(VFIODevice *vbasedev)
537 {
538 VFIOPCIDevice *vdev = vfio_pci_from_vfio_device(vbasedev);
hw/vfio/iommufd.c
+9 -2
@@ -352,6 +352,7 @@ static bool iommufd_cdev_autodomains_get(VFIODevice *vbasedev,
352 ERRP_GUARD();
353 IOMMUFDBackend *iommufd = vbasedev->iommufd;
354 VFIOContainer *bcontainer = VFIO_IOMMU(container);
355 + bool viommu_nesting, viommu_nesting_dirty;
356 uint32_t type, flags = 0;
357 uint64_t hw_caps;
358 VendorCaps caps;
@@ -405,8 +406,14 @@ static bool iommufd_cdev_autodomains_get(VFIODevice *vbasedev,
406 return false;
407 }
408
409 + viommu_nesting = vfio_device_get_viommu_flags_want_nesting(vbasedev);
410 + viommu_nesting_dirty =
411 + vfio_device_get_viommu_flags_want_nesting_dirty(vbasedev);
412 +
413 if (hw_caps & IOMMU_HW_CAP_DIRTY_TRACKING) {
409 - flags = IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
414 + if (!viommu_nesting || viommu_nesting_dirty) {
415 + flags |= IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
416 + }
417 }
418
419 /*
@@ -414,7 +421,7 @@ static bool iommufd_cdev_autodomains_get(VFIODevice *vbasedev,
421 * force to create it so that it could be reused by vIOMMU to create
422 * nested HWPT.
423 */
417 - if (vfio_device_get_viommu_flags_want_nesting(vbasedev)) {
424 + if (viommu_nesting) {
425 flags |= IOMMU_HWPT_ALLOC_NEST_PARENT;
426
427 if (vfio_device_get_host_iommu_quirk_bypass_ro(vbasedev, type,
include/hw/core/iommu.h
+2
@@ -21,6 +21,8 @@ enum viommu_flags {
21 /* vIOMMU needs nesting parent HWPT to create nested HWPT */
22 VIOMMU_FLAG_WANT_NESTING_PARENT = BIT_ULL(0),
23 VIOMMU_FLAG_PASID_SUPPORTED = BIT_ULL(1),
24 + /* vIOMMU needs dirty tracking on the nesting parent HWPT for nested use */
25 + VIOMMU_FLAG_WANT_NESTING_DIRTY_TRACKING = BIT_ULL(2),
26 };
27
28 /* Host IOMMU quirks. Extracted from host IOMMU capabilities */
include/hw/vfio/vfio-device.h
+1
@@ -268,6 +268,7 @@ void vfio_device_prepare(VFIODevice *vbasedev, VFIOContainer *bcontainer,
268 void vfio_device_unprepare(VFIODevice *vbasedev);
269
270 bool vfio_device_get_viommu_flags_want_nesting(VFIODevice *vbasedev);
271 +bool vfio_device_get_viommu_flags_want_nesting_dirty(VFIODevice *vbasedev);
272 bool vfio_device_get_host_iommu_quirk_bypass_ro(VFIODevice *vbasedev,
273 uint32_t type, void *caps,
274 uint32_t size);