Commit b290a05f authored by Yi Liu's avatar Yi Liu Committed by Alex Williamson
Browse files

vfio: Add VFIO_DEVICE_[AT|DE]TACH_IOMMUFD_PT



This adds ioctl for userspace to attach device cdev fd to and detach
from IOAS/hw_pagetable managed by iommufd.

    VFIO_DEVICE_ATTACH_IOMMUFD_PT: attach vfio device to IOAS or hw_pagetable
				   managed by iommufd. Attach can be undo
				   by VFIO_DEVICE_DETACH_IOMMUFD_PT or device
				   fd close.
    VFIO_DEVICE_DETACH_IOMMUFD_PT: detach vfio device from the current attached
				   IOAS or hw_pagetable managed by iommufd.

Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Tested-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Tested-by: default avatarMatthew Rosato <mjrosato@linux.ibm.com>
Tested-by: default avatarYanting Jiang <yanting.jiang@intel.com>
Tested-by: default avatarShameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Tested-by: default avatarTerrence Xu <terrence.xu@intel.com>
Tested-by: default avatarZhenzhong Duan <zhenzhong.duan@intel.com>
Signed-off-by: default avatarYi Liu <yi.l.liu@intel.com>
Link: https://lore.kernel.org/r/20230718135551.6592-24-yi.l.liu@intel.com


Signed-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent 5fcc2696
Loading
Loading
Loading
Loading
+58 −0
Original line number Diff line number Diff line
@@ -152,6 +152,64 @@ void vfio_df_unbind_iommufd(struct vfio_device_file *df)
	vfio_device_unblock_group(device);
}

int vfio_df_ioctl_attach_pt(struct vfio_device_file *df,
			    struct vfio_device_attach_iommufd_pt __user *arg)
{
	struct vfio_device *device = df->device;
	struct vfio_device_attach_iommufd_pt attach;
	unsigned long minsz;
	int ret;

	minsz = offsetofend(struct vfio_device_attach_iommufd_pt, pt_id);

	if (copy_from_user(&attach, arg, minsz))
		return -EFAULT;

	if (attach.argsz < minsz || attach.flags)
		return -EINVAL;

	mutex_lock(&device->dev_set->lock);
	ret = device->ops->attach_ioas(device, &attach.pt_id);
	if (ret)
		goto out_unlock;

	if (copy_to_user(&arg->pt_id, &attach.pt_id, sizeof(attach.pt_id))) {
		ret = -EFAULT;
		goto out_detach;
	}
	mutex_unlock(&device->dev_set->lock);

	return 0;

out_detach:
	device->ops->detach_ioas(device);
out_unlock:
	mutex_unlock(&device->dev_set->lock);
	return ret;
}

int vfio_df_ioctl_detach_pt(struct vfio_device_file *df,
			    struct vfio_device_detach_iommufd_pt __user *arg)
{
	struct vfio_device *device = df->device;
	struct vfio_device_detach_iommufd_pt detach;
	unsigned long minsz;

	minsz = offsetofend(struct vfio_device_detach_iommufd_pt, flags);

	if (copy_from_user(&detach, arg, minsz))
		return -EFAULT;

	if (detach.argsz < minsz || detach.flags)
		return -EINVAL;

	mutex_lock(&device->dev_set->lock);
	device->ops->detach_ioas(device);
	mutex_unlock(&device->dev_set->lock);

	return 0;
}

static char *vfio_device_devnode(const struct device *dev, umode_t *mode)
{
	return kasprintf(GFP_KERNEL, "vfio/devices/%s", dev_name(dev));
+5 −0
Original line number Diff line number Diff line
@@ -266,6 +266,11 @@ vfio_iommufd_compat_attach_ioas(struct vfio_device *device,
}
#endif

int vfio_df_ioctl_attach_pt(struct vfio_device_file *df,
			    struct vfio_device_attach_iommufd_pt __user *arg);
int vfio_df_ioctl_detach_pt(struct vfio_device_file *df,
			    struct vfio_device_detach_iommufd_pt __user *arg);

#if IS_ENABLED(CONFIG_VFIO_DEVICE_CDEV)
void vfio_init_device_cdev(struct vfio_device *device);

+14 −1
Original line number Diff line number Diff line
@@ -1162,6 +1162,19 @@ static long vfio_device_fops_unl_ioctl(struct file *filep,
	if (ret)
		return ret;

	/* cdev only ioctls */
	if (IS_ENABLED(CONFIG_VFIO_DEVICE_CDEV) && !df->group) {
		switch (cmd) {
		case VFIO_DEVICE_ATTACH_IOMMUFD_PT:
			ret = vfio_df_ioctl_attach_pt(df, uptr);
			goto out;

		case VFIO_DEVICE_DETACH_IOMMUFD_PT:
			ret = vfio_df_ioctl_detach_pt(df, uptr);
			goto out;
		}
	}

	switch (cmd) {
	case VFIO_DEVICE_FEATURE:
		ret = vfio_ioctl_device_feature(device, uptr);
@@ -1174,7 +1187,7 @@ static long vfio_device_fops_unl_ioctl(struct file *filep,
			ret = device->ops->ioctl(device, cmd, arg);
		break;
	}

out:
	vfio_device_pm_runtime_put(device);
	return ret;
}
+44 −0
Original line number Diff line number Diff line
@@ -924,6 +924,50 @@ struct vfio_device_bind_iommufd {

#define VFIO_DEVICE_BIND_IOMMUFD	_IO(VFIO_TYPE, VFIO_BASE + 18)

/*
 * VFIO_DEVICE_ATTACH_IOMMUFD_PT - _IOW(VFIO_TYPE, VFIO_BASE + 19,
 *					struct vfio_device_attach_iommufd_pt)
 * @argsz:	User filled size of this data.
 * @flags:	Must be 0.
 * @pt_id:	Input the target id which can represent an ioas or a hwpt
 *		allocated via iommufd subsystem.
 *		Output the input ioas id or the attached hwpt id which could
 *		be the specified hwpt itself or a hwpt automatically created
 *		for the specified ioas by kernel during the attachment.
 *
 * Associate the device with an address space within the bound iommufd.
 * Undo by VFIO_DEVICE_DETACH_IOMMUFD_PT or device fd close.  This is only
 * allowed on cdev fds.
 *
 * Return: 0 on success, -errno on failure.
 */
struct vfio_device_attach_iommufd_pt {
	__u32	argsz;
	__u32	flags;
	__u32	pt_id;
};

#define VFIO_DEVICE_ATTACH_IOMMUFD_PT		_IO(VFIO_TYPE, VFIO_BASE + 19)

/*
 * VFIO_DEVICE_DETACH_IOMMUFD_PT - _IOW(VFIO_TYPE, VFIO_BASE + 20,
 *					struct vfio_device_detach_iommufd_pt)
 * @argsz:	User filled size of this data.
 * @flags:	Must be 0.
 *
 * Remove the association of the device and its current associated address
 * space.  After it, the device should be in a blocking DMA state.  This is only
 * allowed on cdev fds.
 *
 * Return: 0 on success, -errno on failure.
 */
struct vfio_device_detach_iommufd_pt {
	__u32	argsz;
	__u32	flags;
};

#define VFIO_DEVICE_DETACH_IOMMUFD_PT		_IO(VFIO_TYPE, VFIO_BASE + 20)

/*
 * Provide support for setting a PCI VF Token, which is used as a shared
 * secret between PF and VF drivers.  This feature may only be set on a