[PATCH v4 6/6] iommu/vt-d: Convert nested cache invalidation to the core array loop
From: Nicolin Chen <hidden>
Date: 2026-07-14 18:49:58
Also in:
linux-iommu, lkml
Subsystem:
intel iommu (vt-d), iommu subsystem, the rest · Maintainers:
David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon, Linus Torvalds
intel_nested_cache_invalidate_user() used to walk the whole request array on its own, copying and then flushing one single entry at a time. The iommufd core now iterates the request array itself and re-invokes the op with the not-yet-handled sub-array, so handle just a single request per call out of the front of that sub-array and report one handled entry via the array->entry_num. An empty array keeps returning a success, used as a probe of IOMMU_HWPT_INVALIDATE_DATA_VTD_S1 support. Reviewed-by: Kevin Tian <kevin.tian@intel.com> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Nicolin Chen <redacted> --- drivers/iommu/intel/nested.c | 54 ++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 24 deletions(-)
diff --git a/drivers/iommu/intel/nested.c b/drivers/iommu/intel/nested.c
index 2b979bec56cef..36e0e8e85c065 100644
--- a/drivers/iommu/intel/nested.c
+++ b/drivers/iommu/intel/nested.c@@ -93,7 +93,7 @@ static int intel_nested_cache_invalidate_user(struct iommu_domain *domain, { struct dmar_domain *dmar_domain = to_dmar_domain(domain); struct iommu_hwpt_vtd_s1_invalidate inv_entry; - u32 index, processed = 0; + u32 processed = 0; int ret = 0; if (array->type != IOMMU_HWPT_INVALIDATE_DATA_VTD_S1) {
@@ -101,31 +101,37 @@ static int intel_nested_cache_invalidate_user(struct iommu_domain *domain, goto out; } - for (index = 0; index < array->entry_num; index++) { - ret = iommu_copy_struct_from_user_array(&inv_entry, array, - IOMMU_HWPT_INVALIDATE_DATA_VTD_S1, - index, __reserved); - if (ret) - break; - - if ((inv_entry.flags & ~IOMMU_VTD_INV_FLAGS_LEAF) || - inv_entry.__reserved) { - ret = -EOPNOTSUPP; - break; - } - - if (!IS_ALIGNED(inv_entry.addr, VTD_PAGE_SIZE) || - ((inv_entry.npages == U64_MAX) && inv_entry.addr)) { - ret = -EINVAL; - break; - } - - cache_tag_flush_range(dmar_domain, inv_entry.addr, - inv_entry.addr + nrpages_to_size(inv_entry.npages) - 1, - inv_entry.flags & IOMMU_VTD_INV_FLAGS_LEAF); - processed++; + /* + * The core re-invokes this op for the remaining requests, so handle one + * request per call. A zero-length array only probes the type, validated + * above. + */ + if (!array->entry_num) + return 0; + + ret = iommu_copy_struct_from_user_array( + &inv_entry, array, IOMMU_HWPT_INVALIDATE_DATA_VTD_S1, 0, + __reserved); + if (ret) + goto out; + + if ((inv_entry.flags & ~IOMMU_VTD_INV_FLAGS_LEAF) || + inv_entry.__reserved) { + ret = -EOPNOTSUPP; + goto out; + } + + if (!IS_ALIGNED(inv_entry.addr, VTD_PAGE_SIZE) || + (inv_entry.npages == U64_MAX && inv_entry.addr)) { + ret = -EINVAL; + goto out; } + cache_tag_flush_range(dmar_domain, inv_entry.addr, + inv_entry.addr + + nrpages_to_size(inv_entry.npages) - 1, + inv_entry.flags & IOMMU_VTD_INV_FLAGS_LEAF); + processed = 1; out: array->entry_num = processed; return ret;
--
2.43.0