aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2014-08-07 13:12:02 -0400
committerAlex Williamson <alex.williamson@redhat.com>2014-08-07 13:12:02 -0400
commit9c22e660ce8105debb497933b9900eaeb40836d2 (patch)
tree13850f3a51755be42a6b68a03ef6f6b6cab2290b
parent7f0d32e0c1a7a23216a0f2694ec841f60e9dddfd (diff)
vfio-pci: Release devices with BusMaster disabled
Our current open/release path looks like this: vfio_pci_open vfio_pci_enable pci_enable_device pci_save_state pci_store_saved_state vfio_pci_release vfio_pci_disable pci_disable_device pci_restore_state pci_enable_device() doesn't modify PCI_COMMAND_MASTER, so if a device comes to us with it enabled, it persists through the open and gets stored as part of the device saved state. We then restore that saved state when released, which can allow the device to attempt to continue to do DMA. When the group is disconnected from the domain, this will get caught by the IOMMU, but if there are other devices in the group, the device may continue running and interfere with the user. Even in the former case, IOMMUs don't necessarily behave well and a stream of blocked DMA can result in unpleasant behavior on the host. Explicitly disable Bus Master as we're enabling the device and slightly re-work release to make sure that pci_disable_device() is the last thing that touches the device. Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
-rw-r--r--drivers/vfio/pci/vfio_pci.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index e2ee80f36e3e..fc011e13213b 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -44,6 +44,9 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
44 u16 cmd; 44 u16 cmd;
45 u8 msix_pos; 45 u8 msix_pos;
46 46
47 /* Don't allow our initial saved state to include busmaster */
48 pci_clear_master(pdev);
49
47 ret = pci_enable_device(pdev); 50 ret = pci_enable_device(pdev);
48 if (ret) 51 if (ret)
49 return ret; 52 return ret;
@@ -99,7 +102,8 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
99 struct pci_dev *pdev = vdev->pdev; 102 struct pci_dev *pdev = vdev->pdev;
100 int bar; 103 int bar;
101 104
102 pci_disable_device(pdev); 105 /* Stop the device from further DMA */
106 pci_clear_master(pdev);
103 107
104 vfio_pci_set_irqs_ioctl(vdev, VFIO_IRQ_SET_DATA_NONE | 108 vfio_pci_set_irqs_ioctl(vdev, VFIO_IRQ_SET_DATA_NONE |
105 VFIO_IRQ_SET_ACTION_TRIGGER, 109 VFIO_IRQ_SET_ACTION_TRIGGER,
@@ -128,7 +132,7 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
128 __func__, dev_name(&pdev->dev)); 132 __func__, dev_name(&pdev->dev));
129 133
130 if (!vdev->reset_works) 134 if (!vdev->reset_works)
131 return; 135 goto out;
132 136
133 pci_save_state(pdev); 137 pci_save_state(pdev);
134 } 138 }
@@ -151,6 +155,8 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
151 } 155 }
152 156
153 pci_restore_state(pdev); 157 pci_restore_state(pdev);
158out:
159 pci_disable_device(pdev);
154} 160}
155 161
156static void vfio_pci_release(void *device_data) 162static void vfio_pci_release(void *device_data)