[PATCH v2 24/26] iommufd: Introduce vIOMMU command via VIOMMU_COMMAND ioctl
From: Suravee Suthikulpanit
Date: Thu May 28 2026 - 01:24:24 EST
Introduce a new IOMMU_VIOMMU_COMMAND ioctl, to support vIOMMU-specific
commands. Initially, the ioctl support set / get operations on a specified
index to write / read value. This allows write / read access to a
particular index of a data arrays such as hardware registers.
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx>
---
drivers/iommu/iommufd/iommufd_private.h | 1 +
drivers/iommu/iommufd/main.c | 3 ++
drivers/iommu/iommufd/viommu.c | 39 +++++++++++++++++++++++++
include/linux/iommufd.h | 5 ++++
include/uapi/linux/iommufd.h | 34 +++++++++++++++++++++
5 files changed, 82 insertions(+)
diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
index 6ac1965199e9..5cf839a4405a 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -692,6 +692,7 @@ iommufd_viommu_find_veventq(struct iommufd_viommu *viommu,
int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd);
void iommufd_viommu_destroy(struct iommufd_object *obj);
+int iommufd_viommu_command_ioctl(struct iommufd_ucmd *ucmd);
int iommufd_vdevice_alloc_ioctl(struct iommufd_ucmd *ucmd);
void iommufd_vdevice_destroy(struct iommufd_object *obj);
void iommufd_vdevice_abort(struct iommufd_object *obj);
diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c
index 8c6d43601afb..194f6409ce53 100644
--- a/drivers/iommu/iommufd/main.c
+++ b/drivers/iommu/iommufd/main.c
@@ -432,6 +432,7 @@ union ucmd_buffer {
struct iommu_veventq_alloc veventq;
struct iommu_vfio_ioas vfio_ioas;
struct iommu_viommu_alloc viommu;
+ struct iommu_viommu_command viommu_command;
#ifdef CONFIG_IOMMUFD_TEST
struct iommu_test_cmd test;
#endif
@@ -493,6 +494,8 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = {
__reserved),
IOCTL_OP(IOMMU_VIOMMU_ALLOC, iommufd_viommu_alloc_ioctl,
struct iommu_viommu_alloc, out_viommu_id),
+ IOCTL_OP(IOMMU_VIOMMU_COMMAND, iommufd_viommu_command_ioctl,
+ struct iommu_viommu_command, val64),
#ifdef CONFIG_IOMMUFD_TEST
IOCTL_OP(IOMMU_TEST_CMD, iommufd_test, struct iommu_test_cmd, last),
#endif
diff --git a/drivers/iommu/iommufd/viommu.c b/drivers/iommu/iommufd/viommu.c
index bc58d240fafd..53f9a7d2734a 100644
--- a/drivers/iommu/iommufd/viommu.c
+++ b/drivers/iommu/iommufd/viommu.c
@@ -477,3 +477,42 @@ int iommufd_hw_queue_alloc_ioctl(struct iommufd_ucmd *ucmd)
iommufd_put_object(ucmd->ictx, &viommu->obj);
return rc;
}
+
+int iommufd_viommu_command_ioctl(struct iommufd_ucmd *ucmd)
+{
+ int rc = 0;
+ struct iommu_viommu_command *cmd = ucmd->cmd;
+ struct iommufd_viommu *viommu = iommufd_get_viommu(ucmd, cmd->object_id);
+
+ if (cmd->__reserved) {
+ rc = -EOPNOTSUPP;
+ goto out_put_viommu;
+ }
+
+ if (IS_ERR(viommu)) {
+ rc = PTR_ERR(viommu);
+ goto out_put_viommu;
+ }
+
+ if (cmd->op == IOMMU_VIOMMU_COMMAND_OP_SET) {
+ if (!viommu->ops->set_command)
+ rc = -EOPNOTSUPP;
+ rc = viommu->ops->set_command(viommu, cmd->index, cmd->val64);
+ } else if (cmd->op == IOMMU_VIOMMU_COMMAND_OP_GET) {
+ if (!viommu->ops->get_command)
+ rc = -EOPNOTSUPP;
+ rc = viommu->ops->get_command(viommu, cmd->index, &cmd->val64);
+ } else {
+ rc = -EOPNOTSUPP;
+ }
+
+ if (rc)
+ goto out_put_viommu;
+
+ if (copy_to_user(&((struct iommu_viommu_command __user *)ucmd->ubuffer)->val64,
+ &cmd->val64, sizeof(cmd->val64)))
+ rc = -EFAULT;
+out_put_viommu:
+ iommufd_put_object(ucmd->ictx, &viommu->obj);
+ return rc;
+}
diff --git a/include/linux/iommufd.h b/include/linux/iommufd.h
index c0030677e13c..ec3563f4c09c 100644
--- a/include/linux/iommufd.h
+++ b/include/linux/iommufd.h
@@ -183,6 +183,9 @@ struct iommufd_hw_queue {
* @hw_queue_init: Similar to hw_queue_init_phys, but driver providing this op
* indicates that HW accesses the guest queue memory via
* @hw_queue->baseaddr.
+ * @set_command: Set data on the specified index of the specified vIOMMU.
+ * @get_command: Get data on the specified index of the specified vIOMMU.
+ * On success, the value is returned via the provided value.
*/
struct iommufd_viommu_ops {
void (*destroy)(struct iommufd_viommu *viommu);
@@ -198,6 +201,8 @@ struct iommufd_viommu_ops {
int (*hw_queue_init_phys)(struct iommufd_hw_queue *hw_queue, u32 index,
phys_addr_t base_addr_pa);
int (*hw_queue_init)(struct iommufd_hw_queue *hw_queue, u32 index);
+ int (*set_command)(struct iommufd_viommu *viommu, u16 index, u64 value);
+ int (*get_command)(struct iommufd_viommu *viommu, u16 index, u64 *value);
};
#if IS_ENABLED(CONFIG_IOMMUFD)
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index e08de6ab8209..a2195b1dfabe 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -57,6 +57,7 @@ enum {
IOMMUFD_CMD_IOAS_CHANGE_PROCESS = 0x92,
IOMMUFD_CMD_VEVENTQ_ALLOC = 0x93,
IOMMUFD_CMD_HW_QUEUE_ALLOC = 0x94,
+ IOMMUFD_CMD_VIOMMU_COMMAND = 0x95,
};
/**
@@ -1131,6 +1132,39 @@ struct iommu_viommu_alloc {
};
#define IOMMU_VIOMMU_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VIOMMU_ALLOC)
+/**
+ * enum viommu_command_ops - viommu command operations
+ * @IOMMU_VIOMMU_COMMAND_OP_SET: Set the command's data
+ * @IOMMU_VIOMMU_COMMAND_OP_GET: Get the command's data
+ */
+enum viommu_command_ops {
+ IOMMU_VIOMMU_COMMAND_OP_SET = 0,
+ IOMMU_VIOMMU_COMMAND_OP_GET = 1,
+};
+
+/**
+ * struct iommu_viommu_command - iommu viommu command multiplexer
+ * @size: sizeof(struct iommu_viommu_command)
+ * @object_id: ID of the vIOMMU if required
+ * @op: One of enum viommu_command_ops
+ * @index: Command index to match with the value
+ * @__reserved: Must be 0
+ * @val64: Command data to set or data returned on get
+ *
+ * This multiplexer allows controlling commands on vIOMMU.
+ * IOMMU_VIOMMU_COMMAND_OP_SET will load a command and
+ * IOMMU_VIOMMU_COMMAND_OP_GET will return the current value.
+ */
+struct iommu_viommu_command {
+ __u32 size;
+ __u32 object_id;
+ __u16 op;
+ __u16 index;
+ __u32 __reserved;
+ __aligned_u64 val64;
+};
+#define IOMMU_VIOMMU_COMMAND _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VIOMMU_COMMAND)
+
/**
* struct iommu_vdevice_alloc - ioctl(IOMMU_VDEVICE_ALLOC)
* @size: sizeof(struct iommu_vdevice_alloc)
--
2.34.1