aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-21 00:30:12 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-21 00:30:12 -0500
commit54e37b8dbe9a398f74cef313404bd2f1deca7853 (patch)
tree2f72705eeb100b67b73902635763f08a6302a507
parent96680d2b9174668100824d763382240c71baa811 (diff)
parent9a92c5091a42c565ede818fdf204c4f60004d0d8 (diff)
Merge tag 'vfio-for-v3.8-v2' of git://github.com/awilliam/linux-vfio
Pull vfio update from Alex Williamson. * tag 'vfio-for-v3.8-v2' of git://github.com/awilliam/linux-vfio: vfio-pci: Enable device before attempting reset VFIO: fix out of order labels for error recovery in vfio_pci_init() VFIO: use ACCESS_ONCE() to guard access to dev->driver VFIO: unregister IOMMU notifier on error recovery path vfio-pci: Re-order device reset vfio: simplify kmalloc+copy_from_user to memdup_user
-rw-r--r--drivers/vfio/pci/vfio_pci.c83
-rw-r--r--drivers/vfio/vfio.c34
2 files changed, 64 insertions, 53 deletions
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 6c119944bbb6..b28e66c4376a 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -43,6 +43,10 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
43 u16 cmd; 43 u16 cmd;
44 u8 msix_pos; 44 u8 msix_pos;
45 45
46 ret = pci_enable_device(pdev);
47 if (ret)
48 return ret;
49
46 vdev->reset_works = (pci_reset_function(pdev) == 0); 50 vdev->reset_works = (pci_reset_function(pdev) == 0);
47 pci_save_state(pdev); 51 pci_save_state(pdev);
48 vdev->pci_saved_state = pci_store_saved_state(pdev); 52 vdev->pci_saved_state = pci_store_saved_state(pdev);
@@ -51,8 +55,11 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
51 __func__, dev_name(&pdev->dev)); 55 __func__, dev_name(&pdev->dev));
52 56
53 ret = vfio_config_init(vdev); 57 ret = vfio_config_init(vdev);
54 if (ret) 58 if (ret) {
55 goto out; 59 pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state);
60 pci_disable_device(pdev);
61 return ret;
62 }
56 63
57 if (likely(!nointxmask)) 64 if (likely(!nointxmask))
58 vdev->pci_2_3 = pci_intx_mask_supported(pdev); 65 vdev->pci_2_3 = pci_intx_mask_supported(pdev);
@@ -77,24 +84,15 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
77 } else 84 } else
78 vdev->msix_bar = 0xFF; 85 vdev->msix_bar = 0xFF;
79 86
80 ret = pci_enable_device(pdev); 87 return 0;
81 if (ret)
82 goto out;
83
84 return ret;
85
86out:
87 kfree(vdev->pci_saved_state);
88 vdev->pci_saved_state = NULL;
89 vfio_config_free(vdev);
90 return ret;
91} 88}
92 89
93static void vfio_pci_disable(struct vfio_pci_device *vdev) 90static void vfio_pci_disable(struct vfio_pci_device *vdev)
94{ 91{
92 struct pci_dev *pdev = vdev->pdev;
95 int bar; 93 int bar;
96 94
97 pci_disable_device(vdev->pdev); 95 pci_disable_device(pdev);
98 96
99 vfio_pci_set_irqs_ioctl(vdev, VFIO_IRQ_SET_DATA_NONE | 97 vfio_pci_set_irqs_ioctl(vdev, VFIO_IRQ_SET_DATA_NONE |
100 VFIO_IRQ_SET_ACTION_TRIGGER, 98 VFIO_IRQ_SET_ACTION_TRIGGER,
@@ -104,22 +102,40 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
104 102
105 vfio_config_free(vdev); 103 vfio_config_free(vdev);
106 104
107 pci_reset_function(vdev->pdev);
108
109 if (pci_load_and_free_saved_state(vdev->pdev,
110 &vdev->pci_saved_state) == 0)
111 pci_restore_state(vdev->pdev);
112 else
113 pr_info("%s: Couldn't reload %s saved state\n",
114 __func__, dev_name(&vdev->pdev->dev));
115
116 for (bar = PCI_STD_RESOURCES; bar <= PCI_STD_RESOURCE_END; bar++) { 105 for (bar = PCI_STD_RESOURCES; bar <= PCI_STD_RESOURCE_END; bar++) {
117 if (!vdev->barmap[bar]) 106 if (!vdev->barmap[bar])
118 continue; 107 continue;
119 pci_iounmap(vdev->pdev, vdev->barmap[bar]); 108 pci_iounmap(pdev, vdev->barmap[bar]);
120 pci_release_selected_regions(vdev->pdev, 1 << bar); 109 pci_release_selected_regions(pdev, 1 << bar);
121 vdev->barmap[bar] = NULL; 110 vdev->barmap[bar] = NULL;
122 } 111 }
112
113 /*
114 * If we have saved state, restore it. If we can reset the device,
115 * even better. Resetting with current state seems better than
116 * nothing, but saving and restoring current state without reset
117 * is just busy work.
118 */
119 if (pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state)) {
120 pr_info("%s: Couldn't reload %s saved state\n",
121 __func__, dev_name(&pdev->dev));
122
123 if (!vdev->reset_works)
124 return;
125
126 pci_save_state(pdev);
127 }
128
129 /*
130 * Disable INTx and MSI, presumably to avoid spurious interrupts
131 * during reset. Stolen from pci_reset_function()
132 */
133 pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
134
135 if (vdev->reset_works)
136 __pci_reset_function(pdev);
137
138 pci_restore_state(pdev);
123} 139}
124 140
125static void vfio_pci_release(void *device_data) 141static void vfio_pci_release(void *device_data)
@@ -327,15 +343,10 @@ static long vfio_pci_ioctl(void *device_data,
327 hdr.count > vfio_pci_get_irq_count(vdev, hdr.index)) 343 hdr.count > vfio_pci_get_irq_count(vdev, hdr.index))
328 return -EINVAL; 344 return -EINVAL;
329 345
330 data = kmalloc(hdr.count * size, GFP_KERNEL); 346 data = memdup_user((void __user *)(arg + minsz),
331 if (!data) 347 hdr.count * size);
332 return -ENOMEM; 348 if (IS_ERR(data))
333 349 return PTR_ERR(data);
334 if (copy_from_user(data, (void __user *)(arg + minsz),
335 hdr.count * size)) {
336 kfree(data);
337 return -EFAULT;
338 }
339 } 350 }
340 351
341 mutex_lock(&vdev->igate); 352 mutex_lock(&vdev->igate);
@@ -562,9 +573,9 @@ static int __init vfio_pci_init(void)
562 573
563 return 0; 574 return 0;
564 575
565out_virqfd:
566 vfio_pci_virqfd_exit();
567out_driver: 576out_driver:
577 vfio_pci_virqfd_exit();
578out_virqfd:
568 vfio_pci_uninit_perm_bits(); 579 vfio_pci_uninit_perm_bits();
569 return ret; 580 return ret;
570} 581}
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index 56097c6d072d..12c264d3b058 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -191,6 +191,17 @@ static void vfio_container_put(struct vfio_container *container)
191 kref_put(&container->kref, vfio_container_release); 191 kref_put(&container->kref, vfio_container_release);
192} 192}
193 193
194static void vfio_group_unlock_and_free(struct vfio_group *group)
195{
196 mutex_unlock(&vfio.group_lock);
197 /*
198 * Unregister outside of lock. A spurious callback is harmless now
199 * that the group is no longer in vfio.group_list.
200 */
201 iommu_group_unregister_notifier(group->iommu_group, &group->nb);
202 kfree(group);
203}
204
194/** 205/**
195 * Group objects - create, release, get, put, search 206 * Group objects - create, release, get, put, search
196 */ 207 */
@@ -229,8 +240,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
229 240
230 minor = vfio_alloc_group_minor(group); 241 minor = vfio_alloc_group_minor(group);
231 if (minor < 0) { 242 if (minor < 0) {
232 mutex_unlock(&vfio.group_lock); 243 vfio_group_unlock_and_free(group);
233 kfree(group);
234 return ERR_PTR(minor); 244 return ERR_PTR(minor);
235 } 245 }
236 246
@@ -239,8 +249,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
239 if (tmp->iommu_group == iommu_group) { 249 if (tmp->iommu_group == iommu_group) {
240 vfio_group_get(tmp); 250 vfio_group_get(tmp);
241 vfio_free_group_minor(minor); 251 vfio_free_group_minor(minor);
242 mutex_unlock(&vfio.group_lock); 252 vfio_group_unlock_and_free(group);
243 kfree(group);
244 return tmp; 253 return tmp;
245 } 254 }
246 } 255 }
@@ -249,8 +258,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
249 group, "%d", iommu_group_id(iommu_group)); 258 group, "%d", iommu_group_id(iommu_group));
250 if (IS_ERR(dev)) { 259 if (IS_ERR(dev)) {
251 vfio_free_group_minor(minor); 260 vfio_free_group_minor(minor);
252 mutex_unlock(&vfio.group_lock); 261 vfio_group_unlock_and_free(group);
253 kfree(group);
254 return (struct vfio_group *)dev; /* ERR_PTR */ 262 return (struct vfio_group *)dev; /* ERR_PTR */
255 } 263 }
256 264
@@ -274,16 +282,7 @@ static void vfio_group_release(struct kref *kref)
274 device_destroy(vfio.class, MKDEV(MAJOR(vfio.devt), group->minor)); 282 device_destroy(vfio.class, MKDEV(MAJOR(vfio.devt), group->minor));
275 list_del(&group->vfio_next); 283 list_del(&group->vfio_next);
276 vfio_free_group_minor(group->minor); 284 vfio_free_group_minor(group->minor);
277 285 vfio_group_unlock_and_free(group);
278 mutex_unlock(&vfio.group_lock);
279
280 /*
281 * Unregister outside of lock. A spurious callback is harmless now
282 * that the group is no longer in vfio.group_list.
283 */
284 iommu_group_unregister_notifier(group->iommu_group, &group->nb);
285
286 kfree(group);
287} 286}
288 287
289static void vfio_group_put(struct vfio_group *group) 288static void vfio_group_put(struct vfio_group *group)
@@ -466,8 +465,9 @@ static int vfio_dev_viable(struct device *dev, void *data)
466{ 465{
467 struct vfio_group *group = data; 466 struct vfio_group *group = data;
468 struct vfio_device *device; 467 struct vfio_device *device;
468 struct device_driver *drv = ACCESS_ONCE(dev->driver);
469 469
470 if (!dev->driver || vfio_whitelisted_driver(dev->driver)) 470 if (!drv || vfio_whitelisted_driver(drv))
471 return 0; 471 return 0;
472 472
473 device = vfio_group_get_device(group, dev); 473 device = vfio_group_get_device(group, dev);