Skip to content

Commit

Permalink
vfio/pci: Add VFIO_DEVICE_ATTACH_IOASPT
Browse files Browse the repository at this point in the history
This patch supports the ioas_pagetable attachment for vfio pci devices.

An open:
Since the code are mostly common (non-pci specific), should we add the
code in vfio core instead of vfio pci? Wish to have good idea before
pushing to upstream.

Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
  • Loading branch information
yiliu1765 committed Dec 16, 2021
1 parent 4aa75d9 commit e4e0ed3
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 3 deletions.
2 changes: 2 additions & 0 deletions drivers/vfio/pci/vfio_pci.c
Expand Up @@ -132,6 +132,8 @@ static const struct vfio_device_ops vfio_pci_ops = {
.unbind_iommufd = vfio_pci_core_unbind_iommufd,
.open_device = vfio_pci_open_device,
.close_device = vfio_pci_core_close_device,
.attach_ioaspt = vfio_pci_core_attach_ioaspt,
.detach_ioaspt = vfio_pci_core_detach_ioaspt,
.ioctl = vfio_pci_core_ioctl,
.read = vfio_pci_core_read,
.write = vfio_pci_core_write,
Expand Down
69 changes: 69 additions & 0 deletions drivers/vfio/pci/vfio_pci_core.c
Expand Up @@ -659,6 +659,7 @@ int vfio_pci_core_bind_iommufd(struct vfio_device *core_vdev,
}

vdev->idev = idev;
vdev->ioaspt_id = IOMMUFD_INVALID_ID;
bind->out_devid = id;

out_unlock:
Expand All @@ -674,13 +675,81 @@ void vfio_pci_core_unbind_iommufd(struct vfio_device *core_vdev)

mutex_lock(&vdev->idev_lock);
if (vdev->idev) {
if (vdev->ioaspt_id != IOMMUFD_INVALID_ID) {
vdev->iommufd = -1;
vdev->ioaspt_id = IOMMUFD_INVALID_ID;
iommufd_device_detach(vdev->idev);
}
iommufd_unbind_device(vdev->idev);
vdev->idev = NULL;
}
mutex_unlock(&vdev->idev_lock);
}
EXPORT_SYMBOL_GPL(vfio_pci_core_unbind_iommufd);

int vfio_pci_core_attach_ioaspt(struct vfio_device *core_vdev,
struct vfio_device_attach_ioaspt *attach)
{
struct vfio_pci_core_device *vdev =
container_of(core_vdev, struct vfio_pci_core_device, vdev);
u32 pt_id = attach->ioaspt_id;
int ret;

mutex_lock(&vdev->idev_lock);

if (!vdev->idev) {
ret = -EINVAL;
goto out_unlock;
}

/* Currently only allows one IOAS attach */
if (vdev->ioaspt_id != IOMMUFD_INVALID_ID) {
ret = -EBUSY;
goto out_unlock;
}

ret = iommufd_device_attach(vdev->idev, &pt_id);
if (ret)
goto out_unlock;

vdev->iommufd = attach->iommufd;
vdev->ioaspt_id = attach->ioaspt_id;
attach->out_hwpt_id = pt_id;

out_unlock:
mutex_unlock(&vdev->idev_lock);

return ret;
}
EXPORT_SYMBOL_GPL(vfio_pci_core_attach_ioaspt);

void vfio_pci_core_detach_ioaspt(struct vfio_device *core_vdev,
struct vfio_device_detach_ioaspt *detach)
{
struct vfio_pci_core_device *vdev =
container_of(core_vdev, struct vfio_pci_core_device, vdev);

mutex_lock(&vdev->idev_lock);

if (!vdev)
goto out_unlock;

if (vdev->ioaspt_id == IOMMUFD_INVALID_ID)
goto out_unlock;

if (vdev->iommufd != detach->iommufd ||
vdev->ioaspt_id != detach->ioaspt_id)
goto out_unlock;

vdev->iommufd = -1;
vdev->ioaspt_id = IOMMUFD_INVALID_ID;
iommufd_device_detach(vdev->idev);

out_unlock:
mutex_unlock(&vdev->idev_lock);
}
EXPORT_SYMBOL_GPL(vfio_pci_core_detach_ioaspt);

