Add IOMMU_DEVICE_GET_CAPS op for querying iommu capabilities for a given device. Capabilities are IOMMU agnostic and use device_iommu_capable() API passing one of the IOMMU_CAP_*. Enumerate IOMMU_CAP_DIRTY for now in the out_caps field returned back to userspace. Signed-off-by: Joao Martins <joao.m.martins@xxxxxxxxxx> --- drivers/iommu/iommufd/device.c | 26 +++++++++++++++++++++++++ drivers/iommu/iommufd/iommufd_private.h | 1 + drivers/iommu/iommufd/main.c | 3 +++ include/uapi/linux/iommufd.h | 23 ++++++++++++++++++++++ 4 files changed, 53 insertions(+) diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c index 48d1300f0350..63e2ffe21653 100644 --- a/drivers/iommu/iommufd/device.c +++ b/drivers/iommu/iommufd/device.c @@ -263,6 +263,32 @@ u32 iommufd_device_to_id(struct iommufd_device *idev) } EXPORT_SYMBOL_NS_GPL(iommufd_device_to_id, IOMMUFD); +int iommufd_device_get_caps(struct iommufd_ucmd *ucmd) +{ + struct iommu_device_get_caps *cmd = ucmd->cmd; + struct iommufd_object *obj; + struct iommufd_device *idev; + int rc; + + obj = iommufd_get_object(ucmd->ictx, cmd->dev_id, IOMMUFD_OBJ_DEVICE); + if (IS_ERR(obj)) + return PTR_ERR(obj); + + idev = container_of(obj, struct iommufd_device, obj); + + cmd->out_caps = 0; + if (device_iommu_capable(idev->dev, IOMMU_CAP_DIRTY)) + cmd->out_caps |= IOMMUFD_CAP_DIRTY_TRACKING; + + rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); + if (rc) + goto out_put; + +out_put: + iommufd_put_object(obj); + return rc; +} + static int iommufd_group_setup_msi(struct iommufd_group *igroup, struct iommufd_hw_pagetable *hwpt) { diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h index 3de8046fee07..e5782459e4aa 100644 --- a/drivers/iommu/iommufd/iommufd_private.h +++ b/drivers/iommu/iommufd/iommufd_private.h @@ -246,6 +246,7 @@ int iommufd_option_rlimit_mode(struct iommu_option *cmd, int iommufd_vfio_ioas(struct iommufd_ucmd *ucmd); int iommufd_check_iova_range(struct iommufd_ioas *ioas, struct iommufd_dirty_data *bitmap); +int iommufd_device_get_caps(struct iommufd_ucmd *ucmd); /* * A HW pagetable is called an iommu_domain inside the kernel. This user object diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c index f34b309a1baf..c4c6f900ef0a 100644 --- a/drivers/iommu/iommufd/main.c +++ b/drivers/iommu/iommufd/main.c @@ -279,6 +279,7 @@ union ucmd_buffer { struct iommu_vfio_ioas vfio_ioas; struct iommu_hwpt_set_dirty set_dirty; struct iommu_hwpt_get_dirty_iova get_dirty_iova; + struct iommu_device_get_caps get_caps; #ifdef CONFIG_IOMMUFD_TEST struct iommu_test_cmd test; #endif @@ -324,6 +325,8 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = { struct iommu_hwpt_set_dirty, __reserved), IOCTL_OP(IOMMU_HWPT_GET_DIRTY_IOVA, iommufd_hwpt_get_dirty_iova, struct iommu_hwpt_get_dirty_iova, bitmap.data), + IOCTL_OP(IOMMU_DEVICE_GET_CAPS, iommufd_device_get_caps, + struct iommu_device_get_caps, out_caps), #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 44f9ddcfda58..c256f7354867 100644 --- a/include/uapi/linux/iommufd.h +++ b/include/uapi/linux/iommufd.h @@ -48,6 +48,7 @@ enum { IOMMUFD_CMD_HWPT_ALLOC, IOMMUFD_CMD_HWPT_SET_DIRTY, IOMMUFD_CMD_HWPT_GET_DIRTY_IOVA, + IOMMUFD_CMD_DEVICE_GET_CAPS, }; /** @@ -442,4 +443,26 @@ struct iommu_hwpt_get_dirty_iova { }; #define IOMMU_HWPT_GET_DIRTY_IOVA _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_GET_DIRTY_IOVA) + +/** + * enum iommufd_device_caps + * @IOMMU_CAP_DIRTY_TRACKING: IOMMU device support for dirty tracking + */ +enum iommufd_device_caps { + IOMMUFD_CAP_DIRTY_TRACKING = 1 << 0, +}; + +/* + * struct iommu_device_caps - ioctl(IOMMU_DEVICE_GET_CAPS) + * @size: sizeof(struct iommu_device_caps) + * @dev_id: the device to query + * @caps: IOMMU capabilities of the device + */ +struct iommu_device_get_caps { + __u32 size; + __u32 dev_id; + __aligned_u64 out_caps; +}; +#define IOMMU_DEVICE_GET_CAPS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_DEVICE_GET_CAPS) + #endif -- 2.17.2