From: Liu, Yi L yi.l.liu@intel.com Sent: Thursday, May 11, 2023 10:51 PM
This is needed as the stage-1 page table of the nested domain is maintained outside the iommu subsystem, hence, needs to support iotlb flush requests.
This adds the data structure for flushing iotlb for the nested domain allocated with IOMMU_HWPT_TYPE_VTD_S1 type and the related callback to accept iotlb flush request from IOMMUFD.
This only exposes the interface for invalidating IOTLB, but no for device-TLB as device-TLB invalidation will be covered automatically in IOTLB invalidation if the affected device is ATS-capable.
Signed-off-by: Lu Baolu baolu.lu@linux.intel.com Signed-off-by: Yi Liu yi.l.liu@intel.com
Following how you split patches in former part of the series this should be split into three patches: one to introduce the uAPI changes, the 2nd to export symbols and the last to actually add iotlb flush.
+static int intel_nested_cache_invalidate_user(struct iommu_domain *domain,
void *user_data)
+{
- struct iommu_hwpt_invalidate_request_intel_vtd *req = user_data;
- struct iommu_hwpt_invalidate_intel_vtd *inv_info = user_data;
- struct dmar_domain *dmar_domain = to_dmar_domain(domain);
- unsigned int entry_size = inv_info->entry_size;
- u64 uptr = inv_info->inv_data_uptr;
- u64 nr_uptr = inv_info->entry_nr_uptr;
- struct device_domain_info *info;
- u32 entry_nr, index;
- unsigned long flags;
- int ret = 0;
- if (WARN_ON(!user_data))
return 0;
WARN_ON should lead to error returned.
- if (get_user(entry_nr, (uint32_t __user *)u64_to_user_ptr(nr_uptr)))
return -EFAULT;
- if (!entry_nr)
return -EINVAL;
Having zero number of entries is instead not an error. Just means no work to do.
- for (index = 0; index < entry_nr; index++) {
ret = copy_struct_from_user(req, sizeof(*req),
u64_to_user_ptr(uptr + index *
entry_size),
entry_size);
if (ret) {
pr_err_ratelimited("Failed to fetch invalidation
request\n");
break;
}
if (req->__reserved || (req->flags &
~IOMMU_VTD_QI_FLAGS_LEAF) ||
!IS_ALIGNED(req->addr, VTD_PAGE_SIZE)) {
ret = -EINVAL;
break;
}
spin_lock_irqsave(&dmar_domain->lock, flags);
list_for_each_entry(info, &dmar_domain->devices, link)
intel_nested_invalidate(info->dev, dmar_domain,
req->addr, req->npages);
spin_unlock_irqrestore(&dmar_domain->lock, flags);
- }
- if (ret && put_user(index, (uint32_t __user
*)u64_to_user_ptr(nr_uptr)))
return -EFAULT;
You want to always update the nr no matter success or failure
diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c index 39922f83ce34..b338b082950b 100644 --- a/drivers/iommu/iommufd/main.c +++ b/drivers/iommu/iommufd/main.c @@ -282,6 +282,12 @@ union ucmd_buffer { #ifdef CONFIG_IOMMUFD_TEST struct iommu_test_cmd test; #endif
- /*
* hwpt_type specific structure used in the cache invalidation
* path.
*/
- struct iommu_hwpt_invalidate_intel_vtd vtd;
- struct iommu_hwpt_invalidate_request_intel_vtd req_vtd;
};
Can you add some explanation in commit msg why such vendor specific structures must be put in the generic ucmd_buffer?
+/**
- enum iommu_hwpt_intel_vtd_invalidate_flags - Flags for Intel VT-d
enum iommu_hwpt_vtd_s1_invalidate_flags
stage-1 page table cache
invalidation
- @IOMMU_VTD_QI_FLAGS_LEAF: The LEAF flag indicates whether only the
leaf PTE caching needs to be invalidated
and other paging structure caches can be
preserved.
- */
what about "Drain Reads" and "Drain Writes"? Is the user allowed/required to provide those hints?
+/**
- struct iommu_hwpt_invalidate_request_intel_vtd - Intel VT-d cache
invalidation request
here you put "intel_vtd" in the end of the name. let's follow the same order as earlier definitions.
struct iommu_hwpt_vtd_s1_invalidate_desc
- @addr: The start address of the addresses to be invalidated.
- @npages: Number of contiguous 4K pages to be invalidated.
- @flags: Combination of enum iommu_hwpt_intel_vtd_invalidate_flags
- @__reserved: Must be 0
- The Intel VT-d specific invalidation data for user-managed stage-1 cache
- invalidation under nested translation. Userspace uses this structure to
- tell host about the impacted caches after modifying the stage-1 page
table.
- Invalidating all the caches related to the hw_pagetable by setting
- @addr==0 and @npages==__u64(-1).
- */
+struct iommu_hwpt_invalidate_request_intel_vtd {
- __u64 addr;
- __u64 npages;
- __u32 flags;
- __u32 __reserved;
+};
+/**
- struct iommu_hwpt_invalidate_intel_vtd - Intel VT-d cache invalidation
info
iommu_hwpt_vtd_s1_invalidate
- @flags: Must be 0
- @entry_size: Size in bytes of each cache invalidation request
- @entry_nr_uptr: User pointer to the number of invalidation requests.
Kernel reads it to get the number of requests and
updates the buffer with the number of requests that
have been processed successfully. This pointer must
point to a __u32 type of memory location.
- @inv_data_uptr: Pointer to the cache invalidation requests
- The Intel VT-d specific invalidation data for a set of cache invalidation
- requests. Kernel loops the requests one-by-one and stops when failure
- is encountered. The number of handled requests is reported to user by
- writing the buffer pointed by @entry_nr_uptr.
- */
+struct iommu_hwpt_invalidate_intel_vtd {
- __u32 flags;
- __u32 entry_size;
- __u64 entry_nr_uptr;
- __u64 inv_data_uptr;
+};
/**
- struct iommu_hwpt_invalidate - ioctl(IOMMU_HWPT_INVALIDATE)
- @size: sizeof(struct iommu_hwpt_invalidate)
@@ -520,6 +577,8 @@ struct iommu_hw_info {
+==============================+================================ ========+
- | @hwpt_type | Data structure in @data_uptr |
- +------------------------------+----------------------------------------+
- | IOMMU_HWPT_TYPE_VTD_S1 | struct
iommu_hwpt_invalidate_intel_vtd |
*/
- +------------------------------+----------------------------------------+
struct iommu_hwpt_invalidate { __u32 size; -- 2.34.1