Merge tag 'vfio-v4.17-rc1' of git://github.com/awilliam/linux-vfio
[muen/linux.git] / drivers / vfio / pci / vfio_pci.c
index 8a1508a..b423a30 100644 (file)
@@ -302,6 +302,7 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
 {
        struct pci_dev *pdev = vdev->pdev;
        struct vfio_pci_dummy_resource *dummy_res, *tmp;
+       struct vfio_pci_ioeventfd *ioeventfd, *ioeventfd_tmp;
        int i, bar;
 
        /* Stop the device from further DMA */
@@ -311,6 +312,15 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
                                VFIO_IRQ_SET_ACTION_TRIGGER,
                                vdev->irq_type, 0, 0, NULL);
 
+       /* Device closed, don't need mutex here */
+       list_for_each_entry_safe(ioeventfd, ioeventfd_tmp,
+                                &vdev->ioeventfds_list, next) {
+               vfio_virqfd_disable(&ioeventfd->virqfd);
+               list_del(&ioeventfd->next);
+               kfree(ioeventfd);
+       }
+       vdev->ioeventfds_nr = 0;
+
        vdev->virq_disabled = false;
 
        for (i = 0; i < vdev->num_regions; i++)
@@ -1009,6 +1019,28 @@ hot_reset_release:
 
                kfree(groups);
                return ret;
+       } else if (cmd == VFIO_DEVICE_IOEVENTFD) {
+               struct vfio_device_ioeventfd ioeventfd;
+               int count;
+
+               minsz = offsetofend(struct vfio_device_ioeventfd, fd);
+
+               if (copy_from_user(&ioeventfd, (void __user *)arg, minsz))
+                       return -EFAULT;
+
+               if (ioeventfd.argsz < minsz)
+                       return -EINVAL;
+
+               if (ioeventfd.flags & ~VFIO_DEVICE_IOEVENTFD_SIZE_MASK)
+                       return -EINVAL;
+
+               count = ioeventfd.flags & VFIO_DEVICE_IOEVENTFD_SIZE_MASK;
+
+               if (hweight8(count) != 1 || ioeventfd.fd < -1)
+                       return -EINVAL;
+
+               return vfio_pci_ioeventfd(vdev, ioeventfd.offset,
+                                         ioeventfd.data, count, ioeventfd.fd);
        }
 
        return -ENOTTY;
@@ -1171,6 +1203,8 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        vdev->irq_type = VFIO_PCI_NUM_IRQS;
        mutex_init(&vdev->igate);
        spin_lock_init(&vdev->irqlock);
+       mutex_init(&vdev->ioeventfds_lock);
+       INIT_LIST_HEAD(&vdev->ioeventfds_list);
 
        ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev);
        if (ret) {
@@ -1212,6 +1246,7 @@ static void vfio_pci_remove(struct pci_dev *pdev)
 
        vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev);
        kfree(vdev->region);
+       mutex_destroy(&vdev->ioeventfds_lock);
        kfree(vdev);
 
        if (vfio_pci_is_vga(pdev)) {