[PATCH RFC v1 2/3] iommufd: Add IOMMUFD_CMD_DEVICE_SET_RID and IOMMUFD_CMD_DEVICE_UNSET_RID

From: Nicolin Chen
Date: Thu Apr 06 2023 - 02:27:02 EST


Add a new pair of ioctls to allow user space to set user space Request ID
for a passthrough PCI device. This is to create a link between a physical
RID and a virtual RID in the IOMMU driver that cares.

Signed-off-by: Nicolin Chen <nicolinc@xxxxxxxxxx>
---
drivers/iommu/iommufd/device.c | 39 +++++++++++++++++++++++++
drivers/iommu/iommufd/iommufd_private.h | 2 ++
drivers/iommu/iommufd/main.c | 4 +++
include/uapi/linux/iommufd.h | 31 ++++++++++++++++++++
4 files changed, 76 insertions(+)

diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
index 207b0e3fd9c8..db756e5cd77b 100644
--- a/drivers/iommu/iommufd/device.c
+++ b/drivers/iommu/iommufd/device.c
@@ -735,6 +735,45 @@ void iommufd_device_detach(struct iommufd_device *idev)
}
EXPORT_SYMBOL_NS_GPL(iommufd_device_detach, IOMMUFD);

+int iommufd_device_set_rid(struct iommufd_ucmd *ucmd)
+{
+ struct iommufd_device_set_rid *cmd = ucmd->cmd;
+ struct iommufd_device *idev;
+ const struct iommu_ops *ops;
+ int rc = 0;
+
+ if (!cmd->rid)
+ return -EINVAL;
+
+ idev = iommufd_get_device(ucmd, cmd->dev_id);
+ if (IS_ERR(idev))
+ return PTR_ERR(idev);
+
+ ops = dev_iommu_ops(idev->dev);
+ if (ops && ops->set_rid_user)
+ rc = ops->set_rid_user(idev->dev, cmd->rid, cmd->rid_base);
+ iommufd_put_object(&idev->obj);
+ return rc;
+}
+
+int iommufd_device_unset_rid(struct iommufd_ucmd *ucmd)
+{
+ struct iommufd_device_unset_rid *cmd = ucmd->cmd;
+ struct iommufd_device *idev;
+ const struct iommu_ops *ops;
+ int rc = 0;
+
+ idev = iommufd_get_device(ucmd, cmd->dev_id);
+ if (IS_ERR(idev))
+ return PTR_ERR(idev);
+
+ ops = dev_iommu_ops(idev->dev);
+ if (ops && ops->unset_rid_user)
+ rc = ops->unset_rid_user(idev->dev);
+ iommufd_put_object(&idev->obj);
+ return rc;
+}
+
void iommufd_access_destroy_object(struct iommufd_object *obj)
{
struct iommufd_access *access =
diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
index e52fd9d8c160..d65617727c0c 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -320,6 +320,8 @@ iommufd_get_device(struct iommufd_ucmd *ucmd, u32 id)

void iommufd_device_destroy(struct iommufd_object *obj);
int iommufd_device_get_hw_info(struct iommufd_ucmd *ucmd);
+int iommufd_device_set_rid(struct iommufd_ucmd *ucmd);
+int iommufd_device_unset_rid(struct iommufd_ucmd *ucmd);

extern const u64 iommufd_hwpt_type_bitmaps[];

diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c
index 7ec3ceac01b3..113fac4d4de0 100644
--- a/drivers/iommu/iommufd/main.c
+++ b/drivers/iommu/iommufd/main.c
@@ -317,6 +317,10 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = {
val64),
IOCTL_OP(IOMMU_VFIO_IOAS, iommufd_vfio_ioas, struct iommu_vfio_ioas,
__reserved),
+ IOCTL_OP(IOMMU_DEVICE_SET_RID, iommufd_device_set_rid,
+ struct iommufd_device_set_rid, rid_base),
+ IOCTL_OP(IOMMU_DEVICE_UNSET_RID, iommufd_device_unset_rid,
+ struct iommufd_device_unset_rid, dev_id),
#ifdef CONFIG_IOMMUFD_TEST
IOCTL_OP(IOMMU_TEST_CMD, iommufd_test, struct iommu_test_cmd, last),
#endif
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 59a44ceff27d..5188a4318e22 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -48,6 +48,8 @@ enum {
IOMMUFD_CMD_HWPT_ALLOC,
IOMMUFD_CMD_DEVICE_GET_HW_INFO,
IOMMUFD_CMD_HWPT_INVALIDATE,
+ IOMMUFD_CMD_DEVICE_SET_RID,
+ IOMMUFD_CMD_DEVICE_UNSET_RID,
};

/**
@@ -482,4 +484,33 @@ struct iommu_hwpt_invalidate {
__aligned_u64 data_uptr;
};
#define IOMMU_HWPT_INVALIDATE _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_INVALIDATE)
+
+/**
+ * struct iommufd_device_set_rid - ioctl(IOMMU_DEVICE_SET_RID)
+ * @size: sizeof(struct iommufd_device_set_rid)
+ * @dev_id: The device to set a Request ID
+ * @rid: PCI Request ID
+ * Bits [15:8] are the Bus number.
+ * Bits [7:3] are the Device number.
+ * Bits [2:0] are the Function number.
+ * @rid_base: Base ID to map PCI Request ID
+ */
+struct iommufd_device_set_rid {
+ __u32 size;
+ __u32 dev_id;
+ __u32 rid;
+ __u32 rid_base;
+};
+#define IOMMU_DEVICE_SET_RID _IO(IOMMUFD_TYPE, IOMMUFD_CMD_DEVICE_SET_RID)
+
+/**
+ * struct iommufd_device_unset_rid - ioctl(IOMMU_DEVICE_UNSET_RID)
+ * @size: sizeof(struct iommufd_device_unset_rid)
+ * @dev_id: The device to unset a Request ID
+ */
+struct iommufd_device_unset_rid {
+ __u32 size;
+ __u32 dev_id;
+};
+#define IOMMU_DEVICE_UNSET_RID _IO(IOMMUFD_TYPE, IOMMUFD_CMD_DEVICE_UNSET_RID)
#endif
--
2.40.0