@@ -609,6 +609,7 @@ int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd);
void iommufd_viommu_destroy(struct iommufd_object *obj);
int iommufd_vdevice_alloc_ioctl(struct iommufd_ucmd *ucmd);
void iommufd_vdevice_destroy(struct iommufd_object *obj);
+int iommufd_vdevice_tsm_guest_request_ioctl(struct iommufd_ucmd *ucmd);
struct iommufd_vdevice {
struct iommufd_object obj;
@@ -320,6 +320,7 @@ union ucmd_buffer {
struct iommu_veventq_alloc veventq;
struct iommu_vfio_ioas vfio_ioas;
struct iommu_viommu_alloc viommu;
+ struct iommu_vdevice_tsm_guest_request gr;
#ifdef CONFIG_IOMMUFD_TEST
struct iommu_test_cmd test;
#endif
@@ -379,6 +380,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_VDEVICE_TSM_GUEST_REQUEST, iommufd_vdevice_tsm_guest_request_ioctl,
+ struct iommu_vdevice_tsm_guest_request, resp_uptr),
#ifdef CONFIG_IOMMUFD_TEST
IOCTL_OP(IOMMU_TEST_CMD, iommufd_test, struct iommu_test_cmd, last),
#endif
@@ -303,3 +303,42 @@ void iommufd_vdevice_tsm_unbind(struct iommufd_vdevice *vdev)
out_unlock:
mutex_unlock(&vdev->tsm_lock);
}
+
+int iommufd_vdevice_tsm_guest_request_ioctl(struct iommufd_ucmd *ucmd)
+{
+ struct iommu_vdevice_tsm_guest_request *cmd = ucmd->cmd;
+ struct pci_tsm_guest_req_info info = {
+ .type = cmd->type,
+ .type_info = u64_to_user_ptr(cmd->type_info_uptr),
+ .type_info_len = cmd->type_info_len,
+ .req = u64_to_user_ptr(cmd->req_uptr),
+ .req_len = cmd->req_len,
+ .resp = u64_to_user_ptr(cmd->resp_uptr),
+ .resp_len = cmd->resp_len,
+ };
+ struct iommufd_vdevice *vdev;
+ int rc;
+
+ vdev = container_of(iommufd_get_object(ucmd->ictx, cmd->vdevice_id,
+ IOMMUFD_OBJ_VDEVICE),
+ struct iommufd_vdevice, obj);
+ if (IS_ERR(vdev))
+ return PTR_ERR(vdev);
+
+ mutex_lock(&vdev->tsm_lock);
+ if (!vdev->tsm_bound) {
+ rc = -ENOENT;
+ goto out_unlock;
+ }
+
+ rc = pci_tsm_guest_req(to_pci_dev(vdev->dev), &info);
+ if (rc)
+ goto out_unlock;
+
+ cmd->resp_len = info.resp_len;
+ rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
+out_unlock:
+ mutex_unlock(&vdev->tsm_lock);
+ iommufd_put_object(ucmd->ictx, &vdev->obj);
+ return rc;
+}
@@ -56,6 +56,7 @@ enum {
IOMMUFD_CMD_VDEVICE_ALLOC = 0x91,
IOMMUFD_CMD_IOAS_CHANGE_PROCESS = 0x92,
IOMMUFD_CMD_VEVENTQ_ALLOC = 0x93,
+ IOMMUFD_CMD_VDEVICE_TSM_GUEST_REQUEST = 0x94,
};
/**
@@ -1141,4 +1142,31 @@ struct iommu_veventq_alloc {
__u32 __reserved;
};
#define IOMMU_VEVENTQ_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VEVENTQ_ALLOC)
+
+/**
+ * struct iommu_vdevice_tsm_guest_request - ioctl(IOMMU_VDEVICE_TSM_GUEST_REQUEST)
+ * @size: sizeof(struct iommu_vdevice_tsm_guest_request)
+ * @vdevice_id: vDevice ID the guest request is for
+ * @type: identify the format of the following blobs
+ * @type_info_len: the blob size for @type_info_uptr
+ * @req_len: the blob size for @req_uptr, filled by guest
+ * @resp_len: for input, the blob size for @resp_uptr, filled by guest
+ * for output, the size of actual response data, filled by host
+ * @type_info_uptr: extra input/output info, e.g. firmware error code
+ * @req_uptr: request data buffer filled by guest
+ * @resp_uptr: response data buffer filled by host
+ */
+struct iommu_vdevice_tsm_guest_request {
+ __u32 size;
+ __u32 vdevice_id;
+ __u32 type;
+ __u32 type_info_len;
+ __u32 req_len;
+ __u32 resp_len;
+ __aligned_u64 type_info_uptr;
+ __aligned_u64 req_uptr;
+ __aligned_u64 resp_uptr;
+};
+#define IOMMU_VDEVICE_TSM_GUEST_REQUEST _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VDEVICE_TSM_GUEST_REQUEST)
+
#endif