@@ -167,6 +167,7 @@ struct mock_dev {
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 )
@@ -227,6 +228,34 @@ static int mock_domain_set_dev_pasid_nop(struct iommu_domain *domain,
227
228
struct device * dev , ioasid_t pasid ,
228
229
struct iommu_domain * old )
229
230
{
231
+ struct mock_dev * mdev = to_mock_dev (dev );
232
+
233
+ /*
234
+ * Per the first attach with pasid 1024, set the
235
+ * mdev->pasid_1024_fake_error. Hence the second call of this op
236
+ * can fake an error to validate the error path of the core. This
237
+ * is helpful to test the case in which the iommu core needs to
238
+ * rollback to the old domain due to driver failure. e.g. replace.
239
+ * User should be careful about the third call of this op, it shall
240
+ * succeed since the mdev->pasid_1024_fake_error is cleared in the
241
+ * second call.
242
+ */
243
+ if (pasid == 1024 ) {
244
+ if (domain -> type == IOMMU_DOMAIN_BLOCKED ) {
245
+ atomic_set (& mdev -> pasid_1024_fake_error , 0 );
246
+ } else if (atomic_read (& mdev -> pasid_1024_fake_error )) {
247
+ /*
248
+ * Clear the flag, and fake an error to fail the
249
+ * replacement.
250
+ */
251
+ atomic_set (& mdev -> pasid_1024_fake_error , 0 );
252
+ return - ENOMEM ;
253
+ } else {
254
+ /* Set the flag to fake an error in next call */
255
+ atomic_set (& mdev -> pasid_1024_fake_error , 1 );
256
+ }
257
+ }
258
+
230
259
return 0 ;
231
260
}
232
261
@@ -1685,6 +1714,131 @@ static int iommufd_test_trigger_vevent(struct iommufd_ucmd *ucmd,
1685
1714
return rc ;
1686
1715
}
1687
1716
1717
+ static inline struct iommufd_hw_pagetable *
1718
+ iommufd_get_hwpt (struct iommufd_ucmd * ucmd , u32 id )
1719
+ {
1720
+ struct iommufd_object * pt_obj ;
1721
+
1722
+ pt_obj = iommufd_get_object (ucmd -> ictx , id , IOMMUFD_OBJ_ANY );
1723
+ if (IS_ERR (pt_obj ))
1724
+ return ERR_CAST (pt_obj );
1725
+
1726
+ if (pt_obj -> type != IOMMUFD_OBJ_HWPT_NESTED &&
1727
+ pt_obj -> type != IOMMUFD_OBJ_HWPT_PAGING ) {
1728
+ iommufd_put_object (ucmd -> ictx , pt_obj );
1729
+ return ERR_PTR (- EINVAL );
1730
+ }
1731
+
1732
+ return container_of (pt_obj , struct iommufd_hw_pagetable , obj );
1733
+ }
1734
+
1735
+ static int iommufd_test_pasid_check_hwpt (struct iommufd_ucmd * ucmd ,
1736
+ struct iommu_test_cmd * cmd )
1737
+ {
1738
+ u32 hwpt_id = cmd -> pasid_check .hwpt_id ;
1739
+ struct iommu_domain * attached_domain ;
1740
+ struct iommu_attach_handle * handle ;
1741
+ struct iommufd_hw_pagetable * hwpt ;
1742
+ struct selftest_obj * sobj ;
1743
+ struct mock_dev * mdev ;
1744
+ int rc = 0 ;
1745
+
1746
+ sobj = iommufd_test_get_selftest_obj (ucmd -> ictx , cmd -> id );
1747
+ if (IS_ERR (sobj ))
1748
+ return PTR_ERR (sobj );
1749
+
1750
+ mdev = sobj -> idev .mock_dev ;
1751
+
1752
+ handle = iommu_attach_handle_get (mdev -> dev .iommu_group ,
1753
+ cmd -> pasid_check .pasid , 0 );
1754
+ if (IS_ERR (handle ))
1755
+ attached_domain = NULL ;
1756
+ else
1757
+ attached_domain = handle -> domain ;
1758
+
1759
+ /* hwpt_id == 0 means to check if pasid is detached */
1760
+ if (!hwpt_id ) {
1761
+ if (attached_domain )
1762
+ rc = - EINVAL ;
1763
+ goto out_sobj ;
1764
+ }
1765
+
1766
+ hwpt = iommufd_get_hwpt (ucmd , hwpt_id );
1767
+ if (IS_ERR (hwpt )) {
1768
+ rc = PTR_ERR (hwpt );
1769
+ goto out_sobj ;
1770
+ }
1771
+
1772
+ if (attached_domain != hwpt -> domain )
1773
+ rc = - EINVAL ;
1774
+
1775
+ iommufd_put_object (ucmd -> ictx , & hwpt -> obj );
1776
+ out_sobj :
1777
+ iommufd_put_object (ucmd -> ictx , & sobj -> obj );
1778
+ return rc ;
1779
+ }
1780
+
1781
+ static int iommufd_test_pasid_attach (struct iommufd_ucmd * ucmd ,
1782
+ struct iommu_test_cmd * cmd )
1783
+ {
1784
+ struct selftest_obj * sobj ;
1785
+ int rc ;
1786
+
1787
+ sobj = iommufd_test_get_selftest_obj (ucmd -> ictx , cmd -> id );
1788
+ if (IS_ERR (sobj ))
1789
+ return PTR_ERR (sobj );
1790
+
1791
+ rc = iommufd_device_attach (sobj -> idev .idev , cmd -> pasid_attach .pasid ,
1792
+ & cmd -> pasid_attach .pt_id );
1793
+ if (rc )
1794
+ goto out_sobj ;
1795
+
1796
+ rc = iommufd_ucmd_respond (ucmd , sizeof (* cmd ));
1797
+ if (rc )
1798
+ iommufd_device_detach (sobj -> idev .idev ,
1799
+ cmd -> pasid_attach .pasid );
1800
+
1801
+ out_sobj :
1802
+ iommufd_put_object (ucmd -> ictx , & sobj -> obj );
1803
+ return rc ;
1804
+ }
1805
+
1806
+ static int iommufd_test_pasid_replace (struct iommufd_ucmd * ucmd ,
1807
+ struct iommu_test_cmd * cmd )
1808
+ {
1809
+ struct selftest_obj * sobj ;
1810
+ int rc ;
1811
+
1812
+ sobj = iommufd_test_get_selftest_obj (ucmd -> ictx , cmd -> id );
1813
+ if (IS_ERR (sobj ))
1814
+ return PTR_ERR (sobj );
1815
+
1816
+ rc = iommufd_device_replace (sobj -> idev .idev , cmd -> pasid_attach .pasid ,
1817
+ & cmd -> pasid_attach .pt_id );
1818
+ if (rc )
1819
+ goto out_sobj ;
1820
+
1821
+ rc = iommufd_ucmd_respond (ucmd , sizeof (* cmd ));
1822
+
1823
+ out_sobj :
1824
+ iommufd_put_object (ucmd -> ictx , & sobj -> obj );
1825
+ return rc ;
1826
+ }
1827
+
1828
+ static int iommufd_test_pasid_detach (struct iommufd_ucmd * ucmd ,
1829
+ struct iommu_test_cmd * cmd )
1830
+ {
1831
+ struct selftest_obj * sobj ;
1832
+
1833
+ sobj = iommufd_test_get_selftest_obj (ucmd -> ictx , cmd -> id );
1834
+ if (IS_ERR (sobj ))
1835
+ return PTR_ERR (sobj );
1836
+
1837
+ iommufd_device_detach (sobj -> idev .idev , cmd -> pasid_detach .pasid );
1838
+ iommufd_put_object (ucmd -> ictx , & sobj -> obj );
1839
+ return 0 ;
1840
+ }
1841
+
1688
1842
void iommufd_selftest_destroy (struct iommufd_object * obj )
1689
1843
{
1690
1844
struct selftest_obj * sobj = to_selftest_obj (obj );
@@ -1768,6 +1922,14 @@ int iommufd_test(struct iommufd_ucmd *ucmd)
1768
1922
return iommufd_test_trigger_iopf (ucmd , cmd );
1769
1923
case IOMMU_TEST_OP_TRIGGER_VEVENT :
1770
1924
return iommufd_test_trigger_vevent (ucmd , cmd );
1925
+ case IOMMU_TEST_OP_PASID_ATTACH :
1926
+ return iommufd_test_pasid_attach (ucmd , cmd );
1927
+ case IOMMU_TEST_OP_PASID_REPLACE :
1928
+ return iommufd_test_pasid_replace (ucmd , cmd );
1929
+ case IOMMU_TEST_OP_PASID_DETACH :
1930
+ return iommufd_test_pasid_detach (ucmd , cmd );
1931
+ case IOMMU_TEST_OP_PASID_CHECK_HWPT :
1932
+ return iommufd_test_pasid_check_hwpt (ucmd , cmd );
1771
1933
default :
1772
1934
return - EOPNOTSUPP ;
1773
1935
}
0 commit comments