@@ -167,6 +167,7 @@ struct mock_dev {
167167 unsigned long vdev_id ;
168168 int id ;
169169 u32 cache [MOCK_DEV_CACHE_NUM ];
170+ atomic_t pasid_1024_fake_error ;
170171};
171172
172173static 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,
227228 struct device * dev , ioasid_t pasid ,
228229 struct iommu_domain * old )
229230{
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+
230259 return 0 ;
231260}
232261
@@ -1685,6 +1714,131 @@ static int iommufd_test_trigger_vevent(struct iommufd_ucmd *ucmd,
16851714 return rc ;
16861715}
16871716
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+
16881842void iommufd_selftest_destroy (struct iommufd_object * obj )
16891843{
16901844 struct selftest_obj * sobj = to_selftest_obj (obj );
@@ -1768,6 +1922,14 @@ int iommufd_test(struct iommufd_ucmd *ucmd)
17681922 return iommufd_test_trigger_iopf (ucmd , cmd );
17691923 case IOMMU_TEST_OP_TRIGGER_VEVENT :
17701924 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 );
17711933 default :
17721934 return - EOPNOTSUPP ;
17731935 }
0 commit comments