diff options
Diffstat (limited to 'drivers/vfio/pci/vfio_pci.c')
-rw-r--r-- | drivers/vfio/pci/vfio_pci.c | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index b0f759476900..c6822149b394 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c | |||
@@ -305,6 +305,7 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev) | |||
305 | { | 305 | { |
306 | struct pci_dev *pdev = vdev->pdev; | 306 | struct pci_dev *pdev = vdev->pdev; |
307 | struct vfio_pci_dummy_resource *dummy_res, *tmp; | 307 | struct vfio_pci_dummy_resource *dummy_res, *tmp; |
308 | struct vfio_pci_ioeventfd *ioeventfd, *ioeventfd_tmp; | ||
308 | int i, bar; | 309 | int i, bar; |
309 | 310 | ||
310 | /* Stop the device from further DMA */ | 311 | /* Stop the device from further DMA */ |
@@ -314,6 +315,15 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev) | |||
314 | VFIO_IRQ_SET_ACTION_TRIGGER, | 315 | VFIO_IRQ_SET_ACTION_TRIGGER, |
315 | vdev->irq_type, 0, 0, NULL); | 316 | vdev->irq_type, 0, 0, NULL); |
316 | 317 | ||
318 | /* Device closed, don't need mutex here */ | ||
319 | list_for_each_entry_safe(ioeventfd, ioeventfd_tmp, | ||
320 | &vdev->ioeventfds_list, next) { | ||
321 | vfio_virqfd_disable(&ioeventfd->virqfd); | ||
322 | list_del(&ioeventfd->next); | ||
323 | kfree(ioeventfd); | ||
324 | } | ||
325 | vdev->ioeventfds_nr = 0; | ||
326 | |||
317 | vdev->virq_disabled = false; | 327 | vdev->virq_disabled = false; |
318 | 328 | ||
319 | for (i = 0; i < vdev->num_regions; i++) | 329 | for (i = 0; i < vdev->num_regions; i++) |
@@ -1012,6 +1022,28 @@ hot_reset_release: | |||
1012 | 1022 | ||
1013 | kfree(groups); | 1023 | kfree(groups); |
1014 | return ret; | 1024 | return ret; |
1025 | } else if (cmd == VFIO_DEVICE_IOEVENTFD) { | ||
1026 | struct vfio_device_ioeventfd ioeventfd; | ||
1027 | int count; | ||
1028 | |||
1029 | minsz = offsetofend(struct vfio_device_ioeventfd, fd); | ||
1030 | |||
1031 | if (copy_from_user(&ioeventfd, (void __user *)arg, minsz)) | ||
1032 | return -EFAULT; | ||
1033 | |||
1034 | if (ioeventfd.argsz < minsz) | ||
1035 | return -EINVAL; | ||
1036 | |||
1037 | if (ioeventfd.flags & ~VFIO_DEVICE_IOEVENTFD_SIZE_MASK) | ||
1038 | return -EINVAL; | ||
1039 | |||
1040 | count = ioeventfd.flags & VFIO_DEVICE_IOEVENTFD_SIZE_MASK; | ||
1041 | |||
1042 | if (hweight8(count) != 1 || ioeventfd.fd < -1) | ||
1043 | return -EINVAL; | ||
1044 | |||
1045 | return vfio_pci_ioeventfd(vdev, ioeventfd.offset, | ||
1046 | ioeventfd.data, count, ioeventfd.fd); | ||
1015 | } | 1047 | } |
1016 | 1048 | ||
1017 | return -ENOTTY; | 1049 | return -ENOTTY; |
@@ -1174,6 +1206,8 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1174 | vdev->irq_type = VFIO_PCI_NUM_IRQS; | 1206 | vdev->irq_type = VFIO_PCI_NUM_IRQS; |
1175 | mutex_init(&vdev->igate); | 1207 | mutex_init(&vdev->igate); |
1176 | spin_lock_init(&vdev->irqlock); | 1208 | spin_lock_init(&vdev->irqlock); |
1209 | mutex_init(&vdev->ioeventfds_lock); | ||
1210 | INIT_LIST_HEAD(&vdev->ioeventfds_list); | ||
1177 | 1211 | ||
1178 | ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev); | 1212 | ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev); |
1179 | if (ret) { | 1213 | if (ret) { |
@@ -1215,6 +1249,7 @@ static void vfio_pci_remove(struct pci_dev *pdev) | |||
1215 | 1249 | ||
1216 | vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev); | 1250 | vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev); |
1217 | kfree(vdev->region); | 1251 | kfree(vdev->region); |
1252 | mutex_destroy(&vdev->ioeventfds_lock); | ||
1218 | kfree(vdev); | 1253 | kfree(vdev); |
1219 | 1254 | ||
1220 | if (vfio_pci_is_vga(pdev)) { | 1255 | if (vfio_pci_is_vga(pdev)) { |