Skip to content

Commit c1b52b0

Browse files
yiliu1765jgunthorpe
authored andcommitted
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/[email protected] Reviewed-by: Kevin Tian <[email protected]> Signed-off-by: Yi Liu <[email protected]> Tested-by: Nicolin Chen <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 068e140 commit c1b52b0

File tree

2 files changed

+188
-0
lines changed

2 files changed

+188
-0
lines changed

drivers/iommu/iommufd/iommufd_test.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ enum {
2525
IOMMU_TEST_OP_TRIGGER_IOPF,
2626
IOMMU_TEST_OP_DEV_CHECK_CACHE,
2727
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,
2832
};
2933

3034
enum {
@@ -62,6 +66,9 @@ enum {
6266
MOCK_DEV_CACHE_NUM = 4,
6367
};
6468

69+
/* Reserved for special pasid replace test */
70+
#define IOMMU_TEST_PASID_RESERVED 1024
71+
6572
struct iommu_test_cmd {
6673
__u32 size;
6774
__u32 op;
@@ -150,6 +157,25 @@ struct iommu_test_cmd {
150157
struct {
151158
__u32 dev_id;
152159
} trigger_vevent;
160+
struct {
161+
__u32 pasid;
162+
__u32 pt_id;
163+
/* @id is stdev_id */
164+
} pasid_attach;
165+
struct {
166+
__u32 pasid;
167+
__u32 pt_id;
168+
/* @id is stdev_id */
169+
} pasid_replace;
170+
struct {
171+
__u32 pasid;
172+
/* @id is stdev_id */
173+
} pasid_detach;
174+
struct {
175+
__u32 pasid;
176+
__u32 hwpt_id;
177+
/* @id is stdev_id */
178+
} pasid_check;
153179
};
154180
__u32 last;
155181
};

drivers/iommu/iommufd/selftest.c

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

172173
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,
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+
16881842
void 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

Comments
 (0)