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/selftest: Add test ops to test pasid attach/detach

This adds 4 test ops for pasid attach/replace/detach testing. There are
ops to attach/detach pasid, and also op to check the attached hwpt of a
pasid.

Link: https://patch.msgid.link/r/20250321171940.7213-18-yi.l.liu@intel.com
Reviewed-by: Kevin Tian <kevin.tian@intel.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
c1b52b0a 068e1402

+188
+26
drivers/iommu/iommufd/iommufd_test.h
··· 25 25 IOMMU_TEST_OP_TRIGGER_IOPF, 26 26 IOMMU_TEST_OP_DEV_CHECK_CACHE, 27 27 IOMMU_TEST_OP_TRIGGER_VEVENT, 28 + IOMMU_TEST_OP_PASID_ATTACH, 29 + IOMMU_TEST_OP_PASID_REPLACE, 30 + IOMMU_TEST_OP_PASID_DETACH, 31 + IOMMU_TEST_OP_PASID_CHECK_HWPT, 28 32 }; 29 33 30 34 enum { ··· 65 61 MOCK_DEV_CACHE_ID_MAX = 3, 66 62 MOCK_DEV_CACHE_NUM = 4, 67 63 }; 64 + 65 + /* Reserved for special pasid replace test */ 66 + #define IOMMU_TEST_PASID_RESERVED 1024 68 67 69 68 struct iommu_test_cmd { 70 69 __u32 size; ··· 157 150 struct { 158 151 __u32 dev_id; 159 152 } trigger_vevent; 153 + struct { 154 + __u32 pasid; 155 + __u32 pt_id; 156 + /* @id is stdev_id */ 157 + } pasid_attach; 158 + struct { 159 + __u32 pasid; 160 + __u32 pt_id; 161 + /* @id is stdev_id */ 162 + } pasid_replace; 163 + struct { 164 + __u32 pasid; 165 + /* @id is stdev_id */ 166 + } pasid_detach; 167 + struct { 168 + __u32 pasid; 169 + __u32 hwpt_id; 170 + /* @id is stdev_id */ 171 + } pasid_check; 160 172 }; 161 173 __u32 last; 162 174 };
+162
drivers/iommu/iommufd/selftest.c
··· 167 167 unsigned long vdev_id; 168 168 int id; 169 169 u32 cache[MOCK_DEV_CACHE_NUM]; 170 + atomic_t pasid_1024_fake_error; 170 171 }; 171 172 172 173 static inline struct mock_dev *to_mock_dev(struct device *dev) ··· 228 227 struct device *dev, ioasid_t pasid, 229 228 struct iommu_domain *old) 230 229 { 230 + struct mock_dev *mdev = to_mock_dev(dev); 231 + 232 + /* 233 + * Per the first attach with pasid 1024, set the 234 + * mdev->pasid_1024_fake_error. Hence the second call of this op 235 + * can fake an error to validate the error path of the core. This 236 + * is helpful to test the case in which the iommu core needs to 237 + * rollback to the old domain due to driver failure. e.g. replace. 238 + * User should be careful about the third call of this op, it shall 239 + * succeed since the mdev->pasid_1024_fake_error is cleared in the 240 + * second call. 241 + */ 242 + if (pasid == 1024) { 243 + if (domain->type == IOMMU_DOMAIN_BLOCKED) { 244 + atomic_set(&mdev->pasid_1024_fake_error, 0); 245 + } else if (atomic_read(&mdev->pasid_1024_fake_error)) { 246 + /* 247 + * Clear the flag, and fake an error to fail the 248 + * replacement. 249 + */ 250 + atomic_set(&mdev->pasid_1024_fake_error, 0); 251 + return -ENOMEM; 252 + } else { 253 + /* Set the flag to fake an error in next call */ 254 + atomic_set(&mdev->pasid_1024_fake_error, 1); 255 + } 256 + } 257 + 231 258 return 0; 232 259 } 233 260 ··· 1714 1685 return rc; 1715 1686 } 1716 1687 1688 + static inline struct iommufd_hw_pagetable * 1689 + iommufd_get_hwpt(struct iommufd_ucmd *ucmd, u32 id) 1690 + { 1691 + struct iommufd_object *pt_obj; 1692 + 1693 + pt_obj = iommufd_get_object(ucmd->ictx, id, IOMMUFD_OBJ_ANY); 1694 + if (IS_ERR(pt_obj)) 1695 + return ERR_CAST(pt_obj); 1696 + 1697 + if (pt_obj->type != IOMMUFD_OBJ_HWPT_NESTED && 1698 + pt_obj->type != IOMMUFD_OBJ_HWPT_PAGING) { 1699 + iommufd_put_object(ucmd->ictx, pt_obj); 1700 + return ERR_PTR(-EINVAL); 1701 + } 1702 + 1703 + return container_of(pt_obj, struct iommufd_hw_pagetable, obj); 1704 + } 1705 + 1706 + static int iommufd_test_pasid_check_hwpt(struct iommufd_ucmd *ucmd, 1707 + struct iommu_test_cmd *cmd) 1708 + { 1709 + u32 hwpt_id = cmd->pasid_check.hwpt_id; 1710 + struct iommu_domain *attached_domain; 1711 + struct iommu_attach_handle *handle; 1712 + struct iommufd_hw_pagetable *hwpt; 1713 + struct selftest_obj *sobj; 1714 + struct mock_dev *mdev; 1715 + int rc = 0; 1716 + 1717 + sobj = iommufd_test_get_selftest_obj(ucmd->ictx, cmd->id); 1718 + if (IS_ERR(sobj)) 1719 + return PTR_ERR(sobj); 1720 + 1721 + mdev = sobj->idev.mock_dev; 1722 + 1723 + handle = iommu_attach_handle_get(mdev->dev.iommu_group, 1724 + cmd->pasid_check.pasid, 0); 1725 + if (IS_ERR(handle)) 1726 + attached_domain = NULL; 1727 + else 1728 + attached_domain = handle->domain; 1729 + 1730 + /* hwpt_id == 0 means to check if pasid is detached */ 1731 + if (!hwpt_id) { 1732 + if (attached_domain) 1733 + rc = -EINVAL; 1734 + goto out_sobj; 1735 + } 1736 + 1737 + hwpt = iommufd_get_hwpt(ucmd, hwpt_id); 1738 + if (IS_ERR(hwpt)) { 1739 + rc = PTR_ERR(hwpt); 1740 + goto out_sobj; 1741 + } 1742 + 1743 + if (attached_domain != hwpt->domain) 1744 + rc = -EINVAL; 1745 + 1746 + iommufd_put_object(ucmd->ictx, &hwpt->obj); 1747 + out_sobj: 1748 + iommufd_put_object(ucmd->ictx, &sobj->obj); 1749 + return rc; 1750 + } 1751 + 1752 + static int iommufd_test_pasid_attach(struct iommufd_ucmd *ucmd, 1753 + struct iommu_test_cmd *cmd) 1754 + { 1755 + struct selftest_obj *sobj; 1756 + int rc; 1757 + 1758 + sobj = iommufd_test_get_selftest_obj(ucmd->ictx, cmd->id); 1759 + if (IS_ERR(sobj)) 1760 + return PTR_ERR(sobj); 1761 + 1762 + rc = iommufd_device_attach(sobj->idev.idev, cmd->pasid_attach.pasid, 1763 + &cmd->pasid_attach.pt_id); 1764 + if (rc) 1765 + goto out_sobj; 1766 + 1767 + rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); 1768 + if (rc) 1769 + iommufd_device_detach(sobj->idev.idev, 1770 + cmd->pasid_attach.pasid); 1771 + 1772 + out_sobj: 1773 + iommufd_put_object(ucmd->ictx, &sobj->obj); 1774 + return rc; 1775 + } 1776 + 1777 + static int iommufd_test_pasid_replace(struct iommufd_ucmd *ucmd, 1778 + struct iommu_test_cmd *cmd) 1779 + { 1780 + struct selftest_obj *sobj; 1781 + int rc; 1782 + 1783 + sobj = iommufd_test_get_selftest_obj(ucmd->ictx, cmd->id); 1784 + if (IS_ERR(sobj)) 1785 + return PTR_ERR(sobj); 1786 + 1787 + rc = iommufd_device_replace(sobj->idev.idev, cmd->pasid_attach.pasid, 1788 + &cmd->pasid_attach.pt_id); 1789 + if (rc) 1790 + goto out_sobj; 1791 + 1792 + rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); 1793 + 1794 + out_sobj: 1795 + iommufd_put_object(ucmd->ictx, &sobj->obj); 1796 + return rc; 1797 + } 1798 + 1799 + static int iommufd_test_pasid_detach(struct iommufd_ucmd *ucmd, 1800 + struct iommu_test_cmd *cmd) 1801 + { 1802 + struct selftest_obj *sobj; 1803 + 1804 + sobj = iommufd_test_get_selftest_obj(ucmd->ictx, cmd->id); 1805 + if (IS_ERR(sobj)) 1806 + return PTR_ERR(sobj); 1807 + 1808 + iommufd_device_detach(sobj->idev.idev, cmd->pasid_detach.pasid); 1809 + iommufd_put_object(ucmd->ictx, &sobj->obj); 1810 + return 0; 1811 + } 1812 + 1717 1813 void iommufd_selftest_destroy(struct iommufd_object *obj) 1718 1814 { 1719 1815 struct selftest_obj *sobj = to_selftest_obj(obj); ··· 1922 1768 return iommufd_test_trigger_iopf(ucmd, cmd); 1923 1769 case IOMMU_TEST_OP_TRIGGER_VEVENT: 1924 1770 return iommufd_test_trigger_vevent(ucmd, cmd); 1771 + case IOMMU_TEST_OP_PASID_ATTACH: 1772 + return iommufd_test_pasid_attach(ucmd, cmd); 1773 + case IOMMU_TEST_OP_PASID_REPLACE: 1774 + return iommufd_test_pasid_replace(ucmd, cmd); 1775 + case IOMMU_TEST_OP_PASID_DETACH: 1776 + return iommufd_test_pasid_detach(ucmd, cmd); 1777 + case IOMMU_TEST_OP_PASID_CHECK_HWPT: 1778 + return iommufd_test_pasid_check_hwpt(ucmd, cmd); 1925 1779 default: 1926 1780 return -EOPNOTSUPP; 1927 1781 }