@@ -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)
{
@@ -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
@@ -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
@@ -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
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@oracle.com> --- 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(+)