long vfio_pci_core_ioctl(struct vfio_device *core_vdev, unsigned int cmd,
unsigned long arg)
{
Expand Down
80 changes: 77 additions & 3 deletions drivers/vfio/vfio.c
Expand Up @@ -32,6 +32,7 @@
#include <linux/vfio.h>
#include <linux/wait.h>
#include <linux/sched/signal.h>
#include <linux/iommufd.h>
#include "vfio.h"

#define DRIVER_VERSION "0.3"
Expand Down Expand Up @@ -1236,11 +1237,16 @@ static int vfio_device_open_count(struct vfio_device *device)
return ret;
}

static bool vfio_device_in_container(struct vfio_device *device)
{
return device->group && device->group->container;
}

static void vfio_device_close_decount(struct vfio_device *device)
{
mutex_lock(&device->dev_set->lock);
if (device->open_count == 1) {
if ((!device->group || !device->group->container) &&
if (!vfio_device_in_container(device) &&
device->ops->unbind_iommufd)
device->ops->unbind_iommufd(device);
if (device->ops->close_device)
Expand Down Expand Up @@ -1529,6 +1535,63 @@ static long vfio_device_bind_iommufd(struct file *filep, unsigned long arg)
sizeof(bind.out_devid)) ? -EFAULT : 0;
}

static long vfio_device_attach_ioaspt(struct vfio_device *device,
unsigned long arg)
{
struct vfio_device_attach_ioaspt attach;
unsigned long minsz;
int ret;

minsz = offsetofend(struct vfio_device_attach_ioaspt, ioaspt_id);
if (copy_from_user(&attach, (void __user *)arg, minsz))
return -EFAULT;

if (attach.argsz < minsz || attach.flags ||
attach.iommufd < 0 || attach.ioaspt_id == IOMMUFD_INVALID_ID)
return -EINVAL;

/* not allowed if the device is opened in legacy interface */
if (vfio_device_in_container(device))
return -EBUSY;

if (unlikely(!device->ops->attach_ioaspt))
return -EINVAL;

ret = device->ops->attach_ioaspt(device, &attach);
if (ret)
return ret;

return copy_to_user((void __user *)arg + minsz,
&attach.out_hwpt_id,
sizeof(attach.out_hwpt_id)) ? -EFAULT : 0;
}

static long vfio_device_detach_ioaspt(struct vfio_device *device,
unsigned long arg)
{
struct vfio_device_detach_ioaspt detach;
unsigned long minsz;

minsz = offsetofend(struct vfio_device_detach_ioaspt, ioaspt_id);
if (copy_from_user(&detach, (void __user *)arg, minsz))
return -EFAULT;

if (detach.argsz < minsz || detach.flags ||
detach.iommufd < 0 || detach.ioaspt_id == IOMMUFD_INVALID_ID)
return -EINVAL;

/* not allowed if the device is opened in legacy interface */
if (vfio_device_in_container(device))
return -EBUSY;

if (unlikely(!device->ops->detach_ioaspt))
return -EINVAL;

device->ops->detach_ioaspt(device, &detach);

return 0;
}

static long vfio_device_fops_unl_ioctl(struct file *filep,
unsigned int cmd, unsigned long arg)
{
Expand All @@ -1541,10 +1604,21 @@ static long vfio_device_fops_unl_ioctl(struct file *filep,
/* Pair with smp_store_release() in vfio_device_bind_iommufd() */
device = smp_load_acquire(&filep->private_data);

if (!device || unlikely(!device->ops->ioctl))
if (!device)
return -EINVAL;

return device->ops->ioctl(device, cmd, arg);
switch (cmd) {
case VFIO_DEVICE_ATTACH_IOASPT:
return vfio_device_attach_ioaspt(device, arg);
case VFIO_DEVICE_DETACH_IOASPT:
return vfio_device_detach_ioaspt(device, arg);
default: {
if (unlikely(!device->ops->ioctl))
return -EINVAL;

return device->ops->ioctl(device, cmd, arg);
}
}
}

static ssize_t vfio_device_fops_read(struct file *filep, char __user *buf,
Expand Down
2 changes: 2 additions & 0 deletions include/linux/iommufd.h
Expand Up @@ -11,6 +11,8 @@
#include <linux/err.h>
#include <linux/device.h>

#define IOMMUFD_INVALID_ID 0

struct pci_dev;
struct iommufd_device;

Expand Down
4 changes: 4 additions & 0 deletions include/linux/vfio.h
Expand Up @@ -66,6 +66,10 @@ struct vfio_device_ops {
int (*bind_iommufd)(struct vfio_device *vdev,
struct vfio_device_bind_iommufd *bind);
void (*unbind_iommufd)(struct vfio_device *vdev);
int (*attach_ioaspt)(struct vfio_device *vdev,
struct vfio_device_attach_ioaspt *attach);
void (*detach_ioaspt)(struct vfio_device *vdev,
struct vfio_device_detach_ioaspt *detach);
int (*open_device)(struct vfio_device *vdev);
void (*close_device)(struct vfio_device *vdev);
void (*release)(struct vfio_device *vdev);
Expand Down
6 changes: 6 additions & 0 deletions include/linux/vfio_pci_core.h
Expand Up @@ -140,6 +140,8 @@ struct vfio_pci_core_device {
struct rw_semaphore memory_lock;
struct mutex idev_lock;
struct iommufd_device *idev;
int iommufd;
u32 ioaspt_id;
};

#define is_intx(vdev) (vdev->irq_type == VFIO_PCI_INTX_IRQ_INDEX)
Expand Down Expand Up @@ -216,6 +218,10 @@ void vfio_pci_core_release(struct vfio_device *core_dev);
int vfio_pci_core_bind_iommufd(struct vfio_device *core_vdev,
struct vfio_device_bind_iommufd *bind);
void vfio_pci_core_unbind_iommufd(struct vfio_device *core_vdev);
int vfio_pci_core_attach_ioaspt(struct vfio_device *core_vdev,
struct vfio_device_attach_ioaspt *attach);
void vfio_pci_core_detach_ioaspt(struct vfio_device *core_vdev,
struct vfio_device_detach_ioaspt *detach);
void vfio_pci_core_close_device(struct vfio_device *core_vdev);
struct vfio_pci_core_device *
vfio_pci_core_alloc_device(struct pci_dev *pdev,
Expand Down
49 changes: 49 additions & 0 deletions include/uapi/linux/vfio.h
Expand Up @@ -225,6 +225,55 @@ struct vfio_device_bind_iommufd {

#define VFIO_DEVICE_BIND_IOMMUFD _IO(VFIO_TYPE, VFIO_BASE + 19)

/*
* VFIO_DEVICE_ATTACH_IOASPT - _IOW(VFIO_TYPE, VFIO_BASE + 21,
* struct vfio_device_attach_ioaspt)
*
* Attach a vfio device to the specified IOAS Page Table.
*
* Multiple vfio devices can be attached to the same IOAS Page Table. One
* device can be attached to only one ioas at this point.
*
* @argsz: user filled size of this data.
* @flags: reserved for future extension.
* @iommufd: iommufd where the ioas comes from.
* @ioaspt_id: Input the target I/O address space page table.
* @hwpt_id: Output the hw page table id
*
* Return: 0 on success, -errno on failure.
*/
struct vfio_device_attach_ioaspt {
__u32 argsz;
__u32 flags;
__s32 iommufd;
__u32 ioaspt_id;
__u32 out_hwpt_id;
};

#define VFIO_DEVICE_ATTACH_IOASPT _IO(VFIO_TYPE, VFIO_BASE + 20)

/*
* VFIO_DEVICE_DETACH_IOASPT - _IOW(VFIO_TYPE, VFIO_BASE + 21,
* struct vfio_device_detach_ioaspt)
*
* Detach a vfio device to the specified IOAS Page Table.
*
* @argsz: user filled size of this data.
* @flags: reserved for future extension.
* @iommufd: iommufd where the ioas comes from.
* @ioaspt_id: Input the target I/O address space page table.
*
* Return: 0 on success, -errno on failure.
*/
struct vfio_device_detach_ioaspt {
__u32 argsz;
__u32 flags;
__s32 iommufd;
__u32 ioaspt_id;
};

#define VFIO_DEVICE_DETACH_IOASPT _IO(VFIO_TYPE, VFIO_BASE + 21)

/**
* VFIO_DEVICE_GET_INFO - _IOR(VFIO_TYPE, VFIO_BASE + 7,
* struct vfio_device_info)
Expand Down

0 comments on commit e4e0ed3

Please sign in to comment.