Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iommufd: Support pasid attach/replace

This extends the below APIs to support PASID. Device drivers to manage pasid
attach/replace/detach.

int iommufd_device_attach(struct iommufd_device *idev,
ioasid_t pasid, u32 *pt_id);
int iommufd_device_replace(struct iommufd_device *idev,
ioasid_t pasid, u32 *pt_id);
void iommufd_device_detach(struct iommufd_device *idev,
ioasid_t pasid);

The pasid operations share underlying attach/replace/detach infrastructure
with the device operations, but still have some different implications:

- no reserved region per pasid otherwise SVA architecture is already
broken (CPU address space doesn't count device reserved regions);

- accordingly no sw_msi trick;

Cache coherency enforcement is still applied to pasid operations since
it is about memory accesses post page table walking (no matter the walk
is per RID or per PASID).

Link: https://patch.msgid.link/r/20250321171940.7213-12-yi.l.liu@intel.com
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>

authored by

Yi Liu and committed by
Jason Gunthorpe
2fb69c60 ff3f014e

+53 -33
+37 -22
drivers/iommu/iommufd/device.c
··· 428 428 } 429 429 430 430 handle->idev = idev; 431 - WARN_ON(pasid != IOMMU_NO_PASID); 432 - rc = iommu_attach_group_handle(hwpt->domain, idev->igroup->group, 433 - &handle->handle); 431 + if (pasid == IOMMU_NO_PASID) 432 + rc = iommu_attach_group_handle(hwpt->domain, idev->igroup->group, 433 + &handle->handle); 434 + else 435 + rc = iommu_attach_device_pasid(hwpt->domain, idev->dev, pasid, 436 + &handle->handle); 434 437 if (rc) 435 438 goto out_disable_iopf; 436 439 ··· 467 464 { 468 465 struct iommufd_attach_handle *handle; 469 466 470 - WARN_ON(pasid != IOMMU_NO_PASID); 471 - 472 467 handle = iommufd_device_get_attach_handle(idev, pasid); 473 - iommu_detach_group_handle(hwpt->domain, idev->igroup->group); 468 + if (pasid == IOMMU_NO_PASID) 469 + iommu_detach_group_handle(hwpt->domain, idev->igroup->group); 470 + else 471 + iommu_detach_device_pasid(hwpt->domain, idev->dev, pasid); 472 + 474 473 if (hwpt->fault) { 475 474 iommufd_auto_response_faults(hwpt, handle); 476 475 iommufd_fault_iopf_disable(idev); ··· 487 482 { 488 483 struct iommufd_attach_handle *handle, *old_handle; 489 484 int rc; 490 - 491 - WARN_ON(pasid != IOMMU_NO_PASID); 492 485 493 486 rc = iommufd_hwpt_pasid_compat(hwpt, idev, pasid); 494 487 if (rc) ··· 505 502 } 506 503 507 504 handle->idev = idev; 508 - rc = iommu_replace_group_handle(idev->igroup->group, hwpt->domain, 509 - &handle->handle); 505 + if (pasid == IOMMU_NO_PASID) 506 + rc = iommu_replace_group_handle(idev->igroup->group, 507 + hwpt->domain, &handle->handle); 508 + else 509 + rc = iommu_replace_device_pasid(hwpt->domain, idev->dev, 510 + pasid, &handle->handle); 510 511 if (rc) 511 512 goto out_disable_iopf; 512 513 ··· 911 904 } 912 905 913 906 /** 914 - * iommufd_device_attach - Connect a device to an iommu_domain 907 + * iommufd_device_attach - Connect a device/pasid to an iommu_domain 915 908 * @idev: device to attach 909 + * @pasid: pasid to attach 916 910 * @pt_id: Input a IOMMUFD_OBJ_IOAS, or IOMMUFD_OBJ_HWPT_PAGING 917 911 * Output the IOMMUFD_OBJ_HWPT_PAGING ID 918 912 * 919 - * This connects the device to an iommu_domain, either automatically or manually 920 - * selected. Once this completes the device could do DMA. 913 + * This connects the device/pasid to an iommu_domain, either automatically 914 + * or manually selected. Once this completes the device could do DMA with 915 + * @pasid. @pasid is IOMMU_NO_PASID if this attach is for no pasid usage. 921 916 * 922 917 * The caller should return the resulting pt_id back to userspace. 923 918 * This function is undone by calling iommufd_device_detach(). 924 919 */ 925 - int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id) 920 + int iommufd_device_attach(struct iommufd_device *idev, ioasid_t pasid, 921 + u32 *pt_id) 926 922 { 927 923 int rc; 928 924 929 - rc = iommufd_device_change_pt(idev, IOMMU_NO_PASID, pt_id, 925 + rc = iommufd_device_change_pt(idev, pasid, pt_id, 930 926 &iommufd_device_do_attach); 931 927 if (rc) 932 928 return rc; ··· 944 934 EXPORT_SYMBOL_NS_GPL(iommufd_device_attach, "IOMMUFD"); 945 935 946 936 /** 947 - * iommufd_device_replace - Change the device's iommu_domain 937 + * iommufd_device_replace - Change the device/pasid's iommu_domain 948 938 * @idev: device to change 939 + * @pasid: pasid to change 949 940 * @pt_id: Input a IOMMUFD_OBJ_IOAS, or IOMMUFD_OBJ_HWPT_PAGING 950 941 * Output the IOMMUFD_OBJ_HWPT_PAGING ID 951 942 * ··· 957 946 * 958 947 * If it fails then no change is made to the attachment. The iommu driver may 959 948 * implement this so there is no disruption in translation. This can only be 960 - * called if iommufd_device_attach() has already succeeded. 949 + * called if iommufd_device_attach() has already succeeded. @pasid is 950 + * IOMMU_NO_PASID for no pasid usage. 961 951 */ 962 - int iommufd_device_replace(struct iommufd_device *idev, u32 *pt_id) 952 + int iommufd_device_replace(struct iommufd_device *idev, ioasid_t pasid, 953 + u32 *pt_id) 963 954 { 964 - return iommufd_device_change_pt(idev, IOMMU_NO_PASID, pt_id, 955 + return iommufd_device_change_pt(idev, pasid, pt_id, 965 956 &iommufd_device_do_replace); 966 957 } 967 958 EXPORT_SYMBOL_NS_GPL(iommufd_device_replace, "IOMMUFD"); 968 959 969 960 /** 970 - * iommufd_device_detach - Disconnect a device to an iommu_domain 961 + * iommufd_device_detach - Disconnect a device/device to an iommu_domain 971 962 * @idev: device to detach 963 + * @pasid: pasid to detach 972 964 * 973 965 * Undo iommufd_device_attach(). This disconnects the idev from the previously 974 966 * attached pt_id. The device returns back to a blocked DMA translation. 967 + * @pasid is IOMMU_NO_PASID for no pasid usage. 975 968 */ 976 - void iommufd_device_detach(struct iommufd_device *idev) 969 + void iommufd_device_detach(struct iommufd_device *idev, ioasid_t pasid) 977 970 { 978 971 struct iommufd_hw_pagetable *hwpt; 979 972 980 - hwpt = iommufd_hw_pagetable_detach(idev, IOMMU_NO_PASID); 973 + hwpt = iommufd_hw_pagetable_detach(idev, pasid); 981 974 iommufd_hw_pagetable_put(idev->ictx, hwpt); 982 975 refcount_dec(&idev->obj.users); 983 976 }
+4 -4
drivers/iommu/iommufd/selftest.c
··· 945 945 } 946 946 sobj->idev.idev = idev; 947 947 948 - rc = iommufd_device_attach(idev, &pt_id); 948 + rc = iommufd_device_attach(idev, IOMMU_NO_PASID, &pt_id); 949 949 if (rc) 950 950 goto out_unbind; 951 951 ··· 960 960 return 0; 961 961 962 962 out_detach: 963 - iommufd_device_detach(idev); 963 + iommufd_device_detach(idev, IOMMU_NO_PASID); 964 964 out_unbind: 965 965 iommufd_device_unbind(idev); 966 966 out_mdev: ··· 994 994 goto out_dev_obj; 995 995 } 996 996 997 - rc = iommufd_device_replace(sobj->idev.idev, &pt_id); 997 + rc = iommufd_device_replace(sobj->idev.idev, IOMMU_NO_PASID, &pt_id); 998 998 if (rc) 999 999 goto out_dev_obj; 1000 1000 ··· 1655 1655 1656 1656 switch (sobj->type) { 1657 1657 case TYPE_IDEV: 1658 - iommufd_device_detach(sobj->idev.idev); 1658 + iommufd_device_detach(sobj->idev.idev, IOMMU_NO_PASID); 1659 1659 iommufd_device_unbind(sobj->idev.idev); 1660 1660 mock_dev_destroy(sobj->idev.mock_dev); 1661 1661 break;
+6 -4
drivers/vfio/iommufd.c
··· 128 128 lockdep_assert_held(&vdev->dev_set->lock); 129 129 130 130 if (vdev->iommufd_attached) { 131 - iommufd_device_detach(vdev->iommufd_device); 131 + iommufd_device_detach(vdev->iommufd_device, IOMMU_NO_PASID); 132 132 vdev->iommufd_attached = false; 133 133 } 134 134 iommufd_device_unbind(vdev->iommufd_device); ··· 146 146 return -EINVAL; 147 147 148 148 if (vdev->iommufd_attached) 149 - rc = iommufd_device_replace(vdev->iommufd_device, pt_id); 149 + rc = iommufd_device_replace(vdev->iommufd_device, 150 + IOMMU_NO_PASID, pt_id); 150 151 else 151 - rc = iommufd_device_attach(vdev->iommufd_device, pt_id); 152 + rc = iommufd_device_attach(vdev->iommufd_device, 153 + IOMMU_NO_PASID, pt_id); 152 154 if (rc) 153 155 return rc; 154 156 vdev->iommufd_attached = true; ··· 165 163 if (WARN_ON(!vdev->iommufd_device) || !vdev->iommufd_attached) 166 164 return; 167 165 168 - iommufd_device_detach(vdev->iommufd_device); 166 + iommufd_device_detach(vdev->iommufd_device, IOMMU_NO_PASID); 169 167 vdev->iommufd_attached = false; 170 168 } 171 169 EXPORT_SYMBOL_GPL(vfio_iommufd_physical_detach_ioas);
+6 -3
include/linux/iommufd.h
··· 8 8 9 9 #include <linux/err.h> 10 10 #include <linux/errno.h> 11 + #include <linux/iommu.h> 11 12 #include <linux/refcount.h> 12 13 #include <linux/types.h> 13 14 #include <linux/xarray.h> ··· 55 54 struct device *dev, u32 *id); 56 55 void iommufd_device_unbind(struct iommufd_device *idev); 57 56 58 - int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id); 59 - int iommufd_device_replace(struct iommufd_device *idev, u32 *pt_id); 60 - void iommufd_device_detach(struct iommufd_device *idev); 57 + int iommufd_device_attach(struct iommufd_device *idev, ioasid_t pasid, 58 + u32 *pt_id); 59 + int iommufd_device_replace(struct iommufd_device *idev, ioasid_t pasid, 60 + u32 *pt_id); 61 + void iommufd_device_detach(struct iommufd_device *idev, ioasid_t pasid); 61 62 62 63 struct iommufd_ctx *iommufd_device_to_ictx(struct iommufd_device *idev); 63 64 u32 iommufd_device_to_id(struct iommufd_device *idev);