Skip to content

Commit ddee199

Browse files
LuBaolujgunthorpe
authored andcommitted
iommufd/selftest: Add IOPF support for mock device
Extend the selftest mock device to support generating and responding to an IOPF. Also add an ioctl interface to userspace applications to trigger the IOPF on the mock device. This would allow userspace applications to test the IOMMUFD's handling of IOPFs without having to rely on any real hardware. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Lu Baolu <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 34765cb commit ddee199

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

drivers/iommu/iommufd/iommufd_test.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ enum {
2222
IOMMU_TEST_OP_MOCK_DOMAIN_FLAGS,
2323
IOMMU_TEST_OP_DIRTY,
2424
IOMMU_TEST_OP_MD_CHECK_IOTLB,
25+
IOMMU_TEST_OP_TRIGGER_IOPF,
2526
};
2627

2728
enum {
@@ -127,6 +128,13 @@ struct iommu_test_cmd {
127128
__u32 id;
128129
__u32 iotlb;
129130
} check_iotlb;
131+
struct {
132+
__u32 dev_id;
133+
__u32 pasid;
134+
__u32 grpid;
135+
__u32 perm;
136+
__u64 addr;
137+
} trigger_iopf;
130138
};
131139
__u32 last;
132140
};

drivers/iommu/iommufd/selftest.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,8 @@ static bool mock_domain_capable(struct device *dev, enum iommu_cap cap)
504504
return false;
505505
}
506506

507+
static struct iopf_queue *mock_iommu_iopf_queue;
508+
507509
static struct iommu_device mock_iommu_device = {
508510
};
509511

@@ -514,6 +516,29 @@ static struct iommu_device *mock_probe_device(struct device *dev)
514516
return &mock_iommu_device;
515517
}
516518

519+
static void mock_domain_page_response(struct device *dev, struct iopf_fault *evt,
520+
struct iommu_page_response *msg)
521+
{
522+
}
523+
524+
static int mock_dev_enable_feat(struct device *dev, enum iommu_dev_features feat)
525+
{
526+
if (feat != IOMMU_DEV_FEAT_IOPF || !mock_iommu_iopf_queue)
527+
return -ENODEV;
528+
529+
return iopf_queue_add_device(mock_iommu_iopf_queue, dev);
530+
}
531+
532+
static int mock_dev_disable_feat(struct device *dev, enum iommu_dev_features feat)
533+
{
534+
if (feat != IOMMU_DEV_FEAT_IOPF || !mock_iommu_iopf_queue)
535+
return -ENODEV;
536+
537+
iopf_queue_remove_device(mock_iommu_iopf_queue, dev);
538+
539+
return 0;
540+
}
541+
517542
static const struct iommu_ops mock_ops = {
518543
/*
519544
* IOMMU_DOMAIN_BLOCKED cannot be returned from def_domain_type()
@@ -529,6 +554,10 @@ static const struct iommu_ops mock_ops = {
529554
.capable = mock_domain_capable,
530555
.device_group = generic_device_group,
531556
.probe_device = mock_probe_device,
557+
.page_response = mock_domain_page_response,
558+
.dev_enable_feat = mock_dev_enable_feat,
559+
.dev_disable_feat = mock_dev_disable_feat,
560+
.user_pasid_table = true,
532561
.default_domain_ops =
533562
&(struct iommu_domain_ops){
534563
.free = mock_domain_free,
@@ -1375,6 +1404,31 @@ static int iommufd_test_dirty(struct iommufd_ucmd *ucmd, unsigned int mockpt_id,
13751404
return rc;
13761405
}
13771406

1407+
static int iommufd_test_trigger_iopf(struct iommufd_ucmd *ucmd,
1408+
struct iommu_test_cmd *cmd)
1409+
{
1410+
struct iopf_fault event = { };
1411+
struct iommufd_device *idev;
1412+
1413+
idev = iommufd_get_device(ucmd, cmd->trigger_iopf.dev_id);
1414+
if (IS_ERR(idev))
1415+
return PTR_ERR(idev);
1416+
1417+
event.fault.prm.flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
1418+
if (cmd->trigger_iopf.pasid != IOMMU_NO_PASID)
1419+
event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
1420+
event.fault.type = IOMMU_FAULT_PAGE_REQ;
1421+
event.fault.prm.addr = cmd->trigger_iopf.addr;
1422+
event.fault.prm.pasid = cmd->trigger_iopf.pasid;
1423+
event.fault.prm.grpid = cmd->trigger_iopf.grpid;
1424+
event.fault.prm.perm = cmd->trigger_iopf.perm;
1425+
1426+
iommu_report_device_fault(idev->dev, &event);
1427+
iommufd_put_object(ucmd->ictx, &idev->obj);
1428+
1429+
return 0;
1430+
}
1431+
13781432
void iommufd_selftest_destroy(struct iommufd_object *obj)
13791433
{
13801434
struct selftest_obj *sobj = container_of(obj, struct selftest_obj, obj);
@@ -1450,6 +1504,8 @@ int iommufd_test(struct iommufd_ucmd *ucmd)
14501504
cmd->dirty.page_size,
14511505
u64_to_user_ptr(cmd->dirty.uptr),
14521506
cmd->dirty.flags);
1507+
case IOMMU_TEST_OP_TRIGGER_IOPF:
1508+
return iommufd_test_trigger_iopf(ucmd, cmd);
14531509
default:
14541510
return -EOPNOTSUPP;
14551511
}
@@ -1491,6 +1547,9 @@ int __init iommufd_test_init(void)
14911547
&iommufd_mock_bus_type.nb);
14921548
if (rc)
14931549
goto err_sysfs;
1550+
1551+
mock_iommu_iopf_queue = iopf_queue_alloc("mock-iopfq");
1552+
14941553
return 0;
14951554

14961555
err_sysfs:
@@ -1506,6 +1565,11 @@ int __init iommufd_test_init(void)
15061565

15071566
void iommufd_test_exit(void)
15081567
{
1568+
if (mock_iommu_iopf_queue) {
1569+
iopf_queue_free(mock_iommu_iopf_queue);
1570+
mock_iommu_iopf_queue = NULL;
1571+
}
1572+
15091573
iommu_device_sysfs_remove(&mock_iommu_device);
15101574
iommu_device_unregister_bus(&mock_iommu_device,
15111575
&iommufd_mock_bus_type.bus,

0 commit comments

Comments
 (0)